// ************************************************************************************************* // @fn reset_altitude_measurement // @brief Reset altitude measurement. // @param none // @return none // ************************************************************************************************* void reset_altitude_measurement(void) { // Menu item is not visible sAlt.state = MENU_ITEM_NOT_VISIBLE; // Clear timeout counter sAlt.timeout = 0; // Set default altitude value sAlt.altitude = 0; // Pressure sensor ok? if (ps_ok) { // Initialise pressure table init_pressure_table(); // Do single conversion start_altitude_measurement(); stop_altitude_measurement(); // Apply calibration offset and recalculate pressure table if (sAlt.altitude_offset != 0) { sAlt.altitude += sAlt.altitude_offset; update_pressure_table(sAlt.altitude, sAlt.pressure, sAlt.temperature); } } }
// ************************************************************************************************* // @fn reset_altitude_measurement // @brief Reset altitude measurement. // @param none // @return none // ************************************************************************************************* void reset_altitude_measurement(void) { // Set default values sAlt.on = 0; sAlt.altitude = 0; sAlt.temperature_C = 0; sAlt.temperature_C_offset = 0; // Pressure sensor ok? if (ps_ok) { // Initialise pressure table init_pressure_table(); // Do single conversion start_altitude_measurement(); stop_altitude_measurement(); // Apply calibration offset and recalculate pressure table if (sAlt.altitude_offset != 0) { sAlt.altitude += sAlt.altitude_offset; update_pressure_table(sAlt.altitude, sAlt.pressure, sAlt.temperature_K); } } }
// ************************************************************************************************* // @fn altitude_accumulator_start // @brief Initialises the altitude accumulator function // @param none // @return none // ************************************************************************************************* void altitude_accumulator_start (void) { s32 temp; alt_accum__accumtotal = 0; // So far total upwards vertical accumulation is zero alt_accum_direction = 1; // start off by assuming we're heading uphill // Now let's get 4 altitude readings, then average them, to obtain our current altitude start_altitude_measurement(); stop_altitude_measurement(); temp = sAlt.altitude; // first reading /* start_altitude_measurement(); stop_altitude_measurement(); temp += sAlt.altitude; // second reading start_altitude_measurement(); stop_altitude_measurement(); temp += sAlt.altitude; // third reading start_altitude_measurement(); stop_altitude_measurement(); temp += sAlt.altitude; // fourth reading temp = temp >> 2; // divide result by 4 = our current altitude */ alt_accum_startpoint = temp; // the altitude the user zeroed the accumulator at alt_accum_lastpeakdip = temp; // altitude of the last dip (in this case, as we assume we're going uphill) alt_accum_prevalt = temp; // previous altitude value alt_accum_max = temp; // maximum altitude we've encountered so far }
// ************************************************************************************************* // @fn reset_altitude_measurement // @brief Reset altitude measurement. // @param none // @return none // ************************************************************************************************* void reset_altitude_measurement(void) { // Show altitude PressDisplay = DISPLAY_DEFAULT_VIEW; // Offset for Ambient pressure AmbientPressureOffset = AMBIENT_PRESSURE_OFFSET_DEFAULT; // Menu item is not visible sAlt.state = MENU_ITEM_NOT_VISIBLE; // Clear timeout counter sAlt.timeout = 0; // Set default altitude value sAlt.altitude = 0; // Pressure sensor ok? if (ps_ok) { // Initialise pressure table init_pressure_table(); // Do single conversion start_altitude_measurement(); stop_altitude_measurement(); // Apply calibration offset and recalculate pressure table if (sAlt.altitude_offset != 0) { sAlt.altitude += sAlt.altitude_offset; update_pressure_table(sAlt.altitude, sAlt.pressure, sAlt.temperature); } } }
// ************************************************************************************************* // @fn reset_altitude_measurement // @brief Reset altitude measurement. // @param none // @return none // ************************************************************************************************* void reset_altitude_measurement(void) { sAlt.state = MENU_ITEM_NOT_VISIBLE; sAlt.timeout = 0; sAlt.altitude = 0; sAlt.mode = ALTITUDE_REGULAR; // Pressure sensor ok? if (ps_ok) { // Do single conversion start_altitude_measurement(); stop_altitude_measurement(); } }
// ************************************************************************************************* // @fn reset_altitude_measurement // @brief Reset altitude measurement. // @param none // @return none // ************************************************************************************************* void reset_altitude_measurement(void) { // Clear timeout counter sAlt.timeout = 0; // Set default altitude value // Pressure sensor ok? if (ps_ok) { // Initialise pressure table init_pressure_table(); // Do single conversion start_altitude_measurement(); stop_altitude_measurement(); sAlt.accu_threshold = CONFIG_MOD_ALTITUDE_ACCU_THRESHOLD; sAlt.altitude_calib = sAlt.raw_altitude; sAlt.altitude_offset = sAlt.raw_altitude - sAlt.altitude_calib; sAlt.raw_minAltitude = sAlt.raw_altitude; sAlt.raw_maxAltitude = sAlt.raw_altitude; oldAccuAltitude = sAlt.raw_altitude; sAlt.accuClimbDown = 0; sAlt.accuClimbUp = 0; sAlt.minAltitude = sAlt.raw_minAltitude - sAlt.altitude_offset; sAlt.maxAltitude = sAlt.raw_maxAltitude - sAlt.altitude_offset; sAlt.altitude = sAlt.raw_altitude - sAlt.altitude_offset; sAlt.first_pressure = sAlt.pressure; sAlt.climb = 0; for (sAlt.history_pos = 0; sAlt.history_pos < ALT_HISTORY_LEN; sAlt.history_pos++) { sAlt.history[sAlt.history_pos] = 0; } sAlt.history_pos = 0; } }
__interrupt void TIMER0_A0_ISR(void) { static u8 button_lock_counter = 0; // Disable IE TA0CCTL0 &= ~CCIE; // Reset IRQ flag TA0CCTL0 &= ~CCIFG; // Add 1 sec to TACCR0 register (IRQ will be asserted at 0x7FFF and 0xFFFF = 1 sec intervals) TA0CCR0 += 32768; // Enable IE TA0CCTL0 |= CCIE; // Add 1 second to global time clock_tick(); // Set clock update flag display.flag.update_time = 1; // While SimpliciTI stack operates or BlueRobin searches, freeze system state if (is_rf() || is_bluerobin_searching()) { // SimpliciTI automatic timeout if (sRFsmpl.timeout == 0) { simpliciti_flag |= SIMPLICITI_TRIGGER_STOP; } else { sRFsmpl.timeout--; } // switch message after received packet if (sRFsmpl.mode == SIMPLICITI_SYNC) { if (sRFsmpl.display_sync_done == 0) { display_chars(LCD_SEG_L2_5_0, (u8 *) " SYNC", SEG_ON); } else { sRFsmpl.display_sync_done--; } } // Exit from LPM3 on RETI _BIC_SR_IRQ(LPM3_bits); return; } // ------------------------------------------------------------------- // Service modules that require 1/min processing if (sTime.drawFlag >= 2) { // Measure battery voltage to keep track of remaining battery life request.flag.voltage_measurement = 1; // Check if alarm needs to be turned on check_alarm(); } // ------------------------------------------------------------------- // Service active modules that require 1/s processing // Generate alarm signal if (sAlarm.state == ALARM_ON) { // Decrement alarm duration counter if (sAlarm.duration-- > 0) { request.flag.buzzer = 1; } else { sAlarm.duration = ALARM_ON_DURATION; stop_alarm(); } } // Do a temperature measurement each second while menu item is active if (is_temp_measurement()) request.flag.temperature_measurement = 1; // Do a pressure measurement each second while menu item is active if (is_altitude_measurement()) { // Countdown altitude measurement timeout while menu item is active sAlt.timeout--; // Stop measurement when timeout has elapsed if (sAlt.timeout == 0) { stop_altitude_measurement(); // Show ---- m/ft display_chars(LCD_SEG_L1_3_0, (u8 *) "----", SEG_ON); // Clear up/down arrow display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } // In case we missed the IRQ due to debouncing, get data now if ((PS_INT_IN & PS_INT_PIN) == PS_INT_PIN) request.flag.altitude_measurement = 1; } // Count down timeout if (is_acceleration_measurement()) { // Countdown acceleration measurement timeout sAccel.timeout--; // Stop measurement when timeout has elapsed if (sAccel.timeout == 0) { as_stop(); // Show ---- display_chars(LCD_SEG_L1_3_0, (u8 *) "----", SEG_ON); // Clear up/down arrow display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); display_symbol(LCD_SEG_L1_DP1, SEG_OFF); } // If DRDY is (still) high, request data again if ((AS_INT_IN & AS_INT_PIN) == AS_INT_PIN) request.flag.acceleration_measurement = 1; } // If BlueRobin transmitter is connected, get data from API if (is_bluerobin()) get_bluerobin_data(); // If battery is low, decrement display counter if (sys.flag.low_battery) { if (sBatt.lobatt_display-- == 0) { message.flag.prepare = 1; message.flag.type_lobatt = 1; sBatt.lobatt_display = BATTERY_LOW_MESSAGE_CYCLE; } } // If a message has to be displayed, set display flag if (message.all_flags) { if (message.flag.prepare) { message.flag.prepare = 0; message.flag.show = 1; } else if (message.flag.erase) // message cycle is over, so erase it { message.flag.erase = 0; display.flag.full_update = 1; } } // ------------------------------------------------------------------- // Check idle timeout, set timeout flag if (sys.flag.idle_timeout_enabled) { if (sTime.system_time - sTime.last_activity > INACTIVITY_TIME) sys.flag.idle_timeout = 1; //setFlag(sysFlag_g, SYS_TIMEOUT_IDLE); } // ------------------------------------------------------------------- // Turn the Backlight off after timeout if (sButton.backlight_status == 1) { if (sButton.backlight_timeout > BACKLIGHT_TIME_ON) { //turn off Backlight P2OUT &= ~BUTTON_BACKLIGHT_PIN; P2DIR &= ~BUTTON_BACKLIGHT_PIN; sButton.backlight_timeout = 0; sButton.backlight_status = 0; } else { sButton.backlight_timeout++; } } // ------------------------------------------------------------------- // Detect continuous button high states // Trying to lock/unlock buttons? if (BUTTON_NUM_IS_PRESSED && BUTTON_DOWN_IS_PRESSED) { if (button_lock_counter++ > LEFT_BUTTON_LONG_TIME) { // Toggle lock / unlock buttons flag sys.flag.lock_buttons = ~sys.flag.lock_buttons; // Show "buttons are locked/unlocked" message synchronously with next second tick message.flag.prepare = 1; if (sys.flag.lock_buttons) message.flag.type_locked = 1; else message.flag.type_unlocked = 1; // Reset button lock counter button_lock_counter = 0; } } else // Trying to create a long button press? { // Reset button lock counter button_lock_counter = 0; if (BUTTON_STAR_IS_PRESSED) { sButton.star_timeout++; // Check if button was held low for some seconds if (sButton.star_timeout > LEFT_BUTTON_LONG_TIME) { button.flag.star_long = 1; button.flag.star_not_long = 0; sButton.star_timeout = 0; // Return interrupt edge to normal value BUTTONS_IES &= ~BUTTON_STAR_PIN; } } else // there was a button press not long enough { sButton.star_timeout = 0; } if (BUTTON_NUM_IS_PRESSED) { sButton.num_timeout++; // Check if button was held low for some seconds if (sButton.num_timeout > LEFT_BUTTON_LONG_TIME) { button.flag.num_long = 1; button.flag.num_not_long = 0; sButton.num_timeout = 0; // Return interrupt edge to normal value BUTTONS_IES &= ~BUTTON_NUM_PIN; } } else // there was a button press not long enough { sButton.num_timeout = 0; } } // Exit from LPM3 on RETI _BIC_SR_IRQ(LPM3_bits); }
// ************************************************************************************************* // @fn display_altitude // @brief Display routine. Supports display in meters and feet. // @param u8 line LINE1 // u8 update DISPLAY_LINE_UPDATE_FULL, DISPLAY_LINE_UPDATE_PARTIAL, DISPLAY_LINE_CLEAR // @return none // ************************************************************************************************* void display_altitude(u8 line, u8 update) { u8 *str; s16 ft; // Start measurement start_altitude_measurement(); // redraw whole screen if (update == DISPLAY_LINE_UPDATE_FULL) { if (sys.flag.use_metric_units) { // Display "m" symbol display_symbol(LCD_UNIT_L1_M, SEG_ON); } else { // Display "ft" symbol display_symbol(LCD_UNIT_L1_FT, SEG_ON); } // Display altitude display_altitude(LINE1, DISPLAY_LINE_UPDATE_PARTIAL); } else if (update == DISPLAY_LINE_UPDATE_PARTIAL) { if (sys.flag.use_metric_units) { // Display altitude in xxxx m format, allow 3 leading blank digits if (sAlt.altitude >= 0) { str = int_to_array(sAlt.altitude, 4, 3); display_symbol(LCD_SYMB_ARROW_UP, SEG_ON); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } else { str = int_to_array(sAlt.altitude * (-1), 4, 3); display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_ON); } } else { // Convert from meters to feet ft = convert_m_to_ft(sAlt.altitude); // Limit to 9999ft (3047m) if (ft > 9999) ft = 9999; // Display altitude in xxxx ft format, allow 3 leading blank digits if (ft >= 0) { str = int_to_array(ft, 4, 3); display_symbol(LCD_SYMB_ARROW_UP, SEG_ON); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } else { str = int_to_array(ft * (-1), 4, 3); display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_ON); } } display_chars(LCD_SEG_L1_3_0, str, SEG_ON); } else if (update == DISPLAY_LINE_CLEAR) { // Stop measurement stop_altitude_measurement(); // Clean up function-specific segments before leaving function display_symbol(LCD_UNIT_L1_M, SEG_OFF); display_symbol(LCD_UNIT_L1_FT, SEG_OFF); display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } }
// ************************************************************************************************* // @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 acceleration sensor as_stop(); // Get updated altitude start_altitude_measurement(); stop_altitude_measurement(); // Get updated temperature temperature_measurement(FILTER_OFF); // 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 = 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 button DOWN press. if (simpliciti_link()) { // Enter sync routine. This will send ready-to-receive packets at regular intervals to the // access point. // The access point replies with 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; }
__interrupt void TIMER0_A0_ISR(void) #endif { static u8 button_lock_counter = 0; static u8 button_beep_counter = 0; // Disable IE TA0CCTL0 &= ~CCIE; // Reset IRQ flag TA0CCTL0 &= ~CCIFG; // Add 1 sec to TACCR0 register (IRQ will be asserted at 0x7FFF and 0xFFFF = 1 sec intervals) TA0CCR0 += 32768; // Enable IE TA0CCTL0 |= CCIE; // Add 1 second to global time clock_tick(); // Set clock update flag display.flag.update_time = 1; // While SimpliciTI stack operates or BlueRobin searches, freeze system state //pfs #ifdef ELIMINATE_BLUEROBIN if (is_rf()) #else if (is_rf() || is_bluerobin_searching()) #endif { // SimpliciTI automatic timeout if (sRFsmpl.timeout == 0) { simpliciti_flag |= SIMPLICITI_TRIGGER_STOP; } else { sRFsmpl.timeout--; } // Exit from LPM3 on RETI _BIC_SR_IRQ(LPM3_bits); return; } // ------------------------------------------------------------------- // Service modules that require 1/min processing if (sTime.drawFlag >= 2) { #ifdef CONFIG_BATTERY // Measure battery voltage to keep track of remaining battery life request.flag.voltage_measurement = 1; #endif #ifdef CONFIG_ALARM // If the chime is enabled, we beep here if (sTime.minute == 0) { if (sAlarm.hourly == ALARM_ENABLED) { request.flag.alarm_buzzer = 1; } #if (CONFIG_DST > 0) if ((sTime.hour == 1) && (dst_state == 0) && dst_isDateInDST(sDate.month, sDate.day)) { // spring forward sTime.hour++; dst_state = 1; } if ((sTime.hour == 2) && (dst_state != 0) && (!dst_isDateInDST(sDate.month, sDate.day))) { // fall back sTime.hour--; dst_state = 0; } #endif } // Check if alarm needs to be turned on check_alarm(); #endif #ifdef CONFIG_ALTI_ACCUMULATOR // Check if we need to do an altitude accumulation if (alt_accum_enable) request.flag.altitude_accumulator = 1; #endif } // ------------------------------------------------------------------- // Service active modules that require 1/s processing #ifdef CONFIG_EGGTIMER if (sEggtimer.state == EGGTIMER_RUN) { eggtimer_tick(); // Subtract 1 second from eggtimer's count } if (sEggtimer.state == EGGTIMER_ALARM) { // no "else if" intentional // Decrement alarm duration counter if (sEggtimer.duration-- > 0) { request.flag.eggtimer_buzzer = 1; } else { stop_eggtimer_alarm(); // Set state to Stop and reset duration } } #endif #ifdef CONFIG_ALARM // Generate alarm signal if (sAlarm.state == ALARM_ON) { // Decrement alarm duration counter if (sAlarm.duration-- > 0) { request.flag.alarm_buzzer = 1; } else { sAlarm.duration = ALARM_ON_DURATION; stop_alarm(); } } #endif #ifdef CONFIG_PROUT if (is_prout()) prout_tick(); #endif #ifdef CONFIG_STRENGTH // One more second gone by. if(is_strength()) { strength_tick(); } #endif // Do a temperature measurement each second while menu item is active if (is_temp_measurement()) request.flag.temperature_measurement = 1; // Do a pressure measurement each second while menu item is active #ifdef CONFIG_ALTITUDE if (is_altitude_measurement()) { // Countdown altitude measurement timeout while menu item is active sAlt.timeout--; // Stop measurement when timeout has elapsed if (sAlt.timeout == 0) { stop_altitude_measurement(); // Show ---- m/ft display_chars(LCD_SEG_L1_3_0, (u8*)"----", SEG_ON); // Clear up/down arrow display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } // In case we missed the IRQ due to debouncing, get data now if ((PS_INT_IN & PS_INT_PIN) == PS_INT_PIN) request.flag.altitude_measurement = 1; } #endif #ifdef FEATURE_PROVIDE_ACCEL // Count down timeout if (is_acceleration_measurement()) { // Countdown acceleration measurement timeout sAccel.timeout--; // Stop measurement when timeout has elapsed if (sAccel.timeout == 0) as_stop(); // If DRDY is (still) high, request data again if ((AS_INT_IN & AS_INT_PIN) == AS_INT_PIN) request.flag.acceleration_measurement = 1; } #endif //pfs #ifndef ELIMINATE_BLUEROBIN // If BlueRobin transmitter is connected, get data from API if (is_bluerobin()) get_bluerobin_data(); #endif #ifdef CONFIG_BATTERY // If battery is low, decrement display counter if (sys.flag.low_battery) { if (sBatt.lobatt_display-- == 0) { message.flag.prepare = 1; message.flag.type_lobatt = 1; sBatt.lobatt_display = BATTERY_LOW_MESSAGE_CYCLE; } } #endif // If a message has to be displayed, set display flag if (message.all_flags) { if (message.flag.prepare) { message.flag.prepare = 0; message.flag.show = 1; } else if (message.flag.erase) // message cycle is over, so erase it { message.flag.erase = 0; message.flag.block_line1 = 0; message.flag.block_line2 = 0; display.flag.full_update = 1; } } // ------------------------------------------------------------------- // Check idle timeout, set timeout flag if (sys.flag.idle_timeout_enabled) { if (sTime.system_time - sTime.last_activity > INACTIVITY_TIME) sys.flag.idle_timeout = 1; //setFlag(sysFlag_g, SYS_TIMEOUT_IDLE); } // ------------------------------------------------------------------- // Turn the Backlight off after timeout if (sButton.backlight_status == 1) { if (sButton.backlight_timeout > BACKLIGHT_TIME_ON) { //turn off Backlight P2OUT &= ~BUTTON_BACKLIGHT_PIN; P2DIR &= ~BUTTON_BACKLIGHT_PIN; sButton.backlight_timeout = 0; sButton.backlight_status = 0; } else { sButton.backlight_timeout++; } } // ------------------------------------------------------------------- // Detect continuous button high states if (BUTTON_STAR_IS_PRESSED && BUTTON_UP_IS_PRESSED) { if (button_beep_counter++ > LEFT_BUTTON_LONG_TIME) { // Toggle no_beep buttons flag sys.flag.no_beep = ~sys.flag.no_beep; // Show "beep / nobeep" message synchronously with next second tick message.flag.prepare = 1; if (sys.flag.no_beep) message.flag.type_no_beep_on = 1; else message.flag.type_no_beep_off = 1; // Reset button beep counter button_beep_counter = 0; } } else if (BUTTON_NUM_IS_PRESSED && BUTTON_DOWN_IS_PRESSED) // Trying to lock/unlock buttons? { if (button_lock_counter++ > LEFT_BUTTON_LONG_TIME) { // Toggle lock / unlock buttons flag sys.flag.lock_buttons = ~sys.flag.lock_buttons; // Show "buttons are locked/unlocked" message synchronously with next second tick message.flag.prepare = 1; if (sys.flag.lock_buttons) message.flag.type_locked = 1; else message.flag.type_unlocked = 1; // Reset button lock counter button_lock_counter = 0; } } else // Trying to create a long button press? { // Reset button lock counter button_lock_counter = 0; if (BUTTON_STAR_IS_PRESSED) { sButton.star_timeout++; // Check if button was held low for some seconds if (sButton.star_timeout > LEFT_BUTTON_LONG_TIME) { button.flag.star_long = 1; sButton.star_timeout = 0; } } else { sButton.star_timeout = 0; } if (BUTTON_NUM_IS_PRESSED) { sButton.num_timeout++; // Check if button was held low for some seconds if (sButton.num_timeout > LEFT_BUTTON_LONG_TIME) { button.flag.num_long = 1; sButton.num_timeout = 0; } } else { sButton.num_timeout = 0; } } // Exit from LPM3 on RETI _BIC_SR_IRQ(LPM3_bits); }
// ************************************************************************************************* // @fn display_altitude // @brief Display routine. Supports display in meters and feet. // @param u8 line LINE1 // u8 update DISPLAY_LINE_UPDATE_FULL, DISPLAY_LINE_UPDATE_PARTIAL, DISPLAY_LINE_CLEAR // @return none // ************************************************************************************************* void display_altitude(u8 line, u8 update) { if (update == DISPLAY_LINE_UPDATE_FULL) { sAlt.state = MENU_ITEM_VISIBLE; start_altitude_measurement(); u8 m, ft; #ifdef CONFIG_ALTITUDE_UNIT_SETTABLE if (sys.flag.use_metric_units) { m = SEG_ON; ft = SEG_OFF; } else { m = SEG_OFF; ft = SEG_ON; } #elif defined(CONFIG_ALTITUDE_UNIT_METERS) m = SEG_ON; ft = SEG_OFF; #elif defined(CONFIG_ALTITUDE_UNIT_FEET) m = SEG_OFF; ft = SEG_ON; #endif // Display "m" or "ft" symbol display_symbol(LCD_UNIT_L1_M, m); display_symbol(LCD_UNIT_L1_FT, ft); } if (update == DISPLAY_LINE_UPDATE_FULL || update == DISPLAY_LINE_UPDATE_PARTIAL) { // Update display only while measurement is active if (sAlt.timeout > 0) { u8 *str; if (sAlt.mode == ALTITUDE_SKYDIVING && sAlt.altitude > 1000) { u16 altitude = (sAlt.altitude + 50) / 100; str = _itoa(altitude, 3, 1); display_chars(LCD_SEG_L1_3_1, str, SEG_ON); display_chars(LCD_SEG_L1_0, NULL, SEG_OFF); display_symbol(LCD_SEG_L1_DP1, SEG_ON); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } else { // Display altitude in xxxx m format, allow 3 leading blank digits if (sAlt.altitude >= 0) { str = _itoa(sAlt.altitude, 4, 3); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } else { str = _itoa(-sAlt.altitude, 4, 3); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_ON); } display_chars(LCD_SEG_L1_3_0, str, SEG_ON); display_symbol(LCD_SEG_L1_DP1, SEG_OFF); } } } else if (update == DISPLAY_LINE_CLEAR) { // Disable pressure measurement sAlt.state = MENU_ITEM_NOT_VISIBLE; // Stop measurement stop_altitude_measurement(); // Clean up function-specific segments before leaving function display_symbol(LCD_UNIT_L1_M, SEG_OFF); display_symbol(LCD_UNIT_L1_FT, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); display_symbol(LCD_SEG_L1_DP1, SEG_OFF); } }
void read_altitude(void) { // Start measurement start_altitude_measurement(); stop_altitude_measurement(); }
__interrupt void TIMER0_A0_ISR(void) { static u8 button_lock_counter = 0; // Disable IE TA0CCTL0 &= ~CCIE; // Reset IRQ flag TA0CCTL0 &= ~CCIFG; // Add 1 sec to TACCR0 register (IRQ will be asserted at 0x7FFF and 0xFFFF = 1 sec intervals) TA0CCR0 += 32768; // Enable IE TA0CCTL0 |= CCIE; // Add 1 second to global time clock_tick(); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Count down and up if (sCountup.mode == COUNTUP_MODE_ON) { countup_tick(); if (sCountdown.mode == COUNTDOWN_MODE_ON) { // Countdown acceleration measurement timeout sAccel.timeout--; // Stop measurement when timeout has elapsed if (sAccel.timeout == 0) as_stop(); // If DRDY is (still) high, request data again if ((AS_INT_IN & AS_INT_PIN) == AS_INT_PIN) request.flag.acceleration_measurement = 1; // sAccel.xyz[0] = xaxis, sAccel.xyz[0] = yaxis, sAccel.xyz[0] = zaxis if ((sAccel.xyz[0] < sCountdown.thresholdlow[0] || sAccel.xyz[0] > sCountdown.thresholdhigh[0]) && (sAccel.xyz[1] < sCountdown.thresholdlow[1] || sAccel.xyz[1] > sCountdown.thresholdhigh[1])) { // UNDER THRESHOLD VALUES if (sCountdown.speed == 1) { // Clear timer interrupt enable TA0CCTL2 &= ~CCIE; countdown_tick(); } if (sCountdown.speed == 2) { // Recovery loop - set back to default as below threshold if (sCountdown.exceedcount[0] != sCountdown.exceeddefault[0]) { sCountdown.exceedcount[0] = sCountdown.exceeddefault[0]; } // Recovery loop - reduce recovery value if under threshold if (sCountdown.recoverycount != 0) { sCountdown.recoverycount--; } // Set speed to 1 if recovery is back to 0 else { sCountdown.speed = 1; sCountdown.recoverycount = sCountdown.recoverydefault; countdown_tick(); } } if (sCountdown.speed == 3) { // Recovery loop - set back to default as below threshold if (sCountdown.exceedcount[1] != sCountdown.exceeddefault[1]) { sCountdown.exceedcount[1] = sCountdown.exceeddefault[1]; } // Recovery loop - reduce recovery value if under threshold if (sCountdown.recoverycount != 0) { sCountdown.recoverycount--; } // Set speed to 1 if recovery is back to 0 else { sCountdown.speed = 1; sCountdown.recoverycount = sCountdown.recoverydefault; countdown_tick(); } } } // OVER THRESHOLD VALUES else { sCountdown.recoverycount = sCountdown.recoverydefault; if (sCountdown.speed == 1) { // Increase countdown speed sCountdown.speed = 2; // Init CCR register with current time TA0CCR2 = TA0R; // Load CCR register with next capture time TA0CCR2 += sCountdown.tickspeed[0]; // Reset IRQ flag TA0CCTL2 &= ~CCIFG; // Enable timer interrupt TA0CCTL2 |= CCIE; countdown_tick(); } if (sCountdown.speed == 2) { // Counting down from exceed2 limit if (sCountdown.exceedcount[0] != 0) { sCountdown.exceedcount[0]--; } // Speed up if equal to 0 else { sCountdown.exceedcount[0] = sCountdown.exceeddefault[0]; // Increase countdown speed sCountdown.speed = 3; } } if (sCountdown.speed == 3) { // Counting down from exceed3 limit if (sCountdown.exceedcount[1] != 0) { sCountdown.exceedcount[1]--; } // Speed up if equal to 0 else { countdown_droptozero(); } } } } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Set clock update flag display.flag.update_time = 1; // While SimpliciTI stack operates or BlueRobin searches, freeze system state if (is_rf() || is_bluerobin_searching()) { // SimpliciTI automatic timeout if (sRFsmpl.timeout == 0) { simpliciti_flag |= SIMPLICITI_TRIGGER_STOP; } else { sRFsmpl.timeout--; } // Exit from LPM3 on RETI _BIC_SR_IRQ(LPM3_bits); return; } // ------------------------------------------------------------------- // Service modules that require 1/min processing if (sTime.drawFlag >= 2) { // Measure battery voltage to keep track of remaining battery life request.flag.voltage_measurement = 1; // Check if alarm needs to be turned on check_alarm(); } // ------------------------------------------------------------------- // Service active modules that require 1/s processing // Generate alarm signal if (sAlarm.state == ALARM_ON) { // Decrement alarm duration counter if (sAlarm.duration-- > 0) { request.flag.buzzer = 1; } else { sAlarm.duration = ALARM_ON_DURATION; stop_alarm(); } } // Do a temperature measurement each second while menu item is active if (is_temp_measurement()) request.flag.temperature_measurement = 1; // Do a pressure measurement each second while menu item is active if (is_altitude_measurement()) { // Countdown altitude measurement timeout while menu item is active sAlt.timeout--; // Stop measurement when timeout has elapsed if (sAlt.timeout == 0) { stop_altitude_measurement(); // Show ---- m/ft display_chars(LCD_SEG_L1_3_0, (u8*)"----", SEG_ON); // Clear up/down arrow display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } // In case we missed the IRQ due to debouncing, get data now if ((PS_INT_IN & PS_INT_PIN) == PS_INT_PIN) request.flag.altitude_measurement = 1; } // Count down timeout if (is_acceleration_measurement()) { // Countdown acceleration measurement timeout sAccel.timeout--; // Stop measurement when timeout has elapsed if (sAccel.timeout == 0) as_stop(); // If DRDY is (still) high, request data again if ((AS_INT_IN & AS_INT_PIN) == AS_INT_PIN) request.flag.acceleration_measurement = 1; } // If BlueRobin transmitter is connected, get data from API if (is_bluerobin()) get_bluerobin_data(); // If battery is low, decrement display counter if (sys.flag.low_battery) { if (sBatt.lobatt_display-- == 0) { message.flag.prepare = 1; message.flag.type_lobatt = 1; sBatt.lobatt_display = BATTERY_LOW_MESSAGE_CYCLE; } } // If a message has to be displayed, set display flag if (message.all_flags) { if (message.flag.prepare) { message.flag.prepare = 0; message.flag.show = 1; } else if (message.flag.erase) // message cycle is over, so erase it { message.flag.erase = 0; display.flag.full_update = 1; } } // ------------------------------------------------------------------- // Check idle timeout, set timeout flag if (sys.flag.idle_timeout_enabled) { if (sTime.system_time - sTime.last_activity > INACTIVITY_TIME) sys.flag.idle_timeout = 1; //setFlag(sysFlag_g, SYS_TIMEOUT_IDLE); } // ------------------------------------------------------------------- // Detect continuous button high states // Trying to lock/unlock buttons? if (BUTTON_NUM_IS_PRESSED && BUTTON_DOWN_IS_PRESSED) { if (button_lock_counter++ > LEFT_BUTTON_LONG_TIME) { // Toggle lock / unlock buttons flag sys.flag.lock_buttons = ~sys.flag.lock_buttons; // Show "buttons are locked/unlocked" message synchronously with next second tick message.flag.prepare = 1; if (sys.flag.lock_buttons) message.flag.type_locked = 1; else message.flag.type_unlocked = 1; // Reset button lock counter button_lock_counter = 0; } } else // Trying to create a long button press? { // Reset button lock counter button_lock_counter = 0; if (BUTTON_UP_IS_PRESSED) { sButton.up_timeout++; // Check if button was held low for some seconds if (sButton.up_timeout > LEFT_BUTTON_LONG_TIME) { button.flag.up_long = 1; sButton.up_timeout = 0; } } else { sButton.up_timeout = 0; } if (BUTTON_DOWN_IS_PRESSED) { sButton.down_timeout++; // Check if button was held low for some seconds if (sButton.down_timeout > LEFT_BUTTON_LONG_TIME) { button.flag.down_long = 1; sButton.down_timeout = 0; } } else { sButton.down_timeout = 0; } if (BUTTON_NUM_IS_PRESSED) { sButton.num_timeout++; // Check if button was held low for some seconds if (sButton.num_timeout > LEFT_BUTTON_LONG_TIME) { button.flag.num_long = 1; sButton.num_timeout = 0; } } else { sButton.num_timeout = 0; } } // Exit from LPM3 on RETI _BIC_SR_IRQ(LPM3_bits); }
// ************************************************************************************************* // @fn display_altitude // @brief Display routine. Supports display in meters and feet. // @param u8 line LINE1 // u8 update DISPLAY_LINE_UPDATE_FULL, // DISPLAY_LINE_UPDATE_PARTIAL, DISPLAY_LINE_CLEAR // @return none // ************************************************************************************************* void display_altitude(u8 line, u8 update) { u8 *str; s16 ft; // redraw whole screen if (update == DISPLAY_LINE_UPDATE_FULL) { // Enable pressure measurement sAlt.state = MENU_ITEM_VISIBLE; // Start measurement start_altitude_measurement(); // Display altitude display_altitude(LINE1, DISPLAY_LINE_UPDATE_PARTIAL); } else if (update == DISPLAY_LINE_UPDATE_PARTIAL) { // Update display only while measurement is active if (sAlt.timeout > 0) { if (sAlt.display == DISPLAY_DEFAULT_VIEW) { display_symbol(LCD_UNIT_L1_PER_H, SEG_OFF); display_symbol(LCD_SYMB_AM, SEG_OFF); if (sys.flag.use_metric_units) { // Display "m" symbol display_symbol(LCD_UNIT_L1_M, SEG_ON); } else { // Display "ft" symbol display_symbol(LCD_UNIT_L1_FT, SEG_ON); } if (sys.flag.use_metric_units) { // Display altitude in xxxx m format, allow 3 leading blank digits if (sAlt.altitude >= 0) { str = int_to_array(sAlt.altitude, 4, 3); display_symbol(LCD_SYMB_ARROW_UP, SEG_ON); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } else { str = int_to_array((-1)*sAlt.altitude, 4, 3); //const u8 neg_txt[3] ="NEG"; //str = (u8 *)neg_txt; display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_ON); } } else { // Convert from meters to feet ft = convert_m_to_ft(sAlt.altitude); // Limit to 9999ft (3047m) if (ft > 9999) ft = 9999; // Display altitude in xxxx ft format, allow 3 leading blank digits if (ft >= 0) { str = int_to_array(ft, 4, 3); display_symbol(LCD_SYMB_ARROW_UP, SEG_ON); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } else { str = int_to_array(ft * (-1), 4, 3); display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_ON); } } display_symbol(LCD_ICON_RECORD, SEG_OFF_BLINK_OFF); display_chars(LCD_SEG_L1_3_0, str, SEG_ON); } else if (sAlt.display == DISPLAY_ALTERNATIVE_VIEW) { // Display Pressure in hPa u16 PressureToDisp = (u16) (((float)sAlt.pressure + 100.00 * (float) sAlt.pressure_offset) / 100.00 + 0.5); str = int_to_array(PressureToDisp, 4, 3); display_symbol(LCD_SYMB_AM, SEG_OFF); display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); display_symbol(LCD_UNIT_L1_M, SEG_OFF); display_symbol(LCD_UNIT_L1_FT, SEG_OFF); display_symbol(LCD_UNIT_L1_PER_H, SEG_ON_BLINK_OFF); display_chars(LCD_SEG_L1_3_0, str, SEG_ON); } else if (sAlt.display == DISPLAY_ALTERNATIVE_VIEW1) { // Display Pressure in mmHg u16 PressureToDisp = (u16) (3.0 * ((float)sAlt.pressure + 100.00 * (float)sAlt.pressure_offset) / 400.00 + 0.5); str = int_to_array(PressureToDisp, 4, 3); // str = int_to_array(sAlt.pressure_delta, 4, 3); display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); display_symbol(LCD_UNIT_L1_M, SEG_OFF); display_symbol(LCD_UNIT_L1_FT, SEG_OFF); display_symbol(LCD_UNIT_L1_PER_H, SEG_OFF); display_symbol(LCD_ICON_RECORD, SEG_OFF_BLINK_OFF); display_symbol(LCD_SYMB_AM, SEG_ON); display_chars(LCD_SEG_L1_3_0, str, SEG_ON); } else if (sAlt.display == DISPLAY_ALTERNATIVE_VIEW2) { display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); display_symbol(LCD_SYMB_AM, SEG_OFF); display_symbol(LCD_UNIT_L1_M, SEG_OFF); display_symbol(LCD_UNIT_L1_FT, SEG_OFF); display_symbol(LCD_UNIT_L1_PER_H, SEG_OFF); display_symbol(LCD_ICON_RECORD, SEG_ON_BLINK_ON); s16 dp = sAlt.pressure_delta; if (dp > 250) { // unstable high pressure display_chars(LCD_SEG_L1_3_0, (u8 *) "UN H", SEG_ON); } else if ((dp >= 50) && (dp <= 250)) { // stable good weather display_chars(LCD_SEG_L1_3_0, (u8 *) " SUN", SEG_ON); } else if ((dp >= -50) && (dp < 50)) { // stable display_chars(LCD_SEG_L1_3_0, (u8 *) "STAB", SEG_ON); } else if ((dp > -250) && (dp < -50)) { // stable rainy display_chars(LCD_SEG_L1_3_0, (u8 *) "RAIN", SEG_ON); } else { // unstable low display_chars(LCD_SEG_L1_3_0, (u8 *) "UN L", SEG_ON); } /* u32 Temp = (u32)((float) sAlt.pressure_sum / ((float) sAlt.pressure_counter * 100.0) + 0.5); str = int_to_array(Temp, 4, 3); display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); display_symbol(LCD_SYMB_AM, SEG_OFF); display_symbol(LCD_UNIT_L1_M, SEG_OFF); display_symbol(LCD_UNIT_L1_FT, SEG_OFF); display_symbol(LCD_UNIT_L1_PER_H, SEG_ON_BLINK_ON); display_chars(LCD_SEG_L1_3_0, str, SEG_ON); */ } else { if (sAlt.pressure_delta >= 0) { str = int_to_array(sAlt.pressure_delta, 4, 3); display_symbol(LCD_SYMB_ARROW_UP, SEG_ON); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } else { str = int_to_array(sAlt.pressure_delta * (-1), 4, 3); display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_ON); } display_symbol(LCD_ICON_RECORD, SEG_OFF_BLINK_OFF); display_symbol(LCD_SYMB_AM, SEG_OFF); display_symbol(LCD_UNIT_L1_M, SEG_OFF); display_symbol(LCD_UNIT_L1_FT, SEG_OFF); display_symbol(LCD_UNIT_L1_PER_H, SEG_ON); display_chars(LCD_SEG_L1_3_0, str, SEG_ON); } } } else if (update == DISPLAY_LINE_CLEAR) { // Disable pressure measurement sAlt.state = MENU_ITEM_NOT_VISIBLE; // Stop measurement stop_altitude_measurement(); // Clean up function-specific segments before leaving function display_symbol(LCD_UNIT_L1_M, SEG_OFF); display_symbol(LCD_UNIT_L1_FT, SEG_OFF); display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); display_symbol(LCD_UNIT_L1_PER_H, SEG_OFF_BLINK_OFF); display_symbol(LCD_SYMB_AM, SEG_OFF); display_symbol(LCD_ICON_RECORD, SEG_OFF_BLINK_OFF); sAlt.display = DISPLAY_DEFAULT_VIEW; } }
void display_altitude(u8 line, u8 update) { u8 * str; #ifndef CONFIG_METRIC_ONLY s16 ft; #endif // redraw whole screen if (update == DISPLAY_LINE_UPDATE_FULL) { // Enable pressure measurement sAlt.state = MENU_ITEM_VISIBLE; // Start measurement start_altitude_measurement(); #ifdef CONFIG_ALTI_ACCUMULATOR display_chars(LCD_SEG_L1_3_0, (u8*)"ALT ", SEG_ON); #endif #ifdef CONFIG_METRIC_ONLY display_symbol(LCD_UNIT_L1_M, SEG_ON); #else if (sys.flag.use_metric_units) { // Display "m" symbol display_symbol(LCD_UNIT_L1_M, SEG_ON); } else { // Display "ft" symbol display_symbol(LCD_UNIT_L1_FT, SEG_ON); } #endif // Display altitude display_altitude(LINE1, DISPLAY_LINE_UPDATE_PARTIAL); } else if (update == DISPLAY_LINE_UPDATE_PARTIAL) { // Update display only while measurement is active if (sAlt.timeout > 0) { #ifndef CONFIG_METRIC_ONLY if (sys.flag.use_metric_units) { #endif // Display altitude in xxxx m format, allow 3 leading blank digits if (sAlt.altitude >= 0) { #ifdef CONFIG_ALTI_ACCUMULATOR str = _itoa(sAlt.altitude, 5, 4); #else str = _itoa(sAlt.altitude, 4, 3); #endif display_symbol(LCD_SYMB_ARROW_UP, SEG_ON); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } else { #ifdef CONFIG_ALTI_ACCUMULATOR str = _itoa(sAlt.altitude*(-1), 4, 3); #else str = _itoa(sAlt.altitude*(-1), 5, 4); #endif display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_ON); } #ifndef CONFIG_METRIC_ONLY } else { // Convert from meters to feet ft = convert_m_to_ft(sAlt.altitude); #ifndef CONFIG_ALTI_ACCUMULATOR // Limit to 9999ft (3047m) if (ft > 9999) ft = 9999; #endif // Display altitude in xxxx ft format, allow 3 leading blank digits if (ft >= 0) { #ifdef CONFIG_ALTI_ACCUMULATOR str = _itoa(ft, 4, 3); #else str = _itoa(ft, 5, 4); #endif display_symbol(LCD_SYMB_ARROW_UP, SEG_ON); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } else { #ifdef CONFIG_ALTI_ACCUMULATOR str = _itoa(ft*(-1), 4, 3); #else str = _itoa(ft*(-1), 5, 4); #endif display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_ON); } } #endif #ifdef CONFIG_ALTI_ACCUMULATOR // display altitude on bottom line (5 digits) clear_line(LINE2); display_chars(LCD_SEG_L2_4_0, str, SEG_ON); #else display_chars(LCD_SEG_L1_3_0, str, SEG_ON); #endif } } else if (update == DISPLAY_LINE_CLEAR) { // Disable pressure measurement sAlt.state = MENU_ITEM_NOT_VISIBLE; // Stop measurement stop_altitude_measurement(); // Clean up function-specific segments before leaving function #ifdef CONFIG_ALTI_ACCUMULATOR // clear off the altitude display from the second line clear_line(LINE2); // should really try to get the date displayed here again too #endif display_symbol(LCD_UNIT_L1_M, SEG_OFF); display_symbol(LCD_UNIT_L1_FT, SEG_OFF); display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } }
__interrupt void RTC_A_ISR(void) #endif { sTime.second++; if (sTime.second == 60) sTime.second = 0; static u8 button_lock_counter = 0; //gibbons TODO: need to put these just in the 1-sec interrupt section? static u8 button_beep_counter = 0; #ifdef CONFIG_CW u8 CW_Message[] = "NOON\0"; #endif switch (RTCIV) { case RTC_RT0PSIFG: // Interval timer (16384Hz - 128Hz interrupts (binary powers) ) // gibbons TODO: put stopwatch 1/100 sec interrupt here? break; case RTC_RT1PSIFG: // Interval timer (64Hz - 0.5Hz interrupts (binary powers) ) break; case RTC_RTCRDYIFG: // RTC registers ready and safe to read (Use this for 1-sec update) // Add 1 second to stored (global) time, update sTime.drawFlag appropriately clock_tick(); // Set clock update flag display.flag.update_time = 1; // While SimpliciTI stack operates or BlueRobin searches, freeze system state //pfs #ifdef ELIMINATE_BLUEROBIN if (is_rf()) #else if (is_rf() || is_bluerobin_searching()) #endif { // SimpliciTI automatic timeout if (sRFsmpl.timeout == 0) { simpliciti_flag |= SIMPLICITI_TRIGGER_STOP; } else { sRFsmpl.timeout--; } // Exit from LPM3 on RETI _BIC_SR_IRQ(LPM3_bits); return; } // ------------------------------------------------------------------- // Service modules that require 1/min processing if (sTime.drawFlag >= 2) { // Measure battery voltage to keep track of remaining battery life request.flag.voltage_measurement = 1; // Check if alarm needs to be turned on //check_alarm(); //gibbons TODO: remove } // ------------------------------------------------------------------- // Service active modules that require 1/s processing #ifdef CONFIG_EGGTIMER if (sEggtimer.state == EGGTIMER_RUN) { eggtimer_tick(); // Subtract 1 second from eggtimer's count } if (sEggtimer.state == EGGTIMER_ALARM) { // no "else if" intentional // Decrement alarm duration counter if (sEggtimer.duration-- > 0) { request.flag.eggtimer_buzzer = 1; } else { stop_eggtimer_alarm(); // Set state to Stop and reset duration } } #endif // Generate alarm signal if (sAlarm.state == ALARM_ON) { // Decrement alarm duration counter if (sAlarm.duration-- > 0) { request.flag.alarm_buzzer = 1; } else { stop_alarm(); } } #ifdef CONFIG_PROUT if (is_prout()) prout_tick(); #endif #ifdef CONFIG_VARIO if(is_vario()) vario_tick(); #endif #ifdef CONFIG_STRENGTH // One more second gone by. if(is_strength()) { strength_tick(); } #endif // Do a temperature measurement each second while menu item is active if (is_temp_measurement()) request.flag.temperature_measurement = 1; // Do a pressure measurement each second while menu item is active #ifdef CONFIG_ALTITUDE if (is_altitude_measurement()) { // Countdown altitude measurement timeout while menu item is active sAlt.timeout--; // Stop measurement when timeout has elapsed if (sAlt.timeout == 0) { stop_altitude_measurement(); // Show ---- m/ft display_chars(LCD_SEG_L1_3_0, (u8*)"----", SEG_ON); // Clear up/down arrow display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } // In case we missed the IRQ due to debouncing, get data now if ((PS_INT_IN & PS_INT_PIN) == PS_INT_PIN) request.flag.altitude_measurement = 1; } #endif #ifdef FEATURE_PROVIDE_ACCEL // Count down timeout if (is_acceleration_measurement()) { // Countdown acceleration measurement timeout sAccel.timeout--; // Stop measurement when timeout has elapsed if (sAccel.timeout == 0) as_stop(); // If DRDY is (still) high, request data again if ((AS_INT_IN & AS_INT_PIN) == AS_INT_PIN) request.flag.acceleration_measurement = 1; } #endif //pfs #ifndef ELIMINATE_BLUEROBIN // If BlueRobin transmitter is connected, get data from API if (is_bluerobin()) get_bluerobin_data(); #endif // If battery is low, decrement display counter if (sys.flag.low_battery) { if (sBatt.lobatt_display-- == 0) { message.flag.prepare = 1; message.flag.type_lobatt = 1; sBatt.lobatt_display = BATTERY_LOW_MESSAGE_CYCLE; } } // If a message has to be displayed, set display flag if (message.all_flags) { if (message.flag.prepare) { message.flag.prepare = 0; message.flag.show = 1; } else if (message.flag.erase) // message cycle is over, so erase it { message.flag.erase = 0; message.flag.block_line1 = 0; message.flag.block_line2 = 0; display.flag.full_update = 1; } } // ------------------------------------------------------------------- // Check idle timeout, set timeout flag if (sys.flag.idle_timeout_enabled) { if (sTime.last_activity > 0) { if (--sTime.last_activity == 0) sys.flag.idle_timeout = 1; //setFlag(sysFlag_g, SYS_TIMEOUT_IDLE); } } // ------------------------------------------------------------------- // Detect continuous button high states if (BUTTON_STAR_IS_PRESSED && BUTTON_UP_IS_PRESSED) { if (button_beep_counter++ > LEFT_BUTTON_LONG_TIME) { // Toggle no_beep buttons flag sys.flag.no_beep = ~sys.flag.no_beep; // Show "beep / nobeep" message synchronously with next second tick message.flag.prepare = 1; if (sys.flag.no_beep) message.flag.type_no_beep_on = 1; else message.flag.type_no_beep_off = 1; // Reset button beep counter button_beep_counter = 0; } } else if (BUTTON_NUM_IS_PRESSED && BUTTON_DOWN_IS_PRESSED) // Trying to lock/unlock buttons? { if (button_lock_counter++ > LEFT_BUTTON_LONG_TIME) { // Toggle lock / unlock buttons flag sys.flag.lock_buttons = ~sys.flag.lock_buttons; // Show "buttons are locked/unlocked" message synchronously with next second tick message.flag.prepare = 1; if (sys.flag.lock_buttons) message.flag.type_locked = 1; else message.flag.type_unlocked = 1; // Reset button lock counter button_lock_counter = 0; } } else // Trying to create a long button press? { // Reset button lock counter button_lock_counter = 0; if (BUTTON_STAR_IS_PRESSED) { sButton.star_timeout++; // Check if button was held low for some seconds if (sButton.star_timeout > LEFT_BUTTON_LONG_TIME) { button.flag.star_long = 1; sButton.star_timeout = 0; } } else { sButton.star_timeout = 0; } if (BUTTON_NUM_IS_PRESSED) { sButton.num_timeout++; // Check if button was held low for some seconds if (sButton.num_timeout > LEFT_BUTTON_LONG_TIME) { button.flag.num_long = 1; sButton.num_timeout = 0; } } else { sButton.num_timeout = 0; } } // Exit from LPM3 on RETI _BIC_SR_IRQ(LPM3_bits); //gibbons TODO: move this to other interrupts from the RTC? break; case RTC_RTCTEVIFG: // Interval alarm event (min or hour changed, or rollover to midnight or noon) (choose one) // Minute, hour, noon, or midnight rollover beep (same beep as button press, at least for now) #ifdef CONFIG_TIMECHIME #ifdef CONFIG_CW CW_Send_String(CW_Message); #else start_buzzer(1, CONV_MS_TO_TICKS(20), CONV_MS_TO_TICKS(150)); #endif if (RTC_Toggle_12Hr) RTCCTL01 ^= 0x0100; // Toggle Time EVent between noon and midnight #endif break; case RTC_RTCAIFG: // User-configurable alarm event // Indicate that alarm is on sAlarm.state = ALARM_ON; break; } //gibbons: TODO: Remove this old code? (Associated with Timer0_A0 1-sec ISR) // Disable IE //TA0CCTL0 &= ~CCIE; // Reset IRQ flag //TA0CCTL0 &= ~CCIFG; // Add 1 sec to TACCR0 register (IRQ will be asserted at 0x7FFF and 0xFFFF = 1 sec intervals) //TA0CCR0 += 32768; //gibbons TODO: Should this perhaps be (32768 - 1) ? // Enable IE //TA0CCTL0 |= CCIE; }
// ************************************************************************************************* // @fn altitude_accumulator_periodic // @brief Is called periodically, reads altitude and accumulates upwards vertical // @param none // @return none // // This function is called once a minute. It reads the current altitude, then uses that to accumulate // upwards altitude only (it does not measure or accumulate downwards altitude - only altitude gains. // It functions as follows. Current direction (either up or down) is given in alt_accum_direction. // // If we're currently going up, then alt_accum_lastpeakdip contains the altitude of the last dip (valley) // we encountered and we're rising up above that. If the current altimeter value is greater than the // previous altimeter reading alt_accum_prevalt, then update alt_accum_prevalt with the current altitude // and we're done. If however we've dropped below the previous value, then if we've exceeded our // "direction change threshold" ALT_ACCUM_DIR_THRESHOLD, then it appears we've peaked and have started // heading downhill. So add (alt_accum_prevalt - alt_accum_lastpeakdip) to alt_accum__accumtotal to // collect that recently-finished uphill into our accumulated uphill total. Then reverse course: // set alt_accum_lastpeakdip equal to alt_accum_prevalt so that lastpeakdip contains the altitude of the // top of that recently-crossed hill (it's now a peak altitude rather than a dip (valley) altitude), // change the alt_accum_direction flag to downhill, and as usual set the alt_accum_prevalt to our current // altitude. // // On the other hand, if our current altitude is only slightly less than the previous altitude, then // do nothing - not even update our "previous" altitude. When we're going uphill, only 2 things matter to // us: either we've gone uphill some more, or we've gone downhill enough to trigger the change-or-direction // threshold. // // If we're going downhill (direction flag alt_accum_direction says downhill), there's little to do except // keep updating alt_accum_prevalt with the current altitude if we've dropped lower, and watch for a // change of direction to an uphill. Much the same as the uphill case, but we don't accumulate downhills // once the change of direction occurs. // // In addition, independently of all this, we also update alt_accum_max with the highest altitude // we've found. // // All measurements are recorded & stored in metres. // // Yes it's a bit convoluted. That's OK. The basic thing to understand is that a "simple" accumulator // simply adds altitude every time we take an altimeter reading. However every reading has an error, so // adding a bunch of readings results in a lot of error. For that reason we have this more complicated // system whereby we look for peaks and dips, and only add to the accumulator when we find the next peak. // In that way we obtain the best accumulator accuracy possible. It does make for a more complicated // system though. // // ************************************************************************************************* void altitude_accumulator_periodic (void) { s32 currentalt; // our current altitude // First a quick sanity check. If we're not supposed to be running, something's wrong, so just exit if (alt_accum_enable==0) return; // First thing we need to know is our current altitude. Take 4 measurements & average them. start_altitude_measurement(); stop_altitude_measurement(); currentalt = sAlt.altitude; // first reading // Now it's comparisions time. First we'll quickly update the maximum altitude tracker if (currentalt > alt_accum_max) alt_accum_max = currentalt; // update max altitude if we're at a new high // Now our convoluted altitude accumulator, looking for peaks and valleys, etc. if (alt_accum_direction) { // Execute here if we're supposedly going upwards if (currentalt >= alt_accum_prevalt) { // Execute here if we're still going upwards - current alt is greater than previous alt alt_accum_prevalt = currentalt; // just update our "previous" value for next time return; // and that's it - we're done } else { // Execute here if our current altitude is below our previous - have we crested the hill and // started to descend? If we've exceeded the threshold altitude drop we need to deal with that. if ((alt_accum_prevalt - currentalt) >= ALT_ACCUM_DIR_THRESHOLD) { // Execute here if we've descended enough off the hillcrest to exceed the threshold - we've just // gone through a change of direction, so we need to accumulate the previously gained altitude, // then set things up for going downhill now. alt_accum__accumtotal += alt_accum_prevalt - alt_accum_lastpeakdip; // accumulate the vertical from that last hill climb alt_accum_lastpeakdip = alt_accum_prevalt; // peakdip is now a peak elevation alt_accum_direction = 0; // indicate we're tracking downhill now return; } else // we've dropped a little, but not enough to trigger any action yet return; } } else { // Execute here if we're supposedly going downwards if (currentalt <= alt_accum_prevalt) { // Execute here if we're still going downwards - current alt is less than previous alt alt_accum_prevalt = currentalt; // just update our "previous" value for next time return; // and that's it - we're done } else { // Execute here if our current altitude is above our previous - have we bottomed the valley and // started to ascend? If we've exceeded the threshold altitude increase we need to deal with that. if ((currentalt - alt_accum_prevalt) >= ALT_ACCUM_DIR_THRESHOLD) { // Execute here if we've ascended enough above the valley floor to exceed the threshold - we've just // gone through a change of direction, so we need to set things up for going uphill now. alt_accum_lastpeakdip = alt_accum_prevalt; // peakdip is now a dip (valley) elevation alt_accum_direction = 1; // indicate we're tracking uphill now return; } else // we've ascended a little, but not enough to trigger any action yet return; } } }
// ************************************************************************************************* // @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*)"0430", SEG_ON); display_chars(LCD_SEG_L2_4_0, (u8*)"CC430", 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 #ifdef CONFIG_ALTITUDE 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(); #endif 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 = itoa( sAccel.xyz[0], 3, 0); display_chars(LCD_SEG_L1_2_0, str, SEG_ON); str = itoa( sAccel.xyz[2], 3, 0); display_chars(LCD_SEG_L2_2_0, str, SEG_ON); } as_stop(); break; //pfs #ifndef ELIMINATE_BLUEROBIN 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; #endif } // 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; break; } } }
// ************************************************************************************************* // @fn display_alt_accumulator // @brief Display altitude accumulator routine. Supports display in meters and feet. // @param u8 line LINE1 // u8 update DISPLAY_LINE_UPDATE_FULL, DISPLAY_LINE_UPDATE_PARTIAL, DISPLAY_LINE_CLEAR // @return none // ************************************************************************************************* void display_alt_accumulator (u8 line, u8 update) { s32 temp; u8 * str; // show our altitude accumulator numbers on the second line if ( (update==DISPLAY_LINE_UPDATE_FULL) || (update==DISPLAY_LINE_UPDATE_PARTIAL) ) { // Show "ALtA" on top line display_chars(LCD_SEG_L1_3_0, (u8*)"ALTA", SEG_ON); // if the altitude accumulator is currently disabled, we've got nothing else to display so exit if (alt_accum_enable == 0) { clear_line(LINE2); display_chars(LCD_SEG_L2_4_0, (u8*)" OFF ", SEG_ON); // display "OFF" on bottom line return; } // Otherwise the accumulator is running, so display on the second line whatever alt_accum_displaycode // says to display, in metres or feet as appropriate. if (alt_accum_displaycode>2) alt_accum_displaycode=0; // sanity check // light up "m" or "ft" display symbol as appropriate if (sys.flag.use_metric_units) display_symbol(LCD_UNIT_L1_M, SEG_ON); // metres symbol else display_symbol(LCD_UNIT_L1_FT, SEG_ON); // or feet symbol if (alt_accum_displaycode==0) { // Display current altitude relative to the accumulator's starting point // "DIFF" means difference between starting elevation & current elevation display_chars(LCD_SEG_L1_3_0, (u8*)"DIFF", SEG_ON); // top line display message start_altitude_measurement(); stop_altitude_measurement(); // grab our current altitude temp = sAlt.altitude - alt_accum_startpoint; // difference between starting altitude & current altitude if (sys.flag.use_metric_units==0) temp = (temp*328)/100; // convert to feet if necessary clear_line(LINE2); // clear the bottom line of the display if (temp < 0) { // if altitude is a negative number... display_char(LCD_SEG_L2_4, '-', SEG_ON); // display - (negative sign) character at start of second line temp = 0 - temp; // make altitude a positive number again so we can display it if (temp>9999) temp = 9999; // we can only display 4 digits for a negative number str = _itoa(temp, 4, 3); // 4 digits, up to 3 leading blank digits display_chars(LCD_SEG_L2_3_0, str, SEG_ON); // display altitude difference on bottom line (4 digits) return; } else // otherwise altitude difference is a positive number { str = _itoa(temp, 5, 4); // 5 digits, up to 4 leading blank digits display_chars(LCD_SEG_L2_4_0, str, SEG_ON); // display altitude difference on bottom line (5 digits) return; } } else if (alt_accum_displaycode==1) { // Display total accumulated elevation gain. Remember we might currently be going uphill // so we need to check for, and include, any current elevation gain display_chars(LCD_SEG_L1_3_0, (u8*)"ACCA", SEG_ON); // top line display message clear_line(LINE2); // clear the bottom line of the display if (alt_accum__accumtotal<0) alt_accum__accumtotal = 0; // accumulated total should never be negative! temp = alt_accum__accumtotal; // local copy of accumulated total // Now we need to add on any vertical gained recently, that hasn't yet been included in alt_accum__accumtotal // This only happens if we're currently going uphill, and we've above our last valley / dip elevation if (alt_accum_direction && (sAlt.altitude>alt_accum_lastpeakdip)) // if we're going up, and we're higher than our last dip (valley) altitude temp += sAlt.altitude - alt_accum_lastpeakdip; // then add the vertical we've gained so far above that last dip / valley point // display the result str = _itoa(temp, 5, 4); // 5 digits, up to 4 leading blank digits display_chars(LCD_SEG_L2_4_0, str, SEG_ON); // display peak altitude on bottom line (5 digits) return; } else { // Display maximum altitude found so far display_chars(LCD_SEG_L1_3_0, (u8*)"PEAK", SEG_ON); // top line display message clear_line(LINE2); // clear the bottom line of the display temp = alt_accum_max; // local copy of peak altitude if (temp < 0) temp = 0; // I can't be bothered displaying a negative number! So make it zero if it is. str = _itoa(temp, 5, 4); // 5 digits, up to 4 leading blank digits display_chars(LCD_SEG_L2_4_0, str, SEG_ON); // display peak altitude on bottom line (5 digits) return; } } // clear out - we're finished else if (update == DISPLAY_LINE_CLEAR) { clear_line(LINE2); // clear off the altitude display from the second line // should really try to get the date displayed here again // Clean up function-specific segments before leaving function display_symbol(LCD_UNIT_L1_M, SEG_OFF); display_symbol(LCD_UNIT_L1_FT, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } }
// ************************************************************************************************* // @fn display_altitude // @brief Display routine. Supports display in meters and feet. // @param u8 line LINE1 // u8 update DISPLAY_LINE_UPDATE_FULL, DISPLAY_LINE_UPDATE_PARTIAL, DISPLAY_LINE_CLEAR // @return none // ************************************************************************************************* void display_altitude(u8 line, u8 update) { u8 * str; s16 ft; // redraw whole screen if (update == DISPLAY_LINE_UPDATE_FULL) { // Enable pressure measurement sAlt.state = MENU_ITEM_VISIBLE; // Start measurement start_altitude_measurement(); // Display altitude display_altitude(LINE1, DISPLAY_LINE_UPDATE_PARTIAL); } else if (update == DISPLAY_LINE_UPDATE_PARTIAL) { // Update display only while measurement is active if (sAlt.timeout > 0) { // Altitude view if (PressDisplay == DISPLAY_DEFAULT_VIEW) { display_symbol(LCD_SEG_L1_DP1, SEG_OFF); if (sys.flag.use_metric_units) { // Display "m" symbol display_symbol(LCD_UNIT_L1_M, SEG_ON); // Display altitude in xxxx m format, allow 3 leading blank digits if (sAlt.altitude >= 0) { str = itoa(sAlt.altitude, 4, 3); display_symbol(LCD_SYMB_ARROW_UP, SEG_ON); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } else { str = itoa(sAlt.altitude*(-1), 4, 3); display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_ON); } } else { // Display "ft" symbol display_symbol(LCD_UNIT_L1_FT, SEG_ON); // Convert from meters to feet ft = convert_m_to_ft(sAlt.altitude); // Limit to 9999ft (3047m) if (ft > 9999) ft = 9999; // Display altitude in xxxx ft format, allow 3 leading blank digits if (ft >= 0) { str = itoa(ft, 4, 3); display_symbol(LCD_SYMB_ARROW_UP, SEG_ON); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } else { str = itoa(ft*(-1), 4, 3); display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_ON); } } } // Pressure view, unit: milliBar = hectoPascal else if (PressDisplay == DISPLAY_ALTERNATIVE_VIEW) { display_symbol(LCD_SEG_L1_DP1, SEG_OFF); display_symbol(LCD_UNIT_L1_M, SEG_OFF); display_symbol(LCD_UNIT_L1_FT, SEG_OFF); display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); str = itoa(AmbientPressure, 4, 3); } // Pressure view, unit: PSI (Pound-force per square inch absolute) 1mbar = 0.01450377 PSI else // DISPLAY_ALTERNATIVE_VIEW_2 { str = itoa((u32)AmbientPressure * 10000L / 6895L, 4, 3); display_symbol(LCD_SEG_L1_DP1, SEG_ON); } display_chars(LCD_SEG_L1_3_0, str, SEG_ON); } } else if (update == DISPLAY_LINE_CLEAR) { // Disable pressure measurement sAlt.state = MENU_ITEM_NOT_VISIBLE; // Stop measurement stop_altitude_measurement(); // Clean up function-specific segments before leaving function display_symbol(LCD_SEG_L1_DP1, SEG_OFF); display_symbol(LCD_UNIT_L1_M, SEG_OFF); display_symbol(LCD_UNIT_L1_FT, SEG_OFF); display_symbol(LCD_SYMB_ARROW_UP, SEG_OFF); display_symbol(LCD_SYMB_ARROW_DOWN, SEG_OFF); } }