Function bodies 80 total
protocol.ECU.SendCommand method · go · L115-L171 (57 LOC)internal/protocol/ecu.go
func (e *ECU) SendCommand(cmd byte, timeout time.Duration) (byte, error) {
if !validCommandAddrs[cmd] {
return 0, fmt.Errorf("command 0x%02X is not a known ECU command address", cmd)
}
e.busMu.Lock()
defer e.busMu.Unlock()
// Flush stale bytes before sending command
e.conn.Flush()
// Send command
_, err := e.conn.Send([]byte{cmd})
if err != nil {
return 0, fmt.Errorf("failed to send command 0x%02X: %w", cmd, err)
}
// Read echo with short timeout
buf := make([]byte, 1)
echoDeadline := time.Now().Add(500 * time.Millisecond)
echoRead := 0
for echoRead < 1 && time.Now().Before(echoDeadline) {
n, err := e.conn.Receive(buf)
if err != nil {
e.conn.Flush()
return 0, fmt.Errorf("failed to read echo for command 0x%02X: %w", cmd, err)
}
echoRead += n
}
if echoRead < 1 {
e.conn.Flush()
return 0, fmt.Errorf("timeout reading echo for command 0x%02X", cmd)
}
if buf[0] != cmd {
e.conn.Flush()
return 0, fmt.Errorf("command echo mismatch: sent 0x%02X, goprotocol.NewSerialConn function · go · L30-L38 (9 LOC)internal/protocol/serial.go
func NewSerialConn(portName string, baudRate int) *SerialConn {
if baudRate <= 0 {
baudRate = DefaultBaudRate
}
return &SerialConn{
portName: portName,
baudRate: baudRate,
}
}protocol.SerialConn.Open method · go · L41-L74 (34 LOC)internal/protocol/serial.go
func (sc *SerialConn) Open() error {
sc.mu.Lock()
defer sc.mu.Unlock()
if sc.isOpen {
return nil
}
mode := &serial.Mode{
BaudRate: sc.baudRate,
DataBits: DefaultDataBits,
StopBits: serial.OneStopBit,
Parity: serial.NoParity,
}
port, err := serial.Open(sc.portName, mode)
if err != nil {
return fmt.Errorf("failed to open serial port %s: %w", sc.portName, err)
}
// Set read timeout to 500ms (matching original code's half-second timeout)
if err := port.SetReadTimeout(500 * time.Millisecond); err != nil {
port.Close()
return fmt.Errorf("failed to set read timeout: %w", err)
}
sc.port = port
sc.isOpen = true
slog.Info("serial port opened", "port", sc.portName, "baud", sc.baudRate)
if sc.baudRate != DefaultBaudRate {
slog.Warn("non-standard baud rate", "baud", sc.baudRate, "expected", DefaultBaudRate)
}
return nil
}protocol.SerialConn.Close method · go · L77-L90 (14 LOC)internal/protocol/serial.go
func (sc *SerialConn) Close() error {
sc.mu.Lock()
defer sc.mu.Unlock()
if !sc.isOpen {
return nil
}
err := sc.port.Close()
sc.isOpen = false
sc.port = nil
slog.Info("serial port closed", "port", sc.portName)
return err
}protocol.SerialConn.Send method · go · L100-L108 (9 LOC)internal/protocol/serial.go
func (sc *SerialConn) Send(data []byte) (int, error) {
sc.mu.Lock()
defer sc.mu.Unlock()
if !sc.isOpen {
return 0, fmt.Errorf("serial port not open")
}
return sc.port.Write(data)
}protocol.SerialConn.Receive method · go · L111-L119 (9 LOC)internal/protocol/serial.go
func (sc *SerialConn) Receive(buf []byte) (int, error) {
sc.mu.Lock()
defer sc.mu.Unlock()
if !sc.isOpen {
return 0, fmt.Errorf("serial port not open")
}
return sc.port.Read(buf)
}protocol.SerialConn.Flush method · go · L132-L140 (9 LOC)internal/protocol/serial.go
func (sc *SerialConn) Flush() error {
sc.mu.Lock()
defer sc.mu.Unlock()
if !sc.isOpen {
return nil
}
return sc.port.ResetInputBuffer()
}Repobility · code-quality intelligence platform · https://repobility.com
protocol.ListPorts function · go · L143-L149 (7 LOC)internal/protocol/serial.go
func ListPorts() ([]string, error) {
ports, err := serial.GetPortsList()
if err != nil {
return nil, fmt.Errorf("failed to list serial ports: %w", err)
}
return ports, nil
}protocol.NewSimulator function · go · L23-L28 (6 LOC)internal/protocol/simulator.go
func NewSimulator(defs []sensor.Definition) *Simulator {
return &Simulator{
defs: defs,
rng: rand.New(rand.NewSource(time.Now().UnixNano())),
}
}protocol.Simulator.PollSensors method · go · L31-L177 (147 LOC)internal/protocol/simulator.go
func (s *Simulator) PollSensors(indices []int) (sensor.Sample, error) {
s.mu.Lock()
defer s.mu.Unlock()
s.tick += 0.05 // ~20Hz simulation rate
var sample sensor.Sample
sample.Time = time.Now()
// Driving cycle: 60-second loop
// 0-10s: idle
// 10-20s: acceleration (revving up)
// 20-40s: cruise
// 40-50s: deceleration
// 50-60s: idle
cyclePos := math.Mod(s.tick, 60.0)
var rpmTarget, tpsTarget, coolTarget float64
var timingTarget, injpTarget float64
switch {
case cyclePos < 10: // idle
rpmTarget = 850
tpsTarget = 0
coolTarget = 82
timingTarget = 10
injpTarget = 3.0
case cyclePos < 20: // acceleration
progress := (cyclePos - 10) / 10.0
rpmTarget = 850 + progress*5150 // up to 6000
tpsTarget = 30 + progress*60 // up to 90%
coolTarget = 82 + progress*8 // warming up
timingTarget = 10 + progress*25
injpTarget = 3.0 + progress*15.0
case cyclePos < 40: // cruise
rpmTarget = 3200
tpsTarget = 25
coolTarget = 90
timingTarget = 32
injpprotocol.clamp function · go · L179-L187 (9 LOC)internal/protocol/simulator.go
func clamp(v, min, max float64) float64 {
if v < min {
return min
}
if v > max {
return max
}
return v
}sensor.ParseUnitSystem function · go · L17-L26 (10 LOC)internal/sensor/convert.go
func ParseUnitSystem(s string) UnitSystem {
switch s {
case "imperial", "english":
return UnitEnglish
case "raw", "numeric":
return UnitRaw
default:
return UnitMetric
}
}sensor.fFLG0 function · go · L44-L52 (9 LOC)internal/sensor/convert.go
func fFLG0(raw byte, _ UnitSystem) (float64, string) {
s := ""
if raw&0x20 == 0 {
s = "A"
} else {
s = "-"
}
return float64(raw), s
}sensor.fFLG2 function · go · L55-L83 (29 LOC)internal/sensor/convert.go
func fFLG2(raw byte, _ UnitSystem) (float64, string) {
flags := ""
if raw&0x04 == 0 {
flags += "T"
} else {
flags += "-"
}
if raw&0x08 != 0 {
flags += "S"
} else {
flags += "-"
}
if raw&0x10 == 0 {
flags += "A"
} else {
flags += "-"
}
if raw&0x20 == 0 {
flags += "N"
} else {
flags += "-"
}
if raw&0x80 != 0 {
flags += "I"
} else {
flags += "-"
}
return float64(raw), flags
}sensor.fAIRT function · go · L93-L108 (16 LOC)internal/sensor/convert.go
func fAIRT(raw byte, units UnitSystem) (float64, string) {
if units == UnitRaw {
return fDEC(raw, units)
}
idx := int(raw) / 16
rem := int(raw) % 16
v1 := float64(airTempInterp[idx])
v2 := float64(airTempInterp[idx+1])
tempC := v1 - float64(rem)*(v1-v2)/16.0 - 60.0
if units == UnitEnglish {
tempF := tempC*9.0/5.0 + 32.0
return tempF, fmt.Sprintf("%.1f\u00b0F", tempF)
}
return tempC, fmt.Sprintf("%.1f\u00b0C", tempC)
}About: code-quality intelligence by Repobility · https://repobility.com
sensor.fCOOL function · go · L118-L133 (16 LOC)internal/sensor/convert.go
func fCOOL(raw byte, units UnitSystem) (float64, string) {
if units == UnitRaw {
return fDEC(raw, units)
}
idx := int(raw) / 16
rem := int(raw) % 16
v1 := float64(coolantTempInterp[idx])
v2 := float64(coolantTempInterp[idx+1])
tempC := v1 - float64(rem)*(v1-v2)/16.0 - 80.0
if units == UnitEnglish {
tempF := tempC*9.0/5.0 + 32.0
return tempF, fmt.Sprintf("%.1f\u00b0F", tempF)
}
return tempC, fmt.Sprintf("%.1f\u00b0C", tempC)
}sensor.fEGRT function · go · L136-L147 (12 LOC)internal/sensor/convert.go
func fEGRT(raw byte, units UnitSystem) (float64, string) {
if units == UnitRaw {
return fDEC(raw, units)
}
tempC := -1.5*float64(raw) + 314.27
if units == UnitEnglish {
tempF := tempC*9.0/5.0 + 32.0
return tempF, fmt.Sprintf("%.1f\u00b0F", tempF)
}
return tempC, fmt.Sprintf("%.1f\u00b0C", tempC)
}sensor.fBARO function · go · L168-L178 (11 LOC)internal/sensor/convert.go
func fBARO(raw byte, units UnitSystem) (float64, string) {
if units == UnitRaw {
return fDEC(raw, units)
}
bar := 0.00486 * float64(raw)
if units == UnitEnglish {
psi := bar * 14.50326
return psi, fmt.Sprintf("%.2fpsi", psi)
}
return bar, fmt.Sprintf("%.3fbar", bar)
}sensor.Definition.Format method · go · L20-L27 (8 LOC)internal/sensor/definitions.go
func (d *Definition) Format(raw byte, units UnitSystem) string {
if d.convertFunc == nil {
_, s := fDEC(raw, units)
return s
}
_, s := d.convertFunc(raw, units)
return s
}sensor.Definition.Convert method · go · L30-L37 (8 LOC)internal/sensor/definitions.go
func (d *Definition) Convert(raw byte, units UnitSystem) float64 {
if d.convertFunc == nil {
v, _ := fDEC(raw, units)
return v
}
v, _ := d.convertFunc(raw, units)
return v
}sensor.DefaultDefinitions function · go · L41-L123 (83 LOC)internal/sensor/definitions.go
func DefaultDefinitions() []Definition {
defs := make([]Definition, MaxSensors)
// Index 0: unused placeholder
defs[0] = Definition{Addr: 0xFF, Slug: "", Description: "", Exists: false, convertFunc: fDEC}
// Index 1: Flags 0 (AC clutch)
defs[1] = Definition{Addr: 0x00, Slug: "FLG0", Description: "Flags 0 (AC clutch)", Unit: "flags", Exists: true, convertFunc: fFLG0}
// Index 2: Flags 2 (TDC, P/S, AC, P/N, Idle)
defs[2] = Definition{Addr: 0x02, Slug: "FLG2", Description: "Flags 2 (TDC/PS/AC/PN/Idle)", Unit: "flags", Exists: true, convertFunc: fFLG2}
// Index 3: Timing Advance
defs[3] = Definition{Addr: 0x06, Slug: "TIMA", Description: "Timing advance", Unit: "deg", Exists: true, convertFunc: fTIMA}
// Index 4: Coolant Temperature
defs[4] = Definition{Addr: 0x07, Slug: "COOL", Description: "Coolant temp", Unit: "deg", Exists: true, convertFunc: fCOOL}
// Index 5: Fuel Trim Low
defs[5] = Definition{Addr: 0x0C, Slug: "FTRL", Description: "Fuel trim low", Unit: "%", Existsensor.ActiveDefinitions function · go · L127-L135 (9 LOC)internal/sensor/definitions.go
func ActiveDefinitions(defs []Definition) []Definition {
var active []Definition
for _, d := range defs {
if d.Exists && !d.Computed {
active = append(active, d)
}
}
return active
}sensor.FindBySlug function · go · L138-L145 (8 LOC)internal/sensor/definitions.go
func FindBySlug(defs []Definition, slug string) (int, *Definition) {
for i := range defs {
if defs[i].Slug == slug {
return i, &defs[i]
}
}
return -1, nil
}Repobility analyzer · published findings · https://repobility.com
sensor.FindByAddr function · go · L148-L155 (8 LOC)internal/sensor/definitions.go
func FindByAddr(defs []Definition, addr byte) (int, *Definition) {
for i := range defs {
if defs[i].Exists && defs[i].Addr == addr {
return i, &defs[i]
}
}
return -1, nil
}sensor.SlugsToIndices function · go · L159-L171 (13 LOC)internal/sensor/definitions.go
func SlugsToIndices(defs []Definition, slugs []string) ([]int, []string) {
var indices []int
var notFound []string
for _, slug := range slugs {
idx, _ := FindBySlug(defs, slug)
if idx >= 0 {
indices = append(indices, idx)
} else {
notFound = append(notFound, slug)
}
}
return indices, notFound
}sensor.AllPollableIndices function · go · L174-L182 (9 LOC)internal/sensor/definitions.go
func AllPollableIndices(defs []Definition) []int {
var indices []int
for i, d := range defs {
if d.Exists && !d.Computed && d.Addr != 0xFF {
indices = append(indices, i)
}
}
return indices
}sensor.Sample.ConvertedValues method · go · L24-L33 (10 LOC)internal/sensor/sample.go
func (s *Sample) ConvertedValues(defs []Definition, units UnitSystem) map[string]string {
result := make(map[string]string, len(defs))
for i, def := range defs {
if !def.Exists || !s.HasData(i) {
continue
}
result[def.Slug] = def.Format(s.RawData[i], units)
}
return result
}sensor.Sample.ConvertedFloats method · go · L36-L45 (10 LOC)internal/sensor/sample.go
func (s *Sample) ConvertedFloats(defs []Definition, units UnitSystem) map[string]float64 {
result := make(map[string]float64, len(defs))
for i, def := range defs {
if !def.Exists || !s.HasData(i) {
continue
}
result[def.Slug] = def.Convert(s.RawData[i], units)
}
return result
}sensor.Sample.ComputeDerivatives method · go · L49-L77 (29 LOC)internal/sensor/sample.go
func (s *Sample) ComputeDerivatives(defs []Definition) {
rpmIdx := -1
injpIdx := -1
injdIdx := -1
for i, def := range defs {
switch def.Slug {
case "RPM":
rpmIdx = i
case "INJP":
injpIdx = i
case "INJD":
injdIdx = i
}
}
if rpmIdx < 0 || injpIdx < 0 || injdIdx < 0 {
return
}
if s.HasData(rpmIdx) && s.HasData(injpIdx) {
// Injector duty cycle = (IPW_raw * RPM_raw) / 117, capped at 255
v := int32(s.RawData[injpIdx]) * int32(s.RawData[rpmIdx]) / 117
if v > 255 {
v = 255
}
s.SetData(injdIdx, byte(v))
}
}main.main function · go · L18-L45 (28 LOC)main.go
func main() {
// If subcommands are provided, run CLI mode
if len(os.Args) > 1 {
cli.Execute()
return
}
// Otherwise, launch the Wails desktop app
app := NewApp()
err := wails.Run(&options.App{
Title: "MMCD Datalogger",
Width: 1024,
Height: 768,
AssetServer: &assetserver.Options{
Assets: assets,
},
OnStartup: app.startup,
OnShutdown: app.shutdown,
Bind: []interface{}{
app,
},
})
if err != nil {
println("Error:", err.Error())
}
}‹ prevpage 2 / 2