-
Notifications
You must be signed in to change notification settings - Fork 58
Expand file tree
/
Copy pathmain.c
More file actions
207 lines (171 loc) · 5.19 KB
/
Copy pathmain.c
File metadata and controls
207 lines (171 loc) · 5.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/*! \file main.c
\brief Main module. This version initializes the LCD and then
drops to a low power mode, letting the WDT update the display each
quarter second, or in the handler of a keypress.
*/
#include <msp430.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "api.h"
#include "applist.h"
#include "dmesg.h"
#include "rng.h"
//! Power On Self Test
int post(){
if(LCDBIV || (LCDBCTL1&LCDNOCAPIFG)){
/* When the LCD cap is missing, of the wrong value, or
mis-soldered, the charge pump will be disabled out of
self-protection. This looks like a normally dark screen
abruptly fading to nothing, but you might still be able to
see the response at the right angle.
*/
lcd_string("lcd lcd");
printf("LCD Error.\n");
}else if(UCSCTL7&2){
/* This flag is triggered when the 32kHz crystal has a fault, such
as if it is not populated or if a little drag of solder reaches
ground. Watches with this problem will lose minutes a day, but
the '430 will fall back to an internal oscillator so that
non-watch functions still work.
*/
lcd_string(" crystal");
printf("32kHz crystal error.");
/*Can't run this test because of an unfixed errata.
}else if(has_radio && RF1AIFERR & 1){
lcd_string("RF LOWV");
*/
}else if(has_radio && RF1AIFERR & 2){
lcd_string("RF OPERR");
}else if(has_radio && RF1AIFERR & 4){
lcd_string("RFOUTERR");
}else if(has_radio && RF1AIFERR & 8){
lcd_string("RF OVERW");
}else{
/* Return zero if everything is hunky dory.
*/
lcd_string("all good");
return 0;
}
printf("POST failure.\n");
//We had a failure, indicated above.
return 1;
}
//! Main method.
int main(void) {
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
//Initialize the various modules.
dmesg_init();
printf("Firmware git version %s\n", GITHASH_STR);
printf("RNG ");
srand(true_rand()); // we do this as early as possible, because it messes with clocks
printf("REF ");
ref_init();
printf("LCD ");
lcd_init();
lcd_zero();
printf("rtc ");
lcd_string("RTC INIT");
rtc_init();
lcd_zero();
printf("osc ");
lcd_string("OSC INIT");
ucs_init();
//Recognize the CPU model.
descriptor_dump();
lcd_zero();
printf("buzz ");
lcd_string("BUZZINIT");
buzz_init();
/* Startup tones kill the watch in low battery.
tone(NOTE_C7, 500);
tone(NOTE_E7, 500);
tone(NOTE_G7, 500);
tone(NOTE_A8, 500);
tone(NOTE_C8, 500);
*/
lcd_zero();
printf("cp ");
lcd_string("CP INIT");
codeplug_init();
lcd_zero();
printf("rad ");
lcd_string("RAD INIT");
radio_init();
printf("Beginning POST.\n");
lcd_string("POSTPOST");
// Run the POST until it passes.
while(post());
//Finally we initialize the application.
lcd_zero();
lcd_string("APP INIT");
app_init();
//Keys and buttons are initialized *after* the application.
printf("key ");
key_init();
printf("but ");
sidebutton_init();
//Unused IO pins must be outputs.
PJDIR |= 0xF;
PJOUT &= ~0xF;
//UART must come after the sidebuttons.
uart_init();
// Setup and enable WDT 250ms, ACLK, interval timer
WDTCTL = WDT_ADLY_250;
SFRIE1 |= WDTIE;
printf("Booted.\n");
__bis_SR_register(LPM3_bits + GIE); // Enter LPM3
while(1){
/* These dots oughtn't appear in dmesg, because the main thread
ought to be paused with all processing in interrupts. If this
code executes, we've got a power management problem.
*/
printf(".");
}
}
//! Watchdog Timer interrupt service routine, calls back to handler functions.
void __attribute__ ((interrupt(WDT_VECTOR))) watchdog_timer (void) {
static int latch=0;
static int oldsec;
/* When the UART is in use, we don't want to hog interrupt time, so
we will silently return.
*/
if(uartactive)
return;
if(sidebutton_mode()){
/* So if the side button is being pressed, we increment the latch
and move to the next application. Some applications, such as
the calculator, might hijack the call, so if we are latched for
too many polling cycles, we forcibly revert to the clock
application.
*/
//Politely move to the next app if requested.
if(!(latch++)){
//lcd_zero();
app_next();
}
//Force a shift to the home if held for 4 seconds (16 polls)
if(latch>16)
app_forcehome();
/* Similarly, we'll reboot if the SET/PRGM button has been held
for 10 seconds (40 polls). We'll draw a countdown if getting
close, so there's no ambiguity as to whether the chip reset.
The other features of this button are handled within each
application's draw function.
*/
if(latch>40)
PMMCTL0 = PMMPW | PMMSWPOR;
}else{
latch=0;
}
/* The applet is drawn four times per second, except for the clock,
which is only drawn once a second. We handle double-buffering,
so that incomplete drawings won't be shown to the user, but
everything else is the app's responsibility. */
if(applet->draw!=clock_draw || (oldsec!=RTCSEC)){
oldsec=RTCSEC;
lcd_predraw();
app_draw(0); //Unforced, because it's a regular timer.
lcd_postdraw();
}
}