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 } }