From f517b1df5083ddc158c075852d7f2497480b0d84 Mon Sep 17 00:00:00 2001 From: Islam Wahdan Date: Tue, 28 Aug 2018 23:19:57 +0200 Subject: [PATCH] New Stable Release v1.18.1 (#199) * esp32: Added New scripts and updates for Sequans LTE modem firmware Upgrading * New Stable Version v1.18.1 - Added Updated Scripts for Sequans LTE modem as frozen code. - Added support for upgrading Sequans modem over Uart. * py/mkrules.mk: fixed error --- esp32/frozen/{ => Base}/_boot.py | 0 esp32/frozen/{ => Base}/_main.py | 0 esp32/frozen/{ => Common}/MQTTClient.py | 0 esp32/frozen/{ => Common}/MQTTConst.py | 0 esp32/frozen/{ => Common}/MQTTDeviceShadow.py | 0 esp32/frozen/{ => Common}/MQTTLib.py | 0 esp32/frozen/{ => Common}/MQTTMsgHandler.py | 0 .../frozen/{ => Common}/MQTTShadowManager.py | 0 esp32/frozen/LTE/sqnsbr.py | 45 ++ esp32/frozen/LTE/sqnscodec.py | 86 +++ esp32/frozen/LTE/sqnscrc.py | 58 ++ esp32/frozen/LTE/sqnstp.py | 397 ++++++++++++ esp32/frozen/LTE/sqnsupgrade.py | 603 ++++++++++++++++++ esp32/lte/lteppp.c | 26 +- esp32/lte/lteppp.h | 4 + esp32/main.c | 1 + esp32/mods/modlte.c | 148 ++++- esp32/mods/modpycom.c | 10 + esp32/mptask.c | 5 + esp32/pycom_config.c | 11 + esp32/pycom_config.h | 10 +- esp32/pycom_version.h | 2 +- py/mkrules.mk | 35 +- 23 files changed, 1433 insertions(+), 8 deletions(-) rename esp32/frozen/{ => Base}/_boot.py (100%) rename esp32/frozen/{ => Base}/_main.py (100%) rename esp32/frozen/{ => Common}/MQTTClient.py (100%) rename esp32/frozen/{ => Common}/MQTTConst.py (100%) rename esp32/frozen/{ => Common}/MQTTDeviceShadow.py (100%) rename esp32/frozen/{ => Common}/MQTTLib.py (100%) rename esp32/frozen/{ => Common}/MQTTMsgHandler.py (100%) rename esp32/frozen/{ => Common}/MQTTShadowManager.py (100%) create mode 100644 esp32/frozen/LTE/sqnsbr.py create mode 100644 esp32/frozen/LTE/sqnscodec.py create mode 100644 esp32/frozen/LTE/sqnscrc.py create mode 100644 esp32/frozen/LTE/sqnstp.py create mode 100644 esp32/frozen/LTE/sqnsupgrade.py diff --git a/esp32/frozen/_boot.py b/esp32/frozen/Base/_boot.py similarity index 100% rename from esp32/frozen/_boot.py rename to esp32/frozen/Base/_boot.py diff --git a/esp32/frozen/_main.py b/esp32/frozen/Base/_main.py similarity index 100% rename from esp32/frozen/_main.py rename to esp32/frozen/Base/_main.py diff --git a/esp32/frozen/MQTTClient.py b/esp32/frozen/Common/MQTTClient.py similarity index 100% rename from esp32/frozen/MQTTClient.py rename to esp32/frozen/Common/MQTTClient.py diff --git a/esp32/frozen/MQTTConst.py b/esp32/frozen/Common/MQTTConst.py similarity index 100% rename from esp32/frozen/MQTTConst.py rename to esp32/frozen/Common/MQTTConst.py diff --git a/esp32/frozen/MQTTDeviceShadow.py b/esp32/frozen/Common/MQTTDeviceShadow.py similarity index 100% rename from esp32/frozen/MQTTDeviceShadow.py rename to esp32/frozen/Common/MQTTDeviceShadow.py diff --git a/esp32/frozen/MQTTLib.py b/esp32/frozen/Common/MQTTLib.py similarity index 100% rename from esp32/frozen/MQTTLib.py rename to esp32/frozen/Common/MQTTLib.py diff --git a/esp32/frozen/MQTTMsgHandler.py b/esp32/frozen/Common/MQTTMsgHandler.py similarity index 100% rename from esp32/frozen/MQTTMsgHandler.py rename to esp32/frozen/Common/MQTTMsgHandler.py diff --git a/esp32/frozen/MQTTShadowManager.py b/esp32/frozen/Common/MQTTShadowManager.py similarity index 100% rename from esp32/frozen/MQTTShadowManager.py rename to esp32/frozen/Common/MQTTShadowManager.py diff --git a/esp32/frozen/LTE/sqnsbr.py b/esp32/frozen/LTE/sqnsbr.py new file mode 100644 index 0000000000..530584de18 --- /dev/null +++ b/esp32/frozen/LTE/sqnsbr.py @@ -0,0 +1,45 @@ +class bootrom(object): + import binascii + + def __init__(self): + self.__fpointer = 0 + self.__size = len(self.BOOTROM) + + def open(self, filename='', mode='r'): + self.__fpointer = 0 + + def close(self): + self.__fpointer = 0 + + def tell(self): + return self.__fpointer + + def seek(self, offset, start=0): + if start == 1: + start = self.__fpointer + elif start == 2: + start = self.__size + if start + offset < 0: + raise OSError(22,'Invalid argument') + else: + self.__fpointer = start + offset + return self.__fpointer + + def get_size(self): + return self.__size + + def read(self, size=0): + if size == 0: + size = self.__size - self.__fpointer + if self.__fpointer >= self.__size: + return b'' + else: + fpointer = self.__fpointer + self.__fpointer = fpointer + size + + if fpointer + size >= self.__size: + return self.BOOTROM[fpointer:self.__size] + else: + return self.BOOTROM[fpointer:self.__fpointer] + + BOOTROM=binascii.a2b_base64(b"""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AABVbmtvd24gZmxhc2ggSUQgMHgleAoAAABbR1BJT10gRXJyb3I6IEhBTCBpbml0IGZhaWxlZAoAAABgGMAAYBtwAGAabABgFogAYBp2AGAZcFdBUk5JTkc6IEZsb3cgY29udHJvbCBwcmV2ZW50cyB0byBzZW5kIGRhdGEgb24gdWFydCVkCgAAcHNkAHBzaQAA/yMARXJyb3I6IEZsYXNoIGlzIG5vdCBpbiBxdWFkIG1vZGUsIGl0IG1heSBiZSB1bnN1cHBvcnRlZAoAAAAAc2JwOiBCb290aW5nIGF0ICVwLi4uCgAAc2RtYS5jAABfZmlmbwAAAEJMOiBXYXRjaGRvZyB0aW1lb3V0IQoAAGluY29ycmVjdCBoZWFkZXIgY2hlY2sAAHVua25vd24gY29tcHJlc3Npb24gbWV0aG9kAABpbnZhbGlkIHdpbmRvdyBzaXplAHVua25vd24gaGVhZGVyIGZsYWdzIHNldAAAAABoZWFkZXIgY3JjIG1pc21hdGNoAGludmFsaWQgYmxvY2sgdHlwZQAAaW52YWxpZCBzdG9yZWQgYmxvY2sgbGVuZ3RocwAAAAB0b28gbWFueSBsZW5ndGggb3IgZGlzdGFuY2Ugc3ltYm9scwBpbnZhbGlkIGNvZGUgbGVuZ3RocyBzZXQAAAAAaW52YWxpZCBiaXQgbGVuZ3RoIHJlcGVhdAAAAGludmFsaWQgY29kZSAtLSBtaXNzaW5nIGVuZC1vZi1ibG9jawAAAABpbnZhbGlkIGxpdGVyYWwvbGVuZ3RocyBzZXQAaW52YWxpZCBkaXN0YW5jZXMgc2V0AAAAaW52YWxpZCBsaXRlcmFsL2xlbmd0aCBjb2RlAGludmFsaWQgZGlzdGFuY2UgY29kZQAAAGludmFsaWQgZGlzdGFuY2UgdG9vIGZhciBiYWNrAAAAaW5jb3JyZWN0IGRhdGEgY2hlY2sAAAAAaW5jb3JyZWN0IGxlbmd0aCBjaGVjawAAEAUAARcFAQETBQARGwUQAREFAAUZBQQBFQUAQR0FQAEQBQADGAUCARQFACEcBSABEgUACRoFCAEWBQCBQAUAABAFAAIXBQGBEwUAGRsFGAERBQAHGQUGARUFAGEdBWABEAUABBgFAwEUBQAxHAUwARIFAA0aBQwBFgUAwUAFAABgBwAAAAgAUAAIABAUCABzEgcAHwAIAHAACAAwAAkAwBAHAAoACABgAAgAIAAJAKAACAAAAAgAgAAIAEAACQDgEAcABgAIAFgACAAYAAkAkBMHADsACAB4AAgAOAAJANARBwARAAgAaAAIACgACQCwAAgACAAIAIgACABIAAkA8BAHAAQACABUAAgAFBUIAOMTBwArAAgAdAAIADQACQDIEQcADQAIAGQACAAkAAkAqAAIAAQACACEAAgARAAJAOgQBwAIAAgAXAAIABwACQCYFAcAUwAIAHwACAA8AAkA2BIHABcACABsAAgALAAJALgACAAMAAgAjAAIAEwACQD4EAcAAwAIAFIACAASFQgAoxMHACMACAByAAgAMgAJAMQRBwALAAgAYgAIACIACQCkAAgAAgAIAIIACABCAAkA5BAHAAcACABaAAgAGgAJAJQUBwBDAAgAegAIADoACQDUEgcAEwAIAGoACAAqAAkAtAAIAAoACACKAAgASgAJAPQQBwAFAAgAVgAIABZACAAAEwcAMwAIAHYACAA2AAkAzBEHAA8ACABmAAgAJgAJAKwACAAGAAgAhgAIAEYACQDsEAcACQAIAF4ACAAeAAkAnBQHAGMACAB+AAgAPgAJANwSBwAbAAgAbgAIAC4ACQC8AAgADgAIAI4ACABOAAkA/GAHAAAACABRAAgAERUIAIMSBwAfAAgAcQAIADEACQDCEAcACgAIAGEACAAhAAkAogAIAAEACACBAAgAQQAJAOIQBwAGAAgAWQAIABkACQCSEwcAOwAIAHkACAA5AAkA0hEHABEACABpAAgAKQAJALIACAAJAAgAiQAIAEkACQDyEAcABAAIAFUACAAVEAgBAhMHACsACAB1AAgANQAJAMoRBwANAAgAZQAIACUACQCqAAgABQAIAIUACABFAAkA6hAHAAgACABdAAgAHQAJAJoUBwBTAAgAfQAIAD0ACQDaEgcAFwAIAG0ACAAtAAkAugAIAA0ACACNAAgATQAJAPoQBwADAAgAUwAIABMVCADDEwcAIwAIAHMACAAzAAkAxhEHAAsACABjAAgAIwAJAKYACAADAAgAgwAIAEMACQDmEAcABwAIAFsACAAbAAkAlhQHAEMACAB7AAgAOwAJANYSBwATAAgAawAIACsACQC2AAgACwAIAIsACABLAAkA9hAHAAUACABXAAgAF0AIAAATBwAzAAgAdwAIADcACQDOEQcADwAIAGcACAAnAAkArgAIAAcACACHAAgARwAJAO4QBwAJAAgAXwAIAB8ACQCeFAcAYwAIAH8ACAA/AAkA3hIHABsACABvAAgALwAJAL4ACAAPAAgAjwAIAE8ACQD+YAcAAAAIAFAACAAQFAgAcxIHAB8ACABwAAgAMAAJAMEQBwAKAAgAYAAIACAACQChAAgAAAAIAIAACABAAAkA4RAHAAYACABYAAgAGAAJAJETBwA7AAgAeAAIADgACQDREQcAEQAIAGgACAAoAAkAsQAIAAgACACIAAgASAAJAPEQBwAEAAgAVAAIABQVCADjEwcAKwAIAHQACAA0AAkAyREHAA0ACABkAAgAJAAJAKkACAAEAAgAhAAIAEQACQDpEAcACAAIAFwACAAcAAkAmRQHAFMACAB8AAgAPAAJANkSBwAXAAgAbAAIACwACQC5AAgADAAIAIwACABMAAkA+RAHAAMACABSAAgAEhUIAKMTBwAjAAgAcgAIADIACQDFEQcACwAIAGIACAAiAAkApQAIAAIACACCAAgAQgAJAOUQBwAHAAgAWgAIABoACQCVFAcAQwAIAHoACAA6AAkA1RIHABMACABqAAgAKgAJALUACAAKAAgAigAIAEoACQD1EAcABQAIAFYACAAWQAgAABMHADMACAB2AAgANgAJAM0RBwAPAAgAZgAIACYACQCtAAgABgAIAIYACABGAAkA7RAHAAkACABeAAgAHgAJAJ0UBwBjAAgAfgAIAD4ACQDdEgcAGwAIAG4ACAAuAAkAvQAIAA4ACACOAAgATgAJAP1gBwAAAAgAUQAIABEVCACDEgcAHwAIAHEACAAxAAkAwxAHAAoACABhAAgAIQAJAKMACAABAAgAgQAIAEEACQDjEAcABgAIAFkACAAZAAkAkxMHADsACAB5AAgAOQAJANMRBwARAAgAaQAIACkACQCzAAgACQAIAIkACABJAAkA8xAHAAQACABVAAgAFRAIAQITBwArAAgAdQAIADUACQDLEQcADQAIAGUACAAlAAkAqwAIAAUACACFAAgARQAJAOsQBwAIAAgAXQAIAB0ACQCbFAcAUwAIAH0ACAA9AAkA2xIHABcACABtAAgALQAJALsACAANAAgAjQAIAE0ACQD7EAcAAwAIAFMACAATFQgAwxMH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Rm9yY2VkIHRvIEZGSAoAAAAAJXMgaW1hZ2UgZmFpbGVkIHRvIGNvbXBsZXRlIGl0cyAzIGZpcnN0IGJvb3RzIHNvIGlzIG5vdCByZWxpYWJsZS4KAABGbGFzaCBhIG5ldyAlcyBpbWFnZSB0byBzb2x2ZSB0aGUgcHJvYmxlbQoAAGJvb3Q6ICVzIG1vZGUKAABVbmtvd24gYm9vdCBtb2RlICVkLCBmYWxsYmFja2luZyB0byBGRkYKAAAAAEZhaWxlZCB0byBzZXQgZGlydHkgYm9vdAoAAABib290U3JjX2dlcmJpbC5jAAAAAF9wb29sLmZyZWUgPCAzAAAhX3Bvb2wucG9vbFtfcG9vbC5mcmVlXQBQb29sIGVtcHR5CgBfcG9vbC5mcmVlIDw9IDMAcAAAAEVycm9yOiBhbGxvY2F0aW9uIGZhaWx1cmUgKCVkIGJ5dGVzKSwgY2FuJ3QgYWxsb2NhdGUgYmxvY2tzIG9mIG1vcmUgdGhhdCAlZCBieXRlcwoAAEZGRgBGRkgAVVBEQVRFUgBSRUNPVkVSWQAAAAAAYJ94AGCffABgn4AAYJ+IY29uc29sZQBTaHV0ZG93bgoAAABNT0RVTEVfRlNUX1NIVVRET1dOAHVhcnQwX2N0c19uAHVhcnQxX2N0c19uAGJvb3Q6IENhbid0IGFsbG9jYXRlIG1lbW9yeSBmb3IgZXh0IGJvb3QgQUJJIGRlc2NyaXB0b3IKAAAAAFJ1bm5pbmcgb24gJXMgZmxhc2ggZmFpbHNhZmUgc2VjdG9yCgAAAABSdW5uaW5nIG9uICVzIGZsYXNoIHNlY3RvciAlcAoAAFdBUk5JTkc6IGNvcnJ1cHRlZCBib290IHNlY3RvcnMgcHJlc2VudAoAAAAAW2Z3IHBhbmljXQAAUkJHZXJiaWwgJWQuJWRAJWQgJzUuMS4xLjAgWzM4NjM4XScKAAAAAFJlc2V0IGNhdXNlICclcycocmVhbCAnJXMnICklcyAoYm9vdFdERyA6ICclZCcpIFtyYXdSc3QgJzB4JTA4eCddCgAATlZSQU0gQm9vdCBTdGF0dXMgJyVzJwoATG9hZGVkIHZpYSBKVEFHCgAAAAByZWdDb25maWcgJXBAJWQKAAAAAGJvb3RMb2FkZXIuYwAAAABOb3RoaW5nIHRvIGJvb3QgZnJvbQAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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NE1MT1l5QUp3SEVnQ2NSTURBd00KU0F3TURFM0lEWTFOVE0xR0E4TUJrd2dyZ3dzNWxJQW5BY1NBSnhFd01EQXhJREF3TXpRZ05qVTFNelVZQzRZQwprMGdyZ3dzNW5JQW5BV0pBRTRpWUdCZ1lrQmdZR1pxUUd4cWFtWnFNQmNNQlNjUVZ3WVdjMGtBVGdMRWdDY1JNCkRBd01TQXdNRFk0SURZMU5UTTFHQXVHQXBQSUs0TUxPYXlBSndGaVFCT0ltQmdZR0pBWUdCdVprQnNhbXBtYWoKRVRBd01ETWdNREV6T0NBMk5UVXpOUmdLVEJCWEJoWnphUUJPQXNTQUp3R1l3R2d3RkprZ3Jnd3M1dklBbkFXSgpBRTRETVlEUVlDazBRVndZV2M0a0FUaUpnWUdCZ1FHQmthbVpBYkdwcVptcVFCT0FwTmtKYzNGdVJISnBkbVdRClp5WVc1blpjWk5qVTFNelVnTmpVMU16VWdOalUxTXpVZ05qVTFNelV1UUI2Qm1SZ0tsWUN0TEFXREFXakFYREEKVW1HQXNHQXZHQXVHQXBMc0JZTUJnTUJjTUJTV1lDd1lERVlDNFlDa3F3Rmd3R1F3Rnd3RkpSZ0xCaUpnWUdCaQpRR0JnYm1KQWJHcHFabW94RXdNREF6SURBeE16Y2dOalUxTXpVWUNrbXdGZ3dIQXdISXdGSkpnTEJnT0JnT1JnCktTTEFhakFVa0dBMkxFRE16QVZLd0ZhV0FzR0F0R0F1R0FwTU1CWU1CZU1CY01CU1hZQ3dZREFZQzRZQ2tzd0YKZ3dHSXdGd3dGSlZnTEJnTWhnTGhnS1NqQVdERVRBd01ERWdNREUxTUNBMk5UVXpOUmlKZ1lHQm1RR0JpWm14QQpiR3BxWm1vd0ZKTmdMQmdPeGdQQmdLU1RBV0RBZGpBZURBVWtXQTFHQXBJTUJzV0lDQXdGU3NCV2xnTEJnTFJnCkxoZ0tUREFXREFYakFYREFVbDJBc0dBd0dBdUdBcExNQllNQmlNQmNNQlNWWUN3WURJWUM0WUNrb3dGZ3dIWXcKSGd3RkpOZ0xCZ094Z1BCZ0tTVEFXREFkakFlREFVa1dBMUdBcElNQnNXSUdhbUFxVmdLMHNSTURBd01DQXdNVApZMElEWTFOVE0xR0F0R0F1R0FwTU1COE1STURBd01TQXdNREF4SURZMU5UTTFHQXVHQXBMc0I4TVJNREF3TVNBCndNRE16SURZMU5UTTFHQW5EQVNTekFYaGdLSXdFNFlDU1ZZQzhNUk1EQXdNU0F3TURNM0lEWTFOVE0xR0FuREEKU1NqQVhoZ0xBeEV3TURBeklEQXhNemtnTmpVMU16VVlDU1RZQzhNQllHQXhEQVNTVEFYaGdMQXdHSVlDU1JZQwpxTUJKSU1CV0xFRE9EQVNsWUNXbGdMd3dFMFlDY01CSk1NQmVHQXZqQVRoZ0pKZGdMd3dHQVlDY01CSkxNQmVHCkFvakFUaGdKSlZnTHd3R0VZQ2NNQkpLTUJlR0ltQmdZR0pBWUdCcWJrQnNhbXBtYWpBWWhnSkpOZ0x3d0dRWUQKRU1CSkpNQmVHQXlEQVloZ0pKRmdLb3dFa2d3RllzUVF4TWpBU2xZQ1dsZ0x3d0UwWUNjTUJKTU1CZUdBdmpBVApoZ0pKZGdMd3dHQVlDY01CSkxNQmVHQW9qQVRoZ0pKVmdMd3dHRVlDY01CSktNQmVHQXNEQVRoZ0pKTmdMd3dGCmdZQ2NNQkpKTUJlR0FzREFUaGdKSkZnS293RWtnd0ZZc1FReE16QVNsWUNXbGdMd3dFMFlDY01CSk1NQmVHQXYKakFUaGdKSmRnTHd3R0FZQ2NNQkpMTUJlR0FvakFUaGdKSlZnTHd3R0VZQ2NNQkpLTUJlR0FzREFZaGdKSk5nTAp3d0ZnWURFTUJKSk1CZUdBc0RBWWhnSkpGZ0tvd0VrZ3dGWXNRUXhOREFTbFlDV2xnTHd3RTBZQ2NNQkpNTUJlCkdBdmpBVGhnSkpkZ0x3d0dBWUNjTUJKTE1CZUdBb2pBVGhnSkpWZ0x3d0dFWUNjTUJKS01CZUdBc0RBWWhnSkoKTmdMd3dGZ1lERU1CSkpNQmVHQXNEQVloZ0pKRmdLb3dFa2d3RllzUVF4TnpBU2xZQ1dsZ0x3d0UwWUNjTUJKTQpNQmVHQXZqQVRoZ0pKZGdMd3dHQVlDY01CSkxNQmVHQW9qQVRoZ0pKVmdMd3dHRVlDY01CSktNQmVHQXNEQVRoCmdKSk5nTHd3RmdZQ2NNQkpKTUJlR0FzREFUaGdKSkZnS293RWtnd0ZZc1FReE9EQVNsWUNXbGdMd3dFMFlDY00KQkpNTUJlR0F2akFUaGdKSmRnTHd3R0FZQ2NNQkpMTUJlR0FvakFUaGdKSlZnTHd3R0VZQ2NNQkpLTUJlR0FzRApBWWhnSkpOZ0x3d0ZnWURFTUJKSk1CZUdBc0RBWWhnSkpGZ0tvd0VrZ3dGWXNRUXhPVEFTbFlDV2xnTHd3RTBZCkNjTUJKTU1CZUdBdmpBVGhnSkpkZ0x3d0dBWUNjTUJKTE1CZUdBb2pBVGhnSkpWZ0x3d0dFWUNjTUJKS01CZUcKQXNEQVloZ0pKTmdMd3dGZ1lERU1CSkpNQmVHQXNEQVloZ0pKRmdLb3dFa2d3RllzUVF5TURBU2xZQ1dsZ0x3dwpFMFlDY01CSk1NQmVHQXZqQVRoZ0pKZGdMd3dHQVlDY01CSkxNQmVHQW9qQVRoZ0pKVmdMd3dHRVlDY01CSktNCkJlR0FzREFZaGdKSk5nTHd3RmdZREVNQkpKTUJlR0FzREFZaGdKSkZnS293RWtnd0ZZc1FReU5UQVNsWUNXbGcKSmd3RTBZQ2NNQkpNTUJNR0FuakFUaGdKSmRnSmd3RkFZQ2NNQkpMTUJNR0FvakFUaGdKSlZnSmd3RklZQ2NNQgpKS01CTUdBc0RBV1JnSkpOZ0pnd0ZnWUN5TUJKSk1CTUdBc0RBV1JnSkpGZ0tvd0VrZ3dGWXNRUXlOakFTbFlDCldsZ0x3d0UwWUNjTUJKTU1CZUdBdmpBVGhnSkpkZ0x3d0dBWUNjTUJKTE1CZUdBb2pBVGhnSkpWZ0x3d0dFWUMKY01CSktNQmVHQXNEQVloZ0pKTmdMd3dGZ1lERU1CSkpNQmVHQXNEQVloZ0pKRmdLb3dFa2d3RllzUVF5T0RBUwpsWUNXbGdMd3dFMFlDY01CSk1NQmVHQXZqQVRoZ0pKZGdMd3dHQVlDY01CSkxNQmVHQW9qQVRoZ0pKVmdMd3dHCkVZQ2NNQkpLTUJlR0FzREFZaGdKSk5nTHd3RmdZREVNQkpKTUJlR0FzREFZaGdKSkZnS293RWtnd0ZZc1FRMk4KakFTbFlDV2xnSmd3RTBZQ2NNQkpNTUJNR0FuakFUaGdKSmRnSmd3RkFZQ2NNQkpMTUJNR0FvakFUaGdKSlZnSgpnd0ZJWUNjTUJKS01CTUdBdGpBWEJnSkpOZ0pnd0ZzWUM0TUJKSk1CTUdBdGpBWEJnSkpGZ0tvd0VrZ3dGWXRzCmdyQzNPYnZJQVhBUWtnQnNCRFJBRDRDQ3lBSVlDSVFnQ21BaWxnSWhHQWlGU0FPSUNEU0FMd0VWaEEzUjRrQVQKZ0ppUUJPQWtuU0J1VHhJQW5FVEF3TURBZ01ERTBNQ0EyTlRVek5VZ0NjQkhHQW5EQVNUcEFLNWdJb1dBbURBUwpTREFjQmdJNHdFNFlDU2RJQmFNQkZDd0V3WUNTUVlEZ01CSEdBbkRBU1RwQUlCZ0lvV0FtREFTU0RBY0JnSTR3CkU0WUNTZElCZE1CRkN3RjRZQ1NRWWlZR0JnWUVCZ1ltcHNRR3hxYW1acU1CSEdBbkRBU1RwQU1aZ0lvV0F2REEKU1NEQWNSZ0k0d0U0WUNTZElCbE1CRkN3RjRZQ1NRWURpTUJIR0FuREFTVHBBTXhnSW9XQXZEQVNTREFjUmdJNAp3RTRZQ1NkSUJuTUJGQ3dGNFlDU1FZRGlNQkhHQW5EQVNUcEFOQmdJb1dBdkRBU1NEQWNSZ0k0d0U0WUNTZElCCnBNQkZDd0Y0WUNTUVlEaU1CSEdBbkRBU1RwQU5SZ0lvV0F2REFTU0RBY1JnSTR3RTRZQ1NkSUJyTUJGQ3dGNFkKQ1NRWURpTUJIR0FuREFTVHBBTmhnSW9XQW1EQVNTREFjQmdJNHdFNFlDU2RJQnRNQkZDd0Y0WUNTUVlEaU1CSApHQW5EQVNUcEFOeGdJb1dBdkRBU1NEQWNSZ0k0d0U0WUNTZElCdk1CRkN3RXdZQ1NRWURnTUJIR0FuREFTVHJVGW8RbYABAAUACVJFREJFTExZAIABABIABlBZQ09NAIABABYADUdFUkJJTC1SRURCRQCAAQAEAAhTUU4zMzMwAIABABEAK0ZJUFlfQjNCNEIxMkIxM0IyMEIyOF9CQkExLVJGQTMtU0tZNjgwMDEzMQA5PgEgAR4CwG4AAsAxAALAMgACwDMAAsBvAAAAAAAAAAAAAAAJGgEYAALAbQACAwACAgACAQAAAAAAAAAAAAAASU0BSwIlEgExDHVhcnQwX2N0c19uAAACAxIBMQx1YXJ0MF9ydHNfbgAAAgcSATEMdWFydDFfcnRzX24AAAIMEgExDHVhcnQyX3J0c19uAHETGRECuY5iMoNOAAKCrAAAAoHwAA8BEQkPAgMSgZwgAAIHCgMSh6lADxEGAogACogAD0E7AQdWWk0yMFEACQhTUU4zMzMwABkNR0VSQklMLVJFREJFACEXU0VRVUFOUyBDb21tdW5pY2F0aW9ucwAPWSsBKQq4oAAqBDEDYXQAAAIBKgUxCGNvbnNvbGUAAAICCrigACoEMQRkY3AAD2GMegGKcWdFTWMyVnhkV0Z1Y3pNek16QlFadFlXcHZjZ014eUR1ekszTWplNVpvaXF5V2FHSmFna0RHM3R6TTBzN3E1TUwKbzB0N2NRS2FpbkdabVptQkFnbUtDWmtDbWxySnNjR0JnWWxwbVlrQ2tZR0tRZGpiMjF0YjI2UTkwZUY5bllXbAp1WDNCdmNuUmZNTmZMVFk0T0RBZ0xUWTBPREFnTFRVNU1UQWdMVFV6TlRBZ0xUUTVOakFnTFRRek56QWdMVE0zCk5EQWdMVE13T0RBZ0xUSTBNVEFnTFRJd05UQWdMVEUzTXpBZ0xURTFNakFnTFRFek1qQWdMVEV3TXpBZ0xUZ3kKTUNBdE5qQXdTSHVqd3ZzN0MwdHkrNE43azZMNWpzQmFiSEJnWUVCYWFuSmlZRUJhYW1obVlFQmFhRzVtWUVCYQphR0p3WUVCYVpteG1ZRUJhWm1Ca1lFQmFaR3BvWUVCYVpHWnVZRUJhWkdKa1lFQmFZbkJ3WUVCYVltNWdZRUJhClltaHNZRUJhWW1SaVlFQmFZbUJrWUVCYWNHaGdpSHVqd3ZzN0MwdHkrNE43azZMNWxnT3lIdVR3dnM3QzB0eSsKNE43azZMNWhsSmtZR3BnUUdSc2FHQkFabVJtWUVCbWNHUmdRR2hvWm1CQWFtQmlZRUJxYW1aZ1FHeGdZR0NFUApjbmhmWjJGcGJsOXdiM0owWHpIS1RFM05EQWdNak15TUNBeU9UQXdJRE0xTWpBZ05ERXlNQ0EwTnpBd0lEVXlNCnpBZ05UYzJNRkllNVBDK3pzTFMzTDdnM3VUb3ZtV1VtSm9hbUJBWkdwaVlFQm1ZbUJnUUdac2NtQkFhR1JtWUUKQm9ibXhnUUdwb1ptQkFiR0pnWUxFRlltRnVaRkFuQURNOGhMZzN1VG92dHpxMjRDRWhUbzhMN0l3c2EreE4rQgptQ0lVNlBDKzNzek01c3JwZ01NaERnd3I3T3d0TGRraGFZbXB5WUVCaVpHNWdRR0p3Y21CQVpHUmdZRUJrYW1wCmdRR1J5WW1CQVlFQmdoRFhCaFgzUm9jbVZ6YUc5c1pNa0xURTROREFnTFRFME5qQWdMVGMxTUNBeU56VWdPVGcKd0lEUXdNREFnTkRBd01GSXM2UEMrNk1yYTRNcmt3dWpxNU1xKzNzek01c3JwZ2h1Wk1RNXllRjlpYjJGeVpGOQpzYjNOendVeU1EQnlMT1R3dnVqSzJ1REs1TUxvNnVUS3Z0N016T2JLNllJWkhLQ0RPak13c2JwaEpnUUdCQVlFCkJnZ1FNME1CQStBd2JBWUxnTWt3R2g0SWJtQXNCWUhBV2d3RnlCQkRFeU1CUWZBVUd3WXRNVEF3TGtoYVltNXEKWUVCaVlHcGdRR0pvWUdCQVpHSnVZRUJrYUhKZ1FHUndabUJBWUVCZ1RKQzB5TWpVd0lDMHhORGd3SUMwMk1EVQpnTXpJMUlEYzJNQ0EwTURBd0lEUXdNREFlQ0d4Z0xBV0J3UXhOd1lDNUFnaGlabUFvUGdLRFlDZ3VTRnBpYm1aCnFRR0ppYW1CQVltaGdha0JrWW1aZ1FHUm9abXBBWkc1aWFrQmdRR0JNa0xUSXlOakFnTFRFME9UQWdMVFl6TUMKQXlOelVnTmpJd0lEUXdNREFnTkRBd01CNEliSElzQllIQkRFMUJnTGtDQ0dSZ1lDZytBb05nTWk1SVdtSnVhbQpCQVltQnFZRUJpYUdCZ1FHUmlibUJBWkdoeVlFQmtibVpnUUdCQVlFd0dnOEJxTEFXQndHd01CY2dRUXlPREFVCkh3RkJzQmtYQVprd0dnOEJxTEFXQndHd01CY2kJggNVbE5OVWdBQkFBQUFLd0FDTWdBQUJBQVNBQTRCQkFBVkY2OEFGN2dUQUNML1pnQWpDVUFBTFRSSkFET01CQUEyCkFBQUFPeU1CQUR3QUJBQS9BQU1BUUlVbkFFRmpsUUJDSUVBQVRuTGpBRThDRFFCU0Q4QUFXd0EvQUZ3QVB3QmUKQkN3QVh4S0lBR1BjeUFCdE1wOEFjSVJRQUhFUkN3Q2lpT01BdUNBQUFMa2dBQUM2SUFBQXV5QUFBTHdnQUFDOQpBQUFBdmdBQUFMOEFBQURBRWFNQXc2Z3BBTVlDQUFEUUFEa0E0QkdqQU9ZQ0FBRHdBRGt5TmpZNU1ERXhPVGN6ysU6+E6Gxs0=""") diff --git a/esp32/frozen/LTE/sqnscodec.py b/esp32/frozen/LTE/sqnscodec.py new file mode 100644 index 0000000000..9b4bdf0808 --- /dev/null +++ b/esp32/frozen/LTE/sqnscodec.py @@ -0,0 +1,86 @@ +# -*- python -*- +################################################################# +# +# Module : CODEC +# Purpose: Base encoders/decoders +# +################################################################# +# +# Copyright (c) 2011 SEQUANS Communications. +# All rights reserved. +# +# This is confidential and proprietary source code of SEQUANS +# Communications. The use of the present source code and all +# its derived forms is exclusively governed by the restricted +# terms and conditions set forth in the SEQUANS +# Communications' EARLY ADOPTER AGREEMENT and/or LICENCE +# AGREEMENT. The present source code and all its derived +# forms can ONLY and EXCLUSIVELY be used with SEQUANS +# Communications' products. The distribution/sale of the +# present source code and all its derived forms is EXCLUSIVELY +# RESERVED to regular LICENCE holder and otherwise STRICTLY +# PROHIBITED. +# +################################################################# +import struct, array + +LITTLE_ENDIAN = "<" +NATIVE_ENDIAN = "=" +BIG_ENDIAN = ">" + +# -------------------------------------------------// Utility /__________________________________ +class encode: + @staticmethod + def u32 (value, endian = BIG_ENDIAN): + return array.array("c", struct.pack(endian + "I", value)) + + @staticmethod + def s32 (value, endian = BIG_ENDIAN): + if value < 0: + value = 0x100000000 + value + return encode.u32(value, endian) + + @staticmethod + def u16 (value, endian = BIG_ENDIAN): + return array.array("c", struct.pack(endian + "H", value)) + + @staticmethod + def u8 (value, endian = None): + return array.array("c", chr(value)) + + @staticmethod + def string (value, endian = None): + return array.array("c", value + "\x00") + +class decode: + @staticmethod + def u32 (value, endian = BIG_ENDIAN): + return struct.unpack(endian + "I", value)[0] + + @staticmethod + def s32 (value, endian = BIG_ENDIAN): + v = decode.u32(value, endian) + if v & (1 << 31): + return v - 0x100000000 + return v + + @staticmethod + def u16 (value, endian = BIG_ENDIAN): + return struct.unpack(endian + "H", value)[0] + + @staticmethod + def u8 (value, endian = None): + return ord(value) + + @staticmethod + def string (value, endian = None): + offset = 0 + str = "" + c = value[offset] + while c != '\x00': + offset += 1 + str += c + c = value[offset] + + return str + diff --git a/esp32/frozen/LTE/sqnscrc.py b/esp32/frozen/LTE/sqnscrc.py new file mode 100644 index 0000000000..772528e76a --- /dev/null +++ b/esp32/frozen/LTE/sqnscrc.py @@ -0,0 +1,58 @@ +# -*- python -*- +################################################################# +# +# Module : CRC +# Purpose: CRC calculation +# +################################################################# +# +# Copyright (c) 2011 SEQUANS Communications. +# All rights reserved. +# +# This is confidential and proprietary source code of SEQUANS +# Communications. The use of the present source code and all +# its derived forms is exclusively governed by the restricted +# terms and conditions set forth in the SEQUANS +# Communications' EARLY ADOPTER AGREEMENT and/or LICENCE +# AGREEMENT. The present source code and all its derived +# forms can ONLY and EXCLUSIVELY be used with SEQUANS +# Communications' products. The distribution/sale of the +# present source code and all its derived forms is EXCLUSIVELY +# RESERVED to regular LICENCE holder and otherwise STRICTLY +# PROHIBITED. +# +################################################################# +import sqnscodec as codec + +# -------------------------------------------------// Fletcher /_________________________________ +def fletcher32 (data): + l = len(data) + + index = 0 + s1 = s2 = 0xFFFF + while l > 1: + qty = 720 if l > 720 else (l & ~1) + l -= qty + + qty += index + while index < qty: + word = codec.decode.u16(data[index:index+2]) + s1 += word + s2 += s1 + + index += 2 + + s1 = (s1 & 0xFFFF) + (s1 >> 16) + s2 = (s2 & 0xFFFF) + (s2 >> 16) + + if (l & 1): + s1 += ord(data[index]) << 8 + s2 += s1 + + s1 = (s1 & 0xFFFF) + (s1 >> 16) + s2 = (s2 & 0xFFFF) + (s2 >> 16) + + s1 = (s1 & 0xFFFF) + (s1 >> 16) + s2 = (s2 & 0xFFFF) + (s2 >> 16) + + return (s2 << 16) | s1 diff --git a/esp32/frozen/LTE/sqnstp.py b/esp32/frozen/LTE/sqnstp.py new file mode 100644 index 0000000000..8301bd1c3c --- /dev/null +++ b/esp32/frozen/LTE/sqnstp.py @@ -0,0 +1,397 @@ +#!/usr/bin/env python + +import struct +import time +import os + +try: + sysname = os.uname().sysname +except: + sysname = 'Windows' + +# CRC-16(CCIT) +def crc16(s): + crc = 0x0000 + table = [0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0] + for ch in s: + crc = ((crc<<8)&0xff00) ^ table[((crc>>8)&0xff)^ch] + return crc + +def usleep(x): + time.sleep(x/1000000.0) + +def hexdump(src, length=32): + if len(src) == 0: + return + src = src[:length] + FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or '.' for x in range(256)]) + lines = [] + for c in range(0, len(src), length): + chars = src[c:c+length] + hex = ' '.join(['%02x' % x for x in chars]) + printable = ''.join(['%s' % ((x <= 127 and FILTER[x]) or '.') for x in chars]) + lines.append('%04x %-*s %s\n' % (c, length*3, hex, printable)) + print(''.join(lines)) + + +class MException(BaseException): + def __init__(self, s): + self.s = s + def __str__(self): + return self.s + +class SerialDev(object): + def __init__(self, serial, baud, timeout=90000): # 90 seconds timeout + self.serial = serial + self.timeout = timeout + + def read(self, n): + global sysname + _n = n + t = self.timeout + r = b'' + while t > 0: + c = self.serial.read(_n) + if c: + r += c + if len(r) == n: + break + _n -= len(c) + if 'FiPy' in sysname or 'GPy' in sysname: + time.sleep_ms(2) + else: + time.sleep(0.002) + t -= 2 + return r + + def write(self, s): + self.serial.write(s) + + def devastate(self): + self.serial.read() + + def close(self): + self.serial.close() + + def set_timeout(self, timeout): + self.timeout = timeout * 1000 + + +class Master: + RESET = 0 + SESSION_OPEN = 1 + TRANSFER_BLOCK_CMD = 2 + TRANSFER_BLOCK = 3 + + MREQH = b">IBBHIHH" + SRSPH = b">IBBHIHH" + SRSP_SESSION_OPEN = b">BBH" + SRSP_TRANSFER_BLOCK = b">H" + + MREQH_SIZE = struct.calcsize(MREQH) + SRSPH_SIZE = struct.calcsize(SRSPH) + SRSP_SESSION_OPEN_SIZE = struct.calcsize(SRSP_SESSION_OPEN) + SRSP_TRANSFER_BLOCK_SIZE = struct.calcsize(SRSP_TRANSFER_BLOCK) + + MREQ_SIGNATURE = 0x66617374 + SRSP_SIGNATURE = 0x74736166 + + def __init__(self, dev, debug=False, pkgdebug=False): + self.sid = 0 + self.tid = 0 + self.dev = dev + self.debug = debug + self.pkgdebug = pkgdebug + self.mreq = [] + self.srsp = [] + self.version = 1 + self.max_transfer = 16 + + @staticmethod + def mreq_ack(op): + return op | 0x80 + + def wipe(self): + self.dev.devastate() + + def read(self, n): + r = self.dev.read(n) + if self.pkgdebug: + print("IN") + hexdump(r) + return r + + + def write(self, s): + self.dev.write(s) + if self.pkgdebug: + print("OUT") + # hexdump(s.decode('ascii')) + + + def make_mreq(self, op, pld): + assert self.MREQH_SIZE + len(pld) <= self.max_transfer + + if len(pld) != 0: + pcrc = crc16(pld) + else: + pcrc = 0 + hcrc = crc16(struct.pack(self.MREQH, + self.MREQ_SIGNATURE, + op, self.sid, len(pld), + self.tid, + 0, pcrc)) + return struct.pack(self.MREQH, + self.MREQ_SIGNATURE, + op, self.sid, len(pld), + self.tid, + hcrc, pcrc) + + + def decode_srsp(self, p, show=False): + if len(p) < self.SRSPH_SIZE: + raise MException("SRSP header too small: %d" % len(p)) + + (magic, op, sid, plen, tid, hcrc, pcrc) = struct.unpack(self.SRSPH, p[:self.SRSPH_SIZE]) + if show and self.debug: + print('magic=0x%08X, op=0x%X, sid=0x%X, plen=0x%X, tid=0x%X, hcrc=0x%X, pcrc=0x%X' % (magic, op, sid, plen, tid, hcrc, pcrc)) + + if magic != self.SRSP_SIGNATURE: + print("Wrong SRSP signature: 0x%08X" % magic) + #raise MException("Wrong SRSP signature: 0x%08X" % magic) + elif show and self.debug: + print("Correct SRSP signature: 0x%08X" % magic) + + if hcrc != 0: + chcrc = crc16(struct.pack(self.SRSPH, self.SRSP_SIGNATURE, op, sid, plen, tid, 0, pcrc)) + if hcrc != chcrc: + raise MException("Wrong header CRC: 0x%04X" % hcrc) + + return dict(op=op, sid=sid, tid=tid, plen=plen, pcrc=pcrc) + + + def verify_srsp_data(self, p, plen, pcrc): + if len(p) != plen: + raise MException("Wrong payload size: %d" % plen) + if plen != 0 and pcrc != 0 and pcrc != crc16(p): + raise MException("Wrong payload CRC: 0x%04X" % pcrc) + + + def verify_session(self, i, op): + if i['op'] != Master.mreq_ack(op): + raise MException("Invalid op: 0x%02x" % i['op']) + if i['sid'] != self.sid: + raise MException("Invalid sid: %d" % i['sid']) + if i['tid'] != self.tid: + raise MException("Invalid sid: %d" % i['tid']) + + + def decode_open_session(self, p): + if len(p) < self.SRSP_SESSION_OPEN_SIZE: + raise MException("OpenSession data too small: %d" % len(p)) + (ok, ver, mts) = struct.unpack(self.SRSP_SESSION_OPEN, p[:self.SRSP_SESSION_OPEN_SIZE]) + if not ok: + raise MException("OpenSession: failed to open") + + self.version = ver + self.max_transfer = mts + print("Session opened: version %d, max transfer %s bytes" % (ver, mts)) + + + def reset(self, closing=False): + self.write(self.make_mreq(self.RESET, [])) + r = self.read(self.SRSPH_SIZE) + if closing: + return + i = self.decode_srsp(r, show=True) + if i['op'] != Master.mreq_ack(self.RESET): + raise MException("Reset: invalid op: 0x%02x" % i['op']) + + self.sid = 0 + self.tid = 0 + + + def open_session(self): + self.sid = 1 + self.tid = 1 + self.write(self.make_mreq(self.SESSION_OPEN, [])) + r = self.read(self.SRSPH_SIZE) + i = self.decode_srsp(r) + self.verify_session(i, self.SESSION_OPEN) + r = self.read(self.SRSP_SESSION_OPEN_SIZE) + self.verify_srsp_data(r, i['plen'], i['pcrc']) + self.decode_open_session(r) + self.tid += 1 + + + def send_data(self, blobfile, filesize, trials=4, bootrom=None): + global sysname + + class Trial: + def __init__(self, trials): + self.trials = trials + def need_retry(self, c, *a, **k): + try: + c(*a, **k) + except MException: + self.trials -= 1 + if self.trials > 0: return True + else: raise + return False + + trial = Trial(trials) + + downloaded = 0 + + while True: + # if 'FiPy' in sysname or 'GPy' in sysname: + # data = blobfile.read(1536) + # else: + # #data = blobfile.read(512) + # data = blobfile.read(768) + data = blobfile.read(2048) + size = len(data) + if size: + while size: + l = min(size, self.max_transfer-self.MREQH_SIZE) + l = min(l, 2048 - 32) # 31x0 mii limitation + + trials = 4 + while True: + pld = struct.pack(">H", l) + self.write(self.make_mreq(self.TRANSFER_BLOCK_CMD, pld)) + self.write(pld) + try: + r = self.read(self.SRSPH_SIZE) + i = self.decode_srsp(r) + except MException: + trials -= 1 + if not trials: raise + continue + break + + if trial.need_retry(self.verify_session, i, self.TRANSFER_BLOCK_CMD): continue + self.tid += 1 + + trials = 4 + while True: + pld = data[:l] + self.write(self.make_mreq(self.TRANSFER_BLOCK, pld)) + self.write(pld) + try: + r = self.read(self.SRSPH_SIZE) + i = self.decode_srsp(r) + except MException: + trials -= 1 + if not trials: raise + continue + if trial.need_retry(self.verify_session, i, self.TRANSFER_BLOCK): continue + r = self.read(self.SRSP_TRANSFER_BLOCK_SIZE) + break + if trial.need_retry(self.verify_srsp_data, r, i['plen'], i['pcrc']): continue + self.tid += 1 + + (residue, ) = struct.unpack(">H", r) + if residue > 0: + print("Slave didn't consume %d bytes" % residue) + l -= residue + + data = data[l:] + size -= l + downloaded += l + self.progress("Sending %d bytes" % filesize, downloaded, filesize) + else: + break + + blobfile.close() + self.progressComplete() + + return True + + + def progress(self, what, downloaded, total, barLen=40): + percent = float(downloaded)/total + hashes = '#' * int(round(percent*barLen)) + spaces = ' ' * (barLen - len(hashes)) + if 'FiPy' in sysname or 'GPy' in sysname: + print('\r%s: [%s%s] %3d%%' % (what, hashes, spaces, int(round(percent*100))), end='') + else: + print('\r%s: [%s%s] %3d%%' % (what, hashes, spaces, int(round(percent*100))), end='', flush=True) + + + def progressComplete(self): + print() + + +class args(object): + pass + +def start(elf, elfsize, serial, baud=3686400, retry=None, debug=None, AT=True, pkgdebug=False): + dev = None + + try: + # The base-two logarithm of the window size, which therefore ranges between 512 and 32768 + # 12 is 4096K + wbits = 12 + dev = SerialDev(serial, baud) + push = lambda m: m.send_data(elf, elfsize) + except: + raise + + time.sleep(0.05) + m = Master(dev, debug=debug, pkgdebug=pkgdebug) + + while True: + try: + if debug: print('running m.wipe') + m.wipe() + if debug: print('running m.reset') + m.reset() + if debug: print('running m.open_session') + m.open_session() + if debug: print('running push(m)') + push(m) + if debug: print('running dev.set_timeout(2)') + dev.set_timeout(2) + if debug: print('running m.reset(True)') + m.reset(True) + return True + except MException as ex: + print(str(ex)) + if retry: + continue + else: + return False + break + return False diff --git a/esp32/frozen/LTE/sqnsupgrade.py b/esp32/frozen/LTE/sqnsupgrade.py new file mode 100644 index 0000000000..c7f4198208 --- /dev/null +++ b/esp32/frozen/LTE/sqnsupgrade.py @@ -0,0 +1,603 @@ +#!/usr/bin/env python +import struct +import time +import os +import sys +import sqnscrc as crc +import sqnstp as stp + +try: + sysname = os.uname().sysname +except: + sysname = 'Windows' + +if 'FiPy' in sysname or 'GPy' in sysname: + from machine import UART + from machine import SD +else: # this is a computer + import serial + +FFF_FMT = "<4sIIIIIIIHHIHHIHHHH" +FFF_SLIM_FMT = "<4sIIIIIIIHHHH" +FFF_FEATURES_SLIM = 1 << 0 +FFF_MAGIC = "FFF!" + +SFFF_MAGIC = "SFFF" # Firmware +SUFF_MAGIC = "SUFF" # Updater +TEST_MAGIC = "TEST" # Test +DIFF_MAGIC = "DIFF" # Diff Upgrade +UPGR_MAGIC = "UPGR" # Generic raw upgrade +RASR_MAGIC = "RASR" # Generic raw rasterize + +class sqnsupgrade: + + global sysname + + def __init__(self): + + self.__sysname = sysname + self.__pins = None + self.__connected = False + self.__sdpath = None + + def special_print(self, msg, flush=None, end='\n'): + if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: + print(msg, end=end) + else: + print(msg, flush=flush, end=end) + + def read_rsp(self, size=None, timeout=-1): + if timeout < 0: + timeout = 20000 + elif timeout is None: + timeout = 0 + if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: + while not self.__serial.any() and timeout > 0: + time.sleep_ms(1) + timeout -= 1 + else: + while self.__serial.in_waiting <= 0 and timeout > 0: + time.sleep(0.001) + timeout -= 1 + + if size is not None: + rsp = self.__serial.read(size) + else: + rsp = self.__serial.read() + if rsp is not None: + return rsp + else: + return b'' + + def print_pretty_response(self, rsp, flush=False): + lines = rsp.decode('ascii').split('\r\n') + for line in lines: + if 'OK' not in line: + self.special_print(line, flush=flush) + + + def return_pretty_response(self, rsp): + ret_str = '' + lines = rsp.decode('ascii').split('\r\n') + for line in lines: + if 'OK' not in line: + ret_str += line + return ret_str + + def return_code(self, rsp): + ret_str = b'' + lines = rsp.decode('ascii').split('\r\n') + for line in lines: + if 'OK' not in line: + ret_str += line + try: + return int(ret_str) + except: + return -1 + + + def wait_for_modem(self, send=True, expected=b'OK'): + rsp = b'' + while True: + if send: + self.__serial.write(b"AT\r\n") + r = self.read_rsp(size=(len(expected) + 4), timeout=50) + if r: + rsp += r + if expected in rsp: + print() + break + else: + self.special_print('.', end='', flush=True) + time.sleep(0.5) + + def __check_file(self, file_path, debug=False): + if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: + if file_path[0] == '/' and not 'flash' in file_path and not file_path.split('/')[1] in os.listdir('/'): + if self.__sdpath is None: + self.__sdpath = file_path.split('/')[1] + sd = SD() + time.sleep(0.5) + os.mount(sd, '/{}'.format(self.__sdpath)) + else: + print('SD card already mounted on {}!'.format(self.__sdpath)) + return False + try: + size = os.stat(file_path)[6] + if debug: print('File {} has size {}'.format(file_path, size)) + return True + except Exception as ex: + print('Exception when checking file... wrong file name?') + print('{}'.format(ex)) + return False + return False + + + def check_files(self, ffile, mfile=None, debug=False): + if mfile is not None: + if self.__check_file(mfile, debug): + return self.__check_file(ffile, debug) + else: + return False + else: + return self.__check_file(ffile, debug) + + def detect_modem_state(self, retry=10, initial_delay=5): + if 'FiPy' or 'GPy' in self.__sysname: + + if 'GPy' in self.__sysname: + pins = ('P5', 'P98', 'P7', 'P99') + else: + pins = ('P20', 'P18', 'P19', 'P17') + count = 0 + while count < retry: + count += 1 + delay = initial_delay * count + s = UART(1, baudrate=921600, pins=pins, timeout_chars=10) + s.read() + s.write(b"AT\r\n") + time.sleep_ms(delay) + resp = s.read() + s.write(b"AT\r\n") + time.sleep_ms(delay) + resp = s.read() + if resp is not None and b'OK' in resp: + s.write(b"AT+SMOD?\r\n") + time.sleep_ms(delay) + resp = s.read() + return self.return_code(resp) + else: + s = UART(1, baudrate=115200, pins=pins, timeout_chars=10) + s.write(b"AT\r\n") + time.sleep_ms(delay) + resp = s.read() + s.write(b"AT\r\n") + time.sleep_ms(delay) + resp = s.read() + if resp is not None and b'OK' in resp: + s.write(b"AT+SMOD?\r\n") + time.sleep_ms(delay) + resp = s.read() + return self.return_code(resp) + + + def __run(self, file_path=None, baudrate=921600, port=None, resume=False, load_ffh=False, mirror=False, switch_ffh=False, bootrom=False, rgbled=0x050505, debug=False, pkgdebug=False, atneg=True, max_try=10, direct=True, atneg_only=False, version_only=False): + mirror = True if atneg_only else mirror + recover = True if atneg_only else load_ffh + resume = True if mirror or recover or atneg_only or version_only else resume + if debug: print('mirror? {} recover? {} resume? {} direct? {} atneg_only? {} bootrom? {} '.format(mirror, recover, resume, direct, atneg_only, bootrom)) + abort = True + external = False + self.__serial = None + + if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: + + if 'GPy' in self.__sysname: + self.__pins = ('P5', 'P98', 'P7', 'P99') + else: + self.__pins = ('P20', 'P18', 'P19', 'P17') + + self.__serial = UART(1, baudrate=115200 if recover else baudrate, pins=self.__pins, timeout_chars=100) + self.__serial.read() + else: + if port is None: + raise ValueError('serial port not specified') + if debug: print('Setting port {}'.format(port)) + external = True + br = 115200 if recover and not direct else baudrate + if debug: print('Setting baudrate to {}'.format(br)) + self.__serial = serial.Serial(port, br, bytesize=serial.EIGHTBITS, timeout=1 if version_only else 0.1) + self.__serial.reset_input_buffer() + self.__serial.reset_output_buffer() + + if debug: print('Initial prepartion complete...') + + if version_only: + self.__serial.read() + self.__serial.write(b"AT!=\"showver\"\r\n") + time.sleep(.5) + shver = self.read_rsp(2000) + if shver is not None: + self.print_pretty_response(shver) + return True + + if not mirror: + if bootrom: + if debug: print('Loading built-in recovery bootrom') + from sqnsbr import bootrom + blob = bootrom() + blobsize = blob.get_size() + else: + if debug: print('Loading {}'.format(file_path)) + blobsize = os.stat(file_path)[6] + blob = open(file_path, "rb") + + if not load_ffh: + if not self.wakeup_modem(baudrate, port, 10, 1, debug): + return False + + if not resume: + + # disable echo + self.__serial.write(b"ATE0\r\n") + response = self.read_rsp(size=6) + + self.__serial.read(100) + if debug: print('Entering recovery mode') + + self.__serial.write(b"AT+SMOD?\r\n") + response = self.return_pretty_response(self.read_rsp(size=7)) + self.__serial.read(100) + if debug: print("AT+SMOD? returned {}".format(response)) + + if not bootrom: + self.__serial.write(b"AT+SMSWBOOT=3,1\r\n") + time.sleep(2) + self.wait_for_modem() + self.__serial.write(b"AT\r\n") + self.__serial.write(b"AT\r\n") + + else: + self.__serial.read(100) + if debug: print('Entering recovery mode') + + self.__serial.write(b"AT+SMOD?\r\n") + response = self.return_pretty_response(self.read_rsp(size=7)) + self.__serial.read(100) + if debug: print("AT+SMOD? returned {}".format(response)) + + time.sleep(1) + self.__serial.read() + + if (not recover) and (not direct): + if mirror: + time.sleep(.5) + self.__serial.read(100) + print('Going into MIRROR mode... please close this terminal to resume the upgrade via UART') + self.uart_mirror(rgbled) + + elif bootrom: + print('Starting STP (DO NOT DISCONNECT POWER!!!)') + + else: + print('Starting STP ON_THE_FLY') + self.__serial.read(100) + + self.__serial.write(b'AT+SMSTPU=\"ON_THE_FLY\"\r\n') + response = self.read_rsp(size=4) + if response != b'OK\r\n' and response != b'\r\nOK' and response != b'\nOK': + raise OSError("Invalid answer '%s' from the device" % response) + blob.close() + + self.__serial.read() + elif recover and (not direct): + if atneg: + result = self.at_negotiation(baudrate, port, max_try, mirror, atneg_only, debug) + if result: + if atneg_only: + return True + if mirror: + time.sleep(.5) + self.__serial.read(100) + print('Going into MIRROR mode... please close this terminal to resume the upgrade via UART') + self.uart_mirror(rgbled) + else: + self.__serial.write(b"AT+STP\n") + response = self.read_rsp(size=6) + if not b'OK' in response: + print('Failed to start STP mode!') + sys.exit(1) + else: + print('AT auto-negotiation failed! Exiting.') + return False + else: + if debug: print('Starting STP mode...') + self.__serial.write(b"AT+STP\n") + response = self.read_rsp(size=6) + if not b'OK' in response: + print('Failed to start STP mode!') + sys.exit(1) + + try: + if debug: + print('Starting STP code upload') + if stp.start(blob, blobsize, self.__serial, baudrate, AT=False, debug=debug, pkgdebug=pkgdebug): + blob.close() + if switch_ffh: + print('Bootrom updated successfully, switching to upgrade mode') + abort = False + elif load_ffh: + if not self.wakeup_modem(baudrate, port, 100, 1, debug): + return False + print('Upgrader loaded successfully, modem is in upgrade mode') + return True + else: + print('Code download done, returning to user mode') + abort = recover + else: + blob.close() + print('Code download failed, aborting!') + return False + except: + blob.close() + print('Code download failed, aborting!') + abort = True + + time.sleep(1.5) + + if not abort: + self.__serial.read() + if switch_ffh: + self.__serial.write(b"AT+SMSWBOOT=0,1\r\n") + return True + else: + self.special_print('Resetting (DO NOT DISCONNECT POWER!!!).', end='', flush=True) + self.__serial.write(b"AT+SMSWBOOT=1,1\r\n") + self.wait_for_modem(send=False, expected=b'+SYSSTART') + + self.__serial.write(b"AT\r\n") + self.__serial.write(b"AT\r\n") + time.sleep(0.5) + self.__serial.read() + print('Upgrade completed!') + print("Here's the current firmware version:") + time.sleep(0.5) + self.__serial.read() + self.__serial.write(b"AT!=\"showver\"\r\n") + time.sleep(.5) + shver = self.read_rsp(2000) + if shver is not None: + self.print_pretty_response(shver) + return True + return False + + def wakeup_modem(self, baudrate, port, max_try, delay, debug): + if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: + self.__serial = UART(1, baudrate=baudrate, pins=self.__pins, timeout_chars=1) + MAX_TRY = max_try + count = 0 + print('Attempting AT wakeup...') + self.__serial.read() + self.__serial.write(b"AT\r\n") + response = self.read_rsp(size=6) + if debug: print('{}'.format(response)) + while (not b'OK' in response) and (count < MAX_TRY): + count = count + 1 + if debug: print('count={}'.format(count)) + time.sleep(delay) + self.__serial.read() + self.__serial.write(b"AT\r\n") + response = self.read_rsp(size=6) + if debug: print('{}'.format(response)) + if 'FiPy' in sysname or 'GPy' in sysname: + self.__serial = UART(1, baudrate=baudrate, pins=self.__pins, timeout_chars=100) + return count < MAX_TRY + + def at_negotiation(self, baudrate, port, max_try, mirror, atneg_only, debug): + MAX_TRY = max_try + count = 0 + print('Attempting AT auto-negotiation...') + self.__serial.write(b"AT\r\n") + response = self.read_rsp(size=6) + if debug: print('{}'.format(response)) + while (not b'OK' in response) and (count < MAX_TRY): + count = count + 1 + if debug: print('count={}'.format(count)) + time.sleep(1) + self.__serial.read() + self.__serial.write(b"AT\r\n") + response = self.read_rsp(size=6) + if debug: print('{}'.format(response)) + if b'OK' in response: + self.__serial.read() + cmd = "AT+IPR=%d\n"%baudrate + if debug: print('Setting baudrate to {}'.format(baudrate)) + self.__serial.write(cmd.encode()) + response = self.read_rsp(size=6) + if debug: print('{}'.format(response)) + if b'OK' in response: + if atneg_only: + return True + if 'FiPy' in self.__sysname or 'GPy' in self.__sysname: + self.__serial = UART(1, baudrate=baudrate, pins=self.__pins, timeout_chars=100) + else: + self.__serial = None + self.__serial = serial.Serial(port, baudrate, bytesize=serial.EIGHTBITS, timeout=0.1) + self.__serial.reset_input_buffer() + self.__serial.reset_output_buffer() + self.__serial.flush() + self.__serial.read() + if debug: print('Checking SMOD') + self.__serial.write(b"AT+SMOD?\r\n") + response = self.read_rsp(size=1) + if b'0' in response: + if debug: print("AT+SMOD? returned {}".format(response)) + self.__serial.read() + return True + else: + print('ERROR in AT+SMOD returned {}'.format(response)) + return False + else: + print('ERROR in AT+IPR={} returned {}'.format(baudrate, response)) + return False + else: + print('ERROR sending AT command... no response? {}'.format(response)) + return False + time.sleep(1) + return True + + def uart_mirror(self, color): + import pycom + pycom.heartbeat(False) + time.sleep(.5) + pycom.rgbled(color) + from network import LTE + LTE.modem_upgrade_mode() + + def upgrade_sd(self, ffile, mfile=None, baudrate=921600, retry=False, resume=False, debug=False, pkgdebug=False): + print('<<< Welcome to the SQN3330 firmware updater >>>') + success = True + if not retry and mfile is not None: + success = False + success = self.__run(bootrom=True, resume=resume, switch_ffh=True, direct=False, debug=debug, pkgdebug=pkgdebug) + time.sleep(1) + if debug: print('Success1? {}'.format(success)) + if success: + if mfile is not None: + success = False + success = self.__run(file_path=mfile, load_ffh=True, direct=False, baudrate=baudrate, debug=debug, pkgdebug=pkgdebug) + time.sleep(1) + else: + success = True + else: + print('Unable to upgrade bootrom.') + if debug: print('Success2? {}'.format(success)) + if success: + self.__run(file_path=ffile, resume=True if mfile is not None else resume, baudrate=baudrate, direct=False, debug=debug, pkgdebug=pkgdebug) + else: + print('Unable to load updater from {}'.format(mfile)) + + def upgrade_uart(self, ffh_mode=False, mfile=None, retry=False, resume=False, color=0x050505, debug=False, pkgdebug=False): + success = True + print('Preparing modem for upgrade...') + if not retry and ffh_mode: + success = False + success = self.__run(bootrom=True, resume=resume, switch_ffh=True, direct=False, debug=debug, pkgdebug=pkgdebug) + time.sleep(1) + if success: + if mfile is not None: + success = False + success = self.__run(file_path=mfile, load_ffh=True, direct=False, debug=debug, pkgdebug=pkgdebug) + if debug: print('Success2? {}'.format(success)) + if success: + self.__run(mirror=True, load_ffh=False, direct=False, rgbled=color, debug=debug) + else: + print('Unable to load updater from {}'.format(mfile)) + else: + self.__run(mirror=True, load_ffh=ffh_mode, direct=False, rgbled=color, debug=debug) + else: + print('Unable to upgrade bootrom.') + + def show_version(self, port=None, debug=False): + self.__run(port=port, debug=debug, version_only=True) + + def upgrade_ext(self, port, ffile, mfile, resume=False, debug=False, pkgdebug=False): + success = True + print('<<< Welcome to the SQN3330 firmware updater >>>') + if mfile is not None: + success = False + success = self.__run(file_path=mfile, load_ffh=True, port=port, debug=debug, pkgdebug=pkgdebug) + if success: + self.__run(file_path=ffile, resume=True if mfile is not None else resume, direct=False, port=port, debug=debug, pkgdebug=pkgdebug) + else: + print('Unable to load updater from {}'.format(mfile)) + + def recover_ext(self, port, mfile, debug=False, pkgdebug=False): + print('<<< Welcome to the SQN3330 recovery firmware updater >>>') + success = self.__run(atneg_only = True, direct= False, port=port, debug=debug, pkgdebug=pkgdebug) + #success = True + if debug: print('Success1? {}'.format(success)) + if success: + success = False + success = self.__run(file_path=mfile, load_ffh=True, direct=True, port=port, debug=debug, pkgdebug=pkgdebug) + if debug: print('Success2? {}'.format(success)) + if success: + self.__run(bootrom=True, switch_ffh=True, resume=True, direct=False, port=port, debug=debug, pkgdebug=pkgdebug) + else: + print('Unable to load updater from {}'.format(mfile)) + else: + print('Failed to perform AT auto-negotiation') + + +if 'FiPy' in sysname or 'GPy' in sysname: + def run(ffile, mfile=None, baudrate=921600, retry=False, resume=False, debug=False): + fretry = False + fresume = False + sqnup = sqnsupgrade() + if sqnup.check_files(ffile, mfile, debug): + state = sqnup.detect_modem_state() + if debug: print('Modem state: {}'.format(state)) + if (not retry) and (not resume): + if state == 0: + fretry = True + if mfile is None: + print('Your modem is in recovery mode. Please specify updater.elf file') + sys.exit(1) + elif state == 4: + fresume = True + elif state == -1: + print('Cannot detect modem state...Resuming regardless') + promt = input("please Enter 0 to Retry or 1 to Resume operation\n") + if promt: + fresume = True + else: + fretry = True + if debug: print('Resume: {} Retry: {}'.format(fresume, fretry)) + else: + fretry = retry + fresume = resume + + sqnup.upgrade_sd(ffile, mfile, baudrate, fretry, fresume, debug, False) + + def uart(ffh_mode=False, mfile=None, retry=False, resume=False, color=0x050505, debug=False): + fretry = False + fresume = False + sqnup = sqnsupgrade() + state = sqnup.detect_modem_state() + if (not retry) and (not resume): + if state == 0: + print('Your modem is in recovery mode. You will need to use updater.elf file to upgrade.') + fretry = True + elif state == 4: + fresume = True + elif state == -1: + print('Cannot detect modem state...Resuming regardless') + promt = input("please Enter 0 to Retry or 1 to Resume operation\n") + if promt: + fresume = True + else: + fretry = True + if debug: print('Resume: {} Retry: {}'.format(fresume, fretry)) + else: + fretry = retry + fresume = resume + + sqnup.upgrade_uart(ffh_mode, mfile, fretry, fresume, color, debug, False) + + def version(debug=False): + sqnup = sqnsupgrade() + sqnup.show_version(None, debug) + +else: + def run(port, ffile, mfile=None, resume=False, debug=False): + sqnup = sqnsupgrade() + if sqnup.check_files(ffile, mfile, debug): + sqnup.upgrade_ext(port, ffile, mfile, resume, debug, False) + + def recover(port, mfile, debug=False): + sqnup = sqnsupgrade() + sqnup.recover_ext(port, mfile, debug, False) + + def version(port, debug=False): + sqnup = sqnsupgrade() + sqnup.show_version(port, debug) diff --git a/esp32/lte/lteppp.c b/esp32/lte/lteppp.c index 3f9b39d903..8268ffe621 100644 --- a/esp32/lte/lteppp.c +++ b/esp32/lte/lteppp.c @@ -63,6 +63,8 @@ static ip6_addr_t lte_ipv6addr; static bool lteppp_init_complete = false; +static bool lteppp_enabled = false; + /****************************************************************************** DECLARE PRIVATE FUNCTIONS ******************************************************************************/ @@ -86,6 +88,9 @@ void lteppp_init(void) { lteppp_pcb = pppapi_pppos_create(<eppp_netif, lteppp_output_callback, lteppp_status_cb, NULL); + //wait on connecting modem until it is allowed + lteppp_enabled = false; + xTaskCreatePinnedToCore(TASK_LTE, "LTE", LTE_TASK_STACK_SIZE / sizeof(StackType_t), NULL, LTE_TASK_PRIORITY, &xLTETaskHndl, 1); } @@ -94,6 +99,16 @@ void lteppp_start (void) { vTaskDelay(5); } +void lteppp_connect_modem (void) { + + lteppp_enabled = true; +} + +bool lteppp_is_modem_connected(void) +{ + return lteppp_enabled; +} + void lteppp_set_state(lte_state_t state) { xSemaphoreTake(xLTESem, portMAX_DELAY); lteppp_lte_state = state; @@ -218,6 +233,13 @@ static void TASK_LTE (void *pvParameters) { vTaskDelay(5 / portTICK_RATE_MS); uart_set_hw_flow_ctrl(LTE_UART_ID, UART_HW_FLOWCTRL_CTS_RTS, 64); vTaskDelay(5 / portTICK_RATE_MS); + + while (!lteppp_enabled) + { + // wait till connection is enabled + vTaskDelay(LTE_TASK_PERIOD_MS/portTICK_PERIOD_MS); + } + if (lteppp_send_at_cmd("+++", LTE_PPP_BACK_OFF_TIME_MS)) { vTaskDelay(LTE_PPP_BACK_OFF_TIME_MS / portTICK_RATE_MS); while (true) { @@ -284,12 +306,12 @@ static void TASK_LTE (void *pvParameters) { } } - // enable PSM if not already enabled + // disable PSM if enabled by default lteppp_send_at_cmd("AT+CPSMS?", LTE_RX_TIMEOUT_MAX_MS); if (!strstr(lteppp_trx_buffer, "+CPSMS: 0")) { lteppp_send_at_cmd("AT+CPSMS=0", LTE_RX_TIMEOUT_MIN_MS); } - // enable low power mode + // enable airplane low power mode lteppp_send_at_cmd("AT!=\"setlpm airplane=1 enable=1\"", LTE_RX_TIMEOUT_MAX_MS); lteppp_init_complete = true; diff --git a/esp32/lte/lteppp.h b/esp32/lte/lteppp.h index fec740db0b..475e92231a 100644 --- a/esp32/lte/lteppp.h +++ b/esp32/lte/lteppp.h @@ -83,4 +83,8 @@ extern bool lteppp_wait_at_rsp (const char *expected_rsp, uint32_t timeout, bool extern bool lteppp_task_ready(void); +void lteppp_connect_modem (void); + +bool lteppp_is_modem_connected(void); + #endif // _LTEPPP_H_ diff --git a/esp32/main.c b/esp32/main.c index 1673b67792..da28bfe65c 100644 --- a/esp32/main.c +++ b/esp32/main.c @@ -63,6 +63,7 @@ TaskHandle_t xSigfoxTaskHndl; #endif #if defined(GPY) || defined (FIPY) TaskHandle_t xLTETaskHndl; +TaskHandle_t xLTEUpgradeTaskHndl; #endif extern void machine_init0(void); diff --git a/esp32/mods/modlte.c b/esp32/mods/modlte.c index f8cb9b6acb..96aa8fed91 100644 --- a/esp32/mods/modlte.c +++ b/esp32/mods/modlte.c @@ -72,12 +72,27 @@ /****************************************************************************** DEFINE CONSTANTS ******************************************************************************/ - +#define LTE_NUM_UARTS 2 +#define UART_TRANSFER_MAX_LEN 1 /****************************************************************************** DECLARE PRIVATE DATA ******************************************************************************/ static lte_obj_t lte_obj = {.init = false}; static lte_task_rsp_data_t modlte_rsp; +uart_dev_t* uart_driver_0 = &UART0; +uart_dev_t* uart_driver_lte = &UART2; + +uart_config_t lte_uart_config0; +uart_config_t lte_uart_config1; + +extern TaskHandle_t xLTEUpgradeTaskHndl; +extern TaskHandle_t mpTaskHandle; +extern TaskHandle_t svTaskHandle; +#if defined(FIPY) +extern TaskHandle_t xLoRaTaskHndl; +extern TaskHandle_t xSigfoxTaskHndl; +#endif +extern TaskHandle_t xLTETaskHndl; /****************************************************************************** DECLARE PUBLIC DATA @@ -189,6 +204,48 @@ static bool lte_check_sim_present(void) { } } +static void TASK_LTE_UPGRADE (void *pvParameters) { + + size_t len = 0; + uint8_t rx_buff[UART_TRANSFER_MAX_LEN]; + // Suspend All tasks + vTaskSuspend(mpTaskHandle); + vTaskSuspend(svTaskHandle); +#if defined(FIPY) + vTaskSuspend(xLoRaTaskHndl); + vTaskSuspend(xSigfoxTaskHndl); +#endif + vTaskSuspend(xLTETaskHndl); + + for(;;) + { + uart_get_buffered_data_len(0, &len); + + if(len) + { + if(len > UART_TRANSFER_MAX_LEN) + { + len = UART_TRANSFER_MAX_LEN; + } + uart_read_bytes(0,rx_buff,len,0); + uart_write_bytes(1,(char*)(rx_buff),len); + } + + len = 0; + uart_get_buffered_data_len(1, &len); + + if(len) + { + if(len > UART_TRANSFER_MAX_LEN) + { + len = UART_TRANSFER_MAX_LEN; + } + uart_read_bytes(1,rx_buff,len,0); + uart_write_bytes(0,(char*)(rx_buff),len); + } + } +} + /******************************************************************************/ // Micro Python bindings; LTE class @@ -250,6 +307,17 @@ static mp_obj_t lte_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uin mp_arg_val_t args[MP_ARRAY_SIZE(lte_init_args)]; mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), lte_init_args, args); + if (!lteppp_is_modem_connected()) { + //Enable Lte modem connection + lteppp_connect_modem(); + } + + while(!lteppp_is_modem_connected()) + { + //wait till modem is start-up + vTaskDelay(1/portTICK_PERIOD_MS); + } + // setup the object lte_obj_t *self = <e_obj; self->base.type = (mp_obj_t)&mod_network_nic_type_lte; @@ -500,6 +568,83 @@ STATIC mp_obj_t lte_reset(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(lte_reset_obj, lte_reset); +STATIC mp_obj_t lte_upgrade_mode(void) { + + if(lte_obj.init) + { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Modem not disabled")); + } + + // uninstall the driver + uart_driver_delete(0); + uart_driver_delete(1); + + // initialize the UART interface + lte_uart_config1.baud_rate = MICROPY_LTE_UART_BAUDRATE; + lte_uart_config1.data_bits = UART_DATA_8_BITS; + lte_uart_config1.parity = UART_PARITY_DISABLE; + lte_uart_config1.stop_bits = UART_STOP_BITS_1; + lte_uart_config1.flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS; + lte_uart_config1.rx_flow_ctrl_thresh = 64; + uart_param_config(1, <e_uart_config1); + + //deassign LTE Uart pins + pin_deassign(MICROPY_LTE_TX_PIN); + gpio_pullup_dis(MICROPY_LTE_TX_PIN->pin_number); + + pin_deassign(MICROPY_LTE_RX_PIN); + gpio_pullup_dis(MICROPY_LTE_RX_PIN->pin_number); + + pin_deassign(MICROPY_LTE_CTS_PIN); + gpio_pullup_dis(MICROPY_LTE_CTS_PIN->pin_number); + + pin_deassign(MICROPY_LTE_RTS_PIN); + gpio_pullup_dis(MICROPY_LTE_RTS_PIN->pin_number); + + // configure the UART pins + pin_config(MICROPY_LTE_TX_PIN, -1, U1TXD_OUT_IDX, GPIO_MODE_OUTPUT, MACHPIN_PULL_NONE, 1); + pin_config(MICROPY_LTE_RX_PIN, U1RXD_IN_IDX, -1, GPIO_MODE_INPUT, MACHPIN_PULL_NONE, 1); + pin_config(MICROPY_LTE_RTS_PIN, -1, U1RTS_OUT_IDX, GPIO_MODE_OUTPUT, MACHPIN_PULL_NONE, 1); + pin_config(MICROPY_LTE_CTS_PIN, U1CTS_IN_IDX, -1, GPIO_MODE_INPUT, MACHPIN_PULL_NONE, 1); + + // install the UART driver + uart_driver_install(1, LTE_UART_BUFFER_SIZE, 4096, 0, NULL, 0, NULL); + uart_driver_lte = &UART1; + + // disable the delay between transfers + uart_driver_lte->idle_conf.tx_idle_num = 0; + + // configure the rx timeout threshold + uart_driver_lte->conf1.rx_tout_thrhd = 10 & UART_RX_TOUT_THRHD_V; + + + lte_uart_config0.baud_rate = MICROPY_LTE_UART_BAUDRATE; + lte_uart_config0.data_bits = UART_DATA_8_BITS; + lte_uart_config0.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; + lte_uart_config0.parity = UART_PARITY_DISABLE; + lte_uart_config0.rx_flow_ctrl_thresh = 64; + lte_uart_config0.stop_bits = 1.0; + + uart_param_config(0, <e_uart_config0); + + pin_config(&PIN_MODULE_P1, -1, U0TXD_OUT_IDX, GPIO_MODE_OUTPUT, MACHPIN_PULL_NONE, 1); + pin_config(&PIN_MODULE_P0, U0RXD_IN_IDX, -1, GPIO_MODE_INPUT, MACHPIN_PULL_NONE, 1); + + // install the UART driver + uart_driver_install(0, LTE_UART_BUFFER_SIZE, 4096, 0, NULL, 0, NULL); + + // disable the delay between transfers + uart_driver_0->idle_conf.tx_idle_num = 0; + + // configure the rx timeout threshold + uart_driver_0->conf1.rx_tout_thrhd = 10 & UART_RX_TOUT_THRHD_V; + + xTaskCreatePinnedToCore(TASK_LTE_UPGRADE, "LTE_UPGRADE", 3072 / sizeof(StackType_t), NULL, 7, &xLTEUpgradeTaskHndl, 1); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(lte_upgrade_mode_obj, lte_upgrade_mode); + STATIC const mp_map_elem_t lte_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)<e_init_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)<e_deinit_obj }, @@ -513,6 +658,7 @@ STATIC const mp_map_elem_t lte_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_iccid), (mp_obj_t)<e_iccid_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_send_at_cmd), (mp_obj_t)<e_send_raw_at_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)<e_reset_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_modem_upgrade_mode), (mp_obj_t)<e_upgrade_mode_obj }, // class constants }; diff --git a/esp32/mods/modpycom.c b/esp32/mods/modpycom.c index 8bf8a1fb37..c85db88be0 100644 --- a/esp32/mods/modpycom.c +++ b/esp32/mods/modpycom.c @@ -278,6 +278,15 @@ STATIC mp_obj_t mod_pycom_heartbeat_on_boot (mp_uint_t n_args, const mp_obj_t *a } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_pycom_heartbeat_on_boot_obj, 0, 1, mod_pycom_heartbeat_on_boot); +STATIC mp_obj_t mod_pycom_lte_modem_on_boot (mp_uint_t n_args, const mp_obj_t *args) { + if (n_args) { + config_set_lte_modem_enable_on_boot (mp_obj_is_true(args[0])); + } else { + return mp_obj_new_bool(config_get_lte_modem_enable_on_boot()); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_pycom_lte_modem_on_boot_obj, 0, 1, mod_pycom_lte_modem_on_boot); STATIC const mp_map_elem_t pycom_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pycom) }, { MP_OBJ_NEW_QSTR(MP_QSTR_heartbeat), (mp_obj_t)&mod_pycom_heartbeat_obj }, @@ -298,6 +307,7 @@ STATIC const mp_map_elem_t pycom_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_wifi_ssid), (mp_obj_t)&mod_pycom_wifi_ssid_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_wifi_pwd), (mp_obj_t)&mod_pycom_wifi_pwd_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_heartbeat_on_boot), (mp_obj_t)&mod_pycom_heartbeat_on_boot_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_lte_modem_en_on_boot), (mp_obj_t)&mod_pycom_lte_modem_on_boot_obj }, }; STATIC MP_DEFINE_CONST_DICT(pycom_module_globals, pycom_module_globals_table); diff --git a/esp32/mptask.c b/esp32/mptask.c index cc62961ef6..e1e0d72aaa 100644 --- a/esp32/mptask.c +++ b/esp32/mptask.c @@ -78,6 +78,7 @@ #include "freertos/queue.h" +#include "lteppp.h" /****************************************************************************** DECLARE EXTERNAL FUNCTIONS ******************************************************************************/ @@ -264,6 +265,10 @@ void TASK_Micropython (void *pvParameters) { if (!soft_reset) { #if defined(GPY) || defined (FIPY) modlte_init0(); + if(config_get_lte_modem_enable_on_boot()) + { + lteppp_connect_modem(); + } #endif } diff --git a/esp32/pycom_config.c b/esp32/pycom_config.c index c9f27f80ef..d7f19492f8 100644 --- a/esp32/pycom_config.c +++ b/esp32/pycom_config.c @@ -120,6 +120,17 @@ uint32_t config_get_wdt_on_boot_timeout (void) { return pycom_config_block.wdt_config.wdt_on_boot_timeout; } +bool config_set_lte_modem_enable_on_boot (bool lte_modem_en_on_boot) { + if (pycom_config_block.lte_config.lte_modem_en_on_boot != (uint8_t)lte_modem_en_on_boot) { + pycom_config_block.lte_config.lte_modem_en_on_boot = (uint8_t)lte_modem_en_on_boot; + return config_write(); + } + return true; +} + +bool config_get_lte_modem_enable_on_boot (void) { + return (bool)pycom_config_block.lte_config.lte_modem_en_on_boot; +} bool config_set_heartbeat_on_boot (uint8_t hb_on_boot) { if (pycom_config_block.rgbled_config.heartbeat_on_boot != hb_on_boot) { pycom_config_block.rgbled_config.heartbeat_on_boot = hb_on_boot; diff --git a/esp32/pycom_config.h b/esp32/pycom_config.h index 4a6742e79b..de6d55a419 100644 --- a/esp32/pycom_config.h +++ b/esp32/pycom_config.h @@ -56,6 +56,10 @@ typedef struct { uint32_t wdt_on_boot_timeout; } pycom_wdt_config_t; +typedef struct { + uint8_t lte_modem_en_on_boot; +}pycom_lte_config_t; + typedef struct { pycom_lpwan_config_t lpwan_config; pycom_wifi_config_t wifi_config; @@ -63,7 +67,8 @@ typedef struct { uint8_t pycom_reserved[335]; pycom_config_t pycom_config; pycom_wdt_config_t wdt_config; - uint8_t pycom_dummy[248]; + pycom_lte_config_t lte_config; + uint8_t pycom_dummy[247]; } pycom_config_block_t; /****************************************************************************** @@ -119,4 +124,7 @@ bool config_set_lora_region (uint8_t lora_region); uint8_t config_get_lora_region (void); +bool config_set_lte_modem_enable_on_boot (bool lte_modem_en_on_boot); + +bool config_get_lte_modem_enable_on_boot (void); #endif /* PYCOM_CONFIG_H_ */ diff --git a/esp32/pycom_version.h b/esp32/pycom_version.h index b680bd1dc6..29b4f7f296 100644 --- a/esp32/pycom_version.h +++ b/esp32/pycom_version.h @@ -10,7 +10,7 @@ #ifndef VERSION_H_ #define VERSION_H_ -#define SW_VERSION_NUMBER "1.18.0.r1" +#define SW_VERSION_NUMBER "1.18.1" #define LORAWAN_VERSION_NUMBER "1.0.2" diff --git a/py/mkrules.mk b/py/mkrules.mk index b71450a21d..633b0dfab2 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -107,15 +107,44 @@ $(BUILD)/frozen.c: $(wildcard $(FROZEN_DIR)/*) $(HEADER_BUILD) $(FROZEN_EXTRA_DE endif ifneq ($(FROZEN_MPY_DIR),) +OS_NAME := $(shell uname -s) +ifeq ($(OS_NAME), Linux) # make a list of all the .py files that need compiling and freezing -FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py' | $(SED) -e 's=^$(FROZEN_MPY_DIR)/==') +FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR)/Base/ -type f -name '*.py' | $(SED) -e 's/$(FROZEN_MPY_DIR)\/Base\///') +FROZEN_MPY_PY_FILES += $(shell find -L $(FROZEN_MPY_DIR)/Common/ -type f -name '*.py' | $(SED) -e 's/$(FROZEN_MPY_DIR)\/Common\///') +ifeq ($(BOARD), $(filter $(BOARD), GPY FIPY)) +FROZEN_MPY_PY_FILES += $(shell find -L $(FROZEN_MPY_DIR)/LTE/ -type f -name '*.py' | $(SED) -e 's/$(FROZEN_MPY_DIR)\/LTE\///') +endif +else +# make a list of all the .py files that need compiling and freezing +FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR)/Base/ -type f -name '*.py' | $(SED) -e 's=^$(FROZEN_MPY_DIR)\/Base\//==') +FROZEN_MPY_PY_FILES += $(shell find -L $(FROZEN_MPY_DIR)/Common/ -type f -name '*.py' | $(SED) -e 's=^$(FROZEN_MPY_DIR)\/Common\//==') +ifeq ($(BOARD), $(filter $(BOARD), GPY FIPY)) +FROZEN_MPY_PY_FILES += $(shell find -L $(FROZEN_MPY_DIR)/LTE/ -type f -name '*.py' | $(SED) -e 's=^$(FROZEN_MPY_DIR)\/LTE\//==') +endif +endif + FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/frozen_mpy/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) # to build .mpy files from .py files -$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py +$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/Base/%.py + @$(ECHO) "MPY $<" + $(Q)$(MKDIR) -p $(dir $@) + $(Q)$(MPY_CROSS) -o $@ -s $(^:$(FROZEN_MPY_DIR)/Base/%=%) $(MPY_CROSS_FLAGS) $^ + +# to build .mpy files from .py files +$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/Common/%.py @$(ECHO) "MPY $<" $(Q)$(MKDIR) -p $(dir $@) - $(Q)$(MPY_CROSS) -o $@ -s $(^:$(FROZEN_MPY_DIR)/%=%) $(MPY_CROSS_FLAGS) $^ + $(Q)$(MPY_CROSS) -o $@ -s $(^:$(FROZEN_MPY_DIR)/Common/%=%) $(MPY_CROSS_FLAGS) $^ + +ifeq ($(BOARD), $(filter $(BOARD), GPY FIPY)) +# to build .mpy files from .py files +$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/LTE/%.py + @$(ECHO) "MPY $<" + $(Q)$(MKDIR) -p $(dir $@) + $(Q)$(MPY_CROSS) -o $@ -s $(^:$(FROZEN_MPY_DIR)/LTE/%=%) $(MPY_CROSS_FLAGS) $^ +endif # to build frozen_mpy.c from all .mpy files $(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h