Merge branch 'master' into mueller/oldPoolRenaming

This commit is contained in:
Robin Müller 2020-09-22 15:24:09 +02:00
commit d57b329630
83 changed files with 6581 additions and 4218 deletions

View File

@ -1,96 +1,113 @@
#ifndef FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_ #ifndef FSFW_CONTAINER_RINGBUFFERBASE_H_
#define FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_ #define FSFW_CONTAINER_RINGBUFFERBASE_H_
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include <cstddef>
template<uint8_t N_READ_PTRS = 1> template<uint8_t N_READ_PTRS = 1>
class RingBufferBase { class RingBufferBase {
public: public:
RingBufferBase(uint32_t startAddress, uint32_t size, bool overwriteOld) : RingBufferBase(size_t startAddress, const size_t size, bool overwriteOld) :
start(startAddress), write(startAddress), size(size), overwriteOld(overwriteOld) { start(startAddress), write(startAddress), size(size),
overwriteOld(overwriteOld) {
for (uint8_t count = 0; count < N_READ_PTRS; count++) { for (uint8_t count = 0; count < N_READ_PTRS; count++) {
read[count] = startAddress; read[count] = startAddress;
} }
} }
ReturnValue_t readData(uint32_t amount, uint8_t n = 0) {
if (availableReadData(n) >= amount) { virtual ~RingBufferBase() {}
incrementRead(amount, n);
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t writeData(uint32_t amount) {
if (availableWriteSpace() >= amount || overwriteOld) {
incrementWrite(amount);
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
uint32_t availableReadData(uint8_t n = 0) const {
return ((write + size) - read[n]) % size;
}
uint32_t availableWriteSpace(uint8_t n = 0) const {
//One less to avoid ambiguous full/empty problem.
return (((read[n] + size) - write - 1) % size);
}
bool isFull(uint8_t n = 0) { bool isFull(uint8_t n = 0) {
return (availableWriteSpace(n) == 0); return (availableWriteSpace(n) == 0);
} }
bool isEmpty(uint8_t n = 0) { bool isEmpty(uint8_t n = 0) {
return (availableReadData(n) == 0); return (getAvailableReadData(n) == 0);
} }
virtual ~RingBufferBase() {
size_t getAvailableReadData(uint8_t n = 0) const {
return ((write + size) - read[n]) % size;
} }
uint32_t getRead(uint8_t n = 0) const { size_t availableWriteSpace(uint8_t n = 0) const {
return read[n]; //One less to avoid ambiguous full/empty problem.
return (((read[n] + size) - write - 1) % size);
} }
void setRead(uint32_t read, uint8_t n = 0) {
if (read >= start && read < (start+size)) { bool overwritesOld() const {
this->read[n] = read; return overwriteOld;
}
} }
uint32_t getWrite() const {
return write; size_t getMaxSize() const {
} return size - 1;
void setWrite(uint32_t write) {
this->write = write;
} }
void clear() { void clear() {
write = start; write = start;
for (uint8_t count = 0; count < N_READ_PTRS; count++) { for (uint8_t count = 0; count < N_READ_PTRS; count++) {
read[count] = start; read[count] = start;
} }
} }
uint32_t writeTillWrap() {
size_t writeTillWrap() {
return (start + size) - write; return (start + size) - write;
} }
uint32_t readTillWrap(uint8_t n = 0) {
size_t readTillWrap(uint8_t n = 0) {
return (start + size) - read[n]; return (start + size) - read[n];
} }
uint32_t getStart() const {
size_t getStart() const {
return start; return start;
} }
bool overwritesOld() const {
return overwriteOld;
}
uint32_t maxSize() const {
return size - 1;
}
protected: protected:
const uint32_t start; const size_t start;
uint32_t write; size_t write;
uint32_t read[N_READ_PTRS]; size_t read[N_READ_PTRS];
const uint32_t size; const size_t size;
const bool overwriteOld; const bool overwriteOld;
void incrementWrite(uint32_t amount) { void incrementWrite(uint32_t amount) {
write = ((write + amount - start) % size) + start; write = ((write + amount - start) % size) + start;
} }
void incrementRead(uint32_t amount, uint8_t n = 0) { void incrementRead(uint32_t amount, uint8_t n = 0) {
read[n] = ((read[n] + amount - start) % size) + start; read[n] = ((read[n] + amount - start) % size) + start;
} }
ReturnValue_t readData(uint32_t amount, uint8_t n = 0) {
if (getAvailableReadData(n) >= amount) {
incrementRead(amount, n);
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t writeData(uint32_t amount) {
if (availableWriteSpace() >= amount or overwriteOld) {
incrementWrite(amount);
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
size_t getRead(uint8_t n = 0) const {
return read[n];
}
void setRead(uint32_t read, uint8_t n = 0) {
if (read >= start && read < (start+size)) {
this->read[n] = read;
}
}
uint32_t getWrite() const {
return write;
}
void setWrite(uint32_t write) {
this->write = write;
}
}; };
#endif /* FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_ */ #endif /* FSFW_CONTAINER_RINGBUFFERBASE_H_ */

View File

@ -0,0 +1,30 @@
#include "SharedRingBuffer.h"
#include "../ipc/MutexFactory.h"
#include "../ipc/MutexHelper.h"
SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size,
bool overwriteOld, size_t maxExcessBytes):
SystemObject(objectId), SimpleRingBuffer(size, overwriteOld,
maxExcessBytes) {
mutex = MutexFactory::instance()->createMutex();
}
SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t *buffer,
const size_t size, bool overwriteOld, size_t maxExcessBytes):
SystemObject(objectId), SimpleRingBuffer(buffer, size, overwriteOld,
maxExcessBytes) {
mutex = MutexFactory::instance()->createMutex();
}
ReturnValue_t SharedRingBuffer::lockRingBufferMutex(
MutexIF::TimeoutType timeoutType, dur_millis_t timeout) {
return mutex->lockMutex(timeoutType, timeout);
}
ReturnValue_t SharedRingBuffer::unlockRingBufferMutex() {
return mutex->unlockMutex();
}
MutexIF* SharedRingBuffer::getMutexHandle() const {
return mutex;
}

View File

@ -0,0 +1,68 @@
#ifndef FSFW_CONTAINER_SHAREDRINGBUFFER_H_
#define FSFW_CONTAINER_SHAREDRINGBUFFER_H_
#include "SimpleRingBuffer.h"
#include "../ipc/MutexIF.h"
#include "../objectmanager/SystemObject.h"
#include "../timemanager/Clock.h"
/**
* @brief Ring buffer which can be shared among multiple objects
* @details
* This class offers a mutex to perform thread-safe operation on the ring
* buffer. It is still up to the developer to actually perform the lock
* and unlock operations.
*/
class SharedRingBuffer: public SystemObject,
public SimpleRingBuffer {
public:
/**
* This constructor allocates a new internal buffer with the supplied size.
* @param size
* @param overwriteOld
* If the ring buffer is overflowing at a write operartion, the oldest data
* will be overwritten.
*/
SharedRingBuffer(object_id_t objectId, const size_t size,
bool overwriteOld, size_t maxExcessBytes);
/**
* This constructor takes an external buffer with the specified size.
* @param buffer
* @param size
* @param overwriteOld
* If the ring buffer is overflowing at a write operartion, the oldest data
* will be overwritten.
*/
SharedRingBuffer(object_id_t objectId, uint8_t* buffer, const size_t size,
bool overwriteOld, size_t maxExcessBytes);
/**
* Unless a read-only constant value is read, all operations on the
* shared ring buffer should be protected by calling this function.
* @param timeoutType
* @param timeout
* @return
*/
virtual ReturnValue_t lockRingBufferMutex(MutexIF::TimeoutType timeoutType,
dur_millis_t timeout);
/**
* Any locked mutex also has to be unlocked, otherwise, access to the
* shared ring buffer will be blocked.
* @return
*/
virtual ReturnValue_t unlockRingBufferMutex();
/**
* The mutex handle can be accessed directly, for example to perform
* the lock with the #MutexHelper for a RAII compliant lock operation.
* @return
*/
MutexIF* getMutexHandle() const;
private:
MutexIF* mutex = nullptr;
};
#endif /* FSFW_CONTAINER_SHAREDRINGBUFFER_H_ */

View File

@ -1,27 +1,69 @@
#include "SimpleRingBuffer.h" #include "SimpleRingBuffer.h"
#include <string.h> #include <cstring>
SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld) : SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld,
RingBufferBase<>(0, size, overwriteOld) { size_t maxExcessBytes) :
buffer = new uint8_t[size]; RingBufferBase<>(0, size, overwriteOld),
maxExcessBytes(maxExcessBytes) {
if(maxExcessBytes > size) {
this->maxExcessBytes = size;
}
else {
this->maxExcessBytes = maxExcessBytes;
}
buffer = new uint8_t[size + maxExcessBytes];
} }
SimpleRingBuffer::SimpleRingBuffer(uint8_t *buffer, const size_t size, SimpleRingBuffer::SimpleRingBuffer(uint8_t *buffer, const size_t size,
bool overwriteOld): bool overwriteOld, size_t maxExcessBytes):
RingBufferBase<>(0, size, overwriteOld), buffer(buffer) {} RingBufferBase<>(0, size, overwriteOld), buffer(buffer) {
if(maxExcessBytes > size) {
this->maxExcessBytes = size;
}
else {
this->maxExcessBytes = maxExcessBytes;
}
}
SimpleRingBuffer::~SimpleRingBuffer() { SimpleRingBuffer::~SimpleRingBuffer() {
delete[] buffer; delete[] buffer;
} }
ReturnValue_t SimpleRingBuffer::getFreeElement(uint8_t **writePointer,
size_t amount) {
if (availableWriteSpace() >= amount or overwriteOld) {
size_t amountTillWrap = writeTillWrap();
if (amountTillWrap < amount) {
if((amount - amountTillWrap + excessBytes) > maxExcessBytes) {
return HasReturnvaluesIF::RETURN_FAILED;
}
excessBytes = amount - amountTillWrap;
}
*writePointer = &buffer[write];
return HasReturnvaluesIF::RETURN_OK;
}
else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
void SimpleRingBuffer::confirmBytesWritten(size_t amount) {
if(getExcessBytes() > 0) {
moveExcessBytesToStart();
}
incrementWrite(amount);
}
ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data, ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data,
uint32_t amount) { size_t amount) {
if (availableWriteSpace() >= amount or overwriteOld) { if (availableWriteSpace() >= amount or overwriteOld) {
uint32_t amountTillWrap = writeTillWrap(); size_t amountTillWrap = writeTillWrap();
if (amountTillWrap >= amount) { if (amountTillWrap >= amount) {
// remaining size in buffer is sufficient to fit full amount.
memcpy(&buffer[write], data, amount); memcpy(&buffer[write], data, amount);
} else { }
else {
memcpy(&buffer[write], data, amountTillWrap); memcpy(&buffer[write], data, amountTillWrap);
memcpy(buffer, data + amountTillWrap, amount - amountTillWrap); memcpy(buffer, data + amountTillWrap, amount - amountTillWrap);
} }
@ -32,12 +74,13 @@ ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data,
} }
} }
ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, uint32_t amount, ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, size_t amount,
bool readRemaining, uint32_t* trueAmount) { bool incrementReadPtr, bool readRemaining, size_t* trueAmount) {
uint32_t availableData = availableReadData(READ_PTR); size_t availableData = getAvailableReadData(READ_PTR);
uint32_t amountTillWrap = readTillWrap(READ_PTR); size_t amountTillWrap = readTillWrap(READ_PTR);
if (availableData < amount) { if (availableData < amount) {
if (readRemaining) { if (readRemaining) {
// more data available than amount specified.
amount = availableData; amount = availableData;
} else { } else {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
@ -52,12 +95,27 @@ ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, uint32_t amount,
memcpy(data, &buffer[read[READ_PTR]], amountTillWrap); memcpy(data, &buffer[read[READ_PTR]], amountTillWrap);
memcpy(data + amountTillWrap, buffer, amount - amountTillWrap); memcpy(data + amountTillWrap, buffer, amount - amountTillWrap);
} }
if(incrementReadPtr) {
deleteData(amount, readRemaining);
}
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t SimpleRingBuffer::deleteData(uint32_t amount, size_t SimpleRingBuffer::getExcessBytes() const {
bool deleteRemaining, uint32_t* trueAmount) { return excessBytes;
uint32_t availableData = availableReadData(READ_PTR); }
void SimpleRingBuffer::moveExcessBytesToStart() {
if(excessBytes > 0) {
std::memcpy(buffer, &buffer[size], excessBytes);
excessBytes = 0;
}
}
ReturnValue_t SimpleRingBuffer::deleteData(size_t amount,
bool deleteRemaining, size_t* trueAmount) {
size_t availableData = getAvailableReadData(READ_PTR);
if (availableData < amount) { if (availableData < amount) {
if (deleteRemaining) { if (deleteRemaining) {
amount = availableData; amount = availableData;
@ -71,4 +129,3 @@ ReturnValue_t SimpleRingBuffer::deleteData(uint32_t amount,
incrementRead(amount, READ_PTR); incrementRead(amount, READ_PTR);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -1,8 +1,8 @@
#ifndef FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ #ifndef FSFW_CONTAINER_SIMPLERINGBUFFER_H_
#define FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ #define FSFW_CONTAINER_SIMPLERINGBUFFER_H_
#include "RingBufferBase.h" #include "RingBufferBase.h"
#include <stddef.h> #include <cstddef>
/** /**
* @brief Circular buffer implementation, useful for buffering * @brief Circular buffer implementation, useful for buffering
@ -16,53 +16,114 @@ class SimpleRingBuffer: public RingBufferBase<> {
public: public:
/** /**
* This constructor allocates a new internal buffer with the supplied size. * This constructor allocates a new internal buffer with the supplied size.
*
* @param size * @param size
* @param overwriteOld * @param overwriteOld If the ring buffer is overflowing at a write
* operation, the oldest data will be overwritten.
* @param maxExcessBytes These additional bytes will be allocated in addtion
* to the specified size to accomodate contiguous write operations
* with getFreeElement.
*
*/ */
SimpleRingBuffer(const size_t size, bool overwriteOld); SimpleRingBuffer(const size_t size, bool overwriteOld,
size_t maxExcessBytes = 0);
/** /**
* This constructor takes an external buffer with the specified size. * This constructor takes an external buffer with the specified size.
* @param buffer * @param buffer
* @param size * @param size
* @param overwriteOld * @param overwriteOld
* If the ring buffer is overflowing at a write operartion, the oldest data
* will be overwritten.
* @param maxExcessBytes
* If the buffer can accomodate additional bytes for contigous write
* operations with getFreeElement, this is the maximum allowed additional
* size
*/ */
SimpleRingBuffer(uint8_t* buffer, const size_t size, bool overwriteOld); SimpleRingBuffer(uint8_t* buffer, const size_t size, bool overwriteOld,
size_t maxExcessBytes = 0);
virtual ~SimpleRingBuffer(); virtual ~SimpleRingBuffer();
/** /**
* Write to circular buffer and increment write pointer by amount * Write to circular buffer and increment write pointer by amount.
* @param data * @param data
* @param amount * @param amount
* @return -@c RETURN_OK if write operation was successfull
* -@c RETURN_FAILED if
*/
ReturnValue_t writeData(const uint8_t* data, size_t amount);
/**
* Returns a pointer to a free element. If the remaining buffer is
* not large enough, the data will be written past the actual size
* and the amount of excess bytes will be cached. This function
* does not increment the write pointer!
* @param writePointer Pointer to a pointer which can be used to write
* contiguous blocks into the ring buffer
* @param amount
* @return * @return
*/ */
ReturnValue_t writeData(const uint8_t* data, uint32_t amount); ReturnValue_t getFreeElement(uint8_t** writePointer, size_t amount);
/** /**
* Read from circular buffer at read pointer * This increments the write pointer and also copies the excess bytes
* to the beginning. It should be called if the write operation
* conducted after calling getFreeElement() was performed.
* @return
*/
void confirmBytesWritten(size_t amount);
virtual size_t getExcessBytes() const;
/**
* Helper functions which moves any excess bytes to the start
* of the ring buffer.
* @return
*/
virtual void moveExcessBytesToStart();
/**
* Read from circular buffer at read pointer.
* @param data * @param data
* @param amount * @param amount
* @param incrementReadPtr
* If this is set to true, the read pointer will be incremented.
* If readRemaining is set to true, the read pointer will be incremented
* accordingly.
* @param readRemaining * @param readRemaining
* @param trueAmount * If this is set to true, the data will be read even if the amount
* specified exceeds the read data available.
* @param trueAmount [out]
* If readRemaining was set to true, the true amount read will be assigned
* to the passed value.
* @return * @return
* - @c RETURN_OK if data was read successfully
* - @c RETURN_FAILED if not enough data was available and readRemaining
* was set to false.
*/ */
ReturnValue_t readData(uint8_t* data, uint32_t amount, ReturnValue_t readData(uint8_t* data, size_t amount,
bool readRemaining = false, uint32_t* trueAmount = nullptr); bool incrementReadPtr = false, bool readRemaining = false,
size_t* trueAmount = nullptr);
/** /**
* Delete data starting by incrementing read pointer * Delete data by incrementing read pointer.
* @param amount * @param amount
* @param deleteRemaining * @param deleteRemaining
* @param trueAmount * If the amount specified is larger than the remaing size to read and this
* is set to true, the remaining amount will be deleted as well
* @param trueAmount [out]
* If deleteRemaining was set to true, the amount deleted will be assigned
* to the passed value.
* @return * @return
*/ */
ReturnValue_t deleteData(uint32_t amount, bool deleteRemaining = false, ReturnValue_t deleteData(size_t amount, bool deleteRemaining = false,
uint32_t* trueAmount = nullptr); size_t* trueAmount = nullptr);
private: private:
// static const uint8_t TEMP_READ_PTR = 1;
static const uint8_t READ_PTR = 0; static const uint8_t READ_PTR = 0;
uint8_t* buffer = nullptr; uint8_t* buffer = nullptr;
size_t maxExcessBytes;
size_t excessBytes = 0;
}; };
#endif /* FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ */ #endif /* FSFW_CONTAINER_SIMPLERINGBUFFER_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,117 +1,117 @@
#ifndef _sgp4unit_ #ifndef _sgp4unit_
#define _sgp4unit_ #define _sgp4unit_
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* *
* sgp4unit.h * sgp4unit.h
* *
* this file contains the sgp4 procedures for analytical propagation * this file contains the sgp4 procedures for analytical propagation
* of a satellite. the code was originally released in the 1980 and 1986 * of a satellite. the code was originally released in the 1980 and 1986
* spacetrack papers. a detailed discussion of the theory and history * spacetrack papers. a detailed discussion of the theory and history
* may be found in the 2006 aiaa paper by vallado, crawford, hujsak, * may be found in the 2006 aiaa paper by vallado, crawford, hujsak,
* and kelso. * and kelso.
* *
* companion code for * companion code for
* fundamentals of astrodynamics and applications * fundamentals of astrodynamics and applications
* 2007 * 2007
* by david vallado * by david vallado
* *
* (w) 719-573-2600, email dvallado@agi.com * (w) 719-573-2600, email dvallado@agi.com
* *
* current : * current :
* 20 apr 07 david vallado * 20 apr 07 david vallado
* misc fixes for constants * misc fixes for constants
* changes : * changes :
* 11 aug 06 david vallado * 11 aug 06 david vallado
* chg lyddane choice back to strn3, constants, misc doc * chg lyddane choice back to strn3, constants, misc doc
* 15 dec 05 david vallado * 15 dec 05 david vallado
* misc fixes * misc fixes
* 26 jul 05 david vallado * 26 jul 05 david vallado
* fixes for paper * fixes for paper
* note that each fix is preceded by a * note that each fix is preceded by a
* comment with "sgp4fix" and an explanation of * comment with "sgp4fix" and an explanation of
* what was changed * what was changed
* 10 aug 04 david vallado * 10 aug 04 david vallado
* 2nd printing baseline working * 2nd printing baseline working
* 14 may 01 david vallado * 14 may 01 david vallado
* 2nd edition baseline * 2nd edition baseline
* 80 norad * 80 norad
* original baseline * original baseline
* ---------------------------------------------------------------- */ * ---------------------------------------------------------------- */
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
// -------------------------- structure declarations ---------------------------- // -------------------------- structure declarations ----------------------------
typedef enum typedef enum
{ {
wgs72old, wgs72old,
wgs72, wgs72,
wgs84 wgs84
} gravconsttype; } gravconsttype;
typedef struct elsetrec typedef struct elsetrec
{ {
long int satnum; long int satnum;
int epochyr, epochtynumrev; int epochyr, epochtynumrev;
int error; int error;
char init, method; char init, method;
/* Near Earth */ /* Near Earth */
int isimp; int isimp;
double aycof , con41 , cc1 , cc4 , cc5 , d2 , d3 , d4 , double aycof , con41 , cc1 , cc4 , cc5 , d2 , d3 , d4 ,
delmo , eta , argpdot, omgcof , sinmao , t , t2cof, t3cof , delmo , eta , argpdot, omgcof , sinmao , t , t2cof, t3cof ,
t4cof , t5cof , x1mth2 , x7thm1 , mdot , nodedot, xlcof , xmcof , t4cof , t5cof , x1mth2 , x7thm1 , mdot , nodedot, xlcof , xmcof ,
nodecf; nodecf;
/* Deep Space */ /* Deep Space */
int irez; int irez;
double d2201 , d2211 , d3210 , d3222 , d4410 , d4422 , d5220 , d5232 , double d2201 , d2211 , d3210 , d3222 , d4410 , d4422 , d5220 , d5232 ,
d5421 , d5433 , dedt , del1 , del2 , del3 , didt , dmdt , d5421 , d5433 , dedt , del1 , del2 , del3 , didt , dmdt ,
dnodt , domdt , e3 , ee2 , peo , pgho , pho , pinco , dnodt , domdt , e3 , ee2 , peo , pgho , pho , pinco ,
plo , se2 , se3 , sgh2 , sgh3 , sgh4 , sh2 , sh3 , plo , se2 , se3 , sgh2 , sgh3 , sgh4 , sh2 , sh3 ,
si2 , si3 , sl2 , sl3 , sl4 , gsto , xfact , xgh2 , si2 , si3 , sl2 , sl3 , sl4 , gsto , xfact , xgh2 ,
xgh3 , xgh4 , xh2 , xh3 , xi2 , xi3 , xl2 , xl3 , xgh3 , xgh4 , xh2 , xh3 , xi2 , xi3 , xl2 , xl3 ,
xl4 , xlamo , zmol , zmos , atime , xli , xni; xl4 , xlamo , zmol , zmos , atime , xli , xni;
double a , altp , alta , epochdays, jdsatepoch , nddot , ndot , double a , altp , alta , epochdays, jdsatepoch , nddot , ndot ,
bstar , rcse , inclo , nodeo , ecco , argpo , mo , bstar , rcse , inclo , nodeo , ecco , argpo , mo ,
no; no;
} elsetrec; } elsetrec;
// --------------------------- function declarations ---------------------------- // --------------------------- function declarations ----------------------------
int sgp4init int sgp4init
( (
gravconsttype whichconst, const int satn, const double epoch, gravconsttype whichconst, const int satn, const double epoch,
const double xbstar, const double xecco, const double xargpo, const double xbstar, const double xecco, const double xargpo,
const double xinclo, const double xmo, const double xno, const double xinclo, const double xmo, const double xno,
const double xnodeo, const double xnodeo,
elsetrec& satrec elsetrec& satrec
); );
int sgp4 int sgp4
( (
gravconsttype whichconst, gravconsttype whichconst,
elsetrec& satrec, double tsince, elsetrec& satrec, double tsince,
double r[], double v[] double r[], double v[]
); );
double gstime double gstime
( (
double double
); );
void getgravconst void getgravconst
( (
gravconsttype, gravconsttype,
double&, double&,
double&, double&,
double&, double&,
double&, double&,
double&, double&,
double&, double&,
double&, double&,
double& double&
); );
#endif #endif

View File

@ -1,5 +1,5 @@
#ifndef FRAMEWORK_EVENTS_FWSUBSYSTEMIDRANGES_H_ #ifndef FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_
#define FRAMEWORK_EVENTS_FWSUBSYSTEMIDRANGES_H_ #define FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_
namespace SUBSYSTEM_ID { namespace SUBSYSTEM_ID {
enum { enum {
@ -19,10 +19,11 @@ enum {
SYSTEM_MANAGER_1 = 75, SYSTEM_MANAGER_1 = 75,
SYSTEM_1 = 79, SYSTEM_1 = 79,
PUS_SERVICE_1 = 80, PUS_SERVICE_1 = 80,
PUS_SERVICE_17 = 97,
FW_SUBSYSTEM_ID_RANGE FW_SUBSYSTEM_ID_RANGE
}; };
} }
#endif /* FRAMEWORK_EVENTS_FWSUBSYSTEMIDRANGES_H_ */ #endif /* FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_ */

View File

@ -1,95 +1,124 @@
#include "DleEncoder.h" #include "../globalfunctions/DleEncoder.h"
DleEncoder::DleEncoder() { DleEncoder::DleEncoder() {}
}
DleEncoder::~DleEncoder() { DleEncoder::~DleEncoder() {}
ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream,
size_t sourceLen, uint8_t* destStream, size_t maxDestLen,
size_t* encodedLen, bool addStxEtx) {
if (maxDestLen < 2) {
return STREAM_TOO_SHORT;
}
size_t encodedIndex = 0, sourceIndex = 0;
uint8_t nextByte;
if (addStxEtx) {
destStream[0] = STX_CHAR;
++encodedIndex;
}
while (encodedIndex < maxDestLen and sourceIndex < sourceLen)
{
nextByte = sourceStream[sourceIndex];
// STX, ETX and CR characters in the stream need to be escaped with DLE
if (nextByte == STX_CHAR or nextByte == ETX_CHAR or nextByte == CARRIAGE_RETURN) {
if (encodedIndex + 1 >= maxDestLen) {
return STREAM_TOO_SHORT;
}
else {
destStream[encodedIndex] = DLE_CHAR;
++encodedIndex;
/* Escaped byte will be actual byte + 0x40. This prevents
* STX, ETX, and carriage return characters from appearing
* in the encoded data stream at all, so when polling an
* encoded stream, the transmission can be stopped at ETX.
* 0x40 was chosen at random with special requirements:
* - Prevent going from one control char to another
* - Prevent overflow for common characters */
destStream[encodedIndex] = nextByte + 0x40;
}
}
// DLE characters are simply escaped with DLE.
else if (nextByte == DLE_CHAR) {
if (encodedIndex + 1 >= maxDestLen) {
return STREAM_TOO_SHORT;
}
else {
destStream[encodedIndex] = DLE_CHAR;
++encodedIndex;
destStream[encodedIndex] = DLE_CHAR;
}
}
else {
destStream[encodedIndex] = nextByte;
}
++encodedIndex;
++sourceIndex;
}
if (sourceIndex == sourceLen and encodedIndex < maxDestLen) {
if (addStxEtx) {
destStream[encodedIndex] = ETX_CHAR;
++encodedIndex;
}
*encodedLen = encodedIndex;
return RETURN_OK;
}
else {
return STREAM_TOO_SHORT;
}
} }
ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream, ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream,
uint32_t sourceStreamLen, uint32_t *readLen, uint8_t *destStream, size_t sourceStreamLen, size_t *readLen, uint8_t *destStream,
uint32_t maxDestStreamlen, uint32_t *decodedLen) { size_t maxDestStreamlen, size_t *decodedLen) {
uint32_t encodedIndex = 0, decodedIndex = 0; size_t encodedIndex = 0, decodedIndex = 0;
uint8_t nextByte; uint8_t nextByte;
if (*sourceStream != STX) { if (*sourceStream != STX_CHAR) {
return RETURN_FAILED; return DECODING_ERROR;
} }
++encodedIndex; ++encodedIndex;
while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen) while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen)
&& (sourceStream[encodedIndex] != ETX) && (sourceStream[encodedIndex] != ETX_CHAR)
&& (sourceStream[encodedIndex] != STX)) { && (sourceStream[encodedIndex] != STX_CHAR)) {
if (sourceStream[encodedIndex] == DLE) { if (sourceStream[encodedIndex] == DLE_CHAR) {
nextByte = sourceStream[encodedIndex + 1]; nextByte = sourceStream[encodedIndex + 1];
if (nextByte == 0x10) { // The next byte is a DLE character that was escaped by another
// DLE character, so we can write it to the destination stream.
if (nextByte == DLE_CHAR) {
destStream[decodedIndex] = nextByte; destStream[decodedIndex] = nextByte;
} else { }
if ((nextByte == 0x42) || (nextByte == 0x43) else {
|| (nextByte == 0x4D)) { /* The next byte is a STX, DTX or 0x0D character which
* was escaped by a DLE character. The actual byte was
* also encoded by adding + 0x40 to prevent having control chars,
* in the stream at all, so we convert it back. */
if (nextByte == 0x42 or nextByte == 0x43 or nextByte == 0x4D) {
destStream[decodedIndex] = nextByte - 0x40; destStream[decodedIndex] = nextByte - 0x40;
} else { }
return RETURN_FAILED; else {
return DECODING_ERROR;
} }
} }
++encodedIndex; ++encodedIndex;
} else { }
else {
destStream[decodedIndex] = sourceStream[encodedIndex]; destStream[decodedIndex] = sourceStream[encodedIndex];
} }
++encodedIndex; ++encodedIndex;
++decodedIndex; ++decodedIndex;
} }
if (sourceStream[encodedIndex] != ETX) {
return RETURN_FAILED; if (sourceStream[encodedIndex] != ETX_CHAR) {
} else { *readLen = ++encodedIndex;
return DECODING_ERROR;
}
else {
*readLen = ++encodedIndex; *readLen = ++encodedIndex;
*decodedLen = decodedIndex; *decodedLen = decodedIndex;
return RETURN_OK; return RETURN_OK;
} }
} }
ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream,
uint32_t sourceLen, uint8_t* destStream, uint32_t maxDestLen,
uint32_t* encodedLen, bool addStxEtx) {
if (maxDestLen < 2) {
return RETURN_FAILED;
}
uint32_t encodedIndex = 0, sourceIndex = 0;
uint8_t nextByte;
if (addStxEtx) {
destStream[0] = STX;
++encodedIndex;
}
while ((encodedIndex < maxDestLen) && (sourceIndex < sourceLen)) {
nextByte = sourceStream[sourceIndex];
if ((nextByte == STX) || (nextByte == ETX) || (nextByte == 0x0D)) {
if (encodedIndex + 1 >= maxDestLen) {
return RETURN_FAILED;
} else {
destStream[encodedIndex] = DLE;
++encodedIndex;
destStream[encodedIndex] = nextByte + 0x40;
}
} else if (nextByte == DLE) {
if (encodedIndex + 1 >= maxDestLen) {
return RETURN_FAILED;
} else {
destStream[encodedIndex] = DLE;
++encodedIndex;
destStream[encodedIndex] = DLE;
}
} else {
destStream[encodedIndex] = nextByte;
}
++encodedIndex;
++sourceIndex;
}
if ((sourceIndex == sourceLen) && (encodedIndex < maxDestLen)) {
if (addStxEtx) {
destStream[encodedIndex] = ETX;
++encodedIndex;
}
*encodedLen = encodedIndex;
return RETURN_OK;
} else {
return RETURN_FAILED;
}
}

View File

@ -1,25 +1,79 @@
#ifndef DLEENCODER_H_ #ifndef FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_
#define DLEENCODER_H_ #define FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include <cstddef>
/**
* @brief This DLE Encoder (Data Link Encoder) can be used to encode and
* decode arbitrary data with ASCII control characters
* @details
* List of control codes:
* https://en.wikipedia.org/wiki/C0_and_C1_control_codes
*
* This encoder can be used to achieve a basic transport layer when using
* char based transmission systems.
* The passed source strean is converted into a encoded stream by adding
* a STX marker at the start of the stream and an ETX marker at the end of
* the stream. Any STX, ETX, DLE and CR occurrences in the source stream are
* escaped by a DLE character. The encoder also replaces escaped control chars
* by another char, so STX, ETX and CR should not appear anywhere in the actual
* encoded data stream.
*
* When using a strictly char based reception of packets encoded with DLE,
* STX can be used to notify a reader that actual data will start to arrive
* while ETX can be used to notify the reader that the data has ended.
*/
class DleEncoder: public HasReturnvaluesIF { class DleEncoder: public HasReturnvaluesIF {
private: private:
DleEncoder(); DleEncoder();
virtual ~DleEncoder(); virtual ~DleEncoder();
public: public:
static const uint8_t STX = 0x02; static constexpr uint8_t INTERFACE_ID = CLASS_ID::DLE_ENCODER;
static const uint8_t ETX = 0x03; static constexpr ReturnValue_t STREAM_TOO_SHORT = MAKE_RETURN_CODE(0x01);
static const uint8_t DLE = 0x10; static constexpr ReturnValue_t DECODING_ERROR = MAKE_RETURN_CODE(0x02);
//! Start Of Text character. First character is encoded stream
static constexpr uint8_t STX_CHAR = 0x02;
//! End Of Text character. Last character in encoded stream
static constexpr uint8_t ETX_CHAR = 0x03;
//! Data Link Escape character. Used to escape STX, ETX and DLE occurrences
//! in the source stream.
static constexpr uint8_t DLE_CHAR = 0x10;
static constexpr uint8_t CARRIAGE_RETURN = 0x0D;
/**
* Encodes the give data stream by preceding it with the STX marker
* and ending it with an ETX marker. STX, ETX and DLE characters inside
* the stream are escaped by DLE characters and also replaced by adding
* 0x40 (which is reverted in the decoding process).
* @param sourceStream
* @param sourceLen
* @param destStream
* @param maxDestLen
* @param encodedLen
* @param addStxEtx
* Adding STX and ETX can be omitted, if they are added manually.
* @return
*/
static ReturnValue_t encode(const uint8_t *sourceStream, size_t sourceLen,
uint8_t *destStream, size_t maxDestLen, size_t *encodedLen,
bool addStxEtx = true);
/**
* Converts an encoded stream back.
* @param sourceStream
* @param sourceStreamLen
* @param readLen
* @param destStream
* @param maxDestStreamlen
* @param decodedLen
* @return
*/
static ReturnValue_t decode(const uint8_t *sourceStream, static ReturnValue_t decode(const uint8_t *sourceStream,
uint32_t sourceStreamLen, uint32_t *readLen, uint8_t *destStream, size_t sourceStreamLen, size_t *readLen, uint8_t *destStream,
uint32_t maxDestStreamlen, uint32_t *decodedLen); size_t maxDestStreamlen, size_t *decodedLen);
static ReturnValue_t encode(const uint8_t *sourceStream, uint32_t sourceLen,
uint8_t *destStream, uint32_t maxDestLen, uint32_t *encodedLen,
bool addStxEtx = true);
}; };
#endif /* DLEENCODER_H_ */ #endif /* FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ */

View File

@ -0,0 +1,34 @@
#include "PeriodicOperationDivider.h"
PeriodicOperationDivider::PeriodicOperationDivider(uint32_t divider,
bool resetAutomatically): resetAutomatically(resetAutomatically),
counter(divider), divider(divider) {
}
bool PeriodicOperationDivider::checkAndIncrement() {
if(counter >= divider) {
if(resetAutomatically) {
counter = 0;
}
return true;
}
counter ++;
return false;
}
void PeriodicOperationDivider::resetCounter() {
counter = 0;
}
void PeriodicOperationDivider::setDivider(uint32_t newDivider) {
divider = newDivider;
}
uint32_t PeriodicOperationDivider::getCounter() const {
return counter;
}
uint32_t PeriodicOperationDivider::getDivider() const {
return divider;
}

View File

@ -0,0 +1,55 @@
#ifndef FSFW_GLOBALFUNCTIONS_PERIODICOPERATIONDIVIDER_H_
#define FSFW_GLOBALFUNCTIONS_PERIODICOPERATIONDIVIDER_H_
#include <cstdint>
/**
* @brief Lightweight helper class to facilitate periodic operation with
* decreased frequencies.
* @details
* This class is useful to perform operations which have to be performed
* with a reduced frequency, like debugging printouts in high periodic tasks
* or low priority operations.
*/
class PeriodicOperationDivider {
public:
/**
* Initialize with the desired divider and specify whether the internal
* counter will be reset automatically.
* @param divider
* @param resetAutomatically
*/
PeriodicOperationDivider(uint32_t divider, bool resetAutomatically = true);
/**
* Check whether operation is necessary.
* If an operation is necessary and the class has been
* configured to be reset automatically, the counter will be reset.
* If not, the counter will be incremented.
* @return
* -@c true if the counter is larger or equal to the divider
* -@c false otherwise
*/
bool checkAndIncrement();
/**
* Can be used to reset the counter to 0 manually.
*/
void resetCounter();
uint32_t getCounter() const;
/**
* Can be used to set a new divider value.
* @param newDivider
*/
void setDivider(uint32_t newDivider);
uint32_t getDivider() const;
private:
bool resetAutomatically = true;
uint32_t counter = 0;
uint32_t divider = 0;
};
#endif /* FSFW_GLOBALFUNCTIONS_PERIODICOPERATIONDIVIDER_H_ */

View File

@ -1,99 +1,99 @@
#include "timevalOperations.h" #include "timevalOperations.h"
timeval& operator+=(timeval& lhs, const timeval& rhs) { timeval& operator+=(timeval& lhs, const timeval& rhs) {
int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec; int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec;
sum += rhs.tv_sec * 1000000. + rhs.tv_usec; sum += rhs.tv_sec * 1000000. + rhs.tv_usec;
lhs.tv_sec = sum / 1000000; lhs.tv_sec = sum / 1000000;
lhs.tv_usec = sum - lhs.tv_sec * 1000000; lhs.tv_usec = sum - lhs.tv_sec * 1000000;
return lhs; return lhs;
} }
timeval operator+(timeval lhs, const timeval& rhs) { timeval operator+(timeval lhs, const timeval& rhs) {
lhs += rhs; lhs += rhs;
return lhs; return lhs;
} }
timeval& operator-=(timeval& lhs, const timeval& rhs) { timeval& operator-=(timeval& lhs, const timeval& rhs) {
int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec; int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec;
sum -= rhs.tv_sec * 1000000. + rhs.tv_usec; sum -= rhs.tv_sec * 1000000. + rhs.tv_usec;
lhs.tv_sec = sum / 1000000; lhs.tv_sec = sum / 1000000;
lhs.tv_usec = sum - lhs.tv_sec * 1000000; lhs.tv_usec = sum - lhs.tv_sec * 1000000;
return lhs; return lhs;
} }
timeval operator-(timeval lhs, const timeval& rhs) { timeval operator-(timeval lhs, const timeval& rhs) {
lhs -= rhs; lhs -= rhs;
return lhs; return lhs;
} }
double operator/(const timeval& lhs, const timeval& rhs) { double operator/(const timeval& lhs, const timeval& rhs) {
double lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; double lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec;
double rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; double rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec;
return lhs64 / rhs64; return lhs64 / rhs64;
} }
timeval& operator/=(timeval& lhs, double scalar) { timeval& operator/=(timeval& lhs, double scalar) {
int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec; int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec;
product /= scalar; product /= scalar;
lhs.tv_sec = product / 1000000; lhs.tv_sec = product / 1000000;
lhs.tv_usec = product - lhs.tv_sec * 1000000; lhs.tv_usec = product - lhs.tv_sec * 1000000;
return lhs; return lhs;
} }
timeval operator/(timeval lhs, double scalar) { timeval operator/(timeval lhs, double scalar) {
lhs /= scalar; lhs /= scalar;
return lhs; return lhs;
} }
timeval& operator*=(timeval& lhs, double scalar) { timeval& operator*=(timeval& lhs, double scalar) {
int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec; int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec;
product *= scalar; product *= scalar;
lhs.tv_sec = product / 1000000; lhs.tv_sec = product / 1000000;
lhs.tv_usec = product - lhs.tv_sec * 1000000; lhs.tv_usec = product - lhs.tv_sec * 1000000;
return lhs; return lhs;
} }
timeval operator*(timeval lhs, double scalar) { timeval operator*(timeval lhs, double scalar) {
lhs *= scalar; lhs *= scalar;
return lhs; return lhs;
} }
timeval operator*(double scalar, timeval rhs) { timeval operator*(double scalar, timeval rhs) {
rhs *= scalar; rhs *= scalar;
return rhs; return rhs;
} }
bool operator==(const timeval& lhs, const timeval& rhs) { bool operator==(const timeval& lhs, const timeval& rhs) {
int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec;
int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec;
return lhs64 == rhs64; return lhs64 == rhs64;
} }
bool operator!=(const timeval& lhs, const timeval& rhs) { bool operator!=(const timeval& lhs, const timeval& rhs) {
return !operator==(lhs, rhs); return !operator==(lhs, rhs);
} }
bool operator<(const timeval& lhs, const timeval& rhs) { bool operator<(const timeval& lhs, const timeval& rhs) {
int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec;
int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec;
return lhs64 < rhs64; return lhs64 < rhs64;
} }
bool operator>(const timeval& lhs, const timeval& rhs) { bool operator>(const timeval& lhs, const timeval& rhs) {
return operator<(rhs, lhs); return operator<(rhs, lhs);
} }
bool operator<=(const timeval& lhs, const timeval& rhs) { bool operator<=(const timeval& lhs, const timeval& rhs) {
return !operator>(lhs, rhs); return !operator>(lhs, rhs);
} }
bool operator>=(const timeval& lhs, const timeval& rhs) { bool operator>=(const timeval& lhs, const timeval& rhs) {
return !operator<(lhs, rhs); return !operator<(lhs, rhs);
} }
double timevalOperations::toDouble(const timeval timeval) { double timevalOperations::toDouble(const timeval timeval) {
double result = timeval.tv_sec * 1000000. + timeval.tv_usec; double result = timeval.tv_sec * 1000000. + timeval.tv_usec;
return result / 1000000.; return result / 1000000.;
} }
timeval timevalOperations::toTimeval(const double seconds) { timeval timevalOperations::toTimeval(const double seconds) {
timeval tval; timeval tval;
tval.tv_sec = seconds; tval.tv_sec = seconds;
tval.tv_usec = seconds *(double) 1e6 - (tval.tv_sec *1e6); tval.tv_usec = seconds *(double) 1e6 - (tval.tv_sec *1e6);
return tval; return tval;
} }

View File

@ -1,9 +1,8 @@
#include "HealthHelper.h" #include "HealthHelper.h"
#include "../ipc/MessageQueueSenderIF.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterfaceStream.h"
HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId) : HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId) :
healthTable(NULL), eventSender(NULL), objectId(objectId), parentQueue( objectId(objectId), owner(owner) {
0), owner(owner) {
} }
HealthHelper::~HealthHelper() { HealthHelper::~HealthHelper() {
@ -40,9 +39,19 @@ void HealthHelper::setParentQueue(MessageQueueId_t parentQueue) {
ReturnValue_t HealthHelper::initialize() { ReturnValue_t HealthHelper::initialize() {
healthTable = objectManager->get<HealthTableIF>(objects::HEALTH_TABLE); healthTable = objectManager->get<HealthTableIF>(objects::HEALTH_TABLE);
eventSender = objectManager->get<EventReportingProxyIF>(objectId); eventSender = objectManager->get<EventReportingProxyIF>(objectId);
if ((healthTable == NULL) || eventSender == NULL) {
return HasReturnvaluesIF::RETURN_FAILED; if (healthTable == nullptr) {
sif::error << "HealthHelper::initialize: Health table object needs"
"to be created in factory." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
} }
if(eventSender == nullptr) {
sif::error << "HealthHelper::initialize: Owner has to implement "
"ReportingProxyIF." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
ReturnValue_t result = healthTable->registerObject(objectId, ReturnValue_t result = healthTable->registerObject(objectId,
HasHealthIF::HEALTHY); HasHealthIF::HEALTHY);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
@ -62,22 +71,22 @@ void HealthHelper::setHealth(HasHealthIF::HealthState health) {
void HealthHelper::informParent(HasHealthIF::HealthState health, void HealthHelper::informParent(HasHealthIF::HealthState health,
HasHealthIF::HealthState oldHealth) { HasHealthIF::HealthState oldHealth) {
if (parentQueue == 0) { if (parentQueue == MessageQueueIF::NO_QUEUE) {
return; return;
} }
CommandMessage message; CommandMessage information;
HealthMessage::setHealthMessage(&message, HealthMessage::HEALTH_INFO, HealthMessage::setHealthMessage(&information, HealthMessage::HEALTH_INFO,
health, oldHealth); health, oldHealth);
if (MessageQueueSenderIF::sendMessage(parentQueue, &message, if (MessageQueueSenderIF::sendMessage(parentQueue, &information,
owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) { owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) {
sif::debug << "HealthHelper::informParent: sending health reply failed." sif::debug << "HealthHelper::informParent: sending health reply failed."
<< std::endl; << std::endl;
} }
} }
void HealthHelper::handleSetHealthCommand(CommandMessage* message) { void HealthHelper::handleSetHealthCommand(CommandMessage* command) {
ReturnValue_t result = owner->setHealth(HealthMessage::getHealth(message)); ReturnValue_t result = owner->setHealth(HealthMessage::getHealth(command));
if (message->getSender() == 0) { if (command->getSender() == MessageQueueIF::NO_QUEUE) {
return; return;
} }
CommandMessage reply; CommandMessage reply;
@ -85,12 +94,12 @@ void HealthHelper::handleSetHealthCommand(CommandMessage* message) {
HealthMessage::setHealthMessage(&reply, HealthMessage::setHealthMessage(&reply,
HealthMessage::REPLY_HEALTH_SET); HealthMessage::REPLY_HEALTH_SET);
} else { } else {
reply.setReplyRejected(result, message->getCommand()); reply.setReplyRejected(result, command->getCommand());
} }
if (MessageQueueSenderIF::sendMessage(message->getSender(), &reply, if (MessageQueueSenderIF::sendMessage(command->getSender(), &reply,
owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) { owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) {
sif::debug sif::debug << "HealthHelper::handleHealthCommand: sending health "
<< "HealthHelper::handleHealthCommand: sending health reply failed." "reply failed." << std::endl;
<< std::endl;
} }
} }

View File

@ -1,11 +1,13 @@
#ifndef HEALTHHELPER_H_ #ifndef FSFW_HEALTH_HEALTHHELPER_H_
#define HEALTHHELPER_H_ #define FSFW_HEALTH_HEALTHHELPER_H_
#include "../events/EventManagerIF.h"
#include "../events/EventReportingProxyIF.h"
#include "HasHealthIF.h" #include "HasHealthIF.h"
#include "HealthMessage.h" #include "HealthMessage.h"
#include "HealthTableIF.h" #include "HealthTableIF.h"
#include "../events/EventManagerIF.h"
#include "../events/EventReportingProxyIF.h"
#include "../ipc/MessageQueueIF.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
@ -27,8 +29,8 @@ public:
/** /**
* ctor * ctor
* *
* @param owner
* @param objectId the object Id to use when communication with the HealthTable * @param objectId the object Id to use when communication with the HealthTable
* @param useAsFrom id to use as from id when sending replies, can be set to 0
*/ */
HealthHelper(HasHealthIF* owner, object_id_t objectId); HealthHelper(HasHealthIF* owner, object_id_t objectId);
@ -39,12 +41,12 @@ public:
* *
* only valid after initialize() has been called * only valid after initialize() has been called
*/ */
HealthTableIF *healthTable; HealthTableIF *healthTable = nullptr;
/** /**
* Proxy to forward events. * Proxy to forward events.
*/ */
EventReportingProxyIF* eventSender; EventReportingProxyIF* eventSender = nullptr;
/** /**
* Try to handle the message. * Try to handle the message.
@ -100,7 +102,7 @@ private:
/** /**
* The Queue of the parent * The Queue of the parent
*/ */
MessageQueueId_t parentQueue; MessageQueueId_t parentQueue = MessageQueueIF::NO_QUEUE;
/** /**
* The one using the healthHelper. * The one using the healthHelper.
@ -117,4 +119,4 @@ private:
void handleSetHealthCommand(CommandMessage *message); void handleSetHealthCommand(CommandMessage *message);
}; };
#endif /* HEALTHHELPER_H_ */ #endif /* FSFW_HEALTH_HEALTHHELPER_H_ */

View File

@ -1,12 +1,5 @@
/** #ifndef FSFW_OBJECTMANAGER_OBJECTMANAGER_H_
* @file ObjectManager.h #define FSFW_OBJECTMANAGER_OBJECTMANAGER_H_
* @brief This file contains the implementation of the ObjectManager class
* @date 18.09.2012
* @author Bastian Baetz
*/
#ifndef OBJECTMANAGER_H_
#define OBJECTMANAGER_H_
#include "ObjectManagerIF.h" #include "ObjectManagerIF.h"
#include "SystemObjectIF.h" #include "SystemObjectIF.h"
@ -22,14 +15,15 @@
* most of the system initialization. * most of the system initialization.
* As the system is static after initialization, no new objects are * As the system is static after initialization, no new objects are
* created or inserted into the list after startup. * created or inserted into the list after startup.
* \ingroup system_objects * @ingroup system_objects
* @author Bastian Baetz
*/ */
class ObjectManager : public ObjectManagerIF { class ObjectManager : public ObjectManagerIF {
private: private:
//comparison? //comparison?
/** /**
* \brief This is the map of all initialized objects in the manager. * @brief This is the map of all initialized objects in the manager.
* \details Objects in the List must inherit the SystemObjectIF. * @details Objects in the List must inherit the SystemObjectIF.
*/ */
std::map<object_id_t, SystemObjectIF*> objectList; std::map<object_id_t, SystemObjectIF*> objectList;
protected: protected:
@ -54,7 +48,8 @@ public:
/** /**
* @brief In the class's destructor, all objects in the list are deleted. * @brief In the class's destructor, all objects in the list are deleted.
*/ */
//SHOULDDO: If, for some reason, deleting an ObjectManager instance is required, check if this works. // SHOULDDO: If, for some reason, deleting an ObjectManager instance is
// required, check if this works.
virtual ~ObjectManager( void ); virtual ~ObjectManager( void );
ReturnValue_t insert( object_id_t id, SystemObjectIF* object ); ReturnValue_t insert( object_id_t id, SystemObjectIF* object );
ReturnValue_t remove( object_id_t id ); ReturnValue_t remove( object_id_t id );
@ -64,4 +59,4 @@ public:
#endif /* OBJECTMANAGER_H_ */ #endif /* FSFW_OBJECTMANAGER_OBJECTMANAGER_H_ */

View File

@ -1,5 +1,5 @@
#ifndef FRAMEWORK_OBJECTMANAGER_OBJECTMANAGERIF_H_ #ifndef FSFW_OBJECTMANAGER_OBJECTMANAGERIF_H_
#define FRAMEWORK_OBJECTMANAGER_OBJECTMANAGERIF_H_ #define FSFW_OBJECTMANAGER_OBJECTMANAGERIF_H_
#include "frameworkObjects.h" #include "frameworkObjects.h"
#include "SystemObjectIF.h" #include "SystemObjectIF.h"
@ -21,7 +21,6 @@ public:
static constexpr uint8_t INTERFACE_ID = CLASS_ID::OBJECT_MANAGER_IF; static constexpr uint8_t INTERFACE_ID = CLASS_ID::OBJECT_MANAGER_IF;
static constexpr ReturnValue_t INSERTION_FAILED = MAKE_RETURN_CODE( 1 ); static constexpr ReturnValue_t INSERTION_FAILED = MAKE_RETURN_CODE( 1 );
static constexpr ReturnValue_t NOT_FOUND = MAKE_RETURN_CODE( 2 ); static constexpr ReturnValue_t NOT_FOUND = MAKE_RETURN_CODE( 2 );
static constexpr ReturnValue_t CHILD_INIT_FAILED = MAKE_RETURN_CODE( 3 ); //!< Can be used if the initialization of a SystemObject failed. static constexpr ReturnValue_t CHILD_INIT_FAILED = MAKE_RETURN_CODE( 3 ); //!< Can be used if the initialization of a SystemObject failed.
static constexpr ReturnValue_t INTERNAL_ERR_REPORTER_UNINIT = MAKE_RETURN_CODE( 4 ); static constexpr ReturnValue_t INTERNAL_ERR_REPORTER_UNINIT = MAKE_RETURN_CODE( 4 );
@ -80,6 +79,7 @@ public:
/** /**
* @brief This is the forward declaration of the global objectManager instance. * @brief This is the forward declaration of the global objectManager instance.
*/ */
// SHOULDDO: maybe put this in the glob namespace to explicitely mark it global?
extern ObjectManagerIF *objectManager; extern ObjectManagerIF *objectManager;
/*Documentation can be found in the class method declaration above.*/ /*Documentation can be found in the class method declaration above.*/

View File

@ -1,6 +1,6 @@
#include "../events/EventManagerIF.h"
#include "ObjectManager.h" #include "ObjectManager.h"
#include "SystemObject.h" #include "SystemObject.h"
#include "../events/EventManagerIF.h"
SystemObject::SystemObject(object_id_t setObjectId, bool doRegister) : SystemObject::SystemObject(object_id_t setObjectId, bool doRegister) :
objectId(setObjectId), registered(doRegister) { objectId(setObjectId), registered(doRegister) {

View File

@ -1,16 +1,9 @@
/** #ifndef FSFW_OBJECTMANAGER_SYSTEMOBJECT_H_
* @file SystemObject.h #define FSFW_OBJECTMANAGER_SYSTEMOBJECT_H_
* @brief This file contains the definition of the SystemObject class.
* @date 07.11.2012
* @author Ulrich Mohr
*/
#ifndef SYSTEMOBJECT_H_
#define SYSTEMOBJECT_H_
#include "SystemObjectIF.h"
#include "../events/Event.h" #include "../events/Event.h"
#include "../events/EventReportingProxyIF.h" #include "../events/EventReportingProxyIF.h"
#include "SystemObjectIF.h"
#include "../timemanager/Clock.h" #include "../timemanager/Clock.h"
/** /**
@ -20,7 +13,8 @@
* class that is announced to ObjectManager. It automatically includes * class that is announced to ObjectManager. It automatically includes
* itself (and therefore the inheriting class) in the object manager's * itself (and therefore the inheriting class) in the object manager's
* list. * list.
* \ingroup system_objects * @author Ulrich Mohr
* @ingroup system_objects
*/ */
class SystemObject: public SystemObjectIF { class SystemObject: public SystemObjectIF {
private: private:
@ -37,25 +31,28 @@ public:
* @param parameter1 * @param parameter1
* @param parameter2 * @param parameter2
*/ */
virtual void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0); virtual void triggerEvent(Event event, uint32_t parameter1 = 0,
uint32_t parameter2 = 0);
/** /**
* @brief The class's constructor. * @brief The class's constructor.
* @details In the constructor, the object id is set and the class is * @details In the constructor, the object id is set and the class is
* inserted in the object manager. * inserted in the object manager.
* @param setObjectId The id the object shall have. * @param setObjectId The id the object shall have.
* @param doRegister Determines if the object is registered in the global object manager. * @param doRegister Determines if the object is registered in
* the global object manager.
*/ */
SystemObject(object_id_t setObjectId, bool doRegister = true); SystemObject(object_id_t setObjectId, bool doRegister = true);
/** /**
* @brief On destruction, the object removes itself from the list. * @brief On destruction, the object removes itself from the list.
*/ */
virtual ~SystemObject(); virtual ~SystemObject();
object_id_t getObjectId() const; object_id_t getObjectId() const override;
virtual ReturnValue_t initialize(); virtual ReturnValue_t initialize() override;
virtual ReturnValue_t checkObjectConnections(); virtual ReturnValue_t checkObjectConnections();
virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const; virtual void forwardEvent(Event event, uint32_t parameter1 = 0,
uint32_t parameter2 = 0) const;
}; };
#endif /* SYSTEMOBJECT_H_ */ #endif /* FSFW_OBJECTMANAGER_SYSTEMOBJECT_H_ */

View File

@ -1,26 +1,19 @@
/** #ifndef FSFW_OBJECTMANAGER_SYSTEMOBJECTIF_H_
* @file SystemObjectIF.h #define FSFW_OBJECTMANAGER_SYSTEMOBJECTIF_H_
* @brief This file contains the definition of the SystemObjectIF interface.
* @date 18.09.2012
* @author Bastian Baetz
*/
#ifndef SYSTEMOBJECTIF_H_
#define SYSTEMOBJECTIF_H_
#include "../events/EventReportingProxyIF.h" #include "../events/EventReportingProxyIF.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include <stdint.h> #include <cstdint>
/** /**
* \defgroup system_objects Software System Object Management * @defgroup system_objects Software System Object Management
* The classes to create System Objects and classes to manage these are contained in this group. * The classes to create System Objects and classes to manage these are
* System Objects are software elements that can be controlled externally. They all have a unique * contained in this group. System Objects are software elements that can be
* object identifier. * controlled externally. They all have a unique object identifier.
*/ */
/** /**
* This is the typedef for object identifiers. * This is the typedef for object identifiers.
* \ingroup system_objects * @ingroup system_objects
*/ */
typedef uint32_t object_id_t; typedef uint32_t object_id_t;
@ -29,7 +22,8 @@ typedef uint32_t object_id_t;
* list. * list.
* It does not provide any method definitions, still it is required to * It does not provide any method definitions, still it is required to
* perform a type check with dynamic_cast. * perform a type check with dynamic_cast.
* \ingroup system_objects * @author Bastian Baetz
* @ingroup system_objects
*/ */
class SystemObjectIF : public EventReportingProxyIF { class SystemObjectIF : public EventReportingProxyIF {
public: public:
@ -41,24 +35,28 @@ public:
/** /**
* The empty virtual destructor as required for C++ interfaces. * The empty virtual destructor as required for C++ interfaces.
*/ */
virtual ~SystemObjectIF() { virtual ~SystemObjectIF() {}
}
/** /**
* Initializes all inter-object dependencies. * @brief Initializes the object.
* This is necessary to avoid circular dependencies of not-fully * There are initialization steps which can also be done in the constructor.
* initialized objects on start up. * However, there is no clean way to get a returnvalue from a constructor.
* @return - \c RETURN_OK in case the initialization was successful * Furthermore some components require other system object to be created
* - \c RETURN_FAILED otherwise * which might not have been built yet.
* Therefore, a two-step initialization resolves this problem and prevents
* circular dependencies of not-fully initialized objects on start up.
* @return - @c RETURN_OK in case the initialization was successful
* - @c RETURN_FAILED otherwise
*/ */
virtual ReturnValue_t initialize() = 0; virtual ReturnValue_t initialize() = 0;
/** /**
* Checks, if all object-object interconnections are satisfying for operation. * @brief Checks if all object-object interconnections are satisfying
* Some objects need certain other objects (or a certain number), to be registered as children. * for operation.
* These checks can be done in this method. * Some objects need certain other objects (or a certain number), to be
* @return - \c RETURN_OK in case the check was successful * registered as children. These checks can be done in this method.
* - \c any other code otherwise * @return - @c RETURN_OK in case the check was successful
* - @c any other code otherwise
*/ */
virtual ReturnValue_t checkObjectConnections() = 0; virtual ReturnValue_t checkObjectConnections() = 0;
}; };
#endif /* SYSTEMOBJECTIF_H_ */ #endif /* #ifndef FSFW_OBJECTMANAGER_SYSTEMOBJECTIF_H_ */

View File

@ -1,8 +1,15 @@
#ifndef FRAMEWORK_OBJECTMANAGER_FRAMEWORKOBJECTS_H_ #ifndef FSFW_OBJECTMANAGER_FRAMEWORKOBJECTS_H_
#define FRAMEWORK_OBJECTMANAGER_FRAMEWORKOBJECTS_H_ #define FSFW_OBJECTMANAGER_FRAMEWORKOBJECTS_H_
namespace objects { namespace objects {
enum framework_objects { enum framework_objects {
// Default verification reporter.
PUS_SERVICE_1 = 0x53000001,
PUS_SERVICE_2 = 0x53000002,
PUS_SERVICE_5 = 0x53000005,
PUS_SERVICE_8 = 0x53000008,
PUS_SERVICE_200 = 0x53000200,
//Generic IDs for IPC, modes, health, events //Generic IDs for IPC, modes, health, events
HEALTH_TABLE = 0x53010000, HEALTH_TABLE = 0x53010000,
// MODE_STORE = 0x53010100, // MODE_STORE = 0x53010100,
@ -12,10 +19,11 @@ enum framework_objects {
//IDs for PUS Packet Communication //IDs for PUS Packet Communication
TC_STORE = 0x534f0100, TC_STORE = 0x534f0100,
TM_STORE = 0x534f0200, TM_STORE = 0x534f0200,
NO_OBJECT = 0xFFFFFFFF NO_OBJECT = 0xFFFFFFFF
}; };
} }
#endif /* FRAMEWORK_OBJECTMANAGER_FRAMEWORKOBJECTS_H_ */ #endif /* FSFW_OBJECTMANAGER_FRAMEWORKOBJECTS_H_ */

View File

@ -1,95 +1,95 @@
#include "../../osal/FreeRTOS/BinSemaphUsingTask.h" #include "../../osal/FreeRTOS/BinSemaphUsingTask.h"
#include "../../osal/FreeRTOS/TaskManagement.h" #include "../../osal/FreeRTOS/TaskManagement.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() { BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() {
handle = TaskManagement::getCurrentTaskHandle(); handle = TaskManagement::getCurrentTaskHandle();
if(handle == nullptr) { if(handle == nullptr) {
sif::error << "Could not retrieve task handle. Please ensure the" sif::error << "Could not retrieve task handle. Please ensure the"
"constructor was called inside a task." << std::endl; "constructor was called inside a task." << std::endl;
} }
xTaskNotifyGive(handle); xTaskNotifyGive(handle);
} }
BinarySemaphoreUsingTask::~BinarySemaphoreUsingTask() { BinarySemaphoreUsingTask::~BinarySemaphoreUsingTask() {
// Clear notification value on destruction. // Clear notification value on destruction.
xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr);
} }
ReturnValue_t BinarySemaphoreUsingTask::acquire(TimeoutType timeoutType, ReturnValue_t BinarySemaphoreUsingTask::acquire(TimeoutType timeoutType,
uint32_t timeoutMs) { uint32_t timeoutMs) {
TickType_t timeout = 0; TickType_t timeout = 0;
if(timeoutType == TimeoutType::POLLING) { if(timeoutType == TimeoutType::POLLING) {
timeout = 0; timeout = 0;
} }
else if(timeoutType == TimeoutType::WAITING){ else if(timeoutType == TimeoutType::WAITING){
timeout = pdMS_TO_TICKS(timeoutMs); timeout = pdMS_TO_TICKS(timeoutMs);
} }
else { else {
timeout = portMAX_DELAY; timeout = portMAX_DELAY;
} }
return acquireWithTickTimeout(timeoutType, timeout); return acquireWithTickTimeout(timeoutType, timeout);
} }
ReturnValue_t BinarySemaphoreUsingTask::acquireWithTickTimeout( ReturnValue_t BinarySemaphoreUsingTask::acquireWithTickTimeout(
TimeoutType timeoutType, TickType_t timeoutTicks) { TimeoutType timeoutType, TickType_t timeoutTicks) {
BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks); BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks);
if (returncode == pdPASS) { if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
else { else {
return SemaphoreIF::SEMAPHORE_TIMEOUT; return SemaphoreIF::SEMAPHORE_TIMEOUT;
} }
} }
ReturnValue_t BinarySemaphoreUsingTask::release() { ReturnValue_t BinarySemaphoreUsingTask::release() {
return release(this->handle); return release(this->handle);
} }
ReturnValue_t BinarySemaphoreUsingTask::release( ReturnValue_t BinarySemaphoreUsingTask::release(
TaskHandle_t taskHandle) { TaskHandle_t taskHandle) {
if(getSemaphoreCounter(taskHandle) == 1) { if(getSemaphoreCounter(taskHandle) == 1) {
return SemaphoreIF::SEMAPHORE_NOT_OWNED; return SemaphoreIF::SEMAPHORE_NOT_OWNED;
} }
BaseType_t returncode = xTaskNotifyGive(taskHandle); BaseType_t returncode = xTaskNotifyGive(taskHandle);
if (returncode == pdPASS) { if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
else { else {
// This should never happen. // This should never happen.
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
TaskHandle_t BinarySemaphoreUsingTask::getTaskHandle() { TaskHandle_t BinarySemaphoreUsingTask::getTaskHandle() {
return handle; return handle;
} }
uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() const { uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() const {
return getSemaphoreCounter(this->handle); return getSemaphoreCounter(this->handle);
} }
uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter( uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter(
TaskHandle_t taskHandle) { TaskHandle_t taskHandle) {
uint32_t notificationValue; uint32_t notificationValue;
xTaskNotifyAndQuery(taskHandle, 0, eNoAction, &notificationValue); xTaskNotifyAndQuery(taskHandle, 0, eNoAction, &notificationValue);
return notificationValue; return notificationValue;
} }
// Be careful with the stack size here. This is called from an ISR! // Be careful with the stack size here. This is called from an ISR!
ReturnValue_t BinarySemaphoreUsingTask::releaseFromISR( ReturnValue_t BinarySemaphoreUsingTask::releaseFromISR(
TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) { TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) {
if(getSemaphoreCounterFromISR(taskHandle, higherPriorityTaskWoken) == 1) { if(getSemaphoreCounterFromISR(taskHandle, higherPriorityTaskWoken) == 1) {
return SemaphoreIF::SEMAPHORE_NOT_OWNED; return SemaphoreIF::SEMAPHORE_NOT_OWNED;
} }
vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken); vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR( uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR(
TaskHandle_t taskHandle, BaseType_t* higherPriorityTaskWoken) { TaskHandle_t taskHandle, BaseType_t* higherPriorityTaskWoken) {
uint32_t notificationValue = 0; uint32_t notificationValue = 0;
xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, &notificationValue, xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, &notificationValue,
higherPriorityTaskWoken); higherPriorityTaskWoken);
return notificationValue; return notificationValue;
} }

View File

@ -1,76 +1,76 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ #ifndef FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ #define FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_
#include "../../returnvalues/HasReturnvaluesIF.h" #include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/SemaphoreIF.h" #include "../../tasks/SemaphoreIF.h"
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/task.h> #include <freertos/task.h>
/** /**
* @brief Binary Semaphore implementation using the task notification value. * @brief Binary Semaphore implementation using the task notification value.
* The notification value should therefore not be used * The notification value should therefore not be used
* for other purposes. * for other purposes.
* @details * @details
* Additional information: https://www.freertos.org/RTOS-task-notifications.html * Additional information: https://www.freertos.org/RTOS-task-notifications.html
* and general semaphore documentation. * and general semaphore documentation.
*/ */
class BinarySemaphoreUsingTask: public SemaphoreIF, class BinarySemaphoreUsingTask: public SemaphoreIF,
public HasReturnvaluesIF { public HasReturnvaluesIF {
public: public:
static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF;
//! @brief Default ctor //! @brief Default ctor
BinarySemaphoreUsingTask(); BinarySemaphoreUsingTask();
//! @brief Default dtor //! @brief Default dtor
virtual~ BinarySemaphoreUsingTask(); virtual~ BinarySemaphoreUsingTask();
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
uint32_t timeoutMs = portMAX_DELAY) override; uint32_t timeoutMs = portMAX_DELAY) override;
ReturnValue_t release() override; ReturnValue_t release() override;
uint8_t getSemaphoreCounter() const override; uint8_t getSemaphoreCounter() const override;
static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle); static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle);
static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle, static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle,
BaseType_t* higherPriorityTaskWoken); BaseType_t* higherPriorityTaskWoken);
/** /**
* Same as acquire() with timeout in FreeRTOS ticks. * Same as acquire() with timeout in FreeRTOS ticks.
* @param timeoutTicks * @param timeoutTicks
* @return - @c RETURN_OK on success * @return - @c RETURN_OK on success
* - @c RETURN_FAILED on failure * - @c RETURN_FAILED on failure
*/ */
ReturnValue_t acquireWithTickTimeout( ReturnValue_t acquireWithTickTimeout(
TimeoutType timeoutType = TimeoutType::BLOCKING, TimeoutType timeoutType = TimeoutType::BLOCKING,
TickType_t timeoutTicks = portMAX_DELAY); TickType_t timeoutTicks = portMAX_DELAY);
/** /**
* Get handle to the task related to the semaphore. * Get handle to the task related to the semaphore.
* @return * @return
*/ */
TaskHandle_t getTaskHandle(); TaskHandle_t getTaskHandle();
/** /**
* Wrapper function to give back semaphore from handle * Wrapper function to give back semaphore from handle
* @param semaphore * @param semaphore
* @return - @c RETURN_OK on success * @return - @c RETURN_OK on success
* - @c RETURN_FAILED on failure * - @c RETURN_FAILED on failure
*/ */
static ReturnValue_t release(TaskHandle_t taskToNotify); static ReturnValue_t release(TaskHandle_t taskToNotify);
/** /**
* Wrapper function to give back semaphore from handle when called from an ISR * Wrapper function to give back semaphore from handle when called from an ISR
* @param semaphore * @param semaphore
* @param higherPriorityTaskWoken This will be set to pdPASS if a task with * @param higherPriorityTaskWoken This will be set to pdPASS if a task with
* a higher priority was unblocked. A context switch should be requested * a higher priority was unblocked. A context switch should be requested
* from an ISR if this is the case (see TaskManagement functions) * from an ISR if this is the case (see TaskManagement functions)
* @return - @c RETURN_OK on success * @return - @c RETURN_OK on success
* - @c RETURN_FAILED on failure * - @c RETURN_FAILED on failure
*/ */
static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify,
BaseType_t * higherPriorityTaskWoken); BaseType_t * higherPriorityTaskWoken);
protected: protected:
TaskHandle_t handle; TaskHandle_t handle;
}; };
#endif /* FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ */ #endif /* FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ */

View File

@ -1,108 +1,108 @@
#include "../../osal/FreeRTOS/BinarySemaphore.h" #include "../../osal/FreeRTOS/BinarySemaphore.h"
#include "../../osal/FreeRTOS/TaskManagement.h" #include "../../osal/FreeRTOS/TaskManagement.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
BinarySemaphore::BinarySemaphore() { BinarySemaphore::BinarySemaphore() {
handle = xSemaphoreCreateBinary(); handle = xSemaphoreCreateBinary();
if(handle == nullptr) { if(handle == nullptr) {
sif::error << "Semaphore: Binary semaph creation failure" << std::endl; sif::error << "Semaphore: Binary semaph creation failure" << std::endl;
} }
// Initiated semaphore must be given before it can be taken. // Initiated semaphore must be given before it can be taken.
xSemaphoreGive(handle); xSemaphoreGive(handle);
} }
BinarySemaphore::~BinarySemaphore() { BinarySemaphore::~BinarySemaphore() {
vSemaphoreDelete(handle); vSemaphoreDelete(handle);
} }
BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) {
handle = xSemaphoreCreateBinary(); handle = xSemaphoreCreateBinary();
if(handle == nullptr) { if(handle == nullptr) {
sif::error << "Binary semaphore creation failure" << std::endl; sif::error << "Binary semaphore creation failure" << std::endl;
} }
xSemaphoreGive(handle); xSemaphoreGive(handle);
} }
BinarySemaphore& BinarySemaphore::operator =( BinarySemaphore& BinarySemaphore::operator =(
BinarySemaphore&& s) { BinarySemaphore&& s) {
if(&s != this) { if(&s != this) {
handle = xSemaphoreCreateBinary(); handle = xSemaphoreCreateBinary();
if(handle == nullptr) { if(handle == nullptr) {
sif::error << "Binary semaphore creation failure" << std::endl; sif::error << "Binary semaphore creation failure" << std::endl;
} }
xSemaphoreGive(handle); xSemaphoreGive(handle);
} }
return *this; return *this;
} }
ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType, ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType,
uint32_t timeoutMs) { uint32_t timeoutMs) {
TickType_t timeout = 0; TickType_t timeout = 0;
if(timeoutType == TimeoutType::POLLING) { if(timeoutType == TimeoutType::POLLING) {
timeout = 0; timeout = 0;
} }
else if(timeoutType == TimeoutType::WAITING){ else if(timeoutType == TimeoutType::WAITING){
timeout = pdMS_TO_TICKS(timeoutMs); timeout = pdMS_TO_TICKS(timeoutMs);
} }
else { else {
timeout = portMAX_DELAY; timeout = portMAX_DELAY;
} }
return acquireWithTickTimeout(timeoutType, timeout); return acquireWithTickTimeout(timeoutType, timeout);
} }
ReturnValue_t BinarySemaphore::acquireWithTickTimeout(TimeoutType timeoutType, ReturnValue_t BinarySemaphore::acquireWithTickTimeout(TimeoutType timeoutType,
TickType_t timeoutTicks) { TickType_t timeoutTicks) {
if(handle == nullptr) { if(handle == nullptr) {
return SemaphoreIF::SEMAPHORE_INVALID; return SemaphoreIF::SEMAPHORE_INVALID;
} }
BaseType_t returncode = xSemaphoreTake(handle, timeoutTicks); BaseType_t returncode = xSemaphoreTake(handle, timeoutTicks);
if (returncode == pdPASS) { if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
else { else {
return SemaphoreIF::SEMAPHORE_TIMEOUT; return SemaphoreIF::SEMAPHORE_TIMEOUT;
} }
} }
ReturnValue_t BinarySemaphore::release() { ReturnValue_t BinarySemaphore::release() {
return release(handle); return release(handle);
} }
ReturnValue_t BinarySemaphore::release(SemaphoreHandle_t semaphore) { ReturnValue_t BinarySemaphore::release(SemaphoreHandle_t semaphore) {
if (semaphore == nullptr) { if (semaphore == nullptr) {
return SemaphoreIF::SEMAPHORE_INVALID; return SemaphoreIF::SEMAPHORE_INVALID;
} }
BaseType_t returncode = xSemaphoreGive(semaphore); BaseType_t returncode = xSemaphoreGive(semaphore);
if (returncode == pdPASS) { if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
else { else {
return SemaphoreIF::SEMAPHORE_NOT_OWNED; return SemaphoreIF::SEMAPHORE_NOT_OWNED;
} }
} }
uint8_t BinarySemaphore::getSemaphoreCounter() const { uint8_t BinarySemaphore::getSemaphoreCounter() const {
return uxSemaphoreGetCount(handle); return uxSemaphoreGetCount(handle);
} }
SemaphoreHandle_t BinarySemaphore::getSemaphore() { SemaphoreHandle_t BinarySemaphore::getSemaphore() {
return handle; return handle;
} }
// Be careful with the stack size here. This is called from an ISR! // Be careful with the stack size here. This is called from an ISR!
ReturnValue_t BinarySemaphore::releaseFromISR( ReturnValue_t BinarySemaphore::releaseFromISR(
SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) { SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) {
if (semaphore == nullptr) { if (semaphore == nullptr) {
return SemaphoreIF::SEMAPHORE_INVALID; return SemaphoreIF::SEMAPHORE_INVALID;
} }
BaseType_t returncode = xSemaphoreGiveFromISR(semaphore, BaseType_t returncode = xSemaphoreGiveFromISR(semaphore,
higherPriorityTaskWoken); higherPriorityTaskWoken);
if (returncode == pdPASS) { if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
else { else {
return SemaphoreIF::SEMAPHORE_NOT_OWNED; return SemaphoreIF::SEMAPHORE_NOT_OWNED;
} }
} }

View File

@ -1,107 +1,107 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ #ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_
#define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ #define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_
#include "../../returnvalues/HasReturnvaluesIF.h" #include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/SemaphoreIF.h" #include "../../tasks/SemaphoreIF.h"
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/semphr.h> #include <freertos/semphr.h>
/** /**
* @brief OS Tool to achieve synchronization of between tasks or between * @brief OS Tool to achieve synchronization of between tasks or between
* task and ISR. The default semaphore implementation creates a * task and ISR. The default semaphore implementation creates a
* binary semaphore, which can only be taken once. * binary semaphore, which can only be taken once.
* @details * @details
* Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html * Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html
* *
* Please note that if the semaphore implementation is only related to * Please note that if the semaphore implementation is only related to
* the synchronization of one task, the new task notifications can be used, * the synchronization of one task, the new task notifications can be used,
* also see the BinSemaphUsingTask and CountingSemaphUsingTask classes. * also see the BinSemaphUsingTask and CountingSemaphUsingTask classes.
* These use the task notification value instead of a queue and are * These use the task notification value instead of a queue and are
* faster and more efficient. * faster and more efficient.
* *
* @author R. Mueller * @author R. Mueller
* @ingroup osal * @ingroup osal
*/ */
class BinarySemaphore: public SemaphoreIF, class BinarySemaphore: public SemaphoreIF,
public HasReturnvaluesIF { public HasReturnvaluesIF {
public: public:
static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF;
//! @brief Default ctor //! @brief Default ctor
BinarySemaphore(); BinarySemaphore();
//! @brief Copy ctor, deleted explicitely. //! @brief Copy ctor, deleted explicitely.
BinarySemaphore(const BinarySemaphore&) = delete; BinarySemaphore(const BinarySemaphore&) = delete;
//! @brief Copy assignment, deleted explicitely. //! @brief Copy assignment, deleted explicitely.
BinarySemaphore& operator=(const BinarySemaphore&) = delete; BinarySemaphore& operator=(const BinarySemaphore&) = delete;
//! @brief Move ctor //! @brief Move ctor
BinarySemaphore (BinarySemaphore &&); BinarySemaphore (BinarySemaphore &&);
//! @brief Move assignment //! @brief Move assignment
BinarySemaphore & operator=(BinarySemaphore &&); BinarySemaphore & operator=(BinarySemaphore &&);
//! @brief Destructor //! @brief Destructor
virtual ~BinarySemaphore(); virtual ~BinarySemaphore();
uint8_t getSemaphoreCounter() const override; uint8_t getSemaphoreCounter() const override;
/** /**
* Take the binary semaphore. * Take the binary semaphore.
* If the semaphore has already been taken, the task will be blocked * If the semaphore has already been taken, the task will be blocked
* for a maximum of #timeoutMs or until the semaphore is given back, * for a maximum of #timeoutMs or until the semaphore is given back,
* for example by an ISR or another task. * for example by an ISR or another task.
* @param timeoutMs * @param timeoutMs
* @return -@c RETURN_OK on success * @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/ */
ReturnValue_t acquire(TimeoutType timeoutType = ReturnValue_t acquire(TimeoutType timeoutType =
TimeoutType::BLOCKING, uint32_t timeoutMs = portMAX_DELAY) override; TimeoutType::BLOCKING, uint32_t timeoutMs = portMAX_DELAY) override;
/** /**
* Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks.
* @param timeoutTicks * @param timeoutTicks
* @return -@c RETURN_OK on success * @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/ */
ReturnValue_t acquireWithTickTimeout(TimeoutType timeoutType = ReturnValue_t acquireWithTickTimeout(TimeoutType timeoutType =
TimeoutType::BLOCKING, TickType_t timeoutTicks = portMAX_DELAY); TimeoutType::BLOCKING, TickType_t timeoutTicks = portMAX_DELAY);
/** /**
* Release the binary semaphore. * Release the binary semaphore.
* @return -@c RETURN_OK on success * @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is
* already available. * already available.
*/ */
ReturnValue_t release() override; ReturnValue_t release() override;
/** /**
* Get Handle to the semaphore. * Get Handle to the semaphore.
* @return * @return
*/ */
SemaphoreHandle_t getSemaphore(); SemaphoreHandle_t getSemaphore();
/** /**
* Wrapper function to give back semaphore from handle * Wrapper function to give back semaphore from handle
* @param semaphore * @param semaphore
* @return -@c RETURN_OK on success * @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is
* already available. * already available.
*/ */
static ReturnValue_t release(SemaphoreHandle_t semaphore); static ReturnValue_t release(SemaphoreHandle_t semaphore);
/** /**
* Wrapper function to give back semaphore from handle when called from an ISR * Wrapper function to give back semaphore from handle when called from an ISR
* @param semaphore * @param semaphore
* @param higherPriorityTaskWoken This will be set to pdPASS if a task with * @param higherPriorityTaskWoken This will be set to pdPASS if a task with
* a higher priority was unblocked. A context switch from an ISR should * a higher priority was unblocked. A context switch from an ISR should
* then be requested (see TaskManagement functions) * then be requested (see TaskManagement functions)
* @return -@c RETURN_OK on success * @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is
* already available. * already available.
*/ */
static ReturnValue_t releaseFromISR(SemaphoreHandle_t semaphore, static ReturnValue_t releaseFromISR(SemaphoreHandle_t semaphore,
BaseType_t * higherPriorityTaskWoken); BaseType_t * higherPriorityTaskWoken);
protected: protected:
SemaphoreHandle_t handle; SemaphoreHandle_t handle;
}; };
#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ #endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */

View File

@ -1,114 +1,114 @@
#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" #include "../../osal/FreeRTOS/CountingSemaphUsingTask.h"
#include "../../osal/FreeRTOS/TaskManagement.h" #include "../../osal/FreeRTOS/TaskManagement.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount, CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount,
uint8_t initCount): maxCount(maxCount) { uint8_t initCount): maxCount(maxCount) {
if(initCount > maxCount) { if(initCount > maxCount) {
sif::error << "CountingSemaphoreUsingTask: Max count bigger than " sif::error << "CountingSemaphoreUsingTask: Max count bigger than "
"intial cout. Setting initial count to max count." << std::endl; "intial cout. Setting initial count to max count." << std::endl;
initCount = maxCount; initCount = maxCount;
} }
handle = TaskManagement::getCurrentTaskHandle(); handle = TaskManagement::getCurrentTaskHandle();
if(handle == nullptr) { if(handle == nullptr) {
sif::error << "CountingSemaphoreUsingTask: Could not retrieve task " sif::error << "CountingSemaphoreUsingTask: Could not retrieve task "
"handle. Please ensure the constructor was called inside a " "handle. Please ensure the constructor was called inside a "
"task." << std::endl; "task." << std::endl;
} }
uint32_t oldNotificationValue; uint32_t oldNotificationValue;
xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite,
&oldNotificationValue); &oldNotificationValue);
if(oldNotificationValue != 0) { if(oldNotificationValue != 0) {
sif::warning << "CountinSemaphoreUsingTask: Semaphore initiated but " sif::warning << "CountinSemaphoreUsingTask: Semaphore initiated but "
"current notification value is not 0. Please ensure the " "current notification value is not 0. Please ensure the "
"notification value is not used for other purposes!" << std::endl; "notification value is not used for other purposes!" << std::endl;
} }
for(int i = 0; i < initCount; i++) { for(int i = 0; i < initCount; i++) {
xTaskNotifyGive(handle); xTaskNotifyGive(handle);
} }
} }
CountingSemaphoreUsingTask::~CountingSemaphoreUsingTask() { CountingSemaphoreUsingTask::~CountingSemaphoreUsingTask() {
// Clear notification value on destruction. // Clear notification value on destruction.
// If this is not desired, don't call the destructor // If this is not desired, don't call the destructor
// (or implement a boolean which disables the reset) // (or implement a boolean which disables the reset)
xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr);
} }
ReturnValue_t CountingSemaphoreUsingTask::acquire(TimeoutType timeoutType, ReturnValue_t CountingSemaphoreUsingTask::acquire(TimeoutType timeoutType,
uint32_t timeoutMs) { uint32_t timeoutMs) {
TickType_t timeout = 0; TickType_t timeout = 0;
if(timeoutType == TimeoutType::POLLING) { if(timeoutType == TimeoutType::POLLING) {
timeout = 0; timeout = 0;
} }
else if(timeoutType == TimeoutType::WAITING){ else if(timeoutType == TimeoutType::WAITING){
timeout = pdMS_TO_TICKS(timeoutMs); timeout = pdMS_TO_TICKS(timeoutMs);
} }
else { else {
timeout = portMAX_DELAY; timeout = portMAX_DELAY;
} }
return acquireWithTickTimeout(timeoutType, timeout); return acquireWithTickTimeout(timeoutType, timeout);
} }
ReturnValue_t CountingSemaphoreUsingTask::acquireWithTickTimeout( ReturnValue_t CountingSemaphoreUsingTask::acquireWithTickTimeout(
TimeoutType timeoutType, TickType_t timeoutTicks) { TimeoutType timeoutType, TickType_t timeoutTicks) {
// Decrement notfication value without resetting it. // Decrement notfication value without resetting it.
BaseType_t oldCount = ulTaskNotifyTake(pdFALSE, timeoutTicks); BaseType_t oldCount = ulTaskNotifyTake(pdFALSE, timeoutTicks);
if (getSemaphoreCounter() == oldCount - 1) { if (getSemaphoreCounter() == oldCount - 1) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
else { else {
return SemaphoreIF::SEMAPHORE_TIMEOUT; return SemaphoreIF::SEMAPHORE_TIMEOUT;
} }
} }
ReturnValue_t CountingSemaphoreUsingTask::release() { ReturnValue_t CountingSemaphoreUsingTask::release() {
if(getSemaphoreCounter() == maxCount) { if(getSemaphoreCounter() == maxCount) {
return SemaphoreIF::SEMAPHORE_NOT_OWNED; return SemaphoreIF::SEMAPHORE_NOT_OWNED;
} }
return release(handle); return release(handle);
} }
ReturnValue_t CountingSemaphoreUsingTask::release( ReturnValue_t CountingSemaphoreUsingTask::release(
TaskHandle_t taskToNotify) { TaskHandle_t taskToNotify) {
BaseType_t returncode = xTaskNotifyGive(taskToNotify); BaseType_t returncode = xTaskNotifyGive(taskToNotify);
if (returncode == pdPASS) { if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
else { else {
// This should never happen. // This should never happen.
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() const { uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() const {
uint32_t notificationValue = 0; uint32_t notificationValue = 0;
xTaskNotifyAndQuery(handle, 0, eNoAction, &notificationValue); xTaskNotifyAndQuery(handle, 0, eNoAction, &notificationValue);
return notificationValue; return notificationValue;
} }
TaskHandle_t CountingSemaphoreUsingTask::getTaskHandle() { TaskHandle_t CountingSemaphoreUsingTask::getTaskHandle() {
return handle; return handle;
} }
ReturnValue_t CountingSemaphoreUsingTask::releaseFromISR( ReturnValue_t CountingSemaphoreUsingTask::releaseFromISR(
TaskHandle_t taskToNotify, BaseType_t* higherPriorityTaskWoken) { TaskHandle_t taskToNotify, BaseType_t* higherPriorityTaskWoken) {
vTaskNotifyGiveFromISR(taskToNotify, higherPriorityTaskWoken); vTaskNotifyGiveFromISR(taskToNotify, higherPriorityTaskWoken);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
uint8_t CountingSemaphoreUsingTask::getSemaphoreCounterFromISR( uint8_t CountingSemaphoreUsingTask::getSemaphoreCounterFromISR(
TaskHandle_t task, BaseType_t* higherPriorityTaskWoken) { TaskHandle_t task, BaseType_t* higherPriorityTaskWoken) {
uint32_t notificationValue; uint32_t notificationValue;
xTaskNotifyAndQueryFromISR(task, 0, eNoAction, &notificationValue, xTaskNotifyAndQueryFromISR(task, 0, eNoAction, &notificationValue,
higherPriorityTaskWoken); higherPriorityTaskWoken);
return notificationValue; return notificationValue;
} }
uint8_t CountingSemaphoreUsingTask::getMaxCount() const { uint8_t CountingSemaphoreUsingTask::getMaxCount() const {
return maxCount; return maxCount;
} }

View File

@ -1,102 +1,102 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ #ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ #define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_
#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" #include "../../osal/FreeRTOS/CountingSemaphUsingTask.h"
#include "../../tasks/SemaphoreIF.h" #include "../../tasks/SemaphoreIF.h"
extern "C" { extern "C" {
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/task.h> #include <freertos/task.h>
} }
/** /**
* @brief Couting Semaphore implementation which uses the notification value * @brief Couting Semaphore implementation which uses the notification value
* of the task. The notification value should therefore not be used * of the task. The notification value should therefore not be used
* for other purposes. * for other purposes.
* @details * @details
* Additional information: https://www.freertos.org/RTOS-task-notifications.html * Additional information: https://www.freertos.org/RTOS-task-notifications.html
* and general semaphore documentation. * and general semaphore documentation.
*/ */
class CountingSemaphoreUsingTask: public SemaphoreIF { class CountingSemaphoreUsingTask: public SemaphoreIF {
public: public:
CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount); CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount);
virtual ~CountingSemaphoreUsingTask(); virtual ~CountingSemaphoreUsingTask();
/** /**
* Acquire the counting semaphore. * Acquire the counting semaphore.
* If no semaphores are available, the task will be blocked * If no semaphores are available, the task will be blocked
* for a maximum of #timeoutMs or until one is given back, * for a maximum of #timeoutMs or until one is given back,
* for example by an ISR or another task. * for example by an ISR or another task.
* @param timeoutMs * @param timeoutMs
* @return -@c RETURN_OK on success * @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/ */
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
uint32_t timeoutMs = portMAX_DELAY) override; uint32_t timeoutMs = portMAX_DELAY) override;
/** /**
* Release a semaphore, increasing the number of available counting * Release a semaphore, increasing the number of available counting
* semaphores up to the #maxCount value. * semaphores up to the #maxCount value.
* @return -@c RETURN_OK on success * @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are
* already available. * already available.
*/ */
ReturnValue_t release() override; ReturnValue_t release() override;
uint8_t getSemaphoreCounter() const override; uint8_t getSemaphoreCounter() const override;
/** /**
* Get the semaphore counter from an ISR. * Get the semaphore counter from an ISR.
* @param task * @param task
* @param higherPriorityTaskWoken This will be set to pdPASS if a task with * @param higherPriorityTaskWoken This will be set to pdPASS if a task with
* a higher priority was unblocked. A context switch should be requested * a higher priority was unblocked. A context switch should be requested
* from an ISR if this is the case (see TaskManagement functions) * from an ISR if this is the case (see TaskManagement functions)
* @return * @return
*/ */
static uint8_t getSemaphoreCounterFromISR(TaskHandle_t task, static uint8_t getSemaphoreCounterFromISR(TaskHandle_t task,
BaseType_t* higherPriorityTaskWoken); BaseType_t* higherPriorityTaskWoken);
/** /**
* Acquire with a timeout value in ticks * Acquire with a timeout value in ticks
* @param timeoutTicks * @param timeoutTicks
* @return -@c RETURN_OK on success * @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/ */
ReturnValue_t acquireWithTickTimeout( ReturnValue_t acquireWithTickTimeout(
TimeoutType timeoutType = TimeoutType::BLOCKING, TimeoutType timeoutType = TimeoutType::BLOCKING,
TickType_t timeoutTicks = portMAX_DELAY); TickType_t timeoutTicks = portMAX_DELAY);
/** /**
* Get handle to the task related to the semaphore. * Get handle to the task related to the semaphore.
* @return * @return
*/ */
TaskHandle_t getTaskHandle(); TaskHandle_t getTaskHandle();
/** /**
* Release semaphore of task by supplying task handle * Release semaphore of task by supplying task handle
* @param taskToNotify * @param taskToNotify
* @return -@c RETURN_OK on success * @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are
* already available. * already available.
*/ */
static ReturnValue_t release(TaskHandle_t taskToNotify); static ReturnValue_t release(TaskHandle_t taskToNotify);
/** /**
* Release seamphore of a task from an ISR. * Release seamphore of a task from an ISR.
* @param taskToNotify * @param taskToNotify
* @param higherPriorityTaskWoken This will be set to pdPASS if a task with * @param higherPriorityTaskWoken This will be set to pdPASS if a task with
* a higher priority was unblocked. A context switch should be requested * a higher priority was unblocked. A context switch should be requested
* from an ISR if this is the case (see TaskManagement functions) * from an ISR if this is the case (see TaskManagement functions)
* @return -@c RETURN_OK on success * @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are
* already available. * already available.
*/ */
static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify,
BaseType_t* higherPriorityTaskWoken); BaseType_t* higherPriorityTaskWoken);
uint8_t getMaxCount() const; uint8_t getMaxCount() const;
private: private:
TaskHandle_t handle; TaskHandle_t handle;
const uint8_t maxCount; const uint8_t maxCount;
}; };
#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ */ #endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ */

View File

@ -1,43 +1,43 @@
#include "../../osal/FreeRTOS/CountingSemaphore.h" #include "../../osal/FreeRTOS/CountingSemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../osal/FreeRTOS/TaskManagement.h" #include "../../osal/FreeRTOS/TaskManagement.h"
#include <freertos/semphr.h> #include <freertos/semphr.h>
// Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in // Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in
// free FreeRTOSConfig.h file. // free FreeRTOSConfig.h file.
CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount):
maxCount(maxCount), initCount(initCount) { maxCount(maxCount), initCount(initCount) {
if(initCount > maxCount) { if(initCount > maxCount) {
sif::error << "CountingSemaphoreUsingTask: Max count bigger than " sif::error << "CountingSemaphoreUsingTask: Max count bigger than "
"intial cout. Setting initial count to max count." << std::endl; "intial cout. Setting initial count to max count." << std::endl;
initCount = maxCount; initCount = maxCount;
} }
handle = xSemaphoreCreateCounting(maxCount, initCount); handle = xSemaphoreCreateCounting(maxCount, initCount);
if(handle == nullptr) { if(handle == nullptr) {
sif::error << "CountingSemaphore: Creation failure" << std::endl; sif::error << "CountingSemaphore: Creation failure" << std::endl;
} }
} }
CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): CountingSemaphore::CountingSemaphore(CountingSemaphore&& other):
maxCount(other.maxCount), initCount(other.initCount) { maxCount(other.maxCount), initCount(other.initCount) {
handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); handle = xSemaphoreCreateCounting(other.maxCount, other.initCount);
if(handle == nullptr) { if(handle == nullptr) {
sif::error << "CountingSemaphore: Creation failure" << std::endl; sif::error << "CountingSemaphore: Creation failure" << std::endl;
} }
} }
CountingSemaphore& CountingSemaphore::operator =( CountingSemaphore& CountingSemaphore::operator =(
CountingSemaphore&& other) { CountingSemaphore&& other) {
handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); handle = xSemaphoreCreateCounting(other.maxCount, other.initCount);
if(handle == nullptr) { if(handle == nullptr) {
sif::error << "CountingSemaphore: Creation failure" << std::endl; sif::error << "CountingSemaphore: Creation failure" << std::endl;
} }
return * this; return * this;
} }
uint8_t CountingSemaphore::getMaxCount() const { uint8_t CountingSemaphore::getMaxCount() const {
return maxCount; return maxCount;
} }

View File

@ -1,34 +1,34 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ #ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_
#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ #define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_
#include "../../osal/FreeRTOS/BinarySemaphore.h" #include "../../osal/FreeRTOS/BinarySemaphore.h"
/** /**
* @brief Counting semaphores, which can be acquire more than once. * @brief Counting semaphores, which can be acquire more than once.
* @details * @details
* See: https://www.freertos.org/CreateCounting.html * See: https://www.freertos.org/CreateCounting.html
* API of counting semaphores is almost identical to binary semaphores, * API of counting semaphores is almost identical to binary semaphores,
* so we just inherit from binary semaphore and provide the respective * so we just inherit from binary semaphore and provide the respective
* constructors. * constructors.
*/ */
class CountingSemaphore: public BinarySemaphore { class CountingSemaphore: public BinarySemaphore {
public: public:
CountingSemaphore(const uint8_t maxCount, uint8_t initCount); CountingSemaphore(const uint8_t maxCount, uint8_t initCount);
//! @brief Copy ctor, disabled //! @brief Copy ctor, disabled
CountingSemaphore(const CountingSemaphore&) = delete; CountingSemaphore(const CountingSemaphore&) = delete;
//! @brief Copy assignment, disabled //! @brief Copy assignment, disabled
CountingSemaphore& operator=(const CountingSemaphore&) = delete; CountingSemaphore& operator=(const CountingSemaphore&) = delete;
//! @brief Move ctor //! @brief Move ctor
CountingSemaphore (CountingSemaphore &&); CountingSemaphore (CountingSemaphore &&);
//! @brief Move assignment //! @brief Move assignment
CountingSemaphore & operator=(CountingSemaphore &&); CountingSemaphore & operator=(CountingSemaphore &&);
/* Same API as binary semaphore otherwise. acquire() can be called /* Same API as binary semaphore otherwise. acquire() can be called
* until there are not semaphores left and release() can be called * until there are not semaphores left and release() can be called
* until maxCount is reached. */ * until maxCount is reached. */
uint8_t getMaxCount() const; uint8_t getMaxCount() const;
private: private:
const uint8_t maxCount; const uint8_t maxCount;
uint8_t initCount = 0; uint8_t initCount = 0;
}; };
#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ #endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */

View File

@ -64,6 +64,11 @@ ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) {
void PeriodicTask::taskFunctionality() { void PeriodicTask::taskFunctionality() {
TickType_t xLastWakeTime; TickType_t xLastWakeTime;
const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.); const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.);
for (auto const &object: objectList) {
object->initializeAfterTaskCreation();
}
/* The xLastWakeTime variable needs to be initialized with the current tick /* The xLastWakeTime variable needs to be initialized with the current tick
count. Note that this is the only time the variable is written to count. Note that this is the only time the variable is written to
explicitly. After this assignment, xLastWakeTime is updated automatically explicitly. After this assignment, xLastWakeTime is updated automatically

View File

@ -1,11 +1,10 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_ #ifndef FSFW_OSAL_FREERTOS_PERIODICTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_ #define FSFW_OSAL_FREERTOS_PERIODICTASK_H_
#include "FreeRTOSTaskIF.h"
#include "../../objectmanager/ObjectManagerIF.h" #include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/PeriodicTaskIF.h" #include "../../tasks/PeriodicTaskIF.h"
#include "../../tasks/Typedef.h" #include "../../tasks/Typedef.h"
#include "FreeRTOSTaskIF.h"
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/task.h> #include <freertos/task.h>
@ -24,7 +23,6 @@ public:
/** /**
* Keep in Mind that you need to call before this vTaskStartScheduler()! * Keep in Mind that you need to call before this vTaskStartScheduler()!
* A lot of task parameters are set in "FreeRTOSConfig.h". * A lot of task parameters are set in "FreeRTOSConfig.h".
* TODO: why does this need to be called before vTaskStartScheduler?
* @details * @details
* The class is initialized without allocated objects. * The class is initialized without allocated objects.
* These need to be added with #addComponent. * These need to be added with #addComponent.
@ -125,4 +123,4 @@ protected:
void handleMissedDeadline(); void handleMissedDeadline();
}; };
#endif /* PERIODICTASK_H_ */ #endif /* FSFW_OSAL_FREERTOS_PERIODICTASK_H_ */

View File

@ -1,59 +1,59 @@
#include "../../osal/FreeRTOS/BinarySemaphore.h" #include "../../osal/FreeRTOS/BinarySemaphore.h"
#include "../../osal/FreeRTOS/BinSemaphUsingTask.h" #include "../../osal/FreeRTOS/BinSemaphUsingTask.h"
#include "../../osal/FreeRTOS/CountingSemaphore.h" #include "../../osal/FreeRTOS/CountingSemaphore.h"
#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" #include "../../osal/FreeRTOS/CountingSemaphUsingTask.h"
#include "../../tasks/SemaphoreFactory.h" #include "../../tasks/SemaphoreFactory.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr;
static const uint32_t USE_REGULAR_SEMAPHORES = 0; static const uint32_t USE_REGULAR_SEMAPHORES = 0;
static const uint32_t USE_TASK_NOTIFICATIONS = 1; static const uint32_t USE_TASK_NOTIFICATIONS = 1;
SemaphoreFactory::SemaphoreFactory() { SemaphoreFactory::SemaphoreFactory() {
} }
SemaphoreFactory::~SemaphoreFactory() { SemaphoreFactory::~SemaphoreFactory() {
delete factoryInstance; delete factoryInstance;
} }
SemaphoreFactory* SemaphoreFactory::instance() { SemaphoreFactory* SemaphoreFactory::instance() {
if (factoryInstance == nullptr){ if (factoryInstance == nullptr){
factoryInstance = new SemaphoreFactory(); factoryInstance = new SemaphoreFactory();
} }
return SemaphoreFactory::factoryInstance; return SemaphoreFactory::factoryInstance;
} }
SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) { SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) {
if(argument == USE_REGULAR_SEMAPHORES) { if(argument == USE_REGULAR_SEMAPHORES) {
return new BinarySemaphore(); return new BinarySemaphore();
} }
else if(argument == USE_TASK_NOTIFICATIONS) { else if(argument == USE_TASK_NOTIFICATIONS) {
return new BinarySemaphoreUsingTask(); return new BinarySemaphoreUsingTask();
} }
else { else {
sif::warning << "SemaphoreFactory: Invalid argument, return regular" sif::warning << "SemaphoreFactory: Invalid argument, return regular"
"binary semaphore" << std::endl; "binary semaphore" << std::endl;
return new BinarySemaphore(); return new BinarySemaphore();
} }
} }
SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount, SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount,
uint8_t initCount, uint32_t argument) { uint8_t initCount, uint32_t argument) {
if(argument == USE_REGULAR_SEMAPHORES) { if(argument == USE_REGULAR_SEMAPHORES) {
return new CountingSemaphore(maxCount, initCount); return new CountingSemaphore(maxCount, initCount);
} }
else if(argument == USE_TASK_NOTIFICATIONS) { else if(argument == USE_TASK_NOTIFICATIONS) {
return new CountingSemaphoreUsingTask(maxCount, initCount); return new CountingSemaphoreUsingTask(maxCount, initCount);
} }
else { else {
sif::warning << "SemaphoreFactory: Invalid argument, return regular" sif::warning << "SemaphoreFactory: Invalid argument, return regular"
"binary semaphore" << std::endl; "binary semaphore" << std::endl;
return new CountingSemaphore(maxCount, initCount); return new CountingSemaphore(maxCount, initCount);
} }
} }
void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) {
delete semaphore; delete semaphore;
} }

View File

@ -1,24 +1,24 @@
#include "../../osal/FreeRTOS/TaskManagement.h" #include "../../osal/FreeRTOS/TaskManagement.h"
void TaskManagement::vRequestContextSwitchFromTask() { void TaskManagement::vRequestContextSwitchFromTask() {
vTaskDelay(0); vTaskDelay(0);
} }
void TaskManagement::requestContextSwitch( void TaskManagement::requestContextSwitch(
CallContext callContext = CallContext::TASK) { CallContext callContext = CallContext::TASK) {
if(callContext == CallContext::ISR) { if(callContext == CallContext::ISR) {
// This function depends on the partmacro.h definition for the specific device // This function depends on the partmacro.h definition for the specific device
vRequestContextSwitchFromISR(); vRequestContextSwitchFromISR();
} else { } else {
vRequestContextSwitchFromTask(); vRequestContextSwitchFromTask();
} }
} }
TaskHandle_t TaskManagement::getCurrentTaskHandle() { TaskHandle_t TaskManagement::getCurrentTaskHandle() {
return xTaskGetCurrentTaskHandle(); return xTaskGetCurrentTaskHandle();
} }
size_t TaskManagement::getTaskStackHighWatermark( size_t TaskManagement::getTaskStackHighWatermark(
TaskHandle_t task) { TaskHandle_t task) {
return uxTaskGetStackHighWaterMark(task) * sizeof(StackType_t); return uxTaskGetStackHighWaterMark(task) * sizeof(StackType_t);
} }

View File

@ -1,64 +1,64 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ #ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_
#define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ #define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_
#include "../../returnvalues/HasReturnvaluesIF.h" #include "../../returnvalues/HasReturnvaluesIF.h"
extern "C" { extern "C" {
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/task.h> #include <freertos/task.h>
} }
#include <cstdint> #include <cstdint>
/** /**
* Architecture dependant portmacro.h function call. * Architecture dependant portmacro.h function call.
* Should be implemented in bsp. * Should be implemented in bsp.
*/ */
extern void vRequestContextSwitchFromISR(); extern void vRequestContextSwitchFromISR();
/*! /*!
* Used by functions to tell if they are being called from * Used by functions to tell if they are being called from
* within an ISR or from a regular task. This is required because FreeRTOS * within an ISR or from a regular task. This is required because FreeRTOS
* has different functions for handling semaphores and messages from within * has different functions for handling semaphores and messages from within
* an ISR and task. * an ISR and task.
*/ */
enum class CallContext { enum class CallContext {
TASK = 0x00,//!< task_context TASK = 0x00,//!< task_context
ISR = 0xFF //!< isr_context ISR = 0xFF //!< isr_context
}; };
class TaskManagement { class TaskManagement {
public: public:
/** /**
* @brief In this function, a function dependant on the portmacro.h header * @brief In this function, a function dependant on the portmacro.h header
* function calls to request a context switch can be specified. * function calls to request a context switch can be specified.
* This can be used if sending to the queue from an ISR caused a task * This can be used if sending to the queue from an ISR caused a task
* to unblock and a context switch is required. * to unblock and a context switch is required.
*/ */
static void requestContextSwitch(CallContext callContext); static void requestContextSwitch(CallContext callContext);
/** /**
* If task preemption in FreeRTOS is disabled, a context switch * If task preemption in FreeRTOS is disabled, a context switch
* can be requested manually by calling this function. * can be requested manually by calling this function.
*/ */
static void vRequestContextSwitchFromTask(void); static void vRequestContextSwitchFromTask(void);
/** /**
* @return The current task handle * @return The current task handle
*/ */
static TaskHandle_t getCurrentTaskHandle(); static TaskHandle_t getCurrentTaskHandle();
/** /**
* Get returns the minimum amount of remaining stack space in words * Get returns the minimum amount of remaining stack space in words
* that was a available to the task since the task started executing. * that was a available to the task since the task started executing.
* Please note that the actual value in bytes depends * Please note that the actual value in bytes depends
* on the stack depth type. * on the stack depth type.
* E.g. on a 32 bit machine, a value of 200 means 800 bytes. * E.g. on a 32 bit machine, a value of 200 means 800 bytes.
* @return Smallest value of stack remaining since the task was started in * @return Smallest value of stack remaining since the task was started in
* words. * words.
*/ */
static size_t getTaskStackHighWatermark( static size_t getTaskStackHighWatermark(
TaskHandle_t task = nullptr); TaskHandle_t task = nullptr);
}; };
#endif /* FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ */ #endif /* FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ */

227
osal/host/Clock.cpp Normal file
View File

@ -0,0 +1,227 @@
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../timemanager/Clock.h"
#include <chrono>
#if defined(WIN32)
#include <windows.h>
#elif defined(LINUX)
#include <fstream>
#endif
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = NULL;
using SystemClock = std::chrono::system_clock;
uint32_t Clock::getTicksPerSecond(void){
sif::warning << "Clock::getTicksPerSecond: not implemented yet" << std::endl;
return 0;
//return CLOCKS_PER_SEC;
//uint32_t ticks = sysconf(_SC_CLK_TCK);
//return ticks;
}
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
// do some magic with chrono
sif::warning << "Clock::setClock: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::setClock(const timeval* time) {
// do some magic with chrono
#if defined(WIN32)
return HasReturnvaluesIF::RETURN_OK;
#elif defined(LINUX)
return HasReturnvaluesIF::RETURN_OK;
#else
#endif
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t Clock::getClock_timeval(timeval* time) {
#if defined(WIN32)
auto now = std::chrono::system_clock::now();
auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto epoch = now.time_since_epoch();
time->tv_sec = std::chrono::duration_cast<std::chrono::seconds>(epoch).count();
auto fraction = now - secondsChrono;
time->tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
fraction).count();
return HasReturnvaluesIF::RETURN_OK;
#elif defined(LINUX)
timespec timeUnix;
int status = clock_gettime(CLOCK_REALTIME,&timeUnix);
if(status!=0){
return HasReturnvaluesIF::RETURN_FAILED;
}
time->tv_sec = timeUnix.tv_sec;
time->tv_usec = timeUnix.tv_nsec / 1000.0;
return HasReturnvaluesIF::RETURN_OK;
#else
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
#endif
}
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
// do some magic with chrono
sif::warning << "Clock::gerClock_usecs: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
timeval Clock::getUptime() {
timeval timeval;
#if defined(WIN32)
auto uptime = std::chrono::milliseconds(GetTickCount64());
auto secondsChrono = std::chrono::duration_cast<std::chrono::seconds>(uptime);
timeval.tv_sec = secondsChrono.count();
auto fraction = uptime - secondsChrono;
timeval.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
fraction).count();
#elif defined(LINUX)
double uptimeSeconds;
if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds)
{
// value is rounded down automatically
timeval.tv_sec = uptimeSeconds;
timeval.tv_usec = uptimeSeconds *(double) 1e6 - (timeval.tv_sec *1e6);
}
#else
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
#endif
return timeval;
}
ReturnValue_t Clock::getUptime(timeval* uptime) {
*uptime = getUptime();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
timeval uptime = getUptime();
*uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
// do some magic with chrono (C++20!)
// Right now, the library doesn't have the new features yet.
// so we work around that for now.
auto now = SystemClock::now();
auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto fraction = now - seconds;
time_t tt = SystemClock::to_time_t(now);
struct tm* timeInfo;
timeInfo = gmtime(&tt);
time->year = timeInfo->tm_year + 1900;
time->month = timeInfo->tm_mon+1;
time->day = timeInfo->tm_mday;
time->hour = timeInfo->tm_hour;
time->minute = timeInfo->tm_min;
time->second = timeInfo->tm_sec;
auto usecond = std::chrono::duration_cast<std::chrono::microseconds>(fraction);
time->usecond = usecond.count();
//sif::warning << "Clock::getDateAndTime: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
timeval* to) {
struct tm time_tm;
time_tm.tm_year = from->year - 1900;
time_tm.tm_mon = from->month - 1;
time_tm.tm_mday = from->day;
time_tm.tm_hour = from->hour;
time_tm.tm_min = from->minute;
time_tm.tm_sec = from->second;
time_t seconds = mktime(&time_tm);
to->tv_sec = seconds;
to->tv_usec = from->usecond;
//Fails in 2038..
return HasReturnvaluesIF::RETURN_OK;
sif::warning << "Clock::convertTimeBla: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24.
/ 3600.;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
//SHOULDDO: works not for dates in the past (might have less leap seconds)
if (timeMutex == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
uint16_t leapSeconds;
ReturnValue_t result = getLeapSeconds(&leapSeconds);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
timeval leapSeconds_timeval = { 0, 0 };
leapSeconds_timeval.tv_sec = leapSeconds;
//initial offset between UTC and TAI
timeval UTCtoTAI1972 = { 10, 0 };
timeval TAItoTT = { 32, 184000 };
*tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
leapSeconds = leapSeconds_;
result = timeMutex->unlockMutex();
return result;
}
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if(timeMutex == nullptr){
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
*leapSeconds_ = leapSeconds;
result = timeMutex->unlockMutex();
return result;
}
ReturnValue_t Clock::checkOrCreateClockMutex(){
if(timeMutex == nullptr){
MutexFactory* mutexFactory = MutexFactory::instance();
if (mutexFactory == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
timeMutex = mutexFactory->createMutex();
if (timeMutex == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -0,0 +1,197 @@
#include "../../osal/host/FixedTimeslotTask.h"
#include "../../ipc/MutexFactory.h"
#include "../../osal/host/Mutex.h"
#include "../../osal/host/FixedTimeslotTask.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../tasks/ExecutableObjectIF.h"
#include <thread>
#include <chrono>
#if defined(WIN32)
#include <windows.h>
#elif defined(LINUX)
#include <pthread.h>
#endif
FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()) :
started(false), pollingSeqTable(setPeriod*1000), taskName(name),
period(setPeriod), deadlineMissedFunc(setDeadlineMissedFunc) {
// It is propably possible to set task priorities by using the native
// task handles for Windows / Linux
mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this);
#if defined(WIN32)
/* List of possible priority classes:
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/
* nf-processthreadsapi-setpriorityclass
* And respective thread priority numbers:
* https://docs.microsoft.com/en-us/windows/
* win32/procthread/scheduling-priorities */
int result = SetPriorityClass(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
ABOVE_NORMAL_PRIORITY_CLASS);
if(result != 0) {
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
}
result = SetThreadPriority(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
THREAD_PRIORITY_NORMAL);
if(result != 0) {
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
}
#elif defined(LINUX)
// we can just copy and paste the code from linux here.
#endif
}
FixedTimeslotTask::~FixedTimeslotTask(void) {
//Do not delete objects, we were responsible for ptrs only.
terminateThread = true;
if(mainThread.joinable()) {
mainThread.join();
}
delete this;
}
void FixedTimeslotTask::taskEntryPoint(void* argument) {
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
if (not originalTask->started) {
// we have to suspend/block here until the task is started.
// if semaphores are implemented, use them here.
std::unique_lock<std::mutex> lock(initMutex);
initCondition.wait(lock);
}
this->taskFunctionality();
sif::debug << "FixedTimeslotTask::taskEntryPoint: "
"Returned from taskFunctionality." << std::endl;
}
ReturnValue_t FixedTimeslotTask::startTask() {
started = true;
// Notify task to start.
std::lock_guard<std::mutex> lock(initMutex);
initCondition.notify_one();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
return HasReturnvaluesIF::RETURN_OK;
}
void FixedTimeslotTask::taskFunctionality() {
pollingSeqTable.intializeSequenceAfterTaskCreation();
// A local iterator for the Polling Sequence Table is created to
// find the start time for the first entry.
auto slotListIter = pollingSeqTable.current;
// Get start time for first entry.
chron_ms interval(slotListIter->pollingTimeMs);
auto currentStartTime {
std::chrono::duration_cast<chron_ms>(
std::chrono::system_clock::now().time_since_epoch())
};
if(interval.count() > 0) {
delayForInterval(&currentStartTime, interval);
}
/* Enter the loop that defines the task behavior. */
for (;;) {
if(terminateThread.load()) {
break;
}
//The component for this slot is executed and the next one is chosen.
this->pollingSeqTable.executeAndAdvance();
if (not pollingSeqTable.slotFollowsImmediately()) {
// we need to wait before executing the current slot
//this gives us the time to wait:
interval = chron_ms(this->pollingSeqTable.getIntervalToPreviousSlotMs());
delayForInterval(&currentStartTime, interval);
//TODO deadline missed check
}
}
}
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) {
ExecutableObjectIF* executableObject = objectManager->
get<ExecutableObjectIF>(componentId);
if (executableObject != nullptr) {
pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep,
executableObject, this);
return HasReturnvaluesIF::RETURN_OK;
}
sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t FixedTimeslotTask::checkSequence() const {
return pollingSeqTable.checkSequence();
}
uint32_t FixedTimeslotTask::getPeriodMs() const {
return period * 1000;
}
bool FixedTimeslotTask::delayForInterval(chron_ms * previousWakeTimeMs,
const chron_ms interval) {
bool shouldDelay = false;
//Get current wakeup time
auto currentStartTime =
std::chrono::duration_cast<chron_ms>(
std::chrono::system_clock::now().time_since_epoch());
/* Generate the tick time at which the task wants to wake. */
auto nextTimeToWake_ms = (*previousWakeTimeMs) + interval;
if (currentStartTime < *previousWakeTimeMs) {
/* The tick count has overflowed since this function was
lasted called. In this case the only time we should ever
actually delay is if the wake time has also overflowed,
and the wake time is greater than the tick time. When this
is the case it is as if neither time had overflowed. */
if ((nextTimeToWake_ms < *previousWakeTimeMs)
&& (nextTimeToWake_ms > currentStartTime)) {
shouldDelay = true;
}
} else {
/* The tick time has not overflowed. In this case we will
delay if either the wake time has overflowed, and/or the
tick time is less than the wake time. */
if ((nextTimeToWake_ms < *previousWakeTimeMs)
|| (nextTimeToWake_ms > currentStartTime)) {
shouldDelay = true;
}
}
/* Update the wake time ready for the next call. */
(*previousWakeTimeMs) = nextTimeToWake_ms;
if (shouldDelay) {
auto sleepTime = std::chrono::duration_cast<chron_ms>(
nextTimeToWake_ms - currentStartTime);
std::this_thread::sleep_for(sleepTime);
return true;
}
//We are shifting the time in case the deadline was missed like rtems
(*previousWakeTimeMs) = currentStartTime;
return false;
}

View File

@ -0,0 +1,130 @@
#ifndef FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_
#define FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h"
#include "../../tasks/Typedef.h"
#include <vector>
#include <thread>
#include <condition_variable>
#include <atomic>
class ExecutableObjectIF;
/**
* @brief This class represents a task for periodic activities with multiple
* steps and strict timeslot requirements for these steps.
* @details
* @ingroup task_handling
*/
class FixedTimeslotTask: public FixedTimeslotTaskIF {
public:
/**
* @brief Standard constructor of the class.
* @details
* The class is initialized without allocated objects. These need to be
* added with #addComponent.
* @param priority
* @param stack_size
* @param setPeriod
* @param setDeadlineMissedFunc
* The function pointer to the deadline missed function that shall be
* assigned.
*/
FixedTimeslotTask(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.
*/
virtual ~FixedTimeslotTask(void);
/**
* @brief The method to start the task.
* @details The method starts the task with the respective system call.
* Entry point is the taskEntryPoint method described below.
* The address of the task object is passed as an argument
* to the system call.
*/
ReturnValue_t startTask(void);
/**
* Add timeslot to the polling sequence table.
* @param componentId
* @param slotTimeMs
* @param executionStep
* @return
*/
ReturnValue_t addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep);
ReturnValue_t checkSequence() const override;
uint32_t getPeriodMs() const;
ReturnValue_t sleepFor(uint32_t ms);
protected:
using chron_ms = std::chrono::milliseconds;
bool started;
//!< Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList;
std::thread mainThread;
std::atomic<bool> terminateThread = false;
//! Polling sequence table which contains the object to execute
//! and information like the timeslots and the passed execution step.
FixedSlotSequence pollingSeqTable;
std::condition_variable initCondition;
std::mutex initMutex;
std::string taskName;
/**
* @brief The period of the task.
* @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.
*/
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.
* @param A pointer to the task object itself is passed as argument.
*/
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. On missing the deadline, the deadlineMissedFunction is executed.
*/
void taskFunctionality(void);
bool delayForInterval(chron_ms * previousWakeTimeMs,
const chron_ms interval);
};
#endif /* FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ */

159
osal/host/MessageQueue.cpp Normal file
View File

@ -0,0 +1,159 @@
#include "MessageQueue.h"
#include "QueueMapManager.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexHelper.h"
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
messageSize(maxMessageSize), messageDepth(messageDepth) {
queueLock = MutexFactory::instance()->createMutex();
auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "MessageQueue::MessageQueue:"
<< " Could not be created" << std::endl;
}
}
MessageQueue::~MessageQueue() {
MutexFactory::instance()->deleteMutex(queueLock);
}
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
}
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
return sendToDefaultFrom(message, this->getId());
}
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault);
}
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
if (this->lastPartner != 0) {
return sendMessageFrom(this->lastPartner, message, this->getId());
} else {
return MessageQueueIF::NO_REPLY_PARTNER;
}
}
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
return sendMessageFromMessageQueue(sendTo, message, sentFrom,
ignoreFault);
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message);
if(status == HasReturnvaluesIF::RETURN_OK) {
*receivedFrom = this->lastPartner;
}
return status;
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
if(messageQueue.empty()) {
return MessageQueueIF::EMPTY;
}
// not sure this will work..
//*message = std::move(messageQueue.front());
MutexHelper mutexLock(queueLock, MutexIF::TimeoutType::WAITING, 20);
MessageQueueMessage* currentMessage = &messageQueue.front();
std::copy(currentMessage->getBuffer(),
currentMessage->getBuffer() + messageSize, message->getBuffer());
messageQueue.pop();
// The last partner is the first uint32_t field in the message
this->lastPartner = message->getSender();
return HasReturnvaluesIF::RETURN_OK;
}
MessageQueueId_t MessageQueue::getLastPartner() const {
return lastPartner;
}
ReturnValue_t MessageQueue::flush(uint32_t* count) {
*count = messageQueue.size();
// Clears the queue.
messageQueue = std::queue<MessageQueueMessage>();
return HasReturnvaluesIF::RETURN_OK;
}
MessageQueueId_t MessageQueue::getId() const {
return mqId;
}
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
defaultDestinationSet = true;
this->defaultDestination = defaultDestination;
}
MessageQueueId_t MessageQueue::getDefaultDestination() const {
return defaultDestination;
}
bool MessageQueue::isDefaultDestinationSet() const {
return defaultDestinationSet;
}
// static core function to send messages.
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
if(message->getMessageSize() > message->getMaximumMessageSize()) {
// Actually, this should never happen or an error will be emitted
// in MessageQueueMessage.
// But I will still return a failure here.
return HasReturnvaluesIF::RETURN_FAILED;
}
MessageQueue* targetQueue = dynamic_cast<MessageQueue*>(
QueueMapManager::instance()->getMessageQueue(sendTo));
if(targetQueue == nullptr) {
if(not ignoreFault) {
InternalErrorReporterIF* internalErrorReporter =
objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter != nullptr) {
internalErrorReporter->queueMessageNotSent();
}
}
// TODO: Better returnvalue
return HasReturnvaluesIF::RETURN_FAILED;
}
if(targetQueue->messageQueue.size() < targetQueue->messageDepth) {
MutexHelper mutexLock(targetQueue->queueLock,
MutexIF::TimeoutType::WAITING, 20);
// not ideal, works for now though.
MessageQueueMessage* mqmMessage =
dynamic_cast<MessageQueueMessage*>(message);
if(message != nullptr) {
targetQueue->messageQueue.push(*mqmMessage);
}
else {
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message"
"is not MessageQueueMessage!" << std::endl;
}
}
else {
return MessageQueueIF::FULL;
}
message->setSender(sentFrom);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t MessageQueue::lockQueue(MutexIF::TimeoutType timeoutType,
dur_millis_t lockTimeout) {
return queueLock->lockMutex(timeoutType, lockTimeout);
}
ReturnValue_t MessageQueue::unlockQueue() {
return queueLock->unlockMutex();
}

231
osal/host/MessageQueue.h Normal file
View File

@ -0,0 +1,231 @@
#ifndef FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_
#define FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_
#include "../../internalError/InternalErrorReporterIF.h"
#include "../../ipc/MessageQueueIF.h"
#include "../../ipc/MessageQueueMessage.h"
#include "../../ipc/MutexIF.h"
#include "../../timemanager/Clock.h"
#include <queue>
#include <memory>
/**
* @brief This class manages sending and receiving of
* message queue messages.
* @details
* Message queues are used to pass asynchronous messages between processes.
* They work like post boxes, where all incoming messages are stored in FIFO
* order. This class creates a new receiving queue and provides methods to fetch
* received messages. Being a child of MessageQueueSender, this class also
* provides methods to send a message to a user-defined or a default destination.
* In addition it also provides a reply method to answer to the queue it
* received its last message from.
*
* The MessageQueue should be used as "post box" for a single owning object.
* So all message queue communication is "n-to-one".
* For creating the queue, as well as sending and receiving messages, the class
* makes use of the operating system calls provided.
*
* Please keep in mind that FreeRTOS offers different calls for message queue
* operations if called from an ISR.
* For now, the system context needs to be switched manually.
* @ingroup osal
* @ingroup message_queue
*/
class MessageQueue : public MessageQueueIF {
friend class MessageQueueSenderIF;
public:
/**
* @brief The constructor initializes and configures the message queue.
* @details
* By making use of the according operating system call, a message queue is
* created and initialized. The message depth - the maximum number of
* messages to be buffered - may be set with the help of a parameter,
* whereas the message size is automatically set to the maximum message
* queue message size. The operating system sets the message queue id, or
* in case of failure, it is set to zero.
* @param message_depth
* The number of messages to be buffered before passing an error to the
* sender. Default is three.
* @param max_message_size
* With this parameter, the maximum message size can be adjusted.
* This should be left default.
*/
MessageQueue(size_t messageDepth = 3,
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
/** Copying message queues forbidden */
MessageQueue(const MessageQueue&) = delete;
MessageQueue& operator=(const MessageQueue&) = delete;
/**
* @brief The destructor deletes the formerly created message queue.
* @details This is accomplished by using the delete call provided
* by the operating system.
*/
virtual ~MessageQueue();
/**
* @brief This operation sends a message to the given destination.
* @details It directly uses the sendMessage call of the MessageQueueSender
* parent, but passes its queue id as "sentFrom" parameter.
* @param sendTo This parameter specifies the message queue id of the
* destination message queue.
* @param message A pointer to a previously created message, which is sent.
* @param ignoreFault If set to true, the internal software fault counter
* is not incremented if queue is full.
*/
ReturnValue_t sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, bool ignoreFault = false) override;
/**
* @brief This operation sends a message to the default destination.
* @details As in the sendMessage method, this function uses the
* sendToDefault call of the MessageQueueSender parent class and adds its
* queue id as "sentFrom" information.
* @param message A pointer to a previously created message, which is sent.
*/
ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
/**
* @brief This operation sends a message to the last communication partner.
* @details This operation simplifies answering an incoming message by using
* the stored lastPartner information as destination. If there was no
* message received yet (i.e. lastPartner is zero), an error code is returned.
* @param message A pointer to a previously created message, which is sent.
*/
ReturnValue_t reply(MessageQueueMessageIF* message) override;
/**
* @brief With the sendMessage call, a queue message is sent to a
* receiving queue.
* @details
* This method takes the message provided, adds the sentFrom information and
* passes it on to the destination provided with an operating system call.
* The OS's return value is returned.
* @param sendTo This parameter specifies the message queue id to send
* the message to.
* @param message This is a pointer to a previously created message,
* which is sent.
* @param sentFrom The sentFrom information can be set to inject the
* sender's queue id into the message. This variable is set to zero by
* default.
* @param ignoreFault If set to true, the internal software fault counter
* is not incremented if queue is full.
*/
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false) override;
/**
* @brief The sendToDefault method sends a queue message to the default
* destination.
* @details
* In all other aspects, it works identical to the sendMessage method.
* @param message This is a pointer to a previously created message,
* which is sent.
* @param sentFrom The sentFrom information can be set to inject the
* sender's queue id into the message. This variable is set to zero by
* default.
*/
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false) override;
/**
* @brief This function reads available messages from the message queue
* and returns the sender.
* @details
* It works identically to the other receiveMessage call, but in addition
* returns the sender's queue id.
* @param message A pointer to a message in which the received data is stored.
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
*/
ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t *receivedFrom) override;
/**
* @brief This function reads available messages from the message queue.
* @details
* If data is available it is stored in the passed message pointer.
* The message's original content is overwritten and the sendFrom
* information is stored in the lastPartner attribute. Else, the lastPartner
* information remains untouched, the message's content is cleared and the
* function returns immediately.
* @param message A pointer to a message in which the received data is stored.
*/
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
/**
* Deletes all pending messages in the queue.
* @param count The number of flushed messages.
* @return RETURN_OK on success.
*/
ReturnValue_t flush(uint32_t* count) override;
/**
* @brief This method returns the message queue id of the last
* communication partner.
*/
MessageQueueId_t getLastPartner() const override;
/**
* @brief This method returns the message queue id of this class's
* message queue.
*/
MessageQueueId_t getId() const override;
/**
* @brief This method is a simple setter for the default destination.
*/
void setDefaultDestination(MessageQueueId_t defaultDestination) override;
/**
* @brief This method is a simple getter for the default destination.
*/
MessageQueueId_t getDefaultDestination() const override;
bool isDefaultDestinationSet() const override;
ReturnValue_t lockQueue(MutexIF::TimeoutType timeoutType,
dur_millis_t lockTimeout);
ReturnValue_t unlockQueue();
protected:
/**
* @brief Implementation to be called from any send Call within
* MessageQueue and MessageQueueSenderIF.
* @details
* This method takes the message provided, adds the sentFrom information and
* passes it on to the destination provided with an operating system call.
* The OS's return value is returned.
* @param sendTo
* This parameter specifies the message queue id to send the message to.
* @param message
* This is a pointer to a previously created message, which is sent.
* @param sentFrom
* The sentFrom information can be set to inject the sender's queue id into
* the message. This variable is set to zero by default.
* @param ignoreFault
* If set to true, the internal software fault counter is not incremented
* if queue is full.
* @param context Specify whether call is made from task or from an ISR.
*/
static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault=false);
//static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
private:
std::queue<MessageQueueMessage> messageQueue;
/**
* @brief The class stores the queue id it got assigned.
* If initialization fails, the queue id is set to zero.
*/
MessageQueueId_t mqId = 0;
size_t messageSize = 0;
size_t messageDepth = 0;
MutexIF* queueLock;
bool defaultDestinationSet = false;
MessageQueueId_t defaultDestination = 0;
MessageQueueId_t lastPartner = 0;
};
#endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */

39
osal/host/Mutex.cpp Normal file
View File

@ -0,0 +1,39 @@
#include "Mutex.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
Mutex::Mutex() {}
ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, uint32_t timeoutMs) {
if(timeoutMs == MutexIF::BLOCKING) {
mutex.lock();
locked = true;
return HasReturnvaluesIF::RETURN_OK;
}
else if(timeoutMs == MutexIF::POLLING) {
if(mutex.try_lock()) {
locked = true;
return HasReturnvaluesIF::RETURN_OK;
}
}
else if(timeoutMs > MutexIF::POLLING){
auto chronoMs = std::chrono::milliseconds(timeoutMs);
if(mutex.try_lock_for(chronoMs)) {
locked = true;
return HasReturnvaluesIF::RETURN_OK;
}
}
return MutexIF::MUTEX_TIMEOUT;
}
ReturnValue_t Mutex::unlockMutex() {
if(not locked) {
return MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX;
}
mutex.unlock();
locked = false;
return HasReturnvaluesIF::RETURN_OK;
}
std::timed_mutex* Mutex::getMutexHandle() {
return &mutex;
}

29
osal/host/Mutex.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef FSFW_OSAL_HOSTED_MUTEX_H_
#define FSFW_OSAL_HOSTED_MUTEX_H_
#include "../../ipc/MutexIF.h"
#include <mutex>
/**
* @brief OS component to implement MUTual EXclusion
*
* @details
* Mutexes are binary semaphores which include a priority inheritance mechanism.
* Documentation: https://www.freertos.org/Real-time-embedded-RTOS-mutexes.html
* @ingroup osal
*/
class Mutex : public MutexIF {
public:
Mutex();
ReturnValue_t lockMutex(TimeoutType timeoutType =
TimeoutType::BLOCKING, uint32_t timeoutMs = 0) override;
ReturnValue_t unlockMutex() override;
std::timed_mutex* getMutexHandle();
private:
bool locked = false;
std::timed_mutex mutex;
};
#endif /* FSFW_OSAL_HOSTED_MUTEX_H_ */

View File

@ -0,0 +1,28 @@
#include "../../ipc/MutexFactory.h"
#include "../../osal/host/Mutex.h"
//TODO: Different variant than the lazy loading in QueueFactory.
//What's better and why? -> one is on heap the other on bss/data
//MutexFactory* MutexFactory::factoryInstance = new MutexFactory();
MutexFactory* MutexFactory::factoryInstance = nullptr;
MutexFactory::MutexFactory() {
}
MutexFactory::~MutexFactory() {
}
MutexFactory* MutexFactory::instance() {
if (factoryInstance == nullptr){
factoryInstance = new MutexFactory();
}
return MutexFactory::factoryInstance;
}
MutexIF* MutexFactory::createMutex() {
return new Mutex();
}
void MutexFactory::deleteMutex(MutexIF* mutex) {
delete mutex;
}

176
osal/host/PeriodicTask.cpp Normal file
View File

@ -0,0 +1,176 @@
#include "Mutex.h"
#include "PeriodicTask.h"
#include "../../ipc/MutexFactory.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../tasks/ExecutableObjectIF.h"
#include <thread>
#include <chrono>
#if defined(WIN32)
#include <windows.h>
#elif defined(LINUX)
#include <pthread.h>
#endif
PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()) :
started(false), taskName(name), period(setPeriod),
deadlineMissedFunc(setDeadlineMissedFunc) {
// It is propably possible to set task priorities by using the native
// task handles for Windows / Linux
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this);
#if defined(WIN32)
/* List of possible priority classes:
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/
* nf-processthreadsapi-setpriorityclass
* And respective thread priority numbers:
* https://docs.microsoft.com/en-us/windows/
* win32/procthread/scheduling-priorities */
int result = SetPriorityClass(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
ABOVE_NORMAL_PRIORITY_CLASS);
if(result != 0) {
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
}
result = SetThreadPriority(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
THREAD_PRIORITY_NORMAL);
if(result != 0) {
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
}
#elif defined(LINUX)
// we can just copy and paste the code from linux here.
#endif
}
PeriodicTask::~PeriodicTask(void) {
//Do not delete objects, we were responsible for ptrs only.
terminateThread = true;
if(mainThread.joinable()) {
mainThread.join();
}
delete this;
}
void PeriodicTask::taskEntryPoint(void* argument) {
PeriodicTask *originalTask(reinterpret_cast<PeriodicTask*>(argument));
if (not originalTask->started) {
// we have to suspend/block here until the task is started.
// if semaphores are implemented, use them here.
std::unique_lock<std::mutex> lock(initMutex);
initCondition.wait(lock);
}
this->taskFunctionality();
sif::debug << "PeriodicTask::taskEntryPoint: "
"Returned from taskFunctionality." << std::endl;
}
ReturnValue_t PeriodicTask::startTask() {
started = true;
// Notify task to start.
std::lock_guard<std::mutex> lock(initMutex);
initCondition.notify_one();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) {
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
return HasReturnvaluesIF::RETURN_OK;
}
void PeriodicTask::taskFunctionality() {
std::chrono::milliseconds periodChrono(static_cast<uint32_t>(period*1000));
auto currentStartTime {
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
};
auto nextStartTime{ currentStartTime };
/* Enter the loop that defines the task behavior. */
for (;;) {
if(terminateThread.load()) {
break;
}
for (ObjectList::iterator it = objectList.begin();
it != objectList.end(); ++it) {
(*it)->performOperation();
}
if(not delayForInterval(&currentStartTime, periodChrono)) {
sif::warning << "PeriodicTask: " << taskName <<
" missed deadline!\n" << std::flush;
if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}
}
}
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object);
if (newObject == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
objectList.push_back(newObject);
return HasReturnvaluesIF::RETURN_OK;
}
uint32_t PeriodicTask::getPeriodMs() const {
return period * 1000;
}
bool PeriodicTask::delayForInterval(chron_ms* previousWakeTimeMs,
const chron_ms interval) {
bool shouldDelay = false;
//Get current wakeup time
auto currentStartTime =
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch());
/* Generate the tick time at which the task wants to wake. */
auto nextTimeToWake_ms = (*previousWakeTimeMs) + interval;
if (currentStartTime < *previousWakeTimeMs) {
/* The tick count has overflowed since this function was
lasted called. In this case the only time we should ever
actually delay is if the wake time has also overflowed,
and the wake time is greater than the tick time. When this
is the case it is as if neither time had overflowed. */
if ((nextTimeToWake_ms < *previousWakeTimeMs)
&& (nextTimeToWake_ms > currentStartTime)) {
shouldDelay = true;
}
} else {
/* The tick time has not overflowed. In this case we will
delay if either the wake time has overflowed, and/or the
tick time is less than the wake time. */
if ((nextTimeToWake_ms < *previousWakeTimeMs)
|| (nextTimeToWake_ms > currentStartTime)) {
shouldDelay = true;
}
}
/* Update the wake time ready for the next call. */
(*previousWakeTimeMs) = nextTimeToWake_ms;
if (shouldDelay) {
auto sleepTime = std::chrono::duration_cast<std::chrono::milliseconds>(
nextTimeToWake_ms - currentStartTime);
std::this_thread::sleep_for(sleepTime);
return true;
}
//We are shifting the time in case the deadline was missed like rtems
(*previousWakeTimeMs) = currentStartTime;
return false;
}

123
osal/host/PeriodicTask.h Normal file
View File

@ -0,0 +1,123 @@
#ifndef FRAMEWORK_OSAL_HOST_PERIODICTASK_H_
#define FRAMEWORK_OSAL_HOST_PERIODICTASK_H_
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/PeriodicTaskIF.h"
#include "../../tasks/Typedef.h"
#include <vector>
#include <thread>
#include <condition_variable>
#include <atomic>
class ExecutableObjectIF;
/**
* @brief This class represents a specialized task for
* periodic activities of multiple objects.
* @details
*
* @ingroup task_handling
*/
class PeriodicTask: public PeriodicTaskIF {
public:
/**
* @brief Standard constructor of the class.
* @details
* The class is initialized without allocated objects. These need to be
* added with #addComponent.
* @param priority
* @param stack_size
* @param setPeriod
* @param setDeadlineMissedFunc
* The function pointer to the deadline missed function that shall be
* assigned.
*/
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.
*/
virtual ~PeriodicTask(void);
/**
* @brief The method to start the task.
* @details The method starts the task with the respective system call.
* Entry point is the taskEntryPoint method described below.
* The address of the task object is passed as an argument
* to the system call.
*/
ReturnValue_t startTask(void);
/**
* 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
* -@c RETURN_OK on success
* -@c RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(object_id_t object);
uint32_t getPeriodMs() const;
ReturnValue_t sleepFor(uint32_t ms);
protected:
using chron_ms = std::chrono::milliseconds;
bool started;
//!< Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList;
std::thread mainThread;
std::atomic<bool> terminateThread = false;
/**
* @brief This attribute holds a list of objects to be executed.
*/
ObjectList objectList;
std::condition_variable initCondition;
std::mutex initMutex;
std::string taskName;
/**
* @brief The period of the task.
* @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.
*/
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.
* @param A pointer to the task object itself is passed as argument.
*/
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. On missing the deadline, the deadlineMissedFunction is executed.
*/
void taskFunctionality(void);
bool delayForInterval(chron_ms * previousWakeTimeMs,
const chron_ms interval);
};
#endif /* PERIODICTASK_H_ */

View File

@ -0,0 +1,41 @@
#include "../../ipc/QueueFactory.h"
#include "../../osal/host/MessageQueue.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include <cstring>
QueueFactory* QueueFactory::factoryInstance = nullptr;
ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
return MessageQueue::sendMessageFromMessageQueue(sendTo,message,
sentFrom,ignoreFault);
return HasReturnvaluesIF::RETURN_OK;
}
QueueFactory* QueueFactory::instance() {
if (factoryInstance == nullptr) {
factoryInstance = new QueueFactory;
}
return factoryInstance;
}
QueueFactory::QueueFactory() {
}
QueueFactory::~QueueFactory() {
}
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth,
size_t maxMessageSize) {
// A thread-safe queue can be implemented by using a combination
// of std::queue and std::mutex. This uses dynamic memory allocation
// which could be alleviated by using a custom allocator, external library
// (etl::queue) or simply using std::queue, we're on a host machine anyway.
return new MessageQueue(messageDepth, maxMessageSize);
}
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) {
delete queue;
}

View File

@ -0,0 +1,52 @@
#include "QueueMapManager.h"
#include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexHelper.h"
QueueMapManager* QueueMapManager::mqManagerInstance = nullptr;
QueueMapManager::QueueMapManager() {
mapLock = MutexFactory::instance()->createMutex();
}
QueueMapManager* QueueMapManager::instance() {
if (mqManagerInstance == nullptr){
mqManagerInstance = new QueueMapManager();
}
return QueueMapManager::mqManagerInstance;
}
ReturnValue_t QueueMapManager::addMessageQueue(
MessageQueueIF* queueToInsert, MessageQueueId_t* id) {
// Not thread-safe, but it is assumed all message queues are created
// at software initialization now. If this is to be made thread-safe in
// the future, it propably would be sufficient to lock the increment
// operation here
uint32_t currentId = queueCounter++;
auto returnPair = queueMap.emplace(currentId, queueToInsert);
if(not returnPair.second) {
// this should never happen for the atomic variable.
sif::error << "QueueMapManager: This ID is already inside the map!"
<< std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
if (id != nullptr) {
*id = currentId;
}
return HasReturnvaluesIF::RETURN_OK;
}
MessageQueueIF* QueueMapManager::getMessageQueue(
MessageQueueId_t messageQueueId) const {
MutexHelper(mapLock, MutexIF::TimeoutType::WAITING, 50);
auto queueIter = queueMap.find(messageQueueId);
if(queueIter != queueMap.end()) {
return queueIter->second;
}
else {
sif::warning << "QueueMapManager::getQueueHandle: The ID" <<
messageQueueId << " does not exists in the map" << std::endl;
return nullptr;
}
}

View File

@ -0,0 +1,47 @@
#ifndef FSFW_OSAL_HOST_QUEUEMAPMANAGER_H_
#define FSFW_OSAL_HOST_QUEUEMAPMANAGER_H_
#include "../../ipc/MessageQueueSenderIF.h"
#include "../../osal/host/MessageQueue.h"
#include <unordered_map>
#include <atomic>
using QueueMap = std::unordered_map<MessageQueueId_t, MessageQueueIF*>;
/**
* An internal map to map message queue IDs to message queues.
* This propably should be a singleton..
*/
class QueueMapManager {
public:
//! Returns the single instance of SemaphoreFactory.
static QueueMapManager* instance();
/**
* Insert a message queue into the map and returns a message queue ID
* @param queue The message queue to insert.
* @param id The passed value will be set unless a nullptr is passed
* @return
*/
ReturnValue_t addMessageQueue(MessageQueueIF* queue, MessageQueueId_t*
id = nullptr);
/**
* Get the message queue handle by providing a message queue ID.
* @param messageQueueId
* @return
*/
MessageQueueIF* getMessageQueue(MessageQueueId_t messageQueueId) const;
private:
//! External instantiation is forbidden.
QueueMapManager();
uint32_t queueCounter = 1;
MutexIF* mapLock;
QueueMap queueMap;
static QueueMapManager* mqManagerInstance;
};
#endif /* FSFW_OSAL_HOST_QUEUEMAPMANAGER_H_ */

View File

@ -0,0 +1,39 @@
#include "../../tasks/SemaphoreFactory.h"
#include "../../osal/linux/BinarySemaphore.h"
#include "../../osal/linux/CountingSemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr;
SemaphoreFactory::SemaphoreFactory() {
}
SemaphoreFactory::~SemaphoreFactory() {
delete factoryInstance;
}
SemaphoreFactory* SemaphoreFactory::instance() {
if (factoryInstance == nullptr){
factoryInstance = new SemaphoreFactory();
}
return SemaphoreFactory::factoryInstance;
}
SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) {
// Just gonna wait for full C++20 for now.
sif::error << "SemaphoreFactory: Binary Semaphore not implemented yet."
" Returning nullptr!\n" << std::flush;
return nullptr;
}
SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount,
uint8_t initCount, uint32_t arguments) {
// Just gonna wait for full C++20 for now.
sif::error << "SemaphoreFactory: Counting Semaphore not implemented yet."
" Returning nullptr!\n" << std::flush;
return nullptr;
}
void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) {
delete semaphore;
}

51
osal/host/TaskFactory.cpp Normal file
View File

@ -0,0 +1,51 @@
#include "../../osal/host/FixedTimeslotTask.h"
#include "../../osal/host/PeriodicTask.h"
#include "../../tasks/TaskFactory.h"
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/PeriodicTaskIF.h"
#include <chrono>
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
// Will propably not be used for hosted implementation
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0;
TaskFactory::TaskFactory() {
}
TaskFactory::~TaskFactory() {
}
TaskFactory* TaskFactory::instance() {
return TaskFactory::factoryInstance;
}
PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_,
TaskPriority taskPriority_,TaskStackSize stackSize_,
TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
return new PeriodicTask(name_, taskPriority_, stackSize_, periodInSeconds_,
deadLineMissedFunction_);
}
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,
TaskPriority taskPriority_,TaskStackSize stackSize_,
TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
return new FixedTimeslotTask(name_, taskPriority_, stackSize_,
periodInSeconds_, deadLineMissedFunction_);
}
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
// This might block for some time!
delete task;
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
std::this_thread::sleep_for(std::chrono::milliseconds(delayMs));
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,149 +1,149 @@
#include "../../osal/linux/BinarySemaphore.h" #include "../../osal/linux/BinarySemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
extern "C" { extern "C" {
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
} }
BinarySemaphore::BinarySemaphore() { BinarySemaphore::BinarySemaphore() {
// Using unnamed semaphores for now // Using unnamed semaphores for now
initSemaphore(); initSemaphore();
} }
BinarySemaphore::~BinarySemaphore() { BinarySemaphore::~BinarySemaphore() {
sem_destroy(&handle); sem_destroy(&handle);
} }
BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) {
initSemaphore(); initSemaphore();
} }
BinarySemaphore& BinarySemaphore::operator =( BinarySemaphore& BinarySemaphore::operator =(
BinarySemaphore&& s) { BinarySemaphore&& s) {
initSemaphore(); initSemaphore();
return * this; return * this;
} }
ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType, ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType,
uint32_t timeoutMs) { uint32_t timeoutMs) {
int result = 0; int result = 0;
if(timeoutType == TimeoutType::POLLING) { if(timeoutType == TimeoutType::POLLING) {
result = sem_trywait(&handle); result = sem_trywait(&handle);
} }
else if(timeoutType == TimeoutType::BLOCKING) { else if(timeoutType == TimeoutType::BLOCKING) {
result = sem_wait(&handle); result = sem_wait(&handle);
} }
else if(timeoutType == TimeoutType::WAITING){ else if(timeoutType == TimeoutType::WAITING){
timespec timeOut; timespec timeOut;
clock_gettime(CLOCK_REALTIME, &timeOut); clock_gettime(CLOCK_REALTIME, &timeOut);
uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec; uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec;
nseconds += timeoutMs * 1000000; nseconds += timeoutMs * 1000000;
timeOut.tv_sec = nseconds / 1000000000; timeOut.tv_sec = nseconds / 1000000000;
timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000; timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000;
result = sem_timedwait(&handle, &timeOut); result = sem_timedwait(&handle, &timeOut);
if(result != 0 and errno == EINVAL) { if(result != 0 and errno == EINVAL) {
sif::debug << "BinarySemaphore::acquire: Invalid time value possible" sif::debug << "BinarySemaphore::acquire: Invalid time value possible"
<< std::endl; << std::endl;
} }
} }
if(result == 0) { if(result == 0) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
switch(errno) { switch(errno) {
case(EAGAIN): case(EAGAIN):
// Operation could not be performed without blocking (for sem_trywait) // Operation could not be performed without blocking (for sem_trywait)
case(ETIMEDOUT): case(ETIMEDOUT):
// Semaphore is 0 // Semaphore is 0
return SemaphoreIF::SEMAPHORE_TIMEOUT; return SemaphoreIF::SEMAPHORE_TIMEOUT;
case(EINVAL): case(EINVAL):
// Semaphore invalid // Semaphore invalid
return SemaphoreIF::SEMAPHORE_INVALID; return SemaphoreIF::SEMAPHORE_INVALID;
case(EINTR): case(EINTR):
// Call was interrupted by signal handler // Call was interrupted by signal handler
sif::debug << "BinarySemaphore::acquire: Signal handler interrupted." sif::debug << "BinarySemaphore::acquire: Signal handler interrupted."
"Code " << strerror(errno) << std::endl; "Code " << strerror(errno) << std::endl;
/* No break */ /* No break */
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
ReturnValue_t BinarySemaphore::release() { ReturnValue_t BinarySemaphore::release() {
return BinarySemaphore::release(&this->handle); return BinarySemaphore::release(&this->handle);
} }
ReturnValue_t BinarySemaphore::release(sem_t *handle) { ReturnValue_t BinarySemaphore::release(sem_t *handle) {
ReturnValue_t countResult = checkCount(handle, 1); ReturnValue_t countResult = checkCount(handle, 1);
if(countResult != HasReturnvaluesIF::RETURN_OK) { if(countResult != HasReturnvaluesIF::RETURN_OK) {
return countResult; return countResult;
} }
int result = sem_post(handle); int result = sem_post(handle);
if(result == 0) { if(result == 0) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
switch(errno) { switch(errno) {
case(EINVAL): case(EINVAL):
// Semaphore invalid // Semaphore invalid
return SemaphoreIF::SEMAPHORE_INVALID; return SemaphoreIF::SEMAPHORE_INVALID;
case(EOVERFLOW): case(EOVERFLOW):
// SEM_MAX_VALUE overflow. This should never happen // SEM_MAX_VALUE overflow. This should never happen
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
uint8_t BinarySemaphore::getSemaphoreCounter() const { uint8_t BinarySemaphore::getSemaphoreCounter() const {
// And another ugly cast :-D // And another ugly cast :-D
return getSemaphoreCounter(const_cast<sem_t*>(&this->handle)); return getSemaphoreCounter(const_cast<sem_t*>(&this->handle));
} }
uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) { uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) {
int value = 0; int value = 0;
int result = sem_getvalue(handle, &value); int result = sem_getvalue(handle, &value);
if (result == 0) { if (result == 0) {
return value; return value;
} }
else if(result != 0 and errno == EINVAL) { else if(result != 0 and errno == EINVAL) {
// Could be called from interrupt, use lightweight printf // Could be called from interrupt, use lightweight printf
printf("BinarySemaphore::getSemaphoreCounter: Invalid semaphore\n"); printf("BinarySemaphore::getSemaphoreCounter: Invalid semaphore\n");
return 0; return 0;
} }
else { else {
// This should never happen. // This should never happen.
return 0; return 0;
} }
} }
void BinarySemaphore::initSemaphore(uint8_t initCount) { void BinarySemaphore::initSemaphore(uint8_t initCount) {
auto result = sem_init(&handle, true, initCount); auto result = sem_init(&handle, true, initCount);
if(result == -1) { if(result == -1) {
switch(errno) { switch(errno) {
case(EINVAL): case(EINVAL):
// Value exceeds SEM_VALUE_MAX // Value exceeds SEM_VALUE_MAX
case(ENOSYS): case(ENOSYS):
// System does not support process-shared semaphores // System does not support process-shared semaphores
sif::error << "BinarySemaphore: Init failed with" << strerror(errno) sif::error << "BinarySemaphore: Init failed with" << strerror(errno)
<< std::endl; << std::endl;
} }
} }
} }
ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) { ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) {
int value = getSemaphoreCounter(handle); int value = getSemaphoreCounter(handle);
if(value >= maxCount) { if(value >= maxCount) {
if(maxCount == 1 and value > 1) { if(maxCount == 1 and value > 1) {
// Binary Semaphore special case. // Binary Semaphore special case.
// This is a config error use lightweight printf is this is called // This is a config error use lightweight printf is this is called
// from an interrupt // from an interrupt
printf("BinarySemaphore::release: Value of binary semaphore greater" printf("BinarySemaphore::release: Value of binary semaphore greater"
" than 1!\n"); " than 1!\n");
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
return SemaphoreIF::SEMAPHORE_NOT_OWNED; return SemaphoreIF::SEMAPHORE_NOT_OWNED;
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -1,81 +1,81 @@
#ifndef FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ #ifndef FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_
#define FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ #define FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_
#include "../../returnvalues/HasReturnvaluesIF.h" #include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/SemaphoreIF.h" #include "../../tasks/SemaphoreIF.h"
extern "C" { extern "C" {
#include <semaphore.h> #include <semaphore.h>
} }
/** /**
* @brief OS Tool to achieve synchronization of between tasks or between * @brief OS Tool to achieve synchronization of between tasks or between
* task and ISR. The default semaphore implementation creates a * task and ISR. The default semaphore implementation creates a
* binary semaphore, which can only be taken once. * binary semaphore, which can only be taken once.
* @details * @details
* See: http://www.man7.org/linux/man-pages/man7/sem_overview.7.html * See: http://www.man7.org/linux/man-pages/man7/sem_overview.7.html
* @author R. Mueller * @author R. Mueller
* @ingroup osal * @ingroup osal
*/ */
class BinarySemaphore: public SemaphoreIF, class BinarySemaphore: public SemaphoreIF,
public HasReturnvaluesIF { public HasReturnvaluesIF {
public: public:
static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF;
//! @brief Default ctor //! @brief Default ctor
BinarySemaphore(); BinarySemaphore();
//! @brief Copy ctor, deleted explicitely. //! @brief Copy ctor, deleted explicitely.
BinarySemaphore(const BinarySemaphore&) = delete; BinarySemaphore(const BinarySemaphore&) = delete;
//! @brief Copy assignment, deleted explicitely. //! @brief Copy assignment, deleted explicitely.
BinarySemaphore& operator=(const BinarySemaphore&) = delete; BinarySemaphore& operator=(const BinarySemaphore&) = delete;
//! @brief Move ctor //! @brief Move ctor
BinarySemaphore (BinarySemaphore &&); BinarySemaphore (BinarySemaphore &&);
//! @brief Move assignment //! @brief Move assignment
BinarySemaphore & operator=(BinarySemaphore &&); BinarySemaphore & operator=(BinarySemaphore &&);
//! @brief Destructor //! @brief Destructor
virtual ~BinarySemaphore(); virtual ~BinarySemaphore();
void initSemaphore(uint8_t initCount = 1); void initSemaphore(uint8_t initCount = 1);
uint8_t getSemaphoreCounter() const override; uint8_t getSemaphoreCounter() const override;
static uint8_t getSemaphoreCounter(sem_t* handle); static uint8_t getSemaphoreCounter(sem_t* handle);
/** /**
* Take the binary semaphore. * Take the binary semaphore.
* If the semaphore has already been taken, the task will be blocked * If the semaphore has already been taken, the task will be blocked
* for a maximum of #timeoutMs or until the semaphore is given back, * for a maximum of #timeoutMs or until the semaphore is given back,
* for example by an ISR or another task. * for example by an ISR or another task.
* @param timeoutMs * @param timeoutMs
* @return -@c RETURN_OK on success * @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/ */
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
uint32_t timeoutMs = 0) override; uint32_t timeoutMs = 0) override;
/** /**
* Release the binary semaphore. * Release the binary semaphore.
* @return -@c RETURN_OK on success * @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is
* already available. * already available.
*/ */
virtual ReturnValue_t release() override; virtual ReturnValue_t release() override;
/** /**
* This static function can be used to release a semaphore by providing * This static function can be used to release a semaphore by providing
* its handle. * its handle.
* @param handle * @param handle
* @return * @return
*/ */
static ReturnValue_t release(sem_t* handle); static ReturnValue_t release(sem_t* handle);
/** Checks the validity of the semaphore count against a specified /** Checks the validity of the semaphore count against a specified
* known maxCount * known maxCount
* @param handle * @param handle
* @param maxCount * @param maxCount
* @return * @return
*/ */
static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount); static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount);
protected: protected:
sem_t handle; sem_t handle;
}; };
#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ #endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */

View File

@ -75,24 +75,25 @@ timeval Clock::getUptime() {
} }
ReturnValue_t Clock::getUptime(timeval* uptime) { ReturnValue_t Clock::getUptime(timeval* uptime) {
//TODO This is not posix compatible and delivers only seconds precision
// is the OS not called Linux?
//Linux specific file read but more precise
double uptimeSeconds;
if(std::ifstream("/proc/uptime",std::ios::in) >> uptimeSeconds){
uptime->tv_sec = uptimeSeconds;
uptime->tv_usec = uptimeSeconds *(double) 1e6 - (uptime->tv_sec *1e6);
}
//TODO This is not posix compatible and delivers only seconds precision //TODO This is not posix compatible and delivers only seconds precision
struct sysinfo sysInfo; // I suggest this is moved into another clock function which will
int result = sysinfo(&sysInfo); // deliver second precision later.
if(result != 0){ // struct sysinfo sysInfo;
return HasReturnvaluesIF::RETURN_FAILED; // int result = sysinfo(&sysInfo);
} // if(result != 0){
uptime->tv_sec = sysInfo.uptime; // return HasReturnvaluesIF::RETURN_FAILED;
uptime->tv_usec = 0;
//Linux specific file read but more precise
// double uptimeSeconds;
// if(std::ifstream("/proc/uptime",std::ios::in) >> uptimeSeconds){
// uptime->tv_sec = uptimeSeconds;
// uptime->tv_usec = uptimeSeconds *(double) 1e6 - (uptime->tv_sec *1e6);
// } // }
// return sysInfo.uptime;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {

View File

@ -1,54 +1,54 @@
#include "../../osal/linux/CountingSemaphore.h" #include "../../osal/linux/CountingSemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount):
maxCount(maxCount), initCount(initCount) { maxCount(maxCount), initCount(initCount) {
if(initCount > maxCount) { if(initCount > maxCount) {
sif::error << "CountingSemaphoreUsingTask: Max count bigger than " sif::error << "CountingSemaphoreUsingTask: Max count bigger than "
"intial cout. Setting initial count to max count." << std::endl; "intial cout. Setting initial count to max count." << std::endl;
initCount = maxCount; initCount = maxCount;
} }
initSemaphore(initCount); initSemaphore(initCount);
} }
CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): CountingSemaphore::CountingSemaphore(CountingSemaphore&& other):
maxCount(other.maxCount), initCount(other.initCount) { maxCount(other.maxCount), initCount(other.initCount) {
initSemaphore(initCount); initSemaphore(initCount);
} }
CountingSemaphore& CountingSemaphore::operator =( CountingSemaphore& CountingSemaphore::operator =(
CountingSemaphore&& other) { CountingSemaphore&& other) {
initSemaphore(other.initCount); initSemaphore(other.initCount);
return * this; return * this;
} }
ReturnValue_t CountingSemaphore::release() { ReturnValue_t CountingSemaphore::release() {
ReturnValue_t result = checkCount(&handle, maxCount); ReturnValue_t result = checkCount(&handle, maxCount);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
return CountingSemaphore::release(&this->handle); return CountingSemaphore::release(&this->handle);
} }
ReturnValue_t CountingSemaphore::release(sem_t* handle) { ReturnValue_t CountingSemaphore::release(sem_t* handle) {
int result = sem_post(handle); int result = sem_post(handle);
if(result == 0) { if(result == 0) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
switch(errno) { switch(errno) {
case(EINVAL): case(EINVAL):
// Semaphore invalid // Semaphore invalid
return SemaphoreIF::SEMAPHORE_INVALID; return SemaphoreIF::SEMAPHORE_INVALID;
case(EOVERFLOW): case(EOVERFLOW):
// SEM_MAX_VALUE overflow. This should never happen // SEM_MAX_VALUE overflow. This should never happen
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
uint8_t CountingSemaphore::getMaxCount() const { uint8_t CountingSemaphore::getMaxCount() const {
return maxCount; return maxCount;
} }

View File

@ -1,37 +1,37 @@
#ifndef FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ #ifndef FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_
#define FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ #define FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_
#include "../../osal/linux/BinarySemaphore.h" #include "../../osal/linux/BinarySemaphore.h"
/** /**
* @brief Counting semaphores, which can be acquired more than once. * @brief Counting semaphores, which can be acquired more than once.
* @details * @details
* See: https://www.freertos.org/CreateCounting.html * See: https://www.freertos.org/CreateCounting.html
* API of counting semaphores is almost identical to binary semaphores, * API of counting semaphores is almost identical to binary semaphores,
* so we just inherit from binary semaphore and provide the respective * so we just inherit from binary semaphore and provide the respective
* constructors. * constructors.
*/ */
class CountingSemaphore: public BinarySemaphore { class CountingSemaphore: public BinarySemaphore {
public: public:
CountingSemaphore(const uint8_t maxCount, uint8_t initCount); CountingSemaphore(const uint8_t maxCount, uint8_t initCount);
//! @brief Copy ctor, disabled //! @brief Copy ctor, disabled
CountingSemaphore(const CountingSemaphore&) = delete; CountingSemaphore(const CountingSemaphore&) = delete;
//! @brief Copy assignment, disabled //! @brief Copy assignment, disabled
CountingSemaphore& operator=(const CountingSemaphore&) = delete; CountingSemaphore& operator=(const CountingSemaphore&) = delete;
//! @brief Move ctor //! @brief Move ctor
CountingSemaphore (CountingSemaphore &&); CountingSemaphore (CountingSemaphore &&);
//! @brief Move assignment //! @brief Move assignment
CountingSemaphore & operator=(CountingSemaphore &&); CountingSemaphore & operator=(CountingSemaphore &&);
ReturnValue_t release() override; ReturnValue_t release() override;
static ReturnValue_t release(sem_t* sem); static ReturnValue_t release(sem_t* sem);
/* Same API as binary semaphore otherwise. acquire() can be called /* Same API as binary semaphore otherwise. acquire() can be called
* until there are not semaphores left and release() can be called * until there are not semaphores left and release() can be called
* until maxCount is reached. */ * until maxCount is reached. */
uint8_t getMaxCount() const; uint8_t getMaxCount() const;
private: private:
const uint8_t maxCount; const uint8_t maxCount;
uint8_t initCount = 0; uint8_t initCount = 0;
}; };
#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ #endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */

View File

@ -5,8 +5,8 @@
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_,
size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()): size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()):
PosixThread(name_,priority_,stackSize_),objectList(),started(false), PosixThread(name_, priority_, stackSize_), objectList(), started(false),
periodMs(period_),deadlineMissedFunc(deadlineMissedFunc_) { periodMs(period_), deadlineMissedFunc(deadlineMissedFunc_) {
} }
PeriodicPosixTask::~PeriodicPosixTask() { PeriodicPosixTask::~PeriodicPosixTask() {
@ -25,6 +25,8 @@ ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>( ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object); object);
if (newObject == nullptr) { if (newObject == nullptr) {
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
<< " it implements ExecutableObjectIF!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
objectList.push_back(newObject); objectList.push_back(newObject);
@ -38,35 +40,41 @@ ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) {
} }
ReturnValue_t PeriodicPosixTask::startTask(void){ ReturnValue_t PeriodicPosixTask::startTask(void) {
started = true; started = true;
//sif::info << stackSize << std::endl; //sif::info << stackSize << std::endl;
PosixThread::createTask(&taskEntryPoint,this); PosixThread::createTask(&taskEntryPoint,this);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void PeriodicPosixTask::taskFunctionality(void){ void PeriodicPosixTask::taskFunctionality(void) {
if(!started){ if(not started) {
suspend(); suspend();
} }
for (auto const &object: objectList) {
object->initializeAfterTaskCreation();
}
uint64_t lastWakeTime = getCurrentMonotonicTimeMs(); uint64_t lastWakeTime = getCurrentMonotonicTimeMs();
//The task's "infinite" inner loop is entered. //The task's "infinite" inner loop is entered.
while (1) { while (1) {
for (ObjectList::iterator it = objectList.begin(); for (auto const &object: objectList) {
it != objectList.end(); ++it) { object->performOperation();
(*it)->performOperation();
} }
if(!PosixThread::delayUntil(&lastWakeTime,periodMs)){
if(not PosixThread::delayUntil(&lastWakeTime, periodMs)){
char name[20] = {0}; char name[20] = {0};
int status = pthread_getname_np(pthread_self(),name,sizeof(name)); int status = pthread_getname_np(pthread_self(), name, sizeof(name));
if(status==0){ if(status == 0) {
sif::error << "PeriodicPosixTask " << name << ": Deadline " sif::error << "PeriodicPosixTask " << name << ": Deadline "
"missed." << std::endl; "missed." << std::endl;
}else{ }
else {
sif::error << "PeriodicPosixTask X: Deadline missed. " << sif::error << "PeriodicPosixTask X: Deadline missed. " <<
status << std::endl; status << std::endl;
} }
if (this->deadlineMissedFunc != NULL) { if (this->deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc(); this->deadlineMissedFunc();
} }
} }

View File

@ -32,7 +32,7 @@ public:
* The address of the task object is passed as an argument * The address of the task object is passed as an argument
* to the system call. * to the system call.
*/ */
ReturnValue_t startTask(void); ReturnValue_t startTask() override;
/** /**
* Adds an object to the list of objects to be executed. * Adds an object to the list of objects to be executed.
* The objects are executed in the order added. * The objects are executed in the order added.

View File

@ -1,33 +1,33 @@
#include "../../tasks/SemaphoreFactory.h" #include "../../tasks/SemaphoreFactory.h"
#include "BinarySemaphore.h" #include "BinarySemaphore.h"
#include "CountingSemaphore.h" #include "CountingSemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr;
SemaphoreFactory::SemaphoreFactory() { SemaphoreFactory::SemaphoreFactory() {
} }
SemaphoreFactory::~SemaphoreFactory() { SemaphoreFactory::~SemaphoreFactory() {
delete factoryInstance; delete factoryInstance;
} }
SemaphoreFactory* SemaphoreFactory::instance() { SemaphoreFactory* SemaphoreFactory::instance() {
if (factoryInstance == nullptr){ if (factoryInstance == nullptr){
factoryInstance = new SemaphoreFactory(); factoryInstance = new SemaphoreFactory();
} }
return SemaphoreFactory::factoryInstance; return SemaphoreFactory::factoryInstance;
} }
SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) { SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) {
return new BinarySemaphore(); return new BinarySemaphore();
} }
SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount, SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount,
uint8_t initCount, uint32_t arguments) { uint8_t initCount, uint32_t arguments) {
return new CountingSemaphore(maxCount, initCount); return new CountingSemaphore(maxCount, initCount);
} }
void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) {
delete semaphore; delete semaphore;
} }

41
pus/Service17Test.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "Service17Test.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../objectmanager/SystemObject.h"
#include "../tmtcpacket/pus/TmPacketStored.h"
Service17Test::Service17Test(object_id_t objectId,
uint16_t apid, uint8_t serviceId):
PusServiceBase(objectId, apid, serviceId),
packetSubCounter(0) {
}
Service17Test::~Service17Test() {
}
ReturnValue_t Service17Test::handleRequest(uint8_t subservice) {
switch(subservice){
case Subservice::CONNECTION_TEST: {
TmPacketStored connectionPacket(apid, serviceId,
Subservice::CONNECTION_TEST_REPORT, packetSubCounter++);
connectionPacket.sendPacket(requestQueue->getDefaultDestination(),
requestQueue->getId());
return HasReturnvaluesIF::RETURN_OK;
}
case Subservice::EVENT_TRIGGER_TEST: {
TmPacketStored connectionPacket(apid, serviceId,
Subservice::CONNECTION_TEST_REPORT, packetSubCounter++);
connectionPacket.sendPacket(requestQueue->getDefaultDestination(),
requestQueue->getId());
triggerEvent(TEST, 1234, 5678);
return RETURN_OK;
}
default:
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
}
}
ReturnValue_t Service17Test::performService() {
return HasReturnvaluesIF::RETURN_OK;
}

44
pus/Service17Test.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef FSFW_PUS_SERVICE17TEST_H_
#define FSFW_PUS_SERVICE17TEST_H_
#include "../tmtcservices/PusServiceBase.h"
#include "../objectmanager/SystemObject.h"
/**
* @brief Test Service
* Full Documentation: ECSS-E70-41A p.167
*
* The test service provides the capability to activate test functions
* implemented on-board and to report the results of such tests.
* Service capability:
* - TC[17,1]: Perform connection test
* - TM[17,2]: Send Connection Test Report
* - TC[17,128]: Perform connection test and trigger event
*
* @ingroup pus_services
*/
class Service17Test: public PusServiceBase {
public:
// Custom events which can be triggered
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_17;
static constexpr Event TEST = MAKE_EVENT(0, SEVERITY::INFO);
enum Subservice: uint8_t {
//! [EXPORT] : [COMMAND] Perform connection test
CONNECTION_TEST = 1,
//! [EXPORT] : [REPLY] Connection test reply
CONNECTION_TEST_REPORT = 2,
//! [EXPORT] : [COMMAND] Trigger test reply and test event
EVENT_TRIGGER_TEST = 128,
};
Service17Test(object_id_t objectId, uint16_t apid, uint8_t serviceId);
virtual ~Service17Test();
virtual ReturnValue_t handleRequest(uint8_t subservice) override;
virtual ReturnValue_t performService() override;
protected:
uint16_t packetSubCounter = 0;
};
#endif /* FSFW_PUS_SERVICE17TEST_H_ */

View File

@ -0,0 +1,58 @@
#include "Service9TimeManagement.h"
#include "servicepackets/Service9Packets.h"
#include "../timemanager/CCSDSTime.h"
#include "../events/EventManagerIF.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
Service9TimeManagement::Service9TimeManagement(object_id_t objectId,
uint16_t apid, uint8_t serviceId) :
PusServiceBase(objectId, apid , serviceId) {
}
Service9TimeManagement::~Service9TimeManagement() {}
ReturnValue_t Service9TimeManagement::performService() {
return RETURN_OK;
}
ReturnValue_t Service9TimeManagement::handleRequest(uint8_t subservice) {
switch(subservice){
case SUBSERVICE::SET_TIME:{
return setTime();
}
default:
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
}
}
ReturnValue_t Service9TimeManagement::setTime() {
Clock::TimeOfDay_t timeToSet;
TimePacket timePacket(currentPacket.getApplicationData(),
currentPacket.getApplicationDataSize());
ReturnValue_t result = CCSDSTime::convertFromCcsds(&timeToSet,
timePacket.getTime(), timePacket.getTimeSize());
if(result != RETURN_OK) {
triggerEvent(CLOCK_SET_FAILURE, result, 0);
return result;
}
uint32_t formerUptime;
Clock::getUptime(&formerUptime);
result = Clock::setClock(&timeToSet);
if(result == RETURN_OK) {
uint32_t newUptime;
Clock::getUptime(&newUptime);
triggerEvent(CLOCK_SET,newUptime,formerUptime);
return RETURN_OK;
}
else {
triggerEvent(CLOCK_SET_FAILURE, result, 0);
return RETURN_FAILED;
}
}

View File

@ -0,0 +1,41 @@
#ifndef FSFW_PUS_SERVICE9TIMEMANAGEMENT_H_
#define FSFW_PUS_SERVICE9TIMEMANAGEMENT_H_
#include "../tmtcservices/PusServiceBase.h"
class Service9TimeManagement: public PusServiceBase {
public:
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9;
static constexpr Event CLOCK_SET = MAKE_EVENT(0, SEVERITY::INFO); //!< Clock has been set. P1: New Uptime. P2: Old Uptime
static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(1, SEVERITY::LOW); //!< Clock could not be set. P1: Returncode.
static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9;
/**
* @brief This service provides the capability to set the on-board time.
*/
Service9TimeManagement(object_id_t objectId, uint16_t apid,
uint8_t serviceId);
virtual ~Service9TimeManagement();
virtual ReturnValue_t performService() override;
/**
* @brief Sets the onboard-time by retrieving the time to set from TC[9,128].
*/
virtual ReturnValue_t handleRequest(uint8_t subservice) override;
virtual ReturnValue_t setTime();
private:
enum SUBSERVICE {
SET_TIME = 128 //!< [EXPORT] : [COMMAND] Time command in ASCII, CUC or CDS format
};
};
#endif /* FSFW_PUS_SERVICE9TIMEMANAGEMENT_H_ */

View File

@ -0,0 +1,32 @@
#ifndef FSFW_PUS_SERVICEPACKETS_SERVICE9PACKETS_H_
#define FSFW_PUS_SERVICEPACKETS_SERVICE9PACKETS_H_
#include "../../serialize/SerialLinkedListAdapter.h"
/**
* @brief Subservice 128
* @details
* It only contains the time encoded as ASCII, CRC, CUC or CDS
* @ingroup spacepackets
*/
class TimePacket : SerialLinkedListAdapter<SerializeIF> { //!< [EXPORT] : [SUBSERVICE] 128
public:
TimePacket(const uint8_t * timeBuffer_, uint32_t timeSize_) {
timeBuffer = timeBuffer_;
timeSize = timeSize_;
}
const uint8_t* getTime() {
return timeBuffer;
}
uint32_t getTimeSize() const {
return timeSize;
}
private:
TimePacket(const TimePacket &command);
const uint8_t * timeBuffer;
uint32_t timeSize; //!< [EXPORT] : [IGNORE]
};
#endif /* FSFW_PUS_SERVICEPACKETS_SERVICE9PACKETS_H_ */

View File

@ -1,5 +1,5 @@
#ifndef FRAMEWORK_RETURNVALUES_FWCLASSIDS_H_ #ifndef FSFW_RETURNVALUES_FWCLASSIDS_H_
#define FRAMEWORK_RETURNVALUES_FWCLASSIDS_H_ #define FSFW_RETURNVALUES_FWCLASSIDS_H_
namespace CLASS_ID { namespace CLASS_ID {
enum { enum {
@ -64,9 +64,11 @@ enum {
LOCAL_POOL_OWNER_IF, //LPIF 58 LOCAL_POOL_OWNER_IF, //LPIF 58
POOL_VARIABLE_IF, //PVA 59 POOL_VARIABLE_IF, //PVA 59
HOUSEKEEPING_MANAGER, //HKM 60 HOUSEKEEPING_MANAGER, //HKM 60
DLE_ENCODER, //DLEE 61
PUS_SERVICE_9, //PUS9 62
FW_CLASS_ID_COUNT //is actually count + 1 ! FW_CLASS_ID_COUNT //is actually count + 1 !
}; };
} }
#endif /* FRAMEWORK_RETURNVALUES_FWCLASSIDS_H_ */ #endif /* FSFW_RETURNVALUES_FWCLASSIDS_H_ */

View File

@ -1,5 +1,5 @@
#ifndef ENDIANSWAPPER_H_ #ifndef FSFW_SERIALIZE_ENDIANCONVERTER_H_
#define ENDIANSWAPPER_H_ #define FSFW_SERIALIZE_ENDIANCONVERTER_H_
#include "../osal/Endiness.h" #include "../osal/Endiness.h"
#include <cstring> #include <cstring>
@ -35,9 +35,7 @@
*/ */
class EndianConverter { class EndianConverter {
private: private:
EndianConverter() { EndianConverter() {};
}
;
public: public:
/** /**
* Convert a typed variable between big endian and machine endian. * Convert a typed variable between big endian and machine endian.
@ -123,4 +121,4 @@ public:
} }
}; };
#endif /* ENDIANSWAPPER_H_ */ #endif /* FSFW_SERIALIZE_ENDIANCONVERTER_H_ */

View File

@ -1,13 +1,14 @@
#ifndef FRAMEWORK_SERIALIZE_SERIALARRAYLISTADAPTER_H_ #ifndef FSFW_SERIALIZE_SERIALARRAYLISTADAPTER_H_
#define FRAMEWORK_SERIALIZE_SERIALARRAYLISTADAPTER_H_ #define FSFW_SERIALIZE_SERIALARRAYLISTADAPTER_H_
#include "../container/ArrayList.h"
#include "SerializeIF.h" #include "SerializeIF.h"
#include "../container/ArrayList.h"
#include <utility> #include <utility>
/** /**
* Also serializes length field !
* @author baetz
* @ingroup serialize * @ingroup serialize
* @author baetz
*/ */
template<typename T, typename count_t = uint8_t> template<typename T, typename count_t = uint8_t>
class SerialArrayListAdapter : public SerializeIF { class SerialArrayListAdapter : public SerializeIF {
@ -21,14 +22,14 @@ public:
} }
static ReturnValue_t serialize(const ArrayList<T, count_t>* list, static ReturnValue_t serialize(const ArrayList<T, count_t>* list,
uint8_t** buffer, size_t* size, size_t maxSize, uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) { Endianness streamEndianness) {
ReturnValue_t result = SerializeAdapter::serialize(&list->size, ReturnValue_t result = SerializeAdapter::serialize(&list->size,
buffer, size, maxSize, streamEndianness); buffer, size, maxSize, streamEndianness);
count_t i = 0; count_t i = 0;
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < list->size)) { while ((result == HasReturnvaluesIF::RETURN_OK) && (i < list->size)) {
result = SerializeAdapter::serialize(&list->entries[i], buffer, result = SerializeAdapter::serialize(&list->entries[i], buffer, size,
size, maxSize, streamEndianness); maxSize, streamEndianness);
++i; ++i;
} }
return result; return result;
@ -55,17 +56,18 @@ public:
} }
static ReturnValue_t deSerialize(ArrayList<T, count_t>* list, static ReturnValue_t deSerialize(ArrayList<T, count_t>* list,
const uint8_t** buffer, size_t* size, const uint8_t** buffer, size_t* size,
Endianness streamEndianness) { Endianness streamEndianness) {
count_t tempSize = 0; count_t tempSize = 0;
ReturnValue_t result = SerializeAdapter::deSerialize(&tempSize, ReturnValue_t result = SerializeAdapter::deSerialize(&tempSize,
buffer, size, streamEndianness); buffer, size, streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
if (tempSize > list->maxSize()) { if (tempSize > list->maxSize()) {
return SerializeIF::TOO_MANY_ELEMENTS; return SerializeIF::TOO_MANY_ELEMENTS;
} }
list->size = tempSize; list->size = tempSize;
count_t i = 0; count_t i = 0;
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < list->size)) { while ((result == HasReturnvaluesIF::RETURN_OK) && (i < list->size)) {
@ -76,10 +78,9 @@ public:
} }
return result; return result;
} }
private: private:
ArrayList<T, count_t> *adaptee; ArrayList<T, count_t> *adaptee;
}; };
#endif /* FSFW_SERIALIZE_SERIALARRAYLISTADAPTER_H_ */
#endif /* FRAMEWORK_SERIALIZE_SERIALARRAYLISTADAPTER_H_ */

View File

@ -1,129 +1,129 @@
#include "../serialize/SerialBufferAdapter.h" #include "../serialize/SerialBufferAdapter.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterfaceStream.h"
#include <cstring> #include <cstring>
template<typename count_t> template<typename count_t>
SerialBufferAdapter<count_t>::SerialBufferAdapter(const uint8_t* buffer, SerialBufferAdapter<count_t>::SerialBufferAdapter(const uint8_t* buffer,
count_t bufferLength, bool serializeLength) : count_t bufferLength, bool serializeLength) :
serializeLength(serializeLength), serializeLength(serializeLength),
constBuffer(buffer), buffer(nullptr), constBuffer(buffer), buffer(nullptr),
bufferLength(bufferLength) {} bufferLength(bufferLength) {}
template<typename count_t> template<typename count_t>
SerialBufferAdapter<count_t>::SerialBufferAdapter(uint8_t* buffer, SerialBufferAdapter<count_t>::SerialBufferAdapter(uint8_t* buffer,
count_t bufferLength, bool serializeLength) : count_t bufferLength, bool serializeLength) :
serializeLength(serializeLength), constBuffer(buffer), buffer(buffer), serializeLength(serializeLength), constBuffer(buffer), buffer(buffer),
bufferLength(bufferLength) {} bufferLength(bufferLength) {}
template<typename count_t> template<typename count_t>
SerialBufferAdapter<count_t>::~SerialBufferAdapter() { SerialBufferAdapter<count_t>::~SerialBufferAdapter() {
} }
template<typename count_t> template<typename count_t>
ReturnValue_t SerialBufferAdapter<count_t>::serialize(uint8_t** buffer, ReturnValue_t SerialBufferAdapter<count_t>::serialize(uint8_t** buffer,
size_t* size, size_t maxSize, Endianness streamEndianness) const { size_t* size, size_t maxSize, Endianness streamEndianness) const {
if (serializeLength) { if (serializeLength) {
ReturnValue_t result = SerializeAdapter::serialize(&bufferLength, ReturnValue_t result = SerializeAdapter::serialize(&bufferLength,
buffer, size, maxSize, streamEndianness); buffer, size, maxSize, streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
} }
if (*size + bufferLength > maxSize) { if (*size + bufferLength > maxSize) {
return BUFFER_TOO_SHORT; return BUFFER_TOO_SHORT;
} }
if (this->constBuffer != nullptr) { if (this->constBuffer != nullptr) {
std::memcpy(*buffer, this->constBuffer, bufferLength); std::memcpy(*buffer, this->constBuffer, bufferLength);
} }
else if (this->buffer != nullptr) { else if (this->buffer != nullptr) {
// This will propably be never reached, constBuffer should always be // This will propably be never reached, constBuffer should always be
// set if non-const buffer is set. // set if non-const buffer is set.
std::memcpy(*buffer, this->buffer, bufferLength); std::memcpy(*buffer, this->buffer, bufferLength);
} }
else { else {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
*size += bufferLength; *size += bufferLength;
(*buffer) += bufferLength; (*buffer) += bufferLength;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
template<typename count_t> template<typename count_t>
size_t SerialBufferAdapter<count_t>::getSerializedSize() const { size_t SerialBufferAdapter<count_t>::getSerializedSize() const {
if (serializeLength) { if (serializeLength) {
return bufferLength + SerializeAdapter::getSerializedSize(&bufferLength); return bufferLength + SerializeAdapter::getSerializedSize(&bufferLength);
} else { } else {
return bufferLength; return bufferLength;
} }
} }
template<typename count_t> template<typename count_t>
ReturnValue_t SerialBufferAdapter<count_t>::deSerialize(const uint8_t** buffer, ReturnValue_t SerialBufferAdapter<count_t>::deSerialize(const uint8_t** buffer,
size_t* size, Endianness streamEndianness) { size_t* size, Endianness streamEndianness) {
if (this->buffer == nullptr) { if (this->buffer == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
if(serializeLength){ if(serializeLength){
count_t lengthField = 0; count_t lengthField = 0;
ReturnValue_t result = SerializeAdapter::deSerialize(&lengthField, ReturnValue_t result = SerializeAdapter::deSerialize(&lengthField,
buffer, size, streamEndianness); buffer, size, streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
if(lengthField > bufferLength) { if(lengthField > bufferLength) {
return TOO_MANY_ELEMENTS; return TOO_MANY_ELEMENTS;
} }
bufferLength = lengthField; bufferLength = lengthField;
} }
if (bufferLength <= *size) { if (bufferLength <= *size) {
*size -= bufferLength; *size -= bufferLength;
std::memcpy(this->buffer, *buffer, bufferLength); std::memcpy(this->buffer, *buffer, bufferLength);
(*buffer) += bufferLength; (*buffer) += bufferLength;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
else { else {
return STREAM_TOO_SHORT; return STREAM_TOO_SHORT;
} }
} }
template<typename count_t> template<typename count_t>
uint8_t * SerialBufferAdapter<count_t>::getBuffer() { uint8_t * SerialBufferAdapter<count_t>::getBuffer() {
if(buffer == nullptr) { if(buffer == nullptr) {
sif::error << "Wrong access function for stored type !" sif::error << "Wrong access function for stored type !"
" Use getConstBuffer()." << std::endl; " Use getConstBuffer()." << std::endl;
return nullptr; return nullptr;
} }
return buffer; return buffer;
} }
template<typename count_t> template<typename count_t>
const uint8_t * SerialBufferAdapter<count_t>::getConstBuffer() { const uint8_t * SerialBufferAdapter<count_t>::getConstBuffer() {
if(constBuffer == nullptr) { if(constBuffer == nullptr) {
sif::error << "SerialBufferAdapter::getConstBuffer:" sif::error << "SerialBufferAdapter::getConstBuffer:"
" Buffers are unitialized!" << std::endl; " Buffers are unitialized!" << std::endl;
return nullptr; return nullptr;
} }
return constBuffer; return constBuffer;
} }
template<typename count_t> template<typename count_t>
void SerialBufferAdapter<count_t>::setBuffer(uint8_t* buffer, void SerialBufferAdapter<count_t>::setBuffer(uint8_t* buffer,
count_t bufferLength) { count_t bufferLength) {
this->buffer = buffer; this->buffer = buffer;
this->constBuffer = buffer; this->constBuffer = buffer;
this->bufferLength = bufferLength; this->bufferLength = bufferLength;
} }
//forward Template declaration for linker //forward Template declaration for linker
template class SerialBufferAdapter<uint8_t>; template class SerialBufferAdapter<uint8_t>;
template class SerialBufferAdapter<uint16_t>; template class SerialBufferAdapter<uint16_t>;
template class SerialBufferAdapter<uint32_t>; template class SerialBufferAdapter<uint32_t>;
template class SerialBufferAdapter<uint64_t>; template class SerialBufferAdapter<uint64_t>;

View File

@ -1,78 +1,78 @@
#ifndef SERIALBUFFERADAPTER_H_ #ifndef SERIALBUFFERADAPTER_H_
#define SERIALBUFFERADAPTER_H_ #define SERIALBUFFERADAPTER_H_
#include "../serialize/SerializeIF.h" #include "../serialize/SerializeIF.h"
#include "../serialize/SerializeAdapter.h" #include "../serialize/SerializeAdapter.h"
/** /**
* This adapter provides an interface for SerializeIF to serialize or deserialize * This adapter provides an interface for SerializeIF to serialize or deserialize
* buffers with no length header but a known size. * buffers with no length header but a known size.
* *
* Additionally, the buffer length can be serialized too and will be put in * Additionally, the buffer length can be serialized too and will be put in
* front of the serialized buffer. * front of the serialized buffer.
* *
* Can be used with SerialLinkedListAdapter by declaring a SerializeElement with * Can be used with SerialLinkedListAdapter by declaring a SerializeElement with
* SerialElement<SerialBufferAdapter<bufferLengthType(will be uint8_t mostly)>>. * SerialElement<SerialBufferAdapter<bufferLengthType(will be uint8_t mostly)>>.
* Right now, the SerialBufferAdapter must always * Right now, the SerialBufferAdapter must always
* be initialized with the buffer and size ! * be initialized with the buffer and size !
* *
* \ingroup serialize * \ingroup serialize
*/ */
template<typename count_t> template<typename count_t>
class SerialBufferAdapter: public SerializeIF { class SerialBufferAdapter: public SerializeIF {
public: public:
/** /**
* Constructor for constant uint8_t buffer. Length field can be serialized optionally. * Constructor for constant uint8_t buffer. Length field can be serialized optionally.
* Type of length can be supplied as template type. * Type of length can be supplied as template type.
* @param buffer * @param buffer
* @param bufferLength * @param bufferLength
* @param serializeLength * @param serializeLength
*/ */
SerialBufferAdapter(const uint8_t* buffer, count_t bufferLength, SerialBufferAdapter(const uint8_t* buffer, count_t bufferLength,
bool serializeLength = false); bool serializeLength = false);
/** /**
* Constructor for non-constant uint8_t buffer. * Constructor for non-constant uint8_t buffer.
* Length field can be serialized optionally. * Length field can be serialized optionally.
* Type of length can be supplied as template type. * Type of length can be supplied as template type.
* @param buffer * @param buffer
* @param bufferLength * @param bufferLength
* @param serializeLength Length field will be serialized with size count_t * @param serializeLength Length field will be serialized with size count_t
*/ */
SerialBufferAdapter(uint8_t* buffer, count_t bufferLength, SerialBufferAdapter(uint8_t* buffer, count_t bufferLength,
bool serializeLength = false); bool serializeLength = false);
virtual ~SerialBufferAdapter(); virtual ~SerialBufferAdapter();
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const override; size_t maxSize, Endianness streamEndianness) const override;
virtual size_t getSerializedSize() const override; virtual size_t getSerializedSize() const override;
/** /**
* @brief This function deserializes a buffer into the member buffer. * @brief This function deserializes a buffer into the member buffer.
* @details * @details
* If a length field is present, it is ignored, as the size should have * If a length field is present, it is ignored, as the size should have
* been set in the constructor. If the size is not known beforehand, * been set in the constructor. If the size is not known beforehand,
* consider using SerialFixedArrayListAdapter instead. * consider using SerialFixedArrayListAdapter instead.
* @param buffer [out] Resulting buffer * @param buffer [out] Resulting buffer
* @param size remaining size to deserialize, should be larger than buffer * @param size remaining size to deserialize, should be larger than buffer
* + size field size * + size field size
* @param bigEndian * @param bigEndian
* @return * @return
*/ */
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override; Endianness streamEndianness) override;
uint8_t * getBuffer(); uint8_t * getBuffer();
const uint8_t * getConstBuffer(); const uint8_t * getConstBuffer();
void setBuffer(uint8_t* buffer, count_t bufferLength); void setBuffer(uint8_t* buffer, count_t bufferLength);
private: private:
bool serializeLength = false; bool serializeLength = false;
const uint8_t *constBuffer = nullptr; const uint8_t *constBuffer = nullptr;
uint8_t *buffer = nullptr; uint8_t *buffer = nullptr;
count_t bufferLength = 0; count_t bufferLength = 0;
}; };
#endif /* SERIALBUFFERADAPTER_H_ */ #endif /* SERIALBUFFERADAPTER_H_ */

View File

@ -1,31 +1,57 @@
#ifndef SERIALFIXEDARRAYLISTADAPTER_H_ #ifndef FSFW_SERIALIZE_SERIALFIXEDARRAYLISTADAPTER_H_
#define SERIALFIXEDARRAYLISTADAPTER_H_ #define FSFW_SERIALIZE_SERIALFIXEDARRAYLISTADAPTER_H_
#include "../container/FixedArrayList.h"
#include "SerialArrayListAdapter.h" #include "SerialArrayListAdapter.h"
#include "../container/FixedArrayList.h"
/** /**
* \ingroup serialize * @brief This adapter provides an interface for SerializeIF to serialize and
* deserialize buffers with a header containing the buffer length.
* @details
* Can be used by SerialLinkedListAdapter by declaring
* as a linked element with SerializeElement<SerialFixedArrayListAdapter<...>>.
* The sequence of objects is defined in the constructor by
* using the setStart and setNext functions.
*
* @tparam BUFFER_TYPE: Specifies the data type of the buffer
* @tparam MAX_SIZE: Specifies the maximum allowed number of elements
* (not bytes!)
* @tparam count_t: specifies the type/size of the length field which defaults
* to one byte.
* @ingroup serialize
*/ */
template<typename T, uint32_t MAX_SIZE, typename count_t = uint8_t> template<typename BUFFER_TYPE, uint32_t MAX_SIZE, typename count_t = uint8_t>
class SerialFixedArrayListAdapter : public FixedArrayList<T, MAX_SIZE, count_t>, public SerializeIF { class SerialFixedArrayListAdapter :
public FixedArrayList<BUFFER_TYPE, MAX_SIZE, count_t>,
public SerializeIF {
public: public:
/**
* Constructor arguments are forwarded to FixedArrayList constructor.
* Refer to the fixed array list constructors for different options.
* @param args
*/
template<typename... Args> template<typename... Args>
SerialFixedArrayListAdapter(Args... args) : FixedArrayList<T, MAX_SIZE, count_t>(std::forward<Args>(args)...) { SerialFixedArrayListAdapter(Args... args) :
} FixedArrayList<BUFFER_TYPE, MAX_SIZE, count_t>(
ReturnValue_t serialize(uint8_t** buffer, size_t* size, std::forward<Args>(args)...){}
size_t maxSize, Endianness streamEndianness) const {
return SerialArrayListAdapter<T, count_t>::serialize(this, buffer, size, maxSize, streamEndianness); ReturnValue_t serialize(uint8_t** buffer, size_t* size,
} size_t maxSize, Endianness streamEndianness) const {
size_t getSerializedSize() const { return SerialArrayListAdapter<BUFFER_TYPE, count_t>::serialize(this,
return SerialArrayListAdapter<T, count_t>::getSerializedSize(this); buffer, size, maxSize, streamEndianness);
} }
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) { size_t getSerializedSize() const {
return SerialArrayListAdapter<T, count_t>::deSerialize(this, buffer, size, streamEndianness); return SerialArrayListAdapter<BUFFER_TYPE, count_t>::
} getSerializedSize(this);
}
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) {
return SerialArrayListAdapter<BUFFER_TYPE, count_t>::deSerialize(this,
buffer, size, streamEndianness);
}
}; };
#endif /* FSFW_SERIALIZE_SERIALFIXEDARRAYLISTADAPTER_H_ */
#endif /* SERIALFIXEDARRAYLISTADAPTER_H_ */

View File

@ -1,32 +1,52 @@
/** #ifndef FSFW_SERIALIZE_SERIALLINKEDLISTADAPTER_H_
* @file SerialLinkedListAdapter.h #define FSFW_SERIALIZE_SERIALLINKEDLISTADAPTER_H_
* @brief This file defines the SerialLinkedListAdapter class.
* @date 22.07.2014
* @author baetz
*/
#ifndef SERIALLINKEDLISTADAPTER_H_
#define SERIALLINKEDLISTADAPTER_H_
#include "../container/SinglyLinkedList.h" #include "../container/SinglyLinkedList.h"
#include "SerializeAdapter.h" #include "SerializeAdapter.h"
#include "SerializeElement.h" #include "SerializeElement.h"
#include "SerializeIF.h" #include "SerializeIF.h"
//This is where we need the SerializeAdapter!
/** /**
* \ingroup serialize * @brief Implement the conversion of object data to data streams
* or vice-versa, using linked lists.
* @details
* An alternative to the AutoSerializeAdapter functions
* - All object members with a datatype are declared as
* SerializeElement<element_type> members inside the class
* implementing this adapter.
* - The element type can also be a SerialBufferAdapter to
* de-/serialize buffers.
* - The element type can also be a SerialFixedArrayListAdapter to
* de-/serialize buffers with a size header, which is scanned automatically.
*
* The sequence of objects is defined in the constructor by using
* the setStart and setNext functions.
*
* 1. The serialization process is done by instantiating the class and
* calling serialize after all SerializeElement entries have been set by
* using the constructor or setter functions. An additional size variable
* can be supplied which is calculated/incremented automatically.
* 2. The deserialization process is done by instantiating the class and
* supplying a buffer with the data which is converted into an object.
* The size of data to serialize can be supplied and is
* decremented in the function. Range checking is done internally.
* @author baetz
* @ingroup serialize
*/ */
template<typename T, typename count_t = uint8_t> template<typename T, typename count_t = uint8_t>
class SerialLinkedListAdapter: public SinglyLinkedList<T>, public SerializeIF { class SerialLinkedListAdapter: public SinglyLinkedList<T>, public SerializeIF {
public: public:
SerialLinkedListAdapter(typename LinkedElement<T>::Iterator start, SerialLinkedListAdapter(typename LinkedElement<T>::Iterator start,
bool printCount = false) : bool printCount = false) :
SinglyLinkedList<T>(start), printCount(printCount) { SinglyLinkedList<T>(start), printCount(printCount) {
} }
SerialLinkedListAdapter(LinkedElement<T>* first, bool printCount = false) : SerialLinkedListAdapter(LinkedElement<T>* first, bool printCount = false) :
SinglyLinkedList<T>(first), printCount(printCount) { SinglyLinkedList<T>(first), printCount(printCount) {
} }
SerialLinkedListAdapter(bool printCount = false) : SerialLinkedListAdapter(bool printCount = false) :
SinglyLinkedList<T>(), printCount(printCount) { SinglyLinkedList<T>(), printCount(printCount) {
} }
@ -49,13 +69,14 @@ public:
uint8_t** buffer, size_t* size, size_t maxSize, uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) { Endianness streamEndianness) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
while ((result == HasReturnvaluesIF::RETURN_OK) && (element != NULL)) { while ((result == HasReturnvaluesIF::RETURN_OK) and (element != nullptr)) {
result = element->value->serialize(buffer, size, maxSize, result = element->value->serialize(buffer, size, maxSize,
streamEndianness); streamEndianness);
element = element->getNext(); element = element->getNext();
} }
return result; return result;
} }
virtual size_t getSerializedSize() const override { virtual size_t getSerializedSize() const override {
if (printCount) { if (printCount) {
return SerialLinkedListAdapter<T>::getSerializedSize() return SerialLinkedListAdapter<T>::getSerializedSize()
@ -64,32 +85,44 @@ public:
return getSerializedSize(SinglyLinkedList<T>::start); return getSerializedSize(SinglyLinkedList<T>::start);
} }
} }
static size_t getSerializedSize(const LinkedElement<T> *element) { static size_t getSerializedSize(const LinkedElement<T> *element) {
size_t size = 0; size_t size = 0;
while (element != NULL) { while (element != nullptr) {
size += element->value->getSerializedSize(); size += element->value->getSerializedSize();
element = element->getNext(); element = element->getNext();
} }
return size; return size;
} }
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override { Endianness streamEndianness) override {
return deSerialize(SinglyLinkedList<T>::start, buffer, size, streamEndianness); return deSerialize(SinglyLinkedList<T>::start, buffer, size,
streamEndianness);
} }
static ReturnValue_t deSerialize(LinkedElement<T>* element, static ReturnValue_t deSerialize(LinkedElement<T>* element,
const uint8_t** buffer, size_t* size, Endianness streamEndianness) { const uint8_t** buffer, size_t* size, Endianness streamEndianness) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
while ((result == HasReturnvaluesIF::RETURN_OK) && (element != NULL)) { while ((result == HasReturnvaluesIF::RETURN_OK) and (element != nullptr)) {
result = element->value->deSerialize(buffer, size, streamEndianness); result = element->value->deSerialize(buffer, size, streamEndianness);
element = element->getNext(); element = element->getNext();
} }
return result; return result;
} }
bool printCount; /**
* Copying is forbidden by deleting the copy constructor and the copy
* assignment operator because of the pointers to the linked list members.
* Unless the child class implements an own copy constructor or
* copy assignment operator, these operation will throw a compiler error.
* @param
*/
SerialLinkedListAdapter(const SerialLinkedListAdapter &) = delete;
SerialLinkedListAdapter& operator=(const SerialLinkedListAdapter&) = delete;
bool printCount;
}; };
#endif /* SERIALLINKEDLISTADAPTER_H_ */ #endif /* FSFW_SERIALIZE_SERIALLINKEDLISTADAPTER_H_ */

View File

@ -7,17 +7,26 @@
#include <cstddef> #include <cstddef>
#include <type_traits> #include <type_traits>
/** /**
* \ingroup serialize * @brief These adapters provides an interface to use the SerializeIF functions
* with arbitrary template objects to facilitate and simplify the
* serialization of classes with different multiple different data types
* into buffers and vice-versa.
* @details
* The correct serialization or deserialization function is chosen at
* compile time with template type deduction.
*
* @ingroup serialize
*/ */
class SerializeAdapter { class SerializeAdapter {
public: public:
/*** /***
* This function can be used to serialize a trivial copy-able type or a child of SerializeIF. * This function can be used to serialize a trivial copy-able type or a
* child of SerializeIF.
* The right template to be called is determined in the function itself. * The right template to be called is determined in the function itself.
* For objects of non trivial copy-able type this function is almost never called by the user directly. * For objects of non trivial copy-able type this function is almost never
* Instead helpers for specific types like SerialArrayListAdapter or SerialLinkedListAdapter is the right choice here. * called by the user directly. Instead helpers for specific types like
* SerialArrayListAdapter or SerialLinkedListAdapter is the right choice here.
* *
* @param[in] object Object to serialize, the used type is deduced from this pointer * @param[in] object Object to serialize, the used type is deduced from this pointer
* @param[in/out] buffer Buffer to serialize into. Will be moved by the function. * @param[in/out] buffer Buffer to serialize into. Will be moved by the function.
@ -86,7 +95,8 @@ private:
template<typename T> template<typename T>
class InternalSerializeAdapter<T, false> { class InternalSerializeAdapter<T, false> {
static_assert (std::is_trivially_copyable<T>::value, static_assert (std::is_trivially_copyable<T>::value,
"If a type needs to be serialized it must be a child of SerializeIF or trivially copy-able"); "If a type needs to be serialized it must be a child of "
"SerializeIF or trivially copy-able");
public: public:
static ReturnValue_t serialize(const T *object, uint8_t **buffer, static ReturnValue_t serialize(const T *object, uint8_t **buffer,
size_t *size, size_t max_size, size_t *size, size_t max_size,
@ -95,7 +105,8 @@ private:
if (size == nullptr) { if (size == nullptr) {
size = &ignoredSize; size = &ignoredSize;
} }
//Check remaining size is large enough and check integer overflow of *size // Check remaining size is large enough and check integer
// overflow of *size
size_t newSize = sizeof(T) + *size; size_t newSize = sizeof(T) + *size;
if ((newSize <= max_size) and (newSize > *size)) { if ((newSize <= max_size) and (newSize > *size)) {
T tmp; T tmp;
@ -111,7 +122,7 @@ private:
tmp = *object; tmp = *object;
break; break;
} }
memcpy(*buffer, &tmp, sizeof(T)); std::memcpy(*buffer, &tmp, sizeof(T));
*size += sizeof(T); *size += sizeof(T);
(*buffer) += sizeof(T); (*buffer) += sizeof(T);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
@ -125,7 +136,7 @@ private:
T tmp; T tmp;
if (*size >= sizeof(T)) { if (*size >= sizeof(T)) {
*size -= sizeof(T); *size -= sizeof(T);
memcpy(&tmp, *buffer, sizeof(T)); std::memcpy(&tmp, *buffer, sizeof(T));
switch (streamEndianness) { switch (streamEndianness) {
case SerializeIF::Endianness::BIG: case SerializeIF::Endianness::BIG:
*object = EndianConverter::convertBigEndian<T>(tmp); *object = EndianConverter::convertBigEndian<T>(tmp);

View File

@ -1,12 +1,20 @@
#ifndef SERIALIZEELEMENT_H_ #ifndef FSFW_SERIALIZE_SERIALIZEELEMENT_H_
#define SERIALIZEELEMENT_H_ #define FSFW_SERIALIZE_SERIALIZEELEMENT_H_
#include "../container/SinglyLinkedList.h"
#include "SerializeAdapter.h" #include "SerializeAdapter.h"
#include "../container/SinglyLinkedList.h"
#include <utility> #include <utility>
/** /**
* \ingroup serialize * @brief This class is used to mark datatypes for serialization with the
* SerialLinkedListAdapter
* @details
* Used by declaring any arbitrary datatype with SerializeElement<T> myVariable,
* inside a SerialLinkedListAdapter implementation and setting the sequence
* of objects with setNext() and setStart().
* Serialization and Deserialization is then performed automatically in
* specified sequence order.
* @ingroup serialize
*/ */
template<typename T> template<typename T>
class SerializeElement: public SerializeIF, public LinkedElement<SerializeIF> { class SerializeElement: public SerializeIF, public LinkedElement<SerializeIF> {
@ -19,7 +27,7 @@ public:
SerializeElement() : SerializeElement() :
LinkedElement<SerializeIF>(this) { LinkedElement<SerializeIF>(this) {
} }
T entry;
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const override { Endianness streamEndianness) const override {
return SerializeAdapter::serialize(&entry, buffer, size, maxSize, return SerializeAdapter::serialize(&entry, buffer, size, maxSize,
@ -35,6 +43,7 @@ public:
return SerializeAdapter::deSerialize(&entry, buffer, size, return SerializeAdapter::deSerialize(&entry, buffer, size,
streamEndianness); streamEndianness);
} }
operator T() { operator T() {
return entry; return entry;
} }
@ -43,9 +52,12 @@ public:
entry = newValue; entry = newValue;
return *this; return *this;
} }
T* operator->() { T* operator->() {
return &entry; return &entry;
} }
T entry;
}; };
#endif /* SERIALIZEELEMENT_H_ */ #endif /* FSFW_SERIALIZE_SERIALIZEELEMENT_H_ */

View File

@ -2,7 +2,7 @@
#define FSFW_SERIALIZE_SERIALIZEIF_H_ #define FSFW_SERIALIZE_SERIALIZEIF_H_
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include <stddef.h> #include <cstddef>
/** /**
* @defgroup serialize Serialization * @defgroup serialize Serialization
@ -10,7 +10,10 @@
*/ */
/** /**
* Translation of objects into data streams and from data streams. * @brief Translation of objects into data streams and from data streams.
* @details
* Also provides options to convert from/to data with different endianness.
* variables.
* @ingroup serialize * @ingroup serialize
*/ */
class SerializeIF { class SerializeIF {

View File

@ -1,50 +1,50 @@
#ifndef FSFW_TASKS_SEMAPHOREFACTORY_H_ #ifndef FSFW_TASKS_SEMAPHOREFACTORY_H_
#define FSFW_TASKS_SEMAPHOREFACTORY_H_ #define FSFW_TASKS_SEMAPHOREFACTORY_H_
#include "../tasks/SemaphoreIF.h" #include "../tasks/SemaphoreIF.h"
/** /**
* Creates Semaphore. * Creates Semaphore.
* This class is a "singleton" interface, i.e. it provides an * This class is a "singleton" interface, i.e. it provides an
* interface, but also is the base class for a singleton. * interface, but also is the base class for a singleton.
*/ */
class SemaphoreFactory { class SemaphoreFactory {
public: public:
virtual ~SemaphoreFactory(); virtual ~SemaphoreFactory();
/** /**
* Returns the single instance of SemaphoreFactory. * Returns the single instance of SemaphoreFactory.
* The implementation of #instance is found in its subclasses. * The implementation of #instance is found in its subclasses.
* Thus, we choose link-time variability of the instance. * Thus, we choose link-time variability of the instance.
*/ */
static SemaphoreFactory* instance(); static SemaphoreFactory* instance();
/** /**
* Create a binary semaphore. * Create a binary semaphore.
* Creator function for a binary semaphore which may only be acquired once * Creator function for a binary semaphore which may only be acquired once
* @param argument Can be used to pass implementation specific information. * @param argument Can be used to pass implementation specific information.
* @return Pointer to newly created semaphore class instance. * @return Pointer to newly created semaphore class instance.
*/ */
SemaphoreIF* createBinarySemaphore(uint32_t arguments = 0); SemaphoreIF* createBinarySemaphore(uint32_t arguments = 0);
/** /**
* Create a counting semaphore. * Create a counting semaphore.
* Creator functons for a counting semaphore which may be acquired multiple * Creator functons for a counting semaphore which may be acquired multiple
* times. * times.
* @param count Semaphore can be taken count times. * @param count Semaphore can be taken count times.
* @param initCount Initial count value. * @param initCount Initial count value.
* @param argument Can be used to pass implementation specific information. * @param argument Can be used to pass implementation specific information.
* @return * @return
*/ */
SemaphoreIF* createCountingSemaphore(const uint8_t maxCount, SemaphoreIF* createCountingSemaphore(const uint8_t maxCount,
uint8_t initCount, uint32_t arguments = 0); uint8_t initCount, uint32_t arguments = 0);
void deleteSemaphore(SemaphoreIF* semaphore); void deleteSemaphore(SemaphoreIF* semaphore);
private: private:
/** /**
* External instantiation is not allowed. * External instantiation is not allowed.
*/ */
SemaphoreFactory(); SemaphoreFactory();
static SemaphoreFactory* factoryInstance; static SemaphoreFactory* factoryInstance;
}; };
#endif /* FSFW_TASKS_SEMAPHOREFACTORY_H_ */ #endif /* FSFW_TASKS_SEMAPHOREFACTORY_H_ */

View File

@ -1,68 +1,68 @@
#ifndef FRAMEWORK_TASKS_SEMAPHOREIF_H_ #ifndef FRAMEWORK_TASKS_SEMAPHOREIF_H_
#define FRAMEWORK_TASKS_SEMAPHOREIF_H_ #define FRAMEWORK_TASKS_SEMAPHOREIF_H_
#include "../returnvalues/FwClassIds.h" #include "../returnvalues/FwClassIds.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include <cstdint> #include <cstdint>
/** /**
* @brief Generic interface for semaphores, which can be used to achieve * @brief Generic interface for semaphores, which can be used to achieve
* task synchronization. This is a generic interface which can be * task synchronization. This is a generic interface which can be
* used for both binary semaphores and counting semaphores. * used for both binary semaphores and counting semaphores.
* @details * @details
* A semaphore is a synchronization primitive. * A semaphore is a synchronization primitive.
* See: https://en.wikipedia.org/wiki/Semaphore_(programming) * See: https://en.wikipedia.org/wiki/Semaphore_(programming)
* A semaphore can be used to achieve task synchonization and track the * A semaphore can be used to achieve task synchonization and track the
* availability of resources by using either the binary or the counting * availability of resources by using either the binary or the counting
* semaphore types. * semaphore types.
* *
* If mutual exlcusion of a resource is desired, a mutex should be used, * If mutual exlcusion of a resource is desired, a mutex should be used,
* which is a special form of a semaphore and has an own interface. * which is a special form of a semaphore and has an own interface.
*/ */
class SemaphoreIF { class SemaphoreIF {
public: public:
/** /**
* Different types of timeout for the mutex lock. * Different types of timeout for the mutex lock.
*/ */
enum TimeoutType { enum TimeoutType {
POLLING, //!< If mutex is not available, return immediately POLLING, //!< If mutex is not available, return immediately
WAITING, //!< Wait a specified time for the mutex to become available WAITING, //!< Wait a specified time for the mutex to become available
BLOCKING //!< Block indefinitely until the mutex becomes available. BLOCKING //!< Block indefinitely until the mutex becomes available.
}; };
virtual~ SemaphoreIF() {}; virtual~ SemaphoreIF() {};
static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF;
//! Semaphore timeout //! Semaphore timeout
static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1); static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1);
//! The current semaphore can not be given, because it is not owned //! The current semaphore can not be given, because it is not owned
static constexpr ReturnValue_t SEMAPHORE_NOT_OWNED = MAKE_RETURN_CODE(2); static constexpr ReturnValue_t SEMAPHORE_NOT_OWNED = MAKE_RETURN_CODE(2);
static constexpr ReturnValue_t SEMAPHORE_INVALID = MAKE_RETURN_CODE(3); static constexpr ReturnValue_t SEMAPHORE_INVALID = MAKE_RETURN_CODE(3);
/** /**
* Generic call to acquire a semaphore. * Generic call to acquire a semaphore.
* If there are no more semaphores to be taken (for a counting semaphore, * If there are no more semaphores to be taken (for a counting semaphore,
* a semaphore may be taken more than once), the taks will block * a semaphore may be taken more than once), the taks will block
* for a maximum of timeoutMs while trying to acquire the semaphore. * for a maximum of timeoutMs while trying to acquire the semaphore.
* This can be used to achieve task synchrnization. * This can be used to achieve task synchrnization.
* @param timeoutMs * @param timeoutMs
* @return - c RETURN_OK for successfull acquisition * @return - c RETURN_OK for successfull acquisition
*/ */
virtual ReturnValue_t acquire(TimeoutType timeoutType = virtual ReturnValue_t acquire(TimeoutType timeoutType =
TimeoutType::BLOCKING, uint32_t timeoutMs = 0) = 0; TimeoutType::BLOCKING, uint32_t timeoutMs = 0) = 0;
/** /**
* Corrensponding call to release a semaphore. * Corrensponding call to release a semaphore.
* @return -@c RETURN_OK for successfull release * @return -@c RETURN_OK for successfull release
*/ */
virtual ReturnValue_t release() = 0; virtual ReturnValue_t release() = 0;
/** /**
* If the semaphore is a counting semaphore then the semaphores current * If the semaphore is a counting semaphore then the semaphores current
* count value is returned. If the semaphore is a binary semaphore then 1 * count value is returned. If the semaphore is a binary semaphore then 1
* is returned if the semaphore is available, and 0 is returned if the * is returned if the semaphore is available, and 0 is returned if the
* semaphore is not available. * semaphore is not available.
*/ */
virtual uint8_t getSemaphoreCounter() const = 0; virtual uint8_t getSemaphoreCounter() const = 0;
}; };
#endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */ #endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */

View File

@ -1,7 +1,8 @@
#include "CCSDSTime.h" #include "../timemanager/CCSDSTime.h"
#include <stdio.h> #include <cstdio>
#include <inttypes.h> #include <cinttypes>
#include <math.h> #include <cmath>
CCSDSTime::CCSDSTime() { CCSDSTime::CCSDSTime() {
} }

View File

@ -5,7 +5,7 @@
#include "Clock.h" #include "Clock.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include <stdint.h> #include <cstdint>
bool operator<(const timeval& lhs, const timeval& rhs); bool operator<(const timeval& lhs, const timeval& rhs);
bool operator<=(const timeval& lhs, const timeval& rhs); bool operator<=(const timeval& lhs, const timeval& rhs);

View File

@ -9,8 +9,7 @@
#include <sys/time.h> #include <sys/time.h>
//! Don't use these for time points, type is not large enough for UNIX epoch. //! Don't use these for time points, type is not large enough for UNIX epoch.
typedef uint32_t dur_millis_t; using dur_millis_t = uint32_t;
typedef double dur_seconds_t;
class Clock { class Clock {
public: public:

View File

@ -6,19 +6,22 @@ Stopwatch::Stopwatch(bool displayOnDestruction,
StopwatchDisplayMode displayMode): displayOnDestruction( StopwatchDisplayMode displayMode): displayOnDestruction(
displayOnDestruction), displayMode(displayMode) { displayOnDestruction), displayMode(displayMode) {
// Measures start time on initialization. // Measures start time on initialization.
Clock::getClock_timeval(&startTime); Clock::getUptime(&startTime);
} }
void Stopwatch::start() { void Stopwatch::start() {
Clock::getClock_timeval(&startTime); Clock::getUptime(&startTime);
} }
dur_millis_t Stopwatch::stop() { dur_millis_t Stopwatch::stop(bool display) {
stopInternal(); stopInternal();
if(display) {
this->display();
}
return elapsedTime.tv_sec * 1000 + elapsedTime.tv_usec / 1000; return elapsedTime.tv_sec * 1000 + elapsedTime.tv_usec / 1000;
} }
dur_seconds_t Stopwatch::stopSeconds() { double Stopwatch::stopSeconds() {
stopInternal(); stopInternal();
return timevalOperations::toDouble(elapsedTime); return timevalOperations::toDouble(elapsedTime);
} }
@ -52,6 +55,6 @@ StopwatchDisplayMode Stopwatch::getDisplayMode() const {
void Stopwatch::stopInternal() { void Stopwatch::stopInternal() {
timeval endTime; timeval endTime;
Clock::getClock_timeval(&endTime); Clock::getUptime(&endTime);
elapsedTime = endTime - startTime; elapsedTime = endTime - startTime;
} }

View File

@ -1,5 +1,6 @@
#ifndef FRAMEWORK_TIMEMANAGER_STOPWATCH_H_ #ifndef FSFW_TIMEMANAGER_STOPWATCH_H_
#define FRAMEWORK_TIMEMANAGER_STOPWATCH_H_ #define FSFW_TIMEMANAGER_STOPWATCH_H_
#include "Clock.h" #include "Clock.h"
enum class StopwatchDisplayMode { enum class StopwatchDisplayMode {
@ -40,12 +41,12 @@ public:
* Calculates the elapsed time since start and returns it * Calculates the elapsed time since start and returns it
* @return elapsed time in milliseconds (rounded) * @return elapsed time in milliseconds (rounded)
*/ */
dur_millis_t stop(); dur_millis_t stop(bool display = false);
/** /**
* Calculates the elapsed time since start and returns it * Calculates the elapsed time since start and returns it
* @return elapsed time in seconds (double precision) * @return elapsed time in seconds (double precision)
*/ */
dur_seconds_t stopSeconds(); double stopSeconds();
/** /**
* Displays the elapsed times on the osstream, depending on internal display * Displays the elapsed times on the osstream, depending on internal display
@ -66,6 +67,4 @@ private:
}; };
#endif /* FSFW_TIMEMANAGER_STOPWATCH_H_ */
#endif /* FRAMEWORK_TIMEMANAGER_STOPWATCH_H_ */

View File

@ -0,0 +1,23 @@
#include "TimeStamper.h"
#include "Clock.h"
#include <cstring>
TimeStamper::TimeStamper(object_id_t objectId): SystemObject(objectId) {}
ReturnValue_t TimeStamper::addTimeStamp(uint8_t* buffer,
const uint8_t maxSize) {
if(maxSize < TimeStamperIF::MISSION_TIMESTAMP_SIZE){
return HasReturnvaluesIF::RETURN_FAILED;
}
timeval now;
Clock::getClock_timeval(&now);
CCSDSTime::CDS_short cds;
ReturnValue_t result = CCSDSTime::convertToCcsds(&cds,&now);
if(result != HasReturnvaluesIF::RETURN_OK){
return result;
}
std::memcpy(buffer,&cds,sizeof(cds));
return result;
}

36
timemanager/TimeStamper.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef FSFW_TIMEMANAGER_TIMESTAMPER_H_
#define FSFW_TIMEMANAGER_TIMESTAMPER_H_
#include "TimeStamperIF.h"
#include "CCSDSTime.h"
#include "../objectmanager/SystemObject.h"
/**
* @brief Time stamper which can be used to add any timestamp to a
* given buffer.
* @details
* This time stamper uses the CCSDS CDC short timestamp as a fault timestamp.
* This timestamp has a size of 8 bytes. A custom timestamp can be used by
* overriding the #addTimeStamp function.
* @ingroup utility
*/
class TimeStamper: public TimeStamperIF, public SystemObject {
public:
/**
* @brief Default constructor which also registers the time stamper as a
* system object so it can be found with the #objectManager.
* @param objectId
*/
TimeStamper(object_id_t objectId);
/**
* Adds a CCSDS CDC short 8 byte timestamp to the given buffer.
* This function can be overriden to use a custom timestamp.
* @param buffer
* @param maxSize
* @return
*/
virtual ReturnValue_t addTimeStamp(uint8_t* buffer, const uint8_t maxSize);
};
#endif /* FSFW_TIMEMANAGER_TIMESTAMPER_H_ */

View File

@ -384,7 +384,7 @@ void CommandingServiceBase::acceptPacket(uint8_t reportId,
} }
void CommandingServiceBase::checkAndExecuteFifo(CommandMapIter iter) { void CommandingServiceBase::checkAndExecuteFifo(CommandMapIter& iter) {
store_address_t address; store_address_t address;
if (iter->second.fifo.retrieve(&address) != RETURN_OK) { if (iter->second.fifo.retrieve(&address) != RETURN_OK) {
commandMap.erase(&iter); commandMap.erase(&iter);

View File

@ -39,7 +39,11 @@ class CommandingServiceBase: public SystemObject,
public HasReturnvaluesIF { public HasReturnvaluesIF {
friend void (Factory::setStaticFrameworkObjectIds)(); friend void (Factory::setStaticFrameworkObjectIds)();
public: public:
// We could make this configurable via preprocessor and the FSFWConfig file.
static constexpr uint8_t COMMAND_INFO_FIFO_DEPTH = 3;
static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_SERVICE_BASE; static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_SERVICE_BASE;
static const ReturnValue_t EXECUTION_COMPLETE = MAKE_RETURN_CODE(1); static const ReturnValue_t EXECUTION_COMPLETE = MAKE_RETURN_CODE(1);
static const ReturnValue_t NO_STEP_MESSAGE = MAKE_RETURN_CODE(2); static const ReturnValue_t NO_STEP_MESSAGE = MAKE_RETURN_CODE(2);
static const ReturnValue_t OBJECT_BUSY = MAKE_RETURN_CODE(3); static const ReturnValue_t OBJECT_BUSY = MAKE_RETURN_CODE(3);
@ -223,7 +227,7 @@ protected:
uint32_t state; uint32_t state;
Command_t command; Command_t command;
object_id_t objectId; object_id_t objectId;
FIFO<store_address_t, 3> fifo; FIFO<store_address_t, COMMAND_INFO_FIFO_DEPTH> fifo;
virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size,
size_t maxSize, Endianness streamEndianness) const override{ size_t maxSize, Endianness streamEndianness) const override{
@ -235,7 +239,7 @@ protected:
}; };
virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) override{ Endianness streamEndianness) override {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
}; };
}; };
@ -312,7 +316,7 @@ protected:
ReturnValue_t sendTmPacket(uint8_t subservice, SerializeIF* content, ReturnValue_t sendTmPacket(uint8_t subservice, SerializeIF* content,
SerializeIF* header = nullptr); SerializeIF* header = nullptr);
void checkAndExecuteFifo(CommandMapIter iter); void checkAndExecuteFifo(CommandMapIter& iter);
private: private:
/** /**