From 5bf78c42a10065fbe719591e3396acbf318798e5 Mon Sep 17 00:00:00 2001 From: soypat Date: Sun, 26 Sep 2021 10:08:11 -0300 Subject: [PATCH 1/2] add Sensor interface --- sensor.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 sensor.go diff --git a/sensor.go b/sensor.go new file mode 100644 index 000000000..58ce3c8fa --- /dev/null +++ b/sensor.go @@ -0,0 +1,30 @@ +package drivers + +// Measurement specifies a type of measurement, +// for example: temperature, acceleration, pressure. +type Measurement uint32 + +// Sensor measurements +const ( + Temperature Measurement = 1 << iota + Humidity + Pressure + Distance + Acceleration + AngularVelocity + MagneticField + Luminosity + Time + + AllMeasurements Measurement = 0xffffffff +) + +// Sensor represents an object capable of making one +// or more measurements. A sensor will then have methods +// which read the last updated measurements. +// +// Many Sensors may be collected into +// one Sensor interface to synchronize measurements. +type Sensor interface { + Update(which Measurement) error +} From a5b5fbf853553e663bd68ba6eded306fe3572681 Mon Sep 17 00:00:00 2001 From: soypat Date: Tue, 26 Oct 2021 09:15:32 -0300 Subject: [PATCH 2/2] sensor refactor: proof of concept --- bmp180/bmp180.go | 54 +++++++++++++++++++++++ mcp3008/buffered.go | 102 ++++++++++++++++++++++++++++++++++++++++++++ mcp3008/mcp3008.go | 2 +- sensor.go | 7 ++- 4 files changed, 162 insertions(+), 3 deletions(-) create mode 100644 mcp3008/buffered.go diff --git a/bmp180/bmp180.go b/bmp180/bmp180.go index 984c338f1..1d02fc861 100644 --- a/bmp180/bmp180.go +++ b/bmp180/bmp180.go @@ -36,6 +36,8 @@ type Device struct { Address uint16 mode OversamplingMode calibrationCoefficients calibrationCoefficients + temp int32 + pressure int32 } // New creates a new BMP180 connection. The I2C bus must already be @@ -80,6 +82,58 @@ func (d *Device) Configure() { d.calibrationCoefficients.md = readInt(data[20], data[21]) } +// Pressure returns the pressure in milli pascal (mPa). +func (d *Device) Pressure() int32 { return d.pressure } + +// Temperature returns the temperature in celsius milli degrees (°C/1000). +func (d *Device) Temperature() int32 { return d.temp } + +func (d *Device) Update(which drivers.Measurement) (err error) { + // Temperature is needed for presssure calculation. + if which|drivers.Temperature|drivers.Pressure == 0 { + return nil + } + // Temperature calculation. + rawTemp, err := d.rawTemp() + if err != nil { + return err + } + b5 := d.calculateB5(rawTemp) + t := (b5 + 8) >> 4 + d.temp = 100 * t + + // Pressure calculation. + if which|drivers.Pressure == 0 { + return nil + } + rawPressure, err := d.rawPressure(d.mode) + if err != nil { + return err + } + + b6 := b5 - 4000 + x1 := (int32(d.calibrationCoefficients.b2) * (b6 * b6 >> 12)) >> 11 + x2 := (int32(d.calibrationCoefficients.ac2) * b6) >> 11 + x3 := x1 + x2 + b3 := (((int32(d.calibrationCoefficients.ac1)*4 + x3) << uint(d.mode)) + 2) >> 2 + x1 = (int32(d.calibrationCoefficients.ac3) * b6) >> 13 + x2 = (int32(d.calibrationCoefficients.b1) * ((b6 * b6) >> 12)) >> 16 + x3 = ((x1 + x2) + 2) >> 2 + b4 := (uint32(d.calibrationCoefficients.ac4) * uint32(x3+32768)) >> 15 + b7 := uint32(rawPressure-b3) * (50000 >> uint(d.mode)) + var p int32 + if b7 < 0x80000000 { + p = int32((b7 << 1) / b4) + } else { + p = int32((b7 / b4) << 1) + } + x1 = (p >> 8) * (p >> 8) + x1 = (x1 * 3038) >> 16 + x2 = (-7357 * p) >> 16 + d.pressure = 1000 * (p + ((x1 + x2 + 3791) >> 4)) + return nil +} + // ReadTemperature returns the temperature in celsius milli degrees (°C/1000). func (d *Device) ReadTemperature() (temperature int32, err error) { rawTemp, err := d.rawTemp() diff --git a/mcp3008/buffered.go b/mcp3008/buffered.go new file mode 100644 index 000000000..3d59fa6e2 --- /dev/null +++ b/mcp3008/buffered.go @@ -0,0 +1,102 @@ +package mcp3008 + +import ( + "machine" + + "tinygo.org/x/drivers" +) + +const ( + Chan0 = 1 << iota + Chan1 + Chan2 + Chan3 + Chan4 + Chan5 + Chan6 + Chan7 + + numChannels = iota + AllChannels = 0xff +) + +// Buffered implementation of the MCP3008. +type BufferedDev struct { + active uint8 + bus drivers.SPI + cs machine.Pin + tx [3]byte + rx [3]byte + data [numChannels]uint16 +} + +// New returns a new MCP3008 driver. Pass in a fully configured SPI bus. +// activeChannels informs which channels are to be measured. +// +// For example, to measure only on channels 0, 3 and 4 you'd call New as following: +// d := mcp3008.NewBuffered(spi, cs, mcp3008.Chan0|mcp3008.Chan3|mcp3008.Chan4) +func NewBuffered(b drivers.SPI, csPin machine.Pin, activeChannels uint8) *BufferedDev { + if activeChannels&AllChannels == 0 { + panic("mcp3008: no channels selected") + } + d := &BufferedDev{bus: b, + cs: csPin, + active: activeChannels, + } + csPin.High() + d.tx[0] = 0x01 + d.tx[2] = 0x00 + return d +} + +// Configure sets up the device for communication +func (d *BufferedDev) Configure() { + d.cs.Configure(machine.PinConfig{Mode: machine.PinOutput}) +} + +// UNTESTED +func (d *BufferedDev) Update(which drivers.Measurement) error { + if which|drivers.Voltage == 0 { + return nil + } + for i := 0; i < numChannels; i++ { + if 1<