Пример #1
0
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;
}
Пример #2
0
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);
}
Пример #3
0
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;
}
Пример #4
0
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;
    }
  }
}
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #7
0
 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);
   }
 }
Пример #8
0
bool
Port::WaitConnected(OperationEnvironment &env)
{
    while (GetState() == PortState::LIMBO && !env.IsCancelled())
        env.Sleep(200);

    return GetState() == PortState::READY;
}
Пример #9
0
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;
}
Пример #10
0
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;
}
Пример #11
0
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;
}
Пример #12
0
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;
}
Пример #13
0
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;
}
Пример #14
0
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;
}
Пример #15
0
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;
}
Пример #16
0
  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);
    }
  }
Пример #17
0
  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);
    }
  }
Пример #18
0
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;
}
Пример #19
0
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;
}
Пример #20
0
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;
}
Пример #21
0
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();
}
Пример #22
0
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;
}
Пример #23
0
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;
}
Пример #24
0
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;
}
Пример #25
0
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;
}
Пример #26
0
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);
}
Пример #27
0
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;
}
Пример #28
0
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;
}
Пример #29
0
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;
}
Пример #30
0
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;
}