eive-obsw/mission/devices/GyrAdis1650XHandler.cpp
Robin Mueller e9514b1c97
All checks were successful
EIVE/eive-obsw/pipeline/pr-develop This commit looks good
new MGM polling
2023-02-27 11:44:52 +01:00

512 lines
21 KiB
C++

#include "mission/devices/GyrAdis1650XHandler.h"
#include "fsfw/action/HasActionsIF.h"
#include "fsfw/datapool/PoolReadGuard.h"
#include "mission/devices/devicedefinitions/acsPolling.h"
GyrAdis1650XHandler::GyrAdis1650XHandler(object_id_t objectId, object_id_t deviceCommunication,
CookieIF *comCookie, adis1650x::Type type)
: DeviceHandlerBase(objectId, deviceCommunication, comCookie),
adisType(type),
primaryDataset(this),
configDataset(this),
breakCountdown() {
adisRequest.type = adisType;
}
void GyrAdis1650XHandler::doStartUp() {
if (internalState != InternalState::STARTUP) {
internalState = InternalState::STARTUP;
commandExecuted = false;
}
// Initial 310 ms start up time after power-up
if (internalState == InternalState::STARTUP) {
if (not commandExecuted) {
warningSwitch = true;
breakCountdown.setTimeout(adis1650x::START_UP_TIME);
commandExecuted = true;
}
if (breakCountdown.hasTimedOut()) {
updatePeriodicReply(true, adis1650x::REPLY);
if (goToNormalMode) {
setMode(MODE_NORMAL);
} else {
setMode(MODE_ON);
}
internalState = InternalState::NONE;
}
}
}
void GyrAdis1650XHandler::doShutDown() {
if (internalState != InternalState::SHUTDOWN) {
commandExecuted = false;
primaryDataset.setValidity(false, true);
internalState = InternalState::SHUTDOWN;
}
if (internalState == InternalState::SHUTDOWN and commandExecuted) {
updatePeriodicReply(false, adis1650x::REPLY);
internalState = InternalState::NONE;
commandExecuted = false;
setMode(_MODE_POWER_DOWN);
}
}
ReturnValue_t GyrAdis1650XHandler::buildNormalDeviceCommand(DeviceCommandId_t *id) {
*id = adis1650x::REQUEST;
return preparePeriodicRequest(acs::SimpleSensorMode::NORMAL);
}
ReturnValue_t GyrAdis1650XHandler::buildTransitionDeviceCommand(DeviceCommandId_t *id) {
switch (internalState) {
case (InternalState::STARTUP): {
*id = adis1650x::REQUEST;
return preparePeriodicRequest(acs::SimpleSensorMode::NORMAL);
}
case (InternalState::SHUTDOWN): {
*id = adis1650x::REQUEST;
acs::Adis1650XRequest *request = reinterpret_cast<acs::Adis1650XRequest *>(cmdBuf.data());
request->mode = acs::SimpleSensorMode::OFF;
request->type = adisType;
return returnvalue::OK;
}
default: {
// Might be a configuration error
sif::debug << "GyroADIS16507Handler::buildTransitionDeviceCommand: "
"Unknown internal state!"
<< std::endl;
return returnvalue::OK;
}
}
return returnvalue::OK;
}
ReturnValue_t GyrAdis1650XHandler::buildCommandFromCommand(DeviceCommandId_t deviceCommand,
const uint8_t *commandData,
size_t commandDataLen) {
// switch (deviceCommand) {
// case (adis1650x::READ_OUT_CONFIG): {
// this->rawPacketLen = adis1650x::CONFIG_READOUT_SIZE;
// uint8_t regList[6] = {};
// regList[0] = adis1650x::DIAG_STAT_REG;
// regList[1] = adis1650x::FILTER_CTRL_REG;
// regList[2] = adis1650x::RANG_MDL_REG;
// regList[3] = adis1650x::MSC_CTRL_REG;
// regList[4] = adis1650x::DEC_RATE_REG;
// regList[5] = adis1650x::PROD_ID_REG;
// adis1650x::prepareReadCommand(regList, sizeof(regList), commandBuffer.data(),
// commandBuffer.size());
// this->rawPacket = commandBuffer.data();
// break;
// }
// case (adis1650x::READ_SENSOR_DATA): {
// if (breakCountdown.isBusy()) {
// // A glob command is pending and sensor data can't be read currently
// return NO_REPLY_EXPECTED;
// }
// std::memcpy(commandBuffer.data(), adis1650x::BURST_READ_ENABLE.data(),
// adis1650x::BURST_READ_ENABLE.size());
// std::memset(commandBuffer.data() + 2, 0, 10 * 2);
// this->rawPacketLen = adis1650x::SENSOR_READOUT_SIZE;
// this->rawPacket = commandBuffer.data();
// break;
// }
// TODO: Convert to special request
// case (adis1650x::SELF_TEST_SENSORS): {
// if (breakCountdown.isBusy()) {
// // Another glob command is pending
// return HasActionsIF::IS_BUSY;
// }
// prepareWriteCommand(adis1650x::GLOB_CMD, adis1650x::GlobCmds::SENSOR_SELF_TEST, 0x00);
// breakCountdown.setTimeout(adis1650x::SELF_TEST_BREAK);
// break;
// }
// case (adis1650x::SELF_TEST_MEMORY): {
// if (breakCountdown.isBusy()) {
// // Another glob command is pending
// return HasActionsIF::IS_BUSY;
// }
// prepareWriteCommand(adis1650x::GLOB_CMD, adis1650x::GlobCmds::FLASH_MEMORY_TEST, 0x00);
// breakCountdown.setTimeout(adis1650x::FLASH_MEMORY_TEST_BREAK);
// break;
// }
// case (adis1650x::UPDATE_NV_CONFIGURATION): {
// if (breakCountdown.isBusy()) {
// // Another glob command is pending
// return HasActionsIF::IS_BUSY;
// }
// prepareWriteCommand(adis1650x::GLOB_CMD, adis1650x::GlobCmds::FLASH_MEMORY_UPDATE,
// 0x00); breakCountdown.setTimeout(adis1650x::FLASH_MEMORY_UPDATE_BREAK); break;
// }
// case (adis1650x::RESET_SENSOR_CONFIGURATION): {
// if (breakCountdown.isBusy()) {
// // Another glob command is pending
// return HasActionsIF::IS_BUSY;
// }
// prepareWriteCommand(adis1650x::GLOB_CMD, adis1650x::GlobCmds::FACTORY_CALIBRATION,
// 0x00); breakCountdown.setTimeout(adis1650x::FACTORY_CALIBRATION_BREAK); break;
// }
// case (adis1650x::SW_RESET): {
// if (breakCountdown.isBusy()) {
// // Another glob command is pending
// return HasActionsIF::IS_BUSY;
// }
// prepareWriteCommand(adis1650x::GLOB_CMD, adis1650x::GlobCmds::SOFTWARE_RESET, 0x00);
// breakCountdown.setTimeout(adis1650x::SW_RESET_BREAK);
// break;
// }
// case (adis1650x::PRINT_CURRENT_CONFIGURATION): {
//#if OBSW_VERBOSE_LEVEL >= 1
// PoolReadGuard pg(&configDataset);
// sif::info << "ADIS16507 Sensor configuration: DIAG_STAT: 0x" << std::hex << std::setw(4)
// << std::setfill('0') << "0x" << configDataset.diagStatReg.value << std::endl;
// sif::info << "MSC_CTRL: " << std::hex << std::setw(4) << "0x"
// << configDataset.mscCtrlReg.value << " | FILT_CTRL: 0x"
// << configDataset.filterSetting.value << " | DEC_RATE: 0x"
// << configDataset.decRateReg.value << std::setfill(' ') << std::endl;
//#endif /* OBSW_VERBOSE_LEVEL >= 1 */
//
//}
//}
// return returnvalue::OK;
return NOTHING_TO_SEND;
}
void GyrAdis1650XHandler::fillCommandAndReplyMap() {
insertInCommandMap(adis1650x::REQUEST);
insertInReplyMap(adis1650x::REPLY, 5, nullptr, 0, true);
// insertInCommandAndReplyMap(adis1650x::READ_SENSOR_DATA, 1, &primaryDataset);
// insertInCommandAndReplyMap(adis1650x::READ_OUT_CONFIG, 1, &configDataset);
// insertInCommandAndReplyMap(adis1650x::SELF_TEST_SENSORS, 1);
// insertInCommandAndReplyMap(adis1650x::SELF_TEST_MEMORY, 1);
// insertInCommandAndReplyMap(adis1650x::UPDATE_NV_CONFIGURATION, 1);
// insertInCommandAndReplyMap(adis1650x::RESET_SENSOR_CONFIGURATION, 1);
// insertInCommandAndReplyMap(adis1650x::SW_RESET, 1);
// insertInCommandAndReplyMap(adis1650x::PRINT_CURRENT_CONFIGURATION, 1);
}
ReturnValue_t GyrAdis1650XHandler::scanForReply(const uint8_t *start, size_t remainingSize,
DeviceCommandId_t *foundId, size_t *foundLen) {
if (breakCountdown.isBusy() or getMode() == _MODE_WAIT_OFF or getMode() == _MODE_WAIT_ON) {
return IGNORE_FULL_PACKET;
}
if (remainingSize != sizeof(acs::Adis1650XReply)) {
*foundLen = remainingSize;
return returnvalue::FAILED;
}
*foundId = adis1650x::REPLY;
*foundLen = remainingSize;
return returnvalue::OK;
}
ReturnValue_t GyrAdis1650XHandler::interpretDeviceReply(DeviceCommandId_t id,
const uint8_t *packet) {
using namespace adis1650x;
const acs::Adis1650XReply *reply = reinterpret_cast<const acs::Adis1650XReply *>(packet);
if (internalState == InternalState::STARTUP and reply->cfgWasSet) {
switch (adisType) {
case (adis1650x::Type::ADIS16507): {
if (reply->cfg.prodId != adis1650x::PROD_ID_16507) {
sif::error << "GyroADIS1650XHandler::interpretDeviceReply: Invalid product ID "
<< reply->cfg.prodId << "for ADIS type 16507" << std::endl;
return returnvalue::FAILED;
}
break;
}
case (adis1650x::Type::ADIS16505): {
if (reply->cfg.prodId != adis1650x::PROD_ID_16505) {
sif::error << "GyroADIS1650XHandler::interpretDeviceReply: Invalid product ID "
<< reply->cfg.prodId << "for ADIS type 16505" << std::endl;
return returnvalue::FAILED;
}
break;
}
}
PoolReadGuard rg(&configDataset);
configDataset.setValidity(true, true);
configDataset.mscCtrlReg = reply->cfg.mscCtrlReg;
configDataset.rangMdl = reply->cfg.rangMdl;
configDataset.diagStatReg = reply->cfg.diagStat;
configDataset.filterSetting = reply->cfg.filterSetting;
configDataset.decRateReg = reply->cfg.decRateReg;
commandExecuted = true;
}
if (reply->dataWasSet) {
{
PoolReadGuard rg(&configDataset);
configDataset.diagStatReg = reply->cfg.diagStat;
}
auto sensitivity = reply->data.sensitivity;
auto accelSensitivity = reply->data.accelScaling;
PoolReadGuard pg(&primaryDataset);
primaryDataset.setValidity(true, true);
primaryDataset.angVelocX = static_cast<double>(reply->data.angVelocities[0]) * sensitivity;
primaryDataset.angVelocY = static_cast<double>(reply->data.angVelocities[1]) * sensitivity;
primaryDataset.angVelocZ = static_cast<double>(reply->data.angVelocities[2]) * sensitivity;
// TODO: Check whether we need to divide by INT16_MAX
primaryDataset.accelX = static_cast<double>(reply->data.accelerations[0]) * accelSensitivity;
primaryDataset.accelY = static_cast<double>(reply->data.accelerations[1]) * accelSensitivity;
primaryDataset.accelZ = static_cast<double>(reply->data.accelerations[2]) * accelSensitivity;
primaryDataset.temperature.value = static_cast<float>(reply->data.temperatureRaw) * 0.1;
}
return returnvalue::OK;
}
LocalPoolDataSetBase *GyrAdis1650XHandler::getDataSetHandle(sid_t sid) {
if (sid.ownerSetId == adis1650x::ADIS_DATASET_ID) {
return &primaryDataset;
} else if (sid.ownerSetId == adis1650x::ADIS_CFG_DATASET_ID) {
return &configDataset;
}
return nullptr;
}
// ReturnValue_t GyroADIS1650XHandler::handleSensorData(const uint8_t *packet) {
// using namespace adis1650x;
// BurstModes burstMode = getBurstMode();
// switch (burstMode) {
// case (BurstModes::BURST_16_BURST_SEL_1):
// case (BurstModes::BURST_32_BURST_SEL_1): {
// sif::warning << "GyroADIS1650XHandler::interpretDeviceReply: Analysis with BURST_SEL1"
// " not implemented!"
// << std::endl;
// return returnvalue::OK;
// }
// case (adis1650x::BurstModes::BURST_16_BURST_SEL_0): {
// uint16_t checksum = packet[20] << 8 | packet[21];
// // Now verify the read checksum with the expected checksum according to datasheet p. 20
// uint16_t calcChecksum = 0;
// for (size_t idx = 2; idx < 20; idx++) {
// calcChecksum += packet[idx];
// }
// if (checksum != calcChecksum) {
//#if OBSW_VERBOSE_LEVEL >= 1
// sif::warning << "GyroADIS1650XHandler::interpretDeviceReply: "
// "Invalid checksum detected!"
// << std::endl;
//#endif
// return returnvalue::FAILED;
// }
//
// ReturnValue_t result = configDataset.diagStatReg.read();
// if (result == returnvalue::OK) {
// configDataset.diagStatReg.value = packet[2] << 8 | packet[3];
// configDataset.diagStatReg.setValid(true);
// }
// configDataset.diagStatReg.commit();
//
// {
// PoolReadGuard pg(&primaryDataset);
// int16_t angVelocXRaw = packet[4] << 8 | packet[5];
// primaryDataset.angVelocX.value = static_cast<float>(angVelocXRaw) * sensitivity;
// int16_t angVelocYRaw = packet[6] << 8 | packet[7];
// primaryDataset.angVelocY.value = static_cast<float>(angVelocYRaw) * sensitivity;
// int16_t angVelocZRaw = packet[8] << 8 | packet[9];
// primaryDataset.angVelocZ.value = static_cast<float>(angVelocZRaw) * sensitivity;
//
// float accelScaling = 0;
// if (adisType == adis1650x::Type::ADIS16507) {
// accelScaling = adis1650x::ACCELEROMETER_RANGE_16507;
// } else if (adisType == adis1650x::Type::ADIS16505) {
// accelScaling = adis1650x::ACCELEROMETER_RANGE_16505;
// } else {
// sif::warning << "GyroADIS1650XHandler::handleSensorData: "
// "Unknown ADIS type"
// << std::endl;
// }
// int16_t accelXRaw = packet[10] << 8 | packet[11];
// primaryDataset.accelX.value = static_cast<float>(accelXRaw) / INT16_MAX * accelScaling;
// int16_t accelYRaw = packet[12] << 8 | packet[13];
// primaryDataset.accelY.value = static_cast<float>(accelYRaw) / INT16_MAX * accelScaling;
// int16_t accelZRaw = packet[14] << 8 | packet[15];
// primaryDataset.accelZ.value = static_cast<float>(accelZRaw) / INT16_MAX * accelScaling;
//
// int16_t temperatureRaw = packet[16] << 8 | packet[17];
// primaryDataset.temperature.value = static_cast<float>(temperatureRaw) * 0.1;
// // Ignore data counter for now
// primaryDataset.setValidity(true, true);
// }
//
// if (periodicPrintout) {
// if (debugDivider.checkAndIncrement()) {
// sif::info << "GyroADIS1650XHandler: Angular velocities in deg / s" << std::endl;
// sif::info << "X: " << primaryDataset.angVelocX.value << std::endl;
// sif::info << "Y: " << primaryDataset.angVelocY.value << std::endl;
// sif::info << "Z: " << primaryDataset.angVelocZ.value << std::endl;
// sif::info << "GyroADIS1650XHandler: Accelerations in m / s^2: " << std::endl;
// sif::info << "X: " << primaryDataset.accelX.value << std::endl;
// sif::info << "Y: " << primaryDataset.accelY.value << std::endl;
// sif::info << "Z: " << primaryDataset.accelZ.value << std::endl;
// }
// }
//
// break;
// }
// case (BurstModes::BURST_32_BURST_SEL_0): {
// break;
// }
// }
// return returnvalue::OK;
// }
uint32_t GyrAdis1650XHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) { return 6000; }
void GyrAdis1650XHandler::prepareWriteCommand(uint8_t startReg, uint8_t valueOne,
uint8_t valueTwo) {
uint8_t secondReg = startReg + 1;
startReg |= adis1650x::WRITE_MASK;
secondReg |= adis1650x::WRITE_MASK;
cmdBuf[0] = startReg;
cmdBuf[1] = valueOne;
cmdBuf[2] = secondReg;
cmdBuf[3] = valueTwo;
this->rawPacketLen = 4;
this->rawPacket = cmdBuf.data();
}
ReturnValue_t GyrAdis1650XHandler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
LocalDataPoolManager &poolManager) {
localDataPoolMap.emplace(adis1650x::ANG_VELOC_X, new PoolEntry<double>({0.0}));
localDataPoolMap.emplace(adis1650x::ANG_VELOC_Y, new PoolEntry<double>({0.0}));
localDataPoolMap.emplace(adis1650x::ANG_VELOC_Z, new PoolEntry<double>({0.0}));
localDataPoolMap.emplace(adis1650x::ACCELERATION_X, new PoolEntry<double>({0.0}));
localDataPoolMap.emplace(adis1650x::ACCELERATION_Y, new PoolEntry<double>({0.0}));
localDataPoolMap.emplace(adis1650x::ACCELERATION_Z, new PoolEntry<double>({0.0}));
localDataPoolMap.emplace(adis1650x::TEMPERATURE, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(adis1650x::DIAG_STAT_REGISTER, new PoolEntry<uint16_t>());
localDataPoolMap.emplace(adis1650x::FILTER_SETTINGS, new PoolEntry<uint8_t>());
localDataPoolMap.emplace(adis1650x::RANG_MDL, &rangMdl);
localDataPoolMap.emplace(adis1650x::MSC_CTRL_REGISTER, new PoolEntry<uint16_t>());
localDataPoolMap.emplace(adis1650x::DEC_RATE_REGISTER, new PoolEntry<uint16_t>());
poolManager.subscribeForRegularPeriodicPacket(
subdp::RegularHkPeriodicParams(primaryDataset.getSid(), false, 5.0));
return returnvalue::OK;
}
adis1650x::BurstModes GyrAdis1650XHandler::getBurstMode() {
using namespace adis1650x;
configDataset.mscCtrlReg.read();
uint16_t currentCtrlReg = configDataset.mscCtrlReg.value;
configDataset.mscCtrlReg.commit();
return adis1650x::burstModeFromMscCtrl(currentCtrlReg);
}
//#ifdef FSFW_OSAL_LINUX
// ReturnValue_t GyroADIS1650XHandler::spiSendCallback(SpiComIF *comIf, SpiCookie *cookie,
// const uint8_t *sendData, size_t sendLen,
// void *args) {
// GyroADIS1650XHandler *handler = reinterpret_cast<GyroADIS1650XHandler *>(args);
// if (handler == nullptr) {
// sif::error << "GyroADIS16507Handler::spiSendCallback: Passed handler pointer is invalid!"
// << std::endl;
// return returnvalue::FAILED;
// }
// DeviceCommandId_t currentCommand = handler->getPendingCommand();
// switch (currentCommand) {
// case (adis1650x::READ_SENSOR_DATA): {
// return comIf->performRegularSendOperation(cookie, sendData, sendLen);
// }
// case (adis1650x::READ_OUT_CONFIG):
// default: {
// ReturnValue_t result = returnvalue::OK;
// int retval = 0;
// // Prepare transfer
// int fileDescriptor = 0;
// std::string device = comIf->getSpiDev();
// UnixFileGuard fileHelper(device, fileDescriptor, O_RDWR, "SpiComIF::sendMessage");
// if (fileHelper.getOpenResult() != returnvalue::OK) {
// return SpiComIF::OPENING_FILE_FAILED;
// }
// spi::SpiModes spiMode = spi::SpiModes::MODE_0;
// uint32_t spiSpeed = 0;
// cookie->getSpiParameters(spiMode, spiSpeed, nullptr);
// comIf->setSpiSpeedAndMode(fileDescriptor, spiMode, spiSpeed);
// cookie->assignWriteBuffer(sendData);
// cookie->setTransferSize(2);
//
// gpioId_t gpioId = cookie->getChipSelectPin();
// GpioIF &gpioIF = comIf->getGpioInterface();
// MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
// uint32_t timeoutMs = 0;
// MutexIF *mutex = comIf->getCsMutex();
// cookie->getMutexParams(timeoutType, timeoutMs);
// if (mutex == nullptr) {
//#if OBSW_VERBOSE_LEVEL >= 1
// sif::warning << "GyroADIS16507Handler::spiSendCallback: "
// "Mutex or GPIO interface invalid"
// << std::endl;
// return returnvalue::FAILED;
//#endif
// }
//
// if (gpioId != gpio::NO_GPIO) {
// result = mutex->lockMutex(timeoutType, timeoutMs);
// if (result != returnvalue::OK) {
//#if FSFW_CPP_OSTREAM_ENABLED == 1
// sif::error << "SpiComIF::sendMessage: Failed to lock mutex" << std::endl;
//#endif
// return result;
// }
// }
//
// size_t idx = 0;
// spi_ioc_transfer *transferStruct = cookie->getTransferStructHandle();
// uint64_t origTx = transferStruct->tx_buf;
// uint64_t origRx = transferStruct->rx_buf;
// while (idx < sendLen) {
// // 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 = SpiComIF::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);
// }
//
// idx += 2;
// if (idx < sendLen) {
// usleep(adis1650x::STALL_TIME_MICROSECONDS);
// }
//
// transferStruct->tx_buf += 2;
// transferStruct->rx_buf += 2;
// }
// transferStruct->tx_buf = origTx;
// transferStruct->rx_buf = origRx;
// if (gpioId != gpio::NO_GPIO) {
// mutex->unlockMutex();
// }
// }
// }
// return returnvalue::OK;
// }
void GyrAdis1650XHandler::setToGoToNormalModeImmediately() { goToNormalMode = true; }
void GyrAdis1650XHandler::enablePeriodicPrintouts(bool enable, uint8_t divider) {
periodicPrintout = enable;
debugDivider.setDivider(divider);
}
ReturnValue_t GyrAdis1650XHandler::preparePeriodicRequest(acs::SimpleSensorMode mode) {
adisRequest.mode = mode;
rawPacket = reinterpret_cast<uint8_t *>(&adisRequest);
rawPacketLen = sizeof(acs::Adis1650XRequest);
return returnvalue::OK;
}