Renderer, ...: use PixelRect::GetCenter()
[xcsoar.git] / src / Device / Driver / CAI302 / Protocol.cpp
blob13aa244677f72a5a813cbd19269a7c309b0832af
1 /*
2 Copyright_License {
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"
29 #include <algorithm>
30 #include <assert.h>
31 #include <string.h>
32 #include <stdio.h>
34 bool
35 CAI302::WriteString(Port &port, const char *p, OperationEnvironment &env)
37 size_t length = strlen(p);
38 return port.FullWrite(p, length, env, 2000);
41 bool
42 CAI302::CommandModeQuick(Port &port)
44 return port.Write('\x03');
47 static bool
48 WaitCommandPrompt(Port &port, OperationEnvironment &env,
49 unsigned timeout_ms=2000)
51 return port.ExpectString("cmd>", env, timeout_ms);
54 bool
55 CAI302::CommandMode(Port &port, OperationEnvironment &env)
57 port.Flush();
58 return CommandModeQuick(port) && WaitCommandPrompt(port, env);
61 bool
62 CAI302::SendCommandQuick(Port &port, const char *cmd,
63 OperationEnvironment &env)
65 if (!CommandMode(port, env))
66 return false;
68 port.Flush();
69 return WriteString(port, cmd, env);
72 bool
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);
80 bool
81 CAI302::LogModeQuick(Port &port, OperationEnvironment &env)
83 return CommandModeQuick(port) && WriteString(port, "LOG 0\r", env);
86 bool
87 CAI302::LogMode(Port &port, OperationEnvironment &env)
89 return SendCommandQuick(port, "LOG 0\r", env);
92 static bool
93 WaitUploadPrompt(Port &port, OperationEnvironment &env,
94 unsigned timeout_ms=2000)
96 return port.ExpectString("up>", env, timeout_ms);
99 bool
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))
112 return -1;
114 unsigned size = header[0];
115 if (size < sizeof(header))
116 return -1;
118 size -= sizeof(header);
119 if (size > max_size)
120 size = max_size;
122 if (!port.FullRead(buffer, size, env, timeout_ms))
123 return -1;
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);
133 return size;
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))
142 return -1;
144 unsigned size = (header[0] << 8) | header[1];
145 if (size < sizeof(header))
146 return -1;
148 size -= sizeof(header);
149 if (size > max_size)
150 size = max_size;
152 if (!port.FullRead(buffer, size, env, timeout_ms))
153 return -1;
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);
163 return size;
167 CAI302::UploadShort(Port &port, const char *command,
168 void *response, unsigned max_size,
169 OperationEnvironment &env, unsigned timeout_ms)
171 port.Flush();
172 if (!WriteString(port, command, env))
173 return -1;
175 int nbytes = ReadShortReply(port, response, max_size, env, timeout_ms);
176 if (nbytes < 0)
177 return nbytes;
179 if (!WaitUploadPrompt(port, env))
180 return -1;
182 return nbytes;
186 CAI302::UploadLarge(Port &port, const char *command,
187 void *response, unsigned max_size,
188 OperationEnvironment &env, unsigned timeout_ms)
190 port.Flush();
191 if (!WriteString(port, command, env))
192 return -1;
194 int nbytes = ReadLargeReply(port, response, max_size, env, timeout_ms);
195 if (nbytes < 0)
196 return nbytes;
198 if (!WaitUploadPrompt(port, env))
199 return -1;
201 return nbytes;
204 bool
205 CAI302::UploadGeneralInfo(Port &port, GeneralInfo &data,
206 OperationEnvironment &env)
208 return UploadShort(port, "W\r", &data, sizeof(data), env) == sizeof(data);
211 bool
212 CAI302::UploadFileList(Port &port, unsigned i, FileList &data,
213 OperationEnvironment &env)
215 assert(i < 8);
217 char cmd[16];
218 snprintf(cmd, sizeof(cmd), "B %u\r", 196 + i);
219 return UploadLarge(port, cmd, &data, sizeof(data), env) == sizeof(data);
222 bool
223 CAI302::UploadFileASCII(Port &port, unsigned i, FileASCII &data,
224 OperationEnvironment &env)
226 assert(i < 64);
228 char cmd[16];
229 snprintf(cmd, sizeof(cmd), "B %u\r", 64 + i);
230 return UploadLarge(port, cmd, &data, sizeof(data), env) == sizeof(data);
233 bool
234 CAI302::UploadFileBinary(Port &port, unsigned i, FileBinary &data,
235 OperationEnvironment &env)
237 assert(i < 64);
239 char cmd[16];
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);
251 bool
252 CAI302::UploadFileSignatureASCII(Port &port, FileSignatureASCII &data,
253 OperationEnvironment &env)
255 return UploadLarge(port, "B S\r", &data, sizeof(data), env) == sizeof(data);
258 bool
259 CAI302::UploadPolarMeta(Port &port, PolarMeta &data, OperationEnvironment &env)
261 return UploadShort(port, "G\r", &data, sizeof(data), env) > 0;
264 bool
265 CAI302::UploadPolar(Port &port, Polar &data, OperationEnvironment &env)
267 return UploadShort(port, "G 0\r", &data, sizeof(data), env) > 0;
270 bool
271 CAI302::UploadPilotMeta(Port &port, PilotMeta &data, OperationEnvironment &env)
273 return UploadShort(port, "O\r", &data, sizeof(data), env) > 0;
276 bool
277 CAI302::UploadPilotMetaActive(Port &port, PilotMetaActive &data,
278 OperationEnvironment &env)
280 return UploadShort(port, "O A\r", &data, sizeof(data), env) > 0;
283 bool
284 CAI302::UploadPilot(Port &port, unsigned i, Pilot &data,
285 OperationEnvironment &env)
287 char cmd[16];
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)
297 char cmd[16];
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
305 : -1;
308 static bool
309 WaitDownloadPrompt(Port &port, OperationEnvironment &env,
310 unsigned timeout_ms=2000)
312 return port.ExpectString("dn>", env, timeout_ms);
315 bool
316 CAI302::DownloadMode(Port &port, OperationEnvironment &env)
318 return SendCommandQuick(port, "DOWNLOAD 1\r", env) &&
319 WaitDownloadPrompt(port, env);
322 bool
323 CAI302::DownloadCommand(Port &port, const char *command,
324 OperationEnvironment &env, unsigned timeout_ms)
326 return WriteString(port, command, env) && WaitDownloadPrompt(port, env);
329 bool
330 CAI302::DownloadPilot(Port &port, const Pilot &pilot, unsigned ordinal,
331 OperationEnvironment &env)
333 char buffer[256];
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",
336 pilot.name,
337 (ordinal << 8) | pilot.old_units,
338 pilot.old_temperatur_units,
339 pilot.sink_tone,
340 pilot.total_energy_final_glide,
341 pilot.show_final_glide_altitude_difference,
342 pilot.map_datum,
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),
349 pilot.stf_dead_band,
350 pilot.reserved_vario,
351 FromBE16(pilot.unit_word),
352 FromBE16(pilot.margin_height));
354 return DownloadCommand(port, buffer, env);
357 bool
358 CAI302::DownloadPolar(Port &port, const Polar &polar,
359 OperationEnvironment &env)
361 char buffer[256];
362 snprintf(buffer, sizeof(buffer),
363 "G,%-12s,%-12s,%d,%d,%d,%d,%d,%d,%d,%d\r",
364 polar.glider_type,
365 polar.glider_id,
366 polar.best_ld,
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);
378 bool
379 CAI302::UploadNavpointMeta(Port &port, NavpointMeta &data,
380 OperationEnvironment &env)
382 return UploadShort(port, "C\r", &data, sizeof(data), env) > 0;
385 bool
386 CAI302::UploadNavpoint(Port &port, unsigned i, Navpoint &data,
387 OperationEnvironment &env)
389 char cmd[16];
390 snprintf(cmd, sizeof(cmd), "C %u\r", i);
391 return UploadShort(port, cmd, &data, sizeof(data), env) > 0;
394 static void
395 FormatGeoPoint(char *buffer, const GeoPoint &location)
397 int DegLat, DegLon;
398 double tmp, MinLat, MinLon;
399 char NoS, EoW;
401 tmp = (double)location.latitude.Degrees();
402 NoS = 'N';
403 if (tmp < 0) {
404 NoS = 'S';
405 tmp = -tmp;
407 DegLat = (int)tmp;
408 MinLat = (tmp - DegLat) * 60;
410 tmp = (double)location.longitude.Degrees();
411 EoW = 'E';
412 if (tmp < 0) {
413 EoW = 'W';
414 tmp = -tmp;
416 DegLon = (int)tmp;
417 MinLon = (tmp - DegLon) * 60;
419 sprintf(buffer, "%02d%07.4f%c,%03d%07.4f%c",
420 DegLat, MinLat, NoS,
421 DegLon, MinLon, EoW);
424 bool
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) |
442 (airfield << 9);
444 if (remark == NULL)
445 remark = "";
447 char buffer[256];
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);
453 bool
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);
460 char buffer[256];
461 snprintf(buffer, sizeof(buffer),
462 "D,%d,%s,%s,%d\r",
463 128 + i, location_string,
464 name,
465 altitude);
467 return DownloadCommand(port, buffer, env);
470 bool
471 CAI302::DeclareSave(Port &port, OperationEnvironment &env)
473 return DownloadCommand(port, "D,255\r", env, 5000);
476 bool
477 CAI302::Reboot(Port &port, OperationEnvironment &env)
479 return SendCommandQuick(port, "SIF 0 0\r", env);
482 bool
483 CAI302::PowerOff(Port &port, OperationEnvironment &env)
485 return SendCommandQuick(port, "DIE\r", env);
488 bool
489 CAI302::StartLogging(Port &port, OperationEnvironment &env)
491 return SendCommand(port, "START\r", env);
494 bool
495 CAI302::StopLogging(Port &port, OperationEnvironment &env)
497 return SendCommand(port, "STOP\r", env);
500 bool
501 CAI302::SetVolume(Port &port, unsigned volume, OperationEnvironment &env)
503 char cmd[16];
504 sprintf(cmd, "VOL %u\r", volume);
505 return SendCommand(port, cmd, env);
508 bool
509 CAI302::ClearPoints(Port &port, OperationEnvironment &env)
511 return SendCommand(port, "CLEAR POINTS\r", env, 5000);
514 bool
515 CAI302::ClearPilot(Port &port, OperationEnvironment &env)
517 return SendCommand(port, "CLEAR PILOT\r", env, 5000);
520 bool
521 CAI302::ClearLog(Port &port, OperationEnvironment &env)
523 return SendCommand(port, "CLEAR LOG\r", env, 60000);
526 static unsigned
527 ConvertBaudRate(unsigned baud_rate)
529 switch (baud_rate) {
530 case 1200: return 4;
531 case 2400: return 5;
532 case 4800: return 6;
533 case 9600: return 7;
534 case 19200: return 8;
535 case 38400: return 9;
536 case 57600: return 10;
537 case 115200: return 11;
538 default: return 0;
542 bool
543 CAI302::SetBaudRate(Port &port, unsigned baud_rate, OperationEnvironment &env)
545 unsigned n = ConvertBaudRate(baud_rate);
546 if (n == 0)
547 return false;
549 char cmd[16];
550 sprintf(cmd, "BAUD %u\r", n);
551 return SendCommandQuick(port, cmd, env);