mirror of https://github.com/periph/devices
Move code around to make drivers follow a common pattern
The idea is to enable navigating across the code more easily by using similar layout amongs the drivers. Similar to gofmt, it's not about making a stylistic choice, but having a single style. Use the following layout for drivers: - exported support types - Opts struct - New func - Dev struct and methods - Private support code No functional change. A lot of code moved around, so it will likely break any pending PR or fork. :/pull/1/head
parent
89531ab87e
commit
5b5083e8fb
@ -1,202 +0,0 @@
|
|||||||
// Copyright 2016 The Periph Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed under the Apache License, Version 2.0
|
|
||||||
// that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package ds248x
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"periph.io/x/periph/conn"
|
|
||||||
"periph.io/x/periph/conn/onewire"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
//
|
|
||||||
// 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
|
|
||||||
isDS2483 bool // true: ds2483, false: ds2482-100
|
|
||||||
confReg byte // value written to configuration register
|
|
||||||
tReset time.Duration // time to perform a 1-wire reset
|
|
||||||
tSlot time.Duration // time to perform a 1-bit 1-wire read/write
|
|
||||||
err error // persistent error, device will no longer operate
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Dev) String() string {
|
|
||||||
if d.isDS2483 {
|
|
||||||
return fmt.Sprintf("DS2483{%s}", d.i2c)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("DS2482-100{%s}", d.i2c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Halt implements conn.Resource.
|
|
||||||
func (d *Dev) Halt() error {
|
|
||||||
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.
|
|
||||||
//
|
|
||||||
// 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()
|
|
||||||
|
|
||||||
// Issue 1-wire bus reset.
|
|
||||||
if present, err := d.reset(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if !present {
|
|
||||||
return busError("ds248x: no device present")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send bytes onto 1-wire bus.
|
|
||||||
for i, b := range w {
|
|
||||||
if power == onewire.StrongPullup && i == len(w)-1 && len(r) == 0 {
|
|
||||||
// This is the last byte, need to activate strong pull-up.
|
|
||||||
d.i2cTx([]byte{cmdWriteConfig, d.confReg&0xbf | 0x4}, nil)
|
|
||||||
}
|
|
||||||
d.i2cTx([]byte{cmd1WWrite, b}, nil)
|
|
||||||
d.waitIdle(7 * d.tSlot)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read bytes from one-wire bus.
|
|
||||||
for i := range r {
|
|
||||||
if power == onewire.StrongPullup && i == len(r)-1 {
|
|
||||||
// This is the last byte, need to activate strong-pull-up
|
|
||||||
d.i2cTx([]byte{cmdWriteConfig, d.confReg&0xbf | 0x4}, nil)
|
|
||||||
}
|
|
||||||
d.i2cTx([]byte{cmd1WRead}, r[i:i+1])
|
|
||||||
d.waitIdle(7 * d.tSlot)
|
|
||||||
d.i2cTx([]byte{cmdSetReadPtr, regRDR}, r[i:i+1])
|
|
||||||
}
|
|
||||||
|
|
||||||
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.
|
|
||||||
//
|
|
||||||
// If an error occurs during the search the already-discovered devices are
|
|
||||||
// returned with the error.
|
|
||||||
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 should not be used directly, use Search instead.
|
|
||||||
func (d *Dev) SearchTriplet(direction byte) (onewire.TripletResult, error) {
|
|
||||||
// Send one-wire triplet command.
|
|
||||||
var dir byte
|
|
||||||
if direction != 0 {
|
|
||||||
dir = 0x80
|
|
||||||
}
|
|
||||||
d.i2cTx([]byte{cmd1WTriplet, dir}, nil)
|
|
||||||
// Wait and read status register, concoct result from there.
|
|
||||||
status := d.waitIdle(0 * d.tSlot) // in theory 3*tSlot but it's actually overlapped
|
|
||||||
tr := onewire.TripletResult{
|
|
||||||
GotZero: status&0x20 == 0,
|
|
||||||
GotOne: status&0x40 == 0,
|
|
||||||
Taken: status >> 7,
|
|
||||||
}
|
|
||||||
return tr, d.err
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
// reset issues a reset signal on the 1-wire bus and returns true if any device
|
|
||||||
// responded with a presence pulse.
|
|
||||||
func (d *Dev) reset() (bool, error) {
|
|
||||||
// Issue reset.
|
|
||||||
d.i2cTx([]byte{cmd1WReset}, nil)
|
|
||||||
|
|
||||||
// Wait for reset to complete.
|
|
||||||
status := d.waitIdle(d.tReset)
|
|
||||||
if d.err != nil {
|
|
||||||
return false, d.err
|
|
||||||
}
|
|
||||||
// Detect bus short and turn into 1-wire error
|
|
||||||
if (status & 4) != 0 {
|
|
||||||
return false, shortedBusError("onewire/ds248x: bus has a short")
|
|
||||||
}
|
|
||||||
return (status & 2) != 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
d.err = d.i2c.Tx(w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
//
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
// Overall timeout.
|
|
||||||
tOut := time.Now().Add(3 * time.Millisecond)
|
|
||||||
sleep(delay)
|
|
||||||
for {
|
|
||||||
// Read status register.
|
|
||||||
var status [1]byte
|
|
||||||
d.i2cTx(nil, status[:])
|
|
||||||
// If bus idle complete, return status. This also returns if d.err!=nil
|
|
||||||
// because in that case status[0]==0.
|
|
||||||
if (status[0] & 1) == 0 {
|
|
||||||
return status[0]
|
|
||||||
}
|
|
||||||
// If we're timing out return error. This is an error with the ds248x, not with
|
|
||||||
// devices on the 1-wire bus, hence it is persistent.
|
|
||||||
if time.Now().After(tOut) {
|
|
||||||
d.err = fmt.Errorf("ds248x: timeout waiting for bus cycle to finish")
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
// Try not to hog the kernel thread.
|
|
||||||
sleep(delay / 10)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// shortedBusError implements error and onewire.ShortedBusError.
|
|
||||||
type shortedBusError string
|
|
||||||
|
|
||||||
func (e shortedBusError) Error() string { return string(e) }
|
|
||||||
func (e shortedBusError) IsShorted() bool { return true }
|
|
||||||
func (e shortedBusError) BusError() bool { return true }
|
|
||||||
|
|
||||||
// busError implements error and onewire.BusError.
|
|
||||||
type busError string
|
|
||||||
|
|
||||||
func (e busError) Error() string { return string(e) }
|
|
||||||
func (e busError) BusError() bool { return true }
|
|
||||||
|
|
||||||
var sleep = time.Sleep
|
|
||||||
|
|
||||||
var _ conn.Resource = &Dev{}
|
|
||||||
var _ fmt.Stringer = &Dev{}
|
|
||||||
Loading…
Reference in New Issue