diff --git a/examples/async.py b/examples/async.py index 8f41de640..0caef3a4f 100755 --- a/examples/async.py +++ b/examples/async.py @@ -79,6 +79,27 @@ async def get_info(worker) -> None: print(f"{'Firmware':<15}: {firmware[0]}") +async def run(worker) -> None: + await worker.init_async() + + await get_info(worker) + await get_network_info(worker) + + await send_message_async(worker, "6700", "BAL") + + # Just a busy waiting for event + # We need to keep communication with phone to get notifications + print("Press Ctrl+C to interrupt") + while 1: + try: + signal = await worker.get_signal_quality_async() + print(f"Signal is at {signal['SignalPercent']:d}%") + except Exception as e: # ruff: ignore[blind-except] + print(f"Exception reading signal: {e}") + + await asyncio.sleep(10) + + async def main() -> None: gammu.SetDebugFile(sys.stderr) gammu.SetDebugLevel("textall") @@ -88,25 +109,7 @@ async def main() -> None: worker.configure(config) try: - await worker.init_async() - - await get_info(worker) - await get_network_info(worker) - - await send_message_async(worker, "6700", "BAL") - - # Just a busy waiting for event - # We need to keep communication with phone to get notifications - print("Press Ctrl+C to interrupt") - while 1: - try: - signal = await worker.get_signal_quality_async() - print(f"Signal is at {signal['SignalPercent']:d}%") - except Exception as e: # ruff: ignore[blind-except] - print(f"Exception reading signal: {e}") - - await asyncio.sleep(10) - + await run(worker) except Exception as e: # ruff: ignore[blind-except] print("Exception:") print(e) diff --git a/examples/filesystem_test.py b/examples/filesystem_test.py index e8a0d390e..226c25db8 100755 --- a/examples/filesystem_test.py +++ b/examples/filesystem_test.py @@ -53,6 +53,16 @@ import gammu +def print_root_folders(state_machine) -> None: + file_obj = state_machine.GetNextRootFolder("") + while 1: + print(f"{file_obj['ID_FullName']} - {file_obj['Name']}") + try: + file_obj = state_machine.GetNextRootFolder(file_obj["ID_FullName"]) + except gammu.ERR_EMPTY: + break + + def main() -> None: # ruff: ignore[too-many-branches, too-many-statements, complex-structure] parser = argparse.ArgumentParser(usage="usage: %(prog)s [options]") @@ -164,13 +174,7 @@ def main() -> None: # ruff: ignore[too-many-branches, too-many-statements, comp # Check GetNextRootFolder print("\n\nExpectation: Root Folder List") try: - file_obj = state_machine.GetNextRootFolder("") - while 1: - print(f"{file_obj['ID_FullName']} - {file_obj['Name']}") - try: - file_obj = state_machine.GetNextRootFolder(file_obj["ID_FullName"]) - except gammu.ERR_EMPTY: - break + print_root_folders(state_machine) except gammu.ERR_NOTSUPPORTED: print("Not supported...") diff --git a/examples/getallsms.py b/examples/getallsms.py index 3e6e7b1ef..9bf8a7d2f 100755 --- a/examples/getallsms.py +++ b/examples/getallsms.py @@ -24,6 +24,12 @@ import gammu +def get_next_sms(state_machine, previous): + if previous is None: + return state_machine.GetNextSMS(Start=True, Folder=0) + return state_machine.GetNextSMS(Location=previous[0]["Location"], Folder=0) + + def main() -> None: state_machine = gammu.StateMachine() state_machine.ReadConfig() @@ -33,27 +39,23 @@ def main() -> None: remain = status["SIMUsed"] + status["PhoneUsed"] + status["TemplatesUsed"] - start = True - - try: - while remain > 0: - if start: - sms = state_machine.GetNextSMS(Start=True, Folder=0) - start = False - else: - sms = state_machine.GetNextSMS(Location=sms[0]["Location"], Folder=0) - remain -= len(sms) - - for m in sms: - print() - print(f"{'Number':<15}: {m['Number']}") - print(f"{'Date':<15}: {m['DateTime']!s}") - print(f"{'State':<15}: {m['State']}") - print(f"\n{m['Text']}") - except gammu.ERR_EMPTY: - # This error is raised when we've reached last entry - # It can happen when reported status does not match real counts - print("Failed to read all messages!") + sms = None + while remain > 0: + try: + sms = get_next_sms(state_machine, sms) + except gammu.ERR_EMPTY: + # This error is raised when we've reached last entry + # It can happen when reported status does not match real counts + print("Failed to read all messages!") + break + remain -= len(sms) + + for message in sms: + print() + print(f"{'Number':<15}: {message['Number']}") + print(f"{'Date':<15}: {message['DateTime']!s}") + print(f"{'State':<15}: {message['State']}") + print(f"\n{message['Text']}") if __name__ == "__main__": diff --git a/examples/getallsms_decode.py b/examples/getallsms_decode.py index e4baed113..fa4cf3e2e 100755 --- a/examples/getallsms_decode.py +++ b/examples/getallsms_decode.py @@ -23,6 +23,13 @@ import gammu + +def get_next_sms(state_machine, previous): + if previous is None: + return state_machine.GetNextSMS(Start=True, Folder=0) + return state_machine.GetNextSMS(Location=previous[0]["Location"], Folder=0) + + state_machine = gammu.StateMachine() state_machine.ReadConfig() state_machine.Init() @@ -32,21 +39,18 @@ remain = status["SIMUsed"] + status["PhoneUsed"] + status["TemplatesUsed"] sms = [] -start = True +current_sms = None -try: - while remain > 0: - if start: - cursms = state_machine.GetNextSMS(Start=True, Folder=0) - start = False - else: - cursms = state_machine.GetNextSMS(Location=cursms[0]["Location"], Folder=0) - remain -= len(cursms) - sms.append(cursms) -except gammu.ERR_EMPTY: - # This error is raised when we've reached last entry - # It can happen when reported status does not match real counts - print("Failed to read all messages!") +while remain > 0: + try: + current_sms = get_next_sms(state_machine, current_sms) + except gammu.ERR_EMPTY: + # This error is raised when we've reached last entry + # It can happen when reported status does not match real counts + print("Failed to read all messages!") + break + remain -= len(current_sms) + sms.append(current_sms) data = gammu.LinkSMS(sms) diff --git a/examples/savesmspercontact.py b/examples/savesmspercontact.py index 8bd90bf08..8dbe08c17 100755 --- a/examples/savesmspercontact.py +++ b/examples/savesmspercontact.py @@ -69,43 +69,51 @@ def saveSMS(mysms, all_contacts) -> None: handle.write("\n") +def getNextMemory(state_machine, previous): + if previous is None: + return state_machine.GetNextMemory(Start=True, Type="SM") + return state_machine.GetNextMemory(Location=previous["Location"], Type="SM") + + def getContacts(state_machine): # Get all contacts remaining = state_machine.GetMemoryStatus(Type="SM")["Used"] contacts = {} - start = True + memory_entry = None + + while remaining > 0: + first = memory_entry is None + try: + memory_entry = getNextMemory(state_machine, memory_entry) + except gammu.ERR_EMPTY: + # error is raised if memory is empty (this induces wrong reported + # memory status) + print("Failed to read contacts!") + break + if not first: + remaining -= 1 - try: - while remaining > 0: - if start: - memory_entry = state_machine.GetNextMemory(Start=True, Type="SM") - start = False + numbers = [] + name = "Unknown" + for entry in memory_entry["Entries"]: + if entry["Type"] == "Text_FirstName": + name = entry["Value"] else: - memory_entry = state_machine.GetNextMemory( - Location=memory_entry["Location"], Type="SM" - ) - remaining -= 1 - - numbers = [] - name = "Unknown" - for entry in memory_entry["Entries"]: - if entry["Type"] == "Text_FirstName": - name = entry["Value"] - else: - numbers.append(getInternationalizedNumber(entry["Value"])) - - for number in numbers: - contacts[number] = name - - except gammu.ERR_EMPTY: - # error is raised if memory is empty (this induces wrong reported - # memory status) - print("Failed to read contacts!") + numbers.append(getInternationalizedNumber(entry["Value"])) + + for number in numbers: + contacts[number] = name return contacts +def getNextSMS(state_machine, previous): + if previous is None: + return state_machine.GetNextSMS(Folder=0, Start=True) + return state_machine.GetNextSMS(Folder=0, Location=previous[0]["Location"]) + + def getAndDeleteAllSMS(state_machine): # Read SMS memory status ... memory = state_machine.GetSMSStatus() @@ -113,29 +121,22 @@ def getAndDeleteAllSMS(state_machine): remaining = memory["SIMUsed"] + memory["PhoneUsed"] # Get all sms - start = True entries = [] + entry = None - try: - while remaining > 0: - if start: - entry = state_machine.GetNextSMS(Folder=0, Start=True) - start = False - else: - entry = state_machine.GetNextSMS( - Folder=0, Location=entry[0]["Location"] - ) - + while remaining > 0: + try: + entry = getNextSMS(state_machine, entry) remaining -= 1 entries.append(entry) # delete retrieved sms state_machine.DeleteSMS(Folder=0, Location=entry[0]["Location"]) - - except gammu.ERR_EMPTY: - # error is raised if memory is empty (this induces wrong reported - # memory status) - print("Failed to read messages!") + except gammu.ERR_EMPTY: + # error is raised if memory is empty (this induces wrong reported + # memory status) + print("Failed to read messages!") + break # Link all SMS when there are concatenated messages return gammu.LinkSMS(entries) diff --git a/gammu/asyncworker.py b/gammu/asyncworker.py index ebe518ab0..8477dd5fe 100644 --- a/gammu/asyncworker.py +++ b/gammu/asyncworker.py @@ -36,12 +36,7 @@ def _do_command(self, future, cmd, params, percentage=100) -> None: func = getattr(self._sm, cmd) result = None try: - if params is None: - result = func() - elif isinstance(params, dict): - result = func(**params) - else: - result = func(*params) + result = gammu.worker._execute_command(func, params) except gammu.GSMError as info: errcode = info.args[0]["Code"] error = gammu.ErrorNumbers[errcode] diff --git a/gammu/worker.py b/gammu/worker.py index eee6143b7..e0373c12e 100644 --- a/gammu/worker.py +++ b/gammu/worker.py @@ -134,6 +134,14 @@ def gammu_pull_device(state_machine) -> None: state_machine.ReadDevice() +def _execute_command(func, params): + if params is None: + return func() + if isinstance(params, dict): + return func(**params) + return func(*params) + + class GammuThread(threading.Thread): """Thread for phone communication.""" @@ -171,18 +179,43 @@ def _do_command(self, name, cmd, params, percentage=100) -> None: error = "ERR_NONE" result = None try: - if params is None: - result = func() - elif isinstance(params, dict): - result = func(**params) - else: - result = func(*params) + result = _execute_command(func, params) except gammu.GSMError as info: errcode = info.args[0]["Code"] error = gammu.ErrorNumbers[errcode] self._callback(name, result, error, percentage) + def _do_next_command(self, task) -> None: + cmd = task.get_next() + self._do_command( + task.get_name(), + cmd.get_command(), + cmd.get_params(), + cmd.get_percentage(), + ) + + def _finish_task(self, task) -> None: + try: + if task.get_name() != "Init": + self._queue.task_done() + except (AttributeError, ValueError): + # Ignore malformed tasks and duplicate queue acknowledgements. + pass + + def _do_task(self, task) -> None: + try: + while True: + self._do_next_command(task) + except IndexError: + self._finish_task(task) + + def _get_task(self, start): + if start: + return GammuTask("Init", ["Init"]) + # Wait at most ten seconds for next command + return self._queue.get(True, 10) + def run(self) -> None: """ Thread body, which handles phone communication. @@ -192,27 +225,9 @@ def run(self) -> None: start = True while not self._kill: try: - if start: - task = GammuTask("Init", ["Init"]) - start = False - else: - # Wait at most ten seconds for next command - task = self._queue.get(True, 10) - try: - while True: - cmd = task.get_next() - self._do_command( - task.get_name(), - cmd.get_command(), - cmd.get_params(), - cmd.get_percentage(), - ) - except IndexError: - try: - if task.get_name() != "Init": - self._queue.task_done() - except (AttributeError, ValueError): - pass + task = self._get_task(start) + start = False + self._do_task(task) except queue.Empty: if self._terminate: break