コード例 #1
0
bool
LX16xxConfigWidget::SaveFixedEnumSetting(LX1600::Setting key, unsigned idx,
                                         LX1600::SettingsMap &settings,
                                         unsigned factor)
{
  const std::string old_value = device.GetLX16xxSetting(key);
  unsigned value = unsigned(ParseDouble(old_value.c_str()) * factor);
  if (!SaveValue(idx, value))
    return false;

  NarrowString<32> buffer;
  buffer.UnsafeFormat("%.2f", (double)value / factor);
  settings[key] = std::string(buffer.c_str(), buffer.end());
  return true;
}
コード例 #2
0
ファイル: Device.cpp プロジェクト: pascaltempez/xcsoar
bool
FlarmDevice::SetConfig(const char *setting, const TCHAR *value)
{
  NarrowPathName narrow_value(value);

  NarrowString<256> buffer;
  buffer.Format("PFLAC,S,%s,", setting);
  buffer.append(narrow_value);

  NarrowString<256> expected_answer(buffer);
  expected_answer[6u] = 'A';

  Send(buffer);
  return port.ExpectString(expected_answer);
}
コード例 #3
0
ファイル: Device.cpp プロジェクト: XCSoar/XCSoar
bool
FlarmDevice::GetConfig(const char *setting, char *buffer, size_t length,
                       OperationEnvironment &env)
{
  NarrowString<90> request;
  request.Format("PFLAC,R,%s", setting);

  NarrowString<90> expected_answer(request);
  expected_answer[6u] = 'A';
  expected_answer.push_back(',');

  Send(request, env);
  return Receive(expected_answer, buffer, length,
                 env, std::chrono::seconds(2));
}
コード例 #4
0
ファイル: AnalyseFlight.cpp プロジェクト: MindMil/XCSoar
static void
WriteEventAttributes(TextWriter &writer,
                     const BrokenDateTime &time, const GeoPoint &location)
{
  JSON::ObjectWriter object(writer);

  if (time.IsPlausible()) {
    NarrowString<64> buffer;
    FormatISO8601(buffer.buffer(), time);
    object.WriteElement("time", JSON::WriteString, buffer);
  }

  if (location.IsValid())
    JSON::WriteGeoPointAttributes(object, location);
}
コード例 #5
0
ファイル: RunDeviceDriver.cpp プロジェクト: Advi42/XCSoar
int main(int argc, char **argv)
{
  NarrowString<1024> usage;
  usage = "DRIVER\n\n"
          "Where DRIVER is one of:";
  {
    const DeviceRegister *driver;
    for (unsigned i = 0; (driver = GetDriverByIndex(i)) != nullptr; ++i) {
      WideToUTF8Converter driver_name(driver->name);
      usage.AppendFormat("\n\t%s", (const char *)driver_name);
    }
  }

  Args args(argc, argv, usage);
  tstring driver_name = args.ExpectNextT();
  args.ExpectEnd();

  driver = FindDriverByName(driver_name.c_str());
  if (driver == nullptr) {
    _ftprintf(stderr, _T("No such driver: %s\n"), driver_name.c_str());
    return 1;
  }

  DeviceConfig config;
  config.Clear();

  NullPort port;
  Device *device = driver->CreateOnPort != nullptr
    ? driver->CreateOnPort(config, port)
    : nullptr;

  NMEAParser parser;

  NMEAInfo data;
  data.Reset();

  char buffer[1024];
  while (fgets(buffer, sizeof(buffer), stdin) != nullptr) {
    StripRight(buffer);

    if (device == nullptr || !device->ParseNMEA(buffer, data))
      parser.ParseLine(buffer, data);
  }

  Dump(data);

  return EXIT_SUCCESS;
}
コード例 #6
0
 /**
  * Constructs a secure random number generator (RNG) implementing the named
  * random number algorithm.
  */
 SecureRandomBase::SecureRandomBase(const NarrowString& algorithm, const byte*, size_t)
     : m_catastrophic(false), m_algorithm(algorithm)
 {
     ASSERT( !algorithm.empty() );
     //ASSERT(seed);
     //ASSERT(size); 
 }
コード例 #7
0
  /**
   * Return true if specified cipher mode may be used for encryption and
   *   decryption operations via {@link org.owasp.esapi.Encryptor}.
   * @param cipherMode The specified cipher mode to be used for the encryption
   *                   or decryption operation.
   * @return true if the specified cipher mode is in the comma-separated list
   *         of cipher modes supporting both confidentiality and authenticity;
   *         otherwise false.
   * @see #isCombinedCipherMode(String)
   * @see org.owasp.esapi.SecurityConfiguration#getCombinedCipherModes()
   * @see org.owasp.esapi.SecurityConfiguration#getAdditionalAllowedCipherModes()
   */
  bool CryptoHelper::isAllowedCipherMode(const NarrowString& cipherMode)
  {
    ESAPI_ASSERT2( !cipherMode.empty(), "cipherMode is not valid" );
    if(cipherMode.empty())
      throw IllegalArgumentException("Cipher mode is not valid");

    if ( isCombinedCipherMode(cipherMode) ) { 
      return true; 
    } 

    DummyConfiguration config;
    const StringList& extraModes = config.getAdditionalAllowedCipherModes();
        
    StringList::const_iterator it = std::find(extraModes.begin(), extraModes.end(), cipherMode);
    return it != extraModes.end(); 
  }
コード例 #8
0
 /**
  * Constructs a secure random number generator (RNG) implementing the named
  * random number algorithm if specified
  */
 SecureRandom::SecureRandom(const NarrowString& algorithm)   
     : m_lock(new Mutex),
       m_impl(SecureRandomBase::createInstance(AlgorithmName::normalizeAlgorithm(algorithm), nullptr, 0))    
 {
     ASSERT( !algorithm.empty() );
     ASSERT(m_lock.get() != nullptr);
     ASSERT(m_impl.get() != nullptr);
 }
コード例 #9
0
	bool getFirstToken (const NarrowString & str, size_t pos, size_t & endpos, NarrowString & token, const char * sepChars)
	{
		const size_t first_nonspace = str.find_first_not_of ( sepChars, pos );

		if (first_nonspace != std::string::npos)
		{
			const size_t first_space    = str.find_first_of   (sepChars, first_nonspace );
			if (first_space != std::string::npos)
				token = str.substr (first_nonspace, first_space - first_nonspace);
			else
				token = str.substr (first_nonspace);

			endpos = first_space;
			return true;
		}
		else
			return false;
	}
コード例 #10
0
ファイル: Client.cpp プロジェクト: grafal/xcsoar-dev
bool
LiveTrack24::Client::GenerateSessionID(const TCHAR *_username, const TCHAR *_password,
                                       OperationEnvironment &env)
{
  // http://www.livetrack24.com/client.php?op=login&user=<username>&pass=<pass>

  assert(_username != NULL);
  assert(!StringIsEmpty(_username));
  assert(_password != NULL);
  assert(!StringIsEmpty(_password));

  const WideToUTF8Converter username2(_username);
  const WideToUTF8Converter password2(_password);
  if (!username2.IsValid() || !password2.IsValid())
    return false;

  NarrowString<1024> url;
  url.Format("http://%s/client.php?op=login&user=%s&pass=%s",
             (const char *)server, (const char *)username2, (const char *)_password);

  // Open download session
  Net::Session session;

  // Request the file
  char buffer[1024];
  size_t size = Net::DownloadToBuffer(session, url, buffer, sizeof(buffer) - 1,
                                      env);
  if (size == 0 || size == size_t(-1))
    return false;

  buffer[size] = 0;

  char *p_end;
  UserID user_id = strtoul(buffer, &p_end, 10);
  if (buffer == p_end) {
      return false;
  }

  username.SetASCII(_username);
  password.SetASCII(_password);
  session_id = RandomSessionID();
  session_id |= (user_id & 0x00ffffff);
  return true;
}
コード例 #11
0
ファイル: Device.cpp プロジェクト: pascaltempez/xcsoar
bool
FlarmDevice::GetConfig(const char *setting, TCHAR *buffer, size_t length)
{
  NarrowString<256> request;
  request.Format("PFLAC,R,%s", setting);

  NarrowString<256> expected_answer(request);
  expected_answer[6u] = 'A';
  expected_answer += ',';

  char narrow_buffer[length];

  Send(request);
  if (!Receive(expected_answer, narrow_buffer, length, 1000))
    return false;

  _tcscpy(buffer, PathName(narrow_buffer));
  return true;
}
コード例 #12
0
ファイル: ConfigWidget.cpp プロジェクト: CnZoom/XcSoarPull
bool
FLARMConfigWidget::Save(bool &_changed)
{
  PopupOperationEnvironment env;
  bool changed = false;
  NarrowString<32> buffer;

  if (SaveValue(Baud, baud)) {
    buffer.UnsafeFormat("%u", baud);
    device.SendSetting("BAUD", buffer, env);
    changed = true;
  }

  if (SaveValue(Priv, priv)) {
    buffer.UnsafeFormat("%u", priv);
    device.SendSetting("PRIV", buffer, env);
    changed = true;
  }

  if (SaveValue(Thre, thre)) {
    buffer.UnsafeFormat("%u", thre);
    device.SendSetting("THRE", buffer, env);
    changed = true;
  }

  if (SaveValue(Range, range)) {
    buffer.UnsafeFormat("%u", range);
    device.SendSetting("RANGE", buffer, env);
    changed = true;
  }

  if (SaveValue(Acft, acft)) {
    buffer.UnsafeFormat("%u", acft);
    device.SendSetting("ACFT", buffer, env);
    changed = true;
  }

  if (SaveValue(LogInt, log_int)) {
    buffer.UnsafeFormat("%u", log_int);
    device.SendSetting("LOGINT", buffer, env);
    changed = true;
  }

  if (SaveValue(NoTrack, notrack)) {
    buffer.UnsafeFormat("%u", notrack);
    device.SendSetting("NOTRACK", buffer, env);
    changed = true;
  }

  _changed |= changed;
  return true;
}
コード例 #13
0
  /**
   * Generate a random secret key appropriate to the specified cipher algorithm
   * and key size.
   * @param alg        The cipher algorithm or cipher transformation. (If the latter is
   *                   passed, the cipher algorithm is determined from it.) Cannot be empty.
   * @param keyBits    The key size, in bits.
   * @return           A random {@code SecretKey} is returned.
   */
  SecretKey CryptoHelper::generateSecretKey(const NarrowString& alg, unsigned int keyBits)
  {
    ASSERT( !alg.empty() );
    ASSERT( keyBits >= 56 );
    ASSERT( (keyBits % 8) == 0 );

    KeyGenerator kgen(KeyGenerator::getInstance(alg));
    kgen.init(keyBits);

    return kgen.generateKey();
  }
コード例 #14
0
    /**
     * Returns a SecureRandom object that implements the specified Random Number Generator (RNG) algorithm.
     */
    SecureRandom SecureRandom::getInstance(const NarrowString& algorithm)
    {
        ASSERT( !algorithm.empty() );

        const NarrowString alg(AlgorithmName::normalizeAlgorithm(algorithm));
        SecureRandomBase* impl = SecureRandomBase::createInstance(alg, nullptr, 0);
        MEMORY_BARRIER();

        ASSERT(impl != nullptr);
        return SecureRandom(impl);
    }
コード例 #15
0
ファイル: V7ConfigWidget.cpp プロジェクト: damianob/xcsoar
bool
V7ConfigWidget::Save(bool &_changed, bool &require_restart)
{
  PopupOperationEnvironment env;
  bool changed = false;
  NarrowString<32> buffer;

  if (SaveValue(BRGPS, brgps)) {
    buffer.UnsafeFormat("%u", brgps);
    device.SendV7Setting("BRGPS", buffer, env);
    changed = true;
  }

  if (SaveValue(BRPDA, brpda)) {
    buffer.UnsafeFormat("%u", brpda);
    device.SendV7Setting("BRPDA", buffer, env);
    changed = true;
  }

  _changed |= changed;
  return true;
}
コード例 #16
0
  AlgorithmName::AlgorithmName(const NarrowString& algorithm, bool cipherOnly)
    : m_normal(normalizeAlgorithm(algorithm))
  {
    ASSERT( !algorithm.empty() );

    // We'd prefer to throw in the ctor, but its a limitation, not a feature!
    // Actually, we need to narmalize first (in case of throw), so maybe it is a feature.
    NarrowString cipher;
    getCipher(cipher);

    if(cipherOnly && m_normal != cipher)
      throw NoSuchAlgorithmException(m_normal + " not available");
  }
コード例 #17
0
ファイル: LiveTrack24.cpp プロジェクト: Advi42/XCSoar
LiveTrack24::UserID
LiveTrack24::GetUserID(const TCHAR *username, const TCHAR *password,
                       OperationEnvironment &env)
{
  // http://www.livetrack24.com/client.php?op=login&user=<username>&pass=<pass>

  assert(username != NULL);
  assert(!StringIsEmpty(username));
  assert(password != NULL);
  assert(!StringIsEmpty(password));

  const WideToUTF8Converter username2(username);
  const WideToUTF8Converter password2(password);
  if (!username2.IsValid() || !password2.IsValid())
    return 0;

  NarrowString<1024> url;
  url.Format("http://%s/client.php?op=login&user=%s&pass=%s",
             GetServer(), (const char *)username2, (const char *)password);

  // Open download session
  Net::Session session;

  // Request the file
  char buffer[1024];
  size_t size = Net::DownloadToBuffer(session, url, buffer, sizeof(buffer) - 1,
                                      env);
  if (size == 0 || size == size_t(-1))
    return 0;

  buffer[size] = 0;

  char *p_end;
  UserID user_id = strtoul(buffer, &p_end, 10);
  if (buffer == p_end)
    return 0;

  return user_id;
}
コード例 #18
0
ファイル: LiveTrack24.cpp プロジェクト: Advi42/XCSoar
bool
LiveTrack24::SendPosition(SessionID session, unsigned packet_id,
                          GeoPoint position, unsigned altitude,
                          unsigned ground_speed, Angle track,
                          int64_t timestamp_utc,
                          OperationEnvironment &env)
{
  // http://www.livetrack24.com/track.php?leolive=4&sid=42664778&pid=321&
  //   lat=22.3&lon=40.2&alt=23&sog=40&cog=160&tm=1241422845

  NarrowString<2048> url;
  url.Format("http://%s/track.php?leolive=4&sid=%u&pid=%u&"
             "lat=%f&lon=%f&alt=%d&sog=%d&cog=%d&tm=%lld",
             GetServer(), session, packet_id,
             (double)position.latitude.Degrees(),
             (double)position.longitude.Degrees(),
             altitude, ground_speed,
             (unsigned)track.AsBearing().Degrees(),
             (long long int)timestamp_utc);

  return SendRequest(url, env);
}
コード例 #19
0
ファイル: FlightPhaseJSON.cpp プロジェクト: CnZoom/XcSoarPull
static void
WritePhase(TextWriter &writer, Phase &phase)
{
  JSON::ObjectWriter object(writer);
  NarrowString<64> buffer;

  FormatISO8601(buffer.buffer(), phase.start_datetime);
  object.WriteElement("start_time", JSON::WriteString, buffer);

  FormatISO8601(buffer.buffer(), phase.end_datetime);
  object.WriteElement("end_time", JSON::WriteString, buffer);

  object.WriteElement("type", JSON::WriteString,
                      FormatPhaseType(phase.phase_type));
  object.WriteElement("duration", JSON::WriteInteger, (int)phase.duration);
  object.WriteElement("circling_direction", JSON::WriteString,
                      FormatCirclingDirection(phase.circling_direction));
  object.WriteElement("alt_diff", JSON::WriteInteger, (int)phase.alt_diff);
  object.WriteElement("distance", JSON::WriteInteger, (int)phase.distance);
  object.WriteElement("speed", JSON::WriteFixed, phase.GetSpeed());
  object.WriteElement("vario", JSON::WriteFixed, phase.GetVario());
  object.WriteElement("glide_rate", JSON::WriteFixed, phase.GetGlideRate());
}
コード例 #20
0
ファイル: FontConfig.cpp プロジェクト: DRIZO/xcsoar
void
Profile::SetFont(const char *key, LOGFONT &logfont)
{
  assert(key != NULL);
  assert(key[0] != '\0');

#ifdef _UNICODE
  char face[256];
  WideCharToMultiByte(CP_UTF8, 0, logfont.lfFaceName, -1,
                      face, ARRAY_SIZE(face),
                      nullptr, nullptr);
#else
  const char *face = logfont.lfFaceName;
#endif

  NarrowString<256> buffer;
  buffer.Format("%d,%d,0,0,%d,%d,0,0,0,0,0,%d,%d,%s", logfont.lfHeight,
                logfont.lfWidth, logfont.lfWeight, logfont.lfItalic,
                logfont.lfQuality, logfont.lfPitchAndFamily,
                face);

  Profile::Set(key, buffer);
}
コード例 #21
0
ファイル: Resolver.cpp プロジェクト: kjk/ars-framework
status_t resolve(SocketAddress& out, NetLibrary& netLib, const char* address, ushort_t port, ulong_t timeout)
{
    NarrowString validAddress;
    status_t error = validateAddress(address, validAddress, port);
    if (error)
        return error;
        
    INetSocketAddress addr;
    // TODO: the assumption that the ip address is numeric if the first
    // letter is a digit is incorrect. A symbolic name can also start
    // with a digit. Better test would be to check if the whole name
    // consists of digits or "."
    if (!validAddress.empty() && isDigit(validAddress[0]))
    {
        error=netLib.addrAToIN(validAddress.c_str(), addr);
        if (error)
            return error;
        addr.setPort(port);
        out=addr;
        return errNone;
    }
    return blockingResolve(out, netLib, validAddress, port, timeout);
}
コード例 #22
0
ファイル: Resolver.cpp プロジェクト: kjk/ars-framework
static status_t validateAddress(const NarrowString& origAddress, NarrowString& validAddress, ushort_t& port)
{
    NarrowString::size_type pos = origAddress.find(':', 1);
    if (origAddress.npos == pos)
        return netErrParamErr;
    
    ushort_t portLength = origAddress.length() - pos - 1;
    if (portLength>0)
    {
        long value=0;
        status_t error = numericValue(origAddress.data()+pos+1, origAddress.data()+pos+1+portLength, value);
        if ((errNone != error) || (value > ushort_t(-1)))
            return netErrParamErr;

        port = ushort_t(value);
    }

    if (0 == port)
        return netErrParamErr;        

    validAddress.assign(origAddress, 0, pos);
    return errNone;
}
コード例 #23
0
ファイル: Resolver.cpp プロジェクト: kjk/ars-framework
static status_t blockingResolve(SocketAddress& out, NetLibrary& netLib, const NarrowString& name, ushort_t port, ulong_t timeout)
{
    std::auto_ptr<HostInfoBuffer> buffer(new  HostInfoBuffer);
    memzero(buffer.get(), sizeof(HostInfoBuffer));
    assert(!netLib.closed());
    status_t error=netLib.getHostByName(name.c_str(), *buffer, timeout);
    if (error)
        return error;

    IPAddr  resAddr=buffer->getAddress();
    assert(resAddr.ip != 0);
    INetSocketAddress addr(resAddr, port);
    out=addr;
    return errNone;
}
コード例 #24
0
ファイル: TCPClientPort.cpp プロジェクト: DRIZO/xcsoar
bool
TCPClientPort::Connect(const char *host, unsigned port)
{
  NarrowString<32> service;
  service.UnsafeFormat("%u", port);

  SocketAddress address;
  if (!address.Lookup(host, service, AF_INET))
    return false;

  SocketDescriptor s;
  if (!s.CreateTCP())
    return false;

#ifdef HAVE_POSIX
  s.SetNonBlocking();
#endif

  if (s.Connect(address)) {
#ifdef HAVE_POSIX
    s.SetBlocking();
#endif
    Set(std::move(s));
    return true;
  }

#ifdef HAVE_POSIX
  if (errno == EINPROGRESS) {
    connecting = std::move(s);
    io_thread->LockAdd(connecting.Get(), Poll::WRITE, *this);
    return true;
  }
#endif

  return false;
}
コード例 #25
0
  /**
  * Returns a KeyGenerator object that generates secret keys for the specified algorithm.
  */
  KeyGenerator KeyGenerator::getInstance(const NarrowString& algorithm)
  {
    ASSERT( !algorithm.empty() );
    KeyGenerator kgen(algorithm);

    // http://download.oracle.com/javase/6/docs/api/javax/crypto/KeyGenerator.html
    // "This class provides the functionality of a secret (symmetric) key generator."
    NarrowString cipher = kgen.getAlgorithm();
    if(cipher != "DES" && cipher != "DES_ede" && cipher != "Blowfish" && cipher != "AES" &&
      cipher != "Camellia" && cipher != "HmacSHA1" && cipher != "HmacSHA224" &&
      cipher != "HmacSHA256" && cipher != "HmacSHA384"&& cipher != "HmacSHA512" &&
      cipher != "HmacWhirlpoo" )
    {
      throw NoSuchAlgorithmException(cipher + " KeyGenerator not available");
    }

    return kgen;
  }
コード例 #26
0
ファイル: FeedFlyNetData.cpp プロジェクト: ThomasXBMC/XCSoar
int main(int argc, char **argv)
{
  Args args(argc, argv, "PORT");
  const DeviceConfig config = ParsePortArgs(args);
  args.ExpectEnd();

  InitialiseIOThread();

  Port *port = OpenPort(config, nullptr, *(DataHandler *)nullptr);
  if (port == nullptr) {
    DeinitialiseIOThread();
    fprintf(stderr, "Failed to open port\n");
    return EXIT_FAILURE;
  }

  ConsoleOperationEnvironment env;

  if (!port->WaitConnected(env)) {
    delete port;
    DeinitialiseIOThread();
    fprintf(stderr, "Failed to connect the port\n");
    return EXIT_FAILURE;
  }

  PeriodClock start_clock;
  start_clock.Update();

  PeriodClock pressure_clock;
  PeriodClock battery_clock;

  fixed pressure = fixed(101300);
  unsigned battery_level = 11;
  while (true) {
    if (pressure_clock.CheckUpdate(48)) {
      NarrowString<16> sentence;

      int elapsed_ms = start_clock.Elapsed();
      auto elapsed = fixed(elapsed_ms) / 1000;
      auto vario = sin(elapsed / 3) * cos(elapsed / 10) *
        cos(elapsed / 20 + fixed(2)) * 3;

      auto pressure_vario = -vario * fixed(12.5);
      auto delta_pressure = pressure_vario * 48 / 1000;
      pressure += delta_pressure;

      sentence = "_PRS ";
      sentence.AppendFormat("%08X", uround(pressure));
      sentence += "\n";

      port->Write(sentence.c_str(), sentence.length());
    }

    if (battery_clock.CheckUpdate(11000)) {
      NarrowString<16> sentence;

      sentence = "_BAT ";
      if (battery_level <= 10)
        sentence.AppendFormat("%X", battery_level);
      else
        sentence += "*";

      sentence += "\n";
      port->Write(sentence.c_str(), sentence.length());

      if (battery_level == 0)
        battery_level = 11;
      else
        battery_level--;
    }
  }
}
コード例 #27
0
ファイル: Parser.cpp プロジェクト: kwtskran/XCSoar
static void
ReadString(NMEAInputLine &line, NarrowString<N> &value)
{
  line.Read(value.buffer(), value.capacity());
}
コード例 #28
0
ファイル: AvailableFile.hpp プロジェクト: Adrien81/XCSoar
 void Clear() {
   name.clear();
   uri.clear();
   area.clear();
   type = Type::UNKNOWN;
 }
コード例 #29
0
ファイル: Parser.cpp プロジェクト: osteocool/XCSoar-1
static void
ReadString(NMEAInputLine &line, NarrowString<N> &value)
{
  line.Read(value.buffer(), value.MAX_SIZE);
}
コード例 #30
0
ファイル: Declare.cpp プロジェクト: kwtskran/XCSoar
bool
FlarmDevice::DeclareInternal(const Declaration &declaration,
                             OperationEnvironment &env)
{
  unsigned size = declaration.Size();

  env.SetProgressRange(6 + size);
  env.SetProgressPosition(0);

  if (!SetPilot(declaration.pilot_name.c_str(), env))
    return false;

  env.SetProgressPosition(1);

  if (!SetPlaneRegistration(declaration.aircraft_registration.c_str(), env))
    return false;

  env.SetProgressPosition(2);

  if (!SetPlaneType(declaration.aircraft_type.c_str(), env))
    return false;

  env.SetProgressPosition(3);

  if (!SetConfig("NEWTASK", "Task", env))
    return false;

  env.SetProgressPosition(4);

  if (!SetConfig("ADDWP", "0000000N,00000000E,T", env))
    return false;

  env.SetProgressPosition(5);

  for (unsigned i = 0; i < size; ++i) {
    int DegLat, DegLon;
    fixed tmp, MinLat, MinLon;
    char NoS, EoW;

    tmp = declaration.GetLocation(i).latitude.Degrees();
    if (negative(tmp)) {
      NoS = 'S';
      tmp = -tmp;
    } else {
      NoS = 'N';
    }
    DegLat = (int)tmp;
    MinLat = (tmp - fixed(DegLat)) * 60 * 1000;

    tmp = declaration.GetLocation(i).longitude.Degrees();
    if (negative(tmp)) {
      EoW = 'W';
      tmp = -tmp;
    } else {
      EoW = 'E';
    }
    DegLon = (int)tmp;
    MinLon = (tmp - fixed(DegLon)) * 60 * 1000;

    /*
     * We use the waypoint index here as name to get around the 192 byte
     * task size limit of the FLARM devices.
     *
     * see Flarm DataPort Manual:
     * "The total data size entered through this command may not surpass
     * 192 bytes when calculated as follows: 7+(Number of Waypoints * 9) +
     * (sum of length of all task and waypoint descriptions)"
     */
    NarrowString<90> buffer;
    buffer.Format("%02d%05.0f%c,%03d%05.0f%c,%d",
                  DegLat, (double)MinLat, NoS,
                  DegLon, (double)MinLon, EoW, i + 1);

    if (!SetConfig("ADDWP", buffer, env))
      return false;

    env.SetProgressPosition(6 + i);
  }

  if (!SetConfig("ADDWP", "0000000N,00000000E,L", env))
    return false;

  env.SetProgressPosition(6 + size);

  // PFLAC,S,KEY,VALUE
  // Expect
  // PFLAC,A,blah
  // PFLAC,,COPIL:
  // PFLAC,,COMPID:
  // PFLAC,,COMPCLASS:

  // PFLAC,,NEWTASK:
  // PFLAC,,ADDWP:

  // Reset the FLARM to activate the declaration
  Restart(env);

  return true;
}