eive-obsw/mission/tmtc/CCSDSHandler.cpp
2021-09-19 12:27:48 +02:00

606 lines
17 KiB
C++

/*******************************
* FLP Flight Software Framework (FSFW)
* (c) 2016 IRS, Uni Stuttgart
*******************************/
/*
* CCSDSHandler.cpp
*
* Created on: Feb 9, 2012
* Author: baetz
*/
#include <framework/devicehandlers/DeviceHandlerIF.h>
#include <framework/objectmanager/ObjectManagerIF.h>
#include <framework/rmap/RMAPChannelIF.h>
#include <framework/serviceinterface/ServiceInterfaceStream.h>
#include <framework/tmtcservices/AcceptsTelecommandsIF.h>
#include <mission/obc/ccsdsboard/CCSDSHandler.h>
#include <math.h>
#include <config/datapool/dataPoolInit.h>
const float CCSDSHandler::DEFAULT_RATES[BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD] =
{ CCSDSHandler::DEFAULT_BYTES_PER_SECOND, CCSDSHandler::DEFAULT_BYTES_PER_SECOND,
CCSDSHandler::DEFAULT_BYTES_PER_SECOND, CCSDSHandler::DEFAULT_BYTES_PER_SECOND };
CCSDSHandler::CCSDSHandler(object_id_t setObjectId, uint8_t setSwitchId1,
uint8_t setSwitchId2, object_id_t setChannel, uint16_t setSCID,
BoardHandler::DataPoolIds setPool) :
SystemObject(setObjectId), tmPartHealth(setObjectId + 1, 0), commandQueue(), state(
STATE_IDLE), commState(SEND_WRITE), mode(MODE_OFF), submode(
SUBMODE_NONE), boardHandler((uint8_t*) frameBuffer,
sizeof(frameBuffer), setSCID, setPool), dataLinkLayer(
this->frameBuffer, boardHandler.getClcw(), 0, setSCID), frameLength(
0), channelId(setChannel), memoryHelper(this, &commandQueue), pendingWrite(
false), pendingRead(false), modeHelper(this), healthHelper(this,
setObjectId), parameterHelper(this), powerSwitcher(setSwitchId1,
setSwitchId2), switchOffWasReported(false), fdir(setObjectId,
setChannel) {
memset(this->frameBuffer, 0, sizeof(frameBuffer));
DataSet mySet;
PoolVector<float, BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD> rateRatio(
datapool::DATA_RATE_ASSIGN, &mySet, PoolVariableIF::VAR_WRITE);
for (uint8_t i = 0; i < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD;
++i) {
virtualChannels[i] = new VCGeneration(i,
BoardHandler::TM_PACKETS_PER_CALL_PER_CHANNEL);
rateLimitOverload[i] = 0;
rateRatio[i] = DEFAULT_RATES[i];
}
mySet.commit(PoolVariableIF::VALID);
//Set real-time channel to high responsiveness.
virtualChannels[0]->setIdlePacketIntervalMs(
VCGeneration::IDLE_INTERVAL_RT_CHANNEL);
}
CCSDSHandler::~CCSDSHandler() {
for (uint8_t i = 0; i < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD;
++i) {
delete virtualChannels[i];
}
}
void CCSDSHandler::printFrameBuffer(void) {
debug << "frame_buffer contains: " << std::endl;
for (uint32_t i = 0; i < this->frameLength; ++i) {
debug << "frame_buffer[" << std::dec << i << "]: " << std::hex
<< std::showbase << (uint16_t) this->frameBuffer[i] << std::dec
<< std::endl;
}
}
ReturnValue_t CCSDSHandler::packetProcessing(void) {
rateSet.read();
const float* usedRateRatios = NULL;
if (rateSet.dataRates.isValid()) {
usedRateRatios = rateSet.dataRates.value;
} else {
usedRateRatios = DEFAULT_RATES;
}
for (uint8_t i = 0; i < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD;
++i) {
//Set current cycle Limit first
uint32_t newLimit = (usedRateRatios[i]) / SENDS_PER_SECOND;
if (newLimit <= rateLimitOverload[i]) {
//Calculate new overload.
rateLimitOverload[i] -= newLimit;
//Use newLimit as current rate, VC is utilized to its current limit.
rateSet.dataRate[i] = usedRateRatios[i]; //equal to newLimit * SENDS_PER_SECOND
//Don't send anything new.
continue;
}
newLimit -= rateLimitOverload[i];
virtualChannels[i]->tmSendLimitPerCycle = newLimit;
//Send new packets.
uint32_t tempRate = virtualChannels[i]->packetProcessing();
if (tempRate > virtualChannels[i]->tmSendLimitPerCycle) {
rateLimitOverload[i] = tempRate - virtualChannels[i]->tmSendLimitPerCycle;
//VC is fully utilized, but not more. Overload will be accounted for in next cycles.
rateSet.dataRate[i] = virtualChannels[i]->tmSendLimitPerCycle * SENDS_PER_SECOND;
} else {
//Data rate extended to a Bytes/s range. Filtering is performed in controller.
rateSet.dataRate[i] = tempRate * SENDS_PER_SECOND;
rateLimitOverload[i] = 0;
}
}
rateSet.commit(PoolVariableIF::VALID);
return RETURN_OK;
}
ReturnValue_t CCSDSHandler::packetProcessingCheck(void) {
ReturnValue_t status = RETURN_FAILED;
for (uint8_t vc = 0; vc < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD;
++vc) {
status = this->virtualChannels[vc]->packetProcessingCheck();
if (status != RETURN_OK) {
error << "CCSDSHandler " << std::hex << this->getObjectId()
<< " ::packetProcessingCheck: Error on VC " << (uint16_t) vc
<< ". Error code: " << status << std::dec << std::endl;
}
}
return RETURN_OK;
}
ReturnValue_t CCSDSHandler::performOperation(void) {
readCommandQueue();
return RETURN_OK;
}
void CCSDSHandler::searchFrame() {
frameLength = this->boardHandler.findFrame();
while (frameLength != 0) {
ReturnValue_t frame_status = this->dataLinkLayer.processFrame(
frameLength);
if (frame_status != RETURN_OK) {
triggerEvent(DataLinkLayer::FRAME_PROCESSING_FAILED, frame_status,
0);
}
boardHandler.resetFrameBuffer();
frameLength = boardHandler.findFrame();
}
}
ReturnValue_t CCSDSHandler::initialize() {
PtmeIF *ptme = objectManager->get<PtmeIF>(ptmeId);
if (ptme == nullptr) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
status = boardHandler.initialize(channel);
if (status != RETURN_OK) {
return status;
}
status = modeHelper.initialize();
if (status != RETURN_OK) {
return status;
}
status = healthHelper.initialize();
if (status != HasReturnvaluesIF::RETURN_OK) {
return status;
}
status = memoryHelper.initialize();
if (status != HasReturnvaluesIF::RETURN_OK) {
return status;
}
status = parameterHelper.initialize();
if (status != HasReturnvaluesIF::RETURN_OK) {
return status;
}
status = powerSwitcher.initialize(objects::PCDU_HANDLER);
if (status != HasReturnvaluesIF::RETURN_OK) {
return status;
}
StorageManagerIF* tmStore = objectManager->get<StorageManagerIF>(
objects::TM_STORE);
status = dataLinkLayer.initialize();
if ((tmStore != NULL) && status == RETURN_OK) {
status = RETURN_OK;
for (uint8_t i = 0; i < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD;
++i) {
// this->virtualChannels[i] = objectManager->get<VCGeneration>(
// objects::CCSDS_VC_BASE + i);
if (this->virtualChannels[i] != NULL) {
this->virtualChannels[i]->setPacketStore(tmStore);
this->virtualChannels[i]->setBoardHandler(&this->boardHandler);
} else {
status = RETURN_FAILED;
}
}
} else {
status = RETURN_FAILED;
error << "CCSDSHandler " << std::hex << this->getObjectId() << std::dec
<< " ::CCSDSHandler: Configuration failed." << std::endl;
}
status = fdir.initialize();
if (status != HasReturnvaluesIF::RETURN_OK) {
return status;
}
return status;
}
void CCSDSHandler::readCommandQueue(void) {
CommandMessage commandMessage;
ReturnValue_t result = RETURN_FAILED;
while (commandQueue.receiveMessage(&commandMessage) == RETURN_OK) {
result = parameterHelper.handleParameterMessage(&commandMessage);
if (result == RETURN_OK) {
return;
}
CommandMessage reply;
reply.setReplyRejected(CommandMessage::UNKNOW_COMMAND,
commandMessage.getCommand());
commandQueue.reply(&reply);
}
}
MessageQueueId_t CCSDSHandler::getCommandQueue() const {
return commandQueue.getId();
}
void CCSDSHandler::flushTmChannels() {
for (uint8_t i = 0; i < BoardHandler::USED_VIRTUAL_CHANNELS_PER_BOARD;
++i) {
virtualChannels[i]->flush();
}
}
ReturnValue_t CCSDSHandler::handleMemoryLoad(uint32_t address,
const uint8_t* data, uint32_t size, uint8_t** dataPointer) {
if (size != 4) {
return INVALID_SIZE;
}
ReturnValue_t result = boardHandler.manualWriteToRegister(address, data);
if (result == RETURN_OK) {
pendingWrite = true;
return DO_IT_MYSELF;
}
return result;
}
ReturnValue_t CCSDSHandler::handleMemoryDump(uint32_t address, uint32_t size,
uint8_t** dataPointer, uint8_t* dumpTarget) {
if (size != 4) {
return INVALID_SIZE;
}
ReturnValue_t result = boardHandler.sendRegisterReadCommand(address);
if (result == RETURN_OK) {
pendingRead = true;
return DO_IT_MYSELF;
}
return result;
}
ReturnValue_t CCSDSHandler::checkModeCommand(Mode_t commandedMode,
Submode_t commandedSubmode, uint32_t* msToReachTheMode) {
if (state != STATE_IDLE) {
return IN_TRANSITION;
}
switch (commandedMode) {
case MODE_ON:
if ((commandedSubmode == SUBMODE_ACTIVE)
|| (commandedSubmode == SUBMODE_PASSIVE)) {
return RETURN_OK;
} else {
return INVALID_SUBMODE;
}
break;
case MODE_OFF:
if (commandedSubmode == SUBMODE_NONE) {
return RETURN_OK;
} else {
return INVALID_SUBMODE;
}
default:
return INVALID_MODE;
}
}
void CCSDSHandler::startTransition(Mode_t commandedMode,
Submode_t commandedSubmode) {
if (commandedMode == mode) {
if (mode == MODE_ON) {
state = STATE_SELECT_SUBMODE;
} else {
//Turn off switch again anyway
state = STATE_TURN_OFF;
}
} else {
switch (commandedMode) {
case MODE_ON:
state = STATE_TURN_ON;
break;
case MODE_OFF:
state = STATE_TURN_OFF;
break;
default:
//Error case. Cannot happen?
error << "CCSDSHandler::startTransition: Invalid commanded mode: "
<< commandedMode << std::endl;
return;
}
}
triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode);
}
void CCSDSHandler::getMode(Mode_t* modeReturn, Submode_t* submodeReturn) {
*modeReturn = mode;
*submodeReturn = submode;
}
void CCSDSHandler::setToExternalControl() {
healthHelper.setHealth(EXTERNAL_CONTROL);
}
void CCSDSHandler::announceMode(bool recursive) {
triggerEvent(MODE_INFO, mode, submode);
}
void CCSDSHandler::setParentQueue(MessageQueueId_t parentQueueId) {
modeHelper.setParentQueue(parentQueueId);
healthHelper.setParentQeueue(parentQueueId);
tmPartHealth.setParentQueue(parentQueueId);
}
void CCSDSHandler::doStateMachine() {
ReturnValue_t status = RETURN_FAILED;
powerSwitcher.doStateMachine();
switch (state) {
case STATE_IDLE:
//Do nothing? Do perform operation stuff?
break;
case STATE_TURN_ON:
powerSwitcher.turnOn();
modeHelper.startTimer(powerSwitcher.getSwitchDelay());
state = STATE_WAIT_ON;
break;
case STATE_WAIT_ON:
if (powerSwitcher.checkSwitchState() == RETURN_OK) {
modeHelper.startTimer(LINK_UP_DELAY_MS);
state = STATE_WAIT_LINK;
}
if (boardHandler.checkChannel() == RETURN_OK) {
boardHandler.startStateTranstion();
state = STATE_INITIALIZE_BOARD;
} else {
if (modeHelper.isTimedOut()) {
triggerEvent(MODE_TRANSITION_FAILED,
PowerSwitchIF::SWITCH_TIMEOUT, state);
setMode(MODE_OFF, SUBMODE_NONE);
}
}
break;
case STATE_WAIT_LINK:
if (boardHandler.checkAndResetChannel() == RETURN_OK) {
boardHandler.startStateTranstion();
state = STATE_INITIALIZE_BOARD;
} else {
if (modeHelper.isTimedOut()) {
triggerEvent(MODE_TRANSITION_FAILED, DeviceHandlerIF::TIMEOUT,
state);
setMode(MODE_OFF, SUBMODE_NONE);
}
}
break;
case STATE_INITIALIZE_BOARD:
status = boardHandler.initializeBoard();
switch (status) {
case RETURN_OK:
state = STATE_SELECT_SUBMODE;
break;
case BoardHandler::IN_TRANSITION:
//cannot last forever, so just wait.
break;
default:
triggerEvent(MODE_TRANSITION_FAILED, status, state);
state = STATE_TURN_OFF;
break;
}
break;
case STATE_SELECT_SUBMODE:
boardHandler.startStateTranstion();
if (modeHelper.commandedSubmode == SUBMODE_PASSIVE) {
state = STATE_WAIT_SUBMODE_PASSIVE;
} else {
state = STATE_WAIT_SUBMODE_ACTIVE;
}
break;
case STATE_WAIT_SUBMODE_PASSIVE:
//Just one wait cycle to get rid of pending TM.
state = STATE_DO_PASSIVATE;
break;
case STATE_DO_PASSIVATE:
status = boardHandler.tmPassivate();
switch (status) {
case RETURN_OK:
setMode(MODE_ON, SUBMODE_PASSIVE);
break;
case BoardHandler::IN_TRANSITION:
//cannot last forever, so just wait.
break;
default:
//If it comes here and fails then, there might be something wrong with the board.
triggerEvent(MODE_TRANSITION_FAILED, status, state);
state = STATE_TURN_OFF;
break;
}
break;
case STATE_WAIT_SUBMODE_ACTIVE:
status = boardHandler.tmActivate();
switch (status) {
case RETURN_OK:
setMode(MODE_ON, SUBMODE_ACTIVE);
break;
case BoardHandler::IN_TRANSITION:
//cannot last forever, so just wait.
break;
default:
//If it comes here and fails then, there might be something wrong with the board.
triggerEvent(MODE_TRANSITION_FAILED, status, state);
state = STATE_TURN_OFF;
break;
}
break;
case STATE_TURN_OFF:
//Passivate first. Mainly optimization for System Testbed.
boardHandler.startStateTranstion();
state = STATE_DO_PASSIVATE_OFF;
//No break
case STATE_DO_PASSIVATE_OFF:
status = boardHandler.tmPassivate();
switch (status) {
case RETURN_OK:
state = STATE_TURN_SWITCH_OFF;
break;
case BoardHandler::IN_TRANSITION:
//cannot last forever, so just wait.
break;
default:
//If it comes here and fails then, there might be something wrong with the board.
//Just turn it off.
state = STATE_TURN_SWITCH_OFF;
break;
}
break;
case STATE_TURN_SWITCH_OFF:
powerSwitcher.turnOff();
modeHelper.startTimer(powerSwitcher.getSwitchDelay());
state = STATE_WAIT_OFF;
break;
case STATE_WAIT_OFF:
if ((boardHandler.checkAndResetChannel() == RMAPChannelIF::LINK_DOWN)
|| (powerSwitcher.checkSwitchState() == RETURN_OK)) {
setMode(MODE_OFF, SUBMODE_NONE);
state = STATE_IDLE;
} else {
if (modeHelper.isTimedOut()) {
triggerEvent(MODE_TRANSITION_FAILED, status, state);
setMode(mode, submode);
}
}
break;
default:
break;
}
}
ReturnValue_t CCSDSHandler::addVirtualChannel(uint8_t virtualChannelId,
VirtualChannelReceptionIF* object) {
return this->dataLinkLayer.addVirtualChannel(virtualChannelId, object);
}
void CCSDSHandler::setMode(Mode_t newMode, Submode_t newSubmode) {
triggerEvent(MODE_INFO, newMode, newSubmode);
if (newMode == MODE_OFF) {
boardHandler.setDataPoolVaraiblesInvalid();
}
modeHelper.modeChanged(newMode, newSubmode);
state = STATE_IDLE;
mode = newMode;
submode = newSubmode;
}
Mode_t CCSDSHandler::getMode() const {
return mode;
}
Submode_t CCSDSHandler::getSubmode() const {
return submode;
}
MessageQueueId_t CCSDSHandler::getReportReceptionQueue(uint8_t virtualChannel) {
if (virtualChannel < Ptme::NUM_OF_VIRTUAL_CHANNELS) {
return virtualChannels[virtualChannel]->getReportReceptionQueue();
} else {
sif::debug << "CCSDSHandler::getReportReceptionQueue: Invalid virtual channel requested";
}
}
void CCSDSHandler::executeAllWriteCommands() {
ReturnValue_t returnValue = boardHandler.sendWriteCommands();
if (returnValue != RETURN_OK) {
triggerEvent(DeviceHandlerIF::DEVICE_SENDING_COMMAND_FAILED,
returnValue, 0);
}
if (submode == SUBMODE_ACTIVE) {
returnValue = this->packetProcessing();
if (returnValue != RETURN_OK) {
triggerEvent(DeviceHandlerIF::DEVICE_SENDING_COMMAND_FAILED,
returnValue, 1);
}
}
}
void CCSDSHandler::handleAllWriteReplies() {
ReturnValue_t returnValue = boardHandler.getWriteReplys();
if (returnValue != RETURN_OK) {
triggerEvent(DeviceHandlerIF::DEVICE_SENDING_COMMAND_FAILED,
returnValue, 0);
}
if (pendingWrite) {
memoryHelper.completeLoad(returnValue);
pendingWrite = false;
}
if (submode == SUBMODE_ACTIVE) {
returnValue = packetProcessingCheck();
} else {
this->flushTmChannels();
}
}
void CCSDSHandler::executeAllReadCommands() {
ReturnValue_t returnValue = boardHandler.sendReadCommands();
if (returnValue != RETURN_OK) {
triggerEvent(DeviceHandlerIF::DEVICE_REQUESTING_REPLY_FAILED,
returnValue, 0);
}
}
void CCSDSHandler::handleAllReadReplies() {
if ((mode == MODE_ON) && (state == STATE_IDLE)) {
ReturnValue_t returnValue = boardHandler.getReadReplys();
if (returnValue == RETURN_OK) {
searchFrame();
} else {
triggerEvent(DeviceHandlerIF::DEVICE_REQUESTING_REPLY_FAILED,
returnValue, 0);
//do nothing.
}
if (pendingRead) {
uint8_t* tempBuffer;
returnValue = boardHandler.getRegisterReadReply(&tempBuffer);
memoryHelper.completeDump(returnValue, tempBuffer,
BoardHandler::REGISTER_LENGTH);
pendingRead = false;
}
}
}
ReturnValue_t CCSDSHandler::getParameter(uint8_t domainId, uint16_t parameterId,
ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues,
uint16_t startAtIndex) {
ReturnValue_t result = fdir.getParameter(domainId, parameterId,
parameterWrapper, newValues, startAtIndex);
if (result != INVALID_DOMAIN_ID) {
return result;
}
if (domainId != DOMAIN_ID_BASE) {
return INVALID_DOMAIN_ID;
}
switch (parameterId) {
case 0:
parameterWrapper->set(boardHandler.tmPhysicalLayerRegisterValue);
break;
case 1:
parameterWrapper->set(boardHandler.tmCodingSublayerRegisterValue);
break;
default:
return INVALID_MATRIX_ID;
}
return RETURN_OK;
}
ReturnValue_t CCSDSHandler::setHealth(HealthState health) {
healthHelper.setHealth(health);
return RETURN_OK;
}
HasHealthIF::HealthState CCSDSHandler::getHealth() {
return healthHelper.getHealth();
}
CCSDSHandler::DataRateSet::DataRateSet() :
ControllerSet(), dataRate(datapool::VC_DATA_RATE_RAW, this,
PoolVariableIF::VAR_WRITE), dataRates(
datapool::DATA_RATE_ASSIGN, this, PoolVariableIF::VAR_READ) {
}
CCSDSHandler::DataRateSet::~DataRateSet() {
}
void CCSDSHandler::DataRateSet::setToDefault() {
dataRate.value = {0.0, 0.0, 0.0, 0.0};
}
void CCSDSHandler::triggerEvent(Event event, uint32_t parameter1,
uint32_t parameter2) {
fdir.triggerEvent(event, parameter1, parameter2);
}