void selftest(void) { emu_inhibit_gui = 1; emu_timestamp(); printf("selftesting: 0.5 sec sleep\n"); Timer0_A4_Delay(16000); emu_timestamp(); printf("once more 0.5 sec sleep...\n"); Timer0_A4_Delay(16000); emu_timestamp(); printf("ok\n"); test_keys(); emu_inhibit_gui = 0; }
// ************************************************************************************************* // @fn main // @brief Main routine // @param none // @return none // ************************************************************************************************* int main(void) { LED_On(); // Init MCU init_application(); // Assign initial value to global variables init_global_variables(); //timestampInit(1396556875); // Main control loop: wait in low power mode until some event needs to be processed while (1) { // Do the SHM specific stuff here. shmApp(); // Now for the predetermined time we should sleep here... P1OUT ^= 0x01; uint8_t i = 3; while (i--) { Timer0_A4_Delay(CONV_MS_TO_TICKS(1000)); } } }
// ************************************************************************************************* // @fn bmp_ps_init // @brief Init pressure sensor I/O // @param none // @return none // ************************************************************************************************* void i2c_init(void) { I2C_OUT |= SCL_PIN + SDA_PIN; // SCL and SDA are high by default I2C_DIR |= SCL_PIN + SDA_PIN; // SCL and SDA are outputs by default // 100msec delay to guarantee stable operation Timer0_A4_Delay(CONV_MS_TO_TICKS(100)); }
// ************************************************************************************************* // @fn simpliciti_main_sync // @brief Send ready-to-receive packets in regular intervals. Listen shortly for host reply. // Decode received host command and trigger action. // @param none // @return none // ************************************************************************************************* void simpliciti_main_sync(void) { uint8_t len, i; uint8_t ed_data[2]; while (1) { // Sleep 0.5sec between ready-to-receive packets // SimpliciTI has no low power delay function, so we have to use ours Timer0_A4_Delay(CONV_MS_TO_TICKS(500)); // Get radio ready. Radio wakes up in IDLE state. SMPL_Ioctl(IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_AWAKE, 0); // Send 2 byte long ready-to-receive packet to stimulate host reply ed_data[0] = SYNC_ED_TYPE_R2R; ed_data[1] = 0xCB; SMPL_SendOpt(sLinkID1, ed_data, 2, SMPL_TXOPTION_NONE); // Wait shortly for host reply SMPL_Ioctl(IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_RXON, 0); NWK_DELAY(10); // Check if a command packet was received while (SMPL_Receive(sLinkID1, simpliciti_data, &len) == SMPL_SUCCESS) { // Decode received data if (len > 0) { // Use callback function in application to decode data and react simpliciti_sync_decode_ap_cmd_callback(); // Get reply data and send out reply packet burst (19 bytes each) for (i = 0; i < simpliciti_reply_count; i++) { NWK_DELAY(10); simpliciti_sync_get_data_callback(i); SMPL_SendOpt(sLinkID1, simpliciti_data, BM_SYNC_DATA_LENGTH, SMPL_TXOPTION_NONE); } } } // Put radio back to sleep SMPL_Ioctl(IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_SLEEP, 0); // Service watchdog WDTCTL = WDTPW + WDTIS__512K + WDTSSEL__ACLK + WDTCNTCL; // Exit when flag bit SIMPLICITI_TRIGGER_STOP is set if (getFlag(simpliciti_flag, SIMPLICITI_TRIGGER_STOP)) { // Clean up SimpliciTI stack to enable restarting sInit_done = 0; break; } } }
// ************************************************************************************************* // @fn cma_as_start // @brief Power-up and initialize acceleration sensor // @param none // @return none // ************************************************************************************************* void cma_as_start(void) { volatile uint16_t Counter_uint16_t; uint8_t bConfig; // Initialize SPI interface to acceleration sensor AS_SPI_CTL0 |= UCSYNC | UCMST | UCMSB // SPI master, 8 data bits, MSB first, | UCCKPH; // clock idle low, data output on falling // edge AS_SPI_CTL1 |= UCSSEL1; // SMCLK as clock source AS_SPI_BR0 = CMA_AS_BR_DIVIDER; // Low byte of division factor for baud rate AS_SPI_BR1 = 0x00; // High byte of division factor for baud // rate AS_SPI_CTL1 &= ~UCSWRST; // Start SPI hardware // Configure interface pins as_start(); // Configure sensor and start to sample data #if (CMA_AS_RANGE == 2) bConfig = 0x80; # if (CMA_AS_SAMPLE_RATE == 100) bConfig |= 0x02; # elif (CMA_AS_SAMPLE_RATE == 400) bConfig |= 0x04; # else # error "Sample rate not supported" # endif #elif (CMA_AS_RANGE == 8) bConfig = 0x00; # if (CMA_AS_SAMPLE_RATE == 40) bConfig |= 0x06; # elif (CMA_AS_SAMPLE_RATE == 100) bConfig |= 0x02; # elif (CMA_AS_SAMPLE_RATE == 400) bConfig |= 0x04; # else # error "Sample rate not supported" # endif #else # error "Measurement range not supported" #endif // Reset sensor cma_as_write_register(0x04, 0x02); cma_as_write_register(0x04, 0x0A); cma_as_write_register(0x04, 0x04); // Wait 5 ms before starting sensor output Timer0_A4_Delay(CONV_MS_TO_TICKS(5)); // Set 2g measurement range, start to output data with 100Hz rate cma_as_write_register(0x02, bConfig); }
// ************************************************************************************************* // @fn start_simpliciti_sync // @brief Start SimpliciTI (sync mode). // @param none // @return none // ************************************************************************************************* void start_simpliciti_sync(void) { // Clear LINE1 clear_line(LINE1); fptr_lcd_function_line1(LINE1, DISPLAY_LINE_CLEAR); // Stop data logging and close session stop_datalog(); // Turn on beeper icon to show activity display_symbol(LCD_ICON_BEEPER1, SEG_ON_BLINK_ON); display_symbol(LCD_ICON_BEEPER2, SEG_ON_BLINK_ON); display_symbol(LCD_ICON_BEEPER3, SEG_ON_BLINK_ON); // Prepare radio for RF communication open_radio(); // Set SimpliciTI mode sRFsmpl.mode = SIMPLICITI_SYNC; // Set SimpliciTI timeout to save battery power sRFsmpl.timeout = SIMPLICITI_TIMEOUT; // Start SimpliciTI stack. Try to link to access point. // Exit with timeout or by a DOWN button press. if (simpliciti_link()) { // Enter sync routine. This will send ready-to-receive packets at regular intervals to the // access point. // The access point always replies a command (NOP if no other command is set) simpliciti_main_sync(); } // Set SimpliciTI state to OFF sRFsmpl.mode = SIMPLICITI_OFF; // Powerdown radio close_radio(); // Clear last button events Timer0_A4_Delay(CONV_MS_TO_TICKS(BUTTONS_DEBOUNCE_TIME_OUT)); BUTTONS_IFG = 0x00; button.all_flags = 0; // Clear icons display_symbol(LCD_ICON_BEEPER1, SEG_OFF_BLINK_OFF); display_symbol(LCD_ICON_BEEPER2, SEG_OFF_BLINK_OFF); display_symbol(LCD_ICON_BEEPER3, SEG_OFF_BLINK_OFF); // Force full display update display.flag.full_update = 1; }
// ************************************************************************************************* // @fn bmp_ps_init // @brief Init pressure sensor I/O // @param none // @return none // ************************************************************************************************* void ps_init(void) { PS_INT_DIR &= ~PS_INT_PIN; // EOC is input PS_INT_IES &= ~PS_INT_PIN; // Interrupt on EOC rising edge PS_I2C_OUT |= PS_SCL_PIN + PS_SDA_PIN; // SCL and SDA are high by default PS_I2C_DIR |= PS_SCL_PIN + PS_SDA_PIN; // SCL and SDA are outputs by default // Reset global ps_ok flag ps_ok = 0; // 100msec delay to guarantee stable operation Timer0_A4_Delay(CONV_MS_TO_TICKS(100)); }
// ************************************************************************************************* // @fn adc12_single_conversion // @brief Init ADC12. Do single conversion. Turn off ADC12. // @param none // @return none // ************************************************************************************************* u16 adc12_single_conversion(u16 ref, u16 sht, u16 channel) { // Initialize the shared reference module REFCTL0 |= REFMSTR + ref + REFON; // Enable internal reference (1.5V or 2.5V) // Initialize ADC12_A ADC12CTL0 = sht + ADC12ON; // Set sample time ADC12CTL1 = ADC12SHP; // Enable sample timer ADC12MCTL0 = ADC12SREF_1 + channel; // ADC input channel ADC12IE = 0x001; // ADC_IFG upon conv result-ADCMEMO // Wait 2 ticks (66us) to allow internal reference to settle Timer0_A4_Delay(2); // Start ADC12 ADC12CTL0 |= ADC12ENC; // Clear data ready flag adc12_data_ready = 0; // Sampling and conversion start ADC12CTL0 |= ADC12SC; // Wait until ADC12 has finished Timer0_A4_Delay(5); while (!adc12_data_ready); // Shut down ADC12 ADC12CTL0 &= ~(ADC12ENC | ADC12SC | sht); ADC12CTL0 &= ~ADC12ON; // Shut down reference voltage REFCTL0 &= ~(REFMSTR + ref + REFON); ADC12IE = 0; // Return ADC result return (adc12_result); }
// ************************************************************************************************* // @fn CW_Send_Char // @brief Send (via the buzzer) an alphanumeric character ("letter") // @param letter character to send, in range 39 (''') to 90 ('Z'), inclusive // @return none // ************************************************************************************************* void CW_Send_Char(u8 letter) { if ((letter >= 39) && (letter <= 90)) { // In range letter = CW_Char[letter - 39]; // Get first "letter" //gibbons TODO: check if '=' operator or memcpy(...) is more appropriate } else if (letter == ' ') { // Send space (inter-word pause) Timer0_A4_Delay(CONV_MS_TO_TICKS(CW_WORD_PAUSE * CW_DOT_LENGTH)); return; } else { // Invalid character return; } int i = 0x80; // Mask bit, starting at 0x80 = 1000 0000b while (i > letter) i >>= 1; // Find start bit i >>= 1; // Needed to skip over start bit, otherwise all letters start with an extra DASH! while (i > 0) { if (i & letter) { // Send dash (and pause after it) start_buzzer(1, CONV_MS_TO_TICKS(3*CW_DOT_LENGTH), CONV_MS_TO_TICKS(CW_SIGNAL_PAUSE * CW_DOT_LENGTH)); } else { // Send dot (and pause after it) start_buzzer(1, CONV_MS_TO_TICKS(CW_DOT_LENGTH), CONV_MS_TO_TICKS(CW_SIGNAL_PAUSE * CW_DOT_LENGTH)); } i >>= 1; // Move mask bit to the right one // Wait until finished buzzing while (is_buzzer()) { Timer0_A4_Delay(CONV_MS_TO_TICKS(2*CW_DOT_LENGTH)); // Go into LPM3 } } // Now send inter-letter pause (space between successive letters) Timer0_A4_Delay(CONV_MS_TO_TICKS(CW_LETTER_PAUSE * CW_DOT_LENGTH)); // Clean up display display.flag.full_update = 1; }
// ************************************************************************************************* // @fn mx_rfblue // @brief BlueRobin sub menu. Button STAR resets chest strap ID to 0 and searches for next chest strap in range. // @param u8 line LINE2 // @return none // ************************************************************************************************* void mx_bluerobin(u8 line) { #if REMEMBER_TX_ID == TRUE u8 i; // Reset chest strap ID sBlueRobin.cs_id = 0; display_chars(LCD_SEG_L1_2_0, (u8*)"CLR", SEG_ON); for (i=0; i<4; i++) Timer0_A4_Delay(CONV_MS_TO_TICKS(500)); #endif // Clear simulated button event button.all_flags = 0; }
// ************************************************************************************************* // @fn as_start // @brief Power-up and initialize acceleration sensor // @param none // @return none // ************************************************************************************************* void as_start(void) { // Initialize interrupt pin for data read out from acceleration sensor AS_INT_IES &= ~AS_INT_PIN; // Interrupt on rising edge // Enable interrupt AS_INT_DIR &= ~AS_INT_PIN; // Switch INT pin to input AS_SPI_DIR &= ~AS_SDI_PIN; // Switch SDI pin to input AS_SPI_REN |= AS_SDI_PIN; // Pulldown on SDI pin AS_SPI_SEL |= AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN; // Port pins to SDO, SDI and SCK function AS_CSN_OUT |= AS_CSN_PIN; // Deselect acceleration sensor AS_PWR_OUT |= AS_PWR_PIN; // Power on active high // Delay of >5ms required between switching on power and configuring sensor Timer0_A4_Delay(CONV_MS_TO_TICKS(10)); // Initialize interrupt pin for data read out from acceleration sensor AS_INT_IFG &= ~AS_INT_PIN; // Reset flag AS_INT_IE |= AS_INT_PIN; // Enable interrupt }
void sx_gate (u8 line) { u16 i; if (button.flag.down) { display_symbol (LCD_ICON_BEEPER1, SEG_ON); open_radio(); gate_init(); for(i=0;i<50;i++) { GATE_Transmit(open, GATE_SETTING_PKTLEN); Timer0_A4_Delay(CONV_MS_TO_TICKS(11)); } close_radio(); display_symbol (LCD_ICON_BEEPER1, SEG_OFF); } else { } }
// ************************************************************************************************* // @fn start_altitude_measurement // @brief Start altitude measurement // @param none // @return none // ************************************************************************************************* void start_altitude_measurement(void) { u8 timeout = 15; // Already on? if (sAlt.on) return; // Show warning if pressure sensor was not initialised properly if (!ps_ok) { display_chars(LCD_SEG_L1_2_0, (u8 *) "ERR", SEG_ON); return; } // Enable DRDY IRQ on rising edge PS_INT_IFG &= ~PS_INT_PIN; PS_INT_IE |= PS_INT_PIN; // Start pressure sensor ps_start(); // Set altitude measurement flag sAlt.on = 1; // Get updated altitude while (((PS_INT_IN & PS_INT_PIN) == 0) && (timeout > 0)) { Timer0_A4_Delay(CONV_MS_TO_TICKS(100)); timeout--; } // Failed to start? if (timeout == 0) { sAlt.on = 0; } do_altitude_measurement(FILTER_OFF); }
__interrupt void PORT2_ISR(void) { u8 int_flag, int_enable; u8 buzzer = 0; u8 simpliciti_button_event = 0; static u8 simpliciti_button_repeat = 0; // Clear button flags button.all_flags = 0; // Remember interrupt enable bits int_enable = BUTTONS_IE; // Store valid button interrupt flag int_flag = BUTTONS_IFG & int_enable; // --------------------------------------------------- // While SimpliciTI stack is active, buttons behave differently: // - Store M1/M2/S1 button events in SimpliciTI packet data // - Exit SimpliciTI when S2 was pressed if (is_rf()) { // Erase previous button press after a number of resends (increase number if link quality is low) // This will create a series of packets containing the same button press // Necessary because we have no acknowledge // Filtering (edge detection) will be done by receiver software if (simpliciti_button_repeat++ > 6) { simpliciti_data[0] &= ~0xF0; simpliciti_button_repeat = 0; } if ((int_flag & BUTTON_M1_PIN) == BUTTON_M1_PIN) { simpliciti_data[0] |= SIMPLICITI_BUTTON_M1; simpliciti_button_event = 1; } else if ((int_flag & BUTTON_M2_PIN) == BUTTON_M2_PIN) { simpliciti_data[0] |= SIMPLICITI_BUTTON_M2; simpliciti_button_event = 1; } else if ((int_flag & BUTTON_S1_PIN) == BUTTON_S1_PIN) { simpliciti_data[0] |= SIMPLICITI_BUTTON_S1; simpliciti_button_event = 1; } else if ((int_flag & BUTTON_S2_PIN) == BUTTON_S2_PIN) { simpliciti_flag |= SIMPLICITI_TRIGGER_STOP; } // Trigger packet sending inside SimpliciTI stack if (simpliciti_button_event) simpliciti_flag |= SIMPLICITI_TRIGGER_SEND_DATA; } else // Normal operation { // Debounce buttons if ((int_flag & ALL_BUTTONS) != 0) { // Disable PORT2 IRQ __disable_interrupt(); BUTTONS_IE = 0x00; __enable_interrupt(); // Debounce delay 1 Timer0_A4_Delay(CONV_MS_TO_TICKS(BUTTONS_DEBOUNCE_TIME_IN)); // Reset inactivity detection sTime.last_activity = sTime.system_time; // Reset M button high detection sTime.previous_m_button_event = sTime.system_time; } // --------------------------------------------------- // M1 button IRQ if (IRQ_TRIGGERED(int_flag, BUTTON_M1_PIN)) { // Filter bouncing noise if (BUTTON_M1_IS_PRESSED) { button.flag.m1 = 1; sys.flag.mask_m1_button = 0; // Generate button click buzzer = 1; } } // --------------------------------------------------- // M2 button IRQ else if (IRQ_TRIGGERED(int_flag, BUTTON_M2_PIN)) { // Filter bouncing noise if (BUTTON_M2_IS_PRESSED) { button.flag.m2 = 1; sys.flag.mask_m2_button = 0; // Generate button click buzzer = 1; } } // --------------------------------------------------- // S1 button IRQ else if (IRQ_TRIGGERED(int_flag, BUTTON_S1_PIN)) { // Filter bouncing noise if (BUTTON_S1_IS_PRESSED) { button.flag.s1 = 1; // Generate button click buzzer = 1; } } // --------------------------------------------------- // S2 button IRQ else if (IRQ_TRIGGERED(int_flag, BUTTON_S2_PIN)) { // Filter bouncing noise if (BUTTON_S2_IS_PRESSED) { button.flag.s2 = 1; // Generate button click buzzer = 1; // Faster reaction for stopwatch stop button press if (is_stopwatch()) { stop_stopwatch(); button.flag.s2 = 0; } } } // --------------------------------------------------- // B/L button IRQ else if (IRQ_TRIGGERED(int_flag, BUTTON_BL_PIN)) { // Filter bouncing noise if (BUTTON_BL_IS_PRESSED) { button.flag.bl = 1; } } } // Generate button click when button was activated if (buzzer) { // Any button event stops active alarm if (sAlarm.state == ALARM_ON) { stop_alarm(); button.all_flags = 0; } else if (!sys.flag.s_button_repeat_enabled) { start_buzzer(1, CONV_MS_TO_TICKS(20), CONV_MS_TO_TICKS(150)); } // Debounce delay 2 Timer0_A4_Delay(CONV_MS_TO_TICKS(BUTTONS_DEBOUNCE_TIME_OUT)); } // --------------------------------------------------- // Acceleration sensor IRQ if (IRQ_TRIGGERED(int_flag, AS_INT_PIN)) { // Get data from sensor request.flag.acceleration_measurement = 1; } // --------------------------------------------------- // Pressure sensor IRQ if (IRQ_TRIGGERED(int_flag, PS_INT_PIN)) { // Get data from sensor request.flag.altitude_measurement = 1; } // --------------------------------------------------- // Enable safe long button event detection if(button.flag.m1 || button.flag.m2) { // Additional debounce delay to enable safe high detection Timer0_A4_Delay(CONV_MS_TO_TICKS(BUTTONS_DEBOUNCE_TIME_M)); // Check if this button event is short enough if (BUTTON_M1_IS_PRESSED) button.flag.m1 = 0; if (BUTTON_M2_IS_PRESSED) button.flag.m2 = 0; } // Reenable PORT2 IRQ __disable_interrupt(); BUTTONS_IFG = 0x00; BUTTONS_IE = int_enable; __enable_interrupt(); // Exit from LPM3/LPM4 on RETI __bic_SR_register_on_exit(LPM4_bits); }
__interrupt void PORT2_ISR(void) { // Clear flags unsigned char int_flag, int_enable; unsigned char buzzer = 0; // Remember interrupt enable bits int_enable = BUTTONS_IE; if ((!button.flag.star_long) && (!button.flag.num_long)) { // Clear button flags button.all_flags = 0; // Store valid button interrupt flag int_flag = BUTTONS_IFG & int_enable; { // Debounce buttons if ((int_flag & ALL_BUTTONS) != 0) { // Disable PORT2 IRQ __disable_interrupt(); BUTTONS_IE = 0x00; __enable_interrupt(); // Debounce delay 1 Timer0_A4_Delay(CONV_MS_TO_TICKS(BUTTONS_DEBOUNCE_TIME_IN)); } // --------------------------------------------------- // STAR button IRQ if (IRQ_TRIGGERED(int_flag, BUTTON_STAR_PIN)) { // Filter bouncing noise if (BUTTON_STAR_IS_PRESSED) { button.flag.star = 1; button.flag.star_not_long = 0; // Generate button click buzzer = 1; } else if ((BUTTONS_IES & BUTTON_STAR_PIN) == BUTTON_STAR_PIN) { button.flag.star = 1; button.flag.star_not_long = 0; BUTTONS_IES &= ~BUTTON_STAR_PIN; } } // --------------------------------------------------- // NUM button IRQ else if (IRQ_TRIGGERED(int_flag, BUTTON_NUM_PIN)) { // Filter bouncing noise if (BUTTON_NUM_IS_PRESSED) { button.flag.num = 1; button.flag.num_not_long = 0; // Generate button click buzzer = 1; } else if ((BUTTONS_IES & BUTTON_NUM_PIN) == BUTTON_NUM_PIN) { button.flag.num = 1; button.flag.num_not_long = 0; BUTTONS_IES &= ~BUTTON_NUM_PIN; } } // --------------------------------------------------- // UP button IRQ else if (IRQ_TRIGGERED(int_flag, BUTTON_UP_PIN)) { // Filter bouncing noise if (BUTTON_UP_IS_PRESSED) { button.flag.up = 1; // Generate button click buzzer = 1; } } // --------------------------------------------------- // DOWN button IRQ else if (IRQ_TRIGGERED(int_flag, BUTTON_DOWN_PIN)) { // Filter bouncing noise if (BUTTON_DOWN_IS_PRESSED) { button.flag.down = 1; // Generate button click buzzer = 1; // Faster reaction for stopwatch stop button press if (is_stopwatch() && !sys.flag.lock_buttons) { stop_stopwatch(); button.flag.down = 0; } } } // --------------------------------------------------- // B/L button IRQ else if (IRQ_TRIGGERED(int_flag, BUTTON_BACKLIGHT_PIN)) { // Filter bouncing noise if (BUTTON_BACKLIGHT_IS_PRESSED) { sButton.backlight_status = 1; sButton.backlight_timeout = 0; P2OUT |= BUTTON_BACKLIGHT_PIN; P2DIR |= BUTTON_BACKLIGHT_PIN; } } } // Trying to lock/unlock buttons? if (button.flag.num && button.flag.down) { // No buzzer output buzzer = 0; button.all_flags = 0; } // --------------------------------------------------- // Acceleration sensor IRQ if (IRQ_TRIGGERED(int_flag, AS_INT_PIN)) { // Get data from sensor request.flag.acceleration_measurement = 1; } // --------------------------------------------------- // Safe long button event detection if (button.flag.star || button.flag.num) { // Additional debounce delay to enable safe high detection - 50ms Timer0_A4_Delay(CONV_MS_TO_TICKS(BUTTONS_DEBOUNCE_TIME_LEFT)); // Check if this button event is short enough if (BUTTON_STAR_IS_PRESSED) { // Change interrupt edge to detect button release BUTTONS_IES |= BUTTON_STAR_PIN; button.flag.star = 0; // This flag is used to detect if the user released the button before the // time for a long button press (3s) button.flag.star_not_long = 1; } if (BUTTON_NUM_IS_PRESSED) { // Change interrupt edge to detect button release BUTTONS_IES |= BUTTON_NUM_PIN; button.flag.num = 0; // This flag is used to detect if the user released the button before the // time for a long button press (3s) button.flag.num_not_long = 1; } } } // Reenable PORT2 IRQ __disable_interrupt(); BUTTONS_IFG = 0x00; BUTTONS_IE = int_enable; __enable_interrupt(); // Exit from LPM3/LPM4 on RETI __bic_SR_register_on_exit(LPM4_bits); }
// ************************************************************************************************* // @fn sx_bluerobin // @brief BlueRobin direct function. Button UP connects/disconnects with sender unit. // @param u8 line LINE1 // @return none // ************************************************************************************************* void sx_bluerobin(u8 line) { u8 stop = 0; // Exit if battery voltage is too low for radio operation if (sys.flag.low_battery) return; // Exit if SimpliciTI stack is active if (is_rf()) return; // UP: connect / disconnect transmitter if(button.flag.up) { if (sBlueRobin.state == BLUEROBIN_OFF) { // Init BlueRobin timer and radio open_radio(); // Initialize BR library BRRX_Init_v(); // Set BR data transmission properties BRRX_SetPowerdownDelay_v(10); // Power down channel after 10 consecutive lost data packets (~9 seconds) BRRX_SetSearchTimeout_v(8); // Stop searching after 8 seconds // Sensitivity in learn mode reduced --> connect only to close transmitters // Skip this part if chest strap id was set in a previous learn mode run #if REMEMBER_TX_ID == TRUE if (sBlueRobin.cs_id == 0) BRRX_SetSignalLevelReduction_v(5); #else // Forget previously learned transmitter ID and connect to next close transmitter sBlueRobin.cs_id = 0; BRRX_SetSignalLevelReduction_v(5); #endif // Apply frequency offset compensation to radio register FSCTRL0 // If calibration memory was erased, rf_frequoffset defaults to 0x00 and has no effect WriteSingleReg(FSCTRL0, rf_frequoffset); // New state is SEARCH sBlueRobin.state = BLUEROBIN_SEARCHING; // Blink RF icon to show searching display_symbol(LCD_ICON_BEEPER1, SEG_ON_BLINK_ON); display_symbol(LCD_ICON_BEEPER2, SEG_ON_BLINK_ON); display_symbol(LCD_ICON_BEEPER3, SEG_ON_BLINK_ON); // Turn on radio and establish connection if channel not already started if (BRRX_GetState_t(HR_CHANNEL) == TX_OFF) { // Start in learn mode (connect to closest heart rate transmitter) BRRX_SetID_v(HR_CHANNEL, sBlueRobin.cs_id); BRRX_Start_v(HR_CHANNEL); // Wait until learning phase is over while (BRRX_GetState_t(HR_CHANNEL)==TX_SEARCH) { Timer0_A4_Delay(CONV_MS_TO_TICKS(200)); } } // Check if connection attempt was successful if (BRRX_GetState_t(HR_CHANNEL)==TX_ACTIVE) { // Successfully connected to transmitter sBlueRobin.state = BLUEROBIN_CONNECTED; // When in learn mode, copy chest strap ID if (sBlueRobin.cs_id == 0) { sBlueRobin.cs_id = BRRX_GetID_u32(HR_CHANNEL); } // Show steady RF icon to indicate established connection display_symbol(LCD_ICON_BEEPER1, SEG_ON_BLINK_OFF); display_symbol(LCD_ICON_BEEPER2, SEG_ON_BLINK_OFF); display_symbol(LCD_ICON_BEEPER3, SEG_ON_BLINK_OFF); // Show blinking icon display_symbol(LCD_ICON_HEART, SEG_ON_BLINK_ON); } else // Error -> Shutdown connection { stop = 1; } } else if (sBlueRobin.state == BLUEROBIN_CONNECTED) { // Shutdown connection stop = 1; } } // Shutdown connection if (stop) { stop_bluerobin(); } }
// ************************************************************************************************* // @fn simpliciti_get_ed_data_callback // @brief Callback function to read end device data from acceleration sensor (if available) // and trigger sending. Can be also be used to transmit other data at // different packet rates. // Please observe the applicable duty limit in the chosen ISM band. // @param none // @return none // ************************************************************************************************* void simpliciti_get_ed_data_callback(void) { static u8 packet_counter = 0; if (sRFsmpl.mode == SIMPLICITI_ACCELERATION) { // Wait for next sample Timer0_A4_Delay(CONV_MS_TO_TICKS(5)); // Read from sensor if DRDY pin indicates new data (set in PORT2 ISR) if (request.flag.acceleration_measurement && ((AS_INT_IN & AS_INT_PIN) == AS_INT_PIN)) { // Clear flag request.flag.acceleration_measurement = 0; // Get data from sensor as_get_data(sAccel.xyz); // Transmit only every 3rd data set (= 33 packets / second) if (packet_counter++ > 1) { // Reset counter packet_counter = 0; // Store XYZ data in SimpliciTI variable simpliciti_data[1] = sAccel.xyz[0]; simpliciti_data[2] = sAccel.xyz[1]; simpliciti_data[3] = sAccel.xyz[2]; // Trigger packet sending simpliciti_flag |= SIMPLICITI_TRIGGER_SEND_DATA; } } } else // transmit only button events { // New button event is stored in data if ((packet_counter == 0) && (simpliciti_data[0] & 0xF0) != 0) { packet_counter = 5; } // Send packet several times if (packet_counter > 0) { // Clear button event when sending last packet if (--packet_counter == 0) { simpliciti_data[0] &= ~0xF0; } else { // Trigger packet sending in regular intervals Timer0_A4_Delay(CONV_MS_TO_TICKS(30)); simpliciti_flag |= SIMPLICITI_TRIGGER_SEND_DATA; } } else { // Wait in LPM3 for next button press _BIS_SR(LPM3_bits + GIE); __no_operation(); } } // Update clock every 1/1 second if (display.flag.update_time) { display_time(LINE1, DISPLAY_LINE_UPDATE_PARTIAL); display.flag.update_time = 0; // Service watchdog WDTCTL = WDTPW + WDTIS__512K + WDTSSEL__ACLK + WDTCNTCL; } }
// ************************************************************************************************* // @fn start_bluerobin // @brief Start BlueRobin stack and search for a transmitter. // @param none // @return 0 = no transmitter found, 1 = connected to a transmitter // ************************************************************************************************* u8 start_bluerobin(void) { u8 timeout, i; // Init BlueRobin timer and radio // Enable high current mode open_radio(); // Initialize BR library BRRX_Init_v(); // Set BR data transmission properties BRRX_SetPowerdownDelay_v(10); // Power down channel after 10 consecutive lost data packets (~9 // seconds) BRRX_SetSearchTimeout_v(6); // Stop searching after 8 seconds // Sensitivity in learn mode reduced --> connect only to close transmitters // Skip this part if chest strap id was set in a previous learn mode run #if REMEMBER_TX_ID == TRUE if (sBlueRobin.cs_id == 0) BRRX_SetSignalLevelReduction_v(5); #else // Forget previously learned transmitter ID and connect to next close transmitter sBlueRobin.cs_id = 0; BRRX_SetSignalLevelReduction_v(5); #endif // Apply frequency offset compensation to radio register FSCTRL0 // If calibration memory was erased, rf_frequoffset defaults to 0x00 and has no effect WriteSingleReg(FSCTRL0, rf_frequoffset); // New state is SEARCH sBlueRobin.state = BLUEROBIN_SEARCHING; // Blink RF icon to show searching display_symbol(LCD_ICON_BEEPER1, SEG_ON_BLINK_ON); display_symbol(LCD_ICON_BEEPER2, SEG_ON_BLINK_ON); display_symbol(LCD_ICON_BEEPER3, SEG_ON_BLINK_ON); // Turn on radio and establish connection if channel not already started if (BRRX_GetState_t(HR_CHANNEL) == TX_OFF) { // Start in learn mode (connect to closest heart rate transmitter) BRRX_SetID_v(HR_CHANNEL, sBlueRobin.cs_id); BRRX_Start_v(HR_CHANNEL); // Wait until learning phase is over, additional timeout prevents race condition if hardware // works incorrect timeout = 40; while ((BRRX_GetState_t(HR_CHANNEL) == TX_SEARCH) && (timeout-- > 0)) { Timer0_A4_Delay(CONV_MS_TO_TICKS(200)); } // Timeout? if (timeout == 0) { display_chars(LCD_SEG_L1_3_0, (u8 *) "FAIL", SEG_ON); for (i = 0; i < 4; i++) Timer0_A4_Delay(CONV_MS_TO_TICKS(500)); } } // Check if connection attempt was successful if (BRRX_GetState_t(HR_CHANNEL) == TX_ACTIVE) { // Successfully connected to transmitter sBlueRobin.state = BLUEROBIN_CONNECTED; // When in learn mode, copy chest strap ID if (sBlueRobin.cs_id == 0) sBlueRobin.cs_id = BRRX_GetID_u32(HR_CHANNEL); // Show steady RF icon to indicate established connection display_symbol(LCD_ICON_BEEPER1, SEG_ON_BLINK_OFF); display_symbol(LCD_ICON_BEEPER2, SEG_ON_BLINK_OFF); display_symbol(LCD_ICON_BEEPER3, SEG_ON_BLINK_OFF); // Show blinking icon display_symbol(LCD_ICON_HEART, SEG_ON_BLINK_ON); return (1); } else // Error -> Shutdown connection { // Clear RF icon display_symbol(LCD_ICON_BEEPER1, SEG_OFF_BLINK_OFF); display_symbol(LCD_ICON_BEEPER2, SEG_OFF_BLINK_OFF); display_symbol(LCD_ICON_BEEPER3, SEG_OFF_BLINK_OFF); return (0); } }
// ************************************************************************************************* // @fn start_simpliciti_tx_only // @brief Start SimpliciTI (tx only). // @param simpliciti_state_t SIMPLICITI_ACCELERATION, SIMPLICITI_BUTTONS // @return none // ************************************************************************************************* void start_simpliciti_tx_only(simpliciti_mode_t mode) { // Display time in line 1 clear_line(LINE1); fptr_lcd_function_line1(LINE1, DISPLAY_LINE_CLEAR); display_time(LINE1, DISPLAY_LINE_UPDATE_FULL); // Preset simpliciti_data with mode (key or mouse click) and clear other data bytes if (mode == SIMPLICITI_ACCELERATION) { simpliciti_data[0] = SIMPLICITI_MOUSE_EVENTS; } else { simpliciti_data[0] = SIMPLICITI_KEY_EVENTS; } simpliciti_data[1] = 0; simpliciti_data[2] = 0; simpliciti_data[3] = 0; // Turn on beeper icon to show activity display_symbol(LCD_ICON_BEEPER1, SEG_ON_BLINK_ON); display_symbol(LCD_ICON_BEEPER2, SEG_ON_BLINK_ON); display_symbol(LCD_ICON_BEEPER3, SEG_ON_BLINK_ON); // Debounce button event Timer0_A4_Delay(CONV_MS_TO_TICKS(BUTTONS_DEBOUNCE_TIME_OUT)); // Prepare radio for RF communication open_radio(); // Set SimpliciTI mode sRFsmpl.mode = mode; // Set SimpliciTI timeout to save battery power sRFsmpl.timeout = SIMPLICITI_TIMEOUT; // Start SimpliciTI stack. Try to link to access point. // Exit with timeout or by a button DOWN press. if (simpliciti_link()) { if (mode == SIMPLICITI_ACCELERATION) { // Start acceleration sensor as_start(); } // Enter TX only routine. This will transfer button events and/or acceleration data to // access point. simpliciti_main_tx_only(); } // Set SimpliciTI state to OFF sRFsmpl.mode = SIMPLICITI_OFF; // Stop acceleration sensor as_stop(); // Powerdown radio close_radio(); // Clear last button events Timer0_A4_Delay(CONV_MS_TO_TICKS(BUTTONS_DEBOUNCE_TIME_OUT)); BUTTONS_IFG = 0x00; button.all_flags = 0; // Clear icons display_symbol(LCD_ICON_BEEPER1, SEG_OFF_BLINK_OFF); display_symbol(LCD_ICON_BEEPER2, SEG_OFF_BLINK_OFF); display_symbol(LCD_ICON_BEEPER3, SEG_OFF_BLINK_OFF); // Clean up line 1 clear_line(LINE1); display_time(LINE1, DISPLAY_LINE_CLEAR); // Force full display update display.flag.full_update = 1; }
// ************************************************************************************************* // @fn as_start // @brief Power-up and initialize acceleration sensor // @param none // @return none // ************************************************************************************************* void as_start(void) { volatile u16 Counter_u16; u8 bConfig;//, bStatus; // Initialize SPI interface to acceleration sensor AS_SPI_CTL0 |= UCSYNC | UCMST | UCMSB // SPI master, 8 data bits, MSB first, | UCCKPH; // clock idle low, data output on falling edge AS_SPI_CTL1 |= UCSSEL1; // SMCLK as clock source AS_SPI_BR0 = AS_BR_DIVIDER; // Low byte of division factor for baud rate AS_SPI_BR1 = 0x00; // High byte of division factor for baud rate AS_SPI_CTL1 &= ~UCSWRST; // Start SPI hardware // Initialize interrupt pin for data read out from acceleration sensor AS_INT_IES &= ~AS_INT_PIN; // Interrupt on rising edge #ifdef AS_DISCONNECT // Enable interrupt AS_INT_DIR &= ~AS_INT_PIN; // Switch INT pin to input AS_SPI_DIR &= ~AS_SDI_PIN; // Switch SDI pin to input AS_SPI_REN |= AS_SDI_PIN; // Pulldown on SDI pin AS_SPI_SEL |= AS_SDO_PIN + AS_SDI_PIN + AS_SCK_PIN; // Port pins to SDO, SDI and SCK function AS_CSN_OUT |= AS_CSN_PIN; // Deselect acceleration sensor AS_PWR_OUT |= AS_PWR_PIN; // Power on active high #endif // Delay of >5ms required between switching on power and configuring sensor Timer0_A4_Delay(CONV_MS_TO_TICKS(10)); // Initialize interrupt pin for data read out from acceleration sensor AS_INT_IFG &= ~AS_INT_PIN; // Reset flag AS_INT_IE |= AS_INT_PIN; // Enable interrupt // Configure sensor and start to sample data #if (AS_RANGE == 2) bConfig = 0x80; #if (AS_SAMPLE_RATE == 100) bConfig |= 0x02; #elif (AS_SAMPLE_RATE == 400) bConfig |= 0x04; #else #error "Sample rate not supported" #endif #elif (AS_RANGE == 8) bConfig = 0x00; #if (AS_SAMPLE_RATE == 40) bConfig |= 0x06; #elif (AS_SAMPLE_RATE == 100) bConfig |= 0x02; #elif (AS_SAMPLE_RATE == 400) bConfig |= 0x04; #else #error "Sample rate not supported" #endif #else #error "Measurement range not supported" #endif // Reset sensor as_write_register(0x04, 0x02); as_write_register(0x04, 0x0A); as_write_register(0x04, 0x04); // Wait 5 ms before starting sensor output Timer0_A4_Delay(CONV_MS_TO_TICKS(5)); // Set 2g measurement range, start to output data with 100Hz rate as_write_register(0x02, bConfig); }
// ************************************************************************************************* // @fn test_mode // @brief Manual test mode. Activated by holding buttons STAR and UP simultaneously. // Cancelled by any other button press. // @param none // @return none // ************************************************************************************************* void test_mode(void) { u8 test_step, start_next_test; u8 *str; u8 i; // Disable timer - no need for a clock tick Timer0_Stop(); // Disable LCD charge pump while in standby mode // This reduces current consumption by ca. 5�A to ca. 10�A LCDBVCTL = 0; // Show welcome screen display_chars(LCD_SEG_L1_3_0, (u8 *) " DC ", SEG_ON); display_chars(LCD_SEG_L2_4_0, (u8 *) "44 20", SEG_ON); display_symbol(LCD_SEG_L1_COL, SEG_ON); display_symbol(LCD_ICON_HEART, SEG_ON); display_symbol(LCD_ICON_STOPWATCH, SEG_ON); display_symbol(LCD_ICON_RECORD, SEG_ON); display_symbol(LCD_ICON_ALARM, SEG_ON); display_symbol(LCD_ICON_BEEPER1, SEG_ON); display_symbol(LCD_ICON_BEEPER2, SEG_ON); display_symbol(LCD_ICON_BEEPER3, SEG_ON); display_symbol(LCD_SYMB_ARROW_UP, SEG_ON); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_ON); display_symbol(LCD_SYMB_AM, SEG_ON); // Hold watchdog WDTCTL = WDTPW + WDTHOLD; // Wait for button press _BIS_SR(LPM3_bits + GIE); __no_operation(); // Clear display display_all_off(); #ifdef USE_LCD_CHARGE_PUMP // Charge pump voltage generated internally, internal bias (V2-V4) generation // This ensures that the contrast and LCD control is constant for the whole battery lifetime LCDBVCTL = LCDCPEN | VLCD_2_72; #endif // Renenable timer Timer0_Start(); // Debounce button press Timer0_A4_Delay(CONV_MS_TO_TICKS(100)); while (1) { // Check button event if (BUTTON_STAR_IS_PRESSED && BUTTON_UP_IS_PRESSED) { // Start with test #0 test_step = 0; start_next_test = 1; while (1) { if (start_next_test) { // Clean up previous test display display_all_off(); start_next_test = 0; switch (test_step) { case 0: // All LCD segments on display_all_on(); // Wait until buttons are off while (BUTTON_STAR_IS_PRESSED && BUTTON_UP_IS_PRESSED) ; break; // case 1: // Altitude measurement // display_altitude(LINE1, DISPLAY_LINE_UPDATE_FULL); // for (i = 0; i < 2; i++) // { // while ((PS_INT_IN & PS_INT_PIN) == 0) ; // do_altitude_measurement(FILTER_OFF); // display_altitude(LINE1, DISPLAY_LINE_UPDATE_PARTIAL); // } // stop_altitude_measurement(); // break; // case 2: // Temperature measurement // display_temperature(LINE1, DISPLAY_LINE_UPDATE_FULL); // for (i = 0; i < 4; i++) // { // Timer0_A4_Delay(CONV_MS_TO_TICKS(250)); // temperature_measurement(FILTER_OFF); // display_temperature(LINE1, DISPLAY_LINE_UPDATE_PARTIAL); // } // break; // case 3: // Acceleration measurement // as_start(); // for (i = 0; i < 4; i++) // { // Timer0_A4_Delay(CONV_MS_TO_TICKS(250)); // as_get_data(sAccel.xyz); // str = int_to_array(sAccel.xyz[0], 3, 0); // display_chars(LCD_SEG_L1_2_0, str, SEG_ON); // str = int_to_array(sAccel.xyz[2], 3, 0); // display_chars(LCD_SEG_L2_2_0, str, SEG_ON); // } // as_stop(); // break; // case 4: // BlueRobin test // button.flag.up = 1; // sx_bluerobin(LINE1); // Timer0_A4_Delay(CONV_MS_TO_TICKS(100)); // get_bluerobin_data(); // display_heartrate(LINE1, DISPLAY_LINE_UPDATE_FULL); // stop_bluerobin(); // break; } // Debounce button Timer0_A4_Delay(CONV_MS_TO_TICKS(200)); } // Check button event if (BUTTON_STAR_IS_PRESSED) { test_step = 1; start_next_test = 1; } else if (BUTTON_NUM_IS_PRESSED) { test_step = 2; start_next_test = 1; } else if (BUTTON_UP_IS_PRESSED) { test_step = 3; start_next_test = 1; } else if (BUTTON_DOWN_IS_PRESSED) { test_step = 4; start_next_test = 1; } else if (BUTTON_BACKLIGHT_IS_PRESSED) { // Wait until button has been released (avoid restart) while (BUTTON_BACKLIGHT_IS_PRESSED) ; // Disable LCD and LCD charge pump LCDBCTL0 &= ~BIT0; LCDBVCTL = 0; // Debounce button press Timer0_A4_Delay(CONV_MS_TO_TICKS(500)); // Disable timer - no need for a clock tick Timer0_Stop(); // Hold watchdog WDTCTL = WDTPW + WDTHOLD; // Sleep until button is pressed (ca. 4�A current consumption) _BIS_SR(LPM4_bits + GIE); __no_operation(); // Force watchdog reset for a clean restart WDTCTL = 1; } #ifdef USE_WATCHDOG // Service watchdog WDTCTL = WDTPW + WDTIS__512K + WDTSSEL__ACLK + WDTCNTCL; #endif // To LPM3 _BIS_SR(LPM3_bits + GIE); __no_operation(); } } else { // Debounce button Timer0_A4_Delay(CONV_MS_TO_TICKS(100)); button.all_flags = 0; // Turn off backlight P2OUT &= ~BUTTON_BACKLIGHT_PIN; P2DIR &= ~BUTTON_BACKLIGHT_PIN; break; } } }
// ************************************************************************************************* // @fn simpliciti_main_tx_only // @brief Get data through callback. Transfer data when external trigger is set. // @param none // @return none // ************************************************************************************************* void simpliciti_main_tx_only(void) { uint8_t len, i; uint8_t ed_data[2]; while(1) { // Get end device data from callback function simpliciti_get_ed_data_callback(); // Get radio ready. Wakes up in IDLE state. if(getFlag(simpliciti_flag, SIMPLICITI_TRIGGER_SEND_DATA) || getFlag(simpliciti_flag, SIMPLICITI_TRIGGER_RECEIVE_DATA)) { SMPL_Ioctl( IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_AWAKE, 0); // Send data when flag bit SIMPLICITI_TRIGGER_SEND_DATA is set if (getFlag(simpliciti_flag, SIMPLICITI_TRIGGER_SEND_DATA)) { // Acceleration / button events packets are 4 bytes long SMPL_SendOpt(sLinkID1, simpliciti_data, simpliciti_payload_length, SMPL_TXOPTION_NONE); //SMPL_SendOpt(sLinkID1, simpliciti_data, simpliciti_payload_length, simpliciti_options); // reset options to default //simpliciti_options = SMPL_TXOPTION_NONE; clearFlag(simpliciti_flag, SIMPLICITI_TRIGGER_SEND_DATA); } // Receive data when flag bit SIMPLICITI_TRIGGER_RECEIVE_DATA is set if (getFlag(simpliciti_flag, SIMPLICITI_TRIGGER_RECEIVE_DATA)) { // Send 2 byte long ready-to-receive packet to stimulate host reply clearFlag(simpliciti_flag, SIMPLICITI_TRIGGER_RECEIVE_DATA); // clean up tha buffer first simpliciti_data[0] = 0x00; simpliciti_data[1] = 0x00; simpliciti_data[3] = 0x00; simpliciti_data[4] = 0x00; // generate a ready to receive packet ed_data[0] = SYNC_ED_TYPE_R2R; ed_data[1] = 0xCB; SMPL_Ioctl( IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_RXON, 0); // we try to receive 9 times by sending a R2R packet for (i = 0; i < 10; i++) { SMPL_SendOpt(sLinkID1, ed_data, 2, SMPL_TXOPTION_NONE); //WDTCTL = WDTPW + WDTHOLD; // Wait shortly for host reply NWK_DELAY(10); while (SMPL_Receive(sLinkID1, simpliciti_data, &len) == SMPL_SUCCESS) { if (len > 0) { // Decode received data if(simpliciti_get_rvc_callback(len)) { // stop retry loop i = 10; break; } } } Timer0_A4_Delay(CONV_MS_TO_TICKS(500)); } } // Put radio back to SLEEP state SMPL_Ioctl( IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_SLEEP, 0); } // Exit when flag bit SIMPLICITI_TRIGGER_STOP is set if (getFlag(simpliciti_flag, SIMPLICITI_TRIGGER_STOP)) { // Clean up SimpliciTI stack to enable restarting sInit_done = 0; break; } } }
__interrupt void PORT2_ISR(void) { // Clear flags u8 int_flag, int_enable; u8 buzzer = 0; u8 simpliciti_button_event = 0; static u8 simpliciti_button_repeat = 0; // Remember interrupt enable bits int_enable = BUTTONS_IE; if ((!button.flag.star_long) && (!button.flag.num_long)) { // Clear button flags button.all_flags = 0; // Store valid button interrupt flag int_flag = BUTTONS_IFG & int_enable; // --------------------------------------------------- // While SimpliciTI stack is active, buttons behave differently: // - Store button events in SimpliciTI packet data // - Exit SimpliciTI when button DOWN was pressed if (is_rf()) { // Erase previous button press after a number of resends (increase number if link // quality is low) // This will create a series of packets containing the same button press // Necessary because we have no acknowledge // Filtering (edge detection) will be done by receiver software if (simpliciti_button_repeat++ > 6) { simpliciti_data[0] &= ~0xF0; simpliciti_button_repeat = 0; } if ((int_flag & BUTTON_STAR_PIN) == BUTTON_STAR_PIN) { simpliciti_data[0] |= SIMPLICITI_BUTTON_STAR; simpliciti_button_event = 1; } else if ((int_flag & BUTTON_NUM_PIN) == BUTTON_NUM_PIN) { simpliciti_data[0] |= SIMPLICITI_BUTTON_NUM; simpliciti_button_event = 1; } else if ((int_flag & BUTTON_UP_PIN) == BUTTON_UP_PIN) { simpliciti_data[0] |= SIMPLICITI_BUTTON_UP; simpliciti_button_event = 1; } else if ((int_flag & BUTTON_DOWN_PIN) == BUTTON_DOWN_PIN) { simpliciti_flag |= SIMPLICITI_TRIGGER_STOP; } // Trigger packet sending inside SimpliciTI stack if (simpliciti_button_event) simpliciti_flag |= SIMPLICITI_TRIGGER_SEND_DATA; } else // Normal operation { // Debounce buttons if ((int_flag & ALL_BUTTONS) != 0) { // Disable PORT2 IRQ __disable_interrupt(); BUTTONS_IE = 0x00; __enable_interrupt(); // Debounce delay 1 Timer0_A4_Delay(CONV_MS_TO_TICKS(BUTTONS_DEBOUNCE_TIME_IN)); // Reset inactivity detection sTime.last_activity = sTime.system_time; } // --------------------------------------------------- // STAR button IRQ if (IRQ_TRIGGERED(int_flag, BUTTON_STAR_PIN)) { // Filter bouncing noise if (BUTTON_STAR_IS_PRESSED) { button.flag.star = 1; button.flag.star_not_long = 0; // Generate button click buzzer = 1; } else if ((BUTTONS_IES & BUTTON_STAR_PIN) == BUTTON_STAR_PIN) { button.flag.star = 1; button.flag.star_not_long = 0; BUTTONS_IES &= ~BUTTON_STAR_PIN; } } // --------------------------------------------------- // NUM button IRQ else if (IRQ_TRIGGERED(int_flag, BUTTON_NUM_PIN)) { // Filter bouncing noise if (BUTTON_NUM_IS_PRESSED) { button.flag.num = 1; button.flag.num_not_long = 0; // Generate button click buzzer = 1; } else if ((BUTTONS_IES & BUTTON_NUM_PIN) == BUTTON_NUM_PIN) { button.flag.num = 1; button.flag.num_not_long = 0; BUTTONS_IES &= ~BUTTON_NUM_PIN; } } // --------------------------------------------------- // UP button IRQ else if (IRQ_TRIGGERED(int_flag, BUTTON_UP_PIN)) { // Filter bouncing noise if (BUTTON_UP_IS_PRESSED) { button.flag.up = 1; // Generate button click buzzer = 1; } } // --------------------------------------------------- // DOWN button IRQ else if (IRQ_TRIGGERED(int_flag, BUTTON_DOWN_PIN)) { // Filter bouncing noise if (BUTTON_DOWN_IS_PRESSED) { button.flag.down = 1; // Generate button click buzzer = 1; // Faster reaction for stopwatch stop button press if (is_stopwatch() && !sys.flag.lock_buttons) { stop_stopwatch(); button.flag.down = 0; } } } // --------------------------------------------------- // B/L button IRQ else if (IRQ_TRIGGERED(int_flag, BUTTON_BACKLIGHT_PIN)) { // Filter bouncing noise if (BUTTON_BACKLIGHT_IS_PRESSED) { sButton.backlight_status = 1; sButton.backlight_timeout = 0; P2OUT |= BUTTON_BACKLIGHT_PIN; P2DIR |= BUTTON_BACKLIGHT_PIN; } } } // Trying to lock/unlock buttons? if (button.flag.num && button.flag.down) { // No buzzer output buzzer = 0; button.all_flags = 0; } // Generate button click when button was activated if (buzzer) { // Any button event stops active alarm if (sAlarm.state == ALARM_ON) { stop_alarm(); button.all_flags = 0; } else if (!sys.flag.up_down_repeat_enabled) { start_buzzer(1, CONV_MS_TO_TICKS(20), CONV_MS_TO_TICKS(150)); } // Debounce delay 2 Timer0_A4_Delay(CONV_MS_TO_TICKS(BUTTONS_DEBOUNCE_TIME_OUT)); } // --------------------------------------------------- // Acceleration sensor IRQ if (IRQ_TRIGGERED(int_flag, AS_INT_PIN)) { // Get data from sensor request.flag.acceleration_measurement = 1; } // --------------------------------------------------- // Pressure sensor IRQ if (IRQ_TRIGGERED(int_flag, PS_INT_PIN)) { // Get data from sensor request.flag.altitude_measurement = 1; } // --------------------------------------------------- // Safe long button event detection if (button.flag.star || button.flag.num) { // Additional debounce delay to enable safe high detection - 50ms Timer0_A4_Delay(CONV_MS_TO_TICKS(BUTTONS_DEBOUNCE_TIME_LEFT)); // Check if this button event is short enough if (BUTTON_STAR_IS_PRESSED) { // Change interrupt edge to detect button release BUTTONS_IES |= BUTTON_STAR_PIN; button.flag.star = 0; // This flag is used to detect if the user released the button before the // time for a long button press (3s) button.flag.star_not_long = 1; } if (BUTTON_NUM_IS_PRESSED) { // Change interrupt edge to detect button release BUTTONS_IES |= BUTTON_NUM_PIN; button.flag.num = 0; // This flag is used to detect if the user released the button before the // time for a long button press (3s) button.flag.num_not_long = 1; } } } // Reenable PORT2 IRQ __disable_interrupt(); BUTTONS_IFG = 0x00; BUTTONS_IE = int_enable; __enable_interrupt(); // Exit from LPM3/LPM4 on RETI __bic_SR_register_on_exit(LPM4_bits); }