738 lines
17 KiB
C
738 lines
17 KiB
C
#include <msp430.h>
|
|
#include <msp430xgeneric.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "F5xx_F6xx_Core_Lib/HAL_PMM.h"
|
|
#include "F5xx_F6xx_Core_Lib/HAL_UCS.h"
|
|
|
|
#include "mw_main.h"
|
|
|
|
#include "mw_uart.h"
|
|
#include "mw_lcd.h"
|
|
#include "mw_bt.h"
|
|
#include "mw_adc.h"
|
|
#include "mw_bt.h"
|
|
#include "mw_acc.h"
|
|
#include "bt_hci.h"
|
|
#include "bt_l2cap.h"
|
|
|
|
#include "oswald_main.h"
|
|
#include "oswald_hal.h"
|
|
|
|
#include "bluetooth_init_cc256x.h"
|
|
|
|
uint16_t _event_src = 0;
|
|
|
|
#define HARDWARE_REVISION_ADDRESS (0x1a07)
|
|
|
|
uint8_t GetMsp430HardwareRevision(void)
|
|
{
|
|
uint8_t *pDeviceType = (uint8_t *)(uint8_t *)HARDWARE_REVISION_ADDRESS;
|
|
|
|
return pDeviceType[0]+'1';
|
|
}
|
|
|
|
uint8_t DetermineErrata(void)
|
|
{
|
|
uint8_t Revision = GetMsp430HardwareRevision();
|
|
|
|
switch (Revision) {
|
|
case 'F':
|
|
case 'G':
|
|
case 'H':
|
|
return 0;
|
|
break;
|
|
default:
|
|
return 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void set16mhz(void)
|
|
{
|
|
UCSCTL0 = 0x00; // Set lowest possible DCOx, MODx
|
|
UCSCTL1 = DCORSEL_5; // Select suitable range
|
|
UCSCTL2 = 488 + FLLD_1; // Set DCO Multiplier
|
|
UCSCTL4 = SELA__XT1CLK | SELS__DCOCLKDIV | SELM__DCOCLKDIV ;
|
|
|
|
// Worst-case settling time for the DCO when the DCO range bits have been
|
|
// changed is n x 32 x 32 x f_FLL_reference. See UCS chapter in 5xx UG
|
|
// for optimization.
|
|
// 32 x 32 x / f_FLL_reference (32,768 Hz) = .03125 = t_DCO_settle
|
|
// t_DCO_settle / (1 / 18 MHz) = 562500 = counts_DCO_settle
|
|
|
|
// __delay_cycles(562500);
|
|
int i;
|
|
for (i=0;i<10;i++){
|
|
__delay_cycles(56250);
|
|
}
|
|
}
|
|
|
|
static unsigned char PMM15Check(void)
|
|
{
|
|
// First check if SVSL/SVML is configured for fast wake-up
|
|
if ((!(SVSMLCTL & SVSLE)) || ((SVSMLCTL & SVSLE) && (SVSMLCTL & SVSLFP)) ||
|
|
(!(SVSMLCTL & SVMLE)) || ((SVSMLCTL & SVMLE) && (SVSMLCTL & SVMLFP)))
|
|
{
|
|
// Next Check SVSH/SVMH settings to see if settings are affected by PMM15
|
|
if ((SVSMHCTL & SVSHE) && (!(SVSMHCTL & SVSHFP)))
|
|
{
|
|
if ( (!(SVSMHCTL & SVSHMD)) ||
|
|
((SVSMHCTL & SVSHMD) && (SVSMHCTL & SVSMHACE)) )
|
|
return 1; // SVSH affected configurations
|
|
}
|
|
|
|
if ((SVSMHCTL & SVMHE) && (!(SVSMHCTL & SVMHFP)) && (SVSMHCTL & SVSMHACE))
|
|
return 1; // SVMH affected configurations
|
|
}
|
|
|
|
return 0; // SVS/M settings not affected by PMM15
|
|
}
|
|
|
|
#define configCPU_CLOCK_HZ ((unsigned long) 16777216) /* 512*32768 */
|
|
#define configTICK_RATE_HZ ((unsigned int)1024)
|
|
#define ACLK_MULTIPLIER ((unsigned int)512)
|
|
|
|
static void setup_clocks(void)
|
|
{
|
|
unsigned long i;
|
|
|
|
SetVCore(PMMCOREV_2);
|
|
|
|
/* use external oscillator */
|
|
P7SEL |= BIT0 + BIT1;
|
|
|
|
#if 1
|
|
if ((UCSCTL6 & XT1DRIVE_3) != XT1DRIVE_3) {
|
|
UCSCTL6_L |= XT1DRIVE1_L + XT1DRIVE0_L;
|
|
}
|
|
i = 50000;
|
|
while ((SFRIFG1 & OFIFG) && i--) {
|
|
UCSCTL7 &= ~(DCOFFG + XT1LFOFFG + XT1HFOFFG + XT2OFFG);
|
|
SFRIFG1 &= ~OFIFG;
|
|
}
|
|
UCSCTL6 = (UCSCTL6 & ~(XT1DRIVE_3)) |(XT1DRIVE_0);
|
|
|
|
set16mhz();
|
|
|
|
UCSCTL8 |= SMCLKREQEN;
|
|
#else
|
|
// Startup LFXT1 32 kHz crystal
|
|
while (LFXT_Start_Timeout(XT1DRIVE_0, 50000) == UCS_STATUS_ERROR)
|
|
nop();
|
|
|
|
// select the sources for the FLL reference and ACLK
|
|
SELECT_ACLK(SELA__XT1CLK);
|
|
SELECT_FLLREF(SELREF__XT1CLK);
|
|
|
|
// 512 * 32768 = 16777216 / 1024
|
|
Init_FLL_Settle(configCPU_CLOCK_HZ/configTICK_RATE_HZ, ACLK_MULTIPLIER);
|
|
|
|
// Disable FLL loop control
|
|
// __bis_SR_register(SCG0);
|
|
#endif
|
|
// setup for quick wake up from interrupt and
|
|
// minimal power consumption in sleep mode
|
|
DISABLE_SVSL(); // SVS Low side is turned off
|
|
DISABLE_SVSL_RESET();
|
|
|
|
DISABLE_SVML(); // Monitor low side is turned off
|
|
DISABLE_SVML_INTERRUPT();
|
|
|
|
DISABLE_SVMH(); // Monitor high side is turned off
|
|
DISABLE_SVMH_INTERRUPT();
|
|
|
|
ENABLE_SVSH(); // SVS High side is turned on
|
|
ENABLE_SVSH_RESET(); // Enable POR on SVS Event
|
|
|
|
SVSH_ENABLED_IN_LPM_FULL_PERF(); // SVS high side Full perf mode,
|
|
// stays on in LPM3,enhanced protect
|
|
SVSL_ENABLED_IN_LPM_FAST_WAKE();
|
|
|
|
// Wait until high side, low side settled
|
|
while ((PMMIFG & SVSMLDLYIFG) == 0 && (PMMIFG & SVSMHDLYIFG) == 0)
|
|
nop();
|
|
CLEAR_PMM_IFGS();
|
|
|
|
while (PMM15Check());
|
|
|
|
// Errata PMM17
|
|
if (DetermineErrata()) {
|
|
*(unsigned int*)(0x0110) = 0x9602;
|
|
*(unsigned int*)(0x0112) |= 0x0800;
|
|
}
|
|
|
|
/* enable oscillator fault NMI IRQ */
|
|
// SFRIE1 = OFIE;
|
|
}
|
|
|
|
#if 0
|
|
#pragma vector=PWR_PORT_VECTOR
|
|
__interrupt void PWR_ISR (void)
|
|
{
|
|
/* clear all possible sources */
|
|
PWR_PORT_IFG &= ~(BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2 | BAT_CHARGE_PWR_BIT);
|
|
_event_src |= POWER_SRC_EVENT;
|
|
LPM3_EXIT();
|
|
nop();
|
|
}
|
|
#endif
|
|
|
|
static void mw_init_vibrate_pwm(void)
|
|
{
|
|
#ifdef MW_DIGITAL_V2
|
|
// Start with P7.3 as an output
|
|
P7OUT &= ~BIT3; // Low when a digital output
|
|
P7SEL &= ~BIT3; // P7 option select = false
|
|
P7DIR |= BIT3; // P7 outputs
|
|
|
|
TA1CTL = 0;
|
|
|
|
// No expansion divide
|
|
TA1EX0 = 0;
|
|
|
|
// do a PWM with 64 total steps. This gives a count up of 32 and
|
|
// a count down of 32
|
|
TA1CCR0 = 31;
|
|
|
|
// Compare channel 2 is used as output
|
|
TA1CCTL2 = OUTMOD_6; // PWM output mode: 6 - toggle/set
|
|
TA1CCR2 = 10; // 10 is a 2/3 duty cycle
|
|
#endif
|
|
}
|
|
|
|
|
|
static void setup_pins(void)
|
|
{
|
|
CONFIG_SRAM_PINS();
|
|
CONFIGURE_BUTTON_PINS();
|
|
#ifdef MW_DEVBOARD_V2
|
|
CONFIG_LED_PINS(); // debug LEDs on devboard
|
|
#endif
|
|
DISABLE_LCD_LED(); // frontlight
|
|
CONFIG_DEBUG_PINS();
|
|
CONFIG_ACCELEROMETER_PINS();
|
|
//DISABLE_ACCELEROMETER_POWER(); // starts from config 5 and later
|
|
ENABLE_ACCELEROMETER_POWER(); // starts from config 5 and later
|
|
|
|
HARDWARE_CFG_SENSE_INIT();
|
|
|
|
APPLE_CONFIG();
|
|
APPLE_POWER_DISABLE();
|
|
|
|
CONFIG_BT_PINS();
|
|
// BT_CLK_REQ_CONFIG_AS_OUTPUT_LOW();
|
|
// BT_IO1_CONFIG_AS_OUTPUT_LOW();
|
|
// BT_IO2_CONFIG_AS_OUTPUT_LOW();
|
|
BT_CLK_REQ_CONFIG_AS_INPUT();
|
|
BT_IO1_CONFIG_AS_INPUT();
|
|
BT_IO2_CONFIG_AS_INPUT();
|
|
mw_disable_bt();
|
|
|
|
LIGHT_SENSE_INIT();
|
|
LIGHT_SENSOR_SHUTDOWN();
|
|
|
|
BATTERY_SENSE_INIT();
|
|
BATTERY_SENSE_DISABLE();
|
|
BAT_CHARGE_DIR &= ~(BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2 | BAT_CHARGE_PWR_BIT);
|
|
BAT_CHARGE_OUT |= BAT_CHARGE_PWR_BIT | BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2; // pull-up
|
|
BAT_CHARGE_REN |= BAT_CHARGE_PWR_BIT; // enable resistors
|
|
// BAT_CHARGE_IE |= BAT_CHARGE_PWR_BIT;
|
|
BAT_CHARGE_OUT |= BAT_CHARGE_ENABLE_PIN; // !CE, negative logic
|
|
BAT_CHARGE_DIR |= BAT_CHARGE_ENABLE_PIN;
|
|
|
|
/* disable reset function, enable NMI, do not enable NMI IRQ */
|
|
/* to avoid accidential reset on charger clip connect */
|
|
#ifndef MW_DEVBOARD_V2 // but only on real watch
|
|
SFRRPCR &= ~SYSRSTRE;
|
|
SFRRPCR |= SYSNMI;
|
|
#endif
|
|
/* allow debug UART */
|
|
/*
|
|
P10SEL &= ~(BIT6 | BIT7);
|
|
P10DIR |= BIT6 | BIT7;
|
|
P10OUT &= ~(BIT6 | BIT7);
|
|
*/
|
|
#ifndef MW_DEVBOARD_V2
|
|
ENABLE_MUX_OUTPUT_CONTROL();
|
|
#ifdef MW_DEBUG_UART
|
|
MUX_OUTPUT_SELECTS_SERIAL();
|
|
#else
|
|
MUX_OUTPUT_OFF();
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
#pragma vector=WDT_VECTOR
|
|
__interrupt void WDT_ISR (void)
|
|
{
|
|
/* eventually we will do something here, not for now */
|
|
_event_src |= WATCHDOG_EVENT;
|
|
nop();
|
|
}
|
|
|
|
static void setup_wdt(void)
|
|
{
|
|
#if 1
|
|
WDTCTL = WDTPW + WDTHOLD; // disable watchdog
|
|
#else
|
|
WDTCTL = WDT_ADLY_1000; // 1 second timeout
|
|
SFRIE1 |= WDTIE; // Enable WDT interrupt
|
|
#endif
|
|
}
|
|
|
|
#if 1
|
|
#pragma vector=UNMI_VECTOR
|
|
__interrupt void NMI_ISR (void)
|
|
{
|
|
#if defined MW_DEVBOARD_V2
|
|
LED7_TOGGLE();
|
|
debug_uart_tx_char('n');
|
|
#endif
|
|
while ((SFRIFG1 & OFIFG)) {
|
|
UCSCTL7 &= ~(DCOFFG + XT1LFOFFG + XT1HFOFFG + XT2OFFG);
|
|
SFRIFG1 &= ~OFIFG;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#pragma vector=RTC_VECTOR
|
|
__interrupt void RTC_ISR (void)
|
|
{
|
|
switch (RTCIV) {
|
|
case RTCIV_NONE:
|
|
debug_uart_tx("RTC none IRQ\n");
|
|
break;
|
|
case RTCIV_RTCRDYIFG:
|
|
case RTCIV_RTCTEVIFG:
|
|
case RTCIV_RTCAIFG:
|
|
case RTCIV_RT0PSIFG:
|
|
debug_uart_tx("RTC misc IRQ\n");
|
|
break;
|
|
case RTCIV_RT1PSIFG:
|
|
RTCPS1CTL &= ~RT1PSIFG;
|
|
_event_src |= RTC_1HZ_EVENT;
|
|
// LPM3_EXIT;
|
|
LPM3_EXIT_ISR();
|
|
#if defined MW_DEVBOARD_V2
|
|
LED7_TOGGLE();
|
|
#endif
|
|
break;
|
|
default:
|
|
break;
|
|
};
|
|
}
|
|
|
|
void setup_rtc(void)
|
|
{
|
|
// stop it
|
|
RTCCTL01 = RTCHOLD;
|
|
|
|
// calibration
|
|
RTCCTL2 = 0x00 & 0x3f;
|
|
RTCCTL2 |= RTCCALS;
|
|
|
|
// Set the counter for RTC mode
|
|
RTCCTL01 |= RTCMODE;
|
|
|
|
// set 128 Hz rate for prescale 0 interrupt
|
|
RTCPS0CTL |= RT0IP_7;
|
|
|
|
// enable 1 pulse per second interrupt using prescale 1
|
|
RTCPS1CTL |= RT1IP_6 | RT1PSIE;
|
|
|
|
// 1 Hz calibration output
|
|
RTCCTL23 |= RTCCALF_3;
|
|
|
|
// setting the peripheral selection bit makes the other I/O control a don't care
|
|
// P2.4 = 1 Hz RTC calibration output
|
|
// Direction needs to be set as output
|
|
RTC_1HZ_PORT_SEL |= RTC_1HZ_BIT;
|
|
RTC_1HZ_PORT_DIR |= RTC_1HZ_BIT;
|
|
|
|
RTCYEAR = (unsigned int) 2013;
|
|
RTCMON = (unsigned int) 1;
|
|
RTCDAY = (unsigned int) 1;
|
|
RTCDOW = (unsigned int) 2;
|
|
RTCHOUR = (unsigned int) 01;
|
|
RTCMIN = (unsigned int) 0;
|
|
RTCSEC = (unsigned int) 0;
|
|
|
|
// Enable the RTC
|
|
RTCCTL01 &= ~RTCHOLD;
|
|
nop();
|
|
}
|
|
|
|
#if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
|
|
static void dbg_out_rtc(void)
|
|
{
|
|
char clk_str[16];
|
|
snprintf(clk_str, 16, "%02d:%02d.%02d %d\n", RTCHOUR, RTCMIN, RTCSEC, RTCDOW);
|
|
debug_uart_tx(clk_str);
|
|
}
|
|
#endif
|
|
|
|
static void handle_button_event(void)
|
|
{
|
|
unsigned char _button_state = 0;
|
|
#if 0
|
|
char clk_str[16];
|
|
snprintf(clk_str, 16, "0x%02x\n", _button_state);
|
|
debug_uart_tx(clk_str);
|
|
#endif
|
|
while (_button_state != (BUTTON_PORT_IN & ALL_BUTTONS)) {
|
|
__delay_cycles(562500);
|
|
_button_state = (BUTTON_PORT_IN & ALL_BUTTONS);
|
|
__delay_cycles(562500);
|
|
}
|
|
// BUTTON_PORT_IE |= INT_EDGE_SEL_BUTTONS;
|
|
|
|
if (_button_state & SW_A) {
|
|
debug_uart_tx("switch A\n");
|
|
oswald_handle_button_press(BUTTON_A);
|
|
}
|
|
if (_button_state & SW_B) {
|
|
debug_uart_tx("switch B\n");
|
|
oswald_handle_button_press(BUTTON_B);
|
|
}
|
|
if (_button_state & SW_C) {
|
|
debug_uart_tx("switch C\n");
|
|
oswald_handle_button_press(BUTTON_C);
|
|
}
|
|
if (_button_state & SW_D) {
|
|
debug_uart_tx("switch D\n");
|
|
oswald_handle_button_press(BUTTON_D);
|
|
}
|
|
if (_button_state & SW_E) {
|
|
debug_uart_tx("switch E\n");
|
|
oswald_handle_button_press(BUTTON_E);
|
|
}
|
|
if (_button_state & SW_F) {
|
|
debug_uart_tx("switch F\n");
|
|
oswald_handle_button_press(BUTTON_F);
|
|
}
|
|
}
|
|
|
|
void check_pwr_state(void)
|
|
{
|
|
if (BAT_CHARGE_IN & BAT_CHARGE_PWR_BIT) {
|
|
BAT_CHARGE_OUT |= BAT_CHARGE_ENABLE_PIN;
|
|
BAT_CHARGE_REN &= ~(BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2); // disable pull-up
|
|
} else {
|
|
BAT_CHARGE_OUT &= ~BAT_CHARGE_ENABLE_PIN;
|
|
BAT_CHARGE_REN |= BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2; // enable pull-up
|
|
}
|
|
}
|
|
|
|
static void handle_bt_uart_rx_event(void)
|
|
{
|
|
const unsigned char *rx;
|
|
unsigned char len, *rp, p;
|
|
|
|
rx = mw_bt_get_rx_buf(&rp, &len);
|
|
|
|
p = 0;
|
|
while (p < len) {
|
|
p += bt_feed_packet_data(rx[(*rp+p)%BT_RX_MAX_SIZE]);
|
|
}
|
|
// all consumed
|
|
*rp = (*rp + len) % BT_RX_MAX_SIZE;
|
|
}
|
|
|
|
#if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
|
|
static void handle_uart_rx_event(void)
|
|
{
|
|
char c;
|
|
#ifndef CC256x_TRANSP
|
|
char tstr[255];
|
|
|
|
if (debug_uart_rx_char(&c)) {
|
|
debug_uart_tx_char(c);
|
|
if (c == 'a') {
|
|
debug_uart_tx("\nenabling ACC\n");
|
|
mw_acc_enable();
|
|
} else if (c == 'A') {
|
|
debug_uart_tx("\ndisabling ACC\n");
|
|
mw_acc_disable();
|
|
} else if (c == 'r') {
|
|
int16_t x,y,z;
|
|
debug_uart_tx("\nread ACC: ");
|
|
mw_acc_read(&x, &y, &z);
|
|
snprintf(tstr, 64, "x:%d y:%d z:%d\n", x,y,z);
|
|
debug_uart_tx(tstr);
|
|
} else if (c =='R') {
|
|
int16_t al;
|
|
al = mw_get_amblight_adc_val();
|
|
snprintf(tstr, 64, "light: %d\n", al);
|
|
debug_uart_tx(tstr);
|
|
} else if (c == 'b') {
|
|
debug_uart_tx("\nenabling BT\n");
|
|
mw_enable_bt();
|
|
} else if (c == 'B') {
|
|
debug_uart_tx("\ndisabling BT\n");
|
|
mw_disable_bt();
|
|
} else if (c == 'c') {
|
|
debug_uart_tx("\nCharger status: ");
|
|
snprintf(tstr, 16, "0x%04x 0x%04x ", BAT_CHARGE_IN, (BAT_CHARGE_IN & BAT_CHARGE_PWR_BIT));
|
|
debug_uart_tx(tstr);
|
|
if (BAT_CHARGE_IN & BAT_CHARGE_PWR_BIT)
|
|
debug_uart_tx("no ext pwr, ");
|
|
else
|
|
debug_uart_tx("ext pwr connected, ");
|
|
switch (BAT_CHARGE_IN & (BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2)) {
|
|
case BAT_CHARGE_STAT1:
|
|
debug_uart_tx("charge done\n");
|
|
break;
|
|
case BAT_CHARGE_STAT2:
|
|
debug_uart_tx("fast charge\n");
|
|
break;
|
|
case (BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2):
|
|
debug_uart_tx("suspend, sleep or fault\n");
|
|
break;
|
|
default:
|
|
debug_uart_tx("precharge\n");
|
|
break;
|
|
}
|
|
if (BAT_CHARGE_IN & BAT_CHARGE_ENABLE_PIN)
|
|
debug_uart_tx(" !charge\n");
|
|
else
|
|
debug_uart_tx(" charge\n");
|
|
} else if (c == 'd') {
|
|
debug_uart_tx("charging disabled\n");
|
|
BAT_CHARGE_OUT |= BAT_CHARGE_ENABLE_PIN;
|
|
} else if (c == 'e') {
|
|
debug_uart_tx("charging enabled\n");
|
|
BAT_CHARGE_OUT &= ~BAT_CHARGE_ENABLE_PIN;
|
|
} else if (c == 'l') {
|
|
debug_uart_tx("backlight LED on\n");
|
|
hal_lcd_set_backlight(TRUE);
|
|
} else if (c == 'L') {
|
|
debug_uart_tx("backlight LED off\n");
|
|
hal_lcd_set_backlight(FALSE);
|
|
} else if (c == 'u') {
|
|
mw_lcd_update_screen();
|
|
} else if (c == '+') {
|
|
nop();
|
|
} else if (c == '-') {
|
|
nop();
|
|
} else if (c == 'H') {
|
|
uint8_t dclass[3];
|
|
dclass[0] = BT_MW_DEVICE_CLASS & 0xff;
|
|
dclass[1] = (BT_MW_DEVICE_CLASS & 0xff00) >> 8;
|
|
dclass[2] = (BT_MW_DEVICE_CLASS & 0xff0000) >> 16;
|
|
|
|
debug_uart_tx("HCI reset\n");
|
|
bt_hci_cmd(HCI_HC_BB_OGF, HCI_RESET_OCF, 0, NULL);
|
|
bt_hci_cmd(HCI_HC_BB_OGF, HCI_W_COD_OCF, 3, dclass);
|
|
} else if (c == 'i') {
|
|
debug_uart_tx("Information:\n");
|
|
debug_uart_tx("Oswald ");
|
|
debug_uart_tx(MW_MAIN_VERSION);
|
|
debug_uart_tx("\n");
|
|
debug_uart_tx("Build #");
|
|
debug_uart_tx(BUILDNO);
|
|
debug_uart_tx("\n");
|
|
debug_uart_tx("BT V ");
|
|
debug_uart_tx(cc256x_version);
|
|
debug_uart_tx("\n");
|
|
debug_uart_tx("MCU Rev ");
|
|
debug_uart_tx_char(GetMsp430HardwareRevision());
|
|
debug_uart_tx("\n");
|
|
} else if (c == 'S') {
|
|
debug_uart_tx("Scan enable\n");
|
|
tstr[0] = HCI_BB_SCAN_INQUIRY | HCI_BB_SCAN_PAGE;
|
|
bt_hci_cmd(HCI_HC_BB_OGF, HCI_W_SCAN_EN_OCF, 1, (uint8_t *)tstr);
|
|
} else if (c == 'h') {
|
|
RTCHOUR++;
|
|
if (RTCHOUR > 23)
|
|
RTCHOUR = 0;
|
|
} else if (c == 'm') {
|
|
RTCMIN++;
|
|
if (RTCMIN > 59)
|
|
RTCMIN = 0;
|
|
} else if (c == 'N') {
|
|
debug_uart_tx("Set name\n");
|
|
tstr[0] = 'O';
|
|
tstr[1] = 's';
|
|
tstr[2] = 'w';
|
|
tstr[3] = 'a';
|
|
tstr[4] = 'l';
|
|
tstr[5] = 'd';
|
|
tstr[6] = 0x00;
|
|
bt_hci_cmd(HCI_HC_BB_OGF, HCI_W_LOCAL_NAME_OCF, 0x07, (uint8_t *)tstr);
|
|
} else if (c == 'R') {
|
|
bt_hci_cmd(HCI_INFO_PARAM_OGF, HCI_R_BD_ADDR_OCF, 0, NULL);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
void start_timer(int cycles)
|
|
{
|
|
TA0EX0 = TAIDEX_0;
|
|
TA0CTL = TASSEL_1 | TACLR | MC__STOP; // SMCLK, clear TAR
|
|
TA0CCTL0 = CCIE; // CCR0 interrupt enabled
|
|
TA0CCR0 = cycles;
|
|
TA0CTL |= MC_1; // Start Timer_A in continuous mode
|
|
}
|
|
|
|
void stop_timer(void)
|
|
{
|
|
TA0CCTL0 &= ~CCIE; // CCR0 interrupt enabled
|
|
TA0CTL = MC__STOP; // Start Timer_A in continuous mode
|
|
}
|
|
|
|
// Timer A0 interrupt service routine
|
|
#pragma vector=TIMER0_A0_VECTOR
|
|
__interrupt void TIMER0_A0_ISR (void)
|
|
{
|
|
TA0CTL &= ~(TAIFG);
|
|
#if defined xMW_DEVBOARD_V2
|
|
LED6_TOGGLE();
|
|
#endif
|
|
_event_src |= TIMER_500MS_EVENT | TIMER_100MS_EVENT;
|
|
// LPM3_EXIT;
|
|
LPM3_EXIT_ISR();
|
|
}
|
|
|
|
uint8_t handle_event(void)
|
|
{
|
|
#if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
|
|
char tstr[64];
|
|
#endif
|
|
if (_event_src == 0)
|
|
return 1;
|
|
|
|
while (_event_src != 0) {
|
|
if (_event_src & WATCHDOG_EVENT) {
|
|
_event_src &= ~WATCHDOG_EVENT;
|
|
debug_uart_tx_char('w');
|
|
} else if (_event_src & RTC_1HZ_EVENT) {
|
|
_event_src &= ~RTC_1HZ_EVENT;
|
|
check_pwr_state();
|
|
oswald_one_second_tick();
|
|
#if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
|
|
dbg_out_rtc();
|
|
#endif
|
|
} else if (_event_src & BT_UART_RCV_EVENT) {
|
|
_event_src &= ~BT_UART_RCV_EVENT;
|
|
handle_bt_uart_rx_event();
|
|
} else if (_event_src & BT_UART_WAKEUP_EVENT) {
|
|
_event_src &= ~BT_UART_WAKEUP_EVENT;
|
|
bt_hci_ehcill_wake();
|
|
} else if (_event_src & DBG_UART_RCV_EVENT) {
|
|
_event_src &= ~DBG_UART_RCV_EVENT;
|
|
#if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
|
|
handle_uart_rx_event();
|
|
#endif
|
|
} else if (_event_src & BUTTON_EVENT) {
|
|
_event_src &= ~BUTTON_EVENT;
|
|
handle_button_event();
|
|
} else if (_event_src & TIMER_500MS_EVENT) {
|
|
_event_src &= ~TIMER_500MS_EVENT;
|
|
oswald_halfsecond_tick();
|
|
} else if (_event_src & TIMER_100MS_EVENT) {
|
|
_event_src &= ~TIMER_100MS_EVENT;
|
|
oswald_centisecond_tick();
|
|
} else if (_event_src & ACCEL_EVENT) {
|
|
_event_src &= ~ACCEL_EVENT;
|
|
mw_acc_handle_irq();
|
|
} else {
|
|
#if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
|
|
snprintf(tstr, 64, "unhandled event in 0x%04x\n", _event_src);
|
|
debug_uart_tx(tstr);
|
|
#endif
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#pragma vector=BUTTON_PORT_VECTOR
|
|
__interrupt void BUTTON_ISR (void)
|
|
{
|
|
// LPM3_EXIT;
|
|
LPM3_EXIT_ISR();
|
|
BUTTON_PORT_IFG &= ~ALL_BUTTONS;
|
|
// BUTTON_PORT_IE &= ~INT_EDGE_SEL_BUTTONS;
|
|
_event_src |= BUTTON_EVENT;
|
|
//_button_state = (BUTTON_PORT_IN & ALL_BUTTONS);
|
|
}
|
|
|
|
#pragma vector=PORT1_VECTOR
|
|
__interrupt void PORT1_GPIO_ISR (void)
|
|
{
|
|
if (P1IFG & BT_IO_CTS) {
|
|
//LPM3_EXIT;
|
|
LPM3_EXIT_ISR();
|
|
P1IE &= ~BT_IO_CTS;
|
|
P1IFG &= ~BT_IO_CTS;
|
|
debug_uart_tx("BT CTS irq\n");
|
|
_event_src |= BT_UART_WAKEUP_EVENT;
|
|
// bt_hci_ehcill_wake();
|
|
} else if (P1IFG & ACCELEROMETER_INT_PIN) {
|
|
//LPM3_EXIT;
|
|
LPM3_EXIT_ISR();
|
|
P1IFG &= ~ACCELEROMETER_INT_PIN;
|
|
// debug_uart_tx("ACC irq\n");
|
|
_event_src |= ACCEL_EVENT;
|
|
}
|
|
}
|
|
|
|
|
|
#if 0
|
|
#pragma vector=NOVECTOR
|
|
__interrupt void UNEXP_ISR (void)
|
|
{
|
|
debug_uart_tx("unexpected IRQ occured\n");
|
|
}
|
|
#endif
|
|
|
|
|
|
int main(void)
|
|
{
|
|
setup_wdt();
|
|
setup_pins();
|
|
setup_clocks();
|
|
setup_rtc();
|
|
|
|
/* enable interrupts, we will need them! */
|
|
__enable_interrupt();
|
|
|
|
#if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
|
|
init_debug_uart();
|
|
debug_uart_tx("\nOswald on MetaWatch\n");
|
|
#endif
|
|
|
|
mw_lcd_init();
|
|
mw_lcd_clear();
|
|
mw_lcd_update_screen();
|
|
|
|
mw_init_adc();
|
|
mw_init_vibrate_pwm();
|
|
|
|
oswald_set_time(RTCHOUR, RTCMIN, RTCSEC, TRUE);
|
|
oswald_set_date(RTCDAY, RTCMON, RTCYEAR, TRUE);
|
|
oswald_init();
|
|
|
|
while (1) {
|
|
/* handle pending events */
|
|
handle_event();
|
|
|
|
/* enter LPM3 sleep mode waiting for interrupt */
|
|
/* errata PMM11 + PMM12 - divide MCLK before going to sleep */
|
|
if (DetermineErrata()) {
|
|
MCLK_DIV(2);
|
|
nop();
|
|
}
|
|
LPM3;
|
|
nop();
|
|
if (DetermineErrata()) {
|
|
__delay_cycles(100);
|
|
MCLK_DIV(1);
|
|
}
|
|
};
|
|
|
|
return 0;
|
|
}
|