Add stm GO library 43/138543/3
authorAleksander Mistewicz <a.mistewicz@samsung.com>
Tue, 11 Jul 2017 16:48:29 +0000 (18:48 +0200)
committerAleksander Mistewicz <a.mistewicz@samsung.com>
Wed, 13 Sep 2017 10:37:09 +0000 (12:37 +0200)
It uses non-standard GO library for serial communication
(BSD 3-clause License). Fetch it with:
    go get "github.com/tarm/serial"

Change-Id: I7b57d063d0296b66de880a61a1878ce2abd1f606

stm/stm.go [new file with mode: 0644]

diff --git a/stm/stm.go b/stm/stm.go
new file mode 100644 (file)
index 0000000..16622c5
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+// Package stm implements communication with STM32F030 found on MuxPi.
+package stm
+
+import (
+       "bufio"
+       "fmt"
+       "io"
+       "strings"
+       "sync"
+
+       "github.com/tarm/serial"
+)
+
+const (
+       respOK     = "OK"
+       retryLimit = 8
+)
+
+// STM provides methods to execute commands via serial interface.
+//
+// It is safe for concurrent use.
+type STM struct {
+       config *serial.Config
+       port   *serial.Port
+       reader *bufio.Reader
+       mux    *sync.Mutex
+}
+
+// NewSTM prepares STM structure with serial configuration.
+func NewSTM(ttyPath string, baudrate int) *STM {
+       return &STM{
+               config: &serial.Config{
+                       Name:     ttyPath,
+                       Baud:     baudrate,
+                       Size:     8,
+                       Parity:   serial.ParityNone,
+                       StopBits: serial.Stop1,
+               },
+               mux: new(sync.Mutex),
+       }
+}
+
+// Open starts a serial connection.
+//
+// It should be called only once after structure creation
+// or in case the connection has been terminated with Close().
+func (stm *STM) Open() (err error) {
+       stm.port, err = serial.OpenPort(stm.config)
+       if err != nil {
+               return err
+       }
+       stm.reader = bufio.NewReader(stm.port)
+       return stm.noEcho()
+}
+
+// Close terminates the serial connection.
+//
+// It should be called only once after the connection has been created with Open().
+func (stm *STM) Close() error {
+       return stm.port.Close()
+}
+
+// readResponse reads a single line from the reader.
+//
+// It should not be used by public functions unless they are aware of the locking.
+func (stm *STM) readResponse() (string, error) {
+       response, _, err := stm.reader.ReadLine()
+       if err != nil {
+               return "", fmt.Errorf("failed to read a response: %s", err)
+       }
+       return string(response), nil
+}
+
+// checkOK reads a line from the buffer and rises an error
+// if it is not an expected confirmation response.
+//
+// It should not be used by public functions unless they are aware of the locking.
+func (stm *STM) checkOK() error {
+       resp, err := stm.readResponse()
+       if err != nil {
+               return err
+       }
+       if resp != respOK {
+               return fmt.Errorf("unexpected response: %s", resp)
+       }
+       return nil
+}
+
+// executeCommand sends a prepared cmd string and checks the response.
+func (stm *STM) executeCommand(cmd string) (err error) {
+       stm.mux.Lock()
+       defer stm.mux.Unlock()
+       _, err = io.WriteString(stm.port, cmd+"\n")
+       if err != nil {
+               return fmt.Errorf("failed to write a command: %s", err)
+       }
+       return stm.checkOK()
+}
+
+// noEcho requires special handling as there are more possible responses.
+func (stm *STM) noEcho() (err error) {
+       stm.mux.Lock()
+       defer stm.mux.Unlock()
+       _, err = io.WriteString(stm.port, "echo off\n")
+       if err != nil {
+               return fmt.Errorf("failed to write a command: %s", err)
+       }
+       for i := 0; i < retryLimit; i++ {
+               resp, err := stm.readResponse()
+               if err != nil {
+                       return err
+               }
+               if resp == "echo off" || strings.Contains(resp, "Echo is off now") {
+                       continue
+               }
+               if resp == respOK {
+                       return nil
+               }
+               return fmt.Errorf("unexpected response: %s", resp)
+       }
+       return fmt.Errorf("retry limit exceeded")
+}