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; }
void CAI302WaypointUploader::Run(OperationEnvironment &env) { Waypoints waypoints; env.SetText(_("Loading Waypoints...")); if (!reader.Parse(waypoints, env)) { env.SetErrorMessage(_("Failed to load file.")); return; } if (waypoints.size() > 9999) { env.SetErrorMessage(_("Too many waypoints.")); return; } env.SetText(_("Uploading Waypoints")); env.SetProgressRange(waypoints.size() + 1); env.SetProgressPosition(0); if (!device.ClearPoints(env)) { if (!env.IsCancelled()) env.SetErrorMessage(_("Failed to erase waypoints.")); return; } if (!device.EnableBulkMode(env)) { if (!env.IsCancelled()) env.SetErrorMessage(_("Failed to switch baud rate.")); return; } unsigned id = 1; for (auto i = waypoints.begin(), end = waypoints.end(); i != end; ++i, ++id) { if (env.IsCancelled()) break; env.SetProgressPosition(id); if (!device.WriteNavpoint(id, *i, env)) { if (!env.IsCancelled()) env.SetErrorMessage(_("Failed to write waypoint.")); break; } } device.DisableBulkMode(env); }
bool FlarmDevice::DownloadFlight(const RecordedFlightInfo &flight, Path path, OperationEnvironment &env) { if (!BinaryMode(env)) return false; FLARM::MessageType ack_result = SelectFlight(flight.internal.flarm, env); // If no ACK was received -> cancel if (ack_result != FLARM::MT_ACK || env.IsCancelled()) return false; try { if (DownloadFlight(path, env)) return true; } catch (...) { mode = Mode::UNKNOWN; throw; } mode = Mode::UNKNOWN; return false; }
bool Port::ExpectString(const char *token, OperationEnvironment &env, unsigned timeout_ms) { assert(token != NULL); const char *const token_end = token + strlen(token); const TimeoutClock timeout(timeout_ms); char buffer[256]; const char *p = token; while (true) { WaitResult wait_result = WaitRead(env, timeout.GetRemainingOrZero()); if (wait_result != WaitResult::READY) // Operation canceled, Timeout expired or I/O error occurred return false; int nbytes = Read(buffer, std::min(sizeof(buffer), size_t(token_end - p))); if (nbytes < 0 || env.IsCancelled()) return false; for (const char *q = buffer, *end = buffer + nbytes; q != end; ++q) { const char ch = *q; if (ch != *p) /* retry */ p = token; else if (++p == token_end) return true; } } }
int Net::DownloadToBuffer(Session &session, const char *url, void *_buffer, size_t max_length, OperationEnvironment &env) { Request request(session, url, 10000); if (!request.Send(10000)) return -1; int64_t total = request.GetLength(); if (total >= 0) env.SetProgressRange(total); total = 0; uint8_t *buffer = (uint8_t *)_buffer, *p = buffer, *end = buffer + max_length; while (p != end) { if (env.IsCancelled()) return -1; ssize_t nbytes = request.Read(p, end - p, 5000); if (nbytes < 0) return -1; if (nbytes == 0) break; p += nbytes; total += nbytes; env.SetProgressPosition(total); } return p - buffer; }
bool FlarmDevice::ReadFlightList(RecordedFlightList &flight_list, OperationEnvironment &env) { if (!BinaryMode(env)) return false; // Try to receive flight information until the list is full for (uint8_t i = 0; !flight_list.full(); ++i) { FLARM::MessageType ack_result = SelectFlight(i, env); // Last record reached -> bail out and return list if (ack_result == FLARM::MT_NACK) break; // If neither ACK nor NACK was received if (ack_result != FLARM::MT_ACK || env.IsCancelled()) { mode = Mode::UNKNOWN; return false; } RecordedFlightInfo flight_info; flight_info.internal.flarm = i; if (ReadFlightInfo(flight_info, env)) flight_list.append(flight_info); } return true; }
virtual void Run(OperationEnvironment &env) { env.SetText(_T("Working...")); env.SetProgressRange(30); for (unsigned i = 0; i < 30 && !env.IsCancelled(); ++i) { env.SetProgressPosition(i); env.Sleep(500); } }
bool Port::WaitConnected(OperationEnvironment &env) { while (GetState() == PortState::LIMBO && !env.IsCancelled()) env.Sleep(200); return GetState() == PortState::READY; }
bool DeviceDescriptor::OpenOnPort(DumpPort *_port, OperationEnvironment &env) { #if !CLANG_CHECK_VERSION(3,6) /* disabled on clang due to -Wtautological-pointer-compare */ assert(_port != nullptr); #endif assert(port == nullptr); assert(device == nullptr); assert(second_device == nullptr); assert(driver != nullptr); assert(!ticker); assert(!IsBorrowed()); reopen_clock.Update(); device_blackboard->mutex.Lock(); device_blackboard->SetRealState(index).Reset(); device_blackboard->ScheduleMerge(); device_blackboard->mutex.Unlock(); settings_sent.Clear(); settings_received.Clear(); was_alive = false; port = _port; parser.Reset(); parser.SetReal(!StringIsEqual(driver->name, _T("Condor"))); if (config.IsDriver(_T("Condor"))) parser.DisableGeoid(); if (driver->CreateOnPort != nullptr) { Device *new_device = driver->CreateOnPort(config, *port); const ScopeLock protect(mutex); device = new_device; if (driver->HasPassThrough() && config.use_second_device) second_device = second_driver->CreateOnPort(config, *port); } else port->StartRxThread(); EnableNMEA(env); if (env.IsCancelled()) { /* the caller is responsible for freeing the port on error */ port = nullptr; delete device; device = nullptr; delete second_device; second_device = nullptr; return false; } return true; }
bool IMIDevice::DownloadFlight(const RecordedFlightInfo &flight, const TCHAR *path, OperationEnvironment &env) { bool success = Connect(env) && !env.IsCancelled(); success = success && IMI::FlightDownload(port, flight, path, env); // disconnect Disconnect(); return success; }
bool IMIDevice::ReadFlightList(RecordedFlightList &flight_list, OperationEnvironment &env) { bool success = Connect(env) && !env.IsCancelled(); success = success && IMI::ReadFlightList(port, flight_list); // disconnect Disconnect(); return success; }
bool DeviceDescriptor::DoOpen(OperationEnvironment &env) { assert(config.IsAvailable()); if (config.port_type == DeviceConfig::PortType::INTERNAL) return OpenInternalSensors(); if (config.port_type == DeviceConfig::PortType::DROIDSOAR_V2) return OpenDroidSoarV2(); if (config.port_type == DeviceConfig::PortType::I2CPRESSURESENSOR) return OpenI2Cbaro(); if (config.port_type == DeviceConfig::PortType::NUNCHUCK) return OpenNunchuck(); if (config.port_type == DeviceConfig::PortType::IOIOVOLTAGE) return OpenVoltage(); if (config.port_type == DeviceConfig::PortType::ADCAIRSPEED) return OpenAdcAirspeed(); reopen_clock.Update(); Port *port = OpenPort(config, *this); if (port == NULL) { TCHAR name_buffer[64]; const TCHAR *name = config.GetPortName(name_buffer, 64); StaticString<256> msg; msg.Format(_T("%s: %s."), _("Unable to open port"), name); env.SetErrorMessage(msg); return false; } while (port->GetState() == PortState::LIMBO) { env.Sleep(200); if (env.IsCancelled() || port->GetState() == PortState::FAILED) { delete port; return false; } } if (!Open(*port, env)) { delete port; return false; } return true; }
static bool DownloadToFile(Net::Session &session, const char *url, FILE *file, char *md5_digest, OperationEnvironment &env) { assert(url != NULL); assert(file != NULL); Net::Request request(session, url, 10000); if (!request.Send(10000)) return false; int64_t total = request.GetLength(); if (total >= 0) env.SetProgressRange(total); total = 0; MD5 md5; md5.InitKey(); uint8_t buffer[4096]; while (true) { if (env.IsCancelled()) return false; ssize_t nbytes = request.Read(buffer, sizeof(buffer), 5000); if (nbytes < 0) return false; if (nbytes == 0) break; if (md5_digest != NULL) md5.Append(buffer, nbytes); size_t written = fwrite(buffer, 1, nbytes, file); if (written != (size_t)nbytes) return false; total += nbytes; env.SetProgressPosition(total); } if (md5_digest != NULL) { md5.Finalize(); md5.GetDigest(md5_digest); } return true; }
bool DeviceDescriptor::DoOpen(OperationEnvironment &env) { assert(config.IsAvailable()); if (config.port_type == DeviceConfig::PortType::INTERNAL) return OpenInternalSensors(); if (config.port_type == DeviceConfig::PortType::DROIDSOAR_V2) return OpenDroidSoarV2(); if (config.port_type == DeviceConfig::PortType::I2CPRESSURESENSOR) return OpenI2Cbaro(); if (config.port_type == DeviceConfig::PortType::NUNCHUCK) return OpenNunchuck(); if (config.port_type == DeviceConfig::PortType::IOIOVOLTAGE) return OpenVoltage(); reopen_clock.Update(); Port *port = OpenPort(config, port_listener, *this); if (port == nullptr) { TCHAR name_buffer[64]; const TCHAR *name = config.GetPortName(name_buffer, 64); StaticString<256> msg; msg.Format(_T("%s: %s."), _("Unable to open port"), name); env.SetErrorMessage(msg); return false; } DumpPort *dump_port = new DumpPort(port); dump_port->Disable(); if (!port->WaitConnected(env) || !OpenOnPort(dump_port, env)) { if (!env.IsCancelled()) ++n_failures; delete dump_port; return false; } ResetFailureCounter(); return true; }
bool LX::CommandMode(Port &port, OperationEnvironment &env) { /* switch to command mode, first attempt */ if (!SendSYN(port) || !port.FullFlush(env, 50, 200)) return false; /* the port is clean now; try the SYN/ACK procedure up to three times */ for (unsigned i = 0; i < 100 && !env.IsCancelled(); ++i) if (Connect(port, env)) /* make sure all remaining ACKs are flushed */ return port.FullFlush(env, 200, 500); return false; }
const_iterator Wait(const K &key, OperationEnvironment &env, TimeoutClock timeout) { while (true) { auto i = map.find(key); if (i != map.end() && !i->second.old) return const_iterator(i); if (env.IsCancelled()) return end(); int remaining = timeout.GetRemainingSigned(); if (remaining <= 0) return end(); cond.timed_wait(*this, remaining); } }
const_iterator Wait(std::unique_lock<Mutex> &lock, const K &key, OperationEnvironment &env, TimeoutClock timeout) { while (true) { auto i = map.find(key); if (i != map.end() && !i->second.old) return const_iterator(i); if (env.IsCancelled()) return end(); const auto remaining = timeout.GetRemainingSigned(); if (remaining.count() <= 0) return end(); cond.wait_for(lock, remaining); } }
bool IMIDevice::Declare(const Declaration &declaration, gcc_unused const Waypoint *home, OperationEnvironment &env) { // verify WP number unsigned size = declaration.Size(); if (size < 2 || size > 13) return false; bool success = Connect(env) && !env.IsCancelled(); success = success && IMI::DeclarationWrite(port, declaration); // disconnect Disconnect(); return success; }
bool Port::FullWrite(const void *buffer, size_t length, OperationEnvironment &env, unsigned timeout_ms) { const TimeoutClock timeout(timeout_ms); const char *p = (const char *)buffer, *end = p + length; while (p < end) { if (timeout.HasExpired()) return false; size_t nbytes = Write(p, end - p); if (nbytes == 0 || env.IsCancelled()) return false; p += nbytes; } return true; }
Port::WaitResult Port::WaitRead(OperationEnvironment &env, unsigned timeout_ms) { unsigned remaining = timeout_ms; do { /* this loop is ugly, and should be redesigned when we have non-blocking I/O in all Port implementations */ const unsigned t = std::min(remaining, 500u); WaitResult result = WaitRead(t); if (result != WaitResult::TIMEOUT) return result; if (env.IsCancelled()) return WaitResult::CANCELLED; remaining -= t; } while (remaining > 0); return WaitResult::TIMEOUT; }
static bool ReadFlightListInner(Port &port, RecordedFlightList &flight_list, OperationEnvironment &env) { env.SetProgressRange(8); for (unsigned i = 0; i < 8 && !flight_list.full(); ++i) { CAI302::FileList file_list; if (!CAI302::UploadFileList(port, i, file_list, env)) break; for (unsigned j = 0; j < 8 && !flight_list.full(); ++j) { const CAI302::FileList::FileInfo &file = file_list.files[j]; if (file.start_utc.month > 0) Copy(flight_list.append(), i * 8 + j, file); } env.SetProgressPosition(i); } return !flight_list.empty() && !env.IsCancelled(); }
static bool TryConnect(Port &port, char *user_data, size_t max_user_data, OperationEnvironment &env) { port.Write('\x02'); // send IO Mode command unsigned user_size = 0; bool started = false; PeriodClock clock; clock.Update(); int i; while ((i = port.GetChar()) != EOF && !clock.Check(8000) && !env.IsCancelled()) { char ch = (char)i; if (!started && ch == '-') started = true; if (started) { if (ch == 0x13) { port.Write('\x16'); user_data[user_size] = 0; // found end of file return true; } else { if (user_size < max_user_data - 1) { user_data[user_size] = ch; user_size++; } } } } return false; }
bool FlarmDevice::BinaryMode(OperationEnvironment &env) { if (mode == Mode::BINARY) return true; port.StopRxThread(); // "Binary mode is engaged by sending the text command "$PFLAX" // (including a newline character) to Flarm." if (!Send("PFLAX", env)) return false; // Remember that we should now be in binary mode (for further assert() calls) mode = Mode::BINARY; // "After switching, connection should again be checked by issuing a ping." // Testing has revealed that switching the protocol takes a certain amount // of time (around 1.5 sec). Due to that it is recommended to issue new pings // for a certain time until the ping is ACKed properly or a timeout occurs. for (unsigned i = 0; i < 10; ++i) { if (env.IsCancelled()) { BinaryReset(env, 200); mode = Mode::UNKNOWN; return false; } if (BinaryPing(env, 500)) // We are now in binary mode and have verified that with a binary ping return true; } // Apparently the switch to binary mode didn't work mode = Mode::UNKNOWN; return false; }
static bool DownloadFlightInner(Port &port, const RecordedFlightInfo &flight, const TCHAR *path, OperationEnvironment &env) { assert(flight.internal.cai302 < 64); BinaryWriter writer(path); if (writer.HasError()) return false; CAI302::FileASCII file_ascii; if (!UploadFileASCII(port, flight.internal.cai302, file_ascii, env) || env.IsCancelled()) return false; unsigned bytes_per_block = ReadUnalignedBE16(&file_ascii.bytes_per_block); unsigned num_blocks = ReadUnalignedBE16(&file_ascii.num_blocks); env.SetProgressRange(num_blocks); unsigned allocated_size = sizeof(CAI302::FileData) + bytes_per_block; void *allocated = malloc(allocated_size); CAI302::FileData *header = (CAI302::FileData *)allocated; void *data = header + 1; unsigned current_block = 0; unsigned valid_bytes; do { int i = UploadFileData(port, true, header, allocated_size, env); if (i < (int)sizeof(*header)) { free(allocated); return false; } i -= sizeof(*header); valid_bytes = FromBE16(header->valid_bytes); if ((unsigned)i < valid_bytes) { free(allocated); return false; } if (!writer.Write(data, 1, valid_bytes)) { free(allocated); return false; } env.SetProgressPosition(current_block++); } while (valid_bytes == bytes_per_block); free(allocated); CAI302::FileSignatureASCII signature; if (!CAI302::UploadFileSignatureASCII(port, signature, env)) return false; valid_bytes = FromBE16(signature.size); if (valid_bytes > sizeof(signature.signature)) return false; if (!writer.Write(signature.signature, 1, valid_bytes)) return false; return true; }
int Volkslogger::ReadBulk(Port &port, OperationEnvironment &env, void *buffer, size_t max_length, unsigned timeout_firstchar_ms) { unsigned nbytes = 0; bool dle_r = false; uint16_t crc16 = 0; bool start = false, ende = false; memset(buffer, 0xff, max_length); uint8_t *p = (uint8_t *)buffer; constexpr unsigned TIMEOUT_NORMAL_MS = 2000; /** * We need to wait longer for the first char to * give the logger time to calculate security * when downloading a log-file. * Therefore timeout_firstchar is configurable. * If the timeout parameter is not specified or 0, * set standard timeout */ if (timeout_firstchar_ms == 0) timeout_firstchar_ms = TIMEOUT_NORMAL_MS; while (!ende) { // Zeichen anfordern und darauf warten if (!port.Write(ACK)) return -1; // Set longer timeout on first char unsigned timeout = start ? TIMEOUT_NORMAL_MS : timeout_firstchar_ms; if (port.WaitRead(env, timeout) != Port::WaitResult::READY) return -1; int ch = port.GetChar(); if (ch < 0) return -1; // dabei ist Benutzerabbruch jederzeit möglich if (env.IsCancelled()) { env.Sleep(10); port.Write(CAN); port.Write(CAN); port.Write(CAN); return -1; } // oder aber das empfangene Zeichen wird ausgewertet switch (ch) { case DLE: if (!dle_r) { //!DLE, DLE -> Achtung! dle_r = true; } else { // DLE, DLE -> DLE-Zeichen dle_r = false; if (start) { if(nbytes < max_length) *p++ = ch; nbytes++; crc16 = UpdateCRC16CCITT(ch, crc16); } } break; case ETX: if (!dle_r) { //!DLE, ETX -> Zeichen if (start) { if(nbytes < max_length) { *p++ = ch; } nbytes++; crc16 = UpdateCRC16CCITT(ch, crc16); }; } else { if (start) { ende = true; // DLE, ETX -> Blockende dle_r = false; } } break; case STX: if (!dle_r) { //!DLE, STX -> Zeichen if (start) { if(nbytes < max_length) *p++ = ch; nbytes++; crc16 = UpdateCRC16CCITT(ch, crc16); } } else { start = true; // DLE, STX -> Blockstart dle_r = false; crc16 = 0; } break; default: if (start) { if(nbytes < max_length) *p++ = ch; nbytes++; crc16 = UpdateCRC16CCITT(ch, crc16); } break; } } env.Sleep(100); if (crc16 != 0) return -1; if (nbytes < 2) return 0; // CRC am Ende abschneiden return nbytes - 2; }
static bool DeclareInner(Port &port, const Declaration &declaration, OperationEnvironment &env) { assert(declaration.Size() >= 2); assert(declaration.Size() <= 12); char user_data[2500]; if (!TryConnectRetry(port, user_data, sizeof(user_data), env)) return false; char *p = strstr(user_data, "USER DETAILS"); if (p != NULL) *p = 0; port.Write('\x18'); // start to upload file if (!port.FullWriteString(user_data, env, 5000) || !port.FullWriteString("USER DETAILS\r\n--------------\r\n\r\n", env, 1000)) return false; WritePair(port, "Pilot Name", declaration.pilot_name.c_str(), env); WritePair(port, "Competition ID", declaration.competition_id.c_str(), env); WritePair(port, "Aircraft Type", declaration.aircraft_type.c_str(), env); WritePair(port, "Aircraft ID", declaration.aircraft_registration.c_str(), env); if (!port.FullWriteString("\r\nFLIGHT DECLARATION\r\n-------------------\r\n\r\n", env, 1000)) return false; WritePair(port, "Description", _T("XCSoar task declaration"), env); for (unsigned i = 0; i < 11; i++) { if (env.IsCancelled()) return false; if (i+1>= declaration.Size()) { port.FullWriteString("TP LatLon: 0000000N00000000E TURN POINT\r\n", env, 1000); } else { const Waypoint &wp = declaration.GetWaypoint(i); if (i == 0) { if (!EWMicroRecorderWriteWaypoint(port, "Take Off LatLong", wp, env) || !EWMicroRecorderWriteWaypoint(port, "Start LatLon", wp, env)) return false; } else if (i + 1 < declaration.Size()) { if (!EWMicroRecorderWriteWaypoint(port, "TP LatLon", wp, env)) return false; } } } const Waypoint &wp = declaration.GetLastWaypoint(); if (!EWMicroRecorderWriteWaypoint(port, "Finish LatLon", wp, env) || !EWMicroRecorderWriteWaypoint(port, "Land LatLon", wp, env) || env.IsCancelled()) return false; port.Write('\x03'); // finish sending user file return port.ExpectString("uploaded successfully", env, 5000); }
bool FlytecDevice::DownloadFlight(const RecordedFlightInfo &flight, Path path, OperationEnvironment &env) { port.StopRxThread(); PeriodClock status_clock; status_clock.Update(); // Request flight record char buffer[256]; sprintf(buffer, "$PBRTR,%02d", flight.internal.flytec); AppendNMEAChecksum(buffer); strcat(buffer, "\r\n"); port.Write(buffer); if (!ExpectXOff(port, env, 1000)) return false; // Open file writer FileHandle writer(path, _T("wb")); if (!writer.IsOpen()) return false; unsigned start_sec = flight.start_time.GetSecondOfDay(); unsigned end_sec = flight.end_time.GetSecondOfDay(); if (end_sec < start_sec) end_sec += 24 * 60 * 60; unsigned range = end_sec - start_sec; env.SetProgressRange(range); while (true) { // Check if the user cancelled the operation if (env.IsCancelled()) return false; // Receive the next line if (!ReceiveLine(port, buffer, ARRAY_SIZE(buffer), 1000)) return false; // XON was received if (StringIsEmpty(buffer)) break; if (status_clock.CheckUpdate(250) && *buffer == 'B') { // Parse the fix time BrokenTime time; if (IGCParseTime(buffer + 1, time)) { unsigned time_sec = time.GetSecondOfDay(); if (time_sec < start_sec) time_sec += 24 * 60 * 60; if (time_sec > end_sec + 5 * 60) time_sec = start_sec; unsigned position = time_sec - start_sec; if (position > range) position = range; env.SetProgressPosition(position); } } // Write line to the file writer.Write(buffer); } return true; }
bool FlytecDevice::ReadFlightList(RecordedFlightList &flight_list, OperationEnvironment &env) { port.StopRxThread(); char buffer[256]; strcpy(buffer, "$PBRTL,"); AppendNMEAChecksum(buffer); strcat(buffer, "\r\n"); port.Write(buffer); if (!ExpectXOff(port, env, 1000)) return false; unsigned tracks = 0; while (true) { // Check if the user cancelled the operation if (env.IsCancelled()) return false; // Receive the next line if (!ReceiveLine(port, buffer, ARRAY_SIZE(buffer), 1000)) return false; // XON was received, last record was read already if (StringIsEmpty(buffer)) break; // $PBRTL Identifier // AA total number of stored tracks // BB actual number of track (0 indicates the most actual track) // DD.MM.YY date of recorded track (UTC)(e.g. 24.03.04) // hh:mm:ss starttime (UTC)(e.g. 08:23:15) // HH:MM:SS duration (e.g. 03:23:15) // *ZZ Checksum as defined by NMEA RecordedFlightInfo flight; NMEAInputLine line(buffer); // Skip $PBRTL line.Skip(); if (tracks == 0) { // If number of tracks not read yet // .. read and save it if (!line.ReadChecked(tracks)) continue; env.SetProgressRange(tracks); } else line.Skip(); if (!line.ReadChecked(flight.internal.flytec)) continue; if (tracks != 0 && flight.internal.flytec < tracks) env.SetProgressPosition(flight.internal.flytec); char field_buffer[16]; line.Read(field_buffer, ARRAY_SIZE(field_buffer)); if (!ParseDate(field_buffer, flight.date)) continue; line.Read(field_buffer, ARRAY_SIZE(field_buffer)); if (!ParseTime(field_buffer, flight.start_time)) continue; BrokenTime duration; line.Read(field_buffer, ARRAY_SIZE(field_buffer)); if (!ParseTime(field_buffer, duration)) continue; flight.end_time = flight.start_time + duration; flight_list.append(flight); } return true; }
bool IMI::Connect(Port &port, OperationEnvironment &env) { if (_connected) return true; memset(&_info, 0, sizeof(_info)); _serialNumber = 0; MessageParser::Reset(); // check connectivity if (!Send(port, env, MSG_CFG_HELLO) || env.IsCancelled()) return false; const TMsg *msg = Receive(port, env, 100, 0); if (!msg || msg->msgID != MSG_CFG_HELLO || env.IsCancelled()) return false; _serialNumber = msg->sn; // configure baudrate unsigned baudRate = port.GetBaudrate(); if (baudRate == 0) return false; if (!Send(port, env, MSG_CFG_STARTCONFIG, 0, 0, IMICOMM_BIGPARAM1(baudRate), IMICOMM_BIGPARAM2(baudRate)) || env.IsCancelled()) return false; // get device info for (unsigned i = 0; i < 4; i++) { if (!Send(port, env, MSG_CFG_DEVICEINFO)) continue; if (env.IsCancelled()) return false; const TMsg *msg = Receive(port, env, 300, sizeof(TDeviceInfo)); if (!msg || env.IsCancelled()) return false; if (msg->msgID != MSG_CFG_DEVICEINFO) continue; if (msg->payloadSize == sizeof(TDeviceInfo)) { memcpy(&_info, msg->payload, sizeof(TDeviceInfo)); } else if (msg->payloadSize == 16) { // old version of the structure memset(&_info, 0, sizeof(TDeviceInfo)); memcpy(&_info, msg->payload, 16); } else { return false; } _connected = true; return true; } return false; }
bool IMI::FlightDownload(Port &port, const RecordedFlightInfo &flight_info, Path path, OperationEnvironment &env) { if (!_connected) return false; MessageParser::Reset(); Flight flight; if (!FlashRead(port, &flight, flight_info.internal.imi, sizeof(flight), env)) return false; FILE *fileIGC = _tfopen(path.c_str(), _T("w+b")); if (fileIGC == nullptr) return false; unsigned fixesCount = COMM_MAX_PAYLOAD_SIZE / sizeof(Fix); Fix *fixBuffer = (Fix*)malloc(sizeof(Fix) * fixesCount); if (fixBuffer == nullptr) return false; bool ok = true; WriteHeader(flight.decl, flight.signature.tampered, fileIGC); int noenl = 0; if ((flight.decl.header.sensor & IMINO_ENL_MASK) != 0) noenl = 1; unsigned address = flight_info.internal.imi + sizeof(flight); unsigned fixesRemains = flight.finish.fixes; while (ok && fixesRemains) { unsigned fixesToRead = fixesRemains; if (fixesToRead > fixesCount) fixesToRead = fixesCount; if (!FlashRead(port, fixBuffer, address, fixesToRead * sizeof(Fix), env)) ok = false; for (unsigned i = 0; ok && i < fixesToRead; i++) { const Fix *pFix = fixBuffer + i; if (IMIIS_FIX(pFix->id)) WriteFix(*pFix, false, noenl, fileIGC); } address = address + fixesToRead * sizeof(Fix); fixesRemains -= fixesToRead; if (env.IsCancelled()) // canceled by user ok = false; } free(fixBuffer); if (ok) WriteSignature(flight.signature, flight.decl.header.sn, fileIGC); fclose(fileIGC); if (!ok) File::Delete(Path(path)); return ok; }