Merge remote-tracking branch 'upstream/development' into eive/develop

This commit is contained in:
Robin Müller 2022-03-14 17:50:27 +01:00
commit 5ca5fe4040
No known key found for this signature in database
GPG Key ID: 11D4952C8CCEF814
13 changed files with 275 additions and 55 deletions

View File

@ -12,20 +12,29 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Changes ## Changes
- GPIO HAL: Renamed entries of enumerations to avoid nameclashes with Windows defines. - HAL Linux SPI: Set the Clock Default State when setting new SPI speed
`IN` and `OUT` in `Direction` changed to `DIR_IN` and `DIR_OUT`. and mode
`CALLBACK` in `GpioTypes` changed to `TYPE_CALLBACK` PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
- GPIO HAL: `Direction`, `GpioOperation` and `Levels` are enum classes now, which prevents
name clashes with Windows defines.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
- New CMake option `FSFW_HAL_LINUX_ADD_LIBGPIOD` to specifically exclude `gpiod` code.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
- HAL Devicehandlers: Periodic printout is run-time configurable now - HAL Devicehandlers: Periodic printout is run-time configurable now
- `oneShotAction` flag in the `TestTask` class is not static anymore - `oneShotAction` flag in the `TestTask` class is not static anymore
## Removed ## Removed
- Removed the `HkSwitchHelper`. This module should not be needed anymore, now that the local - Removed the `HkSwitchHelper`. This module should not be needed anymore, now that the local
datapools have been implemented datapools have been implemented.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/557
## Additions ## Additions
- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1 - Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1
- Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information
inside `fsfw/version.h`
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
# [v4.0.0] # [v4.0.0]

View File

@ -2,8 +2,8 @@
#define FSFW_VERSION_H_ #define FSFW_VERSION_H_
// Versioning is kept in project CMakeLists.txt file // Versioning is kept in project CMakeLists.txt file
#define FSFW_VERSION @FSFW_VERSION@ #define FSFW_VERSION_MAJOR @FSFW_VERSION@
#define FSFW_SUBVERSION @FSFW_SUBVERSION@ #define FSFW_VERSION_MINOR @FSFW_SUBVERSION@
#define FSFW_REVISION @FSFW_REVISION@ #define FSFW_VERSION_REVISION @FSFW_REVISION@
#endif /* FSFW_VERSION_H_ */ #endif /* FSFW_VERSION_H_ */

View File

@ -7,8 +7,14 @@
// could be moved to more suitable location // could be moved to more suitable location
#include <events/subsystemIdRanges.h> #include <events/subsystemIdRanges.h>
typedef uint16_t EventId_t; using EventId_t = uint16_t;
typedef uint8_t EventSeverity_t; using EventSeverity_t = uint8_t;
using UniqueEventId_t = uint8_t;
namespace severity {
enum Severity : EventSeverity_t { INFO = 1, LOW = 2, MEDIUM = 3, HIGH = 4 };
} // namespace severity
#define MAKE_EVENT(id, severity) (((severity) << 16) + (SUBSYSTEM_ID * 100) + (id)) #define MAKE_EVENT(id, severity) (((severity) << 16) + (SUBSYSTEM_ID * 100) + (id))
@ -20,18 +26,11 @@ constexpr EventId_t getEventId(Event event) { return (event & 0xFFFF); }
constexpr EventSeverity_t getSeverity(Event event) { return ((event >> 16) & 0xFF); } constexpr EventSeverity_t getSeverity(Event event) { return ((event >> 16) & 0xFF); }
constexpr Event makeEvent(uint8_t subsystemId, uint8_t uniqueEventId, constexpr Event makeEvent(uint8_t subsystemId, UniqueEventId_t uniqueEventId,
EventSeverity_t eventSeverity) { EventSeverity_t eventSeverity) {
return (eventSeverity << 16) + (subsystemId * 100) + uniqueEventId; return (eventSeverity << 16) + (subsystemId * 100) + uniqueEventId;
} }
} // namespace event } // namespace event
namespace severity {
static constexpr EventSeverity_t INFO = 1;
static constexpr EventSeverity_t LOW = 2;
static constexpr EventSeverity_t MEDIUM = 3;
static constexpr EventSeverity_t HIGH = 4;
} // namespace severity
#endif /* EVENTOBJECT_EVENT_H_ */ #endif /* EVENTOBJECT_EVENT_H_ */

View File

@ -150,17 +150,14 @@ ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval*
time_tm.tm_hour = from->hour; time_tm.tm_hour = from->hour;
time_tm.tm_min = from->minute; time_tm.tm_min = from->minute;
time_tm.tm_sec = from->second; time_tm.tm_sec = from->second;
time_tm.tm_isdst = 0;
time_t seconds = mktime(&time_tm); time_t seconds = timegm(&time_tm);
to->tv_sec = seconds; to->tv_sec = seconds;
to->tv_usec = from->usecond; to->tv_usec = from->usecond;
// Fails in 2038.. // Fails in 2038..
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::convertTimeBla: not implemented yet" << std::endl;
#endif
return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {

View File

@ -140,8 +140,9 @@ ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval*
fromTm.tm_hour = from->hour; fromTm.tm_hour = from->hour;
fromTm.tm_min = from->minute; fromTm.tm_min = from->minute;
fromTm.tm_sec = from->second; fromTm.tm_sec = from->second;
fromTm.tm_isdst = 0;
to->tv_sec = mktime(&fromTm); to->tv_sec = timegm(&fromTm);
to->tv_usec = from->usecond; to->tv_usec = from->usecond;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -557,6 +557,35 @@ ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const uint8_t* from, size_t
return RETURN_OK; return RETURN_OK;
} }
ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const CCSDSTime::CDS_short* from) {
if (to == nullptr or from == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
uint16_t days = (from->dayMSB << 8) + from->dayLSB;
if (days <= DAYS_CCSDS_TO_UNIX_EPOCH) {
return INVALID_TIME_FORMAT;
}
days -= DAYS_CCSDS_TO_UNIX_EPOCH;
to->tv_sec = days * SECONDS_PER_DAY;
uint32_t msDay =
(from->msDay_hh << 24) + (from->msDay_h << 16) + (from->msDay_l << 8) + from->msDay_ll;
to->tv_sec += (msDay / 1000);
to->tv_usec = (msDay % 1000) * 1000;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const CCSDSTime::CDS_short* from) {
if (to == nullptr or from == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
timeval tempTimeval;
ReturnValue_t result = convertFromCDS(&tempTimeval, from);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return CCSDSTime::convertTimevalToTimeOfDay(to, &tempTimeval);
}
ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8_t* from, ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8_t* from,
size_t* foundLength, size_t maxLength) { size_t* foundLength, size_t maxLength) {
uint32_t secs = 0; uint32_t secs = 0;

View File

@ -180,6 +180,8 @@ class CCSDSTime : public HasReturnvaluesIF {
static ReturnValue_t convertFromCDS(timeval *to, uint8_t const *from, size_t *foundLength, static ReturnValue_t convertFromCDS(timeval *to, uint8_t const *from, size_t *foundLength,
size_t maxLength); size_t maxLength);
static ReturnValue_t convertFromCDS(timeval *to, const CCSDSTime::CDS_short *from);
static ReturnValue_t convertFromCDS(Clock::TimeOfDay_t *to, const CCSDSTime::CDS_short *from);
static ReturnValue_t convertFromCCS(Clock::TimeOfDay_t *to, uint8_t const *from, static ReturnValue_t convertFromCCS(Clock::TimeOfDay_t *to, uint8_t const *from,
size_t *foundLength, size_t maxLength); size_t *foundLength, size_t maxLength);

View File

@ -1,8 +1,22 @@
#include "version.h" #include "version.h"
#include "fsfw/FSFWVersion.h" #include "fsfw/FSFWVersion.h"
void fsfw::getVersion(Version& v) { #include <cstdio>
v.major = FSFW_VERSION;
v.minor = FSFW_SUBVERSION; #ifdef major
v.revision = FSFW_REVISION; #undef major
#endif
#ifdef minor
#undef minor
#endif
const fsfw::Version fsfw::FSFW_VERSION = {FSFW_VERSION_MAJOR, FSFW_VERSION_MINOR,
FSFW_VERSION_REVISION};
fsfw::Version::Version(uint32_t major, uint32_t minor, uint32_t revision)
: major(major), minor(minor), revision(revision) {}
void fsfw::Version::getVersion(char* str, size_t maxLen) const {
snprintf(str, maxLen, "%d.%d.%d", major, minor, revision);
} }

View File

@ -1,18 +1,64 @@
#ifndef FSFW_SRC_FSFW_VERSION_H_ #ifndef FSFW_SRC_FSFW_VERSION_H_
#define FSFW_SRC_FSFW_VERSION_H_ #define FSFW_SRC_FSFW_VERSION_H_
#include "fsfw/FSFW.h"
#if FSFW_CPP_OSTREAM_ENABLED == 1
#include <iostream>
#endif
#include <cstdint> #include <cstdint>
namespace fsfw { namespace fsfw {
struct Version { class Version {
public:
Version(uint32_t major, uint32_t minor, uint32_t revision);
uint32_t major = 0; uint32_t major = 0;
uint32_t minor = 0; uint32_t minor = 0;
uint32_t revision = 0; uint32_t revision = 0;
};
void getVersion(Version& version);
friend bool operator==(const Version& v1, const Version& v2) {
return (v1.major == v2.major and v1.minor == v2.minor and v1.revision == v2.revision);
} }
friend bool operator!=(const Version& v1, const Version& v2) { return not(v1 == v2); }
friend bool operator<(const Version& v1, const Version& v2) {
return ((v1.major < v2.major) or (v1.major == v2.major and v1.minor < v2.minor) or
(v1.major == v2.major and v1.minor == v2.minor and v1.revision < v2.revision));
}
friend bool operator>(const Version& v1, const Version& v2) {
return not (v1 < v2) and not (v1 == v2);
}
friend bool operator<=(const Version& v1, const Version& v2) { return ((v1 == v2) or (v1 < v2)); }
friend bool operator>=(const Version& v1, const Version& v2) { return ((v1 == v2) or (v1 > v2)); }
#if FSFW_CPP_OSTREAM_ENABLED == 1
/**
* Print format to given ostream using format "major.minor.revision"
* @param os
* @param v
* @return
*/
friend std::ostream& operator<<(std::ostream& os, const Version& v) {
os << v.major << "." << v.minor << "." << v.revision;
return os;
}
#endif
/**
* Get version as format "major.minor.revision"
* @param str
* @param maxLen
*/
void getVersion(char* str, size_t maxLen) const;
};
extern const fsfw::Version FSFW_VERSION;
} // namespace fsfw
#endif /* FSFW_SRC_FSFW_VERSION_H_ */ #endif /* FSFW_SRC_FSFW_VERSION_H_ */

View File

@ -2,14 +2,13 @@ target_sources(${FSFW_TEST_TGT} PRIVATE
CatchDefinitions.cpp CatchDefinitions.cpp
CatchFactory.cpp CatchFactory.cpp
printChar.cpp printChar.cpp
version.cpp
) )
# if(FSFW_CUSTOM_UNITTEST_RUNNER)
target_sources(${FSFW_TEST_TGT} PRIVATE target_sources(${FSFW_TEST_TGT} PRIVATE
CatchRunner.cpp CatchRunner.cpp
CatchSetup.cpp CatchSetup.cpp
) )
# endif()
add_subdirectory(testcfg) add_subdirectory(testcfg)
add_subdirectory(action) add_subdirectory(action)

View File

@ -1,6 +1,7 @@
#include <fsfw/datapool/PoolReadGuard.h> #include <fsfw/datapool/PoolReadGuard.h>
#include <fsfw/datapoollocal/HasLocalDataPoolIF.h> #include <fsfw/datapoollocal/HasLocalDataPoolIF.h>
#include <fsfw/datapoollocal/StaticLocalDataSet.h> #include <fsfw/datapoollocal/StaticLocalDataSet.h>
#include <fsfw/globalfunctions/timevalOperations.h>
#include <fsfw/housekeeping/HousekeepingSnapshot.h> #include <fsfw/housekeeping/HousekeepingSnapshot.h>
#include <fsfw/ipc/CommandMessageCleaner.h> #include <fsfw/ipc/CommandMessageCleaner.h>
#include <fsfw/objectmanager/ObjectManager.h> #include <fsfw/objectmanager/ObjectManager.h>
@ -93,10 +94,8 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
poolOwner->dataset.setChanged(true); poolOwner->dataset.setChanged(true);
/* Store current time, we are going to check the (approximate) time equality later */ /* Store current time, we are going to check the (approximate) time equality later */
CCSDSTime::CDS_short timeCdsNow;
timeval now; timeval now;
Clock::getClock_timeval(&now); Clock::getClock_timeval(&now);
CCSDSTime::convertToCcsds(&timeCdsNow, &now);
/* Trigger generation of snapshot */ /* Trigger generation of snapshot */
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
@ -131,13 +130,11 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
CHECK(newSet.localPoolUint16Vec.value[2] == 42932); CHECK(newSet.localPoolUint16Vec.value[2] == 42932);
/* Now we check that both times are equal */ /* Now we check that both times are equal */
CHECK(cdsShort.pField == timeCdsNow.pField); timeval timeFromHK;
CHECK(cdsShort.dayLSB == Catch::Approx(timeCdsNow.dayLSB).margin(1)); auto result = CCSDSTime::convertFromCDS(&timeFromHK, &cdsShort);
CHECK(cdsShort.dayMSB == Catch::Approx(timeCdsNow.dayMSB).margin(1)); CHECK(result == HasReturnvaluesIF::RETURN_OK);
CHECK(cdsShort.msDay_h == Catch::Approx(timeCdsNow.msDay_h).margin(1)); timeval difference = timeFromHK - now;
CHECK(cdsShort.msDay_hh == Catch::Approx(timeCdsNow.msDay_hh).margin(1)); CHECK(timevalOperations::toDouble(difference) < 1.0);
CHECK(cdsShort.msDay_l == Catch::Approx(timeCdsNow.msDay_l).margin(1));
CHECK(cdsShort.msDay_ll == Catch::Approx(timeCdsNow.msDay_ll).margin(5));
} }
SECTION("VariableSnapshotTest") { SECTION("VariableSnapshotTest") {
@ -158,13 +155,10 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
} }
poolVar->setChanged(true); poolVar->setChanged(true);
/* Store current time, we are going to check the (approximate) time equality later */ /* Store current time, we are going to check the (approximate) time equality later */
CCSDSTime::CDS_short timeCdsNow; CCSDSTime::CDS_short timeCdsNow;
timeval now; timeval now;
Clock::getClock_timeval(&now); Clock::getClock_timeval(&now);
CCSDSTime::convertToCcsds(&timeCdsNow, &now);
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
/* Check update snapshot was sent. */ /* Check update snapshot was sent. */
@ -193,13 +187,11 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
CHECK(varCopy.value == 25); CHECK(varCopy.value == 25);
/* Now we check that both times are equal */ /* Now we check that both times are equal */
CHECK(cdsShort.pField == timeCdsNow.pField); timeval timeFromHK;
CHECK(cdsShort.dayLSB == Catch::Approx(timeCdsNow.dayLSB).margin(1)); auto result = CCSDSTime::convertFromCDS(&timeFromHK, &cdsShort);
CHECK(cdsShort.dayMSB == Catch::Approx(timeCdsNow.dayMSB).margin(1)); CHECK(result == HasReturnvaluesIF::RETURN_OK);
CHECK(cdsShort.msDay_h == Catch::Approx(timeCdsNow.msDay_h).margin(1)); timeval difference = timeFromHK - now;
CHECK(cdsShort.msDay_hh == Catch::Approx(timeCdsNow.msDay_hh).margin(1)); CHECK(timevalOperations::toDouble(difference) < 1.0);
CHECK(cdsShort.msDay_l == Catch::Approx(timeCdsNow.msDay_l).margin(1));
CHECK(cdsShort.msDay_ll == Catch::Approx(timeCdsNow.msDay_ll).margin(5));
} }
SECTION("VariableNotificationTest") { SECTION("VariableNotificationTest") {

View File

@ -1,3 +1,4 @@
#include <fsfw/globalfunctions/timevalOperations.h>
#include <fsfw/timemanager/CCSDSTime.h> #include <fsfw/timemanager/CCSDSTime.h>
#include <array> #include <array>
@ -89,4 +90,43 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") {
REQUIRE(timeTo.second == 59); REQUIRE(timeTo.second == 59);
REQUIRE(timeTo.usecond == Catch::Approx(123000)); REQUIRE(timeTo.usecond == Catch::Approx(123000));
} }
SECTION("CDS Conversions") {
// Preperation
Clock::TimeOfDay_t time;
time.year = 2020;
time.month = 2;
time.day = 29;
time.hour = 13;
time.minute = 24;
time.second = 45;
time.usecond = 123456;
timeval timeAsTimeval;
auto result = Clock::convertTimeOfDayToTimeval(&time, &timeAsTimeval);
CHECK(result == HasReturnvaluesIF::RETURN_OK);
CHECK(timeAsTimeval.tv_sec == 1582982685);
CHECK(timeAsTimeval.tv_usec == 123456);
// Conversion to CDS Short
CCSDSTime::CDS_short cdsTime;
result = CCSDSTime::convertToCcsds(&cdsTime, &timeAsTimeval);
CHECK(result == HasReturnvaluesIF::RETURN_OK);
// Days in CCSDS Epoch 22704 (0x58B0)
CHECK(cdsTime.dayMSB == 0x58);
CHECK(cdsTime.dayLSB == 0xB0);
// MS of day 48285123.456 (floored here)
CHECK(cdsTime.msDay_hh == 0x2);
CHECK(cdsTime.msDay_h == 0xE0);
CHECK(cdsTime.msDay_l == 0xC5);
CHECK(cdsTime.msDay_ll == 0xC3);
// Conversion back to timeval
timeval timeReturnAsTimeval;
result = CCSDSTime::convertFromCDS(&timeReturnAsTimeval, &cdsTime);
CHECK(result == HasReturnvaluesIF::RETURN_OK);
// micro seconds precision is lost
timeval difference = timeAsTimeval - timeReturnAsTimeval;
CHECK(difference.tv_usec == 456);
CHECK(difference.tv_sec == 0);
}
} }

View File

@ -0,0 +1,92 @@
#include "fsfw/version.h"
#include <catch2/catch_test_macros.hpp>
#include "fsfw/serviceinterface.h"
#include "fsfw_tests/unit/CatchDefinitions.h"
TEST_CASE("Version API Tests", "[TestVersionAPI]") {
// Check that major version is non-zero
REQUIRE(fsfw::FSFW_VERSION.major > 0);
uint32_t fsfwMajor = fsfw::FSFW_VERSION.major;
REQUIRE(fsfw::Version(255, 0, 0) > fsfw::FSFW_VERSION);
REQUIRE(fsfw::Version(255, 0, 0) >= fsfw::FSFW_VERSION);
REQUIRE(fsfw::Version(0, 0, 0) < fsfw::FSFW_VERSION);
REQUIRE(fsfw::Version(0, 0, 0) <= fsfw::FSFW_VERSION);
fsfw::Version v1 = fsfw::Version(1, 1, 1);
fsfw::Version v2 = fsfw::Version(1, 1, 1);
REQUIRE(v1 == v2);
REQUIRE(not (v1 < v2));
REQUIRE(not (v1 > v2));
REQUIRE(v1 <= v2);
REQUIRE(v1 >= v2);
v1.revision -= 1;
REQUIRE(v1 != v2);
REQUIRE(not (v1 == v2));
REQUIRE(not (v1 > v2));
REQUIRE(not (v1 >= v2));
REQUIRE(v1 < v2);
REQUIRE(v1 <= v2);
v1.revision += 1;
v1.minor -= 1;
REQUIRE(v1 != v2);
REQUIRE(v1 < v2);
REQUIRE(v1 <= v2);
REQUIRE(not (v1 == v2));
REQUIRE(not (v1 > v2));
REQUIRE(not (v1 >= v2));
v1.minor += 1;
v1.major -= 1;
REQUIRE(v1 != v2);
REQUIRE(v1 < v2);
REQUIRE(v1 <= v2);
REQUIRE(not (v1 == v2));
REQUIRE(not (v1 > v2));
REQUIRE(not (v1 >= v2));
v1.major += 1;
REQUIRE(v1 == v2);
REQUIRE(v1 <= v2);
REQUIRE(v1 >= v2);
REQUIRE(not (v1 != v2));
REQUIRE(not (v1 > v2));
REQUIRE(not (v1 < v2));
v1.major += 1;
v1.minor -= 1;
REQUIRE(v1 != v2);
REQUIRE(v1 > v2);
REQUIRE(v1 >= v2);
REQUIRE(not (v1 == v2));
REQUIRE(not (v1 < v2));
REQUIRE(not (v1 <= v2));
v1.major -= 1;
v1.minor += 2;
v1.revision -= 1;
REQUIRE(v1 != v2);
REQUIRE(v1 > v2);
REQUIRE(v1 >= v2);
REQUIRE(not (v1 == v2));
REQUIRE(not (v1 < v2));
REQUIRE(not (v1 <= v2));
v1.minor -= 1;
v1.revision += 2;
REQUIRE(v1 != v2);
REQUIRE(v1 > v2);
REQUIRE(v1 >= v2);
REQUIRE(not (v1 == v2));
REQUIRE(not (v1 < v2));
REQUIRE(not (v1 <= v2));
v1.revision -= 1;
REQUIRE(v1 == v2);
REQUIRE(v1 <= v2);
REQUIRE(v1 >= v2);
REQUIRE(not (v1 != v2));
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "v" << fsfw::FSFW_VERSION << std::endl;
#endif
char verString[10] = {};
fsfw::FSFW_VERSION.getVersion(verString, sizeof(verString));
#if FSFW_DISABLE_PRINTOUT == 0
printf("v%s\n",verString);
#endif
}