Today's the day. Renamed platform to framework.
This commit is contained in:
704
tmstorage/TmStore.cpp
Normal file
704
tmstorage/TmStore.cpp
Normal 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
147
tmstorage/TmStore.h
Normal 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_ */
|
60
tmstorage/TmStoreBackendIF.h
Normal file
60
tmstorage/TmStoreBackendIF.h
Normal 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_ */
|
58
tmstorage/TmStoreFrontendIF.h
Normal file
58
tmstorage/TmStoreFrontendIF.h
Normal 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
67
tmstorage/TmStoreInfo.h
Normal 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_ */
|
511
tmstorage/TmStoreManager.cpp
Normal file
511
tmstorage/TmStoreManager.cpp
Normal 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;
|
||||
}
|
90
tmstorage/TmStoreManager.h
Normal file
90
tmstorage/TmStoreManager.h
Normal 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_ */
|
115
tmstorage/TmStoreMessage.cpp
Normal file
115
tmstorage/TmStoreMessage.cpp
Normal 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);
|
||||
}
|
45
tmstorage/TmStoreMessage.h
Normal file
45
tmstorage/TmStoreMessage.h
Normal 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_ */
|
91
tmstorage/TmStorePackets.h
Normal file
91
tmstorage/TmStorePackets.h
Normal 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_ */
|
Reference in New Issue
Block a user