feat(platform): harden telemetry pipeline and unify Semi UI workspaces
This commit is contained in:
93
go/vehicle-gateway/internal/feichibridge/encoder_test.go
Normal file
93
go/vehicle-gateway/internal/feichibridge/encoder_test.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package feichibridge
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"lingniu-vehicle-ingest/go/vehicle-gateway/internal/protocol/gb32960"
|
||||
)
|
||||
|
||||
func TestDataFrameMapsFeichiFields(t *testing.T) {
|
||||
at := time.Date(2026, 7, 17, 14, 5, 6, 0, shanghai)
|
||||
record := Record{
|
||||
"2000": "2026-07-17 14:05:06",
|
||||
"2201": "42.3", "2202": "12345.6", "2203": "D 0 0",
|
||||
"2208": "35", "2209": "0", "2213": "纯电",
|
||||
"2214": "工作", "2301": "未充电状态", "3201": "启动状态",
|
||||
"2613": "550.2", "2614": "-20.5", "2617": "2200", "7615": "78",
|
||||
"2501": "有效定位", "2502": "113.2644", "2503": "23.1291",
|
||||
"2601": "1", "2602": "8", "2603": "3.955",
|
||||
"2604": "1", "2605": "26", "2606": "3.821",
|
||||
"2607": "1", "2608": "3", "2609": "48",
|
||||
"2610": "1", "2611": "9", "2612": "37",
|
||||
"2003": "1:3.900_3.901_3.902",
|
||||
"2103": "1:35_36_37",
|
||||
}
|
||||
frame, err := (Encoder{}).DataFrame(CommandRealtime, "LTEST32960VIN0001", at, record)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
env, err := gb32960.ParseFrame(frame, at.UnixMilli(), "test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if env.MessageID != "0x02" || env.VIN != "LTEST32960VIN0001" {
|
||||
t.Fatalf("unexpected envelope: %#v", env)
|
||||
}
|
||||
if got := env.Fields["speed_kmh"]; got != 42.3 {
|
||||
t.Fatalf("speed = %#v", got)
|
||||
}
|
||||
if got := env.Fields["total_mileage_km"]; got != 12345.6 {
|
||||
t.Fatalf("mileage = %#v", got)
|
||||
}
|
||||
if got := env.Fields["soc_percent"]; got != 78 {
|
||||
t.Fatalf("soc = %#v", got)
|
||||
}
|
||||
if got := env.Fields["longitude"]; got != 113.2644 {
|
||||
t.Fatalf("longitude = %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDataFrameSplitsMoreThan255CellVoltages(t *testing.T) {
|
||||
values := make([]string, 288)
|
||||
for index := range values {
|
||||
values[index] = fmt.Sprintf("%.3f", 3.5+float64(index)/1000)
|
||||
}
|
||||
frame, err := (Encoder{}).DataFrame(CommandReissue, "LTEST32960VIN0002", time.Now(), Record{
|
||||
"2003": "1:" + strings.Join(values, "_"),
|
||||
"2613": "530",
|
||||
"2614": "10",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
body := frame[24 : len(frame)-1]
|
||||
if got := strings.Count(string(body), string([]byte{0x08})); got < 2 {
|
||||
t.Fatalf("expected at least two voltage units, got %d", got)
|
||||
}
|
||||
if binary.BigEndian.Uint16(frame[22:24]) != uint16(len(body)) {
|
||||
t.Fatal("body length mismatch")
|
||||
}
|
||||
if _, err := gb32960.ParseFrame(frame, time.Now().UnixMilli(), "test"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoginFrameLayout(t *testing.T) {
|
||||
frame, err := LoginFrame("FEICHIBRIDGE00001", "bridge", "secret", 7, time.Date(2026, 7, 17, 1, 2, 3, 0, shanghai))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if frame[2] != CommandLogin || frame[3] != 0xFE {
|
||||
t.Fatalf("unexpected login header: %x", frame[:4])
|
||||
}
|
||||
if got := binary.BigEndian.Uint16(frame[30:32]); got != 7 {
|
||||
t.Fatalf("serial = %d", got)
|
||||
}
|
||||
if got, want := frame[len(frame)-1], bcc(frame[2:len(frame)-1]); got != want {
|
||||
t.Fatalf("BCC = %x, want %x", got, want)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user