From 4d992ef9be36098085a65bc7b621bb98d7d3992a Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 22 Mar 2025 15:21:51 +0100 Subject: [PATCH] Inital Working Dummy for basic Serial Communication --- MessageHandler/handler.go | 139 ++++++++++++++++++++++++++++++++ SerialInteraction/serial.go | 47 +++++++++++ SerialInteraction/serialMock.go | 30 +++++++ go.mod | 13 +++ go.sum | 16 ++++ main.go | 44 ++++++++++ 6 files changed, 289 insertions(+) create mode 100644 MessageHandler/handler.go create mode 100644 SerialInteraction/serial.go create mode 100644 SerialInteraction/serialMock.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/MessageHandler/handler.go b/MessageHandler/handler.go new file mode 100644 index 0000000..1688a65 --- /dev/null +++ b/MessageHandler/handler.go @@ -0,0 +1,139 @@ +package MessageHandler + +import ( + "fmt" + "log" + "net/http" + "strconv" + "strings" + "sync" + + "github.com/gorilla/websocket" +) + +type SerialInteraction interface { + ListComports() []string + Connect(string) error + Disconnect() + Write([]byte) (int, error) + Read([]byte) (int, error) + GetPortPath() string +} + +type MessageHandler struct { + Serial SerialInteraction + socket *websocket.Conn + socketLock sync.Mutex +} + +const ( + VERSION = "1" +) + +func (mh *MessageHandler) WebsocketHandle(w http.ResponseWriter, r *http.Request, c *websocket.Conn) { + for { + mt, message, err := c.ReadMessage() + if err != nil { + log.Printf("read: %v", err) + break + } + log.Printf("recv: %s", message) + answer := mh.messageDispatcher(string(message)) + mh.socketLock.Lock() + err = c.WriteMessage(mt, []byte(answer)) + mh.socketLock.Unlock() + if err != nil { + log.Printf("write: %v", err) + break + } + } +} + +// message format, ";" seperated message version;command;argc;args....? +func (mh *MessageHandler) messageDispatcher(message string) string { + messageParts := strings.Split(message, ";") + + if len(messageParts) < 3 { + log.Printf("Message to Short, %v", message) + return "" + } + + switch messageParts[0] { + case VERSION: + break + default: + log.Printf("Unknow Version %v in Message %v", messageParts[0], message) + return "" + } + + switch messageParts[1] { + case "listports": + return mh.ListComports() + case "connect": + return mh.Connect(messageParts[4]) + case "disconnect": + return mh.Disconnect() + case "write": + return mh.Write(messageParts[4]) + case "read": + return mh.Read() + default: + log.Printf("unknow command %v", message) + break + } + return "" +} + +func (mh *MessageHandler) ListComports() string { + ports := mh.Serial.ListComports() + message := MessageBuilder("portlist", ports...) + return message +} + +func (mh *MessageHandler) Connect(portname string) string { + err := mh.Serial.Connect(portname) + message := "" + if err != nil { + message = MessageBuilder("error", "connection") + } else { + message = MessageBuilder("connected", "portname") + } + return message +} + +func (mh *MessageHandler) Disconnect() string { + mh.Serial.Disconnect() + return MessageBuilder("disconnected") +} + +func (mh *MessageHandler) Write(msg string) string { + _, err := mh.Serial.Write([]byte(msg)) + if err != nil { + return MessageBuilder("write", fmt.Sprintf("write error %v", err)) + } + return MessageBuilder("write") +} + +func (mh *MessageHandler) Read() string { + buffer := make([]byte, 1024) + _, err := mh.Serial.Read(buffer) + if err != nil { + return MessageBuilder("read", fmt.Sprintf("read error %v", err)) + } + return MessageBuilder("read", string(buffer)) +} + +// version;command;argc;argv; +// recv: 1;connect;1;/dev/ttyUSB0; +// send: 1;connected;0; // no args can be used as a acc command +// send: 1;connected;1;error: port not found; +// recv: 1;discoonect;0; +// send: 1;discoonect;0; +// recv: 1;write;1;viele viele bunte bytes; +// send: 1;write;0; +// send: 1;write;1;error: port not connected; +// send: 1:read:1;das hab ich gelesen junge; + +func MessageBuilder(command string, args ...string) string { + return VERSION + ";" + command + ";" + strconv.Itoa(len(args)) + ";" + strings.Join(args, ";") +} diff --git a/SerialInteraction/serial.go b/SerialInteraction/serial.go new file mode 100644 index 0000000..cf4022c --- /dev/null +++ b/SerialInteraction/serial.go @@ -0,0 +1,47 @@ +package serialinteraction + +import ( + "go.bug.st/serial" + "log" +) + +type SerialConnection struct { + port serial.Port + portPath string +} + +func (sc *SerialConnection) ListComports() []string { + ports, err := serial.GetPortsList() + if err != nil { + log.Fatal(err) + } + return ports +} + +func (sc *SerialConnection) GetPortPath() string { + return sc.portPath +} + +func (sc *SerialConnection) Connect(portPath string) error { + mode := &serial.Mode{ + BaudRate: 115200, + } + port, err := serial.Open(portPath, mode) + if err != nil { + return err + } + sc.port = port + return nil +} + +func (sc *SerialConnection) Disconnect() { + sc.port.Close() +} + +func (sc *SerialConnection) Write(data []byte) (int, error) { + return sc.port.Write(data) +} + +func (sc *SerialConnection) Read(data []byte) (int, error) { + return sc.port.Read(data) +} diff --git a/SerialInteraction/serialMock.go b/SerialInteraction/serialMock.go new file mode 100644 index 0000000..3a857ad --- /dev/null +++ b/SerialInteraction/serialMock.go @@ -0,0 +1,30 @@ +package serialinteraction + +type SerialMockConnection struct { + portPath string +} + +func (sc *SerialMockConnection) ListComports() []string { + return []string{"/dev/ttyUSB0", "/dev/ttyUSB1"} +} + +func (sc *SerialMockConnection) GetPortPath() string { + return "/dev/ttyUSB0" +} + +func (sc *SerialMockConnection) Connect(portPath string) error { + return nil +} + +func (sc *SerialMockConnection) Disconnect() { +} + +func (sc *SerialMockConnection) Write(data []byte) (int, error) { + return 10, nil +} + +func (sc *SerialMockConnection) Read(data []byte) (int, error) { + msg := "Viele Lustige Daten" + data = []byte(msg) + return len(msg), nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..a59f9c8 --- /dev/null +++ b/go.mod @@ -0,0 +1,13 @@ +module serialToWebsocket + +go 1.23.6 + +require ( + github.com/gorilla/websocket v1.5.3 + go.bug.st/serial v1.6.2 +) + +require ( + github.com/creack/goselect v0.1.2 // indirect + golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..8434e89 --- /dev/null +++ b/go.sum @@ -0,0 +1,16 @@ +github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0= +github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +go.bug.st/serial v1.6.2 h1:kn9LRX3sdm+WxWKufMlIRndwGfPWsH1/9lCWXQCasq8= +go.bug.st/serial v1.6.2/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..bd55b97 --- /dev/null +++ b/main.go @@ -0,0 +1,44 @@ +package main + +import ( + "log" + "net/http" + "serialToWebsocket/MessageHandler" + serialinteraction "serialToWebsocket/SerialInteraction" + + "github.com/gorilla/websocket" +) + +var upgrader = websocket.Upgrader{ + CheckOrigin: func(r *http.Request) bool { + return true // for debuggin allow all + }, +} + +type Main struct { + handle *MessageHandler.MessageHandler +} + +func (m *Main) websock(w http.ResponseWriter, r *http.Request) { + c, err := upgrader.Upgrade(w, r, nil) + if err != nil { + log.Printf("upgrade: %v", err) + return + } + defer c.Close() + + m.handle.WebsocketHandle(w, r, c) +} + +func main() { + handlerOb := MessageHandler.MessageHandler{ + Serial: &serialinteraction.SerialConnection{}, + } + ma := Main{ + handle: &handlerOb, + } + + http.HandleFunc("/ws", ma.websock) + log.Printf("Server gestaret auf :8080") + log.Fatal(http.ListenAndServe(":8080", nil)) +}