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

Revision:
0:21fea82c85fc
Child:
1:0a051df78be2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sun May 15 18:06:06 2016 +0000
@@ -0,0 +1,268 @@
+/*
+  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);
+    }
+}
\ No newline at end of file