Change in pysim[master]: Improve performance of AT command interface

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Falkenber9 gerrit-no-reply at lists.osmocom.org
Sun May 2 08:21:39 UTC 2021


Falkenber9 has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/24034 )


Change subject: Improve performance of AT command interface
......................................................................

Improve performance of AT command interface

Previous implementation waits 300ms for response after
each command issued. But many commands finish earlier.

This patch improves the command execution time by frequently
checking for the response to complete (i.e. ends with
OK or ERROR), or the occurence of a timeout (default 200ms).

Timeout can be adapted per command to support long response
times of certain commands like AT+COPS=? (network search)

Change-Id: I69b1cbc0a20d54791e5800bf27ebafc2c8606d93
---
A benchmark_at.py
M pySim/transport/modem_atcmd.py
2 files changed, 105 insertions(+), 6 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/34/24034/1

diff --git a/benchmark_at.py b/benchmark_at.py
new file mode 100755
index 0000000..ca6095b
--- /dev/null
+++ b/benchmark_at.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python3
+
+import logging as log
+import time
+from pySim.transport.modem_atcmd import ModemATCommandLink
+
+#log.root.setLevel(log.DEBUG)
+
+tty = "/dev/ttyUSB2"
+
+# Use old code
+tt = time.time()
+tp = time.process_time()
+modem = ModemATCommandLink(tty)
+for i in range(10):
+    modem.send_at_cmd_old("ATI")
+    modem.send_at_cmd_old("AT+CIMI")
+print("Old execution time: {:.6f}s (CPU: {:.6f}s)".format(time.time() - tt, time.process_time() - tp))
+
+# Use new code
+tt = time.time()
+tp = time.process_time()
+modem = ModemATCommandLink(tty)
+for i in range(10):
+    modem.send_at_cmd("ATI")
+    modem.send_at_cmd("AT+CIMI")
+print("New execution time: {:.6f}s (CPU: {:.6f}s)".format(time.time() - tt, time.process_time() - tp))
+
+# Use new code for long-term command (i.e. network search)
+# tt = time.time()
+# tp = time.process_time()
+# modem.send_at_cmd("AT+COPS=?", timeout=60)
+# print("Network search: {:.6f}s (CPU: {:.6f}s)".format(time.time() - tt, time.process_time() - tp))
diff --git a/pySim/transport/modem_atcmd.py b/pySim/transport/modem_atcmd.py
index eef38cb..55f3a00 100644
--- a/pySim/transport/modem_atcmd.py
+++ b/pySim/transport/modem_atcmd.py
@@ -32,16 +32,64 @@
 	def __init__(self, device:str='/dev/ttyUSB0', baudrate:int=115200, **kwargs):
 		super().__init__(**kwargs)
 		self._sl = serial.Serial(device, baudrate, timeout=5)
+		self._echo = False		# this will be auto-detected by _check_echo()
 		self._device = device
 		self._atr = None
 
+		# Check the AT interface
+		self._check_echo()
+
 		# Trigger initial reset
 		self.reset_card()
 
 	def __del__(self):
 		self._sl.close()
 
-	def send_at_cmd(self, cmd):
+	def send_at_cmd(self, cmd, timeout=0.2, patience=0.002):
+		# Convert from string to bytes, if needed
+		bcmd = cmd if type(cmd) is bytes else cmd.encode()
+		bcmd += b'\r'
+
+		# Clean input buffer from previous/unexpected data
+		self._sl.reset_input_buffer()
+
+		# Send command to the modem
+		log.debug('Sending AT command: {}'.format(cmd))
+		try:
+			wlen = self._sl.write(bcmd)
+			assert(wlen == len(bcmd))
+		except:
+			raise ReaderError('Failed to send AT command: {}'.format(cmd))
+
+		rsp = b''
+		its = 1
+		t_start = time.time()
+		while True:
+			rsp = rsp + self._sl.read(self._sl.in_waiting)
+			if rsp.endswith(b'OK\r\n'):
+				log.debug('Command finished with result: OK')
+				break
+			if rsp.endswith(b'ERROR\r\n'):
+				log.debug('Command finished with result: ERROR')
+				break
+			if time.time() - t_start >= timeout:
+				log.debug('Command finished with timeout >= {}s'.format(timeout))
+				break
+			else:
+				time.sleep(patience)
+				its += 1
+		log.debug('Command took {:.6f}s ({} cycles a {}s)'.format(time.time() - t_start, its, patience))
+
+		if self._echo:
+			# Skip echo chars
+			rsp = rsp[wlen:]
+		rsp = rsp.strip()
+		rsp = rsp.split(b'\r\n\r\n')
+
+		log.debug('Got response from modem: {}'.format(rsp))
+		return rsp
+
+	def send_at_cmd_old(self, cmd):
 		# Convert from string to bytes, if needed
 		bcmd = cmd if type(cmd) is bytes else cmd.encode()
 		bcmd += b'\r'
@@ -74,11 +122,29 @@
 		log.debug('Got response from modem: %s' % rsp)
 		return rsp
 
-	def reset_card(self):
-		# Make sure that we can talk to the modem
-		if self.send_at_cmd('AT') != [b'OK']:
-			raise ReaderError('Failed to connect to modem')
+	def _check_echo(self):
+		"""Verify the correct response to 'AT' command
+		and detect if inputs are echoed by the device
 
+		Although echo of inputs can be enabled/disabled via
+		ATE1/ATE0, respectively, we rather detect the current
+		configuration of the modem without any change.
+		"""
+		# Next command shall not strip the echo from the response
+		self._echo = False
+		result = self.send_at_cmd('AT')
+
+		# Verify the response
+		if len(result) > 0:
+			if result[-1] == b'OK':
+				self._echo = False
+				return
+			elif result[-1] == b'AT\r\r\nOK':
+				self._echo = True
+				return
+		raise ReaderError('Interface "{}" does not respond to "AT" command'.format(self._device))
+
+	def reset_card(self):
 		# Reset the modem, just to be sure
 		if self.send_at_cmd('ATZ') != [b'OK']:
 			raise ReaderError('Failed to reset the modem')
@@ -87,7 +153,7 @@
 		if self.send_at_cmd('AT+CSIM=?') != [b'OK']:
 			raise ReaderError('The modem does not seem to support SIM access')
 
-		log.info('Modem at \'%s\' is ready!' % self._device)
+		log.info('Modem at "{}" is ready!'.format(self._device))
 
 	def connect(self):
 		pass # Nothing to do really ...

-- 
To view, visit https://gerrit.osmocom.org/c/pysim/+/24034
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I69b1cbc0a20d54791e5800bf27ebafc2c8606d93
Gerrit-Change-Number: 24034
Gerrit-PatchSet: 1
Gerrit-Owner: Falkenber9 <robert.falkenberg at tu-dortmund.de>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20210502/b9c40958/attachment.htm>


More information about the gerrit-log mailing list