Repository navigation
Bind internal state machines to Python - #16
Open
lestarch-autobot wants to merge 9 commits into
Open
lestarch-autobot wants to merge 9 commits into
lestarch-autobot wants to merge 9 commits into
Conversation
Components with instances of internal state machines are now accepted. Each action and guard of an instantiated machine becomes a forwarded handler (guards const, returning a checked bool), missing ones are reported at init, the template stubs them (guards return False), and the instances' getState/sendSignal methods and the component's SmId are bound. External state machines and instances with 'hook' queue-full behavior are rejected with errors saying why. Co-authored-by: M Starch <LeStarch@googlemail.com>
The module defining an internal state machine (or the annotated component a machine is nested in) binds its <Machine>_State enumeration and <Machine>StateMachineBase::Signal as <Machine>_Signal, so a machine shared by several instances or components is registered once. Co-authored-by: M Starch <LeStarch@googlemail.com>
Fixtures with a shared internal machine (typed, untyped and string signals; two instances; two components), a machine nested in a component, a machine defined in an imported model, an external machine and a hooked instance. Co-authored-by: M Starch <LeStarch@googlemail.com>
Add a State Machines section and update the table of unsupported features. Co-authored-by: M Starch <LeStarch@googlemail.com>
Co-authored-by: M Starch <LeStarch@googlemail.com>
…the GIL on blocking sends A state machine value of an alias type is passed by const reference, as F Prime declares it, even when the alias names a primitive. Signals sent to a 'block' instance release the GIL while waiting; unsized string signals are checked against FW_FIXED_LENGTH_STRING_SIZE. Signals are bound in value order, action and guard views share a base, and duplicate output paths are rejected. Co-authored-by: M Starch <LeStarch@googlemail.com>
Co-authored-by: M Starch <LeStarch@googlemail.com>
…ehavior Co-authored-by: M Starch <LeStarch@googlemail.com>
…tching thread Co-authored-by: M Starch <LeStarch@googlemail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Python components (
@ fprime-python) can now contain internal state-machine instances. An internal machine is one whose states, signals, actions and guards are all written in FPP. Each of the machine's actions and guards becomes a forwarded Python handler. Python can send signals to each instance and read its state. Before this PR, any state-machine instance was rejected.Design points
view.py: aStateMachineHandlerView(HandlerView)base, withStateMachineActionViewandStateMachineGuardViewon top. These are added toComponentView.handlersthe same way as Bindhookqueue-full overflow hooks to Python #15'sOverflowHookView, so the generic forwarder and template loops emit them unchanged. Guards setIS_CONSTandRETURNS_STRICT_BOOL: a guard is aconstoverride, and returning a non-bool(includingNone) raisesTypeError. The template's guard stubs returnFalse.const T&. Ports, by contrast, take aliases by value, so the port rule is deliberately not reused here.SmIdis anative_enumbound inside the component's class.<M>_State(F Prime enum wrapper) and<M>_Signal(native_enum, not exported) are bound once per machine in<M>StateMachineBindingAc.*, because pybind11 rejects a second registration.__FPRIME_INITIAL_TRANSITIONand__FPRIME_UNINITIALIZEDare exposed, because Python actually receives them.<inst>_sendSignal_<s>checks string values against their serialized size. Onblockinstances it releases the GIL (Python's global lock) while waiting for queue room.<inst>_getStateis also bound.initraisesAttributeErrorif any action or guard is missing (the same pattern as Bindhookqueue-full overflow hooks to Python #15's overflow hooks). The initial-transition action runs insideinit, before the queue is created and the ports are connected.visitor.emitraisesUnsupportedModelErrorwhen two generated files would get the same path.Still rejected, each with an error naming the reason
hook: their overflow hook takes a rawFwEnumStoreTypesignal and aFw::SerialBufferBasevalue.Docs and tests
smId, guard rules, the enums, threading (handlers run on whichever thread dispatches the queue), queue-full behavior per instance (assert/drop/block, and theblockself-deadlock caveat), init-time behavior, and the uncaught-exception caveat. The unsupported-features table is updated.StateMachines.fpp,SmShared.fpp,SmExternal.fpp,SmHook.fpp,SmForeign.fppandSmProducts.fpp. They cover signatures (including a "wide" machine with alias, enum, struct and unsized-string values, a nested state and a choice), GIL handling, the startup check, stubs, the bindings, deduplicated registration, and every rejection.Validation
mypyis clean, andpytest testspasses 30 of 30.c++ -fsyntax-onlyof the fprime-python output for the test fixtures, against F Prime headers and pybind11, gives 0 errors in 11 of 11 files.Probemachine onPythonGc(alias-typed value,blockinstance):__FPRIME_INITIAL_TRANSITION.Falsefor value 1, and the machine staysIDLE. For values 2 and 4 it returnsTrue, the action receives the value, and the machine moves toBUSY.getState()returnsProbe_State.setupfails withPythonGc does not implement state machine action FprimePythonReference_Probe_action_store. TheBufferManager::cleanupteardown assert that follows already happened before this PR.blockself-deadlock caveat) is fixed in the last commit.Co-authored-by: M Starch LeStarch@googlemail.com