Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ require (
fyne.io/systray v1.12.0 // indirect
github.com/BurntSushi/toml v1.6.0 // indirect
github.com/FyshOS/fancyfs v0.0.1 // indirect
github.com/TheTitanrain/w32 v0.0.0-20180517000239-4f5cfb03fabf // indirect
github.com/albenik/bcd v0.0.0-20170831201648-635201416bc7 // indirect
github.com/bendikro/dl v0.0.0-20190410215913-e41fdb9069d4 // indirect
github.com/creack/goselect v0.1.3 // indirect
Expand Down Expand Up @@ -73,6 +74,7 @@ require (
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/rymdport/portal v0.4.2 // indirect
github.com/sqweek/dialog v0.0.0-20260123140253-64c163d53aac // indirect
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect
github.com/stretchr/testify v1.11.1 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ github.com/FyshOS/fancyfs v0.0.1 h1:kgvm7VvwOMLkYTqSflplp62SlMVWQ2uAoHw9CXwXHYg=
github.com/FyshOS/fancyfs v0.0.1/go.mod h1:S5SHVz/5R72iCXOxCqdcyTPSlg3JxNd0gaHyGBSrY8A=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/TheTitanrain/w32 v0.0.0-20180517000239-4f5cfb03fabf h1:FPsprx82rdrX2jiKyS17BH6IrTmUBYqZa/CXT4uvb+I=
github.com/TheTitanrain/w32 v0.0.0-20180517000239-4f5cfb03fabf/go.mod h1:peYoMncQljjNS6tZwI9WVyQB3qZS6u79/N3mBOcnd3I=
github.com/albenik/bcd v0.0.0-20170831201648-635201416bc7 h1:m3Ayfs5OcAlIMEdLIQKubBsVLGee4YMUr14+d1256WE=
github.com/albenik/bcd v0.0.0-20170831201648-635201416bc7/go.mod h1:QIAMbrwsnQZ2ES3G26RubSrDB5SPyzsp9Hts5NJdTrI=
github.com/avast/retry-go/v4 v4.7.0 h1:yjDs35SlGvKwRNSykujfjdMxMhMQQM0TnIjJaHB+Zio=
Expand Down Expand Up @@ -125,6 +127,8 @@ github.com/rymdport/portal v0.4.2 h1:7jKRSemwlTyVHHrTGgQg7gmNPJs88xkbKcIL3NlcmSU
github.com/rymdport/portal v0.4.2/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
github.com/samuelbrian/can-go v0.0.2 h1:M2B5j9O97lCGlsUYTWYFBwdhHWvA9HpW+A1wfDukRN4=
github.com/samuelbrian/can-go v0.0.2/go.mod h1:a1aqkRYR3BBP3u9uJvvZQjn//TtH5MnlMsAzbR9IQvM=
github.com/sqweek/dialog v0.0.0-20260123140253-64c163d53aac h1:/QqP+ajFMma4hNWQyBDVaQQhz9Z1kDyXScNWMO3owx0=
github.com/sqweek/dialog v0.0.0-20260123140253-64c163d53aac/go.mod h1:/qNPSY91qTz/8TgHEMioAUc6q7+3SOybeKczHMXFcXw=
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE=
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q=
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
Expand Down
282 changes: 282 additions & 0 deletions pkg/ecu/z22se/info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
package z22se

import (
"bytes"
"context"
"encoding/binary"
"fmt"
"log"
"strconv"
"strings"

"github.com/roffe/gocan"
"github.com/roffe/txlogger/pkg/model"
)

var T8Headers = []model.Header{
{Desc: "VIN", ID: 0x90, Type: "string"},
{Desc: "Calibration set ", ID: 0x74, Type: "string"},
{Desc: "Codefile version", ID: 0x73, Type: "string"},
{Desc: "ECU description", ID: 0x72, Type: "string"},
{Desc: "ECU hardware", ID: 0x71, Type: "string"},
{Desc: "ECU s/w number", ID: 0x95, Type: "hex"},
{Desc: "Programming date", ID: 0x99, Type: "hex"},
{Desc: "Build date", ID: 0x0A, Type: "string"},
{Desc: "Serial number", ID: 0xB4, Type: "string"},
{Desc: "Software version", ID: 0x08, Type: "string"},
{Desc: "0F identifier ", ID: 0x0F, Type: "string"},
{Desc: "SW identifier 1", ID: 0xC1, Type: "string"},
{Desc: "SW identifier 2", ID: 0xC2, Type: "string"},
{Desc: "SW identifier 3", ID: 0xC3, Type: "string"},
{Desc: "SW identifier 4", ID: 0xC4, Type: "string"},
{Desc: "SW identifier 5", ID: 0xC5, Type: "string"},
{Desc: "SW identifier 6", ID: 0xC6, Type: "string"},
{Desc: "Hardware type", ID: 0x97, Type: "string"},
{Desc: "75 identifier", ID: 0x75, Type: "string"},
{Desc: "Engine type", ID: 0x0C, Type: "string"},
{Desc: "Supplier ID", ID: 0x92, Type: "string"},
{Desc: "Speed limiter", ID: 0x02, Type: "km/h"},
{Desc: "Oil quality", ID: 0x25, Type: "oilquality"},
{Desc: "SAAB partnumber", ID: 0x7C, Type: "int32"},
{Desc: "Diagnostic Data Identifier", ID: 0x9A, Type: "ddi"},
{Desc: "End model partnumber", ID: 0xCB, Type: "rint32"},
{Desc: "Base model partnumber", ID: 0xCC, Type: "int32"},
{Desc: "ManufacturersEnableCounter", ID: 0xA0, Type: "hex"},
{Desc: "Tester Serial", ID: 0x98, Type: "string"},
//{Desc: "E85", ID: 0x7A, Type: "e85"},
}

func (t *Client) Info(ctx context.Context) ([]model.HeaderResult, error) {
t.cfg.OnProgress(-float64(len(T8Headers)))
t.cfg.OnMessage("Fetching ECU info")

var out []model.HeaderResult
for i, h := range T8Headers {
switch h.Type {
case "string":
data, err := t.gm.ReadDataByIdentifierString(ctx, h.ID)
if err != nil {
t.cfg.OnError(fmt.Errorf("failed to read %s: %w", h.Desc, err))
continue
}
res := model.HeaderResult{
Value: data,
}
res.ID = h.ID
res.Desc = h.Desc
out = append(out, res)
case "int64":
data, err := t.RequestECUInfoAsInt64(ctx, h.ID)
if err != nil {
t.cfg.OnError(fmt.Errorf("failed to read %s: %w", h.Desc, err))
continue
}
res := model.HeaderResult{
Value: strconv.Itoa(int(data)),
}
res.ID = h.ID
res.Desc = h.Desc
out = append(out, res)
case "hex":
data, err := t.RequestECUInfo(ctx, h.ID)
if err != nil {
t.cfg.OnError(fmt.Errorf("failed to read %s: %w", h.Desc, err))
continue
}
res := model.HeaderResult{
Value: fmt.Sprintf("%X", data),
}
res.ID = h.ID
res.Desc = h.Desc
out = append(out, res)
case "int32":
data, err := t.RequestECUInfoAsInt32(ctx, h.ID)
if err != nil {
t.cfg.OnError(fmt.Errorf("failed to read %s: %w", h.Desc, err))
continue
}
res := model.HeaderResult{
Value: strconv.Itoa(int(data)),
}
res.ID = h.ID
res.Desc = h.Desc
out = append(out, res)
case "uint32":
data, err := t.RequestECUInfoAsUint32(ctx, h.ID)
if err != nil {
t.cfg.OnError(fmt.Errorf("failed to read %s: %w", h.Desc, err))
continue
}
res := model.HeaderResult{
Value: strconv.Itoa(int(data)),
}
res.ID = h.ID
res.Desc = h.Desc
out = append(out, res)
case "rint32":
resp, err := t.RequestECUInfo(ctx, h.ID)
if err != nil {
log.Println(err)
continue
}
var retval uint32
if err := binary.Read(bytes.NewReader(resp), binary.LittleEndian, &retval); err != nil {
log.Println(err)
continue
}
res := model.HeaderResult{
Value: strconv.Itoa(int(retval)),
}
res.ID = h.ID
res.Desc = h.Desc
out = append(out, res)

case "km/h":
data, err := t.RequestECUInfo(ctx, h.ID)
if err != nil {
t.cfg.OnError(fmt.Errorf("failed to read %s: %w", h.Desc, err))
continue
}
var retval uint32
if len(data) == 2 {
retval = uint32(data[0]) * 256
retval += uint32(data[1])
retval /= 10
}
res := model.HeaderResult{
Value: fmt.Sprintf("%d km/h", retval),
}
res.ID = h.ID
res.Desc = h.Desc
out = append(out, res)
case "oilquality":
data, err := t.RequestECUInfoAsUint32(ctx, h.ID)
if err != nil {
t.cfg.OnError(fmt.Errorf("failed to read %s: %w", h.Desc, err))
continue
}
quality := float64(data) / 256
res := model.HeaderResult{
Value: fmt.Sprintf("%.2f%%", quality),
}
res.ID = h.ID
res.Desc = h.Desc
out = append(out, res)

case "ddi":
data, err := t.RequestECUInfo(ctx, h.ID)
if err != nil {
t.cfg.OnError(fmt.Errorf("failed to read %s: %w", h.Desc, err))
continue
}
var retval string
if len(data) == 2 {
retval = fmt.Sprintf("0x%02X 0x%02X", data[0], data[1])
}
res := model.HeaderResult{
Value: retval,
}
res.ID = h.ID
res.Desc = h.Desc
out = append(out, res)
case "e85":
data, err := t.gm.ReadDataByPacketIdentifier(ctx, 0x01, 0x7A)
if err != nil && err.Error() != "Request out of range or session dropped" {
t.cfg.OnError(fmt.Errorf("failed to read %s: %w", h.Desc, err))
continue
}
if len(data) == 2 {
e85 := uint32(data[2])
res := model.HeaderResult{
Value: fmt.Sprintf("%d%%", e85),
}
res.ID = h.ID
res.Desc = h.Desc
out = append(out, res)
} else {
res := model.HeaderResult{
Value: "Not BioPower",
}
res.ID = h.ID
res.Desc = h.Desc
out = append(out, res)
}
}
t.cfg.OnProgress(float64(i + 1))
}

return out, nil
}
func (t *Client) RequestECUInfoAsString(ctx context.Context, pid byte) (string, error) {
resp, err := t.RequestECUInfo(ctx, pid)
if err != nil {
return "", err
}
return strings.ReplaceAll(string(resp[:]), "\x00", ""), nil
}

func (t *Client) RequestECUInfoAsInt32(ctx context.Context, pid byte) (int32, error) {
resp, err := t.RequestECUInfo(ctx, pid)
if err != nil {
return 0, err
}
var retval int32
if err := binary.Read(bytes.NewReader(resp), binary.BigEndian, &retval); err != nil {
return 0, err
}
return retval, nil
}

func (t *Client) RequestECUInfoAsUint32(ctx context.Context, pid byte) (uint32, error) {
resp, err := t.RequestECUInfo(ctx, pid)
if err != nil {
return 0, err
}
var retval uint32
if err := binary.Read(bytes.NewReader(resp), binary.BigEndian, &retval); err != nil {
return 0, err
}
return retval, nil
}

func (t *Client) RequestECUInfoAsInt64(ctx context.Context, pid byte) (int64, error) {
resp, err := t.RequestECUInfo(ctx, pid)
if err != nil {
return 0, err
}
if len(resp) != 8 {
return 0, fmt.Errorf("invalid response length for int64: %d", len(resp))
}

var retval int64
if err := binary.Read(bytes.NewReader(resp), binary.BigEndian, &retval); err != nil {
return 0, err
}
return retval, nil
}

func (t *Client) RequestECUInfoAsUint64(ctx context.Context, pid byte) (uint64, error) {
resp, err := t.RequestECUInfo(ctx, pid)
if err != nil {
return 0, err
}
if len(resp) != 8 {
return 0, fmt.Errorf("invalid response length for uint64: %d", len(resp))
}

var retval uint64
if err := binary.Read(bytes.NewReader(resp), binary.BigEndian, &retval); err != nil {
return 0, err
}
return retval, nil
}

func (t *Client) RequestECUInfo(ctx context.Context, pid byte) ([]byte, error) {
return t.gm.ReadDataByIdentifier(ctx, pid)
}

func (t *Client) SendAckMessageT8() {
if err := t.c.Send(0x7E0, []byte{0x30}, gocan.Outgoing); err != nil {
panic(err)
}
}
6 changes: 0 additions & 6 deletions pkg/ecu/z22se/z22se.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"github.com/roffe/txlogger/pkg/ecu"
"github.com/roffe/txlogger/pkg/ecu/t8legion"
"github.com/roffe/txlogger/pkg/ecu/t8sec"
"github.com/roffe/txlogger/pkg/model"
)

func init() {
Expand All @@ -37,11 +36,6 @@ type Client struct {
cfg *ecu.Config
}

// Info implements [ecu.Client].
func (t *Client) Info(context.Context) ([]model.HeaderResult, error) {
return nil, nil
}

// ReadDTC implements [ecu.Client].
func (t *Client) ReadDTC(context.Context) ([]dtc.DTC, error) {
return nil, nil
Expand Down
19 changes: 16 additions & 3 deletions pkg/native/dialog_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"

"github.com/godbus/dbus/v5"
"github.com/sqweek/dialog"
)

// GenerateDBusToken generates a random D-Bus authentication token
Expand Down Expand Up @@ -115,11 +116,15 @@ func OpenFileDialog(title string, filters ...FileFilter) (string, error) {
if len(filters) > 0 {
options["filters"] = buildPortalFilters(filters)
}
return portalCall(
filename, err := portalCall(
"org.freedesktop.portal.FileChooser.OpenFile",
options,
title,
)
if err == nil {
return filename, err
}
return dialog.File().Title("Open File").Filter("bin file", "bin").Load()
}

func OpenFolderDialog(title string) (string, error) {
Expand All @@ -128,11 +133,15 @@ func OpenFolderDialog(title string) (string, error) {
"multiple": dbus.MakeVariant(false),
"directory": dbus.MakeVariant(true),
}
return portalCall(
filename, err := portalCall(
"org.freedesktop.portal.FileChooser.OpenFile",
options,
title,
)
if err == nil {
return filename, err
}
return dialog.File().Title("Open folder").Load()
}

func SaveFileDialog(title string, defaultExt string, filters ...FileFilter) (string, error) {
Expand Down Expand Up @@ -192,9 +201,13 @@ func SaveFileDialog(title string, defaultExt string, filters ...FileFilter) (str
// If filters is non-empty but no match found, skip current_filter entirely
// to avoid the portal rejecting the call.
}
return portalCall(
filename, err := portalCall(
"org.freedesktop.portal.FileChooser.SaveFile",
options,
title,
)
if err == nil {
return filename, err
}
return dialog.File().Title("Save File").Filter("bin file", "bin").Save()
}