2 # -*- coding: utf-8 -*-
5 # Simple TDMA frame clock generator
7 # (C) 2017-2019 by Vadim Yanitskiy <axilirator@gmail.com>
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 APP_CR_HOLDERS
= [("2017-2019", "Vadim Yanitskiy <axilirator@gmail.com>")]
27 from app_common
import ApplicationBase
28 from udp_link
import UDPLink
29 from gsm_shared
import *
32 # GSM TDMA definitions
33 SEC_DELAY_US
= 1000 * 1000
36 # Average loop back delay
39 def __init__(self
, clck_links
, clck_start
= 0, ind_period
= 102):
40 # This event is needed to control the thread
41 self
._breaker
= threading
.Event()
44 self
.clck_links
= clck_links
45 self
.ind_period
= ind_period
46 self
.clck_start
= clck_start
48 # Calculate counter time
49 self
.ctr_interval
= self
.GSM_FRAME_US
- self
.LO_DELAY_US
50 self
.ctr_interval
/= self
.SEC_DELAY_US
52 # (Optional) clock consumer
53 self
.clck_handler
= None
57 if self
._thread
is None:
59 return self
._thread
.is_alive()
62 # Make sure we won't start two threads
63 assert(self
._thread
is None)
65 # (Re)set the clock counter
66 self
.clck_src
= self
.clck_start
68 # Initialize and start a new thread
69 self
._thread
= threading
.Thread(target
= self
._worker
)
70 self
._thread
.setDaemon(True)
74 # No thread, no problem ;)
75 if self
._thread
is None:
78 # Stop the thread first
82 # Free memory, reset breaker
88 while not self
._breaker
.wait(self
.ctr_interval
):
91 def send_clck_ind(self
):
92 # We don't need to send so often
93 if self
.clck_src
% self
.ind_period
== 0:
95 payload
= "IND CLOCK %u\0" % self
.clck_src
97 # Send indication to all UDP links
98 for link
in self
.clck_links
:
102 log
.debug(payload
.rstrip("\0"))
104 if self
.clck_handler
is not None:
105 self
.clck_handler(self
.clck_src
)
107 # Increase frame count (modular arithmetic)
108 self
.clck_src
= (self
.clck_src
+ 1) % GSM_HYPERFRAME
110 # Just a wrapper for independent usage
111 class Application(ApplicationBase
):
114 self
.app_print_copyright(APP_CR_HOLDERS
)
116 # Set up signal handlers
117 signal
.signal(signal
.SIGINT
, self
.sig_handler
)
120 log
.basicConfig(level
= log
.DEBUG
,
121 format
= "[%(levelname)s] TID#%(thread)s %(filename)s:%(lineno)d %(message)s")
124 self
.link
= UDPLink("127.0.0.1", 5800, "0.0.0.0", 5700)
125 self
.clck
= CLCKGen([self
.link
], ind_period
= 51)
128 # Block unless we receive a signal
129 self
.clck
._thread
.join()
131 def sig_handler(self
, signum
, frame
):
132 log
.info("Signal %d received" % signum
)
133 if signum
== signal
.SIGINT
:
136 if __name__
== '__main__':