This work is licensed under Apache License 2.0

Getting started

Plugin Id: org.infosmid.plugins.kfsm-viz Version: 2.0.0

Gradle Groovy DSL

plugins {
    id 'org.infosmid.plugins.kfsm-viz' version '2.0.0'
}

Configuration

Gradle Groovy DSL

kfsmViz {
  fsm('PacketReaderFSM') {
    input = file('src/main/kotlin/PacketReader.kt') // (1)
    isGeneratePlantUml = true // (2)
    isGeneratePlantUmlSimple = null // (3)
    isGenerateAsciidoc = true // (4)
    output = 'packet-reader' // (5)
    outputFolder = file('generated') // (6)
    plantUmlName = "packet-reader-state-diagram.plantuml" // (7)
    asciidocName = 'packet-reader-state-table.adoc'      // (8)
  }
}
  1. input: File: Required, fully qualified filename of relevant source file

  2. isGeneratePlantUml: Boolean: Required default is false

  3. isGeneratePlantUmlSimple: Boolean: Optional default is null

  4. isGenerateAsciidoc: Boolean: Required default is false

  5. output: String: Optional filename base. The default is the classname

  6. outputFolder: File: Optional directory for output file. Default is $buildDir/generated

  7. plantUmlName: String: Optional filename for plantuml output. Default is $output.plantuml

  8. asciidocName: String: Optional name of Asciidoc output file. Default is $output.adoc

Example for multiple FSM definitions

kfsmViz {
    fsm('PacketReaderFSM') {
        input = file('src/main/kotlin/PacketReader.kt')
        output = 'packet-reader'
        outputFolder = file('generated')
        isGeneratePlantUml = true
        isGenerateAsciidoc = true
    }
    fsm('TurnstileFSM') {
        input = file('src/main/kotlin/Turnstile.kt')
        output = 'turnstile'
        outputFolder = file('generated')
        isGeneratePlantUml = true
        isGenerateAsciidoc = true
    }
    fsm('TimerSecureTurnstileFSM') {
        input = file('TimeoutSecureTurnstile.kt')
        output = 'secure-turnstile'
        outputFolder = file('generated')
        isGeneratePlantUml = true
        isGenerateAsciidoc = true
    }
}

Task

./gradle :generateFsmViz

Expected output

TurnstileFSM

Turnstile State Diagram

turnstile

TurnstileFSM State Chart

TurnstileFSM State Map

Start Event[Guard] Target Action

[start]

UNLOCKED

LOCKED

COIN

UNLOCKED

{
unlock()
}

UNLOCKED

COIN

UNLOCKED

{
returnCoin()
}

UNLOCKED

PASS

LOCKED

{
lock()
}

PacketReaderFSM

PacketReader State Diagram

packet reader

PacketReaderFSM State Chart

PacketReaderFSM State Map

Start Event[Guard] Target Action

START

CTRL [{it == CharacterConstants.SOH}]

RCVPCKT

RCVPCKT

CTRL [{it == CharacterConstants.STX}]

RCVDATA

{
addField()
}

RCVPCKT

BYTE

RCVCHK

{
addChecksum(it)
}

RCVDATA

BYTE

RCVDATA

{
addByte(it)
}

RCVDATA

CTRL [{it == CharacterConstants.ETX}]

RCVPCKT

{
endField()
}

RCVDATA

ESC

RCVESC

RCVESC

ESC

RCVDATA

{
addByte(CharacterConstants.ESC)
}

RCVESC

CTRL

RCVDATA

{
addByte(it)
}

RCVCHK

BYTE

RCVCHK

{
addChecksum(it)
}

RCVCHK

ESC

RCVCHKESC

RCVCHK

CTRL [{it == CharacterConstants.EOT}]

CHKSUM

{
checksum()
}

CHKSUM

<<automatic>> [{!checksumValid}]

[*]

{
sendNACK()
}

CHKSUM

<<automatic>> [{checksumValid}]

[*]

{
sendACK()
}

RCVCHKESC

ESC

RCVCHK

{
addChecksum(CharacterConstants.ESC)
}

RCVCHKESC

CTRL

RCVCHK

{byte->
require(byte != null)
addChecksum(byte)
}

TimeoutSecureTurnstileFSM

TimeoutSecureTurnstile State Diagram

secure turnstile

TimerSecureTurnstileFSM State Chart

TimerSecureTurnstileFSM State Map

Start Event[Guard] Target Action

[start]

UNLOCKED

OVERRIDE

<<timeout = {timeout}>>

LOCKED

{
println("Timeout")
cancelOverride()
}

OVERRIDE

CARD [{cardId→requireNotNull(cardId);isOverrideCard(cardId);}]

LOCKED

{
cancelOverride()
}

OVERRIDE

CARD [{cardId→requireNotNull(cardId);!isValidCard(cardId);}]

UNLOCKED

{cardId->
println("Allowed invalid card:$cardId")
unlock()
}

OVERRIDE

CARD [{cardId→requireNotNull(cardId);isValidCard(cardId);}]

UNLOCKED

{cardId->
println("Allowing valid card:${cardId}")
unlock()
}

LOCKED

CARD [{cardId→requireNotNull(cardId);isOverrideCard(cardId);}]

OVERRIDE

{
activateOverride()
}

LOCKED

CARD [{cardId→requireNotNull(cardId);isValidCard(cardId);}]

UNLOCKED

{
unlock()
}

LOCKED

CARD [{cardId→requireNotNull(cardId){"cardId is required"};!isValidCard(cardId);}]

LOCKED

{cardId->
requireNotNull(cardId)
invalidCard(cardId)
}

UNLOCKED

<<timeout = {timeout}>>

LOCKED

{
println("Timeout. Locking")
lock()
}

UNLOCKED

CARD [{cardId→requireNotNull(cardId);isOverrideCard(cardId);}]

LOCKED

{
lock()
}

UNLOCKED

PASS

LOCKED

{
lock()
}