diff --git a/CMakeLists.txt b/CMakeLists.txt index 71a9f50c7e7ae4cccb7cae6072a0baa40e842cd6..986ff8435fefffb9251e461b81048a9a5f54be4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,13 +17,15 @@ add_custom_target(check add_library(common OBJECT src/ErrorHandler.cpp src/Message.cpp - src/MessageParser.cpp + src/MessageParser.cpp src/Helpers/CRCHelper.cpp - src/Services/EventReportService.cpp + src/Services/EventReportService.cpp src/Services/MemoryManagementService.cpp src/Services/ParameterService.cpp src/Services/RequestVerificationService.cpp - src/Services/TestService.cpp) + src/Services/TestService.cpp + src/Helpers/TimeHelper.cpp + ) # Specify the .cpp files for the executables add_executable(ecss_services diff --git a/inc/Helpers/TimeHelper.hpp b/inc/Helpers/TimeHelper.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8661fff4c05df60a8c43b583bec6a62695f060a7 --- /dev/null +++ b/inc/Helpers/TimeHelper.hpp @@ -0,0 +1,41 @@ +#ifndef ECSS_SERVICES_TIMEHELPER_HPP +#define ECSS_SERVICES_TIMEHELPER_HPP + +#include <cstdint> +#include <Message.hpp> + +/** + * This class formats the spacecraft time and cooperates closely with the ST[09] time management. + * The ECSS standard supports two time formats: the CUC and CSD that are described in + * CCSDS 301.0-B-4 standard + * The chosen time format is CUC. The reasons for this selection are the followings: + * 1)It is more flexible from the CSD. The designer is free to decide how much memory will use + * for the time unit and what that time unit will be(seconds, minutes, hours etc.). + * 2)It can use TAI(international atomic time) as reference time scale. So there is no need + * to worry about leap seconds(code UTC-based) + * + * Note: The implementation of the time formats are in general RTC-dependent. First, we need to + * get the time data from the RTC, so we know what time is it and then format it! + */ +class TimeHelper { +public: + /** + * Generate the CUC time format + * + * @details The CUC time format consists of two main fields: the time code preamble field + * (P-field) and the time specification field(T-field). The P-Field is the metadata for the + * T-Field. The T-Field contains the value of the time unit and the designer decides what the + * time unit will be, so this is a subject for discussion. The recommended time unit from the + * standard is the second and it is probably the best solution for accuracy. + * @param seconds the seconds provided from the RTC. This function in general should have + * parameters corresponding with the RTC. For the time being we assume that the RTC has a + * 32-bit counter that counts seconds(the RTC in Nucleo F103RB!) + * @todo check if we need milliseconds(fractions of the time unit) + * @todo the time unit should be declared in the metadata. But how? + * @todo check if we need to define other epoch than the 1 January 1958 + * @todo time security for critical time operations + */ + static uint64_t implementCUCTimeFormat(uint32_t seconds); +}; + +#endif //ECSS_SERVICES_TIMEHELPER_HPP diff --git a/src/Helpers/TimeHelper.cpp b/src/Helpers/TimeHelper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f8e5c158544a1a519daff6b729c40bf5ef3f3276 --- /dev/null +++ b/src/Helpers/TimeHelper.cpp @@ -0,0 +1,39 @@ +#include "Helpers/TimeHelper.hpp" + +uint64_t TimeHelper::implementCUCTimeFormat(uint32_t seconds) { + // the total number of octets including the P-field (1 octet) and T-field(4 octets) is 5 + + // define the P-field + const uint8_t bit0 = 0; // P-field extension(‘zero’: no extension, ‘one’: field is extended) + const uint8_t bits1_3 = 1; // Time code identification ( 001 -> 1958 January 1 epoch ) + const uint8_t bits4_5 = 4 - 1; // Number of octets of the basic time unit minus one + const uint8_t bits6_7 = 0; // Number of octets of the fractional time unit + const uint8_t pField = (bits6_7 << 6 | bits4_5 << 4 | bits1_3 << 1 | bit0); + + // just a reminder to be careful with the assigned values + static_assert(bit0 < 2); + static_assert(bits1_3 < 16); + static_assert(bits4_5 < 4); + static_assert(bits6_7 < 4); + + /** + * Define the T-field, the seconds passed from the defined epoch 1 January 1958 + * We use 4 octets(32 bits) for the time unit(seconds) because 32 bits for the seconds are + * enough to count 136 years! But if we use 24 bits for the seconds then it will count 0,5 + * years and this isn't enough. Remember we can use only integers numbers of octets for the + * time unit(second) + * + * @todo the implementation of the total seconds depends on the structure of the RTC + */ + uint32_t totalSeconds = seconds; + + /** + * Define time format including P-field and T-Field + * + * Note: Only the 40 bits of the 64 will be used for the timeFormat(0-7 : P-field, 8-39: + * T-field) + */ + uint64_t timeFormat = (totalSeconds << 8 | pField); + + return timeFormat; +} diff --git a/src/main.cpp b/src/main.cpp index dfe9fa685bdb23a929d4bd8975f5f8468d40266f..3219196bc212f42548f6049597b28e51651bcbb3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ #include <iostream> #include "Helpers/CRCHelper.hpp" +#include "Helpers/TimeHelper.hpp" #include "Services/TestService.hpp" #include "Services/ParameterService.hpp" #include "Services/RequestVerificationService.hpp" @@ -169,6 +170,11 @@ int main() { errorMessage.appendBits(2, 7); errorMessage.appendByte(15); + + // TimeHelper test + uint64_t test = TimeHelper::implementCUCTimeFormat(1200); + std::cout << "\n" << test; + // ST[05] (5,5 to 5,8) test [works] EventReportService::Event eventIDs[] = {EventReportService::HighSeverityUnknownEvent, EventReportService::MediumSeverityUnknownEvent}; diff --git a/test/Helpers/TimeHelper.cpp b/test/Helpers/TimeHelper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b23a2a05d7bb06a032bbfee1c51f2baa6d2f23d --- /dev/null +++ b/test/Helpers/TimeHelper.cpp @@ -0,0 +1,10 @@ +#include "catch2/catch.hpp" +#include "Helpers/TimeHelper.hpp" + +TEST_CASE("Time format implementation", "[CUC]") { + // very simple tests for the TimeHelper + + CHECK(TimeHelper::implementCUCTimeFormat(60) == 0b11110000110010); + CHECK(TimeHelper::implementCUCTimeFormat(1000) == 0x3E832); + CHECK(TimeHelper::implementCUCTimeFormat(1200) == 0x4B032); +}