tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/onewire/onewire.go (about)

     1  // Package wire implements the Dallas Semiconductor Corp.'s 1-wire bus system.
     2  //
     3  // Wikipedia: https://en.wikipedia.org/wiki/1-Wire
     4  package onewire // import "tinygo.org/x/drivers/onewire"
     5  
     6  import (
     7  	"errors"
     8  	"machine"
     9  	"time"
    10  )
    11  
    12  // OneWire ROM commands
    13  const (
    14  	READ_ROM   uint8 = 0x33
    15  	MATCH_ROM  uint8 = 0x55
    16  	SKIP_ROM   uint8 = 0xCC
    17  	SEARCH_ROM uint8 = 0xF0
    18  )
    19  
    20  // Device wraps a connection to an 1-Wire devices.
    21  type Device struct {
    22  	p machine.Pin
    23  }
    24  
    25  // Config wraps a configuration to an 1-Wire devices.
    26  type Config struct{}
    27  
    28  // Errors list
    29  var (
    30  	errNoPresence  = errors.New("Error: OneWire. No devices on the bus.")
    31  	errReadAddress = errors.New("Error: OneWire. Read address error: CRC mismatch.")
    32  )
    33  
    34  // New creates a new GPIO 1-Wire connection.
    35  // The pin must be pulled up to the VCC via a resistor greater than 500 ohms (default 4.7k).
    36  func New(p machine.Pin) Device {
    37  	return Device{
    38  		p: p,
    39  	}
    40  }
    41  
    42  // Configure initializes the protocol.
    43  func (d *Device) Configure(config Config) {}
    44  
    45  // Reset pull DQ line low, then up.
    46  func (d Device) Reset() error {
    47  	d.p.Configure(machine.PinConfig{Mode: machine.PinOutput})
    48  	time.Sleep(480 * time.Microsecond)
    49  	d.p.Configure(machine.PinConfig{Mode: machine.PinInput})
    50  	time.Sleep(70 * time.Microsecond)
    51  	precence := d.p.Get()
    52  	time.Sleep(410 * time.Microsecond)
    53  	if precence {
    54  		return errNoPresence
    55  	}
    56  	return nil
    57  }
    58  
    59  // WriteBit transmits a bit to 1-Wire bus.
    60  func (d Device) WriteBit(data uint8) {
    61  	d.p.Configure(machine.PinConfig{Mode: machine.PinOutput})
    62  	if data&1 == 1 { // Send '1'
    63  		time.Sleep(5 * time.Microsecond)
    64  		d.p.Configure(machine.PinConfig{Mode: machine.PinInput})
    65  		time.Sleep(60 * time.Microsecond)
    66  	} else { // Send '0'
    67  		time.Sleep(60 * time.Microsecond)
    68  		d.p.Configure(machine.PinConfig{Mode: machine.PinInput})
    69  		time.Sleep(5 * time.Microsecond)
    70  	}
    71  }
    72  
    73  // Write transmits a byte as bit array to 1-Wire bus. (LSB first)
    74  func (d Device) Write(data uint8) {
    75  	for i := 0; i < 8; i++ {
    76  		d.WriteBit(data)
    77  		data >>= 1
    78  	}
    79  }
    80  
    81  // ReadBit receives a bit from 1-Wire bus.
    82  func (d Device) ReadBit() (data uint8) {
    83  	d.p.Configure(machine.PinConfig{Mode: machine.PinOutput})
    84  	time.Sleep(3 * time.Microsecond)
    85  	d.p.Configure(machine.PinConfig{Mode: machine.PinInput})
    86  	time.Sleep(8 * time.Microsecond)
    87  	if d.p.Get() {
    88  		data = 1
    89  	}
    90  	time.Sleep(60 * time.Microsecond)
    91  	return data
    92  }
    93  
    94  // Read receives a byte from 1-Wire bus. (LSB first)
    95  func (d Device) Read() (data uint8) {
    96  	for i := 0; i < 8; i++ {
    97  		data >>= 1
    98  		data |= d.ReadBit() << 7
    99  	}
   100  	return data
   101  }
   102  
   103  // ReadAddress receives a 64-bit unique ROM ID from Device. (LSB first)
   104  // Note: use this if there is only one slave device on the bus.
   105  func (d Device) ReadAddress() ([]uint8, error) {
   106  	var romid = make([]uint8, 8)
   107  	if err := d.Reset(); err != nil {
   108  		return nil, err
   109  	}
   110  	d.Write(READ_ROM)
   111  	for i := 0; i < 8; i++ {
   112  		romid[i] = d.Read()
   113  	}
   114  	if d.Сrc8(romid, 7) != romid[7] {
   115  		return nil, errReadAddress
   116  	}
   117  	return romid, nil
   118  }
   119  
   120  // Select selects the address of the device for communication
   121  func (d Device) Select(romid []uint8) error {
   122  	if err := d.Reset(); err != nil {
   123  		return err
   124  	}
   125  	if len(romid) == 0 {
   126  		d.Write(SKIP_ROM)
   127  		return nil
   128  	}
   129  	d.Write(MATCH_ROM)
   130  	for i := 0; i < 8; i++ {
   131  		d.Write(romid[i])
   132  	}
   133  	return nil
   134  }
   135  
   136  // Search searches for all devices on the bus.
   137  // Note: max 32 slave devices per bus
   138  func (d Device) Search(cmd uint8) ([][]uint8, error) {
   139  	var (
   140  		bit, bit_c  uint8 = 0, 0
   141  		bitOffset   uint8 = 0
   142  		lastZero    uint8 = 0
   143  		lastFork    uint8 = 0
   144  		lastAddress       = make([]uint8, 8)
   145  		romIDs            = make([][]uint8, 32) //
   146  		romIndex    uint8 = 0
   147  	)
   148  
   149  	for i := range romIDs {
   150  		romIDs[i] = make([]uint8, 8)
   151  	}
   152  
   153  	for ok := true; ok; ok = (lastFork != 0) {
   154  		if err := d.Reset(); err != nil {
   155  			return nil, err
   156  		}
   157  
   158  		// send search command to bus
   159  		d.Write(cmd)
   160  
   161  		lastZero = 0
   162  
   163  		for bitOffset = 0; bitOffset < 64; bitOffset++ {
   164  			bit = d.ReadBit()   // read first address bit
   165  			bit_c = d.ReadBit() // read second (complementary) address bit
   166  
   167  			if bit == 1 && bit_c == 1 { // no device
   168  				return nil, errNoPresence
   169  			}
   170  
   171  			if bit == 0 && bit_c == 0 { // collision
   172  				if bitOffset == lastFork {
   173  					bit = 1
   174  				}
   175  				if bitOffset < lastFork {
   176  					bit = (lastAddress[bitOffset>>3] >> (bitOffset & 0x07)) & 1
   177  				}
   178  				if bit == 0 {
   179  					lastZero = bitOffset
   180  				}
   181  			}
   182  
   183  			if bit == 0 {
   184  				lastAddress[bitOffset>>3] &= ^(1 << (bitOffset & 0x07))
   185  			} else {
   186  				lastAddress[bitOffset>>3] |= (1 << (bitOffset & 0x07))
   187  			}
   188  			d.WriteBit(bit)
   189  		}
   190  		lastFork = lastZero
   191  		copy(romIDs[romIndex], lastAddress)
   192  		romIndex++
   193  	}
   194  	return romIDs[:romIndex:romIndex], nil
   195  }
   196  
   197  // Crc8 compute a Dallas Semiconductor 8 bit CRC.
   198  func (d Device) Сrc8(buffer []uint8, size int) (crc uint8) {
   199  	// Dow-CRC using polynomial X^8 + X^5 + X^4 + X^0
   200  	// Tiny 2x16 entry CRC table created by Arjen Lentz
   201  	// See http://lentz.com.au/blog/calculating-crc-with-a-tiny-32-entry-lookup-table
   202  	crc8_table := [...]uint8{
   203  		0x00, 0x5E, 0xBC, 0xE2, 0x61, 0x3F, 0xDD, 0x83,
   204  		0xC2, 0x9C, 0x7E, 0x20, 0xA3, 0xFD, 0x1F, 0x41,
   205  		0x00, 0x9D, 0x23, 0xBE, 0x46, 0xDB, 0x65, 0xF8,
   206  		0x8C, 0x11, 0xAF, 0x32, 0xCA, 0x57, 0xE9, 0x74,
   207  	}
   208  	for i := 0; i < size; i++ {
   209  		crc = buffer[i] ^ crc // just re-using crc as intermediate
   210  		crc = crc8_table[crc&0x0f] ^ crc8_table[16+((crc>>4)&0x0f)]
   211  	}
   212  	return crc
   213  }