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

Committer:
isonno
Date:
Thu Dec 29 01:59:53 2011 +0000
Revision:
0:6da5625a6946
Child:
1:d1da77023e6a
Contest submission version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
isonno 0:6da5625a6946 1 //
isonno 0:6da5625a6946 2 // UserInterface - Application specific UI
isonno 0:6da5625a6946 3 //
isonno 0:6da5625a6946 4
isonno 0:6da5625a6946 5 #include "NokiaLCD.h"
isonno 0:6da5625a6946 6 #include "UserInterface.h"
isonno 0:6da5625a6946 7 #include "LightString.h"
isonno 0:6da5625a6946 8 #include "SystemState.h"
isonno 0:6da5625a6946 9
isonno 0:6da5625a6946 10 #include "SDFileSystem.h"
isonno 0:6da5625a6946 11 #include <string>
isonno 0:6da5625a6946 12 #include <algorithm>
isonno 0:6da5625a6946 13 #include <math.h>
isonno 0:6da5625a6946 14 #define PI 3.141592653589793
isonno 0:6da5625a6946 15
isonno 0:6da5625a6946 16 static uint32_t Int2LCDColor( uint16_t intColor )
isonno 0:6da5625a6946 17 {
isonno 0:6da5625a6946 18 int r = intColor / 100;
isonno 0:6da5625a6946 19 int g = (intColor % 100) / 10;
isonno 0:6da5625a6946 20 int b = intColor % 10;
isonno 0:6da5625a6946 21
isonno 0:6da5625a6946 22 return (r << 9) | (g << 5) | (b << 1);
isonno 0:6da5625a6946 23 }
isonno 0:6da5625a6946 24
isonno 0:6da5625a6946 25 void ControllerUI::LightSwitch( bool on )
isonno 0:6da5625a6946 26 {
isonno 0:6da5625a6946 27 if (on == fLightsOn)
isonno 0:6da5625a6946 28 return;
isonno 0:6da5625a6946 29
isonno 0:6da5625a6946 30 fLightsOn = on;
isonno 0:6da5625a6946 31 if (fLightsOn)
isonno 0:6da5625a6946 32 TurnOn();
isonno 0:6da5625a6946 33 else
isonno 0:6da5625a6946 34 fLights->Off();
isonno 0:6da5625a6946 35 }
isonno 0:6da5625a6946 36
isonno 0:6da5625a6946 37 PatternSelector::PatternSelector( CheapLCD * lcd, LightString * lights )
isonno 0:6da5625a6946 38 : ControllerUI( lcd, lights )
isonno 0:6da5625a6946 39 {
isonno 0:6da5625a6946 40 SDFileSystem sdcard( p5, p6, p7, p8, "sd" );
isonno 0:6da5625a6946 41 DIR * sdDir = opendir("/sd");
isonno 0:6da5625a6946 42
isonno 0:6da5625a6946 43 struct dirent *p;
isonno 0:6da5625a6946 44
isonno 0:6da5625a6946 45 // Read in patterns off of the SD card
isonno 0:6da5625a6946 46 while ((p = readdir( sdDir )) != NULL)
isonno 0:6da5625a6946 47 {
isonno 0:6da5625a6946 48 // Search for files ending in .CRI
isonno 0:6da5625a6946 49 string srcName = string("/sd/") + string(p->d_name);
isonno 0:6da5625a6946 50 size_t pos = srcName.rfind( ".CRI");
isonno 0:6da5625a6946 51 if (pos != string::npos)
isonno 0:6da5625a6946 52 {
isonno 0:6da5625a6946 53 FILE * f = fopen( srcName.c_str(), "r" );
isonno 0:6da5625a6946 54 if (f)
isonno 0:6da5625a6946 55 {
isonno 0:6da5625a6946 56 Pattern pat;
isonno 0:6da5625a6946 57 char line[50];
isonno 0:6da5625a6946 58 uint32_t color;
isonno 0:6da5625a6946 59
isonno 0:6da5625a6946 60 // Read to the end, or the the end of the frame.
isonno 0:6da5625a6946 61 while (fgets( line, sizeof(line), f) && (line[0] != 'F'))
isonno 0:6da5625a6946 62 {
isonno 0:6da5625a6946 63 sscanf( line, "%d", &color );
isonno 0:6da5625a6946 64 pat.push_back( color );
isonno 0:6da5625a6946 65 }
isonno 0:6da5625a6946 66 fPatterns.push_back( pat );
isonno 0:6da5625a6946 67 fPatternNames.push_back( srcName.substr( 4, pos-4 ) ); // Skip "/sd/", Remove ext.
isonno 0:6da5625a6946 68 fclose(f);
isonno 0:6da5625a6946 69 }
isonno 0:6da5625a6946 70 }
isonno 0:6da5625a6946 71 }
isonno 0:6da5625a6946 72
isonno 0:6da5625a6946 73 // Hack: Since readdir doesn't sort names,
isonno 0:6da5625a6946 74 // force file starting "_" to the top.
isonno 0:6da5625a6946 75 int i;
isonno 0:6da5625a6946 76 for (i = 0; (i < fPatternNames.size()) && (fPatternNames[i][0] != '_'); ++i) {}
isonno 0:6da5625a6946 77 if ((i > 0) && (i < fPatternNames.size()))
isonno 0:6da5625a6946 78 {
isonno 0:6da5625a6946 79 swap( fPatternNames[i], fPatternNames[0] );
isonno 0:6da5625a6946 80 swap( fPatterns[i], fPatterns[0] );
isonno 0:6da5625a6946 81 }
isonno 0:6da5625a6946 82
isonno 0:6da5625a6946 83 // Maybe the card was swapped, etc...
isonno 0:6da5625a6946 84 if (gSystemState.GetPatternIndex() > (fPatterns.size()-1))
isonno 0:6da5625a6946 85 {
isonno 0:6da5625a6946 86 printf("Reset pattern index\r\n");
isonno 0:6da5625a6946 87 gSystemState.SetPatternIndex(0);
isonno 0:6da5625a6946 88 }
isonno 0:6da5625a6946 89
isonno 0:6da5625a6946 90 // Need code to make sure "_WEBPAGE.CRI" is in slot zero...
isonno 0:6da5625a6946 91 }
isonno 0:6da5625a6946 92
isonno 0:6da5625a6946 93 void PatternSelector::Display( bool on )
isonno 0:6da5625a6946 94 {
isonno 0:6da5625a6946 95 if (on)
isonno 0:6da5625a6946 96 {
isonno 0:6da5625a6946 97 DrawPattern();
isonno 0:6da5625a6946 98 SetLights();
isonno 0:6da5625a6946 99 }
isonno 0:6da5625a6946 100 }
isonno 0:6da5625a6946 101
isonno 0:6da5625a6946 102 void PatternSelector::SetLights()
isonno 0:6da5625a6946 103 {
isonno 0:6da5625a6946 104 int curPattern = gSystemState.GetPatternIndex();
isonno 0:6da5625a6946 105 if (fPatterns.size() > 0)
isonno 0:6da5625a6946 106 for (int i = 0; i < fLights->GetNumLights(); ++i)
isonno 0:6da5625a6946 107 fLights->SetOneColor( fPatterns[curPattern][i % fPatterns[curPattern].size()], i );
isonno 0:6da5625a6946 108 }
isonno 0:6da5625a6946 109
isonno 0:6da5625a6946 110 void PatternSelector::DrawPattern()
isonno 0:6da5625a6946 111 {
isonno 0:6da5625a6946 112 int curPattern = gSystemState.GetPatternIndex();
isonno 0:6da5625a6946 113
isonno 0:6da5625a6946 114 fLCD->erase();
isonno 0:6da5625a6946 115 if (fPatterns.size() == 0)
isonno 0:6da5625a6946 116 {
isonno 0:6da5625a6946 117 fLCD->draw_glyph_text( WHITE, BLACK, 2, 40, "No Patterns!" );
isonno 0:6da5625a6946 118 return;
isonno 0:6da5625a6946 119 }
isonno 0:6da5625a6946 120
isonno 0:6da5625a6946 121 fLCD->draw_glyph_text( WHITE, BLACK, 5, 40, fPatternNames[curPattern].c_str() );
isonno 0:6da5625a6946 122
isonno 0:6da5625a6946 123 int numColors = std::min( (int) fPatterns[curPattern].size(), 12 );
isonno 0:6da5625a6946 124
isonno 0:6da5625a6946 125 int i, width = 131 / numColors;
isonno 0:6da5625a6946 126
isonno 0:6da5625a6946 127 for (i = 0; i < numColors; ++i)
isonno 0:6da5625a6946 128 fLCD->clear( Int2LCDColor( (uint16_t) fPatterns[curPattern][i] ),
isonno 0:6da5625a6946 129 i*width + 5, 60, ((i+1)*width)+ 3, 80 );
isonno 0:6da5625a6946 130 }
isonno 0:6da5625a6946 131
isonno 0:6da5625a6946 132 void PatternSelector::TurnOn()
isonno 0:6da5625a6946 133 {
isonno 0:6da5625a6946 134 SetLights();
isonno 0:6da5625a6946 135 }
isonno 0:6da5625a6946 136
isonno 0:6da5625a6946 137 int32_t PatternSelector::KnobMoved( int32_t step )
isonno 0:6da5625a6946 138 {
isonno 0:6da5625a6946 139 int curPattern = gSystemState.GetPatternIndex();
isonno 0:6da5625a6946 140 curPattern += step;
isonno 0:6da5625a6946 141 if (curPattern < 0)
isonno 0:6da5625a6946 142 curPattern = fPatterns.size() - 1;
isonno 0:6da5625a6946 143 if (curPattern == fPatterns.size())
isonno 0:6da5625a6946 144 curPattern = 0;
isonno 0:6da5625a6946 145
isonno 0:6da5625a6946 146 gSystemState.SetPatternIndex( curPattern );
isonno 0:6da5625a6946 147
isonno 0:6da5625a6946 148 DrawPattern();
isonno 0:6da5625a6946 149 SetLights();
isonno 0:6da5625a6946 150
isonno 0:6da5625a6946 151 return step;
isonno 0:6da5625a6946 152 }
isonno 0:6da5625a6946 153
isonno 0:6da5625a6946 154 //====================================================
isonno 0:6da5625a6946 155
isonno 0:6da5625a6946 156 const uint16_t wheelColors[] = {
isonno 0:6da5625a6946 157 770, 760, 750, 740, 730, 720,
isonno 0:6da5625a6946 158 710, 700, 701, 702, 703, 704,
isonno 0:6da5625a6946 159 705, 706, 707, 607, 507, 407,
isonno 0:6da5625a6946 160 307, 207, 107, 7, 17, 27,
isonno 0:6da5625a6946 161 37, 47, 57, 67, 77, 76,
isonno 0:6da5625a6946 162 75, 74, 73, 72, 71, 70,
isonno 0:6da5625a6946 163 170, 270, 370, 470, 570, 670 };
isonno 0:6da5625a6946 164
isonno 0:6da5625a6946 165 #include "WheelCursor.h"
isonno 0:6da5625a6946 166
isonno 0:6da5625a6946 167 const int kNumWheelColors = sizeof(wheelColors) / sizeof(uint16_t);
isonno 0:6da5625a6946 168
isonno 0:6da5625a6946 169 void ColorSelector::Display( bool on )
isonno 0:6da5625a6946 170 {
isonno 0:6da5625a6946 171 if (on)
isonno 0:6da5625a6946 172 {
isonno 0:6da5625a6946 173 fLCD->splash( 1 );
isonno 0:6da5625a6946 174 fLights->SetAllLights( wheelColors[gSystemState.GetSatColorIndex()] );
isonno 0:6da5625a6946 175 }
isonno 0:6da5625a6946 176 DrawCursor( true );
isonno 0:6da5625a6946 177 }
isonno 0:6da5625a6946 178
isonno 0:6da5625a6946 179 void ColorSelector::DrawCursor( bool drawSprite )
isonno 0:6da5625a6946 180 {
isonno 0:6da5625a6946 181 const int kScreenSize = 132;
isonno 0:6da5625a6946 182 const int kCursorSize = 13;
isonno 0:6da5625a6946 183 const uint32_t DKGRAY = 0x666;
isonno 0:6da5625a6946 184
isonno 0:6da5625a6946 185 int curColor = gSystemState.GetSatColorIndex();
isonno 0:6da5625a6946 186
isonno 0:6da5625a6946 187 double angle = 2*PI / kNumWheelColors;
isonno 0:6da5625a6946 188 double radius = 40;
isonno 0:6da5625a6946 189
isonno 0:6da5625a6946 190 double vecX = cos(angle * curColor) * radius;
isonno 0:6da5625a6946 191 double vecY = sin(angle * curColor) * radius;
isonno 0:6da5625a6946 192
isonno 0:6da5625a6946 193 vecX += kScreenSize/2 + 1; // Screwy epson offset
isonno 0:6da5625a6946 194 vecY += kScreenSize/2;
isonno 0:6da5625a6946 195
isonno 0:6da5625a6946 196 vecX -= kCursorSize/2; // Move from center to TR
isonno 0:6da5625a6946 197 vecY -= kCursorSize/2; // corner of the cursor
isonno 0:6da5625a6946 198
isonno 0:6da5625a6946 199 if (drawSprite)
isonno 0:6da5625a6946 200 {
isonno 0:6da5625a6946 201 fLCD->draw_sprite( WHITE, DKGRAY,
isonno 0:6da5625a6946 202 (byte)vecX, (byte)vecY,
isonno 0:6da5625a6946 203 &WheelCursor_sprt );
isonno 0:6da5625a6946 204 fLCD->clear( Int2LCDColor(wheelColors[curColor]), 50, 50, 82, 82 );
isonno 0:6da5625a6946 205 }
isonno 0:6da5625a6946 206 else
isonno 0:6da5625a6946 207 fLCD->clear( DKGRAY, (byte)vecX, (byte)vecY,
isonno 0:6da5625a6946 208 ((byte)vecX)+kCursorSize, ((byte)vecY) + kCursorSize );
isonno 0:6da5625a6946 209 }
isonno 0:6da5625a6946 210
isonno 0:6da5625a6946 211 int32_t ColorSelector::KnobMoved( int32_t step )
isonno 0:6da5625a6946 212 {
isonno 0:6da5625a6946 213 int curColor = gSystemState.GetSatColorIndex();
isonno 0:6da5625a6946 214
isonno 0:6da5625a6946 215 DrawCursor( false );
isonno 0:6da5625a6946 216 curColor += step;
isonno 0:6da5625a6946 217 if (curColor < 0)
isonno 0:6da5625a6946 218 curColor = kNumWheelColors-1;
isonno 0:6da5625a6946 219 if (curColor == kNumWheelColors)
isonno 0:6da5625a6946 220 curColor = 0;
isonno 0:6da5625a6946 221
isonno 0:6da5625a6946 222 // Must update system state before drawing new cursor
isonno 0:6da5625a6946 223 gSystemState.SetSatColorIndex( curColor );
isonno 0:6da5625a6946 224 DrawCursor( true );
isonno 0:6da5625a6946 225 fLights->SetAllLights( wheelColors[curColor] );
isonno 0:6da5625a6946 226 return step;
isonno 0:6da5625a6946 227 }
isonno 0:6da5625a6946 228
isonno 0:6da5625a6946 229 void ColorSelector::TurnOn()
isonno 0:6da5625a6946 230 {
isonno 0:6da5625a6946 231 fLights->SetAllLights( wheelColors[gSystemState.GetSatColorIndex()] );
isonno 0:6da5625a6946 232 }
isonno 0:6da5625a6946 233
isonno 0:6da5625a6946 234 //================================================
isonno 0:6da5625a6946 235
isonno 0:6da5625a6946 236 void WhiteSelector::SetLights()
isonno 0:6da5625a6946 237 {
isonno 0:6da5625a6946 238 int level = gSystemState.GetBrightLevel();
isonno 0:6da5625a6946 239 fLights->SetAllLights( level * 100 + level * 10 + level );
isonno 0:6da5625a6946 240 }
isonno 0:6da5625a6946 241
isonno 0:6da5625a6946 242 void WhiteSelector::Display( bool on )
isonno 0:6da5625a6946 243 {
isonno 0:6da5625a6946 244 if (on)
isonno 0:6da5625a6946 245 {
isonno 0:6da5625a6946 246 DrawLevel();
isonno 0:6da5625a6946 247 SetLights();
isonno 0:6da5625a6946 248 }
isonno 0:6da5625a6946 249 }
isonno 0:6da5625a6946 250
isonno 0:6da5625a6946 251 void WhiteSelector::DrawLevel()
isonno 0:6da5625a6946 252 {
isonno 0:6da5625a6946 253 fLCD->erase();
isonno 0:6da5625a6946 254 char msg[20];
isonno 0:6da5625a6946 255 sprintf( msg, "Brightness: %d", gSystemState.GetBrightLevel() );
isonno 0:6da5625a6946 256 fLCD->draw_glyph_text( WHITE, BLACK, 5, 40, msg );
isonno 0:6da5625a6946 257 }
isonno 0:6da5625a6946 258
isonno 0:6da5625a6946 259 int32_t WhiteSelector::KnobMoved( int32_t step )
isonno 0:6da5625a6946 260 {
isonno 0:6da5625a6946 261 int level = gSystemState.GetBrightLevel();
isonno 0:6da5625a6946 262 level += step;
isonno 0:6da5625a6946 263 if (level < 1)
isonno 0:6da5625a6946 264 level = 1;
isonno 0:6da5625a6946 265 if (level > 7)
isonno 0:6da5625a6946 266 level = 7;
isonno 0:6da5625a6946 267
isonno 0:6da5625a6946 268 gSystemState.SetBrightLevel( level );
isonno 0:6da5625a6946 269 DrawLevel();
isonno 0:6da5625a6946 270 SetLights();
isonno 0:6da5625a6946 271 return step;
isonno 0:6da5625a6946 272 }
isonno 0:6da5625a6946 273
isonno 0:6da5625a6946 274 void WhiteSelector::TurnOn()
isonno 0:6da5625a6946 275 {
isonno 0:6da5625a6946 276 SetLights();
isonno 0:6da5625a6946 277 }
isonno 0:6da5625a6946 278
isonno 0:6da5625a6946 279 //================================================
isonno 0:6da5625a6946 280 LightController::LightController( HomeMenu * parent, CheapLCD * lcd, LightString * lights )
isonno 0:6da5625a6946 281 : PushKnobUI( lcd ),
isonno 0:6da5625a6946 282 fParent( parent ), fLCD( lcd ), fLights( lights ),
isonno 0:6da5625a6946 283 fSubController( NULL ),
isonno 0:6da5625a6946 284 fColorSelector( lcd, lights ),
isonno 0:6da5625a6946 285 fWhiteSelector( lcd, lights ),
isonno 0:6da5625a6946 286 fPatternSelector( lcd, lights )
isonno 0:6da5625a6946 287 {
isonno 0:6da5625a6946 288 SetSelector( gSystemState.GetModeSelector() );
isonno 0:6da5625a6946 289 if (fSubController)
isonno 0:6da5625a6946 290 fSubController->TurnOn();
isonno 0:6da5625a6946 291 }
isonno 0:6da5625a6946 292
isonno 0:6da5625a6946 293
isonno 0:6da5625a6946 294 int32_t LightController::KnobMoved( int32_t step )
isonno 0:6da5625a6946 295 {
isonno 0:6da5625a6946 296 Wake();
isonno 0:6da5625a6946 297 return fSubController->KnobMoved( step );
isonno 0:6da5625a6946 298 }
isonno 0:6da5625a6946 299
isonno 0:6da5625a6946 300 void LightController::SetSelector( ESelector sel )
isonno 0:6da5625a6946 301 {
isonno 0:6da5625a6946 302 switch (sel)
isonno 0:6da5625a6946 303 {
isonno 0:6da5625a6946 304 case kColorSelector: fSubController = &fColorSelector; break;
isonno 0:6da5625a6946 305 case kWhiteSelector: fSubController = &fWhiteSelector; break;
isonno 0:6da5625a6946 306 case kPatternSelector: fSubController =&fPatternSelector; break;
isonno 0:6da5625a6946 307 default :;
isonno 0:6da5625a6946 308 }
isonno 0:6da5625a6946 309
isonno 0:6da5625a6946 310 gSystemState.SetModeSelector( sel );
isonno 0:6da5625a6946 311 }
isonno 0:6da5625a6946 312
isonno 0:6da5625a6946 313 void LightController::KnobPushed()
isonno 0:6da5625a6946 314 {
isonno 0:6da5625a6946 315 Wake();
isonno 0:6da5625a6946 316 Display( false );
isonno 0:6da5625a6946 317 fLCD->erase();
isonno 0:6da5625a6946 318 fParent->Display( true );
isonno 0:6da5625a6946 319 SwitchTo( fParent );
isonno 0:6da5625a6946 320 }
isonno 0:6da5625a6946 321
isonno 0:6da5625a6946 322 //================================================
isonno 0:6da5625a6946 323
isonno 0:6da5625a6946 324 HomeMenu::HomeMenu( CheapLCD * lcd, LightString * lights )
isonno 0:6da5625a6946 325 : UIMenu( lcd, "CuriLights" ),
isonno 0:6da5625a6946 326 fLightController( this, lcd, lights )
isonno 0:6da5625a6946 327 {
isonno 0:6da5625a6946 328 fForcedOff = false;
isonno 0:6da5625a6946 329 fLabels.push_back( string( "Patterns" ) );
isonno 0:6da5625a6946 330 fLabels.push_back( string( "Colors" ) );
isonno 0:6da5625a6946 331 fLabels.push_back( string( "White" ) );
isonno 0:6da5625a6946 332 fLabels.push_back( string( "Lights Off" ) );
isonno 0:6da5625a6946 333 fLabels.push_back( string( "Settings" ) );
isonno 0:6da5625a6946 334 }
isonno 0:6da5625a6946 335
isonno 0:6da5625a6946 336 void HomeMenu::SetLightsOn( bool isOn )
isonno 0:6da5625a6946 337 {
isonno 0:6da5625a6946 338 if (fForcedOff)
isonno 0:6da5625a6946 339 return;
isonno 0:6da5625a6946 340
isonno 0:6da5625a6946 341 if (isOn != fLightController.AreLightsOn() )
isonno 0:6da5625a6946 342 DoToggleLightsOn();
isonno 0:6da5625a6946 343 }
isonno 0:6da5625a6946 344
isonno 0:6da5625a6946 345 void HomeMenu::DoToggleLightsOn()
isonno 0:6da5625a6946 346 {
isonno 0:6da5625a6946 347 fLightController.LightSwitch( ! fLightController.AreLightsOn() );
isonno 0:6da5625a6946 348 ChangeItem( 3, fLightController.AreLightsOn() ? "Lights Off" : "Lights On" );
isonno 0:6da5625a6946 349 }
isonno 0:6da5625a6946 350
isonno 0:6da5625a6946 351 void HomeMenu::DoLightController( ESelector sel )
isonno 0:6da5625a6946 352 {
isonno 0:6da5625a6946 353 Display( false );
isonno 0:6da5625a6946 354 fLightController.SetSelector( sel );
isonno 0:6da5625a6946 355 SwitchTo( &fLightController );
isonno 0:6da5625a6946 356 fLightController.Display( true );
isonno 0:6da5625a6946 357 }
isonno 0:6da5625a6946 358
isonno 0:6da5625a6946 359 void HomeMenu::KnobPushed()
isonno 0:6da5625a6946 360 {
isonno 0:6da5625a6946 361 switch( SelectedItem() )
isonno 0:6da5625a6946 362 {
isonno 0:6da5625a6946 363 case 0: DoLightController( kPatternSelector ); break;
isonno 0:6da5625a6946 364 case 1: DoLightController( kColorSelector ); break;
isonno 0:6da5625a6946 365 case 2: DoLightController( kWhiteSelector ); break;
isonno 0:6da5625a6946 366 case 3: DoToggleLightsOn();
isonno 0:6da5625a6946 367 // The ForcedOff state can only be set via the menu
isonno 0:6da5625a6946 368 fForcedOff = !fLightController.AreLightsOn();
isonno 0:6da5625a6946 369 break;
isonno 0:6da5625a6946 370
isonno 0:6da5625a6946 371 default: UIMenu::KnobPushed(); break;
isonno 0:6da5625a6946 372 }
isonno 0:6da5625a6946 373 }