esp_alox/goTool/main.go

556 lines
14 KiB
Go

package main
import (
"context"
"encoding/binary"
"flag"
"fmt"
"log"
"math"
"os"
"strconv"
"time"
"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() {
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,
}
mode := &serial.Mode{
//BaudRate: 115200,
BaudRate: 921600,
}
port, err := serial.Open("/dev/ttyUSB0", mode)
if err != nil {
log.Fatal(err)
}
ctx, cancle := context.WithCancel(context.Background())
defer cancle()
go func() {
buff := make([]byte, 1024)
mr := MessageReceive{}
initMessageReceive(&mr)
for {
select {
case <-ctx.Done():
return
default:
n, err := port.Read(buff)
if err != nil {
log.Print(err)
break
}
if n == 0 {
fmt.Println("\nEOF")
break
}
for _, b := range buff[:n] {
parseByte(&mr, b)
}
//fmt.Printf("Empfangen: % 02X\n", string(buff[:n]))
break
}
}
}()
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)
// 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])
}
}
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")
}
}
}