예제 #1
0
    def _processLinkCheckReq(self, device, command, request, lsnr):
        """Process a link check request
        
        Args:
            device (Device): Sending device
            command (LinkCheckReq): LinkCheckReq object
        """
        # We assume 'margin' corresponds to the
        # absolute value of LNSR, as an integer.
        # Set to zero if negative.
        margin = max(0, round(lsnr))
        # If we are processing the first request,
        # gateway count must be one, we guess.
        gwcnt = 1

        # Create the LinkCheckAns response and encode. Set fcntdown
        command = LinkCheckAns(margin=margin, gwcnt=gwcnt)

        # Queue the command if required
        if self.config.macqueueing:
            self._queueMACCommand(device.deveui, command)
            return

        frmpayload = command.encode()
        fcntdown = device.fcntdown + 1

        # Create the downlink message. Set fport=0,
        # encrypt with NwkSKey and encode
        message = MACDataDownlinkMessage(device.devaddr,
                                         device.nwkskey,
                                         fcntdown,
                                         self.config.adrenable,
                                         '',
                                         0,
                                         frmpayload,
                                         acknowledge=True)
        message.encrypt(device.nwkskey)
        data = message.encode()

        gateway = self.lora.gateway(device.gw_addr)
        if gateway is None:
            log.info(
                "Could not find gateway for gateway {gw_addr} for device "
                "{devaddr}",
                gw_addr=device.gw_addr,
                devaddr=devaddrString(device.devaddr))
            return

        # Create GatewayMessage and Txpk objects, send immediately
        request = GatewayMessage(version=1,
                                 token=0,
                                 remote=(gateway.host, gateway.port))
        device.rx = self.band.rxparams((device.tx_chan, device.tx_datr))
        txpk = self._txpkResponse(device, data, gateway, immediate=True)

        # Update the device fcntdown
        device.update(fcntdown=fcntdown)

        # Send the RX2 window message
        self.lora.sendPullResponse(request, txpk[2])
예제 #2
0
    def _sendLinkADRRequest(self, device, command):
        """Send a Link ADR Request message
        
        Called if an ADR change is required for this device.
        
        Args:
            device: (Device): Target device
            command (LinkADRReq): Link ADR Request object
        """
        frmpayload = command.encode()

        # Create the downlink message. Increment fcntdown, set fport=0,
        # encrypt with NwkSKey and encode
        fcntdown = device.fcntdown + 1
        log.info("Sending ADR Request to devaddr {devaddr}",
                 devaddr=devaddrString(device.devaddr))
        message = MACDataDownlinkMessage(device.devaddr, device.nwkskey,
                                         fcntdown, self.config.adrenable, '',
                                         0, frmpayload)
        message.encrypt(device.nwkskey)
        data = message.encode()

        gateway = self.lora.gateway(device.gw_addr)
        if gateway is None:
            log.info(
                "Could not find gateway for gateway {gw_addr} for device "
                "{devaddr}",
                gw_addr=device.gw_addr,
                devaddr=devaddrString(device.devaddr))
            returnValue(None)

        # Create GatewayMessage and Txpk objects, send immediately
        request = GatewayMessage(version=1,
                                 token=0,
                                 remote=(gateway.host, gateway.port))
        device.rx = self.band.rxparams((device.tx_chan, device.tx_datr))
        txpk = self._txpkResponse(device, data, gateway, immediate=True)

        # Update the device fcntdown
        device.update(fcntdown=fcntdown)

        # Send the RX2 window message
        self.lora.sendPullResponse(request, txpk[2])
예제 #3
0
    def inboundAppMessage(self, devaddr, appdata, acknowledge=False):
        """Sends inbound data from the application interface to the device
        
        Args:
            devaddr (int): 32 bit device address (DevAddr)
            appdata (str): packed application data
            acknowledge (bool): Acknowledged message
        """

        log.info("Inbound message to devaddr {devaddr}",
                 devaddr=devaddrString(devaddr))

        # Retrieve the active device
        device = yield self._getActiveDevice(devaddr)
        if device is None:
            log.error("Cannot send to unregistered device address {devaddr}",
                      devaddr=devaddrString(devaddr))
            returnValue(None)

        # Check the device is enabled
        if not device.enabled:
            log.error(
                "Inbound application message for disabled device "
                "{deveui}",
                deveui=euiString(device.deveui))
            returnValue(None)

        # Get the associated application
        app = yield Application.find(where=['appeui = ?', device.appeui],
                                     limit=1)
        if app is None:
            log.error(
                "Inbound application message for {deveui} - "
                "AppEUI {appeui} does not match any configured applications.",
                deveui=euiString(device.deveui),
                appeui=device.appeui)
            returnValue(None)

        # Find the gateway
        gateway = self.lora.gateway(device.gw_addr)
        if gateway is None:
            log.error(
                "Could not find gateway for inbound message to "
                "{devaddr}.",
                devaddr=devaddrString(device.devaddr))
            returnValue(None)

        # Increment fcntdown
        fcntdown = device.fcntdown + 1

        # Piggyback any queued MAC messages in fopts
        fopts = ''
        device.rx = self.band.rxparams((device.tx_chan, device.tx_datr),
                                       join=False)
        if self.config.macqueueing:
            # Get all of this device's queued commands: this returns a list of tuples (index, command)
            commands = [(i, c[2]) for i, c in enumerate(self.commands)
                        if device.deveui == c[1]]
            for (index, command) in commands:
                # Check if we can accommodate the command. If so, encode and remove from the queue
                if self.band.checkAppPayloadLen(device.rx[1]['datr'],
                                                len(fopts) + len(appdata)):
                    fopts += command.encode()
                    del self.commands[index]
                else:
                    break

        # Create the downlink message, encrypt with AppSKey and encode
        response = MACDataDownlinkMessage(device.devaddr,
                                          device.nwkskey,
                                          device.fcntdown,
                                          self.config.adrenable,
                                          fopts,
                                          int(app.fport),
                                          appdata,
                                          acknowledge=acknowledge)
        response.encrypt(device.appskey)
        data = response.encode()

        # Create Txpk objects
        txpk = self._txpkResponse(device,
                                  data,
                                  gateway,
                                  itmst=int(device.tmst),
                                  immediate=False)
        request = GatewayMessage(version=2,
                                 gatewayEUI=gateway.eui,
                                 remote=(gateway.host, gateway.port))

        # Save the frame count down
        device.update(fcntdown=fcntdown)

        # Send RX1 window message
        self.lora.sendPullResponse(request, txpk[1])
        # If Class A, send the RX2 window message
        self.lora.sendPullResponse(request, txpk[2])