/*
 * This is the fast integer only version of the code that runs at 1600 Hz
 */

#include "mbed.h"
#include "lut.h"

SPI spi(p11, p12, p13);
DigitalOut latchpin(p10);
DigitalOut led1(LED1);
DigitalOut led2(LED2);
InterruptIn hall(p7);

#define LEDS 96
#define MAX_BRIGHTNESS 4095

void HSVtoRGB( int  *r, int *g,int *b, int h, int s, int v );

void hall_fall() {
    led1 = 1;
}

void hall_rise() {
    led1 = 0;
}

void latch() {
        latchpin = 1;
        latchpin = 1;
        latchpin = 1;
        latchpin = 1;
        latchpin = 1;
        latchpin = 1;
        latchpin = 0;
}

int main() {
    // When magnet goes near Hall-effect sensor, its output will go LOW
    hall.fall(&hall_fall);
    hall.rise(&hall_rise);

    spi.format(12, 0);
    spi.frequency(16 * 1000 * 1000);

    int brightness = 0;
    int dir = 0;
    int r, g, b;

    latchpin = 0;
    while(1) {
        for (int h = 3599; h >= 0; h--) {
            for (int i = LEDS-1; i >= 0; i--) {
                HSVtoRGB(&r, &g, &b, h + i*150/4, 4095, brightness / 4);

                spi.write(gamma[b]);
                spi.write(gamma[g]);
                spi.write(gamma[r]);
            }
            latch();

            if (dir == 0) {
                brightness += 1;
                if (brightness >= 4096) {
                    brightness = 4095;
                    dir = 1;
                }
            } else {
                brightness -= 1;
                if (brightness < 0) {
                    brightness = 0;
                    dir = 0;
                }
            }
        }
    }
}

void HSVtoRGB( int  *r, int *g,int *b, int h, int s, int v )
{
    int f;
    int p, q, t;

    if( s == 0 ) {
        *r = *g = *b = v;
        return;
    }

    h = h % 3600;

    f = ((h%600)*4095)/600;
    h /= 600;

    p = (v * (4096-s))/4096;
    q = (v * (4096 - (s*f)/4096))/4096;
    t = (v * (4096 - (s*(4096-f))/4096))/4096;

    switch( h ) {
        case 0:
            *r = v;
            *g = t;
            *b = p;
            break;
        case 1:
            *r = q;
            *g = v;
            *b = p;
            break;
        case 2:
            *r = p;
            *g = v;
            *b = t;
            break;
        case 3:
            *r = p;
            *g = q;
            *b = v;
            break;
        case 4:
            *r = t;
            *g = p;
            *b = v;
            break;
        default:        // case 5:
            *r = v;
            *g = p;
            *b = q;
            break;
    }
}
/*
 * This is the slow floating point version of the code that only runs at 256 Hz
 */
#include "mbed.h"

SPI spi(p11, p12, p13);
DigitalOut latchpin(p10);
DigitalOut led1(LED1);
DigitalOut led2(LED2);
InterruptIn hall(p7);

#define LEDS 96
#define MAX_BRIGHTNESS 4095

float exp_curve(float x, float a);
int exp_curve2(float x);
void HSVtoRGB( float *r, float *g, float *b, float h, float s, float v );

void hall_fall() {
    led1 = 1;
}

void hall_rise() {
    led1 = 0;
}

void latch() {
        latchpin = 1;
        latchpin = 1;
        latchpin = 1;
        latchpin = 1;
        latchpin = 1;
        latchpin = 1;
        latchpin = 0;
}

int main() {
    // When magnet goes near Hall-effect sensor, its output will go LOW
    hall.fall(&hall_fall);
    hall.rise(&hall_rise);

    spi.format(12, 0);
    spi.frequency(16 * 1000 * 1000);

    int brightness = 0;
    int dir = 0;
    float r, g, b;

    latchpin = 0;
    while(1) {
        for (float h = 0; h < 360; h += (float)0.5) {
            for (int i = 0; i < LEDS; i++) {
                HSVtoRGB(&r, &g, &b, h + i * ((float)360.0/LEDS), (float)1.0, brightness/((float)4095.0));

                spi.write(exp_curve2(b));
                spi.write(exp_curve2(g));
                spi.write(exp_curve2(r));
            }
            latch();

            if (dir == 0) {
                brightness += 5;
                if (brightness >= 4096) {
                    brightness = 4095;
                    dir = 1;
                }
            } else {
                brightness -= 5;
                if (brightness < 0) {
                    brightness = 0;
                    dir = 0;
                }
            }
        }
    }
}

// returns a value between 0.0 and 1.0 for an input x of 0.0 to 1.0
// a affects how "exponential" this curve will be
float exp_curve(float x, float a) {
    //return (exp(x*a)-1)/(exp(a) - 1);
    return (exp(x*a)-1)/53.5982;
}

int exp_curve2(float x) {
    //return (exp(x*a)-1)/(exp(a) - 1);
    return ((exp(x*3)-1)*((float)76.4204768));
}

// stole this from somewhere, forgot
void HSVtoRGB( float *r, float *g, float *b, float h, float s, float v )
{
    int i;
    float f, p, q, t;
    if( s == 0 ) {
        // achromatic (grey)
        *r = *g = *b = v;
        return;
    }
    while (h >= 360) {
        h -= 360;
    }
    h /= 60;            // sector 0 to 5
    i = h;
    f = h - i;            // factorial part of h
    p = v * ( 1 - s );
    q = v * ( 1 - s * f );
    t = v * ( 1 - s * ( 1 - f ) );
    switch( i ) {
        case 0:
            *r = v;
            *g = t;
            *b = p;
            break;
        case 1:
            *r = q;
            *g = v;
            *b = p;
            break;
        case 2:
            *r = p;
            *g = v;
            *b = t;
            break;
        case 3:
            *r = p;
            *g = q;
            *b = v;
            break;
        case 4:
            *r = t;
            *g = p;
            *b = v;
            break;
        default:        // case 5:
            *r = v;
            *g = p;
            *b = q;
            break;
    }
}