#include <Arduino.h>

#include "LEDStripDriver.h"


/**************************************************************************/
/*!
    @brief class constructor
    @param din the data pin to use
    @param cin the clock pin to use
*/
/**************************************************************************/
LEDStripDriver::LEDStripDriver(uint8_t din, uint8_t cin) : _din(din), _cin(cin), _delay(20) {
    pinMode(din, OUTPUT);
    pinMode(cin, OUTPUT);
}

/**************************************************************************/
/*!
    @brief class constructor
    @param din the data pin to use
    @param cin the clock pin to use
    @param delay the clock delay in microseconds
*/
/**************************************************************************/
LEDStripDriver::LEDStripDriver(uint8_t din, uint8_t cin, uint16_t delay) : _din(din), _cin(cin), _delay(delay) {
    pinMode(din, OUTPUT);
    pinMode(cin, OUTPUT);
}

/**************************************************************************/
/*!
    @brief set color from r,g,b parameter
    @param red amount of red color [0-255]
    @param green amount of green color [0-255]
    @param blue amount of blue color [0-255]
*/
/**************************************************************************/
void LEDStripDriver::setColor(uint8_t red, uint8_t green, uint8_t blue) {
    uint32_t dx = 0;
    dx |= (uint32_t)0x03 << 30;
    dx |= (uint32_t)getColorCode(blue) << 28;
    dx |= (uint32_t)getColorCode(green) << 26;
    dx |= (uint32_t)getColorCode(red) << 24;

    dx |= (uint32_t)blue << 16;
    dx |= (uint32_t)green << 8;
    dx |= red;

    senddata(dx);
}

/**************************************************************************/
/*!
    @brief set color from hex parameter
    @param hex hex number [0x000000-0xFFFFFF]
*/
/**************************************************************************/
void LEDStripDriver::setColor(uint32_t hex) {
    uint8_t red   = (hex >> 16) & 0xFF;
    uint8_t green = (hex >> 8) & 0xFF;
    uint8_t blue  = (hex) & 0xFF;
    setColor(red, green, blue);
}

/**************************************************************************/
/*!
    @brief set color from hex string
    @param str string of hex color, e.g. "#00FF00"
*/
/**************************************************************************/
void LEDStripDriver::setColor(String str) {
    uint32_t hex = (uint32_t)strtol(&str[1], NULL, 16);
    setColor(hex);
}

/**************************************************************************/
/*!
    @brief set color to off
*/
/**************************************************************************/
void LEDStripDriver::setColor() {
    setColor(0, 0, 0);
}

/**************************************************************************/
/*!
    @brief send data over data pin
    @param dx data to transmitt
*/
/**************************************************************************/
void LEDStripDriver::senddata(uint32_t dx) {
    sendzero();
    for (uint8_t i = 0; i < 32; i++) {
        if ((dx & 0x80000000) != 0) {
            digitalWrite(_din, HIGH);
        } else {
            digitalWrite(_din, LOW);
        }
        dx <<= 1;
        sendclock();
    }
    sendzero();
}

/**************************************************************************/
/*!
    @brief send a sequence of zeros
*/
/**************************************************************************/
void LEDStripDriver::sendzero() {
    for (uint8_t i = 0; i < 32; i++) {
        digitalWrite(_din, LOW);
        sendclock();
    }
}

/**************************************************************************/
/*!
    @brief send one clock impulse
*/
/**************************************************************************/
void LEDStripDriver::sendclock() {
    digitalWrite(_cin, LOW);
    delayMicroseconds(_delay);
    digitalWrite(_cin, HIGH);
    delayMicroseconds(_delay);
}

/**************************************************************************/
/*!
    @brief convert color to code
*/
/**************************************************************************/
uint8_t LEDStripDriver::getColorCode(uint8_t color) {
    uint8_t tmp = 0;
    if ((color & 0x80) == 0) {
        tmp |= 0x02;
    }
    if ((color & 0x40) == 0) {
        tmp |= 0x01;
    }
    return tmp;
}


 

#ifndef __LEDStripDriver_H__
#define __LEDStripDriver_H__

#include <Arduino.h>


class LEDStripDriver {
    public:
        // constructors
        LEDStripDriver(uint8_t din, uint8_t cin);
        LEDStripDriver(uint8_t din, uint8_t cin, uint16_t delay);

        // color manipulation
        void setColor(uint8_t red, uint8_t green, uint8_t blue);
        void setColor(uint32_t hex);
        void setColor(String str);
        void setColor();

    private:
        uint8_t _din, _cin;
        uint16_t _delay;

        // private methods
        uint8_t getColorCode(uint8_t color);
        void senddata(uint32_t dx);
        void sendzero();
        void sendclock();
};

#endif


//// END Simulator LIbrary Include ////
///////////////////////////////////////
///////////////////////////////////////
///////////////////////////////////////
///////////////////////////////////////


// Begin RGB Color Wheel Sketch
#include <AccelStepper.h>
//#include <LEDStripDriver.h>. // uncomment this line for use on Arduino after removing above library code

// use two available GPIO pins from your board
// DIN=GPIO16, CIN=GPIO14 in this example
LEDStripDriver led1 = LEDStripDriver(8, 7);
LEDStripDriver led2 = LEDStripDriver(10, 9);
LEDStripDriver led3 = LEDStripDriver(12, 11); // data then clock
// Define a stepper and the pins it willuse
//AccelStepper stepper(AccelStepper::FULL4WIRE, 8, 9, 10, 11);

unsigned long currentMillis;
unsigned long startTimer;
unsigned long waitTimer;


int potPin1 = A0;
int potPin2 = A1;
int potPin3 = A2;
int potPin4 = A3;

int val = 0;
int previous = 0;
int long newval = 0;


enum states {
START,
WAIT,
MOVE_WHEEL

};
enum states wheelState = START;


void setup() {

Serial.begin(9600);
Serial.println("Start RGB Wheel Program");

startTimer = millis();
waitTimer = millis();
}

void loop() {
currentMillis = millis(); // set variable to current time in milliseconds

//ledTest();
setHue1();
setHue2();
setHue3();

//switchLEDModes();
//checkWheelState();
}

void setHue1() {
//The Hue value will vary from 0 to 360, which represents degrees in the color wheel
int hue = map(analogRead(potPin1),0,1024,1,360);
setLedColorHSV1(hue,1,1); //We are using Saturation and Value constant at 1
}
void setHue2() {
//The Hue value will vary from 0 to 360, which represents degrees in the color wheel
int hue = map(analogRead(potPin2),0,1024,1,360);
setLedColorHSV2(hue,1,1); //We are using Saturation and Value constant at 1
}

void setHue3() {
//The Hue value will vary from 0 to 360, which represents degrees in the color wheel
int hue = map(analogRead(potPin3),0,1024,1,360);
setLedColorHSV3(hue,1,1); //We are using Saturation and Value constant at 1
}


void setLedColorHSV1(int h, double s, double v) {
//this is the algorithm to convert from RGB to HSV
double r=0; 
double g=0; 
double b=0;

double hf=h/60.0;

int i=(int)floor(h/60.0);
double f = h/60.0 - i;
double pv = v * (1 - s);
double qv = v * (1 - s*f);
double tv = v * (1 - s * (1 - f));

switch (i)
{
case 0: //rojo dominante
r = v;
g = tv;
b = pv;
break;
case 1: //verde
r = qv;
g = v;
b = pv;
break;
case 2: 
r = pv;
g = v;
b = tv;
break;
case 3: //azul
r = pv;
g = qv;
b = v;
break;
case 4:
r = tv;
g = pv;
b = v;
break;
case 5: //rojo
r = v;
g = pv;
b = qv;
break;
}

//set each component to a integer value between 0 and 255
int red=constrain((int)255*r,0,255);
int green=constrain((int)255*g,0,255);
int blue=constrain((int)255*b,0,255);

// setLedColor(red,green,blue);
led1.setColor(red, blue, green); // RGB
}

void setLedColorHSV2(int h, double s, double v) {
//this is the algorithm to convert from RGB to HSV
double r=0; 
double g=0; 
double b=0;

double hf=h/60.0;

int i=(int)floor(h/60.0);
double f = h/60.0 - i;
double pv = v * (1 - s);
double qv = v * (1 - s*f);
double tv = v * (1 - s * (1 - f));

switch (i)
{
case 0: //rojo dominante
r = v;
g = tv;
b = pv;
break;
case 1: //verde
r = qv;
g = v;
b = pv;
break;
case 2: 
r = pv;
g = v;
b = tv;
break;
case 3: //azul
r = pv;
g = qv;
b = v;
break;
case 4:
r = tv;
g = pv;
b = v;
break;
case 5: //rojo
r = v;
g = pv;
b = qv;
break;
}

//set each component to a integer value between 0 and 255
int red=constrain((int)255*r,0,255);
int green=constrain((int)255*g,0,255);
int blue=constrain((int)255*b,0,255);

// setLedColor(red,green,blue);
led2.setColor(red, blue, green); // RGB
}

void setLedColorHSV3(int h, double s, double v) {
//this is the algorithm to convert from RGB to HSV
double r=0; 
double g=0; 
double b=0;

double hf=h/60.0;

int i=(int)floor(h/60.0);
double f = h/60.0 - i;
double pv = v * (1 - s);
double qv = v * (1 - s*f);
double tv = v * (1 - s * (1 - f));

switch (i)
{
case 0: //rojo dominante
r = v;
g = tv;
b = pv;
break;
case 1: //verde
r = qv;
g = v;
b = pv;
break;
case 2: 
r = pv;
g = v;
b = tv;
break;
case 3: //azul
r = pv;
g = qv;
b = v;
break;
case 4:
r = tv;
g = pv;
b = v;
break;
case 5: //rojo
r = v;
g = pv;
b = qv;
break;
}

//set each component to a integer value between 0 and 255
int red=constrain((int)255*r,0,255);
int green=constrain((int)255*g,0,255);
int blue=constrain((int)255*b,0,255);

// setLedColor(red,green,blue);
led3.setColor(red, blue, green); // RGB
}



void checkWheelState() {
switch (wheelState) {

case START:
if (checkTime(startTimer, 1000UL)) {
Serial.println("Start Complete");
Serial.println("Switch to WAIT");
wheelState = WAIT;
}
break;

case WAIT:

if (checkTime(waitTimer, 1000UL)) {
Serial.println("Turn On LEDs");
Serial.println("Switch to MOVE_WHEEL");
wheelState = MOVE_WHEEL;
}


break;

case MOVE_WHEEL:


break;
}
}



// variable names modified from original by Larry D for clarity
// timerLength is how long the timer is in Milliseconds
// lastTimerExpiredTime is the time in Milliseconds of the last time the timer expired

// BEGIN CheckTime()
boolean checkTime(unsigned long& lastTimerExpiredTime, unsigned long timerLength) {
// is the time up for this task?
if (currentMillis - lastTimerExpiredTime >= timerLength) {
lastTimerExpiredTime += timerLength; //get ready for the next iteration
return true;
}
return false;
}
//END CheckTime()
NLSF595