diff --git a/devices/ds18b20/ds18b20_test.go b/devices/ds18b20/ds18b20_test.go index 9f87312..a434d95 100644 --- a/devices/ds18b20/ds18b20_test.go +++ b/devices/ds18b20/ds18b20_test.go @@ -5,20 +5,28 @@ package ds18b20 import ( - "os" "testing" "time" "periph.io/x/periph/conn/onewire" "periph.io/x/periph/conn/onewire/onewiretest" "periph.io/x/periph/devices" - "periph.io/x/periph/host" ) -// TestMain lets periph load all drivers and then runs the tests. -func TestMain(m *testing.M) { - host.Init() - os.Exit(m.Run()) +func TestNew_resolution(t *testing.T) { + bus := &onewiretest.Playback{} + var addr onewire.Address = 0x740000070e41ac28 + if d, err := New(bus, addr, 1); d != nil || err == nil { + t.Fatal("invalid resolution") + } +} + +func TestNew_read(t *testing.T) { + bus := &onewiretest.Playback{DontPanic: true} + var addr onewire.Address = 0x740000070e41ac28 + if d, err := New(bus, addr, 9); d != nil || err == nil { + t.Fatal("invalid resolution") + } } // TestTemperature tests a temperature conversion on a ds18b20 using @@ -27,20 +35,26 @@ func TestTemperature(t *testing.T) { // set-up playback using the recording output. ops := []onewiretest.IO{ // Match ROM + Read Scratchpad (init) - {Write: []uint8{0x55, 0x28, 0xac, 0x41, 0xe, 0x7, 0x0, 0x0, 0x74, 0xbe}, - Read: []uint8{0xe0, 0x1, 0x0, 0x0, 0x3f, 0xff, 0x10, 0x10, 0x3f}, Pull: false}, + { + Write: []uint8{0x55, 0x28, 0xac, 0x41, 0xe, 0x7, 0x0, 0x0, 0x74, 0xbe}, + Read: []uint8{0xe0, 0x1, 0x0, 0x0, 0x3f, 0xff, 0x10, 0x10, 0x3f}, + }, // Match ROM + Convert - {Write: []uint8{0x55, 0x28, 0xac, 0x41, 0xe, 0x7, 0x0, 0x0, 0x74, 0x44}, - Read: []uint8(nil), Pull: true}, + { + Write: []uint8{0x55, 0x28, 0xac, 0x41, 0xe, 0x7, 0x0, 0x0, 0x74, 0x44}, + Pull: true, + }, // Match ROM + Read Scratchpad (read temp) - {Write: []uint8{0x55, 0x28, 0xac, 0x41, 0xe, 0x7, 0x0, 0x0, 0x74, 0xbe}, - Read: []uint8{0xe0, 0x1, 0x0, 0x0, 0x3f, 0xff, 0x10, 0x10, 0x3f}, Pull: false}, + { + Write: []uint8{0x55, 0x28, 0xac, 0x41, 0xe, 0x7, 0x0, 0x0, 0x74, 0xbe}, + Read: []uint8{0xe0, 0x1, 0x0, 0x0, 0x3f, 0xff, 0x10, 0x10, 0x3f}, + }, } var addr onewire.Address = 0x740000070e41ac28 var temp devices.Celsius = 30000 // 30.000°C - owBus := &onewiretest.Playback{Ops: ops} + bus := onewiretest.Playback{Ops: ops} // Init the ds18b20. - ds18b20, err := New(owBus, addr, 10) + ds18b20, err := New(&bus, addr, 10) if err != nil { t.Fatal(err) } @@ -59,6 +73,9 @@ func TestTemperature(t *testing.T) { if dt < 188*time.Millisecond { t.Errorf("expected conversion to take >187ms, took %s", dt) } + if err := bus.Close(); err != nil { + t.Fatal(err) + } } // TestConvertAll tests a temperature conversion on all ds18b20 using @@ -69,16 +86,33 @@ func TestConvertAll(t *testing.T) { // Skip ROM + Convert {Write: []uint8{0xcc, 0x44}, Read: []uint8(nil), Pull: true}, } - owBus := &onewiretest.Playback{Ops: ops} + bus := onewiretest.Playback{Ops: ops} // Perform the conversion t0 := time.Now() - if err := ConvertAll(owBus, 9); err != nil { + if err := ConvertAll(&bus, 9); err != nil { t.Fatal(err) } // Expect it to take >93ms if dt := time.Since(t0); dt < 94*time.Millisecond { t.Errorf("expected conversion to take >93ms, took %s", dt) } + if err := bus.Close(); err != nil { + t.Fatal(err) + } +} + +func TestConvertAll_resolution(t *testing.T) { + bus := &onewiretest.Playback{} + if err := ConvertAll(bus, 1); err == nil { + t.Fatal("invalid resolution") + } +} + +func TestConvertAll_fail(t *testing.T) { + bus := &onewiretest.Playback{DontPanic: true} + if err := ConvertAll(bus, 9); err == nil { + t.Fatal("invalid resolution") + } } /* Commented out in order not to import periph/host, need to move to smoke test diff --git a/devices/ds248x/dev.go b/devices/ds248x/dev.go index 7ccb246..926371d 100644 --- a/devices/ds248x/dev.go +++ b/devices/ds248x/dev.go @@ -13,15 +13,18 @@ import ( "periph.io/x/periph/conn/onewire" ) -// Dev is a handle to a ds248x device and it implements the onewire.Bus interface. +// Dev is a handle to a ds248x device and it implements the onewire.Bus +// interface. // -// Dev implements a persistent error model: if a fatal error is encountered it places -// itself into an error state and immediately returns the last error on all subsequent -// calls. A fresh Dev, which reinitializes the hardware, must be created to proceed. +// Dev implements a persistent error model: if a fatal error is encountered it +// places itself into an error state and immediately returns the last error on +// all subsequent calls. A fresh Dev, which reinitializes the hardware, must be +// created to proceed. // -// A persistent error is only set when there is a problem with the ds248x device itself -// (or the I²C bus used to access it). Errors on the 1-wire bus do not cause persistent -// errors and implement the onewire.BusError interface to indicate this fact. +// A persistent error is only set when there is a problem with the ds248x +// device itself (or the I²C bus used to access it). Errors on the 1-wire bus +// do not cause persistent errors and implement the onewire.BusError interface +// to indicate this fact. type Dev struct { sync.Mutex // lock for the bus while a transaction is in progress i2c conn.Conn // i2c device handle for the ds248x @@ -32,24 +35,16 @@ type Dev struct { err error // persistent error, device will no longer operate } -// String func (d *Dev) String() string { - return fmt.Sprintf("ds248x") + return "ds248x" } -// Close drops the I²C bus handle and sets a persistent error. -func (d *Dev) Close() error { - d.i2c = nil - d.err = fmt.Errorf("ds248x: invalid operation on closed bus") - return nil -} - -// Tx performs a bus transaction, sending and receiving bytes, and -// ending by pulling the bus high either weakly or strongly depending -// on the value of power. +// Tx performs a bus transaction, sending and receiving bytes, and ending by +// pulling the bus high either weakly or strongly depending on the value of +// power. // -// A strong pull-up is typically required to power temperature conversion -// or EEPROM writes. +// A strong pull-up is typically required to power temperature conversion or +// EEPROM writes. func (d *Dev) Tx(w, r []byte, power onewire.Pullup) error { d.Lock() defer d.Unlock() @@ -85,9 +80,9 @@ func (d *Dev) Tx(w, r []byte, power onewire.Pullup) error { return d.err } -// Search performs a "search" cycle on the 1-wire bus and returns the -// addresses of all devices on the bus if alarmOnly is false and of all -// devices in alarm state if alarmOnly is true. +// Search performs a "search" cycle on the 1-wire bus and returns the addresses +// of all devices on the bus if alarmOnly is false and of all devices in alarm +// state if alarmOnly is true. // // If an error occurs during the search the already-discovered devices are // returned with the error. @@ -95,8 +90,8 @@ func (d *Dev) Search(alarmOnly bool) ([]onewire.Address, error) { return onewire.Search(d, alarmOnly) } -// SearchTriplet performs a single bit search triplet command on the bus, -// waits for it to complete and returs the outcome. +// SearchTriplet performs a single bit search triplet command on the bus, waits +// for it to complete and returs the outcome. // // SearchTriplet should not be used directly, use Search instead. func (d *Dev) SearchTriplet(direction byte) (onewire.TripletResult, error) { @@ -136,7 +131,8 @@ func (d *Dev) reset() (bool, error) { return (status & 2) != 0, nil } -// i2cTx is a helper function to call i2c.Tx and handle the error by persisting it. +// i2cTx is a helper function to call i2c.Tx and handle the error by persisting +// it. func (d *Dev) i2cTx(w, r []byte) { if d.err != nil { return @@ -147,11 +143,11 @@ func (d *Dev) i2cTx(w, r []byte) { // waitIdle waits for the one wire bus to be idle. // // It initially sleeps for the delay and then polls the status register and -// sleeps for a tenth of the delay each time the status register indicates -// that the bus is still busy. The last read status byte is returned. +// sleeps for a tenth of the delay each time the status register indicates that +// the bus is still busy. The last read status byte is returned. // -// An overall timeout of 3ms is applied to the whole procedure. waitIdle -// uses the persistent error model and returns 0 if there is an error. +// An overall timeout of 3ms is applied to the whole procedure. waitIdle uses +// the persistent error model and returns 0 if there is an error. func (d *Dev) waitIdle(delay time.Duration) byte { if d.err != nil { return 0 diff --git a/devices/ds248x/ds248x_test.go b/devices/ds248x/ds248x_test.go index cd446b7..a5a34b3 100644 --- a/devices/ds248x/ds248x_test.go +++ b/devices/ds248x/ds248x_test.go @@ -6,56 +6,79 @@ package ds248x import ( "fmt" + "log" "testing" "periph.io/x/periph/conn/i2c/i2creg" "periph.io/x/periph/conn/i2c/i2ctest" ) -// TestInit tests the initialization of a ds2483 using a recording. -func TestInit(t *testing.T) { - var ops = []i2ctest.IO{ - {Addr: 0x18, Write: []byte{0xf0}, Read: []byte(nil)}, - {Addr: 0x18, Write: []byte{0xe1, 0xf0}, Read: []byte{0x18}}, - {Addr: 0x18, Write: []byte{0xd2, 0xe1}, Read: []byte{0x1}}, - {Addr: 0x18, Write: []byte{0xe1, 0xb4}, Read: []byte(nil)}, - {Addr: 0x18, Write: []byte{0xc3, 0x6, 0x26, 0x46, 0x66, 0x86}, Read: []byte(nil)}, - {Addr: 0x18, Write: []byte{0x78, 0x0}, Read: []byte(nil)}, - {Addr: 0x18, Write: []byte{}, Read: []byte{0xe8}}, - } - - bus := &i2ctest.Playback{Ops: ops} - if _, err := New(bus, nil); err != nil { - t.Fatal(err) - } -} - func Example() { // Open the I²C bus to which the DS248x is connected. i2cBus, err := i2creg.Open("") if err != nil { - fmt.Println(err) - return + log.Fatal(err) } defer i2cBus.Close() // Open the DS248x to get a 1-wire bus. owBus, err := New(i2cBus, nil) if err != nil { - fmt.Println(err) - return + log.Fatal(err) } // Search devices on the bus devices, err := owBus.Search(false) if err != nil { - fmt.Println(err) - return + log.Fatal(err) } fmt.Printf("Found %d 1-wire devices: ", len(devices)) for _, d := range devices { fmt.Printf(" %#16x", uint64(d)) } - fmt.Print('\n') + fmt.Print("\n") +} + +// + +func TestNew(t *testing.T) { + bus := i2ctest.Playback{ + Ops: []i2ctest.IO{ + {Addr: 0x18, Write: []byte{0xf0}}, + {Addr: 0x18, Write: []byte{0xe1, 0xf0}, Read: []byte{0x18}}, + {Addr: 0x18, Write: []byte{0xd2, 0xe1}, Read: []byte{0x1}}, + {Addr: 0x18, Write: []byte{0xe1, 0xb4}}, + {Addr: 0x18, Write: []byte{0xc3, 0x6, 0x26, 0x46, 0x66, 0x86}}, + }, + } + d, err := New(&bus, nil) + if err != nil { + t.Fatal(err) + } + if s := d.String(); s != "ds248x" { + t.Fatal(s) + } + if err := bus.Close(); err != nil { + t.Fatal(err) + } +} + +func TestNew_opts(t *testing.T) { + bus := i2ctest.Playback{ + Ops: []i2ctest.IO{ + {Addr: 0x18, Write: []byte{0xf0}}, + {Addr: 0x18, Write: []byte{0xe1, 0xf0}, Read: []byte{0x18}}, + {Addr: 0x18, Write: []byte{0xd2, 0xe1}, Read: []byte{0x1}}, + {Addr: 0x18, Write: []byte{0xe1, 0xb4}}, + {Addr: 0x18, Write: []byte{0xc3, 0x6, 0x26, 0x46, 0x66, 0x86}}, + }, + } + opts := &Opts{Addr: 0x18} + if _, err := New(&bus, opts); err != nil { + t.Fatal(err) + } + if err := bus.Close(); err != nil { + t.Fatal(err) + } } /* Commented out in order not to import periph/host, need to move to smoke test