def enable_device(): enabled = False reboot_required = False v2_hub_hdmi_to_i2s_required = False is_pi_top = (_host_device_id == DeviceID.pi_top) is_pi_top_ceed = (_host_device_id == DeviceID.pi_top_ceed) hub_is_v1 = (is_pi_top or is_pi_top_ceed) is_pi_top_v2 = (_host_device_id == DeviceID.pi_top_v2) if is_pi_top_v2: reboot_required = _initialise_v2_hub_pulse() if (reboot_required is False): v2_hub_hdmi_to_i2s_required = True elif hub_is_v1 or (_host_device_id == DeviceID.unknown): reboot_required = _initialise_v1_hub_pulse() else: PTLogger.error("Error - unrecognised device ID '" + str(_host_device_id) + "' - unsure how to initialise " + speaker_type_name) if (reboot_required is False): _reset_device_state(True) enabled = True return enabled, reboot_required, v2_hub_hdmi_to_i2s_required
def get_i2s_state(): i2s_mode_current = None i2s_mode_next = None try: i2s_output = _SystemCalls._get_cmd_resp([_SystemCalls.PTI2S_CMD ]).splitlines() for line in i2s_output: if 'I2S is currently enabled' in str(line): i2s_mode_current = True elif 'I2S is currently disabled' in str(line): i2s_mode_current = False elif 'I2S is due to be enabled on reboot' in str(line): i2s_mode_next = True elif 'I2S is due to be disabled on reboot' in str(line): i2s_mode_next = False except Exception as e: PTLogger.error("Unable to verify I2S mode. " + str(e)) PTLogger.info(traceback.format_exc()) if i2s_mode_current is None or i2s_mode_next is None: PTLogger.error("Unable to determine I2S mode. Current: " + str(i2s_mode_current) + ", Next: " + str(i2s_mode_next)) return i2s_mode_current, i2s_mode_next
def _get_state_from_hub(self, init=False, process_state=True): valid = False get_state_ctr = Counter(5) do_extra_read = init while not valid and not get_state_ctr.maxed(): valid, resp_bin_str = self._attempt_get_state() if do_extra_read and valid: valid = False do_extra_read = False if not valid: get_state_ctr.current += 1 sleep(_cycle_sleep_time) if valid: if process_state: self._process_spi_resp(resp_bin_str, init=init) else: PTLogger.error("Unable to communicate with hub. " + "init: " + str(init) + ", resp_bin_str: " + str(resp_bin_str)) return valid
def start(self): if not self.is_initialised(): PTLogger.error("Unable to start pi-top peripheral management - run initialise() first!") return False self._run_main_thread = True self._main_thread.start() return True
def change_screen_state(spi_screen_operation): if is_initialised(): _add_state_change_to_send_to_stack(SPIStateChangeType.screen, spi_screen_operation) if not _main_thread.is_alive(): communicate() else: PTLogger.error("Unable to change screen state - run initialise() first!")
def initialise(state): global _battery_state_handler try: _battery_state_handler = BatteryStateHandler(state) return True except Exception as e: PTLogger.error("Error initialising I2C. " + str(e)) PTLogger.info(traceback.format_exc()) _battery_state_handler = None return False
def initialise(state): global _spi_handler try: _spi_handler = SPIHandler(state) return True except Exception as e: PTLogger.error("Error creating SPIHandler. " + str(e)) PTLogger.info(traceback.format_exc()) _spi_handler = None return False
def communicate(): if not is_initialised(): PTLogger.error("I2C has not been initialised - call initialise() first") return False try: _battery_state_handler._refresh_state() return True except Exception as e: PTLogger.error("Error refreshing the state of the battery handler. " + str(e)) PTLogger.info(traceback.format_exc()) return False
def start(): global _main_thread global _run_main_thread if is_initialised(): if _main_thread is None: _main_thread = Thread(target=_main_thread_loop) _run_main_thread = True _main_thread.start() else: PTLogger.error("Unable to start pi-topHUB SPI communication - run initialise() first!")
def communicate(): if _spi_handler is None: PTLogger.error("SPI has not been initialised - initialise first") return False try: return _spi_handler.transceive_and_process() except Exception as e: PTLogger.error("Error transceiving SPI data from pi-topHUB. " + str(e)) PTLogger.info(traceback.format_exc()) raise e return False
def get_audio_output_interface_no(): interface = None try: mixer_output = _SystemCalls._get_cmd_resp( _SystemCalls.AMIXER_GET_CMD_ARR, print_std_err=False).splitlines() for line in mixer_output: if ': values=' in line: prefix, interface = line.split('=') break except Exception as e: PTLogger.error("There was an error getting audio output state: " + str(e)) return interface
def get_i2c_state(): try: i2c_output_str = str( _SystemCalls._get_cmd_resp( _SystemCalls.GET_I2C_CMD_ARR)).rstrip() i2c_output = int(i2c_output_str) i2c_mode = (i2c_output == 0) if i2c_mode is False and i2c_output == 1: PTLogger.error("Unable to verify I2C mode - assuming disabled") return i2c_mode except Exception as e: PTLogger.error("Unable to verify I2C mode. " + str(e)) PTLogger.info(traceback.format_exc()) return None
def get_value(property_name, value_is_number): if not (path.isfile(_BootConfig.BOOT_CONFIG_FILE)): PTLogger.error(_BootConfig.BOOT_CONFIG_FILE + " - file not found!") return "" with open(_BootConfig.BOOT_CONFIG_FILE) as config_file: for line in config_file: if (property_name in line): if not line.strip().startswith("#"): if value_is_number: value = _BootConfig._get_number_value_from_line( line) else: value = _BootConfig._get_last_field_from_line(line) return value return ""
def stop_listening(self): PTLogger.info("Closing publisher socket...") try: self._socket_lock.acquire() self._shutting_down = True self._zmq_socket.close() self._zmq_context.destroy() PTLogger.debug("Closed publisher socket.") except zmq.error.ZMQError as e: PTLogger.error("Error starting the publish server: " + str(e)) PTLogger.info(traceback.format_exc()) finally: self._socket_lock.release()
def attempt_enable_peripheral_by_name(self, current_peripheral_name): current_peripheral = Peripheral(name=current_peripheral_name) if current_peripheral.id == PeripheralID.unknown: PTLogger.error("Attempted to enable peripheral " + current_peripheral_name + ", but it was not recognised") elif not self.get_peripheral_enabled(current_peripheral): PTLogger.debug("Peripheral " + current_peripheral_name + " not already enabled") for enabled_peripheral in self._enabled_peripherals: if enabled_peripheral.id != current_peripheral.id and current_peripheral.id not in enabled_peripheral.compatible_ids: PTLogger.debug("Not compatible with " + enabled_peripheral.name) return self.update_peripheral_state(current_peripheral, True) else: PTLogger.debug("Peripheral " + current_peripheral_name + " already enabled")
def get_connected_device_addresses(): addresses_arr = [] # Switch on I2C if it's not enabled if I2C.get_state() is False: PTLogger.warning( "I2C is not initialised - attempting to initialise") I2C.set_state(True) # Error if still false if I2C.get_state() is False: PTLogger.error( "Unable to initialise I2C - unable to get connected device addresses" ) else: addresses_arr = _SystemCalls.get_connected_i2c_device_addresses() return addresses_arr
def _send_message(self, message_id, parameters): message = Message.from_parts(message_id, parameters) try: self._socket_lock.acquire() if (self._shutting_down is True): return self._zmq_socket.send_string(message.to_string()) PTLogger.debug("Published message: " + message.message_friendly_string()) except zmq.error.ZMQError as e: PTLogger.error("Communication error in publish server: " + str(e)) PTLogger.info(traceback.format_exc()) finally: self._socket_lock.release()
def connect_to_hub(self): # Attempt to connect to a v2 hub first. This is because we can # positively identify v2 on i2c. We can also positively identify # a v1 pi-top, however we cannot do this for a CEED. Hence this # is the fall-through case. PTLogger.info("Attempting to find pi-topHUB v2...") try: self._module_hub_v2 = self._import_module("pthub2.pthub2") if (self._module_hub_v2.initialise() is True): self._active_hub_module = self._module_hub_v2 PTLogger.info("Connected to pi-topHUB v2") self._register_client() return True else: PTLogger.warning("Could not initialise v2 hub") except Exception as e: PTLogger.warning("Failed to connect to a v2 hub. " + str(e)) PTLogger.info(traceback.format_exc()) PTLogger.info("Attempting to find pi-topHUB v1...") try: self._module_hub_v1 = self._import_module("pthub.pthub") if (self._module_hub_v1.initialise() is True): self._active_hub_module = self._module_hub_v1 PTLogger.info("Connected to pi-topHUB v1") self._register_client() return True else: PTLogger.warning("Could not initialise v1 hub") except Exception as e: PTLogger.warning("Failed to connect to a v1 hub. " + str(e)) PTLogger.info(traceback.format_exc()) PTLogger.error("Could not connect to a hub!") return False
def change_brightness_state(brightness_val): if is_initialised(): if (brightness_val > 10): brightness_val = 10 if brightness_val >= 0 and brightness_val <= 10 and _spi_handler._state.valid_brightness(brightness_val): if (_spi_handler._state._screen_blanked == 1): change_screen_state(SPIScreenOperations.unblank) _add_state_change_to_send_to_stack(SPIStateChangeType.brightness, brightness_val) if not _main_thread.is_alive(): communicate() else: PTLogger.info(str(brightness_val) + " is not a valid brightness - doing nothing") else: PTLogger.error("Unable to change brightness - run initialise() first!")
def start_listening(self): PTLogger.debug("Opening publisher socket...") try: self._socket_lock.acquire() self._zmq_context = zmq.Context() self._zmq_socket = self._zmq_context.socket(zmq.PUB) self._zmq_socket.bind("tcp://*:3781") PTLogger.info("Publish server ready...") return True except zmq.error.ZMQError as e: PTLogger.error("Error starting the publish server: " + str(e)) PTLogger.info(traceback.format_exc()) return False finally: self._socket_lock.release()
def start_listening(self): PTLogger.debug("Opening request socket...") try: self._zmq_context = zmq.Context() self._zmq_socket = self._zmq_context.socket(zmq.REP) self._zmq_socket.bind("tcp://*:3782") PTLogger.info("Responder server ready.") except zmq.error.ZMQError as e: PTLogger.error("Error starting the request server: " + str(e)) PTLogger.info(traceback.format_exc()) return False sleep(0.5) self._continue = True self._thread.start() return True
def start(self): PTLogger.info("Starting device manager...") if (self._hub_manager.connect_to_hub()): self._hub_manager.start() else: PTLogger.error("No pi-top hub detected") if (self._publish_server.start_listening() is False): PTLogger.error("Able to start listening on publish server") return # Wait until we have established what device we're running on self._hub_manager.wait_for_device_identification() device_id = self._hub_manager.get_device_id() # Now we have a device id, pass it to the other services self._peripheral_manager.initialise_device_id(device_id) self._shutdown_manager.set_device_id(device_id) PTLogger.info("Device ID set to " + str(device_id)) if (self._peripheral_manager.start() is False): PTLogger.error("Able to start peripheral manager") return self._idle_monitor.start() if (self._request_server.start_listening() is False): PTLogger.error("Able to start listening on request server") return sleep(0.5) self._shutdown_manager.configure_shutdown_from_device_id() PTLogger.info("Fully configured - running") while (self._continue_running is True): sleep(0.5) # Stop the other classes self._request_server.stop_listening() self._idle_monitor.stop() self._peripheral_manager.stop() self._hub_manager.stop() self._publish_server.stop_listening() PTLogger.info("Exiting...") exit(0)
def update_peripheral_state(self, peripheral, enable): if enable: PTLogger.info("Enabling peripheral: " + peripheral.name) else: PTLogger.info("Disabling peripheral: " + peripheral.name) peripheral_enabled = self.get_peripheral_enabled(peripheral) valid = (enable != peripheral_enabled) if valid: if 'pi-topPULSE' in peripheral.name: if 'ptpulse' in self._custom_imported_modules: is_v1_hub = (self._host_device_id == DeviceID.pi_top) or (self._host_device_id == DeviceID.pi_top_ceed) if self._host_device_id == DeviceID.pi_top_v2: self.configure_v2_hub_pulse(peripheral, enable) elif is_v1_hub or self._host_device_id == DeviceID.unknown: self.configure_v1_hub_pulse(peripheral, enable) else: PTLogger.error("Not a valid configuration") else: self.show_pulse_install_package_message() elif 'pi-topSPEAKER' in peripheral.name: if 'ptspeaker' in self._custom_imported_modules: is_v1_hub = (self._host_device_id == DeviceID.pi_top) or (self._host_device_id == DeviceID.pi_top_ceed) if self._host_device_id == DeviceID.pi_top_v2: # CHECK THAT SPEAKER IS V2 if peripheral.name == 'pi-topSPEAKER-v2': self.enable_v2_hub_v2_speaker(peripheral) else: PTLogger.warning("Unable to initialise V1 speaker with V2 hardware") # Mark as enabled even if a reboot is required # to prevent subsequent attempts to enable self.add_enabled_peripheral(peripheral) self.emit_unsupported_hardware_message() elif is_v1_hub or self._host_device_id == DeviceID.unknown: if enable is True: if peripheral.name == 'pi-topSPEAKER-v2': self.enable_v1_hub_v2_speaker(peripheral) else: self.enable_v1_hub_v1_speaker(peripheral) else: self.remove_enabled_peripheral(peripheral) else: PTLogger.error("Not a valid configuration") else: self.show_speaker_install_package_message() elif 'pi-topPROTO+' in peripheral.name: # Nothing to do - add to list of peripherals self.add_enabled_peripheral(peripheral) else: PTLogger.error("Peripheral name not recognised") else: PTLogger.debug("Peripheral state was already set")
def initialise(): global _state _state = State() PTLogger.info("Initialising I2C...") pthub_i2c.initialise(_state) PTLogger.info("Initialising SPI...") pthub_spi.initialise(_state) if pthub_spi.is_initialised() is False: PTLogger.error("Unable to detect pi-topHUB via SPI") _state.set_device_id(DeviceID.unknown) return False if pthub_i2c.is_initialised(): PTLogger.info("Detected pi-top battery. This is a pi-top") _state.set_device_id(DeviceID.pi_top) else: PTLogger.info("Unable to detect pi-topHUB's battery. If host is a CEED this will be established after initial communication") return True
def set_audio_output_interface_no(interface_no, debug_interface_name): PTLogger.debug("Setting audio output to " + debug_interface_name + "...") try: current_interface_no = _SystemCalls.get_audio_output_interface_no() if current_interface_no != str( interface_no) and current_interface_no is not None: PTLogger.debug("Audio not configured to " + debug_interface_name + " - updating...") amixer_set_interface_cmd_arr = list( _SystemCalls.AMIXER_SET_CMD_ARR) amixer_set_interface_cmd_arr.append(str(interface_no)) _SystemCalls._run_cmd(amixer_set_interface_cmd_arr) _SystemCalls._run_cmd(_SystemCalls.ALSA_RESTART_CMD) PTLogger.debug("OK") return True except Exception as e: PTLogger.error("There was an error setting audio output to " + debug_interface_name + ": " + str(e)) return False
def _enable_i2c_if_disabled(): if HDMI.set_as_audio_output(): try: # Switch on I2C if it's not enabled if I2C.get_state() is False: I2C.set_state(True) if I2C.get_state() is False: PTLogger.error("Unable to initialise I2C") except Exception as e: PTLogger.error("Failed to configure pi-topSPEAKER. Error: " + str(e)) PTLogger.info(traceback.format_exc()) else: PTLogger.error("Failed to configure HDMI output")
def enable_device(): enabled = False reboot_required = False v2_hub_hdmi_to_i2s_required = False is_pi_top = _host_device_id == DeviceID.pi_top is_pi_top_ceed = _host_device_id == DeviceID.pi_top_ceed hub_is_v1 = is_pi_top or is_pi_top_ceed is_pi_top_3 = _host_device_id == DeviceID.pi_top_3 if is_pi_top_3: if "pi-topSPEAKER-v1" in _speaker_type_name: PTLogger.info("pi-topSPEAKER v1 is not supported on pi-top v2") elif "pi-topSPEAKER-v2" in _speaker_type_name: enabled, reboot_required, v2_hub_hdmi_to_i2s_required = ( _initialise_v2_hub_v2_speaker()) else: PTLogger.error("Error - unrecognised device: " + _speaker_type_name) elif hub_is_v1 or (_host_device_id == DeviceID.unknown): if "pi-topSPEAKER-v1-" in _speaker_type_name: mode_long = _speaker_type_name.replace("pi-topSPEAKER-v1-", "") mode_first_lower_char = mode_long[0].lower() enabled, reboot_required, v2_hub_hdmi_to_i2s_required = _initialise_v1_hub_v1_speaker( mode_first_lower_char) elif "pi-topSPEAKER-v2" in _speaker_type_name: enabled, reboot_required, v2_hub_hdmi_to_i2s_required = ( _initialise_v1_hub_v2_speaker()) else: PTLogger.error("Error - unrecognised device: " + _speaker_type_name) else: PTLogger.error("Error - unrecognised device ID '" + str(_host_device_id) + "' - unsure how to initialise " + _speaker_type_name) return enabled, reboot_required, v2_hub_hdmi_to_i2s_required
def __init__(self, type, operation): permitted_types = [item.value for item in SPIStateChangeType] if type.value in permitted_types: if type == SPIStateChangeType.brightness: if _spi_handler._state.valid_brightness(operation): self._type = type self._operation = operation else: PTLogger.error("Unable to create class - invalid operation (brightness)") elif type == SPIStateChangeType.screen: self._type = type if SPIScreenOperations.has_value(operation.value): self._operation = operation else: PTLogger.error("Unable to create class - invalid operation (screen)") elif type == SPIStateChangeType.init: self._type = type if operation is True: self._operation = operation else: PTLogger.error("Unable to create class - invalid operation (init)") else: PTLogger.error("Unable to detect supposedly valid type") PTLogger.error("TYPE: " + str(type.value)) else: PTLogger.error("Unable to create class - invalid type") PTLogger.error("TYPE: " + str(type)) PTLogger.error("PERMITTED: " + str(permitted_types))
def _process_request(self, request): try: message = Message.from_string(request) PTLogger.info("Received request: " + message.message_friendly_string()) if (message.message_id() == Message.REQ_PING): message.validate_parameters([]) response = Message.from_parts(Message.RSP_PING, []) elif (message.message_id() == Message.REQ_GET_DEVICE_ID): message.validate_parameters([]) device_id = self._callback_client._on_request_get_device_id() if device_id is None: device_id = -1 response = Message.from_parts(Message.RSP_GET_DEVICE_ID, [device_id]) elif (message.message_id() == Message.REQ_GET_BRIGHTNESS): message.validate_parameters([]) brightness = self._callback_client._on_request_get_brightness() if brightness is None: brightness = -1 response = Message.from_parts(Message.RSP_GET_BRIGHTNESS, [brightness]) elif (message.message_id() == Message.REQ_SET_BRIGHTNESS): message.validate_parameters([int]) self._callback_client._on_request_set_brightness( int(message.parameters()[0])) response = Message.from_parts(Message.RSP_SET_BRIGHTNESS, []) elif (message.message_id() == Message.REQ_INCREMENT_BRIGHTNESS): message.validate_parameters([]) self._callback_client._on_request_increment_brightness() response = Message.from_parts(Message.RSP_INCREMENT_BRIGHTNESS, []) elif (message.message_id() == Message.REQ_DECREMENT_BRIGHTNESS): message.validate_parameters([]) self._callback_client._on_request_decrement_brightness() response = Message.from_parts(Message.RSP_DECREMENT_BRIGHTNESS, []) elif (message.message_id() == Message.REQ_BLANK_SCREEN): message.validate_parameters([]) self._callback_client._on_request_blank_screen() response = Message.from_parts(Message.RSP_BLANK_SCREEN, []) elif (message.message_id() == Message.REQ_UNBLANK_SCREEN): message.validate_parameters([]) self._callback_client._on_request_unblank_screen() response = Message.from_parts(Message.RSP_UNBLANK_SCREEN, []) elif (message.message_id() == Message.REQ_GET_SCREEN_BACKLIGHT_STATE): message.validate_parameters([]) backlight_state = self._callback_client._on_request_get_screen_backlight_state( ) if backlight_state is None: backlight_state = -1 response = Message.from_parts( Message.RSP_GET_SCREEN_BACKLIGHT_STATE, [backlight_state]) elif (message.message_id() == Message.REQ_SET_SCREEN_BACKLIGHT_STATE): message.validate_parameters([int]) self._callback_client._on_request_set_screen_backlight_state( int(message.parameters()[0])) response = Message.from_parts( Message.RSP_SET_SCREEN_BACKLIGHT_STATE, []) elif (message.message_id() == Message.REQ_GET_BATTERY_STATE): message.validate_parameters([]) charging_state, capacity, time_remaining, wattage = self._callback_client._on_request_battery_state( ) response = Message.from_parts( Message.RSP_GET_BATTERY_STATE, [charging_state, capacity, time_remaining, wattage]) elif (message.message_id() == Message.REQ_GET_PERIPHERAL_ENABLED): message.validate_parameters([int]) enabled_bool = self._callback_client._on_request_get_peripheral_enabled( int(message.parameters()[0])) enabled_int = int(enabled_bool is True) response = Message.from_parts( Message.RSP_GET_PERIPHERAL_ENABLED, [enabled_int]) elif (message.message_id() == Message.REQ_GET_SCREEN_BLANKING_TIMEOUT): message.validate_parameters([]) timeout = self._callback_client._on_request_get_screen_blanking_timeout( ) if timeout is None: timeout = -1 response = Message.from_parts( Message.RSP_GET_SCREEN_BLANKING_TIMEOUT, [timeout]) elif (message.message_id() == Message.REQ_SET_SCREEN_BLANKING_TIMEOUT): message.validate_parameters([int]) self._callback_client._on_request_set_screen_blanking_timeout( int(message.parameters()[0])) response = Message.from_parts( Message.RSP_SET_SCREEN_BLANKING_TIMEOUT, []) else: PTLogger.error("Unsupported request received: " + request) response = Message.from_parts(Message.RSP_ERR_UNSUPPORTED, []) except ValueError as e: PTLogger.error("Error processing message: " + str(e)) PTLogger.info(traceback.format_exc()) response = Message.from_parts(Message.RSP_ERR_MALFORMED, []) except Exception as e: PTLogger.error("Unknown error processing message: " + str(e)) PTLogger.info(traceback.format_exc()) response = Message.from_parts(Message.RSP_ERR_SERVER, []) PTLogger.info("Sending response: " + response.message_friendly_string()) return response.to_string()
def _start_spi(): if pthub_spi.is_initialised(): pthub_spi.start() else: PTLogger.error("SPI is not available")