PTME rework reset handling #542
@ -27,27 +27,27 @@ ReturnValue_t PapbVcInterface::initialize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size) {
|
ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size) {
|
||||||
if (pollPapbBusySignal(0) == returnvalue::OK) {
|
if (pollInterfaceReadiness(0, true) == returnvalue::OK) {
|
||||||
startPacketTransfer();
|
startPacketTransfer();
|
||||||
} else {
|
} else {
|
||||||
return DirectTmSinkIF::IS_BUSY;
|
return DirectTmSinkIF::IS_BUSY;
|
||||||
}
|
}
|
||||||
for (size_t idx = 0; idx < size; idx++) {
|
for (size_t idx = 0; idx < size; idx++) {
|
||||||
// This delay is super-important, DO NOT REMOVE!
|
// This delay is super-important, DO NOT REMOVE!
|
||||||
// Polling the GPIO too often can mess up the scheduler.
|
// Polling the GPIO or the config register too often messes up the scheduler.
|
||||||
// TODO: Maybe this should not be done like this. It would be better if there was a custom
|
// TODO: Maybe this should not be done like this. It would be better if there was a custom
|
||||||
// FPGA module which can accept packets and then takes care of dumping that packet into
|
// FPGA module which can accept packets and then takes care of dumping that packet into
|
||||||
// the PTME. DMA would be an ideal solution for this.
|
// the PTME. DMA would be an ideal solution for this.
|
||||||
// nanosleep(&BETWEEN_POLL_DELAY, &remDelay);
|
nanosleep(&BETWEEN_POLL_DELAY, &remDelay);
|
||||||
if (pollPapbBusySignal(2) == returnvalue::OK) {
|
if (pollInterfaceReadiness(2, false) == returnvalue::OK) {
|
||||||
*(vcBaseReg + DATA_REG_OFFSET) = static_cast<uint32_t>(data[idx]);
|
*(vcBaseReg + DATA_REG_OFFSET) = static_cast<uint32_t>(data[idx]);
|
||||||
} else {
|
} else {
|
||||||
abortPacketTransfer();
|
abortPacketTransfer();
|
||||||
return returnvalue::FAILED;
|
return returnvalue::FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// nanosleep(&BETWEEN_POLL_DELAY, &remDelay);
|
nanosleep(&BETWEEN_POLL_DELAY, &remDelay);
|
||||||
if (pollPapbBusySignal(2) == returnvalue::OK) {
|
if (pollInterfaceReadiness(2, false) == returnvalue::OK) {
|
||||||
completePacketTransfer();
|
completePacketTransfer();
|
||||||
} else {
|
} else {
|
||||||
abortPacketTransfer();
|
abortPacketTransfer();
|
||||||
@ -60,17 +60,23 @@ void PapbVcInterface::startPacketTransfer() { *vcBaseReg = CONFIG_START; }
|
|||||||
|
|
||||||
void PapbVcInterface::completePacketTransfer() { *vcBaseReg = CONFIG_END; }
|
void PapbVcInterface::completePacketTransfer() { *vcBaseReg = CONFIG_END; }
|
||||||
|
|
||||||
ReturnValue_t PapbVcInterface::pollPapbBusySignal(uint32_t maxPollRetries) const {
|
ReturnValue_t PapbVcInterface::pollInterfaceReadiness(uint32_t maxPollRetries,
|
||||||
|
bool checkReadyState) const {
|
||||||
uint32_t busyIdx = 0;
|
uint32_t busyIdx = 0;
|
||||||
nextDelay.tv_nsec = 0;
|
nextDelay.tv_nsec = FIRST_NON_NULL_DELAY_NS;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// Check if PAPB interface is ready to receive data. Use the configuration register for this.
|
// Check if PAPB interface is ready to receive data. Use the configuration register for this.
|
||||||
// Bit 5, see PTME ptme_001_01-0-7-r2 Table 31.
|
// Bit 5, see PTME ptme_001_01-0-7-r2 Table 31.
|
||||||
bool busy = ((*vcBaseReg) >> 5) & 0b1;
|
uint32_t reg = *vcBaseReg;
|
||||||
|
bool busy = (reg >> 5) & 0b1;
|
||||||
|
bool ready = (reg >> 6) & 0b1;
|
||||||
if (not busy) {
|
if (not busy) {
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
if(checkReadyState and not ready) {
|
||||||
|
return PAPB_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
busyIdx++;
|
busyIdx++;
|
||||||
if (busyIdx >= maxPollRetries) {
|
if (busyIdx >= maxPollRetries) {
|
||||||
@ -80,9 +86,7 @@ ReturnValue_t PapbVcInterface::pollPapbBusySignal(uint32_t maxPollRetries) const
|
|||||||
// Ignore signal handling here for now.
|
// Ignore signal handling here for now.
|
||||||
nanosleep(&nextDelay, &remDelay);
|
nanosleep(&nextDelay, &remDelay);
|
||||||
// Adaptive delay.
|
// Adaptive delay.
|
||||||
if (nextDelay.tv_nsec == 0) {
|
if (nextDelay.tv_nsec * 2 <= MAX_DELAY_PAPB_POLLING_NS) {
|
||||||
nextDelay.tv_nsec = FIRST_NON_NULL_DELAY_NS;
|
|
||||||
} else if (nextDelay.tv_nsec * 2 <= MAX_DELAY_PAPB_POLLING_NS) {
|
|
||||||
nextDelay.tv_nsec *= 2;
|
nextDelay.tv_nsec *= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,7 +113,7 @@ void PapbVcInterface::isVcInterfaceBufferEmpty() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PapbVcInterface::isBusy() const { return pollPapbBusySignal(0) == PAPB_BUSY; }
|
bool PapbVcInterface::isBusy() const { return pollInterfaceReadiness(0, true) == PAPB_BUSY; }
|
||||||
|
|
||||||
void PapbVcInterface::cancelTransfer() { abortPacketTransfer(); }
|
void PapbVcInterface::cancelTransfer() { abortPacketTransfer(); }
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ class PapbVcInterface : public VirtualChannelIF {
|
|||||||
std::string uioFile;
|
std::string uioFile;
|
||||||
int mapNum = 0;
|
int mapNum = 0;
|
||||||
mutable struct timespec nextDelay = {.tv_sec = 0, .tv_nsec = 0};
|
mutable struct timespec nextDelay = {.tv_sec = 0, .tv_nsec = 0};
|
||||||
const struct timespec BETWEEN_POLL_DELAY = {.tv_sec = 0, .tv_nsec = 5};
|
const struct timespec BETWEEN_POLL_DELAY = {.tv_sec = 0, .tv_nsec = 10};
|
||||||
mutable struct timespec remDelay;
|
mutable struct timespec remDelay;
|
||||||
|
|
||||||
volatile uint32_t* vcBaseReg = nullptr;
|
volatile uint32_t* vcBaseReg = nullptr;
|
||||||
@ -119,7 +119,7 @@ class PapbVcInterface : public VirtualChannelIF {
|
|||||||
*
|
*
|
||||||
* @return returnvalue::OK when ready to receive data else PAPB_BUSY.
|
* @return returnvalue::OK when ready to receive data else PAPB_BUSY.
|
||||||
*/
|
*/
|
||||||
inline ReturnValue_t pollPapbBusySignal(uint32_t maxPollRetries) const;
|
inline ReturnValue_t pollInterfaceReadiness(uint32_t maxPollRetries, bool checkReadyState) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function can be used for debugging to check whether there are packets in
|
* @brief This function can be used for debugging to check whether there are packets in
|
||||||
|
@ -25,6 +25,9 @@ ReturnValue_t PersistentSingleTmStoreTask::performOperation(uint8_t opCode) {
|
|||||||
} else if (dumpContext.vcBusyDuringDump) {
|
} else if (dumpContext.vcBusyDuringDump) {
|
||||||
// TODO: Might not be necessary
|
// TODO: Might not be necessary
|
||||||
TaskFactory::delayTask(10);
|
TaskFactory::delayTask(10);
|
||||||
|
} else {
|
||||||
|
// TODO: Would be best to remove this, but not delaying here can lead to evil issues.
|
||||||
|
TaskFactory::delayTask(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,11 +142,12 @@ ReturnValue_t TmStoreTaskBase::performDump(PersistentTmStoreWithTmQueue& store,
|
|||||||
dumpDoneHandler();
|
dumpDoneHandler();
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
dumpedLen = tmReader.getFullPacketLen();
|
||||||
// Only write to VC if mode is on, but always confirm the dump.
|
// Only write to VC if mode is on, but always confirm the dump.
|
||||||
// If the mode is OFF, it is assumed the PTME is not usable and is not allowed to be written
|
// If the mode is OFF, it is assumed the PTME is not usable and is not allowed to be written
|
||||||
// (e.g. to confirm a reset or the transmitter is off anyway).
|
// (e.g. to confirm a reset or the transmitter is off anyway).
|
||||||
if (mode == MODE_ON) {
|
if (mode == MODE_ON) {
|
||||||
result = channel.write(tmReader.getFullData(), tmReader.getFullPacketLen());
|
result = channel.write(tmReader.getFullData(), dumpedLen);
|
||||||
if (result == DirectTmSinkIF::IS_BUSY) {
|
if (result == DirectTmSinkIF::IS_BUSY) {
|
||||||
sif::warning << "PersistentTmStore: Unexpected VC channel busy" << std::endl;
|
sif::warning << "PersistentTmStore: Unexpected VC channel busy" << std::endl;
|
||||||
} else if (result != returnvalue::OK) {
|
} else if (result != returnvalue::OK) {
|
||||||
|
Loading…
Reference in New Issue
Block a user