#include <Message.hpp> #include <ServicePool.hpp> #include <catch2/catch_all.hpp> #include "Services/EventReportService.hpp" #include "etl/String.hpp" TEST_CASE("Message is usable", "[message]") { Message message(EventReportService::ServiceType, 17, Message::TC, 3); REQUIRE(message.serviceType == EventReportService::ServiceType); REQUIRE(message.messageType == 17); REQUIRE(message.packetType == Message::TC); REQUIRE(message.applicationId == 3); REQUIRE(message.dataSize == 0); message.appendByte(250); REQUIRE(message.dataSize == 1); REQUIRE(message.readByte() == 250); } TEST_CASE("Bit manipulations", "[message]") { Message message(0, 0, Message::TC, 0); message.appendBits(10, 0x357); message.appendBits(4, 0xb); message.appendBits(2, 0); message.appendByte(248); message.appendBits(7, 0x16); message.appendBits(1, 0x1); message.appendBits(8, 0xff); REQUIRE(message.dataSize == 5); CHECK(message.readBits(10) == 0x357); CHECK(message.readBits(4) == 0xb); CHECK(message.readBits(2) == 0); CHECK(message.readBits(5) == 0x1f); CHECK(message.readBits(3) == 0); CHECK(message.readByte() == 0x2d); CHECK(message.readByte() == 0xff); message.resetRead(); CHECK(message.readUint32() == 0xd5ecf82d); CHECK(message.readBits(8) == 0xff); } TEST_CASE("Requirement 5.3.1", "[message][ecss]") { SECTION("5.3.1a") {} SECTION("5.3.1b") { REQUIRE(sizeof(Message::serviceType) == 1); } SECTION("5.3.1c") { // TODO: Unimplemented } SECTION("5.3.1d") { // TODO: Unimplemented } } TEST_CASE("Requirement 7.3.2 (Boolean)", "[message][ecss]") { Message message(0, 0, Message::TC, 0); message.append<bool>(false); message.append<bool>(true); REQUIRE(message.dataSize == 2); CHECK_FALSE(message.read<bool>()); CHECK(message.read<bool>()); } TEST_CASE("Requirement 7.3.3 (Enumerated)", "[message][ecss]") { Message message(0, 0, Message::TC, 0); message.appendEnum8(230); message.appendEnum16(15933); message.appendEnum32(2000001); message.appendEnumerated(12, 2052); message.appendEnumerated(4, 10); REQUIRE(message.dataSize == 1 + 2 + 4 + 2); CHECK(message.readEnum8() == 230); CHECK(message.readEnum16() == 15933); CHECK(message.readEnum32() == 2000001); CHECK(message.readEnumerated(12) == 2052); CHECK(message.readEnumerated(4) == 10); } TEST_CASE("Requirement 7.3.4 (Unsigned integer)", "[message][ecss]") { Message message(0, 0, Message::TC, 0); message.append<char>(110); message.append<uint8_t>(230); message.append<uint16_t>(15933); message.append<uint32_t>(2000001); message.append<uint64_t>(12446744073709551615ULL); REQUIRE(message.dataSize == 1 + 1 + 2 + 4 + 8); CHECK(message.read<char>() == 110); CHECK(message.read<uint8_t>() == 230); CHECK(message.read<uint16_t>() == 15933); CHECK(message.read<uint32_t>() == 2000001); CHECK(message.read<uint64_t>() == 12446744073709551615ULL); SECTION("7.4.3") { /** * Make sure the endianness of the message data is correct. * As per the ECSS standard, stored data should be big-endian. However, ARM and x86 * processors store data in little endian format. As a result, special care needs to be * taken for compliance. */ CHECK(message.data[2] == 0x3e); CHECK(message.data[3] == 0x3d); } } TEST_CASE("Requirement 7.3.5 (Signed integer)", "[message][ecss]") { Message message(0, 0, Message::TC, 0); message.append<int8_t>(-16); message.append<int16_t>(-7009); message.append<int32_t>(-2000001); message.append<int32_t>(15839011); REQUIRE(message.dataSize == 1 + 2 + 4 + 4); CHECK(message.read<int8_t>() == -16); CHECK(message.read<int16_t>() == -7009); CHECK(message.read<int32_t>() == -2000001); CHECK(message.read<int32_t>() == 15839011); SECTION("7.4.3") { // Make sure the endianness of the message data is correct // As per the ECSS standard, stored data should be big-endian. However, ARM and x86 // processors store data in little endian format. As a result, special care needs to be // taken for compliance. CHECK(message.data[1] == 0xe4); CHECK(message.data[2] == 0x9f); } } TEST_CASE("Requirement 7.3.6 (Real)", "[message][ecss]") { Message message(0, 0, Message::TC, 0); message.append<float>(7.209f); message.append<float>(-9003.53135f); REQUIRE(message.dataSize == 8); CHECK(message.read<float>() == 7.209f); CHECK(message.read<float>() == -9003.53135f); } TEST_CASE("Test appending double") { Message message(0, 0, Message::TC, 0); message.append<double>(2.324); REQUIRE(message.dataSize == 8); CHECK(message.read<double>() == Catch::Approx(2.324).epsilon(0.0001)); } TEST_CASE("Test appending offset") { Message message(0, 0, Message::TC, 0); message.append<Time::RelativeTime>(555); REQUIRE(message.dataSize == 8); CHECK(message.read<Time::RelativeTime>() == 555); } TEST_CASE("Test appending a CUC timestamp") { SECTION("Test 1") { auto timeCUC = TimeGetter::getCurrentTimeCustomCUC(); REQUIRE(timeCUC.elapsed100msTicks == 86769000); Message message(0, 0, Message::TC, 0); message.appendCustomCUCTimeStamp(timeCUC); REQUIRE(message.readUint64() == 86769000); } SECTION("Test 2") { Time::CustomCUC_t timeCUC; timeCUC.elapsed100msTicks = 34511; Message message(0, 0, Message::TC, 0); message.appendCustomCUCTimeStamp(timeCUC); REQUIRE(message.readUint64() == 34511); } } TEST_CASE("Test reading a custom CUC timestamp") { /** * Append a custom CUC Time Stamp to a message object and check if is it read corretly */ Time::CustomCUC_t timeCUC; timeCUC.elapsed100msTicks = 34511; Message message(0, 0, Message::TC, 0); message.appendCustomCUCTimeStamp(timeCUC); auto returnTimeCUC = message.readCustomCUCTimeStamp(); REQUIRE(returnTimeCUC.elapsed100msTicks == 34511); } TEST_CASE("Requirement 7.3.8 (Octet-string)", "[message][ecss]") { Message message(0, 0, Message::TC, 0); message.appendString(String<4>("test")); message.append<etl::istring>(String<4>("gaus")); REQUIRE(message.dataSize == 4 + 6); char string[5]; message.readCString(string, 4); CHECK_THAT(string, Catch::Matchers::Equals("test")); auto output = message.readOctetString<10>(); CHECK_THAT(output.c_str(), Catch::Matchers::Equals("gaus")); } TEST_CASE("Requirement 7.3.13 (Packet)", "[message][ecss]") { Message telemetry(0, 0, Message::TM, 0); Message telecommand(0, 0, Message::TC, 0); CHECK(static_cast<int>(telemetry.packetType) == 0); CHECK(static_cast<int>(telecommand.packetType) == 1); } TEST_CASE("Spare field", "[message]") { Message message1(0, 0, Message::TM, 0); message1.appendByte(1); message1.appendHalfword(2); message1.appendBits(1, 1); message1.finalize(); CHECK(message1.data[3] == 0b10000000); CHECK(message1.dataSize == 4); Message message2(0, 0, Message::TM, 0); message2.appendByte(1); message2.appendHalfword(2); message2.appendBits(2, 3); message2.finalize(); CHECK(message2.data[3] == 0b11000000); CHECK(message2.dataSize == 4); Message message3(0, 0, Message::TM, 0); message3.appendByte(1); message3.appendHalfword(2); message3.appendBits(3, 5); message3.finalize(); CHECK(message3.data[3] == 0b10100000); CHECK(message3.dataSize == 4); Message message4(0, 0, Message::TM, 0); message4.appendByte(1); message4.appendHalfword(2); message4.appendBits(4, 5); message4.finalize(); CHECK(message4.data[3] == 0b01010000); CHECK(message4.dataSize == 4); Message message5(0, 0, Message::TM, 0); message5.appendByte(1); message5.appendHalfword(2); message5.appendBits(5, 5); message5.finalize(); CHECK(message5.data[3] == 0b00101000); CHECK(message5.dataSize == 4); Message message6(0, 0, Message::TM, 0); message6.appendByte(1); message6.appendHalfword(2); message6.appendBits(6, 5); message6.finalize(); CHECK(message6.data[3] == 0b00010100); CHECK(message6.dataSize == 4); Message message7(0, 0, Message::TM, 0); message7.appendByte(1); message7.appendHalfword(2); message7.appendBits(7, 5); message7.finalize(); CHECK(message7.data[3] == 0b00001010); CHECK(message7.dataSize == 4); Message message8(0, 0, Message::TM, 0); message8.appendByte(1); message8.appendHalfword(2); message8.appendBits(8, 5); message8.finalize(); CHECK(message8.data[3] == 0b00000101); CHECK(message8.dataSize == 4); Message message9(0, 0, Message::TM, 0); message9.appendByte(1); message9.appendHalfword(2); message9.appendBits(0, 5); message9.finalize(); CHECK(message9.dataSize == 3); } TEST_CASE("Message type counter", "[message]") { SECTION("Message counting") { Message message1(0, 0, Message::TM, 0); message1.finalize(); CHECK(message1.messageTypeCounter == 0); Message message2(0, 0, Message::TM, 0); message2.finalize(); CHECK(message2.messageTypeCounter == 1); } SECTION("Different message types") { Message message1(0, 1, Message::TM, 0); message1.finalize(); CHECK(message1.messageTypeCounter == 0); Message message2(0, 2, Message::TM, 0); message2.finalize(); CHECK(message2.messageTypeCounter == 0); } SECTION("Message counter overflow") { for (int i = 0; i <= 65534; i++) { Message message(0, 3, Message::TM, 0); message.finalize(); } Message message1(0, 3, Message::TM, 0); message1.finalize(); CHECK(message1.messageTypeCounter == 65535); Message message2(0, 3, Message::TM, 0); message2.finalize(); CHECK(message2.messageTypeCounter == 0); } } TEST_CASE("Packet sequence counter", "[message]") { SECTION("Packet counting") { Message message1(0, 0, Message::TM, 0); message1.finalize(); CHECK(message1.packetSequenceCount == 0); Message message2(0, 0, Message::TM, 0); message2.finalize(); CHECK(message2.packetSequenceCount == 1); // Different message type check Message message3(1, 2, Message::TM, 0); message3.finalize(); CHECK(message3.packetSequenceCount == 2); } SECTION("Packet counter overflow") { Services.reset(); for (int i = 0; i <= 16382; i++) { Message message(0, 3, Message::TM, 0); message.finalize(); } Message message1(0, 3, Message::TM, 0); message1.finalize(); CHECK(message1.packetSequenceCount == 16383); Message message2(0, 3, Message::TM, 0); message2.finalize(); CHECK(message2.packetSequenceCount == 0); } }