153 lines
5.3 KiB
Python
153 lines
5.3 KiB
Python
# The MIT License (MIT)
|
|
#
|
|
# Copyright (c) 2017 Carter Nelson for adafruit
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
# THE SOFTWARE.
|
|
# pylint: disable=C0103
|
|
"""
|
|
`adafruit_ds2413`
|
|
====================================================
|
|
|
|
CircuitPython driver for the DS2413 one wire 2 channel GPIO breakout.
|
|
|
|
* Author(s): Carter Nelson
|
|
"""
|
|
|
|
__version__ = "0.0.0-auto.0"
|
|
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DS2413.git"
|
|
|
|
from micropython import const
|
|
from adafruit_onewire.device import OneWireDevice
|
|
|
|
_DS2413_ACCESS_READ = b"\xF5"
|
|
_DS2413_ACCESS_WRITE = b"\x5A"
|
|
_DS2413_ACK_SUCCESS = b"\xAA"
|
|
_DS2413_ACK_ERROR = b"\xFF"
|
|
INPUT = const(0)
|
|
OUTPUT = const(1)
|
|
|
|
|
|
class DS2413Pin:
|
|
"""Class which provides interface to single DS2413 GPIO pin."""
|
|
|
|
def __init__(self, number, host, direction=OUTPUT):
|
|
if number not in (0, 1):
|
|
raise ValueError("Incorrect pin number.")
|
|
self._number = number
|
|
self._host = host
|
|
self._mask = 1 << (number * 2)
|
|
self._direction = None # create it, and then...
|
|
self.direction = direction # set it through setter
|
|
|
|
@property
|
|
def direction(self):
|
|
"""The direction of the pin, either INPUT or OUTPUT."""
|
|
return self._direction
|
|
|
|
@direction.setter
|
|
def direction(self, direction):
|
|
if direction not in (INPUT, OUTPUT):
|
|
raise ValueError("Incorrect direction setting.")
|
|
self._direction = OUTPUT
|
|
self.value = False
|
|
self._direction = direction
|
|
|
|
@property
|
|
def value(self):
|
|
"""The pin state if configured as INPUT. The output latch state
|
|
if configured as OUTPUT. True is HIGH/ON, False is LOW/OFF."""
|
|
# return Pin State if configured for INPUT
|
|
# return Latch State if configured for OUTPUT
|
|
# NOTE: logic is re-inverted to make it more normally
|
|
return not self._host.pio_state & (self._mask << self._direction)
|
|
|
|
@value.setter
|
|
def value(self, state):
|
|
# This only makes sense if the pin is configured for OUTPUT.
|
|
if self._direction == INPUT:
|
|
raise RuntimeError("Can't set value when pin is set to input.")
|
|
# We jump through some hoops in order to only set/clear the bit
|
|
# for the channel associated with this pin object.
|
|
current = self._host.pio_state
|
|
# PIOB Output Latch PIOA Output Latch
|
|
new = (current >> 2 & 0x02) | (current >> 1 & 0x01)
|
|
# To switch the output transistor on, the corresponding bit value is 0.
|
|
# To switch the output transistor off (non-conducting) the bit must be 1.
|
|
if state:
|
|
# clear it (transistor = ON)
|
|
new &= ~(1 << self._number)
|
|
else:
|
|
# set it (transistor = OFF)
|
|
new |= 1 << self._number
|
|
self._host.pio_state = new
|
|
|
|
|
|
class DS2413:
|
|
"""Class which provides interface to DS2413 GPIO breakout."""
|
|
|
|
def __init__(self, bus, address):
|
|
if address.family_code == 0x3A:
|
|
self._address = address
|
|
self._device = OneWireDevice(bus, address)
|
|
self._buf = bytearray(3)
|
|
self._IOA = None
|
|
self._IOB = None
|
|
else:
|
|
raise RuntimeError("Incorrect family code in device address.")
|
|
|
|
@property
|
|
def IOA(self):
|
|
"""The pin object for channel A."""
|
|
if self._IOA is None:
|
|
self._IOA = DS2413Pin(0, self)
|
|
return self._IOA
|
|
|
|
@property
|
|
def IOB(self):
|
|
"""The pin object for channel B."""
|
|
if self._IOB is None:
|
|
self._IOB = DS2413Pin(1, self)
|
|
return self._IOB
|
|
|
|
@property
|
|
def pio_state(self):
|
|
"""The state of both PIO channels."""
|
|
return self._read_status()
|
|
|
|
@pio_state.setter
|
|
def pio_state(self, value):
|
|
return self._write_latches(value)
|
|
|
|
def _read_status(self):
|
|
with self._device as dev:
|
|
dev.write(_DS2413_ACCESS_READ)
|
|
dev.readinto(self._buf, end=1)
|
|
return self._buf[0]
|
|
|
|
def _write_latches(self, value):
|
|
# top six bits must be 1
|
|
value |= 0xFC
|
|
self._buf[0] = value
|
|
self._buf[1] = ~value & 0xFF
|
|
with self._device as dev:
|
|
dev.write(_DS2413_ACCESS_WRITE)
|
|
dev.write(self._buf, end=2)
|
|
dev.readinto(self._buf, end=1)
|
|
if not self._buf[0] == ord(_DS2413_ACK_SUCCESS):
|
|
raise RuntimeError("ACK failure.")
|