From aff40ab7950542399babfc3ca38aac0a514fbb18 Mon Sep 17 00:00:00 2001 From: Davide N Date: Fri, 10 Jan 2025 11:31:57 +0100 Subject: [PATCH 01/20] WIP: print to understand --- hub.go | 1 + 1 file changed, 1 insertion(+) diff --git a/hub.go b/hub.go index a162dd01..b8a14c92 100755 --- a/hub.go +++ b/hub.go @@ -154,6 +154,7 @@ func checkCmd(m []byte) { buftype := strings.Replace(args[3], "\n", "", -1) bufferAlgorithm = buftype } + fmt.Println("bufferAlgorithm: ", bufferAlgorithm) go spHandlerOpen(args[1], baud, bufferAlgorithm) } else if strings.HasPrefix(sl, "close") { From bae632a2ea74d1d23fb8259196d2f87326593f90 Mon Sep 17 00:00:00 2001 From: Davide N Date: Fri, 10 Jan 2025 12:37:33 +0100 Subject: [PATCH 02/20] refactor: remove unused Bufferflow implementations and simplify buffer handling --- bufferflow.go | 23 ----------- bufferflow_default.go | 72 ---------------------------------- bufferflow_timed.go | 4 +- bufferflow_timedraw.go | 89 ------------------------------------------ conn.go | 1 + hub.go | 12 +----- serial.go | 2 +- serialport.go | 65 +++++------------------------- 8 files changed, 15 insertions(+), 253 deletions(-) delete mode 100644 bufferflow.go delete mode 100644 bufferflow_default.go delete mode 100644 bufferflow_timedraw.go 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..31298143 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, 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/conn.go b/conn.go index b6e03268..ae33f634 100644 --- a/conn.go +++ b/conn.go @@ -220,6 +220,7 @@ func wsHandler() *WsServer { c := &connection{send: make(chan []byte, 256*10), ws: so} h.register <- c so.On("command", func(message string) { + fmt.Println("command:", message) h.broadcast <- []byte(message) }) diff --git a/hub.go b/hub.go index b8a14c92..1e163d3d 100755 --- a/hub.go +++ b/hub.go @@ -146,16 +146,8 @@ 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 - if len(args) > 3 { - // cool. we got a buffer type request - buftype := strings.Replace(args[3], "\n", "", -1) - bufferAlgorithm = buftype - } - fmt.Println("bufferAlgorithm: ", bufferAlgorithm) - 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..5f5cd8e0 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 a11483f6..d5862681 100755 --- a/serialport.go +++ b/serialport.go @@ -21,7 +21,6 @@ import ( "io" "strconv" "time" - "unicode/utf8" log "github.com/sirupsen/logrus" serial "go.bug.st/serial" @@ -56,10 +55,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 @@ -74,10 +70,9 @@ 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 { @@ -95,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) - } + p.bufferFlow.OnIncomingData(string(bufferPart[:n])) } // double check that we got characters in the buffer @@ -272,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") @@ -311,23 +275,12 @@ 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 := NewBufferFlowTimed(portname, h.broadcastSys) bw.Init() - p.bufferwatcher = bw + + p.bufferFlow = bw sh.Register(p) defer sh.Unregister(p) @@ -342,14 +295,14 @@ 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() } func (p *serport) Close() { p.isClosing = true - p.bufferwatcher.Close() + p.bufferFlow.Close() p.portIo.Close() serialPorts.MarkPortAsClosed(p.portName) serialPorts.List() From 818f79fb57618974f6a405f1caa7f79faf9a7851 Mon Sep 17 00:00:00 2001 From: Davide N Date: Fri, 10 Jan 2025 12:37:47 +0100 Subject: [PATCH 03/20] refactor: simplify serial test functions by removing unused parameters --- tests/test_ws.py | 93 ++++++++++-------------------------------------- 1 file changed, 19 insertions(+), 74 deletions(-) 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 From baf2ff46bdf6d1783d49eb15bd947df2ce55f214 Mon Sep 17 00:00:00 2001 From: Davide N Date: Fri, 10 Jan 2025 14:02:59 +0100 Subject: [PATCH 04/20] fix(ci): update package installation command to use correct version of libwebkit2gtk --- .github/workflows/check-go-task.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-go-task.yml b/.github/workflows/check-go-task.yml index 21478d23..ddbf1a26 100644 --- a/.github/workflows/check-go-task.yml +++ b/.github/workflows/check-go-task.yml @@ -82,7 +82,7 @@ jobs: version: 3.x - name: Install Dependencies - run: sudo apt update && sudo apt install -y --no-install-recommends build-essential libgtk-3-dev libwebkit2gtk-4.1-0 libappindicator3-dev + run: sudo apt update && sudo apt install -y --no-install-recommends build-essential libgtk-3-dev libwebkit2gtk-4.0 libappindicator3-dev - name: Check for errors env: From e63527a9013c679a9f3d8235de79716f8617feec Mon Sep 17 00:00:00 2001 From: Davide N Date: Fri, 10 Jan 2025 14:07:22 +0100 Subject: [PATCH 05/20] fix(ci): update libwebkit2gtk version in dependency installation --- .github/workflows/check-go-task.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-go-task.yml b/.github/workflows/check-go-task.yml index ddbf1a26..21478d23 100644 --- a/.github/workflows/check-go-task.yml +++ b/.github/workflows/check-go-task.yml @@ -82,7 +82,7 @@ jobs: version: 3.x - name: Install Dependencies - run: sudo apt update && sudo apt install -y --no-install-recommends build-essential libgtk-3-dev libwebkit2gtk-4.0 libappindicator3-dev + run: sudo apt update && sudo apt install -y --no-install-recommends build-essential libgtk-3-dev libwebkit2gtk-4.1-0 libappindicator3-dev - name: Check for errors env: From 98b6376bfdc47f1b051454ec1c1ee8c487ebe3b7 Mon Sep 17 00:00:00 2001 From: Davide N Date: Fri, 10 Jan 2025 15:21:01 +0100 Subject: [PATCH 06/20] fix: remove unused buffer slice and simplify data reading in serial port --- serialport.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/serialport.go b/serialport.go index d5862681..21affc42 100755 --- a/serialport.go +++ b/serialport.go @@ -77,7 +77,6 @@ func (p *serport) reader() { 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 { @@ -90,8 +89,8 @@ func (p *serport) reader() { // 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])) - p.bufferFlow.OnIncomingData(string(bufferPart[:n])) + 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 From 0ce39a56a62c72eaad10100ea73228eee9aa5f69 Mon Sep 17 00:00:00 2001 From: Davide N Date: Fri, 10 Jan 2025 17:57:21 +0100 Subject: [PATCH 07/20] small changes --- hub.go | 2 +- serialport.go | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/hub.go b/hub.go index 1e163d3d..21b3c024 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", diff --git a/serialport.go b/serialport.go index 21affc42..d905c0ea 100755 --- a/serialport.go +++ b/serialport.go @@ -276,10 +276,8 @@ func spHandlerOpen(portname string, baud int) { portName: portname, } - bw := NewBufferFlowTimed(portname, h.broadcastSys) - bw.Init() - - p.bufferFlow = bw + p.bufferFlow = NewBufferFlowTimed(portname, h.broadcastSys) + p.bufferFlow.Init() sh.Register(p) defer sh.Unregister(p) From ec5049da54a6d8ded68d351d1926451ab0f86615 Mon Sep 17 00:00:00 2001 From: Davide N Date: Mon, 13 Jan 2025 09:56:29 +0100 Subject: [PATCH 08/20] fix: remove debug print statement from wsHandler function --- conn.go | 1 - 1 file changed, 1 deletion(-) diff --git a/conn.go b/conn.go index ae33f634..b6e03268 100644 --- a/conn.go +++ b/conn.go @@ -220,7 +220,6 @@ func wsHandler() *WsServer { c := &connection{send: make(chan []byte, 256*10), ws: so} h.register <- c so.On("command", func(message string) { - fmt.Println("command:", message) h.broadcast <- []byte(message) }) From 2fe3c28672d8c0a86d2b321b200b4b4c82d8be98 Mon Sep 17 00:00:00 2001 From: Davide N Date: Mon, 13 Jan 2025 12:36:10 +0100 Subject: [PATCH 09/20] fix: add warning log for unexpected arguments in open command --- hub.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hub.go b/hub.go index 21b3c024..14b24c15 100755 --- a/hub.go +++ b/hub.go @@ -147,6 +147,10 @@ func checkCmd(m []byte) { return } + if len(args) > 3 { + log.Warn(fmt.Sprintf("Unexpected arguments for the open command. Ignored arguments: '%s'.", args[3:])) + } + go spHandlerOpen(args[1], baud) } else if strings.HasPrefix(sl, "close") { From 1849a1c2208b8dbac3d294292fa2496c3c8550d1 Mon Sep 17 00:00:00 2001 From: Davide Date: Mon, 13 Jan 2025 14:00:09 +0100 Subject: [PATCH 10/20] Update hub.go Co-authored-by: Cristian Maglie --- hub.go | 1 + 1 file changed, 1 insertion(+) diff --git a/hub.go b/hub.go index 14b24c15..81a16912 100755 --- a/hub.go +++ b/hub.go @@ -147,6 +147,7 @@ func checkCmd(m []byte) { return } + // Ignore extra "buffer type" param for backward compatibility if len(args) > 3 { log.Warn(fmt.Sprintf("Unexpected arguments for the open command. Ignored arguments: '%s'.", args[3:])) } From 294de02853d35f37df317c2688af6e596d7de9e6 Mon Sep 17 00:00:00 2001 From: Davide N Date: Tue, 14 Jan 2025 10:10:17 +0100 Subject: [PATCH 11/20] fix: update log message for buffer flow initialization --- bufferflow_timed.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bufferflow_timed.go b/bufferflow_timed.go index 31298143..6aaaec5b 100644 --- a/bufferflow_timed.go +++ b/bufferflow_timed.go @@ -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 (output once every 16ms)") go b.consumeInput() } From 99a31e6338733fae63a54a02445e761855ba4ef0 Mon Sep 17 00:00:00 2001 From: Davide N Date: Tue, 14 Jan 2025 10:10:48 +0100 Subject: [PATCH 12/20] fix: update log message for clarity in buffer flow initialization --- bufferflow_timed.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bufferflow_timed.go b/bufferflow_timed.go index 6aaaec5b..6c5fab04 100644 --- a/bufferflow_timed.go +++ b/bufferflow_timed.go @@ -48,7 +48,7 @@ func NewBufferFlowTimed(port string, output chan<- []byte) *BufferflowTimed { // Init will initialize the bufferflow func (b *BufferflowTimed) Init() { - log.Println("Start consuming from serial (output once every 16ms)") + log.Println("Start consuming from serial port (output once every 16ms)") go b.consumeInput() } From 2308b5f125a8627667edf3ed04ac5f0ca8de64d0 Mon Sep 17 00:00:00 2001 From: Davide N Date: Tue, 14 Jan 2025 12:27:23 +0100 Subject: [PATCH 13/20] fix: ignore all tags in check-certificates workflow on push --- .github/workflows/check-certificates.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/check-certificates.yml b/.github/workflows/check-certificates.yml index 694792dc..0c80be9c 100644 --- a/.github/workflows/check-certificates.yml +++ b/.github/workflows/check-certificates.yml @@ -6,6 +6,8 @@ on: push: paths: - ".github/workflows/check-certificates.ya?ml" + tags-ignore: + - '*' pull_request: paths: - ".github/workflows/check-certificates.ya?ml" From 8688ec627d7b82bf94906ca239247e21399995d0 Mon Sep 17 00:00:00 2001 From: Davide N Date: Tue, 14 Jan 2025 12:36:48 +0100 Subject: [PATCH 14/20] fix: update macOS-13 version in publish-go-tester-task workflow --- .github/workflows/publish-go-tester-task.yml | 2 +- .github/workflows/release.yml | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/publish-go-tester-task.yml b/.github/workflows/publish-go-tester-task.yml index 864f21c5..44132df4 100644 --- a/.github/workflows/publish-go-tester-task.yml +++ b/.github/workflows/publish-go-tester-task.yml @@ -65,7 +65,7 @@ jobs: #use the strategy instead because we still use the native build strategy: matrix: - os: [ubuntu-20.04, windows-2019, macos-12] + os: [ubuntu-20.04, windows-2019, macos-13] arch: [-amd64] include: - os: windows-2019 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index af37a9b8..3b2a210d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,7 +32,7 @@ jobs: prerelease: ${{ steps.prerelease.outputs.IS_PRE }} strategy: matrix: - os: [ubuntu-20.04, windows-2019, macos-12] + os: [ubuntu-20.04, windows-2019, macos-13] arch: [amd64] include: - os: windows-2019 @@ -116,7 +116,7 @@ jobs: run: | task go:build mv ${{ env.PROJECT_NAME }} ${{ env.PROJECT_NAME }}_amd64 - if: matrix.os == 'macos-12' + if: matrix.os == 'macos-13' - name: Build the Agent for macos arm64 env: @@ -128,13 +128,13 @@ jobs: run: | task go:build mv ${{ env.PROJECT_NAME }} ${{ env.PROJECT_NAME }}_arm64 - if: matrix.os == 'macos-12' + if: matrix.os == 'macos-13' - name: Create universal macos executable run: | lipo -create -output ${{ env.PROJECT_NAME }} ${{ env.PROJECT_NAME }}_amd64 ${{ env.PROJECT_NAME }}_arm64 rm ${{ env.PROJECT_NAME }}_amd64 ${{ env.PROJECT_NAME }}_arm64 - if: matrix.os == 'macos-12' + if: matrix.os == 'macos-13' # this will create `public/` dir with compressed full bin (/-.gz) and a json file - name: Create autoupdate files @@ -146,7 +146,7 @@ jobs: run: | cp darwin-amd64.json darwin-arm64.json cp ${TAG_VERSION}/darwin-amd64.gz ${TAG_VERSION}/darwin-arm64.gz - if: matrix.os == 'macos-12' && steps.prerelease.outputs.IS_PRE != 'true' + if: matrix.os == 'macos-13' && steps.prerelease.outputs.IS_PRE != 'true' - name: Create autoupdate files for win32 run: go-selfupdate -platform windows-${{ matrix.arch }} ${{ env.PROJECT_NAME }}${{ matrix.ext }} ${TAG_VERSION} @@ -181,7 +181,7 @@ jobs: matrix: arch: [amd64, arm64] - runs-on: macos-12 + runs-on: macos-13 env: EXE_PATH: "skel/ArduinoCloudAgent.app/Contents/MacOS/" @@ -195,7 +195,7 @@ jobs: - name: Download artifact uses: actions/download-artifact@v4 with: - name: ${{ env.PROJECT_NAME }}-macos-12-amd64 # if we want to support darwin-arm64 in the future for real this has to change. + name: ${{ env.PROJECT_NAME }}-macos-13-amd64 # if we want to support darwin-arm64 in the future for real this has to change. path: ${{ env.EXE_PATH }} - name: Remove placeholder file @@ -252,7 +252,7 @@ jobs: matrix: arch: [amd64, arm64] - runs-on: macos-12 + runs-on: macos-13 env: GON_PATH: ${{ github.workspace }}/gon needs: [build, create-macos-bundle] @@ -509,7 +509,7 @@ jobs: matrix: arch: [amd64] - runs-on: macos-12 + runs-on: macos-13 steps: - name: Checkout repo with icons/background uses: actions/checkout@v4 From 894c1397990c95c2067bb0f1698fce8d79462278 Mon Sep 17 00:00:00 2001 From: Davide N Date: Tue, 14 Jan 2025 17:19:30 +0100 Subject: [PATCH 15/20] fix(release): add Go installation step in release workflow --- .github/workflows/release.yml | 5 +++++ 1 file changed, 5 insertions(+) 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: From 3a341863b3f336267b192f3df00e0a641f817600 Mon Sep 17 00:00:00 2001 From: Davide N Date: Thu, 16 Jan 2025 14:51:50 +0100 Subject: [PATCH 16/20] fix: correct JSON formatting in broadcast message for port registration --- serial.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/serial.go b/serial.go index 5f5cd8e0..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) + "\"}") + 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() } From c042f10391e50a28359e65e5073504f4b9676ec1 Mon Sep 17 00:00:00 2001 From: Davide N Date: Mon, 20 Jan 2025 17:49:33 +0100 Subject: [PATCH 17/20] fix: update application identity in release workflow to use Massimo Banzi's Apple Key --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 709073df..0e31abff 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -314,7 +314,7 @@ jobs: bundle_id = "cc.arduino.${{ env.PROJECT_NAME }}" sign { - application_identity = "Developer ID Application: ARDUINO SA (7KT7ZWMCJT)" + application_identity = "Massimo Banzi Apple Key" deep = true } @@ -582,7 +582,7 @@ jobs: bundle_id = "cc.arduino.${{ env.PROJECT_NAME }}-installer" sign { - application_identity = "Developer ID Application: ARDUINO SA (7KT7ZWMCJT)" + application_identity = "Massimo Banzi Apple Key" } # Ask Gon for zip output to force notarization process to take place. From 43bd6eae9951c44342a02f2f94f993368c6f05cd Mon Sep 17 00:00:00 2001 From: Davide N Date: Tue, 21 Jan 2025 09:58:37 +0100 Subject: [PATCH 18/20] resolve conflict --- serialport.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/serialport.go b/serialport.go index d905c0ea..9a06c7f9 100755 --- a/serialport.go +++ b/serialport.go @@ -20,6 +20,7 @@ import ( "encoding/base64" "io" "strconv" + "sync/atomic" "time" log "github.com/sirupsen/logrus" @@ -42,7 +43,7 @@ type serport struct { // Keep track of whether we're being actively closed // just so we don't show scary error messages - isClosing bool + isClosing atomic.Bool isClosingDueToError bool @@ -79,7 +80,7 @@ func (p *serport) reader() { n, err := p.portIo.Read(serialBuffer) //if we detect that port is closing, break out of this for{} loop. - if p.isClosing { + if p.isClosing.Load() { strmsg := "Shutting down reader on " + p.portConf.Name log.Println(strmsg) h.broadcastSys <- []byte(strmsg) @@ -298,7 +299,8 @@ func spHandlerOpen(portname string, baud int) { } func (p *serport) Close() { - p.isClosing = true + p.isClosing.Store(true) + p.bufferFlow.Close() p.portIo.Close() serialPorts.MarkPortAsClosed(p.portName) From 8f5fa3b5dc4215ca86a32c575c03d5a9f6cb3113 Mon Sep 17 00:00:00 2001 From: Davide N Date: Tue, 21 Jan 2025 10:03:24 +0100 Subject: [PATCH 19/20] revert application_identity --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0e31abff..709073df 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -314,7 +314,7 @@ jobs: bundle_id = "cc.arduino.${{ env.PROJECT_NAME }}" sign { - application_identity = "Massimo Banzi Apple Key" + application_identity = "Developer ID Application: ARDUINO SA (7KT7ZWMCJT)" deep = true } @@ -582,7 +582,7 @@ jobs: bundle_id = "cc.arduino.${{ env.PROJECT_NAME }}-installer" sign { - application_identity = "Massimo Banzi Apple Key" + application_identity = "Developer ID Application: ARDUINO SA (7KT7ZWMCJT)" } # Ask Gon for zip output to force notarization process to take place. From 6684e7c7f96da48ffb77ddc12a7c6a226d074e06 Mon Sep 17 00:00:00 2001 From: Davide N Date: Tue, 21 Jan 2025 10:04:18 +0100 Subject: [PATCH 20/20] ci: remove tags-ignore from check-certificates workflow --- .github/workflows/check-certificates.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/check-certificates.yml b/.github/workflows/check-certificates.yml index 0c80be9c..694792dc 100644 --- a/.github/workflows/check-certificates.yml +++ b/.github/workflows/check-certificates.yml @@ -6,8 +6,6 @@ on: push: paths: - ".github/workflows/check-certificates.ya?ml" - tags-ignore: - - '*' pull_request: paths: - ".github/workflows/check-certificates.ya?ml"