Refactor kafka to pure Go (franz-go), fix DBC stubs, update Dockerfile

This commit is contained in:
Chris Rai
2026-01-31 00:05:47 -05:00
parent fbb820d7b3
commit b5bec57dfa
776 changed files with 18945 additions and 2052 deletions

135
pkg/can-go/frame.go Normal file
View File

@@ -0,0 +1,135 @@
package can
import (
"encoding/hex"
"fmt"
"strconv"
"strings"
)
const (
idBits = 11
extendedIDBits = 29
)
// CAN format constants.
const (
MaxID = 0x7ff
MaxExtendedID = 0x1fffffff
)
// Frame represents a CAN frame.
//
// A Frame is intentionally designed to fit into 16 bytes on common architectures
// and is therefore amenable to pass-by-value and judicious copying.
type Frame struct {
// ID is the CAN ID
ID uint32
// Length is the number of bytes of data in the frame.
Length uint16
// Data is the frame data.
Data Data
// IsRemote is true for remote frames.
IsRemote bool
// IsExtended is true for extended frames, i.e. frames with 29-bit IDs.
IsExtended bool
}
// Validate returns an error if the Frame is not a valid CAN frame.
func (f *Frame) Validate() error {
// Validate: ID
if f.IsExtended && f.ID > MaxExtendedID {
return fmt.Errorf(
"invalid extended CAN id: %v does not fit in %v bits",
f.ID,
extendedIDBits,
)
} else if !f.IsExtended && f.ID > MaxID {
return fmt.Errorf(
"invalid standard CAN id: %v does not fit in %v bits",
f.ID,
idBits,
)
}
// Validate: Data
if f.Length > MaxDataLength {
return fmt.Errorf("invalid data length: %v", f.Length)
}
return nil
}
// String returns an ASCII representation the CAN frame.
//
// Format:
//
// ([0-9A-F]{3}|[0-9A-F]{3})#(R[0-8]?|[0-9A-F]{0,16})
//
// The format is compatible with the candump(1) log file format.
func (f Frame) String() string {
var id string
if f.IsExtended {
id = fmt.Sprintf("%08X", f.ID)
} else {
id = fmt.Sprintf("%03X", f.ID)
}
if f.IsRemote && f.Length == 0 {
return id + "#R"
} else if f.IsRemote {
return id + "#R" + strconv.Itoa(int(f.Length))
}
return id + "#" + strings.ToUpper(hex.EncodeToString(f.Data[:f.Length]))
}
// UnmarshalString sets *f using the provided ASCII representation of a Frame.
func (f *Frame) UnmarshalString(s string) error {
// Split split into parts
parts := strings.Split(s, "#")
if len(parts) != 2 {
return fmt.Errorf("invalid frame format: %v", s)
}
idPart, dataPart := parts[0], parts[1]
var frame Frame
// Parse: IsExtended
if len(idPart) != 3 && len(idPart) != 8 {
return fmt.Errorf("invalid ID length: %v", s)
}
frame.IsExtended = len(idPart) == 8
// Parse: ID
id, err := strconv.ParseUint(idPart, 16, 32)
if err != nil {
return fmt.Errorf("invalid frame ID: %v", s)
}
frame.ID = uint32(id)
if len(dataPart) == 0 {
*f = frame
return nil
}
// Parse: IsRemote
if dataPart[0] == 'R' {
frame.IsRemote = true
if len(dataPart) > 2 {
return fmt.Errorf("invalid remote length: %v", s)
} else if len(dataPart) == 2 {
dataLength, err := strconv.Atoi(dataPart[1:2])
if err != nil {
return fmt.Errorf("invalid remote length: %v: %w", s, err)
}
frame.Length = uint16(dataLength)
}
*f = frame
return nil
}
// Parse: Length
if len(dataPart) > 16 || len(dataPart)%2 != 0 {
return fmt.Errorf("invalid data length: %v", s)
}
frame.Length = uint16(len(dataPart) / 2)
// Parse: Data
decodedData, err := hex.DecodeString(dataPart)
if err != nil {
return fmt.Errorf("invalid data: %v: %w", s, err)
}
copy(frame.Data[:], decodedData)
*f = frame
return nil
}