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.
devices/ina219/ina219_test.go

394 lines
9.9 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/periph/conn/i2c"
"periph.io/x/periph/conn/i2c/i2ctest"
"periph.io/x/periph/conn/mmr"
"periph.io/x/periph/conn/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")
type fields struct {
currentLSB physic.ElectricCurrent
powerLSB physic.Power
}
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
caibrated bool
}
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)
}
}