Merge remote-tracking branch 'origin/v3.0.0-dev' into core-ctrl-dir-listing-fsm
All checks were successful
EIVE/eive-obsw/pipeline/pr-v3.0.0-dev This commit looks good

This commit is contained in:
Robin Müller 2023-06-09 14:24:42 +02:00
commit 3bdbc67e0d
Signed by: muellerr
GPG Key ID: A649FB78196E3849
13 changed files with 147 additions and 26 deletions

View File

@ -20,6 +20,8 @@ will consitute of a breaking change warranting a new major release:
# [v3.0.0] to be released # [v3.0.0] to be released
- `eive-tmtc` version v4.0.0
## Changed ## Changed
- Adapt EM configuration to include all GomSpace PCDU devices except the ACU. For the ACU - Adapt EM configuration to include all GomSpace PCDU devices except the ACU. For the ACU
@ -55,7 +57,9 @@ will consitute of a breaking change warranting a new major release:
commands. commands.
- The Directory Listing direct dumper now has a state machine to stagger the directory listing dump. - 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. 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 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.
## Added ## Added
@ -66,9 +70,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
@ -102,6 +109,7 @@ 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
# [v2.0.5] 2023-05-11 # [v2.0.5] 2023-05-11

2
fsfw

@ -1 +1 @@
Subproject commit b442ca09b91d0cfdc6acd5a30349a25c4051972c 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,21 @@ void AcsBoardPolling::gyroAdisHandler(GyroAdis& gyro) {
gyro.replyResult = returnvalue::FAILED; gyro.replyResult = returnvalue::FAILED;
return; return;
} }
uint16_t decRateReadBack = (rawReply[10] << 8) | rawReply[11];
sif::debug << "AcsPollingTask: DEC rate configuration. Read " << decRateReadBack
<< ", expected " << decRate << std::endl;
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

@ -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

@ -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);

2
tmtc

@ -1 +1 @@
Subproject commit 6182369e4f40872c5c26e59be25d5fa79339176a Subproject commit 8804a4e8e9fce1d45fcf62314affb791114d1517