Skip to content

Rewrite bme280 driver in Lua+C #3126

@nwf

Description

@nwf

In an effort to decrease the project's technical debt, I've proposed (in #3124) that the C-only bme280 be cut into a Lua layer that drives communication and a C module that does any requisite low-level fiddling. This will be similar to #2819 and may, incidentally, address #2527 correctly as well. (As you can see, between that and #2241, this module has a history of being sufficiently troublesome that issues have been worked around rather than fixed.) This rewrite will also eliminate yet another source of static allocation and artificial limitation in our driver layer. All in all, deeply worth it.

I would like it very much if the result of this rewrite included a test driver, as well. Ideally bme280 becomes an example of how all drivers should look. No pressure (ha!). ;)

OK, so, what does this entail, concretely?

Looking at the existing bme280.c, we almost immediately see that there's a bunch of goo associated with performing i2c transactions: bme280_i2c_addr, r8u_n, r8u, and w8u. These can all be directly transcoded to Lua. The results from the i2c package will be Lua strings.

The bme280_data structure holds per-device state obtained during setup, which means we probably want to hold it instead in a Lua userdata object that represents the sensor. Reading setup, it looks like this takes 3 or 4 I2C transactions to set up, including getting the chip ID, so I think our sensor object constructor should take 2 or 3 Lua strings (DIG_T, DIG_P, and DIG_H) to build itself. Since it appears that the static values bme280_t_fine, bme280_h, and bme280_hc may outlive a particular measurement, they should perhaps join the bme280_data in the per-device userdata object.

Armed with the sensor parameters, we can look at interacting with the device: bme280_lua_startreadout does some i2c transactions, easily done instead in Lua, and schedules a timer, also easily done in Lua. (Can the device not raise IRQs?)

Once it's time to read data, bme280_lua_read does some more i2c transactions and a lot of math, including storing "fine" constants between procedure calls. To continue the theme, the transactions should be done in Lua, and passed to a C routine that takes the sensor userdata object and does the requisite math. For my $0.02, the results should just land in a Lua table.

The abbreviated bme280_lua_temp, bme280_lua_baro, and bme280_lua_humi functions are readily achieved by having the Lua replacement for bme280_lua_read perform fewer transactions and call into the C function with fewer string arguments. That function should return a table with fewer keys as a result.

For the purposes of PRing, I'd suggest placing code in

  • app/modules/bme280_math.c for the C layer
  • lua_modules/bme280/bme280.lua for the Lua top-level and main driver
  • lua_modules/bme280/bme280_test.lua for the test script (ideally in mispec, I think? See Create unit tests in Lua #2145).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions