/*
 * main.c
 *
 * Copyright (C) 2022-2023  Sylvain Munaut <tnt@246tNt.com>
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

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

#include <no2usb/usb.h>
#include <no2usb/usb_dfu_rt.h>

#include "led_ctrl.h"
#include "pmu.h"
#include "spi.h"
#include "utils.h"
#include "usb_dev.h"


/* ------------------------------------------------------------------------ */
/* USB                                                                      */
/* ------------------------------------------------------------------------ */

extern const struct usb_stack_descriptors app_stack_desc;

static void
usb_serial_no_init(void)
{
	uint8_t buf[8];
	char *id, *desc;
	int i;

	/* Get flash ID */
	flash_unique_id(buf);

	/* Shutdown flash chip */
	flash_deep_power_down();

	/* Overwrite descriptor string */
		/* In theory in rodata ... but nothing is ro here */
	id = hexstr(buf, 8, false);
	desc = (char*)app_stack_desc.str[1];
	for (i=0; i<16; i++)
		desc[2 + (i << 1)] = id[i];
}

static bool
usb_run(void)
{
	/* Check current power state */
	bool powered     = pmu_is_vbus_present();
	bool usb_running = pmu_usb_state();

	/* Power USB on/off accordingly */
	if (powered && !usb_running)
	{
		/* Re-enable USB clock */
		pmu_usb_enable();

		/* Stack init (got reset) */
		usb_init(&app_stack_desc);
		usb_dfu_rt_init();
		usb_dev_init();
		usb_connect();

		/* We're up ! */
		usb_running = true;
	}
	else if (!powered & usb_running)
	{
		/* Shutdown USB clock (and reset USB core) */
		pmu_usb_disable();

		/* USB not active, don't try to access it */
		usb_running = false;
	}

	/* Run USB if need be */
	if (usb_running)
		usb_poll();

	return usb_running;
}

void
usb_dfu_rt_cb_reboot(void)
{
	/* Force re-enumeration */
	usb_disconnect();

	/* Boot firmware */
	pmu_sys_reboot(1);
}


/* ------------------------------------------------------------------------ */
/* Main                                                                     */
/* ------------------------------------------------------------------------ */

void main()
{
	/* SPI */
	spi_init();
	usb_serial_no_init();

	/* Clear events */
	pmu_get_buttons();

	/* Enable LEDs */
	led_init();
	led_start();

	/* Main loop */
	while (1)
	{
		/* Run USB */
		bool usb_running = usb_run();

		/* Check buttons */
		uint8_t btn = pmu_get_buttons();

		if (btn & BTN_1_SHORT) {
			led_cycle_speed();
		} else if (btn & BTN_1_LONG) {
			led_cycle_dim();
		}

		if (btn & BTN_2_SHORT) {
			led_cycle_anim();
		} else if (btn & BTN_2_LONG) {
			pmu_sys_shutdown();
		}

		/* LED */
		led_poll(!usb_running);
	}
}
