]> git.karo-electronics.de Git - oswald.git/blob - metawatch/mw_main.c
Add modified LPM3_EXIT_ISR to work around FLL IRQ wake-up problem
[oswald.git] / metawatch / mw_main.c
1 #include <msp430.h>
2 #include <msp430xgeneric.h>
3 #include <stdio.h>
4 #include <string.h>
5
6 #include "F5xx_F6xx_Core_Lib/HAL_PMM.h"
7 #include "F5xx_F6xx_Core_Lib/HAL_UCS.h"
8
9 #include "mw_main.h"
10
11 #include "mw_uart.h"
12 #include "mw_lcd.h"
13 #include "mw_bt.h"
14 #include "mw_adc.h"
15 #include "mw_bt.h"
16 #include "mw_acc.h"
17 #include "bt_hci.h"
18 #include "bt_l2cap.h"
19
20 #include "oswald_main.h"
21 #include "oswald_hal.h"
22
23 #include "bluetooth_init_cc256x.h"
24
25 uint16_t _event_src = 0;
26
27 #define HARDWARE_REVISION_ADDRESS (0x1a07)
28
29 uint8_t GetMsp430HardwareRevision(void)
30 {
31         uint8_t *pDeviceType = (uint8_t *)(uint8_t *)HARDWARE_REVISION_ADDRESS;
32   
33         return pDeviceType[0]+'1';                         
34 }
35
36 uint8_t DetermineErrata(void)
37 {
38         uint8_t Revision = GetMsp430HardwareRevision();
39   
40         switch (Revision) {
41                 case 'F':
42                 case 'G':
43                 case 'H':
44                         return 0;
45                         break;
46                 default:
47                         return 1;
48                         break;
49         }
50 }
51
52 static void set16mhz(void)
53 {
54         UCSCTL0 = 0x00;                 // Set lowest possible DCOx, MODx
55         UCSCTL1 = DCORSEL_5;            // Select suitable range
56         UCSCTL2 = 488 + FLLD_1;         // Set DCO Multiplier
57         UCSCTL4 = SELA__XT1CLK | SELS__DCOCLKDIV  |  SELM__DCOCLKDIV ;
58
59         // Worst-case settling time for the DCO when the DCO range bits have been 
60         // changed is n x 32 x 32 x f_FLL_reference. See UCS chapter in 5xx UG 
61         // for optimization.
62         // 32 x 32 x / f_FLL_reference (32,768 Hz) = .03125 = t_DCO_settle
63         // t_DCO_settle / (1 / 18 MHz) = 562500 = counts_DCO_settle
64   
65         // __delay_cycles(562500);  
66         int i;
67         for (i=0;i<10;i++){
68                 __delay_cycles(56250);  
69         }
70 }
71
72 static unsigned char PMM15Check(void)
73 {
74   // First check if SVSL/SVML is configured for fast wake-up
75   if ((!(SVSMLCTL & SVSLE)) || ((SVSMLCTL & SVSLE) && (SVSMLCTL & SVSLFP)) ||
76       (!(SVSMLCTL & SVMLE)) || ((SVSMLCTL & SVMLE) && (SVSMLCTL & SVMLFP)))
77   { 
78     // Next Check SVSH/SVMH settings to see if settings are affected by PMM15
79     if ((SVSMHCTL & SVSHE) && (!(SVSMHCTL & SVSHFP)))
80     {
81       if ( (!(SVSMHCTL & SVSHMD)) ||
82            ((SVSMHCTL & SVSHMD) && (SVSMHCTL & SVSMHACE)) )
83         return 1; // SVSH affected configurations
84     }
85
86     if ((SVSMHCTL & SVMHE) && (!(SVSMHCTL & SVMHFP)) && (SVSMHCTL & SVSMHACE))
87       return 1; // SVMH affected configurations
88   }
89
90   return 0; // SVS/M settings not affected by PMM15
91 }
92
93 #define configCPU_CLOCK_HZ ((unsigned long) 16777216) /* 512*32768 */
94 #define configTICK_RATE_HZ ((unsigned int)1024)
95 #define ACLK_MULTIPLIER    ((unsigned int)512)
96
97 static void setup_clocks(void)
98 {
99         unsigned long i;
100
101         SetVCore(PMMCOREV_2);
102
103         /* use external oscillator */
104         P7SEL |= BIT0 + BIT1;
105
106 #if 1
107         if ((UCSCTL6 & XT1DRIVE_3) != XT1DRIVE_3) {
108                 UCSCTL6_L |= XT1DRIVE1_L + XT1DRIVE0_L;
109         }
110         i = 50000;
111         while ((SFRIFG1 & OFIFG) && i--) {
112                 UCSCTL7 &= ~(DCOFFG + XT1LFOFFG + XT1HFOFFG + XT2OFFG);
113                 SFRIFG1 &= ~OFIFG;
114         }
115         UCSCTL6 = (UCSCTL6 & ~(XT1DRIVE_3)) |(XT1DRIVE_0);
116
117         set16mhz();
118
119         UCSCTL8 |= SMCLKREQEN;
120 #else
121         // Startup LFXT1 32 kHz crystal
122         while (LFXT_Start_Timeout(XT1DRIVE_0, 50000) == UCS_STATUS_ERROR)
123                 nop();
124
125         // select the sources for the FLL reference and ACLK
126         SELECT_ACLK(SELA__XT1CLK);
127         SELECT_FLLREF(SELREF__XT1CLK);
128
129         // 512 * 32768 = 16777216 / 1024
130         Init_FLL_Settle(configCPU_CLOCK_HZ/configTICK_RATE_HZ, ACLK_MULTIPLIER);
131   
132         // Disable FLL loop control
133 //      __bis_SR_register(SCG0);
134 #endif
135         // setup for quick wake up from interrupt and
136         // minimal power consumption in sleep mode
137         DISABLE_SVSL();                         // SVS Low side is turned off
138         DISABLE_SVSL_RESET();
139   
140         DISABLE_SVML();                         // Monitor low side is turned off
141         DISABLE_SVML_INTERRUPT();
142   
143         DISABLE_SVMH();                         // Monitor high side is turned off
144         DISABLE_SVMH_INTERRUPT();
145   
146         ENABLE_SVSH();                          // SVS High side is turned on
147         ENABLE_SVSH_RESET();                    // Enable POR on SVS Event
148
149         SVSH_ENABLED_IN_LPM_FULL_PERF();        // SVS high side Full perf mode,
150                                                 // stays on in LPM3,enhanced protect
151         SVSL_ENABLED_IN_LPM_FAST_WAKE();
152
153         // Wait until high side, low side settled
154         while ((PMMIFG & SVSMLDLYIFG) == 0 && (PMMIFG & SVSMHDLYIFG) == 0)
155                 nop();
156         CLEAR_PMM_IFGS();
157
158         while (PMM15Check());
159
160         // Errata PMM17
161         if (DetermineErrata()) {
162                 *(unsigned int*)(0x0110) = 0x9602;
163                 *(unsigned int*)(0x0112) |= 0x0800;
164         }
165
166         /* enable oscillator fault NMI IRQ */
167 //      SFRIE1 = OFIE;
168 }
169
170 #if 0
171 #pragma vector=PWR_PORT_VECTOR
172 __interrupt void PWR_ISR (void)
173 {
174         /* clear all possible sources */
175         PWR_PORT_IFG &= ~(BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2 | BAT_CHARGE_PWR_BIT);
176         _event_src |= POWER_SRC_EVENT;
177         LPM3_EXIT();
178         nop();
179 }
180 #endif
181
182 static void mw_init_vibrate_pwm(void)
183 {
184 #ifdef MW_DIGITAL_V2
185         // Start with P7.3 as an output
186         P7OUT &= ~BIT3;   // Low when a digital output
187         P7SEL &= ~BIT3;   // P7 option select = false
188         P7DIR |=  BIT3;   // P7 outputs
189
190         TA1CTL = 0;
191
192         // No expansion divide
193         TA1EX0 = 0;
194
195         // do a PWM with 64 total steps.  This gives a count up of 32 and
196         // a count down of 32
197         TA1CCR0 =  31;
198
199         // Compare channel 2 is used as output
200         TA1CCTL2 = OUTMOD_6;         // PWM output mode: 6 - toggle/set
201         TA1CCR2 = 10;                // 10 is a 2/3 duty cycle
202 #endif
203 }
204
205
206 static void setup_pins(void)
207 {
208         CONFIG_SRAM_PINS();
209         CONFIGURE_BUTTON_PINS();
210 #ifdef MW_DEVBOARD_V2
211         CONFIG_LED_PINS();              // debug LEDs on devboard
212 #endif
213         DISABLE_LCD_LED();              // frontlight
214         CONFIG_DEBUG_PINS();
215         CONFIG_ACCELEROMETER_PINS();
216         //DISABLE_ACCELEROMETER_POWER(); // starts from config 5 and later
217         ENABLE_ACCELEROMETER_POWER(); // starts from config 5 and later
218
219         HARDWARE_CFG_SENSE_INIT();
220
221         APPLE_CONFIG();
222         APPLE_POWER_DISABLE();
223
224         CONFIG_BT_PINS();
225 //      BT_CLK_REQ_CONFIG_AS_OUTPUT_LOW();
226 //      BT_IO1_CONFIG_AS_OUTPUT_LOW();
227 //      BT_IO2_CONFIG_AS_OUTPUT_LOW();
228         BT_CLK_REQ_CONFIG_AS_INPUT();
229         BT_IO1_CONFIG_AS_INPUT();
230         BT_IO2_CONFIG_AS_INPUT();
231         mw_disable_bt();
232
233         LIGHT_SENSE_INIT();
234         LIGHT_SENSOR_SHUTDOWN();
235
236         BATTERY_SENSE_INIT();
237         BATTERY_SENSE_DISABLE();
238         BAT_CHARGE_DIR &= ~(BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2 | BAT_CHARGE_PWR_BIT);
239         BAT_CHARGE_OUT |= BAT_CHARGE_PWR_BIT | BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2;                                             // pull-up
240         BAT_CHARGE_REN |= BAT_CHARGE_PWR_BIT;   // enable resistors
241         // BAT_CHARGE_IE |= BAT_CHARGE_PWR_BIT;
242         BAT_CHARGE_OUT |= BAT_CHARGE_ENABLE_PIN;        // !CE, negative logic
243         BAT_CHARGE_DIR |= BAT_CHARGE_ENABLE_PIN;
244
245         /* disable reset function, enable NMI, do not enable NMI IRQ */
246         /* to avoid accidential reset on charger clip connect */
247 #ifndef MW_DEVBOARD_V2 // but only on real watch
248         SFRRPCR &= ~SYSRSTRE;
249         SFRRPCR |= SYSNMI;
250 #endif
251         /* allow debug UART */
252 /*
253         P10SEL &= ~(BIT6 | BIT7);
254         P10DIR |= BIT6 | BIT7;
255         P10OUT &= ~(BIT6 | BIT7);
256 */
257 #ifndef MW_DEVBOARD_V2
258         ENABLE_MUX_OUTPUT_CONTROL();
259 #ifdef MW_DEBUG_UART
260         MUX_OUTPUT_SELECTS_SERIAL();
261 #else
262         MUX_OUTPUT_OFF();
263 #endif
264 #endif
265 }
266
267 #pragma vector=WDT_VECTOR
268 __interrupt void WDT_ISR (void)
269 {
270         /* eventually we will do something here, not for now */
271         _event_src |= WATCHDOG_EVENT;
272         nop();
273 }
274
275 static void setup_wdt(void)
276 {
277 #if 1
278         WDTCTL = WDTPW + WDTHOLD;       // disable watchdog
279 #else
280         WDTCTL = WDT_ADLY_1000;         // 1 second timeout
281         SFRIE1 |= WDTIE;                // Enable WDT interrupt
282 #endif
283 }
284
285 #if 1
286 #pragma vector=UNMI_VECTOR
287 __interrupt void NMI_ISR (void)
288 {
289 #if defined MW_DEVBOARD_V2
290         LED7_TOGGLE();
291         debug_uart_tx_char('n');
292 #endif
293         while ((SFRIFG1 & OFIFG)) {
294                 UCSCTL7 &= ~(DCOFFG + XT1LFOFFG + XT1HFOFFG + XT2OFFG);
295                 SFRIFG1 &= ~OFIFG;
296         }
297 }
298 #endif
299
300 #pragma vector=RTC_VECTOR
301 __interrupt void RTC_ISR (void)
302 {
303         switch (RTCIV) {
304                 case RTCIV_NONE:
305                         debug_uart_tx("RTC none IRQ\n");
306                         break;
307                 case RTCIV_RTCRDYIFG:
308                 case RTCIV_RTCTEVIFG:
309                 case RTCIV_RTCAIFG:
310                 case RTCIV_RT0PSIFG:
311                         debug_uart_tx("RTC misc IRQ\n");
312                         break;
313                 case RTCIV_RT1PSIFG:
314                         RTCPS1CTL &= ~RT1PSIFG;
315                         _event_src |= RTC_1HZ_EVENT;
316                         // LPM3_EXIT;
317                         LPM3_EXIT_ISR();
318 #if defined MW_DEVBOARD_V2
319                         LED7_TOGGLE();
320 #endif
321                         break;
322                 default:
323                         break;
324         };
325 }
326
327 void setup_rtc(void)
328 {
329         // stop it
330         RTCCTL01 = RTCHOLD;
331
332         // calibration
333         RTCCTL2 = 0x00 & 0x3f;
334         RTCCTL2 |= RTCCALS;
335
336         // Set the counter for RTC mode
337         RTCCTL01 |= RTCMODE;
338
339         // set 128 Hz rate for prescale 0 interrupt
340         RTCPS0CTL |= RT0IP_7;
341
342         // enable 1 pulse per second interrupt using prescale 1
343         RTCPS1CTL |= RT1IP_6 | RT1PSIE;
344
345         // 1 Hz calibration output
346         RTCCTL23 |= RTCCALF_3;
347
348         // setting the peripheral selection bit makes the other I/O control a don't care
349         // P2.4 = 1 Hz RTC calibration output
350         // Direction needs to be set as output
351         RTC_1HZ_PORT_SEL |= RTC_1HZ_BIT;  
352         RTC_1HZ_PORT_DIR |= RTC_1HZ_BIT;  
353
354         RTCYEAR = (unsigned int) 2013;
355         RTCMON = (unsigned int) 1;
356         RTCDAY = (unsigned int) 1;
357         RTCDOW = (unsigned int) 2;
358         RTCHOUR = (unsigned int) 01;
359         RTCMIN = (unsigned int) 0;
360         RTCSEC = (unsigned int) 0;
361
362         // Enable the RTC
363         RTCCTL01 &= ~RTCHOLD;
364         nop();
365 }
366
367 #if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
368 static void dbg_out_rtc(void)
369 {
370         char clk_str[16];
371         snprintf(clk_str, 16, "%02d:%02d.%02d %d\n", RTCHOUR, RTCMIN, RTCSEC, RTCDOW);
372         debug_uart_tx(clk_str);
373 }
374 #endif
375
376 static void handle_button_event(void)
377 {
378         unsigned char _button_state = 0;
379 #if 0
380         char clk_str[16];
381         snprintf(clk_str, 16, "0x%02x\n", _button_state);
382         debug_uart_tx(clk_str);
383 #endif
384         while (_button_state != (BUTTON_PORT_IN & ALL_BUTTONS)) {
385                 __delay_cycles(562500);
386                 _button_state = (BUTTON_PORT_IN & ALL_BUTTONS);
387                 __delay_cycles(562500);
388         }
389         // BUTTON_PORT_IE |= INT_EDGE_SEL_BUTTONS;
390
391         if (_button_state & SW_A) {
392                 debug_uart_tx("switch A\n");
393                 oswald_handle_button_press(BUTTON_A);
394         }
395         if (_button_state & SW_B) {
396                 debug_uart_tx("switch B\n");
397                 oswald_handle_button_press(BUTTON_B);
398         }
399         if (_button_state & SW_C) {
400                 debug_uart_tx("switch C\n");
401                 oswald_handle_button_press(BUTTON_C);
402         }
403         if (_button_state & SW_D) {
404                 debug_uart_tx("switch D\n");
405                 oswald_handle_button_press(BUTTON_D);
406         }
407         if (_button_state & SW_E) {
408                 debug_uart_tx("switch E\n");
409                 oswald_handle_button_press(BUTTON_E);
410         }
411         if (_button_state & SW_F) {
412                 debug_uart_tx("switch F\n");
413                 oswald_handle_button_press(BUTTON_F);
414         }
415 }
416
417 void check_pwr_state(void)
418 {
419         if (BAT_CHARGE_IN & BAT_CHARGE_PWR_BIT) {
420                 BAT_CHARGE_OUT |= BAT_CHARGE_ENABLE_PIN;
421                 BAT_CHARGE_REN &= ~(BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2); // disable pull-up
422         } else {
423                 BAT_CHARGE_OUT &= ~BAT_CHARGE_ENABLE_PIN;
424                 BAT_CHARGE_REN |= BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2; // enable pull-up
425         }
426 }
427
428 static void handle_bt_uart_rx_event(void)
429 {
430         const unsigned char *rx;
431         unsigned char len, *rp, p;
432
433         rx = mw_bt_get_rx_buf(&rp, &len);
434
435         p = 0;
436         while (p < len) {
437                 p += bt_feed_packet_data(rx[(*rp+p)%BT_RX_MAX_SIZE]);
438         }
439         // all consumed
440         *rp = (*rp + len) % BT_RX_MAX_SIZE;
441 }
442
443 #if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
444 static void handle_uart_rx_event(void)
445 {
446         char c;
447 #ifndef CC256x_TRANSP
448         char tstr[255];
449
450         if (debug_uart_rx_char(&c)) {
451                 debug_uart_tx_char(c);
452                 if (c == 'a') {
453                         debug_uart_tx("\nenabling ACC\n");
454                         mw_acc_enable();
455                 } else if (c == 'A') {
456                         debug_uart_tx("\ndisabling ACC\n");
457                         mw_acc_disable();
458                 } else if (c == 'r') {
459                         int16_t x,y,z;
460                         debug_uart_tx("\nread ACC: ");
461                         mw_acc_read(&x, &y, &z);
462                         snprintf(tstr, 64, "x:%d y:%d z:%d\n", x,y,z);
463                         debug_uart_tx(tstr);
464                 } else if (c =='R') {
465                         int16_t al;
466                         al = mw_get_amblight_adc_val();
467                         snprintf(tstr, 64, "light: %d\n", al);
468                         debug_uart_tx(tstr);
469                 } else if (c == 'b') {
470                         debug_uart_tx("\nenabling BT\n");
471                         mw_enable_bt();
472                 } else if (c == 'B') {
473                         debug_uart_tx("\ndisabling BT\n");
474                         mw_disable_bt();
475                 } else if (c == 'c') {
476                         debug_uart_tx("\nCharger status: ");
477                         snprintf(tstr, 16, "0x%04x 0x%04x ", BAT_CHARGE_IN, (BAT_CHARGE_IN & BAT_CHARGE_PWR_BIT));
478                         debug_uart_tx(tstr);
479                         if (BAT_CHARGE_IN & BAT_CHARGE_PWR_BIT)
480                                 debug_uart_tx("no ext pwr, ");
481                         else
482                                 debug_uart_tx("ext pwr connected, ");
483                         switch (BAT_CHARGE_IN & (BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2)) {
484                                 case BAT_CHARGE_STAT1:
485                                         debug_uart_tx("charge done\n");
486                                         break;
487                                 case BAT_CHARGE_STAT2:
488                                         debug_uart_tx("fast charge\n");
489                                         break;
490                                 case (BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2):
491                                         debug_uart_tx("suspend, sleep or fault\n");
492                                         break;
493                                 default:
494                                         debug_uart_tx("precharge\n");
495                                         break;
496                         }
497                         if (BAT_CHARGE_IN & BAT_CHARGE_ENABLE_PIN)
498                                 debug_uart_tx(" !charge\n");
499                         else
500                                 debug_uart_tx(" charge\n");
501                 } else if (c == 'd') {
502                         debug_uart_tx("charging disabled\n");
503                         BAT_CHARGE_OUT |= BAT_CHARGE_ENABLE_PIN;
504                 } else if (c == 'e') {
505                         debug_uart_tx("charging enabled\n");
506                         BAT_CHARGE_OUT &= ~BAT_CHARGE_ENABLE_PIN;
507                 } else if (c == 'l') {
508                         debug_uart_tx("backlight LED on\n");
509                         hal_lcd_set_backlight(TRUE);
510                 } else if (c == 'L') {
511                         debug_uart_tx("backlight LED off\n");
512                         hal_lcd_set_backlight(FALSE);
513                 } else if (c == 'u') {
514                         mw_lcd_update_screen();
515                 } else if (c == '+') {
516                         nop();
517                 } else if (c == '-') {
518                         nop();
519                 } else if (c == 'H') {
520                         uint8_t dclass[3];
521                         dclass[0] = BT_MW_DEVICE_CLASS & 0xff;
522                         dclass[1] = (BT_MW_DEVICE_CLASS & 0xff00) >> 8;
523                         dclass[2] = (BT_MW_DEVICE_CLASS & 0xff0000) >> 16;
524
525                         debug_uart_tx("HCI reset\n");
526                         bt_hci_cmd(HCI_HC_BB_OGF, HCI_RESET_OCF, 0, NULL);
527                         bt_hci_cmd(HCI_HC_BB_OGF, HCI_W_COD_OCF, 3, dclass);
528                 } else if (c == 'i') {
529                         debug_uart_tx("Information:\n");
530                         debug_uart_tx("Oswald ");
531                         debug_uart_tx(MW_MAIN_VERSION);
532                         debug_uart_tx("\n");
533                         debug_uart_tx("Build #");
534                         debug_uart_tx(BUILDNO);
535                         debug_uart_tx("\n");
536                         debug_uart_tx("BT V ");
537                         debug_uart_tx(cc256x_version);
538                         debug_uart_tx("\n");
539                         debug_uart_tx("MCU Rev ");
540                         debug_uart_tx_char(GetMsp430HardwareRevision());
541                         debug_uart_tx("\n");
542                 } else if (c == 'S') {
543                         debug_uart_tx("Scan enable\n");
544                         tstr[0] = HCI_BB_SCAN_INQUIRY | HCI_BB_SCAN_PAGE;
545                         bt_hci_cmd(HCI_HC_BB_OGF, HCI_W_SCAN_EN_OCF, 1, (uint8_t *)tstr);
546                 } else if (c == 'h') {
547                         RTCHOUR++;
548                         if (RTCHOUR > 23)
549                                 RTCHOUR = 0;
550                 } else if (c == 'm') {
551                         RTCMIN++;
552                         if (RTCMIN > 59)
553                                 RTCMIN = 0;
554                 } else if (c == 'N') {
555                         debug_uart_tx("Set name\n");
556                         tstr[0] = 'O';
557                         tstr[1] = 's';
558                         tstr[2] = 'w';
559                         tstr[3] = 'a';
560                         tstr[4] = 'l';
561                         tstr[5] = 'd';
562                         tstr[6] = 0x00;
563                         bt_hci_cmd(HCI_HC_BB_OGF, HCI_W_LOCAL_NAME_OCF, 0x07, (uint8_t *)tstr);
564                 } else if (c == 'R') {
565                         bt_hci_cmd(HCI_INFO_PARAM_OGF, HCI_R_BD_ADDR_OCF, 0, NULL);
566                 }
567         }
568 #endif
569 }
570 #endif
571
572 void start_timer(int cycles)
573 {
574         TA0EX0 = TAIDEX_0;
575         TA0CTL = TASSEL_1 | TACLR | MC__STOP;   // SMCLK, clear TAR
576         TA0CCTL0 = CCIE;                        // CCR0 interrupt enabled
577         TA0CCR0 = cycles;
578         TA0CTL |= MC_1;                         // Start Timer_A in continuous mode
579 }
580
581 void stop_timer(void)
582 {
583         TA0CCTL0 &= ~CCIE;                      // CCR0 interrupt enabled
584         TA0CTL = MC__STOP;                      // Start Timer_A in continuous mode
585 }
586  
587 // Timer A0 interrupt service routine
588 #pragma vector=TIMER0_A0_VECTOR
589 __interrupt void TIMER0_A0_ISR (void)
590 {
591         TA0CTL &= ~(TAIFG);
592 #if defined xMW_DEVBOARD_V2
593         LED6_TOGGLE();
594 #endif
595         _event_src |= TIMER_500MS_EVENT | TIMER_100MS_EVENT;
596         // LPM3_EXIT;
597         LPM3_EXIT_ISR();
598 }
599
600 uint8_t handle_event(void)
601 {
602 #if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
603         char tstr[64];
604 #endif
605         if (_event_src == 0)
606                 return 1;
607
608         while (_event_src != 0) {
609                 if (_event_src & WATCHDOG_EVENT) {
610                         _event_src &= ~WATCHDOG_EVENT;
611                         debug_uart_tx_char('w');
612                 } else if (_event_src & RTC_1HZ_EVENT) {
613                         _event_src &= ~RTC_1HZ_EVENT;
614                         check_pwr_state();
615                         oswald_one_second_tick();
616 #if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
617                         dbg_out_rtc();
618 #endif
619                 } else if (_event_src & BT_UART_RCV_EVENT) {
620                         _event_src &= ~BT_UART_RCV_EVENT;
621                         handle_bt_uart_rx_event();
622                 } else if (_event_src & BT_UART_WAKEUP_EVENT) {
623                         _event_src &= ~BT_UART_WAKEUP_EVENT;
624                         bt_hci_ehcill_wake();
625                 } else if (_event_src & DBG_UART_RCV_EVENT) {
626                         _event_src &= ~DBG_UART_RCV_EVENT;
627 #if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
628                         handle_uart_rx_event();
629 #endif
630                 } else if (_event_src & BUTTON_EVENT) {
631                         _event_src &= ~BUTTON_EVENT;
632                         handle_button_event();
633                 } else if (_event_src & TIMER_500MS_EVENT) {
634                         _event_src &= ~TIMER_500MS_EVENT;
635                         oswald_halfsecond_tick();
636                 } else if (_event_src & TIMER_100MS_EVENT) {
637                         _event_src &= ~TIMER_100MS_EVENT;
638                         oswald_centisecond_tick();
639                 } else if (_event_src & ACCEL_EVENT) {
640                         _event_src &= ~ACCEL_EVENT;
641                         mw_acc_handle_irq();
642                 } else {
643 #if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
644                         snprintf(tstr, 64, "unhandled event in 0x%04x\n", _event_src);
645                         debug_uart_tx(tstr);
646 #endif
647                 }
648         }
649         return 0;
650 }
651
652 #pragma vector=BUTTON_PORT_VECTOR
653 __interrupt void BUTTON_ISR (void)
654 {
655         // LPM3_EXIT;
656         LPM3_EXIT_ISR();
657         BUTTON_PORT_IFG &= ~ALL_BUTTONS;
658         // BUTTON_PORT_IE  &= ~INT_EDGE_SEL_BUTTONS;
659         _event_src |= BUTTON_EVENT;
660         //_button_state = (BUTTON_PORT_IN & ALL_BUTTONS);
661 }
662
663 #pragma vector=PORT1_VECTOR
664 __interrupt void PORT1_GPIO_ISR (void)
665 {
666         if (P1IFG & BT_IO_CTS) {
667                 //LPM3_EXIT;
668                 LPM3_EXIT_ISR();
669                 P1IE &= ~BT_IO_CTS;
670                 P1IFG &= ~BT_IO_CTS;
671                 debug_uart_tx("BT CTS irq\n");
672                 _event_src |= BT_UART_WAKEUP_EVENT;
673                 // bt_hci_ehcill_wake();
674         } else if (P1IFG & ACCELEROMETER_INT_PIN) {
675                 //LPM3_EXIT;
676                 LPM3_EXIT_ISR();
677                 P1IFG &= ~ACCELEROMETER_INT_PIN;
678                 // debug_uart_tx("ACC irq\n");
679                 _event_src |= ACCEL_EVENT;
680         }
681 }
682
683
684 #if 0
685 #pragma vector=NOVECTOR
686 __interrupt void UNEXP_ISR (void)
687 {
688         debug_uart_tx("unexpected IRQ occured\n");
689 }
690 #endif
691
692
693 int main(void)
694 {
695         setup_wdt();
696         setup_pins();
697         setup_clocks();
698         setup_rtc();
699
700         /* enable interrupts, we will need them! */
701         __enable_interrupt();
702
703 #if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
704         init_debug_uart();
705         debug_uart_tx("\nOswald on MetaWatch\n");
706 #endif
707
708         mw_lcd_init();
709         mw_lcd_clear();
710         mw_lcd_update_screen();
711
712         mw_init_adc();
713         mw_init_vibrate_pwm();
714
715         oswald_set_time(RTCHOUR, RTCMIN, RTCSEC, TRUE);
716         oswald_set_date(RTCDAY, RTCMON, RTCYEAR, TRUE);
717         oswald_init();
718
719         while (1) {
720                 /* handle pending events */
721                 handle_event();
722
723                 /* enter LPM3 sleep mode waiting for interrupt */
724                 /* errata PMM11 + PMM12 - divide MCLK before going to sleep */
725                 if (DetermineErrata()) {
726                         MCLK_DIV(2);
727                         nop();
728                 }
729                 LPM3;
730                 nop();
731                 if (DetermineErrata()) {
732                         __delay_cycles(100);
733                         MCLK_DIV(1);
734                 }
735         };
736
737 return 0;
738 }