Merge remote-tracking branch 'origin/main' into relax-sus-fdir
Some checks are pending
EIVE/eive-obsw/pipeline/head Build started...
EIVE/eive-obsw/pipeline/pr-main This commit looks good

This commit is contained in:
Robin Müller 2023-06-13 07:49:28 +02:00
commit 5e79293d38
No known key found for this signature in database
GPG Key ID: 11D4952C8CCEF814
22 changed files with 266 additions and 55 deletions

View File

@ -26,7 +26,9 @@ will consitute of a breaking change warranting a new major release:
sensible raw values most of the time. Some further testing is necessary, but some changes in the sensible raw values most of the time. Some further testing is necessary, but some changes in the
code should cause the SUS devices to remain healthy for now. code should cause the SUS devices to remain healthy for now.
# [v3.0.0] to be released # [v3.0.0] 2023-06-11
- `eive-tmtc` version v4.0.0
## Changed ## Changed
@ -61,6 +63,13 @@ will consitute of a breaking change warranting a new major release:
only be used to cancel a transfer. only be used to cancel a transfer.
- Handling of multiple RWs in the ACS Controller is improved and can be changed by parameter - Handling of multiple RWs in the ACS Controller is improved and can be changed by parameter
commands. commands.
- The Directory Listing direct dumper now has a state machine to stagger the directory listing dump.
This is required because very large dumps will overload the queue capacities in the framework.
- The PUS Service 8 now has larger queue sizes to handle more action replies. The PUS Service 1
also has a larger queue size to handle a lot of step replies now.
- Moved PDU `vcc` and `vbat` variable from auxiliary dataset to core dataset.
- Tweak TCP/IP configuration: Only the TCP server will be included on the EM. For the FM, no
TCP/IP servers will be included by default.
## Added ## Added
@ -71,9 +80,12 @@ will consitute of a breaking change warranting a new major release:
- IMTQ HK sets - IMTQ HK sets
- IMTQ dummy now handles power switch - IMTQ dummy now handles power switch
- Added some new ACS parameters - Added some new ACS parameters
- Enabled decimation filter for the ADIS GYRs
- Enabled second low-pass filter for L3GD20H GYRs
## Fixed ## Fixed
- CFDP low level protocol bugfix. Requires `fsfw` update and `tmtc` update.
- Compile fix if SCEX is compiled for the EM. - Compile fix if SCEX is compiled for the EM.
- Set up Rad Sensor chip select even for EM to avoid SPI bus issues. - Set up Rad Sensor chip select even for EM to avoid SPI bus issues.
- Correct ADIS Gyroscope type configuration for the EM, where the 16507 type is used instead of the - Correct ADIS Gyroscope type configuration for the EM, where the 16507 type is used instead of the
@ -107,6 +119,8 @@ will consitute of a breaking change warranting a new major release:
quaternion. quaternion.
- Various fixes for the pointing modes of the `ACS Controller`. All modes should work now as - Various fixes for the pointing modes of the `ACS Controller`. All modes should work now as
intended. intended.
- The variance for the ADIS GYRs now represents the used `-3` version and not the `-1` version
- CFDP funnel did not route packets to live channel VC0
# [v2.0.5] 2023-05-11 # [v2.0.5] 2023-05-11

View File

@ -79,6 +79,13 @@ else()
set(INIT_VAL 1) set(INIT_VAL 1)
set(OBSW_STAR_TRACKER_GROUND_CONFIG 0) set(OBSW_STAR_TRACKER_GROUND_CONFIG 0)
endif() endif()
set(OBSW_ADD_TMTC_TCP_SERVER
${OBSW_Q7S_EM}
CACHE STRING "Add TCP TMTC Server")
set(OBSW_ADD_TMTC_UDP_SERVER
0
CACHE STRING "Add UDP TMTC Server")
set(OBSW_ADD_MGT set(OBSW_ADD_MGT
${INIT_VAL} ${INIT_VAL}
CACHE STRING "Add MGT module") CACHE STRING "Add MGT module")

View File

@ -67,8 +67,8 @@
// because UDP packets are not allowed in the VPN // because UDP packets are not allowed in the VPN
// This will cause the OBSW to initialize the TMTC bridge responsible for exchanging data with the // This will cause the OBSW to initialize the TMTC bridge responsible for exchanging data with the
// CCSDS IP Cores. // CCSDS IP Cores.
#define OBSW_ADD_TMTC_TCP_SERVER 1 #define OBSW_ADD_TMTC_TCP_SERVER @OBSW_ADD_TMTC_TCP_SERVER@
#define OBSW_ADD_TMTC_UDP_SERVER 1 #define OBSW_ADD_TMTC_UDP_SERVER @OBSW_ADD_TMTC_UDP_SERVER@
// Can be used to switch device to NORMAL mode immediately // Can be used to switch device to NORMAL mode immediately
#define OBSW_SWITCH_TO_NORMAL_MODE_AFTER_STARTUP 0 #define OBSW_SWITCH_TO_NORMAL_MODE_AFTER_STARTUP 0

View File

@ -112,6 +112,9 @@ void CoreController::performControlOperation() {
sdStateMachine(); sdStateMachine();
performMountedSdCardOperations(); performMountedSdCardOperations();
readHkData(); readHkData();
if (dumpContext.active) {
dirListingDumpHandler();
}
if (shellCmdIsExecuting) { if (shellCmdIsExecuting) {
bool replyReceived = false; bool replyReceived = false;
@ -1038,7 +1041,6 @@ ReturnValue_t CoreController::actionListDirectoryDumpDirectly(ActionId_t actionI
return returnvalue::FAILED; return returnvalue::FAILED;
} }
} }
std::array<uint8_t, 1024> dirListingBuf{};
dirListingBuf[8] = parser.compressionOptionSet(); dirListingBuf[8] = parser.compressionOptionSet();
// First four bytes reserved for segment index. One byte for compression option information // First four bytes reserved for segment index. One byte for compression option information
std::strcpy(reinterpret_cast<char *>(dirListingBuf.data() + 2 * sizeof(uint32_t) + 1), repoName); std::strcpy(reinterpret_cast<char *>(dirListingBuf.data() + 2 * sizeof(uint32_t) + 1), repoName);
@ -1047,38 +1049,47 @@ ReturnValue_t CoreController::actionListDirectoryDumpDirectly(ActionId_t actionI
return returnvalue::FAILED; return returnvalue::FAILED;
} }
std::error_code e; std::error_code e;
size_t totalFileSize = std::filesystem::file_size(LIST_DIR_DUMP_WORK_FILE, e); dumpContext.totalFileSize = std::filesystem::file_size(LIST_DIR_DUMP_WORK_FILE, e);
uint32_t segmentIdx = 0; dumpContext.segmentIdx = 0;
size_t dumpedBytes = 0; dumpContext.dumpedBytes = 0;
size_t nextDumpLen = 0; size_t nextDumpLen = 0;
size_t dummy = 0; size_t dummy = 0;
size_t maxDumpLen = dirListingBuf.size() - 2 * sizeof(uint32_t) - 1 - repoNameLen - 1; dumpContext.maxDumpLen = dirListingBuf.size() - 2 * sizeof(uint32_t) - 1 - repoNameLen - 1;
size_t listingDataOffset = 2 * sizeof(uint32_t) + 1 + repoNameLen + 1; dumpContext.listingDataOffset = 2 * sizeof(uint32_t) + 1 + repoNameLen + 1;
uint32_t chunks = totalFileSize / maxDumpLen; uint32_t chunks = dumpContext.totalFileSize / dumpContext.maxDumpLen;
if (totalFileSize % maxDumpLen != 0) { if (dumpContext.totalFileSize % dumpContext.maxDumpLen != 0) {
chunks++; chunks++;
} }
SerializeAdapter::serialize(&chunks, dirListingBuf.data() + sizeof(uint32_t), &dummy, SerializeAdapter::serialize(&chunks, dirListingBuf.data() + sizeof(uint32_t), &dummy,
dirListingBuf.size() - sizeof(uint32_t), dirListingBuf.size() - sizeof(uint32_t),
SerializeIF::Endianness::NETWORK); SerializeIF::Endianness::NETWORK);
while (dumpedBytes < totalFileSize) { while (dumpContext.dumpedBytes < dumpContext.totalFileSize) {
ifile.seekg(dumpedBytes, std::ios::beg); ifile.seekg(dumpContext.dumpedBytes, std::ios::beg);
nextDumpLen = maxDumpLen; nextDumpLen = dumpContext.maxDumpLen;
if (totalFileSize - dumpedBytes < maxDumpLen) { if (dumpContext.totalFileSize - dumpContext.dumpedBytes < dumpContext.maxDumpLen) {
nextDumpLen = totalFileSize - dumpedBytes; nextDumpLen = dumpContext.totalFileSize - dumpContext.dumpedBytes;
} }
SerializeAdapter::serialize(&segmentIdx, dirListingBuf.data(), &dummy, dirListingBuf.size(), SerializeAdapter::serialize(&dumpContext.segmentIdx, dirListingBuf.data(), &dummy,
SerializeIF::Endianness::NETWORK); dirListingBuf.size(), SerializeIF::Endianness::NETWORK);
ifile.read(reinterpret_cast<char *>(dirListingBuf.data() + listingDataOffset), nextDumpLen); ifile.read(reinterpret_cast<char *>(dirListingBuf.data() + dumpContext.listingDataOffset),
nextDumpLen);
result = actionHelper.reportData(commandedBy, actionId, dirListingBuf.data(), result = actionHelper.reportData(commandedBy, actionId, dirListingBuf.data(),
listingDataOffset + nextDumpLen); dumpContext.listingDataOffset + nextDumpLen);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
// Remove work file when we are done // Remove work file when we are done
std::filesystem::remove(LIST_DIR_DUMP_WORK_FILE, e); std::filesystem::remove(LIST_DIR_DUMP_WORK_FILE, e);
return result; return result;
} }
segmentIdx++; dumpContext.segmentIdx++;
dumpedBytes += nextDumpLen; dumpContext.dumpedBytes += nextDumpLen;
// Dump takes multiple task cycles, so cache the dump state and continue dump the next cycles.
if (dumpContext.segmentIdx == 10) {
dumpContext.active = true;
dumpContext.firstDump = true;
dumpContext.commander = commandedBy;
dumpContext.actionId = actionId;
return returnvalue::OK;
}
} }
// Remove work file when we are done // Remove work file when we are done
std::filesystem::remove(LIST_DIR_DUMP_WORK_FILE, e); std::filesystem::remove(LIST_DIR_DUMP_WORK_FILE, e);
@ -2346,6 +2357,54 @@ MessageQueueId_t CoreController::getCommandQueue() const {
return ExtendedControllerBase::getCommandQueue(); return ExtendedControllerBase::getCommandQueue();
} }
void CoreController::dirListingDumpHandler() {
if (dumpContext.firstDump) {
dumpContext.firstDump = false;
return;
}
size_t nextDumpLen = 0;
size_t dummy = 0;
ReturnValue_t result;
std::error_code e;
std::ifstream ifile(LIST_DIR_DUMP_WORK_FILE, std::ios::binary);
if (ifile.bad()) {
return;
}
while (dumpContext.dumpedBytes < dumpContext.totalFileSize) {
ifile.seekg(dumpContext.dumpedBytes, std::ios::beg);
nextDumpLen = dumpContext.maxDumpLen;
if (dumpContext.totalFileSize - dumpContext.dumpedBytes < dumpContext.maxDumpLen) {
nextDumpLen = dumpContext.totalFileSize - dumpContext.dumpedBytes;
}
SerializeAdapter::serialize(&dumpContext.segmentIdx, dirListingBuf.data(), &dummy,
dirListingBuf.size(), SerializeIF::Endianness::NETWORK);
ifile.read(reinterpret_cast<char *>(dirListingBuf.data() + dumpContext.listingDataOffset),
nextDumpLen);
result =
actionHelper.reportData(dumpContext.commander, dumpContext.actionId, dirListingBuf.data(),
dumpContext.listingDataOffset + nextDumpLen);
if (result != returnvalue::OK) {
// Remove work file when we are done
std::filesystem::remove(LIST_DIR_DUMP_WORK_FILE, e);
dumpContext.active = false;
actionHelper.finish(false, dumpContext.commander, dumpContext.actionId, result);
return;
}
dumpContext.segmentIdx++;
dumpContext.dumpedBytes += nextDumpLen;
// Dump takes multiple task cycles, so cache the dump state and continue dump the next cycles.
if (dumpContext.segmentIdx == 10) {
break;
}
}
if (dumpContext.dumpedBytes >= dumpContext.totalFileSize) {
actionHelper.finish(true, dumpContext.commander, dumpContext.actionId, result);
dumpContext.active = false;
// Remove work file when we are done
std::filesystem::remove(LIST_DIR_DUMP_WORK_FILE, e);
}
}
bool CoreController::isNumber(const std::string &s) { bool CoreController::isNumber(const std::string &s) {
return !s.empty() && std::find_if(s.begin(), s.end(), return !s.empty() && std::find_if(s.begin(), s.end(),
[](unsigned char c) { return !std::isdigit(c); }) == s.end(); [](unsigned char c) { return !std::isdigit(c); }) == s.end();

View File

@ -177,6 +177,20 @@ class CoreController : public ExtendedControllerBase, public ReceivesParameterMe
DeviceCommandId_t actionId; DeviceCommandId_t actionId;
} sdCommandingInfo; } sdCommandingInfo;
struct DirListingDumpContext {
bool active;
bool firstDump;
size_t dumpedBytes;
size_t totalFileSize;
size_t listingDataOffset;
size_t maxDumpLen;
uint32_t segmentIdx;
MessageQueueId_t commander = MessageQueueIF::NO_QUEUE;
DeviceCommandId_t actionId;
};
std::array<uint8_t, 1024> dirListingBuf{};
DirListingDumpContext dumpContext{};
RebootFile rebootFile = {}; RebootFile rebootFile = {};
CommandExecutor cmdExecutor; CommandExecutor cmdExecutor;
@ -274,6 +288,7 @@ class CoreController : public ExtendedControllerBase, public ReceivesParameterMe
void rewriteRebootFile(RebootFile file); void rewriteRebootFile(RebootFile file);
void announceBootCounts(); void announceBootCounts();
void readHkData(); void readHkData();
void dirListingDumpHandler();
bool isNumber(const std::string& s); bool isNumber(const std::string& s);
}; };

View File

@ -140,6 +140,7 @@ void ObjectFactory::produce(void* args) {
#if OBSW_TM_TO_PTME == 1 #if OBSW_TM_TO_PTME == 1
if (ccsdsArgs.liveDestination != nullptr) { if (ccsdsArgs.liveDestination != nullptr) {
pusFunnel->addLiveDestination("VC0 LIVE TM", *ccsdsArgs.liveDestination, 0); pusFunnel->addLiveDestination("VC0 LIVE TM", *ccsdsArgs.liveDestination, 0);
cfdpFunnel->addLiveDestination("VC0 LIVE TM", *ccsdsArgs.liveDestination, 0);
} }
#endif #endif
#endif /* OBSW_ADD_CCSDS_IP_CORES == 1 */ #endif /* OBSW_ADD_CCSDS_IP_CORES == 1 */

View File

@ -97,6 +97,7 @@ void ObjectFactory::produce(void* args) {
#if OBSW_TM_TO_PTME == 1 #if OBSW_TM_TO_PTME == 1
if (ccsdsArgs.liveDestination != nullptr) { if (ccsdsArgs.liveDestination != nullptr) {
pusFunnel->addLiveDestination("VC0 LIVE TM", *ccsdsArgs.liveDestination, 0); pusFunnel->addLiveDestination("VC0 LIVE TM", *ccsdsArgs.liveDestination, 0);
cfdpFunnel->addLiveDestination("VC0 LIVE TM", *ccsdsArgs.liveDestination, 0);
} }
#endif #endif
#endif /* OBSW_ADD_CCSDS_IP_CORES == 1 */ #endif /* OBSW_ADD_CCSDS_IP_CORES == 1 */

View File

@ -58,7 +58,9 @@ static constexpr uint32_t CFDP_STORE_QUEUE_SIZE = 300;
static constexpr uint32_t MAX_PUS_FUNNEL_QUEUE_DEPTH = 100; static constexpr uint32_t MAX_PUS_FUNNEL_QUEUE_DEPTH = 100;
static constexpr uint32_t MAX_CFDP_FUNNEL_QUEUE_DEPTH = 80; static constexpr uint32_t MAX_CFDP_FUNNEL_QUEUE_DEPTH = 80;
static constexpr uint32_t VERIFICATION_SERVICE_QUEUE_DEPTH = 120;
static constexpr uint32_t HK_SERVICE_QUEUE_DEPTH = 60; static constexpr uint32_t HK_SERVICE_QUEUE_DEPTH = 60;
static constexpr uint32_t ACTION_SERVICE_QUEUE_DEPTH = 60;
static constexpr uint32_t MAX_STORED_CMDS_UDP = 150; static constexpr uint32_t MAX_STORED_CMDS_UDP = 150;
static constexpr uint32_t MAX_STORED_CMDS_TCP = 180; static constexpr uint32_t MAX_STORED_CMDS_TCP = 180;

View File

@ -19,7 +19,7 @@ struct DummyCfg {
bool addTempSensorDummies = true; bool addTempSensorDummies = true;
bool addRtdComIFDummy = true; bool addRtdComIFDummy = true;
bool addPlocDummies = true; bool addPlocDummies = true;
bool addCamSwitcherDummy = true; bool addCamSwitcherDummy = false;
}; };
void createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitch, GpioIF* gpioIF, bool enableHkSets); void createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitch, GpioIF* gpioIF, bool enableHkSets);

2
fsfw

@ -1 +1 @@
Subproject commit 5eb9ee8bc1e6f8640cbea46febd11e4b92241881 Subproject commit 5322de059916efcf874b10ccc766b46e53d2470b

View File

@ -113,6 +113,7 @@ ReturnValue_t AcsBoardPolling::sendMessage(CookieIF* cookie, const uint8_t* send
if (req->mode != adis.mode) { if (req->mode != adis.mode) {
if (req->mode == acs::SimpleSensorMode::NORMAL) { if (req->mode == acs::SimpleSensorMode::NORMAL) {
adis.type = req->type; adis.type = req->type;
adis.decRate = req->cfg.decRateReg;
// The initial countdown is handled by the device handler now. // The initial countdown is handled by the device handler now.
// adis.countdown.setTimeout(adis1650x::START_UP_TIME); // adis.countdown.setTimeout(adis1650x::START_UP_TIME);
if (adis.type == adis1650x::Type::ADIS16507) { if (adis.type == adis1650x::Type::ADIS16507) {
@ -376,6 +377,80 @@ void AcsBoardPolling::gyroL3gHandler(GyroL3g& l3g) {
} }
} }
ReturnValue_t AcsBoardPolling::writeAdisReg(SpiCookie& cookie) {
ReturnValue_t result = returnvalue::OK;
int retval = 0;
// Prepare transfer
int fileDescriptor = 0;
std::string device = spiComIF.getSpiDev();
UnixFileGuard fileHelper(device, fileDescriptor, O_RDWR, "SpiComIF::sendMessage");
if (fileHelper.getOpenResult() != returnvalue::OK) {
return spi::OPENING_FILE_FAILED;
}
spi::SpiModes spiMode = spi::SpiModes::MODE_0;
uint32_t spiSpeed = 0;
cookie.getSpiParameters(spiMode, spiSpeed, nullptr);
spiComIF.setSpiSpeedAndMode(fileDescriptor, spiMode, spiSpeed);
cookie.assignWriteBuffer(cmdBuf.data());
cookie.setTransferSize(2);
gpioId_t gpioId = cookie.getChipSelectPin();
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
uint32_t timeoutMs = 0;
MutexIF* mutex = spiComIF.getCsMutex();
cookie.getMutexParams(timeoutType, timeoutMs);
if (mutex == nullptr) {
sif::warning << "GyroADIS16507Handler::spiSendCallback: "
"Mutex or GPIO interface invalid"
<< std::endl;
return returnvalue::FAILED;
}
size_t idx = 0;
spi_ioc_transfer* transferStruct = cookie.getTransferStructHandle();
uint64_t origTx = transferStruct->tx_buf;
uint64_t origRx = transferStruct->rx_buf;
for (idx = 0; idx < 4; idx += 2) {
result = mutex->lockMutex(timeoutType, timeoutMs);
if (result != returnvalue::OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "AcsBoardPolling: Failed to lock mutex" << std::endl;
#endif
return result;
}
// Pull SPI CS low. For now, no support for active high given
if (gpioId != gpio::NO_GPIO) {
gpioIF.pullLow(gpioId);
}
// Execute transfer
// Initiate a full duplex SPI transfer.
retval = ioctl(fileDescriptor, SPI_IOC_MESSAGE(1), cookie.getTransferStructHandle());
if (retval < 0) {
utility::handleIoctlError("SpiComIF::sendMessage: ioctl error.");
result = spi::FULL_DUPLEX_TRANSFER_FAILED;
}
#if FSFW_HAL_SPI_WIRETAPPING == 1
comIf->performSpiWiretapping(cookie);
#endif /* FSFW_LINUX_SPI_WIRETAPPING == 1 */
if (gpioId != gpio::NO_GPIO) {
gpioIF.pullHigh(gpioId);
}
mutex->unlockMutex();
transferStruct->tx_buf += 2;
transferStruct->rx_buf += 2;
if (idx < 4) {
usleep(adis1650x::STALL_TIME_MICROSECONDS);
}
}
transferStruct->tx_buf = origTx;
transferStruct->rx_buf = origRx;
cookie.setTransferSize(0);
return returnvalue::OK;
}
ReturnValue_t AcsBoardPolling::readAdisCfg(SpiCookie& cookie, size_t transferLen) { ReturnValue_t AcsBoardPolling::readAdisCfg(SpiCookie& cookie, size_t transferLen) {
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
int retval = 0; int retval = 0;
@ -455,15 +530,20 @@ void AcsBoardPolling::gyroAdisHandler(GyroAdis& gyro) {
ReturnValue_t result; ReturnValue_t result;
acs::SimpleSensorMode mode = acs::SimpleSensorMode::OFF; acs::SimpleSensorMode mode = acs::SimpleSensorMode::OFF;
bool mustPerformStartup = false; bool mustPerformStartup = false;
uint16_t decRate = 0;
{ {
MutexGuard mg(ipcLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX); MutexGuard mg(ipcLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX);
mode = gyro.mode; mode = gyro.mode;
decRate = gyro.decRate;
mustPerformStartup = gyro.performStartup; mustPerformStartup = gyro.performStartup;
} }
if (mode == acs::SimpleSensorMode::OFF) { if (mode == acs::SimpleSensorMode::OFF) {
return; return;
} }
if (mustPerformStartup) { if (mustPerformStartup) {
adis1650x::prepareWriteRegCommand(adis1650x::DEC_RATE_REG, decRate, cmdBuf.data(),
cmdBuf.size());
writeAdisReg(*gyro.cookie);
uint8_t regList[6]; uint8_t regList[6];
// Read configuration // Read configuration
regList[0] = adis1650x::DIAG_STAT_REG; regList[0] = adis1650x::DIAG_STAT_REG;
@ -491,13 +571,19 @@ void AcsBoardPolling::gyroAdisHandler(GyroAdis& gyro) {
gyro.replyResult = returnvalue::FAILED; gyro.replyResult = returnvalue::FAILED;
return; return;
} }
uint16_t decRateReadBack = (rawReply[10] << 8) | rawReply[11];
if (decRateReadBack != decRate) {
sif::warning << "AcsPollingTask: DEC rate configuration failed. Read " << decRateReadBack
<< ", expected " << decRate << std::endl;
gyro.replyResult = returnvalue::FAILED;
}
MutexGuard mg(ipcLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX); MutexGuard mg(ipcLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX);
gyro.ownReply.cfgWasSet = true; gyro.ownReply.cfgWasSet = true;
gyro.ownReply.cfg.diagStat = (rawReply[2] << 8) | rawReply[3]; gyro.ownReply.cfg.diagStat = (rawReply[2] << 8) | rawReply[3];
gyro.ownReply.cfg.filterSetting = (rawReply[4] << 8) | rawReply[5]; gyro.ownReply.cfg.filterSetting = (rawReply[4] << 8) | rawReply[5];
gyro.ownReply.cfg.rangMdl = (rawReply[6] << 8) | rawReply[7]; gyro.ownReply.cfg.rangMdl = (rawReply[6] << 8) | rawReply[7];
gyro.ownReply.cfg.mscCtrlReg = (rawReply[8] << 8) | rawReply[9]; gyro.ownReply.cfg.mscCtrlReg = (rawReply[8] << 8) | rawReply[9];
gyro.ownReply.cfg.decRateReg = (rawReply[10] << 8) | rawReply[11]; gyro.ownReply.cfg.decRateReg = decRateReadBack;
gyro.ownReply.cfg.prodId = prodId; gyro.ownReply.cfg.prodId = prodId;
gyro.ownReply.data.sensitivity = adis1650x::rangMdlToSensitivity(gyro.ownReply.cfg.rangMdl); gyro.ownReply.data.sensitivity = adis1650x::rangMdlToSensitivity(gyro.ownReply.cfg.rangMdl);
gyro.performStartup = false; gyro.performStartup = false;

View File

@ -37,6 +37,7 @@ class AcsBoardPolling : public SystemObject,
struct GyroAdis : public DevBase { struct GyroAdis : public DevBase {
adis1650x::Type type; adis1650x::Type type;
uint16_t decRate;
Countdown countdown; Countdown countdown;
acs::Adis1650XReply ownReply; acs::Adis1650XReply ownReply;
acs::Adis1650XReply readerReply; acs::Adis1650XReply readerReply;
@ -84,6 +85,8 @@ class AcsBoardPolling : public SystemObject,
void gyroAdisHandler(GyroAdis& gyro); void gyroAdisHandler(GyroAdis& gyro);
void mgmLis3Handler(MgmLis3& mgm); void mgmLis3Handler(MgmLis3& mgm);
void mgmRm3100Handler(MgmRm3100& mgm); void mgmRm3100Handler(MgmRm3100& mgm);
// This fumction configures the register as specified on p.21 of the datasheet.
ReturnValue_t writeAdisReg(SpiCookie& cookie);
// Special readout: 16us stall time between small 2 byte transfers. // Special readout: 16us stall time between small 2 byte transfers.
ReturnValue_t readAdisCfg(SpiCookie& spiCookie, size_t transferLen); ReturnValue_t readAdisCfg(SpiCookie& spiCookie, size_t transferLen);
}; };

View File

@ -15,7 +15,7 @@ GyrAdis1650XHandler::GyrAdis1650XHandler(object_id_t objectId, object_id_t devic
} }
void GyrAdis1650XHandler::doStartUp() { void GyrAdis1650XHandler::doStartUp() {
if (internalState != InternalState::STARTUP) { if (internalState == InternalState::NONE) {
internalState = InternalState::STARTUP; internalState = InternalState::STARTUP;
commandExecuted = false; commandExecuted = false;
} }
@ -24,13 +24,14 @@ void GyrAdis1650XHandler::doStartUp() {
if (not commandExecuted) { if (not commandExecuted) {
warningSwitch = true; warningSwitch = true;
breakCountdown.setTimeout(adis1650x::START_UP_TIME); breakCountdown.setTimeout(adis1650x::START_UP_TIME);
updatePeriodicReply(true, adis1650x::REPLY);
commandExecuted = true; commandExecuted = true;
} }
if (breakCountdown.hasTimedOut()) { }
updatePeriodicReply(true, adis1650x::REPLY); if (internalState == InternalState::STARTUP_DONE) {
setMode(MODE_ON); setMode(MODE_ON);
internalState = InternalState::NONE; commandExecuted = false;
} internalState = InternalState::NONE;
} }
} }
@ -61,6 +62,7 @@ ReturnValue_t GyrAdis1650XHandler::buildTransitionDeviceCommand(DeviceCommandId_
return NOTHING_TO_SEND; return NOTHING_TO_SEND;
} }
*id = adis1650x::REQUEST; *id = adis1650x::REQUEST;
adisRequest.cfg.decRateReg = adis1650x::DEC_RATE;
return preparePeriodicRequest(acs::SimpleSensorMode::NORMAL); return preparePeriodicRequest(acs::SimpleSensorMode::NORMAL);
} }
case (InternalState::SHUTDOWN): { case (InternalState::SHUTDOWN): {
@ -91,6 +93,9 @@ ReturnValue_t GyrAdis1650XHandler::scanForReply(const uint8_t *start, size_t rem
getMode() == _MODE_POWER_DOWN) { getMode() == _MODE_POWER_DOWN) {
return IGNORE_FULL_PACKET; return IGNORE_FULL_PACKET;
} }
if (internalState == InternalState::STARTUP) {
internalState = InternalState::STARTUP_DONE;
}
*foundLen = remainingSize; *foundLen = remainingSize;
if (remainingSize != sizeof(acs::Adis1650XReply)) { if (remainingSize != sizeof(acs::Adis1650XReply)) {
return returnvalue::FAILED; return returnvalue::FAILED;

View File

@ -48,7 +48,7 @@ class GyrAdis1650XHandler : public DeviceHandlerBase {
bool warningSwitch = true; bool warningSwitch = true;
enum class InternalState { NONE, STARTUP, SHUTDOWN }; enum class InternalState { NONE, STARTUP, STARTUP_DONE, SHUTDOWN };
InternalState internalState = InternalState::STARTUP; InternalState internalState = InternalState::STARTUP;
bool commandExecuted = false; bool commandExecuted = false;

View File

@ -8,11 +8,6 @@
namespace acs { namespace acs {
struct Adis1650XRequest {
SimpleSensorMode mode;
adis1650x::Type type;
};
struct Adis1650XConfig { struct Adis1650XConfig {
uint16_t diagStat; uint16_t diagStat;
uint16_t filterSetting; uint16_t filterSetting;
@ -22,6 +17,12 @@ struct Adis1650XConfig {
uint16_t prodId; uint16_t prodId;
}; };
struct Adis1650XRequest {
SimpleSensorMode mode;
adis1650x::Type type;
Adis1650XConfig cfg;
};
struct Adis1650XData { struct Adis1650XData {
double sensitivity = 0.0; double sensitivity = 0.0;
// Angular velocities in all axes (X, Y and Z) // Angular velocities in all axes (X, Y and Z)

View File

@ -52,3 +52,14 @@ double adis1650x::rangMdlToSensitivity(uint16_t rangMdl) {
} }
} }
} }
void adis1650x::prepareWriteRegCommand(uint8_t regStart, uint16_t val, uint8_t* outBuf,
size_t maxLen) {
if (maxLen < 4) {
return;
}
outBuf[0] = regStart | adis1650x::WRITE_MASK;
outBuf[1] = val & 0xff;
outBuf[2] = (regStart + 1) | adis1650x::WRITE_MASK;
outBuf[3] = (val >> 8) & 0xff;
}

View File

@ -16,6 +16,8 @@ enum class BurstModes {
}; };
size_t prepareReadCommand(const uint8_t* regList, size_t len, uint8_t* outBuf, size_t maxLen); size_t prepareReadCommand(const uint8_t* regList, size_t len, uint8_t* outBuf, size_t maxLen);
void prepareWriteRegCommand(uint8_t regStart, uint16_t val, uint8_t* outBuf, size_t maxLen);
BurstModes burstModeFromMscCtrl(uint16_t mscCtrl); BurstModes burstModeFromMscCtrl(uint16_t mscCtrl);
double rangMdlToSensitivity(uint16_t rangMdl); double rangMdlToSensitivity(uint16_t rangMdl);
@ -92,6 +94,9 @@ static constexpr size_t SENSOR_READOUT_SIZE = 20 + 2;
static constexpr uint32_t ADIS_DATASET_ID = READ_SENSOR_DATA; static constexpr uint32_t ADIS_DATASET_ID = READ_SENSOR_DATA;
static constexpr uint32_t ADIS_CFG_DATASET_ID = READ_OUT_CONFIG; static constexpr uint32_t ADIS_CFG_DATASET_ID = READ_OUT_CONFIG;
static constexpr uint16_t FILT_CTRL = 0x0000;
static constexpr uint16_t DEC_RATE = 0x00C7;
enum GlobCmds : uint8_t { enum GlobCmds : uint8_t {
FACTORY_CALIBRATION = 0b0000'0010, FACTORY_CALIBRATION = 0b0000'0010,
SENSOR_SELF_TEST = 0b0000'0100, SENSOR_SELF_TEST = 0b0000'0100,

View File

@ -93,6 +93,7 @@ ReturnValue_t CfdpHandler::handleCfdpPacket(TmTcMessage& msg) {
return INVALID_PDU_FORMAT; return INVALID_PDU_FORMAT;
} }
if (not FileDirectiveReader::checkFileDirective(pduDataField[0])) { if (not FileDirectiveReader::checkFileDirective(pduDataField[0])) {
sif::error << "CfdpHandler: Invalid PDU directive field " << pduDataField[0] << std::endl;
return INVALID_DIRECTIVE_FIELD; return INVALID_DIRECTIVE_FIELD;
} }
auto directive = static_cast<FileDirective>(pduDataField[0]); auto directive = static_cast<FileDirective>(pduDataField[0]);

View File

@ -781,9 +781,9 @@ class AcsParameters : public HasParametersIF {
/* var = sigma^2, sigma = RND*sqrt(freq), following values are RND^2 and not var as freq is /* var = sigma^2, sigma = RND*sqrt(freq), following values are RND^2 and not var as freq is
* assumed to be equal for the same class of sensors */ * assumed to be equal for the same class of sensors */
float gyr02variance[3] = {pow(3.0e-3, 2), // RND_x = 3.0e-3 deg/s/sqrt(Hz) rms float gyr02variance[3] = {pow(4.6e-3, 2), // RND_x = 3.0e-3 deg/s/sqrt(Hz) rms
pow(3.0e-3, 2), // RND_y = 3.0e-3 deg/s/sqrt(Hz) rms pow(4.6e-3, 2), // RND_y = 3.0e-3 deg/s/sqrt(Hz) rms
pow(4.3e-3, 2)}; // RND_z = 4.3e-3 deg/s/sqrt(Hz) rms pow(6.1e-3, 2)}; // RND_z = 4.3e-3 deg/s/sqrt(Hz) rms
float gyr13variance[3] = {pow(11e-3, 2), pow(11e-3, 2), pow(11e-3, 2)}; float gyr13variance[3] = {pow(11e-3, 2), pow(11e-3, 2), pow(11e-3, 2)};
uint8_t preferAdis = false; uint8_t preferAdis = false;
float gyrFilterWeight = 0.6; float gyrFilterWeight = 0.6;

View File

@ -49,6 +49,7 @@
#include "mission/system/acs/acsModeTree.h" #include "mission/system/acs/acsModeTree.h"
#include "mission/system/tcs/tcsModeTree.h" #include "mission/system/tcs/tcsModeTree.h"
#include "mission/tcs/defs.h" #include "mission/tcs/defs.h"
#include "mission/tmtc/Service15TmStorage.h"
#include "mission/tmtc/tmFilters.h" #include "mission/tmtc/tmFilters.h"
#include "objects/systemObjectList.h" #include "objects/systemObjectList.h"
#include "tmtc/pusIds.h" #include "tmtc/pusIds.h"
@ -58,15 +59,13 @@ using persTmStore::PersistentTmStores;
#if OBSW_ADD_TCPIP_SERVERS == 1 #if OBSW_ADD_TCPIP_SERVERS == 1
#if OBSW_ADD_TMTC_UDP_SERVER == 1 #if OBSW_ADD_TMTC_UDP_SERVER == 1
// UDP server includes // UDP server includes
#include "devices/gpioIds.h" #include <fsfw/osal/common/UdpTcPollingTask.h>
#include "fsfw/osal/common/UdpTcPollingTask.h" #include <fsfw/osal/common/UdpTmTcBridge.h>
#include "fsfw/osal/common/UdpTmTcBridge.h"
#endif #endif
#if OBSW_ADD_TMTC_TCP_SERVER == 1 #if OBSW_ADD_TMTC_TCP_SERVER == 1
// TCP server includes // TCP server includes
#include "fsfw/osal/common/TcpTmTcBridge.h" #include <fsfw/osal/common/TcpTmTcBridge.h>
#include "fsfw/osal/common/TcpTmTcServer.h" #include <fsfw/osal/common/TcpTmTcServer.h>
#include "mission/tmtc/Service15TmStorage.h"
#endif #endif
#endif #endif
@ -234,7 +233,8 @@ void ObjectFactory::produceGenericObjects(HealthTableIF** healthTable_, PusTmFun
// PUS service stack // PUS service stack
new Service1TelecommandVerification(objects::PUS_SERVICE_1_VERIFICATION, config::EIVE_PUS_APID, new Service1TelecommandVerification(objects::PUS_SERVICE_1_VERIFICATION, config::EIVE_PUS_APID,
pus::PUS_SERVICE_1, objects::PUS_TM_FUNNEL, 40); pus::PUS_SERVICE_1, objects::PUS_TM_FUNNEL,
config::VERIFICATION_SERVICE_QUEUE_DEPTH);
new Service2DeviceAccess(objects::PUS_SERVICE_2_DEVICE_ACCESS, config::EIVE_PUS_APID, new Service2DeviceAccess(objects::PUS_SERVICE_2_DEVICE_ACCESS, config::EIVE_PUS_APID,
pus::PUS_SERVICE_2, 3, 10); pus::PUS_SERVICE_2, 3, 10);
new Service3Housekeeping(objects::PUS_SERVICE_3_HOUSEKEEPING, config::EIVE_PUS_APID, new Service3Housekeeping(objects::PUS_SERVICE_3_HOUSEKEEPING, config::EIVE_PUS_APID,
@ -243,7 +243,7 @@ void ObjectFactory::produceGenericObjects(HealthTableIF** healthTable_, PusTmFun
PsbParams(objects::PUS_SERVICE_5_EVENT_REPORTING, config::EIVE_PUS_APID, pus::PUS_SERVICE_5), PsbParams(objects::PUS_SERVICE_5_EVENT_REPORTING, config::EIVE_PUS_APID, pus::PUS_SERVICE_5),
80, 160); 80, 160);
new Service8FunctionManagement(objects::PUS_SERVICE_8_FUNCTION_MGMT, config::EIVE_PUS_APID, new Service8FunctionManagement(objects::PUS_SERVICE_8_FUNCTION_MGMT, config::EIVE_PUS_APID,
pus::PUS_SERVICE_8, 16, 60); pus::PUS_SERVICE_8, config::ACTION_SERVICE_QUEUE_DEPTH, 16, 60);
new Service9TimeManagement( new Service9TimeManagement(
PsbParams(objects::PUS_SERVICE_9_TIME_MGMT, config::EIVE_PUS_APID, pus::PUS_SERVICE_9)); PsbParams(objects::PUS_SERVICE_9_TIME_MGMT, config::EIVE_PUS_APID, pus::PUS_SERVICE_9));

View File

@ -595,8 +595,8 @@ ReturnValue_t GomspaceDeviceHandler::parsePduHkTable(PDU::PduCoreHk& coreHk, PDU
for (uint8_t idx = 0; idx < PDU::CHANNELS_LEN; idx++) { for (uint8_t idx = 0; idx < PDU::CHANNELS_LEN; idx++) {
coreHk.voltages[idx] = as<uint16_t>(packet + 0x12 + (idx * 2)); coreHk.voltages[idx] = as<uint16_t>(packet + 0x12 + (idx * 2));
} }
auxHk.vcc.value = as<int16_t>(packet + 0x24); coreHk.vcc.value = as<int16_t>(packet + 0x24);
auxHk.vbat.value = as<int16_t>(packet + 0x26); coreHk.vbat.value = as<int16_t>(packet + 0x26);
coreHk.temperature = as<int16_t>(packet + 0x28) * 0.1; coreHk.temperature = as<int16_t>(packet + 0x28) * 0.1;
for (uint8_t idx = 0; idx < 3; idx++) { for (uint8_t idx = 0; idx < 3; idx++) {

View File

@ -404,6 +404,11 @@ class PduCoreHk : public StaticLocalDataSet<9> {
/** Battery mode: 1 = Critical, 2 = Safe, 3 = Normal, 4 = Full */ /** Battery mode: 1 = Critical, 2 = Safe, 3 = Normal, 4 = Full */
lp_var_t<uint8_t> battMode = lp_var_t<uint8_t>(sid.objectId, pool::PDU_BATT_MODE, this); lp_var_t<uint8_t> battMode = lp_var_t<uint8_t>(sid.objectId, pool::PDU_BATT_MODE, this);
lp_var_t<float> temperature = lp_var_t<float>(sid.objectId, pool::PDU_TEMPERATURE, this); lp_var_t<float> temperature = lp_var_t<float>(sid.objectId, pool::PDU_TEMPERATURE, this);
/** Measured VCC */
lp_var_t<int16_t> vcc = lp_var_t<int16_t>(sid.objectId, pool::PDU_VCC, this);
/** Measured VBAT */
lp_var_t<int16_t> vbat = lp_var_t<int16_t>(sid.objectId, pool::PDU_VBAT, this);
}; };
class PduConfig : public StaticLocalDataSet<32> { class PduConfig : public StaticLocalDataSet<32> {
@ -451,11 +456,6 @@ class PduAuxHk : public StaticLocalDataSet<36> {
PduAuxHk(object_id_t objectId, uint32_t setId) : StaticLocalDataSet(sid_t(objectId, setId)) {} PduAuxHk(object_id_t objectId, uint32_t setId) : StaticLocalDataSet(sid_t(objectId, setId)) {}
/** Measured VCC */
lp_var_t<int16_t> vcc = lp_var_t<int16_t>(sid.objectId, pool::PDU_VCC, this);
/** Measured VBAT */
lp_var_t<int16_t> vbat = lp_var_t<int16_t>(sid.objectId, pool::PDU_VBAT, this);
/** Output converter enable status */ /** Output converter enable status */
lp_vec_t<uint8_t, 3> converterEnable = lp_vec_t<uint8_t, 3> converterEnable =
lp_vec_t<uint8_t, 3>(sid.objectId, pool::PDU_CONV_EN, this); lp_vec_t<uint8_t, 3>(sid.objectId, pool::PDU_CONV_EN, this);