def createNewTraffic(self, spawn_coords, spawn_hdg): dialog = CreateTrafficDialog(spawn_coords, spawn_hdg, parent=self.gui) dialog.exec() if dialog.result() > 0: params = dialog.acftInitParams() params.XPDR_mode = new_traffic_XPDR_mode acft = ControlledAircraft(dialog.acftCallsign(), dialog.acftType(), params, None) acft.spawned = False acft.frozen = dialog.startFrozen() acft.tickOnce() self.aircraft_list.append(acft) if dialog.createStrip(): strip = Strip() strip.writeDetail(FPL.CALLSIGN, acft.identifier) strip.writeDetail(FPL.ACFT_TYPE, acft.aircraft_type) strip.writeDetail(FPL.WTC, wake_turb_cat(acft.aircraft_type)) strip.linkAircraft(acft) signals.receiveStrip.emit(strip) selection.selectAircraft(acft)
def strip_auto_print_check(): if settings.session_manager.isRunning(): for fpl in env.FPLs.findAll(): reason_to_print = auto_print_strip_reason(fpl) if reason_to_print != None: strip = Strip() strip.linkFPL(fpl) strip.writeDetail( rack_detail, some(settings.auto_print_collecting_rack, default_rack_name)) strip.writeDetail(auto_printed_detail, True) fpl.strip_auto_printed = True env.strips.addStrip(strip) signals.stripAutoPrinted.emit(strip, reason_to_print) signals.selectionChanged.emit()
def receiveMsgFromStudent(self, msg): #DEBUG if msg.type != TeachingMsg.TRAFFIC: #DEBUG print('=== TEACHERS RECEIVES ===\n%s\n=== End ===' % msg.data) if msg.type == TeachingMsg.ATC_TEXT_CHAT: lines = msg.strData().split('\n') if len(lines) == 2: signals.incomingAtcTextMsg.emit( ChatMessage(student_callsign, lines[1], recipient=lines[0], private=True)) else: print( 'ERROR: Invalid format in received ATC text chat from student.' ) elif msg.type == TeachingMsg.STRIP_EXCHANGE: line_sep = msg.strData().split('\n', maxsplit=1) toATC = line_sep[0] strip = Strip.fromEncodedDetails( '' if len(line_sep) < 2 else line_sep[1]) strip.writeDetail(received_from_detail, student_callsign) if toATC != teacher_callsign: strip.writeDetail(sent_to_detail, toATC) signals.receiveStrip.emit(strip) elif msg.type == TeachingMsg.WEATHER: # requesting weather information if msg.strData() == settings.primary_METAR_station: self.sendWeather() elif msg.type == TeachingMsg.TRAFFIC: # acknowledging a traffic message if self.noACK_traffic_count > 0: self.noACK_traffic_count -= 1 else: print('ERROR: Student acknowledging unsent traffic?!') elif msg.type == TeachingMsg.CPDLC: # Msg format in 2 lines, first being ACFT callsign, second is either of the following: # - connect/disconnect: "0" or "1" # - data authority transfer: CPDLC_transfer_cmd_prefix + ATC callsign transferring to/from # - other: CPDLC_message_cmd_prefix + encoded message string try: acft_callsign, line2 = msg.strData().split('\n', maxsplit=1) if line2 == '0': # ACFT disconnected by student if env.cpdlc.isConnected(acft_callsign): env.cpdlc.endDataLink(acft_callsign) else: # student is rejecting a connection (unable CPDLC) QMessageBox.warning( self.gui, 'CPDLC connection failed', 'Student is not accepting CPDLC connections.') elif line2 == '1': # student confirming ACFT log-on env.cpdlc.beginDataLink(acft_callsign, student_callsign) elif line2.startswith( CPDLC_transfer_cmd_prefix ): # student transferring or confirming transfer atc = line2[len(CPDLC_transfer_cmd_prefix):] if env.cpdlc.isConnected( acft_callsign ): # student initiating transfer to next ATC env.cpdlc.endDataLink(acft_callsign, transferTo=atc) else: # student confirming proposed transfer env.cpdlc.beginDataLink(acft_callsign, student_callsign, transferFrom=atc) elif line2.startswith(CPDLC_message_cmd_prefix ): # student ATC sent a message encoded_msg = line2[len(CPDLC_message_cmd_prefix):] link = env.cpdlc.currentDataLink(acft_callsign) if link == None: print( 'Ignored CPDLC message sent to %s while not connected.' % acft_callsign) else: link.appendMessage( CpdlcMessage.fromText(False, encoded_msg)) else: print('Error decoding CPDLC command from student:', line2) except (IndexError, ValueError): print('Error decoding CPDLC message value from student') else: print('ERROR: Unhandled message type from student: %s' % msg.type)
def run(self): ## PREPARING QUERY pos = env.radarPos() qdict = { 'username': settings.MP_social_name, 'lon': pos.lon, 'lat': pos.lat, 'range': some(settings.ORSX_handover_range, settings.radar_range), 'xmlVersion': '1.0', 'contacts': ','.join( acft.identifier for acft in env.radar.contacts()) # should this be all FGMS connections? } if settings.publicised_frequency != None: qdict['frequency'] = str(settings.publicised_frequency) server_response = server_query('getFlightplans', qdict) ## USING RESPONSE if server_response != None: try: ww_root = ElementTree.fromstring(server_response) except ElementTree.ParseError as parse_error: print('Parse error in SX server data: %s' % parse_error) return new_ATCs = [] # ATCs first for ww_atc in ww_root.find('atcsInRange').iter( 'atc'): # NOTE the server sends the full list each time atc = ATC(ww_atc.find('callsign').text) atc.social_name = ww_atc.find('username').text atc.position = EarthCoords(float(ww_atc.find('lat').text), float(ww_atc.find('lon').text)) ww_frq = ww_atc.find('frequency').text try: atc.frequency = CommFrequency(ww_frq) except ValueError: atc.frequency = None new_ATCs.append(atc) self.ATCs_on_last_run = new_ATCs # Then strip data (contact claims and handover) for ww_flightplan in ww_root.iter( 'flightplan' ): # NOTE the server only sends those when something changes ww_header = ww_flightplan.find('header') ww_callsign = ww_header.find('callsign').text ww_owner = ww_header.find('owner').text if ww_owner == None: if ww_callsign in self.current_contact_claims: del self.current_contact_claims[ww_callsign] else: self.current_contact_claims[ww_callsign] = ww_owner if ww_header.find( 'handover' ).text == settings.session_manager.myCallsign( ): # RECEIVE A STRIP! strip = Strip() strip.writeDetail(received_from_detail, ww_owner) strip.writeDetail( assigned_SQ_detail, ck_int(ww_header.find('squawk').text, base=8)) strip.writeDetail(assigned_altitude_detail, ww_header.find('assignedAlt').text) # Ignored from WW header above: <flags>, <assignedRunway>, <assignedRoute>, <status>, <flight> # Ignored from WW data below: <fuelTime>; used with ulterior motive: <pilot> ww_data = ww_flightplan.find('data') # ATC-pie hides a token in <pilot>, wake turb. on its left and callsign to its right # e.g. <pilot>M__ATC-pie__X-FOO</pilot> for M turb. and X-FOO strip callsign # If the token is absent, we know the strip is from OpenRadar hidden_tokens = some(ww_data.find('pilot').text, '').split(ATCpie_hidden_string, maxsplit=1) if len( hidden_tokens ) == 1: # hidden marker NOT present; previous strip editor was OpenRadar strip.writeDetail(FPL.CALLSIGN, ww_callsign) else: # recognise strip edited with ATC-pie strip.writeDetail(FPL.WTC, hidden_tokens[0]) strip.writeDetail(FPL.CALLSIGN, hidden_tokens[1]) strip.writeDetail(FPL.FLIGHT_RULES, ww_data.find('type').text) strip.writeDetail(FPL.ACFT_TYPE, ww_data.find('aircraft').text) strip.writeDetail(FPL.ICAO_DEP, ww_data.find('departure').text) strip.writeDetail(FPL.ICAO_ARR, ww_data.find('destination').text) strip.writeDetail(FPL.ROUTE, ww_data.find('route').text) strip.writeDetail(FPL.CRUISE_ALT, ww_data.find('cruisingAlt').text) spd = ck_int(ww_data.find('trueAirspeed').text) if spd != None: strip.writeDetail(FPL.TAS, Speed(spd)) strip.writeDetail(FPL.COMMENTS, ww_data.find('remarks').text) # Possibly ignored details (OpenRadar confuses FPLs and strips): DEP time, EET, alt. AD, souls [*] signals.receiveStrip.emit(strip) send_update(ww_callsign, strip) # Acknowledge strip
def generateAircraftAndStrip(self): start_angle = uniform(0, 360) start_pos = env.radarPos().moved(Heading(start_angle, True), settings.solo_CTR_range_dist) end_pos = env.radarPos().moved( Heading(start_angle + 90 + uniform(1, 179), True), settings.solo_CTR_range_dist) transit_hdg = start_pos.headingTo(end_pos) dep_ad = world_navpoint_db.findClosest(env.radarPos().moved(transit_hdg.opposite(), \ uniform(1.2 * settings.map_range, 5000)), types=[Navpoint.AD]) dest_ad = world_navpoint_db.findClosest(env.radarPos().moved(transit_hdg, \ uniform(1.2 * settings.map_range, 5000)), types=[Navpoint.AD]) if env.pointOnMap(dep_ad.coordinates) or env.pointOnMap( dest_ad.coordinates): return None, None candidate_midpoints = [p for code in settings.solo_CTR_routing_points \ for p in env.navpoints.findAll(code, types=[Navpoint.NDB, Navpoint.VOR, Navpoint.FIX]) \ if start_pos.distanceTo(p.coordinates) < start_pos.distanceTo(end_pos)] midpoint = None if candidate_midpoints == [] else choice( candidate_midpoints) FLd10 = randint(settings.solo_CTR_floor_FL // 10, settings.solo_CTR_ceiling_FL // 10) if settings.solo_CTR_semi_circular_rule == SemiCircRule.E_W and (FLd10 % 2 == 0) != (transit_hdg.magneticAngle() >= 180) \ or settings.solo_CTR_semi_circular_rule == SemiCircRule.N_S and (FLd10 % 2 == 1) != (90 <= transit_hdg.magneticAngle() < 270): FLd10 += 1 if 10 * FLd10 > settings.solo_CTR_ceiling_FL: return None, None p_alt = StdPressureAlt.fromFL(10 * FLd10) if not self.airbornePositionFullySeparated(start_pos, p_alt): return None, None acft_type = choice(self.playable_aircraft_types) hdg = start_pos.headingTo(some(midpoint, dest_ad).coordinates) params = SoloParams(Status(Status.AIRBORNE), start_pos, p_alt, hdg, cruise_speed(acft_type)) params.XPDR_code = env.nextSquawkCodeAssignment(XPDR_range_IFR_transit) new_acft = self.mkAiAcft(acft_type, params, dest_ad) dist_key = lambda atc: env.ATCs.getATC(atc).position.distanceTo( start_pos) received_from = min(env.ATCs.knownATCs(), key=dist_key) strip = Strip() strip.writeDetail(FPL.CALLSIGN, new_acft.identifier) strip.writeDetail(FPL.ACFT_TYPE, new_acft.aircraft_type) strip.writeDetail(FPL.WTC, wake_turb_cat(new_acft.aircraft_type)) strip.writeDetail(FPL.FLIGHT_RULES, 'IFR') strip.writeDetail(FPL.ICAO_DEP, dep_ad.code) strip.writeDetail(FPL.ICAO_ARR, dest_ad.code) strip.writeDetail(FPL.CRUISE_ALT, env.readStdAlt(new_acft.params.altitude)) strip.writeDetail(assigned_altitude_detail, strip.lookup(FPL.CRUISE_ALT)) strip.writeDetail(assigned_SQ_detail, new_acft.params.XPDR_code) strip.writeDetail(received_from_detail, received_from) if midpoint != None: strip.insertRouteWaypoint(midpoint) new_acft.instructions.append( Instruction(Instruction.FOLLOW_ROUTE, arg=strip.lookup(parsed_route_detail).dup())) return new_acft, strip
def generateAircraftAndStrip(self): new_acft = received_from = None is_arrival = random() >= settings.solo_ARRvsDEP_balance if is_arrival: dep_ad = choose_dep_dest_AD(True) dest_ad = env.airport_data.navpoint midpoint = local_ee_point_closest_to(dest_ad, False) # None if none found if settings.solo_role_APP: new_acft = self.new_arrival_APP(midpoint) received_from = 'CTR' elif settings.solo_role_TWR: new_acft = self.new_arrival_TWR() received_from = 'APP' elif settings.solo_role_GND: new_acft = self.new_arrival_GND() received_from = 'TWR' else: # Create a departure dep_ad = env.airport_data.navpoint dest_ad = choose_dep_dest_AD(False) midpoint = local_ee_point_closest_to(dep_ad, True) # None if none found if settings.solo_role_GND: new_acft = self.new_departure_GND(midpoint) received_from = 'DEL' elif settings.solo_role_TWR: new_acft = self.new_departure_TWR(midpoint) received_from = 'GND' elif settings.solo_role_DEP: new_acft = self.new_departure_DEP(midpoint) received_from = 'TWR' if new_acft == None: return None, None else: strip = Strip() strip.writeDetail(FPL.CALLSIGN, new_acft.identifier) strip.writeDetail(FPL.ACFT_TYPE, new_acft.aircraft_type) strip.writeDetail(FPL.WTC, wake_turb_cat(new_acft.aircraft_type)) strip.writeDetail(FPL.FLIGHT_RULES, 'IFR') strip.writeDetail(assigned_SQ_detail, new_acft.params.XPDR_code) strip.writeDetail(received_from_detail, received_from) if received_from == 'CTR': strip.writeDetail(assigned_altitude_detail, env.readStdAlt(new_acft.params.altitude)) elif received_from == 'TWR' and not settings.solo_role_GND: strip.writeDetail(assigned_altitude_detail, settings.solo_initial_climb_reading) # routing details strip.writeDetail(FPL.ICAO_DEP, dep_ad.code) strip.writeDetail(FPL.ICAO_ARR, dest_ad.code) if is_arrival and midpoint != None: # arrival with local entry point try: strip.writeDetail( FPL.ROUTE, world_routing_db.shortestRouteStr(dep_ad, midpoint) + ' ' + midpoint.code) except ValueError: strip.writeDetail(FPL.ROUTE, 'DCT %s' % midpoint.code) elif not is_arrival and midpoint != None: # departure with local exit point try: strip.writeDetail( FPL.ROUTE, midpoint.code + ' ' + world_routing_db.shortestRouteStr(midpoint, dest_ad)) except ValueError: strip.writeDetail(FPL.ROUTE, '%s DCT' % midpoint.code) return new_acft, strip
def receiveMsgFromTeacher(self, msg): #DEBUG if msg.type != TeachingMsg.TRAFFIC:# #DEBUG print('=== STUDENT RECEIVES ===\n%s\n=== End ===' % msg.data) if msg.type == TeachingMsg.ACFT_KILLED: callsign = msg.strData() if env.cpdlc.isConnected(callsign): env.cpdlc.endDataLink(callsign) for acft in pop_all(self.traffic, lambda a: a.identifier == callsign): signals.aircraftKilled.emit(acft) elif msg.type == TeachingMsg.TRAFFIC: # traffic update; contains FGMS packet fgms_packet = msg.binData() update_FgmsAircraft_list(self.traffic, fgms_packet) send_packet_to_views(fgms_packet) self.teacher.sendMessage(TeachingMsg(TeachingMsg.TRAFFIC)) elif msg.type == TeachingMsg.SIM_PAUSED: self.teacher_paused_at = now() signals.sessionPaused.emit() elif msg.type == TeachingMsg.SIM_RESUMED: pause_delay = now() - self.teacher_paused_at for acft in self.traffic: acft.moveHistoryTimesForward(pause_delay) self.teacher_paused_at = None signals.sessionResumed.emit() elif msg.type == TeachingMsg.ATC_TEXT_CHAT: lines = msg.strData().split('\n') if len(lines) == 2: signals.incomingAtcTextMsg.emit( ChatMessage(lines[0], lines[1], recipient=student_callsign, private=True)) else: print( 'ERROR: Invalid format in received ATC text chat from teacher.' ) elif msg.type == TeachingMsg.STRIP_EXCHANGE: line_sep = msg.strData().split('\n', maxsplit=1) fromATC = line_sep[0] strip = Strip.fromEncodedDetails( '' if len(line_sep) < 2 else line_sep[1]) strip.writeDetail(received_from_detail, fromATC) signals.receiveStrip.emit(strip) elif msg.type == TeachingMsg.SX_LIST: to_remove = set(env.ATCs.knownATCs()) to_remove.discard(teacher_callsign) for line in msg.strData().split('\n'): if line != '': # last line is empty lst = line.rsplit('\t', maxsplit=1) try: frq = CommFrequency(lst[1]) if len(lst) == 2 else None except ValueError: frq = None env.ATCs.updateATC(lst[0], None, None, frq) to_remove.discard(lst[0]) for atc in to_remove: env.ATCs.removeATC(atc) env.ATCs.refreshViews() elif msg.type == TeachingMsg.WEATHER: metar = msg.strData() station = metar.split(' ', maxsplit=1)[0] if station == settings.primary_METAR_station and metar != self.known_METAR: self.known_METAR = metar signals.newWeather.emit(station, Weather(metar)) elif msg.type == TeachingMsg.PTT: # msg format: "b acft" where b is '1' or '0' for PTT on/off; acft is caller's identifier line_sep = msg.strData().split(' ', maxsplit=1) try: ptt = bool(int(line_sep[0])) caller = next(acft for acft in self.getAircraft() if acft.identifier == line_sep[1]) if ptt: env.rdf.receiveSignal(caller.identifier, lambda acft=caller: acft.coords()) else: env.rdf.dieSignal(caller.identifier) except StopIteration: print('Ignored PTT message from teacher (unknown ACFT %s).' % line_sep[1]) except (ValueError, IndexError): print('Error decoding PTT message value from teacher') elif msg.type == TeachingMsg.CPDLC: try: acft_callsign, line2 = msg.strData().split('\n', maxsplit=1) if line2 == '0': # ACFT is disconnecting env.cpdlc.endDataLink(acft_callsign) elif line2 == '1': # ACFT is connecting (CAUTION: teacher needs confirmation of accepted connection) if settings.controller_pilot_data_link: env.cpdlc.beginDataLink(acft_callsign, student_callsign) self.teacher.sendMessage( TeachingMsg( TeachingMsg.CPDLC, data=('%s\n%d' % (acft_callsign, settings.controller_pilot_data_link)))) elif line2.startswith(CPDLC_transfer_cmd_prefix ): # ACFT being transferred to me if settings.controller_pilot_data_link: # CAUTION: teacher needs confirmation of accepted connection xfr_auth = line2[len(CPDLC_transfer_cmd_prefix):] env.cpdlc.beginDataLink(acft_callsign, student_callsign, transferFrom=xfr_auth) self.teacher.sendMessage(TeachingMsg(TeachingMsg.CPDLC, \ data=('%s\n%s%s' % (acft_callsign, CPDLC_transfer_cmd_prefix, xfr_auth)))) else: self.teacher.sendMessage( TeachingMsg(TeachingMsg.CPDLC, data=('%s\n0' % acft_callsign))) elif line2.startswith( CPDLC_message_cmd_prefix): # ACFT sending a message encoded_msg = line2[len(CPDLC_message_cmd_prefix):] link = env.cpdlc.currentDataLink(acft_callsign) if link == None: print( 'Ignored CPDLC message sent from %s while not connected.' % acft_callsign) else: link.appendMessage( CpdlcMessage.fromText(False, encoded_msg)) else: print('Error decoding CPDLC command from teacher:', line2) except (IndexError, ValueError): print('Error decoding CPDLC message value from teacher') else: print('Unhandled message type from teacher: %s' % msg.type)
def new_strip_dialog(parent_widget, rack, linkToSelection=False): ''' Returns the created strip if operation not aborted ''' new_strip = Strip() new_strip.writeDetail(rack_detail, rack) if linkToSelection: new_strip.linkAircraft(selection.acft) if settings.strip_autofill_on_ACFT_link: new_strip.fillFromXPDR() new_strip.linkFPL(selection.fpl) dialog = StripDetailSheetDialog(parent_widget, new_strip) dialog.exec() if dialog.result() > 0: # not rejected new_strip.writeDetail(rack_detail, dialog.selectedRack()) env.strips.addStrip(new_strip) selection.selectStrip(new_strip) return new_strip else: return None