Sinelabore Homepage

Update for SysML v2. A state machine can now accept a signal directly and work with what it carries, durations are written in the units a model uses, and a send reaches a part from wherever the model writes it. Both code targets, C++ and Python, generate all of it. Highlights since 7.3:

  • Calculations. A calc def and a calc usage generate in full and can be called from a part’s actions and from its state machines — see Calculations.
  • Accepting signals. A transition accepts an item type directly and binds what arrived: accept e : Reading if e.value < 0 do assign last := e.value then Alarm;. No event enum has to be made up for it. A machine takes one event per step and selects the transition by the event’s type — see State Machines.
  • Sends from anywhere. send … to <part> now also works from the body of an action and from a state’s entry and exit, and follows a path such as studio.screen hop by hop. A send or accept that goes against the direction of the port’s item is reported (W3214).
  • Durations in units. accept after 2 [s], 0.5 [min] and [h] work as written, as does a feature typed DurationValue or a sum such as settle + 250 [ms]. The value is converted when the code is generated. SI declares the second, minute, hour and day; a prefixed unit such as ms is declared once in the model (see the example below). A unit that is not declared is reported as E3250, with the declaration to add.
  • Names the target reserves. A feature may be called delete, switch, lambda, yield or process, or like a member of the runtime’s Part. The generated code escapes the name, and messages and drawings show it as the model writes it.
  • More of the language is accepted: & and |, aliases inside a body, packages and enumerations without a body, quoted state names, perform :>> x { … }, a state machine declared where it is exhibited, a parameter that redefines an inherited one without a new name, and guarded successions without a decide — several of them leaving the same action.
  • Port delegation (from 7.4). A part’s port can stand for the port of a part inside it: bind or connect the boundary port to the inner one, and the two are one port — see Ports.
  • Improved part drawing layout.

New diagnostics include W3214 (a send against the port’s direction), E3249 (accept E::lit names an enumeration literal, not a type), E3250 (a duration unit that is not declared) and E3254 (a bracket after a value that is not a unit). See Diagnostics.

A machine that accepts signals#

item def Reading { attribute value : Integer; }

part def Monitor {
    attribute last : Integer default 0;

    state sm {
        entry; then Watching;

        state Watching;
            accept e : Reading if e.value < 0 do assign last := e.value then Alarm;

        state Alarm;
            accept e : Reading if e.value >= 0 then Watching;
    }
}

A driver hands the machine a signal and steps the part:

Monitor m;
m.init();
m.stateMachine.send(Reading{-3});   // queued
m.process();                        // taken: Watching -> Alarm, last == -3
m = Monitor()
m.init()
m.stateMachine.send(Reading(-3))
m.process()

Durations in the units of the model#

attribute <ms> millisecond : DurationUnit {
    :>> unitConversion : ConversionByPrefix { :>> prefix = milli; :>> referenceUnit = s; }
}

state On;
    accept after 500 [ms] then Off;
state Off;
    accept after settle + 250 [ms] then On;