#define TRISTAR_IIC_BUS 0
#define CBTL1610_R 0x35
#define CBTL1610_W 0x34

void (*task_sleep)(uint64_t delay) = TARGET_BASEADDR + 0x1FFDC;
int (*iic_read)(int iic, uint8_t address, const void *send_data, size_t send_len, void *data, size_t len, uint8_t fmt) = TARGET_BASEADDR + 0xA008;
int (*iic_write)(int iic, uint8_t address, const void *data, size_t len) = TARGET_BASEADDR + 0xA168;
int (*tristar_write)(uint8_t reg, uint8_t value) = TARGET_BASEADDR + 0xD644;
int (*tristar_read)(uint8_t reg, uint8_t *data) = TARGET_BASEADDR + 0xD604;

void do_tristar(int argc, struct cmd_arg *args) {
	if (argc == 2) {
		if (strcmp(args[1].str, "prov") == 0) {
			uint8_t data = 0;

			if (tristar_read(0x11, &data) != 0) {
				printf_("unable to read configuration status (1)");
				return;
			}

			data |= 0x8;

			if (tristar_write(0x11, data) != 0) {
				printf_("unable to select configuration bank");
				return;
			}

			task_sleep(100000);

			if (tristar_read(0x11, &data) != 0) {
				printf_("unable to retrieve provisioning state");
				return;
			}

			if (!(data & 0x80)) {
				printf_("provisioning state not valid\n");
				return;
			}

			uint8_t step1 = (data >> 4) & 1;
			uint8_t step2 = (data >> 5) & 1;
			uint8_t step3 = (data >> 6) & 1;

			if (step1 && step2 && step3) {
				printf_("Provisioned\n");
			} else if (step1 | step2 | step3) {
				printf_("Partially provisioned\n");
			} else {
				printf_("Not provisioned\n");
			}

			if (tristar_read(0x11, &data) != 0) {
				printf_("unable to read configuration status (2)\n");
				return;
			}

			data &= 0xF7;

			if (tristar_write(0x11, data) != 0) {
				printf_("unable to de-select configuration bank\n");
				return;
			}

			return;
		}

		if (strcmp(args[1].str, "esn") == 0) {
			uint8_t data = 0;

			if (tristar_read(0x11, &data) != 0) {
				printf_("unable to read configuration status (1)\n");
				return;
			}

			if (data & 0x8) {
				data &= 0xF7;

				if (tristar_write(0x11, data) != 0) {
					printf_("unable to de-select configuration bank\n");
					return;
				}
			}

			data = 0;

			if (tristar_write(0x21, data) != 0) {
				printf_("unable to do something (1)\n");
				return;
			}

			uint64_t smth = 0;

			if (iic_write(TRISTAR_IIC_BUS, CBTL1610_W, &smth, sizeof(smth)) != 0) {
				printf_("unable to do something (2)\n");
				return;
			}

			if (tristar_read(0x11, &data) != 0) {
				printf_("unable to read configuration status (2)\n");
				return;
			}

			data |= 1;

			if (tristar_write(0x11, data) != 0) {
				printf_("unable to do something (3)\n");
				return;
			}

			if (tristar_read(0x11, &data) != 0) {
				printf_("unable to read configuration status (3)\n");
				return;
			}

			while (!(data & 2)) {
				task_sleep(100000);
				if (tristar_read(0x11, &data) != 0) {
					printf_("unable to read configuration status (4)\n");
					return;
				}
			}

			if (tristar_read(0x11, &data) != 0) {
				printf_("unable to read configuration status (5)\n");
				return;
			}

			if (!(data & 1)) {
				printf_("some error\n");
				return;
			}

			data &= 0xF4;

			if (tristar_write(0x11, data) != 0) {
				printf_("unable to do something (4)\n");
				return;
			}

			uint8_t buffer[16];

			uint8_t reg = 0x4F;

			if (iic_read(TRISTAR_IIC_BUS, CBTL1610_R, &reg, sizeof(reg), &buffer, sizeof(buffer), 1) != 0) {
				printf_("unable to do something (5)\n");
				return;
			}

			printf_("ESN: ");

			for (int i = 0; i < 8; i++) {
				printf_("%02X", buffer[8 + i]);
			}

			printf_("\n");

			return;
		}
	}

	printf_("lina tristar prov\n");
	printf_("lina tristar esn\n");
}