2020-04-12 16:37:58 -06:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/binary"
|
2020-05-30 22:23:53 -06:00
|
|
|
"time"
|
2020-04-12 16:37:58 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
// VailMessage is a single Vail message.
|
|
|
|
type Message struct {
|
|
|
|
// Relative time in ms of this message.
|
|
|
|
// These timestamps need to be consistent, but the offset can be anything.
|
|
|
|
// ECMAScript `performance.now()` is ideal.
|
2020-05-30 22:23:53 -06:00
|
|
|
Timestamp int64
|
2020-04-12 16:37:58 -06:00
|
|
|
|
|
|
|
// Message timing in ms.
|
|
|
|
// Timings alternate between tone and silence.
|
|
|
|
// For example, `A` could be sent as [80, 80, 240]
|
|
|
|
Duration []uint8
|
|
|
|
}
|
|
|
|
|
2020-05-30 22:23:53 -06:00
|
|
|
func NewMessage(ts time.Time, durations []time.Duration) Message {
|
|
|
|
msg := Message{
|
|
|
|
Timestamp: ts.UnixNano() / time.Millisecond.Nanoseconds(),
|
|
|
|
Duration: make([]uint8, len(durations)),
|
|
|
|
}
|
|
|
|
for i, dns := range durations {
|
|
|
|
ms := dns.Milliseconds()
|
|
|
|
if (ms > 255) {
|
|
|
|
ms = 255
|
|
|
|
} else if (ms < 0) {
|
|
|
|
ms = 0
|
|
|
|
}
|
|
|
|
msg.Duration[i] = uint8(ms)
|
|
|
|
}
|
|
|
|
return msg
|
|
|
|
}
|
|
|
|
|
2020-04-12 20:55:17 -06:00
|
|
|
// Marshaling presumes something else is keeping track of lengths
|
2020-04-12 16:37:58 -06:00
|
|
|
func (m Message) MarshalBinary() ([]byte, error) {
|
|
|
|
var w bytes.Buffer
|
|
|
|
if err := binary.Write(&w, binary.BigEndian, m.Timestamp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if err := binary.Write(&w, binary.BigEndian, m.Duration); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return w.Bytes(), nil
|
|
|
|
}
|
|
|
|
|
2020-04-12 20:55:17 -06:00
|
|
|
// Unmarshaling presumes something else is keeping track of lengths
|
2020-04-12 16:37:58 -06:00
|
|
|
func (m *Message) UnmarshalBinary(data []byte) error {
|
|
|
|
r := bytes.NewReader(data)
|
|
|
|
if err := binary.Read(r, binary.BigEndian, &m.Timestamp); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-04-12 20:55:17 -06:00
|
|
|
dlen := r.Len()
|
2020-04-12 16:37:58 -06:00
|
|
|
m.Duration = make([]uint8, dlen)
|
|
|
|
if err := binary.Read(r, binary.BigEndian, &m.Duration); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m Message) Equal(m2 Message) bool {
|
|
|
|
if m.Timestamp != m2.Timestamp {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(m.Duration) != len(m2.Duration) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := range m.Duration {
|
|
|
|
if m.Duration[i] != m2.Duration[i] {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|