Compare commits

..

No commits in common. "0767ddac381096de7c012d44713655678a43e9b8" and "de747ef463efe14209006f05a9f0a5dc334ce2db" have entirely different histories.

20 changed files with 535 additions and 1126 deletions

View File

@ -1,11 +0,0 @@
package api
const (
TopicFrontendCmd = "front:cmd"
)
type FrontendCmd struct {
Action string `json:"action"`
ID byte `json:"id"`
Data []byte `json:"data"`
}

View File

@ -1,39 +0,0 @@
package api
// Topics
const (
TopicUARTRx = "uart:rx"
TopicUARTTx = "uart:tx"
TopicUARTError = "uart:error"
)
type Frame struct {
Time uint64
ID byte
Data []byte
}
const (
CmdEcho byte = 0x01
CmdVersion byte = 0x02
CmdClientInfo byte = 0x03
CmdClientInput byte = 0x04
)
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 {
}

View File

@ -1,8 +0,0 @@
package main
type Config struct {
Port int
Host string
UartPort string
Baudrate int
}

View File

@ -1,64 +0,0 @@
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
}
}
}

View File

@ -1,102 +0,0 @@
package frontend
import (
"context"
"embed"
"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() {
// Statische Dateien aus dem Embed-FS
// "www" Präfix entfernen, damit index.html unter / verfügbar ist
root, _ := fs.Sub(staticFiles, "www")
fsrv.mux.Handle("/", http.FileServer(http.FS(root)))
// WebSocket Endpunkt
fsrv.mux.HandleFunc("/ws", fsrv.handleWS)
}
func (fsrv *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()
// Kanäle für die Hardware-Events abonnieren
rxChan := fsrv.bus.Subscribe(api.TopicUARTRx)
txChan := fsrv.bus.Subscribe(api.TopicUARTTx)
// 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 func() {
for {
select {
case <-ctx.Done():
return
case f := <-rxChan:
if err := conn.WriteJSON(map[string]any{"type": "rx", "frame": f}); err != nil {
return
}
case f := <-txChan:
if err := conn.WriteJSON(map[string]any{"type": "tx", "frame": f}); err != nil {
return
}
}
}
}()
// READER: Commands from Browser
for {
var cmd api.FrontendCmd
if err := conn.ReadJSON(&cmd); err != nil {
log.Printf("WS Read Error: %v", err)
break
}
fsrv.bus.Publish(api.TopicFrontendCmd, cmd)
log.Printf("Browser Action: %s auf ID 0x%02X", cmd.Action, cmd.ID)
}
}
func (fsrv *FServer) Start(addr string) error {
server := &http.Server{
Addr: addr,
Handler: fsrv.mux,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
}
log.Printf("Frontend Server gestartet auf %s", addr)
return server.ListenAndServe()
}

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

View File

@ -1,32 +0,0 @@
<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>

View File

@ -1,337 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<link href="www/bootstrap.min.css" rel="stylesheet">
<script src="www/bootstrap.bundle.min.js"></script>
<script defer src="www/alpinejs.min.js"></script>
<style>
[x-cloak] {
display: none !important;
}
body {
background-color: #f8f9fa;
/* Create 20px x 20px Grid */
background-image:
linear-gradient(90deg, rgba(0, 0, 0, .03) 1px, transparent 1px),
linear-gradient(rgba(0, 0, 0, .03) 1px, transparent 1px);
background-size: 20px 20px;
height: 100vh;
margin: 0;
overflow: hidden;
}
.draggable-card {
width: 450px;
z-index: 1000;
user-select: none;
}
.drag-handle {
cursor: move;
}
.card {
transition: width 0.1s ease, height 0.1s ease, left 0.1s ease, top 0.1s ease;
}
.card[style*="cursor: move"] {
transition: none;
}
</style>
<script>
document.addEventListener('alpine:init', () => {
Alpine.store("ui", {
topZ: 1000,
getNewZ() {return ++this.topZ}
});
Alpine.store("adapters", ["can0", "can1", "vcan0"]);
Alpine.store("selected_adapter", "");
Alpine.store("selected_bitrate", "");
Alpine.store("can_connected", false);
});
function windowBox(id, initialX = 50, initialY = 50) {
// Load saved data or user defaults
const saved = JSON.parse(localStorage.getItem(`win_${id}`)) || {x: initialX, y: initialY, min: false};
return {
id: id,
pos: {x: saved.x, y: saved.y},
lastPos: {x: saved.x, y: saved.y},
dragging: false,
minimized: saved.min,
fullscreen: false,
zIndex: Alpine.store('ui').topZ,
offset: {x: 0, y: 0},
init() {
// Move window in viewport when browser is other size
this.keepInBounds();
},
focus() {
this.zIndex = Alpine.store('ui').getNewZ();
},
startDrag(e) {
if (e.target.closest('button') || this.fullscreen) return;
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;
// Calc new position
let newX = e.clientX - this.offset.x;
let newY = e.clientY - this.offset.y;
// Boundary Check
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() {
this.dragging = false;
this.save();
},
keepInBounds() {
if (this.pos.x > window.innerWidth) this.pos.x = window.innerWidth - 400;
if (this.pos.y > window.innerHeight) this.pos.y = 50;
},
save() {
localStorage.setItem(`win_${this.id}`, JSON.stringify({
x: this.pos.x,
y: this.pos.y,
min: this.minimized
}));
},
reset() {
localStorage.removeItem(`win_${this.id}`);
location.reload();
},
toggleMinimize() {
this.minimized = !this.minimized;
this.save();
},
toggleFullscreen() {
if (!this.fullscreen) {
this.lastPos = {...this.pos}; // Save Position
this.pos = {x: 0, y: 0};
this.fullscreen = true;
} else {
this.pos = {...this.lastPos}; // Back to old Position
this.fullscreen = false;
}
this.focus();
}
}
}
</script>
<script>
let socket = new WebSocket("ws://localhost:8000/echo");
socket.onopen = function (e) {
console.log("[open] Connection established");
console.log("Sending to server");
};
socket.onmessage = function (event) {
console.log(`[message] Data received from server: ${event.data}`);
let mes;
try {
mes = JSON.parse(event.data)
} catch {
mes = null
}
if (mes != null) {
handleCommand(mes)
} else {
console.log(`${event.data} is not valid JSON`)
}
};
socket.onclose = function (event) {
if (event.wasClean) {
alert(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
} else {
// e.g. server process killed or network down
// event.code is usually 1006 in this case
console.log('[close] Connection died');
}
};
socket.onerror = function (error) {
console.log(`[error]`);
};
function handleCommand(command) {
switch (command.cmd) {
case "value":
console.log("CHANGE VALUE");
Alpine.store(command.name, command.value);
break;
}
}
</script>
</head>
<body>
<h1>Alox Debug Tool</h1>
<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>
<div x-data="windowBox('can_config', 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">
<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.can_connected">
Adapter
</button>
<ul class="dropdown-menu" :class="{ 'show': open }" x-show="open"
style="display: block;">
<template x-for="adapter in $store.adapters">
<li>
<button class="dropdown-item" type="button"
x-text="adapter"
@click="$store.selected_adapter = adapter; open = false"></button>
</li>
</template>
</ul>
<input type="text" class="form-control bg-light" readonly
:value="$store.selected_adapter || 'Select Interface...'">
</div>
<label class="form-label small fw-bold text-uppercase text-muted">Bitrate (kbps)</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.can_connected">
Speed
</button>
<ul class="dropdown-menu" :class="{ 'show': open }" x-show="open"
style="display: block;">
<template
x-for="rate in ['10', '20', '50', '100', '125', '250', '500', '800', '1000']">
<li>
<button class="dropdown-item" type="button"
x-text="rate + ' kbps'"
@click="$store.selected_bitrate = rate; open = false"></button>
</li>
</template>
</ul>
<input type="text" class="form-control bg-light" readonly
:value="$store.selected_bitrate ? $store.selected_bitrate + ' kbps' : 'Select Speed...'">
</div>
<div class="d-grid">
<button x-show="!$store.can_connected" class="btn btn-primary btn-lg"
type="button"
:disabled="!$store.selected_adapter || !$store.selected_bitrate"
@click="socket.send(JSON.stringify({cmd: 'connect', adapter: $store.selected_adapter, bitrate: parseInt($store.selected_bitrate)}))">
Connect to CAN
</button>
<button x-show="$store.can_connected" x-cloak class="btn btn-danger btn-lg"
type="button" @click="socket.send(JSON.stringify({cmd: 'disconnect'}))">
Disconnect
</button>
</div>
</div>
</div>
</div>
<div x-data="windowBox('can_log', 500, 50)" @mousemove.window="onDrag" @mouseup.window="stopDrag"
@mousedown="focus" class="card shadow-lg position-absolute draggable-card"
:style="`left: ${pos.x}px; top: ${pos.y}px; z-index: ${zIndex}; width: ${fullscreen ? '100vw' : '500px'};`"
x-cloak>
<div class="card-header bg-primary text-white d-flex justify-content-between align-items-center drag-handle"
@mousedown="startDrag">
<h6 class="mb-0">📜 CAN Log</h6>
<div class="d-flex gap-1">
<button class="btn btn-sm btn-outline-light py-0" @click="toggleMinimize">
<span x-text="minimized ? '+' : ''"></span>
</button>
</div>
</div>
<div x-show="!minimized" class="card-body bg-dark text-success font-monospace small"
style="height: 200px; overflow-y: auto;">
<div>[0.001] ID: 0x123 Data: FF AA 00</div>
<div>[0.005] ID: 0x456 Data: 12 34 56</div>
</div>
</div>
</body>
</html>

View File

@ -3,7 +3,6 @@ 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
)

View File

@ -28,8 +28,6 @@ github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQ
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=

View File

@ -1,85 +1,555 @@
package main
import (
"context"
"encoding/binary"
"flag"
"fmt"
"log"
"math"
"os"
"strconv"
"time"
"alox.tool/api"
"alox.tool/eventbus"
"alox.tool/frontend"
"alox.tool/uart"
"github.com/pterm/pterm"
"go.bug.st/serial"
)
type ParserState int
const (
// 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
)
const (
WAITING_FOR_START_BYTE ParserState = iota
ESCAPED_MESSAGE_ID
GET_MESSAGE_ID
IN_PAYLOD
ESCAPED_PAYLOAD_BYTE
)
const (
START_BYTE = 0xAA
ESCAPE_BYTE = 0xBB
END_BYTE = 0xCC
)
type ParseError int
const (
WRONG_CHECKSUM ParseError = iota
UNEXPECETD_BYTE
)
type MessageReceive struct {
raw_message []byte
parsed_message []byte
checksum byte
error ParseError
state ParserState
write_index int
raw_write_index int
}
type OTASyncManager struct {
OTA_MessageCounter int
OTA_PayloadMessageSequence int
NewOTAMessage chan MessageReceive
TimeoutMessage time.Duration
}
func (ot *OTASyncManager) WaitForNextMessageTimeout() (*MessageReceive, error) {
select {
case msg := <-ot.NewOTAMessage:
return &msg, nil
case <-time.After(ot.TimeoutMessage):
return nil, fmt.Errorf("Message Timeout")
}
}
func initMessageReceive(mr *MessageReceive) {
mr.raw_message = make([]byte, 1024*4)
mr.parsed_message = make([]byte, 1024*4)
mr.checksum = 0
mr.error = 0
mr.write_index = 0
mr.raw_write_index = 0
mr.state = WAITING_FOR_START_BYTE
}
func addByteToRawBuffer(mr *MessageReceive, pbyte byte) {
mr.raw_message[mr.raw_write_index] = pbyte
mr.raw_write_index += 1
}
func addByteToParsedBuffer(mr *MessageReceive, pbyte byte) {
mr.parsed_message[mr.write_index] = pbyte
mr.write_index += 1
mr.checksum ^= pbyte
}
func parse_uart_ota_payload_payload(payloadBuffer []byte, payload_len int) {
//fmt.Printf("RAW BUFFER: % 02X", payloadBuffer[:payload_len])
if payload_len != 4 {
fmt.Printf("Payload should be 4 is %v", payload_len)
return
}
fmt.Printf("Sequence %v, WriteIndex %v", binary.LittleEndian.Uint16(payloadBuffer[0:1]), binary.LittleEndian.Uint16(payloadBuffer[2:3]))
}
func parse_uart_version_payload(payloadBuffer []byte, payload_len int) {
type payload_data struct {
Version uint16
BuildHash [7]uint8
}
tableHeaders := pterm.TableData{
{"Version", "Buildhash"},
}
tableData := tableHeaders
tableData = append(tableData, []string{
fmt.Sprintf("%d", binary.LittleEndian.Uint16(payloadBuffer[1:3])),
fmt.Sprintf("%s", payloadBuffer[3:10]),
})
err := pterm.DefaultTable.WithHasHeader().WithBoxed().WithData(tableData).Render()
if err != nil {
fmt.Printf("Fehler beim Rendern der Tabelle: %s\n", err)
}
}
func parse_uart_client_info_payload(payloadBuffer []byte, payload_len int) {
type payload_data struct {
ClientID uint8
IsAvailable uint8
SlotIsUsed uint8
MACAddr [6]uint8
LastPing uint32
LastSuccessfulPing uint32
Version uint16
}
tableHeaders := pterm.TableData{
{"Client ID", "Verfügbar", "Genutzt", "MAC-Adresse", "Last Ping", "Letzter Erfolg Ping", "Version"},
}
tableData := tableHeaders
currentOffset := 2
const (
ENTRY_LEN = 19
OFFSET_MAC_ADDR = 3
OFFSET_LAST_PING = 9
OFFSET_LAST_SUCCESS_PING = 13
OFFSET_VERSION = 17
)
for i := 0; i < int(payloadBuffer[1]); i++ {
if currentOffset+ENTRY_LEN > payload_len {
fmt.Printf("Fehler: Payload zu kurz für Client-Eintrag %d\n", i)
break
}
entryBytes := payloadBuffer[currentOffset : currentOffset+ENTRY_LEN]
var clientData payload_data
clientData.ClientID = entryBytes[0]
clientData.IsAvailable = entryBytes[1]
clientData.SlotIsUsed = entryBytes[2]
copy(clientData.MACAddr[:], entryBytes[OFFSET_MAC_ADDR:OFFSET_MAC_ADDR+6])
clientData.LastPing = binary.LittleEndian.Uint32(entryBytes[OFFSET_LAST_PING : OFFSET_LAST_PING+4])
clientData.LastSuccessfulPing = binary.LittleEndian.Uint32(entryBytes[OFFSET_LAST_SUCCESS_PING : OFFSET_LAST_SUCCESS_PING+4])
clientData.Version = binary.LittleEndian.Uint16(entryBytes[OFFSET_VERSION : OFFSET_VERSION+2])
// Füge die geparsten Daten als String-Slice zur Tabelle hinzu
tableData = append(tableData, []string{
fmt.Sprintf("%d", clientData.ClientID),
fmt.Sprintf("%d", clientData.IsAvailable),
fmt.Sprintf("%d", clientData.SlotIsUsed),
fmt.Sprintf("%X:%X:%X:%X:%X:%X",
clientData.MACAddr[0], clientData.MACAddr[1], clientData.MACAddr[2],
clientData.MACAddr[3], clientData.MACAddr[4], clientData.MACAddr[5]),
fmt.Sprintf("%d", clientData.LastPing),
fmt.Sprintf("%d", clientData.LastSuccessfulPing),
fmt.Sprintf("%d", clientData.Version),
})
currentOffset += ENTRY_LEN
}
err := pterm.DefaultTable.WithHasHeader().WithBoxed().WithData(tableData).Render()
if err != nil {
fmt.Printf("Fehler beim Rendern der Tabelle: %s\n", err)
}
}
func parse_uart_client_input(payloadBuffer []byte, payload_len int) {
clientCount := payloadBuffer[1]
fmt.Printf("Client Count %d\n", clientCount)
clientInputLen := 13
for i := 0; i < int(clientCount); i++ {
offset := 2 + (i * clientInputLen)
// --- Client ID (uint8) ---
clientID := payloadBuffer[offset]
offset += 1
fmt.Printf("Client: %d\n", clientID)
// --- Lage X (float32) ---
xBits := binary.LittleEndian.Uint32(payloadBuffer[offset : offset+4])
lageX := math.Float32frombits(xBits)
offset += 4
fmt.Printf("\tLAGE_X: %f\n", lageX)
// --- Lage Y (float32) ---
yBits := binary.LittleEndian.Uint32(payloadBuffer[offset : offset+4])
lageY := math.Float32frombits(yBits)
offset += 4
fmt.Printf("\tLAGE_Y: %f\n", lageY)
// --- Bitmask (int32) ---
maskBits := binary.LittleEndian.Uint32(payloadBuffer[offset : offset+4])
bitmask := uint32(maskBits)
offset += 4
fmt.Printf("\tBITMASK: %032b\n", bitmask)
}
}
func message_receive_callback(mr MessageReceive) {
log.Printf("Message Received: % 02X\n", mr.raw_message[:mr.raw_write_index])
switch mr.parsed_message[0] {
case byte(UART_ECHO):
case UART_VERSION:
parse_uart_version_payload(mr.parsed_message, mr.write_index)
case UART_CLIENT_INFO:
parse_uart_client_info_payload(mr.parsed_message, mr.write_index)
case UART_OTA_START:
OTA_UpdateHandler.NewOTAMessage <- mr
case UART_OTA_PAYLOAD:
parse_uart_ota_payload_payload(mr.parsed_message, mr.write_index)
OTA_UpdateHandler.NewOTAMessage <- mr
case UART_OTA_END:
OTA_UpdateHandler.NewOTAMessage <- mr
case UART_OTA_STATUS:
OTA_UpdateHandler.NewOTAMessage <- mr
case UART_CLIENT_INPUT:
parse_uart_client_input(mr.parsed_message, mr.write_index)
}
}
func message_receive_failed_callback(mr MessageReceive) {
log.Printf("Error Message Received: % 02X\n", mr.raw_message[:mr.raw_write_index])
}
func parseByte(mr *MessageReceive, pbyte byte) {
addByteToRawBuffer(mr, pbyte)
switch mr.state {
case WAITING_FOR_START_BYTE:
if pbyte == START_BYTE {
initMessageReceive(mr)
mr.state = GET_MESSAGE_ID
addByteToRawBuffer(mr, pbyte)
}
// ignore every other byte
case GET_MESSAGE_ID:
if pbyte == ESCAPE_BYTE {
mr.state = ESCAPED_MESSAGE_ID
} else {
addByteToParsedBuffer(mr, pbyte)
mr.state = IN_PAYLOD
}
case ESCAPED_MESSAGE_ID:
addByteToParsedBuffer(mr, pbyte)
mr.state = IN_PAYLOD
case IN_PAYLOD:
if pbyte == ESCAPE_BYTE {
mr.state = ESCAPED_PAYLOAD_BYTE
break
}
if pbyte == START_BYTE {
mr.error = UNEXPECETD_BYTE
go message_receive_failed_callback(*mr)
initMessageReceive(mr)
return
}
if pbyte == END_BYTE {
if mr.checksum != 0 { // checksum wrong
mr.error = WRONG_CHECKSUM
go message_receive_failed_callback(*mr)
initMessageReceive(mr)
return
}
go message_receive_callback(*mr)
initMessageReceive(mr)
break
}
// normal case
addByteToParsedBuffer(mr, pbyte)
case ESCAPED_PAYLOAD_BYTE:
addByteToParsedBuffer(mr, pbyte)
mr.state = IN_PAYLOD
default:
panic(fmt.Sprintf("unexpected main.ParserState: %#v", mr.state))
}
}
func buildMessage(payloadBuffer []byte, payload_len int, sendBuffer []byte) int {
var writeIndex int
checksum := byte(0x00)
writeIndex = 0
sendBuffer[writeIndex] = START_BYTE
writeIndex++
for i := range payload_len {
b := payloadBuffer[i]
if b == START_BYTE || b == ESCAPE_BYTE || b == END_BYTE {
sendBuffer[writeIndex] = ESCAPE_BYTE
writeIndex++
}
sendBuffer[writeIndex] = b
writeIndex++
checksum ^= b
}
if checksum == START_BYTE || checksum == ESCAPE_BYTE || checksum == END_BYTE {
sendBuffer[writeIndex] = ESCAPE_BYTE
writeIndex++
}
sendBuffer[writeIndex] = checksum
writeIndex++
sendBuffer[writeIndex] = END_BYTE
writeIndex++
return writeIndex
}
func sendMessage(port serial.Port, sendBuffer []byte) {
n, err := port.Write(sendBuffer)
if err != nil {
log.Printf("Could not Send %v to Serial Port", sendBuffer)
}
if n < len(sendBuffer) {
log.Printf("Did not send all data %v, only send %v", len(sendBuffer), n)
}
fmt.Printf("Send Message % 02X\n", sendBuffer[:n])
}
var (
updatePath string
OTA_UpdateHandler OTASyncManager
)
func main() {
config := Config{
Port: 8000,
Host: "0.0.0.0",
UartPort: "/dev/ttyUSB0",
Baudrate: 115200,
flag.StringVar(&updatePath, "update", "", "Path to Updatefile")
flag.Parse()
OTA_UpdateHandler = OTASyncManager{
OTA_MessageCounter: 0,
OTA_PayloadMessageSequence: 0,
NewOTAMessage: make(chan MessageReceive),
TimeoutMessage: time.Millisecond * 30000,
}
StartApp(config)
}
func StartApp(config Config) {
bus := eventbus.New()
com, err := uart.Connect(bus, config.UartPort, config.Baudrate)
mode := &serial.Mode{
//BaudRate: 115200,
BaudRate: 921600,
}
port, err := serial.Open("/dev/ttyUSB0", mode)
if err != nil {
log.Printf("Could not Connect with Uart Device %v", err)
log.Fatal(err)
}
defer com.Close()
ctx, cancle := context.WithCancel(context.Background())
defer cancle()
go func() {
buff := make([]byte, 1024)
mr := MessageReceive{}
initMessageReceive(&mr)
for {
select {
case msg := <-bus.Subscribe(api.TopicUARTTx):
log.Printf("MSG[TX]: % X", msg)
case msg := <-bus.Subscribe(api.TopicUARTRx):
log.Printf("MSG[RX]: % X", msg)
val, ok := msg.(api.Frame)
if !ok {
log.Printf("val is not type api.Frame its %T", val)
continue
case <-ctx.Done():
return
default:
n, err := port.Read(buff)
if err != nil {
log.Print(err)
break
}
log.Printf("[%d] Frame: %X, % X", val.Time, val.ID, val.Data)
switch val.ID {
case api.CmdEcho:
case api.CmdVersion:
v, err := uart.ParseFrameVersion(val)
if err != nil {
log.Printf("Could not Parse Version %v", err)
continue
}
log.Printf("Version Info %d %X", v.Version, v.Buildhash)
case api.CmdClientInfo:
v, err := uart.ParseFrameClientInfo(val)
if err != nil {
log.Printf("Could not Parse Client Info %v", err)
continue
}
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)
}
if n == 0 {
fmt.Println("\nEOF")
break
}
for _, b := range buff[:n] {
parseByte(&mr, b)
}
//fmt.Printf("Empfangen: % 02X\n", string(buff[:n]))
break
}
}
}()
time.Sleep(time.Millisecond * 5)
if updatePath != "" {
// start update
update, err := os.ReadFile(updatePath)
if err != nil {
log.Printf("Could not read Update file %v", err)
return
}
log.Printf("Update Buffer read, update size %v", len(update))
log.Printf("Gonna break it down in 200 Bytes packages will send %v packages", len(update)/200)
com.Send(api.CmdEcho, make([]byte, 0))
com.Send(api.CmdVersion, make([]byte, 0))
com.Send(api.CmdClientInfo, make([]byte, 0))
// start
payload_buffer := make([]byte, 1024)
send_buffer := make([]byte, 1024)
payload_buffer[0] = UART_OTA_START
n := buildMessage(payload_buffer, 1, send_buffer)
sendMessage(port, send_buffer[:n])
msg, err := OTA_UpdateHandler.WaitForNextMessageTimeout()
if err != nil {
log.Printf("Error Message not acked %v", err)
} else {
if msg.parsed_message[2] != 0x00 {
log.Printf("Update Start failed %v", msg.parsed_message[2])
return
} else {
log.Printf("Update Start confirmed Updating Partition %v", msg.parsed_message[1])
}
}
url := fmt.Sprintf("%s:%d", config.Host, config.Port)
fserver := frontend.New(bus)
fserver.Start(url)
update_write_index := 0
// write update parts
for update_write_index < len(update) {
payload_buffer = make([]byte, 1024)
send_buffer = make([]byte, 1024)
payload_buffer[0] = UART_OTA_PAYLOAD
write_len := min(200, len(update)-update_write_index)
//end_payload_len := min(update_write_index+200, len(update))
copy(payload_buffer[1:write_len+1], update[update_write_index:update_write_index+write_len])
n = buildMessage(payload_buffer, write_len+1, send_buffer)
sendMessage(port, send_buffer[:n])
msg, err := OTA_UpdateHandler.WaitForNextMessageTimeout()
if err != nil {
log.Printf("Error Message not acked %v", err)
return
} else {
seqCounter := binary.LittleEndian.Uint16(msg.parsed_message[1:3])
buff_write_index := binary.LittleEndian.Uint16(msg.parsed_message[3:5])
log.Printf("Sequenzce Counter: %d, Update buffer Write Index: %d", seqCounter, buff_write_index)
}
update_write_index += 200
}
log.Printf("Update übertragen beende hier!!!")
// end
payload_buffer = make([]byte, 1024)
send_buffer = make([]byte, 1024)
payload_buffer[0] = UART_OTA_END
n = buildMessage(payload_buffer, 1, send_buffer)
sendMessage(port, send_buffer[:n])
_, err = OTA_UpdateHandler.WaitForNextMessageTimeout()
if err != nil {
log.Printf("Error Message not acked %v", err)
return
} else {
log.Printf("Message Waiting hat funktionioert")
}
return
}
for {
var input string
var input2 string
_, err := fmt.Scanln(&input, &input2)
if err != nil {
log.Fatalf("Could not read from stdin %v", err)
return
}
fmt.Printf("Input %v", input)
switch input {
case "q":
return
case "1":
payload_buffer := make([]byte, 1024)
send_buffer := make([]byte, 1024)
payload_buffer[0] = UART_ECHO
n := buildMessage(payload_buffer, 1, send_buffer)
sendMessage(port, send_buffer[:n])
case "2":
payload_buffer := make([]byte, 1024)
send_buffer := make([]byte, 1024)
payload_buffer[0] = UART_VERSION
n := buildMessage(payload_buffer, 1, send_buffer)
sendMessage(port, send_buffer[:n])
case "3":
payload_buffer := make([]byte, 1024)
send_buffer := make([]byte, 1024)
payload_buffer[0] = UART_CLIENT_INFO
n := buildMessage(payload_buffer, 1, send_buffer)
sendMessage(port, send_buffer[:n])
case "4": // start update
payload_buffer := make([]byte, 1024)
send_buffer := make([]byte, 1024)
payload_buffer[0] = UART_OTA_START
n := buildMessage(payload_buffer, 1, send_buffer)
sendMessage(port, send_buffer[:n])
case "5": // send payload
payload_buffer := make([]byte, 1024)
send_buffer := make([]byte, 1024)
payload_buffer[0] = UART_OTA_PAYLOAD
for i := range 200 {
payload_buffer[i+1] = byte(i)
}
n := buildMessage(payload_buffer, 201, send_buffer)
sendMessage(port, send_buffer[:n])
case "6": // end update
case "7": // Start OTA for ESP-NOW clients
payload_buffer := make([]byte, 1024)
send_buffer := make([]byte, 1024)
payload_buffer[0] = UART_OTA_START_ESPNOW
n := buildMessage(payload_buffer, 1, send_buffer)
sendMessage(port, send_buffer[:n])
case "8": // Get Fake Client Input
payload_buffer := make([]byte, 1024)
send_buffer := make([]byte, 1024)
payload_buffer[0] = UART_CLIENT_INPUT
seed, err := strconv.Atoi(input2)
if err != nil {
log.Printf("Could not parse %v to a number", input2)
return
}
payload_buffer[1] = byte(seed)
n := buildMessage(payload_buffer, 2, send_buffer)
sendMessage(port, send_buffer[:n])
default:
fmt.Printf("Not a valid input")
}
}
}

View File

@ -1,48 +0,0 @@
package testrunner
import (
"context"
"fmt"
"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) 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
}
}
}

View File

@ -1,21 +0,0 @@
package testrunner
import (
"fmt"
"time"
"alox.tool/api"
)
func (tr *TestRunner) RunVersionTest() error {
fmt.Println("Starte Version Test...")
// Sende VersionRequest (0x02), erwarte VersionResponse (0x02)
frame, err := tr.Expect(api.CmdVersion, nil, api.CmdVersion, 1*time.Second)
if err != nil {
return err
}
fmt.Printf("Test bestanden! Hardware Version ist: %s\n", string(frame.Data))
return nil
}

View File

@ -1,101 +0,0 @@
package uart
import (
"context"
"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 Connect(bus eventbus.EventBus, portName string, baudrate int) (*Com, error) {
mode := &serial.Mode{BaudRate: baudrate}
port, err := serial.Open(portName, mode)
if err != nil {
return nil, err
}
ctx, cancel := context.WithCancel(context.Background())
drv := New(bus)
go func() {
buff := make([]byte, 1024)
for {
select {
case <-ctx.Done():
return
default:
n, err := port.Read(buff)
if err != nil {
log.Print("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)
}
}
}
}
}()
return &Com{
bus: bus,
port: port,
cancel: cancel,
}, 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: % 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
}

View File

@ -1,109 +0,0 @@
package uart
import (
"encoding/binary"
"fmt"
"log"
"math"
"alox.tool/api"
)
func ParseFrameVersion(frame api.Frame) (api.PayloadVersion, error) {
if len(frame.Data) != 10 {
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) != 19 {
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 * 19)
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 * 19)
end := start + 19
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 parse_uart_client_input(payloadBuffer []byte, payload_len int) {
clientCount := payloadBuffer[1]
fmt.Printf("Client Count %d\n", clientCount)
clientInputLen := 13
for i := 0; i < int(clientCount); i++ {
offset := 2 + (i * clientInputLen)
// --- Client ID (uint8) ---
clientID := payloadBuffer[offset]
offset += 1
fmt.Printf("Client: %d\n", clientID)
// --- Lage X (float32) ---
xBits := binary.LittleEndian.Uint32(payloadBuffer[offset : offset+4])
lageX := math.Float32frombits(xBits)
offset += 4
fmt.Printf("\tLAGE_X: %f\n", lageX)
// --- Lage Y (float32) ---
yBits := binary.LittleEndian.Uint32(payloadBuffer[offset : offset+4])
lageY := math.Float32frombits(yBits)
offset += 4
fmt.Printf("\tLAGE_Y: %f\n", lageY)
// --- Bitmask (int32) ---
maskBits := binary.LittleEndian.Uint32(payloadBuffer[offset : offset+4])
bitmask := uint32(maskBits)
offset += 4
fmt.Printf("\tBITMASK: %032b\n", bitmask)
}
}

View File

@ -1,128 +0,0 @@
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
}
}

View File

@ -1,6 +1,6 @@
#include "i2c.h"
#include "bma4.h"
#include "bma456h.h"
#include "bma456w.h"
#include "bma4_defs.h"
#include "driver/gpio.h"
#include "driver/i2c_master.h"
@ -135,34 +135,11 @@ void read_sensor_task(void *params) {
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);
ret = bma456w_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);
@ -190,7 +167,7 @@ void init_bma456() {
int8_t ret;
bma456_struct.chip_id = 0;
ret = bma456h_init(&bma456_struct);
ret = bma456w_init(&bma456_struct);
bma4_error_codes_print_result("I2C Init", ret);
ESP_LOGI("I2C", "Chip Init ausgelesene CHIP ID %d", bma456_struct.chip_id);
@ -207,35 +184,20 @@ void init_bma456() {
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);
ret = bma456w_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);
ret = bma456w_feature_enable(BMA456W_STEP_CNTR, 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);
ret = bma456w_step_counter_set_watermark(1, &bma456_struct);
bma4_error_codes_print_result("bma456w_step_counter_set_watermark status",
ret);
@ -245,9 +207,8 @@ void init_bma456() {
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,
ret = bma456w_map_interrupt(int_line, BMA456W_STEP_CNTR_INT, BMA4_ENABLE,
&bma456_struct);
bma4_error_codes_print_result("bma456w_map_interrupt status", ret);
pin_config.edge_ctrl = BMA4_EDGE_TRIGGER;