package main import ( "context" "encoding/binary" "flag" "fmt" "log" "os" "time" "github.com/pterm/pterm" "go.bug.st/serial" ) type ParserState int const ( // MISC UART_ECHO = 0x01 UART_VERSION = 0x02 UART_CLIENT_INFO = 0x03 // OTA UART_OTA_START = 0x10 UART_OTA_PAYLOAD = 0x11 UART_OTA_END = 0x12 UART_OTA_STATUS = 0x13 ) 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 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): break case UART_VERSION: parse_uart_version_payload(mr.parsed_message, mr.write_index) break case UART_CLIENT_INFO: parse_uart_client_info_payload(mr.parsed_message, mr.write_index) break case UART_OTA_START: OTA_UpdateHandler.NewOTAMessage <- mr break case UART_OTA_PAYLOAD: parse_uart_ota_payload_payload(mr.parsed_message, mr.write_index) OTA_UpdateHandler.NewOTAMessage <- mr break case UART_OTA_END: OTA_UpdateHandler.NewOTAMessage <- mr break case UART_OTA_STATUS: OTA_UpdateHandler.NewOTAMessage <- mr break } } 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 break case GET_MESSAGE_ID: if pbyte == ESCAPE_BYTE { mr.state = ESCAPED_MESSAGE_ID } else { addByteToParsedBuffer(mr, pbyte) mr.state = IN_PAYLOD } break case ESCAPED_MESSAGE_ID: addByteToParsedBuffer(mr, pbyte) mr.state = IN_PAYLOD break 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) break case ESCAPED_PAYLOAD_BYTE: addByteToParsedBuffer(mr, pbyte) mr.state = IN_PAYLOD break 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 _, err := fmt.Scanln(&input) if err != nil { log.Fatalf("Could not read from stdin") } 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]) break 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]) break 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]) break 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]) break 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]) break case "6": // end update default: fmt.Printf("Not a valid input") } } }