/*
 * $Id: rgbled.c 464 2019-08-01 02:15:54Z true $
 * begin 20190505 true
 */

#include "efm8_config.h"
#include "disp/hsv2rgb.h"

#include "led/rgbled.h"


color_rgb idata rgb[RGBLED_COUNT];
color_hsv idata hsv[RGBLED_COUNT];


void rgbled_update(uint8_t idx) {
	uint8_t i;
	uint8_t data *p;
	uint8_t pwm[RGBLED_COUNT];
	uint8_t sfrsave;

	// calculate values or figure out which color we are lighting this round
	switch (idx) {
		case 0: {
			for (i = 0; i < RGBLED_COUNT; i++) {
				hsv2rgb_8b(hsv[i].h, hsv[i].s, hsv[i].v, &rgb[i].r, &rgb[i].g, &rgb[i].b);
			}
			return;
		}
		case 1: p = &rgb[0].r; break;
		case 2: p = &rgb[0].g; break;
		case 3: p = &rgb[0].b; break;
	}

	// copy colors into working variable
	for (i = 0; i < RGBLED_COUNT; i++) {
		// max clamp
		if (pwm[i] == 0xff) {
			pwm[i] = 0xfe;
		}

		pwm[i] = *p;
		p += 3;
	}

	// don't break shit
	sfrsave = SFRPAGE;
	SFRPAGE = LEGACY_PAGE;

	// pwm minimum duty is 0.39%; for off we need 0% to be fully off.
	// if we were common cathode this would be OK since this would be inverted.
	// but we're not. and since we don't have reload, we're stuck at 8-bits,
	// because 16-bit timing is too long. at 8-bit, we can never fully turn off.
	// how do we turn off then this with the shitty PCA controller?
	// if we disconnect pins then the mapping can / will shift. because WTF SiLabs.
	// to do it, we force no match, then disable pwm compare to keep the state.
	// bullshit. why. I don't fucking understand you, silicon labs.
	p = pwm;
	if (*p++ == 0) {
		PCA0CPL0 = 0xff;					// try to force no match (may match if PCA0L == 0xff)
		while (RGBLED_PWM1_PIN);			// wait until we have no match for sure
		PCA0CPM0 &= ~PCA0CPM0_ECOM__BMASK;	// disable compare mode, will stay low now
	}

	if (*p++ == 0) {
		PCA0CPL1 = 0xff;
		while (RGBLED_PWM2_PIN);
		PCA0CPM1 &= ~PCA0CPM1_ECOM__BMASK;
	}

	if (*p++ == 0) {
		PCA0CPL2 = 0xff;
		while (RGBLED_PWM3_PIN);
		PCA0CPM2 &= ~PCA0CPM2_ECOM__BMASK;
	}

	if (*p == 0) {
		PCA0CPL3 = 0xff;
		while (RGBLED_PWM4_PIN);
		PCA0CPM3 &= ~PCA0CPM3_ECOM__BMASK;
	}

	// actually set our PWMs now
	p = pwm;
	if (*p) {
		PCA0CPH0 = 0xfe - *p;
		PCA0CPL0 = 0xfe - *p;
		PCA0CPM0 |= PCA0CPM0_ECOM__BMASK;	// (re)enable compare mode
	}

	p++;
	if (*p) {
		PCA0CPH1 = 0xfe - *p;
		PCA0CPL1 = 0xfe - *p;
		PCA0CPM1 |= PCA0CPM1_ECOM__BMASK;	// (re)enable compare mode
	}

	p++;
	if (*p) {
		PCA0CPH2 = 0xfe - *p;
		PCA0CPL2 = 0xfe - *p;
		PCA0CPM2 |= PCA0CPM2_ECOM__BMASK;	// (re)enable compare mode
	}

	p++;
	if (*p) {
		PCA0CPH3 = 0xfe - *p;
		PCA0CPL3 = 0xfe - *p;
		PCA0CPM3 |= PCA0CPM3_ECOM__BMASK;	// (re)enable compare mode
	}

	SFRPAGE = sfrsave;
}
