go-inthex/record.go

83 lines
1.6 KiB
Go

package go_inthex
import (
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"io"
"math"
"strings"
)
type RecordCode uint8
const ExtendedLinearAddressMask uint32 = 0xFFFF0000
const RecordExtendedSegmentAddressMask uint32 = 0x000FFFF0
const (
RecordData = RecordCode(iota)
RecordEOF
RecordExtendedSegmentAddress
RecordStartSegmentAddress
RecordExtendedLinearAddress
RecordStartLinearAddress
)
type Record struct {
Code RecordCode
Address uint16
Data []byte
}
func (r Record) String() string {
if len(r.Data) > math.MaxUint8 {
panic("data too long")
}
buf := make([]byte, 1+1+2+len(r.Data)+1)
buf[0] = uint8(len(r.Data))
binary.BigEndian.PutUint16(buf[1:], r.Address)
buf[3] = uint8(r.Code)
copy(buf[4:], r.Data)
buf[len(buf)-1] = Checksum(buf[:len(buf)-1])
return ":" + strings.ToUpper(hex.EncodeToString(buf)) + "\r\n"
}
func RecordFromString(data string) (Record, error) {
if data[0] != ':' {
return Record{}, fmt.Errorf("expected :, got %s", data[:1])
}
if len(data) < 1+(1+2+1)*2 {
return Record{}, io.ErrUnexpectedEOF
}
b, err := hex.DecodeString(strings.Trim(data[1:], "\r\n"))
if err != nil {
return Record{}, err
}
if len(b) < 1 {
return Record{}, io.ErrUnexpectedEOF
}
byteCount := b[0]
if len(b) != 1+1+2+int(byteCount)+1 {
return Record{}, errors.New("data mismatch")
}
var r Record
r.Address = binary.BigEndian.Uint16(b[1:])
r.Code = RecordCode(b[3])
r.Data = b[4 : 4+int(byteCount)]
checkSum := b[4+int(byteCount)]
calculatedCksum := Checksum(b[:len(b)-1])
if calculatedCksum != checkSum {
return Record{}, errors.New("wrong checksum")
}
return r, nil
}