diff --git a/inc/Helpers/TimeHelper.hpp b/inc/Helpers/TimeHelper.hpp index 8661fff4c05df60a8c43b583bec6a62695f060a7..eae6d844e7cd1b8baa3609dc56eb012db173a245 100644 --- a/inc/Helpers/TimeHelper.hpp +++ b/inc/Helpers/TimeHelper.hpp @@ -2,40 +2,38 @@ #define ECSS_SERVICES_TIMEHELPER_HPP #include <cstdint> +#include <ctime> #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) + * CCSDS 301.0-B-4 standard. The chosen time format is CDS and it is UTC-based(UTC: Coordinated + * Universal Time) + * + * Note: + * Since this code is UTC-based, the leap second correction must be made and leap seconds should + * be considered in the difference between timestamps if a critical time-difference is needed * - * 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 + * Generate the CDS time format(3.3 in CCSDS 301.0-B-4 standard) * - * @details The CUC time format consists of two main fields: the time code preamble field + * @details The CDS 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 + * T-Field. The T-Field is consisted of two segments: 1)the `DAY` and the 2)`ms of + * day` segments. The P-field won't be included in the code, because as the ECSS standards + * claims, it can be just implicitly declared. + * @param timeInfo is the data provided from RTC(Real Time Clock) + * @todo check if we need to define other epoch than the 1 January 1970 * @todo time security for critical time operations + * @todo declare the implicit P-field + * @todo check if we need milliseconds */ - static uint64_t implementCUCTimeFormat(uint32_t seconds); + static uint64_t implementCDSTimeFormat(struct tm* timeInfo); }; #endif //ECSS_SERVICES_TIMEHELPER_HPP diff --git a/inc/Services/TimeManagementService.hpp b/inc/Services/TimeManagementService.hpp index 0b4c727acca1019c9f43767d48b9c6c5706c99ce..d75c377684510eb2c72d55e8badd2a4c3cfc79bf 100644 --- a/inc/Services/TimeManagementService.hpp +++ b/inc/Services/TimeManagementService.hpp @@ -2,14 +2,25 @@ #define ECSS_SERVICES_TIMEMANAGEMENTSERVICE_HPP #include <Service.hpp> -#include <ctime> #include "Helpers/TimeHelper.hpp" /** - * Implementation of the ST[09] time management. The current implementation sends - * a report with the spacecraft time that is formatted according to the CUC time code format - * (check TimeHelper for the format) + * Implementation of the ST[09] time management * + * Notes: + * There is a noticeable difference between setting the time using GPS and setting the time + * using space packets from the ground segment. The GPS module sent the actual time of UTC(123519 + * is 12:35:19 UTC),while space packets,for time configuration,sent the elapsed time units + * (seconds,days depends on the time format) from a specific epoch(1 January 1958 00:00:00). Time + * updates using GPS have nothing to do with this service, but for consistency and simplicity we + * are trying to set the time with a common way independently of the time source. This is also + * the reason that we chose CDS time format(because it is UTC based, check class `TimeHelper`) + * + * About the GPS receiver,we assume that it outputs NMEA(message format) data + * + * @todo check if we need to follow the standard for time-management or we should send the time-data + * like GPS + * @todo check if the final GPS receiver support NMEA protocol * @todo When the time comes for the application processes we should consider this: All reports * generated by the application process that is identified by APID 0 are time reports * @todo Declare the time accuracy that the standard claims in the spacecraft @@ -22,7 +33,10 @@ public: } /** - * TM[9,2] CUC time report + * TM[9,3] CDS time report + * + * This function sends reports with the spacecraft time that is formatted according to the CDS + * time code format(check class `TimeHelper` for the format) * * @todo check if we need spacecraft time reference status * @todo ECSS standard claims: <<The time reports generated by the time reporting subservice @@ -30,19 +44,20 @@ public: * consisting of the service type and message subtype.>> Check if we need to implement that * or should ignore the standard? */ - void cucTimeReport(); + void cdsTimeReport(); /** - * TC[9,128] + * TC[9,128] CDS time request * * This function is a custom subservice(mission specific) with message type 128(as defined * from the standard for custom message types, 5.3.3.1.f) and it parses the data of the - * time-management telecommand packet + * time-management telecommand packet. This data is formatted according to the CDS time code + * format(check class `TimeHelper` for the format) * * @param messageTime The class-member `data` of /p has the data for the time configuration * (a CUC format as described in the documentation of the class TimeHelper) */ - void parseTime(Message &messageTime); + void parseTime(Message &messageTime); }; diff --git a/src/Helpers/TimeHelper.cpp b/src/Helpers/TimeHelper.cpp index 462c7e8b35ea06bfe440f84b7e3e568e2a7891d2..0920fab46c8b6dfdbae557b876a39366291babf9 100644 --- a/src/Helpers/TimeHelper.cpp +++ b/src/Helpers/TimeHelper.cpp @@ -1,42 +1,43 @@ #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 +uint64_t TimeHelper::implementCDSTimeFormat(struct tm* timeInfo) { + /** + * Define the T-field. The total number of octets for the implementation of T-field is 6(2 for + * the `DAY` and 4 for the `ms of day` + */ - // 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); + /** + * Elapsed seconds between a given date from `timeInfo`(UTC time) and epoch 1 January 1970 + * 00:00:00(hours:minutes:seconds) + * + * @todo WARNING: evaluate the mktime() (Is it computer efficient and embedded + * systems-compliant?) + */ + time_t seconds = mktime(timeInfo); - // 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); + /** + * The `DAY` segment, 16 bits as defined from standard. Actually the days passed from an + * Agency-defined epoch,that it will be 1 January 1970(1/1/1970) 00:00:00(hours:minutes:seconds) + * This epoch is configured from the current implementation, using mktime() function + */ + uint16_t elapsedDays = static_cast<uint16_t>(seconds/86400); /** - * 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 + * The `ms of day` segment, 32 bits as defined in standard. The `ms of the day` and DAY` + * should give the time passed from the defined epoch (1/1/1970) */ - uint32_t totalSeconds = seconds; + uint32_t msOfDay = static_cast<uint32_t >((seconds%86400)*1000); /** - * Define time format including P-field and T-Field + * Define CDS time format * * Notes: - * Only the 40 bits of the 64 will be used for the timeFormat(0-7 : P-field, 8-39: T-field) + * Only the 48 bits of the 64 will be used for the timeFormat * * Shift operators have high priority. That's why we should do a type-casting first so we * don't lose valuable bits */ - uint64_t timeFormat = (static_cast<uint64_t>(totalSeconds) << 8 | pField); + uint64_t timeFormat = (static_cast<uint64_t>(elapsedDays) << 32 | msOfDay); return timeFormat; diff --git a/src/Services/TimeManagementService.cpp b/src/Services/TimeManagementService.cpp index 649ffe60e99db8915bf714df373e563b5fe24bca..c23b2356d5f7b953e9410dfaf73f679e9834a575 100644 --- a/src/Services/TimeManagementService.cpp +++ b/src/Services/TimeManagementService.cpp @@ -1,20 +1,21 @@ #include "Services/TimeManagementService.hpp" -void TimeManagementService::cucTimeReport() { - // TM[9,2] CUC time report +void TimeManagementService::cdsTimeReport() { + // TM[9,3] CDS time report - Message timeReport = createTM(2); + Message timeReport = createTM(3); /** * For the time being we will use C++ functions to get a time value, but this will change * when the RTC will be implemented */ - uint32_t seconds; - seconds = time(nullptr); // seconds have passed since 00:00:00 GMT, Jan 1, 1970 - uint64_t timeFormat = TimeHelper::implementCUCTimeFormat(seconds); // store the return value + time_t currTime = time(nullptr); // seconds have passed since 00:00:00 GMT, Jan 1, 1970 + struct tm* timeInfo = gmtime(&currTime); // UTC time - timeReport.appendByte(timeFormat); // append the P-field - timeReport.appendWord(timeFormat >> 8); // append the T-field + uint64_t timeFormat = TimeHelper::implementCDSTimeFormat(timeInfo); // store the return value + + timeReport.appendByte(static_cast<uint8_t >(timeFormat >> 32)); // append the first byte + timeReport.appendWord(static_cast<uint32_t >(timeFormat)); // append the rest bytes(4 bytes) storeMessage(timeReport); } diff --git a/src/main.cpp b/src/main.cpp index bcc262edea6839be3fdee14bebf64daf2f0a1859..ef935aa7a20a88840e3a597ff8a5743414a9f00b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -172,14 +172,9 @@ int main() { errorMessage.appendBits(2, 7); errorMessage.appendByte(15); - - // TimeHelper test - uint64_t test = TimeHelper::implementCUCTimeFormat(1200); - std::cout << "\n" << test << "\n"; - // ST[09] test TimeManagementService timeReport; - timeReport.cucTimeReport(); + timeReport.cdsTimeReport(); // ST[05] (5,5 to 5,8) test [works] EventReportService::Event eventIDs[] = {EventReportService::HighSeverityUnknownEvent,