← back to kevin-buckham__MMCd-Go

Function bodies 80 total

All specs Real LLM only Function bodies
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, go
protocol.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
		injp
protocol.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: "%", Exist
sensor.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