# Path: luma/core/interface/serial.py
# def ftdi_spi(device='ftdi://::/1', bus_speed_hz=12000000, gpio_CS=3, gpio_DC=5, gpio_RST=6,
#         reset_hold_time=0, reset_release_time=0):
#     """
#     Bridges an `SPI <https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus>`_
#     (Serial Peripheral Interface) bus over an FTDI USB device to provide :py:func:`data` and
#     :py:func:`command` methods.
# 
#     :param device: A URI describing the location of the FTDI device. If ``None`` is
#         supplied (default), ``ftdi://::/1`` is used. See `pyftdi <https://pypi.org/project/pyftdi>`_
#         for further details of the naming scheme used.
#     :type device: string
#     :param bus_speed_hz: SPI bus speed, defaults to 12MHz.
#     :type bus_speed_hz: int
#     :param gpio_CS: The ADx pin to connect chip select (CS) to (defaults to 3).
#     :type gpio_CS: int
#     :param gpio_DC: The ADx pin to connect data/command select (DC) to (defaults to 5).
#     :type gpio_DC: int
#     :param gpio_RST: The ADx pin to connect reset (RES / RST) to (defaults to 6).
#     :type gpio_RST: int
#         :param reset_hold_time: The number of seconds to hold reset active. Some devices may require
#         a duration of 100ms or more to fully reset the display (default:0)
#     :type reset_hold_time: float
#     :param reset_release_time: The number of seconds to delay afer reset. Some devices may require
#         a duration of 150ms or more after reset was triggered before the device can accept the
#         initialization sequence (default:0)
#     :type reset_release_time: float
# 
#     .. versionadded:: 1.9.0
#     """
#     from pyftdi.spi import SpiController
# 
#     controller = SpiController(cs_count=1)
#     controller.configure(device)
# 
#     slave = controller.get_port(cs=gpio_CS - 3, freq=bus_speed_hz, mode=0)
#     gpio = controller.get_gpio()
# 
#     # RESET and DC configured as outputs
#     pins = _ftdi_pin(gpio_RST) | _ftdi_pin(gpio_DC)
#     gpio.set_direction(pins, pins & 0xFF)
# 
#     serial = spi(
#         __FTDI_WRAPPER_SPI(controller, slave),
#         __FTDI_WRAPPER_GPIO(gpio),
#         gpio_DC=gpio_DC,
#         gpio_RST=gpio_RST,
#         reset_hold_time=reset_hold_time,
#         reset_release_time=reset_release_time)
#     serial._managed = True
#     return serial


from unittest.mock import Mock, call, patch
from luma.core.interface.serial import ftdi_spi
from helpers import fib, assert_only_cleans_whats_setup
    instance.get_gpio.assert_called_with()
    gpio.set_direction.assert_called_with(0x60, 0x60)


@patch('pyftdi.spi.SpiController')
def test_command(mock_controller):
    cmds = [3, 1, 4, 2]
    gpio = Mock()
    port = Mock()
    instance = Mock()
    instance.get_port = Mock(return_value=port)
    instance.get_gpio = Mock(return_value=gpio)
    mock_controller.side_effect = [instance]

    serial = ftdi_spi(device='ftdi://dummy', bus_speed_hz=16000000, gpio_CS=3, gpio_DC=5, gpio_RST=6)
    serial.command(*cmds)
    gpio.write.assert_has_calls([call(0x00), call(0x40), call(0x40)])
    port.write.assert_called_once_with(cmds)


@patch('pyftdi.spi.SpiController')
def test_data(mock_controller):
    data = list(fib(100))
    gpio = Mock()
    port = Mock()
    instance = Mock()
    instance.get_port = Mock(return_value=port)
    instance.get_gpio = Mock(return_value=gpio)
    mock_controller.side_effect = [instance]


# Path: luma/core/interface/serial.py
# def ftdi_spi(device='ftdi://::/1', bus_speed_hz=12000000, gpio_CS=3, gpio_DC=5, gpio_RST=6,
#         reset_hold_time=0, reset_release_time=0):
#     """
#     Bridges an `SPI <https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus>`_
#     (Serial Peripheral Interface) bus over an FTDI USB device to provide :py:func:`data` and
#     :py:func:`command` methods.
# 
#     :param device: A URI describing the location of the FTDI device. If ``None`` is
#         supplied (default), ``ftdi://::/1`` is used. See `pyftdi <https://pypi.org/project/pyftdi>`_
#         for further details of the naming scheme used.
#     :type device: string
#     :param bus_speed_hz: SPI bus speed, defaults to 12MHz.
#     :type bus_speed_hz: int
#     :param gpio_CS: The ADx pin to connect chip select (CS) to (defaults to 3).
#     :type gpio_CS: int
#     :param gpio_DC: The ADx pin to connect data/command select (DC) to (defaults to 5).
#     :type gpio_DC: int
#     :param gpio_RST: The ADx pin to connect reset (RES / RST) to (defaults to 6).
#     :type gpio_RST: int
#         :param reset_hold_time: The number of seconds to hold reset active. Some devices may require
#         a duration of 100ms or more to fully reset the display (default:0)
#     :type reset_hold_time: float
#     :param reset_release_time: The number of seconds to delay afer reset. Some devices may require
#         a duration of 150ms or more after reset was triggered before the device can accept the
#         initialization sequence (default:0)
#     :type reset_release_time: float
# 
#     .. versionadded:: 1.9.0
#     """
#     from pyftdi.spi import SpiController
# 
#     controller = SpiController(cs_count=1)
#     controller.configure(device)
# 
#     slave = controller.get_port(cs=gpio_CS - 3, freq=bus_speed_hz, mode=0)
#     gpio = controller.get_gpio()
# 
#     # RESET and DC configured as outputs
#     pins = _ftdi_pin(gpio_RST) | _ftdi_pin(gpio_DC)
#     gpio.set_direction(pins, pins & 0xFF)
# 
#     serial = spi(
#         __FTDI_WRAPPER_SPI(controller, slave),
#         __FTDI_WRAPPER_GPIO(gpio),
#         gpio_DC=gpio_DC,
#         gpio_RST=gpio_RST,
#         reset_hold_time=reset_hold_time,
#         reset_release_time=reset_release_time)
#     serial._managed = True
#     return serial


# Path: tests/test_ftdi_spi.py
from unittest.mock import Mock, call, patch
from luma.core.interface.serial import ftdi_spi
from helpers import fib, assert_only_cleans_whats_setup

    instance.get_gpio.assert_called_with()
    gpio.set_direction.assert_called_with(0x60, 0x60)


@patch('pyftdi.spi.SpiController')
def test_command(mock_controller):
    cmds = [3, 1, 4, 2]
    gpio = Mock()
    port = Mock()
    instance = Mock()
    instance.get_port = Mock(return_value=port)
    instance.get_gpio = Mock(return_value=gpio)
    mock_controller.side_effect = [instance]

    serial = ftdi_spi(device='ftdi://dummy', bus_speed_hz=16000000, gpio_CS=3, gpio_DC=5, gpio_RST=6)
    serial.command(*cmds)
    gpio.write.assert_has_calls([call(0x00), call(0x40), call(0x40)])
    port.write.assert_called_once_with(cmds)


@patch('pyftdi.spi.SpiController')
def test_data(mock_controller):
    data = list(fib(100))
    gpio = Mock()
    port = Mock()
    instance = Mock()
    instance.get_port = Mock(return_value=port)
    instance.get_gpio = Mock(return_value=gpio)
    mock_controller.side_effect = [instance]


    serial = ftdi_spi(device='ftdi://dummy', bus_speed_hz=16000000, gpio_CS=3, gpio_DC=5, gpio_RST=6)