107 lines
3.4 KiB
Go
107 lines
3.4 KiB
Go
package gb32960
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"testing"
|
|
|
|
"lingniu-vehicle-ingest/go/vehicle-gateway/internal/envelope"
|
|
)
|
|
|
|
func TestExtractFramesKeepsPartialRemainderAndParsesHeader(t *testing.T) {
|
|
first := buildFrame(0x02, 0xfe, "LNBSCB3D4R1234567", []byte{0x1a, 0x06, 0x30, 0x16, 0x23, 0x57})
|
|
second := buildFrame(0x05, 0xfe, "PLATFORM-LOGIN001", nil)
|
|
stream := append([]byte{0x00, 0x01}, first...)
|
|
stream = append(stream, second[:len(second)-3]...)
|
|
|
|
frames, remainder, err := ExtractFrames(stream)
|
|
if err != nil {
|
|
t.Fatalf("ExtractFrames() error = %v", err)
|
|
}
|
|
if len(frames) != 1 {
|
|
t.Fatalf("expected one complete frame, got %d", len(frames))
|
|
}
|
|
if string(remainder) != string(second[:len(second)-3]) {
|
|
t.Fatalf("expected partial second frame as remainder, got %s", hex.EncodeToString(remainder))
|
|
}
|
|
|
|
env, err := ParseFrame(frames[0], 1782745114999, "115.29.187.205:32960")
|
|
if err != nil {
|
|
t.Fatalf("ParseFrame() error = %v", err)
|
|
}
|
|
if env.Protocol != envelope.ProtocolGB32960 || env.MessageID != "0x02" {
|
|
t.Fatalf("unexpected envelope header: %#v", env)
|
|
}
|
|
if env.VIN != "LNBSCB3D4R1234567" {
|
|
t.Fatalf("unexpected vin: %q", env.VIN)
|
|
}
|
|
}
|
|
|
|
func TestParseFrameRejectsBadBCC(t *testing.T) {
|
|
frame := buildFrame(0x02, 0xfe, "LNBSCB3D4R1234567", nil)
|
|
frame[len(frame)-1] ^= 0xff
|
|
|
|
if _, err := ParseFrame(frame, 1782745114999, ""); err == nil {
|
|
t.Fatal("expected bad bcc error")
|
|
}
|
|
}
|
|
|
|
func TestParseFrameExtractsRealtimeVehicleMileageAndPosition(t *testing.T) {
|
|
body := []byte{0x1a, 0x06, 0x30, 0x16, 0x23, 0x57}
|
|
body = append(body, 0x01)
|
|
body = append(body,
|
|
0x01, // vehicle status
|
|
0x03, // charge status
|
|
0x02, // running mode
|
|
0x01, 0x2c, // speed: 30.0km/h
|
|
0x00, 0x01, 0x86, 0xa0, // total mileage: 10000.0km
|
|
0x15, 0xe5, // total voltage: 560.5V
|
|
0x27, 0x10, // total current: 0A after -1000 offset
|
|
85, 0x01, 0x00,
|
|
0x27, 0x10,
|
|
0x00, 0x00)
|
|
body = append(body, 0x05)
|
|
body = append(body,
|
|
0x00,
|
|
0x07, 0x36, 0x50, 0x40, // longitude: 121.000000
|
|
0x01, 0xd2, 0x4f, 0x00) // latitude: 30.560000
|
|
frame := buildFrame(0x02, 0xfe, "LNBSCB3D4R1234567", body)
|
|
|
|
env, err := ParseFrame(frame, 1782745114999, "115.29.187.205:32960")
|
|
if err != nil {
|
|
t.Fatalf("ParseFrame() error = %v", err)
|
|
}
|
|
assertFloatField(t, env, envelope.FieldSpeedKMH, 30.0)
|
|
assertFloatField(t, env, envelope.FieldTotalMileageKM, 10000.0)
|
|
assertFloatField(t, env, envelope.FieldLongitude, 121.0)
|
|
assertFloatField(t, env, envelope.FieldLatitude, 30.56)
|
|
if env.Fields[envelope.FieldSOCPercent] != 85 {
|
|
t.Fatalf("unexpected soc: %#v", env.Fields[envelope.FieldSOCPercent])
|
|
}
|
|
if env.EventTimeMS == 1782745114999 {
|
|
t.Fatal("event time should come from GB32960 device timestamp")
|
|
}
|
|
}
|
|
|
|
func assertFloatField(t *testing.T, env envelope.FrameEnvelope, key string, want float64) {
|
|
t.Helper()
|
|
got, ok := env.Fields[key].(float64)
|
|
if !ok {
|
|
t.Fatalf("field %s missing or not float64: %#v", key, env.Fields[key])
|
|
}
|
|
if got != want {
|
|
t.Fatalf("field %s = %v, want %v", key, got, want)
|
|
}
|
|
}
|
|
|
|
func buildFrame(command byte, response byte, vin string, body []byte) []byte {
|
|
frame := []byte{'#', '#', command, response}
|
|
vinBytes := []byte(vin)
|
|
if len(vinBytes) < 17 {
|
|
vinBytes = append(vinBytes, make([]byte, 17-len(vinBytes))...)
|
|
}
|
|
frame = append(frame, vinBytes[:17]...)
|
|
frame = append(frame, 0x01, byte(len(body)>>8), byte(len(body)))
|
|
frame = append(frame, body...)
|
|
return append(frame, bcc(frame[2:]))
|
|
}
|