1
0
forked from fsfw/fsfw

Today's the day. Renamed platform to framework.

This commit is contained in:
Bastian Baetz
2016-06-15 23:48:41 +02:00
committed by Ulrich Mohr
parent 40987d0b27
commit 1d22a6c97e
356 changed files with 33946 additions and 3 deletions

704
tmstorage/TmStore.cpp Normal file
View File

@ -0,0 +1,704 @@
/*
* TmStore.cpp
*
* Created on: 05.02.2015
* Author: baetz
*/
#include <framework/memory/AcceptsMemoryMessagesIF.h>
#include <framework/memory/MemoryMessage.h>
#include <framework/serviceinterface/ServiceInterfaceStream.h>
#include <framework/tmstorage/TmStore.h>
#include <framework/tmtcservices/AcceptsTelemetryIF.h>
#include <framework/tmtcservices/TmTcMessage.h>
TmStore::TmStore(TmStoreFrontendIF* owner, object_id_t memoryObject,
uint32_t storeAddress, uint32_t size, bool overwriteOld,
uint32_t maxDumpPacketsPerCylce, uint32_t maxDumpedBytesPerCylce,
uint32_t updateRemotePtrsMs, uint32_t chunkSize) :
owner(owner), eventProxy(NULL), info(&oldestPacket, &newestPacket), infoSize(
info.getSerializedSize()), ring(storeAddress + infoSize,
size - infoSize, overwriteOld), state(OFF), writeState(
WRITE_IDLE), readState(READ_IDLE), memoryObject(memoryObject), memoryQueue(), ipcStore(
NULL), timer(), pendingDataToWrite(0), maximumAmountToRead(0), storedPacketCounter(0), pendingStoredPackets(0), splitWrite(
false), splitRead(NO_SPLIT), splitReadTotalSize(0), tmBuffer(chunkSize), dumpBuffer(
NULL), pointerAddress(storeAddress), updateRemotePtrsMs(
updateRemotePtrsMs), maxDumpPacketsPerCycle(
maxDumpPacketsPerCylce), maxDumpedBytesPerCycle(maxDumpedBytesPerCylce), tryToSetStoreInfo(false) {
dumpBuffer = new uint8_t[chunkSize];
}
TmStore::~TmStore() {
delete[] dumpBuffer;
}
ReturnValue_t TmStore::performOperation() {
doStateMachine();
checkMemoryQueue();
if (localBufferTimer.hasTimedOut() && (state == READY)) {
sendTmBufferToStore();
localBufferTimer.setTimeout(LOCAL_BUFFER_TIMEOUT_MS);
}
return RETURN_OK;
}
ReturnValue_t TmStore::storePacket(TmPacketMinimal* tmPacket) {
if (tmPacket->getFullSize() > chunkSize()) {
return TOO_LARGE;
}
ReturnValue_t result = RETURN_FAILED;
if (hasEnoughSpaceFor(tmPacket->getFullSize())) {
localBufferTimer.setTimeout(LOCAL_BUFFER_TIMEOUT_MS);
result = storeOrForwardPacket(tmPacket->getWholeData(),
tmPacket->getFullSize());
} else {
result = handleFullStore(tmPacket->getWholeData(),
tmPacket->getFullSize());
}
if (result == RETURN_OK) {
pendingNewestPacket.setContent(tmPacket);
if (!pendingOldestPacket.isValid()) {
pendingOldestPacket.setContent(tmPacket);
}
pendingStoredPackets++;
}
return result;
}
ReturnValue_t TmStore::fetchPackets(bool useAddress, uint32_t startAtAddress) {
if (!isReady()) {
return NOT_READY;
}
if (ring.isEmpty()) {
return EMPTY;
}
if (readState != READ_IDLE) {
return BUSY;
}
// Never download more than the currently available data.
maximumAmountToRead = ring.availableReadData();
if (useAddress) {
ring.setRead(startAtAddress, TEMP_READ_PTR);
} else {
ring.setRead(ring.getRead(READ_PTR), TEMP_READ_PTR);
}
ReturnValue_t result = requestChunkOfData();
if (result != RETURN_OK) {
return result;
}
setReadState(DUMPING_PACKETS);
return RETURN_OK;
}
ReturnValue_t TmStore::requestStoreInfo() {
CommandMessage message;
MemoryMessage::setMemoryDumpCommand(&message, pointerAddress, infoSize);
ReturnValue_t result = memoryQueue.sendToDefault(&message);
if (result != RETURN_OK) {
return result;
}
return RETURN_OK;
}
ReturnValue_t TmStore::setStoreInfo() {
store_address_t storeId;
uint8_t* data = NULL;
uint32_t size = 0;
ReturnValue_t result = ipcStore->getFreeElement(&storeId, infoSize, &data);
if (result != RETURN_OK) {
return result;
}
info.setContent(ring.getRead(), ring.getWrite(), storedPacketCounter);
result = info.serialize(&data, &size, infoSize, true);
if (result != RETURN_OK) {
ipcStore->deleteData(storeId);
return result;
}
CommandMessage message;
MemoryMessage::setMemoryLoadCommand(&message, pointerAddress, storeId);
result = memoryQueue.sendToDefault(&message);
if (result != RETURN_OK) {
ipcStore->deleteData(storeId);
return result;
}
return RETURN_OK;
}
void TmStore::doStateMachine() {
switch (state) {
case OFF:
break;
case STARTUP: {
ReturnValue_t result = requestStoreInfo();
if (result == RETURN_OK) {
setState(FETCH_STORE_INFORMATION);
setReadState(FETCHING_STORE_INFO);
timer.setTimeout(DEFAULT_TIMEOUT_MS);
} else {
eventProxy->forwardEvent(STORE_INIT_FAILED, result, 0);
setState(OFF);
}
}
break;
case FETCH_STORE_INFORMATION:
if (timer.hasTimedOut()) {
eventProxy->forwardEvent(STORE_INIT_FAILED, TIMEOUT, 1);
setState(OFF);
}
break;
case READY:
if (tryToSetStoreInfo) {
if ((writeState == WRITE_IDLE) && (readState == READ_IDLE)) {
if (setStoreInfo() == RETURN_OK) {
setWriteState(SETTING_STORE_INFO);
}
tryToSetStoreInfo = false;
}
}
break;
default:
//do nothing.
break;
}
}
void TmStore::checkMemoryQueue() {
CommandMessage message;
for (ReturnValue_t result = memoryQueue.receiveMessage(&message);
result == RETURN_OK;
result = memoryQueue.receiveMessage(&message)) {
switch (message.getCommand()) {
case CommandMessage::REPLY_COMMAND_OK:
handleLoadSuccess();
break;
case MemoryMessage::REPLY_MEMORY_DUMP:
handleDump(MemoryMessage::getStoreID(&message));
break;
case MemoryMessage::REPLY_MEMORY_FAILED:
case CommandMessage::REPLY_REJECTED: // REPLY_REJECTED uses the same protocol.
switch (MemoryMessage::getInitialCommand(&message)) {
case MemoryMessage::CMD_MEMORY_LOAD:
handleLoadFailed(MemoryMessage::getErrorCode(&message));
break;
case MemoryMessage::CMD_MEMORY_DUMP:
handleDumpFailed(MemoryMessage::getErrorCode(&message));
break;
default:
debug << "TmStore: Unknown InitialCommand: "
<< MemoryMessage::getInitialCommand(&message)
<< std::endl;
break;
}
break;
default:
eventProxy->forwardEvent(UNEXPECTED_MSG, 0, 0);
break;
}
}
}
void TmStore::handleLoadSuccess() {
switch (writeState) {
case SETTING_STORE_INFO:
setWriteState(WRITE_IDLE);
break;
case SENDING_PACKETS:
if (splitWrite) {
ReturnValue_t result = sendRemainingTmPiece();
if (result != RETURN_OK) {
eventProxy->forwardEvent(STORE_SEND_WRITE_FAILED, result, 0);
resetStore(true);
pendingDataToWrite = 0;
}
splitWrite = false;
} else {
ring.writeData(pendingDataToWrite);
pendingDataToWrite = 0;
storedPacketCounter += pendingStoredPackets;
newestPacket.setContent(&pendingNewestPacket);
if (!oldestPacket.isValid()) {
oldestPacket.setContent(&pendingOldestPacket);
}
pendingStoredPackets = 0;
setWriteState(WRITE_IDLE);
tryToSetStoreInfo = true;
}
break;
default:
eventProxy->forwardEvent(UNEXPECTED_MSG, 0, 1);
}
}
void TmStore::handleDump(store_address_t storeId) {
const uint8_t* buffer = NULL;
uint32_t size = 0;
ReturnValue_t result = ipcStore->getData(storeId, &buffer, &size);
if (result != RETURN_OK) {
return;
}
switch (readState) {
case FETCHING_STORE_INFO:
readStoreInfo(buffer, size);
break;
case DUMPING_PACKETS:
case DELETING_OLD:
case DELETING_MORE:
handleSplitRead(buffer, size);
break;
default:
setReadState(READ_IDLE);
//No break.
case READ_IDLE:
eventProxy->forwardEvent(UNEXPECTED_MSG, 0, 2);
break;
}
ipcStore->deleteData(storeId);
}
void TmStore::handleSplitRead(const uint8_t* buffer, uint32_t size) {
switch (splitRead) {
case NO_SPLIT:
if (readState == DELETING_OLD || readState == DELETING_MORE) {
deleteOld(buffer, size);
} else {
dumpPackets(buffer, size);
}
break;
case SPLIT_STARTED:
if (size <= chunkSize()) {
ReturnValue_t result = requestRemainingDumpPiece(size);
if (result == RETURN_OK) {
memcpy(dumpBuffer, buffer, size);
splitRead = ONE_RECEIVED;
} else {
eventProxy->forwardEvent(STORE_SEND_READ_FAILED, result, 0);
splitRead = NO_SPLIT;
maximumAmountToRead = 0;
}
} else {
eventProxy->forwardEvent(STORE_SEND_READ_FAILED, TOO_LARGE, 0);
splitRead = NO_SPLIT;
maximumAmountToRead = 0;
}
break;
case ONE_RECEIVED:
memcpy(&dumpBuffer[splitReadTotalSize - size], buffer, size);
if (readState == DELETING_OLD || readState == DELETING_MORE) {
deleteOld(dumpBuffer, splitReadTotalSize);
} else {
dumpPackets(dumpBuffer, splitReadTotalSize);
}
splitRead = NO_SPLIT;
break;
}
}
void TmStore::handleLoadFailed(ReturnValue_t errorCode) {
eventProxy->forwardEvent(STORE_WRITE_FAILED, errorCode, 0);
setWriteState(WRITE_IDLE);
setState(READY);
splitWrite = false;
pendingDataToWrite = 0;
}
void TmStore::handleDumpFailed(ReturnValue_t errorCode) {
switch (readState) {
case FETCHING_STORE_INFO:
eventProxy->forwardEvent(STORE_INIT_FAILED, errorCode, 2);
setState(OFF);
break;
case DUMPING_PACKETS:
owner->handleRetrievalFailed(errorCode);
//No break
default:
case READ_IDLE:
case DELETING_OLD:
case DELETING_MORE:
eventProxy->forwardEvent(STORE_READ_FAILED, errorCode, 0);
setState(READY);
break;
}
setReadState(READ_IDLE);
splitRead = NO_SPLIT;
maximumAmountToRead = 0;
}
void TmStore::readStoreInfo(const uint8_t* buffer, uint32_t size) {
setReadState(READ_IDLE);
if (::Calculate_CRC(buffer, infoSize) != 0) {
eventProxy->forwardEvent(STORE_INIT_EMPTY, 0, 0);
setState(READY);
return;
}
int32_t deSize = size;
ReturnValue_t result = info.deSerialize(&buffer, &deSize, true);
if (result != RETURN_OK) {
//An error here is extremely unlikely.
eventProxy->forwardEvent(STORE_INIT_FAILED, result, 3);
setState(OFF);
return;
}
eventProxy->forwardEvent(STORE_INIT_DONE);
ring.setWrite(info.writeP);
ring.setRead(info.readP);
storedPacketCounter = info.storedPacketCount;
setState(READY);
}
void TmStore::dumpPackets(const uint8_t* buffer, uint32_t size) {
ReturnValue_t result = RETURN_OK;
uint32_t tempSize = 0;
uint32_t dumpedPacketCounter = 0;
uint32_t dumpedBytesCounter = 0;
while (size >= TmPacketMinimal::MINIMUM_SIZE
&& dumpedPacketCounter < maxDumpPacketsPerCycle
&& dumpedBytesCounter < maxDumpedBytesPerCycle
&& result == RETURN_OK) {
TmPacketMinimal packet(buffer);
tempSize = packet.getFullSize();
if (tempSize > size) {
if (tempSize > ring.availableReadData(READ_PTR) || tempSize > chunkSize()) {
owner->handleRetrievalFailed(DUMP_ERROR);
eventProxy->forwardEvent(STORE_CONTENT_CORRUPTED, 0, tempSize);
result = DUMP_ERROR;
}
break;
}
size -= tempSize;
buffer += tempSize;
dumpedBytesCounter += tempSize;
if (maximumAmountToRead > tempSize) {
result = owner->packetRetrieved(&packet,
ring.getRead(TEMP_READ_PTR));
maximumAmountToRead -= tempSize;
} else {
//packet is complete and last.
result = owner->packetRetrieved(&packet,
ring.getRead(TEMP_READ_PTR), true);
maximumAmountToRead = 0;
break;
}
if (result == RETURN_OK) {
ring.readData(tempSize, TEMP_READ_PTR);
dumpedPacketCounter++;
}
}
if (result == RETURN_OK && maximumAmountToRead != 0) {
result = requestChunkOfData();
if (result != HasReturnvaluesIF::RETURN_OK) {
owner->handleRetrievalFailed(result);
}
} else {
setReadState(READ_IDLE);
}
}
ReturnValue_t TmStore::sendDataToTmStore(const uint8_t* data, uint32_t size) {
//Unfortunately, cleanup is quite complex.
store_address_t storeId;
ReturnValue_t result = RETURN_FAILED;
if (size > ring.writeTillWrap()) {
//Two-folded write
result = ipcStore->addData(&storeId, data, ring.writeTillWrap());
if (result != RETURN_OK) {
return result;
}
splitWrite = true;
result = ipcStore->addData(&splitWriteStoreId,
data + ring.writeTillWrap(), size - ring.writeTillWrap());
if (result != RETURN_OK) {
ipcStore->deleteData(storeId);
}
} else {
//Normal write
splitWrite = false;
result = ipcStore->addData(&storeId, data, size);
}
if (result != RETURN_OK) {
splitWrite = false;
return result;
}
CommandMessage message;
MemoryMessage::setMemoryLoadCommand(&message, ring.getWrite(), storeId);
if ((result = memoryQueue.sendToDefault(&message)) == RETURN_OK) {
setWriteState(SENDING_PACKETS);
pendingDataToWrite = size;
} else {
if (splitWrite) {
ipcStore->deleteData(splitWriteStoreId);
}
splitWrite = false;
ipcStore->deleteData(storeId);
}
return result;
}
ReturnValue_t TmStore::requestChunkOfData() {
uint32_t readSize =
(maximumAmountToRead > chunkSize()) ?
chunkSize() : maximumAmountToRead;
CommandMessage message;
if (readSize > ring.readTillWrap(TEMP_READ_PTR)) {
//Wrap
splitReadTotalSize = readSize;
splitRead = SPLIT_STARTED;
MemoryMessage::setMemoryDumpCommand(&message,
ring.getRead(TEMP_READ_PTR), ring.readTillWrap(TEMP_READ_PTR));
} else {
splitRead = NO_SPLIT;
MemoryMessage::setMemoryDumpCommand(&message,
ring.getRead(TEMP_READ_PTR), readSize);
}
ReturnValue_t result = memoryQueue.sendToDefault(&message);
if (result != RETURN_OK) {
splitRead = NO_SPLIT;
maximumAmountToRead = 0;
}
return result;
}
ReturnValue_t TmStore::initialize() {
AcceptsMemoryMessagesIF* memoryTarget = objectManager->get<
AcceptsMemoryMessagesIF>(memoryObject);
if (memoryTarget == NULL) {
return RETURN_FAILED;
}
memoryQueue.setDefaultDestination(memoryTarget->getCommandQueue());
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
if (ipcStore == NULL) {
return RETURN_FAILED;
}
//assert that Store is larger than local store and potential data on the way.
if (ring.availableWriteSpace(READ_PTR) < (2 * tmBuffer.maxSize())) {
//Ring buffer is too small.
return RETURN_FAILED;
}
//Ugly cast to have the correct link to eventProxy:
eventProxy = dynamic_cast<EventReportingProxyIF*>(owner);
if (eventProxy == NULL) {
return RETURN_FAILED;
}
return RETURN_OK;
}
ReturnValue_t TmStore::initializeStore() {
setState(STARTUP);
eventProxy->forwardEvent(STORE_INITIALIZE, 0, 0);
return RETURN_OK;
}
bool TmStore::isReady() {
return (state == READY);
}
ReturnValue_t TmStore::sendRemainingTmPiece() {
if (writeState != SENDING_PACKETS) {
return RETURN_FAILED;
}
CommandMessage message;
MemoryMessage::setMemoryLoadCommand(&message, ring.getStart(),
splitWriteStoreId);
return memoryQueue.sendToDefault(&message);
}
ReturnValue_t TmStore::requestRemainingDumpPiece(uint32_t firstPartSize) {
CommandMessage message;
MemoryMessage::setMemoryDumpCommand(&message, ring.getStart(),
splitReadTotalSize - firstPartSize);
return memoryQueue.sendToDefault(&message);
}
uint32_t TmStore::availableData() {
return ring.availableReadData();
}
ReturnValue_t TmStore::storeOrForwardPacket(const uint8_t* data,
uint32_t size) {
if (tmBuffer.remaining() >= size) {
memcpy(&tmBuffer[tmBuffer.size], data, size);
tmBuffer.size += size;
return RETURN_OK;
} else {
if (writeState != WRITE_IDLE) {
return BUSY;
}
if (!isReady()) {
return NOT_READY;
}
sendTmBufferToStore();
memcpy(tmBuffer.front(), data, size);
tmBuffer.size += size;
return RETURN_OK;
}
}
bool TmStore::hasEnoughSpaceFor(uint32_t size) {
//Correct size configuration is asserted in initialize().
if ((ring.availableWriteSpace(READ_PTR) - tmBuffer.size - pendingDataToWrite)
> size) {
return true;
} else {
return false;
}
}
ReturnValue_t TmStore::deleteContent(bool deletePart, uint32_t upToAddress,
uint32_t nDeletedPackets, TmPacketMinimal* newOldestPacket) {
if (deletePart) {
ring.setRead(upToAddress, READ_PTR);
storedPacketCounter -= nDeletedPackets;
if (newOldestPacket != NULL) {
oldestPacket.setContent(newOldestPacket);
}
} else {
resetStore();
}
tryToSetStoreInfo = true;
return RETURN_OK;
}
ReturnValue_t TmStore::handleFullStore(const uint8_t* data, uint32_t size) {
if (!isReady()) {
return NOT_READY;
}
if (!ring.overwritesOld()) {
sendTmBufferToStore();
return FULL;
}
ReturnValue_t result = FULL;
if ((writeState == WRITE_IDLE) && (readState == READ_IDLE)) {
sendTmBufferToStore();
maximumAmountToRead = chunkSize();
ring.setRead(ring.getRead(READ_PTR), TEMP_READ_PTR);
result = requestChunkOfData();
if (result != RETURN_OK) {
return result;
}
setReadState(DELETING_OLD);
//Store data in cleared store.
memcpy(tmBuffer.front(), data, size);
tmBuffer.size += size;
result = RETURN_OK;
} else if (readState == DELETING_OLD) {
//Try to store local as long as possible
if (tmBuffer.remaining() >= size) {
memcpy(&tmBuffer[tmBuffer.size], data, size);
tmBuffer.size += size;
result = RETURN_OK;
}
}
return result;
}
void TmStore::deleteOld(const uint8_t* buffer, uint32_t size) {
ReturnValue_t result = RETURN_OK;
uint32_t tempSize = 0;
while (size >= TmPacketMinimal::MINIMUM_SIZE && result == RETURN_OK) {
TmPacketMinimal packet(buffer);
tempSize = packet.getFullSize();
if (readState == DELETING_MORE) {
if (size < (TmPacketMinimal::MINIMUM_SIZE + tempSize)) {
oldestPacket.setContent(&packet);
break;
}
} else {
if (tempSize > size) {
//Don't delete the last packet half in store...
break;
}
}
result = ring.readData(tempSize, READ_PTR);
ring.readData(tempSize, TEMP_READ_PTR);
size -= tempSize;
buffer += tempSize;
storedPacketCounter--;
}
if (readState == DELETING_OLD) {
result = requestChunkOfData();
if (result != HasReturnvaluesIF::RETURN_OK) {
oldestPacket.reset();
eventProxy->forwardEvent(STORE_SEND_WRITE_FAILED, result, 1);
setReadState(READ_IDLE);
} else {
setReadState(DELETING_MORE);
}
} else {
setReadState(READ_IDLE);
owner->restDownlinkedPacketCount();
tryToSetStoreInfo = true;
}
}
void TmStore::sendTmBufferToStore() {
//No need to send empty data packet.
if (tmBuffer.size > 0) {
ReturnValue_t result = sendDataToTmStore(tmBuffer.front(), tmBuffer.size);
if (result != HasReturnvaluesIF::RETURN_OK) {
eventProxy->forwardEvent(STORE_SEND_WRITE_FAILED, result, 2);
}
tmBuffer.clear();
}
}
void TmStore::resetStore(bool resetWrite, bool resetRead) {
ring.clear();
setState(READY);
storedPacketCounter = 0;
clearPending();
tmBuffer.clear();
oldestPacket.reset();
newestPacket.reset();
tryToSetStoreInfo = true;
if (resetWrite) {
setWriteState(WRITE_IDLE);
splitWrite = false;
pendingDataToWrite = 0;
}
if (resetRead) {
maximumAmountToRead = 0;
splitRead = NO_SPLIT;
setReadState(READ_IDLE);
}
}
void TmStore::setState(State state) {
// debug << "TmStore::setState: " << state << std::endl;
this->state = state;
}
void TmStore::setWriteState(WriteState writeState) {
// debug << "TmStore::setWriteState: " << writeState << std::endl;
this->writeState = writeState;
}
void TmStore::setReadState(ReadState readState) {
// debug << "TmStore::setReadState: " << readState << std::endl;
this->readState = readState;
}
float TmStore::getPercentageFilled() const {
return ring.availableReadData(READ_PTR) / float(ring.maxSize());
}
uint32_t TmStore::getStoredPacketsCount() const {
return storedPacketCounter;
}
TmPacketInformation* TmStore::getOldestPacket() {
return &oldestPacket;
}
TmPacketInformation* TmStore::getYoungestPacket() {
return &newestPacket;
}
uint32_t TmStore::chunkSize() {
return tmBuffer.maxSize();
}
void TmStore::clearPending() {
pendingOldestPacket.reset();
pendingNewestPacket.reset();
pendingStoredPackets = 0;
}

147
tmstorage/TmStore.h Normal file
View File

@ -0,0 +1,147 @@
/*
* TmStore.h
*
* Created on: 05.02.2015
* Author: baetz
*/
#ifndef PLATFORM_TMTCSERVICES_TMSTORE_H_
#define PLATFORM_TMTCSERVICES_TMSTORE_H_
#include <framework/container/FixedArrayList.h>
#include <framework/container/RingBufferBase.h>
#include <framework/events/EventReportingProxyIF.h>
#include <framework/globalfunctions/crc_ccitt.h>
#include <framework/ipc/MessageQueue.h>
#include <framework/objectmanager/ObjectManagerIF.h>
#include <framework/serialize/SerialLinkedListAdapter.h>
#include <framework/storagemanager/StorageManagerIF.h>
#include <framework/timemanager/Countdown.h>
#include <framework/tmstorage/TmStoreBackendIF.h>
#include <framework/tmstorage/TmStoreFrontendIF.h>
#include <framework/tmstorage/TmStoreInfo.h>
#include <framework/tmstorage/TmStorePackets.h>
#include <framework/tmtcpacket/pus/TmPacketMinimal.h>
class TmStore: public HasReturnvaluesIF, public TmStoreBackendIF {
public:
static const uint32_t DEFAULT_TIMEOUT_MS = 3000;
static const uint32_t UPDATE_REMOTE_PTRS_DEFAULT_MS = 20000;
static const uint32_t MAX_DUMP_PACKETS_PER_CYCLE_DEFAULT = 16;
static const uint32_t MAX_DUMPED_BYTES_PER_CYCLE_DEFAULT = 1024;
TmStore(TmStoreFrontendIF* owner, object_id_t memoryObject,
uint32_t storeAddress, uint32_t size, bool overwriteOld = false,
uint32_t maxDumpPacketsPerCylce = MAX_DUMP_PACKETS_PER_CYCLE_DEFAULT,
uint32_t maxDumpedBytesPerCycle = MAX_DUMPED_BYTES_PER_CYCLE_DEFAULT,
uint32_t updateRemotePtrsMs = UPDATE_REMOTE_PTRS_DEFAULT_MS,
uint32_t chunkSize = CHUNK_SIZE_DEFAULT);
virtual ~TmStore();
ReturnValue_t performOperation();
ReturnValue_t storePacket(TmPacketMinimal* tmPacket);
ReturnValue_t fetchPackets(bool useAddress = false,
uint32_t startAtAddress = 0);
uint32_t availableData();
ReturnValue_t deleteContent(bool deletePart = false, uint32_t upToAddress =
0, uint32_t nDeletedPackets = 0, TmPacketMinimal* newOldestPacket =
NULL);
ReturnValue_t initialize();
ReturnValue_t initializeStore();
bool isReady();
void resetStore(bool resetWrite = false, bool resetRead = false);
float getPercentageFilled() const;
uint32_t getStoredPacketsCount() const;
TmPacketInformation* getOldestPacket();
TmPacketInformation* getYoungestPacket();
private:
TmStoreFrontendIF* owner;
EventReportingProxyIF* eventProxy;
TmPacketInformation pendingOldestPacket;
TmPacketInformation pendingNewestPacket;
TmPacketInformation oldestPacket;
TmPacketInformation newestPacket;
TmStoreInfo info;
const uint32_t infoSize;
RingBufferBase<2> ring;
enum State {
OFF = 0,
STARTUP = 1,
FETCH_STORE_INFORMATION = 2,
STORE_INFORMATION_RECEIVED = 3,
READY = 4
};
State state;
enum WriteState {
WRITE_IDLE = 0, SETTING_STORE_INFO = 1, SENDING_PACKETS = 2,
};
WriteState writeState;
enum ReadState {
READ_IDLE = 0,
DELETING_OLD = 1,
DUMPING_PACKETS = 2,
FETCHING_STORE_INFO = 3,
DELETING_MORE = 4
};
ReadState readState;
object_id_t memoryObject;
MessageQueue memoryQueue;
StorageManagerIF* ipcStore;
Countdown timer;
uint32_t pendingDataToWrite;
uint32_t maximumAmountToRead;
uint32_t storedPacketCounter;
uint32_t pendingStoredPackets;
bool splitWrite;
store_address_t splitWriteStoreId;
enum SplitReadState {
NO_SPLIT, SPLIT_STARTED, ONE_RECEIVED
};
SplitReadState splitRead;
uint32_t splitReadTotalSize;
ArrayList<uint8_t, uint16_t> tmBuffer;
uint8_t* dumpBuffer;
const uint32_t pointerAddress;
const uint32_t updateRemotePtrsMs;
const uint32_t maxDumpPacketsPerCycle;
const uint32_t maxDumpedBytesPerCycle;
Countdown localBufferTimer;
bool tryToSetStoreInfo;
static const uint8_t READ_PTR = 0;
static const uint8_t TEMP_READ_PTR = 1;
static const uint32_t LOCAL_BUFFER_TIMEOUT_MS = 5000;
static const uint32_t CHUNK_SIZE_DEFAULT = 2048;
void checkMemoryQueue();
ReturnValue_t requestStoreInfo();
ReturnValue_t setStoreInfo();
void readStoreInfo(const uint8_t* buffer, uint32_t size);
void dumpPackets(const uint8_t* buffer, uint32_t size);
/**
* Deletes old packets to free space in the store for new packets.
* Two chunks of data are requested to definitely delete mored than one
* chunk. Deletion is stopped when the last full packet is found, to
* be able to remember the oldest packet in store.
* @param buffer Data containing the old packets.
* @param size Size of the data chunk.
*/
void deleteOld(const uint8_t* buffer, uint32_t size);
void doStateMachine();
void handleLoadSuccess();
void handleDump(store_address_t storeId);
void handleLoadFailed(ReturnValue_t errorCode);
void handleDumpFailed(ReturnValue_t errorCode);
ReturnValue_t sendDataToTmStore(const uint8_t* data, uint32_t size);
ReturnValue_t sendRemainingTmPiece();
ReturnValue_t requestChunkOfData();
ReturnValue_t requestRemainingDumpPiece(uint32_t firstPartSize);
ReturnValue_t storeOrForwardPacket(const uint8_t* data, uint32_t size);
ReturnValue_t handleFullStore(const uint8_t* data, uint32_t size);
bool hasEnoughSpaceFor(uint32_t size);
void sendTmBufferToStore();
void handleSplitRead(const uint8_t* buffer, uint32_t size);
void setState(State state);
void setReadState(ReadState readState);
void setWriteState(WriteState writeState);
uint32_t chunkSize();
void clearPending();
};
#endif /* PLATFORM_TMTCSERVICES_TMSTORE_H_ */

View File

@ -0,0 +1,60 @@
/*
* TmStoreBackendIF.h
*
* Created on: 18.02.2015
* Author: baetz
*/
#ifndef PLATFORM_TMTCSERVICES_TMSTOREBACKENDIF_H_
#define PLATFORM_TMTCSERVICES_TMSTOREBACKENDIF_H_
#include <framework/returnvalues/HasReturnvaluesIF.h>
class TmPacketInformation;
class TmPacketMinimal;
class TmStoreBackendIF {
public:
static const uint8_t INTERFACE_ID = TM_STORE_BACKEND_IF;
static const ReturnValue_t BUSY = MAKE_RETURN_CODE(1);
static const ReturnValue_t FULL = MAKE_RETURN_CODE(2);
static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(3);
static const ReturnValue_t NULL_REQUESTED = MAKE_RETURN_CODE(4);
static const ReturnValue_t TOO_LARGE = MAKE_RETURN_CODE(5);
static const ReturnValue_t NOT_READY = MAKE_RETURN_CODE(6);
static const ReturnValue_t DUMP_ERROR = MAKE_RETURN_CODE(7);
static const ReturnValue_t CRC_ERROR = MAKE_RETURN_CODE(8);
static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(9);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::MEMORY;
static const Event STORE_SEND_WRITE_FAILED = MAKE_EVENT(0, SEVERITY::LOW); //!< Initiating sending data to store failed. Low, par1: returnCode, par2: integer (debug info)
static const Event STORE_WRITE_FAILED = MAKE_EVENT(1, SEVERITY::LOW); //!< Data was sent, but writing failed. Low, par1: returnCode, par2: 0
static const Event STORE_SEND_READ_FAILED = MAKE_EVENT(2, SEVERITY::LOW); //!< Initiating reading data from store failed. Low, par1: returnCode, par2: 0
static const Event STORE_READ_FAILED = MAKE_EVENT(3, SEVERITY::LOW); //!< Data was requested, but access failed. Low, par1: returnCode, par2: 0
static const Event UNEXPECTED_MSG = MAKE_EVENT(4, SEVERITY::INFO); //!< An unexpected TM packet or data message occurred. Info, par1: 0, par2: integer (debug info)
static const Event STORING_FAILED = MAKE_EVENT(5, SEVERITY::LOW); //!< Storing data failed. May simply be a full store. Low, par1: returnCode, par2: integer (sequence count of failed packet).
static const Event TM_DUMP_FAILED = MAKE_EVENT(6, SEVERITY::LOW); //!< Dumping retrieved data failed. Low, par1: returnCode, par2: integer (sequence count of failed packet).
static const Event STORE_INIT_FAILED = MAKE_EVENT(7, SEVERITY::LOW); //!< Corrupted init data or read error. Low, par1: returnCode, par2: integer (debug info)
static const Event STORE_INIT_EMPTY = MAKE_EVENT(8, SEVERITY::INFO); //!< Store was not initialized. Starts empty. Info, parameters both zero.
static const Event STORE_CONTENT_CORRUPTED = MAKE_EVENT(9, SEVERITY::LOW); //!< Data was read out, but it is inconsistent. Low par1: 0, par2: integer (debug info)
static const Event STORE_INITIALIZE = MAKE_EVENT(10, SEVERITY::INFO); //!< Info event indicating the store will be initialized, either at boot or after IOB switch. Info. pars: 0
static const Event STORE_INIT_DONE = MAKE_EVENT(11, SEVERITY::INFO); //!< Info event indicating the store was successfully initialized, either at boot or after IOB switch. Info. pars: 0
virtual ~TmStoreBackendIF() {}
virtual ReturnValue_t performOperation() = 0;
virtual ReturnValue_t initialize() = 0;
virtual ReturnValue_t storePacket(TmPacketMinimal* tmPacket) = 0;
virtual ReturnValue_t fetchPackets(bool useAddress = false, uint32_t startAtAddress = 0) = 0;
virtual ReturnValue_t deleteContent(bool deletePart = false, uint32_t upToAddress = 0, uint32_t nDeletedPackets = 0, TmPacketMinimal* newOldestPacket = NULL) = 0;
virtual ReturnValue_t initializeStore() = 0;
virtual void resetStore(bool resetWrite = false, bool resetRead = false) = 0;
virtual bool isReady() = 0;
virtual uint32_t availableData() = 0;
virtual float getPercentageFilled() const = 0;
virtual uint32_t getStoredPacketsCount() const = 0;
virtual TmPacketInformation* getOldestPacket() = 0;
virtual TmPacketInformation* getYoungestPacket() = 0;
};
#endif /* PLATFORM_TMTCSERVICES_TMSTOREBACKENDIF_H_ */

View File

@ -0,0 +1,58 @@
/*
* TmStoreFrontendIF.h
*
* Created on: 19.02.2015
* Author: baetz
*/
#ifndef PLATFORM_TMTCSERVICES_TMSTOREFRONTENDIF_H_
#define PLATFORM_TMTCSERVICES_TMSTOREFRONTENDIF_H_
#include <framework/ipc/MessageQueueSender.h>
#include <framework/returnvalues/HasReturnvaluesIF.h>
class TmPacketMinimal;
class SpacePacketBase;
class TmStoreBackendIF;
class TmStoreFrontendIF {
public:
struct ApidSsc {
uint16_t apid;
uint16_t ssc;
};
virtual TmStoreBackendIF* getBackend() const = 0;
virtual ReturnValue_t performOperation() = 0;
/**
* Callback from the back-end to indicate a certain packet was received.
* front-end takes care of discarding/downloading the packet.
* @param packet Pointer to the newly received Space Packet.
* @param address Start address of the packet found
* @param isLastPacket Indicates if no more packets can be fetched.
* @return If more packets shall be fetched, RETURN_OK must be returned.
* Any other code stops fetching packets.
*/
virtual ReturnValue_t packetRetrieved(TmPacketMinimal* packet, uint32_t address, bool isLastPacket = false) = 0;
virtual void handleRetrievalFailed(ReturnValue_t errorCode, uint32_t parameter1 = 0, uint32_t parameter2 = 0) = 0;
/**
* To get the queue where commands shall be sent.
* @return Id of command queue.
*/
virtual MessageQueueId_t getCommandQueue() = 0;
virtual ReturnValue_t fetchPackets(ApidSsc start, ApidSsc end) = 0;
virtual ReturnValue_t deletePackets(ApidSsc upTo) = 0;
virtual ReturnValue_t checkPacket(SpacePacketBase* tmPacket) = 0;
virtual bool isEnabled() const = 0;
virtual void setEnabled(bool enabled) = 0;
virtual void restDownlinkedPacketCount() = 0;
static const uint8_t INTERFACE_ID = TM_STORE_FRONTEND_IF;
static const ReturnValue_t BUSY = MAKE_RETURN_CODE(1);
static const ReturnValue_t LAST_PACKET_FOUND = MAKE_RETURN_CODE(2);
static const ReturnValue_t STOP_FETCH = MAKE_RETURN_CODE(3);
static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(4);
virtual ~TmStoreFrontendIF() {
}
};
#endif /* PLATFORM_TMTCSERVICES_TMSTOREFRONTENDIF_H_ */

67
tmstorage/TmStoreInfo.h Normal file
View File

@ -0,0 +1,67 @@
/*
* TmStoreInfo.h
*
* Created on: 19.03.2015
* Author: baetz
*/
#ifndef FRAMEWORK_TMSTORAGE_TMSTOREINFO_H_
#define FRAMEWORK_TMSTORAGE_TMSTOREINFO_H_
#include <framework/serialize/SerializeElement.h>
#include <framework/serialize/SerialLinkedListAdapter.h>
class TmStoreInfo: public SerializeIF {
public:
SerializeElement<uint32_t> readP;
SerializeElement<uint32_t> writeP;
SerializeElement<uint32_t> storedPacketCount;
LinkedElement<SerializeIF> linkedOldestPacket;
LinkedElement<SerializeIF> linkedYoungestPacket;
SerializeElement<uint16_t> crc;
TmStoreInfo(SerializeIF* oldestPacket, SerializeIF* youngestPacket) :
readP(0), writeP(0), linkedOldestPacket(oldestPacket), linkedYoungestPacket(
youngestPacket) {
this->readP.setNext(&this->writeP);
this->writeP.setNext(&this->storedPacketCount);
storedPacketCount.setNext(&linkedOldestPacket);
linkedOldestPacket.setNext(&linkedYoungestPacket);
}
void setContent(uint32_t readP, uint32_t writeP, uint32_t storedPackets) {
this->readP = readP;
this->writeP = writeP;
this->storedPacketCount = storedPackets;
}
ReturnValue_t serialize(uint8_t** buffer, uint32_t* size,
const uint32_t max_size, bool bigEndian) const {
uint8_t* startBuffer = *buffer;
ReturnValue_t result = SerialLinkedListAdapter<SerializeIF>::serialize(
&readP, buffer, size, max_size, bigEndian);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
uint32_t elementSize =
SerialLinkedListAdapter<SerializeIF>::getSerializedSize(&readP);
SerializeElement<uint16_t> localCrc;
localCrc.entry = ::Calculate_CRC(startBuffer, elementSize);
return localCrc.serialize(buffer, size, max_size, bigEndian);
}
uint32_t getSerializedSize() const {
return (SerialLinkedListAdapter<SerializeIF>::getSerializedSize(&readP)
+ crc.getSerializedSize());
}
ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size,
bool bigEndian) {
ReturnValue_t result =
SerialLinkedListAdapter<SerializeIF>::deSerialize(&readP,
buffer, size, bigEndian);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return crc.deSerialize(buffer, size, bigEndian);
}
};
#endif /* FRAMEWORK_TMSTORAGE_TMSTOREINFO_H_ */

View File

@ -0,0 +1,511 @@
/*
* TmStoreManager.cpp
*
* Created on: 18.02.2015
* Author: baetz
*/
#include <framework/tmstorage/TmStoreManager.h>
#include <framework/tmstorage/TmStoreMessage.h>
#include <framework/tmtcpacket/SpacePacketBase.h>
#include <framework/tmtcservices/AcceptsTelemetryIF.h>
#include <framework/tmtcservices/TmTcMessage.h>
TmStoreManager::TmStoreManager(object_id_t objectId, object_id_t setDumpTarget,
uint8_t setVC, uint32_t setTimeoutMs) :
SystemObject(objectId), backend(NULL), tmForwardStore(NULL), dumpTarget(
setDumpTarget), virtualChannel(setVC), fetchState(
NOTHING_FETCHED), addressOfFetchCandidate(0), deletionStarted(
false), lastAddressToDelete(0), pendingPacketsToDelete(0), state(IDLE), storingEnabled(
false), timeoutMs(setTimeoutMs), ipcStore(NULL), downlinkedPacketsCount(
0), fullEventThrown(false) {
}
TmStoreManager::~TmStoreManager() {
}
ReturnValue_t TmStoreManager::initialize() {
ReturnValue_t result = SystemObject::initialize();
if (result != RETURN_OK) {
return result;
}
AcceptsTelemetryIF* telemetryDestimation = objectManager->get<
AcceptsTelemetryIF>(dumpTarget);
if (telemetryDestimation == NULL) {
return RETURN_FAILED;
}
tmQueue.setDefaultDestination(
telemetryDestimation->getReportReceptionQueue(virtualChannel));
tmForwardStore = objectManager->get<StorageManagerIF>(objects::TM_STORE);
if (tmForwardStore == NULL) {
return RETURN_FAILED;
}
result = backend->initialize();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
if (ipcStore == NULL) {
return RETURN_FAILED;
}
return matcher.initialize();
}
ReturnValue_t TmStoreManager::fetchPackets(ApidSsc start, ApidSsc end) {
//Check mode, store ids, start fetching.
if (state != IDLE) {
return BUSY;
}
if (start.apid < SpacePacketBase::LIMIT_APID) {
firstPacketToFetch = start;
fetchCandidate.apid = start.apid;
fetchState = NOTHING_FETCHED;
} else {
firstPacketToFetch.apid = SpacePacketBase::LIMIT_APID;
firstPacketToFetch.ssc = 0;
//There's no start defined, so we're in range automatically.
fetchState = IN_RANGE;
}
if (end.apid < SpacePacketBase::LIMIT_APID) {
lastPacketToFetch = end;
} else {
lastPacketToFetch.apid = SpacePacketBase::LIMIT_APID;
lastPacketToFetch.ssc = SpacePacketBase::LIMIT_SEQUENCE_COUNT;
}
//Advanced: start fetching at a certain position
ReturnValue_t result = backend->fetchPackets();
if (result != RETURN_OK) {
return result;
}
downlinkedPacketsCount = 0;
state = RETRIEVING_PACKETS;
return result;
}
ReturnValue_t TmStoreManager::performOperation() {
backend->performOperation();
checkCommandQueue();
return RETURN_OK;
}
ReturnValue_t TmStoreManager::packetRetrieved(TmPacketMinimal* packet,
uint32_t address, bool isLastPacket) {
ReturnValue_t result = RETURN_FAILED;
switch (state) {
case DELETING_PACKETS:
result = checkDeletionLimit(packet, address);
break;
case RETRIEVING_PACKETS:
result = checkRetrievalLimit(packet, address);
break;
case GET_OLDEST_PACKET_INFO: {
backend->deleteContent(true, lastAddressToDelete,
pendingPacketsToDelete, packet);
result = LAST_PACKET_FOUND;
}
break;
default:
triggerEvent(TmStoreBackendIF::UNEXPECTED_MSG, 0, packet->getPacketSequenceCount());
break;
}
switch (result) {
case RETURN_OK:
//We go on. But if lastPacket...
if (isLastPacket) {
//... we'll stop successfully.
replySuccess();
if (state == DELETING_PACKETS) {
//Store is completely deleted, so we can reset oldest and newest packet.
restDownlinkedPacketCount();
backend->resetStore();
}
state = IDLE;
}
break;
case LAST_PACKET_FOUND:
//All ok
replySuccess();
state = IDLE;
break;
case STOP_FETCH:
//This means, we started a new fetch. Returning STOP_FETCH will stop current scan. Stay in state.
break;
default:
//Some error occurred.
replyFailure(result);
state = IDLE;
break;
}
return result;
}
ReturnValue_t TmStoreManager::checkRetrievalLimit(TmPacketMinimal* packet,
uint32_t address) {
switch (fetchState) {
case NOTHING_FETCHED:
case BEFORE_RANGE:
if (packet->getAPID() != firstPacketToFetch.apid) {
//Dump all packets of unknown APID.
dumpPacket(packet);
return RETURN_OK;
}
if (packet->getPacketSequenceCount() < firstPacketToFetch.ssc) {
addressOfFetchCandidate = address;
fetchCandidate.ssc = packet->getPacketSequenceCount();
fetchState = BEFORE_RANGE;
return RETURN_OK;
} else if ((packet->getPacketSequenceCount() == firstPacketToFetch.ssc)
|| (fetchState == NOTHING_FETCHED)) {
//We have either found the right packet or one with higher count without having an older packet. So dump.
fetchState = IN_RANGE;
dumpPacket(packet);
if (packet->getPacketSequenceCount() < lastPacketToFetch.ssc) {
return RETURN_OK;
} else {
return LAST_PACKET_FOUND;
}
} else {
//We're in range, but the expected SSC is not in store. So we shall restart from the first older packet.
ReturnValue_t result = backend->fetchPackets(true,
addressOfFetchCandidate);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
fetchState = NOTHING_FETCHED;
firstPacketToFetch = fetchCandidate;
return STOP_FETCH;
}
case IN_RANGE:
dumpPacket(packet);
if ((packet->getAPID() == lastPacketToFetch.apid)
&& (packet->getPacketSequenceCount() >= lastPacketToFetch.ssc)) {
return LAST_PACKET_FOUND;
} else {
return RETURN_OK;
}
default:
break;
}
return RETURN_FAILED;
}
ReturnValue_t TmStoreManager::deletePackets(ApidSsc upTo) {
if (state != IDLE) {
return BUSY;
}
if (upTo.apid >= SpacePacketBase::LIMIT_APID) {
ReturnValue_t result = backend->deleteContent();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
restDownlinkedPacketCount();
return result;
} else {
state = DELETING_PACKETS;
restDownlinkedPacketCount();
lastPacketToDelete = upTo;
deletionStarted = false;
pendingPacketsToDelete = 0;
return backend->fetchPackets();
}
}
ReturnValue_t TmStoreManager::checkDeletionLimit(TmPacketMinimal* packet,
uint32_t address) {
uint32_t addressOfLastByte = address + packet->getFullSize();
if (packet->getAPID() == lastPacketToDelete.apid) {
if (packet->getPacketSequenceCount() < lastPacketToDelete.ssc) {
if (deletionStarted) {
backend->deleteContent(true, lastAddressToDelete,
pendingPacketsToDelete, packet);
pendingPacketsToDelete = 0;
} else {
deletionStarted = true;
}
pendingPacketsToDelete++;
lastAddressToDelete = addressOfLastByte;
return RETURN_OK;
} else if (packet->getPacketSequenceCount() == lastPacketToDelete.ssc) {
lastAddressToDelete = addressOfLastByte;
pendingPacketsToDelete++;
state = GET_OLDEST_PACKET_INFO;
return RETURN_OK;
} else {
return LAST_PACKET_FOUND;
}
} else {
lastAddressToDelete = addressOfLastByte;
pendingPacketsToDelete++;
return RETURN_OK;
}
}
void TmStoreManager::setBackend(TmStoreBackendIF* backend) {
this->backend = backend;
}
TmStoreBackendIF* TmStoreManager::getBackend() const {
return backend;
}
ReturnValue_t TmStoreManager::checkPacket(SpacePacketBase* tmPacket) {
if (!storingEnabled) {
return RETURN_OK;
}
TmPacketMinimal testPacket(tmPacket->getWholeData());
if (matcher.match(&testPacket)) {
ReturnValue_t result = backend->storePacket(&testPacket);
if (result != HasReturnvaluesIF::RETURN_OK) {
//Generate only one event to avoid full event store loop.
if (!fullEventThrown) {
triggerEvent(TmStoreBackendIF::STORING_FAILED, result, testPacket.getPacketSequenceCount());
fullEventThrown = true;
}
} else {
fullEventThrown = false;
}
return result;
} else {
return RETURN_OK;
}
}
void TmStoreManager::dumpPacket(SpacePacketBase* packet) {
store_address_t forwardStoreId;
TmTcMessage message;
ReturnValue_t result = tmForwardStore->addData(&forwardStoreId,
packet->getWholeData(), packet->getFullSize());
if (result != RETURN_OK) {
triggerEvent(TmStoreBackendIF::TM_DUMP_FAILED, result, packet->getPacketSequenceCount());
return;
}
message.setStorageId(forwardStoreId);
result = tmQueue.sendToDefault(&message);
if (result != RETURN_OK) {
triggerEvent(TmStoreBackendIF::TM_DUMP_FAILED, result, packet->getPacketSequenceCount());
tmForwardStore->deleteData(forwardStoreId);
return;
}
downlinkedPacketsCount.entry++;
}
bool TmStoreManager::isEnabled() const {
return storingEnabled;
}
void TmStoreManager::setEnabled(bool enabled) {
storingEnabled = enabled;
}
void TmStoreManager::checkCommandQueue() {
if (state != IDLE) {
if (timer.hasTimedOut()) {
replyFailure(TIMEOUT);
state = IDLE;
}
return;
}
CommandMessage message;
for (ReturnValue_t result = commandQueue.receiveMessage(&message);
result == RETURN_OK;
result = commandQueue.receiveMessage(&message)) {
switch (message.getCommand()) {
case TmStoreMessage::ENABLE_STORING:
setEnabled(TmStoreMessage::getEnableStoring(&message));
replySuccess();
break;
case TmStoreMessage::CHANGE_SELECTION_DEFINITION: {
uint32_t errorCount = 0;
result = changeSelectionDefinition(
TmStoreMessage::getAddToSelection(&message),
TmStoreMessage::getStoreId(&message), &errorCount);
if (result != RETURN_OK) {
replyFailure(result, errorCount);
} else {
replySuccess();
}
break;
}
case TmStoreMessage::DOWNLINK_STORE_CONTENT:
result = fetchPackets(TmStoreMessage::getPacketId1(&message),
TmStoreMessage::getPacketId2(&message));
if (result != RETURN_OK) {
if (result == TmStoreBackendIF::EMPTY) {
replySuccess();
} else {
replyFailure(result);
}
} else {
timer.setTimeout(timeoutMs);
}
break;
case TmStoreMessage::DELETE_STORE_CONTENT:
result = deletePackets(TmStoreMessage::getPacketId1(&message));
if (result == RETURN_OK) {
if (state == IDLE) {
//We're finished
replySuccess();
} else {
timer.setTimeout(timeoutMs);
}
} else {
replyFailure(result);
}
break;
case TmStoreMessage::REPORT_SELECTION_DEFINITION:
result = sendMatchTree();
if (result != RETURN_OK) {
replyFailure(result);
}
break;
case TmStoreMessage::REPORT_STORE_CATALOGUE:
result = sendStatistics();
if (result != RETURN_OK) {
replyFailure(result);
}
break;
default:
replyFailure(CommandMessage::UNKNOW_COMMAND, message.getCommand());
break;
}
}
}
void TmStoreManager::replySuccess() {
CommandMessage reply(CommandMessage::REPLY_COMMAND_OK, 0, 0);
commandQueue.reply(&reply);
}
MessageQueueId_t TmStoreManager::getCommandQueue() {
return commandQueue.getId();
}
void TmStoreManager::replyFailure(ReturnValue_t errorCode, uint32_t parameter) {
CommandMessage reply(CommandMessage::REPLY_REJECTED, errorCode, parameter);
commandQueue.reply(&reply);
}
ReturnValue_t TmStoreManager::changeSelectionDefinition(bool addSelection,
store_address_t storeId, uint32_t* errorCount) {
const uint8_t* pData;
uint32_t size = 0;
ReturnValue_t result = ipcStore->getData(storeId, &pData, &size);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
int32_t iSize = size;
ChangeSelectionDefinition content;
result = content.deSerialize(&pData, &iSize, true);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
ReturnValue_t totalResult = RETURN_OK;
if (content.serviceList.size == 0) {
return updateMatch(addSelection, content.apid, NO_SERVICE,
NO_SUBSERVICE);
}
for (auto iter = content.serviceList.begin();
iter != content.serviceList.end(); iter++) {
if (iter->subservices.size == 0) {
result = updateMatch(addSelection, content.apid,
iter->service, NO_SUBSERVICE);
if (result != HasReturnvaluesIF::RETURN_OK) {
totalResult = result;
(*errorCount)++;
}
} else {
for (auto iter2 = iter->subservices.begin();
iter2 != iter->subservices.end(); iter2++) {
result = updateMatch(addSelection, content.apid,
iter->service, *(iter2.value));
if (result != HasReturnvaluesIF::RETURN_OK) {
totalResult = result;
(*errorCount)++;
}
}
}
}
return totalResult;
}
ReturnValue_t TmStoreManager::sendMatchTree() {
store_address_t storeId;
uint8_t* buffer;
uint32_t maxSize = matcher.getSerializedSize();
ReturnValue_t result = ipcStore->getFreeElement(&storeId, maxSize, &buffer);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
uint32_t size = 0;
result = matcher.serialize(&buffer, &size, maxSize, true);
if (result != HasReturnvaluesIF::RETURN_OK) {
ipcStore->deleteData(storeId);
return result;
}
CommandMessage reply;
TmStoreMessage::setSelectionDefinitionReportMessage(&reply, storeId);
result = commandQueue.reply(&reply);
if (result != RETURN_OK) {
ipcStore->deleteData(storeId);
}
return result;
}
void TmStoreManager::restDownlinkedPacketCount() {
downlinkedPacketsCount = 0;
}
ReturnValue_t TmStoreManager::updateMatch(bool addSelection, uint16_t apid, uint8_t serviceType,
uint8_t serviceSubtype) {
return matcher.changeMatch(addSelection, apid, serviceType, serviceSubtype);
}
void TmStoreManager::handleRetrievalFailed(ReturnValue_t errorCode,
uint32_t parameter1, uint32_t parameter2) {
restDownlinkedPacketCount();
state = IDLE;
replyFailure(errorCode, parameter1);
}
ReturnValue_t TmStoreManager::sendStatistics() {
LinkedElement<SerializeIF> linkedOldestPacket(backend->getOldestPacket());
LinkedElement<SerializeIF> linkedYoungestPacket(
backend->getYoungestPacket());
SerializeElement<float> percentageFilled(backend->getPercentageFilled());
float pDownlinked =
(backend->getStoredPacketsCount() != 0) ?
(float) downlinkedPacketsCount
/ (float) backend->getStoredPacketsCount() :
0.0;
SerializeElement<float> percentageDownlinked(pDownlinked);
SerializeElement<uint32_t> storedPacketsCount(
backend->getStoredPacketsCount());
linkedOldestPacket.setNext(&linkedYoungestPacket);
linkedYoungestPacket.setNext(&percentageFilled);
percentageFilled.setNext(&percentageDownlinked);
percentageDownlinked.setNext(&storedPacketsCount);
storedPacketsCount.setNext(&downlinkedPacketsCount);
store_address_t storeId;
uint8_t* buffer;
uint32_t maxSize = SerialLinkedListAdapter<SerializeIF>::getSerializedSize(
&linkedOldestPacket);
ReturnValue_t result = ipcStore->getFreeElement(&storeId, maxSize, &buffer);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
uint32_t size = 0;
result = SerialLinkedListAdapter<SerializeIF>::serialize(
&linkedOldestPacket, &buffer, &size, maxSize, true);
if (result != HasReturnvaluesIF::RETURN_OK) {
ipcStore->deleteData(storeId);
return result;
}
CommandMessage reply;
TmStoreMessage::setStoreCatalogueReportMessage(&reply, storeId);
result = commandQueue.reply(&reply);
if (result != RETURN_OK) {
ipcStore->deleteData(storeId);
}
return result;
}

View File

@ -0,0 +1,90 @@
/*
* TmStoreManager.h
*
* Created on: 18.02.2015
* Author: baetz
*/
#ifndef PLATFORM_TMTCSERVICES_TMSTOREMANAGER_H_
#define PLATFORM_TMTCSERVICES_TMSTOREMANAGER_H_
#include <framework/ipc/MessageQueue.h>
#include <framework/objectmanager/ObjectManagerIF.h>
#include <framework/objectmanager/SystemObject.h>
#include <framework/returnvalues/HasReturnvaluesIF.h>
#include <framework/storagemanager/StorageManagerIF.h>
#include <framework/tasks/ExecutableObjectIF.h>
#include <framework/timemanager/Countdown.h>
#include <framework/tmstorage/TmStoreBackendIF.h>
#include <framework/tmstorage/TmStoreFrontendIF.h>
#include <framework/tmstorage/TmStorePackets.h>
#include <framework/tmtcpacket/packetmatcher/PacketMatchTree.h>
class TmStoreManager : public SystemObject, public HasReturnvaluesIF, public TmStoreFrontendIF {
public:
TmStoreManager(object_id_t objectId, object_id_t setDumpTarget, uint8_t setVC, uint32_t setTimeoutMs);
virtual ~TmStoreManager();
ReturnValue_t fetchPackets(ApidSsc start, ApidSsc end);
ReturnValue_t deletePackets(ApidSsc upTo);
ReturnValue_t checkPacket(SpacePacketBase* tmPacket);
ReturnValue_t performOperation();
ReturnValue_t initialize();
ReturnValue_t packetRetrieved(TmPacketMinimal* packet, uint32_t address, bool isLastPacket = false);
void handleRetrievalFailed(ReturnValue_t errorCode, uint32_t parameter1 = 0, uint32_t parameter2 = 0);
bool isEnabled() const;
void setEnabled(bool enabled);
void setBackend(TmStoreBackendIF* backend);
TmStoreBackendIF* getBackend() const;
MessageQueueId_t getCommandQueue();
ReturnValue_t updateMatch(bool addSelection, uint16_t apid, uint8_t serviceType, uint8_t serviceSubtype);
private:
MessageQueue commandQueue;
TmStoreBackendIF* backend;
StorageManagerIF* tmForwardStore;
MessageQueueSender tmQueue;
const object_id_t dumpTarget;
const uint8_t virtualChannel;
enum FetchState {
NOTHING_FETCHED,
BEFORE_RANGE,
IN_RANGE
};
FetchState fetchState;
ApidSsc firstPacketToFetch;
ApidSsc lastPacketToFetch;
uint32_t addressOfFetchCandidate;
ApidSsc fetchCandidate;
bool deletionStarted;
ApidSsc lastPacketToDelete;
uint32_t lastAddressToDelete;
uint32_t pendingPacketsToDelete;
TmPacketInformation pendingOldestPacket;
enum State {
IDLE,
DELETING_PACKETS,
RETRIEVING_PACKETS,
GET_OLDEST_PACKET_INFO
};
State state;
bool storingEnabled;
const uint32_t timeoutMs;
Countdown timer;
PacketMatchTree matcher;
StorageManagerIF* ipcStore;
SerializeElement<uint32_t> downlinkedPacketsCount;
bool fullEventThrown;
ReturnValue_t checkRetrievalLimit(TmPacketMinimal* packet, uint32_t address);
ReturnValue_t checkDeletionLimit(TmPacketMinimal* packet, uint32_t address);
void dumpPacket(SpacePacketBase* packet);
void checkCommandQueue();
void replySuccess();
void replyFailure(ReturnValue_t errorCode, uint32_t parameter = 0);
ReturnValue_t changeSelectionDefinition(bool addSelection, store_address_t storeId, uint32_t* errorCount);
ReturnValue_t sendMatchTree();
void restDownlinkedPacketCount();
ReturnValue_t sendStatistics();
static const uint8_t NO_SERVICE = 0;
static const uint8_t NO_SUBSERVICE = 0;
};
#endif /* PLATFORM_TMTCSERVICES_TMSTOREMANAGER_H_ */

View File

@ -0,0 +1,115 @@
/*
* TmStoreMessage.cpp
*
* Created on: 23.02.2015
* Author: baetz
*/
#include <framework/objectmanager/ObjectManagerIF.h>
#include <framework/tmstorage/TmStoreMessage.h>
TmStoreMessage::~TmStoreMessage() {
}
TmStoreMessage::TmStoreMessage() {
}
ReturnValue_t TmStoreMessage::setEnableStoringMessage(CommandMessage* cmd,
bool setEnabled) {
cmd->setCommand(ENABLE_STORING);
cmd->setParameter(setEnabled);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TmStoreMessage::setDeleteContentMessage(CommandMessage* cmd,
TmStoreFrontendIF::ApidSsc upTo) {
cmd->setCommand(DELETE_STORE_CONTENT);
cmd->setParameter((upTo.apid<<16) + upTo.ssc);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TmStoreMessage::setDownlinkContentMessage(CommandMessage* cmd,
TmStoreFrontendIF::ApidSsc fromPacket,
TmStoreFrontendIF::ApidSsc toPacket) {
cmd->setCommand(DOWNLINK_STORE_CONTENT);
cmd->setParameter((fromPacket.apid<<16) + fromPacket.ssc);
cmd->setParameter2((toPacket.apid<<16) + toPacket.ssc);
return HasReturnvaluesIF::RETURN_OK;
}
TmStoreFrontendIF::ApidSsc TmStoreMessage::getPacketId1(CommandMessage* cmd) {
TmStoreFrontendIF::ApidSsc temp;
temp.apid = (cmd->getParameter() >> 16) & 0xFFFF;
temp.ssc = cmd->getParameter() & 0xFFFF;
return temp;
}
TmStoreFrontendIF::ApidSsc TmStoreMessage::getPacketId2(CommandMessage* cmd) {
TmStoreFrontendIF::ApidSsc temp;
temp.apid = (cmd->getParameter2() >> 16) & 0xFFFF;
temp.ssc = cmd->getParameter2() & 0xFFFF;
return temp;
}
bool TmStoreMessage::getEnableStoring(CommandMessage* cmd) {
return (bool)cmd->getParameter();
}
void TmStoreMessage::setChangeSelectionDefinitionMessage(
CommandMessage* cmd, bool addDefinition, store_address_t store_id) {
cmd->setCommand(CHANGE_SELECTION_DEFINITION);
cmd->setParameter(addDefinition);
cmd->setParameter2(store_id.raw);
}
void TmStoreMessage::clear(CommandMessage* cmd) {
switch(cmd->getCommand()) {
case SELECTION_DEFINITION_REPORT:
case STORE_CATALOGUE_REPORT:
case CHANGE_SELECTION_DEFINITION: {
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>(
objects::IPC_STORE);
if (ipcStore != NULL) {
ipcStore->deleteData(getStoreId(cmd));
}
}
break;
default:
break;
}
}
store_address_t TmStoreMessage::getStoreId(const CommandMessage* cmd) {
store_address_t temp;
temp.raw = cmd->getParameter2();
return temp;
}
bool TmStoreMessage::getAddToSelection(CommandMessage* cmd) {
return (bool)cmd->getParameter();
}
ReturnValue_t TmStoreMessage::setReportSelectionDefinitionMessage(
CommandMessage* cmd) {
cmd->setCommand(REPORT_SELECTION_DEFINITION);
return HasReturnvaluesIF::RETURN_OK;
}
void TmStoreMessage::setSelectionDefinitionReportMessage(
CommandMessage* cmd, store_address_t storeId) {
cmd->setCommand(SELECTION_DEFINITION_REPORT);
cmd->setParameter2(storeId.raw);
}
ReturnValue_t TmStoreMessage::setReportStoreCatalogueMessage(
CommandMessage* cmd) {
cmd->setCommand(REPORT_STORE_CATALOGUE);
return HasReturnvaluesIF::RETURN_OK;
}
void TmStoreMessage::setStoreCatalogueReportMessage(CommandMessage* cmd,
store_address_t storeId) {
cmd->setCommand(STORE_CATALOGUE_REPORT);
cmd->setParameter2(storeId.raw);
}

View File

@ -0,0 +1,45 @@
/*
* TmStoreMessage.h
*
* Created on: 23.02.2015
* Author: baetz
*/
#ifndef FRAMEWORK_TMSTORAGE_TMSTOREMESSAGE_H_
#define FRAMEWORK_TMSTORAGE_TMSTOREMESSAGE_H_
#include <framework/ipc/CommandMessage.h>
#include <framework/storagemanager/StorageManagerIF.h>
#include <framework/tmstorage/TmStoreFrontendIF.h>
class TmStoreMessage: public CommandMessage {
public:
static ReturnValue_t setEnableStoringMessage(CommandMessage* cmd, bool setEnabled);
static ReturnValue_t setDeleteContentMessage(CommandMessage* cmd, TmStoreFrontendIF::ApidSsc upTo);
static ReturnValue_t setDownlinkContentMessage(CommandMessage* cmd, TmStoreFrontendIF::ApidSsc fromPacket, TmStoreFrontendIF::ApidSsc toPacket );
static void setChangeSelectionDefinitionMessage(CommandMessage* cmd, bool addDefinition, store_address_t store_id);
static ReturnValue_t setReportSelectionDefinitionMessage(CommandMessage* cmd);
static void setSelectionDefinitionReportMessage(CommandMessage* cmd, store_address_t storeId);
static ReturnValue_t setReportStoreCatalogueMessage(CommandMessage* cmd);
static void setStoreCatalogueReportMessage(CommandMessage* cmd, store_address_t storeId);
static void clear(CommandMessage* cmd);
static TmStoreFrontendIF::ApidSsc getPacketId1(CommandMessage* cmd);
static TmStoreFrontendIF::ApidSsc getPacketId2(CommandMessage* cmd);
static bool getEnableStoring(CommandMessage* cmd);
static bool getAddToSelection(CommandMessage* cmd);
static store_address_t getStoreId(const CommandMessage* cmd);
virtual ~TmStoreMessage();
static const uint8_t MESSAGE_ID = TM_STORE_MESSAGE_ID;
static const Command_t ENABLE_STORING = MAKE_COMMAND_ID(1);
static const Command_t DELETE_STORE_CONTENT = MAKE_COMMAND_ID(2);
static const Command_t DOWNLINK_STORE_CONTENT = MAKE_COMMAND_ID(3);
static const Command_t CHANGE_SELECTION_DEFINITION = MAKE_COMMAND_ID(4);
static const Command_t REPORT_SELECTION_DEFINITION = MAKE_COMMAND_ID(5);
static const Command_t SELECTION_DEFINITION_REPORT = MAKE_COMMAND_ID(6);
static const Command_t REPORT_STORE_CATALOGUE = MAKE_COMMAND_ID(7);
static const Command_t STORE_CATALOGUE_REPORT = MAKE_COMMAND_ID(8);
private:
TmStoreMessage();
};
#endif /* FRAMEWORK_TMSTORAGE_TMSTOREMESSAGE_H_ */

View File

@ -0,0 +1,91 @@
/*
* TmStorePackets.h
*
* Created on: 11.03.2015
* Author: baetz
*/
#ifndef FRAMEWORK_TMSTORAGE_TMSTOREPACKETS_H_
#define FRAMEWORK_TMSTORAGE_TMSTOREPACKETS_H_
#include <framework/serialize/SerialFixedArrayListAdapter.h>
#include <framework/serialize/SerializeElement.h>
#include <framework/serialize/SerialLinkedListAdapter.h>
#include <framework/tmtcpacket/pus/TmPacketMinimal.h>
class ServiceSubservice: public SerialLinkedListAdapter<SerializeIF> {
public:
SerializeElement<uint8_t> service;
SerialFixedArrayListAdapter<uint8_t, 16> subservices;
LinkedElement<SerializeIF> linkedSubservices;
ServiceSubservice() :
SerialLinkedListAdapter<SerializeIF>(&service), linkedSubservices(
&subservices) {
service.setNext(&linkedSubservices);
}
};
class ChangeSelectionDefinition: public SerialLinkedListAdapter<SerializeIF> {
public:
SerializeElement<uint16_t> apid;
SerialFixedArrayListAdapter<ServiceSubservice, 16> serviceList;
LinkedElement<SerializeIF> linkedServiceList;
ChangeSelectionDefinition() :
SerialLinkedListAdapter<SerializeIF>(&apid), linkedServiceList(
&serviceList) {
apid.setNext(&linkedServiceList);
}
};
class TmPacketInformation: public SerialLinkedListAdapter<SerializeIF> {
public:
TmPacketInformation(TmPacketMinimal* packet) :
SerialLinkedListAdapter<SerializeIF>(&apid) {
setAllNext();
setContent(packet);
}
TmPacketInformation() :
SerialLinkedListAdapter<SerializeIF>(&apid), apid(
SpacePacketBase::LIMIT_APID), sourceSequenceCount(0), serviceType(
0), serviceSubtype(0), subCounter(0) {
setAllNext();
}
void reset() {
apid = SpacePacketBase::LIMIT_APID;
sourceSequenceCount = 0;
serviceType = 0;
serviceSubtype = 0;
subCounter = 0;
}
void setContent(TmPacketMinimal* packet) {
apid = packet->getAPID();
sourceSequenceCount = packet->getPacketSequenceCount();
serviceType = packet->getService();
serviceSubtype = packet->getSubService();
subCounter = packet->getPacketSubcounter();
}
void setContent(TmPacketInformation* content) {
apid.entry = content->apid.entry;
sourceSequenceCount.entry = content->sourceSequenceCount.entry;
serviceType.entry = content->serviceType.entry;
serviceSubtype.entry = content->serviceSubtype.entry;
subCounter.entry = content->subCounter.entry;
}
bool isValid() {
return (apid < SpacePacketBase::LIMIT_APID) ? true : false;
}
private:
SerializeElement<uint16_t> apid;
SerializeElement<uint16_t> sourceSequenceCount;
SerializeElement<uint8_t> serviceType;
SerializeElement<uint8_t> serviceSubtype;
SerializeElement<uint8_t> subCounter;
void setAllNext() {
apid.setNext(&sourceSequenceCount);
sourceSequenceCount.setNext(&serviceType);
serviceType.setNext(&serviceSubtype);
serviceSubtype.setNext(&subCounter);
}
};
#endif /* FRAMEWORK_TMSTORAGE_TMSTOREPACKETS_H_ */