Compare commits

...
56 Commits
Author SHA1 Message Date
skruecken 9b2474c261 Improved GoTool 2026-03-21 15:11:14 +01:00
skruecken 4628041b55 Updated SDK 2026-03-21 15:10:59 +01:00
skruecken 864ffbbd7f Added Network Rebuild Test 2026-03-03 17:42:51 +01:00
skruecken 22a72ee02d Adjusted new Com Connect Logic 2026-02-10 15:58:44 +01:00
skruecken f8aa19d331 Added many Eventbus Structs for the Frontend Handling 2026-02-08 23:49:22 +01:00
skruecken 7534459e73 First api draft for ui communication 2026-02-08 19:11:49 +01:00
skruecken f4f3c695af Refactored Frontend with gemini 2026-02-08 19:11:24 +01:00
skruecken 2fd19db88d Typo 2026-02-08 17:39:34 +01:00
skruecken 0b27d68c0c Installed Formatter and extracted javascript window logic from index 2026-02-08 17:14:37 +01:00
skruecken 0bcacb4a53 Improved Go Tool so that the OTA Update Works again 2026-02-08 17:00:41 +01:00
skruecken c656d4afd7 Added Naming Convetions 2026-02-08 17:00:08 +01:00
skruecken d0ff63783f Removed RAW Logs 2026-02-03 15:34:54 +01:00
skruecken 028b6feae8 Added Dummy Tests 2026-01-27 17:36:41 +01:00
skruecken 3c011e272b Added ClientInput
- refactored some magic numbers
2026-01-27 16:42:24 +01:00
skruecken 0767ddac38 Big Gotool Refactoring
- Added Event Bus
- Reworked Package Parsing
- Rewokred Frame Parsing
2026-01-27 16:23:51 +01:00
skruecken 9efef034f0 Changed to new Frontend for UI Components 2026-01-06 16:14:51 +01:00
skruecken 6edf7e6e5f Added Working Prototype for Websocket Communication 2025-12-30 16:19:43 +01:00
skruecken 2070001f4c Added Config for Tap/Acceleration Sensor 2025-12-30 14:11:33 +01:00
skruecken 50586f2b50 Moved to the bma456h lib 2025-12-30 14:11:12 +01:00
skruecken de747ef463 BMA456 HW Interrupt after 2 Steps working 2025-12-16 17:47:58 +01:00
skruecken 6521e290d6 Prototyped the first configuration and read of the BMA456 Sensor 2025-12-13 13:54:44 +01:00
skruecken f2296a33e6 Create a simpler version of the OTA Update
Using no Broadcast logic for speed but its working now.
There is to much Acks going on but for the prototyp that is okay
2025-09-28 20:52:36 +02:00
skruecken 7097e9e7ab Added Test Data Message for Game Development Testing 2025-09-27 15:57:52 +02:00
skruecken df35def702 Added Function to Read App Image size from Partition 2025-09-27 14:26:32 +02:00
skruecken 337976e637 OTA Update nearly working but could not get image correctly transefered 2025-09-14 13:07:08 +02:00
skruecken d8716c232e Updated Message Handling to new MessageBroker 2025-08-23 21:14:18 +02:00
skruecken a3e330ed77 Added Simple Switch Command Between C3 and S3 2025-08-23 21:13:56 +02:00
skruecken 672267b991 WIP First working version of registered callback esp now logic 2025-08-18 22:38:16 +02:00
skruecken 8398442544 Reworked ESPNOW MessageBrokerTask 2025-08-18 20:27:30 +02:00
Skruecken b29512d922 WIP changes to ota update 2025-08-18 19:56:14 +02:00
Skruecken 6e4525df38 Updated Readme 2025-08-15 14:19:31 +02:00
skruecken 60a304a93d Boilerplate for OTA Update over ESPNOW 2025-08-10 19:43:54 +02:00
skruecken f504553ab6 Added Header Definitions 2025-08-10 15:17:22 +02:00
skruecken bbfe61a9ed Fixed const pointer 2025-08-10 15:14:36 +02:00
skruecken 73bc078465 Moved OTA Functionality to functions to reuse it 2025-08-10 15:08:48 +02:00
skruecken 8d4f1da028 Fixed UART Version output and visualized it in go tool 2025-08-10 13:20:11 +02:00
skruecken 1d36a757c0 Added pagebreak in readme for printing 2025-08-10 13:17:08 +02:00
skruecken 648e201f5e Fixed Readme Layout 2025-08-10 13:05:33 +02:00
skruecken 400d308f4a Fixed Readme Layout 2025-08-10 13:03:40 +02:00
skruecken 1c9120a197 Updated Readme with actual UART Protocol 2025-08-10 12:22:45 +02:00
skruecken 3b560799af Working OTA Update over UART to the Master 2025-08-03 22:52:01 +02:00
skruecken 3abdd8816c Tool Adjustments for OTA Update 2025-08-02 16:13:08 +02:00
skruecken cf42e86322 First Prototype of OTA Uart Update Protkol, not working in this state!!! 2025-08-02 16:12:41 +02:00
skruecken 59dbd7b035 Adjustes UART Message Length to 512 2025-08-02 16:12:09 +02:00
skruecken d3e44125a2 Added Defines, fixed broken function call 2025-07-26 10:42:31 +02:00
skruecken ebb739a3a0 Removed old vibe coded Python Test Tool 2025-07-26 10:39:11 +02:00
skruecken 441347fc95 Added UART MSG IDs and Prep work for OTA 2025-07-26 10:38:26 +02:00
skruecken a9779cbade Added Version to Client Infos 2025-07-26 10:37:57 +02:00
skruecken 704d1c9c0b Added Test of NVS and Partion API 2025-07-26 10:36:31 +02:00
skruecken 95bfcaa4d2 Added OTA Update Strategie writedown 2025-07-26 10:35:40 +02:00
skruecken 01d0be7004 Rebuild Python Tool in Go 2025-07-26 10:35:21 +02:00
skruecken a8c7c42471 Added new Payload Structs for Preperation of OTA Update 2025-07-24 16:11:26 +02:00
skruecken 0934105952 Reworked MAC to String logic to many little buffers 2025-07-24 14:32:25 +02:00
skruecken 55228fff8d Added MultiBoard Support
Support ESP32S3 and ESP32C3 while compiling
2025-07-24 14:15:53 +02:00
skruecken 2bc6686d90 Adjustes Target to ESP32S3 and made uart payload build static 2025-07-24 11:39:29 +02:00
skruecken 73d3e24786 Improved Tool for Testing with Threading 2025-07-23 17:36:28 +02:00
55 changed files with 9639 additions and 1247 deletions
+35
View File
@@ -13,6 +13,15 @@ get_code_gen:
gen_prot: gen_prot:
./alox.protogen -i prot.json -o main/uart ./alox.protogen -i prot.json -o main/uart
switch_to_s3:
idf.py set-target esp32s3
cp sdkconfig.s3 sdkconfig
idf.py build
switch_to_c3:
idf.py set-target esp32c3
cp sdkconfig.c3 sdkconfig
idf.py build
buildIdf: buildIdf:
idf.py build idf.py build
@@ -20,9 +29,32 @@ buildIdf:
flashMini: flashMini:
idf.py flash -p /dev/ttyACM0 idf.py flash -p /dev/ttyACM0
flashMini2:
idf.py flash -p /dev/ttyACM1
flashMini3:
idf.py flash -p /dev/ttyACM2
flashCluster:
idf.py flash -p /dev/ttyACM1
idf.py flash -p /dev/ttyACM2
idf.py flash -p /dev/ttyACM3
idf.py flash -p /dev/ttyACM4
idf.py flash -p /dev/ttyACM5
idf.py flash -p /dev/ttyACM6
idf.py flash -p /dev/ttyACM7
idf.py flash -p /dev/ttyACM8
monitorMini: monitorMini:
idf.py monitor -p /dev/ttyACM0 idf.py monitor -p /dev/ttyACM0
monitorMini1:
idf.py monitor -p /dev/ttyACM1
monitorMini2:
idf.py monitor -p /dev/ttyACM2
flash0: flash0:
idf.py flash -p /dev/ttyUSB0 idf.py flash -p /dev/ttyUSB0
@@ -40,3 +72,6 @@ monitor1:
monitor2: monitor2:
idf.py monitor -p /dev/ttyUSB2 idf.py monitor -p /dev/ttyUSB2
flash_second_ota:
parttool.py --port /dev/ttyACM0 write_partition --partition-name="ota_1" --input build/espAlox.bin
+55
View File
@@ -0,0 +1,55 @@
package api
const (
TopicFrontendCmd = "front:cmd"
)
const (
CmdUpdateValue = "update_value"
CmdInitState = "init_state"
CmdConnect = "connect"
CmdDisconnect = "disconnect"
CmdSendMessage = "send"
CmdRX = "uart_rx"
CmdTX = "uart_tx"
)
var MessageReceiveRegistry = map[string]func() any{
CmdConnect: func() any { return &WsUartConnect{} },
CmdDisconnect: func() any { return &WsUartDisconnect{} },
CmdSendMessage: func() any { return &WsUartSendMessage{} },
}
type WsMessage struct {
Cmd string `json:"cmd"`
Payload []byte `json:"payload,omitempty"`
}
type SystemState struct {
Adapters []string `json:"adapters"`
SelectedAdapter string `json:"selected_adapter"`
Baudrates string `json:"baudrates"`
SelectedBaudrate string `json:"selected_baudrate"`
UartConnected bool `json:"uart_connected"`
}
type WsUartConnect struct {
SelectedAdapter string `json:"selected_adapter"`
Baudrate int `json:"baudrate"`
}
type WsUartDisconnect struct {
}
type WsUartSendMessage struct {
MsgId byte `json:"msg_id"`
Data []byte `json:"data"`
}
type WsUartRX struct {
Data []byte `json:"data"`
}
type WsUartTX struct {
Data []byte `json:"data"`
}
+110
View File
@@ -0,0 +1,110 @@
package api
// Topics
const (
TopicUARTRx = "uart:rx"
TopicUARTTx = "uart:tx"
TopicUARTError = "uart:error"
TopicUartAction = "uart:action"
TopicOTA = "ota"
)
type Frame struct {
Time uint64
ID byte
Data []byte
}
const (
CmdEcho byte = 0x01
CmdVersion byte = 0x02
CmdClientInfo byte = 0x03
CmdClientInput byte = 0x04
CmdOtaStart byte = 0x10
CmdOtaPayload byte = 0x11
CmdOtaEnd byte = 0x12
CmdOtaStatus byte = 0x13
CmdOtaStartEspNow byte = 0x14
)
const (
ClientCountOffset = 1
// Payload Sizes
PayloadVersionSize = 10
PayloadClientInfoSize = 19
PayloadClientInputSize = 13
)
type PayloadVersion struct {
Version uint16
Buildhash [7]uint8
}
type PayloadClientInfo struct {
ClientID uint8
IsAvailable uint8
SlotIsUsed uint8
MACAddr [6]uint8
LastPing uint32
LastSuccessfulPing uint32
Version uint16
}
type PayloadClientInput struct {
ClientID byte
X float32
Y float32
InputMask uint32
}
type PayloadOtaStatus struct {
SequenzCounter uint16
WriteIndex uint16
Data []byte
}
type PayloadOtaStart struct {
Data []byte
Parition byte
Error byte
}
type PayloadOtaEnd struct {
Data []byte
}
type PayloadOtaPayload struct {
SequenzCounter uint16
WriteIndex uint16
Data []byte
Error byte
}
type PayloadOtaStartEspNow struct {
Data []byte
}
type ActionUartConnect struct {
Adapter string
Baudrate int
}
type ActionUartConnected struct {
Adapter string
Baudrate int
Error error
}
type ActionUartDisconnect struct {
}
type ActionUartDisconnected struct {
}
type ActionUartSendMessage struct {
MsgId byte
Data []byte
}
+8
View File
@@ -0,0 +1,8 @@
package main
type Config struct {
Port int
Host string
UartPort string
Baudrate int
}
+64
View File
@@ -0,0 +1,64 @@
package eventbus
import (
"log"
"sync"
)
type EventBus interface {
Subscribe(topic string) chan any
Publish(topic string, data any)
Unsubscribe(topic string, ch chan any)
}
type EBus struct {
mu sync.RWMutex
topics map[string][]chan any
}
func New() *EBus {
return &EBus{
mu: sync.RWMutex{},
topics: map[string][]chan any{},
}
}
func (eb *EBus) Subscribe(topic string) chan any {
eb.mu.Lock()
defer eb.mu.Unlock()
ch := make(chan any, 20)
eb.topics[topic] = append(eb.topics[topic], ch)
return ch
}
func (eb *EBus) Publish(topic string, data any) {
eb.mu.RLock()
defer eb.mu.RUnlock()
for _, ch := range eb.topics[topic] {
select {
case ch <- data:
default:
log.Printf("[Event Bus]: Could not pass Message %v to %v channel full", data, topic)
}
}
}
func (eb *EBus) Unsubscribe(topic string, c chan any) {
eb.mu.Lock()
defer eb.mu.Unlock()
channels, ok := eb.topics[topic]
if !ok {
return
}
for i, ch := range channels {
if ch != c {
eb.topics[topic] = append(channels[:i], channels[i+1:]...) // example: 5 channels max i=3 channels[:3] (0,1,2) + channels[3+1:] (4,5)
close(ch)
return
}
}
}
+175
View File
@@ -0,0 +1,175 @@
package frontend
import (
"context"
"embed"
"encoding/json"
"io/fs"
"log"
"net/http"
"time"
"alox.tool/api"
"alox.tool/eventbus"
"github.com/gorilla/websocket"
)
//go:embed www
var staticFiles embed.FS
var upgrader = websocket.Upgrader{}
type FServer struct {
bus eventbus.EventBus
mux *http.ServeMux
}
func New(bus eventbus.EventBus) *FServer {
fsrv := &FServer{
bus: bus,
mux: http.NewServeMux(),
}
fsrv.routes()
return fsrv
}
func (fsrv *FServer) routes() {
// Static files from the Embed-FS
// remove "www" prefix, so index.html is reachable over /
root, _ := fs.Sub(staticFiles, "www")
fsrv.mux.Handle("/", http.FileServer(http.FS(root)))
fsrv.mux.HandleFunc("/ws", fsrv.handleWS)
}
func (fs *FServer) handleWS(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Printf("Upgrade error: %v", err)
return
}
defer conn.Close()
// Context nutzen, um Goroutinen zu stoppen, wenn die Verbindung abreißt
ctx, cancel := context.WithCancel(r.Context())
defer cancel()
// WRITER: Send Events to Browser
go fs.HandleAppEvents(ctx, conn)
// READER: Commands from Browser
// This Function is Blocking
fs.GetFrontendEvents(ctx, conn)
}
func (fs *FServer) Start(addr string) error {
server := &http.Server{
Addr: addr,
Handler: fs.mux,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
ctx, cancle := context.WithCancel(context.Background())
defer cancle()
go fs.HandleFrontendEvents(ctx)
log.Printf("Frontend Server gestartet auf %s", addr)
return server.ListenAndServe()
}
func (fs *FServer) HandleAppEvents(ctx context.Context, conn *websocket.Conn) error {
// Kanäle für die Hardware-Events abonnieren
rxChan := fs.bus.Subscribe(api.TopicUARTRx)
txChan := fs.bus.Subscribe(api.TopicUARTTx)
UartActions := fs.bus.Subscribe(api.TopicUartAction)
for {
select {
case <-ctx.Done():
return nil
case f := <-rxChan:
if err := conn.WriteJSON(map[string]any{"type": "rx", "frame": f}); err != nil {
return nil
}
case f := <-txChan:
if err := conn.WriteJSON(map[string]any{"type": "tx", "frame": f}); err != nil {
return nil
}
case msgT := <-UartActions:
switch msg := msgT.(type) {
case api.ActionUartConnected:
// TODO: nicht hier die daten nachhaltig speichern damit sie ans frontend gesendet werden können
// TODO: das muss irgendwo central passieren nicht für jeden client
if msg.Error != nil {
}
continue
case api.ActionUartDisconnected:
continue
}
}
}
}
func (fs *FServer) GetFrontendEvents(ctx context.Context, conn *websocket.Conn) error {
for {
select {
case <-ctx.Done():
return nil
default:
var cmd api.WsMessage
if err := conn.ReadJSON(&cmd); err != nil {
log.Printf("WS Read Error: %v", err)
return err
}
val, ok := api.MessageReceiveRegistry[cmd.Cmd]
if !ok {
log.Printf("No Message Type mapped to %v", cmd.Cmd)
continue
}
valM := val()
err := json.Unmarshal(cmd.Payload, valM)
if err != nil {
log.Printf("Could not Unmarshal payload %v", cmd.Payload)
}
fs.bus.Publish(api.TopicFrontendCmd, valM)
log.Printf("Browser Action: %s auf with %v", cmd.Cmd, cmd.Payload)
}
}
}
func (fs *FServer) HandleFrontendEvents(ctx context.Context) error {
fChan := fs.bus.Subscribe(api.TopicFrontendCmd)
for {
select {
case <-ctx.Done():
return nil
case msg := <-fChan:
switch msgT := msg.(type) {
case api.WsUartSendMessage:
log.Printf("Sending Uart Data % X", msgT.Data)
fs.bus.Publish(api.TopicUartAction, api.ActionUartSendMessage{
MsgId: msgT.MsgId,
Data: msgT.Data,
})
continue
case api.WsUartConnect:
log.Printf("Connect with %s : %d", msgT.SelectedAdapter, msgT.Baudrate)
fs.bus.Publish(api.TopicUartAction, api.ActionUartConnect{
Adapter: msgT.SelectedAdapter,
Baudrate: msgT.Baudrate,
})
continue
case api.WsUartDisconnect:
log.Printf("Disconnect from Uart Adapter")
fs.bus.Publish(api.TopicUartAction, api.ActionUartDisconnect{})
continue
}
}
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+32
View File
@@ -0,0 +1,32 @@
<div x-data="windowBox('window_id' ,100, 100)"
@mousemove.window="onDrag"
@mouseup.window="stopDrag"
@mousedown="focus"
class="card shadow-lg position-absolute"
:class="{ 'w-100 h-100 m-0 shadow-none': fullscreen }"
:style="`left: ${pos.x}px; top: ${pos.y}px; z-index: ${zIndex}; width: ${fullscreen ? '100vw' : '400px'};`"
x-cloak>
<div class="card-header bg-dark text-white d-flex justify-content-between align-items-center drag-handle"
@mousedown="startDrag" @dblclick="toggleFullscreen">
<h6 class="mb-0">CAN Interface</h6>
<div class="d-flex align-items-center gap-1">
<span class="badge me-1" :class="socket.readyState === 1 ? 'bg-success' : 'bg-danger'">WS</span>
<button class="btn btn-sm btn-outline-light py-0 px-2" @click="toggleFullscreen">
<span>▢</span>
</button>
<button class="btn btn-sm btn-outline-light py-0 px-2" @click="minimized = !minimized">
<span x-text="minimized ? '+' : ''"></span>
</button>
</div>
</div>
<div x-show="!minimized" class="flex-grow-1 overflow-auto">
<div class="card-body">
<p>HIER DER INHALT DER COMPONENT</p>
</div>
</div>
</div>
Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

+241
View File
@@ -0,0 +1,241 @@
<!doctype html>
<html>
<head>
<link href="bootstrap.min.css" rel="stylesheet" />
<script src="bootstrap.bundle.min.js"></script>
<script defer src="windows.js"></script>
<script defer src="alpinejs.min.js"></script>
<style>
[x-cloak] {
display: none !important;
}
body {
background-color: #f8f9fa;
background-image:
linear-gradient(90deg, rgba(0, 0, 0, 0.03) 1px, transparent 1px),
linear-gradient(rgba(0, 0, 0, 0.03) 1px, transparent 1px);
background-size: 20px 20px;
height: 100vh;
margin: 0;
padding-top: 56px; /* Space for navbar */
overflow: hidden;
}
.drag-handle {
cursor: move;
}
.card[style*="cursor: move"] {
transition: none;
}
.navbar {
z-index: 2000; /* Above windows */
}
.ws-indicator {
width: 12px;
height: 12px;
border: 1px solid rgba(255, 255, 255, 0.3);
transition: all 0.3s ease;
}
.glow-success {
box-shadow: 0 0 10px #198754;
}
.glow-danger {
box-shadow: 0 0 10px #dc3545;
}
</style>
<script>
document.addEventListener("alpine:init", () => {
Alpine.store("sys", {
ws_connected: false,
adapters: ["/dev/ttyUSB0"],
selected_adapter: "",
baudrates: ["115200", "916000"],
selected_baudrate: "",
uart_connected: false,
});
});
</script>
<script>
let socket;
function connectWS() {
socket = new WebSocket("ws://" + window.location.host + "/ws");
socket.onopen = () => {
console.log("[open] Connection established");
Alpine.store("sys").ws_connected = true;
};
socket.onmessage = (event) => {
try {
let mes = JSON.parse(event.data);
if (mes && mes.cmd === "value") {
Alpine.store(mes.name, mes.value);
}
} catch (e) {
console.log("Invalid JSON:", event.data);
}
};
socket.onclose = () => {
console.log("[close] Connection died");
Alpine.store("sys").ws_connected = false;
setTimeout(connectWS, 2000);
};
socket.onerror = (error) => {
console.log("[error]");
socket.close();
};
}
connectWS();
</script>
</head>
<body x-data>
<!-- Top Navbar -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top shadow">
<div class="container-fluid">
<a class="navbar-brand fw-bold" href="#">
<span class="text-primary">Alox</span> Debug Tool
</a>
<div class="d-flex align-items-center gap-2">
<span class="text-light small opacity-75">Websocket:</span>
<div
class="rounded-circle ws-indicator"
:class="$store.sys.ws_connected ? 'bg-success glow-success' : 'bg-danger glow-danger'"
></div>
</div>
</div>
</nav>
<!-- UART Configuration Window -->
<yet-window
id="uart_config"
title="UART Configuration"
x="50"
y="80"
width="400px"
>
<label class="form-label small fw-bold text-uppercase text-muted"
>Interface</label
>
<div
class="input-group mb-3"
x-data="{ open: false }"
@click.outside="open = false"
>
<button
class="btn btn-outline-secondary dropdown-toggle"
type="button"
@click="open = !open"
:disabled="$store.sys.uart_connected"
>
Adapter
</button>
<ul class="dropdown-menu" :class="{ 'show': open }" x-show="open">
<template x-for="adapter in $store.sys.adapters">
<li>
<button
class="dropdown-item"
type="button"
x-text="adapter"
@click="$store.sys.selected_adapter = adapter; open = false"
></button>
</li>
</template>
</ul>
<input
type="text"
class="form-control bg-light"
readonly
:value="$store.sys.selected_adapter || 'Select Interface...'"
/>
</div>
<label class="form-label small fw-bold text-uppercase text-muted"
>Baudrate</label
>
<div
class="input-group mb-4"
x-data="{ open: false }"
@click.outside="open = false"
>
<button
class="btn btn-outline-secondary dropdown-toggle"
type="button"
@click="open = !open"
:disabled="$store.sys.uart_connected"
>
Speed
</button>
<ul class="dropdown-menu" :class="{ 'show': open }" x-show="open">
<template x-for="rate in $store.sys.baudrates">
<li>
<button
class="dropdown-item"
type="button"
x-text="rate"
@click="$store.sys.selected_baudrate = rate; open = false"
></button>
</li>
</template>
</ul>
<input
type="text"
class="form-control bg-light"
readonly
:value="$store.sys.selected_baudrate || 'Select Baudrate...'"
/>
</div>
<div class="d-grid">
<button
x-show="!$store.sys.uart_connected"
class="btn btn-primary btn-lg"
type="button"
:disabled="!$store.sys.selected_adapter || !$store.sys.selected_baudrate"
@click="socket.send(JSON.stringify({cmd: 'connect', adapter: $store.sys.selected_adapter, baudrate: parseInt($store.sys.selected_baudrate)}))"
>
Connect to UART
</button>
<button
x-show="$store.sys.uart_connected"
x-cloak
class="btn btn-danger btn-lg"
type="button"
@click="socket.send(JSON.stringify({cmd: 'disconnect'}))"
>
Disconnect
</button>
</div>
</yet-window>
<!-- UART Log Window -->
<yet-window
id="uart_log"
title="UART Log"
x="500"
y="80"
width="550px"
header-class="bg-primary text-white"
>
<div
class="bg-dark text-success font-monospace small p-2 rounded shadow-inner"
style="height: 400px; overflow-y: auto"
>
<div class="text-muted small mt-2">
// UART log data will appear here...
</div>
</div>
</yet-window>
</body>
</html>
+153
View File
@@ -0,0 +1,153 @@
// windows.js
document.addEventListener("alpine:init", () => {
// 1. Globaler Store for Window Managment
Alpine.store("Yet_WM", {
topZ: 1000,
getNewZ() {
return ++this.topZ;
},
});
Alpine.data("YetWindow", (id, initialX = 50, initialY = 50) => ({
id: id,
pos: { x: parseInt(initialX), y: parseInt(initialY) },
lastPos: { x: 0, y: 0 },
dragging: false,
minimized: false,
fullscreen: false,
zIndex: 1000,
offset: { x: 0, y: 0 },
init() {
// Lade gespeicherten Zustand (einheitlicher Key: yet_win_)
const saved = JSON.parse(localStorage.getItem(`yet_win_${this.id}`));
if (saved) {
this.pos = { x: saved.x, y: saved.y };
this.minimized = saved.min;
}
this.focus();
this.keepInBounds();
},
focus() {
this.zIndex = Alpine.store("Yet_WM").getNewZ();
},
startDrag(e) {
if (e.target.closest("button") || this.fullscreen) return;
// Verhindert Text-Markierung während des Verschiebens
e.preventDefault();
this.focus();
this.dragging = true;
this.offset.x = e.clientX - this.pos.x;
this.offset.y = e.clientY - this.pos.y;
},
onDrag(e) {
if (!this.dragging) return;
let newX = e.clientX - this.offset.x;
let newY = e.clientY - this.offset.y;
const margin = 20;
this.pos.x = Math.max(margin - 350, Math.min(newX, window.innerWidth - 50));
this.pos.y = Math.max(0, Math.min(newY, window.innerHeight - 40));
},
stopDrag() {
if (this.dragging) {
this.dragging = false;
this.save();
}
},
toggleMinimize() {
this.minimized = !this.minimized;
this.save();
},
toggleFullscreen() {
if (!this.fullscreen) {
this.lastPos = { ...this.pos };
this.pos = { x: 0, y: 0 };
this.fullscreen = true;
} else {
this.pos = { ...this.lastPos };
this.fullscreen = false;
}
this.focus();
},
save() {
localStorage.setItem(
`yet_win_${this.id}`,
JSON.stringify({
x: this.pos.x,
y: this.pos.y,
min: this.minimized,
})
);
},
keepInBounds() {
if (this.pos.x > window.innerWidth) this.pos.x = 50;
if (this.pos.y > window.innerHeight) this.pos.y = 50;
},
}));
});
// Definition der Web Component
class YetWindowElement extends HTMLElement {
connectedCallback() {
const id = this.getAttribute("id") || "win_" + Math.random().toString(36).substr(2, 9);
const title = this.getAttribute("title") || "Window";
const x = this.getAttribute("x") || "50";
const y = this.getAttribute("y") || "50";
const width = this.getAttribute("width") || "450px";
const headerClass = this.getAttribute("header-class") || "bg-dark text-white";
const content = this.innerHTML;
this.innerHTML = `
<div
x-data="YetWindow('${id}', ${x}, ${y})"
@mousemove.window="onDrag"
@mouseup.window="stopDrag"
@mousedown="focus"
class="card shadow-lg position-absolute"
:class="{ 'w-100 h-100 m-0 shadow-none': fullscreen }"
:style="\`left: \${pos.x}px; top: \${pos.y}px; z-index: \${zIndex}; width: \${fullscreen ? '100vw' : '${width}'}; user-select: \${dragging ? 'none' : 'auto'};\`"
x-cloak
>
<div
class="card-header d-flex justify-content-between align-items-center drag-handle ${headerClass}"
@mousedown="startDrag"
@dblclick="toggleFullscreen"
style="user-select: none;"
>
<h6 class="mb-0">${title}</h6>
<div class="d-flex align-items-center gap-1">
<button class="btn btn-sm btn-outline-light py-0 px-2" @click="toggleFullscreen">
<span></span>
</button>
<button class="btn btn-sm btn-outline-light py-0 px-2" @click="toggleMinimize">
<span x-text="minimized ? '+' : ''"></span>
</button>
</div>
</div>
<div x-show="!minimized" class="flex-grow-1 overflow-auto">
<div class="card-body">
${content}
</div>
</div>
</div>
`;
}
}
customElements.define("yet-window", YetWindowElement);
+25
View File
@@ -0,0 +1,25 @@
module alox.tool
go 1.24.5
require (
github.com/gorilla/websocket v1.5.3
github.com/pterm/pterm v0.12.81
go.bug.st/serial v1.6.4
)
require (
atomicgo.dev/cursor v0.2.0 // indirect
atomicgo.dev/keyboard v0.2.9 // indirect
atomicgo.dev/schedule v0.1.0 // indirect
github.com/containerd/console v1.0.5 // indirect
github.com/creack/goselect v0.1.2 // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/lithammer/fuzzysearch v1.1.8 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/term v0.32.0 // indirect
golang.org/x/text v0.26.0 // indirect
)
+126
View File
@@ -0,0 +1,126 @@
atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg=
atomicgo.dev/assert v0.0.2/go.mod h1:ut4NcI3QDdJtlmAxQULOmA13Gz6e2DWbSAS8RUOmNYQ=
atomicgo.dev/cursor v0.2.0 h1:H6XN5alUJ52FZZUkI7AlJbUc1aW38GWZalpYRPpoPOw=
atomicgo.dev/cursor v0.2.0/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU=
atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8=
atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ=
atomicgo.dev/schedule v0.1.0 h1:nTthAbhZS5YZmgYbb2+DH8uQIZcTlIrd4eYr3UQxEjs=
atomicgo.dev/schedule v0.1.0/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU=
github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs=
github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8=
github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII=
github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k=
github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI=
github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c=
github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE=
github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4=
github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY=
github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk=
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/qqsc=
github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU=
github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI=
github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg=
github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE=
github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU=
github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE=
github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8=
github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s=
github.com/pterm/pterm v0.12.81 h1:ju+j5I2++FO1jBKMmscgh5h5DPFDFMB7epEjSoKehKA=
github.com/pterm/pterm v0.12.81/go.mod h1:TyuyrPjnxfwP+ccJdBTeWHtd/e0ybQHkOS/TakajZCw=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.bug.st/serial v1.6.4 h1:7FmqNPgVp3pu2Jz5PoPtbZ9jJO5gnEnZIvnI1lzve8A=
go.bug.st/serial v1.6.4/go.mod h1:nofMJxTeNVny/m6+KaafC6vJGj3miwQZ6vW4BZUGJPI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+128
View File
@@ -0,0 +1,128 @@
package main
import (
"context"
"flag"
"fmt"
"log"
"os"
"time"
"alox.tool/api"
"alox.tool/eventbus"
"alox.tool/frontend"
"alox.tool/state"
"alox.tool/testrunner"
"alox.tool/uart"
)
var (
Tests bool
Baudrate uint
)
func main() {
flag.BoolVar(&Tests, "t", false, "Tests")
flag.UintVar(&Baudrate, "b", 921600, "Baudrate") // 115200
flag.Parse()
log.Printf("Starting with Params %v", Baudrate)
config := Config{
Port: 8000,
Host: "0.0.0.0",
UartPort: "/dev/ttyUSB0",
Baudrate: int(Baudrate),
}
if Tests {
StartTests(config)
return
}
StartApp(config)
}
func StartTests(config Config) {
bus := eventbus.New()
com, err := uart.NewCom(bus)
if err != nil {
log.Printf("Could not Create COM %v", err)
}
err = com.Connect(config.UartPort, config.Baudrate)
if err != nil {
log.Printf("Could not Connect with Uart Device %v", err)
}
defer com.Close()
tr := testrunner.New(bus, com)
testTest := make(map[string]func() error)
testTest["Echo Test"] = tr.RunEchoTest
testTest["Version Test"] = tr.RunVersionTest
testTest["Info Test"] = tr.RunClientInfoTest
testTest["Input Test"] = tr.RunClientInputTest
testTest["Rebuild Network"] = tr.RebuildNetwork
tr.RunTestSet(testTest)
}
func StartApp(config Config) {
bus := eventbus.New()
com, err := uart.NewCom(bus)
ctx, cancle := context.WithCancel(context.Background())
defer cancle()
go com.EventbusHandler(ctx)
if err != nil {
log.Printf("Could not Create Com with Uart Device %v", err)
return
}
err = com.Connect(config.UartPort, config.Baudrate)
if err != nil {
log.Printf("Could not Connect with Uart Device %v", err)
}
defer com.Close()
update, err := os.ReadFile("../espAlox.bin")
if err != nil {
log.Printf("Could not read Update file %v", err)
return
}
updateSlices := SliceUpdate(update, 200)
oManager := NewOTAManager(bus, com, updateSlices)
espHandle := state.New()
espHandle.Start(ctx, bus)
oManager.StartUpdateHandler(ctx)
time.Sleep(time.Millisecond * 5)
//tr := testrunner.New(bus, com)
//tr.RunVersionTest()
time.Sleep(time.Millisecond * 5)
//com.Send(api.CmdEcho, make([]byte, 0))
//com.Send(api.CmdVersion, make([]byte, 0))
com.Send(api.CmdClientInfo, make([]byte, 0))
//com.Send(api.CmdClientInput, make([]byte, 0))
//com.Send(api.CmdOtaStart, make([]byte, 0))
//com.Send(api.CmdOtaStartEspNow, make([]byte, 0))
url := fmt.Sprintf("%s:%d", config.Host, config.Port)
fserver := frontend.New(bus)
fserver.Start(url)
}
func SliceUpdate(update []byte, maxlen int) [][]byte {
updateSlices := [][]byte{}
for i := 0; i < len(update); i += 200 {
end := min(i+200, len(update))
updateSlices = append(updateSlices, update[i:end])
}
return updateSlices
}
+136
View File
@@ -0,0 +1,136 @@
package main
import (
"context"
"log"
"time"
"alox.tool/api"
"alox.tool/eventbus"
"alox.tool/uart"
)
type OTAManager struct {
Bus eventbus.EventBus
Com *uart.Com
Update [][]byte
CurrentSlice uint16
Partition byte
StartTime time.Time
EndTime time.Time
}
func NewOTAManager(bus eventbus.EventBus, com *uart.Com, update [][]byte) OTAManager {
return OTAManager{
Bus: bus,
Com: com,
Update: update,
CurrentSlice: 0,
}
}
func (om *OTAManager) StartUpdateHandler(ctx context.Context) {
RXC := om.Bus.Subscribe(api.TopicUARTRx)
defer om.Bus.Unsubscribe(api.TopicUARTRx, RXC)
go func() {
for {
select {
case <-ctx.Done():
return
case msg := <-RXC:
val, ok := msg.(api.Frame)
if !ok {
log.Printf("val is not type api.Frame its %T", val)
continue
}
log.Printf("[%d] Frame: %X, % X", val.Time, val.ID, val.Data)
om.processFrame(val)
}
}
}()
}
func (om *OTAManager) processFrame(val api.Frame) {
switch val.ID {
case api.CmdOtaStart:
msgT, err := uart.ParseFrameOtaStart(val)
if err != nil {
log.Printf("Could not Parse Client Input %v", err)
return
}
// Send First Payload
om.StartTime = time.Now()
om.Partition = msgT.Parition
err = om.Com.Send(api.CmdOtaPayload, om.Update[om.CurrentSlice])
if err != nil {
log.Printf("Error Sending Update Step!: %v", err)
return
}
om.CurrentSlice = om.CurrentSlice + 1
log.Printf("First Update Step %d", om.CurrentSlice)
log.Printf("%v", msgT)
case api.CmdOtaPayload:
msgT, err := uart.ParseFrameOtaPayload(val)
if err != nil {
log.Printf("Could not Parse Client Input %v", err)
return
}
// Send Next Payload until there is no more then send end package
log.Printf("msgT %v", msgT)
if msgT.Error != 0x00 {
log.Printf("Error in Sending Update! Check ESP Log")
return
}
log.Printf("NEXT PAYLOAD")
if om.CurrentSlice == uint16(len(om.Update)) {
log.Printf("LAST PAYLOAD SEND ENDING")
om.Com.Send(api.CmdOtaEnd, make([]byte, 1))
return
}
err = om.Com.Send(api.CmdOtaPayload, om.Update[om.CurrentSlice])
if err != nil {
log.Printf("Error Sending Update Step!: %v", err)
return
}
om.CurrentSlice = om.CurrentSlice + 1
log.Printf("UPDATE CURRENT SLICE %d/%d", om.CurrentSlice, len(om.Update))
log.Printf("UPDATE Part/WriteIndex %d/%d", msgT.SequenzCounter, msgT.WriteIndex)
log.Printf("Progress: %05.2f%%", (float32(om.CurrentSlice)/float32(len(om.Update)))*100)
case api.CmdOtaStatus:
v, err := uart.ParseFrameOtaStatus(val)
if err != nil {
log.Printf("Could not Parse Client Input %v", err)
return
}
log.Printf("%v", v)
// Update State Machine
case api.CmdOtaEnd:
msgT, err := uart.ParseFrameOtaEnd(val)
if err != nil {
log.Printf("Could not Parse Client Input %v", err)
return
}
// End bestätigung
om.EndTime = time.Now()
duration := om.EndTime.Sub(om.StartTime)
log.Printf("Partition %d Update done in %f.2s!", om.Partition, duration.Seconds())
log.Printf("%v", msgT)
case api.CmdOtaStartEspNow:
v, err := uart.ParseFrameOtaStartEspNow(val)
if err != nil {
log.Printf("Could not Parse Client Input %v", err)
return
}
//bus.Publish(api.TopicOTA, v)
log.Printf("%v", v)
}
}
+186
View File
@@ -0,0 +1,186 @@
package state
import (
"context"
"log"
"sync"
"alox.tool/api"
"alox.tool/eventbus"
"alox.tool/uart"
)
type ESPStateHandler struct {
RWMutex sync.RWMutex
Master MasterESP
}
type ESPVersion struct {
Version uint16
Buildhash [7]byte
}
type BaseESP struct {
ClientId byte
IsUpdating bool
UpdateProgress float32
Version ESPVersion
RunningPartition int
MAC [6]byte
}
type MasterESP struct {
BaseESP
Slaves map[byte]*SlaveESP
}
type SlaveESP struct {
BaseESP
SlotAvailable bool
SlotUsed bool
Bitmask uint32
LageX float32
LageY float32
LastPing uint32
LastSuccessfullPing uint32
}
func New() *ESPStateHandler {
return &ESPStateHandler{
RWMutex: sync.RWMutex{},
Master: NewMasterESP(),
}
}
func NewMasterESP() MasterESP {
return MasterESP{
BaseESP: BaseESP{
ClientId: 0,
IsUpdating: false,
UpdateProgress: 0,
Version: ESPVersion{
Version: 0,
Buildhash: [7]byte{},
},
RunningPartition: 0,
MAC: [6]byte{},
},
Slaves: map[byte]*SlaveESP{},
}
}
func NewSlaveESP() *SlaveESP {
return &SlaveESP{
BaseESP: BaseESP{
ClientId: 0,
IsUpdating: false,
UpdateProgress: 0,
Version: ESPVersion{
Version: 0,
Buildhash: [7]byte{},
},
RunningPartition: 0,
MAC: [6]byte{},
},
SlotAvailable: false,
SlotUsed: false,
Bitmask: 0,
LageX: 0,
LageY: 0,
LastPing: 0,
LastSuccessfullPing: 0,
}
}
func (s *ESPStateHandler) Start(ctx context.Context, bus eventbus.EventBus) {
go func() {
RXC := bus.Subscribe(api.TopicUARTRx)
defer bus.Unsubscribe(api.TopicUARTRx, RXC)
for {
select {
case <-ctx.Done():
return
case msg := <-RXC:
val, ok := msg.(api.Frame)
if !ok {
log.Printf("val is not type api.Frame its %T", val)
continue
}
log.Printf("[%d] Frame: %X, % X", val.Time, val.ID, val.Data)
s.processFrame(val)
}
}
}()
}
func (s *ESPStateHandler) processFrame(val api.Frame) {
s.RWMutex.Lock()
defer s.RWMutex.Unlock()
switch val.ID {
case api.CmdEcho:
log.Printf("Echo %v", val)
case api.CmdVersion:
v, err := uart.ParseFrameVersion(val)
if err != nil {
log.Printf("Could not Parse Version %v", err)
return
}
log.Printf("Version Info %d %s", v.Version, v.Buildhash)
// Update State
s.Master.Version.Version = v.Version
s.Master.Version.Buildhash = v.Buildhash
case api.CmdClientInfo:
v, err := uart.ParseFrameClientInfo(val)
if err != nil {
log.Printf("Could not Parse Client Info %v", err)
return
}
for _, c := range v {
log.Printf("Client ID %d", c.ClientID)
log.Printf("\tIsAvailable %d", c.IsAvailable)
log.Printf("\tLastPing %d", c.LastPing)
log.Printf("\tLastSuccessfulPing %d", c.LastSuccessfulPing)
log.Printf("\tSlotIsUsed %d", c.SlotIsUsed)
log.Printf("\tVersion %d", c.Version)
log.Printf("\tMACAddr % X", c.MACAddr)
_, ok := s.Master.Slaves[c.ClientID]
if !ok {
s.Master.Slaves[c.ClientID] = NewSlaveESP()
}
s.Master.Slaves[c.ClientID].SlotAvailable = c.IsAvailable != 0
s.Master.Slaves[c.ClientID].SlotUsed = c.SlotIsUsed != 0
s.Master.Slaves[c.ClientID].LastPing = c.LastPing
s.Master.Slaves[c.ClientID].LastSuccessfullPing = c.LastSuccessfulPing
s.Master.Slaves[c.ClientID].Version.Version = c.Version
s.Master.Slaves[c.ClientID].MAC = c.MACAddr
}
case api.CmdClientInput:
v, err := uart.ParseFrameClientInput(val)
if err != nil {
log.Printf("Could not Parse Client Input %v", err)
return
}
for _, c := range v {
log.Printf("Client ID %d", c.ClientID)
log.Printf("\tX %f", c.X)
log.Printf("\tY %f", c.Y)
log.Printf("\tBitmask %08b", c.InputMask)
_, ok := s.Master.Slaves[c.ClientID]
if !ok {
s.Master.Slaves[c.ClientID] = NewSlaveESP()
}
s.Master.Slaves[c.ClientID].LageX = c.X
s.Master.Slaves[c.ClientID].LageY = c.Y
s.Master.Slaves[c.ClientID].Bitmask = c.InputMask
}
}
}
+18
View File
@@ -0,0 +1,18 @@
package testrunner
import (
"os/exec"
)
const (
ESPTOOLPATH = "/home/simon/.espressif/python_env/idf5.5_py3.14_env/bin/esptool.py"
)
func RestartESPOnPort(port string) error {
cmd := exec.Command(ESPTOOLPATH, "--port", port, "run")
err := cmd.Run()
if err != nil {
return err
}
return nil
}
+82
View File
@@ -0,0 +1,82 @@
package testrunner
import (
"context"
"fmt"
"io"
"log"
"os"
"time"
"alox.tool/api"
"alox.tool/eventbus"
"alox.tool/uart"
)
type TestRunner struct {
bus eventbus.EventBus
com *uart.Com
}
func New(bus eventbus.EventBus, com *uart.Com) *TestRunner {
return &TestRunner{
bus: bus,
com: com,
}
}
func (tr *TestRunner) RunTestSet(TSet map[string]func() error) {
null, _ := os.OpenFile(os.DevNull, os.O_WRONLY, 0)
defer null.Close()
// Backups der originalen Deskriptoren
oldStdout := os.Stdout
oldStderr := os.Stderr
oldLogOut := log.Writer()
for name, f := range TSet {
// 1. Output komplett abdrehen
os.Stdout = null
os.Stderr = null
log.SetOutput(io.Discard)
err := f()
// 2. Sofort wiederherstellen für das Log-Resultat
os.Stdout = oldStdout
os.Stderr = oldStderr
log.SetOutput(oldLogOut)
if err != nil {
log.Printf("[%s]: \t\tFailed: %v", name, err)
continue
}
log.Printf("[%s]: \t\tSucceeded", name)
}
}
func (tr *TestRunner) Expect(idToSend byte, payload []byte, expectedID byte, timeout time.Duration) (*api.Frame, error) {
rxChan := tr.bus.Subscribe(api.TopicUARTRx)
defer tr.bus.Unsubscribe(api.TopicUARTRx, rxChan)
if err := tr.com.Send(idToSend, payload); err != nil {
return nil, fmt.Errorf("send error: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
for {
select {
case <-ctx.Done():
return nil, fmt.Errorf("timeout waiting for ID 0x%02X", expectedID)
case frame := <-rxChan:
f := frame.(api.Frame)
if f.ID == expectedID {
return &f, nil
}
// Ignore other IDs and Messages on the Bus
}
}
}
+139
View File
@@ -0,0 +1,139 @@
package testrunner
import (
"fmt"
"slices"
"time"
"alox.tool/api"
"alox.tool/uart"
)
func (tr *TestRunner) RunEchoTest() error {
frame, err := tr.Expect(api.CmdEcho, []byte{0x01}, api.CmdEcho, 1*time.Second)
if err != nil {
return err
}
if frame.Data[0] != 0x01 {
return fmt.Errorf("Got % X expected % X", frame.Data[0], 0x01)
}
return nil
}
func (tr *TestRunner) RunVersionTest() error {
frame, err := tr.Expect(api.CmdVersion, nil, api.CmdVersion, 1*time.Second)
if err != nil {
return err
}
// TODO: Check Version and Buildhash?
_, err = uart.ParseFrameVersion(*frame)
if err != nil {
return err
}
v, err := uart.ParseFrameVersion(*frame)
if v.Version != 1 {
return fmt.Errorf("Got %d expected %d", v.Version, 1)
}
return nil
}
func (tr *TestRunner) RunClientInfoTest() error {
_, err := tr.Expect(api.CmdClientInfo, nil, api.CmdClientInfo, 1*time.Second)
if err != nil {
return err
}
// TODO: Real Check
return nil
}
func (tr *TestRunner) RunClientInputTest() error {
_, err := tr.Expect(api.CmdClientInput, nil, api.CmdClientInput, 1*time.Second)
if err != nil {
return err
}
// TODO: Real Check
return nil
}
func (tr *TestRunner) RebuildNetwork() error {
// Hardcoded for now
Clients := map[string]string{
"C1": "/dev/ttyACM1",
"C2": "/dev/ttyACM2",
"C3": "/dev/ttyACM3",
"C4": "/dev/ttyACM4",
}
// Hardcoded for now
macAddresses := [][6]byte{
{0x50, 0x78, 0x7D, 0x18, 0x85, 0xA0},
{0x50, 0x78, 0x7D, 0x18, 0x7D, 0x74},
{0x50, 0x78, 0x7D, 0x18, 0x1D, 0x14},
{0x50, 0x78, 0x7D, 0x18, 0x00, 0x10},
}
// Hardcoded for now
err := RestartESPOnPort("/dev/ttyACM0")
if err != nil {
return fmt.Errorf("Could not Restart Master!")
}
time.Sleep(500 * time.Millisecond)
for c, p := range Clients {
fmt.Printf("Restarting Client %v", c)
err = RestartESPOnPort(p)
if err != nil {
fmt.Printf("Could not Restart Client %v on Port %v", c, p)
return err
}
time.Sleep(500 * time.Millisecond)
}
success := false
var frame *api.Frame
var clientInfos []api.PayloadClientInfo
var lastError string
for i := 0; i <= 5; i++ {
time.Sleep(1000 * time.Millisecond) // inital sleep for first network setup
var err error // for local error scope
frame, err = tr.Expect(api.CmdClientInfo, nil, api.CmdClientInfo, 1*time.Second)
if err != nil {
lastError = "No Uart Message"
continue
}
clientInfos, err = uart.ParseFrameClientInfo(*frame)
if err != nil {
lastError = fmt.Sprintf("Could not parse Message: %v", err)
continue
}
if len(clientInfos) != len(macAddresses) {
lastError = fmt.Sprintf("Want %v Clients, got %v Clients", len(macAddresses), len(clientInfos))
continue
}
success = true
break
}
if !success {
return fmt.Errorf("%v", lastError)
}
for _, client := range clientInfos {
if !slices.Contains(macAddresses, client.MACAddr) {
return fmt.Errorf("Client %v not found in expected list %v", client.MACAddr, macAddresses)
}
}
return nil
}
+138
View File
@@ -0,0 +1,138 @@
package uart
import (
"context"
"fmt"
"log"
"time"
"alox.tool/api"
"alox.tool/eventbus"
"go.bug.st/serial"
)
type Com struct {
bus eventbus.EventBus
port serial.Port
cancel context.CancelFunc
}
func NewCom(bus eventbus.EventBus) (*Com, error) {
return &Com{
bus: bus,
port: nil,
cancel: nil,
}, nil
}
func (c *Com) Connect(portName string, baudrate int) error {
if c.port != nil {
return fmt.Errorf("Port already connected")
}
mode := &serial.Mode{BaudRate: baudrate}
port, err := serial.Open(portName, mode)
if err != nil {
return err
}
ctx, cancel := context.WithCancel(context.Background())
drv := New(c.bus)
go func() {
buff := make([]byte, 1024)
for {
select {
case <-ctx.Done():
return
default:
n, err := port.Read(buff)
if err != nil {
log.Print("[Warning]: Read Error:", err)
return // Loop beenden bei Hardware-Fehler
}
if n > 0 {
for _, b := range buff[:n] {
//log.Printf("[RAW][RX] % X", b)
drv.ParseByte(b)
}
}
}
}
}()
c.port = port
c.cancel = cancel
return nil
}
func (c *Com) Close() {
c.cancel()
c.port.Close()
}
func packFrame(id byte, payload []byte) []byte {
out := make([]byte, 0, len(payload)+5) // Guessing extra Puffer size
checksum := id
out = append(out, StartByte)
// Helper für Escaping
writeEscaped := func(b byte) {
if b == StartByte || b == EscapeByte || b == EndByte {
out = append(out, EscapeByte)
}
out = append(out, b)
}
writeEscaped(id)
for _, b := range payload {
writeEscaped(b)
checksum ^= b
}
writeEscaped(checksum)
out = append(out, EndByte)
return out
}
func (c *Com) Send(id byte, payload []byte) error {
raw := packFrame(id, payload)
log.Printf("[RAW]: %v", raw)
//log.Printf("RAW: % X", raw)
_, err := c.port.Write(raw)
c.bus.Publish(api.TopicUARTTx, api.Frame{
Time: uint64(time.Now().UnixNano()),
ID: id,
Data: payload,
})
return err
}
func (c *Com) EventbusHandler(ctx context.Context) error {
UActions := c.bus.Subscribe(api.TopicUartAction)
for {
select {
case <-ctx.Done():
return nil
case msgT := <-UActions:
switch msg := msgT.(type) {
case api.ActionUartConnect:
err := c.Connect(msg.Adapter, msg.Baudrate)
c.bus.Publish(api.TopicUartAction, api.ActionUartConnected{
Adapter: msg.Adapter,
Baudrate: msg.Baudrate,
Error: err,
})
case api.ActionUartDisconnect:
c.Close()
c.bus.Publish(api.TopicUartAction, api.ActionUartDisconnected{})
case api.ActionUartSendMessage:
c.Send(msg.MsgId, msg.Data)
}
}
}
}
+189
View File
@@ -0,0 +1,189 @@
package uart
import (
"encoding/binary"
"fmt"
"log"
"math"
"alox.tool/api"
)
func ParseFrameVersion(frame api.Frame) (api.PayloadVersion, error) {
if len(frame.Data) != api.PayloadVersionSize {
return api.PayloadVersion{}, fmt.Errorf("payload wrong size: got %d bytes, want 10", len(frame.Data))
}
v := api.PayloadVersion{
Version: binary.LittleEndian.Uint16(frame.Data[0:2]),
Buildhash: [7]uint8(frame.Data[2:10])}
return v, nil
}
func parseFrameClientInfoPart(data []byte) (api.PayloadClientInfo, error) {
if len(data) != api.PayloadClientInfoSize {
return api.PayloadClientInfo{}, fmt.Errorf("payload wrong size: got %d bytes, want 19", len(data))
}
v := api.PayloadClientInfo{
ClientID: data[0],
IsAvailable: data[1],
SlotIsUsed: data[2],
MACAddr: [6]uint8(data[3:9]),
LastPing: binary.LittleEndian.Uint32(data[9:13]),
LastSuccessfulPing: binary.LittleEndian.Uint32(data[13:17]),
Version: binary.LittleEndian.Uint16(data[17:19]),
}
return v, nil
}
func ParseFrameClientInfo(frame api.Frame) ([]api.PayloadClientInfo, error) {
if len(frame.Data) == 0 {
return nil, fmt.Errorf("empty frame data")
}
clientCount := int(frame.Data[0])
log.Printf("Clients %d", clientCount)
expectedLen := 1 + (clientCount * api.PayloadClientInfoSize)
if len(frame.Data) < expectedLen {
return nil, fmt.Errorf("frame data too short: got %d, want %d", len(frame.Data), expectedLen)
}
clientList := make([]api.PayloadClientInfo, 0, clientCount)
for i := 0; i < clientCount; i++ {
start := 1 + (i * api.PayloadClientInfoSize)
end := start + api.PayloadClientInfoSize
client, err := parseFrameClientInfoPart(frame.Data[start:end])
if err != nil {
log.Printf("Could not parse client part %d: %v", i, err)
continue
}
clientList = append(clientList, client)
}
return clientList, nil
}
func parseFrameClientInputPart(data []byte) (api.PayloadClientInput, error) {
if len(data) != api.PayloadClientInputSize {
return api.PayloadClientInput{}, fmt.Errorf("payload wrong size: got %d bytes, want 13", len(data))
}
v := api.PayloadClientInput{
ClientID: data[0],
X: math.Float32frombits(binary.LittleEndian.Uint32(data[1 : 1+4])),
Y: math.Float32frombits(binary.LittleEndian.Uint32(data[5 : 5+4])),
InputMask: binary.LittleEndian.Uint32(data[9 : 9+4]),
}
return v, nil
}
func ParseFrameClientInput(frame api.Frame) ([]api.PayloadClientInput, error) {
if len(frame.Data) == 0 {
return nil, fmt.Errorf("empty frame data")
}
clientCount := int(frame.Data[0])
log.Printf("Clients %d", clientCount)
expectedLen := 1 + (clientCount * api.PayloadClientInputSize)
if len(frame.Data) < expectedLen {
return nil, fmt.Errorf("frame data too short: got %d, want %d", len(frame.Data), expectedLen)
}
clientList := make([]api.PayloadClientInput, 0, clientCount)
for i := 0; i < clientCount; i++ {
start := 1 + (i * api.PayloadClientInputSize)
end := start + api.PayloadClientInputSize
client, err := parseFrameClientInputPart(frame.Data[start:end])
if err != nil {
log.Printf("Could not parse client art %d: %v", i, err)
continue
}
clientList = append(clientList, client)
}
return clientList, nil
}
// Dummy for now Just get Data
func ParseFrameOtaPayload(frame api.Frame) (api.PayloadOtaPayload, error) {
if len(frame.Data) == 0 {
return api.PayloadOtaPayload{}, fmt.Errorf("empty frame data")
}
status := api.PayloadOtaPayload{
Data: frame.Data,
SequenzCounter: binary.LittleEndian.Uint16(frame.Data[0:2]),
WriteIndex: binary.LittleEndian.Uint16(frame.Data[2:4]),
Error: frame.Data[4],
}
return status, nil
}
// Dummy for now Just get Data
func ParseFrameOtaStatus(frame api.Frame) (api.PayloadOtaStatus, error) {
if len(frame.Data) == 0 {
return api.PayloadOtaStatus{}, fmt.Errorf("empty frame data")
}
status := api.PayloadOtaStatus{
Data: frame.Data,
SequenzCounter: binary.LittleEndian.Uint16(frame.Data[0:2]),
WriteIndex: binary.LittleEndian.Uint16(frame.Data[2:4]),
}
return status, nil
}
// Dummy for now Just get Data
func ParseFrameOtaStart(frame api.Frame) (api.PayloadOtaStart, error) {
if len(frame.Data) == 0 {
return api.PayloadOtaStart{}, fmt.Errorf("empty frame data")
}
status := api.PayloadOtaStart{
Data: frame.Data,
Parition: frame.Data[0],
Error: frame.Data[1],
}
return status, nil
}
// Dummy for now Just get Data
func ParseFrameOtaEnd(frame api.Frame) (api.PayloadOtaEnd, error) {
if len(frame.Data) == 0 {
return api.PayloadOtaEnd{}, fmt.Errorf("empty frame data")
}
status := api.PayloadOtaEnd{
Data: frame.Data,
}
return status, nil
}
// Dummy for now Just get Data
func ParseFrameOtaStartEspNow(frame api.Frame) (api.PayloadOtaStartEspNow, error) {
if len(frame.Data) == 0 {
return api.PayloadOtaStartEspNow{}, fmt.Errorf("empty frame data")
}
status := api.PayloadOtaStartEspNow{
Data: frame.Data,
}
return status, nil
}
+128
View File
@@ -0,0 +1,128 @@
package uart
import (
"fmt"
"time"
"alox.tool/api"
"alox.tool/eventbus"
)
const (
StartByte = 0xAA
EscapeByte = 0xBB
EndByte = 0xCC
)
type parserState int
const (
stateWaitingForStart parserState = iota
stateGetID
stateEscapedID
stateInPayload
stateEscapedPayload
)
type Parser struct {
bus eventbus.EventBus
state parserState
parsedData []byte
rawCapture []byte
checksum byte
}
func New(bus eventbus.EventBus) *Parser {
return &Parser{
bus: bus,
state: stateWaitingForStart,
parsedData: make([]byte, 0, 1024*4),
rawCapture: make([]byte, 0, 1024*4),
}
}
func (p *Parser) reset() {
p.state = stateWaitingForStart
p.parsedData = p.parsedData[:0]
p.rawCapture = p.rawCapture[:0]
p.checksum = 0
}
func (p *Parser) pushError(reason string) {
// Throw Error on the Bus befor resetting
p.bus.Publish(api.TopicUARTError, fmt.Errorf("%s: %02X", reason, p.rawCapture))
p.reset()
}
func (p *Parser) emitFrame() {
if len(p.parsedData) == 0 {
p.reset()
return
}
// Copy Data for Message Frame
dataCopy := make([]byte, len(p.parsedData)-1) // Exclude ID
copy(dataCopy, p.parsedData[1:])
f := api.Frame{
Time: uint64(time.Now().UnixNano()),
ID: p.parsedData[0],
Data: dataCopy,
}
p.bus.Publish(api.TopicUARTRx, f)
p.reset()
}
func (p *Parser) addByte(b byte) {
p.parsedData = append(p.parsedData, b)
p.checksum ^= b
}
func (p *Parser) ParseByte(b byte) {
p.rawCapture = append(p.rawCapture, b)
switch p.state {
case stateWaitingForStart:
if b == StartByte {
p.reset()
p.rawCapture = append(p.rawCapture, b) // Start Byte behalten
p.state = stateGetID
}
case stateGetID:
if b == EscapeByte {
p.state = stateEscapedID
} else {
p.addByte(b)
p.state = stateInPayload
}
case stateEscapedID:
p.addByte(b)
p.state = stateInPayload
case stateInPayload:
if b == EscapeByte {
p.state = stateEscapedPayload
return
}
if b == StartByte {
p.pushError("unexpected start byte")
return
}
if b == EndByte {
if p.checksum != 0 {
p.pushError("checksum mismatch")
return
}
p.emitFrame()
return
}
p.addByte(b)
case stateEscapedPayload:
p.addByte(b)
p.state = stateInPayload
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
idf_component_register(SRCS "main.c" "uart_handler.c" "communication_handler.c" "client_handler.c" "message_parser.c" "message_builder.c" "message_handler.c" idf_component_register(SRCS "main.c" "uart_handler.c" "communication_handler.c" "client_handler.c" "message_parser.c" "message_builder.c" "message_handler.c" "ota_update.c" "i2c.c"
INCLUDE_DIRS ".") INCLUDE_DIRS ".")
# Get the short Git commit hash of the current HEAD. # Get the short Git commit hash of the current HEAD.
+4 -1
View File
@@ -1,6 +1,7 @@
#include "client_handler.h" #include "client_handler.h"
#include "communication_handler.h"
#include "esp_log.h" #include "esp_log.h"
#include "freertos/task.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@@ -40,6 +41,8 @@ int add_client(ClientList *list, const uint8_t *client_mac) {
list->Clients[slot].slotIsUsed = true; list->Clients[slot].slotIsUsed = true;
list->Clients[slot].isAvailable = true; list->Clients[slot].isAvailable = true;
list->Clients[slot].last_seen = xTaskGetTickCount();
list->Clients[slot].retry_counter = 0;
memcpy(list->Clients[slot].macAddr, client_mac, MAC_LENGTH); memcpy(list->Clients[slot].macAddr, client_mac, MAC_LENGTH);
list->ClientCount++; list->ClientCount++;
return CLIENT_OK; return CLIENT_OK;
+18 -1
View File
@@ -1,7 +1,7 @@
#ifndef CLIENT_HANDLER_H #ifndef CLIENT_HANDLER_H
#define CLIENT_HANDLER_H #define CLIENT_HANDLER_H
#include "portmacro.h" #include "freertos/FreeRTOS.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@@ -21,6 +21,16 @@ enum ClientErrors {
CLIENT_INVALID_ID = -4, CLIENT_INVALID_ID = -4,
}; };
typedef enum {
OTA_IDLE,
OTA_AWAITING_ACK,
OTA_PREPARING,
OTA_READY,
OTA_UPDATING,
OTA_FAILED,
OTA_SUCCESS,
} ota_status_t;
typedef struct { typedef struct {
bool slotIsUsed; bool slotIsUsed;
bool isAvailable; bool isAvailable;
@@ -28,6 +38,13 @@ typedef struct {
uint8_t macAddr[MAC_LENGTH]; uint8_t macAddr[MAC_LENGTH];
TickType_t lastSuccessfullPing; TickType_t lastSuccessfullPing;
TickType_t lastPing; TickType_t lastPing;
uint16_t clientVersion;
ota_status_t ota_status;
uint16_t current_block_id;
uint32_t chunk_bitmask;
uint32_t resent_chunks_counter;
uint8_t retry_counter;
TickType_t last_seen;
} ClientInfo; } ClientInfo;
typedef struct { typedef struct {
+296 -150
View File
@@ -1,48 +1,128 @@
#include "communication_handler.h"
#include "esp_err.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_now.h" #include "esp_now.h"
#include "esp_ota_ops.h"
#include "esp_partition.h"
#include "esp_timer.h" #include "esp_timer.h"
#include "freertos/idf_additions.h" #include "freertos/idf_additions.h"
#include "freertos/task.h"
#include "message_structs.h"
#include "ota_update.h"
#include "client_handler.h" #include "client_handler.h"
#include "communication_handler.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <sys/types.h>
uint8_t broadcast_address[ESP_NOW_ETH_ALEN] = {0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF};
static const char *TAG = "ALOX - COM"; static const char *TAG = "ALOX - COM";
QueueHandle_t messageQueue = NULL; // Warteschlange für empfangene Nachrichten static QueueHandle_t messageQueue = NULL;
bool hasMaster = false; static struct ESP_MessageBroker mr;
static QueueHandle_t ESP_recieved_message_queue;
void free_ESPNOW_MessageInfo(ESPNOW_MessageInfo *msg) {
if (msg->esp_now_info.src_addr) {
free(msg->esp_now_info.src_addr);
msg->esp_now_info.src_addr = NULL;
}
if (msg->esp_now_info.des_addr) {
free(msg->esp_now_info.des_addr);
msg->esp_now_info.des_addr = NULL;
}
if (msg->esp_now_info.rx_ctrl) {
free(msg->esp_now_info.rx_ctrl);
msg->esp_now_info.rx_ctrl = NULL;
}
if (msg->data) {
free(msg->data);
msg->data = NULL;
}
}
void ESP_InitMessageBroker(QueueHandle_t msg_queue_handle) {
mr.num_direct_callbacks = 0;
mr.num_task_callbacks = 0;
ESP_recieved_message_queue = msg_queue_handle;
return;
}
void ESP_RegisterFunction(CommandPages command,
ESP_RegisterFunctionCallback callback) {
mr.FunctionList[mr.num_direct_callbacks].MSGID = command;
mr.FunctionList[mr.num_direct_callbacks].callback = callback;
mr.num_direct_callbacks++;
return;
}
void ESP_RegisterTask(CommandPages command, ESP_RegisterTaskCallback callback) {
mr.TaskList[mr.num_task_callbacks].MSGID = command;
mr.TaskList[mr.num_task_callbacks].task = callback;
mr.num_task_callbacks++;
}
void ESP_MessageBrokerTask(void *param) {
ESPNOW_MessageInfo received_msg;
ESP_MessageBrokerTaskParams_t *task_params =
(ESP_MessageBrokerTaskParams_t *)param;
QueueHandle_t msg_queue = task_params->message_queue;
if (msg_queue == NULL) {
ESP_LOGE(TAG, "Message queue not initialized. Terminating task.");
vTaskDelete(NULL);
}
ESP_LOGI(TAG, "Message broker task started.");
while (1) {
if (xQueueReceive(msg_queue, &received_msg, portMAX_DELAY)) {
const BaseMessage *message = (const BaseMessage *)received_msg.data;
for (int i = 0; i < mr.num_direct_callbacks; i++) {
if (mr.FunctionList[i].MSGID == message->commandPage) {
mr.FunctionList[i].callback(&received_msg.esp_now_info,
received_msg.data, received_msg.data_len);
free_ESPNOW_MessageInfo(&received_msg);
}
}
}
}
}
static bool hasMaster = false;
static ClientList *esp_client_list; static ClientList *esp_client_list;
static uint8_t channelNumber = 0;
#define MAC_STRING_BUFFER_SIZE 18 int init_com(ClientList *clients, uint8_t wifi_channel) {
messageQueue = xQueueCreate(MESSAGE_QUEUE_SIZE, sizeof(ESPNOW_MessageInfo));
void init_com(ClientList *clients) {
// Initialisiere die Kommunikations-Warteschlange
messageQueue = xQueueCreate(MESSAGE_QUEUE_SIZE, sizeof(BaseMessage));
if (messageQueue == NULL) { if (messageQueue == NULL) {
ESP_LOGE(TAG, "Message queue creation failed"); ESP_LOGE(TAG, "Message queue creation failed");
return -1;
} }
esp_client_list = clients; esp_client_list = clients;
hasMaster = false; hasMaster = false;
channelNumber = wifi_channel;
return 0;
} }
void add_peer(uint8_t *macAddr) { int add_peer(uint8_t *macAddr) {
esp_now_peer_info_t peerInfo = { esp_now_peer_info_t peerInfo = {
.channel = .channel = channelNumber,
0, // Standardkanal, sollte uit den anderen Geräten übereinstimmen
.ifidx = ESP_IF_WIFI_STA, .ifidx = ESP_IF_WIFI_STA,
.encrypt = false, // Keine Verschlüsselung (kann geändert werden) .encrypt = false,
}; };
memcpy(peerInfo.peer_addr, macAddr, ESP_NOW_ETH_ALEN); memcpy(peerInfo.peer_addr, macAddr, ESP_NOW_ETH_ALEN);
esp_err_t result = esp_now_add_peer(&peerInfo); esp_err_t result = esp_now_add_peer(&peerInfo);
if (result == ESP_OK) { if (result == ESP_OK) {
ESP_LOGI(TAG, "Peer added: %02X:%02X:%02X:%02X:%02X:%02X", ESP_LOGI(TAG, "Peer added");
peerInfo.peer_addr[0], peerInfo.peer_addr[1],
peerInfo.peer_addr[2], peerInfo.peer_addr[3],
peerInfo.peer_addr[4], peerInfo.peer_addr[5]);
if (!IS_BROADCAST_ADDR(macAddr)) { if (!IS_BROADCAST_ADDR(macAddr)) {
int ret = add_client(esp_client_list, peerInfo.peer_addr); int ret = add_client(esp_client_list, peerInfo.peer_addr);
@@ -50,6 +130,7 @@ void add_peer(uint8_t *macAddr) {
ESP_LOGE(TAG, "Client could not be added to client handler, removing " ESP_LOGE(TAG, "Client could not be added to client handler, removing "
"it from esp now client list!"); "it from esp now client list!");
esp_now_del_peer(peerInfo.peer_addr); esp_now_del_peer(peerInfo.peer_addr);
return -1;
} }
ESP_LOGI(TAG, "New client added."); ESP_LOGI(TAG, "New client added.");
} }
@@ -57,30 +138,24 @@ void add_peer(uint8_t *macAddr) {
ESP_LOGW(TAG, "Peer already exists."); ESP_LOGW(TAG, "Peer already exists.");
int id = get_client_id(esp_client_list, peerInfo.peer_addr); int id = get_client_id(esp_client_list, peerInfo.peer_addr);
if (id >= 0) { if (id >= 0) {
ESP_LOGI(TAG, "Client found again, welcome back!");
esp_client_list->Clients[id].isAvailable = true; esp_client_list->Clients[id].isAvailable = true;
} }
} else { } else {
ESP_LOGE(TAG, "Failed to add peer: %s", esp_err_to_name(result)); ESP_LOGE(TAG, "Failed to add peer: %s", esp_err_to_name(result));
return -1;
} }
} return 0;
void MACtoString(const uint8_t *macAddr, char *outputBuffer) {
sprintf(outputBuffer, "%02X:%02X:%02X:%02X:%02X:%02X", macAddr[0], macAddr[1],
macAddr[2], macAddr[3], macAddr[4], macAddr[5]);
} }
BaseMessage MessageBuilder(CommandPages commandPage, PayloadUnion payload, BaseMessage MessageBuilder(CommandPages commandPage, PayloadUnion payload,
size_t payload_size) { size_t payload_size) {
BaseMessage message; BaseMessage message;
// Initialisierung der BaseMessage
message.commandPage = commandPage; message.commandPage = commandPage;
message.version = 1; message.version = 1;
message.length = (uint16_t)payload_size; message.length = (uint16_t)payload_size;
// Kopieren des Payloads in die Union memset(&message.payload, 0, sizeof(message.payload));
memset(&message.payload, 0, sizeof(message.payload)); // Sicherheitsmaßnahme
memcpy(&message.payload, &payload, payload_size); memcpy(&message.payload, &payload, payload_size);
return message; return message;
@@ -95,192 +170,263 @@ void master_broadcast_task(void *param) {
ESP_ERROR_CHECK(esp_now_send(broadcast_address, (uint8_t *)&message, ESP_ERROR_CHECK(esp_now_send(broadcast_address, (uint8_t *)&message,
sizeof(BaseMessage))); sizeof(BaseMessage)));
ESP_LOGI(TAG, "Broadcast Message sent");
vTaskDelay(pdMS_TO_TICKS(5000)); vTaskDelay(pdMS_TO_TICKS(5000));
} }
} }
void master_broadcast_ping(void *param) { void master_broadcast_ping(void *param) {
while (1) { while (1) {
// BroadCastPayload payload = {};
PingPayload payload = {}; PingPayload payload = {};
payload.timestamp = esp_timer_get_time(); payload.timestamp = esp_timer_get_time();
BaseMessage message = BaseMessage message =
MessageBuilder(PingPage, *(PayloadUnion *)&payload, sizeof(payload)); MessageBuilder(PingPage, *(PayloadUnion *)&payload, sizeof(payload));
ESP_ERROR_CHECK(esp_now_send(broadcast_address, (uint8_t *)&message, ESP_ERROR_CHECK(esp_now_send(broadcast_address, (uint8_t *)&message,
sizeof(BaseMessage))); sizeof(BaseMessage)));
ESP_LOGI(TAG, "Broadcast PING Message sent");
vTaskDelay(pdMS_TO_TICKS(2500)); vTaskDelay(pdMS_TO_TICKS(2500));
} }
} }
void master_ping_task(void *param) { void master_ping_task(void *param) {
char macBuffer[MAC_STRING_BUFFER_SIZE];
while (1) { while (1) {
for (size_t i = 0; i < MAX_CLIENTS; i++) { for (size_t i = 0; i < MAX_CLIENTS; i++) {
if (esp_client_list->Clients[i].isAvailable) { if (esp_client_list->Clients[i].isAvailable) {
MACtoString(esp_client_list->Clients[i].macAddr, macBuffer);
ESP_LOGI(TAG, "SEND PING TO %zu: %s", i, macBuffer);
PingPayload payload = {}; PingPayload payload = {};
payload.timestamp = esp_timer_get_time(); payload.timestamp = esp_timer_get_time();
BaseMessage message = MessageBuilder( BaseMessage message = MessageBuilder(
PingPage, *(PayloadUnion *)&payload, sizeof(payload)); PingPage, *(PayloadUnion *)&payload, sizeof(payload));
esp_now_send(esp_client_list->Clients[i].macAddr, (uint8_t *)&message, esp_now_send(esp_client_list->Clients[i].macAddr, (uint8_t *)&message,
sizeof(BaseMessage)); sizeof(BaseMessage));
ESP_LOGI(TAG, "SENDING PING!!!!");
} }
} }
vTaskDelay(pdMS_TO_TICKS(1000)); vTaskDelay(pdMS_TO_TICKS(1000));
} }
} }
void master_receive_callback(const esp_now_recv_info_t *esp_now_info, void master_StatusCallback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) { const uint8_t *data, int data_len) {
char macBuffer[MAC_STRING_BUFFER_SIZE];
ESP_LOGI(TAG, "MASTER GOT MESSAGE");
const BaseMessage *message = (const BaseMessage *)data; const BaseMessage *message = (const BaseMessage *)data;
switch (message->commandPage) { ESP_LOGI(TAG, "SRC");
case StatusPage: ESP_LOGI(TAG,
ESP_LOGI(TAG, "GOT STATUS MESSAGE"); "Status Message Received: status: %d, runningPartition: %d, uptime: "
break; "%d, version: %d",
case PingPage: message->payload.status_payload.status,
ESP_LOGI(TAG, "GOT PING MESSAGE"); message->payload.status_payload.runningPartition,
uint32_t currentTime = esp_timer_get_time(); message->payload.status_payload.uptime,
uint32_t diff = currentTime - message->payload.ping_payload.timestamp; message->payload.status_payload.version);
ESP_LOGI(TAG, "Start: %lu, End: %lu, Diff: %lu, Ping: %lu",
message->payload.ping_payload.timestamp, currentTime, diff,
diff / 1000); // ping in ms
int id = get_client_id(esp_client_list, esp_now_info->src_addr);
if (id >= 0) {
esp_client_list->Clients[id].lastSuccessfullPing = xTaskGetTickCount();
esp_client_list->Clients[id].lastPing = (diff / 1000);
MACtoString(esp_now_info->src_addr, macBuffer);
ESP_LOGI(TAG, "Updated client %d: %s last ping time to %lu", id,
macBuffer, esp_client_list->Clients[id].lastSuccessfullPing);
}
break;
case BroadCastPage:
ESP_LOGI(TAG, "MASTER SHOULD NOT GET BROADCAST MESSAGE, is there another "
"master calling?");
break;
case RegisterPage:
ESP_LOGI(TAG, "WILL REGISTER DEVICE");
esp_now_peer_info_t checkPeerInfo;
esp_err_t checkPeer =
esp_now_get_peer(esp_now_info->src_addr, &checkPeerInfo);
switch (checkPeer) {
case (ESP_OK):
ESP_LOGI(TAG, "CLIENT BEKANNT");
int id = get_client_id(esp_client_list, esp_now_info->src_addr);
esp_client_list->Clients[id].isAvailable = true;
esp_client_list->Clients[id].lastSuccessfullPing = xTaskGetTickCount();
ESP_LOGI(TAG, "Updated client %d last ping time to %lu", id,
esp_client_list->Clients[id].lastSuccessfullPing);
break;
case (ESP_ERR_ESPNOW_NOT_INIT):
ESP_LOGI(TAG, "Not initalised");
break;
case (ESP_ERR_ESPNOW_ARG):
ESP_LOGI(TAG, "ESP ERR ESPNOW_ARG");
break;
case (ESP_ERR_ESPNOW_NOT_FOUND):
ESP_LOGI(TAG, "CLIENT WIRD IN DIE LISTE AUFGENOMMEN");
add_peer(esp_now_info->src_addr);
break;
default:
ESP_LOGI(TAG, "Unknown Message %i", checkPeer);
}
break;
default:
ESP_LOGI(TAG, "Unknown CommandPage %i", message->commandPage);
break;
}
} }
void client_receive_callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) {
char macBuffer[MAC_STRING_BUFFER_SIZE];
ESP_LOGI(TAG, "SLAVE GOT MESSAGE");
MACtoString(esp_now_info->src_addr, macBuffer);
ESP_LOGI(TAG, "Received message from: %s", macBuffer);
ESP_LOGI(TAG, "Message: %.*s", data_len, data);
void master_RegisterCallback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) {
BaseMessage replyMessage = {}; BaseMessage replyMessage = {};
const BaseMessage *message = (const BaseMessage *)data; esp_now_peer_info_t checkPeerInfo;
switch (message->commandPage) { esp_err_t checkPeer =
case StatusPage: esp_now_get_peer(esp_now_info->src_addr, &checkPeerInfo);
ESP_LOGI(TAG, "GOT STATUS MESSAGE"); switch (checkPeer) {
case (ESP_OK):
int id = get_client_id(esp_client_list, esp_now_info->src_addr);
esp_client_list->Clients[id].isAvailable = true;
esp_client_list->Clients[id].lastSuccessfullPing = xTaskGetTickCount();
break; break;
case PingPage: case (ESP_ERR_ESPNOW_NOT_FOUND):
ESP_LOGI(TAG, "GOT PING MESSAGE"); add_peer(esp_now_info->src_addr);
replyMessage = MessageBuilder(PingPage, *(PayloadUnion *)&message->payload, GetStatusPayload payload = {};
sizeof(message->payload)); replyMessage = MessageBuilder(GetStatusPage, *(PayloadUnion *)&payload,
ESP_ERROR_CHECK(esp_now_send( sizeof(payload));
esp_now_info->src_addr, (uint8_t *)&replyMessage, sizeof(BaseMessage))); esp_now_send(esp_now_info->src_addr, (uint8_t *)&replyMessage,
break; sizeof(BaseMessage));
case BroadCastPage:
ESP_LOGI(TAG, "GOT BROADCAST MESSAGE");
if (!hasMaster) {
if (IS_BROADCAST_ADDR(esp_now_info->des_addr)) {
ESP_LOGI(TAG,
"GOT BROADCAST MESSAGE ATTEMPTING TO REGISTER TO MASTER!");
add_peer(esp_now_info->src_addr);
replyMessage =
MessageBuilder(RegisterPage, *(PayloadUnion *)&message->payload,
sizeof(message->payload));
ESP_ERROR_CHECK(esp_now_send(esp_now_info->src_addr,
(uint8_t *)&replyMessage,
sizeof(BaseMessage)));
hasMaster = true;
}
}
break;
case RegisterPage:
break; break;
default: default:
ESP_LOGI(TAG, "GOT UNKONW MESSAGE");
break; break;
} }
} }
void client_data_sending_task(void *param) { void master_pingCallback(const esp_now_recv_info_t *esp_now_info,
while (1) { const uint8_t *data, int data_len) {
const char *dataToSend = "DATA:42"; const BaseMessage *message = (const BaseMessage *)data;
ESP_LOGI(TAG, "SEND DATA");
esp_now_send(NULL, (uint8_t *)dataToSend, uint32_t currentTime = esp_timer_get_time();
strlen(dataToSend)); // Sende Daten an Master uint32_t diff = currentTime - message->payload.ping_payload.timestamp;
vTaskDelay(pdMS_TO_TICKS(5000));
int id = get_client_id(esp_client_list, esp_now_info->src_addr);
if (id >= 0) {
esp_client_list->Clients[id].lastSuccessfullPing = xTaskGetTickCount();
esp_client_list->Clients[id].lastPing = (diff / 1000);
} }
} }
void master_broadcastCallback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) {}
void ESPNOW_RegisterMasterCallbacks() {
ESP_RegisterFunction(StatusPage, master_StatusCallback);
ESP_RegisterFunction(RegisterPage, master_RegisterCallback);
ESP_RegisterFunction(PingPage, master_pingCallback);
ESP_RegisterFunction(BroadCastPage, master_broadcastCallback);
}
void slave_broadcastCallback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) {
if (!hasMaster) {
if (IS_BROADCAST_ADDR(esp_now_info->des_addr)) {
add_peer(esp_now_info->src_addr);
BaseMessage replyMessage = {};
replyMessage =
MessageBuilder(RegisterPage, *(PayloadUnion *)&replyMessage.payload,
sizeof(replyMessage.payload));
esp_now_send(esp_now_info->src_addr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
hasMaster = true;
}
}
}
void slave_getstatusCallback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) {
StatusPayload payload = {
.status = 1,
.runningPartition = 1,
.uptime = 100,
.version = 0x0002,
};
BaseMessage replyMessage =
MessageBuilder(StatusPage, *(PayloadUnion *)&payload, sizeof(payload));
esp_now_send(esp_now_info->src_addr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
}
void slave_pingCallback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) {
if (!hasMaster)
return;
const BaseMessage *message = (const BaseMessage *)data;
BaseMessage replyMessage = MessageBuilder(
PingPage, *(PayloadUnion *)&message->payload, sizeof(message->payload));
esp_now_send(esp_now_info->src_addr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
}
void ESPNOW_RegisterSlaveCallbacks() {
ESP_RegisterFunction(BroadCastPage, slave_broadcastCallback);
ESP_RegisterFunction(GetStatusPage, slave_getstatusCallback);
ESP_RegisterFunction(PingPage, slave_pingCallback);
}
void master_receive_callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) {
uint8_t *copied_data = (uint8_t *)malloc(data_len);
if (copied_data == NULL) {
return;
}
memcpy(copied_data, data, data_len);
ESPNOW_MessageInfo msg_info;
msg_info.esp_now_info.src_addr = malloc(6);
if (msg_info.esp_now_info.src_addr) {
memcpy(msg_info.esp_now_info.src_addr, esp_now_info->src_addr, 6);
}
msg_info.esp_now_info.des_addr = malloc(6);
if (msg_info.esp_now_info.des_addr) {
memcpy(msg_info.esp_now_info.des_addr, esp_now_info->des_addr, 6);
}
msg_info.esp_now_info.rx_ctrl = malloc(sizeof(wifi_pkt_rx_ctrl_t));
if (msg_info.esp_now_info.rx_ctrl) {
memcpy(msg_info.esp_now_info.rx_ctrl, esp_now_info->rx_ctrl,
sizeof(wifi_pkt_rx_ctrl_t));
}
msg_info.data = copied_data;
msg_info.data_len = data_len;
xQueueSend(ESP_recieved_message_queue, &msg_info, portMAX_DELAY);
}
void client_receive_callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) {
uint8_t *copied_data = (uint8_t *)malloc(data_len);
if (copied_data == NULL) {
return;
}
memcpy(copied_data, data, data_len);
ESPNOW_MessageInfo msg_info;
// Initialize the esp_now_info struct to zeros
memset(&msg_info.esp_now_info, 0, sizeof(esp_now_recv_info_t));
// Now, allocate and copy the data pointed to by the pointers within
// esp_now_info src_addr
msg_info.esp_now_info.src_addr = malloc(6);
if (msg_info.esp_now_info.src_addr) {
memcpy(msg_info.esp_now_info.src_addr, esp_now_info->src_addr, 6);
} else {
free(copied_data);
return;
}
// des_addr
msg_info.esp_now_info.des_addr = malloc(6);
if (msg_info.esp_now_info.des_addr) {
memcpy(msg_info.esp_now_info.des_addr, esp_now_info->des_addr, 6);
} else {
free(msg_info.esp_now_info.src_addr);
free(copied_data);
return;
}
msg_info.esp_now_info.rx_ctrl = NULL; // Set to NULL as we are not copying it
msg_info.data = copied_data;
msg_info.data_len = data_len;
xQueueSend(ESP_recieved_message_queue, &msg_info, portMAX_DELAY);
}
void client_monitor_task(void *pvParameters) { void client_monitor_task(void *pvParameters) {
char macBuffer[MAC_STRING_BUFFER_SIZE]; TickType_t timeout_ticks = pdMS_TO_TICKS(CLIENT_TIMEOUT_MS);
TickType_t timeout_ticks = TickType_t interval_ticks = pdMS_TO_TICKS(CHECK_INTERVAL_MS);
pdMS_TO_TICKS(CLIENT_TIMEOUT_MS); // Timeout in Ticks
TickType_t interval_ticks =
pdMS_TO_TICKS(CHECK_INTERVAL_MS); // Prüfintervall in Ticks
while (1) { while (1) {
TickType_t now = xTaskGetTickCount(); // Aktuelle Zeit in Ticks TickType_t now = xTaskGetTickCount();
for (int i = 0; i < MAX_CLIENTS; i++) { for (int i = 0; i < MAX_CLIENTS; i++) {
if (esp_client_list->Clients[i].isAvailable) { if (esp_client_list->Clients[i].isAvailable) {
TickType_t time_diff = TickType_t time_diff =
now - esp_client_list->Clients[i].lastSuccessfullPing; now - esp_client_list->Clients[i].lastSuccessfullPing;
// Prüfen, ob der Client als "nicht verfügbar" markiert werden soll
if (time_diff > timeout_ticks) { if (time_diff > timeout_ticks) {
esp_client_list->Clients[i].isAvailable = false; esp_client_list->Clients[i].isAvailable = false;
MACtoString(esp_client_list->Clients[i].macAddr, macBuffer);
ESP_LOGW(TAG, "Client %d (MAC: %s) is unavailable", macBuffer);
} }
} }
} }
// Task für das Prüfintervall anhalten
vTaskDelay(interval_ticks); vTaskDelay(interval_ticks);
} }
} }
const esp_partition_t *ota_update_partition = NULL;
void ESPNOW_RegisterOTAMaster() {
// Observe this States for all Slaves in ClientList
// OTA_SLAVE_PREPARING
// OTA_SLAVE_READY
// OTA_SLAVE_ERROR
// OTA_SLAVE_WRITE_FINISHED
// OTA_SLAVE_FINISHED
ESP_RegisterFunction(OTA_PREPARE_ACKNOWLEDGED,
master_ota_prepare_acknowledge_callback);
ESP_RegisterFunction(OTA_READY_TO_RECEIVE,
master_ota_ready_to_recieve_callback);
ESP_RegisterFunction(OTA_UPDATE_SLAVE_ACKED,
master_ota_update_slave_acknowledge_callback);
}
void ESPNOW_RegisterOTASlave() {
ESP_RegisterFunction(OTA_PREPARE_FOR_UPDATE, slave_Prep_Upgrade_Callback);
ESP_RegisterFunction(OTA_CHUNK, slave_Update_Chunk_Callback);
ESP_RegisterFunction(OTA_FINISH_UPDATE, slave_Update_Finished_Callback);
}
+71 -33
View File
@@ -11,50 +11,42 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/types.h>
#include "esp_partition.h"
#include "message_structs.h"
#define BROADCAST_INTERVAL_MS 500 #define BROADCAST_INTERVAL_MS 500
#define CLIENT_TIMEOUT_MS 5000 // 5 Sekunden Timeout #define CLIENT_TIMEOUT_MS 5000 // 5 Sekunden Timeout
#define CHECK_INTERVAL_MS 1000 // Jede Sekunde überprüfen #define CHECK_INTERVAL_MS 1000 // Jede Sekunde überprüfen
static uint8_t broadcast_address[ESP_NOW_ETH_ALEN] = {0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF}; extern uint8_t broadcast_address[ESP_NOW_ETH_ALEN];
#define IS_BROADCAST_ADDR(addr) \ #define IS_BROADCAST_ADDR(addr) (memcmp(addr, broadcast_address, ESP_NOW_ETH_ALEN) == 0)
(memcmp(addr, broadcast_address, ESP_NOW_ETH_ALEN) == 0)
#define MESSAGE_QUEUE_SIZE 10 #define MESSAGE_QUEUE_SIZE 10
typedef enum { typedef union __attribute__((packed)) {
BroadCastPage, OTA_PREPARE_FOR_UPDATE_Payload ota_prepare_for_update_payload;
StatusPage, OTA_PREPARE_ACKNOWLEDGED_Payload ota_prepare_acknowledged_payload;
PingPage, OTA_READY_TO_RECEIVE_Payload ota_ready_to_receive_payload;
RegisterPage, OTA_CHUNK_Payload ota_chunk_payload;
} CommandPages; OTA_REQUEST_BLOCK_STATUS_Payload ota_request_block_status_payload;
OTA_BLOCK_STATUS_REPORT_Payload ota_block_status_report_payload;
typedef struct { OTA_COMMIT_BLOCK_Payload ota_commit_block_payload;
uint32_t uptime; OTA_BLOCK_COMMITTED_Payload ota_block_committed_payload;
uint8_t status; OTA_FINISH_UPDATE_Payload ota_finish_update_payload;
} StatusPayload; OTA_UPDATE_STATUS_Payload ota_update_status_payload;
typedef struct {
uint32_t timestamp;
} PingPayload;
typedef struct {
} BroadCastPayload;
typedef struct {
bool familierClient;
} RegisterPayload;
typedef union {
StatusPayload status_payload; StatusPayload status_payload;
ConfigPayload config_payload;
PingPayload ping_payload; PingPayload ping_payload;
BroadCastPayload broadcast_payload; BroadCastPayload broadcast_payload;
RegisterPayload register_payload; RegisterPayload register_payload;
FirmwarePrepPayload firmware_prep_payload;
FirmwarePayload firmware_payload;
} PayloadUnion; } PayloadUnion;
typedef struct { typedef struct __attribute__((packed)) {
uint16_t version; uint16_t version; // protcol version
CommandPages commandPage; CommandPages commandPage;
uint16_t length; uint16_t length;
PayloadUnion payload; PayloadUnion payload;
@@ -63,10 +55,52 @@ typedef struct {
static_assert(sizeof(BaseMessage) <= 255, static_assert(sizeof(BaseMessage) <= 255,
"BaseMessage darf nicht größer als 255 sein"); "BaseMessage darf nicht größer als 255 sein");
void init_com(ClientList *clients); typedef void (*ESP_RegisterFunctionCallback)(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data, int data_len);
typedef void (*ESP_RegisterTaskCallback)(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data, int data_len);
struct ESP_RegisterdFunction {
CommandPages MSGID;
ESP_RegisterFunctionCallback callback;
};
struct ESP_RegisterdTask {
CommandPages MSGID;
ESP_RegisterTaskCallback task;
};
struct ESP_MessageBroker {
struct ESP_RegisterdFunction FunctionList[64];
uint8_t num_direct_callbacks;
struct ESP_RegisterdTask TaskList[64];
uint8_t num_task_callbacks;
};
typedef struct {
QueueHandle_t message_queue;
} ESP_MessageBrokerTaskParams_t;
typedef struct {
esp_now_recv_info_t esp_now_info;
uint8_t *data;
int data_len;
} ESPNOW_MessageInfo;
void ESP_InitMessageBroker(QueueHandle_t msg_queue_handle);
void ESP_RegisterFunction(CommandPages command,
ESP_RegisterFunctionCallback callback);
void ESP_RegisterTask(CommandPages command, ESP_RegisterTaskCallback callback);
void ESP_MessageBrokerTask(void *param);
void ESPNOW_RegisterMasterCallbacks();
void ESPNOW_RegisterSlaveCallbacks();
void ESPNOW_RegisterOTAMaster();
void ESPNOW_RegisterOTASlave();
int init_com(ClientList *clients, uint8_t wifi_channel);
int getNextFreeClientId(); int getNextFreeClientId();
void add_peer(uint8_t *macAddr); int add_peer(uint8_t *macAddr);
void MACtoString(const uint8_t *macAddr, char *outputBuffer);
BaseMessage MessageBuilder(CommandPages commandPage, PayloadUnion payload, BaseMessage MessageBuilder(CommandPages commandPage, PayloadUnion payload,
size_t payload_size); size_t payload_size);
@@ -79,6 +113,10 @@ void master_receive_callback(const esp_now_recv_info_t *esp_now_info,
void client_receive_callback(const esp_now_recv_info_t *esp_now_info, void client_receive_callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len); const uint8_t *data, int data_len);
void client_data_sending_task(void *param); void client_data_sending_task(void *param);
void client_send_random_data_task(void *param);
void client_monitor_task(void *pvParameters); void client_monitor_task(void *pvParameters);
void send_ota_block_chunks(uint8_t client_id, uint16_t block_id);
#endif #endif
View File
View File
+278
View File
@@ -0,0 +1,278 @@
#include "i2c.h"
#include "bma4.h"
#include "bma456h.h"
#include "bma4_defs.h"
#include "driver/gpio.h"
#include "driver/i2c_master.h"
#include "esp_err.h"
#include "esp_log.h"
#include "freertos/idf_additions.h"
#include "hal/gpio_types.h"
#include "ota_update.h"
#include <rom/ets_sys.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
static i2c_master_bus_handle_t bus_handle;
static i2c_master_dev_handle_t bma456_dev_handle;
static struct bma4_dev bma456_struct;
volatile uint8_t interrupt_status = 0;
uint8_t int_line;
struct bma4_int_pin_config pin_config = {0};
uint16_t int_status = 0;
#define BMA4_READ_WRITE_LEN UINT8_C(46)
#define BMA456W_INT_PIN 7
static void interrupt_callback(void *) {
interrupt_status = 1;
// ESP_LOGI("INTERRUPT", "STEP DETECTED");
}
/******************************************************************************/
/*! User interface functions */
/*!
* I2C read function map to ESP platform
*/
BMA4_INTF_RET_TYPE bma4_i2c_read(uint8_t reg_addr, uint8_t *reg_data,
uint32_t len, void *intf_ptr) {
// ESP_ERROR_CHECK(i2c_master_receive(bma456_dev_handle, reg_data, len, -1));
esp_err_t err = i2c_master_transmit_receive(bma456_dev_handle, &reg_addr, 1,
reg_data, len, -1);
return (err == ESP_OK) ? BMA4_OK : BMA4_E_COM_FAIL;
// return BMA4_OK;
}
/*!
* I2C write function map to ESP platform
*/
BMA4_INTF_RET_TYPE bma4_i2c_write(uint8_t reg_addr, const uint8_t *reg_data,
uint32_t len, void *intf_ptr) {
// ESP_ERROR_CHECK(i2c_master_transmit(bma456_dev_handle, reg_data, len, -1));
// Bei Bosch muss zuerst das Register, dann die Daten in einem Transfer
// gesendet werden
uint8_t *buffer = malloc(len + 1);
if (!buffer)
return BMA4_E_NULL_PTR;
buffer[0] = reg_addr;
ESP_LOGI("I2CWrite", "Message Length: %d", len);
memcpy(&buffer[1], reg_data, len);
esp_err_t err = i2c_master_transmit(bma456_dev_handle, buffer, len + 1, -1);
free(buffer);
return (err == ESP_OK) ? BMA4_OK : BMA4_E_COM_FAIL;
// return BMA4_OK;
}
/*!
* Delay function map to ESP platform
*/
void bma4_delay_us(uint32_t period, void *intf_ptr) {
uint32_t wait_ms = period / 1000;
uint32_t wait_us = period % 1000;
if (wait_ms) {
vTaskDelay(pdMS_TO_TICKS(wait_ms));
}
ets_delay_us(wait_us);
}
/*!
* @brief Prints the execution status of the APIs.
*/
void bma4_error_codes_print_result(const char api_name[], int8_t rslt) {
if (rslt != BMA4_OK) {
ESP_LOGI("BMA4_I2C", "%s\t", api_name);
if (rslt == BMA4_E_NULL_PTR) {
ESP_LOGI("BMA4_I2C", "Error [%d] : Null pointer\r\n", rslt);
} else if (rslt == BMA4_E_COM_FAIL) {
ESP_LOGI("BMA4_I2C", "Error [%d] : Communication failure\r\n", rslt);
} else if (rslt == BMA4_E_CONFIG_STREAM_ERROR) {
ESP_LOGI("BMA4_I2C", "Error [%d] : Invalid configuration stream\r\n",
rslt);
} else if (rslt == BMA4_E_SELF_TEST_FAIL) {
ESP_LOGI("BMA4_I2C", "Error [%d] : Self test failed\r\n", rslt);
} else if (rslt == BMA4_E_INVALID_SENSOR) {
ESP_LOGI("BMA4_I2C", "Error [%d] : Device not found\r\n", rslt);
} else if (rslt == BMA4_E_OUT_OF_RANGE) {
ESP_LOGI("BMA4_I2C", "Error [%d] : Out of Range\r\n", rslt);
} else if (rslt == BMA4_E_AVG_MODE_INVALID_CONF) {
ESP_LOGI("BMA4_I2C",
"Error [%d] : Invalid bandwidth and ODR combination in Accel "
"Averaging mode\r\n",
rslt);
} else {
/* For more error codes refer "*_defs.h" */
ESP_LOGI("BMA4_I2C", "Error [%d] : Unknown error code\r\n", rslt);
}
}
}
void init_i2c() {
i2c_master_bus_config_t i2c_mst_config = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.i2c_port = I2C_PORT,
.scl_io_num = I2C_MASTER_SCL_IO,
.sda_io_num = I2C_MASTER_SDA_IO,
.glitch_ignore_cnt = 7,
//.flags.enable_internal_pullup = true,
};
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
}
void read_sensor_task(void *params) {
int8_t ret;
struct bma4_accel sens_data = {0};
while (1) {
ret = bma4_read_accel_xyz(&sens_data, &bma456_struct);
bma4_error_codes_print_result("bma4_read_accel_xyz", ret);
ESP_LOGI("ACC", "X: %d, Y: %d, Z: %d", sens_data.x, sens_data.y,
sens_data.z);
if (interrupt_status) {
ESP_LOGI("INTERRUPT", "Da war der Interrupt resetting");
interrupt_status = 0;
ret = bma456h_read_int_status(&int_status, &bma456_struct);
bma4_error_codes_print_result("bma456w_step_counter_output status", ret);
int8_t rslt;
struct bma456h_out_state tap_out = {0};
rslt = bma456h_output_state(&tap_out, &bma456_struct);
if (BMA4_OK == rslt) {
/* Enters only if the obtained interrupt is single-tap */
if (tap_out.single_tap) {
ESP_LOGI("INTERRUPT", "Single Tap interrupt occurred\n");
}
/* Enters only if the obtained interrupt is double-tap */
else if (tap_out.double_tap) {
ESP_LOGI("INTERRUPT", "Double Tap interrupt occurred\n");
}
/* Enters only if the obtained interrupt is triple-tap */
else if (tap_out.triple_tap) {
ESP_LOGI("INTERRUPT", "Triple Tap interrupt occurred\n");
}
}
}
// ESP_LOGI("i2c", "X:%d, Y%d, Z%d", sens_data.x, sens_data.y, sens_data.z);
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void init_bma456() {
i2c_device_config_t dev_cfg_bma456 = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = BMA456_ADDRESS,
.scl_speed_hz = 100000,
};
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg_bma456,
&bma456_dev_handle));
bma456_struct.intf = BMA4_I2C_INTF;
bma456_struct.bus_read = bma4_i2c_read;
bma456_struct.bus_write = bma4_i2c_write;
bma456_struct.delay_us = bma4_delay_us;
bma456_struct.read_write_len = BMA4_READ_WRITE_LEN;
bma456_struct.intf_ptr = &bma456_dev_handle;
int8_t ret;
bma456_struct.chip_id = 0;
ret = bma456h_init(&bma456_struct);
bma4_error_codes_print_result("I2C Init", ret);
ESP_LOGI("I2C", "Chip Init ausgelesene CHIP ID %d", bma456_struct.chip_id);
ret = bma4_soft_reset(&bma456_struct);
bma4_error_codes_print_result("bma4_soft_reset", ret);
vTaskDelay(pdMS_TO_TICKS(20)); // Wartezeit nach Reset
ret = bma4_set_advance_power_save(BMA4_DISABLE, &bma456_struct);
bma4_error_codes_print_result("bma4_set_advance_power_save", ret);
vTaskDelay(pdMS_TO_TICKS(10));
ESP_LOGI("I2C", "Config SIZE %d", bma456_struct.config_size);
ESP_LOGI("I2C", "Config Pointer %p", bma456_struct.config_file_ptr);
ESP_LOGI("I2C", "Starte Config-File Upload...");
ret = bma456h_write_config_file(&bma456_struct);
bma4_error_codes_print_result("bma4_write_config_file", ret);
struct bma4_accel_config accel_config;
bma4_get_accel_config(&accel_config, &bma456_struct);
accel_config.range = BMA4_ACCEL_RANGE_2G;
ret = bma4_set_accel_config(&accel_config, &bma456_struct);
bma4_error_codes_print_result("bma4_set_accel_config status", ret);
/* Enable the accelerometer */
ret = bma4_set_accel_enable(BMA4_ENABLE, &bma456_struct);
bma4_error_codes_print_result("bma4_set_accel_enable status", ret);
struct bma456h_multitap_settings tap_settings = {0};
ret = bma456h_tap_get_parameter(&tap_settings, &bma456_struct);
bma4_error_codes_print_result("bma456h_tap_get_parameter status", ret);
tap_settings.tap_sens_thres = 0;
ret = bma456h_tap_set_parameter(&tap_settings, &bma456_struct);
bma4_error_codes_print_result("bma456h_tap_set_parameter status", ret);
ret = bma456h_feature_enable(
(BMA456H_SINGLE_TAP_EN | BMA456H_DOUBLE_TAP_EN | BMA456H_TRIPLE_TAP_EN),
BMA4_ENABLE, &bma456_struct);
bma4_error_codes_print_result("bma456w_feature_enable status", ret);
/* Setting watermark level 1, the output step resolution is 20 steps.
* Eg: 1 means, 1 * 20 = 20. Every 20 steps once output triggers
*/
ret = bma456h_step_counter_set_watermark(1, &bma456_struct);
bma4_error_codes_print_result("bma456w_step_counter_set_watermark status",
ret);
/* Hardware interrupt configuration */
int_line = BMA4_INTR2_MAP;
ret = bma4_get_int_pin_config(&pin_config, int_line, &bma456_struct);
bma4_error_codes_print_result("bma4_get_int_pin_config status", ret);
ret = bma456h_map_interrupt(int_line, BMA456H_TAP_OUT_INT, BMA4_ENABLE,
&bma456_struct);
bma4_error_codes_print_result("bma456w_map_interrupt status", ret);
pin_config.edge_ctrl = BMA4_EDGE_TRIGGER;
pin_config.output_en = BMA4_OUTPUT_ENABLE;
pin_config.lvl = BMA4_ACTIVE_HIGH;
pin_config.od = BMA4_PUSH_PULL;
pin_config.input_en = BMA4_INPUT_DISABLE;
ret = bma4_set_int_pin_config(&pin_config, int_line, &bma456_struct);
bma4_error_codes_print_result("bma4_set_int_pin_config status", ret);
gpio_reset_pin(BMA456W_INT_PIN);
gpio_set_direction(BMA456W_INT_PIN, GPIO_MODE_INPUT);
gpio_set_pull_mode(BMA456W_INT_PIN, GPIO_PULLDOWN_ONLY);
gpio_set_intr_type(BMA456W_INT_PIN, GPIO_INTR_POSEDGE);
gpio_intr_enable(BMA456W_INT_PIN);
gpio_install_isr_service(0);
gpio_isr_handler_add(BMA456W_INT_PIN, interrupt_callback,
(void *)BMA456W_INT_PIN);
xTaskCreate(read_sensor_task, "READ_SENSOR", 4096, NULL, 1, NULL);
}
void init_i2c_with_all_devices() {
init_i2c();
init_bma456();
}
+8
View File
@@ -0,0 +1,8 @@
#define I2C_PORT 0
#define I2C_MASTER_SCL_IO 5
#define I2C_MASTER_SDA_IO 6
#define BMA456_ADDRESS 0x18
void init_i2c();
void init_bma456();
void init_i2c_with_all_devices();
+239 -75
View File
@@ -1,7 +1,15 @@
#include "client_handler.h" #include "client_handler.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "driver/uart.h" #include "driver/uart.h"
#include "esp_app_desc.h"
#include "esp_app_format.h"
#include "esp_err.h"
#include "esp_flash_partitions.h"
#include "esp_image_format.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_log_buffer.h"
#include "esp_ota_ops.h"
#include "esp_partition.h"
#include "esp_phy_init.h" #include "esp_phy_init.h"
#include "esp_rom_gpio.h" #include "esp_rom_gpio.h"
#include "esp_timer.h" #include "esp_timer.h"
@@ -10,44 +18,102 @@
#include "hal/uart_types.h" #include "hal/uart_types.h"
#include "message_handler.h" #include "message_handler.h"
#include "message_parser.h" #include "message_parser.h"
#include "nvs.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "glob.h"
#include "communication_handler.h" #include "communication_handler.h"
#include "main.h" #include "main.h"
#include "portmacro.h" #include "ota_update.h"
#include "uart_handler.h" #include "uart_handler.h"
#include <math.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include "message_builder.h" #include "message_builder.h"
#include "uart_msg_ids.h"
typedef struct { #include "i2c.h"
QueueHandle_t message_queue;
uint8_t *send_buffer;
size_t send_buffer_size;
} MessageBrokerTaskParams_t;
static const char *TAG = "ALOX - MAIN"; static const char *TAG = "ALOX - MAIN";
static const uint16_t version = 0x0001; static const uint16_t version = 0x0001;
static uint8_t send_message_buffer[1024]; static uint8_t send_message_buffer[1024];
static uint8_t send_message_payload_buffer[512];
uint32_t g_uart_firmware_total_size = 0;
static MessageBrokerTaskParams_t broker_task_params; static MessageBrokerTaskParams_t broker_task_params;
static MasterOTA_TaskParams_t master_ota_task_params;
static ESP_MessageBrokerTaskParams_t esp_broker_task_params;
ClientList clientList = {.Clients = {{0}}, .ClientCount = 0}; ClientList clientList = {.Clients = {{0}}, .ClientCount = 0};
typedef void (*RegisterTaskCallback)(uint8_t msgid, const uint8_t *payload, size_t build_ClientInfoPart(uint8_t clientid, float_t lagex, float_t lagey,
size_t payload_len, uint8_t *send_buffer, int32_t bitmask, uint8_t *outputArray,
size_t send_buffer_size); size_t outputArrayOffset, size_t outputArraySize) {
size_t offset = outputArrayOffset;
memcpy(&outputArray[offset], &clientid, sizeof(clientid));
offset += sizeof(clientid);
// lagex (typischerweise 4 Bytes)
memcpy(&outputArray[offset], &lagex, sizeof(lagex));
offset += sizeof(lagex);
// lagey (typischerweise 4 Bytes)
memcpy(&outputArray[offset], &lagey, sizeof(lagey));
offset += sizeof(lagey);
// bitmask (4 Bytes)
memcpy(&outputArray[offset], &bitmask, sizeof(bitmask));
offset += sizeof(bitmask);
return offset - outputArrayOffset;
}
void fakeDataCallback(uint8_t msgid, const uint8_t *payload, size_t payload_len,
uint8_t *send_payload_buffer,
size_t send_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size) {
uint8_t seed = payload[1];
ESP_LOGI(TAG, "Sending Fake Client Infos with seed %d", seed);
srand(seed);
size_t offset = 1;
send_payload_buffer[0] = 3; // Client Count
offset +=
build_ClientInfoPart(1, rand() * 1.0, rand() * 1.0, rand() * 1,
send_payload_buffer, 1, send_payload_buffer_size);
offset += build_ClientInfoPart(2, rand() * 2.0, rand() * 2.0, rand() * 2,
send_payload_buffer, offset,
send_payload_buffer_size);
offset += build_ClientInfoPart(3, rand() * 3.0, rand() * 3.0, rand() * 3,
send_payload_buffer, offset,
send_payload_buffer_size);
int len = build_message(UART_CLIENT_INPUT, send_payload_buffer, offset,
send_buffer, send_buffer_size);
if (len < 0) {
ESP_LOGE(TAG,
"Error Building UART Message: payload_len, %d, sendbuffer_size: "
"%d, mes_len(error): %d",
payload_len, send_buffer_size, len);
return;
}
uart_write_bytes(MASTER_UART, send_buffer, len);
}
void echoCallback(uint8_t msgid, const uint8_t *payload, size_t payload_len, void echoCallback(uint8_t msgid, const uint8_t *payload, size_t payload_len,
uint8_t *send_payload_buffer, size_t send_payload_buffer_size,
uint8_t *send_buffer, size_t send_buffer_size) { uint8_t *send_buffer, size_t send_buffer_size) {
// Code für den Button-Press
ESP_LOGI(TAG, "Echo command 0x01..."); ESP_LOGI(TAG, "Echo command 0x01...");
int len = int len = build_message(UART_ECHO, payload, payload_len, send_buffer,
build_message(0x01, payload, payload_len, send_buffer, send_buffer_size); send_buffer_size);
if (len < 0) { if (len < 0) {
ESP_LOGE(TAG, ESP_LOGE(TAG,
"Error Building UART Message: payload_len, %d, sendbuffer_size: " "Error Building UART Message: payload_len, %d, sendbuffer_size: "
@@ -60,18 +126,25 @@ void echoCallback(uint8_t msgid, const uint8_t *payload, size_t payload_len,
} }
void versionCallback(uint8_t msgid, const uint8_t *payload, size_t payload_len, void versionCallback(uint8_t msgid, const uint8_t *payload, size_t payload_len,
uint8_t *send_buffer, size_t send_buffer_size) { uint8_t *send_payload_buffer,
// Code für den Button-Press size_t send_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size) {
ESP_LOGI(TAG, "Version command 0x02..."); ESP_LOGI(TAG, "Version command 0x02...");
size_t git_build_hash_len = strlen(BUILD_GIT_HASH); size_t git_build_hash_len = strlen(BUILD_GIT_HASH);
size_t needed_buffer_size = 2 + git_build_hash_len;
uint8_t send_payload[2 + git_build_hash_len]; if (send_payload_buffer_size < needed_buffer_size) {
send_payload[0] = (uint8_t)(version & 0xFF); ESP_LOGE(TAG, "send_payload_buffer to small size %d need %d",
send_payload[1] = (uint8_t)((version >> 8) & 0xFF); send_payload_buffer_size, needed_buffer_size);
memcpy(&send_payload[2], &BUILD_GIT_HASH, git_build_hash_len); return;
}
int len = build_message(0x02, send_payload, sizeof(send_payload), send_buffer, send_payload_buffer[0] = (uint8_t)(version & 0xFF);
send_buffer_size); send_payload_buffer[1] = (uint8_t)((version >> 8) & 0xFF);
memcpy(&send_payload_buffer[2], &BUILD_GIT_HASH, git_build_hash_len);
int len = build_message(UART_VERSION, send_payload_buffer, needed_buffer_size,
send_buffer, send_buffer_size);
if (len < 0) { if (len < 0) {
ESP_LOGE(TAG, ESP_LOGE(TAG,
"Error Building UART Message: payload_len, %d, sendbuffer_size: " "Error Building UART Message: payload_len, %d, sendbuffer_size: "
@@ -83,64 +156,115 @@ void versionCallback(uint8_t msgid, const uint8_t *payload, size_t payload_len,
} }
void clientInfoCallback(uint8_t msgid, const uint8_t *payload, void clientInfoCallback(uint8_t msgid, const uint8_t *payload,
size_t payload_len, uint8_t *send_buffer, size_t payload_len, uint8_t *send_payload_buffer,
size_t send_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size) { size_t send_buffer_size) {
ESP_LOGI(TAG, "Client Info Command 0x03..."); ESP_LOGI(TAG, "Client Info Command 0x03...");
static uint8_t entryLength = 17; static uint8_t entryLength = 19;
uint8_t needed_buffer_size = 1 + entryLength * clientList.ClientCount;
ESP_LOGE(TAG, "clientList.ClientCount = %d", clientList.ClientCount); if (send_payload_buffer_size < needed_buffer_size) {
ESP_LOGE(TAG, "send_payload_buffer to small size %d need %d",
send_payload_buffer_size, needed_buffer_size);
return;
}
uint8_t payload_size = 1 + entryLength * clientList.ClientCount; send_payload_buffer[0] = clientList.ClientCount;
ESP_LOGE(TAG, "payload_size = %d", payload_size);
uint8_t send_payload[payload_size];
send_payload[0] = clientList.ClientCount;
uint8_t offsetMult = 0; uint8_t offsetMult = 0;
uint8_t used_slots = 0;
for (int i = 0; i < MAX_CLIENTS; i++) { for (int i = 0; i < MAX_CLIENTS; i++) {
if (clientList.Clients[i].slotIsUsed) { if (clientList.Clients[i].slotIsUsed) {
used_slots++;
}
}
ESP_LOGE("SPECIAL", "USED SLOTS: %d", used_slots);
uint8_t loop_sanity_counter = 0;
for (int i = 0; i < MAX_CLIENTS; i++) {
if (clientList.Clients[i].slotIsUsed) {
loop_sanity_counter++;
if (loop_sanity_counter > clientList.ClientCount) {
ESP_LOGE("SPECIAL", "DAS KANN NICHT SEIN");
ESP_LOGE("SPECIAL", "loop_santy_count: %d, client_count: %d", loop_sanity_counter, clientList.ClientCount);
}
size_t offset = 1 + (entryLength * offsetMult++); size_t offset = 1 + (entryLength * offsetMult++);
send_payload_buffer[offset] = i;
ESP_LOGE("SPECIAL", "OFFSET %d", offset); send_payload_buffer[offset + 1] = clientList.Clients[i].isAvailable;
send_payload[offset] = i; send_payload_buffer[offset + 2] = clientList.Clients[i].slotIsUsed;
send_payload[offset + 1] = clientList.Clients[i].isAvailable; memcpy(&send_payload_buffer[offset + 3], clientList.Clients[i].macAddr,
send_payload[offset + 2] = clientList.Clients[i].slotIsUsed;
memcpy(&send_payload[offset + 3], clientList.Clients[i].macAddr,
MAC_LENGTH); MAC_LENGTH);
memcpy(&send_payload[offset + 9], &clientList.Clients[i].lastPing, 4); memcpy(&send_payload_buffer[offset + 9], &clientList.Clients[i].lastPing,
memcpy(&send_payload[offset + 13], 4);
memcpy(&send_payload_buffer[offset + 13],
&clientList.Clients[i].lastSuccessfullPing, 4); &clientList.Clients[i].lastSuccessfullPing, 4);
memcpy(&send_payload_buffer[offset + 17],
&clientList.Clients[i].clientVersion, 2);
} }
} }
int len = build_message(0x04, send_payload, sizeof(send_payload), send_buffer, int len = build_message(UART_CLIENT_INFO, send_payload_buffer,
send_buffer_size); needed_buffer_size, send_buffer, send_buffer_size);
if (len < 0) { if (len < 0) {
ESP_LOGE(TAG, ESP_LOGE(TAG,
"Error Building UART Message: payload_len, %d, sendbuffer_size: " "Error Building UART Message: payload_len, %d, sendbuffer_size: "
"%d, mes_len(error): %d", "%d, mes_len(error): %d",
payload_len, send_buffer_size, len); needed_buffer_size, send_buffer_size, len);
return; return;
} }
uart_write_bytes(MASTER_UART, send_buffer, len); uart_write_bytes(MASTER_UART, send_buffer, len);
} }
bool g_ota_in_progress = false;
void ota_monitor_task(void *param) {
const TickType_t timeout = pdMS_TO_TICKS(10000); // 10 seconds
while (g_ota_in_progress) {
bool all_done = true;
for (int i = 0; i < MAX_CLIENTS; i++) {
if (clientList.Clients[i].slotIsUsed) {
if (clientList.Clients[i].ota_status != OTA_SUCCESS &&
clientList.Clients[i].ota_status != OTA_FAILED) {
all_done = false;
if ((xTaskGetTickCount() - clientList.Clients[i].last_seen) >
timeout) {
ESP_LOGE(TAG, "Client %d timed out", i);
clientList.Clients[i].ota_status = OTA_FAILED;
}
}
}
}
if (all_done) {
g_ota_in_progress = false;
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
ESP_LOGI(TAG, "OTA Operation Finished.");
for (int i = 0; i < MAX_CLIENTS; i++) {
if (clientList.Clients[i].slotIsUsed) {
ESP_LOGI(TAG, "Client %d [MAC: " MACSTR "]: %s, Resent Chunks: %d", i,
MAC2STR(clientList.Clients[i].macAddr),
clientList.Clients[i].ota_status == OTA_SUCCESS ? "SUCCESS"
: "FAILED",
clientList.Clients[i].resent_chunks_counter);
}
}
vTaskDelete(NULL);
}
void send_client_ota_start_message(uint8_t clientID, uint32_t app_size) {
BaseMessage message = {};
OTA_PREPARE_FOR_UPDATE_Payload ota_payload = {
.total_size = app_size,
};
message = MessageBuilder(OTA_PREPARE_FOR_UPDATE,
*(PayloadUnion *)&ota_payload, sizeof(ota_payload));
esp_err_t err = esp_now_send(clientList.Clients[clientID].macAddr,
(uint8_t *)&message, sizeof(BaseMessage));
if (err != ESP_OK) {
ESP_LOGE(TAG, "Could not send OTA PREPARE FOR UPDATE to " MACSTR ", %s",
MAC2STR(clientList.Clients[clientID].macAddr),
esp_err_to_name(err));
} else {
ESP_LOGI(TAG, "Sent OTA PREPARE FOR UPDATE to " MACSTR,
MAC2STR(clientList.Clients[clientID].macAddr));
}
}
void app_main(void) { void app_main(void) {
ESP_LOGI(TAG, "Starting Alox Powerpod Version %d Build: %s", version, ESP_LOGI(TAG, "Starting Alox Powerpod Version %d Build: %s", version,
BUILD_GIT_HASH); BUILD_GIT_HASH);
@@ -153,12 +277,10 @@ void app_main(void) {
} }
ESP_ERROR_CHECK(ret); ESP_ERROR_CHECK(ret);
// GPIO-Pin für Moduserkennung
gpio_reset_pin(MASTER_MODE_PIN); gpio_reset_pin(MASTER_MODE_PIN);
gpio_set_direction(MASTER_MODE_PIN, GPIO_MODE_INPUT); gpio_set_direction(MASTER_MODE_PIN, GPIO_MODE_INPUT);
bool isMaster = (gpio_get_level(MASTER_MODE_PIN) == 0); bool isMaster = (gpio_get_level(MASTER_MODE_PIN) == 0);
// ESP-NOW Initialisieren
ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default()); ESP_ERROR_CHECK(esp_event_loop_create_default());
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
@@ -166,8 +288,7 @@ void app_main(void) {
wifi_config_t wifi_config = { wifi_config_t wifi_config = {
.sta = .sta =
{ {
.channel = 1, // Kanal 1, stelle sicher, dass alle Geräte .channel = 1,
// denselben Kanal verwenden
}, },
}; };
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
@@ -181,42 +302,85 @@ void app_main(void) {
ESP_ERROR_CHECK(esp_now_register_recv_cb(client_receive_callback)); ESP_ERROR_CHECK(esp_now_register_recv_cb(client_receive_callback));
} }
init_com(&clientList); ret = init_com(&clientList, 1);
if (ret < 0) {
ESP_LOGE(TAG, "Could not Init ESP NOW Communication!");
}
const esp_partition_t *running = esp_ota_get_running_partition();
ESP_LOGI(TAG, "OTA: Running Partition: %s", running->label);
esp_ota_img_states_t ota_state;
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
bool diagnostic_is_ok = true; // TODO build in valid diagnostics
if (diagnostic_is_ok) {
esp_ota_mark_app_valid_cancel_rollback();
} else {
// esp_ota_mark_app_invalid_rollback(); Put this function at the start
// so when the esp crashes it can rollback
esp_ota_mark_app_invalid_rollback_and_reboot();
}
}
}
const esp_partition_t *next_ota_partition =
esp_ota_get_next_update_partition(NULL);
int app_size = get_app_size(next_ota_partition);
ESP_LOGE(TAG, "App Size in Other Partition %d", app_size);
QueueHandle_t espnow_message_queue =
xQueueCreate(10, sizeof(ESPNOW_MessageInfo));
ESP_InitMessageBroker(espnow_message_queue);
esp_broker_task_params.message_queue = espnow_message_queue;
xTaskCreate(ESP_MessageBrokerTask, "espnow_message_broker_task", 4096,
(void *)&esp_broker_task_params, 4, NULL);
init_ota();
// Tasks starten basierend auf Master/Client
if (isMaster) { if (isMaster) {
ESP_LOGI(TAG, "Started in Mastermode"); ESP_LOGI(TAG, "Started in Mastermode");
ESPNOW_RegisterMasterCallbacks();
ESPNOW_RegisterOTAMaster();
add_peer(broadcast_address); add_peer(broadcast_address);
xTaskCreate(master_broadcast_task, "MasterBroadcast", 4096, NULL, 1, NULL); xTaskCreate(master_broadcast_task, "MasterBroadcast", 4096, NULL, 1, NULL);
// xTaskCreate(master_ping_task, "MasterPing", 4096, NULL, 1, NULL);
xTaskCreate(master_broadcast_ping, "MasterBroadcastPing", 4096, NULL, 1, xTaskCreate(master_broadcast_ping, "MasterBroadcastPing", 4096, NULL, 1,
NULL); NULL);
// xTaskCreate(client_monitor_task, "MonitorClientTask", 4096, NULL, 1,
// NULL);
QueueHandle_t parsed_message_queue = QueueHandle_t parsed_message_queue =
xQueueCreate(10, sizeof(ParsedMessage_t)); xQueueCreate(10, sizeof(ParsedMessage_t));
init_uart(parsed_message_queue); init_uart(parsed_message_queue);
InitMessageBroker(); InitMessageBroker();
// Initialisiere die Parameterstruktur
broker_task_params.message_queue = parsed_message_queue; broker_task_params.message_queue = parsed_message_queue;
broker_task_params.send_buffer = send_message_buffer; broker_task_params.send_buffer = send_message_buffer;
broker_task_params.send_buffer_size = sizeof(send_message_buffer); broker_task_params.send_buffer_size = sizeof(send_message_buffer);
broker_task_params.payload_buffer = send_message_payload_buffer;
broker_task_params.payload_buffer_size =
sizeof(send_message_payload_buffer);
xTaskCreate(MessageBrokerTask, "message_handler_task", 4096, xTaskCreate(MessageBrokerTask, "MessageHandler", 4096,
(void *)&broker_task_params, 5, NULL); (void *)&broker_task_params, 5, NULL);
RegisterCallback(0x01, echoCallback); master_ota_task_params.client_list = &clientList;
RegisterCallback(0x02, versionCallback); xTaskCreate(MasterOTATask, "MasterOTATask", 4096,
RegisterCallback(0x03, clientInfoCallback); (void *)&master_ota_task_params, 4, NULL);
RegisterCallback(UART_ECHO, echoCallback);
RegisterCallback(UART_VERSION, versionCallback);
RegisterCallback(UART_CLIENT_INFO, clientInfoCallback);
RegisterCallback(UART_CLIENT_INPUT, fakeDataCallback);
RegisterCallback(UART_OTA_START_ESPNOW, start_ota_update_espnow);
RegisterUART_OTAFunctions();
// init_i2c_with_all_devices();
// xTaskCreate(uart_status_task, "MasterUartStatusTask", 4096, NULL, 1,
// NULL); xTaskCreate(SendClientInfoTask, "SendCientInfo", 4096, NULL, 1,
// NULL);
} else { } else {
ESP_LOGI(TAG, "Started in Slavemode"); ESP_LOGI(TAG, "Started in Slavemode");
xTaskCreate(client_data_sending_task, "ClientDataSending", 4096, NULL, 1, ESPNOW_RegisterSlaveCallbacks();
NULL); xTaskCreate(slave_ota_task, "SlaveOTATask", 4096, NULL, 4, NULL);
ESPNOW_RegisterOTASlave();
} }
} }
+4 -1
View File
@@ -14,6 +14,9 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#ifdef CONFIG_IDF_TARGET_ESP32S3
#define MASTER_MODE_PIN GPIO_NUM_1 // Jumper-Erkennungspin
#elif CONFIG_IDF_TARGET_ESP32C3
#define MASTER_MODE_PIN GPIO_NUM_0 // Jumper-Erkennungspin #define MASTER_MODE_PIN GPIO_NUM_0 // Jumper-Erkennungspin
#endif
#endif #endif
+2 -3
View File
@@ -20,8 +20,8 @@ bool add_byte_with_length_check(uint8_t byte, size_t write_index, uint8_t *data,
int build_message(uint8_t msgid, const uint8_t *payload, size_t payload_len, int build_message(uint8_t msgid, const uint8_t *payload, size_t payload_len,
uint8_t *msg_buffer, size_t msg_buffer_size) { uint8_t *msg_buffer, size_t msg_buffer_size) {
ESP_LOGE("BM", "payload_len %d, msg_buffer_size %d", payload_len + 4, //ESP_LOGE("BM", "payload_len %d, msg_buffer_size %d", payload_len + 4,
msg_buffer_size); // msg_buffer_size);
if (payload_len + 4 > msg_buffer_size) { if (payload_len + 4 > msg_buffer_size) {
return PayloadBiggerThenBuffer; return PayloadBiggerThenBuffer;
} }
@@ -75,6 +75,5 @@ int build_message(uint8_t msgid, const uint8_t *payload, size_t payload_len,
msg_buffer[write_index++] = checksum; msg_buffer[write_index++] = checksum;
msg_buffer[write_index++] = EndByte; msg_buffer[write_index++] = EndByte;
ESP_LOGE("BM", "MESSAGE FERTIG GEBAUT");
return write_index; return write_index;
} }
+8 -8
View File
@@ -6,12 +6,6 @@
static struct MessageBroker mr; static struct MessageBroker mr;
static char *TAG = "ALOX - Message Handler"; static char *TAG = "ALOX - Message Handler";
typedef struct {
QueueHandle_t message_queue;
uint8_t *send_buffer;
size_t send_buffer_size;
} MessageBrokerTaskParams_t;
void InitMessageBroker() { void InitMessageBroker() {
mr.num_direct_callbacks = 0; mr.num_direct_callbacks = 0;
mr.num_task_callbacks = 0; mr.num_task_callbacks = 0;
@@ -19,6 +13,7 @@ void InitMessageBroker() {
} }
void RegisterCallback(uint8_t msgid, RegisterFunctionCallback callback) { void RegisterCallback(uint8_t msgid, RegisterFunctionCallback callback) {
ESP_LOGI(TAG, "Registerd Uart Callback for % X", msgid);
mr.FunctionList[mr.num_direct_callbacks].MSGID = msgid; mr.FunctionList[mr.num_direct_callbacks].MSGID = msgid;
mr.FunctionList[mr.num_direct_callbacks].callback = callback; mr.FunctionList[mr.num_direct_callbacks].callback = callback;
mr.num_direct_callbacks++; mr.num_direct_callbacks++;
@@ -40,6 +35,8 @@ void MessageBrokerTask(void *param) {
QueueHandle_t msg_queue = task_params->message_queue; QueueHandle_t msg_queue = task_params->message_queue;
uint8_t *send_message_buffer = task_params->send_buffer; uint8_t *send_message_buffer = task_params->send_buffer;
size_t send_message_buffer_size = task_params->send_buffer_size; size_t send_message_buffer_size = task_params->send_buffer_size;
uint8_t *send_payload_buffer = task_params->payload_buffer;
size_t send_payload_buffer_size = task_params->payload_buffer_size;
if (msg_queue == NULL) { if (msg_queue == NULL) {
ESP_LOGE(TAG, "Message queue not initialized. Terminating task."); ESP_LOGE(TAG, "Message queue not initialized. Terminating task.");
@@ -50,13 +47,16 @@ void MessageBrokerTask(void *param) {
while (1) { while (1) {
if (xQueueReceive(msg_queue, &received_msg, portMAX_DELAY)) { if (xQueueReceive(msg_queue, &received_msg, portMAX_DELAY)) {
ESP_LOGI(TAG, "Received message from queue: MSGID=0x%02X, Length=%u", // ESP_LOGI(TAG, "Received message from queue: MSGID=0x%02X, Length=%u",
received_msg.msgid, received_msg.payload_len); // received_msg.msgid, received_msg.payload_len);
for (int i = 0; i < mr.num_direct_callbacks; i++) { for (int i = 0; i < mr.num_direct_callbacks; i++) {
//ESP_LOGI(TAG, "Searching CALLBACK for %d", received_msg.msgid);
if (mr.FunctionList[i].MSGID == received_msg.msgid) { if (mr.FunctionList[i].MSGID == received_msg.msgid) {
//ESP_LOGI(TAG, "FOUND CALLBACK");
mr.FunctionList[i].callback( mr.FunctionList[i].callback(
received_msg.msgid, received_msg.data, received_msg.payload_len, received_msg.msgid, received_msg.data, received_msg.payload_len,
send_payload_buffer, send_payload_buffer_size,
send_message_buffer, send_message_buffer_size); send_message_buffer, send_message_buffer_size);
} }
} }
+15 -1
View File
@@ -5,12 +5,26 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
typedef struct {
QueueHandle_t message_queue;
uint8_t *send_buffer;
size_t send_buffer_size;
uint8_t *payload_buffer;
size_t payload_buffer_size;
} MessageBrokerTaskParams_t;
typedef void (*RegisterFunctionCallback)(uint8_t msgid, const uint8_t *payload, typedef void (*RegisterFunctionCallback)(uint8_t msgid, const uint8_t *payload,
size_t payload_len, size_t payload_len,
uint8_t *send_payload_buffer,
size_t send_payload_buffer_size,
uint8_t *send_buffer, uint8_t *send_buffer,
size_t send_buffer_size); size_t send_buffer_size);
typedef void (*RegisterTaskCallback)(uint8_t msgid, const uint8_t *payload, typedef void (*RegisterTaskCallback)(uint8_t msgid, const uint8_t *payload,
size_t payload_len, uint8_t *send_buffer, size_t payload_len,
uint8_t *send_payload_buffer,
size_t send_payload_buffer_size,
uint8_t *send_buffer,
size_t send_buffer_size); size_t send_buffer_size);
struct RegisterdFunction { struct RegisterdFunction {
+2 -2
View File
@@ -4,7 +4,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#define MAX_MESSAGE_PAYLOAD_LENGTH 128 #define MAX_MESSAGE_PAYLOAD_LENGTH 512
#define MAX_TOTAL_CONTENT_LENGTH (MAX_MESSAGE_PAYLOAD_LENGTH + 1) #define MAX_TOTAL_CONTENT_LENGTH (MAX_MESSAGE_PAYLOAD_LENGTH + 1)
enum ParserState { enum ParserState {
@@ -33,7 +33,7 @@ struct MessageReceive {
enum ParserError error; enum ParserError error;
uint8_t messageid; uint8_t messageid;
uint8_t message[MAX_MESSAGE_PAYLOAD_LENGTH]; uint8_t message[MAX_MESSAGE_PAYLOAD_LENGTH];
uint8_t index; uint16_t index;
uint8_t checksum; uint8_t checksum;
}; };
+124
View File
@@ -0,0 +1,124 @@
#ifndef MESSAGE_STRUCTS_H
#define MESSAGE_STRUCTS_H
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MACSTR "%02X:%02X:%02X:%02X:%02X:%02X"
typedef enum {
OTA_PREPARE_FOR_UPDATE,
OTA_PREPARE_ACKNOWLEDGED,
OTA_READY_TO_RECEIVE,
OTA_CHUNK,
OTA_REQUEST_BLOCK_STATUS,
OTA_BLOCK_STATUS_REPORT,
OTA_COMMIT_BLOCK,
OTA_BLOCK_COMMITTED,
OTA_FINISH_UPDATE,
OTA_UPDATE_STATUS,
OTA_UPDATE_SLAVE_ACKED,
MASTER_READY_TO_SEND_CHUNKS,
StatusPage,
GetStatusPage,
ConfigPage,
PingPage,
BroadCastPage,
RegisterPage,
} CommandPages;
typedef struct __attribute__((packed)) {
uint32_t total_size;
uint32_t block_size;
} OTA_PREPARE_FOR_UPDATE_Payload;
typedef struct __attribute__((packed)) {
// Empty
} OTA_PREPARE_ACKNOWLEDGED_Payload;
typedef struct __attribute__((packed)) {
uint8_t status; // 0 = READY, 1 = ERROR
} OTA_READY_TO_RECEIVE_Payload;
typedef struct __attribute__((packed)) {
uint16_t block_id;
uint8_t chunk_id;
uint8_t data_len;
uint8_t data[200];
} OTA_CHUNK_Payload;
typedef struct __attribute__((packed)) {
uint16_t block_id;
} OTA_REQUEST_BLOCK_STATUS_Payload;
typedef struct __attribute__((packed)) {
uint16_t block_id;
uint32_t chunk_bitmask;
} OTA_BLOCK_STATUS_REPORT_Payload;
typedef struct __attribute__((packed)) {
uint16_t block_id;
} OTA_COMMIT_BLOCK_Payload;
typedef struct __attribute__((packed)) {
uint16_t block_id;
} OTA_BLOCK_COMMITTED_Payload;
typedef struct __attribute__((packed)) {
// Empty
} OTA_FINISH_UPDATE_Payload;
typedef struct __attribute__((packed)) {
uint8_t status; // 0 = SUCCESS, 1 = FAILED
} OTA_UPDATE_STATUS_Payload;
typedef struct __attribute__((packed)) {
uint16_t current_block_id;
uint16_t update_buffer_write_index;
uint32_t update_size;
uint16_t sequenz_counter; // how often the update buffer gets written
uint8_t status; // 0 = SUCCESS, 1 = FAILED
} OTA_UPDATE_ACK_Payload;
typedef struct __attribute__((packed)) {
uint16_t version; // software version
uint8_t runningPartition;
uint8_t status;
uint32_t uptime;
} StatusPayload;
typedef struct __attribute__((packed)) {
} GetStatusPayload;
typedef struct __attribute__((packed)) {
uint8_t timeslot;
} ConfigPayload;
typedef struct __attribute__((packed)) {
uint32_t timestamp;
} PingPayload;
typedef struct __attribute__((packed)) {
} BroadCastPayload;
typedef struct __attribute__((packed)) {
bool familierClient;
} RegisterPayload;
// TODO: Check checksum fields
typedef struct __attribute__((packed)) {
uint16_t length; // length of complete firmware
uint8_t checksum; // checksum of firmware
} FirmwarePrepPayload;
// TODO: Check checksum fields
typedef struct __attribute__((packed)) {
uint8_t length;
uint8_t checksum;
uint32_t address;
uint8_t payload[240]; // TODO: need a way to figure out a safe value for this
} FirmwarePayload;
#endif // MESSAGE_STRUCTS_H
+678
View File
@@ -0,0 +1,678 @@
#include "ota_update.h"
#include "client_handler.h"
#include "communication_handler.h"
#include "driver/uart.h"
#include "esp_app_format.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_log_buffer.h"
#include "esp_now.h"
#include "esp_ota_ops.h"
#include "esp_partition.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "message_builder.h"
#include "message_handler.h"
#include "message_structs.h"
#include "uart_handler.h"
#include "uart_msg_ids.h"
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
static const char *TAG = "ALOX - OTA";
static QueueHandle_t ota_task_queue = NULL;
static esp_ota_handle_t update_handle = 0;
static uint8_t update_buffer[UPDATE_BUFFER_SIZE];
static uint8_t update_buffer_chunk[250];
static uint8_t update_buffer_chunk_len;
static uint32_t chunk_bitmask;
static uint16_t current_block_id;
static uint16_t update_buffer_write_index;
static uint32_t update_size;
static uint16_t sequenz_counter; // how often the update buffer gets written
static esp_partition_t partition_to_read_update_from;
static uint32_t partition_to_read_from_read_index;
static ClientList *client_list;
static bool all_chunks_send;
static bool finished;
uint32_t get_app_size(const esp_partition_t *app_size_partition) {
esp_app_desc_t app_desc;
esp_ota_get_partition_description(app_size_partition, &app_desc);
esp_image_header_t header;
esp_partition_read(app_size_partition, 0, &header, sizeof(header));
if (header.magic != ESP_IMAGE_HEADER_MAGIC) {
ESP_LOGE(TAG, "KEIN VALIDER HEADER");
return 0;
}
uint32_t data_len = sizeof(header);
for (int i = 0; i < header.segment_count; i++) {
esp_image_segment_header_t segment_header;
esp_partition_read(app_size_partition, data_len, &segment_header,
sizeof(segment_header));
ESP_LOGI(TAG, "SEGMENT %d Address %d, Segment DataLen %d", i,
segment_header.load_addr, segment_header.data_len);
uint32_t padded_len = (segment_header.data_len + 3) & ~3;
data_len += padded_len + sizeof(segment_header);
}
data_len += 1;
data_len += 32;
uint32_t padding = (16 - (data_len % 16)) % 16;
data_len += padding;
return data_len;
}
int ota_send_finish(ClientList *client_list) {
// read flash and send data
BaseMessage replyMessage = {};
OTA_FINISH_UPDATE_Payload payload = {};
ESP_LOGI(TAG, "OTA SEND FINISH");
replyMessage = MessageBuilder(OTA_FINISH_UPDATE, *(PayloadUnion *)&payload,
sizeof(payload));
for (int i = 0; i < MAX_CLIENTS; i++) {
if (client_list->Clients[i].slotIsUsed) {
if (client_list->Clients[i].ota_status == OTA_UPDATING) {
esp_now_send(client_list->Clients[i].macAddr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
client_list->Clients[i].ota_status = OTA_AWAITING_ACK;
}
}
}
finished = true;
return 0;
}
int ota_send_next_update_chunk(ClientList *client_list) {
// read flash and send data
BaseMessage replyMessage = {};
OTA_CHUNK_Payload payload = {};
size_t actual_read = 200;
if (partition_to_read_from_read_index + actual_read > update_size) {
actual_read = update_size - partition_to_read_from_read_index;
}
esp_err_t err = esp_partition_read(&partition_to_read_update_from,
partition_to_read_from_read_index,
payload.data, actual_read);
if (actual_read < 200) {
ESP_LOG_BUFFER_HEX(TAG, payload.data, actual_read);
}
if (err != ESP_OK) {
ESP_LOGE(TAG, "Could not read partition");
}
partition_to_read_from_read_index += actual_read;
payload.data_len = actual_read;
ESP_LOGI(TAG, "READ %d Bytes Sendig it to all Clients waiting", actual_read);
ESP_LOGI(TAG, "READ PARTITION AT %d Bytes MAX Bytes %d",
partition_to_read_from_read_index, update_size);
replyMessage =
MessageBuilder(OTA_CHUNK, *(PayloadUnion *)&payload, sizeof(payload));
for (int i = 0; i < MAX_CLIENTS; i++) {
if (client_list->Clients[i].slotIsUsed) {
if (client_list->Clients[i].ota_status == OTA_UPDATING) {
esp_now_send(client_list->Clients[i].macAddr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
client_list->Clients[i].ota_status = OTA_AWAITING_ACK;
}
}
}
if (partition_to_read_from_read_index == update_size)
return 1; // last update chunk send now finish it!
return 0;
}
void MasterOTATask(void *pvParameter) {
ESP_LOGI(TAG, "master_ota_task started");
ota_task_queue_message_t msg;
MasterOTA_TaskParams_t task_params = *(MasterOTA_TaskParams_t *)pvParameter;
client_list = task_params.client_list;
while (1) {
if (xQueueReceive(ota_task_queue, &msg, portMAX_DELAY)) {
ESP_LOGI(TAG, "master ota_task received command: %d", msg.command);
BaseMessage replyMessage = {};
switch (msg.command) {
case OTA_SEND_SLAVES_PREPARE_MESSAGE: {
}
case OTA_SLAVE_WILL_PREPARE: {
int id = get_client_id(client_list, msg.mac_addr);
if (id < 0) {
// error
ESP_LOGE(TAG, "Error set OTA_PREPARE could not get client id");
}
// just wait
// mark client that it will wait
ESP_LOGI(TAG, "MASTER OTA TASK: Marking Client %d as OTA_PREPARING",
id);
client_list->Clients[id].ota_status = OTA_PREPARING;
break;
}
case OTA_SLAVE_IS_PREPARED: {
// client is prepared check if all clients are preapred to send chunks
int id = get_client_id(client_list, msg.mac_addr);
if (id < 0) {
// error
}
if (client_list->Clients[id].ota_status == OTA_PREPARING) {
ESP_LOGI(TAG, "MASTER OTA TASK: Marking Client %d as OTA_UPDATING",
id);
client_list->Clients[id].ota_status = OTA_UPDATING;
} else {
ESP_LOGE(TAG, "MASTER OTA TASK: Client this should not happend");
}
bool start = true;
// check if all clients are prepared
for (int i = 0; i < MAX_CLIENTS; i++) {
if (client_list->Clients[i].slotIsUsed) {
if (client_list->Clients[i].ota_status != OTA_UPDATING)
start = false;
}
}
if (start)
ota_send_next_update_chunk(client_list);
break;
}
case OTA_SLAVE_ACKED: {
// mark client as acked check if all clients acked to send next message
int id = get_client_id(client_list, msg.mac_addr);
if (id < 0) {
// error
}
if (client_list->Clients[id].ota_status == OTA_AWAITING_ACK) {
ESP_LOGI(TAG, "OTA_SLAVE_ACKED Client %d Status Update OTA_UPDATING",
id);
client_list->Clients[id].ota_status = OTA_UPDATING;
} else {
ESP_LOGE(TAG, "OTA_SLAVE_ACKED Client %d Status Should not HAPPEND",
id);
}
bool start = true;
// check if all clients are prepared
for (int i = 0; i < MAX_CLIENTS; i++) {
if (client_list->Clients[i].slotIsUsed) {
ESP_LOGI(TAG, "SLOT %d is USED", i);
if (client_list->Clients[i].ota_status != OTA_UPDATING)
start = false;
}
}
if (start) {
if (finished)
break; // dont need to send anything else
if (all_chunks_send) {
ota_send_finish(client_list);
break;
}
ESP_LOGE(TAG, "OTA_SLAVE_ACKED all clients have the status "
"OTA_UPDATING SENDING NEXT CHUNK");
int end = ota_send_next_update_chunk(client_list);
if (end) {
all_chunks_send = true;
}
}
break;
}
case OTA_SLAVE_ERROR:
break;
// mark client as error
case OTA_MASTER_SEND_PREAPRE_REQUEST:
break;
case OTA_MASTER_SEND_CHUNK:
break;
case OTA_MASTER_SEND_FINISH:
break;
}
}
}
}
void slave_ota_task(void *pvParameter) {
ESP_LOGI(TAG, "slave_ota_task started");
ota_task_queue_message_t msg;
BaseMessage replyMessage = {};
while (1) {
if (xQueueReceive(ota_task_queue, &msg, portMAX_DELAY)) {
ESP_LOGI(TAG, "slave ota_task received command: %d", msg.command);
switch (msg.command) {
case OTA_SEND_SLAVES_PREPARE_MESSAGE:
break;
case OTA_SLAVE_WILL_PREPARE:
break;
case OTA_SLAVE_IS_PREPARED:
break;
case OTA_SLAVE_ACKED:
break;
case OTA_SLAVE_ERROR:
break;
case OTA_MASTER_SEND_PREAPRE_REQUEST: {
ESP_LOGE(TAG, "START PREAPRE CALL");
int part = prepare_ota_update(); // this part function is blocking
OTA_READY_TO_RECEIVE_Payload payload = {};
if (part < 0) {
payload.status = 1; // ERROR
} else {
payload.status = 0; // READY
}
ESP_LOGE(TAG, "PREPARED %d", part);
replyMessage = MessageBuilder(
OTA_READY_TO_RECEIVE, *(PayloadUnion *)&payload, sizeof(payload));
esp_now_send(msg.mac_addr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
break;
}
case OTA_MASTER_SEND_CHUNK: {
// TODO: Move Update_buffer_chunk in normal update buffer no need for
// the extra step...
// TODO: at the moment its just so i can use the write_ota_update
// function unmodified
ESP_LOGI(TAG, "Master send Chunk writing it!");
write_ota_update(update_buffer_chunk_len, update_buffer_chunk);
ESP_LOGI(TAG, "AFTER WRITE_OTA_UPDATE!");
OTA_UPDATE_ACK_Payload payload = {
.update_buffer_write_index = update_buffer_write_index,
.current_block_id = current_block_id,
.sequenz_counter = sequenz_counter,
.status = 0,
};
replyMessage = MessageBuilder(
OTA_UPDATE_SLAVE_ACKED, *(PayloadUnion *)&payload, sizeof(payload));
esp_now_send(msg.mac_addr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
break;
}
case OTA_MASTER_SEND_FINISH: {
esp_err_t err = end_ota_update();
int status = 0;
if (err != ESP_OK) {
status = 1; // TODO: Set real error
}
ESP_LOGI(TAG, "UPDATE FERTIG STATUS %d should be 0", status);
OTA_UPDATE_ACK_Payload payload = {
.update_buffer_write_index = update_buffer_write_index,
.current_block_id = current_block_id,
.sequenz_counter = sequenz_counter,
.status = status,
};
replyMessage = MessageBuilder(
OTA_UPDATE_SLAVE_ACKED, *(PayloadUnion *)&payload, sizeof(payload));
esp_now_send(msg.mac_addr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
break;
}
}
}
}
}
void start_uart_update(uint8_t msgid, const uint8_t *payload,
size_t payload_len, uint8_t *send_payload_buffer,
size_t send_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size) {
ESP_LOGI(TAG, "OTA Update Start Uart Command");
vTaskPrioritySet(NULL, 2);
update_size = 0;
update_buffer_write_index = 0;
sequenz_counter = 0;
all_chunks_send = false;
finished = false;
int part = prepare_ota_update();
uart_ota_start_t *start = (uart_ota_start_t *)send_payload_buffer;
start->partition = part & 0xff;
// TODO: Refine Errors
// Set error
if (part < 0) {
start->error = 0x01;
}
int send_payload_len = sizeof(uart_ota_start_t);
int len = build_message(UART_OTA_START, send_payload_buffer, send_payload_len,
send_buffer, send_buffer_size);
if (len < 0) {
ESP_LOGE(TAG,
"Error Building UART Message: payload_len, %d, sendbuffer_size: "
"%d, mes_len(error): %d",
payload_len, send_buffer_size, len);
return;
}
uart_write_bytes(MASTER_UART, send_buffer, len);
}
esp_err_t write_ota_update(uint32_t write_len, const uint8_t *payload) {
// ESP_LOGI(TAG, "write_ota_update: write_len: %d", write_len);
// ESP_LOGI(TAG, "write_ota_update: update_buffer_write_index: %d",
// update_buffer_write_index);
if (update_buffer_write_index + write_len > UPDATE_BUFFER_SIZE) {
ESP_LOGI(TAG, "write_ota_update: schreib das update weg!");
esp_err_t err =
esp_ota_write(update_handle, update_buffer, update_buffer_write_index);
if (err != ESP_OK) {
return err;
}
update_buffer_write_index = 0;
sequenz_counter++;
}
memcpy(&update_buffer[update_buffer_write_index], payload, write_len);
update_buffer_write_index += write_len;
return ESP_OK;
}
void payload_uart_update(uint8_t msgid, const uint8_t *payload_data_from_uart,
size_t total_payload_len_from_uart,
uint8_t *send_payload_buffer,
size_t send_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size) {
const uint8_t *actual_firmware_data = payload_data_from_uart;
uint32_t write_len = total_payload_len_from_uart;
if (update_size == 0) {
ESP_LOGI(TAG, "First chunk received. write_len: %d", write_len);
}
update_size += write_len;
esp_err_t err = write_ota_update(write_len, actual_firmware_data);
uart_ota_ack_t *ack = (uart_ota_ack_t *)send_payload_buffer;
ack->sequence_counter = sequenz_counter;
ack->write_index = update_buffer_write_index;
ack->error = (err == ESP_OK) ? 0x00 : 0x01;
size_t send_payload_len = sizeof(uart_ota_ack_t);
if (err != ESP_OK) {
ESP_LOGE(TAG, "GOT ESP ERROR WRITE OTA %d", err);
}
int len = build_message(UART_OTA_PAYLOAD, send_payload_buffer,
send_payload_len, send_buffer, send_buffer_size);
if (len < 0) {
ESP_LOGE(TAG,
"Error Building UART Message: payload_len, %d, sendbuffer_size: "
"%d, mes_len(error): %d",
total_payload_len_from_uart, send_buffer_size, len);
return;
}
uart_write_bytes(MASTER_UART, send_buffer, len);
}
void end_uart_update(uint8_t msgid, const uint8_t *payload, size_t payload_len,
uint8_t *send_payload_buffer,
size_t send_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size) {
ESP_LOGI(TAG, "OTA Update End Uart Command");
esp_err_t err = end_ota_update();
uart_ota_end_t *end = (uart_ota_end_t *)send_payload_buffer;
end->error = err & 0xff;
int send_payload_len = sizeof(uart_ota_end_t);
int len = build_message(UART_OTA_END, send_payload_buffer, send_payload_len,
send_buffer, send_buffer_size);
if (len < 0) {
ESP_LOGE(TAG,
"Error Building UART Message: payload_len, %d, sendbuffer_size: "
"%d, mes_len(error): %d",
payload_len, send_buffer_size, len);
return;
}
uart_write_bytes(MASTER_UART, send_buffer, len);
vTaskPrioritySet(NULL, 1);
}
void init_ota() {
ota_task_queue = xQueueCreate(50, sizeof(ota_task_queue_message_t));
}
void RegisterUART_OTAFunctions() {
RegisterCallback(UART_OTA_START, start_uart_update);
RegisterCallback(UART_OTA_PAYLOAD, payload_uart_update);
RegisterCallback(UART_OTA_END, end_uart_update);
}
int prepare_ota_update() {
const esp_partition_t *running = esp_ota_get_running_partition();
ESP_LOGI(TAG, "Running Partition: %s", running->label);
const esp_partition_t *update_partition =
esp_ota_get_next_update_partition(NULL);
if (update_partition == NULL) {
ESP_LOGE(TAG, "Failed to find OTA partition.");
return -1;
}
ESP_LOGI(TAG, "Writing OTA Update to Partition: %s", update_partition->label);
esp_err_t err =
esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
return -2;
}
if (update_partition->subtype == ESP_PARTITION_SUBTYPE_APP_OTA_0) {
return 0;
}
if (update_partition->subtype == ESP_PARTITION_SUBTYPE_APP_OTA_1) {
return 1;
}
// TODO: Unknow partition
return 2;
}
esp_err_t end_ota_update() {
if (update_buffer_write_index > 0) {
ESP_LOG_BUFFER_HEX(TAG, update_buffer, update_buffer_write_index);
esp_err_t err =
esp_ota_write(update_handle, update_buffer, update_buffer_write_index);
vTaskDelay(1);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error writing remaining data to partition: %s",
esp_err_to_name(err));
return err;
}
}
esp_err_t err = esp_ota_end(update_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_end failed: %s", esp_err_to_name(err));
ESP_LOGI(TAG, "Total blocks written: %u, Last partial block size: %u",
sequenz_counter, update_buffer_write_index);
return err;
}
const esp_partition_t *update_partition =
esp_ota_get_next_update_partition(NULL);
err = esp_ota_set_boot_partition(update_partition);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed: %s",
esp_err_to_name(err));
}
return err;
}
// Acknoledge that the slave should prepare for an update
// Queues the Prepare Task beacuse it takes like 30 seconds
void slave_Prep_Upgrade_Callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) {
ESP_LOGE(TAG, "SLAVE PREPARE FOR UPDATE Callback");
update_size = 0;
update_buffer_write_index = 0;
sequenz_counter = 0;
const BaseMessage *message = (const BaseMessage *)data;
const OTA_PREPARE_FOR_UPDATE_Payload *payload =
&message->payload.ota_prepare_for_update_payload;
// total_update_size = payload->total_size;
// Queue Command for Task to call the prepare method
ota_task_queue_message_t msg = {.command = OTA_MASTER_SEND_PREAPRE_REQUEST};
memcpy(msg.mac_addr, esp_now_info->src_addr, ESP_NOW_ETH_ALEN);
if (xQueueSend(ota_task_queue, &msg, pdMS_TO_TICKS(10)) != pdTRUE) {
ESP_LOGE(TAG, "Failed to send prepare command to OTA task");
}
ESP_LOGE(TAG, "SLAVE PREPARE CALLBACK AFTER QUEUE SEND");
// Tell the master that the slave will preapre
OTA_PREPARE_ACKNOWLEDGED_Payload *reply_payload;
BaseMessage reply_message =
MessageBuilder(OTA_PREPARE_ACKNOWLEDGED, *(PayloadUnion *)&reply_payload,
sizeof(OTA_PREPARE_ACKNOWLEDGED_Payload));
ESP_ERROR_CHECK(esp_now_send(esp_now_info->src_addr,
(uint8_t *)&reply_message, sizeof(BaseMessage)));
}
void slave_Update_Chunk_Callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) {
const BaseMessage *message = (const BaseMessage *)data;
const OTA_CHUNK_Payload *payload = &message->payload.ota_chunk_payload;
// copy data to update_buffer_chunk so that the write method can write it
// back later
memcpy(update_buffer_chunk, payload->data, payload->data_len);
update_buffer_chunk_len = payload->data_len;
ESP_LOGI(TAG, "slave_update_Chunk_Callback got %d bytes from Master",
payload->data_len);
// Queue Command for Task to call the ota_write_message method
ota_task_queue_message_t msg = {.command = OTA_MASTER_SEND_CHUNK};
memcpy(msg.mac_addr, esp_now_info->src_addr, ESP_NOW_ETH_ALEN);
if (xQueueSend(ota_task_queue, &msg, pdMS_TO_TICKS(10)) != pdTRUE) {
ESP_LOGE(TAG, "Failed to send prepare command to OTA task");
}
}
void slave_Update_Finished_Callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) {
const BaseMessage *message = (const BaseMessage *)data;
const OTA_FINISH_UPDATE_Payload *payload =
&message->payload.ota_finish_update_payload;
ESP_LOGI(TAG, "slave_Update_Finished_Callback");
// Queue Command for Task to call the ota_write_message method
ota_task_queue_message_t msg = {.command = OTA_MASTER_SEND_FINISH};
memcpy(msg.mac_addr, esp_now_info->src_addr, ESP_NOW_ETH_ALEN);
if (xQueueSend(ota_task_queue, &msg, pdMS_TO_TICKS(10)) != pdTRUE) {
ESP_LOGE(TAG, "Failed to send prepare command to OTA task");
}
}
void start_ota_update_espnow(uint8_t msgid, const uint8_t *payload,
size_t payload_len, uint8_t *send_payload_buffer,
size_t send_payload_buffer_size,
uint8_t *send_buffer, size_t send_buffer_size) {
ESP_LOGI(TAG, "Starting OTA update for all clients");
const esp_partition_t *ota_update_partition;
ota_update_partition = esp_ota_get_next_update_partition(NULL);
if (ota_update_partition == NULL) {
ESP_LOGE(TAG, "Failed to get update partition");
return;
}
update_size = get_app_size(ota_update_partition);
partition_to_read_update_from = *ota_update_partition;
partition_to_read_from_read_index = 0;
BaseMessage replyMessage = {};
OTA_PREPARE_FOR_UPDATE_Payload replyPayload = {};
replyMessage =
MessageBuilder(OTA_PREPARE_FOR_UPDATE, *(PayloadUnion *)&replyPayload,
sizeof(replyPayload));
for (int i = 0; i < MAX_CLIENTS; i++) {
if (client_list->Clients[i].slotIsUsed) {
esp_now_send(client_list->Clients[i].macAddr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
client_list->Clients[i].ota_status = OTA_READY;
}
}
}
void master_ota_prepare_acknowledge_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data,
int data_len) {
ESP_LOGI(TAG, "entering master_ota_prepare_acknowledge_callback");
// Queue Command for Task to call the ota_write_message method
ota_task_queue_message_t msg = {.command = OTA_SLAVE_WILL_PREPARE};
memcpy(msg.mac_addr, esp_now_info->src_addr, ESP_NOW_ETH_ALEN);
if (xQueueSend(ota_task_queue, &msg, pdMS_TO_TICKS(10)) != pdTRUE) {
ESP_LOGE(TAG, "Failed to send prepare command to OTA task");
}
}
void master_ota_ready_to_recieve_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data,
int data_len) {
ESP_LOGI(TAG, "entering master_ota_ready_to_recieve_callback");
// Queue Command for Task to call the ota_write_message method
ota_task_queue_message_t msg = {.command = OTA_SLAVE_IS_PREPARED};
memcpy(msg.mac_addr, esp_now_info->src_addr, ESP_NOW_ETH_ALEN);
if (xQueueSend(ota_task_queue, &msg, pdMS_TO_TICKS(10)) != pdTRUE) {
ESP_LOGE(TAG, "Failed to send prepare command to OTA task");
}
}
void master_ota_update_slave_acknowledge_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data,
int data_len) {
ESP_LOGI(TAG, "entering master_ota_update_slave_acknowledge_callback");
// Queue Command for Task to call the ota_write_message method
ota_task_queue_message_t msg = {.command = OTA_SLAVE_ACKED};
memcpy(msg.mac_addr, esp_now_info->src_addr, ESP_NOW_ETH_ALEN);
if (xQueueSend(ota_task_queue, &msg, pdMS_TO_TICKS(10)) != pdTRUE) {
ESP_LOGE(TAG, "Failed to send prepare command to OTA task");
}
}
+97
View File
@@ -0,0 +1,97 @@
#ifndef OTA_UPDATE_H
#define OTA_UPDATE_H
#include "client_handler.h"
#include "esp_err.h"
#include "esp_now.h"
#include "esp_partition.h"
#include "message_structs.h"
#include <stdint.h>
#include <sys/types.h>
#define UPDATE_BUFFER_SIZE 4096
#define UPDATE_PAYLOAD_SIZE 200
#define UPDATE_MAX_SEQUENZES (UPDATE_BUFFER_SIZE / UPDATE_PAYLOAD_SIZE)
typedef enum {
OTA_SEND_SLAVES_PREPARE_MESSAGE,
OTA_SLAVE_WILL_PREPARE,
OTA_SLAVE_IS_PREPARED,
OTA_SLAVE_ACKED,
OTA_SLAVE_ERROR,
OTA_MASTER_SEND_PREAPRE_REQUEST,
OTA_MASTER_SEND_CHUNK,
OTA_MASTER_SEND_FINISH,
} ota_command_t;
typedef struct {
ota_command_t command;
uint8_t mac_addr[ESP_NOW_ETH_ALEN];
} ota_task_queue_message_t;
typedef struct {
ClientList *client_list;
} MasterOTA_TaskParams_t;
typedef struct __attribute__((packed)) {
uint16_t sequence_counter;
uint16_t write_index;
uint8_t error;
} uart_ota_ack_t;
typedef struct __attribute__((packed)) {
uint8_t partition;
uint8_t error;
} uart_ota_start_t;
typedef struct __attribute__((packed)) {
uint8_t error;
} uart_ota_end_t;
void init_ota();
void RegisterUART_OTAFunctions();
void MasterOTATask(void *pvParameter);
void slave_ota_task(void *pvParameter);
u_int32_t get_app_size(const esp_partition_t *app_size_partition);
int prepare_ota_update();
esp_err_t write_ota_update(uint32_t write_len, const uint8_t *payload);
esp_err_t end_ota_update();
void slave_Prep_Upgrade_Callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len);
void slave_Update_Chunk_Callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len);
void slave_Update_Finished_Callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len);
void master_ota_prepare_acknowledge_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data, int data_len);
void master_ota_ready_to_recieve_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data, int data_len);
void master_ota_update_slave_acknowledge_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data, int data_len);
void start_uart_update(uint8_t msgid, const uint8_t *payload,
size_t payload_len, uint8_t *send_payload_buffer,
size_t send_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size);
void payload_uart_update(uint8_t msgid, const uint8_t *payload_data_from_uart,
size_t total_payload_len_from_uart,
uint8_t *send_payload_buffer,
size_t send_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size);
void end_uart_update(uint8_t msgid, const uint8_t *payload, size_t payload_len,
uint8_t *send_payload_buffer,
size_t send_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size);
void start_ota_update_espnow(uint8_t msgid, const uint8_t *payload,
size_t payload_len, uint8_t *send_payload_buffer,
size_t send_payload_buffer_size,
uint8_t *send_buffer, size_t send_buffer_size);
#endif
+4 -3
View File
@@ -18,7 +18,8 @@ static const char *TAG = "ALOX - UART";
static QueueHandle_t parsed_message_queue; static QueueHandle_t parsed_message_queue;
void init_uart(QueueHandle_t msg_queue_handle) { void init_uart(QueueHandle_t msg_queue_handle) {
uart_config_t uart_config = {.baud_rate = 115200, uart_config_t uart_config = {// .baud_rate = 115200, // 921600, 115200
.baud_rate = 921600,
.data_bits = UART_DATA_8_BITS, .data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE, .parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1, .stop_bits = UART_STOP_BITS_1,
@@ -61,9 +62,9 @@ void send_message_hook(const uint8_t *buffer, size_t length) {
void HandleMessageReceivedCallback(uint8_t msgid, const uint8_t *payload, void HandleMessageReceivedCallback(uint8_t msgid, const uint8_t *payload,
size_t payload_len) { size_t payload_len) {
ESP_LOGI(TAG, "GOT UART MESSAGE MSGID: %02X, Len: %u bytes \nMSG: ", msgid, /*ESP_LOGI(TAG, "GOT UART MESSAGE MSGID: %02X, Len: %u bytes \nMSG: ", msgid,
payload_len, payload); payload_len, payload);
ESP_LOG_BUFFER_HEX(TAG, payload, payload_len); ESP_LOG_BUFFER_HEX(TAG, payload, payload_len);*/
ParsedMessage_t msg_to_send; ParsedMessage_t msg_to_send;
msg_to_send.msgid = msgid; msg_to_send.msgid = msgid;
+6
View File
@@ -6,9 +6,15 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#ifdef CONFIG_IDF_TARGET_ESP32S3
#define MASTER_UART UART_NUM_1
#define TXD_PIN (GPIO_NUM_2)
#define RXD_PIN (GPIO_NUM_3)
#elif CONFIG_IDF_TARGET_ESP32C3
#define MASTER_UART UART_NUM_1 #define MASTER_UART UART_NUM_1
#define TXD_PIN (GPIO_NUM_1) #define TXD_PIN (GPIO_NUM_1)
#define RXD_PIN (GPIO_NUM_2) #define RXD_PIN (GPIO_NUM_2)
#endif
#define BUF_SIZE (256) #define BUF_SIZE (256)
+19
View File
@@ -0,0 +1,19 @@
#ifndef UART_MSG_IDS_H
#define UART_MSG_IDS_H
enum UART_MSG_IDS {
// MISC
UART_ECHO = 0x01,
UART_VERSION = 0x02,
UART_CLIENT_INFO = 0x03,
UART_CLIENT_INPUT = 0x04,
// OTA
UART_OTA_START = 0x10,
UART_OTA_PAYLOAD = 0x11,
UART_OTA_END = 0x12,
UART_OTA_STATUS = 0x13,
UART_OTA_START_ESPNOW = 0x14,
};
#endif
+182 -35
View File
@@ -1,55 +1,150 @@
# Conventions
## Naming
### Filenames: snake_case (ota_master.c, ota_slave.c, com_handler.c)
### Functions: module_submodule_action()
- OTA Master = ota_m_send_chunk(), ota_m_init()
- OTA Slave = ota_s_handle_chunk(), ota_s_prepare_flash()
- com_init(), msg_parse()
### Variables:
- Global: g_ (g_client_list)
- Statics: s_ (s_update_handle)
- Constants: UPPER_SNAKE_CASE (UPDATE_BUFFER_SIZE)
### Types:
- Typedefs: Ends with _t (ota_payload_t)
- Struct-Tags: Ends with _t or spezifik name (struct ota_context)
- Unions: Ends with _u (msg_payload_u)
- Callbacks: End with _cb (com_m_rx_cb)
### FreeRTOS-Objects
- x for Basetypes (x_ota_queue, x_status_semaphor)
- v for void return (v_ota_task)
# UART Protokoll # UART Protokoll
## Struktur einer Nachricht ## Struktur einer Nachricht
0xAA = Startbyte - Control Bytes:
checksum = XOR über alle Bytes (ohne Startbyte und Checksum-Byte) - 0xAA = Startbyte
- 0xBB = EscapeByte
- 0xCC = EndByte
## Nachrichtenaufbau (Message Frame) checksum = XOR über alle Bytes (ohne Control Bytes und Checksum-Byte)
[ Startbyte ] [ Length ] [ CommandPage ] [ Payload (variabel) ] [ Checksum ] Command, Payload und Checksum werden Escaped sollten sie einem Control Byte ensteprechend
| Startbyte | Command | Payload (variable) | Checksum | Endbyte |
|-----------|---------|--------------------|----------|---------|
### Felder im Detail: ### Felder im Detail:
- **Length** (`uint8_t`): - **Command** (`uint8_t`):
Gibt die Gesamtlänge der Nachricht **ab `CommandPage` bis einschließlich `Payload`** an. Gibt an, welcher Nachrichtentyp gesendet wird.
- **CommandPage** (`uint8_t`):
Gibt an, welcher Nachrichtentyp oder Befehl gesendet wird.
- **Payload** (`variabel`): - **Payload** (`variabel`):
Datenfeld mit variabler Länge, abhängig vom `CommandPage`. Datenfeld mit variabler Länge, abhängig vom `Command`.
- **Checksum** (`uint8_t`): - **Checksum** (`uint8_t`):
XOR über alle Bytes ab `Length` bis einschließlich `Payload`. XOR über aller Bytes von `Command` und `Payload`.
### Nachrichten von PC zu ESP:
clientid: 0x00 für master, 0xFF für broadcast, ansonsten 0xA0-0xB3 // 19 Clients
### RequestPing 0xE1
Payload: byte: clientid
### RequestInfo 0xE2
Payload: byte: clientid
### RequestRestart 0xE3
Payload: byte: clientid
### PrepareFirmwareUpdate 0xF1
Payload: none
### FirmwareUpdateLine 0xF2
Payload: firmware line 240Bytes MAX
### ExecuteFirmwareUpdate 0xF3
Payload: none
### Nachrichten von ESP zu PC:
### Messages
--- Command:
- UART_ECHO = 0x01
- UART_VERSION = 0x02
- UART_CLIENT_INFO = 0x03
# Roadmap Grundlegend sind alle Zahlenwerte im LittleEndian format!
- [ ] SEND STATUS OF DEVICE OVER UART
- [ ] CONFIGURE PEERS OVER MASTER #### UART_ECHO:
- [ ] SAVE PIN CONFIG ON PEERS
- Send Message: AA 01 01 CC
- Message Received: AA 01 01 CC
Sendet zurück was geschickt wird.
#### UART_VERSION:
| Offset | Länge (Bytes) | Bezeichnung | Beschreibung |
|--------|---------------|-------------|------------------|
| 0 | 2 | Version | Software Version |
| 2 | 7 | BuildHash | Git Hash |
- Send Message: AA 02 02 CC
- Message Received: AA 02 01 00 33 62 35 36 30 37 39 6F CC
| Version | Buildhash |
|---------|-----------|
| 1 | 3b56078 |
Sendet die Version und den Buildhash vom Master zurück.
#### UART_CLIENT_INFO:
Das erste Datenbyte nach dem Commando gibt an wie viele Client Infos in dieser Nachricht vorhanden sind.
Danach teilt sich ein Eintrag wie Folgt auf:
| Offset | Länge (Bytes) | Bezeichnung | Beschreibung |
|--------|---------------|----------------------------|---------------------------------------------------------------|
| 0 | 1 | Client ID | Eindeutige ID des Clients. |
| 1 | 1 | Ist verfügbar | Boolean-Wert (0 = nein, 1 = ja), ob der Client verfügbar ist. |
| 2 | 1 | Slot genutzt | Boolean-Wert (0 = nein, 1 = ja), ob der Slot belegt ist. |
| 3 | 6 | MAC-Adresse | Die Hardware-Adresse des Clients. |
| 9 | 4 | Letzter Ping | Zeit in Millisekunden seit dem letzten Ping. |
| 13 | 4 | Letzter erfolgreicher Ping | Zeit in Millisekunden seit dem letzten erfolgreichen Ping. |
| 17 | 2 | Version | Versionsnummer des Clients. |
##### Ein Client
- Send Message: AA 03 03 CC
- Message Received: AA 03 01 00 01 01 50 78 7D 18 89 F8 34 00 00 00 61 1F 00 00 02 00 76 CC
| Client ID | Verfügbar | Genutzt | MAC-Adresse | Last Ping | Last Successful Ping | Version |
|-----------|-----------|---------|-------------------|-----------|----------------------|---------|
| 0 | 1 | 1 | 50:78:7D:18:89:F8 | 52 | 8033 | 2 |
##### Zwei Clients
- Send Message: AA 03 03 CC
- Message Received: AA 03 02 00 01 01 50 78 7D 18 89 F8 22 00 00 00 F4 2A 01 00 02 00 01 01 01 50 78 7D 18 0C B4 10 00 00 00 F1 2A 01 00 02 00 FE CC
| Client ID | Verfügbar | Genutzt | MAC-Adresse | Last Ping | Last Successful Ping | Version |
|-----------|-----------|---------|-------------------|-----------|----------------------|---------|
| 0 | 1 | 1 | 50:78:7D:18:89:F8 | 34 | 76532 | 2 |
| 1 | 1 | 1 | 50:78:7D:18:C:B4 | 16 | 76529 | 2 |
#### UART_CLIENT_INPUT:
Die Identifizierung wird hier anhand der vorher gesendeten ClientID gemacht also muss einmal vorher `UART_CLIENT_INFO` aufgerufen werden.
Das erste Datenbyte nach dem Commando gibt an wie viele Client Infos in dieser Nachricht vorhanden sind.
Danach teilt sich ein Eintrag wie Folgt auf:
| Offset | Länge (Bytes) | Bezeichnung | Beschreibung |
|--------|---------------|-------------|----------------------------------------------------------------------------------|
| 0 | 1 | Client ID | Eindeutige ID des Clients. |
| 1 | 4 | LageX | Float Wert von der X Lage. |
| 5 | 4 | LageY | Float Wert von der Y Lage. |
| 9 | 4 | InputMaske | Int32 Wert der als Bitmaske genutzt wird um bis zu 32 Boolische Werte anzugeben. |
Inputmaske:
Taster1, Taster2, IOError1, IOErro2, AkkuStand1, AkkuStand2 (2 Bit kodiert für 25%,50%,75%,100%), rest unbelegt, default 0
| Bit1 | Bit2 | Akkustand |
|------|------|-----------|
| 0 | 0 | 25% |
| 0 | 1 | 50% |
| 1 | 0 | 75% |
| 1 | 1 | 100% |
<div style="page-break-after: always;"></div>
# Machbarkeits-Studie # Machbarkeits-Studie
@@ -177,3 +272,55 @@ techn. Anforderungen hinreichend gut umsetzen lassen.
und ob diese den ursprünglichen Anforderungen entsprechen. und ob diese den ursprünglichen Anforderungen entsprechen.
## OTA-Update Technische Umsetzung:
### Vorrausetzung:
- Update File steht bereit und ist unter 2MB groß.
- UART Verbindung steht
- ESP Funktioniert einwandfrei
- ESP Läuft auf Partition A, Partition B soll geupdated werden
### Erste Schritt:
- Update in 200Byte stücke zerhacken und stück für stück per UART an den Master schicken
- Uart Protokol hat schon eine fehlercheck für die Übertragung drinnen
- Firmware wird in Partition B geschrieben
- OTA API Validiert Firmware am ende
#### Hier könnte man schon einen Neustart machen und Validieren ob die Firmware für den Master läuft!
#### Denn angeblich kann man beim ESP die aktuell laufende Partition auslesen
### Zweiter Schritt:
- Master liest in 200Byte stücken die Firmware aus seiner Partition B aus
- Und schickt per Broadcast die ersten 20 Packete an die Clients
- Die clients haben 4KB Buffer vorgesehen wo sie die 20 Packete unterbringen können
- Master Forder Ack Bitmaske an zur Validierung das alle 20 Packete da sind
- Sollten in der Bitmaske zeilen fehlen gibt der Master per unicast die fehlenden Zeilen an die Entsprechend Clients erneut
- ESP NOW kümmert sich hier um die Datenintigrität
- Wenn alle ihre ersten 20 packete haben gibt der master das go und alle schreiben die ersten 20 packete weg.
- Der master aktuallisiert den fortschritt für alle clients -> dann kann man das auch abfragen per uart und hat eine Fortschrittsanzeige
- Alle melden sich zurück wenn sie fertig sind mit dem schreiben per ota und der buffer leer ist.
- Repeat bis alle Daten da sind
Hier hab ich mal grob gerechnet:
2MB in 200Byte Schritten -> 10.000 Packete
10.000 Packete in 20er Schritten -> 500 Sequencen
Retries und Acks mal aussen vor hab ich leider keinen richtigen anhaltspunkt wie lang das dauern kann.
Aber 500* ca 300ms => ist schonmal 150sekunden nur für das acken das die Packete da sind. Annahme hier das die maximal latenz beim Ping mit 16 Clients ca 300ms sind.
Entsprechend mit Daten und retries... ja kp, Gemini schätzt max 10min. Wird sich zeigen. Da addiert sich zu viel auf.
- Alle Clients validieren ihren firmware
- Sollte das bei einem nicht klappen muss man hier nochmal gucken ob man den ganzen process nochmal von vorne anstößt nur mit dem fehlenden client...
### Dritter Schritt:
- Alle Clients rebooten
- Clients geben rückmeldung ob das Update funktioniert
#### Hier müssten war noch entscheiden was passiert wenn das Update bei nur ein paar funktionert hat?
#### Was passiert wenn das Update garnicht funktioniert hat, behält der master dann auch seinen stand?
#### Entsprechend hätte man ihn vorher auch nicht neustarten dürfen
- Sollten alle Clients ihr go geben startet der Master auch neu
#### Wenn das Master Update jetzt fehlschlägt sagt er den clients bescheid und die booten auch wieder um?
Gibt halt noch ein zwar sachen die man sich überlegen muss aber ich denke den rest hab ich soweit ausgearbeitet
+545 -196
View File
File diff suppressed because it is too large Load Diff
+2098
View File
File diff suppressed because it is too large Load Diff
+395 -148
View File
@@ -3,25 +3,37 @@
# Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Configuration # Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Configuration
# #
CONFIG_SOC_ADC_SUPPORTED=y CONFIG_SOC_ADC_SUPPORTED=y
CONFIG_SOC_DEDICATED_GPIO_SUPPORTED=y
CONFIG_SOC_UART_SUPPORTED=y CONFIG_SOC_UART_SUPPORTED=y
CONFIG_SOC_PCNT_SUPPORTED=y
CONFIG_SOC_PHY_SUPPORTED=y
CONFIG_SOC_WIFI_SUPPORTED=y
CONFIG_SOC_TWAI_SUPPORTED=y
CONFIG_SOC_GDMA_SUPPORTED=y CONFIG_SOC_GDMA_SUPPORTED=y
CONFIG_SOC_AHB_GDMA_SUPPORTED=y CONFIG_SOC_AHB_GDMA_SUPPORTED=y
CONFIG_SOC_GPTIMER_SUPPORTED=y CONFIG_SOC_GPTIMER_SUPPORTED=y
CONFIG_SOC_TWAI_SUPPORTED=y CONFIG_SOC_LCDCAM_SUPPORTED=y
CONFIG_SOC_LCDCAM_I80_LCD_SUPPORTED=y
CONFIG_SOC_LCDCAM_RGB_LCD_SUPPORTED=y
CONFIG_SOC_MCPWM_SUPPORTED=y
CONFIG_SOC_DEDICATED_GPIO_SUPPORTED=y
CONFIG_SOC_CACHE_SUPPORT_WRAP=y
CONFIG_SOC_ULP_SUPPORTED=y
CONFIG_SOC_ULP_FSM_SUPPORTED=y
CONFIG_SOC_RISCV_COPROC_SUPPORTED=y
CONFIG_SOC_BT_SUPPORTED=y CONFIG_SOC_BT_SUPPORTED=y
CONFIG_SOC_ASYNC_MEMCPY_SUPPORTED=y CONFIG_SOC_USB_OTG_SUPPORTED=y
CONFIG_SOC_USB_SERIAL_JTAG_SUPPORTED=y CONFIG_SOC_USB_SERIAL_JTAG_SUPPORTED=y
CONFIG_SOC_TEMP_SENSOR_SUPPORTED=y CONFIG_SOC_CCOMP_TIMER_SUPPORTED=y
CONFIG_SOC_XT_WDT_SUPPORTED=y CONFIG_SOC_ASYNC_MEMCPY_SUPPORTED=y
CONFIG_SOC_PHY_SUPPORTED=y
CONFIG_SOC_WIFI_SUPPORTED=y
CONFIG_SOC_SUPPORTS_SECURE_DL_MODE=y CONFIG_SOC_SUPPORTS_SECURE_DL_MODE=y
CONFIG_SOC_EFUSE_KEY_PURPOSE_FIELD=y CONFIG_SOC_EFUSE_KEY_PURPOSE_FIELD=y
CONFIG_SOC_EFUSE_HAS_EFUSE_RST_BUG=y
CONFIG_SOC_EFUSE_SUPPORTED=y CONFIG_SOC_EFUSE_SUPPORTED=y
CONFIG_SOC_SDMMC_HOST_SUPPORTED=y
CONFIG_SOC_RTC_FAST_MEM_SUPPORTED=y CONFIG_SOC_RTC_FAST_MEM_SUPPORTED=y
CONFIG_SOC_RTC_SLOW_MEM_SUPPORTED=y
CONFIG_SOC_RTC_MEM_SUPPORTED=y CONFIG_SOC_RTC_MEM_SUPPORTED=y
CONFIG_SOC_PSRAM_DMA_CAPABLE=y
CONFIG_SOC_XT_WDT_SUPPORTED=y
CONFIG_SOC_I2S_SUPPORTED=y CONFIG_SOC_I2S_SUPPORTED=y
CONFIG_SOC_RMT_SUPPORTED=y CONFIG_SOC_RMT_SUPPORTED=y
CONFIG_SOC_SDM_SUPPORTED=y CONFIG_SOC_SDM_SUPPORTED=y
@@ -30,6 +42,7 @@ CONFIG_SOC_LEDC_SUPPORTED=y
CONFIG_SOC_I2C_SUPPORTED=y CONFIG_SOC_I2C_SUPPORTED=y
CONFIG_SOC_SYSTIMER_SUPPORTED=y CONFIG_SOC_SYSTIMER_SUPPORTED=y
CONFIG_SOC_SUPPORT_COEXISTENCE=y CONFIG_SOC_SUPPORT_COEXISTENCE=y
CONFIG_SOC_TEMP_SENSOR_SUPPORTED=y
CONFIG_SOC_AES_SUPPORTED=y CONFIG_SOC_AES_SUPPORTED=y
CONFIG_SOC_MPI_SUPPORTED=y CONFIG_SOC_MPI_SUPPORTED=y
CONFIG_SOC_SHA_SUPPORTED=y CONFIG_SOC_SHA_SUPPORTED=y
@@ -38,9 +51,10 @@ CONFIG_SOC_DIG_SIGN_SUPPORTED=y
CONFIG_SOC_FLASH_ENC_SUPPORTED=y CONFIG_SOC_FLASH_ENC_SUPPORTED=y
CONFIG_SOC_SECURE_BOOT_SUPPORTED=y CONFIG_SOC_SECURE_BOOT_SUPPORTED=y
CONFIG_SOC_MEMPROT_SUPPORTED=y CONFIG_SOC_MEMPROT_SUPPORTED=y
CONFIG_SOC_TOUCH_SENSOR_SUPPORTED=y
CONFIG_SOC_BOD_SUPPORTED=y CONFIG_SOC_BOD_SUPPORTED=y
CONFIG_SOC_CLK_TREE_SUPPORTED=y CONFIG_SOC_CLK_TREE_SUPPORTED=y
CONFIG_SOC_ASSIST_DEBUG_SUPPORTED=y CONFIG_SOC_MPU_SUPPORTED=y
CONFIG_SOC_WDT_SUPPORTED=y CONFIG_SOC_WDT_SUPPORTED=y
CONFIG_SOC_SPI_FLASH_SUPPORTED=y CONFIG_SOC_SPI_FLASH_SUPPORTED=y
CONFIG_SOC_RNG_SUPPORTED=y CONFIG_SOC_RNG_SUPPORTED=y
@@ -48,21 +62,20 @@ CONFIG_SOC_LIGHT_SLEEP_SUPPORTED=y
CONFIG_SOC_DEEP_SLEEP_SUPPORTED=y CONFIG_SOC_DEEP_SLEEP_SUPPORTED=y
CONFIG_SOC_LP_PERIPH_SHARE_INTERRUPT=y CONFIG_SOC_LP_PERIPH_SHARE_INTERRUPT=y
CONFIG_SOC_PM_SUPPORTED=y CONFIG_SOC_PM_SUPPORTED=y
CONFIG_SOC_SIMD_INSTRUCTION_SUPPORTED=y
CONFIG_SOC_XTAL_SUPPORT_40M=y CONFIG_SOC_XTAL_SUPPORT_40M=y
CONFIG_SOC_AES_SUPPORT_DMA=y CONFIG_SOC_APPCPU_HAS_CLOCK_GATING_BUG=y
CONFIG_SOC_AES_GDMA=y CONFIG_SOC_ADC_RTC_CTRL_SUPPORTED=y
CONFIG_SOC_AES_SUPPORT_AES_128=y
CONFIG_SOC_AES_SUPPORT_AES_256=y
CONFIG_SOC_ADC_DIG_CTRL_SUPPORTED=y CONFIG_SOC_ADC_DIG_CTRL_SUPPORTED=y
CONFIG_SOC_ADC_ARBITER_SUPPORTED=y CONFIG_SOC_ADC_ARBITER_SUPPORTED=y
CONFIG_SOC_ADC_DIG_IIR_FILTER_SUPPORTED=y CONFIG_SOC_ADC_DIG_IIR_FILTER_SUPPORTED=y
CONFIG_SOC_ADC_MONITOR_SUPPORTED=y CONFIG_SOC_ADC_MONITOR_SUPPORTED=y
CONFIG_SOC_ADC_DMA_SUPPORTED=y CONFIG_SOC_ADC_DMA_SUPPORTED=y
CONFIG_SOC_ADC_PERIPH_NUM=2 CONFIG_SOC_ADC_PERIPH_NUM=2
CONFIG_SOC_ADC_MAX_CHANNEL_NUM=5 CONFIG_SOC_ADC_MAX_CHANNEL_NUM=10
CONFIG_SOC_ADC_ATTEN_NUM=4 CONFIG_SOC_ADC_ATTEN_NUM=4
CONFIG_SOC_ADC_DIGI_CONTROLLER_NUM=1 CONFIG_SOC_ADC_DIGI_CONTROLLER_NUM=2
CONFIG_SOC_ADC_PATT_LEN_MAX=8 CONFIG_SOC_ADC_PATT_LEN_MAX=24
CONFIG_SOC_ADC_DIGI_MIN_BITWIDTH=12 CONFIG_SOC_ADC_DIGI_MIN_BITWIDTH=12
CONFIG_SOC_ADC_DIGI_MAX_BITWIDTH=12 CONFIG_SOC_ADC_DIGI_MAX_BITWIDTH=12
CONFIG_SOC_ADC_DIGI_RESULT_BYTES=4 CONFIG_SOC_ADC_DIGI_RESULT_BYTES=4
@@ -78,40 +91,43 @@ CONFIG_SOC_ADC_SELF_HW_CALI_SUPPORTED=y
CONFIG_SOC_ADC_SHARED_POWER=y CONFIG_SOC_ADC_SHARED_POWER=y
CONFIG_SOC_APB_BACKUP_DMA=y CONFIG_SOC_APB_BACKUP_DMA=y
CONFIG_SOC_BROWNOUT_RESET_SUPPORTED=y CONFIG_SOC_BROWNOUT_RESET_SUPPORTED=y
CONFIG_SOC_SHARED_IDCACHE_SUPPORTED=y CONFIG_SOC_CACHE_WRITEBACK_SUPPORTED=y
CONFIG_SOC_CACHE_MEMORY_IBANK_SIZE=0x4000 CONFIG_SOC_CACHE_FREEZE_SUPPORTED=y
CONFIG_SOC_CPU_CORES_NUM=1 CONFIG_SOC_CACHE_ACS_INVALID_STATE_ON_PANIC=y
CONFIG_SOC_CPU_CORES_NUM=2
CONFIG_SOC_CPU_INTR_NUM=32 CONFIG_SOC_CPU_INTR_NUM=32
CONFIG_SOC_CPU_HAS_FLEXIBLE_INTC=y CONFIG_SOC_CPU_HAS_FPU=y
CONFIG_SOC_CPU_HAS_CSR_PC=y CONFIG_SOC_HP_CPU_HAS_MULTIPLE_CORES=y
CONFIG_SOC_CPU_BREAKPOINTS_NUM=8 CONFIG_SOC_CPU_BREAKPOINTS_NUM=2
CONFIG_SOC_CPU_WATCHPOINTS_NUM=8 CONFIG_SOC_CPU_WATCHPOINTS_NUM=2
CONFIG_SOC_CPU_WATCHPOINT_MAX_REGION_SIZE=0x80000000 CONFIG_SOC_CPU_WATCHPOINT_MAX_REGION_SIZE=64
CONFIG_SOC_DS_SIGNATURE_MAX_BIT_LEN=3072 CONFIG_SOC_SIMD_PREFERRED_DATA_ALIGNMENT=16
CONFIG_SOC_DS_SIGNATURE_MAX_BIT_LEN=4096
CONFIG_SOC_DS_KEY_PARAM_MD_IV_LENGTH=16 CONFIG_SOC_DS_KEY_PARAM_MD_IV_LENGTH=16
CONFIG_SOC_DS_KEY_CHECK_MAX_WAIT_US=1100 CONFIG_SOC_DS_KEY_CHECK_MAX_WAIT_US=1100
CONFIG_SOC_AHB_GDMA_VERSION=1 CONFIG_SOC_AHB_GDMA_VERSION=1
CONFIG_SOC_GDMA_NUM_GROUPS_MAX=1 CONFIG_SOC_GDMA_NUM_GROUPS_MAX=1
CONFIG_SOC_GDMA_PAIRS_PER_GROUP_MAX=3 CONFIG_SOC_GDMA_PAIRS_PER_GROUP=5
CONFIG_SOC_GDMA_PAIRS_PER_GROUP_MAX=5
CONFIG_SOC_AHB_GDMA_SUPPORT_PSRAM=y
CONFIG_SOC_GPIO_PORT=1 CONFIG_SOC_GPIO_PORT=1
CONFIG_SOC_GPIO_PIN_COUNT=22 CONFIG_SOC_GPIO_PIN_COUNT=49
CONFIG_SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER=y CONFIG_SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER=y
CONFIG_SOC_GPIO_FILTER_CLK_SUPPORT_APB=y CONFIG_SOC_GPIO_FILTER_CLK_SUPPORT_APB=y
CONFIG_SOC_GPIO_SUPPORT_RTC_INDEPENDENT=y
CONFIG_SOC_GPIO_SUPPORT_FORCE_HOLD=y CONFIG_SOC_GPIO_SUPPORT_FORCE_HOLD=y
CONFIG_SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP=y CONFIG_SOC_GPIO_VALID_GPIO_MASK=0x1FFFFFFFFFFFF
CONFIG_SOC_GPIO_IN_RANGE_MAX=21 CONFIG_SOC_GPIO_IN_RANGE_MAX=48
CONFIG_SOC_GPIO_OUT_RANGE_MAX=21 CONFIG_SOC_GPIO_OUT_RANGE_MAX=48
CONFIG_SOC_GPIO_DEEP_SLEEP_WAKE_VALID_GPIO_MASK=0 CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0x0001FFFFFC000000
CONFIG_SOC_GPIO_DEEP_SLEEP_WAKE_SUPPORTED_PIN_CNT=6 CONFIG_SOC_GPIO_CLOCKOUT_BY_IO_MUX=y
CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0x00000000003FFFC0
CONFIG_SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX=y
CONFIG_SOC_GPIO_CLOCKOUT_CHANNEL_NUM=3 CONFIG_SOC_GPIO_CLOCKOUT_CHANNEL_NUM=3
CONFIG_SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP=y CONFIG_SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP=y
CONFIG_SOC_DEDIC_GPIO_OUT_CHANNELS_NUM=8 CONFIG_SOC_DEDIC_GPIO_OUT_CHANNELS_NUM=8
CONFIG_SOC_DEDIC_GPIO_IN_CHANNELS_NUM=8 CONFIG_SOC_DEDIC_GPIO_IN_CHANNELS_NUM=8
CONFIG_SOC_DEDIC_PERIPH_ALWAYS_ENABLE=y CONFIG_SOC_DEDIC_GPIO_OUT_AUTO_ENABLE=y
CONFIG_SOC_I2C_NUM=1 CONFIG_SOC_I2C_NUM=2
CONFIG_SOC_HP_I2C_NUM=1 CONFIG_SOC_HP_I2C_NUM=2
CONFIG_SOC_I2C_FIFO_LEN=32 CONFIG_SOC_I2C_FIFO_LEN=32
CONFIG_SOC_I2C_CMD_REG_NUM=8 CONFIG_SOC_I2C_CMD_REG_NUM=8
CONFIG_SOC_I2C_SUPPORT_SLAVE=y CONFIG_SOC_I2C_SUPPORT_SLAVE=y
@@ -120,9 +136,9 @@ CONFIG_SOC_I2C_SUPPORT_XTAL=y
CONFIG_SOC_I2C_SUPPORT_RTC=y CONFIG_SOC_I2C_SUPPORT_RTC=y
CONFIG_SOC_I2C_SUPPORT_10BIT_ADDR=y CONFIG_SOC_I2C_SUPPORT_10BIT_ADDR=y
CONFIG_SOC_I2C_SLAVE_SUPPORT_BROADCAST=y CONFIG_SOC_I2C_SLAVE_SUPPORT_BROADCAST=y
CONFIG_SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE=y
CONFIG_SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS=y CONFIG_SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS=y
CONFIG_SOC_I2S_NUM=1 CONFIG_SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE=y
CONFIG_SOC_I2S_NUM=2
CONFIG_SOC_I2S_HW_VERSION_2=y CONFIG_SOC_I2S_HW_VERSION_2=y
CONFIG_SOC_I2S_SUPPORTS_XTAL=y CONFIG_SOC_I2S_SUPPORTS_XTAL=y
CONFIG_SOC_I2S_SUPPORTS_PLL_F160M=y CONFIG_SOC_I2S_SUPPORTS_PLL_F160M=y
@@ -131,52 +147,74 @@ CONFIG_SOC_I2S_SUPPORTS_PDM=y
CONFIG_SOC_I2S_SUPPORTS_PDM_TX=y CONFIG_SOC_I2S_SUPPORTS_PDM_TX=y
CONFIG_SOC_I2S_SUPPORTS_PCM2PDM=y CONFIG_SOC_I2S_SUPPORTS_PCM2PDM=y
CONFIG_SOC_I2S_SUPPORTS_PDM_RX=y CONFIG_SOC_I2S_SUPPORTS_PDM_RX=y
CONFIG_SOC_I2S_SUPPORTS_PDM2PCM=y
CONFIG_SOC_I2S_PDM_MAX_TX_LINES=2 CONFIG_SOC_I2S_PDM_MAX_TX_LINES=2
CONFIG_SOC_I2S_PDM_MAX_RX_LINES=1 CONFIG_SOC_I2S_PDM_MAX_RX_LINES=4
CONFIG_SOC_I2S_SUPPORTS_TDM=y CONFIG_SOC_I2S_SUPPORTS_TDM=y
CONFIG_SOC_LEDC_SUPPORT_APB_CLOCK=y CONFIG_SOC_LEDC_SUPPORT_APB_CLOCK=y
CONFIG_SOC_LEDC_SUPPORT_XTAL_CLOCK=y CONFIG_SOC_LEDC_SUPPORT_XTAL_CLOCK=y
CONFIG_SOC_LEDC_TIMER_NUM=4 CONFIG_SOC_LEDC_TIMER_NUM=4
CONFIG_SOC_LEDC_CHANNEL_NUM=6 CONFIG_SOC_LEDC_CHANNEL_NUM=8
CONFIG_SOC_LEDC_TIMER_BIT_WIDTH=14 CONFIG_SOC_LEDC_TIMER_BIT_WIDTH=14
CONFIG_SOC_LEDC_SUPPORT_FADE_STOP=y CONFIG_SOC_LEDC_SUPPORT_FADE_STOP=y
CONFIG_SOC_MCPWM_GROUPS=2
CONFIG_SOC_MCPWM_TIMERS_PER_GROUP=3
CONFIG_SOC_MCPWM_OPERATORS_PER_GROUP=3
CONFIG_SOC_MCPWM_COMPARATORS_PER_OPERATOR=2
CONFIG_SOC_MCPWM_GENERATORS_PER_OPERATOR=2
CONFIG_SOC_MCPWM_TRIGGERS_PER_OPERATOR=2
CONFIG_SOC_MCPWM_GPIO_FAULTS_PER_GROUP=3
CONFIG_SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP=y
CONFIG_SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER=3
CONFIG_SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP=3
CONFIG_SOC_MCPWM_SWSYNC_CAN_PROPAGATE=y
CONFIG_SOC_MMU_LINEAR_ADDRESS_REGION_NUM=1 CONFIG_SOC_MMU_LINEAR_ADDRESS_REGION_NUM=1
CONFIG_SOC_MMU_PERIPH_NUM=1 CONFIG_SOC_MMU_PERIPH_NUM=1
CONFIG_SOC_MPU_MIN_REGION_SIZE=0x20000000 CONFIG_SOC_MPU_MIN_REGION_SIZE=0x20000000
CONFIG_SOC_MPU_REGIONS_MAX_NUM=8 CONFIG_SOC_MPU_REGIONS_MAX_NUM=8
CONFIG_SOC_PCNT_GROUPS=1
CONFIG_SOC_PCNT_UNITS_PER_GROUP=4
CONFIG_SOC_PCNT_CHANNELS_PER_UNIT=2
CONFIG_SOC_PCNT_THRES_POINT_PER_UNIT=2
CONFIG_SOC_RMT_GROUPS=1 CONFIG_SOC_RMT_GROUPS=1
CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP=2 CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP=4
CONFIG_SOC_RMT_RX_CANDIDATES_PER_GROUP=2 CONFIG_SOC_RMT_RX_CANDIDATES_PER_GROUP=4
CONFIG_SOC_RMT_CHANNELS_PER_GROUP=4 CONFIG_SOC_RMT_CHANNELS_PER_GROUP=8
CONFIG_SOC_RMT_MEM_WORDS_PER_CHANNEL=48 CONFIG_SOC_RMT_MEM_WORDS_PER_CHANNEL=48
CONFIG_SOC_RMT_SUPPORT_RX_PINGPONG=y CONFIG_SOC_RMT_SUPPORT_RX_PINGPONG=y
CONFIG_SOC_RMT_SUPPORT_RX_DEMODULATION=y CONFIG_SOC_RMT_SUPPORT_RX_DEMODULATION=y
CONFIG_SOC_RMT_SUPPORT_TX_ASYNC_STOP=y CONFIG_SOC_RMT_SUPPORT_TX_ASYNC_STOP=y
CONFIG_SOC_RMT_SUPPORT_TX_LOOP_COUNT=y CONFIG_SOC_RMT_SUPPORT_TX_LOOP_COUNT=y
CONFIG_SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP=y
CONFIG_SOC_RMT_SUPPORT_TX_SYNCHRO=y CONFIG_SOC_RMT_SUPPORT_TX_SYNCHRO=y
CONFIG_SOC_RMT_SUPPORT_TX_CARRIER_DATA_ONLY=y CONFIG_SOC_RMT_SUPPORT_TX_CARRIER_DATA_ONLY=y
CONFIG_SOC_RMT_SUPPORT_XTAL=y CONFIG_SOC_RMT_SUPPORT_XTAL=y
CONFIG_SOC_RMT_SUPPORT_APB=y
CONFIG_SOC_RMT_SUPPORT_RC_FAST=y CONFIG_SOC_RMT_SUPPORT_RC_FAST=y
CONFIG_SOC_RMT_SUPPORT_APB=y
CONFIG_SOC_RMT_SUPPORT_DMA=y
CONFIG_SOC_LCD_I80_SUPPORTED=y
CONFIG_SOC_LCD_RGB_SUPPORTED=y
CONFIG_SOC_LCD_I80_BUSES=1
CONFIG_SOC_LCD_RGB_PANELS=1
CONFIG_SOC_LCD_I80_BUS_WIDTH=16
CONFIG_SOC_LCD_RGB_DATA_WIDTH=16
CONFIG_SOC_LCD_SUPPORT_RGB_YUV_CONV=y
CONFIG_SOC_LCDCAM_I80_NUM_BUSES=1
CONFIG_SOC_LCDCAM_I80_BUS_WIDTH=16
CONFIG_SOC_LCDCAM_RGB_NUM_PANELS=1
CONFIG_SOC_LCDCAM_RGB_DATA_WIDTH=16
CONFIG_SOC_RTC_CNTL_CPU_PD_DMA_BUS_WIDTH=128 CONFIG_SOC_RTC_CNTL_CPU_PD_DMA_BUS_WIDTH=128
CONFIG_SOC_RTC_CNTL_CPU_PD_REG_FILE_NUM=108 CONFIG_SOC_RTC_CNTL_CPU_PD_REG_FILE_NUM=549
CONFIG_SOC_SLEEP_SYSTIMER_STALL_WORKAROUND=y CONFIG_SOC_RTC_CNTL_TAGMEM_PD_DMA_BUS_WIDTH=128
CONFIG_SOC_SLEEP_TGWDT_STOP_WORKAROUND=y CONFIG_SOC_RTCIO_PIN_COUNT=22
CONFIG_SOC_RTCIO_PIN_COUNT=0 CONFIG_SOC_RTCIO_INPUT_OUTPUT_SUPPORTED=y
CONFIG_SOC_MPI_MEM_BLOCKS_NUM=4 CONFIG_SOC_RTCIO_HOLD_SUPPORTED=y
CONFIG_SOC_MPI_OPERATIONS_NUM=3 CONFIG_SOC_RTCIO_WAKE_SUPPORTED=y
CONFIG_SOC_RSA_MAX_BIT_LEN=3072 CONFIG_SOC_LP_IO_CLOCK_IS_INDEPENDENT=y
CONFIG_SOC_SHA_DMA_MAX_BUFFER_SIZE=3968 CONFIG_SOC_SDM_GROUPS=y
CONFIG_SOC_SHA_SUPPORT_DMA=y CONFIG_SOC_SDM_CHANNELS_PER_GROUP=8
CONFIG_SOC_SHA_SUPPORT_RESUME=y
CONFIG_SOC_SHA_GDMA=y
CONFIG_SOC_SHA_SUPPORT_SHA1=y
CONFIG_SOC_SHA_SUPPORT_SHA224=y
CONFIG_SOC_SHA_SUPPORT_SHA256=y
CONFIG_SOC_SDM_GROUPS=1
CONFIG_SOC_SDM_CHANNELS_PER_GROUP=4
CONFIG_SOC_SDM_CLK_SUPPORT_APB=y CONFIG_SOC_SDM_CLK_SUPPORT_APB=y
CONFIG_SOC_SPI_PERIPH_NUM=2 CONFIG_SOC_SPI_PERIPH_NUM=3
CONFIG_SOC_SPI_MAX_CS_NUM=6 CONFIG_SOC_SPI_MAX_CS_NUM=6
CONFIG_SOC_SPI_MAXIMUM_BUFFER_SIZE=64 CONFIG_SOC_SPI_MAXIMUM_BUFFER_SIZE=64
CONFIG_SOC_SPI_SUPPORT_DDRCLK=y CONFIG_SOC_SPI_SUPPORT_DDRCLK=y
@@ -187,24 +225,19 @@ CONFIG_SOC_SPI_SUPPORT_SLAVE_HD_VER2=y
CONFIG_SOC_SPI_SUPPORT_CLK_APB=y CONFIG_SOC_SPI_SUPPORT_CLK_APB=y
CONFIG_SOC_SPI_SUPPORT_CLK_XTAL=y CONFIG_SOC_SPI_SUPPORT_CLK_XTAL=y
CONFIG_SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUT=y CONFIG_SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUT=y
CONFIG_SOC_MEMSPI_IS_INDEPENDENT=y
CONFIG_SOC_SPI_MAX_PRE_DIVIDER=16
CONFIG_SOC_SPI_SUPPORT_OCT=y
CONFIG_SOC_SPI_SCT_SUPPORTED=y CONFIG_SOC_SPI_SCT_SUPPORTED=y
CONFIG_SOC_SPI_SCT_REG_NUM=14 CONFIG_SOC_SPI_SCT_REG_NUM=14
CONFIG_SOC_SPI_SCT_BUFFER_NUM_MAX=y CONFIG_SOC_SPI_SCT_BUFFER_NUM_MAX=y
CONFIG_SOC_SPI_SCT_CONF_BITLEN_MAX=0x3FFFA CONFIG_SOC_SPI_SCT_CONF_BITLEN_MAX=0x3FFFA
CONFIG_SOC_MEMSPI_IS_INDEPENDENT=y CONFIG_SOC_MEMSPI_SRC_FREQ_120M_SUPPORTED=y
CONFIG_SOC_SPI_MAX_PRE_DIVIDER=16
CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE=y
CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND=y
CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_RESUME=y
CONFIG_SOC_SPI_MEM_SUPPORT_IDLE_INTR=y
CONFIG_SOC_SPI_MEM_SUPPORT_SW_SUSPEND=y
CONFIG_SOC_SPI_MEM_SUPPORT_CHECK_SUS=y
CONFIG_SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE=y
CONFIG_SOC_SPI_MEM_SUPPORT_WRAP=y
CONFIG_SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED=y CONFIG_SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED=y
CONFIG_SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED=y CONFIG_SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED=y
CONFIG_SOC_MEMSPI_SRC_FREQ_26M_SUPPORTED=y
CONFIG_SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED=y CONFIG_SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED=y
CONFIG_SOC_SPIRAM_SUPPORTED=y
CONFIG_SOC_SPIRAM_XIP_SUPPORTED=y
CONFIG_SOC_SYSTIMER_COUNTER_NUM=2 CONFIG_SOC_SYSTIMER_COUNTER_NUM=2
CONFIG_SOC_SYSTIMER_ALARM_NUM=3 CONFIG_SOC_SYSTIMER_ALARM_NUM=3
CONFIG_SOC_SYSTIMER_BIT_WIDTH_LO=32 CONFIG_SOC_SYSTIMER_BIT_WIDTH_LO=32
@@ -213,57 +246,75 @@ CONFIG_SOC_SYSTIMER_FIXED_DIVIDER=y
CONFIG_SOC_SYSTIMER_INT_LEVEL=y CONFIG_SOC_SYSTIMER_INT_LEVEL=y
CONFIG_SOC_SYSTIMER_ALARM_MISS_COMPENSATE=y CONFIG_SOC_SYSTIMER_ALARM_MISS_COMPENSATE=y
CONFIG_SOC_TIMER_GROUPS=2 CONFIG_SOC_TIMER_GROUPS=2
CONFIG_SOC_TIMER_GROUP_TIMERS_PER_GROUP=1 CONFIG_SOC_TIMER_GROUP_TIMERS_PER_GROUP=2
CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=54 CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=54
CONFIG_SOC_TIMER_GROUP_SUPPORT_XTAL=y CONFIG_SOC_TIMER_GROUP_SUPPORT_XTAL=y
CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y
CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=2 CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=4
CONFIG_SOC_LP_TIMER_BIT_WIDTH_LO=32 CONFIG_SOC_LP_TIMER_BIT_WIDTH_LO=32
CONFIG_SOC_LP_TIMER_BIT_WIDTH_HI=16 CONFIG_SOC_LP_TIMER_BIT_WIDTH_HI=16
CONFIG_SOC_MWDT_SUPPORT_XTAL=y CONFIG_SOC_TOUCH_SENSOR_VERSION=2
CONFIG_SOC_TOUCH_SENSOR_NUM=15
CONFIG_SOC_TOUCH_MIN_CHAN_ID=y
CONFIG_SOC_TOUCH_MAX_CHAN_ID=14
CONFIG_SOC_TOUCH_SUPPORT_BENCHMARK=y
CONFIG_SOC_TOUCH_SUPPORT_SLEEP_WAKEUP=y
CONFIG_SOC_TOUCH_SUPPORT_WATERPROOF=y
CONFIG_SOC_TOUCH_SUPPORT_PROX_SENSING=y
CONFIG_SOC_TOUCH_SUPPORT_DENOISE_CHAN=y
CONFIG_SOC_TOUCH_PROXIMITY_CHANNEL_NUM=3
CONFIG_SOC_TOUCH_PROXIMITY_MEAS_DONE_SUPPORTED=y
CONFIG_SOC_TOUCH_SAMPLE_CFG_NUM=1
CONFIG_SOC_TWAI_CONTROLLER_NUM=1 CONFIG_SOC_TWAI_CONTROLLER_NUM=1
CONFIG_SOC_TWAI_CLK_SUPPORT_APB=y CONFIG_SOC_TWAI_CLK_SUPPORT_APB=y
CONFIG_SOC_TWAI_BRP_MIN=2 CONFIG_SOC_TWAI_BRP_MIN=2
CONFIG_SOC_TWAI_BRP_MAX=16384 CONFIG_SOC_TWAI_BRP_MAX=16384
CONFIG_SOC_TWAI_SUPPORTS_RX_STATUS=y CONFIG_SOC_TWAI_SUPPORTS_RX_STATUS=y
CONFIG_SOC_EFUSE_DIS_DOWNLOAD_ICACHE=y CONFIG_SOC_UART_NUM=3
CONFIG_SOC_EFUSE_DIS_PAD_JTAG=y CONFIG_SOC_UART_HP_NUM=3
CONFIG_SOC_EFUSE_DIS_USB_JTAG=y
CONFIG_SOC_EFUSE_DIS_DIRECT_BOOT=y
CONFIG_SOC_EFUSE_SOFT_DIS_JTAG=y
CONFIG_SOC_EFUSE_DIS_ICACHE=y
CONFIG_SOC_EFUSE_BLOCK9_KEY_PURPOSE_QUIRK=y
CONFIG_SOC_SECURE_BOOT_V2_RSA=y
CONFIG_SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS=3
CONFIG_SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS=y
CONFIG_SOC_SUPPORT_SECURE_BOOT_REVOKE_KEY=y
CONFIG_SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX=32
CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES=y
CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_128=y
CONFIG_SOC_MEMPROT_CPU_PREFETCH_PAD_SIZE=16
CONFIG_SOC_MEMPROT_MEM_ALIGN_SIZE=512
CONFIG_SOC_UART_NUM=2
CONFIG_SOC_UART_HP_NUM=2
CONFIG_SOC_UART_FIFO_LEN=128 CONFIG_SOC_UART_FIFO_LEN=128
CONFIG_SOC_UART_BITRATE_MAX=5000000 CONFIG_SOC_UART_BITRATE_MAX=5000000
CONFIG_SOC_UART_SUPPORT_FSM_TX_WAIT_SEND=y
CONFIG_SOC_UART_SUPPORT_WAKEUP_INT=y
CONFIG_SOC_UART_SUPPORT_APB_CLK=y CONFIG_SOC_UART_SUPPORT_APB_CLK=y
CONFIG_SOC_UART_SUPPORT_RTC_CLK=y CONFIG_SOC_UART_SUPPORT_RTC_CLK=y
CONFIG_SOC_UART_SUPPORT_XTAL_CLK=y CONFIG_SOC_UART_SUPPORT_XTAL_CLK=y
CONFIG_SOC_UART_SUPPORT_WAKEUP_INT=y
CONFIG_SOC_UART_SUPPORT_FSM_TX_WAIT_SEND=y
CONFIG_SOC_UART_WAKEUP_SUPPORT_ACTIVE_THRESH_MODE=y CONFIG_SOC_UART_WAKEUP_SUPPORT_ACTIVE_THRESH_MODE=y
CONFIG_SOC_COEX_HW_PTI=y CONFIG_SOC_USB_OTG_PERIPH_NUM=1
CONFIG_SOC_PHY_DIG_REGS_MEM_SIZE=21 CONFIG_SOC_SHA_DMA_MAX_BUFFER_SIZE=3968
CONFIG_SOC_MAC_BB_PD_MEM_SIZE=192 CONFIG_SOC_SHA_SUPPORT_DMA=y
CONFIG_SOC_WIFI_LIGHT_SLEEP_CLK_WIDTH=12 CONFIG_SOC_SHA_SUPPORT_RESUME=y
CONFIG_SOC_SHA_GDMA=y
CONFIG_SOC_SHA_SUPPORT_SHA1=y
CONFIG_SOC_SHA_SUPPORT_SHA224=y
CONFIG_SOC_SHA_SUPPORT_SHA256=y
CONFIG_SOC_SHA_SUPPORT_SHA384=y
CONFIG_SOC_SHA_SUPPORT_SHA512=y
CONFIG_SOC_SHA_SUPPORT_SHA512_224=y
CONFIG_SOC_SHA_SUPPORT_SHA512_256=y
CONFIG_SOC_SHA_SUPPORT_SHA512_T=y
CONFIG_SOC_MPI_MEM_BLOCKS_NUM=4
CONFIG_SOC_MPI_OPERATIONS_NUM=3
CONFIG_SOC_RSA_MAX_BIT_LEN=4096
CONFIG_SOC_AES_SUPPORT_DMA=y
CONFIG_SOC_AES_GDMA=y
CONFIG_SOC_AES_SUPPORT_AES_128=y
CONFIG_SOC_AES_SUPPORT_AES_256=y
CONFIG_SOC_PM_SUPPORT_EXT0_WAKEUP=y
CONFIG_SOC_PM_SUPPORT_EXT1_WAKEUP=y
CONFIG_SOC_PM_SUPPORT_EXT_WAKEUP=y
CONFIG_SOC_PM_SUPPORT_WIFI_WAKEUP=y CONFIG_SOC_PM_SUPPORT_WIFI_WAKEUP=y
CONFIG_SOC_PM_SUPPORT_BT_WAKEUP=y CONFIG_SOC_PM_SUPPORT_BT_WAKEUP=y
CONFIG_SOC_PM_SUPPORT_TOUCH_SENSOR_WAKEUP=y
CONFIG_SOC_PM_SUPPORT_CPU_PD=y CONFIG_SOC_PM_SUPPORT_CPU_PD=y
CONFIG_SOC_PM_SUPPORT_WIFI_PD=y CONFIG_SOC_PM_SUPPORT_TAGMEM_PD=y
CONFIG_SOC_PM_SUPPORT_BT_PD=y CONFIG_SOC_PM_SUPPORT_RTC_PERIPH_PD=y
CONFIG_SOC_PM_SUPPORT_RC_FAST_PD=y CONFIG_SOC_PM_SUPPORT_RC_FAST_PD=y
CONFIG_SOC_PM_SUPPORT_VDDSDIO_PD=y CONFIG_SOC_PM_SUPPORT_VDDSDIO_PD=y
CONFIG_SOC_PM_SUPPORT_MAC_BB_PD=y CONFIG_SOC_PM_SUPPORT_MAC_BB_PD=y
CONFIG_SOC_PM_SUPPORT_MODEM_PD=y
CONFIG_SOC_CONFIGURABLE_VDDSDIO_SUPPORTED=y
CONFIG_SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY=y
CONFIG_SOC_PM_CPU_RETENTION_BY_RTCCNTL=y CONFIG_SOC_PM_CPU_RETENTION_BY_RTCCNTL=y
CONFIG_SOC_PM_MODEM_RETENTION_BY_BACKUPDMA=y CONFIG_SOC_PM_MODEM_RETENTION_BY_BACKUPDMA=y
CONFIG_SOC_PM_MODEM_PD_BY_SW=y CONFIG_SOC_PM_MODEM_PD_BY_SW=y
@@ -272,8 +323,46 @@ CONFIG_SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256=y
CONFIG_SOC_CLK_RC_FAST_SUPPORT_CALIBRATION=y CONFIG_SOC_CLK_RC_FAST_SUPPORT_CALIBRATION=y
CONFIG_SOC_CLK_XTAL32K_SUPPORTED=y CONFIG_SOC_CLK_XTAL32K_SUPPORTED=y
CONFIG_SOC_CLK_LP_FAST_SUPPORT_XTAL_D2=y CONFIG_SOC_CLK_LP_FAST_SUPPORT_XTAL_D2=y
CONFIG_SOC_EFUSE_DIS_DOWNLOAD_ICACHE=y
CONFIG_SOC_EFUSE_DIS_DOWNLOAD_DCACHE=y
CONFIG_SOC_EFUSE_HARD_DIS_JTAG=y
CONFIG_SOC_EFUSE_DIS_USB_JTAG=y
CONFIG_SOC_EFUSE_SOFT_DIS_JTAG=y
CONFIG_SOC_EFUSE_DIS_DIRECT_BOOT=y
CONFIG_SOC_EFUSE_DIS_ICACHE=y
CONFIG_SOC_EFUSE_BLOCK9_KEY_PURPOSE_QUIRK=y
CONFIG_SOC_SECURE_BOOT_V2_RSA=y
CONFIG_SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS=3
CONFIG_SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS=y
CONFIG_SOC_SUPPORT_SECURE_BOOT_REVOKE_KEY=y
CONFIG_SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX=64
CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES=y
CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_OPTIONS=y
CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_128=y
CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_256=y
CONFIG_SOC_MEMPROT_CPU_PREFETCH_PAD_SIZE=16
CONFIG_SOC_MEMPROT_MEM_ALIGN_SIZE=256
CONFIG_SOC_PHY_DIG_REGS_MEM_SIZE=21
CONFIG_SOC_MAC_BB_PD_MEM_SIZE=192
CONFIG_SOC_WIFI_LIGHT_SLEEP_CLK_WIDTH=12
CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE=y
CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND=y
CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_RESUME=y
CONFIG_SOC_SPI_MEM_SUPPORT_SW_SUSPEND=y
CONFIG_SOC_SPI_MEM_SUPPORT_OPI_MODE=y
CONFIG_SOC_SPI_MEM_SUPPORT_TIMING_TUNING=y
CONFIG_SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE=y
CONFIG_SOC_SPI_MEM_SUPPORT_WRAP=y
CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY=y
CONFIG_SOC_MEMSPI_CORE_CLK_SHARED_WITH_PSRAM=y
CONFIG_SOC_SPI_MEM_SUPPORT_CACHE_32BIT_ADDR_MAP=y
CONFIG_SOC_COEX_HW_PTI=y
CONFIG_SOC_EXTERNAL_COEX_LEADER_TX_LINE=y
CONFIG_SOC_SDMMC_USE_GPIO_MATRIX=y
CONFIG_SOC_SDMMC_NUM_SLOTS=2
CONFIG_SOC_SDMMC_SUPPORT_XTAL_CLOCK=y
CONFIG_SOC_SDMMC_DELAY_PHASE_NUM=4
CONFIG_SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC=y CONFIG_SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC=y
CONFIG_SOC_TEMPERATURE_SENSOR_SUPPORT_XTAL=y
CONFIG_SOC_WIFI_HW_TSF=y CONFIG_SOC_WIFI_HW_TSF=y
CONFIG_SOC_WIFI_FTM_SUPPORT=y CONFIG_SOC_WIFI_FTM_SUPPORT=y
CONFIG_SOC_WIFI_GCMP_SUPPORT=y CONFIG_SOC_WIFI_GCMP_SUPPORT=y
@@ -287,16 +376,17 @@ CONFIG_SOC_BLE_MESH_SUPPORTED=y
CONFIG_SOC_BLE_50_SUPPORTED=y CONFIG_SOC_BLE_50_SUPPORTED=y
CONFIG_SOC_BLE_DEVICE_PRIVACY_SUPPORTED=y CONFIG_SOC_BLE_DEVICE_PRIVACY_SUPPORTED=y
CONFIG_SOC_BLUFI_SUPPORTED=y CONFIG_SOC_BLUFI_SUPPORTED=y
CONFIG_SOC_ULP_HAS_ADC=y
CONFIG_SOC_PHY_COMBO_MODULE=y CONFIG_SOC_PHY_COMBO_MODULE=y
CONFIG_IDF_CMAKE=y CONFIG_IDF_CMAKE=y
CONFIG_IDF_TOOLCHAIN="gcc" CONFIG_IDF_TOOLCHAIN="gcc"
CONFIG_IDF_TOOLCHAIN_GCC=y CONFIG_IDF_TOOLCHAIN_GCC=y
CONFIG_IDF_TARGET_ARCH_RISCV=y CONFIG_IDF_TARGET_ARCH_XTENSA=y
CONFIG_IDF_TARGET_ARCH="riscv" CONFIG_IDF_TARGET_ARCH="xtensa"
CONFIG_IDF_TARGET="esp32c3" CONFIG_IDF_TARGET="esp32s3"
CONFIG_IDF_INIT_VERSION="5.5.0" CONFIG_IDF_INIT_VERSION="5.5.0"
CONFIG_IDF_TARGET_ESP32C3=y CONFIG_IDF_TARGET_ESP32S3=y
CONFIG_IDF_FIRMWARE_CHIP_ID=0x0005 CONFIG_IDF_FIRMWARE_CHIP_ID=0x0009
# #
# Build type # Build type
@@ -346,10 +436,10 @@ CONFIG_BOOTLOADER_LOG_VERSION=1
# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set # CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set
# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set # CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set
# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set # CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set
CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y # CONFIG_BOOTLOADER_LOG_LEVEL_INFO is not set
# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG=y
# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set # CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set
CONFIG_BOOTLOADER_LOG_LEVEL=3 CONFIG_BOOTLOADER_LOG_LEVEL=4
# #
# Format # Format
@@ -366,6 +456,7 @@ CONFIG_BOOTLOADER_LOG_TIMESTAMP_SOURCE_CPU_TICKS=y
CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y
# end of Serial Flash Configurations # end of Serial Flash Configurations
CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y
# CONFIG_BOOTLOADER_FACTORY_RESET is not set # CONFIG_BOOTLOADER_FACTORY_RESET is not set
# CONFIG_BOOTLOADER_APP_TEST is not set # CONFIG_BOOTLOADER_APP_TEST is not set
CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y
@@ -405,11 +496,13 @@ CONFIG_ESP_ROM_HAS_CRC_BE=y
CONFIG_ESP_ROM_HAS_MZ_CRC32=y CONFIG_ESP_ROM_HAS_MZ_CRC32=y
CONFIG_ESP_ROM_HAS_JPEG_DECODE=y CONFIG_ESP_ROM_HAS_JPEG_DECODE=y
CONFIG_ESP_ROM_UART_CLK_IS_XTAL=y CONFIG_ESP_ROM_UART_CLK_IS_XTAL=y
CONFIG_ESP_ROM_USB_SERIAL_DEVICE_NUM=3
CONFIG_ESP_ROM_HAS_RETARGETABLE_LOCKING=y CONFIG_ESP_ROM_HAS_RETARGETABLE_LOCKING=y
CONFIG_ESP_ROM_USB_OTG_NUM=3
CONFIG_ESP_ROM_USB_SERIAL_DEVICE_NUM=4
CONFIG_ESP_ROM_HAS_ERASE_0_REGION_BUG=y CONFIG_ESP_ROM_HAS_ERASE_0_REGION_BUG=y
CONFIG_ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV=y CONFIG_ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV=y
CONFIG_ESP_ROM_GET_CLK_FREQ=y CONFIG_ESP_ROM_GET_CLK_FREQ=y
CONFIG_ESP_ROM_HAS_HAL_WDT=y
CONFIG_ESP_ROM_NEEDS_SWSETUP_WORKAROUND=y CONFIG_ESP_ROM_NEEDS_SWSETUP_WORKAROUND=y
CONFIG_ESP_ROM_HAS_LAYOUT_TABLE=y CONFIG_ESP_ROM_HAS_LAYOUT_TABLE=y
CONFIG_ESP_ROM_HAS_SPI_FLASH=y CONFIG_ESP_ROM_HAS_SPI_FLASH=y
@@ -419,10 +512,13 @@ CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT=y
CONFIG_ESP_ROM_HAS_NEWLIB_32BIT_TIME=y CONFIG_ESP_ROM_HAS_NEWLIB_32BIT_TIME=y
CONFIG_ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE=y CONFIG_ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE=y
CONFIG_ESP_ROM_RAM_APP_NEEDS_MMU_INIT=y CONFIG_ESP_ROM_RAM_APP_NEEDS_MMU_INIT=y
CONFIG_ESP_ROM_HAS_FLASH_COUNT_PAGES_BUG=y
CONFIG_ESP_ROM_HAS_CACHE_SUSPEND_WAITI_BUG=y
CONFIG_ESP_ROM_HAS_CACHE_WRITEBACK_BUG=y
CONFIG_ESP_ROM_HAS_SW_FLOAT=y CONFIG_ESP_ROM_HAS_SW_FLOAT=y
CONFIG_ESP_ROM_USB_OTG_NUM=-1
CONFIG_ESP_ROM_HAS_VERSION=y CONFIG_ESP_ROM_HAS_VERSION=y
CONFIG_ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB=y CONFIG_ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB=y
CONFIG_ESP_ROM_HAS_OUTPUT_PUTC_FUNC=y
CONFIG_ESP_ROM_CONSOLE_OUTPUT_SECONDARY=y CONFIG_ESP_ROM_CONSOLE_OUTPUT_SECONDARY=y
# #
@@ -438,15 +534,17 @@ CONFIG_BOOT_ROM_LOG_ALWAYS_ON=y
# Serial flasher config # Serial flasher config
# #
# CONFIG_ESPTOOLPY_NO_STUB is not set # CONFIG_ESPTOOLPY_NO_STUB is not set
# CONFIG_ESPTOOLPY_OCT_FLASH is not set
CONFIG_ESPTOOLPY_FLASH_MODE_AUTO_DETECT=y
# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set # CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set
# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set # CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set
CONFIG_ESPTOOLPY_FLASHMODE_DIO=y CONFIG_ESPTOOLPY_FLASHMODE_DIO=y
# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set # CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set
CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y
CONFIG_ESPTOOLPY_FLASHMODE="dio" CONFIG_ESPTOOLPY_FLASHMODE="dio"
# CONFIG_ESPTOOLPY_FLASHFREQ_120M is not set
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set # CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set
# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set
# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set # CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
CONFIG_ESPTOOLPY_FLASHFREQ="80m" CONFIG_ESPTOOLPY_FLASHFREQ="80m"
# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
@@ -505,7 +603,6 @@ CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set # CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set
# CONFIG_COMPILER_NO_MERGE_CONSTANTS is not set # CONFIG_COMPILER_NO_MERGE_CONSTANTS is not set
# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set # CONFIG_COMPILER_WARN_WRITE_STRINGS is not set
# CONFIG_COMPILER_SAVE_RESTORE_LIBCALLS is not set
CONFIG_COMPILER_DISABLE_DEFAULT_ERRORS=y CONFIG_COMPILER_DISABLE_DEFAULT_ERRORS=y
# CONFIG_COMPILER_DISABLE_GCC12_WARNINGS is not set # CONFIG_COMPILER_DISABLE_GCC12_WARNINGS is not set
# CONFIG_COMPILER_DISABLE_GCC13_WARNINGS is not set # CONFIG_COMPILER_DISABLE_GCC13_WARNINGS is not set
@@ -528,6 +625,7 @@ CONFIG_COMPILER_ORPHAN_SECTIONS_WARNING=y
# CONFIG_APPTRACE_DEST_JTAG is not set # CONFIG_APPTRACE_DEST_JTAG is not set
CONFIG_APPTRACE_DEST_NONE=y CONFIG_APPTRACE_DEST_NONE=y
# CONFIG_APPTRACE_DEST_UART1 is not set # CONFIG_APPTRACE_DEST_UART1 is not set
# CONFIG_APPTRACE_DEST_UART2 is not set
# CONFIG_APPTRACE_DEST_USB_CDC is not set # CONFIG_APPTRACE_DEST_USB_CDC is not set
CONFIG_APPTRACE_DEST_UART_NONE=y CONFIG_APPTRACE_DEST_UART_NONE=y
CONFIG_APPTRACE_UART_TASK_PRIO=1 CONFIG_APPTRACE_UART_TASK_PRIO=1
@@ -576,6 +674,13 @@ CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM=y
# end of Legacy ADC Calibration Configuration # end of Legacy ADC Calibration Configuration
# end of Legacy ADC Driver Configuration # end of Legacy ADC Driver Configuration
#
# Legacy MCPWM Driver Configurations
#
# CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_MCPWM_SKIP_LEGACY_CONFLICT_CHECK is not set
# end of Legacy MCPWM Driver Configurations
# #
# Legacy Timer Group Driver Configurations # Legacy Timer Group Driver Configurations
# #
@@ -603,6 +708,13 @@ CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM=y
# CONFIG_I2C_SKIP_LEGACY_CONFLICT_CHECK is not set # CONFIG_I2C_SKIP_LEGACY_CONFLICT_CHECK is not set
# end of Legacy I2C Driver Configurations # end of Legacy I2C Driver Configurations
#
# Legacy PCNT Driver Configurations
#
# CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_PCNT_SKIP_LEGACY_CONFLICT_CHECK is not set
# end of Legacy PCNT Driver Configurations
# #
# Legacy SDM Driver Configurations # Legacy SDM Driver Configurations
# #
@@ -616,6 +728,13 @@ CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM=y
# CONFIG_TEMP_SENSOR_SUPPRESS_DEPRECATE_WARN is not set # CONFIG_TEMP_SENSOR_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_TEMP_SENSOR_SKIP_LEGACY_CONFLICT_CHECK is not set # CONFIG_TEMP_SENSOR_SKIP_LEGACY_CONFLICT_CHECK is not set
# end of Legacy Temperature Sensor Driver Configurations # end of Legacy Temperature Sensor Driver Configurations
#
# Legacy Touch Sensor Driver Configurations
#
# CONFIG_TOUCH_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_TOUCH_SKIP_LEGACY_CONFLICT_CHECK is not set
# end of Legacy Touch Sensor Driver Configurations
# end of Driver Configurations # end of Driver Configurations
# #
@@ -646,7 +765,6 @@ CONFIG_ESP_TLS_USE_DS_PERIPHERAL=y
# CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM is not set # CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM is not set
# CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE is not set # CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE is not set
# CONFIG_ADC_CONTINUOUS_FORCE_USE_ADC2_ON_C3_S3 is not set # CONFIG_ADC_CONTINUOUS_FORCE_USE_ADC2_ON_C3_S3 is not set
# CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3 is not set
# CONFIG_ADC_ENABLE_DEBUG_LOG is not set # CONFIG_ADC_ENABLE_DEBUG_LOG is not set
# end of ADC and ADC Calibration # end of ADC and ADC Calibration
@@ -702,6 +820,22 @@ CONFIG_I2C_MASTER_ISR_HANDLER_IN_IRAM=y
# CONFIG_LEDC_CTRL_FUNC_IN_IRAM is not set # CONFIG_LEDC_CTRL_FUNC_IN_IRAM is not set
# end of ESP-Driver:LEDC Configurations # end of ESP-Driver:LEDC Configurations
#
# ESP-Driver:MCPWM Configurations
#
# CONFIG_MCPWM_ISR_IRAM_SAFE is not set
# CONFIG_MCPWM_CTRL_FUNC_IN_IRAM is not set
# CONFIG_MCPWM_ENABLE_DEBUG_LOG is not set
# end of ESP-Driver:MCPWM Configurations
#
# ESP-Driver:PCNT Configurations
#
# CONFIG_PCNT_CTRL_FUNC_IN_IRAM is not set
# CONFIG_PCNT_ISR_IRAM_SAFE is not set
# CONFIG_PCNT_ENABLE_DEBUG_LOG is not set
# end of ESP-Driver:PCNT Configurations
# #
# ESP-Driver:RMT Configurations # ESP-Driver:RMT Configurations
# #
@@ -728,6 +862,15 @@ CONFIG_SPI_MASTER_ISR_IN_IRAM=y
CONFIG_SPI_SLAVE_ISR_IN_IRAM=y CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
# end of ESP-Driver:SPI Configurations # end of ESP-Driver:SPI Configurations
#
# ESP-Driver:Touch Sensor Configurations
#
# CONFIG_TOUCH_CTRL_FUNC_IN_IRAM is not set
# CONFIG_TOUCH_ISR_IRAM_SAFE is not set
# CONFIG_TOUCH_ENABLE_DEBUG_LOG is not set
# CONFIG_TOUCH_SKIP_FSM_CHECK is not set
# end of ESP-Driver:Touch Sensor Configurations
# #
# ESP-Driver:Temperature Sensor Configurations # ESP-Driver:Temperature Sensor Configurations
# #
@@ -828,25 +971,22 @@ CONFIG_ESP_HTTPS_SERVER_EVENT_POST_TIMEOUT=2000
# #
# Chip revision # Chip revision
# #
# CONFIG_ESP32C3_REV_MIN_0 is not set CONFIG_ESP32S3_REV_MIN_0=y
# CONFIG_ESP32C3_REV_MIN_1 is not set # CONFIG_ESP32S3_REV_MIN_1 is not set
# CONFIG_ESP32C3_REV_MIN_2 is not set # CONFIG_ESP32S3_REV_MIN_2 is not set
CONFIG_ESP32C3_REV_MIN_3=y CONFIG_ESP32S3_REV_MIN_FULL=0
# CONFIG_ESP32C3_REV_MIN_4 is not set CONFIG_ESP_REV_MIN_FULL=0
# CONFIG_ESP32C3_REV_MIN_101 is not set
CONFIG_ESP32C3_REV_MIN_FULL=3
CONFIG_ESP_REV_MIN_FULL=3
# #
# Maximum Supported ESP32-C3 Revision (Rev v1.99) # Maximum Supported ESP32-S3 Revision (Rev v0.99)
# #
CONFIG_ESP32C3_REV_MAX_FULL=199 CONFIG_ESP32S3_REV_MAX_FULL=99
CONFIG_ESP_REV_MAX_FULL=199 CONFIG_ESP_REV_MAX_FULL=99
CONFIG_ESP_EFUSE_BLOCK_REV_MIN_FULL=0 CONFIG_ESP_EFUSE_BLOCK_REV_MIN_FULL=0
CONFIG_ESP_EFUSE_BLOCK_REV_MAX_FULL=199 CONFIG_ESP_EFUSE_BLOCK_REV_MAX_FULL=199
# #
# Maximum Supported ESP32-C3 eFuse Block Revision (eFuse Block Rev v1.99) # Maximum Supported ESP32-S3 eFuse Block Revision (eFuse Block Rev v1.99)
# #
# end of Chip revision # end of Chip revision
@@ -859,9 +999,9 @@ CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y
CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y
CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES_FOUR=y CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES_FOUR=y
CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES=4 CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES=4
# CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES_TWO is not set # CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES_TWO is not set
CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES_FOUR=y CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES_FOUR=y
CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES=4 CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES=4
# CONFIG_ESP_MAC_USE_CUSTOM_MAC_AS_BASE_MAC is not set # CONFIG_ESP_MAC_USE_CUSTOM_MAC_AS_BASE_MAC is not set
# end of MAC Config # end of MAC Config
@@ -870,9 +1010,10 @@ CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES=4
# #
# CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set # CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set
CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y
# CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU is not set CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU=y
CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y
CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND=y CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND=y
CONFIG_ESP_SLEEP_WAIT_FLASH_READY_EXTRA_DELAY=0 CONFIG_ESP_SLEEP_WAIT_FLASH_READY_EXTRA_DELAY=2000
# CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION is not set # CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION is not set
# CONFIG_ESP_SLEEP_DEBUG is not set # CONFIG_ESP_SLEEP_DEBUG is not set
CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS=y CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS=y
@@ -924,6 +1065,7 @@ CONFIG_ESP_BROWNOUT_DET_LVL_SEL_7=y
# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_4 is not set # CONFIG_ESP_BROWNOUT_DET_LVL_SEL_4 is not set
# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_3 is not set # CONFIG_ESP_BROWNOUT_DET_LVL_SEL_3 is not set
# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_2 is not set # CONFIG_ESP_BROWNOUT_DET_LVL_SEL_2 is not set
# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_1 is not set
CONFIG_ESP_BROWNOUT_DET_LVL=7 CONFIG_ESP_BROWNOUT_DET_LVL=7
CONFIG_ESP_BROWNOUT_USE_INTR=y CONFIG_ESP_BROWNOUT_USE_INTR=y
# end of Brownout Detector # end of Brownout Detector
@@ -936,11 +1078,14 @@ CONFIG_ESP_SPI_BUS_LOCK_ISR_FUNCS_IN_IRAM=y
# ESP-Driver:LCD Controller Configurations # ESP-Driver:LCD Controller Configurations
# #
# CONFIG_LCD_ENABLE_DEBUG_LOG is not set # CONFIG_LCD_ENABLE_DEBUG_LOG is not set
# CONFIG_LCD_RGB_ISR_IRAM_SAFE is not set
# CONFIG_LCD_RGB_RESTART_IN_VSYNC is not set
# end of ESP-Driver:LCD Controller Configurations # end of ESP-Driver:LCD Controller Configurations
# #
# ESP-MM: Memory Management Configurations # ESP-MM: Memory Management Configurations
# #
# CONFIG_ESP_MM_CACHE_MSYNC_C2M_CHUNKED_OPS is not set
# end of ESP-MM: Memory Management Configurations # end of ESP-MM: Memory Management Configurations
# #
@@ -988,11 +1133,14 @@ CONFIG_ESP_PHY_CALIBRATION_MODE=0
# CONFIG_PM_ENABLE is not set # CONFIG_PM_ENABLE is not set
# CONFIG_PM_SLP_IRAM_OPT is not set # CONFIG_PM_SLP_IRAM_OPT is not set
CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y
CONFIG_PM_RESTORE_CACHE_TAGMEM_AFTER_LIGHT_SLEEP=y
# end of Power Management # end of Power Management
# #
# ESP PSRAM # ESP PSRAM
# #
# CONFIG_SPIRAM is not set
# end of ESP PSRAM
# #
# ESP Ringbuf # ESP Ringbuf
@@ -1010,18 +1158,55 @@ CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y
# #
# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80 is not set # CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80 is not set
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y
# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240 is not set
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=160 CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=160
#
# Cache config
#
CONFIG_ESP32S3_INSTRUCTION_CACHE_16KB=y
# CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB is not set
CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE=0x4000
# CONFIG_ESP32S3_INSTRUCTION_CACHE_4WAYS is not set
CONFIG_ESP32S3_INSTRUCTION_CACHE_8WAYS=y
CONFIG_ESP32S3_ICACHE_ASSOCIATED_WAYS=8
# CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_16B is not set
CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_32B=y
CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_SIZE=32
# CONFIG_ESP32S3_DATA_CACHE_16KB is not set
CONFIG_ESP32S3_DATA_CACHE_32KB=y
# CONFIG_ESP32S3_DATA_CACHE_64KB is not set
CONFIG_ESP32S3_DATA_CACHE_SIZE=0x8000
# CONFIG_ESP32S3_DATA_CACHE_4WAYS is not set
CONFIG_ESP32S3_DATA_CACHE_8WAYS=y
CONFIG_ESP32S3_DCACHE_ASSOCIATED_WAYS=8
# CONFIG_ESP32S3_DATA_CACHE_LINE_16B is not set
CONFIG_ESP32S3_DATA_CACHE_LINE_32B=y
# CONFIG_ESP32S3_DATA_CACHE_LINE_64B is not set
CONFIG_ESP32S3_DATA_CACHE_LINE_SIZE=32
# end of Cache config
#
# Memory
#
# CONFIG_ESP32S3_RTCDATA_IN_FAST_MEM is not set
# CONFIG_ESP32S3_USE_FIXED_STATIC_RAM_SIZE is not set
# end of Memory
#
# Trace memory
#
# CONFIG_ESP32S3_TRAX is not set
CONFIG_ESP32S3_TRACEMEM_RESERVE_DRAM=0x0
# end of Trace memory
# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set # CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set
CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y
# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set # CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set
# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set # CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set
CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS=0 CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS=0
CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE=y
CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK=y CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK=y
CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=y CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=y
CONFIG_ESP_SYSTEM_NO_BACKTRACE=y
# CONFIG_ESP_SYSTEM_USE_EH_FRAME is not set
# CONFIG_ESP_SYSTEM_USE_FRAME_POINTER is not set
# #
# Memory protection # Memory protection
@@ -1034,10 +1219,12 @@ CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304
CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584
CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y
# CONFIG_ESP_MAIN_TASK_AFFINITY_CPU1 is not set
# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set # CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set
CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 CONFIG_ESP_MAIN_TASK_AFFINITY=0x0
CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048
CONFIG_ESP_CONSOLE_UART_DEFAULT=y CONFIG_ESP_CONSOLE_UART_DEFAULT=y
# CONFIG_ESP_CONSOLE_USB_CDC is not set
# CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set # CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set
# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set # CONFIG_ESP_CONSOLE_UART_CUSTOM is not set
# CONFIG_ESP_CONSOLE_NONE is not set # CONFIG_ESP_CONSOLE_NONE is not set
@@ -1050,23 +1237,26 @@ CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM=0
CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
CONFIG_ESP_INT_WDT=y CONFIG_ESP_INT_WDT=y
CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
CONFIG_ESP_INT_WDT_CHECK_CPU1=y
CONFIG_ESP_TASK_WDT_EN=y CONFIG_ESP_TASK_WDT_EN=y
CONFIG_ESP_TASK_WDT_INIT=y CONFIG_ESP_TASK_WDT_INIT=y
# CONFIG_ESP_TASK_WDT_PANIC is not set # CONFIG_ESP_TASK_WDT_PANIC is not set
CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 CONFIG_ESP_TASK_WDT_TIMEOUT_S=5
CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y
# CONFIG_ESP_PANIC_HANDLER_IRAM is not set # CONFIG_ESP_PANIC_HANDLER_IRAM is not set
# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set # CONFIG_ESP_DEBUG_STUBS_ENABLE is not set
CONFIG_ESP_DEBUG_OCDAWARE=y CONFIG_ESP_DEBUG_OCDAWARE=y
CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4=y CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4=y
CONFIG_ESP_SYSTEM_HW_STACK_GUARD=y CONFIG_ESP_SYSTEM_BBPLL_RECALIB=y
CONFIG_ESP_SYSTEM_HW_PC_RECORD=y
# end of ESP System Settings # end of ESP System Settings
# #
# IPC (Inter-Processor Call) # IPC (Inter-Processor Call)
# #
CONFIG_ESP_IPC_TASK_STACK_SIZE=1024 CONFIG_ESP_IPC_TASK_STACK_SIZE=1280
CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y
CONFIG_ESP_IPC_ISR_ENABLE=y
# end of IPC (Inter-Processor Call) # end of IPC (Inter-Processor Call)
# #
@@ -1105,6 +1295,8 @@ CONFIG_ESP_WIFI_TX_BA_WIN=6
CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP_WIFI_RX_BA_WIN=6 CONFIG_ESP_WIFI_RX_BA_WIN=6
CONFIG_ESP_WIFI_NVS_ENABLED=y CONFIG_ESP_WIFI_NVS_ENABLED=y
CONFIG_ESP_WIFI_TASK_PINNED_TO_CORE_0=y
# CONFIG_ESP_WIFI_TASK_PINNED_TO_CORE_1 is not set
CONFIG_ESP_WIFI_SOFTAP_BEACON_MAX_LEN=752 CONFIG_ESP_WIFI_SOFTAP_BEACON_MAX_LEN=752
CONFIG_ESP_WIFI_MGMT_SBUF_NUM=32 CONFIG_ESP_WIFI_MGMT_SBUF_NUM=32
CONFIG_ESP_WIFI_IRAM_OPT=y CONFIG_ESP_WIFI_IRAM_OPT=y
@@ -1209,9 +1401,8 @@ CONFIG_FATFS_LINK_LOCK=y
# Kernel # Kernel
# #
# CONFIG_FREERTOS_SMP is not set # CONFIG_FREERTOS_SMP is not set
CONFIG_FREERTOS_UNICORE=y # CONFIG_FREERTOS_UNICORE is not set
CONFIG_FREERTOS_HZ=100 CONFIG_FREERTOS_HZ=100
CONFIG_FREERTOS_OPTIMIZED_SCHEDULER=y
# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set # CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set
# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set # CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set
CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y
@@ -1224,6 +1415,7 @@ CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
CONFIG_FREERTOS_USE_TIMERS=y CONFIG_FREERTOS_USE_TIMERS=y
CONFIG_FREERTOS_TIMER_SERVICE_TASK_NAME="Tmr Svc" CONFIG_FREERTOS_TIMER_SERVICE_TASK_NAME="Tmr Svc"
# CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU0 is not set # CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU0 is not set
# CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU1 is not set
CONFIG_FREERTOS_TIMER_TASK_NO_AFFINITY=y CONFIG_FREERTOS_TIMER_TASK_NO_AFFINITY=y
CONFIG_FREERTOS_TIMER_SERVICE_TASK_CORE_AFFINITY=0x7FFFFFFF CONFIG_FREERTOS_TIMER_SERVICE_TASK_CORE_AFFINITY=0x7FFFFFFF
CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
@@ -1248,6 +1440,7 @@ CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS=y
CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y
CONFIG_FREERTOS_ISR_STACKSIZE=1536 CONFIG_FREERTOS_ISR_STACKSIZE=1536
CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y
# CONFIG_FREERTOS_FPU_IN_ISR is not set
CONFIG_FREERTOS_TICK_SUPPORT_SYSTIMER=y CONFIG_FREERTOS_TICK_SUPPORT_SYSTIMER=y
CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL1=y CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL1=y
# CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3 is not set # CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3 is not set
@@ -1267,7 +1460,7 @@ CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
CONFIG_FREERTOS_DEBUG_OCDAWARE=y CONFIG_FREERTOS_DEBUG_OCDAWARE=y
CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y
CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH=y CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH=y
CONFIG_FREERTOS_NUMBER_OF_CORES=1 CONFIG_FREERTOS_NUMBER_OF_CORES=2
# end of FreeRTOS # end of FreeRTOS
# #
@@ -1278,6 +1471,7 @@ CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y
# CONFIG_HAL_ASSERTION_SILENT is not set # CONFIG_HAL_ASSERTION_SILENT is not set
# CONFIG_HAL_ASSERTION_ENABLE is not set # CONFIG_HAL_ASSERTION_ENABLE is not set
CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2 CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2
CONFIG_HAL_WDT_USE_ROM_IMPL=y
# end of Hardware Abstraction Layer (HAL) and Low Level (LL) # end of Hardware Abstraction Layer (HAL) and Low Level (LL)
# #
@@ -1305,17 +1499,20 @@ CONFIG_LOG_VERSION=1
# #
# Log Level # Log Level
# #
# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set CONFIG_LOG_DEFAULT_LEVEL_NONE=y
# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set # CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set # CONFIG_LOG_DEFAULT_LEVEL_WARN is not set
CONFIG_LOG_DEFAULT_LEVEL_INFO=y # CONFIG_LOG_DEFAULT_LEVEL_INFO is not set
# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set # CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set
# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set # CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set
CONFIG_LOG_DEFAULT_LEVEL=3 CONFIG_LOG_DEFAULT_LEVEL=0
CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y
# CONFIG_LOG_MAXIMUM_LEVEL_ERROR is not set
# CONFIG_LOG_MAXIMUM_LEVEL_WARN is not set
# CONFIG_LOG_MAXIMUM_LEVEL_INFO is not set
# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set # CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set
# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set # CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set
CONFIG_LOG_MAXIMUM_LEVEL=3 CONFIG_LOG_MAXIMUM_LEVEL=0
# #
# Level Settings # Level Settings
@@ -1449,6 +1646,7 @@ CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y
CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072 CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072
CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set # CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set
# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set
CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF
CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3 CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3
CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5 CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5
@@ -1565,7 +1763,7 @@ CONFIG_MBEDTLS_AES_USE_INTERRUPT=y
CONFIG_MBEDTLS_AES_INTERRUPT_LEVEL=0 CONFIG_MBEDTLS_AES_INTERRUPT_LEVEL=0
CONFIG_MBEDTLS_GCM_SUPPORT_NON_AES_CIPHER=y CONFIG_MBEDTLS_GCM_SUPPORT_NON_AES_CIPHER=y
CONFIG_MBEDTLS_HARDWARE_MPI=y CONFIG_MBEDTLS_HARDWARE_MPI=y
CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI=y # CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI is not set
CONFIG_MBEDTLS_MPI_USE_INTERRUPT=y CONFIG_MBEDTLS_MPI_USE_INTERRUPT=y
CONFIG_MBEDTLS_MPI_INTERRUPT_LEVEL=0 CONFIG_MBEDTLS_MPI_INTERRUPT_LEVEL=0
CONFIG_MBEDTLS_HARDWARE_SHA=y CONFIG_MBEDTLS_HARDWARE_SHA=y
@@ -1728,6 +1926,9 @@ CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_PATCH_VERSION=y
CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5
CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
CONFIG_PTHREAD_STACK_MIN=768 CONFIG_PTHREAD_STACK_MIN=768
CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y
# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set
# CONFIG_PTHREAD_DEFAULT_CORE_1 is not set
CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1 CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1
CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread"
# end of PThreads # end of PThreads
@@ -1758,6 +1959,12 @@ CONFIG_SPI_FLASH_BROWNOUT_RESET=y
# #
# Features here require specific hardware (READ DOCS FIRST!) # Features here require specific hardware (READ DOCS FIRST!)
# #
# CONFIG_SPI_FLASH_HPM_ENA is not set
CONFIG_SPI_FLASH_HPM_AUTO=y
# CONFIG_SPI_FLASH_HPM_DIS is not set
CONFIG_SPI_FLASH_HPM_ON=y
CONFIG_SPI_FLASH_HPM_DC_AUTO=y
# CONFIG_SPI_FLASH_HPM_DC_DISABLE is not set
# CONFIG_SPI_FLASH_AUTO_SUSPEND is not set # CONFIG_SPI_FLASH_AUTO_SUSPEND is not set
CONFIG_SPI_FLASH_SUSPEND_TSUS_VAL_US=50 CONFIG_SPI_FLASH_SUSPEND_TSUS_VAL_US=50
# CONFIG_SPI_FLASH_FORCE_ENABLE_XMC_C_SUSPEND is not set # CONFIG_SPI_FLASH_FORCE_ENABLE_XMC_C_SUSPEND is not set
@@ -1801,6 +2008,7 @@ CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y
CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y
CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP=y CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP=y
CONFIG_SPI_FLASH_SUPPORT_TH_CHIP=y CONFIG_SPI_FLASH_SUPPORT_TH_CHIP=y
CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP=y
# end of Auto-detect flash chips # end of Auto-detect flash chips
CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y
@@ -1855,6 +2063,17 @@ CONFIG_WS_BUFFER_SIZE=1024
# end of Websocket # end of Websocket
# end of TCP Transport # end of TCP Transport
#
# Ultra Low Power (ULP) Co-processor
#
# CONFIG_ULP_COPROC_ENABLED is not set
#
# ULP Debugging Options
#
# end of ULP Debugging Options
# end of Ultra Low Power (ULP) Co-processor
# #
# Unity unit testing library # Unity unit testing library
# #
@@ -1867,6 +2086,34 @@ CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set # CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set
# end of Unity unit testing library # end of Unity unit testing library
#
# USB-OTG
#
CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE=256
CONFIG_USB_HOST_HW_BUFFER_BIAS_BALANCED=y
# CONFIG_USB_HOST_HW_BUFFER_BIAS_IN is not set
# CONFIG_USB_HOST_HW_BUFFER_BIAS_PERIODIC_OUT is not set
#
# Hub Driver Configuration
#
#
# Root Port configuration
#
CONFIG_USB_HOST_DEBOUNCE_DELAY_MS=250
CONFIG_USB_HOST_RESET_HOLD_MS=30
CONFIG_USB_HOST_RESET_RECOVERY_MS=30
CONFIG_USB_HOST_SET_ADDR_RECOVERY_MS=10
# end of Root Port configuration
# CONFIG_USB_HOST_HUBS_SUPPORTED is not set
# end of Hub Driver Configuration
# CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK is not set
CONFIG_USB_OTG_SUPPORTED=y
# end of USB-OTG
# #
# Virtual file system # Virtual file system
# #
+2357
View File
File diff suppressed because it is too large Load Diff
-111
View File
@@ -1,111 +0,0 @@
import serial
import time
from parser import UartMessageParser, ParserError
from message_builder import MessageBuilder, MessageBuilderError, PayloadTooLargeError, BufferOverflowError
import payload_parser
SERIAL_PORT = "/dev/ttyUSB0"
BAUDRATE = 115200
WRITE_TIMEOUT = 0.5
READ_TIMEOUT = 1.0
payload_parser = payload_parser.PayloadParser()
def on_message_received_from_uart(message_id: int, payload: bytes, payload_length: int):
"""
Callback-Funktion, die aufgerufen wird, wenn der Parser eine vollständige,
gültige Nachricht empfangen hat.
"""
print(f"\n[MAIN] Nachricht erfolgreich empfangen! ID: 0x{
message_id:02X}")
print(f"[MAIN] Payload ({payload_length} Bytes): {
payload[:payload_length].hex().upper()}")
parsed_object = payload_parser.parse_payload(
message_id, payload[:payload_length])
print(parsed_object)
def on_message_fail_from_uart(message_id: int, current_message_buffer: bytes,
current_index: int, error_type: ParserError):
"""
Callback-Funktion, die aufgerufen wird, wenn der Parser einen Fehler
beim Empfang einer Nachricht feststellt.
"""
print(f"\n[MAIN] Fehler beim Parsen der Nachricht! ID: 0x{
message_id:02X}")
print(f"[MAIN] Fehler: {error_type.name}")
print(f"[MAIN] Bisheriger Puffer ({current_index} Bytes): {
current_message_buffer[:current_index].hex().upper()}")
def run_uart_test():
"""
Führt den UART-Test durch: Sendet eine Nachricht und liest alle Antworten.
"""
ser = None
parser = UartMessageParser(
on_message_received_callback=on_message_received_from_uart,
on_message_fail_callback=on_message_fail_from_uart
)
message_builder = MessageBuilder()
try:
ser = serial.Serial(
port=SERIAL_PORT,
baudrate=BAUDRATE,
timeout=READ_TIMEOUT,
write_timeout=WRITE_TIMEOUT
)
print(f"Serielle Schnittstelle {
SERIAL_PORT} mit Baudrate {BAUDRATE} geöffnet.")
try:
# Baue die Nachricht
message_to_send = message_builder.build_message(
0x3,
b'',
255
)
print(f"\n[MAIN] Gebaute Nachricht zum Senden: {
message_to_send.hex().upper()}")
bytes_written = ser.write(message_to_send)
print(f"[MAIN] {bytes_written} Bytes gesendet.")
except (PayloadTooLargeError, BufferOverflowError) as e:
print(f"[MAIN] Fehler beim Bauen der Nachricht: {e}")
return # Beende die Funktion, wenn die Nachricht nicht gebaut werden kann
except Exception as e:
print(
f"[MAIN] Ein unerwarteter Fehler beim Bauen der Nachricht ist aufgetreten: {e}")
return
time.sleep(0.1)
received_data = ser.read_all()
if received_data:
print(f"Empfangene Daten ({len(received_data)} Bytes): {
received_data.hex().upper()}")
for byte_val in received_data:
parser.parse_byte(byte_val)
else:
print("Keine Daten empfangen.")
except serial.SerialException as e:
print(f"Fehler beim Zugriff auf die serielle Schnittstelle: {e}")
print(f"Stelle sicher, dass '{
SERIAL_PORT}' der korrekte Port ist und nicht von einer anderen Anwendung verwendet wird.")
except Exception as e:
print(f"Ein unerwarteter Fehler ist aufgetreten: {e}")
finally:
if ser and ser.is_open:
ser.close()
print("Serielle Schnittstelle geschlossen.")
# Führe den Test aus
if __name__ == "__main__":
run_uart_test()
-115
View File
@@ -1,115 +0,0 @@
import enum
START_BYTE = 0xAA
ESCAPE_BYTE = 0xBB
END_BYTE = 0xCC
class MessageBuilderError(Exception):
"""Basisklasse für Fehler des Message Builders."""
pass
class PayloadTooLargeError(MessageBuilderError):
"""Ausnahme, wenn der Payload zu groß für den Puffer ist."""
def __init__(self, required_size, buffer_size):
super().__init__(f"Payload ({
required_size} bytes) ist größer als der verfügbare Puffer ({buffer_size} bytes).")
self.required_size = required_size
self.buffer_size = buffer_size
class BufferOverflowError(MessageBuilderError):
"""Ausnahme, wenn der Puffer während des Bauens überläuft."""
def __init__(self, current_size, max_size, byte_to_add=None):
msg = f"Pufferüberlauf: Aktuelle Größe {
current_size}, Max. Größe {max_size}."
if byte_to_add is not None:
msg += f" Versuch, Byte 0x{byte_to_add:02X} hinzuzufügen."
super().__init__(msg)
self.current_size = current_size
self.max_size = max_size
self.byte_to_add = byte_to_add
class MessageBuilder:
"""
Klasse zum Aufbau von UART-Nachrichten gemäß dem definierten Protokoll,
inklusive Stuffing und Checksummenberechnung.
"""
def __init__(self):
pass
def _needs_stuffing_byte(self, byte: int) -> bool:
"""
Prüft, ob ein Byte ein Stuffing-Byte benötigt (d.h. ob es ein Steuerbyte ist).
"""
return (byte == START_BYTE or byte == ESCAPE_BYTE or byte == END_BYTE)
def _add_byte_with_length_check(self, byte: int, buffer: bytearray, max_length: int):
"""
Fügt ein Byte zum Puffer hinzu und prüft auf Pufferüberlauf.
Löst BufferOverflowError aus, wenn der Puffer voll ist.
"""
if len(buffer) >= max_length:
raise BufferOverflowError(len(buffer), max_length, byte)
buffer.append(byte)
def build_message(self, msgid: int, payload: bytes, msg_buffer_size: int) -> bytes:
"""
Baut eine vollständige UART-Nachricht.
Args:
msgid (int): Die Message ID (0-255).
payload (bytes): Die Nutzdaten der Nachricht als Byte-Objekt.
msg_buffer_size (int): Die maximale Größe des Ausgabepuffers.
Dies ist die maximale Länge der *fertigen* Nachricht.
Returns:
bytes: Die fertig aufgebaute Nachricht als Byte-Objekt.
Raises:
PayloadTooLargeError: Wenn der Payload (mit Overhead) den Puffer überschreiten würde.
BufferOverflowError: Wenn während des Bauens ein Pufferüberlauf auftritt.
"""
if len(payload) + 4 > msg_buffer_size:
raise PayloadTooLargeError(len(payload) + 4, msg_buffer_size)
checksum = 0
msg_buffer = bytearray()
# 1. StartByte hinzufügen
self._add_byte_with_length_check(
START_BYTE, msg_buffer, msg_buffer_size)
# 2. Message ID hinzufügen (mit Stuffing)
if self._needs_stuffing_byte(msgid):
self._add_byte_with_length_check(
ESCAPE_BYTE, msg_buffer, msg_buffer_size)
self._add_byte_with_length_check(msgid, msg_buffer, msg_buffer_size)
checksum ^= msgid
# 3. Payload-Bytes hinzufügen (mit Stuffing)
for byte_val in payload:
if self._needs_stuffing_byte(byte_val):
self._add_byte_with_length_check(
ESCAPE_BYTE, msg_buffer, msg_buffer_size)
self._add_byte_with_length_check(
byte_val, msg_buffer, msg_buffer_size)
checksum ^= byte_val
# 4. Checksumme hinzufügen (mit Stuffing)
if self._needs_stuffing_byte(checksum):
self._add_byte_with_length_check(
ESCAPE_BYTE, msg_buffer, msg_buffer_size)
self._add_byte_with_length_check(checksum, msg_buffer, msg_buffer_size)
# 5. EndByte hinzufügen
self._add_byte_with_length_check(END_BYTE, msg_buffer, msg_buffer_size)
# Konvertiere bytearray zu unveränderlichem bytes-Objekt
return bytes(msg_buffer)
-170
View File
@@ -1,170 +0,0 @@
import enum
# --- Konstanten für das UART-Protokoll ---
# Diese Werte müssen mit denen auf deinem Embedded-System übereinstimmen
START_BYTE = 0xAA
END_BYTE = 0xCC
ESCAPE_BYTE = 0x7D # Beispielwert, bitte an dein Protokoll anpassen
MAX_PAYLOAD_LENGTH = 255 # Maximale Länge des Nachrichten-Payloads (ohne Message ID und Checksumme)
# MAX_TOTAL_CONTENT_LENGTH in C beinhaltet Message ID, Payload und Checksumme.
# Hier definieren wir MAX_PAYLOAD_LENGTH, da der Parser den Payload sammelt.
# Die Gesamtgröße des empfangenen Puffers (message + checksum) darf MAX_PAYLOAD_LENGTH + 1 nicht überschreiten,
# da die Checksumme als letztes Byte des Payloads behandelt wird.
# --- Enumerationen für Parser-Zustände und Fehler ---
class ParserState(enum.Enum):
WAITING_FOR_START_BYTE = 0
GET_MESSAGE_TYPE = 1
ESCAPED_MESSAGE_TYPE = 2
IN_PAYLOAD = 3
ESCAPE_PAYLOAD_BYTE = 4
class ParserError(enum.Enum):
NO_ERROR = 0
UNEXPECTED_COMMAND_BYTE = 1
WRONG_CHECKSUM = 2
MESSAGE_TOO_LONG = 3
class UartMessageParser:
"""
Ein State-Machine-Parser für UART-Nachrichten basierend auf der bereitgestellten C-Logik.
Nachrichtenformat (angenommen):
[START_BYTE] [MESSAGE_ID] [PAYLOAD_BYTES...] [CHECKSUM_BYTE] [END_BYTE]
Escape-Sequenzen:
Wenn START_BYTE, END_BYTE oder ESCAPE_BYTE im MESSAGE_ID oder PAYLOAD vorkommen,
werden sie durch ESCAPE_BYTE gefolgt vom ursprünglichen Byte (nicht XORed) ersetzt.
Die Checksumme wird über die unescaped Bytes berechnet.
"""
def __init__(self, on_message_received_callback=None, on_message_fail_callback=None):
"""
Initialisiert den UART-Nachrichten-Parser.
Args:
on_message_received_callback (callable, optional): Eine Funktion, die aufgerufen wird,
wenn eine gültige Nachricht empfangen wurde.
Signatur: on_message_received(message_id: int, payload: bytes, payload_length: int)
on_message_fail_callback (callable, optional): Eine Funktion, die aufgerufen wird,
wenn ein Nachrichtenfehler auftritt.
Signatur: on_message_fail(message_id: int, current_message_buffer: bytes,
current_index: int, error_type: ParserError)
"""
self.state = ParserState.WAITING_FOR_START_BYTE
self.index = 0
self.checksum = 0
self.message_id = 0
self.message_buffer = bytearray(MAX_PAYLOAD_LENGTH + 1) # +1 für Checksummen-Byte
self.error = ParserError.NO_ERROR
# Callbacks für die Anwendung. Standardmäßig None oder einfache Print-Funktionen.
self.on_message_received = on_message_received_callback if on_message_received_callback else self._default_on_message_received
self.on_message_fail = on_message_fail_callback if on_message_fail_callback else self._default_on_message_fail
def _default_on_message_received(self, message_id, payload, payload_length):
"""Standard-Callback für empfangene Nachrichten, falls keiner angegeben ist."""
print(f"Parser: Nachricht empfangen! ID: 0x{message_id:02X}, "
f"Payload ({payload_length} Bytes): {payload[:payload_length].hex().upper()}")
def _default_on_message_fail(self, message_id, current_message_buffer, current_index, error_type):
"""Standard-Callback für Nachrichtenfehler, falls keiner angegeben ist."""
print(f"Parser: Fehler bei Nachricht! ID: 0x{message_id:02X}, "
f"Fehler: {error_type.name}, "
f"Bisheriger Puffer ({current_index} Bytes): {current_message_buffer[:current_index].hex().upper()}")
def parse_byte(self, pbyte: int):
"""
Verarbeitet ein einzelnes empfangenes Byte.
Args:
pbyte (int): Das empfangene Byte (0-255).
"""
# Sicherstellen, dass pbyte ein Integer im Bereich 0-255 ist
if not isinstance(pbyte, int) or not (0 <= pbyte <= 255):
print(f"Parser: Ungültiges Byte empfangen: {pbyte}. Muss ein Integer von 0-255 sein.")
return
current_state = self.state # Für bessere Lesbarkeit
if current_state == ParserState.WAITING_FOR_START_BYTE:
if pbyte == START_BYTE:
self.index = 0
self.checksum = 0
self.message_id = 0 # Reset message_id
self.error = ParserError.NO_ERROR # Reset error
self.state = ParserState.GET_MESSAGE_TYPE
# Andernfalls ignorieren wir Bytes, bis ein Start-Byte gefunden wird
elif current_state == ParserState.ESCAPED_MESSAGE_TYPE:
self.message_id = pbyte
self.checksum ^= pbyte
self.state = ParserState.IN_PAYLOAD
elif current_state == ParserState.GET_MESSAGE_TYPE:
if pbyte == ESCAPE_BYTE:
self.state = ParserState.ESCAPED_MESSAGE_TYPE
return # Dieses Byte wurde als Escape-Sequenz verarbeitet, nicht zum Payload hinzufügen
if pbyte == START_BYTE or pbyte == END_BYTE:
self.state = ParserState.WAITING_FOR_START_BYTE
self.error = ParserError.UNEXPECTED_COMMAND_BYTE
self.on_message_fail(self.message_id, self.message_buffer, self.index, self.error)
return
self.message_id = pbyte
self.checksum ^= pbyte
self.state = ParserState.IN_PAYLOAD
elif current_state == ParserState.ESCAPE_PAYLOAD_BYTE:
# Das escapte Byte ist Teil des Payloads
if self.index < MAX_PAYLOAD_LENGTH + 1: # +1 für Checksummen-Byte
self.message_buffer[self.index] = pbyte
self.index += 1
self.checksum ^= pbyte
self.state = ParserState.IN_PAYLOAD
else:
self.state = ParserState.WAITING_FOR_START_BYTE
self.error = ParserError.MESSAGE_TOO_LONG
self.on_message_fail(self.message_id, self.message_buffer, self.index, self.error)
return
elif current_state == ParserState.IN_PAYLOAD:
if pbyte == ESCAPE_BYTE:
self.state = ParserState.ESCAPE_PAYLOAD_BYTE
return # Dieses Byte wurde als Escape-Sequenz verarbeitet
if pbyte == START_BYTE:
self.state = ParserState.WAITING_FOR_START_BYTE
self.error = ParserError.UNEXPECTED_COMMAND_BYTE
self.on_message_fail(self.message_id, self.message_buffer, self.index, self.error)
return
if pbyte == END_BYTE:
if self.checksum != 0x00:
# Checksummenfehler: Die Checksumme wurde bis zum End-Byte XORed.
# Wenn die empfangene Checksumme korrekt war, sollte das Ergebnis 0 sein.
self.state = ParserState.WAITING_FOR_START_BYTE
self.error = ParserError.WRONG_CHECKSUM
self.on_message_fail(self.message_id, self.message_buffer, self.index, self.error)
return
# Erfolgreich empfangen! Die Checksumme ist das letzte Byte im Puffer.
# Die Länge des Payloads ist index - 1 (da das letzte Byte die Checksumme war).
payload_length = self.index - 1
if payload_length < 0: # Falls nur Message ID und Checksumme, aber kein Payload
payload_length = 0
self.on_message_received(self.message_id, self.message_buffer, payload_length)
self.state = ParserState.WAITING_FOR_START_BYTE
return # EndByte wurde verarbeitet, nicht zum Payload hinzufügen
# Normales Payload-Byte
if self.index < MAX_PAYLOAD_LENGTH + 1: # +1 für Checksummen-Byte
self.message_buffer[self.index] = pbyte
self.index += 1
self.checksum ^= pbyte
else:
# Nachricht zu lang
self.state = ParserState.WAITING_FOR_START_BYTE
self.error = ParserError.MESSAGE_TOO_LONG
self.on_message_fail(self.message_id, self.message_buffer, self.index, self.error)
return
-192
View File
@@ -1,192 +0,0 @@
import dataclasses
import struct
from typing import Optional, Union, List
@dataclasses.dataclass
class StatusMessage:
"""
Repräsentiert eine Status-Nachricht (z.B. Message ID 0x01).
Payload-Format: [status_code: uint8], [battery_level: uint8], [uptime_seconds: uint16]
"""
status_code: int
battery_level: int # 0-100%
uptime_seconds: int
@dataclasses.dataclass
class SensorDataMessage:
"""
Repräsentiert eine Sensor-Daten-Nachricht (z.B. Message ID 0x02).
Payload-Format: [temperature_celsius: int16], [humidity_percent: uint16]
"""
temperature_celsius: int # signed short
humidity_percent: int # unsigned short
@dataclasses.dataclass
class ClientEntry:
"""
Repräsentiert die Informationen für einen einzelnen Client innerhalb der ClientInfoMessage.
Payload-Format:
[client_id: uint8]
[is_available: uint8] (0=false, >0=true)
[is_slot_used: uint8] (0=false, >0=true)
[mac_address: bytes (6)]
[unoccupied_value_1: uint32]
[unoccupied_value_2: uint32]
Gesamt: 1 + 1 + 1 + 6 + 4 + 4 = 17 Bytes pro Eintrag.
"""
client_id: int
is_available: bool
is_slot_used: bool
mac_address: bytes # 6 Bytes MAC-Adresse
last_ping: int # 4 Bytes, unbelegt
last_successfull_ping: int # 4 Bytes, unbelegt
@dataclasses.dataclass
class ClientInfoMessage:
"""
Repräsentiert eine Nachricht mit Client-Informationen (Message ID 0x03).
Payload-Format:
[num_clients: uint8]
[client_entry_1: ClientEntry]
[client_entry_2: ClientEntry]
...
"""
num_clients: int
clients: List[ClientEntry]
@dataclasses.dataclass
class UnknownMessage:
"""
Repräsentiert eine Nachricht mit unbekannter ID oder fehlerhaftem Payload.
"""
message_id: int
raw_payload: bytes
error_message: str
# --- Payload Parser Klasse ---
class PayloadParser:
"""
Interpretiert den Payload einer UART-Nachricht basierend auf ihrer Message ID
und wandelt ihn in ein strukturiertes Python-Objekt (dataclass) um.
"""
def __init__(self):
# Ein Dictionary, das Message IDs auf ihre entsprechenden Parsing-Funktionen abbildet.
self._parser_map = {
0x01: self._parse_status_message,
0x02: self._parse_sensor_data_message,
# Aktualisiert für die neue 0x03 Struktur
0x03: self._parse_client_info_message,
0x04: self._parse_client_info_message,
# Füge hier weitere Message IDs und ihre Parsing-Funktionen hinzu
}
def _parse_status_message(self, payload: bytes) -> Union[StatusMessage, UnknownMessage]:
"""Parsen des Payloads für Message ID 0x01 (StatusMessage)."""
# Erwartetes Format: 1 Byte Status, 1 Byte Battery, 2 Bytes Uptime (Little-Endian)
if len(payload) != 4:
return UnknownMessage(0x01, payload, f"Falsche Payload-Länge für StatusMessage: Erwartet 4, Got {len(payload)}")
try:
# '<BBH' bedeutet: Little-Endian, Byte (unsigned char), Byte (unsigned char), Half-word (unsigned short)
status_code, battery_level, uptime_seconds = struct.unpack(
'<BBH', payload)
return StatusMessage(status_code, battery_level, uptime_seconds)
except struct.error as e:
return UnknownMessage(0x01, payload, f"Fehler beim Entpacken der StatusMessage: {e}")
def _parse_sensor_data_message(self, payload: bytes) -> Union[SensorDataMessage, UnknownMessage]:
"""Parsen des Payloads für Message ID 0x02 (SensorDataMessage)."""
# Erwartetes Format: 2 Bytes Temperatur (signed short), 2 Bytes Feuchtigkeit (unsigned short) (Little-Endian)
if len(payload) != 4:
return UnknownMessage(0x02, payload, f"Falsche Payload-Länge für SensorDataMessage: Erwartet 4, Got {len(payload)}")
try:
# '<hH' bedeutet: Little-Endian, short (signed), unsigned short
temperature_celsius, humidity_percent = struct.unpack(
'<hH', payload)
return SensorDataMessage(temperature_celsius, humidity_percent)
except struct.error as e:
return UnknownMessage(0x02, payload, f"Fehler beim Entpacken der SensorDataMessage: {e}")
def _parse_client_info_message(self, payload: bytes) -> Union[ClientInfoMessage, UnknownMessage]:
"""Parsen des Payloads für Message ID 0x03 (ClientInfoMessage)."""
if not payload:
# Wenn der Payload leer ist, aber num_clients erwartet wird, ist das ein Fehler
return UnknownMessage(0x03, payload, "Payload für ClientInfoMessage ist leer, aber num_clients erwartet.")
try:
# Das erste Byte ist die Anzahl der Clients
num_clients = payload[0]
# Die restlichen Bytes sind die Client-Einträge
client_data_bytes = payload[1:]
# 1 (ID) + 1 (Avail) + 1 (Used) + 6 (MAC) + 4 (Val1) + 4 (Val2)
EXPECTED_CLIENT_ENTRY_SIZE = 17
if len(client_data_bytes) != num_clients * EXPECTED_CLIENT_ENTRY_SIZE:
return UnknownMessage(0x03, payload,
f"Falsche Payload-Länge für Client-Einträge: Erwartet {
num_clients * EXPECTED_CLIENT_ENTRY_SIZE}, "
f"Got {len(client_data_bytes)} nach num_clients.")
clients_list: List[ClientEntry] = []
# Formatstring für einen Client-Eintrag:
# < : Little-Endian
# B : uint8 (client_id, is_available, is_slot_used)
# 6s: 6 Bytes (mac_address)
# I : uint32 (unoccupied_value_1, unoccupied_value_2)
CLIENT_ENTRY_FORMAT = '<BBB6sII'
for i in range(num_clients):
start_index = i * EXPECTED_CLIENT_ENTRY_SIZE
end_index = start_index + EXPECTED_CLIENT_ENTRY_SIZE
entry_bytes = client_data_bytes[start_index:end_index]
# Entpacke die Daten für einen Client-Eintrag
client_id, is_available_byte, is_slot_used_byte, mac_address, val1, val2 = \
struct.unpack(CLIENT_ENTRY_FORMAT, entry_bytes)
# Konvertiere 0/1 Bytes zu boolschen Werten
is_available = bool(is_available_byte)
is_slot_used = bool(is_slot_used_byte)
clients_list.append(ClientEntry(
client_id=client_id,
is_available=is_available,
is_slot_used=is_slot_used,
mac_address=mac_address,
last_ping=val1,
last_successfull_ping=val2
))
return ClientInfoMessage(num_clients=num_clients, clients=clients_list)
except struct.error as e:
return UnknownMessage(0x03, payload, f"Fehler beim Entpacken der ClientInfoMessage-Einträge: {e}")
except Exception as e:
return UnknownMessage(0x03, payload, f"Unerwarteter Fehler beim Parsen der ClientInfoMessage: {e}")
def parse_payload(self, message_id: int, payload: bytes) -> Union[StatusMessage, SensorDataMessage, ClientInfoMessage, UnknownMessage]:
"""
Interpretiert den gegebenen Payload basierend auf der Message ID.
Args:
message_id (int): Die ID der Nachricht.
payload (bytes): Die rohen Nutzdaten der Nachricht.
Returns:
Union[StatusMessage, SensorDataMessage, ClientInfoMessage, UnknownMessage]:
Ein dataclass-Objekt, das die dekodierten Daten repräsentiert,
oder ein UnknownMessage-Objekt bei unbekannter ID oder Parsing-Fehler.
"""
parser_func = self._parser_map.get(message_id)
if parser_func:
return parser_func(payload)
else:
return UnknownMessage(message_id, payload, "Unbekannte Message ID.")