diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2da357dc015d8f927476603fa55ad5935987ae2d..6f35ada2ca5f210505520aab5288777ee3d538d9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,14 +1,14 @@ image: rikorose/gcc-cmake +stages: + - build + - test + before_script: - - apt-get update -qq && apt-get install -y -qq cppcheck vera++ clang-tidy-4.0 - g++ --version - - cppcheck --version - - vera++ --version - - clang-tidy-4.0 --version - - cp ci/vera.profile /usr/lib/vera++/profiles/custom build: + stage: build script: - cmake . -DCMAKE_CXX_FLAGS="-Werror" - make -j4 @@ -16,14 +16,41 @@ build: - cmake . -DCMAKE_CXX_FLAGS="-Wall -Wextra" # Build again, but with more warnings - make -j4 +tests: + stage: test + variables: + GIT_SUBMODULE_STRATEGY: normal + script: + - cmake . + - make tests -j4 + - ./tests --use-colour yes + after_script: + - ./tests -r junit -o junit.xml + artifacts: + reports: + junit: junit.xml + cppcheck: + stage: build + before_script: + - apt-get update -qq && apt-get install -y -qq cppcheck + - cppcheck --version script: - bash -x ci/cppcheck.sh vera: + stage: build + before_script: + - apt-get update -qq && apt-get install -y -qq vera++ + - vera++ --version + - cp ci/vera.profile /usr/lib/vera++/profiles/custom script: - bash -x ci/vera.sh clang-tidy: + stage: build + before_script: + - apt-get update -qq && apt-get install -y -qq clang-tidy-4.0 + - clang-tidy-4.0 --version script: - bash -x ci/clang-tidy.sh diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..d49fb0620ae4893df6f92e7f878d7202c37cf84b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/Catch2"] + path = lib/Catch2 + url = https://github.com/catchorg/Catch2.git diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index efd791e85b4902d773897aeb8ae48aa37dfc243b..5b44ac96da73d9acc2af3bb992aa3611e574d766 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,6 +1,7 @@ <component name="ProjectCodeStyleConfiguration"> <code_scheme name="Project" version="173"> <option name="RIGHT_MARGIN" value="100" /> + <option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" /> <Objective-C-extensions> <file> <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" /> diff --git a/.idea/misc.xml b/.idea/misc.xml index 79b3c94830bab93d40d0770f2765540fe24ed423..91d4361702769bdfe6326464a61298263c79e5e3 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,13 @@ <?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" /> + <component name="CidrRootsConfiguration"> + <sourceRoots> + <file path="$PROJECT_DIR$/inc" /> + <file path="$PROJECT_DIR$/src" /> + </sourceRoots> + <libraryRoots> + <file path="$PROJECT_DIR$/lib" /> + </libraryRoots> + </component> </project> \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7f4cb416c083d265558da75d457237d671..76ade6edd581314bf32ea0f3fd0e76c366ce9100 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,5 +2,6 @@ <project version="4"> <component name="VcsDirectoryMappings"> <mapping directory="$PROJECT_DIR$" vcs="Git" /> + <mapping directory="$PROJECT_DIR$/lib/Catch2" vcs="Git" /> </component> </project> \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 5024e08c5e64ff5389687520541565c70fd16a81..4ee0466937f6439a8ab12dd476a285c05929f32a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,4 +14,14 @@ add_custom_target(check WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/ci") # Specify the .cpp files for the executables -add_executable(ecss_services src/main.cpp src/Message.cpp src/Service.cpp src/Services/TestService.cpp inc/Services/ParameterService.hpp src/Services/ParameterService.cpp) +add_executable(ecss_services src/main.cpp src/Message.cpp src/Service.cpp + src/Services/TestService.cpp src/Services/RequestVerificationService.cpp src/Services/ParameterService.cpp) + +IF (EXISTS "${PROJECT_SOURCE_DIR}/lib/Catch2/CMakeLists.txt") + add_subdirectory(lib/Catch2) + add_executable(tests src/Message.cpp src/Services/TestService.cpp + src/Services/RequestVerificationService.cpp test/tests.cpp + test/Message.cpp test/TestPlatform.cpp test/Services/TestService.cpp + test/Services/RequestVerificationService.cpp) + target_link_libraries(tests Catch2::Catch2) +ENDIF () diff --git a/CMakeLists.txt.orig b/CMakeLists.txt.orig new file mode 100644 index 0000000000000000000000000000000000000000..fde62d5c6eda08ea7719cb6268dc327931d43f79 --- /dev/null +++ b/CMakeLists.txt.orig @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.7) +project(ecss_services) + +# Set C++ version to c++17 +set(CMAKE_CXX_STANDARD 17) + +# Specify the directories for #includes +include_directories("${PROJECT_SOURCE_DIR}/inc") + +add_custom_target(check + COMMAND ./cppcheck.sh + COMMAND ./vera.sh + COMMAND ./clang-tidy.sh + WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/ci") + +# Specify the .cpp files for the executables +<<<<<<< HEAD +add_executable(ecss_services src/main.cpp src/Message.cpp src/Service.cpp src/Services/TestService.cpp inc/Services/ParameterService.hpp src/Services/ParameterService.cpp) +======= +add_executable(ecss_services src/main.cpp src/Message.cpp src/Service.cpp + src/Services/TestService.cpp src/Services/RequestVerificationService.cpp) + +IF (EXISTS "${PROJECT_SOURCE_DIR}/lib/Catch2/CMakeLists.txt") + add_subdirectory(lib/Catch2) + add_executable(tests src/Message.cpp src/Services/TestService.cpp + src/Services/RequestVerificationService.cpp test/tests.cpp + test/Message.cpp test/TestPlatform.cpp test/Services/TestService.cpp + test/Services/RequestVerificationService.cpp) + target_link_libraries(tests Catch2::Catch2) +ENDIF () +>>>>>>> master diff --git a/ci/clang-tidy.sh b/ci/clang-tidy.sh index 8a0c19301fe7e7efc7ff350cd9119e5c4b9c97a5..1e676ce2d6926d700576c3a0fe69bad656c16389 100755 --- a/ci/clang-tidy.sh +++ b/ci/clang-tidy.sh @@ -11,4 +11,4 @@ echo -e "\033[0;34mRunning clang-tidy...\033[0m" cd "$(dirname "$0")" clang-tidy-4.0 `find ../src/ -type f -regextype posix-egrep -regex '.*\.(cpp|hpp|c|h)'` \ - -- -std=c++14 -I../inc + -extra-arg=-fcolor-diagnostics -- -std=c++14 -I../inc diff --git a/ci/cppcheck.sh b/ci/cppcheck.sh index a8335c61296643714ec50b402b322253be41c254..3b8d4cf3f1ee124eaa6787290a505837e7fefbaf 100755 --- a/ci/cppcheck.sh +++ b/ci/cppcheck.sh @@ -10,4 +10,4 @@ echo -e "\033[0;34mRunning cppcheck...\033[0m" cd "$(dirname "$0")/.." -cppcheck --enable=all --error-exitcode=1 -I inc src +cppcheck --enable=all --suppress=unusedFunction --suppress=missingIncludeSystem --error-exitcode=1 -I inc src tests diff --git a/ci/vera.sh b/ci/vera.sh index 9f7d0b6a391c7554bc73fe6b1baab1278e49e868..b758842ff8b395ee548e6389a8f6b08426fbaf87 100755 --- a/ci/vera.sh +++ b/ci/vera.sh @@ -10,4 +10,4 @@ echo -e "\033[0;34mRunning vera++...\033[0m" cd "$(dirname "$0")/.." -vera++ --error --profile custom `find src inc -type f -regextype posix-egrep -regex '.*\.(cpp|hpp|c|h)'` +vera++ --error --profile custom `find src inc tests -type f -regextype posix-egrep -regex '.*\.(cpp|hpp|c|h)'` diff --git a/inc/Message.hpp b/inc/Message.hpp index 268af02f6780a11e17d3a655e3fce29c96589358..28ba738b09ab3babeb2173514da8704d892a5301 100644 --- a/inc/Message.hpp +++ b/inc/Message.hpp @@ -335,6 +335,8 @@ public: * Fetches an 4-byte single-precision floating point number from the current position in the * message * + * @todo Check if endianness matters for this + * * PTC = 5, PFC = 1 */ float readFloat() { @@ -344,6 +346,11 @@ public: uint32_t value = readWord(); return reinterpret_cast<float &>(value); } + + /** + * Reset the message reading status, and start reading data from it again + */ + void resetRead(); }; diff --git a/inc/Services/RequestVerificationService.hpp b/inc/Services/RequestVerificationService.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f1d2bf9210a97e69bd6f2f6e2938bb1bd4ddb7e9 --- /dev/null +++ b/inc/Services/RequestVerificationService.hpp @@ -0,0 +1,98 @@ +#ifndef ECSS_SERVICES_REQUESTVERIFICATIONSERVICE_HPP +#define ECSS_SERVICES_REQUESTVERIFICATIONSERVICE_HPP + +#include "Service.hpp" + +/** + * Implementation of the ST[01] request verification service + * + * @todo All telemetry packets shall have a telemetry packet secondary header + * @todo See if it would be more efficient to use Messages as arguments instead of individual + * parameters + */ +class RequestVerificationService : public Service { +public: + RequestVerificationService() { + serviceType = 1; + } + + /** + * TM[1,1] successful acceptance verification report + * Send report when the Cubesat accepts successfully commands + * + * Note:The parameters are the necessary information, defined from the standard, that the report + * should contain + * + * @param apid Application process ID + * @param seqFlag Sequence flags + * @param packetSeqCount Packet sequence count + */ + void successAcceptanceVerification(Message::PacketType packetType, bool secondaryHeaderFlag, + uint16_t apid, uint8_t seqFlag, uint16_t packetSeqCount); + + /** + * TM[1,2] failed acceptance verification report + *Send report when the Cubesat don't accept commands + * + * Note:The parameters are the necessary information, defined from the standard, that the report + * should contain + * + * @param apid Application process ID + * @param seqFlag Sequence flags + * @param packetSeqCount Packet sequence count + */ + void failAcceptanceVerification(Message::PacketType packetType, bool secondaryHeaderFlag, + uint16_t apid, uint8_t seqFlag, uint16_t packetSeqCount, + uint16_t errorCode); + + + /** + * TM[1,7] successful completion of execution verification report + * Send report when the Cubesat completes an execution + * + * Note:The parameters are the necessary information, defined from the standard, that the report + * should contain + * + * @param apid Application process ID + * @param seqFlag Sequence flags + * @param packetSeqCount Packet sequence count + */ + void successExecutionVerification(Message::PacketType packetType, bool secondaryHeaderFlag, + uint16_t apid, uint8_t seqFlag, uint16_t packetSeqCount); + + /** + * TM[1,8] failed completion of execution verification report + * Send report when the Cubesat don't complete an execution + * + * Note:The parameters are the necessary information, defined from the standard, that the report + * should contain + * + * @param apid Application process ID + * @param seqFlag Sequence flags + * @param packetSeqCount Packet sequence count + */ + void failExecutionVerification(Message::PacketType packetType, + bool secondaryHeaderFlag, + uint16_t apid, uint8_t seqFlag, uint16_t packetSeqCount, + uint16_t errorCode); + + /** + * TM[1,10] failed routing verification report + * Send report when the routing of a request has failed + * + * Note:The parameters are the necessary information, defined from the standard, that the report + * should contain + * + * @param apid Application process ID + * @param seqFlag Sequence flags + * @param packetSeqCount Packet sequence count + */ + void failRoutingVerification(Message::PacketType packetType, + bool secondaryHeaderFlag, + uint16_t apid, uint8_t seqFlag, uint16_t packetSeqCount, + uint16_t errorCode); + + +}; + +#endif //ECSS_SERVICES_REQUESTVERIFICATIONSERVICE_HPP diff --git a/inc/Services/TestService.hpp b/inc/Services/TestService.hpp index 1d367e9563701083e0c10efd9c1c82b3a9c34ae8..a3704aa16a0ca3b7d7a19c9d639983614f5d91fd 100644 --- a/inc/Services/TestService.hpp +++ b/inc/Services/TestService.hpp @@ -15,14 +15,14 @@ public: /** * TC[17,1] perform an are-you-alive connection test */ - void areYouAlive(Message & request); + void areYouAlive(Message &request); /** * TC[17,3] perform an on-board connection test * * @todo Only respond if we have the correct APID */ - void onBoardConnection(Message & request); + void onBoardConnection(Message &request); }; diff --git a/lib/Catch2 b/lib/Catch2 new file mode 160000 index 0000000000000000000000000000000000000000..62460fafe6b54c3173bc5cbc46d05a5f071017ff --- /dev/null +++ b/lib/Catch2 @@ -0,0 +1 @@ +Subproject commit 62460fafe6b54c3173bc5cbc46d05a5f071017ff diff --git a/src/Message.cpp b/src/Message.cpp index d17eb0f5c003792d37fe66975425ae15d4e7a92d..15baf5f217098562171fc6ff63a0705b0e212f7c 100644 --- a/src/Message.cpp +++ b/src/Message.cpp @@ -1,6 +1,5 @@ #include "Message.hpp" #include <cstring> -#include <Message.hpp> Message::Message(uint8_t serviceType, uint8_t messageType, Message::PacketType packetType, @@ -139,3 +138,8 @@ void Message::readString(char *string, uint8_t size) { readPosition += size; } + +void Message::resetRead() { + readPosition = 0; + currentBit = 0; +} diff --git a/src/Service.cpp b/src/Service.cpp index 27a9f4746007488ac3a881c5afda77d88adb581d..07403e438e1ff884b430c5eafff7d92a7d63c63c 100644 --- a/src/Service.cpp +++ b/src/Service.cpp @@ -7,9 +7,10 @@ void Service::storeMessage(const Message &message) { std::cout << "New " << ((message.packetType == Message::TM) ? "TM" : "TC") << "[" << std::dec << static_cast<int>(message.serviceType) << "," << static_cast<int>(message.messageType) << "] message!\n"; - std::cout << std::hex << std::setfill('0') << std::setw(2); + //std::cout << std::hex << std::setfill('0') << std::setw(2); for (int i = 0; i < message.dataSize; i++) { std::cout << static_cast<int>(message.data[i]); + std::cout << " "; } std::cout << std::endl; } diff --git a/src/Services/RequestVerificationService.cpp b/src/Services/RequestVerificationService.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ccacfb591ee31076c14501d29792e5b560c8130a --- /dev/null +++ b/src/Services/RequestVerificationService.cpp @@ -0,0 +1,126 @@ +#include "Services/RequestVerificationService.hpp" +#include "Message.hpp" + +void RequestVerificationService::successAcceptanceVerification(Message::PacketType packetType, + bool secondaryHeaderFlag, + uint16_t apid, uint8_t seqFlag, + uint16_t packetSeqCount) { + // TM[1,1] successful acceptance verification report + + // parameters have max values defined from standard + assert(apid < 2048); + assert(seqFlag < 4); + assert(packetSeqCount < 16384); + + Message report = createTM(1); + + report.appendEnumerated(3, ECSS_PUS_VERSION); // packet version number + report.appendEnumerated(1, packetType); + report.appendBits(1, static_cast<uint8_t >(secondaryHeaderFlag)); + report.appendEnumerated(11, apid); + report.appendEnumerated(2, seqFlag); + report.appendBits(14, packetSeqCount); + + storeMessage(report); +} + +void +RequestVerificationService::failAcceptanceVerification(Message::PacketType packetType, + bool secondaryHeaderFlag, + uint16_t apid, uint8_t seqFlag, + uint16_t packetSeqCount, + uint16_t errorCode) { + // TM[1,2] failed acceptance verification report + + // parameters have max values defined from standard + assert(apid < 2048); + assert(seqFlag < 4); + assert(packetSeqCount < 16384); + + Message report = createTM(2); + + report.appendEnumerated(3, ECSS_PUS_VERSION); // packet version number + report.appendEnumerated(1, packetType); + report.appendBits(1, static_cast<uint8_t >(secondaryHeaderFlag)); + report.appendEnumerated(11, apid); + report.appendEnumerated(2, seqFlag); + report.appendBits(14, packetSeqCount); + report.appendEnum16(errorCode); + + storeMessage(report); +} + +void RequestVerificationService::successExecutionVerification(Message::PacketType packetType, + bool secondaryHeaderFlag, + uint16_t apid, uint8_t seqFlag, + uint16_t packetSeqCount) { + // TM[1,7] successful completion of execution verification report + + // parameters have max values defined from standard + assert(apid < 2048); + assert(seqFlag < 4); + assert(packetSeqCount < 16384); + + Message report = createTM(7); + + report.appendEnumerated(3, ECSS_PUS_VERSION); // packet version number + report.appendEnumerated(1, packetType); + report.appendBits(1, static_cast<uint8_t >(secondaryHeaderFlag)); + report.appendEnumerated(11, apid); + report.appendEnumerated(2, seqFlag); + report.appendBits(14, packetSeqCount); + + storeMessage(report); +} + +void +RequestVerificationService::failExecutionVerification(Message::PacketType packetType, + bool secondaryHeaderFlag, + uint16_t apid, uint8_t seqFlag, + uint16_t packetSeqCount, + uint16_t errorCode) { + // TM[1,8] failed completion of execution verification report + + // parameters have max values defined from standard + assert(apid < 2048); + assert(seqFlag < 4); + assert(packetSeqCount < 16384); + + Message report = createTM(8); + + report.appendEnumerated(3, ECSS_PUS_VERSION); // packet version number + report.appendEnumerated(1, packetType); + report.appendBits(1, static_cast<uint8_t >(secondaryHeaderFlag)); + report.appendEnumerated(11, apid); + report.appendEnumerated(2, seqFlag); + report.appendBits(14, packetSeqCount); + report.appendEnum16(errorCode); + + storeMessage(report); +} + +void +RequestVerificationService::failRoutingVerification(Message::PacketType packetType, + bool secondaryHeaderFlag, + uint16_t apid, uint8_t seqFlag, + uint16_t packetSeqCount, + uint16_t errorCode) { + // TM[1,10] failed routing verification report + + // parameters have max values defined from standard + assert(apid < 2048); + assert(seqFlag < 4); + assert(packetSeqCount < 16384); + + Message report = createTM(10); + + report.appendEnumerated(3, ECSS_PUS_VERSION); // packet version number + report.appendEnumerated(1, packetType); + report.appendBits(1, static_cast<uint8_t >(secondaryHeaderFlag)); + report.appendEnumerated(11, apid); + report.appendEnumerated(2, seqFlag); + report.appendBits(14, packetSeqCount); + report.appendEnum16(errorCode); + + storeMessage(report); +} diff --git a/src/Services/TestService.cpp b/src/Services/TestService.cpp index 06f60263866d9ed9192dc95385e7570b174a1bea..670a8e2fe18cdf1403490b7393d7e7e9030b01d9 100644 --- a/src/Services/TestService.cpp +++ b/src/Services/TestService.cpp @@ -12,6 +12,6 @@ void TestService::onBoardConnection(Message &request) { Message report = createTM(4); report.appendUint16(request.readUint16()); - + // just print it on the screen storeMessage(report); } diff --git a/src/main.cpp b/src/main.cpp index 20b53961763c52f86c0ded09fe8cdc8de8b7fdc4..f11acf2130d3b6891d18b120066b65c905d81e7f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,7 @@ #include <iostream> #include <Services/TestService.hpp> #include "Services/ParameterService.hpp" +#include <Services/RequestVerificationService.hpp> #include "Message.hpp" int main() { @@ -72,5 +73,13 @@ int main() { } +// ST[01] test + // parameters take random values and works as expected + RequestVerificationService reqVerifService; + reqVerifService.successAcceptanceVerification(Message::TC, true, 2, 2, 10); + reqVerifService.failAcceptanceVerification(Message::TC, true, 2, 2, 10, 5); + reqVerifService.successExecutionVerification(Message::TC, true, 2, 2, 10); + reqVerifService.failExecutionVerification(Message::TC, true, 2, 2, 10, 6); + reqVerifService.failRoutingVerification(Message::TC, true, 2, 2, 10, 7); return 0; } diff --git a/src/main.cpp.orig b/src/main.cpp.orig new file mode 100644 index 0000000000000000000000000000000000000000..1fe56064df00e8f7b486bd7ca3da24b0abf41ca8 --- /dev/null +++ b/src/main.cpp.orig @@ -0,0 +1,91 @@ +#include <iostream> +#include <Services/TestService.hpp> +<<<<<<< HEAD +#include "Services/ParameterService.hpp" +======= +#include <Services/RequestVerificationService.hpp> +>>>>>>> master +#include "Message.hpp" + +int main() { + Message packet = Message(0, 0, Message::TC, 1); + + packet.appendString(5, "hello"); + packet.appendBits(15, 0x28a8); + packet.appendBits(1, 1); + packet.appendFloat(5.7); + packet.appendSint32(-123456789); + + std::cout << "Hello, World!" << std::endl; + std::cout << std::hex << packet.data << std::endl; // packet data must be 'helloQQ' + + char string[6]; + packet.readString(string, 5); + std::cout << "Word: " << string << " " << packet.readBits(15) << packet.readBits(1) + << std::endl; + std::cout << packet.readFloat() << " " << std::dec << packet.readSint32() << std::endl; + + // ST[17] test + TestService testService; + Message receivedPacket = Message(17, 1, Message::TC, 1); + testService.areYouAlive(receivedPacket); + receivedPacket = Message(17, 3, Message::TC, 1); + receivedPacket.appendUint16(7); + testService.onBoardConnection(receivedPacket); + +<<<<<<< HEAD + //ST[20] test + ParameterService paramService; + + //Test code for reportParameter + Message sentPacket = Message(20, 1, Message::TC, 1); //application id is a dummy number (1) + sentPacket.appendUint16(2); //number of contained IDs + sentPacket.appendUint16(0); //first ID + sentPacket.appendUint16(1); //second ID + Message returnedPacket = paramService.reportParameterIds(sentPacket); + + uint16_t numOfIds = returnedPacket.readUint16(); + + std::cout << std::endl << "Number of contained configs: " << numOfIds << std::endl; + + for (int i = 0; i < numOfIds; i++) { + + std::cout << "Parameter ID: " << std::dec << returnedPacket.readUint16() << std::endl + << "Parameter value: " << std::dec << returnedPacket.readUint32() << std::endl; + + } + + std::cout << std::endl << "(First value is hours, second is minutes)" << std::endl; + + //Test code for setParameter + Message sentPacket2 = Message(20, 3, Message::TC, 1); //application id is a dummy number (1) + sentPacket2.appendUint16(2); //number of contained IDs + sentPacket2.appendUint16(0); //first parameter ID + sentPacket2.appendUint32(63238); //settings for first parameter + sentPacket2.appendUint16(1); //2nd parameter ID + sentPacket2.appendUint32(45823); //settings for 2nd parameter + + paramService.setParameterIds(sentPacket2); + returnedPacket = paramService.reportParameterIds(sentPacket); + + numOfIds = returnedPacket.readUint16(); + + for (int i = 0; i < numOfIds; i++) { + + std::cout << "Parameter ID: " << std::dec << returnedPacket.readUint16() << std::endl + << "Parameter value: " << std::dec << returnedPacket.readUint32() << std::endl; + + } +======= + // ST[01] test + // parameters take random values and works as expected + RequestVerificationService reqVerifService; + reqVerifService.successAcceptanceVerification(Message::TC, true, 2, 2, 10); + reqVerifService.failAcceptanceVerification(Message::TC, true, 2, 2, 10, 5); + reqVerifService.successExecutionVerification(Message::TC, true, 2, 2, 10); + reqVerifService.failExecutionVerification(Message::TC, true, 2, 2, 10, 6); + reqVerifService.failRoutingVerification(Message::TC, true, 2, 2, 10, 7); +>>>>>>> master + + return 0; +} diff --git a/test/Message.cpp b/test/Message.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a745e04e5c1bdf8cf449996f5bff135fb1312bf --- /dev/null +++ b/test/Message.cpp @@ -0,0 +1,173 @@ +#include <catch2/catch.hpp> +#include <Message.hpp> + +TEST_CASE("Message is usable", "[message]") { + Message message(5, 17, Message::TC, 3); + + REQUIRE(message.serviceType == 5); + 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.appendBoolean(false); + message.appendBoolean(true); + + REQUIRE(message.dataSize == 2); + + CHECK_FALSE(message.readBoolean()); + CHECK(message.readBoolean()); +} + +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.appendUint8(230); + message.appendUint16(15933); + message.appendUint32(2000001); + + REQUIRE(message.dataSize == 1 + 2 + 4); + + CHECK(message.readUint8() == 230); + CHECK(message.readUint16() == 15933); + CHECK(message.readUint32() == 2000001); + + 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] == 0x3e); + CHECK(message.data[2] == 0x3d); + } +} + +TEST_CASE("Requirement 7.3.5 (Signed integer)", "[message][ecss]") { + Message message(0, 0, Message::TC, 0); + + message.appendSint8(-16); + message.appendSint16(-7009); + message.appendSint32(-2000001); + message.appendSint32(15839011); + + REQUIRE(message.dataSize == 1 + 2 + 4 + 4); + + CHECK(message.readSint8() == -16); + CHECK(message.readSint16() == -7009); + CHECK(message.readSint32() == -2000001); + CHECK(message.readSint32() == 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.appendFloat(7.209f); + message.appendFloat(-9003.53135f); + + REQUIRE(message.dataSize == 8); + + CHECK(message.readFloat() == 7.209f); + CHECK(message.readFloat() == -9003.53135f); +} + +TEST_CASE("Requirement 7.3.8 (Octet-string)", "[message][ecss]") { + Message message(0, 0, Message::TC, 0); + + message.appendString(4, "test"); + + REQUIRE(message.dataSize == 4); + + char string[5]; + message.readString(string, 4); + CHECK_THAT(string, Catch::Matchers::Equals("test")); +} + +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); +} diff --git a/test/Services/RequestVerificationService.cpp b/test/Services/RequestVerificationService.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6c9e3c8ccda90deb72c48e62f585f6dd9394a7ba --- /dev/null +++ b/test/Services/RequestVerificationService.cpp @@ -0,0 +1,113 @@ +#include <catch2/catch.hpp> +#include <Services/RequestVerificationService.hpp> +#include <Message.hpp> +#include "ServiceTests.hpp" + +TEST_CASE("TM[1,1]", "[service][st01]") { + RequestVerificationService reqVerifService; + reqVerifService.successAcceptanceVerification(Message::TC, true, 2, 2, 10); + REQUIRE(ServiceTests::hasOneMessage()); + + Message response = ServiceTests::get(0); + // Checks for the data-members of the object response + CHECK(response.serviceType == 1); + CHECK(response.messageType == 1); + CHECK(response.packetType == 0); // packet type(TM = 0, TC = 1) + CHECK(response.applicationId == 0); + REQUIRE(response.dataSize == 4); // dataSize is the number of bytes of data array + // Check for the value that is stored in <<data>> array(data-member of object response) + CHECK(response.readEnumerated(3) == 2); // packet version number + CHECK(response.readEnumerated(1) == 1); // packet type + CHECK(response.readBits(1) == true); // secondary header flag + CHECK(response.readEnumerated(11) == 2); // application process ID + CHECK(response.readEnumerated(2) == 2); // sequence flags + CHECK(response.readBits(14) == 10); // packet sequence count +} + +TEST_CASE("TM[1,2]", "[service][st01]") { + RequestVerificationService reqVerifService; + reqVerifService.failAcceptanceVerification(Message::TC, true, 2, 2, 10, 5); + REQUIRE(ServiceTests::hasOneMessage()); + + Message response = ServiceTests::get(0); + // Checks for the data-members of the object response + CHECK(response.serviceType == 1); + CHECK(response.messageType == 2); + CHECK(response.packetType == 0); // packet type(TM = 0, TC = 1) + CHECK(response.applicationId == 0); + REQUIRE(response.dataSize == 6); // dataSize is the number of bytes of data array + // Check for the value that is stored in <<data>> array(data-member of object response) + CHECK(response.readEnumerated(3) == 2); // packet version number + CHECK(response.readEnumerated(1) == 1); // packet type + CHECK(response.readBits(1) == true); // secondary header flag + CHECK(response.readEnumerated(11) == 2); // application process ID + CHECK(response.readEnumerated(2) == 2); // sequence flags + CHECK(response.readBits(14) == 10); // packet sequence count + CHECK(response.readEnum16() == 5); // error code +} + +TEST_CASE("TM[1,7]", "[service][st01]") { + RequestVerificationService reqVerifService; + reqVerifService.successExecutionVerification(Message::TC, true, 2, 2, 10); + REQUIRE(ServiceTests::hasOneMessage()); + + Message response = ServiceTests::get(0); + // Checks for the data-members of the object response + CHECK(response.serviceType == 1); + CHECK(response.messageType == 7); + CHECK(response.packetType == 0); // packet type(TM = 0, TC = 1) + CHECK(response.applicationId == 0); + REQUIRE(response.dataSize == 4); // dataSize is the number of bytes of data array + // Check for the value that is stored in <<data>> array(data-member of object response) + CHECK(response.readEnumerated(3) == 2); // packet version number + CHECK(response.readEnumerated(1) == 1); // packet type + CHECK(response.readBits(1) == true); // secondary header flag + CHECK(response.readEnumerated(11) == 2); // application process ID + CHECK(response.readEnumerated(2) == 2); // sequence flags + CHECK(response.readBits(14) == 10); // packet sequence count +} + +TEST_CASE("TM[1,8]", "[service][st01]") { + RequestVerificationService reqVerifService; + reqVerifService.failExecutionVerification(Message::TC, true, 2, 2, 10, 6); + REQUIRE(ServiceTests::hasOneMessage()); + + Message response = ServiceTests::get(0); + // Checks for the data-members of the object response + CHECK(response.serviceType == 1); + CHECK(response.messageType == 8); + CHECK(response.packetType == 0); // packet type(TM = 0, TC = 1) + CHECK(response.applicationId == 0); + REQUIRE(response.dataSize == 6); // dataSize is the number of bytes of data array + // Check for the value that is stored in <<data>> array(data-member of object response) + CHECK(response.readEnumerated(3) == 2); // packet version number + CHECK(response.readEnumerated(1) == 1); // packet type + CHECK(response.readBits(1) == true); // secondary header flag + CHECK(response.readEnumerated(11) == 2); // application process ID + CHECK(response.readEnumerated(2) == 2); // sequence flags + CHECK(response.readBits(14) == 10); // packet sequence count + CHECK(response.readEnum16() == 6); // error code +} + +TEST_CASE("TM[1,10]", "[service][st01]") { + RequestVerificationService reqVerifService; + reqVerifService.failRoutingVerification(Message::TC, true, 2, 2, 10, 7); + REQUIRE(ServiceTests::hasOneMessage()); + + Message response = ServiceTests::get(0); + // Checks for the data-members of the object response + CHECK(response.serviceType == 1); + CHECK(response.messageType == 10); + CHECK(response.packetType == 0); // packet type(TM = 0, TC = 1) + CHECK(response.applicationId == 0); + REQUIRE(response.dataSize == 6); // dataSize is the number of bytes of data array + // Check for the value that is stored in <<data>> array(data-member of object response) + CHECK(response.readEnumerated(3) == 2); // packet version number + CHECK(response.readEnumerated(1) == 1); // packet type + CHECK(response.readBits(1) == true); // secondary header flag + CHECK(response.readEnumerated(11) == 2); // application process ID + CHECK(response.readEnumerated(2) == 2); // sequence flags + CHECK(response.readBits(14) == 10); // packet sequence count + CHECK(response.readEnum16() == 7); // error code +} + diff --git a/test/Services/ServiceTests.hpp b/test/Services/ServiceTests.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a160558a0aac56d215ae6af329ce7b690c0b2f4d --- /dev/null +++ b/test/Services/ServiceTests.hpp @@ -0,0 +1,53 @@ +#ifndef ECSS_SERVICES_TESTS_SERVICES_SERVICETESTS_HPP +#define ECSS_SERVICES_TESTS_SERVICES_SERVICETESTS_HPP + +#include <vector> +#include <Message.hpp> + +/** + * Supporting class for tests against ECSS services + * + * @todo See if members of this class can be made non-static + */ +class ServiceTests { + static std::vector<Message> queuedMessages; + +public: + /** + * Get a message from the list of queued messages to send + * @param number The number of the message, starting from 0 in chronological order + */ + static Message &get(uint64_t number) { + return queuedMessages.at(number); + } + + /** + * Add a message to the queue of messages to be sent + */ + static void queue(const Message &message) { + queuedMessages.push_back(message); + } + + /** + * Counts the number of messages in the queue + */ + static uint64_t count() { + return queuedMessages.size(); + } + + /** + * Checks that there is *exactly* one message in the list of queued messages + */ + static bool hasOneMessage() { + return count() == 1; + } + + /** + * Remove all the queued messages from the list, starting over from 0 items again + */ + static void reset() { + queuedMessages.clear(); + } +}; + +#endif //ECSS_SERVICES_TESTS_SERVICES_SERVICETESTS_HPP diff --git a/test/Services/TestService.cpp b/test/Services/TestService.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a94934ad20836620ec2ab1779d4ce0107798d08c --- /dev/null +++ b/test/Services/TestService.cpp @@ -0,0 +1,32 @@ +#include <catch2/catch.hpp> +#include <Services/TestService.hpp> +#include <Message.hpp> +#include "ServiceTests.hpp" + +TEST_CASE("TM[17,1]", "[service][st17]") { + TestService testService; + + Message receivedPacket = Message(17, 1, Message::TC, 1); + testService.areYouAlive(receivedPacket); + REQUIRE(ServiceTests::hasOneMessage()); + + Message response = ServiceTests::get(0); + CHECK(response.serviceType == 17); + CHECK(response.messageType == 2); + REQUIRE(response.dataSize == 0); +} + +TEST_CASE("TM[17,3]", "[service][st17]") { + TestService testService; + + Message receivedPacket = Message(17, 3, Message::TC, 1); + receivedPacket.appendEnum16(40); + testService.onBoardConnection(receivedPacket); + REQUIRE(ServiceTests::hasOneMessage()); + + Message response = ServiceTests::get(0); + CHECK(response.serviceType == 17); + CHECK(response.messageType == 4); + REQUIRE(response.dataSize == 2); + CHECK(response.readEnum16() == 40); +} diff --git a/test/TestPlatform.cpp b/test/TestPlatform.cpp new file mode 100644 index 0000000000000000000000000000000000000000..10f9cdf366fd4950138248a6564b33c7d8dd0a10 --- /dev/null +++ b/test/TestPlatform.cpp @@ -0,0 +1,22 @@ +#define CATCH_CONFIG_EXTERNAL_INTERFACES + +#include <catch2/catch.hpp> +#include <Message.hpp> +#include <Service.hpp> +#include "Services/ServiceTests.hpp" + +std::vector<Message> ServiceTests::queuedMessages = std::vector<Message>(); + +void Service::storeMessage(const Message &message) { + ServiceTests::queue(message); +} + +struct ServiceTestsListener : Catch::TestEventListenerBase { + using TestEventListenerBase::TestEventListenerBase; // inherit constructor + + void testCaseEnded(Catch::TestCaseStats const &testCaseStats) override { + // Tear-down after a test case is run + ServiceTests::reset(); + } +}; +CATCH_REGISTER_LISTENER(ServiceTestsListener) diff --git a/test/tests.cpp b/test/tests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f481b16fe25e9b620f1dcf078a53f4f357d466c5 --- /dev/null +++ b/test/tests.cpp @@ -0,0 +1,3 @@ +#define CATCH_CONFIG_MAIN + +#include <catch2/catch.hpp>