Model views from Syside CLI

Hello,

I have a question about Syside’s vizualizer using CLI. I have noticed that when trying to vizualize part definitions, the created diagram is empty, so I turned the definition into the part, which had every possible part, port and item inside the port redefined for it to show up in diagram correctly.

That was not that much of a hassle, since I did not really need to define it as a part, usage was enough for me. However now I am trying to visualize a part, which comes from the definition:

part def WirelessActuatorNode {
part mcu : MCU {
port toOutputDriver : DataPort;
port fromOutputDriver : ~DataPort;
}
part lora : LoRa_FrontEnd;
part rfAntenna : RF_Antenna;
part accel[0..1] : Accelerometer;       // Optional accelerometer
part temp[0..1] : TemperatureSensor;    // Optional temperature sensor
part leds : LEDs;
part button : Button;
part battery : Battery;
part pmc : PowerManagementCircuit;
part outputDriver : OutputDriverCircuit {
doc
/* Receives arm and actuation commands
through commandIn port and sends feedback through feedbackOut.
*/
}
// Ports for external use
port extLoraIn  : ~RFPort;
port extLoraOut : RFPort;
port extActuationOut : ActuationPort;
// Connections
interface : SPI   connect mcu.toLoRa             to lora.fromMCU;
interface : SPI   connect lora.toMCU              to mcu.fromLoRa;
interface : RF    connect lora.toAntenna          to rfAntenna.internalIn;
interface : RF    connect rfAntenna.internalOut   to lora.fromAntenna;
interface : SPI   connect mcu.toAccelerometer     to accel.fromMCU;
interface : SPI   connect accel.toMCU             to mcu.fromAccelerometer;
interface : I2C   connect temp.toMCU              to mcu.fromTempSensor;
interface : GPIO  connect mcu.toLEDs              to leds.fromMCU;
interface : POWER connect pmc.powerOut            to mcu.fromPMC;
connect mcu.toPMC                                 to pmc.dataIn;
interface : GPIO  connect button.pwrCtrl          to pmc.dataIn;
interface : POWER connect battery.powerOut        to pmc.batteryIn;
connect mcu.toOutputDriver                        to outputDriver.commandIn;
connect outputDriver.feedbackOut                  to mcu.fromOutputDriver;
bind extLoraIn       = rfAntenna.externalIn;
bind extLoraOut      = rfAntenna.externalOut;
}

Then I need to have a specialized Actuator, which is done here:

part def AdvancedActuatorNode :> WirelessActuatorNode {
:>> mcu {
port toBarometer   : DataPort;
port fromBarometer : ~DataPort;
}
:>> battery[2] : Battery {
doc /* 2x 18650 Li-Ion */
}
:>> pmc {
port latchInput : ~MechanicalPort;
}
part barometer   : Barometer;
part safetyLatch : MechanicalLatch;
interface : MECHANICAL connect safetyLatch.latchOut to pmc.latchInput;
interface : I2C connect mcu.toBarometer    to barometer.fromMCU;
interface : I2C connect barometer.toMCU    to mcu.fromBarometer;
bind extActuationOut = outputDriver.actuationOut;
}

Then I create a usage:

part advancedNode : AdvancedActuatorNode;

Now I should be able to generate a diagram using viz view in the CLI, but… as mentioned before it shows up empty. To solve this problem, everything needs to be redefind inside the usage.

part advancedNode : AdvancedActuatorNode {
part redefines mcu {
port redefines toOutputDriver    { out item redefines data; }
port redefines fromOutputDriver  { in  item redefines data; }
port redefines toLoRa            { out item redefines data; }
port redefines fromLoRa          { in  item redefines data; }
port redefines toAccelerometer   { out item redefines data; }
port redefines fromAccelerometer { in  item redefines data; }
port redefines fromTempSensor    { in  item redefines data; }
port redefines toLEDs            { out item redefines data; }
port redefines fromPMC           { in  item redefines power; }
port redefines toPMC             { out item redefines data; }
// AdvancedActuatorNode-specific MCU ports
port redefines toBarometer       { out item redefines data; }
port redefines fromBarometer     { in  item redefines data; }
}
part redefines lora {
port redefines fromMCU     { in  item redefines data; }
port redefines toMCU       { out item redefines data; }
port redefines toAntenna   { out item redefines signal; }
port redefines fromAntenna { in  item redefines signal; }
}

< ... >

// ─── AdvancedActuatorNode-specific parts ───
part redefines barometer {
    port redefines fromMCU { in  item redefines data; }
    port redefines toMCU   { out item redefines data; }
}
part redefines safetyLatch {
    port redefines latchOut { out item redefines mech; }
}
// ─── External ports ───
port redefines extLoraIn      { in  item redefines signal; }
port redefines extLoraOut     { out item redefines signal; }
port redefines extActuationOut { out item redefines signal; }

}

Only now I manage to generate a diagram that contains every part and every port, but there are no connections. In order to see connections, I need to copy&paste every connection from part def into the usage with redefinitions.
Doing it this way seems to defeat the purpose in SysMLv2 of being able to use and re-use parts, ports, etc., if I need to double the amount of code needed only to visualize it.

Maybe I am doing something wrong? Or is it a known issue in the visualizer? Any help is greatly appreciated

Hi JK,

What version of Modeler CLI are you using? The 0.10.3 version fixed bug with feature inheritance, so with latest version they should be displayed fine and not require redefinition.

Note, I had to add missing definitions for parts, ports and interfaces to resolve them. Also, the redefined parts end up in the feature compartment since the keyword “part” is omitted in the redefinition and the mcu, battery and pmc actually become ReferenceUsages rather than inherited PartUsages in the AdvancedActuatorNode. To avoid this, always include original usage type keyword when redefining features, for example: “part :>> …”, “attribute :>> …” and so on. See rendered modified advancedNode (viz element):

Furthermore, don’t forget in views to expose recursively all elements in ( expose <name>::**;).

Lastly, this particular binding bind extActuationOut = outputDriver.actuationOut; seems to be incorrectly rendered in 0.10.3 Modeler CLI viz. The workaround is to do port redefinition with inline binding, for example: port :>> extActuationOut = outputDriver.actuationOut;.

Here is the snippet code that I used to create visualization:

package Forum564 {
    // Missing parts
    abstract part def CommsWithMCU {
        port fromMCU;
        port toMCU;
    }
    part def MCU {
        port toLoRa;
        port fromLoRa;
        port toAccelerometer;
        port fromAccelerometer;
        port toTempSensor;
        port fromTempSensor;
        port toLEDs;
        port fromLEDs;
        port toPMC;
        port fromPMC;
        // port toOutputDriver;
        // port fromOutputDriver;
    }
    part def LoRa_FrontEnd {
        port fromMCU;
        port toMCU;
        port toAntenna;
        port fromAntenna;
    }

    part def RF_Antenna specializes CommsWithMCU {
        port internalIn :>> fromMCU;
        port internalOut :>> toMCU;
    }
    part def Accelerometer specializes CommsWithMCU;
    part def TemperatureSensor specializes CommsWithMCU;
    part def LEDs specializes CommsWithMCU;
    part def Button {
        port pwrCtrl;
    }
    part def Battery {
        port powerOut;
    }
    part def PowerManagementCircuit specializes CommsWithMCU {
        port dataIn :>> fromMCU;
        port powerOut :>> toMCU;
        port batteryIn;
    }
    part def OutputDriverCircuit {
        port commandIn;
        port feedbackOut;
        port actuationOut : ActuationPort;
    }
    part def Barometer specializes CommsWithMCU;
    part def MechanicalLatch {
        port latchOut;
    }

    // missing ports
    port def DataPort;
    port def RFPort;
    port def ActuationPort;
    port def MechanicalPort;

    // missing interfaces
    interface def SPI {
        end port a;
        end port b;
    }
    interface def I2C {
        end port a;
        end port b;
    }
    interface def GPIO {
        end port a;
        end port b;
    }
    interface def POWER {
        end port a;
        end port b;
    }
    interface def MECHANICAL {
        end port a;
        end port b;
    }
    interface def RF {
        end port a;
        end port b;
    }

    // end of missign defs ---------------------------------------------------

    part def WirelessActuatorNode {
        part mcu : MCU {
            port toOutputDriver : DataPort;
            port fromOutputDriver : ~DataPort;
        }
        part lora : LoRa_FrontEnd;
        part rfAntenna : RF_Antenna {
            port externalIn;
            port externalOut;
        }
        part accel : Accelerometer [0..1]; // Optional accelerometer
        part temp : TemperatureSensor [0..1]; // Optional temperature sensor
        part leds : LEDs;
        part button : Button;
        part battery : Battery;
        part pmc : PowerManagementCircuit;
        part outputDriver : OutputDriverCircuit {
            doc
            /* Receives arm and actuation commands
             * through commandIn port and sends feedback through feedbackOut.
             */
        }
        // Ports for external use
        port extLoraIn : ~RFPort;
        port extLoraOut : RFPort;
        port extActuationOut : ActuationPort;

        // Connections
        interface : SPI connect mcu.toLoRa to lora.fromMCU;
        interface : SPI connect lora.toMCU to mcu.fromLoRa;
        interface : RF connect lora.toAntenna to rfAntenna.internalIn;
        interface : RF connect rfAntenna.internalOut to lora.fromAntenna;
        interface : SPI connect mcu.toAccelerometer to accel.fromMCU;
        interface : SPI connect accel.toMCU to mcu.fromAccelerometer;
        interface : I2C connect temp.toMCU to mcu.fromTempSensor;
        interface : GPIO connect mcu.toLEDs to leds.fromMCU;
        interface : POWER connect pmc.powerOut to mcu.fromPMC;

        connect mcu.toPMC to pmc.dataIn;
        interface : GPIO connect button.pwrCtrl to pmc.dataIn;
        interface : POWER connect battery.powerOut to pmc.batteryIn;
        connect mcu.toOutputDriver to outputDriver.commandIn;
        connect outputDriver.feedbackOut to mcu.fromOutputDriver;
        bind extLoraIn = rfAntenna.externalIn;
        bind extLoraOut = rfAntenna.externalOut;
    }

    part def AdvancedActuatorNode specializes WirelessActuatorNode {
        :>> mcu {
            port toBarometer : DataPort;
            port fromBarometer : ~DataPort;
        }
        :>> battery [2] : Battery {
            doc
            /* 2x 18650 Li-Ion */
        }
        :>> pmc {
            port latchInput : ~MechanicalPort;
        }
        part barometer : Barometer;
        part safetyLatch : MechanicalLatch;
        interface : MECHANICAL connect safetyLatch.latchOut to pmc.latchInput;
        interface : I2C connect mcu.toBarometer to barometer.fromMCU;
        interface : I2C connect barometer.toMCU to mcu.fromBarometer;
        bind extActuationOut = outputDriver.actuationOut;
    }

    part def AdvancedActuatorNodeV2 specializes WirelessActuatorNode {
        part :>> mcu {
            port toBarometer : DataPort;
            port fromBarometer : ~DataPort;
        }
        part :>> battery [2] : Battery {
            doc
            /* 2x 18650 Li-Ion */
        }
        part :>> pmc {
            port latchInput : ~MechanicalPort;
        }
        part barometer : Barometer;
        part safetyLatch : MechanicalLatch;
        interface : MECHANICAL connect safetyLatch.latchOut to pmc.latchInput;
        interface : I2C connect mcu.toBarometer to barometer.fromMCU;
        interface : I2C connect barometer.toMCU to mcu.fromBarometer;
        port :>> extActuationOut = outputDriver.actuationOut;
        //bind extActuationOut = outputDriver.actuationOut;
    }

    part advancedNode : AdvancedActuatorNode;
    part advancedNodeV2 : AdvancedActuatorNodeV2;


    // views 
    private import StandardViewDefinitions::*;
    //private import Views::*;
    
    occurrence def DiagramViews {
        view d1 : GeneralView {
            expose advancedNode::**;
            attribute fileName = "diagram_AdvancedActuatorNode";
        }
        view d2 : GeneralView {
            expose advancedNodeV2::**;
            attribute fileName = "diagram_AdvancedActuatorNodeV2";
        }
    }
} // package Forum564

Hope this helps!
Kestutis

Hello Kestutis,

I have adjusted my code per your suggestions and everything works now.

Main problem was that VSCode shows that I am using 0.10.3 though extensions page, but syside --version in terminal showed 0.10.2. Not sure why that is, but it is consistent for all my colleagues, however after local offline installation, CLI works correctly. Not sure from which side this could be the issue, just raising awareness about it.

Thank you for an extensive answer and your help!

Hi again,

Currently Syside Modeler CLI is additional tool that is installed separately from Syside Modeler VS Code extension. Thus you can have latest VS Code extension but still have an old CLI version. Please follow Modeler CLI installation instructions described to update it.

Kind regards,
Kestutis