/**
 * @file example.c
 * @brief I3C HDR-DDR Example with Binho Supernova (Blocking C API)
 *
 * This example demonstrates I3C HDR-DDR transfers using:
 * - Binho Supernova
 * - Binho mikroBUS Adapter Board
 * - MikroE 6DOF IMU 14 Click
 *
 * Workflow:
 * 1. Connect to the adapter and print host device information.
 * 2. Set I3C VTARG to 3.3 V, initialize I3C controller, and initialize I3C bus.
 * 3. Execute one HDR-DDR write transaction.
 * 4. Reset the target internal register pointer with an SDR write.
 * 5. Execute one HDR-DDR read transaction and print the received bytes.
 */

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>

#include "CosmicSDK_API_c.h"

#define CHECK_RESULT(op, code) \
  do { \
    if ((code) != SUCCESS) { \
      printf("%s failed. ERROR CODE: %u\n", (op), (unsigned)(code)); \
      exit_code = 1; \
      goto cleanup; \
    } \
  } while (0)

int main(void) {
  int exit_code = 0;
  bool connected = false;
  CosmicSDK_Handle* handle_ptr = NULL;
  uint16_t result_code = SUCCESS;

  printf("Started C example\n");

  // Step 1: Connect to adapter and print device information.
  handle_ptr = CosmicSDK_Create(2000);
  if (handle_ptr == NULL) {
    printf("Could not create CosmicSDK handle\n");
    return 1;
  }

  if (!CosmicSDK_Connect(handle_ptr, NULL)) {
    printf("Could not connect to device\n");
    exit_code = 1;
    goto cleanup;
  }
  connected = true;

  C_DeviceInfo device_info;
  result_code = CosmicSDK_GetDeviceInfo(handle_ptr, &device_info);
  CHECK_RESULT("GetDeviceInfo", result_code);
  printf("Manufacturer: %.*s\n", (int)device_info.manufacturerLength, device_info.manufacturer);
  printf("Product Name: %.*s\n", (int)device_info.productNameLength, device_info.productName);
  printf("Serial Number: %.*s\n", (int)device_info.serialNumberLength, device_info.serialNumber);
  printf("Firmware Version: %.*s\n", (int)device_info.fwVersionLength, device_info.fwVersion);
  printf("Hardware Version: %.*s\n", (int)device_info.hwVersionLength, device_info.hwVersion);

  // Step 2: Set VTARG, initialize I3C controller, and initialize I3C bus.
  result_code = CosmicSDK_I3cSetBusVoltage(handle_ptr, 3300);
  CHECK_RESULT("I3cSetBusVoltage", result_code);

  result_code = CosmicSDK_I3cControllerInit(handle_ptr, PUSH_PULL_3_125_MHz_DC_31_25,
                                            OPEN_DRAIN_1_MHz, FAST_MODE, FAST);
  if (result_code != SUCCESS && result_code != FW_INTERFACE_ALREADY_INITIALIZED) {
    CHECK_RESULT("I3cControllerInit", result_code);
  }

  result_code = CosmicSDK_I3cInitBus(handle_ptr, NULL, 0);
  CHECK_RESULT("I3cInitBus", result_code);

  // Step 3: HDR-DDR write.
  uint8_t data_in[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  result_code = CosmicSDK_I3cHdrDdrWrite(handle_ptr, 0x08, 0x04, data_in, 10);
  CHECK_RESULT("I3cHdrDdrWrite", result_code);

  // Step 4: Reset target internal register pointer with SDR write.
  uint8_t register_addr[1] = {0x00};
  result_code =
      CosmicSDK_I3cSdrWrite(handle_ptr, 0x08, register_addr, 1, NULL, 0, I3C_XFER_START_WITH_7E);
  CHECK_RESULT("I3cSdrWrite", result_code);

  // Step 5: HDR-DDR read and print output.
  uint8_t data_out[20] = {0};
  uint16_t out_data_length;
  result_code = CosmicSDK_I3cHdrDdrRead(handle_ptr, 0x08, 0x80, 10, &out_data_length, data_out);
  CHECK_RESULT("I3cHdrDdrRead", result_code);

  printf("HDR-DDR read data: ");
  for (uint8_t i = 0; i < out_data_length; ++i) {
    printf("%u ", data_out[i]);
  }
  printf("\n");

cleanup:
  if (connected) {
    CosmicSDK_Disconnect(handle_ptr);
  }
  CosmicSDK_Destroy(handle_ptr);
  return exit_code;
}

