#!/usr/bin/env python3 # -*- coding: utf-8 -*- # TRX Toolkit # Unit test for CLCKGen # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. import threading import time import unittest import clck_gen class CLCKGen_Test(unittest.TestCase): # verify that timing error is not accumulated in the clock gen loop def test_no_timing_error_accumulated(self): # observe many ticks with spending some noticeable time in clock handler each tick # assert that t(last) - t(first) ≈ ntick·dt(tick) # this will break if the clock generator is not careful to prevent timing error from accumulating clck = clck_gen.CLCKGen([]) ntick = 200 # ~ 1 s tick = 0 tstart = tend = None done = threading.Event() def _(fn): nonlocal tick, tstart, tend if tick == 0: tstart = time.monotonic() if tick == ntick: tend = time.monotonic() done.set() tick += 1 time.sleep(clck.ctr_interval / 2) clck.clck_handler = _ clck.start() try: ok = done.wait(10) self.assertTrue(ok, "clck_gen stuck") self.assertIsNotNone(tstart) self.assertIsNotNone(tend) dT = tend - tstart dTok = ntick * clck.ctr_interval dTerr = dT - dTok self.assertTrue((ntick-1)*clck.ctr_interval < dT, "tick #%d: time underrun by %dus total" % (ntick, dTerr // 1e-6)) self.assertTrue((ntick+1)*clck.ctr_interval > dT, "tick #%d: time overrun by %dus total" % (ntick, dTerr // 1e-6)) finally: clck.stop() # verify that default tick interval is 1 TDMA frame exactly def test_period_is_gsm_frame(self): clck = clck_gen.CLCKGen([]) self.assertEqual(clck.ctr_interval, 4.615e-3) if __name__ == '__main__': unittest.main()