/elec/propeller-clock

To get this branch, use:
bzr branch http://bzr.ed.am/elec/propeller-clock

« back to all changes in this revision

Viewing changes to src/propeller-clock.cc

  • Committer: Tim Marston
  • Date: 2012-05-18 18:29:50 UTC
  • Revision ID: tim@ed.am-20120518182950-t85bn9a21n72uzm8
text messages are now individually enabled and draw()n automatically

Show diffs side-by-side

added added

removed removed

1
 
/* -*- mode: c++; compile-command: "BOARD=pro5v make"; -*- */
 
1
/* -*- mode: c++; compile-command: "make"; -*- */
2
2
/*
3
3
 * propeller-clock.ino
4
4
 *
28
28
 
29
29
 * a PC fan is wired up to a 12V power supply
30
30
 
31
 
 * the fan's SENSE (tachiometer) pin connected to pin 2 on the
32
 
   arduino.
 
31
 * the fan's SENSE (tachometer) pin connected to pin 2 on the
 
32
   Arduino.
33
33
 
34
 
 * the pins 4 to 13 on the arduino should directly drive an LED (the
 
34
 * the pins 4 to 13 on the Arduino should directly drive an LED (the
35
35
   LED on pin 4 is in the centre of the clock face and the LED on pin
36
36
   13 is at the outside.
37
37
 
38
38
 * if a longer hand (and a larger clock face) is desired, pin 4 can be
39
39
   used to indirectly drive a transistor which in turn drives several
40
 
   LEDs that turn on anf off in unison in the centre of the clock.
 
40
   LEDs that turn on and off in unison in the centre of the clock.
41
41
 
42
42
 * a button should be attached to pin 3 that grounds it when pressed.
43
43
 
44
 
 * A DS1307 remote clock is connected via I2C on analog pins 4 and 5.
 
44
 * A DS1307 remote clock is connected via I2C on analogue pins 4 and 5.
45
45
 
46
46
Implementation details:
47
47
 
50
50
 * the timing of the drawing of the clock face is recalculated with
51
51
   every rotation of the propeller.
52
52
    
53
 
 * a PC fan actually sends 2 tachiometer pulses per revolution, so the
 
53
 * a PC fan actually sends 2 tachometer pulses per revolution, so the
54
54
   software skips every other one. This means that the clock may
55
55
   appear upside-down if started with the propeller in the wrong
56
 
   position. You will need to experiment to dicsover the position that
 
56
   position. You will need to experiment to discover the position that
57
57
   the propeller must be in when starting the clock.
58
58
    
59
59
Usage instructions:
79
79
#include "button.h"
80
80
#include "time.h"
81
81
#include "Arduino.h"
82
 
#include "analogue_clock.h"
83
 
#include "digital_clock.h"
84
 
#include "test_pattern.h"
 
82
#include "modes/switcher_major_mode.h"
 
83
#include "modes/settings_major_mode.h"
 
84
#include "modes/analogue_clock_mode.h"
 
85
#include "modes/digital_clock_mode.h"
 
86
#include "modes/info_mode.h"
 
87
#include "modes/test_pattern_mode.h"
 
88
#include "text.h"
 
89
#include "text_renderer.h"
 
90
#include "common.h"
85
91
 
86
92
//_____________________________________________________________________________
87
93
//                                                                         data
104
110
// the button
105
111
static Button _button( 3 );
106
112
 
107
 
// modes
108
 
static int _major_mode = 0;
109
 
static int _minor_mode = 0;
110
 
 
111
 
#define MAIN_MODE_IDX 0
112
 
 
113
 
#define ANALOGUE_CLOCK_IDX 0
114
 
#define DIGITAL_CLOCK_IDX 1
115
 
#define TEST_PATTERN_IDX 2
 
113
// major modes
 
114
static MajorMode *_modes[ 3 ];
 
115
 
 
116
// current major mode
 
117
static int _mode = 0;
116
118
 
117
119
//_____________________________________________________________________________
118
120
//                                                                         code
119
121
 
120
 
 
121
 
// activate the current minor mode
122
 
void activate_minor_mode()
123
 
{
124
 
        switch( _minor_mode ) {
125
 
        case DIGITAL_CLOCK_IDX: digital_clock_activate(); break;
126
 
        }
127
 
}
128
 
 
129
122
// perform button events
130
123
void do_button_events()
131
124
{
136
129
                {
137
130
                case 1:
138
131
                        // short press
139
 
                        switch( _major_mode ) {
140
 
                        case MAIN_MODE_IDX:
141
 
                                switch( _minor_mode ) {
142
 
                                case ANALOGUE_CLOCK_IDX: analogue_clock_press(); break;
143
 
                                case DIGITAL_CLOCK_IDX: digital_clock_press(); break;
144
 
                                }
145
 
                                break;
146
 
                        }
 
132
                        _modes[ _mode ]->press();
147
133
                        break;
148
 
 
149
134
                case 2:
150
135
                        // long press
151
 
                        switch( _major_mode ) {
152
 
                        case MAIN_MODE_IDX:
153
 
                                if( ++_minor_mode >= 3 )
154
 
                                        _minor_mode = 0;
155
 
                                switch( _minor_mode ) {
156
 
                                case DIGITAL_CLOCK_IDX: digital_clock_activate(); break;
157
 
                                }
158
 
                                break;
159
 
                        }
 
136
                        _modes[ _mode ]->long_press();
160
137
                        break;
161
 
 
162
138
                case 3:
163
139
                        // looooong press (change major mode)
164
 
                        if( ++_major_mode > 0 )
165
 
                                _major_mode = 0;
166
 
                        switch( _major_mode ) {
167
 
                        case MAIN_MODE_IDX: _minor_mode = 0; break;
168
 
                        }
169
 
                        activate_minor_mode();
 
140
                        _modes[ _mode ]->deactivate();
 
141
                        if( !_modes[ ++_mode ] ) _mode = 0;
 
142
                        _modes[ _mode ]->activate();
170
143
                        break;
171
144
                }
172
145
        }
185
158
        if( reset ) segment = NUM_SEGMENTS - 1 - CLOCK_SHIFT;
186
159
#endif
187
160
 
 
161
        // reset the text renderer's buffer
 
162
        TextRenderer::reset_buffer();
 
163
 
 
164
        if( reset )
 
165
        {
 
166
                _modes[ _mode ]->draw_reset();
 
167
 
 
168
                // tell the text services we're starting a new frame
 
169
                Text::draw_reset();
 
170
        }
 
171
 
188
172
        // draw
189
 
        switch( _major_mode ) {
190
 
        case MAIN_MODE_IDX:
191
 
                switch( _minor_mode ) {
192
 
                case ANALOGUE_CLOCK_IDX: analogue_clock_draw( segment ); break;
193
 
                case DIGITAL_CLOCK_IDX: digital_clock_draw( segment ); break;
194
 
                case TEST_PATTERN_IDX: test_pattern_draw( segment ); break;
195
 
                }
196
 
                break;
197
 
        }
 
173
        _modes[ _mode ]->draw( segment );
 
174
 
 
175
        // draw text
 
176
        Text::draw( segment );
 
177
 
 
178
        // draw text rednerer's buffer
 
179
        TextRenderer::output_buffer();
198
180
 
199
181
#if CLOCK_FORWARD
200
182
        if( ++segment >= NUM_SEGMENTS ) segment = 0;
248
230
}
249
231
 
250
232
 
251
 
// ISR to handle the pulses from the fan's tachiometer
 
233
// ISR to handle the pulses from the fan's tachometer
252
234
void fan_pulse_handler()
253
235
{
254
236
        // the fan actually sends two pulses per revolution. These pulses
268
250
// main setup
269
251
void setup()
270
252
{
271
 
        // set up an interrupt handler on pin 2 to nitice fan pulses
 
253
        // set up an interrupt handler on pin 2 to notice fan pulses
272
254
        attachInterrupt( 0, fan_pulse_handler, RISING );
273
255
        digitalWrite( 2, HIGH );
274
256
  
282
264
        static int event_times[] = { 5, 500, 4000, 0 };
283
265
        _button.set_event_times( event_times );
284
266
 
285
 
        // activate the minor mode
286
 
        switch( _major_mode ) {
287
 
        case MAIN_MODE_IDX: activate_minor_mode(); break;
288
 
        }
 
267
        // initialise RTC
 
268
//      Time::load_time();
 
269
 
 
270
        // init text renderer
 
271
        TextRenderer::init();
 
272
 
 
273
        // reset text
 
274
        Text::reset();
 
275
        leds_off();
 
276
 
 
277
        static SwitcherMajorMode switcher;
 
278
        static SettingsMajorMode settings( _button );
 
279
 
 
280
        // add major modes
 
281
        int mode = 0;
 
282
        _modes[ mode++ ] = &switcher;
 
283
        _modes[ mode++ ] = &settings;
 
284
        _modes[ mode ] = 0;
 
285
 
 
286
        // activate the current major mode
 
287
        _modes[ _mode ]->activate();
289
288
}
290
289
 
291
290
 
306
305
                calculate_segment_times();
307
306
 
308
307
                // keep track of time
309
 
                Time &time = Time::get_instance();
310
 
                time.update();
 
308
                Time::update();
311
309
 
312
310
                // perform button events
313
311
                do_button_events();