def new_departure_DEP(self, goal_point): acft_type = choice( self.parkable_aircraft_types if self.parkable_aircraft_types != [] else self.playable_aircraft_types) rwy = rnd_rwy([ rwy for rwy in env.airport_data.allRunways() if rwy.use_for_departures ], lambda rwy: rwy.acceptsAcftType(acft_type)) if rwy == None: return None thr = rwy.threshold() hdg = rwy.orientation() pos = thr.moved(hdg, settings.solo_TWR_range_dist) try: # Check for separation horiz_dist = [ pos.distanceTo(acft.params.position) for acft in self.controlled_traffic if acft.isOutboundGoal() ] if time_to_fly(min(horiz_dist), cruise_speed(acft_type)) < TTF_separation: return None except ValueError: pass # No departures in the sky yet alt = GS_alt(env.elevation(thr), rwy.param_FPA, pos.distanceTo(thr)) ias = restrict_speed_under_ceiling(cruise_speed(acft_type), alt, StdPressureAlt.fromFL(100)) params = SoloParams(Status(Status.AIRBORNE), pos, alt, hdg, ias) params.XPDR_code = env.nextSquawkCodeAssignment(XPDR_range_IFR_DEP) acft = self.mkAiAcft(acft_type, params, (goal_point, None)) acft.instructions.append( Instruction(Instruction.VECTOR_ALT, arg=settings.solo_initial_climb_reading)) return acft
def sendCpdlcMsg(self, callsign, msg): link = env.cpdlc.currentDataLink(callsign) if link == None: return if msg.type() == CpdlcMessage.ACK and link.msgCount() > 0: last_msg = link.lastMsg() if not last_msg.isFromMe() and last_msg.type() == CpdlcMessage.INSTR \ and yesNo_question(self.gui, 'ACK after received INSTR', last_msg.contents(), 'Execute instruction?'): try: instr = Instruction.fromEncodedStr(last_msg.contents()) self.instructAircraftByCallsign(callsign, instr) except ValueError: # raised by Instruction.fromEncodedStr if not yesNo_question(self.gui, 'CPDLC comm error', \ 'Unable to decode instruction.', 'Send ACK and perform manually?'): return # cancel sending any message except Instruction.Error as err: # raised by TeacherSessionManager.instructAircraftByCallsign if not yesNo_question(self.gui, 'CPDLC instruction error', \ 'Unable to perform instruction: %s' % err, 'Send ACK anyway?'): return # cancel sending any message else: # no problem executing instruction selection.writeStripAssignment(instr) if self.studentConnected() and link != None: link.appendMessage(msg) self.student.sendMessage( TeachingMsg( TeachingMsg.CPDLC, data=('%s\n%s%s' % (callsign, CPDLC_message_cmd_prefix, msg.text()))))
def new_arrival_TWR(self): acft_type = choice( self.parkable_aircraft_types if self.parkable_aircraft_types != [] else self.playable_aircraft_types) ils = random() >= settings.solo_ILSvsVisual_balance rwy_ok = lambda rwy: rwy.acceptsAcftType(acft_type) and (not ils or rwy .hasILS()) rwy = rnd_rwy([ rwy for rwy in env.airport_data.allRunways() if rwy.use_for_arrivals ], rwy_ok) if rwy == None: return None dthr = rwy.threshold(dthr=True) try: furthest = max([ dthr.distanceTo(acft.params.position) for acft in self.controlled_traffic if acft.isInboundGoal() ]) dist = max( furthest + uniform(1, 2) * distance_flown(TTF_separation, cruise_speed(acft_type)), settings.solo_TWR_range_dist) except ValueError: dist = settings.solo_TWR_range_dist / 2 if dist > min(settings.solo_TWR_range_dist * 1.5, settings.radar_range - 10): return None # to protect from creating aircraft out of radar range status = Status(Status.LANDING, arg=rwy.name) if ils else Status( Status.AIRBORNE) hdg = rwy.appCourse() alt = GS_alt(env.elevation(dthr), rwy.param_FPA, max(2, dist if ils else dist - 2)) params = SoloParams(status, env.radarPos().moved(hdg.opposite(), dist), alt, hdg, touch_down_speed(acft_type)) params.XPDR_code = env.nextSquawkCodeAssignment(XPDR_range_IFR_ARR) acft = self.mkAiAcft(acft_type, params, ils) acft.instructions.append( Instruction(Instruction.EXPECT_RWY, arg=rwy.name)) if ils: acft.instructions.append(Instruction(Instruction.CLEARED_APP)) return acft
def sendInstruction_followRoute(self): strip = selection.strip if strip == None: QMessageBox.critical(self, 'Instruction error', 'No strip selected.') else: route = strip.lookup(parsed_route_detail) if route == None: QMessageBox.critical(self, 'Instruction error', 'No valid route on selected strip.') else: instr = Instruction(Instruction.FOLLOW_ROUTE, arg=route.dup()) self.sendInstruction(instr)
def sendCpdlcMsg(self, callsign, msg): link = env.cpdlc.currentDataLink(callsign) if link != None: link.appendMessage(msg) if msg.type( ) == CpdlcMessage.INSTR: # other message types ignored (unimplemented in solo) try: acft = next( a for a in self.controlled_traffic if a.identifier == callsign) # uncontrolled traffic is not in contact acft.instruct([Instruction.fromEncodedStr(msg.contents())]) # FUTURE ingest before instruct to allow exception raised or (delayed?) WILCO msg before actually executing except StopIteration: # ACFT not found or not connected print('WARNING: Aircraft %s not found.' % callsign) except Instruction.Error as err: # raised by ControlledAircraft.instruct link.appendMessage( CpdlcMessage(False, CpdlcMessage.REJECT, contents=str(err))) else: # instruction sent and already accepted link.appendMessage(CpdlcMessage(False, CpdlcMessage.ACK))
def ackButtonClicked(self): if self.data_link_model.msgCount() > 0: last_msg = self.data_link_model.lastMsg() if not last_msg.isFromMe() and last_msg.type( ) == CpdlcMessage.REQUEST: try: instr = Instruction.fromEncodedStr(last_msg.contents()) except ValueError: QMessageBox.critical( self, 'CPDLC comm error', 'Unable to decode request. Mismatching program versions?' ) else: selection.writeStripAssignment(instr) msg = CpdlcMessage(True, CpdlcMessage.INSTR, contents=instr.encodeToStr()) settings.session_manager.sendCpdlcMsg( self.data_link_model.acftCallsign(), msg) return msg = CpdlcMessage(True, CpdlcMessage.ACK) settings.session_manager.sendCpdlcMsg( self.data_link_model.acftCallsign(), msg)
def sendInstruction_interceptNav(self): heading = Heading(self.intercept_heading_edit.value(), False) self.sendInstruction(Instruction(Instruction.INTERCEPT_NAV, arg=(self.navpoint_edit.text(), heading)))
def sendInstruction_hold(self): right_turns = self.hold_turn_select.currentText() == 'right' self.sendInstruction(Instruction(Instruction.HOLD, arg=(self.navpoint_edit.text(), right_turns)))
def sendInstruction_DCT(self): self.sendInstruction(Instruction(Instruction.VECTOR_DCT, arg=self.navpoint_edit.text()))
def sendInstruction_cancelApproach(self): self.sendInstruction(Instruction(Instruction.CANCEL_APP))
def sendInstruction_clearToLand(self): self.sendInstruction(Instruction(Instruction.CLEARED_TO_LAND))
def sendInstruction_clearedApproach(self): self.sendInstruction(Instruction(Instruction.CLEARED_APP))
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 handoverInstructionTo(self, atc): try: frq = self.getATC(atc).frequency except KeyError: frq = None return Instruction(Instruction.HAND_OVER, arg=(atc, frq))
def sendInstruction_lineUp(self): self.sendInstruction(Instruction(Instruction.LINE_UP))
def sendInstruction_holdPosition(self): self.sendInstruction(Instruction(Instruction.HOLD_POSITION))
def sendInstruction_expectDepartureRunway(self): self.sendInstruction(Instruction(Instruction.EXPECT_RWY, arg=self.reportReadyRWY_select.currentText()))
def sendInstruction_sayIntentions(self): self.sendInstruction(Instruction(Instruction.SAY_INTENTIONS))
def sendInstruction_speedYourDiscretion(self): self.sendInstruction(Instruction(Instruction.CANCEL_VECTOR_SPD))
def sendInstruction_takeOff(self): self.sendInstruction(Instruction(Instruction.CLEARED_TKOF))
def sendInstruction_interceptLocaliser(self): self.sendInstruction(Instruction(Instruction.INTERCEPT_LOC))
def sendInstruction_expectArrivalRunway(self): self.sendInstruction(Instruction(Instruction.EXPECT_RWY, arg=self.expectArrRWY_select.currentText()))
def interpret_string(string): tokens = string.split() named_runways = pop_named_runways(tokens) rwy_to_expect = ' '.join(named_runways) ## Callsign recognition ialnum, alnumtk = find_tokens(is_alphanum_token, tokens, 0, False) addressee_tokens = [] for i in range(ialnum + len(alnumtk)): addressee_tokens.append(tokens.pop(0)) ## Instruction list recognised_instructions = [] # Instruction.CANCEL_APP try: try: i = tokens.index('go-around') j = i + 1 except ValueError: i = tokens.index('cancel') # cf. "cancel approach" j = i + 2 except ValueError: pass else: SR_log('RECOGNISED: cancel app', tokens) recognised_instructions.append( Instruction(Instruction.CANCEL_APP, voiceData={})) del tokens[i:j] # Instruction.EXPECT_RWY try: i = tokens.index('expect') except ValueError: pass else: # 'j' below is last index to remove once instr is recognised; runway tokens are already removed j_max = min(len(tokens), i + 3) j = next((j for j in range(i + 1, j_max) if tokens[j] not in ['ils', 'visual', 'approach']), j_max) app = next((b for t, b in [('ils', True), ('visual', False)] if t in tokens[i + 1:j + 1]), None) SR_log('RECOGNISED: rwy/app', rwy_to_expect, app, tokens) recognised_instructions.append( Instruction(Instruction.EXPECT_RWY, arg=rwy_to_expect, voiceData={'app': app})) del tokens[i:j + 1] # Instruction.VECTOR_HDG try: try: i = tokens.index('turn') except ValueError: i = tokens.index('heading') except ValueError: pass else: try: ni, ntk = find_num_tokens(tokens, i + 1) hdg = convert_num_tokens(ntk) except ValueError as err: SR_log('Please report bug with heading instruction: %s' % err, tokens) else: SR_log('RECOGNISED: hdg', hdg, tokens) recognised_instructions.append( Instruction(Instruction.VECTOR_HDG, arg=Heading(hdg, False), voiceData={})) del tokens[i:ni + len(ntk)] # Instruction.VECTOR_ALT try: ifl = tokens.index('flight-level') # "flight level" except ValueError: # try altitude th = hu = None try: ith = tokens.index('thousand') nith, thtk = find_num_tokens(tokens, ith - 1, bwd=True) del tokens[nith:ith + 1] SR_log('Tokens left after "thousand":', tokens) th = convert_num_tokens(thtk) # STYLE catch a fail here? except ValueError: pass try: ihu = tokens.index('hundred') nihu, hutk = find_num_tokens(tokens, ihu - 1, bwd=True) del tokens[nihu:ihu + 1] SR_log('Tokens left after "hundred":', tokens) hu = convert_num_tokens(hutk) # STYLE catch a fail here? except ValueError: pass if th != None or hu != None: # got altitude alt = 1000 * some(th, 0) + 100 * some(hu, 0) SR_log('RECOGNISED: alt', alt) recognised_instructions.append( Instruction(Instruction.VECTOR_ALT, arg=('%d ft' % alt), voiceData={})) else: # got FL try: nifl, fltk = find_num_tokens(tokens, ifl + 1) fl = convert_num_tokens(fltk) except ValueError as err: SR_log('Please report bug with FL instruction: %s' % err, tokens) else: SR_log('RECOGNISED: FL', fl, tokens) recognised_instructions.append( Instruction(Instruction.VECTOR_ALT, arg=('FL%03d' % fl), voiceData={})) del tokens[ifl:nifl + len(fltk)] # Instruction.VECTOR_SPD try: i = tokens.index('speed') except ValueError: pass else: if tokens[i + 1:i + 3] == ['your', 'discretion']: SR_log('RECOGNISED: cancel spd') recognised_instructions.append( Instruction(Instruction.CANCEL_VECTOR_SPD, voiceData={})) del tokens[i:i + 3] else: try: ni, ntk = find_num_tokens(tokens, i + 1) spd = convert_num_tokens(ntk) except ValueError as err: SR_log('Please report bug with speed instruction: %s' % err, tokens) else: SR_log('RECOGNISED: spd', spd, tokens) recognised_instructions.append( Instruction(Instruction.VECTOR_SPD, arg=Speed(spd), voiceData={})) del tokens[i:ni + len(ntk)] # Instruction.SQUAWK try: i = tokens.index('squawk') except ValueError: pass else: sq = [digit_tokens[tokens[k]] for k in range(i + 1, i + 5)] sq_code = 8 * 8 * 8 * sq[0] + 8 * 8 * sq[1] + 8 * sq[2] + sq[3] SR_log('RECOGNISED: sq', sq_code, tokens) recognised_instructions.append( Instruction(Instruction.SQUAWK, arg=sq_code, voiceData={})) del tokens[i:i + 5] # Instruction.HAND_OVER try: i = tokens.index('contact') except ValueError: pass else: try: atc = atc_tokens[tokens[i + 1]] except (KeyError, IndexError) as err: SR_log('Please report bug with h/o instruction: %s' % err, tokens) else: SR_log('RECOGNISED: handover', tokens) recognised_instructions.append( Instruction(Instruction.HAND_OVER, arg=(atc, None), voiceData={})) del tokens[i:i + 2] # Instruction.INTERCEPT_LOC try: iloc = tokens.index('localiser') i, tk = find_tokens('intercept'.__eq__, tokens, iloc - 1, True) except ValueError: pass else: SR_log('RECOGNISED: loc', tokens) recognised_instructions.append( Instruction(Instruction.INTERCEPT_LOC, voiceData={'rwy': rwy_to_expect})) del tokens[i:iloc + 1] # Instruction.CLEARED_APP try: try: iapp = tokens.index( 'approach' ) # WARNING "approach" also appears in CANCEL_APP, EXPECT_RWY and HAND_OVER, but should be removed by now except ValueError: iapp = tokens.index( 'ils' ) # WARNING "ils" also appears in EXPECT_RWY, but should be removed by now i, tk1_ignore = find_tokens('cleared'.__eq__, tokens, iapp - 1, True) except ValueError: pass else: app = next((b for t, b in [('ils', True), ('visual', False)] if t in tokens[i + 1:iapp + 1]), None) SR_log('RECOGNISED: app', app, tokens) recognised_instructions.append( Instruction(Instruction.CLEARED_APP, voiceData={ 'rwy': rwy_to_expect, 'app': app })) del tokens[i:iapp + 1] # Instruction.LINE_UP try: i = tokens.index('wait') except ValueError: pass else: SR_log('RECOGNISED: luw', tokens) recognised_instructions.append( Instruction(Instruction.LINE_UP, voiceData={'rwy': rwy_to_expect})) del tokens[i - 2:i + 1] # Instruction.CLEARED_TKOF try: i = tokens.index('take-off') except ValueError: pass else: SR_log('RECOGNISED: cto', tokens) recognised_instructions.append( Instruction(Instruction.CLEARED_TKOF, voiceData={'rwy': rwy_to_expect})) del tokens[i - 2:i + 1] # Instruction.CLEARED_TO_LAND try: i = tokens.index('land') except ValueError: pass else: SR_log('RECOGNISED: ctl', tokens) recognised_instructions.append( Instruction(Instruction.CLEARED_TO_LAND, voiceData={'rwy': rwy_to_expect})) del tokens[i - 2:i + 1] # Instruction.SAY_INTENTIONS try: i = tokens.index('intentions') except ValueError: pass else: SR_log('RECOGNISED: intentions?', tokens) recognised_instructions.append( Instruction(Instruction.SAY_INTENTIONS, voiceData={})) del tokens[i - 1:i + 1] # Instruction.VECTOR_DCT try: i = tokens.index('proceed') except ValueError: pass else: try: pi, ptk = find_tokens(is_navpoint_token, tokens, i + 1, False) point = convert_navpoint_tokens(ptk) except ValueError as err: SR_log('Please report bug with DCT instruction: %s' % err, tokens) else: SR_log('RECOGNISED: dct', point, tokens) recognised_instructions.append( Instruction(Instruction.VECTOR_DCT, arg=point, voiceData={})) del tokens[i:pi + len(ptk)] # Instruction.HOLD, Instruction.HOLD_POSITION try: i = tokens.index('hold') except ValueError: pass else: if i + 1 < len(tokens) and tokens[i + 1] == 'position': SR_log('RECOGNISED: hold-position', tokens) recognised_instructions.append( Instruction(Instruction.HOLD_POSITION, voiceData={})) del tokens[i:i + 2] else: try: pi, ptk = find_tokens(is_navpoint_token, tokens, i + 1, False) point = convert_navpoint_tokens(ptk) except ValueError as err: SR_log('Please report bug with hold instruction: %s' % err, tokens) else: j = pi + len(ptk) if j < len(tokens) and tokens[j] in ['left', 'right']: turns = tokens[j] == 'right' j += 2 else: turns = True SR_log('RECOGNISED: hold', point, tokens) recognised_instructions.append( Instruction(Instruction.HOLD, arg=(point, turns), voiceData={})) del tokens[i:j] return addressee_tokens, recognised_instructions