From e21e49885e30d5a2728fc3a697d13c3bdf94dad9 Mon Sep 17 00:00:00 2001 From: Dominic Amato <dom@hologram.io> Date: Fri, 3 Jan 2020 12:05:13 -0600 Subject: [PATCH] Add chunking for messeages over 512 bytes (#15) --- Hologram/Network/Modem/Modem.py | 25 ++++++++++++++++--------- tests/Modem/test_Modem.py | 29 +++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/Hologram/Network/Modem/Modem.py b/Hologram/Network/Modem/Modem.py index 5b19d56..3f5d710 100644 --- a/Hologram/Network/Modem/Modem.py +++ b/Hologram/Network/Modem/Modem.py @@ -289,7 +289,6 @@ def connect_socket(self, host, port): self.logger.info('Connect socket is successful') def listen_socket(self, port): - at_command_val = "%d,%s" % (self.socket_identifier, port) self.listen_socket_identifier = self.socket_identifier ok, _ = self.set('+USOLI', at_command_val, timeout=5) @@ -298,17 +297,25 @@ def listen_socket(self, port): raise NetworkError('Failed to listen socket') def write_socket(self, data): - self.enable_hex_mode() - value = b'%d,%d,\"%s\"' % (self.socket_identifier, - len(data), - binascii.hexlify(data)) - ok, _ = self.set('+USOWR', value, timeout=10) - if ok != ModemResult.OK: - self.logger.error('Failed to write to socket') - raise NetworkError('Failed to write socket') + hexdata = binascii.hexlify(data) + # We have to do it in chunks of 510 since 512 is actually too long (CMEE error) + # and we need 2n chars for hexified data + for chunk in self._chunks(hexdata, 510): + value = b'%d,%d,\"%s\"' % (self.socket_identifier, + len(binascii.unhexlify(chunk)), + chunk) + ok, _ = self.set('+USOWR', value, timeout=10) + if ok != ModemResult.OK: + self.logger.error('Failed to write to socket') + raise NetworkError('Failed to write socket') self.disable_hex_mode() + def _chunks(self, data, n): + """Yield successive n-sized chunks from lst.""" + for i in range(0, len(data), n): + yield data[i:i + n] + def read_socket(self, socket_identifier=None, payload_length=None): if socket_identifier is None: diff --git a/tests/Modem/test_Modem.py b/tests/Modem/test_Modem.py index dc6cf2d..9cd540a 100644 --- a/tests/Modem/test_Modem.py +++ b/tests/Modem/test_Modem.py @@ -32,6 +32,9 @@ def mock_open_serial_port(modem, device_name=None): def mock_close_serial_port(modem): return True +def mock_result(modem): + return (ModemResult.OK, None) + def mock_detect_usable_serial_port(modem, stop_on_first=True): return '/dev/ttyUSB0' @@ -54,9 +57,14 @@ def no_serial_port(monkeypatch): def get_sms(monkeypatch): monkeypatch.setattr(Modem, 'command', mock_command_sms) monkeypatch.setattr(Modem, 'set', mock_set_sms) +def override_command_result(monkeypatch): + monkeypatch.setattr(Modem, '_command_result', mock_result) -# CONSTRUCTOR +@pytest.fixture +def override_command_result(monkeypatch): + monkeypatch.setattr(Modem, '_command_result', mock_result) +# CONSTRUCTOR def test_init_modem_no_args(no_serial_port): modem = Modem() @@ -80,10 +88,8 @@ def test_get_result_string(no_serial_port): assert(modem.getResultString(-3) == 'Modem response doesn\'t match expected return value') assert(modem.getResultString(-99) == 'Unknown response code') - # PROPERTIES - def test_get_location(no_serial_port): modem = Modem() with pytest.raises(NotImplementedError) as e: @@ -99,8 +105,19 @@ def test_get_sms(no_serial_port, get_sms): assert(res.timestamp == datetime.utcfromtimestamp(1498264009)) assert(res.message == 'Test 123') -# DEBUGWRITE +# WRITE SOCKET + +def test_socket_write_under_512(no_serial_port, override_command_result): + modem = Modem() + data = '{message:{fill}{align}{width}}'.format(message='Test-', fill='@', align='<', width=64) + modem.write_socket(data.encode()) + +def test_socket_write_over_512(no_serial_port, override_command_result): + modem = Modem() + data = '{message:{fill}{align}{width}}'.format(message='Test-', fill='@', align='<', width=600) + modem.write_socket(data.encode()) +# DEBUGWRITE def test_debugwrite(no_serial_port): modem = Modem() @@ -111,10 +128,8 @@ def test_debugwrite(no_serial_port): modem.debugwrite('test222', hide=True) assert(modem.debug_out == 'test') # debug_out shouldn't change since hide is enabled. - # MODEMWRITE - def test_modemwrite(no_serial_port): modem = Modem() assert(modem.debug_out == '') @@ -136,7 +151,6 @@ def test_modemwrite(no_serial_port): modem.modemwrite('test5', start=True, at=True, seteq=True, read=True, end=True) assert(modem.debug_out == '[ATtest5=?]') - # COMMAND_RESULT def test_command_result(no_serial_port): @@ -193,7 +207,6 @@ def test_command_result(no_serial_port): # HANDLEURC - # These are static methods that can be tested independently. # We decided to wrap it all here under this test object class TestModemProtectedStaticMethods():