/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file Utilities for working with raw CHPP packets in a test setting */ #include #include #include #include #include "chpp/crc.h" #include "chpp/transport.h" namespace chpp::test { // Note: the preamble is actually sent in the reverse byte order one might // expect (0x68 'h', 0x43 'C'); the simplification below assumes little endian constexpr uint16_t kPreamble = (CHPP_PREAMBLE_BYTE_SECOND << 8) | CHPP_PREAMBLE_BYTE_FIRST; struct ChppEmptyPacket { uint16_t preamble; ChppTransportHeader header; ChppTransportFooter footer; } CHPP_PACKED_ATTR; struct ChppResetPacket { uint16_t preamble; ChppTransportHeader header; ChppTransportConfiguration config; ChppTransportFooter footer; } CHPP_PACKED_ATTR; struct ChppPacketPrefix { uint16_t preamble; ChppTransportHeader header; uint8_t payload[1]; // Variable size per header.length } CHPP_PACKED_ATTR; // Utilities for packet creation ----------------------------------------------- //! Computes the CRC of one of the complete packet types defined above template uint32_t computeCrc(const PktType &pkt) { return chppCrc32(0, reinterpret_cast(&pkt.header), sizeof(pkt) - sizeof(pkt.preamble) - sizeof(pkt.footer)); } ChppResetPacket generateResetPacket(uint8_t ackSeq = 0, uint8_t seq = 0); ChppResetPacket generateResetAckPacket(uint8_t ackSeq = 1, uint8_t seq = 0); ChppEmptyPacket generateEmptyPacket(uint8_t ackSeq = 1, uint8_t seq = 0, uint8_t error = CHPP_TRANSPORT_ERROR_NONE); //! Create an empty ACK packet for the given packet ChppEmptyPacket generateAck(std::vector &pkt); // Utilities for packet parsing ------------------------------------------------ inline ChppEmptyPacket &asEmptyPacket(std::vector &pkt) { EXPECT_EQ(pkt.size(), sizeof(ChppEmptyPacket)); return *reinterpret_cast(pkt.data()); } inline ChppResetPacket &asResetPacket(std::vector &pkt) { EXPECT_EQ(pkt.size(), sizeof(ChppResetPacket)); return *reinterpret_cast(pkt.data()); } inline ChppPacketPrefix &asChpp(std::vector &pkt) { EXPECT_GE(pkt.size(), sizeof(ChppEmptyPacket)); return *reinterpret_cast(pkt.data()); } inline ChppTransportHeader &getHeader(std::vector &pkt) { static_assert(CHPP_PREAMBLE_LEN_BYTES == sizeof(uint16_t)); EXPECT_GE(pkt.size(), sizeof(uint16_t) + sizeof(ChppTransportHeader)); return *reinterpret_cast(&pkt[sizeof(uint16_t)]); } // Utilities for debugging ----------------------------------------------------- //! Tuned for outputting a raw binary buffer (e.g. payload or full packet) void dumpRaw(std::ostream &os, const void *ptr, size_t len); void dumpPreamble(std::ostream &os, uint16_t preamble); void dumpHeader(std::ostream &os, const ChppTransportHeader &hdr); void dumpConfig(std::ostream &os, const ChppTransportConfiguration &cfg); template void dumpFooter(std::ostream &os, const PktType &pkt) { os << "CRC: 0x" << std::hex << pkt.footer.checksum; uint32_t computed = computeCrc(pkt); if (pkt.footer.checksum != computed) { os << " (invalid, expected " << computed << ")"; } else { os << " (ok)"; } os << std::endl; } void dumpEmptyPacket(std::ostream &os, const ChppEmptyPacket &pkt); void dumpResetPacket(std::ostream &os, const ChppResetPacket &pkt); void dumpPacket(std::ostream &os, const ChppPacketPrefix &pkt); std::ostream &operator<<(std::ostream &os, const ChppEmptyPacket &pkt); std::ostream &operator<<(std::ostream &os, const ChppResetPacket &pkt); std::ostream &operator<<(std::ostream &os, const ChppPacketPrefix &pkt); // Utilities for gtest packet checking ----------------------------------------- //! Confirms that the supplied packet has a valid preamble, CRC, length, etc., //! raising a gtest failure (via EXPECT_*) if not void checkPacketValidity(std::vector &received); // These return true if the packets are the same, false otherwise bool comparePacketHeader(const ChppTransportHeader &rx, const ChppTransportHeader &expected); bool comparePacket(const std::vector &received, const ChppEmptyPacket &expected); bool comparePacket(const std::vector &received, const ChppResetPacket &expected); } // namespace chpp::test