inline void SkyLinesTracking::Client::OnDatagramReceived(void *data, size_t length) { Header &header = *(Header *)data; if (length < sizeof(header)) return; const uint16_t received_crc = FromBE16(header.crc); header.crc = 0; const uint16_t calculated_crc = UpdateCRC16CCITT(data, length, 0); if (received_crc != calculated_crc) return; const ACKPacket &ack = *(const ACKPacket *)data; const TrafficResponsePacket &traffic = *(const TrafficResponsePacket *)data; const UserNameResponsePacket &user_name = *(const UserNameResponsePacket *)data; const auto &wave = *(const WaveResponsePacket *)data; const auto &thermal = *(const ThermalResponsePacket *)data; switch ((Type)FromBE16(header.type)) { case PING: case FIX: case TRAFFIC_REQUEST: case USER_NAME_REQUEST: case WAVE_SUBMIT: case WAVE_REQUEST: case THERMAL_SUBMIT: case THERMAL_REQUEST: break; case ACK: handler->OnAck(FromBE16(ack.id)); break; case TRAFFIC_RESPONSE: OnTrafficReceived(traffic, length); break; case USER_NAME_RESPONSE: OnUserNameReceived(user_name, length); break; case WAVE_RESPONSE: OnWaveReceived(wave, length); break; case THERMAL_RESPONSE: OnThermalReceived(thermal, length); break; } }
bool CAI302::DownloadPilot(Port &port, const Pilot &pilot, unsigned ordinal, OperationEnvironment &env) { char buffer[256]; snprintf(buffer, sizeof(buffer), "O,%-24s,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\r", pilot.name, (ordinal << 8) | pilot.old_units, pilot.old_temperatur_units, pilot.sink_tone, pilot.total_energy_final_glide, pilot.show_final_glide_altitude_difference, pilot.map_datum, FromBE16(pilot.approach_radius), FromBE16(pilot.arrival_radius), FromBE16(pilot.enroute_logging_interval), FromBE16(pilot.close_logging_interval), FromBE16(pilot.time_between_flight_logs), FromBE16(pilot.minimum_speed_to_force_flight_logging), pilot.stf_dead_band, pilot.reserved_vario, FromBE16(pilot.unit_word), FromBE16(pilot.margin_height)); return DownloadCommand(port, buffer, env); }
static void HandleExtConfig(FILE *file, const struct LXN::ExtConfig &packet, LXN::ExtensionConfig &config, char record, unsigned column) { /* count bits in extension mask and write information about each extension*/ const unsigned ext_dat = FromBE16(packet.dat); config.num = 0; for (unsigned bit = 0; bit < 16; ++bit) { if (ext_dat & (1 << bit)) { config.extensions[config.num++] = LXN::extension_defs[bit]; } } if (config.num == 0) return; /* begin record */ fprintf(file, "%c%02d", record, config.num); /* write information about each extension */ for (unsigned i = 0; i < config.num; ++i) { fprintf(file, "%02d%02d%s", column, column + config.extensions[i].width - 1, config.extensions[i].name); column += config.extensions[i].width; } fprintf(file, "\r\n"); }
rx_int16 IOBuffer::consumeI16BE() { rx_int16 val = 0; memcpy(&val, buffer+consumed, 2); val = FromBE16(val); consumed += 2; return val; }
// generate Header-Structure from DBB-File void DBB::open_dbb() { int i; // determine the beginning and length of the database parts const Volkslogger::TableHeader *src = GetHeader(0); for(i=0; i<8; i++) { if (src->start_offset == 0xffff) continue; header[i].dsfirst = FromBE16(src->start_offset); header[i].dslast = FromBE16(src->end_offset); header[i].dslaenge = src->dslaenge; header[i].keylaenge = src->keylaenge; ++src; } }
bool CAI302::DownloadPolar(Port &port, const Polar &polar, OperationEnvironment &env) { char buffer[256]; snprintf(buffer, sizeof(buffer), "G,%-12s,%-12s,%d,%d,%d,%d,%d,%d,%d,%d\r", polar.glider_type, polar.glider_id, polar.best_ld, polar.best_glide_speed, polar.two_ms_sink_at_speed, FromBE16(polar.weight_in_litres), FromBE16(polar.ballast_capacity), 0, FromBE16(polar.config_word), FromBE16(polar.wing_area)); return DownloadCommand(port, buffer, env); }
inline void SkyLinesTracking::Client::OnThermalReceived(const ThermalResponsePacket &packet, size_t length) { if (length < sizeof(packet)) return; const unsigned n = packet.thermal_count; ConstBuffer<Thermal> thermals((const Thermal *)(&packet + 1), n); if (length != sizeof(packet) + thermals.size * sizeof(thermals.front())) return; for (const auto &thermal : thermals) handler->OnThermal(FromBE32(thermal.time), AGeoPoint(ImportGeoPoint(thermal.bottom_location), FromBE16(thermal.bottom_altitude)), AGeoPoint(ImportGeoPoint(thermal.top_location), FromBE16(thermal.top_altitude)), FromBE16(thermal.lift) / 256.); }
CloudThermal CloudThermal::Load(Deserialiser &s) { s.Read8(); const unsigned client_key = s.Read64(); std::chrono::steady_clock::time_point time; s >> time; SkyLinesTracking::Thermal t; s.ReadT(t); CloudThermal thermal(client_key, AGeoPoint(SkyLinesTracking::ImportGeoPoint(t.bottom_location), FromBE16(t.bottom_altitude)), AGeoPoint(SkyLinesTracking::ImportGeoPoint(t.top_location), FromBE16(t.top_altitude)), FromBE16(t.lift) / 256.); thermal.time = time; return thermal; }
int CAI302Device::ReadNavpointCount(OperationEnvironment &env) { if (!UploadMode(env)) return false; CAI302::NavpointMeta meta; if (!CAI302::UploadNavpointMeta(port, meta, env)) { mode = Mode::UNKNOWN; return -1; } return FromBE16(meta.count); }
static bool DownloadFlightInner(Port &port, const RecordedFlightInfo &flight, FILE *file, OperationEnvironment &env) { if (!LX::CommandMode(port, env)) return false; port.Flush(); LX::SeekMemory seek; seek.start_address = flight.internal.lx.start_address; seek.end_address = flight.internal.lx.end_address; if (!LX::SendPacket(port, LX::SEEK_MEMORY, &seek, sizeof(seek), env) || !LX::ExpectACK(port, env)) return false; LX::MemorySection memory_section; if (!LX::ReceivePacketRetry(port, LX::READ_MEMORY_SECTION, &memory_section, sizeof(memory_section), env, 5000, 2000, 60000, 2)) return false; unsigned lengths[LX::MemorySection::N]; unsigned total_length = 0; for (unsigned i = 0; i < LX::MemorySection::N; ++i) { lengths[i] = FromBE16(memory_section.lengths[i]); total_length += lengths[i]; } env.SetProgressRange(total_length); uint8_t *data = new uint8_t[total_length], *p = data; for (unsigned i = 0; i < LX::MemorySection::N && lengths[i] > 0; ++i) { if (!LX::ReceivePacketRetry(port, (LX::Command)(LX::READ_LOGGER_DATA + i), p, lengths[i], env, 20000, 2000, 300000, 2)) { delete [] data; return false; } p += lengths[i]; env.SetProgressPosition(p - data); } bool success = LX::ConvertLXNToIGC(data, total_length, file); delete [] data; return success; }
static void HandlePosition(FILE *file, Context &context, const struct LXN::Position &position) { int latitude, longitude; context.fix_stat = position.cmd == LXN::POSITION_OK ? 'A' : 'V'; context.time = context.origin_time + (int16_t)FromBE16(position.time); latitude = context.origin_latitude + (int16_t)FromBE16(position.latitude); longitude = context.origin_longitude + (int16_t)FromBE16(position.longitude); if (context.is_event) { fprintf(file,"E%02d%02d%02d%s\r\n", context.time / 3600, context.time % 3600 / 60, context.time % 60, context.event.foo); context.is_event = 0; } fprintf(file, "B%02d%02d%02d", context.time / 3600, context.time % 3600 / 60, context.time % 60); fprintf(file, "%02d%05d%c" "%03d%05d%c", abs(latitude) / 60000, abs(latitude) % 60000, latitude >= 0 ? 'N' : 'S', abs(longitude) / 60000, abs(longitude) % 60000, longitude >= 0 ? 'E' : 'W'); fprintf(file, "%c", context.fix_stat); fprintf(file, "%05d%05d", /* altitudes can be negative, so cast the uint16_t to int16_t to interpret the most significant bit as sign bit */ (int16_t)FromBE16(position.aalt), (int16_t)FromBE16(position.galt)); if (context.b_ext.num == 0) fprintf(file, "\r\n"); }
inline void SkyLinesTracking::Client::OnTrafficReceived(const TrafficResponsePacket &packet, size_t length) { const unsigned n = packet.traffic_count; const TrafficResponsePacket::Traffic *traffic = (const TrafficResponsePacket::Traffic *)(&packet + 1); if (length != sizeof(packet) + n * sizeof(*traffic)) return; const TrafficResponsePacket::Traffic *end = traffic + n; for (; traffic != end; ++traffic) handler->OnTraffic(FromBE32(traffic->pilot_id), FromBE32(traffic->time), ::GeoPoint(Angle::Degrees(fixed(FromBE32(traffic->location.longitude)) / 1000000), Angle::Degrees(fixed(FromBE32(traffic->location.latitude)) / 1000000)), FromBE16(traffic->altitude)); }
inline void SkyLinesTracking::Client::OnTrafficReceived(const TrafficResponsePacket &packet, size_t length) { if (length < sizeof(packet)) return; const unsigned n = packet.traffic_count; const ConstBuffer<TrafficResponsePacket::Traffic> list((const TrafficResponsePacket::Traffic *)(&packet + 1), n); if (length != sizeof(packet) + n * sizeof(list.front())) return; for (const auto &traffic : list) handler->OnTraffic(FromBE32(traffic.pilot_id), FromBE32(traffic.time), ImportGeoPoint(traffic.location), (int16_t)FromBE16(traffic.altitude)); }
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; }
bool LX::ConvertLXNToIGC(const void *_data, size_t _length, FILE *file) { const uint8_t *data = (const uint8_t *)_data, *end = data + _length; Context context; char ch; unsigned l; while (data < end) { union LXN::Packet packet = { data }; unsigned packet_length; switch ((LXN::Command)*packet.cmd) { case LXN::EMPTY: packet_length = 0; while (data < end && *data == LXN::EMPTY) { ++packet_length; ++data; } fprintf(file, "LFILEMPTY%u\r\n", packet_length); break; case LXN::END: return true; case LXN::VERSION: data += sizeof(*packet.version); if (data > end) return false; fprintf(file, "HFRFWFIRMWAREVERSION:%3.1f\r\n" "HFRHWHARDWAREVERSION:%3.1f\r\n", packet.version->software / 10., packet.version->hardware / 10.); break; case LXN::START: data += sizeof(*packet.start); if (data > end || memcmp(packet.start->streraz, "STReRAZ", 8) != 0) return false; context.flight_no = packet.start->flight_no; break; case LXN::ORIGIN: data += sizeof(*packet.origin); if (data > end) return false; context.origin_time = FromBE32(packet.origin->time); context.origin_latitude = (int32_t)FromBE32(packet.origin->latitude); context.origin_longitude = (int32_t)FromBE32(packet.origin->longitude); fprintf(file, "L%.*sORIGIN%02d%02d%02d" "%02d%05d%c" "%03d%05d%c\r\n", (int)sizeof(context.vendor), context.vendor, context.origin_time / 3600, context.origin_time % 3600 / 60, context.origin_time % 60, abs(context.origin_latitude) / 60000, abs(context.origin_latitude) % 60000, context.origin_latitude >= 0 ? 'N' : 'S', abs(context.origin_longitude) / 60000, abs(context.origin_longitude) % 60000, context.origin_longitude >= 0 ? 'E' : 'W'); break; case LXN::SECURITY_OLD: data += sizeof(*packet.security_old); if (data > end) return false; fprintf(file, "G%22.22s\r\n", packet.security_old->foo); break; case LXN::SERIAL: data += sizeof(*packet.serial); if (data > end) return false; if (!ValidString(packet.serial->serial, sizeof(packet.serial->serial))) return false; fprintf(file, "A%sFLIGHT:%u\r\nHFDTE%s\r\n", packet.serial->serial, context.flight_no, context.date); break; case LXN::POSITION_OK: case LXN::POSITION_BAD: data += sizeof(*packet.position); if (data > end) return false; HandlePosition(file, context, *packet.position); break; case LXN::SECURITY: data += sizeof(*packet.security); if (data > end || packet.security->length > sizeof(packet.security->foo)) return false; if (packet.security->type == LXN::SECURITY_HIGH) ch = '2'; else if (packet.security->type == LXN::SECURITY_MED) ch = '1'; else if (packet.security->type == LXN::SECURITY_LOW) ch = '0'; else return false; fprintf(file, "G%c", ch); for (unsigned i = 0; i < packet.security->length; ++i) fprintf(file, "%02X", packet.security->foo[i]); fprintf(file, "\r\n"); break; case LXN::SECURITY_7000: data += sizeof(*packet.security_7000); if (data > end || packet.security_7000->x40 != 0x40) return false; fprintf(file, "G3"); for (auto ch : packet.security_7000->line1) fprintf(file, "%02X", ch); fprintf(file, "\r\nG"); for (auto ch : packet.security_7000->line2) fprintf(file, "%02X", ch); fprintf(file, "\r\nG"); for (auto ch : packet.security_7000->line3) fprintf(file, "%02X", ch); fprintf(file, "\r\n"); break; case LXN::COMPETITION_CLASS: data += sizeof(*packet.competition_class); if (data > end) return false; if (!ValidString(packet.competition_class->class_id, sizeof(packet.competition_class->class_id))) return false; if (context.flight_info.competition_class_id == 7) fprintf(file, "HFFXA%03d\r\n" "HFPLTPILOT:%s\r\n" "HFGTYGLIDERTYPE:%s\r\n" "HFGIDGLIDERID:%s\r\n" "HFDTM%03dGPSDATUM:%s\r\n" "HFCIDCOMPETITIONID:%s\r\n" "HFCCLCOMPETITIONCLASS:%s\r\n" "HFGPSGPS:%s\r\n", context.flight_info.fix_accuracy, context.flight_info.pilot, context.flight_info.glider, context.flight_info.registration, context.flight_info.gps_date, LXN::FormatGPSDate(context.flight_info.gps_date), context.flight_info.competition_class, packet.competition_class->class_id, context.flight_info.gps); break; case LXN::TASK: data += sizeof(*packet.task); if (data > end) return false; context.time = FromBE32(packet.task->time); // from a valid IGC file read with LXe: // C 11 08 11 14 11 18 11 08 11 0001 -2 fprintf(file, "C%02d%02d%02d%02d%02d%02d" "%02d%02d%02d" "%04d%02d\r\n", packet.task->day, packet.task->month, packet.task->year, context.time / 3600, context.time % 3600 / 60, context.time % 60, packet.task->day2, packet.task->month2, packet.task->year2, FromBE16(packet.task->task_id), packet.task->num_tps); for (unsigned i = 0; i < sizeof(packet.task->usage); ++i) { if (packet.task->usage[i]) { int latitude = (int32_t)FromBE32(packet.task->latitude[i]); int longitude = (int32_t)FromBE32(packet.task->longitude[i]); if (!ValidString(packet.task->name[i], sizeof(packet.task->name[i]))) return false; fprintf(file, "C%02d%05d%c" "%03d%05d%c" "%s\r\n", abs(latitude) / 60000, abs(latitude) % 60000, latitude >= 0 ? 'N' : 'S', abs(longitude) / 60000, abs(longitude) % 60000, longitude >= 0 ? 'E' : 'W', packet.task->name[i]); } } break; case LXN::EVENT: data += sizeof(*packet.event); if (data > end || !ValidString(packet.event->foo, sizeof(packet.event->foo))) return false; context.event = *packet.event; context.is_event = true; break; case LXN::B_EXT: data += sizeof(*packet.b_ext) + context.b_ext.num * sizeof(packet.b_ext->data[0]); if (data > end) return false; for (unsigned i = 0; i < context.b_ext.num; ++i) fprintf(file, "%0*u", (int)context.b_ext.extensions[i].width, FromBE16(packet.b_ext->data[i])); fprintf(file, "\r\n"); break; case LXN::K_EXT: data += sizeof(*packet.k_ext) + context.k_ext.num * sizeof(packet.k_ext->data[0]); if (data > end) return false; l = context.time + packet.k_ext->foo; fprintf(file, "K%02d%02d%02d", l / 3600, l % 3600 / 60, l % 60); for (unsigned i = 0; i < context.k_ext.num; ++i) fprintf(file, "%0*u", context.k_ext.extensions[i].width, FromBE16(packet.k_ext->data[i])); fprintf(file, "\r\n"); break; case LXN::DATE: data += sizeof(*packet.date); if (data > end || packet.date->day > 31 || packet.date->month > 12) return false; snprintf(context.date, sizeof(context.date), "%02d%02d%02d", packet.date->day % 100, packet.date->month % 100, FromBE16(packet.date->year)); break; case LXN::FLIGHT_INFO: data += sizeof(*packet.flight_info); if (data > end || !ValidString(packet.flight_info->pilot, sizeof(packet.flight_info->pilot)) || !ValidString(packet.flight_info->glider, sizeof(packet.flight_info->glider)) || !ValidString(packet.flight_info->registration, sizeof(packet.flight_info->registration)) || !ValidString(packet.flight_info->competition_class, sizeof(packet.flight_info->competition_class)) || !ValidString(packet.flight_info->gps, sizeof(packet.flight_info->gps))) return false; if (packet.flight_info->competition_class_id > 7) return false; if (packet.flight_info->competition_class_id < 7) fprintf(file, "HFFXA%03d\r\n" "HFPLTPILOT:%s\r\n" "HFGTYGLIDERTYPE:%s\r\n" "HFGIDGLIDERID:%s\r\n" "HFDTM%03dGPSDATUM:%s\r\n" "HFCIDCOMPETITIONID:%s\r\n" "HFCCLCOMPETITIONCLASS:%s\r\n" "HFGPSGPS:%s\r\n", packet.flight_info->fix_accuracy, packet.flight_info->pilot, packet.flight_info->glider, packet.flight_info->registration, packet.flight_info->gps_date, LXN::FormatGPSDate(packet.flight_info->gps_date), packet.flight_info->competition_class, LXN::FormatCompetitionClass(packet.flight_info->competition_class_id), packet.flight_info->gps); context.flight_info = *packet.flight_info; break; case LXN::K_EXT_CONFIG: data += sizeof(*packet.ext_config); if (data > end) return false; HandleExtConfig(file, *packet.ext_config, context.k_ext, 'J', 8); break; case LXN::B_EXT_CONFIG: data += sizeof(*packet.ext_config); if (data > end) return false; HandleExtConfig(file, *packet.ext_config, context.b_ext, 'I', 36); break; #ifdef __clang__ #pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif default: if (*packet.cmd < 0x40) { data += sizeof(*packet.string); if (data > end) return false; data += packet.string->length; if (data > end) return false; fprintf(file, "%.*s\r\n", (int)packet.string->length, packet.string->value); if (packet.string->length >= 12 + sizeof(context.vendor) && memcmp(packet.string->value, "HFFTYFRTYPE:", 12) == 0) memcpy(context.vendor, packet.string->value + 12, sizeof(context.vendor)); } else return false; } } return false; }
inline void Server::OnDatagramReceived(Client &&client, void *data, size_t length) { Header &header = *(Header *)data; if (length < sizeof(header)) return; const uint16_t received_crc = FromBE16(header.crc); header.crc = 0; const uint16_t calculated_crc = UpdateCRC16CCITT(data, length, 0); if (received_crc != calculated_crc) return; client.key = FromBE64(header.key); const auto &ping = *(const PingPacket *)data; const auto &fix = *(const FixPacket *)data; const auto &traffic = *(const TrafficRequestPacket *)data; const auto &user_name = *(const UserNameRequestPacket *)data; const auto &wave = ((const WaveSubmitPacket *)data)->wave; const auto &thermal = ((const ThermalSubmitPacket *)data)->thermal; switch ((Type)FromBE16(header.type)) { case PING: if (length < sizeof(ping)) return; OnPing(client, FromBE16(ping.id)); break; case FIX: if (length < sizeof(fix)) return; OnFix(client, ImportTimeMs(fix.time), fix.flags & ToBE32(FixPacket::FLAG_LOCATION) ? ImportGeoPoint(fix.location) : ::GeoPoint::Invalid(), fix.flags & ToBE32(FixPacket::FLAG_ALTITUDE) ? FromBE16(fix.altitude) : -1); break; case TRAFFIC_REQUEST: if (length < sizeof(traffic)) return; OnTrafficRequest(client, traffic.flags & ToBE32(TrafficRequestPacket::FLAG_NEAR)); break; case USER_NAME_REQUEST: if (length < sizeof(user_name)) return; OnUserNameRequest(client, FromBE32(user_name.user_id)); break; case WAVE_SUBMIT: if (length < sizeof(wave)) return; OnWaveSubmit(client, ImportTimeMs(wave.time), ImportGeoPoint(wave.a), ImportGeoPoint(wave.b), (int16_t)FromBE16(wave.bottom_altitude), (int16_t)FromBE16(wave.top_altitude), FromBE16(wave.lift) / 256.); break; case WAVE_REQUEST: OnWaveRequest(client); break; case THERMAL_SUBMIT: if (length < sizeof(thermal)) return; OnThermalSubmit(client, ImportTimeMs(thermal.time), ImportGeoPoint(thermal.bottom_location), (int16_t)FromBE16(thermal.bottom_altitude), ImportGeoPoint(thermal.top_location), (int16_t)FromBE16(thermal.top_altitude), FromBE16(thermal.lift) / 256.); break; case THERMAL_REQUEST: OnThermalRequest(client); break; case ACK: case TRAFFIC_RESPONSE: case USER_NAME_RESPONSE: case WAVE_RESPONSE: case THERMAL_RESPONSE: /* these are server-to-client packets; ignore them */ break; } }