def split_into_bytes(data: int, no_of_bytes: int = -1, little_endian: bool = False, signed: bool = False): """ This function will split a given integer into a integer list representing the bytes to be split; :param data: A integer that represents the value of the bytes to be split :param no_of_bytes: The number of bytes the integer to be converted into. If the no_of_bytes is too small the method returns None. :return: A integer list representing a bytes list version of the given integer """ byteorder_indicator = "little" if little_endian is True else "big" if no_of_bytes == -1: no_of_bytes = ceil(data / 255) try: byte_string = data.to_bytes(no_of_bytes, byteorder=byteorder_indicator, signed=signed) except OverflowError as e: PTLogger.error(e) return None return [i for i in bytearray(byte_string)]
def write_word(self, register_address: int, word_value: int, little_endian: bool = False, signed: bool = False): word_to_write = split_into_bytes( word_value, 2, little_endian=little_endian, signed=signed) if word_to_write is None: PTLogger.error( "Error splitting word into bytes list. Value: ", word_value) else: self.write_n_bytes(register_address, word_to_write)
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) ) self.write_n_bytes(register_address, [byte_value & 0xFF])
def disconnect(self): PTLogger.debug("I2C: Disconnecting...") if self._write_device is not None: self._write_device.close() if self._read_device is not None: self._read_device.close()
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) ) self._bus.write_byte_data( self._device_address, register_address, byte_value)
def run_command_background(command_str: str, print_output=False) -> Popen: PTLogger.debug("Function: run_command_background(command_str=%s)" % command_str) return Popen(split(command_str), env=__get_env(), stderr=None if print_output else DEVNULL, stdout=None if print_output else DEVNULL)
def connect(self): PTLogger.debug( "I2C (SMBus): Connecting to address " + hex(self._device_address) + " on bus " + str(self._bus_number) ) self._bus = SMBus(self._bus_number)
def write_n_bytes(self, register_address: int, byte_list: list): """ Base function to write to an I2C device """ PTLogger.debug( "I2C: Writing byte/s " + str(byte_list) + " to " + hex(register_address) ) self.__run_transaction([register_address] + byte_list, 0)
def write_word(self, register_address: int, word_value: int, little_endian: bool, signed: bool): bytes_to_write = split_into_bytes( word_value, 2, little_endian=little_endian, signed=signed) if bytes_to_write is None: PTLogger.error( "Error splitting word into bytes list. Value: ", word_value) return self.write_n_bytes(register_address, bytes_to_write)
def write_n_bytes(self, register_address: int, byte_list: list): """ Base function to write to an I2C device """ PTLogger.debug( "I2C: Writing byte/s " + str(byte_list) + " to " + hex(register_address) ) self._bus.write_i2c_block_data( self._device_address, register_address, byte_list)
def __init__(self, id, _single_purpose=False): self.path = "/tmp/%s.lock" % id self._thread_lock = Lock() self._single_purpose = _single_purpose lock_file_already_existed = exists(self.path) self.__lock_file_handle = open(self.path, "w") if not lock_file_already_existed: chmod(self.path, S_IWUSR | S_IWGRP | S_IWOTH) PTLogger.debug("Creating PTLock with path: {}".format(self.path))
def send_notification(title: str, text: str, icon_name: str = "", timeout: int = 0, app_name: str = "", notification_id: int = -1, actions_manager: NotificationActionManager = None, urgency_level: NotificationUrgencyLevel = None, capture_notification_id: bool = True) -> str: # TODO: check that `pt-notify-send` is available, as it's not a hard dependency of the package cmd = "/usr/bin/pt-notify-send " cmd += "--print-id " cmd += "--expire-time=" + str(timeout) + " " if icon_name: cmd += "--icon=" + icon_name + " " if notification_id >= 0: cmd += "--replace=" + str(notification_id) + " " if actions_manager is not None: for action in actions_manager.actions: cmd += "--action=\"" + action.call_to_action_text + \ ":" + action.command_str + "\" " if actions_manager.default_action is not None: cmd += "--default-action=" + actions_manager.default_action.command_str + " " if actions_manager.close_action is not None: cmd += "--close-action=" + actions_manager.close_action.command_str + " " if app_name: cmd += "--app-name=" + app_name + " " if urgency_level is not None: cmd += "--urgency=" + urgency_level.name + " " cmd += " \"" + title + "\" " cmd += "\"" + text + "\"" PTLogger.info("pt-notify-send command: {}".format(cmd)) try: resp_stdout = run_command(cmd, 2000, capture_output=capture_notification_id) except Exception as e: PTLogger.warning("Failed to show message: {}".format(e)) raise return resp_stdout
def is_locked(self): if self.__locked_by_self: return self.__locked_by_self lock_status = False try: flock(self.__lock_file_handle, LOCK_EX | LOCK_NB) flock(self.__lock_file_handle, LOCK_UN) except BlockingIOError: lock_status = True PTLogger.debug("Lock file at {} is {}locked".format( self.path, "not " if not lock_status else "")) return lock_status
def get_list_of_displays() -> int: def represents_int(s): try: int(s) return True except ValueError: return False displays = [ f.replace('X', ':') for f in listdir("/tmp/.X11-unix/") if represents_int(f.replace('X', '')) ] PTLogger.debug("List of displays found: {}".format(displays)) return displays
def __read_n_bytes( self, register_address: int, number_of_bytes: int, signed: bool = False, little_endian: bool = False, ): """ Base function to read from an I2C device :param register_address: Register address to target for reading :param number_of_bytes: Number of bytes to attempt to read from register address :param signed: Indicates whether or not the value could potentially have a negative value, and is therefore represented with a signed number representation :param little_endian: Indicates whether the data to be read is in little-endian byte-order :return: result: The response from the read attempt via I2C """ # Read from device result_array = self.__run_transaction( [register_address], number_of_bytes ) # Check response length is correct if len(result_array) != number_of_bytes: return None # Invert byte ordering, if appropriate if little_endian: result_array.reverse() # Convert array into integer result = join_bytes(result_array) # Process signed number if appropriate if signed: if result & (1 << ((8 * number_of_bytes) - 1)): result = -(1 << (8 * number_of_bytes)) + result PTLogger.debug( "I2C: Read " + str(number_of_bytes) + " bytes from " + hex(register_address) + " (" + ( "Signed," if signed else "Unsigned,") + ("LE" if little_endian else "BE") + ")" ) PTLogger.debug(str(result_array) + " : " + str(result)) return result
def release(self) -> bool: """ Attempt to release lock """ if not self._thread_lock.locked(): PTLogger.debug("Attempting to release thread lock, which is currently already acquired.") if not self.is_locked(): PTLogger.debug(f"Attempting to release lock file ({self.path}), which is currently already globally acquired.") PTLogger.debug("Releasing thread lock") self._thread_lock.release() PTLogger.debug("Releasing lock file at {}".format(self.path)) flock(self.__lock_file_handle, LOCK_UN) self.__locked_by_self = False
def acquire(self) -> bool: """ Block until lock can be acquired """ if self._thread_lock.locked(): PTLogger.debug("Attempting to acquire thread lock, which is currently already acquired.") if self.is_locked(): PTLogger.debug(f"Attempting to acquire lock file ({self.path}), which is currently already globally acquired.") PTLogger.debug("Acquiring thread lock") self._thread_lock.acquire() PTLogger.debug("Acquiring lock file at {}".format(self.path)) flock(self.__lock_file_handle, LOCK_EX) self.__locked_by_self = True
def __connect_to_socket(self): self.__zmq_context = zmq.Context() self.__zmq_socket = self.__zmq_context.socket(zmq.REQ) self.__zmq_socket.sndtimeo = _TIMEOUT_MS self.__zmq_socket.rcvtimeo = _TIMEOUT_MS try: self.__zmq_socket.connect("tcp://127.0.0.1:3782") PTLogger.debug("pt-device-manager request client is ready") except zmq.error.ZMQError as e: PTLogger.error("Error starting the request client: " + str(e)) PTLogger.info(format_exc()) raise
def __connect_to_socket(self): self.__zmq_context = zmq.Context() self.__zmq_socket = self.__zmq_context.socket(zmq.SUB) self.__zmq_socket.setsockopt_string(zmq.SUBSCRIBE, "") try: self.__zmq_socket.connect("tcp://127.0.0.1:3781") PTLogger.debug("pt-device-manager subscribe client is ready") except zmq.error.ZMQError as e: PTLogger.error("Error starting the subscribe client: " + str(e)) PTLogger.info(format_exc()) return False return True
def connect(self, read_test=True): PTLogger.debug( "I2C: Connecting to address " + hex(self._device_address) + " on " + self._device_path ) self._read_device = iopen(self._device_path, "rb", buffering=0) self._write_device = iopen(self._device_path, "wb", buffering=0) ioctl(self._read_device, self.I2C_SLAVE, self._device_address) ioctl(self._write_device, self.I2C_SLAVE, self._device_address) if read_test is True: PTLogger.debug("I2C: Test read 1 byte") self._read_device.read(1) PTLogger.debug("I2C: OK")
def disconnect(self): PTLogger.debug("I2C (SMBus): Disconnecting...") self._bus.close()
def get_first_display() -> int: displays = get_list_of_displays() first_display = displays[0] if len(displays) > 0 else None PTLogger.debug("First display is: {}".format(first_display)) return first_display
def run_command(command_str: str, timeout: int, check: bool = True, capture_output: bool = True, log_errors: bool = True) -> str: PTLogger.debug( f"Function: run_command(command_str={command_str}, timeout={timeout}, check={check}, capture_output={capture_output}, \ log_errors={log_errors})") resp_stdout = None try: resp = run(split(command_str), check=check, capture_output=capture_output, timeout=timeout, env=__get_env()) if capture_output: resp_stdout = str(resp.stdout, 'utf8') resp_stderr = str(resp.stderr, 'utf8') PTLogger.debug(f"run_command(" f"command_str='{command_str}', " f"timeout={timeout}, " f"check='{check}', " f"capture_output='{capture_output}'" f") stdout:\n{resp_stdout}") PTLogger.debug(f"run_command(" f"command_str='{command_str}', " f"timeout={timeout}, " f"check='{check}', " f"capture_output='{capture_output}'" f") stderr:\n{resp_stderr}") if not check: PTLogger.debug(f"run_command(" f"command_str='{command_str}', " f"timeout={timeout}, " f"check='{check}', " f"capture_output='{capture_output}'" f") exit code: {resp.returncode}") except (CalledProcessError, TimeoutExpired) as e: if log_errors: PTLogger.error(str(e)) raise e except Exception as e: if log_errors: PTLogger.error(str(e)) return resp_stdout