Merge pull request 'GPS controller update' (#239) from mueller/gps-tests into develop
All checks were successful
EIVE/eive-obsw/pipeline/head This commit looks good

Reviewed-on: #239
Reviewed-by: Jakob.Meier <meierj@irs.uni-stuttgart.de>
This commit is contained in:
Jakob Meier 2022-05-03 13:41:30 +02:00
commit e088bec582
7 changed files with 296 additions and 185 deletions

View File

@ -13,12 +13,15 @@ list yields a list of all related PRs for each release.
# [v1.11.0] # [v1.11.0]
## Fixed
- Host build working again
## Added ## Added
- Custom Gomspace FDIR which disabled most of the default FDIR functionality
- Custom Syrlinks FDIR which disabled most of the default FDIR functionality - Custom Syrlinks FDIR which disabled most of the default FDIR functionality
## Changed ## Changed
- PCDU handler only called once in PST, but can handle multiple messages now - PCDU handler only called once in PST, but can handle multiple messages now
@ -27,6 +30,8 @@ list yields a list of all related PRs for each release.
- Add `/usr/local/bin` to PATH. All shell scripts are there now - Add `/usr/local/bin` to PATH. All shell scripts are there now
- Rename GPS device to `/dev/gps0` - Rename GPS device to `/dev/gps0`
- Add Syrlinks and TMP devices to Software by default - Add Syrlinks and TMP devices to Software by default
- Update GPS Linux Hyperion Handler to use socket interface. Still allows switching
back to SHM interface, but the SHM interface is a possible cause of SW crashes
# [v1.10.1] # [v1.10.1]

View File

@ -23,8 +23,9 @@
Q7STestTask::Q7STestTask(object_id_t objectId) : TestTask(objectId) { Q7STestTask::Q7STestTask(object_id_t objectId) : TestTask(objectId) {
doTestSdCard = false; doTestSdCard = false;
doTestScratchApi = false; doTestScratchApi = false;
doTestGps = false; doTestGpsShm = false;
doTestXadc = true; doTestGpsSocket = false;
doTestXadc = false;
} }
ReturnValue_t Q7STestTask::performOneShotAction() { ReturnValue_t Q7STestTask::performOneShotAction() {
@ -36,15 +37,20 @@ ReturnValue_t Q7STestTask::performOneShotAction() {
} }
// testJsonLibDirect(); // testJsonLibDirect();
// testDummyParams(); // testDummyParams();
// testProtHandler(); if (doTestProtHandler) {
testProtHandler();
}
FsOpCodes opCode = FsOpCodes::APPEND_TO_FILE; FsOpCodes opCode = FsOpCodes::APPEND_TO_FILE;
testFileSystemHandlerDirect(opCode); testFileSystemHandlerDirect(opCode);
return TestTask::performOneShotAction(); return TestTask::performOneShotAction();
} }
ReturnValue_t Q7STestTask::performPeriodicAction() { ReturnValue_t Q7STestTask::performPeriodicAction() {
if (doTestGps) { if (doTestGpsShm) {
testGpsDaemon(); testGpsDaemonShm();
}
if (doTestGpsSocket) {
testGpsDaemonSocket();
} }
if (doTestXadc) { if (doTestXadc) {
xadcTest(); xadcTest();
@ -150,13 +156,13 @@ void Q7STestTask::testDummyParams() {
result = param.getValue<int>(DummyParameter::DUMMY_KEY_PARAM_1, test); result = param.getValue<int>(DummyParameter::DUMMY_KEY_PARAM_1, test);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "Q7STestTask::testDummyParams: Key " << DummyParameter::DUMMY_KEY_PARAM_1 sif::warning << "Q7STestTask::testDummyParams: Key " << DummyParameter::DUMMY_KEY_PARAM_1
<< " does not exist" << std::endl; << " does not exist" << std::endl;
} }
std::string test2; std::string test2;
result = param.getValue<std::string>(DummyParameter::DUMMY_KEY_PARAM_2, test2); result = param.getValue<std::string>(DummyParameter::DUMMY_KEY_PARAM_2, test2);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "Q7STestTask::testDummyParams: Key " << DummyParameter::DUMMY_KEY_PARAM_1 sif::warning << "Q7STestTask::testDummyParams: Key " << DummyParameter::DUMMY_KEY_PARAM_1
<< " does not exist" << std::endl; << " does not exist" << std::endl;
} }
sif::info << "Test value (3 expected): " << test << std::endl; sif::info << "Test value (3 expected): " << test << std::endl;
sif::info << "Test value 2 (\"blirb\" expected): " << test2 << std::endl; sif::info << "Test value 2 (\"blirb\" expected): " << test2 << std::endl;
@ -166,7 +172,7 @@ ReturnValue_t Q7STestTask::initialize() {
coreController = ObjectManager::instance()->get<CoreController>(objects::CORE_CONTROLLER); coreController = ObjectManager::instance()->get<CoreController>(objects::CORE_CONTROLLER);
if (coreController == nullptr) { if (coreController == nullptr) {
sif::warning << "Q7STestTask::initialize: Could not retrieve CORE_CONTROLLER object" sif::warning << "Q7STestTask::initialize: Could not retrieve CORE_CONTROLLER object"
<< std::endl; << std::endl;
} }
return TestTask::initialize(); return TestTask::initialize();
} }
@ -176,14 +182,14 @@ void Q7STestTask::testProtHandler() {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
// If any chips are unlocked, lock them here // If any chips are unlocked, lock them here
result = coreController->setBootCopyProtection(xsc::Chip::ALL_CHIP, xsc::Copy::ALL_COPY, true, result = coreController->setBootCopyProtection(xsc::Chip::ALL_CHIP, xsc::Copy::ALL_COPY, true,
opPerformed, true); opPerformed, true);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl; sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl;
} }
// unlock own copy // unlock own copy
result = coreController->setBootCopyProtection(xsc::Chip::SELF_CHIP, xsc::Copy::SELF_COPY, false, result = coreController->setBootCopyProtection(xsc::Chip::SELF_CHIP, xsc::Copy::SELF_COPY, false,
opPerformed, true); opPerformed, true);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl; sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl;
} }
@ -197,7 +203,7 @@ void Q7STestTask::testProtHandler() {
// lock own copy // lock own copy
result = coreController->setBootCopyProtection(xsc::Chip::SELF_CHIP, xsc::Copy::SELF_COPY, true, result = coreController->setBootCopyProtection(xsc::Chip::SELF_CHIP, xsc::Copy::SELF_COPY, true,
opPerformed, true); opPerformed, true);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl; sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl;
} }
@ -211,7 +217,7 @@ void Q7STestTask::testProtHandler() {
// unlock specific copy // unlock specific copy
result = coreController->setBootCopyProtection(xsc::Chip::CHIP_1, xsc::Copy::COPY_1, false, result = coreController->setBootCopyProtection(xsc::Chip::CHIP_1, xsc::Copy::COPY_1, false,
opPerformed, true); opPerformed, true);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl; sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl;
} }
@ -225,7 +231,7 @@ void Q7STestTask::testProtHandler() {
// lock specific copy // lock specific copy
result = coreController->setBootCopyProtection(xsc::Chip::CHIP_1, xsc::Copy::COPY_1, true, result = coreController->setBootCopyProtection(xsc::Chip::CHIP_1, xsc::Copy::COPY_1, true,
opPerformed, true); opPerformed, true);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl; sif::warning << "Q7STestTask::testProtHandler: Op failed" << std::endl;
} }
@ -238,8 +244,8 @@ void Q7STestTask::testProtHandler() {
} }
} }
void Q7STestTask::testGpsDaemon() { void Q7STestTask::testGpsDaemonShm() {
gpsmm gpsmm(GPSD_SHARED_MEMORY, 0); gpsmm gpsmm(GPSD_SHARED_MEMORY, "");
gps_data_t* gps; gps_data_t* gps;
gps = gpsmm.read(); gps = gpsmm.read();
if (gps == nullptr) { if (gps == nullptr) {
@ -266,11 +272,74 @@ void Q7STestTask::testGpsDaemon() {
sif::info << "Speed(m/s): " << gps->fix.speed << std::endl; sif::info << "Speed(m/s): " << gps->fix.speed << std::endl;
} }
void Q7STestTask::testGpsDaemonSocket() {
if(gpsmmShmPtr == nullptr) {
gpsmmShmPtr = new gpsmm("localhost", DEFAULT_GPSD_PORT);
}
// The data from the device will generally be read all at once. Therefore, we
// can set all field here
if (not gpsmmShmPtr->is_open()) {
if (gpsNotOpenSwitch) {
// Opening failed
#if FSFW_VERBOSE_LEVEL >= 1
sif::warning << "Q7STestTask::testGpsDaemonSocket: Opening GPSMM failed | "
<< "Error " << errno << " | " << gps_errstr(errno) << std::endl;
#endif
gpsNotOpenSwitch = false;
}
return;
}
// Stopwatch watch;
gps_data_t *gps = nullptr;
gpsmmShmPtr->stream(WATCH_ENABLE | WATCH_JSON);
if(not gpsmmShmPtr->waiting(50000000)) {
return;
}
gps = gpsmmShmPtr->read();
if (gps == nullptr) {
if (gpsReadFailedSwitch) {
gpsReadFailedSwitch = false;
sif::warning << "Q7STestTask::testGpsDaemonSocket: Reading GPS data failed"
<< std::endl;
}
return;
}
if (MODE_SET != (MODE_SET & gps->set)) {
if (noModeSetCntr >= 0) {
noModeSetCntr++;
}
if (noModeSetCntr == 10) {
// TODO: Trigger event here
sif::warning << "Q7STestTask::testGpsDaemonSocket: No mode could be "
"read for 10 consecutive reads"
<< std::endl;
noModeSetCntr = -1;
}
return;
} else {
noModeSetCntr = 0;
}
sif::info << "-- Q7STestTask: GPS socket read test --" << std::endl;
#if LIBGPS_VERSION_MINOR <= 17
time_t timeRaw = gps->fix.time;
#else
time_t timeRaw = gps->fix.time.tv_sec;
#endif
std::tm* time = gmtime(&timeRaw);
sif::info << "Time: " << std::put_time(time, "%c %Z") << std::endl;
sif::info << "Visible satellites: " << gps->satellites_visible << std::endl;
sif::info << "Satellites used: " << gps->satellites_used << std::endl;
sif::info << "Fix (0:Not Seen|1:No Fix|2:2D|3:3D): " << gps->fix.mode << std::endl;
sif::info << "Latitude: " << gps->fix.latitude << std::endl;
sif::info << "Longitude: " << gps->fix.longitude << std::endl;
}
void Q7STestTask::testFileSystemHandlerDirect(FsOpCodes opCode) { void Q7STestTask::testFileSystemHandlerDirect(FsOpCodes opCode) {
auto fsHandler = ObjectManager::instance()->get<FileSystemHandler>(objects::FILE_SYSTEM_HANDLER); auto fsHandler = ObjectManager::instance()->get<FileSystemHandler>(objects::FILE_SYSTEM_HANDLER);
if (fsHandler == nullptr) { if (fsHandler == nullptr) {
sif::warning << "Q7STestTask::testFileSystemHandlerDirect: No FS handler running.." sif::warning << "Q7STestTask::testFileSystemHandlerDirect: No FS handler running.."
<< std::endl; << std::endl;
} }
FileSystemHandler::FsCommandCfg cfg = {}; FileSystemHandler::FsCommandCfg cfg = {};
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
@ -297,115 +366,115 @@ void Q7STestTask::testFileSystemHandlerDirect(FsOpCodes opCode) {
}; };
switch (opCode) { switch (opCode) {
case (FsOpCodes::CREATE_EMPTY_FILE_IN_TMP): { case (FsOpCodes::CREATE_EMPTY_FILE_IN_TMP): {
// No mount prefix, cause file is created in tmp // No mount prefix, cause file is created in tmp
cfg.useMountPrefix = false; cfg.useMountPrefix = false;
sif::info << "Creating empty file in /tmp folder" << std::endl; sif::info << "Creating empty file in /tmp folder" << std::endl;
// Do not delete file, user can check existence in shell // Do not delete file, user can check existence in shell
fsHandler->createFile("/tmp/", "test.txt", nullptr, 0, &cfg);
break;
}
case (FsOpCodes::REMOVE_TMP_FILE): {
sif::info << "Deleting /tmp/test.txt sample file" << std::endl;
// No mount prefix, cause file is created in tmp
cfg.useMountPrefix = false;
if (not std::filesystem::exists("/tmp/test.txt")) {
// Creating sample file
sif::info << "Creating sample file /tmp/test.txt to delete" << std::endl;
fsHandler->createFile("/tmp/", "test.txt", nullptr, 0, &cfg); fsHandler->createFile("/tmp/", "test.txt", nullptr, 0, &cfg);
break;
} }
case (FsOpCodes::REMOVE_TMP_FILE): { result = fsHandler->removeFile("/tmp", "test.txt", &cfg);
sif::info << "Deleting /tmp/test.txt sample file" << std::endl; if (result == HasReturnvaluesIF::RETURN_OK) {
// No mount prefix, cause file is created in tmp sif::info << "File removed successfully" << std::endl;
cfg.useMountPrefix = false; } else {
if (not std::filesystem::exists("/tmp/test.txt")) { sif::warning << "File removal failed!" << std::endl;
// Creating sample file
sif::info << "Creating sample file /tmp/test.txt to delete" << std::endl;
fsHandler->createFile("/tmp/", "test.txt", nullptr, 0, &cfg);
}
result = fsHandler->removeFile("/tmp", "test.txt", &cfg);
if (result == HasReturnvaluesIF::RETURN_OK) {
sif::info << "File removed successfully" << std::endl;
} else {
sif::warning << "File removal failed!" << std::endl;
}
break;
} }
case (FsOpCodes::CREATE_DIR_IN_TMP): { break;
// No mount prefix, cause file is created in tmp }
cfg.useMountPrefix = false; case (FsOpCodes::CREATE_DIR_IN_TMP): {
sif::info << "Creating empty file in /tmp folder" << std::endl; // No mount prefix, cause file is created in tmp
// Do not delete file, user can check existence in shell cfg.useMountPrefix = false;
ReturnValue_t result = fsHandler->createDirectory("/tmp/", "test", false, &cfg); sif::info << "Creating empty file in /tmp folder" << std::endl;
if (result == HasReturnvaluesIF::RETURN_OK) { // Do not delete file, user can check existence in shell
sif::info << "Directory created successfully" << std::endl; ReturnValue_t result = fsHandler->createDirectory("/tmp/", "test", false, &cfg);
} else { if (result == HasReturnvaluesIF::RETURN_OK) {
sif::warning << "Directory creation failed!" << std::endl; sif::info << "Directory created successfully" << std::endl;
} } else {
break; sif::warning << "Directory creation failed!" << std::endl;
} }
case (FsOpCodes::REMOVE_EMPTY_DIR_IN_TMP): { break;
// No mount prefix, cause file is created in tmp }
cfg.useMountPrefix = false; case (FsOpCodes::REMOVE_EMPTY_DIR_IN_TMP): {
if (not std::filesystem::exists("/tmp/test")) { // No mount prefix, cause file is created in tmp
result = fsHandler->createDirectory("/tmp", "test", false, &cfg); cfg.useMountPrefix = false;
} else { if (not std::filesystem::exists("/tmp/test")) {
// Delete any leftover files to regular dir removal works result = fsHandler->createDirectory("/tmp", "test", false, &cfg);
std::remove("/tmp/test/*"); } else {
} // Delete any leftover files to regular dir removal works
result = fsHandler->removeDirectory("/tmp/", "test", false, &cfg); std::remove("/tmp/test/*");
if (result == HasReturnvaluesIF::RETURN_OK) {
sif::info << "Directory removed successfully" << std::endl;
} else {
sif::warning << "Directory removal failed!" << std::endl;
}
break;
} }
case (FsOpCodes::REMOVE_FILLED_DIR_IN_TMP): { result = fsHandler->removeDirectory("/tmp/", "test", false, &cfg);
result = createNonEmptyTmpDir(); if (result == HasReturnvaluesIF::RETURN_OK) {
if (result != HasReturnvaluesIF::RETURN_OK) { sif::info << "Directory removed successfully" << std::endl;
return; } else {
} sif::warning << "Directory removal failed!" << std::endl;
result = fsHandler->removeDirectory("/tmp/", "test", true, &cfg);
if (result == HasReturnvaluesIF::RETURN_OK) {
sif::info << "Directory removed recursively successfully" << std::endl;
} else {
sif::warning << "Recursive directory removal failed!" << std::endl;
}
break;
} }
case (FsOpCodes::ATTEMPT_DIR_REMOVAL_NON_EMPTY): { break;
result = createNonEmptyTmpDir(); }
if (result != HasReturnvaluesIF::RETURN_OK) { case (FsOpCodes::REMOVE_FILLED_DIR_IN_TMP): {
return; result = createNonEmptyTmpDir();
} if (result != HasReturnvaluesIF::RETURN_OK) {
result = fsHandler->removeDirectory("/tmp/", "test", false, &cfg); return;
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::info << "Directory removal attempt failed as expected" << std::endl;
} else {
sif::warning << "Directory removal worked when it should not have!" << std::endl;
}
break;
} }
case (FsOpCodes::RENAME_FILE): { result = fsHandler->removeDirectory("/tmp/", "test", true, &cfg);
// No mount prefix, cause file is created in tmp if (result == HasReturnvaluesIF::RETURN_OK) {
cfg.useMountPrefix = false; sif::info << "Directory removed recursively successfully" << std::endl;
if (std::filesystem::exists("/tmp/test.txt")) { } else {
fsHandler->removeDirectory("/tmp/", "test", false, &cfg); sif::warning << "Recursive directory removal failed!" << std::endl;
}
sif::info << "Creating empty file /tmp/test.txt and rename to /tmp/test2.txt" << std::endl;
// Do not delete file, user can check existence in shell
fsHandler->createFile("/tmp/", "test.txt", nullptr, 0, &cfg);
fsHandler->renameFile("/tmp/", "test.txt", "test2.txt", &cfg);
break;
} }
case (FsOpCodes::APPEND_TO_FILE): { break;
// No mount prefix, cause file is created in tmp }
cfg.useMountPrefix = false; case (FsOpCodes::ATTEMPT_DIR_REMOVAL_NON_EMPTY): {
if (std::filesystem::exists("/tmp/test.txt")) { result = createNonEmptyTmpDir();
fsHandler->removeDirectory("/tmp/", "test", false, &cfg); if (result != HasReturnvaluesIF::RETURN_OK) {
} return;
if (std::filesystem::exists("/tmp/test.txt")) {
fsHandler->removeDirectory("/tmp/", "test", false, &cfg);
}
sif::info << "Creating empty file /tmp/test.txt and adding content" << std::endl;
std::string content = "Hello World\n";
// Do not delete file, user can check existence in shell
fsHandler->createFile("/tmp/", "test.txt", nullptr, 0, &cfg);
fsHandler->appendToFile("/tmp/", "test.txt", reinterpret_cast<const uint8_t*>(content.data()),
content.size(), 0, &cfg);
} }
result = fsHandler->removeDirectory("/tmp/", "test", false, &cfg);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::info << "Directory removal attempt failed as expected" << std::endl;
} else {
sif::warning << "Directory removal worked when it should not have!" << std::endl;
}
break;
}
case (FsOpCodes::RENAME_FILE): {
// No mount prefix, cause file is created in tmp
cfg.useMountPrefix = false;
if (std::filesystem::exists("/tmp/test.txt")) {
fsHandler->removeDirectory("/tmp/", "test", false, &cfg);
}
sif::info << "Creating empty file /tmp/test.txt and rename to /tmp/test2.txt" << std::endl;
// Do not delete file, user can check existence in shell
fsHandler->createFile("/tmp/", "test.txt", nullptr, 0, &cfg);
fsHandler->renameFile("/tmp/", "test.txt", "test2.txt", &cfg);
break;
}
case (FsOpCodes::APPEND_TO_FILE): {
// No mount prefix, cause file is created in tmp
cfg.useMountPrefix = false;
if (std::filesystem::exists("/tmp/test.txt")) {
fsHandler->removeDirectory("/tmp/", "test", false, &cfg);
}
if (std::filesystem::exists("/tmp/test.txt")) {
fsHandler->removeDirectory("/tmp/", "test", false, &cfg);
}
sif::info << "Creating empty file /tmp/test.txt and adding content" << std::endl;
std::string content = "Hello World\n";
// Do not delete file, user can check existence in shell
fsHandler->createFile("/tmp/", "test.txt", nullptr, 0, &cfg);
fsHandler->appendToFile("/tmp/", "test.txt", reinterpret_cast<const uint8_t*>(content.data()),
content.size(), 0, &cfg);
}
} }
} }

View File

@ -1,6 +1,7 @@
#ifndef BSP_Q7S_BOARDTEST_Q7STESTTASK_H_ #ifndef BSP_Q7S_BOARDTEST_Q7STESTTASK_H_
#define BSP_Q7S_BOARDTEST_Q7STESTTASK_H_ #define BSP_Q7S_BOARDTEST_Q7STESTTASK_H_
#include <libgpsmm.h>
#include "test/testtasks/TestTask.h" #include "test/testtasks/TestTask.h"
class CoreController; class CoreController;
@ -14,14 +15,22 @@ class Q7STestTask : public TestTask {
private: private:
bool doTestSdCard = false; bool doTestSdCard = false;
bool doTestScratchApi = false; bool doTestScratchApi = false;
bool doTestGps = false; bool doTestGpsShm = false;
bool doTestGpsSocket = false;
bool doTestProtHandler = false;
bool doTestXadc = false; bool doTestXadc = false;
bool gpsNotOpenSwitch = false;
bool gpsReadFailedSwitch = false;
int32_t noModeSetCntr = 0;
gpsmm* gpsmmShmPtr = nullptr;
CoreController* coreController = nullptr; CoreController* coreController = nullptr;
ReturnValue_t performOneShotAction() override; ReturnValue_t performOneShotAction() override;
ReturnValue_t performPeriodicAction() override; ReturnValue_t performPeriodicAction() override;
void testGpsDaemon(); void testGpsDaemonShm();
void testGpsDaemonSocket();
void testSdCard(); void testSdCard();
void fileTests(); void fileTests();

2
fsfw

@ -1 +1 @@
Subproject commit d61fe7db93b37dd6652dbfee5b7c93f400ac5a11 Subproject commit 7f6c8b8b123a63546de0d73f0de35900d6c806bf

View File

@ -24,7 +24,10 @@ GPSHyperionLinuxController::GPSHyperionLinuxController(object_id_t objectId, obj
timeUpdateCd.resetTimer(); timeUpdateCd.resetTimer();
} }
GPSHyperionLinuxController::~GPSHyperionLinuxController() {} GPSHyperionLinuxController::~GPSHyperionLinuxController() {
gps_stream(&gps, WATCH_DISABLE, nullptr);
gps_close(&gps);
}
void GPSHyperionLinuxController::performControlOperation() { void GPSHyperionLinuxController::performControlOperation() {
#ifdef FSFW_OSAL_LINUX #ifdef FSFW_OSAL_LINUX
@ -99,6 +102,27 @@ ReturnValue_t GPSHyperionLinuxController::initialize() {
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
auto openError = [&](const char *type, int error) {
if (gpsNotOpenSwitch) {
// Opening failed
#if FSFW_VERBOSE_LEVEL >= 1
sif::warning << "GPSHyperionHandler::readGpsDataFromGpsd: Opening GPSMM " << type
<< " failed | Error " << error << " | " << gps_errstr(error) << std::endl;
#endif
gpsNotOpenSwitch = false;
}
};
if (readMode == ReadModes::SOCKET) {
int retval = gps_open("localhost", DEFAULT_GPSD_PORT, &gps);
if (retval != 0) {
openError("Socket", retval);
}
} else if (readMode == ReadModes::SHM) {
int retval = gps_open(GPSD_SHARED_MEMORY, "", &gps);
if (retval != 0) {
openError("SHM", retval);
}
}
return result; return result;
} }
@ -107,41 +131,29 @@ ReturnValue_t GPSHyperionLinuxController::handleCommandMessage(CommandMessage *m
} }
#ifdef FSFW_OSAL_LINUX #ifdef FSFW_OSAL_LINUX
void GPSHyperionLinuxController::readGpsDataFromGpsd() {
gpsmm gpsmm("localhost", DEFAULT_GPSD_PORT);
// The data from the device will generally be read all at once. Therefore, we
// can set all field here
if (not gpsmm.is_open()) {
if (gpsNotOpenSwitch) {
// Opening failed
#if FSFW_VERBOSE_LEVEL >= 1
sif::warning << "GPSHyperionHandler::readGpsDataFromGpsd: Opening GPSMM failed | "
<< "Error " << errno << " | " << gps_errstr(errno) << std::endl;
#endif
gpsNotOpenSwitch = false; void GPSHyperionLinuxController::readGpsDataFromGpsd() {
auto readError = [&](int error) {
if (gpsReadFailedSwitch) {
gpsReadFailedSwitch = false;
sif::warning << "GPSHyperionHandler::readGpsDataFromGpsd: Reading GPS data failed | "
"Error "
<< error << " | " << gps_errstr(error) << std::endl;
} }
return; };
} currentClientBuf = gps_data(&gps);
// Stopwatch watch; if (readMode == ReadModes::SOCKET) {
gps_data_t *gps = nullptr; gps_stream(&gps, WATCH_ENABLE | WATCH_JSON, nullptr);
gps = gpsmm.stream(WATCH_ENABLE | WATCH_JSON); // Exit if no data is seen in 2 seconds (should not happen)
if (gps == nullptr) { if (not gps_waiting(&gps, 2000000)) {
sif::warning << "GPSHyperionHandler::readGpsDataFromGpsd:: Setting GPSD watch "
"policy failed"
<< std::endl;
}
while (gpsmm.waiting(2000)) {
gps = gpsmm.read();
if (gps == nullptr) {
if (gpsReadFailedSwitch) {
gpsReadFailedSwitch = false;
sif::warning << "GPSHyperionHandler::readGpsDataFromGpsd: Reading GPS data failed"
<< std::endl;
}
return; return;
} }
if (MODE_SET != (MODE_SET & gps->set)) { int result = gps_read(&gps);
if (result == -1) {
readError(result);
return;
}
if (MODE_SET != (MODE_SET & gps.set)) {
if (noModeSetCntr >= 0) { if (noModeSetCntr >= 0) {
noModeSetCntr++; noModeSetCntr++;
} }
@ -152,24 +164,31 @@ void GPSHyperionLinuxController::readGpsDataFromGpsd() {
<< std::endl; << std::endl;
noModeSetCntr = -1; noModeSetCntr = -1;
} }
}
noModeSetCntr = 0;
} else if (readMode == ReadModes::SHM) {
int result = gps_read(&gps);
if (result == -1) {
readError(result);
return; return;
} else {
noModeSetCntr = 0;
} }
} }
gps = gpsmm.stream(WATCH_DISABLE); handleGpsRead();
}
ReturnValue_t GPSHyperionLinuxController::handleGpsRead() {
PoolReadGuard pg(&gpsSet); PoolReadGuard pg(&gpsSet);
if (pg.getReadResult() != HasReturnvaluesIF::RETURN_OK) { if (pg.getReadResult() != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_VERBOSE_LEVEL >= 1
sif::warning << "GPSHyperionHandler::readGpsDataFromGpsd: Reading dataset failed" << std::endl; sif::warning << "GPSHyperionHandler::readGpsDataFromGpsd: Reading dataset failed" << std::endl;
#endif #endif
return; return RETURN_FAILED;
} }
bool validFix = false; bool validFix = false;
static_cast<void>(validFix); static_cast<void>(validFix);
// 0: Not seen, 1: No fix, 2: 2D-Fix, 3: 3D-Fix // 0: Not seen, 1: No fix, 2: 2D-Fix, 3: 3D-Fix
int newFixMode = gps->fix.mode; int newFixMode = gps.fix.mode;
if (newFixMode == 2 or newFixMode == 3) { if (newFixMode == 2 or newFixMode == 3) {
validFix = true; validFix = true;
} }
@ -177,7 +196,7 @@ void GPSHyperionLinuxController::readGpsDataFromGpsd() {
triggerEvent(GpsHyperion::GPS_FIX_CHANGE, gpsSet.fixMode.value, newFixMode); triggerEvent(GpsHyperion::GPS_FIX_CHANGE, gpsSet.fixMode.value, newFixMode);
} }
gpsSet.fixMode.value = newFixMode; gpsSet.fixMode.value = newFixMode;
if (gps->fix.mode == 0 or gps->fix.mode == 1) { if (gps.fix.mode == 0 or gps.fix.mode == 1) {
if (modeCommanded and maxTimeToReachFix.hasTimedOut()) { if (modeCommanded and maxTimeToReachFix.hasTimedOut()) {
// We are supposed to be on and functioning, but not fix was found // We are supposed to be on and functioning, but not fix was found
if (mode == MODE_ON or mode == MODE_NORMAL) { if (mode == MODE_ON or mode == MODE_NORMAL) {
@ -186,51 +205,51 @@ void GPSHyperionLinuxController::readGpsDataFromGpsd() {
modeCommanded = false; modeCommanded = false;
} }
gpsSet.setValidity(false, true); gpsSet.setValidity(false, true);
} else if (gps->satellites_used > 0) { } else if (gps.satellites_used > 0) {
gpsSet.setValidity(true, true); gpsSet.setValidity(true, true);
} }
gpsSet.satInUse.value = gps->satellites_used; gpsSet.satInUse.value = gps.satellites_used;
gpsSet.satInView.value = gps->satellites_visible; gpsSet.satInView.value = gps.satellites_visible;
if (std::isfinite(gps->fix.latitude)) { if (std::isfinite(gps.fix.latitude)) {
// Negative latitude -> South direction // Negative latitude -> South direction
gpsSet.latitude.value = gps->fix.latitude; gpsSet.latitude.value = gps.fix.latitude;
} else { } else {
gpsSet.latitude.setValid(false); gpsSet.latitude.setValid(false);
} }
if (std::isfinite(gps->fix.longitude)) { if (std::isfinite(gps.fix.longitude)) {
// Negative longitude -> West direction // Negative longitude -> West direction
gpsSet.longitude.value = gps->fix.longitude; gpsSet.longitude.value = gps.fix.longitude;
} else { } else {
gpsSet.longitude.setValid(false); gpsSet.longitude.setValid(false);
} }
if (std::isfinite(gps->fix.altitude)) { if (std::isfinite(gps.fix.altitude)) {
gpsSet.altitude.value = gps->fix.altitude; gpsSet.altitude.value = gps.fix.altitude;
} else { } else {
gpsSet.altitude.setValid(false); gpsSet.altitude.setValid(false);
} }
if (std::isfinite(gps->fix.speed)) { if (std::isfinite(gps.fix.speed)) {
gpsSet.speed.value = gps->fix.speed; gpsSet.speed.value = gps.fix.speed;
} else { } else {
gpsSet.speed.setValid(false); gpsSet.speed.setValid(false);
} }
#if LIBGPS_VERSION_MINOR <= 17 #if LIBGPS_VERSION_MINOR <= 17
gpsSet.unixSeconds.value = gps->fix.time; gpsSet.unixSeconds.value = gps.fix.time;
#else #else
gpsSet.unixSeconds.value = gps->fix.time.tv_sec; gpsSet.unixSeconds.value = gps.fix.time.tv_sec;
#endif #endif
timeval time = {}; timeval time = {};
time.tv_sec = gpsSet.unixSeconds.value; time.tv_sec = gpsSet.unixSeconds.value;
#if LIBGPS_VERSION_MINOR <= 17 #if LIBGPS_VERSION_MINOR <= 17
double fractionalPart = gps->fix.time - std::floor(gps->fix.time); double fractionalPart = gps.fix.time - std::floor(gps.fix.time);
time.tv_usec = fractionalPart * 1000.0 * 1000.0; time.tv_usec = fractionalPart * 1000.0 * 1000.0;
#else #else
time.tv_usec = gps->fix.time.tv_nsec / 1000; time.tv_usec = gps.fix.time.tv_nsec / 1000;
#endif #endif
std::time_t t = std::time(nullptr); std::time_t t = std::time(nullptr);
if (time.tv_sec == t) { if (time.tv_sec == t) {
@ -271,26 +290,28 @@ void GPSHyperionLinuxController::readGpsDataFromGpsd() {
if (debugHyperionGps) { if (debugHyperionGps) {
sif::info << "-- Hyperion GPS Data --" << std::endl; sif::info << "-- Hyperion GPS Data --" << std::endl;
#if LIBGPS_VERSION_MINOR <= 17 #if LIBGPS_VERSION_MINOR <= 17
time_t timeRaw = gps->fix.time; time_t timeRaw = gps.fix.time;
#else #else
time_t timeRaw = gps->fix.time.tv_sec; time_t timeRaw = gps.fix.time.tv_sec;
#endif #endif
std::tm *time = gmtime(&timeRaw); std::tm *time = gmtime(&timeRaw);
std::cout << "Time: " << std::put_time(time, "%c %Z") << std::endl; std::cout << "Time: " << std::put_time(time, "%c %Z") << std::endl;
std::cout << "Visible satellites: " << gps->satellites_visible << std::endl; std::cout << "Visible satellites: " << gps.satellites_visible << std::endl;
std::cout << "Satellites used: " << gps->satellites_used << std::endl; std::cout << "Satellites used: " << gps.satellites_used << std::endl;
std::cout << "Fix (0:Not Seen|1:No Fix|2:2D|3:3D): " << gps->fix.mode << std::endl; std::cout << "Fix (0:Not Seen|1:No Fix|2:2D|3:3D): " << gps.fix.mode << std::endl;
std::cout << "Latitude: " << gps->fix.latitude << std::endl; std::cout << "Latitude: " << gps.fix.latitude << std::endl;
std::cout << "Longitude: " << gps->fix.longitude << std::endl; std::cout << "Longitude: " << gps.fix.longitude << std::endl;
#if LIBGPS_VERSION_MINOR <= 17 #if LIBGPS_VERSION_MINOR <= 17
std::cout << "Altitude(MSL): " << gps->fix.altitude << std::endl; std::cout << "Altitude(MSL): " << gps.fix.altitude << std::endl;
#else #else
std::cout << "Altitude(MSL): " << gps->fix.altMSL << std::endl; std::cout << "Altitude(MSL): " << gps.fix.altMSL << std::endl;
#endif #endif
std::cout << "Speed(m/s): " << gps->fix.speed << std::endl; std::cout << "Speed(m/s): " << gps.fix.speed << std::endl;
std::time_t t = std::time(nullptr); std::time_t t = std::time(nullptr);
std::tm tm = *std::gmtime(&t); std::tm tm = *std::gmtime(&t);
std::cout << "C Time: " << std::put_time(&tm, "%c") << std::endl; std::cout << "C Time: " << std::put_time(&tm, "%c") << std::endl;
} }
return RETURN_OK;
} }
#endif #endif

View File

@ -24,6 +24,8 @@ class GPSHyperionLinuxController : public ExtendedControllerBase {
public: public:
static constexpr uint32_t MAX_SECONDS_TO_REACH_FIX = 60 * 60 * 5; static constexpr uint32_t MAX_SECONDS_TO_REACH_FIX = 60 * 60 * 5;
enum ReadModes { SHM = 0, SOCKET = 1 };
GPSHyperionLinuxController(object_id_t objectId, object_id_t parentId, GPSHyperionLinuxController(object_id_t objectId, object_id_t parentId,
bool debugHyperionGps = false); bool debugHyperionGps = false);
virtual ~GPSHyperionLinuxController(); virtual ~GPSHyperionLinuxController();
@ -47,8 +49,13 @@ class GPSHyperionLinuxController : public ExtendedControllerBase {
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override; LocalDataPoolManager& poolManager) override;
ReturnValue_t handleGpsRead();
private: private:
GpsPrimaryDataset gpsSet; GpsPrimaryDataset gpsSet;
gps_data_t gps = {};
const char* currentClientBuf = nullptr;
ReadModes readMode = ReadModes::SOCKET;
Countdown maxTimeToReachFix = Countdown(MAX_SECONDS_TO_REACH_FIX * 1000); Countdown maxTimeToReachFix = Countdown(MAX_SECONDS_TO_REACH_FIX * 1000);
bool modeCommanded = true; bool modeCommanded = true;
bool timeInit = true; bool timeInit = true;

2
tmtc

@ -1 +1 @@
Subproject commit 168b662288175f9db77a5796a02f38cb66911092 Subproject commit 0a47c17fa699dc571d2d3e63ec08c9f4cf513f65