#include "mgos.h"
#include "tests_autogen.h"
#include <fcntl.h>
#include <math.h>
#include <sys/ioctl.h>

static bool i2c_dumpregs(struct mgos_i2c *i2c, uint8_t i2caddr);
static void i2c_scanner(struct mgos_i2c *i2c, bool dumpregs);
static int usage(void);

static int usage(void) {
  printf("Flags: [-i <i2cnusnr>] [-s] [-d]\n");
  printf("  -i: Select the I2C bus number, ie '7' for /dev/i2c-7\n");
  printf("  -s: Scan the I2C bus upon startup\n");
  printf("  -d: Dump byte-registers on each found I2C device\n");
  return -1;
}

void i2c_scanner(struct mgos_i2c *i2c, bool dumpregs) {
  int i;

  if (!i2c) {
    LOG(LL_ERROR, ("No global I2C bus configured"));
    return;
  }

  for (i = 0x3; i < 0x78; i++) {
    bool ret;
    ret = mgos_i2c_read(i2c, i, NULL, 0, true);
    if (ret) {
      LOG(LL_INFO, ("Found device at I2C address 0x%02x", i));
      if (dumpregs) {
        i2c_dumpregs(i2c, i);
      }
    }
  }
}

static bool i2c_dumpregs(struct mgos_i2c *i2c, uint8_t i2caddr) {
  uint16_t reg;
  int      value;

  for (reg = 0; reg < 256; reg++) {
    value = mgos_i2c_read_reg_b(i2c, i2caddr, reg);
    if (value < 0) {
      printf(" XX");
    }else {
      printf(" %02x", value);
    }
    if (reg % 16 == 15) {
      printf("\n");
    }
  }
  printf("\n");
  return true;
}

int main(int argc, char **argv, char **environ) {
  int scan   = 0;
  int dump   = 0;
  int i2cbus = 1;
  int index;
  int c;

  opterr = 0;

  while ((c = getopt(argc, argv, "i:sdh")) != -1) {
    switch (c) {
    case 's':
      scan = 1;
      break;

    case 'd':
      dump = 1;
      break;

    case 'i':
      i2cbus = atoi(optarg);
      break;

    case '?':
      if (optopt == 'i') {
        LOG(LL_ERROR, ("Option -%c requires an argument", optopt));
      } else if (isprint(optopt)) {
        LOG(LL_ERROR, ("Unknown option `-%c'", optopt));
      } else{
        LOG(LL_ERROR, ("Unknown option character `\\x%x'", optopt));
      }
      return usage();

    default:
      return usage();
    }
  }

  for (index = optind; index < argc; index++) {
    LOG(LL_WARN, ("Non-option argument %s, skipping", argv[index]));
  }

  struct mgos_i2c *i2c = NULL;

  if (!mgos_i2c_open(i2cbus)) {
    LOG(LL_ERROR, ("Cannot open I2C bus %u", i2cbus));
    return -1;
  }

  if (!(i2c = mgos_i2c_get_global())) {
    LOG(LL_ERROR, ("Cannot open I2C bus"));
    return -2;
  }

  if (scan) {
    i2c_scanner(i2c, dump);
  }

  tests_create();
  tests_run();
  tests_destroy();

  return 0;
  (void)argc;
  (void)argv;
  (void)environ;
}
