From 280f49bf36cc7ac56b3f0345a03b2d54dbf9d028 Mon Sep 17 00:00:00 2001 From: Bertho Stultiens Date: Tue, 28 Jul 2026 10:11:24 +0200 Subject: [PATCH] hal: Introduce post_export in halcompile so parameters can be preset. --- docs/src/hal/comp.adoc | 11 ++++++++++ src/hal/components/multiswitch.comp | 31 +++++++++++++++++++---------- src/hal/utils/halcompile.g | 9 ++++++++- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/docs/src/hal/comp.adoc b/docs/src/hal/comp.adoc index d382a70f475..0e66c1a16b3 100644 --- a/docs/src/hal/comp.adoc +++ b/docs/src/hal/comp.adoc @@ -328,6 +328,10 @@ When implementing your own `rtapi_app_main()`, call the function `int export(cha If specified, call the function defined by 'EXTRA_CLEANUP' from the automatically defined 'rtapi_app_exit' or, in case of a detected error, in the automatically defined 'rtapi_app_main'. +* 'option post_export yes' - (default: no) + + If specified, call the function defined by 'POST_EXPORT' for each instance. + If using the automatically defined 'rtapi_app_main', 'extra_arg' is the number of this instance. + * 'option userspace yes' - (default: no) + If specified, this file describes a non-realtime (formerly known as "userspace") component, rather than a regular (i.e., realtime) one. A non-realtime component may not have functions defined by the 'function' directive. @@ -434,6 +438,7 @@ Variable and function names that can not be used or are likely to cause problems * 'rtapi_app_exit' * 'extra_setup' * 'extra_cleanup' +* 'post_export' == Convenience Macros @@ -449,6 +454,12 @@ The details of `struct __comp_state` and these macros may change from one versio * `EXTRA_CLEANUP()` - Use this macro to begin the definition of the function called to perform extra cleanup of the component. Note that this function must clean up all instances of the component, not just one. The "pin_name", "parameter_name", and "data" macros may not be used here. +* `POST_EXPORT()` - Use this macro to begin the definition of the function called to perform extra setup _after_ all pins and parameters have been created for this instance. + This function is called just before the export() function returns. + You can use the POST_EXPORT() function to preset parameter values you otherwise would not be able to set. + Return a negative UNIX 'errno' value to indicate failure, or 0 to indicate success. + + Note: POST_EXPORT() should not change 'personality'. + If you need to adapt 'personality', then you must do so in EXTRA_SETUP(), which runs before pins and parameters are created. * 'pin_name' or 'parameter_name' - For each pin 'pin_name' or param 'parameter_name' there is a macro which allows the name to be used on its own to refer to the pin or parameter. diff --git a/src/hal/components/multiswitch.comp b/src/hal/components/multiswitch.comp index 4a6068635cc..e1f2eae4c40 100644 --- a/src/hal/components/multiswitch.comp +++ b/src/hal/components/multiswitch.comp @@ -22,19 +22,20 @@ don't connect the extra pin. component multiswitch """This component toggles between a specified number of output bits."""; -pin in bit up = false "Receives signal to toggle up"; -pin in bit down = false "Receives signal to toggle down"; +pin in bool up = false "Receives signal to toggle up"; +pin in bool down = false "Receives signal to toggle down"; -param rw unsigned top-position "Number of positions"; -param rw signed position "Current state (may be set in the HAL)"; +param rw ui32 top-position "Number of positions"; +param rw si32 position "Current state (may be set in the HAL)"; -pin out bit bit-##[32:personality] = false "Output bits"; +pin out bool bit-##[32:personality] = false "Output bits"; modparam dummy cfg """cfg should be a comma-separated list of sizes, for example cfg=2,4,6 would create 3 instances of 2, 4 and 6 bits respectively. Ignore the "personality" parameter, that is auto-generated."""; function _ ; option extra_setup yes; +option post_export yes; option count_function yes; option period no; @@ -53,24 +54,32 @@ FUNCTION(_) { int i; // debounce - if (up && !old_up) { position++; } - if (down && !old_down) { position--;} + if (up && !old_up) { position_set(position + 1); } + if (down && !old_down) { position_set(position - 1);} old_up = up; old_down = down; - if (position < 0) position = top_position; - if ((unsigned)position > top_position) position = 0; + if (position < 0) position_set(top_position); + if ((unsigned)position > top_position) position_set(0); for (i = 0 ; i < personality; i++){ - bit(i) = (i == position); + bit_set(i, i == position); } } EXTRA_SETUP(){ (void)prefix; + // This sets the instance's personality and the number of pins to export. personality = cfg[extra_arg]; - top_position = personality - 1; + return 0; +} + +POST_EXPORT(){ + (void)prefix; + (void)extra_arg; + // This can only be set after the parameter is created. + top_position_set(personality - 1); return 0; } diff --git a/src/hal/utils/halcompile.g b/src/hal/utils/halcompile.g index 62c4da5d336..4c15f148eef 100644 --- a/src/hal/utils/halcompile.g +++ b/src/hal/utils/halcompile.g @@ -120,7 +120,7 @@ mp_decl_map = {'int': 'RTAPI_MP_INT', 'dummy': None} # names. That includes not only global variables and functions, but also # HAL pins & parameters, because comp adds #defines with the names of HAL # pins & params. -reserved_names = [ 'comp_id', 'fperiod', 'rtapi_app_main', 'rtapi_app_exit', 'extra_setup', 'extra_cleanup' ] +reserved_names = [ 'comp_id', 'fperiod', 'rtapi_app_main', 'rtapi_app_exit', 'extra_setup', 'extra_cleanup', 'post_export' ] def _parse(rule, text, filename=None): global P, S @@ -401,6 +401,8 @@ static int comp_id; print("static int extra_setup(struct __comp_state *__comp_inst, char *prefix, long extra_arg);", file=f) if options.get("extra_cleanup"): print("static void extra_cleanup(void);", file=f) + if options.get("post_export"): + print("static int post_export(struct __comp_state *__comp_inst, char *prefix, long extra_arg);", file=f) if not options.get("no_convenience_defines"): print("#undef TRUE", file=f) @@ -538,6 +540,9 @@ static int comp_id; print(" if(__comp_last_inst) __comp_last_inst->_next = inst;", file=f) print(" __comp_last_inst = inst;", file=f) print(" if(!__comp_first_inst) __comp_first_inst = inst;", file=f) + if options.get("post_export"): + print(" r = post_export(inst, prefix, extra_arg);", file=f) + print(" if(r != 0) return r;", file=f) print(" return 0;", file=f) print("}", file=f) @@ -776,6 +781,8 @@ int __comp_parse_names(int *argc, char **argv) { print("#define EXTRA_SETUP() static int extra_setup(struct __comp_state *__comp_inst, char *prefix, long extra_arg)", file=f) print("#undef EXTRA_CLEANUP", file=f) print("#define EXTRA_CLEANUP() static void extra_cleanup(void)", file=f) + print("#undef POST_EXPORT", file=f) + print("#define POST_EXPORT() static int post_export(struct __comp_state *__comp_inst, char *prefix, long extra_arg)", file=f) if options.get("period"): print("#undef fperiod", file=f) print("#define fperiod (period * 1e-9)", file=f)