diff --git a/test/test_comms.cpp b/test/test_comms.cpp new file mode 100644 index 0000000..95321e5 --- /dev/null +++ b/test/test_comms.cpp @@ -0,0 +1,96 @@ +#include "um7/comms.h" +#include "um7/registers.h" +#include "serial/serial.h" +#include +#include + +class FakeSerial : public ::testing::Test { + protected: + /** + * What's going on here? The posix_openpt() call establishes a pseudo terminal + * and gives us a fd for the other end of it. So we can connect up a Serial + * instance to the pty, and have full control over reading-from and writing-to + * the driver. + */ + virtual void SetUp() { + ASSERT_NE(-1, master_fd = posix_openpt( O_RDWR | O_NOCTTY | O_NDELAY )); + ASSERT_NE(-1, grantpt(master_fd)); + ASSERT_NE(-1, unlockpt(master_fd)); + ASSERT_TRUE((ser_name = ptsname(master_fd)) != NULL); + ser.setPort(ser_name); + ser.open(); + ASSERT_TRUE(ser.isOpen()) << "Couldn't open Serial connection to pseudoterminal."; + } + + void write_serial(const std::string& msg) { + write(master_fd, msg.c_str(), msg.length()); + } + + virtual void TearDown() { + ser.close(); + close(master_fd); + } + + serial::Serial ser; + + private: + int master_fd; + char* ser_name; +}; + +TEST_F(FakeSerial, basic_message_rx) { + // Send message from device which should write four bytes to the raw magnetometer's first register. + std::string msg(um7::Comms::message(DREG_MAG_RAW_XY, std::string("\x1\x2\x3\x4"))); + write_serial(msg); + + um7::Comms sensor(&ser); + um7::Registers registers; + ASSERT_EQ(DREG_MAG_RAW_XY, sensor.receive(®isters)) << "Didn't return ID of arriving message."; + EXPECT_EQ(0x0102, registers.mag_raw.get(0)); +} + +TEST_F(FakeSerial, batch_message_rx) { + // Send message from device which should write four bytes to the raw accelerometer's registers. + std::string msg(um7::Comms::message(DREG_ACCEL_RAW_XY, std::string("\x5\x6\x7\x8\x9\xa\0\0", 8))); + write_serial(msg); + + um7::Comms sensor(&ser); + um7::Registers registers; + ASSERT_EQ(DREG_ACCEL_RAW_XY, sensor.receive(®isters)) << "Didn't return ID of arriving message."; + EXPECT_EQ(0x0506, registers.accel_raw.get(0)); + EXPECT_EQ(0x0708, registers.accel_raw.get(1)); + EXPECT_EQ(0x090a, registers.accel_raw.get(2)); +} + +TEST_F(FakeSerial, bad_checksum_message_rx) { + // Generate message, then twiddle final byte. + std::string msg(um7::Comms::message(DREG_MAG_RAW_XY, std::string("\x1\x2\x3\x4"))); + msg[msg.length() - 1]++; + write_serial(msg); + + um7::Comms sensor(&ser); + um7::Registers registers; + EXPECT_EQ(-1, sensor.receive(®isters)) << "Didn't properly ignore bad checksum message."; +} + +TEST_F(FakeSerial, garbage_bytes_preceeding_message_rx) { + // Generate message, then prepend junk. + std::string msg(um7::Comms::message(CONFIG_REG_START_ADDRESS, std::string())); + msg = "ssssssnsnsns" + msg; + write_serial(msg); + + um7::Comms sensor(&ser); + EXPECT_EQ(CONFIG_REG_START_ADDRESS, sensor.receive(NULL)) << "Didn't handle garbage prepended to message."; +} + +TEST_F(FakeSerial, timeout_message_rx) { + std::string msg("snp\x12\x45"); + write_serial(msg); + um7::Comms sensor(&ser); + EXPECT_EQ(-1, sensor.receive(NULL)) << "Didn't properly time out in the face of a partial message."; +} + +int main(int argc, char **argv){ +testing::InitGoogleTest(&argc, argv); +return RUN_ALL_TESTS(); +} diff --git a/test/test_registers.cpp b/test/test_registers.cpp new file mode 100644 index 0000000..bed0a8d --- /dev/null +++ b/test/test_registers.cpp @@ -0,0 +1,92 @@ +#include "um7/registers.h" +#include + +#include + + +TEST(ByteOrder, compare_with_htons) +{ + // Arbitrary, just try a selection of values. + for(uint16_t host_num = 0; host_num < 50000; host_num += 71) { + uint16_t net_num = htons(host_num); + uint16_t memcpy_num = 0; + um7::memcpy_network(&memcpy_num, &host_num, sizeof(host_num)); + EXPECT_EQ(memcpy_num, net_num); + } +} + +TEST(ByteOrder, compare_with_htonl) +{ + for(uint32_t host_num = 0; host_num < 4000000000; host_num += 1299827) { + uint32_t net_num = htonl(host_num); + uint32_t memcpy_num = 0; + um7::memcpy_network(&memcpy_num, &host_num, sizeof(host_num)); + EXPECT_EQ(memcpy_num, net_num); + } +} + +TEST(Accessor, basic_int) +{ + um7::Registers r; + r.write_raw(5, "\x01\x02\x03\x04\x05\x06"); + + um7::Accessor u16(&r, 5, 3); + EXPECT_EQ(0x0102, u16.get(0)); + EXPECT_EQ(0x0304, u16.get(1)); + EXPECT_EQ(0x0506, u16.get(2)); + + um7::Accessor u16n(&r, 6, 1); + EXPECT_EQ(0x0506, u16n.get(0)); + + um7::Accessor u32(&r, 5, 3); + EXPECT_EQ(0x01020304, u32.get(0)); +} + +TEST(Accessor, basic_float) +{ + um7::Registers r; + r.write_raw(10, "\x01\x02\x03\x04\x05\x06\x07\x08"); + + um7::Accessor f(&r, 10, 2); + union { + float val; + uint32_t bytes; + }; + bytes = 0x01020304; + EXPECT_FLOAT_EQ(val, f.get(0)); + bytes = 0x05060708; + EXPECT_FLOAT_EQ(val, f.get(1)); +} + +TEST(Accessor, scaled_int) +{ + um7::Registers r; + r.write_raw(11, "\x01\x02\x03\x04"); + + const float scale(0.001); + um7::Accessor i16(&r, 11, 2, scale); + EXPECT_FLOAT_EQ(scale * 0x0102, i16.get_scaled(0)); + EXPECT_FLOAT_EQ(scale * 0x0304, i16.get_scaled(1)); +} + +TEST(Accessor, set_float) +{ + um7::Registers r; + r.mag_bias.set(0, 0.123); + r.mag_bias.set_scaled(1, 0.987); + r.mag_bias.set_scaled(2, 0.555); + + float check; + um7::memcpy_network(&check, (float*)r.mag_bias.raw(), 4); + EXPECT_FLOAT_EQ(0.123, check); + um7::memcpy_network(&check, (float*)r.mag_bias.raw() + 1, 4); + EXPECT_FLOAT_EQ(0.987, check); + um7::memcpy_network(&check, (float*)r.mag_bias.raw() + 2, 4); + EXPECT_FLOAT_EQ(0.555, check); +} + +int main(int argc, char **argv){ +testing::InitGoogleTest(&argc, argv); +return RUN_ALL_TESTS(); +} +