From f033fb5c2bf4097915eb8faf9d399a213452f6a8 Mon Sep 17 00:00:00 2001 From: Andre Renaud Date: Thu, 22 Dec 2022 16:49:08 +1300 Subject: [PATCH 1/4] Added in "ModeFromString" for turning standard serial port mode notation into the Mode structure --- serial.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ serial_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 serial_test.go diff --git a/serial.go b/serial.go index e072d42..cc9c35a 100644 --- a/serial.go +++ b/serial.go @@ -199,3 +199,52 @@ func (e PortError) Error() string { func (e PortError) Code() PortErrorCode { return e.code } + +// ModeFromString turns a string description of a serial mode (such as "8N1") into +// the appropriate Mode structure. The default of 8N1 will be used if any values +// are not specified. +// See https://en.wikipedia.org/wiki/8-N-1 for details +func ModeFromString(smode string) (*Mode, error) { + mode := &Mode{DataBits: 8, Parity: NoParity, StopBits: OneStopBit} + if len(smode) > 0 { + switch smode[0] { + case '8': + mode.DataBits = 8 + case '7': + mode.DataBits = 7 + case '6': + mode.DataBits = 6 + case '5': + mode.DataBits = 5 + default: + return nil, &PortError{code: InvalidDataBits} + } + } + if len(smode) > 1 { + switch smode[1] { + case 'E': + mode.Parity = EvenParity + case 'N': + mode.Parity = NoParity + case 'O': + mode.Parity = OddParity + case 'M': + mode.Parity = MarkParity + case 'S': + mode.Parity = SpaceParity + default: + return nil, &PortError{code: InvalidParity} + } + } + if len(smode) > 2 { + switch smode[2] { + case '1': + mode.StopBits = OneStopBit + case '2': + mode.StopBits = TwoStopBits + default: + return nil, &PortError{code: InvalidStopBits} + } + } + return mode, nil +} diff --git a/serial_test.go b/serial_test.go new file mode 100644 index 0000000..8ca416d --- /dev/null +++ b/serial_test.go @@ -0,0 +1,38 @@ +package serial + +import ( + "errors" + "reflect" + "testing" +) + +func TestModeFromString(t *testing.T) { + good_cases := map[string]*Mode{ + "8N1": {DataBits: 8, Parity: NoParity, StopBits: OneStopBit}, + "7S2": {DataBits: 7, Parity: SpaceParity, StopBits: TwoStopBits}, + } + + bad_cases := map[string]error{ + "9N1": &PortError{code: InvalidDataBits}, + "8N3": &PortError{code: InvalidStopBits}, + "8R1": &PortError{code: InvalidParity}, + } + + for s, m := range good_cases { + res, err := ModeFromString(s) + if err != nil { + t.Errorf("Failed to convert mode %q: %s", s, err) + } else if !reflect.DeepEqual(res, m) { + t.Errorf("Mode %q should convert to %+v, got %+v", s, m, res) + } + } + + for s, e := range bad_cases { + res, err := ModeFromString(s) + if err == nil { + t.Errorf("Mode %q should be invalid, got %v", s, res) + } else if errors.Is(err, e) { + t.Errorf("Mode %q should fail with %v, got %v", s, e, err) + } + } +} From 208024646a0d8a79091a405f7332c35a485032d1 Mon Sep 17 00:00:00 2001 From: Andre Renaud Date: Fri, 23 Dec 2022 08:13:43 +1300 Subject: [PATCH 2/4] Move to populate an existing structure, which makes applying other settings easier --- serial.go | 16 +++++++--------- serial_test.go | 12 +++++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/serial.go b/serial.go index cc9c35a..7b83d27 100644 --- a/serial.go +++ b/serial.go @@ -200,12 +200,10 @@ func (e PortError) Code() PortErrorCode { return e.code } -// ModeFromString turns a string description of a serial mode (such as "8N1") into -// the appropriate Mode structure. The default of 8N1 will be used if any values -// are not specified. +// ModeFromString uses a string description of a serial mode (such as "8N1") +// to partially populate a Mode structure. // See https://en.wikipedia.org/wiki/8-N-1 for details -func ModeFromString(smode string) (*Mode, error) { - mode := &Mode{DataBits: 8, Parity: NoParity, StopBits: OneStopBit} +func ModeFromString(smode string, mode *Mode) error { if len(smode) > 0 { switch smode[0] { case '8': @@ -217,7 +215,7 @@ func ModeFromString(smode string) (*Mode, error) { case '5': mode.DataBits = 5 default: - return nil, &PortError{code: InvalidDataBits} + return &PortError{code: InvalidDataBits} } } if len(smode) > 1 { @@ -233,7 +231,7 @@ func ModeFromString(smode string) (*Mode, error) { case 'S': mode.Parity = SpaceParity default: - return nil, &PortError{code: InvalidParity} + return &PortError{code: InvalidParity} } } if len(smode) > 2 { @@ -243,8 +241,8 @@ func ModeFromString(smode string) (*Mode, error) { case '2': mode.StopBits = TwoStopBits default: - return nil, &PortError{code: InvalidStopBits} + return &PortError{code: InvalidStopBits} } } - return mode, nil + return nil } diff --git a/serial_test.go b/serial_test.go index 8ca416d..1f98dc7 100644 --- a/serial_test.go +++ b/serial_test.go @@ -19,18 +19,20 @@ func TestModeFromString(t *testing.T) { } for s, m := range good_cases { - res, err := ModeFromString(s) + mode := &Mode{} + err := ModeFromString(s, mode) if err != nil { t.Errorf("Failed to convert mode %q: %s", s, err) - } else if !reflect.DeepEqual(res, m) { - t.Errorf("Mode %q should convert to %+v, got %+v", s, m, res) + } else if !reflect.DeepEqual(mode, m) { + t.Errorf("Mode %q should convert to %+v, got %+v", s, m, mode) } } for s, e := range bad_cases { - res, err := ModeFromString(s) + mode := &Mode{} + err := ModeFromString(s, mode) if err == nil { - t.Errorf("Mode %q should be invalid, got %v", s, res) + t.Errorf("Mode %q should be invalid, got %v", s, mode) } else if errors.Is(err, e) { t.Errorf("Mode %q should fail with %v, got %v", s, e, err) } From 7e6be5cc22723a649a5378a78a1ac3d00adb82b6 Mon Sep 17 00:00:00 2001 From: Andre Renaud Date: Mon, 9 Jan 2023 08:44:24 +1300 Subject: [PATCH 3/4] Fix up error testing - errors.Is didn't match properly --- serial_test.go | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/serial_test.go b/serial_test.go index 1f98dc7..f7a41e0 100644 --- a/serial_test.go +++ b/serial_test.go @@ -1,7 +1,6 @@ package serial import ( - "errors" "reflect" "testing" ) @@ -12,10 +11,10 @@ func TestModeFromString(t *testing.T) { "7S2": {DataBits: 7, Parity: SpaceParity, StopBits: TwoStopBits}, } - bad_cases := map[string]error{ - "9N1": &PortError{code: InvalidDataBits}, - "8N3": &PortError{code: InvalidStopBits}, - "8R1": &PortError{code: InvalidParity}, + bad_cases := map[string]*PortError{ + "9N1": {code: InvalidDataBits}, + "8N3": {code: InvalidStopBits}, + "8R1": {code: InvalidParity}, } for s, m := range good_cases { @@ -33,8 +32,16 @@ func TestModeFromString(t *testing.T) { err := ModeFromString(s, mode) if err == nil { t.Errorf("Mode %q should be invalid, got %v", s, mode) - } else if errors.Is(err, e) { - t.Errorf("Mode %q should fail with %v, got %v", s, e, err) + } else { + switch pe := err.(type) { + case *PortError: + if pe.code != e.code { + t.Errorf("Mode %q should fail with %v, got %v", s, e, err) + + } + default: + t.Errorf("Mode %q should fail with %v, got %v", s, e, err) + } } } } From f852eeb91c50bb5aceb830067b4a260ad66593ab Mon Sep 17 00:00:00 2001 From: Andre Renaud Date: Tue, 31 Jan 2023 16:48:36 +1300 Subject: [PATCH 4/4] Simplify test error checking --- serial_test.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/serial_test.go b/serial_test.go index f7a41e0..af2b3ad 100644 --- a/serial_test.go +++ b/serial_test.go @@ -32,16 +32,8 @@ func TestModeFromString(t *testing.T) { err := ModeFromString(s, mode) if err == nil { t.Errorf("Mode %q should be invalid, got %v", s, mode) - } else { - switch pe := err.(type) { - case *PortError: - if pe.code != e.code { - t.Errorf("Mode %q should fail with %v, got %v", s, e, err) - - } - default: - t.Errorf("Mode %q should fail with %v, got %v", s, e, err) - } + } else if pe, ok := err.(*PortError); !ok || pe.code != e.code { + t.Errorf("Mode %q should fail with %v, got %v", s, e, err) } } }