Skip to content

Instantly share code, notes, and snippets.

@mipsparc
Last active August 23, 2016 15:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mipsparc/710bcfd36fc42c9159d3da6532a4915e to your computer and use it in GitHub Desktop.
Save mipsparc/710bcfd36fc42c9159d3da6532a4915e to your computer and use it in GitHub Desktop.
チューナーから標準入力されたストリームを読み込んで時刻情報パケット(TDT)から時刻を取得し、GUIの時計を表示します
#!/usr/bin/env python3
#coding:utf-8
import json
import random
import time
try:
from gi import pygtkcompat
except ImportError:
pygtkcompat = None
if pygtkcompat is not None:
pygtkcompat.enable()
pygtkcompat.enable_gtk(version='3.0')
import gtk
import gobject
import math
import bitstring
import sys
import io
import datetime
packet_length = 188
#packet_length = 204
syncbyte = 0x47
count = 0
failcount = 0
readpos = 0
bio = io.BytesIO()
#quoted from https://gist.github.com/jiffyclub/1294443
def mjd_to_date(mjd):
jd = mjd + 2400000.5
jd = jd + 0.5
F, I = math.modf(jd)
I = int(I)
A = math.trunc((I - 1867216.25)/36524.25)
if I > 2299160:
B = I + 1 + A - math.trunc(A / 4.)
else:
B = I
C = B + 1524
D = math.trunc((C - 122.1) / 365.25)
E = math.trunc(365.25 * D)
G = math.trunc((C - E) / 30.6001)
day = int(C - E + F - math.trunc(30.6001 * G))
if G < 13.5:
month = G - 1
else:
month = G - 13
if month > 2.5:
year = D - 4716
else:
year = D - 4715
return year, month, day
class TS:
def __init__(self, packet):
self.packet = packet
def unpack(self):
if packet_length == 188:
#188-5(header+pointer)-4(CRC)=179, 179*8=1432bits
self.sync, self.error, self.pid, self.scramble, self.counter, self.pointer, self.payload, self.crc = \
self.packet.unpack('uint:8, bool, pad:2, uint:13, bits:2, pad:2, uint:4, uint:8, bits:1432, bytes:4')
else:
#204(16がリードソロモン)
self.sync, self.error, self.pid, self.scramble, self.counter, self.pointer, self.payload, self.crc, self.reedsolomon = \
self.packet.unpack('uint:8, bool, pad:2, uint:13, bits:2, pad:2, uint:4, uint:8, bits:1432, bytes:4, bytes:16')
#find sync
if self.sync != syncbyte:
found = self.packet.find('0x47', bytealigned=True) #findには文字列で渡す…
return True
return False
def tdt_unpack(self):
table_id, mjd16, h1, h2, m1, m2, s1, s2 = \
self.payload.unpack('uint:8, pad:16, uint:16, uint:4, uint:4, uint:4, uint:4, uint:4, uint:4')
year, month, day = mjd_to_date(mjd16)
hour = int(str(h1)+str(h2))
minute = int(str(m1)+str(m2))
sec = int(str(s1)+str(s2))
print('TIME {}-{}-{} {}:{}:{} JST'.format(year, month, day, hour, minute, sec))
return datetime.datetime(year, month, day, hour, minute, sec)
while True:
#新規パケットをwriteする前に終端にseek(seek位置から書くから)
bio.seek(0, io.SEEK_END)
bio.write(sys.stdin.buffer.read(packet_length*2))
#読むので前回位置にseek
bio.seek(readpos)
read_data = bio.read(packet_length)
#前回seek位置を次のに合わせる
if count%10000 != 0:
readpos += packet_length*2 #一つ飛ばし
else:
#10000ごとにバッファクリア
bio = io.BytesIO()
readpos = 0
packet = bitstring.ConstBitStream(bytes=read_data)
ts = TS(packet)
if ts.unpack():
#syncできなかったら戻る
if ts.packet.bytepos != 0: #このパケット内にsyncがあったら
if readpos > packet_length*2:
readpos = readpos - packet_length*2 + ts.packet.bytepos #一つ飛ばし考慮
else:
readpos = ts.packet.bytepos
failcount += 1
else:
#TDT
if ts.pid == 0x14 and not ts.error:
nowtime = ts.tdt_unpack()
break
count += 1
#マシン時計の標準時に対する遅延を返す
def delayer(nowtime):
unixtime_isdb = nowtime.timestamp()
unixtime_machine = time.time()
unixtime_delay = unixtime_isdb-unixtime_machine
return unixtime_delay
delay = delayer(nowtime)
print('delay:', delay)
class gui:
def __init__(self):
#Window
self.window = gtk.Window()
self.window.set_title('ISDB-T Clock')
self.window.connect('destroy_event',self.end_app)
self.window.connect('delete_event',self.end_app)
#self.window.set_icon_from_file("icon.ico")
self.window.set_default_size(200,50)
time_str, wait_msecs = self.make_time(delay)
if 0<wait_msecs:
time.sleep(wait_msecs)
else:
#正に修正
time.sleep(1+wait_msecs)
#Label
self.label_clock = gtk.Label()
self.label_clock.set_markup(time_str)
#Button
#self.adjust_button = gtk.Button()
#self.adjust_button.set_label("再校正")
#self.adjust_button.connect("clicked",self.redelayer)
self.vbox = gtk.VBox()
self.vbox.add(self.label_clock)
#self.vbox.add(self.adjust_button)
self.window.add(self.vbox)
self.window.show_all()
gobject.timeout_add(1000,self.on_timeout)
def make_time(self, delay):
nowunixtime = time.time() + delay
nowtime_str = time.ctime(nowunixtime)
#小数点以下を出1-
wait_msecs = 1-math.modf(nowunixtime)[0]
return '<b>'+nowtime_str + '</b>', wait_msecs
def end_app(self,widget,data=None):
#gtk.main_quit()
exit()
return False
def on_timeout(self,*args):
wait_sec = self.make_time(delay)[1]
#誤差修正
if 0<wait_sec:
time.sleep(wait_sec)
#多少の誤差は許容
elif 0>wait_sec+0.05:
time.sleep(1+wait_msec)
time_str = self.make_time(delay)[0]
self.label_clock.set_markup(time_str)
return True
def redelayer(self,widget,data=None):
delayer(uri)
gobject.threads_init()
gui_instance = gui()
gtk.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment