Compare commits
No commits in common. "89319125839f9b71dda75878a9806f048e2a4fe2" and "5a948a5c8c7f0650c2ace123880ca8561e89619b" have entirely different histories.
8931912583
...
5a948a5c8c
14
Makefile
14
Makefile
@ -18,6 +18,10 @@ default:
|
|||||||
@echo "Targets: proto_generate gotool-build gotool-clients gotool-version …"
|
@echo "Targets: proto_generate gotool-build gotool-clients gotool-version …"
|
||||||
@echo "Set PORT=$(PORT) (current) for goTool targets."
|
@echo "Set PORT=$(PORT) (current) for goTool targets."
|
||||||
|
|
||||||
|
proto_generate_uart:
|
||||||
|
cd main/proto && python ../../libs/nanopb/generator/nanopb_generator.py \
|
||||||
|
-I ../../libs/nanopb/generator/proto uart_messages.proto
|
||||||
|
|
||||||
proto_generate_espnow:
|
proto_generate_espnow:
|
||||||
cd main/proto && python ../../libs/nanopb/generator/nanopb_generator.py \
|
cd main/proto && python ../../libs/nanopb/generator/nanopb_generator.py \
|
||||||
-I ../../libs/nanopb/generator/proto esp_now_messages.proto
|
-I ../../libs/nanopb/generator/proto esp_now_messages.proto
|
||||||
@ -27,15 +31,7 @@ proto_generate: proto_generate_uart proto_generate_espnow
|
|||||||
gotool-proto:
|
gotool-proto:
|
||||||
cd $(GOTOOL_DIR) && protoc --go_out=./pb --go_opt=paths=source_relative \
|
cd $(GOTOOL_DIR) && protoc --go_out=./pb --go_opt=paths=source_relative \
|
||||||
--go_opt=Muart_messages.proto=powerpod/gotool/pb \
|
--go_opt=Muart_messages.proto=powerpod/gotool/pb \
|
||||||
--go_opt=Mnanopb.proto=powerpod/gotool/pb/nanopb \
|
-I ../main/proto ../main/proto/uart_messages.proto
|
||||||
-I ../main/proto \
|
|
||||||
-I ../libs/nanopb/generator/proto \
|
|
||||||
../main/proto/uart_messages.proto
|
|
||||||
@sed -i '/powerpod\/gotool\/pb\/nanopb/d' $(GOTOOL_DIR)/pb/uart_messages.pb.go
|
|
||||||
|
|
||||||
proto_generate_uart:
|
|
||||||
cd main/proto && python3 ../../libs/nanopb/generator/nanopb_generator.py \
|
|
||||||
-I . -I ../../libs/nanopb/generator/proto uart_messages.proto
|
|
||||||
|
|
||||||
gotool-tidy:
|
gotool-tidy:
|
||||||
cd $(GOTOOL_DIR) && go mod tidy
|
cd $(GOTOOL_DIR) && go mod tidy
|
||||||
|
|||||||
@ -28,8 +28,6 @@ go run . -port /dev/ttyUSB0 clients
|
|||||||
| `test` | — | Run an automated scenario (JSON configs under `testdata/`) |
|
| `test` | — | Run an automated scenario (JSON configs under `testdata/`) |
|
||||||
| `serve` | — | Web dashboard at `http://localhost:8080` (WebSocket live updates) |
|
| `serve` | — | Web dashboard at `http://localhost:8080` (WebSocket live updates) |
|
||||||
| `ota` | 16–19 | UART firmware upload to master; firmware then pushes to slaves via ESP-NOW |
|
| `ota` | 16–19 | UART firmware upload to master; firmware then pushes to slaves via ESP-NOW |
|
||||||
| `ota-progress` | 21 | Query per-slave ESP-NOW OTA progress on the master (`-client N`, default all) |
|
|
||||||
| `led-ring` | 8 | LED ring: `-mode clear\|progress\|digit\|blink`, `-progress`, `-digit`, RGB, `-intensity` (0 = ~5 %), `-blink-ms`, `-blink-count` |
|
|
||||||
|
|
||||||
`clients` requires slaves to have responded to master discover broadcasts first.
|
`clients` requires slaves to have responded to master discover broadcasts first.
|
||||||
|
|
||||||
@ -74,7 +72,7 @@ HTTP API (used by the web UI): `GET/POST /api/deadzone`, `POST /api/unicast-test
|
|||||||
|
|
||||||
| UI / API | Behaviour |
|
| UI / API | Behaviour |
|
||||||
|----------|-----------|
|
|----------|-----------|
|
||||||
| Firmware OTA card | Same as `ota` CLI; WebSocket `ota_progress` with `step` `master` (UART) then `slaves` (ESP-NOW) |
|
| Firmware OTA card | Same as `ota` CLI; progress via WebSocket `ota_progress` events |
|
||||||
| `POST /api/ota` | Upload `.bin` to master only — slaves are updated by firmware over ESP-NOW after `OTA_END` |
|
| `POST /api/ota` | Upload `.bin` to master only — slaves are updated by firmware over ESP-NOW after `OTA_END` |
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@ -98,9 +96,8 @@ clients (2):
|
|||||||
|
|
||||||
## Regenerate protobuf
|
## Regenerate protobuf
|
||||||
|
|
||||||
From repo root (needs `protoc`, `protoc-gen-go`, and for C also `pip install protobuf`):
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make gotool-proto # Go: goTool/pb/uart_messages.pb.go
|
protoc --go_out=./pb --go_opt=paths=source_relative \
|
||||||
make proto_generate # C: main/proto/*.pb.h, *.pb.c
|
--go_opt=Muart_messages.proto=powerpod/gotool/pb \
|
||||||
|
-I ../main/proto ../main/proto/uart_messages.proto
|
||||||
```
|
```
|
||||||
|
|||||||
@ -16,14 +16,6 @@ func (m *managedSerial) getVersion() (*pb.VersionResponse, error) {
|
|||||||
return decodeVersionPayload(payload)
|
return decodeVersionPayload(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *managedSerial) getVersionPoll() (*pb.VersionResponse, error) {
|
|
||||||
payload, err := m.exchangePoll(byte(pb.MessageType_VERSION), "VERSION")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return decodeVersionPayload(payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *managedSerial) listClients() ([]*pb.ClientInfo, error) {
|
func (m *managedSerial) listClients() ([]*pb.ClientInfo, error) {
|
||||||
payload, err := m.exchange(byte(pb.MessageType_CLIENT_INFO), "CLIENT_INFO")
|
payload, err := m.exchange(byte(pb.MessageType_CLIENT_INFO), "CLIENT_INFO")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -32,28 +24,9 @@ func (m *managedSerial) listClients() ([]*pb.ClientInfo, error) {
|
|||||||
return decodeClientsPayload(payload)
|
return decodeClientsPayload(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *managedSerial) listClientsPoll() ([]*pb.ClientInfo, error) {
|
|
||||||
payload, err := m.exchangePoll(byte(pb.MessageType_CLIENT_INFO), "CLIENT_INFO")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return decodeClientsPayload(payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *managedSerial) AccelDeadzone(req *pb.AccelDeadzoneRequest) (*pb.AccelDeadzoneResponse, error) {
|
func (m *managedSerial) AccelDeadzone(req *pb.AccelDeadzoneRequest) (*pb.AccelDeadzoneResponse, error) {
|
||||||
return m.accelDeadzoneVia(m.withPort, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *managedSerial) AccelDeadzonePoll(req *pb.AccelDeadzoneRequest) (*pb.AccelDeadzoneResponse, error) {
|
|
||||||
return m.accelDeadzoneVia(m.withPortPoll, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *managedSerial) accelDeadzoneVia(
|
|
||||||
portFn func(func(*serialPort) error) error,
|
|
||||||
req *pb.AccelDeadzoneRequest,
|
|
||||||
) (*pb.AccelDeadzoneResponse, error) {
|
|
||||||
var resp *pb.AccelDeadzoneResponse
|
var resp *pb.AccelDeadzoneResponse
|
||||||
err := portFn(func(sp *serialPort) error {
|
err := m.withPort(func(sp *serialPort) error {
|
||||||
var e error
|
var e error
|
||||||
resp, e = sp.AccelDeadzone(req)
|
resp, e = sp.AccelDeadzone(req)
|
||||||
return e
|
return e
|
||||||
@ -172,33 +145,6 @@ func (s *serialPort) espnowUnicastTest(clientID, seq uint32) (*pb.EspNowUnicastT
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serialPort) ledRingProgress(req *pb.LedRingProgressRequest) (*pb.LedRingProgressResponse, error) {
|
|
||||||
msg := &pb.UartMessage{
|
|
||||||
Type: pb.MessageType_LED_RING,
|
|
||||||
Payload: &pb.UartMessage_LedRingProgressRequest{
|
|
||||||
LedRingProgressRequest: req,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
body, err := proto.Marshal(msg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("encode: %w", err)
|
|
||||||
}
|
|
||||||
payload := append([]byte{byte(pb.MessageType_LED_RING)}, body...)
|
|
||||||
respPayload, err := s.exchangePayload(payload, "LED_RING")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var respMsg pb.UartMessage
|
|
||||||
if err := proto.Unmarshal(respPayload[1:], &respMsg); err != nil {
|
|
||||||
return nil, fmt.Errorf("decode: %w", err)
|
|
||||||
}
|
|
||||||
r := respMsg.GetLedRingProgressResponse()
|
|
||||||
if r == nil {
|
|
||||||
return nil, fmt.Errorf("missing led_ring_progress_response")
|
|
||||||
}
|
|
||||||
return r, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *serialPort) GetVersion() (*pb.VersionResponse, error) { return s.getVersion() }
|
func (s *serialPort) GetVersion() (*pb.VersionResponse, error) { return s.getVersion() }
|
||||||
|
|
||||||
func (s *serialPort) ListClients() ([]*pb.ClientInfo, error) { return s.listClients() }
|
func (s *serialPort) ListClients() ([]*pb.ClientInfo, error) { return s.listClients() }
|
||||||
|
|||||||
@ -1,63 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"powerpod/gotool/pb"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ledRingModeClear = 0
|
|
||||||
ledRingModeProgress = 1
|
|
||||||
ledRingModeDigit = 2
|
|
||||||
ledRingModeBlink = 3
|
|
||||||
)
|
|
||||||
|
|
||||||
func runLedRing(sp *serialPort, args []string) error {
|
|
||||||
fs := flag.NewFlagSet("led-ring", flag.ExitOnError)
|
|
||||||
mode := fs.String("mode", "progress", "clear, progress, digit, or blink")
|
|
||||||
progress := fs.Uint("progress", 0, "fill level 0–100 (mode=progress)")
|
|
||||||
digit := fs.Uint("digit", 0, "digit 0–10 (mode=digit)")
|
|
||||||
r := fs.Uint("r", 0, "red 0–255")
|
|
||||||
g := fs.Uint("g", 255, "green 0–255")
|
|
||||||
b := fs.Uint("b", 0, "blue 0–255")
|
|
||||||
intensity := fs.Uint("intensity", 0, "brightness 0–255 (0 = device default ~5%)")
|
|
||||||
blinkMs := fs.Uint("blink-ms", 350, "pulse length in ms (mode=blink)")
|
|
||||||
blinkCount := fs.Uint("blink-count", 1, "number of pulses (mode=blink)")
|
|
||||||
if err := fs.Parse(args); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var modeVal uint32
|
|
||||||
switch *mode {
|
|
||||||
case "clear":
|
|
||||||
modeVal = ledRingModeClear
|
|
||||||
case "progress":
|
|
||||||
modeVal = ledRingModeProgress
|
|
||||||
case "digit":
|
|
||||||
modeVal = ledRingModeDigit
|
|
||||||
case "blink":
|
|
||||||
modeVal = ledRingModeBlink
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unknown -mode %q (clear, progress, digit, blink)", *mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := sp.ledRingProgress(&pb.LedRingProgressRequest{
|
|
||||||
Mode: modeVal,
|
|
||||||
Progress: uint32(*progress),
|
|
||||||
Digit: uint32(*digit),
|
|
||||||
R: uint32(*r),
|
|
||||||
G: uint32(*g),
|
|
||||||
B: uint32(*b),
|
|
||||||
Intensity: uint32(*intensity),
|
|
||||||
BlinkMs: uint32(*blinkMs),
|
|
||||||
BlinkCount: uint32(*blinkCount),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Printf("success=%v mode=%d progress=%d digit=%d\n",
|
|
||||||
resp.GetSuccess(), resp.GetMode(), resp.GetProgress(), resp.GetDigit())
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func runOtaProgress(sp *serialPort, args []string) error {
|
|
||||||
fs := flag.NewFlagSet("ota-progress", flag.ExitOnError)
|
|
||||||
clientID := fs.Uint("client", 0, "slave client id (0 = all in session)")
|
|
||||||
if err := fs.Parse(args); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
r, err := QueryOtaSlaveProgress(sp, uint32(*clientID))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("active=%v total=%d aggregate=%d slaves=%d\n",
|
|
||||||
r.GetActive(), r.GetTotalBytes(), r.GetAggregateBytes(), r.GetSlaveCount())
|
|
||||||
for _, s := range r.GetSlaves() {
|
|
||||||
fmt.Printf(" slave %d: %d / %d bytes status=%d error=%d\n",
|
|
||||||
s.GetClientId(), s.GetBytesWritten(), s.GetTotalBytes(),
|
|
||||||
s.GetStatus(), s.GetError())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@ -3,7 +3,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
@ -106,17 +105,14 @@ func (h *wsHub) broadcastRaw(v any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func pollDashboard(link *managedSerial, portName string, last *DashboardState) DashboardState {
|
func pollDashboard(link *managedSerial, portName string) DashboardState {
|
||||||
st := DashboardState{
|
st := DashboardState{
|
||||||
UpdatedAt: time.Now().Format(time.RFC3339),
|
UpdatedAt: time.Now().Format(time.RFC3339),
|
||||||
SerialPort: portName,
|
SerialPort: portName,
|
||||||
Clients: []ClientView{},
|
Clients: []ClientView{},
|
||||||
}
|
}
|
||||||
|
|
||||||
ver, err := link.getVersionPoll()
|
ver, err := link.getVersion()
|
||||||
if errors.Is(err, errUARTBusy) {
|
|
||||||
return pausedPollState(portName, last)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return disconnectedState(portName, err)
|
return disconnectedState(portName, err)
|
||||||
}
|
}
|
||||||
@ -128,15 +124,12 @@ func pollDashboard(link *managedSerial, portName string, last *DashboardState) D
|
|||||||
RunningPartition: ver.GetRunningPartition(),
|
RunningPartition: ver.GetRunningPartition(),
|
||||||
OK: true,
|
OK: true,
|
||||||
}
|
}
|
||||||
if dz, err := readDeadzonePoll(link, 0); err == nil {
|
if dz, err := readDeadzone(link, 0); err == nil {
|
||||||
st.Master.Deadzone = dz
|
st.Master.Deadzone = dz
|
||||||
}
|
}
|
||||||
|
|
||||||
clients, err := link.listClientsPoll()
|
clients, err := link.listClients()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, errUARTBusy) {
|
|
||||||
return pausedPollState(portName, last)
|
|
||||||
}
|
|
||||||
st.SerialOK = false
|
st.SerialOK = false
|
||||||
st.SerialError = err.Error()
|
st.SerialError = err.Error()
|
||||||
st.UARTConnected = link.IsConnected()
|
st.UARTConnected = link.IsConnected()
|
||||||
@ -153,7 +146,7 @@ func pollDashboard(link *managedSerial, portName string, last *DashboardState) D
|
|||||||
LastPing: c.GetLastPing(),
|
LastPing: c.GetLastPing(),
|
||||||
LastSuccessPing: c.GetLastSuccessPing(),
|
LastSuccessPing: c.GetLastSuccessPing(),
|
||||||
}
|
}
|
||||||
if dz, err := readDeadzonePoll(link, c.GetId()); err == nil {
|
if dz, err := readDeadzone(link, c.GetId()); err == nil {
|
||||||
cv.Deadzone = dz
|
cv.Deadzone = dz
|
||||||
}
|
}
|
||||||
st.Clients = append(st.Clients, cv)
|
st.Clients = append(st.Clients, cv)
|
||||||
@ -161,18 +154,6 @@ func pollDashboard(link *managedSerial, portName string, last *DashboardState) D
|
|||||||
return st
|
return st
|
||||||
}
|
}
|
||||||
|
|
||||||
func pausedPollState(portName string, last *DashboardState) DashboardState {
|
|
||||||
if last != nil && last.UARTConnected {
|
|
||||||
st := *last
|
|
||||||
st.UpdatedAt = time.Now().Format(time.RFC3339)
|
|
||||||
st.SerialPort = portName
|
|
||||||
st.SerialOK = true
|
|
||||||
st.SerialError = "Live-Polling pausiert (OTA läuft)"
|
|
||||||
return st
|
|
||||||
}
|
|
||||||
return disconnectedState(portName, errUARTBusy)
|
|
||||||
}
|
|
||||||
|
|
||||||
func readDeadzone(link *managedSerial, clientID uint32) (uint32, error) {
|
func readDeadzone(link *managedSerial, clientID uint32) (uint32, error) {
|
||||||
r, err := link.AccelDeadzone(&pb.AccelDeadzoneRequest{
|
r, err := link.AccelDeadzone(&pb.AccelDeadzoneRequest{
|
||||||
Write: false,
|
Write: false,
|
||||||
@ -187,20 +168,6 @@ func readDeadzone(link *managedSerial, clientID uint32) (uint32, error) {
|
|||||||
return r.GetDeadzone(), nil
|
return r.GetDeadzone(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readDeadzonePoll(link *managedSerial, clientID uint32) (uint32, error) {
|
|
||||||
r, err := link.AccelDeadzonePoll(&pb.AccelDeadzoneRequest{
|
|
||||||
Write: false,
|
|
||||||
ClientId: clientID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if !r.GetSuccess() {
|
|
||||||
return 0, fmt.Errorf("deadzone read failed for client %d", clientID)
|
|
||||||
}
|
|
||||||
return r.GetDeadzone(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatMAC(mac []byte) string {
|
func formatMAC(mac []byte) string {
|
||||||
if len(mac) == 0 {
|
if len(mac) == 0 {
|
||||||
return ""
|
return ""
|
||||||
@ -213,12 +180,8 @@ func runPoller(link *managedSerial, portName string, hub *wsHub, interval time.D
|
|||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
uartUp := false
|
uartUp := false
|
||||||
var lastGood DashboardState
|
|
||||||
publish := func() {
|
publish := func() {
|
||||||
st := pollDashboard(link, portName, &lastGood)
|
st := pollDashboard(link, portName)
|
||||||
if st.UARTConnected && st.SerialOK {
|
|
||||||
lastGood = st
|
|
||||||
}
|
|
||||||
if st.UARTConnected && !uartUp {
|
if st.UARTConnected && !uartUp {
|
||||||
log.Printf("UART %s connected", portName)
|
log.Printf("UART %s connected", portName)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,9 +19,7 @@ func usage() {
|
|||||||
fmt.Fprintf(os.Stderr, " unicast-test send ESP-NOW unicast test to one slave\n")
|
fmt.Fprintf(os.Stderr, " unicast-test send ESP-NOW unicast test to one slave\n")
|
||||||
fmt.Fprintf(os.Stderr, " test run automated scenario (see testdata/)\n")
|
fmt.Fprintf(os.Stderr, " test run automated scenario (see testdata/)\n")
|
||||||
fmt.Fprintf(os.Stderr, " serve web dashboard (Bootstrap + WebSocket)\n")
|
fmt.Fprintf(os.Stderr, " serve web dashboard (Bootstrap + WebSocket)\n")
|
||||||
fmt.Fprintf(os.Stderr, " ota UART OTA upload (A/B partitions)\n")
|
fmt.Fprintf(os.Stderr, " ota UART OTA upload (A/B partitions)\n\n")
|
||||||
fmt.Fprintf(os.Stderr, " ota-progress query per-slave ESP-NOW OTA progress on master\n")
|
|
||||||
fmt.Fprintf(os.Stderr, " led-ring set LED ring progress bar (0–100%%, rgb, intensity)\n\n")
|
|
||||||
flag.PrintDefaults()
|
flag.PrintDefaults()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +46,7 @@ func main() {
|
|||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
runErr = runServe(*portName, *baud, flag.Args()[1:])
|
runErr = runServe(*portName, *baud, flag.Args()[1:])
|
||||||
case "version", "clients", "client-info", "deadzone", "accel-deadzone", "unicast-test", "unicast_test", "led-ring", "led_ring", "ota", "ota-progress", "ota_progress":
|
case "version", "clients", "client-info", "deadzone", "accel-deadzone", "unicast-test", "unicast_test", "ota":
|
||||||
if *portName == "" {
|
if *portName == "" {
|
||||||
fmt.Fprintf(os.Stderr, "command %q requires -port\n\n", cmd)
|
fmt.Fprintf(os.Stderr, "command %q requires -port\n\n", cmd)
|
||||||
usage()
|
usage()
|
||||||
@ -68,12 +66,8 @@ func main() {
|
|||||||
runErr = runDeadzone(sp, flag.Args()[1:])
|
runErr = runDeadzone(sp, flag.Args()[1:])
|
||||||
case "unicast-test", "unicast_test":
|
case "unicast-test", "unicast_test":
|
||||||
runErr = runUnicastTest(sp, flag.Args()[1:])
|
runErr = runUnicastTest(sp, flag.Args()[1:])
|
||||||
case "led-ring", "led_ring":
|
|
||||||
runErr = runLedRing(sp, flag.Args()[1:])
|
|
||||||
case "ota":
|
case "ota":
|
||||||
runErr = runOTA(sp, flag.Args()[1:])
|
runErr = runOTA(sp, flag.Args()[1:])
|
||||||
case "ota-progress", "ota_progress":
|
|
||||||
runErr = runOtaProgress(sp, flag.Args()[1:])
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
fmt.Fprintf(os.Stderr, "unknown command %q\n\n", cmd)
|
fmt.Fprintf(os.Stderr, "unknown command %q\n\n", cmd)
|
||||||
|
|||||||
@ -16,11 +16,6 @@ const (
|
|||||||
otaFlashBlockSize = 4096
|
otaFlashBlockSize = 4096
|
||||||
otaPrepareTimeout = 120 * time.Second
|
otaPrepareTimeout = 120 * time.Second
|
||||||
otaDefaultTimeout = 15 * time.Second
|
otaDefaultTimeout = 15 * time.Second
|
||||||
otaStatusPollTimeout = 3 * time.Second
|
|
||||||
otaDistReadTimeout = 400 * time.Millisecond
|
|
||||||
otaDistQueryInterval = 500 * time.Millisecond
|
|
||||||
otaDistQueryTimeout = 2 * time.Second
|
|
||||||
otaDistEmitMinInterval = 150 * time.Millisecond
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -29,45 +24,20 @@ const (
|
|||||||
otaStBlockAck = 3
|
otaStBlockAck = 3
|
||||||
otaStSuccess = 4
|
otaStSuccess = 4
|
||||||
otaStFailed = 5
|
otaStFailed = 5
|
||||||
otaStDistributing = 6
|
|
||||||
otaDistAggregate = 0
|
|
||||||
otaDistPerSlave = 1
|
|
||||||
otaDistTimeout = 45 * time.Minute
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// OtaSlaveDetail is per-slave ESP-NOW OTA state from OTA_SLAVE_PROGRESS.
|
|
||||||
type OtaSlaveDetail struct {
|
|
||||||
BytesWritten uint32 `json:"bytes_written"`
|
|
||||||
TotalBytes uint32 `json:"total_bytes"`
|
|
||||||
Status uint32 `json:"status"`
|
|
||||||
Error uint32 `json:"error"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// OTAProgress is pushed to the dashboard during web uploads.
|
// OTAProgress is pushed to the dashboard during web uploads.
|
||||||
type OTAProgress struct {
|
type OTAProgress struct {
|
||||||
Type string `json:"type"` // always "ota_progress"
|
Type string `json:"type"` // always "ota_progress"
|
||||||
Phase string `json:"phase"`
|
Phase string `json:"phase"` // preparing, ready, uploading, done, error
|
||||||
Step string `json:"step,omitempty"` // master, slaves
|
|
||||||
Percent int `json:"percent"`
|
Percent int `json:"percent"`
|
||||||
MasterPercent int `json:"master_percent,omitempty"`
|
|
||||||
MasterDone bool `json:"master_done,omitempty"`
|
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
MasterMessage string `json:"master_message,omitempty"`
|
|
||||||
Bytes uint32 `json:"bytes_written,omitempty"`
|
Bytes uint32 `json:"bytes_written,omitempty"`
|
||||||
Slot uint32 `json:"target_slot,omitempty"`
|
Slot uint32 `json:"target_slot,omitempty"`
|
||||||
Slaves uint32 `json:"slaves,omitempty"`
|
|
||||||
ImageSize uint32 `json:"image_size,omitempty"`
|
|
||||||
SlaveProgress map[uint32]uint32 `json:"slave_progress,omitempty"` // client_id -> bytes
|
|
||||||
SlaveDetails map[uint32]OtaSlaveDetail `json:"slave_details,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type otaProgressFn func(OTAProgress)
|
type otaProgressFn func(OTAProgress)
|
||||||
|
|
||||||
const (
|
|
||||||
otaStepMaster = "master"
|
|
||||||
otaStepSlaves = "slaves"
|
|
||||||
)
|
|
||||||
|
|
||||||
func runOTAUpload(m *managedSerial, firmware []byte, onProgress otaProgressFn) error {
|
func runOTAUpload(m *managedSerial, firmware []byte, onProgress otaProgressFn) error {
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
defer m.mu.Unlock()
|
defer m.mu.Unlock()
|
||||||
@ -82,95 +52,69 @@ func runOTAOnPortUnlocked(m *managedSerial, firmware []byte, onProgress otaProgr
|
|||||||
if len(firmware) == 0 {
|
if len(firmware) == 0 {
|
||||||
return fmt.Errorf("empty firmware")
|
return fmt.Errorf("empty firmware")
|
||||||
}
|
}
|
||||||
imageSize := len(firmware)
|
notify := func(phase string, percent int, msg string, extra ...OTAProgress) {
|
||||||
masterPct := 0
|
|
||||||
masterMsg := ""
|
|
||||||
notify := func(phase, step string, percent int, msg string, extra ...OTAProgress) {
|
|
||||||
if onProgress == nil {
|
if onProgress == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p := OTAProgress{
|
p := OTAProgress{Type: "ota_progress", Phase: phase, Percent: percent, Message: msg}
|
||||||
Type: "ota_progress", Phase: phase, Step: step,
|
|
||||||
Percent: percent, Message: msg,
|
|
||||||
ImageSize: uint32(imageSize),
|
|
||||||
}
|
|
||||||
if step == otaStepMaster || phase == "preparing" || phase == "ready" || phase == "uploading" {
|
|
||||||
masterPct = percent
|
|
||||||
masterMsg = msg
|
|
||||||
}
|
|
||||||
p.MasterPercent = masterPct
|
|
||||||
p.MasterMessage = masterMsg
|
|
||||||
if step == otaStepSlaves || phase == "distributing" || phase == "done" {
|
|
||||||
p.MasterDone = true
|
|
||||||
}
|
|
||||||
if len(extra) > 0 {
|
if len(extra) > 0 {
|
||||||
e := extra[0]
|
p.Bytes = extra[0].Bytes
|
||||||
p.Bytes = e.Bytes
|
p.Slot = extra[0].Slot
|
||||||
p.Slot = e.Slot
|
|
||||||
p.Slaves = e.Slaves
|
|
||||||
p.SlaveProgress = e.SlaveProgress
|
|
||||||
p.SlaveDetails = e.SlaveDetails
|
|
||||||
if e.MasterPercent > 0 {
|
|
||||||
p.MasterPercent = e.MasterPercent
|
|
||||||
}
|
|
||||||
if e.MasterMessage != "" {
|
|
||||||
p.MasterMessage = e.MasterMessage
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
onProgress(p)
|
onProgress(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.sp == nil {
|
if m.sp == nil {
|
||||||
if err := m.openLocked(); err != nil {
|
if err := m.openLocked(); err != nil {
|
||||||
notify("error", "", 0, err.Error())
|
notify("error", 0, err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sp := m.sp
|
sp := m.sp
|
||||||
if err := sp.port.SetReadTimeout(otaPrepareTimeout); err != nil {
|
if err := sp.port.SetReadTimeout(otaPrepareTimeout); err != nil {
|
||||||
notify("error", "", 0, err.Error())
|
notify("error", 0, err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer sp.port.SetReadTimeout(readTimeout)
|
defer sp.port.SetReadTimeout(readTimeout)
|
||||||
|
|
||||||
notify("preparing", otaStepMaster, 0, fmt.Sprintf("Master: OTA start (%d bytes)…", imageSize))
|
notify("preparing", 0, fmt.Sprintf("OTA start (%d bytes)…", len(firmware)))
|
||||||
|
|
||||||
if err := writeUartMessage(sp, &pb.UartMessage{
|
if err := writeUartMessage(sp, &pb.UartMessage{
|
||||||
Type: pb.MessageType_OTA_START,
|
Type: pb.MessageType_OTA_START,
|
||||||
Payload: &pb.UartMessage_OtaStart{
|
Payload: &pb.UartMessage_OtaStart{
|
||||||
OtaStart: &pb.OtaStartPayload{TotalSize: uint32(imageSize)},
|
OtaStart: &pb.OtaStartPayload{TotalSize: uint32(len(firmware))},
|
||||||
},
|
},
|
||||||
}, false); err != nil {
|
}, false); err != nil {
|
||||||
notify("error", "", 0, err.Error())
|
notify("error", 0, err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ready, err := waitOtaStatus(sp, otaStReady, otaPrepareTimeout, func(msg string) {
|
ready, err := waitOtaStatus(sp, otaStReady, otaPrepareTimeout, func(msg string) {
|
||||||
notify("preparing", otaStepMaster, 2, msg)
|
notify("preparing", 2, msg)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
notify("error", "", 0, err.Error())
|
notify("error", 0, err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
notify("ready", otaStepMaster, 5, fmt.Sprintf("Master: Slot %d bereit", ready.GetTargetSlot()))
|
notify("ready", 5, fmt.Sprintf("Ziel-Slot %d bereit", ready.GetTargetSlot()))
|
||||||
|
|
||||||
if err := sp.port.SetReadTimeout(otaDefaultTimeout); err != nil {
|
if err := sp.port.SetReadTimeout(otaDefaultTimeout); err != nil {
|
||||||
notify("error", "", 0, err.Error())
|
notify("error", 0, err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var seq uint32
|
var seq uint32
|
||||||
for offset := 0; offset < imageSize; {
|
for offset := 0; offset < len(firmware); {
|
||||||
bytesInBlock := 0
|
bytesInBlock := 0
|
||||||
for bytesInBlock < otaFlashBlockSize && offset < imageSize {
|
for bytesInBlock < otaFlashBlockSize && offset < len(firmware) {
|
||||||
n := otaHostChunkSize
|
n := otaHostChunkSize
|
||||||
room := otaFlashBlockSize - bytesInBlock
|
room := otaFlashBlockSize - bytesInBlock
|
||||||
if n > room {
|
if n > room {
|
||||||
n = room
|
n = room
|
||||||
}
|
}
|
||||||
if offset+n > imageSize {
|
if offset+n > len(firmware) {
|
||||||
n = imageSize - offset
|
n = len(firmware) - offset
|
||||||
}
|
}
|
||||||
chunk := firmware[offset : offset+n]
|
chunk := firmware[offset : offset+n]
|
||||||
|
|
||||||
@ -180,311 +124,53 @@ func runOTAOnPortUnlocked(m *managedSerial, firmware []byte, onProgress otaProgr
|
|||||||
OtaPayload: &pb.OtaPayload{Seq: seq, Data: chunk},
|
OtaPayload: &pb.OtaPayload{Seq: seq, Data: chunk},
|
||||||
},
|
},
|
||||||
}, false); err != nil {
|
}, false); err != nil {
|
||||||
notify("error", "", 0, err.Error())
|
notify("error", 0, err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
seq++
|
seq++
|
||||||
offset += n
|
offset += n
|
||||||
bytesInBlock += n
|
bytesInBlock += n
|
||||||
|
|
||||||
pct := offset * 100 / imageSize
|
pct := 5 + (offset * 90 / len(firmware))
|
||||||
if pct > 99 {
|
notify("uploading", pct, fmt.Sprintf("%d / %d bytes", offset, len(firmware)))
|
||||||
pct = 99
|
|
||||||
}
|
|
||||||
notify("uploading", otaStepMaster, pct, fmt.Sprintf("Master: %d / %d bytes", offset, imageSize))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if bytesInBlock == otaFlashBlockSize {
|
if bytesInBlock == otaFlashBlockSize {
|
||||||
st, err := waitOtaStatus(sp, otaStBlockAck, otaDefaultTimeout, nil)
|
st, err := waitOtaStatus(sp, otaStBlockAck, otaDefaultTimeout, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
notify("error", "", 0, err.Error())
|
notify("error", 0, err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
pct := offset * 100 / imageSize
|
pct := 5 + (offset * 90 / len(firmware))
|
||||||
if pct > 99 {
|
notify("uploading", pct, fmt.Sprintf("Block geschrieben (%d bytes in flash)", st.GetBytesWritten()),
|
||||||
pct = 99
|
|
||||||
}
|
|
||||||
notify("uploading", otaStepMaster, pct,
|
|
||||||
fmt.Sprintf("Master: Block geschrieben (%d bytes)", st.GetBytesWritten()),
|
|
||||||
OTAProgress{Bytes: st.GetBytesWritten()})
|
OTAProgress{Bytes: st.GetBytesWritten()})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
masterPct = 100
|
|
||||||
masterMsg = "Master: UART-Upload abgeschlossen"
|
|
||||||
notify("uploading", otaStepMaster, 100, masterMsg)
|
|
||||||
|
|
||||||
if err := writeUartMessage(sp, &pb.UartMessage{
|
if err := writeUartMessage(sp, &pb.UartMessage{
|
||||||
Type: pb.MessageType_OTA_END,
|
Type: pb.MessageType_OTA_END,
|
||||||
Payload: &pb.UartMessage_OtaEnd{
|
Payload: &pb.UartMessage_OtaEnd{
|
||||||
OtaEnd: &pb.OtaEndPayload{},
|
OtaEnd: &pb.OtaEndPayload{},
|
||||||
},
|
},
|
||||||
}, false); err != nil {
|
}, false); err != nil {
|
||||||
notify("error", "", 0, err.Error())
|
notify("error", 0, err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
slaveBytes := make(map[uint32]uint32)
|
|
||||||
slaveDetails := make(map[uint32]OtaSlaveDetail)
|
|
||||||
|
|
||||||
emitSlaveOTA := func(msg string, aggBytes uint32, slaveCount uint32) {
|
|
||||||
if slaveCount == 0 && len(slaveDetails) > 0 {
|
|
||||||
slaveCount = uint32(len(slaveDetails))
|
|
||||||
}
|
|
||||||
notify("distributing", otaStepSlaves, 0, msg,
|
|
||||||
OTAProgress{
|
|
||||||
Bytes: aggBytes, Slaves: slaveCount,
|
|
||||||
MasterPercent: 100, MasterMessage: masterMsg,
|
|
||||||
SlaveProgress: copySlaveMap(slaveBytes),
|
|
||||||
SlaveDetails: copySlaveDetails(slaveDetails),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onDistStatus := func(st *pb.OtaStatusPayload) {
|
|
||||||
applyDistributingOtaStatus(st, imageSize, slaveBytes, slaveDetails)
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastEmit, lastQuery time.Time
|
|
||||||
slaveDistMessage := func() (msg string, aggBytes, slaveCount uint32) {
|
|
||||||
slaveCount = uint32(len(slaveDetails))
|
|
||||||
for _, d := range slaveDetails {
|
|
||||||
if d.BytesWritten > aggBytes {
|
|
||||||
aggBytes = d.BytesWritten
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if slaveCount == 0 {
|
|
||||||
return "Keine verfügbaren Slaves — Verteilung übersprungen", 0, 0
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("ESP-NOW: %d / %d bytes (%d Slaves)",
|
|
||||||
aggBytes, imageSize, slaveCount), aggBytes, slaveCount
|
|
||||||
}
|
|
||||||
|
|
||||||
emitSlaveThrottled := func(force bool) {
|
|
||||||
if !force && time.Since(lastEmit) < otaDistEmitMinInterval {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
lastEmit = time.Now()
|
|
||||||
msg, agg, n := slaveDistMessage()
|
|
||||||
emitSlaveOTA(msg, agg, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
querySlaveProgress := func() {
|
|
||||||
if time.Since(lastQuery) < otaDistQueryInterval {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
lastQuery = time.Now()
|
|
||||||
prog, err := queryOtaSlaveProgressLocked(sp, 0, onDistStatus, otaDistQueryTimeout)
|
|
||||||
if err != nil {
|
|
||||||
if len(slaveDetails) > 0 {
|
|
||||||
emitSlaveThrottled(true)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mergeSlaveProgressResponse(prog, slaveBytes, slaveDetails)
|
|
||||||
emitSlaveThrottled(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
pushSlaveDist := func(st *pb.OtaStatusPayload) {
|
|
||||||
onDistStatus(st)
|
|
||||||
emitSlaveThrottled(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
onWaitTick := func() {
|
|
||||||
querySlaveProgress()
|
|
||||||
}
|
|
||||||
|
|
||||||
lastQuery = time.Time{} // first query immediately when distribution starts
|
|
||||||
querySlaveProgress()
|
|
||||||
st, err := waitOtaComplete(sp, otaDistTimeout, pushSlaveDist, onWaitTick, otaDistReadTimeout)
|
|
||||||
if err != nil {
|
|
||||||
notify("error", "", 0, err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if prog, err := queryOtaSlaveProgressLocked(sp, 0, nil, otaDistQueryTimeout); err == nil {
|
|
||||||
mergeSlaveProgressResponse(prog, slaveBytes, slaveDetails)
|
|
||||||
}
|
|
||||||
notify("done", "", 100,
|
|
||||||
fmt.Sprintf("Fertig — %d bytes, Boot-Slot %d. Master und Slaves neu starten.",
|
|
||||||
st.GetBytesWritten(), st.GetTargetSlot()),
|
|
||||||
OTAProgress{
|
|
||||||
Bytes: st.GetBytesWritten(), Slot: st.GetTargetSlot(),
|
|
||||||
MasterPercent: 100, MasterMessage: "Master: OK",
|
|
||||||
SlaveProgress: copySlaveMap(slaveBytes),
|
|
||||||
SlaveDetails: copySlaveDetails(slaveDetails),
|
|
||||||
})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryOtaSlaveProgress queries the master for per-slave ESP-NOW OTA progress.
|
|
||||||
func QueryOtaSlaveProgress(sp *serialPort, clientID uint32) (*pb.OtaSlaveProgressResponse, error) {
|
|
||||||
sp.mu.Lock()
|
|
||||||
defer sp.mu.Unlock()
|
|
||||||
return queryOtaSlaveProgressLocked(sp, clientID, nil, otaDefaultTimeout)
|
|
||||||
}
|
|
||||||
|
|
||||||
func queryOtaSlaveProgressLocked(sp *serialPort, clientID uint32,
|
|
||||||
onStatus func(*pb.OtaStatusPayload), queryTimeout time.Duration) (*pb.OtaSlaveProgressResponse, error) {
|
|
||||||
req := &pb.UartMessage{
|
|
||||||
Type: pb.MessageType_OTA_SLAVE_PROGRESS,
|
|
||||||
Payload: &pb.UartMessage_OtaSlaveProgressRequest{
|
|
||||||
OtaSlaveProgressRequest: &pb.OtaSlaveProgressRequest{
|
|
||||||
ClientId: clientID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if err := writeUartMessage(sp, req, false); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if queryTimeout <= 0 {
|
|
||||||
queryTimeout = otaDefaultTimeout
|
|
||||||
}
|
|
||||||
deadline := time.Now().Add(queryTimeout)
|
|
||||||
msg, err := readUartMessageUntil(sp, deadline, pb.MessageType_OTA_SLAVE_PROGRESS, onStatus, otaDistReadTimeout)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
r := msg.GetOtaSlaveProgressResponse()
|
|
||||||
if r == nil {
|
|
||||||
return nil, fmt.Errorf("missing ota_slave_progress_response")
|
|
||||||
}
|
|
||||||
return r, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func applyDistributingOtaStatus(st *pb.OtaStatusPayload, imageSize int,
|
|
||||||
slaveBytes map[uint32]uint32, details map[uint32]OtaSlaveDetail) {
|
|
||||||
if st == nil || st.GetStatus() != otaStDistributing {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if st.GetError() != otaDistPerSlave {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
id := st.GetTargetSlot()
|
|
||||||
bw := st.GetBytesWritten()
|
|
||||||
slaveBytes[id] = bw
|
|
||||||
d := details[id]
|
|
||||||
d.BytesWritten = bw
|
|
||||||
if d.TotalBytes == 0 {
|
|
||||||
d.TotalBytes = uint32(imageSize)
|
|
||||||
}
|
|
||||||
if d.Status == 0 || d.Status == 1 || d.Status == 2 {
|
|
||||||
d.Status = 3
|
|
||||||
}
|
|
||||||
details[id] = d
|
|
||||||
}
|
|
||||||
|
|
||||||
func readUartMessageUntil(sp *serialPort, deadline time.Time, want pb.MessageType,
|
|
||||||
onStatus func(*pb.OtaStatusPayload), readChunk time.Duration) (*pb.UartMessage, error) {
|
|
||||||
if readChunk <= 0 {
|
|
||||||
readChunk = otaStatusPollTimeout
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
if time.Now().After(deadline) {
|
|
||||||
return nil, fmt.Errorf("timeout waiting for %v", want)
|
|
||||||
}
|
|
||||||
wait := time.Until(deadline)
|
|
||||||
if wait > readChunk {
|
|
||||||
wait = readChunk
|
|
||||||
}
|
|
||||||
if err := sp.port.SetReadTimeout(wait); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
payload, err := uartframe.ReadFrame(sp.port, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
msg, err := decodeUartPayload(payload)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if msg.GetType() == pb.MessageType_OTA_STATUS {
|
|
||||||
if onStatus != nil {
|
|
||||||
if st := msg.GetOtaStatus(); st != nil {
|
|
||||||
onStatus(st)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if msg.GetType() == want {
|
|
||||||
return msg, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mergeSlaveProgressResponse(r *pb.OtaSlaveProgressResponse,
|
|
||||||
bytesOut map[uint32]uint32, detailsOut map[uint32]OtaSlaveDetail) {
|
|
||||||
if r == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, s := range r.GetSlaves() {
|
|
||||||
id := s.GetClientId()
|
|
||||||
bytesOut[id] = s.GetBytesWritten()
|
|
||||||
detailsOut[id] = OtaSlaveDetail{
|
|
||||||
BytesWritten: s.GetBytesWritten(),
|
|
||||||
TotalBytes: s.GetTotalBytes(),
|
|
||||||
Status: s.GetStatus(),
|
|
||||||
Error: s.GetError(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func copySlaveDetails(m map[uint32]OtaSlaveDetail) map[uint32]OtaSlaveDetail {
|
|
||||||
out := make(map[uint32]OtaSlaveDetail, len(m))
|
|
||||||
for k, v := range m {
|
|
||||||
out[k] = v
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func copySlaveMap(m map[uint32]uint32) map[uint32]uint32 {
|
|
||||||
out := make(map[uint32]uint32, len(m))
|
|
||||||
for k, v := range m {
|
|
||||||
out[k] = v
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func waitOtaComplete(sp *serialPort, timeout time.Duration,
|
|
||||||
onDistributing func(*pb.OtaStatusPayload), onInterval func(),
|
|
||||||
readTimeout time.Duration) (*pb.OtaStatusPayload, error) {
|
|
||||||
if readTimeout <= 0 {
|
|
||||||
readTimeout = otaStatusPollTimeout
|
|
||||||
}
|
|
||||||
deadline := time.Now().Add(timeout)
|
|
||||||
for {
|
|
||||||
if time.Now().After(deadline) {
|
|
||||||
return nil, fmt.Errorf("timeout waiting for OTA success (slave distribution?)")
|
|
||||||
}
|
|
||||||
readWait := time.Until(deadline)
|
|
||||||
if readWait > readTimeout {
|
|
||||||
readWait = readTimeout
|
|
||||||
}
|
|
||||||
if err := sp.port.SetReadTimeout(readWait); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
st, err := readOtaStatus(sp)
|
st, err := readOtaStatus(sp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if onInterval != nil {
|
notify("error", 0, err.Error())
|
||||||
onInterval()
|
return err
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch st.GetStatus() {
|
|
||||||
case otaStSuccess:
|
|
||||||
return st, nil
|
|
||||||
case otaStFailed:
|
|
||||||
return nil, fmt.Errorf("OTA failed (error=%d)", st.GetError())
|
|
||||||
case otaStDistributing:
|
|
||||||
if onDistributing != nil {
|
|
||||||
onDistributing(st)
|
|
||||||
}
|
|
||||||
if onInterval != nil {
|
|
||||||
onInterval()
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// ignore other interim statuses
|
|
||||||
}
|
}
|
||||||
|
if st.GetStatus() != otaStSuccess {
|
||||||
|
err := fmt.Errorf("OTA failed: status=%d error=%d", st.GetStatus(), st.GetError())
|
||||||
|
notify("error", 0, err.Error())
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
notify("done", 100, fmt.Sprintf("Erfolg — %d bytes auf Slot %d (Neustart)", st.GetBytesWritten(), st.GetTargetSlot()),
|
||||||
|
OTAProgress{Bytes: st.GetBytesWritten(), Slot: st.GetTargetSlot()})
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeUartMessage(sp *serialPort, msg *pb.UartMessage, logFrame bool) error {
|
func writeUartMessage(sp *serialPort, msg *pb.UartMessage, logFrame bool) error {
|
||||||
|
|||||||
@ -32,13 +32,11 @@ const (
|
|||||||
MessageType_CLIENT_INPUT MessageType = 5
|
MessageType_CLIENT_INPUT MessageType = 5
|
||||||
MessageType_ACCEL_DEADZONE MessageType = 6
|
MessageType_ACCEL_DEADZONE MessageType = 6
|
||||||
MessageType_ESPNOW_UNICAST_TEST MessageType = 7
|
MessageType_ESPNOW_UNICAST_TEST MessageType = 7
|
||||||
MessageType_LED_RING MessageType = 8
|
|
||||||
MessageType_OTA_START MessageType = 16
|
MessageType_OTA_START MessageType = 16
|
||||||
MessageType_OTA_PAYLOAD MessageType = 17
|
MessageType_OTA_PAYLOAD MessageType = 17
|
||||||
MessageType_OTA_END MessageType = 18
|
MessageType_OTA_END MessageType = 18
|
||||||
MessageType_OTA_STATUS MessageType = 19
|
MessageType_OTA_STATUS MessageType = 19
|
||||||
MessageType_OTA_START_ESPNOW MessageType = 20
|
MessageType_OTA_START_ESPNOW MessageType = 20
|
||||||
MessageType_OTA_SLAVE_PROGRESS MessageType = 21
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Enum value maps for MessageType.
|
// Enum value maps for MessageType.
|
||||||
@ -52,13 +50,11 @@ var (
|
|||||||
5: "CLIENT_INPUT",
|
5: "CLIENT_INPUT",
|
||||||
6: "ACCEL_DEADZONE",
|
6: "ACCEL_DEADZONE",
|
||||||
7: "ESPNOW_UNICAST_TEST",
|
7: "ESPNOW_UNICAST_TEST",
|
||||||
8: "LED_RING",
|
|
||||||
16: "OTA_START",
|
16: "OTA_START",
|
||||||
17: "OTA_PAYLOAD",
|
17: "OTA_PAYLOAD",
|
||||||
18: "OTA_END",
|
18: "OTA_END",
|
||||||
19: "OTA_STATUS",
|
19: "OTA_STATUS",
|
||||||
20: "OTA_START_ESPNOW",
|
20: "OTA_START_ESPNOW",
|
||||||
21: "OTA_SLAVE_PROGRESS",
|
|
||||||
}
|
}
|
||||||
MessageType_value = map[string]int32{
|
MessageType_value = map[string]int32{
|
||||||
"UNKNOWN": 0,
|
"UNKNOWN": 0,
|
||||||
@ -69,13 +65,11 @@ var (
|
|||||||
"CLIENT_INPUT": 5,
|
"CLIENT_INPUT": 5,
|
||||||
"ACCEL_DEADZONE": 6,
|
"ACCEL_DEADZONE": 6,
|
||||||
"ESPNOW_UNICAST_TEST": 7,
|
"ESPNOW_UNICAST_TEST": 7,
|
||||||
"LED_RING": 8,
|
|
||||||
"OTA_START": 16,
|
"OTA_START": 16,
|
||||||
"OTA_PAYLOAD": 17,
|
"OTA_PAYLOAD": 17,
|
||||||
"OTA_END": 18,
|
"OTA_END": 18,
|
||||||
"OTA_STATUS": 19,
|
"OTA_STATUS": 19,
|
||||||
"OTA_START_ESPNOW": 20,
|
"OTA_START_ESPNOW": 20,
|
||||||
"OTA_SLAVE_PROGRESS": 21,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -124,10 +118,6 @@ type UartMessage struct {
|
|||||||
// *UartMessage_AccelDeadzoneResponse
|
// *UartMessage_AccelDeadzoneResponse
|
||||||
// *UartMessage_EspnowUnicastTestRequest
|
// *UartMessage_EspnowUnicastTestRequest
|
||||||
// *UartMessage_EspnowUnicastTestResponse
|
// *UartMessage_EspnowUnicastTestResponse
|
||||||
// *UartMessage_OtaSlaveProgressRequest
|
|
||||||
// *UartMessage_OtaSlaveProgressResponse
|
|
||||||
// *UartMessage_LedRingProgressRequest
|
|
||||||
// *UartMessage_LedRingProgressResponse
|
|
||||||
Payload isUartMessage_Payload `protobuf_oneof:"payload"`
|
Payload isUartMessage_Payload `protobuf_oneof:"payload"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@ -294,42 +284,6 @@ func (x *UartMessage) GetEspnowUnicastTestResponse() *EspNowUnicastTestResponse
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *UartMessage) GetOtaSlaveProgressRequest() *OtaSlaveProgressRequest {
|
|
||||||
if x != nil {
|
|
||||||
if x, ok := x.Payload.(*UartMessage_OtaSlaveProgressRequest); ok {
|
|
||||||
return x.OtaSlaveProgressRequest
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *UartMessage) GetOtaSlaveProgressResponse() *OtaSlaveProgressResponse {
|
|
||||||
if x != nil {
|
|
||||||
if x, ok := x.Payload.(*UartMessage_OtaSlaveProgressResponse); ok {
|
|
||||||
return x.OtaSlaveProgressResponse
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *UartMessage) GetLedRingProgressRequest() *LedRingProgressRequest {
|
|
||||||
if x != nil {
|
|
||||||
if x, ok := x.Payload.(*UartMessage_LedRingProgressRequest); ok {
|
|
||||||
return x.LedRingProgressRequest
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *UartMessage) GetLedRingProgressResponse() *LedRingProgressResponse {
|
|
||||||
if x != nil {
|
|
||||||
if x, ok := x.Payload.(*UartMessage_LedRingProgressResponse); ok {
|
|
||||||
return x.LedRingProgressResponse
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type isUartMessage_Payload interface {
|
type isUartMessage_Payload interface {
|
||||||
isUartMessage_Payload()
|
isUartMessage_Payload()
|
||||||
}
|
}
|
||||||
@ -386,22 +340,6 @@ type UartMessage_EspnowUnicastTestResponse struct {
|
|||||||
EspnowUnicastTestResponse *EspNowUnicastTestResponse `protobuf:"bytes,14,opt,name=espnow_unicast_test_response,json=espnowUnicastTestResponse,proto3,oneof"`
|
EspnowUnicastTestResponse *EspNowUnicastTestResponse `protobuf:"bytes,14,opt,name=espnow_unicast_test_response,json=espnowUnicastTestResponse,proto3,oneof"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UartMessage_OtaSlaveProgressRequest struct {
|
|
||||||
OtaSlaveProgressRequest *OtaSlaveProgressRequest `protobuf:"bytes,15,opt,name=ota_slave_progress_request,json=otaSlaveProgressRequest,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type UartMessage_OtaSlaveProgressResponse struct {
|
|
||||||
OtaSlaveProgressResponse *OtaSlaveProgressResponse `protobuf:"bytes,16,opt,name=ota_slave_progress_response,json=otaSlaveProgressResponse,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type UartMessage_LedRingProgressRequest struct {
|
|
||||||
LedRingProgressRequest *LedRingProgressRequest `protobuf:"bytes,17,opt,name=led_ring_progress_request,json=ledRingProgressRequest,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type UartMessage_LedRingProgressResponse struct {
|
|
||||||
LedRingProgressResponse *LedRingProgressResponse `protobuf:"bytes,18,opt,name=led_ring_progress_response,json=ledRingProgressResponse,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*UartMessage_AckPayload) isUartMessage_Payload() {}
|
func (*UartMessage_AckPayload) isUartMessage_Payload() {}
|
||||||
|
|
||||||
func (*UartMessage_EchoPayload) isUartMessage_Payload() {}
|
func (*UartMessage_EchoPayload) isUartMessage_Payload() {}
|
||||||
@ -428,14 +366,6 @@ func (*UartMessage_EspnowUnicastTestRequest) isUartMessage_Payload() {}
|
|||||||
|
|
||||||
func (*UartMessage_EspnowUnicastTestResponse) isUartMessage_Payload() {}
|
func (*UartMessage_EspnowUnicastTestResponse) isUartMessage_Payload() {}
|
||||||
|
|
||||||
func (*UartMessage_OtaSlaveProgressRequest) isUartMessage_Payload() {}
|
|
||||||
|
|
||||||
func (*UartMessage_OtaSlaveProgressResponse) isUartMessage_Payload() {}
|
|
||||||
|
|
||||||
func (*UartMessage_LedRingProgressRequest) isUartMessage_Payload() {}
|
|
||||||
|
|
||||||
func (*UartMessage_LedRingProgressResponse) isUartMessage_Payload() {}
|
|
||||||
|
|
||||||
type Ack struct {
|
type Ack struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
@ -1068,189 +998,6 @@ func (x *EspNowUnicastTestResponse) GetSeq() uint32 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Host → device: LED ring display (progress bar, digit, clear, or blink).
|
|
||||||
// mode: 0=clear, 1=progress (0–100 %), 2=digit (0–10), 3=blink full ring.
|
|
||||||
type LedRingProgressRequest struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
Mode uint32 `protobuf:"varint,1,opt,name=mode,proto3" json:"mode,omitempty"`
|
|
||||||
// * 0–100: fraction of ring LEDs to light (mode=progress)
|
|
||||||
Progress uint32 `protobuf:"varint,2,opt,name=progress,proto3" json:"progress,omitempty"`
|
|
||||||
// * 0–10 (mode=digit)
|
|
||||||
Digit uint32 `protobuf:"varint,3,opt,name=digit,proto3" json:"digit,omitempty"`
|
|
||||||
R uint32 `protobuf:"varint,4,opt,name=r,proto3" json:"r,omitempty"`
|
|
||||||
G uint32 `protobuf:"varint,5,opt,name=g,proto3" json:"g,omitempty"`
|
|
||||||
B uint32 `protobuf:"varint,6,opt,name=b,proto3" json:"b,omitempty"`
|
|
||||||
// * 0–255 brightness scale; 0 = firmware default (~5 %)
|
|
||||||
Intensity uint32 `protobuf:"varint,7,opt,name=intensity,proto3" json:"intensity,omitempty"`
|
|
||||||
// * Pulse length in ms (mode=blink, default 350)
|
|
||||||
BlinkMs uint32 `protobuf:"varint,8,opt,name=blink_ms,json=blinkMs,proto3" json:"blink_ms,omitempty"`
|
|
||||||
// * Number of pulses (mode=blink, default 1)
|
|
||||||
BlinkCount uint32 `protobuf:"varint,9,opt,name=blink_count,json=blinkCount,proto3" json:"blink_count,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LedRingProgressRequest) Reset() {
|
|
||||||
*x = LedRingProgressRequest{}
|
|
||||||
mi := &file_uart_messages_proto_msgTypes[12]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LedRingProgressRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*LedRingProgressRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *LedRingProgressRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_uart_messages_proto_msgTypes[12]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use LedRingProgressRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*LedRingProgressRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_uart_messages_proto_rawDescGZIP(), []int{12}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LedRingProgressRequest) GetMode() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Mode
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LedRingProgressRequest) GetProgress() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Progress
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LedRingProgressRequest) GetDigit() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Digit
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LedRingProgressRequest) GetR() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.R
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LedRingProgressRequest) GetG() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.G
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LedRingProgressRequest) GetB() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.B
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LedRingProgressRequest) GetIntensity() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Intensity
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LedRingProgressRequest) GetBlinkMs() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.BlinkMs
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LedRingProgressRequest) GetBlinkCount() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.BlinkCount
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type LedRingProgressResponse struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
|
||||||
Mode uint32 `protobuf:"varint,2,opt,name=mode,proto3" json:"mode,omitempty"`
|
|
||||||
Progress uint32 `protobuf:"varint,3,opt,name=progress,proto3" json:"progress,omitempty"`
|
|
||||||
Digit uint32 `protobuf:"varint,4,opt,name=digit,proto3" json:"digit,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LedRingProgressResponse) Reset() {
|
|
||||||
*x = LedRingProgressResponse{}
|
|
||||||
mi := &file_uart_messages_proto_msgTypes[13]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LedRingProgressResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*LedRingProgressResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *LedRingProgressResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_uart_messages_proto_msgTypes[13]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use LedRingProgressResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*LedRingProgressResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_uart_messages_proto_rawDescGZIP(), []int{13}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LedRingProgressResponse) GetSuccess() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.Success
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LedRingProgressResponse) GetMode() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Mode
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LedRingProgressResponse) GetProgress() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Progress
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LedRingProgressResponse) GetDigit() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Digit
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS).
|
// Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS).
|
||||||
type OtaStartPayload struct {
|
type OtaStartPayload struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
@ -1261,7 +1008,7 @@ type OtaStartPayload struct {
|
|||||||
|
|
||||||
func (x *OtaStartPayload) Reset() {
|
func (x *OtaStartPayload) Reset() {
|
||||||
*x = OtaStartPayload{}
|
*x = OtaStartPayload{}
|
||||||
mi := &file_uart_messages_proto_msgTypes[14]
|
mi := &file_uart_messages_proto_msgTypes[12]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@ -1273,7 +1020,7 @@ func (x *OtaStartPayload) String() string {
|
|||||||
func (*OtaStartPayload) ProtoMessage() {}
|
func (*OtaStartPayload) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *OtaStartPayload) ProtoReflect() protoreflect.Message {
|
func (x *OtaStartPayload) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_uart_messages_proto_msgTypes[14]
|
mi := &file_uart_messages_proto_msgTypes[12]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@ -1286,7 +1033,7 @@ func (x *OtaStartPayload) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use OtaStartPayload.ProtoReflect.Descriptor instead.
|
// Deprecated: Use OtaStartPayload.ProtoReflect.Descriptor instead.
|
||||||
func (*OtaStartPayload) Descriptor() ([]byte, []int) {
|
func (*OtaStartPayload) Descriptor() ([]byte, []int) {
|
||||||
return file_uart_messages_proto_rawDescGZIP(), []int{14}
|
return file_uart_messages_proto_rawDescGZIP(), []int{12}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *OtaStartPayload) GetTotalSize() uint32 {
|
func (x *OtaStartPayload) GetTotalSize() uint32 {
|
||||||
@ -1307,7 +1054,7 @@ type OtaPayload struct {
|
|||||||
|
|
||||||
func (x *OtaPayload) Reset() {
|
func (x *OtaPayload) Reset() {
|
||||||
*x = OtaPayload{}
|
*x = OtaPayload{}
|
||||||
mi := &file_uart_messages_proto_msgTypes[15]
|
mi := &file_uart_messages_proto_msgTypes[13]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@ -1319,7 +1066,7 @@ func (x *OtaPayload) String() string {
|
|||||||
func (*OtaPayload) ProtoMessage() {}
|
func (*OtaPayload) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *OtaPayload) ProtoReflect() protoreflect.Message {
|
func (x *OtaPayload) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_uart_messages_proto_msgTypes[15]
|
mi := &file_uart_messages_proto_msgTypes[13]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@ -1332,7 +1079,7 @@ func (x *OtaPayload) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use OtaPayload.ProtoReflect.Descriptor instead.
|
// Deprecated: Use OtaPayload.ProtoReflect.Descriptor instead.
|
||||||
func (*OtaPayload) Descriptor() ([]byte, []int) {
|
func (*OtaPayload) Descriptor() ([]byte, []int) {
|
||||||
return file_uart_messages_proto_rawDescGZIP(), []int{15}
|
return file_uart_messages_proto_rawDescGZIP(), []int{13}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *OtaPayload) GetSeq() uint32 {
|
func (x *OtaPayload) GetSeq() uint32 {
|
||||||
@ -1358,7 +1105,7 @@ type OtaEndPayload struct {
|
|||||||
|
|
||||||
func (x *OtaEndPayload) Reset() {
|
func (x *OtaEndPayload) Reset() {
|
||||||
*x = OtaEndPayload{}
|
*x = OtaEndPayload{}
|
||||||
mi := &file_uart_messages_proto_msgTypes[16]
|
mi := &file_uart_messages_proto_msgTypes[14]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@ -1370,7 +1117,7 @@ func (x *OtaEndPayload) String() string {
|
|||||||
func (*OtaEndPayload) ProtoMessage() {}
|
func (*OtaEndPayload) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *OtaEndPayload) ProtoReflect() protoreflect.Message {
|
func (x *OtaEndPayload) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_uart_messages_proto_msgTypes[16]
|
mi := &file_uart_messages_proto_msgTypes[14]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@ -1383,11 +1130,11 @@ func (x *OtaEndPayload) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use OtaEndPayload.ProtoReflect.Descriptor instead.
|
// Deprecated: Use OtaEndPayload.ProtoReflect.Descriptor instead.
|
||||||
func (*OtaEndPayload) Descriptor() ([]byte, []int) {
|
func (*OtaEndPayload) Descriptor() ([]byte, []int) {
|
||||||
return file_uart_messages_proto_rawDescGZIP(), []int{16}
|
return file_uart_messages_proto_rawDescGZIP(), []int{14}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Device → host status (also used as ACK after each 4 KiB written).
|
// Device → host status (also used as ACK after each 4 KiB written).
|
||||||
// status: 1=preparing, 2=ready, 3=block_ack, 4=success, 5=failed, 6=distributing
|
// status: 1=preparing, 2=ready, 3=block_ack, 4=success, 5=failed
|
||||||
type OtaStatusPayload struct {
|
type OtaStatusPayload struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
Status uint32 `protobuf:"varint,1,opt,name=status,proto3" json:"status,omitempty"`
|
Status uint32 `protobuf:"varint,1,opt,name=status,proto3" json:"status,omitempty"`
|
||||||
@ -1400,7 +1147,7 @@ type OtaStatusPayload struct {
|
|||||||
|
|
||||||
func (x *OtaStatusPayload) Reset() {
|
func (x *OtaStatusPayload) Reset() {
|
||||||
*x = OtaStatusPayload{}
|
*x = OtaStatusPayload{}
|
||||||
mi := &file_uart_messages_proto_msgTypes[17]
|
mi := &file_uart_messages_proto_msgTypes[15]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@ -1412,7 +1159,7 @@ func (x *OtaStatusPayload) String() string {
|
|||||||
func (*OtaStatusPayload) ProtoMessage() {}
|
func (*OtaStatusPayload) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *OtaStatusPayload) ProtoReflect() protoreflect.Message {
|
func (x *OtaStatusPayload) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_uart_messages_proto_msgTypes[17]
|
mi := &file_uart_messages_proto_msgTypes[15]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@ -1425,7 +1172,7 @@ func (x *OtaStatusPayload) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use OtaStatusPayload.ProtoReflect.Descriptor instead.
|
// Deprecated: Use OtaStatusPayload.ProtoReflect.Descriptor instead.
|
||||||
func (*OtaStatusPayload) Descriptor() ([]byte, []int) {
|
func (*OtaStatusPayload) Descriptor() ([]byte, []int) {
|
||||||
return file_uart_messages_proto_rawDescGZIP(), []int{17}
|
return file_uart_messages_proto_rawDescGZIP(), []int{15}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *OtaStatusPayload) GetStatus() uint32 {
|
func (x *OtaStatusPayload) GetStatus() uint32 {
|
||||||
@ -1456,210 +1203,11 @@ func (x *OtaStatusPayload) GetError() uint32 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Host → master: query ESP-NOW slave OTA progress (client_id 0 = all slaves in session).
|
|
||||||
type OtaSlaveProgressRequest struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
ClientId uint32 `protobuf:"varint,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressRequest) Reset() {
|
|
||||||
*x = OtaSlaveProgressRequest{}
|
|
||||||
mi := &file_uart_messages_proto_msgTypes[18]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*OtaSlaveProgressRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_uart_messages_proto_msgTypes[18]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use OtaSlaveProgressRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*OtaSlaveProgressRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_uart_messages_proto_rawDescGZIP(), []int{18}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressRequest) GetClientId() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.ClientId
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type OtaSlaveProgressEntry struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
ClientId uint32 `protobuf:"varint,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
|
|
||||||
BytesWritten uint32 `protobuf:"varint,2,opt,name=bytes_written,json=bytesWritten,proto3" json:"bytes_written,omitempty"`
|
|
||||||
TotalBytes uint32 `protobuf:"varint,3,opt,name=total_bytes,json=totalBytes,proto3" json:"total_bytes,omitempty"`
|
|
||||||
// * 0=idle, 1=preparing, 2=ready, 3=distributing, 4=success, 5=failed
|
|
||||||
Status uint32 `protobuf:"varint,4,opt,name=status,proto3" json:"status,omitempty"`
|
|
||||||
Error uint32 `protobuf:"varint,5,opt,name=error,proto3" json:"error,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressEntry) Reset() {
|
|
||||||
*x = OtaSlaveProgressEntry{}
|
|
||||||
mi := &file_uart_messages_proto_msgTypes[19]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressEntry) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*OtaSlaveProgressEntry) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressEntry) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_uart_messages_proto_msgTypes[19]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use OtaSlaveProgressEntry.ProtoReflect.Descriptor instead.
|
|
||||||
func (*OtaSlaveProgressEntry) Descriptor() ([]byte, []int) {
|
|
||||||
return file_uart_messages_proto_rawDescGZIP(), []int{19}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressEntry) GetClientId() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.ClientId
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressEntry) GetBytesWritten() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.BytesWritten
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressEntry) GetTotalBytes() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.TotalBytes
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressEntry) GetStatus() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Status
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressEntry) GetError() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Error
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type OtaSlaveProgressResponse struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
Active bool `protobuf:"varint,1,opt,name=active,proto3" json:"active,omitempty"`
|
|
||||||
TotalBytes uint32 `protobuf:"varint,2,opt,name=total_bytes,json=totalBytes,proto3" json:"total_bytes,omitempty"`
|
|
||||||
AggregateBytes uint32 `protobuf:"varint,3,opt,name=aggregate_bytes,json=aggregateBytes,proto3" json:"aggregate_bytes,omitempty"`
|
|
||||||
SlaveCount uint32 `protobuf:"varint,4,opt,name=slave_count,json=slaveCount,proto3" json:"slave_count,omitempty"`
|
|
||||||
Slaves []*OtaSlaveProgressEntry `protobuf:"bytes,5,rep,name=slaves,proto3" json:"slaves,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressResponse) Reset() {
|
|
||||||
*x = OtaSlaveProgressResponse{}
|
|
||||||
mi := &file_uart_messages_proto_msgTypes[20]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*OtaSlaveProgressResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_uart_messages_proto_msgTypes[20]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use OtaSlaveProgressResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*OtaSlaveProgressResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_uart_messages_proto_rawDescGZIP(), []int{20}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressResponse) GetActive() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.Active
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressResponse) GetTotalBytes() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.TotalBytes
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressResponse) GetAggregateBytes() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.AggregateBytes
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressResponse) GetSlaveCount() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.SlaveCount
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *OtaSlaveProgressResponse) GetSlaves() []*OtaSlaveProgressEntry {
|
|
||||||
if x != nil {
|
|
||||||
return x.Slaves
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_uart_messages_proto protoreflect.FileDescriptor
|
var File_uart_messages_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_uart_messages_proto_rawDesc = "" +
|
const file_uart_messages_proto_rawDesc = "" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"\x13uart_messages.proto\x12\x04alox\x1a\fnanopb.proto\"\xc4\n" +
|
"\x13uart_messages.proto\x12\x04alox\"\xcc\a\n" +
|
||||||
"\n" +
|
|
||||||
"\vUartMessage\x12%\n" +
|
"\vUartMessage\x12%\n" +
|
||||||
"\x04type\x18\x01 \x01(\x0e2\x11.alox.MessageTypeR\x04type\x12,\n" +
|
"\x04type\x18\x01 \x01(\x0e2\x11.alox.MessageTypeR\x04type\x12,\n" +
|
||||||
"\vack_payload\x18\x02 \x01(\v2\t.alox.AckH\x00R\n" +
|
"\vack_payload\x18\x02 \x01(\v2\t.alox.AckH\x00R\n" +
|
||||||
@ -1678,11 +1226,7 @@ const file_uart_messages_proto_rawDesc = "" +
|
|||||||
"\x16accel_deadzone_request\x18\v \x01(\v2\x1a.alox.AccelDeadzoneRequestH\x00R\x14accelDeadzoneRequest\x12U\n" +
|
"\x16accel_deadzone_request\x18\v \x01(\v2\x1a.alox.AccelDeadzoneRequestH\x00R\x14accelDeadzoneRequest\x12U\n" +
|
||||||
"\x17accel_deadzone_response\x18\f \x01(\v2\x1b.alox.AccelDeadzoneResponseH\x00R\x15accelDeadzoneResponse\x12_\n" +
|
"\x17accel_deadzone_response\x18\f \x01(\v2\x1b.alox.AccelDeadzoneResponseH\x00R\x15accelDeadzoneResponse\x12_\n" +
|
||||||
"\x1bespnow_unicast_test_request\x18\r \x01(\v2\x1e.alox.EspNowUnicastTestRequestH\x00R\x18espnowUnicastTestRequest\x12b\n" +
|
"\x1bespnow_unicast_test_request\x18\r \x01(\v2\x1e.alox.EspNowUnicastTestRequestH\x00R\x18espnowUnicastTestRequest\x12b\n" +
|
||||||
"\x1cespnow_unicast_test_response\x18\x0e \x01(\v2\x1f.alox.EspNowUnicastTestResponseH\x00R\x19espnowUnicastTestResponse\x12\\\n" +
|
"\x1cespnow_unicast_test_response\x18\x0e \x01(\v2\x1f.alox.EspNowUnicastTestResponseH\x00R\x19espnowUnicastTestResponseB\t\n" +
|
||||||
"\x1aota_slave_progress_request\x18\x0f \x01(\v2\x1d.alox.OtaSlaveProgressRequestH\x00R\x17otaSlaveProgressRequest\x12_\n" +
|
|
||||||
"\x1bota_slave_progress_response\x18\x10 \x01(\v2\x1e.alox.OtaSlaveProgressResponseH\x00R\x18otaSlaveProgressResponse\x12Y\n" +
|
|
||||||
"\x19led_ring_progress_request\x18\x11 \x01(\v2\x1c.alox.LedRingProgressRequestH\x00R\x16ledRingProgressRequest\x12\\\n" +
|
|
||||||
"\x1aled_ring_progress_response\x18\x12 \x01(\v2\x1d.alox.LedRingProgressResponseH\x00R\x17ledRingProgressResponseB\t\n" +
|
|
||||||
"\apayload\"\x05\n" +
|
"\apayload\"\x05\n" +
|
||||||
"\x03Ack\"!\n" +
|
"\x03Ack\"!\n" +
|
||||||
"\vEchoPayload\x12\x12\n" +
|
"\vEchoPayload\x12\x12\n" +
|
||||||
@ -1725,54 +1269,21 @@ const file_uart_messages_proto_rawDesc = "" +
|
|||||||
"\x03seq\x18\x02 \x01(\rR\x03seq\"G\n" +
|
"\x03seq\x18\x02 \x01(\rR\x03seq\"G\n" +
|
||||||
"\x19EspNowUnicastTestResponse\x12\x18\n" +
|
"\x19EspNowUnicastTestResponse\x12\x18\n" +
|
||||||
"\asuccess\x18\x01 \x01(\bR\asuccess\x12\x10\n" +
|
"\asuccess\x18\x01 \x01(\bR\asuccess\x12\x10\n" +
|
||||||
"\x03seq\x18\x02 \x01(\rR\x03seq\"\xe2\x01\n" +
|
"\x03seq\x18\x02 \x01(\rR\x03seq\"0\n" +
|
||||||
"\x16LedRingProgressRequest\x12\x12\n" +
|
|
||||||
"\x04mode\x18\x01 \x01(\rR\x04mode\x12\x1a\n" +
|
|
||||||
"\bprogress\x18\x02 \x01(\rR\bprogress\x12\x14\n" +
|
|
||||||
"\x05digit\x18\x03 \x01(\rR\x05digit\x12\f\n" +
|
|
||||||
"\x01r\x18\x04 \x01(\rR\x01r\x12\f\n" +
|
|
||||||
"\x01g\x18\x05 \x01(\rR\x01g\x12\f\n" +
|
|
||||||
"\x01b\x18\x06 \x01(\rR\x01b\x12\x1c\n" +
|
|
||||||
"\tintensity\x18\a \x01(\rR\tintensity\x12\x19\n" +
|
|
||||||
"\bblink_ms\x18\b \x01(\rR\ablinkMs\x12\x1f\n" +
|
|
||||||
"\vblink_count\x18\t \x01(\rR\n" +
|
|
||||||
"blinkCount\"y\n" +
|
|
||||||
"\x17LedRingProgressResponse\x12\x18\n" +
|
|
||||||
"\asuccess\x18\x01 \x01(\bR\asuccess\x12\x12\n" +
|
|
||||||
"\x04mode\x18\x02 \x01(\rR\x04mode\x12\x1a\n" +
|
|
||||||
"\bprogress\x18\x03 \x01(\rR\bprogress\x12\x14\n" +
|
|
||||||
"\x05digit\x18\x04 \x01(\rR\x05digit\"0\n" +
|
|
||||||
"\x0fOtaStartPayload\x12\x1d\n" +
|
"\x0fOtaStartPayload\x12\x1d\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"total_size\x18\x01 \x01(\rR\ttotalSize\":\n" +
|
"total_size\x18\x01 \x01(\rR\ttotalSize\"2\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"OtaPayload\x12\x10\n" +
|
"OtaPayload\x12\x10\n" +
|
||||||
"\x03seq\x18\x01 \x01(\rR\x03seq\x12\x1a\n" +
|
"\x03seq\x18\x01 \x01(\rR\x03seq\x12\x12\n" +
|
||||||
"\x04data\x18\x02 \x01(\fB\x06\x92?\x03\b\xc8\x01R\x04data\"\x0f\n" +
|
"\x04data\x18\x02 \x01(\fR\x04data\"\x0f\n" +
|
||||||
"\rOtaEndPayload\"\x86\x01\n" +
|
"\rOtaEndPayload\"\x86\x01\n" +
|
||||||
"\x10OtaStatusPayload\x12\x16\n" +
|
"\x10OtaStatusPayload\x12\x16\n" +
|
||||||
"\x06status\x18\x01 \x01(\rR\x06status\x12#\n" +
|
"\x06status\x18\x01 \x01(\rR\x06status\x12#\n" +
|
||||||
"\rbytes_written\x18\x02 \x01(\rR\fbytesWritten\x12\x1f\n" +
|
"\rbytes_written\x18\x02 \x01(\rR\fbytesWritten\x12\x1f\n" +
|
||||||
"\vtarget_slot\x18\x03 \x01(\rR\n" +
|
"\vtarget_slot\x18\x03 \x01(\rR\n" +
|
||||||
"targetSlot\x12\x14\n" +
|
"targetSlot\x12\x14\n" +
|
||||||
"\x05error\x18\x04 \x01(\rR\x05error\"6\n" +
|
"\x05error\x18\x04 \x01(\rR\x05error*\xdd\x01\n" +
|
||||||
"\x17OtaSlaveProgressRequest\x12\x1b\n" +
|
|
||||||
"\tclient_id\x18\x01 \x01(\rR\bclientId\"\xa8\x01\n" +
|
|
||||||
"\x15OtaSlaveProgressEntry\x12\x1b\n" +
|
|
||||||
"\tclient_id\x18\x01 \x01(\rR\bclientId\x12#\n" +
|
|
||||||
"\rbytes_written\x18\x02 \x01(\rR\fbytesWritten\x12\x1f\n" +
|
|
||||||
"\vtotal_bytes\x18\x03 \x01(\rR\n" +
|
|
||||||
"totalBytes\x12\x16\n" +
|
|
||||||
"\x06status\x18\x04 \x01(\rR\x06status\x12\x14\n" +
|
|
||||||
"\x05error\x18\x05 \x01(\rR\x05error\"\xd9\x01\n" +
|
|
||||||
"\x18OtaSlaveProgressResponse\x12\x16\n" +
|
|
||||||
"\x06active\x18\x01 \x01(\bR\x06active\x12\x1f\n" +
|
|
||||||
"\vtotal_bytes\x18\x02 \x01(\rR\n" +
|
|
||||||
"totalBytes\x12'\n" +
|
|
||||||
"\x0faggregate_bytes\x18\x03 \x01(\rR\x0eaggregateBytes\x12\x1f\n" +
|
|
||||||
"\vslave_count\x18\x04 \x01(\rR\n" +
|
|
||||||
"slaveCount\x12:\n" +
|
|
||||||
"\x06slaves\x18\x05 \x03(\v2\x1b.alox.OtaSlaveProgressEntryB\x05\x92?\x02\x10\x10R\x06slaves*\x83\x02\n" +
|
|
||||||
"\vMessageType\x12\v\n" +
|
"\vMessageType\x12\v\n" +
|
||||||
"\aUNKNOWN\x10\x00\x12\a\n" +
|
"\aUNKNOWN\x10\x00\x12\a\n" +
|
||||||
"\x03ACK\x10\x01\x12\b\n" +
|
"\x03ACK\x10\x01\x12\b\n" +
|
||||||
@ -1781,15 +1292,13 @@ const file_uart_messages_proto_rawDesc = "" +
|
|||||||
"\vCLIENT_INFO\x10\x04\x12\x10\n" +
|
"\vCLIENT_INFO\x10\x04\x12\x10\n" +
|
||||||
"\fCLIENT_INPUT\x10\x05\x12\x12\n" +
|
"\fCLIENT_INPUT\x10\x05\x12\x12\n" +
|
||||||
"\x0eACCEL_DEADZONE\x10\x06\x12\x17\n" +
|
"\x0eACCEL_DEADZONE\x10\x06\x12\x17\n" +
|
||||||
"\x13ESPNOW_UNICAST_TEST\x10\a\x12\f\n" +
|
"\x13ESPNOW_UNICAST_TEST\x10\a\x12\r\n" +
|
||||||
"\bLED_RING\x10\b\x12\r\n" +
|
|
||||||
"\tOTA_START\x10\x10\x12\x0f\n" +
|
"\tOTA_START\x10\x10\x12\x0f\n" +
|
||||||
"\vOTA_PAYLOAD\x10\x11\x12\v\n" +
|
"\vOTA_PAYLOAD\x10\x11\x12\v\n" +
|
||||||
"\aOTA_END\x10\x12\x12\x0e\n" +
|
"\aOTA_END\x10\x12\x12\x0e\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"OTA_STATUS\x10\x13\x12\x14\n" +
|
"OTA_STATUS\x10\x13\x12\x14\n" +
|
||||||
"\x10OTA_START_ESPNOW\x10\x14\x12\x16\n" +
|
"\x10OTA_START_ESPNOW\x10\x14b\x06proto3"
|
||||||
"\x12OTA_SLAVE_PROGRESS\x10\x15b\x06proto3"
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_uart_messages_proto_rawDescOnce sync.Once
|
file_uart_messages_proto_rawDescOnce sync.Once
|
||||||
@ -1804,7 +1313,7 @@ func file_uart_messages_proto_rawDescGZIP() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var file_uart_messages_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
var file_uart_messages_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||||
var file_uart_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 21)
|
var file_uart_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 16)
|
||||||
var file_uart_messages_proto_goTypes = []any{
|
var file_uart_messages_proto_goTypes = []any{
|
||||||
(MessageType)(0), // 0: alox.MessageType
|
(MessageType)(0), // 0: alox.MessageType
|
||||||
(*UartMessage)(nil), // 1: alox.UartMessage
|
(*UartMessage)(nil), // 1: alox.UartMessage
|
||||||
@ -1819,15 +1328,10 @@ var file_uart_messages_proto_goTypes = []any{
|
|||||||
(*AccelDeadzoneResponse)(nil), // 10: alox.AccelDeadzoneResponse
|
(*AccelDeadzoneResponse)(nil), // 10: alox.AccelDeadzoneResponse
|
||||||
(*EspNowUnicastTestRequest)(nil), // 11: alox.EspNowUnicastTestRequest
|
(*EspNowUnicastTestRequest)(nil), // 11: alox.EspNowUnicastTestRequest
|
||||||
(*EspNowUnicastTestResponse)(nil), // 12: alox.EspNowUnicastTestResponse
|
(*EspNowUnicastTestResponse)(nil), // 12: alox.EspNowUnicastTestResponse
|
||||||
(*LedRingProgressRequest)(nil), // 13: alox.LedRingProgressRequest
|
(*OtaStartPayload)(nil), // 13: alox.OtaStartPayload
|
||||||
(*LedRingProgressResponse)(nil), // 14: alox.LedRingProgressResponse
|
(*OtaPayload)(nil), // 14: alox.OtaPayload
|
||||||
(*OtaStartPayload)(nil), // 15: alox.OtaStartPayload
|
(*OtaEndPayload)(nil), // 15: alox.OtaEndPayload
|
||||||
(*OtaPayload)(nil), // 16: alox.OtaPayload
|
(*OtaStatusPayload)(nil), // 16: alox.OtaStatusPayload
|
||||||
(*OtaEndPayload)(nil), // 17: alox.OtaEndPayload
|
|
||||||
(*OtaStatusPayload)(nil), // 18: alox.OtaStatusPayload
|
|
||||||
(*OtaSlaveProgressRequest)(nil), // 19: alox.OtaSlaveProgressRequest
|
|
||||||
(*OtaSlaveProgressEntry)(nil), // 20: alox.OtaSlaveProgressEntry
|
|
||||||
(*OtaSlaveProgressResponse)(nil), // 21: alox.OtaSlaveProgressResponse
|
|
||||||
}
|
}
|
||||||
var file_uart_messages_proto_depIdxs = []int32{
|
var file_uart_messages_proto_depIdxs = []int32{
|
||||||
0, // 0: alox.UartMessage.type:type_name -> alox.MessageType
|
0, // 0: alox.UartMessage.type:type_name -> alox.MessageType
|
||||||
@ -1836,26 +1340,21 @@ var file_uart_messages_proto_depIdxs = []int32{
|
|||||||
4, // 3: alox.UartMessage.version_response:type_name -> alox.VersionResponse
|
4, // 3: alox.UartMessage.version_response:type_name -> alox.VersionResponse
|
||||||
6, // 4: alox.UartMessage.client_info_response:type_name -> alox.ClientInfoResponse
|
6, // 4: alox.UartMessage.client_info_response:type_name -> alox.ClientInfoResponse
|
||||||
8, // 5: alox.UartMessage.client_input_response:type_name -> alox.ClientInputResponse
|
8, // 5: alox.UartMessage.client_input_response:type_name -> alox.ClientInputResponse
|
||||||
15, // 6: alox.UartMessage.ota_start:type_name -> alox.OtaStartPayload
|
13, // 6: alox.UartMessage.ota_start:type_name -> alox.OtaStartPayload
|
||||||
16, // 7: alox.UartMessage.ota_payload:type_name -> alox.OtaPayload
|
14, // 7: alox.UartMessage.ota_payload:type_name -> alox.OtaPayload
|
||||||
17, // 8: alox.UartMessage.ota_end:type_name -> alox.OtaEndPayload
|
15, // 8: alox.UartMessage.ota_end:type_name -> alox.OtaEndPayload
|
||||||
18, // 9: alox.UartMessage.ota_status:type_name -> alox.OtaStatusPayload
|
16, // 9: alox.UartMessage.ota_status:type_name -> alox.OtaStatusPayload
|
||||||
9, // 10: alox.UartMessage.accel_deadzone_request:type_name -> alox.AccelDeadzoneRequest
|
9, // 10: alox.UartMessage.accel_deadzone_request:type_name -> alox.AccelDeadzoneRequest
|
||||||
10, // 11: alox.UartMessage.accel_deadzone_response:type_name -> alox.AccelDeadzoneResponse
|
10, // 11: alox.UartMessage.accel_deadzone_response:type_name -> alox.AccelDeadzoneResponse
|
||||||
11, // 12: alox.UartMessage.espnow_unicast_test_request:type_name -> alox.EspNowUnicastTestRequest
|
11, // 12: alox.UartMessage.espnow_unicast_test_request:type_name -> alox.EspNowUnicastTestRequest
|
||||||
12, // 13: alox.UartMessage.espnow_unicast_test_response:type_name -> alox.EspNowUnicastTestResponse
|
12, // 13: alox.UartMessage.espnow_unicast_test_response:type_name -> alox.EspNowUnicastTestResponse
|
||||||
19, // 14: alox.UartMessage.ota_slave_progress_request:type_name -> alox.OtaSlaveProgressRequest
|
5, // 14: alox.ClientInfoResponse.clients:type_name -> alox.ClientInfo
|
||||||
21, // 15: alox.UartMessage.ota_slave_progress_response:type_name -> alox.OtaSlaveProgressResponse
|
7, // 15: alox.ClientInputResponse.clients:type_name -> alox.ClientInput
|
||||||
13, // 16: alox.UartMessage.led_ring_progress_request:type_name -> alox.LedRingProgressRequest
|
16, // [16:16] is the sub-list for method output_type
|
||||||
14, // 17: alox.UartMessage.led_ring_progress_response:type_name -> alox.LedRingProgressResponse
|
16, // [16:16] is the sub-list for method input_type
|
||||||
5, // 18: alox.ClientInfoResponse.clients:type_name -> alox.ClientInfo
|
16, // [16:16] is the sub-list for extension type_name
|
||||||
7, // 19: alox.ClientInputResponse.clients:type_name -> alox.ClientInput
|
16, // [16:16] is the sub-list for extension extendee
|
||||||
20, // 20: alox.OtaSlaveProgressResponse.slaves:type_name -> alox.OtaSlaveProgressEntry
|
0, // [0:16] is the sub-list for field type_name
|
||||||
21, // [21:21] is the sub-list for method output_type
|
|
||||||
21, // [21:21] is the sub-list for method input_type
|
|
||||||
21, // [21:21] is the sub-list for extension type_name
|
|
||||||
21, // [21:21] is the sub-list for extension extendee
|
|
||||||
0, // [0:21] is the sub-list for field type_name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_uart_messages_proto_init() }
|
func init() { file_uart_messages_proto_init() }
|
||||||
@ -1877,10 +1376,6 @@ func file_uart_messages_proto_init() {
|
|||||||
(*UartMessage_AccelDeadzoneResponse)(nil),
|
(*UartMessage_AccelDeadzoneResponse)(nil),
|
||||||
(*UartMessage_EspnowUnicastTestRequest)(nil),
|
(*UartMessage_EspnowUnicastTestRequest)(nil),
|
||||||
(*UartMessage_EspnowUnicastTestResponse)(nil),
|
(*UartMessage_EspnowUnicastTestResponse)(nil),
|
||||||
(*UartMessage_OtaSlaveProgressRequest)(nil),
|
|
||||||
(*UartMessage_OtaSlaveProgressResponse)(nil),
|
|
||||||
(*UartMessage_LedRingProgressRequest)(nil),
|
|
||||||
(*UartMessage_LedRingProgressResponse)(nil),
|
|
||||||
}
|
}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
@ -1888,7 +1383,7 @@ func file_uart_messages_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_uart_messages_proto_rawDesc), len(file_uart_messages_proto_rawDesc)),
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_uart_messages_proto_rawDesc), len(file_uart_messages_proto_rawDesc)),
|
||||||
NumEnums: 1,
|
NumEnums: 1,
|
||||||
NumMessages: 21,
|
NumMessages: 16,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,16 +1,12 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// errUARTBusy is returned when the port is held for OTA (poller should not treat as unplug).
|
|
||||||
var errUARTBusy = errors.New("uart busy (OTA in progress)")
|
|
||||||
|
|
||||||
// managedSerial keeps the UART open and reconnects after I/O failures or unplug.
|
// managedSerial keeps the UART open and reconnects after I/O failures or unplug.
|
||||||
type managedSerial struct {
|
type managedSerial struct {
|
||||||
portName string
|
portName string
|
||||||
@ -73,22 +69,7 @@ func (m *managedSerial) invalidateLocked(reason error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managedSerial) withPort(fn func(*serialPort) error) error {
|
func (m *managedSerial) withPort(fn func(*serialPort) error) error {
|
||||||
return m.withPortLocked(false, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// withPortPoll is like withPort but returns errUARTBusy instead of blocking during OTA.
|
|
||||||
func (m *managedSerial) withPortPoll(fn func(*serialPort) error) error {
|
|
||||||
return m.withPortLocked(true, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *managedSerial) withPortLocked(try bool, fn func(*serialPort) error) error {
|
|
||||||
if try {
|
|
||||||
if !m.mu.TryLock() {
|
|
||||||
return errUARTBusy
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
}
|
|
||||||
defer m.mu.Unlock()
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
if m.sp == nil {
|
if m.sp == nil {
|
||||||
@ -105,19 +86,8 @@ func (m *managedSerial) withPortLocked(try bool, fn func(*serialPort) error) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managedSerial) exchangePayload(payload []byte, cmdName string) ([]byte, error) {
|
func (m *managedSerial) exchangePayload(payload []byte, cmdName string) ([]byte, error) {
|
||||||
return m.exchangePayloadVia(m.withPort, payload, cmdName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *managedSerial) exchangePayloadPoll(payload []byte, cmdName string) ([]byte, error) {
|
|
||||||
return m.exchangePayloadVia(m.withPortPoll, payload, cmdName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *managedSerial) exchangePayloadVia(
|
|
||||||
portFn func(func(*serialPort) error) error,
|
|
||||||
payload []byte, cmdName string,
|
|
||||||
) ([]byte, error) {
|
|
||||||
var resp []byte
|
var resp []byte
|
||||||
err := portFn(func(sp *serialPort) error {
|
err := m.withPort(func(sp *serialPort) error {
|
||||||
var e error
|
var e error
|
||||||
resp, e = sp.exchangePayloadLocked(payload, cmdName)
|
resp, e = sp.exchangePayloadLocked(payload, cmdName)
|
||||||
return e
|
return e
|
||||||
@ -126,19 +96,8 @@ func (m *managedSerial) exchangePayloadVia(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managedSerial) exchange(cmdID byte, cmdName string) ([]byte, error) {
|
func (m *managedSerial) exchange(cmdID byte, cmdName string) ([]byte, error) {
|
||||||
return m.exchangeVia(m.withPort, cmdID, cmdName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *managedSerial) exchangePoll(cmdID byte, cmdName string) ([]byte, error) {
|
|
||||||
return m.exchangeVia(m.withPortPoll, cmdID, cmdName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *managedSerial) exchangeVia(
|
|
||||||
portFn func(func(*serialPort) error) error,
|
|
||||||
cmdID byte, cmdName string,
|
|
||||||
) ([]byte, error) {
|
|
||||||
var resp []byte
|
var resp []byte
|
||||||
err := portFn(func(sp *serialPort) error {
|
err := m.withPort(func(sp *serialPort) error {
|
||||||
var e error
|
var e error
|
||||||
resp, e = sp.exchangeLocked(cmdID, cmdName)
|
resp, e = sp.exchangeLocked(cmdID, cmdName)
|
||||||
return e
|
return e
|
||||||
|
|||||||
@ -131,19 +131,6 @@
|
|||||||
.progress-bar {
|
.progress-bar {
|
||||||
background: #2d6cdf;
|
background: #2d6cdf;
|
||||||
}
|
}
|
||||||
.progress-bar.bg-success { background: #00a86b !important; }
|
|
||||||
.progress-bar.bg-danger { background: #e35d6a !important; }
|
|
||||||
.progress-bar.bg-info { background: #2d6cdf !important; }
|
|
||||||
.progress-bar.bg-secondary { background: #5c6570 !important; }
|
|
||||||
|
|
||||||
.ota-progress-table .ota-progress-col {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.ota-progress-table .ota-restart-col {
|
|
||||||
width: 6.5rem;
|
|
||||||
white-space: nowrap;
|
|
||||||
vertical-align: middle !important;
|
|
||||||
}
|
|
||||||
.form-control[type="file"]::file-selector-button {
|
.form-control[type="file"]::file-selector-button {
|
||||||
background: var(--pp-border);
|
background: var(--pp-border);
|
||||||
border: none;
|
border: none;
|
||||||
@ -193,7 +180,7 @@
|
|||||||
<dl class="row mb-0">
|
<dl class="row mb-0">
|
||||||
<dt class="col-5 text-muted">Version</dt>
|
<dt class="col-5 text-muted">Version</dt>
|
||||||
<dd class="col-7" x-text="state.master.version"></dd>
|
<dd class="col-7" x-text="state.master.version"></dd>
|
||||||
<dt class="col-5 text-muted">Hash</dt>
|
<dt class="col-5 text-muted">Git</dt>
|
||||||
<dd class="col-7 text-break" x-text="state.master.git_hash"></dd>
|
<dd class="col-7 text-break" x-text="state.master.git_hash"></dd>
|
||||||
<dt class="col-5 text-muted">Partition</dt>
|
<dt class="col-5 text-muted">Partition</dt>
|
||||||
<dd class="col-7" x-text="state.master.running_partition || '—'"></dd>
|
<dd class="col-7" x-text="state.master.running_partition || '—'"></dd>
|
||||||
@ -316,7 +303,7 @@
|
|||||||
<div class="card-header">Firmware OTA (A/B)</div>
|
<div class="card-header">Firmware OTA (A/B)</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p class="text-muted small mb-3">
|
<p class="text-muted small mb-3">
|
||||||
Lädt eine <code>.bin</code> auf den Master (UART), danach verteilt die Firmware automatisch per ESP-NOW an alle verfügbaren Slaves.
|
Lädt eine <code>.bin</code> auf die inaktive OTA-Partition (wie <code>gotool ota</code>).
|
||||||
Während des Uploads pausiert das Live-Polling.
|
Während des Uploads pausiert das Live-Polling.
|
||||||
</p>
|
</p>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@ -333,76 +320,17 @@
|
|||||||
<span class="text-muted small" x-show="otaFile"
|
<span class="text-muted small" x-show="otaFile"
|
||||||
x-text="otaFile ? otaFile.name + ' (' + formatSize(otaFile.size) + ')' : ''"></span>
|
x-text="otaFile ? otaFile.name + ' (' + formatSize(otaFile.size) + ')' : ''"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="ota-progress-panel mt-3"
|
<template x-if="ota.active || ota.phase === 'done' || ota.phase === 'error'">
|
||||||
x-show="ota.active || ota.phase === 'distributing' || ota.phase === 'done' || ota.phase === 'error'">
|
<div class="progress mb-2" style="height: 1.25rem;">
|
||||||
<p class="small text-muted mb-2">Master (UART)</p>
|
|
||||||
<table class="table table-sm pp-table ota-progress-table mb-3">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td class="ota-progress-col">
|
|
||||||
<div class="d-flex justify-content-between small text-muted mb-1">
|
|
||||||
<span>Master</span>
|
|
||||||
<span x-text="otaMasterPct() + '%'"></span>
|
|
||||||
</div>
|
|
||||||
<div class="progress mb-1" style="height: 1.1rem;">
|
|
||||||
<div class="progress-bar" role="progressbar"
|
<div class="progress-bar" role="progressbar"
|
||||||
:style="'width: ' + otaMasterPct() + '%'"
|
:style="'width: ' + ota.percent + '%'"
|
||||||
:class="otaMasterBarClass()"
|
:class="ota.phase === 'error' ? 'bg-danger' : (ota.phase === 'done' ? 'bg-success' : '')"
|
||||||
x-text="otaMasterPct() + '%'"></div>
|
x-text="ota.percent + '%'"></div>
|
||||||
</div>
|
</div>
|
||||||
<p class="small text-muted mb-0"
|
<p class="small mb-0"
|
||||||
x-text="ota.masterMessage || (ota.step === 'master' ? ota.message : '')"></p>
|
:class="ota.phase === 'error' ? 'text-danger' : (ota.phase === 'done' ? 'text-success' : 'text-muted')"
|
||||||
</td>
|
|
||||||
<td class="ota-restart-col text-end">
|
|
||||||
<button type="button" class="btn btn-outline-secondary btn-sm">Restart</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p class="small text-muted mb-2">
|
|
||||||
Slaves (ESP-NOW)
|
|
||||||
<span x-text="'(' + otaSlaveRows().length + ')'"></span>
|
|
||||||
</p>
|
|
||||||
<p class="small text-muted mb-2" x-show="ota.message && ota.step === 'slaves'"
|
|
||||||
x-text="ota.message"></p>
|
x-text="ota.message"></p>
|
||||||
<table class="table table-sm pp-table ota-progress-table mb-2">
|
|
||||||
<tbody>
|
|
||||||
<template x-for="row in otaSlaveRows()" :key="'ota-slave-' + row.id">
|
|
||||||
<tr>
|
|
||||||
<td class="ota-progress-col">
|
|
||||||
<div class="d-flex justify-content-between small mb-1">
|
|
||||||
<span>
|
|
||||||
Slave <span x-text="row.id"></span>
|
|
||||||
<span class="text-muted mac ms-1" x-text="row.mac"></span>
|
|
||||||
<span class="badge bg-secondary ms-1" x-text="row.statusLabel"></span>
|
|
||||||
</span>
|
|
||||||
<span x-text="row.percent + '%'"></span>
|
|
||||||
</div>
|
|
||||||
<div class="progress mb-1" style="height: 0.85rem;">
|
|
||||||
<div class="progress-bar" role="progressbar"
|
|
||||||
:class="row.barClass"
|
|
||||||
:style="'width: ' + row.percent + '%'"></div>
|
|
||||||
</div>
|
|
||||||
<p class="small text-muted mb-0" x-text="row.bytesLabel"></p>
|
|
||||||
</td>
|
|
||||||
<td class="ota-restart-col text-end">
|
|
||||||
<button type="button" class="btn btn-outline-secondary btn-sm">Restart</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</template>
|
</template>
|
||||||
<tr x-show="otaSlaveRows().length === 0">
|
|
||||||
<td colspan="2" class="text-muted small py-3">
|
|
||||||
Warte auf Slave-Fortschritt…
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p class="small mb-0" x-show="ota.phase === 'done' || ota.phase === 'error'"
|
|
||||||
:class="ota.phase === 'error' ? 'text-danger' : 'text-success'"
|
|
||||||
x-text="ota.message"></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -419,13 +347,7 @@
|
|||||||
allDz: 100,
|
allDz: 100,
|
||||||
slaveDz: {},
|
slaveDz: {},
|
||||||
otaFile: null,
|
otaFile: null,
|
||||||
ota: {
|
ota: { active: false, phase: '', percent: 0, message: '' },
|
||||||
active: false, phase: '', step: '', percent: 0,
|
|
||||||
masterPercent: 0, masterDone: false, masterMessage: '',
|
|
||||||
message: '', slaves: 0, imageSize: 0,
|
|
||||||
slaveProgress: {},
|
|
||||||
slaveDetails: {}
|
|
||||||
},
|
|
||||||
busy: false,
|
busy: false,
|
||||||
configMsg: '',
|
configMsg: '',
|
||||||
configMsgOk: false,
|
configMsgOk: false,
|
||||||
@ -470,148 +392,20 @@
|
|||||||
if (n < 1024 * 1024) return (n / 1024).toFixed(1) + ' KiB';
|
if (n < 1024 * 1024) return (n / 1024).toFixed(1) + ' KiB';
|
||||||
return (n / (1024 * 1024)).toFixed(2) + ' MiB';
|
return (n / (1024 * 1024)).toFixed(2) + ' MiB';
|
||||||
},
|
},
|
||||||
otaMasterPct() {
|
|
||||||
if (this.ota.masterDone || this.ota.step === 'slaves' ||
|
|
||||||
this.ota.phase === 'distributing' || this.ota.phase === 'done') {
|
|
||||||
return this.ota.masterPercent >= 100 ? 100 : (this.ota.masterPercent || 100);
|
|
||||||
}
|
|
||||||
if (this.ota.step === 'master' || this.ota.phase === 'preparing' ||
|
|
||||||
this.ota.phase === 'ready' || this.ota.phase === 'uploading') {
|
|
||||||
return this.ota.masterPercent ?? this.ota.percent ?? 0;
|
|
||||||
}
|
|
||||||
return this.ota.masterPercent || 0;
|
|
||||||
},
|
|
||||||
otaMasterBarClass() {
|
|
||||||
if (this.ota.phase === 'error' && this.ota.step === 'master') return 'bg-danger';
|
|
||||||
if (this.otaMasterPct() >= 100) return 'bg-success';
|
|
||||||
return '';
|
|
||||||
},
|
|
||||||
mergeSlaveDetails(incoming) {
|
|
||||||
const out = { ...(this.ota.slaveDetails || {}) };
|
|
||||||
if (!incoming) return out;
|
|
||||||
for (const [k, v] of Object.entries(incoming)) {
|
|
||||||
const id = Number(k);
|
|
||||||
out[id] = { ...(out[id] || {}), ...v };
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
},
|
|
||||||
otaSlaveStatusLabel(status) {
|
|
||||||
const labels = {
|
|
||||||
0: 'idle', 1: 'vorbereiten', 2: 'bereit', 3: 'lädt',
|
|
||||||
4: 'fertig', 5: 'fehler'
|
|
||||||
};
|
|
||||||
return labels[status] || 'status ' + status;
|
|
||||||
},
|
|
||||||
otaSlaveBarClass(status) {
|
|
||||||
if (status === 4) return 'bg-success';
|
|
||||||
if (status === 5) return 'bg-danger';
|
|
||||||
if (status === 1 || status === 2) return 'bg-secondary';
|
|
||||||
return 'bg-info';
|
|
||||||
},
|
|
||||||
otaSlaveRows() {
|
|
||||||
const details = this.mergeSlaveDetails(this.ota.slaveDetails);
|
|
||||||
const ids = new Set(Object.keys(details).map(Number).filter(id => !Number.isNaN(id)));
|
|
||||||
for (const [k, v] of Object.entries(this.ota.slaveProgress || {})) {
|
|
||||||
const id = Number(k);
|
|
||||||
if (!Number.isNaN(id)) {
|
|
||||||
ids.add(id);
|
|
||||||
if (!details[id]) {
|
|
||||||
details[id] = { bytes_written: v, status: 3 };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const rows = [];
|
|
||||||
for (const id of [...ids].sort((a, b) => a - b)) {
|
|
||||||
const c = (this.state.clients || []).find(x => x.id === id);
|
|
||||||
const d = details[id] || {};
|
|
||||||
const total = d.total_bytes || this.ota.imageSize || this.otaFile?.size || 0;
|
|
||||||
const bytes = d.bytes_written ?? 0;
|
|
||||||
const status = d.status ?? 0;
|
|
||||||
let percent = 0;
|
|
||||||
if (total > 0) percent = Math.min(100, Math.round(bytes * 100 / total));
|
|
||||||
if (status === 4) percent = 100;
|
|
||||||
rows.push({
|
|
||||||
id,
|
|
||||||
mac: c?.mac ? this.formatMac(c.mac) : '—',
|
|
||||||
percent,
|
|
||||||
status,
|
|
||||||
statusLabel: this.otaSlaveStatusLabel(status),
|
|
||||||
barClass: this.otaSlaveBarClass(status),
|
|
||||||
bytesLabel: total ? `${bytes} / ${total} bytes` : `${bytes} bytes`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (rows.length === 0 && (this.ota.phase === 'distributing' || this.ota.step === 'slaves')) {
|
|
||||||
const targets = (this.state.clients || []).filter(c => c.available);
|
|
||||||
const limit = this.ota.slaves > 0 ? this.ota.slaves : targets.length;
|
|
||||||
for (const c of targets.slice(0, limit)) {
|
|
||||||
rows.push({
|
|
||||||
id: c.id,
|
|
||||||
mac: c.mac ? this.formatMac(c.mac) : '—',
|
|
||||||
percent: 0,
|
|
||||||
status: 1,
|
|
||||||
statusLabel: this.otaSlaveStatusLabel(1),
|
|
||||||
barClass: this.otaSlaveBarClass(1),
|
|
||||||
bytesLabel: '—'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rows;
|
|
||||||
},
|
|
||||||
applyOTAProgress(p) {
|
applyOTAProgress(p) {
|
||||||
this.ota.phase = p.phase || '';
|
this.ota.phase = p.phase || '';
|
||||||
this.ota.step = p.step || this.ota.step || '';
|
this.ota.percent = p.percent ?? 0;
|
||||||
this.ota.percent = p.percent ?? this.ota.percent;
|
|
||||||
this.ota.message = p.message || '';
|
this.ota.message = p.message || '';
|
||||||
if (p.image_size) this.ota.imageSize = p.image_size;
|
if (p.phase === 'preparing' || p.phase === 'ready' || p.phase === 'uploading') {
|
||||||
if (p.master_done) this.ota.masterDone = true;
|
|
||||||
if (p.step === 'master' || p.phase === 'preparing' || p.phase === 'ready' || p.phase === 'uploading') {
|
|
||||||
if (p.master_percent != null) this.ota.masterPercent = p.master_percent;
|
|
||||||
else if (p.percent != null) this.ota.masterPercent = p.percent;
|
|
||||||
if (p.master_message) this.ota.masterMessage = p.master_message;
|
|
||||||
else if (p.message) this.ota.masterMessage = p.message;
|
|
||||||
} else if (p.step === 'slaves' || p.phase === 'distributing' || p.phase === 'done') {
|
|
||||||
this.ota.masterDone = true;
|
|
||||||
if (p.master_percent != null) this.ota.masterPercent = p.master_percent;
|
|
||||||
else if (this.ota.masterPercent < 100) this.ota.masterPercent = 100;
|
|
||||||
if (p.master_message) this.ota.masterMessage = p.master_message;
|
|
||||||
}
|
|
||||||
if (p.slaves != null) this.ota.slaves = p.slaves;
|
|
||||||
if (p.phase === 'distributing') {
|
|
||||||
this.ota.step = 'slaves';
|
|
||||||
}
|
|
||||||
if (p.slave_details) {
|
|
||||||
const merged = this.mergeSlaveDetails(p.slave_details);
|
|
||||||
this.ota.slaveDetails = { ...merged };
|
|
||||||
if (Object.keys(this.ota.slaveDetails).length > 0) {
|
|
||||||
this.ota.step = 'slaves';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (p.slave_progress) {
|
|
||||||
if (!this.ota.slaveProgress) this.ota.slaveProgress = {};
|
|
||||||
for (const [k, v] of Object.entries(p.slave_progress)) {
|
|
||||||
this.ota.slaveProgress[Number(k)] = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (p.phase === 'preparing' || p.phase === 'ready' || p.phase === 'uploading' ||
|
|
||||||
p.phase === 'distributing') {
|
|
||||||
this.ota.active = true;
|
this.ota.active = true;
|
||||||
}
|
}
|
||||||
if (p.phase === 'done' || p.phase === 'error') {
|
if (p.phase === 'done' || p.phase === 'error') {
|
||||||
this.ota.active = false;
|
this.ota.active = false;
|
||||||
if (p.phase === 'done') {
|
|
||||||
this.ota.masterPercent = 100;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async uploadOTA() {
|
async uploadOTA() {
|
||||||
if (!this.otaFile) return;
|
if (!this.otaFile) return;
|
||||||
this.ota = {
|
this.ota = { active: true, phase: 'preparing', percent: 0, message: 'Upload startet…' };
|
||||||
active: true, phase: 'preparing', step: 'master', percent: 0,
|
|
||||||
masterPercent: 0, masterDone: false, masterMessage: 'Upload startet…',
|
|
||||||
message: 'Upload startet…', slaves: 0,
|
|
||||||
imageSize: this.otaFile?.size || 0,
|
|
||||||
slaveProgress: {}, slaveDetails: {}
|
|
||||||
};
|
|
||||||
this.busy = true;
|
this.busy = true;
|
||||||
const form = new FormData();
|
const form = new FormData();
|
||||||
form.append('firmware', this.otaFile);
|
form.append('firmware', this.otaFile);
|
||||||
@ -620,22 +414,23 @@
|
|||||||
const data = await r.json();
|
const data = await r.json();
|
||||||
if (!r.ok || !data.success) {
|
if (!r.ok || !data.success) {
|
||||||
this.applyOTAProgress({
|
this.applyOTAProgress({
|
||||||
phase: 'error', step: '', percent: 0,
|
phase: 'error',
|
||||||
|
percent: 0,
|
||||||
message: data.error || 'OTA fehlgeschlagen'
|
message: data.error || 'OTA fehlgeschlagen'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.ota.phase !== 'done') {
|
|
||||||
const slot = data.target_slot != null ? 'ota_' + data.target_slot : '?';
|
const slot = data.target_slot != null ? 'ota_' + data.target_slot : '?';
|
||||||
this.applyOTAProgress({
|
this.applyOTAProgress({
|
||||||
phase: 'done', step: '', percent: 100,
|
phase: 'done',
|
||||||
message: `OK — ${data.bytes_written} Bytes, Slot ${slot}. Alle Knoten neu starten.`
|
percent: 100,
|
||||||
|
message: `OK — ${data.bytes_written} Bytes nach ${slot} (Neustart zum Booten)`
|
||||||
});
|
});
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.applyOTAProgress({ phase: 'error', step: '', percent: 0, message: String(e) });
|
this.applyOTAProgress({ phase: 'error', percent: 0, message: String(e) });
|
||||||
} finally {
|
} finally {
|
||||||
this.busy = false;
|
this.busy = false;
|
||||||
|
this.ota.active = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
flash(msg, ok) {
|
flash(msg, ok) {
|
||||||
|
|||||||
@ -19,9 +19,7 @@ idf_component_register(
|
|||||||
"cmd_client_info.c"
|
"cmd_client_info.c"
|
||||||
"cmd_accel_deadzone.c"
|
"cmd_accel_deadzone.c"
|
||||||
"cmd_espnow_unicast_test.c"
|
"cmd_espnow_unicast_test.c"
|
||||||
"cmd_led_ring.c"
|
|
||||||
"cmd_ota.c"
|
"cmd_ota.c"
|
||||||
"cmd_ota_slave_progress.c"
|
|
||||||
"ota_uart.c"
|
"ota_uart.c"
|
||||||
"ota_espnow.c"
|
"ota_espnow.c"
|
||||||
"client_registry.c"
|
"client_registry.c"
|
||||||
|
|||||||
@ -202,14 +202,11 @@ Host and master speak nanopb-encoded `UartMessage` inside UART frames (byte 0 =
|
|||||||
| 4 | `CLIENT_INFO` | Implemented (`cmd_client_info.c`) — slave list from registry |
|
| 4 | `CLIENT_INFO` | Implemented (`cmd_client_info.c`) — slave list from registry |
|
||||||
| 5 | `CLIENT_INPUT` | Planned |
|
| 5 | `CLIENT_INPUT` | Planned |
|
||||||
| 6 | `ACCEL_DEADZONE` | Implemented (`cmd_accel_deadzone.c`) — get/set accel filter LSB |
|
| 6 | `ACCEL_DEADZONE` | Implemented (`cmd_accel_deadzone.c`) — get/set accel filter LSB |
|
||||||
| 7 | `ESPNOW_UNICAST_TEST` | Implemented (`cmd_espnow_unicast_test.c`) |
|
|
||||||
| 8 | `LED_RING` | Implemented (`cmd_led_ring.c`) — ring progress bar (0–100 %, RGB, intensity) |
|
|
||||||
| 16 | `OTA_START` | Implemented (`cmd_ota.c`) — begin UART OTA on inactive slot |
|
| 16 | `OTA_START` | Implemented (`cmd_ota.c`) — begin UART OTA on inactive slot |
|
||||||
| 17 | `OTA_PAYLOAD` | Implemented — up to 200 B per frame; device buffers 4 KiB |
|
| 17 | `OTA_PAYLOAD` | Implemented — up to 200 B per frame; device buffers 4 KiB |
|
||||||
| 18 | `OTA_END` | Implemented — flush, `esp_ota_end`, push image to slaves via ESP-NOW, set boot |
|
| 18 | `OTA_END` | Implemented — flush, `esp_ota_end`, push image to slaves via ESP-NOW, set boot |
|
||||||
| 19 | `OTA_STATUS` | Device → host (prepare/ready/block ACK/success/failed) |
|
| 19 | `OTA_STATUS` | Device → host (prepare/ready/block ACK/success/failed) |
|
||||||
| 20 | `OTA_START_ESPNOW` | Implemented — re-distribute staged image to slaves only |
|
| 20 | `OTA_START_ESPNOW` | Implemented — re-distribute staged image to slaves only |
|
||||||
| 21 | `OTA_SLAVE_PROGRESS` | Implemented (`cmd_ota_slave_progress.c`) — query per-slave ESP-NOW OTA progress |
|
|
||||||
|
|
||||||
Regenerate C code:
|
Regenerate C code:
|
||||||
|
|
||||||
@ -253,8 +250,6 @@ Inactive app partition is selected with `esp_ota_get_next_update_partition()`; `
|
|||||||
|
|
||||||
`OTA_END` can take a long time on the wire (slave flash + ESP-NOW); the host should use a generous read timeout.
|
`OTA_END` can take a long time on the wire (slave flash + ESP-NOW); the host should use a generous read timeout.
|
||||||
|
|
||||||
During OTA the LED ring shows progress at ~5 % brightness: **blue** while the image is written (UART on master, ESP-NOW on slaves), **green** on the master while it forwards the image to slaves over ESP-NOW. On **success** the ring gives one short **green** blink; on **failure** one **red** blink and ESP-NOW distribution is not started (failed UART upload / `OTA_END` validation).
|
|
||||||
|
|
||||||
`OTA_START_ESPNOW` (type `20`): re-run ESP-NOW distribution from the last staged image without a new UART upload (no-op if nothing staged).
|
`OTA_START_ESPNOW` (type `20`): re-run ESP-NOW distribution from the last staged image without a new UART upload (no-op if nothing staged).
|
||||||
|
|
||||||
Implementation: `ota_uart.c` (4 KiB buffer, `esp_ota_write`), `ota_espnow.c`, `cmd_ota.c`.
|
Implementation: `ota_uart.c` (4 KiB buffer, `esp_ota_write`), `ota_espnow.c`, `cmd_ota.c`.
|
||||||
@ -265,28 +260,7 @@ Host upload:
|
|||||||
go run . -port /dev/ttyUSB0 ota build/powerpod.bin
|
go run . -port /dev/ttyUSB0 ota build/powerpod.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
`OtaStatusPayload.status`: `1` preparing, `2` ready, `3` block_ack, `4` success, `5` failed, `6` distributing (`bytes_written` = progress, `target_slot` = slave count).
|
`OtaStatusPayload.status`: `1` preparing, `2` ready, `3` block_ack, `4` success, `5` failed.
|
||||||
|
|
||||||
### OTA_SLAVE_PROGRESS command
|
|
||||||
|
|
||||||
**Request:** framed `15` (`0x15`) + optional `ota_slave_progress_request` (`client_id`; `0` = all slaves in the current/last distribution session).
|
|
||||||
|
|
||||||
**Response:** `ota_slave_progress_response`:
|
|
||||||
|
|
||||||
| Field | Meaning |
|
|
||||||
|-------|---------|
|
|
||||||
| `active` | ESP-NOW distribution running |
|
|
||||||
| `total_bytes` | Image size |
|
|
||||||
| `aggregate_bytes` | Overall bytes sent to all slaves |
|
|
||||||
| `slave_count` | Number of slaves in session |
|
|
||||||
| `slaves[]` | Per slave: `client_id`, `bytes_written`, `total_bytes`, `status`, `error` |
|
|
||||||
|
|
||||||
Per-slave `status`: `0` idle, `1` preparing, `2` ready, `3` block_ack/distributing, `4` success, `5` failed.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go run . -port /dev/ttyUSB0 ota-progress
|
|
||||||
go run . -port /dev/ttyUSB0 ota-progress -client 16
|
|
||||||
```
|
|
||||||
|
|
||||||
### ACCEL_DEADZONE command
|
### ACCEL_DEADZONE command
|
||||||
|
|
||||||
@ -313,30 +287,6 @@ Minimal master→slave ESP-NOW unicast check (no BMA456). Use this before debugg
|
|||||||
|
|
||||||
**Firmware logs:** master `unicast TEST to … seq=N`; slave `UNICAST TEST OK from master … seq=N`.
|
**Firmware logs:** master `unicast TEST to … seq=N`; slave `UNICAST TEST OK from master … seq=N`.
|
||||||
|
|
||||||
### LED_RING command
|
|
||||||
|
|
||||||
Control the 95-LED ring from the host. The firmware **does not** animate digits locally; only UART updates the display.
|
|
||||||
|
|
||||||
**Request:** framed `08` + `led_ring_progress_request`:
|
|
||||||
|
|
||||||
| Field | Meaning |
|
|
||||||
|-------|---------|
|
|
||||||
| `mode` | `0` = clear, `1` = progress bar, `2` = digit, `3` = blink full ring |
|
|
||||||
| `progress` | 0–100 (% of ring lit, mode `1`) |
|
|
||||||
| `digit` | 0–10 (mode `2`, same segment maps as built-in digits) |
|
|
||||||
| `r`, `g`, `b` | Color 0–255 |
|
|
||||||
| `intensity` | Brightness 0–255 (scaled into RGB; `0` → firmware default ~5 %) |
|
|
||||||
| `blink_ms`, `blink_count` | Pulse length and count (mode `3`; defaults 350 ms, 1) |
|
|
||||||
|
|
||||||
**Response:** `led_ring_progress_response` (`success`, `mode`, `progress`, `digit`).
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go run . -port /dev/ttyUSB0 led-ring -mode progress -progress 75 -g 80 -b 255
|
|
||||||
go run . -port /dev/ttyUSB0 led-ring -mode digit -digit 7 -r 255 -g 200
|
|
||||||
go run . -port /dev/ttyUSB0 led-ring -mode clear
|
|
||||||
go run . -port /dev/ttyUSB0 led-ring -mode blink -g 255 -blink-count 2
|
|
||||||
```
|
|
||||||
|
|
||||||
### CLIENT_INFO command
|
### CLIENT_INFO command
|
||||||
|
|
||||||
**Request:** framed payload `04` only (`MessageType.CLIENT_INFO`).
|
**Request:** framed payload `04` only (`MessageType.CLIENT_INFO`).
|
||||||
@ -421,8 +371,7 @@ Target: ESP32-S3. Close serial monitor on the UART adapter port before running `
|
|||||||
| `client_registry.c/h` | Registered slave table |
|
| `client_registry.c/h` | Registered slave table |
|
||||||
| `bosch456.c/h` | BMA456H I2C driver, accel poll, tap INT, deadzone filter |
|
| `bosch456.c/h` | BMA456H I2C driver, accel poll, tap INT, deadzone filter |
|
||||||
| `board_input.c/h` | Taster GPIO12, LiPo ADC on GPIO1 / GPIO12 |
|
| `board_input.c/h` | Taster GPIO12, LiPo ADC on GPIO1 / GPIO12 |
|
||||||
| `led_ring.c/h` | LED ring (digit display, progress bar) |
|
| `led_ring.c/h` | LED digit display |
|
||||||
| `cmd_led_ring.c` | UART `LED_RING` progress command |
|
|
||||||
| `proto/uart_messages.proto` | UART protocol schema |
|
| `proto/uart_messages.proto` | UART protocol schema |
|
||||||
| `proto/esp_now_messages.proto` | ESP-NOW protocol schema |
|
| `proto/esp_now_messages.proto` | ESP-NOW protocol schema |
|
||||||
| `esp_now_proto.c/h` | Encode/decode `EspNowMessage` |
|
| `esp_now_proto.c/h` | Encode/decode `EspNowMessage` |
|
||||||
|
|||||||
@ -30,8 +30,6 @@ static const char *message_type_name(uint16_t id) {
|
|||||||
return "ACCEL_DEADZONE";
|
return "ACCEL_DEADZONE";
|
||||||
case alox_MessageType_ESPNOW_UNICAST_TEST:
|
case alox_MessageType_ESPNOW_UNICAST_TEST:
|
||||||
return "ESPNOW_UNICAST_TEST";
|
return "ESPNOW_UNICAST_TEST";
|
||||||
case alox_MessageType_LED_RING:
|
|
||||||
return "LED_RING";
|
|
||||||
case alox_MessageType_OTA_START:
|
case alox_MessageType_OTA_START:
|
||||||
return "OTA_START";
|
return "OTA_START";
|
||||||
case alox_MessageType_OTA_PAYLOAD:
|
case alox_MessageType_OTA_PAYLOAD:
|
||||||
@ -42,8 +40,6 @@ static const char *message_type_name(uint16_t id) {
|
|||||||
return "OTA_STATUS";
|
return "OTA_STATUS";
|
||||||
case alox_MessageType_OTA_START_ESPNOW:
|
case alox_MessageType_OTA_START_ESPNOW:
|
||||||
return "OTA_START_ESPNOW";
|
return "OTA_START_ESPNOW";
|
||||||
case alox_MessageType_OTA_SLAVE_PROGRESS:
|
|
||||||
return "OTA_SLAVE_PROGRESS";
|
|
||||||
default:
|
default:
|
||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,139 +0,0 @@
|
|||||||
#include "cmd_led_ring.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "led_ring.h"
|
|
||||||
#include "uart_cmd.h"
|
|
||||||
|
|
||||||
static const char *TAG = "[LED_RING_CMD]";
|
|
||||||
|
|
||||||
#define LED_RING_MODE_CLEAR 0
|
|
||||||
#define LED_RING_MODE_PROGRESS 1
|
|
||||||
#define LED_RING_MODE_DIGIT 2
|
|
||||||
#define LED_RING_MODE_BLINK 3
|
|
||||||
|
|
||||||
static uint8_t clamp_u8(uint32_t v) {
|
|
||||||
if (v > 255) {
|
|
||||||
return 255;
|
|
||||||
}
|
|
||||||
return (uint8_t)v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t clamp_progress(uint32_t v) {
|
|
||||||
if (v > 100) {
|
|
||||||
return 100;
|
|
||||||
}
|
|
||||||
return (uint8_t)v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t resolve_intensity(uint32_t intensity) {
|
|
||||||
if (intensity == 0) {
|
|
||||||
return LED_RING_DEFAULT_INTENSITY;
|
|
||||||
}
|
|
||||||
return clamp_u8(intensity);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void reply(bool success, uint32_t mode, uint32_t progress, uint32_t digit) {
|
|
||||||
alox_UartMessage response;
|
|
||||||
uart_cmd_init_response(&response, alox_MessageType_LED_RING,
|
|
||||||
alox_UartMessage_led_ring_progress_response_tag);
|
|
||||||
response.payload.led_ring_progress_response.success = success;
|
|
||||||
response.payload.led_ring_progress_response.mode = mode;
|
|
||||||
response.payload.led_ring_progress_response.progress = progress;
|
|
||||||
response.payload.led_ring_progress_response.digit = digit;
|
|
||||||
uart_cmd_send(&response, TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_led_ring(const uint8_t *data, size_t len) {
|
|
||||||
alox_UartMessage uart_msg;
|
|
||||||
alox_LedRingProgressRequest req = alox_LedRingProgressRequest_init_zero;
|
|
||||||
|
|
||||||
if (uart_cmd_decode(data, len, &uart_msg) != ESP_OK) {
|
|
||||||
ESP_LOGW(TAG, "decode failed");
|
|
||||||
reply(false, 0, 0, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const alox_LedRingProgressRequest *req_ptr = UART_CMD_REQ(
|
|
||||||
&uart_msg, alox_UartMessage_led_ring_progress_request_tag,
|
|
||||||
led_ring_progress_request);
|
|
||||||
if (req_ptr != NULL) {
|
|
||||||
req = *req_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t mode = req.mode;
|
|
||||||
uint8_t r = clamp_u8(req.r);
|
|
||||||
uint8_t g = clamp_u8(req.g);
|
|
||||||
uint8_t b = clamp_u8(req.b);
|
|
||||||
uint8_t intensity = resolve_intensity(req.intensity);
|
|
||||||
|
|
||||||
led_command_t cmd = {0};
|
|
||||||
|
|
||||||
switch (mode) {
|
|
||||||
case LED_RING_MODE_CLEAR:
|
|
||||||
cmd.mode = LED_CMD_CLEAR;
|
|
||||||
led_ring_send_command(&cmd);
|
|
||||||
ESP_LOGI(TAG, "clear");
|
|
||||||
reply(true, mode, 0, 0);
|
|
||||||
return;
|
|
||||||
|
|
||||||
case LED_RING_MODE_PROGRESS: {
|
|
||||||
uint8_t progress = clamp_progress(req.progress);
|
|
||||||
cmd.mode = LED_CMD_PROGRESS;
|
|
||||||
cmd.progress = progress;
|
|
||||||
cmd.r = r;
|
|
||||||
cmd.g = g;
|
|
||||||
cmd.b = b;
|
|
||||||
cmd.intensity = intensity;
|
|
||||||
led_ring_send_command(&cmd);
|
|
||||||
ESP_LOGI(TAG, "progress %u%% rgb=%u,%u,%u", (unsigned)progress,
|
|
||||||
(unsigned)r, (unsigned)g, (unsigned)b);
|
|
||||||
reply(true, mode, progress, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case LED_RING_MODE_DIGIT: {
|
|
||||||
if (req.digit > 10) {
|
|
||||||
ESP_LOGW(TAG, "digit %lu out of range", (unsigned long)req.digit);
|
|
||||||
reply(false, mode, 0, req.digit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cmd.mode = LED_CMD_SET_DIGIT;
|
|
||||||
cmd.value = (uint8_t)req.digit;
|
|
||||||
cmd.r = r;
|
|
||||||
cmd.g = g;
|
|
||||||
cmd.b = b;
|
|
||||||
cmd.intensity = intensity;
|
|
||||||
led_ring_send_command(&cmd);
|
|
||||||
ESP_LOGI(TAG, "digit %u rgb=%u,%u,%u", (unsigned)cmd.value, (unsigned)r,
|
|
||||||
(unsigned)g, (unsigned)b);
|
|
||||||
reply(true, mode, 0, req.digit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case LED_RING_MODE_BLINK: {
|
|
||||||
cmd.mode = LED_CMD_BLINK;
|
|
||||||
cmd.r = r;
|
|
||||||
cmd.g = g;
|
|
||||||
cmd.b = b;
|
|
||||||
cmd.intensity = intensity;
|
|
||||||
cmd.blink_ms = (uint16_t)(req.blink_ms > 0 ? req.blink_ms : 350);
|
|
||||||
cmd.blink_count = req.blink_count > 0 ? (uint8_t)req.blink_count : 1;
|
|
||||||
if (cmd.blink_count == 0) {
|
|
||||||
cmd.blink_count = 1;
|
|
||||||
}
|
|
||||||
led_ring_send_command(&cmd);
|
|
||||||
ESP_LOGI(TAG, "blink x%u %u ms rgb=%u,%u,%u", (unsigned)cmd.blink_count,
|
|
||||||
(unsigned)cmd.blink_ms, (unsigned)r, (unsigned)g, (unsigned)b);
|
|
||||||
reply(true, mode, 0, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
ESP_LOGW(TAG, "unknown mode %lu", (unsigned long)mode);
|
|
||||||
reply(false, mode, 0, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cmd_led_ring_register(void) {
|
|
||||||
uart_cmd_register(alox_MessageType_LED_RING, handle_led_ring);
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
#ifndef CMD_LED_RING_H
|
|
||||||
#define CMD_LED_RING_H
|
|
||||||
|
|
||||||
void cmd_led_ring_register(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
184
main/cmd_ota.c
184
main/cmd_ota.c
@ -1,34 +1,16 @@
|
|||||||
#include "cmd_ota.h"
|
#include "cmd_ota.h"
|
||||||
#include "led_ring.h"
|
|
||||||
#include "ota_espnow.h"
|
#include "ota_espnow.h"
|
||||||
#include "ota_uart.h"
|
#include "ota_uart.h"
|
||||||
#include "uart_cmd.h"
|
#include "uart_cmd.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/idf_additions.h"
|
#include "freertos/idf_additions.h"
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static const char *TAG = "[OTA_CMD]";
|
static const char *TAG = "[OTA_CMD]";
|
||||||
|
|
||||||
#define OTA_PREPARE_STACK 8192
|
#define OTA_PREPARE_STACK 8192
|
||||||
#define OTA_PREPARE_PRIO 5
|
#define OTA_PREPARE_PRIO 5
|
||||||
#define OTA_DIST_STACK 8192
|
|
||||||
#define OTA_DIST_PRIO 5
|
|
||||||
|
|
||||||
/** UART OTA upload to this node (master). */
|
|
||||||
#define OTA_LED_UART_R 0
|
|
||||||
#define OTA_LED_UART_G 0
|
|
||||||
#define OTA_LED_UART_B 255
|
|
||||||
/** ESP-NOW distribution from master to slaves. */
|
|
||||||
#define OTA_LED_ESPNOW_TX_R 0
|
|
||||||
#define OTA_LED_ESPNOW_TX_G 255
|
|
||||||
#define OTA_LED_ESPNOW_TX_B 0
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t written;
|
|
||||||
int slot;
|
|
||||||
} ota_dist_job_t;
|
|
||||||
static void send_ota_status(ota_uart_status_t status, uint32_t err_code) {
|
static void send_ota_status(ota_uart_status_t status, uint32_t err_code) {
|
||||||
alox_UartMessage response;
|
alox_UartMessage response;
|
||||||
uart_cmd_init_response(&response, alox_MessageType_OTA_STATUS,
|
uart_cmd_init_response(&response, alox_MessageType_OTA_STATUS,
|
||||||
@ -42,42 +24,6 @@ static void send_ota_status(ota_uart_status_t status, uint32_t err_code) {
|
|||||||
uart_cmd_send(&response, TAG);
|
uart_cmd_send(&response, TAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send_ota_failed(uint32_t err_code) {
|
|
||||||
led_ring_ota_failed();
|
|
||||||
send_ota_status(OTA_UART_ST_FAILED, err_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void send_ota_distributing(uint32_t kind, uint32_t bytes_done,
|
|
||||||
uint32_t target_slot) {
|
|
||||||
alox_UartMessage response;
|
|
||||||
uart_cmd_init_response(&response, alox_MessageType_OTA_STATUS,
|
|
||||||
alox_UartMessage_ota_status_tag);
|
|
||||||
response.payload.ota_status.status = (uint32_t)OTA_UART_ST_DISTRIBUTING;
|
|
||||||
response.payload.ota_status.bytes_written = bytes_done;
|
|
||||||
response.payload.ota_status.target_slot = target_slot;
|
|
||||||
response.payload.ota_status.error = kind;
|
|
||||||
uart_cmd_send(&response, TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ota_dist_aggregate(uint32_t bytes_done, uint32_t total_bytes,
|
|
||||||
uint8_t slave_count) {
|
|
||||||
(void)slave_count;
|
|
||||||
led_ring_show_ota_progress(bytes_done, total_bytes, OTA_LED_ESPNOW_TX_R,
|
|
||||||
OTA_LED_ESPNOW_TX_G, OTA_LED_ESPNOW_TX_B);
|
|
||||||
send_ota_distributing(OTA_DIST_AGGREGATE, bytes_done, (uint32_t)slave_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ota_dist_per_slave(uint32_t slave_id, uint32_t bytes_done,
|
|
||||||
uint32_t total_bytes) {
|
|
||||||
(void)total_bytes;
|
|
||||||
send_ota_distributing(OTA_DIST_PER_SLAVE, bytes_done, slave_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const ota_espnow_progress_cbs_t s_dist_progress = {
|
|
||||||
.aggregate = ota_dist_aggregate,
|
|
||||||
.per_slave = ota_dist_per_slave,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void ota_prepare_task(void *param) {
|
static void ota_prepare_task(void *param) {
|
||||||
uint32_t total_size = (uint32_t)(uintptr_t)param;
|
uint32_t total_size = (uint32_t)(uintptr_t)param;
|
||||||
|
|
||||||
@ -85,7 +31,7 @@ static void ota_prepare_task(void *param) {
|
|||||||
|
|
||||||
int slot = ota_uart_prepare(total_size);
|
int slot = ota_uart_prepare(total_size);
|
||||||
if (slot < 0) {
|
if (slot < 0) {
|
||||||
send_ota_failed(1);
|
send_ota_status(OTA_UART_ST_FAILED, 1);
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -99,9 +45,6 @@ static void ota_prepare_task(void *param) {
|
|||||||
response.payload.ota_status.error = 0;
|
response.payload.ota_status.error = 0;
|
||||||
uart_cmd_send(&response, TAG);
|
uart_cmd_send(&response, TAG);
|
||||||
|
|
||||||
led_ring_show_ota_progress(0, total_size, OTA_LED_UART_R, OTA_LED_UART_G,
|
|
||||||
OTA_LED_UART_B);
|
|
||||||
|
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +53,7 @@ static void handle_ota_start(const uint8_t *data, size_t len) {
|
|||||||
alox_OtaStartPayload req = alox_OtaStartPayload_init_zero;
|
alox_OtaStartPayload req = alox_OtaStartPayload_init_zero;
|
||||||
|
|
||||||
if (uart_cmd_decode(data, len, &uart_msg) != ESP_OK) {
|
if (uart_cmd_decode(data, len, &uart_msg) != ESP_OK) {
|
||||||
send_ota_failed( 2);
|
send_ota_status(OTA_UART_ST_FAILED, 2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,13 +65,13 @@ static void handle_ota_start(const uint8_t *data, size_t len) {
|
|||||||
|
|
||||||
if (req.total_size == 0) {
|
if (req.total_size == 0) {
|
||||||
ESP_LOGW(TAG, "OTA_START: total_size required");
|
ESP_LOGW(TAG, "OTA_START: total_size required");
|
||||||
send_ota_failed( 3);
|
send_ota_status(OTA_UART_ST_FAILED, 3);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ota_uart_is_active()) {
|
if (ota_uart_is_active()) {
|
||||||
ESP_LOGW(TAG, "OTA_START while session active");
|
ESP_LOGW(TAG, "OTA_START while session active");
|
||||||
send_ota_failed( 4);
|
send_ota_status(OTA_UART_ST_FAILED, 4);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +79,7 @@ static void handle_ota_start(const uint8_t *data, size_t len) {
|
|||||||
(void *)(uintptr_t)req.total_size, OTA_PREPARE_PRIO,
|
(void *)(uintptr_t)req.total_size, OTA_PREPARE_PRIO,
|
||||||
NULL) != pdPASS) {
|
NULL) != pdPASS) {
|
||||||
ESP_LOGE(TAG, "failed to create ota_prepare task");
|
ESP_LOGE(TAG, "failed to create ota_prepare task");
|
||||||
send_ota_failed( 5);
|
send_ota_status(OTA_UART_ST_FAILED, 5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +88,7 @@ static void handle_ota_payload(const uint8_t *data, size_t len) {
|
|||||||
|
|
||||||
if (uart_cmd_decode(data, len, &uart_msg) != ESP_OK) {
|
if (uart_cmd_decode(data, len, &uart_msg) != ESP_OK) {
|
||||||
ESP_LOGW(TAG, "OTA_PAYLOAD decode failed");
|
ESP_LOGW(TAG, "OTA_PAYLOAD decode failed");
|
||||||
send_ota_failed( 10);
|
send_ota_status(OTA_UART_ST_FAILED, 10);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,104 +97,77 @@ static void handle_ota_payload(const uint8_t *data, size_t len) {
|
|||||||
if (req_ptr == NULL) {
|
if (req_ptr == NULL) {
|
||||||
ESP_LOGW(TAG, "OTA_PAYLOAD: missing ota_payload (which=%u)",
|
ESP_LOGW(TAG, "OTA_PAYLOAD: missing ota_payload (which=%u)",
|
||||||
(unsigned)uart_msg.which_payload);
|
(unsigned)uart_msg.which_payload);
|
||||||
send_ota_failed( 11);
|
send_ota_status(OTA_UART_ST_FAILED, 11);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req_ptr->data.size == 0) {
|
if (req_ptr->data.size == 0) {
|
||||||
ESP_LOGW(TAG, "OTA_PAYLOAD: empty data (seq=%lu)",
|
ESP_LOGW(TAG, "OTA_PAYLOAD: empty data (seq=%lu)",
|
||||||
(unsigned long)req_ptr->seq);
|
(unsigned long)req_ptr->seq);
|
||||||
send_ota_failed( 11);
|
send_ota_status(OTA_UART_ST_FAILED, 11);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ota_uart_is_active()) {
|
if (!ota_uart_is_active()) {
|
||||||
ESP_LOGW(TAG, "OTA_PAYLOAD without active session (seq=%lu)",
|
ESP_LOGW(TAG, "OTA_PAYLOAD without active session (seq=%lu)",
|
||||||
(unsigned long)req_ptr->seq);
|
(unsigned long)req_ptr->seq);
|
||||||
send_ota_failed( 12);
|
send_ota_status(OTA_UART_ST_FAILED, 12);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ota_feed_result_t r =
|
ota_feed_result_t r =
|
||||||
ota_uart_feed(req_ptr->data.bytes, req_ptr->data.size);
|
ota_uart_feed(req_ptr->data.bytes, req_ptr->data.size);
|
||||||
if (r == OTA_FEED_ERROR) {
|
if (r == OTA_FEED_ERROR) {
|
||||||
send_ota_failed( 13);
|
send_ota_status(OTA_UART_ST_FAILED, 13);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (r == OTA_FEED_BLOCK_WRITTEN) {
|
if (r == OTA_FEED_BLOCK_WRITTEN) {
|
||||||
uint32_t total = ota_uart_total_size();
|
|
||||||
uint32_t done = ota_uart_bytes_written();
|
|
||||||
ESP_LOGI(TAG, "OTA block ack (%lu bytes in flash)",
|
ESP_LOGI(TAG, "OTA block ack (%lu bytes in flash)",
|
||||||
(unsigned long)done);
|
(unsigned long)ota_uart_bytes_written());
|
||||||
led_ring_show_ota_progress(done, total, OTA_LED_UART_R, OTA_LED_UART_G,
|
|
||||||
OTA_LED_UART_B);
|
|
||||||
send_ota_status(OTA_UART_ST_BLOCK_ACK, 0);
|
send_ota_status(OTA_UART_ST_BLOCK_ACK, 0);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r == OTA_FEED_OK) {
|
|
||||||
uint32_t total = ota_uart_total_size();
|
|
||||||
if (total > 0) {
|
|
||||||
led_ring_show_ota_progress(ota_uart_bytes_received(), total,
|
|
||||||
OTA_LED_UART_R, OTA_LED_UART_G, OTA_LED_UART_B);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ota_distribute_task(void *param) {
|
static esp_err_t finish_master_ota_and_distribute(void) {
|
||||||
ota_dist_job_t *job = (ota_dist_job_t *)param;
|
uint32_t written = ota_uart_bytes_written();
|
||||||
if (job == NULL) {
|
int slot = ota_uart_target_slot();
|
||||||
vTaskDelete(NULL);
|
bool success = false;
|
||||||
return;
|
esp_err_t err = ota_uart_finish(false, &success);
|
||||||
|
if (err != ESP_OK || !success) {
|
||||||
|
send_ota_status(OTA_UART_ST_FAILED, (uint32_t)err);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
const esp_partition_t *part = NULL;
|
const esp_partition_t *part = NULL;
|
||||||
uint32_t image_size = 0;
|
uint32_t image_size = 0;
|
||||||
if (!ota_uart_get_staged_image(&part, &image_size)) {
|
if (!ota_uart_get_staged_image(&part, &image_size)) {
|
||||||
send_ota_failed( 30);
|
send_ota_status(OTA_UART_ST_FAILED, 30);
|
||||||
free(job);
|
return ESP_ERR_INVALID_STATE;
|
||||||
vTaskDelete(NULL);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
led_ring_show_ota_progress(0, image_size, OTA_LED_ESPNOW_TX_R, OTA_LED_ESPNOW_TX_G,
|
err = ota_espnow_distribute(part, image_size);
|
||||||
OTA_LED_ESPNOW_TX_B);
|
|
||||||
send_ota_distributing(OTA_DIST_AGGREGATE, 0, 0);
|
|
||||||
|
|
||||||
esp_err_t err = ota_espnow_distribute(part, image_size, &s_dist_progress);
|
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "slave OTA distribution failed: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "slave OTA distribution failed: %s", esp_err_to_name(err));
|
||||||
ota_uart_clear_staged();
|
ota_uart_clear_staged();
|
||||||
send_ota_failed(31);
|
send_ota_status(OTA_UART_ST_FAILED, 31);
|
||||||
free(job);
|
return err;
|
||||||
vTaskDelete(NULL);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ota_uart_apply_boot();
|
err = ota_uart_apply_boot();
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
send_ota_failed((uint32_t)err);
|
send_ota_status(OTA_UART_ST_FAILED, (uint32_t)err);
|
||||||
free(job);
|
return err;
|
||||||
vTaskDelete(NULL);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
led_ring_show_ota_progress(image_size, image_size, OTA_LED_ESPNOW_TX_R,
|
|
||||||
OTA_LED_ESPNOW_TX_G, OTA_LED_ESPNOW_TX_B);
|
|
||||||
|
|
||||||
alox_UartMessage response;
|
alox_UartMessage response;
|
||||||
uart_cmd_init_response(&response, alox_MessageType_OTA_STATUS,
|
uart_cmd_init_response(&response, alox_MessageType_OTA_STATUS,
|
||||||
alox_UartMessage_ota_status_tag);
|
alox_UartMessage_ota_status_tag);
|
||||||
response.payload.ota_status.status = (uint32_t)OTA_UART_ST_SUCCESS;
|
response.payload.ota_status.status = (uint32_t)OTA_UART_ST_SUCCESS;
|
||||||
response.payload.ota_status.bytes_written = job->written;
|
response.payload.ota_status.bytes_written = written;
|
||||||
response.payload.ota_status.target_slot =
|
response.payload.ota_status.target_slot = slot >= 0 ? (uint32_t)slot : 0;
|
||||||
job->slot >= 0 ? (uint32_t)job->slot : 0;
|
|
||||||
response.payload.ota_status.error = 0;
|
response.payload.ota_status.error = 0;
|
||||||
uart_cmd_send(&response, TAG);
|
uart_cmd_send(&response, TAG);
|
||||||
|
return ESP_OK;
|
||||||
led_ring_ota_success();
|
|
||||||
free(job);
|
|
||||||
vTaskDelete(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_ota_end(const uint8_t *data, size_t len) {
|
static void handle_ota_end(const uint8_t *data, size_t len) {
|
||||||
@ -259,38 +175,11 @@ static void handle_ota_end(const uint8_t *data, size_t len) {
|
|||||||
(void)len;
|
(void)len;
|
||||||
|
|
||||||
if (!ota_uart_is_active()) {
|
if (!ota_uart_is_active()) {
|
||||||
send_ota_failed( 20);
|
send_ota_status(OTA_UART_ST_FAILED, 20);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ota_dist_job_t *job = calloc(1, sizeof(*job));
|
(void)finish_master_ota_and_distribute();
|
||||||
if (job == NULL) {
|
|
||||||
send_ota_failed( 21);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
job->written = ota_uart_bytes_written();
|
|
||||||
job->slot = ota_uart_target_slot();
|
|
||||||
uint32_t uart_total = ota_uart_total_size();
|
|
||||||
|
|
||||||
bool success = false;
|
|
||||||
esp_err_t err = ota_uart_finish(false, &success);
|
|
||||||
if (err != ESP_OK || !success) {
|
|
||||||
send_ota_failed((uint32_t)err);
|
|
||||||
free(job);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uart_total > 0) {
|
|
||||||
led_ring_show_ota_progress(job->written, uart_total, OTA_LED_UART_R,
|
|
||||||
OTA_LED_UART_G, OTA_LED_UART_B);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xTaskCreate(ota_distribute_task, "ota_dist", OTA_DIST_STACK, job,
|
|
||||||
OTA_DIST_PRIO, NULL) != pdPASS) {
|
|
||||||
ESP_LOGE(TAG, "failed to create ota_dist task");
|
|
||||||
send_ota_failed( 22);
|
|
||||||
free(job);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_ota_start_espnow(const uint8_t *data, size_t len) {
|
static void handle_ota_start_espnow(const uint8_t *data, size_t len) {
|
||||||
@ -298,26 +187,26 @@ static void handle_ota_start_espnow(const uint8_t *data, size_t len) {
|
|||||||
(void)len;
|
(void)len;
|
||||||
|
|
||||||
if (ota_uart_is_active()) {
|
if (ota_uart_is_active()) {
|
||||||
send_ota_failed( 40);
|
send_ota_status(OTA_UART_ST_FAILED, 40);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const esp_partition_t *part = NULL;
|
const esp_partition_t *part = NULL;
|
||||||
uint32_t image_size = 0;
|
uint32_t image_size = 0;
|
||||||
if (!ota_uart_get_staged_image(&part, &image_size)) {
|
if (!ota_uart_get_staged_image(&part, &image_size)) {
|
||||||
send_ota_failed( 41);
|
send_ota_status(OTA_UART_ST_FAILED, 41);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t err = ota_espnow_distribute(part, image_size, &s_dist_progress);
|
esp_err_t err = ota_espnow_distribute(part, image_size);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
send_ota_failed( 42);
|
send_ota_status(OTA_UART_ST_FAILED, 42);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ota_uart_apply_boot();
|
err = ota_uart_apply_boot();
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
send_ota_failed( (uint32_t)err);
|
send_ota_status(OTA_UART_ST_FAILED, (uint32_t)err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,7 +217,6 @@ static void handle_ota_start_espnow(const uint8_t *data, size_t len) {
|
|||||||
response.payload.ota_status.bytes_written = image_size;
|
response.payload.ota_status.bytes_written = image_size;
|
||||||
response.payload.ota_status.error = 0;
|
response.payload.ota_status.error = 0;
|
||||||
uart_cmd_send(&response, TAG);
|
uart_cmd_send(&response, TAG);
|
||||||
led_ring_ota_success();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_ota_register(void) {
|
void cmd_ota_register(void) {
|
||||||
|
|||||||
@ -1,37 +0,0 @@
|
|||||||
#include "cmd_ota_slave_progress.h"
|
|
||||||
#include "ota_espnow.h"
|
|
||||||
#include "uart_cmd.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
|
|
||||||
static const char *TAG = "[OTA_PROG]";
|
|
||||||
|
|
||||||
static void handle_ota_slave_progress(const uint8_t *data, size_t len) {
|
|
||||||
alox_UartMessage uart_msg;
|
|
||||||
uint32_t filter = 0;
|
|
||||||
|
|
||||||
if (uart_cmd_decode(data, len, &uart_msg) == ESP_OK) {
|
|
||||||
const alox_OtaSlaveProgressRequest *req =
|
|
||||||
UART_CMD_REQ(&uart_msg, alox_UartMessage_ota_slave_progress_request_tag,
|
|
||||||
ota_slave_progress_request);
|
|
||||||
if (req != NULL) {
|
|
||||||
filter = req->client_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
alox_UartMessage response;
|
|
||||||
uart_cmd_init_response(
|
|
||||||
&response, alox_MessageType_OTA_SLAVE_PROGRESS,
|
|
||||||
alox_UartMessage_ota_slave_progress_response_tag);
|
|
||||||
ota_espnow_progress_query(filter, &response.payload.ota_slave_progress_response);
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "query client_id=%lu -> %u slave(s) active=%d",
|
|
||||||
(unsigned long)filter,
|
|
||||||
(unsigned)response.payload.ota_slave_progress_response.slaves_count,
|
|
||||||
(int)response.payload.ota_slave_progress_response.active);
|
|
||||||
uart_cmd_send(&response, TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cmd_ota_slave_progress_register(void) {
|
|
||||||
uart_cmd_register(alox_MessageType_OTA_SLAVE_PROGRESS,
|
|
||||||
handle_ota_slave_progress);
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
#ifndef CMD_OTA_SLAVE_PROGRESS_H
|
|
||||||
#define CMD_OTA_SLAVE_PROGRESS_H
|
|
||||||
|
|
||||||
void cmd_ota_slave_progress_register(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
119
main/led_ring.c
119
main/led_ring.c
@ -3,8 +3,6 @@
|
|||||||
#include "driver/i2c_types.h"
|
#include "driver/i2c_types.h"
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "led_strip.h"
|
#include "led_strip.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
@ -18,8 +16,6 @@ static led_strip_handle_t led_ring;
|
|||||||
|
|
||||||
#define RING_LEDS 95
|
#define RING_LEDS 95
|
||||||
#define LED_RING_PIN 7
|
#define LED_RING_PIN 7
|
||||||
#define LED_RING_BLINK_ON_MS 350
|
|
||||||
#define LED_RING_BLINK_OFF_MS 150
|
|
||||||
|
|
||||||
static QueueHandle_t led_queue;
|
static QueueHandle_t led_queue;
|
||||||
|
|
||||||
@ -47,33 +43,20 @@ const uint8_t d9[] = {19, 20, 21, 22, 23, 24, 25, 26, 27, 46, 47, 58,
|
|||||||
const uint8_t d10[] = {46, 50, 57, 61, 65, 72, 76, 78, 80,
|
const uint8_t d10[] = {46, 50, 57, 61, 65, 72, 76, 78, 80,
|
||||||
82, 84, 86, 88, 90, 92, 93, 94, 95};
|
82, 84, 86, 88, 90, 92, 93, 94, 95};
|
||||||
|
|
||||||
|
// Lookup Array for the Digits
|
||||||
const digit_definition_t digit_lookup[] = {
|
const digit_definition_t digit_lookup[] = {
|
||||||
{d0, sizeof(d0)}, {d1, sizeof(d1)}, {d2, sizeof(d2)}, {d3, sizeof(d3)},
|
{d0, sizeof(d0)}, {d1, sizeof(d1)}, {d2, sizeof(d2)}, {d3, sizeof(d3)},
|
||||||
{d4, sizeof(d4)}, {d5, sizeof(d5)}, {d6, sizeof(d6)}, {d7, sizeof(d7)},
|
{d4, sizeof(d4)}, {d5, sizeof(d5)}, {d6, sizeof(d6)}, {d7, sizeof(d7)},
|
||||||
{d8, sizeof(d8)}, {d9, sizeof(d9)}, {d10, sizeof(d10)}};
|
{d8, sizeof(d8)}, {d9, sizeof(d9)}, {d10, sizeof(d10)}};
|
||||||
|
|
||||||
void led_ring_scale_rgb(uint8_t *r, uint8_t *g, uint8_t *b, uint8_t intensity) {
|
|
||||||
if (intensity == 0) {
|
|
||||||
intensity = LED_RING_DEFAULT_INTENSITY;
|
|
||||||
}
|
|
||||||
*r = (uint16_t)(*r) * intensity / 255;
|
|
||||||
*g = (uint16_t)(*g) * intensity / 255;
|
|
||||||
*b = (uint16_t)(*b) * intensity / 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ring_fill_color(uint8_t r, uint8_t g, uint8_t b) {
|
|
||||||
for (uint32_t i = 0; i < RING_LEDS; i++) {
|
|
||||||
led_strip_set_pixel(led_ring, i, r, g, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void vTaskLedRing(void *pvParameters) {
|
void vTaskLedRing(void *pvParameters) {
|
||||||
|
/* LED Ring config */
|
||||||
led_strip_config_t ring_config = {
|
led_strip_config_t ring_config = {
|
||||||
.strip_gpio_num = LED_RING_PIN,
|
.strip_gpio_num = LED_RING_PIN,
|
||||||
.max_leds = RING_LEDS,
|
.max_leds = RING_LEDS,
|
||||||
};
|
};
|
||||||
led_strip_rmt_config_t rmt_ring_config = {
|
led_strip_rmt_config_t rmt_ring_config = {
|
||||||
.resolution_hz = 10 * 1000 * 1000,
|
.resolution_hz = 10 * 1000 * 1000, // 10 MHz
|
||||||
};
|
};
|
||||||
esp_err_t err =
|
esp_err_t err =
|
||||||
led_strip_new_rmt_device(&ring_config, &rmt_ring_config, &led_ring);
|
led_strip_new_rmt_device(&ring_config, &rmt_ring_config, &led_ring);
|
||||||
@ -84,44 +67,18 @@ void vTaskLedRing(void *pvParameters) {
|
|||||||
led_command_t cmd;
|
led_command_t cmd;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (xQueueReceive(led_queue, &cmd, portMAX_DELAY)) {
|
if (xQueueReceive(led_queue, &cmd, portMAX_DELAY)) {
|
||||||
uint8_t r = cmd.r;
|
// Clear all LEDS
|
||||||
uint8_t g = cmd.g;
|
|
||||||
uint8_t b = cmd.b;
|
|
||||||
led_ring_scale_rgb(&r, &g, &b, cmd.intensity);
|
|
||||||
|
|
||||||
led_strip_clear(led_ring);
|
led_strip_clear(led_ring);
|
||||||
|
|
||||||
if (cmd.mode == LED_CMD_CLEAR) {
|
if (cmd.mode == LED_CMD_SET_DIGIT && cmd.value <= 10) {
|
||||||
/* ring already cleared */
|
|
||||||
} else if (cmd.mode == LED_CMD_SET_DIGIT && cmd.value <= 10) {
|
|
||||||
digit_definition_t digit = digit_lookup[cmd.value];
|
digit_definition_t digit = digit_lookup[cmd.value];
|
||||||
for (int i = 0; i < digit.count; i++) {
|
|
||||||
led_strip_set_pixel(led_ring, RING_LEDS - digit.leds[i], r, g, b);
|
|
||||||
}
|
|
||||||
} else if (cmd.mode == LED_CMD_PROGRESS) {
|
|
||||||
uint32_t lit = ((uint32_t)cmd.progress * RING_LEDS + 50) / 100;
|
|
||||||
if (lit > RING_LEDS) {
|
|
||||||
lit = RING_LEDS;
|
|
||||||
}
|
|
||||||
for (uint32_t i = 0; i < lit; i++) {
|
|
||||||
led_strip_set_pixel(led_ring, i, r, g, b);
|
|
||||||
}
|
|
||||||
} else if (cmd.mode == LED_CMD_BLINK) {
|
|
||||||
uint16_t on_ms = cmd.blink_ms > 0 ? cmd.blink_ms : LED_RING_BLINK_ON_MS;
|
|
||||||
uint8_t count = cmd.blink_count > 0 ? cmd.blink_count : 1;
|
|
||||||
|
|
||||||
for (uint8_t n = 0; n < count; n++) {
|
for (int i = 0; i < digit.count; i++) {
|
||||||
ring_fill_color(r, g, b);
|
// Invert LED Counting for Now
|
||||||
led_strip_refresh(led_ring);
|
led_strip_set_pixel(led_ring, RING_LEDS - digit.leds[i], cmd.r, cmd.g,
|
||||||
vTaskDelay(pdMS_TO_TICKS(on_ms));
|
cmd.b);
|
||||||
led_strip_clear(led_ring);
|
|
||||||
led_strip_refresh(led_ring);
|
|
||||||
if (n + 1 < count) {
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(LED_RING_BLINK_OFF_MS));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
|
||||||
led_strip_refresh(led_ring);
|
led_strip_refresh(led_ring);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,61 +94,3 @@ void led_ring_send_command(led_command_t *cmd) {
|
|||||||
xQueueSend(led_queue, cmd, portMAX_DELAY);
|
xQueueSend(led_queue, cmd, portMAX_DELAY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void led_ring_show_ota_clear(void) {
|
|
||||||
led_command_t cmd = {.mode = LED_CMD_CLEAR};
|
|
||||||
led_ring_send_command(&cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void led_ring_show_ota_progress(uint32_t bytes_done, uint32_t total_bytes,
|
|
||||||
uint8_t r, uint8_t g, uint8_t b) {
|
|
||||||
static struct {
|
|
||||||
uint8_t pct;
|
|
||||||
uint8_t r, g, b;
|
|
||||||
} last = {255, 0, 0, 0};
|
|
||||||
|
|
||||||
if (total_bytes == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t pct32 = (bytes_done * 100u + total_bytes / 2) / total_bytes;
|
|
||||||
if (pct32 > 100) {
|
|
||||||
pct32 = 100;
|
|
||||||
}
|
|
||||||
uint8_t pct = (uint8_t)pct32;
|
|
||||||
|
|
||||||
if (pct == last.pct && r == last.r && g == last.g && b == last.b) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
last.pct = pct;
|
|
||||||
last.r = r;
|
|
||||||
last.g = g;
|
|
||||||
last.b = b;
|
|
||||||
|
|
||||||
led_command_t cmd = {
|
|
||||||
.mode = LED_CMD_PROGRESS,
|
|
||||||
.progress = pct,
|
|
||||||
.r = r,
|
|
||||||
.g = g,
|
|
||||||
.b = b,
|
|
||||||
.intensity = LED_RING_DEFAULT_INTENSITY,
|
|
||||||
};
|
|
||||||
led_ring_send_command(&cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void led_ring_blink_once(uint8_t r, uint8_t g, uint8_t b) {
|
|
||||||
led_command_t cmd = {
|
|
||||||
.mode = LED_CMD_BLINK,
|
|
||||||
.r = r,
|
|
||||||
.g = g,
|
|
||||||
.b = b,
|
|
||||||
.intensity = LED_RING_DEFAULT_INTENSITY,
|
|
||||||
.blink_ms = LED_RING_BLINK_ON_MS,
|
|
||||||
.blink_count = 1,
|
|
||||||
};
|
|
||||||
led_ring_send_command(&cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void led_ring_ota_success(void) { led_ring_blink_once(0, 255, 0); }
|
|
||||||
|
|
||||||
void led_ring_ota_failed(void) { led_ring_blink_once(255, 0, 0); }
|
|
||||||
|
|||||||
@ -1,42 +1,12 @@
|
|||||||
#ifndef LED_RING_H
|
|
||||||
#define LED_RING_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/** Default RGB scale (~5 % of full brightness). */
|
typedef enum { LED_CMD_CLEAR, LED_CMD_SET_DIGIT, LED_CMD_SET_COLOR } led_mode_t;
|
||||||
#define LED_RING_DEFAULT_INTENSITY 13
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
LED_CMD_CLEAR,
|
|
||||||
LED_CMD_SET_DIGIT,
|
|
||||||
LED_CMD_SET_COLOR,
|
|
||||||
LED_CMD_PROGRESS,
|
|
||||||
LED_CMD_BLINK
|
|
||||||
} led_mode_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
led_mode_t mode;
|
led_mode_t mode;
|
||||||
uint8_t value;
|
uint8_t value;
|
||||||
uint8_t r, g, b;
|
uint8_t r, g, b;
|
||||||
uint8_t intensity;
|
|
||||||
uint8_t progress;
|
|
||||||
uint16_t blink_ms;
|
|
||||||
uint8_t blink_count;
|
|
||||||
} led_command_t;
|
} led_command_t;
|
||||||
|
|
||||||
void led_ring_send_command(led_command_t *cmd);
|
void led_ring_send_command(led_command_t *cmd);
|
||||||
void led_ring_init(void);
|
void led_ring_init(void);
|
||||||
|
|
||||||
void led_ring_scale_rgb(uint8_t *r, uint8_t *g, uint8_t *b, uint8_t intensity);
|
|
||||||
|
|
||||||
/** OTA feedback: ring fill 0–100 % with RGB. */
|
|
||||||
void led_ring_show_ota_progress(uint32_t bytes_done, uint32_t total_bytes,
|
|
||||||
uint8_t r, uint8_t g, uint8_t b);
|
|
||||||
void led_ring_show_ota_clear(void);
|
|
||||||
|
|
||||||
/** Single pulse on the full ring (blocking in LED task). */
|
|
||||||
void led_ring_blink_once(uint8_t r, uint8_t g, uint8_t b);
|
|
||||||
void led_ring_ota_success(void);
|
|
||||||
void led_ring_ota_failed(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
#include "ota_espnow.h"
|
#include "ota_espnow.h"
|
||||||
#include "app_config.h"
|
#include "app_config.h"
|
||||||
#include "led_ring.h"
|
|
||||||
#include "client_registry.h"
|
#include "client_registry.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_now_comm.h"
|
#include "esp_now_comm.h"
|
||||||
@ -28,11 +27,6 @@ static const char *TAG = "[OTA_ESPNOW]";
|
|||||||
#define OTA_ST_SUCCESS 4u
|
#define OTA_ST_SUCCESS 4u
|
||||||
#define OTA_ST_FAILED 5u
|
#define OTA_ST_FAILED 5u
|
||||||
|
|
||||||
/** ESP-NOW OTA receive on slave (blue progress bar). */
|
|
||||||
#define OTA_LED_ESPNOW_RX_R 0
|
|
||||||
#define OTA_LED_ESPNOW_RX_G 0
|
|
||||||
#define OTA_LED_ESPNOW_RX_B 255
|
|
||||||
|
|
||||||
#define OTA_MAX_TARGETS CLIENT_REGISTRY_MAX
|
#define OTA_MAX_TARGETS CLIENT_REGISTRY_MAX
|
||||||
|
|
||||||
static EventGroupHandle_t s_eg;
|
static EventGroupHandle_t s_eg;
|
||||||
@ -42,90 +36,10 @@ typedef struct {
|
|||||||
uint8_t mac[OTA_MAX_TARGETS][6];
|
uint8_t mac[OTA_MAX_TARGETS][6];
|
||||||
uint32_t id[OTA_MAX_TARGETS];
|
uint32_t id[OTA_MAX_TARGETS];
|
||||||
uint32_t expected_bytes;
|
uint32_t expected_bytes;
|
||||||
uint32_t total_bytes;
|
|
||||||
ota_espnow_progress_cbs_t progress;
|
|
||||||
} ota_dist_t;
|
} ota_dist_t;
|
||||||
|
|
||||||
static ota_dist_t s_dist;
|
static ota_dist_t s_dist;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t client_id;
|
|
||||||
uint32_t bytes_written;
|
|
||||||
uint32_t status;
|
|
||||||
uint32_t error;
|
|
||||||
} ota_prog_entry_t;
|
|
||||||
|
|
||||||
static struct {
|
|
||||||
bool active;
|
|
||||||
uint32_t total_bytes;
|
|
||||||
uint32_t aggregate_bytes;
|
|
||||||
uint8_t count;
|
|
||||||
ota_prog_entry_t entries[OTA_MAX_TARGETS];
|
|
||||||
} s_prog;
|
|
||||||
|
|
||||||
static void prog_begin(uint32_t total_bytes) {
|
|
||||||
s_prog.active = true;
|
|
||||||
s_prog.total_bytes = total_bytes;
|
|
||||||
s_prog.aggregate_bytes = 0;
|
|
||||||
s_prog.count = s_dist.count;
|
|
||||||
for (uint8_t i = 0; i < s_dist.count; i++) {
|
|
||||||
s_prog.entries[i].client_id = s_dist.id[i];
|
|
||||||
s_prog.entries[i].bytes_written = 0;
|
|
||||||
s_prog.entries[i].status = OTA_ST_PREPARING;
|
|
||||||
s_prog.entries[i].error = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void prog_end(void) { s_prog.active = false; }
|
|
||||||
|
|
||||||
static void prog_set_aggregate(uint32_t bytes_done) {
|
|
||||||
s_prog.aggregate_bytes = bytes_done;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void prog_update_idx(int idx, uint32_t status, uint32_t bytes,
|
|
||||||
uint32_t error) {
|
|
||||||
if (idx < 0 || idx >= (int)s_prog.count) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ota_prog_entry_t *e = &s_prog.entries[idx];
|
|
||||||
e->status = status;
|
|
||||||
if (bytes > e->bytes_written) {
|
|
||||||
e->bytes_written = bytes;
|
|
||||||
}
|
|
||||||
if (error != 0) {
|
|
||||||
e->error = error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ota_espnow_progress_query(uint32_t filter_client_id,
|
|
||||||
alox_OtaSlaveProgressResponse *out) {
|
|
||||||
if (out == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*out = (alox_OtaSlaveProgressResponse)alox_OtaSlaveProgressResponse_init_zero;
|
|
||||||
out->active = s_prog.active;
|
|
||||||
out->total_bytes = s_prog.total_bytes;
|
|
||||||
out->aggregate_bytes = s_prog.aggregate_bytes;
|
|
||||||
out->slave_count = s_prog.count;
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < s_prog.count; i++) {
|
|
||||||
const ota_prog_entry_t *e = &s_prog.entries[i];
|
|
||||||
if (filter_client_id != 0 && e->client_id != filter_client_id) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (out->slaves_count >=
|
|
||||||
sizeof(out->slaves) / sizeof(out->slaves[0])) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
alox_OtaSlaveProgressEntry *dst = &out->slaves[out->slaves_count++];
|
|
||||||
dst->client_id = e->client_id;
|
|
||||||
dst->bytes_written = e->bytes_written;
|
|
||||||
dst->total_bytes = s_prog.total_bytes;
|
|
||||||
dst->status = e->status;
|
|
||||||
dst->error = e->error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int find_target_index(const uint8_t mac[6]) {
|
static int find_target_index(const uint8_t mac[6]) {
|
||||||
for (uint8_t i = 0; i < s_dist.count; i++) {
|
for (uint8_t i = 0; i < s_dist.count; i++) {
|
||||||
if (memcmp(s_dist.mac[i], mac, 6) == 0) {
|
if (memcmp(s_dist.mac[i], mac, 6) == 0) {
|
||||||
@ -176,8 +90,6 @@ static void ota_slave_prepare_task(void *param) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
send_slave_status(master_mac, OTA_ST_READY, 0, 0);
|
send_slave_status(master_mac, OTA_ST_READY, 0, 0);
|
||||||
led_ring_show_ota_progress(0, total_size, OTA_LED_ESPNOW_RX_R, OTA_LED_ESPNOW_RX_G,
|
|
||||||
OTA_LED_ESPNOW_RX_B);
|
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,27 +134,13 @@ void ota_espnow_slave_on_payload(const uint8_t master_mac[6],
|
|||||||
ota_feed_result_t r =
|
ota_feed_result_t r =
|
||||||
ota_uart_feed(payload->data.bytes, payload->data.size);
|
ota_uart_feed(payload->data.bytes, payload->data.size);
|
||||||
if (r == OTA_FEED_ERROR) {
|
if (r == OTA_FEED_ERROR) {
|
||||||
led_ring_ota_failed();
|
|
||||||
send_slave_status(master_mac, OTA_ST_FAILED, ota_uart_bytes_written(), 13);
|
send_slave_status(master_mac, OTA_ST_FAILED, ota_uart_bytes_written(), 13);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (r == OTA_FEED_BLOCK_WRITTEN) {
|
if (r == OTA_FEED_BLOCK_WRITTEN) {
|
||||||
uint32_t written = ota_uart_bytes_written();
|
uint32_t written = ota_uart_bytes_written();
|
||||||
uint32_t total = ota_uart_total_size();
|
|
||||||
ESP_LOGI(TAG, "block written %lu bytes -> ack master", (unsigned long)written);
|
ESP_LOGI(TAG, "block written %lu bytes -> ack master", (unsigned long)written);
|
||||||
led_ring_show_ota_progress(written, total, OTA_LED_ESPNOW_RX_R, OTA_LED_ESPNOW_RX_G,
|
|
||||||
OTA_LED_ESPNOW_RX_B);
|
|
||||||
send_slave_status(master_mac, OTA_ST_BLOCK_ACK, written, 0);
|
send_slave_status(master_mac, OTA_ST_BLOCK_ACK, written, 0);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r == OTA_FEED_OK) {
|
|
||||||
uint32_t total = ota_uart_total_size();
|
|
||||||
if (total > 0) {
|
|
||||||
led_ring_show_ota_progress(ota_uart_bytes_received(), total,
|
|
||||||
OTA_LED_ESPNOW_RX_R, OTA_LED_ESPNOW_RX_G,
|
|
||||||
OTA_LED_ESPNOW_RX_B);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,13 +155,11 @@ void ota_espnow_slave_on_end(const uint8_t master_mac[6]) {
|
|||||||
bool success = false;
|
bool success = false;
|
||||||
esp_err_t err = ota_uart_finish(true, &success);
|
esp_err_t err = ota_uart_finish(true, &success);
|
||||||
if (err != ESP_OK || !success) {
|
if (err != ESP_OK || !success) {
|
||||||
led_ring_ota_failed();
|
|
||||||
send_slave_status(master_mac, OTA_ST_FAILED, written, (uint32_t)err);
|
send_slave_status(master_mac, OTA_ST_FAILED, written, (uint32_t)err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
send_slave_status(master_mac, OTA_ST_SUCCESS, written, 0);
|
send_slave_status(master_mac, OTA_ST_SUCCESS, written, 0);
|
||||||
led_ring_ota_success();
|
|
||||||
ESP_LOGI(TAG, "slave OTA success (%lu bytes), reboot to run",
|
ESP_LOGI(TAG, "slave OTA success (%lu bytes), reboot to run",
|
||||||
(unsigned long)written);
|
(unsigned long)written);
|
||||||
}
|
}
|
||||||
@ -283,15 +179,9 @@ void ota_espnow_master_on_status(const uint8_t slave_mac[6],
|
|||||||
|
|
||||||
switch (status->status) {
|
switch (status->status) {
|
||||||
case OTA_ST_READY:
|
case OTA_ST_READY:
|
||||||
prog_update_idx(idx, OTA_ST_READY, 0, 0);
|
|
||||||
xEventGroupSetBits(s_eg, bit);
|
xEventGroupSetBits(s_eg, bit);
|
||||||
break;
|
break;
|
||||||
case OTA_ST_BLOCK_ACK:
|
case OTA_ST_BLOCK_ACK:
|
||||||
prog_update_idx(idx, OTA_ST_BLOCK_ACK, status->bytes_written, 0);
|
|
||||||
if (s_dist.progress.per_slave != NULL) {
|
|
||||||
s_dist.progress.per_slave(s_dist.id[idx], status->bytes_written,
|
|
||||||
s_dist.total_bytes);
|
|
||||||
}
|
|
||||||
if (status->bytes_written >= s_dist.expected_bytes) {
|
if (status->bytes_written >= s_dist.expected_bytes) {
|
||||||
xEventGroupSetBits(s_eg, bit);
|
xEventGroupSetBits(s_eg, bit);
|
||||||
} else {
|
} else {
|
||||||
@ -301,12 +191,9 @@ void ota_espnow_master_on_status(const uint8_t slave_mac[6],
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OTA_ST_SUCCESS:
|
case OTA_ST_SUCCESS:
|
||||||
prog_update_idx(idx, OTA_ST_SUCCESS, status->bytes_written, 0);
|
|
||||||
xEventGroupSetBits(s_eg, bit);
|
xEventGroupSetBits(s_eg, bit);
|
||||||
break;
|
break;
|
||||||
case OTA_ST_FAILED:
|
case OTA_ST_FAILED:
|
||||||
prog_update_idx(idx, OTA_ST_FAILED, status->bytes_written,
|
|
||||||
status->error);
|
|
||||||
ESP_LOGW(TAG, "slave %lu OTA failed (err=%lu)",
|
ESP_LOGW(TAG, "slave %lu OTA failed (err=%lu)",
|
||||||
(unsigned long)s_dist.id[idx], (unsigned long)status->error);
|
(unsigned long)s_dist.id[idx], (unsigned long)status->error);
|
||||||
break;
|
break;
|
||||||
@ -333,8 +220,7 @@ static size_t collect_targets(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t distribute_image(const esp_partition_t *partition,
|
static esp_err_t distribute_image(const esp_partition_t *partition,
|
||||||
uint32_t size,
|
uint32_t size) {
|
||||||
const ota_espnow_progress_cbs_t *progress) {
|
|
||||||
if (s_eg == NULL) {
|
if (s_eg == NULL) {
|
||||||
s_eg = xEventGroupCreate();
|
s_eg = xEventGroupCreate();
|
||||||
if (s_eg == NULL) {
|
if (s_eg == NULL) {
|
||||||
@ -342,13 +228,6 @@ static esp_err_t distribute_image(const esp_partition_t *partition,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&s_dist.progress, 0, sizeof(s_dist.progress));
|
|
||||||
if (progress != NULL) {
|
|
||||||
s_dist.progress = *progress;
|
|
||||||
}
|
|
||||||
s_dist.total_bytes = size;
|
|
||||||
prog_begin(size);
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "distributing %lu bytes from %s to %u slave(s)",
|
ESP_LOGI(TAG, "distributing %lu bytes from %s to %u slave(s)",
|
||||||
(unsigned long)size, partition->label, (unsigned)s_dist.count);
|
(unsigned long)size, partition->label, (unsigned)s_dist.count);
|
||||||
|
|
||||||
@ -361,22 +240,15 @@ static esp_err_t distribute_image(const esp_partition_t *partition,
|
|||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGW(TAG, "OTA_START to slave %lu failed",
|
ESP_LOGW(TAG, "OTA_START to slave %lu failed",
|
||||||
(unsigned long)s_dist.id[i]);
|
(unsigned long)s_dist.id[i]);
|
||||||
prog_end();
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wait_target_bits(target_mask, OTA_PREPARE_TIMEOUT_MS)) {
|
if (!wait_target_bits(target_mask, OTA_PREPARE_TIMEOUT_MS)) {
|
||||||
ESP_LOGE(TAG, "timeout waiting for slave OTA ready");
|
ESP_LOGE(TAG, "timeout waiting for slave OTA ready");
|
||||||
prog_end();
|
|
||||||
return ESP_ERR_TIMEOUT;
|
return ESP_ERR_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
prog_set_aggregate(0);
|
|
||||||
if (s_dist.progress.aggregate != NULL) {
|
|
||||||
s_dist.progress.aggregate(0, size, s_dist.count);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t block_buf[OTA_UART_FLASH_BLOCK_SIZE];
|
uint8_t block_buf[OTA_UART_FLASH_BLOCK_SIZE];
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
uint32_t seq = 0;
|
uint32_t seq = 0;
|
||||||
@ -391,7 +263,6 @@ static esp_err_t distribute_image(const esp_partition_t *partition,
|
|||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "partition read @%lu failed: %s", (unsigned long)offset,
|
ESP_LOGE(TAG, "partition read @%lu failed: %s", (unsigned long)offset,
|
||||||
esp_err_to_name(err));
|
esp_err_to_name(err));
|
||||||
prog_end();
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,7 +277,6 @@ static esp_err_t distribute_image(const esp_partition_t *partition,
|
|||||||
err = esp_now_comm_send_ota_payload(s_dist.mac[i], seq,
|
err = esp_now_comm_send_ota_payload(s_dist.mac[i], seq,
|
||||||
block_buf + sent, chunk);
|
block_buf + sent, chunk);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
prog_end();
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -423,7 +293,6 @@ static esp_err_t distribute_image(const esp_partition_t *partition,
|
|||||||
if (!wait_target_bits(target_mask, OTA_BLOCK_TIMEOUT_MS)) {
|
if (!wait_target_bits(target_mask, OTA_BLOCK_TIMEOUT_MS)) {
|
||||||
ESP_LOGE(TAG, "timeout block ack @%lu bytes",
|
ESP_LOGE(TAG, "timeout block ack @%lu bytes",
|
||||||
(unsigned long)s_dist.expected_bytes);
|
(unsigned long)s_dist.expected_bytes);
|
||||||
prog_end();
|
|
||||||
return ESP_ERR_TIMEOUT;
|
return ESP_ERR_TIMEOUT;
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "block ack @%lu/%lu (%lu%%)",
|
ESP_LOGI(TAG, "block ack @%lu/%lu (%lu%%)",
|
||||||
@ -434,48 +303,34 @@ static esp_err_t distribute_image(const esp_partition_t *partition,
|
|||||||
(unsigned long)block_len);
|
(unsigned long)block_len);
|
||||||
}
|
}
|
||||||
offset += block_len;
|
offset += block_len;
|
||||||
prog_set_aggregate(offset);
|
|
||||||
if (s_dist.progress.aggregate != NULL) {
|
|
||||||
s_dist.progress.aggregate(offset, size, s_dist.count);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xEventGroupClearBits(s_eg, target_mask);
|
xEventGroupClearBits(s_eg, target_mask);
|
||||||
for (uint8_t i = 0; i < s_dist.count; i++) {
|
for (uint8_t i = 0; i < s_dist.count; i++) {
|
||||||
err = esp_now_comm_send_ota_end(s_dist.mac[i]);
|
err = esp_now_comm_send_ota_end(s_dist.mac[i]);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
prog_end();
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wait_target_bits(target_mask, OTA_END_TIMEOUT_MS)) {
|
if (!wait_target_bits(target_mask, OTA_END_TIMEOUT_MS)) {
|
||||||
ESP_LOGE(TAG, "timeout waiting for slave OTA success");
|
ESP_LOGE(TAG, "timeout waiting for slave OTA success");
|
||||||
prog_end();
|
|
||||||
return ESP_ERR_TIMEOUT;
|
return ESP_ERR_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
prog_set_aggregate(size);
|
|
||||||
prog_end();
|
|
||||||
ESP_LOGI(TAG, "ESP-NOW OTA complete for %u slave(s)", (unsigned)s_dist.count);
|
ESP_LOGI(TAG, "ESP-NOW OTA complete for %u slave(s)", (unsigned)s_dist.count);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t ota_espnow_distribute(const esp_partition_t *partition, uint32_t size,
|
esp_err_t ota_espnow_distribute(const esp_partition_t *partition, uint32_t size) {
|
||||||
const ota_espnow_progress_cbs_t *progress) {
|
|
||||||
if (partition == NULL || size == 0) {
|
if (partition == NULL || size == 0) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collect_targets() == 0) {
|
if (collect_targets() == 0) {
|
||||||
ESP_LOGI(TAG, "no available slaves — skip ESP-NOW OTA");
|
ESP_LOGI(TAG, "no available slaves — skip ESP-NOW OTA");
|
||||||
memset(&s_prog, 0, sizeof(s_prog));
|
|
||||||
s_prog.total_bytes = size;
|
|
||||||
if (progress != NULL && progress->aggregate != NULL) {
|
|
||||||
progress->aggregate(size, size, 0);
|
|
||||||
}
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return distribute_image(partition, size, progress);
|
return distribute_image(partition, size);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,20 +4,10 @@
|
|||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_now_messages.pb.h"
|
#include "esp_now_messages.pb.h"
|
||||||
#include "esp_partition.h"
|
#include "esp_partition.h"
|
||||||
#include "uart_messages.pb.h"
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/** bytes_done, total_bytes, number of slaves targeted. */
|
|
||||||
void (*aggregate)(uint32_t bytes_done, uint32_t total_bytes,
|
|
||||||
uint8_t slave_count);
|
|
||||||
/** Per-slave block ACK (slave_id, bytes_written on that slave, total_bytes). */
|
|
||||||
void (*per_slave)(uint32_t slave_id, uint32_t bytes_done, uint32_t total_bytes);
|
|
||||||
} ota_espnow_progress_cbs_t;
|
|
||||||
|
|
||||||
/** Master: read staged image from partition and push to all available slaves. */
|
/** Master: read staged image from partition and push to all available slaves. */
|
||||||
esp_err_t ota_espnow_distribute(const esp_partition_t *partition, uint32_t size,
|
esp_err_t ota_espnow_distribute(const esp_partition_t *partition, uint32_t size);
|
||||||
const ota_espnow_progress_cbs_t *progress);
|
|
||||||
|
|
||||||
/** Master: handle slave → master OTA status / block ACK. */
|
/** Master: handle slave → master OTA status / block ACK. */
|
||||||
void ota_espnow_master_on_status(const uint8_t slave_mac[6],
|
void ota_espnow_master_on_status(const uint8_t slave_mac[6],
|
||||||
@ -30,11 +20,4 @@ void ota_espnow_slave_on_payload(const uint8_t master_mac[6],
|
|||||||
const alox_EspNowOtaPayload *payload);
|
const alox_EspNowOtaPayload *payload);
|
||||||
void ota_espnow_slave_on_end(const uint8_t master_mac[6]);
|
void ota_espnow_slave_on_end(const uint8_t master_mac[6]);
|
||||||
|
|
||||||
/**
|
|
||||||
* Fill UART OtaSlaveProgressResponse from tracked per-slave state.
|
|
||||||
* filter_client_id 0 = all slaves in the last/current distribution session.
|
|
||||||
*/
|
|
||||||
void ota_espnow_progress_query(uint32_t filter_client_id,
|
|
||||||
alox_OtaSlaveProgressResponse *out);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -151,10 +151,6 @@ ota_feed_result_t ota_uart_feed(const uint8_t *data, size_t len) {
|
|||||||
|
|
||||||
uint32_t ota_uart_bytes_written(void) { return s_ota.written; }
|
uint32_t ota_uart_bytes_written(void) { return s_ota.written; }
|
||||||
|
|
||||||
uint32_t ota_uart_bytes_received(void) { return s_ota.received; }
|
|
||||||
|
|
||||||
uint32_t ota_uart_total_size(void) { return s_ota.active ? s_ota.total_size : 0; }
|
|
||||||
|
|
||||||
bool ota_uart_get_staged_image(const esp_partition_t **partition_out,
|
bool ota_uart_get_staged_image(const esp_partition_t **partition_out,
|
||||||
uint32_t *size_out) {
|
uint32_t *size_out) {
|
||||||
if (!s_staged.valid || s_staged.partition == NULL) {
|
if (!s_staged.valid || s_staged.partition == NULL) {
|
||||||
|
|||||||
@ -17,14 +17,8 @@ typedef enum {
|
|||||||
OTA_UART_ST_BLOCK_ACK = 3,
|
OTA_UART_ST_BLOCK_ACK = 3,
|
||||||
OTA_UART_ST_SUCCESS = 4,
|
OTA_UART_ST_SUCCESS = 4,
|
||||||
OTA_UART_ST_FAILED = 5,
|
OTA_UART_ST_FAILED = 5,
|
||||||
/** ESP-NOW slave distribution in progress (see OTA_DIST_* in cmd_ota.c). */
|
|
||||||
OTA_UART_ST_DISTRIBUTING = 6,
|
|
||||||
} ota_uart_status_t;
|
} ota_uart_status_t;
|
||||||
|
|
||||||
/** OtaStatusPayload.error when status == OTA_UART_ST_DISTRIBUTING. */
|
|
||||||
#define OTA_DIST_AGGREGATE 0u
|
|
||||||
#define OTA_DIST_PER_SLAVE 1u
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OTA_FEED_OK = 0,
|
OTA_FEED_OK = 0,
|
||||||
OTA_FEED_BLOCK_WRITTEN,
|
OTA_FEED_BLOCK_WRITTEN,
|
||||||
@ -46,12 +40,6 @@ ota_feed_result_t ota_uart_feed(const uint8_t *data, size_t len);
|
|||||||
|
|
||||||
uint32_t ota_uart_bytes_written(void);
|
uint32_t ota_uart_bytes_written(void);
|
||||||
|
|
||||||
/** Bytes accepted in the current session (includes buffered block). */
|
|
||||||
uint32_t ota_uart_bytes_received(void);
|
|
||||||
|
|
||||||
/** Image size from OTA_START / ESP-NOW OTA_START; 0 if inactive. */
|
|
||||||
uint32_t ota_uart_total_size(void);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flush remainder and esp_ota_end. When set_boot is false, the staged image
|
* Flush remainder and esp_ota_end. When set_boot is false, the staged image
|
||||||
* remains readable via ota_uart_get_staged_image() until ota_uart_apply_boot().
|
* remains readable via ota_uart_get_staged_image() until ota_uart_apply_boot().
|
||||||
|
|||||||
@ -5,8 +5,6 @@
|
|||||||
#include "cmd_client_info.h"
|
#include "cmd_client_info.h"
|
||||||
#include "cmd_version.h"
|
#include "cmd_version.h"
|
||||||
#include "cmd_ota.h"
|
#include "cmd_ota.h"
|
||||||
#include "cmd_ota_slave_progress.h"
|
|
||||||
#include "cmd_led_ring.h"
|
|
||||||
#include "esp_now_comm.h"
|
#include "esp_now_comm.h"
|
||||||
#include "powerpod.h"
|
#include "powerpod.h"
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
@ -169,13 +167,19 @@ void app_main(void) {
|
|||||||
cmd_client_info_register();
|
cmd_client_info_register();
|
||||||
cmd_accel_deadzone_register();
|
cmd_accel_deadzone_register();
|
||||||
cmd_espnow_unicast_test_register();
|
cmd_espnow_unicast_test_register();
|
||||||
cmd_led_ring_register();
|
|
||||||
cmd_ota_register();
|
cmd_ota_register();
|
||||||
cmd_ota_slave_progress_register();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "LED ring: UART LED_RING commands only (no local demo loop)");
|
uint8_t current_digit = 10;
|
||||||
while (1) {
|
while (1) {
|
||||||
vTaskDelay(portMAX_DELAY);
|
led_command_t cmd = {.mode = LED_CMD_SET_DIGIT,
|
||||||
|
.value = current_digit,
|
||||||
|
.r = 5,
|
||||||
|
.g = 5,
|
||||||
|
.b = 0};
|
||||||
|
|
||||||
|
led_ring_send_command(&cmd);
|
||||||
|
current_digit = (current_digit + 1) % 11;
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
#error Regenerate this file with the current version of nanopb generator.
|
#error Regenerate this file with the current version of nanopb generator.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PB_BIND(alox_UartMessage, alox_UartMessage, 2)
|
PB_BIND(alox_UartMessage, alox_UartMessage, AUTO)
|
||||||
|
|
||||||
|
|
||||||
PB_BIND(alox_Ack, alox_Ack, AUTO)
|
PB_BIND(alox_Ack, alox_Ack, AUTO)
|
||||||
@ -42,12 +42,6 @@ PB_BIND(alox_EspNowUnicastTestRequest, alox_EspNowUnicastTestRequest, AUTO)
|
|||||||
PB_BIND(alox_EspNowUnicastTestResponse, alox_EspNowUnicastTestResponse, AUTO)
|
PB_BIND(alox_EspNowUnicastTestResponse, alox_EspNowUnicastTestResponse, AUTO)
|
||||||
|
|
||||||
|
|
||||||
PB_BIND(alox_LedRingProgressRequest, alox_LedRingProgressRequest, AUTO)
|
|
||||||
|
|
||||||
|
|
||||||
PB_BIND(alox_LedRingProgressResponse, alox_LedRingProgressResponse, AUTO)
|
|
||||||
|
|
||||||
|
|
||||||
PB_BIND(alox_OtaStartPayload, alox_OtaStartPayload, AUTO)
|
PB_BIND(alox_OtaStartPayload, alox_OtaStartPayload, AUTO)
|
||||||
|
|
||||||
|
|
||||||
@ -60,15 +54,6 @@ PB_BIND(alox_OtaEndPayload, alox_OtaEndPayload, AUTO)
|
|||||||
PB_BIND(alox_OtaStatusPayload, alox_OtaStatusPayload, AUTO)
|
PB_BIND(alox_OtaStatusPayload, alox_OtaStatusPayload, AUTO)
|
||||||
|
|
||||||
|
|
||||||
PB_BIND(alox_OtaSlaveProgressRequest, alox_OtaSlaveProgressRequest, AUTO)
|
|
||||||
|
|
||||||
|
|
||||||
PB_BIND(alox_OtaSlaveProgressEntry, alox_OtaSlaveProgressEntry, AUTO)
|
|
||||||
|
|
||||||
|
|
||||||
PB_BIND(alox_OtaSlaveProgressResponse, alox_OtaSlaveProgressResponse, 2)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
/* Automatically generated nanopb header */
|
/* Automatically generated nanopb header */
|
||||||
/* Generated by nanopb-1.0.0-dev */
|
/* Generated by nanopb-1.0.0-dev */
|
||||||
|
|
||||||
#ifndef PB_ALOX_UART_MESSAGES_PB_H_INCLUDED
|
#ifndef PB_ALOX_MAIN_PROTO_UART_MESSAGES_PB_H_INCLUDED
|
||||||
#define PB_ALOX_UART_MESSAGES_PB_H_INCLUDED
|
#define PB_ALOX_MAIN_PROTO_UART_MESSAGES_PB_H_INCLUDED
|
||||||
#include <pb.h>
|
#include <pb.h>
|
||||||
|
|
||||||
#if PB_PROTO_HEADER_VERSION != 40
|
#if PB_PROTO_HEADER_VERSION != 40
|
||||||
@ -19,13 +19,11 @@ typedef enum _alox_MessageType {
|
|||||||
alox_MessageType_CLIENT_INPUT = 5,
|
alox_MessageType_CLIENT_INPUT = 5,
|
||||||
alox_MessageType_ACCEL_DEADZONE = 6,
|
alox_MessageType_ACCEL_DEADZONE = 6,
|
||||||
alox_MessageType_ESPNOW_UNICAST_TEST = 7,
|
alox_MessageType_ESPNOW_UNICAST_TEST = 7,
|
||||||
alox_MessageType_LED_RING = 8,
|
|
||||||
alox_MessageType_OTA_START = 16,
|
alox_MessageType_OTA_START = 16,
|
||||||
alox_MessageType_OTA_PAYLOAD = 17,
|
alox_MessageType_OTA_PAYLOAD = 17,
|
||||||
alox_MessageType_OTA_END = 18,
|
alox_MessageType_OTA_END = 18,
|
||||||
alox_MessageType_OTA_STATUS = 19,
|
alox_MessageType_OTA_STATUS = 19,
|
||||||
alox_MessageType_OTA_START_ESPNOW = 20,
|
alox_MessageType_OTA_START_ESPNOW = 20
|
||||||
alox_MessageType_OTA_SLAVE_PROGRESS = 21
|
|
||||||
} alox_MessageType;
|
} alox_MessageType;
|
||||||
|
|
||||||
/* Struct definitions */
|
/* Struct definitions */
|
||||||
@ -96,39 +94,13 @@ typedef struct _alox_EspNowUnicastTestResponse {
|
|||||||
uint32_t seq;
|
uint32_t seq;
|
||||||
} alox_EspNowUnicastTestResponse;
|
} alox_EspNowUnicastTestResponse;
|
||||||
|
|
||||||
/* Host → device: LED ring display (progress bar, digit, clear, or blink).
|
|
||||||
mode: 0=clear, 1=progress (0–100 %), 2=digit (0–10), 3=blink full ring. */
|
|
||||||
typedef struct _alox_LedRingProgressRequest {
|
|
||||||
uint32_t mode;
|
|
||||||
/* * 0–100: fraction of ring LEDs to light (mode=progress) */
|
|
||||||
uint32_t progress;
|
|
||||||
/* * 0–10 (mode=digit) */
|
|
||||||
uint32_t digit;
|
|
||||||
uint32_t r;
|
|
||||||
uint32_t g;
|
|
||||||
uint32_t b;
|
|
||||||
/* * 0–255 brightness scale; 0 = firmware default (~5 %) */
|
|
||||||
uint32_t intensity;
|
|
||||||
/* * Pulse length in ms (mode=blink, default 350) */
|
|
||||||
uint32_t blink_ms;
|
|
||||||
/* * Number of pulses (mode=blink, default 1) */
|
|
||||||
uint32_t blink_count;
|
|
||||||
} alox_LedRingProgressRequest;
|
|
||||||
|
|
||||||
typedef struct _alox_LedRingProgressResponse {
|
|
||||||
bool success;
|
|
||||||
uint32_t mode;
|
|
||||||
uint32_t progress;
|
|
||||||
uint32_t digit;
|
|
||||||
} alox_LedRingProgressResponse;
|
|
||||||
|
|
||||||
/* Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS). */
|
/* Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS). */
|
||||||
typedef struct _alox_OtaStartPayload {
|
typedef struct _alox_OtaStartPayload {
|
||||||
uint32_t total_size;
|
uint32_t total_size;
|
||||||
} alox_OtaStartPayload;
|
} alox_OtaStartPayload;
|
||||||
|
|
||||||
typedef PB_BYTES_ARRAY_T(200) alox_OtaPayload_data_t;
|
|
||||||
/* Host → device: firmware chunk (up to 200 bytes); device buffers 4 KiB before flash write. */
|
/* Host → device: firmware chunk (up to 200 bytes); device buffers 4 KiB before flash write. */
|
||||||
|
typedef PB_BYTES_ARRAY_T(200) alox_OtaPayload_data_t;
|
||||||
typedef struct _alox_OtaPayload {
|
typedef struct _alox_OtaPayload {
|
||||||
uint32_t seq;
|
uint32_t seq;
|
||||||
alox_OtaPayload_data_t data;
|
alox_OtaPayload_data_t data;
|
||||||
@ -140,7 +112,7 @@ typedef struct _alox_OtaEndPayload {
|
|||||||
} alox_OtaEndPayload;
|
} alox_OtaEndPayload;
|
||||||
|
|
||||||
/* Device → host status (also used as ACK after each 4 KiB written).
|
/* Device → host status (also used as ACK after each 4 KiB written).
|
||||||
status: 1=preparing, 2=ready, 3=block_ack, 4=success, 5=failed, 6=distributing */
|
status: 1=preparing, 2=ready, 3=block_ack, 4=success, 5=failed */
|
||||||
typedef struct _alox_OtaStatusPayload {
|
typedef struct _alox_OtaStatusPayload {
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
uint32_t bytes_written;
|
uint32_t bytes_written;
|
||||||
@ -148,29 +120,6 @@ typedef struct _alox_OtaStatusPayload {
|
|||||||
uint32_t error;
|
uint32_t error;
|
||||||
} alox_OtaStatusPayload;
|
} alox_OtaStatusPayload;
|
||||||
|
|
||||||
/* Host → master: query ESP-NOW slave OTA progress (client_id 0 = all slaves in session). */
|
|
||||||
typedef struct _alox_OtaSlaveProgressRequest {
|
|
||||||
uint32_t client_id;
|
|
||||||
} alox_OtaSlaveProgressRequest;
|
|
||||||
|
|
||||||
typedef struct _alox_OtaSlaveProgressEntry {
|
|
||||||
uint32_t client_id;
|
|
||||||
uint32_t bytes_written;
|
|
||||||
uint32_t total_bytes;
|
|
||||||
/* * 0=idle, 1=preparing, 2=ready, 3=distributing, 4=success, 5=failed */
|
|
||||||
uint32_t status;
|
|
||||||
uint32_t error;
|
|
||||||
} alox_OtaSlaveProgressEntry;
|
|
||||||
|
|
||||||
typedef struct _alox_OtaSlaveProgressResponse {
|
|
||||||
bool active;
|
|
||||||
uint32_t total_bytes;
|
|
||||||
uint32_t aggregate_bytes;
|
|
||||||
uint32_t slave_count;
|
|
||||||
pb_size_t slaves_count;
|
|
||||||
alox_OtaSlaveProgressEntry slaves[16];
|
|
||||||
} alox_OtaSlaveProgressResponse;
|
|
||||||
|
|
||||||
typedef struct _alox_UartMessage {
|
typedef struct _alox_UartMessage {
|
||||||
alox_MessageType type;
|
alox_MessageType type;
|
||||||
pb_size_t which_payload;
|
pb_size_t which_payload;
|
||||||
@ -188,10 +137,6 @@ typedef struct _alox_UartMessage {
|
|||||||
alox_AccelDeadzoneResponse accel_deadzone_response;
|
alox_AccelDeadzoneResponse accel_deadzone_response;
|
||||||
alox_EspNowUnicastTestRequest espnow_unicast_test_request;
|
alox_EspNowUnicastTestRequest espnow_unicast_test_request;
|
||||||
alox_EspNowUnicastTestResponse espnow_unicast_test_response;
|
alox_EspNowUnicastTestResponse espnow_unicast_test_response;
|
||||||
alox_OtaSlaveProgressRequest ota_slave_progress_request;
|
|
||||||
alox_OtaSlaveProgressResponse ota_slave_progress_response;
|
|
||||||
alox_LedRingProgressRequest led_ring_progress_request;
|
|
||||||
alox_LedRingProgressResponse led_ring_progress_response;
|
|
||||||
} payload;
|
} payload;
|
||||||
} alox_UartMessage;
|
} alox_UartMessage;
|
||||||
|
|
||||||
@ -202,8 +147,8 @@ extern "C" {
|
|||||||
|
|
||||||
/* Helper constants for enums */
|
/* Helper constants for enums */
|
||||||
#define _alox_MessageType_MIN alox_MessageType_UNKNOWN
|
#define _alox_MessageType_MIN alox_MessageType_UNKNOWN
|
||||||
#define _alox_MessageType_MAX alox_MessageType_OTA_SLAVE_PROGRESS
|
#define _alox_MessageType_MAX alox_MessageType_OTA_START_ESPNOW
|
||||||
#define _alox_MessageType_ARRAYSIZE ((alox_MessageType)(alox_MessageType_OTA_SLAVE_PROGRESS+1))
|
#define _alox_MessageType_ARRAYSIZE ((alox_MessageType)(alox_MessageType_OTA_START_ESPNOW+1))
|
||||||
|
|
||||||
#define alox_UartMessage_type_ENUMTYPE alox_MessageType
|
#define alox_UartMessage_type_ENUMTYPE alox_MessageType
|
||||||
|
|
||||||
@ -221,11 +166,6 @@ extern "C" {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Initializer values for message structs */
|
/* Initializer values for message structs */
|
||||||
@ -241,15 +181,10 @@ extern "C" {
|
|||||||
#define alox_AccelDeadzoneResponse_init_default {0, 0, 0, 0}
|
#define alox_AccelDeadzoneResponse_init_default {0, 0, 0, 0}
|
||||||
#define alox_EspNowUnicastTestRequest_init_default {0, 0}
|
#define alox_EspNowUnicastTestRequest_init_default {0, 0}
|
||||||
#define alox_EspNowUnicastTestResponse_init_default {0, 0}
|
#define alox_EspNowUnicastTestResponse_init_default {0, 0}
|
||||||
#define alox_LedRingProgressRequest_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
|
||||||
#define alox_LedRingProgressResponse_init_default {0, 0, 0, 0}
|
|
||||||
#define alox_OtaStartPayload_init_default {0}
|
#define alox_OtaStartPayload_init_default {0}
|
||||||
#define alox_OtaPayload_init_default {0, {0, {0}}}
|
#define alox_OtaPayload_init_default {0, {0, {0}}}
|
||||||
#define alox_OtaEndPayload_init_default {0}
|
#define alox_OtaEndPayload_init_default {0}
|
||||||
#define alox_OtaStatusPayload_init_default {0, 0, 0, 0}
|
#define alox_OtaStatusPayload_init_default {0, 0, 0, 0}
|
||||||
#define alox_OtaSlaveProgressRequest_init_default {0}
|
|
||||||
#define alox_OtaSlaveProgressEntry_init_default {0, 0, 0, 0, 0}
|
|
||||||
#define alox_OtaSlaveProgressResponse_init_default {0, 0, 0, 0, 0, {alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default}}
|
|
||||||
#define alox_UartMessage_init_zero {_alox_MessageType_MIN, 0, {alox_Ack_init_zero}}
|
#define alox_UartMessage_init_zero {_alox_MessageType_MIN, 0, {alox_Ack_init_zero}}
|
||||||
#define alox_Ack_init_zero {0}
|
#define alox_Ack_init_zero {0}
|
||||||
#define alox_EchoPayload_init_zero {{{NULL}, NULL}}
|
#define alox_EchoPayload_init_zero {{{NULL}, NULL}}
|
||||||
@ -262,15 +197,10 @@ extern "C" {
|
|||||||
#define alox_AccelDeadzoneResponse_init_zero {0, 0, 0, 0}
|
#define alox_AccelDeadzoneResponse_init_zero {0, 0, 0, 0}
|
||||||
#define alox_EspNowUnicastTestRequest_init_zero {0, 0}
|
#define alox_EspNowUnicastTestRequest_init_zero {0, 0}
|
||||||
#define alox_EspNowUnicastTestResponse_init_zero {0, 0}
|
#define alox_EspNowUnicastTestResponse_init_zero {0, 0}
|
||||||
#define alox_LedRingProgressRequest_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
|
||||||
#define alox_LedRingProgressResponse_init_zero {0, 0, 0, 0}
|
|
||||||
#define alox_OtaStartPayload_init_zero {0}
|
#define alox_OtaStartPayload_init_zero {0}
|
||||||
#define alox_OtaPayload_init_zero {0, {0, {0}}}
|
#define alox_OtaPayload_init_zero {0, {0, {0}}}
|
||||||
#define alox_OtaEndPayload_init_zero {0}
|
#define alox_OtaEndPayload_init_zero {0}
|
||||||
#define alox_OtaStatusPayload_init_zero {0, 0, 0, 0}
|
#define alox_OtaStatusPayload_init_zero {0, 0, 0, 0}
|
||||||
#define alox_OtaSlaveProgressRequest_init_zero {0}
|
|
||||||
#define alox_OtaSlaveProgressEntry_init_zero {0, 0, 0, 0, 0}
|
|
||||||
#define alox_OtaSlaveProgressResponse_init_zero {0, 0, 0, 0, 0, {alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero}}
|
|
||||||
|
|
||||||
/* Field tags (for use in manual encoding/decoding) */
|
/* Field tags (for use in manual encoding/decoding) */
|
||||||
#define alox_EchoPayload_data_tag 1
|
#define alox_EchoPayload_data_tag 1
|
||||||
@ -302,19 +232,6 @@ extern "C" {
|
|||||||
#define alox_EspNowUnicastTestRequest_seq_tag 2
|
#define alox_EspNowUnicastTestRequest_seq_tag 2
|
||||||
#define alox_EspNowUnicastTestResponse_success_tag 1
|
#define alox_EspNowUnicastTestResponse_success_tag 1
|
||||||
#define alox_EspNowUnicastTestResponse_seq_tag 2
|
#define alox_EspNowUnicastTestResponse_seq_tag 2
|
||||||
#define alox_LedRingProgressRequest_mode_tag 1
|
|
||||||
#define alox_LedRingProgressRequest_progress_tag 2
|
|
||||||
#define alox_LedRingProgressRequest_digit_tag 3
|
|
||||||
#define alox_LedRingProgressRequest_r_tag 4
|
|
||||||
#define alox_LedRingProgressRequest_g_tag 5
|
|
||||||
#define alox_LedRingProgressRequest_b_tag 6
|
|
||||||
#define alox_LedRingProgressRequest_intensity_tag 7
|
|
||||||
#define alox_LedRingProgressRequest_blink_ms_tag 8
|
|
||||||
#define alox_LedRingProgressRequest_blink_count_tag 9
|
|
||||||
#define alox_LedRingProgressResponse_success_tag 1
|
|
||||||
#define alox_LedRingProgressResponse_mode_tag 2
|
|
||||||
#define alox_LedRingProgressResponse_progress_tag 3
|
|
||||||
#define alox_LedRingProgressResponse_digit_tag 4
|
|
||||||
#define alox_OtaStartPayload_total_size_tag 1
|
#define alox_OtaStartPayload_total_size_tag 1
|
||||||
#define alox_OtaPayload_seq_tag 1
|
#define alox_OtaPayload_seq_tag 1
|
||||||
#define alox_OtaPayload_data_tag 2
|
#define alox_OtaPayload_data_tag 2
|
||||||
@ -322,17 +239,6 @@ extern "C" {
|
|||||||
#define alox_OtaStatusPayload_bytes_written_tag 2
|
#define alox_OtaStatusPayload_bytes_written_tag 2
|
||||||
#define alox_OtaStatusPayload_target_slot_tag 3
|
#define alox_OtaStatusPayload_target_slot_tag 3
|
||||||
#define alox_OtaStatusPayload_error_tag 4
|
#define alox_OtaStatusPayload_error_tag 4
|
||||||
#define alox_OtaSlaveProgressRequest_client_id_tag 1
|
|
||||||
#define alox_OtaSlaveProgressEntry_client_id_tag 1
|
|
||||||
#define alox_OtaSlaveProgressEntry_bytes_written_tag 2
|
|
||||||
#define alox_OtaSlaveProgressEntry_total_bytes_tag 3
|
|
||||||
#define alox_OtaSlaveProgressEntry_status_tag 4
|
|
||||||
#define alox_OtaSlaveProgressEntry_error_tag 5
|
|
||||||
#define alox_OtaSlaveProgressResponse_active_tag 1
|
|
||||||
#define alox_OtaSlaveProgressResponse_total_bytes_tag 2
|
|
||||||
#define alox_OtaSlaveProgressResponse_aggregate_bytes_tag 3
|
|
||||||
#define alox_OtaSlaveProgressResponse_slave_count_tag 4
|
|
||||||
#define alox_OtaSlaveProgressResponse_slaves_tag 5
|
|
||||||
#define alox_UartMessage_type_tag 1
|
#define alox_UartMessage_type_tag 1
|
||||||
#define alox_UartMessage_ack_payload_tag 2
|
#define alox_UartMessage_ack_payload_tag 2
|
||||||
#define alox_UartMessage_echo_payload_tag 3
|
#define alox_UartMessage_echo_payload_tag 3
|
||||||
@ -347,10 +253,6 @@ extern "C" {
|
|||||||
#define alox_UartMessage_accel_deadzone_response_tag 12
|
#define alox_UartMessage_accel_deadzone_response_tag 12
|
||||||
#define alox_UartMessage_espnow_unicast_test_request_tag 13
|
#define alox_UartMessage_espnow_unicast_test_request_tag 13
|
||||||
#define alox_UartMessage_espnow_unicast_test_response_tag 14
|
#define alox_UartMessage_espnow_unicast_test_response_tag 14
|
||||||
#define alox_UartMessage_ota_slave_progress_request_tag 15
|
|
||||||
#define alox_UartMessage_ota_slave_progress_response_tag 16
|
|
||||||
#define alox_UartMessage_led_ring_progress_request_tag 17
|
|
||||||
#define alox_UartMessage_led_ring_progress_response_tag 18
|
|
||||||
|
|
||||||
/* Struct field encoding specification for nanopb */
|
/* Struct field encoding specification for nanopb */
|
||||||
#define alox_UartMessage_FIELDLIST(X, a) \
|
#define alox_UartMessage_FIELDLIST(X, a) \
|
||||||
@ -367,11 +269,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,ota_status,payload.ota_status), 10)
|
|||||||
X(a, STATIC, ONEOF, MESSAGE, (payload,accel_deadzone_request,payload.accel_deadzone_request), 11) \
|
X(a, STATIC, ONEOF, MESSAGE, (payload,accel_deadzone_request,payload.accel_deadzone_request), 11) \
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (payload,accel_deadzone_response,payload.accel_deadzone_response), 12) \
|
X(a, STATIC, ONEOF, MESSAGE, (payload,accel_deadzone_response,payload.accel_deadzone_response), 12) \
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (payload,espnow_unicast_test_request,payload.espnow_unicast_test_request), 13) \
|
X(a, STATIC, ONEOF, MESSAGE, (payload,espnow_unicast_test_request,payload.espnow_unicast_test_request), 13) \
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (payload,espnow_unicast_test_response,payload.espnow_unicast_test_response), 14) \
|
X(a, STATIC, ONEOF, MESSAGE, (payload,espnow_unicast_test_response,payload.espnow_unicast_test_response), 14)
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (payload,ota_slave_progress_request,payload.ota_slave_progress_request), 15) \
|
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (payload,ota_slave_progress_response,payload.ota_slave_progress_response), 16) \
|
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (payload,led_ring_progress_request,payload.led_ring_progress_request), 17) \
|
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (payload,led_ring_progress_response,payload.led_ring_progress_response), 18)
|
|
||||||
#define alox_UartMessage_CALLBACK NULL
|
#define alox_UartMessage_CALLBACK NULL
|
||||||
#define alox_UartMessage_DEFAULT NULL
|
#define alox_UartMessage_DEFAULT NULL
|
||||||
#define alox_UartMessage_payload_ack_payload_MSGTYPE alox_Ack
|
#define alox_UartMessage_payload_ack_payload_MSGTYPE alox_Ack
|
||||||
@ -387,10 +285,6 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,led_ring_progress_response,payload.l
|
|||||||
#define alox_UartMessage_payload_accel_deadzone_response_MSGTYPE alox_AccelDeadzoneResponse
|
#define alox_UartMessage_payload_accel_deadzone_response_MSGTYPE alox_AccelDeadzoneResponse
|
||||||
#define alox_UartMessage_payload_espnow_unicast_test_request_MSGTYPE alox_EspNowUnicastTestRequest
|
#define alox_UartMessage_payload_espnow_unicast_test_request_MSGTYPE alox_EspNowUnicastTestRequest
|
||||||
#define alox_UartMessage_payload_espnow_unicast_test_response_MSGTYPE alox_EspNowUnicastTestResponse
|
#define alox_UartMessage_payload_espnow_unicast_test_response_MSGTYPE alox_EspNowUnicastTestResponse
|
||||||
#define alox_UartMessage_payload_ota_slave_progress_request_MSGTYPE alox_OtaSlaveProgressRequest
|
|
||||||
#define alox_UartMessage_payload_ota_slave_progress_response_MSGTYPE alox_OtaSlaveProgressResponse
|
|
||||||
#define alox_UartMessage_payload_led_ring_progress_request_MSGTYPE alox_LedRingProgressRequest
|
|
||||||
#define alox_UartMessage_payload_led_ring_progress_response_MSGTYPE alox_LedRingProgressResponse
|
|
||||||
|
|
||||||
#define alox_Ack_FIELDLIST(X, a) \
|
#define alox_Ack_FIELDLIST(X, a) \
|
||||||
|
|
||||||
@ -468,27 +362,6 @@ X(a, STATIC, SINGULAR, UINT32, seq, 2)
|
|||||||
#define alox_EspNowUnicastTestResponse_CALLBACK NULL
|
#define alox_EspNowUnicastTestResponse_CALLBACK NULL
|
||||||
#define alox_EspNowUnicastTestResponse_DEFAULT NULL
|
#define alox_EspNowUnicastTestResponse_DEFAULT NULL
|
||||||
|
|
||||||
#define alox_LedRingProgressRequest_FIELDLIST(X, a) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, mode, 1) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, progress, 2) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, digit, 3) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, r, 4) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, g, 5) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, b, 6) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, intensity, 7) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, blink_ms, 8) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, blink_count, 9)
|
|
||||||
#define alox_LedRingProgressRequest_CALLBACK NULL
|
|
||||||
#define alox_LedRingProgressRequest_DEFAULT NULL
|
|
||||||
|
|
||||||
#define alox_LedRingProgressResponse_FIELDLIST(X, a) \
|
|
||||||
X(a, STATIC, SINGULAR, BOOL, success, 1) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, mode, 2) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, progress, 3) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, digit, 4)
|
|
||||||
#define alox_LedRingProgressResponse_CALLBACK NULL
|
|
||||||
#define alox_LedRingProgressResponse_DEFAULT NULL
|
|
||||||
|
|
||||||
#define alox_OtaStartPayload_FIELDLIST(X, a) \
|
#define alox_OtaStartPayload_FIELDLIST(X, a) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, total_size, 1)
|
X(a, STATIC, SINGULAR, UINT32, total_size, 1)
|
||||||
#define alox_OtaStartPayload_CALLBACK NULL
|
#define alox_OtaStartPayload_CALLBACK NULL
|
||||||
@ -513,30 +386,6 @@ X(a, STATIC, SINGULAR, UINT32, error, 4)
|
|||||||
#define alox_OtaStatusPayload_CALLBACK NULL
|
#define alox_OtaStatusPayload_CALLBACK NULL
|
||||||
#define alox_OtaStatusPayload_DEFAULT NULL
|
#define alox_OtaStatusPayload_DEFAULT NULL
|
||||||
|
|
||||||
#define alox_OtaSlaveProgressRequest_FIELDLIST(X, a) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, client_id, 1)
|
|
||||||
#define alox_OtaSlaveProgressRequest_CALLBACK NULL
|
|
||||||
#define alox_OtaSlaveProgressRequest_DEFAULT NULL
|
|
||||||
|
|
||||||
#define alox_OtaSlaveProgressEntry_FIELDLIST(X, a) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, client_id, 1) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, bytes_written, 2) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, total_bytes, 3) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, status, 4) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, error, 5)
|
|
||||||
#define alox_OtaSlaveProgressEntry_CALLBACK NULL
|
|
||||||
#define alox_OtaSlaveProgressEntry_DEFAULT NULL
|
|
||||||
|
|
||||||
#define alox_OtaSlaveProgressResponse_FIELDLIST(X, a) \
|
|
||||||
X(a, STATIC, SINGULAR, BOOL, active, 1) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, total_bytes, 2) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, aggregate_bytes, 3) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, slave_count, 4) \
|
|
||||||
X(a, STATIC, REPEATED, MESSAGE, slaves, 5)
|
|
||||||
#define alox_OtaSlaveProgressResponse_CALLBACK NULL
|
|
||||||
#define alox_OtaSlaveProgressResponse_DEFAULT NULL
|
|
||||||
#define alox_OtaSlaveProgressResponse_slaves_MSGTYPE alox_OtaSlaveProgressEntry
|
|
||||||
|
|
||||||
extern const pb_msgdesc_t alox_UartMessage_msg;
|
extern const pb_msgdesc_t alox_UartMessage_msg;
|
||||||
extern const pb_msgdesc_t alox_Ack_msg;
|
extern const pb_msgdesc_t alox_Ack_msg;
|
||||||
extern const pb_msgdesc_t alox_EchoPayload_msg;
|
extern const pb_msgdesc_t alox_EchoPayload_msg;
|
||||||
@ -549,15 +398,10 @@ extern const pb_msgdesc_t alox_AccelDeadzoneRequest_msg;
|
|||||||
extern const pb_msgdesc_t alox_AccelDeadzoneResponse_msg;
|
extern const pb_msgdesc_t alox_AccelDeadzoneResponse_msg;
|
||||||
extern const pb_msgdesc_t alox_EspNowUnicastTestRequest_msg;
|
extern const pb_msgdesc_t alox_EspNowUnicastTestRequest_msg;
|
||||||
extern const pb_msgdesc_t alox_EspNowUnicastTestResponse_msg;
|
extern const pb_msgdesc_t alox_EspNowUnicastTestResponse_msg;
|
||||||
extern const pb_msgdesc_t alox_LedRingProgressRequest_msg;
|
|
||||||
extern const pb_msgdesc_t alox_LedRingProgressResponse_msg;
|
|
||||||
extern const pb_msgdesc_t alox_OtaStartPayload_msg;
|
extern const pb_msgdesc_t alox_OtaStartPayload_msg;
|
||||||
extern const pb_msgdesc_t alox_OtaPayload_msg;
|
extern const pb_msgdesc_t alox_OtaPayload_msg;
|
||||||
extern const pb_msgdesc_t alox_OtaEndPayload_msg;
|
extern const pb_msgdesc_t alox_OtaEndPayload_msg;
|
||||||
extern const pb_msgdesc_t alox_OtaStatusPayload_msg;
|
extern const pb_msgdesc_t alox_OtaStatusPayload_msg;
|
||||||
extern const pb_msgdesc_t alox_OtaSlaveProgressRequest_msg;
|
|
||||||
extern const pb_msgdesc_t alox_OtaSlaveProgressEntry_msg;
|
|
||||||
extern const pb_msgdesc_t alox_OtaSlaveProgressResponse_msg;
|
|
||||||
|
|
||||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||||
#define alox_UartMessage_fields &alox_UartMessage_msg
|
#define alox_UartMessage_fields &alox_UartMessage_msg
|
||||||
@ -572,15 +416,10 @@ extern const pb_msgdesc_t alox_OtaSlaveProgressResponse_msg;
|
|||||||
#define alox_AccelDeadzoneResponse_fields &alox_AccelDeadzoneResponse_msg
|
#define alox_AccelDeadzoneResponse_fields &alox_AccelDeadzoneResponse_msg
|
||||||
#define alox_EspNowUnicastTestRequest_fields &alox_EspNowUnicastTestRequest_msg
|
#define alox_EspNowUnicastTestRequest_fields &alox_EspNowUnicastTestRequest_msg
|
||||||
#define alox_EspNowUnicastTestResponse_fields &alox_EspNowUnicastTestResponse_msg
|
#define alox_EspNowUnicastTestResponse_fields &alox_EspNowUnicastTestResponse_msg
|
||||||
#define alox_LedRingProgressRequest_fields &alox_LedRingProgressRequest_msg
|
|
||||||
#define alox_LedRingProgressResponse_fields &alox_LedRingProgressResponse_msg
|
|
||||||
#define alox_OtaStartPayload_fields &alox_OtaStartPayload_msg
|
#define alox_OtaStartPayload_fields &alox_OtaStartPayload_msg
|
||||||
#define alox_OtaPayload_fields &alox_OtaPayload_msg
|
#define alox_OtaPayload_fields &alox_OtaPayload_msg
|
||||||
#define alox_OtaEndPayload_fields &alox_OtaEndPayload_msg
|
#define alox_OtaEndPayload_fields &alox_OtaEndPayload_msg
|
||||||
#define alox_OtaStatusPayload_fields &alox_OtaStatusPayload_msg
|
#define alox_OtaStatusPayload_fields &alox_OtaStatusPayload_msg
|
||||||
#define alox_OtaSlaveProgressRequest_fields &alox_OtaSlaveProgressRequest_msg
|
|
||||||
#define alox_OtaSlaveProgressEntry_fields &alox_OtaSlaveProgressEntry_msg
|
|
||||||
#define alox_OtaSlaveProgressResponse_fields &alox_OtaSlaveProgressResponse_msg
|
|
||||||
|
|
||||||
/* Maximum encoded size of messages (where known) */
|
/* Maximum encoded size of messages (where known) */
|
||||||
/* alox_UartMessage_size depends on runtime parameters */
|
/* alox_UartMessage_size depends on runtime parameters */
|
||||||
@ -589,20 +428,15 @@ extern const pb_msgdesc_t alox_OtaSlaveProgressResponse_msg;
|
|||||||
/* alox_ClientInfo_size depends on runtime parameters */
|
/* alox_ClientInfo_size depends on runtime parameters */
|
||||||
/* alox_ClientInfoResponse_size depends on runtime parameters */
|
/* alox_ClientInfoResponse_size depends on runtime parameters */
|
||||||
/* alox_ClientInputResponse_size depends on runtime parameters */
|
/* alox_ClientInputResponse_size depends on runtime parameters */
|
||||||
#define ALOX_UART_MESSAGES_PB_H_MAX_SIZE alox_OtaSlaveProgressResponse_size
|
/* alox_OtaPayload_size depends on runtime parameters */
|
||||||
|
#define ALOX_MAIN_PROTO_UART_MESSAGES_PB_H_MAX_SIZE alox_OtaStatusPayload_size
|
||||||
#define alox_AccelDeadzoneRequest_size 16
|
#define alox_AccelDeadzoneRequest_size 16
|
||||||
#define alox_AccelDeadzoneResponse_size 20
|
#define alox_AccelDeadzoneResponse_size 20
|
||||||
#define alox_Ack_size 0
|
#define alox_Ack_size 0
|
||||||
#define alox_ClientInput_size 22
|
#define alox_ClientInput_size 22
|
||||||
#define alox_EspNowUnicastTestRequest_size 12
|
#define alox_EspNowUnicastTestRequest_size 12
|
||||||
#define alox_EspNowUnicastTestResponse_size 8
|
#define alox_EspNowUnicastTestResponse_size 8
|
||||||
#define alox_LedRingProgressRequest_size 54
|
|
||||||
#define alox_LedRingProgressResponse_size 20
|
|
||||||
#define alox_OtaEndPayload_size 0
|
#define alox_OtaEndPayload_size 0
|
||||||
#define alox_OtaPayload_size 209
|
|
||||||
#define alox_OtaSlaveProgressEntry_size 30
|
|
||||||
#define alox_OtaSlaveProgressRequest_size 6
|
|
||||||
#define alox_OtaSlaveProgressResponse_size 532
|
|
||||||
#define alox_OtaStartPayload_size 6
|
#define alox_OtaStartPayload_size 6
|
||||||
#define alox_OtaStatusPayload_size 24
|
#define alox_OtaStatusPayload_size 24
|
||||||
|
|
||||||
|
|||||||
@ -13,13 +13,11 @@ enum MessageType {
|
|||||||
CLIENT_INPUT = 5;
|
CLIENT_INPUT = 5;
|
||||||
ACCEL_DEADZONE = 6;
|
ACCEL_DEADZONE = 6;
|
||||||
ESPNOW_UNICAST_TEST = 7;
|
ESPNOW_UNICAST_TEST = 7;
|
||||||
LED_RING = 8;
|
|
||||||
OTA_START = 16;
|
OTA_START = 16;
|
||||||
OTA_PAYLOAD = 17;
|
OTA_PAYLOAD = 17;
|
||||||
OTA_END = 18;
|
OTA_END = 18;
|
||||||
OTA_STATUS = 19;
|
OTA_STATUS = 19;
|
||||||
OTA_START_ESPNOW = 20;
|
OTA_START_ESPNOW = 20;
|
||||||
OTA_SLAVE_PROGRESS = 21;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message UartMessage {
|
message UartMessage {
|
||||||
@ -38,10 +36,6 @@ message UartMessage {
|
|||||||
AccelDeadzoneResponse accel_deadzone_response = 12;
|
AccelDeadzoneResponse accel_deadzone_response = 12;
|
||||||
EspNowUnicastTestRequest espnow_unicast_test_request = 13;
|
EspNowUnicastTestRequest espnow_unicast_test_request = 13;
|
||||||
EspNowUnicastTestResponse espnow_unicast_test_response = 14;
|
EspNowUnicastTestResponse espnow_unicast_test_response = 14;
|
||||||
OtaSlaveProgressRequest ota_slave_progress_request = 15;
|
|
||||||
OtaSlaveProgressResponse ota_slave_progress_response = 16;
|
|
||||||
LedRingProgressRequest led_ring_progress_request = 17;
|
|
||||||
LedRingProgressResponse led_ring_progress_response = 18;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,32 +104,6 @@ message EspNowUnicastTestResponse {
|
|||||||
uint32 seq = 2;
|
uint32 seq = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Host → device: LED ring display (progress bar, digit, clear, or blink).
|
|
||||||
// mode: 0=clear, 1=progress (0–100 %), 2=digit (0–10), 3=blink full ring.
|
|
||||||
message LedRingProgressRequest {
|
|
||||||
uint32 mode = 1;
|
|
||||||
/** 0–100: fraction of ring LEDs to light (mode=progress) */
|
|
||||||
uint32 progress = 2;
|
|
||||||
/** 0–10 (mode=digit) */
|
|
||||||
uint32 digit = 3;
|
|
||||||
uint32 r = 4;
|
|
||||||
uint32 g = 5;
|
|
||||||
uint32 b = 6;
|
|
||||||
/** 0–255 brightness scale; 0 = firmware default (~5 %) */
|
|
||||||
uint32 intensity = 7;
|
|
||||||
/** Pulse length in ms (mode=blink, default 350) */
|
|
||||||
uint32 blink_ms = 8;
|
|
||||||
/** Number of pulses (mode=blink, default 1) */
|
|
||||||
uint32 blink_count = 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
message LedRingProgressResponse {
|
|
||||||
bool success = 1;
|
|
||||||
uint32 mode = 2;
|
|
||||||
uint32 progress = 3;
|
|
||||||
uint32 digit = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS).
|
// Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS).
|
||||||
message OtaStartPayload {
|
message OtaStartPayload {
|
||||||
uint32 total_size = 1;
|
uint32 total_size = 1;
|
||||||
@ -151,32 +119,10 @@ message OtaPayload {
|
|||||||
message OtaEndPayload {}
|
message OtaEndPayload {}
|
||||||
|
|
||||||
// Device → host status (also used as ACK after each 4 KiB written).
|
// Device → host status (also used as ACK after each 4 KiB written).
|
||||||
// status: 1=preparing, 2=ready, 3=block_ack, 4=success, 5=failed, 6=distributing
|
// status: 1=preparing, 2=ready, 3=block_ack, 4=success, 5=failed
|
||||||
message OtaStatusPayload {
|
message OtaStatusPayload {
|
||||||
uint32 status = 1;
|
uint32 status = 1;
|
||||||
uint32 bytes_written = 2;
|
uint32 bytes_written = 2;
|
||||||
uint32 target_slot = 3;
|
uint32 target_slot = 3;
|
||||||
uint32 error = 4;
|
uint32 error = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Host → master: query ESP-NOW slave OTA progress (client_id 0 = all slaves in session).
|
|
||||||
message OtaSlaveProgressRequest {
|
|
||||||
uint32 client_id = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message OtaSlaveProgressEntry {
|
|
||||||
uint32 client_id = 1;
|
|
||||||
uint32 bytes_written = 2;
|
|
||||||
uint32 total_bytes = 3;
|
|
||||||
/** 0=idle, 1=preparing, 2=ready, 3=distributing, 4=success, 5=failed */
|
|
||||||
uint32 status = 4;
|
|
||||||
uint32 error = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
message OtaSlaveProgressResponse {
|
|
||||||
bool active = 1;
|
|
||||||
uint32 total_bytes = 2;
|
|
||||||
uint32 aggregate_bytes = 3;
|
|
||||||
uint32 slave_count = 4;
|
|
||||||
repeated OtaSlaveProgressEntry slaves = 5 [(nanopb).max_count = 16];
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user