mirror of https://github.com/periph/devices
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
388 lines
9.8 KiB
Go
388 lines
9.8 KiB
Go
// Copyright 2018 The Periph Authors. All rights reserved.
|
|
// Use of this source code is governed under the Apache License, Version 2.0
|
|
// that can be found in the LICENSE file.
|
|
|
|
package ina219
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
|
|
"periph.io/x/conn/v3/i2c"
|
|
"periph.io/x/conn/v3/i2c/i2ctest"
|
|
"periph.io/x/conn/v3/mmr"
|
|
"periph.io/x/conn/v3/physic"
|
|
)
|
|
|
|
func TestNew(t *testing.T) {
|
|
stringErr := errors.New("use err.Error() error")
|
|
|
|
type fields struct {
|
|
currentLSB physic.ElectricCurrent
|
|
powerLSB physic.Power
|
|
}
|
|
|
|
var tests = []struct {
|
|
name string
|
|
opts Opts
|
|
want fields
|
|
tx []i2ctest.IO
|
|
err error
|
|
errString string
|
|
}{
|
|
{name: "defaults",
|
|
tx: []i2ctest.IO{
|
|
{Addr: 0x40, W: []byte{calibrationRegister, 0x10, 0x62}, R: []byte{}},
|
|
{Addr: 0x40, W: []byte{configRegister, 0x1f, 0xff}, R: []byte{}},
|
|
},
|
|
want: fields{
|
|
currentLSB: 97656 * physic.NanoAmpere,
|
|
powerLSB: 1953125 * physic.NanoWatt,
|
|
},
|
|
},
|
|
{name: "badAddressOption",
|
|
opts: Opts{Address: 0x60},
|
|
err: errAddressOutOfRange,
|
|
},
|
|
{name: "badSenseResistorOption",
|
|
opts: Opts{SenseResistor: -1},
|
|
err: errSenseResistorValueInvalid,
|
|
},
|
|
{name: "badMaxCurrentOption",
|
|
opts: Opts{MaxCurrent: -1},
|
|
err: errMaxCurrentInvalid,
|
|
},
|
|
{name: "setAddress",
|
|
opts: Opts{Address: 0x41},
|
|
tx: []i2ctest.IO{
|
|
{Addr: 0x41, W: []byte{calibrationRegister, 0x10, 0x62}, R: []byte{}},
|
|
{Addr: 0x41, W: []byte{configRegister, 0x1f, 0xff}, R: []byte{}},
|
|
},
|
|
want: fields{
|
|
currentLSB: 97656 * physic.NanoAmpere,
|
|
powerLSB: 1953125 * physic.NanoWatt,
|
|
},
|
|
err: nil,
|
|
},
|
|
{name: "setMaxCurrent",
|
|
opts: Opts{MaxCurrent: 1000 * physic.MilliAmpere},
|
|
tx: []i2ctest.IO{
|
|
{Addr: 0x40, W: []byte{calibrationRegister, 0x34, 0x6e}, R: []byte{}},
|
|
{Addr: 0x40, W: []byte{configRegister, 0x1f, 0xff}, R: []byte{}},
|
|
},
|
|
want: fields{
|
|
currentLSB: 30517 * physic.NanoAmpere,
|
|
powerLSB: 610352 * physic.NanoWatt,
|
|
},
|
|
err: nil,
|
|
},
|
|
{name: "setSenseResistor",
|
|
opts: Opts{SenseResistor: 20 * physic.MilliOhm},
|
|
tx: []i2ctest.IO{
|
|
{Addr: 0x40, W: []byte{calibrationRegister, 0x51, 0xeb}, R: []byte{}},
|
|
{Addr: 0x40, W: []byte{configRegister, 0x1f, 0xff}, R: []byte{}},
|
|
},
|
|
want: fields{
|
|
currentLSB: 97656 * physic.NanoAmpere,
|
|
powerLSB: 1953125 * physic.NanoWatt,
|
|
},
|
|
err: nil,
|
|
},
|
|
{name: "txError",
|
|
tx: []i2ctest.IO{{Addr: 0x40, W: []byte{}, R: []byte{}}},
|
|
want: fields{
|
|
currentLSB: 48828 * physic.NanoAmpere,
|
|
powerLSB: 976560 * physic.NanoWatt,
|
|
},
|
|
err: stringErr,
|
|
errString: "unexpected write",
|
|
},
|
|
{name: "errWritingToConfigRegister",
|
|
tx: []i2ctest.IO{
|
|
{Addr: 0x40, W: []byte{calibrationRegister, 0x10, 0x62}, R: []byte{}},
|
|
{Addr: 0x40, W: []byte{configRegister}, R: []byte{}},
|
|
},
|
|
want: fields{
|
|
currentLSB: 48828 * physic.NanoAmpere,
|
|
powerLSB: 976560 * physic.NanoWatt,
|
|
},
|
|
err: errWritingToConfigRegister,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
|
|
bus := &i2ctest.Playback{
|
|
Ops: test.tx,
|
|
DontPanic: true,
|
|
}
|
|
|
|
ina, err := New(bus, &test.opts)
|
|
|
|
if test.err != nil {
|
|
if err != test.err {
|
|
if test.err == stringErr {
|
|
if !strings.Contains(err.Error(), test.errString) {
|
|
t.Errorf("%v wanted err: %v, but got: %v", test.name, test.errString, err)
|
|
}
|
|
} else {
|
|
t.Errorf("%v wanted err: %v, but got: %v", test.name, test.err, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
if test.err == nil {
|
|
if ina == nil {
|
|
t.Errorf("%v wanted no err but got: %v", test.name, err)
|
|
return
|
|
}
|
|
|
|
var got = fields{
|
|
currentLSB: ina.currentLSB,
|
|
powerLSB: ina.powerLSB,
|
|
}
|
|
if got != test.want {
|
|
t.Errorf("%v wanted: %v, but got: %v", test.name, test.want, got)
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
func TestSense(t *testing.T) {
|
|
stringErr := errors.New("use err.Error() error")
|
|
var tests = []struct {
|
|
name string
|
|
args Opts
|
|
want PowerMonitor
|
|
tx []i2ctest.IO
|
|
err error
|
|
errString string
|
|
}{
|
|
{
|
|
name: "errReadShunt",
|
|
err: errReadShunt,
|
|
args: Opts{},
|
|
tx: []i2ctest.IO{
|
|
{Addr: 0x40, W: []byte{calibrationRegister, 0x10, 0x62}, R: []byte{}},
|
|
{Addr: 0x40, W: []byte{configRegister, 0x1f, 0xff}, R: []byte{}},
|
|
{Addr: 0x40, W: []byte{shuntVoltageRegister}, R: []byte{}},
|
|
},
|
|
},
|
|
{
|
|
name: "errReadBus",
|
|
err: errReadBus,
|
|
args: Opts{},
|
|
tx: []i2ctest.IO{
|
|
{Addr: 0x40, W: []byte{calibrationRegister, 0x10, 0x62}, R: []byte{}},
|
|
{Addr: 0x40, W: []byte{configRegister, 0x1f, 0xff}, R: []byte{}},
|
|
{Addr: 0x40, W: []byte{shuntVoltageRegister}, R: []byte{0x00, 0x00}},
|
|
{Addr: 0x40, W: []byte{busVoltageRegister}, R: []byte{}},
|
|
},
|
|
},
|
|
{
|
|
name: "errReadCurrent",
|
|
err: errReadCurrent,
|
|
args: Opts{},
|
|
tx: []i2ctest.IO{
|
|
{Addr: 0x40, W: []byte{calibrationRegister, 0x10, 0x62}, R: []byte{}},
|
|
{Addr: 0x40, W: []byte{configRegister, 0x1f, 0xff}, R: []byte{}},
|
|
{Addr: 0x40, W: []byte{shuntVoltageRegister}, R: []byte{0x00, 0x00}},
|
|
{Addr: 0x40, W: []byte{busVoltageRegister}, R: []byte{0x00, 0x00}},
|
|
{Addr: 0x40, W: []byte{currentRegister}, R: []byte{}},
|
|
},
|
|
},
|
|
{
|
|
name: "errReadPower",
|
|
err: errReadPower,
|
|
args: Opts{},
|
|
tx: []i2ctest.IO{
|
|
{Addr: 0x40, W: []byte{calibrationRegister, 0x10, 0x62}, R: []byte{}},
|
|
{Addr: 0x40, W: []byte{configRegister, 0x1f, 0xff}, R: []byte{}},
|
|
{Addr: 0x40, W: []byte{shuntVoltageRegister}, R: []byte{0x00, 0x00}},
|
|
{Addr: 0x40, W: []byte{busVoltageRegister}, R: []byte{0x00, 0x00}},
|
|
{Addr: 0x40, W: []byte{currentRegister}, R: []byte{0x00, 0x00}},
|
|
{Addr: 0x40, W: []byte{powerRegister}, R: []byte{}},
|
|
},
|
|
},
|
|
{
|
|
name: "readZero",
|
|
err: nil,
|
|
args: Opts{},
|
|
tx: []i2ctest.IO{
|
|
{Addr: 0x40, W: []byte{calibrationRegister, 0x10, 0x62}, R: []byte{}},
|
|
{Addr: 0x40, W: []byte{configRegister, 0x1f, 0xff}, R: []byte{}},
|
|
{Addr: 0x40, W: []byte{shuntVoltageRegister}, R: []byte{0x00, 0x00}},
|
|
{Addr: 0x40, W: []byte{busVoltageRegister}, R: []byte{0x00, 0x00}},
|
|
{Addr: 0x40, W: []byte{currentRegister}, R: []byte{0x00, 0x00}},
|
|
{Addr: 0x40, W: []byte{powerRegister}, R: []byte{0x00, 0x00}},
|
|
},
|
|
want: PowerMonitor{Shunt: 0, Voltage: 0, Current: 0, Power: 0},
|
|
},
|
|
{
|
|
name: "busVoltageOverflow",
|
|
err: errRegisterOverflow,
|
|
args: Opts{},
|
|
tx: []i2ctest.IO{
|
|
{Addr: 0x40, W: []byte{calibrationRegister, 0x10, 0x62}, R: []byte{}},
|
|
{Addr: 0x40, W: []byte{configRegister, 0x1f, 0xff}, R: []byte{}},
|
|
{Addr: 0x40, W: []byte{shuntVoltageRegister}, R: []byte{0x00, 0x00}},
|
|
{Addr: 0x40, W: []byte{busVoltageRegister}, R: []byte{0x00, 0x01}},
|
|
},
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
bus := &i2ctest.Playback{
|
|
Ops: test.tx,
|
|
DontPanic: true,
|
|
}
|
|
ina, err := New(bus, &Opts{})
|
|
if err != nil {
|
|
t.Fatalf("set setup failure %v", err)
|
|
}
|
|
if ina == nil {
|
|
t.Fatalf("device init failed")
|
|
}
|
|
got, err := ina.Sense()
|
|
if test.err != nil {
|
|
if err != test.err {
|
|
if test.err == stringErr {
|
|
if !strings.Contains(err.Error(), test.errString) {
|
|
t.Errorf("%v wanted err: %v, but got: %v", test.name, test.errString, err)
|
|
}
|
|
} else {
|
|
t.Errorf("%v wanted err: %v, but got: %v", test.name, test.err, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
if test.err == nil {
|
|
if err != nil {
|
|
t.Errorf("%v wanted no err but got: %v", test.name, err)
|
|
return
|
|
}
|
|
|
|
if got != test.want {
|
|
t.Errorf("%v wanted: %v, but got: %v", test.name, test.want, got)
|
|
}
|
|
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCalibrate(t *testing.T) {
|
|
stringErr := errors.New("use err.Error() error")
|
|
|
|
type fields struct {
|
|
sense physic.ElectricResistance
|
|
maxCurrent physic.ElectricCurrent
|
|
currentLSB physic.ElectricCurrent
|
|
powerLSB physic.Power
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
tx []i2ctest.IO
|
|
args fields
|
|
want fields
|
|
err error
|
|
errString string
|
|
}{
|
|
{
|
|
name: "errBadSense",
|
|
err: errSenseResistorValueInvalid,
|
|
},
|
|
{
|
|
name: "errBadMaxCurrent",
|
|
args: fields{
|
|
sense: physic.MilliOhm,
|
|
},
|
|
err: errMaxCurrentInvalid,
|
|
},
|
|
{
|
|
name: "errCalibrationOverflow",
|
|
args: fields{
|
|
sense: physic.MilliOhm,
|
|
maxCurrent: physic.Ampere,
|
|
},
|
|
err: errCalibrationOverflow,
|
|
},
|
|
{
|
|
name: "default",
|
|
args: fields{
|
|
sense: 100 * physic.MilliOhm,
|
|
maxCurrent: 3200 * physic.MilliAmpere,
|
|
},
|
|
want: fields{
|
|
currentLSB: 97656 * physic.NanoAmpere,
|
|
powerLSB: 1953125 * physic.NanoWatt,
|
|
},
|
|
tx: []i2ctest.IO{
|
|
{Addr: 0x40, W: []byte{0x05, 0x10, 0x62}, R: []byte{}},
|
|
},
|
|
err: nil,
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
|
|
bus := i2ctest.Playback{
|
|
Ops: test.tx,
|
|
DontPanic: true,
|
|
}
|
|
|
|
ina := &Dev{
|
|
m: mmr.Dev8{
|
|
Conn: &i2c.Dev{Bus: &bus, Addr: 0x40},
|
|
Order: binary.BigEndian},
|
|
}
|
|
|
|
err := ina.calibrate(test.args.sense, test.args.maxCurrent)
|
|
if test.err != nil {
|
|
if err != test.err {
|
|
if test.err == stringErr {
|
|
if !strings.Contains(err.Error(), test.errString) {
|
|
t.Errorf("%v wanted err: %v, but got: %v", test.name, test.errString, err)
|
|
}
|
|
} else {
|
|
t.Errorf("%v wanted err: %v, but got: %v", test.name, test.err, err)
|
|
}
|
|
}
|
|
}
|
|
if test.err == nil {
|
|
if err != nil {
|
|
t.Errorf("%v wanted no err but got: %v", test.name, err)
|
|
}
|
|
got := fields{
|
|
currentLSB: ina.currentLSB,
|
|
powerLSB: ina.powerLSB,
|
|
}
|
|
if got != test.want {
|
|
t.Errorf("%v wanted: %v, but got: %v", test.name, test.want, got)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPowerStringer(t *testing.T) {
|
|
var p = PowerMonitor{
|
|
Shunt: 1,
|
|
Voltage: 1,
|
|
Current: 1,
|
|
Power: 1,
|
|
}
|
|
want := "Bus: 1nV, Current: 1nA, Power: 1nW, Shunt: 1nV"
|
|
got := p.String()
|
|
if want != got {
|
|
t.Errorf("wanted %s\n, but got: %s", want, got)
|
|
}
|
|
}
|