コード例 #1
0
    async def rx_timing_setup_req(self) -> bool:
        def check_rtsa(m:lm.Msg, explain:Optional[str]=None) -> None:
            opts = self.get_opts(m)
            self.assert_equals(len(opts), 1, explain)
            self.assert_equals(type(opts[0]), lo.RXTimingSetupAns, explain)

        m = await self.start_testmode()

        # -- Modify RX1 and RX2 timing to X second delay
        for delay in range(1, 16):
            self.lw_dnlink(m, port=0,
                    payload=lo.pack_opts([lo.RXTimingSetupReq(Delay=delay)]))
            self.session['rx1delay'] = delay
            m = await self.lw_uplink()
            check_rtsa(m)
            m = await self.req_check_echo(m, b'\1\2\3')
            self.assert_equals(len(self.get_opts(m)), 0)
            m = await self.req_check_echo(m, b'\4\5\6', rx2=True)

        # -- Restore default timing
        self.lw_dnlink(m, port=0,
                payload=lo.pack_opts([lo.RXTimingSetupReq(Delay=0)]))
        self.session['rx1delay'] = 1

        # -- Test reply transmission
        for i in range(2):
            m = await self.lw_uplink()
            check_rtsa(m, explain=f'iteration {i+1}')

        m = await self.req_check_echo(m, b'\1\2\3')
        self.assert_equals(len(self.get_opts(m)), 0)
        m = await self.req_check_echo(m, b'\4\5\6', rx2=True)

        return True
コード例 #2
0
async def _(dut=createtest):
    m = await dut.start_testmode()

    def check_rtsa(m:LoraWanMsg, msg:str) -> None:
        opts = m.unpack_opts()
        assert len(opts) == 1, msg
        opt, = opts
        assert type(opt) == lo.RXTimingSetupAns, msg

    # -- Modify RX1 and RX2 timing to X second delay
    for delay in range(1, 16):
        dut.dndf(m, 0, lo.pack_opts([lo.RXTimingSetupReq(Delay=delay)]))
        dut.session['rx1delay'] = delay
        m = await dut.updf()
        check_rtsa(m, f'rxdelay={delay}')
        m = await dut.echo(m, b'\1\2\3')
        assert len(m.unpack_opts()) == 0, f'rxdelay={delay}'
        m = await dut.echo(m, b'\4\5\6', rx2=True)

    # -- Restore default timing
    dut.dndf(m, 0, lo.pack_opts([lo.RXTimingSetupReq(Delay=0)]))
    dut.session['rx1delay'] = 1

    # -- Test reply transmission
    for i in range(2):
        m = await dut.updf()
        check_rtsa(m, f'iteration {i+1}')

    m = await dut.echo(m, b'\1\2\3')
    assert len(m.unpack_opts()) == 0
    m = await dut.echo(m, b'\4\5\6', rx2=True)
コード例 #3
0
ファイル: lwtest.py プロジェクト: povik/basicmac
    async def rx_param_setup_req(self) -> bool:
        def check_rpsa(m: lm.Msg, explain: Optional[str] = None) -> None:
            opts = self.get_opts(m)
            self.assert_equals(len(opts), 1, explain)
            self.assert_equals(type(opts[0]), lo.RXParamSetupAns, explain)
            self.assert_equals(opts[0].FreqAck.value, 1, explain)
            self.assert_equals(opts[0].RX2DRAck.value, 1, explain)
            self.assert_equals(opts[0].RX1DRoffAck.value, 1, explain)

        m = await self.start_testmode()

        # Make sure we are DR5 so we can see the rx1droff effect
        self.assert_equals(self.rps2dr(m['upmsg'].rps), 5)

        # -- Modify RX1 and RX2 downlink parameters
        opt = lo.RXParamSetupReq(RX2DR=2, RX1DRoff=2, Freq=868525000 // 100)
        self.lw_dnlink(m, port=0, payload=lo.pack_opts([opt]))

        m = await self.lw_uplink()
        check_rpsa(m)

        m = await self.req_check_echo(m,
                                      b'\1\2\3',
                                      rx1droffset=opt.RX1DRoff.value)
        m = await self.req_check_echo(m,
                                      b'\4\5\6',
                                      rx2=True,
                                      rps=self.dndr2rps(opt.RX2DR.value),
                                      freq=opt.Freq.value * 100)

        # -- Restore default downlink parameters
        self.lw_dnlink(m,
                       port=0,
                       payload=lo.pack_opts([
                           lo.RXParamSetupReq(RX2DR=self.region.RX2DR,
                                              RX1DRoff=0,
                                              Freq=self.region.RX2Freq // 100)
                       ]),
                       rx1droffset=opt.RX1DRoff.value)

        # -- Test reply transmission
        for i in range(2):
            m = await self.lw_uplink()
            check_rpsa(m, explain=f'iteration {i+1}')

        m = await self.req_check_echo(m, b'\1\2\3')
        self.assert_equals(len(self.get_opts(m)), 0)
        m = await self.req_check_echo(m, b'\4\5\6', rx2=True)

        return True
コード例 #4
0
 async def ncr_optdr(m:lm.Msg, freq:int) -> lm.Msg:
     self.lw_dnlink(m, port=0, payload=lo.pack_opts(
         [lo.NewChannelReq(Chnl=3, Freq=freq//100, MinDR=0, MaxDR=7)]))
     m = await self.lw_uplink()
     opts = self.get_opts(m)
     self.assert_equals(len(opts), 1)
     self.check_ncr_o(opts[0])
     return m
コード例 #5
0
 async def ncr_optdr(m:LoraWanMsg, freq:int, msg:str) -> LoraWanMsg:
     dut.dndf(m, 0, lo.pack_opts([lo.NewChannelReq(Chnl=3, Freq=freq//100, MinDR=0, MaxDR=7)]))
     m = await dut.updf(explain=msg)
     opts = m.unpack_opts()
     assert len(opts) == 1, msg
     opt, = opts
     dut.check_ncr_o(opt, explain=msg)
     return m
コード例 #6
0
async def _(dut=createtest):
    m = await dut.start_testmode()

    dut.dndf(m, 0, lo.pack_opts([lo.DevStatusReq()]))
    m = await dut.updf()

    opts = m.unpack_opts()
    assert len(opts) == 1
    assert type(opts[0]) is lo.DevStatusAns
    print(opts[0])
コード例 #7
0
async def _(dut=createtest):
    m = await dut.start_testmode()

    region = dut.session['region']

    # helper function
    def check_rpsa(m:LoraWanMsg, msg:str) -> None:
        opts = m.unpack_opts()
        assert len(opts) == 1, msg
        opt, = opts
        assert type(opt) == lo.RXParamSetupAns, msg
        assert opt.FreqAck.value == 1, msg
        assert opt.RX2DRAck.value == 1, msg
        assert opt.RX1DRoffAck.value == 1, msg

    # Make sure we are DR5 so we can see the rx1droff effect
    assert m.dr == 5

    # -- Modify RX1 and RX2 downlink parameters
    rx1droff, rx2dr, rx2freq = 2, 2, 868525000
    opt = lo.RXParamSetupReq(RX2DR=rx2dr, RX1DRoff=rx1droff, Freq=rx2freq//100)
    dut.dndf(m, 0, lo.pack_opts([opt]))

    with dut.modified_session(rx1droff=rx1droff, rx2dr=rx2dr, rx2freq=rx2freq):
        m = await dut.updf()
        check_rpsa(m, None)

        m = await dut.echo(m, b'\1\2\3')
        m = await dut.echo(m, b'\4\5\6', rx2=True)

        # -- Restore default downlink parameters
        dut.dndf(m, 0, lo.pack_opts([lo.RXParamSetupReq(RX2DR=region.RX2DR, RX1DRoff=0, Freq=region.RX2Freq//100)]))

    # -- Test reply transmission
    for i in range(2):
        m = await dut.updf()
        check_rpsa(m, f'iteration {i+1}')

    m = await dut.echo(m, b'\1\2\3')
    assert len(m.unpack_opts()) ==  0
    m = await dut.echo(m, b'\1\2\3', rx2=True)
コード例 #8
0
ファイル: lwtest.py プロジェクト: povik/basicmac
    async def dev_status_req(self) -> bool:
        m = await self.start_testmode()

        self.lw_dnlink(m, port=0, payload=lo.pack_opts([lo.DevStatusReq()]))
        m = await self.lw_uplink()

        opts = self.get_opts(m)
        assert len(opts) == 1
        assert type(opts[0]) is lo.DevStatusAns
        print(opts[0])

        return True
コード例 #9
0
async def _(dut=createtest):
    m = await dut.start_testmode()

    dc = dut.unpack_dnctr(m)

    for _ in range(2):
        cmd = lo.pack_opts([lo.DevStatusReq()])
        dut.dndf(m, 0, cmd, fopts=cmd)
        m = await dut.updf()

        opts = m.unpack_opts()
        assert len(opts) == 0 and m.rtm['FPort'] != 0

    m = await dut.test_updf()
    dc = dut.unpack_dnctr(m, expected=dc)
コード例 #10
0
ファイル: lwtest.py プロジェクト: povik/basicmac
    async def mcmd_invalid(self) -> bool:
        m = await self.start_testmode()
        dc = self.get_dnctr(m)

        for _ in range(2):
            cmd = lo.pack_opts([lo.DevStatusReq()])
            self.lw_dnlink(m, port=0, payload=cmd, fopts=cmd)
            m = await self.lw_uplink()

            opts = self.get_opts(m)
            assert len(opts) == 0 and m['FPort'] != 0

        m = await self.lw_uplink()
        self.get_dnctr(m, expect=dc)

        return True
コード例 #11
0
        async def ncr_add(m:lm.Msg, chans:List[Tuple[int,int]]) -> lm.Msg:
            opts = [lo.NewChannelReq(Chnl=ch, Freq=f//100, MinDR=0, MaxDR=5)
                    for ch, f in chans]
            self.lw_dnlink(m, port=0, payload=lo.pack_opts(opts))

            m = await self.lw_uplink()
            opts = self.get_opts(m)
            self.assert_equals(len(opts), len(chans))
            for i,o in enumerate(opts):
                if chans[i][0] < len(self.region.upchannels):
                    self.check_ncr_o(o, ChnlAck=0, DRAck=None)
                else:
                    self.check_ncr_o(o)

            return await self.check_freqs(m, frozenset(it.chain(
                (ch[1] for ch in chans if ch[1]),
                (ch.freq for ch in self.region.upchannels))))
コード例 #12
0
    async def ncr_add(m:LoraWanMsg, chans:List[Tuple[int,int]]) -> LoraWanMsg:
        opts = [lo.NewChannelReq(Chnl=ch, Freq=f//100, MinDR=0, MaxDR=5)
                for ch, f in chans]
        dut.dndf(m, 0, lo.pack_opts(opts))

        m = await dut.test_updf()
        opts = m.unpack_opts()
        assert len(opts) == len(chans)
        for i, o in enumerate(opts):
            if chans[i][0] < len(dut.session['region'].upchannels):
                dut.check_ncr_o(o, ChnlAck=0, DRAck=None)
            else:
                dut.check_ncr_o(o)

        return await dut.check_freqs(m, frozenset(itertools.chain(
            (ch[1] for ch in chans if ch[1]),
            (ch.freq for ch in dut.session['region'].upchannels))))
コード例 #13
0
ファイル: lwtest.py プロジェクト: povik/basicmac
    async def link_adr_req(self) -> bool:
        def check_laa(m: lm.Msg, explain: Optional[str] = None) -> None:
            opts = self.get_opts(m)
            self.assert_equals(len(opts), 1, explain)
            self.check_laa_o(opts[0], explain=explain)

        def check_laa_block(m: lm.Msg,
                            n: int,
                            ChAck: Optional[int] = 1,
                            DRAck: Optional[int] = 1,
                            TXPowAck: Optional[int] = 1,
                            explain: Optional[str] = None) -> None:
            opts = self.get_opts(m)
            self.assert_equals(len(opts), n, explain)
            # check that all are of the same type
            self.assert_equals(len(set(type(o) for o in opts)), 1, explain)
            # check that all have the same value
            self.assert_equals(len(set(a.value for o in opts for a in o.args)),
                               1, explain)
            # verify last one (others are identical)
            self.check_laa_o(opts[-1], ChAck, DRAck, TXPowAck, explain)

        async def ncr_optdr(m: lm.Msg, freq: int) -> lm.Msg:
            self.lw_dnlink(m,
                           port=0,
                           payload=lo.pack_opts([
                               lo.NewChannelReq(Chnl=3,
                                                Freq=freq // 100,
                                                MinDR=0,
                                                MaxDR=7)
                           ]))
            m = await self.lw_uplink()
            opts = self.get_opts(m)
            self.assert_equals(len(opts), 1)
            self.check_ncr_o(opts[0])
            return m

        m = await self.start_testmode()

        # a. ADR bit
        assert self.isadren(m)

        # b. TXPower
        self.lw_dnlink(m,
                       port=0,
                       payload=lo.pack_opts(
                           [lo.LinkADRReq(TXPow=7, DR=5, ChMaskCntl=6)]))
        m = await self.lw_uplink()
        check_laa(m)

        pstats = [0, 0]
        m = await self.ul_stats(m, 3, pstats=pstats)
        rssi0 = pstats[0] / pstats[1]

        self.lw_dnlink(m,
                       port=0,
                       payload=lo.pack_opts(
                           [lo.LinkADRReq(TXPow=0, DR=5, ChMaskCntl=6)]))
        m = await self.lw_uplink()
        check_laa(m)

        pstats = [0, 0]
        m = await self.ul_stats(m, 3, pstats=pstats)
        rssi1 = pstats[0] / pstats[1]

        print(f'RSSI @  2dBm: {rssi0:6.1f} dBm')
        print(f'RSSI @ 16dBm: {rssi1:6.1f} dBm')
        print(f'Difference:   {rssi1-rssi0:6.1f} dBm')
        self.assert_range(rssi0, -80, -10)
        self.assert_range(rssi1, -80, -10)
        self.assert_ge(rssi1 - rssi0, 6)

        # c. Required DataRates
        for dr in range(6):
            self.lw_dnlink(m,
                           port=0,
                           payload=lo.pack_opts(
                               [lo.LinkADRReq(TXPow=0, DR=dr, ChMaskCntl=6)]))
            m = await self.lw_uplink()
            check_laa(m)
            self.assert_equals(self.rps2dr(m['upmsg'].rps), dr)

        # d. Optional DataRates
        nchfreq = 869100000
        m = await ncr_optdr(m, nchfreq)
        for dr in range(6, 8):
            self.lw_dnlink(m,
                           port=0,
                           payload=lo.pack_opts(
                               [lo.LinkADRReq(TXPow=0, DR=dr, ChMaskCntl=6)]))
            m = await self.lw_uplink()
            check_laa(m)
            self.assert_equals(m['upmsg'].freq, nchfreq)
            self.assert_equals(self.rps2dr(m['upmsg'].rps), dr)
        m = await ncr_optdr(m, 0)
        self.assert_in(m['upmsg'].freq,
                       list(ch.freq for ch in self.region.upchannels))

        # e. ChannelMask
        self.lw_dnlink(m,
                       port=0,
                       payload=lo.pack_opts([
                           lo.NewChannelReq(Chnl=3,
                                            Freq=nchfreq // 100,
                                            MinDR=0,
                                            MaxDR=5),
                           lo.LinkADRReq(TXPow=5, DR=5, ChMaskCntl=0, ChMask=7)
                       ]))

        m = await self.lw_uplink()
        opts = self.get_opts(m)
        self.assert_equals(len(opts), 2)
        self.check_ncr_o(opts[0])
        self.check_laa_o(opts[1])

        m = await self.check_freqs(
            m, frozenset(ch.freq for ch in self.region.upchannels))

        self.lw_dnlink(m,
                       port=0,
                       payload=lo.pack_opts([
                           lo.LinkADRReq(TXPow=5,
                                         DR=5,
                                         ChMaskCntl=0,
                                         ChMask=0xf)
                       ]))

        m = await self.lw_uplink()
        opts = self.get_opts(m)
        self.assert_equals(len(opts), 1)
        self.check_laa_o(opts[0])

        m = await self.check_freqs(
            m,
            frozenset(
                it.chain([nchfreq],
                         (ch.freq for ch in self.region.upchannels))))

        self.lw_dnlink(m,
                       port=0,
                       payload=lo.pack_opts([
                           lo.LinkADRReq(TXPow=5, DR=5, ChMaskCntl=0, ChMask=0)
                       ]))

        m = await self.lw_uplink()
        opts = self.get_opts(m)
        self.assert_equals(len(opts), 1)
        self.check_laa_o(opts[0], ChAck=0, DRAck=None, TXPowAck=None)

        self.lw_dnlink(m,
                       port=0,
                       payload=lo.pack_opts([lo.NewChannelReq(Chnl=3,
                                                              Freq=0)]))

        m = await self.lw_uplink()
        opts = self.get_opts(m)
        self.assert_equals(len(opts), 1)
        self.check_ncr_o(opts[0])

        # f. Redundancy
        self.lw_dnlink(m,
                       port=0,
                       payload=lo.pack_opts(
                           [lo.LinkADRReq(DR=5, ChMaskCntl=6, NbTrans=2)]))
        m = await self.lw_uplink()
        check_laa(m)

        l = [await self.lw_uplink() for _ in range(3)]

        self.assert_equals(l[0]['MIC'], m['MIC'])
        self.assert_equals(l[2]['MIC'], l[1]['MIC'])

        m = l[-1]
        self.lw_dnlink(m,
                       port=0,
                       payload=lo.pack_opts(
                           [lo.LinkADRReq(DR=5, ChMaskCntl=6, NbTrans=1)]))
        m = await self.lw_uplink()
        check_laa(m)

        # g. ADRACKReq bit
        self.lw_dnlink(m)

        for i in range(64):
            m = await self.lw_uplink()
            self.assert_equals(self.isadrarq(m), False, explain=f'iter={i}')
            self.assert_equals(self.rps2dr(m['upmsg'].rps), 5)
        for dr in [5, 4, 3]:
            for i in range(32):
                m = await self.lw_uplink()
                self.assert_equals(self.isadrarq(m),
                                   True,
                                   explain=f'dr={dr}, iter={i}')
                self.assert_equals(self.rps2dr(m['upmsg'].rps), dr)

        self.lw_dnlink(m,
                       port=0,
                       payload=lo.pack_opts(
                           [lo.LinkADRReq(DR=5, ChMaskCntl=6)]))
        m = await self.lw_uplink()
        check_laa(m)
        self.assert_equals(self.rps2dr(m['upmsg'].rps), 5)

        # h. a.. Successful LinkADRReq commands block
        self.lw_dnlink(m,
                       port=0,
                       payload=lo.pack_opts([
                           lo.LinkADRReq(ChMaskCntl=0, ChMask=0),
                           lo.LinkADRReq(TXPow=4,
                                         DR=4,
                                         ChMaskCntl=0,
                                         ChMask=3,
                                         NbTrans=1),
                           lo.LinkADRReq(TXPow=0,
                                         DR=3,
                                         ChMaskCntl=6,
                                         ChMask=0,
                                         NbTrans=1)
                       ]))

        m = await self.lw_uplink()
        check_laa_block(m, 3)

        m = await self.check_freqs(
            m, frozenset(ch.freq for ch in self.region.upchannels))

        self.lw_dnlink(m,
                       port=0,
                       payload=lo.pack_opts(
                           [lo.LinkADRReq(DR=5, ChMaskCntl=6)]))
        m = await self.lw_uplink()
        check_laa(m)
        self.assert_equals(self.rps2dr(m['upmsg'].rps), 5)

        # h. b.. Unsuccessful LinkADRReq commands block
        self.lw_dnlink(m,
                       port=0,
                       payload=lo.pack_opts([
                           lo.LinkADRReq(ChMask=0x07, DR=4, TXPow=4),
                           lo.LinkADRReq(ChMaskCntl=0, ChMask=0)
                       ]))

        m = await self.lw_uplink()
        check_laa_block(m, 2, ChAck=0, DRAck=None, TXPowAck=None)

        self.assert_equals(self.rps2dr(m['upmsg'].rps), 5)

        self.lw_dnlink(m)  # empty downlink to avoid timeout (?)
        m = await self.check_freqs(
            m, frozenset(ch.freq for ch in self.region.upchannels))

        return True
コード例 #14
0
ファイル: lwtest.py プロジェクト: povik/basicmac
    async def dl_channel_req(self) -> bool:
        m = await self.start_testmode()

        for f in [868500000, self.region.upchannels[1].freq, 0]:
            # modify channel 1 RX1 frequency
            self.lw_dnlink(m,
                           port=0,
                           payload=lo.pack_opts(
                               [lo.DlChannelReq(Chnl=1, Freq=f // 100)]))

            # wait until message is received on channel 1 AND
            # simultaneously ensure that the DlChannelAns is being
            # repeated while no DL is received
            for i in range(20):
                m = await self.lw_uplink()
                opts = self.get_opts(m)
                self.assert_equals(len(opts), 1, explain=f'i={i}, f={f}')
                o = opts[0]
                assert type(o) is lo.DlChannelAns
                self.assert_equals(o.ChnlAck.value, 1)
                self.assert_equals(o.FreqAck.value, 1 if f else 0)
                if i and self.getupch(m) == 1:
                    break
            else:
                assert False, 'no message received on modified channel'

            # save current DL counter and send DL on modified channel freq
            dc = self.get_dnctr(m)
            self.req_mode(m, mode_conf=False, freq=f or None)

            # check uplink -- DlChannelAns must be cleared
            # *and* DL counter incremented
            m = await self.tst_uplink()
            opts = self.get_opts(m)
            self.assert_equals(len(opts), 0)
            self.get_dnctr(m, expect=dc + 1)

            # make sure we get a message on an unmodified channel, otherwise
            # next command won't be received..
            while self.getupch(m) == 1:
                m = await self.tst_uplink()

        # Note: the following part of the test expands upon what's required...
        for ch, f in [(1, 333333333), (3, 868500000)]:
            # attempt to modify channel
            self.lw_dnlink(m,
                           port=0,
                           payload=lo.pack_opts(
                               [lo.DlChannelReq(Chnl=ch, Freq=f // 100)]))

            # check that the command is rejected for the correct reason, and
            # simultaneously ensure that the DlChannelAns is being repeated
            # while no DL is received
            for i in range(16):
                m = await self.lw_uplink()
                opts = self.get_opts(m)
                self.assert_equals(len(opts), 1)
                o = opts[0]
                assert type(o) is lo.DlChannelAns
                if ch < len(self.region.upchannels):
                    self.assert_equals(o.ChnlAck.value, 1)
                    self.assert_equals(o.FreqAck.value, 0)
                else:
                    self.assert_equals(o.ChnlAck.value, 0)
                    self.assert_equals(o.FreqAck.value, 1)
                if i and self.getupch(m) == 1:
                    break
            else:
                assert False, 'no message received on channel 1'

            # save current DL counter and send DL
            dc = self.get_dnctr(m)
            self.req_mode(m, mode_conf=False)

            # check uplink -- DlChannelAns must be cleared
            # *and* DL counter incremented
            m = await self.tst_uplink()
            opts = self.get_opts(m)
            self.assert_equals(len(opts), 0)
            self.get_dnctr(m, expect=dc + 1)

            # make sure invalid channel didn't get enabled somehow
            m = await self.check_freqs(
                m, frozenset(ch.freq for ch in self.region.upchannels))

        return True
コード例 #15
0
async def _(dut=createtest):
    m = await dut.start_testmode()

    def check_laa(m:LoraWanMsg, msg:str) -> None:
        opts = m.unpack_opts()
        assert len(opts) == 1, msg
        opt, = opts
        dut.check_laa_o(opt, explain=msg)

    def check_laa_block(m:LoraWanMsg, n:int, *, ChAck:Optional[int]=1, DRAck:Optional[int]=1, TXPowAck:Optional[int]=1, msg:str) -> None:
        opts = m.unpack_opts()
        assert len(opts) == n, msg
        # check that all have the correct type
        assert [type(o) for o in opts] == [lo.LinkADRAns for _ in range(n)], msg
        # check that all have the same value
        opt = opts[-1]
        assert list(opts) == [opt for _ in range(n)], msg
        # verify last one (others are identical)
        dut.check_laa_o(opt, ChAck, DRAck, TXPowAck, explain=msg)

    async def ncr_optdr(m:LoraWanMsg, freq:int, msg:str) -> LoraWanMsg:
        dut.dndf(m, 0, lo.pack_opts([lo.NewChannelReq(Chnl=3, Freq=freq//100, MinDR=0, MaxDR=7)]))
        m = await dut.updf(explain=msg)
        opts = m.unpack_opts()
        assert len(opts) == 1, msg
        opt, = opts
        dut.check_ncr_o(opt, explain=msg)
        return m

    # a. ADR bit
    assert m.isadren()

    # b. TXPower
    dut.dndf(m, 0, lo.pack_opts([lo.LinkADRReq(TXPow=7, DR=5, ChMaskCntl=6)]))
    m = await dut.updf()
    check_laa(m, 'txpower=7')

    pstats = PowerStats()
    m = await dut.upstats(m, 3, pstats=pstats)
    rssi0 = pstats.avg()

    dut.dndf(m, 0, lo.pack_opts([lo.LinkADRReq(TXPow=0, DR=5, ChMaskCntl=6)]))
    m = await dut.updf()
    check_laa(m, 'txpower=0')

    pstats.reset()
    m = await dut.upstats(m, 3, pstats=pstats)
    rssi1 = pstats.avg()

    print(f'RSSI @  2dBm: {rssi0:6.1f} dBm')
    print(f'RSSI @ 16dBm: {rssi1:6.1f} dBm')
    print(f'Difference:   {rssi1-rssi0:6.1f} dBm')
    assert rssi0 > -80 and rssi0 < -10
    assert rssi1 > -80 and rssi1 < -10
    assert (rssi1 - rssi0) >= 6

    # c. Required DataRates
    for dr in range(6):
        dut.dndf(m, 0, lo.pack_opts([lo.LinkADRReq(TXPow=0, DR=dr, ChMaskCntl=6)]))
        m = await dut.updf()
        check_laa(m, f'dr={dr}')
        assert m.dr == dr

    # d. Optional DataRates
    nchannel = ld.ChDef(freq=869100000, minDR=0, maxDR=7)
    reg = ld.Region_EU868()
    reg.upchannels.append(nchannel)
    dut.gateway.regions.append(reg)

    m = await ncr_optdr(m, nchannel.freq, 'create new channel')
    for dr in range(6, 8):
        dut.dndf(m, 0, lo.pack_opts([lo.LinkADRReq(TXPow=0, DR=dr, ChMaskCntl=6)]))
        m = await dut.updf()
        check_laa(m, f'dr={dr}')
        assert m.msg.freq == nchannel.freq, f'dr={dr}'
        assert m.dr == dr, f'dr={dr}'
    m = await ncr_optdr(m, 0, 'delete new channel')
    assert m.msg.freq in list(ch.freq for ch in dut.session['region'].upchannels)

    # e. ChannelMask
    dut.dndf(m, 0, lo.pack_opts([lo.NewChannelReq(Chnl=3, Freq=nchannel.freq//100, MinDR=0, MaxDR=5),
        lo.LinkADRReq(TXPow=5, DR=5, ChMaskCntl=0, ChMask=7)]))

    m = await dut.updf()
    opts = m.unpack_opts()
    assert len(opts) == 2
    opt1, opt2 = opts
    dut.check_ncr_o(opt1)
    dut.check_laa_o(opt2)

    m = await dut.check_freqs(m, frozenset(ch.freq for ch in dut.session['region'].upchannels))

    dut.dndf(m, 0, lo.pack_opts([lo.LinkADRReq(TXPow=5, DR=5, ChMaskCntl=0, ChMask=0xf)]))

    m = await dut.updf()
    check_laa(m, 'chmask=0xf')

    m = await dut.check_freqs(m, frozenset(ch.freq for ch in reg.upchannels))

    dut.dndf(m, 0, lo.pack_opts([lo.LinkADRReq(TXPow=5, DR=5, ChMaskCntl=0, ChMask=0)]))

    m = await dut.updf()
    opts = m.unpack_opts()
    assert len(opts) == 1
    opt, = opts
    dut.check_laa_o(opt, ChAck=0, DRAck=None, TXPowAck=None)

    dut.dndf(m, 0, lo.pack_opts([lo.NewChannelReq(Chnl=3, Freq=0)]))

    m = await dut.updf()
    opts = m.unpack_opts()
    assert len(opts) == 1
    opt, = opts
    dut.check_ncr_o(opt)

    # f. Redundancy
    dut.dndf(m, 0, lo.pack_opts([lo.LinkADRReq(DR=5, ChMaskCntl=6, NbTrans=2)]))
    m = await dut.updf()
    check_laa(m, 'nbtrans=2')

    l = [await dut.updf() for _ in range(3)]

    assert l[0].rtm['MIC'] == m.rtm['MIC']
    assert l[2].rtm['MIC'] == l[1].rtm['MIC']

    m = l[-1]
    dut.dndf(m, 0, lo.pack_opts([lo.LinkADRReq(DR=5, ChMaskCntl=6, NbTrans=1)]))
    m = await dut.updf()
    check_laa(m, 'nbtrans=1')

    # g. ADRACKReq bit
    dut.dndf(m)

    for i in range(64):
        m = await dut.updf()
        assert m.isadrarq() == False, f'iter={i}'
        assert m.dr == 5, f'iter={i}'
    for dr in [5, 4, 3]:
        for i in range(32):
            m = await dut.updf()
            assert m.isadrarq() == True, f'dr={dr}, iter={i}'
            assert m.dr == dr, f'dr={dr}, iter={i}'

    dut.dndf(m, 0, lo.pack_opts([lo.LinkADRReq(DR=5, ChMaskCntl=6)]))
    m = await dut.updf()
    check_laa(m, 'dr=5')
    assert m.dr == 5

    # h. a.. Successful LinkADRReq commands block
    dut.dndf(m, 0, lo.pack_opts([lo.LinkADRReq(ChMaskCntl=0, ChMask=0),
        lo.LinkADRReq(TXPow=4, DR=4, ChMaskCntl=0, ChMask=3, NbTrans=1),
        lo.LinkADRReq(TXPow=0, DR=3, ChMaskCntl=6, ChMask=0, NbTrans=1)]))
    m = await dut.updf()
    check_laa_block(m, 3, msg='linkadrreq block')

    m = await dut.check_freqs(m, frozenset(ch.freq for ch in dut.session['region'].upchannels))

    dut.dndf(m, 0, lo.pack_opts([lo.LinkADRReq(DR=5, ChMaskCntl=6)]))
    m = await dut.updf()
    check_laa(m, 'dr=5')
    assert m.dr == 5

    # h. b.. Unsuccessful LinkADRReq commands block
    dut.dndf(m, 0, lo.pack_opts([lo.LinkADRReq(ChMask=0x07, DR=4, TXPow=4),
        lo.LinkADRReq(ChMaskCntl=0, ChMask=0)]))

    m = await dut.updf()
    check_laa_block(m, 2, ChAck=0, DRAck=None, TXPowAck=None, msg='invalid linkadrreq block')
    assert m.dr == 5

    dut.dndf(m) # empty downlink to avoid timeout (?)
    m = await dut.check_freqs(m, frozenset(ch.freq for ch in dut.session['region'].upchannels))
コード例 #16
0
async def _(dut=createtest):
    m = await dut.start_testmode()

    region = dut.session['region']

    for f in [ 868500000, region.upchannels[1].freq, 0 ]:
        # modify channel 1 RX1 frequency
        dut.dndf(m, 0, lo.pack_opts([lo.DlChannelReq(Chnl=1, Freq=f//100)]))

        # wait until message is received on channel 1 AND
        # simultaneously ensure that the DlChannelAns is being
        # repeated while no DL is received
        for i in range(32):
            m = await dut.updf()
            opts = m.unpack_opts()
            assert len(opts) == 1, f'i={i}, f={f}'
            o, = opts
            assert type(o) is lo.DlChannelAns
            assert o.ChnlAck.value == 1
            assert o.FreqAck.value == (1 if f else 0)
            if i and m.ch == 1:
                break
        else:
            assert False, 'no message received on modified channel'

        # save current DL counter and send DL on modified channel freq
        dc = dut.unpack_dnctr(m)
        dut.request_mode(m, False, freq=f or None)

        # check uplink -- DlChannelAns must be cleared
        # *and* DL counter incremented
        m = await dut.test_updf()
        opts = m.unpack_opts()
        assert len(opts) == 0, f'f={f}'
        dut.unpack_dnctr(m, expected=dc+1)

        # make sure we get a message on an unmodified channel, otherwise
        # next command won't be received..
        while m.ch == 1:
            m = await dut.test_updf()

    # Note: the following part of the test expands upon what's required...
    for ch, f in [(1, 333333333), (3, 868500000)]:
        # attempt to modify channel
        dut.dndf(m, 0, lo.pack_opts([lo.DlChannelReq(Chnl=ch, Freq=f//100)]))

        # check that the command is rejected for the correct reason, and
        # simultaneously ensure that the DlChannelAns is being repeated
        # while no DL is received
        for i in range(32):
            m = await dut.updf()
            opts = m.unpack_opts()
            assert len(opts) == 1, f'ch={ch}, f={f}'
            o, = opts
            assert type(o) is lo.DlChannelAns
            if ch < len(region.upchannels):
                assert o.ChnlAck.value == 1
                assert o.FreqAck.value == 0
            else:
                assert o.ChnlAck.value == 0
                assert o.FreqAck.value == 1
            if i and m.ch == 1:
                break
        else:
            assert False, 'no message received on channel 1'

        # save current DL counter and send DL
        dc = dut.unpack_dnctr(m)
        dut.request_mode(m, False)

        # check uplink -- DlChannelAns must be cleared
        # *and* DL counter incremented
        m = await dut.test_updf()
        opts = m.unpack_opts()
        assert len(opts) == 0, f'f={f}'
        dut.unpack_dnctr(m, expected=dc+1)

        # make sure invalid channel didn't get enabled somehow
        m = await dut.check_freqs(m, frozenset(ch.freq for ch in region.upchannels))