# Script to automatically Simulate Dispatched trains # # Author: Bill Fitch, copyright 2020 # Part of the JMRI distribution trains_being_simulated = java.util.concurrent.CopyOnWriteArrayList() # list of trains actively being simulated auto_trains_list = java.util.concurrent.CopyOnWriteArrayList() active_trains_list = java.util.concurrent.CopyOnWriteArrayList() active_train_name_list = java.util.concurrent.CopyOnWriteArrayList() removetrain = {} # dictionary of pairs [train, boolean value] the value will be set to true if we want to delete the train from auto_trains_list class SimulationMaster(jmri.jmrit.automat.AbstractAutomaton): def __init__(self): self.logLevel = 0 def setup(self): if self.logLevel > 0: print "starting SimulationMaster setup" self.simulation_master_sensor = sensors.getSensor("simulateSensor") # #get dictionary of buttons self.button_dict # self.get_buttons() # #set all move_to buttons inactive # for sensor in self.button_sensors: # sensor.setKnownState(INACTIVE) # #store the values in a clone # #self.store_button_states() # # #at moment there are no trains so: # self.button_sensors_to_watch = self.button_sensors # if self.logLevel > 0: print "self.button_sensors_to_watch_init", [str(sensor.getUserName()) for sensor in self.button_sensors_to_watch] # self.sensor_active = None if self.logLevel > 0: print "finished SimulationMaster setup" #self.testRoutines() return True def testRoutines(self): if self.logLevel > 0: print "locations" def handle(self): self.waitMsec(5000) ########################################### # update the activetrainlist (trains in DispatcherFrame) # for each train in the list # if in list of trains being simulated, but the train has stopped (not in dispatch list) # remove from trains being simulated # if it is not in trains being simulated, and the train is in the dispatch list # add to trains being simulated # start simulate train thread if the train is running # get blocks on transit # get occupied blocks on transit => blocklist # call simulate train ########################################### self.waitSensorState(self.simulation_master_sensor, ACTIVE) # get list of dispatched trains # if self.logLevel > 0: print("checking dispatched trains") DF = jmri.InstanceManager.getDefault(jmri.jmrit.dispatcher.DispatcherFrame) #print "DF.getActiveTrainsList()", DF.getActiveTrainsList() if DF != None: # update the activetrainlist with all the trains currently being dispatched active_trains_list.clear() active_train_name_list.clear() for activeTrain in DF.getActiveTrainsList(): if self.logLevel > 0: print "activeTrain", activeTrain.getActiveTrainName() if activeTrain not in active_trains_list: activeTrainName = activeTrain.getActiveTrainName() active_trains_list.add(activeTrain) active_train_name_list.add(activeTrainName) # if train in trains_being simulated not being dispatched remove from list [trains_being_simulated.remove(atn) for atn in trains_being_simulated if atn not in active_train_name_list] for activeTrain in active_trains_list: activeTrainName = activeTrain.getActiveTrainName() # if train being dispatched not in train_being simulated, and train is RUNNING simulate it if activeTrainName not in trains_being_simulated: # do not want to simulate a train already being simulated while activeTrain.getModeText() != "AUTOMATIC": # will be DISPATCHED if not enough time for the throttle to start # print "activeTrain.getMode()", activeTrain.getModeText() #waiting to change to "AUTOMATIC" self.waitMsec(500) if self.logLevel > 0: print "!!!!!!activeTrainName started simulation = " , activeTrain, "activeTrainName", activeTrainName,"trains_being_simulated", [train for train in trains_being_simulated] if activeTrain.getStatus() == activeTrain.RUNNING: #only simulate if the train is running # add to trains being simulated trains_being_simulated.append(activeTrainName) if self.logLevel > 0: print "!!!!!$activeTrainName = " , activeTrainName, "trains_being_simulated", [train for train in trains_being_simulated] if self.logLevel > 0: print "active train " , activeTrain #transit = activeTrain.getTransit() # AllocatedSectionList = activeTrain.getAllocatedSectionList() startBlock = activeTrain.getStartBlock() transit = activeTrain.getTransit() DestBlockList = transit.getDestinationBlocksList(startBlock,False) for block in DestBlockList: if self.logLevel > 0: print "destblocklist", block, block.getUserName(), self.blockOccupied(block) # set up the list of occupied blocks (blocklist) # startblock is outside the transit DestBlockList contains the blocks in the transit blocklist = [] if startBlock not in DestBlockList: blocklist.append(startBlock) for block in reversed(DestBlockList) : blocklist.append(block) for block in blocklist: if self.logLevel > 0: print "occupied blocks", block, block.getUserName(), self.blockOccupied(block) # simulate the train self.simulate_train(blocklist, activeTrain, activeTrainName) if self.logLevel > 0: print "********************" if self.logLevel > 0: print "start block ",startBlock, self.blockOccupied(startBlock), " start block sequence no ", activeTrain.getStartBlockSectionSequenceNumber(), " end block sequence no ", activeTrain.getEndBlockSectionSequenceNumber() else: if self.logLevel > 0: print "attempted to simulate train ", activeTrainName, "but train not running: status" , activeTrain.getStatus() else: if self.logLevel > 0: print "No active trains12" if self.logLevel > 0: print "trains_being_simulated", trains_being_simulated else: if self.logLevel > 0: print "No active trains2" if self.logLevel > 0: print "trains_being_simulated before",trains_being_simulated return True def simulate_train(self, block_list, activeTrain, activeTrainName): simulate_instance = Simulate_instance(block_list, activeTrain, activeTrainName) instanceList.append(simulate_instance) if simulate_instance.setup(): simulate_instance.setName(activeTrainName + "_simulation") simulate_instance.start() def blockOccupied(self, block): if block.getSensor().getState() == ACTIVE: state = True else: state = True return state class Simulate_instance(jmri.jmrit.automat.AbstractAutomaton): ########################################### # repeat # take block off end or add one to start max no blocks == 2 # make_first_block_unoccupied # make_next_block_occupied # if at end return FINISHED # if not running go into wait state until running # then set next block occupied and return SUCCESS # ########################################### def __init__(self, block_list, activeTrain, activeTrainName): #global trains_being_simulated self.block_list = block_list # all the blocks in the transit self.activeTrain = activeTrain self.activeTrainName = activeTrainName self.transit = activeTrain.getTransit() self.allocatedSectionList = self.activeTrain.getAllocatedSectionList() # print "SectionList", [section.getSectionName() for section in self.allocatedSectionList] #trains_being_simulated.append(activeTrainName) self.logLevel = 0 if self.logLevel > 0: print "activeTrainName", activeTrainName if self.logLevel > 0: print 'Simulate_instance ' + activeTrainName + " " + activeTrain.getTrainName() + " " + activeTrain.getActiveTrainName() def setup(self): i = 0 index = -1 success = False for block in self.block_list: if self.logLevel > 0: print "block", block.getUserName() if block.getSensor().getState() == ACTIVE: index = i if self.logLevel > 0: print "Success occupied block is", "index",index success = True i+=1 if success == True: break if index != -1: self.start_position = index self.end_position = index if self.logLevel > 0: print "end of setup", "returning True", index return True else: if self.logLevel > 0: print "end of setup", "returning False", index return False def handle(self): global removetrain if self.number_blocks_occupied(self.block_list) > 1: # print "start occupied" self.make_first_block_unoccupied(self.block_list) response = "Success" # print "end unoccupied" else: msg = "make_next_block_occupied" if self.logLevel > 0: print "make_next_block_occupied" title = self.activeTrainName #JOptionPane.showMessageDialog(None, msg, title, JOptionPane.WARNING_MESSAGE) response = "Waiting" while response == "Waiting": response = self.make_next_block_occupied(self.block_list) if self.logLevel > 0: print "response = " , response, "name", self.activeTrainName if response == "Waiting": if self.logLevel > 0: print "waiting" # self.waitMsec(500) if response == "Success": break if self.logLevel > 0: print "end make_next_block_occupied" if response == "Finished": if self.forward_stopping_sensor_exists(self.activeTrain): # simulate the stopping sensor being activated # if we are stopping by speed profile we won't use it, but that doesn't matter forward_stopping_sensor = self.forward_stopping_sensor(self.activeTrain) forward_stopping_sensor.setKnownState(ACTIVE) self.wait_for_sensor_to_change(forward_stopping_sensor, ACTIVE) forward_stopping_sensor.setKnownState(INACTIVE) if self.logLevel > 0: print "FINISHED" # (Note train will be removed from trains_being_simulated by looking at the dispatched train list # which will have the train removed when the dispatch finishes) return False else: # self.waitMsec(1000) # msg = "click to move to next step" # title = self.activeTrainName # JOptionPane.showMessageDialog(None, msg, title, JOptionPane.WARNING_MESSAGE) # uncomment for debugging if self.logLevel > 0: print "SUCCESS" return True def number_blocks_occupied(self, block_list): return (self.end_position - self.start_position) +1 def blockOccupied(self, block): if block.getSensor().getState() == ACTIVE: state = True else: state = False return state def make_first_block_unoccupied(self, block_list): if self.logLevel > 0: print ("******make_first_block_unoccupied",self.activeTrainName, self.getPrintStatus(self.activeTrain.getStatus()), self.activeTrain.getTrainName(),"\n") if self.logLevel > 0: print "self.start_position at start", self.start_position # print "setting block ", block_list[self.start_position].getUserName() , "inactive" sensor = block_list[self.start_position].getSensor() # print "sensor", sensor.getUserName() # print "sensor state" , sensor.getState() block_list[self.start_position].getSensor().setState(INACTIVE) # print "waiting for sensor to change" self.wait_for_sensor_to_change(block_list[self.start_position].getSensor(), INACTIVE) # print "waited making block unoccupied" # print "self.start_position", self.start_position, "self.end_position", self.end_position # print "blocklist", [[str(block.getUserName()), block.getSensor().getState()] for block in self.block_list] if self.logLevel > 0: print "sensor set inactive", block_list[self.start_position].getSensor().getUserName() if self.logLevel > 0: print "Success", "Set block ", self.start_position, "inactive" self.start_position += 1 if self.logLevel > 0: print "self.start_position at end", self.start_position if self.logLevel > 0: print "**********" def wait_for_sensor_to_change(self, sensor, state): counter = 0 # while sensor.getState() != state or counter < 5: while sensor.getState() != state: self.waitMsec(100) counter += 1 while counter < 5: self.waitMsec(100) counter += 1 def make_next_block_occupied(self, block_list): if self.logLevel > 0: print "end pos at start", self.end_position title = "debug" if self.logLevel > 0: print ("******make_next_block_occupied",self.activeTrainName, self.getPrintStatus(self.activeTrain.getStatus()), self.activeTrain.getTrainName(),"\n") if self.end_position == len(block_list)-1: # Stop if at end block if self.logLevel > 0: print "finished", "end position" , self.end_position, "len(block_list)-1", len(block_list)-1 # print "self.start_position", self.start_position, "self.end_position", self.end_position ret = "Finished" else: at_last_block_in_section = self.at_last_block_in_section() # if self.logLevel > 0: print "*******" # if self.logLevel > 0: print "at_last_block_in_section", at_last_block_in_section, \ # "self.activeTrain.getStatus()", self.activeTrain.getStatus(), \ # "self.activeTrain.RUNNING", self.activeTrain.RUNNING # if next section is occupied , proceed to the last block of the current section # in otherwords, proceed to last block of current section, then check if section ahead is clear train_running = self.activeTrain.getStatus() == self.activeTrain.RUNNING if train_running == False: print "train running: ", train_running # would prefer to check if active train running, but can't because the throttle sometimes stops. if (self.signal_ahead_clear() or not at_last_block_in_section): self.end_position +=1 if self.logLevel > 0: print "end pos incremented", self.end_position # print "setting block ", block_list[self.end_position].getUserName() , "active" block_list[self.end_position].getSensor().setState(ACTIVE) self.wait_for_sensor_to_change(block_list[self.end_position].getSensor(), ACTIVE) # print "waited making block occupied" # print "self.start_position", self.start_position, "self.end_position", self.end_position # print "blocklist", [[block.getUserName(), block.getSensor().getState()] for block in self.block_list] if self.logLevel > 0: print "Success", "Set block ", self.end_position ret = "Success" else: # msg = "status is False, hence not proceeding " + str(self.activeTrain.getStatusText()) # title = self.activeTrainName # JOptionPane.showMessageDialog(None, msg, title, JOptionPane.WARNING_MESSAGE) # uncomment for debugging ret = "Waiting" # to stop an error message if self.logLevel > 0: print "end pos at end", self.end_position if self.logLevel > 0: print "sensor set active", block_list[self.end_position].getSensor().getUserName() if self.logLevel > 0: print "ret", ret # msg = "status is True, hence proceeding " + str(self.activeTrain.getStatusText()) # title = self.activeTrainName # JOptionPane.showMessageDialog(None, msg, title, JOptionPane.WARNING_MESSAGE) # uncomment for debugging return ret def current_section(self, print_flag = False): # we know the sections in the transit # we know the blocks in each section # we know the current block # we can determine the current section # current_block = self.block_list[self.end_position] # end_position is the last block occupied # sections_in_transit = [allocatedSection.getSection() for allocatedSection in allocatedSectionList] # blocks_ # allocatedSectionList = self.allocatedSectionList # current_section_list = [allocatedSection.getSection() for allocatedSection in allocatedSectionList] # if current_block in allocatedSection.getSection().getBlockList()] # print "self.end_position", self.end_position current_block = self.block_list[self.end_position] # end_position is the last block occupied # print "current_block", current_block.getUserName() train_name = self.activeTrain.getTrainName() id = "__" + train_name + ": " self.allocatedSectionList = self.activeTrain.getAllocatedSectionList() # print "*****" # print "no sections" , len(self.allocatedSectionList), "sections", [asl.getSection().getUserName() for asl in self.allocatedSectionList] iter = 1 for allocatedSection in self.allocatedSectionList: # print "iteration", iter section = allocatedSection.getSection() blocks_in_section = section.getBlockList() # print "section", section.getUserName(), "blocks in section", [block.getUserName() for block in blocks_in_section] if current_block in blocks_in_section: # print "current_block", current_block.getUserName(), "current block in section" # print id + "blocks in each section: ", [ [str(block.getUserName()) for block in allocatedSection.getSection().getBlockList()] for allocatedSection in self.allocatedSectionList] # print id + "current_block: ", current_block.getUserName() # if print_flag: print id + "current section: ", section.getUserName(), "no of blocks in section", len(blocks_in_section) return section # print "current_block", current_block.getUserName(), "current block not yet found in section", "iteration", iter iter += 1 # print "++++++" # if print_flag: print id + "could not find current section" # if print_flag: print id + "blocks in each section: ", [ [str(block.getUserName()) for block in allocatedSection.getSection().getBlockList()] for allocatedSection in self.allocatedSectionList] # if print_flag: print id + "current_block", current_block.getUserName() return None def last_block_name_in_current_section(self): if self.current_section(True) != None: blocks_in_section = self.current_section().getBlockList() last_block = blocks_in_section[-1] last_block_name = last_block.getUserName() # print "last_block_name in section", last_block_name return last_block_name def next_signal_mast(self): SignalMastManager = jmri.InstanceManager.getDefault(jmri.SignalMastManager) current_section = self.current_section() if current_section == None: return None current_section_name = current_section.getUserName() if ":" in current_section_name: next_signal_mast_name = current_section_name.split(":")[1] else: transit = self.transit sections_in_transit = [transit_section.getSection().getUserName() \ for transit_section in transit.getTransitSectionList()] if self.logLevel > 0: print "sections_in_transit", sections_in_transit next_section_index = sections_in_transit.index(current_section.getUserName()) + 1 if self.logLevel > 0: print "current_section.getUserName()", current_section.getUserName() if self.logLevel > 0: print "next_section_index", next_section_index next_section_name = sections_in_transit[next_section_index] next_signal_mast_name = next_section_name.split(":")[0] if self.logLevel > 0: print "next_signal_mast_name", next_signal_mast_name signal_mast = SignalMastManager.getSignalMast(next_signal_mast_name) return signal_mast def at_last_block_in_section(self): last_block_name = self.last_block_name_in_current_section() if self.logLevel > 0: print "last_block_name", last_block_name current_block_name = self.block_list[self.end_position].getUserName() if self.logLevel > 0: print "current_block_name", current_block_name if last_block_name == current_block_name: if self.logLevel > 0: print "at_last_block_in_section", "True" return True else: if self.logLevel > 0: print "at_last_block_in_section", "False" return False def signal_ahead_clear(self): signal_mast = self.next_signal_mast() if signal_mast != None: if self.logLevel > 0: print "signal_mast" , signal_mast.getUserName() if self.logLevel > 0: print "signal_mast.isCleared()", signal_mast.isCleared() if self.logLevel > 0: print "signal_mast.getAspect()", signal_mast.getAspect() if signal_mast.isCleared(): if self.logLevel > 0: print "clear True" else: if self.logLevel > 0: print "clear False" return signal_mast.isCleared() else: return False def getPrintStatus(self, status): if status == self.activeTrain.RUNNING: return "status = running" else: return "status = not running" def forward_stopping_sensor_exists(self, transit_name): forward_stopping_sensor = self.forward_stopping_sensor(transit_name) if forward_stopping_sensor != None: return True else: return False def forward_stopping_sensor(selfself, activeTrain): transit = activeTrain.getTransit() transit_section_list = transit.getTransitSectionList() transit_section = transit_section_list[transit.getMaxSequence()-1] section = transit_section.getSection() forward_stopping_sensor = section.getForwardStoppingSensor() return forward_stopping_sensor