Network programming language tutorial

Decorating your demos

The simulator displays a png image as the background for your scenarios. Each scenario can provide its own background image by storing a png file with the same name as your scenario files (e.g. HelloWorld.wnl would attempt to load HelloWorld.png). In case this image file cannot be found it will look for a grid image in the base directory of the simulator. When supplying your own background image, make sure it's dimensions correspond to the grid image.

Custom nodes

In this section we examine the extension procedure of the simulated OSAS runtime. We take a look at how we can provide rich computational facilities at the gateway or simulate specific nodes. Custom nodes are written directly in python.

To create a new custom node, we need to subclass the Node class

import random
from Nodes import Node

class TemperatureNode(Node):
    def __init__(self, namingscheme, ID, logger):
        Node.__init__(self, namingscheme, ID, logger)

        self.RegisterCall(namingscheme, 'Temp', self.Temp, 1)

    def Temp(self):
        return random.randint(0, 32767)

Here we create a new TemperatureNode which exposes a new function call Temp and is implemented as a random value. The temperature function is implemented straightforwardly as a method. The important part is the registration. We can call the RegisterCall method which we should pass our namingscheme (this is the xml configuration file), a name which will be added to the OSAS runtime, a reference to the function or method and finally the number of return values.

To add a handler, we need to adhere to the standard handler signature (packet, start, end) as shown in the example below. Furthermore we need to use self.RegisterHandler instead of self.RegisterCall. The main difference is that self.RegisterHandler does not specify the amount of return values, since handlers have none.

from Nodes import Node

class Gateway(Node):
    def __init__(self, namingscheme, ID, logger):
        Node.__init__(self, namingscheme, ID, logger)

        self.colour = 0x0000ff

        self.RegisterHandler(namingscheme, "PrintArray", self.PrintArray)

    def PrintArray(self, packet, start, end):
        handler_payload = str(packet[start+1:end])
        self.printqueue.put("%03d: %s" % (self.NodeID(), handler_payload))

Note that packet is a list which contains our entire packet payload. Start refers to the starting index of the handler (it will refer to the ID of PrintArray) and end refers to the first element which is NOT part of this handler.

The above example adds a string to self.printqueue which will cause it to be displayed in the graphical user interface next on the canvas tab. Also, notice that we modify the self.colour attribute to change the colour of the node on the canvas tab.

The first tutorial explained how to refer to these nodes from a scenario layout file (e.g. HelloWorld.wnl). It is allowed to add additional parameters after the name of the node. For instance, HelloWorld.wnl could also look like this:

2 4 CommonNodes GenericNode SubjectID=3
4 4 CommonNodes Gateway
6 4 LoaderNode2 LoaderNode

In such a case any text following the name of the node class to create will be considered as a space separated list of string arguments and passed into the constructor of the node (i.e. __init__). This way you can have some more fine grained customization of simulated nodes.

After renaming or adding any new functions or handlers to custom nodes, don't forget to start your simulator once for each scenario that uses these nodes to regenerate your configuration files. After this, your program also needs to be recompiled.

Refer to CommonNodes to see more examples. Note that in principle you are free to use arbitrary python libraries in here, although there might be some issues in locating these dependencies when using the binary version of the toolchain.