Compare commits

..

19 Commits

Author SHA1 Message Date
56e8e5a8b3 dont know if I am going to need this 2022-10-24 10:39:43 +02:00
754b71a35f Merge pull request 'Update CFDP components' (#113) from mueller/update-cfdp-components into develop
Reviewed-on: #113
2022-10-21 15:27:40 +02:00
2de9e25ceb Merge remote-tracking branch 'upstream/mueller/new-cfdp-update-with-handlers' into mueller/update-cfdp-components 2022-10-21 11:21:26 +02:00
73454c629c oh god 2022-10-20 16:05:45 +02:00
0c5c2f6c4f important bugfix for i2c device com IF 2022-10-20 14:24:03 +02:00
009700ce80 remove info printout 2022-10-17 17:29:10 +02:00
1e43296f2b missing validity check 2022-10-17 17:24:46 +02:00
1aa062df7f const specifier for AcceptsTelemetryIF 2022-10-17 16:27:41 +02:00
14a8924a83 size check bugfix 2022-10-17 14:01:21 +02:00
9f81926aec some more basic error handling 2022-10-17 12:22:01 +02:00
79c38b45df events for FSFW specific errors 2022-10-17 12:20:26 +02:00
e893e73f86 add first CFDP events 2022-10-17 12:19:31 +02:00
692be9df8d DHB bugfix and addition 2022-10-06 16:57:47 +02:00
8195587604 Merge branch 'mueller/uart-helper-module' into mueller/simplify-dle-parser 2022-10-06 11:14:54 +02:00
1c53b60442 small additional tweak 2022-10-04 23:04:28 +02:00
d1630cdc4c something is wrong 2022-10-04 21:17:35 +02:00
49747fc8a4 some bugfixes 2022-10-04 20:51:58 +02:00
cfc00d0260 try to do this in a simpler way 2022-10-04 18:38:20 +02:00
bdbe0cc9da pass message queue externally 2022-09-16 16:28:41 +02:00
15 changed files with 174 additions and 174 deletions

View File

@@ -425,21 +425,31 @@ ReturnValue_t cfdp::DestHandler::sendFinishedPdu() {
store_address_t storeId;
uint8_t* dataPtr = nullptr;
ReturnValue_t result =
fp.tcStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr);
fp.tmStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr);
if (result != OK) {
// TODO: Error handling and event, this is a non CFDP specific error (most likely store is full)
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler:sendFinishedPdu: Getting store slot failed" << std::endl;
#endif
fp.eventReporter->forwardEvent(events::STORE_ERROR, result, 0);
return result;
}
size_t serLen = 0;
result = finishedPdu.serialize(dataPtr, serLen, finishedPdu.getSerializedSize());
if (result != OK) {
// TODO: Error printout, this really should not happen
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Serializing Finished PDU failed"
<< std::endl;
#endif
fp.eventReporter->forwardEvent(events::SERIALIZATION_ERROR, result, 0);
return result;
}
TmTcMessage msg(storeId);
result = fp.msgQueue->sendMessage(fp.packetDest.getReportReceptionQueue(), &msg);
if (result != OK) {
// TODO: Error handling and event, this is a non CFDP specific error (most likely store is full)
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Sending PDU failed" << std::endl;
#endif
fp.eventReporter->forwardEvent(events::MSG_QUEUE_ERROR, result, 0);
return result;
}
fsmRes.packetsSent++;

View File

@@ -5,5 +5,15 @@ namespace cfdp {
enum class CfdpStates { IDLE, BUSY_CLASS_1_NACKED, BUSY_CLASS_2_ACKED, SUSPENDED };
}
static constexpr uint8_t SSID = SUBSYSTEM_ID::CFDP;
namespace events {
static constexpr Event STORE_ERROR = event::makeEvent(SSID, 0, severity::LOW);
static constexpr Event MSG_QUEUE_ERROR = event::makeEvent(SSID, 1, severity::LOW);
static constexpr Event SERIALIZATION_ERROR = event::makeEvent(SSID, 2, severity::LOW);
} // namespace events
} // namespace cfdp
#endif // FSFW_CFDP_HANDLER_DEFS_H

View File

@@ -17,7 +17,7 @@ ReturnValue_t FinishPduCreator::serialize(uint8_t **buffer, size_t *size, size_t
if (result != returnvalue::OK) {
return result;
}
if (*size + 1 >= maxSize) {
if (*size + 1 > maxSize) {
return SerializeIF::BUFFER_TOO_SHORT;
}
**buffer = finishInfo.getConditionCode() << 4 | finishInfo.getDeliveryCode() << 2 |

View File

@@ -467,7 +467,7 @@ ReturnValue_t DeviceHandlerBase::insertInCommandMap(DeviceCommandId_t deviceComm
info.expectedReplies = 0;
info.isExecuting = false;
info.sendReplyTo = NO_COMMANDER;
info.useAlternativeReplyId = alternativeReplyId;
info.useAlternativeReplyId = useAlternativeReply;
info.alternativeReplyId = alternativeReplyId;
auto resultPair = deviceCommandMap.emplace(deviceCommand, info);
if (resultPair.second) {
@@ -1601,3 +1601,14 @@ void DeviceHandlerBase::disableCommandsAndReplies() {
}
}
}
ReturnValue_t DeviceHandlerBase::finishAction(bool success, DeviceCommandId_t action,
ReturnValue_t result) {
auto commandIter = deviceCommandMap.find(action);
if (commandIter == deviceCommandMap.end()) {
return MessageQueueIF::NO_QUEUE;
}
commandIter->second.isExecuting = false;
actionHelper.finish(success, commandIter->second.sendReplyTo, action, result);
return returnvalue::OK;
}

View File

@@ -399,6 +399,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/
virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) = 0;
MessageQueueId_t getCommanderQueueId(DeviceCommandId_t replyId) const;
ReturnValue_t finishAction(bool success, DeviceCommandId_t action, ReturnValue_t result);
/**
* Helper function to get pending command. This is useful for devices
* like SPI sensors to identify the last sent command.
@@ -1138,6 +1140,22 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/
virtual ReturnValue_t doSendReadHook();
/**
* Send a RMAP getRead command.
*
* The size of the getRead command is #maxDeviceReplyLen.
* This is always executed, independently from the current mode.
*/
virtual void doSendRead(void);
/**
* Check the getRead reply and the contained data.
*
* If data was received scanForReply() and, if successful, handleReply()
* are called. If the current mode is @c MODE_RAW, the received packet
* is sent to the commanding object via commandQueue.
*/
virtual void doGetRead();
private:
/**
* State a cookie is in.
@@ -1273,21 +1291,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* - if the action was successful, the reply timout counter is initialized
*/
void doGetWrite(void);
/**
* Send a RMAP getRead command.
*
* The size of the getRead command is #maxDeviceReplyLen.
* This is always executed, independently from the current mode.
*/
void doSendRead(void);
/**
* Check the getRead reply and the contained data.
*
* If data was received scanForReply() and, if successful, handleReply()
* are called. If the current mode is @c MODE_RAW, the received packet
* is sent to the commanding object via commandQueue.
*/
void doGetRead(void);
/**
* @brief Resets replies which use a timeout to detect missed replies.

View File

@@ -33,6 +33,7 @@ enum : uint8_t {
PUS_SERVICE_23 = 103,
MGM_LIS3MDL = 106,
MGM_RM3100 = 107,
CFDP = 108,
FW_SUBSYSTEM_ID_RANGE
};

View File

@@ -3,159 +3,95 @@
#include <fsfw/serviceinterface/ServiceInterface.h>
#include <cstdio>
#include <fstream>
#include <iostream>
DleParser::DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf,
BufPair decodedBuf, UserHandler handler, void* args)
BufPair decodedBuf)
: decodeRingBuf(decodeRingBuf),
decoder(decoder),
encodedBuf(encodedBuf),
decodedBuf(decodedBuf),
handler(handler),
ctx(args) {
if (handler == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DleParser::DleParser: Invalid user handler" << std::endl;
#else
sif::printError("DleParser::DleParser: Invalid user handler\n");
#endif
}
decodedBuf(decodedBuf) {
}
ReturnValue_t DleParser::passData(uint8_t* data, size_t len) {
if (data == nullptr or len == 0 or handler == nullptr) {
ReturnValue_t DleParser::passData(const uint8_t* data, size_t len) {
if (data == nullptr or len == 0) {
return returnvalue::FAILED;
}
size_t copyIntoRingBufFromHere = 0;
size_t copyAmount = len;
size_t startIdx = 0;
ReturnValue_t result = returnvalue::OK;
bool startFoundInThisPacket = false;
for (size_t idx = 0; idx < len; idx++) {
if (data[idx] == DleEncoder::STX_CHAR) {
if (not startFound and not startFoundInThisPacket) {
startIdx = idx;
copyIntoRingBufFromHere = idx;
copyAmount = len - idx;
return decodeRingBuf.writeData(data, len);
}
ReturnValue_t DleParser::parseRingBuf(size_t& readSize) {
ctx.setType(DleParser::ContextType::NONE);
size_t availableData = decodeRingBuf.getAvailableReadData();
if(availableData == 0) {
return NO_PACKET_FOUND;
}
if (availableData > encodedBuf.second) {
ErrorInfo info;
info.len = decodeRingBuf.getAvailableReadData();
setErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
return returnvalue::FAILED;
}
ReturnValue_t result = decodeRingBuf.readData(encodedBuf.first, availableData);
if (result != returnvalue::OK) {
ErrorInfo info;
info.res = result;
setErrorContext(ErrorTypes::RING_BUF_ERROR, info);
return result;
}
bool stxFound = false;
size_t stxIdx = 0;
for (size_t vectorIdx = 0; vectorIdx < availableData; vectorIdx++) {
// handle STX char
if (encodedBuf.first[vectorIdx] == DleEncoder::STX_CHAR) {
if (not stxFound) {
stxFound = true;
stxIdx = vectorIdx;
} else {
// Maybe print warning, should not happen
decodeRingBuf.clear();
// might be lost packet, so we should advance the read pointer
// without skipping the STX
readSize = vectorIdx;
ErrorInfo info;
info.len = idx;
prepareErrorContext(ErrorTypes::CONSECUTIVE_STX_CHARS, info);
handler(ctx);
copyIntoRingBufFromHere = idx;
copyAmount = len - idx;
setErrorContext(ErrorTypes::CONSECUTIVE_STX_CHARS, info);
return POSSIBLE_PACKET_LOSS;
}
startFound = true;
startFoundInThisPacket = true;
} else if (data[idx] == DleEncoder::ETX_CHAR) {
if (startFoundInThisPacket) {
size_t readLen = 0;
}
// handle ETX char
if (encodedBuf.first[vectorIdx] == DleEncoder::ETX_CHAR) {
if (stxFound) {
// This is propably a packet, so we decode it.
size_t decodedLen = 0;
result = decoder.decode(data + startIdx, idx + 1 - startIdx, &readLen, decodedBuf.first,
decodedBuf.second, &decodedLen);
size_t dummy = 0;
ReturnValue_t result =
decoder.decode(&encodedBuf.first[stxIdx], availableData - stxIdx, &dummy,
decodedBuf.first, decodedBuf.second, &decodedLen);
if (result == returnvalue::OK) {
ctx.setType(ContextType::PACKET_FOUND);
ctx.decodedPacket.first = decodedBuf.first;
ctx.decodedPacket.second = decodedLen;
this->handler(ctx);
} else if (result == DleEncoder::STREAM_TOO_SHORT) {
readSize = ++vectorIdx;
return returnvalue::OK;
} else {
// invalid packet, skip.
readSize = ++vectorIdx;
ErrorInfo info;
info.res = result;
prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
handler(ctx);
} else {
ErrorInfo info;
info.res = result;
prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
handler(ctx);
}
decodeRingBuf.clear();
if ((idx + 1) < len) {
copyIntoRingBufFromHere = idx + 1;
copyAmount = len - idx - 1;
} else {
copyAmount = 0;
}
} else if (startFound) {
// ETX found but STX was found in another mini packet. Reconstruct the full packet
// to decode it
result = decodeRingBuf.writeData(data, idx + 1);
if (result != returnvalue::OK) {
ErrorInfo info;
info.res = result;
prepareErrorContext(ErrorTypes::RING_BUF_ERROR, info);
handler(ctx);
}
size_t fullEncodedLen = decodeRingBuf.getAvailableReadData();
if (fullEncodedLen > encodedBuf.second) {
ErrorInfo info;
info.len = fullEncodedLen;
prepareErrorContext(ErrorTypes::ENCODED_BUF_TOO_SMALL, info);
handler(ctx);
decodeRingBuf.clear();
} else {
size_t decodedLen = 0;
size_t readLen = 0;
decodeRingBuf.readData(encodedBuf.first, fullEncodedLen, true);
result = decoder.decode(encodedBuf.first, fullEncodedLen, &readLen, decodedBuf.first,
decodedBuf.second, &decodedLen);
if (result == returnvalue::OK) {
if (this->handler != nullptr) {
ctx.setType(ContextType::PACKET_FOUND);
ctx.decodedPacket.first = decodedBuf.first;
ctx.decodedPacket.second = decodedLen;
this->handler(ctx);
}
} else if (result == DleEncoder::STREAM_TOO_SHORT) {
ErrorInfo info;
info.res = result;
prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
handler(ctx);
} else {
ErrorInfo info;
info.res = result;
prepareErrorContext(ErrorTypes::DECODE_ERROR, info);
handler(ctx);
}
decodeRingBuf.clear();
startFound = false;
startFoundInThisPacket = false;
if ((idx + 1) < len) {
copyIntoRingBufFromHere = idx + 1;
copyAmount = len - idx - 1;
} else {
copyAmount = 0;
}
setErrorContext(ErrorTypes::DECODE_ERROR, info);
return POSSIBLE_PACKET_LOSS;
}
} else {
// End data without preceeding STX
// might be lost packet, so we should advance the read pointer
readSize = ++vectorIdx;
ErrorInfo info;
info.len = idx + 1;
prepareErrorContext(ErrorTypes::CONSECUTIVE_ETX_CHARS, info);
handler(ctx);
decodeRingBuf.clear();
if ((idx + 1) < len) {
copyIntoRingBufFromHere = idx + 1;
copyAmount = len - idx - 1;
} else {
copyAmount = 0;
}
info.len = 0;
setErrorContext(ErrorTypes::CONSECUTIVE_ETX_CHARS, info);
return POSSIBLE_PACKET_LOSS;
}
startFoundInThisPacket = false;
startFound = false;
}
}
if (copyAmount > 0) {
result = decodeRingBuf.writeData(data + copyIntoRingBufFromHere, copyAmount);
if (result != returnvalue::OK) {
ErrorInfo info;
info.res = result;
prepareErrorContext(ErrorTypes::RING_BUF_ERROR, info);
handler(ctx);
}
}
return returnvalue::OK;
return NO_PACKET_FOUND;
}
void DleParser::defaultFoundPacketHandler(uint8_t* packet, size_t len, void* args) {
@@ -169,8 +105,12 @@ void DleParser::defaultFoundPacketHandler(uint8_t* packet, size_t len, void* arg
#endif
}
void DleParser::defaultErrorHandler(ErrorTypes err, ErrorInfo ctx) {
switch (err) {
void DleParser::defaultErrorHandler() {
if(ctx.getType() != DleParser::ContextType::ERROR) {
errorPrinter("No error");
return;
}
switch (ctx.error.first) {
case (ErrorTypes::NONE): {
errorPrinter("No error");
break;
@@ -186,8 +126,8 @@ void DleParser::defaultErrorHandler(ErrorTypes err, ErrorInfo ctx) {
case (ErrorTypes::ENCODED_BUF_TOO_SMALL):
case (ErrorTypes::DECODING_BUF_TOO_SMALL): {
char opt[64];
snprintf(opt, sizeof(opt), ": Too small for packet with length %zu", ctx.len);
if (err == ErrorTypes::ENCODED_BUF_TOO_SMALL) {
snprintf(opt, sizeof(opt), ": Too small for packet with length %zu", ctx.decodedPacket.second);
if (ctx.error.first == ErrorTypes::ENCODED_BUF_TOO_SMALL) {
errorPrinter("Encoded buf too small", opt);
} else {
errorPrinter("Decoding buf too small", opt);
@@ -218,13 +158,20 @@ void DleParser::errorPrinter(const char* str, const char* opt) {
#endif
}
void DleParser::prepareErrorContext(ErrorTypes err, ErrorInfo info) {
void DleParser::setErrorContext(ErrorTypes err, ErrorInfo info) {
ctx.setType(ContextType::ERROR);
ctx.error.first = err;
ctx.error.second = info;
}
ReturnValue_t DleParser::confirmBytesRead(size_t bytesRead) {
return decodeRingBuf.deleteData(bytesRead);
}
const DleParser::Context& DleParser::getContext() {
return ctx;
}
void DleParser::reset() {
startFound = false;
decodeRingBuf.clear();
}

View File

@@ -18,9 +18,11 @@
*/
class DleParser {
public:
static constexpr ReturnValue_t NO_PACKET_FOUND = returnvalue::makeCode(1, 1);
static constexpr ReturnValue_t POSSIBLE_PACKET_LOSS = returnvalue::makeCode(1, 2);
using BufPair = std::pair<uint8_t*, size_t>;
enum class ContextType { PACKET_FOUND, ERROR };
enum class ContextType { NONE, PACKET_FOUND, ERROR };
enum class ErrorTypes {
NONE,
@@ -41,7 +43,7 @@ class DleParser {
struct Context {
public:
Context(void* args) : userArgs(args) { setType(ContextType::PACKET_FOUND); }
Context() { setType(ContextType::PACKET_FOUND); }
void setType(ContextType type) {
this->type = type;
@@ -58,14 +60,11 @@ class DleParser {
BufPair decodedPacket = {};
ErrorPair error;
void* userArgs;
private:
ContextType type;
};
using UserHandler = void (*)(const Context& ctx);
/**
* Base class constructor
* @param decodeRingBuf Ring buffer used to store multiple packets to allow detecting DLE packets
@@ -79,7 +78,7 @@ class DleParser {
* @param args Arbitrary user argument
*/
DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf,
BufPair decodedBuf, UserHandler handler, void* args);
BufPair decodedBuf);
/**
* This function allows to pass new data into the parser. It then scans for DLE packets
@@ -88,8 +87,13 @@ class DleParser {
* @param len
* @return
*/
ReturnValue_t passData(uint8_t* data, size_t len);
ReturnValue_t passData(const uint8_t* data, size_t len);
ReturnValue_t parseRingBuf(size_t& bytesRead);
ReturnValue_t confirmBytesRead(size_t bytesRead);
const Context& getContext();
/**
* Example found packet handler
* function call
@@ -104,11 +108,11 @@ class DleParser {
* - For buffer length errors, will be set to the detected packet length which is too large
* - For decode or ring buffer errors, will be set to the result returned from the failed call
*/
static void defaultErrorHandler(ErrorTypes err, ErrorInfo ctx);
void defaultErrorHandler();
static void errorPrinter(const char* str, const char* opt = nullptr);
void prepareErrorContext(ErrorTypes err, ErrorInfo ctx);
void setErrorContext(ErrorTypes err, ErrorInfo ctx);
/**
* Resets the parser by resetting the internal states and clearing the decoding ring buffer
*/
@@ -119,7 +123,5 @@ class DleParser {
DleEncoder& decoder;
BufPair encodedBuf;
BufPair decodedBuf;
UserHandler handler = nullptr;
Context ctx;
bool startFound = false;
};

View File

@@ -15,8 +15,8 @@ Service5EventReporting::Service5EventReporting(PsbParams params, size_t maxNumbe
maxNumberReportsPerCycle(maxNumberReportsPerCycle) {
auto mqArgs = MqArgs(getObjectId(), static_cast<void*>(this));
psbParams.name = "PUS 5 Event Reporting";
eventQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth,
MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
eventQueue = QueueFactory::instance()->createMessageQueue(
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
Service5EventReporting::~Service5EventReporting() {

View File

@@ -0,0 +1,15 @@
#ifndef FSFW_SRC_FSFW_TMSTORAGE_TMSTOREBACKENDSIMPLEIF_H_
#define FSFW_SRC_FSFW_TMSTORAGE_TMSTOREBACKENDSIMPLEIF_H_
#include <fsfw/ipc/messageQueueDefinitions.h>
class TmStoreFrontendSimpleIF {
public:
virtual ~TmStoreFrontendSimpleIF() = default;
private:
virtual MessageQueueId_t getCommandQueue() const = 0;
};
#endif /* FSFW_SRC_FSFW_TMSTORAGE_TMSTOREBACKENDSIMPLEIF_H_ */

View File

@@ -14,6 +14,7 @@ SpacePacketCreator::SpacePacketCreator(ccsds::PacketType packetType, bool secHea
: params(SpacePacketParams(PacketId(packetType, secHeaderFlag, apid),
PacketSeqCtrl(seqFlags, seqCount), dataLen)) {
params.version = version;
checkFieldValidity();
}
uint16_t SpacePacketCreator::getPacketIdRaw() const { return params.packetId.raw(); }

View File

@@ -21,9 +21,9 @@ class AcceptsTelemetryIF {
* receiving message queue.
* @return The telemetry reception message queue id.
*/
virtual MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel) = 0;
[[nodiscard]] virtual MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel) const = 0;
virtual MessageQueueId_t getReportReceptionQueue() { return getReportReceptionQueue(0); }
[[nodiscard]] virtual MessageQueueId_t getReportReceptionQueue() const { return getReportReceptionQueue(0); }
};
#endif /* FSFW_TMTCSERVICES_ACCEPTSTELEMETRYIF_H_ */

View File

@@ -245,7 +245,7 @@ void TmTcBridge::registerCommDisconnect() {
}
}
MessageQueueId_t TmTcBridge::getReportReceptionQueue(uint8_t virtualChannel) {
MessageQueueId_t TmTcBridge::getReportReceptionQueue(uint8_t virtualChannel) const {
return tmTcReceptionQueue->getId();
}

View File

@@ -65,7 +65,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
ReturnValue_t performOperation(uint8_t operationCode = 0) override;
/** AcceptsTelemetryIF override */
MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0) override;
MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0) const override;
/** AcceptsTelecommandsIF override */
uint32_t getIdentifier() const override;

View File

@@ -216,7 +216,7 @@ ReturnValue_t I2cComIF::readReceivedMessage(CookieIF* cookie, uint8_t** buffer,
}
*buffer = i2cDeviceMapIter->second.replyBuffer.data();
*size = i2cDeviceMapIter->second.replyLen;
i2cDeviceMapIter->second.replyLen = 0;
return returnvalue::OK;
}