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 "Protocol.hpp"
25 #include "Device/Port/Port.hpp"
26 #include "OS/ByteOrder.hpp"
27 #include "Geo/GeoPoint.hpp"
35 CAI302::WriteString(Port
&port
, const char *p
, OperationEnvironment
&env
)
37 size_t length
= strlen(p
);
38 return port
.FullWrite(p
, length
, env
, 2000);
42 CAI302::CommandModeQuick(Port
&port
)
44 return port
.Write('\x03');
48 WaitCommandPrompt(Port
&port
, OperationEnvironment
&env
,
49 unsigned timeout_ms
=2000)
51 return port
.ExpectString("cmd>", env
, timeout_ms
);
55 CAI302::CommandMode(Port
&port
, OperationEnvironment
&env
)
58 return CommandModeQuick(port
) && WaitCommandPrompt(port
, env
);
62 CAI302::SendCommandQuick(Port
&port
, const char *cmd
,
63 OperationEnvironment
&env
)
65 if (!CommandMode(port
, env
))
69 return WriteString(port
, cmd
, env
);
73 CAI302::SendCommand(Port
&port
, const char *cmd
,
74 OperationEnvironment
&env
, unsigned timeout_ms
)
76 return SendCommandQuick(port
, cmd
, env
) &&
77 WaitCommandPrompt(port
, env
, timeout_ms
);
81 CAI302::LogModeQuick(Port
&port
, OperationEnvironment
&env
)
83 return CommandModeQuick(port
) && WriteString(port
, "LOG 0\r", env
);
87 CAI302::LogMode(Port
&port
, OperationEnvironment
&env
)
89 return SendCommandQuick(port
, "LOG 0\r", env
);
93 WaitUploadPrompt(Port
&port
, OperationEnvironment
&env
,
94 unsigned timeout_ms
=2000)
96 return port
.ExpectString("up>", env
, timeout_ms
);
100 CAI302::UploadMode(Port
&port
, OperationEnvironment
&env
)
102 return SendCommandQuick(port
, "UPLOAD 1\r", env
) &&
103 WaitUploadPrompt(port
, env
);
107 CAI302::ReadShortReply(Port
&port
, void *buffer
, unsigned max_size
,
108 OperationEnvironment
&env
, unsigned timeout_ms
)
110 unsigned char header
[3];
111 if (!port
.FullRead(header
, sizeof(header
), env
, timeout_ms
))
114 unsigned size
= header
[0];
115 if (size
< sizeof(header
))
118 size
-= sizeof(header
);
122 if (!port
.FullRead(buffer
, size
, env
, timeout_ms
))
125 // XXX verify the checksum
127 if (size
< max_size
) {
128 /* fill the rest with zeroes */
129 char *p
= (char *)buffer
;
130 std::fill(p
+ size
, p
+ max_size
, 0);
137 CAI302::ReadLargeReply(Port
&port
, void *buffer
, unsigned max_size
,
138 OperationEnvironment
&env
, unsigned timeout_ms
)
140 unsigned char header
[5];
141 if (!port
.FullRead(header
, sizeof(header
), env
, timeout_ms
))
144 unsigned size
= (header
[0] << 8) | header
[1];
145 if (size
< sizeof(header
))
148 size
-= sizeof(header
);
152 if (!port
.FullRead(buffer
, size
, env
, timeout_ms
))
155 // XXX verify the checksum
157 if (size
< max_size
) {
158 /* fill the rest with zeroes */
159 char *p
= (char *)buffer
;
160 std::fill(p
+ size
, p
+ max_size
, 0);
167 CAI302::UploadShort(Port
&port
, const char *command
,
168 void *response
, unsigned max_size
,
169 OperationEnvironment
&env
, unsigned timeout_ms
)
172 if (!WriteString(port
, command
, env
))
175 int nbytes
= ReadShortReply(port
, response
, max_size
, env
, timeout_ms
);
179 if (!WaitUploadPrompt(port
, env
))
186 CAI302::UploadLarge(Port
&port
, const char *command
,
187 void *response
, unsigned max_size
,
188 OperationEnvironment
&env
, unsigned timeout_ms
)
191 if (!WriteString(port
, command
, env
))
194 int nbytes
= ReadLargeReply(port
, response
, max_size
, env
, timeout_ms
);
198 if (!WaitUploadPrompt(port
, env
))
205 CAI302::UploadGeneralInfo(Port
&port
, GeneralInfo
&data
,
206 OperationEnvironment
&env
)
208 return UploadShort(port
, "W\r", &data
, sizeof(data
), env
) == sizeof(data
);
212 CAI302::UploadFileList(Port
&port
, unsigned i
, FileList
&data
,
213 OperationEnvironment
&env
)
218 snprintf(cmd
, sizeof(cmd
), "B %u\r", 196 + i
);
219 return UploadLarge(port
, cmd
, &data
, sizeof(data
), env
) == sizeof(data
);
223 CAI302::UploadFileASCII(Port
&port
, unsigned i
, FileASCII
&data
,
224 OperationEnvironment
&env
)
229 snprintf(cmd
, sizeof(cmd
), "B %u\r", 64 + i
);
230 return UploadLarge(port
, cmd
, &data
, sizeof(data
), env
) == sizeof(data
);
234 CAI302::UploadFileBinary(Port
&port
, unsigned i
, FileBinary
&data
,
235 OperationEnvironment
&env
)
240 snprintf(cmd
, sizeof(cmd
), "B %u\r", 256 + i
);
241 return UploadLarge(port
, cmd
, &data
, sizeof(data
), env
) == sizeof(data
);
245 CAI302::UploadFileData(Port
&port
, bool next
, void *data
, unsigned length
,
246 OperationEnvironment
&env
)
248 return UploadLarge(port
, next
? "B N\r" : "B R\r", data
, length
, env
, 15000);
252 CAI302::UploadFileSignatureASCII(Port
&port
, FileSignatureASCII
&data
,
253 OperationEnvironment
&env
)
255 return UploadLarge(port
, "B S\r", &data
, sizeof(data
), env
) == sizeof(data
);
259 CAI302::UploadPolarMeta(Port
&port
, PolarMeta
&data
, OperationEnvironment
&env
)
261 return UploadShort(port
, "G\r", &data
, sizeof(data
), env
) > 0;
265 CAI302::UploadPolar(Port
&port
, Polar
&data
, OperationEnvironment
&env
)
267 return UploadShort(port
, "G 0\r", &data
, sizeof(data
), env
) > 0;
271 CAI302::UploadPilotMeta(Port
&port
, PilotMeta
&data
, OperationEnvironment
&env
)
273 return UploadShort(port
, "O\r", &data
, sizeof(data
), env
) > 0;
277 CAI302::UploadPilotMetaActive(Port
&port
, PilotMetaActive
&data
,
278 OperationEnvironment
&env
)
280 return UploadShort(port
, "O A\r", &data
, sizeof(data
), env
) > 0;
284 CAI302::UploadPilot(Port
&port
, unsigned i
, Pilot
&data
,
285 OperationEnvironment
&env
)
288 snprintf(cmd
, sizeof(cmd
), "O %u\r", i
);
289 return UploadShort(port
, cmd
, &data
, sizeof(data
), env
) > 0;
293 CAI302::UploadPilotBlock(Port
&port
, unsigned start
, unsigned count
,
294 unsigned record_size
, void *buffer
,
295 OperationEnvironment
&env
)
298 snprintf(cmd
, sizeof(cmd
), "O B %u %u\r", start
, count
);
300 /* the CAI302 data port user's guide 2.2 says that the "O B"
301 response is "large", but this seems wrong */
302 int nbytes
= UploadShort(port
, cmd
, buffer
, count
* record_size
, env
);
303 return nbytes
>= 0 && nbytes
% record_size
== 0
304 ? nbytes
/ record_size
309 WaitDownloadPrompt(Port
&port
, OperationEnvironment
&env
,
310 unsigned timeout_ms
=2000)
312 return port
.ExpectString("dn>", env
, timeout_ms
);
316 CAI302::DownloadMode(Port
&port
, OperationEnvironment
&env
)
318 return SendCommandQuick(port
, "DOWNLOAD 1\r", env
) &&
319 WaitDownloadPrompt(port
, env
);
323 CAI302::DownloadCommand(Port
&port
, const char *command
,
324 OperationEnvironment
&env
, unsigned timeout_ms
)
326 return WriteString(port
, command
, env
) && WaitDownloadPrompt(port
, env
);
330 CAI302::DownloadPilot(Port
&port
, const Pilot
&pilot
, unsigned ordinal
,
331 OperationEnvironment
&env
)
334 snprintf(buffer
, sizeof(buffer
),
335 "O,%-24s,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\r",
337 (ordinal
<< 8) | pilot
.old_units
,
338 pilot
.old_temperatur_units
,
340 pilot
.total_energy_final_glide
,
341 pilot
.show_final_glide_altitude_difference
,
343 FromBE16(pilot
.approach_radius
),
344 FromBE16(pilot
.arrival_radius
),
345 FromBE16(pilot
.enroute_logging_interval
),
346 FromBE16(pilot
.close_logging_interval
),
347 FromBE16(pilot
.time_between_flight_logs
),
348 FromBE16(pilot
.minimum_speed_to_force_flight_logging
),
350 pilot
.reserved_vario
,
351 FromBE16(pilot
.unit_word
),
352 FromBE16(pilot
.margin_height
));
354 return DownloadCommand(port
, buffer
, env
);
358 CAI302::DownloadPolar(Port
&port
, const Polar
&polar
,
359 OperationEnvironment
&env
)
362 snprintf(buffer
, sizeof(buffer
),
363 "G,%-12s,%-12s,%d,%d,%d,%d,%d,%d,%d,%d\r",
367 polar
.best_glide_speed
,
368 polar
.two_ms_sink_at_speed
,
369 FromBE16(polar
.weight_in_litres
),
370 FromBE16(polar
.ballast_capacity
),
372 FromBE16(polar
.config_word
),
373 FromBE16(polar
.wing_area
));
375 return DownloadCommand(port
, buffer
, env
);
379 CAI302::UploadNavpointMeta(Port
&port
, NavpointMeta
&data
,
380 OperationEnvironment
&env
)
382 return UploadShort(port
, "C\r", &data
, sizeof(data
), env
) > 0;
386 CAI302::UploadNavpoint(Port
&port
, unsigned i
, Navpoint
&data
,
387 OperationEnvironment
&env
)
390 snprintf(cmd
, sizeof(cmd
), "C %u\r", i
);
391 return UploadShort(port
, cmd
, &data
, sizeof(data
), env
) > 0;
395 FormatGeoPoint(char *buffer
, const GeoPoint
&location
)
398 double tmp
, MinLat
, MinLon
;
401 tmp
= (double)location
.latitude
.Degrees();
408 MinLat
= (tmp
- DegLat
) * 60;
410 tmp
= (double)location
.longitude
.Degrees();
417 MinLon
= (tmp
- DegLon
) * 60;
419 sprintf(buffer
, "%02d%07.4f%c,%03d%07.4f%c",
421 DegLon
, MinLon
, EoW
);
425 CAI302::DownloadNavpoint(Port
&port
, const GeoPoint
&location
,
426 int altitude
, unsigned id
,
427 bool turnpoint
, bool airfield
, bool markpoint
,
428 bool landing_point
, bool start_point
,
429 bool finish_point
, bool home_point
,
430 bool thermal_point
, bool waypoint
, bool airspace
,
431 const char *name
, const char *remark
,
432 OperationEnvironment
&env
)
434 assert(name
!= NULL
);
436 char location_string
[32];
437 FormatGeoPoint(location_string
, location
);
439 unsigned attr
= turnpoint
| (airfield
<< 1) | (markpoint
<< 2) |
440 (landing_point
<< 3) | (start_point
<< 4) | (finish_point
<< 5) |
441 (home_point
<< 6) | (thermal_point
<< 7) | (waypoint
<< 8) |
448 snprintf(buffer
, sizeof(buffer
), "C,0,%s,%d,%u,%u,%-12s,%-12s\r",
449 location_string
, altitude
, id
, attr
, name
, remark
);
450 return DownloadCommand(port
, buffer
, env
);
454 CAI302::DeclareTP(Port
&port
, unsigned i
, const GeoPoint
&location
,
455 int altitude
, const char *name
, OperationEnvironment
&env
)
457 char location_string
[32];
458 FormatGeoPoint(location_string
, location
);
461 snprintf(buffer
, sizeof(buffer
),
463 128 + i
, location_string
,
467 return DownloadCommand(port
, buffer
, env
);
471 CAI302::DeclareSave(Port
&port
, OperationEnvironment
&env
)
473 return DownloadCommand(port
, "D,255\r", env
, 5000);
477 CAI302::Reboot(Port
&port
, OperationEnvironment
&env
)
479 return SendCommandQuick(port
, "SIF 0 0\r", env
);
483 CAI302::PowerOff(Port
&port
, OperationEnvironment
&env
)
485 return SendCommandQuick(port
, "DIE\r", env
);
489 CAI302::StartLogging(Port
&port
, OperationEnvironment
&env
)
491 return SendCommand(port
, "START\r", env
);
495 CAI302::StopLogging(Port
&port
, OperationEnvironment
&env
)
497 return SendCommand(port
, "STOP\r", env
);
501 CAI302::SetVolume(Port
&port
, unsigned volume
, OperationEnvironment
&env
)
504 sprintf(cmd
, "VOL %u\r", volume
);
505 return SendCommand(port
, cmd
, env
);
509 CAI302::ClearPoints(Port
&port
, OperationEnvironment
&env
)
511 return SendCommand(port
, "CLEAR POINTS\r", env
, 5000);
515 CAI302::ClearPilot(Port
&port
, OperationEnvironment
&env
)
517 return SendCommand(port
, "CLEAR PILOT\r", env
, 5000);
521 CAI302::ClearLog(Port
&port
, OperationEnvironment
&env
)
523 return SendCommand(port
, "CLEAR LOG\r", env
, 60000);
527 ConvertBaudRate(unsigned baud_rate
)
534 case 19200: return 8;
535 case 38400: return 9;
536 case 57600: return 10;
537 case 115200: return 11;
543 CAI302::SetBaudRate(Port
&port
, unsigned baud_rate
, OperationEnvironment
&env
)
545 unsigned n
= ConvertBaudRate(baud_rate
);
550 sprintf(cmd
, "BAUD %u\r", n
);
551 return SendCommandQuick(port
, cmd
, env
);