/*
 * probe.c: helping you probe things
 *
 * this file is responsible for figuring out the
 * continuity and diode tests from the raw analog data.
 *
 * file creation: 20231016 0255
 */

#include "py32f0xx_conf.h"

#include "testo.h"

#include "adc.h"
#include "led.h"
#include "userio.h"



#define CONT_OPEN			1240



// diode measurements at 3V3
#define DIODE_OPEN			4000		// test unit measures ~4060
#define DIODE_STANDARD		2330		// fairchild 5V2 zener, forward biased
#define DIODE_SCHOTTKY		1960		// vishay 40V 1A SB140
#define DIODE_LED_BLUE		3190
#define DIODE_LED_GRN		3040		// very dim
#define DIODE_LED_RED		3020
#define DIODE_SHORT			1900		// test unit measures ~1820

#define SHORT_THRESHOLD		2



static uint16_t vref;

static uint8_t latch = 0;
static uint8_t buzzer = 0;



static inline void probe_measure_cont()
{
	uint16_t probe, v_ext;
	uint32_t x;

	probe = adc_avg[ADC_PROBE];
	v_ext = adc_avg[ADC_VREF_EXT];

	// if the button has been pushed, toggle the buzzer
	if (userio_get_btn() > 0) {
		buzzer ^= 1;
	}

	// this LED will not set anything,
	// but zero it out anyway
	led_setrgb(1, 0, 0, 0);
	
	if (vref) {
		x  = probe << 12;			// maximum possible level
		x /= vref;					// normalize to 4096max
		if (x > 4095) x = 4095;

		if (x < 2405) {				// roughly 100ohm or lower
			latch = 4;				// latch any continuity for a while
		}

		if (latch) {
			// indicate continuity
			if (x >= 2420) latch--;	// hysteresis

			led_setrgb(0, 0, 250, ((buzzer) ? 100 : 0));
			led_buzz(0);
			if (buzzer) led_buzz(1);
		} else {
			// idle
			led_setrgb(0, 120, 0, ((buzzer) ?   8 : 0));
			led_buzz(0);
		}
	}

	if (!vref) vref = v_ext;
	vref += v_ext;
	vref >>= 1;
}

static inline void probe_measure_diode()
{
	uint16_t p;

	p = adc_avg[ADC_PROBE];

	led_setrgb(0, 0, 0, 0);

	if (p < DIODE_SHORT) {
		// show off on short
		led_setrgb(1, 0, 0, 0);
	}

	if (p >= DIODE_OPEN) {
		// show red on open
		led_setrgb(1, 120, 0, 0);
	}

	if (p >= 1940 && p < 2650) {
		// show green on regular or schottky diodes
		led_setrgb(1, 0, 200, 0);
	}
	if (p >= 2650 && p < 3800) {
		// show blue on LEDs
		led_setrgb(1, 0, 0, 500);
	}

	// if we haven't set a value, flash red to indicate error state
}

void probe_measure()
{
	uint8_t mode;

	mode = userio_get_mode();

	switch (mode) {
		case MODE_CONT:		probe_measure_cont(); break;
		case MODE_FUN:		break;	// todo: run RGBLED program
		case MODE_DIODE:	probe_measure_diode(); break;
	}
}

/*
 * switch probe mode.
 * sets up LED peripheral and mode pin as necessary.
 */
void probe_mode_switch(uint8_t mode)
{
	if (mode == MODE_CONT) {
		// set LED to buzzer mode, set PROBESEL low
		led_mode_buzzer();
		PROBESEL_PORT->BRR  = (1 << PROBESEL_PIN);
	} else {
		// set LED to dual RGB mode, set PROBESEL high
		led_mode_rgb();
		PROBESEL_PORT->BSRR = (1 << PROBESEL_PIN);
	}
}