I assume you have suffered through the precursor to this writeup, 'a mini-tutorial on the flow of status information in LinuxCNC'.
-- Before I start, let me point out the following facts in the example I used to describe the flow of status information: - we started with a HAL pin - we ended up with a Python attribute. Now both are 'late binding' - most of you are used to defining HAL pins in components, and how pins are glued together at _startup time_. Also many of you are familiar with Python programming; that isnt compiled either - reedit, reexecute, done. Now remember the steps from motion 'probe-input' to Python 'probe_input'. We went through 2 data structures - emcmot_status_t and EMC_MOT_STAT to convey that single bit. Unfortunately, these data structures are compiled with the C and C++ compilers respectively - that's called 'early binding' and it translates into the following limitation: The type and layout of information bits which can be conveyed through an NML message is fixed at compile time. So no matter how flexible HAL or Python is - there you go: either them LinuxCNC gurus have forethought your use case for an extra pin value in a NML message, or you're out on the limb. Can't be done without without several nontrivial changes here and there, and it's pretty hard to get right first time, nevermind having it supported in mainline code. Thats why nobody does it, and it is also the reason why emcmot_status_t and EMC_MOT_STAT have become the kitchen sink of status information: just in case somebody might need it, keep it there. Result: several incomprehensible whales of datastructures. Now assume a non-LinuxCNC application of HAL/RTAPI for a moment - just for the sake of argument, assume the prototypical 'garden sprinkler' application. Its is safe to assume that the user will find HAL to be super-flexible, but be less than enthusiastic about the set of NML messages provided to talk to it, and report status from it - assuming the sprinkler controller is some headless board, maybe a Beaglebone. Trajectory status doesnt make a whole lot of sense when reporting whether a faucet is open or closed. Standing back a bit, it's like we've just shot ourselves in the foot big time: we have super-flexible languages for GUI's, we have HAL and its stunning arsenal of components, and we have a veritable straightjacket of a limitation when communicating between the two. No wonder folks hit upon the idea they could circumvent the NML restrictions by including HAL access in UI's, and thats where we are with PyVCP, and GladeVCP: we have a very restricted mechanism to communicate which is in principle network capable, and a much more generic mechanism which is not network capable, and we have _both of them in parallel_, inheriting the union of restrictions derived from both. I'm sorry, this cannot be it. So we arrive at requirement #1: Any future NML replacement should be late-binding capable. That means that message contents become subject to integrator definition and extension, as opposed to guru discretion. Note that I'm not suggesting everybody _has_ to do this; to the contrary, common message types will surely be held in some library, and reused. It is all about enabling it, not forcing it. ---- Let's look for a moment what type of information is reported from HAL components to task and other using code: it turns out It is all scalar values: floats, signed ints, unsigned ints, booleans. (there are some minor exceptions like the gcode filename which are not relevant here). That maps perfectly on the HAL primitive datatypes. However, an essential feature of NML is to arrange single scalar values into a compound structure, like EMC_MOTION_STAT or EMC_IO_STAT, and to report those structures 'in one go'. HAL as it stands doesnt support that. So we arrive at requirement #2: Any future NML replacement must support grouping of scalars into compound messages. That brings the question: how and where is that grouping done? In essence you need a way of expressing 'I want message X to contain values A, B and C, which are of type int, float and bool'. That's a typical language feature: C does it, C++ does it, Python does it, Google Protobufs does it, unfortunately HAL/halcmd does not. So the options are: a) use an existing language to do the grouping b) extend HAL to support grouping. a) has been the NML approach, with the consequences outlined in the previous article. Whatever the language: it is a second language, which must be learned and understood, and brings its own set of restrictions. b) is new and requires some thought. If route b) is chosen, it would be wise to get away with the very minimum bloat of HAL per se, and do the rest elsewhere - in using code, like components. So lets think though this a bit. Object grouping in HAL ---------------------- In HAL right now we have the following objects: pins, signals, params, threads, modules, thread functions. Assume we add to the above two new objects: a 'group', and a 'member' object - both of them having a HAL name, a type, and several attributes, just like the rest of them. HAL groups would have the following attributes: - a name and a uniqe integer ID - some, say 2, integer attributes, which are not interpreted by HAL per se but are for 'using code only'. - an ordered list of members. A HAL member would have the following attributes: - any member is a part of a single given group. - a member refers to a HAL signal, which must exist at the time when the member is added to a group. - again, say 2, attributes; an integer and a float value; again not interpreted by HAL per se but by using code only. To support groups and members, the HAL C library needs a bit of extension - adding, deleting or iterating over groups; adding and deleting members. Also halcmd needs to understand the new objects, and be able to display them. Smells like a spec, so let's do A simple usage example: defining a group in halcmd: --------------------------------------------------- We use 'monitoring a battery-backed power supply' as example scenario. Assume a meaningful status report for such a power supply would contain: current voltage, current load, is the mains fuse blown/OK, are we're running on battery, or on mains. Now let's translate that into a HAL group: ----- extended halcmd ---- # declare the signals - these must exist before using them in a member newsig volt float newsig amps float newsig mains bit newsig fuse-ok bit # here we would link any pins reporting actual values from the power supply # to the signals declared at the top net volt meter.voltage # etc etc # declare named group 'power-suply' # groups have a unique ID (23 below), plus two optional userargs (10 and 1000). # HAL doesnt care about userargs, except they be integer newg power-supply 23 10 1000 # add some members to this group: # note members can have an optional int and a float userargs parameter # HAL ascribes no meaning to them newm power-supply volt 1 0.1 newm power-supply amps newm power-supply mains 1 newm power-supply fuse-ok 1 ---------------------------- Great, so what does this gain us? Nothing except we now have a named HAL object 'power-supply' which has several member signals. It's a group definition, nothing else - HAL per se will not do anything with it. We added some int and float params to group and members. Not much more. That's why the support code in HAL and halcmd for dealing with groups and members is fairly minimal. This turns us to How is a group used? -------------------- There are two users of the HAL group code: - halcmd - to define a group and members, as outlined above. - one or several HAL components: to actually do something useful with a group: the HAL library would provide a few new functions: - iterate of the list of groups, retrieve a group name and its parameters - likewise, iterate over members of a group, and retrieve their names and parameters. Now let's assume we would design a 'status reporter' for our power supply. What that would do is inspect a HAL group periodically, and send a status update message to some interested entity, maybe a GUI. That reporter could well be a userland HAL component. The outline would look like so: - normal HAL initialisation. Nothing new here. - ask HAL for group 'power-supply', retrieving group parameters. - walk the list of group members, retrieving each member parameter. - do something useful periodically, based on the above, running until shutdown. at this point, the report component can ascribe some meaning to group and member parameters. For instance, report could: - interpret group parameter 1 (1000) as a periodic update timer - meaning a status update message should be sent unconditionally every second. - interpret group parameter 2 (10) as a an internal change detection timer - meaning members are checked as follows: -- default member parameter - zero - means no periodic check of this member signal -- member parameter '1' means - include in periodic check ---- in the case of the float 'volt' value, the float param '0.1' is used as an epsilon value to trigger the 'this value has changed' condition - float equality comparisons are notoriously unreliable and an epsilon parameter deals with that issue. Note that the behavior of the report component - timers, what to check for etc - is completely driven by the HAL group and member attributes, so there is actually very few code which is specific to the 'power supply' theme, in fact its completely generic. The behavior would be as follows: - every second, a status update is sent no matter what. - if any of: mains goes away, the fuse is blown, or the voltage changes by more than 0.1 volts a status update is sent after the next 10msec internal poll interval. Also, note a single component can report for an arbitrary number of groups 'in one go'. The only thing left here is 'what happens when a change is detected'? Well, a HAL status update message is sent, by a mechanism which I already discussed - using zeroMQ, and - for a start - the PUBLISH/SUBSCRIBE mechanism to any interested readers - for instance HAL widgets in a GUI. I leave the details how such an update message is sent with ZeroMQ and protobufs for a separate installment of the 'How to break LinuxCNC effectively' miniseries; but be it enough here that even at that level, the group mechanism is very useful: - the member list drives the encoding of values in the protobuf serialisation. The message format need not know about the power supply fields, types and so on - see requirement #1. - the group name can be used as a ZeroMQ channel name - interested consumers subscribe to the 'power-supply' ZMQ channel, and get updates - done. In summary: HAL groups and members support the definition of messages, with a late binding approach, and with a fairly minimal extension to HAL per se, and no interpretation or using code within the HAL library whatsoever. Any using code will be components which are group/member aware. Great. Now how's that going to help with dumping NML and replacing EMC_STAT with this grandiose scheme? ------------------------------------------------------------------------------------------------------- Well, really not much different like the above group definition, just longer. All the needed types are there. Nested structures can be dealt with by HAL naming - for instance "status.traj.probe_tripped" conveys the 'object nesting', even if its just a HAL name in a flat namespace. The only thing which is not very well covered is arrays, for instance the array of axes, or array of analog/digital I/O pins used in the interpreter. That has it's reason in the fact that HAL doesnt support an array notation. I dont see that as a reason to add one - that doesnt bring enough upside IMO. The issue can be dealt by rolling the index into the HAL name - for instance, 'status.digital-in-04' and thats' not different from current practice. So the above lets us define the equivalent of EMC_STAT with HAL groups. So how's the migration of motion and iocontrol going to happen? --------------------------------------------------------------- Unfortunately, motion and iocontrol dont have a clue about groups and members right now, so how's that going to work? The answer to this is: they dont need to know zilch about groups or members, that 'need to know' is confined to the reporting mechanism. What is needed, however, is: --> each scalar which is to be reported through the group mechanism needs to be exported as a HAL pin so it can be linked to a member signal <---- Note that many members of emcmot_status_t are already exported as pin, so there's nothing new here, and also the breakage potential is limited: the old scheme can remain in place, and run in fact in parallel, while the new needed pins are added and status reporting is defined. Eventually we can put EMC_STAT, and emcmot_status_t to rest on the old code burial grounds. --- Please let me know if where above makes any sense, or not at all, where it is unclear, and point me to out outright errors and omissions. - Michael ps: for the very curious: I did a proof-of-concept of groups and members, hal_lib and halcmd support, as well as a generic reporter with ZMQ messaging and protobufs here: http://git.mah.priv.at/gitweb?p=emc2-dev.git;a=tree;f=src/hal/halreport;hb=4259166865c681017b6009f041ac4d1ed5e16439 This is not anything mergeable, and way too bloated - it supports a group notification mechanism from kernel modules which isnt needed, and lots of other fluff which will got away. But it gives a rough effort indication: v0.001 of the generic HAL reporter component is less than 1000 lines; the hal_lib.c group/member support much less than that. A very basic Python subscriber to the reporter's channel is here: http://git.mah.priv.at/gitweb?p=emc2-dev.git;a=blob;f=src/hal/halreport/sub.py;h=85ffeae0e4a576755aaab186d7378b29cdeca75d;hb=4259166865c681017b6009f041ac4d1ed5e16439 ------------------------------------------------------------------------------ Free Next-Gen Firewall Hardware Offer Buy your Sophos next-gen firewall before the end March 2013 and get the hardware for free! Learn more. http://p.sf.net/sfu/sophos-d2d-feb _______________________________________________ Emc-developers mailing list Emc-developers@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/emc-developers