Automatically created Python bridges

The principles behind automatically written GUIs 11.4 were also put to use in building automatically-generated Python bridges.

The reasoning behind using Python (or any other interpreted language) is very simple: Testing the (usually complex) logic inside space systems requires big regression checking suites. In the absence of support for interpreted languages, the checking code has to use the low-level APIs, which is a tedious and error-prone process.

The ASSERT tools, however, automatically create Python bridges that offer direct access to the contents of the ASN.1 parameters, as well as direct runtime access to the TM/TCs offered by the system. All that the user needs to do to create his set of regression checks, is to write simple Python scripts, that exercise any behavioural aspect of the system. As an example, the automatically generated Python interface can be used to write a scenario like this:

When I send a TC with value X in param Y, then I expect a TM after a max waiting of Z seconds, with the value K in the incoming param L
This kind of scenario can be expressed in less than 10 lines of Python code, that is, an order of magnitude less work than the corresponding C code.

The code below is a simple (but complete) example that illustrates how ASN.1 types can be handled from within Python:

#!/usr/bin/env python
import sys

#
# From this ASN.1 grammar:
# (file DataView.asn)
#
#    DataView DEFINITIONS AUTOMATIC TAGS ::= BEGIN
#
#    T-REAL ::= REAL( -10000.0 .. 10000.0 )
#
#    END
#
# You process the ASN.1 file like this:
#
# bash$ export ASN2DATAMODEL=/path/to/asn2dataModel/asn2dataModel
# bash$ mkdir output
# bash$ $ASN2DATAMODEL -o output -toPython DataView.asn
# bash$ cd output/
# bash$ make -f Makefile.python
#
# After that, you can run this script...

from DataView_asn import *

def testReal(val):
    # Create a stream buffer to host the encoded data
    d1 = DataStream(DV.T_REAL_REQUIRED_BYTES_FOR_ENCODING)
    # Create a T_REAL
    f1 = T_REAL()
    # Set the value
    f1.Set(val)
    try:
	# Encode the value of f1 into the buffer d1
	f1.Encode(d1)  
    except:
	print "Encoding failed..."
	sys.exit(1)

    binaryData = d1.GetPyString() # Get the encoded stream bytes
                                  # as a Python string. You can
                                  # pass these data over sockets,
                                  # save them to files, etc

    # Create a second stream buffer, put the encoded data
    # inside it, and decode from it.
    # Another way (one that avoids a separate DataStream)
    # is to re-use d1, calling d1.Reset (which "rewinds"
    # the stream indexes to the start, thus making it ready
    # for access by the Decoders)
    d2 = DataStream(DV.T_REAL_REQUIRED_BYTES_FOR_ENCODING)
    d2.SetFromPyString(binaryData)
    f2 = T_REAL()
    f2.Decode(d2)
    #f2.PrintAll()
    assert(abs(val - f2.Get())<1e-5)

if __name__ == "__main__":
    i = -5.0
    while i<5.0:
	testReal(i)
	i+=0.001

... and the following code is an example of TM/TCs communication with an actual system:

import time, sys

# DV, DataView_asn and PythonController are automatically written 
# by the ASSERT tools (in this example)

import DV
from DataView_asn import *
from PythonController import *

cnt = 0
try:
# Poll_mygui is a class automatically written by ASSERT tools, which
# is imported from PythonController and polls for arriving TMs
# in a thread, reporting their arrivals...
    thread = Poll_mygui()    
    thread.start()
    while True: 
	# While polling in a thread for arriving TMs, 
	# we will also send a TC every two seconds:
        print "Sleeping for two seconds..."
        time.sleep(2)
        print "Invoking TC"

        # Direct access to ASN.1 types from Python:
        a = TC_T()             
	a.action.kind.Set(DV.display_PRESENT)
        cnt += 1
        a.action.display.SetFromPyString("abc" + str(cnt))
        a.destination.Set(Destination_T.displayer)
# Show the contents of the ASN.1 message before you send it
        a.PrintAll()
# automatically written accessor to the TC, imported from PythonController
        Invoke_router_put_tc(a)    
except:
    sys.exit(1)