from __future__ import annotations

import sys
from pathlib import Path


ROOT = next(parent for parent in Path(__file__).resolve().parents if (parent / "cosmic_driver").is_dir())
sys.path.insert(0, str(ROOT))

from cosmic_driver import (
    CosmicPySDK,
    FW_INTERFACE_ALREADY_INITIALIZED,
    I2cTransferRate,
    I3cBcr,
    I3cDriveStrength,
    I3cOpenDrainTransferRate,
    I3cPushPullRate,
    I3cTargetConfiguration,
    I3cTargetInfo,
    I3cTransferFlags,
    SUCCESS,
)
from example_helpers import print_device_info, print_payload, print_target_device_table, assert_status


def main() -> None:
    with CosmicPySDK(timeout_ms=2000) as device:
        if not device.open():
            raise RuntimeError("Failed to connect to a Binho device.")

        status, info = device.get_device_info()
        assert_status(status, "get_device_info")
        assert info is not None
        print_device_info(info)

        status, _ = device.i3c_set_bus_voltage(3300)
        assert_status(status, "i3c_set_bus_voltage")

        status, _ = device.i3c_controller_init(
            I3cPushPullRate.PUSH_PULL_5_MHz_DC_50,
            I3cOpenDrainTransferRate.OPEN_DRAIN_400_KHz,
            I2cTransferRate.FAST_MODE,
            I3cDriveStrength.FAST,
        )
        assert_status(status, "i3c_controller_init", (SUCCESS, FW_INTERFACE_ALREADY_INITIALIZED))

        status, _ = device.i3c_set_parameters(
            I3cPushPullRate.PUSH_PULL_2_5_MHz_DC_25,
            I3cOpenDrainTransferRate.OPEN_DRAIN_100_KHz,
            I2cTransferRate.STANDARD_MODE,
            I3cDriveStrength.STANDARD,
        )
        assert_status(status, "i3c_set_parameters")

        status, table = device.i3c_get_device_table()
        assert_status(status, "i3c_get_device_table(before init)")
        assert table is not None
        print_target_device_table(table)

        status, _ = device.i3c_init_bus()
        assert_status(status, "i3c_init_bus()")
        status, table = device.i3c_get_device_table()
        assert_status(status, "i3c_get_device_table(after discovery)")
        assert table is not None
        print_target_device_table(table)

        status, _ = device.i3c_reset_bus()
        assert_status(status, "i3c_reset_bus")
        status, table = device.i3c_get_device_table()
        assert_status(status, "i3c_get_device_table(after reset)")
        assert table is not None
        print_target_device_table(table)

        targets = [
            I3cTargetInfo(
                static_address=0x50,
                dynamic_address=0x00,
                pid=[0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
                bcr=I3cBcr.from_byte(0x00),
                dcr=0x00,
                mwl=0x0000,
                mrl=0x0000,
                max_ibi_payload_length=0x00,
                configuration=I3cTargetConfiguration(
                    target_type=1,
                    ibi_request=False,
                    cr_request=False,
                    daa_use_setdasa=False,
                    daa_use_setaasa=False,
                    daa_use_entdaa=False,
                    ibi_timestamp_enable=False,
                    pending_read_capability=False,
                ),
            ),
            I3cTargetInfo(
                static_address=0x6B,
                dynamic_address=0x0A,
                pid=[0x02, 0x08, 0x00, 0x70, 0x92, 0x0B],
                bcr=I3cBcr.from_byte(0x07),
                dcr=0x44,
                mwl=0x0000,
                mrl=0x0000,
                max_ibi_payload_length=0x00,
                configuration=I3cTargetConfiguration(
                    target_type=0,
                    ibi_request=True,
                    cr_request=False,
                    daa_use_setdasa=True,
                    daa_use_setaasa=False,
                    daa_use_entdaa=False,
                    ibi_timestamp_enable=False,
                    pending_read_capability=False,
                ),
            ),
            I3cTargetInfo(
                static_address=0x69,
                dynamic_address=0x0B,
                pid=[0x07, 0x70, 0x10, 0x43, 0x10, 0x00],
                bcr=I3cBcr.from_byte(0x00),
                dcr=0xEF,
                mwl=0x0000,
                mrl=0x0000,
                max_ibi_payload_length=0x00,
                configuration=I3cTargetConfiguration(
                    target_type=0,
                    ibi_request=True,
                    cr_request=True,
                    daa_use_setdasa=False,
                    daa_use_setaasa=False,
                    daa_use_entdaa=True,
                    ibi_timestamp_enable=False,
                    pending_read_capability=False,
                ),
            ),
        ]

        status, _ = device.i3c_init_bus(targets)
        assert_status(status, "i3c_init_bus(targets)")
        status, table = device.i3c_get_device_table()
        assert_status(status, "i3c_get_device_table(after static init)")
        assert table is not None
        print_target_device_table(table)

        configuration = I3cTargetConfiguration(
            target_type=0,
            ibi_request=True,
            cr_request=False,
            daa_use_setdasa=True,
            daa_use_setaasa=False,
            daa_use_entdaa=False,
            ibi_timestamp_enable=True,
            pending_read_capability=False,
        )
        status, _ = device.i3c_set_target_device_configuration(0x08, configuration)
        assert_status(status, "i3c_set_target_device_configuration")
        status, table = device.i3c_get_device_table()
        assert_status(status, "i3c_get_device_table(after configuration update)")
        assert table is not None
        print_target_device_table(table)

        subaddress = [0x00, 0x05]
        data = [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12]
        status, _ = device.i3c_legacy_i2c_write(0x50, subaddress, data, I3cTransferFlags.I3C_XFER_NONE)
        assert_status(status, "i3c_legacy_i2c_write")
        status, _ = device.i3c_legacy_i2c_write(0x50, subaddress, [], I3cTransferFlags.I3C_XFER_NONE)
        assert_status(status, "i3c_legacy_i2c_write(pointer reset)")
        status, out_data = device.i3c_legacy_i2c_read(0x50, subaddress, 11, I3cTransferFlags.I3C_XFER_NONE)
        assert_status(status, "i3c_legacy_i2c_read")
        assert out_data is not None
        print_payload("Legacy I2C data:", out_data)

        subaddress = [0x05]
        status, _ = device.i3c_sdr_write(0x08, subaddress, data, I3cTransferFlags.I3C_XFER_NONE)
        assert_status(status, "i3c_sdr_write")
        status, out_data = device.i3c_sdr_read(0x08, subaddress, 11, I3cTransferFlags.I3C_XFER_NONE)
        assert_status(status, "i3c_sdr_read")
        assert out_data is not None
        print_payload("SDR data:", out_data)


if __name__ == "__main__":
    main()
