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.
27 // adding baro alt sentance parser to support baro source priority if (d == pDevPrimaryBaroSource){...}
29 #include "Device/Driver/EWMicroRecorder.hpp"
30 #include "Device/Driver.hpp"
31 #include "Device/Port/Port.hpp"
32 #include "Device/Declaration.hpp"
33 #include "NMEA/Info.hpp"
34 #include "NMEA/InputLine.hpp"
35 #include "NMEA/Checksum.hpp"
36 #include "Waypoint/Waypoint.hpp"
37 #include "Units/System.hpp"
38 #include "Time/TimeoutClock.hpp"
39 #include "Operation/Operation.hpp"
40 #include "Util/StaticString.hpp"
45 // Additional sentance for EW support
47 class EWMicroRecorderDevice
: public AbstractDevice
{
52 EWMicroRecorderDevice(Port
&_port
)
56 virtual bool ParseNMEA(const char *line
, struct NMEAInfo
&info
) override
;
57 virtual bool Declare(const Declaration
&declaration
, const Waypoint
*home
,
58 OperationEnvironment
&env
) override
;
62 ReadAltitude(NMEAInputLine
&line
, fixed
&value_r
)
65 bool available
= line
.ReadChecked(value
);
66 char unit
= line
.ReadFirstChar();
70 if (unit
== _T('f') || unit
== _T('F'))
71 value
= Units::ToSysUnit(value
, Unit::FEET
);
78 EWMicroRecorderDevice::ParseNMEA(const char *String
, NMEAInfo
&info
)
80 if (!VerifyNMEAChecksum(String
))
83 NMEAInputLine
line(String
);
87 if (StringIsEqual(type
, "$PGRMZ")) {
90 /* The normal Garmin $PGRMZ line contains the "true" barometric
91 altitude above MSL (corrected with QNH), but EWMicroRecorder
92 differs here slightly: it emits the uncorrected barometric
93 altitude. That is the only reason why we catch this sentence
94 in the driver instead of letting the generic class NMEAParser
96 if (ReadAltitude(line
, value
))
97 info
.ProvidePressureAltitude(value
);
105 TryConnect(Port
&port
, char *user_data
, size_t max_user_data
,
106 OperationEnvironment
&env
)
109 port
.Write('\x02'); // send IO Mode command
111 unsigned user_size
= 0;
113 TimeoutClock
timeout(8000);
116 int remaining
= timeout
.GetRemainingSigned();
120 if (port
.WaitRead(env
, remaining
) != Port::WaitResult::READY
)
123 int nbytes
= port
.Read(user_data
+ user_size
, max_user_data
- user_size
);
127 if (user_size
== 0) {
128 const char *minus
= (const char *)memchr(user_data
, '-', nbytes
);
132 user_size
= user_data
+ nbytes
- minus
;
133 memmove(user_data
, minus
, user_size
);
137 char *end
= (char *)memchr(user_data
, '\x13', user_size
);
144 if (user_size
>= max_user_data
)
145 /* response too large */
153 TryConnectRetry(Port
&port
, char *user_data
, size_t max_user_data
,
154 OperationEnvironment
&env
)
159 if (TryConnect(port
, user_data
, max_user_data
, env
))
166 * "It is important that only alpha numeric characters are included in
167 * the declaration, as other characters such as a comma will prevent
168 * the resultant .IGC file from being validated."
170 * @see http://www.ewavionics.com/products/microRecorder/microRecorder-instructionsfull.pdf
173 IsValidEWChar(char ch
)
175 return ch
== '\r' || ch
== '\n' ||
176 ch
== ' ' || ch
== '-' ||
177 (ch
>= 'a' && ch
<= 'z') ||
178 (ch
>= 'A' && ch
<= 'Z') ||
179 (ch
>= '0' && ch
<= '9');
183 * Replace all invalid characters according to IsValidEWChar() with a
190 if (!IsValidEWChar(*p
))
195 * Clean a string and write it to the Port.
198 WriteCleanString(Port
&port
, const TCHAR
*p
,
199 OperationEnvironment
&env
, unsigned timeout_ms
)
201 NarrowString
<256> buffer
;
204 CleanString(buffer
.buffer());
206 return port
.FullWriteString(buffer
, env
, timeout_ms
);
210 WriteLabel(Port
&port
, const char *name
, OperationEnvironment
&env
)
212 return port
.FullWriteString(name
, env
, 1000) &&
213 port
.FullWrite(": ", 2, env
, 500);
217 * Write a name/value pair to the EW microRecorder.
220 WritePair(Port
&port
, const char *name
, const TCHAR
*value
,
221 OperationEnvironment
&env
)
223 return WriteLabel(port
, name
, env
) &&
224 WriteCleanString(port
, value
, env
, 1000) &&
225 port
.FullWrite("\r\n", 2, env
, 500);
229 WriteGeoPoint(Port
&port
, const GeoPoint
&value
, OperationEnvironment
&env
)
232 double tmp
, MinLat
, MinLon
;
236 tmp
= (double)value
.latitude
.Degrees();
245 MinLat
= (tmp
- DegLat
) * 60 * 1000;
248 tmp
= (double)value
.longitude
.Degrees();
257 MinLon
= (tmp
- DegLon
) * 60 * 1000;
260 sprintf(buffer
, "%02d%05d%c%03d%05d%c",
261 DegLat
, (int)MinLat
, NoS
,
262 DegLon
, (int)MinLon
, EoW
);
264 return port
.FullWriteString(buffer
, env
, 1000);
268 EWMicroRecorderWriteWaypoint(Port
&port
, const char *type
,
269 const Waypoint
&way_point
,
270 OperationEnvironment
&env
)
272 return WriteLabel(port
, type
, env
) &&
273 WriteGeoPoint(port
, way_point
.location
, env
) &&
275 WriteCleanString(port
, way_point
.name
.c_str(), env
, 1000) &&
276 port
.FullWrite("\r\n", 2, env
, 500);
280 DeclareInner(Port
&port
, const Declaration
&declaration
,
281 OperationEnvironment
&env
)
283 assert(declaration
.Size() >= 2);
284 assert(declaration
.Size() <= 12);
286 char user_data
[2500];
288 if (!TryConnectRetry(port
, user_data
, sizeof(user_data
), env
))
291 char *p
= strstr(user_data
, "USER DETAILS");
295 port
.Write('\x18'); // start to upload file
297 if (!port
.FullWriteString(user_data
, env
, 5000) ||
298 !port
.FullWriteString("USER DETAILS\r\n--------------\r\n\r\n",
302 WritePair(port
, "Pilot Name", declaration
.pilot_name
.c_str(), env
);
303 WritePair(port
, "Competition ID", declaration
.competition_id
.c_str(), env
);
304 WritePair(port
, "Aircraft Type", declaration
.aircraft_type
.c_str(), env
);
305 WritePair(port
, "Aircraft ID",
306 declaration
.aircraft_registration
.c_str(), env
);
308 if (!port
.FullWriteString("\r\nFLIGHT DECLARATION\r\n-------------------\r\n\r\n",
312 WritePair(port
, "Description", _T("XCSoar task declaration"), env
);
314 for (unsigned i
= 0; i
< 11; i
++) {
315 if (env
.IsCancelled())
318 if (i
+1>= declaration
.Size()) {
319 port
.FullWriteString("TP LatLon: 0000000N00000000E TURN POINT\r\n",
322 const Waypoint
&wp
= declaration
.GetWaypoint(i
);
324 if (!EWMicroRecorderWriteWaypoint(port
, "Take Off LatLong", wp
, env
) ||
325 !EWMicroRecorderWriteWaypoint(port
, "Start LatLon", wp
, env
))
327 } else if (i
+ 1 < declaration
.Size()) {
328 if (!EWMicroRecorderWriteWaypoint(port
, "TP LatLon", wp
, env
))
334 const Waypoint
&wp
= declaration
.GetLastWaypoint();
335 if (!EWMicroRecorderWriteWaypoint(port
, "Finish LatLon", wp
, env
) ||
336 !EWMicroRecorderWriteWaypoint(port
, "Land LatLon", wp
, env
) ||
340 port
.Write('\x03'); // finish sending user file
342 return port
.ExpectString("uploaded successfully", env
, 5000);
346 EWMicroRecorderDevice::Declare(const Declaration
&declaration
,
347 const Waypoint
*home
,
348 OperationEnvironment
&env
)
350 // Must have at least two, max 12 waypoints
351 if (declaration
.Size() < 2 || declaration
.Size() > 12)
356 bool success
= DeclareInner(port
, declaration
, env
);
358 // go back to NMEA mode
359 port
.FullWrite("!!\r\n", 4, env
, 500);
366 EWMicroRecorderCreateOnPort(const DeviceConfig
&config
, Port
&com_port
)
368 return new EWMicroRecorderDevice(com_port
);
371 const struct DeviceRegister ew_microrecorder_driver
= {
372 _T("EW MicroRecorder"),
373 _T("EW microRecorder"),
374 DeviceRegister::DECLARE
,
375 EWMicroRecorderCreateOnPort
,