Great Deal! Get Instant $10 FREE in Account on First Order + 10% Cashback on Every Order Order Now

Mini Project #2: PLC Programming with Ladder Logic CS 6263/ECE 8813: Cyber Physical System Security (Summer 2020) Assigned: June 3rd, 2020 Due: June 17th, 2020, 11:59pm EST Ladder Diagram (LD) In the...

2 answer below »
Mini Project #2: PLC Programming with
Ladder Logic
CS 6263/ECE 8813: Cyber Physical System Security (Summer 2020)
Assigned: June 3rd, 2020 Due: June 17th, 2020, 11:59pm EST
Ladder Diagram (LD)
In the second mini project, we will write PLC programs to control different real-world
systems. The programs will be written in the Ladder Diagram (LD) format which is the
most popular language for writing PLC programs. Other formats for PLC programming
are: Structured Text (ST), Function Block Diagram (FBD), Instruction List (IL), and
Sequential Function Chart (SFC). Many early PLCs did not have accompanying program-
ming terminals that were capable of graphical representation of the logic, and so the logic
was instead represented as a series of logic expressions in some version of Boolean format,
similar to Boolean alge
a. As programming terminals evolved, it became more common
for ladder logic to be used, for the aforementioned reasons and because it was a familia
format used for electro-mechanical control panels. Newer formats such as state logic and
Function Block (which is similar to the way logic is depicted when using digital integrated
logic circuits) exist, but they are still not as popular as ladder logic. A primary reason fo
this is that PLCs solve the logic in a predictable and repeating sequence, and ladder logic
allows the programmer (the person writing the logic) to see any issues with the timing of
the logic sequence more easily than would be possible in other formats.
OpenPLC
Instead of using a real PLC, we will use an open source PLC emulator called OpenPLC
to do the programming. The performance of the programs will be evaluated in simulated
environments representing the behavior of real-world processes. The OpenPLC is the first
fully functional standardized open source PLC, both in software and in hardware. In fact,
OpenPLC is an alternative program which simulates the behaviours and capabilities of
eal PLCs with the help of simple and low-cost hardware such as Arduino or Raspbe
y
Pi. The focus of this software is to provide a low cost industrial solution for automation
and research. OpenPLC has also been used in many research papers as a framework fo
industrial cybersecurity research, given that it is the only controller to provide the entire
source code. Once you learn how to work with OpenPLC, you can easily pick up how to
program real PLCs of different vendors.
1
Mini Project #2 PLC Programming with Ladder Logic
Ladder Logic, though is different from mainstream coding languages, is very easy to pick
up. Here are a few tutorials on ladder logic to get you started: Tutorial 1, Tutorial 2. You
can also find a lot of tutorials in YouTube and Google. Note that there is no limitation on
the methods you can use in the following sections unless it is explicitly mentioned in the
write-up. For example, you can use any number of ladders and rungs you need in you
program. It should be also noted that since we will use an autograder for this project,
you must use the predetermined names of the inputs and outputs in your program (please
see Appendix for more detailed information). This is highly important because even if
your logic is 100% co
ect and you don’t use the predetermined memory addresses for the
inputs and outputs, the autograder will return full/partial points deduction. Failure to
follow this instruction will lead to significant points loss (ZERO) in your final grade. We
will NOT accept any excuses for naming mistakes. You MUST triple check the names
efore submission!
OpenPLC Setup – Writing and Testing Programs
In this section, we will explain how you can set up the project environment, write the
equired programs, and test them in the provided simulators. As the first step, please
follow the below instructions to download and set up the environment containing all of
the tools required to complete this project:
1. We have provided a Virtual Machine (Ubuntu) completely tailored for this mini
project. All of the required li
aries have already been installed on it and every tool
has been tested to perform as best as possible. You can use VirtualBox, VMware
Workstation (for Windows users) or Parallels Desktop (for MAC users) to use this
VM. First download the VM files located here (.ova format) and move them to you
desired location on your personal machine. Use VirtualBox (version 6.0 or later) o
Parallels Desktop (version 15 preferably) to open the downloaded VM. You can open
the VM in by clicking on the .vbox file or importing the .ova file directly in you
hypervisor. Do not forget that these files are your actual virtual machine
and deleting them from your personal computer will result in losing all
of your work. We strongly recommend saving your written programs in
cloud environments such as Google Drive so that in the case of failure in
the VM, you can resume your work with minimum issues on a fresh VM.
2. A user (username: cs6263 and password: Project2) has been created for you.
Please refer to this credential in case you need it or if you need to use the “sudo”
command. Open a terminal and navigate into the “OpenPLC v3” folder. Run the
OpenPLC server by typing the following command
sudo ./start_openplc.sh
The OpenPLC server should be running now and you can open Firefox and visit
http:
localhost:8080 to access it. This platform provides you with a PLC simulated
environment in which you can upload and run your PLC program like a real PLC.
Georgia Institute of Technology 2 Introduction to CPS Security (CS 6263)
https:
www.youtube.com/watch?v=Y1yD7aoUmOo
https:
www.youtube.com/watch?v=xpTBpFHyluw&list=PL9eN6-TpvPMVA7h3QK6LNct2xND-ZcnHp
https:
gatech.box.com/s/ok03lt8s7l8uohf7th54t4av9n0dtieg
http:
localhost:8080
Mini Project #2 PLC Programming with Ladder Logic
In fact, the server will act as the hardware for the PLC program that will run
your written program and communicate with a physical process (simulator in this
project). Once you verified that the OpenPLC works fine on the VM, you can kill
the process and start writing the PLC program as explained in the following steps.
Note that you will later use this OpenPLC server for testing the written programs
in parts 2, 3, 4, and 5.
3. Now it is the time to write your PLC programs. You can navigate to the Linux
application directory or “/Desktop/OpenPLC Editor v1.0-Linux” directory and run
sudo ./OpenPLC_Edito
openplc_editor.sh
to write logic for the OpenPLC program. To start, you should create an empty
folder for each part separately and choose that directory for that part. This link
can help you to learn how to start programing in the IDE. Please do not touch the
.Config settings (i.e., task0, Cyclic, T#20ms, Priority 0, instance0). For a list of
input/output pin definition, see the Appendix. Note: If the OpenPLC Edito
uns slowly in the VM, you can install it on your host machine and then
move the written programs to the VM for evaluation purposes. Please
see here for more information.
4. You can easily test the performance of the written program using the run button
within the IDE. You can choose the items to be shown in the Debugger tab by
selecting them with the glasses icon in the left side of the screen. By right clicking
and enforcing the values of inputs, you can see the effect of different inputs on
outputs in the Debugger tab.
5. After running and testing your program, the XML and .ST versions of the program
can be found in the relevant directory (XML is named plc.xml in the main directory
and .st is in the build directory with the name of generated plc.st). Note that you
need to create separate folders for each part and subpart. For testing parts 2, 3, 4,
and 5, you should upload the relevant .ST file into the server as described in here.
Verify that the page says “compiled without e
ors”. Please remember that you need
to follow the naming instructions in Deliverables and Submission Instructions
section. A schematic diagram of the relationship between .st file and the server has
een shown in Fig. 1.
6. For Part 1 of this Mini Project, you need to test the logic of your program using the
editor, but for the Parts 2-5, very useful HMIs have been developed and are provided
in the VM. item (for part 2 & 3) You can use the directories /Desktop/Process-
Simulato
RoboPath and /Desktop/ProcessSimulato
TrafficLight directories and
un
python ProcessSimulator.py
to start the HMIs associated with these parts of the project. Please note that the
HMI needs to be launched after the OpenPLC server is running using the .st file you
Georgia Institute of Technology 3 Introduction to CPS Security (CS 6263)
https:
www.openplcproject.com
eference-your-first-project
https:
openplcproject.com/plcopen-edito
https:
www.openplcproject.com
eference-uploading-your-project
Mini Project #2 PLC Programming with Ladder Logic
Figure 1: The overall overview of the program design and test in the OpenPLC platform.
generate from the OpenPLC GUI. If you need to restart the server by uploading a
new PLC program, please close the HMI before uploading, and relaunch it after the
server is running again.
7. (for Part 4 & 5) You can do the same as what you did for parts 2 and 3 by going
through each process’ directory (i.e., /Desktop/ProcessSimulato
TankSystem o
Desktop/ProcessSimulato
Sti
ingSystem) and run the process simulator with
.
un.sh
and the HMI file with
python hmi.py
You can also use the UaExpert software. In the /Desktop/UaExpert folder, double
click “UaExpert XXXXXXXXXXx86 64.AppImage” (in GUI) or by typing the following
command in Terminal
./UaExpert XXXXXXXXXXx86_64.AppImage
to start the software. Then, open the pre-configured “Sti
ingSystem.uap” or “TankSys-
temMonitor.uap” file to start monitoring the I/O values in real time. The values of
Georgia Institute of Technology 4 Introduction to CPS Security (CS 6263)
Mini Project #2 PLC Programming with Ladder Logic
interest have already been added to the “Data access view”. You may also leverage
this software to manually set the input and test your program. In this case, the
simulator does not need to be running.
Georgia Institute of Technology 5 Introduction to CPS Security (CS 6263)
Mini Project #2 PLC Programming with Ladder Logic
1 Part 1 (25 Points)
Construct three different Ladder Logic programs, each building on the previous one:
1.1 Part 1A (5 Points)
Construct a program that will simulate a push button activated LED. The program should
satisfy the following requirements:
1. When Input0 is activated, Output1 should activate;
2. When Input0 is deactivated, Output1 should deactivate;
3. Inversely, when Input1 is activated, Output0 should deactivate;
4. When Input1 is deactivated, Output0 should activate.
Note: Input0 and Input1 are not push buttons. For example, Output1 should
e active as long as the Input0 is active. To be more clear, Input0 and Input1
are like light switches, i.e., you should use simple contacts for them.
1.2 Part 1B (10 Points)
Construct a program that simulates an LED powered by an On-Off loop. Program re-
quirements:
1. When Input0 is activated
Answered Same Day Jun 04, 2021

Solution

Gaurav answered on Jun 18 2021
150 Votes
PLC Assignment/HMI/RobotPath/hmi.py
#!/us
in/env python
import sys
import time
import math
import logging
import Tkinter as tk
import tkMessageBox
from opcua import Client, ua
max_x = 7
max_y = 7
x_bits = int(math.ceil(math.log(max_x + 1, 2)))
y_bits = int(math.ceil(math.log(max_y + 1, 2)))
target_addr_offset = x_bits + y_bits
grid_padding = 50
grid_spacing = 100
def index2addr(index, bit_width=8):
return "{}.{}".format(index
it_width, index % bit_width)
class GUI(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.wm_title("HMI")
grid_frame = tk.LabelFrame(self, text='Grid')
grid_frame.pack(side="left", fill="both", expand=False, padx=10, pady=10)
self.canvas = tk.Canvas(grid_frame, width=grid_padding*2+grid_spacing*max_x, height=grid_padding*2+grid_spacing*max_y)
for x in xrange(grid_padding, grid_padding + grid_spacing * max_x + 1, grid_spacing):
self.canvas.create_line(x, grid_padding, x, grid_padding + grid_spacing * max_x)
for y in xrange(grid_padding, grid_padding + grid_spacing * max_y + 1, grid_spacing):
self.canvas.create_line(grid_padding, y, grid_padding + grid_spacing * max_y, y)
self.canvas.bind("", self.__click_callback__)
self.canvas.pack(fill="both", expand=False)
param_frame = tk.LabelFrame(self, text="Status")
param_frame.pack(side="right", fill="both", expand=False, padx=10, pady=10)
up_enabled_label = tk.Label(param_frame, text="Up Enabled")
up_enabled_label.grid(row=0, column=0, padx=5, pady=5)
self.up_enabled_status_label = tk.Label(param_frame, text="")
self.up_enabled_status_label.grid(row=0, column=1, padx=5, pady=5)
down_enabled_label = tk.Label(param_frame, text="Down Enabled")
down_enabled_label.grid(row=1, column=0, padx=5, pady=5)
self.down_enabled_status_label = tk.Label(param_frame, text="")
self.down_enabled_status_label.grid(row=1, column=1, padx=5, pady=5)
left_enabled_label = tk.Label(param_frame, text="Left Enabled")
left_enabled_label.grid(row=2, column=0, padx=5, pady=5)
self.left_enabled_status_label = tk.Label(param_frame, text="")
self.left_enabled_status_label.grid(row=2, column=1, padx=5, pady=5)
right_enabled_label = tk.Label(param_frame, text="Right Enabled")
right_enabled_label.grid(row=3, column=0, padx=5, pady=5)
self.right_enabled_status_label = tk.Label(param_frame, text="")
self.right_enabled_status_label.grid(row=3, column=1, padx=5, pady=5)
direction_label = tk.Label(param_frame, text="Direction")
direction_label.grid(row=4, column=0, padx=5, pady=5)
self.direction_status_label = tk.Label(param_frame, text="N/A")
self.direction_status_label.grid(row=4, column=1, padx=5, pady=5)
self.up_enable = False
self.down_enable = False
self.left_enable = False
self.right_enable = False
self.position_circle = None
self.position_x_bits_val = [0] * x_bits
self.position_y_bits_val = [0] * y_bits
self.target_circle = None
self.target_x_bits_val = [0] * x_bits
self.target_y_bits_val = [0] * y_bits
self.protocol("WM_DELETE_WINDOW", self.__disconnect_opcua_server__)
self.__connect_opcua_server__()
def __connect_opcua_server__(self):
logging.basicConfig(level=logging.WARN)
self.client = Client("opc.tcp:
localhost:4840/freeopcua/serve
")
try:
self.client.connect()
root = self.client.get_root_node()
handler = SubHandler(self)
sub = self.client.create_subscription(500, handler)
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.0"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.1"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.2"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.3"]))
self.target_x_bits = [
root.get_child(["0:Objects", "2:OpenPLC", "2:%IX{}".format(index2addr(target_addr_offset + idx))])
for idx in xrange(x_bits)
]
self.target_y_bits = [
root.get_child(["0:Objects", "2:OpenPLC", "2:%IX{}".format(index2addr(target_addr_offset + x_bits + idx))])
for idx in xrange(y_bits)
]
for idx in xrange(x_bits):
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX{}".format(index2addr(idx))]))
for idx in xrange(y_bits):
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX{}".format(index2addr(x_bits + idx))]))
for idx in xrange(x_bits):
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX{}".format(index2addr(target_addr_offset + idx))]))
for idx in xrange(y_bits):
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX{}".format(index2addr(target_addr_offset + x_bits + idx))]))
except:
print("E
or: Could not connect to server!")
sys.exit(-1)
def __click_callback__(self, event):
# Convert window coordinates to grid coordinates
target_x = int(float(event.x - grid_padding) / grid_spacing + 0.5)
target_y = max_y - int(float(event.y - grid_padding) / grid_spacing + 0.5)
# Encode target (little endian)
for x_bit in self.target_x_bits:
x_bit.set_value(True if target_x % 2 else False)
target_x
= 2
for y_bit in self.target_y_bits:
y_bit.set_value(True if target_y % 2 else False)
target_y
= 2
def update_direction(self):
self.up_enabled_status_label.config(text=str(self.up_enable))
self.down_enabled_status_label.config(text=str(self.down_enable))
self.left_enabled_status_label.config(text=str(self.left_enable))
self.right_enabled_status_label.config(text=str(self.right_enable))
if self.up_enable and not (self.down_enable or self.left_enable or self.right_enable):
self.direction_status_label.config(text="Up")
elif self.down_enable and not (self.up_enable or self.left_enable or self.right_enable):
self.direction_status_label.config(text="Down")
elif self.left_enable and not (self.up_enable or self.down_enable or self.right_enable):
self.direction_status_label.config(text="Left")
elif self.right_enable and not (self.up_enable or self.down_enable or self.left_enable):
self.direction_status_label.config(text="Right")
else:
self.direction_status_label.config(text="N/A")
def update_position(self):
# Decode position (little endian)
pos_x = 0
pos_y = 0
for weight, val in enumerate(self.position_x_bits_val):
pos_x += val * 2 ** weight
for weight, val in enumerate(self.position_y_bits_val):
pos_y += val * 2 ** weight
print("Position: ({}, {})".format(pos_x, pos_y))
if self.position_circle:
self.canvas.delete(self.position_circle)
position_circle_x = pos_x * grid_spacing + grid_padding
position_circle_y = (max_y - pos_y) * grid_spacing + grid_padding
self.position_circle = self.canvas.create_oval(
position_circle_x - 20,
position_circle_y - 20,
position_circle_x + 20,
position_circle_y + 20,
fill="black")
target_x = 0
target_y = 0
for weight, val in enumerate(self.target_x_bits_val):
target_x += val * 2 ** weight
for weight, val in enumerate(self.target_y_bits_val):
target_y += val * 2 ** weight
print("Target: ({}, {})".format(target_x, target_y))
if self.target_circle:
self.canvas.delete(self.target_circle)
target_circle_x = target_x * grid_spacing + grid_padding
target_circle_y = (max_y - target_y) * grid_spacing + grid_padding
self.target_circle = self.canvas.create_oval(
target_circle_x - 30,
target_circle_y - 30,
target_circle_x + 30,
target_circle_y + 30)
#self.canvas.update_idletasks()
def __disconnect_opcua_server__(self):
self.client.disconnect()
self.destroy()
class SubHandler(object):
"""
Subscription Handler. To receive events from server for a subscription
data_change and event methods are called directly from receiving thread.
Do not do expensive, slow or network operation there. Create anothe
thread if you need to do such a thing
"""
def __init__(self, gui):
object.__init__(self)
self.gui = gui
def datachange_notification(self, node, val, data):
print("New data change event", node, val)
try:
nodeid = int(str(node.nodeid).split('=')[-1].strip(')'))
except:
return
if nodeid == 3: # Up enabled
self.gui.up_enable = val
self.gui.update_direction()
elif nodeid == 5: # Down enabled
self.gui.down_enable = val
self.gui.update_direction()
elif nodeid == 7: # Left enabled
self.gui.left_enable = val
self.gui.update_direction()
elif nodeid == 9: # Right enabled
self.gui.right_enable = val
self.gui.update_direction()
elif nodeid % 2 == 0: # %IX
# Normalize nodeid
nodeid -= nodeid
18 * 2
if nodeid <= 2 * x_bits: # Position x
self.gui.position_x_bits_val[nodeid/2 - 1] = 1 if val else 0
self.gui.update_position()
elif nodeid <= 2 * (x_bits + y_bits): # Position y
self.gui.position_y_bits_val[nodeid/2 - x_bits - 1] = 1 if val else 0
self.gui.update_position()
elif nodeid <= 2 * (target_addr_offset + x_bits): # Target x
self.gui.target_x_bits_val[nodeid/2 - target_addr_offset - 1] = 1 if val else 0
self.gui.update_position()
elif nodeid <= 2 * (target_addr_offset + x_bits + y_bits): # Target y
self.gui.target_y_bits_val[nodeid/2 - target_addr_offset - x_bits - 1] = 1 if val else 0
self.gui.update_position()
def event_notification(self, event):
print("New event", event)
if __name__ == '__main__':
app = GUI()
app.mainloop()
PLC Assignment/HMI/RobotPath/ProcessSimulator.py
#!/us
in/env python
import sys
import time
import logging
import math
from opcua import Client, ua
def index2addr(index, bit_width=8):
return "{}.{}".format(index
it_width, index % bit_width)
class Simulator:
def __init__(self, max_x=7, max_y=7):
self.max_x = max_x
self.max_y = max_y
self.pos_x = 0
self.pos_y = 0
self.up_enable = False
self.down_enable = False
self.left_enable = False
self.right_enable = False
self.last_direction = None
self.last_timestamp = None
self.__connect_opcua_server__()
self.update_position()
def __connect_opcua_server__(self):
logging.basicConfig(level=logging.WARN)
self.client = Client("opc.tcp:
localhost:4840/freeopcua/serve
")
try:
self.client.connect()
root = self.client.get_root_node()
handler = SubHandler(self)
sub = self.client.create_subscription(500, handler)
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.0"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.1"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.2"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.3"]))
x_bits = int(math.ceil(math.log(self.max_x + 1, 2)))
y_bits = int(math.ceil(math.log(self.max_y + 1, 2)))
self.position_x_bits = [
root.get_child(["0:Objects", "2:OpenPLC", "2:%IX{}".format(index2addr(idx))])
for idx in xrange(x_bits)
]
self.position_y_bits = [
root.get_child(["0:Objects", "2:OpenPLC", "2:%IX{}".format(index2addr(x_bits + idx))])
for idx in xrange(y_bits)
]
except:
print("E
or: Could not connect to server!")
sys.exit(-1)

def update_position(self):
pos_x = self.pos_x
pos_y = self.pos_y
# Encode position (little endian)
for x_bit in self.position_x_bits:
x_bit.set_value(True if pos_x % 2 else False)
pos_x
= 2
for y_bit in self.position_y_bits:
y_bit.set_value(True if pos_y % 2 else False)
pos_y
= 2
def move(self, direction):
if direction == "up" and self.pos_y < self.max_y:
self.pos_y += 1
print("Position: ({}, {})".format(self.pos_x, self.pos_y))
self.update_position()
elif direction == "down" and self.pos_y > 0:
self.pos_y -= 1
print("Position: ({}, {})".format(self.pos_x, self.pos_y))
self.update_position()
elif direction == "left" and self.pos_x > 0:
self.pos_x -= 1
print("Position: ({}, {})".format(self.pos_x, self.pos_y))
self.update_position()
elif direction == "right" and self.pos_x < self.max_x:
self.pos_x += 1
print("Position: ({}, {})".format(self.pos_x, self.pos_y))
self.update_position()
def run(self):
try:
while True:
if self.up_enable and not (self.down_enable or self.left_enable or self.right_enable):
if self.last_direction == "up":
if time.time() - self.last_timestamp > 1.0:
self.last_timestamp = time.time()
self.move("up")
else:
self.last_direction = "up"
self.last_timestamp = time.time()
elif self.down_enable and not (self.up_enable or self.left_enable or self.right_enable):
if self.last_direction == "down":
if time.time() - self.last_timestamp > 1.0:
self.last_timestamp = time.time()
self.move("down")
else:
self.last_direction = "down"
self.last_timestamp = time.time()
elif self.left_enable and not (self.up_enable or self.down_enable or self.right_enable):
if self.last_direction == "left":
if time.time() - self.last_timestamp > 1.0:
self.last_timestamp = time.time()
self.move("left")
else:
self.last_direction = "left"
self.last_timestamp = time.time()
elif self.right_enable and not (self.up_enable or self.down_enable or self.left_enable):
if self.last_direction == "right":
if time.time() - self.last_timestamp > 1.0:
self.last_timestamp = time.time()
self.move("right")
else:
self.last_direction = "right"
self.last_timestamp = time.time()
except KeyboardInte
upt:
self.__disconnect_opcua_server__()
def __disconnect_opcua_server__(self):
try:
self.client.disconnect()
except:
pass
class SubHandler(object):
"""
Subscription Handler. To receive events from server for a subscription
data_change and event methods are called directly from receiving thread.
Do not do expensive, slow or network operation there. Create anothe
thread if you need to do such a thing
"""
def __init__(self, sim):
object.__init__(self)
self.sim = sim
def datachange_notification(self, node, val, data):
print("New data change event", node, val)
try:
nodeid = int(str(node.nodeid).split('=')[-1].strip(')'))
except:
return
if nodeid == 3: # Up
self.sim.up_enable = val
elif nodeid == 5: # Down
self.sim.down_enable = val
elif nodeid == 7: # Left
self.sim.left_enable = val
elif nodeid == 9: # Right
self.sim.right_enable = val
def event_notification(self, event):
print("New event", event)
if __name__ == '__main__':
sim = Simulator()
sim.run()
PLC Assignment/HMI/Sti
ingSystem/config.sim






























































































































































PLC Assignment/HMI/Sti
ingSystem/hmi.py
#!/us
in/env python
import matplotli
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
from matplotlib import colors
plt.ion()
import numpy as np
import time
import numpy
import logging
import threading
from Queue import Queue
import Tkinter as tk
import tkMessageBox
from opcua import Client, ua
color_palettes = colors.cnames.keys()
class GUI(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.wm_title("HMI")
inputs_frame = tk.LabelFrame(self, text='Inputs')
inputs_frame.pack(side="top", fill="both", expand=True, padx=10, pady=10)
empty_level_label = tk.Label(inputs_frame, text='Empty level sensor')
empty_level_label.grid(row=0, column=0, padx=5, pady=5)
self.empty_level_status_label = tk.Label(inputs_frame, text='N/A')
self.empty_level_status_label.grid(row=0, column=1, padx=5, pady=5)
low_level_label = tk.Label(inputs_frame, text='Low level sensor')
low_level_label.grid(row=1, column=0, padx=5, pady=5)
self.low_level_status_label = tk.Label(inputs_frame, text='N/A')
self.low_level_status_label.grid(row=1, column=1, padx=5, pady=5)
medium_level_label = tk.Label(inputs_frame, text='Medium level sensor')
medium_level_label.grid(row=2, column=0, padx=5, pady=5)
self.medium_level_status_label = tk.Label(inputs_frame, text='N/A')
self.medium_level_status_label.grid(row=2, column=1, padx=5, pady=5)
high_level_label = tk.Label(inputs_frame, text='High level sensor')
high_level_label.grid(row=3, column=0, padx=5, pady=5)
self.high_level_status_label = tk.Label(inputs_frame, text='N/A')
self.high_level_status_label.grid(row=3, column=1, padx=5, pady=5)
outputs_frame = tk.LabelFrame(self, text='Outputs')
outputs_frame.pack(side="top", fill="both", expand=True, padx=10, pady=10)
inlet_1_label = tk.Label(outputs_frame, text='Inlet 1 valve (material A)')
inlet_1_label.grid(row=0, column=0, padx=5, pady=5)
self.inlet_1_status_label = tk.Label(outputs_frame, text='N/A')
self.inlet_1_status_label.grid(row=0, column=1, padx=5, pady=5)
inlet_2_label = tk.Label(outputs_frame, text='Inlet 2 valve (material B)')
inlet_2_label.grid(row=1, column=0, padx=5, pady=5)
self.inlet_2_status_label = tk.Label(outputs_frame, text='N/A')
self.inlet_2_status_label.grid(row=1, column=1, padx=5, pady=5)
inlet_3_label = tk.Label(outputs_frame, text='Inlet 3 valve (material C)')
inlet_3_label.grid(row=2, column=0, padx=5, pady=5)
self.inlet_3_status_label = tk.Label(outputs_frame, text='N/A')
self.inlet_3_status_label.grid(row=2, column=1, padx=5, pady=5)
sti
ing_label = tk.Label(outputs_frame, text='Sti
ing')
sti
ing_label.grid(row=3, column=0, padx=5, pady=5)
self.sti
ing_status_label = tk.Label(outputs_frame, text='N/A')
self.sti
ing_status_label.grid(row=3, column=1, padx=5, pady=5)
outlet_label = tk.Label(outputs_frame, text='Outlet valve')
outlet_label.grid(row=4, column=0, padx=5, pady=5)
self.outlet_status_label = tk.Label(outputs_frame, text='N/A')
self.outlet_status_label.grid(row=4, column=1, padx=5, pady=5)
self.protocol("WM_DELETE_WINDOW", self.__disconnect_opcua_server__)
self.__connect_opcua_server__()

def __connect_opcua_server__(self):
logging.basicConfig(level=logging.WARN)
self.client = Client("opc.tcp:
localhost:4840/freeopcua/serve
")
try:
self.client.connect()
root = self.client.get_root_node()
handler = SubHandler(self)
sub = self.client.create_subscription(500, handler)
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.0"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.1"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.2"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.3"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.0"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.1"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.2"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.3"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.4"]))
except:
raise
tkMessageBox.showe
or("E
or", "Cannot connect to Open PLC server!")
self.destroy()
return
def __disconnect_opcua_server__(self):
try:
self.client.disconnect()
self.destroy()
except:
pass
def update_val(self, variable_name, value):
print("Update {} with {}".format(variable_name, value))
if variable_name == 'empty_level':
self.empty_level_status_label.config(text=value)
elif variable_name == 'low_level':
self.low_level_status_label.config(text=value)
elif variable_name == 'medium_level':
self.medium_level_status_label.config(text=value)
elif variable_name == 'high_level':
self.high_level_status_label.config(text=value)
elif variable_name == 'inlet_1':
self.inlet_1_status_label.config(text=value)
elif variable_name == 'inlet_2':
self.inlet_2_status_label.config(text=value)
elif variable_name == 'inlet_3':
self.inlet_3_status_label.config(text=value)
elif variable_name == 'sti
ing':
self.sti
ing_status_label.config(text=value)
elif variable_name == 'outlet':
self.outlet_status_label.config(text=value)
class SubHandler(object):
"""
Subscription Handler. To receive events from server for a subscription
data_change and event methods are called directly from receiving thread.
Do not do expensive, slow or network operation there. Create anothe
thread if you need to do such a thing
"""
def __init__(self, gui):
object.__init__(self)
self.gui = gui
self.values = {}
def datachange_notification(self, node, val, data):
print("New data change event", node, val)
try:
nodeid = str(node.nodeid).split('=')[-1].strip(')')
self.values[nodeid] = val
if nodeid == '2': # Empty level senso
self.gui.update_val("empty_level", str(val))
elif nodeid == '4': # Low level senso
self.gui.update_val("low_level", str(val))
elif nodeid == '6': # Medium level senso
self.gui.update_val("medium_level", str(val))
elif nodeid == '8': # High level senso
self.gui.update_val("high_level", str(val))
elif nodeid == "3": # Inlet 1
self.gui.update_val("inlet_1", str(val))
elif nodeid == "5": # Inlet 2
self.gui.update_val("inlet_2", str(val))
elif nodeid == "7": # Inlet 3
self.gui.update_val("inlet_3", str(val))
elif nodeid == "9": # Sti
ing
self.gui.update_val("sti
ing", str(val))
elif nodeid == "11": # Outlet
self.gui.update_val("outlet", str(val))
except:
pass
def event_notification(self, event):
print("New event", event)
app = GUI()
app.mainloop()
PLC Assignment/HMI/Sti
ingSystem/libOPCUA.so
PLC Assignment/HMI/Sti
ingSystem/libopen62541.so
PLC Assignment/HMI/Sti
ingSystem/License.txt
Software Credits and Copyrights
clapack
Copyright (c) 1992-2008 The University of Tennessee. All rights reserved.
$COPYRIGHT$
Additional copyrights may follow
$HEADER$
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer listed
in this license in the documentation and/or other materials
provided with the distribution.

- Neither the name of the copyright holders nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ddassl.f
This software includes ddassl.f, which is in the public domain and can be
downloaded at http:
www.netlib.org/ode/. Used and distributed with permission
of the author.
Expat
Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
and Clark Coope
Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Expat maintainers.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FMI Li
ary (FMIL)
Copyright (C) 2012 Modelon AB
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Modelon AB nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL MODELON AB BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
LINPACK
Developed by Jack Donga
a, Jim Bunch, Cleve Moler and Pete Stewart.
1 Feb 84
Minpack
Minpack Copyright Notice (1999) University of Chicago. All rights reserved
Redistribution and use in source and binary forms, with o
without modification, are permitted provided that the
following conditions are met:
1. Redistributions of source code must retain the above
copyright notice, this list of conditions and the following
disclaimer.
2. Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials
provided with the distribution.
3. The end-user documentation included with the
edistribution, if any, must include the following
acknowledgment:
"This product includes software developed by the
University of Chicago, as Operator of Argonne National
Laboratory.
Alternately, this acknowledgment may appear in the software
itself, if and wherever such third-party acknowledgments
normally appear.
4. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS"
WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT HOLDER, THE
UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND
THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE
OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY
OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR
USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF
THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4)
DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION
UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL
BE CORRECTED.
5. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT
HOLDER, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF
ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT,
INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF
ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS OF
PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER
SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT
(INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE,
EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE
POSSIBILITY OF SUCH LOSS OR DAMAGES.
Nelder-Mead
! Fortran 90 conversion by Alan Miller, June 1995
! Alan.Miller @ vic.cmis.csiro.au
Public doman.
NEWUOA
This software includes newuoa Fortran code, Copyright "Mike Powell" . Distributed with permission of the author.
strsep.c
Copyright (c) 1990, 1993
The Regents of the University of California. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
SUNDIALS
Copyright © 2002, The Regents of the University of California.
Produced at the Lawrence Livermore National Laboratory.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the disclaimer below.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer (as noted below) in the
documentation and/or other materials provided with the distribution.
- Neither the name of the UC/LLNL nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA, THE
U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Additional BSD Notice
- This notice is required to be provided under our contract with the U.S.
Department of Energy (DOE). This work was produced at the University of
California, Lawrence Livermore National Laboratory under Contract No.
W-7405-ENG-48 with the DOE.
- Neither the United States Government nor the University of California no
any of their employees, makes any wa
anty, express or implied, o
assumes any liability or responsibility for the accuracy, completeness,
or usefulness of any information, apparatus, product, or process
disclosed, or represents that its use would not infringe privately-owned
rights.
- Also, reference herein to any specific commercial products, process, o
services by trade name, trademark, manufacturer or otherwise does not
necessarily constitute or imply its endorsement, recommendation, o
favoring by the United States Government or the University of California.
The views and opinions of authors expressed herein do not necessarily
state or reflect those of the United States Government or the University
of California, and shall not be used for advertising or product
endorsement purposes.
SuperLU
Copyright (c) 2003, The Regents of the University of California, through
Lawrence Berkeley National Laboratory (subject to receipt of any required
approvals from U.S. Dept. of Energy)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
(1) Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
(3) Neither the name of Lawrence Berkeley National Laboratory, U.S. Dept. of
Energy nor the names of its contributors may be used to endorse or promote
products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
PLC Assignment/HMI/Sti
ingSystem/ProcessSimulato
PLC Assignment/HMI/Sti
ingSystem
un.sh
#!
in/sh
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
echo "Running sti
ing system simulator"
./ProcessSimulator -f config.sim
dev/null 2>&1
echo "Disconnected from the PLC server"
PLC Assignment/HMI/Sti
ingSystem2/config.sim






























































































































































PLC Assignment/HMI/Sti
ingSystem2/hmi.py
#!/us
in/env python
import matplotli
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
from matplotlib import colors
plt.ion()
import numpy as np
import time
import numpy
import logging
import threading
from Queue import Queue
import Tkinter as tk
import tkMessageBox
from opcua import Client, ua
color_palettes = colors.cnames.keys()
class GUI(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.wm_title("HMI")
inputs_frame = tk.LabelFrame(self, text='Inputs')
inputs_frame.pack(side="top", fill="both", expand=True, padx=10, pady=10)
empty_level_label = tk.Label(inputs_frame, text='Empty level sensor')
empty_level_label.grid(row=0, column=0, padx=5, pady=5)
self.empty_level_status_label = tk.Label(inputs_frame, text='N/A')
self.empty_level_status_label.grid(row=0, column=1, padx=5, pady=5)
low_level_label = tk.Label(inputs_frame, text='Low level sensor')
low_level_label.grid(row=1, column=0, padx=5, pady=5)
self.low_level_status_label = tk.Label(inputs_frame, text='N/A')
self.low_level_status_label.grid(row=1, column=1, padx=5, pady=5)
medium_level_label = tk.Label(inputs_frame, text='Medium level sensor')
medium_level_label.grid(row=2, column=0, padx=5, pady=5)
self.medium_level_status_label = tk.Label(inputs_frame, text='N/A')
self.medium_level_status_label.grid(row=2, column=1, padx=5, pady=5)
high_level_label = tk.Label(inputs_frame, text='High level sensor')
high_level_label.grid(row=3, column=0, padx=5, pady=5)
self.high_level_status_label = tk.Label(inputs_frame, text='N/A')
self.high_level_status_label.grid(row=3, column=1, padx=5, pady=5)
outputs_frame = tk.LabelFrame(self, text='Outputs')
outputs_frame.pack(side="top", fill="both", expand=True, padx=10, pady=10)
inlet_1_label = tk.Label(outputs_frame, text='Inlet 1 valve (material A)')
inlet_1_label.grid(row=0, column=0, padx=5, pady=5)
self.inlet_1_status_label = tk.Label(outputs_frame, text='N/A')
self.inlet_1_status_label.grid(row=0, column=1, padx=5, pady=5)
inlet_2_label = tk.Label(outputs_frame, text='Inlet 2 valve (material B)')
inlet_2_label.grid(row=1, column=0, padx=5, pady=5)
self.inlet_2_status_label = tk.Label(outputs_frame, text='N/A')
self.inlet_2_status_label.grid(row=1, column=1, padx=5, pady=5)
inlet_3_label = tk.Label(outputs_frame, text='Inlet 3 valve (material C)')
inlet_3_label.grid(row=2, column=0, padx=5, pady=5)
self.inlet_3_status_label = tk.Label(outputs_frame, text='N/A')
self.inlet_3_status_label.grid(row=2, column=1, padx=5, pady=5)
sti
ing_label = tk.Label(outputs_frame, text='Sti
ing')
sti
ing_label.grid(row=3, column=0, padx=5, pady=5)
self.sti
ing_status_label = tk.Label(outputs_frame, text='N/A')
self.sti
ing_status_label.grid(row=3, column=1, padx=5, pady=5)
outlet_label = tk.Label(outputs_frame, text='Outlet valve')
outlet_label.grid(row=4, column=0, padx=5, pady=5)
self.outlet_status_label = tk.Label(outputs_frame, text='N/A')
self.outlet_status_label.grid(row=4, column=1, padx=5, pady=5)
self.protocol("WM_DELETE_WINDOW", self.__disconnect_opcua_server__)
self.__connect_opcua_server__()

def __connect_opcua_server__(self):
logging.basicConfig(level=logging.WARN)
self.client = Client("opc.tcp:
localhost:4840/freeopcua/serve
")
try:
self.client.connect()
root = self.client.get_root_node()
handler = SubHandler(self)
sub = self.client.create_subscription(500, handler)
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.0"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.1"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.2"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.3"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.0"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.1"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.2"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.3"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.4"]))
except:
raise
tkMessageBox.showe
or("E
or", "Cannot connect to Open PLC server!")
self.destroy()
return
def __disconnect_opcua_server__(self):
try:
self.client.disconnect()
self.destroy()
except:
pass
def update_val(self, variable_name, value):
print("Update {} with {}".format(variable_name, value))
if variable_name == 'empty_level':
self.empty_level_status_label.config(text=value)
elif variable_name == 'low_level':
self.low_level_status_label.config(text=value)
elif variable_name == 'medium_level':
self.medium_level_status_label.config(text=value)
elif variable_name == 'high_level':
self.high_level_status_label.config(text=value)
elif variable_name == 'inlet_1':
self.inlet_1_status_label.config(text=value)
elif variable_name == 'inlet_2':
self.inlet_2_status_label.config(text=value)
elif variable_name == 'inlet_3':
self.inlet_3_status_label.config(text=value)
elif variable_name == 'sti
ing':
self.sti
ing_status_label.config(text=value)
elif variable_name == 'outlet':
self.outlet_status_label.config(text=value)
class SubHandler(object):
"""
Subscription Handler. To receive events from server for a subscription
data_change and event methods are called directly from receiving thread.
Do not do expensive, slow or network operation there. Create anothe
thread if you need to do such a thing
"""
def __init__(self, gui):
object.__init__(self)
self.gui = gui
self.values = {}
def datachange_notification(self, node, val, data):
print("New data change event", node, val)
try:
nodeid = str(node.nodeid).split('=')[-1].strip(')')
self.values[nodeid] = val
if nodeid == '2': # Empty level senso
self.gui.update_val("empty_level", str(val))
elif nodeid == '4': # Low level senso
self.gui.update_val("low_level", str(val))
elif nodeid == '6': # Medium level senso
self.gui.update_val("medium_level", str(val))
elif nodeid == '8': # High level senso
self.gui.update_val("high_level", str(val))
elif nodeid == "3": # Inlet 1
self.gui.update_val("inlet_1", str(val))
elif nodeid == "5": # Inlet 2
self.gui.update_val("inlet_2", str(val))
elif nodeid == "7": # Inlet 3
self.gui.update_val("inlet_3", str(val))
elif nodeid == "9": # Sti
ing
self.gui.update_val("sti
ing", str(val))
elif nodeid == "11": # Outlet
self.gui.update_val("outlet", str(val))
except:
pass
def event_notification(self, event):
print("New event", event)
app = GUI()
app.mainloop()
PLC Assignment/HMI/Sti
ingSystem2/hmi-stir.py
#!/us
in/env python
import matplotli
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
from matplotlib import colors
plt.ion()
import numpy as np
import time
import numpy
import logging
import threading
from Queue import Queue
import Tkinter as tk
import tkMessageBox
from PIL import ImageTk, Image
from opcua import Client, ua
color_palettes = colors.cnames.keys()
class GUI(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.wm_title("HMI")
diagram_frame = tk.LabelFrame(self, text='Diagram')
diagram_frame.pack(side="left", fill="both", expand=False, padx=10, pady=10)
# Tank
self.canvas = tk.Canvas(diagram_frame, width=500, height=500)
self.canvas.create_rectangle(30, 250, 300, 450)
# Pipes
self.canvas.create_line(50, 250, 50, 60, width=2)
self.canvas.create_line(70, 250, 70, 110, width=2)
self.canvas.create_line(90, 250, 90, 160, width=2)
# self.canvas.create_line(110, 250, 110, 210, width=2)
self.canvas.create_line(50, 60, 300, 60, width=2)
self.canvas.create_line(70, 110, 300, 110, width=2)
self.canvas.create_line(90, 160, 300, 160, width=2)
# self.canvas.create_line(110, 210, 300, 210, width=2)
self.canvas.create_line(300, 410, 490, 410, width=2)
# Valves
self.valve1 = ImageTk.PhotoImage(Image.open("vlv-red.png"))
self.valveid1 = self.canvas.create_image(200, 50, image=self.valve1)
self.valve2 = ImageTk.PhotoImage(Image.open("vlv-red.png"))
self.valveid2 = self.canvas.create_image(200, 100, image=self.valve2)
self.valve3 = ImageTk.PhotoImage(Image.open("vlv-red.png"))
self.valveid3 = self.canvas.create_image(200, 150, image=self.valve3)
# self.valve4 = ImageTk.PhotoImage(Image.open("vlv-red.png"))
# self.canvas.create_image(200, 200, image=self.valve4)
self.outlet = ImageTk.PhotoImage(Image.open("vlv-red.png"))
self.outletid = self.canvas.create_image(400, 401, image=self.outlet)
self.mixer = ImageTk.PhotoImage(Image.open("stir.png"))
self.canvas.create_image(165, 340, image=self.mixer)
    # Initialize dynamic values
self.emptyid = 0
self.lowid = 0
self.highid = 0
self.medid = 0
self.mixing = self.canvas.create_line(150, 310, 120, 320, 165, 330, 210, 320, 180, 310, a
ow=tk.LAST, fill="darkgreen", width=4, smooth="true")
self.canvas.pack(fill="both", expand=False)
inputs_frame = tk.LabelFrame(self, text='Inputs')
inputs_frame.pack(side="top", fill="both", expand=True, padx=10, pady=10)
empty_level_label = tk.Label(inputs_frame, text='Empty level sensor')
empty_level_label.grid(row=0, column=0, padx=5, pady=5)
self.empty_level_status_label = tk.Label(inputs_frame, text='N/A')
self.empty_level_status_label.grid(row=0, column=1, padx=5, pady=5)
low_level_label = tk.Label(inputs_frame, text='Low level sensor')
low_level_label.grid(row=1, column=0, padx=5, pady=5)
self.low_level_status_label = tk.Label(inputs_frame, text='N/A')
self.low_level_status_label.grid(row=1, column=1, padx=5, pady=5)
medium_level_label = tk.Label(inputs_frame, text='Medium level sensor')
medium_level_label.grid(row=2, column=0, padx=5, pady=5)
self.medium_level_status_label = tk.Label(inputs_frame, text='N/A')
self.medium_level_status_label.grid(row=2, column=1, padx=5, pady=5)
high_level_label = tk.Label(inputs_frame, text='High level sensor')
high_level_label.grid(row=3, column=0, padx=5, pady=5)
self.high_level_status_label = tk.Label(inputs_frame, text='N/A')
self.high_level_status_label.grid(row=3, column=1, padx=5, pady=5)
outputs_frame = tk.LabelFrame(self, text='Outputs')
outputs_frame.pack(side="top", fill="both", expand=True, padx=10, pady=10)
inlet_1_label = tk.Label(outputs_frame, text='Inlet 1 valve (material A)')
inlet_1_label.grid(row=0, column=0, padx=5, pady=5)
self.inlet_1_status_label = tk.Label(outputs_frame, text='N/A')
self.inlet_1_status_label.grid(row=0, column=1, padx=5, pady=5)
inlet_2_label = tk.Label(outputs_frame, text='Inlet 2 valve (material B)')
inlet_2_label.grid(row=1, column=0, padx=5, pady=5)
self.inlet_2_status_label = tk.Label(outputs_frame, text='N/A')
self.inlet_2_status_label.grid(row=1, column=1, padx=5, pady=5)
inlet_3_label = tk.Label(outputs_frame, text='Inlet 3 valve (material C)')
inlet_3_label.grid(row=2, column=0, padx=5, pady=5)
self.inlet_3_status_label = tk.Label(outputs_frame, text='N/A')
self.inlet_3_status_label.grid(row=2, column=1, padx=5, pady=5)
sti
ing_label = tk.Label(outputs_frame, text='Sti
ing')
sti
ing_label.grid(row=3, column=0, padx=5, pady=5)
self.sti
ing_status_label = tk.Label(outputs_frame, text='N/A')
self.sti
ing_status_label.grid(row=3, column=1, padx=5, pady=5)
outlet_label = tk.Label(outputs_frame, text='Outlet valve')
outlet_label.grid(row=4, column=0, padx=5, pady=5)
self.outlet_status_label = tk.Label(outputs_frame, text='N/A')
self.outlet_status_label.grid(row=4, column=1, padx=5, pady=5)
self.protocol("WM_DELETE_WINDOW", self.__disconnect_opcua_server__)
self.__connect_opcua_server__()
def __connect_opcua_server__(self):
logging.basicConfig(level=logging.WARN)
self.client = Client("opc.tcp:
localhost:4840/freeopcua/serve
")
try:
self.client.connect()
root = self.client.get_root_node()
handler = SubHandler(self)
sub = self.client.create_subscription(500, handler)
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.0"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.1"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.2"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.3"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.0"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.1"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.2"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.3"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.4"]))
except:
raise
tkMessageBox.showe
or("E
or", "Cannot connect to Open PLC server!")
self.destroy()
return
def __disconnect_opcua_server__(self):
try:
self.client.disconnect()
self.destroy()
except:
pass
def update_val(self, variable_name, value):
print("Update {} with {}".format(variable_name, value))
if variable_name == 'empty_level':
self.empty_level_status_label.config(text=value)
elif variable_name == 'low_level':
self.low_level_status_label.config(text=value)
elif variable_name == 'medium_level':
self.medium_level_status_label.config(text=value)
elif variable_name == 'high_level':
self.high_level_status_label.config(text=value)
elif variable_name == 'inlet_1':
self.inlet_1_status_label.config(text=value)
elif variable_name == 'inlet_2':
self.inlet_2_status_label.config(text=value)
elif variable_name == 'inlet_3':
self.inlet_3_status_label.config(text=value)
elif variable_name == 'sti
ing':
self.sti
ing_status_label.config(text=value)
elif variable_name == 'outlet':
self.outlet_status_label.config(text=value)
def update_valve(self, valveid, value):
# print("VALVE: Update {} with {}".format(valveid, value))
img = "vlv-grn.png" if value == "True" else "vlv-red.png"
x = int(self.canvas.coords(valveid)[0])
y = int(self.canvas.coords(valveid)[1])
self.canvas.delete(valveid)
valveobj = ImageTk.PhotoImage(Image.open(img))
id = self.canvas.create_image(x, y, image=valveobj)
return id, valveobj
def update_mixer(self, value):
# print("MIXER: Mixer {}".format(value))
if value == "True":
# Mixer On
self.mixing = self.canvas.create_line(150, 310, 120, 320, 165, 330, 210, 320, 180, 310, a
ow=tk.LAST, fill="darkgreen", width=4, smooth="true")
else:
# Mixer Off
self.canvas.delete(self.mixing)

def update_level(self, id, hi, lo, value):
# print("LEVEL: Level {} {}".format(lo, hi))
# 25% level = 40px
self.canvas.delete(id)
if value == "True":
levelid = self.canvas.create_rectangle(50, lo, 65, hi, fill="steel blue")
else:
levelid = self.canvas.create_rectangle(50, lo, 65, lo - 3, fill="steel blue")
return levelid
class SubHandler(object):
"""
Subscription Handler. To receive events from server for a subscription
data_change and event methods are called directly from receiving thread.
Do not do expensive, slow or network operation there. Create anothe
thread if you need to do such a thing
"""
def __init__(self, gui):
object.__init__(self)
self.gui = gui
self.values = {}
def datachange_notification(self, node, val, data):
print("New data change event", node, val)
try:
nodeid = str(node.nodeid).split('=')[-1].strip(')')
self.values[nodeid] = val
if nodeid == '2': # Empty level senso
self.gui.update_val("empty_level", str(val))
self.gui.emptyid = self.gui.update_level(self.gui.emptyid, 430, 395, str(val))
elif nodeid == '4': # Low level senso
self.gui.update_val("low_level", str(val))
self.gui.lowid = self.gui.update_level(self.gui.lowid, 390, 355, str(val))
elif nodeid == '6': # Medium level senso
self.gui.update_val("medium_level", str(val))
self.gui.medid = self.gui.update_level(self.gui.medid, 350, 315, str(val))
elif nodeid == '8': # High level senso
self.gui.update_val("high_level", str(val))
self.gui.highid = self.gui.update_level(self.gui.highid, 310, 270, str(val))
elif nodeid == "3": # Inlet 1
self.gui.update_val("inlet_1", str(val))
self.gui.valveid1, self.gui.valve1 = self.gui.update_valve(self.gui.valveid1, str(val))
elif nodeid == "5": # Inlet 2
self.gui.update_val("inlet_2", str(val))
self.gui.valveid2, self.gui.valve2 = self.gui.update_valve(self.gui.valveid2, str(val))
elif nodeid == "7": # Inlet 3
self.gui.update_val("inlet_3", str(val))
self.gui.valveid3, self.gui.valve3 = self.gui.update_valve(self.gui.valveid3, str(val))
elif nodeid == "9": # Sti
ing
self.gui.update_val("sti
ing", str(val))
self.gui.update_mixer(str(val))
elif nodeid == "11": # Outlet
self.gui.update_val("outlet", str(val))
self.gui.outletid, self.gui.outlet = self.gui.update_valve(self.gui.outletid, str(val))
except Exception as e:
print "Unexpected e
or: {}".format(e.message)
pass
def event_notification(self, event):
print("New event", event)
app = GUI()
app.mainloop()
PLC Assignment/HMI/Sti
ingSystem2/libOPCUA.so
PLC Assignment/HMI/Sti
ingSystem2/libopen62541.so
PLC Assignment/HMI/Sti
ingSystem2/License.txt
Software Credits and Copyrights
clapack
Copyright (c) 1992-2008 The University of Tennessee. All rights reserved.
$COPYRIGHT$
Additional copyrights may follow
$HEADER$
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer listed
in this license in the documentation and/or other materials
provided with the distribution.

- Neither the name of the copyright holders nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ddassl.f
This software includes ddassl.f, which is in the public domain and can be
downloaded at http:
www.netlib.org/ode/. Used and distributed with permission
of the author.
Expat
Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
and Clark Coope
Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Expat maintainers.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FMI Li
ary (FMIL)
Copyright (C) 2012 Modelon AB
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Modelon AB nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL MODELON AB BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
LINPACK
Developed by Jack Donga
a, Jim Bunch, Cleve Moler and Pete Stewart.
1 Feb 84
Minpack
Minpack Copyright Notice (1999) University of Chicago. All rights reserved
Redistribution and use in source and binary forms, with o
without modification, are permitted provided that the
following conditions are met:
1. Redistributions of source code must retain the above
copyright notice, this list of conditions and the following
disclaimer.
2. Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials
provided with the distribution.
3. The end-user documentation included with the
edistribution, if any, must include the following
acknowledgment:
"This product includes software developed by the
University of Chicago, as Operator of Argonne National
Laboratory.
Alternately, this acknowledgment may appear in the software
itself, if and wherever such third-party acknowledgments
normally appear.
4. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS"
WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT HOLDER, THE
UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND
THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE
OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY
OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR
USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF
THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4)
DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION
UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL
BE CORRECTED.
5. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT
HOLDER, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF
ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT,
INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF
ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS OF
PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER
SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT
(INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE,
EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE
POSSIBILITY OF SUCH LOSS OR DAMAGES.
Nelder-Mead
! Fortran 90 conversion by Alan Miller, June 1995
! Alan.Miller @ vic.cmis.csiro.au
Public doman.
NEWUOA
This software includes newuoa Fortran code, Copyright "Mike Powell" . Distributed with permission of the author.
strsep.c
Copyright (c) 1990, 1993
The Regents of the University of California. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
SUNDIALS
Copyright © 2002, The Regents of the University of California.
Produced at the Lawrence Livermore National Laboratory.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the disclaimer below.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer (as noted below) in the
documentation and/or other materials provided with the distribution.
- Neither the name of the UC/LLNL nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA, THE
U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Additional BSD Notice
- This notice is required to be provided under our contract with the U.S.
Department of Energy (DOE). This work was produced at the University of
California, Lawrence Livermore National Laboratory under Contract No.
W-7405-ENG-48 with the DOE.
- Neither the United States Government nor the University of California no
any of their employees, makes any wa
anty, express or implied, o
assumes any liability or responsibility for the accuracy, completeness,
or usefulness of any information, apparatus, product, or process
disclosed, or represents that its use would not infringe privately-owned
rights.
- Also, reference herein to any specific commercial products, process, o
services by trade name, trademark, manufacturer or otherwise does not
necessarily constitute or imply its endorsement, recommendation, o
favoring by the United States Government or the University of California.
The views and opinions of authors expressed herein do not necessarily
state or reflect those of the United States Government or the University
of California, and shall not be used for advertising or product
endorsement purposes.
SuperLU
Copyright (c) 2003, The Regents of the University of California, through
Lawrence Berkeley National Laboratory (subject to receipt of any required
approvals from U.S. Dept. of Energy)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
(1) Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
(3) Neither the name of Lawrence Berkeley National Laboratory, U.S. Dept. of
Energy nor the names of its contributors may be used to endorse or promote
products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
PLC Assignment/HMI/Sti
ingSystem2/ProcessSimulato
PLC Assignment/HMI/Sti
ingSystem2
un.sh
#!
in/sh
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
echo "Running sti
ing system simulator"
./ProcessSimulator -f config.sim
dev/null 2>&1
echo "Disconnected from the PLC server"
PLC Assignment/HMI/Sti
ingSystem2/stir.png
PLC Assignment/HMI/Sti
ingSystem2/vlv-grn.png
PLC Assignment/HMI/Sti
ingSystem2/vlv-red.png
PLC Assignment/HMI/TankBalance
config.sim













































































































































































































































































































































































PLC Assignment/HMI/TankBalance
hmi.py
#!/us
in/env python
import matplotli
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
from matplotlib import colors
plt.ion()
import numpy as np
import time
import numpy
import logging
import threading
from Queue import Queue
import Tkinter as tk
import tkMessageBox
from opcua import Client, ua
color_palettes = colors.cnames.keys()
class GUI(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.wm_title("HMI")
inputs_frame = tk.LabelFrame(self, text='Inputs')
inputs_frame.pack(side="top", fill="both", expand=True, padx=10, pady=10)
tank1_level_label = tk.Label(inputs_frame, text='Tank 1 level')
tank1_level_label.grid(row=0, column=0, padx=5, pady=5)
self.tank1_level_status_label = tk.Label(inputs_frame, text='N/A')
self.tank1_level_status_label.grid(row=0, column=1, padx=5, pady=5)
tank2_level_label = tk.Label(inputs_frame, text='Tank 2 level')
tank2_level_label.grid(row=1, column=0, padx=5, pady=5)
self.tank2_level_status_label = tk.Label(inputs_frame, text='N/A')
self.tank2_level_status_label.grid(row=1, column=1, padx=5, pady=5)
tank3_level_label = tk.Label(inputs_frame, text='Tank 3 level')
tank3_level_label.grid(row=2, column=0, padx=5, pady=5)
self.tank3_level_status_label = tk.Label(inputs_frame, text='N/A')
self.tank3_level_status_label.grid(row=2, column=1, padx=5, pady=5)
tank4_level_label = tk.Label(inputs_frame, text='Tank 4 level')
tank4_level_label.grid(row=3, column=0, padx=5, pady=5)
self.tank4_level_status_label = tk.Label(inputs_frame, text='N/A')
self.tank4_level_status_label.grid(row=3, column=1, padx=5, pady=5)
outputs_frame = tk.LabelFrame(self, text='Outputs')
outputs_frame.pack(side="top", fill="both", expand=True, padx=10, pady=10)
tank1_outlet_label = tk.Label(outputs_frame, text='Tank 1 outlet valve')
tank1_outlet_label.grid(row=0, column=0, padx=5, pady=5)
self.tank1_outlet_status_label = tk.Label(outputs_frame, text='N/A')
self.tank1_outlet_status_label.grid(row=0, column=1, padx=5, pady=5)
tank2_outlet_label = tk.Label(outputs_frame, text='Tank 2 outlet valve')
tank2_outlet_label.grid(row=1, column=0, padx=5, pady=5)
self.tank2_outlet_status_label = tk.Label(outputs_frame, text='N/A')
self.tank2_outlet_status_label.grid(row=1, column=1, padx=5, pady=5)
tank3_outlet_label = tk.Label(outputs_frame, text='Tank 3 outlet valve')
tank3_outlet_label.grid(row=2, column=0, padx=5, pady=5)
self.tank3_outlet_status_label = tk.Label(outputs_frame, text='N/A')
self.tank3_outlet_status_label.grid(row=2, column=1, padx=5, pady=5)
tank4_outlet_label = tk.Label(outputs_frame, text='Tank 4 outlet valve')
tank4_outlet_label.grid(row=3, column=0, padx=5, pady=5)
self.tank4_outlet_status_label = tk.Label(outputs_frame, text='N/A')
self.tank4_outlet_status_label.grid(row=3, column=1, padx=5, pady=5)
self.protocol("WM_DELETE_WINDOW", self.__disconnect_opcua_server__)
self.__connect_opcua_server__()

def __connect_opcua_server__(self):
logging.basicConfig(level=logging.WARN)
self.client = Client("opc.tcp:
localhost:4840/freeopcua/serve
")
try:
self.client.connect()
root = self.client.get_root_node()
handler = SubHandler(self)
sub = self.client.create_subscription(500, handler)
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.0"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.1"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.2"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.3"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.4"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.5"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.6"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.7"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX1.0"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX1.1"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX1.2"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX1.3"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.0"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.1"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.2"]))
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.3"]))
except:
tkMessageBox.showe
or("E
or", "Cannot connect to Open PLC server!")
self.destroy()
return
def __disconnect_opcua_server__(self):
try:
self.client.disconnect()
self.destroy()
except:
pass
def update_val(self, variable_name, value):
print("Update {} with {}".format(variable_name, value))
if variable_name == 'tank1_level':
self.tank1_level_status_label.config(text=value)
elif variable_name == 'tank2_level':
self.tank2_level_status_label.config(text=value)
elif variable_name == 'tank3_level':
self.tank3_level_status_label.config(text=value)
elif variable_name == 'tank4_level':
self.tank4_level_status_label.config(text=value)
elif variable_name == 'tank1_outlet':
self.tank1_outlet_status_label.config(text=value)
elif variable_name == 'tank2_outlet':
self.tank2_outlet_status_label.config(text=value)
elif variable_name == 'tank3_outlet':
self.tank3_outlet_status_label.config(text=value)
elif variable_name == 'tank4_outlet':
self.tank4_outlet_status_label.config(text=value)
class SubHandler(object):
"""
Subscription Handler. To receive events from server for a subscription
data_change and event methods are called directly from receiving thread.
Do not do expensive, slow or network operation there. Create anothe
thread if you need to do such a thing
"""
def __init__(self, gui):
object.__init__(self)
self.gui = gui
self.values = {}
def datachange_notification(self, node, val, data):
print("New data change event", node, val)
def convert_to_level(low_sensor, medium_sensor, high_sensor):
if not low_sensor:
return "below low"
elif not medium_sensor:
return "low to medium"
elif not high_sensor:
return "medium to high"
else:
return "above high"
try:
nodeid = str(node.nodeid).split('=')[-1].strip(')')
self.values[nodeid] = val
if nodeid in {'2', '4', '6'}: # Tank 1 sensors
self.gui.update_val("tank1_level", convert_to_level(self.values['2'], self.values['4'], self.values['6']))
elif nodeid in {'8', '10', '12'}: # Tank 2 sensors
self.gui.update_val("tank2_level", convert_to_level(self.values['8'], self.values['10'], self.values['12']))
elif nodeid in {'14', '16', '20'}: # Tank 3 sensors
self.gui.update_val("tank3_level", convert_to_level(self.values['14'], self.values['16'], self.values['20']))
elif nodeid in {'22', '24', '26'}: # Tank 4 sensors
self.gui.update_val("tank4_level", convert_to_level(self.values['22'], self.values['24'], self.values['26']))
elif nodeid == "3": # Tank 1 outlet valve
self.gui.update_val("tank1_outlet", "Open" if val else "Closed")
elif nodeid == "5": # Tank 2 outlet valve
self.gui.update_val("tank2_outlet", "Open" if val else "Closed")
elif nodeid == "7": # Tank 3 outlet valve
self.gui.update_val("tank3_outlet", "Open" if val else "Closed")
elif nodeid == "9": # Tank 4 outlet valve
self.gui.update_val("tank4_outlet", "Open" if val else "Closed")
except:
pass
def event_notification(self, event):
print("New event", event)
app = GUI()
app.mainloop()
PLC Assignment/HMI/TankBalance
libOPCUA.so
PLC Assignment/HMI/TankBalance
libopen62541.so
PLC Assignment/HMI/TankBalance
License.txt
Software Credits and Copyrights
clapack
Copyright (c) 1992-2008 The University of Tennessee. All rights reserved.
$COPYRIGHT$
Additional copyrights may follow
$HEADER$
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer listed
in this license in the documentation and/or other materials
provided with the distribution.

- Neither the name of the copyright holders nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ddassl.f
This software includes ddassl.f, which is in the public domain and can be
downloaded at http:
www.netlib.org/ode/. Used and distributed with permission
of the author.
Expat
Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
and Clark Coope
Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Expat maintainers.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FMI Li
ary (FMIL)
Copyright (C) 2012 Modelon AB
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Modelon AB nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL MODELON AB BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
LINPACK
Developed by Jack Donga
a, Jim Bunch, Cleve Moler and Pete Stewart.
1 Feb 84
Minpack
Minpack Copyright Notice (1999) University of Chicago. All rights reserved
Redistribution and use in source and binary forms, with o
without modification, are permitted provided that the
following conditions are met:
1. Redistributions of source code must retain the above
copyright notice, this list of conditions and the following
disclaimer.
2. Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials
provided with the distribution.
3. The end-user documentation included with the
edistribution, if any, must include the following
acknowledgment:
"This product includes software developed by the
University of Chicago, as Operator of Argonne National
Laboratory.
Alternately, this acknowledgment may appear in the software
itself, if and wherever such third-party acknowledgments
normally appear.
4. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS"
WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT HOLDER, THE
UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND
THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE
OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY
OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR
USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF
THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4)
DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION
UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL
BE CORRECTED.
5. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT
HOLDER, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF
ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT,
INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF
ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS OF
PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER
SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT
(INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE,
EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE
POSSIBILITY OF SUCH LOSS OR DAMAGES.
Nelder-Mead
! Fortran 90 conversion by Alan Miller, June 1995
! Alan.Miller @ vic.cmis.csiro.au
Public doman.
NEWUOA
This software includes newuoa Fortran code, Copyright "Mike Powell" . Distributed with permission of the author.
strsep.c
Copyright (c) 1990, 1993
The Regents of the University of California. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
SUNDIALS
Copyright © 2002, The Regents of the University of California.
Produced at the Lawrence Livermore National Laboratory.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the disclaimer below.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer (as noted below) in the
documentation and/or other materials provided with the distribution.
- Neither the name of the UC/LLNL nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA, THE
U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Additional BSD Notice
- This notice is required to be provided under our contract with the U.S.
Department of Energy (DOE). This work was produced at the University of
California, Lawrence Livermore National Laboratory under Contract No.
W-7405-ENG-48 with the DOE.
- Neither the United States Government nor the University of California no
any of their employees, makes any wa
anty, express or implied, o
assumes any liability or responsibility for the accuracy, completeness,
or usefulness of any information, apparatus, product, or process
disclosed, or represents that its use would not infringe privately-owned
rights.
- Also, reference herein to any specific commercial products, process, o
services by trade name, trademark, manufacturer or otherwise does not
necessarily constitute or imply its endorsement, recommendation, o
favoring by the United States Government or the University of California.
The views and opinions of authors expressed herein do not necessarily
state or reflect those of the United States Government or the University
of California, and shall not be used for advertising or product
endorsement purposes.
SuperLU
Copyright (c) 2003, The Regents of the University of California, through
Lawrence Berkeley National Laboratory (subject to receipt of any required
approvals from U.S. Dept. of Energy)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
(1) Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
(3) Neither the name of Lawrence Berkeley National Laboratory, U.S. Dept. of
Energy nor the names of its contributors may be used to endorse or promote
products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
PLC Assignment/HMI/TankBalance
ProcessSimulato
PLC Assignment/HMI/TankBalance
un.sh
#!
in/sh
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
echo "Running tank balancer simulator"
./ProcessSimulator -f config.sim #
dev/null 2>&1
echo "Disconnected from the PLC server"
PLC Assignment/HMI/TrafficLight/car.png
PLC Assignment/HMI/TrafficLight/hmi.py
#!/us
in/env python
import sys
import time
import logging
import Tkinter as tk
from Tkinter import *
import tkMessageBox
from PIL import ImageTk, Image
from opcua import Client, ua
class GUI(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.wm_title("HMI")
diagram_frame = tk.LabelFrame(self, text='Diagram')
diagram_frame.pack(side="left", fill="both", expand=False, padx=10, pady=10)
self.canvas = tk.Canvas(diagram_frame, width=500, height=500)
self.canvas.create_line(0, 200, 500, 200, width=2)
self.canvas.create_line(0, 300, 500, 300, width=2)
self.canvas.create_line(0, 250, 500, 250, width=2, dash=(4,4))
self.canvas.create_line(250, 202, 250, 298, width=50, dash=(4, 4), fill="white")
self.vehicle_red_light_upper = self.canvas.create_oval(280, 235, 290, 245, outline="red")
self.vehicle_yellow_light_upper = self.canvas.create_oval(280, 220, 290, 230, outline="yellow")
self.vehicle_green_light_upper = self.canvas.create_oval(280, 205, 290, 215, outline="green")
self.vehicle_red_light_lower = self.canvas.create_oval(210, 255, 220, 265, outline="red")
self.vehicle_yellow_light_lower = self.canvas.create_oval(210, 270, 220, 280, outline="yellow")
self.vehicle_green_light_lower = self.canvas.create_oval(210, 285, 220, 295, outline="green")
self.pedestrian_red_light_upper = self.canvas.create_oval(255, 185, 265, 195, outline="red")
self.pedestrian_green_light_upper = self.canvas.create_oval(235, 185, 245, 195, outline="green")
self.pedestrian_red_light_lower = self.canvas.create_oval(235, 305, 245, 315, outline="red")
self.pedestrian_green_light_lower = self.canvas.create_oval(255, 305, 265, 315, outline="green")
self.vehicle_sensor_line_upper = self.canvas.create_line(435, 202, 435, 248, dash=(2, 2))
self.canvas.create_text(380, 185, anchor=W, text="Vehicle Sensor")
self.car_image_upper = ImageTk.PhotoImage(Image.open("car.png").resize((73, 23), Image.ANTIALIAS).transpose(Image.FLIP_LEFT_RIGHT))
self.canvas.create_image(292, 212, anchor=NW, image=self.car_image_upper)
self.car_upper = None
self.vehicle_sensor_line_lower = self.canvas.create_line(65, 248, 65, 298, dash=(2, 2))
self.canvas.create_text(30, 310, anchor=W, text="Vehicle Sensor")
self.car_image_lower = ImageTk.PhotoImage(Image.open("car.png").resize((73, 23), Image.ANTIALIAS))
self.canvas.create_image(135, 265, anchor=NW, image=self.car_image_lower)
self.car_lower = None
self.canvas.create_text(20, 20, anchor=W, text="Accidents: ")
self.accident_counter = 0
self.accident_text = self.canvas.create_text(90, 20, anchor=W, text=str(self.accident_counter), fill="green")
self.canvas.pack(fill="both", expand=False)
status_frame = tk.LabelFrame(self, text="Status")
status_frame.pack(side="right", fill="both", expand=False, padx=10, pady=10)
input_frame = tk.LabelFrame(status_frame, text="Input")
input_frame.pack(side="top", fill="both", expand=False, padx=5, pady=5)
vehicle_sensor_label = tk.Label(input_frame, text="Vehicle Sensor")
vehicle_sensor_label.grid(row=0, column=0, padx=5, pady=5)
self.vehicle_sensor_status_label = tk.Label(input_frame, text="")
self.vehicle_sensor_status_label.grid(row=0, column=1, padx=5, pady=5)
pedestrian_button_label = tk.Button(input_frame, text="Pedestrian XING", command=self.__pedestrian_button__)
pedestrian_button_label.grid(row=1, column=0, columnspan=2, padx=5, pady=5)
vehicle_lights_frame = tk.LabelFrame(status_frame, text="Vehicle Lights")
vehicle_lights_frame.pack(side="top", fill="both", expand=False, padx=5, pady=5)
vehicle_red_label = tk.Label(vehicle_lights_frame, text="Red", fg="red")
vehicle_red_label.grid(row=0, column=0, padx=5, pady=5)
self.vehicle_red_status_label = tk.Label(vehicle_lights_frame, text="")
self.vehicle_red_status_label.grid(row=0, column=1, padx=5, pady=5)
vehicle_yellow_label = tk.Label(vehicle_lights_frame, text="Yellow", fg="yellow")
vehicle_yellow_label.grid(row=1, column=0, padx=5, pady=5)
self.vehicle_yellow_status_label = tk.Label(vehicle_lights_frame, text="")
self.vehicle_yellow_status_label.grid(row=1, column=1, padx=5, pady=5)
vehicle_green_label = tk.Label(vehicle_lights_frame, text="Green", fg="green")
vehicle_green_label.grid(row=2, column=0, padx=5, pady=5)
self.vehicle_green_status_label = tk.Label(vehicle_lights_frame, text="")
self.vehicle_green_status_label.grid(row=2, column=1, padx=5, pady=5)
pedestrian_lights_frame = tk.LabelFrame(status_frame, text="Pedestrian Lights")
pedestrian_lights_frame.pack(side="top", fill="both", expand=False, padx=5, pady=5)
pedestrian_red_label = tk.Label(pedestrian_lights_frame, text="Red", fg="red")
pedestrian_red_label.grid(row=0, column=0, padx=5, pady=5)
self.pedestrian_red_status_label = tk.Label(pedestrian_lights_frame, text="")
self.pedestrian_red_status_label.grid(row=0, column=1, padx=5, pady=5)
pedestrian_green_label = tk.Label(pedestrian_lights_frame, text="Green", fg="green")
pedestrian_green_label.grid(row=1, column=0, padx=5, pady=5)
self.pedestrian_green_status_label = tk.Label(pedestrian_lights_frame, text="")
self.pedestrian_green_status_label.grid(row=1, column=1, padx=5, pady=5)
self.protocol("WM_DELETE_WINDOW", self.__disconnect_opcua_server__)
self.__connect_opcua_server__()
def __connect_opcua_server__(self):
logging.basicConfig(level=logging.WARN)
self.client = Client("opc.tcp:
localhost:4840/freeopcua/serve
")
try:
self.client.connect()
root = self.client.get_root_node()
handler = SubHandler(self)
sub = self.client.create_subscription(500, handler)
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.0"])) # Vehicle red light
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.1"])) # Vehicle yellow light
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.2"])) # Vehicle green light
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.3"])) # Pedestrian red light
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.4"])) # Pedestrian green light
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.0"])) # Vehicle senso
self.pedestrian_button = root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.1"]) # Pedestrian XING button
self.vehicle_green_enabled = False
self.pedestrian_green_enabled = False
except:
print("E
or: Could not connect to server!")
sys.exit(-1)
def update_light(self, light, val):
if light == "vehicle_red":
self.canvas.delete(self.vehicle_red_light_upper)
self.vehicle_red_light_upper = self.canvas.create_oval(280, 235, 290, 245, outline="red", fill="red" if val else "")
self.canvas.delete(self.vehicle_red_light_lower)
self.vehicle_red_light_lower = self.canvas.create_oval(210, 255, 220, 265, outline="red", fill="red" if val else "")
self.vehicle_red_status_label.config(text=str(val))
elif light == "vehicle_yellow":
self.canvas.delete(self.vehicle_yellow_light_upper)
self.vehicle_yellow_light_upper = self.canvas.create_oval(280, 220, 290, 230, outline="yellow", fill="yellow" if val else "")
self.canvas.delete(self.vehicle_yellow_light_lower)
self.vehicle_yellow_light_lower = self.canvas.create_oval(210, 270, 220, 280, outline="yellow" ,fill="yellow" if val else "")
self.vehicle_yellow_status_label.config(text=str(val))
elif light == "vehicle_green":
self.canvas.delete(self.vehicle_green_light_upper)
self.vehicle_green_light_upper = self.canvas.create_oval(280, 205, 290, 215, outline="green", fill="green" if val else "")
self.canvas.delete(self.vehicle_green_light_lower)
self.vehicle_green_light_lower = self.canvas.create_oval(210, 285, 220, 295, outline="green", fill="green" if val else "")
self.vehicle_green_status_label.config(text=str(val))
self.vehicle_green_enabled = val
if self.vehicle_green_enabled and self.pedestrian_green_enabled:
self.accident_counter += 1
self.canvas.delete(self.accident_text)
self.accident_text = self.canvas.create_text(90, 20, anchor=W, text=str(self.accident_counter), fill="red")
elif light == "pedestrian_red":
self.canvas.delete(self.pedestrian_red_light_upper)
self.pedestrian_red_light_upper = self.canvas.create_oval(255, 185, 265, 195, outline="red", fill="red" if val else "")
self.canvas.delete(self.pedestrian_red_light_lower)
self.pedestrian_red_light_lower = self.canvas.create_oval(235, 305, 245, 315, outline="red", fill="red" if val else "")
self.pedestrian_red_status_label.config(text=str(val))
elif light == "pedestrian_green":
self.canvas.delete(self.pedestrian_green_light_upper)
self.pedestrian_green_light_upper = self.canvas.create_oval(235, 185, 245, 195, outline="green", fill="green" if val else "")
self.canvas.delete(self.pedestrian_green_light_lower)
self.pedestrian_green_light_lower = self.canvas.create_oval(255, 305, 265, 315, outline="green", fill="green" if val else "")
self.pedestrian_green_status_label.config(text=str(val))
self.pedestrian_green_enabled = val
if self.vehicle_green_enabled and self.pedestrian_green_enabled:
self.accident_counter += 1
self.canvas.delete(self.accident_text)
self.accident_text = self.canvas.create_text(90, 20, anchor=W, text=str(self.accident_counter), fill="red")
def update_vehicle_sensor(self, val):
self.vehicle_sensor_status_label.config(text=str(val))
if val:
if self.car_upper is None and self.car_lower is None:
self.car_upper = self.canvas.create_image(370, 212, anchor=NW, image=self.car_image_upper)
self.car_lower = self.canvas.create_image(57, 265, anchor=NW, image=self.car_image_lower)
else:
if self.car_upper is not None:
self.canvas.delete(self.car_upper)
self.car_upper = None
if self.car_lower is not None:
self.canvas.delete(self.car_lower)
self.car_lower = None
def __pedestrian_button__(self):
self.pedestrian_button.set_value(True)
print("Pedestrian crossing button pressed")
def __disconnect_opcua_server__(self):
self.client.disconnect()
self.destroy()
class SubHandler(object):
"""
Subscription Handler. To receive events from server for a subscription
data_change and event methods are called directly from receiving thread.
Do not do expensive, slow or network operation there. Create anothe
thread if you need to do such a thing
"""
def __init__(self, gui):
object.__init__(self)
self.gui = gui
def datachange_notification(self, node, val, data):
print("New data change event", node, val)
try:
nodeid = int(str(node.nodeid).split('=')[-1].strip(')'))
except:
return
if nodeid == 3: # Vehicle red light
self.gui.update_light("vehicle_red", val)
elif nodeid == 5: # Vehicle yellow light
self.gui.update_light("vehicle_yellow", val)
elif nodeid == 7: # Vehicle green light
self.gui.update_light("vehicle_green", val)
elif nodeid == 9: # Pedestrian red light
self.gui.update_light("pedestrian_red", val)
elif nodeid == 11: # Pedestrian green light
self.gui.update_light("pedestrian_green", val)
elif nodeid == 2: # Vehicle senso
self.gui.update_vehicle_sensor(val)
def event_notification(self, event):
print("New event", event)
if __name__ == '__main__':
app = GUI()
app.mainloop()
PLC Assignment/HMI/TrafficLight/ProcessSimulator.py
#!/us
in/env python
import sys
import time
import logging
import random
from opcua import Client, ua
class Simulator:
def __init__(self):
self.vehicle_red_light = False
self.__connect_opcua_server__()
def __connect_opcua_server__(self):
logging.basicConfig(level=logging.WARN)
self.client = Client("opc.tcp:
localhost:4840/freeopcua/serve
")
try:
self.client.connect()
root = self.client.get_root_node()
handler = SubHandler(self)
sub = self.client.create_subscription(500, handler)
handle = sub.subscribe_data_change(root.get_child(["0:Objects", "2:OpenPLC", "2:%QX0.0"])) # Vehicle red light
self.vehicle_sensor = root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.0"]) # Vehicle senso
self.pedestrian_button = root.get_child(["0:Objects", "2:OpenPLC", "2:%IX0.1"]) # Pedestrian XING button
self.last_pedestrian_button_status = self.pedestrian_button.get_value()
except:
print("E
or: Could not connect to server!")
sys.exit(-1)
def run(self):
try:
previous_vehicle_red_light = self.vehicle_red_light
last_change_time = time.time()
interval = random.randint(3, 15)
last_pedestrian_button_pressed_time = time.time()
while True:
if previous_vehicle_red_light != self.vehicle_red_light:
last_change_time = time.time()
if time.time() - last_change_time >= interval:
if self.vehicle_red_light == True:
if not self.vehicle_sensor.get_value():
self.vehicle_sensor.set_value(True)
print("Traffic jam")
else:
if self.vehicle_sensor.get_value():
self.vehicle_sensor.set_value(False)
print("No traffic jam")
else:
self.vehicle_sensor.set_value(True)
print("Traffic jam")
last_change_time = time.time()
interval = random.randint(3, 15)
previous_vehicle_red_light = self.vehicle_red_light
# Reset the button after 1 second
cu
ent_pedestrian_button_status = self.pedestrian_button.get_value()
if cu
ent_pedestrian_button_status:
if not self.last_pedestrian_button_status:
last_pedestrian_button_pressed_time = time.time()
elif time.time() - last_pedestrian_button_pressed_time >= 1:
self.pedestrian_button.set_value(False)
self.last_pedestrian_button_status = cu
ent_pedestrian_button_status
except KeyboardInte
upt:
self.__disconnect_opcua_server__()
def __disconnect_opcua_server__(self):
self.client.disconnect()
class SubHandler(object):
"""
Subscription Handler. To receive events from server for a subscription
data_change and event methods are called directly from receiving thread.
Do not do expensive, slow or network operation there. Create anothe
thread if you need to do such a thing
"""
def __init__(self, sim):
object.__init__(self)
self.sim = sim
def datachange_notification(self, node, val, data):
print("New data change event", node, val)
try:
nodeid = int(str(node.nodeid).split('=')[-1].strip(')'))
except:
return
if nodeid == 3: # Vehicle red light
self.sim.vehicle_red_light = val
def event_notification(self, event):
print("New event", event)
if __name__ == '__main__':
sim = Simulator()
sim.run()
PLC Assignment/Lab_1a
eremiz.xml


PLC Assignment/Lab_1a
uild
eremiz.h
#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
PLC Assignment/Lab_1a
uild/Config0.c
*******************************************
* 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__ = 20000000ULL; /*ns*
unsigned long greatest_tick_count__ = 0UL; /*tick*
PLC Assignment/Lab_1a
uild/Config0.h
#include "beremiz.h"
PLC Assignment/Lab_1a
uild/Config0.o
PLC Assignment/Lab_1a
uild/generated_plc.st
PROGRAM Lab_1a
VAR
Input0 AT %IX0.0 : BOOL;
Input1 AT %IX0.1 : BOOL;
Output0 AT %QX0.0 : BOOL;
Output1 AT %QX0.1 : BOOL;
END_VAR
Output0 := Input0;
Output1 := NOT(Input1);
END_PROGRAM
CONFIGURATION Config0
RESOURCE Res0 ON PLC
TASK task0(INTERVAL := T#20ms,PRIORITY := 0);
PROGRAM instance0 WITH task0 : Lab_1a;
END_RESOURCE
END_CONFIGURATION
PLC Assignment/Lab_1a
uild/Lab_1a.so
PLC Assignment/Lab_1a
uild/lastbuildPLC.md5
3ae27c0d58ced0857094cb644a9a2d7f
PLC Assignment/Lab_1a
uild/LOCATED_VARIABLES.h
PLC Assignment/Lab_1a
uild/plc.st
PROGRAM Lab_1a
VAR
Input0 AT %IX0.0 : BOOL;
Input1 AT %IX0.1 : BOOL;
Output0 AT %QX0.0 : BOOL;
Output1 AT %QX0.1 : BOOL;
END_VAR
Output0 := Input0;
Output1 := NOT(Input1);
END_PROGRAM
CONFIGURATION Config0
RESOURCE Res0 ON PLC
TASK task0(INTERVAL := T#20ms,PRIORITY := 0);
PROGRAM instance0 WITH task0 : Lab_1a;
END_RESOURCE
END_CONFIGURATION
PLC Assignment/Lab_1a
uild/plc_debugger.c
*
* DEBUGGER code
*
* On "publish", when buffer is free, debugger stores a
itrary 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 4
* 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 LAB_1A RES0__INSTANCE0;
***
* Declare global variables from resources and conf
**
extern LAB_1A RES0__INSTANCE0;
typedef const struct {
void *ptr;
__IEC_types_enum type;
} dbgvardsc_t;
static dbgvardsc_t dbgvardsc[] = {
{&(RES0__INSTANCE0.INPUT0), BOOL_ENUM},
{&(RES0__INSTANCE0.INPUT1), BOOL_ENUM},
{&(RES0__INSTANCE0.OUTPUT0), BOOL_ENUM},
{&(RES0__INSTANCE0.OUTPUT1), BOOL_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;\

eak;
#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;\

eak;
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:

eak;
}
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);\

eak;
#define __RegisterDebugVariable_case_p(TYPENAME)\
case TYPENAME##_P_ENUM :\
((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\
if(force)\
((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\

eak;\
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);\
}\

eak;
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:

eak;
}
}
}
#define __ResetDebugVariablesIterator_case_t(TYPENAME) \
case TYPENAME##_ENUM :\
((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\

eak;
#define __ResetDebugVariablesIterator_case_p(TYPENAME)\
case TYPENAME##_P_ENUM :\
case TYPENAME##_O_ENUM :\
((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\

eak;
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:

eak;
}
}
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_e
or = WaitDebugData(tick);
if(!wait_e
or){
*size = buffer_cursor - debug_buffer;
*buffer = debug_buffer;
}
return wait_e
or;
}
#endif
#endif
PLC Assignment/Lab_1a
uild/plc_debugger.o
PLC Assignment/Lab_1a
uild/plc_main.c
**
* 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
)?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
eak *
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 fo
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
_file[] = "retain_buffer_file";
const char
_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* cu
ent = (unsigned char*) buf;
    while (len--)
        crc = crc32_table[(crc ^ *cu
ent++) & 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 cu
ent 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 a
ay of char in hex digits
     (that's why we divide strlen in two). *
    retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0;
    
etain_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, "
");
    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(
_file))
        return 1;
    /* Check if we have backup. *
    if (CheckRetainFile(
_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(
_file,
_file_bckp);
    /* Set file CRC initial value. *
    retain_crc = retain_info.header_crc;
    /* Create new retain file. *
    retain_buffer = fopen(
_file, "wb+");
    if (!retain_buffer) {
        fprintf(stde
, "Failed to create retain file : %s\n",
_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 cu
ent 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 : 64
|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        LogCursor[level] = 0;
    }
}
* Store one log message of give size *
int LogMessage(uint8_t level, char* buf, uint32_t size){
if(size < LOG_BUFFER_SIZE - sizeof(mTail)){
uint32_t buffpos;
uint64_t new_cursor, old_cursor;
mTail tail;
tail.msgsize = size;
tail.tick = __tick;
PLC_GetTime(&tail.time);
/* We cannot increment both msg index and string pointer
in a single atomic operation but we can detect having been inte
upted.
So we can try with atomic compare and swap in a loop until operation
succeeds non inte
upted *
do{
old_cursor = LogCursor[level];
buffpos = (uint32_t)old_cursor;
tail.msgidx = (old_cursor
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 e
or : 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 cali
ation_count = NOT_CALIBRATED;
static IEC_TIME cal_begin;
static long long Tsync = 0;
static long long FreqCo
= 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, cali
ate period
**
void align_tick(int sync_align_ratio)
{
    /*
    printf("align_tick(%d)\n", cali
ate);
    *
    if(sync_align_ratio < 0){ /* Cali
ation *
        if(cali
ation_count == CALIBRATED)
            /* Re-cali
ation*
            cali
ation_count = NOT_CALIBRATED;
        if(cali
ation_count == NOT_CALIBRATED)
            /* Cali
ation start, get time*
            PLC_GetTime(&cal_begin);
        cali
ation_count++;
    }else{ /* do alignment (if possible) *
        if(cali
ation_count >= 0){
            /* End of cali
ation *
            /* Get final time *
            IEC_TIME cal_end;
            PLC_GetTime(&cal_end);
            /*adjust cali
ation_count*
            cali
ation_count++;
            /* compute mean of Tsync, over cali
ation period *
            Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 +
                    (cal_end.tv_nsec - cal_begin.tv_nsec)) / cali
ation_count;
            if( (Nticks = (Tsync / common_ticktime__)) > 0){
                FreqCo
= (Tsync % common_ticktime__); /* to be divided by Nticks *
            }else{
                FreqCo
= Tsync - (common_ticktime__ % Tsync);
            }
            /*
            printf("Tsync = %ld\n", Tsync);
            printf("cali
ation_count = %d\n", cali
ation_count);
            printf("Nticks = %d\n", Nticks);
            *
            cali
ation_count = CALIBRATED;
        }
        if(cali
ation_count == CALIBRATED){
            /* Get Elapsed time since last PLC tick (__CURRENT_TIME) *
            IEC_TIME now;
            long long elapsed;
            long long Tco
;
            long long PhaseCo
;
            long long PeriodicTco
;
            PLC_GetTime(&now);
            elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec;
            if(Nticks > 0){
                PhaseCo
= elapsed - (common_ticktime__ + FreqCo
Nticks)*sync_align_ratio/100; /* to be divided by Nticks *
                Tco
= common_ticktime__ + (PhaseCo
+ FreqCo
) / Nticks;
                if(Nticks < 2){
                    /* When Sync source period is near Tick time *
                    /* PhaseCo
may not be applied to Periodic time given to timer *
                    PeriodicTco
= common_ticktime__ + FreqCo
/ Nticks;
                }else{
                    PeriodicTco
= Tco
;
                }
            }else if(__tick > last_tick){
                last_tick = __tick;
                PhaseCo
= elapsed - (Tsync*sync_align_ratio/100);
                PeriodicTco
= Tco
= common_ticktime__ + PhaseCo
+ FreqCo
;
            }else{
                /*PLC did not run meanwhile. Nothing to do*
                return;
            }
            /* DO ALIGNEMENT *
            PLC_SetTimer(Tco
- elapsed, PeriodicTco
);
        }
    }
}
#endif
PLC Assignment/Lab_1a
uild/plc_main.o
PLC Assignment/Lab_1a
uild/POUS.c
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 GetFbVa
#undef SetFbVa
;
};
__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 GetFbVa
#undef SetFbVa
;
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 GetFbVa
#undef SetFbVa
;
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 LAB_1A_init__(LAB_1A *data__, BOOL retain) {
__INIT_VAR(data__->INPUT0,__BOOL_LITERAL(FALSE),retain)
__INIT_VAR(data__->INPUT1,__BOOL_LITERAL(FALSE),retain)
__INIT_VAR(data__->OUTPUT0,__BOOL_LITERAL(FALSE),retain)
__INIT_VAR(data__->OUTPUT1,__BOOL_LITERAL(FALSE),retain)
}
Code part
void LAB_1A_body__(LAB_1A *data__) {

Initialise TEMP variables
__SET_VAR(data__->,OUTPUT0,,__GET_VAR(data__->INPUT0,));
__SET_VAR(data__->,OUTPUT1,,!(__GET_VAR(data__->INPUT1,)));
goto __end;
__end:
return;
}
LAB_1A_body__()
PLC Assignment/Lab_1a
uild/POUS.h
#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__);
PROGRAM LAB_1A
Data part
typedef struct {

PROGRAM Interface - IN, OUT, IN_OUT variables

PROGRAM private variables - TEMP, private and located variables
__DECLARE_VAR(BOOL,INPUT0)
__DECLARE_VAR(BOOL,INPUT1)
__DECLARE_VAR(BOOL,OUTPUT0)
__DECLARE_VAR(BOOL,OUTPUT1)
} LAB_1A;
void LAB_1A_init__(LAB_1A *data__, BOOL retain);
Code part
void LAB_1A_body__(LAB_1A *data__);
#endif
__POUS_H
PLC Assignment/Lab_1a
uild/py_ext.c
*
* Python Asynchronous execution code
*
* PLC put python commands in a fifo, respecting execution orde
* 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 Cu
ent_PLC_EvalFB;
static int Cu
ent_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 *
    Cu
ent_Python_EvalFB = 0;
    Cu
ent_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",Cu
ent_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[Cu
ent_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",Cu
ent_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*
            /* Get a new line *
            Cu
ent_PLC_EvalFB = (Cu
ent_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 cu
ent FB *
    data__ = EvalFBs[Cu
ent_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 ove
un *
            if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN)
            {
             __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN);
                /* TODO : signal e
or *
            }
            /* 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[Cu
ent_Python_EvalFB] = NULL;
        /* Mark block as answered *
        __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED);
        /* Get a new line *
        Cu
ent_Python_EvalFB = (Cu
ent_Python_EvalFB + 1) % 1;
        
printf("PythonIterator ++ Cu
ent_Python_EvalFB %d\n", Cu
ent_Python_EvalFB);
    }
    /* while next slot is empty *
    while(((data__ = EvalFBs[Cu
ent_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;
}
PLC Assignment/Lab_1a
uild/py_ext.o
PLC Assignment/Lab_1a
uild/Res0.c
*******************************************
* 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 TASK0;
LAB_1A RES0__INSTANCE0;
#define INSTANCE0 RES0__INSTANCE0
void RES0_init__(void) {
BOOL retain;
retain = 0;

TASK0 = __BOOL_LITERAL(FALSE);
LAB_1A_init__(&INSTANCE0,retain);
}
void RES0_run__(unsigned long tick) {
TASK0 = !(tick % 1);
if (TASK0) {
LAB_1A_body__(&INSTANCE0);
}
}
PLC Assignment/Lab_1a
uild/Res0.o
PLC Assignment/Lab_1a
uild/VARIABLES.csv
Programs
0;CONFIG0.RES0.INSTANCE0;LAB_1A;
Variables
0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;LAB_1A;
1;VAR;CONFIG0.RES0.INSTANCE0.INPUT0;CONFIG0.RES0.INSTANCE0.INPUT0;BOOL;
2;VAR;CONFIG0.RES0.INSTANCE0.INPUT1;CONFIG0.RES0.INSTANCE0.INPUT1;BOOL;
3;VAR;CONFIG0.RES0.INSTANCE0.OUTPUT0;CONFIG0.RES0.INSTANCE0.OUTPUT0;BOOL;
4;VAR;CONFIG0.RES0.INSTANCE0.OUTPUT1;CONFIG0.RES0.INSTANCE0.OUTPUT1;BOOL;
Ticktime
20000000
PLC Assignment/Lab_1a/plc.xml



















































































Input0













Input1













Output1













Output0

















PLC Assignment/Lab_1
eremiz.xml


PLC Assignment/Lab_1
uild
eremiz.h
#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
PLC Assignment/Lab_1
uild/Config0.c
*******************************************
* 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__ = 20000000ULL; /*ns*
unsigned long greatest_tick_count__ = 0UL; /*tick*
PLC Assignment/Lab_1
uild/Config0.h
#include "beremiz.h"
PLC Assignment/Lab_1
uild/Config0.o
PLC Assignment/Lab_1
uild/generated_plc.st
PROGRAM Lab_1
VAR
Input0 AT %IX0.0 : BOOL;
Output0 AT %QX0.0 : BOOL;
END_VAR
VAR
TON0 : TON;
TOF0 : TOF;
END_VAR
TON0(IN := NOT(Output0), PT := T#5000ms);
TOF0(IN := NOT(Input0) AND NOT(Output0) OR TON0.Q, PT := T#5000ms);
Output0 := Input0 AND TOF0.Q;
END_PROGRAM
CONFIGURATION Config0
RESOURCE Res0 ON PLC
TASK task0(INTERVAL := T#20ms,PRIORITY := 0);
PROGRAM instance0 WITH task0 : Lab_1b;
END_RESOURCE
END_CONFIGURATION
PLC Assignment/Lab_1
uild/Lab_1b.so
PLC Assignment/Lab_1
uild/lastbuildPLC.md5
e07dfbe83e80221b42f44800f3f95c4f
PLC Assignment/Lab_1
uild/LOCATED_VARIABLES.h
PLC Assignment/Lab_1
uild/plc.st
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_gea
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
PROGRAM Lab_1
VAR
Input0 : BOOL;
Output0 : BOOL;
END_VAR
VAR
TON0 : TON;
TOF0 : TOF;
END_VAR
TON0(IN := NOT(Output0), PT := T#5000ms);
TOF0(IN := NOT(Input0) AND NOT(Output0) OR TON0.Q, PT := T#5000ms);
Output0 := Input0 AND TOF0.Q;
END_PROGRAM
CONFIGURATION Config0
RESOURCE Res0 ON PLC
TASK task0(INTERVAL := T#20ms,PRIORITY := 0);
PROGRAM instance0 WITH task0 : Lab_1b;
END_RESOURCE
END_CONFIGURATION
PLC Assignment/Lab_1
uild/plc_debugger.c
*
* DEBUGGER code
*
* On "publish", when buffer is free, debugger stores a
itrary 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 142
* 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 LAB_1B RES0__INSTANCE0;
***
* Declare global variables from resources and conf
**
extern LAB_1B RES0__INSTANCE0;
typedef const struct {
void *ptr;
__IEC_types_enum type;
} dbgvardsc_t;
static dbgvardsc_t dbgvardsc[] = {
{&(RES0__INSTANCE0.INPUT0), BOOL_ENUM},
{&(RES0__INSTANCE0.OUTPUT0), BOOL_ENUM},
{&(RES0__INSTANCE0.TON0.EN), BOOL_ENUM},
{&(RES0__INSTANCE0.TON0.ENO), BOOL_ENUM},
{&(RES0__INSTANCE0.TON0.IN), BOOL_ENUM},
{&(RES0__INSTANCE0.TON0.PT), TIME_ENUM},
{&(RES0__INSTANCE0.TON0.Q), BOOL_ENUM},
{&(RES0__INSTANCE0.TON0.ET), TIME_ENUM},
{&(RES0__INSTANCE0.TON0.STATE), SINT_ENUM},
{&(RES0__INSTANCE0.TON0.PREV_IN), BOOL_ENUM},
{&(RES0__INSTANCE0.TON0.CURRENT_TIME), TIME_ENUM},
{&(RES0__INSTANCE0.TON0.START_TIME), TIME_ENUM},
{&(RES0__INSTANCE0.TOF0.EN), BOOL_ENUM},
{&(RES0__INSTANCE0.TOF0.ENO), BOOL_ENUM},
{&(RES0__INSTANCE0.TOF0.IN), BOOL_ENUM},
{&(RES0__INSTANCE0.TOF0.PT), TIME_ENUM},
{&(RES0__INSTANCE0.TOF0.Q), BOOL_ENUM},
{&(RES0__INSTANCE0.TOF0.ET), TIME_ENUM},
{&(RES0__INSTANCE0.TOF0.STATE), SINT_ENUM},
{&(RES0__INSTANCE0.TOF0.PREV_IN), BOOL_ENUM},
{&(RES0__INSTANCE0.TOF0.CURRENT_TIME), TIME_ENUM},
{&(RES0__INSTANCE0.TOF0.START_TIME), TIME_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;\

eak;
#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;\

eak;
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:

eak;
}
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,...
SOLUTION.PDF

Answer To This Question Is Available To Download

Related Questions & Answers

More Questions »

Submit New Assignment

Copy and Paste Your Assignment Here