A somewhat silly project that uses an LPC11U24 to control the system, a Neopixel stick to provide light, and a sound FX board with a small speaker to make noise. I set the pins to inputs with pull-ups then connected 14 jumper wires to ground. Every time a wire was disconnected, the system changed its lighting pattern: color, blink timing, blink pattern (blink to white, black, random, or opposite the main color). The system also played a random audio clip. More details on http://embedded.fm/blog/2016/5/24/fistful-of-wires License: CC-A-NC

Dependencies:   PixelArray mbed

main.cpp

Committer:
Elecia
Date:
2016-05-15
Revision:
0:21fea82c85fc
Child:
1:0a051df78be2

File content as of revision 0:21fea82c85fc:

/*
  Fist full of wires!
  The intention here is to make a ball of wires that someone can reach in and 
  grab, changing the behavior of the system. 
  
  So we read in the free IO lines, build up a variable.
  If it has changed,
    do the change actions:
        make a bzzzzt sound
        vibrate the motor
        turn off all of the LEDs for a brief instant
  
    Use the created variable to choose the neopixel pattern
    and the sound pattern to output to the audio (intermittent beeps)

 
  This program depends on neopixel library.
  http://developer.mbed.org/users/JacobBramley/code/PixelArray/
  
  Audio (R2D2 sounds) from Szilard Liptak:
  https://developer.mbed.org/users/Szilard/notebook/mbed-r2d2-robot/
  Sounds in general: https://developer.mbed.org/users/4180_1/notebook/using-a-speaker-for-audio-output/

    Todo:
        Blinking needs a timer attachment
        

 
*/
#include "mbed.h"
#include "neopixel.h"
#include "SongPlayer.h"
 
 #include <stdlib.h>     /* srand, rand */
#define NLED (8)
#define ONE_COLOR
 
BusIn mColorWires(
        p20, p19, p18, p17, p16, p15    // six color, two each, RGB        
        );
BusIn mBlinkConfig( 
        p14, p13, p12,                  // three timing: indexes into mBlinkTiming
        p30, p29 );                     // two for blink type 

typedef union {
    struct 
    {
        uint32_t green:2;
        uint32_t blue:2;
        uint32_t red:2;
        uint32_t junk:26;
    };
    uint32_t value;
} tLedBehaviorWires;
    
BusIn mLedBitmask (p11, p10, p9, p8, p36, p35, p34, p33);  // eight to for bitmask which LED indexes are on... this is not enough of a difference

#define COLOR_WHITE 0xFFFFFF
#define COLOR_BLACK 0x000000

void InitializePins(void);
void AllOneColorLeds(neopixel::Pixel * out, uint32_t index, uintptr_t color);
void OnChangeMode(neopixel::PixelArray array);
neopixel::Pixel GetCurrentColor(uint32_t wireConfig);
void SetLeds(neopixel::Pixel * out, uint32_t index, uintptr_t wireConfig);

class LedArrayController {
public:
    LedArrayController(BusIn *bus, neopixel::PixelArray *array) : mBus(bus), mArray(array)
    {
        mBus->mode(PullUp);
        srand (time(NULL));
    }
    void OnChangeMode(uint32_t baseColor)
    {
                                   // 000  001  010  011  100  101  110, 111
        const float mBlinkTiming[] = {1.0, 0.1, 0.5, 0.0, 2.0, 0.0, 0.0, 5.0};
        mBaseColor = baseColor;
        mIsBaseColor = false;
        mBehavior.value = *mBus;
        Update();

        mTiming = mBlinkTiming[mBehavior.timingIndex];
        if (mTiming > 0.0f)
        {
            mTimer.attach(this, &LedArrayController::Update, mTiming); 
        } else {
            mTimer.detach();
        }        
    }
    void Update() {
        // called by timer for updating LEDs:
        if (mIsBaseColor) 
        {
            switch (mBehavior.type) {
            case (BLINK_TO_WHITE):
                mArray->update(AllOneColorLeds, NLED, COLOR_WHITE);
                break;
            case (BLINK_TO_BLACK):
                mArray->update(AllOneColorLeds, NLED, COLOR_BLACK);
                break;
            case (BLINK_TO_RANDOM):
                mArray->update(AllOneColorLeds, NLED, (rand() & COLOR_WHITE));
                break;
            case (BLINK_TO_OPPOSITE):
                mArray->update(AllOneColorLeds, NLED, ~mBaseColor);
                break;
            }
            mIsBaseColor = false;

        } else {
           // set to base color
            mArray->update(AllOneColorLeds, NLED, mBaseColor);
            mIsBaseColor = true;           
        }     
        mTimer.attach(this, &LedArrayController::Update, mTiming); 
                   
    }
private:
    float mTiming;
    BusIn *mBus;
    neopixel::PixelArray *mArray;
    Timeout mTimer;
    bool mIsBaseColor;
    uint32_t mBaseColor;
    typedef enum {BLINK_TO_WHITE=0, BLINK_TO_BLACK=1, BLINK_TO_RANDOM=2, BLINK_TO_OPPOSITE=3 } eBlinkType;
    union {
        struct {
            uint32_t timingIndex:3;
            uint32_t type:2;
            uint32_t junk:28;
        };
        uint32_t value;            
   } mBehavior;
};


void InitializePins(void)
{
    mColorWires.mode(PullUp);
    mLedBitmask.mode(PullUp);
    mBlinkConfig.mode(PullUp);
}

void OnChangeMode(neopixel::PixelArray array)
{
    // FIXME play bzzzt sound

    // all white, delay all black
    array.update(AllOneColorLeds, NLED, COLOR_WHITE);    
    wait_ms(200);
    array.update(AllOneColorLeds, NLED, COLOR_BLACK);    
    wait_ms(200);
    // FIXME mBlinkTimer.detach(); // clear timer functionality
}

uint8_t MakeColorFromWires(uint32_t singleColorWireConfig)
{
    uint8_t color;
    if (singleColorWireConfig == 3u)      { color = 0xFF; }
    else if (singleColorWireConfig == 0u) { color = 0x00; }
    else /* one bit on */                 { color = 0x80; }
    return color;
}

void AllOneColorLeds(neopixel::Pixel * out, uint32_t index, uintptr_t color)
{
    out->red =   (color >> 16) & 0xFF;    
    out->green = (color >> 8 ) & 0xFF;
    out->blue =  (color      ) & 0xFF;    
}

uint32_t GetCurrentColorU32(uint32_t wireConfig)
{
    neopixel::Pixel pix;
    uint32_t out;
    pix = GetCurrentColor(wireConfig);
    out = pix.blue + (pix.green << 8) + (pix.red << 16);
    return out;
}


neopixel::Pixel GetCurrentColor(uint32_t wireConfig)
{
    tLedBehaviorWires config;
    neopixel::Pixel out;
    config.value = wireConfig;
    if ( (config.red == 0u) && (config.green == 0u) && (config.blue == 0u) )
    {
        out.red = 0x10u;    
        out.green = 0x10u;
        out.blue = 0x10u;
    } else {
        out.red  =  MakeColorFromWires(config.red);
        out.green = MakeColorFromWires(config.green);
        out.blue =  MakeColorFromWires(config.blue);
    }
    return out;
}
void SetLeds(neopixel::Pixel * out, uint32_t index, uintptr_t wireConfig) 
 {
    bool thisOneOn = false;
    uint32_t indexMask = 1u << index;
    
    indexMask &= mLedBitmask;
    if (indexMask) // if this one set
    {
        thisOneOn = true;
    } else if (mLedBitmask == 0u) // all wires plugged in, let all LEDs turn on
    {
        thisOneOn = true;
    }
    
    if (thisOneOn) 
    {
        *out = GetCurrentColor(wireConfig);
    } else {
        AllOneColorLeds(out, index, COLOR_BLACK);    
    }
 }
 
 
int main() {
    uint32_t ledBehaviorWires;
    uint32_t ledBitMask;
    uint32_t ledBlinkConfig;
    bool change = true;
    neopixel::PixelArray array(p5);
    LedArrayController ledArrayController(&mBlinkConfig, &array);
 //   SongPlayer mySpeaker(p21);
    
    InitializePins();
    
//    float note[18]= {3520, 3135.96, 2637.02, 2093, 2349.32, 3951.07, 2793.83, 4186.01, 3520, 3135.96, 2637.02, 2093, 2349.32, 3951.07, 2793.83, 4186.01}; //R2D2 sound effect
//    float duration[18]= {0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1};   //for a bit of variety, multiple sound samples could be chosen at random
 
// float note[18]= {1568.0,1396.9,1244.5,1244.5,1396.9,1568.0,1568.0,1568.0,1396.9,
//                 1244.5,1396.9,1568.0,1396.9,1244.5,1174.7,1244.5,1244.5, 0.0
//                };
//float duration[18]= {0.48,0.24,0.72,0.48,0.24,0.48,0.24,0.24,0.24,
 //                    0.24,0.24,0.24,0.24,0.48,0.24,0.48,0.48, 0.0
 //                   };
 
//    uint32_t val = 0;
    while (1) 
    { 
        if ((ledBehaviorWires != mColorWires) ||
            (ledBitMask !=  mLedBitmask) ||
            (ledBlinkConfig != mBlinkConfig) )
        {
            change = true;
        }
        if (change)
        {
            change = false;
            ledBehaviorWires = mColorWires;
            ledBitMask =  mLedBitmask;
            ledBlinkConfig = mBlinkConfig;
            ledArrayController.OnChangeMode(GetCurrentColorU32(ledBehaviorWires));
//            OnChangeMode(array);
            
            array.update(SetLeds, NLED, ledBehaviorWires);
        }
    
//      mySpeaker.PlaySong(note,duration);  //play R2D2 sound effects
      wait_ms(10);
    }
}