Merge branch 'mueller_framework' into front_branch

This commit is contained in:
Robin Müller 2020-06-19 20:48:35 +02:00
commit 65c775b83c
43 changed files with 720 additions and 379 deletions

View File

@ -1,5 +1,5 @@
#ifndef ARRAYLIST_H_
#define ARRAYLIST_H_
#ifndef FRAMEWORK_CONTAINER_ARRAYLIST_H_
#define FRAMEWORK_CONTAINER_ARRAYLIST_H_
#include <framework/returnvalues/HasReturnvaluesIF.h>
#include <framework/serialize/SerializeAdapter.h>
@ -7,8 +7,9 @@
/**
* @brief A List that stores its values in an array.
* @details The backend is an array that can be allocated
* by the class itself or supplied via ctor.
* @details
* The underlying storage is an array that can be allocated by the class
* itself or supplied via ctor.
*
* @ingroup container
*/
@ -19,6 +20,53 @@ public:
static const uint8_t INTERFACE_ID = CLASS_ID::ARRAY_LIST;
static const ReturnValue_t FULL = MAKE_RETURN_CODE(0x01);
/**
* Copying is forbiden by declaring copy ctor and copy assignment deleted
* It is too ambigous in this case.
* (Allocate a new backend? Use the same? What to do in an modifying call?)
*/
ArrayList(const ArrayList& other) = delete;
const ArrayList& operator=(const ArrayList& other) = delete;
/**
* Number of Elements stored in this List
*/
count_t size;
/**
* This is the allocating constructor;
*
* It allocates an array of the specified size.
*
* @param maxSize
*/
ArrayList(count_t maxSize) :
size(0), maxSize_(maxSize), allocated(true) {
entries = new T[maxSize];
}
/**
* This is the non-allocating constructor
*
* It expects a pointer to an array of a certain size and initializes itself to it.
*
* @param storage the array to use as backend
* @param maxSize size of storage
* @param size size of data already present in storage
*/
ArrayList(T *storage, count_t maxSize, count_t size = 0) :
size(size), entries(storage), maxSize_(maxSize), allocated(false) {
}
/**
* Destructor, if the allocating constructor was used, it deletes the array.
*/
virtual ~ArrayList() {
if (allocated) {
delete[] entries;
}
}
/**
* An Iterator to go trough an ArrayList
*
@ -30,10 +78,7 @@ public:
/**
* Empty ctor, points to NULL
*/
Iterator() :
value(0) {
}
Iterator(): value(0) {}
/**
* Initializes the Iterator to point to an element
@ -92,47 +137,7 @@ public:
bool operator!=(const typename ArrayList<T, count_t>::Iterator& other) const {
return !(*this == other);
}
}
;
/**
* Number of Elements stored in this List
*/
count_t size;
/**
* This is the allocating constructor;
*
* It allocates an array of the specified size.
*
* @param maxSize
*/
ArrayList(count_t maxSize) :
size(0), maxSize_(maxSize), allocated(true) {
entries = new T[maxSize];
}
/**
* This is the non-allocating constructor
*
* It expects a pointer to an array of a certain size and initializes itself to it.
*
* @param storage the array to use as backend
* @param maxSize size of storage
* @param size size of data already present in storage
*/
ArrayList(T *storage, count_t maxSize, count_t size = 0) :
size(size), entries(storage), maxSize_(maxSize), allocated(false) {
}
/**
* Destructor, if the allocating constructor was used, it deletes the array.
*/
virtual ~ArrayList() {
if (allocated) {
delete[] entries;
}
}
};
/**
* Iterator pointing to the first stored elmement
@ -223,19 +228,6 @@ public:
return (maxSize_ - size);
}
private:
/**
* This is the copy constructor
*
* It is private, as copying is too ambigous in this case. (Allocate a new backend? Use the same?
* What to do in an modifying call?)
*
* @param other
*/
ArrayList(const ArrayList& other) :
size(other.size), entries(other.entries), maxSize_(other.maxSize_),
allocated(false) {}
protected:
/**
* pointer to the array in which the entries are stored

View File

@ -8,13 +8,11 @@ template<typename T, typename count_t = uint8_t>
class HybridIterator: public LinkedElement<T>::Iterator,
public ArrayList<T, count_t>::Iterator {
public:
HybridIterator() :
value(NULL), linked(NULL), end(NULL) {
}
HybridIterator() {}
HybridIterator(typename LinkedElement<T>::Iterator *iter) :
LinkedElement<T>::Iterator(*iter), value(
iter->value), linked(true), end(NULL) {
LinkedElement<T>::Iterator(*iter), value(iter->value),
linked(true) {
}
@ -66,11 +64,11 @@ public:
return tmp;
}
bool operator==(HybridIterator other) {
bool operator==(const HybridIterator& other) {
return value == other.value;
}
bool operator!=(HybridIterator other) {
bool operator!=(const HybridIterator& other) {
return !(*this == other);
}
@ -82,11 +80,11 @@ public:
return value;
}
T* value;
T* value = nullptr;
private:
bool linked;
T *end;
bool linked = false;
T *end = nullptr;
};
#endif /* HYBRIDITERATOR_H_ */

View File

@ -2,12 +2,14 @@
#define FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_
#include <framework/returnvalues/HasReturnvaluesIF.h>
#include <cstddef>
template<uint8_t N_READ_PTRS = 1>
class RingBufferBase {
public:
RingBufferBase(uint32_t startAddress, uint32_t size, bool overwriteOld) :
start(startAddress), write(startAddress), size(size), overwriteOld(overwriteOld) {
RingBufferBase(uint32_t startAddress, const size_t size, bool overwriteOld) :
start(startAddress), write(startAddress), size(size),
overwriteOld(overwriteOld) {
for (uint8_t count = 0; count < N_READ_PTRS; count++) {
read[count] = startAddress;
}
@ -83,7 +85,7 @@ protected:
const uint32_t start;
uint32_t write;
uint32_t read[N_READ_PTRS];
const uint32_t size;
const size_t size;
const bool overwriteOld;
void incrementWrite(uint32_t amount) {
write = ((write + amount - start) % size) + start;

View File

@ -1,11 +1,16 @@
#include <framework/container/SimpleRingBuffer.h>
#include <string.h>
#include <cstring>
SimpleRingBuffer::SimpleRingBuffer(uint32_t size, bool overwriteOld) :
RingBufferBase<>(0, size, overwriteOld), buffer(NULL) {
SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld) :
RingBufferBase<>(0, size, overwriteOld) {
buffer = new uint8_t[size];
}
SimpleRingBuffer::SimpleRingBuffer(uint8_t *buffer, const size_t size,
bool overwriteOld):
RingBufferBase<>(0, size, overwriteOld), buffer(buffer) {}
SimpleRingBuffer::~SimpleRingBuffer() {
delete[] buffer;
}
@ -66,3 +71,4 @@ ReturnValue_t SimpleRingBuffer::deleteData(uint32_t amount,
incrementRead(amount, READ_PTR);
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -5,13 +5,29 @@
#include <stddef.h>
/**
* @brief Circular buffer implementation, useful for buffering into data streams.
* @details Note that the deleteData() has to be called to increment the read pointer
* @brief Circular buffer implementation, useful for buffering
* into data streams.
* @details
* Note that the deleteData() has to be called to increment the read pointer.
* This class allocated dynamically, so
* @ingroup containers
*/
class SimpleRingBuffer: public RingBufferBase<> {
public:
SimpleRingBuffer(uint32_t size, bool overwriteOld);
/**
* This constructor allocates a new internal buffer with the supplied size.
* @param size
* @param overwriteOld
*/
SimpleRingBuffer(const size_t size, bool overwriteOld);
/**
* This constructor takes an external buffer with the specified size.
* @param buffer
* @param size
* @param overwriteOld
*/
SimpleRingBuffer(uint8_t* buffer, const size_t size, bool overwriteOld);
virtual ~SimpleRingBuffer();
/**
@ -30,7 +46,8 @@ public:
* @param trueAmount
* @return
*/
ReturnValue_t readData(uint8_t* data, uint32_t amount, bool readRemaining = false, uint32_t* trueAmount = NULL);
ReturnValue_t readData(uint8_t* data, uint32_t amount,
bool readRemaining = false, uint32_t* trueAmount = nullptr);
/**
* Delete data starting by incrementing read pointer
@ -39,11 +56,12 @@ public:
* @param trueAmount
* @return
*/
ReturnValue_t deleteData(uint32_t amount, bool deleteRemaining = false, uint32_t* trueAmount = NULL);
ReturnValue_t deleteData(uint32_t amount, bool deleteRemaining = false,
uint32_t* trueAmount = nullptr);
private:
// static const uint8_t TEMP_READ_PTR = 1;
static const uint8_t READ_PTR = 0;
uint8_t* buffer;
uint8_t* buffer = nullptr;
};
#endif /* FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ */

View File

@ -1,8 +1,9 @@
#ifndef SINGLYLINKEDLIST_H_
#define SINGLYLINKEDLIST_H_
#ifndef FRAMEWORK_CONTAINER_SINGLYLINKEDLIST_H_
#define FRAMEWORK_CONTAINER_SINGLYLINKEDLIST_H_
#include <cstddef>
#include <cstdint>
#include <stddef.h>
#include <stdint.h>
/**
* @brief Linked list data structure,
* each entry has a pointer to the next entry (singly)
@ -14,11 +15,8 @@ public:
T *value;
class Iterator {
public:
LinkedElement<T> *value;
Iterator() :
value(NULL) {
}
LinkedElement<T> *value = nullptr;
Iterator() {}
Iterator(LinkedElement<T> *element) :
value(element) {
@ -47,12 +45,11 @@ public:
}
};
LinkedElement(T* setElement, LinkedElement<T>* setNext = NULL) : value(setElement),
next(setNext) {
}
virtual ~LinkedElement(){
LinkedElement(T* setElement, LinkedElement<T>* setNext = nullptr):
value(setElement), next(setNext) {}
virtual ~LinkedElement(){}
}
virtual LinkedElement* getNext() const {
return next;
}
@ -61,7 +58,7 @@ public:
this->next = next;
}
void setEnd() {
virtual void setEnd() {
this->next = nullptr;
}
@ -69,7 +66,7 @@ public:
return this;
}
LinkedElement* end() {
return NULL;
return nullptr;
}
private:
LinkedElement *next;
@ -78,21 +75,21 @@ private:
template<typename T>
class SinglyLinkedList {
public:
SinglyLinkedList() :
start(NULL) {
}
using ElementIterator = typename LinkedElement<T>::Iterator;
SinglyLinkedList() {}
SinglyLinkedList(ElementIterator start) :
start(start.value) {}
SinglyLinkedList(typename LinkedElement<T>::Iterator start) :
start(start.value) {
}
SinglyLinkedList(LinkedElement<T>* startElement) :
start(startElement) {
start(startElement) {}
ElementIterator begin() const {
return ElementIterator::Iterator(start);
}
typename LinkedElement<T>::Iterator begin() const {
return LinkedElement<T>::Iterator::Iterator(start);
}
typename LinkedElement<T>::Iterator::Iterator end() const {
return LinkedElement<T>::Iterator::Iterator();
typename ElementIterator::Iterator end() const {
return ElementIterator::Iterator();
}
uint32_t getSize() const {
@ -107,8 +104,15 @@ public:
void setStart(LinkedElement<T>* setStart) {
start = setStart;
}
void setEnd(LinkedElement<T>* setEnd) {
setEnd->setEnd();
}
// SHOULDDO: Insertion operation ?
protected:
LinkedElement<T> *start;
LinkedElement<T> *start = nullptr;
};
#endif /* SINGLYLINKEDLIST_H_ */

View File

@ -53,6 +53,10 @@ ReturnValue_t DataSetBase::read(uint32_t lockTimeout) {
return result;
}
uint16_t DataSetBase::getFillCount() const {
return fillCount;
}
ReturnValue_t DataSetBase::readVariable(uint16_t count) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
// These checks are often performed by the respective

View File

@ -101,8 +101,10 @@ public:
*/
virtual ReturnValue_t unlockDataPool() override;
virtual uint16_t getFillCount() const;
/* SerializeIF implementations */
ReturnValue_t serialize(uint8_t** buffer, size_t* size,
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
const size_t maxSize, bool bigEndian) const override;
virtual size_t getSerializedSize() const override;
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,

View File

@ -43,6 +43,7 @@ public:
*/
virtual ReturnValue_t registerVariable(PoolVariableIF* variable) = 0;
virtual uint16_t getFillCount() const = 0;
private:
/**
* @brief Most underlying data structures will have a pool like structure

View File

@ -1,16 +1,17 @@
#include <framework/datapoollocal/LocalDataPoolManager.h>
#include <framework/datapoollocal/LocalDataSet.h>
#include <framework/returnvalues/HasReturnvaluesIF.h>
#include <framework/objectmanager/frameworkObjects.h>
#include <framework/ipc/MutexFactory.h>
#include <framework/ipc/MutexHelper.h>
#include <framework/ipc/QueueFactory.h>
#include <array>
LocalDataPoolManager::LocalDataPoolManager(OwnsLocalDataPoolIF* owner) {
LocalDataPoolManager::LocalDataPoolManager(OwnsLocalDataPoolIF* owner,
uint32_t replyQueueDepth, bool appendValidityBuffer):
appendValidityBuffer(appendValidityBuffer) {
if(owner == nullptr) {
sif::error << "HkManager: Invalid supplied owner!" << std::endl;
std::exit(0);
return;
}
this->owner = owner;
mutex = MutexFactory::instance()->createMutex();
@ -23,6 +24,8 @@ LocalDataPoolManager::LocalDataPoolManager(OwnsLocalDataPoolIF* owner) {
sif::error << "LocalDataPoolManager::LocalDataPoolManager: "
"Could not set IPC store." << std::endl;
}
hkQueue = QueueFactory::instance()->createMessageQueue(replyQueueDepth,
HousekeepingMessage::HK_MESSAGE_SIZE);
}
LocalDataPoolManager::~LocalDataPoolManager() {}
@ -30,19 +33,35 @@ LocalDataPoolManager::~LocalDataPoolManager() {}
ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() {
if(not mapInitialized) {
ReturnValue_t result =
owner->initializeHousekeepingPoolEntries(localDpMap);
owner->initializePoolEntries(localDpMap);
if(result == HasReturnvaluesIF::RETURN_OK) {
mapInitialized = true;
}
return result;
}
sif::warning << "HousekeepingManager: The map" << std::endl;
sif::warning << "HousekeepingManager: The map should only be initialized "
"once!" << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(
HousekeepingMessage& message) {
return HasReturnvaluesIF::RETURN_FAILED;
Command_t command = message.getCommand();
switch(command) {
// I think those are the only commands which can be handled here..
case(HousekeepingMessage::ADD_HK_REPORT_STRUCT):
case(HousekeepingMessage::ADD_DIAGNOSTICS_REPORT_STRUCT):
// We should use OwnsLocalPoolDataIF to specify those functions..
return HasReturnvaluesIF::RETURN_OK;
case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES):
case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES):
return generateSetStructurePacket(message.getSid());
case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT):
case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT):
return generateHousekeepingPacket(message.getSid());
default:
return CommandMessageIF::UNKNOWN_COMMAND;
}
}
ReturnValue_t LocalDataPoolManager::printPoolEntry(
@ -51,7 +70,7 @@ ReturnValue_t LocalDataPoolManager::printPoolEntry(
if (poolIter == localDpMap.end()) {
sif::debug << "HousekeepingManager::fechPoolEntry:"
" Pool entry not found." << std::endl;
return OwnsLocalDataPoolIF::POOL_ENTRY_NOT_FOUND;
return POOL_ENTRY_NOT_FOUND;
}
poolIter->second->print();
return HasReturnvaluesIF::RETURN_OK;
@ -61,6 +80,15 @@ MutexIF* LocalDataPoolManager::getMutexHandle() {
return mutex;
}
void LocalDataPoolManager::setHkPacketDestination(
MessageQueueId_t destinationQueueId) {
this->currentHkPacketDestination = destinationQueueId;
}
const OwnsLocalDataPoolIF* LocalDataPoolManager::getOwner() const {
return owner;
}
ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid) {
LocalDataSet* dataSetToSerialize = dynamic_cast<LocalDataSet*>(
owner->getDataSetHandle(sid));
@ -70,28 +98,84 @@ ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid) {
return HasReturnvaluesIF::RETURN_FAILED;
}
store_address_t storeId;
size_t hkSize = dataSetToSerialize->getSerializedSize();
uint8_t* storePtr = nullptr;
ReturnValue_t result = ipcStore->getFreeElement(&storeId, hkSize,&storePtr);
ReturnValue_t result = serializeHkPacketIntoStore(&storeId,
dataSetToSerialize);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
// and now we set a HK message and send it the HK packet destination.
MessageQueueMessage message;
HousekeepingMessage hkMessage(&message);
hkMessage.setHkReportMessage(sid, storeId);
if(hkQueue == nullptr) {
return QUEUE_NOT_SET;
}
if(currentHkPacketDestination != MessageQueueIF::NO_QUEUE) {
result = hkQueue->sendMessage(currentHkPacketDestination, &hkMessage);
}
else {
result = hkQueue->sendToDefault(&hkMessage);
}
return result;
}
ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid) {
LocalDataSet* dataSet = dynamic_cast<LocalDataSet*>(
owner->getDataSetHandle(sid));
if(dataSet == nullptr) {
sif::warning << "HousekeepingManager::generateHousekeepingPacket:"
" Set ID not found" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
size_t expectedSize = dataSet->getFillCount() * sizeof(lp_id_t);
uint8_t* storePtr = nullptr;
store_address_t storeId;
ReturnValue_t result = ipcStore->getFreeElement(&storeId,
expectedSize,&storePtr);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "HousekeepingManager::generateHousekeepingPacket: "
"Could not get free element from IPC store." << std::endl;
return result;
}
size_t size = 0;
dataSetToSerialize->serialize(&storePtr, &size, hkSize, false);
// and now we have to set a HK message and send it the queue.
return HasReturnvaluesIF::RETURN_OK;
result = dataSet->serializeLocalPoolIds(&storePtr, &size,
expectedSize, false);
if(expectedSize != size) {
sif::error << "HousekeepingManager::generateSetStructurePacket: "
"Expected size is not equal to serialized size" << std::endl;
}
return result;
}
void LocalDataPoolManager::setHkPacketQueue(MessageQueueIF *msgQueue) {
this->hkPacketQueue = msgQueue;
ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore(
store_address_t *storeId, LocalDataSet* dataSet) {
size_t hkSize = dataSet->getSerializedSize();
uint8_t* storePtr = nullptr;
ReturnValue_t result = ipcStore->getFreeElement(storeId, hkSize,&storePtr);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "HousekeepingManager::generateHousekeepingPacket: "
"Could not get free element from IPC store." << std::endl;
return result;
}
size_t size = 0;
if(appendValidityBuffer) {
result = dataSet->serializeWithValidityBuffer(&storePtr,
&size, hkSize, false);
}
else {
result = dataSet->serialize(&storePtr, &size, hkSize, false);
}
void LocalDataPoolManager::setHkReplyQueue(MessageQueueIF *replyQueue) {
this->hkReplyQueue = replyQueue;
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "HousekeepingManager::serializeHkPacketIntoStore: "
"Serialization proccess failed!" << std::endl;
}
return result;
}
const OwnsLocalDataPoolIF* LocalDataPoolManager::getOwner() const {
return owner;
}

View File

@ -13,6 +13,8 @@
#include <map>
class LocalDataSet;
/**
* @brief This class is the managing instance for local data pool.
* @details
@ -37,8 +39,16 @@ class LocalDataPoolManager {
friend class LocalPoolVector;
friend class LocalDataSet;
public:
static constexpr uint8_t INTERFACE_ID = CLASS_ID::HOUSEKEEPING_MANAGER;
LocalDataPoolManager(OwnsLocalDataPoolIF* owner);
static constexpr ReturnValue_t POOL_ENTRY_NOT_FOUND = MAKE_RETURN_CODE(0x0);
static constexpr ReturnValue_t POOL_ENTRY_TYPE_CONFLICT = MAKE_RETURN_CODE(0x1);
static constexpr ReturnValue_t QUEUE_NOT_SET = MAKE_RETURN_CODE(0x2);
//static constexpr ReturnValue_t SET_NOT_FOUND = MAKE_RETURN_CODE(0x3);
LocalDataPoolManager(OwnsLocalDataPoolIF* owner,
uint32_t replyQueueDepth = 20, bool appendValidityBuffer = true);
virtual~ LocalDataPoolManager();
/* Copying forbidden */
@ -46,6 +56,8 @@ public:
LocalDataPoolManager operator=(const LocalDataPoolManager&) = delete;
ReturnValue_t generateHousekeepingPacket(sid_t sid);
ReturnValue_t generateSetStructurePacket(sid_t sid);
ReturnValue_t handleHousekeepingMessage(HousekeepingMessage& message);
/**
@ -57,10 +69,7 @@ public:
ReturnValue_t initializeHousekeepingPoolEntriesOnce();
//! Set the queue for HK packets, which are sent unrequested.
void setHkPacketQueue(MessageQueueIF* msgQueue);
//! Set the queue for replies. This can be set manually or by the owner
//! class if the manager if message are relayed by it.
void setHkReplyQueue(MessageQueueIF* replyQueue);
void setHkPacketDestination(MessageQueueId_t destinationQueueId);
const OwnsLocalDataPoolIF* getOwner() const;
@ -70,6 +79,10 @@ private:
//! This is the map holding the actual data. Should only be initialized
//! once !
bool mapInitialized = false;
//! This specifies whether a validity buffer is appended at the end
//! of generated housekeeping packets.
bool appendValidityBuffer = true;
LocalDataPool localDpMap;
//! Every housekeeping data manager has a mutex to protect access
@ -79,13 +92,14 @@ private:
//! The class which actually owns the manager (and its datapool).
OwnsLocalDataPoolIF* owner = nullptr;
//! Used for replies.
//! (maybe we dont need this, the sender can be retrieved from command
//! message..)
MessageQueueIF* hkReplyQueue = nullptr;
//! Used for HK packets, which are generated without requests.
//! Maybe this will just be the TM funnel.
MessageQueueIF* hkPacketQueue = nullptr;
//! Queue used for communication, for example commands.
//! Is also used to send messages.
MessageQueueIF* hkQueue = nullptr;
//! HK replies will always be a reply to the commander, but HK packet
//! can be sent to another destination by specifying this message queue
//! ID, for example to a dedicated housekeeping service implementation.
MessageQueueId_t currentHkPacketDestination = MessageQueueIF::NO_QUEUE;
//! Global IPC store is used to store all packets.
StorageManagerIF* ipcStore = nullptr;
@ -113,6 +127,8 @@ private:
PoolEntry<T> **poolEntry);
void setMinimalSamplingFrequency(float frequencySeconds);
ReturnValue_t serializeHkPacketIntoStore(store_address_t* storeId,
LocalDataSet* dataSet);
};
@ -123,14 +139,14 @@ ReturnValue_t LocalDataPoolManager::fetchPoolEntry(lp_id_t localPoolId,
if (poolIter == localDpMap.end()) {
sif::debug << "HousekeepingManager::fechPoolEntry:"
" Pool entry not found." << std::endl;
return OwnsLocalDataPoolIF::POOL_ENTRY_NOT_FOUND;
return POOL_ENTRY_NOT_FOUND;
}
*poolEntry = dynamic_cast< PoolEntry<T>* >(poolIter->second);
if(*poolEntry == nullptr) {
sif::debug << "HousekeepingManager::fetchPoolEntry:"
" Pool entry not found." << std::endl;
return OwnsLocalDataPoolIF::POOL_ENTRY_TYPE_CONFLICT;
return POOL_ENTRY_TYPE_CONFLICT;
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,20 +1,24 @@
#include <framework/datapoollocal/LocalDataPoolManager.h>
#include <framework/datapoollocal/LocalDataSet.h>
#include <framework/serialize/SerializeAdapter.h>
#include <cmath>
#include <cstring>
LocalDataSet::LocalDataSet(OwnsLocalDataPoolIF *hkOwner): DataSetBase() {
if(hkOwner != nullptr) {
if(hkOwner == nullptr) {
sif::error << "LocalDataSet::LocalDataSet: Owner can't be nullptr!"
<< std::endl;
}
hkManager = hkOwner->getHkManagerHandle();
}
else {
// config error, error output here.
}
}
LocalDataSet::LocalDataSet(object_id_t ownerId): DataSetBase() {
OwnsLocalDataPoolIF* hkOwner = objectManager->get<OwnsLocalDataPoolIF>(
ownerId);
if(hkOwner == nullptr) {
// config error, error output here.
sif::error << "LocalDataSet::LocalDataSet: Owner can't be nullptr!"
<< std::endl;
}
hkManager = hkOwner->getHkManagerHandle();
}
@ -27,9 +31,65 @@ ReturnValue_t LocalDataSet::lockDataPool(uint32_t timeoutMs) {
return mutex->lockMutex(timeoutMs);
}
ReturnValue_t LocalDataSet::serializeWithValidityBuffer(uint8_t **buffer,
size_t *size, const size_t maxSize, bool bigEndian) const {
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
uint8_t validityMaskSize = std::ceil(static_cast<float>(fillCount)/8.0);
uint8_t validityMask[validityMaskSize];
uint8_t validBufferIndex = 0;
uint8_t validBufferIndexBit = 0;
for (uint16_t count = 0; count < fillCount; count++) {
if(registeredVariables[count]->isValid()) {
// set validity buffer here.
this->bitSetter(validityMask + validBufferIndex,
validBufferIndexBit, true);
if(validBufferIndexBit == 7) {
validBufferIndex ++;
validBufferIndexBit = 0;
}
else {
validBufferIndexBit ++;
}
}
result = registeredVariables[count]->serialize(buffer, size, maxSize,
bigEndian);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
}
// copy validity buffer to end
std::memcpy(*buffer, validityMask, validityMaskSize);
*size += validityMaskSize;
return result;
}
ReturnValue_t LocalDataSet::unlockDataPool() {
MutexIF* mutex = hkManager->getMutexHandle();
return mutex->unlockMutex();
}
ReturnValue_t LocalDataSet::serializeLocalPoolIds(uint8_t** buffer,
size_t* size, const size_t maxSize, bool bigEndian) const {
for (uint16_t count = 0; count < fillCount; count++) {
lp_id_t currentPoolId = registeredVariables[count]->getDataPoolId();
auto result = AutoSerializeAdapter::serialize(&currentPoolId, buffer,
size, maxSize, bigEndian);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "LocalDataSet::serializeLocalPoolIds: Serialization"
" error!" << std::endl;
return result;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
void LocalDataSet::bitSetter(uint8_t* byte, uint8_t position,
bool value) const {
if(position > 7) {
sif::debug << "Pool Raw Access: Bit setting invalid position" << std::endl;
return;
}
uint8_t shiftNumber = position + (7 - 2 * position);
*byte |= 1UL << shiftNumber;
}

View File

@ -55,6 +55,23 @@ public:
*/
~LocalDataSet();
/**
* Special version of the serilization function which appends a
* validity buffer at the end. Each bit of this validity buffer
* denotes whether the container data set entries are valid from left
* to right, MSB first.
* @param buffer
* @param size
* @param maxSize
* @param bigEndian
* @param withValidityBuffer
* @return
*/
ReturnValue_t serializeWithValidityBuffer(uint8_t** buffer,
size_t* size, const size_t maxSize, bool bigEndian) const;
ReturnValue_t serializeLocalPoolIds(uint8_t** buffer,
size_t* size, const size_t maxSize, bool bigEndian) const;
protected:
private:
/**
@ -79,6 +96,16 @@ private:
ReturnValue_t unlockDataPool() override;
LocalDataPoolManager* hkManager;
/**
* Sets the bit at the bit-position of a byte provided by its address
* to the specified value (zero or one).
* @param byte Pointer to byte to bitset.
* @param position MSB first, 0 to 7 possible.
* @param value Value to set.
* @return
*/
void bitSetter(uint8_t* byte, uint8_t position, bool value) const;
};
#endif /* FRAMEWORK_DATAPOOLLOCAL_LOCALDATASET_H_ */

View File

@ -40,16 +40,38 @@ class OwnsLocalDataPoolIF {
public:
virtual~ OwnsLocalDataPoolIF() {};
static constexpr uint8_t INTERFACE_ID = CLASS_ID::HOUSEKEEPING;
static constexpr ReturnValue_t POOL_ENTRY_NOT_FOUND = MAKE_RETURN_CODE(0XA0);
static constexpr ReturnValue_t POOL_ENTRY_TYPE_CONFLICT = MAKE_RETURN_CODE(0xA1);
static constexpr uint8_t INTERFACE_ID = CLASS_ID::LOCAL_POOL_OWNER_IF;
/** Command queue for housekeeping messages. */
virtual MessageQueueId_t getCommandQueue() const = 0;
virtual ReturnValue_t initializeHousekeepingPoolEntries(
/** Is used by pool owner to initialize the pool map once */
virtual ReturnValue_t initializePoolEntries(
LocalDataPool& localDataPoolMap) = 0;
//virtual float setMinimalHkSamplingFrequency() = 0;
/** Can be used to get a handle to the local data pool manager. */
virtual LocalDataPoolManager* getHkManagerHandle() = 0;
/**
* This function is used by the pool manager to get a valid dataset
* from a SID
* @param sid Corresponding structure ID
* @return
*/
virtual DataSetIF* getDataSetHandle(sid_t sid) = 0;
/* These function can be implemented by pool owner, as they are required
* by the housekeeping message interface */
virtual ReturnValue_t addDataSet(sid_t sid) {
return HasReturnvaluesIF::RETURN_FAILED;
};
virtual ReturnValue_t removeDataSet(sid_t sid) {
return HasReturnvaluesIF::RETURN_FAILED;
};
virtual ReturnValue_t changeCollectionInterval(sid_t sid,
dur_seconds_t newInterval) {
return HasReturnvaluesIF::RETURN_FAILED;
};
};
#endif /* FRAMEWORK_DATAPOOL_HASHKPOOLPARAMETERSIF_H_ */

View File

@ -72,7 +72,7 @@ public:
* by implementing and calling related drivers or wrapper functions.
* @param cookie
* @param data
* @param len
* @param len If this is 0, nothing shall be sent.
* @return
* - @c RETURN_OK for successfull send
* - Everything else triggers failure event with returnvalue as parameter 1

View File

@ -1360,7 +1360,7 @@ void DeviceHandlerBase::debugInterface(uint8_t positionTracker,
void DeviceHandlerBase::performOperationHook() {
}
ReturnValue_t DeviceHandlerBase::initializeHousekeepingPoolEntries(
ReturnValue_t DeviceHandlerBase::initializePoolEntries(
LocalDataPool &localDataPoolMap) {
return RETURN_OK;
}
@ -1369,6 +1369,19 @@ LocalDataPoolManager* DeviceHandlerBase::getHkManagerHandle() {
return &hkManager;
}
ReturnValue_t DeviceHandlerBase::addDataSet(sid_t sid) {
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t DeviceHandlerBase::removeDataSet(sid_t sid) {
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t DeviceHandlerBase::changeCollectionInterval(sid_t sid,
dur_seconds_t newInterval) {
return HasReturnvaluesIF::RETURN_OK;
}
DataSetIF* DeviceHandlerBase::getDataSetHandle(sid_t sid) {
auto iter = deviceReplyMap.find(sid.ownerSetId);
if(iter != deviceReplyMap.end()) {

View File

@ -477,12 +477,17 @@ protected:
* @param localDataPoolMap
* @return
*/
virtual ReturnValue_t initializeHousekeepingPoolEntries(
virtual ReturnValue_t initializePoolEntries(
LocalDataPool& localDataPoolMap) override;
/** Get the HK manager object handle */
virtual LocalDataPoolManager* getHkManagerHandle() override;
virtual ReturnValue_t addDataSet(sid_t sid) override;
virtual ReturnValue_t removeDataSet(sid_t sid) override;
virtual ReturnValue_t changeCollectionInterval(sid_t sid,
dur_seconds_t newInterval) override;
/**
* @brief Hook function for child handlers which is called once per
* performOperation(). Default implementation is empty.
@ -703,7 +708,9 @@ protected:
bool switchOffWasReported; //!< Indicates if SWITCH_WENT_OFF was already thrown.
PeriodicTaskIF* executingTask = nullptr;//!< Pointer to the task which executes this component, is invalid before setTaskIF was called.
//! Pointer to the task which executes this component, is invalid
//! before setTaskIF was called.
PeriodicTaskIF* executingTask = nullptr;
static object_id_t powerSwitcherId; //!< Object which switches power on and off.

View File

@ -8,13 +8,16 @@
const uint16_t EventManager::POOL_SIZES[N_POOLS] = {
sizeof(EventMatchTree::Node), sizeof(EventIdRangeMatcher),
sizeof(ReporterRangeMatcher) };
//If one checks registerListener calls, there are around 40 (to max 50) objects registering for certain events.
//Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher. So a good guess is 75 to a max of 100 pools required for each, which fits well.
// If one checks registerListener calls, there are around 40 (to max 50)
// objects registering for certain events.
// Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher.
// So a good guess is 75 to a max of 100 pools required for each, which fits well.
// SHOULDDO: Shouldn't this be in the config folder and passed via ctor?
const uint16_t EventManager::N_ELEMENTS[N_POOLS] = { 240, 120, 120 };
EventManager::EventManager(object_id_t setObjectId) :
SystemObject(setObjectId), eventReportQueue(NULL), mutex(NULL), factoryBackend(
0, POOL_SIZES, N_ELEMENTS, false, true) {
SystemObject(setObjectId),
factoryBackend(0, POOL_SIZES, N_ELEMENTS, false, true) {
mutex = MutexFactory::instance()->createMutex();
eventReportQueue = QueueFactory::instance()->createMessageQueue(
MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE);
@ -130,20 +133,23 @@ void EventManager::printEvent(EventMessage* message) {
break;
default:
string = translateObject(message->getReporter());
sif::error << "EVENT: ";
sif::debug << "EventManager: ";
if (string != 0) {
sif::error << string;
} else {
sif::error << "0x" << std::hex << message->getReporter() << std::dec;
sif::debug << string;
}
sif::error << " reported " << translateEvents(message->getEvent()) << " ("
<< std::dec << message->getEventId() << ") " << std::endl;
sif::error << std::hex << "P1 Hex: 0x" << message->getParameter1() << ", P1 Dec: "
<< std::dec << message->getParameter1() << std::endl;
sif::error << std::hex << "P2 Hex: 0x" << message->getParameter2() << ", P2 Dec: "
<< std::dec << message->getParameter2() << std::endl;
else {
sif::debug << "0x" << std::hex << message->getReporter() << std::dec;
}
sif::debug << " reported " << translateEvents(message->getEvent())
<< " (" << std::dec << message->getEventId() << ") "
<< std::endl;
sif::debug << std::hex << "P1 Hex: 0x" << message->getParameter1()
<< ", P1 Dec: " << std::dec << message->getParameter1()
<< std::endl;
sif::debug << std::hex << "P2 Hex: 0x" << message->getParameter2()
<< ", P2 Dec: " << std::dec << message->getParameter2()
<< std::endl;
break;
}

View File

@ -36,11 +36,11 @@ public:
ReturnValue_t performOperation(uint8_t opCode);
protected:
MessageQueueIF* eventReportQueue;
MessageQueueIF* eventReportQueue = nullptr;
std::map<MessageQueueId_t, EventMatchTree> listenerList;
MutexIF* mutex;
MutexIF* mutex = nullptr;
static const uint8_t N_POOLS = 3;
LocalPool<N_POOLS> factoryBackend;

View File

@ -4,8 +4,8 @@
HousekeepingMessage::HousekeepingMessage(MessageQueueMessageIF* message):
CommandMessageBase(message) {
if(message->getMaximumMessageSize() < HK_MESSAGE_SIZE) {
sif::error << "CommandMessage::ComandMessage: Passed message buffer"
" can not hold minimum "<< HK_MESSAGE_SIZE
sif::error << "HousekeepingMessage::HousekeepingMessage: Passed "
"message buffer can not hold minimum " << HK_MESSAGE_SIZE
<< " bytes!" << std::endl;
return;
}

View File

@ -36,8 +36,8 @@ union sid_t {
class HousekeepingMessage : public CommandMessageBase {
public:
static constexpr size_t HK_MESSAGE_SIZE = sizeof(MessageQueueId_t)
+ sizeof(Command_t) + sizeof(sid_t) * sizeof(uint32_t);
static constexpr size_t HK_MESSAGE_SIZE = CommandMessageIF::HEADER_SIZE +
sizeof(sid_t) + sizeof(uint32_t);
/**
* The HK message is initialized with a pointer to a message which holds
@ -96,6 +96,7 @@ public:
void setParameter(uint32_t parameter);
uint32_t getParameter() const;
sid_t getSid() const;
void setHkReportMessage(sid_t sid, store_address_t storeId);
void setHkDiagnosticsMessage(sid_t sid, store_address_t storeId);
@ -106,7 +107,7 @@ public:
virtual size_t getMinimumMessageSize() const override;
virtual void clear() override;
private:
sid_t getSid() const;
void setSid(sid_t sid);
virtual uint8_t* getData() override;

View File

@ -12,7 +12,7 @@ CommandMessage::CommandMessage(MessageQueueMessageIF* receiverMessage):
if(receiverMessage->getMaximumMessageSize() <
getMinimumMessageSize()) {
sif::error << "CommandMessage::ComandMessage: Passed message buffer"
" can not hold minimum "<< MINIMUM_COMMAND_MESSAGE_SIZE
" can not hold minimum "<< getMinimumMessageSize()
<< " bytes!" << std::endl;
return;
}

View File

@ -1,6 +1,7 @@
#include <framework/serviceinterface/ServiceInterfaceStream.h>
#include "FixedTimeslotTask.h"
#include <framework/serviceinterface/ServiceInterfaceStream.h>
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE;
@ -18,16 +19,19 @@ FixedTimeslotTask::~FixedTimeslotTask() {
void FixedTimeslotTask::taskEntryPoint(void* argument) {
//The argument is re-interpreted as FixedTimeslotTask. The Task object is global, so it is found from any place.
// The argument is re-interpreted as FixedTimeslotTask. The Task object is
// global, so it is found from any place.
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
// Task should not start until explicitly requested
// in FreeRTOS, tasks start as soon as they are created if the scheduler is running
// but not if the scheduler is not running.
// to be able to accommodate both cases we check a member which is set in #startTask()
// if it is not set and we get here, the scheduler was started before #startTask() was called and we need to suspend
// if it is set, the scheduler was not running before #startTask() was called and we can continue
/* Task should not start until explicitly requested,
* but in FreeRTOS, tasks start as soon as they are created if the scheduler
* is running but not if the scheduler is not running.
* To be able to accommodate both cases we check a member which is set in
* #startTask(). If it is not set and we get here, the scheduler was started
* before #startTask() was called and we need to suspend if it is set,
* the scheduler was not running before #startTask() was called and we
* can continue */
if (!originalTask->started) {
if (not originalTask->started) {
vTaskSuspend(NULL);
}
@ -58,11 +62,6 @@ ReturnValue_t FixedTimeslotTask::startTask() {
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) {
if (objectManager->get<ExecutableObjectIF>(componentId) != nullptr) {
if(slotTimeMs == 0) {
// FreeRTOS throws a sanity error for zero values, so we set
// the time to one millisecond.
slotTimeMs = 1;
}
pst.addSlot(componentId, slotTimeMs, executionStep, this);
return HasReturnvaluesIF::RETURN_OK;
}
@ -81,7 +80,8 @@ ReturnValue_t FixedTimeslotTask::checkSequence() const {
}
void FixedTimeslotTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to find the start time for the first entry.
// A local iterator for the Polling Sequence Table is created to find the
// start time for the first entry.
SlotListIter slotListIter = pst.current;
//The start time for the first entry is read.
@ -96,21 +96,36 @@ void FixedTimeslotTask::taskFunctionality() {
xLastWakeTime = xTaskGetTickCount();
// wait for first entry's start time
if(interval > 0) {
vTaskDelayUntil(&xLastWakeTime, interval);
}
/* Enter the loop that defines the task behavior. */
for (;;) {
//The component for this slot is executed and the next one is chosen.
this->pst.executeAndAdvance();
if (pst.slotFollowsImmediately()) {
//Do nothing
} else {
if (not pst.slotFollowsImmediately()) {
/* If all operations are finished and the difference of the
* current time minus the last wake time is larger than the
* expected wait period, a deadline was missed. */
if(xTaskGetTickCount() - xLastWakeTime >=
pdMS_TO_TICKS(this->pst.getIntervalToPreviousSlotMs())) {
#ifdef DEBUG
sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) <<
" missed deadline!\n" << std::flush;
#endif
if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
// Continue immediately, no need to wait.
break;
}
// we need to wait before executing the current slot
//this gives us the time to wait:
intervalMs = this->pst.getIntervalToPreviousSlotMs();
interval = pdMS_TO_TICKS(intervalMs);
vTaskDelayUntil(&xLastWakeTime, interval);
//TODO deadline missed check
}
}
}
@ -119,3 +134,4 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
vTaskDelay(pdMS_TO_TICKS(ms));
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,12 +1,12 @@
#ifndef POLLINGTASK_H_
#define POLLINGTASK_H_
#ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_
#include <framework/devicehandlers/FixedSlotSequence.h>
#include <framework/tasks/FixedSlotSequence.h>
#include <framework/tasks/FixedTimeslotTaskIF.h>
#include <framework/tasks/Typedef.h>
#include <FreeRTOS.h>
#include "task.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
class FixedTimeslotTask: public FixedTimeslotTaskIF {
public:
@ -29,16 +29,18 @@ public:
/**
* @brief The destructor of the class.
*
* @details The destructor frees all heap memory that was allocated on thread initialization for the PST and
* the device handlers. This is done by calling the PST's destructor.
* @details
* The destructor frees all heap memory that was allocated on thread
* initialization for the PST and the device handlers. This is done by
* calling the PST's destructor.
*/
virtual ~FixedTimeslotTask(void);
ReturnValue_t startTask(void);
/**
* This static function can be used as #deadlineMissedFunc.
* It counts missedDeadlines and prints the number of missed deadlines every 10th time.
* It counts missedDeadlines and prints the number of missed deadlines
* every 10th time.
*/
static void missedDeadlineCounter();
/**
@ -47,13 +49,13 @@ public:
static uint32_t deadlineMissedCount;
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep);
int8_t executionStep) override;
uint32_t getPeriodMs() const;
uint32_t getPeriodMs() const override;
ReturnValue_t checkSequence() const;
ReturnValue_t checkSequence() const override;
ReturnValue_t sleepFor(uint32_t ms);
ReturnValue_t sleepFor(uint32_t ms) override;
protected:
bool started;
@ -62,30 +64,29 @@ protected:
FixedSlotSequence pst;
/**
* @brief This attribute holds a function pointer that is executed when a deadline was missed.
*
* @details Another function may be announced to determine the actions to perform when a deadline was missed.
* Currently, only one function for missing any deadline is allowed.
* If not used, it shall be declared NULL.
* @brief This attribute holds a function pointer that is executed when
* a deadline was missed.
* @details
* Another function may be announced to determine the actions to perform
* when a deadline was missed. Currently, only one function for missing
* any deadline is allowed. If not used, it shall be declared NULL.
*/
void (*deadlineMissedFunc)(void);
/**
* @brief This is the entry point in a new polling thread.
*
* @details This method, that is the generalOSAL::checkAndRestartPeriod( this->periodId, interval ); entry point in the new thread, is here set to generate
* and link the Polling Sequence Table to the thread object and start taskFunctionality()
* on success. If operation of the task is ended for some reason,
* the destructor is called to free allocated memory.
* @brief This is the entry point for a new task.
* @details
* This method starts the task by calling taskFunctionality(), as soon as
* all requirements (task scheduler has started and startTask()
* has been called) are met.
*/
static void taskEntryPoint(void* argument);
/**
* @brief This function holds the main functionality of the thread.
*
*
* @details Holding the main functionality of the task, this method is most important.
* It links the functionalities provided by FixedSlotSequence with the OS's System Calls
* to keep the timing of the periods.
* @details
* Core function holding the main functionality of the task
* It links the functionalities provided by FixedSlotSequence with the
* OS's System Calls to keep the timing of the periods.
*/
void taskFunctionality(void);
};

View File

@ -12,8 +12,8 @@ PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
BaseType_t status = xTaskCreate(taskEntryPoint, name,
setStack, this, setPriority, &handle);
if(status != pdPASS){
sif::debug << "PeriodicTask Insufficient heap memory remaining. Status: "
<< status << std::endl;
sif::debug << "PeriodicTask Insufficient heap memory remaining. "
"Status: " << status << std::endl;
}
}
@ -23,14 +23,17 @@ PeriodicTask::~PeriodicTask(void) {
}
void PeriodicTask::taskEntryPoint(void* argument) {
//The argument is re-interpreted as PeriodicTask. The Task object is global, so it is found from any place.
// The argument is re-interpreted as PeriodicTask. The Task object is
// global, so it is found from any place.
PeriodicTask *originalTask(reinterpret_cast<PeriodicTask*>(argument));
// Task should not start until explicitly requested
// in FreeRTOS, tasks start as soon as they are created if the scheduler is running
// but not if the scheduler is not running.
// to be able to accommodate both cases we check a member which is set in #startTask()
// if it is not set and we get here, the scheduler was started before #startTask() was called and we need to suspend
// if it is set, the scheduler was not running before #startTask() was called and we can continue
/* Task should not start until explicitly requested,
* but in FreeRTOS, tasks start as soon as they are created if the scheduler
* is running but not if the scheduler is not running.
* To be able to accommodate both cases we check a member which is set in
* #startTask(). If it is not set and we get here, the scheduler was started
* before #startTask() was called and we need to suspend if it is set,
* the scheduler was not running before #startTask() was called and we
* can continue */
if (not originalTask->started) {
vTaskSuspend(NULL);
@ -61,38 +64,45 @@ void PeriodicTask::taskFunctionality() {
TickType_t xLastWakeTime;
const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.);
/* The xLastWakeTime variable needs to be initialized with the current tick
count. Note that this is the only time the variable is written to explicitly.
After this assignment, xLastWakeTime is updated automatically internally within
vTaskDelayUntil(). */
count. Note that this is the only time the variable is written to
explicitly. After this assignment, xLastWakeTime is updated automatically
internally within vTaskDelayUntil(). */
xLastWakeTime = xTaskGetTickCount();
/* Enter the loop that defines the task behavior. */
for (;;) {
for (ObjectList::iterator it = objectList.begin();
it != objectList.end(); ++it) {
(*it)->performOperation();
for (auto const& object: objectList) {
object->performOperation();
}
/* If all operations are finished and the difference of the
* current time minus the last wake time is larger than the
* wait period, a deadline was missed. */
if(xTaskGetTickCount() - xLastWakeTime >= xPeriod) {
#ifdef DEBUG
sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) <<
" missed deadline!\n" << std::flush;
#endif
if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}
vTaskDelayUntil(&xLastWakeTime, xPeriod);
}
}
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ReturnValue_t PeriodicTask::addComponent(object_id_t object, bool setTaskIF) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object);
if (newObject == NULL) {
if (newObject == nullptr) {
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
"it implement ExecutableObjectIF" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
if(setTaskIF) {
newObject->setTaskIF(this);
}
objectList.push_back(newObject);
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -5,10 +5,8 @@
#include <framework/tasks/PeriodicTaskIF.h>
#include <framework/tasks/Typedef.h>
extern "C" {
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
}
#include <vector>
@ -22,7 +20,9 @@ class ExecutableObjectIF;
class PeriodicTask: public PeriodicTaskIF {
public:
/**
* @brief Standard constructor of the class.
* Keep in Mind that you need to call before this vTaskStartScheduler()!
* A lot of task parameters are set in "FreeRTOSConfig.h".
* TODO: why does this need to be called before vTaskStartScheduler?
* @details
* The class is initialized without allocated objects.
* These need to be added with #addComponent.
@ -38,8 +38,9 @@ public:
* The function pointer to the deadline missed function that shall
* be assigned.
*/
PeriodicTask(const char *name, TaskPriority setPriority, TaskStackSize setStack,
TaskPeriod setPeriod,void (*setDeadlineMissedFunc)());
PeriodicTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)());
/**
* @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty.
@ -53,55 +54,65 @@ public:
* The address of the task object is passed as an argument
* to the system call.
*/
ReturnValue_t startTask(void);
ReturnValue_t startTask() override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object Id of the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
* @return
* -@c RETURN_OK on success
* -@c RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(object_id_t object);
ReturnValue_t addComponent(object_id_t object,
bool setTaskIF = true) override;
uint32_t getPeriodMs() const;
uint32_t getPeriodMs() const override;
ReturnValue_t sleepFor(uint32_t ms);
ReturnValue_t sleepFor(uint32_t ms) override;
protected:
bool started;
TaskHandle_t handle;
typedef std::vector<ExecutableObjectIF*> ObjectList; //!< Typedef for the List of objects.
//! Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList;
/**
* @brief This attribute holds a list of objects to be executed.
*/
ObjectList objectList;
/**
* @brief The period of the task.
* @details The period determines the frequency of the task's execution. It is expressed in clock ticks.
* @details
* The period determines the frequency of the task's execution.
* It is expressed in clock ticks.
*/
TaskPeriod period;
/**
* @brief The pointer to the deadline-missed function.
* @details This pointer stores the function that is executed if the task's deadline is missed.
* So, each may react individually on a timing failure. The pointer may be NULL,
* then nothing happens on missing the deadline. The deadline is equal to the next execution
* of the periodic task.
* @details
* This pointer stores the function that is executed if the task's deadline
* is missed so each may react individually on a timing failure.
* The pointer may be NULL, then nothing happens on missing the deadline.
* The deadline is equal to the next execution of the periodic task.
*/
void (*deadlineMissedFunc)(void);
/**
* @brief This is the function executed in the new task's context.
* @details It converts the argument back to the thread object type and copies the class instance
* to the task context. The taskFunctionality method is called afterwards.
* @details
* It converts the argument back to the thread object type and copies the
* class instance to the task context. The taskFunctionality method is
* called afterwards.
* @param A pointer to the task object itself is passed as argument.
*/
static void taskEntryPoint(void* argument);
/**
* @brief The function containing the actual functionality of the task.
* @details The method sets and starts
* the task's period, then enters a loop that is repeated as long as the isRunning
* attribute is true. Within the loop, all performOperation methods of the added
* objects are called. Afterwards the checkAndRestartPeriod system call blocks the task
* until the next period.
* @details
* The method sets and starts the task's period, then enters a loop that is
* repeated as long as the isRunning attribute is true. Within the loop,
* all performOperation methods of the added objects are called.
* Afterwards the checkAndRestartPeriod system call blocks the task until
* the next period.
* On missing the deadline, the deadlineMissedFunction is executed.
*/
void taskFunctionality(void);

View File

@ -2,7 +2,7 @@
#define FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_
#include <framework/objectmanager/ObjectManagerIF.h>
#include <framework/devicehandlers/FixedSlotSequence.h>
#include <framework/tasks/FixedSlotSequence.h>
#include <framework/tasks/FixedTimeslotTaskIF.h>
#include <framework/tasks/Typedef.h>

View File

@ -2,7 +2,7 @@
#define FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_
#include <framework/tasks/FixedTimeslotTaskIF.h>
#include <framework/devicehandlers/FixedSlotSequence.h>
#include <framework/tasks/FixedSlotSequence.h>
#include <framework/osal/linux/PosixThread.h>
#include <pthread.h>

View File

@ -1,8 +1,9 @@
#include <framework/tasks/ExecutableObjectIF.h>
#include <framework/serviceinterface/ServiceInterfaceStream.h>
#include <errno.h>
#include <framework/osal/linux/PeriodicPosixTask.h>
#include <errno.h>
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_,
size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()):
PosixThread(name_, priority_, stackSize_), objectList(), started(false),
@ -21,12 +22,18 @@ void* PeriodicPosixTask::taskEntryPoint(void* arg) {
return NULL;
}
ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object,
bool setTaskIF) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object);
if (newObject == NULL) {
if (newObject == nullptr) {
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
"it implements ExecutableObjectIF" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
if(setTaskIF) {
newObject->setTaskIF(this);
}
objectList.push_back(newObject);
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -39,7 +39,8 @@ public:
* @param object Id of the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(object_id_t object);
ReturnValue_t addComponent(object_id_t object,
bool setTaskIF = true) override;
uint32_t getPeriodMs() const;

View File

@ -1,4 +1,4 @@
#include <framework/devicehandlers/FixedSequenceSlot.h>
#include <framework/tasks/FixedSequenceSlot.h>
#include <framework/objectmanager/SystemObjectIF.h>
#include <framework/osal/rtems/PollingTask.h>
#include <framework/osal/rtems/RtemsBasic.h>

View File

@ -1,7 +1,7 @@
#ifndef POLLINGTASK_H_
#define POLLINGTASK_H_
#include <framework/devicehandlers/FixedSlotSequence.h>
#include <framework/tasks/FixedSlotSequence.h>
#include <framework/tasks/FixedTimeslotTaskIF.h>
#include "TaskBase.h"

View File

@ -61,8 +61,9 @@ enum {
MUTEX_IF, //MUX 55
MESSAGE_QUEUE_IF,//MQI 56
SEMAPHORE_IF, //SPH 57
HOUSEKEEPING, //HK 58
LOCAL_POOL_OWNER_IF, //LPIF 58
POOL_VARIABLE_IF, //PVA 59
HOUSEKEEPING_MANAGER, //HKM 60
FW_CLASS_ID_COUNT //is actually count + 1 !
};

View File

@ -65,6 +65,21 @@
// No type specification necessary here.
class AutoSerializeAdapter {
public:
/**
* Serialize object into buffer.
* @tparam T Type of object.
* @param object Object to serialize
* @param buffer
* Serialize into this buffer, pointer to pointer has to be passed,
* *buffer will be incremented automatically.
* @param size [out]
* Update passed size value, will be incremented by serialized size
* @param max_size
* Maximum size for range checking
* @param bigEndian
* Set to true if host-to-network conversion or vice-versa is needed
* @return
*/
template<typename T>
static ReturnValue_t serialize(const T* object, uint8_t** buffer,
size_t* size, const size_t max_size, bool bigEndian) {

View File

@ -37,8 +37,10 @@ public:
/**
* @brief Function called during setup assignment of object to task
* @details Has to be called from the function that assigns the object to a task and
* enables the object implementation to overwrite this function and get a reference to the executing task
* @details
* Has to be called from the function that assigns the object to a task and
* enables the object implementation to overwrite this function and get
* a reference to the executing task
* @param task_ Pointer to the taskIF of this task
*/
virtual void setTaskIF(PeriodicTaskIF* task_) {

View File

@ -1,20 +1,15 @@
/**
* @file PollingSlot.cpp
* @brief This file defines the PollingSlot class.
* @date 19.12.2012
* @author baetz
*/
#include <framework/devicehandlers/FixedSequenceSlot.h>
#include <framework/objectmanager/SystemObjectIF.h>
#include <framework/tasks/FixedSequenceSlot.h>
#include <cstddef>
FixedSequenceSlot::FixedSequenceSlot(object_id_t handlerId, uint32_t setTime,
int8_t setSequenceId, PeriodicTaskIF* executingTask) :
handler(NULL), pollingTimeMs(setTime), opcode(setSequenceId) {
pollingTimeMs(setTime), opcode(setSequenceId) {
handler = objectManager->get<ExecutableObjectIF>(handlerId);
if(executingTask != nullptr) {
handler->setTaskIF(executingTask);
}
}
FixedSequenceSlot::~FixedSequenceSlot() {}

View File

@ -1,22 +1,17 @@
/**
* @file FixedSequenceSlot.h
* @brief This file defines the PollingSlot class.
* @date 19.12.2012
* @author baetz
*/
#ifndef FIXEDSEQUENCESLOT_H_
#define FIXEDSEQUENCESLOT_H_
#ifndef FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_
#define FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_
#include <framework/objectmanager/ObjectManagerIF.h>
#include <framework/tasks/ExecutableObjectIF.h>
class PeriodicTaskIF;
/**
* @brief This class is the representation of a single polling sequence table entry.
*
* @details The PollingSlot class is the representation of a single polling
* @brief This class is the representation of a single polling sequence
* table entry.
* @details
* The PollingSlot class is the representation of a single polling
* sequence table entry.
* @author baetz
*/
class FixedSequenceSlot {
public:
@ -27,7 +22,7 @@ public:
/**
* @brief Handler identifies which device handler object is executed in this slot.
*/
ExecutableObjectIF* handler;
ExecutableObjectIF* handler = nullptr;
/**
* @brief This attribute defines when a device handler object is executed.

View File

@ -1,5 +1,5 @@
#include <framework/devicehandlers/FixedSlotSequence.h>
#include <framework/serviceinterface/ServiceInterfaceStream.h>
#include <framework/tasks/FixedSlotSequence.h>
#include <cstdlib>
FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) :

View File

@ -1,8 +1,8 @@
#ifndef FIXEDSLOTSEQUENCE_H_
#define FIXEDSLOTSEQUENCE_H_
#ifndef FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_
#define FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_
#include <framework/devicehandlers/FixedSequenceSlot.h>
#include <framework/objectmanager/SystemObject.h>
#include <framework/tasks/FixedSequenceSlot.h>
#include <set>

View File

@ -12,11 +12,18 @@ class FixedTimeslotTaskIF : public PeriodicTaskIF {
public:
virtual ~FixedTimeslotTaskIF() {}
/**
* Add an object with a slot time and the execution step to the task.
* The execution step shall be passed to the object.
* @param componentId
* @param slotTimeMs
* @param executionStep
* @return
*/
virtual ReturnValue_t addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) = 0;
/** Check whether the sequence is valid */
virtual ReturnValue_t checkSequence() const = 0;
};
#endif /* FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ */

View File

@ -1,9 +1,11 @@
#ifndef PERIODICTASKIF_H_
#define PERIODICTASKIF_H_
#ifndef FRAMEWORK_TASK_PERIODICTASKIF_H_
#define FRAMEWORK_TASK_PERIODICTASKIF_H_
#include <framework/objectmanager/SystemObjectIF.h>
#include <framework/timemanager/Clock.h>
#include <cstddef>
class ExecutableObjectIF;
/**
* New version of TaskIF
* Follows RAII principles, i.e. there's no create or delete method.
@ -17,11 +19,27 @@ public:
*/
virtual ~PeriodicTaskIF() { }
/**
* @brief With the startTask method, a created task can be started for the first time.
* @brief With the startTask method, a created task can be started
* for the first time.
*/
virtual ReturnValue_t startTask() = 0;
virtual ReturnValue_t addComponent(object_id_t object) {return HasReturnvaluesIF::RETURN_FAILED;};
/**
* Add a component (object) to a periodic task. The pointer to the
* task can be set optionally
* @param object
* Add an object to the task. The most important case is to add an
* executable object with a function which will be called regularly
* (see ExecutableObjectIF)
* @param setTaskIF
* Can be used to specify whether the task object pointer is passed
* to the component.
* @return
*/
virtual ReturnValue_t addComponent(object_id_t object,
bool setTaskIF = true) {
return HasReturnvaluesIF::RETURN_FAILED;
};
virtual ReturnValue_t sleepFor(uint32_t ms) = 0;

View File

@ -412,5 +412,6 @@ void CommandingServiceBase::checkTimeout() {
}
}
void CommandingServiceBase::setTaskIF(PeriodicTaskIF* task_) {
executingTask = task_;
}

View File

@ -97,9 +97,7 @@ public:
* Used to setup the reference of the task, that executes this component
* @param task_ Pointer to the taskIF of this task
*/
virtual void setTaskIF(PeriodicTaskIF* task_){
executingTask = task_;
};
virtual void setTaskIF(PeriodicTaskIF* task_);
protected:
/**