kirr has uploaded this change for review. (
https://gerrit.osmocom.org/c/osmocom-bb/+/40049?usp=email )
Change subject: trx_toolkit/clck_gen: Split it into clck_gen and _clck_gen modules
......................................................................
trx_toolkit/clck_gen: Split it into clck_gen and _clck_gen modules
clck_gen will remain at Python while _clck_gen will be later converted
to Cython for speed to avoid py-related overhead. This patch does only
plain code movement as a preparatory step for that.
Change-Id: If90f5b6718d6a24eda6221e52dc4626197f57356
---
A src/target/trx_toolkit/_clck_gen.py
M src/target/trx_toolkit/clck_gen.py
2 files changed, 112 insertions(+), 91 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/49/40049/1
diff --git a/src/target/trx_toolkit/_clck_gen.py b/src/target/trx_toolkit/_clck_gen.py
new file mode 100644
index 0000000..9d9fd15
--- /dev/null
+++ b/src/target/trx_toolkit/_clck_gen.py
@@ -0,0 +1,111 @@
+# TRX Toolkit
+# Simple TDMA frame clock generator
+#
+# (C) 2017-2019 by Vadim Yanitskiy <axilirator(a)gmail.com>
+#
+# All Rights Reserved
+#
+# 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 logging as log
+import time
+import os
+import sys
+
+from gsm_shared import *
+
+
+ns = 1e-9
+us = 1e-6
+
+
+class CLCKGen:
+ # GSM TDMA definitions
+ SEC_DELAY_US = 1000 * 1000
+ GSM_FRAME_US = 4615.0
+
+ def __init__(self, clck_links, clck_start = 0, ind_period = 102):
+ self.clck_links = clck_links
+ self.ind_period = ind_period
+ self.clck_start = clck_start
+
+ # Calculate counter time
+ self.ctr_interval = self.GSM_FRAME_US
+ self.ctr_interval /= self.SEC_DELAY_US
+ self._t_tick = int(self.ctr_interval // ns)
+
+ # Initialize timer fd
+ self._timerfd = os.timerfd_create(time.CLOCK_MONOTONIC)
+
+ # (Optional) clock consumer
+ self.clck_handler = None
+
+ def __del__(self):
+ os.close(self._timerfd)
+
+ @property
+ def running(self):
+ t_next, _ = os.timerfd_gettime_ns(self._timerfd)
+ return (t_next != 0)
+
+ def start(self):
+ # (Re)set the clock counter
+ self.clck_src = self.clck_start
+
+ # start timer fd
+ os.timerfd_settime_ns(self._timerfd, initial=self._t_tick, interval=self._t_tick)
+
+ def stop(self):
+ # stop timer fd
+ os.timerfd_settime_ns(self._timerfd, initial=0, interval=0)
+
+ # tick must be called periodically by CLCKGen user.
+ #
+ # It waits for the next GSM frame to happen and emits corresponding clock indication at
that time.
+ # It also runs attached .clck_handler if there is one.
+ #
+ # It is possible to use .tick in both blocking and non-blocking ways:
+ #
+ # - without extra care .tick will block waiting for the next GSM frame as explained
above,
+ # - client code can also poll/select on ._timerfd to wait for GSM frame.
+ # After ._timerfd becomes ready it is guaranteed that the next .tick call will not
block.
+ def tick(self):
+ # run .send_clck_ind() every .ctr_interval
+ # NOTE timerfd is careful not to accumulate timing error when organizing the clock
loop
+
+ _ = os.read(self._timerfd, 8)
+ assert len(_) == 8, len(_)
+ ticks = int.from_bytes(_, byteorder=sys.byteorder)
+ assert ticks > 0, ticks
+ if ticks > 1:
+ log.warning("CLCKGen: time overrun by %dus; resetting the clock" %
((ticks-1)*self._t_tick * ns // us))
+ # (the kernel does clock reset by itself)
+
+ self.send_clck_ind()
+
+ def send_clck_ind(self):
+ # We don't need to send so often
+ if self.clck_src % self.ind_period == 0:
+ # Create UDP payload
+ payload = "IND CLOCK %u\0" % self.clck_src
+
+ # Send indication to all UDP links
+ for link in self.clck_links:
+ link.send(payload)
+
+ # Debug print
+ log.debug(payload.rstrip("\0"))
+
+ if self.clck_handler is not None:
+ self.clck_handler(self.clck_src)
+
+ # Increase frame count (modular arithmetic)
+ self.clck_src = (self.clck_src + 1) % GSM_HYPERFRAME
diff --git a/src/target/trx_toolkit/clck_gen.py b/src/target/trx_toolkit/clck_gen.py
index a223572..c40446b 100755
--- a/src/target/trx_toolkit/clck_gen.py
+++ b/src/target/trx_toolkit/clck_gen.py
@@ -21,103 +21,13 @@
APP_CR_HOLDERS = [("2017-2019", "Vadim Yanitskiy
<axilirator(a)gmail.com>")]
import logging as log
-import time
import signal
-import os
-import sys
+from _clck_gen import CLCKGen
from app_common import ApplicationBase
from udp_link import UDPLink
-from gsm_shared import *
-ns = 1e-9
-us = 1e-6
-
-
-class CLCKGen:
- # GSM TDMA definitions
- SEC_DELAY_US = 1000 * 1000
- GSM_FRAME_US = 4615.0
-
- def __init__(self, clck_links, clck_start = 0, ind_period = 102):
- self.clck_links = clck_links
- self.ind_period = ind_period
- self.clck_start = clck_start
-
- # Calculate counter time
- self.ctr_interval = self.GSM_FRAME_US
- self.ctr_interval /= self.SEC_DELAY_US
- self._t_tick = int(self.ctr_interval // ns)
-
- # Initialize timer fd
- self._timerfd = os.timerfd_create(time.CLOCK_MONOTONIC)
-
- # (Optional) clock consumer
- self.clck_handler = None
-
- def __del__(self):
- os.close(self._timerfd)
-
- @property
- def running(self):
- t_next, _ = os.timerfd_gettime_ns(self._timerfd)
- return (t_next != 0)
-
- def start(self):
- # (Re)set the clock counter
- self.clck_src = self.clck_start
-
- # start timer fd
- os.timerfd_settime_ns(self._timerfd, initial=self._t_tick, interval=self._t_tick)
-
- def stop(self):
- # stop timer fd
- os.timerfd_settime_ns(self._timerfd, initial=0, interval=0)
-
- # tick must be called periodically by CLCKGen user.
- #
- # It waits for the next GSM frame to happen and emits corresponding clock indication at
that time.
- # It also runs attached .clck_handler if there is one.
- #
- # It is possible to use .tick in both blocking and non-blocking ways:
- #
- # - without extra care .tick will block waiting for the next GSM frame as explained
above,
- # - client code can also poll/select on ._timerfd to wait for GSM frame.
- # After ._timerfd becomes ready it is guaranteed that the next .tick call will not
block.
- def tick(self):
- # run .send_clck_ind() every .ctr_interval
- # NOTE timerfd is careful not to accumulate timing error when organizing the clock
loop
-
- _ = os.read(self._timerfd, 8)
- assert len(_) == 8, len(_)
- ticks = int.from_bytes(_, byteorder=sys.byteorder)
- assert ticks > 0, ticks
- if ticks > 1:
- log.warning("CLCKGen: time overrun by %dus; resetting the clock" %
((ticks-1)*self._t_tick * ns // us))
- # (the kernel does clock reset by itself)
-
- self.send_clck_ind()
-
- def send_clck_ind(self):
- # We don't need to send so often
- if self.clck_src % self.ind_period == 0:
- # Create UDP payload
- payload = "IND CLOCK %u\0" % self.clck_src
-
- # Send indication to all UDP links
- for link in self.clck_links:
- link.send(payload)
-
- # Debug print
- log.debug(payload.rstrip("\0"))
-
- if self.clck_handler is not None:
- self.clck_handler(self.clck_src)
-
- # Increase frame count (modular arithmetic)
- self.clck_src = (self.clck_src + 1) % GSM_HYPERFRAME
-
# Just a wrapper for independent usage
class Application(ApplicationBase):
def __init__(self):
--
To view, visit
https://gerrit.osmocom.org/c/osmocom-bb/+/40049?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Change-Id: If90f5b6718d6a24eda6221e52dc4626197f57356
Gerrit-Change-Number: 40049
Gerrit-PatchSet: 1
Gerrit-Owner: kirr <kirr(a)nexedi.com>
Gerrit-CC: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-CC: osmith <osmith(a)sysmocom.de>
Gerrit-CC: pespin <pespin(a)sysmocom.de>