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
System Block Diagram
UserInterface.cpp
- Committer:
- isonno
- Date:
- 2013-02-11
- Revision:
- 4:cfef06d8bb96
- Parent:
- 3:0ac64c4ca40f
File content as of revision 4:cfef06d8bb96:
// // UserInterface - Application specific UI // #include "NokiaLCD.h" #include "UserInterface.h" #include "LightString.h" #include "SystemState.h" #include "SettingsMenu.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 ), 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(); SwitchControl( fParent ); fParent->Display( true ); } //================================================ HomeMenu::HomeMenu( CheapLCD * lcd, LightString * lights ) : UIMenu( lcd, "CuriLights" ), fLightController( this, lcd, lights ), fSettingsMenu( lcd, this ) { 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 ); SwitchControl( &fLightController ); fLightController.Display( true ); } void HomeMenu::KnobPushed() { // BUG: If display is asleep, should just wake it here. 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; case 4: SwitchTo( &fSettingsMenu ); break; default: UIMenu::KnobPushed(); break; } }