/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-17 22:49:36 UTC
  • Revision ID: tim@ed.am-20120517224936-0wgyem932dlq5bs4
various tweaks, a (failed) attempt to fix text reset bug and added TODO

Show diffs side-by-side

added added

removed removed

Lines of Context:
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/analogue_clock.h"
 
83
#include "modes/digital_clock.h"
 
84
#include "modes/test_pattern.h"
 
85
#include "modes/settings_mode.h"
 
86
#include "modes/info_mode.h"
 
87
#include "text.h"
 
88
#include "text_renderer.h"
 
89
#include "common.h"
85
90
 
86
91
//_____________________________________________________________________________
87
92
//                                                                         data
108
113
static int _major_mode = 0;
109
114
static int _minor_mode = 0;
110
115
 
 
116
#define SETTINGS_MODE_IDX 1
111
117
#define MAIN_MODE_IDX 0
112
118
 
113
119
#define ANALOGUE_CLOCK_IDX 0
114
120
#define DIGITAL_CLOCK_IDX 1
115
 
#define TEST_PATTERN_IDX 2
 
121
#define INFO_MODE_IDX 2
 
122
#define TEST_PATTERN_IDX 3
116
123
 
117
124
//_____________________________________________________________________________
118
125
//                                                                         code
121
128
// activate the current minor mode
122
129
void activate_minor_mode()
123
130
{
 
131
        // reset text
 
132
        Text::reset();
 
133
        leds_off();
 
134
 
 
135
        // give the mode a chance to init
124
136
        switch( _minor_mode ) {
 
137
        case ANALOGUE_CLOCK_IDX: analogue_clock_activate(); break;
125
138
        case DIGITAL_CLOCK_IDX: digital_clock_activate(); break;
126
 
        }
127
 
}
 
139
        case INFO_MODE_IDX: info_mode_activate(); break;
 
140
        }
 
141
}
 
142
 
 
143
 
 
144
// activate major mode
 
145
void activate_major_mode()
 
146
{
 
147
        // reset text
 
148
        Text::reset();
 
149
        leds_off();
 
150
 
 
151
        // reset buttons
 
152
        _button.set_press_mode( _major_mode != SETTINGS_MODE_IDX );
 
153
 
 
154
        // give the mode a chance to init
 
155
        switch( _major_mode ) {
 
156
        case MAIN_MODE_IDX: activate_minor_mode(); break;
 
157
        case SETTINGS_MODE_IDX: settings_mode_activate(); break;
 
158
        }
 
159
}
 
160
 
128
161
 
129
162
// perform button events
130
163
void do_button_events()
141
174
                                switch( _minor_mode ) {
142
175
                                case ANALOGUE_CLOCK_IDX: analogue_clock_press(); break;
143
176
                                case DIGITAL_CLOCK_IDX: digital_clock_press(); break;
 
177
                                case INFO_MODE_IDX: info_mode_press(); break;
144
178
                                }
145
179
                                break;
 
180
                        case SETTINGS_MODE_IDX: settings_mode_press(); break;
146
181
                        }
147
182
                        break;
148
183
 
150
185
                        // long press
151
186
                        switch( _major_mode ) {
152
187
                        case MAIN_MODE_IDX:
153
 
                                if( ++_minor_mode >= 3 )
 
188
                                if( ++_minor_mode >= 4 )
154
189
                                        _minor_mode = 0;
155
 
                                switch( _minor_mode ) {
156
 
                                case DIGITAL_CLOCK_IDX: digital_clock_activate(); break;
157
 
                                }
 
190
                                activate_minor_mode();
158
191
                                break;
 
192
                        case SETTINGS_MODE_IDX: settings_mode_long_press(); break;
159
193
                        }
160
194
                        break;
161
195
 
162
196
                case 3:
163
197
                        // looooong press (change major mode)
164
 
                        if( ++_major_mode > 0 )
 
198
                        if( ++_major_mode > 1 )
165
199
                                _major_mode = 0;
166
 
                        switch( _major_mode ) {
167
 
                        case MAIN_MODE_IDX: _minor_mode = 0; break;
168
 
                        }
169
 
                        activate_minor_mode();
 
200
                        activate_major_mode();
170
201
                        break;
171
202
                }
172
203
        }
185
216
        if( reset ) segment = NUM_SEGMENTS - 1 - CLOCK_SHIFT;
186
217
#endif
187
218
 
 
219
        // reset the text renderer
 
220
        TextRenderer::reset_buffer();
 
221
 
 
222
        // frame reset
 
223
        if( reset ) {
 
224
                switch( _major_mode ) {
 
225
                case MAIN_MODE_IDX:
 
226
                        switch( _minor_mode ) {
 
227
                        case ANALOGUE_CLOCK_IDX: analogue_clock_draw_reset(); break;
 
228
                        case DIGITAL_CLOCK_IDX: digital_clock_draw_reset(); break;
 
229
                        case INFO_MODE_IDX: info_mode_draw_reset(); break;
 
230
                        }
 
231
                        break;
 
232
                case SETTINGS_MODE_IDX: settings_mode_draw_reset(); break;
 
233
                }
 
234
 
 
235
                // tell the text services we're starting a new frame
 
236
                Text::draw_reset();
 
237
        }
 
238
 
188
239
        // draw
189
240
        switch( _major_mode ) {
190
241
        case MAIN_MODE_IDX:
192
243
                case ANALOGUE_CLOCK_IDX: analogue_clock_draw( segment ); break;
193
244
                case DIGITAL_CLOCK_IDX: digital_clock_draw( segment ); break;
194
245
                case TEST_PATTERN_IDX: test_pattern_draw( segment ); break;
 
246
                case INFO_MODE_IDX: info_mode_draw( segment ); break;
195
247
                }
196
248
                break;
 
249
        case SETTINGS_MODE_IDX: settings_mode_draw( segment ); break;
197
250
        }
 
251
        Text::post_draw();
 
252
 
 
253
        // draw any text that was rendered
 
254
        TextRenderer::output_buffer();
198
255
 
199
256
#if CLOCK_FORWARD
200
257
        if( ++segment >= NUM_SEGMENTS ) segment = 0;
248
305
}
249
306
 
250
307
 
251
 
// ISR to handle the pulses from the fan's tachiometer
 
308
// ISR to handle the pulses from the fan's tachometer
252
309
void fan_pulse_handler()
253
310
{
254
311
        // the fan actually sends two pulses per revolution. These pulses
268
325
// main setup
269
326
void setup()
270
327
{
271
 
        // set up an interrupt handler on pin 2 to nitice fan pulses
 
328
        // set up an interrupt handler on pin 2 to notice fan pulses
272
329
        attachInterrupt( 0, fan_pulse_handler, RISING );
273
330
        digitalWrite( 2, HIGH );
274
331
  
282
339
        static int event_times[] = { 5, 500, 4000, 0 };
283
340
        _button.set_event_times( event_times );
284
341
 
 
342
        // initialise RTC
 
343
        Time::init();
 
344
 
 
345
        // init text renderer
 
346
        TextRenderer::init();
 
347
 
285
348
        // activate the minor mode
286
 
        switch( _major_mode ) {
287
 
        case MAIN_MODE_IDX: activate_minor_mode(); break;
288
 
        }
 
349
        activate_major_mode();
289
350
}
290
351
 
291
352
 
306
367
                calculate_segment_times();
307
368
 
308
369
                // keep track of time
309
 
                Time &time = Time::get_instance();
310
 
                time.update();
 
370
                Time::update();
311
371
 
312
372
                // perform button events
313
373
                do_button_events();