psi: restructured psi_test.go and started writing tests for gps

This commit is contained in:
saxon 2018-12-12 16:26:59 +10:30
parent 14e5676f6f
commit 3cf6c00991
4 changed files with 249 additions and 178 deletions

View File

@ -32,14 +32,14 @@ import (
"errors" "errors"
) )
func TimeToBytes(time uint64) []byte { func TimeBytes(time uint64) (s []byte) {
s := make([]byte, 8) s = make([]byte, timeSize)
binary.BigEndian.PutUint64(s, time) binary.BigEndian.PutUint64(s[:], time)
return s return s
} }
func chkTime(d []byte) error { func chkTime(d []byte) error {
if d[descTagIndx] != timeDescTag { if d[timeTagIndx] != timeDescTag {
return errors.New("PSI does not contain a time descriptor, cannot update") return errors.New("PSI does not contain a time descriptor, cannot update")
} }
return nil return nil
@ -51,7 +51,7 @@ func UpdateTime(d []byte, t int) error {
if err != nil { if err != nil {
return err return err
} }
ts := TimeToBytes(uint64(t)) ts := TimeBytes(uint64(t))
for i := range d[timeIndx : timeIndx+8] { for i := range d[timeIndx : timeIndx+8] {
d[i+timeIndx] = ts[i] d[i+timeIndx] = ts[i]
} }
@ -68,3 +68,9 @@ func TimeOf(d []byte) (t uint64, err error) {
} }
return t, nil return t, nil
} }
func GpsStrBytes(l string) (out []byte) {
out = make([]byte, gpsSize)
copy(out, []byte(l))
return
}

View File

@ -50,8 +50,17 @@ const (
// Consts relating to time description // Consts relating to time description
const ( const (
timeDescTag = 234 timeDescTag = 234
descTagIndx = 13 timeTagIndx = 13
timeIndx = 15 timeIndx = 15
timeSize = 8
)
// Consts relating to gps description
const (
gpsDescTag = 235
gpsTagIndx = 23
gpsIndx = 25
gpsSize = 32 // bytes
) )
// Program specific information // Program specific information

View File

@ -31,94 +31,95 @@ import (
"testing" "testing"
) )
// Times as ints for testing
const ( const (
tstTime = 1235367435 // 0x49A2360B tstTime1 = 1235367435 // 0x49A2360B
tstTime2 = 1735357535 // 0x676F745F tstTime2 = 1735357535 // 0x676F745F
) )
// GPS string for testing
const (
gpsTstStr1 = "$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47"
gpsTstStr2 = "$GPGGA,183710,4902.048,N,02171.020,E,1,09,0.5,547.2,M,43.4,M,,*42"
)
// err message
const ( const (
errCmp = "Incorrect output, for: %v wanted: %v, got: %v" errCmp = "Incorrect output, for: %v wanted: %v, got: %v"
) )
// Frist write tests // Test time to bytes test Data
var ( var (
timeSlice = []byte{ timeSlice = []byte{
0x00, 0x00, 0x00, 0x00, 0x49, 0xA2, 0x36, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x49, 0xA2, 0x36, 0x0B,
} }
patPsi1 = PSI{ )
Pf: 0x00,
Tid: 0x00,
Ssi: true,
Pb: false,
Sl: uint16(0x0d),
Tss: &TSS{
Tide: uint16(0x01),
V: 0,
Cni: true,
Sn: 0,
Lsn: 0,
Sd: &PAT{
Pn: uint16(0x01),
Pmpid: uint16(0x1000),
},
},
}
pmtPsi1 = PSI{
Pf: 0x00,
Tid: 0x02,
Ssi: true,
Sl: uint16(0x12),
Tss: &TSS{
Tide: uint16(0x01),
V: 0,
Cni: true,
Sn: 0,
Lsn: 0,
Sd: &PMT{
Pcrpid: 0x0100, // wrong
Pil: 0,
Essd: &ESSD{
St: 0x1b,
Epid: 0x0100,
Esil: 0x00,
},
},
},
}
// pmt with descriptor in it
StdPmtTime = []byte{
0x00, // pointer
// ---- section included in data sent to CRC32 during check // Parts to construct bytes of pmt with time and bytes
// table header var (
0x02, // table id pmtTimeGpsBytesPart1 = []byte{
0xb0, // section syntax indicator:1|private bit:1|reserved:2|section length:2|more bytes...:2 0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, 0x00, 0xe1, 0x00, 0xf0, 0x0a,
0x12, // more bytes... byte(timeDescTag), // Descriptor tag for timestamp
byte(timeSize), // Length of bytes to follow
0x00, 0x00, 0x00, 0x00, 0x67, 0x6F, 0x74, 0x5F, // Timestamp data
byte(gpsDescTag), // Descriptor tag for gps
byte(gpsSize), // Length of bytes to follow
}
pmtTimeGpsBytesPart2 = []byte{
0x1b, 0xe1, 0x00, 0xf0, 0x00,
}
)
// syntax section var (
0x00, 0x01, // table id extension // Bytes representing pmt with tstTime1
0xc1, // reserved bits:3|version:5|use now:1 pmtTimeBytes1 = []byte{
0x00, // section number 0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, 0x00, 0xe1, 0x00, 0xf0, 0x0a,
0x00, // last section number
// table data
0xe1, 0x00, // reserved:3|PCR PID:13
0xf0, 0x0a, // reserved:4|unused:2|program info length:10
// Desriptor
byte(timeDescTag), // Descriptor tag byte(timeDescTag), // Descriptor tag
byte(8), // Length of bytes to follow byte(timeSize), // Length of bytes to follow
0x00, 0x00, 0x00, 0x00, 0x49, 0xA2, 0x36, 0x0B, // timestamp 0x00, 0x00, 0x00, 0x00, 0x49, 0xA2, 0x36, 0x0B, // timestamp
// No program descriptors since program info length is 0. 0x1b, 0xe1, 0x00, 0xf0, 0x00,
// elementary stream info data
0x1b, // stream type
0xe1, 0x00, // reserved:3|elementary PID:13
0xf0, 0x00, // reserved:4|unused:2|ES info length:10
// No elementary stream descriptors since ES info length is 0.
// 0x15, 0xbd, 0x4d, 0x56, // CRC
// ----
} }
pmtPsiTime = PSI{
// Bytes representing pmt with tstTime 2
pmtTimeBytes2 = []byte{
0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, 0x00, 0xe1, 0x00, 0xf0, 0x0a,
byte(timeDescTag), // Descriptor tag
byte(timeSize), // Length of bytes to follow
0x00, 0x00, 0x00, 0x00, 0x67, 0x6F, 0x74, 0x5F, // timestamp
0x1b, 0xe1, 0x00, 0xf0, 0x00,
}
// Bytes representing pmt with time1 and gps1
pmtTimeGpsBytes1 = buildPmtTimeGpsBytes(gpsTstStr1)
// bytes representing pmt with with time1 and gps 2
pmtTimeGpsBytes2 = buildPmtTimeGpsBytes(gpsTstStr2)
)
// bytesTests contains data for testing the Bytes() funcs for the PSI data struct
var bytesTests = []struct {
name string
input PSI
want []byte
}{
// Pat test
{
name: "pat Bytes()",
input: stdPat,
want: stdPatBytes,
},
// Pmt test data no descriptor
{
name: "pmt to Bytes() without descriptors",
input: stdPmt,
want: stdPmtBytes,
},
// Pmt with time descriptor
{
name: "pmt to Bytes() with time descriptor",
input: PSI{
Pf: 0x00, Pf: 0x00,
Tid: 0x02, Tid: 0x02,
Ssi: true, Ssi: true,
@ -135,8 +136,8 @@ var (
Pd: []Desc{ Pd: []Desc{
Desc{ Desc{
Dt: byte(timeDescTag), Dt: byte(timeDescTag),
Dl: byte(8), Dl: byte(timeSize),
Dd: TimeToBytes(tstTime), Dd: TimeBytes(tstTime1),
}, },
}, },
Essd: &ESSD{ Essd: &ESSD{
@ -146,97 +147,108 @@ var (
}, },
}, },
}, },
},
want: pmtTimeBytes1,
},
// Pmt with time and gps
{
name: "pmt Bytes() with time and gps",
input: PSI{
Pf: 0x00,
Tid: 0x02,
Ssi: true,
Sl: uint16(0x12),
Tss: &TSS{
Tide: uint16(0x01),
V: 0,
Cni: true,
Sn: 0,
Lsn: 0,
Sd: &PMT{
Pcrpid: 0x0100, // wrong
Pil: 10,
Pd: []Desc{
Desc{
Dt: byte(timeDescTag),
Dl: byte(timeSize),
Dd: TimeBytes(tstTime2),
},
Desc{
Dt: byte(gpsDescTag),
Dl: byte(gpsSize),
Dd: GpsStrBytes(gpsTstStr1),
},
},
Essd: &ESSD{
St: 0x1b,
Epid: 0x0100,
Esil: 0x00,
},
},
},
},
want: buildPmtTimeGpsBytes(gpsTstStr1),
},
} }
// pmt with descriptor in it
StdPmtTime2 = []byte{
0x00, // pointer
// ---- section included in data sent to CRC32 during check // TestBytes ensures that the Bytes() funcs are working correctly to take PSI
// table header // structs and converting them to byte slices
0x02, // table id func TestBytes(t *testing.T) {
0xb0, // section syntax indicator:1|private bit:1|reserved:2|section length:2|more bytes...:2 for _, test := range bytesTests {
0x12, // more bytes... got := test.input.Bytes()
// Remove crc32s
// syntax section
0x00, 0x01, // table id extension
0xc1, // reserved bits:3|version:5|use now:1
0x00, // section number
0x00, // last section number
// table data
0xe1, 0x00, // reserved:3|PCR PID:13
0xf0, 0x0a, // reserved:4|unused:2|program info length:10
// Desriptor
byte(timeDescTag), // Descriptor tag
byte(8), // Length of bytes to follow
0x00, 0x00, 0x00, 0x00, 0x67, 0x6F, 0x74, 0x5F, // timestamp
// No program descriptors since program info length is 0.
// elementary stream info data
0x1b, // stream type
0xe1, 0x00, // reserved:3|elementary PID:13
0xf0, 0x00, // reserved:4|unused:2|ES info length:10
// No elementary stream descriptors since ES info length is 0.
// 0x15, 0xbd, 0x4d, 0x56, // CRC
// ----
}
)
// Test Bytes for a standard pat
func TestBytesPAT1(t *testing.T) {
got := patPsi1.Bytes()
// Remove crc32
got = got[:len(got)-4] got = got[:len(got)-4]
if !bytes.Equal(StdPat, got) { if !bytes.Equal(got, test.want) {
t.Errorf(errCmp, "TestBytesPAT1", StdPat, got) t.Errorf("unexpected error for test %v: got:%v want:%v", test.name, got,
test.want)
} }
} }
// Test Bytes for a standard pmt
func TestBytesPMT1(t *testing.T) {
got := pmtPsi1.Bytes()
// Remove crc32
got = got[:len(got)-4]
if !bytes.Equal(StdPmt, got) {
t.Errorf(errCmp, "TestBytesPMT1", StdPmt, got)
}
} }
// A quick sanity check of the int64 time to []byte func // A quick sanity check of the int64 time to []byte func
func TestTimestampToBytes(t *testing.T) { func TestTimestampToBytes(t *testing.T) {
timeBytes := TimeToBytes(tstTime) tb := TimeBytes(tstTime1)
if !bytes.Equal(timeSlice, timeBytes) { if !bytes.Equal(timeSlice, tb) {
t.Errorf(errCmp, "testTimeStampToBytes", timeSlice, timeBytes) t.Errorf(errCmp, "testTimeStampToBytes", timeSlice, tb)
}
}
// Test Bytes for a a standard PMT with a descripot containing a timestamp
func TestBytesPmt2(t *testing.T) {
got := pmtPsiTime.Bytes()
// Remove crc32
got = got[:len(got)-4]
if !bytes.Equal(StdPmtTime, got) {
t.Errorf(errCmp, "testBytesPmt2", StdPmtTime, got)
} }
} }
func TestTimeUpdate(t *testing.T) { func TestTimeUpdate(t *testing.T) {
cpy := make([]byte, len(StdPmtTime)) cpy := make([]byte, len(pmtTimeBytes1))
copy(cpy, StdPmtTime) copy(cpy, pmtTimeBytes1)
err := UpdateTime(cpy, tstTime2) err := UpdateTime(cpy, tstTime2)
if err != nil { if err != nil {
t.Errorf("Update time returned err: %v", err) t.Errorf("Update time returned err: %v", err)
} }
if !bytes.Equal(StdPmtTime2, cpy) { if !bytes.Equal(pmtTimeBytes2, cpy) {
t.Errorf(errCmp, "TestTimeUpdate", StdPmtTime2, cpy) t.Errorf(errCmp, "TestTimeUpdate", pmtTimeBytes2, cpy)
} }
} }
func TestTimeGet(t *testing.T) { func TestTimeGet(t *testing.T) {
s, err := TimeOf(StdPmtTime) s, err := TimeOf(pmtTimeBytes1)
if err != nil { if err != nil {
t.Errorf("Getting timestamp failed with err: %v", err) t.Errorf("Getting timestamp failed with err: %v", err)
} }
if s != tstTime { if s != tstTime1 {
t.Errorf(errCmp, "TestTimeGet", tstTime, s) t.Errorf(errCmp, "TestTimeGet", tstTime1, s)
} }
} }
func TestGpsUpdate(t *testing.T) {
cpy := make([]byte, len(pmtTimeGpsBytes1))
copy(cpy, pmtTimeGpsBytes1)
err := UpdateGps(cpy, tstTime2)
if err != nil {
t.Errorf("Update time returned err: %v", err)
}
if !bytes.Equal(pmtTimeGpsBytes2, cpy) {
t.Errorf(errCmp, "TestGpsUpdate", pmtTimeGpsBytes2, cpy)
}
}
func buildPmtTimeGpsBytes(tstStr string) []byte {
return append(append(append(make([]byte, 0), pmtTimeGpsBytesPart1...),
GpsStrBytes(tstStr)...), pmtTimeGpsBytesPart2...)
}

View File

@ -26,10 +26,54 @@ LICENSE
package psi package psi
// TODO: Finish off mts/psi so that we can create pat and pmt tables instead // Std PSI in struct form without descriptor
// of hardcoding.
var ( var (
StdPat = []byte{ stdPat = PSI{
Pf: 0x00,
Tid: 0x00,
Ssi: true,
Pb: false,
Sl: uint16(0x0d),
Tss: &TSS{
Tide: uint16(0x01),
V: 0,
Cni: true,
Sn: 0,
Lsn: 0,
Sd: &PAT{
Pn: uint16(0x01),
Pmpid: uint16(0x1000),
},
},
}
stdPmt = PSI{
Pf: 0x00,
Tid: 0x02,
Ssi: true,
Sl: uint16(0x12),
Tss: &TSS{
Tide: uint16(0x01),
V: 0,
Cni: true,
Sn: 0,
Lsn: 0,
Sd: &PMT{
Pcrpid: 0x0100, // wrong
Pil: 0,
Essd: &ESSD{
St: 0x1b,
Epid: 0x0100,
Esil: 0x00,
},
},
},
}
)
// Std PSI in bytes form
var (
stdPatBytes = []byte{
0x00, // pointer 0x00, // pointer
// ---- section included in data sent to CRC32 during check // ---- section included in data sent to CRC32 during check
@ -50,7 +94,7 @@ var (
// 0x2a, 0xb1, 0x04, 0xb2, // CRC // 0x2a, 0xb1, 0x04, 0xb2, // CRC
// ---- // ----
} }
StdPmt = []byte{ stdPmtBytes = []byte{
0x00, // pointer 0x00, // pointer
// ---- section included in data sent to CRC32 during check // ---- section included in data sent to CRC32 during check