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
UIMenu.cpp@4:cfef06d8bb96, 2013-02-11 (annotated)
- Committer:
- isonno
- Date:
- Mon Feb 11 05:04:18 2013 +0000
- Revision:
- 4:cfef06d8bb96
- Parent:
- 3:0ac64c4ca40f
Minor changes to add backlight routines. Not hooked up yet, shouldn't affect build operation.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
isonno |
0:6da5625a6946 | 1 | // |
isonno |
0:6da5625a6946 | 2 | // UIMenu - Click-knob menu implementation |
isonno |
0:6da5625a6946 | 3 | // |
isonno |
0:6da5625a6946 | 4 | |
isonno |
0:6da5625a6946 | 5 | #include "NokiaLCD.h" |
isonno |
0:6da5625a6946 | 6 | #include "UIMenu.h" |
isonno |
0:6da5625a6946 | 7 | #include "HoldInterrupts.h" |
isonno |
0:6da5625a6946 | 8 | |
isonno |
0:6da5625a6946 | 9 | static Timeout gScreenTimer; |
isonno |
0:6da5625a6946 | 10 | |
isonno |
0:6da5625a6946 | 11 | void PushKnobUI::ConnectDevices( RotaryEncoder * knob, PushButton * button ) |
isonno |
0:6da5625a6946 | 12 | { |
isonno |
0:6da5625a6946 | 13 | HoldInterrupts holdint(); |
isonno |
0:6da5625a6946 | 14 | |
isonno |
0:6da5625a6946 | 15 | if (! knob && fKnob) // Disconnect |
isonno |
0:6da5625a6946 | 16 | { |
isonno |
0:6da5625a6946 | 17 | fKnob->detach(); |
isonno |
0:6da5625a6946 | 18 | fKnob = NULL; |
isonno |
0:6da5625a6946 | 19 | } |
isonno |
0:6da5625a6946 | 20 | if (! button && fKnobButton) |
isonno |
0:6da5625a6946 | 21 | { |
isonno |
0:6da5625a6946 | 22 | fKnobButton->detach(); |
isonno |
0:6da5625a6946 | 23 | fKnobButton = NULL; |
isonno |
0:6da5625a6946 | 24 | } |
isonno |
0:6da5625a6946 | 25 | |
isonno |
0:6da5625a6946 | 26 | if (knob && !fKnob) |
isonno |
0:6da5625a6946 | 27 | { |
isonno |
0:6da5625a6946 | 28 | fKnob = knob; |
isonno |
0:6da5625a6946 | 29 | //fKnob->attach( this, &UIMenu::KnobMoved ); |
isonno |
0:6da5625a6946 | 30 | AttachKnob( fKnob ); |
isonno |
0:6da5625a6946 | 31 | } |
isonno |
0:6da5625a6946 | 32 | if (button && !fKnobButton) |
isonno |
0:6da5625a6946 | 33 | { |
isonno |
0:6da5625a6946 | 34 | fKnobButton = button; |
isonno |
0:6da5625a6946 | 35 | //fKnobButton->attach( this, &UIMenu::KnobPushed ); |
isonno |
0:6da5625a6946 | 36 | AttachButton( fKnobButton ); |
isonno |
0:6da5625a6946 | 37 | } |
isonno |
0:6da5625a6946 | 38 | } |
isonno |
0:6da5625a6946 | 39 | |
isonno |
1:d1da77023e6a | 40 | void PushKnobUI::SwitchControl( PushKnobUI * other ) |
isonno |
0:6da5625a6946 | 41 | { |
isonno |
0:6da5625a6946 | 42 | other->ConnectDevices( fKnob, fKnobButton ); |
isonno |
0:6da5625a6946 | 43 | fKnob = NULL; |
isonno |
0:6da5625a6946 | 44 | fKnobButton = NULL; |
isonno |
0:6da5625a6946 | 45 | } |
isonno |
0:6da5625a6946 | 46 | |
isonno |
0:6da5625a6946 | 47 | int32_t PushKnobUI::KnobMoved( int32_t step ) |
isonno |
0:6da5625a6946 | 48 | { |
isonno |
0:6da5625a6946 | 49 | printf("Knob moved %d\r\n", step ); |
isonno |
0:6da5625a6946 | 50 | Wake(); |
isonno |
0:6da5625a6946 | 51 | return step; |
isonno |
0:6da5625a6946 | 52 | } |
isonno |
0:6da5625a6946 | 53 | |
isonno |
0:6da5625a6946 | 54 | void PushKnobUI::KnobPushed() |
isonno |
0:6da5625a6946 | 55 | { |
isonno |
0:6da5625a6946 | 56 | Wake(); |
isonno |
0:6da5625a6946 | 57 | printf("Button pushed\r\n"); |
isonno |
0:6da5625a6946 | 58 | } |
isonno |
0:6da5625a6946 | 59 | |
isonno |
0:6da5625a6946 | 60 | void PushKnobUI::Wake() |
isonno |
0:6da5625a6946 | 61 | { |
isonno |
0:6da5625a6946 | 62 | fLCD->fade_backlight( true ); |
isonno |
0:6da5625a6946 | 63 | gScreenTimer.detach(); |
isonno |
0:6da5625a6946 | 64 | gScreenTimer.attach( this, &PushKnobUI::Sleep, 10 ); |
isonno |
0:6da5625a6946 | 65 | } |
isonno |
0:6da5625a6946 | 66 | |
isonno |
0:6da5625a6946 | 67 | void PushKnobUI::Sleep() |
isonno |
0:6da5625a6946 | 68 | { |
isonno |
0:6da5625a6946 | 69 | fLCD->fade_backlight( false ); |
isonno |
0:6da5625a6946 | 70 | gScreenTimer.detach(); |
isonno |
0:6da5625a6946 | 71 | } |
isonno | 4:cfef06d8bb96 | 72 | |
isonno | 4:cfef06d8bb96 | 73 | bool PushKnobUI::IsSleeping() const |
isonno | 4:cfef06d8bb96 | 74 | { |
isonno | 4:cfef06d8bb96 | 75 | return ! fLCD->is_backlight_on(); |
isonno | 4:cfef06d8bb96 | 76 | } |
isonno |
0:6da5625a6946 | 77 | |
isonno |
0:6da5625a6946 | 78 | //---------------------------------------------------- |
isonno |
0:6da5625a6946 | 79 | |
isonno |
0:6da5625a6946 | 80 | UIMenu::UIMenu( CheapLCD * lcd, const char * header, bool upMenuItem ) : PushKnobUI( lcd ), |
isonno |
0:6da5625a6946 | 81 | fHeader( header ), |
isonno |
0:6da5625a6946 | 82 | fDisplayOn( false ), |
isonno |
3:0ac64c4ca40f | 83 | fSelectedItem( kNoSelection ) |
isonno |
0:6da5625a6946 | 84 | {} |
isonno |
0:6da5625a6946 | 85 | |
isonno |
0:6da5625a6946 | 86 | void UIMenu::AddItem( const char * label ) |
isonno |
0:6da5625a6946 | 87 | { |
isonno |
0:6da5625a6946 | 88 | fLabels.push_back( string( label )); |
isonno |
0:6da5625a6946 | 89 | if (fDisplayOn) |
isonno |
0:6da5625a6946 | 90 | Display( true ); // Refresh |
isonno |
0:6da5625a6946 | 91 | } |
isonno |
0:6da5625a6946 | 92 | |
isonno |
0:6da5625a6946 | 93 | void UIMenu::ChangeItem( int item, const char * label ) |
isonno |
0:6da5625a6946 | 94 | { |
isonno |
0:6da5625a6946 | 95 | if ((item > 0) && (item < fLabels.size())) |
isonno |
0:6da5625a6946 | 96 | { |
isonno |
0:6da5625a6946 | 97 | fLabels[item] = string( label ); |
isonno |
0:6da5625a6946 | 98 | DrawItem( item ); |
isonno |
0:6da5625a6946 | 99 | } |
isonno |
0:6da5625a6946 | 100 | } |
isonno |
0:6da5625a6946 | 101 | |
isonno |
3:0ac64c4ca40f | 102 | void UIMenu::ChangeHeader( const char * newHeader ) |
isonno |
3:0ac64c4ca40f | 103 | { |
isonno |
3:0ac64c4ca40f | 104 | fHeader = string( newHeader ); |
isonno |
3:0ac64c4ca40f | 105 | DrawHeader(); |
isonno |
3:0ac64c4ca40f | 106 | } |
isonno |
3:0ac64c4ca40f | 107 | |
isonno |
0:6da5625a6946 | 108 | int32_t UIMenu::KnobMoved( int32_t step ) |
isonno |
0:6da5625a6946 | 109 | { |
isonno |
0:6da5625a6946 | 110 | Wake(); |
isonno |
0:6da5625a6946 | 111 | |
isonno |
0:6da5625a6946 | 112 | if (fSelectedItem == kNoSelection) |
isonno |
0:6da5625a6946 | 113 | { |
isonno |
0:6da5625a6946 | 114 | fSelectedItem = (step > 0) ? 0 : fLabels.size() - 1; |
isonno |
0:6da5625a6946 | 115 | DrawItem( fSelectedItem ); |
isonno |
0:6da5625a6946 | 116 | } |
isonno |
0:6da5625a6946 | 117 | else |
isonno |
0:6da5625a6946 | 118 | { |
isonno |
0:6da5625a6946 | 119 | int lastItem = fSelectedItem; |
isonno |
0:6da5625a6946 | 120 | fSelectedItem += step; |
isonno |
0:6da5625a6946 | 121 | // Handle wrap-around |
isonno |
0:6da5625a6946 | 122 | if (fSelectedItem < 0) |
isonno |
0:6da5625a6946 | 123 | fSelectedItem = fLabels.size() - 1; |
isonno |
0:6da5625a6946 | 124 | if (fSelectedItem == fLabels.size()) |
isonno |
0:6da5625a6946 | 125 | fSelectedItem = 0; |
isonno |
0:6da5625a6946 | 126 | |
isonno |
0:6da5625a6946 | 127 | DrawItem( lastItem ); |
isonno |
0:6da5625a6946 | 128 | DrawItem( fSelectedItem ); |
isonno |
0:6da5625a6946 | 129 | } |
isonno |
0:6da5625a6946 | 130 | |
isonno |
0:6da5625a6946 | 131 | return 0; |
isonno |
0:6da5625a6946 | 132 | } |
isonno |
0:6da5625a6946 | 133 | |
isonno |
0:6da5625a6946 | 134 | void UIMenu::KnobPushed() |
isonno |
0:6da5625a6946 | 135 | { |
isonno |
0:6da5625a6946 | 136 | Wake(); |
isonno |
0:6da5625a6946 | 137 | printf("Selected %s\n\r", fLabels[fSelectedItem].c_str() ); |
isonno |
0:6da5625a6946 | 138 | } |
isonno |
1:d1da77023e6a | 139 | |
isonno |
1:d1da77023e6a | 140 | void UIMenu::SwitchTo( UIMenu * nextMenu ) |
isonno |
1:d1da77023e6a | 141 | { |
isonno |
1:d1da77023e6a | 142 | Display( false ); |
isonno |
1:d1da77023e6a | 143 | SwitchControl( nextMenu ); |
isonno |
1:d1da77023e6a | 144 | nextMenu->Display( true ); |
isonno |
1:d1da77023e6a | 145 | } |
isonno |
0:6da5625a6946 | 146 | |
isonno |
0:6da5625a6946 | 147 | // Parameters controlling the display layout |
isonno |
0:6da5625a6946 | 148 | const int kLineSpace = 20; |
isonno |
0:6da5625a6946 | 149 | const int kTopGap = 4; |
isonno |
0:6da5625a6946 | 150 | const int kIndent = 12; |
isonno |
0:6da5625a6946 | 151 | #define MEDGREEN 0x0A0 // "medium" green |
isonno |
0:6da5625a6946 | 152 | |
isonno |
3:0ac64c4ca40f | 153 | void UIMenu::ClearItem( int i, uint32_t color ) |
isonno |
3:0ac64c4ca40f | 154 | { |
isonno |
3:0ac64c4ca40f | 155 | if (! fDisplayOn) |
isonno |
3:0ac64c4ca40f | 156 | return; |
isonno |
3:0ac64c4ca40f | 157 | |
isonno |
3:0ac64c4ca40f | 158 | fLCD->clear( color, |
isonno |
3:0ac64c4ca40f | 159 | 0, i * kLineSpace + kLineSpace + kTopGap, |
isonno |
3:0ac64c4ca40f | 160 | 131, (i+1) * kLineSpace + kLineSpace + kTopGap ); |
isonno |
3:0ac64c4ca40f | 161 | } |
isonno |
3:0ac64c4ca40f | 162 | |
isonno |
0:6da5625a6946 | 163 | void UIMenu::DrawItem( int i ) |
isonno |
0:6da5625a6946 | 164 | { |
isonno |
0:6da5625a6946 | 165 | if (! fDisplayOn) |
isonno |
0:6da5625a6946 | 166 | return; |
isonno |
0:6da5625a6946 | 167 | |
isonno |
0:6da5625a6946 | 168 | uint32_t foreColor = WHITE; |
isonno |
0:6da5625a6946 | 169 | uint32_t backColor = (i == fSelectedItem) ? MEDGREEN : BLACK; |
isonno |
0:6da5625a6946 | 170 | |
isonno |
3:0ac64c4ca40f | 171 | ClearItem( i, backColor ); |
isonno |
0:6da5625a6946 | 172 | fLCD->draw_glyph_text( foreColor, backColor, |
isonno |
0:6da5625a6946 | 173 | kIndent, (i+2) * kLineSpace, |
isonno |
0:6da5625a6946 | 174 | fLabels[i].c_str() ); |
isonno |
0:6da5625a6946 | 175 | } |
isonno |
0:6da5625a6946 | 176 | |
isonno |
3:0ac64c4ca40f | 177 | void UIMenu::DrawHeader() |
isonno |
3:0ac64c4ca40f | 178 | { |
isonno |
3:0ac64c4ca40f | 179 | if (! fDisplayOn) |
isonno |
3:0ac64c4ca40f | 180 | return; |
isonno |
3:0ac64c4ca40f | 181 | fLCD->clear( BLACK, 0, 0, 131, kLineSpace + kTopGap ); |
isonno |
3:0ac64c4ca40f | 182 | fLCD->clear( GRAY, 0, kLineSpace + kTopGap-1, 131, kLineSpace + kTopGap ); |
isonno |
3:0ac64c4ca40f | 183 | if (! fHeader.empty()) |
isonno |
3:0ac64c4ca40f | 184 | fLCD->draw_glyph_text( WHITE, BLACK, 2, kLineSpace-2, fHeader.c_str() ); |
isonno |
3:0ac64c4ca40f | 185 | } |
isonno |
3:0ac64c4ca40f | 186 | |
isonno |
0:6da5625a6946 | 187 | void UIMenu::Display( bool on ) |
isonno |
0:6da5625a6946 | 188 | { |
isonno |
0:6da5625a6946 | 189 | |
isonno |
0:6da5625a6946 | 190 | if (on) |
isonno |
0:6da5625a6946 | 191 | { |
isonno |
0:6da5625a6946 | 192 | fDisplayOn = true; |
isonno |
3:0ac64c4ca40f | 193 | DrawHeader(); |
isonno |
3:0ac64c4ca40f | 194 | |
isonno |
3:0ac64c4ca40f | 195 | int maxLines = (int)((131 - (kLineSpace + kTopGap)) / kLineSpace); |
isonno |
3:0ac64c4ca40f | 196 | |
isonno |
3:0ac64c4ca40f | 197 | int numLines = std::min( maxLines, (int)fLabels.size() ); |
isonno |
0:6da5625a6946 | 198 | |
isonno |
3:0ac64c4ca40f | 199 | for (int i = 0; i < numLines; ++i) |
isonno |
3:0ac64c4ca40f | 200 | DrawItem( i ); |
isonno |
0:6da5625a6946 | 201 | |
isonno |
3:0ac64c4ca40f | 202 | for (int i = numLines; i < maxLines; ++i ) |
isonno |
3:0ac64c4ca40f | 203 | ClearItem( i, BLACK ); |
isonno |
0:6da5625a6946 | 204 | } |
isonno |
0:6da5625a6946 | 205 | else |
isonno |
0:6da5625a6946 | 206 | fDisplayOn = false; |
isonno |
0:6da5625a6946 | 207 | } |
isonno |
0:6da5625a6946 | 208 |