-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathtdt_tot.go
100 lines (86 loc) · 2.89 KB
/
tdt_tot.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package mpeg2ts
import (
"errors"
"fmt"
"time"
)
// ETSI EN 300 468 V1.17.1 p.34
type TDT struct {
TableID byte // 8
SectionSyntaxIndicator byte // 1
ReservedFutureUse byte // 1
Reserved1 byte // 2
SectionLength uint16 // 12
RAWTimestamp uint64 // 40
Timestamp time.Time
}
// ETSI EN 300 468 V1.17.1 p.35
type TOT struct {
TDT
Reserved2 byte // 4
DescriptorsLength uint16 // 12
Descriptors []struct{}
CRC32 uint //32
Timestamp time.Time
}
var ErrPacketIsTDT = errors.New("This packet is TDT. Use ParseTDT")
func (p *Packet) ParseTDT(acceptTOT bool) (TDT, error) {
tdt := TDT{}
payload, err := p.GetPayload()
if err != nil {
return TDT{}, err
}
tdt.TableID = payload[1]
if tdt.TableID != TableID_TimeDateSection && tdt.TableID != TableID_TimeOffsetSection {
return TDT{}, fmt.Errorf("invalid TableID. expected: 0x70, actual: 0x%02x", tdt.TableID)
}
if tdt.TableID == TableID_TimeOffsetSection && !acceptTOT {
return TDT{}, errors.New("This packet is TOT. Set the acceptTOT to true or use ParseTOT")
}
tdt.SectionSyntaxIndicator = (payload[2] >> 7) & 0x01
tdt.ReservedFutureUse = (payload[2] >> 6) & 0x01
tdt.Reserved1 = (payload[2] >> 4) & 0x03
tdt.SectionLength = uint16(payload[2]&0x0F)<<8 | uint16(payload[3])
tdt.RAWTimestamp = uint64(payload[4])<<32 | uint64(payload[5])<<24 | uint64(payload[6])<<16 | uint64(payload[7])<<8 | uint64(payload[8])
tdt.Timestamp = getTimestampByMJD(tdt.RAWTimestamp)
return tdt, nil
}
func (p *Packet) ParseTOT() (TOT, error) {
tot := TOT{}
payload, err := p.GetPayload()
if err != nil {
return TOT{}, err
}
tot.TableID = payload[1]
if tot.TableID != TableID_TimeOffsetSection {
return TOT{}, ErrPacketIsTDT
}
tot.TDT, err = p.ParseTDT(true)
if err != nil {
return TOT{}, err
}
tot.Reserved2 = (payload[9] >> 4) & 0x0f
tot.DescriptorsLength = uint16(payload[9]&0x0f)<<8 | uint16(payload[10])
for i := 0; i < int(tot.DescriptorsLength); i++ {
// FIXME: implement descriptor
}
tot.CRC32 = uint(payload[tot.SectionLength])<<24 | uint(payload[tot.SectionLength+1])<<16 | uint(payload[tot.SectionLength+2])<<8 | uint(payload[tot.SectionLength+3])
tot.Timestamp = getTimestampByMJD(tot.RAWTimestamp)
crc := calculateCRC(payload[1:tot.SectionLength])
if uint32(tot.CRC32) != crc {
return TOT{}, errors.New("CRC32 mismatch")
}
return tot, nil
}
func getTimestampByMJD(mjd uint64) time.Time {
rawDate := mjd >> 24
mjdOrigin := time.Date(1858, 11, 17, 0, 00, 00, 00, time.UTC)
mjdDate := mjdOrigin.Add(time.Duration(rawDate) * time.Hour * 24)
hour := bcdToDec(byte((mjd >> 16) & 0xff))
min := bcdToDec(byte((mjd >> 8) & 0xff))
sec := bcdToDec(byte((mjd) & 0xff))
return mjdDate.Add(time.Duration(hour) * time.Hour).Add(time.Duration(min) * time.Minute).Add(time.Duration(sec) * time.Second)
}
func bcdToDec(bcd byte) byte {
return bcd>>4*10 + bcd&0x0f
}