Skip to content

Latest commit

 

History

History
109 lines (91 loc) · 5.36 KB

File metadata and controls

109 lines (91 loc) · 5.36 KB

Switching between the C and Python paths

The two language paths of this tutorial teach the same Lingua Franca concepts with the same labs, exercises, and checkpoints. If you finished the labs in one language, you can redo any lab in the other by translating only the reaction bodies and a handful of API calls. Everything at the LF level (reactors, ports, connections, timers, actions, modes, deadlines, federated) is identical in both paths.

What is identical

  • All LF syntax: reactor, main reactor, federated reactor, ports, state, parameters, timer, logical action, physical action, connections (including after), modes with reset/history transitions, and deadline(...) clauses.
  • Target properties used in the labs: timeout, keepalive.
  • The commands: lfc src/labN/Program.lf and bin/Program, run from the C or Python project root.
  • The generated layout: bin/, src-gen/, and (Lab 8) fed-gen/ with the RTI, the per-federate programs, and the bin/<Name> launch script.
  • The observable behavior of every lab program, including the tags, microsteps, and deadline patterns in the expected outputs. (Lab 7 Part B uses a different grid size per language so that pass times suit each runtime's speed, so the reported path lengths differ; the anytime behavior is the same.)

Declarations inside LF (types)

C is typed; Python is not. The same declarations look like this:

Declaration C Python
Input port input x: int input x
Output port output y: int output y
State variable state count: int = 0 state count = 0
Time parameter period: time = 1 s period = 1 s
Typed action logical action a: int logical action a

One naming difference: in is a reserved word in Python, so the Python labs name input ports inp where the C labs use in.

Reaction body APIs, side by side

Purpose C Python
Print lf_print("v %d", x); print(f"v {x}")
Read an input x->value, x->is_present x.value, x.is_present
Write an output lf_set(y, v); y.set(v)
State / parameter self->count self.count
Schedule an action lf_schedule(a, d); a.schedule(d)
Schedule with payload lf_schedule_int(a, d, v); a.schedule(d, v)
Action payload a->value a.value
Elapsed logical time lf_time_logical_elapsed() lf.time.logical_elapsed()
Logical time lf_time_logical() lf.time.logical()
Physical time lf_time_physical() lf.time.physical()
Elapsed physical time lf_time_physical_elapsed() lf.time.physical_elapsed()
Current tag lf_tag().time, lf_tag().microstep lf.tag().time, lf.tag().microstep
Set the next mode lf_set_mode(MovingUp); MovingUp.set()
Request a clean stop lf_request_stop(); lf.request_stop()
Mid-reaction deadline check lf_check_deadline(self, true) self.check_deadline(True)
Time literals in body code MSEC(250), SEC(1) MSEC(250), SEC(1)

Time values are 64-bit nanosecond integers in both targets. In C, print them with %lld after casting to long long; in Python they are ordinary ints.

Preambles and external code

Both targets use preamble {= ... =} blocks, but they hold different things:

  • C: #include directives, helper functions, and thread functions. A file-level preamble may only declare symbols shared across reactors; definitions go inside a reactor's preamble. Threads use lf_thread_t and lf_thread_create(...) from "platform.h", and sleeping uses lf_sleep(...) from the same header.
  • Python: import statements and helper functions. Anything defined in a reactor's preamble is reached through self: after import threading, use self.threading.Thread(...); a preamble function def helper(self, ...) becomes the method self.helper(...). Threads that block on input() are created with daemon=True so the process can exit while they are blocked; sleeping uses self.time.sleep(seconds) (note: seconds, not nanoseconds).

The keyboard pattern used in Labs 5, 6, and 8 is the same in both languages: a thread blocks on standard input and schedules a physical action for each line; only the thread-creation and read calls differ.

The one API asymmetry worth knowing (Lab 7)

The LF handbook describes the mid-reaction deadline check, lf_check_deadline(), as implemented only for the C target. In practice, the Python runtime shipped with LF v0.13.0 provides the equivalent method self.check_deadline(invoke_handler), and the Python Lab 7 uses it. If you need a portable fallback in Python, compare lf.time.physical() against lf.time.logical() plus your budget; that is an ordinary target-language computation, not an LF feature.

Redoing a lab in the other language

  1. cd into the other project root (C or Python); the lab layout and README structure are identical.
  2. Read the same lab README there; commands, exercises, and checkpoints match, with the code snippets already translated.
  3. When you translate your own reaction bodies, work through the tables above; almost every line maps one to one.
  4. Expect the same output, with two caveats: the Python runtime prints a Using Python version banner, and in federated runs the C lf_print lines carry a Fed N (...) prefix while Python print lines do not.