/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-09 21:36:01 UTC
  • Revision ID: tim@ed.am-20120509213601-kk1tqa9yg4xk45y9
added info mode, a '/' to the fonts and cleaned up a couple of bits

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
 
111
 
#define MAIN_MODE_IDX 0
 
116
#define MAIN_MODE_IDX 1
 
117
#define SETTINGS_MODE_IDX 0
112
118
 
113
119
#define ANALOGUE_CLOCK_IDX 0
114
120
#define DIGITAL_CLOCK_IDX 1
115
121
#define TEST_PATTERN_IDX 2
 
122
#define INFO_MODE_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
 
152
187
                        case MAIN_MODE_IDX:
153
188
                                if( ++_minor_mode >= 3 )
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
        }
198
251
 
 
252
        // draw any text that was rendered
 
253
        TextRenderer::output_buffer();
 
254
 
199
255
#if CLOCK_FORWARD
200
256
        if( ++segment >= NUM_SEGMENTS ) segment = 0;
201
257
#else
248
304
}
249
305
 
250
306
 
251
 
// ISR to handle the pulses from the fan's tachiometer
 
307
// ISR to handle the pulses from the fan's tachometer
252
308
void fan_pulse_handler()
253
309
{
254
310
        // the fan actually sends two pulses per revolution. These pulses
268
324
// main setup
269
325
void setup()
270
326
{
271
 
        // set up an interrupt handler on pin 2 to nitice fan pulses
 
327
        // set up an interrupt handler on pin 2 to notice fan pulses
272
328
        attachInterrupt( 0, fan_pulse_handler, RISING );
273
329
        digitalWrite( 2, HIGH );
274
330
  
282
338
        static int event_times[] = { 5, 500, 4000, 0 };
283
339
        _button.set_event_times( event_times );
284
340
 
 
341
        // initialise RTC
 
342
        Time::init();
 
343
 
 
344
        // init text renderer
 
345
        TextRenderer::init();
 
346
 
285
347
        // activate the minor mode
286
 
        switch( _major_mode ) {
287
 
        case MAIN_MODE_IDX: activate_minor_mode(); break;
288
 
        }
 
348
        activate_major_mode();
289
349
}
290
350
 
291
351
 
306
366
                calculate_segment_times();
307
367
 
308
368
                // keep track of time
309
 
                Time &time = Time::get_instance();
310
 
                time.update();
 
369
                Time::update();
311
370
 
312
371
                // perform button events
313
372
                do_button_events();