From c373640940d52bfb7bcdcb5147036de0bc752059 Mon Sep 17 00:00:00 2001 From: Balazs Racz Date: Thu, 16 Dec 2021 13:00:12 +0100 Subject: [PATCH 1/4] Adds POM commands to the dcc debug print routine. --- src/dcc/DccDebug.cxx | 51 +++++++++++++++++++++++++++++++++++++++- src/dcc/DccDebug.cxxtest | 32 +++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/dcc/DccDebug.cxx b/src/dcc/DccDebug.cxx index e0b1ccbc0..8854dce42 100644 --- a/src/dcc/DccDebug.cxx +++ b/src/dcc/DccDebug.cxx @@ -229,7 +229,56 @@ string packet_to_string(const DCCPacket &pkt, bool bin_payload) else if (cmd == 0 && is_idle_packet) { } - + else if ((cmd >> 4) == 0b1110) + { + // POM command + options += " POM CV"; + unsigned kk = (cmd >> 2) & 3; + unsigned cv = (cmd & 3) << 8; + cv |= pkt.payload[ofs]; + ofs++; + options += StringPrintf("%d", cv + 1); + uint8_t d = pkt.payload[ofs++]; + + switch (kk) + { + case 0b00: + { + options += " resvd %d"; + break; + } + case 0b01: + { + options += StringPrintf(" read/verify %d", d); + break; + } + case 0b11: + { + options += StringPrintf(" write = %d", d); + break; + } + case 0b10: + { + unsigned bit = d & 7; + unsigned value = (d >> 3) & 1; + if ((d & 0xE0) != 0xE0) + { + options += StringPrintf(" bit manipulate unknown (%02x)", d); + break; + } + if ((d & 0x10) == 0x10) + { + options += StringPrintf(" bit %d write = %d", bit, value); + } + else + { + options += StringPrintf(" bit %d verify ?= %d", bit, value); + } + break; + } + } + } + // checksum of packet if (ofs == pkt.dlc && pkt.packet_header.skip_ec == 0) { diff --git a/src/dcc/DccDebug.cxxtest b/src/dcc/DccDebug.cxxtest index a1e09ac9d..cab803ac1 100644 --- a/src/dcc/DccDebug.cxxtest +++ b/src/dcc/DccDebug.cxxtest @@ -125,6 +125,38 @@ TEST(DccDebug, F21_28) EXPECT_EQ("[dcc] Short Address 3 F[21-28]=01101001", packet_to_string(pkt)); } +TEST(DccDebug, POMWrite) +{ + Packet pkt; + pkt.add_dcc_address(DccShortAddress(3)); + pkt.add_dcc_pom_write1(13, 67); + EXPECT_EQ( + "[dcc] Short Address 3 POM CV14 write = 67", packet_to_string(pkt)); +} + +TEST(DccDebug, POMWriteHighCV) +{ + Packet pkt; + pkt.add_dcc_address(DccShortAddress(3)); + pkt.add_dcc_pom_write1(950, 255); + EXPECT_EQ( + "[dcc] Short Address 3 POM CV951 write = 255", packet_to_string(pkt)); + pkt.clear(); + pkt.add_dcc_address(DccShortAddress(3)); + pkt.add_dcc_pom_write1(1023, 0); + EXPECT_EQ( + "[dcc] Short Address 3 POM CV1024 write = 0", packet_to_string(pkt)); +} + +TEST(DccDebug, POMRead) +{ + Packet pkt; + pkt.add_dcc_address(DccShortAddress(3)); + pkt.add_dcc_pom_read1(13); + EXPECT_EQ( + "[dcc] Short Address 3 POM CV14 read/verify 0", packet_to_string(pkt)); +} + TEST(DccDebug, Accy) { Packet pkt; From 68d5beea752b2efd0448888cb71715dfd09136b2 Mon Sep 17 00:00:00 2001 From: Balazs Racz Date: Fri, 17 Dec 2021 10:54:29 +0100 Subject: [PATCH 2/4] fix mixed up printf --- src/dcc/DccDebug.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dcc/DccDebug.cxx b/src/dcc/DccDebug.cxx index 8854dce42..22f09f7c3 100644 --- a/src/dcc/DccDebug.cxx +++ b/src/dcc/DccDebug.cxx @@ -244,7 +244,7 @@ string packet_to_string(const DCCPacket &pkt, bool bin_payload) { case 0b00: { - options += " resvd %d"; + options += StringPrintf(" resvd %02x", d); break; } case 0b01: From 85eedd681e9fc21b75ef58bafba652f326d59a93 Mon Sep 17 00:00:00 2001 From: Balazs Racz Date: Fri, 17 Dec 2021 11:55:05 +0100 Subject: [PATCH 3/4] Fixes the PacketIs expectation used in unit tests. The matcher will now fix when the skip_ec bit is differently set in the expectation and in the actual value by computing the correct EC byte. Previously the expectation would silently fail in this case. --- src/dcc/dcc_test_utils.hxx | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/dcc/dcc_test_utils.hxx b/src/dcc/dcc_test_utils.hxx index c1e683140..59969b6ad 100644 --- a/src/dcc/dcc_test_utils.hxx +++ b/src/dcc/dcc_test_utils.hxx @@ -63,10 +63,42 @@ dcc::Packet packet_from(uint8_t hdr, std::vector payload) return pkt; } -MATCHER_P2(PacketIs, hdr, payload, - std::string(" is a packet of ") + PrintToString(packet_from(hdr, payload))) +MATCHER_P2(PacketIs, hdr, payload, PrintToString(packet_from(hdr, payload))) { dcc::Packet pkt = packet_from(hdr, payload); + dcc::Packet argc = arg; + vector exp_bytes(pkt.payload, pkt.payload + pkt.dlc); + vector act_bytes(arg.payload, arg.payload + arg.dlc); + if (pkt.packet_header.is_pkt == 0 && pkt.packet_header.is_marklin == 0 && + arg.packet_header.is_pkt == 0 && arg.packet_header.is_marklin == 0 && + pkt.packet_header.skip_ec != arg.packet_header.skip_ec) + { + // Mismatch in whether the EC byte is there. We fix this by adding the + // EC byte to the place where it is missing. This avoids test failures + // where the packets really are equivalent. + if (pkt.packet_header.skip_ec == 0) + { + uint8_t ec = 0; + for (uint8_t b : exp_bytes) + { + ec ^= b; + } + exp_bytes.push_back(ec); + pkt.packet_header.skip_ec = 1; + } + if (arg.packet_header.skip_ec == 0) + { + uint8_t ec = 0; + for (uint8_t b : act_bytes) + { + ec ^= b; + } + act_bytes.push_back(ec); + argc.packet_header.skip_ec = 1; + } + return (pkt.header_raw_data == argc.header_raw_data && + exp_bytes == act_bytes); + } return (pkt.header_raw_data == arg.header_raw_data && pkt.dlc == arg.dlc && memcmp(pkt.payload, arg.payload, pkt.dlc) == 0); } From 0bc07a048d93bf4d4b97d537534fbbc3467f3fae Mon Sep 17 00:00:00 2001 From: Balazs Racz Date: Fri, 17 Dec 2021 11:59:15 +0100 Subject: [PATCH 4/4] Adds helper macro expect_packet_and_send_response. This allows building simpler test scripts where the script can automatically react to packets sent by the code under test. Previously the script had to have separate steps. --- src/utils/async_if_test_helper.hxx | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/utils/async_if_test_helper.hxx b/src/utils/async_if_test_helper.hxx index f2af652f9..ea6e5cd11 100644 --- a/src/utils/async_if_test_helper.hxx +++ b/src/utils/async_if_test_helper.hxx @@ -158,6 +158,26 @@ protected: #define expect_packet(gc_packet) \ EXPECT_CALL(canBus_, mwrite(StrCaseEq(gc_packet))) +/** Adds an expectation that the code will send a packet to the CANbus. Upon + * receiving that packet, sends a packet to CAN-bus. This is helpful when the + * test script is simulating a node connected to the CAN-bus and that remote + * node has to respond with an ack to the packet emitted by the code under + * test. + + Example: + expect_packet_and_send_response(":X1A555444N0102030405060708;", + ":X19A28555N044400;"); + + @param gc_packet the packet that the code under test should emit, in + GridConnect format, including the leading : and trailing ; + @param resp_packet the packet that will be sent to the code under test + after seeing the emitted packet. +*/ +#define expect_packet_and_send_response(gc_packet, resp_packet) \ + EXPECT_CALL(canBus_, mwrite(StrCaseEq(gc_packet))) \ + .WillOnce(::testing::InvokeWithoutArgs( \ + [this]() { send_packet(resp_packet); })) + /** Ignores all produced packets. * * Tihs can be used in tests where the expectations are tested in a higher