#define WS2812BSIMPLE_IMPLEMENTATION

#include "ch32v003fun.h"
#include "ch32v003_GPIO_branchless.h"
#include "ws2812b_simple.h"
#include <stdbool.h>

#define PIXEL_NUM 8
uint8_t data[PIXEL_NUM*3] = {0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0};//RGB pixel values
uint8_t heat[PIXEL_NUM];//Heat values for fire simulation
uint8_t cooldown;//cooldown speed for fire animation

//fire color
uint8_t base_red = 100;
uint8_t base_green = 40;
uint8_t base_blue = 10;

//animation parameters
uint8_t max_heat = 32;
uint8_t max_cooldown =20;
uint8_t max_brightness = 100;

//A simple pseudo-random number generator
static uint16_t random(void){ 
  #define LFSR_MASK  ((unsigned long)( 1UL<<31 | 1UL <<15 | 1UL <<2 | 1UL <<1  ))
  static unsigned long lfsr = 0xfeedfaceUL;
  if(lfsr & 1) lfsr = (lfsr >>1) ^ LFSR_MASK ; else lfsr >>= 1;
  return(lfsr);
}

//Set RGB values of one particular pixel 
bool setPixel(uint8_t id, uint8_t r, uint8_t g, uint8_t b)
{
	if(id>=PIXEL_NUM)
		return false;
	data[id*3] = g;
	data[id*3+1] = r;
	data[id*3+2] = b;
	return true;
}

//Convert hue to RGB
void setHue(uint8_t hue)
{
	uint8_t width = 255/6;
	if (hue<width){
		base_red = max_brightness;
		base_green = max_brightness*hue/width;
		base_blue = 0;
	}
	else if (hue<width*2){
		base_green = max_brightness;
		base_red = max_brightness*(width*2-hue)/width;
		base_blue = 0;
	}
	else if (hue<width*3){
		base_green = max_brightness;
		base_blue = max_brightness*(hue-width*2)/width;
		base_red = 0;
	}
	else if (hue<width*4){
		base_blue = max_brightness;
		base_green = max_brightness*(width*4-hue)/width;
		base_red = 0;
	}
	else if (hue<width*5){
		base_blue = max_brightness;
		base_red = max_brightness*(hue-width*4)/width;
		base_green = 0;
	}
	else{
		base_red = max_brightness;
		base_blue = max_brightness*(width*6-hue)/width;
		base_green = 0;
	}
}

//Fire animation loop
void fireAnimation()
{
uint8_t i;
//generate cooldown
for (i = 0; i < PIXEL_NUM ; ++i) {
	cooldown = random()%max_cooldown;
	if(cooldown>heat[i]) {
		heat[i]=0;
	} else {
		heat[i]=heat[i]-cooldown;
	}
}
//redistribute the heat among the nearest pixels
for( int i= PIXEL_NUM - 1; i >= 2; --i) {
	heat[i] = (heat[i - 1] + heat[i - 2]) / 2;
}
//generate heat burst
if( random()%256 < 180 ) {
	i = random()%3;
	heat[i] = heat[i] + random()%max_heat/2+max_heat/2;
}
//set pixel color
for(i = 0; i < PIXEL_NUM; ++i)
	setPixel(i,base_red*heat[i]/max_heat, base_green*heat[i]/max_heat, base_blue*heat[i]/max_heat);
}

int main()
{
	SystemInit();
	// Enable GPIOs
	funGpioInitAll();
	funPinMode( PC0, GPIO_Speed_10MHz | GPIO_CNF_OUT_PP );
	GPIO_pinMode(GPIOv_from_PORT_PIN(GPIO_port_D, 6), GPIO_pinMode_I_analog, GPIO_Speed_In);
	GPIO_ADCinit();
	while(1)
	{
		uint16_t analogResult = GPIO_analogRead(GPIO_Ain6_D6);//read the potentiometer value
		//Turning everything of if the potentiometer is close to min or max position
		if ((analogResult<128)||(analogResult>895)){
			base_red=0;
			base_green=0;
			base_blue=0;
		}
		else 
			setHue((uint8_t)((analogResult-128)/3)); //set the hue of the flame
		WS2812BSimpleSend ( GPIOA, 2, data, PIXEL_NUM*3); //send data to LEDs
		fireAnimation(); //execute fire animation iteration
		Delay_Ms( 50 );
	}
}
