From ee6511a8ef5344feb3594737d83f2f76ba233442 Mon Sep 17 00:00:00 2001 From: Juan Ma Date: Mon, 26 Apr 2021 10:51:49 -0400 Subject: [PATCH 01/50] Change example lopy simulation --- fragmentation_layer/code/schc_base/bitmap.py | 2 - .../code/schc_handlers/schc_handler_node.py | 6 +-- .../code/schc_machines/lorawan/__init__.py | 1 - .../lorawan/ack_on_error_receiver.py | 12 ++--- .../lorawan/ack_on_error_sender.py | 8 ++-- .../code/schc_machines/schc_fsm.py | 21 ++++----- .../code/schc_machines/schc_receiver.py | 2 +- fragmentation_layer/example/common_methods.py | 46 +++++++++---------- fragmentation_layer/example/test_receiver.py | 1 + fragmentation_layer/example/test_sender.py | 1 + 10 files changed, 44 insertions(+), 56 deletions(-) diff --git a/fragmentation_layer/code/schc_base/bitmap.py b/fragmentation_layer/code/schc_base/bitmap.py index f76d6c7..4cf01d7 100644 --- a/fragmentation_layer/code/schc_base/bitmap.py +++ b/fragmentation_layer/code/schc_base/bitmap.py @@ -1,7 +1,5 @@ """ bitmap: Bitmap class """ -from schc_protocols import SCHCProtocol - class Bitmap: """ diff --git a/fragmentation_layer/code/schc_handlers/schc_handler_node.py b/fragmentation_layer/code/schc_handlers/schc_handler_node.py index a81fc03..2c833db 100644 --- a/fragmentation_layer/code/schc_handlers/schc_handler_node.py +++ b/fragmentation_layer/code/schc_handlers/schc_handler_node.py @@ -18,7 +18,6 @@ def send_package(self, rule_id, packet, dtag=None): raise ValueError("Rule ID not allowed for sending a message from a end device") else: raise NotImplementedError("Just LoRaWAN implemented") - self.__sessions__[rule_id][dtag].receive_message(message) def receive(self, rule_id, dtag, message, f_port=None): if self.__protocol__.id == SCHCProtocol.LoRaWAN: @@ -37,7 +36,4 @@ def receive(self, rule_id, dtag, message, f_port=None): raise NotImplementedError("Just LoRaWAN implemented") def generate_message(self, rule_id, dtag, mtu=512): - try: - return self.__sessions__[rule_id][dtag].generate_message(mtu).as_bytes() - except GeneratorExit: - return b'' + return self.__sessions__[rule_id][dtag].generate_message(mtu).as_bytes() diff --git a/fragmentation_layer/code/schc_machines/lorawan/__init__.py b/fragmentation_layer/code/schc_machines/lorawan/__init__.py index 7785b62..6a3c93d 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/__init__.py +++ b/fragmentation_layer/code/schc_machines/lorawan/__init__.py @@ -1,6 +1,5 @@ """ lorawan: LoRaWAN state machines """ - from schc_machines.lorawan.ack_on_error_receiver import AckOnErrorReceiver from schc_machines.lorawan.ack_on_error_sender import AckOnErrorSender from schc_machines.lorawan.ack_always_receiver import AckAlwaysReceiver diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py index bf1e965..7d3cfc1 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py @@ -15,6 +15,8 @@ class AckOnErrorReceiver(SCHCReceiver): protocol state """ + __mode__ = "Ack On Error" + class ReceivingPhase(SCHCReceiver.ReceiverState): """ Receiving Phase of Ack on Error @@ -61,11 +63,6 @@ def generate_message(self, mtu): ------- SCHCMessage : A message saved to be send - - Raises - ------ - GeneratorExit - No message to be send """ if self.sm.__last_window__ and self.__success__: self.sm.state = self.sm.states["end"] @@ -73,7 +70,8 @@ def generate_message(self, mtu): message = self.sm.message_to_send.pop(0) self._logger_.schc_message(message) return message - raise GeneratorExit("No message to send, keep receiving") + else: + return None def receive_regular_schc_fragment(self, schc_message): """ @@ -229,7 +227,7 @@ def generate_message(self, mtu): self._logger_.schc_message(message) return message else: - raise GeneratorExit("No message to send, keep receiving") + return None def receive_regular_schc_fragment(self, schc_message): """ diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py index ce4be0b..5cf5005 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py @@ -15,6 +15,8 @@ class AckOnErrorSender(SCHCSender): state residue """ + __mode__ = "Ack On Error" + class InitialPhase(SCHCSender.SenderState): """ Initial Phase of Ack on Error @@ -125,12 +127,8 @@ def generate_message(self, mtu): ------- SCHCMessage : None - Raises - ------ - GeneratorExit - Awaits for Ack """ - raise GeneratorExit("Awaits for Ack after a windows was sent") + return None def receive_schc_ack(self, schc_message): """ diff --git a/fragmentation_layer/code/schc_machines/schc_fsm.py b/fragmentation_layer/code/schc_machines/schc_fsm.py index dc99e8f..1807780 100644 --- a/fragmentation_layer/code/schc_machines/schc_fsm.py +++ b/fragmentation_layer/code/schc_machines/schc_fsm.py @@ -1,6 +1,5 @@ """ schc_fsm: SCHC Finite State Machine Abstract Class """ -import logging from machine import Timer from schc_base import AttemptsCounter, Bitmap from schc_messages import SCHCMessage @@ -91,7 +90,7 @@ def enter_state(self): ------- None """ - self.__log__(logging.debug) + self.__log__(print) return def schc_message(self, message): @@ -108,7 +107,7 @@ def schc_message(self, message): None """ self.enter_state() - logging.debug("\tMessage:\n{}".format(message.as_text())) + print("\tMessage:\n{}".format(message.as_text())) return def error(self, message): @@ -124,8 +123,8 @@ def error(self, message): ------- None """ - self.__log__(logging.error) - logging.error("\t{}".format(message)) + self.__log__(print) + print("\t{}".format(message)) return def warning(self, message): @@ -141,8 +140,8 @@ def warning(self, message): ------- None """ - self.__log__(logging.warning) - logging.warning("\t{}".format(message)) + self.__log__(print) + print("\t{}".format(message)) return def debug(self, message): @@ -158,8 +157,8 @@ def debug(self, message): ------- None """ - self.__log__(logging.debug) - logging.debug("\t{}".format(message)) + self.__log__(print) + print("\t{}".format(message)) return def info(self, message): @@ -175,8 +174,8 @@ def info(self, message): ------- None """ - self.__log__(logging.info) - logging.info("\t{}".format(message)) + self.__log__(print) + print("\t{}".format(message)) return def __init__(self, state_machine): diff --git a/fragmentation_layer/code/schc_machines/schc_receiver.py b/fragmentation_layer/code/schc_machines/schc_receiver.py index 587f3ed..8ab7e87 100644 --- a/fragmentation_layer/code/schc_machines/schc_receiver.py +++ b/fragmentation_layer/code/schc_machines/schc_receiver.py @@ -137,7 +137,7 @@ def receive_schc_sender_abort(self, schc_message): def __init__(self, protocol, dtag=None): super().__init__(protocol, dtag=dtag) - self.payload: SCHCPayload = SCHCPayload() + self.payload = SCHCPayload() self.inactivity_timer = SCHCTimer(self.on_expiration_time, protocol.INACTIVITY_TIMER) self.__end_msg__ = "Message received and resembled" return diff --git a/fragmentation_layer/example/common_methods.py b/fragmentation_layer/example/common_methods.py index b77270f..4c39598 100644 --- a/fragmentation_layer/example/common_methods.py +++ b/fragmentation_layer/example/common_methods.py @@ -96,29 +96,27 @@ def messaging_loop(machine: SCHCFiniteStateMachine, socket_rx: socket.socket, se ------- None """ - exit_all = False while True: - while True: - try: - mtu = get_mtu() - lost = is_this_loss() - message = machine.generate_message(mtu) - logging.info("Current mtu: {}".format(mtu)) - logging.info("Package sent: {}".format(not lost)) - if not lost: - send_socket(message.as_bytes(), sender_port) - except GeneratorExit: - break - except SystemExit as e: - print(e) - exit_all = True - break - if exit_all: + mtu = get_mtu() + lost = is_this_loss() + try: + print("Sending...") + message = machine.generate_message(mtu) + logging.info("Current mtu: {}".format(mtu)) + logging.info("Package sent: {}".format(not lost)) + if not lost and message is not None: + send_socket(message.as_bytes(), sender_port) + except SystemExit as e: + print(e) break - data = receive_socket(socket_rx) - if data: - try: - machine.receive_message(data) - except SystemExit as e: - print(e) - break + try: + print("Receiving...") + data = receive_socket(socket_rx) + if data: + try: + machine.receive_message(data) + except SystemExit as e: + print(e) + break + except socket.timeout: + pass diff --git a/fragmentation_layer/example/test_receiver.py b/fragmentation_layer/example/test_receiver.py index cd798c8..a5cc952 100644 --- a/fragmentation_layer/example/test_receiver.py +++ b/fragmentation_layer/example/test_receiver.py @@ -8,6 +8,7 @@ SENDER_PORT = 50007 socket_rx = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +socket_rx.settimeout(10) socket_rx.bind((HOST, RECEIVER_PORT)) socket_rx.listen(1) diff --git a/fragmentation_layer/example/test_sender.py b/fragmentation_layer/example/test_sender.py index 02a5a53..8395d11 100644 --- a/fragmentation_layer/example/test_sender.py +++ b/fragmentation_layer/example/test_sender.py @@ -57,6 +57,7 @@ RESIDUE = "0101100" socket_rx = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +socket_rx.settimeout(1) socket_rx.bind((HOST, RECEIVER_PORT)) socket_rx.listen(1) From b64c8c1942e13fde9a1dc128d079d460cb06212b Mon Sep 17 00:00:00 2001 From: Juan Ma Date: Thu, 29 Apr 2021 09:16:27 -0400 Subject: [PATCH 02/50] Lopy refactor --- .../code/schc_handlers/__init__.py | 4 +- ...ler_gateway.py => schc_gateway_handler.py} | 16 ++--- .../code/schc_handlers/schc_handler.py | 6 +- .../code/schc_handlers/schc_handler_node.py | 39 ----------- .../code/schc_handlers/schc_node_handler.py | 65 +++++++++++++++++++ .../lorawan/ack_on_error_sender.py | 9 ++- .../code/schc_machines/schc_sender.py | 16 +++-- fragmentation_layer/example/received.txt | 2 - fragmentation_layer/example/test_receiver.py | 2 - fragmentation_layer/example/test_sender.py | 3 +- 10 files changed, 92 insertions(+), 70 deletions(-) rename fragmentation_layer/code/schc_handlers/{schc_handler_gateway.py => schc_gateway_handler.py} (66%) delete mode 100644 fragmentation_layer/code/schc_handlers/schc_handler_node.py create mode 100644 fragmentation_layer/code/schc_handlers/schc_node_handler.py diff --git a/fragmentation_layer/code/schc_handlers/__init__.py b/fragmentation_layer/code/schc_handlers/__init__.py index e53b85e..670d3cb 100644 --- a/fragmentation_layer/code/schc_handlers/__init__.py +++ b/fragmentation_layer/code/schc_handlers/__init__.py @@ -1,5 +1,5 @@ """ schc_handlers: Package of handlers classes""" from schc_handlers.schc_handler import SCHCHandler -from schc_handlers.schc_handler_node import SCHCHandlerNode -from schc_handlers.schc_handler_gateway import SCHCHandlerGateway +from schc_handlers.schc_node_handler import SCHCNodeHandler +from schc_handlers.schc_gateway_handler import SCHCGatewayHandler diff --git a/fragmentation_layer/code/schc_handlers/schc_handler_gateway.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py similarity index 66% rename from fragmentation_layer/code/schc_handlers/schc_handler_gateway.py rename to fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index 06ff3fd..8a9f2a2 100644 --- a/fragmentation_layer/code/schc_handlers/schc_handler_gateway.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -1,24 +1,20 @@ -""" schc_handler_gateway: SCHC Handler Gateway Class """ +""" schc_gateway_handler: SCHC Gateway Handler Class """ from schc_handlers import SCHCHandler -from schc_protocols import LoRaWAN, SCHCProtocol, get_protocol +from schc_protocols import LoRaWAN, SCHCProtocol -class SCHCHandlerGateway(SCHCHandler): +class SCHCGatewayHandler(SCHCHandler): def __init__(self, protocol): super().__init__(protocol) - def send_package(self, rule_id, packet, dtag=None): + def send_package(self, packet): if self.__protocol__.id == SCHCProtocol.LoRaWAN: - if rule_id == LoRaWAN.ACK_ALWAYS: - from schc_machines.lorawan import AckAlwaysSender - self.assign_session(rule_id, dtag, AckAlwaysSender(LoRaWAN(LoRaWAN.ACK_ON_ERROR), packet)) - else: - raise ValueError("Rule ID not allowed for sending a message from a gateway") + from schc_machines.lorawan import AckAlwaysSender + self.assign_session(LoRaWAN.ACK_ALWAYS, None, AckAlwaysSender(LoRaWAN(LoRaWAN.ACK_ALWAYS), packet)) else: raise NotImplementedError("Just LoRaWAN implemented") - self.__sessions__[rule_id][dtag].receive_message(message) def receive(self, rule_id, dtag, message, f_port=None): if self.__protocol__.id == SCHCProtocol.LoRaWAN: diff --git a/fragmentation_layer/code/schc_handlers/schc_handler.py b/fragmentation_layer/code/schc_handlers/schc_handler.py index d837f17..c463661 100644 --- a/fragmentation_layer/code/schc_handlers/schc_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_handler.py @@ -4,11 +4,13 @@ from schc_protocols import SCHCProtocol, get_protocol +# TODO: class SCHCHandler: - def __init__(self, protocol): + def __init__(self, protocol, mtu): self.__protocol__ = get_protocol(protocol) self.__sessions__ = dict() + self.__mtu__ = mtu def identify_session_from_message(self, message, f_port=None): if self.__protocol__.id == SCHCProtocol.LoRaWAN: @@ -24,7 +26,7 @@ def identify_session_from_message(self, message, f_port=None): dtag = int(dtag, 2) return rule_id, dtag - def send_package(self, rule_id, packet, dtag=None): + def send_package(self, packet): return def receive(self, rule_id, dtag, message, f_port=None): diff --git a/fragmentation_layer/code/schc_handlers/schc_handler_node.py b/fragmentation_layer/code/schc_handlers/schc_handler_node.py deleted file mode 100644 index 2c833db..0000000 --- a/fragmentation_layer/code/schc_handlers/schc_handler_node.py +++ /dev/null @@ -1,39 +0,0 @@ -""" schc_handler_node: SCHC Handler Node Class """ - -from schc_handlers import SCHCHandler -from schc_protocols import LoRaWAN, SCHCProtocol, get_protocol - - -class SCHCHandlerGateway(SCHCHandler): - - def __init__(self, protocol): - super().__init__(protocol) - - def send_package(self, rule_id, packet, dtag=None): - if self.__protocol__.id == SCHCProtocol.LoRaWAN: - if rule_id == LoRaWAN.ACK_ON_ERROR: - from schc_machines.lorawan import AckOnErrorSender - self.assign_session(rule_id, dtag, AckOnErrorSender(LoRaWAN(LoRaWAN.ACK_ON_ERROR), packet)) - else: - raise ValueError("Rule ID not allowed for sending a message from a end device") - else: - raise NotImplementedError("Just LoRaWAN implemented") - - def receive(self, rule_id, dtag, message, f_port=None): - if self.__protocol__.id == SCHCProtocol.LoRaWAN: - if rule_id == LoRaWAN.ACK_ALWAYS: - # message received - from schc_machines.lorawan import AckAlwaysReceiver - self.assign_session(rule_id, dtag, AckAlwaysReceiver(LoRaWAN(LoRaWAN.ACK_ALWAYS))) - self.__sessions__[rule_id][dtag].receive_message(message) - elif rule_id == LoRaWAN.ACK_ON_ERROR: - # response received - self.__sessions__[rule_id][dtag].receive_message(message) - else: - pass - # TODO compression - else: - raise NotImplementedError("Just LoRaWAN implemented") - - def generate_message(self, rule_id, dtag, mtu=512): - return self.__sessions__[rule_id][dtag].generate_message(mtu).as_bytes() diff --git a/fragmentation_layer/code/schc_handlers/schc_node_handler.py b/fragmentation_layer/code/schc_handlers/schc_node_handler.py new file mode 100644 index 0000000..f4d9096 --- /dev/null +++ b/fragmentation_layer/code/schc_handlers/schc_node_handler.py @@ -0,0 +1,65 @@ +""" schc_node_handler: SCHC Node Handler Class """ + +from schc_handlers import SCHCHandler +from schc_protocols import LoRaWAN, SCHCProtocol + + +class SCHCNodeHandler(SCHCHandler): + + def __init__(self, protocol, mtu): + super().__init__(protocol, mtu=mtu) + + def send_package(self, packet): + if self.__protocol__.id == SCHCProtocol.LoRaWAN: + from schc_machines.lorawan import AckOnErrorSender + self.assign_session(LoRaWAN.ACK_ON_ERROR, None, AckOnErrorSender(LoRaWAN(LoRaWAN.ACK_ON_ERROR), packet)) + else: + raise NotImplementedError("Just LoRaWAN implemented") + + def receive(self, rule_id, dtag, message, f_port=None): + if self.__protocol__.id == SCHCProtocol.LoRaWAN: + if rule_id == LoRaWAN.ACK_ALWAYS: + # message received + from schc_machines.lorawan import AckAlwaysReceiver + self.assign_session(rule_id, dtag, AckAlwaysReceiver(LoRaWAN(LoRaWAN.ACK_ALWAYS))) + self.__sessions__[rule_id][dtag].receive_message(message) + elif rule_id == LoRaWAN.ACK_ON_ERROR: + # response received + self.__sessions__[rule_id][dtag].receive_message(message) + else: + pass + # TODO compression + else: + raise NotImplementedError("Just LoRaWAN implemented") + + def generate_message(self, rule_id, dtag, mtu=512): + return self.__sessions__[rule_id][dtag].generate_message(mtu).as_bytes() + + def start(self, s): + while True: + for rule_id in self.__sessions__.keys(): + for dtag in self.__sessions__[rule_id].keys(): + machine = self.__sessions__[rule_id][dtag] + message = machine.generate_message(self.__mtu__) + + if message is not None: + s.setblocking(True) + print(message.as_text()) + + # send some data + if self.__protocol__.id == SCHCProtocol.LoRaWAN: + s.bind(int(message.as_bytes()[0])) + s.send(message.as_bytes()[1:]) + else: + s.send(message.as_bytes()) + + # make the socket non-blocking + # (because if there's no data received it will block forever...) + s.setblocking(False) + + # get any data received (if any...) + data = s.recvfrom(512) + print(data) + if data[0] != b'': + r, d = self.identify_session_from_message() + self.receive(r, d, data) diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py index 5cf5005..581fc28 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py @@ -71,6 +71,8 @@ def generate_message(self, mtu): self.sm.__dtag__, self.sm.__cw__) mtu_available = (mtu - (regular_message.size // 8)) * 8 + # MTU should not count FPort + mtu_available += regular_message.header.rule_id.size if len(self.sm.tiles) > 1: candid = self.sm.tiles[0] while mtu_available >= candid.size and len(self.sm.tiles) > 1: @@ -168,16 +170,13 @@ def receive_schc_ack(self, schc_message): # TODO return - def __init__(self, protocol, payload, residue="", dtag=None): - super().__init__(protocol, payload, residue=residue, dtag=dtag) + def __init__(self, protocol, payload, padding=0, dtag=None): + super().__init__(protocol, payload, padding=padding, dtag=dtag) self.states["initial_phase"] = AckOnErrorSender.InitialPhase(self) self.states["sending_phase"] = AckOnErrorSender.SendingPhase(self) self.states["waiting_phase"] = AckOnErrorSender.WaitingPhase(self) self.state = self.states["initial_phase"] self.state.enter_state() - if len(self.remaining_packet) % self.protocol.L2_WORD != 0: - padding = "0" * (self.protocol.L2_WORD - (len(self.remaining_packet) % self.protocol.L2_WORD)) - self.rcs = self.protocol.calculate_rcs(self.remaining_packet + padding) self.tiles = list() self.sent_tiles = list() self.state.__generate_tiles__() diff --git a/fragmentation_layer/code/schc_machines/schc_sender.py b/fragmentation_layer/code/schc_machines/schc_sender.py index 4e59bfa..ef8fd67 100644 --- a/fragmentation_layer/code/schc_machines/schc_sender.py +++ b/fragmentation_layer/code/schc_machines/schc_sender.py @@ -91,7 +91,7 @@ def receive_schc_receiver_abort(self, schc_message): self.sm.state.enter_state() return - def __init__(self, protocol, payload, residue="", dtag=None): + def __init__(self, protocol, payload, padding=0, dtag=None): """ Constructor @@ -100,16 +100,20 @@ def __init__(self, protocol, payload, residue="", dtag=None): protocol payload : bytes Payload to fragment - residue : str - Bits (as a string) obtained as residue of compression process + padding : int + Padding size dtag """ super().__init__(protocol, dtag=dtag) self.retransmission_timer = SCHCTimer(self.on_expiration_time, protocol.RETRANSMISSION_TIMER) self.retransmission_timer.stop() self.packet = payload - self.residue = residue - self.remaining_packet = residue + SCHCObject.bytes_2_bits(payload) - self.rcs = self.protocol.calculate_rcs(self.remaining_packet) + if padding == 0: + self.remaining_packet = SCHCObject.bytes_2_bits(payload) + self.rcs = self.protocol.calculate_rcs(self.remaining_packet) + else: + payload_as_bits = SCHCObject.bytes_2_bits(payload) + self.remaining_packet = payload_as_bits[0:-padding] + self.rcs = self.protocol.calculate_rcs(payload_as_bits) self.__end_msg__ = "Message sent and acknowledged" return diff --git a/fragmentation_layer/example/received.txt b/fragmentation_layer/example/received.txt index 606f887..454a602 100644 --- a/fragmentation_layer/example/received.txt +++ b/fragmentation_layer/example/received.txt @@ -42,5 +42,3 @@ Copyright Notice include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License. - -And residue: 0101100 diff --git a/fragmentation_layer/example/test_receiver.py b/fragmentation_layer/example/test_receiver.py index a5cc952..63a537b 100644 --- a/fragmentation_layer/example/test_receiver.py +++ b/fragmentation_layer/example/test_receiver.py @@ -26,8 +26,6 @@ messaging_loop(receiver, socket_rx, SENDER_PORT) packet = receiver.payload.as_bits() - residue = packet[0:7] - packet = packet[7:-1] assert len(packet) % 8 == 0 from schc_base import SCHCObject diff --git a/fragmentation_layer/example/test_sender.py b/fragmentation_layer/example/test_sender.py index 8395d11..86a2b5d 100644 --- a/fragmentation_layer/example/test_sender.py +++ b/fragmentation_layer/example/test_sender.py @@ -70,8 +70,7 @@ sender = AckOnErrorSender( LoRaWAN(LoRaWAN.ACK_ON_ERROR), - MESSAGE, - RESIDUE + MESSAGE ) messaging_loop(sender, socket_rx, SENDER_PORT) From c52e2a570139f2f8b9889c9c94380f7c7670819c Mon Sep 17 00:00:00 2001 From: Juan Ma Date: Thu, 29 Apr 2021 09:30:37 -0400 Subject: [PATCH 03/50] Conflics resolved, and fixed lopy script --- .gitignore | 3 -- fragmentation_layer/code/main.py | 42 +++++++++++++++++ fragmentation_layer/code/message.py | 45 +++++++++++++++++++ .../code/schc_handlers/schc_node_handler.py | 29 ++++++++++++ fragmentation_layer/example/test_receiver.py | 1 - 5 files changed, 116 insertions(+), 4 deletions(-) create mode 100644 fragmentation_layer/code/main.py create mode 100644 fragmentation_layer/code/message.py diff --git a/.gitignore b/.gitignore index 456860b..1051571 100644 --- a/.gitignore +++ b/.gitignore @@ -72,6 +72,3 @@ fabric.properties # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser - -# Node -fragmentation_layer/code/main.py diff --git a/fragmentation_layer/code/main.py b/fragmentation_layer/code/main.py new file mode 100644 index 0000000..2bcbc6a --- /dev/null +++ b/fragmentation_layer/code/main.py @@ -0,0 +1,42 @@ +from network import LoRa +import socket +import binascii +import struct + +from message import MESSAGE +from schc_handlers import SCHCNodeHandler +from schc_protocols import LoRaWAN + +# Initialise LoRa in LORAWAN mode. +# Please pick the region that matches where you are using the device: +# Asia = LoRa.AS923 +# Australia = LoRa.AU915 +# Europe = LoRa.EU868 +# United States = LoRa.US915 +lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.AU915) + +# create an ABP authentication params +dev_addr = struct.unpack(">l", binascii.unhexlify('2601350A'))[0] +nwk_swkey = binascii.unhexlify('2A46B48AE1418C4C55CFA6B06822FBE8') +app_swkey = binascii.unhexlify('A9054AA86E7049BC5D76C4E40CDE44E9') + +# Uncomment for US915 / AU915 & Pygate +for i in range(0, 8): + lora.remove_channel(i) +for i in range(9, 65): + lora.remove_channel(i) +for i in range(66, 72): + lora.remove_channel(i) + +# join a network using ABP (Activation By Personalization) +lora.join(activation=LoRa.ABP, auth=(dev_addr, nwk_swkey, app_swkey)) + +# create a LoRa socket +s = socket.socket(socket.AF_LORA, socket.SOCK_RAW) + +# set the LoRaWAN data rate +s.setsockopt(socket.SOL_LORA, socket.SO_DR, 0) + +handler = SCHCNodeHandler(LoRaWAN(LoRaWAN.ACK_ON_ERROR), 51) +handler.send_package(MESSAGE) +handler.start(s) diff --git a/fragmentation_layer/code/message.py b/fragmentation_layer/code/message.py new file mode 100644 index 0000000..feab135 --- /dev/null +++ b/fragmentation_layer/code/message.py @@ -0,0 +1,45 @@ +MESSAGE = """ +Abstract + + The Static Context Header Compression (SCHC) specification describes + generic header compression and fragmentation techniques for Low Power + Wide Area Networks (LPWAN) technologies. SCHC is a generic mechanism + designed for great flexibility so that it can be adapted for any of + the LPWAN technologies. + + This document specifies a profile of RFC8724 to use SCHC in + LoRaWAN(R) networks, and provides elements such as efficient + parameterization and modes of operation. + +Status of This Memo + + This Internet-Draft is submitted in full conformance with the + provisions of BCP 78 and BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF). Note that other groups may also distribute + working documents as Internet-Drafts. The list of current Internet- + Drafts is at https://datatracker.ietf.org/drafts/current/. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + This Internet-Draft will expire on July 29, 2021. + +Copyright Notice + + Copyright (c) 2021 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. +""".encode("ascii") diff --git a/fragmentation_layer/code/schc_handlers/schc_node_handler.py b/fragmentation_layer/code/schc_handlers/schc_node_handler.py index dae89bb..211a27b 100644 --- a/fragmentation_layer/code/schc_handlers/schc_node_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_node_handler.py @@ -37,3 +37,32 @@ def generate_message(self, rule_id, dtag, mtu=512): return self.__sessions__[rule_id][dtag].generate_message(mtu).as_bytes() except GeneratorExit: return b'' + + def start(self, s): + while True: + for rule_id in self.__sessions__.keys(): + for dtag in self.__sessions__[rule_id].keys(): + machine = self.__sessions__[rule_id][dtag] + message = machine.generate_message(self.__mtu__) + + if message is not None: + s.setblocking(True) + print(message.as_text()) + + # send some data + if self.__protocol__.id == SCHCProtocol.LoRaWAN: + s.bind(int(message.as_bytes()[0])) + s.send(message.as_bytes()[1:]) + else: + s.send(message.as_bytes()) + + # make the socket non-blocking + # (because if there's no data received it will block forever...) + s.setblocking(False) + + # get any data received (if any...) + data = s.recvfrom(512) + print(data) + if data[0] != b'': + r, d = self.identify_session_from_message(data) + self.receive(r, d, data) diff --git a/fragmentation_layer/example/test_receiver.py b/fragmentation_layer/example/test_receiver.py index 63a537b..2233bc5 100644 --- a/fragmentation_layer/example/test_receiver.py +++ b/fragmentation_layer/example/test_receiver.py @@ -32,4 +32,3 @@ message = SCHCObject.bits_2_bytes(packet) with open("received.txt", "w", encoding="utf-8") as received_file: received_file.write(message.decode("ascii")) - received_file.write("\nAnd residue:\t{}\n".format(residue)) From e73f877431f984414372b94393b2a02c09cce2e4 Mon Sep 17 00:00:00 2001 From: Juan Ma Date: Thu, 29 Apr 2021 09:57:09 -0400 Subject: [PATCH 04/50] Code on LoPy tested --- fragmentation_layer/code/main.py | 4 ++-- fragmentation_layer/code/schc_machines/lorawan/__init__.py | 4 ++-- fragmentation_layer/code/schc_protocols/schc_protocol.py | 6 ++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/fragmentation_layer/code/main.py b/fragmentation_layer/code/main.py index 2bcbc6a..7818694 100644 --- a/fragmentation_layer/code/main.py +++ b/fragmentation_layer/code/main.py @@ -5,7 +5,7 @@ from message import MESSAGE from schc_handlers import SCHCNodeHandler -from schc_protocols import LoRaWAN +from schc_protocols import SCHCProtocol # Initialise LoRa in LORAWAN mode. # Please pick the region that matches where you are using the device: @@ -37,6 +37,6 @@ # set the LoRaWAN data rate s.setsockopt(socket.SOL_LORA, socket.SO_DR, 0) -handler = SCHCNodeHandler(LoRaWAN(LoRaWAN.ACK_ON_ERROR), 51) +handler = SCHCNodeHandler(SCHCProtocol.LoRaWAN, 51) handler.send_package(MESSAGE) handler.start(s) diff --git a/fragmentation_layer/code/schc_machines/lorawan/__init__.py b/fragmentation_layer/code/schc_machines/lorawan/__init__.py index 6a3c93d..147e7e5 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/__init__.py +++ b/fragmentation_layer/code/schc_machines/lorawan/__init__.py @@ -2,5 +2,5 @@ from schc_machines.lorawan.ack_on_error_receiver import AckOnErrorReceiver from schc_machines.lorawan.ack_on_error_sender import AckOnErrorSender -from schc_machines.lorawan.ack_always_receiver import AckAlwaysReceiver -from schc_machines.lorawan.ack_always_sender import AckAlwaysSender +# from schc_machines.lorawan.ack_always_receiver import AckAlwaysReceiver +# from schc_machines.lorawan.ack_always_sender import AckAlwaysSender diff --git a/fragmentation_layer/code/schc_protocols/schc_protocol.py b/fragmentation_layer/code/schc_protocols/schc_protocol.py index 07f56b7..6e86b28 100644 --- a/fragmentation_layer/code/schc_protocols/schc_protocol.py +++ b/fragmentation_layer/code/schc_protocols/schc_protocol.py @@ -109,8 +109,10 @@ def calculate_rcs(self, packet): str : Result of Reassembly Check Sequence (RCS) """ - from binascii import crc32 - return hex(crc32(SCHCObject.bits_2_bytes(packet))) + # TODO: self implementation of crc32 + # from binascii import crc32 + # return hex(crc32(SCHCObject.bits_2_bytes(packet))) + return "" def penultimate_tile(self): """ From 8303511ebe1d20c22d3b0a3ec07e0ef5e69e6283 Mon Sep 17 00:00:00 2001 From: Juan Ma Date: Thu, 29 Apr 2021 10:13:05 -0400 Subject: [PATCH 05/50] Current config changed --- fragmentation_layer/code/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fragmentation_layer/code/main.py b/fragmentation_layer/code/main.py index 7818694..330d80d 100644 --- a/fragmentation_layer/code/main.py +++ b/fragmentation_layer/code/main.py @@ -16,9 +16,9 @@ lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.AU915) # create an ABP authentication params -dev_addr = struct.unpack(">l", binascii.unhexlify('2601350A'))[0] -nwk_swkey = binascii.unhexlify('2A46B48AE1418C4C55CFA6B06822FBE8') -app_swkey = binascii.unhexlify('A9054AA86E7049BC5D76C4E40CDE44E9') +dev_addr = struct.unpack(">l", binascii.unhexlify('26011011'))[0] +nwk_swkey = binascii.unhexlify('40792D626980A95B0F1F863C291D420E') +app_swkey = binascii.unhexlify('5ED101DD805B089C90BC3BD1061EA6FC') # Uncomment for US915 / AU915 & Pygate for i in range(0, 8): From 1feea53e1b60b8e1a055c22e0179f20a3b4de5ca Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Thu, 29 Apr 2021 12:43:25 -0400 Subject: [PATCH 06/50] Changes to GatewayHandler --- .../code/schc_handlers/schc_gateway_handler.py | 10 +++++++++- fragmentation_layer/code/schc_handlers/schc_handler.py | 2 +- .../code/schc_handlers/schc_node_handler.py | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index 925f4a5..db5927d 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -16,7 +16,7 @@ def send_package(self, packet): else: raise NotImplementedError("Just LoRaWAN implemented") - def receive(self, rule_id, dtag, message, f_port=None): + def receive(self, rule_id, dtag, message): if self.__protocol__.id == SCHCProtocol.LoRaWAN: if rule_id == LoRaWAN.ACK_ON_ERROR: # message received @@ -32,6 +32,14 @@ def receive(self, rule_id, dtag, message, f_port=None): else: raise NotImplementedError("Just LoRaWAN implemented") + def handle(self, message, f_port=None): + if self.__protocol__.id == SCHCProtocol.LoRaWAN: + r,d = self.identify_session_from_message(message, f_port) + self.receive(r,d,bytes([f_port]) + message) + return self.generate_message(r,d) + else: + raise NotImplementedError("Just LoRaWAN implemented") + def generate_message(self, rule_id, dtag, mtu=512): try: return self.__sessions__[rule_id][dtag].generate_message(mtu).as_bytes() diff --git a/fragmentation_layer/code/schc_handlers/schc_handler.py b/fragmentation_layer/code/schc_handlers/schc_handler.py index c463661..03ee919 100644 --- a/fragmentation_layer/code/schc_handlers/schc_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_handler.py @@ -29,7 +29,7 @@ def identify_session_from_message(self, message, f_port=None): def send_package(self, packet): return - def receive(self, rule_id, dtag, message, f_port=None): + def receive(self, rule_id, dtag, message): return def generate_message(self, rule_id, dtag, mtu=512): diff --git a/fragmentation_layer/code/schc_handlers/schc_node_handler.py b/fragmentation_layer/code/schc_handlers/schc_node_handler.py index 211a27b..c231b66 100644 --- a/fragmentation_layer/code/schc_handlers/schc_node_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_node_handler.py @@ -16,7 +16,7 @@ def send_package(self, packet): else: raise NotImplementedError("Just LoRaWAN implemented") - def receive(self, rule_id, dtag, message, f_port=None): + def receive(self, rule_id, dtag, message): if self.__protocol__.id == SCHCProtocol.LoRaWAN: if rule_id == LoRaWAN.ACK_ALWAYS: # message received From 16b0eec6eb5820fc219031b916e1e1c02e4991a3 Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Thu, 29 Apr 2021 12:47:19 -0400 Subject: [PATCH 07/50] fport as bytes --- fragmentation_layer/code/schc_handlers/schc_gateway_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index db5927d..c0b6026 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -34,7 +34,7 @@ def receive(self, rule_id, dtag, message): def handle(self, message, f_port=None): if self.__protocol__.id == SCHCProtocol.LoRaWAN: - r,d = self.identify_session_from_message(message, f_port) + r,d = self.identify_session_from_message(message, bytes([f_port])) self.receive(r,d,bytes([f_port]) + message) return self.generate_message(r,d) else: From 0d54b99087f2ccc70096045fc6ed90daeb57a9cc Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Thu, 29 Apr 2021 12:56:40 -0400 Subject: [PATCH 08/50] Bugfix: generate_message --- .../code/schc_handlers/schc_gateway_handler.py | 9 +++++---- fragmentation_layer/code/schc_handlers/schc_handler.py | 3 --- .../code/schc_handlers/schc_node_handler.py | 6 ------ 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index c0b6026..b354ceb 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -41,7 +41,8 @@ def handle(self, message, f_port=None): raise NotImplementedError("Just LoRaWAN implemented") def generate_message(self, rule_id, dtag, mtu=512): - try: - return self.__sessions__[rule_id][dtag].generate_message(mtu).as_bytes() - except GeneratorExit: - return b'' + message = self.__sessions__[rule_id][dtag].generate_message(mtu) + if message is None: + return message + else: + return message.as_bytes() diff --git a/fragmentation_layer/code/schc_handlers/schc_handler.py b/fragmentation_layer/code/schc_handlers/schc_handler.py index 03ee919..375257a 100644 --- a/fragmentation_layer/code/schc_handlers/schc_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_handler.py @@ -32,9 +32,6 @@ def send_package(self, packet): def receive(self, rule_id, dtag, message): return - def generate_message(self, rule_id, dtag, mtu=512): - raise GeneratorExit("Abstract class cannot generate message") - def assign_session(self, rule_id, dtag, machine): if rule_id not in self.__sessions__.keys(): self.__sessions__[rule_id] = dict() diff --git a/fragmentation_layer/code/schc_handlers/schc_node_handler.py b/fragmentation_layer/code/schc_handlers/schc_node_handler.py index c231b66..3764e5f 100644 --- a/fragmentation_layer/code/schc_handlers/schc_node_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_node_handler.py @@ -32,12 +32,6 @@ def receive(self, rule_id, dtag, message): else: raise NotImplementedError("Just LoRaWAN implemented") - def generate_message(self, rule_id, dtag, mtu=512): - try: - return self.__sessions__[rule_id][dtag].generate_message(mtu).as_bytes() - except GeneratorExit: - return b'' - def start(self, s): while True: for rule_id in self.__sessions__.keys(): From 0b3fe624a46160b6c534d8b82b36370ceae77093 Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Thu, 29 Apr 2021 13:29:15 -0400 Subject: [PATCH 09/50] Respond a message --- .../code/schc_handlers/schc_gateway_handler.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index b354ceb..687944e 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -8,6 +8,8 @@ class SCHCGatewayHandler(SCHCHandler): def __init__(self, protocol, mtu): super().__init__(protocol, mtu) + import requests + import base64 def send_package(self, packet): if self.__protocol__.id == SCHCProtocol.LoRaWAN: @@ -32,13 +34,23 @@ def receive(self, rule_id, dtag, message): else: raise NotImplementedError("Just LoRaWAN implemented") - def handle(self, message, f_port=None): + def handle(self, message, f_port=None, url=None, dev_id=None): if self.__protocol__.id == SCHCProtocol.LoRaWAN: r,d = self.identify_session_from_message(message, bytes([f_port])) self.receive(r,d,bytes([f_port]) + message) - return self.generate_message(r,d) + response = self.generate_message(r,d) else: raise NotImplementedError("Just LoRaWAN implemented") + if url is None: + return response + else: + post_obj = { + "dev_id": dev_id, + "port": f_port, + "confirmed": False, + "payload_raw": base64.b64encode(response).decode("utf-8") + } + requests.post(url, post_obj) def generate_message(self, rule_id, dtag, mtu=512): message = self.__sessions__[rule_id][dtag].generate_message(mtu) From aa22f19daa7967f5eb6d3a09cd88ff5b2b2cc603 Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Thu, 29 Apr 2021 13:39:25 -0400 Subject: [PATCH 10/50] fix imports --- .../code/schc_handlers/schc_gateway_handler.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index 687944e..8f877d2 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -1,4 +1,9 @@ """ schc_gateway_handler: SCHC Gateway Handler Class """ +import sys + +if sys.implementation.name != 'micropython': + import requests + import base64 from schc_handlers import SCHCHandler from schc_protocols import LoRaWAN, SCHCProtocol @@ -8,8 +13,6 @@ class SCHCGatewayHandler(SCHCHandler): def __init__(self, protocol, mtu): super().__init__(protocol, mtu) - import requests - import base64 def send_package(self, packet): if self.__protocol__.id == SCHCProtocol.LoRaWAN: From 08c6898401c0def8c9b55966b961d34fc52c5d5f Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Thu, 29 Apr 2021 13:41:43 -0400 Subject: [PATCH 11/50] fix bug --- fragmentation_layer/code/schc_handlers/schc_gateway_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index 8f877d2..2cbbf60 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -46,7 +46,7 @@ def handle(self, message, f_port=None, url=None, dev_id=None): raise NotImplementedError("Just LoRaWAN implemented") if url is None: return response - else: + elif response is None: post_obj = { "dev_id": dev_id, "port": f_port, From a8a9ad0bad98dade0295f1e729a2297705b11e7b Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Thu, 29 Apr 2021 13:43:27 -0400 Subject: [PATCH 12/50] fix bug x2 --- fragmentation_layer/code/schc_handlers/schc_gateway_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index 2cbbf60..7460f6d 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -46,7 +46,7 @@ def handle(self, message, f_port=None, url=None, dev_id=None): raise NotImplementedError("Just LoRaWAN implemented") if url is None: return response - elif response is None: + elif response != None: post_obj = { "dev_id": dev_id, "port": f_port, From e1434a2633421bcca33376f2b1cc49cae33836ba Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Thu, 29 Apr 2021 13:52:10 -0400 Subject: [PATCH 13/50] fix request format --- .../code/schc_handlers/schc_gateway_handler.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index 7460f6d..69a85df 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -4,6 +4,7 @@ if sys.implementation.name != 'micropython': import requests import base64 + import json from schc_handlers import SCHCHandler from schc_protocols import LoRaWAN, SCHCProtocol @@ -51,9 +52,11 @@ def handle(self, message, f_port=None, url=None, dev_id=None): "dev_id": dev_id, "port": f_port, "confirmed": False, - "payload_raw": base64.b64encode(response).decode("utf-8") + "payload_raw": base64.b64encode(response[1:]).decode("utf-8") } - requests.post(url, post_obj) + r = requests.post(url, data=json.dumps(post_obj), headers={'content-type': 'application/json'}) + print(r.status_code) + def generate_message(self, rule_id, dtag, mtu=512): message = self.__sessions__[rule_id][dtag].generate_message(mtu) From baf796fff06e8fb8ee82ab0539fa1e7fd222fa21 Mon Sep 17 00:00:00 2001 From: Juan Ma Date: Thu, 29 Apr 2021 16:27:28 -0400 Subject: [PATCH 14/50] SCHCAckReq after window --- .../code/schc_handlers/schc_gateway_handler.py | 9 ++++----- .../schc_machines/lorawan/ack_on_error_sender.py | 14 +++++++++++++- .../code/schc_protocols/schc_protocol.py | 2 +- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index 69a85df..dca2e18 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -40,14 +40,14 @@ def receive(self, rule_id, dtag, message): def handle(self, message, f_port=None, url=None, dev_id=None): if self.__protocol__.id == SCHCProtocol.LoRaWAN: - r,d = self.identify_session_from_message(message, bytes([f_port])) - self.receive(r,d,bytes([f_port]) + message) - response = self.generate_message(r,d) + r, d = self.identify_session_from_message(message, bytes([f_port])) + self.receive(r, d, bytes([f_port]) + message) + response = self.generate_message(r, d) else: raise NotImplementedError("Just LoRaWAN implemented") if url is None: return response - elif response != None: + elif response is not None: post_obj = { "dev_id": dev_id, "port": f_port, @@ -57,7 +57,6 @@ def handle(self, message, f_port=None, url=None, dev_id=None): r = requests.post(url, data=json.dumps(post_obj), headers={'content-type': 'application/json'}) print(r.status_code) - def generate_message(self, rule_id, dtag, mtu=512): message = self.__sessions__[rule_id][dtag].generate_message(mtu) if message is None: diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py index 581fc28..b7ce390 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py @@ -2,7 +2,7 @@ from schc_base import Tile, Bitmap from schc_machines import SCHCSender -from schc_messages import RegularSCHCFragment, All1SCHCFragment, SCHCAck +from schc_messages import RegularSCHCFragment, All1SCHCFragment, SCHCAck, SCHCAckReq class AckOnErrorSender(SCHCSender): @@ -89,6 +89,12 @@ def generate_message(self, mtu): self.sm.state = self.sm.states["waiting_phase"] self.sm.retransmission_timer.reset() self.sm.state.enter_state() + self.sm.message_to_send.append(SCHCAckReq( + self.sm.__rule_id__, + self.sm.protocol.id, + self.sm.__cw__, + self.sm.__dtag__ + )) break else: last_tile = self.sm.tiles.pop(0) @@ -106,6 +112,12 @@ def generate_message(self, mtu): self.sm.state = self.sm.states["waiting_phase"] self.sm.state.enter_state() self.sm.retransmission_timer.reset() + self.sm.message_to_send.append(SCHCAckReq( + self.sm.__rule_id__, + self.sm.protocol.id, + self.sm.__cw__, + self.sm.__dtag__ + )) all1.add_padding() return all1 regular_message.add_padding() diff --git a/fragmentation_layer/code/schc_protocols/schc_protocol.py b/fragmentation_layer/code/schc_protocols/schc_protocol.py index 6e86b28..de39080 100644 --- a/fragmentation_layer/code/schc_protocols/schc_protocol.py +++ b/fragmentation_layer/code/schc_protocols/schc_protocol.py @@ -112,7 +112,7 @@ def calculate_rcs(self, packet): # TODO: self implementation of crc32 # from binascii import crc32 # return hex(crc32(SCHCObject.bits_2_bytes(packet))) - return "" + return "0xb4cc4a0" def penultimate_tile(self): """ From 318bf22924e3b449d70039d9a72ff8836da68706 Mon Sep 17 00:00:00 2001 From: Juan Ma Date: Thu, 29 Apr 2021 17:02:21 -0400 Subject: [PATCH 15/50] SCHC Ack Req sent --- .../code/schc_machines/lorawan/ack_on_error_sender.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py index b7ce390..aefde3b 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py @@ -142,7 +142,12 @@ def generate_message(self, mtu): SCHCMessage : None """ - return None + if len(self.sm.message_to_send) != 0: + if self.sm.message_to_send[0].size - self.sm.protocol.FPORT_LENGTH <= mtu * 8: + message = self.sm.message_to_send.pop(0) + return message + else: + return None def receive_schc_ack(self, schc_message): """ From 9570a01dcd7f9f76520b3d8b5769bc1c837baf95 Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Thu, 20 May 2021 19:45:00 -0400 Subject: [PATCH 16/50] Fixed uncompressed bitmaps in schc acks --- .../code/schc_machines/lorawan/ack_on_error_receiver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py index 7d3cfc1..598b316 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py @@ -286,7 +286,7 @@ def receive_schc_ack_req(self, schc_message): if not self.sm.__last_window__: self.sm.message_to_send.append( SCHCAck(self.sm.__rule_id__, self.sm.protocol.id, - c=False, w=w, compressed_bitmap=self.sm.bitmaps[w]) + c=False, w=w, compressed_bitmap=self.sm.bitmaps[w].generate_compress()) ) else: pass From 06e037bcea45ca1c1f90957bc318c22c4c3caa31 Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Mon, 24 May 2021 16:48:33 -0400 Subject: [PATCH 17/50] (Sort of) successful 1st test --- fragmentation_layer/code/main.py | 10 +++++----- fragmentation_layer/code/message.py | 1 + .../code/schc_handlers/schc_handler.py | 2 +- .../code/schc_handlers/schc_node_handler.py | 4 ++-- .../schc_machines/lorawan/ack_on_error_sender.py | 15 +++++++++++++++ 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/fragmentation_layer/code/main.py b/fragmentation_layer/code/main.py index 330d80d..9445e4f 100644 --- a/fragmentation_layer/code/main.py +++ b/fragmentation_layer/code/main.py @@ -3,7 +3,7 @@ import binascii import struct -from message import MESSAGE +from message import SHORT_MESSAGE from schc_handlers import SCHCNodeHandler from schc_protocols import SCHCProtocol @@ -16,9 +16,9 @@ lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.AU915) # create an ABP authentication params -dev_addr = struct.unpack(">l", binascii.unhexlify('26011011'))[0] -nwk_swkey = binascii.unhexlify('40792D626980A95B0F1F863C291D420E') -app_swkey = binascii.unhexlify('5ED101DD805B089C90BC3BD1061EA6FC') +dev_addr = struct.unpack(">l", binascii.unhexlify('260138EA'))[0] +nwk_swkey = binascii.unhexlify('133CD7499E57B03FF0430D14FF479D71') +app_swkey = binascii.unhexlify('A9CEF74251EC08F21FBEFBD8E08D3206') # Uncomment for US915 / AU915 & Pygate for i in range(0, 8): @@ -38,5 +38,5 @@ s.setsockopt(socket.SOL_LORA, socket.SO_DR, 0) handler = SCHCNodeHandler(SCHCProtocol.LoRaWAN, 51) -handler.send_package(MESSAGE) +handler.send_package(SHORT_MESSAGE) handler.start(s) diff --git a/fragmentation_layer/code/message.py b/fragmentation_layer/code/message.py index feab135..cb1a82a 100644 --- a/fragmentation_layer/code/message.py +++ b/fragmentation_layer/code/message.py @@ -43,3 +43,4 @@ the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License. """.encode("ascii") +SHORT_MESSAGE = "Copyright (c) 2021 IETF Trust and the persons identified as the document authors. All rights reserved.".encode("ascii") \ No newline at end of file diff --git a/fragmentation_layer/code/schc_handlers/schc_handler.py b/fragmentation_layer/code/schc_handlers/schc_handler.py index 375257a..65f7579 100644 --- a/fragmentation_layer/code/schc_handlers/schc_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_handler.py @@ -14,7 +14,7 @@ def __init__(self, protocol, mtu): def identify_session_from_message(self, message, f_port=None): if self.__protocol__.id == SCHCProtocol.LoRaWAN: - rule_id = int.from_bytes(f_port, "big") + rule_id = f_port else: raise NotImplementedError("Just LoRaWAN implemented") protocol = get_protocol(self.__protocol__.id) diff --git a/fragmentation_layer/code/schc_handlers/schc_node_handler.py b/fragmentation_layer/code/schc_handlers/schc_node_handler.py index 3764e5f..a8c9b42 100644 --- a/fragmentation_layer/code/schc_handlers/schc_node_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_node_handler.py @@ -58,5 +58,5 @@ def start(self, s): data = s.recvfrom(512) print(data) if data[0] != b'': - r, d = self.identify_session_from_message(data) - self.receive(r, d, data) + r, d = self.identify_session_from_message(*data) + self.receive(r, d, bytes([data[1]]) + data[0]) diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py index aefde3b..eec730a 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py @@ -124,6 +124,21 @@ def generate_message(self, mtu): self._logger_.schc_message(regular_message) return regular_message + def receive_schc_ack(self, schc_message): + """ + Logs SCHC ACK + + Parameters + ---------- + schc_message : SCHCAck + Message received + + Returns + ------- + None + """ + self._logger_.debug("Received SCHC ACK. Ignoring.") + class WaitingPhase(SCHCSender.SenderState): """ Waiting Phase of Ack on Error From cc5fbc7782f66fd58f7ef560087e2379230140fc Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Tue, 25 May 2021 21:13:07 -0400 Subject: [PATCH 18/50] minor fixes --- fragmentation_layer/code/main.py | 4 ++-- fragmentation_layer/code/message.py | 2 +- .../code/schc_machines/lorawan/ack_on_error_sender.py | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fragmentation_layer/code/main.py b/fragmentation_layer/code/main.py index 9445e4f..70987ba 100644 --- a/fragmentation_layer/code/main.py +++ b/fragmentation_layer/code/main.py @@ -3,7 +3,7 @@ import binascii import struct -from message import SHORT_MESSAGE +from message import MESSAGE from schc_handlers import SCHCNodeHandler from schc_protocols import SCHCProtocol @@ -38,5 +38,5 @@ s.setsockopt(socket.SOL_LORA, socket.SO_DR, 0) handler = SCHCNodeHandler(SCHCProtocol.LoRaWAN, 51) -handler.send_package(SHORT_MESSAGE) +handler.send_package(MESSAGE) handler.start(s) diff --git a/fragmentation_layer/code/message.py b/fragmentation_layer/code/message.py index cb1a82a..4d54f6b 100644 --- a/fragmentation_layer/code/message.py +++ b/fragmentation_layer/code/message.py @@ -43,4 +43,4 @@ the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License. """.encode("ascii") -SHORT_MESSAGE = "Copyright (c) 2021 IETF Trust and the persons identified as the document authors. All rights reserved.".encode("ascii") \ No newline at end of file +SHORT_MESSAGE = "Copyright (c) 2021 IETF Trust and the persons identified as the document authors.".encode("ascii") \ No newline at end of file diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py index eec730a..cd89a06 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py @@ -92,8 +92,8 @@ def generate_message(self, mtu): self.sm.message_to_send.append(SCHCAckReq( self.sm.__rule_id__, self.sm.protocol.id, - self.sm.__cw__, - self.sm.__dtag__ + self.sm.__dtag__, + self.sm.__cw__ )) break else: @@ -115,8 +115,8 @@ def generate_message(self, mtu): self.sm.message_to_send.append(SCHCAckReq( self.sm.__rule_id__, self.sm.protocol.id, - self.sm.__cw__, - self.sm.__dtag__ + self.sm.__dtag__, + self.sm.__cw__ )) all1.add_padding() return all1 From 2d364f0b96e25c0035b60d7d568402c0bb856f23 Mon Sep 17 00:00:00 2001 From: Juan Ma Date: Tue, 25 May 2021 23:18:32 -0400 Subject: [PATCH 19/50] Message reassembled show in logs once is cocompletely received --- .../code/schc_machines/lorawan/ack_on_error_receiver.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py index 598b316..96379d8 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py @@ -138,6 +138,7 @@ def receive_all1_schc_fragment(self, schc_message): self.sm.__last_window__ = True last_payload = schc_message.payload.as_bytes() self.sm.payload.add_content(last_payload) + self._logger_.debug("Message received:\n" + self.sm.payload.as_bytes().decode("ascii")) rcs = self.sm.protocol.calculate_rcs( self.sm.payload.as_bits() ) From c60c597c1dec1f0718c54102480d58c58adb7617 Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Wed, 26 May 2021 19:38:55 -0400 Subject: [PATCH 20/50] fixed inconsistency --- fragmentation_layer/code/schc_handlers/schc_gateway_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index dca2e18..c5d4a24 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -40,7 +40,7 @@ def receive(self, rule_id, dtag, message): def handle(self, message, f_port=None, url=None, dev_id=None): if self.__protocol__.id == SCHCProtocol.LoRaWAN: - r, d = self.identify_session_from_message(message, bytes([f_port])) + r, d = self.identify_session_from_message(message, f_port) self.receive(r, d, bytes([f_port]) + message) response = self.generate_message(r, d) else: From 07171191ef43358a6cecb4fa61ea53edd1894f11 Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Wed, 26 May 2021 20:40:55 -0400 Subject: [PATCH 21/50] Sending img test --- fragmentation_layer/code/image_message.py | 1 + fragmentation_layer/code/main.py | 2 +- .../lorawan/ack_on_error_receiver.py | 5 ++++- fragmentation_layer/code/test_img.png | Bin 0 -> 928 bytes 4 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 fragmentation_layer/code/image_message.py create mode 100644 fragmentation_layer/code/test_img.png diff --git a/fragmentation_layer/code/image_message.py b/fragmentation_layer/code/image_message.py new file mode 100644 index 0000000..e72a15d --- /dev/null +++ b/fragmentation_layer/code/image_message.py @@ -0,0 +1 @@ +MESSAGE = open("test_img.png", "rb").read() \ No newline at end of file diff --git a/fragmentation_layer/code/main.py b/fragmentation_layer/code/main.py index 70987ba..000ca2d 100644 --- a/fragmentation_layer/code/main.py +++ b/fragmentation_layer/code/main.py @@ -3,7 +3,7 @@ import binascii import struct -from message import MESSAGE +from image_message import MESSAGE from schc_handlers import SCHCNodeHandler from schc_protocols import SCHCProtocol diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py index 96379d8..465b0a5 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py @@ -138,13 +138,16 @@ def receive_all1_schc_fragment(self, schc_message): self.sm.__last_window__ = True last_payload = schc_message.payload.as_bytes() self.sm.payload.add_content(last_payload) - self._logger_.debug("Message received:\n" + self.sm.payload.as_bytes().decode("ascii")) rcs = self.sm.protocol.calculate_rcs( self.sm.payload.as_bits() ) integrity = rcs == schc_message.header.rcs.rcs if integrity: self._logger_.debug("Integrity check successful") + #self._logger_.debug("Message received:\n" + self.sm.payload.as_bytes().decode("ascii")) + out = open("received.png", "wb") + out.write(self.sm.payload.as_bytes()) + out.close() compressed_bitmap = None self.__success__ = True else: diff --git a/fragmentation_layer/code/test_img.png b/fragmentation_layer/code/test_img.png new file mode 100644 index 0000000000000000000000000000000000000000..5bd4791212f1a9f18fffb00fb3707a0b3bdd3be7 GIT binary patch literal 928 zcmV;R17G}!P)Px#1ZP1_K>z@;j|==^1poj59#BkFMZKz{_1VLKKWgb;fc^L1hK7b-t=3q1qEJ|U z|NsB{c)dmd000SaNLh0L01m?d01m?e$8V@)0009ENklhmEJrTf7fu17(&Kc1^O@>F{jX7~GLkgIh z<0#1tIEMr|*G5_OW!MU9T#EziXzNT*=ZThx_>*Lg2N%NE?kiphze3tq^6&q_N z0OD#Zxws47A&}11HO^YxAQ|{A$}|r>D|3??Yu0|>60kZ@edv2ja=qB^!woaT9glrd zV0gHq)~FjxKe+XE8{OiTwiua2S$3lu(3IH22*d4IXaL@b2rwa(s8^&+Qd}aK( z7?_~jeFmfuenSS2wF38CO4ex!%TNfvp%mcIpVJfr+F-EY1FMDbTZfPE`owG8;I+~2 zrWs-({ImP=_~F%RoiOxHJP`_bzuTP$;5we^WxR-I&#v{qr3zB1(EvsOebR>q)t7qJ zay&aOK-7mpJ0@JUavq!rQYVTZd(so2S1svpX$Dbr{Q9sUqSK2y0Yi#)4e`9mtHF!( zTQYcwdINHt)0-ou9EM*nL8m$jQH_mN%t-eaL6@D5&rxj7Z{El8x)D$p5Z@e*z5Z*| z!)1BYg~kdOfK=wPP5^T6Ky0i?h#mm!r!N*Gmoi>}GsN32f3fr;ngDoPj4xIQ!zmb@ zfuhR_5pE)5bKo{F1joDUDS%x$ef|+6aE8&MDB&ON6KJ*NF1$Jb0000 Date: Tue, 8 Jun 2021 16:19:27 -0400 Subject: [PATCH 22/50] Revert "Sending img test" This reverts commit 07171191ef43358a6cecb4fa61ea53edd1894f11. --- fragmentation_layer/code/image_message.py | 1 - fragmentation_layer/code/main.py | 2 +- .../lorawan/ack_on_error_receiver.py | 5 +---- fragmentation_layer/code/test_img.png | Bin 928 -> 0 bytes 4 files changed, 2 insertions(+), 6 deletions(-) delete mode 100644 fragmentation_layer/code/image_message.py delete mode 100644 fragmentation_layer/code/test_img.png diff --git a/fragmentation_layer/code/image_message.py b/fragmentation_layer/code/image_message.py deleted file mode 100644 index e72a15d..0000000 --- a/fragmentation_layer/code/image_message.py +++ /dev/null @@ -1 +0,0 @@ -MESSAGE = open("test_img.png", "rb").read() \ No newline at end of file diff --git a/fragmentation_layer/code/main.py b/fragmentation_layer/code/main.py index 000ca2d..70987ba 100644 --- a/fragmentation_layer/code/main.py +++ b/fragmentation_layer/code/main.py @@ -3,7 +3,7 @@ import binascii import struct -from image_message import MESSAGE +from message import MESSAGE from schc_handlers import SCHCNodeHandler from schc_protocols import SCHCProtocol diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py index 465b0a5..96379d8 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py @@ -138,16 +138,13 @@ def receive_all1_schc_fragment(self, schc_message): self.sm.__last_window__ = True last_payload = schc_message.payload.as_bytes() self.sm.payload.add_content(last_payload) + self._logger_.debug("Message received:\n" + self.sm.payload.as_bytes().decode("ascii")) rcs = self.sm.protocol.calculate_rcs( self.sm.payload.as_bits() ) integrity = rcs == schc_message.header.rcs.rcs if integrity: self._logger_.debug("Integrity check successful") - #self._logger_.debug("Message received:\n" + self.sm.payload.as_bytes().decode("ascii")) - out = open("received.png", "wb") - out.write(self.sm.payload.as_bytes()) - out.close() compressed_bitmap = None self.__success__ = True else: diff --git a/fragmentation_layer/code/test_img.png b/fragmentation_layer/code/test_img.png deleted file mode 100644 index 5bd4791212f1a9f18fffb00fb3707a0b3bdd3be7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 928 zcmV;R17G}!P)Px#1ZP1_K>z@;j|==^1poj59#BkFMZKz{_1VLKKWgb;fc^L1hK7b-t=3q1qEJ|U z|NsB{c)dmd000SaNLh0L01m?d01m?e$8V@)0009ENklhmEJrTf7fu17(&Kc1^O@>F{jX7~GLkgIh z<0#1tIEMr|*G5_OW!MU9T#EziXzNT*=ZThx_>*Lg2N%NE?kiphze3tq^6&q_N z0OD#Zxws47A&}11HO^YxAQ|{A$}|r>D|3??Yu0|>60kZ@edv2ja=qB^!woaT9glrd zV0gHq)~FjxKe+XE8{OiTwiua2S$3lu(3IH22*d4IXaL@b2rwa(s8^&+Qd}aK( z7?_~jeFmfuenSS2wF38CO4ex!%TNfvp%mcIpVJfr+F-EY1FMDbTZfPE`owG8;I+~2 zrWs-({ImP=_~F%RoiOxHJP`_bzuTP$;5we^WxR-I&#v{qr3zB1(EvsOebR>q)t7qJ zay&aOK-7mpJ0@JUavq!rQYVTZd(so2S1svpX$Dbr{Q9sUqSK2y0Yi#)4e`9mtHF!( zTQYcwdINHt)0-ou9EM*nL8m$jQH_mN%t-eaL6@D5&rxj7Z{El8x)D$p5Z@e*z5Z*| z!)1BYg~kdOfK=wPP5^T6Ky0i?h#mm!r!N*Gmoi>}GsN32f3fr;ngDoPj4xIQ!zmb@ zfuhR_5pE)5bKo{F1joDUDS%x$ef|+6aE8&MDB&ON6KJ*NF1$Jb0000 Date: Tue, 8 Jun 2021 17:31:52 -0400 Subject: [PATCH 23/50] callback on end of reassembly --- .../code/schc_handlers/schc_gateway_handler.py | 13 +++++++++++-- .../schc_machines/lorawan/ack_on_error_receiver.py | 5 +++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index c5d4a24..df64c28 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -12,8 +12,17 @@ class SCHCGatewayHandler(SCHCHandler): - def __init__(self, protocol, mtu): + def __init__(self, protocol, mtu, on_receive_callback=None): super().__init__(protocol, mtu) + if on_receive_callback: + def after_reassembly_processing(msg_bytes): + # TODO decompress before calling callback + on_receive_callback(msg_bytes) + else: + def after_reassembly_processing(msg_bytes): + # TODO decompress before calling callback + print("Message received:", msg_bytes) + self.callback = after_reassembly_processing def send_package(self, packet): if self.__protocol__.id == SCHCProtocol.LoRaWAN: @@ -27,7 +36,7 @@ def receive(self, rule_id, dtag, message): if rule_id == LoRaWAN.ACK_ON_ERROR: # message received from schc_machines.lorawan import AckOnErrorReceiver - self.assign_session(rule_id, dtag, AckOnErrorReceiver(LoRaWAN(LoRaWAN.ACK_ON_ERROR))) + self.assign_session(rule_id, dtag, AckOnErrorReceiver(LoRaWAN(LoRaWAN.ACK_ON_ERROR), on_success=self.callback)) self.__sessions__[rule_id][dtag].receive_message(message) elif rule_id == LoRaWAN.ACK_ALWAYS: # response received diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py index 96379d8..eb32008 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py @@ -138,7 +138,7 @@ def receive_all1_schc_fragment(self, schc_message): self.sm.__last_window__ = True last_payload = schc_message.payload.as_bytes() self.sm.payload.add_content(last_payload) - self._logger_.debug("Message received:\n" + self.sm.payload.as_bytes().decode("ascii")) + self.on_success(self.sm.payload.as_bytes()) rcs = self.sm.protocol.calculate_rcs( self.sm.payload.as_bits() ) @@ -293,11 +293,12 @@ def receive_schc_ack_req(self, schc_message): pass return - def __init__(self, protocol, dtag=None): + def __init__(self, protocol, dtag=None, on_success=None): super().__init__(protocol, dtag=dtag) self.states["receiving_phase"] = AckOnErrorReceiver.ReceivingPhase(self) self.states["waiting_phase"] = AckOnErrorReceiver.WaitingPhase(self) self.state = self.states["receiving_phase"] self.inactivity_timer.stop() self.state.enter_state() + self.on_success = on_success return From 96a7b6f3f33674b9392b38211e70a1a49e881164 Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Wed, 9 Jun 2021 12:12:14 -0400 Subject: [PATCH 24/50] small fix --- .../code/schc_machines/lorawan/ack_on_error_receiver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py index eb32008..858b183 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py @@ -138,7 +138,6 @@ def receive_all1_schc_fragment(self, schc_message): self.sm.__last_window__ = True last_payload = schc_message.payload.as_bytes() self.sm.payload.add_content(last_payload) - self.on_success(self.sm.payload.as_bytes()) rcs = self.sm.protocol.calculate_rcs( self.sm.payload.as_bits() ) @@ -147,6 +146,7 @@ def receive_all1_schc_fragment(self, schc_message): self._logger_.debug("Integrity check successful") compressed_bitmap = None self.__success__ = True + self.on_success(self.sm.payload.as_bytes()) else: self._logger_.error("Integrity check failed:\tSender: {}\tReceiver:{}".format( schc_message.header.rcs.rcs, From a9489e8d04e5e5265cf4a1d8fd2677d615a432be Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Fri, 11 Jun 2021 21:58:48 -0400 Subject: [PATCH 25/50] callback system after reassembly --- fragmentation_layer/code/main.py | 2 +- .../schc_handlers/schc_gateway_handler.py | 19 ++++++++++++------- .../lorawan/ack_on_error_receiver.py | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/fragmentation_layer/code/main.py b/fragmentation_layer/code/main.py index 70987ba..521a3b4 100644 --- a/fragmentation_layer/code/main.py +++ b/fragmentation_layer/code/main.py @@ -3,7 +3,7 @@ import binascii import struct -from message import MESSAGE +from message import SHORT_MESSAGE as MESSAGE from schc_handlers import SCHCNodeHandler from schc_protocols import SCHCProtocol diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index df64c28..f045fa7 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -15,14 +15,18 @@ class SCHCGatewayHandler(SCHCHandler): def __init__(self, protocol, mtu, on_receive_callback=None): super().__init__(protocol, mtu) if on_receive_callback: - def after_reassembly_processing(msg_bytes): - # TODO decompress before calling callback - on_receive_callback(msg_bytes) + used_callback = on_receive_callback else: + used_callback = lambda msg: print("Message received", msg) + + def create_after_processing_callback(rule_id, dtag): def after_reassembly_processing(msg_bytes): # TODO decompress before calling callback - print("Message received:", msg_bytes) - self.callback = after_reassembly_processing + used_callback(msg_bytes) + self.__sessions__[rule_id].pop(dtag) + return after_reassembly_processing + + self.callback_creator = create_after_processing_callback def send_package(self, packet): if self.__protocol__.id == SCHCProtocol.LoRaWAN: @@ -36,7 +40,9 @@ def receive(self, rule_id, dtag, message): if rule_id == LoRaWAN.ACK_ON_ERROR: # message received from schc_machines.lorawan import AckOnErrorReceiver - self.assign_session(rule_id, dtag, AckOnErrorReceiver(LoRaWAN(LoRaWAN.ACK_ON_ERROR), on_success=self.callback)) + self.assign_session(rule_id, dtag, AckOnErrorReceiver( + LoRaWAN(LoRaWAN.ACK_ON_ERROR), + on_success=self.callback_creator(rule_id, dtag))) self.__sessions__[rule_id][dtag].receive_message(message) elif rule_id == LoRaWAN.ACK_ALWAYS: # response received @@ -64,7 +70,6 @@ def handle(self, message, f_port=None, url=None, dev_id=None): "payload_raw": base64.b64encode(response[1:]).decode("utf-8") } r = requests.post(url, data=json.dumps(post_obj), headers={'content-type': 'application/json'}) - print(r.status_code) def generate_message(self, rule_id, dtag, mtu=512): message = self.__sessions__[rule_id][dtag].generate_message(mtu) diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py index 858b183..4f11d91 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py @@ -146,7 +146,7 @@ def receive_all1_schc_fragment(self, schc_message): self._logger_.debug("Integrity check successful") compressed_bitmap = None self.__success__ = True - self.on_success(self.sm.payload.as_bytes()) + self.sm.on_success(self.sm.payload.as_bytes()) else: self._logger_.error("Integrity check failed:\tSender: {}\tReceiver:{}".format( schc_message.header.rcs.rcs, From 95003ee0fe5dcc5f442eb427160c41137d68d8f3 Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Fri, 11 Jun 2021 22:55:23 -0400 Subject: [PATCH 26/50] fix to not sending last ack --- fragmentation_layer/code/schc_handlers/schc_gateway_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index f045fa7..ed472e0 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -23,7 +23,7 @@ def create_after_processing_callback(rule_id, dtag): def after_reassembly_processing(msg_bytes): # TODO decompress before calling callback used_callback(msg_bytes) - self.__sessions__[rule_id].pop(dtag) + # self.__sessions__[rule_id].pop(dtag) return after_reassembly_processing self.callback_creator = create_after_processing_callback From 53ecdb56daae39273b73164b49f1a243fd3616ff Mon Sep 17 00:00:00 2001 From: Juan Ma Date: Mon, 14 Jun 2021 11:17:24 -0400 Subject: [PATCH 27/50] CRC32 implemented --- .../lorawan/ack_on_error_receiver.py | 2 +- .../code/schc_protocols/schc_protocol.py | 16 ++++++++++++---- fragmentation_layer/example/common_methods.py | 3 +-- fragmentation_layer/example/test_receiver.py | 3 ++- .../tests/test_header/__init__.py | 1 - .../tests/test_header/test_rcs.py | 1 - 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py index 858b183..4f11d91 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py @@ -146,7 +146,7 @@ def receive_all1_schc_fragment(self, schc_message): self._logger_.debug("Integrity check successful") compressed_bitmap = None self.__success__ = True - self.on_success(self.sm.payload.as_bytes()) + self.sm.on_success(self.sm.payload.as_bytes()) else: self._logger_.error("Integrity check failed:\tSender: {}\tReceiver:{}".format( schc_message.header.rcs.rcs, diff --git a/fragmentation_layer/code/schc_protocols/schc_protocol.py b/fragmentation_layer/code/schc_protocols/schc_protocol.py index de39080..eb43999 100644 --- a/fragmentation_layer/code/schc_protocols/schc_protocol.py +++ b/fragmentation_layer/code/schc_protocols/schc_protocol.py @@ -109,10 +109,18 @@ def calculate_rcs(self, packet): str : Result of Reassembly Check Sequence (RCS) """ - # TODO: self implementation of crc32 - # from binascii import crc32 - # return hex(crc32(SCHCObject.bits_2_bytes(packet))) - return "0xb4cc4a0" + # CRC32 + # Thanks to https://lxp32.github.io/docs/a-simple-example-crc32-calculation/ + from schc_base import SCHCObject + crc = 0xffffffff + for i in SCHCObject.bits_2_bytes(packet): + for j in range(8): + b = (i ^ crc) & 1 + crc >>= 1 + if b == 1: + crc = crc ^ 0xedb88320 + i >>= 1 + return hex((~crc) & 0xffffffff) def penultimate_tile(self): """ diff --git a/fragmentation_layer/example/common_methods.py b/fragmentation_layer/example/common_methods.py index 4c39598..10aea40 100644 --- a/fragmentation_layer/example/common_methods.py +++ b/fragmentation_layer/example/common_methods.py @@ -34,8 +34,7 @@ def is_this_loss() -> bool: bool : True if sent does not occur """ - # return random.random() < PROBABILITY_OF_FAILURE - return False + return random.random() < PROBABILITY_OF_FAILURE def send_socket(msg: bytes, port: int) -> None: diff --git a/fragmentation_layer/example/test_receiver.py b/fragmentation_layer/example/test_receiver.py index 2233bc5..2117258 100644 --- a/fragmentation_layer/example/test_receiver.py +++ b/fragmentation_layer/example/test_receiver.py @@ -20,7 +20,8 @@ from schc_protocols import LoRaWAN receiver = AckOnErrorReceiver( - LoRaWAN(LoRaWAN.ACK_ON_ERROR) + LoRaWAN(LoRaWAN.ACK_ON_ERROR), + on_success=print ) messaging_loop(receiver, socket_rx, SENDER_PORT) diff --git a/fragmentation_layer/tests/test_header/__init__.py b/fragmentation_layer/tests/test_header/__init__.py index 2564c98..66966c2 100644 --- a/fragmentation_layer/tests/test_header/__init__.py +++ b/fragmentation_layer/tests/test_header/__init__.py @@ -4,4 +4,3 @@ from test_header.test_dtag import TestDTag from test_header.test_fcn import TestFragmentCompressedNumber from test_header.test_rcs import TestRCS -# TODO: Unittest of Header Objects diff --git a/fragmentation_layer/tests/test_header/test_rcs.py b/fragmentation_layer/tests/test_header/test_rcs.py index c91e820..1b7c898 100644 --- a/fragmentation_layer/tests/test_header/test_rcs.py +++ b/fragmentation_layer/tests/test_header/test_rcs.py @@ -14,7 +14,6 @@ def setUp(self) -> None: ------- None """ - # TODO: Pending unit testing of headers # self.rcs = ReassemblyCheckSequence() def test_wrong_fcn_size(self) -> None: From 39ada84fa77f6ca664f4632f28e05432b8bd6f9b Mon Sep 17 00:00:00 2001 From: Juan Ma Date: Mon, 14 Jun 2021 11:51:32 -0400 Subject: [PATCH 28/50] CRC32 implemented and tested --- .../tests/test_protocols/__init__.py | 3 + .../test_protocols/test_schc_protocol.py | 88 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 fragmentation_layer/tests/test_protocols/__init__.py create mode 100644 fragmentation_layer/tests/test_protocols/test_schc_protocol.py diff --git a/fragmentation_layer/tests/test_protocols/__init__.py b/fragmentation_layer/tests/test_protocols/__init__.py new file mode 100644 index 0000000..53e893b --- /dev/null +++ b/fragmentation_layer/tests/test_protocols/__init__.py @@ -0,0 +1,3 @@ +""" test_protocol: Unit test for schc_protocols package """ + +from test_protocols.test_schc_protocol import TestSCHCProtocol diff --git a/fragmentation_layer/tests/test_protocols/test_schc_protocol.py b/fragmentation_layer/tests/test_protocols/test_schc_protocol.py new file mode 100644 index 0000000..0bcf752 --- /dev/null +++ b/fragmentation_layer/tests/test_protocols/test_schc_protocol.py @@ -0,0 +1,88 @@ +""" test_schc_protocol: SCHC Protocol unit test class """ + +from binascii import crc32 +from random import seed, choices, choice +from unittest import TestCase, main +from schc_base import SCHCObject +from schc_protocols import LoRaWAN + +SEED = 7 +SHORT_MESSAGE = "This is a short message".encode("ascii") +LONG_MESSAGE = """ +Abstract + + The Static Context Header Compression (SCHC) specification describes + generic header compression and fragmentation techniques for Low Power + Wide Area Networks (LPWAN) technologies. SCHC is a generic mechanism + designed for great flexibility so that it can be adapted for any of + the LPWAN technologies. + + This document specifies a profile of RFC8724 to use SCHC in + LoRaWAN(R) networks, and provides elements such as efficient + parameterization and modes of operation. + +Status of This Memo + + This Internet-Draft is submitted in full conformance with the + provisions of BCP 78 and BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF). Note that other groups may also distribute + working documents as Internet-Drafts. The list of current Internet- + Drafts is at https://datatracker.ietf.org/drafts/current/. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + This Internet-Draft will expire on July 29, 2021. + +Copyright Notice + + Copyright (c) 2021 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. +""".encode("ascii") +WORD_LENGTHS = [10, 200, int(1e3)] + + +class TestSCHCProtocol(TestCase): + + def test_crc32_static_message(self) -> None: + short = SCHCObject.bytes_2_bits(SHORT_MESSAGE) + library = hex(crc32(SCHCObject.bits_2_bytes(short))) + local = LoRaWAN().calculate_rcs(short) + self.assertEqual(library, local, "Short message crc32 do not match") + long = SCHCObject.bytes_2_bits(LONG_MESSAGE) + library = hex(crc32(SCHCObject.bits_2_bytes(long))) + local = LoRaWAN().calculate_rcs(long) + self.assertEqual(library, local, "Long message crc32 do not match") + + def test_crc32_random(self) -> None: + seed(SEED) + import string + for _ in range(100): + a_word = "".join( + choices(string.ascii_letters, k=choice(WORD_LENGTHS)) + ).encode("ascii") + word = SCHCObject.bytes_2_bits(a_word) + library = hex(crc32(SCHCObject.bits_2_bytes(word))) + local = LoRaWAN().calculate_rcs(word) + self.assertEqual( + library, local, + "Random message {} crc32 do not match".format(a_word) + ) + + +if __name__ == '__main__': + main() From 94dff7c95ea7d4fd412ab74e6b93feea63ba8bb3 Mon Sep 17 00:00:00 2001 From: Juan Ma Date: Tue, 15 Jun 2021 12:46:25 -0400 Subject: [PATCH 29/50] Add failed fragments handling protocol (not 100% functional) --- fragmentation_layer/code/schc_base/bitmap.py | 30 ++- fragmentation_layer/code/schc_base/tile.py | 23 ++ .../lorawan/ack_on_error_receiver.py | 206 ++++++++++----- .../lorawan/ack_on_error_sender.py | 244 +++++++++++++++--- .../code/schc_machines/schc_fsm.py | 41 ++- .../code/schc_protocols/lorawan.py | 4 +- fragmentation_layer/example/common_methods.py | 3 +- .../tests/test_base/test_bitmap.py | 19 ++ 8 files changed, 437 insertions(+), 133 deletions(-) diff --git a/fragmentation_layer/code/schc_base/bitmap.py b/fragmentation_layer/code/schc_base/bitmap.py index 4cf01d7..12717a2 100644 --- a/fragmentation_layer/code/schc_base/bitmap.py +++ b/fragmentation_layer/code/schc_base/bitmap.py @@ -98,11 +98,26 @@ def is_missing(self): Returns ------- - bool : + bool True if there are missing tiles """ return len(self.__bitmap__) > sum(self.__bitmap__) + def has_missing(self): + """ + Whether is a missing value so far + + Returns + ------- + bool + True if there are missing tiles between ones + """ + i = 0 + for i, bit in enumerate(self.__bitmap__): + if not bit: + break + return 0 < sum(self.__bitmap__[i+1:]) + def get_missing(self, fcn=False): """ Gets first index of reported missing tile. If fcn is True, passes @@ -115,7 +130,7 @@ def get_missing(self, fcn=False): Returns ------- - int : + int First index with missing tile """ i = self.__bitmap__.index(False) @@ -124,6 +139,17 @@ def get_missing(self, fcn=False): else: return i + def get_received_tiles(self): + """ + Gets number of received tiles + + Returns + ------- + int + Tiles received and reported + """ + return sum(self.__bitmap__) + def __repr__(self): return "".join(["1" if i else "0" for i in self.__bitmap__]) diff --git a/fragmentation_layer/code/schc_base/tile.py b/fragmentation_layer/code/schc_base/tile.py index 0c604cf..5485bdc 100644 --- a/fragmentation_layer/code/schc_base/tile.py +++ b/fragmentation_layer/code/schc_base/tile.py @@ -61,3 +61,26 @@ def as_bits(self): Bits sequence as text """ return self.encoded_content + + def __copy__(self): + """ + Copies object + + Returns + ------- + Tile + A copy of this tile + """ + out = Tile(self.as_bytes()[0]) + return out + + def copy(self): + """ + Copies this object + + Returns + ------- + Tile + A copy of this tile + """ + return self.__copy__() diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py index 4f11d91..ca588be 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py @@ -3,7 +3,7 @@ from machine import Timer from schc_base import Bitmap from schc_machines import SCHCReceiver -from schc_messages import RegularSCHCFragment, SCHCAck, All1SCHCFragment, SCHCAckReq +from schc_messages import RegularSCHCFragment, SCHCAck, All1SCHCFragment, SCHCAckReq, SCHCReceiverAbort class AckOnErrorReceiver(SCHCReceiver): @@ -32,33 +32,13 @@ def __init__(self, state_machine): super().__init__(state_machine) self.__success__ = False - def on_expiration_time(self, alarm): - """ - Executed on expiration time - - Parameters - ---------- - alarm : Timer - Timer that triggers expiration - - Returns - ------- - None, alter state to error - """ - self.sm.__exit_msg__ = "Connection timeout" - self.sm.state = self.sm.states["error"] - self.sm.state.enter_state() - return - def generate_message(self, mtu): """ Send messages saved on message_to_send variable - Parameters ---------- mtu : int MTU available - Returns ------- SCHCMessage : @@ -67,12 +47,31 @@ def generate_message(self, mtu): if self.sm.__last_window__ and self.__success__: self.sm.state = self.sm.states["end"] self.sm.state.enter_state() - message = self.sm.message_to_send.pop(0) - self._logger_.schc_message(message) - return message + if len(self.sm.message_to_send) > 0: + message = self.sm.message_to_send.pop(0) + self._logger_.schc_message(message) + return message + else: + return None else: return None + def on_expiration_time(self, alarm) -> None: + """ + On expiration time behaviour for this phase + + Parameters + ---------- + alarm : Timer + Timer ofg machine that activates the alarm + + Returns + ------- + None + """ + std_on_expiration_time(self, alarm) + return + def receive_regular_schc_fragment(self, schc_message): """ @@ -85,6 +84,7 @@ def receive_regular_schc_fragment(self, schc_message): ------- None, alter state """ + self.sm.inactivity_timer.stop() if self.sm.__cw__ == schc_message.header.w: fcn = schc_message.header.fcn.fcn self.sm.__fcn__ = fcn @@ -109,8 +109,10 @@ def receive_regular_schc_fragment(self, schc_message): ].generate_compress()) ack.add_padding() self.sm.message_to_send.append(ack) + self.sm.attempts.increment() self.sm.state = self.sm.states["waiting_phase"] self.sm.state.enter_state() + self.sm.inactivity_timer.reset() return self._logger_.debug("Current bitmap: {}. Waiting for w={} fcn={} tile".format( self.sm.bitmaps[ @@ -138,23 +140,27 @@ def receive_all1_schc_fragment(self, schc_message): self.sm.__last_window__ = True last_payload = schc_message.payload.as_bytes() self.sm.payload.add_content(last_payload) - rcs = self.sm.protocol.calculate_rcs( - self.sm.payload.as_bits() - ) - integrity = rcs == schc_message.header.rcs.rcs - if integrity: - self._logger_.debug("Integrity check successful") - compressed_bitmap = None - self.__success__ = True - self.sm.on_success(self.sm.payload.as_bytes()) + bitmap = self.sm.bitmaps[schc_message.header.w.w] + if bitmap.has_missing(): + integrity = False + compressed_bitmap = bitmap.generate_compress() else: - self._logger_.error("Integrity check failed:\tSender: {}\tReceiver:{}".format( - schc_message.header.rcs.rcs, - rcs - )) - compressed_bitmap = self.sm.bitmaps[ - self.sm.__cw__ - ].generate_compress() + rcs = self.sm.protocol.calculate_rcs( + self.sm.payload.as_bits() + ) + integrity = rcs == schc_message.header.rcs.rcs + if integrity: + self._logger_.debug("Integrity check successful") + compressed_bitmap = None + self.__success__ = True + self.sm.on_success(self.sm.payload.as_bytes()) + else: + self._logger_.error("Integrity check failed:\tSender: {}\tReceiver:{}".format( + schc_message.header.rcs.rcs, + rcs + )) + compressed_bitmap = bitmap.generate_compress() + return integrity, compressed_bitmap ack = SCHCAck(self.sm.__rule_id__, self.sm.protocol.id, c=integrity, @@ -165,7 +171,7 @@ def receive_all1_schc_fragment(self, schc_message): self.sm.message_to_send.append(ack) return else: - # TODO + self._logger_.degug("(All-1) Different window received") return def receive_schc_ack_req(self, schc_message): @@ -181,19 +187,26 @@ def receive_schc_ack_req(self, schc_message): ------- None, alter state """ - for w in sorted(self.sm.bitmaps.keys()): - bitmap = self.sm.bitmaps[w] - if bitmap.is_missing(): - self._logger_.debug("Window {} has missing tiles".format(w)) - self.sm.message_to_send.append( - SCHCAck(self.sm.__rule_id__, self.sm.protocol.id, - False, w=w, compressed_bitmap=bitmap.generate_compress()) - ) + w = schc_message.header.w.w + if self.sm.__cw__ == w: + try: + bitmap = self.sm.bitmaps[w] + except KeyError: + self._logger_.warning("W is not valid: w received: {}".format(w)) return - bitmap = self.sm.bitmaps[self.sm.__cw__] + elif self.sm.__cw__ > w: + self._logger_.warning( + "SCHCAckReq is for a completed window (current w={} > {}). Discarding message".format( + self.sm.__cw__, w)) + return + else: # self.sm.__cw__ < w: + self._logger_.warning("Incorrect window, discarding") + return + if bitmap.is_missing(): + self._logger_.debug("Window {} has missing tiles".format(w)) self.sm.message_to_send.append( SCHCAck(self.sm.__rule_id__, self.sm.protocol.id, - False, w=self.sm.__cw__, compressed_bitmap=bitmap.generate_compress()) + False, w=w, compressed_bitmap=bitmap.generate_compress()) ) return @@ -216,19 +229,7 @@ def generate_message(self, mtu): SCHCMessage : Message to send """ - if len(self.sm.message_to_send) != 0: - message = self.sm.message_to_send.pop(0) - if (message.size // 8) > mtu: - self.sm.message_to_send.insert(0, message) - self._logger_.warning( - "Cannot send message, no bandwidth available. MTU = {} < Message size = {}".format( - mtu, message.size // 8 - ) - ) - self._logger_.schc_message(message) - return message - else: - return None + return super().generate_message(mtu) def receive_regular_schc_fragment(self, schc_message): """ @@ -265,7 +266,35 @@ def receive_regular_schc_fragment(self, schc_message): if self.sm.bitmaps[self.sm.__cw__].is_missing(): fcn = self.sm.bitmaps[self.sm.__cw__].get_missing(fcn=True) else: - break + ack = SCHCAck( + rule_id=self.sm.__rule_id__, + protocol=self.sm.protocol.id, + c=False, + dtag=self.sm.__dtag__, + w=self.sm.__cw__, + compressed_bitmap=self.sm.bitmaps[self.sm.__cw__].generate_compress() + ) + ack.add_padding() + self.sm.message_to_send.append(ack) + return + return + + def receive_all1_schc_fragment(self, schc_message): + """ + Behaviour when receiving All-1 SCHC Fragment + + Parameters + ---------- + schc_message : All1SCHCFragment + Last fragment to be received + + Returns + ------- + None, alter state + """ + self.sm.state = self.sm.states["receiving_phase"] + self.sm.state.enter_state() + self.sm.state.receive_all1_schc_fragment(schc_message) return def receive_schc_ack_req(self, schc_message): @@ -289,16 +318,61 @@ def receive_schc_ack_req(self, schc_message): SCHCAck(self.sm.__rule_id__, self.sm.protocol.id, c=False, w=w, compressed_bitmap=self.sm.bitmaps[w].generate_compress()) ) + self.sm.attempts.increment() else: pass return + def on_expiration_time(self, alarm) -> None: + """ + On expiration time behaviour for this phase + + Parameters + ---------- + alarm : Timer + Timer of machine that activates the alarm + + Returns + ------- + None + """ + std_on_expiration_time(self, alarm) + return + def __init__(self, protocol, dtag=None, on_success=None): super().__init__(protocol, dtag=dtag) self.states["receiving_phase"] = AckOnErrorReceiver.ReceivingPhase(self) self.states["waiting_phase"] = AckOnErrorReceiver.WaitingPhase(self) self.state = self.states["receiving_phase"] - self.inactivity_timer.stop() + self.inactivity_timer.reset() self.state.enter_state() self.on_success = on_success return + + +def std_on_expiration_time(state, alarm): + """ + Standard expiration time (for both phases) + + Parameters + ---------- + state : SCHCReceiver.ReceiverState + State which Inactivity timer expired + alarm : Timer + Timer of machine that activates the alarm + + Returns + ------- + None + """ + state.sm.state = state.sm.states["error"] + state.sm.state.enter_state() + state.sm.message_to_send.append( + SCHCReceiverAbort( + rule_id=state.sm.__rule_id__, + protocol=state.sm.protocol.id, + dtag=state.sm.__dtag__, + w=state.sm.__cw__ + ) + ) + return diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py index cd89a06..daf1d3b 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py @@ -2,7 +2,7 @@ from schc_base import Tile, Bitmap from schc_machines import SCHCSender -from schc_messages import RegularSCHCFragment, All1SCHCFragment, SCHCAck, SCHCAckReq +from schc_messages import RegularSCHCFragment, All1SCHCFragment, SCHCAck, SCHCAckReq, SCHCSenderAbort class AckOnErrorSender(SCHCSender): @@ -13,7 +13,6 @@ class AckOnErrorSender(SCHCSender): ---------- protocol state - residue """ __mode__ = "Ack On Error" @@ -65,11 +64,13 @@ def generate_message(self, mtu): RegularSCHCFragment until all tiles are sent, then All1SCHCFragment """ - regular_message = RegularSCHCFragment(self.sm.__rule_id__, - self.sm.__fcn__, - self.sm.protocol.id, - self.sm.__dtag__, - self.sm.__cw__) + regular_message = RegularSCHCFragment( + rule_id=self.sm.__rule_id__, + fcn=self.sm.__fcn__, + protocol=self.sm.protocol.id, + dtag=self.sm.__dtag__, + w=self.sm.__cw__ + ) mtu_available = (mtu - (regular_message.size // 8)) * 8 # MTU should not count FPort mtu_available += regular_message.header.rule_id.size @@ -77,9 +78,7 @@ def generate_message(self, mtu): candid = self.sm.tiles[0] while mtu_available >= candid.size and len(self.sm.tiles) > 1: regular_message.add_tile(candid) - self.sm.sent_tiles.append( - self.sm.tiles.pop(0) - ) + self.sm.sent_tiles[self.sm.__fcn__] = self.sm.tiles.pop(0).copy() mtu_available -= candid.size candid = self.sm.tiles[0] self._logger_.debug("Add tile with fcn {} for windows {}".format( @@ -90,22 +89,22 @@ def generate_message(self, mtu): self.sm.retransmission_timer.reset() self.sm.state.enter_state() self.sm.message_to_send.append(SCHCAckReq( - self.sm.__rule_id__, - self.sm.protocol.id, - self.sm.__dtag__, - self.sm.__cw__ + rule_id=self.sm.__rule_id__, + protocol=self.sm.protocol.id, + dtag=self.sm.__dtag__, + w=self.sm.__cw__ )) break else: last_tile = self.sm.tiles.pop(0) - self.sm.sent_tiles.append(last_tile) + self.sm.sent_tiles[self.sm.__fcn__] = last_tile.copy() self.sm.__last_window__ = True all1 = All1SCHCFragment( - self.sm.__rule_id__, - self.sm.protocol.id, - self.sm.__dtag__, - self.sm.__cw__, - self.sm.rcs + rule_id=self.sm.__rule_id__, + protocol=self.sm.protocol.id, + dtag=self.sm.__dtag__, + w=self.sm.__cw__, + rcs=self.sm.rcs ) all1.add_tile(last_tile) self._logger_.schc_message(all1) @@ -170,46 +169,217 @@ def receive_schc_ack(self, schc_message): Parameters ---------- schc_message : SCHCAck - SCHCAck reporting end of transmission or window + SCHCAck reporting end transmission of a window Returns ------- None, alter state """ - if self.sm.__cw__ != schc_message.header.w: - # TODO + if self.sm.__cw__ < schc_message.header.w.w: + self._logger_.warning("Incorrect window, discarding") return - else: + if self.sm.__cw__ > schc_message.header.w.w: + self._logger_.warning( + "SCHCAck is for a previous window (current w={} > {}). Retaking window".format( + self.sm.__cw__, schc_message.header.w.w)) + self.sm.__cw__ = schc_message.header.w.w + self.sm.state = self.sm.states["resending_phase"] + self.sm.state.enter_state() + return + else: # self.sm.__cw__ == schc_message.header.w.w: if schc_message.header.c.c: if self.sm.__last_window__: self.sm.state = self.sm.states["end"] self.sm.state.enter_state() return else: - # TODO + self.sm.state = self.sm.states["error"] + self.sm.state.enter_state() + abort = SCHCSenderAbort( + rule_id=self.sm.__rule_id__, + protocol=self.sm.protocol.id, + dtag=self.sm.__dtag__, + w=self.sm.__cw__ + ) + abort.add_padding() + self.sm.message_to_send.append(abort) return else: - self.sm.bitmap = Bitmap.from_compress_bitmap( + bitmap = Bitmap.from_compress_bitmap( schc_message.header.compressed_bitmap.bitmap, self.sm.protocol) - self._logger_.debug("Received bitmap: {}".format(self.sm.bitmap)) - if sum(self.sm.bitmap) == len(self.sm.bitmap): - self.sm.state = self.sm.states["sending_phase"] - self.sm.retransmission_timer.stop() - self.sm.__cw__ += 1 - self.sm.__fcn__ = self.sm.protocol.WINDOW_SIZE - 1 - self.sm.state.enter_state() - return + self._logger_.debug("Received bitmap: {}".format(bitmap)) + self.sm.bitmaps[schc_message.header.w.w] = bitmap + if self.sm.__last_window__: + if bitmap.has_missing() or bitmap.get_received_tiles() < self.sm.sent_tiles: + self.sm.retransmission_timer.stop() + self.sm.state = self.sm.states["resending_phase"] + self.sm.state.enter_state() + return + else: + self.sm.state = self.sm.states["error"] + abort = SCHCSenderAbort( + rule_id=self.sm.__rule_id__, + protocol=self.sm.protocol.id, + dtag=self.sm.__dtag__, + w=self.sm.__cw__ + ) + abort.add_padding() + self.sm.message_to_send.append(abort) + return else: - # TODO - return + if bitmap.is_missing(): + self.sm.state = self.sm.states["resending_phase"] + self.sm.retransmission_timer.stop() + self.sm.state.enter_state() + return + else: + self.sm.sent_tiles.clear() + self.sm.state = self.sm.states["sending_phase"] + self.sm.retransmission_timer.stop() + self.sm.__cw__ += 1 + self.sm.__fcn__ = self.sm.protocol.WINDOW_SIZE - 1 + self.sm.state.enter_state() + return + + def on_expiration_time(self, alarm): + """ + Behaviour on time expiration + + Parameters + ---------- + alarm : Timer + Timer of machine that activates the alarm + + Returns + ------- + None + """ + if self.sm.attempts.exceeds_max(): + sender_abort = SCHCSenderAbort( + rule_id=self.sm.__rule_id__, + protocol=self.sm.protocol.id, + dtag=self.sm.__dtag__, + w=self.sm.__cw__ + ) + sender_abort.add_padding() + self.sm.message_to_send.append(sender_abort) + self.sm.state = self.sm.states["error"] + self.sm.state.enter_state() + return + else: + ack_req = SCHCAckReq( + rule_id=self.sm.__rule_id__, + protocol=self.sm.protocol.id, + dtag=self.sm.__dtag__, + w=self.sm.__cw__ + ) + ack_req.add_padding() + self.sm.message_to_send.append(ack_req) + self.sm.attempts.increment() + return + + class ResendingPhase(SCHCSender.SenderState): + """ + Resending Phase of Ack on Error, resend tiles reported missing + """ + __name__ = "Resending Phase" + + def generate_message(self, mtu): + """ + Generate regular fragment until all tiles are sent + Parameters + ---------- + mtu : int + MTU in bytes + Returns + ------- + SCHCMessage + RegularSCHCFragment or All1SCHCFragment, according + to bitmap received + """ + bitmap = self.sm.bitmaps[self.sm.__cw__] + if not bitmap.is_missing(): + self.sm.state = self.sm.states["waiting_phase"] + self.sm.state.enter_state() + self.sm.retransmission_timer.reset() + return + last_tile = min(self.sm.sent_tiles.keys()) + the_fcn = bitmap.get_missing(fcn=True) + regular_message = RegularSCHCFragment( + rule_id=self.sm.__rule_id__, + fcn=the_fcn, + protocol=self.sm.protocol.id, + dtag=self.sm.__dtag__, + w=self.sm.__cw__) + mtu_available = (mtu - (regular_message.size // 8)) * 8 + # MTU should not count FPort + mtu_available += regular_message.header.rule_id.size + if 0 < last_tile == the_fcn: + all1 = All1SCHCFragment( + rule_id=self.sm.__rule_id__, + protocol=self.sm.protocol.id, + dtag=self.sm.__dtag__, + w=self.sm.__cw__, + rcs=self.sm.rcs + ) + all1.add_tile(self.sm.sent_tiles[last_tile]) + self._logger_.schc_message(all1) + self.sm.state = self.sm.states["waiting_phase"] + self.sm.state.enter_state() + self.sm.retransmission_timer.reset() + self.sm.message_to_send.append(SCHCAckReq( + self.sm.__rule_id__, + self.sm.protocol.id, + self.sm.__dtag__, + self.sm.__cw__ + )) + all1.add_padding() + return all1 + if the_fcn < last_tile: + self.sm.state = self.sm.states["waiting_phase"] + self.sm.state.enter_state() + self.sm.retransmission_timer.reset() + return + candid = self.sm.sent_tiles[the_fcn] + while mtu_available >= candid.size and len(self.sm.tiles) > 1: + regular_message.add_tile(candid) + self._logger_.debug("Add tile with fcn {} for windows {}".format( + the_fcn, self.sm.__cw__)) + mtu_available -= candid.size + bitmap.tile_received(the_fcn) + if not bitmap.is_missing(): + break + the_fcn = bitmap.get_missing(fcn=True) + if the_fcn < last_tile or (self.sm.__last_window__ and the_fcn <= last_tile): + break + candid = self.sm.sent_tiles[the_fcn] + regular_message.add_padding() + self._logger_.schc_message(regular_message) + return regular_message + + def receive_schc_ack(self, schc_message): + """ + Logs SCHC ACK + + Parameters + ---------- + schc_message : SCHCAck + Message received + + Returns + ------- + None + """ + self._logger_.debug("Received SCHC ACK. Ignoring.") def __init__(self, protocol, payload, padding=0, dtag=None): super().__init__(protocol, payload, padding=padding, dtag=dtag) self.states["initial_phase"] = AckOnErrorSender.InitialPhase(self) self.states["sending_phase"] = AckOnErrorSender.SendingPhase(self) self.states["waiting_phase"] = AckOnErrorSender.WaitingPhase(self) + self.states["resending_phase"] = AckOnErrorSender.ResendingPhase(self) self.state = self.states["initial_phase"] self.state.enter_state() self.tiles = list() - self.sent_tiles = list() + self.sent_tiles = dict() self.state.__generate_tiles__() return diff --git a/fragmentation_layer/code/schc_machines/schc_fsm.py b/fragmentation_layer/code/schc_machines/schc_fsm.py index 1807780..45d875b 100644 --- a/fragmentation_layer/code/schc_machines/schc_fsm.py +++ b/fragmentation_layer/code/schc_machines/schc_fsm.py @@ -196,7 +196,7 @@ def enter_state(self): def generate_message(self, mtu): """ - Generates a SCHC message to send + Message to send by default: Sends enqueue messages Parameters ---------- @@ -210,10 +210,22 @@ def generate_message(self, mtu): Raises ------ - GeneratorExit - No more SCHC Message to send on current state + SystemExit : + Raises a SystemExit with error code -1 """ - raise GeneratorExit("No more message to send") + if len(self.sm.message_to_send) != 0: + message = self.sm.message_to_send.pop(0) + if (message.size // 8) > mtu: + self.sm.message_to_send.insert(0, message) + self._logger_.warning( + "Cannot send message, no bandwidth available. MTU = {} < Message size = {}".format( + mtu, message.size // 8 + ) + ) + self._logger_.schc_message(message) + return message + else: + return None def receive_message(self, message): """ @@ -324,27 +336,6 @@ def receive_message(self, message): """ raise SystemExit(self.sm.__end_msg__) - def generate_message(self, mtu): - """ - Generates a SCHC message to send - - Parameters - ---------- - mtu : int - Size of MTU available (in bytes) - - Returns - ------- - SCHCMessage: - SCHC Message to send - - Raises - ------ - SystemExit : - Raises a SystemExit with error code -1 - """ - raise SystemExit(self.sm.__end_msg__) - def __init__(self, protocol, dtag=None): """ Constructor diff --git a/fragmentation_layer/code/schc_protocols/lorawan.py b/fragmentation_layer/code/schc_protocols/lorawan.py index 5a1c2d4..301041f 100644 --- a/fragmentation_layer/code/schc_protocols/lorawan.py +++ b/fragmentation_layer/code/schc_protocols/lorawan.py @@ -69,8 +69,8 @@ def __set_parameters__(self): self.WINDOW_SIZE = 63 # 2^(n=6) = 64 - {All-1 fragment} self.TILE_SIZE = 10 * 8 # 10 bytes = 80 bits self.MAX_ACK_REQUEST = 1e6 # TODO - self.INACTIVITY_TIMER = 10 # in seconds TODO - self.RETRANSMISSION_TIMER = 10 # in seconds TODO + self.INACTIVITY_TIMER = 30 # in seconds TODO + self.RETRANSMISSION_TIMER = 5 # in seconds TODO elif self.RULE_ID == LoRaWAN.ACK_ALWAYS: # Downlink data transfer self.T = 0 # in bits self.M = 1 # in bits diff --git a/fragmentation_layer/example/common_methods.py b/fragmentation_layer/example/common_methods.py index 10aea40..542a96b 100644 --- a/fragmentation_layer/example/common_methods.py +++ b/fragmentation_layer/example/common_methods.py @@ -8,7 +8,7 @@ HOST = "127.0.0.1" MTU = 50 SEED = 8 -PROBABILITY_OF_FAILURE = 0.05 +PROBABILITY_OF_FAILURE = 0.0 random.seed(SEED) @@ -100,6 +100,7 @@ def messaging_loop(machine: SCHCFiniteStateMachine, socket_rx: socket.socket, se lost = is_this_loss() try: print("Sending...") + print("Messages enqueued: {}".format(machine.message_to_send)) message = machine.generate_message(mtu) logging.info("Current mtu: {}".format(mtu)) logging.info("Package sent: {}".format(not lost)) diff --git a/fragmentation_layer/tests/test_base/test_bitmap.py b/fragmentation_layer/tests/test_base/test_bitmap.py index ac8305c..cb53762 100644 --- a/fragmentation_layer/tests/test_base/test_bitmap.py +++ b/fragmentation_layer/tests/test_base/test_bitmap.py @@ -72,6 +72,25 @@ def test_compression(self): ]) % protocol_to_use.L2_WORD) + protocol_to_use.L2_WORD - 1, sum(compressed_bitmap), "Wrong compression") + def test_has_missing(self): + protocol = LoRaWAN(LoRaWAN.ACK_ON_ERROR) + bitmap = Bitmap(protocol) + self.assertFalse(bitmap.has_missing(), "Bitmap full False has missing") + bitmap.tile_received(protocol.WINDOW_SIZE - 1) + self.assertFalse(bitmap.has_missing(), "Bitmap first one has missing") + for i in range(5): + bitmap.tile_received(protocol.WINDOW_SIZE - (i + 2)) + self.assertFalse(bitmap.has_missing(), "Bitmap first ones has missing") + for i in range(5): + bitmap.tile_received(protocol.WINDOW_SIZE - (i + 10)) + self.assertTrue(bitmap.has_missing(), "Bitmap has missing not reported") + for i in range(5): + bitmap.tile_received(protocol.WINDOW_SIZE - (i + 20)) + self.assertTrue(bitmap.has_missing(), "Bitmap has missing not reported (second case)") + for i in range(protocol.WINDOW_SIZE): + bitmap.tile_received(protocol.WINDOW_SIZE - (i + 1)) + self.assertFalse(bitmap.has_missing(), "Bitmap full True has missing") + if __name__ == '__main__': main() From 5308cc7fe13734be09dd43fe3978968afe7f8306 Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Tue, 15 Jun 2021 17:29:15 -0400 Subject: [PATCH 30/50] Remove machine after reassembly --- fragmentation_layer/code/schc_handlers/schc_gateway_handler.py | 2 +- .../code/schc_machines/lorawan/ack_on_error_receiver.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index ed472e0..f045fa7 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -23,7 +23,7 @@ def create_after_processing_callback(rule_id, dtag): def after_reassembly_processing(msg_bytes): # TODO decompress before calling callback used_callback(msg_bytes) - # self.__sessions__[rule_id].pop(dtag) + self.__sessions__[rule_id].pop(dtag) return after_reassembly_processing self.callback_creator = create_after_processing_callback diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py index 4f11d91..f922837 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py @@ -69,6 +69,7 @@ def generate_message(self, mtu): self.sm.state.enter_state() message = self.sm.message_to_send.pop(0) self._logger_.schc_message(message) + self.sm.on_success(self.sm.payload.as_bytes()) return message else: return None @@ -146,7 +147,6 @@ def receive_all1_schc_fragment(self, schc_message): self._logger_.debug("Integrity check successful") compressed_bitmap = None self.__success__ = True - self.sm.on_success(self.sm.payload.as_bytes()) else: self._logger_.error("Integrity check failed:\tSender: {}\tReceiver:{}".format( schc_message.header.rcs.rcs, From 0382785785d5aeca4b4d61e5461e86f954556dd6 Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Wed, 16 Jun 2021 12:35:57 -0400 Subject: [PATCH 31/50] Fix: ACK REQ has issues with next fsm --- .../lorawan/ack_on_error_receiver.py | 1 + .../code/schc_machines/schc_fsm.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py index f922837..6278379 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py @@ -67,6 +67,7 @@ def generate_message(self, mtu): if self.sm.__last_window__ and self.__success__: self.sm.state = self.sm.states["end"] self.sm.state.enter_state() + self.sm.inactivity_timer.reset() message = self.sm.message_to_send.pop(0) self._logger_.schc_message(message) self.sm.on_success(self.sm.payload.as_bytes()) diff --git a/fragmentation_layer/code/schc_machines/schc_fsm.py b/fragmentation_layer/code/schc_machines/schc_fsm.py index 1807780..013eb4b 100644 --- a/fragmentation_layer/code/schc_machines/schc_fsm.py +++ b/fragmentation_layer/code/schc_machines/schc_fsm.py @@ -345,6 +345,22 @@ def generate_message(self, mtu): """ raise SystemExit(self.sm.__end_msg__) + def on_expiration_time(self, alarm) -> None: + """ + Behaviour on time expiration + + Parameters + ---------- + alarm : Timer + Alarm that triggers expiration + + Returns + ------- + None + """ + self.sm.__active__ = False + return + def __init__(self, protocol, dtag=None): """ Constructor @@ -378,6 +394,7 @@ def __init__(self, protocol, dtag=None): self.__exit_msg__ = "" self.__end_msg__ = "" self.message_to_send = list() + self.__active__ = True return def receive_message(self, message): From 8f76723008165702cedf09272d37ae4caf3ef48d Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Wed, 16 Jun 2021 12:40:31 -0400 Subject: [PATCH 32/50] Missing code in previous commit --- fragmentation_layer/code/schc_handlers/schc_gateway_handler.py | 2 +- fragmentation_layer/code/schc_handlers/schc_handler.py | 2 +- fragmentation_layer/code/schc_machines/schc_fsm.py | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index f045fa7..0b52267 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -23,7 +23,7 @@ def create_after_processing_callback(rule_id, dtag): def after_reassembly_processing(msg_bytes): # TODO decompress before calling callback used_callback(msg_bytes) - self.__sessions__[rule_id].pop(dtag) + #self.__sessions__[rule_id].pop(dtag) return after_reassembly_processing self.callback_creator = create_after_processing_callback diff --git a/fragmentation_layer/code/schc_handlers/schc_handler.py b/fragmentation_layer/code/schc_handlers/schc_handler.py index 65f7579..a282b4e 100644 --- a/fragmentation_layer/code/schc_handlers/schc_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_handler.py @@ -35,5 +35,5 @@ def receive(self, rule_id, dtag, message): def assign_session(self, rule_id, dtag, machine): if rule_id not in self.__sessions__.keys(): self.__sessions__[rule_id] = dict() - if dtag not in self.__sessions__[rule_id].keys(): + if dtag not in self.__sessions__[rule_id].keys() or self.__sessions__[rule_id][dtag].is_active() == False: self.__sessions__[rule_id][dtag] = machine diff --git a/fragmentation_layer/code/schc_machines/schc_fsm.py b/fragmentation_layer/code/schc_machines/schc_fsm.py index 013eb4b..0bed43e 100644 --- a/fragmentation_layer/code/schc_machines/schc_fsm.py +++ b/fragmentation_layer/code/schc_machines/schc_fsm.py @@ -450,3 +450,6 @@ def on_expiration_time(self, alarm): """ self.state.on_expiration_time(alarm) return + + def is_active(self): + return self.__active__ From 13342fabc51f41ba87ba7fad4530bea9932b309b Mon Sep 17 00:00:00 2001 From: Juan Ma Date: Wed, 16 Jun 2021 17:22:27 -0400 Subject: [PATCH 33/50] Functional with no errors --- .../schc_machines/lorawan/ack_on_error_receiver.py | 10 +++++++++- .../code/schc_machines/lorawan/ack_on_error_sender.py | 5 +++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py index 805efb7..3bb413c 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py @@ -54,7 +54,15 @@ def generate_message(self, mtu): self._logger_.schc_message(message) return message else: - return None + ack = SCHCAck( + rule_id=self.sm.__rule_id__, + protocol=self.sm.protocol.id, + c=True, + dtag=self.sm.__dtag__, + w=self.sm.__cw__ + ) + ack.add_padding() + return ack else: return None diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py index daf1d3b..fd9bb9e 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py @@ -43,6 +43,7 @@ def __generate_tiles__(self): self._logger_.debug("{} tiles generated".format(len(sm.tiles))) self.sm.state = self.sm.states["sending_phase"] self.sm.state.enter_state() + self.sm.message_to_send.clear() return class SendingPhase(SCHCSender.SenderState): @@ -184,6 +185,7 @@ def receive_schc_ack(self, schc_message): self.sm.__cw__ = schc_message.header.w.w self.sm.state = self.sm.states["resending_phase"] self.sm.state.enter_state() + self.sm.message_to_send.clear() return else: # self.sm.__cw__ == schc_message.header.w.w: if schc_message.header.c.c: @@ -213,6 +215,7 @@ def receive_schc_ack(self, schc_message): self.sm.retransmission_timer.stop() self.sm.state = self.sm.states["resending_phase"] self.sm.state.enter_state() + self.sm.message_to_send.clear() return else: self.sm.state = self.sm.states["error"] @@ -230,6 +233,7 @@ def receive_schc_ack(self, schc_message): self.sm.state = self.sm.states["resending_phase"] self.sm.retransmission_timer.stop() self.sm.state.enter_state() + self.sm.message_to_send.clear() return else: self.sm.sent_tiles.clear() @@ -238,6 +242,7 @@ def receive_schc_ack(self, schc_message): self.sm.__cw__ += 1 self.sm.__fcn__ = self.sm.protocol.WINDOW_SIZE - 1 self.sm.state.enter_state() + self.sm.message_to_send.clear() return def on_expiration_time(self, alarm): From 9a49ee28c44dbd27749f6a4178011e66f51cbc85 Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Wed, 16 Jun 2021 18:48:34 -0400 Subject: [PATCH 34/50] Sending more than one message in a row --- fragmentation_layer/code/main.py | 10 +++++++++- .../code/schc_handlers/schc_node_handler.py | 7 ++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/fragmentation_layer/code/main.py b/fragmentation_layer/code/main.py index 521a3b4..6ff0ece 100644 --- a/fragmentation_layer/code/main.py +++ b/fragmentation_layer/code/main.py @@ -2,8 +2,9 @@ import socket import binascii import struct +import time -from message import SHORT_MESSAGE as MESSAGE +from message import MESSAGE as MESSAGE from schc_handlers import SCHCNodeHandler from schc_protocols import SCHCProtocol @@ -38,5 +39,12 @@ s.setsockopt(socket.SOL_LORA, socket.SO_DR, 0) handler = SCHCNodeHandler(SCHCProtocol.LoRaWAN, 51) +# first message +handler.send_package(MESSAGE) +handler.start(s) + +time.sleep(20) + +# second message handler.send_package(MESSAGE) handler.start(s) diff --git a/fragmentation_layer/code/schc_handlers/schc_node_handler.py b/fragmentation_layer/code/schc_handlers/schc_node_handler.py index a8c9b42..b8bd7b2 100644 --- a/fragmentation_layer/code/schc_handlers/schc_node_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_node_handler.py @@ -37,7 +37,12 @@ def start(self, s): for rule_id in self.__sessions__.keys(): for dtag in self.__sessions__[rule_id].keys(): machine = self.__sessions__[rule_id][dtag] - message = machine.generate_message(self.__mtu__) + try: + message = machine.generate_message(self.__mtu__) + except SystemExit as e: + print(e) + self.__sessions__[rule_id].pop(dtag) + return if message is not None: s.setblocking(True) From 954d3a7612526b5fe6393b5b463f2361197a4947 Mon Sep 17 00:00:00 2001 From: Juan Ma Date: Thu, 17 Jun 2021 00:49:14 -0400 Subject: [PATCH 35/50] On error functional, with 2 exceptions: All-1 lost and final Ack lost --- fragmentation_layer/code/schc_base/bitmap.py | 13 +- .../lorawan/ack_on_error_receiver.py | 199 ++++++++++++++---- .../lorawan/ack_on_error_sender.py | 85 ++++---- .../code/schc_machines/schc_fsm.py | 31 +-- .../code/schc_machines/schc_receiver.py | 35 +++ .../code/schc_protocols/lorawan.py | 2 +- fragmentation_layer/example/common_methods.py | 13 +- fragmentation_layer/example/test_receiver.py | 4 +- fragmentation_layer/example/test_sender.py | 2 - .../tests/test_base/test_bitmap.py | 15 ++ 10 files changed, 288 insertions(+), 111 deletions(-) diff --git a/fragmentation_layer/code/schc_base/bitmap.py b/fragmentation_layer/code/schc_base/bitmap.py index 12717a2..5225fe3 100644 --- a/fragmentation_layer/code/schc_base/bitmap.py +++ b/fragmentation_layer/code/schc_base/bitmap.py @@ -118,7 +118,7 @@ def has_missing(self): break return 0 < sum(self.__bitmap__[i+1:]) - def get_missing(self, fcn=False): + def get_missing(self, fcn=False, after=None): """ Gets first index of reported missing tile. If fcn is True, passes as fcn @@ -127,13 +127,22 @@ def get_missing(self, fcn=False): ---------- fcn : bool, optional If fcn is True, missing as fcn + after : int, optional + Check after a particular fcn Returns ------- int First index with missing tile """ - i = self.__bitmap__.index(False) + if after is None: + i = self.__bitmap__.index(False) + else: + if fcn: + i = self.__bitmap__[self.protocol.WINDOW_SIZE - after:].index(False) + return after - 1 - i + else: + i = self.__bitmap__[after + 1:].index(False) + after + 1 if fcn: return self.protocol.WINDOW_SIZE - 1 - i else: diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py index 3bb413c..f7e8f5c 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py @@ -1,7 +1,7 @@ """ ack_on_error_receiver: AckOnError receiver state machine """ from machine import Timer -from schc_base import Bitmap +from schc_base import Bitmap, Tile from schc_machines import SCHCReceiver from schc_messages import RegularSCHCFragment, SCHCAck, All1SCHCFragment, SCHCAckReq, SCHCReceiverAbort @@ -84,6 +84,7 @@ def on_expiration_time(self, alarm) -> None: def receive_regular_schc_fragment(self, schc_message): """ + Behaviour when receiving a Regular SCHC Fragment Parameters ---------- @@ -103,7 +104,9 @@ def receive_regular_schc_fragment(self, schc_message): self._logger_.debug("Window received: {}\tTiles from: {} to {}".format( schc_message.header.w.w, fcn, fcn - tiles_received + 1)) for tile in range(tiles_received): - self.sm.payload.add_content(tiles[0:self.sm.protocol.TILE_SIZE // 8]) + self.sm.add_tile(Tile( + tiles[0:self.sm.protocol.TILE_SIZE // 8] + ), w=self.sm.__cw__, fcn=self.sm.__fcn__) tiles = tiles[self.sm.protocol.TILE_SIZE // 8:] self.sm.bitmaps[ self.sm.__cw__ @@ -149,12 +152,13 @@ def receive_all1_schc_fragment(self, schc_message): if self.sm.__cw__ == schc_message.header.w: self.sm.__last_window__ = True last_payload = schc_message.payload.as_bytes() - self.sm.payload.add_content(last_payload) + self.sm.add_tile(Tile(last_payload), w=self.sm.__cw__, fcn=self.sm.__fcn__) bitmap = self.sm.bitmaps[schc_message.header.w.w] if bitmap.has_missing(): integrity = False compressed_bitmap = bitmap.generate_compress() else: + self.sm.reassemble() rcs = self.sm.protocol.calculate_rcs( self.sm.payload.as_bits() ) @@ -164,12 +168,21 @@ def receive_all1_schc_fragment(self, schc_message): compressed_bitmap = None self.__success__ = True else: - self._logger_.error("Integrity check failed:\tSender: {}\tReceiver:{}".format( + self._logger_.error("Integrity check failed:\tSender: {}\tReceiver: {}".format( schc_message.header.rcs.rcs, rcs )) - compressed_bitmap = bitmap.generate_compress() - return integrity, compressed_bitmap + abort = SCHCReceiverAbort( + rule_id=self.sm.__rule_id__, + protocol=self.sm.protocol.id, + dtag=self.sm.__dtag__, + w=self.sm.__cw__ + ) + abort.add_padding() + self.sm.message_to_send.append(abort) + self.sm.state = self.sm.states["error"] + self.sm.state.enter_state() + return ack = SCHCAck(self.sm.__rule_id__, self.sm.protocol.id, c=integrity, @@ -180,7 +193,7 @@ def receive_all1_schc_fragment(self, schc_message): self.sm.message_to_send.append(ack) return else: - self._logger_.degug("(All-1) Different window received") + self._logger_.debug("(All-1) Different window received") return def receive_schc_ack_req(self, schc_message): @@ -213,6 +226,9 @@ def receive_schc_ack_req(self, schc_message): return if bitmap.is_missing(): self._logger_.debug("Window {} has missing tiles".format(w)) + self.sm.state = self.sm.states["waiting_phase"] + self.sm.state.enter_state() + self.sm.inactivity_timer.reset() self.sm.message_to_send.append( SCHCAck(self.sm.__rule_id__, self.sm.protocol.id, False, w=w, compressed_bitmap=bitmap.generate_compress()) @@ -263,29 +279,10 @@ def receive_regular_schc_fragment(self, schc_message): self.sm.state.receive_regular_schc_fragment(schc_message) else: self._logger_.debug("Receiving failed ones") - fcn = schc_message.header.fcn.fcn - tiles_received = schc_message.payload.size // self.sm.protocol.TILE_SIZE - tiles = schc_message.payload.as_bytes() - for tile in range(tiles_received): - self._logger_.debug("Window received: {}\tTile {}".format( - schc_message.header.w.w, fcn)) - self.sm.payload.add_content(tiles[0:self.sm.protocol.TILE_SIZE // 8]) - tiles = tiles[self.sm.protocol.TILE_SIZE // 8:] - self.sm.bitmaps[self.sm.__cw__].tile_received(fcn) - if self.sm.bitmaps[self.sm.__cw__].is_missing(): - fcn = self.sm.bitmaps[self.sm.__cw__].get_missing(fcn=True) - else: - ack = SCHCAck( - rule_id=self.sm.__rule_id__, - protocol=self.sm.protocol.id, - c=False, - dtag=self.sm.__dtag__, - w=self.sm.__cw__, - compressed_bitmap=self.sm.bitmaps[self.sm.__cw__].generate_compress() - ) - ack.add_padding() - self.sm.message_to_send.append(ack) - return + self.sm.__cw__ = schc_message.header.w.w + self.sm.state = self.sm.states["receiving_missing_phase"] + self.enter_state() + self.sm.state.receive_regular_schc_fragment(schc_message) return def receive_all1_schc_fragment(self, schc_message): @@ -322,14 +319,16 @@ def receive_schc_ack_req(self, schc_message): w = schc_message.header.w.w if w not in self.sm.bitmaps.keys(): return - if not self.sm.__last_window__: - self.sm.message_to_send.append( - SCHCAck(self.sm.__rule_id__, self.sm.protocol.id, - c=False, w=w, compressed_bitmap=self.sm.bitmaps[w].generate_compress()) - ) - self.sm.attempts.increment() - else: - pass + ack = SCHCAck( + rule_id=self.sm.__rule_id__, + protocol=self.sm.protocol.id, + c=False, + w=w, + compressed_bitmap=self.sm.bitmaps[w].generate_compress() + ) + ack.add_padding() + self.sm.message_to_send.append(ack) + self.sm.attempts.increment() return def on_expiration_time(self, alarm) -> None: @@ -348,10 +347,120 @@ def on_expiration_time(self, alarm) -> None: std_on_expiration_time(self, alarm) return + class ReceivingMissingPhase(SCHCReceiver.ReceiverState): + """ + Receiving Missing Phase, machine receive missing fragments + """ + __name__ = "Receiving Missing Phase" + + def receive_regular_schc_fragment(self, schc_message): + """ + Behaviour when receiving a Regular SCHC Fragment + + Parameters + ---------- + schc_message : RegularSCHCFragment + A regular Fragment received + + Returns + ------- + None, alter state + """ + self.sm.inactivity_timer.stop() + if self.sm.__cw__ == schc_message.header.w: + fcn = schc_message.header.fcn.fcn + tiles_received = schc_message.payload.size // self.sm.protocol.TILE_SIZE + tiles = schc_message.payload.as_bytes() + for tile in range(tiles_received): + self._logger_.debug("Window received: {}\tTile {}".format( + schc_message.header.w.w, fcn)) + self.sm.add_tile(Tile( + tiles[0:self.sm.protocol.TILE_SIZE // 8] + ), w=self.sm.__cw__, fcn=fcn) + tiles = tiles[self.sm.protocol.TILE_SIZE // 8:] + self.sm.bitmaps[self.sm.__cw__].tile_received(fcn) + try: + fcn = self.sm.bitmaps[self.sm.__cw__].get_missing(fcn=True, after=fcn) + except ValueError: + try: + fcn = self.sm.bitmaps[self.sm.__cw__].get_missing(fcn=True) + except ValueError: + ack = SCHCAck( + rule_id=self.sm.__rule_id__, + protocol=self.sm.protocol.id, + c=False, + dtag=self.sm.__dtag__, + w=self.sm.__cw__, + compressed_bitmap=self.sm.bitmaps[self.sm.__cw__].generate_compress() + ) + ack.add_padding() + self.sm.message_to_send.append(ack) + self.sm.state = self.sm.states["waiting_phase"] + self.sm.state.enter_state() + self.sm.inactivity_timer.reset() + return + self._logger_.debug("Current bitmap: {}. Waiting for w={} fcn={} tile".format( + self.sm.bitmaps[ + self.sm.__cw__ + ], self.sm.__cw__, fcn) + ) + else: + self._logger_.debug("Different window received") + return + + def receive_all1_schc_fragment(self, schc_message): + """ + Behaviour when receiving All-1 SCHC Fragment + + Parameters + ---------- + schc_message : All1SCHCFragment + Last fragment to be received + + Returns + ------- + None, alter state + """ + self.sm.state = self.sm.states["receiving_phase"] + self.sm.state.enter_state() + self.sm.state.receive_all1_schc_fragment(schc_message) + return + + def receive_schc_ack_req(self, schc_message): + """ + Behaviour when SCHC Ack Request + + Parameters + ---------- + schc_message : SCHCAckReq + SCHC message received + + Returns + ------- + None, alter state + """ + w = schc_message.header.w.w + if w not in self.sm.bitmaps.keys(): + return + if not self.sm.__last_window__: + ack = SCHCAck( + rule_id=self.sm.__rule_id__, + protocol=self.sm.protocol.id, + c=False, + w=w, + compressed_bitmap=self.sm.bitmaps[w].generate_compress() + ) + ack.add_padding() + self.sm.message_to_send.append(ack) + else: + pass + return + def __init__(self, protocol, dtag=None, on_success=None): super().__init__(protocol, dtag=dtag) self.states["receiving_phase"] = AckOnErrorReceiver.ReceivingPhase(self) self.states["waiting_phase"] = AckOnErrorReceiver.WaitingPhase(self) + self.states["receiving_missing_phase"] = AckOnErrorReceiver.ReceivingMissingPhase(self) self.state = self.states["receiving_phase"] self.inactivity_timer.reset() self.state.enter_state() @@ -376,12 +485,12 @@ def std_on_expiration_time(state, alarm): """ state.sm.state = state.sm.states["error"] state.sm.state.enter_state() - state.sm.message_to_send.append( - SCHCReceiverAbort( - rule_id=state.sm.__rule_id__, - protocol=state.sm.protocol.id, - dtag=state.sm.__dtag__, - w=state.sm.__cw__ - ) + abort = SCHCReceiverAbort( + rule_id=state.sm.__rule_id__, + protocol=state.sm.protocol.id, + dtag=state.sm.__dtag__, + w=state.sm.__cw__ ) + abort.add_padding() + state.sm.message_to_send.append(abort) return diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py index fd9bb9e..26be139 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py @@ -8,7 +8,7 @@ class AckOnErrorSender(SCHCSender): """ AckOnError Sender State Machine with Ack-on-Error Mode - + Attributes ---------- protocol @@ -99,26 +99,8 @@ def generate_message(self, mtu): else: last_tile = self.sm.tiles.pop(0) self.sm.sent_tiles[self.sm.__fcn__] = last_tile.copy() - self.sm.__last_window__ = True - all1 = All1SCHCFragment( - rule_id=self.sm.__rule_id__, - protocol=self.sm.protocol.id, - dtag=self.sm.__dtag__, - w=self.sm.__cw__, - rcs=self.sm.rcs - ) - all1.add_tile(last_tile) + all1 = send_all1(self, last_tile) self._logger_.schc_message(all1) - self.sm.state = self.sm.states["waiting_phase"] - self.sm.state.enter_state() - self.sm.retransmission_timer.reset() - self.sm.message_to_send.append(SCHCAckReq( - self.sm.__rule_id__, - self.sm.protocol.id, - self.sm.__dtag__, - self.sm.__cw__ - )) - all1.add_padding() return all1 regular_message.add_padding() self._logger_.schc_message(regular_message) @@ -160,6 +142,7 @@ def generate_message(self, mtu): if len(self.sm.message_to_send) != 0: if self.sm.message_to_send[0].size - self.sm.protocol.FPORT_LENGTH <= mtu * 8: message = self.sm.message_to_send.pop(0) + self._logger_.schc_message(message) return message else: return None @@ -211,7 +194,7 @@ def receive_schc_ack(self, schc_message): self._logger_.debug("Received bitmap: {}".format(bitmap)) self.sm.bitmaps[schc_message.header.w.w] = bitmap if self.sm.__last_window__: - if bitmap.has_missing() or bitmap.get_received_tiles() < self.sm.sent_tiles: + if bitmap.has_missing() or bitmap.get_received_tiles() < len(self.sm.sent_tiles): self.sm.retransmission_timer.stop() self.sm.state = self.sm.states["resending_phase"] self.sm.state.enter_state() @@ -280,6 +263,7 @@ def on_expiration_time(self, alarm): ack_req.add_padding() self.sm.message_to_send.append(ack_req) self.sm.attempts.increment() + self.sm.retransmission_timer.reset() return class ResendingPhase(SCHCSender.SenderState): @@ -319,25 +303,8 @@ def generate_message(self, mtu): # MTU should not count FPort mtu_available += regular_message.header.rule_id.size if 0 < last_tile == the_fcn: - all1 = All1SCHCFragment( - rule_id=self.sm.__rule_id__, - protocol=self.sm.protocol.id, - dtag=self.sm.__dtag__, - w=self.sm.__cw__, - rcs=self.sm.rcs - ) - all1.add_tile(self.sm.sent_tiles[last_tile]) + all1 = send_all1(self, self.sm.sent_tiles[last_tile]) self._logger_.schc_message(all1) - self.sm.state = self.sm.states["waiting_phase"] - self.sm.state.enter_state() - self.sm.retransmission_timer.reset() - self.sm.message_to_send.append(SCHCAckReq( - self.sm.__rule_id__, - self.sm.protocol.id, - self.sm.__dtag__, - self.sm.__cw__ - )) - all1.add_padding() return all1 if the_fcn < last_tile: self.sm.state = self.sm.states["waiting_phase"] @@ -388,3 +355,43 @@ def __init__(self, protocol, payload, padding=0, dtag=None): self.sent_tiles = dict() self.state.__generate_tiles__() return + + +def send_all1(state, last_tile): + """ + Sends All1SCHCFragment + + Parameters + ---------- + state : AckOnErrorSender.SenderState + State to send all-1 from + last_tile : Tile + Last tile to send + + Returns + ------- + All1SCHCFragment + Fragment to send + """ + state.sm.__last_window__ = True + all1 = All1SCHCFragment( + rule_id=state.sm.__rule_id__, + protocol=state.sm.protocol.id, + dtag=state.sm.__dtag__, + w=state.sm.__cw__, + rcs=state.sm.rcs + ) + all1.add_tile(last_tile) + state.sm.state = state.sm.states["waiting_phase"] + state.sm.state.enter_state() + state.sm.retransmission_timer.reset() + ack_req = SCHCAckReq( + rule_id=state.sm.__rule_id__, + protocol=state.sm.protocol.id, + dtag=state.sm.__dtag__, + w=state.sm.__cw__ + ) + ack_req.add_padding() + state.sm.message_to_send.append(ack_req) + all1.add_padding() + return all1 diff --git a/fragmentation_layer/code/schc_machines/schc_fsm.py b/fragmentation_layer/code/schc_machines/schc_fsm.py index 9fc774d..db0dd63 100644 --- a/fragmentation_layer/code/schc_machines/schc_fsm.py +++ b/fragmentation_layer/code/schc_machines/schc_fsm.py @@ -1,5 +1,6 @@ """ schc_fsm: SCHC Finite State Machine Abstract Class """ +import datetime from machine import Timer from schc_base import AttemptsCounter, Bitmap from schc_messages import SCHCMessage @@ -8,7 +9,7 @@ class SCHCFiniteStateMachine: """ - Finite State Machine of Sender/Receiver (Fragmenter/Ensembler) + Finite State Machine of Sender/Receiver (Fragmenter/Reassembler) behaviours Attributes @@ -61,15 +62,19 @@ class Logger: """ SCHC Logger to log SCHC Fragmentation """ - def __init__(self, state) -> None: + TAG = "{mode}::[{datetime}]::" + + def __init__(self, state): self.__state__ = state return - def __log__(self, mode) -> None: - mode("SCHC Fragment on '{}' mode, {} on '{}' state".format( - self.__state__.sm.__mode__, - self.__state__.sm.__type__, - self.__state__.__name__ + def __log__(self, mode): + print( + self.TAG.format(mode=mode, datetime=datetime.datetime.now()) + + "SCHC Fragment on '{}' mode, {} on '{}' state".format( + self.__state__.sm.__mode__, + self.__state__.sm.__type__, + self.__state__.__name__ )) second_line = "\tProtocol: {}, Rule ID: {}".format( self.__state__.sm.protocol.__name__, @@ -79,7 +84,7 @@ def __log__(self, mode) -> None: second_line += ", DTag: {}".format( self.__state__.sm.__dtag__ ) - mode(second_line) + print(second_line) return def enter_state(self): @@ -90,7 +95,7 @@ def enter_state(self): ------- None """ - self.__log__(print) + self.__log__("DEBUG") return def schc_message(self, message): @@ -123,7 +128,7 @@ def error(self, message): ------- None """ - self.__log__(print) + self.__log__("ERROR") print("\t{}".format(message)) return @@ -140,7 +145,7 @@ def warning(self, message): ------- None """ - self.__log__(print) + self.__log__("WARNING") print("\t{}".format(message)) return @@ -157,7 +162,7 @@ def debug(self, message): ------- None """ - self.__log__(print) + self.__log__("DEBUG") print("\t{}".format(message)) return @@ -174,7 +179,7 @@ def info(self, message): ------- None """ - self.__log__(print) + self.__log__("INFO") print("\t{}".format(message)) return diff --git a/fragmentation_layer/code/schc_machines/schc_receiver.py b/fragmentation_layer/code/schc_machines/schc_receiver.py index 8ab7e87..2ae7e38 100644 --- a/fragmentation_layer/code/schc_machines/schc_receiver.py +++ b/fragmentation_layer/code/schc_machines/schc_receiver.py @@ -138,6 +138,41 @@ def receive_schc_sender_abort(self, schc_message): def __init__(self, protocol, dtag=None): super().__init__(protocol, dtag=dtag) self.payload = SCHCPayload() + self.__payload__ = dict() self.inactivity_timer = SCHCTimer(self.on_expiration_time, protocol.INACTIVITY_TIMER) self.__end_msg__ = "Message received and resembled" return + + def add_tile(self, tile, w, fcn): + """ + Adds tile to future payload + Parameters + ---------- + tile : Tile + The tile to add + w : int + Window of tile + fcn : int + FCN of tile + + Returns + ------- + None + """ + if w not in self.__payload__.keys(): + self.__payload__[w] = dict() + self.__payload__[w][fcn] = tile.copy() + return + + def reassemble(self): + """ + Reassembles payload and saved on payload + + Returns + ------- + None + """ + for w in sorted(self.__payload__.keys()): + for fcn in reversed(sorted(self.__payload__[w].keys())): + self.payload.add_content(self.__payload__[w][fcn].as_bits()) + return diff --git a/fragmentation_layer/code/schc_protocols/lorawan.py b/fragmentation_layer/code/schc_protocols/lorawan.py index 301041f..3a37fc2 100644 --- a/fragmentation_layer/code/schc_protocols/lorawan.py +++ b/fragmentation_layer/code/schc_protocols/lorawan.py @@ -70,7 +70,7 @@ def __set_parameters__(self): self.TILE_SIZE = 10 * 8 # 10 bytes = 80 bits self.MAX_ACK_REQUEST = 1e6 # TODO self.INACTIVITY_TIMER = 30 # in seconds TODO - self.RETRANSMISSION_TIMER = 5 # in seconds TODO + self.RETRANSMISSION_TIMER = 2 # in seconds TODO elif self.RULE_ID == LoRaWAN.ACK_ALWAYS: # Downlink data transfer self.T = 0 # in bits self.M = 1 # in bits diff --git a/fragmentation_layer/example/common_methods.py b/fragmentation_layer/example/common_methods.py index 542a96b..1004590 100644 --- a/fragmentation_layer/example/common_methods.py +++ b/fragmentation_layer/example/common_methods.py @@ -2,13 +2,12 @@ import random import socket -import logging from schc_machines import SCHCFiniteStateMachine HOST = "127.0.0.1" MTU = 50 -SEED = 8 -PROBABILITY_OF_FAILURE = 0.0 +SEED = 7 +PROBABILITY_OF_FAILURE = 0.2 random.seed(SEED) @@ -102,9 +101,11 @@ def messaging_loop(machine: SCHCFiniteStateMachine, socket_rx: socket.socket, se print("Sending...") print("Messages enqueued: {}".format(machine.message_to_send)) message = machine.generate_message(mtu) - logging.info("Current mtu: {}".format(mtu)) - logging.info("Package sent: {}".format(not lost)) - if not lost and message is not None: + print("Current mtu: {}".format(mtu)) + print("Package sent: {}".format(not lost)) + if isinstance(machine.state, SCHCFiniteStateMachine.EndState): + send_socket(message.as_bytes(), sender_port) + elif not lost and message is not None: send_socket(message.as_bytes(), sender_port) except SystemExit as e: print(e) diff --git a/fragmentation_layer/example/test_receiver.py b/fragmentation_layer/example/test_receiver.py index 2117258..8dac5db 100644 --- a/fragmentation_layer/example/test_receiver.py +++ b/fragmentation_layer/example/test_receiver.py @@ -8,14 +8,12 @@ SENDER_PORT = 50007 socket_rx = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -socket_rx.settimeout(10) +socket_rx.settimeout(2) socket_rx.bind((HOST, RECEIVER_PORT)) socket_rx.listen(1) if __name__ == '__main__': - logging.basicConfig(level=logging.DEBUG) - from schc_machines.lorawan import AckOnErrorReceiver from schc_protocols import LoRaWAN diff --git a/fragmentation_layer/example/test_sender.py b/fragmentation_layer/example/test_sender.py index 86a2b5d..c302140 100644 --- a/fragmentation_layer/example/test_sender.py +++ b/fragmentation_layer/example/test_sender.py @@ -63,8 +63,6 @@ if __name__ == '__main__': - logging.basicConfig(level=logging.DEBUG) - from schc_machines.lorawan import AckOnErrorSender from schc_protocols import LoRaWAN diff --git a/fragmentation_layer/tests/test_base/test_bitmap.py b/fragmentation_layer/tests/test_base/test_bitmap.py index cb53762..7673826 100644 --- a/fragmentation_layer/tests/test_base/test_bitmap.py +++ b/fragmentation_layer/tests/test_base/test_bitmap.py @@ -91,6 +91,21 @@ def test_has_missing(self): bitmap.tile_received(protocol.WINDOW_SIZE - (i + 1)) self.assertFalse(bitmap.has_missing(), "Bitmap full True has missing") + def test_get_missing(self): + protocol = LoRaWAN(LoRaWAN.ACK_ON_ERROR) + bitmap = Bitmap(protocol) + self.assertEqual(0, bitmap.get_missing(), "fcn = False, after = None") + bitmap.tile_received(protocol.WINDOW_SIZE - 5) # 63 - 5 = 58, index = 4 + self.assertEqual(0, bitmap.get_missing(), "fcn = False, after = None (with one tile)") + self.assertEqual(7, bitmap.get_missing(after=6), "fcn = False, after = 6 (with one tile)") + self.assertEqual(56, bitmap.get_missing(fcn=True, after=57), "fcn = True, after = 57 (with one tile)") + for i in range(5): + bitmap.tile_received(protocol.WINDOW_SIZE - (i + 1)) + self.assertEqual(5, bitmap.get_missing(), "fcn = False, after = None (with six tiles)") + self.assertEqual(57, bitmap.get_missing(fcn=True), "fcn = True, after = None (with six tiles)") + self.assertEqual(5, bitmap.get_missing(after=4), "fcn = False, after = 4 (with one tile)") + self.assertEqual(57, bitmap.get_missing(fcn=True, after=62), "fcn = True, after = 55 (with one tile)") + if __name__ == '__main__': main() From 5e45b3cf5d445ec7907cab02c96c25f91d5c13bb Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Mon, 21 Jun 2021 13:51:21 -0400 Subject: [PATCH 36/50] making last changes lopy compatible --- .../{machine => lopy_machine}/__init__.py | 15 +- .../code/{machine => lopy_machine}/timer.py | 200 +++++++++--------- 2 files changed, 108 insertions(+), 107 deletions(-) rename fragmentation_layer/code/{machine => lopy_machine}/__init__.py (62%) rename fragmentation_layer/code/{machine => lopy_machine}/timer.py (97%) diff --git a/fragmentation_layer/code/machine/__init__.py b/fragmentation_layer/code/lopy_machine/__init__.py similarity index 62% rename from fragmentation_layer/code/machine/__init__.py rename to fragmentation_layer/code/lopy_machine/__init__.py index c46b5e0..98c929b 100644 --- a/fragmentation_layer/code/machine/__init__.py +++ b/fragmentation_layer/code/lopy_machine/__init__.py @@ -1,7 +1,8 @@ -""" -machine: Package implementing PyCom machine modules ( -https://docs.pycom.io/firmwareapi/pycom/machine/ -). Not to be used in production -""" - -from machine.timer import Timer +""" +machine: Package implementing PyCom machine modules ( +https://docs.pycom.io/firmwareapi/pycom/machine/ +). Not to be used in production +""" + +if sys.implementation.name != "mycropython": + from lopy_machine.timer import Timer diff --git a/fragmentation_layer/code/machine/timer.py b/fragmentation_layer/code/lopy_machine/timer.py similarity index 97% rename from fragmentation_layer/code/machine/timer.py rename to fragmentation_layer/code/lopy_machine/timer.py index 2c6f535..1c8bf2d 100644 --- a/fragmentation_layer/code/machine/timer.py +++ b/fragmentation_layer/code/lopy_machine/timer.py @@ -1,100 +1,100 @@ -""" Timer: Equivalent to Timer class (PyCom) """ - -import threading - - -class Timer: - """ - Class implementing desire functionalities of PyCom Timer Class ( - https://docs.pycom.io/firmwareapi/pycom/machine/timer/ - ). Used for testing on local only, - """ - - class Alarm: - """ - Used to get interrupted after a specific interval (PyCom) - """ - - def __init__(self, handler, s=None, *, ms=None, us=None, arg=None, periodic=False): - """ - Constructor - - Parameters - ---------- - handler : Callable - Handler of alarm funcion - s : float, optional - Seconds, if ms and us are not specified this parameter is not optional - ms : float, optional - Milliseconds, if s and us are not specified this parameter is not optional - us : float, optional - Microseconds, if s and ms are not specified this parameter is not optional - arg : Tuple[object, ...], optional - Args of handler function - periodic : bool, optional - Whether the alarm is periodic (start counting again when limit time is reach) - """ - if s is None and ms is None and us is None: - raise TypeError("__init__() missing 1 required keyword only argument: 's', 'ms' or 'us'") - self.__timer__ = None - self.__seconds__ = sum([ - (s if s is not None else 0), - (ms / 1e3 if ms is not None else 0), - (us / 1e6 if us is not None else 0) - ]) - self.__handler__ = handler - self.__args__ = arg - self.__periodic__ = periodic - self.__set_alarm__() - return - - def __set_alarm__(self) -> None: - if self.__handler__ is None: - return - else: - self.__timer__ = threading.Timer(self.__seconds__, self.__run__) - self.__timer__.start() - return - - def __run__(self) -> None: - if self.__args__ is not None: - self.__handler__(self, *self.__args__) - else: - self.__handler__(self) - if self.__periodic__: - self.__set_alarm__() - return - - def callback(self, handler, arg=None): - """ - Specify a callback handler for the alarm. - - Parameters - ---------- - handler : Callable - Callback handler. If set to None, the alarm will be disabled. - arg : Tuple, optional - Argument passed to the callback handler function. - If None is specified, the function will receive the object that triggered the alarm. - - Returns - ------- - None - """ - self.__handler__ = handler - self.__args__ = arg - self.__set_alarm__() - return - - def cancel(self): - """ - Disables the alarm. - - Returns - ------- - None - """ - if self.__timer__ is not None: - self.__timer__.cancel() - self.__periodic__ = False - return +""" Timer: Equivalent to Timer class (PyCom) """ + +import threading + + +class Timer: + """ + Class implementing desire functionalities of PyCom Timer Class ( + https://docs.pycom.io/firmwareapi/pycom/machine/timer/ + ). Used for testing on local only, + """ + + class Alarm: + """ + Used to get interrupted after a specific interval (PyCom) + """ + + def __init__(self, handler, s=None, *, ms=None, us=None, arg=None, periodic=False): + """ + Constructor + + Parameters + ---------- + handler : Callable + Handler of alarm funcion + s : float, optional + Seconds, if ms and us are not specified this parameter is not optional + ms : float, optional + Milliseconds, if s and us are not specified this parameter is not optional + us : float, optional + Microseconds, if s and ms are not specified this parameter is not optional + arg : Tuple[object, ...], optional + Args of handler function + periodic : bool, optional + Whether the alarm is periodic (start counting again when limit time is reach) + """ + if s is None and ms is None and us is None: + raise TypeError("__init__() missing 1 required keyword only argument: 's', 'ms' or 'us'") + self.__timer__ = None + self.__seconds__ = sum([ + (s if s is not None else 0), + (ms / 1e3 if ms is not None else 0), + (us / 1e6 if us is not None else 0) + ]) + self.__handler__ = handler + self.__args__ = arg + self.__periodic__ = periodic + self.__set_alarm__() + return + + def __set_alarm__(self) -> None: + if self.__handler__ is None: + return + else: + self.__timer__ = threading.Timer(self.__seconds__, self.__run__) + self.__timer__.start() + return + + def __run__(self) -> None: + if self.__args__ is not None: + self.__handler__(self, *self.__args__) + else: + self.__handler__(self) + if self.__periodic__: + self.__set_alarm__() + return + + def callback(self, handler, arg=None): + """ + Specify a callback handler for the alarm. + + Parameters + ---------- + handler : Callable + Callback handler. If set to None, the alarm will be disabled. + arg : Tuple, optional + Argument passed to the callback handler function. + If None is specified, the function will receive the object that triggered the alarm. + + Returns + ------- + None + """ + self.__handler__ = handler + self.__args__ = arg + self.__set_alarm__() + return + + def cancel(self): + """ + Disables the alarm. + + Returns + ------- + None + """ + if self.__timer__ is not None: + self.__timer__.cancel() + self.__periodic__ = False + return From 5dcf1ab3e0c9211f11e3409420b312bd83e7579c Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Tue, 22 Jun 2021 12:27:52 -0400 Subject: [PATCH 37/50] code works on lopy without modification --- fragmentation_layer/code/lopy_machine/__init__.py | 3 +-- fragmentation_layer/code/main.py | 7 +------ fragmentation_layer/code/schc_base/timer.py | 6 +++++- fragmentation_layer/code/schc_machines/schc_fsm.py | 12 ++++++++++-- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/fragmentation_layer/code/lopy_machine/__init__.py b/fragmentation_layer/code/lopy_machine/__init__.py index 98c929b..755ed9f 100644 --- a/fragmentation_layer/code/lopy_machine/__init__.py +++ b/fragmentation_layer/code/lopy_machine/__init__.py @@ -4,5 +4,4 @@ ). Not to be used in production """ -if sys.implementation.name != "mycropython": - from lopy_machine.timer import Timer +from lopy_machine.timer import Timer diff --git a/fragmentation_layer/code/main.py b/fragmentation_layer/code/main.py index 6ff0ece..d5f56a7 100644 --- a/fragmentation_layer/code/main.py +++ b/fragmentation_layer/code/main.py @@ -39,12 +39,7 @@ s.setsockopt(socket.SOL_LORA, socket.SO_DR, 0) handler = SCHCNodeHandler(SCHCProtocol.LoRaWAN, 51) -# first message -handler.send_package(MESSAGE) -handler.start(s) - -time.sleep(20) -# second message +# send message handler.send_package(MESSAGE) handler.start(s) diff --git a/fragmentation_layer/code/schc_base/timer.py b/fragmentation_layer/code/schc_base/timer.py index d96515a..3a0eb59 100644 --- a/fragmentation_layer/code/schc_base/timer.py +++ b/fragmentation_layer/code/schc_base/timer.py @@ -1,7 +1,11 @@ """ timer: Timer class """ -from machine import Timer +import sys +if sys.implementation.name == "micropython": + from machine import Timer +else: + from lopy_machine import Timer class SCHCTimer: """ diff --git a/fragmentation_layer/code/schc_machines/schc_fsm.py b/fragmentation_layer/code/schc_machines/schc_fsm.py index db0dd63..d5aff4d 100644 --- a/fragmentation_layer/code/schc_machines/schc_fsm.py +++ b/fragmentation_layer/code/schc_machines/schc_fsm.py @@ -1,6 +1,14 @@ """ schc_fsm: SCHC Finite State Machine Abstract Class """ -import datetime +import sys + +if sys.implementation.name == "micropython": + import time + now = time.time +else: + import datetime + now = datetime.datetime.now + from machine import Timer from schc_base import AttemptsCounter, Bitmap from schc_messages import SCHCMessage @@ -70,7 +78,7 @@ def __init__(self, state): def __log__(self, mode): print( - self.TAG.format(mode=mode, datetime=datetime.datetime.now()) + + self.TAG.format(mode=mode, datetime=now()) + "SCHC Fragment on '{}' mode, {} on '{}' state".format( self.__state__.sm.__mode__, self.__state__.sm.__type__, From ab4d1767454acc0de884edc8d4ad9349171d17cb Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Tue, 22 Jun 2021 12:33:59 -0400 Subject: [PATCH 38/50] server fix --- fragmentation_layer/code/schc_machines/schc_fsm.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fragmentation_layer/code/schc_machines/schc_fsm.py b/fragmentation_layer/code/schc_machines/schc_fsm.py index d5aff4d..165e25b 100644 --- a/fragmentation_layer/code/schc_machines/schc_fsm.py +++ b/fragmentation_layer/code/schc_machines/schc_fsm.py @@ -5,9 +5,11 @@ if sys.implementation.name == "micropython": import time now = time.time + from machine import Timer else: import datetime now = datetime.datetime.now + from lopy_machine import Timer from machine import Timer from schc_base import AttemptsCounter, Bitmap From abb2ade11691c5ea40750998ee7a28abd3bf1074 Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Tue, 22 Jun 2021 12:35:07 -0400 Subject: [PATCH 39/50] server fix 2 --- fragmentation_layer/code/schc_machines/schc_fsm.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fragmentation_layer/code/schc_machines/schc_fsm.py b/fragmentation_layer/code/schc_machines/schc_fsm.py index 165e25b..c4f3399 100644 --- a/fragmentation_layer/code/schc_machines/schc_fsm.py +++ b/fragmentation_layer/code/schc_machines/schc_fsm.py @@ -11,7 +11,6 @@ now = datetime.datetime.now from lopy_machine import Timer -from machine import Timer from schc_base import AttemptsCounter, Bitmap from schc_messages import SCHCMessage from schc_protocols import SCHCProtocol From 2f6f1a44bb8dd9395e21ea6a7ed1e187931488af Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Tue, 22 Jun 2021 12:38:12 -0400 Subject: [PATCH 40/50] server fix 3 --- .../code/schc_machines/lorawan/ack_on_error_receiver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py index f7e8f5c..2bedc26 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py @@ -1,6 +1,6 @@ """ ack_on_error_receiver: AckOnError receiver state machine """ -from machine import Timer +from lopy_machine import Timer from schc_base import Bitmap, Tile from schc_machines import SCHCReceiver from schc_messages import RegularSCHCFragment, SCHCAck, All1SCHCFragment, SCHCAckReq, SCHCReceiverAbort From c95717f73254523028a2754ed0b5e56e7f1bba6d Mon Sep 17 00:00:00 2001 From: Juan Ma Date: Fri, 2 Jul 2021 00:46:00 -0400 Subject: [PATCH 41/50] Numpy documentation of SCHC handlers package --- .../schc_handlers/schc_gateway_handler.py | 90 ++++++++++++++++++ .../code/schc_handlers/schc_handler.py | 93 +++++++++++++++++++ .../code/schc_handlers/schc_node_handler.py | 58 ++++++++++++ 3 files changed, 241 insertions(+) diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index 0b52267..42d93dd 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -11,8 +11,27 @@ class SCHCGatewayHandler(SCHCHandler): + """ + SCHC Gateway Handler + To be used as an API on Gateway side of communication + + Attributes + ---------- + callback_creator : Callable + A function to be used on reassembled message + """ def __init__(self, protocol, mtu, on_receive_callback=None): + """ + Constructor + + Parameters + ---------- + protocol + mtu + on_receive_callback : Callable + A function to be used when message is reassembled + """ super().__init__(protocol, mtu) if on_receive_callback: used_callback = on_receive_callback @@ -29,6 +48,25 @@ def after_reassembly_processing(msg_bytes): self.callback_creator = create_after_processing_callback def send_package(self, packet): + """ + Load package to send + + Parameters + ---------- + packet : bytes + Packet to be fragmented + + Returns + ------- + None + Parameters + ---------- + packet + + Returns + ------- + + """ if self.__protocol__.id == SCHCProtocol.LoRaWAN: from schc_machines.lorawan import AckAlwaysSender self.assign_session(LoRaWAN.ACK_ALWAYS, None, AckAlwaysSender(LoRaWAN(LoRaWAN.ACK_ALWAYS), packet)) @@ -36,6 +74,22 @@ def send_package(self, packet): raise NotImplementedError("Just LoRaWAN implemented") def receive(self, rule_id, dtag, message): + """ + Defines behaviour after receiving a message + + Parameters + ---------- + rule_id : int + Rule id of received message + dtag : int or None + DTag of received message + message : bytes + Message receive + + Returns + ------- + None + """ if self.__protocol__.id == SCHCProtocol.LoRaWAN: if rule_id == LoRaWAN.ACK_ON_ERROR: # message received @@ -54,6 +108,25 @@ def receive(self, rule_id, dtag, message): raise NotImplementedError("Just LoRaWAN implemented") def handle(self, message, f_port=None, url=None, dev_id=None): + """ + Handles a reception of SCHCMessages + + Parameters + ---------- + message : bytes + A message received + f_port : int, optional + In case of using LoRaWAN, rule id to handled message + url : str, optional + In case of using LoRaWAN, url to send answer + dev_id : str, optional + In case of using LoRaWAN, unique identifier of device + that sent the received message + + Returns + ------- + None + """ if self.__protocol__.id == SCHCProtocol.LoRaWAN: r, d = self.identify_session_from_message(message, f_port) self.receive(r, d, bytes([f_port]) + message) @@ -72,6 +145,23 @@ def handle(self, message, f_port=None, url=None, dev_id=None): r = requests.post(url, data=json.dumps(post_obj), headers={'content-type': 'application/json'}) def generate_message(self, rule_id, dtag, mtu=512): + """ + Generates a message to response + + Parameters + ---------- + rule_id : int + Rule id to identify session + dtag : int + Dtag to identify session + mtu : mtu, optional + MTU to use. Default 512 bytes + + Returns + ------- + bytes + Response to be send as bytes + """ message = self.__sessions__[rule_id][dtag].generate_message(mtu) if message is None: return message diff --git a/fragmentation_layer/code/schc_handlers/schc_handler.py b/fragmentation_layer/code/schc_handlers/schc_handler.py index a282b4e..b6bf5c9 100644 --- a/fragmentation_layer/code/schc_handlers/schc_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_handler.py @@ -6,13 +6,59 @@ # TODO: class SCHCHandler: + """ + SCHC Handler super class + Define functions and interface of Node and Gateway concrete class + Attributes + ---------- + __protocol__ : SCHCProtocol + Protocol to be use + __sessions__ : Dict[int, Dict[int, SCHCFiniteStateMachine]] + A dictionary with rule_id and DTag assigned to a SCGHCFiniteStateMachine + __mtu__ : int + MTU to use + + See Also + -------- + SCHCFiniteStateMachine + """ def __init__(self, protocol, mtu): + """ + Constructor + + Parameters + ---------- + protocol : int + Number indicating SCHCProtocol to use + mtu : int + MTU to use + + See Also + -------- + SCHCProtocol + """ self.__protocol__ = get_protocol(protocol) self.__sessions__ = dict() self.__mtu__ = mtu def identify_session_from_message(self, message, f_port=None): + """ + Identifies the session to use according to protocol and message + + Parameters + ---------- + message : bytes + A bytes message + f_port : int, optional + In case of using LoRaWAN, rule id to use + + Returns + ------- + Tuple[int, int] + Rule id and Dtag that are going to be use to find + session (and SCHCFiniteStateMachine associated) + """ if self.__protocol__.id == SCHCProtocol.LoRaWAN: rule_id = f_port else: @@ -27,12 +73,59 @@ def identify_session_from_message(self, message, f_port=None): return rule_id, dtag def send_package(self, packet): + """ + To be implemented by concrete class + Load package to send + + Parameters + ---------- + packet : bytes + Packet to be fragmented + + Returns + ------- + None + """ return def receive(self, rule_id, dtag, message): + """ + To be implemented by concrete class + Defines behaviour after receiving a message + + Parameters + ---------- + rule_id : int + Rule id of received message + dtag : int or None + DTag of received message + message : bytes + Message receive + + Returns + ------- + None + """ return def assign_session(self, rule_id, dtag, machine): + """ + Assigns a SCHCFiniteStateMachine (machine) to the corresponding + rule id and dtag + + Parameters + ---------- + rule_id : int + Rule id defining mode + dtag : int + DTag to differentiates parallel packets + machine : SCHCFiniteStateMachine + Finite State Machine defining behaviour of fragmentation + + Returns + ------- + None, alter self.__session__ + """ if rule_id not in self.__sessions__.keys(): self.__sessions__[rule_id] = dict() if dtag not in self.__sessions__[rule_id].keys() or self.__sessions__[rule_id][dtag].is_active() == False: diff --git a/fragmentation_layer/code/schc_handlers/schc_node_handler.py b/fragmentation_layer/code/schc_handlers/schc_node_handler.py index b8bd7b2..629ee46 100644 --- a/fragmentation_layer/code/schc_handlers/schc_node_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_node_handler.py @@ -5,11 +5,40 @@ class SCHCNodeHandler(SCHCHandler): + """ + SCHC Node Handler + Concrete class to be used as API for sending messages + using SCHC Protocols on a Node + """ def __init__(self, protocol, mtu): + """ + Constructor + + Parameters + ---------- + protocol + mtu + + See Also + -------- + SCHCHandler + """ super().__init__(protocol, mtu) def send_package(self, packet): + """ + Load package to send + + Parameters + ---------- + packet : bytes + Packet to be fragmented + + Returns + ------- + None + """ if self.__protocol__.id == SCHCProtocol.LoRaWAN: from schc_machines.lorawan import AckOnErrorSender self.assign_session(LoRaWAN.ACK_ON_ERROR, None, AckOnErrorSender(LoRaWAN(LoRaWAN.ACK_ON_ERROR), packet)) @@ -17,6 +46,22 @@ def send_package(self, packet): raise NotImplementedError("Just LoRaWAN implemented") def receive(self, rule_id, dtag, message): + """ + Defines behaviour after receiving a message + + Parameters + ---------- + rule_id : int + Rule id of received message + dtag : int or None + DTag of received message + message : bytes + Message receive + + Returns + ------- + None + """ if self.__protocol__.id == SCHCProtocol.LoRaWAN: if rule_id == LoRaWAN.ACK_ALWAYS: # message received @@ -33,6 +78,19 @@ def receive(self, rule_id, dtag, message): raise NotImplementedError("Just LoRaWAN implemented") def start(self, s): + """ + Starts communication, by separating message in fragments + and send them to Gateway + + Parameters + ---------- + s : socket + A socket + + Returns + ------- + None + """ while True: for rule_id in self.__sessions__.keys(): for dtag in self.__sessions__[rule_id].keys(): From 660b9f25a1261fa0fd42ec0b0fe05bcafc2d14ca Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Fri, 2 Jul 2021 10:12:11 -0400 Subject: [PATCH 42/50] lopy fix --- .../code/schc_machines/lorawan/ack_on_error_receiver.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py index 2bedc26..8b3732f 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py @@ -1,6 +1,10 @@ """ ack_on_error_receiver: AckOnError receiver state machine """ -from lopy_machine import Timer +if sys.implementation.name == "micropython": + from machine import Timer +else: + from lopy_machine import Timer + from schc_base import Bitmap, Tile from schc_machines import SCHCReceiver from schc_messages import RegularSCHCFragment, SCHCAck, All1SCHCFragment, SCHCAckReq, SCHCReceiverAbort From 1508b7ce6ee366934095c6d98e299c1c8ebdbf43 Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Fri, 2 Jul 2021 10:29:24 -0400 Subject: [PATCH 43/50] better fix for timer import --- fragmentation_layer/code/lopy_machine/__init__.py | 7 ++++++- fragmentation_layer/code/schc_base/timer.py | 7 +------ .../code/schc_machines/lorawan/ack_on_error_receiver.py | 5 +---- fragmentation_layer/code/schc_machines/schc_fsm.py | 3 +-- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/fragmentation_layer/code/lopy_machine/__init__.py b/fragmentation_layer/code/lopy_machine/__init__.py index 755ed9f..3c098f6 100644 --- a/fragmentation_layer/code/lopy_machine/__init__.py +++ b/fragmentation_layer/code/lopy_machine/__init__.py @@ -4,4 +4,9 @@ ). Not to be used in production """ -from lopy_machine.timer import Timer +import sys + +if sys.implementation.name == "micropython": + from machine import Timer +else: + from lopy_machine.timer import Timer diff --git a/fragmentation_layer/code/schc_base/timer.py b/fragmentation_layer/code/schc_base/timer.py index 3a0eb59..e696b6a 100644 --- a/fragmentation_layer/code/schc_base/timer.py +++ b/fragmentation_layer/code/schc_base/timer.py @@ -1,11 +1,6 @@ """ timer: Timer class """ -import sys - -if sys.implementation.name == "micropython": - from machine import Timer -else: - from lopy_machine import Timer +from lopy_machine import Timer class SCHCTimer: """ diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py index 8b3732f..7dbc81b 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_receiver.py @@ -1,9 +1,6 @@ """ ack_on_error_receiver: AckOnError receiver state machine """ -if sys.implementation.name == "micropython": - from machine import Timer -else: - from lopy_machine import Timer +from lopy_machine import Timer from schc_base import Bitmap, Tile from schc_machines import SCHCReceiver diff --git a/fragmentation_layer/code/schc_machines/schc_fsm.py b/fragmentation_layer/code/schc_machines/schc_fsm.py index c4f3399..bb34ff6 100644 --- a/fragmentation_layer/code/schc_machines/schc_fsm.py +++ b/fragmentation_layer/code/schc_machines/schc_fsm.py @@ -5,12 +5,11 @@ if sys.implementation.name == "micropython": import time now = time.time - from machine import Timer else: import datetime now = datetime.datetime.now - from lopy_machine import Timer +from lopy_machine import Timer from schc_base import AttemptsCounter, Bitmap from schc_messages import SCHCMessage from schc_protocols import SCHCProtocol From 4cdf97570fb99bb954633385860582f39873a567 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Sat, 3 Jul 2021 10:24:42 -0400 Subject: [PATCH 44/50] se agrega argumento al metodo handler para soportar API key --- .../code/schc_handlers/schc_gateway_handler.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index 0b52267..750b6e4 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -18,7 +18,7 @@ def __init__(self, protocol, mtu, on_receive_callback=None): used_callback = on_receive_callback else: used_callback = lambda msg: print("Message received", msg) - + def create_after_processing_callback(rule_id, dtag): def after_reassembly_processing(msg_bytes): # TODO decompress before calling callback @@ -41,7 +41,7 @@ def receive(self, rule_id, dtag, message): # message received from schc_machines.lorawan import AckOnErrorReceiver self.assign_session(rule_id, dtag, AckOnErrorReceiver( - LoRaWAN(LoRaWAN.ACK_ON_ERROR), + LoRaWAN(LoRaWAN.ACK_ON_ERROR), on_success=self.callback_creator(rule_id, dtag))) self.__sessions__[rule_id][dtag].receive_message(message) elif rule_id == LoRaWAN.ACK_ALWAYS: @@ -53,7 +53,7 @@ def receive(self, rule_id, dtag, message): else: raise NotImplementedError("Just LoRaWAN implemented") - def handle(self, message, f_port=None, url=None, dev_id=None): + def handle(self, message, f_port=None, url=None, dev_id=None, api_key=None): if self.__protocol__.id == SCHCProtocol.LoRaWAN: r, d = self.identify_session_from_message(message, f_port) self.receive(r, d, bytes([f_port]) + message) @@ -69,7 +69,8 @@ def handle(self, message, f_port=None, url=None, dev_id=None): "confirmed": False, "payload_raw": base64.b64encode(response[1:]).decode("utf-8") } - r = requests.post(url, data=json.dumps(post_obj), headers={'content-type': 'application/json'}) + headers = {'content-type': 'application/json','Authorization': api_key} + r = requests.post(url, data=json.dumps(post_obj), headers=headers) def generate_message(self, rule_id, dtag, mtu=512): message = self.__sessions__[rule_id][dtag].generate_message(mtu) From cf9e0cb100bd9116900256078696c377f0262c1a Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Mon, 12 Jul 2021 21:39:34 -0400 Subject: [PATCH 45/50] =?UTF-8?q?Se=20comenta=20la=20linea=20de=20codigo?= =?UTF-8?q?=20que=20muestra=20el=20mensaje=20que=20se=20enviar=C3=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../code/schc_machines/lorawan/ack_on_error_sender.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py index 26be139..e43fb26 100644 --- a/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py +++ b/fragmentation_layer/code/schc_machines/lorawan/ack_on_error_sender.py @@ -103,7 +103,7 @@ def generate_message(self, mtu): self._logger_.schc_message(all1) return all1 regular_message.add_padding() - self._logger_.schc_message(regular_message) + #self._logger_.schc_message(regular_message) return regular_message def receive_schc_ack(self, schc_message): From 6864eaa5239064deae193240411273aab9f38b5d Mon Sep 17 00:00:00 2001 From: root Date: Mon, 12 Jul 2021 23:04:45 -0400 Subject: [PATCH 46/50] Migrate to The Things Network v3 --- .../code/schc_handlers/schc_gateway_handler.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py index 750b6e4..45ccd0a 100644 --- a/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py +++ b/fragmentation_layer/code/schc_handlers/schc_gateway_handler.py @@ -63,13 +63,13 @@ def handle(self, message, f_port=None, url=None, dev_id=None, api_key=None): if url is None: return response elif response is not None: - post_obj = { - "dev_id": dev_id, - "port": f_port, - "confirmed": False, - "payload_raw": base64.b64encode(response[1:]).decode("utf-8") + internal_obj = { + "f_port": f_port, + "priority": "NORMAL", + "frm_payload": base64.b64encode(response[1:]).decode("utf-8") } - headers = {'content-type': 'application/json','Authorization': api_key} + post_obj = {"downlinks":[internal_obj]} + headers = {'content-type': 'application/json','Authorization': 'Bearer {}'.format(api_key),'User-Agent':'myint'} r = requests.post(url, data=json.dumps(post_obj), headers=headers) def generate_message(self, rule_id, dtag, mtu=512): From d5d4e68551f928cfe4fd6d48c35cb49b5c88126a Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Wed, 14 Jul 2021 20:47:32 -0400 Subject: [PATCH 47/50] Refactor of old example and removal of tests --- README.md | 18 +- .../local}/common_methods.py | 246 +++++++++--------- .../{example => examples/local}/received.txt | 0 .../local}/test_receiver.py | 66 ++--- .../local}/test_sender.py | 148 +++++------ .../tests/test_base/__init__.py | 3 - .../tests/test_base/test_bitmap.py | 111 -------- .../tests/test_base/test_schc_object.py | 40 --- .../tests/test_header/__init__.py | 6 - .../tests/test_header/test_bitmap.py | 70 ----- .../tests/test_header/test_dtag.py | 59 ----- .../tests/test_header/test_fcn.py | 71 ----- .../tests/test_header/test_integrity_check.py | 42 --- .../tests/test_header/test_rcs.py | 33 --- .../tests/test_message/__init__.py | 1 - .../tests/test_message/test_all1_fragment.py | 132 ---------- .../test_message/test_regular_fragment.py | 129 --------- .../tests/test_parser/__init__.py | 1 - .../test_parser/test_parser_lo_ra_wan.py | 152 ----------- .../tests/test_protocols/__init__.py | 3 - .../test_protocols/test_schc_protocol.py | 88 ------- 21 files changed, 239 insertions(+), 1180 deletions(-) rename fragmentation_layer/{example => examples/local}/common_methods.py (95%) rename fragmentation_layer/{example => examples/local}/received.txt (100%) rename fragmentation_layer/{example => examples/local}/test_receiver.py (96%) rename fragmentation_layer/{example => examples/local}/test_sender.py (97%) delete mode 100644 fragmentation_layer/tests/test_base/__init__.py delete mode 100644 fragmentation_layer/tests/test_base/test_bitmap.py delete mode 100644 fragmentation_layer/tests/test_base/test_schc_object.py delete mode 100644 fragmentation_layer/tests/test_header/__init__.py delete mode 100644 fragmentation_layer/tests/test_header/test_bitmap.py delete mode 100644 fragmentation_layer/tests/test_header/test_dtag.py delete mode 100644 fragmentation_layer/tests/test_header/test_fcn.py delete mode 100644 fragmentation_layer/tests/test_header/test_integrity_check.py delete mode 100644 fragmentation_layer/tests/test_header/test_rcs.py delete mode 100644 fragmentation_layer/tests/test_message/__init__.py delete mode 100644 fragmentation_layer/tests/test_message/test_all1_fragment.py delete mode 100644 fragmentation_layer/tests/test_message/test_regular_fragment.py delete mode 100644 fragmentation_layer/tests/test_parser/__init__.py delete mode 100644 fragmentation_layer/tests/test_parser/test_parser_lo_ra_wan.py delete mode 100644 fragmentation_layer/tests/test_protocols/__init__.py delete mode 100644 fragmentation_layer/tests/test_protocols/test_schc_protocol.py diff --git a/README.md b/README.md index aed26b5..af67016 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,15 @@ Code of SCHC protocol implemented in Python to be loaded on a [PyCOM](https://py -## Fragmentation +## Fragmentation Layer -### On Local computer +### Example on local computer + +The following steps indicate how to run an example where the sender and the receiver are on the same machine and a message is sent with the `ACK-On-Error` mode specified in the LoRaWAN profile. A successful run means everything is working as intended. #### Installation -1. (Opcional) Create a new virtual environment to install Fragmentation package. +1. (Optional) Create a new virtual environment to install Fragmentation package. Using [`conda`](https://docs.conda.io/en/latest/): @@ -35,9 +37,7 @@ Code of SCHC protocol implemented in Python to be loaded on a [PyCOM](https://py .\niclabs-schc\env\Scripts\activate ```` -2. It is supposed that no package is needed, due to code is going to run on `LoPy`. Server side could have further requirements, but local example simulates Gateway/Node just using sockets. - -3. Install `fragmentation_layer` code on virtual environment +2. Install `fragmentation_layer` code on virtual environment ````bash cd fragmentation_layer/code @@ -53,12 +53,12 @@ Code of SCHC protocol implemented in Python to be loaded on a [PyCOM](https://py #### Execution of example -In two different terminal, one for the receiver and other for the sender. +Open two different terminals, one for the receiver and other for the sender. For the receiver (execute first): ````bash -cd example +cd examples/local python test_receiver.py # To save logs on a file @@ -68,7 +68,7 @@ python test_receiver.py 2> `` For the sender (execute in less than [`INACTIVITY_TIMER`](https://github.com/niclabs/PySCHC/blob/master/fragmentation_layer/code/schc_protocols/lorawan.py) seconds): ````bash -cd example +cd examples/local python test_sender.py # To save logs on a file diff --git a/fragmentation_layer/example/common_methods.py b/fragmentation_layer/examples/local/common_methods.py similarity index 95% rename from fragmentation_layer/example/common_methods.py rename to fragmentation_layer/examples/local/common_methods.py index 1004590..75c7bae 100644 --- a/fragmentation_layer/example/common_methods.py +++ b/fragmentation_layer/examples/local/common_methods.py @@ -1,123 +1,123 @@ -""" common_methods on example """ - -import random -import socket -from schc_machines import SCHCFiniteStateMachine - -HOST = "127.0.0.1" -MTU = 50 -SEED = 7 -PROBABILITY_OF_FAILURE = 0.2 - -random.seed(SEED) - - -def get_mtu() -> int: - """ - Get MTU size - - Returns - ------- - int : - MTU available - """ - return MTU - - -def is_this_loss() -> bool: - """ - Returns whether the send process was done - - Returns - ------- - bool : - True if sent does not occur - """ - return random.random() < PROBABILITY_OF_FAILURE - - -def send_socket(msg: bytes, port: int) -> None: - """ - Send using socket - - Parameters - ---------- - msg : bytes - Message to send - port : int - Port to use - - Returns - ------- - None, send message - """ - sock_tx = socket.socket() - sock_tx.connect((HOST, port)) - sock_tx.send(msg) - sock_tx.close() - return - - -def receive_socket(socket_rx: socket.socket) -> bytes: - """ - Receive from socket - - Parameters - ---------- - socket_rx : socket - Receiver socket - - Returns - ------- - bytes : - Message received - """ - conn, addr = socket_rx.accept() - data = conn.recv(1024) - return data - - -def messaging_loop(machine: SCHCFiniteStateMachine, socket_rx: socket.socket, sender_port: int) -> None: - """ - Loop of messages - - Parameters - ---------- - machine : SCHCFiniteStateMachine - Machine to execute on loop - socket_rx : socket - Socket of receiver - sender_port : int - Port to use to sent messages - - Returns - ------- - None - """ - while True: - mtu = get_mtu() - lost = is_this_loss() - try: - print("Sending...") - print("Messages enqueued: {}".format(machine.message_to_send)) - message = machine.generate_message(mtu) - print("Current mtu: {}".format(mtu)) - print("Package sent: {}".format(not lost)) - if isinstance(machine.state, SCHCFiniteStateMachine.EndState): - send_socket(message.as_bytes(), sender_port) - elif not lost and message is not None: - send_socket(message.as_bytes(), sender_port) - except SystemExit as e: - print(e) - break - try: - print("Receiving...") - data = receive_socket(socket_rx) - if data: - try: - machine.receive_message(data) - except SystemExit as e: - print(e) - break - except socket.timeout: - pass +""" common_methods on example """ + +import random +import socket +from schc_machines import SCHCFiniteStateMachine + +HOST = "127.0.0.1" +MTU = 50 +SEED = 7 +PROBABILITY_OF_FAILURE = 0.2 + +random.seed(SEED) + + +def get_mtu() -> int: + """ + Get MTU size + + Returns + ------- + int : + MTU available + """ + return MTU + + +def is_this_loss() -> bool: + """ + Returns whether the send process was done + + Returns + ------- + bool : + True if sent does not occur + """ + return random.random() < PROBABILITY_OF_FAILURE + + +def send_socket(msg: bytes, port: int) -> None: + """ + Send using socket + + Parameters + ---------- + msg : bytes + Message to send + port : int + Port to use + + Returns + ------- + None, send message + """ + sock_tx = socket.socket() + sock_tx.connect((HOST, port)) + sock_tx.send(msg) + sock_tx.close() + return + + +def receive_socket(socket_rx: socket.socket) -> bytes: + """ + Receive from socket + + Parameters + ---------- + socket_rx : socket + Receiver socket + + Returns + ------- + bytes : + Message received + """ + conn, addr = socket_rx.accept() + data = conn.recv(1024) + return data + + +def messaging_loop(machine: SCHCFiniteStateMachine, socket_rx: socket.socket, sender_port: int) -> None: + """ + Loop of messages + + Parameters + ---------- + machine : SCHCFiniteStateMachine + Machine to execute on loop + socket_rx : socket + Socket of receiver + sender_port : int + Port to use to sent messages + + Returns + ------- + None + """ + while True: + mtu = get_mtu() + lost = is_this_loss() + try: + print("Sending...") + print("Messages enqueued: {}".format(machine.message_to_send)) + message = machine.generate_message(mtu) + print("Current mtu: {}".format(mtu)) + print("Package sent: {}".format(not lost)) + if isinstance(machine.state, SCHCFiniteStateMachine.EndState): + send_socket(message.as_bytes(), sender_port) + elif not lost and message is not None: + send_socket(message.as_bytes(), sender_port) + except SystemExit as e: + print(e) + break + try: + print("Receiving...") + data = receive_socket(socket_rx) + if data: + try: + machine.receive_message(data) + except SystemExit as e: + print(e) + break + except socket.timeout: + pass diff --git a/fragmentation_layer/example/received.txt b/fragmentation_layer/examples/local/received.txt similarity index 100% rename from fragmentation_layer/example/received.txt rename to fragmentation_layer/examples/local/received.txt diff --git a/fragmentation_layer/example/test_receiver.py b/fragmentation_layer/examples/local/test_receiver.py similarity index 96% rename from fragmentation_layer/example/test_receiver.py rename to fragmentation_layer/examples/local/test_receiver.py index 8dac5db..9186b6f 100644 --- a/fragmentation_layer/example/test_receiver.py +++ b/fragmentation_layer/examples/local/test_receiver.py @@ -1,33 +1,33 @@ -""" test_receiver: Test script Receiver side""" - -import logging -import socket -from common_methods import messaging_loop, HOST - -RECEIVER_PORT = 50006 -SENDER_PORT = 50007 - -socket_rx = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -socket_rx.settimeout(2) -socket_rx.bind((HOST, RECEIVER_PORT)) -socket_rx.listen(1) - - -if __name__ == '__main__': - from schc_machines.lorawan import AckOnErrorReceiver - from schc_protocols import LoRaWAN - - receiver = AckOnErrorReceiver( - LoRaWAN(LoRaWAN.ACK_ON_ERROR), - on_success=print - ) - - messaging_loop(receiver, socket_rx, SENDER_PORT) - - packet = receiver.payload.as_bits() - assert len(packet) % 8 == 0 - - from schc_base import SCHCObject - message = SCHCObject.bits_2_bytes(packet) - with open("received.txt", "w", encoding="utf-8") as received_file: - received_file.write(message.decode("ascii")) +""" test_receiver: Test script Receiver side""" + +import logging +import socket +from common_methods import messaging_loop, HOST + +RECEIVER_PORT = 50006 +SENDER_PORT = 50007 + +socket_rx = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +socket_rx.settimeout(2) +socket_rx.bind((HOST, RECEIVER_PORT)) +socket_rx.listen(1) + + +if __name__ == '__main__': + from schc_machines.lorawan import AckOnErrorReceiver + from schc_protocols import LoRaWAN + + receiver = AckOnErrorReceiver( + LoRaWAN(LoRaWAN.ACK_ON_ERROR), + on_success=print + ) + + messaging_loop(receiver, socket_rx, SENDER_PORT) + + packet = receiver.payload.as_bits() + assert len(packet) % 8 == 0 + + from schc_base import SCHCObject + message = SCHCObject.bits_2_bytes(packet) + with open("received.txt", "w", encoding="utf-8") as received_file: + received_file.write(message.decode("ascii")) diff --git a/fragmentation_layer/example/test_sender.py b/fragmentation_layer/examples/local/test_sender.py similarity index 97% rename from fragmentation_layer/example/test_sender.py rename to fragmentation_layer/examples/local/test_sender.py index c302140..ba35268 100644 --- a/fragmentation_layer/example/test_sender.py +++ b/fragmentation_layer/examples/local/test_sender.py @@ -1,74 +1,74 @@ -""" test_sender: Test script Sender side""" - -import logging -import socket - -from common_methods import messaging_loop, HOST - -RECEIVER_PORT = 50007 -SENDER_PORT = 50006 - -MESSAGE = """ -Abstract - - The Static Context Header Compression (SCHC) specification describes - generic header compression and fragmentation techniques for Low Power - Wide Area Networks (LPWAN) technologies. SCHC is a generic mechanism - designed for great flexibility so that it can be adapted for any of - the LPWAN technologies. - - This document specifies a profile of RFC8724 to use SCHC in - LoRaWAN(R) networks, and provides elements such as efficient - parameterization and modes of operation. - -Status of This Memo - - This Internet-Draft is submitted in full conformance with the - provisions of BCP 78 and BCP 79. - - Internet-Drafts are working documents of the Internet Engineering - Task Force (IETF). Note that other groups may also distribute - working documents as Internet-Drafts. The list of current Internet- - Drafts is at https://datatracker.ietf.org/drafts/current/. - - Internet-Drafts are draft documents valid for a maximum of six months - and may be updated, replaced, or obsoleted by other documents at any - time. It is inappropriate to use Internet-Drafts as reference - material or to cite them other than as "work in progress." - - This Internet-Draft will expire on July 29, 2021. - -Copyright Notice - - Copyright (c) 2021 IETF Trust and the persons identified as the - document authors. All rights reserved. - - This document is subject to BCP 78 and the IETF Trust's Legal - Provisions Relating to IETF Documents - (https://trustee.ietf.org/license-info) in effect on the date of - publication of this document. Please review these documents - carefully, as they describe your rights and restrictions with respect - to this document. Code Components extracted from this document must - include Simplified BSD License text as described in Section 4.e of - the Trust Legal Provisions and are provided without warranty as - described in the Simplified BSD License. -""".encode("ascii") - -RESIDUE = "0101100" - -socket_rx = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -socket_rx.settimeout(1) -socket_rx.bind((HOST, RECEIVER_PORT)) -socket_rx.listen(1) - - -if __name__ == '__main__': - from schc_machines.lorawan import AckOnErrorSender - from schc_protocols import LoRaWAN - - sender = AckOnErrorSender( - LoRaWAN(LoRaWAN.ACK_ON_ERROR), - MESSAGE - ) - - messaging_loop(sender, socket_rx, SENDER_PORT) +""" test_sender: Test script Sender side""" + +import logging +import socket + +from common_methods import messaging_loop, HOST + +RECEIVER_PORT = 50007 +SENDER_PORT = 50006 + +MESSAGE = """ +Abstract + + The Static Context Header Compression (SCHC) specification describes + generic header compression and fragmentation techniques for Low Power + Wide Area Networks (LPWAN) technologies. SCHC is a generic mechanism + designed for great flexibility so that it can be adapted for any of + the LPWAN technologies. + + This document specifies a profile of RFC8724 to use SCHC in + LoRaWAN(R) networks, and provides elements such as efficient + parameterization and modes of operation. + +Status of This Memo + + This Internet-Draft is submitted in full conformance with the + provisions of BCP 78 and BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF). Note that other groups may also distribute + working documents as Internet-Drafts. The list of current Internet- + Drafts is at https://datatracker.ietf.org/drafts/current/. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + This Internet-Draft will expire on July 29, 2021. + +Copyright Notice + + Copyright (c) 2021 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. +""".encode("ascii") + +RESIDUE = "0101100" + +socket_rx = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +socket_rx.settimeout(1) +socket_rx.bind((HOST, RECEIVER_PORT)) +socket_rx.listen(1) + + +if __name__ == '__main__': + from schc_machines.lorawan import AckOnErrorSender + from schc_protocols import LoRaWAN + + sender = AckOnErrorSender( + LoRaWAN(LoRaWAN.ACK_ON_ERROR), + MESSAGE + ) + + messaging_loop(sender, socket_rx, SENDER_PORT) diff --git a/fragmentation_layer/tests/test_base/__init__.py b/fragmentation_layer/tests/test_base/__init__.py deleted file mode 100644 index 21e635d..0000000 --- a/fragmentation_layer/tests/test_base/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -""" test of schc_base package """ - -from test_base.test_schc_object import SCHCObjectTest diff --git a/fragmentation_layer/tests/test_base/test_bitmap.py b/fragmentation_layer/tests/test_base/test_bitmap.py deleted file mode 100644 index 7673826..0000000 --- a/fragmentation_layer/tests/test_base/test_bitmap.py +++ /dev/null @@ -1,111 +0,0 @@ -""" test_bitmap: Unit test for Bitmap class """ - -from unittest import TestCase, main -from schc_base import Bitmap -from schc_protocols import LoRaWAN - - -class TestBitmap(TestCase): - - def test_constructor(self): - bitmap = Bitmap(LoRaWAN(rule_id=LoRaWAN.ACK_ON_ERROR)) - self.assertEqual([False] * LoRaWAN(rule_id=LoRaWAN.ACK_ON_ERROR).WINDOW_SIZE, bitmap.__bitmap__, - "Wrong bitmap generated") - self.assertEqual(LoRaWAN(rule_id=LoRaWAN.ACK_ON_ERROR).WINDOW_SIZE, len(bitmap.__bitmap__), "Wrong length of bitmap") - bitmap = Bitmap(LoRaWAN(rule_id=LoRaWAN.ACK_ON_ERROR), short_size=10) - self.assertEqual([False] * 10, bitmap.__bitmap__, "Wrong bitmap generated (short)") - self.assertEqual(10, len(bitmap.__bitmap__), "Wrong length of bitmap (short)") - - def test_register_tile(self): - bitmap = Bitmap(LoRaWAN(rule_id=LoRaWAN.ACK_ON_ERROR)) - bitmap.tile_received(LoRaWAN(rule_id=LoRaWAN.ACK_ON_ERROR).WINDOW_SIZE - 1) - self.assertTrue(bitmap.__bitmap__[0], "Wrong first tile registered") - fcn = 30 - bitmap.tile_received(fcn) - self.assertTrue(bitmap.__bitmap__[LoRaWAN(rule_id=LoRaWAN.ACK_ON_ERROR).WINDOW_SIZE - fcn - 1], - "Wrong tile registered {}".format(fcn)) - bitmap.tile_received(0) - self.assertTrue(bitmap.__bitmap__[LoRaWAN(rule_id=LoRaWAN.ACK_ON_ERROR).WINDOW_SIZE - 1], - "Wrong last tile registered") - self.assertEqual(LoRaWAN(rule_id=LoRaWAN.ACK_ON_ERROR).WINDOW_SIZE, len(bitmap.__bitmap__), - "Length changed") - self.assertEqual(3, sum(bitmap.__bitmap__), "Wrong registration") - - def test_compression_all_one(self): - protocol_to_use = LoRaWAN(rule_id=LoRaWAN.ACK_ON_ERROR) - bitmap = Bitmap(protocol_to_use) - bitmap.__bitmap__ = [True] * protocol_to_use.WINDOW_SIZE - compressed_bitmap = bitmap.generate_compress() - self.assertEqual( - protocol_to_use.L2_WORD - (sum([ - protocol_to_use.RULE_SIZE, protocol_to_use.T, protocol_to_use.M, 1 - ]) % protocol_to_use.L2_WORD), - len(compressed_bitmap), "Wrong compression") - self.assertEqual( - protocol_to_use.L2_WORD - (sum([ - protocol_to_use.RULE_SIZE, protocol_to_use.T, protocol_to_use.M, 1 - ]) % protocol_to_use.L2_WORD), - sum(compressed_bitmap), "Wrong compression") - - def test_compression_uncompressed(self): - protocol_to_use = LoRaWAN(rule_id=LoRaWAN.ACK_ON_ERROR) - bitmap = Bitmap(protocol_to_use) - compressed_bitmap = bitmap.generate_compress() - self.assertEqual(protocol_to_use.WINDOW_SIZE, len(compressed_bitmap), "Wrong compression") - self.assertEqual(0, sum(compressed_bitmap), "Wrong compression") - - def test_compression(self): - protocol_to_use = LoRaWAN(rule_id=LoRaWAN.ACK_ON_ERROR) - bitmap = Bitmap(protocol_to_use) - bitmap.__bitmap__ = [True] * protocol_to_use.WINDOW_SIZE - bitmap.__bitmap__[protocol_to_use.L2_WORD] = False - compressed_bitmap = bitmap.generate_compress() - self.assertEqual( - protocol_to_use.L2_WORD - (sum([ - protocol_to_use.RULE_SIZE, protocol_to_use.T, - protocol_to_use.M, 1 - ]) % protocol_to_use.L2_WORD) + protocol_to_use.L2_WORD, - len(compressed_bitmap), "Wrong compression") - self.assertEqual( - protocol_to_use.L2_WORD - (sum([ - protocol_to_use.RULE_SIZE, protocol_to_use.T, protocol_to_use.M, 1 - ]) % protocol_to_use.L2_WORD) + protocol_to_use.L2_WORD - 1, - sum(compressed_bitmap), "Wrong compression") - - def test_has_missing(self): - protocol = LoRaWAN(LoRaWAN.ACK_ON_ERROR) - bitmap = Bitmap(protocol) - self.assertFalse(bitmap.has_missing(), "Bitmap full False has missing") - bitmap.tile_received(protocol.WINDOW_SIZE - 1) - self.assertFalse(bitmap.has_missing(), "Bitmap first one has missing") - for i in range(5): - bitmap.tile_received(protocol.WINDOW_SIZE - (i + 2)) - self.assertFalse(bitmap.has_missing(), "Bitmap first ones has missing") - for i in range(5): - bitmap.tile_received(protocol.WINDOW_SIZE - (i + 10)) - self.assertTrue(bitmap.has_missing(), "Bitmap has missing not reported") - for i in range(5): - bitmap.tile_received(protocol.WINDOW_SIZE - (i + 20)) - self.assertTrue(bitmap.has_missing(), "Bitmap has missing not reported (second case)") - for i in range(protocol.WINDOW_SIZE): - bitmap.tile_received(protocol.WINDOW_SIZE - (i + 1)) - self.assertFalse(bitmap.has_missing(), "Bitmap full True has missing") - - def test_get_missing(self): - protocol = LoRaWAN(LoRaWAN.ACK_ON_ERROR) - bitmap = Bitmap(protocol) - self.assertEqual(0, bitmap.get_missing(), "fcn = False, after = None") - bitmap.tile_received(protocol.WINDOW_SIZE - 5) # 63 - 5 = 58, index = 4 - self.assertEqual(0, bitmap.get_missing(), "fcn = False, after = None (with one tile)") - self.assertEqual(7, bitmap.get_missing(after=6), "fcn = False, after = 6 (with one tile)") - self.assertEqual(56, bitmap.get_missing(fcn=True, after=57), "fcn = True, after = 57 (with one tile)") - for i in range(5): - bitmap.tile_received(protocol.WINDOW_SIZE - (i + 1)) - self.assertEqual(5, bitmap.get_missing(), "fcn = False, after = None (with six tiles)") - self.assertEqual(57, bitmap.get_missing(fcn=True), "fcn = True, after = None (with six tiles)") - self.assertEqual(5, bitmap.get_missing(after=4), "fcn = False, after = 4 (with one tile)") - self.assertEqual(57, bitmap.get_missing(fcn=True, after=62), "fcn = True, after = 55 (with one tile)") - - -if __name__ == '__main__': - main() diff --git a/fragmentation_layer/tests/test_base/test_schc_object.py b/fragmentation_layer/tests/test_base/test_schc_object.py deleted file mode 100644 index 0a17ea2..0000000 --- a/fragmentation_layer/tests/test_base/test_schc_object.py +++ /dev/null @@ -1,40 +0,0 @@ -""" test_schc_object: Unit testing of SCHCObject static methods """ - -from unittest import TestCase, main -from schc_base import SCHCObject - - -class SCHCObjectTest(TestCase): - - def test_bits_2_bytes(self): - actual = SCHCObject.bits_2_bytes("01001000") - expected = b'H' - self.assertEqual(expected, actual, "H wrong decoded") - hello = "01001000" + "01100101" + "01101100" + "01101100" + "01101111" - actual = SCHCObject.bits_2_bytes(hello) - expected = b'Hello' - self.assertEqual(expected, actual, "H wrong decoded") - actual = SCHCObject.bits_2_bytes("1001000") - expected = b'H' - self.assertEqual(expected, actual, "H wrong decoded") - actual = SCHCObject.bits_2_bytes("1001") - expected = b'\t' - self.assertEqual(expected, actual, "\\t character wrong decoded") - actual = SCHCObject.bits_2_bytes("1001") - expected = SCHCObject.bits_2_bytes("00001001") - self.assertEqual(expected, actual, "\\t character wrong decoded") - - def test_bytes_2_bits(self): - actual = SCHCObject.bytes_2_bits(b'Hello') - expected = "01001000" + "01100101" + "01101100" + "01101100" + "01101111" - self.assertEqual(expected, actual, "Hello wrong encoded") - actual = SCHCObject.bytes_2_bits(b'a') - expected = "01100001" - self.assertEqual(expected, actual, "Letter a wrong encoded") - actual = SCHCObject.bytes_2_bits(b'1') - expected = "00110001" - self.assertEqual(expected, actual, "Number 1 wrong encoded") - - -if __name__ == '__main__': - main() diff --git a/fragmentation_layer/tests/test_header/__init__.py b/fragmentation_layer/tests/test_header/__init__.py deleted file mode 100644 index 66966c2..0000000 --- a/fragmentation_layer/tests/test_header/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -""" test of schc_header package """ - -from test_header.test_bitmap import TestCompressedBitmap -from test_header.test_dtag import TestDTag -from test_header.test_fcn import TestFragmentCompressedNumber -from test_header.test_rcs import TestRCS diff --git a/fragmentation_layer/tests/test_header/test_bitmap.py b/fragmentation_layer/tests/test_header/test_bitmap.py deleted file mode 100644 index 27fa381..0000000 --- a/fragmentation_layer/tests/test_header/test_bitmap.py +++ /dev/null @@ -1,70 +0,0 @@ -"""test_bitmap: Compressed Bitmap Unit Test""" - -from unittest import TestCase, main -from schc_messages.schc_header import CompressedBitmap - - -class TestCompressedBitmap(TestCase): - - def setUp(self) -> None: - """ - Sets up unit test - - Returns - ------- - None - """ - self.bitmap = CompressedBitmap([True, False, False, True], 4) - self.un_bitmap = CompressedBitmap([True, False], 5) - self.empty_bitmap = CompressedBitmap([], 0) - - def test_wrong_bitmap_size(self) -> None: - self.assertRaises(AssertionError, CompressedBitmap, [True] * 10, 8) - - def test_fill_up(self) -> None: - self.assertEqual(2, len(self.un_bitmap.bitmap), "Filled up length wrong") - self.assertEqual( - [True, False], - self.un_bitmap.bitmap, - "Filled up values wrong" - ) - - def test_size(self) -> None: - self.assertEqual(4, self.bitmap.size, "Wrong Size of Bitmap") - self.assertEqual(4, self.bitmap.window_size, "Wrong Window Size of Bitmap") - self.assertEqual(2, self.un_bitmap.size, "Wrong Size of Filled up Bitmap") - self.assertEqual(5, self.un_bitmap.window_size, "Wrong Window Size of Filled up Bitmap") - self.assertEqual(0, self.empty_bitmap.size, "Wrong Size of Empty Bitmap") - self.assertEqual(0, self.empty_bitmap.window_size, "Wrong Window Size of Empty Bitmap") - - def test_as_bits(self) -> None: - self.assertEqual("1001", self.bitmap.as_bits(), "Bitmap bits wrong mapped") - self.assertEqual("10", self.un_bitmap.as_bits(), "Filled Up Bitmap bits wrong mapped") - self.assertEqual("", self.empty_bitmap.as_bits(), "Empty Bitmap bits wrong mapped") - - def test_format_text(self) -> None: - self.assertEqual( - ("", " Compressed Bitmap ", "1001 "), - self.bitmap.format_text(), - "Wrong text generated for Bitmap" - ) - self.assertEqual( - ("", " Compressed Bitmap ", "10 "), - self.un_bitmap.format_text(), - "Wrong text generated for Filled up Bitmap" - ) - self.assertEqual( - ("", "", ""), - self.empty_bitmap.format_text(), - "Wrong text generated for Empty Bitmap" - ) - giant_bitmap = CompressedBitmap([True] * 25, 25) - self.assertEqual( - ("", " Compressed Bitmap ", "1"*25), - giant_bitmap.format_text(), - "Wrong text generated for Empty Bitmap" - ) - - -if __name__ == '__main__': - main() diff --git a/fragmentation_layer/tests/test_header/test_dtag.py b/fragmentation_layer/tests/test_header/test_dtag.py deleted file mode 100644 index 9793f16..0000000 --- a/fragmentation_layer/tests/test_header/test_dtag.py +++ /dev/null @@ -1,59 +0,0 @@ -"""test_dtag: DTag Unit Test""" - -from unittest import TestCase, main -from schc_messages.schc_header import DTag - - -class TestDTag(TestCase): - - def setUp(self) -> None: - """ - Sets up unit test - - Returns - ------- - None - """ - self.dtag = DTag(1, 2) - self.giant_dtag = DTag(20, 8) - self.empty_dtag = DTag(1502, 0) - - def test_size(self) -> None: - self.assertEqual(2, self.dtag.size, "Wrong Size of DTag") - self.assertEqual(2, self.dtag.t, "T Size of DTag") - self.assertEqual(8, self.giant_dtag.size, "Wrong Size of Giant DTag") - self.assertEqual(8, self.giant_dtag.t, "T Size of Giant Bitmap") - self.assertEqual(0, self.empty_dtag.size, "Wrong Size of Empty DTag") - self.assertEqual(0, self.empty_dtag.t, "T Size of Empty DTag") - - def test_as_bits(self) -> None: - self.assertEqual("01", self.dtag.as_bits(), "DTag bits wrong mapped") - self.assertEqual("00010100", self.giant_dtag.as_bits(), "Giant DTag bits wrong mapped") - self.assertEqual("", self.empty_dtag.as_bits(), "Empty DTag bits wrong mapped") - - def test_format_text(self) -> None: - self.assertEqual( - (" T=2 ", " DTag ", "01 "), - self.dtag.format_text(), - "Wrong text generated for DTag" - ) - self.assertEqual( - (" T=8 ", " DTag ", "00010100"), - self.giant_dtag.format_text(), - "Wrong text generated for Giant DTag" - ) - self.assertEqual( - ("", "", ""), - self.empty_dtag.format_text(), - "Wrong text generated for Empty DTag" - ) - more_giant_dtag = DTag(456, 20) - self.assertEqual( - (" T=20 ", " DTag ", "00000000000111001000"), - more_giant_dtag.format_text(), - "Wrong text generated for Really Giant DTag" - ) - - -if __name__ == '__main__': - main() diff --git a/fragmentation_layer/tests/test_header/test_fcn.py b/fragmentation_layer/tests/test_header/test_fcn.py deleted file mode 100644 index d75de81..0000000 --- a/fragmentation_layer/tests/test_header/test_fcn.py +++ /dev/null @@ -1,71 +0,0 @@ -"""test_fcn: Fragment Compressed Number Unit Test""" - -from unittest import TestCase, main -from schc_messages.schc_header import FragmentedCompressedNumber - - -class TestFragmentCompressedNumber(TestCase): - - def setUp(self) -> None: - """ - Sets up unit test - - Returns - ------- - None - """ - self.fcn = FragmentedCompressedNumber(56, 6) - self.giant_fcn = FragmentedCompressedNumber(185, 10) - self.mini_fcn = FragmentedCompressedNumber(0, 2) - self.empty_fcn = FragmentedCompressedNumber(0, 0) - - def test_wrong_fcn_size(self) -> None: - self.assertRaises(AssertionError, FragmentedCompressedNumber, 64, 6) - - def test_size(self) -> None: - self.assertEqual(6, self.fcn.size, "Wrong Size of FCN") - self.assertEqual(6, self.fcn.n, "N Size of FCN") - self.assertEqual(10, self.giant_fcn.size, "Wrong Size of Giant FCN") - self.assertEqual(10, self.giant_fcn.n, "N Size of Giant FCN") - self.assertEqual(2, self.mini_fcn.size, "Wrong Size of Mini FCN") - self.assertEqual(2, self.mini_fcn.n, "N Size of Mini FCN") - self.assertEqual(0, self.empty_fcn.size, "Wrong Size of Empty FCN") - self.assertEqual(0, self.empty_fcn.n, "N Size of Empty FCN") - - def test_as_bits(self) -> None: - self.assertEqual("111000", self.fcn.as_bits(), "FCN bits wrong mapped") - self.assertEqual("0010111001", self.giant_fcn.as_bits(), "Giant FCN bits wrong mapped") - self.assertEqual("00", self.mini_fcn.as_bits(), "Mini FCN bits wrong mapped") - self.assertEqual("", self.empty_fcn.as_bits(), "Empty FCN bits wrong mapped") - - def test_format_text(self) -> None: - self.assertEqual( - ("--- N=6 ---", " FCN ", "111000 "), - self.fcn.format_text(), - "Wrong text generated for FCN" - ) - self.assertEqual( - ("--- N=10 ---", " FCN ", "0010111001 "), - self.giant_fcn.format_text(), - "Wrong text generated for Giant FCN" - ) - self.assertEqual( - ("--- N=2 ---", " FCN ", "00 "), - self.mini_fcn.format_text(), - "Wrong text generated for Mini FCN" - ) - self.assertEqual( - ("", "", ""), - self.empty_fcn.format_text(), - "Wrong text generated for Empty FCN" - ) - more_giant_fcn = FragmentedCompressedNumber(185, 13) - self.assertEqual( - ("--- N=13 ---", " FCN ", "0000010111001"), - more_giant_fcn.format_text(), - "Wrong text generated for Really Giant FCN" - ) - - -if __name__ == '__main__': - main() diff --git a/fragmentation_layer/tests/test_header/test_integrity_check.py b/fragmentation_layer/tests/test_header/test_integrity_check.py deleted file mode 100644 index 7c04995..0000000 --- a/fragmentation_layer/tests/test_header/test_integrity_check.py +++ /dev/null @@ -1,42 +0,0 @@ -"""test_integrity_check: Integrity Check Unit Test""" - -from unittest import TestCase, main -from schc_messages.schc_header import IntegrityCheck - - -class TestIntegrityCheck(TestCase): - - def setUp(self) -> None: - """ - Sets up unit test - - Returns - ------- - None - """ - self.c = IntegrityCheck(True) - self.not_c = IntegrityCheck(False) - - def test_size(self) -> None: - self.assertEqual(1, self.c.size, "Wrong Size of IC") - self.assertEqual(1, self.not_c.size, "Wrong Size of Not IC") - - def test_as_bits(self) -> None: - self.assertEqual("1", self.c.as_bits(), "IC bits wrong mapped") - self.assertEqual("0", self.not_c.as_bits(), "Not IC bits wrong mapped") - - def test_format_text(self) -> None: - self.assertEqual( - (" 1 ", " C ", " 1 "), - self.c.format_text(), - "Wrong text generated for IC" - ) - self.assertEqual( - (" 1 ", " C ", " 0 "), - self.not_c.format_text(), - "Wrong text generated for Not IC" - ) - - -if __name__ == '__main__': - main() diff --git a/fragmentation_layer/tests/test_header/test_rcs.py b/fragmentation_layer/tests/test_header/test_rcs.py deleted file mode 100644 index 1b7c898..0000000 --- a/fragmentation_layer/tests/test_header/test_rcs.py +++ /dev/null @@ -1,33 +0,0 @@ -"""test_rcs: Reassembly Check Sequence Unit Test""" - -from unittest import TestCase, main -from schc_messages.schc_header import ReassemblyCheckSequence - - -class TestRCS(TestCase): - - def setUp(self) -> None: - """ - Sets up unit test - - Returns - ------- - None - """ - # self.rcs = ReassemblyCheckSequence() - - def test_wrong_fcn_size(self) -> None: - self.assertTrue(True) - - def test_size(self) -> None: - self.assertTrue(True) - - def test_as_bits(self) -> None: - self.assertTrue(True) - - def test_format_text(self) -> None: - self.assertTrue(True) - - -if __name__ == '__main__': - main() diff --git a/fragmentation_layer/tests/test_message/__init__.py b/fragmentation_layer/tests/test_message/__init__.py deleted file mode 100644 index 73bb6db..0000000 --- a/fragmentation_layer/tests/test_message/__init__.py +++ /dev/null @@ -1 +0,0 @@ -""" test of schc_message package """ diff --git a/fragmentation_layer/tests/test_message/test_all1_fragment.py b/fragmentation_layer/tests/test_message/test_all1_fragment.py deleted file mode 100644 index 467f762..0000000 --- a/fragmentation_layer/tests/test_message/test_all1_fragment.py +++ /dev/null @@ -1,132 +0,0 @@ -""" test_all1_fragment: All1SCHCFragment Unit test """ - -from unittest import TestCase, main -from schc_messages import All1SCHCFragment -from schc_base import Tile -from schc_protocols import SCHCProtocol - - -class TestAll1Fragment(TestCase): - - def setUp(self) -> None: - """ - Sets up unit test - - Returns - ------- - None - """ - self.all1 = All1SCHCFragment(20, protocol=SCHCProtocol.LoRaWAN, - dtag=4, w=2, rcs='0xacde3214') - - def test_base(self) -> None: - self.assertEqual(48, self.all1.size, "Wrong size on initialization") - self.assertEqual(0, self.all1.payload.size, "Payload present before added") - self.assertEqual(0, self.all1.padding.size, "Padding present before added") - self.assertEqual(48, self.all1.header.size, "Header size incorrect") - self.assertEqual(8, self.all1.header.rule_id.size, "Wrong RuleID size") - self.assertEqual(0, self.all1.header.dtag.size, "Wrong DTag size") - self.assertEqual(2, self.all1.header.w.size, "Wrong W size") - self.assertEqual(6, self.all1.header.fcn.size, "Wrong FCN size") - self.assertEqual(32, self.all1.header.rcs.size, "Wrong RCS size") - self.assertEqual(0, self.all1.header.c.size, "Wrong IC size") - self.assertEqual(0, self.all1.header.compressed_bitmap.size, "Wrong Bitmap size") - - def test_add_tile(self) -> None: - self.assertEqual(0, self.all1.payload.size, "Payload prior initialization") - init_size = self.all1.size - first_tile = Tile(b'Hello') - second_tile = Tile(b' ') - third_tile = Tile(b'World!') - payload_size = self.all1.add_tile(first_tile) - self.assertEqual(payload_size - init_size, first_tile.size, "First tile size got wrong (on return)") - self.assertEqual(payload_size - init_size, self.all1.payload.size, "First tile size got wrong (on instance)") - self.assertEqual(payload_size, self.all1.size, "Size got wrong (first)") - payload_size = self.all1.add_tile(second_tile) - self.assertEqual(payload_size - init_size, first_tile.size + second_tile.size, - "Second tile size got wrong (on return)") - self.assertEqual(payload_size - init_size, self.all1.payload.size, "Second tile size got wrong (on instance)") - self.assertEqual(payload_size, self.all1.size, "Size got wrong (second)") - payload_size = self.all1.add_tile(third_tile) - self.assertEqual(payload_size - init_size, first_tile.size + second_tile.size + third_tile.size, - "Third tile size got wrong (on return)") - self.assertEqual(payload_size - init_size, self.all1.payload.size, "Third tile size got wrong (on instance)") - self.assertEqual(payload_size, self.all1.size, "Size got wrong (third)") - - def test_add_padding(self) -> None: - self.assertEqual(0, self.all1.padding.size, "Pad added (on init)") - size = self.all1.add_padding() - self.assertEqual(48, size, "Pad added (on return)") - self.assertEqual(48, self.all1.size, "Pad added (on instance)") - self.assertEqual(0, self.all1.padding.size, "Pad added (on padding)") - payload_size = self.all1.add_tile(Tile(b'Hello')) - self.assertEqual(48, size, "Pad added (on return)") - self.assertEqual(payload_size, self.all1.size, "Pad added (on instance)") - self.assertEqual(0, self.all1.padding.size, "Pad added (on padding)") - - def test_as_bits(self) -> None: - self.assertEqual( - "000101001011111110101100110111100011001000010100", - self.all1.as_bits(), - "Just header got wrong" - ) - self.all1.add_tile(Tile(b'Hello')) - self.all1.add_padding() - self.assertEqual( - "0001010010111111101011001101111000110010000101000100100001100101011011000110110001101111", - self.all1.as_bits(), - "Message got wrong" - ) - - def test_as_bytes(self) -> None: - self.assertEqual( - (b'\x14', b'\xbf\xac\xde2\x14'), - self.all1.as_bytes(), - "Just header got wrong" - ) - self.all1.add_tile(Tile(b'Hello')) - self.all1.add_padding() - self.assertEqual( - (b'\x14', b'\xbf\xac\xde2\x14Hello'), - self.all1.as_bytes(), - "Message got wrong" - ) - - def test_as_text(self) -> None: - self.assertEqual( - "|--- SCHC Fragment Header ---|\n" + - " |-- M=2 --|--- N=6 ---| U=32 |\n" + - "| RuleID | W | FCN | RCS |\n" + - "|00010100|10 |111111 |10101100110111100011001000010100|", - self.all1.as_text(), - "Just header got wrong" - ) - self.all1.add_tile(Tile(b'Hello')) - self.all1.add_padding() - self.assertEqual( - "|--- SCHC Fragment Header ---|\n" + - " |-- M=2 --|--- N=6 ---| U=32 |\n" + - "| RuleID | W | FCN | RCS |" + - " Fragment Payload |\n" + - "|00010100|10 |111111 |10101100110111100011001000010100|" + - "0100100001100101011011000110110001101111|", - self.all1.as_text(), - "Message got wrong" - ) - - def test_from_bytes(self) -> None: - all1 = All1SCHCFragment.from_bytes(b'\x14\xbf\xac\xde2\x14Hello') - self.assertEqual( - "|--- SCHC Fragment Header ---|\n" + - " |-- M=2 --|--- N=6 ---| U=32 |\n" + - "| RuleID | W | FCN | RCS |" + - " Fragment Payload |\n" + - "|00010100|10 |111111 |10101100110111100011001000010100|" + - "0100100001100101011011000110110001101111|", - all1.as_text(), - "Message parsed wrong" - ) - - -if __name__ == '__main__': - main() diff --git a/fragmentation_layer/tests/test_message/test_regular_fragment.py b/fragmentation_layer/tests/test_message/test_regular_fragment.py deleted file mode 100644 index a00a02e..0000000 --- a/fragmentation_layer/tests/test_message/test_regular_fragment.py +++ /dev/null @@ -1,129 +0,0 @@ -""" test_regular_fragment: RegularSCHCFragment Unit test """ - -from unittest import TestCase, main -from schc_messages import RegularSCHCFragment -from schc_base import Tile -from schc_protocols import SCHCProtocol - - -class TestRegularFragment(TestCase): - - def setUp(self) -> None: - """ - Sets up unit test - - Returns - ------- - None - """ - self.regular = RegularSCHCFragment(20, protocol=SCHCProtocol.LoRaWAN, - dtag=4, w=3, fcn=17) - - def test_base(self) -> None: - self.assertEqual(16, self.regular.size, "Wrong size on initialization") - self.assertEqual(0, self.regular.payload.size, "Payload present before added") - self.assertEqual(0, self.regular.padding.size, "Padding present before added") - self.assertEqual(16, self.regular.header.size, "Header size incorrect") - self.assertEqual(8, self.regular.header.rule_id.size, "Wrong RuleID size") - self.assertEqual(0, self.regular.header.dtag.size, "Wrong DTag size") - self.assertEqual(2, self.regular.header.w.size, "Wrong W size") - self.assertEqual(6, self.regular.header.fcn.size, "Wrong FCN size") - self.assertEqual(0, self.regular.header.rcs.size, "Wrong RCS size") - self.assertEqual(0, self.regular.header.c.size, "Wrong IC size") - self.assertEqual(0, self.regular.header.compressed_bitmap.size, "Wrong Bitmap size") - - def test_add_tile(self) -> None: - self.assertEqual(0, self.regular.payload.size, "Payload prior initialization") - init_size = self.regular.size - first_tile = Tile(b'Hello') - second_tile = Tile(b' ') - third_tile = Tile(b'World!') - payload_size = self.regular.add_tile(first_tile) - self.assertEqual(payload_size - init_size, first_tile.size, "First tile size got wrong (on return)") - self.assertEqual(payload_size - init_size, self.regular.payload.size, "First tile size got wrong (on instance)") - self.assertEqual(payload_size, self.regular.size, "Size got wrong (first)") - payload_size = self.regular.add_tile(second_tile) - self.assertEqual(payload_size - init_size, first_tile.size + second_tile.size, "Second tile size got wrong (on return)") - self.assertEqual(payload_size - init_size, self.regular.payload.size, "Second tile size got wrong (on instance)") - self.assertEqual(payload_size, self.regular.size, "Size got wrong (second)") - payload_size = self.regular.add_tile(third_tile) - self.assertEqual(payload_size - init_size, first_tile.size + second_tile.size + third_tile.size, - "Third tile size got wrong (on return)") - self.assertEqual(payload_size - init_size, self.regular.payload.size, "Third tile size got wrong (on instance)") - self.assertEqual(payload_size, self.regular.size, "Size got wrong (third)") - - def test_add_padding(self) -> None: - self.assertEqual(0, self.regular.padding.size, "Pad added (on init)") - size = self.regular.add_padding() - self.assertEqual(16, size, "Pad added (on return)") - self.assertEqual(16, self.regular.size, "Pad added (on instance)") - self.assertEqual(0, self.regular.padding.size, "Pad added (on padding)") - payload_size = self.regular.add_tile(Tile(b'Hello')) - self.assertEqual(16, size, "Pad added (on return)") - self.assertEqual(payload_size, self.regular.size, "Pad added (on instance)") - self.assertEqual(0, self.regular.padding.size, "Pad added (on padding)") - - def test_as_bits(self) -> None: - self.assertEqual( - "0001010011010001", - self.regular.as_bits(), - "Just header got wrong" - ) - self.regular.add_tile(Tile(b'Hello')) - self.regular.add_padding() - self.assertEqual( - "00010100110100010100100001100101011011000110110001101111", - self.regular.as_bits(), - "Message got wrong" - ) - - def test_as_bytes(self) -> None: - self.assertEqual( - (b'\x14', b'\xd1'), - self.regular.as_bytes(), - "Just header got wrong" - ) - self.regular.add_tile(Tile(b'Hello')) - self.regular.add_padding() - self.assertEqual( - (b'\x14', b'\xd1Hello'), - self.regular.as_bytes(), - "Message got wrong" - ) - - def test_as_text(self) -> None: - self.assertEqual( - "|--- SCHC Fragment Header ---|\n" + - " |-- M=2 --|--- N=6 ---|\n" + - "| RuleID | W | FCN |\n" + - "|00010100|11 |010001 |", - self.regular.as_text(), - "Just header got wrong" - ) - self.regular.add_tile(Tile(b'Hello')) - self.regular.add_padding() - self.assertEqual( - "|--- SCHC Fragment Header ---|\n" + - " |-- M=2 --|--- N=6 ---|\n" + - "| RuleID | W | FCN | Fragment Payload |\n" + - "|00010100|11 |010001 |0100100001100101011011000110110001101111|", - self.regular.as_text(), - "Message got wrong" - ) - - def test_from_bytes(self) -> None: - regular = RegularSCHCFragment.from_bytes(b'\x14\xd1HelloWorld') - self.assertEqual( - "|--- SCHC Fragment Header ---|\n" + - " |-- M=2 --|--- N=6 ---|\n" + - "| RuleID | W | FCN |" + - " Fragment Payload |\n" + - "|00010100|11 |010001 |" + - "01001000011001010110110001101100011011110101011101101111011100100110110001100100|", - regular.as_text(), - "Message parsed wrong" - ) - - -if __name__ == '__main__': - main() diff --git a/fragmentation_layer/tests/test_parser/__init__.py b/fragmentation_layer/tests/test_parser/__init__.py deleted file mode 100644 index 435494e..0000000 --- a/fragmentation_layer/tests/test_parser/__init__.py +++ /dev/null @@ -1 +0,0 @@ -""" test of schc_parser package """ diff --git a/fragmentation_layer/tests/test_parser/test_parser_lo_ra_wan.py b/fragmentation_layer/tests/test_parser/test_parser_lo_ra_wan.py deleted file mode 100644 index fc752c1..0000000 --- a/fragmentation_layer/tests/test_parser/test_parser_lo_ra_wan.py +++ /dev/null @@ -1,152 +0,0 @@ -""" test_parser_lo_ra_wan: Unit test for parsing over LoRaWAN """ - -from unittest import TestCase, main -from schc_parsers import SCHCParser -from schc_protocols import LoRaWAN - - -class TestParserLoRaWAN(TestCase): - - def test_regular(self): - # AckOnError - expected_regular = SCHCParser.from_bytes(LoRaWAN(), b'\x14\xd1HelloWorld') - self.assertEqual( - "|--- SCHC Fragment Header ---|\n" + - " |-- M=2 --|--- N=6 ---|\n" + - "| RuleID | W | FCN |" + - " Fragment Payload |\n" + - "|00010100|11 |010001 |" + - "01001000011001010110110001101100011011110101011101101111011100100110110001100100|", - expected_regular.as_text(), - "SCHCRegular not parsed (ack_on_error mode)" - ) - # Downlink - expected_regular = SCHCParser.from_bytes(LoRaWAN(), b'\x15\x12\x00') - self.assertEqual( - "|--- SCHC Fragment Header ---|\n" + - " |-- M=1 --|--- N=1 ---|\n" + - "| RuleID | W | FCN |" + - " Fragment Payload | padding |\n" + - "|00010101|0 |0 |" + - "01001000 |000000 |", - expected_regular.as_text(), - "SCHCRegular not parsed (downlink mode)" - ) - - def test_all1(self): - # AckOnError - # With Payload - expected_all1 = SCHCParser.from_bytes(LoRaWAN(), b'\x14\xbf\xac\xde2\x14HelloWorld') - self.assertEqual( - "|--- SCHC Fragment Header ---|\n" + - " |-- M=2 --|--- N=6 ---| U=32 |\n" + - "| RuleID | W | FCN | RCS |" + - " Fragment Payload |\n" + - "|00010100|10 |111111 |10101100110111100011001000010100|" + - "01001000011001010110110001101100011011110101011101101111011100100110110001100100|", - expected_all1.as_text(), - "SCHCAll1 not parsed (ack_on_error mode, with payload)" - ) - # AckOnError - # Without Payload - expected_all1 = SCHCParser.from_bytes(LoRaWAN(), b'\x14\xbf\xac\xde2\x14') - self.assertEqual( - "|--- SCHC Fragment Header ---|\n" + - " |-- M=2 --|--- N=6 ---| U=32 |\n" + - "| RuleID | W | FCN | RCS |\n" + - "|00010100|10 |111111 |10101100110111100011001000010100|", - expected_all1.as_text(), - "SCHCAll1 not parsed (ack_on_error mode, without payload)" - ) - # Downlink - expected_all1 = SCHCParser.from_bytes(LoRaWAN(), b'\x15k7\x8c\x85\x12\x00') - self.assertEqual( - "|--- SCHC Fragment Header ---|\n" + - " |-- M=1 --|--- N=1 ---| U=32 |\n" + - "| RuleID | W | FCN | RCS | Fragment Payload | padding |\n" + - "|00010101|0 |1 |10101100110111100011001000010100|0100100000000000 |000000 |", - expected_all1.as_text(), - "SCHCAll1 not parsed (downlink mode)" - ) - - def test_ack(self): - # AckOnError - # Correct - expected_ack = SCHCParser.from_bytes(LoRaWAN(), b'\x14`') - self.assertEqual( - "|-- SCHC ACK Header --|\n" + - " |-- M=2 --| 1 |\n" + - "| RuleID | W | C | padding |\n" + - "|00010100|01 | 1 |00000 |", - expected_ack.as_text(), - "SCHC Ack not parsed (ack_on_error mode, correct one)" - ) - # Incorrect - expected_ack = SCHCParser.from_bytes(LoRaWAN(), b'\x14W') - self.assertEqual( - "|-- SCHC ACK Header --|\n" + - " |-- M=2 --| 1 |\n" + - "| RuleID | W | C | Compressed Bitmap |\n" + - "|00010100|01 | 0 |10111 |", - expected_ack.as_text(), - "SCHC Ack not parsed (ack_on_error mode, incorrect one)" - ) - # Downlink - # Correct - expected_ack = SCHCParser.from_bytes(LoRaWAN(), b'\x15@') - self.assertEqual( - "|-- SCHC ACK Header --|\n" + - " |-- M=1 --| 1 |\n" + - "| RuleID | W | C | padding |\n" + - "|00010101|0 | 1 |000000 |", - expected_ack.as_text(), - "SCHC Ack not parsed (downlink mode, correct one)" - ) - # Incorrect - expected_ack = SCHCParser.from_bytes(LoRaWAN(), b'\x15 ') - self.assertEqual( - "|-- SCHC ACK Header --|\n" + - " |-- M=1 --| 1 |\n" + - "| RuleID | W | C | Compressed Bitmap | padding |\n" + - "|00010101|0 | 0 |1 |00000 |", - expected_ack.as_text(), - "SCHC Ack not parsed (downlink mode, incorrect one)" - ) - - def test_acq_req(self): - # AckOnError - expected_ack_req = SCHCParser.from_bytes(LoRaWAN(), b'\x14@') - self.assertEqual( - "|- SCHC ACK REQ Header -|\n" + - " |-- M=2 --|--- N=6 ---|\n" + - "| RuleID | W | FCN |\n" + - "|00010100|01 |000000 |", - expected_ack_req.as_text(), - "SCHC ACK Request not parsed (ack_on_error mode)" - ) - - def test_receiver_abort(self): - # AckOnError - expected_rec_abort = SCHCParser.from_bytes(LoRaWAN(), b'\x14\xff\xff') - self.assertEqual( - "| Receiver-Abort Header|\n" + - " |-- M=2 --| 1 |\n" + - "| RuleID | W | C |\n" + - "|00010100|11 | 1 |11111|11111111|", - expected_rec_abort.as_text(), - "SCHC Receiver Abort not parsed (ack_on_error mode)" - ) - # Downlink - expected_rec_abort = SCHCParser.from_bytes(LoRaWAN(), b'\x15\xff\xff') - self.assertEqual( - "| Receiver-Abort Header|\n" + - " |-- M=1 --| 1 |\n" + - "| RuleID | W | C |\n" + - "|00010101|1 | 1 |111111|11111111|", - expected_rec_abort.as_text(), - "SCHC Receiver Abort not parsed (downlink mode)" - ) - - -if __name__ == '__main__': - main() diff --git a/fragmentation_layer/tests/test_protocols/__init__.py b/fragmentation_layer/tests/test_protocols/__init__.py deleted file mode 100644 index 53e893b..0000000 --- a/fragmentation_layer/tests/test_protocols/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -""" test_protocol: Unit test for schc_protocols package """ - -from test_protocols.test_schc_protocol import TestSCHCProtocol diff --git a/fragmentation_layer/tests/test_protocols/test_schc_protocol.py b/fragmentation_layer/tests/test_protocols/test_schc_protocol.py deleted file mode 100644 index 0bcf752..0000000 --- a/fragmentation_layer/tests/test_protocols/test_schc_protocol.py +++ /dev/null @@ -1,88 +0,0 @@ -""" test_schc_protocol: SCHC Protocol unit test class """ - -from binascii import crc32 -from random import seed, choices, choice -from unittest import TestCase, main -from schc_base import SCHCObject -from schc_protocols import LoRaWAN - -SEED = 7 -SHORT_MESSAGE = "This is a short message".encode("ascii") -LONG_MESSAGE = """ -Abstract - - The Static Context Header Compression (SCHC) specification describes - generic header compression and fragmentation techniques for Low Power - Wide Area Networks (LPWAN) technologies. SCHC is a generic mechanism - designed for great flexibility so that it can be adapted for any of - the LPWAN technologies. - - This document specifies a profile of RFC8724 to use SCHC in - LoRaWAN(R) networks, and provides elements such as efficient - parameterization and modes of operation. - -Status of This Memo - - This Internet-Draft is submitted in full conformance with the - provisions of BCP 78 and BCP 79. - - Internet-Drafts are working documents of the Internet Engineering - Task Force (IETF). Note that other groups may also distribute - working documents as Internet-Drafts. The list of current Internet- - Drafts is at https://datatracker.ietf.org/drafts/current/. - - Internet-Drafts are draft documents valid for a maximum of six months - and may be updated, replaced, or obsoleted by other documents at any - time. It is inappropriate to use Internet-Drafts as reference - material or to cite them other than as "work in progress." - - This Internet-Draft will expire on July 29, 2021. - -Copyright Notice - - Copyright (c) 2021 IETF Trust and the persons identified as the - document authors. All rights reserved. - - This document is subject to BCP 78 and the IETF Trust's Legal - Provisions Relating to IETF Documents - (https://trustee.ietf.org/license-info) in effect on the date of - publication of this document. Please review these documents - carefully, as they describe your rights and restrictions with respect - to this document. Code Components extracted from this document must - include Simplified BSD License text as described in Section 4.e of - the Trust Legal Provisions and are provided without warranty as - described in the Simplified BSD License. -""".encode("ascii") -WORD_LENGTHS = [10, 200, int(1e3)] - - -class TestSCHCProtocol(TestCase): - - def test_crc32_static_message(self) -> None: - short = SCHCObject.bytes_2_bits(SHORT_MESSAGE) - library = hex(crc32(SCHCObject.bits_2_bytes(short))) - local = LoRaWAN().calculate_rcs(short) - self.assertEqual(library, local, "Short message crc32 do not match") - long = SCHCObject.bytes_2_bits(LONG_MESSAGE) - library = hex(crc32(SCHCObject.bits_2_bytes(long))) - local = LoRaWAN().calculate_rcs(long) - self.assertEqual(library, local, "Long message crc32 do not match") - - def test_crc32_random(self) -> None: - seed(SEED) - import string - for _ in range(100): - a_word = "".join( - choices(string.ascii_letters, k=choice(WORD_LENGTHS)) - ).encode("ascii") - word = SCHCObject.bytes_2_bits(a_word) - library = hex(crc32(SCHCObject.bits_2_bytes(word))) - local = LoRaWAN().calculate_rcs(word) - self.assertEqual( - library, local, - "Random message {} crc32 do not match".format(a_word) - ) - - -if __name__ == '__main__': - main() From d00078147545b93557fd2a49fead6cb330ea4fb7 Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Wed, 14 Jul 2021 22:45:30 -0400 Subject: [PATCH 48/50] New examples and updated Readme --- README.md | 145 ++++++++++++++++-- .../examples/flask_server/app_server.py | 19 +++ .../examples/flask_server/uplink_test.py | 38 +++++ .../{code => examples/lopy}/main.py | 0 .../{code => examples/lopy}/message.py | 0 5 files changed, 193 insertions(+), 9 deletions(-) create mode 100644 fragmentation_layer/examples/flask_server/app_server.py create mode 100644 fragmentation_layer/examples/flask_server/uplink_test.py rename fragmentation_layer/{code => examples/lopy}/main.py (100%) rename fragmentation_layer/{code => examples/lopy}/message.py (100%) diff --git a/README.md b/README.md index af67016..10c0530 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Code of SCHC protocol implemented in Python to be loaded on a [PyCOM](https://py ### Example on local computer -The following steps indicate how to run an example where the sender and the receiver are on the same machine and a message is sent with the `ACK-On-Error` mode specified in the LoRaWAN profile. A successful run means everything is working as intended. +The following steps indicate how to run an example where the sender and the receiver are on the same machine and a message is sent with the `ACK-On-Error` mode specified in the LoRaWAN profile. A successful run means the packet fragmentation/reassembly is working as intended. #### Installation @@ -37,7 +37,7 @@ The following steps indicate how to run an example where the sender and the rece .\niclabs-schc\env\Scripts\activate ```` -2. Install `fragmentation_layer` code on virtual environment +2. Install `fragmentation_layer` code on virtual environment. ````bash cd fragmentation_layer/code @@ -58,7 +58,7 @@ Open two different terminals, one for the receiver and other for the sender. For the receiver (execute first): ````bash -cd examples/local +cd fragmentation_layer/examples/local python test_receiver.py # To save logs on a file @@ -68,20 +68,147 @@ python test_receiver.py 2> `` For the sender (execute in less than [`INACTIVITY_TIMER`](https://github.com/niclabs/PySCHC/blob/master/fragmentation_layer/code/schc_protocols/lorawan.py) seconds): ````bash -cd examples/local +cd fragmentation_layer/examples/local python test_sender.py # To save logs on a file python test_sender.py 2> `` ```` -This will send SCHC Fragments from sender (`localhost:50006`) to receiver (`localhost:50007`) recovering message defined on [`test_sender.py` file](https://github.com/niclabs/PySCHC/blob/master/fragmentation_layer/example/test_sender.py) and writing it on [`received.txt` text file](https://github.com/niclabs/PySCHC/blob/master/fragmentation_layer/example/received.txt). +This will send SCHC Fragments from sender (`localhost:50006`) to receiver (`localhost:50007`) recovering the message defined on [`test_sender.py` file](https://github.com/niclabs/PySCHC/blob/master/fragmentation_layer/example/test_sender.py) and writing it on [`received.txt` text file](https://github.com/niclabs/PySCHC/blob/master/fragmentation_layer/example/received.txt). -### On LoPy as Node +This example only uses the finite state machines of ACK-On-Error mode. - -### On LoPy as Gateway +### On LoPy (as Node) - +To use this library on **LoPy**, you first need to configure the device according to PyCOM instructions: [https://docs.pycom.io/gettingstarted/](https://docs.pycom.io/gettingstarted/). + +#### Installation + +1. Create a `main.py` and other required files. + + The `main.py` file is the one that is run by the **LoPy** in order to obtain or create the data to be sent, use the library to fragment it, and send the packets. An example of [`main.py`](https://github.com/niclabs/PySCHC/blob/master/fragmentation_layer/examples/lopy/main.py) is available in `fragmentation_layer/examples/lopy` alongside a `message.py` file that is imported. + +2. Copy all needed files to the device. + + This includes: + + The contents of `fragmentation_layer/code`. + + The `main.py` file and other imports. + + The **Pymakr** plugin on [ATOM](https://docs.pycom.io/gettingstarted/software/atom/) or [Visual Studio Code](https://docs.pycom.io/gettingstarted/software/vscode/) can be used for this purpose. + +#### Standard use + +To use the methods and classes of the fragmentation layer, import `SCHCNodeHandler` and the protocol you want to use (currently only LoRaWAN ACK-On-Error is implemented): + +````python +from schc_handlers import SCHCNodeHandler +from schc_protocols import SCHCProtocol + +# First parameter of Node is the protocol, in this case LoRaWAN +node = SCHCNodeHandler(SCHCProtocol.LoRaWAN, mtu=51) # change to use other mtu + +# Load the message you want to send +handler.send_package(b"A message") + +# Define the socket your hardware use +import socket +s = socket#.methods according to each socket +handler.start(s) +```` + +### On Server (as Gateway) + +To use this library on a server, an HTTP Server listening to and processing The Things Network (TTN) requests is required. A small [Flask](https://flask.palletsprojects.com/en/2.0.x/) server with this functionality is provided in `fragmentation_layer/examples/flask_server`. This Readme does not include an explanation of how to configure a TTN account to connect a device and the server. + +#### Installation + +1. (Optional) Create a new virtual environment to install Fragmentation package. + + Using [`conda`](https://docs.conda.io/en/latest/): + + ````bash + conda create -n niclabs-schc python=3.9 + + # Activate + conda activate niclabs-schc + ```` + + Using [`venv`](https://docs.python.org/3.8/library/venv.html): + + ````bash + python3 -m venv niclabs-schc + + # Activate + # On Linux and macOS + source env/bin/activate + # On Windows + .\niclabs-schc\env\Scripts\activate + ```` + +2. Install `fragmentation_layer` code on virtual environment. + + ````bash + cd fragmentation_layer/code + + # As an static package (production) + python setup.py install + + # As an on-deployment package (develop) + python setup.py develop + ```` + +3. (Optional) Install Flask server. + + Copy files in `fragmentation_layer/examples/flask_server` to a desired location and install the Flask library on the virtual enviroment. + +#### Execution of example + +On the location of the Flask server: + +````python +python app_server.py +```` + +The server should now be running and waiting for TTN requests to the `/uplink` subdirectory. All reassembled packets will be saved in and overwrite a `received.bin` file. + +#### Standard use + +On the server, use this API as follows: + +````python +from flask import request +import base64 +import json + +from schc_handlers.schc_gateway_handler import SCHCGatewayHandler +from schc_protocols import SCHCProtocol + +# This function is called after the succesful reassembly of a packet +def example_callback(msg): + print(msg) + +MTU = 51 + +handler = SCHCGatewayHandler(SCHCProtocol.LoRaWAN, MTU, on_receive_callback=example_callback) +# If no callback is given to the handler, reassembled data will be printed on stdout as bytes. + +def receive_uplink(): + # Obtaining data from TTN requests + data = request.get_json() + downlink_url = request.headers["x-downlink-push"] + fport = data["uplink_message"]["f_port"] + dev_id = data["end_device_ids"]["device_id"] + api_key = request.headers["x-downlink-apikey"] + data = request.get_json()["uplink_message"]["frm_payload"] + payload64 = data.encode("ascii") + msg_bytes = base64.b64decode(payload64) + + # Packet processing + handler.handle(msg_bytes, fport, downlink_url, dev_id, api_key) + # This is an example for LoRaWAN. Different protocols may not require all these values + # Only msg_bytes is required by the method signature. + return json.dumps({"Message": "Okay"}), 200 +```` diff --git a/fragmentation_layer/examples/flask_server/app_server.py b/fragmentation_layer/examples/flask_server/app_server.py new file mode 100644 index 0000000..b8c4664 --- /dev/null +++ b/fragmentation_layer/examples/flask_server/app_server.py @@ -0,0 +1,19 @@ +from flask import Flask, make_response, request +import os +import sys +from uplink_test import receive_uplink +import logging +import socket + +app_server = Flask(__name__) + +logging.basicConfig(filename='error.log', level=logging.DEBUG) + +@app_server.route("/uplink", methods=["POST"]) +def uplink(): + return receive_uplink() + +print("Starting...") + +if __name__ == '__main__': + app_server.run(host="0.0.0.0", port=5000) diff --git a/fragmentation_layer/examples/flask_server/uplink_test.py b/fragmentation_layer/examples/flask_server/uplink_test.py new file mode 100644 index 0000000..611a744 --- /dev/null +++ b/fragmentation_layer/examples/flask_server/uplink_test.py @@ -0,0 +1,38 @@ +from flask import request +import base64 +import json + +from schc_handlers.schc_gateway_handler import SCHCGatewayHandler +from schc_protocols import SCHCProtocol + +MTU = 51 + +### After reassembly callbacks ### + +# print received message as ascii text +def process_print(msg): + print("It works!") + print(msg.decode("ascii")) + +# save message to 'received.bin' file +def process_save2file(msg): + with open("received.bin", "wb") as f: + f.write(msg) + print("Saved to received.bin") + +handler = SCHCGatewayHandler(SCHCProtocol.LoRaWAN, MTU, process_save2file) + +def receive_uplink(): + # Obtaining data from TTN requests + data = request.get_json() + downlink_url = request.headers["x-downlink-push"] + fport = data["uplink_message"]["f_port"] + dev_id = data["end_device_ids"]["device_id"] + api_key = request.headers["x-downlink-apikey"] + data = request.get_json()["uplink_message"]["frm_payload"] + payload64 = data.encode("ascii") + msg_bytes = base64.b64decode(payload64) + + # packet processing + handler.handle(msg_bytes, fport, downlink_url, dev_id, api_key) + return json.dumps({"Message": "Okay"}), 200 \ No newline at end of file diff --git a/fragmentation_layer/code/main.py b/fragmentation_layer/examples/lopy/main.py similarity index 100% rename from fragmentation_layer/code/main.py rename to fragmentation_layer/examples/lopy/main.py diff --git a/fragmentation_layer/code/message.py b/fragmentation_layer/examples/lopy/message.py similarity index 100% rename from fragmentation_layer/code/message.py rename to fragmentation_layer/examples/lopy/message.py From 885717810e69b64d7cce818e980ed1a33d263fa3 Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Thu, 15 Jul 2021 18:58:30 -0400 Subject: [PATCH 49/50] Changes to compression layer structure --- README.md | 4 +- compression_layer/PacketGenerator.py | 129 ------------------ compression_layer/README.md | 8 -- compression_layer/README2.md | 22 --- .../{ => code}/SCHC_Compressor.py | 0 .../{ => code}/SCHC_Decompressor.py | 0 compression_layer/{ => code}/SCHC_Parser.py | 0 .../{ => code}/SCHC_RuleManager.py | 0 .../SCHC_Compressor.cpython-37.pyc | Bin 0 -> 4512 bytes .../SCHC_Compressor.cpython-38.pyc | Bin 0 -> 4547 bytes .../SCHC_Decompressor.cpython-37.pyc | Bin 0 -> 6864 bytes .../SCHC_Decompressor.cpython-38.pyc | Bin 0 -> 6867 bytes .../__pycache__/SCHC_Parser.cpython-37.pyc | Bin 0 -> 4157 bytes .../__pycache__/SCHC_Parser.cpython-38.pyc | Bin 0 -> 4093 bytes .../SCHC_RuleManager.cpython-37.pyc | Bin 0 -> 3557 bytes .../SCHC_RuleManager.cpython-38.pyc | Bin 0 -> 3639 bytes .../local/__pycache__/common.cpython-37.pyc | Bin 0 -> 4156 bytes .../local/__pycache__/common.cpython-38.pyc | Bin 0 -> 4203 bytes .../{ => examples/local}/common.py | 0 .../{ => examples/local}/compression_log.txt | 0 .../local}/compression_sender.py | 5 +- .../local}/decompression_log.txt | 0 .../local}/decompression_receiver.py | 4 +- .../{ => examples/local}/packets/demo.txt | 0 .../{ => examples/local}/packets/demo2.txt | 0 25 files changed, 9 insertions(+), 163 deletions(-) delete mode 100755 compression_layer/PacketGenerator.py delete mode 100644 compression_layer/README.md delete mode 100755 compression_layer/README2.md rename compression_layer/{ => code}/SCHC_Compressor.py (100%) mode change 100755 => 100644 rename compression_layer/{ => code}/SCHC_Decompressor.py (100%) mode change 100755 => 100644 rename compression_layer/{ => code}/SCHC_Parser.py (100%) mode change 100755 => 100644 rename compression_layer/{ => code}/SCHC_RuleManager.py (100%) mode change 100755 => 100644 create mode 100644 compression_layer/code/__pycache__/SCHC_Compressor.cpython-37.pyc create mode 100644 compression_layer/code/__pycache__/SCHC_Compressor.cpython-38.pyc create mode 100644 compression_layer/code/__pycache__/SCHC_Decompressor.cpython-37.pyc create mode 100644 compression_layer/code/__pycache__/SCHC_Decompressor.cpython-38.pyc create mode 100644 compression_layer/code/__pycache__/SCHC_Parser.cpython-37.pyc create mode 100644 compression_layer/code/__pycache__/SCHC_Parser.cpython-38.pyc create mode 100644 compression_layer/code/__pycache__/SCHC_RuleManager.cpython-37.pyc create mode 100644 compression_layer/code/__pycache__/SCHC_RuleManager.cpython-38.pyc create mode 100644 compression_layer/examples/local/__pycache__/common.cpython-37.pyc create mode 100644 compression_layer/examples/local/__pycache__/common.cpython-38.pyc rename compression_layer/{ => examples/local}/common.py (100%) rename compression_layer/{ => examples/local}/compression_log.txt (100%) rename compression_layer/{ => examples/local}/compression_sender.py (90%) rename compression_layer/{ => examples/local}/decompression_log.txt (100%) rename compression_layer/{ => examples/local}/decompression_receiver.py (92%) rename compression_layer/{ => examples/local}/packets/demo.txt (100%) rename compression_layer/{ => examples/local}/packets/demo2.txt (100%) diff --git a/README.md b/README.md index 10c0530..87b9e19 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@ Code of SCHC protocol implemented in Python to be loaded on a [PyCOM](https://py ## Compression - + + + ## Fragmentation Layer diff --git a/compression_layer/PacketGenerator.py b/compression_layer/PacketGenerator.py deleted file mode 100755 index f91f79e..0000000 --- a/compression_layer/PacketGenerator.py +++ /dev/null @@ -1,129 +0,0 @@ -import struct -import binascii - - -class PacketGenerator: - def __init__(self): - pass - - @staticmethod - def generate(): - - # ****************** IPv6 ************************* - # Enter the value of the headers - ipv6_version = 0x6 - ipv6_traffic_class = 0x95 - ipv6_flow_label = 0xFDFD3 - ipv6_next_header = 0x11 # UDP - ipv6_hop_limit = 0x40 - - # Mask definition - mask_high = 0xF0 - mask_low = 0x0F - mask_flow_label_high = 0xF0000 - mask_flow_label_low = 0x0FFFF - - # byte 0 - ipv6_version = ipv6_version << 4 - traffic_class_hi = ipv6_traffic_class & mask_high - traffic_class_low = ipv6_traffic_class & mask_low - traffic_class_hi = traffic_class_hi >> 4 - first_byte = ipv6_version | traffic_class_hi - first_byte_bf = struct.pack('>B', first_byte) # bit format - # print("byte 0: " + binascii.hexlify(first_byte_bf).__str__()) - - # byte 1 - traffic_class_low = traffic_class_low << 4 - flow_label_hi = mask_flow_label_high & ipv6_flow_label - flow_label_hi = flow_label_hi >> 16 - second_byte = traffic_class_low | flow_label_hi - second_byte_bf = struct.pack('>B', second_byte) # bit format - # print("byte 1: " + binascii.hexlify(second_byte_bf).__str__()) - - # byte 2 and 3 - third_byte = mask_flow_label_low & ipv6_flow_label - third_byte_bf = struct.pack('>H', third_byte) # bit format - # print("byte 2 - 3: " + binascii.hexlify(third_byte_bf).__str__()) - - # byte 6 - sixth_byte_bf = struct.pack('>B', ipv6_next_header) # bit format - # print("byte 6: " + binascii.hexlify(sixth_byte_bf).__str__()) - - # byte 7 - seventh_byte_bf = struct.pack('>B', ipv6_hop_limit) # bit format - # print("byte 7: " + binascii.hexlify(seventh_byte_bf).__str__()) - - # byte 8 - 20 - ipv6_source_address = "fc0c0000000000000000000000000094" - ipv6_source_address_bf = binascii.unhexlify(ipv6_source_address) - - # byte 24 - 36 - ipv6_destination_address = "fc0c0000000000000000000000000008" - ipv6_destination_address_bf = binascii.unhexlify(ipv6_destination_address) - - - # ****************** UDP packet **************************** - udp_source_port = 32513 - udp_source_port_bf = struct.pack('>H', udp_source_port) - - udp_destination_port = 32640 - udp_destination_port_bf = struct.pack('>H', udp_destination_port) - - udp_data = "07025f0128040015040233" - udp_data_bf = binascii.unhexlify(udp_data) - - udp_length = len(udp_data_bf) + 8 - udp_length_bf = struct.pack('>H', udp_length) - - # Calculating UDP checksum - ipv6_pseudo_header = PacketGenerator.build_pseudo_header(ipv6_source_address, ipv6_destination_address, ipv6_next_header, udp_length) - udp_checksum_bf = PacketGenerator.checksum(ipv6_pseudo_header, udp_length, udp_source_port, udp_destination_port, udp_data) - - # Creating UDP packet - udp_packet = b''.join([udp_source_port_bf, udp_destination_port_bf, udp_length_bf, udp_checksum_bf, udp_data_bf]) - - # ********* IPv6 byte 4 and 5 ********* - ipv6_payload_length = len(udp_packet) - fourth_fifth_byte_bf = struct.pack('>H', ipv6_payload_length) # bit format - # print("byte 4 - 5: " + binascii.hexlify(fourth_fifth_byte_bf).__str__()) - - # Creating IPv6 packet - headers = b''.join([first_byte_bf, second_byte_bf, third_byte_bf, fourth_fifth_byte_bf, sixth_byte_bf, seventh_byte_bf, ipv6_source_address_bf, ipv6_destination_address_bf, udp_source_port_bf, udp_destination_port_bf, udp_length_bf, udp_checksum_bf]) - headers_and_data = b''.join([first_byte_bf, second_byte_bf, third_byte_bf, fourth_fifth_byte_bf, sixth_byte_bf, seventh_byte_bf, ipv6_source_address_bf, ipv6_destination_address_bf, udp_packet]) - print("Packet IPv6: " + str(binascii.hexlify(headers_and_data))) - print("Lenght: " + str(len(headers_and_data)) + " bytes") - return (headers_and_data, udp_data_bf, headers) - - @staticmethod - def checksum(pseudo_header, udp_length, udp_source_port, udp_destination_port, udp_data): - if (len(udp_data)%4) == 3: - udp_data = udp_data + '0' - elif (len(udp_data)%4) == 2: - udp_data = udp_data + '00' - elif (len(udp_data)%4) == 1: - udp_data = udp_data + '000' - - udp_data_sum = 0 - for i in range(0, int(len(udp_data) // 4) ): - udp_data_sum = int(udp_data[i * 4:i * 4 + 4], 16) + udp_data_sum - - sum_udp = udp_source_port + udp_destination_port + udp_length + udp_data_sum - sum_total = pseudo_header + sum_udp - sum_sup = sum_total & 0xFFFF0000 - sum_inf = sum_total & 0x0000FFFF - sum_final = (sum_sup >> 16) + sum_inf - result = sum_final ^ int('FFFF', 16) - return struct.pack('>H', result) - - @staticmethod - def build_pseudo_header(src_ip, dest_ip, next_header, payload_len): - sum_ipv6_sa = 0 - for i in range(0,int(len(src_ip)//4)): - sum_ipv6_sa = int(src_ip[i*4:i*4+4],16) + sum_ipv6_sa - - sum_ipv6_da = 0 - for i in range(0,int(len(dest_ip)//4)): - sum_ipv6_da = int(dest_ip[i*4:i*4+4],16) + sum_ipv6_da - - sum_phdr = sum_ipv6_sa + sum_ipv6_da + next_header + payload_len - return sum_phdr diff --git a/compression_layer/README.md b/compression_layer/README.md deleted file mode 100644 index 1a48b58..0000000 --- a/compression_layer/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# PySCHC - -Code of SCHC protocol implemented in Python to be loaded on a [PyCOM](https://pycom.io/) device. - -## Compression - - - diff --git a/compression_layer/README2.md b/compression_layer/README2.md deleted file mode 100755 index 559a7ae..0000000 --- a/compression_layer/README2.md +++ /dev/null @@ -1,22 +0,0 @@ -# Compresión/Descompresión PySCHC - - -### Cambios - -- Implementado Matching Operator MSB. Número de bits en la string MO de la regla (ej: "MSB(6)"). -- Implementados Compression/Decompression Actions LSB, mapping-sent y devIID (aes128_cmac). -- Implementada descompresión con residuo en bits. -- Implementado alineamiento en bits del payload. -- Implementada reconstrucción del paquete IPv6 en el método `decompress`. -- Fix: Ahora método `compress` recibe paquete bruto en lugar de preparseado. -- Fix: Ahora residuo de compresión es armado como array de bits. -- Fix: Problemas varios con la regla por defecto (no compresión). -- Fix: Ahora cuando se descarta una regla por MOs no se termina la iteración por reglas prematuramente. -- Fix: Nombres incorrectos de prefijos e iids. -- Cambio de nombres de variables y comentarios de español a inglés - - -### Detalles no implementados - -- CDA devIID con valores obtenidos del device. -- CDAs/Reglas con headers de largo variable (no requerido para IPv6 + UDP). \ No newline at end of file diff --git a/compression_layer/SCHC_Compressor.py b/compression_layer/code/SCHC_Compressor.py old mode 100755 new mode 100644 similarity index 100% rename from compression_layer/SCHC_Compressor.py rename to compression_layer/code/SCHC_Compressor.py diff --git a/compression_layer/SCHC_Decompressor.py b/compression_layer/code/SCHC_Decompressor.py old mode 100755 new mode 100644 similarity index 100% rename from compression_layer/SCHC_Decompressor.py rename to compression_layer/code/SCHC_Decompressor.py diff --git a/compression_layer/SCHC_Parser.py b/compression_layer/code/SCHC_Parser.py old mode 100755 new mode 100644 similarity index 100% rename from compression_layer/SCHC_Parser.py rename to compression_layer/code/SCHC_Parser.py diff --git a/compression_layer/SCHC_RuleManager.py b/compression_layer/code/SCHC_RuleManager.py old mode 100755 new mode 100644 similarity index 100% rename from compression_layer/SCHC_RuleManager.py rename to compression_layer/code/SCHC_RuleManager.py diff --git a/compression_layer/code/__pycache__/SCHC_Compressor.cpython-37.pyc b/compression_layer/code/__pycache__/SCHC_Compressor.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6755781c9c7408b650f56c8463dbf7f34a6a9e13 GIT binary patch literal 4512 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 NWIunGM*f8+{sov!Up@c; literal 0 HcmV?d00001 diff --git a/compression_layer/code/__pycache__/SCHC_Parser.cpython-38.pyc b/compression_layer/code/__pycache__/SCHC_Parser.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3c777ab735bd0e20da8c651f1a385df541258c2d GIT binary patch literal 4093 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 literal 0 HcmV?d00001 diff --git a/compression_layer/code/__pycache__/SCHC_RuleManager.cpython-38.pyc b/compression_layer/code/__pycache__/SCHC_RuleManager.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..95a2b004a649ca89a92ec87d06df7d522683b76a GIT binary patch literal 3639 zcmai1&2J+~74NEUx7&{6IGOBZGDJfYRtrX9vI{FDR%n^oeCz~GoM__NgSER&kE@+D zvDUSl&lcaUgp3bFyhZZec%F@To4i$v_dSuSKZDeP6o<(_4!`C z-+T4?Rps&IWKl!;^Kbw0)4$DY+FxmKvFI4w1BElFKGcLJ*mKYkZ)k$=XjQ$5`Adak zbPp76qw=%{6Iz1{*3bnP`g5&e2t(x1=7cHoXiZ^>0@}PNiV3uqD2Yk51yL4LXp5pE zrqND_8R)x_RCZP#tT>Mj+TNxcxVxS_`x1(p4ArPmKL=U?g^Q?mwODgNKVu*c(m{q` zzcDbM6B;(=wW^Vr{%+8fUL)uA58U=(vg1b0z3+D1Ue6D96Mb{%gQ}V2o82Jto<&Ka z({)mT#6nleBva@qv5}NX6XBC&dXqN8K3hFcx=~k#RhAf`*KU2G$r3<*xwqW$gzqkg zEoY@Gz`5-74x_zpu-rTB>`T;PbFb+<{oZo3+v!O!4E=84wB18bE_=`1POt5S%k6H{ zZ7<)wOMlI-@RrBjb+>nzSdQZde&jd?d5Dy2%;W}Bzkd(rugHw}o8;C}p+31`dBi49sEJ8gZJA*6LTi^0PrKWugeDb!I??l%cSqo zoFa-;y;fgGtQyf_&r1y9H=`uyM_wmPjJ6*})x7e%Bn#ykSmX((^3CZ(+V zk=s7-#yv!?B!TcYDvgy`g<1F+=vjJ&ndyiR?CZ|yV)QrZWJiViI!HNi79E@xi*vWM zAH$LN;V5--ymm$c3R2a4tt|~RaGv;4I1ar4*|$KW!=1YpV)&$~LX9+`5UO)zOBf(M z&|%&h@))^mUWaC{tdtgKlKEx(9(+uX0IW zNs{YHKZvS&`bp%8+wn!hj&SsV$-|? z&ja^8vW}5Wur0On_E3*?WhI4dnQTKi@?WrinK({xN~h8gvfklxsFtZMQ8wR~*{jGem1>*WeZ9qoNAMH7UC? zF%hR;AgV^{FoU!;CS4&sk$T4$@(y+#cb^3o#qc&3Q@3$TIj+R7NoynSCLR8$&^JRV zaRn4gtiRUn$v_ir$svC^Yhvfn*%Wo>y`>HW0-^F^Zr7dlfUYhmDZ7_ z*3eR#DU&Qv#<`^R^GxfX`k!Z7Kf|tt6cw}ez$_n2f zF5vt97{0o~HwApf*W!G6j`LsVIA6k=3eK^pP`}Jj^ZqQfzC1_$;u7lV|BIUU>yUo| z)Lee7P*12h`a4c=bh3X@h@pE}0^9eyq#yAl`E)hIr$Y#ie*MF2|L~1lNqXNnA(lD0i%f z58;;yrXBOX2o_U`cjAQcC+)?-t;JUv*7gHCODykYiDsdWl%(c1AMeyD4+%e%-mWW=JqE>f-)jpS zd1!G^UbMR{mBAGIVE#OD)3&L;(0+(Cbw&vy;UD;emN0E9kjXC&{tOPkLT>0EkDSzy1Mf+^*_YM;R{q6GI$A()AapO!7GH` zAGR8s7;&B6CA2QVbVa@c56CiA zDgfveD(QVD>7^sTPSrQ5`TG<6M<*kCGwOW;__JXY1 SiZ)2BAEnUVC(eI@wEqH96+r9& literal 0 HcmV?d00001 diff --git a/compression_layer/examples/local/__pycache__/common.cpython-37.pyc b/compression_layer/examples/local/__pycache__/common.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba0f055ed12034e6b9079c01ff3cfb1c360f1adf GIT binary patch literal 4156 zcmds4TW=dh6yEjv7T@BO5Xz+&uI&Ozo5Z+DNz>FesFBhV8Y&^nQnKAMu}9q-yK6UI z38>V+06f7D;0b;N{{Wu+!UHet8_&GJne|MFEn=A>i-fg&biQ+&`DVtm$CZ3OBjNM? zH^1$Dw=PM)Fd&{eR5tMI-OEZ6NFYND6o^9tl8}OQGX+zSiEx(V9ONTh;CLE}5td;F z&S3mAJbsq@pN;SwJjd}_)L8xJIevlT7dd`u$bXLG4ELYs<6YqRBF8Ut{L0XLUOj?e zYo?k7c>QaoF2NfkxH2x6kjwvrs|=S%a8*HR#^6nO>jd!?>;H6n8-uq;@IC40Sa2Wj z94jzCf~%-?QqHlM&(rN|92QOy*Wvp~a36196L4h&*WoiPYM;)#I0;ura24Fd85a0- za!tYF0N4I|M!aKHSQ@y8m!W`na|zzTyZOK3E7n{5X3Knz)>Hyyr zxDM|&m4C=s;%|P@S**d0sH*5J*5M{(4y%g(LPUxFVlYZ{8N=)aKFXeT3P-yP#JtOx zf{lr@zcs|Z0@X3ti>OJm&p>U$?BByqawh6h#oh~EqxW7!O_F^Uv1QJinyyz7=;CX^MStbQxGmvHb%{QhzE zdgI=$yR{GQT->?6`B9^411>^i*XjB#+iEyn^P!8<(_8v(XQ{!q$t4~;`MZYJC2oTp zXr^NjuVL7_X0QO$wicXjFTG~kfV9?efh6xU{E5Wmm|Q&eb5MP1U%8S#!)V0q{sUV$>+%~g0C@8rRse_U1c7a~gZ7sFAa%NS)Z@JaTpQ#jdWAm&}h z6l|V3`}aoJZ^8Bi>_yaBvd=^PjM=}Bo#ag1rHZ{5yvFanh&oI51(5e8<%8%pcGn*V z#htxgZLvpOkJ?t0LR%!G2oqa0$}lBOKI>{mkh5%m!6TL*%)}YKtF>BG-!?SQi*hXO zD-=OFcD4-r-mZ3s7||RW>CeATOTldHakRc+Yp_eKw%>^=Y=8`HTeeGrvTmDB*Cz`` z>qX-1dC%NyN7Lo|gVOn$V#6()E0w<7$5 zBt@5*xWa_W#55Ci6hQ{#u2&WM3tQ%rsrhoqm{GH*G*h8@M)-_dWhP5^_SWoc{SU@h~$xdCc5tl^(OssWbYw>s%7tPhmDR OpZR0nt literal 0 HcmV?d00001 diff --git a/compression_layer/common.py b/compression_layer/examples/local/common.py similarity index 100% rename from compression_layer/common.py rename to compression_layer/examples/local/common.py diff --git a/compression_layer/compression_log.txt b/compression_layer/examples/local/compression_log.txt similarity index 100% rename from compression_layer/compression_log.txt rename to compression_layer/examples/local/compression_log.txt diff --git a/compression_layer/compression_sender.py b/compression_layer/examples/local/compression_sender.py similarity index 90% rename from compression_layer/compression_sender.py rename to compression_layer/examples/local/compression_sender.py index 72d9c79..9b17307 100644 --- a/compression_layer/compression_sender.py +++ b/compression_layer/examples/local/compression_sender.py @@ -1,6 +1,7 @@ -import socket, binascii +import socket, binascii, sys + +sys.path.insert(0, "../../code") -from PacketGenerator import PacketGenerator from SCHC_Compressor import SCHC_Compressor from SCHC_RuleManager import SCHC_RuleManager from common import * diff --git a/compression_layer/decompression_log.txt b/compression_layer/examples/local/decompression_log.txt similarity index 100% rename from compression_layer/decompression_log.txt rename to compression_layer/examples/local/decompression_log.txt diff --git a/compression_layer/decompression_receiver.py b/compression_layer/examples/local/decompression_receiver.py similarity index 92% rename from compression_layer/decompression_receiver.py rename to compression_layer/examples/local/decompression_receiver.py index 2d9fb74..c7156b6 100644 --- a/compression_layer/decompression_receiver.py +++ b/compression_layer/examples/local/decompression_receiver.py @@ -1,4 +1,6 @@ -import socket, binascii +import socket, binascii, sys + +sys.path.insert(0, "../../code") from SCHC_Decompressor import SCHC_Decompressor from SCHC_RuleManager import SCHC_RuleManager diff --git a/compression_layer/packets/demo.txt b/compression_layer/examples/local/packets/demo.txt similarity index 100% rename from compression_layer/packets/demo.txt rename to compression_layer/examples/local/packets/demo.txt diff --git a/compression_layer/packets/demo2.txt b/compression_layer/examples/local/packets/demo2.txt similarity index 100% rename from compression_layer/packets/demo2.txt rename to compression_layer/examples/local/packets/demo2.txt From b4845e756386a84ddee83e966c1278b87ffee190 Mon Sep 17 00:00:00 2001 From: Felipe Canales Date: Mon, 9 Aug 2021 16:21:48 -0400 Subject: [PATCH 50/50] Updated readme regarding compression layer --- README.md | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 87b9e19..45ab4be 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,46 @@ Code of SCHC protocol implemented in Python to be loaded on a [PyCOM](https://pycom.io/) device. -## Compression +## Compression Layer + +The compression layer has not been tested in LoPy and should be considered unfinished. The following example indicates how to run an example where the sender and the receiver are on the same machine and the message is a IPv6 packet. There is currently no integration with the fragmentation layer. + +### Example on local computer + +Before running the example, the `pycryptodome` library must be installed. + +#### Execution of example + +Open two different terminals, one for the receiver and other for the sender. + +For the receiver (execute first): + +````bash +cd compression_layer/examples/local +python compression_receiver.py +```` + +For the sender: + +````bash +cd compression_layer/examples/local +python compression_sender.py +```` + +This will send a SCHC Packet from sender to receiver through the socket `localhost:8099`. The IPv6 packet that is sent is in `packets/demo.txt` and after succesfully being decompressed is saved in `packets/demo2.txt`. + +### Future work + +There are a few main tasks to be adressed before this layer is considered complete: + +1. **Create an installation script**: This layer must be installed as a library, similarly to the fragmentation layer. + +2. **Refactor Protocol Parser**: Currently, this layer only supports an IPv6 for compression (SCHC_Parser.py) with no easy way to specify other protocols. The protocol selection must be dynamic on library initialization (see protocol selection on fragmentation layer). + +3. **Test and adjust LoPy compatibility**: This layer has to run on LoPy alongside the fragmentation layer. + +4. **Integration with fragmentation**: compressed packets must be delivered and received from the fragmetation layer. This is likely more direct if done from the fragmentation layer's side. -