Skip to content
Snippets Groups Projects
Commit a0056341 authored by Sebastien Binet's avatar Sebastien Binet
Browse files

dif: implement Encoder

parent 89902315
No related branches found
No related tags found
No related merge requests found
......@@ -95,7 +95,7 @@ func (dec *Decoder) Decode(dif *DIF) error {
dif.Header.DTC = binary.BigEndian.Uint32(hdr[1 : 1+4])
dif.Header.ATC = binary.BigEndian.Uint32(hdr[5 : 5+4])
dif.Header.GTC = binary.BigEndian.Uint32(hdr[9 : 9+4])
copy(dif.Header.AbsBCID[:], hdr[13:15+4])
copy(dif.Header.AbsBCID[:], hdr[13:13+6])
copy(dif.Header.TimeDIFTC[:], hdr[19:19+3])
dif.Frames = dif.Frames[:0]
......@@ -203,8 +203,9 @@ func (dec *Decoder) readU8() uint8 {
}
func (dec *Decoder) readU16() uint16 {
dec.load(2)
return binary.BigEndian.Uint16(dec.buf[:2])
const n = 2
dec.load(n)
return binary.BigEndian.Uint16(dec.buf[:n])
}
func (dec *Decoder) load(n int) {
......
// Copyright 2020 The go-lpc Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package dif
import (
"encoding/binary"
"io"
"github.com/go-lpc/mim/internal/crc16"
"golang.org/x/xerrors"
)
type Encoder struct {
w io.Writer
buf []byte
err error
crc crc16.Hash16
}
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{
w: w,
buf: make([]byte, 8),
crc: crc16.New(nil),
}
}
func (enc *Encoder) crcw(p []byte) {
_, _ = enc.crc.Write(p) // can not fail.
}
func (enc *Encoder) reset() {
enc.crc.Reset()
}
func (enc *Encoder) Encode(dif *DIF) error {
if dif == nil {
return nil
}
enc.reset()
enc.writeU8(gbHeader)
if enc.err != nil {
return xerrors.Errorf("dif: could not write global header marker: %w", enc.err)
}
enc.writeU8(dif.Header.ID)
enc.writeU32(dif.Header.DTC)
enc.writeU32(dif.Header.ATC)
enc.writeU32(dif.Header.GTC)
enc.write(dif.Header.AbsBCID[:])
enc.write(dif.Header.TimeDIFTC[:])
enc.writeU8(0) // nlines
enc.writeU8(frHeader)
for _, frame := range dif.Frames {
enc.writeU8(frame.Header)
enc.write(frame.BCID[:])
enc.write(frame.Data[:])
}
enc.writeU8(frTrailer)
crc := enc.crc.Sum16() // gb-trailer not part of CRC-16
enc.writeU8(gbTrailer)
enc.writeU16(crc)
return enc.err
}
func (enc *Encoder) write(p []byte) {
if enc.err != nil {
return
}
_, enc.err = enc.w.Write(p)
enc.crcw(p)
}
func (enc *Encoder) writeU8(v uint8) {
const n = 1
enc.reserve(n)
enc.buf[0] = v
enc.write(enc.buf[:n])
}
func (enc *Encoder) writeU16(v uint16) {
const n = 2
enc.reserve(n)
binary.BigEndian.PutUint16(enc.buf[:n], v)
enc.write(enc.buf[:n])
}
func (enc *Encoder) writeU32(v uint32) {
const n = 4
enc.reserve(n)
binary.BigEndian.PutUint32(enc.buf[:n], v)
enc.write(enc.buf[:n])
}
func (enc *Encoder) reserve(n int) {
if cap(enc.buf) < n {
enc.buf = append(enc.buf[:len(enc.buf)], make([]byte, n-cap(enc.buf))...)
}
}
......@@ -7,11 +7,117 @@ package dif
import (
"bytes"
"io"
"reflect"
"testing"
"golang.org/x/xerrors"
)
func TestCodec(t *testing.T) {
const (
difID = 0x42
)
for _, tc := range []struct {
name string
dif DIF
}{
{
name: "normal",
dif: DIF{
Header: GlobalHeader{
ID: difID,
DTC: 10,
ATC: 11,
GTC: 12,
AbsBCID: [6]uint8{1, 2, 3, 4, 5, 6},
TimeDIFTC: [3]uint8{10, 11, 12},
},
Frames: []Frame{
{
Header: 1,
BCID: [3]uint8{10, 11, 12},
Data: [16]uint8{0xa, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
},
{
Header: 2,
BCID: [3]uint8{20, 21, 22},
Data: [16]uint8{
0xb, 21, 22, 23, 24, 25, 26, 27, 28, 29,
210, 211, 212, 213, 214, 215,
},
},
},
},
},
{
name: "no-frame",
dif: DIF{
Header: GlobalHeader{
ID: difID,
DTC: 10,
ATC: 11,
GTC: 12,
AbsBCID: [6]uint8{1, 2, 3, 4, 5, 6},
TimeDIFTC: [3]uint8{10, 11, 12},
},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
buf := new(bytes.Buffer)
enc := NewEncoder(buf)
err := enc.Encode(&tc.dif)
if err != nil {
t.Fatalf("could not encode dif frames: %+v", err)
}
dec := NewDecoder(difID, buf)
var got DIF
err = dec.Decode(&got)
if err != nil {
t.Fatalf("could not decode dif frames: %+v", err)
}
if got, want := got, tc.dif; !reflect.DeepEqual(got, want) {
t.Fatalf("invalid r/w round-trip:\ngot= %#v\nwant=%#v", got, want)
}
})
}
}
func TestEncoder(t *testing.T) {
{
buf := new(bytes.Buffer)
enc := NewEncoder(buf)
if got, want := enc.Encode(nil), error(nil); got != want {
t.Fatalf("invalid nil-dif encoding: got=%v, want=%v", got, want)
}
}
{
buf := failingWriter{n: 0}
enc := NewEncoder(&buf)
if got, want := enc.Encode(&DIF{}), xerrors.Errorf("dif: could not write global header marker: %w", io.ErrUnexpectedEOF); got.Error() != want.Error() {
t.Fatalf("invalid error:\ngot= %+v\nwant=%+v", got, want)
}
}
}
type failingWriter struct {
n int
cur int
}
func (w *failingWriter) Write(p []byte) (int, error) {
w.cur += len(p)
if w.cur >= w.n {
return 0, io.ErrUnexpectedEOF
}
return len(p), nil
}
func TestDecoder(t *testing.T) {
const (
difID = 0x42
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment