#include <Adafruit_NeoPixel.h>
#include <IRremote.h>

static const uint8_t LFA = 8;
static const uint8_t LFB = 9;
static const uint8_t LBA = 10;
static const uint8_t LBB = 11;
static const uint8_t RFA = 12;
static const uint8_t RFB = 13;
static const uint8_t RBA = 14;
static const uint8_t RBB = 15;

static const uint8_t BUZZER = 16;

static const uint8_t led = 25;

static const uint8_t Track0 = 26; // ADC0
static const uint8_t Track1 = 27; // ADC1
static const uint8_t Track2 = 28; // ADC2

static const uint8_t TRIG = 6;
static const uint8_t ECHO = 7;

static const int RECV = 18;

#define NUM_LEDS 15       // LED灯珠数量
#define LED_DT 17         // Arduino输出控制信号引脚
#define LED_TYPE WS2812   // LED灯带型号
#define COLOR_ORDER GRB   // RGB灯珠中红色、绿色、蓝色LED的排列顺序
uint8_t max_bright = 127; // LED亮度控制变量，可使用数值为 0 ～ 255， 数值越大则光带亮度越高

byte rabbit_model = 0;
int Black_Line = 200;
uint64_t delaytime;
byte IR_DATA = 0;

Adafruit_NeoPixel strip(NUM_LEDS, LED_DT, NEO_GRB + NEO_KHZ800);

enum em_dir
{
    stop = 0,
    forward,
    backward,
    turnleft,
    turnright,
    l_up,
    l_down,
    r_up,
    r_down,
    Contrarotate, // 逆时针
    Clockwise     // 顺时针
};

void setup()
{
    Serial1.begin(9600);
    Serial1.setTimeout(60);

    IrReceiver.begin(RECV, DISABLE_LED_FEEDBACK);

    pinMode(LFA, OUTPUT);
    pinMode(LFB, OUTPUT);
    pinMode(LBA, OUTPUT);
    pinMode(LBB, OUTPUT);
    pinMode(RFA, OUTPUT);
    pinMode(RFB, OUTPUT);
    pinMode(RBA, OUTPUT);
    pinMode(RBB, OUTPUT);

    pinMode(BUZZER, OUTPUT);

    pinMode(led, OUTPUT);

    pinMode(TRIG, OUTPUT);
    pinMode(ECHO, INPUT);

    strip.begin();
    strip.setBrightness(max_bright);
    for (size_t i = 0; i < 15; i++)
    {
        strip.setPixelColor(i, 255, 0, 0);
        strip.show();
        delay(200);
        strip.clear();
        strip.show();
    }

    delaytime = millis();

    Serial1.print("asdadad: ");
}

void loop()
{
    IR_DATA = 0;
    if (IrReceiver.decode())
    {                                                           //当接收到信号时
//         Serial1.println(IrReceiver.decodedIRData.command, HEX); //打印遥控按键编码
        IR_DATA = IrReceiver.decodedIRData.command;
        IrReceiver.resume();
        switch (IR_DATA)
        {
        case 0xC:
            rabbit_model = 0;
            break;
        case 0x18:
            rabbit_model = 1;
            break;
        case 0x5E:
            rabbit_model = 2;
            break;
        case 0x8:
            rabbit_model = 3;
            break;
        default:
            break;
        }
        
    }
    switch (rabbit_model)
    {
    case 1:
        obstacle_avoidance_model();
        break;
    case 2:
        follow_model();
        break;
    case 3:
        tracking_model();
        break;
    default:
        free_model();
        break;
    }
}

void tracking_model() // 循迹模式
{
    while(3 == rabbit_model)
    {
        int T0 = analogRead(Track0);
        int T1 = analogRead(Track1);
        int T2 = analogRead(Track2);
        if (IrReceiver.decode())
        {                                                           //当接收到信号时
            IR_DATA = IrReceiver.decodedIRData.command;
            IrReceiver.resume();
            switch (IR_DATA)
            {
            case 0xC:
                rabbit_model = 0;
                break;
            case 0x18:
                rabbit_model = 1;
                break;
            case 0x5E:
                rabbit_model = 2;
                break;
            case 0x8:
                rabbit_model = 3;
                break;  
             }
        }
        Serial1.print("IR_DATA:  ");
        Serial1.println(IR_DATA);
        Serial1.print("rabbit_model:  ");
        Serial1.println(rabbit_model);
        Serial1.println();
        Serial1.println();
        strip.fill(0x00ffff, 0, 15);
        strip.show();
        if (T0 > Black_Line && T1 <= Black_Line && T2 > Black_Line)
        {
            car_movement(forward);
            if (IrReceiver.decode())
            {                                                           //当接收到信号时
                IR_DATA = IrReceiver.decodedIRData.command;
                IrReceiver.resume();
                switch (IR_DATA)
                {
                case 0xC:
                    rabbit_model = 0;
                    break;
                case 0x18:
                    rabbit_model = 1;
                    break;
                case 0x5E:
                    rabbit_model = 2;
                    break;
                case 0x8:
                    rabbit_model = 3;
                    break;  
                }
            }
        }
        else if (T0 <= Black_Line && T1 > Black_Line && T2 > Black_Line)
        {
            car_movement(Clockwise);
            if (IrReceiver.decode())
            {                                                           //当接收到信号时
                IR_DATA = IrReceiver.decodedIRData.command;
                IrReceiver.resume();
                switch (IR_DATA)
                {
                case 0xC:
                    rabbit_model = 0;
                    break;
                case 0x18:
                    rabbit_model = 1;
                    break;
                case 0x5E:
                    rabbit_model = 2;
                    break;
                case 0x8:
                    rabbit_model = 3;
                    break;  
                }
            }
        }
        else if (T0 <= Black_Line && T1 <= Black_Line && T2 > Black_Line)
        {
            car_movement(Clockwise);
            if (IrReceiver.decode())
            {                                                           //当接收到信号时
                IR_DATA = IrReceiver.decodedIRData.command;
                IrReceiver.resume();
                switch (IR_DATA)
                {
                case 0xC:
                    rabbit_model = 0;
                    break;
                case 0x18:
                    rabbit_model = 1;
                    break;
                case 0x5E:
                    rabbit_model = 2;
                    break;
                case 0x8:
                    rabbit_model = 3;
                    break;  
                }
            }
        }
        else if (T0 > Black_Line && T1 > Black_Line && T2 <= Black_Line)
        {
            car_movement(Contrarotate);
            if (IrReceiver.decode())
            {                                                           //当接收到信号时
                IR_DATA = IrReceiver.decodedIRData.command;
                IrReceiver.resume();
                switch (IR_DATA)
                {
                case 0xC:
                    rabbit_model = 0;
                    break;
                case 0x18:
                    rabbit_model = 1;
                    break;
                case 0x5E:
                    rabbit_model = 2;
                    break;
                case 0x8:
                    rabbit_model = 3;
                    break; 
                } 
            }
        }
        else if (T0 > Black_Line && T1 <= Black_Line && T2 <= Black_Line)
        {
            car_movement(Contrarotate);
            if (IrReceiver.decode())
            {                                                           //当接收到信号时
                IR_DATA = IrReceiver.decodedIRData.command;
                IrReceiver.resume();
                switch (IR_DATA)
                {
                case 0xC:
                    rabbit_model = 0;
                    break;
                case 0x18:
                    rabbit_model = 1;
                    break;
                case 0x5E:
                    rabbit_model = 2;
                    break;
                case 0x8:
                    rabbit_model = 3;
                    break;  
                }
            }
        }
        else if (T0 > Black_Line && T1 > Black_Line && T2 > Black_Line)
        {
            car_movement(forward);
            if (IrReceiver.decode())
            {                                                           //当接收到信号时
                IR_DATA = IrReceiver.decodedIRData.command;
                IrReceiver.resume();
                switch (IR_DATA)
                {
                case 0xC:
                    rabbit_model = 0;
                    break;
                case 0x18:
                    rabbit_model = 1;
                    break;
                case 0x5E:
                    rabbit_model = 2;
                    break;
                case 0x8:
                    rabbit_model = 3;
                    break;  
                }
            }
        }
        else if (T0 <= Black_Line && T1 <= Black_Line && T2 <= Black_Line)
        {
            car_movement(stop);
            if (IrReceiver.decode())
            {                                                           //当接收到信号时
                IR_DATA = IrReceiver.decodedIRData.command;
                IrReceiver.resume();
                switch (IR_DATA)
                {
                case 0xC:
                    rabbit_model = 0;
                    break;
                case 0x18:
                    rabbit_model = 1;
                    break;
                case 0x5E:
                    rabbit_model = 2;
                    break;
                case 0x8:
                    rabbit_model = 3;
                    break; 
                } 
            }
        }
        if (IrReceiver.decode())
        {                                                           //当接收到信号时
            IR_DATA = IrReceiver.decodedIRData.command;
            IrReceiver.resume();
            switch (IR_DATA)
            {
            case 0xC:
                rabbit_model = 0;
                break;
            case 0x18:
                rabbit_model = 1;
                break;
            case 0x5E:
                rabbit_model = 2;
                break;
            case 0x8:
                rabbit_model = 3;
                break;
            }
            
        }
        Serial1.print(IR_DATA);
    }
}

void follow_model() // 跟随模式
{
    int Avoidance_distance = SR04(TRIG, ECHO);
    strip.fill(0x8B00FF, 0, 15);
    strip.show();
    if (IrReceiver.decode())
    {                                                           //当接收到信号时
        IR_DATA = IrReceiver.decodedIRData.command;
        IrReceiver.resume();
        switch (IR_DATA)
        {
        case 0xC:
            rabbit_model = 0;
            break;
        case 0x18:
            rabbit_model = 1;
            break;
        case 0x5E:
            rabbit_model = 2;
            break;
        case 0x8:
            rabbit_model = 3;
            break;
        }   
    }
    if (Avoidance_distance <= 15)
    {
        buzzer_sound(100);
        car_movement(backward);
    }
    else if (15 <= Avoidance_distance && Avoidance_distance <= 20)
    {
        car_movement(stop); // 停止
        if (IrReceiver.decode())
        {                                                           //当接收到信号时
            IR_DATA = IrReceiver.decodedIRData.command;
            IrReceiver.resume();
            switch (IR_DATA)
            {
            case 0xC:
                rabbit_model = 0;
                break;
            case 0x18:
                rabbit_model = 1;
                break;
            case 0x5E:
                rabbit_model = 2;
                break;
            case 0x8:
                rabbit_model = 3;
                break;
            }   
        }
    }
    else if (20 <= Avoidance_distance && Avoidance_distance <= 35)
    {
        car_movement(forward);
        if (IrReceiver.decode())
        {                                                           //当接收到信号时
            IR_DATA = IrReceiver.decodedIRData.command;
            IrReceiver.resume();
            switch (IR_DATA)
            {
            case 0xC:
                rabbit_model = 0;
                break;
            case 0x18:
                rabbit_model = 1;
                break;
            case 0x5E:
                rabbit_model = 2;
                break;
            case 0x8:
                rabbit_model = 3;
                break;
            }   
        }
    }
    else
    {
        car_movement(stop); // 停止
        if (IrReceiver.decode())
        {                                                           //当接收到信号时
            IR_DATA = IrReceiver.decodedIRData.command;
            IrReceiver.resume();
            switch (IR_DATA)
            {
            case 0xC:
                rabbit_model = 0;
                break;
            case 0x18:
                rabbit_model = 1;
                break;
            case 0x5E:
                rabbit_model = 2;
                break;
            case 0x8:
                rabbit_model = 3;
                break;
            }   
        }
    }
    if (IrReceiver.decode())
    {                                                           //当接收到信号时
        IR_DATA = IrReceiver.decodedIRData.command;
        IrReceiver.resume();
        switch (IR_DATA)
        {
        case 0xC:
            rabbit_model = 0;
            break;
        case 0x18:
            rabbit_model = 1;
            break;
        case 0x5E:
            rabbit_model = 2;
            break;
        case 0x8:
            rabbit_model = 3;
            break;
        }   
    }
}

void obstacle_avoidance_model() // 避障模式
{
    int Avoidance_distance = SR04(TRIG, ECHO);
    strip.fill(0x0000ff, 0, 15);
    strip.show();
    if (Avoidance_distance <= 25)
    {
        buzzer_sound(100);
        if (Avoidance_distance <= 15)
        {
            car_movement(stop); // 停止
            if(false == delay50ms(5)) return;
            car_movement(backward);
            if(false == delay50ms(5)) return;
            car_movement(Clockwise);
            if(false == delay50ms(2)) return;
        }
        else
        {
            car_movement(stop); // 停止
            if(false == delay50ms(5)) return;
            car_movement(backward);
            if(false == delay50ms(6)) return;
            car_movement(Contrarotate);
            if(false == delay50ms(5)) return;
        }
    }
    else
    {
        car_movement(forward);
    }
}

bool delay50ms(uint32_t ms)
{
    for(; ms>0; ms--)
    {
        delay(50);  
        if (IrReceiver.decode())
        {                                                           //当接收到信号时
            IR_DATA = IrReceiver.decodedIRData.command;
            IrReceiver.resume();
            switch (IR_DATA)
            {
            case 0xC:
                rabbit_model = 0;
                return false;
                break;
            case 0x18:
                rabbit_model = 1;
                break;
            case 0x5E:
                rabbit_model = 2;
                return false;
                break;
            case 0x8:
                rabbit_model = 3;
                return false;
                break;
            default:
                break;
            }
            
        }   
    } 
    return true;
}

void free_model() // 遥控模式
{
    if (IR_DATA == 0x15) // 顺时针
    {
        car_movement(Clockwise);
        delay(100);
        strip.fill(0x00ff00, 0, 15);
        strip.show();
    }
    else if (IR_DATA == 0x47) // 喇叭
    {
        buzzer_sound(100);
    }
    else if (IR_DATA == 0x40) // 前进
    {
        car_movement(forward);
        delay(100);
        strip.fill(0x00ff00, 0, 15);
        strip.show();
    }
    else if (IR_DATA == 0x19) // 后退
    {
        car_movement(backward);
        delay(100);
        strip.fill(0x00ff00, 0, 15);
        strip.show();
    }
    else if (IR_DATA == 0x7) // 左平移
    {
        car_movement(turnleft);
        delay(100);
        strip.fill(0x00ff00, 0, 15);
        strip.show();
    }
    else if (IR_DATA == 0x9) // 右平移
    {
        car_movement(turnright);
        delay(100);
        strip.fill(0x00ff00, 0, 15);
        strip.show();
    }
    else if (IR_DATA == 0x44) // 左上
    {
        car_movement(l_up);
        delay(100);
        strip.fill(0x00ff00, 0, 15);
        strip.show();
    }
    else if (IR_DATA == 0x16) // 左下
    {
        car_movement(l_down);
        delay(100);
        strip.fill(0x00ff00, 0, 15);
        strip.show();
    }
    else if (IR_DATA == 0x43) // 右上
    {
        car_movement(r_up);
        delay(100);
        strip.fill(0x00ff00, 0, 15);
        strip.show();
    }
    else if (IR_DATA == 0xD) // 右下
    {
        car_movement(r_down);
        delay(100);
        strip.fill(0x00ff00, 0, 15);
        strip.show();
    }
    else
    {
        car_movement(stop); // 停止
        if ((millis() - delaytime) > 1000)
        {
            delaytime = millis();
            strip.fill(random(1, 16777215), 0, 15);
            strip.show();
        }
    }
    IR_DATA = 0;
}

void buzzer_sound(unsigned int time_ms)
{
    while (time_ms)
    {
        time_ms--;
        digitalWrite(BUZZER, 1);
        delayMicroseconds(600);
        digitalWrite(BUZZER, 0);
        delayMicroseconds(400);
    }
}

float SR04(int Trig, int Echo)
{
    digitalWrite(Trig, LOW);
    delayMicroseconds(2);
    digitalWrite(Trig, HIGH);
    delayMicroseconds(10);
    digitalWrite(Trig, LOW);
    float distance = pulseIn(Echo, HIGH) / 58.00;
    delay(10);
    return distance;
}

void car_movement(em_dir direction)
{
    switch (direction)
    {
    case forward:
        digitalWrite(LFA, 1);
        digitalWrite(LFB, 0);
        digitalWrite(LBA, 1);
        digitalWrite(LBB, 0);
        digitalWrite(RFA, 0);
        digitalWrite(RFB, 1);
        digitalWrite(RBA, 0);
        digitalWrite(RBB, 1);
        break;
    case backward:
        digitalWrite(LFA, 0);
        digitalWrite(LFB, 1);
        digitalWrite(LBA, 0);
        digitalWrite(LBB, 1);
        digitalWrite(RFA, 1);
        digitalWrite(RFB, 0);
        digitalWrite(RBA, 1);
        digitalWrite(RBB, 0);
        break;
    case turnleft:
        digitalWrite(LFA, 0);
        digitalWrite(LFB, 1);
        digitalWrite(LBA, 1);
        digitalWrite(LBB, 0);
        digitalWrite(RFA, 0);
        digitalWrite(RFB, 1);
        digitalWrite(RBA, 1);
        digitalWrite(RBB, 0);
        break;
    case turnright:
        digitalWrite(LFA, 1);
        digitalWrite(LFB, 0);
        digitalWrite(LBA, 0);
        digitalWrite(LBB, 1);
        digitalWrite(RFA, 1);
        digitalWrite(RFB, 0);
        digitalWrite(RBA, 0);
        digitalWrite(RBB, 1);
        break;
    case l_up:
        digitalWrite(LFA, 0);
        digitalWrite(LFB, 0);
        digitalWrite(LBA, 1);
        digitalWrite(LBB, 0);
        digitalWrite(RFA, 0);
        digitalWrite(RFB, 1);
        digitalWrite(RBA, 0);
        digitalWrite(RBB, 0);
        break;
    case l_down:
        digitalWrite(LFA, 0);
        digitalWrite(LFB, 1);
        digitalWrite(LBA, 0);
        digitalWrite(LBB, 0);
        digitalWrite(RFA, 0);
        digitalWrite(RFB, 0);
        digitalWrite(RBA, 1);
        digitalWrite(RBB, 0);
        break;
    case r_up:
        digitalWrite(LFA, 1);
        digitalWrite(LFB, 0);
        digitalWrite(LBA, 0);
        digitalWrite(LBB, 0);
        digitalWrite(RFA, 0);
        digitalWrite(RFB, 0);
        digitalWrite(RBA, 0);
        digitalWrite(RBB, 1);
        break;
    case r_down:
        digitalWrite(LFA, 0);
        digitalWrite(LFB, 0);
        digitalWrite(LBA, 0);
        digitalWrite(LBB, 1);
        digitalWrite(RFA, 1);
        digitalWrite(RFB, 0);
        digitalWrite(RBA, 0);
        digitalWrite(RBB, 0);
        break;
    case Clockwise:
        digitalWrite(LFA, 1);
        digitalWrite(LFB, 0);
        digitalWrite(LBA, 1);
        digitalWrite(LBB, 0);
        digitalWrite(RFA, 1);
        digitalWrite(RFB, 0);
        digitalWrite(RBA, 1);
        digitalWrite(RBB, 0);
        break;
    case Contrarotate:
        digitalWrite(LFA, 0);
        digitalWrite(LFB, 1);
        digitalWrite(LBA, 0);
        digitalWrite(LBB, 1);
        digitalWrite(RFA, 0);
        digitalWrite(RFB, 1);
        digitalWrite(RBA, 0);
        digitalWrite(RBB, 1);
        break;
    default:
        digitalWrite(LFA, 0);
        digitalWrite(LFB, 0);
        digitalWrite(LBA, 0);
        digitalWrite(LBB, 0);
        digitalWrite(RFA, 0);
        digitalWrite(RFB, 0);
        digitalWrite(RBA, 0);
        digitalWrite(RBB, 0);
        break;
    }
}
