Skip to content

pseja/visual-fsm-editor

Repository files navigation

Visual FSM Editor, Code Generator, and Runtime Monitor

A full-stack desktop toolchain for designing, generating, and monitoring interpreted finite state machines. Built as a final project for the ICP course at FIT VUT, it spans multiple disciplines: visual graph modeling, formal syntax parsing (XML), on-the-fly C++ source generation, compiler chaining, and networked Inter-Process Communication (IPC).

It covers the complete engineering loop: define a state machine visually, serialize it to XML, generate a standalone runnable C++ daemon, shell out to compile it, and monitor its real-time telemetry over a TCP socket.

The submitted version received 97/100.

Architecture

This project can be viewed as an integrated IDE for state logic. The complexity lies in perfectly synchronizing different representations of the same logical machine across multiple layers of abstraction.

  • Visual Model (Qt): The user's interaction layer.
  • AST & Serialization (XML): The canonical truth of the automaton, separated from GUI concerns.
  • Metaprogramming Layer (C++ CodeGen): Translating the model's structure, standard library behaviors, and user-provided C++ snippets into a completely standalone Qt/C++ source file.
  • Compilation & OS Process Management: The GUI invokes system compilers (g++, pkg-config) to build the generated code and spawns it as a child process.
  • Networked Telemetry (TCP): The GUI connects back to the generated process using a continuously streaming XML protocol, translating backend execution into visual state updates.

The Pipeline

The TOF (Timer-Off) example demonstrates the complete lifecycle of an automaton within the tool suite.

1. XML Parsing & Visual Reconstruction

TOF import and run

Importing an XML definition completely rebuilds the structural graph of the machine. The parser dynamically instantiates the nodes and edges, preserving inputs, outputs, variables, and inlined C++ routines. Watch as the GUI connects into the live telemetry loop instantly.

2. Interactive Modeling & AST Mutation

Editing the automaton

Here, visual interactions seamlessly mutate the underlying abstract structure. By adding new states, setting local state-action code ({ output(...) }), and wiring transitions with guards, the user manipulates the machine logic directly in the editor. Because code and graph share the same data definitions, modifications survive the round-trip through export and re-import.

3. Immediate Execution & Code Generation

Edited automaton running

After modifying the automaton, hitting "Run" triggers a deeply technical sequence beneath the hood: the model is exported to XML, cross-compiled via the code generator into C++, compiled by the system toolchain, executed as a background process, and immediately connected-to by the Qt graphical monitor. The new visual branch lights up as execution routes through it.

4. Re-importing the Saved State

Import and run

Because the canonical format is an extensible XML representation, picking up work from previous states is trivial. This demonstrates importing the edited TOF machine back into a fresh instance of the workspace.

5. Networked Telemetry & Protocol Bridging

Client connection

This highlights the IPC decoupling. The GUI is not executing the automaton. It is merely a TCP client attaching itself to a socket opened by the generated standalone execution daemon. The executable streams XML packets (timer updates, state changes) which the GUI parses and projects back onto the visual diagram in real time.

6. Command-Line Interaction

CLI interaction

Because the generated daemon handles its own logic, it offers a CLI interface for inputs. This empowers scriptable testing or integration with outside processes that do not require any graphical overhead.

7. Exporting the Logic Payload

Export flow

The automaton can be cleanly emitted as a .cpp payload. This file contains the state machine classes, the internal variable routing, a standalone TCP server, and an input parser block that handles external triggers.

8. The Standalone Target Environment

Generated runtime

Once generated, the C++ interpreter is completely decoupled from the editor. It brings its own event loop, terminal parser, networking layer, timer management, and state machine transitions.

The XML Automaton Schema

All these systems orchestrate around this simple plaintext root definition. It is readable, diffable, and completely independent of any proprietary binary wrappers.

<automaton name="TOF">
  <inputs>
    <input name="in"/>
    <input name="set_to"/>
  </inputs>
  <outputs>
    <output name="out"/>
    <output name="rt"/>
  </outputs>
  <variables>
    <variable name="timeout" type="int" value="5000"/>
  </variables>
  <transition from="IDLE" to="ACTIVE">
    <condition event="in"><![CDATA[Qtoi(valueof("in")) == 1]]></condition>
  </transition>
</automaton>

Automaton Type

The project implements a Moore-type interpreted finite state machine, extended heavily to function as a software controller. In practice, it mirrors an Execution Control Chart (ECC) found in IEC 61499 industrial control systems.

Key behavioral upgrades:

  • C++ Native Actions: States run arbitrary C++ on entry.
  • Complex Guardianship: Transitions rely on real-time hardware variables, delays, input triggers, and boolean evaluations.
  • Dynamic Scheduling: Timed delays (@ timeout) are embedded in the automaton model, granting proactive reactivity (it takes action based on its own internal clocks rather than waiting for inputs).
  • Embedded Abstraction: The code generator supplies a helper DSL inside the C++ execution environment (valueof(), defined(), elapsed(), and output()), making the small C++ entry snippets powerful and succinct.

Runtime Monitoring & API

Because the GUI and the executing runtime are completely severed by a network boundary, they speak a strict XML dialect over TCP. This has huge implications for the generalizability of the runtime:

A client drives the machine with generic commands:

<command type="set"><name>in</name><value>1</value></command>
<command type="call"><name>req_rt</name></command>
<command type="status"></command>

And the executing daemon responds asynchronously with lifecycle state updates:

<event type="timerStart"><from>TIMING</from><to>IDLE</to><ms>5000</ms></event>
<event type="output"><name>out</name><value>1</value></event>

This ensures that the generated interpreter could theoretically be managed by a web server, a Python testing script, or another industrial standard dashboard with zero modification to the FSM.

Architectural Separation & System Documentation

The project successfully divides responsibilities to prevent monolithic spaghetti code, distributing subsystems across different logical domains (parsing, GUI, networking, OS processes):

Architecture Data Flow

Component Level Responsibility & Field
Backend Model (fsm, state) In-memory object graphs representing states and transition routes.
Serialization (xmlparser) DOM parsing and writing to establish the structure as the canonical source of truth.
Code Generation (CodeGenerator) Compiler meta-design. Stringifying logical schemas, transitions, and inline C++ actions into compilable macros.
Networking (GuiClient) Managing async TCP socket I/O in Qt to bridge external telemetry back to the GUI.
Frontend UI (AutomatView, etc) Qt Graphics / Canvas implementation and interactive state diagrammatics.

Class Hierarchy

Comprehensive Architecture Document (doc/architecture.pdf)

Rather than duplicating deep technical decisions here, please refer to doc/architecture.pdf for a rigorous breakdown. Exploring that document is recommended to understand:

  • TCP/XML Protocol Specification: Network framing, keep-alives, broadcast mechanics, and full sequence diagrams mapping how the GUI acts as an IPC client.
  • Qt State Machine Extension Details: How the custom FSM class hierarchy wraps native Qt states to incorporate runtime data, timers, and variables independently of the UI.
  • Formal XML Schema Requirements: The structural rules behind serialization and deserialization of the Moore machine format.
  • Extensive Component Context: Thorough details on GUI contextual editing states, and code generation translation.

Tech Stack

Building a pipeline this interconnected required tapping into an array of ecosystems:

  • C++17 for strict type safety and modern language features natively mapped in user scripts.
  • Qt 5 (Widgets, Core, Gui, Network, Xml) for GUI scaffolding, TCP server bindings, DOM manipulation, and asynchronous event loops.
  • CMake / Make for reliable multi-stage daemon compilation.
  • Doxygen for rigorous API generation.
  • Linux / GCC (specifically modeled around FIT/Merlin expectations) to harness low-level process spawning (sys/wait.h, unistd.h) underneath QProcess.

Build and Run

Prerequisites

  • Qt 5 development libraries

  • cmake, make, g++, pkg-config, doxygen

Quick Start

# Build the editor toolkit
make

# Run the unified GUI
make run

# Build all generated independent daemons stored in generated/
make gen

# Export API references
make doxygen

Included examples

The repository ships with several example automata that cover both simple and timed behavior:

Example What it demonstrates
Addition.xml Event-driven arithmetic with a short delayed reset
CounterWithReset.xml Stateful counting logic
EdgeDetector.xml Input-change driven behavior
TimeoutOnly.xml Minimal timer-based transition flow
Timers.xml Multiple timer-oriented transitions
TOF5.xml, TOF5s.xml Timer-off style control logic
TrafficLight.xml A larger timed automaton with several outputs and phases

(Additional parser tests are housed under examples/parser_testing_examples/)

Environment notes

This project was developed around the FIT/Merlin Linux environment and the build files currently reflect that. In particular:

  • CMakeLists.txt points to a specific Qt 5.9.2 installation path
  • make run sets QT_QPA_PLATFORM_PLUGIN_PATH for that same environment
  • the generated runtime build path also assumes a Qt 5.9 style setup available through pkg-config

So if you are building outside that environment, expect to adjust the Qt paths first. The code itself is standard Qt/C++, but the current build configuration is opinionated about where Qt lives.

Known limitations

  • The inscription language is intentionally limited to small synchronous C++ snippets, it is not a full embedded scripting environment
  • All generated variables are global in the runtime layer, so naming discipline matters

Repository layout

├── src/
│   ├── backend/         # FSM model, XML parser, generator, client, logger
│   ├── frontend/        # Qt GUI, scene editor, state and transition items
│   └── main.cpp         # Application entry point
├── examples/            # Sample automata and parser test inputs
├── doc/                 # Generated docs and architecture.pdf
├── Makefile             # Main developer entry point
├── CMakeLists.txt       # Qt/CMake project definition
├── Doxyfile             # Doxygen configuration
└── README.txt           # Original short course-project summary

Team

Built by:

Name Main focus
Matúš Csirik Project lead, code generation, runtime client, documentation
Lukáš Pšeja FSM core model, parser, logging
Václav Sovák GUI diagram editor, runtime interaction

About

A full-stack C++/Qt desktop IDE for visual modeling, code generation, compilation, and real-time TCP telemetry monitoring of interpreted finite state machines.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages