const (
headerLength = 3
maxDataLength = 1021
maxFrameLength = 1024
)
var (
ErrUnexpectedFrameType = errors.New("unexpected frame type")
ErrUnknownFrameType = errors.New("unknown frame type")
)
type HapticFrame struct {
Type entities.FrameType
Data []byte
dataLength uint16
}
func NewHapticFrame(t entities.FrameType, data []byte) *HapticFrame {
return &HapticFrame{
Type: t,
Data: data,
}
}
// ReadNextFrame reads a single frame from the stream.
// It returns an error if the frame is invalid or the stream is closed.
func ReadNextFrame(s io.Reader) (*HapticFrame, error) {
frame := &HapticFrame{}
// Read the frame type
if err := frame.readType(s); err != nil {
return nil, err
}
// Read the frame length
if err := frame.readLength(s); err != nil {
return nil, err
}
// Read the frame data
buf, n, err := readN(s, int(frame.dataLength))
if err != nil {
return nil, err
}
if n == int(frame.dataLength) {
frame.Data = buf
return frame, nil
}
return nil, fmt.Errorf("invalid frame length %d, expected %d", n, frame.dataLength)
}
// readType reads the frame type (always the first byte of the frame).
func (f *HapticFrame) readType(s io.Reader) error {
buf, n, err := readN(s, 1)
if err != nil {
return err
}
if n == 1 {
ft := entities.FrameType(buf[0])
if ft != entities.FrameType_UNKNOWN && ft <= entities.FrameType_CONNECTION_INFO {
f.Type = ft
return nil
}
}
return ErrUnknownFrameType
}
func (f *HapticFrame) Length() uint16 {
if f.dataLength == 0 {
f.dataLength = uint16(len(f.Data))
}
return f.dataLength
}
// readLength reads the frame length (second and third bytes of the frame).
func (f *HapticFrame) readLength(s io.Reader) error {
buf, n, err := readN(s, 2)
if err != nil {
return err
}
if n == 2 {
f.dataLength = binary.LittleEndian.Uint16(buf) - headerLength
if f.dataLength > 0 && f.dataLength <= maxDataLength {
return nil
}
}
return ErrInvalidLength(int(f.dataLength))
}
// readN reads until n bytes have been read.
func readN(s io.Reader, n int) ([]byte, int, error) {
k := 0
buf := make([]byte, n)
for k < n {
kk, err := s.Read(buf[k:])
if err != nil {
return nil, k, err
}
k += kk
}
return buf, k, nil
}