bool FlarmDevice::ReadFlightInfo(RecordedFlightInfo &flight, OperationEnvironment &env) { // Create header for getting record information FLARM::FrameHeader header = PrepareFrameHeader(FLARM::MT_GETRECORDINFO); // Send request if (!SendStartByte() || !SendFrameHeader(header, env, 1000)) return false; // Wait for an answer and save the payload for further processing AllocatedArray<uint8_t> data; uint16_t length; uint8_t ack_result = WaitForACKOrNACK(header.GetSequenceNumber(), data, length, env, 1000); // If neither ACK nor NACK was received if (ack_result != FLARM::MT_ACK || length <= 2) return false; char *record_info = (char *)data.begin() + 2; return ParseRecordInfo(record_info, flight); }
size_t HandleBinary(const void *_data, size_t length) { const uint8_t *const data = (const uint8_t *)_data, *end = data + length; const uint8_t *p = data; p = std::find(p, end, FLARM::START_FRAME); if (p == NULL) return length; ++p; FLARM::FrameHeader header; size_t nbytes = Unescape(p, end, &header, sizeof(header)); p += nbytes; if (nbytes < sizeof(header)) return p - data; //XXX size_t payload_length = header.GetLength(); switch (header.type) { case FLARM::MT_PING: case FLARM::MT_SELECTRECORD: SendACK(header.GetSequenceNumber()); break; case FLARM::MT_EXIT: SendACK(header.GetSequenceNumber()); binary = false; break; } return p - data; }
bool FlarmDevice::DownloadFlight(Path path, OperationEnvironment &env) { FileOutputStream fos(path); BufferedOutputStream os(fos); if (env.IsCancelled()) return false; env.SetProgressRange(100); while (true) { // Create header for getting IGC file data FLARM::FrameHeader header = PrepareFrameHeader(FLARM::MT_GETIGCDATA); // Send request if (!SendStartByte() || !SendFrameHeader(header, env, 1000) || env.IsCancelled()) return false; // Wait for an answer and save the payload for further processing AllocatedArray<uint8_t> data; uint16_t length; bool ack = WaitForACKOrNACK(header.GetSequenceNumber(), data, length, env, 10000) == FLARM::MT_ACK; // If no ACK was received if (!ack || length <= 3 || env.IsCancelled()) return false; length -= 3; // Read progress (in percent) uint8_t progress = *(data.begin() + 2); env.SetProgressPosition(std::min((unsigned)progress, 100u)); const char *last_char = (const char *)data.end() - 1; bool is_last_packet = (*last_char == 0x1A); if (is_last_packet) length--; // Read IGC data const char *igc_data = (const char *)data.begin() + 3; os.Write(igc_data, length); if (is_last_packet) break; } os.Flush(); fos.Commit(); return true; }
FLARM::MessageType FlarmDevice::WaitForACKOrNACK(uint16_t sequence_number, AllocatedArray<uint8_t> &data, uint16_t &length, OperationEnvironment &env, unsigned timeout_ms) { const TimeoutClock timeout(timeout_ms); // Receive frames until timeout or expected frame found while (!timeout.HasExpired()) { // Wait until the next start byte comes around if (!WaitForStartByte(env, timeout.GetRemainingOrZero())) continue; // Read the following FrameHeader FLARM::FrameHeader header; if (!ReceiveFrameHeader(header, env, timeout.GetRemainingOrZero())) continue; // Read and check length of the FrameHeader length = header.GetLength(); if (length <= sizeof(header)) continue; // Calculate payload length length -= sizeof(header); // Read payload and check length data.GrowDiscard(length); if (!ReceiveEscaped(data.begin(), length, env, timeout.GetRemainingOrZero())) continue; // Verify CRC if (header.GetCRC() != FLARM::CalculateCRC(header, data.begin(), length)) continue; // Check message type if (header.type != FLARM::MT_ACK && header.type != FLARM::MT_NACK) continue; // Check payload length if (length < 2) continue; // Check whether the received ACK is for the right sequence number if (FromLE16(*((const uint16_t *)(const void *)data.begin())) == sequence_number) return (FLARM::MessageType)header.type; } return FLARM::MT_ERROR; }
bool FlarmDevice::BinaryPing(OperationEnvironment &env, unsigned timeout_ms) { const TimeoutClock timeout(timeout_ms); // Create header for sending a binary ping request FLARM::FrameHeader header = PrepareFrameHeader(FLARM::MT_PING); // Send request and wait for positive answer return SendStartByte() && SendFrameHeader(header, env, timeout.GetRemainingOrZero()) && WaitForACK(header.GetSequenceNumber(), env, timeout.GetRemainingOrZero()); }
FLARM::MessageType FlarmDevice::SelectFlight(uint8_t record_number, OperationEnvironment &env) { // Create header for selecting a log record uint8_t data[1] = { record_number }; FLARM::FrameHeader header = PrepareFrameHeader(FLARM::MT_SELECTRECORD, data, sizeof(data)); // Send request if (!SendStartByte() || !SendFrameHeader(header, env, 1000) || !SendEscaped(data, sizeof(data), env, 1000)) return FLARM::MT_ERROR; // Wait for an answer return WaitForACKOrNACK(header.GetSequenceNumber(), env, 1000); }