rx_int32 IOBuffer::consumeI32BE() { rx_int32 val = 0; memcpy(&val, buffer+consumed, 4); val = FromBE32(val); consumed += 4; return val; }
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 ListNavpoints(CAI302Device &device, OperationEnvironment &env) { const int count = device.ReadNavpointCount(env); if (count < 0) return false; printf("count=%u\n", count); for (int i = 0; i < count; ++i) { CAI302::Navpoint n; if (!device.ReadNavpoint(i, n, env)) return false; int32_t latitude = FromBE32(n.latitude) - 54000000; char latitude_letter = latitude >= 0 ? 'N' : 'S'; if (latitude < 0) latitude = -latitude; int32_t longitude = FromBE32(n.longitude) - 108000000; char longitude_letter = longitude >= 0 ? 'E' : 'W'; if (longitude < 0) longitude = -longitude; printf("%u: %u:%02u:%02u%c %u:%02u:%02u%c '%.*s' '%.*s'\n", i, latitude / 10000 / 60, latitude / 10000 % 60, latitude * 6 / 1000 % 60, latitude_letter, longitude / 10000 / 60, longitude / 10000 % 60, longitude * 6 / 1000 % 60, longitude_letter, StringBufferLength(n.name, ARRAY_SIZE(n.name)), n.name, StringBufferLength(n.remark, ARRAY_SIZE(n.remark)), n.remark); } return true; }
inline void SkyLinesTracking::Client::OnUserNameReceived(const UserNameResponsePacket &packet, size_t length) { if (length != sizeof(packet) + packet.name_length) return; /* the name follows the UserNameResponsePacket object */ const char *_name = (const char *)(&packet + 1); const std::string name(_name, packet.name_length); if (!ValidateUTF8(name.c_str())) return; UTF8ToWideConverter tname(name.c_str()); handler->OnUserName(FromBE32(packet.user_id), tname); }
inline void SkyLinesTracking::Client::OnWaveReceived(const WaveResponsePacket &packet, size_t length) { if (length < sizeof(packet)) return; const unsigned n = packet.wave_count; ConstBuffer<Wave> waves((const Wave *)(&packet + 1), n); if (length != sizeof(packet) + waves.size * sizeof(waves.front())) return; for (const auto &wave : waves) handler->OnWave(FromBE32(wave.time), ImportGeoPoint(wave.a), ImportGeoPoint(wave.b)); }
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.); }
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; }
static constexpr Angle ImportAngle(int32_t src) { return Angle::Degrees(int32_t(FromBE32(src)) / 1000000.); }
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; } }