10 Signal Script

Scripts allow the user to customize impulses in many ways. These include, among others, the evaluation of signals, the parsing of signal sources, the search for signal positions and the definition or extension of charts.

 

Extract or derive signals

The Signal Scripts production allows the users to combine signals using mathematical operations, generate references, implement protocol parsers, extract statistical informations or search for conflicts automatically.

Parse signal sources

If you are reading signal and trace data from a TCP, file, serial or other port input and with a format unknown to the impulse tool, you can get on the right track with a scripted reader. Using a scripted reader is an easy way to read data from any format.

Stimulate and handle ports

By using scripts, connected devices or applications can be stimulated and their events processed. This could be for example a CAN bus message or a byte sequence via TCP.

Search for sample positions

The Find dialogue helps you to find signal patterns using script expression.

Create signal references

RecJs files are wave files based on scripts. You can create signal references, define test vectors for your design, or script a custom reader. Everything is based on the same simple API used in signal scripts and serializers.

Create and extent charts

You can extend most diagram types using scripts. The scripting API varies depending on the chart type.

Synchronize signal sources

Multiple signal ports of varying types can be combined into one, synchronizing the received signals.

Define stubs for simulation environments

Scripted stubs allow the simulation of the dependencies of models such as the YAKINDU State Charts.

Screen Cast: J20 Reading samples

Java and Scripts

The Scripting Envronment

impulse is build on Java and Signal Script uses the JSR223 Scripting API of Java.

With the current release only JavaScript is supported. Further release will be extended to all availabe JSR223 languages.

Scripting Objects

Signal Script usually works with Java objects (e.g. input streams, signal reader and writer object, ...).

Its up to the user to work with script language dependend objects (like JavaScript objects) but its usually not required and to our understanding not useful. Primitives from java are converted into script language (JavaScript) primitives.

But there are limits: JavaScript, for example, has only one number type (64 float), so that a long value cannot be converted and is given as a long object.

Scripting APIs

Signal Script contains APIs (impulse JDK) to

  • Read sample data;
  • create records,signals and sample data;
  • iterate over multiple signal inputs;
  • convert sample data;

plus several extention specific APIs.

How to get started with scripting ?

Have a look at the script examples. Select a script that is close to your requirements, than copy script and optinal settings into the dialogue or editor.

JavaScript

  • Rhino > Nashorn > GraalVM(?)

    Rhino > Nashorn >  GraalVM(?)

    impulse 1.x started with a Rhino JavaScript engine. If the Rhino engine was used (Java 7 or higher), impulse automatically used the Rhino compatibility library. Note that Rhino and Rhinoceros had a slightly different interface to Java. Please refer to the Scripting Java (Rhino) and Rhino Migration Guide (to Nashorn).

    impulse 2.0 uses the Nashort Engine by default (Rhino is no longer supported) and assumes compatibility with the upcoming GraalVM.

  • Class access and Java objects

    Class access

    To access a Java class, use the Java.type(typeName) function.

    var FileClass = Java.type('java.io.File');

    Existing code accessing e.g. java.io.File or Packages.de.toem.impulse.samples.GroupPointer should be rewritten to use the Java.type(name) function.

    Constructing Java objects

    Java objects can be constructed with JavaScript's new keyword.

    var FileClass = Java.type('java.io.File');
    var file = new FileClass("myFile.md");
  • Signal Script imports

    To access a Java class, you typically have to add a snippet like:

    var FileClass = Java.type('java.io.File');

    However, impulse automatically adds typical signal script class definitions, depending on the application.
    For example the Signal Script production adds the following definitions:

    var ISample = Java.type("de.toem.impulse.samples.ISample");
    var ISamples = Java.type("de.toem.impulse.samples.ISamples");
    var GroupPointer = Java.type("de.toem.impulse.samples.iterator.GroupPointer");
    var SamplePointer = Java.type("de.toem.impulse.samples.iterator.SamplePointer");
    var SamplesIterator = Java.type("de.toem.impulse.samples.iterator.SamplesIterator");
    var AttachedLabel = Java.type("de.toem.impulse.values.AttachedLabel");
    var AttachedRelation = Java.type("de.toem.impulse.values.AttachedRelation");
    var Enumeration = Java.type("de.toem.impulse.values.Enumeration");
    var Logic = Java.type("de.toem.impulse.values.Logic");
    var Struct = Java.type("de.toem.impulse.values.Struct");
    var StructMember = Java.type("de.toem.impulse.values.StructMember");
    ...
    

    For further information please refer to the corresponding documentation.

  • Field/method access and Arrays

    Field and method access

    Static fields of a Java class or fields of a Java object can be accessed like JavaScript properties.

    var JavaPI = Java.type('java.lang.Math').PI;

    Java methods can be called like JavaScript functions.

    var file = new (Java.type('java.io.File'))("test.md");
    var fileName = file.getName();

    Array creation

    var IntArray = Java.type("int[]");
    var iarr = new IntArray(5);
  • Nashorn vs GraalVM

    This chapter shall point out the differences between Nashorn (JDK8+) and GraalVM.

    As GraalVM is not completed, this chapter will extend over time.

    Conversion of primitives

    JavaScript has just a single Number type, wheras Jaca supports multiple types.

    The conversion of types may differ between both engines. See below logs:

    while ( iter.hasNext()) {
        var current = iter.next(out);  // returns a Java long value
    	console.log(current,current.getClass());
    }    
    
    # Nashorn log
    1282 ;0 ;class java.lang.Long
    1419 ;1112500000 ;class java.lang.Long
    1435 ;2387500000 ;class java.lang.Long
    1444 ;4887500000 ;class java.lang.Long
    
    
    # GraalVM log
    623 ;0 ;class java.lang.Integer
    653 ;1112500000 ;class java.lang.Integer
    684 ;2.3875E9 ;class java.lang.Double
    691 ;4.8875E9 ;class java.lang.Double
    
  • Psoido typing

    The psoido typing snippet has the form:

    • varname /*: string_name_or_binary_name :*/

    or

    • varname /*:@ string_name_or_binary_name :*/

    The first options refers to a java instance, whereas the second option referes to a class.

    The string_name_or_binary_name of the psiodo typing snippet may be in form of:

    Examples:

        var current /*:java.lang.Long:*/  = iter.next(out);
    	var b = current.byteValue();
    
        var Long /*:@java.lang.Long:*/  = Java.type("java.lang.Long");
    	var l = Long.numberOfLeadingZeros(current);
    

Using the eclipse script editor

Besides the recJs script recording format, which has its own editor, most scripts are bound to configuration items like plots, ports and charts.

The associated element dialogs contain text fields for inserting and editing the script.

You can use the built-in script editor instead of the text field in the dialog. Click on "Edit in the eclipse script editor" to open a new Eclipse editor. Once you save the content, the configuration element is updated.

Log and exception messages of the script execution are sent to the impulse console view.

Content Assist

Embedded and eclipse editor

Syntax checker

Content assist and psoido typing

Signal Script usually works with Java objects (e.g. input streams, signal reader and writer object, ...).

To allow content assist on java objects in dynamic type checking languages (e.g. JavaScript), impulse utilizes a so-called psoido typing.

var myVar /*:ISamplesReader:*/ = generator.getReader();  // psoido typing in JavaScript

Psoido typing snippets tell the environment the java type of a variable so that the system can prepare suggestions for content support. The snippets have no effect on the JavaScript execution (they are removed before processing or take the form of a comment). Their use is optional, but they are very helpful if you do not want to read reference documents all the time.

The java class definition of the psiodo typing snippet may be in form of:

Iterating and reading samples

The typical goal of a script is to read the content of source signals and create any kind of output signal. A typical script for the Signal Script Production looks like this:

// input: an array of all input signals
// in0: primary input of type ISamplePointer,IReadableSamples
// in1..: additional inputs of type ISamplePointer,IReadableSamples
// out: output signal of type IFloatSamplesWriter
// console: console output of type MessageConsoleStream
// iter: iterator of type ISamplesIterator
// progress: progess control of type  IScriptProgress

while ( iter.hasNext()) {
    var current <:Long:> = iter.next(out);
    out.write(current, false, input[0].floatValue() +  input[1].floatValue());
}

SamplesIterator instance iter allows to iterate over events of multiple source signals. 'iter.next()' returns the current domain value (e.g current time). All input variable can be accessed as signal pointers: For each event found, the iterator set the pointers to the current position, e.g. floatValue() returns the float value at that position.

Reading signals with IReadableSamples and ISamplesPointer

There are 2 important interfaces for reading the signal data, IReadableSamplesand ISamplesPointer.

The IReadableSamples interface defines the basic reader interface. It has methods like:

  • getCount()
  • valueAt(int idx)
  • intValueAt(int idx)
  • ...

So you can get the total number of available samples and use one of the accessor methods to get the value at a given index.

The ISamplesPointer interface allows to modify an index and read the value at the current index. You find functions like:

  • setIndex(int idx)
  • goPrev()
  • goNext()
  • val()
  • intValue();

If an input has a an additional dimension (struct members or arrays) you might read the value object and use the member accessors:

  • structAt(n).intValueOf("max")
  • intValueOf("max")

If you use a SamplesIterator, all pointers are updated by the iterator automatically. There is no need to use 'goNext()','goPrev()',... implicitly.

while ( iter.hasNext()) {
   .... in0.intValue() ....  }

Creating signals

Independent from its source and type, impulse organizes all signal data by using these elements:

  • Record: The top-level element, usually the content of a file, or the resulting input of a port.  
  • Scope: An organization element (like a folder) to group signals.  
  • Signal: An indexed sequence of signal samples (containing values of different type), organized along a domain base (e.g. time).  
  • Proxy: A signal that contains the identical content of a another signal, and therefore contains only a link to that signal (wave file often contains identical signals).

Record generator

The record generator help you to prepare a record with all its contents. If you create a reader, your class will be derived from IRecordGenerator, if you are working with recJs scripts or a scripted reader, a IRecordGenerator variable (generator) will be provided. The "Signal Script" production does not require to use a record generator, as the signal and reader setup is done internally.

To create a record , the following steps are required:

  • Initialize the record
  • Add the record content (scopes, signals and proxies)
  • Acquire writers for the signals you want to fill
    •     Open the writer
    •     Write samples
    •     Close the writer
// Init the record
generator.initRecord("Example Record", TimeBase.ns);


// Create scopes and signals
var signals = generator.addScope(null, "External Signals");
var int = generator.addSignal(signals, "Sin", "", ProcessType.Discrete, SignalType.Integer, SignalDescriptor.DEFAULT);
var struct = generator.addSignal(signals, "Birt", "", ProcessType.Discrete, SignalType.Struct, SignalDescriptor.DEFAULT);
var floatArray = generator.addSignal(signals, "XY", "", ProcessType.Discrete, SignalType.Float, new SignalDescriptor(SignalDescriptor.CONTENT_DEFAULT, 2, ISample.FLOAT_WIDTH_64, ISample.FORMAT_DEFAULT));


open(tStart);
// writing samples
close(tEnd);

Writing samples

Each signal type comes with a writer interface.

The float signal of the above example uses the IFloatSamplesWriter interface (integer:  IIntegerSamplesWriter, text: ITextSamplesWriter, ...).

A simple write includes the parameters for domain position, a tag flag and one or more parameters describing the value.

public interface IFloatSamplesWriter extends INumberSamplesWriter {

	// default interface
    boolean write(long units, double value);
    boolean write(long units, boolean tag, float value);
    boolean write(long units, boolean tag, double value);
    boolean write(long units, boolean tag, BigDecimal value);
    boolean write(long units, boolean tag, Number value);
    boolean write(long units, boolean tag, float[] value);
    boolean write(long units, boolean tag, double[] value);  
	// named interface for scripts   
    boolean writeFloat(long units, boolean tag, float value);
    boolean writeDouble(long units, boolean tag, double value);
    boolean writeBig(long units, boolean tag, BigDecimal value);
    boolean writeFloatArray(long units, boolean tag, float[] value);
    boolean writeFloatArgs(long units, boolean tag, float... value);    
    boolean writeDoubleArray(long units, boolean tag, double[] value);
    boolean writeDoubleArgs(long units, boolean tag, double... value);
}

The parameters have the following meaning:

units
Domain position as no of domain units (e.g, domain base:ns, units = 1000 -> domain position = 1us)
tag
Possiblity to tag a sample.
value
The given value in different formats (float/double/BigDecimal)
toem

technical software and tooling

Company

Contact Us

This email address is being protected from spambots. You need JavaScript enabled to view it.