mirror of
https://github.com/hybridgroup/gobot.git
synced 2025-04-24 13:48:49 +08:00
ADXL345 use ReadBlockData()
This commit is contained in:
parent
dbf33f7f63
commit
038853286d
@ -2,69 +2,79 @@ package i2c
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"log"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gobot.io/x/gobot"
|
||||
)
|
||||
|
||||
const ADXL345AddressLow = 0x53
|
||||
const ADXL345AddressHigh = 0x1D
|
||||
const adxl345Debug = false
|
||||
|
||||
// ADXL345 supports 2 addresses, which can be changed by the address pin, there is no internal pull-up/down resistor!
|
||||
// pin to GND: 0x53, pin to VDD: 0x1D
|
||||
const (
|
||||
ADXL345AddressPullUp = 0x1D // can be used by WithAddress()
|
||||
adxl345DefaultAddress = 0x53
|
||||
)
|
||||
|
||||
type ADXL345RateConfig uint8
|
||||
type ADXL345FsRangeConfig uint8
|
||||
|
||||
const (
|
||||
// Data rate
|
||||
ADXL345_RATE_3200HZ = 0x0F // 3200 Hz
|
||||
ADXL345_RATE_1600HZ = 0x0E // 1600 Hz
|
||||
ADXL345_RATE_800HZ = 0x0D // 800 Hz
|
||||
ADXL345_RATE_400HZ = 0x0C // 400 Hz
|
||||
ADXL345_RATE_200HZ = 0x0B // 200 Hz
|
||||
ADXL345_RATE_100HZ = 0x0A // 100 Hz
|
||||
ADXL345_RATE_50HZ = 0x09 // 50 Hz
|
||||
ADXL345_RATE_25HZ = 0x08 // 25 Hz
|
||||
ADXL345_RATE_12_5HZ = 0x07 // 12.5 Hz
|
||||
ADXL345_RATE_6_25HZ = 0x06 // 6.25 Hz
|
||||
ADXL345_RATE_3_13HZ = 0x05 // 3.13 Hz
|
||||
ADXL345_RATE_1_56HZ = 0x04 // 1.56 Hz
|
||||
ADXL345_RATE_0_78HZ = 0x03 // 0.78 Hz
|
||||
ADXL345_RATE_0_39HZ = 0x02 // 0.39 Hz
|
||||
ADXL345_RATE_0_20HZ = 0x01 // 0.20 Hz
|
||||
ADXL345_RATE_0_10HZ = 0x00 // 0.10 Hz
|
||||
// registers are named according to the datasheet
|
||||
adxl345Reg_DEVID = 0x00 // R, 11100101, Device ID
|
||||
adxl345Reg_THRESH_TAP = 0x1D // R/W, 00000000, Tap threshold
|
||||
adxl345Reg_OFSX = 0x1E // R/W, 00000000, X-axis offset
|
||||
adxl345Reg_OFSY = 0x1F // R/W, 00000000, Y-axis offset
|
||||
adxl345Reg_OFSZ = 0x20 // R/W, 00000000, Z-axis offset
|
||||
adxl345Reg_DUR = 0x21 // R/W, 00000000, Tap duration
|
||||
adxl345Reg_LATENT = 0x22 // R/W, 00000000, Tap latency
|
||||
adxl345Reg_WINDOW = 0x23 // R/W, 00000000, Tap window
|
||||
adxl345Reg_THRESH_ACT = 0x24 // R/W, 00000000, Activity threshold
|
||||
adxl345Reg_THRESH_INACT = 0x25 // R/W, 00000000, Inactivity threshold
|
||||
adxl345Reg_TIME_INACT = 0x26 // R/W, 00000000, Inactivity time
|
||||
adxl345Reg_ACT_INACT_CTL = 0x27 // R/W, 00000000, Axis enable control for activity and inactivity detection
|
||||
adxl345Reg_THRESH_FF = 0x28 // R/W, 00000000, Free-fall threshold
|
||||
adxl345Reg_TIME_FF = 0x29 // R/W, 00000000, Free-fall time
|
||||
adxl345Reg_TAP_AXES = 0x2A // R/W, 00000000, Axis control for single tap/double tap
|
||||
adxl345Reg_ACT_TAP_STATUS = 0x2B // R, 00000000, Source of single tap/double tap
|
||||
adxl345Reg_BW_RATE = 0x2C // R/W, 00001010, Data rate and power mode control
|
||||
adxl345Reg_POWER_CTL = 0x2D // R/W, 00000000, Power-saving features control
|
||||
adxl345Reg_INT_ENABLE = 0x2E // R/W, 00000000, Interrupt enable control
|
||||
adxl345Reg_INT_MAP = 0x2F // R/W, 00000000, Interrupt mapping control
|
||||
adxl345Reg_INT_SOUCE = 0x30 // R, 00000010, Source of interrupts
|
||||
adxl345Reg_DATA_FORMAT = 0x31 // R/W, 00000000, Data format control (FS range, justify, full resolution)
|
||||
adxl345Reg_DATAX0 = 0x32 // R, 00000000, X-Axis Data 0 (LSByte)
|
||||
adxl345Reg_DATAX1 = 0x33 // R, 00000000, X-Axis Data 1 (MSByte)
|
||||
adxl345Reg_DATAY0 = 0x34 // R, 00000000, Y-Axis Data 0
|
||||
adxl345Reg_DATAY1 = 0x35 // R, 00000000, Y-Axis Data 1
|
||||
adxl345Reg_DATAZ0 = 0x36 // R, 00000000, Z-Axis Data 0
|
||||
adxl345Reg_DATAZ1 = 0x37 // R, 00000000, Z-Axis Data 1
|
||||
adxl345Reg_FIFO_CTL = 0x38 // R/W, 00000000, FIFO control
|
||||
adxl345Reg_FIFO_STATUS = 0x39 // R, 00000000, FIFO status
|
||||
|
||||
// Data range
|
||||
ADXL345_RANGE_2G = 0x00 // +-2 g
|
||||
ADXL345_RANGE_4G = 0x01 // +-4 g
|
||||
ADXL345_RANGE_8G = 0x02 // +-8 g
|
||||
ADXL345_RANGE_16G = 0x03 // +-16 g)
|
||||
adxl345Rate_LowPowerBit = 0x10 // set the device to low power, but increase the noise by ~2.5x
|
||||
|
||||
ADXL345_REG_DEVID = 0x00 // R, 11100101, Device ID
|
||||
ADXL345_REG_THRESH_TAP = 0x1D // R/W, 00000000, Tap threshold
|
||||
ADXL345_REG_OFSX = 0x1E // R/W, 00000000, X-axis offset
|
||||
ADXL345_REG_OFSY = 0x1F // R/W, 00000000, Y-axis offset
|
||||
ADXL345_REG_OFSZ = 0x20 // R/W, 00000000, Z-axis offset
|
||||
ADXL345_REG_DUR = 0x21 // R/W, 00000000, Tap duration
|
||||
ADXL345_REG_LATENT = 0x22 // R/W, 00000000, Tap latency
|
||||
ADXL345_REG_WINDOW = 0x23 // R/W, 00000000, Tap window
|
||||
ADXL345_REG_THRESH_ACT = 0x24 // R/W, 00000000, Activity threshold
|
||||
ADXL345_REG_THRESH_INACT = 0x25 // R/W, 00000000, Inactivity threshold
|
||||
ADXL345_REG_TIME_INACT = 0x26 // R/W, 00000000, Inactivity time
|
||||
ADXL345_REG_ACT_INACT_CTL = 0x27 // R/W, 00000000, Axis enable control for activity and inactiv ity detection
|
||||
ADXL345_REG_THRESH_FF = 0x28 // R/W, 00000000, Free-fall threshold
|
||||
ADXL345_REG_TIME_FF = 0x29 // R/W, 00000000, Free-fall time
|
||||
ADXL345_REG_TAP_AXES = 0x2A // R/W, 00000000, Axis control for single tap/double tap
|
||||
ADXL345_REG_ACT_TAP_STATUS = 0x2B // R, 00000000, Source of single tap/double tap
|
||||
ADXL345_REG_BW_RATE = 0x2C // R/W, 00001010, Data rate and power mode control
|
||||
ADXL345_REG_POWER_CTL = 0x2D // R/W, 00000000, Power-saving features control
|
||||
ADXL345_REG_INT_ENABLE = 0x2E // R/W, 00000000, Interrupt enable control
|
||||
ADXL345_REG_INT_MAP = 0x2F // R/W, 00000000, Interrupt mapping control
|
||||
ADXL345_REG_INT_SOUCE = 0x30 // R, 00000010, Source of interrupts
|
||||
ADXL345_REG_DATA_FORMAT = 0x31 // R/W, 00000000, Data format control
|
||||
ADXL345_REG_DATAX0 = 0x32 // R, 00000000, X-Axis Data 0
|
||||
ADXL345_REG_DATAX1 = 0x33 // R, 00000000, X-Axis Data 1
|
||||
ADXL345_REG_DATAY0 = 0x34 // R, 00000000, Y-Axis Data 0
|
||||
ADXL345_REG_DATAY1 = 0x35 // R, 00000000, Y-Axis Data 1
|
||||
ADXL345_REG_DATAZ0 = 0x36 // R, 00000000, Z-Axis Data 0
|
||||
ADXL345_REG_DATAZ1 = 0x37 // R, 00000000, Z-Axis Data 1
|
||||
ADXL345_REG_FIFO_CTL = 0x38 // R/W, 00000000, FIFO control
|
||||
ADXL345_REG_FIFO_STATUS = 0x39 // R, 00000000, FIFO status
|
||||
ADXL345Rate_100mHZ ADXL345RateConfig = 0x00 // 0.10 Hz
|
||||
ADXL345Rate_200mHZ ADXL345RateConfig = 0x01 // 0.20 Hz
|
||||
ADXL345Rate_390mHZ ADXL345RateConfig = 0x02 // 0.39 Hz
|
||||
ADXL345Rate_780mHZ ADXL345RateConfig = 0x03 // 0.78 Hz
|
||||
ADXL345Rate_1560mHZ ADXL345RateConfig = 0x04 // 1.56 Hz
|
||||
ADXL345Rate_3130mHZ ADXL345RateConfig = 0x05 // 3.13 Hz
|
||||
ADXL345Rate_6250mHZ ADXL345RateConfig = 0x06 // 6.25 Hz
|
||||
ADXL345Rate_12500mHZ ADXL345RateConfig = 0x07 // 12.5 Hz
|
||||
ADXL345Rate_25HZ ADXL345RateConfig = 0x08 // 25 Hz
|
||||
ADXL345Rate_50HZ ADXL345RateConfig = 0x09 // 50 Hz
|
||||
ADXL345Rate_100HZ ADXL345RateConfig = 0x0A // 100 Hz
|
||||
ADXL345Rate_200HZ ADXL345RateConfig = 0x0B // 200 Hz
|
||||
ADXL345Rate_400HZ ADXL345RateConfig = 0x0C // 400 Hz
|
||||
ADXL345Rate_800HZ ADXL345RateConfig = 0x0D // 800 Hz
|
||||
ADXL345Rate_1600HZ ADXL345RateConfig = 0x0E // 1600 Hz
|
||||
ADXL345Rate_3200HZ ADXL345RateConfig = 0x0F // 3200 Hz
|
||||
|
||||
ADXL345FsRange_2G ADXL345FsRangeConfig = 0x00 // +-2 g
|
||||
ADXL345FsRange_4G ADXL345FsRangeConfig = 0x01 // +-4 g
|
||||
ADXL345FsRange_8G ADXL345FsRangeConfig = 0x02 // +-8 g
|
||||
ADXL345FsRange_16G ADXL345FsRangeConfig = 0x03 // +-16 g)
|
||||
)
|
||||
|
||||
// ADXL345Driver is the gobot driver for the digital accelerometer ADXL345
|
||||
@ -74,18 +84,10 @@ const (
|
||||
//
|
||||
// Ported from the Arduino driver https://github.com/jakalada/Arduino-ADXL345
|
||||
type ADXL345Driver struct {
|
||||
name string
|
||||
connector Connector
|
||||
connection Connection
|
||||
|
||||
*Driver
|
||||
powerCtl adxl345PowerCtl
|
||||
dataFormat adxl345DataFormat
|
||||
bwRate adxl345BwRate
|
||||
|
||||
x, y, z float64
|
||||
rawX, rawY, rawZ int16
|
||||
|
||||
Config
|
||||
}
|
||||
|
||||
// Internal structure for the power configuration
|
||||
@ -99,194 +101,189 @@ type adxl345PowerCtl struct {
|
||||
|
||||
// Internal structure for the sensor's data format configuration
|
||||
type adxl345DataFormat struct {
|
||||
selfTest uint8
|
||||
spi uint8
|
||||
intInvert uint8
|
||||
fullRes uint8
|
||||
justify uint8
|
||||
sensorRange uint8
|
||||
selfTest uint8
|
||||
spi uint8
|
||||
intInvert uint8
|
||||
fullRes uint8
|
||||
justify uint8
|
||||
fullScaleRange ADXL345FsRangeConfig
|
||||
}
|
||||
|
||||
// Internal structure for the sampling rate configuration
|
||||
type adxl345BwRate struct {
|
||||
lowPower uint8
|
||||
rate uint8
|
||||
lowPower bool
|
||||
rate ADXL345RateConfig
|
||||
}
|
||||
|
||||
// NewADXL345Driver creates a new driver with specified i2c interface
|
||||
// Params:
|
||||
// conn Connector - the Adaptor to use with this Driver
|
||||
// c Connector - the Adaptor to use with this Driver
|
||||
//
|
||||
// Optional params:
|
||||
// i2c.WithBus(int): bus to use with this driver
|
||||
// i2c.WithAddress(int): address to use with this driver
|
||||
//
|
||||
func NewADXL345Driver(a Connector, options ...func(Config)) *ADXL345Driver {
|
||||
m := &ADXL345Driver{
|
||||
name: gobot.DefaultName("ADXL345"),
|
||||
connector: a,
|
||||
func NewADXL345Driver(c Connector, options ...func(Config)) *ADXL345Driver {
|
||||
d := &ADXL345Driver{
|
||||
Driver: NewDriver(c, "ADXL345", adxl345DefaultAddress),
|
||||
powerCtl: adxl345PowerCtl{
|
||||
measure: 1,
|
||||
},
|
||||
dataFormat: adxl345DataFormat{
|
||||
sensorRange: ADXL345_RANGE_2G,
|
||||
fullScaleRange: ADXL345FsRange_2G,
|
||||
},
|
||||
bwRate: adxl345BwRate{
|
||||
lowPower: 1,
|
||||
rate: ADXL345_RATE_100HZ,
|
||||
lowPower: true,
|
||||
rate: ADXL345Rate_100HZ,
|
||||
},
|
||||
Config: NewConfig(),
|
||||
}
|
||||
d.afterStart = d.initialize
|
||||
d.beforeHalt = d.shutdown
|
||||
|
||||
for _, option := range options {
|
||||
option(m)
|
||||
option(d)
|
||||
}
|
||||
|
||||
// TODO: add commands for API
|
||||
return m
|
||||
return d
|
||||
}
|
||||
|
||||
// Name returns the Name for the Driver
|
||||
func (h *ADXL345Driver) Name() string { return h.name }
|
||||
// WithADXL345LowPowerMode option modifies the low power mode.
|
||||
func WithADXL345LowPowerMode(val bool) func(Config) {
|
||||
return func(c Config) {
|
||||
if d, ok := c.(*ADXL345Driver); ok {
|
||||
d.bwRate.lowPower = val
|
||||
} else if adxl345Debug {
|
||||
log.Printf("Trying to modify low power mode for non-ADXL345Driver %v", c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetName sets the Name for the Driver
|
||||
func (h *ADXL345Driver) SetName(n string) { h.name = n }
|
||||
// WithADXL345DataOutputRate option sets the data output rate.
|
||||
// Valid settings are of type "ADXL345RateConfig"
|
||||
func WithADXL345DataOutputRate(val ADXL345RateConfig) func(Config) {
|
||||
return func(c Config) {
|
||||
if d, ok := c.(*ADXL345Driver); ok {
|
||||
d.bwRate.rate = val
|
||||
} else if adxl345Debug {
|
||||
log.Printf("Trying to set data output rate for non-ADXL345Driver %v", c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Connection returns the connection for the Driver
|
||||
func (h *ADXL345Driver) Connection() gobot.Connection { return h.connector.(gobot.Connection) }
|
||||
// WithADXL345FullScaleRange option sets the full scale range.
|
||||
// Valid settings are of type "ADXL345FsRangeConfig"
|
||||
func WithADXL345FullScaleRange(val ADXL345FsRangeConfig) func(Config) {
|
||||
return func(c Config) {
|
||||
if d, ok := c.(*ADXL345Driver); ok {
|
||||
d.dataFormat.fullScaleRange = val
|
||||
} else if adxl345Debug {
|
||||
log.Printf("Trying to set full scale range for non-ADXL345Driver %v", c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start initialized the adxl345
|
||||
func (h *ADXL345Driver) Start() (err error) {
|
||||
bus := h.GetBusOrDefault(h.connector.GetDefaultBus())
|
||||
address := h.GetAddressOrDefault(ADXL345AddressLow)
|
||||
// UseLowPower change the current rate of the sensor
|
||||
func (d *ADXL345Driver) UseLowPower(lowPower bool) (err error) {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
h.connection, err = h.connector.GetConnection(address, bus)
|
||||
d.bwRate.lowPower = lowPower
|
||||
if err := d.connection.WriteByteData(adxl345Reg_BW_RATE, d.bwRate.toByte()); err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetRate change the current rate of the sensor immediately
|
||||
func (d *ADXL345Driver) SetRate(rate ADXL345RateConfig) (err error) {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
d.bwRate.rate = rate
|
||||
if err := d.connection.WriteByteData(adxl345Reg_BW_RATE, d.bwRate.toByte()); err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetRange change the current range of the sensor immediately
|
||||
func (d *ADXL345Driver) SetRange(fullScaleRange ADXL345FsRangeConfig) (err error) {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
d.dataFormat.fullScaleRange = fullScaleRange
|
||||
if err := d.connection.WriteByteData(adxl345Reg_DATA_FORMAT, d.dataFormat.toByte()); err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// XYZ returns the adjusted x, y and z axis, unit [g]
|
||||
func (d *ADXL345Driver) XYZ() (float64, float64, float64, error) {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
xr, yr, zr, err := d.readRawData()
|
||||
if err != nil {
|
||||
return err
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
|
||||
if _, err := h.connection.Write([]byte{ADXL345_REG_BW_RATE, h.bwRate.toByte()}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := h.connection.Write([]byte{ADXL345_REG_POWER_CTL, h.powerCtl.toByte()}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := h.connection.Write([]byte{ADXL345_REG_DATA_FORMAT, h.dataFormat.toByte()}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return
|
||||
return d.dataFormat.convertToG(xr), d.dataFormat.convertToG(yr), d.dataFormat.convertToG(zr), nil
|
||||
}
|
||||
|
||||
// Stop adxl345
|
||||
func (h *ADXL345Driver) Stop() (err error) {
|
||||
h.powerCtl.measure = 0
|
||||
if h.connection == nil {
|
||||
return errors.New("connection not available")
|
||||
}
|
||||
if _, err := h.connection.Write([]byte{ADXL345_REG_POWER_CTL, h.powerCtl.toByte()}); err != nil {
|
||||
return err
|
||||
}
|
||||
// XYZ returns the raw x,y and z axis
|
||||
func (d *ADXL345Driver) RawXYZ() (int16, int16, int16, error) {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
return
|
||||
return d.readRawData()
|
||||
}
|
||||
|
||||
// Halt returns true if devices is halted successfully
|
||||
func (h *ADXL345Driver) Halt() (err error) {
|
||||
h.Stop()
|
||||
return
|
||||
}
|
||||
|
||||
// XYZ returns the adjusted x, y and z axis from the adxl345
|
||||
func (h *ADXL345Driver) XYZ() (float64, float64, float64, error) {
|
||||
err := h.update()
|
||||
return h.x, h.y, h.z, err
|
||||
}
|
||||
|
||||
// XYZ returns the raw x,y and z axis from the adxl345
|
||||
func (h *ADXL345Driver) RawXYZ() (int16, int16, int16, error) {
|
||||
err := h.update()
|
||||
return h.rawX, h.rawY, h.rawZ, err
|
||||
}
|
||||
|
||||
// update the cached values for the axis to avoid errors if the connection is not available (polling too frequently)
|
||||
func (h *ADXL345Driver) update() (err error) {
|
||||
|
||||
if h.connection == nil {
|
||||
return errors.New("connection not available")
|
||||
}
|
||||
|
||||
h.connection.Write([]byte{ADXL345_REG_DATAX0})
|
||||
func (d *ADXL345Driver) readRawData() (int16, int16, int16, error) {
|
||||
buf := []byte{0, 0, 0, 0, 0, 0}
|
||||
|
||||
_, err = h.connection.Read(buf)
|
||||
if err != nil {
|
||||
return
|
||||
if err := d.connection.ReadBlockData(adxl345Reg_DATAX0, buf); err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
|
||||
h.rawX = int16(binary.LittleEndian.Uint16(buf[0:2]))
|
||||
h.rawY = int16(binary.LittleEndian.Uint16(buf[2:4]))
|
||||
h.rawZ = int16(binary.LittleEndian.Uint16(buf[4:6]))
|
||||
|
||||
h.x = h.dataFormat.ConvertToSI(h.rawX)
|
||||
h.y = h.dataFormat.ConvertToSI(h.rawY)
|
||||
h.z = h.dataFormat.ConvertToSI(h.rawZ)
|
||||
|
||||
return
|
||||
rx := int16(binary.LittleEndian.Uint16(buf[0:2]))
|
||||
ry := int16(binary.LittleEndian.Uint16(buf[2:4]))
|
||||
rz := int16(binary.LittleEndian.Uint16(buf[4:6]))
|
||||
return rx, ry, rz, nil
|
||||
}
|
||||
|
||||
// SetRate change the current rate of the sensor
|
||||
func (h *ADXL345Driver) UseLowPower(power bool) (err error) {
|
||||
if power {
|
||||
h.bwRate.lowPower = 1
|
||||
} else {
|
||||
h.bwRate.lowPower = 0
|
||||
}
|
||||
if _, err := h.connection.Write([]byte{ADXL345_REG_BW_RATE, h.bwRate.toByte()}); err != nil {
|
||||
func (d *ADXL345Driver) initialize() error {
|
||||
if err := d.connection.WriteByteData(adxl345Reg_BW_RATE, d.bwRate.toByte()); err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetRate change the current rate of the sensor
|
||||
func (h *ADXL345Driver) SetRate(rate byte) (err error) {
|
||||
if rate <= ADXL345_RATE_3200HZ {
|
||||
return errors.New("not a valid rate")
|
||||
}
|
||||
h.bwRate.rate = rate & 0x0F
|
||||
if _, err := h.connection.Write([]byte{ADXL345_REG_BW_RATE, h.bwRate.toByte()}); err != nil {
|
||||
if err := d.connection.WriteByteData(adxl345Reg_POWER_CTL, d.powerCtl.toByte()); err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetRange change the current range of the sensor
|
||||
func (h *ADXL345Driver) SetRange(sensorRange byte) (err error) {
|
||||
if sensorRange != ADXL345_RANGE_2G &&
|
||||
sensorRange != ADXL345_RANGE_4G &&
|
||||
sensorRange != ADXL345_RANGE_8G &&
|
||||
sensorRange != ADXL345_RANGE_16G {
|
||||
return errors.New("not a valid range")
|
||||
}
|
||||
h.dataFormat.sensorRange = sensorRange & 0x03
|
||||
if _, err := h.connection.Write([]byte{ADXL345_REG_DATA_FORMAT, h.dataFormat.toByte()}); err != nil {
|
||||
if err := d.connection.WriteByteData(adxl345Reg_DATA_FORMAT, d.dataFormat.toByte()); err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConvertToSI adjusts the raw values from the adxl345 with the range configuration
|
||||
func (d *adxl345DataFormat) ConvertToSI(rawValue int16) float64 {
|
||||
switch d.sensorRange {
|
||||
case ADXL345_RANGE_2G:
|
||||
func (d *ADXL345Driver) shutdown() error {
|
||||
d.powerCtl.measure = 0
|
||||
if d.connection == nil {
|
||||
return errors.New("connection not available")
|
||||
}
|
||||
return d.connection.WriteByteData(adxl345Reg_POWER_CTL, d.powerCtl.toByte())
|
||||
}
|
||||
|
||||
// convertToG converts the given raw value by range configuration to the unit [g]
|
||||
func (d *adxl345DataFormat) convertToG(rawValue int16) float64 {
|
||||
switch d.fullScaleRange {
|
||||
case ADXL345FsRange_2G:
|
||||
return float64(rawValue) * 2 / 512
|
||||
case ADXL345_RANGE_4G:
|
||||
case ADXL345FsRange_4G:
|
||||
return float64(rawValue) * 4 / 512
|
||||
case ADXL345_RANGE_8G:
|
||||
case ADXL345FsRange_8G:
|
||||
return float64(rawValue) * 8 / 512
|
||||
case ADXL345_RANGE_16G:
|
||||
case ADXL345FsRange_16G:
|
||||
return float64(rawValue) * 16 / 512
|
||||
default:
|
||||
return 0
|
||||
@ -294,35 +291,29 @@ func (d *adxl345DataFormat) ConvertToSI(rawValue int16) float64 {
|
||||
}
|
||||
|
||||
// toByte returns a byte from the powerCtl configuration
|
||||
func (p *adxl345PowerCtl) toByte() (bits uint8) {
|
||||
bits = 0x00
|
||||
bits = bits | (p.link << 5)
|
||||
bits = bits | (p.autoSleep << 4)
|
||||
bits = bits | (p.measure << 3)
|
||||
func (p *adxl345PowerCtl) toByte() uint8 {
|
||||
bits := p.wakeUp
|
||||
bits = bits | (p.sleep << 2)
|
||||
bits = bits | p.wakeUp
|
||||
|
||||
return bits
|
||||
bits = bits | (p.measure << 3)
|
||||
bits = bits | (p.autoSleep << 4)
|
||||
return bits | (p.link << 5)
|
||||
}
|
||||
|
||||
// toByte returns a byte from the dataFormat configuration
|
||||
func (d *adxl345DataFormat) toByte() (bits uint8) {
|
||||
bits = 0x00
|
||||
bits = bits | (d.selfTest << 7)
|
||||
bits = bits | (d.spi << 6)
|
||||
bits = bits | (d.intInvert << 5)
|
||||
bits = bits | (d.fullRes << 3)
|
||||
func (d *adxl345DataFormat) toByte() uint8 {
|
||||
bits := uint8(d.fullScaleRange)
|
||||
bits = bits | (d.justify << 2)
|
||||
bits = bits | d.sensorRange
|
||||
|
||||
return bits
|
||||
bits = bits | (d.fullRes << 3)
|
||||
bits = bits | (d.intInvert << 5)
|
||||
bits = bits | (d.spi << 6)
|
||||
return bits | (d.selfTest << 7)
|
||||
}
|
||||
|
||||
// toByte returns a byte from the bwRate configuration
|
||||
func (b *adxl345BwRate) toByte() (bits uint8) {
|
||||
bits = 0x00
|
||||
bits = bits | (b.lowPower << 4)
|
||||
bits = bits | b.rate
|
||||
|
||||
func (b *adxl345BwRate) toByte() uint8 {
|
||||
bits := uint8(b.rate)
|
||||
if b.lowPower {
|
||||
bits = bits | adxl345Rate_LowPowerBit
|
||||
}
|
||||
return bits
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package i2c
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
@ -10,144 +9,314 @@ import (
|
||||
"gobot.io/x/gobot/gobottest"
|
||||
)
|
||||
|
||||
// this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver
|
||||
// and tests all implementations, so no further tests needed here for gobot.Driver interface
|
||||
var _ gobot.Driver = (*ADXL345Driver)(nil)
|
||||
|
||||
// --------- HELPERS
|
||||
func initTestADXL345Driver() (driver *ADXL345Driver) {
|
||||
driver, _ = initTestADXL345DriverWithStubbedAdaptor()
|
||||
return
|
||||
func initTestADXL345WithStubbedAdaptor() (*ADXL345Driver, *i2cTestAdaptor) {
|
||||
a := newI2cTestAdaptor()
|
||||
d := NewADXL345Driver(a)
|
||||
return d, a
|
||||
}
|
||||
|
||||
func initTestADXL345DriverWithStubbedAdaptor() (*ADXL345Driver, *i2cTestAdaptor) {
|
||||
adaptor := newI2cTestAdaptor()
|
||||
return NewADXL345Driver(adaptor), adaptor
|
||||
}
|
||||
|
||||
// --------- TESTS
|
||||
|
||||
func TestNewADXL345Driver(t *testing.T) {
|
||||
// Does it return a pointer to an instance of ADXL345Driver?
|
||||
var mma interface{} = NewADXL345Driver(newI2cTestAdaptor())
|
||||
_, ok := mma.(*ADXL345Driver)
|
||||
var di interface{} = NewADXL345Driver(newI2cTestAdaptor())
|
||||
d, ok := di.(*ADXL345Driver)
|
||||
if !ok {
|
||||
t.Errorf("NewADXL345Driver() should have returned a *ADXL345Driver")
|
||||
}
|
||||
gobottest.Refute(t, d.Driver, nil)
|
||||
gobottest.Assert(t, strings.HasPrefix(d.Name(), "ADXL345"), true)
|
||||
gobottest.Assert(t, d.powerCtl.measure, uint8(1))
|
||||
gobottest.Assert(t, d.dataFormat.fullScaleRange, ADXL345FsRangeConfig(0x00))
|
||||
gobottest.Assert(t, d.bwRate.rate, ADXL345RateConfig(0x0A))
|
||||
gobottest.Assert(t, d.bwRate.lowPower, true)
|
||||
}
|
||||
|
||||
// Methods
|
||||
func TestADXL345Driver(t *testing.T) {
|
||||
mma := initTestADXL345Driver()
|
||||
|
||||
gobottest.Refute(t, mma.Connection(), nil)
|
||||
gobottest.Assert(t, strings.HasPrefix(mma.Name(), "ADXL345"), true)
|
||||
}
|
||||
|
||||
func TestADXL345DriverSetName(t *testing.T) {
|
||||
d := initTestADXL345Driver()
|
||||
d.SetName("TESTME")
|
||||
gobottest.Assert(t, d.Name(), "TESTME")
|
||||
}
|
||||
|
||||
func TestADXL345DriverOptions(t *testing.T) {
|
||||
d := NewADXL345Driver(newI2cTestAdaptor(), WithBus(2))
|
||||
func TestADXL345Options(t *testing.T) {
|
||||
// This is a general test, that options are applied in constructor by using the common WithBus() option and
|
||||
// least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)".
|
||||
d := NewADXL345Driver(newI2cTestAdaptor(), WithBus(2), WithADXL345LowPowerMode(false))
|
||||
gobottest.Assert(t, d.GetBusOrDefault(1), 2)
|
||||
gobottest.Assert(t, d.bwRate.lowPower, false)
|
||||
}
|
||||
|
||||
func TestADXL345DriverStart(t *testing.T) {
|
||||
d := initTestADXL345Driver()
|
||||
gobottest.Assert(t, d.Start(), nil)
|
||||
func TestADXL345WithADXL345DataOutputRate(t *testing.T) {
|
||||
// arrange
|
||||
d, a := initTestADXL345WithStubbedAdaptor()
|
||||
a.written = []byte{} // reset writes of former test
|
||||
const (
|
||||
setVal = ADXL345RateConfig(0x0E) // 1.6kHz
|
||||
)
|
||||
// act
|
||||
WithADXL345DataOutputRate(setVal)(d)
|
||||
// assert
|
||||
gobottest.Assert(t, d.bwRate.rate, setVal)
|
||||
gobottest.Assert(t, len(a.written), 0)
|
||||
}
|
||||
|
||||
func TestADXL345StartConnectError(t *testing.T) {
|
||||
d, adaptor := initTestADXL345DriverWithStubbedAdaptor()
|
||||
adaptor.Testi2cConnectErr(true)
|
||||
gobottest.Assert(t, d.Start(), errors.New("Invalid i2c connection"))
|
||||
func TestADXL345WithADXL345FullScaleRange(t *testing.T) {
|
||||
// arrange
|
||||
d, a := initTestADXL345WithStubbedAdaptor()
|
||||
a.written = []byte{} // reset writes of former test
|
||||
const (
|
||||
setVal = ADXL345FsRangeConfig(0x02) // +-8 g
|
||||
)
|
||||
// act
|
||||
WithADXL345FullScaleRange(setVal)(d)
|
||||
// assert
|
||||
gobottest.Assert(t, d.dataFormat.fullScaleRange, setVal)
|
||||
gobottest.Assert(t, len(a.written), 0)
|
||||
}
|
||||
|
||||
func TestADXL345DriverStartWriteError(t *testing.T) {
|
||||
mma, adaptor := initTestADXL345DriverWithStubbedAdaptor()
|
||||
adaptor.i2cWriteImpl = func([]byte) (int, error) {
|
||||
return 0, errors.New("write error")
|
||||
func TestADXL345UseLowPower(t *testing.T) {
|
||||
// sequence to set low power:
|
||||
// * set value in data rate structure
|
||||
// * write the data rate register (0x2C)
|
||||
d, a := initTestADXL345WithStubbedAdaptor()
|
||||
d.Start()
|
||||
a.written = []byte{} // reset writes of former test
|
||||
setVal := !d.bwRate.lowPower
|
||||
const (
|
||||
wantReg = uint8(0x2C)
|
||||
wantVal = uint8(0x0A) // only 100 Hz left over
|
||||
)
|
||||
// act
|
||||
err := d.UseLowPower(setVal)
|
||||
// assert
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, d.bwRate.lowPower, setVal)
|
||||
gobottest.Assert(t, len(a.written), 2)
|
||||
gobottest.Assert(t, a.written[0], wantReg)
|
||||
gobottest.Assert(t, a.written[1], wantVal)
|
||||
}
|
||||
|
||||
func TestADXL345SetRate(t *testing.T) {
|
||||
// sequence to set rate:
|
||||
// * set value in data rate structure
|
||||
// * write the data rate register (0x2C)
|
||||
d, a := initTestADXL345WithStubbedAdaptor()
|
||||
d.Start()
|
||||
a.written = []byte{} // reset writes of former test
|
||||
const (
|
||||
setVal = ADXL345RateConfig(0x0F) // 3.2kHz
|
||||
wantReg = uint8(0x2C)
|
||||
wantVal = uint8(0x1F) // also low power bit
|
||||
)
|
||||
// act
|
||||
err := d.SetRate(setVal)
|
||||
// assert
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, d.bwRate.rate, setVal)
|
||||
gobottest.Assert(t, len(a.written), 2)
|
||||
gobottest.Assert(t, a.written[0], wantReg)
|
||||
gobottest.Assert(t, a.written[1], wantVal)
|
||||
}
|
||||
|
||||
func TestADXL345SetRange(t *testing.T) {
|
||||
// sequence to set range:
|
||||
// * set value in data format structure
|
||||
// * write the data format register (0x31)
|
||||
d, a := initTestADXL345WithStubbedAdaptor()
|
||||
d.Start()
|
||||
a.written = []byte{} // reset writes of former test
|
||||
const (
|
||||
setVal = ADXL345FsRangeConfig(0x03) // +/- 16 g
|
||||
wantReg = uint8(0x31)
|
||||
wantVal = uint8(0x03)
|
||||
)
|
||||
// act
|
||||
err := d.SetRange(setVal)
|
||||
// assert
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, d.dataFormat.fullScaleRange, setVal)
|
||||
gobottest.Assert(t, len(a.written), 2)
|
||||
gobottest.Assert(t, a.written[0], wantReg)
|
||||
gobottest.Assert(t, a.written[1], wantVal)
|
||||
}
|
||||
|
||||
func TestADXL345RawXYZ(t *testing.T) {
|
||||
// sequence to read:
|
||||
// * prepare read, see test of initialize()
|
||||
// * read data output registers (0x32, 3 x 16 bit, LSByte first)
|
||||
// * apply two's complement converter
|
||||
//
|
||||
// arrange
|
||||
var tests = map[string]struct {
|
||||
inputX []uint8
|
||||
inputY []uint8
|
||||
inputZ []uint8
|
||||
wantX int16
|
||||
wantY int16
|
||||
wantZ int16
|
||||
}{
|
||||
"+FS_0_-FS": {
|
||||
inputX: []uint8{0xFF, 0x07},
|
||||
inputY: []uint8{0x00, 0x00},
|
||||
inputZ: []uint8{0x00, 0xF8},
|
||||
wantX: (1<<11 - 1),
|
||||
wantY: 0,
|
||||
wantZ: -(1 << 11),
|
||||
},
|
||||
"-4096_-1_+1": {
|
||||
inputX: []uint8{0x00, 0xF0},
|
||||
inputY: []uint8{0xFF, 0xFF},
|
||||
inputZ: []uint8{0x01, 0x00},
|
||||
wantX: -4096,
|
||||
wantY: -1,
|
||||
wantZ: 1,
|
||||
},
|
||||
}
|
||||
gobottest.Assert(t, mma.Start(), errors.New("write error"))
|
||||
}
|
||||
|
||||
func TestADXL345DriverHalt(t *testing.T) {
|
||||
d := initTestADXL345Driver()
|
||||
gobottest.Assert(t, d.Start(), nil)
|
||||
gobottest.Assert(t, d.Halt(), nil)
|
||||
}
|
||||
|
||||
func TestADXL345DriverNullXYZ(t *testing.T) {
|
||||
d, _ := initTestADXL345DriverWithStubbedAdaptor()
|
||||
d, a := initTestADXL345WithStubbedAdaptor()
|
||||
d.Start()
|
||||
x, y, z, _ := d.XYZ()
|
||||
gobottest.Assert(t, x, 0.0)
|
||||
gobottest.Assert(t, y, 0.0)
|
||||
gobottest.Assert(t, z, 0.0)
|
||||
}
|
||||
|
||||
func TestADXL345DriverXYZ(t *testing.T) {
|
||||
d, adaptor := initTestADXL345DriverWithStubbedAdaptor()
|
||||
d.Start()
|
||||
|
||||
adaptor.i2cReadImpl = func(b []byte) (int, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.Write([]byte{218, 0, 251, 255, 100, 0})
|
||||
copy(b, buf.Bytes())
|
||||
return buf.Len(), nil
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
a.written = []byte{} // reset writes of former test and start
|
||||
// arrange reads
|
||||
returnRead := append(append(tc.inputX, tc.inputY...), tc.inputZ...)
|
||||
numCallsRead := 0
|
||||
a.i2cReadImpl = func(b []byte) (int, error) {
|
||||
numCallsRead++
|
||||
copy(b, returnRead)
|
||||
return len(b), nil
|
||||
}
|
||||
// act
|
||||
gotX, gotY, gotZ, err := d.RawXYZ()
|
||||
// assert
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, gotX, tc.wantX)
|
||||
gobottest.Assert(t, gotY, tc.wantY)
|
||||
gobottest.Assert(t, gotZ, tc.wantZ)
|
||||
gobottest.Assert(t, numCallsRead, 1)
|
||||
gobottest.Assert(t, len(a.written), 1)
|
||||
gobottest.Assert(t, a.written[0], uint8(0x32))
|
||||
})
|
||||
}
|
||||
|
||||
x, y, z, _ := d.XYZ()
|
||||
gobottest.Assert(t, x, 0.8515625)
|
||||
gobottest.Assert(t, y, -0.01953125)
|
||||
gobottest.Assert(t, z, 0.390625)
|
||||
}
|
||||
|
||||
func TestADXL345DriverXYZError(t *testing.T) {
|
||||
d, adaptor := initTestADXL345DriverWithStubbedAdaptor()
|
||||
func TestADXL345RawXYZError(t *testing.T) {
|
||||
// arrange
|
||||
d, a := initTestADXL345WithStubbedAdaptor()
|
||||
d.Start()
|
||||
|
||||
adaptor.i2cReadImpl = func(b []byte) (int, error) {
|
||||
a.i2cReadImpl = func(b []byte) (int, error) {
|
||||
return 0, errors.New("read error")
|
||||
}
|
||||
|
||||
_, _, _, err := d.XYZ()
|
||||
gobottest.Assert(t, err, errors.New("read error"))
|
||||
}
|
||||
|
||||
|
||||
func TestADXL345DriverRawXYZ(t *testing.T) {
|
||||
d, adaptor := initTestADXL345DriverWithStubbedAdaptor()
|
||||
d.Start()
|
||||
|
||||
adaptor.i2cReadImpl = func(b []byte) (int, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.Write([]byte{218, 0, 251, 255, 100, 0})
|
||||
copy(b, buf.Bytes())
|
||||
return buf.Len(), nil
|
||||
}
|
||||
|
||||
x, y, z, _ := d.RawXYZ()
|
||||
gobottest.Assert(t, int(x), 218)
|
||||
gobottest.Assert(t, int(y), -5)
|
||||
gobottest.Assert(t, int(z), 100)
|
||||
}
|
||||
|
||||
func TestADXL345DriverRawXYZError(t *testing.T) {
|
||||
d, adaptor := initTestADXL345DriverWithStubbedAdaptor()
|
||||
d.Start()
|
||||
|
||||
adaptor.i2cReadImpl = func(b []byte) (int, error) {
|
||||
return 0, errors.New("read error")
|
||||
}
|
||||
|
||||
// act
|
||||
_, _, _, err := d.RawXYZ()
|
||||
// assert
|
||||
gobottest.Assert(t, err, errors.New("read error"))
|
||||
}
|
||||
|
||||
func TestADXL345DriverSetRange(t *testing.T) {
|
||||
d := initTestADXL345Driver()
|
||||
d.Start()
|
||||
gobottest.Assert(t, d.SetRange(ADXL345_RANGE_16G), nil)
|
||||
func TestADXL345XYZ(t *testing.T) {
|
||||
// arrange
|
||||
var tests = map[string]struct {
|
||||
inputX []uint8
|
||||
inputY []uint8
|
||||
inputZ []uint8
|
||||
wantX float64
|
||||
wantY float64
|
||||
wantZ float64
|
||||
}{
|
||||
"null_value": {
|
||||
inputX: []uint8{0, 0},
|
||||
inputY: []uint8{0, 0},
|
||||
inputZ: []uint8{0, 0},
|
||||
wantX: 0,
|
||||
wantY: 0,
|
||||
wantZ: 0,
|
||||
},
|
||||
"some_value": {
|
||||
inputX: []uint8{218, 0},
|
||||
inputY: []uint8{251, 255},
|
||||
inputZ: []uint8{100, 0},
|
||||
wantX: 0.8515625,
|
||||
wantY: -0.01953125,
|
||||
wantZ: 0.390625,
|
||||
},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// arrange
|
||||
d, a := initTestADXL345WithStubbedAdaptor()
|
||||
d.Start()
|
||||
a.written = []byte{} // reset writes of former test and start
|
||||
// arrange reads
|
||||
returnRead := append(append(tc.inputX, tc.inputY...), tc.inputZ...)
|
||||
numCallsRead := 0
|
||||
a.i2cReadImpl = func(b []byte) (int, error) {
|
||||
numCallsRead++
|
||||
copy(b, returnRead)
|
||||
return len(b), nil
|
||||
}
|
||||
// act
|
||||
x, y, z, _ := d.XYZ()
|
||||
// assert
|
||||
gobottest.Assert(t, x, tc.wantX)
|
||||
gobottest.Assert(t, y, tc.wantY)
|
||||
gobottest.Assert(t, z, tc.wantZ)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestADXL345XYZError(t *testing.T) {
|
||||
// arrange
|
||||
d, a := initTestADXL345WithStubbedAdaptor()
|
||||
d.Start()
|
||||
a.i2cReadImpl = func(b []byte) (int, error) {
|
||||
return 0, errors.New("read error")
|
||||
}
|
||||
// act
|
||||
_, _, _, err := d.XYZ()
|
||||
// assert
|
||||
gobottest.Assert(t, err, errors.New("read error"))
|
||||
}
|
||||
|
||||
func TestADXL345_initialize(t *testing.T) {
|
||||
// sequence to prepare read in initialize():
|
||||
// * prepare rate register content (data output rate, low power mode)
|
||||
// * prepare power control register content (wake up, sleep, measure, auto sleep, link)
|
||||
// * prepare data format register (fullScaleRange, justify, fullRes, intInvert, spi, selfTest)
|
||||
// * write 3 registers
|
||||
// arrange
|
||||
d, a := initTestADXL345WithStubbedAdaptor()
|
||||
a.written = []byte{} // reset writes of former test
|
||||
const (
|
||||
wantRateReg = uint8(0x2C)
|
||||
wantRateRegVal = uint8(0x1A) // 100HZ and low power
|
||||
wantPwrReg = uint8(0x2D)
|
||||
wantPwrRegVal = uint8(0x08) // measurement on
|
||||
wantFormatReg = uint8(0x31)
|
||||
wantFormatRegVal = uint8(0x00) // FS to +/-2 g
|
||||
)
|
||||
// act, assert - initialize() must be called on Start()
|
||||
err := d.Start()
|
||||
// assert
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, len(a.written), 6)
|
||||
gobottest.Assert(t, a.written[0], wantRateReg)
|
||||
gobottest.Assert(t, a.written[1], wantRateRegVal)
|
||||
gobottest.Assert(t, a.written[2], wantPwrReg)
|
||||
gobottest.Assert(t, a.written[3], wantPwrRegVal)
|
||||
gobottest.Assert(t, a.written[4], wantFormatReg)
|
||||
gobottest.Assert(t, a.written[5], wantFormatRegVal)
|
||||
}
|
||||
|
||||
func TestADXL345_shutdown(t *testing.T) {
|
||||
// sequence to prepare read in shutdown():
|
||||
// * reset the measurement bit in structure
|
||||
// * write the power control register (0x2D)
|
||||
d, a := initTestADXL345WithStubbedAdaptor()
|
||||
d.Start()
|
||||
a.written = []byte{} // reset writes of former test
|
||||
const (
|
||||
wantReg = uint8(0x2D)
|
||||
wantVal = uint8(0x00)
|
||||
)
|
||||
// act, assert - shutdown() must be called on Halt()
|
||||
err := d.Halt()
|
||||
// assert
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, len(a.written), 2)
|
||||
gobottest.Assert(t, a.written[0], wantReg)
|
||||
gobottest.Assert(t, a.written[1], wantVal)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user