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 }