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

UIMenu.cpp

Committer:
isonno
Date:
2013-02-11
Revision:
4:cfef06d8bb96
Parent:
3:0ac64c4ca40f

File content as of revision 4:cfef06d8bb96:

//
// UIMenu - Click-knob menu implementation
//

#include "NokiaLCD.h"
#include "UIMenu.h"
#include "HoldInterrupts.h"

static Timeout gScreenTimer;

void PushKnobUI::ConnectDevices( RotaryEncoder * knob, PushButton * button )
{
    HoldInterrupts holdint();
    
    if (! knob && fKnob)    // Disconnect
    {
        fKnob->detach();
        fKnob = NULL;
    }
    if (! button && fKnobButton)
    {
        fKnobButton->detach();
        fKnobButton = NULL;
    }
    
    if (knob && !fKnob)
    {
        fKnob = knob;
        //fKnob->attach( this, &UIMenu::KnobMoved );
        AttachKnob( fKnob );
    }
    if (button && !fKnobButton)
    {
        fKnobButton = button;
        //fKnobButton->attach( this, &UIMenu::KnobPushed );
        AttachButton( fKnobButton );
    }
}

void PushKnobUI::SwitchControl( PushKnobUI * other )
{
    other->ConnectDevices( fKnob, fKnobButton );
    fKnob = NULL;
    fKnobButton = NULL;
}    
    
int32_t PushKnobUI::KnobMoved( int32_t step )
{
    printf("Knob moved %d\r\n", step );
    Wake();
    return step;
}

void PushKnobUI::KnobPushed()
{
    Wake();
    printf("Button pushed\r\n");
}

void PushKnobUI::Wake()
{
    fLCD->fade_backlight( true );
    gScreenTimer.detach();
    gScreenTimer.attach( this, &PushKnobUI::Sleep, 10 );
}

void PushKnobUI::Sleep()
{
    fLCD->fade_backlight( false );
    gScreenTimer.detach();
}

bool PushKnobUI::IsSleeping() const
{
    return ! fLCD->is_backlight_on();
}

//----------------------------------------------------

UIMenu::UIMenu( CheapLCD * lcd, const char * header, bool upMenuItem ) : PushKnobUI( lcd ),
  fHeader( header ), 
  fDisplayOn( false ), 
  fSelectedItem( kNoSelection )
{}

void UIMenu::AddItem( const char * label )
{
    fLabels.push_back( string( label ));
    if (fDisplayOn)
        Display( true );    // Refresh
}

void UIMenu::ChangeItem( int item, const char * label )
{
    if ((item > 0) && (item < fLabels.size()))
    {
        fLabels[item] = string( label );
        DrawItem( item );
    }
}

void UIMenu::ChangeHeader( const char * newHeader )
{
    fHeader = string( newHeader );
    DrawHeader();
}

int32_t UIMenu::KnobMoved( int32_t step )
{
    Wake();
    
    if (fSelectedItem == kNoSelection)
    {
        fSelectedItem = (step > 0) ? 0 : fLabels.size() - 1;
        DrawItem( fSelectedItem );
    }
    else
    {
        int lastItem = fSelectedItem;
        fSelectedItem += step;
        // Handle wrap-around
        if (fSelectedItem < 0)
            fSelectedItem = fLabels.size() - 1; 
        if (fSelectedItem == fLabels.size())
            fSelectedItem = 0;
            
        DrawItem( lastItem );
        DrawItem( fSelectedItem );
    }

    return 0;
}

void UIMenu::KnobPushed()
{
    Wake();
    printf("Selected %s\n\r", fLabels[fSelectedItem].c_str() );
}

void UIMenu::SwitchTo( UIMenu * nextMenu )
{
    Display( false );
    SwitchControl( nextMenu );
    nextMenu->Display( true );
}
    
// Parameters controlling the display layout
const int kLineSpace = 20;
const int kTopGap = 4;
const int kIndent = 12;
#define MEDGREEN 0x0A0      // "medium" green

void UIMenu::ClearItem( int i, uint32_t color )
{
    if (! fDisplayOn)
        return;

    fLCD->clear( color, 
                 0, i * kLineSpace + kLineSpace + kTopGap, 
                 131, (i+1) * kLineSpace + kLineSpace + kTopGap );
}

void UIMenu::DrawItem( int i )
{
    if (! fDisplayOn)
        return;
        
    uint32_t foreColor = WHITE;
    uint32_t backColor = (i == fSelectedItem) ? MEDGREEN : BLACK;
    
    ClearItem( i, backColor );
    fLCD->draw_glyph_text( foreColor, backColor,
                           kIndent, (i+2) * kLineSpace,
                           fLabels[i].c_str() );
}

void UIMenu::DrawHeader()
{
    if (! fDisplayOn)
        return;
    fLCD->clear( BLACK, 0, 0, 131, kLineSpace + kTopGap );
    fLCD->clear( GRAY, 0, kLineSpace + kTopGap-1, 131, kLineSpace + kTopGap );
    if (! fHeader.empty())
        fLCD->draw_glyph_text( WHITE, BLACK, 2, kLineSpace-2, fHeader.c_str() );
}

void UIMenu::Display( bool on )
{   
 
    if (on)
    {
        fDisplayOn = true;
        DrawHeader();
        
        int maxLines = (int)((131 - (kLineSpace + kTopGap)) / kLineSpace);
        
        int numLines = std::min( maxLines, (int)fLabels.size() );
        
        for (int i = 0; i < numLines; ++i)
            DrawItem( i );
        
        for (int i = numLines; i < maxLines; ++i )
            ClearItem( i, BLACK );
    }
    else
        fDisplayOn = false;
}