/*
 * main.c: test-o continuity and diode tester
 *
 * your robot addon badge buddy for testing all the things
 *
 * file creation: 20231015 0021
 */


#include "testo.h"

#include "adc.h"
#include "probe.h"
#include "userio.h"

#include "led.h"
#include "rgbprog.h"

#include "rand.h"

#include "flash.h"



uint16_t ctr;
uint32_t uptime;



static inline void gpio_init()
{
    // set registers manually instead of with
    // LL functions to save space.
    // though we probably don't _need_ this space...

    // PF2=OUT(high), low speed
    // unused pins are analog
    GPIOF->ODR     = (1 << 2);
    GPIOF->MODER   = 0xFFFFFCDF;
	
	// set I2C outputs as open drain
    GPIOA->OTYPER  = 0x000c;
    // enable pullups on I2C outputs
    GPIOA->PUPDR   = 0x24000050;
    // datasheet doesn't say what the speeds are for GPIO...
    // so set SWDIO to very high speed, PA12 low speed, all other outputs as high speed
    GPIOA->OSPEEDR = 0x2C002AA0;
    // alternate function select
    // PA6=T3C1, PA5=T3C2, PA4=T3C3, PA3=I2C_SCL, PA2=I2C_SDA
    GPIOA->AFR[0]  = 0x01DDCC00;
	// PA12=OUT(high)
	GPIOA->ODR     = (1 << 12);

    // PA14=ALT, PA13=ALT, PA12=OUT, PA11=OUT
    // PA7=AN,   PA6=AF,   PA5=AF,   PA4=AF
    // PA3=AF,   PA2=AF,   PA1=AN,   PA0=AN
    // unused pins are digital inputs
    GPIOA->MODER   = 0x2900EAAF;
    

    // PB1=OUT(HIGH), PB0=AN
    // unused pins are analog, all outputs are low speed
    GPIOB->OSPEEDR = 0x00000000;
	GPIOB->ODR     = (1 << 1);
    GPIOB->MODER   = 0xfffffff7;
}

static inline void clk_init()
{
    // run all buses at core clock speed
    LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
    LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);

    // enable GPIO and peripheral clocks
    RCC->IOPENR = LL_IOP_GRP1_PERIPH_GPIOA |
                    LL_IOP_GRP1_PERIPH_GPIOB |
                    LL_IOP_GRP1_PERIPH_GPIOF;

    RCC->AHBENR |= LL_AHB1_GRP1_PERIPH_CRC;

    RCC->APBENR1 = LL_APB1_GRP1_PERIPH_TIM3;
    RCC->APBENR2 = LL_APB1_GRP2_PERIPH_ADC1;
}

static inline void systick_init()
{
    // configure nvic
    NVIC_EnableIRQ(SysTick_IRQn);
    NVIC_SetPriority(SysTick_IRQn, 0);
    
    // configure timebase with interrupt at 4096Hz
    // this assumes we'll always be running at 8MHz
    SysTick_Config((8000000 / 4096) - 1);
}

/*
 * get things started, then
 * low priority application execution
 */
int main()
{
    // base hardware initialization
    clk_init();
    flash_init();   // also configures option bytes to enable PF2, if necessary
    gpio_init();

    // peripheral initialization
    led_init();
    adc_init();

    // mainline loop interrupt
    systick_init();

    // let's go
    __enable_irq();

    while (1) {
        // run LED programs out of interrupt context at 256Hz
        if ((ctr & 0xf) == 0) {
            if (userio_get_mode() == MODE_FUN) {
                rgbprog_run();
            }
        }

        // nap time
        __WFI();
    }
}

/*
 * main application interrupt
 */

void SysTick_Handler(void)
{
    uint16_t cs;

    ctr++;

    // run LED programs quickly
    led_next();

    // limit counter to 4096 counts
    ctr &= 0xfff;
    if (!ctr) {
        uptime++;
    }

    // run main logic at 1024Hz
    if (!(ctr & 0x3)) {
        // shifted counter for use in the program
        cs = ctr >> 2;

		// adc tested to result in about 61 reads/second
		if (!adc_next()) {
			// adc has new computed results
			if (uptime || cs) {
                // figure out knobs, buttons, switches
				userio_parse();

                // initialize randomness
                rand_init((knob[0] << 8) | knob[1]);

                // show probe measurement results, or if not in a measurement mode,
                // run RGBLED program
                probe_measure();
			}
		}
    }
}
