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,
    I3cDriveStrength,
    I3cEvent,
    I3cOpenDrainTransferRate,
    I3cPushPullRate,
    I3cTargetResetDefByte,
    I3cTransferDirection,
    SUCCESS,
)
from example_helpers import print_device_info, print_hex_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_10_MHz_DC_40,
            I3cOpenDrainTransferRate.OPEN_DRAIN_400_KHz,
            I2cTransferRate.FAST_MODE,
            I3cDriveStrength.FAST,
        )
        assert_status(status, "i3c_controller_init", (SUCCESS, FW_INTERFACE_ALREADY_INITIALIZED))

        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, pid = device.i3c_ccc_getpid(0x09)
        assert_status(status, "i3c_ccc_getpid")
        assert pid is not None
        print_hex_payload("PID:", pid)

        status, bcr = device.i3c_ccc_getbcr(0x09)
        assert_status(status, "i3c_ccc_getbcr")
        print(f"BCR: {bcr}")

        status, dcr = device.i3c_ccc_getdcr(0x09)
        assert_status(status, "i3c_ccc_getdcr")
        print(f"DCR: {dcr}")

        status, caps = device.i3c_ccc_getcaps(0x08)
        assert_status(status, "i3c_ccc_getcaps")
        assert caps is not None
        print_hex_payload("CAPS:", caps)

        status, mrl = device.i3c_ccc_getmrl(0x09)
        assert_status(status, "i3c_ccc_getmrl(0x09)")
        assert mrl is not None
        print(f"MRL 0x09: {mrl.max_read_length}, IBI length: {mrl.ibi_length}")

        status, _ = device.i3c_ccc_setmrl_broadcast(0x0F03, 0x03)
        assert_status(status, "i3c_ccc_setmrl_broadcast")
        status, mrl = device.i3c_ccc_getmrl(0x08)
        assert_status(status, "i3c_ccc_getmrl(0x08)")
        assert mrl is not None
        print(f"MRL 0x08: {mrl.max_read_length}, IBI length: {mrl.ibi_length}")

        status, mrl = device.i3c_ccc_getmrl(0x09)
        assert_status(status, "i3c_ccc_getmrl(0x09) after broadcast")
        assert mrl is not None
        print(f"MRL 0x09 after broadcast: {mrl.max_read_length}, IBI length: {mrl.ibi_length}")

        status, _ = device.i3c_ccc_setmrl_direct(0x09, 0x0200)
        assert_status(status, "i3c_ccc_setmrl_direct")

        status, mwl = device.i3c_ccc_getmwl(0x09)
        assert_status(status, "i3c_ccc_getmwl(0x09)")
        print(f"MWL 0x09: {mwl}")

        status, _ = device.i3c_ccc_setmwl_broadcast(0x0F03)
        assert_status(status, "i3c_ccc_setmwl_broadcast")
        status, mwl = device.i3c_ccc_getmwl(0x08)
        assert_status(status, "i3c_ccc_getmwl(0x08)")
        print(f"MWL 0x08: {mwl}")

        status, _ = device.i3c_ccc_setmwl_direct(0x08, 0x0200)
        assert_status(status, "i3c_ccc_setmwl_direct")

        status, _ = device.i3c_ccc_disec_broadcast(I3cEvent.IBI | I3cEvent.CR | I3cEvent.HJ)
        assert_status(status, "i3c_ccc_disec_broadcast")
        status, _ = device.i3c_ccc_disec_direct(0x09, I3cEvent.CR | I3cEvent.HJ)
        assert_status(status, "i3c_ccc_disec_direct")
        status, _ = device.i3c_ccc_enec_broadcast(I3cEvent.IBI | I3cEvent.CR | I3cEvent.HJ)
        assert_status(status, "i3c_ccc_enec_broadcast")
        status, _ = device.i3c_ccc_enec_direct(0x09, I3cEvent.CR | I3cEvent.HJ)
        assert_status(status, "i3c_ccc_enec_direct")

        status, out_value = device.i3c_ccc_rstact_direct(
            0x08,
            I3cTargetResetDefByte.NO_RESET,
            I3cTransferDirection.READ,
        )
        assert_status(status, "i3c_ccc_rstact_direct(read)")
        print(f"RSTACT read value: {out_value}")

        status, _ = device.i3c_ccc_rstact_broadcast(I3cTargetResetDefByte.NO_RESET)
        assert_status(status, "i3c_ccc_rstact_broadcast")

        status, _ = device.i3c_ccc_rstact_direct(
            0x09,
            I3cTargetResetDefByte.RESET_WHOLE_TARGET,
            I3cTransferDirection.WRITE,
        )
        assert_status(status, "i3c_ccc_rstact_direct(write)")

        status, _ = device.i3c_target_reset_pattern()
        assert_status(status, "i3c_target_reset_pattern")
        status, _ = device.i3c_hdr_exit_pattern()
        assert_status(status, "i3c_hdr_exit_pattern")


if __name__ == "__main__":
    main()
