]> git.karo-electronics.de Git - oswald.git/blob - metawatch/mw_main.c
89b014ebe748be909e475509957392796cf23304
[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 "mw_main.h"
7
8 #include "mw_uart.h"
9 #include "mw_lcd.h"
10 #include "mw_bt.h"
11 #include "mw_adc.h"
12 #include "mw_bt.h"
13 #include "bt_hci.h"
14 #include "bt_l2cap.h"
15
16 #include "oswald_main.h"
17 #include "oswald_hal.h"
18
19 #include "bluetooth_init_cc256x.h"
20
21 unsigned int _event_src = 0;
22
23
24 static void set16mhz(void)
25 {
26         UCSCTL0 = 0x00;                 // Set lowest possible DCOx, MODx
27         UCSCTL1 = DCORSEL_5;            // Select suitable range
28         UCSCTL2 = 488 + FLLD_1;         // Set DCO Multiplier
29         UCSCTL4 = SELA__XT1CLK | SELS__DCOCLKDIV  |  SELM__DCOCLKDIV ;
30
31         // Worst-case settling time for the DCO when the DCO range bits have been 
32         // changed is n x 32 x 32 x f_FLL_reference. See UCS chapter in 5xx UG 
33         // for optimization.
34         // 32 x 32 x / f_FLL_reference (32,768 Hz) = .03125 = t_DCO_settle
35         // t_DCO_settle / (1 / 18 MHz) = 562500 = counts_DCO_settle
36   
37         // __delay_cycles(562500);  
38         int i;
39         for (i=0;i<10;i++){
40                 __delay_cycles(56250);  
41         }
42 }
43
44 static void setup_clocks(void)
45 {
46         unsigned long i;
47
48         /* use external oscillator */
49         P7SEL |= BIT0 + BIT1;
50         if ((UCSCTL6 & XT1DRIVE_3) != XT1DRIVE_3) {
51                 UCSCTL6_L |= XT1DRIVE1_L + XT1DRIVE0_L;
52         }
53         i = 50000;
54         while ((SFRIFG1 & OFIFG) && i--) {
55                 UCSCTL7 &= ~(DCOFFG + XT1LFOFFG + XT1HFOFFG + XT2OFFG);
56                 SFRIFG1 &= ~OFIFG;
57         }
58         UCSCTL6 = (UCSCTL6 & ~(XT1DRIVE_3)) |(XT1DRIVE_0);
59
60         set16mhz();
61
62         UCSCTL8 |= SMCLKREQEN;
63
64         /* enable oscillator fault NMI IRQ */
65 //      SFRIE1 = OFIE;
66 }
67
68 #if 0
69 #pragma vector=PWR_PORT_VECTOR
70 __interrupt void PWR_ISR (void)
71 {
72         /* clear all possible sources */
73         PWR_PORT_IFG &= ~(BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2 | BAT_CHARGE_PWR_BIT);
74         _event_src |= POWER_SRC_EVENT;
75         LPM3_EXIT();
76         nop();
77 }
78 #endif
79
80 static void mw_init_vibrate_pwm(void)
81 {
82 #ifdef MW_DIGITAL_V2
83         // Start with P7.3 as an output
84         P7OUT &= ~BIT3;   // Low when a digital output
85         P7SEL &= ~BIT3;   // P7 option select = false
86         P7DIR |=  BIT3;   // P7 outputs
87
88         TA1CTL = 0;
89
90         // No expansion divide
91         TA1EX0 = 0;
92
93         // do a PWM with 64 total steps.  This gives a count up of 32 and
94         // a count down of 32
95         TA1CCR0 =  31;
96
97         // Compare channel 2 is used as output
98         TA1CCTL2 = OUTMOD_6;         // PWM output mode: 6 - toggle/set
99         TA1CCR2 = 10;                // 10 is a 2/3 duty cycle
100 #endif
101 }
102
103
104 static void setup_pins(void)
105 {
106         CONFIG_SRAM_PINS();
107         CONFIGURE_BUTTON_PINS();
108 #ifdef MW_DEVBOARD_V2
109         CONFIG_LED_PINS();              // debug LEDs on devboard
110 #endif
111         DISABLE_LCD_LED();              // frontlight
112         CONFIG_DEBUG_PINS();
113         CONFIG_ACCELEROMETER_PINS();
114         // DISABLE_ACCELEROMETER_POWER(); // there is no accel. power switching!
115
116         HARDWARE_CFG_SENSE_INIT();
117
118         APPLE_CONFIG();
119         APPLE_POWER_DISABLE();
120
121         CONFIG_BT_PINS();
122         BT_CLK_REQ_CONFIG_AS_OUTPUT_LOW();
123         BT_IO1_CONFIG_AS_OUTPUT_LOW();
124         BT_IO2_CONFIG_AS_OUTPUT_LOW();
125         mw_disable_bt();
126
127         LIGHT_SENSE_INIT();
128         LIGHT_SENSOR_SHUTDOWN();
129
130         BATTERY_SENSE_INIT();
131         BATTERY_SENSE_DISABLE();
132         BAT_CHARGE_DIR &= ~(BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2 | BAT_CHARGE_PWR_BIT);
133         BAT_CHARGE_OUT |= BAT_CHARGE_PWR_BIT | BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2;                                             // pull-up
134         BAT_CHARGE_REN |= BAT_CHARGE_PWR_BIT;   // enable resistors
135         // BAT_CHARGE_IE |= BAT_CHARGE_PWR_BIT;
136         BAT_CHARGE_OUT |= BAT_CHARGE_ENABLE_PIN;        // !CE, negative logic
137         BAT_CHARGE_DIR |= BAT_CHARGE_ENABLE_PIN;
138
139         /* disable reset function, enable NMI, do not enable NMI IRQ */
140         /* to avoid accidential reset on charger clip connect */
141 #ifndef MW_DEVBOARD_V2 // but only on real watch
142         SFRRPCR &= ~SYSRSTRE;
143         SFRRPCR |= SYSNMI;
144 #endif
145 }
146
147 #pragma vector=WDT_VECTOR
148 __interrupt void WDT_ISR (void)
149 {
150         /* eventually we will do something here, not for now */
151         _event_src |= WATCHDOG_EVENT;
152         nop();
153 }
154
155 static void setup_wdt(void)
156 {
157 #if 1
158         WDTCTL = WDTPW + WDTHOLD;       // disable watchdog
159 #else
160         WDTCTL = WDT_ADLY_1000;         // 1 second timeout
161         SFRIE1 |= WDTIE;                // Enable WDT interrupt
162 #endif
163 }
164
165 #if 1
166 #pragma vector=UNMI_VECTOR
167 __interrupt void NMI_ISR (void)
168 {
169 #if defined MW_DEVBOARD_V2
170         LED7_TOGGLE();
171         debug_uart_tx_char('n');
172 #endif
173         while ((SFRIFG1 & OFIFG)) {
174                 UCSCTL7 &= ~(DCOFFG + XT1LFOFFG + XT1HFOFFG + XT2OFFG);
175                 SFRIFG1 &= ~OFIFG;
176         }
177 }
178 #endif
179
180 #pragma vector=RTC_VECTOR
181 __interrupt void RTC_ISR (void)
182 {
183         switch (RTCIV) {
184                 case RTCIV_NONE:
185                         break;
186                 case RTCIV_RTCRDYIFG:
187                 case RTCIV_RTCTEVIFG:
188                 case RTCIV_RTCAIFG:
189                 case RTCIV_RT0PSIFG:
190                         break;
191                 case RTCIV_RT1PSIFG:
192                         RTCPS1CTL &= ~RT1PSIFG;
193                         _event_src |= RTC_1HZ_EVENT;
194                         LPM3_EXIT;
195                         break;
196                 default:
197                         break;
198         };
199 }
200
201 void setup_rtc(void)
202 {
203         // stop it
204         RTCCTL01 = RTCHOLD;
205
206         // calibration
207         RTCCTL2 = 0x00 & 0x3f;
208         RTCCTL2 |= RTCCALS;
209
210         // Set the counter for RTC mode
211         RTCCTL01 |= RTCMODE;
212
213         // set 128 Hz rate for prescale 0 interrupt
214         RTCPS0CTL |= RT0IP_7;
215
216         // enable 1 pulse per second interrupt using prescale 1
217         RTCPS1CTL |= RT1IP_6 | RT1PSIE;
218
219         // 1 Hz calibration output
220         RTCCTL23 |= RTCCALF_3;
221
222         // setting the peripheral selection bit makes the other I/O control a don't care
223         // P2.4 = 1 Hz RTC calibration output
224         // Direction needs to be set as output
225         RTC_1HZ_PORT_SEL |= RTC_1HZ_BIT;  
226         RTC_1HZ_PORT_DIR |= RTC_1HZ_BIT;  
227
228         RTCYEAR = (unsigned int) 2013;
229         RTCMON = (unsigned int) 1;
230         RTCDAY = (unsigned int) 1;
231         RTCDOW = (unsigned int) 2;
232         RTCHOUR = (unsigned int) 01;
233         RTCMIN = (unsigned int) 0;
234         RTCSEC = (unsigned int) 0;
235
236         // Enable the RTC
237         RTCCTL01 &= ~RTCHOLD;
238         nop();
239 }
240
241 #if defined MW_DEVBOARD_V2
242 static void dbg_out_rtc(void)
243 {
244         char clk_str[16];
245         snprintf(clk_str, 16, "%02d:%02d.%02d %d\n", RTCHOUR, RTCMIN, RTCSEC, RTCDOW);
246         debug_uart_tx(clk_str);
247         // bt_l2cap_send_channel(0x40, clk_str, strlen(clk_str));
248 }
249 #endif
250
251 static void handle_button_event(void)
252 {
253         unsigned char _button_state = 0;
254 #if 0
255         char clk_str[16];
256         snprintf(clk_str, 16, "0x%02x\n", _button_state);
257         debug_uart_tx(clk_str);
258 #endif
259         while (_button_state != (BUTTON_PORT_IN & ALL_BUTTONS)) {
260                 __delay_cycles(562500);
261                 _button_state = (BUTTON_PORT_IN & ALL_BUTTONS);
262                 __delay_cycles(562500);
263         }
264         // BUTTON_PORT_IE |= INT_EDGE_SEL_BUTTONS;
265
266         if (_button_state & SW_A) {
267                 debug_uart_tx("switch A\n");
268                 oswald_handle_button_press(BUTTON_A);
269         }
270         if (_button_state & SW_B) {
271                 debug_uart_tx("switch B\n");
272                 oswald_handle_button_press(BUTTON_B);
273         }
274         if (_button_state & SW_C) {
275                 debug_uart_tx("switch C\n");
276                 oswald_handle_button_press(BUTTON_C);
277         }
278         if (_button_state & SW_D) {
279                 debug_uart_tx("switch D\n");
280                 oswald_handle_button_press(BUTTON_D);
281         }
282         if (_button_state & SW_E) {
283                 debug_uart_tx("switch E\n");
284                 oswald_handle_button_press(BUTTON_E);
285         }
286         if (_button_state & SW_F) {
287                 debug_uart_tx("switch F\n");
288                 oswald_handle_button_press(BUTTON_F);
289         }
290 }
291
292 void check_pwr_state(void)
293 {
294         if (BAT_CHARGE_IN & BAT_CHARGE_PWR_BIT) {
295                 BAT_CHARGE_OUT |= BAT_CHARGE_ENABLE_PIN;
296                 BAT_CHARGE_REN &= ~(BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2); // disable pull-up
297         } else {
298                 BAT_CHARGE_OUT &= ~BAT_CHARGE_ENABLE_PIN;
299                 BAT_CHARGE_REN |= BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2; // enable pull-up
300         }
301 }
302
303 static void handle_bt_uart_rx_event(void)
304 {
305         const unsigned char *rx;
306         unsigned char len, *rp, p;
307
308         rx = mw_bt_get_rx_buf(&rp, &len);
309
310         p = 0;
311         while (p < len) {
312                 p += bt_feed_packet_data(rx[(*rp+p)%BT_RX_MAX_SIZE]);
313         }
314         // all consumed
315         *rp = (*rp + len) % BT_RX_MAX_SIZE;
316 }
317
318 #if defined MW_DEVBOARD_V2
319 static void handle_uart_rx_event(void)
320 {
321         char c;
322 #ifndef CC256x_TRANSP
323         char tstr[255];
324
325         if (debug_uart_rx_char(&c)) {
326                 debug_uart_tx_char(c);
327                 if (c == 'b') {
328                         debug_uart_tx("\nenabling BT\n");
329                         mw_enable_bt();
330                 } else if (c == 'B') {
331                         debug_uart_tx("\ndisabling BT\n");
332                         mw_disable_bt();
333                 } else if (c == 'c') {
334                         debug_uart_tx("\nCharger status: ");
335                         snprintf(tstr, 16, "0x%04x 0x%04x ", BAT_CHARGE_IN, (BAT_CHARGE_IN & BAT_CHARGE_PWR_BIT));
336                         debug_uart_tx(tstr);
337                         if (BAT_CHARGE_IN & BAT_CHARGE_PWR_BIT)
338                                 debug_uart_tx("no ext pwr, ");
339                         else
340                                 debug_uart_tx("ext pwr connected, ");
341                         switch (BAT_CHARGE_IN & (BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2)) {
342                                 case BAT_CHARGE_STAT1:
343                                         debug_uart_tx("charge done\n");
344                                         break;
345                                 case BAT_CHARGE_STAT2:
346                                         debug_uart_tx("fast charge\n");
347                                         break;
348                                 case (BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2):
349                                         debug_uart_tx("suspend, sleep or fault\n");
350                                         break;
351                                 default:
352                                         debug_uart_tx("precharge\n");
353                                         break;
354                         }
355                         if (BAT_CHARGE_IN & BAT_CHARGE_ENABLE_PIN)
356                                 debug_uart_tx(" !charge\n");
357                         else
358                                 debug_uart_tx(" charge\n");
359                 } else if (c == 'd') {
360                         debug_uart_tx("charging disabled\n");
361                         BAT_CHARGE_OUT |= BAT_CHARGE_ENABLE_PIN;
362                 } else if (c == 'e') {
363                         debug_uart_tx("charging enabled\n");
364                         BAT_CHARGE_OUT &= ~BAT_CHARGE_ENABLE_PIN;
365                 } else if (c == 'l') {
366                         debug_uart_tx("backlight LED on\n");
367                         hal_lcd_set_backlight(TRUE);
368                 } else if (c == 'L') {
369                         debug_uart_tx("backlight LED off\n");
370                         hal_lcd_set_backlight(FALSE);
371                 } else if (c == 'u') {
372                         mw_lcd_update_screen();
373                 } else if (c == '+') {
374                         nop();
375                 } else if (c == '-') {
376                         nop();
377                 } else if (c == 't') {
378                         int i;
379                         debug_uart_tx("cc256x ini content:\n");
380                         for (i=0; i<16; i++) {
381                                 snprintf(tstr, 16, "0x%04x 0x%02x\n", i, cc256x_init_script[i]);
382                                 debug_uart_tx(tstr);
383                         }
384                 } else if (c == 'H') {
385                         uint8_t dclass[3];
386                         dclass[0] = BT_MW_DEVICE_CLASS & 0xff;
387                         dclass[1] = (BT_MW_DEVICE_CLASS & 0xff00) >> 8;
388                         dclass[2] = (BT_MW_DEVICE_CLASS & 0xff0000) >> 16;
389
390                         debug_uart_tx("HCI reset\n");
391                         bt_hci_cmd(HCI_HC_BB_OGF, HCI_RESET_OCF, 0, NULL);
392                         bt_hci_cmd(HCI_HC_BB_OGF, HCI_W_COD_OCF, 3, dclass);
393                 } else if (c == 'S') {
394                         debug_uart_tx("Scan enable\n");
395                         tstr[0] = HCI_BB_SCAN_INQUIRY | HCI_BB_SCAN_PAGE;
396                         bt_hci_cmd(HCI_HC_BB_OGF, HCI_W_SCAN_EN_OCF, 1, (uint8_t *)tstr);
397                 } else if (c == 'h') {
398                         RTCHOUR++;
399                         if (RTCHOUR > 23)
400                                 RTCHOUR = 0;
401                 } else if (c == 'm') {
402                         RTCMIN++;
403                         if (RTCMIN > 59)
404                                 RTCMIN = 0;
405                 } else if (c == 'N') {
406                         debug_uart_tx("Set name\n");
407                         tstr[0] = 'O';
408                         tstr[1] = 's';
409                         tstr[2] = 'w';
410                         tstr[3] = 'a';
411                         tstr[4] = 'l';
412                         tstr[5] = 'd';
413                         tstr[6] = 0x00;
414                         bt_hci_cmd(HCI_HC_BB_OGF, HCI_W_LOCAL_NAME_OCF, 0x07, (uint8_t *)tstr);
415                 } else if (c == 'R') {
416                         bt_hci_cmd(HCI_INFO_PARAM_OGF, HCI_R_BD_ADDR_OCF, 0, NULL);
417                 }
418         }
419 #endif
420 }
421 #endif
422
423 void start_timer(int cycles)
424 {
425         TA0EX0 = TAIDEX_0;
426         TA0CTL = TASSEL_1 | TACLR | MC__STOP;              // SMCLK, clear TAR
427         TA0CCTL0 = CCIE;                         // CCR0 interrupt enabled
428         TA0CCR0 = cycles;
429         TA0CTL |= MC_1;                         // Start Timer_A in continuous mode
430 }
431
432 void stop_timer(void)
433 {
434         TA0CCTL0 &= ~CCIE;                         // CCR0 interrupt enabled
435         TA0CTL = MC__STOP;                         // Start Timer_A in continuous mode
436 }
437  
438 // Timer A0 interrupt service routine
439 #pragma vector=TIMER0_A0_VECTOR
440 __interrupt void TIMER0_A0_ISR (void)
441 {
442         TA0CTL &= ~(TAIFG);
443 #if defined xMW_DEVBOARD_V2
444         LED6_TOGGLE();
445 #endif
446         _event_src |= TIMER_500MS_EVENT | TIMER_100MS_EVENT;
447         LPM3_EXIT;
448 }
449
450 uint8_t handle_event(void)
451 {
452 #if defined MW_DEVBOARD_V2
453         char tstr[64];
454 #endif
455         if (_event_src == 0)
456                 return 1;
457
458         while (_event_src != 0) {
459                 if (_event_src & WATCHDOG_EVENT) {
460                         _event_src &= ~WATCHDOG_EVENT;
461                         debug_uart_tx_char('w');
462                 } else if (_event_src & RTC_1HZ_EVENT) {
463                         _event_src &= ~RTC_1HZ_EVENT;
464                         check_pwr_state();
465                         oswald_one_second_tick();
466 #if defined MW_DEVBOARD_V2
467                         dbg_out_rtc();
468                         LED7_TOGGLE();
469 #endif
470                 } else if (_event_src & BT_UART_RCV_EVENT) {
471                         _event_src &= ~BT_UART_RCV_EVENT;
472                         handle_bt_uart_rx_event();
473                 } else if (_event_src & DBG_UART_RCV_EVENT) {
474                         _event_src &= ~DBG_UART_RCV_EVENT;
475 #if defined MW_DEVBOARD_V2
476                         handle_uart_rx_event();
477 #endif
478                 } else if (_event_src & BUTTON_EVENT) {
479                         _event_src &= ~BUTTON_EVENT;
480                         handle_button_event();
481                 } else if (_event_src & TIMER_500MS_EVENT) {
482                         _event_src &= ~TIMER_500MS_EVENT;
483                         oswald_halfsecond_tick();
484                 } else if (_event_src & TIMER_100MS_EVENT) {
485                         _event_src &= ~TIMER_100MS_EVENT;
486                         oswald_centisecond_tick();
487                 } else {
488 #if defined MW_DEVBOARD_V2
489                         snprintf(tstr, 64, "unhandled event in 0x%04x\n", _event_src);
490                         debug_uart_tx(tstr);
491 #endif
492                 }
493         }
494         return 0;
495 }
496
497 #pragma vector=BUTTON_PORT_VECTOR
498 __interrupt void BUTTON_ISR (void)
499 {
500         BUTTON_PORT_IFG &= ~ALL_BUTTONS;
501         // BUTTON_PORT_IE  &= ~INT_EDGE_SEL_BUTTONS;
502         _event_src |= BUTTON_EVENT;
503         //_button_state = (BUTTON_PORT_IN & ALL_BUTTONS);
504         LPM3_EXIT;
505 }
506
507 #if 0
508 #pragma vector=NOVECTOR
509 __interrupt void UNEXP_ISR (void)
510 {
511         debug_uart_tx("unexpected IRQ occured\n");
512 }
513 #endif
514
515
516 int main(void)
517 {
518         int idle = 0;
519
520         setup_wdt();
521         setup_pins();
522         setup_clocks();
523         setup_rtc();
524
525         /* enable interrupts, we will need them! */
526         __eint();
527
528 #if defined MW_DEVBOARD_V2
529         init_debug_uart();
530         debug_uart_tx("\nOswald on MetaWatch\n");
531 #endif
532
533         mw_lcd_init();
534         mw_lcd_clear();
535         mw_lcd_update_screen();
536
537         mw_init_adc();
538         mw_init_vibrate_pwm();
539
540 #if 0
541         RTCYEAR = (unsigned int) 2013;
542         RTCMON = (unsigned int) 1;
543         RTCDAY = (unsigned int) 1;
544         RTCDOW = (unsigned int) 2;
545         RTCHOUR = (unsigned int) 01;
546         RTCMIN = (unsigned int) 0;
547         RTCSEC = (unsigned int) 0;
548 #endif
549
550         oswald_set_time(RTCHOUR, RTCMIN, RTCSEC, TRUE);
551         oswald_set_date(RTCDAY, RTCMON, RTCYEAR, TRUE);
552         oswald_init();
553
554         while (1) {
555                 /* handle pending events */
556                 if (handle_event())
557                         idle++;
558                 else
559                         idle = 0;
560
561                 /* enter LPM3 sleep mode waiting for interrupt */
562                 if (idle > 100) {
563                         idle = 0;
564                         // debug_uart_tx("z");
565                         LPM3;
566                 }
567         };
568
569 return 0;
570 }