bugfixes and improvements
All checks were successful
EIVE/eive-obsw/pipeline/pr-develop This commit looks good

- Tests finished
This commit is contained in:
Robin Müller 2022-04-08 11:22:16 +02:00
parent 45007d726d
commit 4a6840f098
No known key found for this signature in database
GPG Key ID: 71B58F8A3CDFA9AC
12 changed files with 144 additions and 118 deletions

View File

@ -1,6 +1,9 @@
#include "CoreController.h"
#include <fsfw/events/EventManager.h>
#include <fsfw/ipc/QueueFactory.h>
#include <algorithm>
#include "OBSWConfig.h"
#include "OBSWVersion.h"
@ -8,7 +11,6 @@
#include "fsfw/timemanager/Stopwatch.h"
#include "fsfw/version.h"
#include "watchdogConf.h"
#include <algorithm>
#if OBSW_USE_TMTC_TCP_BRIDGE == 0
#include "fsfw/osal/common/UdpTmTcBridge.h"
#else
@ -22,6 +24,7 @@
#include "bsp_q7s/memory/SdCardManager.h"
#include "bsp_q7s/memory/scratchApi.h"
#include "bsp_q7s/xadc/Xadc.h"
#include "linux/utility/utility.h"
xsc::Chip CoreController::CURRENT_CHIP = xsc::Chip::NO_CHIP;
xsc::Copy CoreController::CURRENT_COPY = xsc::Copy::NO_COPY;
@ -51,6 +54,7 @@ CoreController::CoreController(object_id_t objectId)
} catch (const std::filesystem::filesystem_error &e) {
sif::error << "CoreController::CoreController: Failed with exception " << e.what() << std::endl;
}
eventQueue = QueueFactory::instance()->createMessageQueue(5, EventMessage::MAX_MESSAGE_SIZE);
}
ReturnValue_t CoreController::handleCommandMessage(CommandMessage *message) {
@ -62,7 +66,7 @@ void CoreController::performControlOperation() {
for (ReturnValue_t result = eventQueue->receiveMessage(&event); result == RETURN_OK;
result = eventQueue->receiveMessage(&event)) {
switch (event.getEvent()) {
case(GpsHyperion::GPS_FIX_CHANGE): {
case (GpsHyperion::GPS_FIX_CHANGE): {
gpsFix = static_cast<GpsHyperion::FixMode>(event.getParameter2());
break;
}
@ -90,8 +94,10 @@ LocalPoolDataSetBase *CoreController::getDataSetHandle(sid_t sid) {
}
ReturnValue_t CoreController::initialize() {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
ReturnValue_t result = ExtendedControllerBase::initialize();
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "CoreController::initialize: Base init failed" << std::endl;
}
result = scratch::writeNumber(scratch::ALLOC_FAILURE_COUNT, 0);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "CoreController::initialize: Setting up alloc failure "
@ -102,18 +108,23 @@ ReturnValue_t CoreController::initialize() {
sdStateMachine();
triggerEvent(REBOOT_SW, CURRENT_CHIP, CURRENT_COPY);
EventManagerIF* eventManager = ObjectManager::instance()->get<EventManagerIF>(
objects::EVENT_MANAGER);
EventManagerIF *eventManager =
ObjectManager::instance()->get<EventManagerIF>(objects::EVENT_MANAGER);
if (eventManager == nullptr or eventQueue == nullptr) {
sif::warning << "CoreController::initialize: No valid event manager found or "
"queue invalid"
<< std::endl;
}
result = eventManager->registerListener(eventQueue->getId());
if(result != HasReturnvaluesIF::RETURN_OK) {
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "CoreController::initialize: Registering as event listener failed" << std::endl;
}
result = eventManager->subscribeToEvent(this->getCommandQueue(),
result = eventManager->subscribeToEvent(eventQueue->getId(),
event::getEventId(GpsHyperion::GPS_FIX_CHANGE));
if(result != HasReturnvaluesIF::RETURN_OK) {
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "Subscribing for GPS GPS_FIX_CHANGE event failed" << std::endl;
}
return ExtendedControllerBase::initialize();
return RETURN_OK;
}
ReturnValue_t CoreController::initializeAfterTaskCreation() {
@ -661,8 +672,7 @@ ReturnValue_t CoreController::initVersionFile() {
fsfw::FSFW_VERSION.getVersion(versionString, sizeof(versionString));
std::string fullFsfwVersionString = "FSFW: v" + std::string(versionString);
std::string systemString = "System: " + unameLine;
std::string mountPrefix = SdCardManager::instance()->getCurrentMountPrefix();
std::string versionFilePath = mountPrefix + VERSION_FILE;
std::string versionFilePath = currMntPrefix + VERSION_FILE;
std::fstream versionFile;
if (not std::filesystem::exists(versionFilePath)) {
@ -1220,15 +1230,17 @@ void CoreController::performWatchdogControlOperation() {
}
void CoreController::performMountedSdCardOperations() {
currMntPrefix = sdcMan->getCurrentMountPrefix();
if (doPerformMountedSdCardOps) {
bool sdCardMounted = false;
sdCardMounted = sdcMan->isSdCardMounted(sdInfo.pref);
if (sdCardMounted) {
std::string path = sdcMan->getCurrentMountPrefix(sdInfo.pref) + "/" + CONF_FOLDER;
std::string path = currMntPrefix + "/" + CONF_FOLDER;
if (not std::filesystem::exists(path)) {
std::filesystem::create_directory(path);
}
initVersionFile();
initClockFromTimeFile();
performRebootFileHandling(false);
doPerformMountedSdCardOps = false;
}
@ -1238,7 +1250,7 @@ void CoreController::performMountedSdCardOperations() {
void CoreController::performRebootFileHandling(bool recreateFile) {
using namespace std;
std::string path = sdcMan->getCurrentMountPrefix(sdInfo.pref) + REBOOT_FILE;
std::string path = currMntPrefix + REBOOT_FILE;
if (not std::filesystem::exists(path) or recreateFile) {
#if OBSW_VERBOSE_LEVEL >= 1
sif::info << "CoreController::performRebootFileHandling: Recreating reboot file" << std::endl;
@ -1617,7 +1629,7 @@ bool CoreController::parseRebootFile(std::string path, RebootFile &rf) {
}
void CoreController::resetRebootCount(xsc::Chip tgtChip, xsc::Copy tgtCopy) {
std::string path = sdcMan->getCurrentMountPrefix(sdInfo.pref) + REBOOT_FILE;
std::string path = currMntPrefix + REBOOT_FILE;
// Disable the reboot file mechanism
parseRebootFile(path, rebootFile);
if (tgtChip == xsc::ALL_CHIP and tgtCopy == xsc::ALL_COPY) {
@ -1644,7 +1656,7 @@ void CoreController::resetRebootCount(xsc::Chip tgtChip, xsc::Copy tgtCopy) {
}
void CoreController::rewriteRebootFile(RebootFile file) {
std::string path = sdcMan->getCurrentMountPrefix(sdInfo.pref) + REBOOT_FILE;
std::string path = currMntPrefix + REBOOT_FILE;
std::ofstream rebootFile(path);
if (rebootFile.is_open()) {
// Initiate reboot file first. Reboot handling will be on on initialization
@ -1681,15 +1693,15 @@ void CoreController::setRebootMechanismLock(bool lock, xsc::Chip tgtChip, xsc::C
}
ReturnValue_t CoreController::timeFileHandler() {
if(gpsFix == GpsHyperion::FixMode::FIX_2D or gpsFix == GpsHyperion::FixMode::FIX_3D) {
if (gpsFix == GpsHyperion::FixMode::FIX_2D or gpsFix == GpsHyperion::FixMode::FIX_3D) {
// It is assumed that the system time is set from the GPS time
timeval currentTime = {};
ReturnValue_t result = Clock::getClock_timeval(&currentTime);
if(result != HasReturnvaluesIF::RETURN_OK) {
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
std::ofstream timeFile(TIME_FILE);
timeFile << "UNIX SECONDS: " << currentTime.tv_sec;
std::ofstream timeFile(currMntPrefix + TIME_FILE);
timeFile << "UNIX SECONDS: " << currentTime.tv_sec << std::endl;
}
return RETURN_OK;
}
@ -1697,30 +1709,30 @@ ReturnValue_t CoreController::timeFileHandler() {
ReturnValue_t CoreController::initClockFromTimeFile() {
using namespace GpsHyperion;
using namespace std;
if ((gpsFix == FixMode::UNKNOWN or gpsFix == FixMode::NOT_SEEN) and
std::filesystem::exists(TIME_FILE)) {
ifstream timeFile(TIME_FILE);
std::string fileName = currMntPrefix + TIME_FILE;
if (std::filesystem::exists(fileName) and
((gpsFix == FixMode::UNKNOWN or gpsFix == FixMode::NOT_SEEN) or
not utility::timeSanityCheck())) {
ifstream timeFile(fileName);
string nextWord;
getline(timeFile, nextWord);
istringstream iss(nextWord);
iss >> nextWord;
if(iss.bad() or nextWord != "UNIX") {
if (iss.bad() or nextWord != "UNIX") {
return RETURN_FAILED;
}
iss >> nextWord;
if(iss.bad() or nextWord != "SECONDS:") {
if (iss.bad() or nextWord != "SECONDS:") {
return RETURN_FAILED;
}
iss >> nextWord;
timeval currentTime = {};
char* checkPtr;
char *checkPtr;
currentTime.tv_sec = strtol(nextWord.c_str(), &checkPtr, 10);
if(iss.bad() or *checkPtr) {
if (iss.bad() or *checkPtr) {
return RETURN_FAILED;
}
Clock::setClock(&currentTime);
return RETURN_OK;
return Clock::setClock(&currentTime);
}
return RETURN_OK;
}
@ -1759,8 +1771,7 @@ void CoreController::readHkData() {
}
}
bool CoreController::isNumber(const std::string& s)
{
return !s.empty() && std::find_if(s.begin(),
s.end(), [](unsigned char c) { return !std::isdigit(c); }) == s.end();
bool CoreController::isNumber(const std::string &s) {
return !s.empty() && std::find_if(s.begin(), s.end(),
[](unsigned char c) { return !std::isdigit(c); }) == s.end();
}

View File

@ -7,10 +7,10 @@
#include <cstddef>
#include "CoreDefinitions.h"
#include "mission/devices/devicedefinitions/GPSDefinitions.h"
#include "bsp_q7s/memory/SdCardManager.h"
#include "events/subsystemIdRanges.h"
#include "fsfw/controller/ExtendedControllerBase.h"
#include "mission/devices/devicedefinitions/GPSDefinitions.h"
class Timer;
class SdCardManager;
@ -59,8 +59,7 @@ class CoreController : public ExtendedControllerBase {
"/" + std::string(CONF_FOLDER) + "/" + std::string(VERSION_FILE_NAME);
const std::string REBOOT_FILE =
"/" + std::string(CONF_FOLDER) + "/" + std::string(REBOOT_FILE_NAME);
const std::string TIME_FILE =
"/" + std::string(CONF_FOLDER) + "/" + std::string(TIME_FILE_NAME);
const std::string TIME_FILE = "/" + std::string(CONF_FOLDER) + "/" + std::string(TIME_FILE_NAME);
static constexpr ActionId_t LIST_DIRECTORY_INTO_FILE = 0;
static constexpr ActionId_t SWITCH_REBOOT_FILE_HANDLING = 5;
@ -179,6 +178,7 @@ class CoreController : public ExtendedControllerBase {
sd::SdState commandedState = sd::SdState::OFF;
} sdInfo;
RebootFile rebootFile = {};
std::string currMntPrefix;
bool doPerformMountedSdCardOps = true;
/**

View File

@ -1,7 +1,7 @@
/**
* @brief Auto-generated event translation file. Contains 183 translations.
* @details
* Generated on: 2022-04-07 17:27:42
* Generated on: 2022-04-08 11:21:58
*/
#include "translateEvents.h"

View File

@ -2,7 +2,7 @@
* @brief Auto-generated object translation file.
* @details
* Contains 117 translations.
* Generated on: 2022-04-07 17:27:42
* Generated on: 2022-04-08 11:21:58
*/
#include "translateObjects.h"

View File

@ -3,7 +3,7 @@
#include "OBSWConfig.h"
#include "fsfw/datapool/PoolReadGuard.h"
#include "fsfw/timemanager/Clock.h"
#include "linux/utility/utility.h"
#include "mission/utility/compileTime.h"
#if FSFW_DEV_HYPERION_GPS_CREATE_NMEA_CSV == 1
@ -127,9 +127,14 @@ void GPSHyperionLinuxController::readGpsDataFromGpsd() {
return;
}
bool validFix = false;
static_cast<void>(validFix);
// 0: Not seen, 1: No fix, 2: 2D-Fix, 3: 3D-Fix
int newFixMode = gps->fix.mode;
if(gpsSet.fixMode.value != newFixMode) {
if (newFixMode == 2 or newFixMode == 3) {
validFix = true;
}
if (gpsSet.fixMode.value != newFixMode) {
triggerEvent(GpsHyperion::GPS_FIX_CHANGE, gpsSet.fixMode.value, newFixMode);
}
gpsSet.fixMode.value = newFixMode;
@ -185,11 +190,19 @@ void GPSHyperionLinuxController::readGpsDataFromGpsd() {
} else {
timeIsConstantCounter = 0;
}
if (timeInit) {
if (not utility::timeSanityCheck()) {
sif::info << "Setting init clock in gps ctrl" << std::endl;
// For some reason, the clock needs to be somewhat correct for NTP to work. Really dumb..
Clock::setClock(&time);
}
timeInit = false;
}
// If the received time does not change anymore for whatever reason, do not set it here
// to avoid stale times. Also, don't do it too often often to avoid jumping times
if (timeIsConstantCounter < 20 and timeUpdateCd.hasTimedOut()) {
// Update the system time here for now. NTP seems to be unable to do so for whatever reason.
// Further tests have shown that the time seems to be set by NTPD after sme time..
// Further tests have shown that the time seems to be set by NTPD after some time..
// Clock::setClock(&time);
timeUpdateCd.resetTimer();
}

View File

@ -1,8 +1,8 @@
#ifndef MISSION_DEVICES_GPSHYPERIONHANDLER_H_
#define MISSION_DEVICES_GPSHYPERIONHANDLER_H_
#include "fsfw/FSFW.h"
#include "commonSubsystemIds.h"
#include "fsfw/FSFW.h"
#include "fsfw/controller/ExtendedControllerBase.h"
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
#include "mission/devices/devicedefinitions/GPSDefinitions.h"
@ -24,7 +24,6 @@ class GPSHyperionLinuxController : public ExtendedControllerBase {
public:
static constexpr uint32_t MAX_SECONDS_TO_REACH_FIX = 60 * 60 * 5;
GPSHyperionLinuxController(object_id_t objectId, object_id_t parentId,
bool debugHyperionGps = false);
virtual ~GPSHyperionLinuxController();
@ -52,6 +51,7 @@ class GPSHyperionLinuxController : public ExtendedControllerBase {
GpsPrimaryDataset gpsSet;
Countdown maxTimeToReachFix = Countdown(MAX_SECONDS_TO_REACH_FIX * 1000);
bool modeCommanded = true;
bool timeInit = true;
gpsmm myGpsmm;
bool debugHyperionGps = false;
uint32_t timeIsConstantCounter = 0;

View File

@ -1,7 +1,7 @@
/**
* @brief Auto-generated event translation file. Contains 183 translations.
* @details
* Generated on: 2022-04-07 17:27:42
* Generated on: 2022-04-08 11:21:58
*/
#include "translateEvents.h"

View File

@ -2,7 +2,7 @@
* @brief Auto-generated object translation file.
* @details
* Contains 117 translations.
* Generated on: 2022-04-07 17:27:42
* Generated on: 2022-04-08 11:21:58
*/
#include "translateObjects.h"

View File

@ -1,3 +1,4 @@
#include "utility.h"
#include <cstring>
@ -5,6 +6,7 @@
#include "FSFWConfig.h"
#include "OBSWConfig.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/timemanager/Clock.h"
void utility::handleSystemError(int retcode, std::string function) {
#if OBSW_VERBOSE_LEVEL >= 1
@ -12,3 +14,14 @@ void utility::handleSystemError(int retcode, std::string function) {
<< strerror(retcode) << std::endl;
#endif
}
bool utility::timeSanityCheck() {
timeval currentTime = {};
Clock::getUptime(&currentTime);
Clock::TimeOfDay_t currTimeOfDay = {};
Clock::convertTimevalToTimeOfDay(&currentTime, &currTimeOfDay);
if (currTimeOfDay.year == 2000) {
return false;
}
return true;
}

View File

@ -9,6 +9,8 @@ namespace utility {
void handleSystemError(int retcode, std::string function);
}
bool timeSanityCheck();
} // namespace utility
#endif /* LINUX_UTILITY_UTILITY_H_ */

View File

@ -6,13 +6,7 @@
namespace GpsHyperion {
enum class FixMode: uint8_t {
NOT_SEEN = 0,
NO_FIX = 1,
FIX_2D = 2,
FIX_3D = 3,
UNKNOWN = 4
};
enum class FixMode : uint8_t { NOT_SEEN = 0, NO_FIX = 1, FIX_2D = 2, FIX_3D = 3, UNKNOWN = 4 };
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::GPS_HANDLER;
//! [EXPORT] : [COMMENT] Fix has changed. P1: Old fix. P2: New fix

View File

@ -5,14 +5,17 @@
* Authors:
*
* Assembled from the code released on Stackoverflow by:
* Dennis (instructable.com/member/nqtronix) | https://stackoverflow.com/questions/23032002/c-c-how-to-get-integer-unix-timestamp-of-build-time-not-string
* Dennis (instructable.com/member/nqtronix) |
* https://stackoverflow.com/questions/23032002/c-c-how-to-get-integer-unix-timestamp-of-build-time-not-string
* and
* Alexis Wilke | https://stackoverflow.com/questions/10538444/do-you-know-of-a-c-macro-to-compute-unix-time-and-date
* Alexis Wilke |
* https://stackoverflow.com/questions/10538444/do-you-know-of-a-c-macro-to-compute-unix-time-and-date
*
* Assembled by Jean Rabault
*
* UNIX_TIMESTAMP gives the UNIX timestamp (unsigned long integer of seconds since 1st Jan 1970) of compilation from macros using the compiler defined __TIME__ macro.
* This should include Gregorian calendar leap days, in particular the 29ths of February, 100 and 400 years modulo leaps.
* UNIX_TIMESTAMP gives the UNIX timestamp (unsigned long integer of seconds since 1st Jan 1970) of
* compilation from macros using the compiler defined __TIME__ macro. This should include Gregorian
* calendar leap days, in particular the 29ths of February, 100 and 400 years modulo leaps.
*
* Careful: __TIME__ is the local time of the computer, NOT the UTC time in general!
*
@ -25,27 +28,29 @@
#define SEC_PER_MIN 60UL
#define SEC_PER_HOUR 3600UL
#define SEC_PER_DAY 86400UL
#define SEC_PER_YEAR (SEC_PER_DAY*365)
#define SEC_PER_YEAR (SEC_PER_DAY * 365)
// extracts 1..4 characters from a string and interprets it as a decimal value
#define CONV_STR2DEC_1(str, i) (str[i]>'0'?str[i]-'0':0)
#define CONV_STR2DEC_2(str, i) (CONV_STR2DEC_1(str, i)*10 + str[i+1]-'0')
#define CONV_STR2DEC_3(str, i) (CONV_STR2DEC_2(str, i)*10 + str[i+2]-'0')
#define CONV_STR2DEC_4(str, i) (CONV_STR2DEC_3(str, i)*10 + str[i+3]-'0')
#define CONV_STR2DEC_1(str, i) (str[i] > '0' ? str[i] - '0' : 0)
#define CONV_STR2DEC_2(str, i) (CONV_STR2DEC_1(str, i) * 10 + str[i + 1] - '0')
#define CONV_STR2DEC_3(str, i) (CONV_STR2DEC_2(str, i) * 10 + str[i + 2] - '0')
#define CONV_STR2DEC_4(str, i) (CONV_STR2DEC_3(str, i) * 10 + str[i + 3] - '0')
// Custom "glue logic" to convert the month name to a usable number
#define GET_MONTH(str, i) (str[i]=='J' && str[i+1]=='a' && str[i+2]=='n' ? 1 : \
str[i]=='F' && str[i+1]=='e' && str[i+2]=='b' ? 2 : \
str[i]=='M' && str[i+1]=='a' && str[i+2]=='r' ? 3 : \
str[i]=='A' && str[i+1]=='p' && str[i+2]=='r' ? 4 : \
str[i]=='M' && str[i+1]=='a' && str[i+2]=='y' ? 5 : \
str[i]=='J' && str[i+1]=='u' && str[i+2]=='n' ? 6 : \
str[i]=='J' && str[i+1]=='u' && str[i+2]=='l' ? 7 : \
str[i]=='A' && str[i+1]=='u' && str[i+2]=='g' ? 8 : \
str[i]=='S' && str[i+1]=='e' && str[i+2]=='p' ? 9 : \
str[i]=='O' && str[i+1]=='c' && str[i+2]=='t' ? 10 : \
str[i]=='N' && str[i+1]=='o' && str[i+2]=='v' ? 11 : \
str[i]=='D' && str[i+1]=='e' && str[i+2]=='c' ? 12 : 0)
#define GET_MONTH(str, i) \
(str[i] == 'J' && str[i + 1] == 'a' && str[i + 2] == 'n' ? 1 \
: str[i] == 'F' && str[i + 1] == 'e' && str[i + 2] == 'b' ? 2 \
: str[i] == 'M' && str[i + 1] == 'a' && str[i + 2] == 'r' ? 3 \
: str[i] == 'A' && str[i + 1] == 'p' && str[i + 2] == 'r' ? 4 \
: str[i] == 'M' && str[i + 1] == 'a' && str[i + 2] == 'y' ? 5 \
: str[i] == 'J' && str[i + 1] == 'u' && str[i + 2] == 'n' ? 6 \
: str[i] == 'J' && str[i + 1] == 'u' && str[i + 2] == 'l' ? 7 \
: str[i] == 'A' && str[i + 1] == 'u' && str[i + 2] == 'g' ? 8 \
: str[i] == 'S' && str[i + 1] == 'e' && str[i + 2] == 'p' ? 9 \
: str[i] == 'O' && str[i + 1] == 'c' && str[i + 2] == 't' ? 10 \
: str[i] == 'N' && str[i + 1] == 'o' && str[i + 2] == 'v' ? 11 \
: str[i] == 'D' && str[i + 1] == 'e' && str[i + 2] == 'c' ? 12 \
: 0)
// extract the information from the time string given by __TIME__ and __DATE__
#define __TIME_SECONDS__ CONV_STR2DEC_2(__TIME__, 6)
@ -57,41 +62,29 @@
// Days in February
#define _UNIX_TIMESTAMP_FDAY(year) \
(((year) % 400) == 0UL ? 29UL : \
(((year) % 100) == 0UL ? 28UL : \
(((year) % 4) == 0UL ? 29UL : \
28UL)))
(((year) % 400) == 0UL ? 29UL \
: (((year) % 100) == 0UL ? 28UL : (((year) % 4) == 0UL ? 29UL : 28UL)))
// Days in the year
#define _UNIX_TIMESTAMP_YDAY(year, month, day) \
( \
/* January */ day \
/* February */ + (month >= 2 ? 31UL : 0UL) \
/* March */ + (month >= 3 ? _UNIX_TIMESTAMP_FDAY(year) : 0UL) \
/* April */ + (month >= 4 ? 31UL : 0UL) \
/* May */ + (month >= 5 ? 30UL : 0UL) \
/* June */ + (month >= 6 ? 31UL : 0UL) \
/* July */ + (month >= 7 ? 30UL : 0UL) \
/* August */ + (month >= 8 ? 31UL : 0UL) \
/* September */+ (month >= 9 ? 31UL : 0UL) \
/* October */ + (month >= 10 ? 30UL : 0UL) \
/* November */ + (month >= 11 ? 31UL : 0UL) \
/* December */ + (month >= 12 ? 30UL : 0UL) \
)
(/* January */ day /* February */ + (month >= 2 ? 31UL : 0UL) /* March */ + \
(month >= 3 ? _UNIX_TIMESTAMP_FDAY(year) : 0UL) /* April */ + \
(month >= 4 ? 31UL : 0UL) /* May */ + (month >= 5 ? 30UL : 0UL) /* June */ + \
(month >= 6 ? 31UL : 0UL) /* July */ + (month >= 7 ? 30UL : 0UL) /* August */ + \
(month >= 8 ? 31UL : 0UL) /* September */ + (month >= 9 ? 31UL : 0UL) /* October */ + \
(month >= 10 ? 30UL : 0UL) /* November */ + (month >= 11 ? 31UL : 0UL) /* December */ + \
(month >= 12 ? 30UL : 0UL))
// get the UNIX timestamp from a digits representation
#define _UNIX_TIMESTAMP(year, month, day, hour, minute, second) \
( /* time */ second \
+ minute * SEC_PER_MIN \
+ hour * SEC_PER_HOUR \
+ /* year day (month + day) */ (_UNIX_TIMESTAMP_YDAY(year, month, day) - 1) * SEC_PER_DAY \
+ /* year */ (year - 1970UL) * SEC_PER_YEAR \
+ ((year - 1969UL) / 4UL) * SEC_PER_DAY \
- ((year - 1901UL) / 100UL) * SEC_PER_DAY \
+ ((year - 1601UL) / 400UL) * SEC_PER_DAY \
)
(/* time */ second + minute * SEC_PER_MIN + hour * SEC_PER_HOUR + \
/* year day (month + day) */ (_UNIX_TIMESTAMP_YDAY(year, month, day) - 1) * SEC_PER_DAY + \
/* year */ (year - 1970UL) * SEC_PER_YEAR + ((year - 1969UL) / 4UL) * SEC_PER_DAY - \
((year - 1901UL) / 100UL) * SEC_PER_DAY + ((year - 1601UL) / 400UL) * SEC_PER_DAY)
// the UNIX timestamp
#define UNIX_TIMESTAMP (_UNIX_TIMESTAMP(__TIME_YEARS__, __TIME_MONTH__, __TIME_DAYS__, __TIME_HOURS__, __TIME_MINUTES__, __TIME_SECONDS__))
#define UNIX_TIMESTAMP \
(_UNIX_TIMESTAMP(__TIME_YEARS__, __TIME_MONTH__, __TIME_DAYS__, __TIME_HOURS__, \
__TIME_MINUTES__, __TIME_SECONDS__))
#endif