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:
@@ -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 {
|
} else {
|
||||||
tmp.scale = math.Abs(float64(scl))
|
tmp.supported = true
|
||||||
|
var scl int16
|
||||||
|
var ofs int16
|
||||||
|
if len(frame) == 6 {
|
||||||
|
scl = int16(frame[2])<<8 + int16(frame[1])
|
||||||
|
ofs = int16(uint16(frame[4])<<8 + uint16(frame[3]))
|
||||||
|
} else {
|
||||||
|
scl = int16(frame[2])<<8 + int16(frame[1])
|
||||||
|
ofs = int16(uint16(frame[5])<<8 + uint16(frame[4]))
|
||||||
|
}
|
||||||
|
if scl < 0 {
|
||||||
|
tmp.signed = true
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
tmp.supported = true
|
|
||||||
scl := uint16(frame[2])<<8 + uint16(frame[1])
|
|
||||||
ofs := int16(uint16(frame[5])<<8 + uint16(frame[4]))
|
|
||||||
|
|
||||||
tmp.offset = float64(ofs)
|
tmp.offset = float64(ofs)
|
||||||
if scl >= 0x4000 {
|
scale := int16Abs(scl)
|
||||||
tmp.scale = math.Abs(1 / (0x8000 - float64(scl)))
|
if scale >= 0x4000 {
|
||||||
|
tmp.scale = 1 / (0x8000 - float64(scale))
|
||||||
} else {
|
} else {
|
||||||
tmp.scale = math.Abs(float64(scl))
|
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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user