/ adafruit_ds2413.py
adafruit_ds2413.py
1 # The MIT License (MIT) 2 # 3 # Copyright (c) 2017 Carter Nelson for adafruit 4 # 5 # Permission is hereby granted, free of charge, to any person obtaining a copy 6 # of this software and associated documentation files (the "Software"), to deal 7 # in the Software without restriction, including without limitation the rights 8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 # copies of the Software, and to permit persons to whom the Software is 10 # furnished to do so, subject to the following conditions: 11 # 12 # The above copyright notice and this permission notice shall be included in 13 # all copies or substantial portions of the Software. 14 # 15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 # THE SOFTWARE. 22 # pylint: disable=C0103 23 """ 24 `adafruit_ds2413` 25 ==================================================== 26 27 CircuitPython driver for the DS2413 one wire 2 channel GPIO breakout. 28 29 * Author(s): Carter Nelson 30 """ 31 32 __version__ = "0.0.0-auto.0" 33 __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DS2413.git" 34 35 from micropython import const 36 from adafruit_onewire.device import OneWireDevice 37 38 _DS2413_ACCESS_READ = b"\xF5" 39 _DS2413_ACCESS_WRITE = b"\x5A" 40 _DS2413_ACK_SUCCESS = b"\xAA" 41 _DS2413_ACK_ERROR = b"\xFF" 42 INPUT = const(0) 43 OUTPUT = const(1) 44 45 46 class DS2413Pin: 47 """Class which provides interface to single DS2413 GPIO pin.""" 48 49 def __init__(self, number, host, direction=OUTPUT): 50 if number not in (0, 1): 51 raise ValueError("Incorrect pin number.") 52 self._number = number 53 self._host = host 54 self._mask = 1 << (number * 2) 55 self._direction = None # create it, and then... 56 self.direction = direction # set it through setter 57 58 @property 59 def direction(self): 60 """The direction of the pin, either INPUT or OUTPUT.""" 61 return self._direction 62 63 @direction.setter 64 def direction(self, direction): 65 if direction not in (INPUT, OUTPUT): 66 raise ValueError("Incorrect direction setting.") 67 self._direction = OUTPUT 68 self.value = False 69 self._direction = direction 70 71 @property 72 def value(self): 73 """The pin state if configured as INPUT. The output latch state 74 if configured as OUTPUT. True is HIGH/ON, False is LOW/OFF.""" 75 # return Pin State if configured for INPUT 76 # return Latch State if configured for OUTPUT 77 # NOTE: logic is re-inverted to make it more normally 78 return not self._host.pio_state & (self._mask << self._direction) 79 80 @value.setter 81 def value(self, state): 82 # This only makes sense if the pin is configured for OUTPUT. 83 if self._direction == INPUT: 84 raise RuntimeError("Can't set value when pin is set to input.") 85 # We jump through some hoops in order to only set/clear the bit 86 # for the channel associated with this pin object. 87 current = self._host.pio_state 88 # PIOB Output Latch PIOA Output Latch 89 new = (current >> 2 & 0x02) | (current >> 1 & 0x01) 90 # To switch the output transistor on, the corresponding bit value is 0. 91 # To switch the output transistor off (non-conducting) the bit must be 1. 92 if state: 93 # clear it (transistor = ON) 94 new &= ~(1 << self._number) 95 else: 96 # set it (transistor = OFF) 97 new |= 1 << self._number 98 self._host.pio_state = new 99 100 101 class DS2413: 102 """Class which provides interface to DS2413 GPIO breakout.""" 103 104 def __init__(self, bus, address): 105 if address.family_code == 0x3A: 106 self._address = address 107 self._device = OneWireDevice(bus, address) 108 self._buf = bytearray(3) 109 self._IOA = None 110 self._IOB = None 111 else: 112 raise RuntimeError("Incorrect family code in device address.") 113 114 @property 115 def IOA(self): 116 """The pin object for channel A.""" 117 if self._IOA is None: 118 self._IOA = DS2413Pin(0, self) 119 return self._IOA 120 121 @property 122 def IOB(self): 123 """The pin object for channel B.""" 124 if self._IOB is None: 125 self._IOB = DS2413Pin(1, self) 126 return self._IOB 127 128 @property 129 def pio_state(self): 130 """The state of both PIO channels.""" 131 return self._read_status() 132 133 @pio_state.setter 134 def pio_state(self, value): 135 return self._write_latches(value) 136 137 def _read_status(self): 138 with self._device as dev: 139 dev.write(_DS2413_ACCESS_READ) 140 dev.readinto(self._buf, end=1) 141 return self._buf[0] 142 143 def _write_latches(self, value): 144 # top six bits must be 1 145 value |= 0xFC 146 self._buf[0] = value 147 self._buf[1] = ~value & 0xFF 148 with self._device as dev: 149 dev.write(_DS2413_ACCESS_WRITE) 150 dev.write(self._buf, end=2) 151 dev.readinto(self._buf, end=1) 152 if not self._buf[0] == ord(_DS2413_ACK_SUCCESS): 153 raise RuntimeError("ACK failure.")