diff --git a/adafruit_as726x.py b/adafruit_as726x.py index 94d9e67..2a715c5 100644 --- a/adafruit_as726x.py +++ b/adafruit_as726x.py @@ -92,12 +92,33 @@ _AS726X_NUM_CHANNELS = const(6) +_COLOR_REGS = ( + _AS7262_VIOLET, + _AS7262_BLUE, + _AS7262_GREEN, + _AS7262_YELLOW, + _AS7262_ORANGE, + _AS7262_RED, +) +_COLOR_REGS_CALIBRATED = ( + _AS7262_VIOLET_CALIBRATED, + _AS7262_BLUE_CALIBRATED, + _AS7262_GREEN_CALIBRATED, + _AS7262_YELLOW_CALIBRATED, + _AS7262_ORANGE_CALIBRATED, + _AS7262_RED_CALIBRATED, +) + # pylint: disable=too-many-instance-attributes # pylint: disable=too-many-public-methods -class Adafruit_AS726x: - """AS726x spectral sensor. +# pylint: disable=invalid-name +# pylint: disable=no-else-return +# pylint: disable=inconsistent-return-statements + + +class AS726x: + """AS726x spectral sensor base class. - :param ~busio.I2C i2c_bus: The I2C bus connected to the sensor """ MODE_0 = 0b00 @@ -120,18 +141,16 @@ class Adafruit_AS726x: DRIVER_CURRENT_LIMITS = (12.5, 25, 50, 100) - def __init__(self, i2c_bus): + def __init__(self): self._driver_led = False self._indicator_led = False - self._driver_led_current = Adafruit_AS726x.DRIVER_CURRENT_LIMITS.index(12.5) - self._indicator_led_current = Adafruit_AS726x.INDICATOR_CURRENT_LIMITS.index(1) - self._conversion_mode = Adafruit_AS726x.MODE_2 + self._driver_led_current = AS726x.DRIVER_CURRENT_LIMITS.index(12.5) + self._indicator_led_current = AS726x.INDICATOR_CURRENT_LIMITS.index(1) + self._conversion_mode = AS726x.MODE_2 self._integration_time = 0 - self._gain = Adafruit_AS726x.GAIN.index(1) + self._gain = AS726x.GAIN.index(1) self.buf2 = bytearray(2) - self.i2c_device = I2CDevice(i2c_bus, _AS726X_ADDRESS) - # reset device self._virtual_write(_AS726X_CONTROL_SETUP, 0x80) @@ -148,7 +167,7 @@ def __init__(self, i2c_bus): ) self.integration_time = 140 - self.conversion_mode = Adafruit_AS726x.MODE_2 + self.conversion_mode = AS726x.MODE_2 self.gain = 64 @property @@ -193,14 +212,14 @@ def driver_led_current(self): @driver_led_current.setter def driver_led_current(self, val): - if val not in Adafruit_AS726x.DRIVER_CURRENT_LIMITS: + if val not in AS726x.DRIVER_CURRENT_LIMITS: raise ValueError("Must be 12.5, 25, 50 or 100") if self._driver_led_current == val: return self._driver_led_current = val state = self._virtual_read(_AS726X_LED_CONTROL) state &= ~(0x3 << 4) - state = state | (Adafruit_AS726x.DRIVER_CURRENT_LIMITS.index(val) << 4) + state = state | (AS726x.DRIVER_CURRENT_LIMITS.index(val) << 4) self._virtual_write(_AS726X_LED_CONTROL, state) @property @@ -215,14 +234,14 @@ def indicator_led_current(self): @indicator_led_current.setter def indicator_led_current(self, val): - if val not in Adafruit_AS726x.INDICATOR_CURRENT_LIMITS: + if val not in AS726x.INDICATOR_CURRENT_LIMITS: raise ValueError("Must be 1, 2, 4 or 8") if self._indicator_led_current == val: return self._indicator_led_current = val state = self._virtual_read(_AS726X_LED_CONTROL) state &= ~(0x3 << 1) - state = state | (Adafruit_AS726x.INDICATOR_CURRENT_LIMITS.index(val) << 4) + state = state | (AS726x.INDICATOR_CURRENT_LIMITS.index(val) << 4) self._virtual_write(_AS726X_LED_CONTROL, state) @property @@ -253,14 +272,14 @@ def gain(self): @gain.setter def gain(self, val): - if val not in Adafruit_AS726x.GAIN: + if val not in AS726x.GAIN: raise ValueError("Must be 1, 3.7, 16 or 64") if self._gain == val: return self._gain = val state = self._virtual_read(_AS726X_CONTROL_SETUP) state &= ~(0x3 << 4) - state |= Adafruit_AS726x.GAIN.index(val) << 4 + state |= AS726x.GAIN.index(val) << 4 self._virtual_write(_AS726X_CONTROL_SETUP, state) @property @@ -372,6 +391,23 @@ def raw_red(self): """Raw red (650nm) 16-bit value""" return self.read_channel(_AS7262_RED) + def _virtual_read(self, addr): + raise NotImplementedError("Must be implemented.") + + def _virtual_write(self, addr, value): + raise NotImplementedError("Must be implemented.") + + +class AS726x_I2C(AS726x): + """AS726x spectral sensor via I2C. + + :param ~busio.I2C i2c_bus: The I2C bus connected to the sensor + """ + + def __init__(self, i2c_bus, address=_AS726X_ADDRESS): + self.i2c_device = I2CDevice(i2c_bus, address) + super().__init__() + def _read_u8(self, command): """read a single byte from a specified register""" buf = self.buf2 @@ -428,5 +464,84 @@ def _virtual_write(self, addr, value): self.__write_u8(_AS726X_SLAVE_WRITE_REG, value) +class AS726x_UART(AS726x): + """AS726x spectral sensor via UART. + + :param ~busio.UART uart: The UART connected to the sensor + """ + + def __init__(self, uart): + self._uart = uart + self._uart.baudrate = 115200 + super().__init__() + + def read_channel(self, channel): + """Read an individual sensor channel""" + return self._virtual_read(channel) + + def read_calibrated_value(self, channel): + """Read a calibrated sensor channel""" + return self._virtual_read(channel) + + def _uart_xfer(self, cmd): + self._uart.reset_input_buffer() + cmd += "\n" + self._uart.write(cmd.encode()) + time.sleep(0.1) + if self._uart.in_waiting: + resp = self._uart.read(self._uart.in_waiting) + return resp.rstrip(b" OK\n") + return None + + def _virtual_read(self, addr): + if addr == _AS726X_HW_VERSION: + # just return what is expected + return 0x40 + elif addr == _AS726X_DEVICE_TEMP: + return int(self._uart_xfer("ATTEMP")) + elif addr == _AS726X_LED_CONTROL: + LED_IND = int(self._uart_xfer("ATLED0")) + LED_DRV = int(self._uart_xfer("ATLED1")) + return LED_IND << 3 | LED_DRV + elif addr == _AS726X_CONTROL_SETUP: + GAIN = int(self._uart_xfer("ATGAIN")) + BANK = int(self._uart_xfer("ATTCSMD")) + return GAIN << 4 | BANK << 2 | 1 << 1 + elif addr in _COLOR_REGS: + resp = self._uart_xfer("ATDATA") + resp = resp.decode().split(",") + return int(resp[_COLOR_REGS.index(addr)]) + elif addr in _COLOR_REGS_CALIBRATED: + resp = self._uart_xfer("ATCDATA") + resp = resp.decode().split(",") + return float(resp[_COLOR_REGS_CALIBRATED.index(addr)]) + + def _virtual_write(self, addr, value): + if addr == _AS726X_CONTROL_SETUP: + # check for reset + if (value >> 7) & 0x01: + self._uart.write(b"ATRST\n") + return + # otherwise proceed + GAIN = (value >> 4) & 0x03 + BANK = (value >> 2) & 0x03 + self._uart_xfer("ATGAIN={}".format(GAIN)) + self._uart_xfer("ATTCSMD={}".format(BANK)) + elif addr == _AS726X_LED_CONTROL: + ICL_DRV = (value >> 4) & 0x07 + LED_DRV = 100 if value & 0x08 else 0 + ICL_IND = (value >> 1) & 0x07 + LED_IND = 100 if value & 0x01 else 0 + self._uart_xfer("ATLED0={}".format(LED_IND)) + self._uart_xfer("ATLED1={}".format(LED_DRV)) + self._uart_xfer("ATLEDC={}".format(ICL_DRV << 4 | ICL_IND)) + elif addr == _AS726X_INT_T: + value = int(value / 2.8) + self._uart_xfer("ATINTTIME={}".format(value)) + + # pylint: enable=too-many-instance-attributes # pylint: enable=too-many-public-methods +# pylint: enable=invalid-name +# pylint: enable=no-else-return +# pylint: enable=inconsistent-return-statements diff --git a/examples/as726x_simpletest.py b/examples/as726x_simpletest.py index d91a813..4ed5e95 100644 --- a/examples/as726x_simpletest.py +++ b/examples/as726x_simpletest.py @@ -3,7 +3,11 @@ import board import busio -from adafruit_as726x import Adafruit_AS726x +# for I2C use: +from adafruit_as726x import AS726x_I2C + +# for UART use: +# from adafruit_as726x import AS726x_UART # maximum value for sensor reading max_val = 16000 @@ -16,9 +20,13 @@ def graph_map(x): return min(int(x * max_graph / max_val), max_graph) -# Initialize I2C bus and sensor. +# for I2C use: i2c = busio.I2C(board.SCL, board.SDA) -sensor = Adafruit_AS726x(i2c) +sensor = AS726x_I2C(i2c) + +# for UART use: +# uart = busio.UART(board.TX, board.RX) +# sensor = AS726x_UART(uart) sensor.conversion_mode = sensor.MODE_2