class Testnoisefloor(unittest.TestCase):
    def setUp(self):
        """setUp()

        """
        _ui = UserInput()
        _ui.request('com4')
        self.flex = Flex(_ui)
        self.flex.open()
        self.flex.do_cmd_list(postproc.INITIALZE_FLEX)

    def tearDown(self):
        """tearDown()

        """
        self.flex.close()

    @classmethod
    def setUpClass(cls):
        """setUpClass()

        """
        _ui = UserInput()
        _ui.request('com4')
        flex = Flex(_ui)
        flex.open()
        cls.initial_state = flex.save_current_state()
        flex.close()
        postproc.enable_bands(['10', '20'])

    @classmethod
    def tearDownClass(cls):
        """tearDownClass()

        """
        _ui = UserInput()
        _ui.request('com4')
        flex = Flex(_ui)
        flex.open()
        flex.restore_state(cls.initial_state)
        flex.close()

    def test_A01SMeter(self):
        try:

            smeter = SMeter(SMArgkeys(
                'ZZSM000;',
                5_000_000,
            ))
            self.assertEqual('[SMeter: freq:5000000, -140.00000dBm, S0]',
                             str(smeter))
            gg = repr(smeter)

            self.assertEqual('SMeter: freq:5000000, -140.00000dBm, S0',
                             gg)  # repr(smeter))
        except:
            a = 0
            a = 1

    def test_A02Noisefloor_inst(self):

        dataq = QUEUES[QK.dQ]
        #stope = STOP_EVENTS['acquireData']
        stope = STOP_EVENTS[SEK.ad]

        # , testdata='noisefloordata.pickle')
        nf: Noisefloor = Noisefloor(self.flex, dataq, stope)
        self.assertTrue(nf.open(), 'smartSDR not running')
        nf.doit(loops=10, testdatafile='nfrlistdata.pickle', dups=True)

        self.assertTrue(nf.close())
        results: List[NFResult] = []
        try:
            while True:
                results.append(dataq.get(timeout=3))

        except QEmpty:
            pass

        self.assertEqual(10, len(results))
        samp: NFResult = results[2].get()
        self.assertEqual('Jul 15 2020 11:14:43', samp.starttime)
        self.assertEqual('Jul 15 2020 11:15:49', samp.endtime)
        r0bss: SMeterAvg = samp.readings[0]
        self.assertEqual('40', r0bss.band)
        self.assertEqual(-86.5, r0bss.dBm['mdBm'])

    def test_B01NoiseFloorStopEvent(self):
        """test_005NoiseFloorStopEvent

        The two seperate operations in this section make sure that
        1) shutdown works with no threads, first and 3rd thread and 3rd and 5th threads
        2) disabled threads start and end correctly
        3) that all the threads can be started and operate reaonable (with test data)
        the only data sent on a queue is to the TESTQ which basically the result of myprint calls
           and the debug text output for this is disabled by default.

        these tests check operation of trackermain.timedwork, but not much else as all the test
        functions are in the test routine
        """

        # must release the flex and ui setup in the per test setup for this test
        self.flex.close()

        #from queuesandevents import QUEUES, STOP_EVENTS
        from qdatainfo import NFQ

        barrier: CTX.Barrier = CTX.Barrier(0)

        # timesdic = {'tf': 15, 'nf': 4, 'dqr': 5, 'da': 6, 'db': 7}

        def tf(arg: Threadargs
               ):  # the program periodically executed by the timer thread
            """tf()

            """
            pass


#
# Threadargs = namedtuple('Threadargs', ['execute', 'barrier', 'stope',
# 'qs', 'name', 'interval', 'doit'])
#

        def nf(arg: Threadargs, **kwargs):
            """
            noisefloor proxy
            arg is named tuple Threadargs

            Justs writes the routine name, thread name and time to TESTQ and maybe the consule

            """
            def doita(
            ):  # the program to be run by _thread_template the return 0 says that no work need be done when stopping
                try:

                    UI: UserInput = UserInput()
                    UI.request(port='com4')
                    flexr: Flex = Flex(UI)
                    nf: Noisefloor = Noisefloor(flexr,
                                                arg.qs[QK.dQ],
                                                arg.stope,
                                                run_till_stopped=True)
                    nf.open()
                    nf.doit(loops=0, runtime=0, interval=100, dups=True)
                except StopEventException as see:
                    nf.close()
                    raise see

                # update the interval and function

            mma: Threadargs = arg._replace(doit=doita)
            # run it
            return _thread_template(mma, printfun=myprint, **kwargs)

        def dqr(arg: Threadargs, **kwargs):
            """
            noisefloor proxy
            arg is named tuple Threadargs

            Justs writes the routine name, thread name and time to TESTQ and maybe the consule

            """
            def doita(
            ):  # the program to be run by _thread_template the return 0 says that no work need be done when stopping
                pass

            mma = arg._replace(interval=1, doit=doita)
            # run it
            return _thread_template(mma, printfun=myprint, **kwargs)

        def daf(arg: Threadargs, **kwargs):
            """
            noisefloor proxy
            arg is named tuple Threadargs

            Justs writes the routine name, thread name and time to TESTQ and maybe the consule

            """
            def doita(
            ):  # the program to be run by _thread_template the return 0 says that no work need be done when stopping
                pass

            mma = arg._replace(interval=1, doit=doita)
            # run it
            return _thread_template(mma, printfun=myprint, **kwargs)

        def dbf(arg: Threadargs, **kwargs):
            """
            noisefloor proxy
            arg is named tuple Threadargs

            Justs writes the routine name, thread name and time to TESTQ and maybe the consule

            """
            def doita(
            ):  # the program to be run by _thread_template the return 0 says that no work need be done when stopping
                pass

            mma = arg._replace(interval=1, doit=doita)
            # run it
            return _thread_template(mma, printfun=myprint, **kwargs)

        # def runthreads(calls: Tuple[Callable, ...], argdicin: Dict[str, Threadargs], tpex) -> Dict[str, Any]:
        #futures: Dict[str, Any] = {}
        # futures[FK.w] = tpex.submit(
        # calls.w, argdicin[AK.w], printfn=myprint)

        # gets banddata data
        #futures[FK.n] = tpex.submit(calls.n, argdicin[AK.n])

        # reads the dataQ and sends to the data processing queue dpq
        #futures[FK.t] = tpex.submit(calls.t, argdicin[AK.t])

        # looks at the data and generates the approprate sql to send to dbwriter
        #futures[FK.da] = tpex.submit(calls.da, argdicin[AK.da])

        # reads the database Q and writes it to the database
        #futures[FK.db] = tpex.submit(calls.db, argdicin[AK.db])

        # _ = tpex.submit(breakwait, barrier)  # break the barrier
        # _.add_done_callback(bwdone)
        # return futures

        # turn off all selected thread routines
        bollst: Tuple[bool, ...] = ENABLES(
            w=False,
            n=False,
            t=False,
            da=False,
            db=False,
        )
        """
        # Check empty submit works with tracker.shutdown
        """
        calls: Tuple[Callable, ...] = ENABLES(w=trackermain.timed_work,
                                              n=nf,
                                              t=dqr,
                                              da=daf,
                                              db=dbf)
        # no threads running
        futures: Dict[str, Any] = {}
        waitresults: Tuple[Set,
                           Set] = trackermain.shutdown(futures, QUEUES,
                                                       STOP_EVENTS)
        self.assertTrue(waitresults is None)
        """
        # Check submit and shutdown works with all threads disabled
        """
        argdic: Dict[int, Threadargs] = genargs(barrier, bollst)
        #tpex = None
        """
        This did not work when placed in a with construct, and it stops the diagnostic from completing!
        No idea why not
        """
        if False:
            if True:
                tpex = concurrent.futures.ThreadPoolExecutor(
                    max_workers=10, thread_name_prefix='dbc-')
                futures: Dict[str, Any] = runthreads(barrier, calls, argdic,
                                                     tpex)
                for _ in range(1):
                    Sleep(1)  # wait for a while to let the threads work
                waitresults = trackermain.shutdown(futures,
                                                   QUEUES,
                                                   STOP_EVENTS,
                                                   time_out=1)
                a = 0
                # wait = True cause hang, false doesn't let the diagnostic end
                tpex.shutdown(wait=True)

            # all 5 threads ran to completion
            self.assertEqual(5, len(waitresults.done))
            self.assertEqual(0, len(waitresults.not_done))

        cleartestq()
        bollst: Tuple[bool, ...] = ENABLES(
            w=False,
            n=False,
            t=False,
            da=False,
            db=False,
        )

        bc: int = sum([1 for _ in bollst if _]) + 1  # count them for barrier
        barrier = CTX.Barrier(bc)
        myprint('starting')

        argdic: Dict[int, Threadargs] = genargs(barrier, bollst)
        # mods for test
        argdic[AK.w] = argdic[AK.w]._replace(name='timed_work',
                                             interval=10.5,
                                             doit=tf)
        """
        Start the threads, all should just activate and then exit leaving a trace this time
        """
        # mythreadname = threading.currentThread().getName()
        # mythread = threading.currentThread()

        with concurrent.futures.ThreadPoolExecutor(
                max_workers=10, thread_name_prefix='dbc-') as tpex:
            futures: Dict[str, Any] = runthreads(barrier, calls, argdic, tpex)
            for _ in range(1):
                Sleep(1)
            waitresults = trackermain.shutdown(futures, QUEUES, STOP_EVENTS)

        self.assertEqual(5, len(waitresults.done))
        self.assertEqual(0, len(waitresults.not_done))
        # check that the results were expected
        for _ in waitresults.done:
            self.assertTrue(_.done())
            rrr = repr(_.result())
            self.assertTrue(rrr in ['[]', 'None', 'deque([], maxlen=10)'])

        # turn on noisefloor thread
        bollst: Tuple[bool, ...] = ENABLES(False, True, False, False, False)
        # count them for barrier the plus 1 is for starting thread
        bc = sum([1 for _ in bollst if _]) + 1
        barrier = CTX.Barrier(bc)
        runtime = 90  # either 60, or 120 if not one of these, some of the asserts are ignored
        cleartestq()
        RESET_STOP_EVENTS()

        argdic: Dict[int, Threadargs] = genargs(barrier, bollst)
        # mods for test
        argdic[AK.w] = argdic[AK.w]._replace(interval=1, doit=tf)
        argdic[AK.n] = argdic[AK.n]._replace(interval=None)
        argdic[AK.t] = argdic[AK.t]._replace(interval=1)
        argdic[AK.da] = argdic[AK.da]._replace(interval=1)
        argdic[AK.db] = argdic[AK.db]._replace(interval=1)
        """
        Try running the noise floor for real on a thread
        check that shutdown will actually stop it
        """
        start = monotonic()
        futures: Dict[str, Any] = None
        with concurrent.futures.ThreadPoolExecutor(
                max_workers=10, thread_name_prefix='dbc-') as tpex:
            futures: Dict[str, Any] = runthreads(barrier, calls, argdic, tpex)
            for _ in range(
                    runtime):  # wait for a while to let the threads work
                Sleep(1)
            waitresults = trackermain.shutdown(
                futures, QUEUES, STOP_EVENTS,
                time_out=120)  # wait max 60 for the threads to stop

        end = monotonic()
        elapsed = end - start
        myprint(
            f'elapsed: {elapsed}, runtime set to: {runtime}, 120 sec timeout delay'
        )
        # took the expected one reading
        self.assertEqual(1, QUEUES[QK.dQ].qsize())
        nfqdta: NFQ = QUEUES[QK.dQ].get_nowait()
        nfr: NFResult = nfqdta.get()
        if (nfr is None):
            print('nfr is none')
        else:
            self.assertTrue(nfr._started and nfr._ended)
            self.assertEqual(4, len(nfr.readings))  # got all 4 bands

        bollst: Tuple[bool, ...] = ENABLES(w=False,
                                           n=True,
                                           t=False,
                                           da=False,
                                           db=False)
        # count them for barrier the plus 1 is for starting thread
        bc = sum([1 for _ in bollst if _]) + 1
        barrier = CTX.Barrier(bc)
        # runtime = 100  # either 60, or 120 if not one of these, some of the asserts are ignored
        cleartestq()
        RESET_STOP_EVENTS()

        argdic: Dict[int, Threadargs] = genargs(barrier, bollst)
        # mods for test
        argdic[AK.w] = argdic[AK.w]._replace(interval=1, doit=tf)
        argdic[AK.n] = argdic[AK.n]._replace(interval=None)
        argdic[AK.t] = argdic[AK.t]._replace(interval=1)
        argdic[AK.da] = argdic[AK.da]._replace(interval=1)
        argdic[AK.db] = argdic[AK.db]._replace(interval=1)
        """
        Try running the noise floor for real on a thread
        check that setting stop event will stop it
        Set to stop in the mid band scan
        """

        start = monotonic()
        with concurrent.futures.ThreadPoolExecutor(
                max_workers=10, thread_name_prefix='dbc-') as tpex:
            futures: Dict[str, Any] = runthreads(barrier, calls, argdic, tpex)
            for _ in range(int(runtime /
                               3)):  # wait for a while to let the threads work
                Sleep(1)
            STOP_EVENTS[SEK.da].set()  # stop the the data acquisition
            waitresults = trackermain.shutdown(
                futures, QUEUES, STOP_EVENTS,
                time_out=120)  # wait max 60 for the threads to stop

        end = monotonic()
        elapsed = end - start
        # aborted before it could complete a cycle
        self.assertEqual(0, QUEUES[QK.dQ].qsize())
        myprint(
            f'elapsed: {elapsed}, runtime set to: {int(runtime/3)}, 120 sec timeout delay'
        )
        a = 0

    def test_A03Noisefloortestfiles(self):
        from qdatainfo import NFQ
        from math import isclose
        from datetime import datetime as DT
        from datetime import timedelta as TD
        nfqldata: List[NFQ] = []
        with open('nfqlistdata.pickle', 'rb') as jso:
            nfqldata = pickle.load(jso)
        self.assertEqual(90, len(nfqldata))

        nfrldata: List[NFResult] = []
        with open('nfrlistdata.pickle', 'rb') as jso:
            nfrldata = pickle.load(jso)
        self.assertEqual(90, len(nfrldata))

        smavdata: List[SMeterAvg] = []
        with open('smavflistdata.pickle', 'rb') as jso:
            smavdata = pickle.load(jso)
        self.assertEqual(270, len(smavdata))

        nfq = nfqldata[0]
        nfqtimel: List[Tuple[int, TD, DT, DT, ]] = []
        for i in range(1, len(nfqldata)):
            t1: DT = nfqldata[i].utctime
            t0: DT = nfqldata[i - 1].utctime
            td: TD = t1 - t0
            if not isclose(td.total_seconds(), 90.0, abs_tol=0.5):
                nfqtimel.append((
                    i,
                    td,
                    t0,
                    t1,
                ))
        self.assertEqual(4, len(nfqtimel))

        # index, time delta between starts, time taken
        nfrlderr: List[Tuple[int, TD, TD]] = []
        for i in range(1, len(nfrldata)):
            st1: DT = DT.strptime(nfrldata[i].starttime, '%b %d %Y %H:%M:%S')
            st0: DT = DT.strptime(nfrldata[i - 1].starttime,
                                  '%b %d %Y %H:%M:%S')
            et: DT = DT.strptime(nfrldata[i].endtime, '%b %d %Y %H:%M:%S')
            sd: TD = st1 - st0
            dur: TD = et - st1
            if not isclose(sd.seconds, 90.0, abs_tol=0.5) or not isclose(
                    dur.seconds, 65.0, abs_tol=3.0):
                nfrlderr.append((i, sd, dur))
        self.assertEqual(3, len(nfrlderr))
def main(stop_events: Mapping[str, CTX.Event], queues: Mapping[str, CTX.JoinableQueue]):
    from smeteravg import SMeterAvg
    UI = UserInput()
    NOISE = None

    UI.request(port='com4')
    flexr = Flex(UI)
    initial_state = None
    try:
        if not flexr.open():
            raise (RuntimeError('Flex not connected to serial serial port'))
        print('saving current flex state')
        initial_state = flexr.save_current_state()
        print('initializing dbg flex state')
        flexr.do_cmd_list(INITIALZE_FLEX)
        flexr.close()
        resultQ = queues.get(QK.dQ)
        stop_event = stop_events.get(SEK.da)

        NOISE = Noisefloor(flexr, resultQ, stop_event)
        NOISE.open()
        # loops must be less than 100 as that is the queue size and I am not emptying it here
        NOISE.doit(loops=90, interval=90, dups=True)
        # NOISE.doit(runtime=1, interval=60)
        try:
            stop_event.set()
        except StopEventException:
            pass

        if NOISE and NOISE.is_open:
            flexr.restore_state(initial_state)
            NOISE.close()

        indata: List[NFQ] = []
        deck: Deck = Deck(1000)
        deck.q2deck(resultQ, mark_done=True)
        indata = deck.deck2lst()

        # try:

        # while True:
        #indata.append(resultQ.get(True, 1))
        # resultQ.task_done()
        # except QEmpty:
        # pass  # q is empty
        # except Exception as ex:
        # print(ex)
        #raise ex

        with open('nfqlistdata.pickle', 'wb') as jso:
            pickle.dump(indata, jso)

        unpacked: List[NFResult] = [npq.get() for npq in indata]
        with open('nfrlistdata.pickle', 'wb') as jso:
            pickle.dump(unpacked, jso)

        reads: List[SMeterAvg] = []
        for nfr in unpacked:
            reads.extend(nfr.readings)

        with open('smavflistdata.pickle', 'wb') as jso:
            pickle.dump(reads, jso)

        up0: NFResult = unpacked[0]
        outdata = []
        with open('nfqlistdata.pickle', 'rb') as jsi:
            outdata = pickle.load(jsi)

        brlst: List[Bandreadings] = []
        for nfq in outdata:
            br: Bandreadings = nfq.get()
            brlst.append(br)

        a = indata[0]
        b = outdata[0]

    except(Exception, KeyboardInterrupt) as exc:
        if NOISE and NOISE.is_open:
            flexr.restore_state(initial_state)
            NOISE.close()
        UI.close()
        raise exc

    finally:
        print('restore flex prior state')

        if NOISE and NOISE.is_open:
            flexr.restore_state(initial_state)
            NOISE.close()
        UI.close()
示例#3
0
class Testflex(unittest.TestCase):
    """Testflex

    unit testing for the flex class

    """

    # def initialize_flex(self):
    # """initialize_flex()

    # """

    # _ui = UserInput()
    # _ui.request('com4')
    # self.flex = Flex(_ui)
    # self.flex.open()
    # self.initialize_flex()
    # self.flex.do_cmd_list(postproc.INITIALZE_FLEX)
    # results = self.flex.do_cmd_list(postproc.INITIALZE_FLEX)
    # return results

    def setUp(self):
        _ui = UserInput()
        _ui.request('com4')
        self.flex = Flex(_ui)
        self.flex.open()
        _ = self.flex.do_cmd_list(postproc.INITIALZE_FLEX)
        self.assertEqual(13, len(_))

    def tearDown(self):
        self.flex.close()

    @classmethod
    def setUpClass(cls):
        _ui = UserInput()
        _ui.request('com4')
        flex = Flex(_ui)
        flex.open()
        cls.initial_state = flex.save_current_state()
        flex.close()

    @classmethod
    def tearDownClass(cls):
        _ui = UserInput()
        _ui.request('com4')
        flex = Flex(_ui)
        flex.open()
        flex.restore_state(cls.initial_state)
        flex.close()

    def test01_instantiate(self):
        """test_instantiate()

        check if Flex instiantiates and has expected str and repr without flex being opened

        """
        _ui = UserInput()
        _ui.request('com4')
        flex = Flex(_ui)

        self.assertEqual('Flex cat: com4, opened: False', str(flex))
        self.assertEqual('[Flex] Flex cat: com4, opened: False', repr(flex))
        flex.close()

    def test02_open_close(self):
        """test_open_close()

        check if Flex instiantiates and opens and has expected str and repr flex
        verifies that flex closes
        verifies re-open and can do a simple do_cmd
        """

        self.assertEqual('Flex cat: com4, opened: True', str(self.flex))
        self.assertEqual('[Flex] Flex cat: com4, opened: True',
                         repr(self.flex))

        self.flex.close()
        self.assertEqual('Flex cat: com4, opened: False', str(self.flex))
        self.assertEqual('[Flex] Flex cat: com4, opened: False',
                         repr(self.flex))

        self.flex.open()
        result = self.flex.do_cmd('ZZIF;')
        self.assertEqual(41, len(result))

    def test03_do_cmd(self):
        """test_do_cmd()

        checks error conditions on do_cmd
        """
        result = self.flex.do_cmd('ZZIF;')

        self.assertEqual(41, len(result))
        result = self.flex.do_cmd('ZZIF')
        self.assertEqual(41, len(result))
        result = self.flex.do_cmd('')
        self.assertEqual('??;', result)
        result = self.flex.do_cmd('junk')
        self.assertEqual('??;', result)

    def test04_save_current_state(self):
        """test_save_current_state()

        checks that flex state can be saved, modified and restored

        """

        savedstate = self.flex.save_current_state()
        self.assertEqual(savedstate, self.flex.saved_state[:])

        self.flex.restore_saved_state()
        newsavedstate = self.flex.save_current_state()
        self.assertEqual(savedstate, newsavedstate)

        _aa = int([i for i in newsavedstate if 'ZZFA' in i][0][-12:-1])
        _aa = 14000000 if _aa != 14000000 else 15000000
        # aat = f'ZZFA{_aa:011};'

        self.flex.do_cmd(f'ZZFA{_aa:011};')
        modstate = self.flex.save_current_state()
        self.assertNotEqual(modstate, newsavedstate)

        restore_results = self.flex.restore_state(newsavedstate)
        self.assertEqual(19, len(restore_results))
        self.assertEqual(newsavedstate, self.flex.saved_state)

    def test10_get_cat_data(self):
        """testget_cat_data()
        """
        gdata1 = [
            CMDListEnt(
                'wait0.5',
                None,
            ),
            CMDListEnt(
                'ZZIF;',
                postproc.zzifpost,
            ),
        ]

        stime = time.perf_counter()
        results = self.flex.get_cat_data([], 14_000_000)
        etime = time.perf_counter()
        dtime = etime - stime
        self.assertAlmostEqual(0.00, dtime, delta=0.001)

        stime = time.perf_counter()
        results = self.flex.get_cat_data([CMDListEnt(
            'wait0.5',
            None,
        )], 14_000_000)
        etime = time.perf_counter()
        dtime = etime - stime
        self.assertAlmostEqual(0.50, dtime, delta=0.1)

        results = self.flex.get_cat_data(gdata1, 14_000_000)
        dtime = etime - stime
        self.assertAlmostEqual(0.50, dtime, delta=0.1)
        self.assertEqual(1, len(results))

    def test05_jsonpickel(self):
        import jsonpickle
        try:
            self.flex.close()
            jsonpickelst = jsonpickle.encode(
                self.flex)  # _ui cannot be pickeled
            testob = jsonpickle.decode(jsonpickelst)
            rp1 = repr(self.flex)
            rp2 = repr(testob)
            self.assertEqual(rp1, rp2)
        except Exception as ex:
            self.fail("unexpected exception")
            a = 0
            b = 0

    def test000011_get_cat_dataA(self):
        myband: BandPrams = BANDS['20']

        proto: List[Tuple[Any, Any]] = GET_SMETER_PROTO[:]
        cmdlst: List[Tuple[Any, Any]] = []
        for cmdt in myband.get_freq_cmds():
            cmdlst.extend([CMDListEnt(cmdt, None)])
            cmdlst.extend(proto)

        cmdresult: List[Any] = self.flex.get_cat_dataA(cmdlst)
        sm_readings: List[SMeter] = [
            _ for _ in cmdresult if isinstance(_, SMeter)
        ]
        sm_readings.sort()

        cmdresultB: List[Any] = [
            _ for _ in cmdresult if not isinstance(_, SMeter)
        ]
        cmdrestup = tuple(cmdresultB)
        self.assertEqual(myband.get_freq_cmds(), cmdrestup)

        maplist: List[Mapping[str, float]] = [
            list(_.signal_st.items()) for _ in sm_readings
        ]
        keyset: Set[str] = set(
            [list(sm.signal_st.items())[0][1] for sm in sm_readings])

        noisedic: Dict[str, List[SMeter]] = {}
        for k in keyset:
            noisedic.setdefault(k, [])

        for ls in maplist:
            noisedic[ls[0][1]].append(ls[1][1])

        key = sorted(list(noisedic.keys()))[0]
        dkdk: List[SMeter] = [
            sm for sm in sm_readings if sm.signal_st['sl'] == key
        ]

        sma: SMeterAvg = SMeterAvg(dkdk, myband.bandid)
        a = 0
class TestBandreadings(unittest.TestCase):
    """TestBandreadings

    """

    def setUp(self):
        """setUp()

        """
        _ui = UserInput()
        _ui.request('com4')
        self.flex = Flex(_ui)
        self.flex.open()
        self.flex.do_cmd_list(postproc.INITIALZE_FLEX)

    def tearDown(self):
        """tearDown()

        """
        self.flex.close()

    @classmethod
    def setUpClass(cls):
        """setUpClass()

        """
        _ui = UserInput()
        _ui.request('com4')
        flex = Flex(_ui)
        flex.open()
        cls.initial_state = flex.save_current_state()
        flex.close()
        postproc.enable_bands(['10', '20'])

    @classmethod
    def tearDownClass(cls):
        """tearDownClass()

        """
        _ui = UserInput()
        _ui.request('com4')
        flex = Flex(_ui)
        flex.open()
        flex.restore_state(cls.initial_state)
        flex.close()

    def test01_instat(self):
        """test01_instat()

        """
        postproc.enable_bands('80', False)
        postproc.enable_bands('10')
        _br: Bandreadings = None
        try:
            _br = Bandreadings(None, self.flex)
            self.fail('should have had a KeyError')
        except KeyError as ke:
            pass

        try:
            _br = Bandreadings('80', self.flex)
            self.fail('should have had a ValueError')
        except ValueError as ve:
            pass

        _br = Bandreadings('10', self.flex)
        self.assertEqual('no reading, band 10', str(_br))
        self.assertEqual('Bandreadings: no reading, band 10', repr(_br))
        self.assertEqual('10', _br.bandid)

        _br = Bandreadings('20', self.flex)
        self.assertEqual('no reading, band 20', str(_br))
        self.assertEqual('Bandreadings: no reading, band 20', repr(_br))
        self.assertEqual('20', _br.bandid)

        _br = Bandreadings(
            '20', self.flex)  # these freqs in 20m band
        self.assertEqual('no reading, band 20', str(_br))
        self.assertEqual('Bandreadings: no reading, band 20', repr(_br))
        self.assertEqual('20', _br.bandid)

    def test02_radioaccess(self):
        """test02_radioaccess()

        """
        import multiprocessing as mp
        import queue
        CTX = mp.get_context('spawn')  # threading context
        dataq = CTX.JoinableQueue(maxsize=100)

        try:
            _br: Bandreadings = Bandreadings(
                '20', self.flex)
            _br.get_readings(testing='./quiet20band.json')
            self.assertEqual(
                '[SMeterAvg: b:20, -103.45833adBm, -103.50000mdBm, S3, var: 0.15720, stddv: 0.39648]',
                repr(_br.band_signal_strength))

            bss0: SMeterAvg = _br.band_signal_strength
            _br.flexradio = None  # must be done to allow pikceling in the que
            dataq.put(_br)

            _br.get_readings(testing='./noisy20band.json')
            self.assertEqual(
                '[SMeterAvg: b:20, -102.06250adBm, -103.50000mdBm, S3, var: 12.79583, stddv: 3.57713]',
                repr(_br.band_signal_strength))

            bss1: SMeterAvg = _br.band_signal_strength
            dataq.put(_br)
            # if _br.band_signal_strength.signal_st.get('stddv') > 1.5:
            # _br.changefreqs(
            # testing='./focusedbadspotreading.json')
            # self.assertEqual(
            #'[SMeterAvg: -103.32090adBm, -103.50000mdBm, S3, var: 0.74774, stddv: 0.86472]',
            # repr(_br.band_signal_strength))
            datain: List[SMeterAvg] = []
            try:
                while True:
                    datain.append(dataq.get(True, 0.005))
                    dataq.task_done()

            except queue.Empty as mt:
                b = 0
                pass

            except Exception as ex:
                a = 0
                pass

            self.assertEqual(2, len(datain))
            self.assertEqual(
                '[Bandreadings: SMeterAvg: [band:20, avgsignal: -103.45833dBm, S3, var: 0.15720, stddv: 0.39648]]', repr(datain[0]))
            tbr = datain[0]

            self.assertEqual(
                'band:20, enabled: True, chan: False, [14000000, 14035000, 14070000, 14105000, 14140000, 14175000, 14210000, 14245000, 14280000, 14315000, 14350000]',
                str(tbr.myband))

            # self.assertFalse(tbr.useable)

            bss0a = datain[0].band_signal_strength
            bss1a = datain[1].band_signal_strength
            self.assertEqual(repr(bss0), repr(bss0a))
            self.assertEqual(repr(bss1), repr(bss1a))

        except(Exception, KeyboardInterrupt) as exc:
            excs = str(exc)
            self.fail(f'unexpected exception {excs}')

    def test03_get_readings(self):
        """test03_get_readings()

        """
        _br = Bandreadings(
            '20', self.flex)  # 14000000
        _br.get_readings(testing='./noisy20band.json')
        smar = _br.band_signal_strength
        self.assertEqual(16, len(smar.smlist))
        self.assertEqual(
            'SMeter: freq:14000000, -105.00000dBm, S3', repr(smar.smlist[0]))
        self.assertEqual(
            'SMeter: freq:14074000, -96.00000dBm, S5', repr(smar.smlist[6]))
        self.assertEqual(
            '[SMeterAvg: b:20, -102.06250adBm, -103.50000mdBm, S3, var: 12.79583, stddv: 3.57713]',
            repr(smar))