def _process_charging_time_i2c_resp(self, resp): if resp <= 2400 and resp >= 0: self.set_time(resp) return True else: PTLogger.debug("Invalid, not less than or equal to 2400: " + str(resp)) return False
def _initialise_v2_hub_v2_speaker(): # Disable I2S enabled = False reboot_required = False i2s_mode_current, i2s_mode_next = I2S.get_states() if i2s_mode_current is True: # If in I2S mode if i2s_mode_next is True: PTLogger.debug("I2S appears to be enabled - disabling...") I2S.set_state(False) reboot_required = True else: PTLogger.debug("Initialising pi-topSPEAKER v2...") _enable_i2c_if_disabled() enabled = True reboot_required = (HDMI.set_hdmi_drive_in_boot_config(2) or reboot_required) enabled = enabled and not reboot_required v2_hub_hdmi_to_i2s_required = True return enabled, reboot_required, v2_hub_hdmi_to_i2s_required
def transceive_and_process(self): state_change_to_send = self.pop_from_queue() self._update_state_from_pending_state_change(state_change_to_send) # Should this be here? # Set bits to send according to state variables if state_change_to_send is not None: # Pi's current state bits_to_send = self._parse_state_to_bits() else: # Probe for hub's state bits_to_send = 255 hub_response_bstring = self._transceive_spi(bits_to_send) byte_type = self._determine_byte(hub_response_bstring) # Determine if received byte represents device ID or state if byte_type == SPIResponseType.device_id: PTLogger.debug("Valid response from hub - DEVICE ID") self._process_device_id(hub_response_bstring) elif byte_type == SPIResponseType.state: self._process_spi_resp(hub_response_bstring) # State update has been sent to hub: perform another transceive to sync states self._get_state_from_hub(process_state=False) else: PTLogger.warning("Invalid response from hub") return False return True
def get_device_id(self): if (self._hub_connected()): return self._active_hub_module.get_device_id() else: PTLogger.debug( "Attempted to call get_device_id when there was no active hub") return DeviceID.unknown
def _process_voltage_i2c_resp(self, resp): if resp <= 20000 and resp >= 0: self.set_voltage(resp) return True else: PTLogger.debug("Invalid voltage: " + str(resp) + "mV") return False
def _sync_with_device(): """INTERNAL. Send the sync frame to tell the device that LED data is expected.""" _initialise() PTLogger.debug("Sync data:") _write(_sync)
def show(): """Update pi-topPULSE with the contents of the display buffer.""" global _pixel_map global _rotation global _show_enabled wait_counter = 0 attempt_to_show_early = not _show_enabled if attempt_to_show_early: PTLogger.info("Can't update pi-topPULSE LEDs more than 50/s. Waiting...") pause_length = 0.001 # Scale wait time to _max_freq wait_counter_length = ceil(float(1 / float(_max_freq * pause_length))) while not _show_enabled: if wait_counter >= wait_counter_length: # Timer hasn't reset for some reason - force override _enable_show_state() break else: sleep(pause_length) wait_counter = wait_counter + 1 if attempt_to_show_early: PTLogger.debug("pi-topPULSE LEDs re-enabled.") _sync_with_device() rotated_pixel_map = _get_rotated_pixel_map() avg_rgb = _get_avg_colour() _initialise() PTLogger.debug("LED data:") # For each col for x in range(_w): # Write col to LED matrix # Start with col no., so LED matrix knows which one it belongs to pixel_map_buffer = chr(x) # Get col's frame buffer, iterating over each pixel for y in range(_h + 1): if y == _h: # Ambient lighting bytes byte0, byte1 = _rgb_to_bytes_to_send(avg_rgb) else: byte0, byte1 = _rgb_to_bytes_to_send(rotated_pixel_map[x][y]) pixel_map_buffer += chr(byte0) pixel_map_buffer += chr(byte1) # Write col to LED matrix arr = bytearray(pixel_map_buffer, 'Latin_1') _write(arr) # Prevent another write if it's too fast _disable_show_state()
def _check_and_set_serial_config(): reboot_required = False version = get_debian_version() if isinstance(version, int): if int(version) > 8: PTLogger.debug( "UART baud rate does not need to be configured for ptpulse...") else: if UART.boot_config_correctly_configured( expected_clock_val=1627604, expected_baud_val=460800) is True: PTLogger.debug("Baud rate is already configured for ptpulse") else: PTLogger.debug( "Baud rate NOT already configured for ptpulse, configuring..." ) UART.configure_in_boot_config(init_uart_clock=1627604, init_uart_baud=460800) reboot_required = True else: PTLogger.warning( "Unable to detect OS version - cannot determine if UART baud rate needs to be configured for ptpulse..." ) if UART.enabled() is True: PTLogger.debug("UART is already enabled") else: PTLogger.debug("UART NOT already enabled, enabling...") UART.set_enable(True) # UART.configure_in_boot_config(enable_uart=1) reboot_required = True reboot_required = (UART.remove_serial_from_cmdline() or reboot_required) return reboot_required
def _initialise(): """INTERNAL. Initialise the matrix.""" global _initialised global _serial_device global _pixel_map if not _initialised: if configuration.mcu_enabled(): if not path.exists('/dev/serial0'): err_str = "Could not find serial port - are you sure it's enabled?" raise serialutil.SerialException(err_str) PTLogger.debug("Opening serial port...") _serial_device = Serial("/dev/serial0", baudrate=250000, timeout=2) if _serial_device.isOpen(): PTLogger.debug("OK.") else: PTLogger.info("Error: Failed to open serial port!") exit() _initialised = True else: PTLogger.info("Error: pi-topPULSE is not initialised. Call ptpulse.configuration.initialise() ptpulse.configuration.enable_device()") exit()
def disconnect(self): PTLogger.debug("I2C: Disconnecting...") self._write_device.close() self._read_device.close() self._lock_file_handle.close()
def _process_capacity_i2c_resp(self, resp): if resp <= 100 and resp >= 0: self.set_capacity(resp) return True else: PTLogger.debug("Invalid, not less than or equal to 100") return False
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 _get_addr_for_bit(bit): if bit in [0, 1, 2, 3]: PTLogger.debug("bit: " + str(bit)) addr = int(pow(2, bit)) PTLogger.debug("addr: " + str(addr)) return addr else: PTLogger.warning("Internal ERROR: invalid bit; cannot get address") return -1
def set_value(property_name, value_to_set): PTLogger.debug("Checking " + property_name + " setting in " + _BootConfig.BOOT_CONFIG_FILE + "...") property_updated = False property_found = False temp_file = common_functions.create_temp_file() with open(temp_file, 'w') as output_file: last_char = "" with open(_BootConfig.BOOT_CONFIG_FILE, 'r') as input_file: for line in input_file: line_to_write = line line_to_find = str(property_name + "=") desired_line = str(line_to_find + str(value_to_set)) if line_to_find in line_to_write: property_found = True if (common_functions.is_line_commented(line_to_write)): line_to_write = common_functions.get_uncommented_line( line_to_write) property_updated = True if desired_line not in line_to_write: line_to_write = desired_line + "\n" property_updated = True output_file.write(line_to_write) last_char = line_to_write[-1] if (property_found is False): line_to_append = "" if last_char != "\n": line_to_append += "\n" line_to_append += desired_line + "\n" # Append if not found output_file.write(line_to_append) property_updated = True if (property_updated is True): PTLogger.info("Updating " + _BootConfig.BOOT_CONFIG_FILE + " to set " + property_name + " setting...") copy(temp_file, _BootConfig.BOOT_CONFIG_FILE) else: PTLogger.debug(property_name + " setting already set in " + _BootConfig.BOOT_CONFIG_FILE) return property_updated
def read_unsigned_byte(self, register_address: int): result_array = self._run_transaction([register_address], 1) if (len(result_array) != 1): return None PTLogger.debug("I2C: Read byte " + str(result_array[0]) + " from " + hex(register_address)) return result_array[0]
def _setup_i2c(self): try: PTLogger.debug("Setting up i2c connection to battery") self._bus = SMBus(self._bus_no) PTLogger.debug("Testing comms with battery") return self._refresh_state() except: PTLogger.warning("Unable to find pi-topHUB battery") return False
def write_byte(self, register_address: int, byte_value: int): if (byte_value > 0xFF): PTLogger.warning( "Possible unintended overflow writing value to register " + hex(register_address)) PTLogger.debug("I2C: Writing byte " + str(byte_value) + " to " + hex(register_address)) self._run_transaction([register_address, byte_value & 0xFF], 0)
def attempt_disable_peripheral_by_name(self, current_peripheral_name): current_peripheral = Peripheral(name=current_peripheral_name) if current_peripheral.id == PeripheralID.unknown: PTLogger.warning("Peripheral " + current_peripheral_name + " not recognised") elif self.get_peripheral_enabled(current_peripheral): PTLogger.debug("updating peripheral state") self.update_peripheral_state(current_peripheral, False) else: PTLogger.warning("Peripheral " + current_peripheral_name + " already disabled")
def stop_listening(self): PTLogger.info("Closing responder socket...") self._continue = False if self._thread.is_alive(): self._thread.join() self._zmq_socket.close() self._zmq_context.destroy() PTLogger.debug("Closed responder socket.")
def write_word(self, register_address: int, word_value: int): if (word_value > 0xFFFF): PTLogger.warning( "Possible unintended overflow writing value to register " + hex(register_address)) PTLogger.debug("I2C: Writing word " + str(word_value) + " to " + hex(register_address)) high, low = self._split_word(word_value) self._run_transaction([register_address, high & 0xFF, low & 0xFF], 0)
def read_unsigned_word(self, register_address: int): result_array = self._run_transaction([register_address], 2) if (len(result_array) != 2): return None result = self._join_word(result_array[0], result_array[1]) PTLogger.debug("I2C: Read word " + str(result) + " from " + hex(register_address)) return result
def _main_thread_loop(self): while self._run_main_thread: FNULL = open(devnull, 'w') PTLogger.debug("Running xprintidle...") try: xprintidle_resp = check_output(['xprintidle'], stderr=FNULL) except CalledProcessError as exc: PTLogger.warning( "Unable to call xprintidle - have non-network local connections been added to X server access control list?" ) break PTLogger.debug("Got xprintidle response...") xprintidle_resp_str = xprintidle_resp.decode("utf-8") try: idletime_ms = int(xprintidle_resp_str) except: PTLogger.warning( "Unable to convert xprintidle response to integer") break PTLogger.debug("Parsed xprintidle response to integer") PTLogger.info("MS since idle: " + str(idletime_ms)) if (self._idle_timeout_s > 0): timeout_expired = (idletime_ms > (self._idle_timeout_s * 1000)) idletime_reset = (idletime_ms < self.previous_idletime) PTLogger.debug("Timeout Expired?: " + str(timeout_expired)) PTLogger.debug("Idletime Reset?: " + str(idletime_reset)) timeout_already_expired = (self.previous_idletime > (self._idle_timeout_s * 1000)) if timeout_expired and not timeout_already_expired: self._emit_idletime_threshold_exceeded() self._cycle_sleep_time = self.SENSITIVE_CYCLE_SLEEP_TIME elif idletime_reset and timeout_already_expired: self._emit_exceeded_idletime_reset() self._cycle_sleep_time = self.DEFAULT_CYCLE_SLEEP_TIME self.previous_idletime = idletime_ms for i in range(5): sleep(self._cycle_sleep_time / 5) if (self._run_main_thread is False): break
def _process_current_and_charging_state_i2c_resp(self, resp): if resp < -2500 or resp > 2500: PTLogger.debug("Invalid current: " + str(resp) + "mA") return False if resp <= -10: self.set_charging_state(0) else: charging_state = 2 if (self._state._battery_time == 0) else 1 # charging state self.set_charging_state(charging_state) self.set_current(resp) return True
def auto_initialise_peripherals(self): addresses = I2C.get_connected_device_addresses() for peripheral in self._enabled_peripherals: if format(peripheral.addr, 'x') not in addresses: PTLogger.debug("Peripheral " + peripheral.name + " was enabled but not detected.") self.remove_enabled_peripheral(peripheral) self.attempt_disable_peripheral_by_name(peripheral.name) for address in addresses: current_peripheral = Peripheral(addr=int(address, 16)) if current_peripheral.id != PeripheralID.unknown: self.attempt_enable_peripheral_by_name(current_peripheral.name)
def _finalise_wav_file(file_path): """INTERNAL. Update the WAV file header with the size of the data.""" size_of_data = _get_size(file_path) - 44 if size_of_data <= 0: PTLogger.info("Error: No data was recorded!") remove(file_path) else: with open(file_path, 'rb+') as file: PTLogger.debug("Updating header information...") _update_header_in_file(file, 4, size_of_data + 36) _update_header_in_file(file, 40, size_of_data)
def _read_device_state(): """INTERNAL. Read from the I2C bus to get the current state of the pulse. Caller should handle exceptions""" try: PTLogger.debug("Connecting to bus...") i2c_bus = SMBus(_bus_id) current_state = i2c_bus.read_byte(_device_addr) & 0x0F return int(current_state) except: PTLogger.warning("Error: There was a problem reading from the device") # Best to re-raise as we can't recover from this raise
def _get_battery_data(self, data_to_get): reattempt_sleep_s = float(_cycle_sleep_time / self._i2c_ctr.max) self._i2c_ctr.reset() while not self._i2c_ctr.maxed(): self._i2c_ctr.increment() successful_read, resp, register = self._attempt_read(data_to_get) if successful_read: return self._parse_response(resp, register) else: PTLogger.debug("Unsuccessful read...") sleep(reattempt_sleep_s) # Value was not fetched PTLogger.debug("Unable to read from I2C after multiple attempts") return False
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 wait_for_device_identification(self): PTLogger.debug("Waiting for device id to be established...") time_waited = 0 while (time_waited < 5): device_id = self.get_device_id() if (device_id == DeviceID.unknown): sleep(0.25) time_waited += 0.25 else: PTLogger.debug("Got device id (" + str(device_id) + "). Waited " + str(time_waited) + " seconds") return PTLogger.warning("Timed out waiting for device identification.")
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()