package com.binho.cosmicsdk.examples.i3c.basic;

import com.binho.cosmicsdk.CosmicSdk;
import com.binho.cosmicsdk.ResultCodes;
import com.binho.cosmicsdk.Types.I2cTransferRate;
import com.binho.cosmicsdk.Types.I3cBcr;
import com.binho.cosmicsdk.Types.I3cDriveStrength;
import com.binho.cosmicsdk.Types.I3cOpenDrainTransferRate;
import com.binho.cosmicsdk.Types.I3cPushPullRate;
import com.binho.cosmicsdk.Types.I3cTargetConfiguration;
import com.binho.cosmicsdk.Types.I3cTargetInfo;
import com.binho.cosmicsdk.Types.I3cTransferFlags;

import java.util.List;

import static com.binho.cosmicsdk.examples.ExampleHelpers.assertStatus;
import static com.binho.cosmicsdk.examples.ExampleHelpers.printDeviceInfo;
import static com.binho.cosmicsdk.examples.ExampleHelpers.printPayload;
import static com.binho.cosmicsdk.examples.ExampleHelpers.printTargetDeviceTable;

public final class I3cBasicExample {
    private I3cBasicExample() {
    }

    public static void main(String[] args) {
        try (CosmicSdk sdk = new CosmicSdk(2000)) {
            if (!sdk.connect()) {
                throw new IllegalStateException("Failed to connect to a Binho device.");
            }

            var infoResult = sdk.getDeviceInfo();
            assertStatus(infoResult.status(), "getDeviceInfo");
            printDeviceInfo(infoResult.value());

            assertStatus(sdk.i3cSetBusVoltage(3300), "i3cSetBusVoltage");
            assertStatus(
                    sdk.i3cControllerInit(
                            I3cPushPullRate.PUSH_PULL_5_MHz_DC_50,
                            I3cOpenDrainTransferRate.OPEN_DRAIN_400_KHz,
                            I2cTransferRate.FAST_MODE,
                            I3cDriveStrength.FAST
                    ),
                    "i3cControllerInit",
                    ResultCodes.SUCCESS,
                    ResultCodes.FW_INTERFACE_ALREADY_INITIALIZED
            );
            assertStatus(
                    sdk.i3cSetParameters(
                            I3cPushPullRate.PUSH_PULL_2_5_MHz_DC_25,
                            I3cOpenDrainTransferRate.OPEN_DRAIN_100_KHz,
                            I2cTransferRate.STANDARD_MODE,
                            I3cDriveStrength.STANDARD
                    ),
                    "i3cSetParameters"
            );

            var tableBefore = sdk.i3cGetDeviceTable();
            assertStatus(tableBefore.status(), "i3cGetDeviceTable(before init)");
            printTargetDeviceTable(tableBefore.value());

            assertStatus(sdk.i3cInitBus(), "i3cInitBus");
            var tableAfter = sdk.i3cGetDeviceTable();
            assertStatus(tableAfter.status(), "i3cGetDeviceTable(after discovery)");
            printTargetDeviceTable(tableAfter.value());

            assertStatus(sdk.i3cResetBus(), "i3cResetBus");

            List<I3cTargetInfo> targets = List.of(
                    new I3cTargetInfo(0x50, 0x00, new byte[]{0, 0, 0, 0, 0, 0}, I3cBcr.fromByte((byte) 0x00), 0x00, 0, 0, 0, new I3cTargetConfiguration(1, false, false, false, false, false, false, false)),
                    new I3cTargetInfo(0x6B, 0x0A, new byte[]{0x02, 0x08, 0x00, 0x70, (byte) 0x92, 0x0B}, I3cBcr.fromByte((byte) 0x07), 0x44, 0, 0, 0, new I3cTargetConfiguration(0, true, false, true, false, false, false, false)),
                    new I3cTargetInfo(0x69, 0x0B, new byte[]{0x07, 0x70, 0x10, 0x43, 0x10, 0x00}, I3cBcr.fromByte((byte) 0x00), 0xEF, 0, 0, 0, new I3cTargetConfiguration(0, true, true, false, false, true, false, false))
            );
            assertStatus(sdk.i3cInitBus(targets), "i3cInitBus(targets)");
            assertStatus(sdk.i3cSetTargetDeviceConfiguration(0x08, new I3cTargetConfiguration(0, true, false, true, false, false, true, false)), "i3cSetTargetDeviceConfiguration");

            assertStatus(sdk.i3cLegacyI2cWrite(0x50, new byte[]{0x00, 0x05}, new byte[]{1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12}, I3cTransferFlags.I3C_XFER_NONE), "i3cLegacyI2cWrite");
            assertStatus(sdk.i3cLegacyI2cWrite(0x50, new byte[]{0x00, 0x05}, new byte[0], I3cTransferFlags.I3C_XFER_NONE), "i3cLegacyI2cWrite(pointer reset)");
            var legacyRead = sdk.i3cLegacyI2cRead(0x50, new byte[]{0x00, 0x05}, 11, I3cTransferFlags.I3C_XFER_NONE);
            assertStatus(legacyRead.status(), "i3cLegacyI2cRead");
            printPayload("Legacy I2C data:", legacyRead.value());

            assertStatus(sdk.i3cSdrWrite(0x08, new byte[]{0x05}, new byte[]{1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12}, I3cTransferFlags.I3C_XFER_NONE), "i3cSdrWrite");
            var sdrRead = sdk.i3cSdrRead(0x08, new byte[]{0x05}, 11, I3cTransferFlags.I3C_XFER_NONE);
            assertStatus(sdrRead.status(), "i3cSdrRead");
            printPayload("SDR data:", sdrRead.value());
        }
    }
}
