def run(pkt_size, gap_ms): util.ping_test() switch = Switch(config.active_config) switch.reset_flow_table() control_client = ExpControlClient('mumu.ucsd.edu') control_client.execute('RESET') control_client.execute('SET learning False') pktgen = Pktgen(config.active_config) pktgen.low_level_start(pkt_count=50000, flow_count=50000, pkt_size=pkt_size, gap_ns=1000000*gap_ms) try: time.sleep(20) except KeyboardInterrupt: pktgen.stop_and_get_result() sys.exit(1) pktgen_result = pktgen.stop_and_get_result() pkt_in_count = control_client.execute('GET pkt_in_count') pktgen_rate = pktgen_result.sent_pkt_count / pktgen_result.running_time pkt_in_rate = pkt_in_count / pktgen_result.running_time control_client.execute('RESET') return (pktgen_rate, pkt_in_rate)
def main(): conf = config.active_config switch = Switch(conf) switch.reset_flow_table() #new_wildcard_rules() start_processes(200, 50, TOTAL_CLIENT_COUNT, 10.0, 10*1000*1000, REDIS_HOST_OF)
def new_exact_match_rules(wait_and_verify=True, reset_flow_table=True, rule_count=CLIENT_COUNT, flow_table_filter=FLOW_TABLE_FILTER, client_base_port=CLIENT_BASE_PORT): conf = config.active_config switch = Switch(conf) if reset_flow_table: switch.reset_flow_table() # From client to redis server. new_tcp_rule1 = lambda client_id: \ 'cookie=0,idle_timeout=0,hard_timeout=0,tcp,nw_tos=0x00,' + \ 'dl_vlan=0xffff,dl_vlan_pcp=0x00,dl_src=' + \ conf.dest_mac + ',dl_dst=' + conf.source_mac + ',nw_src=' + \ conf.dest_ip + ',nw_dst=' + conf.source_ip + \ ',tp_src=' + str(client_id + client_base_port) + \ ',tp_dst=' + str(REDIS_PORT) + \ ',actions=output:' + conf.source_of_port # From server back to client. new_tcp_rule2 = lambda client_id: \ 'cookie=0,idle_timeout=0,hard_timeout=0,tcp,nw_tos=0x00,' + \ 'dl_vlan=0xffff,dl_vlan_pcp=0x00,dl_src=' + \ conf.source_mac + ',dl_dst=' + conf.dest_mac + ',nw_src=' + \ conf.source_ip + ',nw_dst=' + conf.dest_ip + \ ',tp_dst=' + str(client_id + client_base_port) + \ ',tp_src=' + str(REDIS_PORT) + \ ',actions=output:' + conf.dest_of_port initial_rule_count = len(switch.dump_tables(filter_str=flow_table_filter)) for client_id in range(rule_count): # Add the rules first. for rule_f in [new_tcp_rule1, new_tcp_rule2]: proc = util.run_ssh(conf.add_rule_cmd(rule_f(client_id)), hostname=conf.ofctl_ip, verbose=True, stdout=subprocess.PIPE) if wait_and_verify or (client_id % 5 == 0): proc.wait() # Then verify if the correct number of rules have been added. if wait_and_verify and (client_id % 5 == 0 or client_id + 1 == rule_count): current_rule_count = len(switch.dump_tables(filter_str=flow_table_filter)) try: assert current_rule_count - initial_rule_count == (client_id + 1) * 2 except: print current_rule_count, initial_rule_count, client_id raise
def run(self): self.pi_setup() switch_obj = Switch(self, Water_System.push_button) switch_obj.run(Water_System.led) thread1 = threading.Thread(target=self.data_generator.monitor_data, name="thread1", args=(self.lock, ), daemon=True) thread1.start() try: while True: pass except KeyboardInterrupt: return
def new_software_table_rules(rule_count=CLIENT_COUNT, client_base_port=CLIENT_BASE_PORT): conf = config.active_config switch = Switch(conf) # Fill up TCAM try: new_exact_match_rules(rule_count=1510, client_base_port=0) except AssertionError: if len(switch.dump_tables(filter_str=FLOW_TABLE_FILTER)) < 1500: raise # Any new rules will go into the software table. new_exact_match_rules(wait_and_verify=False, reset_flow_table=False, rule_count=CLIENT_COUNT, client_base_port=client_base_port)
def configure_ht0740(self): self._log.warning('configure ht0740...') from lib.switch import Switch self._log.info('configuring switch...') self._ros._switch = Switch(Level.INFO) # since we're using the HT0740 Switch we need to turn it on to enable # the sensors that rely upon its power # self._ros._switch.enable() self._ros._switch.on()
def new_wildcard_rules(): conf = config.active_config switch = Switch(conf) switch.reset_flow_table() new_tcp_rule1 = 'cookie=0, priority=32768, idle_timeout=3600,hard_timeout=3600,tcp,in_port=' + \ conf.source_of_port + ',dl_src=' + \ conf.source_mac + ',dl_dst=' + conf.dest_mac + ',nw_src=' + \ conf.source_ip + ',nw_dst=' + conf.dest_ip + \ ',actions=output:' + conf.dest_of_port new_tcp_rule2 = 'cookie=0, priority=32768, idle_timeout=3600,hard_timeout=3600,tcp,in_port=' + \ conf.dest_of_port + ',dl_src=' + \ conf.dest_mac + ',dl_dst=' + conf.source_mac + ',nw_src=' + \ conf.dest_ip + ',nw_dst=' + conf.source_ip + \ ',actions=output:' + conf.source_of_port for rule in [new_tcp_rule1, new_tcp_rule2]: add_rule_cmd = conf.add_rule_cmd(rule) util.run_ssh(add_rule_cmd, hostname=conf.ofctl_ip, verbose=True)
def start(self): """ Ejecuta el comando y mira si tiene que ejecutarlo localmente o se tiene que ejecutar en otro host. """ tmp_exec = {'out': None, 'err': None} if self.__is_command_exist(): with Switch(self.location) as case: if case(EnumLocationExec.local): tmp_exec = self.__execute_local() elif case(EnumLocationExec.remote): tmp_exec = self.__execute_remote() return tmp_exec['out'], tmp_exec['err'], tmp_exec['code'], tmp_exec[ 'exception']
def run(flow_mod_gap_ms): util.ping_test() switch = Switch(config.active_config) switch.reset_flow_table() control_client = ExpControlClient('mumu.ucsd.edu') control_client.execute('RESET') control_client.execute('SET auto_install_rules False') control_client.execute('SET manual_install_gap_ms %s' % flow_mod_gap_ms) control_client.execute('SET manual_install_active True') # Send a starter packet to trigger packet-in. Doesn't matter what port it # goes to, as long as it has the IP address of what would have been the # pktgen host. sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.sendto('Hi', (config.active_config.source_ip, 12345)) # Let the whole system run for a while. We cannot check for TCAM status; # that'd sometimes take forever when the switch is busily processing flow- # mods, and it'd probably affect the flow-mods. We check the TCAM # afterwards. util.verbose_sleep(60) control_client.execute('SET manual_install_active False') # Gather stats about flow-mod. The flow-mod gap may not be accurate. flow_mod_count = control_client.execute('GET flow_mod_count') flow_mod_start_time = control_client.execute('GET flow_mod_start_time') flow_mod_end_time = control_client.execute('GET flow_mod_end_time') flow_mod_rate = flow_mod_count / (flow_mod_end_time - flow_mod_start_time) # Wait for the switch to stabilize before asking it for stats. util.verbose_sleep(80) print 'Dumping table...' # Parse flow tables. Search up to the last point of a TCAM-write, which # signifies a full TCAM. Up to that point, we count the total number of # rules added. rule_list = switch.dump_tables(filter_str='') tcam_rule_count = 0 total_rule_count = 0 print 'Parsing', len(rule_list), 'rules...' for rule in rule_list: total_rule_count += 1 if 'table_id=0' in rule: tcam_rule_count += 1 if tcam_rule_count == 1500: break control_client.execute('RESET') switch.reset_flow_table() util.verbose_sleep(5) return (tcam_rule_count, total_rule_count, flow_mod_rate)
def Risposta(r): risultato = r # Inizializzazione risultato clear = False # Inizializzazione variabile operators = ['×', '÷', '+', '-', '√'] # Lista degli operatori while not clear: # Finchè l'espressione non è stata analizzata tutta, allora... for operator in operators: # ... per ogni operatore della lista operators ... trovato = r.find(operator) # trova l'operatore nella stringa if trovato != -1: # Se l'operatore è stato trovato... l = r.split(operator) # Dividi la stringa in base all'operatore if operator == "-" and not l[0]: # Se l'operatore è il - e se l'elemento in prima posizione # dell'espressione è vuoto (ad esempio: -2-1 --> l = ["", "2", "1"] del l[0] # elimina quell'elemento l[0] = -float(l[0]) # trasforma il nuovo primo elemento in un float (numero decimale) negativo for p, e in enumerate(l): # Per ogni elemento (e la sua posizione) nell'espressione: if type(e) == str: # se l'elemento attuale è una stringa ... e = e.replace(",", ".") # ... sostituisci tutte le virgole con dei punti (per la trasformazione in stringa) l[p] = float(e) # Trasforma l'elemento in float with Switch(operator) as case: # Switch (controlla che l'operatore sia uguale a... if case(operators[0]): # Primo operatore nella lista (multiply) + calcolo risultato = 1 for x in l: risultato = risultato * x elif case(operators[1]): # Secondo operatore nella lista (divide) + calcolo risultato = l[0] for p, x in enumerate(l): if p == 0: continue risultato = risultato / x elif case(operators[2]): # Terzo operatore nella lista (plus) + calcolo risultato = sum(l) elif case(operators[3]): # Quarto operatore nella lista (minus) + calcolo for p, e in enumerate(l): if p != 0 and float(e) > 0: l[p] = -float(e) risultato = sum(l) elif case(operators[4]): # Quinto operatore nella lista (square root) + calcolo risultato = math.sqrt(float(l[1])) clear = True # Quando il ciclo è concluso, imposta la variabile clear a True # (l'espressione è stata analizzata) salvaInCronologia(r, risultato) # Salva nella cronologia l'espressione e il risultato return risultato
def update(self, key: str, option: str, value) -> bool: """ Actualiza alguna de las propiedades de un return que ya existe. :param key: Key del return :param option: Nombre de la opción. :param value: Nuevo valor. :return: True si todo ha ido bien y False si algo ha fallado. """ if key: with Switch(option, invariant_culture_ignore_case=True) as case: if case("status", "message", "send", "other_data"): if self.is_exist(key): self.__dict_return[key][option] = value return True else: # Opción no valida!! pass return False
def start_processes(process_count, worker_thread_per_process, client_count, gap_ms, data_length, redis_host): switch = Switch(config.active_config) data_length = int(data_length) total_workers = process_count * worker_thread_per_process redis_set(data_length) worker_status_queue = Queue(maxsize=total_workers) client_id_queue = Queue(maxsize=client_count) result_queue = Queue(maxsize=client_count) # Starts the worker processes that spawn individual worker threads. for _ in range(process_count): p = Process(target=RedisClientProcess, args=(worker_thread_per_process, data_length, redis_host, worker_status_queue, client_id_queue, result_queue)) p.daemon = True p.start() # Wait for all worker threads to start. while True: started_count = worker_status_queue.qsize() if started_count < total_workers: print total_workers - started_count, 'workers yet to start.' time.sleep(1) else: break # Send requests in a different thread. util.ping_test(dest_host=redis_host, how_many_pings=2) def requests(): for client_id in range(client_count): client_id_queue.put(client_id) time.sleep(gap_ms / 1000.0) t = threading.Thread(target=requests) t.daemon = True t.start() # Monitor the changes for the first minute. base_time = time.time() while True: current_count = result_queue.qsize() remaining_count = client_count - current_count print 'Current:', current_count, 'Remaining:', remaining_count if remaining_count > 0 and time.time() - base_time < 120: try: time.sleep(10) except KeyboardInterrupt: break if redis_host == REDIS_HOST_OF: rule_list = switch.dump_tables(filter_str='') print 't =', time.time() - base_time, print '; tcam_size =', len([rule for rule in rule_list if 'table_id=0' in rule]), print '; table_1_size =', len([rule for rule in rule_list if 'table_id=1' in rule]), print '; table_2_size =', len([rule for rule in rule_list if 'table_id=2' in rule]), print '; total_size =', len([rule for rule in rule_list if 'cookie' in rule]) else: break # Extract the result into local lists. All time values are expressed in ms. # We're only interested in results between 30-60 seconds. print 'Analyzing the result...' start_time_list = [] completion_time_list = [] while not result_queue.empty(): (_, start_time, end_time) = result_queue.get() if start_time - base_time >= 60: start_time_list.append(start_time * 1000.0) if end_time is None: completion_time = -100.0 # Not to be plotted. else: completion_time = (end_time - start_time) * 1000.0 completion_time_list.append(completion_time) # Calculate the actual request gap. start_time_list.sort() gap_list = [] for index in range(0, len(start_time_list) - 1): gap_list.append(start_time_list[index + 1] - start_time_list[index]) print 'Client gap: (mean, stdev) =', util.get_mean_and_stdev(gap_list) # Calculate the CDF of completion times. cdf_list = util.make_cdf(completion_time_list) with open('data/realistic_redis_completion_times.txt', 'w') as f: for (x, y) in zip(completion_time_list, cdf_list): print >> f, x, y
def resetIdleCountdown(): settings.lastMotionEndTime = None def onMotionSwitchChange(value): if (value): light.switchOn() resetIdleCountdown() if (app.is_running == False): app.start() print("Started") else: light.switchOff() settings.lastMotionEndTime = time.time() Switch(15, onMotionSwitchChange) while True: if (is_idle()): idle = calcSecondsIdle() print(idle) if (idle >= settings.maxIdleSeconds): resetIdleCountdown() app.stop() print("Stopped") time.sleep(1) GPIO.cleanup()
def run(packet_per_second=100, pkt_size=1500, run_time=220): """ Returns (pktgen_pps, pkt_in_pps, flow_mod_pps, flow_mod_pps_stdev, pkt_out_pps), where pps_in is the actual number of packets/sec of pktgen, and flow_mod_pps and flow_mod_pps_stdev are the mean and stdev pps of successful flow installations at steady state. """ util.ping_test() switch = Switch(config.active_config) switch.reset_flow_table() # Initialize the experimental controller so that POX would have the # necessary settings. control_client = ExpControlClient('mumu.ucsd.edu') control_client.execute(['RESET']) control_client.execute(['SET', 'flow_stat_interval', 20]) control_client.execute(['SET', 'install_bogus_rules', True]) control_client.execute(['SET', 'emulate_hp_switch', True]) # Start capturing packets. tcpdump = Tcpdump(config.active_config) tcpdump.start() tcpdump_start_time = time.time() # Start firing packets. pktgen = Pktgen(config.active_config) gap = 1.0 / packet_per_second pkt_count = int(run_time * packet_per_second) pktgen.low_level_start(pkt_count=pkt_count, pkt_size=pkt_size, gap_ns=gap*1000*1000*1000, flow_count=1) pktgen_start_time = time.time() flow_mod_pps_list = [] # How fast were rules successfully written into the hardware table? We take # statistics at steady state. Also display flow statistics once in a while. last_stat_time = [0] def callback(t_left): flow_stat_dict = control_client.execute(['GET', 'flow_count_dict']) for stat_time in sorted(flow_stat_dict.keys()): if stat_time > last_stat_time[0]: last_stat_time[0] = stat_time flow_count = flow_stat_dict[stat_time] print t_left, 'seconds left, with flows', flow_count if pktgen_start_time + 60 <= time.time() <= pktgen_start_time + 180: flow_mod_pps_list.append(flow_count / 10.0) # Check the stat every 20 seconds. util.callback_sleep(run_time, callback, interval=20) # How fast were packets actually generated? pktgen_result = pktgen.stop_and_get_result() pktgen_pps = pktgen_result.sent_pkt_count / pktgen_result.running_time # How fast were pkt_out events? tcpdump_end_time = time.time() tcpdump_result = tcpdump.stop_and_get_result() pkt_out_pps = (tcpdump_result.dropped_pkt_count + tcpdump_result.recvd_pkt_count) / \ (tcpdump_end_time - tcpdump_start_time) # Calculate the mean and stdev of successful flow_mod pps. (flow_mod_pps, flow_mod_pps_stdev) = util.get_mean_and_stdev(flow_mod_pps_list) # How fast were pkt_in events arriving? pkt_in_count = control_client.execute(['GET', 'pkt_in_count']) pkt_in_start_time = control_client.execute(['GET', 'pkt_in_start_time']) pkt_in_end_time = control_client.execute(['GET', 'pkt_in_end_time']) pkt_in_pps = pkt_in_count / (pkt_in_end_time - pkt_in_start_time) return (pktgen_pps, pkt_in_pps, flow_mod_pps, flow_mod_pps_stdev, pkt_out_pps)
class ROS(AbstractTask): ''' Extends AbstractTask as a Finite State Machine (FSM) basis of a Robot Operating System (ROS) or behaviour-based system (BBS), including spawning the various tasks and an Arbitrator as separate threads, inter-communicating over a common message queue. This establishes a message queue, an Arbitrator and a Controller, as well as an optional RESTful flask-based web service. The message queue receives Event-containing messages, which are passed on to the Arbitrator, whose job it is to determine the highest priority action to execute for that task cycle. Example usage: try: _ros = ROS() _ros.start() except Exception: _ros.close() There is also a rosd linux daemon, which can be used to start, enable and disable ros (actually via its Arbitrator). ''' # .......................................................................... def __init__(self): ''' This initialises the ROS and calls the YAML configurer. ''' self._queue = MessageQueue(Level.INFO) self._mutex = threading.Lock() super().__init__("ros", self._queue, None, None, self._mutex) self._log.info('initialising...') self._active = False self._closing = False self._disable_leds = False # self._switch = None self._motors = None self._arbitrator = None self._controller = None self._gamepad = None self._features = [] # self._flask_wrapper = None # read YAML configuration _loader = ConfigLoader(Level.INFO) filename = 'config.yaml' self._config = _loader.configure(filename) self._gamepad_enabled = self._config['ros'].get('gamepad').get( 'enabled') self._log.info('initialised.') self._configure() # .......................................................................... def _configure(self): ''' Configures ROS based on both KR01 standard hardware as well as optional features, the latter based on devices showing up (by address) on the I²C bus. Optional devices are only enabled at startup time via registration of their feature availability. ''' scanner = I2CScanner(Level.WARN) self._addresses = scanner.getAddresses() hexAddresses = scanner.getHexAddresses() self._addrDict = dict( list(map(lambda x, y: (x, y), self._addresses, hexAddresses))) for i in range(len(self._addresses)): self._log.debug( Fore.BLACK + Style.DIM + 'found device at address: {}'.format(hexAddresses[i]) + Style.RESET_ALL) self._log.info('configure default features...') # standard devices ........................................... self._log.info('configuring integrated front sensors...') self._ifs = IntegratedFrontSensor(self._config, self._queue, Level.INFO) self._log.info('configure ht0740 switch...') self._switch = Switch(Level.INFO) # since we're using the HT0740 Switch, turn it on to enable sensors that rely upon its power # self._switch.enable() self._switch.on() self._log.info('configuring button...') self._button = Button(self._config, self.get_message_queue(), self._mutex) self._log.info('configure battery check...') _battery_check = BatteryCheck(self._config, self.get_message_queue(), Level.INFO) self.add_feature(_battery_check) self._log.info('configure CPU temperature check...') _temperature_check = Temperature(self._config, self._queue, Level.INFO) self.add_feature(_temperature_check) ultraborg_available = (0x36 in self._addresses) if ultraborg_available: self._log.debug(Fore.CYAN + Style.BRIGHT + '-- UltraBorg available at 0x36.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + '-- no UltraBorg available at 0x36.' + Style.RESET_ALL) self._set_feature_available('ultraborg', ultraborg_available) thunderborg_available = (0x15 in self._addresses) if thunderborg_available: # then configure motors self._log.debug(Fore.CYAN + Style.BRIGHT + '-- ThunderBorg available at 0x15' + Style.RESET_ALL) _motor_configurer = MotorConfigurer(self, self._config, Level.INFO) self._motors = _motor_configurer.configure() else: self._log.debug(Fore.RED + Style.BRIGHT + '-- no ThunderBorg available at 0x15.' + Style.RESET_ALL) self._set_feature_available('thunderborg', thunderborg_available) # optional devices ........................................... # the 5x5 RGB Matrix is at 0x74 for port, 0x77 for starboard rgbmatrix5x5_stbd_available = (0x74 in self._addresses) if rgbmatrix5x5_stbd_available: self._log.debug(Fore.CYAN + Style.BRIGHT + '-- RGB Matrix available at 0x74.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + '-- no RGB Matrix available at 0x74.' + Style.RESET_ALL) self._set_feature_available('rgbmatrix5x5_stbd', rgbmatrix5x5_stbd_available) rgbmatrix5x5_port_available = (0x77 in self._addresses) if rgbmatrix5x5_port_available: self._log.debug(Fore.CYAN + Style.BRIGHT + '-- RGB Matrix available at 0x77.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + '-- no RGB Matrix available at 0x77.' + Style.RESET_ALL) self._set_feature_available('rgbmatrix5x5_port', rgbmatrix5x5_port_available) if rgbmatrix5x5_stbd_available or rgbmatrix5x5_port_available: self._log.info('configure rgbmatrix...') self._rgbmatrix = RgbMatrix(Level.INFO) self.add_feature(self._rgbmatrix) # FIXME this is added twice # ............................................ # the 11x7 LED matrix is at 0x75 for starboard, 0x77 for port. The latter # conflicts with the RGB LED matrix, so both cannot be used simultaneously. matrix11x7_stbd_available = (0x75 in self._addresses) if matrix11x7_stbd_available: self._log.debug(Fore.CYAN + Style.BRIGHT + '-- 11x7 Matrix LEDs available at 0x75.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + '-- no 11x7 Matrix LEDs available at 0x75.' + Style.RESET_ALL) self._set_feature_available('matrix11x7_stbd', matrix11x7_stbd_available) # device availability ........................................ bno055_available = (0x28 in self._addresses) if bno055_available: self._log.info('configuring BNO055 9DoF sensor...') self._bno055 = BNO055(self._config, self.get_message_queue(), Level.INFO) else: self._log.debug(Fore.RED + Style.BRIGHT + 'no BNO055 orientation sensor available at 0x28.' + Style.RESET_ALL) self._set_feature_available('bno055', bno055_available) # NOTE: the default address for the ICM20948 is 0x68, but this conflicts with the PiJuice icm20948_available = (0x69 in self._addresses) if icm20948_available: self._log.debug(Fore.CYAN + Style.BRIGHT + 'ICM20948 available at 0x69.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + 'no ICM20948 available at 0x69.' + Style.RESET_ALL) self._set_feature_available('icm20948', icm20948_available) lsm303d_available = (0x1D in self._addresses) if lsm303d_available: self._log.debug(Fore.CYAN + Style.BRIGHT + 'LSM303D available at 0x1D.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + 'no LSM303D available at 0x1D.' + Style.RESET_ALL) self._set_feature_available('lsm303d', lsm303d_available) vl53l1x_available = (0x29 in self._addresses) if vl53l1x_available: self._log.debug(Fore.CYAN + Style.BRIGHT + 'VL53L1X available at 0x29.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + 'no VL53L1X available at 0x29.' + Style.RESET_ALL) self._set_feature_available('vl53l1x', vl53l1x_available) as7262_available = (0x49 in self._addresses) if as7262_available: self._log.debug(Fore.CYAN + Style.BRIGHT + '-- AS7262 Spectrometer available at 0x49.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + '-- no AS7262 Spectrometer available at 0x49.' + Style.RESET_ALL) self._set_feature_available('as7262', as7262_available) pijuice_available = (0x68 in self._addresses) if pijuice_available: self._log.debug(Fore.CYAN + Style.BRIGHT + 'PiJuice hat available at 0x68.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + 'no PiJuice hat available at 0x68.' + Style.RESET_ALL) self._set_feature_available('pijuice', pijuice_available) self._log.info('configured.') # .......................................................................... def summation(): ''' Displays unaccounted I2C addresses. This is currently non-functional, as we don't remove a device from the list when its address is found. ''' self._log.info(Fore.YELLOW + '-- unaccounted for self._addresses:') for i in range(len(self._addresses)): hexAddr = self._addrDict.get(self._addresses[i]) self._log.info(Fore.YELLOW + Style.BRIGHT + '-- address: {}'.format(hexAddr) + Style.RESET_ALL) # .......................................................................... def _set_feature_available(self, name, value): ''' Sets a feature's availability to the boolean value. ''' self._log.debug(Fore.BLUE + Style.BRIGHT + '-- set feature available. name: \'{}\' value: \'{}\'.' .format(name, value)) self.set_property('features', name, value) # .......................................................................... def get_message_queue(self): return self._queue # .......................................................................... def get_controller(self): return self._controller # .......................................................................... def get_configuration(self): return self._config # .......................................................................... def get_property(self, section, property_name): ''' Return the value of the named property of the application configuration, provided its section and property name. ''' return self._config[section].get(property_name) # .......................................................................... def set_property(self, section, property_name, property_value): ''' Set the value of the named property of the application configuration, provided its section, property name and value. ''' self._log.debug( Fore.GREEN + 'set config on section \'{}\' for property key: \'{}\' to value: {}.' .format(section, property_name, property_value)) if section == 'ros': self._config[section].update(property_name=property_value) else: _ros = self._config['ros'] _ros[section].update(property_name=property_value) # .......................................................................... def _set_pi_leds(self, enable): ''' Enables or disables the Raspberry Pi's board LEDs. ''' sudo_name = self.get_property('pi', 'sudo_name') led_0_path = self._config['pi'].get('led_0_path') led_1_path = self._config['pi'].get('led_1_path') if enable: self._log.info('re-enabling LEDs...') os.system('echo 1 | {} tee {}'.format(sudo_name, led_0_path)) os.system('echo 1 | {} tee {}'.format(sudo_name, led_1_path)) else: self._log.debug('disabling LEDs...') os.system('echo 0 | {} tee {}'.format(sudo_name, led_0_path)) os.system('echo 0 | {} tee {}'.format(sudo_name, led_1_path)) # .......................................................................... def _connect_gamepad(self): if not self._gamepad_enabled: self._log.info('gamepad disabled.') return if self._gamepad is None: self._log.info('creating gamepad...') try: self._gamepad = Gamepad(self._config, self._queue, Level.INFO) except GamepadConnectException as e: self._log.error('unable to connect to gamepad: {}'.format(e)) self._gamepad = None self._gamepad_enabled = False self._log.info('gamepad unavailable.') return if self._gamepad is not None: self._log.info('enabling gamepad...') self._gamepad.enable() _count = 0 while not self._gamepad.has_connection(): _count += 1 if _count == 1: self._log.info('connecting to gamepad...') else: self._log.info( 'gamepad not connected; re-trying... [{:d}]'.format( _count)) self._gamepad.connect() time.sleep(0.5) if self._gamepad.has_connection() or _count > 5: break # .......................................................................... def has_connected_gamepad(self): return self._gamepad is not None and self._gamepad.has_connection() # .......................................................................... def get_arbitrator(self): return self._arbitrator # .......................................................................... def add_feature(self, feature): ''' Add the feature to the list of features. Features must have an enable() method. ''' self._features.append(feature) self._log.info('added feature {}.'.format(feature.name())) # .......................................................................... def _callback_shutdown(self): _enable_self_shutdown = self._config['ros'].get('enable_self_shutdown') if _enable_self_shutdown: self._log.critical('callback: shutting down os...') self.close() sys.exit(0) else: self._log.critical('self-shutdown disabled.') # .......................................................................... def run(self): ''' This first disables the Pi's status LEDs, establishes the message queue arbitrator, the controller, enables the set of features, then starts the main OS loop. ''' super(AbstractTask, self).run() loop_count = 0 # display banner! _banner = '\n' \ 'ros\n' \ 'ros █▒▒▒▒▒▒▒ █▒▒▒▒▒▒ █▒▒▒▒▒▒ █▒▒ \n' \ + 'ros █▒▒ █▒▒ █▒▒ █▒▒ █▒▒ █▒▒ \n' \ + 'ros █▒▒▒▒▒▒ █▒▒ █▒▒ █▒▒▒▒▒▒ █▒▒ \n' \ + 'ros █▒▒ █▒▒ █▒▒ █▒▒ █▒▒ \n' \ + 'ros █▒▒ █▒▒ █▒▒▒▒▒▒ █▒▒▒▒▒▒ █▒▒ \n' \ + 'ros\n' self._log.info(_banner) self._disable_leds = self._config['pi'].get('disable_leds') if self._disable_leds: # disable Pi LEDs since they may be distracting self._set_pi_leds(False) self._log.info('enabling features...') for feature in self._features: self._log.info('enabling feature {}...'.format(feature.name())) feature.enable() # __enable_player = self._config['ros'].get('enable_player') # if __enable_player: # self._log.info('configuring sound player...') # self._player = Player(Level.INFO) # else: # self._player = None # i2c_slave_address = config['ros'].get('i2c_master').get('device_id') # i2c hex address of I2C slave device vl53l1x_available = True # self.get_property('features', 'vl53l1x') ultraborg_available = True # self.get_property('features', 'ultraborg') if vl53l1x_available and ultraborg_available: self._log.critical('starting scanner tool...') self._lidar = Lidar(self._config, Level.INFO) self._lidar.enable() else: self._log.critical( 'lidar scanner tool does not have necessary dependencies.') # wait to stabilise features? # configure the Controller and Arbitrator self._log.info('configuring controller...') self._controller = Controller(self._config, self._ifs, self._motors, self._callback_shutdown, Level.INFO) self._log.info('configuring arbitrator...') self._arbitrator = Arbitrator(self._config, self._queue, self._controller, Level.WARN) _flask_enabled = self._config['flask'].get('enabled') if _flask_enabled: self._log.info('starting flask web server...') self.configure_web_server() else: self._log.info( 'not starting flask web server (suppressed from command line).' ) # bluetooth gamepad controller if self._gamepad_enabled: self._connect_gamepad() self._log.warning('Press Ctrl-C to exit.') _wait_for_button_press = self._config['ros'].get( 'wait_for_button_press') self._controller.set_standby(_wait_for_button_press) # begin main loop .............................. self._log.info('starting button thread...') self._button.start() # self._log.info('enabling bno055 sensor...') # self._bno055.enable() # self._bumpers.enable() self._indicator = Indicator(Level.INFO) # add indicator as message consumer self._queue.add_consumer(self._indicator) self._log.info(Fore.MAGENTA + 'enabling integrated front sensor...') self._ifs.enable() # self._log.info('starting info thread...') # self._info.start() # self._log.info('starting blinky thread...') # self._rgbmatrix.enable(DisplayType.RANDOM) # enable arbitrator tasks (normal functioning of robot) main_loop_delay_ms = self._config['ros'].get('main_loop_delay_ms') self._log.info( 'begin main os loop with {:d}ms delay.'.format(main_loop_delay_ms)) _loop_delay_sec = main_loop_delay_ms / 1000 _main_loop_count = 0 self._arbitrator.start() self._active = True while self._active: # The sensors and the flask service sends messages to the message queue, # which forwards those messages on to the arbitrator, which chooses the # highest priority message to send on to the controller. So the timing # of this loop is inconsequential; it exists solely as a keep-alive. _main_loop_count += 1 self._log.debug(Fore.BLACK + Style.DIM + '[{:d}] main loop...'.format(_main_loop_count)) time.sleep(_loop_delay_sec) # end application loop ......................... if not self._closing: self._log.warning('closing following loop...') self.close() # end main ................................... # .......................................................................... def configure_web_server(self): ''' Start flask web server. ''' try: self._mutex.acquire() self._log.info('starting web service...') self._flask_wrapper = FlaskWrapperService(self._queue, self._controller) self._flask_wrapper.start() except KeyboardInterrupt: self._log.error('caught Ctrl-C interrupt.') finally: self._mutex.release() time.sleep(1) self._log.info(Fore.BLUE + 'web service started.' + Style.RESET_ALL) # .......................................................................... def emergency_stop(self): ''' Stop immediately, something has hit the top feelers. ''' self._motors.stop() self._log.info(Fore.RED + Style.BRIGHT + 'emergency stop: contact on upper feelers.') # .......................................................................... def send_message(self, message): ''' Send the Message into the MessageQueue. ''' self._queue.add(message) # .......................................................................... def enable(self): super(AbstractTask, self).enable() # .......................................................................... def disable(self): super(AbstractTask, self).disable() # .......................................................................... def close(self): ''' This sets the ROS back to normal following a session. ''' if self._closing: # this also gets called by the arbitrator so we ignore that self._log.info('already closing.') return else: self._active = False self._closing = True self._log.info(Style.BRIGHT + 'closing...') if self._gamepad: self._gamepad.close() if self._motors: self._motors.close() if self._ifs: self._ifs.close() # close features for feature in self._features: self._log.info('closing feature {}...'.format(feature.name())) feature.close() self._log.info('finished closing features.') if self._arbitrator: self._arbitrator.disable() self._arbitrator.close() # self._arbitrator.join(timeout=1.0) if self._controller: self._controller.disable() # if self._flask_wrapper is not None: # self._flask_wrapper.close() super().close() # self._info.close() # self._rgbmatrix.close() # if self._switch: # self._switch.close() # super(AbstractTask, self).close() if self._disable_leds: # restore LEDs self._set_pi_leds(True) # GPIO.cleanup() # self._log.info('joining main thread...') # self.join(timeout=0.5) self._log.info('os closed.') sys.stderr = DevNull() sys.exit(0)
def _configure(self): ''' Configures ROS based on both KR01 standard hardware as well as optional features, the latter based on devices showing up (by address) on the I²C bus. Optional devices are only enabled at startup time via registration of their feature availability. ''' scanner = I2CScanner(Level.WARN) self._addresses = scanner.getAddresses() hexAddresses = scanner.getHexAddresses() self._addrDict = dict( list(map(lambda x, y: (x, y), self._addresses, hexAddresses))) for i in range(len(self._addresses)): self._log.debug( Fore.BLACK + Style.DIM + 'found device at address: {}'.format(hexAddresses[i]) + Style.RESET_ALL) self._log.info('configure default features...') # standard devices ........................................... self._log.info('configuring integrated front sensors...') self._ifs = IntegratedFrontSensor(self._config, self._queue, Level.INFO) self._log.info('configure ht0740 switch...') self._switch = Switch(Level.INFO) # since we're using the HT0740 Switch, turn it on to enable sensors that rely upon its power # self._switch.enable() self._switch.on() self._log.info('configuring button...') self._button = Button(self._config, self.get_message_queue(), self._mutex) self._log.info('configure battery check...') _battery_check = BatteryCheck(self._config, self.get_message_queue(), Level.INFO) self.add_feature(_battery_check) self._log.info('configure CPU temperature check...') _temperature_check = Temperature(self._config, self._queue, Level.INFO) self.add_feature(_temperature_check) ultraborg_available = (0x36 in self._addresses) if ultraborg_available: self._log.debug(Fore.CYAN + Style.BRIGHT + '-- UltraBorg available at 0x36.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + '-- no UltraBorg available at 0x36.' + Style.RESET_ALL) self._set_feature_available('ultraborg', ultraborg_available) thunderborg_available = (0x15 in self._addresses) if thunderborg_available: # then configure motors self._log.debug(Fore.CYAN + Style.BRIGHT + '-- ThunderBorg available at 0x15' + Style.RESET_ALL) _motor_configurer = MotorConfigurer(self, self._config, Level.INFO) self._motors = _motor_configurer.configure() else: self._log.debug(Fore.RED + Style.BRIGHT + '-- no ThunderBorg available at 0x15.' + Style.RESET_ALL) self._set_feature_available('thunderborg', thunderborg_available) # optional devices ........................................... # the 5x5 RGB Matrix is at 0x74 for port, 0x77 for starboard rgbmatrix5x5_stbd_available = (0x74 in self._addresses) if rgbmatrix5x5_stbd_available: self._log.debug(Fore.CYAN + Style.BRIGHT + '-- RGB Matrix available at 0x74.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + '-- no RGB Matrix available at 0x74.' + Style.RESET_ALL) self._set_feature_available('rgbmatrix5x5_stbd', rgbmatrix5x5_stbd_available) rgbmatrix5x5_port_available = (0x77 in self._addresses) if rgbmatrix5x5_port_available: self._log.debug(Fore.CYAN + Style.BRIGHT + '-- RGB Matrix available at 0x77.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + '-- no RGB Matrix available at 0x77.' + Style.RESET_ALL) self._set_feature_available('rgbmatrix5x5_port', rgbmatrix5x5_port_available) if rgbmatrix5x5_stbd_available or rgbmatrix5x5_port_available: self._log.info('configure rgbmatrix...') self._rgbmatrix = RgbMatrix(Level.INFO) self.add_feature(self._rgbmatrix) # FIXME this is added twice # ............................................ # the 11x7 LED matrix is at 0x75 for starboard, 0x77 for port. The latter # conflicts with the RGB LED matrix, so both cannot be used simultaneously. matrix11x7_stbd_available = (0x75 in self._addresses) if matrix11x7_stbd_available: self._log.debug(Fore.CYAN + Style.BRIGHT + '-- 11x7 Matrix LEDs available at 0x75.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + '-- no 11x7 Matrix LEDs available at 0x75.' + Style.RESET_ALL) self._set_feature_available('matrix11x7_stbd', matrix11x7_stbd_available) # device availability ........................................ bno055_available = (0x28 in self._addresses) if bno055_available: self._log.info('configuring BNO055 9DoF sensor...') self._bno055 = BNO055(self._config, self.get_message_queue(), Level.INFO) else: self._log.debug(Fore.RED + Style.BRIGHT + 'no BNO055 orientation sensor available at 0x28.' + Style.RESET_ALL) self._set_feature_available('bno055', bno055_available) # NOTE: the default address for the ICM20948 is 0x68, but this conflicts with the PiJuice icm20948_available = (0x69 in self._addresses) if icm20948_available: self._log.debug(Fore.CYAN + Style.BRIGHT + 'ICM20948 available at 0x69.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + 'no ICM20948 available at 0x69.' + Style.RESET_ALL) self._set_feature_available('icm20948', icm20948_available) lsm303d_available = (0x1D in self._addresses) if lsm303d_available: self._log.debug(Fore.CYAN + Style.BRIGHT + 'LSM303D available at 0x1D.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + 'no LSM303D available at 0x1D.' + Style.RESET_ALL) self._set_feature_available('lsm303d', lsm303d_available) vl53l1x_available = (0x29 in self._addresses) if vl53l1x_available: self._log.debug(Fore.CYAN + Style.BRIGHT + 'VL53L1X available at 0x29.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + 'no VL53L1X available at 0x29.' + Style.RESET_ALL) self._set_feature_available('vl53l1x', vl53l1x_available) as7262_available = (0x49 in self._addresses) if as7262_available: self._log.debug(Fore.CYAN + Style.BRIGHT + '-- AS7262 Spectrometer available at 0x49.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + '-- no AS7262 Spectrometer available at 0x49.' + Style.RESET_ALL) self._set_feature_available('as7262', as7262_available) pijuice_available = (0x68 in self._addresses) if pijuice_available: self._log.debug(Fore.CYAN + Style.BRIGHT + 'PiJuice hat available at 0x68.' + Style.RESET_ALL) else: self._log.debug(Fore.RED + Style.BRIGHT + 'no PiJuice hat available at 0x68.' + Style.RESET_ALL) self._set_feature_available('pijuice', pijuice_available) self._log.info('configured.')