archive
arduino
automation
bsp_egse
bsp_hosted
bsp_linux_board
bsp_q7s
bsp_te0720_1cfa
cmake
common
doc
dummies
fsfw
generators
linux
misc
mission
cfdp
config
controller
core
csp
devices
devicedefinitions
ACUHandler.cpp
ACUHandler.h
BpxBatteryHandler.cpp
BpxBatteryHandler.h
CMakeLists.txt
GPSHyperionHandler.cpp
GPSHyperionHandler.h
GomspaceDeviceHandler.cpp
GomspaceDeviceHandler.h
GyroADIS1650XHandler.cpp
GyroADIS1650XHandler.h
HeaterHandler.cpp
HeaterHandler.h
ImtqHandler.cpp
ImtqHandler.h
Max31865EiveHandler.cpp
Max31865EiveHandler.h
Max31865PT1000Handler.cpp
Max31865PT1000Handler.h
P60DockHandler.cpp
P60DockHandler.h
PDU1Handler.cpp
PDU1Handler.h
PDU2Handler.cpp
PDU2Handler.h
PayloadPcduHandler.cpp
PayloadPcduHandler.h
PcduHandler.cpp
PcduHandler.h
RadiationSensorHandler.cpp
RadiationSensorHandler.h
RwHandler.cpp
RwHandler.h
ScexDeviceHandler.cpp
ScexDeviceHandler.h
SolarArrayDeploymentHandler.cpp
SolarArrayDeploymentHandler.h
SusHandler.cpp
SusHandler.h
SyrlinksHandler.cpp
SyrlinksHandler.h
Tmp1075Handler.cpp
Tmp1075Handler.h
max1227.cpp
max1227.h
memory
system
tmtc
utility
CMakeLists.txt
acsDefs.h
comDefs.h
mission.mk
scripts
test
thirdparty
tmtc
unittest
watchdog
.clang-format
.dockerignore
.gitignore
.gitmodules
CHANGELOG.md
CMakeLists.txt
Justfile
LICENSE
NOTICE
README.md
clone-submodules-no-privlibs.sh
docker-compose.yml
q7s-env-em.sh
q7s-env.sh
386 lines
12 KiB
C++
386 lines
12 KiB
C++
#include "ScexDeviceHandler.h"
|
|
|
|
#include <fsfw/filesystem/HasFileSystemIF.h>
|
|
#include <linux/devices/ScexHelper.h>
|
|
#include <mission/memory/SdCardMountedIF.h>
|
|
|
|
#include <algorithm>
|
|
#include <ctime>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <random>
|
|
|
|
#include "fsfw/globalfunctions/CRC.h"
|
|
#include "mission/devices/devicedefinitions/ScexDefinitions.h"
|
|
|
|
using std::ofstream;
|
|
using namespace returnvalue;
|
|
|
|
ScexDeviceHandler::ScexDeviceHandler(object_id_t objectId, ScexUartReader& reader, CookieIF* cookie,
|
|
SdCardMountedIF& sdcMan)
|
|
: DeviceHandlerBase(objectId, reader.getObjectId(), cookie), sdcMan(sdcMan), reader(reader) {}
|
|
|
|
ScexDeviceHandler::~ScexDeviceHandler() {}
|
|
|
|
void ScexDeviceHandler::doStartUp() { setMode(MODE_ON); }
|
|
|
|
void ScexDeviceHandler::doShutDown() {
|
|
reader.reset();
|
|
commandActive = false;
|
|
multiFileFinishOutstanding = false;
|
|
setMode(_MODE_POWER_DOWN);
|
|
}
|
|
|
|
ReturnValue_t ScexDeviceHandler::buildNormalDeviceCommand(DeviceCommandId_t* id) { return OK; }
|
|
|
|
ReturnValue_t ScexDeviceHandler::buildTransitionDeviceCommand(DeviceCommandId_t* id) { return OK; }
|
|
|
|
ReturnValue_t ScexDeviceHandler::buildCommandFromCommand(DeviceCommandId_t deviceCommand,
|
|
const uint8_t* commandData,
|
|
size_t commandDataLen) {
|
|
using namespace scex;
|
|
|
|
auto cmdTyped = static_cast<scex::Cmds>(deviceCommand);
|
|
if (std::find(VALID_CMDS.begin(), VALID_CMDS.end(), deviceCommand) == VALID_CMDS.end()) {
|
|
return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED;
|
|
}
|
|
bool tempCheck = false;
|
|
if (commandDataLen == 1) {
|
|
tempCheck = commandData[0];
|
|
}
|
|
if (commandActive) {
|
|
return DeviceHandlerIF::BUSY;
|
|
}
|
|
|
|
switch (deviceCommand) {
|
|
case (PING): {
|
|
finishCountdown.setTimeout(SHORT_CD);
|
|
// countdown starten
|
|
finishCountdown.resetTimer();
|
|
prepareScexCmd(cmdTyped, {cmdBuf.data(), cmdBuf.size()}, rawPacketLen, {nullptr, 0},
|
|
tempCheck);
|
|
break;
|
|
}
|
|
case (EXP_STATUS_CMD): {
|
|
finishCountdown.setTimeout(SHORT_CD);
|
|
// countdown starten
|
|
finishCountdown.resetTimer();
|
|
prepareScexCmd(cmdTyped, {cmdBuf.data(), cmdBuf.size()}, rawPacketLen, {nullptr, 0},
|
|
tempCheck);
|
|
break;
|
|
}
|
|
case (ION_CMD): {
|
|
finishCountdown.setTimeout(SHORT_CD);
|
|
// countdown starten
|
|
finishCountdown.resetTimer();
|
|
prepareScexCmd(cmdTyped, {cmdBuf.data(), cmdBuf.size()}, rawPacketLen, {nullptr, 0},
|
|
tempCheck);
|
|
break;
|
|
}
|
|
case (TEMP_CMD): {
|
|
finishCountdown.setTimeout(SHORT_CD);
|
|
// countdown starten
|
|
finishCountdown.resetTimer();
|
|
prepareScexCmd(cmdTyped, {cmdBuf.data(), cmdBuf.size()}, rawPacketLen, {nullptr, 0},
|
|
tempCheck);
|
|
break;
|
|
}
|
|
case (FRAM): {
|
|
finishCountdown.setTimeout(LONG_CD);
|
|
// countdown starten
|
|
finishCountdown.resetTimer();
|
|
if (debugMode) {
|
|
uint32_t remainingMillis = finishCountdown.getRemainingMillis();
|
|
|
|
sif::info << "ScexDeviceHandler::buildCommandFromCommand: RemainingMillis: "
|
|
<< remainingMillis << std::endl;
|
|
}
|
|
|
|
multiFileFinishOutstanding = true;
|
|
prepareScexCmd(cmdTyped, {cmdBuf.data(), cmdBuf.size()}, rawPacketLen,
|
|
{commandData + 1, commandDataLen - 1}, tempCheck);
|
|
updatePeriodicReply(true, deviceCommand);
|
|
break;
|
|
}
|
|
case (ONE_CELL): {
|
|
finishCountdown.setTimeout(LONG_CD);
|
|
// countdown starts
|
|
finishCountdown.resetTimer();
|
|
multiFileFinishOutstanding = true;
|
|
prepareScexCmd(cmdTyped, {cmdBuf.data(), cmdBuf.size()}, rawPacketLen,
|
|
{commandData + 1, commandDataLen - 1}, tempCheck);
|
|
updatePeriodicReply(true, deviceCommand);
|
|
break;
|
|
}
|
|
case (ALL_CELLS_CMD): {
|
|
finishCountdown.setTimeout(LONG_CD);
|
|
// countdown starts
|
|
finishCountdown.resetTimer();
|
|
multiFileFinishOutstanding = true;
|
|
prepareScexCmd(cmdTyped, {cmdBuf.data(), cmdBuf.size()}, rawPacketLen,
|
|
{commandData + 1, commandDataLen - 1}, tempCheck);
|
|
updatePeriodicReply(true, deviceCommand);
|
|
break;
|
|
}
|
|
default: {
|
|
return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED;
|
|
}
|
|
}
|
|
commandActive = true;
|
|
rawPacket = cmdBuf.data();
|
|
return OK;
|
|
}
|
|
|
|
void ScexDeviceHandler::fillCommandAndReplyMap() {
|
|
insertInCommandAndReplyMap(scex::Cmds::PING, 5, nullptr, 0, false, false, 0, &finishCountdown);
|
|
insertInCommandAndReplyMap(scex::Cmds::ION_CMD, 3, nullptr, 0, false, false, 0, &finishCountdown);
|
|
insertInCommandAndReplyMap(scex::Cmds::TEMP_CMD, 3, nullptr, 0, false, false, 0,
|
|
&finishCountdown);
|
|
insertInCommandAndReplyMap(scex::Cmds::EXP_STATUS_CMD, 3, nullptr, 0, false, false, 0,
|
|
&finishCountdown);
|
|
|
|
insertInCommandAndReplyMap(scex::Cmds::ALL_CELLS_CMD, 0, nullptr, 0, true, false,
|
|
scex::Cmds::ALL_CELLS_CMD, &finishCountdown);
|
|
insertInCommandAndReplyMap(scex::Cmds::ONE_CELL, 0, nullptr, 0, true, false, scex::Cmds::ONE_CELL,
|
|
&finishCountdown);
|
|
insertInCommandAndReplyMap(scex::Cmds::FRAM, 0, nullptr, 0, true, false, scex::Cmds::FRAM,
|
|
&finishCountdown);
|
|
|
|
insertInReplyMap(scex::Cmds::ERROR_REPLY, 3);
|
|
}
|
|
|
|
ReturnValue_t ScexDeviceHandler::scanForReply(const uint8_t* start, size_t remainingSize,
|
|
DeviceCommandId_t* foundId, size_t* foundLen) {
|
|
size_t len = remainingSize;
|
|
ReturnValue_t result = helper.deSerialize(&start, &len);
|
|
|
|
if (result == ScexHelper::INVALID_CRC) {
|
|
sif::warning << "ScexDeviceHandler::scanForReply: CRC invalid" << std::endl;
|
|
*foundLen = remainingSize;
|
|
} else {
|
|
result = handleValidReply(remainingSize, foundId, foundLen);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
ReturnValue_t ScexDeviceHandler::handleValidReply(size_t remSize, DeviceCommandId_t* foundId,
|
|
size_t* foundLen) {
|
|
using namespace scex;
|
|
ReturnValue_t result = OK;
|
|
|
|
switch (helper.getCmd()) {
|
|
case (FRAM): {
|
|
if (debugMode) {
|
|
uint32_t remainingMillis = finishCountdown.getRemainingMillis();
|
|
|
|
sif::info << "ScexDeviceHandler::handleValidReply: RemMillis: " << remainingMillis
|
|
<< std::endl;
|
|
}
|
|
result = APERIODIC_REPLY;
|
|
break;
|
|
}
|
|
case (ONE_CELL): {
|
|
result = APERIODIC_REPLY;
|
|
break;
|
|
}
|
|
case (ALL_CELLS_CMD): {
|
|
result = APERIODIC_REPLY;
|
|
break;
|
|
}
|
|
default: {
|
|
break;
|
|
}
|
|
}
|
|
if (result == APERIODIC_REPLY and multiFileFinishOutstanding) {
|
|
finishAction(true, helper.getCmd(), OK);
|
|
multiFileFinishOutstanding = false;
|
|
}
|
|
|
|
*foundId = helper.getCmd();
|
|
*foundLen = remSize;
|
|
return result;
|
|
}
|
|
|
|
ReturnValue_t ScexDeviceHandler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t* packet) {
|
|
using namespace scex;
|
|
|
|
ReturnValue_t status = OK;
|
|
auto oneFileHandler = [&](std::string cmdName) {
|
|
auto activeSd = sdcMan.getActiveSdCard();
|
|
if (not activeSd) {
|
|
return HasFileSystemIF::FILESYSTEM_INACTIVE;
|
|
}
|
|
fileId = date_time_string();
|
|
std::ostringstream oss;
|
|
auto prefix = sdcMan.getCurrentMountPrefix();
|
|
oss << prefix << "/scex/scex-" << cmdName << fileId << ".bin";
|
|
fileName = oss.str();
|
|
ofstream out(fileName, ofstream::binary);
|
|
if (out.bad()) {
|
|
sif::error << "ScexDeviceHandler::interpretDeviceReply: Could not open file " << fileName
|
|
<< std::endl;
|
|
return FAILED;
|
|
}
|
|
out << helper;
|
|
return OK;
|
|
};
|
|
auto multiFileHandler = [&](std::string cmdName) {
|
|
if ((helper.getPacketCounter() == 1) or (not fileNameSet)) {
|
|
auto activeSd = sdcMan.getActiveSdCard();
|
|
if (not activeSd) {
|
|
return HasFileSystemIF::FILESYSTEM_INACTIVE;
|
|
}
|
|
fileId = date_time_string();
|
|
std::ostringstream oss;
|
|
auto prefix = sdcMan.getCurrentMountPrefix();
|
|
oss << prefix << "/scex/scex-" << cmdName << fileId << ".bin";
|
|
fileName = oss.str();
|
|
fileNameSet = true;
|
|
ofstream out(fileName, ofstream::binary);
|
|
if (out.bad()) {
|
|
sif::error << "ScexDeviceHandler::handleValidReply: Could not open file " << fileName
|
|
<< std::endl;
|
|
return FAILED;
|
|
}
|
|
out << helper;
|
|
} else {
|
|
ofstream out(fileName,
|
|
ofstream::binary | ofstream::app); // append
|
|
if (out.bad()) {
|
|
sif::error << "ScexDeviceHandler::handleValidReply: Could not open file " << fileName
|
|
<< std::endl;
|
|
return FAILED;
|
|
}
|
|
out << helper;
|
|
}
|
|
return OK;
|
|
};
|
|
id = helper.getCmd();
|
|
switch (id) {
|
|
case (PING): {
|
|
status = oneFileHandler("ping_");
|
|
break;
|
|
}
|
|
case (ION_CMD): {
|
|
status = oneFileHandler("ion_");
|
|
break;
|
|
}
|
|
case (TEMP_CMD): {
|
|
status = oneFileHandler("temp_");
|
|
break;
|
|
}
|
|
case (EXP_STATUS_CMD): {
|
|
status = oneFileHandler("exp_status_");
|
|
break;
|
|
}
|
|
case (FRAM): {
|
|
status = multiFileHandler("fram_");
|
|
break;
|
|
}
|
|
case (ONE_CELL): {
|
|
status = multiFileHandler("one_cell_");
|
|
break;
|
|
}
|
|
case (ALL_CELLS_CMD): {
|
|
status = multiFileHandler("multi_cell_");
|
|
break;
|
|
}
|
|
default:
|
|
// Unknown DeviceCommand
|
|
return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED;
|
|
}
|
|
if (helper.getPacketCounter() == helper.getTotalPacketCounter()) {
|
|
reader.finish();
|
|
commandActive = false;
|
|
if (id != PING) {
|
|
fileNameSet = false;
|
|
}
|
|
if (id == FRAM or id == ALL_CELLS_CMD or id == ONE_CELL) {
|
|
triggerEvent(MULTI_PACKET_COMMAND_DONE, id);
|
|
updatePeriodicReply(false, id);
|
|
}
|
|
}
|
|
if (debugMode) {
|
|
uint32_t remainingMillis = finishCountdown.getRemainingMillis();
|
|
sif::info << __FILE__ << __func__ << "(" << __LINE__ << ") RemMillis: " << remainingMillis
|
|
<< std::endl;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
void ScexDeviceHandler::performOperationHook() {
|
|
uint32_t remainingMillis = finishCountdown.getRemainingMillis();
|
|
if (commandActive and finishCountdown.hasTimedOut()) {
|
|
triggerEvent(scex::EXPERIMENT_TIMEDOUT, currCmd, 0);
|
|
reader.finish();
|
|
sif::warning << "ScexDeviceHandler::scanForReply: Reader timeout; RemMillis: "
|
|
<< remainingMillis << std::endl;
|
|
fileNameSet = false;
|
|
commandActive = false;
|
|
}
|
|
}
|
|
|
|
uint32_t ScexDeviceHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) { return OK; }
|
|
|
|
ReturnValue_t ScexDeviceHandler::getSwitches(const uint8_t** switches, uint8_t* numberOfSwitches) {
|
|
if (switchId) {
|
|
*numberOfSwitches = 1;
|
|
*switches = &switchId.value();
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
ReturnValue_t ScexDeviceHandler::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
|
LocalDataPoolManager& poolManager) {
|
|
return OK;
|
|
}
|
|
|
|
std::string ScexDeviceHandler::date_time_string() {
|
|
using namespace std;
|
|
string date_time;
|
|
Clock::TimeOfDay_t tod;
|
|
Clock::getDateAndTime(&tod);
|
|
ostringstream oss(std::ostringstream::ate);
|
|
|
|
if (tod.hour < 10) {
|
|
oss << tod.year << tod.month << tod.day << "_0" << tod.hour;
|
|
} else {
|
|
oss << tod.year << tod.month << tod.day << "_" << tod.hour;
|
|
}
|
|
if (tod.minute < 10) {
|
|
oss << 0 << tod.minute;
|
|
|
|
} else {
|
|
oss << tod.minute;
|
|
}
|
|
if (tod.second < 10) {
|
|
oss << 0 << tod.second;
|
|
} else {
|
|
oss << tod.second;
|
|
}
|
|
|
|
date_time = oss.str();
|
|
|
|
return date_time;
|
|
}
|
|
|
|
void ScexDeviceHandler::modeChanged() {}
|
|
|
|
void ScexDeviceHandler::setPowerSwitcher(PowerSwitchIF& powerSwitcher, power::Switch_t switchId) {
|
|
DeviceHandlerBase::setPowerSwitcher(&powerSwitcher);
|
|
this->switchId = switchId;
|
|
}
|
|
|
|
ReturnValue_t ScexDeviceHandler::initializeAfterTaskCreation() {
|
|
auto mntPrefix = sdcMan.getCurrentMountPrefix();
|
|
std::filesystem::path fullFilePath = mntPrefix;
|
|
fullFilePath /= "scex";
|
|
bool fileExists = std::filesystem::exists(fullFilePath);
|
|
|
|
if (not fileExists) {
|
|
std::filesystem::create_directory(fullFilePath);
|
|
}
|
|
return DeviceHandlerBase::initializeAfterTaskCreation();
|
|
}
|