Fix scaling to more closely match the Victron documentation.

We were decoding the scale as unsigned while it is signed. We were also
ignoring the fact that the sign of the scale determines the signedness of
the value it scales.
This commit is contained in:
Hendrik van Wyk
2020-09-25 15:03:26 +02:00
parent c991503e33
commit 86f3f0c8e3

View File

@@ -4,7 +4,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"math"
"sync" "sync"
"time" "time"
@@ -14,6 +13,7 @@ import (
type scaling struct { type scaling struct {
scale float64 scale float64
offset float64 offset float64
signed bool
supported bool supported bool
} }
@@ -233,6 +233,13 @@ func (m *mk2Ser) reqScaleFactor(in byte) {
m.sendCommand(cmd) m.sendCommand(cmd)
} }
func int16Abs(in int16) uint16 {
if in < 0 {
return uint16(-in)
}
return uint16(in)
}
// Decode the scale factor frame. // Decode the scale factor frame.
func (m *mk2Ser) scaleDecode(frame []byte) { func (m *mk2Ser) scaleDecode(frame []byte) {
tmp := scaling{} tmp := scaling{}
@@ -240,27 +247,26 @@ func (m *mk2Ser) scaleDecode(frame []byte) {
if len(frame) < 6 { if len(frame) < 6 {
tmp.supported = false tmp.supported = false
logrus.Warnf("Skiping scaling factors for: %d", m.scaleCount) logrus.Warnf("Skiping scaling factors for: %d", m.scaleCount)
} else if len(frame) == 6 {
tmp.supported = true
scl := uint16(frame[2])<<8 + uint16(frame[1])
ofs := int16(uint16(frame[4])<<8 + uint16(frame[3]))
tmp.offset = float64(ofs)
if scl >= 0x4000 {
tmp.scale = math.Abs(1 / (0x8000 - float64(scl)))
} else {
tmp.scale = math.Abs(float64(scl))
}
} else { } else {
tmp.supported = true tmp.supported = true
scl := uint16(frame[2])<<8 + uint16(frame[1]) var scl int16
ofs := int16(uint16(frame[5])<<8 + uint16(frame[4])) var ofs int16
if len(frame) == 6 {
tmp.offset = float64(ofs) scl = int16(frame[2])<<8 + int16(frame[1])
if scl >= 0x4000 { ofs = int16(uint16(frame[4])<<8 + uint16(frame[3]))
tmp.scale = math.Abs(1 / (0x8000 - float64(scl)))
} else { } else {
tmp.scale = math.Abs(float64(scl)) scl = int16(frame[2])<<8 + int16(frame[1])
ofs = int16(uint16(frame[5])<<8 + uint16(frame[4]))
}
if scl < 0 {
tmp.signed = true
}
tmp.offset = float64(ofs)
scale := int16Abs(scl)
if scale >= 0x4000 {
tmp.scale = 1 / (0x8000 - float64(scale))
} else {
tmp.scale = float64(scale)
} }
} }
m.scales = append(m.scales, tmp) m.scales = append(m.scales, tmp)
@@ -292,6 +298,20 @@ func (m *mk2Ser) versionDecode(frame []byte) {
} }
} }
// Decode with correct signedness and apply scale
func (m *mk2Ser) applyScaleAndSign(data []byte, scale int) float64 {
var value float64
if !m.scales[scale].supported {
return 0
}
if m.scales[scale].signed {
value = getSigned(data)
} else {
value = getUnsigned16(data)
}
return m.applyScale(value, scale)
}
// Apply scaling to float // Apply scaling to float
func (m *mk2Ser) applyScale(value float64, scale int) float64 { func (m *mk2Ser) applyScale(value float64, scale int) float64 {
if !m.scales[scale].supported { if !m.scales[scale].supported {
@@ -305,6 +325,11 @@ func getSigned(data []byte) float64 {
return float64(int16(data[0]) + int16(data[1])<<8) return float64(int16(data[0]) + int16(data[1])<<8)
} }
// Convert bytes->int16->float
func getUnsigned16(data []byte) float64 {
return float64(uint16(data[0]) + uint16(data[1])<<8)
}
// Convert bytes->uint32->float // Convert bytes->uint32->float
func getUnsigned(data []byte) float64 { func getUnsigned(data []byte) float64 {
return float64(uint32(data[0]) + uint32(data[1])<<8 + uint32(data[2])<<16) return float64(uint32(data[0]) + uint32(data[1])<<8 + uint32(data[2])<<16)
@@ -312,7 +337,7 @@ func getUnsigned(data []byte) float64 {
// Decodes DC frame. // Decodes DC frame.
func (m *mk2Ser) dcDecode(frame []byte) { func (m *mk2Ser) dcDecode(frame []byte) {
m.info.BatVoltage = m.applyScale(getSigned(frame[5:7]), ramVarVBat) m.info.BatVoltage = m.applyScaleAndSign(frame[5:7], ramVarVBat)
usedC := m.applyScale(getUnsigned(frame[7:10]), ramVarIBat) usedC := m.applyScale(getUnsigned(frame[7:10]), ramVarIBat)
chargeC := m.applyScale(getUnsigned(frame[10:13]), ramVarIBat) chargeC := m.applyScale(getUnsigned(frame[10:13]), ramVarIBat)
@@ -329,10 +354,10 @@ func (m *mk2Ser) dcDecode(frame []byte) {
// Decodes AC frame. // Decodes AC frame.
func (m *mk2Ser) acDecode(frame []byte) { func (m *mk2Ser) acDecode(frame []byte) {
m.info.InVoltage = m.applyScale(getSigned(frame[5:7]), ramVarVMains) m.info.InVoltage = m.applyScaleAndSign(frame[5:7], ramVarVMains)
m.info.InCurrent = m.applyScale(getSigned(frame[7:9]), ramVarIMains) m.info.InCurrent = m.applyScaleAndSign(frame[7:9], ramVarIMains)
m.info.OutVoltage = m.applyScale(getSigned(frame[9:11]), ramVarVInverter) m.info.OutVoltage = m.applyScaleAndSign(frame[9:11], ramVarVInverter)
m.info.OutCurrent = m.applyScale(getSigned(frame[11:13]), ramVarIInverter) m.info.OutCurrent = m.applyScaleAndSign(frame[11:13], ramVarIInverter)
if frame[13] == 0xff { if frame[13] == 0xff {
m.info.InFrequency = 0 m.info.InFrequency = 0
@@ -348,7 +373,7 @@ func (m *mk2Ser) acDecode(frame []byte) {
// Decode charge state of battery. // Decode charge state of battery.
func (m *mk2Ser) stateDecode(frame []byte) { func (m *mk2Ser) stateDecode(frame []byte) {
m.info.ChargeState = m.applyScale(getSigned(frame[1:3]), ramVarChargeState) m.info.ChargeState = m.applyScaleAndSign(frame[1:3], ramVarChargeState)
m.updateReport() m.updateReport()
} }