4 XCSoar Glide Computer - http://www.xcsoar.org/
5 Copyright (C) 2000-2013 The XCSoar Project
6 A detailed list of copyright holders can be found in the file "AUTHORS".
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "ActionInterface.hpp"
25 #include "Interface.hpp"
26 #include "Thread/Mutex.hpp"
27 #include "MainWindow.hpp"
28 #include "MapWindow/GlueMapWindow.hpp"
29 #include "Language/Language.hpp"
30 #include "StatusMessage.hpp"
31 #include "InfoBoxes/InfoBoxManager.hpp"
32 #include "InfoBoxes/InfoBoxLayout.hpp"
33 #include "Screen/Layout.hpp"
35 #include "Components.hpp"
36 #include "DrawThread.hpp"
37 #include "FLARM/Glue.hpp"
38 #include "Gauge/GlueGaugeVario.hpp"
39 #include "Gauge/GaugeFLARM.hpp"
40 #include "Time/PeriodClock.hpp"
41 #include "LogFile.hpp"
42 #include "Blackboard/DeviceBlackboard.hpp"
43 #include "CalculationThread.hpp"
44 #include "Task/ProtectedTaskManager.hpp"
45 #include "Profile/Profile.hpp"
46 #include "UIState.hpp"
47 #include "Operation/MessageOperationEnvironment.hpp"
49 using namespace CommonInterface
;
51 namespace ActionInterface
{
52 static void SendGetComputerSettings();
56 XCSoarInterface::ReceiveGPS()
59 ScopeLock
protect(device_blackboard
->mutex
);
61 ReadBlackboardBasic(device_blackboard
->Basic());
63 const NMEAInfo
&real
= device_blackboard
->RealState();
64 Private::movement_detected
= real
.alive
&& real
.gps
.real
&&
65 real
.MovementDetected();
70 if (!Basic().flarm
.traffic
.IsEmpty())
71 /* auto-load FlarmNet when traffic is seen */
76 XCSoarInterface::ReceiveCalculated()
79 ScopeLock
protect(device_blackboard
->mutex
);
81 ReadBlackboardCalculated(device_blackboard
->Calculated());
82 device_blackboard
->ReadComputerSettings(GetComputerSettings());
85 BroadcastCalculatedUpdate();
89 XCSoarInterface::ExchangeBlackboard()
91 ExchangeDeviceBlackboard();
92 ActionInterface::SendGetComputerSettings();
93 ActionInterface::SendMapSettings();
97 XCSoarInterface::ExchangeDeviceBlackboard()
99 ScopeLock
protect(device_blackboard
->mutex
);
101 device_blackboard
->ReadComputerSettings(GetComputerSettings());
105 ActionInterface::SendGetComputerSettings()
107 assert(calculation_thread
!= NULL
);
109 main_window
->SetComputerSettings(GetComputerSettings());
111 calculation_thread
->SetComputerSettings(GetComputerSettings());
112 calculation_thread
->SetScreenDistanceMeters(main_window
->GetProjection().GetScreenDistanceMeters());
116 ActionInterface::SetBallast(fixed ballast
, bool to_devices
)
118 // write ballast into settings
119 GlidePolar
&polar
= SetComputerSettings().polar
.glide_polar_task
;
120 polar
.SetBallast(ballast
);
122 // send to calculation thread and trigger recalculation
123 if (protected_task_manager
!= NULL
)
124 protected_task_manager
->SetGlidePolar(polar
);
126 if (calculation_thread
!= NULL
) {
127 calculation_thread
->SetComputerSettings(GetComputerSettings());
128 calculation_thread
->Trigger();
131 // send to external devices
133 const Plane
&plane
= GetComputerSettings().plane
;
134 if (positive(plane
.dry_mass
)) {
135 fixed overload
= (plane
.dry_mass
+ ballast
* plane
.max_ballast
) /
138 MessageOperationEnvironment env
;
139 device_blackboard
->SetBallast(ballast
, overload
, env
);
145 ActionInterface::SetBugs(fixed bugs
, bool to_devices
)
147 // Write Bugs into settings
148 CommonInterface::SetComputerSettings().polar
.SetBugs(bugs
);
149 GlidePolar
&polar
= SetComputerSettings().polar
.glide_polar_task
;
151 // send to calculation thread and trigger recalculation
152 if (protected_task_manager
!= NULL
)
153 protected_task_manager
->SetGlidePolar(polar
);
155 if (calculation_thread
!= NULL
) {
156 calculation_thread
->SetComputerSettings(GetComputerSettings());
157 calculation_thread
->Trigger();
160 // send to external devices
162 MessageOperationEnvironment env
;
163 device_blackboard
->SetBugs(bugs
, env
);
168 ActionInterface::SetMacCready(fixed mc
, bool to_devices
)
170 // Repeated adjustment of MC with the +/- UI elements could result in
171 // an MC which is slightly larger than 0. Since the calculations
172 // fundamentally change depending on "MC == 0" or "MC <> 0" force
173 // a fixed(0) for small MC values.
174 if (mc
< fixed(0.01))
177 /* update interface settings */
179 GlidePolar
&polar
= SetComputerSettings().polar
.glide_polar_task
;
182 /* update InfoBoxes (that might show the MacCready setting) */
184 InfoBoxManager::SetDirty();
186 /* send to calculation thread and trigger recalculation */
188 if (protected_task_manager
!= NULL
)
189 protected_task_manager
->SetGlidePolar(polar
);
191 if (calculation_thread
!= NULL
) {
192 calculation_thread
->SetComputerSettings(GetComputerSettings());
193 calculation_thread
->Trigger();
196 /* send to external devices */
199 MessageOperationEnvironment env
;
200 device_blackboard
->SetMC(mc
, env
);
204 void ActionInterface::SetManualMacCready(fixed mc
, bool to_devices
)
206 TaskBehaviour
&task_behaviour
= CommonInterface::SetComputerSettings().task
;
207 if (task_behaviour
.auto_mc
) {
208 task_behaviour
.auto_mc
= false;
209 Profile::Set(ProfileKeys::AutoMc
, false);
212 SetMacCready(mc
, to_devices
);
216 ActionInterface::OffsetManualMacCready(fixed offset
, bool to_devices
)
218 const GlidePolar
&polar
= GetComputerSettings().polar
.glide_polar_task
;
219 const fixed old_mc
= polar
.GetMC();
220 fixed mc
= old_mc
+ offset
;
223 else if (mc
> fixed(5))
227 SetManualMacCready(mc
, to_devices
);
231 ActionInterface::SendMapSettings(const bool trigger_draw
)
233 // trigger_draw: asks for an immediate exchange of blackboard data
234 // (via ProcessTimer()) rather than waiting for the idle timer every 500ms
237 main_window
->UpdateGaugeVisibility();
238 InfoBoxManager::ProcessTimer();
241 /* Don't show indicator when the gauge is indicating the traffic anyway */
242 SetMapSettings().show_flarm_alarm_level
=
243 !GetUISettings().traffic
.enable_gauge
;
245 main_window
->SetMapSettings(GetMapSettings());
248 main_window
->FullRedraw();
249 BroadcastUISettingsUpdate();
252 // TODO: trigger refresh if the settings are changed
257 GetPanelIndex(const UIState
&ui_state
)
259 if (ui_state
.auxiliary_enabled
) {
260 unsigned panel
= ui_state
.auxiliary_index
;
261 if (panel
>= InfoBoxSettings::MAX_PANELS
)
262 panel
= InfoBoxSettings::PANEL_AUXILIARY
;
265 else if (ui_state
.display_mode
== DisplayMode::CIRCLING
)
266 return InfoBoxSettings::PANEL_CIRCLING
;
267 else if (ui_state
.display_mode
== DisplayMode::FINAL_GLIDE
)
268 return InfoBoxSettings::PANEL_FINAL_GLIDE
;
270 return InfoBoxSettings::PANEL_CRUISE
;
274 ActionInterface::UpdateDisplayMode()
276 UIState
&state
= SetUIState();
277 const UISettings
&settings
= GetUISettings();
279 state
.display_mode
= GetNewDisplayMode(settings
.info_boxes
, state
,
281 state
.panel_index
= GetPanelIndex(state
);
283 const auto &panel
= settings
.info_boxes
.panels
[state
.panel_index
];
284 state
.panel_name
= gettext(panel
.name
);
288 ActionInterface::SendUIState()
290 /* force-update all InfoBoxes just in case the display mode has
292 InfoBoxManager::SetDirty();
293 InfoBoxManager::ProcessTimer();
295 main_window
->SetUIState(GetUIState());