static void sound_test_cb(guiObject_t *obj, void *data) { (void)obj; u8 idx = (long)data; #if HAS_EXTENDED_AUDIO && HAS_MUSIC_CONFIG MUSIC_Play(MUSIC_GetTelemetryAlarm(MUSIC_TELEMALARM1 + idx)); #else MUSIC_Play(MUSIC_TELEMALARM1 + idx); #endif }
void PAGE_SplashEvent() { static unsigned int time=0; #if HAS_EXTENDED_AUDIO static unsigned int time_startup_msg; #endif if(GUI_IsModal()) return; // u8 step = 5; if ( 0 == time ) { time = CLOCK_getms() + Transmitter.splash_delay * 100; #if HAS_EXTENDED_AUDIO time_startup_msg = CLOCK_getms() + 5 * 100; // Dealy 0.5 second to play startup audio #endif } #if HAS_EXTENDED_AUDIO if (time_startup_msg && (CLOCK_getms() > time_startup_msg) ) { AUDIO_SetVolume(); MUSIC_Play(MUSIC_STARTUP); time_startup_msg = 0; } #endif if ( CLOCK_getms() > time ) PAGE_ChangeByID(PAGEID_MAIN,0); /* if ( offset > 0 ) { offset -= step; GUI_ChangeImage(&gui->splash_image,SPLASH_FILE,offset,0); GUI_Redraw(&gui->splash_image); }*/ }
void TIMER_Power(){ static u32 timer = 0; u32 alert = Transmitter.power_alarm * 60 * 1000; static u16 throttle; u16 new_throttle; u16 elevator; unsigned mode = MODE_2 == Transmitter.mode || MODE_4 == Transmitter.mode ? 2 : 1; if( 0 == timer) timer = CLOCK_getms() + alert; elevator = 2 == mode ? abs(CHAN_ReadInput(INP_THROTTLE)) : abs(CHAN_ReadInput(INP_ELEVATOR)); new_throttle = 2 == mode ? abs(CHAN_ReadInput(INP_ELEVATOR)) : abs(CHAN_ReadInput(INP_THROTTLE)); new_throttle = abs(new_throttle - throttle); if( elevator < 1000 && abs(CHAN_ReadInput(INP_AILERON)) < 1000 && new_throttle < 1000 && abs(CHAN_ReadInput(INP_RUDDER)) < 1000 && !ScanButtons() && (!HAS_TOUCH || !SPITouch_IRQ()) ) { if ( CLOCK_getms() > timer ) { timer = CLOCK_getms() + 2000; MUSIC_Play(MUSIC_SHUTDOWN); } } else timer = CLOCK_getms() + alert; throttle = 2 == mode ? abs(CHAN_ReadInput(INP_ELEVATOR)) : abs(CHAN_ReadInput(INP_THROTTLE)); }
void kb_update_string(struct guiKeyboard *keyboard, u8 ch) { u8 len = strlen(keyboard->text); if(ch == '\x08') { if (len > 0) { keyboard->text[len - 1] = 0; _kb_draw_text(keyboard->text); } return; } if (keyboard->type == KEYBOARD_NUM) { s32 val = atoi(keyboard->text); val = val * 10 + (ch - '0'); if (val > keyboard->max_size) return; sprintf(keyboard->text, "%d", (int)val); _kb_draw_text(keyboard->text); return; } if (len >= keyboard->max_size) { MUSIC_Play(MUSIC_MAXLEN); return; } if(! (keyboard->flags & FLAG_CAPS) && ch >= 'A' && ch <= 'Z') { ch = (ch - 'A') + 'a'; } keyboard->text[len] = ch; keyboard->text[len+1] = 0; _kb_draw_text(keyboard->text); }
static unsigned _action_cb(u32 button, unsigned flags, void *data) { if (CHAN_ButtonIsPressed(button, BUT_ENTER)) { MUSIC_Play(MUSIC_SAVING); save_changes(); return 1; } return default_button_action_cb(button, flags, data); }
void EventLoop() { CLOCK_ResetWatchdog(); unsigned int time; #ifdef HEAP_DEBUG static int heap = 0; int h = _sbrk_r(NULL, 0); if(h > heap) { printf("heap: %x\n", h); heap = h; } #endif #ifdef TIMING_DEBUG debug_timing(0, 0); #endif priority_ready &= ~(1 << MEDIUM_PRIORITY); if(PWR_CheckPowerSwitch()) { if(! (BATTERY_Check() & BATTERY_CRITICAL)) { CONFIG_SaveModelIfNeeded(); CONFIG_SaveTxIfNeeded(); } if(Transmitter.music_shutdown) { MUSIC_Play(MUSIC_SHUTDOWN); // We wait ~1sec for shutdown music finished time = CLOCK_getms()+700; while(CLOCK_getms()<time); } PWR_Shutdown(); } BUTTON_Handler(); TOUCH_Handler(); if (priority_ready & (1 << LOW_PRIORITY)) { priority_ready &= ~(1 << LOW_PRIORITY); PAGE_Event(); PROTOCOL_CheckDialogs(); TIMER_Update(); TELEMETRY_Alarm(); BATTERY_Check(); AUTODIMMER_Update(); #if DATALOG_ENABLED DATALOG_Update(); #endif GUI_RefreshScreen(); } #ifdef TIMING_DEBUG debug_timing(0, 1); #endif }
static const char *_buzz_vol_cb(guiObject_t *obj, int dir, void *data) { (void)data; u8 *unsigned_data = (u8 *)data; u8 changed; if (GUI_IsTextSelectEnabled(obj)) { *unsigned_data = GUI_TextSelectHelper(*unsigned_data, 0, 10, dir, 1, 1, &changed); if (changed) MUSIC_Play(MUSIC_VOLUME); } if (*unsigned_data == 0) return _tr("Off"); sprintf(tempstring, "%d", *unsigned_data); return tempstring; }
static unsigned _action_cb(u32 button, unsigned flags, void *data) { (void)data; if ((flags & BUTTON_PRESS) || (flags & BUTTON_LONGPRESS)) { if (CHAN_ButtonIsPressed(button, BUT_EXIT)) { PAGE_ChangeByID(PAGEID_MENU, PREVIOUS_ITEM); } else if (CHAN_ButtonIsPressed(button, BUT_ENTER)) { MUSIC_Play(MUSIC_SAVING); save_changes(); } else { // only one callback can handle a button press, so we don't handle BUT_ENTER here, let it handled by press cb return 0; } } return 1; }
MODULE_CALLTYPE static u16 cflie_callback() { switch (phase) { case CFLIE_INIT_SEARCH: send_search_packet(); phase = CFLIE_SEARCH; break; case CFLIE_INIT_CRTP_LOG: if (crtp_log_setup_state_machine()) { phase = CFLIE_INIT_DATA; } break; case CFLIE_INIT_DATA: send_cmd_packet(); phase = CFLIE_DATA; break; case CFLIE_SEARCH: switch (packet_ack()) { case PKT_PENDING: return PACKET_CHKTIME; // packet send not yet complete case PKT_ACKED: phase = CFLIE_DATA; PROTOCOL_SetBindState(0); MUSIC_Play(MUSIC_DONE_BINDING); break; case PKT_TIMEOUT: send_search_packet(); counter = BIND_COUNT; } break; case CFLIE_DATA: if (Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_ON_CRTPLOG) { update_telemetry_crtplog(); } else if (Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_ON_ACKPKT) { update_telemetry_ackpkt(); } if (packet_ack() == PKT_PENDING) return PACKET_CHKTIME; // packet send not yet complete send_cmd_packet(); break; } return PACKET_PERIOD; // Packet at standard protocol interval }
static void navigate_item(struct guiKeyboard *keyboard, short leftRight, short upDown) { const char * const *keys = array[keyboard->type]; MUSIC_Play(MUSIC_KEY_PRESSING); short i = keyboard->last_row; short j = 0; u8 col_len = 0; if (! (keyboard->flags & FLAG_BUTTON)) { keyboard->lastchar = array[keyboard->type][0][0]; keyboard->flags |= FLAG_BUTTON; } if (leftRight != 0) { const char *ptr = keys[i]; col_len = strlen(ptr); if (i < 3 || keyboard->type == KEYBOARD_NUM) { j = keyboard->last_col; j += leftRight; if (j < 0) j = col_len -1; if (j >= col_len) j = 0; keyboard->last_col = j; } else { // when row = 3, don't keep track of its col for (j = 0; j < col_len; j++) { if (ptr[j] == keyboard->lastchar) { break; } } j += leftRight; if (j < 0) j = col_len -1; if (j >= col_len) j = 0; } } else { i += upDown; if (i < 0) i = 3; if (i >= 4) i = 0; keyboard->last_row = i; j = keyboard->last_col; if (j >= (short)strlen(keys[i])) { j = strlen(keys[i]) - 1; } } keyboard_cmd(KB_RELEASE, keyboard, NULL); keyboard->lastchar = keys[i][j]; keyboard_cmd(KB_PRESS, keyboard, NULL); }
MODULE_CALLTYPE static u16 cflie_callback() { switch (phase) { case CFLIE_INIT_SEARCH: send_search_packet(); phase = CFLIE_SEARCH; break; case CFLIE_INIT_TELEMETRY: if (telemetry_setup_state_machine()) { phase = CFLIE_INIT_DATA; } break; case CFLIE_INIT_DATA: send_cmd_packet(); phase = CFLIE_DATA; break; case CFLIE_SEARCH: switch (packet_ack()) { case PKT_PENDING: return PACKET_CHKTIME; // packet send not yet complete case PKT_ACKED: phase = CFLIE_DATA; PROTOCOL_SetBindState(0); MUSIC_Play(MUSIC_DONE_BINDING); break; case PKT_TIMEOUT: send_search_packet(); counter = BIND_COUNT; } break; case CFLIE_DATA: update_telemetry(); if (packet_ack() == PKT_PENDING) return PACKET_CHKTIME; // packet send not yet complete send_cmd_packet(); break; } return PACKET_PERIOD; // Packet at standard protocol interval }
void PROTOCOL_CheckDialogs() { if (proto_state & PROTO_MODULEDLG) { if(! PAGE_DialogVisible()) { //Dialog was dismissed, proceed proto_state &= ~PROTO_MODULEDLG; PROTOCOL_Init(0); } return; } if (PROTOCOL_WaitingForSafe()) { PAGE_ShowSafetyDialog(); } else { if (PROTOCOL_Binding()) { PAGE_ShowBindingDialog(proto_state & PROTO_BINDDLG); proto_state |= PROTO_BINDDLG; } else if (proto_state & PROTO_BINDDLG) { PAGE_CloseBindingDialog(); MUSIC_Play(MUSIC_DONE_BINDING); proto_state &= ~PROTO_BINDDLG; } } }
static void _vibration_test_cb(guiObject_t *obj, void *data) { (void)obj; (void)data; MUSIC_Play(MUSIC_TIMER_WARNING); }
int main() { Init(); #ifndef ENABLE_MODULAR //Banner(); #endif if(PWR_CheckPowerSwitch()) PWR_Shutdown(); LCD_Clear(0x0000); #ifdef TEST_ADC ADC_ScanChannels(); while(1); #endif u32 buttons = ScanButtons(); if (CHAN_ButtonIsPressed(buttons, BUT_ENTER) || !FS_Init()) { LCD_DrawUSBLogo(LCD_WIDTH, LCD_HEIGHT); USB_Connect(); LCD_Clear(0x0000); FS_Init(); } CONFIG_LoadTx(); SPI_ProtoInit(); CONFIG_ReadDisplay(); CONFIG_ReadModel(CONFIG_GetCurrentModel()); CONFIG_ReadLang(Transmitter.language); BACKLIGHT_Brightness(Transmitter.backlight); LCD_Contrast(Transmitter.contrast); LCD_SetFont(DEFAULT_FONT.font); LCD_SetFontColor(DEFAULT_FONT.font_color); GUI_HandleButtons(1); MIXER_Init(); PAGE_Init(); CLOCK_StartWatchdog(); #if HAS_DATALOG DATALOG_Init(); #endif priority_ready = 0; CLOCK_SetMsecCallback(LOW_PRIORITY, LOW_PRIORITY_MSEC); CLOCK_SetMsecCallback(MEDIUM_PRIORITY, MEDIUM_PRIORITY_MSEC); // We need to wait until we've actually measured the ADC before proceeding while(! (priority_ready & (1 << LOW_PRIORITY))) PWR_Sleep(); //Only do this after we've initialized all channel data so the saftey works PROTOCOL_InitModules(); GUI_DrawScreen(); // Add startup delay to make sure audio player is initialized // AUDIO_Init() has already been called by CONFIG_ReadModel() #if HAS_EXTENDED_AUDIO audio_queue_time = CLOCK_getms() + 1500; num_audio=1; next_audio=1; #if (LCD_WIDTH == 480) || (LCD_WIDTH == 320) if(Display.background.drawn_background) while(CLOCK_getms() < audio_queue_time - 1200); #endif AUDIO_SetVolume(); // Initial setting of voice volume #endif MUSIC_Play(MUSIC_STARTUP); #ifdef HAS_EVENT_LOOP start_event_loop(); #else while(1) { if(priority_ready) { EventLoop(); } //This does not appear to have any impact on power //and has been disabled in common/devo/power.c //but it helps a huge amount for the emulator PWR_Sleep(); } #endif }
void EventLoop() { CLOCK_ResetWatchdog(); #ifdef HEAP_DEBUG static int heap = 0; int h = _sbrk_r(NULL, 0); if(h > heap) { printf("heap: %x\n", h); heap = h; } #endif #ifdef TIMING_DEBUG debug_timing(0, 0); #endif priority_ready &= ~(1 << MEDIUM_PRIORITY); #if !HAS_HARD_POWER_OFF if(PWR_CheckPowerSwitch()) { if(! (BATTERY_Check() & BATTERY_CRITICAL)) { PAGE_Test(); CONFIG_SaveModelIfNeeded(); CONFIG_SaveTxIfNeeded(); } if(Transmitter.music_shutdown) { #if HAS_EXTENDED_AUDIO if(AUDIO_VoiceAvailable()) { MUSIC_Play(MUSIC_SHUTDOWN); while (CLOCK_getms() < audio_queue_time) { // Wait for voice to finished CLOCK_ResetWatchdog(); } } else { #else { // We wait ~1sec for shutdown buzzer music finished unsigned int time; MUSIC_Play(MUSIC_SHUTDOWN); time = CLOCK_getms()+700; while (CLOCK_getms() < time) { CLOCK_ResetWatchdog(); } #endif } } PWR_Shutdown(); } #endif BUTTON_Handler(); TOUCH_Handler(); INPUT_CheckChanges(); if (priority_ready & (1 << LOW_PRIORITY)) { priority_ready &= ~(1 << LOW_PRIORITY); PAGE_Event(); PROTOCOL_CheckDialogs(); TIMER_Update(); TELEMETRY_Alarm(); BATTERY_Check(); AUTODIMMER_Update(); #if HAS_DATALOG DATALOG_Update(); #endif #if HAS_VIDEO VIDEO_Update(); #endif #if HAS_EXTENDED_AUDIO AUDIO_CheckQueue(); #endif GUI_RefreshScreen(); #if HAS_HARD_POWER_OFF if (PAGE_ModelDoneEditing()) CONFIG_SaveModelIfNeeded(); CONFIG_SaveTxIfNeeded(); #endif } #ifdef TIMING_DEBUG debug_timing(0, 1); #endif } void TOUCH_Handler() { if(! HAS_TOUCH) return; u32 pen_down=0; static u32 pen_down_last=0; static u32 pen_down_long_at=0; struct touch t; if(SPITouch_IRQ()) { pen_down=1; t=SPITouch_GetCoords(); if (! pen_down_last) pen_down_long_at=CLOCK_getms()+500; } else { pen_down=0; } if(pen_down && (!pen_down_last)) { AUTODIMMER_Check(); GUI_CheckTouch(&t, 0); } if(!pen_down && pen_down_last) { GUI_TouchRelease(); } if(pen_down && pen_down_last) { if(CLOCK_getms()>pen_down_long_at) { GUI_CheckTouch(&t, 1); pen_down_long_at += 100; } } pen_down_last=pen_down; } #if HAS_VIDEO void VIDEO_Update() { static u8 video_enable = 0; static u32 check_standard_ms = 0; // Check if Video is turn on int enabled = MIXER_SourceAsBoolean(Model.videosrc); if (enabled != video_enable) { VIDEO_Enable(enabled); video_enable = enabled; if (enabled) { VIDEO_SetChannel(Model.videoch); VIDEO_Contrast(Model.video_contrast); VIDEO_Brightness(Model.video_brightness); check_standard_ms = CLOCK_getms() + 3000; } else check_standard_ms = 0; } if(video_enable && check_standard_ms > 0 && check_standard_ms < CLOCK_getms()) { u8 video_standard_current = VIDEO_GetStandard(); if((video_standard_current > 0) && (video_standard_current < 8)) { VIDEO_SetStandard(video_standard_current); check_standard_ms = 0; } else { check_standard_ms = CLOCK_getms() + 3000; } } if(video_enable) AUTODIMMER_Check(); } #endif //HAS_VIDEO #ifdef TIMING_DEBUG void debug_timing(u32 type, int startend) { static u32 last_time[2][100]; static u32 loop_time[4][101]; static u32 loop_pos[4] = {-1, -1, -1, -1}; static u32 max_last[2]; static u32 max_loop[4]; static int save_priority; if (type == 0) { if (! startend) save_priority = priority_ready; if (save_priority & (1 << MEDIUM_PRIORITY)) debug_timing(2, startend); if (save_priority & (1 << LOW_PRIORITY)) debug_timing(1, startend); return; } type--; if (! startend) { u32 t = CLOCK_getms(); loop_pos[type] = (loop_pos[type] + 1) % 100; if (type < 2) { last_time[type][loop_pos[type]] = t; if (t - last_time[type][(loop_pos[type] + 99) % 100] > max_last[type]) max_last[type] = t - last_time[type][(loop_pos[type] + 99) % 100]; } loop_time[type][100] = t; } else { loop_time[type][loop_pos[type]] = CLOCK_getms() - loop_time[type][100]; if (loop_time[type][loop_pos[type]] > max_loop[type]) max_loop[type] = loop_time[type][loop_pos[type]]; if (type == 0 && loop_pos[0] == 99) { unsigned avg_loop[4] = {0, 0, 0, 0}; unsigned avg_last[2] = {0, 0}; for(int i = 0; i < 99; i++) { for(int t = 0; t < 2; t++) { u32 delay = last_time[t][(i + loop_pos[t] + 2) % 100] - last_time[t][(i + loop_pos[t] + 1) % 100]; avg_last[t] += delay; } for(int t = 0; t < 4; t++) avg_loop[t] += loop_time[t][i]; } for(int t = 0; t < 4; t++) avg_loop[t] /= 99; avg_last[0] /= 99; avg_last[1] /= 99; printf("Avg: radio: %d mix: %d med: %d/%d low: %d/%d\n", avg_loop[3], avg_loop[2], avg_loop[1], avg_last[1], avg_loop[0], avg_last[0]); printf("Max: radio: %d mix: %d med: %d/%d low: %d/%d\n", max_loop[3], max_loop[2], max_loop[1], max_last[1], max_loop[0], max_last[0]); memset(max_loop, 0, sizeof(max_loop)); max_last[0] = 0; max_last[1] = 0; } } } #endif void debug_switches() { s32 data[INP_LAST]; for(int i = INP_HAS_CALIBRATION+1; i < INP_LAST; i++) { data[i] = CHAN_ReadRawInput(i); } while(1) { u32 changed = 0; for(int i = INP_HAS_CALIBRATION+1; i < INP_LAST; i++) { s32 val = CHAN_ReadRawInput(i); if (val != data[i]) { printf("%s=%d ", INPUT_SourceName(tempstring, i), val); data[i] = val; changed = 1; } } if (changed) { printf("\n"); } if(PWR_CheckPowerSwitch()) PWR_Shutdown(); } }
void TIMER_Update() { unsigned i; unsigned chan_val = 0; u32 t = CLOCK_getms(); if (PROTOCOL_WaitingForSafe()) return; if( Transmitter.power_alarm > 0 ) TIMER_Power(); for (i = 0; i < NUM_TIMERS; i++) { if (Model.timer[i].src) { s16 val; if (MIXER_SRC(Model.timer[i].src) <= NUM_INPUTS) { volatile s16 *raw = MIXER_GetInputs(); val = raw[MIXER_SRC(Model.timer[i].src)]; } else { val = MIXER_GetChannel(Model.timer[i].src - NUM_INPUTS - 1, APPLY_SAFETY); } if (MIXER_SRC_IS_INV(Model.timer[i].src)) val = -val; if (Model.timer[i].type == TIMER_STOPWATCH_PROP || Model.timer[i].type == TIMER_COUNTDOWN_PROP) { chan_val = RANGE_TO_PCT(abs(val)); if (chan_val > 100) chan_val = 100; } else { unsigned new_state = (val - CHAN_MIN_VALUE > (CHAN_MAX_VALUE - CHAN_MIN_VALUE) / 20) ? 1 : 0; if (new_state != timer_state[i]) { if (new_state) last_time[i] = t; timer_state[i] = new_state; } } } if (timer_state[i]) { s32 delta = t - last_time[i]; if (Model.timer[i].type == TIMER_STOPWATCH_PROP || Model.timer[i].type == TIMER_COUNTDOWN_PROP) { delta = delta * chan_val / 100; } if (Model.timer[i].type == TIMER_PERMANENT) { timer_val[i] += delta; if( timer_val[i] >= 359999900) // Reset when 99h59mn59sec timer_val[i] = 0 ; Model.timer[i].val = timer_val[i]; } else if (Model.timer[i].type == TIMER_STOPWATCH || Model.timer[i].type == TIMER_STOPWATCH_PROP) { timer_val[i] += delta; } else { s32 warn_time; // start to beep for each prealert_interval at the last prealert_time(seconds) if (Transmitter.countdown_timer_settings.prealert_time != 0 && Transmitter.countdown_timer_settings.prealert_interval != 0 && timer_val[i] > Transmitter.countdown_timer_settings.prealert_interval && timer_val[i] < (s32)Transmitter.countdown_timer_settings.prealert_time + 1000) { // give extra 1seconds warn_time = ((timer_val[i] / Transmitter.countdown_timer_settings.prealert_interval) * Transmitter.countdown_timer_settings.prealert_interval); if (timer_val[i] > warn_time && (timer_val[i] - delta) <= warn_time) { MUSIC_Play(MUSIC_TIMER_WARNING); } } // Beep once for each timeup_interval past 0 if (timer_val[i] < 0 && Transmitter.countdown_timer_settings.timeup_interval != 0) { warn_time = ((timer_val[i] - Transmitter.countdown_timer_settings.timeup_interval) / Transmitter.countdown_timer_settings.timeup_interval) * Transmitter.countdown_timer_settings.timeup_interval; if (timer_val[i] > warn_time && (timer_val[i] - delta) <= warn_time) { MUSIC_Play(MUSIC_ALARM1 + i); } } if (timer_val[i] >= 0 && timer_val[i] < delta) { MUSIC_Play(MUSIC_ALARM1 + i); } timer_val[i] -= delta; } last_time[i] = t; } if (Model.timer[i].resetsrc) { s16 val; if (MIXER_SRC(Model.timer[i].resetsrc) <= NUM_INPUTS) { volatile s16 *raw = MIXER_GetInputs(); val = raw[MIXER_SRC(Model.timer[i].resetsrc)]; } else { val = MIXER_GetChannel(Model.timer[i].resetsrc - NUM_INPUTS - 1, APPLY_SAFETY); } if (MIXER_SRC_IS_INV(Model.timer[i].resetsrc)) val = -val; if (val - CHAN_MIN_VALUE > (CHAN_MAX_VALUE - CHAN_MIN_VALUE) / 20) { TIMER_Reset(i); } } } }
int main() { Init(); #ifndef MODULAR //Banner(); #endif if(PWR_CheckPowerSwitch()) PWR_Shutdown(); LCD_Clear(0x0000); #ifdef TEST_ADC ADC_ScanChannels(); while(1); #endif u32 buttons = ScanButtons(); if(CHAN_ButtonIsPressed(buttons, BUT_ENTER) || !FS_Mount(NULL, NULL)) { LCD_DrawUSBLogo(LCD_WIDTH, LCD_HEIGHT); USB_Connect(); LCD_Clear(0x0000); FS_Mount(NULL, NULL); } CONFIG_LoadTx(); SPI_ProtoInit(); CONFIG_ReadDisplay(); CONFIG_ReadModel(CONFIG_GetCurrentModel()); CONFIG_ReadLang(Transmitter.language); BACKLIGHT_Brightness(Transmitter.brightness); LCD_Contrast(Transmitter.contrast); LCD_SetFont(DEFAULT_FONT.font); LCD_SetFontColor(DEFAULT_FONT.font_color); MUSIC_Play(MUSIC_STARTUP); GUI_HandleButtons(1); MIXER_Init(); PAGE_Init(); CLOCK_StartWatchdog(); #if DATALOG_ENABLED DATALOG_Init(); #endif priority_ready = 0; CLOCK_SetMsecCallback(LOW_PRIORITY, LOW_PRIORITY_MSEC); CLOCK_SetMsecCallback(MEDIUM_PRIORITY, MEDIUM_PRIORITY_MSEC); // We need to wait until we've actually measured the ADC before proceeding while(! (priority_ready & (1 << LOW_PRIORITY))) ; //Only do this after we've initialized all channel data so the saftey works PROTOCOL_Init(0); GUI_DrawScreen(); #ifdef HAS_EVENT_LOOP start_event_loop(); #else while(1) { if(priority_ready) { EventLoop(); } //PWR_Sleep(); //This does not appear to have any impact on power } #endif }
//#define DEBUG_TELEMALARM void TELEMETRY_Alarm() { //Update 'updated' state every time we get here u32 current_time = CLOCK_getms(); if (current_time - last_time > TELEM_ERROR_TIME) { last_time = current_time; for(int i = 0; i < TELEM_UPDATE_SIZE; i++) { last_updated[i] = Telemetry.updated[i]; Telemetry.updated[i] = 0; } } // don't need to check all the 6 telem-configs at one time, this is not a critical and urgent task // instead, check 1 of them at a time telem_idx = (telem_idx + 1) % TELEM_NUM_ALARMS; if(! Model.telem_alarm[telem_idx]) { alarm &= ~(1 << telem_idx); // clear this set return; } u8 idx = Model.telem_alarm[telem_idx]; s32 value = TELEMETRY_GetValue(idx); if (value == 0) { alarm &= ~(1 << telem_idx); // clear this set return; } if (! TELEMETRY_IsUpdated(0xff)) { // bug fix: do not alarm when no telem packet is received, it might caused by RX is powered off alarm &= ~(1 << telem_idx); // clear this set return; } if (Model.telem_flags & (1 << telem_idx)) { if (! (alarm & (1 << telem_idx)) && (value <= Model.telem_alarm_val[telem_idx])) { if (alarm_duration[telem_idx] == 0) { alarm_duration[telem_idx] = current_time; } else if (current_time - alarm_duration[telem_idx] > CHECK_DURATION) { alarm_duration[telem_idx] = 0; alarm |= 1 << telem_idx; #ifdef DEBUG_TELEMALARM printf("set: 0x%x\n\n", alarm); #endif } } else if ((alarm & (1 << telem_idx)) && (value > (s32)Model.telem_alarm_val[telem_idx])) { if (alarm_duration[telem_idx] == 0) { alarm_duration[telem_idx] = current_time; } else if (current_time - alarm_duration[telem_idx] > CHECK_DURATION) { alarm_duration[telem_idx] = 0; alarm &= ~(1 << telem_idx); #ifdef DEBUG_TELEMALARM printf("clear: 0x%x\n\n", alarm); #endif } } else alarm_duration[telem_idx] = 0; } else { if (! (alarm & (1 << telem_idx)) && (value >= Model.telem_alarm_val[telem_idx])) { if (alarm_duration[telem_idx] == 0) { alarm_duration[telem_idx] = current_time; } else if (current_time - alarm_duration[telem_idx] > CHECK_DURATION) { alarm_duration[telem_idx] = 0; alarm |= 1 << telem_idx; #ifdef DEBUG_TELEMALARM printf("set: 0x%x\n\n", alarm); #endif } } else if ((alarm & (1 << telem_idx)) && (value < (s32)Model.telem_alarm_val[telem_idx])) { if (alarm_duration[telem_idx] == 0) { alarm_duration[telem_idx] = current_time; } else if (current_time - alarm_duration[telem_idx] > CHECK_DURATION) { alarm_duration[telem_idx] = 0; alarm &= ~(1 << telem_idx); #ifdef DEBUG_TELEMALARM printf("clear: 0x%x\n\n", alarm); #endif } } else alarm_duration[telem_idx] = 0; } if ((alarm & (1 << telem_idx))) { if (current_time >= alarm_time + MUSIC_INTERVAL) { alarm_time = current_time; #ifdef DEBUG_TELEMALARM printf("beep: %d\n\n", telem_idx); #endif MUSIC_Play(MUSIC_TELEMALARM1 + telem_idx); } } }
int main() { Init(); #ifndef MODULAR //Banner(); #endif if(PWR_CheckPowerSwitch()) PWR_Shutdown(); LCD_Clear(0x0000); #ifdef TEST_ADC ADC_ScanChannels(); while(1); #endif u32 buttons = ScanButtons(); if(CHAN_ButtonIsPressed(buttons, BUT_ENTER) || !FS_Mount(NULL, NULL)) { LCD_DrawUSBLogo(LCD_WIDTH, LCD_HEIGHT); USB_Connect(); LCD_Clear(0x0000); FS_Mount(NULL, NULL); } CONFIG_LoadTx(); SPI_ProtoInit(); CONFIG_ReadDisplay(); CONFIG_ReadModel(CONFIG_GetCurrentModel()); CONFIG_ReadLang(Transmitter.language); BACKLIGHT_Brightness(Transmitter.backlight); LCD_Contrast(Transmitter.contrast); LCD_SetFont(DEFAULT_FONT.font); LCD_SetFontColor(DEFAULT_FONT.font_color); #if !HAS_EXTENDED_AUDIO // If Extended Audio is present, move startup msg to Splash page to allow additional audio hardware initialization time MUSIC_Play(MUSIC_STARTUP); #else if (Transmitter.splash_delay < 5) MUSIC_Play(MUSIC_STARTUP); // if no splash page startup msg is used force playing here #endif GUI_HandleButtons(1); MIXER_Init(); PAGE_Init(); CLOCK_StartWatchdog(); #if HAS_DATALOG DATALOG_Init(); #endif priority_ready = 0; CLOCK_SetMsecCallback(LOW_PRIORITY, LOW_PRIORITY_MSEC); CLOCK_SetMsecCallback(MEDIUM_PRIORITY, MEDIUM_PRIORITY_MSEC); // We need to wait until we've actually measured the ADC before proceeding while(! (priority_ready & (1 << LOW_PRIORITY))) ; //Only do this after we've initialized all channel data so the saftey works PROTOCOL_InitModules(); GUI_DrawScreen(); #ifdef HAS_EVENT_LOOP start_event_loop(); #else while(1) { if(priority_ready) { EventLoop(); } //This does not appear to have any impact on power //and has been disabled in common/devo/power.c //but it helps a huge amount for the emulator PWR_Sleep(); } #endif }
void MUSIC_PlayValue(u16 music, s32 value, u8 unit, u8 prec) { u32 i; char digits[6]; // Do we need more? char thousands = 0; u8 digit_count = 0; if ( !AUDIO_VoiceAvailable() || !AUDIO_AddQueue(music)) { if (music < MUSIC_TOTAL) MUSIC_Play(music); return; } // Play minutes/hours/seconds for timers if (unit == VOICE_UNIT_TIME) { if (value >= 3600) { i = value / 3600; AUDIO_AddQueue(i + MUSIC_TOTAL); AUDIO_AddQueue(VOICE_UNIT_HOURS + VOICE_UNIT_OFFSET); value %= 3600; } if (value >= 60) { i = value / 60; AUDIO_AddQueue(i + MUSIC_TOTAL); AUDIO_AddQueue(VOICE_UNIT_MINUTES + VOICE_UNIT_OFFSET); value %= 60; } if (value > 0) { AUDIO_AddQueue(value + MUSIC_TOTAL); AUDIO_AddQueue(VOICE_UNIT_SECONDS + VOICE_UNIT_OFFSET); } return; } // Add minus sign for negative number if (value < 0) { AUDIO_AddQueue(VOICE_UNIT_MINUS + VOICE_UNIT_OFFSET); value *= -1; } //Add precision digits for (i=0; i < prec; i++) { digits[digit_count++] = value % 10; value /=10; } //Add decimal seperator if (prec > 0) { digits[digit_count++] = VOICE_DEC_SEP; } // Special case value == 0 and not playing TIME if (value == 0 && unit != VOICE_UNIT_TIME) digits[digit_count++] = 0; // Get single digits from remaining value while (value > 0) { if(value > 999) { thousands = value / 1000; value %= 1000; } if(value > 100) { digits[digit_count++] = value % 100; value /= 100; digits[digit_count++] = value + 99; if (thousands){ digits[digit_count++] = 109; // MP3 for "thousands" digits[digit_count++] = thousands; } break; } if(value < 101 && value > 0) { digits[digit_count++] = value; break; } else { if (thousands){ digits[digit_count++] = 109; // MP3 for "thousands" digits[digit_count++] = thousands; } } } // Fill music queue with digits for (i = digit_count; i > 0; i--) { AUDIO_AddQueue(digits[i-1] + MUSIC_TOTAL); } // Add unit for value if specified if (unit > VOICE_UNIT_NONE) AUDIO_AddQueue(unit + VOICE_UNIT_OFFSET); }