Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: encoder endianness #82

Merged
merged 2 commits into from
Jan 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions encoder/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ const (
type headerOption byte

const (
littleEndian = 0
bigEndian = 1
defaultEndianess = littleEndian
littleEndian = 0
bigEndian = 1
defaultEndianness = littleEndian

// headerOptionNormal is the default header option.
// This option has two sub-option to select from:
Expand Down Expand Up @@ -84,14 +84,14 @@ type Encoder struct {
type options struct {
protocolVersion proto.Version
messageValidator MessageValidator
endianess byte
endianness byte
headerOption headerOption
multipleLocalMessageType byte
}

func defaultOptions() *options {
return &options{
endianess: defaultEndianess,
endianness: defaultEndianness,
protocolVersion: proto.V1,
messageValidator: NewMessageValidator(),
headerOption: headerOptionNormal,
Expand Down Expand Up @@ -122,7 +122,7 @@ func WithMessageValidator(validator MessageValidator) Option {

// WithBigEndian directs the Encoder to encode values in Big-Endian bytes order (default: Little-Endian).
func WithBigEndian() Option {
return fnApply(func(o *options) { o.endianess = bigEndian })
return fnApply(func(o *options) { o.endianness = bigEndian })
}

// WithCompressedTimestampHeader directs the Encoder to compress timestamp in header to reduce file size.
Expand Down Expand Up @@ -375,6 +375,7 @@ func (e *Encoder) encodeMessages(w io.Writer, messages []proto.Message) error {
// encodeMessage marshals and encodes message definition and its message into w.
func (e *Encoder) encodeMessage(w io.Writer, mesg *proto.Message) error {
mesg.Header = proto.MesgNormalHeaderMask
mesg.Architecture = e.options.endianness

if err := e.messageValidator.Validate(mesg); err != nil {
return fmt.Errorf("message validation failed: %w", err)
Expand Down
30 changes: 23 additions & 7 deletions encoder/encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func TestOptions(t *testing.T) {
opts: nil,
expected: &options{
multipleLocalMessageType: 0,
endianess: 0,
endianness: 0,
protocolVersion: proto.V1,
messageValidator: NewMessageValidator(),
},
Expand All @@ -127,7 +127,7 @@ func TestOptions(t *testing.T) {
},
expected: &options{
multipleLocalMessageType: 15,
endianess: 1,
endianness: 1,
protocolVersion: proto.V2,
messageValidator: fnValidateOK,
headerOption: headerOptionCompressedTimestamp,
Expand Down Expand Up @@ -562,11 +562,12 @@ func TestEncodeHeader(t *testing.T) {

func TestEncodeMessage(t *testing.T) {
tt := []struct {
name string
mesg proto.Message
opts []Option
w io.Writer
err error
name string
mesg proto.Message
opts []Option
w io.Writer
endianness byte
err error
}{
{
name: "encode message with default header option happy flow",
Expand All @@ -577,6 +578,17 @@ func TestEncodeMessage(t *testing.T) {
return 0, nil
}),
},
{
name: "encode message with big-endian",
mesg: factory.CreateMesg(mesgnum.FileId).WithFieldValues(map[byte]any{
fieldnum.FileIdType: typedef.FileActivity,
}),
w: fnWriter(func(b []byte) (n int, err error) {
return 0, nil
}),
opts: []Option{WithBigEndian()},
endianness: bigEndian,
},
{
name: "encode message with header normal multiple local message type happy flow",
opts: []Option{
Expand Down Expand Up @@ -692,6 +704,10 @@ func TestEncodeMessage(t *testing.T) {
if (tc.mesg.Header & proto.DevDataMask) == proto.DevDataMask {
t.Fatalf("message header should not contain Developer Data Flag")
}

if tc.mesg.Architecture != tc.endianness {
t.Fatalf("expected endianness: %d, got: %d", tc.endianness, tc.mesg.Architecture)
}
})
}
}
Expand Down
2 changes: 1 addition & 1 deletion profile/basetype/basetype.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ func (t BaseType) Kind() reflect.Kind {
return basetypes[t&BaseTypeNumMask].kind
}

// EndianAbility return whether t have endianess.
// EndianAbility return whether t have endianness.
func (t BaseType) EndianAbility() byte {
if !valid(t) {
return 0
Expand Down
2 changes: 1 addition & 1 deletion proto/proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ type Message struct {
Header byte // Message Header serves to distinguish whether the message is a Normal Data or a Compressed Timestamp Data. Unlike MessageDefinition, Message's Header should not contain Developer Data Flag.
Num typedef.MesgNum // Global Message Number defined in Global Fit Profile, except number within range 0xFF00 - 0xFFFE are manufacturer specific number.
Reserved byte // Currently undetermined; the default value is 0.
Architecture byte // Architecture type / Endianess. Must be the same
Architecture byte // Architecture type / Endianness. Must be the same
Fields []Field // List of Field
DeveloperFields []DeveloperField // List of DeveloperField
}
Expand Down
22 changes: 22 additions & 0 deletions proto/proto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,28 @@ func TestCreateMessageDefinition(t *testing.T) {
},
},
},
{
name: "fields only with mesg architecture big-endian",
mesg: func() proto.Message {
mesg := factory.CreateMesgOnly(mesgnum.FileId).WithFields(
factory.CreateField(mesgnum.FileId, fieldnum.FileIdType).WithValue(typedef.FileActivity),
)
mesg.Architecture = 1 // big-endian
return mesg
}(),
mesgDef: proto.MessageDefinition{
Header: proto.MesgDefinitionMask,
Architecture: 1, // big-endian
MesgNum: mesgnum.FileId,
FieldDefinitions: []proto.FieldDefinition{
{
Num: fieldnum.FileIdType,
Size: 1,
BaseType: basetype.Enum,
},
},
},
},
{
name: "fields only with string value",
mesg: factory.CreateMesgOnly(mesgnum.FileId).WithFields(
Expand Down