I have been wrestling with a problem for a little while now and thought I might send this out into the ether for others to comment upon. (Or, in other words, Dear Lazyweb…)
I am writing system which collects data from embedded computers in my car (ECUs) over the CAN bus, using the on-board diagnostics port in the vehicle. This requires me to generate packets on the CAN bus, listen to responses, including managing flow control, and then interpret the resulting byte arrays.
I have sorted everything but the last little bit of that particular data pipeline. I have a prototype which can convert the byte arrays into "raw" values by interpreting them either as bitfields and producing booleans, or as anything from an unsigned 8 bit integer to a signed 32 bit integer in either endianness. Fortunately none of the fields I'd need to interpret are floats.
This is, however, pretty clunky and nasty. Since I asked around and a majority of people would prefer that I keep the software configurable at runtime rather than doing meta-programming to describe these fields, I need to develop a way to have the data produced by reading these byte arrays (or by processing results already interpreted out of the arrays) type-checked.
As an example, one field might be the voltage of the main breaker in the car. It's represented as a 16 bit big-endian unsigned field, in tenths of a volt. So the field must be divided by ten and then given the type "volts". Another field is the current passing through that main breaker. This is a 16 bit big-endian signed value measured in tenths of an amp, so must be interpreted as as such, divided by ten, and then given the type "amps". I intend for all values handled beyond the raw byte arrays themselves to simply be floats, so there'll be signedness available regardless.
What I'd like, is to later have a "computed" value, let's call it "power flow", which is the voltage multiplied by the current. Naturally this would need to be given the type 'watts'. What I'd dearly love is to build into my program the understanding that volts times amps equals watts, and then have the reader of the runtime configuration type-check the function for "power flow".
I'm working on this in Rust, though for now the language is less important than the algorithms involved in doing this (unless you know of a Rust library which will help me along). I'd dearly love it if someone out there could help me to understand the right way to handle such expression type checking without having to build up a massively complex type system.
Currently I am considering things (expressed for now in yaml) along the lines of:
- name: main_voltage type: volts expr: u16_be(raw_bmc, 14) / 10 - name: main_current type: amps expr: i16_be(raw_bmc, 12) / 10 - name: power_flow type: watts expr: main_voltage * main_current
What I'd like is for each expression to be type-checked. I'm happy for untyped
scalars to end up auto-labelled (so the
u16_be() function would return an
untyped number which then ends up marked as volts since 10 is also untyped).
power_flow is typechecked, it should be able to work out that
the type of the expression is
volts * amps which should then typecheck
watts and be accepted. Since there's also consideration needed for
times, distances, booleans, etc. this is not a completely trivial thing to
manage. I will know the set of valid types up-front though, so there's that at
If you have any ideas, ping me on IRC or perhaps blog a response and then drop me an email to let me know about it.
Thanks in advance.