void init_watchdog(void) { /* Enable interface clock */ LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 15); LPC_SYSCON->WDTCLKSEL = 0x0; // Use IRC oscillator LPC_SYSCON->WDTCLKUEN = 1; // Switch Clock LPC_SYSCON->WDTCLKUEN = 0; LPC_SYSCON->WDTCLKUEN = 1; // Switch Clock LPC_SYSCON->WDTCLKDIV = 1; /* IRC = 12MHz, TC = 4 * 12*10_6, => Twdt = 4 seconds */ LPC_WDT->TC = 12*1000*1000; // MAX: 2^24 /* Lock on the watchdog */ LPC_WDT->MOD |= 0x3; // WDEN = 1, WDRESET = 1 /* And feed to enable */ feed_watchdog(); /* Make sure feed sequence completed */ for (int i = 0; i < 0x80000; i++); }
/********************************************************************* * @fn Thermometer_ProcessEvent * * @brief Thermometer Application Task event processor. This function * is called to process all events for the task. Events * include timers, messages and any other user defined events. * * @param task_id - The OSAL assigned task ID. * @param events - events to process. This is a bit map and can * contain more than one event. * * @return events not processed */ uint16 Thermometer_ProcessEvent(uint8 task_id, uint16 events) { struct ther_info *ti = &ther_info; /* message handle */ if ( events & SYS_EVENT_MSG ) { uint8 *msg; if ( (msg = osal_msg_receive(ti->task_id)) != NULL ) { ther_dispatch_msg(ti, (osal_event_hdr_t *)msg); osal_msg_deallocate( msg ); } return (events ^ SYS_EVENT_MSG); } if (events & TH_POWER_ON_EVT) { ther_system_power_on(ti); return (events ^ TH_POWER_ON_EVT); } if (events & TH_POWER_OFF_EVT) { ther_system_power_off_post(ti); return (events ^ TH_POWER_OFF_EVT); } if (events & TH_AUTO_POWER_OFF_EVT) { if (!ti->ble_connect && ((ti->previous_temp >= ti->temp_current && ti->previous_temp - ti->temp_current < 50) || (ti->previous_temp < ti->temp_current && ti->temp_current - ti->previous_temp < 50))) { ti->same_temp_number++; } else { ti->same_temp_number = 0; // ti->previous_temp = ti->temp_current; } print(LOG_DBG, MODULE "auto power off: same_temp_number %d\n", ti->same_temp_number); if (ti->same_temp_number >= AUTO_POWER_OFF_NUMBER_THRESHOLD) { print(LOG_DBG, MODULE "auto power off\n"); ther_system_power_off_pre(ti); } else { osal_start_timerEx( ti->task_id, TH_AUTO_POWER_OFF_EVT, AUTO_POWER_OFF_MEASURE_INTERVAL); } return (events ^ TH_AUTO_POWER_OFF_EVT); } /* batt measure */ if (events & TH_BATT_EVT) { if (ti->mode == NORMAL_MODE) { Batt_MeasLevel(); ti->batt_percentage = ther_batt_get_percentage(FALSE); oled_update_picture(OLED_CONTENT_BATT, TRUE, ti->batt_percentage); print(LOG_DBG, MODULE "batt %d%%\n", ti->batt_percentage); if (!ti->batt_warning_on && ti->batt_percentage < 10) { ti->batt_warning_on = TRUE; osal_start_timerEx( ti->task_id, TH_LOW_BATT_WARNING_EVT, LOW_BATT_WARNING_INTERVAL); } osal_start_timerEx( ti->task_id, TH_BATT_EVT, BATT_MEASURE_INTERVAL); } return (events ^ TH_BATT_EVT); } if (events & TH_LOW_BATT_BLINK_EVT) { if (ti->batt_in_dispaly) { oled_update_picture(OLED_CONTENT_BATT, FALSE, 0); ti->batt_in_dispaly = FALSE; } else { oled_update_picture(OLED_CONTENT_BATT, TRUE, ti->batt_percentage); ti->batt_in_dispaly = TRUE; } if (ti->display_picture != OLED_PICTURE_NONE) osal_start_timerEx(ti->task_id, TH_LOW_BATT_BLINK_EVT, LOW_BATT_BLINK_INTERVAL); return (events ^ TH_LOW_BATT_BLINK_EVT); } if (events & TH_LOW_BATT_WARNING_EVT) { ther_buzzer_start_music(BUZZER_MUSIC_LOW_BATT_WARNING); if (ti->batt_percentage < LOW_BATT_WARNING_THRESHOLD) osal_start_timerEx( ti->task_id, TH_LOW_BATT_WARNING_EVT, LOW_BATT_WARNING_INTERVAL); else ti->batt_warning_on = FALSE; return (events ^ TH_LOW_BATT_WARNING_EVT); } /* temp measure event */ if (events & TH_TEMP_MEASURE_EVT) { if (ti->mode != NORMAL_MODE) { return (events ^ TH_TEMP_MEASURE_EVT); } switch (ti->temp_measure_stage) { case TEMP_STAGE_SETUP: ther_temp_power_on(); osal_start_timerEx( ti->task_id, TH_TEMP_MEASURE_EVT, TEMP_POWER_SETUP_TIME); ti->temp_measure_stage = TEMP_STAGE_MEASURE; break; case TEMP_STAGE_MEASURE: ti->temp_last_saved = ti->temp_current; ti->temp_current = (int16)(ther_read_temp() * 100 + 0.5); ther_temp_power_off(); /* for auto power off, save only once */ if (ti->previous_temp == 0) ti->previous_temp = ti->temp_current; if (ti->temp_max < ti->temp_current) { ti->temp_max = ti->temp_current; print(LOG_DBG, MODULE "update max temp to %d\n", ti->temp_max); oled_update_picture(OLED_CONTENT_MAX_TEMP, TRUE, ti->temp_max); } /* high temp warning */ if (ti->warning_enabled && !ti->temp_warning_on && ti->temp_current >= ti->next_warning_threshold) { ti->temp_warning_on = TRUE; osal_start_timerEx( ti->task_id, TH_HIGH_TEMP_WARNING_EVT, HIGH_TEMP_WARNING_INTERVAL); } if (ti->temp_warning_on && ti->temp_current < ti->next_warning_threshold) { ti->next_warning_threshold -= 50; /* 0.5 C */ if (ti->next_warning_threshold < ti->high_temp_threshold) ti->next_warning_threshold = ti->high_temp_threshold; ti->temp_warning_on = FALSE; osal_stop_timerEx(ti->task_id, TH_HIGH_TEMP_WARNING_EVT); } if (ti->ble_connect) { if (ti->temp_notification_enable) { // ther_send_temp_notify(ti->temp_current); } if (ti->temp_indication_enable) { ther_send_temp_indicate(ti->task_id, ti->temp_current); } } else { ther_save_temp_to_local(ti->temp_current); } if (ti->temp_current != ti->temp_last_saved) { oled_update_picture(OLED_CONTENT_TEMP, TRUE, ti->temp_current); } osal_start_timerEx( ti->task_id, TH_TEMP_MEASURE_EVT, ti->temp_measure_interval); ti->temp_measure_stage = TEMP_STAGE_SETUP; break; default: break; } return (events ^ TH_TEMP_MEASURE_EVT); } if (events & TH_HIGH_TEMP_WARNING_EVT) { ther_buzzer_start_music(BUZZER_MUSIC_HIGH_TEMP_WARNING); osal_start_timerEx( ti->task_id, TH_HIGH_TEMP_WARNING_EVT, HIGH_TEMP_WARNING_INTERVAL); return (events ^ TH_HIGH_TEMP_WARNING_EVT); } if (events & TH_HIS_TEMP_RESTORE_EVT) { if (!ti->his_temp_bundle) { if (ti->temp_notification_enable) { storage_restore_temp((uint8 **)&ti->his_temp_bundle, &ti->his_temp_len); if (ti->his_temp_bundle) { ti->his_temp_offset = 0; osal_start_timerEx(ti->task_id, TH_HIS_TEMP_RESTORE_EVT, HIS_TEMP_UPLOADING_INTERVAL); } else { print(LOG_DBG, MODULE "his temp restore: no more his temp, exit\n"); ti->his_temp_uploading = FALSE; } } else if (!ti->ble_connect) { print(LOG_DBG, MODULE "his temp restore: ble disconnect, exit\n"); ti->his_temp_uploading = FALSE; } else { // print(LOG_DBG, MODULE "his temp restore: wait for notify enable\n"); osal_start_timerEx(ti->task_id, TH_HIS_TEMP_RESTORE_EVT, HIS_TEMP_RESTORE_WAIT_ENABLE); } } else { if (ti->his_temp_offset < ti->his_temp_len) { uint8 *data = ti->his_temp_bundle + ti->his_temp_offset; ther_send_history_temp(ti->task_id, data, sizeof(struct temp_data)); ti->his_temp_offset += sizeof(struct temp_data); } else { ti->his_temp_bundle = NULL; ti->his_temp_offset = 0; ti->his_temp_len = 0; print(LOG_DBG, MODULE "his temp restore: a bundle uploading completed\n"); } osal_start_timerEx(ti->task_id, TH_HIS_TEMP_RESTORE_EVT, HIS_TEMP_UPLOADING_INTERVAL); } return (events ^ TH_HIS_TEMP_RESTORE_EVT); } /* Display event */ if (events & TH_DISPLAY_EVT) { oled_display_state_machine(); return (events ^ TH_DISPLAY_EVT); } /* buzzer event */ if (events & TH_BUZZER_EVT) { ther_buzzer_playing_music(); return (events ^ TH_BUZZER_EVT); } /* button event */ if (events & TH_BUTTON_EVT) { ther_measure_button_time(); return (events ^ TH_BUTTON_EVT); } if (events & TH_WATCHDOG_EVT) { feed_watchdog(); osal_start_timerEx(ti->task_id, TH_WATCHDOG_EVT, WATCHDOG_FEED_INTERVAL); return (events ^ TH_WATCHDOG_EVT); } if (events & TH_TEST_EVT) { { struct display_param param; if (ti->display_picture > OLED_PICTURE_NONE) { print(LOG_DBG, MODULE "ignore button press when picture is %d\n", ti->display_picture); return (events ^ TH_TEST_EVT); } encap_picture_param(ti, ¶m); if (ti->display_picture == OLED_PICTURE_NONE) { oled_show_picture(OLED_PICTURE1, DISPLAY_TIME, ¶m); } else { oled_show_next_picture(DISPLAY_TIME, ¶m); } } osal_start_timerEx(ti->task_id, TH_TEST_EVT, SEC_TO_MS(10 * 60)); return (events ^ TH_TEST_EVT); } return 0; }
/** * Main system entry point */ int main (void) { SystemInit(); /* Initialise Pins */ CUTDOWN_OFF(); HEATER_OFF(); MBED_OFF(); GREEN_OFF(); /* Update the value of SystemCoreClock */ SystemCoreClockUpdate(); /* Initialise Interfaces */ i2c_init(); spi_init(process_imu_frame); // IMU sd_spi_init(); // SD uart_init(); // GPS pwrmon_init(); // ADC /* Initialise Sensors */ init_barometer(); /* SD Card */ if (initialise_card()) { // Initialised to something if (disk_initialize() == 0) { // Disk initialisation was successful sd_good = 1; } } GREEN_ON(); /* Configure the SysTick */ NVIC_SetPriority(SysTick_IRQn, 0); // Highest Priority Interrupt SysTick_Config(SystemCoreClock / RTTY_BAUD); /* Watchdog - Disabled for debugging */ #ifndef WATCHDOG_DISABLED init_watchdog(); #endif struct barometer* b; struct imu_raw ir; struct gps_data gd; struct gps_time gt; double alt, ext_temp; int tx_length; // The length of the built tx string char tx_string[TX_STRING_LENGTH]; while (1) { /* Grab Data */ pwrmon_start(pwrmon_callback); b = get_barometer(); get_imu_raw_data(&ir); get_gps_data(&gd); get_gps_time(>); ext_temp = get_temperature(); /* Data Processing */ if (b->valid) { alt = pressure_to_altitude(b->pressure); } else { alt = -1; b->temperature = -1; } /* Act on the data */ control_gsm(alt); control_cutdown(ticks_until_cutdown, alt); control_heater(b->temperature); /* Create a protocol string */ int cutstat; if (ticks_until_cutdown == 0) { cutstat = -1; } else { cutstat = ticks_until_cutdown / (RTTY_BAUD*60); } tx_length = build_communications_frame(tx_string, TX_STRING_LENGTH, >, b, &gd, alt, ext_temp, &ir, cutstat, cutdown_voltage); /* Transmit - Quietly fails if another transmission is ongoing */ rtty_set_string(tx_string, tx_length); /* Store */ if (sd_good) { tx_length -= 2; // Remove \n\0 tx_length += communications_frame_add_extra(tx_string + tx_length, TX_STRING_LENGTH - tx_length, &ir); disk_write_next_block((uint8_t*)tx_string, tx_length+1); // Include null terminator } /* Housekeeping */ GREEN_TOGGLE(); feed_watchdog(); } }