implement some features of Venus OS
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -463,6 +463,110 @@ func Test_mk2Ser_WriteRAMVarByID(t *testing.T) {
|
||||
assert.Equal(t, expected, writeBuffer.Bytes())
|
||||
}
|
||||
|
||||
func Test_mk2Ser_RegisterMetadata(t *testing.T) {
|
||||
m := &mk2Ser{}
|
||||
|
||||
meta, ok := m.RegisterMetadata(RegisterKindRAMVar, ramVarVBat)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, RegisterKindRAMVar, meta.Kind)
|
||||
assert.Equal(t, uint16(ramVarVBat), meta.ID)
|
||||
assert.Equal(t, "battery_voltage", meta.Name)
|
||||
assert.False(t, meta.Writable)
|
||||
|
||||
_, ok = m.RegisterMetadata(RegisterKindSetting, 9999)
|
||||
assert.False(t, ok)
|
||||
|
||||
all := m.ListRegisterMetadata()
|
||||
assert.NotEmpty(t, all)
|
||||
}
|
||||
|
||||
func Test_mk2Ser_WriteRegister_Verified(t *testing.T) {
|
||||
testIO := NewIOStub(nil)
|
||||
m := &mk2Ser{
|
||||
p: testIO,
|
||||
writeAck: make(chan byte, 2),
|
||||
winmonAck: make(chan winmonResponse, 4),
|
||||
}
|
||||
|
||||
go func() {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
// Read-before-write response.
|
||||
m.pushWinmonResponse(commandReadSettingResponse, []byte{0x01, 0x00})
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
// Write acknowledgement.
|
||||
m.pushWriteResponse(commandWriteViaIDResponse)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
// Verify-after-write response.
|
||||
m.pushWinmonResponse(commandReadSettingResponse, []byte{0x34, 0x12})
|
||||
}()
|
||||
|
||||
result, err := m.WriteRegister(RegisterKindSetting, 0x0042, 0x1234, TransactionOptions{
|
||||
ReadBeforeWrite: true,
|
||||
VerifyAfterWrite: true,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, result.Attempts)
|
||||
if assert.NotNil(t, result.PreviousValue) {
|
||||
assert.Equal(t, int16(1), *result.PreviousValue)
|
||||
}
|
||||
if assert.NotNil(t, result.VerifiedValue) {
|
||||
assert.Equal(t, int16(0x1234), *result.VerifiedValue)
|
||||
}
|
||||
|
||||
expected := append([]byte{}, buildSentCommand(winmonFrame, commandReadSetting, 0x42, 0x00)...)
|
||||
expected = append(expected, buildSentCommand(winmonFrame, commandWriteViaID, 0x42, 0x00, 0x34, 0x12)...)
|
||||
expected = append(expected, buildSentCommand(winmonFrame, commandReadSetting, 0x42, 0x00)...)
|
||||
assert.Equal(t, expected, writeBuffer.Bytes())
|
||||
}
|
||||
|
||||
func Test_mk2Ser_WriteRegister_VerifyRetry(t *testing.T) {
|
||||
testIO := NewIOStub(nil)
|
||||
m := &mk2Ser{
|
||||
p: testIO,
|
||||
writeAck: make(chan byte, 4),
|
||||
winmonAck: make(chan winmonResponse, 8),
|
||||
}
|
||||
|
||||
go func() {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
m.pushWriteResponse(commandWriteViaIDResponse)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
// First verify mismatch.
|
||||
m.pushWinmonResponse(commandReadSettingResponse, []byte{0x00, 0x00})
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
m.pushWriteResponse(commandWriteViaIDResponse)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
// Second verify matches expected value.
|
||||
m.pushWinmonResponse(commandReadSettingResponse, []byte{0x78, 0x56})
|
||||
}()
|
||||
|
||||
result, err := m.WriteRegister(RegisterKindSetting, 0x0042, 0x5678, TransactionOptions{
|
||||
Retries: 1,
|
||||
RetryDelay: 1 * time.Millisecond,
|
||||
VerifyAfterWrite: true,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, result.Attempts)
|
||||
if assert.NotNil(t, result.VerifiedValue) {
|
||||
assert.Equal(t, int16(0x5678), *result.VerifiedValue)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_mk2Ser_WriteRegister_ReadOnlyMetadata(t *testing.T) {
|
||||
testIO := NewIOStub(nil)
|
||||
m := &mk2Ser{
|
||||
p: testIO,
|
||||
writeAck: make(chan byte, 1),
|
||||
}
|
||||
|
||||
_, err := m.WriteRegister(RegisterKindRAMVar, ramVarVBat, 1, TransactionOptions{
|
||||
VerifyAfterWrite: true,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.ErrorContains(t, err, "read-only")
|
||||
assert.Empty(t, writeBuffer.Bytes())
|
||||
}
|
||||
|
||||
func Test_mk2Ser_GetDeviceState(t *testing.T) {
|
||||
testIO := NewIOStub(nil)
|
||||
m := &mk2Ser{
|
||||
@@ -726,6 +830,149 @@ func Test_mk2Ser_SetStandby_Disabled(t *testing.T) {
|
||||
assert.Equal(t, expected, writeBuffer.Bytes())
|
||||
}
|
||||
|
||||
func Test_mk2Ser_WriteSettingBySelection(t *testing.T) {
|
||||
testIO := NewIOStub(nil)
|
||||
m := &mk2Ser{
|
||||
p: testIO,
|
||||
writeAck: make(chan byte, 1),
|
||||
}
|
||||
|
||||
go func() {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
m.pushWriteResponse(commandWriteSettingResponse)
|
||||
}()
|
||||
|
||||
err := m.WriteSettingBySelection(0x0020, 0x0011)
|
||||
assert.NoError(t, err)
|
||||
|
||||
expected := append([]byte{}, buildSentCommand(winmonFrame, commandWriteSetting, 0x20, 0x00)...)
|
||||
expected = append(expected, buildSentCommand(winmonFrame, commandWriteData, 0x11, 0x00)...)
|
||||
assert.Equal(t, expected, writeBuffer.Bytes())
|
||||
}
|
||||
|
||||
func Test_mk2Ser_WriteSelectedData(t *testing.T) {
|
||||
testIO := NewIOStub(nil)
|
||||
m := &mk2Ser{
|
||||
p: testIO,
|
||||
writeAck: make(chan byte, 1),
|
||||
}
|
||||
|
||||
go func() {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
m.pushWriteResponse(commandWriteRAMResponse)
|
||||
}()
|
||||
|
||||
err := m.WriteSelectedData(0x0022)
|
||||
assert.NoError(t, err)
|
||||
|
||||
expected := buildSentCommand(winmonFrame, commandWriteData, 0x22, 0x00)
|
||||
assert.Equal(t, expected, writeBuffer.Bytes())
|
||||
}
|
||||
|
||||
func Test_mk2Ser_CaptureAndDiffSnapshot(t *testing.T) {
|
||||
testIO := NewIOStub(nil)
|
||||
m := &mk2Ser{
|
||||
p: testIO,
|
||||
winmonAck: make(chan winmonResponse, 2),
|
||||
}
|
||||
|
||||
go func() {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
m.pushWinmonResponse(commandReadRAMResponse, []byte{0x03, 0x00})
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
m.pushWinmonResponse(commandReadRAMResponse, []byte{0x04, 0x00})
|
||||
}()
|
||||
|
||||
addresses := []RegisterAddress{
|
||||
{Kind: RegisterKindRAMVar, ID: ramVarVirSwitchPos},
|
||||
}
|
||||
snapshot, err := m.CaptureSnapshot(addresses)
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, snapshot.Entries, 1) {
|
||||
assert.Equal(t, RegisterSafetyGuarded, snapshot.Entries[0].Safety)
|
||||
assert.Equal(t, int16(3), snapshot.Entries[0].Value)
|
||||
}
|
||||
|
||||
diffs, err := m.DiffSnapshot(snapshot)
|
||||
assert.NoError(t, err)
|
||||
if assert.Len(t, diffs, 1) {
|
||||
assert.True(t, diffs[0].Changed)
|
||||
assert.Equal(t, int16(4), diffs[0].Current)
|
||||
assert.Equal(t, int16(3), diffs[0].Target)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_mk2Ser_RestoreSnapshot(t *testing.T) {
|
||||
testIO := NewIOStub(nil)
|
||||
m := &mk2Ser{
|
||||
p: testIO,
|
||||
winmonAck: make(chan winmonResponse, 4),
|
||||
writeAck: make(chan byte, 2),
|
||||
}
|
||||
|
||||
go func() {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
// DiffSnapshot current value.
|
||||
m.pushWinmonResponse(commandReadRAMResponse, []byte{0x04, 0x00})
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
// WriteRegister read-before-write.
|
||||
m.pushWinmonResponse(commandReadRAMResponse, []byte{0x04, 0x00})
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
// Write ack.
|
||||
m.pushWriteResponse(commandWriteRAMViaIDResponse)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
// Verify-after-write.
|
||||
m.pushWinmonResponse(commandReadRAMResponse, []byte{0x03, 0x00})
|
||||
}()
|
||||
|
||||
result, err := m.RestoreSnapshot(RegisterSnapshot{
|
||||
Entries: []RegisterSnapshotEntry{
|
||||
{
|
||||
Kind: RegisterKindRAMVar,
|
||||
ID: ramVarVirSwitchPos,
|
||||
Value: 3,
|
||||
Writable: true,
|
||||
},
|
||||
},
|
||||
}, TransactionOptions{
|
||||
ReadBeforeWrite: true,
|
||||
VerifyAfterWrite: true,
|
||||
RetryDelay: 1 * time.Millisecond,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, result.RolledBack)
|
||||
if assert.Len(t, result.Applied, 1) {
|
||||
if assert.NotNil(t, result.Applied[0].PreviousValue) {
|
||||
assert.Equal(t, int16(4), *result.Applied[0].PreviousValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_mk2Ser_DriverDiagnostics(t *testing.T) {
|
||||
m := &mk2Ser{
|
||||
traceLimit: 10,
|
||||
traces: make([]ProtocolTrace, 0, 10),
|
||||
}
|
||||
m.appendTrace(ProtocolTrace{
|
||||
Timestamp: time.Now().UTC(),
|
||||
Direction: TraceDirectionTX,
|
||||
Frame: "0x57",
|
||||
Command: "winmon:0x30",
|
||||
BytesHex: "AA",
|
||||
})
|
||||
m.noteCommandFailure(assert.AnError)
|
||||
m.noteCommandTimeout(assert.AnError)
|
||||
m.checksumErrors.Add(1)
|
||||
m.markFrameSeen()
|
||||
|
||||
diag := m.DriverDiagnostics(10)
|
||||
assert.NotEmpty(t, diag.Traces)
|
||||
assert.Greater(t, diag.CommandFailures, uint64(0))
|
||||
assert.Greater(t, diag.CommandTimeouts, uint64(0))
|
||||
assert.Greater(t, diag.ChecksumFailures, uint64(0))
|
||||
assert.GreaterOrEqual(t, diag.HealthScore, 0)
|
||||
}
|
||||
|
||||
func Test_parseFrameLength(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
Reference in New Issue
Block a user