Source code for the Curilights Controller. See http://www.saccade.com/writing/projects/CuriController/ for details.

Dependencies:   FatFileSystem mbed

This is the source code for the Curilights controller. This lets you interactively control a string of Curilights. It provides a simple click-wheel user interface for changing colors, brightness and behavior. It responds to movement and lighting.

Finished Controller

/media/uploads/isonno/nxp3872_controllerclose.jpg

System Block Diagram

/media/uploads/isonno/blockdiagram.png

Revision:
0:6da5625a6946
Child:
1:d1da77023e6a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UserInterface.cpp	Thu Dec 29 01:59:53 2011 +0000
@@ -0,0 +1,373 @@
+//
+// UserInterface - Application specific UI
+//
+
+#include "NokiaLCD.h"
+#include "UserInterface.h"
+#include "LightString.h"
+#include "SystemState.h"
+
+#include "SDFileSystem.h"
+#include <string>
+#include <algorithm>
+#include <math.h>
+#define PI 3.141592653589793
+
+static uint32_t Int2LCDColor( uint16_t intColor )
+{
+    int r = intColor / 100;
+    int g = (intColor % 100) / 10;
+    int b = intColor % 10;
+    
+    return (r << 9) | (g << 5) | (b << 1);
+}
+
+void ControllerUI::LightSwitch( bool on )
+{
+    if (on == fLightsOn)
+        return;
+        
+    fLightsOn = on;
+    if (fLightsOn)
+        TurnOn();
+    else
+        fLights->Off();
+}
+
+PatternSelector::PatternSelector( CheapLCD * lcd, LightString * lights )
+: ControllerUI( lcd, lights )
+{
+    SDFileSystem sdcard( p5, p6, p7, p8, "sd" );
+    DIR * sdDir = opendir("/sd");
+
+    struct dirent *p;
+    
+    // Read in patterns off of the SD card
+    while ((p = readdir( sdDir )) != NULL)
+    {
+        // Search for files ending in .CRI
+        string srcName = string("/sd/") + string(p->d_name);
+        size_t pos = srcName.rfind( ".CRI");
+        if (pos != string::npos)
+        {
+            FILE * f = fopen( srcName.c_str(), "r" );
+            if (f)
+            {
+                Pattern pat;
+                char line[50];
+                uint32_t color;
+                
+                // Read to the end, or the the end of the frame.
+                while (fgets( line, sizeof(line), f) && (line[0] != 'F'))
+                {
+                    sscanf( line, "%d", &color );
+                    pat.push_back( color );
+                }
+                fPatterns.push_back( pat );
+                fPatternNames.push_back( srcName.substr( 4, pos-4 ) ); // Skip "/sd/", Remove ext.
+                fclose(f);
+            }
+        }
+    }
+    
+    // Hack: Since readdir doesn't sort names,
+    // force file starting "_" to the top.
+    int i;
+    for (i = 0; (i < fPatternNames.size()) && (fPatternNames[i][0] != '_'); ++i) {}
+    if ((i > 0) && (i < fPatternNames.size()))
+    {
+        swap( fPatternNames[i], fPatternNames[0] );
+        swap( fPatterns[i], fPatterns[0] );
+    }
+    
+    // Maybe the card was swapped, etc...
+    if (gSystemState.GetPatternIndex() > (fPatterns.size()-1))
+    {
+        printf("Reset pattern index\r\n");
+        gSystemState.SetPatternIndex(0);
+    }
+        
+    // Need code to make sure "_WEBPAGE.CRI" is in slot zero...
+}               
+
+void PatternSelector::Display( bool on )
+{
+    if (on)
+    {
+        DrawPattern();
+        SetLights();
+    }
+}
+
+void PatternSelector::SetLights()
+{
+    int curPattern = gSystemState.GetPatternIndex();
+    if (fPatterns.size() > 0)
+        for (int i = 0; i < fLights->GetNumLights(); ++i)
+            fLights->SetOneColor( fPatterns[curPattern][i % fPatterns[curPattern].size()], i );
+}
+
+void PatternSelector::DrawPattern()
+{
+    int curPattern = gSystemState.GetPatternIndex();
+
+    fLCD->erase();
+    if (fPatterns.size() == 0)
+    {
+        fLCD->draw_glyph_text( WHITE, BLACK, 2, 40, "No Patterns!" );
+        return;
+    }
+    
+    fLCD->draw_glyph_text( WHITE, BLACK, 5, 40, fPatternNames[curPattern].c_str() );
+    
+    int numColors = std::min( (int) fPatterns[curPattern].size(), 12 );
+    
+    int i, width = 131 / numColors;
+    
+    for (i = 0; i < numColors; ++i)
+        fLCD->clear( Int2LCDColor( (uint16_t) fPatterns[curPattern][i] ), 
+                     i*width + 5, 60, ((i+1)*width)+ 3, 80 );
+}
+
+void PatternSelector::TurnOn()
+{
+    SetLights();
+}
+
+int32_t PatternSelector::KnobMoved( int32_t step )
+{
+    int curPattern = gSystemState.GetPatternIndex();
+    curPattern += step;
+    if (curPattern < 0)
+        curPattern = fPatterns.size() - 1;
+    if (curPattern == fPatterns.size())
+        curPattern = 0;
+        
+    gSystemState.SetPatternIndex( curPattern );
+
+    DrawPattern();
+    SetLights();    
+    
+    return step;
+}
+
+//====================================================
+
+const uint16_t wheelColors[] = {
+    770, 760, 750, 740, 730, 720, 
+    710, 700, 701, 702, 703, 704, 
+    705, 706, 707, 607, 507, 407, 
+    307, 207, 107,   7,  17,  27, 
+     37,  47,  57,  67,  77,  76, 
+     75,  74,  73,  72,  71,  70, 
+    170, 270, 370, 470, 570, 670 };
+    
+#include "WheelCursor.h"
+    
+const int kNumWheelColors = sizeof(wheelColors) / sizeof(uint16_t);
+
+void ColorSelector::Display( bool on )
+{
+    if (on)
+    {
+        fLCD->splash( 1 );
+        fLights->SetAllLights( wheelColors[gSystemState.GetSatColorIndex()] );
+    }
+    DrawCursor( true );
+}
+
+void ColorSelector::DrawCursor( bool drawSprite )
+{
+    const int kScreenSize = 132;
+    const int kCursorSize = 13;
+    const uint32_t DKGRAY = 0x666;
+    
+    int curColor = gSystemState.GetSatColorIndex();
+    
+    double angle = 2*PI / kNumWheelColors;
+    double radius = 40;
+    
+    double vecX = cos(angle * curColor) * radius;
+    double vecY = sin(angle * curColor) * radius;
+    
+    vecX += kScreenSize/2 + 1;   // Screwy epson offset
+    vecY += kScreenSize/2;
+    
+    vecX -= kCursorSize/2;      // Move from center to TR 
+    vecY -= kCursorSize/2;      // corner of the cursor
+    
+    if (drawSprite)
+    {
+        fLCD->draw_sprite( WHITE, DKGRAY, 
+                           (byte)vecX, (byte)vecY, 
+                           &WheelCursor_sprt );
+        fLCD->clear( Int2LCDColor(wheelColors[curColor]), 50, 50, 82, 82 );
+    }
+    else
+        fLCD->clear( DKGRAY, (byte)vecX, (byte)vecY,
+                     ((byte)vecX)+kCursorSize, ((byte)vecY) + kCursorSize );
+}
+
+int32_t ColorSelector::KnobMoved( int32_t step )
+{
+    int curColor = gSystemState.GetSatColorIndex();
+    
+    DrawCursor( false );
+    curColor += step;
+    if (curColor < 0)
+        curColor = kNumWheelColors-1;
+    if (curColor == kNumWheelColors)
+        curColor = 0;
+
+    // Must update system state before drawing new cursor
+    gSystemState.SetSatColorIndex( curColor );
+    DrawCursor( true );
+    fLights->SetAllLights( wheelColors[curColor] );
+    return step;
+}
+
+void ColorSelector::TurnOn()
+{
+    fLights->SetAllLights( wheelColors[gSystemState.GetSatColorIndex()] );
+}
+
+//================================================
+
+void WhiteSelector::SetLights()
+{
+    int level = gSystemState.GetBrightLevel();
+    fLights->SetAllLights( level * 100 + level * 10 + level );
+}
+
+void WhiteSelector::Display( bool on )
+{
+    if (on)
+    {
+        DrawLevel();
+        SetLights();
+    }
+}
+
+void WhiteSelector::DrawLevel()
+{
+    fLCD->erase();
+    char msg[20];
+    sprintf( msg, "Brightness: %d", gSystemState.GetBrightLevel() );
+    fLCD->draw_glyph_text( WHITE, BLACK, 5, 40, msg );
+}
+
+int32_t WhiteSelector::KnobMoved( int32_t step )
+{
+    int level = gSystemState.GetBrightLevel();
+    level += step;
+    if (level < 1)
+        level = 1;
+    if (level > 7)
+        level = 7;
+
+    gSystemState.SetBrightLevel( level );
+    DrawLevel();
+    SetLights();
+    return step;
+}
+
+void WhiteSelector::TurnOn()
+{
+    SetLights();
+}
+
+//================================================
+LightController::LightController( HomeMenu * parent, CheapLCD * lcd, LightString * lights ) 
+: PushKnobUI( lcd ), 
+  fParent( parent ), fLCD( lcd ), fLights( lights ),
+  fSubController( NULL ), 
+  fColorSelector( lcd, lights ), 
+  fWhiteSelector( lcd, lights ),
+  fPatternSelector( lcd, lights )
+{
+    SetSelector( gSystemState.GetModeSelector() );
+    if (fSubController)
+        fSubController->TurnOn();
+}
+
+
+int32_t LightController::KnobMoved( int32_t step )
+{
+    Wake();
+    return fSubController->KnobMoved( step );
+}
+
+void LightController::SetSelector( ESelector sel )
+{
+    switch (sel)
+    {
+    case kColorSelector: fSubController = &fColorSelector; break;
+    case kWhiteSelector: fSubController = &fWhiteSelector; break;
+    case kPatternSelector: fSubController =&fPatternSelector; break;
+    default :;
+    }
+    
+    gSystemState.SetModeSelector( sel );
+}
+
+void LightController::KnobPushed()
+{
+    Wake();
+    Display( false );
+    fLCD->erase();
+    fParent->Display( true );
+    SwitchTo( fParent );
+}
+    
+//================================================
+
+HomeMenu::HomeMenu( CheapLCD * lcd, LightString * lights ) 
+: UIMenu( lcd, "CuriLights" ), 
+  fLightController( this, lcd, lights )
+{
+    fForcedOff = false;
+    fLabels.push_back( string( "Patterns" ) );
+    fLabels.push_back( string( "Colors" ) );
+    fLabels.push_back( string( "White" ) );
+    fLabels.push_back( string( "Lights Off" ) );
+    fLabels.push_back( string( "Settings" ) );
+}
+
+void HomeMenu::SetLightsOn( bool isOn )
+{
+    if (fForcedOff)
+        return;
+
+    if (isOn != fLightController.AreLightsOn() )
+        DoToggleLightsOn();
+}
+
+void HomeMenu::DoToggleLightsOn()
+{
+    fLightController.LightSwitch( ! fLightController.AreLightsOn() );
+    ChangeItem( 3, fLightController.AreLightsOn() ? "Lights Off" : "Lights On" );
+}
+
+void HomeMenu::DoLightController( ESelector sel )
+{
+    Display( false );
+    fLightController.SetSelector( sel );
+    SwitchTo( &fLightController );
+    fLightController.Display( true );
+}
+
+void HomeMenu::KnobPushed()
+{
+    switch( SelectedItem() )
+    {
+    case 0: DoLightController( kPatternSelector ); break;
+    case 1: DoLightController( kColorSelector ); break;
+    case 2: DoLightController( kWhiteSelector ); break;
+    case 3: DoToggleLightsOn(); 
+            // The ForcedOff state can only be set via the menu
+            fForcedOff = !fLightController.AreLightsOn();
+            break;
+            
+    default: UIMenu::KnobPushed(); break;
+    }
+}