Platform controller for the Mobile Arcade project

Dependencies:   APA102 Motor

main.cpp

Committer:
abraha2d
Date:
2018-12-11
Revision:
2:774edcf60939
Parent:
1:113469a23547
Child:
3:7e5233f883c7

File content as of revision 2:774edcf60939:

#include "mbed.h"
#include "Motor.h"
#include "APA102.h"

#define NUM_LEDS            72

#define TAIL_BLINKER_START  0
#define NUM_TAIL_BLINKER    3
#define TAIL_REVERSE_START  3
#define NUM_TAIL_REVERSE    2

#define GLOW_START          6
#define NUM_GLOW            21

#define HEAD_FOG_START      28
#define NUM_HEAD_FOG        1

#define HEAD_BLINKER_START  30
#define NUM_HEAD_BLINKER    2
#define HEAD_LIGHT_START    32
#define NUM_HEAD_LIGHT      3

#define GAME_START          51
#define NUM_GAME            19

#define COLOR_GAME_MENU     CRGB(1, 1, 1)
#define COLOR_GAME_GAME     CRGB(0, 1, 2)

#define COLOR_HEADLIGHT_DIM CRGB(8, 8, 8)
#define COLOR_HEADLIGHT_ON  CRGB(32, 32, 32)
#define COLOR_FOGLIGHT      CRGB(64, 64, 0)

#define COLOR_TAILLIGHT     CRGB(32, 0, 0)
#define COLOR_BRAKELIGHT    CRGB(128, 0, 0)
#define COLOR_REVERSE       CRGB(64, 64, 64)

#define COLOR_UNDERGLOW     CRGB(0, 16, 0)

#define COLOR_BLINKER       CRGB(128, 32, 0)
#define BLINK_DELAY         0.5

#define BLINKER_L           1
#define BLINKER_R           2
#define FOGLIGHT            4
#define REVERSE             8
#define UNDERGLOW           16
#define HEADLIGHT           32
#define BRAKELIGHT          64
uint8_t lights = 0;

CRGB l_leds[NUM_LEDS];
CRGB r_leds[NUM_LEDS];

int numGame = 0;

CRGB gameColor = COLOR_GAME_MENU;
int gamePwmNum = 1;
int gamePwmDen = 4;
int gamePwmMax = 8;

SPI l_strip(p5, p6, p7);
SPI r_strip(p11, p12, p13);

Motor l_motor(p21, p23, p22);   // PWMA, AI1, AI2
Motor r_motor(p26, p24, p25);   // PWMB, BI1, BI2

float l_vel = 0;
float r_vel = 0;

Serial bt(p28, p27);    // Bluefruit RX, TX
Serial pc(USBTX, USBRX);

Thread pcThread;
Thread btThread;
Thread blinkerThread;

void pc_thread() {
    for(;;) {
        while (!pc.readable()) wait(0.1);
        switch (pc.getc()) {
            case 's':
                // Switch to game
                while(pc.getc() != '\n'); // Flush rest of command
                while (gamePwmNum != 1) wait(0.01); // Wait for dim before switch
                gameColor = COLOR_GAME_GAME;
                break;
            case 'e':
                // Switch to menu
                while(pc.getc() != '\n'); // Flush rest of command
                while (gamePwmNum != 1) wait(0.01); // Wait for dim before switch
                gameColor = COLOR_GAME_MENU;
                break;
            case 'b':
                // Starting up
                while (numGame < NUM_GAME) {
                    numGame++;
                    wait(0.05);
                }
                lights = FOGLIGHT | UNDERGLOW | BRAKELIGHT;
                break;
            case 'h':
                // Shutting down
                lights = 0;
                while (numGame > 0) {
                    numGame--;
                    wait(0.05);
                }
                break;
        }
    }
}

void bt_thread() {
    char bnum = 0;
    char bhit = 0;
    for(;;) {
        while (!bt.readable()) wait(0.1);
        if (bt.getc() == '!' && bt.getc() == 'B') {
            bnum = bt.getc(); // button number
            bhit = bt.getc(); // '1' = hit, '0' = release
            if (bt.getc() == char(~('!' + 'B' + bnum + bhit))) {
                pc.printf("%i\n", bnum);
                if (bnum == 53 && bhit == '1') { // UP
                    l_vel += 0.25f;
                    r_vel += 0.25f;
                } else if (bnum == 54 && bhit == '1') { // DOWN
                    l_vel -= 0.25f;
                    r_vel -= 0.25f;
                } else if (bnum == 55 && bhit == '1') { // LEFT
                    l_vel += 0.25f;
                    r_vel -= 0.25f;
                } else if (bnum == 56 && bhit == '1') { // RIGHT
                    l_vel -= 0.25f;
                    r_vel += 0.25f;
                } else if (bnum == '2' && bhit == '1') {
                    lights ^= FOGLIGHT;
                }
                l_motor.speed(l_vel);
                r_motor.speed(r_vel);
                if (bnum == '1' && bhit == '1') {
                    l_vel = 0;
                    r_vel = 0;
                    l_motor.brake(1);
                    r_motor.brake(1);
                }
                if (l_vel + r_vel > 0.01f) {
                    lights &= ~(BRAKELIGHT | REVERSE);
                    lights |= HEADLIGHT;
                } else if (l_vel + r_vel < -0.01f) {
                    lights &= ~(BRAKELIGHT | HEADLIGHT);
                    lights |= REVERSE;
                } else {
                    lights &= ~(HEADLIGHT | REVERSE);
                    lights |= BRAKELIGHT;
                }
                if (l_vel - r_vel > 0.01f) {
                    lights &= ~BLINKER_R;
                    lights |= BLINKER_L;
                } else if (r_vel - l_vel > 0.01f) {
                    lights &= ~BLINKER_L;
                    lights |= BLINKER_R;
                } else {
                    lights &= ~(BLINKER_L | BLINKER_R);
                }
            }
        }
    }
}

void blinker_thread() {
  for (;;) {
    while (!(lights & (BLINKER_L | BLINKER_R))) {
      wait(0.1);
    }
    
    if (lights & BLINKER_L) {
      fill_solid(&(l_leds[HEAD_BLINKER_START]), NUM_HEAD_BLINKER, COLOR_BLINKER);
      fill_solid(&(l_leds[TAIL_BLINKER_START]), NUM_TAIL_BLINKER, COLOR_BLINKER);
    }
    if (lights & BLINKER_R) {
      fill_solid(&(r_leds[HEAD_BLINKER_START]), NUM_HEAD_BLINKER, COLOR_BLINKER);
      fill_solid(&(r_leds[TAIL_BLINKER_START]), NUM_TAIL_BLINKER, COLOR_BLINKER);
    }
    wait(BLINK_DELAY);
    
    if (l_leds[HEAD_BLINKER_START] == COLOR_BLINKER) {
      fill_solid(&(l_leds[HEAD_BLINKER_START]), NUM_HEAD_BLINKER, CRGB::Black);
      fill_solid(&(l_leds[TAIL_BLINKER_START]), NUM_TAIL_BLINKER, CRGB::Black);
    }
    if (r_leds[HEAD_BLINKER_START] == COLOR_BLINKER) {
      fill_solid(&(r_leds[HEAD_BLINKER_START]), NUM_HEAD_BLINKER, CRGB::Black);
      fill_solid(&(r_leds[TAIL_BLINKER_START]), NUM_TAIL_BLINKER, CRGB::Black);
    }
    wait(BLINK_DELAY);
  }
}

// main() runs in its own thread in the OS
int main() {
    
    // Jack up the SPI frequency
    l_strip.frequency(4000000);
    r_strip.frequency(4000000);
    
    // Clear out the strip
    fill_solid(l_leds, NUM_LEDS, CRGB::Black);
    fill_solid(r_leds, NUM_LEDS, CRGB::Black);
    APA102_write(l_strip, l_leds, NUM_LEDS);
    APA102_write(r_strip, r_leds, NUM_LEDS);
    
    // Start threads
    pcThread.start(pc_thread);
    btThread.start(bt_thread);
    blinkerThread.start(blinker_thread);
    
    int ctr = 0;
    bool up = true;
    
    for(;;) {
        if (ctr % (gamePwmDen * 7) == 0) {
            gamePwmNum += up ? 1 : -1;
            if (gamePwmNum == gamePwmMax) {
                up = false;
            } else if (gamePwmNum == 1) {
                up = true;
                ctr = 0;
            }
        }
        
        if (lights) {
        
            fill_solid(&(l_leds[HEAD_LIGHT_START]), NUM_HEAD_LIGHT, lights & HEADLIGHT ? COLOR_HEADLIGHT_ON : COLOR_HEADLIGHT_DIM);
            fill_solid(&(r_leds[HEAD_LIGHT_START]), NUM_HEAD_LIGHT, lights & HEADLIGHT ? COLOR_HEADLIGHT_ON : COLOR_HEADLIGHT_DIM);
            
            if (!(lights & BLINKER_L)) {
                fill_solid(&(l_leds[HEAD_BLINKER_START]), NUM_HEAD_BLINKER, lights & HEADLIGHT ? COLOR_HEADLIGHT_ON : COLOR_HEADLIGHT_DIM);
                fill_solid(&(l_leds[TAIL_BLINKER_START]), NUM_TAIL_BLINKER, lights & BRAKELIGHT ? COLOR_BRAKELIGHT : COLOR_TAILLIGHT);
            }
            
            if (!(lights & BLINKER_R)) {
                fill_solid(&(r_leds[HEAD_BLINKER_START]), NUM_HEAD_BLINKER, lights & HEADLIGHT ? COLOR_HEADLIGHT_ON : COLOR_HEADLIGHT_DIM);
                fill_solid(&(r_leds[TAIL_BLINKER_START]), NUM_TAIL_BLINKER, lights & BRAKELIGHT ? COLOR_BRAKELIGHT : COLOR_TAILLIGHT);
            }
            
            fill_solid(&(l_leds[HEAD_FOG_START]), NUM_HEAD_FOG, lights & FOGLIGHT ? COLOR_FOGLIGHT : CRGB::Black);
            fill_solid(&(r_leds[HEAD_FOG_START]), NUM_HEAD_FOG, lights & FOGLIGHT ? COLOR_FOGLIGHT : CRGB::Black);
            
            fill_solid(&(l_leds[GLOW_START]), NUM_GLOW, lights & UNDERGLOW ? COLOR_UNDERGLOW : CRGB::Black);
            fill_solid(&(r_leds[GLOW_START]), NUM_GLOW, lights & UNDERGLOW ? COLOR_UNDERGLOW : CRGB::Black);
            
            fill_solid(&(l_leds[TAIL_REVERSE_START]), NUM_TAIL_REVERSE, lights & REVERSE ? COLOR_REVERSE :
                                                                        lights & BRAKELIGHT ? COLOR_BRAKELIGHT : COLOR_TAILLIGHT);
            fill_solid(&(r_leds[TAIL_REVERSE_START]), NUM_TAIL_REVERSE, lights & REVERSE ? COLOR_REVERSE :
                                                                        lights & BRAKELIGHT ? COLOR_BRAKELIGHT : COLOR_TAILLIGHT);
        
        } else {
            
            fill_solid(&(l_leds[0]), NUM_LEDS, CRGB::Black);
            fill_solid(&(r_leds[0]), NUM_LEDS, CRGB::Black);
            
        }
        
        double scaleFactor = ceil((double) gamePwmNum / gamePwmDen);
        if (numGame != NUM_GAME) {
            fill_solid(&(l_leds[GAME_START]), NUM_GAME, CRGB::Black);
            fill_solid(&(r_leds[GAME_START]), NUM_GAME, CRGB::Black);
        }
        fill_solid(&(l_leds[GAME_START]), numGame, (ctr % gamePwmDen) < (gamePwmNum / scaleFactor) ? gameColor * scaleFactor : CRGB::Black);
        fill_solid(&(r_leds[GAME_START]), numGame, (ctr % gamePwmDen) < (gamePwmNum / scaleFactor) ? gameColor * scaleFactor : CRGB::Black);
        ctr++;
        
        APA102_write(l_strip, l_leds, NUM_LEDS);
        APA102_write(r_strip, r_leds, NUM_LEDS);
        
        wait(0);
    }
}