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