# SPDX-License-Identifier: LGPL-3.0-or-later
# Copyright (C) 2020 Daniel Thompson

"""Hynitron CST816S touch contoller driver
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""

import array
import time
from machine import Pin

class CST816S:
    """Hynitron CST816S I2C touch controller driver.

    .. automethod:: __init__
    """

    def __init__(self, bus, intr, rst, schedule=None):
        """Specify the bus used by the touch controller.

        :param machine.I2C bus: I2C bus for the CST816S.
        """
        self.i2c = bus
        self.tp_int = intr
        self.tp_rst = rst
        self.schedule = schedule
        self.dbuf = bytearray(6)
        self.event = array.array('H', (0, 0, 0))

        self._reset()
        self.tp_int.irq(trigger=Pin.IRQ_FALLING, handler=self.get_touch_data)

    def _reset(self):
        self.tp_rst.off()
        time.sleep_ms(5)
        self.tp_rst.on()
        time.sleep_ms(50)

    def version(self):
        self.wake()
        v = self.i2c.readfrom_mem(21, 0xa6, 4)
        self.sleep()
        return v

    def get_touch_data(self, pin_obj):
        """Receive a touch event by interrupt.

        Check for a pending touch event and, if an event is pending,
        prepare it ready to go in the event queue.
        """
        dbuf = self.dbuf
        event = self.event

        try:
            self.i2c.readfrom_mem_into(21, 1, dbuf)
        except OSError:
            return None

        event[0] = dbuf[0] # event
        event[1] = ((dbuf[2] & 0xf) << 8) + dbuf[3] # x coord
        event[2] = ((dbuf[4] & 0xf) << 8) + dbuf[5] # y coord

        if self.schedule:
            self.schedule(self)

    def get_event(self):
        """Receive a touch event.

        Check for a pending touch event and, if an event is pending,
        prepare it ready to go in the event queue.

        :return: An event record if an event is received, None otherwise.
        """
        if self.event[0] == 0:
            return None

        return self.event

    def reset_touch_data(self):
        """Reset touch data.

        Reset touch data, call this function after processing an event.
        """
        self.event[0] = 0

    def wake(self):
        """Wake up touch controller chip.

        Just reset the chip in order to wake it up
        """
        self._reset()
        self.event[0] = 0

    def sleep(self):
        """Put touch controller chip on sleep mode to save power.
        """
        # Before we can send the sleep command we have to reset the
        # panel to get the I2C hardware running again...
        self._reset()
        try:
            self.i2c.writeto_mem(21, 0xa5, b'\x03')
        except:
            # If we can't power down then let's just put it in reset instead
            self.tp_rst.off()

        # Ensure get_event() cannot return anything
        self.event[0] = 0