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 "Util/CRC.hpp"
26 #include "Device/Port/Port.hpp"
27 #include "Operation/Operation.hpp"
28 #include "Time/TimeoutClock.hpp"
33 Volkslogger::Reset(Port
&port
, OperationEnvironment
&env
, unsigned n
)
35 static constexpr unsigned delay
= 2;
48 Volkslogger::Handshake(Port
&port
, OperationEnvironment
&env
,
51 TimeoutClock
timeout(timeout_ms
);
53 while (true) { // Solange R's aussenden, bis ein L zurückkommt
57 int remaining
= timeout
.GetRemainingSigned();
64 Port::WaitResult result
=
65 port
.WaitForChar('L', env
, remaining
);
66 if (result
== Port::WaitResult::READY
)
69 if (result
!= Port::WaitResult::TIMEOUT
)
72 /* timeout, try again */
76 while (true) { // Auf 4 hintereinanderfolgende L's warten
77 int remaining
= timeout
.GetRemainingSigned();
81 if (port
.WaitForChar('L', env
, remaining
) != Port::WaitResult::READY
)
91 Volkslogger::Connect(Port
&port
, OperationEnvironment
&env
,
94 return Reset(port
, env
, 10) && Handshake(port
, env
, timeout_ms
);
98 Volkslogger::ConnectAndFlush(Port
&port
, OperationEnvironment
&env
,
103 return Connect(port
, env
, timeout_ms
) && port
.FullFlush(env
, 50, 300);
107 SendWithCRC(Port
&port
, const void *data
, size_t length
,
108 OperationEnvironment
&env
)
110 if (!port
.FullWrite(data
, length
, env
, 2000))
113 uint16_t crc16
= UpdateCRC16CCITT(data
, length
, 0);
114 return port
.Write(crc16
>> 8) && port
.Write(crc16
& 0xff);
118 Volkslogger::SendCommand(Port
&port
, OperationEnvironment
&env
,
119 Command cmd
, uint8_t param1
, uint8_t param2
)
121 static constexpr unsigned delay
= 2;
124 if (!port
.FullFlush(env
, 20, 100))
127 /* reset command interpreter */
128 if (!Reset(port
, env
, 6))
131 /* send command packet */
133 const uint8_t cmdarray
[8] = {
134 (uint8_t)cmd
, param1
, param2
,
138 if (!port
.Write(ENQ
))
143 if (!SendWithCRC(port
, cmdarray
, sizeof(cmdarray
), env
))
146 /* wait for confirmation */
148 return port
.WaitRead(env
, 4000) == Port::WaitResult::READY
&&
154 GetBaudRateIndex(unsigned baud_rate
)
178 Volkslogger::SendCommandSwitchBaudRate(Port
&port
, OperationEnvironment
&env
,
179 Command cmd
, uint8_t param1
,
182 int baud_rate_index
= GetBaudRateIndex(baud_rate
);
183 if (baud_rate_index
< 0)
186 if (!SendCommand(port
, env
, cmd
, param1
, baud_rate_index
))
189 return port
.SetBaudrate(baud_rate
);
193 Volkslogger::WaitForACK(Port
&port
, OperationEnvironment
&env
)
195 return port
.WaitForChar(ACK
, env
, 30000) == Port::WaitResult::READY
;
199 Volkslogger::ReadBulk(Port
&port
, OperationEnvironment
&env
,
200 void *buffer
, size_t max_length
,
201 unsigned timeout_firstchar_ms
)
206 bool start
= false, ende
= false;
208 memset(buffer
, 0xff, max_length
);
210 uint8_t *p
= (uint8_t *)buffer
;
212 constexpr unsigned TIMEOUT_NORMAL_MS
= 2000;
214 * We need to wait longer for the first char to
215 * give the logger time to calculate security
216 * when downloading a log-file.
217 * Therefore timeout_firstchar is configurable.
218 * If the timeout parameter is not specified or 0,
219 * set standard timeout
221 if (timeout_firstchar_ms
== 0)
222 timeout_firstchar_ms
= TIMEOUT_NORMAL_MS
;
225 // Zeichen anfordern und darauf warten
227 if (!port
.Write(ACK
))
230 // Set longer timeout on first char
231 unsigned timeout
= start
? TIMEOUT_NORMAL_MS
: timeout_firstchar_ms
;
232 if (port
.WaitRead(env
, timeout
) != Port::WaitResult::READY
)
235 int ch
= port
.GetChar();
239 // dabei ist Benutzerabbruch jederzeit möglich
240 if (env
.IsCancelled()) {
248 // oder aber das empfangene Zeichen wird ausgewertet
251 if (!dle_r
) { //!DLE, DLE -> Achtung!
254 else { // DLE, DLE -> DLE-Zeichen
257 if(nbytes
< max_length
)
260 crc16
= UpdateCRC16CCITT(ch
, crc16
);
265 if (!dle_r
) { //!DLE, ETX -> Zeichen
267 if(nbytes
< max_length
) {
271 crc16
= UpdateCRC16CCITT(ch
, crc16
);
276 ende
= true; // DLE, ETX -> Blockende
282 if (!dle_r
) { //!DLE, STX -> Zeichen
284 if(nbytes
< max_length
)
287 crc16
= UpdateCRC16CCITT(ch
, crc16
);
291 start
= true; // DLE, STX -> Blockstart
298 if(nbytes
< max_length
)
301 crc16
= UpdateCRC16CCITT(ch
, crc16
);
315 // CRC am Ende abschneiden
320 Volkslogger::WriteBulk(Port
&port
, OperationEnvironment
&env
,
321 const void *buffer
, unsigned length
)
323 const unsigned delay
= 1;
325 env
.SetProgressRange(length
);
328 const uint8_t *p
= (const uint8_t *)buffer
, *end
= p
+ length
;
330 unsigned n
= end
- p
;
334 n
= port
.Write(p
, n
);
338 crc16
= UpdateCRC16CCITT(p
, n
, crc16
);
341 env
.SetProgressPosition(p
- (const uint8_t *)buffer
);
343 /* throttle sending a bit, or the Volkslogger's receive buffer
345 env
.Sleep(delay
* 100);
348 return port
.Write(crc16
>> 8) && port
.Write(crc16
& 0xff);
352 Volkslogger::SendCommandReadBulk(Port
&port
, OperationEnvironment
&env
,
354 void *buffer
, size_t max_length
,
355 const unsigned timeout_firstchar_ms
)
357 return SendCommand(port
, env
, cmd
)
358 ? ReadBulk(port
, env
, buffer
, max_length
, timeout_firstchar_ms
)
363 Volkslogger::SendCommandReadBulk(Port
&port
, unsigned baud_rate
,
364 OperationEnvironment
&env
,
365 Command cmd
, uint8_t param1
,
366 void *buffer
, size_t max_length
,
367 const unsigned timeout_firstchar_ms
)
369 unsigned old_baud_rate
= port
.GetBaudrate();
371 if (old_baud_rate
!= 0) {
372 if (!SendCommandSwitchBaudRate(port
, env
, cmd
, param1
, baud_rate
))
375 /* after switching baud rates, this sleep time is necessary; it has
376 been verified experimentally */
379 /* port does not support baud rate switching, use plain
380 SendCommand() without new baud rate */
382 if (!SendCommand(port
, env
, cmd
, param1
))
386 int nbytes
= ReadBulk(port
, env
, buffer
, max_length
, timeout_firstchar_ms
);
388 if (old_baud_rate
!= 0)
389 port
.SetBaudrate(old_baud_rate
);
395 Volkslogger::SendCommandWriteBulk(Port
&port
, OperationEnvironment
&env
,
397 const void *data
, size_t size
)
399 if (!SendCommand(port
, env
, cmd
, 0, 0) || !WaitForACK(port
, env
))
404 return WriteBulk(port
, env
, data
, size
) && WaitForACK(port
, env
);
408 Volkslogger::ReadFlight(Port
&port
, unsigned databaud
,
409 OperationEnvironment
&env
,
410 unsigned flightnr
, bool secmode
,
411 void *buffer
, size_t buffersize
)
413 const Volkslogger::Command cmd
= secmode
414 ? Volkslogger::cmd_GFS
415 : Volkslogger::cmd_GFL
;
418 * It is necessary to wait long for the first reply from
419 * the Logger in ReadBulk.
420 * Since the VL needs time to calculate the Security of
421 * the log before it responds.
423 const unsigned timeout_firstchar_ms
= 300000;
425 // Download binary log data supports BulkBaudrate
426 int groesse
= SendCommandReadBulk(port
, databaud
, env
, cmd
,
427 flightnr
, buffer
, buffersize
,
428 timeout_firstchar_ms
);
436 * Testing has shown that downloading the Signature does not support
437 * BulkRate. It has to be done with standard IO Rate (9600)
439 int sgr
= SendCommandReadBulk(port
, env
, Volkslogger::cmd_SIG
,
440 (uint8_t *)buffer
+ groesse
,
441 buffersize
- groesse
);
445 return groesse
+ sgr
;