Compare commits
No commits in common. "4b991729ea3ebbf7a6e724d315476c61e27fac5d" and "4e1ebdedb5d6370098ee7a44f39354b2b5e7589c" have entirely different histories.
4b991729ea
...
4e1ebdedb5
@ -1,19 +1,33 @@
|
|||||||
name: Build
|
name: Build and Test Golang
|
||||||
on: [push]
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
container:
|
||||||
|
image: golang:1.22 # Aktuelle Version verwenden
|
||||||
|
options: --network host
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- run: echo "The job was automatically triggered by a ${{ gitea.event_name }} event."
|
# Schritt 1: Repository klonen
|
||||||
- run: echo "This job is now running on a ${{ runner.os }} server hosted by Gitea!"
|
- name: Checkout Code
|
||||||
- run: echo "The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
|
|
||||||
- name: Check out repository code
|
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- run: echo "The ${{ gitea.repository }} repository has been cloned to the runner."
|
|
||||||
- run: echo "The workflow is now ready to test your code on the runner."
|
# Schritt 2: Abhängigkeiten installieren
|
||||||
- name: List files in the repository
|
- name: Install Dependencies
|
||||||
run: |
|
run: go mod tidy
|
||||||
ls ${{ gitea.workspace }}
|
|
||||||
- run: go build .
|
# Schritt 3: Code bauen
|
||||||
- run: echo "This job's status is ${{ job.status }}."
|
- name: Build Application
|
||||||
|
run: go build .
|
||||||
|
|
||||||
|
- name: Upload Build Artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: serialToWebsocket
|
||||||
|
path: .
|
||||||
|
|||||||
19
.gitea/workflows/demo.yaml
Normal file
19
.gitea/workflows/demo.yaml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
name: Gitea Actions Demo
|
||||||
|
run-name: ${{ gitea.actor }} is testing out Gitea Actions
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Explore-Gitea-Actions:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- run: echo " The job was automatically triggered by a ${{ gitea.event_name }} event."
|
||||||
|
- run: echo " This job is now running on a ${{ runner.os }} server hosted by Gitea!"
|
||||||
|
- run: echo " The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- run: echo " The ${{ gitea.repository }} repository has been cloned to the runner."
|
||||||
|
- run: echo " The workflow is now ready to test your code on the runner."
|
||||||
|
- name: List files in the repository
|
||||||
|
run: |
|
||||||
|
ls ${{ gitea.workspace }}
|
||||||
|
- run: echo " This job's status is ${{ job.status }}."
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
serialAlox
|
|
||||||
139
MessageHandler/handler.go
Normal file
139
MessageHandler/handler.go
Normal file
@ -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, ";")
|
||||||
|
}
|
||||||
147
Parser/parser.go
147
Parser/parser.go
@ -1,147 +0,0 @@
|
|||||||
package parser
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ParsedMessage struct {
|
|
||||||
typeByte byte
|
|
||||||
payloadBytes []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type ParserConfig struct {
|
|
||||||
StartByte byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewParserConfig() *ParserConfig {
|
|
||||||
return &ParserConfig{
|
|
||||||
StartByte: 0xAA,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ParserErrorCodes int
|
|
||||||
type ParserError struct {
|
|
||||||
Code ParserErrorCodes
|
|
||||||
Message string
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
ChecksumError ParserErrorCodes = iota
|
|
||||||
)
|
|
||||||
|
|
||||||
func (e *ParserError) Error() string {
|
|
||||||
return e.Message
|
|
||||||
}
|
|
||||||
|
|
||||||
type ParserState int
|
|
||||||
|
|
||||||
const (
|
|
||||||
StateWaitForStartByte ParserState = iota
|
|
||||||
StateReadType
|
|
||||||
StateReadLength
|
|
||||||
StateReadPayload
|
|
||||||
StateCheckChecksum
|
|
||||||
)
|
|
||||||
|
|
||||||
type Parser struct {
|
|
||||||
messages []ParsedMessage
|
|
||||||
currentMessageBuffer []byte
|
|
||||||
currentMsgType byte
|
|
||||||
readLength byte
|
|
||||||
readIndex byte
|
|
||||||
parserState ParserState
|
|
||||||
parserConfig ParserConfig
|
|
||||||
checksum byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewParser(cfg ParserConfig) *Parser {
|
|
||||||
return &Parser{
|
|
||||||
messages: []ParsedMessage{},
|
|
||||||
currentMessageBuffer: []byte{},
|
|
||||||
currentMsgType: 0,
|
|
||||||
readLength: 0,
|
|
||||||
readIndex: 0,
|
|
||||||
parserState: StateWaitForStartByte,
|
|
||||||
parserConfig: cfg,
|
|
||||||
checksum: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pa *Parser) ParseBytes(p []byte) (n int, err error) {
|
|
||||||
for i, b := range p {
|
|
||||||
err := pa.parseByte(b)
|
|
||||||
if err != nil {
|
|
||||||
return i, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len(p), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pa *Parser) parseByte(p byte) error {
|
|
||||||
switch pa.parserState {
|
|
||||||
case StateWaitForStartByte:
|
|
||||||
if p == pa.parserConfig.StartByte {
|
|
||||||
pa.parserState = StateReadType
|
|
||||||
pa.readIndex = 0
|
|
||||||
pa.checksum = 0
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case StateReadType:
|
|
||||||
pa.currentMsgType = p
|
|
||||||
pa.checksum ^= p
|
|
||||||
pa.parserState = StateReadLength
|
|
||||||
case StateReadLength:
|
|
||||||
pa.readLength = p
|
|
||||||
pa.checksum ^= p
|
|
||||||
pa.parserState = StateReadPayload
|
|
||||||
break
|
|
||||||
case StateReadPayload:
|
|
||||||
if pa.readIndex < pa.readLength {
|
|
||||||
pa.currentMessageBuffer = append(pa.currentMessageBuffer, p)
|
|
||||||
pa.checksum ^= p
|
|
||||||
pa.readIndex++
|
|
||||||
if pa.readIndex == pa.readLength {
|
|
||||||
pa.parserState = StateCheckChecksum
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case StateCheckChecksum:
|
|
||||||
if pa.checksum != p {
|
|
||||||
return &ParserError{
|
|
||||||
Code: ChecksumError,
|
|
||||||
Message: fmt.Sprintf("Checksum does not Match, want %v, got %v", pa.checksum, p),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pm := &ParsedMessage{
|
|
||||||
typeByte: pa.currentMsgType,
|
|
||||||
payloadBytes: pa.currentMessageBuffer,
|
|
||||||
}
|
|
||||||
pa.messages = append(pa.messages, *pm)
|
|
||||||
pa.reset()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pa *Parser) reset() {
|
|
||||||
pa.currentMessageBuffer = nil
|
|
||||||
pa.currentMsgType = 0
|
|
||||||
pa.readIndex = 0
|
|
||||||
pa.readLength = 0
|
|
||||||
pa.checksum = 0
|
|
||||||
pa.parserState = StateWaitForStartByte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pa *Parser) IsMessageAvailable() bool {
|
|
||||||
return len(pa.messages) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pa *Parser) GetNextMessage() (typeByte byte, payload []byte, err error) {
|
|
||||||
if !pa.IsMessageAvailable() {
|
|
||||||
return 0x00, nil, fmt.Errorf("No message available")
|
|
||||||
}
|
|
||||||
lastMessage := pa.messages[0]
|
|
||||||
pa.messages = pa.messages[1:]
|
|
||||||
|
|
||||||
return lastMessage.typeByte, lastMessage.payloadBytes, nil
|
|
||||||
}
|
|
||||||
@ -1,118 +0,0 @@
|
|||||||
package parser
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Hilfsfunktion zum Berechnen der Checksumme
|
|
||||||
func calcChecksum(msgType byte, length byte, payload []byte) byte {
|
|
||||||
cs := msgType ^ length
|
|
||||||
for _, b := range payload {
|
|
||||||
cs ^= b
|
|
||||||
}
|
|
||||||
return cs
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParser_ParseBytes(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
input []byte
|
|
||||||
expectErr bool
|
|
||||||
expectMessages []ParsedMessage
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "valid single message",
|
|
||||||
input: func() []byte {
|
|
||||||
msgType := byte(0x01)
|
|
||||||
payload := []byte{0x10, 0x20}
|
|
||||||
length := byte(len(payload))
|
|
||||||
cs := calcChecksum(msgType, length, payload)
|
|
||||||
return []byte{0xAA, msgType, length, payload[0], payload[1], cs}
|
|
||||||
}(),
|
|
||||||
expectErr: false,
|
|
||||||
expectMessages: []ParsedMessage{
|
|
||||||
{typeByte: 0x01, payloadBytes: []byte{0x10, 0x20}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "invalid checksum",
|
|
||||||
input: []byte{
|
|
||||||
0xAA, 0x02, 0x01, 0x33, 0x00, // falsche Checksumme (letztes Byte)
|
|
||||||
},
|
|
||||||
expectErr: true,
|
|
||||||
expectMessages: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "no start byte",
|
|
||||||
input: []byte{
|
|
||||||
0x01, 0x02, 0x03,
|
|
||||||
},
|
|
||||||
expectErr: false,
|
|
||||||
expectMessages: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "multiple valid messages",
|
|
||||||
input: func() []byte {
|
|
||||||
payload1 := []byte{0x11}
|
|
||||||
payload2 := []byte{0x22, 0x23}
|
|
||||||
cs1 := calcChecksum(0x01, 1, payload1)
|
|
||||||
cs2 := calcChecksum(0x02, 2, payload2)
|
|
||||||
return append(
|
|
||||||
[]byte{0xAA, 0x01, 0x01, payload1[0], cs1,
|
|
||||||
0xAA, 0x02, 0x02, payload2[0], payload2[1], cs2},
|
|
||||||
)
|
|
||||||
}(),
|
|
||||||
expectErr: false,
|
|
||||||
expectMessages: []ParsedMessage{
|
|
||||||
{typeByte: 0x01, payloadBytes: []byte{0x11}},
|
|
||||||
{typeByte: 0x02, payloadBytes: []byte{0x22, 0x23}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
parser := NewParser(ParserConfig{StartByte: 0xAA})
|
|
||||||
n, err := parser.ParseBytes(tt.input)
|
|
||||||
|
|
||||||
if tt.expectErr && err == nil {
|
|
||||||
t.Errorf("expected error, got none")
|
|
||||||
}
|
|
||||||
if !tt.expectErr && err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if !tt.expectErr && n != len(tt.input) {
|
|
||||||
t.Errorf("expected to read %d bytes, read %d", len(tt.input), n)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, expected := range tt.expectMessages {
|
|
||||||
if !parser.IsMessageAvailable() {
|
|
||||||
t.Errorf("expected message %d to be available", i)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
msgtype, msgpayload, err := parser.GetNextMessage()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error when getting message: %v", err)
|
|
||||||
}
|
|
||||||
if msgtype != expected.typeByte {
|
|
||||||
t.Errorf("message %d: expected type 0x%02X, got 0x%02X", i, expected.typeByte, msgtype)
|
|
||||||
}
|
|
||||||
if !equalBytes(msgpayload, expected.payloadBytes) {
|
|
||||||
t.Errorf("message %d: expected payload %v, got %v", i, expected.payloadBytes, msgpayload)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func equalBytes(a, b []byte) bool {
|
|
||||||
if len(a) != len(b) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for i := range a {
|
|
||||||
if a[i] != b[i] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
@ -22,7 +22,10 @@ func (sc *SerialConnection) GetPortPath() string {
|
|||||||
return sc.portPath
|
return sc.portPath
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *SerialConnection) Connect(portPath string, mode *serial.Mode) error {
|
func (sc *SerialConnection) Connect(portPath string) error {
|
||||||
|
mode := &serial.Mode{
|
||||||
|
BaudRate: 115200,
|
||||||
|
}
|
||||||
port, err := serial.Open(portPath, mode)
|
port, err := serial.Open(portPath, mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
4
go.mod
4
go.mod
@ -1,9 +1,9 @@
|
|||||||
module serialAlox
|
module serialToWebsocket
|
||||||
|
|
||||||
go 1.23.6
|
go 1.23.6
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/micmonay/keybd_event v1.1.2
|
github.com/gorilla/websocket v1.5.3
|
||||||
go.bug.st/serial v1.6.2
|
go.bug.st/serial v1.6.2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
4
go.sum
4
go.sum
@ -2,8 +2,8 @@ github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0
|
|||||||
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
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 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/micmonay/keybd_event v1.1.2 h1:RpgvPJKOh4Jc+ZYe0OrVzGd2eNMCfuVg3dFTCsuSah4=
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
github.com/micmonay/keybd_event v1.1.2/go.mod h1:CGMWMDNgsfPljzrAWoybUOSKafQPZpv+rLigt2LzNGI=
|
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
|
|||||||
72
main.go
72
main.go
@ -1,62 +1,44 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime"
|
"serialToWebsocket/MessageHandler"
|
||||||
parser "serialAlox/Parser"
|
serialinteraction "serialToWebsocket/SerialInteraction"
|
||||||
serialinteraction "serialAlox/SerialInteraction"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/micmonay/keybd_event"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MainConfig struct {
|
var upgrader = websocket.Upgrader{
|
||||||
Debug bool
|
CheckOrigin: func(r *http.Request) bool {
|
||||||
Port int
|
return true // for debuggin allow all
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMainConfig() *MainConfig {
|
type Main struct {
|
||||||
return &MainConfig{
|
handle *MessageHandler.MessageHandler
|
||||||
Debug: false,
|
|
||||||
Port: 8080,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
func main() {
|
||||||
kb, err := keybd_event.NewKeyBonding()
|
handlerOb := MessageHandler.MessageHandler{
|
||||||
if err != nil {
|
Serial: &serialinteraction.SerialConnection{},
|
||||||
panic(err)
|
}
|
||||||
|
ma := Main{
|
||||||
|
handle: &handlerOb,
|
||||||
}
|
}
|
||||||
|
|
||||||
if runtime.GOOS == "linux" {
|
http.HandleFunc("/ws", ma.websock)
|
||||||
time.Sleep(2 * time.Second)
|
log.Printf("Server gestaret auf :8080")
|
||||||
}
|
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||||
|
|
||||||
mc := NewMainConfig()
|
|
||||||
mc.Debug = true
|
|
||||||
|
|
||||||
sc := serialinteraction.SerialConnection{}
|
|
||||||
msConf := NewMessageHandlerConfig()
|
|
||||||
|
|
||||||
msParserConf := parser.NewParserConfig()
|
|
||||||
msParser := parser.NewParser(*msParserConf)
|
|
||||||
msHandler := NewMessageHandler(&sc, *msConf, msParser)
|
|
||||||
|
|
||||||
msHandler.RegisterMessageCallback(0x01, func(b1 byte, b2 []byte) {
|
|
||||||
log.Printf("ICH BIN DER HANDLER % X, % X", b1, b2)
|
|
||||||
kb.SetKeys(keybd_event.VK_A, keybd_event.VK_B)
|
|
||||||
kb.Press()
|
|
||||||
time.Sleep(10 * time.Millisecond)
|
|
||||||
kb.Release()
|
|
||||||
})
|
|
||||||
|
|
||||||
go msHandler.ListenAndServe()
|
|
||||||
|
|
||||||
msHandler.MessageParser.ParseBytes([]byte{0xAA, 0x01, 0x02, 0x10, 0x20, 0x33})
|
|
||||||
|
|
||||||
log.Printf("Started Server on %d", mc.Port)
|
|
||||||
connectString := fmt.Sprintf(":%d", mc.Port)
|
|
||||||
log.Fatal(http.ListenAndServe(connectString, nil))
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,86 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ReaderWriter interface {
|
|
||||||
Write(p []byte) (n int, err error)
|
|
||||||
Read(b []byte) (n int, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Parser interface {
|
|
||||||
ParseBytes(p []byte) (n int, err error)
|
|
||||||
IsMessageAvailable() bool
|
|
||||||
GetNextMessage() (typeByte byte, payload []byte, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type HandlerFunc func(byte, []byte)
|
|
||||||
|
|
||||||
type MessageHandler struct {
|
|
||||||
WriterReader ReaderWriter
|
|
||||||
Conf MessageHandlerConfig
|
|
||||||
MessageParser Parser
|
|
||||||
handlers map[byte]HandlerFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
type MessageHandlerConfig struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMessageHandlerConfig() *MessageHandlerConfig {
|
|
||||||
return &MessageHandlerConfig{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMessageHandler(con ReaderWriter, conf MessageHandlerConfig, msgParser Parser) *MessageHandler {
|
|
||||||
return &MessageHandler{
|
|
||||||
WriterReader: con,
|
|
||||||
Conf: conf,
|
|
||||||
MessageParser: msgParser,
|
|
||||||
handlers: make(map[byte]HandlerFunc),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mh *MessageHandler) RegisterMessageCallback(typeByte byte, fn HandlerFunc) error {
|
|
||||||
mh.handlers[typeByte] = fn
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mh *MessageHandler) ListenAndServe() {
|
|
||||||
ctx, cancle := context.WithCancel(context.Background())
|
|
||||||
go mh.readBytes(ctx)
|
|
||||||
defer cancle()
|
|
||||||
|
|
||||||
for {
|
|
||||||
if mh.MessageParser.IsMessageAvailable() {
|
|
||||||
msgType, msgPayload, err := mh.MessageParser.GetNextMessage()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error getting message %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Printf("Got messagetype % X, with payload % X", msgType, msgPayload)
|
|
||||||
if mh.handlers[msgType] != nil {
|
|
||||||
mh.handlers[msgType](msgType, msgPayload)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mh *MessageHandler) readBytes(ctx context.Context) error {
|
|
||||||
buffer := make([]byte, 1024)
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return ctx.Err()
|
|
||||||
default:
|
|
||||||
// Proceed with reading
|
|
||||||
n, err := mh.WriterReader.Read(buffer)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Process the read bytes
|
|
||||||
mh.MessageParser.ParseBytes(buffer[:n])
|
|
||||||
//time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HexByte byte
|
|
||||||
|
|
||||||
type ProtoComplete struct {
|
|
||||||
Header ProtocolHeader `json:"protocol"`
|
|
||||||
Protocols map[string][]ProtoMessage `json:"protocols"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProtocolHeader struct {
|
|
||||||
StartByte HexByte `json:"start_byte"`
|
|
||||||
MessageLength int `json:"message_length"`
|
|
||||||
MaxPayload int `json:"max_payload"`
|
|
||||||
Checksum string `json:"checksum"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProtoMessage struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
ID HexByte `json:"id"`
|
|
||||||
Payload []ProtoMessagePayload `json:"payload,omitempty"` // optional falls kein payload
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProtoMessagePayload struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
DataType string `json:"type"`
|
|
||||||
ArrayLength int `json:"array,omitempty"` // optional falls kein array
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HexByte) UnmarshalJSON(data []byte) error {
|
|
||||||
var s string
|
|
||||||
if err := json.Unmarshal(data, &s); err != nil { // turn into go string
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
i, err := strconv.ParseUint(s, 0, 8)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
*h = HexByte(i)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestReadJson(t *testing.T) {
|
|
||||||
con, err := os.ReadFile("../testdata/prot1.json")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Could not read file %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pc := &ProtoComplete{}
|
|
||||||
|
|
||||||
json.Unmarshal(con, pc)
|
|
||||||
|
|
||||||
log.Printf("%v", pc)
|
|
||||||
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
92
testdata/prot1.json
vendored
92
testdata/prot1.json
vendored
@ -1,92 +0,0 @@
|
|||||||
{
|
|
||||||
"protocol": {
|
|
||||||
"start_byte": "0xAA",
|
|
||||||
"message_length": 0,
|
|
||||||
"max_payload": 255,
|
|
||||||
"checksum": "xor"
|
|
||||||
},
|
|
||||||
"protocols": {
|
|
||||||
"messages_esp_to_pc": [
|
|
||||||
{
|
|
||||||
"name": "Clients",
|
|
||||||
"id": "0xE1",
|
|
||||||
"payload": [
|
|
||||||
{
|
|
||||||
"name": "clientCount",
|
|
||||||
"type": "uint8_t"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "clientAvaiableBitMask",
|
|
||||||
"type": "uint32_t"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Status",
|
|
||||||
"id": "0xE2",
|
|
||||||
"payload": [
|
|
||||||
{
|
|
||||||
"name": "clientId",
|
|
||||||
"type": "uint8_t"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "mac",
|
|
||||||
"type": "uint8_t",
|
|
||||||
"array": 6
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Pong",
|
|
||||||
"id": "0xD1",
|
|
||||||
"payload": [
|
|
||||||
{
|
|
||||||
"name": "clientId",
|
|
||||||
"type": "uint8_t"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ping",
|
|
||||||
"type": "uint32_t"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"messages_pc_to_esp": [
|
|
||||||
{
|
|
||||||
"name": "RequestPing",
|
|
||||||
"id": "0xE1",
|
|
||||||
"payload": [
|
|
||||||
{
|
|
||||||
"name": "clientId",
|
|
||||||
"type": "uint8_t"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "RequestStatus",
|
|
||||||
"id": "0xE2",
|
|
||||||
"payload": [
|
|
||||||
{
|
|
||||||
"name": "clientId",
|
|
||||||
"type": "uint8_t"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "PrepareFirmwareUpdate",
|
|
||||||
"id": "0xF1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "FirmwareUpdateLine",
|
|
||||||
"id": "0xF2",
|
|
||||||
"payload": [
|
|
||||||
{
|
|
||||||
"name": "data",
|
|
||||||
"type": "uint8_t",
|
|
||||||
"array": 240
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user