Announcing v3.0.0

Leveraging past learnings for the future

Version 3.0.0 is released!

This is a breaking changes major version bump, refactoring many APIs based on the learnings made in the past year, acquired hindsight by fine tuning drivers and feedback from users.

We do not take breaking users lightly!

Every single breaking change was done thoughtfully. We consider users have the right for an explanation why their time is spent on this, so this document lists the rationale for every single breaking change.


The refactorings enabled:

The rationale is that host provides resources that devices drivers in package devices can leverage. Having host/… depend on devices creates a import loop.

This is now a very clean design.

Breaking changes

You will likely be affected by the following changes. They are described along the rationale, expected symptom and what you have to do to update your client code:

  • conn/gpio: Merged PinDefaultPull into PinIn, PinPWM into PinOut.
    • Rationale: The PinDefaultPull and PinPWM were added in v2 to not expand PinIn and PinOut, which we considered a breaking change. Merging the interfaces simplifies utilisation.
    • Symptom: Compile error.
    • Required work: Simplify references by removing the cast to PinDefaultPull or PinPWM, they are now unnecessary.
  • conn/i2c and conn/spi: Change all the hz parameters to use physic.Frequency. This affects the functions Connect(), LimitSpeed() and SetSpeed().
    • Rationale: This enables a 0.000001 Hertz resolution consistently across the package, and enables methods like Duration() to convert to time.Duration. This enables using constants like MegaHertz, which makes easier to read expressions like 10 * physic.MegaHertz versus 10000000. A ParseFrequency() ala ParseDuration() is planned but I ran out of time.
    • Symptom: Runtime error, either the driver refuses the specified frequency or everything runs at a one millionth the desired speed (or 0).
    • Required work: Multiply the value with Hertz, KiloHertz or MegaHertz.
  • conn/physic: Increase RelativeHumidity precision by 10x.
    • Rationale: the BME280 has an higher precision that what RelativeHumidity was providing.
    • Symptom: humidity value is 10x larger than expected.
    • Required work: Use the RH constants in package physic.
  • devices: Was stripped of most of its types into physic.
    • Rationale: This required drivers in host (like sysfs) to import package devices, which was a layering violation.
    • Symptom: Compile error.
    • Required work: Replace imports of package devices with physic.
  • devices: most types were renamed while moved into physic, and many had their base type changed.
    • Rationale: Separate the what (e.g. Temperature) from the unit (e.g. MilliKelvin, MilliFahrenheit). This is largely inspired by time.Duration, which has constants for MicroSecond, Second, Minute, etc. We decided to stick with fixed point instead of floating point as this enables deterministic calculation across platforms. We are open to revisiting this decision in v4 based on the feedback.
    • Symptom: Compile error, invalid runtime behavior due to incorrect constants.
    • Required work: Update references like devices.Celsius, KPascal, Environment to their physic counter parts: Temperature, Pressure, Env. Use the constants (Kelvin, Pascal, MicroRH) in physic to convert the units, similar to how one would do with time.MicroSecond.
  • devices: Moved the interface devices.Display as Drawer in a new conn/display package.
    • Rationale: the package devices is only a container for device drivers, not a location to define interfaces.
    • Symptom: Compile error.
    • Required work: Update references of devices.Display to display.Drawer,
  • devices/devicetest: Moved to conn/display/displaytest
    • Rationale: coherency with the mode of devices.Display.
  • conn/display: changed Drawer.Draw() to return an error. We also clarified that the device driver is expected to support incremental update, which requires a full frame buffer.
    • Rationale: Draw() didn’t return an error to lookalike the draw.Drawer interface but that was irrelevant.
    • Symptom: Compile error for device drivers. User code not checking for error.
    • Required work: Update device drivers, check error value.

Driver specific changes

This changes will affect you if you use this device driver:

  • devices/apa102, devices/bmxx80, devices/ds248x, devices/ssd136: Use Opts pattern instead of individual arguments in the New() function.
    • Rationale: This is extensible. This permits to consider adding more members to Opts a non breaking change, which opens the door to add more functionality to a device driver without having to wait for v4. Use a DefaultOpts struct instance instead of a function to use more data instead of code.
    • Symptom: Compile error.
    • Required work: Update the New() call to pass an Opts instance, likely using DefaultOpts. Initialize the Opts member via their name, never by order. Use bmxx80.Opts{Temperature: bmxx80.O4x, Pressure: bmxx80.O1x, Humidity: bmxx80.O1x, Filter: bmxx80.NoFilter}, not the short form bmxx80.Opts{bmxx80.O4x, bmxx80.O1x, bmxx80.O1x, bmxx80.NoFilter}.
  • devices/ds18b20: Replaced Temperature() method with physic.SenseEnv implementation.
    • Rationale: This makes this sensor behaves like any other temperature sensor, so that physic.SenseEnv can be passed around.
    • Symptom: Compile error.
    • Required work: Update the dev.Temperature() call to use dev.SenseEnv().
  • devices/ds248x: Remove I²C address from the options, to NewI2C() as an explicit argument.
    • Rationale: Coherency with all the other device drivers, which pass the I²C address to NewI2C(). The rationale is that many devices support both SPI and I²C, so putting the I²C device address in Opts results in an ambiguous option.
    • Symptom: Compile error.
    • Required work: update call to New().
  • devices/lepton: Remove cs argument from New().
    • Rationale: This was a hack trying to work around issues in the Raspberry Pi driver, but this was incorrect. The driver now use the SPI’s connection CS pin normally.
    • Symptom: Compile error.
    • Required work: Update call to New().
  • devices/lepton: Frame uses image14bit.Gray14 instead of image.Gray16.
    • Rationale: A perf test determined that using []byte to store uint16 values is significantly slower than using []uint16. It is also clunky to use. This permits using Intensity14 as the ColorModel, which uses 8191 as full intensity.
    • Symptom: Compile error.
    • Required work: Update client code to use image14bit.
  • devices/lepton: Replaced ReadImg() with NextFrame().
    • Rationale: ReadImg() required doing a memory allocation at every call, NextFrame() permits reusing Frame instances, reducing heap churn.
    • Symptom: Compile error.
    • Required work: Update client code to preallocate the frame with f := Frame{Gray14: image14bit.NewGray14(dev.Bounds())}.

Lesser changes

These changes have no required work unless you wrote a device driver:

  • cmd/apa102: Default intensity increased from 127 to 255.
  • conn: Add String() to Resource.
    • Rationale: This permits to have a clear naming convention to help explain the user what is being used. This enables removing a lot of dependency on fmt.
  • conn/gpio: Changed DutyMax from 1«16-1 to 1«24.
    • Rationale: The fact that it was 1«16-1 was to keep it under 16 bits but caused usability issues, as half wasn’t an exact number.
    • Symptom: Invalid runtime behavior due to incorrect constants.
    • Required work: Use values in referece to DutyMax.
  • conn/gpio: PWM() now accepts a physic.Frequency instead of time.Duration period.
    • Rationale: While clock period is logical, it is really hard to relate. Users will have a much easier time to understand 10kHz than 100µs.
    • Symptom: Compile error.
    • Required work: Use frequency instead of clock period.
  • conn/gpio: Pull constants changed, PullNoChange is now 0, instead of Float.
    • Rationale: It is default value, which is more useful (and expected) than Float.
    • Symptom: Invalid runtime behavior due to incorrect constants.
    • Required work: Explicitly specify Float where it was assumed to be the default.
  • conn/gpio/gpioreg: Remove prefered argument to Register().
    • Rationale: The reason that led to this argument were not needed anymore. This was due to parallelism between sysfs-gpio and CPU GPIO drivers.
  • conn/gpio/gpiostream: Rewrote.
    • Rationale: Its implementation proved to be suboptimal. Since this package wasn’t used much yet, now was the right time to refactor it.
  • conn/gpio/gpiotest: PinPWM was merged into Pin.
    • Rationale: This follows that gpio.PinPWM was merged into gpio.PinOut.
  • conn/pin: pin.Pin is now a conn.Resource, so it implements Halt().
    • Rationale: Make everything a Resource, so they can be enumerated (via String()) and halted on shutdown if desired.
  • conn/physic: Added SenseEnv.Precision(), implemented in all drivers.
    • Rationale: It is useful for the application to know at which precision the sensor is making its measurement.
  • host/sysfs: Renamed SetSpeedHook to I2CSetSpeedHook.
    • Rationale: This function is I²C specific, but it was not clear from the name.
  • periph: Added After() to interface Driver.
    • Rationale: Was needed to untangle the sysfs-gpio and CPU drivers, and host pin headers. This enabled automatic fallback to sysfs GPIO driver when sysfs loaded but the CPU GPIO driver failed to load, which may require running as root.

Additional improvements

These are not breaking changes:

  • cci: implements SenseEnv to be used as a temperature sensor. This returns the housing temperature.
    • Rationale: This permits to use all the temperature sensors connected to a host in the same way.
  • experimental: Many drivers were improved towards being moved into non-experimental. These are not considered breaking changes.
  • The code is now tested on go1.5.4. This makes it easier for users to just apt install golang and immediately get going.
  • conn: Removed all dependencies on /devices or /host, by moving the smoketests under /cmd/periph-smoketest. Added travis checks to verify.

Going forward

Some of the changes here are to enable new drivers like the FT232H and FT232R, which enables a less Linux-focused driver support.


I’d like to thanks for all the folks on the slack channel for the feedback and code reviews. The project would be much less awesome without them!

Found bugs? Have questions?

Follow for news and updates!