diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 3b2a210d..709073df 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -286,6 +286,11 @@ jobs:
-k "${{ env.KEYCHAIN_PASSWORD }}" \
"${{ env.KEYCHAIN }}"
+ - name: Install Go
+ uses: actions/setup-go@v5
+ with:
+ go-version: ${{ env.GO_VERSION }}
+
- name: Install gon for code signing
uses: actions/checkout@v4
with:
diff --git a/bufferflow.go b/bufferflow.go
deleted file mode 100644
index a9fef8e5..00000000
--- a/bufferflow.go
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2022 Arduino SA
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published
-// by the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-
-package main
-
-// Bufferflow interface
-type Bufferflow interface {
- Init()
- OnIncomingData(data string) // implement this method
- Close() // implement this method
-}
diff --git a/bufferflow_default.go b/bufferflow_default.go
deleted file mode 100644
index 959737d5..00000000
--- a/bufferflow_default.go
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2022 Arduino SA
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published
-// by the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-
-package main
-
-import (
- "encoding/json"
-
- log "github.com/sirupsen/logrus"
-)
-
-// BufferflowDefault is the default bufferflow, whick means no buffering
-type BufferflowDefault struct {
- port string
- output chan<- []byte
- input chan string
- done chan bool
-}
-
-// NewBufferflowDefault create a new default bufferflow
-func NewBufferflowDefault(port string, output chan<- []byte) *BufferflowDefault {
- return &BufferflowDefault{
- port: port,
- output: output,
- input: make(chan string),
- done: make(chan bool),
- }
-}
-
-// Init will initialize the bufferflow
-func (b *BufferflowDefault) Init() {
- log.Println("Initting default buffer flow (which means no buffering)")
- go b.consumeInput()
-}
-
-func (b *BufferflowDefault) consumeInput() {
-Loop:
- for {
- select {
- case data := <-b.input:
- m := SpPortMessage{b.port, data}
- message, _ := json.Marshal(m)
- b.output <- message
- case <-b.done:
- break Loop //this is required, a simple break statement would only exit the innermost switch statement
- }
- }
- close(b.input) // close the input channel at the end of the computation
-}
-
-// OnIncomingData will forward the data
-func (b *BufferflowDefault) OnIncomingData(data string) {
- b.input <- data
-}
-
-// Close will close the bufferflow
-func (b *BufferflowDefault) Close() {
- b.done <- true
- close(b.done)
-}
diff --git a/bufferflow_timed.go b/bufferflow_timed.go
index 36aaf08b..6c5fab04 100644
--- a/bufferflow_timed.go
+++ b/bufferflow_timed.go
@@ -33,8 +33,8 @@ type BufferflowTimed struct {
bufferedOutput string
}
-// NewBufferflowTimed will create a new timed bufferflow
-func NewBufferflowTimed(port string, output chan<- []byte) *BufferflowTimed {
+// NewBufferFlowTimed will create a new timed bufferflow
+func NewBufferFlowTimed(port string, output chan<- []byte) *BufferflowTimed {
return &BufferflowTimed{
port: port,
output: output,
@@ -48,7 +48,7 @@ func NewBufferflowTimed(port string, output chan<- []byte) *BufferflowTimed {
// Init will initialize the bufferflow
func (b *BufferflowTimed) Init() {
- log.Println("Initting timed buffer flow (output once every 16ms)")
+ log.Println("Start consuming from serial port (output once every 16ms)")
go b.consumeInput()
}
diff --git a/bufferflow_timedraw.go b/bufferflow_timedraw.go
deleted file mode 100644
index 08b34cab..00000000
--- a/bufferflow_timedraw.go
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2022 Arduino SA
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published
-// by the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-
-package main
-
-import (
- "encoding/json"
- "time"
-
- log "github.com/sirupsen/logrus"
-)
-
-// BufferflowTimedRaw sends raw data once every 16ms
-type BufferflowTimedRaw struct {
- port string
- output chan<- []byte
- input chan string
- done chan bool
- ticker *time.Ticker
- bufferedOutputRaw []byte
- sPortRaw string
-}
-
-// NewBufferflowTimedRaw will create a new raw bufferflow
-func NewBufferflowTimedRaw(port string, output chan<- []byte) *BufferflowTimedRaw {
- return &BufferflowTimedRaw{
- port: port,
- output: output,
- input: make(chan string),
- done: make(chan bool),
- ticker: time.NewTicker(16 * time.Millisecond),
- bufferedOutputRaw: nil,
- sPortRaw: "",
- }
-}
-
-// Init will initialize the bufferflow
-func (b *BufferflowTimedRaw) Init() {
- log.Println("Initting timed buffer raw flow (output once every 16ms)")
- go b.consumeInput()
-}
-
-func (b *BufferflowTimedRaw) consumeInput() {
-Loop:
- for {
- select {
- case data := <-b.input: // use the buffer and append data to it
- b.bufferedOutputRaw = append(b.bufferedOutputRaw, []byte(data)...)
- b.sPortRaw = b.port
- case <-b.ticker.C: // after 16ms send the buffered output message
- if b.bufferedOutputRaw != nil {
- m := SpPortMessageRaw{b.sPortRaw, b.bufferedOutputRaw}
- buf, _ := json.Marshal(m)
- // since bufferedOutputRaw is a []byte is base64-encoded by json.Marshal() function automatically
- b.output <- buf
- // reset the buffer and the port
- b.bufferedOutputRaw = nil
- b.sPortRaw = ""
- }
- case <-b.done:
- break Loop //this is required, a simple break statement would only exit the innermost switch statement
- }
- }
- close(b.input)
-}
-
-// OnIncomingData will forward the data
-func (b *BufferflowTimedRaw) OnIncomingData(data string) {
- b.input <- data
-}
-
-// Close will close the bufferflow
-func (b *BufferflowTimedRaw) Close() {
- b.ticker.Stop()
- b.done <- true
- close(b.done)
-}
diff --git a/hub.go b/hub.go
index a162dd01..81a16912 100755
--- a/hub.go
+++ b/hub.go
@@ -58,7 +58,7 @@ var h = hub{
const commands = `{
"Commands": [
"list",
- "open [bufferAlgorithm: ({default}, timed, timedraw)]",
+ "open ",
"(send, sendnobuf, sendraw) ",
"close ",
"restart",
@@ -146,15 +146,13 @@ func checkCmd(m []byte) {
go spErr("Problem converting baud rate " + args[2])
return
}
- // pass in buffer type now as string. if user does not
- // ask for a buffer type pass in empty string
- bufferAlgorithm := "default" // use the default buffer if none is specified
+
+ // Ignore extra "buffer type" param for backward compatibility
if len(args) > 3 {
- // cool. we got a buffer type request
- buftype := strings.Replace(args[3], "\n", "", -1)
- bufferAlgorithm = buftype
+ log.Warn(fmt.Sprintf("Unexpected arguments for the open command. Ignored arguments: '%s'.", args[3:]))
}
- go spHandlerOpen(args[1], baud, bufferAlgorithm)
+
+ go spHandlerOpen(args[1], baud)
} else if strings.HasPrefix(sl, "close") {
diff --git a/serial.go b/serial.go
index 64e5b8f7..f5841457 100755
--- a/serial.go
+++ b/serial.go
@@ -67,7 +67,7 @@ var sh = serialhub{
func (sh *serialhub) Register(port *serport) {
sh.mu.Lock()
//log.Print("Registering a port: ", p.portConf.Name)
- h.broadcastSys <- []byte("{\"Cmd\":\"Open\",\"Desc\":\"Got register/open on port.\",\"Port\":\"" + port.portConf.Name + "\",\"Baud\":" + strconv.Itoa(port.portConf.Baud) + ",\"BufferType\":\"" + port.BufferType + "\"}")
+ h.broadcastSys <- []byte("{\"Cmd\":\"Open\",\"Desc\":\"Got register/open on port.\",\"Port\":\"" + port.portConf.Name + "\",\"Baud\":" + strconv.Itoa(port.portConf.Baud) + "}")
sh.ports[port] = true
sh.mu.Unlock()
}
diff --git a/serialport.go b/serialport.go
index 0d386bbf..9a06c7f9 100755
--- a/serialport.go
+++ b/serialport.go
@@ -22,7 +22,6 @@ import (
"strconv"
"sync/atomic"
"time"
- "unicode/utf8"
log "github.com/sirupsen/logrus"
serial "go.bug.st/serial"
@@ -57,10 +56,7 @@ type serport struct {
// channel containing raw base64 encoded binary data (outbound messages)
sendRaw chan string
- // Do we have an extra channel/thread to watch our buffer?
- BufferType string
- //bufferwatcher *BufferflowDummypause
- bufferwatcher Bufferflow
+ bufferFlow *BufferflowTimed
}
// SpPortMessage is the serial port message
@@ -75,15 +71,13 @@ type SpPortMessageRaw struct {
D []byte // the data, i.e. G0 X0 Y0
}
-func (p *serport) reader(buftype string) {
+func (p *serport) reader() {
timeCheckOpen := time.Now()
- var bufferedCh bytes.Buffer
serialBuffer := make([]byte, 1024)
for {
n, err := p.portIo.Read(serialBuffer)
- bufferPart := serialBuffer[:n]
//if we detect that port is closing, break out of this for{} loop.
if p.isClosing.Load() {
@@ -96,39 +90,8 @@ func (p *serport) reader(buftype string) {
// read can return legitimate bytes as well as an error
// so process the n bytes red, if n > 0
if n > 0 && err == nil {
-
- log.Print("Read " + strconv.Itoa(n) + " bytes ch: " + string(bufferPart[:n]))
-
- data := ""
- switch buftype {
- case "timedraw", "timed":
- data = string(bufferPart[:n])
- // give the data to our bufferflow so it can do it's work
- // to read/translate the data to see if it wants to block
- // writes to the serialport. each bufferflow type will decide
- // this on its own based on its logic
- p.bufferwatcher.OnIncomingData(data)
- case "default": // the bufferbuftype is actually called default 🤷♂️
- // save the left out bytes for the next iteration due to UTF-8 encoding
- bufferPart = append(bufferedCh.Bytes(), bufferPart[:n]...)
- n += len(bufferedCh.Bytes())
- bufferedCh.Reset()
- for i, w := 0, 0; i < n; i += w {
- runeValue, width := utf8.DecodeRune(bufferPart[i:n]) // try to decode the first i bytes in the buffer (UTF8 runes do not have a fixed length)
- if runeValue == utf8.RuneError {
- bufferedCh.Write(bufferPart[i:n])
- break
- }
- if i == n {
- bufferedCh.Reset()
- }
- data += string(runeValue)
- w = width
- }
- p.bufferwatcher.OnIncomingData(data)
- default:
- log.Panicf("unknown buffer type %s", buftype)
- }
+ log.Print("Read " + strconv.Itoa(n) + " bytes ch: " + string(serialBuffer[:n]))
+ p.bufferFlow.OnIncomingData(string(serialBuffer[:n]))
}
// double check that we got characters in the buffer
@@ -273,7 +236,7 @@ func (p *serport) writerRaw() {
h.broadcastSys <- []byte(msgstr)
}
-func spHandlerOpen(portname string, baud int, buftype string) {
+func spHandlerOpen(portname string, baud int) {
log.Print("Inside spHandler")
@@ -312,23 +275,10 @@ func spHandlerOpen(portname string, baud int, buftype string) {
portConf: conf,
portIo: sp,
portName: portname,
- BufferType: buftype}
-
- var bw Bufferflow
-
- switch buftype {
- case "timed":
- bw = NewBufferflowTimed(portname, h.broadcastSys)
- case "timedraw":
- bw = NewBufferflowTimedRaw(portname, h.broadcastSys)
- case "default":
- bw = NewBufferflowDefault(portname, h.broadcastSys)
- default:
- log.Panicf("unknown buffer type: %s", buftype)
}
- bw.Init()
- p.bufferwatcher = bw
+ p.bufferFlow = NewBufferFlowTimed(portname, h.broadcastSys)
+ p.bufferFlow.Init()
sh.Register(p)
defer sh.Unregister(p)
@@ -343,7 +293,7 @@ func spHandlerOpen(portname string, baud int, buftype string) {
// this is thread to send to serial port but with base64 decoding
go p.writerRaw()
- p.reader(buftype)
+ p.reader()
serialPorts.List()
}
@@ -351,7 +301,7 @@ func spHandlerOpen(portname string, baud int, buftype string) {
func (p *serport) Close() {
p.isClosing.Store(true)
- p.bufferwatcher.Close()
+ p.bufferFlow.Close()
p.portIo.Close()
serialPorts.MarkPortAsClosed(p.portName)
serialPorts.List()
diff --git a/tests/test_ws.py b/tests/test_ws.py
index b8004649..2f3ee9fa 100644
--- a/tests/test_ws.py
+++ b/tests/test_ws.py
@@ -49,77 +49,28 @@ def test_list(socketio, message):
running_on_ci(),
reason="VMs have no serial ports",
)
-def test_open_serial_default(socketio, serial_port, baudrate, message):
- general_open_serial(socketio, serial_port, baudrate, message, "default")
-
-
-@pytest.mark.skipif(
- running_on_ci(),
- reason="VMs have no serial ports",
-)
-def test_open_serial_timed(socketio, serial_port, baudrate, message):
- general_open_serial(socketio, serial_port, baudrate, message, "timed")
-
-
-@pytest.mark.skipif(
- running_on_ci(),
- reason="VMs have no serial ports",
-)
-def test_open_serial_timedraw(socketio, serial_port, baudrate, message):
- general_open_serial(socketio, serial_port, baudrate, message, "timedraw")
-
+def test_open_serial(socketio, serial_port, baudrate, message):
+ general_open_serial(socketio, serial_port, baudrate, message)
# NOTE run the following tests with a board connected to the PC and with the sketch found in tests/testdata/SerialEcho.ino on it be sure to change serial_address in conftest.py
@pytest.mark.skipif(
running_on_ci(),
reason="VMs have no serial ports",
)
-def test_send_serial_default(socketio, close_port, serial_port, baudrate, message):
- general_send_serial(socketio, close_port, serial_port, baudrate, message, "default")
-
-
-@pytest.mark.skipif(
- running_on_ci(),
- reason="VMs have no serial ports",
-)
-def test_send_serial_timed(socketio, close_port, serial_port, baudrate, message):
- general_send_serial(socketio, close_port, serial_port, baudrate, message, "timed")
+def test_send_serial(socketio, close_port, serial_port, baudrate, message):
+ general_send_serial(socketio, close_port, serial_port, baudrate, message)
@pytest.mark.skipif(
running_on_ci(),
reason="VMs have no serial ports",
)
-def test_send_serial_timedraw(socketio, close_port, serial_port, baudrate, message):
- general_send_serial(socketio, close_port, serial_port, baudrate, message, "timedraw")
+def test_send_emoji_serial(socketio, close_port, serial_port, baudrate, message):
+ general_send_emoji_serial(socketio, close_port, serial_port, baudrate, message)
-@pytest.mark.skipif(
- running_on_ci(),
- reason="VMs have no serial ports",
-)
-def test_send_emoji_serial_default(socketio, close_port, serial_port, baudrate, message):
- general_send_emoji_serial(socketio, close_port, serial_port, baudrate, message, "default")
-
-
-@pytest.mark.skipif(
- running_on_ci(),
- reason="VMs have no serial ports",
-)
-def test_send_emoji_serial_timed(socketio, close_port, serial_port, baudrate, message):
- general_send_emoji_serial(socketio, close_port, serial_port, baudrate, message, "timed")
-
-
-@pytest.mark.skipif(
- running_on_ci(),
- reason="VMs have no serial ports",
-)
-def test_send_emoji_serial_timedraw(socketio, close_port, serial_port, baudrate, message):
- general_send_emoji_serial(socketio, close_port, serial_port, baudrate, message, "timedraw")
-
-
-def general_open_serial(socketio, serial_port, baudrate, message, buffertype):
- open_serial_port(socketio, serial_port, baudrate, message, buffertype)
+def general_open_serial(socketio, serial_port, baudrate, message):
+ open_serial_port(socketio, serial_port, baudrate, message)
# test the closing of the serial port, we are gonna use close_port for the other tests
socketio.emit('command', 'close ' + serial_port)
time.sleep(.2)
@@ -128,8 +79,8 @@ def general_open_serial(socketio, serial_port, baudrate, message, buffertype):
assert any("\"IsOpen\": false," in i for i in message)
-def general_send_serial(socketio, close_port, serial_port, baudrate, message, buffertype):
- open_serial_port(socketio, serial_port, baudrate, message, buffertype)
+def general_send_serial(socketio, close_port, serial_port, baudrate, message):
+ open_serial_port(socketio, serial_port, baudrate, message)
# send the string "ciao" using the serial connection
socketio.emit('command', 'send ' + serial_port + ' ciao')
time.sleep(1)
@@ -137,33 +88,27 @@ def general_send_serial(socketio, close_port, serial_port, baudrate, message, bu
# check if the send command has been registered
assert any("send " + serial_port + " ciao" in i for i in message)
#check if message has been sent back by the connected board
- if buffertype == "timedraw":
- output = decode_output(extract_serial_data(message))
- elif buffertype in ("default", "timed"):
- output = extract_serial_data(message)
+ output = extract_serial_data(message)
assert "ciao" in output
# the serial connection is closed by close_port() fixture: even if in case of test failure
-def general_send_emoji_serial(socketio, close_port, serial_port, baudrate, message, buffertype):
- open_serial_port(socketio, serial_port, baudrate, message, buffertype)
+def general_send_emoji_serial(socketio, close_port, serial_port, baudrate, message):
+ open_serial_port(socketio, serial_port, baudrate, message)
# send a lot of emoji: they can be messed up
socketio.emit('command', 'send ' + serial_port + ' /"🧀🧀🧀🧀🧀🧀🧀🧀🧀🧀/"')
time.sleep(1)
print(message)
# check if the send command has been registered
assert any("send " + serial_port + " /\"🧀🧀🧀🧀🧀🧀🧀🧀🧀🧀/\"" in i for i in message)
- if buffertype == "timedraw":
- output = decode_output(extract_serial_data(message))
- elif buffertype in ("default", "timed"):
- output = extract_serial_data(message)
+ output = extract_serial_data(message)
assert "/\"🧀🧀🧀🧀🧀🧀🧀🧀🧀🧀/\"" in output
# the serial connection is closed by close_port() fixture: even if in case of test failure
-def open_serial_port(socketio, serial_port, baudrate, message, buffertype):
- #open a new serial connection with the specified buffertype
- socketio.emit('command', 'open ' + serial_port + ' ' + baudrate + ' ' + buffertype)
+def open_serial_port(socketio, serial_port, baudrate, message):
+ #open a new serial connection
+ socketio.emit('command', 'open ' + serial_port + ' ' + baudrate)
# give time to the message var to be filled
time.sleep(.5)
print(message)
@@ -176,7 +121,7 @@ def open_serial_port(socketio, serial_port, baudrate, message, buffertype):
reason="VMs have no serial ports",
)
def test_sendraw_serial(socketio, close_port, serial_port, baudrate, message):
- open_serial_port(socketio, serial_port, baudrate, message, "timedraw")
+ open_serial_port(socketio, serial_port, baudrate, message)
#test with bytes
integers = [1, 2, 3, 4, 5]
bytes_array=bytearray(integers)
@@ -202,7 +147,7 @@ def extract_serial_data(msg):
serial_data+=json.loads(i)["D"]
print("serialdata:"+serial_data)
return serial_data
-
+
def decode_output(raw_output):
# print(raw_output)
base64_bytes = raw_output.encode('ascii') #encode rawoutput message into a bytes-like object