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.
191 lines
4.2 KiB
Go
191 lines
4.2 KiB
Go
// Copyright 2024 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 am2320
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"periph.io/x/conn/v3/i2c"
|
|
"periph.io/x/conn/v3/i2c/i2creg"
|
|
"periph.io/x/conn/v3/i2c/i2ctest"
|
|
"periph.io/x/conn/v3/physic"
|
|
"periph.io/x/host/v3"
|
|
)
|
|
|
|
var bus i2c.Bus
|
|
var liveDevice bool
|
|
|
|
// Playback values for a single sense operation.
|
|
var pbSense = []i2ctest.IO{
|
|
{Addr: SensorAddress, W: []uint8{0x0}},
|
|
{Addr: SensorAddress, W: []uint8{0x3, 0x0, 0x4}, R: []uint8{0x3, 0x4, 0x1, 0x5c, 0x0, 0xef, 0x71, 0x8a}}}
|
|
|
|
func init() {
|
|
var err error
|
|
|
|
liveDevice = os.Getenv("AM2320") != ""
|
|
|
|
// Make sure periph is initialized.
|
|
if _, err = host.Init(); err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
|
|
if liveDevice {
|
|
bus, err = i2creg.Open("")
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
// Add the recorder to dump the data stream when we're using a live device.
|
|
bus = &i2ctest.Record{Bus: bus}
|
|
} else {
|
|
bus = &i2ctest.Playback{DontPanic: true}
|
|
}
|
|
|
|
}
|
|
|
|
// getDev returns a configured device using either an i2c bus, or a playback bus.
|
|
func getDev(t *testing.T, playbackOps ...[]i2ctest.IO) (*Dev, error) {
|
|
if liveDevice {
|
|
if recorder, ok := bus.(*i2ctest.Record); ok {
|
|
// Clear the operations buffer.
|
|
recorder.Ops = make([]i2ctest.IO, 0, 32)
|
|
}
|
|
} else {
|
|
if len(playbackOps) == 1 {
|
|
pb := bus.(*i2ctest.Playback)
|
|
pb.Ops = playbackOps[0]
|
|
pb.Count = 0
|
|
}
|
|
}
|
|
dev, err := NewI2C(bus, SensorAddress)
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
return dev, err
|
|
}
|
|
|
|
// shutdown dumps the recorder values if we we're running a live device.
|
|
func shutdown(t *testing.T) {
|
|
if recorder, ok := bus.(*i2ctest.Record); ok {
|
|
t.Logf("%#v", recorder.Ops)
|
|
}
|
|
}
|
|
|
|
func TestBasic(t *testing.T) {
|
|
dev := Dev{}
|
|
env := &physic.Env{}
|
|
dev.Precision(env)
|
|
if env.Pressure != 0 {
|
|
t.Error("this device doesn't measure pressure")
|
|
}
|
|
if 10*env.Temperature != physic.Celsius {
|
|
t.Error("incorrect temperature precision value")
|
|
}
|
|
if env.Humidity != physic.MilliRH {
|
|
t.Error("incorrect humidity precision")
|
|
}
|
|
|
|
s := dev.String()
|
|
if len(s) == 0 {
|
|
t.Error("invalid value for String()")
|
|
}
|
|
|
|
// Check the CRC Calculation algorithm using the data supplied by the vendor.
|
|
crcTest := []byte{0x03, 0x04, 0x01, 0xf4, 0x00, 0xfa, 0x31, 0xa5}
|
|
if !checkCRC(crcTest) {
|
|
t.Error("crc error")
|
|
}
|
|
// ensure a corruption is detected.
|
|
crcTest[0] = crcTest[0] ^ 0xff
|
|
if checkCRC(crcTest) {
|
|
t.Error("crc error")
|
|
}
|
|
}
|
|
|
|
func TestSense(t *testing.T) {
|
|
d, err := getDev(t, pbSense)
|
|
if err != nil {
|
|
t.Fatalf("failed to initialize am2320: %v", err)
|
|
}
|
|
defer shutdown(t)
|
|
|
|
// Read temperature and humidity from the sensor
|
|
e := physic.Env{}
|
|
|
|
if err := d.Sense(&e); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Logf("%8s %9s", e.Temperature, e.Humidity)
|
|
|
|
if !liveDevice {
|
|
// The playback temp is 23.9C Ensure that's what we got.
|
|
expected := physic.ZeroCelsius + 23_900*physic.MilliKelvin
|
|
if e.Temperature != expected {
|
|
t.Errorf("incorrect temperature value read. Expected: %s (%d) Found: %s (%d)",
|
|
e.Temperature.String(),
|
|
e.Temperature,
|
|
expected.String(),
|
|
expected)
|
|
}
|
|
|
|
// 34.8% expected.
|
|
expectedRH := 34*physic.PercentRH + 8*physic.MilliRH
|
|
if e.Humidity != expectedRH {
|
|
t.Errorf("incorrect humidity value read. Expected: %s (%d) Found: %s (%d)",
|
|
e.Humidity.String(),
|
|
e.Humidity,
|
|
expectedRH.String(),
|
|
expectedRH)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSenseContinuous(t *testing.T) {
|
|
readCount := 10
|
|
|
|
// make 10 copies of the single reading playback data.
|
|
pb := make([]i2ctest.IO, 0, len(pbSense)*10)
|
|
for range readCount {
|
|
pb = append(pb, pbSense...)
|
|
}
|
|
|
|
d, err := getDev(t, pb)
|
|
if err != nil {
|
|
t.Fatalf("failed to initialize am2320: %v", err)
|
|
}
|
|
defer shutdown(t)
|
|
|
|
_, err = d.SenseContinuous(time.Second)
|
|
if err == nil {
|
|
t.Error("SenseContinuous() accepted invalid reading interval")
|
|
}
|
|
ch, err := d.SenseContinuous(3 * time.Second)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
go func() {
|
|
time.Sleep(3 * time.Duration(readCount) * time.Second)
|
|
err := d.Halt()
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}()
|
|
|
|
count := 0
|
|
for e := range ch {
|
|
count += 1
|
|
t.Log(time.Now(), e)
|
|
}
|
|
if count < (readCount-1) || count > (readCount+1) {
|
|
t.Errorf("expected %d readings. received %d", readCount, count)
|
|
}
|
|
}
|