diff --git a/action/ActionHelper.cpp b/action/ActionHelper.cpp index b43c676d..361f7dc3 100644 --- a/action/ActionHelper.cpp +++ b/action/ActionHelper.cpp @@ -1,5 +1,6 @@ #include "ActionHelper.h" #include "HasActionsIF.h" +#include "../ipc/MessageQueueSenderIF.h" #include "../objectmanager/ObjectManagerIF.h" ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue) : diff --git a/container/RingBufferBase.h b/container/RingBufferBase.h index e3a87d9d..886b9fab 100644 --- a/container/RingBufferBase.h +++ b/container/RingBufferBase.h @@ -1,96 +1,113 @@ -#ifndef FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_ -#define FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_ +#ifndef FSFW_CONTAINER_RINGBUFFERBASE_H_ +#define FSFW_CONTAINER_RINGBUFFERBASE_H_ #include "../returnvalues/HasReturnvaluesIF.h" +#include template class RingBufferBase { public: - RingBufferBase(uint32_t startAddress, uint32_t size, bool overwriteOld) : - start(startAddress), write(startAddress), size(size), overwriteOld(overwriteOld) { + RingBufferBase(size_t startAddress, const size_t size, bool overwriteOld) : + start(startAddress), write(startAddress), size(size), + overwriteOld(overwriteOld) { for (uint8_t count = 0; count < N_READ_PTRS; count++) { read[count] = startAddress; } } - ReturnValue_t readData(uint32_t amount, uint8_t n = 0) { - if (availableReadData(n) >= amount) { - 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); - } + + virtual ~RingBufferBase() {} + bool isFull(uint8_t n = 0) { return (availableWriteSpace(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 { - return read[n]; + size_t availableWriteSpace(uint8_t n = 0) const { + //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)) { - this->read[n] = read; - } + + bool overwritesOld() const { + return overwriteOld; } - uint32_t getWrite() const { - return write; - } - void setWrite(uint32_t write) { - this->write = write; + + size_t getMaxSize() const { + return size - 1; } + void clear() { write = start; for (uint8_t count = 0; count < N_READ_PTRS; count++) { read[count] = start; } } - uint32_t writeTillWrap() { + + size_t writeTillWrap() { return (start + size) - write; } - uint32_t readTillWrap(uint8_t n = 0) { + + size_t readTillWrap(uint8_t n = 0) { return (start + size) - read[n]; } - uint32_t getStart() const { + + size_t getStart() const { return start; } - bool overwritesOld() const { - return overwriteOld; - } - uint32_t maxSize() const { - return size - 1; - } + protected: - const uint32_t start; - uint32_t write; - uint32_t read[N_READ_PTRS]; - const uint32_t size; + const size_t start; + size_t write; + size_t read[N_READ_PTRS]; + const size_t size; const bool overwriteOld; + void incrementWrite(uint32_t amount) { write = ((write + amount - start) % size) + start; } void incrementRead(uint32_t amount, uint8_t n = 0) { 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_ */ diff --git a/container/SharedRingBuffer.cpp b/container/SharedRingBuffer.cpp new file mode 100644 index 00000000..800e75d3 --- /dev/null +++ b/container/SharedRingBuffer.cpp @@ -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; +} diff --git a/container/SharedRingBuffer.h b/container/SharedRingBuffer.h new file mode 100644 index 00000000..80c068b3 --- /dev/null +++ b/container/SharedRingBuffer.h @@ -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_ */ diff --git a/container/SimpleRingBuffer.cpp b/container/SimpleRingBuffer.cpp index 30e70514..88c9290e 100644 --- a/container/SimpleRingBuffer.cpp +++ b/container/SimpleRingBuffer.cpp @@ -1,27 +1,69 @@ #include "SimpleRingBuffer.h" -#include +#include -SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld) : - RingBufferBase<>(0, size, overwriteOld) { - buffer = new uint8_t[size]; +SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld, + size_t maxExcessBytes) : + 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, - bool overwriteOld): - RingBufferBase<>(0, size, overwriteOld), buffer(buffer) {} - + bool overwriteOld, size_t maxExcessBytes): + RingBufferBase<>(0, size, overwriteOld), buffer(buffer) { + if(maxExcessBytes > size) { + this->maxExcessBytes = size; + } + else { + this->maxExcessBytes = maxExcessBytes; + } +} SimpleRingBuffer::~SimpleRingBuffer() { 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, - uint32_t amount) { + size_t amount) { if (availableWriteSpace() >= amount or overwriteOld) { - uint32_t amountTillWrap = writeTillWrap(); + size_t amountTillWrap = writeTillWrap(); if (amountTillWrap >= amount) { + // remaining size in buffer is sufficient to fit full amount. memcpy(&buffer[write], data, amount); - } else { + } + else { memcpy(&buffer[write], data, 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, - bool readRemaining, uint32_t* trueAmount) { - uint32_t availableData = availableReadData(READ_PTR); - uint32_t amountTillWrap = readTillWrap(READ_PTR); +ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, size_t amount, + bool incrementReadPtr, bool readRemaining, size_t* trueAmount) { + size_t availableData = getAvailableReadData(READ_PTR); + size_t amountTillWrap = readTillWrap(READ_PTR); if (availableData < amount) { if (readRemaining) { + // more data available than amount specified. amount = availableData; } else { 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 + amountTillWrap, buffer, amount - amountTillWrap); } + + if(incrementReadPtr) { + deleteData(amount, readRemaining); + } return HasReturnvaluesIF::RETURN_OK; } -ReturnValue_t SimpleRingBuffer::deleteData(uint32_t amount, - bool deleteRemaining, uint32_t* trueAmount) { - uint32_t availableData = availableReadData(READ_PTR); +size_t SimpleRingBuffer::getExcessBytes() const { + return excessBytes; +} + +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 (deleteRemaining) { amount = availableData; @@ -71,4 +129,3 @@ ReturnValue_t SimpleRingBuffer::deleteData(uint32_t amount, incrementRead(amount, READ_PTR); return HasReturnvaluesIF::RETURN_OK; } - diff --git a/container/SimpleRingBuffer.h b/container/SimpleRingBuffer.h index c6a29902..37ad5679 100644 --- a/container/SimpleRingBuffer.h +++ b/container/SimpleRingBuffer.h @@ -1,8 +1,8 @@ -#ifndef FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ -#define FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ +#ifndef FSFW_CONTAINER_SIMPLERINGBUFFER_H_ +#define FSFW_CONTAINER_SIMPLERINGBUFFER_H_ #include "RingBufferBase.h" -#include +#include /** * @brief Circular buffer implementation, useful for buffering @@ -16,53 +16,114 @@ class SimpleRingBuffer: public RingBufferBase<> { public: /** * This constructor allocates a new internal buffer with the supplied 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. * @param buffer * @param size * @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(); /** - * Write to circular buffer and increment write pointer by amount + * Write to circular buffer and increment write pointer by amount. * @param data * @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 */ - 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 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 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 + * - @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, - bool readRemaining = false, uint32_t* trueAmount = nullptr); + ReturnValue_t readData(uint8_t* data, size_t amount, + 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 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 */ - ReturnValue_t deleteData(uint32_t amount, bool deleteRemaining = false, - uint32_t* trueAmount = nullptr); + ReturnValue_t deleteData(size_t amount, bool deleteRemaining = false, + size_t* trueAmount = nullptr); + private: -// static const uint8_t TEMP_READ_PTR = 1; static const uint8_t READ_PTR = 0; uint8_t* buffer = nullptr; + size_t maxExcessBytes; + size_t excessBytes = 0; }; -#endif /* FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ */ +#endif /* FSFW_CONTAINER_SIMPLERINGBUFFER_H_ */ diff --git a/contrib/sgp4/sgp4unit.cpp b/contrib/sgp4/sgp4unit.cpp index 24d63aa9..b707a7a2 100644 --- a/contrib/sgp4/sgp4unit.cpp +++ b/contrib/sgp4/sgp4unit.cpp @@ -1,2090 +1,2090 @@ -/* ---------------------------------------------------------------- -* -* sgp4unit.cpp -* -* this file contains the sgp4 procedures for analytical propagation -* of a satellite. the code was originally released in the 1980 and 1986 -* spacetrack papers. a detailed discussion of the theory and history -* may be found in the 2006 aiaa paper by vallado, crawford, hujsak, -* and kelso. -* -* companion code for -* fundamentals of astrodynamics and applications -* 2007 -* by david vallado -* -* (w) 719-573-2600, email dvallado@agi.com -* -* current : -* 16 nov 07 david vallado -* misc fixes for better compliance -* changes : -* 20 apr 07 david vallado -* misc fixes for constants -* 11 aug 06 david vallado -* chg lyddane choice back to strn3, constants, misc doc -* 15 dec 05 david vallado -* misc fixes -* 26 jul 05 david vallado -* fixes for paper -* note that each fix is preceded by a -* comment with "sgp4fix" and an explanation of -* what was changed -* 10 aug 04 david vallado -* 2nd printing baseline working -* 14 may 01 david vallado -* 2nd edition baseline -* 80 norad -* original baseline -* ---------------------------------------------------------------- */ - -#include "sgp4unit.h" - -const char help = 'n'; -FILE *dbgfile; - -#define pi 3.14159265358979323846 - - -/* ----------- local functions - only ever used internally by sgp4 ---------- */ -static void dpper - ( - double e3, double ee2, double peo, double pgho, double pho, - double pinco, double plo, double se2, double se3, double sgh2, - double sgh3, double sgh4, double sh2, double sh3, double si2, - double si3, double sl2, double sl3, double sl4, double t, - double xgh2, double xgh3, double xgh4, double xh2, double xh3, - double xi2, double xi3, double xl2, double xl3, double xl4, - double zmol, double zmos, double inclo, - char init, - double& ep, double& inclp, double& nodep, double& argpp, double& mp - ); - -static void dscom - ( - double epoch, double ep, double argpp, double tc, double inclp, - double nodep, double np, - double& snodm, double& cnodm, double& sinim, double& cosim, double& sinomm, - double& cosomm,double& day, double& e3, double& ee2, double& em, - double& emsq, double& gam, double& peo, double& pgho, double& pho, - double& pinco, double& plo, double& rtemsq, double& se2, double& se3, - double& sgh2, double& sgh3, double& sgh4, double& sh2, double& sh3, - double& si2, double& si3, double& sl2, double& sl3, double& sl4, - double& s1, double& s2, double& s3, double& s4, double& s5, - double& s6, double& s7, double& ss1, double& ss2, double& ss3, - double& ss4, double& ss5, double& ss6, double& ss7, double& sz1, - double& sz2, double& sz3, double& sz11, double& sz12, double& sz13, - double& sz21, double& sz22, double& sz23, double& sz31, double& sz32, - double& sz33, double& xgh2, double& xgh3, double& xgh4, double& xh2, - double& xh3, double& xi2, double& xi3, double& xl2, double& xl3, - double& xl4, double& nm, double& z1, double& z2, double& z3, - double& z11, double& z12, double& z13, double& z21, double& z22, - double& z23, double& z31, double& z32, double& z33, double& zmol, - double& zmos - ); - -static void dsinit - ( - gravconsttype whichconst, - double cosim, double emsq, double argpo, double s1, double s2, - double s3, double s4, double s5, double sinim, double ss1, - double ss2, double ss3, double ss4, double ss5, double sz1, - double sz3, double sz11, double sz13, double sz21, double sz23, - double sz31, double sz33, double t, double tc, double gsto, - double mo, double mdot, double no, double nodeo, double nodedot, - double xpidot, double z1, double z3, double z11, double z13, - double z21, double z23, double z31, double z33, double ecco, - double eccsq, double& em, double& argpm, double& inclm, double& mm, - double& nm, double& nodem, - int& irez, - double& atime, double& d2201, double& d2211, double& d3210, double& d3222, - double& d4410, double& d4422, double& d5220, double& d5232, double& d5421, - double& d5433, double& dedt, double& didt, double& dmdt, double& dndt, - double& dnodt, double& domdt, double& del1, double& del2, double& del3, - double& xfact, double& xlamo, double& xli, double& xni - ); - -static void dspace - ( - int irez, - double d2201, double d2211, double d3210, double d3222, double d4410, - double d4422, double d5220, double d5232, double d5421, double d5433, - double dedt, double del1, double del2, double del3, double didt, - double dmdt, double dnodt, double domdt, double argpo, double argpdot, - double t, double tc, double gsto, double xfact, double xlamo, - double no, - double& atime, double& em, double& argpm, double& inclm, double& xli, - double& mm, double& xni, double& nodem, double& dndt, double& nm - ); - -static void initl - ( - int satn, gravconsttype whichconst, - double ecco, double epoch, double inclo, double& no, - char& method, - double& ainv, double& ao, double& con41, double& con42, double& cosio, - double& cosio2,double& eccsq, double& omeosq, double& posq, - double& rp, double& rteosq,double& sinio , double& gsto - ); - -/* ----------------------------------------------------------------------------- -* -* procedure dpper -* -* this procedure provides deep space long period periodic contributions -* to the mean elements. by design, these periodics are zero at epoch. -* this used to be dscom which included initialization, but it's really a -* recurring function. -* -* author : david vallado 719-573-2600 28 jun 2005 -* -* inputs : -* e3 - -* ee2 - -* peo - -* pgho - -* pho - -* pinco - -* plo - -* se2 , se3 , sgh2, sgh3, sgh4, sh2, sh3, si2, si3, sl2, sl3, sl4 - -* t - -* xh2, xh3, xi2, xi3, xl2, xl3, xl4 - -* zmol - -* zmos - -* ep - eccentricity 0.0 - 1.0 -* inclo - inclination - needed for lyddane modification -* nodep - right ascension of ascending node -* argpp - argument of perigee -* mp - mean anomaly -* -* outputs : -* ep - eccentricity 0.0 - 1.0 -* inclp - inclination -* nodep - right ascension of ascending node -* argpp - argument of perigee -* mp - mean anomaly -* -* locals : -* alfdp - -* betdp - -* cosip , sinip , cosop , sinop , -* dalf - -* dbet - -* dls - -* f2, f3 - -* pe - -* pgh - -* ph - -* pinc - -* pl - -* sel , ses , sghl , sghs , shl , shs , sil , sinzf , sis , -* sll , sls -* xls - -* xnoh - -* zf - -* zm - -* -* coupling : -* none. -* -* references : -* hoots, roehrich, norad spacetrack report #3 1980 -* hoots, norad spacetrack report #6 1986 -* hoots, schumacher and glover 2004 -* vallado, crawford, hujsak, kelso 2006 - ----------------------------------------------------------------------------*/ - -static void dpper - ( - double e3, double ee2, double peo, double pgho, double pho, - double pinco, double plo, double se2, double se3, double sgh2, - double sgh3, double sgh4, double sh2, double sh3, double si2, - double si3, double sl2, double sl3, double sl4, double t, - double xgh2, double xgh3, double xgh4, double xh2, double xh3, - double xi2, double xi3, double xl2, double xl3, double xl4, - double zmol, double zmos, double inclo, - char init, - double& ep, double& inclp, double& nodep, double& argpp, double& mp - ) -{ - /* --------------------- local variables ------------------------ */ - const double twopi = 2.0 * pi; - double alfdp, betdp, cosip, cosop, dalf, dbet, dls, - f2, f3, pe, pgh, ph, pinc, pl , - sel, ses, sghl, sghs, shll, shs, sil, - sinip, sinop, sinzf, sis, sll, sls, xls, - xnoh, zf, zm, zel, zes, znl, zns; - - /* ---------------------- constants ----------------------------- */ - zns = 1.19459e-5; - zes = 0.01675; - znl = 1.5835218e-4; - zel = 0.05490; - - /* --------------- calculate time varying periodics ----------- */ - zm = zmos + zns * t; - // be sure that the initial call has time set to zero - if (init == 'y') - zm = zmos; - zf = zm + 2.0 * zes * sin(zm); - sinzf = sin(zf); - f2 = 0.5 * sinzf * sinzf - 0.25; - f3 = -0.5 * sinzf * cos(zf); - ses = se2* f2 + se3 * f3; - sis = si2 * f2 + si3 * f3; - sls = sl2 * f2 + sl3 * f3 + sl4 * sinzf; - sghs = sgh2 * f2 + sgh3 * f3 + sgh4 * sinzf; - shs = sh2 * f2 + sh3 * f3; - zm = zmol + znl * t; - if (init == 'y') - zm = zmol; - zf = zm + 2.0 * zel * sin(zm); - sinzf = sin(zf); - f2 = 0.5 * sinzf * sinzf - 0.25; - f3 = -0.5 * sinzf * cos(zf); - sel = ee2 * f2 + e3 * f3; - sil = xi2 * f2 + xi3 * f3; - sll = xl2 * f2 + xl3 * f3 + xl4 * sinzf; - sghl = xgh2 * f2 + xgh3 * f3 + xgh4 * sinzf; - shll = xh2 * f2 + xh3 * f3; - pe = ses + sel; - pinc = sis + sil; - pl = sls + sll; - pgh = sghs + sghl; - ph = shs + shll; - - if (init == 'n') - { - pe = pe - peo; - pinc = pinc - pinco; - pl = pl - plo; - pgh = pgh - pgho; - ph = ph - pho; - inclp = inclp + pinc; - ep = ep + pe; - sinip = sin(inclp); - cosip = cos(inclp); - - /* ----------------- apply periodics directly ------------ */ - // sgp4fix for lyddane choice - // strn3 used original inclination - this is technically feasible - // gsfc used perturbed inclination - also technically feasible - // probably best to readjust the 0.2 limit value and limit discontinuity - // 0.2 rad = 11.45916 deg - // use next line for original strn3 approach and original inclination - // if (inclo >= 0.2) - // use next line for gsfc version and perturbed inclination - if (inclp >= 0.2) - { - ph = ph / sinip; - pgh = pgh - cosip * ph; - argpp = argpp + pgh; - nodep = nodep + ph; - mp = mp + pl; - } - else - { - /* ---- apply periodics with lyddane modification ---- */ - sinop = sin(nodep); - cosop = cos(nodep); - alfdp = sinip * sinop; - betdp = sinip * cosop; - dalf = ph * cosop + pinc * cosip * sinop; - dbet = -ph * sinop + pinc * cosip * cosop; - alfdp = alfdp + dalf; - betdp = betdp + dbet; - nodep = fmod(nodep, twopi); - // sgp4fix for afspc written intrinsic functions - // nodep used without a trigonometric function ahead - if (nodep < 0.0) - nodep = nodep + twopi; - xls = mp + argpp + cosip * nodep; - dls = pl + pgh - pinc * nodep * sinip; - xls = xls + dls; - xnoh = nodep; - nodep = atan2(alfdp, betdp); - // sgp4fix for afspc written intrinsic functions - // nodep used without a trigonometric function ahead - if (nodep < 0.0) - nodep = nodep + twopi; - if (fabs(xnoh - nodep) > pi){ - if (nodep < xnoh) - nodep = nodep + twopi; - else - nodep = nodep - twopi; - } - mp = mp + pl; - argpp = xls - mp - cosip * nodep; - } - } // if init == 'n' - -//#include "debug1.cpp" -} // end dpper - -/*----------------------------------------------------------------------------- -* -* procedure dscom -* -* this procedure provides deep space common items used by both the secular -* and periodics subroutines. input is provided as shown. this routine -* used to be called dpper, but the functions inside weren't well organized. -* -* author : david vallado 719-573-2600 28 jun 2005 -* -* inputs : -* epoch - -* ep - eccentricity -* argpp - argument of perigee -* tc - -* inclp - inclination -* nodep - right ascension of ascending node -* np - mean motion -* -* outputs : -* sinim , cosim , sinomm , cosomm , snodm , cnodm -* day - -* e3 - -* ee2 - -* em - eccentricity -* emsq - eccentricity squared -* gam - -* peo - -* pgho - -* pho - -* pinco - -* plo - -* rtemsq - -* se2, se3 - -* sgh2, sgh3, sgh4 - -* sh2, sh3, si2, si3, sl2, sl3, sl4 - -* s1, s2, s3, s4, s5, s6, s7 - -* ss1, ss2, ss3, ss4, ss5, ss6, ss7, sz1, sz2, sz3 - -* sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33 - -* xgh2, xgh3, xgh4, xh2, xh3, xi2, xi3, xl2, xl3, xl4 - -* nm - mean motion -* z1, z2, z3, z11, z12, z13, z21, z22, z23, z31, z32, z33 - -* zmol - -* zmos - -* -* locals : -* a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 - -* betasq - -* cc - -* ctem, stem - -* x1, x2, x3, x4, x5, x6, x7, x8 - -* xnodce - -* xnoi - -* zcosg , zsing , zcosgl , zsingl , zcosh , zsinh , zcoshl , zsinhl , -* zcosi , zsini , zcosil , zsinil , -* zx - -* zy - -* -* coupling : -* none. -* -* references : -* hoots, roehrich, norad spacetrack report #3 1980 -* hoots, norad spacetrack report #6 1986 -* hoots, schumacher and glover 2004 -* vallado, crawford, hujsak, kelso 2006 - ----------------------------------------------------------------------------*/ - -static void dscom - ( - double epoch, double ep, double argpp, double tc, double inclp, - double nodep, double np, - double& snodm, double& cnodm, double& sinim, double& cosim, double& sinomm, - double& cosomm,double& day, double& e3, double& ee2, double& em, - double& emsq, double& gam, double& peo, double& pgho, double& pho, - double& pinco, double& plo, double& rtemsq, double& se2, double& se3, - double& sgh2, double& sgh3, double& sgh4, double& sh2, double& sh3, - double& si2, double& si3, double& sl2, double& sl3, double& sl4, - double& s1, double& s2, double& s3, double& s4, double& s5, - double& s6, double& s7, double& ss1, double& ss2, double& ss3, - double& ss4, double& ss5, double& ss6, double& ss7, double& sz1, - double& sz2, double& sz3, double& sz11, double& sz12, double& sz13, - double& sz21, double& sz22, double& sz23, double& sz31, double& sz32, - double& sz33, double& xgh2, double& xgh3, double& xgh4, double& xh2, - double& xh3, double& xi2, double& xi3, double& xl2, double& xl3, - double& xl4, double& nm, double& z1, double& z2, double& z3, - double& z11, double& z12, double& z13, double& z21, double& z22, - double& z23, double& z31, double& z32, double& z33, double& zmol, - double& zmos - ) -{ - /* -------------------------- constants ------------------------- */ - const double zes = 0.01675; - const double zel = 0.05490; - const double c1ss = 2.9864797e-6; - const double c1l = 4.7968065e-7; - const double zsinis = 0.39785416; - const double zcosis = 0.91744867; - const double zcosgs = 0.1945905; - const double zsings = -0.98088458; - const double twopi = 2.0 * pi; - - /* --------------------- local variables ------------------------ */ - int lsflg; - double a1 , a2 , a3 , a4 , a5 , a6 , a7 , - a8 , a9 , a10 , betasq, cc , ctem , stem , - x1 , x2 , x3 , x4 , x5 , x6 , x7 , - x8 , xnodce, xnoi , zcosg , zcosgl, zcosh , zcoshl, - zcosi , zcosil, zsing , zsingl, zsinh , zsinhl, zsini , - zsinil, zx , zy; - - nm = np; - em = ep; - snodm = sin(nodep); - cnodm = cos(nodep); - sinomm = sin(argpp); - cosomm = cos(argpp); - sinim = sin(inclp); - cosim = cos(inclp); - emsq = em * em; - betasq = 1.0 - emsq; - rtemsq = sqrt(betasq); - - /* ----------------- initialize lunar solar terms --------------- */ - peo = 0.0; - pinco = 0.0; - plo = 0.0; - pgho = 0.0; - pho = 0.0; - day = epoch + 18261.5 + tc / 1440.0; - xnodce = fmod(4.5236020 - 9.2422029e-4 * day, twopi); - stem = sin(xnodce); - ctem = cos(xnodce); - zcosil = 0.91375164 - 0.03568096 * ctem; - zsinil = sqrt(1.0 - zcosil * zcosil); - zsinhl = 0.089683511 * stem / zsinil; - zcoshl = sqrt(1.0 - zsinhl * zsinhl); - gam = 5.8351514 + 0.0019443680 * day; - zx = 0.39785416 * stem / zsinil; - zy = zcoshl * ctem + 0.91744867 * zsinhl * stem; - zx = atan2(zx, zy); - zx = gam + zx - xnodce; - zcosgl = cos(zx); - zsingl = sin(zx); - - /* ------------------------- do solar terms --------------------- */ - zcosg = zcosgs; - zsing = zsings; - zcosi = zcosis; - zsini = zsinis; - zcosh = cnodm; - zsinh = snodm; - cc = c1ss; - xnoi = 1.0 / nm; - - for (lsflg = 1; lsflg <= 2; lsflg++) - { - a1 = zcosg * zcosh + zsing * zcosi * zsinh; - a3 = -zsing * zcosh + zcosg * zcosi * zsinh; - a7 = -zcosg * zsinh + zsing * zcosi * zcosh; - a8 = zsing * zsini; - a9 = zsing * zsinh + zcosg * zcosi * zcosh; - a10 = zcosg * zsini; - a2 = cosim * a7 + sinim * a8; - a4 = cosim * a9 + sinim * a10; - a5 = -sinim * a7 + cosim * a8; - a6 = -sinim * a9 + cosim * a10; - - x1 = a1 * cosomm + a2 * sinomm; - x2 = a3 * cosomm + a4 * sinomm; - x3 = -a1 * sinomm + a2 * cosomm; - x4 = -a3 * sinomm + a4 * cosomm; - x5 = a5 * sinomm; - x6 = a6 * sinomm; - x7 = a5 * cosomm; - x8 = a6 * cosomm; - - z31 = 12.0 * x1 * x1 - 3.0 * x3 * x3; - z32 = 24.0 * x1 * x2 - 6.0 * x3 * x4; - z33 = 12.0 * x2 * x2 - 3.0 * x4 * x4; - z1 = 3.0 * (a1 * a1 + a2 * a2) + z31 * emsq; - z2 = 6.0 * (a1 * a3 + a2 * a4) + z32 * emsq; - z3 = 3.0 * (a3 * a3 + a4 * a4) + z33 * emsq; - z11 = -6.0 * a1 * a5 + emsq * (-24.0 * x1 * x7-6.0 * x3 * x5); - z12 = -6.0 * (a1 * a6 + a3 * a5) + emsq * - (-24.0 * (x2 * x7 + x1 * x8) - 6.0 * (x3 * x6 + x4 * x5)); - z13 = -6.0 * a3 * a6 + emsq * (-24.0 * x2 * x8 - 6.0 * x4 * x6); - z21 = 6.0 * a2 * a5 + emsq * (24.0 * x1 * x5 - 6.0 * x3 * x7); - z22 = 6.0 * (a4 * a5 + a2 * a6) + emsq * - (24.0 * (x2 * x5 + x1 * x6) - 6.0 * (x4 * x7 + x3 * x8)); - z23 = 6.0 * a4 * a6 + emsq * (24.0 * x2 * x6 - 6.0 * x4 * x8); - z1 = z1 + z1 + betasq * z31; - z2 = z2 + z2 + betasq * z32; - z3 = z3 + z3 + betasq * z33; - s3 = cc * xnoi; - s2 = -0.5 * s3 / rtemsq; - s4 = s3 * rtemsq; - s1 = -15.0 * em * s4; - s5 = x1 * x3 + x2 * x4; - s6 = x2 * x3 + x1 * x4; - s7 = x2 * x4 - x1 * x3; - - /* ----------------------- do lunar terms ------------------- */ - if (lsflg == 1) - { - ss1 = s1; - ss2 = s2; - ss3 = s3; - ss4 = s4; - ss5 = s5; - ss6 = s6; - ss7 = s7; - sz1 = z1; - sz2 = z2; - sz3 = z3; - sz11 = z11; - sz12 = z12; - sz13 = z13; - sz21 = z21; - sz22 = z22; - sz23 = z23; - sz31 = z31; - sz32 = z32; - sz33 = z33; - zcosg = zcosgl; - zsing = zsingl; - zcosi = zcosil; - zsini = zsinil; - zcosh = zcoshl * cnodm + zsinhl * snodm; - zsinh = snodm * zcoshl - cnodm * zsinhl; - cc = c1l; - } - } - - zmol = fmod(4.7199672 + 0.22997150 * day - gam, twopi); - zmos = fmod(6.2565837 + 0.017201977 * day, twopi); - - /* ------------------------ do solar terms ---------------------- */ - se2 = 2.0 * ss1 * ss6; - se3 = 2.0 * ss1 * ss7; - si2 = 2.0 * ss2 * sz12; - si3 = 2.0 * ss2 * (sz13 - sz11); - sl2 = -2.0 * ss3 * sz2; - sl3 = -2.0 * ss3 * (sz3 - sz1); - sl4 = -2.0 * ss3 * (-21.0 - 9.0 * emsq) * zes; - sgh2 = 2.0 * ss4 * sz32; - sgh3 = 2.0 * ss4 * (sz33 - sz31); - sgh4 = -18.0 * ss4 * zes; - sh2 = -2.0 * ss2 * sz22; - sh3 = -2.0 * ss2 * (sz23 - sz21); - - /* ------------------------ do lunar terms ---------------------- */ - ee2 = 2.0 * s1 * s6; - e3 = 2.0 * s1 * s7; - xi2 = 2.0 * s2 * z12; - xi3 = 2.0 * s2 * (z13 - z11); - xl2 = -2.0 * s3 * z2; - xl3 = -2.0 * s3 * (z3 - z1); - xl4 = -2.0 * s3 * (-21.0 - 9.0 * emsq) * zel; - xgh2 = 2.0 * s4 * z32; - xgh3 = 2.0 * s4 * (z33 - z31); - xgh4 = -18.0 * s4 * zel; - xh2 = -2.0 * s2 * z22; - xh3 = -2.0 * s2 * (z23 - z21); - -//#include "debug2.cpp" -} // end dscom - -/*----------------------------------------------------------------------------- -* -* procedure dsinit -* -* this procedure provides deep space contributions to mean motion dot due -* to geopotential resonance with half day and one day orbits. -* -* author : david vallado 719-573-2600 28 jun 2005 -* -* inputs : -* cosim, sinim- -* emsq - eccentricity squared -* argpo - argument of perigee -* s1, s2, s3, s4, s5 - -* ss1, ss2, ss3, ss4, ss5 - -* sz1, sz3, sz11, sz13, sz21, sz23, sz31, sz33 - -* t - time -* tc - -* gsto - greenwich sidereal time rad -* mo - mean anomaly -* mdot - mean anomaly dot (rate) -* no - mean motion -* nodeo - right ascension of ascending node -* nodedot - right ascension of ascending node dot (rate) -* xpidot - -* z1, z3, z11, z13, z21, z23, z31, z33 - -* eccm - eccentricity -* argpm - argument of perigee -* inclm - inclination -* mm - mean anomaly -* xn - mean motion -* nodem - right ascension of ascending node -* -* outputs : -* em - eccentricity -* argpm - argument of perigee -* inclm - inclination -* mm - mean anomaly -* nm - mean motion -* nodem - right ascension of ascending node -* irez - flag for resonance 0-none, 1-one day, 2-half day -* atime - -* d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433 - -* dedt - -* didt - -* dmdt - -* dndt - -* dnodt - -* domdt - -* del1, del2, del3 - -* ses , sghl , sghs , sgs , shl , shs , sis , sls -* theta - -* xfact - -* xlamo - -* xli - -* xni -* -* locals : -* ainv2 - -* aonv - -* cosisq - -* eoc - -* f220, f221, f311, f321, f322, f330, f441, f442, f522, f523, f542, f543 - -* g200, g201, g211, g300, g310, g322, g410, g422, g520, g521, g532, g533 - -* sini2 - -* temp - -* temp1 - -* theta - -* xno2 - -* -* coupling : -* getgravconst -* -* references : -* hoots, roehrich, norad spacetrack report #3 1980 -* hoots, norad spacetrack report #6 1986 -* hoots, schumacher and glover 2004 -* vallado, crawford, hujsak, kelso 2006 - ----------------------------------------------------------------------------*/ - -static void dsinit - ( - gravconsttype whichconst, - double cosim, double emsq, double argpo, double s1, double s2, - double s3, double s4, double s5, double sinim, double ss1, - double ss2, double ss3, double ss4, double ss5, double sz1, - double sz3, double sz11, double sz13, double sz21, double sz23, - double sz31, double sz33, double t, double tc, double gsto, - double mo, double mdot, double no, double nodeo, double nodedot, - double xpidot, double z1, double z3, double z11, double z13, - double z21, double z23, double z31, double z33, double ecco, - double eccsq, double& em, double& argpm, double& inclm, double& mm, - double& nm, double& nodem, - int& irez, - double& atime, double& d2201, double& d2211, double& d3210, double& d3222, - double& d4410, double& d4422, double& d5220, double& d5232, double& d5421, - double& d5433, double& dedt, double& didt, double& dmdt, double& dndt, - double& dnodt, double& domdt, double& del1, double& del2, double& del3, - double& xfact, double& xlamo, double& xli, double& xni - ) -{ - /* --------------------- local variables ------------------------ */ - const double twopi = 2.0 * pi; - - double ainv2 , aonv=0.0, cosisq, eoc, f220 , f221 , f311 , - f321 , f322 , f330 , f441 , f442 , f522 , f523 , - f542 , f543 , g200 , g201 , g211 , g300 , g310 , - g322 , g410 , g422 , g520 , g521 , g532 , g533 , - ses , sgs , sghl , sghs , shs , shll , sis , - sini2 , sls , temp , temp1 , theta , xno2 , q22 , - q31 , q33 , root22, root44, root54, rptim , root32, - root52, x2o3 , xke , znl , emo , zns , emsqo, - tumin, mu, radiusearthkm, j2, j3, j4, j3oj2; - - q22 = 1.7891679e-6; - q31 = 2.1460748e-6; - q33 = 2.2123015e-7; - root22 = 1.7891679e-6; - root44 = 7.3636953e-9; - root54 = 2.1765803e-9; - rptim = 4.37526908801129966e-3; // this equates to 7.29211514668855e-5 rad/sec - root32 = 3.7393792e-7; - root52 = 1.1428639e-7; - x2o3 = 2.0 / 3.0; - znl = 1.5835218e-4; - zns = 1.19459e-5; - - // sgp4fix identify constants and allow alternate values - getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); - - /* -------------------- deep space initialization ------------ */ - irez = 0; - if ((nm < 0.0052359877) && (nm > 0.0034906585)) - irez = 1; - if ((nm >= 8.26e-3) && (nm <= 9.24e-3) && (em >= 0.5)) - irez = 2; - - /* ------------------------ do solar terms ------------------- */ - ses = ss1 * zns * ss5; - sis = ss2 * zns * (sz11 + sz13); - sls = -zns * ss3 * (sz1 + sz3 - 14.0 - 6.0 * emsq); - sghs = ss4 * zns * (sz31 + sz33 - 6.0); - shs = -zns * ss2 * (sz21 + sz23); - // sgp4fix for 180 deg incl - if ((inclm < 5.2359877e-2) || (inclm > pi - 5.2359877e-2)) - shs = 0.0; - if (sinim != 0.0) - shs = shs / sinim; - sgs = sghs - cosim * shs; - - /* ------------------------- do lunar terms ------------------ */ - dedt = ses + s1 * znl * s5; - didt = sis + s2 * znl * (z11 + z13); - dmdt = sls - znl * s3 * (z1 + z3 - 14.0 - 6.0 * emsq); - sghl = s4 * znl * (z31 + z33 - 6.0); - shll = -znl * s2 * (z21 + z23); - // sgp4fix for 180 deg incl - if ((inclm < 5.2359877e-2) || (inclm > pi - 5.2359877e-2)) - shll = 0.0; - domdt = sgs + sghl; - dnodt = shs; - if (sinim != 0.0) - { - domdt = domdt - cosim / sinim * shll; - dnodt = dnodt + shll / sinim; - } - - /* ----------- calculate deep space resonance effects -------- */ - dndt = 0.0; - theta = fmod(gsto + tc * rptim, twopi); - em = em + dedt * t; - inclm = inclm + didt * t; - argpm = argpm + domdt * t; - nodem = nodem + dnodt * t; - mm = mm + dmdt * t; - // sgp4fix for negative inclinations - // the following if statement should be commented out - //if (inclm < 0.0) - // { - // inclm = -inclm; - // argpm = argpm - pi; - // nodem = nodem + pi; - // } - - /* -------------- initialize the resonance terms ------------- */ - if (irez != 0) - { - aonv = pow(nm / xke, x2o3); - - /* ---------- geopotential resonance for 12 hour orbits ------ */ - if (irez == 2) - { - cosisq = cosim * cosim; - emo = em; - em = ecco; - emsqo = emsq; - emsq = eccsq; - eoc = em * emsq; - g201 = -0.306 - (em - 0.64) * 0.440; - - if (em <= 0.65) - { - g211 = 3.616 - 13.2470 * em + 16.2900 * emsq; - g310 = -19.302 + 117.3900 * em - 228.4190 * emsq + 156.5910 * eoc; - g322 = -18.9068 + 109.7927 * em - 214.6334 * emsq + 146.5816 * eoc; - g410 = -41.122 + 242.6940 * em - 471.0940 * emsq + 313.9530 * eoc; - g422 = -146.407 + 841.8800 * em - 1629.014 * emsq + 1083.4350 * eoc; - g520 = -532.114 + 3017.977 * em - 5740.032 * emsq + 3708.2760 * eoc; - } - else - { - g211 = -72.099 + 331.819 * em - 508.738 * emsq + 266.724 * eoc; - g310 = -346.844 + 1582.851 * em - 2415.925 * emsq + 1246.113 * eoc; - g322 = -342.585 + 1554.908 * em - 2366.899 * emsq + 1215.972 * eoc; - g410 = -1052.797 + 4758.686 * em - 7193.992 * emsq + 3651.957 * eoc; - g422 = -3581.690 + 16178.110 * em - 24462.770 * emsq + 12422.520 * eoc; - if (em > 0.715) - g520 =-5149.66 + 29936.92 * em - 54087.36 * emsq + 31324.56 * eoc; - else - g520 = 1464.74 - 4664.75 * em + 3763.64 * emsq; - } - if (em < 0.7) - { - g533 = -919.22770 + 4988.6100 * em - 9064.7700 * emsq + 5542.21 * eoc; - g521 = -822.71072 + 4568.6173 * em - 8491.4146 * emsq + 5337.524 * eoc; - g532 = -853.66600 + 4690.2500 * em - 8624.7700 * emsq + 5341.4 * eoc; - } - else - { - g533 =-37995.780 + 161616.52 * em - 229838.20 * emsq + 109377.94 * eoc; - g521 =-51752.104 + 218913.95 * em - 309468.16 * emsq + 146349.42 * eoc; - g532 =-40023.880 + 170470.89 * em - 242699.48 * emsq + 115605.82 * eoc; - } - - sini2= sinim * sinim; - f220 = 0.75 * (1.0 + 2.0 * cosim+cosisq); - f221 = 1.5 * sini2; - f321 = 1.875 * sinim * (1.0 - 2.0 * cosim - 3.0 * cosisq); - f322 = -1.875 * sinim * (1.0 + 2.0 * cosim - 3.0 * cosisq); - f441 = 35.0 * sini2 * f220; - f442 = 39.3750 * sini2 * sini2; - f522 = 9.84375 * sinim * (sini2 * (1.0 - 2.0 * cosim- 5.0 * cosisq) + - 0.33333333 * (-2.0 + 4.0 * cosim + 6.0 * cosisq) ); - f523 = sinim * (4.92187512 * sini2 * (-2.0 - 4.0 * cosim + - 10.0 * cosisq) + 6.56250012 * (1.0+2.0 * cosim - 3.0 * cosisq)); - f542 = 29.53125 * sinim * (2.0 - 8.0 * cosim+cosisq * - (-12.0 + 8.0 * cosim + 10.0 * cosisq)); - f543 = 29.53125 * sinim * (-2.0 - 8.0 * cosim+cosisq * - (12.0 + 8.0 * cosim - 10.0 * cosisq)); - xno2 = nm * nm; - ainv2 = aonv * aonv; - temp1 = 3.0 * xno2 * ainv2; - temp = temp1 * root22; - d2201 = temp * f220 * g201; - d2211 = temp * f221 * g211; - temp1 = temp1 * aonv; - temp = temp1 * root32; - d3210 = temp * f321 * g310; - d3222 = temp * f322 * g322; - temp1 = temp1 * aonv; - temp = 2.0 * temp1 * root44; - d4410 = temp * f441 * g410; - d4422 = temp * f442 * g422; - temp1 = temp1 * aonv; - temp = temp1 * root52; - d5220 = temp * f522 * g520; - d5232 = temp * f523 * g532; - temp = 2.0 * temp1 * root54; - d5421 = temp * f542 * g521; - d5433 = temp * f543 * g533; - xlamo = fmod(mo + nodeo + nodeo-theta - theta, twopi); - xfact = mdot + dmdt + 2.0 * (nodedot + dnodt - rptim) - no; - em = emo; - emsq = emsqo; - } - - /* ---------------- synchronous resonance terms -------------- */ - if (irez == 1) - { - g200 = 1.0 + emsq * (-2.5 + 0.8125 * emsq); - g310 = 1.0 + 2.0 * emsq; - g300 = 1.0 + emsq * (-6.0 + 6.60937 * emsq); - f220 = 0.75 * (1.0 + cosim) * (1.0 + cosim); - f311 = 0.9375 * sinim * sinim * (1.0 + 3.0 * cosim) - 0.75 * (1.0 + cosim); - f330 = 1.0 + cosim; - f330 = 1.875 * f330 * f330 * f330; - del1 = 3.0 * nm * nm * aonv * aonv; - del2 = 2.0 * del1 * f220 * g200 * q22; - del3 = 3.0 * del1 * f330 * g300 * q33 * aonv; - del1 = del1 * f311 * g310 * q31 * aonv; - xlamo = fmod(mo + nodeo + argpo - theta, twopi); - xfact = mdot + xpidot - rptim + dmdt + domdt + dnodt - no; - } - - /* ------------ for sgp4, initialize the integrator ---------- */ - xli = xlamo; - xni = no; - atime = 0.0; - nm = no + dndt; - } - -//#include "debug3.cpp" -} // end dsinit - -/*----------------------------------------------------------------------------- -* -* procedure dspace -* -* this procedure provides deep space contributions to mean elements for -* perturbing third body. these effects have been averaged over one -* revolution of the sun and moon. for earth resonance effects, the -* effects have been averaged over no revolutions of the satellite. -* (mean motion) -* -* author : david vallado 719-573-2600 28 jun 2005 -* -* inputs : -* d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433 - -* dedt - -* del1, del2, del3 - -* didt - -* dmdt - -* dnodt - -* domdt - -* irez - flag for resonance 0-none, 1-one day, 2-half day -* argpo - argument of perigee -* argpdot - argument of perigee dot (rate) -* t - time -* tc - -* gsto - gst -* xfact - -* xlamo - -* no - mean motion -* atime - -* em - eccentricity -* ft - -* argpm - argument of perigee -* inclm - inclination -* xli - -* mm - mean anomaly -* xni - mean motion -* nodem - right ascension of ascending node -* -* outputs : -* atime - -* em - eccentricity -* argpm - argument of perigee -* inclm - inclination -* xli - -* mm - mean anomaly -* xni - -* nodem - right ascension of ascending node -* dndt - -* nm - mean motion -* -* locals : -* delt - -* ft - -* theta - -* x2li - -* x2omi - -* xl - -* xldot - -* xnddt - -* xndt - -* xomi - -* -* coupling : -* none - -* -* references : -* hoots, roehrich, norad spacetrack report #3 1980 -* hoots, norad spacetrack report #6 1986 -* hoots, schumacher and glover 2004 -* vallado, crawford, hujsak, kelso 2006 - ----------------------------------------------------------------------------*/ - -static void dspace - ( - int irez, - double d2201, double d2211, double d3210, double d3222, double d4410, - double d4422, double d5220, double d5232, double d5421, double d5433, - double dedt, double del1, double del2, double del3, double didt, - double dmdt, double dnodt, double domdt, double argpo, double argpdot, - double t, double tc, double gsto, double xfact, double xlamo, - double no, - double& atime, double& em, double& argpm, double& inclm, double& xli, - double& mm, double& xni, double& nodem, double& dndt, double& nm - ) -{ - const double twopi = 2.0 * pi; - int iretn , iret; - double delt, ft, theta, x2li, x2omi, xl, xldot , xnddt, xndt, xomi, g22, g32, - g44, g52, g54, fasx2, fasx4, fasx6, rptim , step2, stepn , stepp; - - ft = 0.0; - fasx2 = 0.13130908; - fasx4 = 2.8843198; - fasx6 = 0.37448087; - g22 = 5.7686396; - g32 = 0.95240898; - g44 = 1.8014998; - g52 = 1.0508330; - g54 = 4.4108898; - rptim = 4.37526908801129966e-3; // this equates to 7.29211514668855e-5 rad/sec - stepp = 720.0; - stepn = -720.0; - step2 = 259200.0; - - /* ----------- calculate deep space resonance effects ----------- */ - dndt = 0.0; - theta = fmod(gsto + tc * rptim, twopi); - em = em + dedt * t; - - inclm = inclm + didt * t; - argpm = argpm + domdt * t; - nodem = nodem + dnodt * t; - mm = mm + dmdt * t; - - // sgp4fix for negative inclinations - // the following if statement should be commented out - // if (inclm < 0.0) - // { - // inclm = -inclm; - // argpm = argpm - pi; - // nodem = nodem + pi; - // } - - /* - update resonances : numerical (euler-maclaurin) integration - */ - /* ------------------------- epoch restart ---------------------- */ - // sgp4fix for propagator problems - // the following integration works for negative time steps and periods - // the specific changes are unknown because the original code was so convoluted - - ft = 0.0; - atime = 0.0; - if (irez != 0) - { - if ((atime == 0.0) || ((t >= 0.0) && (atime < 0.0)) || - ((t < 0.0) && (atime >= 0.0))) - { - if (t >= 0.0) - delt = stepp; - else - delt = stepn; - atime = 0.0; - xni = no; - xli = xlamo; - } - iretn = 381; // added for do loop - iret = 0; // added for loop - while (iretn == 381) - { - if ((fabs(t) < fabs(atime)) || (iret == 351)) - { - if (t >= 0.0) - delt = stepn; - else - delt = stepp; - iret = 351; - iretn = 381; - } - else - { - if (t > 0.0) // error if prev if has atime:=0.0 and t:=0.0 (ge) - delt = stepp; - else - delt = stepn; - if (fabs(t - atime) >= stepp) - { - iret = 0; - iretn = 381; - } - else - { - ft = t - atime; - iretn = 0; - } - } - - /* ------------------- dot terms calculated ------------- */ - /* ----------- near - synchronous resonance terms ------- */ - if (irez != 2) - { - xndt = del1 * sin(xli - fasx2) + del2 * sin(2.0 * (xli - fasx4)) + - del3 * sin(3.0 * (xli - fasx6)); - xldot = xni + xfact; - xnddt = del1 * cos(xli - fasx2) + - 2.0 * del2 * cos(2.0 * (xli - fasx4)) + - 3.0 * del3 * cos(3.0 * (xli - fasx6)); - xnddt = xnddt * xldot; - } - else - { - /* --------- near - half-day resonance terms -------- */ - xomi = argpo + argpdot * atime; - x2omi = xomi + xomi; - x2li = xli + xli; - xndt = d2201 * sin(x2omi + xli - g22) + d2211 * sin(xli - g22) + - d3210 * sin(xomi + xli - g32) + d3222 * sin(-xomi + xli - g32)+ - d4410 * sin(x2omi + x2li - g44)+ d4422 * sin(x2li - g44) + - d5220 * sin(xomi + xli - g52) + d5232 * sin(-xomi + xli - g52)+ - d5421 * sin(xomi + x2li - g54) + d5433 * sin(-xomi + x2li - g54); - xldot = xni + xfact; - xnddt = d2201 * cos(x2omi + xli - g22) + d2211 * cos(xli - g22) + - d3210 * cos(xomi + xli - g32) + d3222 * cos(-xomi + xli - g32) + - d5220 * cos(xomi + xli - g52) + d5232 * cos(-xomi + xli - g52) + - 2.0 * (d4410 * cos(x2omi + x2li - g44) + - d4422 * cos(x2li - g44) + d5421 * cos(xomi + x2li - g54) + - d5433 * cos(-xomi + x2li - g54)); - xnddt = xnddt * xldot; - } - - /* ----------------------- integrator ------------------- */ - if (iretn == 381) - { - xli = xli + xldot * delt + xndt * step2; - xni = xni + xndt * delt + xnddt * step2; - atime = atime + delt; - } - } // while iretn = 381 - - nm = xni + xndt * ft + xnddt * ft * ft * 0.5; - xl = xli + xldot * ft + xndt * ft * ft * 0.5; - if (irez != 1) - { - mm = xl - 2.0 * nodem + 2.0 * theta; - dndt = nm - no; - } - else - { - mm = xl - nodem - argpm + theta; - dndt = nm - no; - } - nm = no + dndt; - } - -//#include "debug4.cpp" -} // end dsspace - -/*----------------------------------------------------------------------------- -* -* procedure initl -* -* this procedure initializes the spg4 propagator. all the initialization is -* consolidated here instead of having multiple loops inside other routines. -* -* author : david vallado 719-573-2600 28 jun 2005 -* -* inputs : -* ecco - eccentricity 0.0 - 1.0 -* epoch - epoch time in days from jan 0, 1950. 0 hr -* inclo - inclination of satellite -* no - mean motion of satellite -* satn - satellite number -* -* outputs : -* ainv - 1.0 / a -* ao - semi major axis -* con41 - -* con42 - 1.0 - 5.0 cos(i) -* cosio - cosine of inclination -* cosio2 - cosio squared -* eccsq - eccentricity squared -* method - flag for deep space 'd', 'n' -* omeosq - 1.0 - ecco * ecco -* posq - semi-parameter squared -* rp - radius of perigee -* rteosq - square root of (1.0 - ecco*ecco) -* sinio - sine of inclination -* gsto - gst at time of observation rad -* no - mean motion of satellite -* -* locals : -* ak - -* d1 - -* del - -* adel - -* po - -* -* coupling : -* getgravconst -* gstime - find greenwich sidereal time from the julian date -* -* references : -* hoots, roehrich, norad spacetrack report #3 1980 -* hoots, norad spacetrack report #6 1986 -* hoots, schumacher and glover 2004 -* vallado, crawford, hujsak, kelso 2006 - ----------------------------------------------------------------------------*/ - -static void initl - ( - int satn, gravconsttype whichconst, - double ecco, double epoch, double inclo, double& no, - char& method, - double& ainv, double& ao, double& con41, double& con42, double& cosio, - double& cosio2,double& eccsq, double& omeosq, double& posq, - double& rp, double& rteosq,double& sinio , double& gsto - ) -{ - /* --------------------- local variables ------------------------ */ - double ak, d1, del, adel, po, x2o3, j2, xke, - tumin, mu, radiusearthkm, j3, j4, j3oj2; - - // sgp4fix use old way of finding gst - int ids70; - double ts70, ds70, tfrac, c1, thgr70, fk5r, c1p2p; - const double twopi = 2.0 * pi; - - /* ----------------------- earth constants ---------------------- */ - // sgp4fix identify constants and allow alternate values - getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); - x2o3 = 2.0 / 3.0; - - /* ------------- calculate auxillary epoch quantities ---------- */ - eccsq = ecco * ecco; - omeosq = 1.0 - eccsq; - rteosq = sqrt(omeosq); - cosio = cos(inclo); - cosio2 = cosio * cosio; - - /* ------------------ un-kozai the mean motion ----------------- */ - ak = pow(xke / no, x2o3); - d1 = 0.75 * j2 * (3.0 * cosio2 - 1.0) / (rteosq * omeosq); - del = d1 / (ak * ak); - adel = ak * (1.0 - del * del - del * - (1.0 / 3.0 + 134.0 * del * del / 81.0)); - del = d1/(adel * adel); - no = no / (1.0 + del); - - ao = pow(xke / no, x2o3); - sinio = sin(inclo); - po = ao * omeosq; - con42 = 1.0 - 5.0 * cosio2; - con41 = -con42-cosio2-cosio2; - ainv = 1.0 / ao; - posq = po * po; - rp = ao * (1.0 - ecco); - method = 'n'; - - // sgp4fix modern approach to finding sidereal timew - // gsto = gstime(epoch + 2433281.5); - - // sgp4fix use old way of finding gst - // count integer number of days from 0 jan 1970 - ts70 = epoch - 7305.0; - ids70 = floor(ts70 + 1.0e-8); - ds70 = ids70; - tfrac = ts70 - ds70; - // find greenwich location at epoch - c1 = 1.72027916940703639e-2; - thgr70= 1.7321343856509374; - fk5r = 5.07551419432269442e-15; - c1p2p = c1 + twopi; - gsto = fmod( thgr70 + c1*ds70 + c1p2p*tfrac + ts70*ts70*fk5r, twopi); - if ( gsto < 0.0 ) - gsto = gsto + twopi; - -//#include "debug5.cpp" -} // end initl - -/*----------------------------------------------------------------------------- -* -* procedure sgp4init -* -* this procedure initializes variables for sgp4. -* -* author : david vallado 719-573-2600 28 jun 2005 -* -* inputs : -* satn - satellite number -* bstar - sgp4 type drag coefficient kg/m2er -* ecco - eccentricity -* epoch - epoch time in days from jan 0, 1950. 0 hr -* argpo - argument of perigee (output if ds) -* inclo - inclination -* mo - mean anomaly (output if ds) -* no - mean motion -* nodeo - right ascension of ascending node -* -* outputs : -* satrec - common values for subsequent calls -* return code - non-zero on error. -* 1 - mean elements, ecc >= 1.0 or ecc < -0.001 or a < 0.95 er -* 2 - mean motion less than 0.0 -* 3 - pert elements, ecc < 0.0 or ecc > 1.0 -* 4 - semi-latus rectum < 0.0 -* 5 - epoch elements are sub-orbital -* 6 - satellite has decayed -* -* locals : -* cnodm , snodm , cosim , sinim , cosomm , sinomm -* cc1sq , cc2 , cc3 -* coef , coef1 -* cosio4 - -* day - -* dndt - -* em - eccentricity -* emsq - eccentricity squared -* eeta - -* etasq - -* gam - -* argpm - argument of perigee -* nodem - -* inclm - inclination -* mm - mean anomaly -* nm - mean motion -* perige - perigee -* pinvsq - -* psisq - -* qzms24 - -* rtemsq - -* s1, s2, s3, s4, s5, s6, s7 - -* sfour - -* ss1, ss2, ss3, ss4, ss5, ss6, ss7 - -* sz1, sz2, sz3 -* sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33 - -* tc - -* temp - -* temp1, temp2, temp3 - -* tsi - -* xpidot - -* xhdot1 - -* z1, z2, z3 - -* z11, z12, z13, z21, z22, z23, z31, z32, z33 - -* -* coupling : -* getgravconst- -* initl - -* dscom - -* dpper - -* dsinit - -* sgp4 - -* -* references : -* hoots, roehrich, norad spacetrack report #3 1980 -* hoots, norad spacetrack report #6 1986 -* hoots, schumacher and glover 2004 -* vallado, crawford, hujsak, kelso 2006 - ----------------------------------------------------------------------------*/ - -int sgp4init - ( - gravconsttype whichconst, const int satn, const double epoch, - const double xbstar, const double xecco, const double xargpo, - const double xinclo, const double xmo, const double xno, - const double xnodeo, elsetrec& satrec - ) -{ - /* --------------------- local variables ------------------------ */ - double ao, ainv, con42, cosio, sinio, cosio2, eccsq, - omeosq, posq, rp, rteosq, - cnodm , snodm , cosim , sinim , cosomm, sinomm, cc1sq , - cc2 , cc3 , coef , coef1 , cosio4, day , dndt , - em , emsq , eeta , etasq , gam , argpm , nodem , - inclm , mm , nm , perige, pinvsq, psisq , qzms24, - rtemsq, s1 , s2 , s3 , s4 , s5 , s6 , - s7 , sfour , ss1 = 0 , ss2 = 0 , ss3 = 0 , ss4 = 0 , ss5 = 0 , - ss6 = 0 , ss7 = 0 , sz1 = 0 , sz2 = 0 , sz3 = 0 , sz11 = 0 , sz12 = 0 , - sz13 = 0 , sz21 = 0 , sz22 = 0 , sz23 = 0 , sz31 = 0 , sz32 = 0 , sz33 = 0 , - tc , temp , temp1 , temp2 , temp3 , tsi , xpidot, - xhdot1, z1 , z2 , z3 , z11 , z12 , z13 , - z21 , z22 , z23 , z31 , z32 , z33, - qzms2t, ss, j2, j3oj2, j4, x2o3, r[3], v[3], - tumin, mu, radiusearthkm, xke, j3; - - /* ------------------------ initialization --------------------- */ - // sgp4fix divisor for divide by zero check on inclination - const double temp4 = 1.0 + cos(pi-1.0e-9); - - /* ----------- set all near earth variables to zero ------------ */ - satrec.isimp = 0; satrec.method = 'n'; satrec.aycof = 0.0; - satrec.con41 = 0.0; satrec.cc1 = 0.0; satrec.cc4 = 0.0; - satrec.cc5 = 0.0; satrec.d2 = 0.0; satrec.d3 = 0.0; - satrec.d4 = 0.0; satrec.delmo = 0.0; satrec.eta = 0.0; - satrec.argpdot = 0.0; satrec.omgcof = 0.0; satrec.sinmao = 0.0; - satrec.t = 0.0; satrec.t2cof = 0.0; satrec.t3cof = 0.0; - satrec.t4cof = 0.0; satrec.t5cof = 0.0; satrec.x1mth2 = 0.0; - satrec.x7thm1 = 0.0; satrec.mdot = 0.0; satrec.nodedot = 0.0; - satrec.xlcof = 0.0; satrec.xmcof = 0.0; satrec.nodecf = 0.0; - - /* ----------- set all deep space variables to zero ------------ */ - satrec.irez = 0; satrec.d2201 = 0.0; satrec.d2211 = 0.0; - satrec.d3210 = 0.0; satrec.d3222 = 0.0; satrec.d4410 = 0.0; - satrec.d4422 = 0.0; satrec.d5220 = 0.0; satrec.d5232 = 0.0; - satrec.d5421 = 0.0; satrec.d5433 = 0.0; satrec.dedt = 0.0; - satrec.del1 = 0.0; satrec.del2 = 0.0; satrec.del3 = 0.0; - satrec.didt = 0.0; satrec.dmdt = 0.0; satrec.dnodt = 0.0; - satrec.domdt = 0.0; satrec.e3 = 0.0; satrec.ee2 = 0.0; - satrec.peo = 0.0; satrec.pgho = 0.0; satrec.pho = 0.0; - satrec.pinco = 0.0; satrec.plo = 0.0; satrec.se2 = 0.0; - satrec.se3 = 0.0; satrec.sgh2 = 0.0; satrec.sgh3 = 0.0; - satrec.sgh4 = 0.0; satrec.sh2 = 0.0; satrec.sh3 = 0.0; - satrec.si2 = 0.0; satrec.si3 = 0.0; satrec.sl2 = 0.0; - satrec.sl3 = 0.0; satrec.sl4 = 0.0; satrec.gsto = 0.0; - satrec.xfact = 0.0; satrec.xgh2 = 0.0; satrec.xgh3 = 0.0; - satrec.xgh4 = 0.0; satrec.xh2 = 0.0; satrec.xh3 = 0.0; - satrec.xi2 = 0.0; satrec.xi3 = 0.0; satrec.xl2 = 0.0; - satrec.xl3 = 0.0; satrec.xl4 = 0.0; satrec.xlamo = 0.0; - satrec.zmol = 0.0; satrec.zmos = 0.0; satrec.atime = 0.0; - satrec.xli = 0.0; satrec.xni = 0.0; - - // sgp4fix - note the following variables are also passed directly via satrec. - // it is possible to streamline the sgp4init call by deleting the "x" - // variables, but the user would need to set the satrec.* values first. we - // include the additional assignments in case twoline2rv is not used. - satrec.bstar = xbstar; - satrec.ecco = xecco; - satrec.argpo = xargpo; - satrec.inclo = xinclo; - satrec.mo = xmo; - satrec.no = xno; - satrec.nodeo = xnodeo; - - /* ------------------------ earth constants ----------------------- */ - // sgp4fix identify constants and allow alternate values - getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); - ss = 78.0 / radiusearthkm + 1.0; - qzms2t = pow(((120.0 - 78.0) / radiusearthkm), 4); - x2o3 = 2.0 / 3.0; - - satrec.init = 'y'; - satrec.t = 0.0; - - initl - ( - satn, whichconst, satrec.ecco, epoch, satrec.inclo, satrec.no, satrec.method, - ainv, ao, satrec.con41, con42, cosio, cosio2, eccsq, omeosq, - posq, rp, rteosq, sinio, satrec.gsto - ); - satrec.error = 0; - - if (rp < 1.0) - { -// printf("# *** satn%d epoch elts sub-orbital ***\n", satn); - satrec.error = 5; - } - - if ((omeosq >= 0.0 ) || ( satrec.no >= 0.0)) - { - satrec.isimp = 0; - if (rp < (220.0 / radiusearthkm + 1.0)) - satrec.isimp = 1; - sfour = ss; - qzms24 = qzms2t; - perige = (rp - 1.0) * radiusearthkm; - - /* - for perigees below 156 km, s and qoms2t are altered - */ - if (perige < 156.0) - { - sfour = perige - 78.0; - if (perige < 98.0) - sfour = 20.0; - qzms24 = pow(((120.0 - sfour) / radiusearthkm), 4.0); - sfour = sfour / radiusearthkm + 1.0; - } - pinvsq = 1.0 / posq; - - tsi = 1.0 / (ao - sfour); - satrec.eta = ao * satrec.ecco * tsi; - etasq = satrec.eta * satrec.eta; - eeta = satrec.ecco * satrec.eta; - psisq = fabs(1.0 - etasq); - coef = qzms24 * pow(tsi, 4.0); - coef1 = coef / pow(psisq, 3.5); - cc2 = coef1 * satrec.no * (ao * (1.0 + 1.5 * etasq + eeta * - (4.0 + etasq)) + 0.375 * j2 * tsi / psisq * satrec.con41 * - (8.0 + 3.0 * etasq * (8.0 + etasq))); - satrec.cc1 = satrec.bstar * cc2; - cc3 = 0.0; - if (satrec.ecco > 1.0e-4) - cc3 = -2.0 * coef * tsi * j3oj2 * satrec.no * sinio / satrec.ecco; - satrec.x1mth2 = 1.0 - cosio2; - satrec.cc4 = 2.0* satrec.no * coef1 * ao * omeosq * - (satrec.eta * (2.0 + 0.5 * etasq) + satrec.ecco * - (0.5 + 2.0 * etasq) - j2 * tsi / (ao * psisq) * - (-3.0 * satrec.con41 * (1.0 - 2.0 * eeta + etasq * - (1.5 - 0.5 * eeta)) + 0.75 * satrec.x1mth2 * - (2.0 * etasq - eeta * (1.0 + etasq)) * cos(2.0 * satrec.argpo))); - satrec.cc5 = 2.0 * coef1 * ao * omeosq * (1.0 + 2.75 * - (etasq + eeta) + eeta * etasq); - cosio4 = cosio2 * cosio2; - temp1 = 1.5 * j2 * pinvsq * satrec.no; - temp2 = 0.5 * temp1 * j2 * pinvsq; - temp3 = -0.46875 * j4 * pinvsq * pinvsq * satrec.no; - satrec.mdot = satrec.no + 0.5 * temp1 * rteosq * satrec.con41 + 0.0625 * - temp2 * rteosq * (13.0 - 78.0 * cosio2 + 137.0 * cosio4); - satrec.argpdot = -0.5 * temp1 * con42 + 0.0625 * temp2 * - (7.0 - 114.0 * cosio2 + 395.0 * cosio4) + - temp3 * (3.0 - 36.0 * cosio2 + 49.0 * cosio4); - xhdot1 = -temp1 * cosio; - satrec.nodedot = xhdot1 + (0.5 * temp2 * (4.0 - 19.0 * cosio2) + - 2.0 * temp3 * (3.0 - 7.0 * cosio2)) * cosio; - xpidot = satrec.argpdot+ satrec.nodedot; - satrec.omgcof = satrec.bstar * cc3 * cos(satrec.argpo); - satrec.xmcof = 0.0; - if (satrec.ecco > 1.0e-4) - satrec.xmcof = -x2o3 * coef * satrec.bstar / eeta; - satrec.nodecf = 3.5 * omeosq * xhdot1 * satrec.cc1; - satrec.t2cof = 1.5 * satrec.cc1; - // sgp4fix for divide by zero with xinco = 180 deg - if (fabs(cosio+1.0) > 1.5e-12) - satrec.xlcof = -0.25 * j3oj2 * sinio * (3.0 + 5.0 * cosio) / (1.0 + cosio); - else - satrec.xlcof = -0.25 * j3oj2 * sinio * (3.0 + 5.0 * cosio) / temp4; - satrec.aycof = -0.5 * j3oj2 * sinio; - satrec.delmo = pow((1.0 + satrec.eta * cos(satrec.mo)), 3); - satrec.sinmao = sin(satrec.mo); - satrec.x7thm1 = 7.0 * cosio2 - 1.0; - - /* --------------- deep space initialization ------------- */ - if ((2*pi / satrec.no) >= 225.0) - { - satrec.method = 'd'; - satrec.isimp = 1; - tc = 0.0; - inclm = satrec.inclo; - - dscom - ( - epoch, satrec.ecco, satrec.argpo, tc, satrec.inclo, satrec.nodeo, - satrec.no, snodm, cnodm, sinim, cosim,sinomm, cosomm, - day, satrec.e3, satrec.ee2, em, emsq, gam, - satrec.peo, satrec.pgho, satrec.pho, satrec.pinco, - satrec.plo, rtemsq, satrec.se2, satrec.se3, - satrec.sgh2, satrec.sgh3, satrec.sgh4, - satrec.sh2, satrec.sh3, satrec.si2, satrec.si3, - satrec.sl2, satrec.sl3, satrec.sl4, s1, s2, s3, s4, s5, - s6, s7, ss1, ss2, ss3, ss4, ss5, ss6, ss7, sz1, sz2, sz3, - sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33, - satrec.xgh2, satrec.xgh3, satrec.xgh4, satrec.xh2, - satrec.xh3, satrec.xi2, satrec.xi3, satrec.xl2, - satrec.xl3, satrec.xl4, nm, z1, z2, z3, z11, - z12, z13, z21, z22, z23, z31, z32, z33, - satrec.zmol, satrec.zmos - ); - dpper - ( - satrec.e3, satrec.ee2, satrec.peo, satrec.pgho, - satrec.pho, satrec.pinco, satrec.plo, satrec.se2, - satrec.se3, satrec.sgh2, satrec.sgh3, satrec.sgh4, - satrec.sh2, satrec.sh3, satrec.si2, satrec.si3, - satrec.sl2, satrec.sl3, satrec.sl4, satrec.t, - satrec.xgh2,satrec.xgh3,satrec.xgh4, satrec.xh2, - satrec.xh3, satrec.xi2, satrec.xi3, satrec.xl2, - satrec.xl3, satrec.xl4, satrec.zmol, satrec.zmos, inclm, satrec.init, - satrec.ecco, satrec.inclo, satrec.nodeo, satrec.argpo, satrec.mo - ); - - argpm = 0.0; - nodem = 0.0; - mm = 0.0; - - dsinit - ( - whichconst, - cosim, emsq, satrec.argpo, s1, s2, s3, s4, s5, sinim, ss1, ss2, ss3, ss4, - ss5, sz1, sz3, sz11, sz13, sz21, sz23, sz31, sz33, satrec.t, tc, - satrec.gsto, satrec.mo, satrec.mdot, satrec.no, satrec.nodeo, - satrec.nodedot, xpidot, z1, z3, z11, z13, z21, z23, z31, z33, - satrec.ecco, eccsq, em, argpm, inclm, mm, nm, nodem, - satrec.irez, satrec.atime, - satrec.d2201, satrec.d2211, satrec.d3210, satrec.d3222 , - satrec.d4410, satrec.d4422, satrec.d5220, satrec.d5232, - satrec.d5421, satrec.d5433, satrec.dedt, satrec.didt, - satrec.dmdt, dndt, satrec.dnodt, satrec.domdt , - satrec.del1, satrec.del2, satrec.del3, satrec.xfact, - satrec.xlamo, satrec.xli, satrec.xni - ); - } - - /* ----------- set variables if not deep space ----------- */ - if (satrec.isimp != 1) - { - cc1sq = satrec.cc1 * satrec.cc1; - satrec.d2 = 4.0 * ao * tsi * cc1sq; - temp = satrec.d2 * tsi * satrec.cc1 / 3.0; - satrec.d3 = (17.0 * ao + sfour) * temp; - satrec.d4 = 0.5 * temp * ao * tsi * (221.0 * ao + 31.0 * sfour) * - satrec.cc1; - satrec.t3cof = satrec.d2 + 2.0 * cc1sq; - satrec.t4cof = 0.25 * (3.0 * satrec.d3 + satrec.cc1 * - (12.0 * satrec.d2 + 10.0 * cc1sq)); - satrec.t5cof = 0.2 * (3.0 * satrec.d4 + - 12.0 * satrec.cc1 * satrec.d3 + - 6.0 * satrec.d2 * satrec.d2 + - 15.0 * cc1sq * (2.0 * satrec.d2 + cc1sq)); - } - } // if omeosq = 0 ... - - /* finally propogate to zero epoch to initialise all others. */ - if(satrec.error == 0) - sgp4(whichconst, satrec, 0.0, r, v); - - satrec.init = 'n'; - -//#include "debug6.cpp" - return satrec.error; -} // end sgp4init - -/*----------------------------------------------------------------------------- -* -* procedure sgp4 -* -* this procedure is the sgp4 prediction model from space command. this is an -* updated and combined version of sgp4 and sdp4, which were originally -* published separately in spacetrack report #3. this version follows the -* methodology from the aiaa paper (2006) describing the history and -* development of the code. -* -* author : david vallado 719-573-2600 28 jun 2005 -* -* inputs : -* satrec - initialised structure from sgp4init() call. -* tsince - time eince epoch (minutes) -* -* outputs : -* r - position vector km -* v - velocity km/sec -* return code - non-zero on error. -* 1 - mean elements, ecc >= 1.0 or ecc < -0.001 or a < 0.95 er -* 2 - mean motion less than 0.0 -* 3 - pert elements, ecc < 0.0 or ecc > 1.0 -* 4 - semi-latus rectum < 0.0 -* 5 - epoch elements are sub-orbital -* 6 - satellite has decayed -* -* locals : -* am - -* axnl, aynl - -* betal - -* cosim , sinim , cosomm , sinomm , cnod , snod , cos2u , -* sin2u , coseo1 , sineo1 , cosi , sini , cosip , sinip , -* cosisq , cossu , sinsu , cosu , sinu -* delm - -* delomg - -* dndt - -* eccm - -* emsq - -* ecose - -* el2 - -* eo1 - -* eccp - -* esine - -* argpm - -* argpp - -* omgadf - -* pl - -* r - -* rtemsq - -* rdotl - -* rl - -* rvdot - -* rvdotl - -* su - -* t2 , t3 , t4 , tc -* tem5, temp , temp1 , temp2 , tempa , tempe , templ -* u , ux , uy , uz , vx , vy , vz -* inclm - inclination -* mm - mean anomaly -* nm - mean motion -* nodem - right asc of ascending node -* xinc - -* xincp - -* xl - -* xlm - -* mp - -* xmdf - -* xmx - -* xmy - -* nodedf - -* xnode - -* nodep - -* np - -* -* coupling : -* getgravconst- -* dpper -* dpspace -* -* references : -* hoots, roehrich, norad spacetrack report #3 1980 -* hoots, norad spacetrack report #6 1986 -* hoots, schumacher and glover 2004 -* vallado, crawford, hujsak, kelso 2006 - ----------------------------------------------------------------------------*/ - -int sgp4 - ( - gravconsttype whichconst, elsetrec& satrec, double tsince, - double r[3], double v[3] - ) -{ - double am , axnl , aynl , betal , cosim , cnod , - cos2u, coseo1, cosi , cosip , cosisq, cossu , cosu, - delm , delomg, em , emsq , ecose , el2 , eo1 , - ep , esine , argpm, argpp , argpdf, pl, mrt = 0.0, - mvt , rdotl , rl , rvdot , rvdotl, sinim , - sin2u, sineo1, sini , sinip , sinsu , sinu , - snod , su , t2 , t3 , t4 , tem5 , temp, - temp1, temp2 , tempa, tempe , templ , u , ux , - uy , uz , vx , vy , vz , inclm , mm , - nm , nodem, xinc , xincp , xl , xlm , mp , - xmdf , xmx , xmy , nodedf, xnode , nodep, tc , dndt, - twopi, x2o3 , j2 , j3 , tumin, j4 , xke , j3oj2, radiusearthkm, - mu, vkmpersec; - int ktr; - - /* ------------------ set mathematical constants --------------- */ - // sgp4fix divisor for divide by zero check on inclination - const double temp4 = 1.0 + cos(pi-1.0e-9); - twopi = 2.0 * pi; - x2o3 = 2.0 / 3.0; - // sgp4fix identify constants and allow alternate values - getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); - vkmpersec = radiusearthkm * xke/60.0; - - /* --------------------- clear sgp4 error flag ----------------- */ - satrec.t = tsince; - satrec.error = 0; - - /* ------- update for secular gravity and atmospheric drag ----- */ - xmdf = satrec.mo + satrec.mdot * satrec.t; - argpdf = satrec.argpo + satrec.argpdot * satrec.t; - nodedf = satrec.nodeo + satrec.nodedot * satrec.t; - argpm = argpdf; - mm = xmdf; - t2 = satrec.t * satrec.t; - nodem = nodedf + satrec.nodecf * t2; - tempa = 1.0 - satrec.cc1 * satrec.t; - tempe = satrec.bstar * satrec.cc4 * satrec.t; - templ = satrec.t2cof * t2; - - if (satrec.isimp != 1) - { - delomg = satrec.omgcof * satrec.t; - delm = satrec.xmcof * - (pow((1.0 + satrec.eta * cos(xmdf)), 3) - - satrec.delmo); - temp = delomg + delm; - mm = xmdf + temp; - argpm = argpdf - temp; - t3 = t2 * satrec.t; - t4 = t3 * satrec.t; - tempa = tempa - satrec.d2 * t2 - satrec.d3 * t3 - - satrec.d4 * t4; - tempe = tempe + satrec.bstar * satrec.cc5 * (sin(mm) - - satrec.sinmao); - templ = templ + satrec.t3cof * t3 + t4 * (satrec.t4cof + - satrec.t * satrec.t5cof); - } - - nm = satrec.no; - em = satrec.ecco; - inclm = satrec.inclo; - if (satrec.method == 'd') - { - tc = satrec.t; - dspace - ( - satrec.irez, - satrec.d2201, satrec.d2211, satrec.d3210, - satrec.d3222, satrec.d4410, satrec.d4422, - satrec.d5220, satrec.d5232, satrec.d5421, - satrec.d5433, satrec.dedt, satrec.del1, - satrec.del2, satrec.del3, satrec.didt, - satrec.dmdt, satrec.dnodt, satrec.domdt, - satrec.argpo, satrec.argpdot, satrec.t, tc, - satrec.gsto, satrec.xfact, satrec.xlamo, - satrec.no, satrec.atime, - em, argpm, inclm, satrec.xli, mm, satrec.xni, - nodem, dndt, nm - ); - } // if method = d - - if (nm <= 0.0) - { -// printf("# error nm %f\n", nm); - satrec.error = 2; - } - am = pow((xke / nm),x2o3) * tempa * tempa; - nm = xke / pow(am, 1.5); - em = em - tempe; - - // fix tolerance for error recognition - if ((em >= 1.0) || (em < -0.001) || (am < 0.95)) - { -// printf("# error em %f\n", em); - satrec.error = 1; - } - if (em < 0.0) - em = 1.0e-6; - mm = mm + satrec.no * templ; - xlm = mm + argpm + nodem; - emsq = em * em; - temp = 1.0 - emsq; - - nodem = fmod(nodem, twopi); - argpm = fmod(argpm, twopi); - xlm = fmod(xlm, twopi); - mm = fmod(xlm - argpm - nodem, twopi); - - /* ----------------- compute extra mean quantities ------------- */ - sinim = sin(inclm); - cosim = cos(inclm); - - /* -------------------- add lunar-solar periodics -------------- */ - ep = em; - xincp = inclm; - argpp = argpm; - nodep = nodem; - mp = mm; - sinip = sinim; - cosip = cosim; - if (satrec.method == 'd') - { - dpper - ( - satrec.e3, satrec.ee2, satrec.peo, - satrec.pgho, satrec.pho, satrec.pinco, - satrec.plo, satrec.se2, satrec.se3, - satrec.sgh2, satrec.sgh3, satrec.sgh4, - satrec.sh2, satrec.sh3, satrec.si2, - satrec.si3, satrec.sl2, satrec.sl3, - satrec.sl4, satrec.t, satrec.xgh2, - satrec.xgh3, satrec.xgh4, satrec.xh2, - satrec.xh3, satrec.xi2, satrec.xi3, - satrec.xl2, satrec.xl3, satrec.xl4, - satrec.zmol, satrec.zmos, satrec.inclo, - 'n', ep, xincp, nodep, argpp, mp - ); - if (xincp < 0.0) - { - xincp = -xincp; - nodep = nodep + pi; - argpp = argpp - pi; - } - if ((ep < 0.0 ) || ( ep > 1.0)) - { - // printf("# error ep %f\n", ep); - satrec.error = 3; - } - } // if method = d - - /* -------------------- long period periodics ------------------ */ - if (satrec.method == 'd') - { - sinip = sin(xincp); - cosip = cos(xincp); - satrec.aycof = -0.5*j3oj2*sinip; - // sgp4fix for divide by zero for xincp = 180 deg - if (fabs(cosip+1.0) > 1.5e-12) - satrec.xlcof = -0.25 * j3oj2 * sinip * (3.0 + 5.0 * cosip) / (1.0 + cosip); - else - satrec.xlcof = -0.25 * j3oj2 * sinip * (3.0 + 5.0 * cosip) / temp4; - } - axnl = ep * cos(argpp); - temp = 1.0 / (am * (1.0 - ep * ep)); - aynl = ep* sin(argpp) + temp * satrec.aycof; - xl = mp + argpp + nodep + temp * satrec.xlcof * axnl; - - /* --------------------- solve kepler's equation --------------- */ - u = fmod(xl - nodep, twopi); - eo1 = u; - tem5 = 9999.9; - ktr = 1; - // sgp4fix for kepler iteration - // the following iteration needs better limits on corrections - while (( fabs(tem5) >= 1.0e-12) && (ktr <= 10) ) - { - sineo1 = sin(eo1); - coseo1 = cos(eo1); - tem5 = 1.0 - coseo1 * axnl - sineo1 * aynl; - tem5 = (u - aynl * coseo1 + axnl * sineo1 - eo1) / tem5; - if(fabs(tem5) >= 0.95) - tem5 = tem5 > 0.0 ? 0.95 : -0.95; - eo1 = eo1 + tem5; - ktr = ktr + 1; - } - - /* ------------- short period preliminary quantities ----------- */ - ecose = axnl*coseo1 + aynl*sineo1; - esine = axnl*sineo1 - aynl*coseo1; - el2 = axnl*axnl + aynl*aynl; - pl = am*(1.0-el2); - if (pl < 0.0) - { -// printf("# error pl %f\n", pl); - satrec.error = 4; - } - else - { - rl = am * (1.0 - ecose); - rdotl = sqrt(am) * esine/rl; - rvdotl = sqrt(pl) / rl; - betal = sqrt(1.0 - el2); - temp = esine / (1.0 + betal); - sinu = am / rl * (sineo1 - aynl - axnl * temp); - cosu = am / rl * (coseo1 - axnl + aynl * temp); - su = atan2(sinu, cosu); - sin2u = (cosu + cosu) * sinu; - cos2u = 1.0 - 2.0 * sinu * sinu; - temp = 1.0 / pl; - temp1 = 0.5 * j2 * temp; - temp2 = temp1 * temp; - - /* -------------- update for short period periodics ------------ */ - if (satrec.method == 'd') - { - cosisq = cosip * cosip; - satrec.con41 = 3.0*cosisq - 1.0; - satrec.x1mth2 = 1.0 - cosisq; - satrec.x7thm1 = 7.0*cosisq - 1.0; - } - mrt = rl * (1.0 - 1.5 * temp2 * betal * satrec.con41) + - 0.5 * temp1 * satrec.x1mth2 * cos2u; - su = su - 0.25 * temp2 * satrec.x7thm1 * sin2u; - xnode = nodep + 1.5 * temp2 * cosip * sin2u; - xinc = xincp + 1.5 * temp2 * cosip * sinip * cos2u; - mvt = rdotl - nm * temp1 * satrec.x1mth2 * sin2u / xke; - rvdot = rvdotl + nm * temp1 * (satrec.x1mth2 * cos2u + - 1.5 * satrec.con41) / xke; - - /* --------------------- orientation vectors ------------------- */ - sinsu = sin(su); - cossu = cos(su); - snod = sin(xnode); - cnod = cos(xnode); - sini = sin(xinc); - cosi = cos(xinc); - xmx = -snod * cosi; - xmy = cnod * cosi; - ux = xmx * sinsu + cnod * cossu; - uy = xmy * sinsu + snod * cossu; - uz = sini * sinsu; - vx = xmx * cossu - cnod * sinsu; - vy = xmy * cossu - snod * sinsu; - vz = sini * cossu; - - /* --------- position and velocity (in km and km/sec) ---------- */ - r[0] = (mrt * ux)* radiusearthkm; - r[1] = (mrt * uy)* radiusearthkm; - r[2] = (mrt * uz)* radiusearthkm; - v[0] = (mvt * ux + rvdot * vx) * vkmpersec; - v[1] = (mvt * uy + rvdot * vy) * vkmpersec; - v[2] = (mvt * uz + rvdot * vz) * vkmpersec; - } // if pl > 0 - - // sgp4fix for decaying satellites - if (mrt < 1.0) - { -// printf("# decay condition %11.6f \n",mrt); - satrec.error = 6; - } - - -//#include "debug7.cpp" - return satrec.error; -} // end sgp4 - - -/* ----------------------------------------------------------------------------- -* -* function gstime -* -* this function finds the greenwich sidereal time. -* -* author : david vallado 719-573-2600 1 mar 2001 -* -* inputs description range / units -* jdut1 - julian date in ut1 days from 4713 bc -* -* outputs : -* gstime - greenwich sidereal time 0 to 2pi rad -* -* locals : -* temp - temporary variable for doubles rad -* tut1 - julian centuries from the -* jan 1, 2000 12 h epoch (ut1) -* -* coupling : -* none -* -* references : -* vallado 2004, 191, eq 3-45 -* --------------------------------------------------------------------------- */ - -double gstime - ( - double jdut1 - ) - { - const double twopi = 2.0 * pi; - const double deg2rad = pi / 180.0; - double temp, tut1; - - tut1 = (jdut1 - 2451545.0) / 36525.0; - temp = -6.2e-6* tut1 * tut1 * tut1 + 0.093104 * tut1 * tut1 + - (876600.0*3600 + 8640184.812866) * tut1 + 67310.54841; // sec - temp = fmod(temp * deg2rad / 240.0, twopi); //360/86400 = 1/240, to deg, to rad - - // ------------------------ check quadrants --------------------- - if (temp < 0.0) - temp += twopi; - - return temp; - } // end gstime - -/* ----------------------------------------------------------------------------- -* -* function getgravconst -* -* this function gets constants for the propagator. note that mu is identified to -* facilitiate comparisons with newer models. the common useage is wgs72. -* -* author : david vallado 719-573-2600 21 jul 2006 -* -* inputs : -* whichconst - which set of constants to use wgs72old, wgs72, wgs84 -* -* outputs : -* tumin - minutes in one time unit -* mu - earth gravitational parameter -* radiusearthkm - radius of the earth in km -* xke - reciprocal of tumin -* j2, j3, j4 - un-normalized zonal harmonic values -* j3oj2 - j3 divided by j2 -* -* locals : -* -* coupling : -* none -* -* references : -* norad spacetrack report #3 -* vallado, crawford, hujsak, kelso 2006 - --------------------------------------------------------------------------- */ - -void getgravconst - ( - gravconsttype whichconst, - double& tumin, - double& mu, - double& radiusearthkm, - double& xke, - double& j2, - double& j3, - double& j4, - double& j3oj2 - ) - { - - switch (whichconst) - { - // -- wgs-72 low precision str#3 constants -- - case wgs72old: - mu = 398600.79964; // in km3 / s2 - radiusearthkm = 6378.135; // km - xke = 0.0743669161; - tumin = 1.0 / xke; - j2 = 0.001082616; - j3 = -0.00000253881; - j4 = -0.00000165597; - j3oj2 = j3 / j2; - break; - // ------------ wgs-72 constants ------------ - case wgs72: - mu = 398600.8; // in km3 / s2 - radiusearthkm = 6378.135; // km - xke = 60.0 / sqrt(radiusearthkm*radiusearthkm*radiusearthkm/mu); - tumin = 1.0 / xke; - j2 = 0.001082616; - j3 = -0.00000253881; - j4 = -0.00000165597; - j3oj2 = j3 / j2; - break; - case wgs84: - // ------------ wgs-84 constants ------------ - mu = 398600.5; // in km3 / s2 - radiusearthkm = 6378.137; // km - xke = 60.0 / sqrt(radiusearthkm*radiusearthkm*radiusearthkm/mu); - tumin = 1.0 / xke; - j2 = 0.00108262998905; - j3 = -0.00000253215306; - j4 = -0.00000161098761; - j3oj2 = j3 / j2; - break; - default: - fprintf(stderr,"unknown gravity option (%d)\n",whichconst); - break; - } - - } // end getgravconst - - - - - +/* ---------------------------------------------------------------- +* +* sgp4unit.cpp +* +* this file contains the sgp4 procedures for analytical propagation +* of a satellite. the code was originally released in the 1980 and 1986 +* spacetrack papers. a detailed discussion of the theory and history +* may be found in the 2006 aiaa paper by vallado, crawford, hujsak, +* and kelso. +* +* companion code for +* fundamentals of astrodynamics and applications +* 2007 +* by david vallado +* +* (w) 719-573-2600, email dvallado@agi.com +* +* current : +* 16 nov 07 david vallado +* misc fixes for better compliance +* changes : +* 20 apr 07 david vallado +* misc fixes for constants +* 11 aug 06 david vallado +* chg lyddane choice back to strn3, constants, misc doc +* 15 dec 05 david vallado +* misc fixes +* 26 jul 05 david vallado +* fixes for paper +* note that each fix is preceded by a +* comment with "sgp4fix" and an explanation of +* what was changed +* 10 aug 04 david vallado +* 2nd printing baseline working +* 14 may 01 david vallado +* 2nd edition baseline +* 80 norad +* original baseline +* ---------------------------------------------------------------- */ + +#include "sgp4unit.h" + +const char help = 'n'; +FILE *dbgfile; + +#define pi 3.14159265358979323846 + + +/* ----------- local functions - only ever used internally by sgp4 ---------- */ +static void dpper + ( + double e3, double ee2, double peo, double pgho, double pho, + double pinco, double plo, double se2, double se3, double sgh2, + double sgh3, double sgh4, double sh2, double sh3, double si2, + double si3, double sl2, double sl3, double sl4, double t, + double xgh2, double xgh3, double xgh4, double xh2, double xh3, + double xi2, double xi3, double xl2, double xl3, double xl4, + double zmol, double zmos, double inclo, + char init, + double& ep, double& inclp, double& nodep, double& argpp, double& mp + ); + +static void dscom + ( + double epoch, double ep, double argpp, double tc, double inclp, + double nodep, double np, + double& snodm, double& cnodm, double& sinim, double& cosim, double& sinomm, + double& cosomm,double& day, double& e3, double& ee2, double& em, + double& emsq, double& gam, double& peo, double& pgho, double& pho, + double& pinco, double& plo, double& rtemsq, double& se2, double& se3, + double& sgh2, double& sgh3, double& sgh4, double& sh2, double& sh3, + double& si2, double& si3, double& sl2, double& sl3, double& sl4, + double& s1, double& s2, double& s3, double& s4, double& s5, + double& s6, double& s7, double& ss1, double& ss2, double& ss3, + double& ss4, double& ss5, double& ss6, double& ss7, double& sz1, + double& sz2, double& sz3, double& sz11, double& sz12, double& sz13, + double& sz21, double& sz22, double& sz23, double& sz31, double& sz32, + double& sz33, double& xgh2, double& xgh3, double& xgh4, double& xh2, + double& xh3, double& xi2, double& xi3, double& xl2, double& xl3, + double& xl4, double& nm, double& z1, double& z2, double& z3, + double& z11, double& z12, double& z13, double& z21, double& z22, + double& z23, double& z31, double& z32, double& z33, double& zmol, + double& zmos + ); + +static void dsinit + ( + gravconsttype whichconst, + double cosim, double emsq, double argpo, double s1, double s2, + double s3, double s4, double s5, double sinim, double ss1, + double ss2, double ss3, double ss4, double ss5, double sz1, + double sz3, double sz11, double sz13, double sz21, double sz23, + double sz31, double sz33, double t, double tc, double gsto, + double mo, double mdot, double no, double nodeo, double nodedot, + double xpidot, double z1, double z3, double z11, double z13, + double z21, double z23, double z31, double z33, double ecco, + double eccsq, double& em, double& argpm, double& inclm, double& mm, + double& nm, double& nodem, + int& irez, + double& atime, double& d2201, double& d2211, double& d3210, double& d3222, + double& d4410, double& d4422, double& d5220, double& d5232, double& d5421, + double& d5433, double& dedt, double& didt, double& dmdt, double& dndt, + double& dnodt, double& domdt, double& del1, double& del2, double& del3, + double& xfact, double& xlamo, double& xli, double& xni + ); + +static void dspace + ( + int irez, + double d2201, double d2211, double d3210, double d3222, double d4410, + double d4422, double d5220, double d5232, double d5421, double d5433, + double dedt, double del1, double del2, double del3, double didt, + double dmdt, double dnodt, double domdt, double argpo, double argpdot, + double t, double tc, double gsto, double xfact, double xlamo, + double no, + double& atime, double& em, double& argpm, double& inclm, double& xli, + double& mm, double& xni, double& nodem, double& dndt, double& nm + ); + +static void initl + ( + int satn, gravconsttype whichconst, + double ecco, double epoch, double inclo, double& no, + char& method, + double& ainv, double& ao, double& con41, double& con42, double& cosio, + double& cosio2,double& eccsq, double& omeosq, double& posq, + double& rp, double& rteosq,double& sinio , double& gsto + ); + +/* ----------------------------------------------------------------------------- +* +* procedure dpper +* +* this procedure provides deep space long period periodic contributions +* to the mean elements. by design, these periodics are zero at epoch. +* this used to be dscom which included initialization, but it's really a +* recurring function. +* +* author : david vallado 719-573-2600 28 jun 2005 +* +* inputs : +* e3 - +* ee2 - +* peo - +* pgho - +* pho - +* pinco - +* plo - +* se2 , se3 , sgh2, sgh3, sgh4, sh2, sh3, si2, si3, sl2, sl3, sl4 - +* t - +* xh2, xh3, xi2, xi3, xl2, xl3, xl4 - +* zmol - +* zmos - +* ep - eccentricity 0.0 - 1.0 +* inclo - inclination - needed for lyddane modification +* nodep - right ascension of ascending node +* argpp - argument of perigee +* mp - mean anomaly +* +* outputs : +* ep - eccentricity 0.0 - 1.0 +* inclp - inclination +* nodep - right ascension of ascending node +* argpp - argument of perigee +* mp - mean anomaly +* +* locals : +* alfdp - +* betdp - +* cosip , sinip , cosop , sinop , +* dalf - +* dbet - +* dls - +* f2, f3 - +* pe - +* pgh - +* ph - +* pinc - +* pl - +* sel , ses , sghl , sghs , shl , shs , sil , sinzf , sis , +* sll , sls +* xls - +* xnoh - +* zf - +* zm - +* +* coupling : +* none. +* +* references : +* hoots, roehrich, norad spacetrack report #3 1980 +* hoots, norad spacetrack report #6 1986 +* hoots, schumacher and glover 2004 +* vallado, crawford, hujsak, kelso 2006 + ----------------------------------------------------------------------------*/ + +static void dpper + ( + double e3, double ee2, double peo, double pgho, double pho, + double pinco, double plo, double se2, double se3, double sgh2, + double sgh3, double sgh4, double sh2, double sh3, double si2, + double si3, double sl2, double sl3, double sl4, double t, + double xgh2, double xgh3, double xgh4, double xh2, double xh3, + double xi2, double xi3, double xl2, double xl3, double xl4, + double zmol, double zmos, double inclo, + char init, + double& ep, double& inclp, double& nodep, double& argpp, double& mp + ) +{ + /* --------------------- local variables ------------------------ */ + const double twopi = 2.0 * pi; + double alfdp, betdp, cosip, cosop, dalf, dbet, dls, + f2, f3, pe, pgh, ph, pinc, pl , + sel, ses, sghl, sghs, shll, shs, sil, + sinip, sinop, sinzf, sis, sll, sls, xls, + xnoh, zf, zm, zel, zes, znl, zns; + + /* ---------------------- constants ----------------------------- */ + zns = 1.19459e-5; + zes = 0.01675; + znl = 1.5835218e-4; + zel = 0.05490; + + /* --------------- calculate time varying periodics ----------- */ + zm = zmos + zns * t; + // be sure that the initial call has time set to zero + if (init == 'y') + zm = zmos; + zf = zm + 2.0 * zes * sin(zm); + sinzf = sin(zf); + f2 = 0.5 * sinzf * sinzf - 0.25; + f3 = -0.5 * sinzf * cos(zf); + ses = se2* f2 + se3 * f3; + sis = si2 * f2 + si3 * f3; + sls = sl2 * f2 + sl3 * f3 + sl4 * sinzf; + sghs = sgh2 * f2 + sgh3 * f3 + sgh4 * sinzf; + shs = sh2 * f2 + sh3 * f3; + zm = zmol + znl * t; + if (init == 'y') + zm = zmol; + zf = zm + 2.0 * zel * sin(zm); + sinzf = sin(zf); + f2 = 0.5 * sinzf * sinzf - 0.25; + f3 = -0.5 * sinzf * cos(zf); + sel = ee2 * f2 + e3 * f3; + sil = xi2 * f2 + xi3 * f3; + sll = xl2 * f2 + xl3 * f3 + xl4 * sinzf; + sghl = xgh2 * f2 + xgh3 * f3 + xgh4 * sinzf; + shll = xh2 * f2 + xh3 * f3; + pe = ses + sel; + pinc = sis + sil; + pl = sls + sll; + pgh = sghs + sghl; + ph = shs + shll; + + if (init == 'n') + { + pe = pe - peo; + pinc = pinc - pinco; + pl = pl - plo; + pgh = pgh - pgho; + ph = ph - pho; + inclp = inclp + pinc; + ep = ep + pe; + sinip = sin(inclp); + cosip = cos(inclp); + + /* ----------------- apply periodics directly ------------ */ + // sgp4fix for lyddane choice + // strn3 used original inclination - this is technically feasible + // gsfc used perturbed inclination - also technically feasible + // probably best to readjust the 0.2 limit value and limit discontinuity + // 0.2 rad = 11.45916 deg + // use next line for original strn3 approach and original inclination + // if (inclo >= 0.2) + // use next line for gsfc version and perturbed inclination + if (inclp >= 0.2) + { + ph = ph / sinip; + pgh = pgh - cosip * ph; + argpp = argpp + pgh; + nodep = nodep + ph; + mp = mp + pl; + } + else + { + /* ---- apply periodics with lyddane modification ---- */ + sinop = sin(nodep); + cosop = cos(nodep); + alfdp = sinip * sinop; + betdp = sinip * cosop; + dalf = ph * cosop + pinc * cosip * sinop; + dbet = -ph * sinop + pinc * cosip * cosop; + alfdp = alfdp + dalf; + betdp = betdp + dbet; + nodep = fmod(nodep, twopi); + // sgp4fix for afspc written intrinsic functions + // nodep used without a trigonometric function ahead + if (nodep < 0.0) + nodep = nodep + twopi; + xls = mp + argpp + cosip * nodep; + dls = pl + pgh - pinc * nodep * sinip; + xls = xls + dls; + xnoh = nodep; + nodep = atan2(alfdp, betdp); + // sgp4fix for afspc written intrinsic functions + // nodep used without a trigonometric function ahead + if (nodep < 0.0) + nodep = nodep + twopi; + if (fabs(xnoh - nodep) > pi){ + if (nodep < xnoh) + nodep = nodep + twopi; + else + nodep = nodep - twopi; + } + mp = mp + pl; + argpp = xls - mp - cosip * nodep; + } + } // if init == 'n' + +//#include "debug1.cpp" +} // end dpper + +/*----------------------------------------------------------------------------- +* +* procedure dscom +* +* this procedure provides deep space common items used by both the secular +* and periodics subroutines. input is provided as shown. this routine +* used to be called dpper, but the functions inside weren't well organized. +* +* author : david vallado 719-573-2600 28 jun 2005 +* +* inputs : +* epoch - +* ep - eccentricity +* argpp - argument of perigee +* tc - +* inclp - inclination +* nodep - right ascension of ascending node +* np - mean motion +* +* outputs : +* sinim , cosim , sinomm , cosomm , snodm , cnodm +* day - +* e3 - +* ee2 - +* em - eccentricity +* emsq - eccentricity squared +* gam - +* peo - +* pgho - +* pho - +* pinco - +* plo - +* rtemsq - +* se2, se3 - +* sgh2, sgh3, sgh4 - +* sh2, sh3, si2, si3, sl2, sl3, sl4 - +* s1, s2, s3, s4, s5, s6, s7 - +* ss1, ss2, ss3, ss4, ss5, ss6, ss7, sz1, sz2, sz3 - +* sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33 - +* xgh2, xgh3, xgh4, xh2, xh3, xi2, xi3, xl2, xl3, xl4 - +* nm - mean motion +* z1, z2, z3, z11, z12, z13, z21, z22, z23, z31, z32, z33 - +* zmol - +* zmos - +* +* locals : +* a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 - +* betasq - +* cc - +* ctem, stem - +* x1, x2, x3, x4, x5, x6, x7, x8 - +* xnodce - +* xnoi - +* zcosg , zsing , zcosgl , zsingl , zcosh , zsinh , zcoshl , zsinhl , +* zcosi , zsini , zcosil , zsinil , +* zx - +* zy - +* +* coupling : +* none. +* +* references : +* hoots, roehrich, norad spacetrack report #3 1980 +* hoots, norad spacetrack report #6 1986 +* hoots, schumacher and glover 2004 +* vallado, crawford, hujsak, kelso 2006 + ----------------------------------------------------------------------------*/ + +static void dscom + ( + double epoch, double ep, double argpp, double tc, double inclp, + double nodep, double np, + double& snodm, double& cnodm, double& sinim, double& cosim, double& sinomm, + double& cosomm,double& day, double& e3, double& ee2, double& em, + double& emsq, double& gam, double& peo, double& pgho, double& pho, + double& pinco, double& plo, double& rtemsq, double& se2, double& se3, + double& sgh2, double& sgh3, double& sgh4, double& sh2, double& sh3, + double& si2, double& si3, double& sl2, double& sl3, double& sl4, + double& s1, double& s2, double& s3, double& s4, double& s5, + double& s6, double& s7, double& ss1, double& ss2, double& ss3, + double& ss4, double& ss5, double& ss6, double& ss7, double& sz1, + double& sz2, double& sz3, double& sz11, double& sz12, double& sz13, + double& sz21, double& sz22, double& sz23, double& sz31, double& sz32, + double& sz33, double& xgh2, double& xgh3, double& xgh4, double& xh2, + double& xh3, double& xi2, double& xi3, double& xl2, double& xl3, + double& xl4, double& nm, double& z1, double& z2, double& z3, + double& z11, double& z12, double& z13, double& z21, double& z22, + double& z23, double& z31, double& z32, double& z33, double& zmol, + double& zmos + ) +{ + /* -------------------------- constants ------------------------- */ + const double zes = 0.01675; + const double zel = 0.05490; + const double c1ss = 2.9864797e-6; + const double c1l = 4.7968065e-7; + const double zsinis = 0.39785416; + const double zcosis = 0.91744867; + const double zcosgs = 0.1945905; + const double zsings = -0.98088458; + const double twopi = 2.0 * pi; + + /* --------------------- local variables ------------------------ */ + int lsflg; + double a1 , a2 , a3 , a4 , a5 , a6 , a7 , + a8 , a9 , a10 , betasq, cc , ctem , stem , + x1 , x2 , x3 , x4 , x5 , x6 , x7 , + x8 , xnodce, xnoi , zcosg , zcosgl, zcosh , zcoshl, + zcosi , zcosil, zsing , zsingl, zsinh , zsinhl, zsini , + zsinil, zx , zy; + + nm = np; + em = ep; + snodm = sin(nodep); + cnodm = cos(nodep); + sinomm = sin(argpp); + cosomm = cos(argpp); + sinim = sin(inclp); + cosim = cos(inclp); + emsq = em * em; + betasq = 1.0 - emsq; + rtemsq = sqrt(betasq); + + /* ----------------- initialize lunar solar terms --------------- */ + peo = 0.0; + pinco = 0.0; + plo = 0.0; + pgho = 0.0; + pho = 0.0; + day = epoch + 18261.5 + tc / 1440.0; + xnodce = fmod(4.5236020 - 9.2422029e-4 * day, twopi); + stem = sin(xnodce); + ctem = cos(xnodce); + zcosil = 0.91375164 - 0.03568096 * ctem; + zsinil = sqrt(1.0 - zcosil * zcosil); + zsinhl = 0.089683511 * stem / zsinil; + zcoshl = sqrt(1.0 - zsinhl * zsinhl); + gam = 5.8351514 + 0.0019443680 * day; + zx = 0.39785416 * stem / zsinil; + zy = zcoshl * ctem + 0.91744867 * zsinhl * stem; + zx = atan2(zx, zy); + zx = gam + zx - xnodce; + zcosgl = cos(zx); + zsingl = sin(zx); + + /* ------------------------- do solar terms --------------------- */ + zcosg = zcosgs; + zsing = zsings; + zcosi = zcosis; + zsini = zsinis; + zcosh = cnodm; + zsinh = snodm; + cc = c1ss; + xnoi = 1.0 / nm; + + for (lsflg = 1; lsflg <= 2; lsflg++) + { + a1 = zcosg * zcosh + zsing * zcosi * zsinh; + a3 = -zsing * zcosh + zcosg * zcosi * zsinh; + a7 = -zcosg * zsinh + zsing * zcosi * zcosh; + a8 = zsing * zsini; + a9 = zsing * zsinh + zcosg * zcosi * zcosh; + a10 = zcosg * zsini; + a2 = cosim * a7 + sinim * a8; + a4 = cosim * a9 + sinim * a10; + a5 = -sinim * a7 + cosim * a8; + a6 = -sinim * a9 + cosim * a10; + + x1 = a1 * cosomm + a2 * sinomm; + x2 = a3 * cosomm + a4 * sinomm; + x3 = -a1 * sinomm + a2 * cosomm; + x4 = -a3 * sinomm + a4 * cosomm; + x5 = a5 * sinomm; + x6 = a6 * sinomm; + x7 = a5 * cosomm; + x8 = a6 * cosomm; + + z31 = 12.0 * x1 * x1 - 3.0 * x3 * x3; + z32 = 24.0 * x1 * x2 - 6.0 * x3 * x4; + z33 = 12.0 * x2 * x2 - 3.0 * x4 * x4; + z1 = 3.0 * (a1 * a1 + a2 * a2) + z31 * emsq; + z2 = 6.0 * (a1 * a3 + a2 * a4) + z32 * emsq; + z3 = 3.0 * (a3 * a3 + a4 * a4) + z33 * emsq; + z11 = -6.0 * a1 * a5 + emsq * (-24.0 * x1 * x7-6.0 * x3 * x5); + z12 = -6.0 * (a1 * a6 + a3 * a5) + emsq * + (-24.0 * (x2 * x7 + x1 * x8) - 6.0 * (x3 * x6 + x4 * x5)); + z13 = -6.0 * a3 * a6 + emsq * (-24.0 * x2 * x8 - 6.0 * x4 * x6); + z21 = 6.0 * a2 * a5 + emsq * (24.0 * x1 * x5 - 6.0 * x3 * x7); + z22 = 6.0 * (a4 * a5 + a2 * a6) + emsq * + (24.0 * (x2 * x5 + x1 * x6) - 6.0 * (x4 * x7 + x3 * x8)); + z23 = 6.0 * a4 * a6 + emsq * (24.0 * x2 * x6 - 6.0 * x4 * x8); + z1 = z1 + z1 + betasq * z31; + z2 = z2 + z2 + betasq * z32; + z3 = z3 + z3 + betasq * z33; + s3 = cc * xnoi; + s2 = -0.5 * s3 / rtemsq; + s4 = s3 * rtemsq; + s1 = -15.0 * em * s4; + s5 = x1 * x3 + x2 * x4; + s6 = x2 * x3 + x1 * x4; + s7 = x2 * x4 - x1 * x3; + + /* ----------------------- do lunar terms ------------------- */ + if (lsflg == 1) + { + ss1 = s1; + ss2 = s2; + ss3 = s3; + ss4 = s4; + ss5 = s5; + ss6 = s6; + ss7 = s7; + sz1 = z1; + sz2 = z2; + sz3 = z3; + sz11 = z11; + sz12 = z12; + sz13 = z13; + sz21 = z21; + sz22 = z22; + sz23 = z23; + sz31 = z31; + sz32 = z32; + sz33 = z33; + zcosg = zcosgl; + zsing = zsingl; + zcosi = zcosil; + zsini = zsinil; + zcosh = zcoshl * cnodm + zsinhl * snodm; + zsinh = snodm * zcoshl - cnodm * zsinhl; + cc = c1l; + } + } + + zmol = fmod(4.7199672 + 0.22997150 * day - gam, twopi); + zmos = fmod(6.2565837 + 0.017201977 * day, twopi); + + /* ------------------------ do solar terms ---------------------- */ + se2 = 2.0 * ss1 * ss6; + se3 = 2.0 * ss1 * ss7; + si2 = 2.0 * ss2 * sz12; + si3 = 2.0 * ss2 * (sz13 - sz11); + sl2 = -2.0 * ss3 * sz2; + sl3 = -2.0 * ss3 * (sz3 - sz1); + sl4 = -2.0 * ss3 * (-21.0 - 9.0 * emsq) * zes; + sgh2 = 2.0 * ss4 * sz32; + sgh3 = 2.0 * ss4 * (sz33 - sz31); + sgh4 = -18.0 * ss4 * zes; + sh2 = -2.0 * ss2 * sz22; + sh3 = -2.0 * ss2 * (sz23 - sz21); + + /* ------------------------ do lunar terms ---------------------- */ + ee2 = 2.0 * s1 * s6; + e3 = 2.0 * s1 * s7; + xi2 = 2.0 * s2 * z12; + xi3 = 2.0 * s2 * (z13 - z11); + xl2 = -2.0 * s3 * z2; + xl3 = -2.0 * s3 * (z3 - z1); + xl4 = -2.0 * s3 * (-21.0 - 9.0 * emsq) * zel; + xgh2 = 2.0 * s4 * z32; + xgh3 = 2.0 * s4 * (z33 - z31); + xgh4 = -18.0 * s4 * zel; + xh2 = -2.0 * s2 * z22; + xh3 = -2.0 * s2 * (z23 - z21); + +//#include "debug2.cpp" +} // end dscom + +/*----------------------------------------------------------------------------- +* +* procedure dsinit +* +* this procedure provides deep space contributions to mean motion dot due +* to geopotential resonance with half day and one day orbits. +* +* author : david vallado 719-573-2600 28 jun 2005 +* +* inputs : +* cosim, sinim- +* emsq - eccentricity squared +* argpo - argument of perigee +* s1, s2, s3, s4, s5 - +* ss1, ss2, ss3, ss4, ss5 - +* sz1, sz3, sz11, sz13, sz21, sz23, sz31, sz33 - +* t - time +* tc - +* gsto - greenwich sidereal time rad +* mo - mean anomaly +* mdot - mean anomaly dot (rate) +* no - mean motion +* nodeo - right ascension of ascending node +* nodedot - right ascension of ascending node dot (rate) +* xpidot - +* z1, z3, z11, z13, z21, z23, z31, z33 - +* eccm - eccentricity +* argpm - argument of perigee +* inclm - inclination +* mm - mean anomaly +* xn - mean motion +* nodem - right ascension of ascending node +* +* outputs : +* em - eccentricity +* argpm - argument of perigee +* inclm - inclination +* mm - mean anomaly +* nm - mean motion +* nodem - right ascension of ascending node +* irez - flag for resonance 0-none, 1-one day, 2-half day +* atime - +* d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433 - +* dedt - +* didt - +* dmdt - +* dndt - +* dnodt - +* domdt - +* del1, del2, del3 - +* ses , sghl , sghs , sgs , shl , shs , sis , sls +* theta - +* xfact - +* xlamo - +* xli - +* xni +* +* locals : +* ainv2 - +* aonv - +* cosisq - +* eoc - +* f220, f221, f311, f321, f322, f330, f441, f442, f522, f523, f542, f543 - +* g200, g201, g211, g300, g310, g322, g410, g422, g520, g521, g532, g533 - +* sini2 - +* temp - +* temp1 - +* theta - +* xno2 - +* +* coupling : +* getgravconst +* +* references : +* hoots, roehrich, norad spacetrack report #3 1980 +* hoots, norad spacetrack report #6 1986 +* hoots, schumacher and glover 2004 +* vallado, crawford, hujsak, kelso 2006 + ----------------------------------------------------------------------------*/ + +static void dsinit + ( + gravconsttype whichconst, + double cosim, double emsq, double argpo, double s1, double s2, + double s3, double s4, double s5, double sinim, double ss1, + double ss2, double ss3, double ss4, double ss5, double sz1, + double sz3, double sz11, double sz13, double sz21, double sz23, + double sz31, double sz33, double t, double tc, double gsto, + double mo, double mdot, double no, double nodeo, double nodedot, + double xpidot, double z1, double z3, double z11, double z13, + double z21, double z23, double z31, double z33, double ecco, + double eccsq, double& em, double& argpm, double& inclm, double& mm, + double& nm, double& nodem, + int& irez, + double& atime, double& d2201, double& d2211, double& d3210, double& d3222, + double& d4410, double& d4422, double& d5220, double& d5232, double& d5421, + double& d5433, double& dedt, double& didt, double& dmdt, double& dndt, + double& dnodt, double& domdt, double& del1, double& del2, double& del3, + double& xfact, double& xlamo, double& xli, double& xni + ) +{ + /* --------------------- local variables ------------------------ */ + const double twopi = 2.0 * pi; + + double ainv2 , aonv=0.0, cosisq, eoc, f220 , f221 , f311 , + f321 , f322 , f330 , f441 , f442 , f522 , f523 , + f542 , f543 , g200 , g201 , g211 , g300 , g310 , + g322 , g410 , g422 , g520 , g521 , g532 , g533 , + ses , sgs , sghl , sghs , shs , shll , sis , + sini2 , sls , temp , temp1 , theta , xno2 , q22 , + q31 , q33 , root22, root44, root54, rptim , root32, + root52, x2o3 , xke , znl , emo , zns , emsqo, + tumin, mu, radiusearthkm, j2, j3, j4, j3oj2; + + q22 = 1.7891679e-6; + q31 = 2.1460748e-6; + q33 = 2.2123015e-7; + root22 = 1.7891679e-6; + root44 = 7.3636953e-9; + root54 = 2.1765803e-9; + rptim = 4.37526908801129966e-3; // this equates to 7.29211514668855e-5 rad/sec + root32 = 3.7393792e-7; + root52 = 1.1428639e-7; + x2o3 = 2.0 / 3.0; + znl = 1.5835218e-4; + zns = 1.19459e-5; + + // sgp4fix identify constants and allow alternate values + getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); + + /* -------------------- deep space initialization ------------ */ + irez = 0; + if ((nm < 0.0052359877) && (nm > 0.0034906585)) + irez = 1; + if ((nm >= 8.26e-3) && (nm <= 9.24e-3) && (em >= 0.5)) + irez = 2; + + /* ------------------------ do solar terms ------------------- */ + ses = ss1 * zns * ss5; + sis = ss2 * zns * (sz11 + sz13); + sls = -zns * ss3 * (sz1 + sz3 - 14.0 - 6.0 * emsq); + sghs = ss4 * zns * (sz31 + sz33 - 6.0); + shs = -zns * ss2 * (sz21 + sz23); + // sgp4fix for 180 deg incl + if ((inclm < 5.2359877e-2) || (inclm > pi - 5.2359877e-2)) + shs = 0.0; + if (sinim != 0.0) + shs = shs / sinim; + sgs = sghs - cosim * shs; + + /* ------------------------- do lunar terms ------------------ */ + dedt = ses + s1 * znl * s5; + didt = sis + s2 * znl * (z11 + z13); + dmdt = sls - znl * s3 * (z1 + z3 - 14.0 - 6.0 * emsq); + sghl = s4 * znl * (z31 + z33 - 6.0); + shll = -znl * s2 * (z21 + z23); + // sgp4fix for 180 deg incl + if ((inclm < 5.2359877e-2) || (inclm > pi - 5.2359877e-2)) + shll = 0.0; + domdt = sgs + sghl; + dnodt = shs; + if (sinim != 0.0) + { + domdt = domdt - cosim / sinim * shll; + dnodt = dnodt + shll / sinim; + } + + /* ----------- calculate deep space resonance effects -------- */ + dndt = 0.0; + theta = fmod(gsto + tc * rptim, twopi); + em = em + dedt * t; + inclm = inclm + didt * t; + argpm = argpm + domdt * t; + nodem = nodem + dnodt * t; + mm = mm + dmdt * t; + // sgp4fix for negative inclinations + // the following if statement should be commented out + //if (inclm < 0.0) + // { + // inclm = -inclm; + // argpm = argpm - pi; + // nodem = nodem + pi; + // } + + /* -------------- initialize the resonance terms ------------- */ + if (irez != 0) + { + aonv = pow(nm / xke, x2o3); + + /* ---------- geopotential resonance for 12 hour orbits ------ */ + if (irez == 2) + { + cosisq = cosim * cosim; + emo = em; + em = ecco; + emsqo = emsq; + emsq = eccsq; + eoc = em * emsq; + g201 = -0.306 - (em - 0.64) * 0.440; + + if (em <= 0.65) + { + g211 = 3.616 - 13.2470 * em + 16.2900 * emsq; + g310 = -19.302 + 117.3900 * em - 228.4190 * emsq + 156.5910 * eoc; + g322 = -18.9068 + 109.7927 * em - 214.6334 * emsq + 146.5816 * eoc; + g410 = -41.122 + 242.6940 * em - 471.0940 * emsq + 313.9530 * eoc; + g422 = -146.407 + 841.8800 * em - 1629.014 * emsq + 1083.4350 * eoc; + g520 = -532.114 + 3017.977 * em - 5740.032 * emsq + 3708.2760 * eoc; + } + else + { + g211 = -72.099 + 331.819 * em - 508.738 * emsq + 266.724 * eoc; + g310 = -346.844 + 1582.851 * em - 2415.925 * emsq + 1246.113 * eoc; + g322 = -342.585 + 1554.908 * em - 2366.899 * emsq + 1215.972 * eoc; + g410 = -1052.797 + 4758.686 * em - 7193.992 * emsq + 3651.957 * eoc; + g422 = -3581.690 + 16178.110 * em - 24462.770 * emsq + 12422.520 * eoc; + if (em > 0.715) + g520 =-5149.66 + 29936.92 * em - 54087.36 * emsq + 31324.56 * eoc; + else + g520 = 1464.74 - 4664.75 * em + 3763.64 * emsq; + } + if (em < 0.7) + { + g533 = -919.22770 + 4988.6100 * em - 9064.7700 * emsq + 5542.21 * eoc; + g521 = -822.71072 + 4568.6173 * em - 8491.4146 * emsq + 5337.524 * eoc; + g532 = -853.66600 + 4690.2500 * em - 8624.7700 * emsq + 5341.4 * eoc; + } + else + { + g533 =-37995.780 + 161616.52 * em - 229838.20 * emsq + 109377.94 * eoc; + g521 =-51752.104 + 218913.95 * em - 309468.16 * emsq + 146349.42 * eoc; + g532 =-40023.880 + 170470.89 * em - 242699.48 * emsq + 115605.82 * eoc; + } + + sini2= sinim * sinim; + f220 = 0.75 * (1.0 + 2.0 * cosim+cosisq); + f221 = 1.5 * sini2; + f321 = 1.875 * sinim * (1.0 - 2.0 * cosim - 3.0 * cosisq); + f322 = -1.875 * sinim * (1.0 + 2.0 * cosim - 3.0 * cosisq); + f441 = 35.0 * sini2 * f220; + f442 = 39.3750 * sini2 * sini2; + f522 = 9.84375 * sinim * (sini2 * (1.0 - 2.0 * cosim- 5.0 * cosisq) + + 0.33333333 * (-2.0 + 4.0 * cosim + 6.0 * cosisq) ); + f523 = sinim * (4.92187512 * sini2 * (-2.0 - 4.0 * cosim + + 10.0 * cosisq) + 6.56250012 * (1.0+2.0 * cosim - 3.0 * cosisq)); + f542 = 29.53125 * sinim * (2.0 - 8.0 * cosim+cosisq * + (-12.0 + 8.0 * cosim + 10.0 * cosisq)); + f543 = 29.53125 * sinim * (-2.0 - 8.0 * cosim+cosisq * + (12.0 + 8.0 * cosim - 10.0 * cosisq)); + xno2 = nm * nm; + ainv2 = aonv * aonv; + temp1 = 3.0 * xno2 * ainv2; + temp = temp1 * root22; + d2201 = temp * f220 * g201; + d2211 = temp * f221 * g211; + temp1 = temp1 * aonv; + temp = temp1 * root32; + d3210 = temp * f321 * g310; + d3222 = temp * f322 * g322; + temp1 = temp1 * aonv; + temp = 2.0 * temp1 * root44; + d4410 = temp * f441 * g410; + d4422 = temp * f442 * g422; + temp1 = temp1 * aonv; + temp = temp1 * root52; + d5220 = temp * f522 * g520; + d5232 = temp * f523 * g532; + temp = 2.0 * temp1 * root54; + d5421 = temp * f542 * g521; + d5433 = temp * f543 * g533; + xlamo = fmod(mo + nodeo + nodeo-theta - theta, twopi); + xfact = mdot + dmdt + 2.0 * (nodedot + dnodt - rptim) - no; + em = emo; + emsq = emsqo; + } + + /* ---------------- synchronous resonance terms -------------- */ + if (irez == 1) + { + g200 = 1.0 + emsq * (-2.5 + 0.8125 * emsq); + g310 = 1.0 + 2.0 * emsq; + g300 = 1.0 + emsq * (-6.0 + 6.60937 * emsq); + f220 = 0.75 * (1.0 + cosim) * (1.0 + cosim); + f311 = 0.9375 * sinim * sinim * (1.0 + 3.0 * cosim) - 0.75 * (1.0 + cosim); + f330 = 1.0 + cosim; + f330 = 1.875 * f330 * f330 * f330; + del1 = 3.0 * nm * nm * aonv * aonv; + del2 = 2.0 * del1 * f220 * g200 * q22; + del3 = 3.0 * del1 * f330 * g300 * q33 * aonv; + del1 = del1 * f311 * g310 * q31 * aonv; + xlamo = fmod(mo + nodeo + argpo - theta, twopi); + xfact = mdot + xpidot - rptim + dmdt + domdt + dnodt - no; + } + + /* ------------ for sgp4, initialize the integrator ---------- */ + xli = xlamo; + xni = no; + atime = 0.0; + nm = no + dndt; + } + +//#include "debug3.cpp" +} // end dsinit + +/*----------------------------------------------------------------------------- +* +* procedure dspace +* +* this procedure provides deep space contributions to mean elements for +* perturbing third body. these effects have been averaged over one +* revolution of the sun and moon. for earth resonance effects, the +* effects have been averaged over no revolutions of the satellite. +* (mean motion) +* +* author : david vallado 719-573-2600 28 jun 2005 +* +* inputs : +* d2201, d2211, d3210, d3222, d4410, d4422, d5220, d5232, d5421, d5433 - +* dedt - +* del1, del2, del3 - +* didt - +* dmdt - +* dnodt - +* domdt - +* irez - flag for resonance 0-none, 1-one day, 2-half day +* argpo - argument of perigee +* argpdot - argument of perigee dot (rate) +* t - time +* tc - +* gsto - gst +* xfact - +* xlamo - +* no - mean motion +* atime - +* em - eccentricity +* ft - +* argpm - argument of perigee +* inclm - inclination +* xli - +* mm - mean anomaly +* xni - mean motion +* nodem - right ascension of ascending node +* +* outputs : +* atime - +* em - eccentricity +* argpm - argument of perigee +* inclm - inclination +* xli - +* mm - mean anomaly +* xni - +* nodem - right ascension of ascending node +* dndt - +* nm - mean motion +* +* locals : +* delt - +* ft - +* theta - +* x2li - +* x2omi - +* xl - +* xldot - +* xnddt - +* xndt - +* xomi - +* +* coupling : +* none - +* +* references : +* hoots, roehrich, norad spacetrack report #3 1980 +* hoots, norad spacetrack report #6 1986 +* hoots, schumacher and glover 2004 +* vallado, crawford, hujsak, kelso 2006 + ----------------------------------------------------------------------------*/ + +static void dspace + ( + int irez, + double d2201, double d2211, double d3210, double d3222, double d4410, + double d4422, double d5220, double d5232, double d5421, double d5433, + double dedt, double del1, double del2, double del3, double didt, + double dmdt, double dnodt, double domdt, double argpo, double argpdot, + double t, double tc, double gsto, double xfact, double xlamo, + double no, + double& atime, double& em, double& argpm, double& inclm, double& xli, + double& mm, double& xni, double& nodem, double& dndt, double& nm + ) +{ + const double twopi = 2.0 * pi; + int iretn , iret; + double delt, ft, theta, x2li, x2omi, xl, xldot , xnddt, xndt, xomi, g22, g32, + g44, g52, g54, fasx2, fasx4, fasx6, rptim , step2, stepn , stepp; + + ft = 0.0; + fasx2 = 0.13130908; + fasx4 = 2.8843198; + fasx6 = 0.37448087; + g22 = 5.7686396; + g32 = 0.95240898; + g44 = 1.8014998; + g52 = 1.0508330; + g54 = 4.4108898; + rptim = 4.37526908801129966e-3; // this equates to 7.29211514668855e-5 rad/sec + stepp = 720.0; + stepn = -720.0; + step2 = 259200.0; + + /* ----------- calculate deep space resonance effects ----------- */ + dndt = 0.0; + theta = fmod(gsto + tc * rptim, twopi); + em = em + dedt * t; + + inclm = inclm + didt * t; + argpm = argpm + domdt * t; + nodem = nodem + dnodt * t; + mm = mm + dmdt * t; + + // sgp4fix for negative inclinations + // the following if statement should be commented out + // if (inclm < 0.0) + // { + // inclm = -inclm; + // argpm = argpm - pi; + // nodem = nodem + pi; + // } + + /* - update resonances : numerical (euler-maclaurin) integration - */ + /* ------------------------- epoch restart ---------------------- */ + // sgp4fix for propagator problems + // the following integration works for negative time steps and periods + // the specific changes are unknown because the original code was so convoluted + + ft = 0.0; + atime = 0.0; + if (irez != 0) + { + if ((atime == 0.0) || ((t >= 0.0) && (atime < 0.0)) || + ((t < 0.0) && (atime >= 0.0))) + { + if (t >= 0.0) + delt = stepp; + else + delt = stepn; + atime = 0.0; + xni = no; + xli = xlamo; + } + iretn = 381; // added for do loop + iret = 0; // added for loop + while (iretn == 381) + { + if ((fabs(t) < fabs(atime)) || (iret == 351)) + { + if (t >= 0.0) + delt = stepn; + else + delt = stepp; + iret = 351; + iretn = 381; + } + else + { + if (t > 0.0) // error if prev if has atime:=0.0 and t:=0.0 (ge) + delt = stepp; + else + delt = stepn; + if (fabs(t - atime) >= stepp) + { + iret = 0; + iretn = 381; + } + else + { + ft = t - atime; + iretn = 0; + } + } + + /* ------------------- dot terms calculated ------------- */ + /* ----------- near - synchronous resonance terms ------- */ + if (irez != 2) + { + xndt = del1 * sin(xli - fasx2) + del2 * sin(2.0 * (xli - fasx4)) + + del3 * sin(3.0 * (xli - fasx6)); + xldot = xni + xfact; + xnddt = del1 * cos(xli - fasx2) + + 2.0 * del2 * cos(2.0 * (xli - fasx4)) + + 3.0 * del3 * cos(3.0 * (xli - fasx6)); + xnddt = xnddt * xldot; + } + else + { + /* --------- near - half-day resonance terms -------- */ + xomi = argpo + argpdot * atime; + x2omi = xomi + xomi; + x2li = xli + xli; + xndt = d2201 * sin(x2omi + xli - g22) + d2211 * sin(xli - g22) + + d3210 * sin(xomi + xli - g32) + d3222 * sin(-xomi + xli - g32)+ + d4410 * sin(x2omi + x2li - g44)+ d4422 * sin(x2li - g44) + + d5220 * sin(xomi + xli - g52) + d5232 * sin(-xomi + xli - g52)+ + d5421 * sin(xomi + x2li - g54) + d5433 * sin(-xomi + x2li - g54); + xldot = xni + xfact; + xnddt = d2201 * cos(x2omi + xli - g22) + d2211 * cos(xli - g22) + + d3210 * cos(xomi + xli - g32) + d3222 * cos(-xomi + xli - g32) + + d5220 * cos(xomi + xli - g52) + d5232 * cos(-xomi + xli - g52) + + 2.0 * (d4410 * cos(x2omi + x2li - g44) + + d4422 * cos(x2li - g44) + d5421 * cos(xomi + x2li - g54) + + d5433 * cos(-xomi + x2li - g54)); + xnddt = xnddt * xldot; + } + + /* ----------------------- integrator ------------------- */ + if (iretn == 381) + { + xli = xli + xldot * delt + xndt * step2; + xni = xni + xndt * delt + xnddt * step2; + atime = atime + delt; + } + } // while iretn = 381 + + nm = xni + xndt * ft + xnddt * ft * ft * 0.5; + xl = xli + xldot * ft + xndt * ft * ft * 0.5; + if (irez != 1) + { + mm = xl - 2.0 * nodem + 2.0 * theta; + dndt = nm - no; + } + else + { + mm = xl - nodem - argpm + theta; + dndt = nm - no; + } + nm = no + dndt; + } + +//#include "debug4.cpp" +} // end dsspace + +/*----------------------------------------------------------------------------- +* +* procedure initl +* +* this procedure initializes the spg4 propagator. all the initialization is +* consolidated here instead of having multiple loops inside other routines. +* +* author : david vallado 719-573-2600 28 jun 2005 +* +* inputs : +* ecco - eccentricity 0.0 - 1.0 +* epoch - epoch time in days from jan 0, 1950. 0 hr +* inclo - inclination of satellite +* no - mean motion of satellite +* satn - satellite number +* +* outputs : +* ainv - 1.0 / a +* ao - semi major axis +* con41 - +* con42 - 1.0 - 5.0 cos(i) +* cosio - cosine of inclination +* cosio2 - cosio squared +* eccsq - eccentricity squared +* method - flag for deep space 'd', 'n' +* omeosq - 1.0 - ecco * ecco +* posq - semi-parameter squared +* rp - radius of perigee +* rteosq - square root of (1.0 - ecco*ecco) +* sinio - sine of inclination +* gsto - gst at time of observation rad +* no - mean motion of satellite +* +* locals : +* ak - +* d1 - +* del - +* adel - +* po - +* +* coupling : +* getgravconst +* gstime - find greenwich sidereal time from the julian date +* +* references : +* hoots, roehrich, norad spacetrack report #3 1980 +* hoots, norad spacetrack report #6 1986 +* hoots, schumacher and glover 2004 +* vallado, crawford, hujsak, kelso 2006 + ----------------------------------------------------------------------------*/ + +static void initl + ( + int satn, gravconsttype whichconst, + double ecco, double epoch, double inclo, double& no, + char& method, + double& ainv, double& ao, double& con41, double& con42, double& cosio, + double& cosio2,double& eccsq, double& omeosq, double& posq, + double& rp, double& rteosq,double& sinio , double& gsto + ) +{ + /* --------------------- local variables ------------------------ */ + double ak, d1, del, adel, po, x2o3, j2, xke, + tumin, mu, radiusearthkm, j3, j4, j3oj2; + + // sgp4fix use old way of finding gst + int ids70; + double ts70, ds70, tfrac, c1, thgr70, fk5r, c1p2p; + const double twopi = 2.0 * pi; + + /* ----------------------- earth constants ---------------------- */ + // sgp4fix identify constants and allow alternate values + getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); + x2o3 = 2.0 / 3.0; + + /* ------------- calculate auxillary epoch quantities ---------- */ + eccsq = ecco * ecco; + omeosq = 1.0 - eccsq; + rteosq = sqrt(omeosq); + cosio = cos(inclo); + cosio2 = cosio * cosio; + + /* ------------------ un-kozai the mean motion ----------------- */ + ak = pow(xke / no, x2o3); + d1 = 0.75 * j2 * (3.0 * cosio2 - 1.0) / (rteosq * omeosq); + del = d1 / (ak * ak); + adel = ak * (1.0 - del * del - del * + (1.0 / 3.0 + 134.0 * del * del / 81.0)); + del = d1/(adel * adel); + no = no / (1.0 + del); + + ao = pow(xke / no, x2o3); + sinio = sin(inclo); + po = ao * omeosq; + con42 = 1.0 - 5.0 * cosio2; + con41 = -con42-cosio2-cosio2; + ainv = 1.0 / ao; + posq = po * po; + rp = ao * (1.0 - ecco); + method = 'n'; + + // sgp4fix modern approach to finding sidereal timew + // gsto = gstime(epoch + 2433281.5); + + // sgp4fix use old way of finding gst + // count integer number of days from 0 jan 1970 + ts70 = epoch - 7305.0; + ids70 = floor(ts70 + 1.0e-8); + ds70 = ids70; + tfrac = ts70 - ds70; + // find greenwich location at epoch + c1 = 1.72027916940703639e-2; + thgr70= 1.7321343856509374; + fk5r = 5.07551419432269442e-15; + c1p2p = c1 + twopi; + gsto = fmod( thgr70 + c1*ds70 + c1p2p*tfrac + ts70*ts70*fk5r, twopi); + if ( gsto < 0.0 ) + gsto = gsto + twopi; + +//#include "debug5.cpp" +} // end initl + +/*----------------------------------------------------------------------------- +* +* procedure sgp4init +* +* this procedure initializes variables for sgp4. +* +* author : david vallado 719-573-2600 28 jun 2005 +* +* inputs : +* satn - satellite number +* bstar - sgp4 type drag coefficient kg/m2er +* ecco - eccentricity +* epoch - epoch time in days from jan 0, 1950. 0 hr +* argpo - argument of perigee (output if ds) +* inclo - inclination +* mo - mean anomaly (output if ds) +* no - mean motion +* nodeo - right ascension of ascending node +* +* outputs : +* satrec - common values for subsequent calls +* return code - non-zero on error. +* 1 - mean elements, ecc >= 1.0 or ecc < -0.001 or a < 0.95 er +* 2 - mean motion less than 0.0 +* 3 - pert elements, ecc < 0.0 or ecc > 1.0 +* 4 - semi-latus rectum < 0.0 +* 5 - epoch elements are sub-orbital +* 6 - satellite has decayed +* +* locals : +* cnodm , snodm , cosim , sinim , cosomm , sinomm +* cc1sq , cc2 , cc3 +* coef , coef1 +* cosio4 - +* day - +* dndt - +* em - eccentricity +* emsq - eccentricity squared +* eeta - +* etasq - +* gam - +* argpm - argument of perigee +* nodem - +* inclm - inclination +* mm - mean anomaly +* nm - mean motion +* perige - perigee +* pinvsq - +* psisq - +* qzms24 - +* rtemsq - +* s1, s2, s3, s4, s5, s6, s7 - +* sfour - +* ss1, ss2, ss3, ss4, ss5, ss6, ss7 - +* sz1, sz2, sz3 +* sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33 - +* tc - +* temp - +* temp1, temp2, temp3 - +* tsi - +* xpidot - +* xhdot1 - +* z1, z2, z3 - +* z11, z12, z13, z21, z22, z23, z31, z32, z33 - +* +* coupling : +* getgravconst- +* initl - +* dscom - +* dpper - +* dsinit - +* sgp4 - +* +* references : +* hoots, roehrich, norad spacetrack report #3 1980 +* hoots, norad spacetrack report #6 1986 +* hoots, schumacher and glover 2004 +* vallado, crawford, hujsak, kelso 2006 + ----------------------------------------------------------------------------*/ + +int sgp4init + ( + gravconsttype whichconst, const int satn, const double epoch, + const double xbstar, const double xecco, const double xargpo, + const double xinclo, const double xmo, const double xno, + const double xnodeo, elsetrec& satrec + ) +{ + /* --------------------- local variables ------------------------ */ + double ao, ainv, con42, cosio, sinio, cosio2, eccsq, + omeosq, posq, rp, rteosq, + cnodm , snodm , cosim , sinim , cosomm, sinomm, cc1sq , + cc2 , cc3 , coef , coef1 , cosio4, day , dndt , + em , emsq , eeta , etasq , gam , argpm , nodem , + inclm , mm , nm , perige, pinvsq, psisq , qzms24, + rtemsq, s1 , s2 , s3 , s4 , s5 , s6 , + s7 , sfour , ss1 = 0 , ss2 = 0 , ss3 = 0 , ss4 = 0 , ss5 = 0 , + ss6 = 0 , ss7 = 0 , sz1 = 0 , sz2 = 0 , sz3 = 0 , sz11 = 0 , sz12 = 0 , + sz13 = 0 , sz21 = 0 , sz22 = 0 , sz23 = 0 , sz31 = 0 , sz32 = 0 , sz33 = 0 , + tc , temp , temp1 , temp2 , temp3 , tsi , xpidot, + xhdot1, z1 , z2 , z3 , z11 , z12 , z13 , + z21 , z22 , z23 , z31 , z32 , z33, + qzms2t, ss, j2, j3oj2, j4, x2o3, r[3], v[3], + tumin, mu, radiusearthkm, xke, j3; + + /* ------------------------ initialization --------------------- */ + // sgp4fix divisor for divide by zero check on inclination + const double temp4 = 1.0 + cos(pi-1.0e-9); + + /* ----------- set all near earth variables to zero ------------ */ + satrec.isimp = 0; satrec.method = 'n'; satrec.aycof = 0.0; + satrec.con41 = 0.0; satrec.cc1 = 0.0; satrec.cc4 = 0.0; + satrec.cc5 = 0.0; satrec.d2 = 0.0; satrec.d3 = 0.0; + satrec.d4 = 0.0; satrec.delmo = 0.0; satrec.eta = 0.0; + satrec.argpdot = 0.0; satrec.omgcof = 0.0; satrec.sinmao = 0.0; + satrec.t = 0.0; satrec.t2cof = 0.0; satrec.t3cof = 0.0; + satrec.t4cof = 0.0; satrec.t5cof = 0.0; satrec.x1mth2 = 0.0; + satrec.x7thm1 = 0.0; satrec.mdot = 0.0; satrec.nodedot = 0.0; + satrec.xlcof = 0.0; satrec.xmcof = 0.0; satrec.nodecf = 0.0; + + /* ----------- set all deep space variables to zero ------------ */ + satrec.irez = 0; satrec.d2201 = 0.0; satrec.d2211 = 0.0; + satrec.d3210 = 0.0; satrec.d3222 = 0.0; satrec.d4410 = 0.0; + satrec.d4422 = 0.0; satrec.d5220 = 0.0; satrec.d5232 = 0.0; + satrec.d5421 = 0.0; satrec.d5433 = 0.0; satrec.dedt = 0.0; + satrec.del1 = 0.0; satrec.del2 = 0.0; satrec.del3 = 0.0; + satrec.didt = 0.0; satrec.dmdt = 0.0; satrec.dnodt = 0.0; + satrec.domdt = 0.0; satrec.e3 = 0.0; satrec.ee2 = 0.0; + satrec.peo = 0.0; satrec.pgho = 0.0; satrec.pho = 0.0; + satrec.pinco = 0.0; satrec.plo = 0.0; satrec.se2 = 0.0; + satrec.se3 = 0.0; satrec.sgh2 = 0.0; satrec.sgh3 = 0.0; + satrec.sgh4 = 0.0; satrec.sh2 = 0.0; satrec.sh3 = 0.0; + satrec.si2 = 0.0; satrec.si3 = 0.0; satrec.sl2 = 0.0; + satrec.sl3 = 0.0; satrec.sl4 = 0.0; satrec.gsto = 0.0; + satrec.xfact = 0.0; satrec.xgh2 = 0.0; satrec.xgh3 = 0.0; + satrec.xgh4 = 0.0; satrec.xh2 = 0.0; satrec.xh3 = 0.0; + satrec.xi2 = 0.0; satrec.xi3 = 0.0; satrec.xl2 = 0.0; + satrec.xl3 = 0.0; satrec.xl4 = 0.0; satrec.xlamo = 0.0; + satrec.zmol = 0.0; satrec.zmos = 0.0; satrec.atime = 0.0; + satrec.xli = 0.0; satrec.xni = 0.0; + + // sgp4fix - note the following variables are also passed directly via satrec. + // it is possible to streamline the sgp4init call by deleting the "x" + // variables, but the user would need to set the satrec.* values first. we + // include the additional assignments in case twoline2rv is not used. + satrec.bstar = xbstar; + satrec.ecco = xecco; + satrec.argpo = xargpo; + satrec.inclo = xinclo; + satrec.mo = xmo; + satrec.no = xno; + satrec.nodeo = xnodeo; + + /* ------------------------ earth constants ----------------------- */ + // sgp4fix identify constants and allow alternate values + getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); + ss = 78.0 / radiusearthkm + 1.0; + qzms2t = pow(((120.0 - 78.0) / radiusearthkm), 4); + x2o3 = 2.0 / 3.0; + + satrec.init = 'y'; + satrec.t = 0.0; + + initl + ( + satn, whichconst, satrec.ecco, epoch, satrec.inclo, satrec.no, satrec.method, + ainv, ao, satrec.con41, con42, cosio, cosio2, eccsq, omeosq, + posq, rp, rteosq, sinio, satrec.gsto + ); + satrec.error = 0; + + if (rp < 1.0) + { +// printf("# *** satn%d epoch elts sub-orbital ***\n", satn); + satrec.error = 5; + } + + if ((omeosq >= 0.0 ) || ( satrec.no >= 0.0)) + { + satrec.isimp = 0; + if (rp < (220.0 / radiusearthkm + 1.0)) + satrec.isimp = 1; + sfour = ss; + qzms24 = qzms2t; + perige = (rp - 1.0) * radiusearthkm; + + /* - for perigees below 156 km, s and qoms2t are altered - */ + if (perige < 156.0) + { + sfour = perige - 78.0; + if (perige < 98.0) + sfour = 20.0; + qzms24 = pow(((120.0 - sfour) / radiusearthkm), 4.0); + sfour = sfour / radiusearthkm + 1.0; + } + pinvsq = 1.0 / posq; + + tsi = 1.0 / (ao - sfour); + satrec.eta = ao * satrec.ecco * tsi; + etasq = satrec.eta * satrec.eta; + eeta = satrec.ecco * satrec.eta; + psisq = fabs(1.0 - etasq); + coef = qzms24 * pow(tsi, 4.0); + coef1 = coef / pow(psisq, 3.5); + cc2 = coef1 * satrec.no * (ao * (1.0 + 1.5 * etasq + eeta * + (4.0 + etasq)) + 0.375 * j2 * tsi / psisq * satrec.con41 * + (8.0 + 3.0 * etasq * (8.0 + etasq))); + satrec.cc1 = satrec.bstar * cc2; + cc3 = 0.0; + if (satrec.ecco > 1.0e-4) + cc3 = -2.0 * coef * tsi * j3oj2 * satrec.no * sinio / satrec.ecco; + satrec.x1mth2 = 1.0 - cosio2; + satrec.cc4 = 2.0* satrec.no * coef1 * ao * omeosq * + (satrec.eta * (2.0 + 0.5 * etasq) + satrec.ecco * + (0.5 + 2.0 * etasq) - j2 * tsi / (ao * psisq) * + (-3.0 * satrec.con41 * (1.0 - 2.0 * eeta + etasq * + (1.5 - 0.5 * eeta)) + 0.75 * satrec.x1mth2 * + (2.0 * etasq - eeta * (1.0 + etasq)) * cos(2.0 * satrec.argpo))); + satrec.cc5 = 2.0 * coef1 * ao * omeosq * (1.0 + 2.75 * + (etasq + eeta) + eeta * etasq); + cosio4 = cosio2 * cosio2; + temp1 = 1.5 * j2 * pinvsq * satrec.no; + temp2 = 0.5 * temp1 * j2 * pinvsq; + temp3 = -0.46875 * j4 * pinvsq * pinvsq * satrec.no; + satrec.mdot = satrec.no + 0.5 * temp1 * rteosq * satrec.con41 + 0.0625 * + temp2 * rteosq * (13.0 - 78.0 * cosio2 + 137.0 * cosio4); + satrec.argpdot = -0.5 * temp1 * con42 + 0.0625 * temp2 * + (7.0 - 114.0 * cosio2 + 395.0 * cosio4) + + temp3 * (3.0 - 36.0 * cosio2 + 49.0 * cosio4); + xhdot1 = -temp1 * cosio; + satrec.nodedot = xhdot1 + (0.5 * temp2 * (4.0 - 19.0 * cosio2) + + 2.0 * temp3 * (3.0 - 7.0 * cosio2)) * cosio; + xpidot = satrec.argpdot+ satrec.nodedot; + satrec.omgcof = satrec.bstar * cc3 * cos(satrec.argpo); + satrec.xmcof = 0.0; + if (satrec.ecco > 1.0e-4) + satrec.xmcof = -x2o3 * coef * satrec.bstar / eeta; + satrec.nodecf = 3.5 * omeosq * xhdot1 * satrec.cc1; + satrec.t2cof = 1.5 * satrec.cc1; + // sgp4fix for divide by zero with xinco = 180 deg + if (fabs(cosio+1.0) > 1.5e-12) + satrec.xlcof = -0.25 * j3oj2 * sinio * (3.0 + 5.0 * cosio) / (1.0 + cosio); + else + satrec.xlcof = -0.25 * j3oj2 * sinio * (3.0 + 5.0 * cosio) / temp4; + satrec.aycof = -0.5 * j3oj2 * sinio; + satrec.delmo = pow((1.0 + satrec.eta * cos(satrec.mo)), 3); + satrec.sinmao = sin(satrec.mo); + satrec.x7thm1 = 7.0 * cosio2 - 1.0; + + /* --------------- deep space initialization ------------- */ + if ((2*pi / satrec.no) >= 225.0) + { + satrec.method = 'd'; + satrec.isimp = 1; + tc = 0.0; + inclm = satrec.inclo; + + dscom + ( + epoch, satrec.ecco, satrec.argpo, tc, satrec.inclo, satrec.nodeo, + satrec.no, snodm, cnodm, sinim, cosim,sinomm, cosomm, + day, satrec.e3, satrec.ee2, em, emsq, gam, + satrec.peo, satrec.pgho, satrec.pho, satrec.pinco, + satrec.plo, rtemsq, satrec.se2, satrec.se3, + satrec.sgh2, satrec.sgh3, satrec.sgh4, + satrec.sh2, satrec.sh3, satrec.si2, satrec.si3, + satrec.sl2, satrec.sl3, satrec.sl4, s1, s2, s3, s4, s5, + s6, s7, ss1, ss2, ss3, ss4, ss5, ss6, ss7, sz1, sz2, sz3, + sz11, sz12, sz13, sz21, sz22, sz23, sz31, sz32, sz33, + satrec.xgh2, satrec.xgh3, satrec.xgh4, satrec.xh2, + satrec.xh3, satrec.xi2, satrec.xi3, satrec.xl2, + satrec.xl3, satrec.xl4, nm, z1, z2, z3, z11, + z12, z13, z21, z22, z23, z31, z32, z33, + satrec.zmol, satrec.zmos + ); + dpper + ( + satrec.e3, satrec.ee2, satrec.peo, satrec.pgho, + satrec.pho, satrec.pinco, satrec.plo, satrec.se2, + satrec.se3, satrec.sgh2, satrec.sgh3, satrec.sgh4, + satrec.sh2, satrec.sh3, satrec.si2, satrec.si3, + satrec.sl2, satrec.sl3, satrec.sl4, satrec.t, + satrec.xgh2,satrec.xgh3,satrec.xgh4, satrec.xh2, + satrec.xh3, satrec.xi2, satrec.xi3, satrec.xl2, + satrec.xl3, satrec.xl4, satrec.zmol, satrec.zmos, inclm, satrec.init, + satrec.ecco, satrec.inclo, satrec.nodeo, satrec.argpo, satrec.mo + ); + + argpm = 0.0; + nodem = 0.0; + mm = 0.0; + + dsinit + ( + whichconst, + cosim, emsq, satrec.argpo, s1, s2, s3, s4, s5, sinim, ss1, ss2, ss3, ss4, + ss5, sz1, sz3, sz11, sz13, sz21, sz23, sz31, sz33, satrec.t, tc, + satrec.gsto, satrec.mo, satrec.mdot, satrec.no, satrec.nodeo, + satrec.nodedot, xpidot, z1, z3, z11, z13, z21, z23, z31, z33, + satrec.ecco, eccsq, em, argpm, inclm, mm, nm, nodem, + satrec.irez, satrec.atime, + satrec.d2201, satrec.d2211, satrec.d3210, satrec.d3222 , + satrec.d4410, satrec.d4422, satrec.d5220, satrec.d5232, + satrec.d5421, satrec.d5433, satrec.dedt, satrec.didt, + satrec.dmdt, dndt, satrec.dnodt, satrec.domdt , + satrec.del1, satrec.del2, satrec.del3, satrec.xfact, + satrec.xlamo, satrec.xli, satrec.xni + ); + } + + /* ----------- set variables if not deep space ----------- */ + if (satrec.isimp != 1) + { + cc1sq = satrec.cc1 * satrec.cc1; + satrec.d2 = 4.0 * ao * tsi * cc1sq; + temp = satrec.d2 * tsi * satrec.cc1 / 3.0; + satrec.d3 = (17.0 * ao + sfour) * temp; + satrec.d4 = 0.5 * temp * ao * tsi * (221.0 * ao + 31.0 * sfour) * + satrec.cc1; + satrec.t3cof = satrec.d2 + 2.0 * cc1sq; + satrec.t4cof = 0.25 * (3.0 * satrec.d3 + satrec.cc1 * + (12.0 * satrec.d2 + 10.0 * cc1sq)); + satrec.t5cof = 0.2 * (3.0 * satrec.d4 + + 12.0 * satrec.cc1 * satrec.d3 + + 6.0 * satrec.d2 * satrec.d2 + + 15.0 * cc1sq * (2.0 * satrec.d2 + cc1sq)); + } + } // if omeosq = 0 ... + + /* finally propogate to zero epoch to initialise all others. */ + if(satrec.error == 0) + sgp4(whichconst, satrec, 0.0, r, v); + + satrec.init = 'n'; + +//#include "debug6.cpp" + return satrec.error; +} // end sgp4init + +/*----------------------------------------------------------------------------- +* +* procedure sgp4 +* +* this procedure is the sgp4 prediction model from space command. this is an +* updated and combined version of sgp4 and sdp4, which were originally +* published separately in spacetrack report #3. this version follows the +* methodology from the aiaa paper (2006) describing the history and +* development of the code. +* +* author : david vallado 719-573-2600 28 jun 2005 +* +* inputs : +* satrec - initialised structure from sgp4init() call. +* tsince - time eince epoch (minutes) +* +* outputs : +* r - position vector km +* v - velocity km/sec +* return code - non-zero on error. +* 1 - mean elements, ecc >= 1.0 or ecc < -0.001 or a < 0.95 er +* 2 - mean motion less than 0.0 +* 3 - pert elements, ecc < 0.0 or ecc > 1.0 +* 4 - semi-latus rectum < 0.0 +* 5 - epoch elements are sub-orbital +* 6 - satellite has decayed +* +* locals : +* am - +* axnl, aynl - +* betal - +* cosim , sinim , cosomm , sinomm , cnod , snod , cos2u , +* sin2u , coseo1 , sineo1 , cosi , sini , cosip , sinip , +* cosisq , cossu , sinsu , cosu , sinu +* delm - +* delomg - +* dndt - +* eccm - +* emsq - +* ecose - +* el2 - +* eo1 - +* eccp - +* esine - +* argpm - +* argpp - +* omgadf - +* pl - +* r - +* rtemsq - +* rdotl - +* rl - +* rvdot - +* rvdotl - +* su - +* t2 , t3 , t4 , tc +* tem5, temp , temp1 , temp2 , tempa , tempe , templ +* u , ux , uy , uz , vx , vy , vz +* inclm - inclination +* mm - mean anomaly +* nm - mean motion +* nodem - right asc of ascending node +* xinc - +* xincp - +* xl - +* xlm - +* mp - +* xmdf - +* xmx - +* xmy - +* nodedf - +* xnode - +* nodep - +* np - +* +* coupling : +* getgravconst- +* dpper +* dpspace +* +* references : +* hoots, roehrich, norad spacetrack report #3 1980 +* hoots, norad spacetrack report #6 1986 +* hoots, schumacher and glover 2004 +* vallado, crawford, hujsak, kelso 2006 + ----------------------------------------------------------------------------*/ + +int sgp4 + ( + gravconsttype whichconst, elsetrec& satrec, double tsince, + double r[3], double v[3] + ) +{ + double am , axnl , aynl , betal , cosim , cnod , + cos2u, coseo1, cosi , cosip , cosisq, cossu , cosu, + delm , delomg, em , emsq , ecose , el2 , eo1 , + ep , esine , argpm, argpp , argpdf, pl, mrt = 0.0, + mvt , rdotl , rl , rvdot , rvdotl, sinim , + sin2u, sineo1, sini , sinip , sinsu , sinu , + snod , su , t2 , t3 , t4 , tem5 , temp, + temp1, temp2 , tempa, tempe , templ , u , ux , + uy , uz , vx , vy , vz , inclm , mm , + nm , nodem, xinc , xincp , xl , xlm , mp , + xmdf , xmx , xmy , nodedf, xnode , nodep, tc , dndt, + twopi, x2o3 , j2 , j3 , tumin, j4 , xke , j3oj2, radiusearthkm, + mu, vkmpersec; + int ktr; + + /* ------------------ set mathematical constants --------------- */ + // sgp4fix divisor for divide by zero check on inclination + const double temp4 = 1.0 + cos(pi-1.0e-9); + twopi = 2.0 * pi; + x2o3 = 2.0 / 3.0; + // sgp4fix identify constants and allow alternate values + getgravconst( whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2 ); + vkmpersec = radiusearthkm * xke/60.0; + + /* --------------------- clear sgp4 error flag ----------------- */ + satrec.t = tsince; + satrec.error = 0; + + /* ------- update for secular gravity and atmospheric drag ----- */ + xmdf = satrec.mo + satrec.mdot * satrec.t; + argpdf = satrec.argpo + satrec.argpdot * satrec.t; + nodedf = satrec.nodeo + satrec.nodedot * satrec.t; + argpm = argpdf; + mm = xmdf; + t2 = satrec.t * satrec.t; + nodem = nodedf + satrec.nodecf * t2; + tempa = 1.0 - satrec.cc1 * satrec.t; + tempe = satrec.bstar * satrec.cc4 * satrec.t; + templ = satrec.t2cof * t2; + + if (satrec.isimp != 1) + { + delomg = satrec.omgcof * satrec.t; + delm = satrec.xmcof * + (pow((1.0 + satrec.eta * cos(xmdf)), 3) - + satrec.delmo); + temp = delomg + delm; + mm = xmdf + temp; + argpm = argpdf - temp; + t3 = t2 * satrec.t; + t4 = t3 * satrec.t; + tempa = tempa - satrec.d2 * t2 - satrec.d3 * t3 - + satrec.d4 * t4; + tempe = tempe + satrec.bstar * satrec.cc5 * (sin(mm) - + satrec.sinmao); + templ = templ + satrec.t3cof * t3 + t4 * (satrec.t4cof + + satrec.t * satrec.t5cof); + } + + nm = satrec.no; + em = satrec.ecco; + inclm = satrec.inclo; + if (satrec.method == 'd') + { + tc = satrec.t; + dspace + ( + satrec.irez, + satrec.d2201, satrec.d2211, satrec.d3210, + satrec.d3222, satrec.d4410, satrec.d4422, + satrec.d5220, satrec.d5232, satrec.d5421, + satrec.d5433, satrec.dedt, satrec.del1, + satrec.del2, satrec.del3, satrec.didt, + satrec.dmdt, satrec.dnodt, satrec.domdt, + satrec.argpo, satrec.argpdot, satrec.t, tc, + satrec.gsto, satrec.xfact, satrec.xlamo, + satrec.no, satrec.atime, + em, argpm, inclm, satrec.xli, mm, satrec.xni, + nodem, dndt, nm + ); + } // if method = d + + if (nm <= 0.0) + { +// printf("# error nm %f\n", nm); + satrec.error = 2; + } + am = pow((xke / nm),x2o3) * tempa * tempa; + nm = xke / pow(am, 1.5); + em = em - tempe; + + // fix tolerance for error recognition + if ((em >= 1.0) || (em < -0.001) || (am < 0.95)) + { +// printf("# error em %f\n", em); + satrec.error = 1; + } + if (em < 0.0) + em = 1.0e-6; + mm = mm + satrec.no * templ; + xlm = mm + argpm + nodem; + emsq = em * em; + temp = 1.0 - emsq; + + nodem = fmod(nodem, twopi); + argpm = fmod(argpm, twopi); + xlm = fmod(xlm, twopi); + mm = fmod(xlm - argpm - nodem, twopi); + + /* ----------------- compute extra mean quantities ------------- */ + sinim = sin(inclm); + cosim = cos(inclm); + + /* -------------------- add lunar-solar periodics -------------- */ + ep = em; + xincp = inclm; + argpp = argpm; + nodep = nodem; + mp = mm; + sinip = sinim; + cosip = cosim; + if (satrec.method == 'd') + { + dpper + ( + satrec.e3, satrec.ee2, satrec.peo, + satrec.pgho, satrec.pho, satrec.pinco, + satrec.plo, satrec.se2, satrec.se3, + satrec.sgh2, satrec.sgh3, satrec.sgh4, + satrec.sh2, satrec.sh3, satrec.si2, + satrec.si3, satrec.sl2, satrec.sl3, + satrec.sl4, satrec.t, satrec.xgh2, + satrec.xgh3, satrec.xgh4, satrec.xh2, + satrec.xh3, satrec.xi2, satrec.xi3, + satrec.xl2, satrec.xl3, satrec.xl4, + satrec.zmol, satrec.zmos, satrec.inclo, + 'n', ep, xincp, nodep, argpp, mp + ); + if (xincp < 0.0) + { + xincp = -xincp; + nodep = nodep + pi; + argpp = argpp - pi; + } + if ((ep < 0.0 ) || ( ep > 1.0)) + { + // printf("# error ep %f\n", ep); + satrec.error = 3; + } + } // if method = d + + /* -------------------- long period periodics ------------------ */ + if (satrec.method == 'd') + { + sinip = sin(xincp); + cosip = cos(xincp); + satrec.aycof = -0.5*j3oj2*sinip; + // sgp4fix for divide by zero for xincp = 180 deg + if (fabs(cosip+1.0) > 1.5e-12) + satrec.xlcof = -0.25 * j3oj2 * sinip * (3.0 + 5.0 * cosip) / (1.0 + cosip); + else + satrec.xlcof = -0.25 * j3oj2 * sinip * (3.0 + 5.0 * cosip) / temp4; + } + axnl = ep * cos(argpp); + temp = 1.0 / (am * (1.0 - ep * ep)); + aynl = ep* sin(argpp) + temp * satrec.aycof; + xl = mp + argpp + nodep + temp * satrec.xlcof * axnl; + + /* --------------------- solve kepler's equation --------------- */ + u = fmod(xl - nodep, twopi); + eo1 = u; + tem5 = 9999.9; + ktr = 1; + // sgp4fix for kepler iteration + // the following iteration needs better limits on corrections + while (( fabs(tem5) >= 1.0e-12) && (ktr <= 10) ) + { + sineo1 = sin(eo1); + coseo1 = cos(eo1); + tem5 = 1.0 - coseo1 * axnl - sineo1 * aynl; + tem5 = (u - aynl * coseo1 + axnl * sineo1 - eo1) / tem5; + if(fabs(tem5) >= 0.95) + tem5 = tem5 > 0.0 ? 0.95 : -0.95; + eo1 = eo1 + tem5; + ktr = ktr + 1; + } + + /* ------------- short period preliminary quantities ----------- */ + ecose = axnl*coseo1 + aynl*sineo1; + esine = axnl*sineo1 - aynl*coseo1; + el2 = axnl*axnl + aynl*aynl; + pl = am*(1.0-el2); + if (pl < 0.0) + { +// printf("# error pl %f\n", pl); + satrec.error = 4; + } + else + { + rl = am * (1.0 - ecose); + rdotl = sqrt(am) * esine/rl; + rvdotl = sqrt(pl) / rl; + betal = sqrt(1.0 - el2); + temp = esine / (1.0 + betal); + sinu = am / rl * (sineo1 - aynl - axnl * temp); + cosu = am / rl * (coseo1 - axnl + aynl * temp); + su = atan2(sinu, cosu); + sin2u = (cosu + cosu) * sinu; + cos2u = 1.0 - 2.0 * sinu * sinu; + temp = 1.0 / pl; + temp1 = 0.5 * j2 * temp; + temp2 = temp1 * temp; + + /* -------------- update for short period periodics ------------ */ + if (satrec.method == 'd') + { + cosisq = cosip * cosip; + satrec.con41 = 3.0*cosisq - 1.0; + satrec.x1mth2 = 1.0 - cosisq; + satrec.x7thm1 = 7.0*cosisq - 1.0; + } + mrt = rl * (1.0 - 1.5 * temp2 * betal * satrec.con41) + + 0.5 * temp1 * satrec.x1mth2 * cos2u; + su = su - 0.25 * temp2 * satrec.x7thm1 * sin2u; + xnode = nodep + 1.5 * temp2 * cosip * sin2u; + xinc = xincp + 1.5 * temp2 * cosip * sinip * cos2u; + mvt = rdotl - nm * temp1 * satrec.x1mth2 * sin2u / xke; + rvdot = rvdotl + nm * temp1 * (satrec.x1mth2 * cos2u + + 1.5 * satrec.con41) / xke; + + /* --------------------- orientation vectors ------------------- */ + sinsu = sin(su); + cossu = cos(su); + snod = sin(xnode); + cnod = cos(xnode); + sini = sin(xinc); + cosi = cos(xinc); + xmx = -snod * cosi; + xmy = cnod * cosi; + ux = xmx * sinsu + cnod * cossu; + uy = xmy * sinsu + snod * cossu; + uz = sini * sinsu; + vx = xmx * cossu - cnod * sinsu; + vy = xmy * cossu - snod * sinsu; + vz = sini * cossu; + + /* --------- position and velocity (in km and km/sec) ---------- */ + r[0] = (mrt * ux)* radiusearthkm; + r[1] = (mrt * uy)* radiusearthkm; + r[2] = (mrt * uz)* radiusearthkm; + v[0] = (mvt * ux + rvdot * vx) * vkmpersec; + v[1] = (mvt * uy + rvdot * vy) * vkmpersec; + v[2] = (mvt * uz + rvdot * vz) * vkmpersec; + } // if pl > 0 + + // sgp4fix for decaying satellites + if (mrt < 1.0) + { +// printf("# decay condition %11.6f \n",mrt); + satrec.error = 6; + } + + +//#include "debug7.cpp" + return satrec.error; +} // end sgp4 + + +/* ----------------------------------------------------------------------------- +* +* function gstime +* +* this function finds the greenwich sidereal time. +* +* author : david vallado 719-573-2600 1 mar 2001 +* +* inputs description range / units +* jdut1 - julian date in ut1 days from 4713 bc +* +* outputs : +* gstime - greenwich sidereal time 0 to 2pi rad +* +* locals : +* temp - temporary variable for doubles rad +* tut1 - julian centuries from the +* jan 1, 2000 12 h epoch (ut1) +* +* coupling : +* none +* +* references : +* vallado 2004, 191, eq 3-45 +* --------------------------------------------------------------------------- */ + +double gstime + ( + double jdut1 + ) + { + const double twopi = 2.0 * pi; + const double deg2rad = pi / 180.0; + double temp, tut1; + + tut1 = (jdut1 - 2451545.0) / 36525.0; + temp = -6.2e-6* tut1 * tut1 * tut1 + 0.093104 * tut1 * tut1 + + (876600.0*3600 + 8640184.812866) * tut1 + 67310.54841; // sec + temp = fmod(temp * deg2rad / 240.0, twopi); //360/86400 = 1/240, to deg, to rad + + // ------------------------ check quadrants --------------------- + if (temp < 0.0) + temp += twopi; + + return temp; + } // end gstime + +/* ----------------------------------------------------------------------------- +* +* function getgravconst +* +* this function gets constants for the propagator. note that mu is identified to +* facilitiate comparisons with newer models. the common useage is wgs72. +* +* author : david vallado 719-573-2600 21 jul 2006 +* +* inputs : +* whichconst - which set of constants to use wgs72old, wgs72, wgs84 +* +* outputs : +* tumin - minutes in one time unit +* mu - earth gravitational parameter +* radiusearthkm - radius of the earth in km +* xke - reciprocal of tumin +* j2, j3, j4 - un-normalized zonal harmonic values +* j3oj2 - j3 divided by j2 +* +* locals : +* +* coupling : +* none +* +* references : +* norad spacetrack report #3 +* vallado, crawford, hujsak, kelso 2006 + --------------------------------------------------------------------------- */ + +void getgravconst + ( + gravconsttype whichconst, + double& tumin, + double& mu, + double& radiusearthkm, + double& xke, + double& j2, + double& j3, + double& j4, + double& j3oj2 + ) + { + + switch (whichconst) + { + // -- wgs-72 low precision str#3 constants -- + case wgs72old: + mu = 398600.79964; // in km3 / s2 + radiusearthkm = 6378.135; // km + xke = 0.0743669161; + tumin = 1.0 / xke; + j2 = 0.001082616; + j3 = -0.00000253881; + j4 = -0.00000165597; + j3oj2 = j3 / j2; + break; + // ------------ wgs-72 constants ------------ + case wgs72: + mu = 398600.8; // in km3 / s2 + radiusearthkm = 6378.135; // km + xke = 60.0 / sqrt(radiusearthkm*radiusearthkm*radiusearthkm/mu); + tumin = 1.0 / xke; + j2 = 0.001082616; + j3 = -0.00000253881; + j4 = -0.00000165597; + j3oj2 = j3 / j2; + break; + case wgs84: + // ------------ wgs-84 constants ------------ + mu = 398600.5; // in km3 / s2 + radiusearthkm = 6378.137; // km + xke = 60.0 / sqrt(radiusearthkm*radiusearthkm*radiusearthkm/mu); + tumin = 1.0 / xke; + j2 = 0.00108262998905; + j3 = -0.00000253215306; + j4 = -0.00000161098761; + j3oj2 = j3 / j2; + break; + default: + fprintf(stderr,"unknown gravity option (%d)\n",whichconst); + break; + } + + } // end getgravconst + + + + + diff --git a/contrib/sgp4/sgp4unit.h b/contrib/sgp4/sgp4unit.h index 48c113d7..f16acbd9 100644 --- a/contrib/sgp4/sgp4unit.h +++ b/contrib/sgp4/sgp4unit.h @@ -1,117 +1,117 @@ -#ifndef _sgp4unit_ -#define _sgp4unit_ -/* ---------------------------------------------------------------- -* -* sgp4unit.h -* -* this file contains the sgp4 procedures for analytical propagation -* of a satellite. the code was originally released in the 1980 and 1986 -* spacetrack papers. a detailed discussion of the theory and history -* may be found in the 2006 aiaa paper by vallado, crawford, hujsak, -* and kelso. -* -* companion code for -* fundamentals of astrodynamics and applications -* 2007 -* by david vallado -* -* (w) 719-573-2600, email dvallado@agi.com -* -* current : -* 20 apr 07 david vallado -* misc fixes for constants -* changes : -* 11 aug 06 david vallado -* chg lyddane choice back to strn3, constants, misc doc -* 15 dec 05 david vallado -* misc fixes -* 26 jul 05 david vallado -* fixes for paper -* note that each fix is preceded by a -* comment with "sgp4fix" and an explanation of -* what was changed -* 10 aug 04 david vallado -* 2nd printing baseline working -* 14 may 01 david vallado -* 2nd edition baseline -* 80 norad -* original baseline -* ---------------------------------------------------------------- */ - -#include -#include - -// -------------------------- structure declarations ---------------------------- -typedef enum -{ - wgs72old, - wgs72, - wgs84 -} gravconsttype; - -typedef struct elsetrec -{ - long int satnum; - int epochyr, epochtynumrev; - int error; - char init, method; - - /* Near Earth */ - int isimp; - double aycof , con41 , cc1 , cc4 , cc5 , d2 , d3 , d4 , - delmo , eta , argpdot, omgcof , sinmao , t , t2cof, t3cof , - t4cof , t5cof , x1mth2 , x7thm1 , mdot , nodedot, xlcof , xmcof , - nodecf; - - /* Deep Space */ - int irez; - double d2201 , d2211 , d3210 , d3222 , d4410 , d4422 , d5220 , d5232 , - d5421 , d5433 , dedt , del1 , del2 , del3 , didt , dmdt , - dnodt , domdt , e3 , ee2 , peo , pgho , pho , pinco , - plo , se2 , se3 , sgh2 , sgh3 , sgh4 , sh2 , sh3 , - si2 , si3 , sl2 , sl3 , sl4 , gsto , xfact , xgh2 , - xgh3 , xgh4 , xh2 , xh3 , xi2 , xi3 , xl2 , xl3 , - xl4 , xlamo , zmol , zmos , atime , xli , xni; - - double a , altp , alta , epochdays, jdsatepoch , nddot , ndot , - bstar , rcse , inclo , nodeo , ecco , argpo , mo , - no; -} elsetrec; - -// --------------------------- function declarations ---------------------------- -int sgp4init - ( - gravconsttype whichconst, const int satn, const double epoch, - const double xbstar, const double xecco, const double xargpo, - const double xinclo, const double xmo, const double xno, - const double xnodeo, - elsetrec& satrec - ); - -int sgp4 - ( - gravconsttype whichconst, - elsetrec& satrec, double tsince, - double r[], double v[] - ); - -double gstime - ( - double - ); - -void getgravconst - ( - gravconsttype, - double&, - double&, - double&, - double&, - double&, - double&, - double&, - double& - ); - -#endif - +#ifndef _sgp4unit_ +#define _sgp4unit_ +/* ---------------------------------------------------------------- +* +* sgp4unit.h +* +* this file contains the sgp4 procedures for analytical propagation +* of a satellite. the code was originally released in the 1980 and 1986 +* spacetrack papers. a detailed discussion of the theory and history +* may be found in the 2006 aiaa paper by vallado, crawford, hujsak, +* and kelso. +* +* companion code for +* fundamentals of astrodynamics and applications +* 2007 +* by david vallado +* +* (w) 719-573-2600, email dvallado@agi.com +* +* current : +* 20 apr 07 david vallado +* misc fixes for constants +* changes : +* 11 aug 06 david vallado +* chg lyddane choice back to strn3, constants, misc doc +* 15 dec 05 david vallado +* misc fixes +* 26 jul 05 david vallado +* fixes for paper +* note that each fix is preceded by a +* comment with "sgp4fix" and an explanation of +* what was changed +* 10 aug 04 david vallado +* 2nd printing baseline working +* 14 may 01 david vallado +* 2nd edition baseline +* 80 norad +* original baseline +* ---------------------------------------------------------------- */ + +#include +#include + +// -------------------------- structure declarations ---------------------------- +typedef enum +{ + wgs72old, + wgs72, + wgs84 +} gravconsttype; + +typedef struct elsetrec +{ + long int satnum; + int epochyr, epochtynumrev; + int error; + char init, method; + + /* Near Earth */ + int isimp; + double aycof , con41 , cc1 , cc4 , cc5 , d2 , d3 , d4 , + delmo , eta , argpdot, omgcof , sinmao , t , t2cof, t3cof , + t4cof , t5cof , x1mth2 , x7thm1 , mdot , nodedot, xlcof , xmcof , + nodecf; + + /* Deep Space */ + int irez; + double d2201 , d2211 , d3210 , d3222 , d4410 , d4422 , d5220 , d5232 , + d5421 , d5433 , dedt , del1 , del2 , del3 , didt , dmdt , + dnodt , domdt , e3 , ee2 , peo , pgho , pho , pinco , + plo , se2 , se3 , sgh2 , sgh3 , sgh4 , sh2 , sh3 , + si2 , si3 , sl2 , sl3 , sl4 , gsto , xfact , xgh2 , + xgh3 , xgh4 , xh2 , xh3 , xi2 , xi3 , xl2 , xl3 , + xl4 , xlamo , zmol , zmos , atime , xli , xni; + + double a , altp , alta , epochdays, jdsatepoch , nddot , ndot , + bstar , rcse , inclo , nodeo , ecco , argpo , mo , + no; +} elsetrec; + +// --------------------------- function declarations ---------------------------- +int sgp4init + ( + gravconsttype whichconst, const int satn, const double epoch, + const double xbstar, const double xecco, const double xargpo, + const double xinclo, const double xmo, const double xno, + const double xnodeo, + elsetrec& satrec + ); + +int sgp4 + ( + gravconsttype whichconst, + elsetrec& satrec, double tsince, + double r[], double v[] + ); + +double gstime + ( + double + ); + +void getgravconst + ( + gravconsttype, + double&, + double&, + double&, + double&, + double&, + double&, + double&, + double& + ); + +#endif + diff --git a/datalinklayer/MapPacketExtraction.cpp b/datalinklayer/MapPacketExtraction.cpp index cb12b321..d64348e1 100644 --- a/datalinklayer/MapPacketExtraction.cpp +++ b/datalinklayer/MapPacketExtraction.cpp @@ -18,7 +18,7 @@ MapPacketExtraction::MapPacketExtraction(uint8_t setMapId, object_id_t setPacketDestination) : lastSegmentationFlag(NO_SEGMENTATION), mapId(setMapId), packetLength(0), bufferPosition( packetBuffer), packetDestination(setPacketDestination), packetStore( - NULL), tcQueueId(MessageQueueSenderIF::NO_QUEUE) { + NULL), tcQueueId(MessageQueueIF::NO_QUEUE) { memset(packetBuffer, 0, sizeof(packetBuffer)); } diff --git a/devicehandlers/FixedSequenceSlot.cpp b/devicehandlers/FixedSequenceSlot.cpp deleted file mode 100644 index 667aba1d..00000000 --- a/devicehandlers/FixedSequenceSlot.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @file PollingSlot.cpp - * @brief This file defines the PollingSlot class. - * @date 19.12.2012 - * @author baetz - */ - -#include "FixedSequenceSlot.h" -#include "../objectmanager/SystemObjectIF.h" -#include - -FixedSequenceSlot::FixedSequenceSlot(object_id_t handlerId, uint32_t setTime, - int8_t setSequenceId, PeriodicTaskIF* executingTask) : - handler(NULL), pollingTimeMs(setTime), opcode(setSequenceId) { - handler = objectManager->get(handlerId); - handler->setTaskIF(executingTask); -} - -FixedSequenceSlot::~FixedSequenceSlot() {} - diff --git a/devicehandlers/HealthDevice.cpp b/devicehandlers/HealthDevice.cpp index 411731dc..b15e5d2b 100644 --- a/devicehandlers/HealthDevice.cpp +++ b/devicehandlers/HealthDevice.cpp @@ -5,7 +5,7 @@ HealthDevice::HealthDevice(object_id_t setObjectId, MessageQueueId_t parentQueue) : SystemObject(setObjectId), lastHealth(HEALTHY), parentQueue( parentQueue), commandQueue(), healthHelper(this, setObjectId) { - commandQueue = QueueFactory::instance()->createMessageQueue(3, CommandMessage::COMMAND_MESSAGE_SIZE); + commandQueue = QueueFactory::instance()->createMessageQueue(3); } HealthDevice::~HealthDevice() { diff --git a/events/fwSubsystemIdRanges.h b/events/fwSubsystemIdRanges.h index 5e086f0e..1b0b238e 100644 --- a/events/fwSubsystemIdRanges.h +++ b/events/fwSubsystemIdRanges.h @@ -19,6 +19,7 @@ enum { SYSTEM_MANAGER_1 = 75, SYSTEM_1 = 79, PUS_SERVICE_1 = 80, + PUS_SERVICE_9 = 89, PUS_SERVICE_17 = 97, FW_SUBSYSTEM_ID_RANGE }; diff --git a/globalfunctions/timevalOperations.cpp b/globalfunctions/timevalOperations.cpp index ae49ef21..1228da04 100644 --- a/globalfunctions/timevalOperations.cpp +++ b/globalfunctions/timevalOperations.cpp @@ -1,99 +1,99 @@ -#include "timevalOperations.h" - -timeval& operator+=(timeval& lhs, const timeval& rhs) { - int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec; - sum += rhs.tv_sec * 1000000. + rhs.tv_usec; - lhs.tv_sec = sum / 1000000; - lhs.tv_usec = sum - lhs.tv_sec * 1000000; - return lhs; -} - -timeval operator+(timeval lhs, const timeval& rhs) { - lhs += rhs; - return lhs; -} - -timeval& operator-=(timeval& lhs, const timeval& rhs) { - int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec; - sum -= rhs.tv_sec * 1000000. + rhs.tv_usec; - lhs.tv_sec = sum / 1000000; - lhs.tv_usec = sum - lhs.tv_sec * 1000000; - return lhs; -} - -timeval operator-(timeval lhs, const timeval& rhs) { - lhs -= rhs; - return lhs; -} - -double operator/(const timeval& lhs, const timeval& rhs) { - double lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; - double rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; - return lhs64 / rhs64; -} - -timeval& operator/=(timeval& lhs, double scalar) { - int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec; - product /= scalar; - lhs.tv_sec = product / 1000000; - lhs.tv_usec = product - lhs.tv_sec * 1000000; - return lhs; -} - -timeval operator/(timeval lhs, double scalar) { - lhs /= scalar; - return lhs; -} - -timeval& operator*=(timeval& lhs, double scalar) { - int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec; - product *= scalar; - lhs.tv_sec = product / 1000000; - lhs.tv_usec = product - lhs.tv_sec * 1000000; - return lhs; -} - -timeval operator*(timeval lhs, double scalar) { - lhs *= scalar; - return lhs; -} - -timeval operator*(double scalar, timeval rhs) { - rhs *= scalar; - return rhs; -} - -bool operator==(const timeval& lhs, const timeval& rhs) { - int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; - int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; - return lhs64 == rhs64; -} -bool operator!=(const timeval& lhs, const timeval& rhs) { - return !operator==(lhs, rhs); -} -bool operator<(const timeval& lhs, const timeval& rhs) { - int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; - int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; - return lhs64 < rhs64; -} -bool operator>(const timeval& lhs, const timeval& rhs) { - return operator<(rhs, lhs); -} -bool operator<=(const timeval& lhs, const timeval& rhs) { - return !operator>(lhs, rhs); -} -bool operator>=(const timeval& lhs, const timeval& rhs) { - return !operator<(lhs, rhs); -} - -double timevalOperations::toDouble(const timeval timeval) { - double result = timeval.tv_sec * 1000000. + timeval.tv_usec; - return result / 1000000.; -} - -timeval timevalOperations::toTimeval(const double seconds) { - timeval tval; - tval.tv_sec = seconds; - tval.tv_usec = seconds *(double) 1e6 - (tval.tv_sec *1e6); - return tval; -} +#include "timevalOperations.h" + +timeval& operator+=(timeval& lhs, const timeval& rhs) { + int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec; + sum += rhs.tv_sec * 1000000. + rhs.tv_usec; + lhs.tv_sec = sum / 1000000; + lhs.tv_usec = sum - lhs.tv_sec * 1000000; + return lhs; +} + +timeval operator+(timeval lhs, const timeval& rhs) { + lhs += rhs; + return lhs; +} + +timeval& operator-=(timeval& lhs, const timeval& rhs) { + int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec; + sum -= rhs.tv_sec * 1000000. + rhs.tv_usec; + lhs.tv_sec = sum / 1000000; + lhs.tv_usec = sum - lhs.tv_sec * 1000000; + return lhs; +} + +timeval operator-(timeval lhs, const timeval& rhs) { + lhs -= rhs; + return lhs; +} + +double operator/(const timeval& lhs, const timeval& rhs) { + double lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; + double rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; + return lhs64 / rhs64; +} + +timeval& operator/=(timeval& lhs, double scalar) { + int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec; + product /= scalar; + lhs.tv_sec = product / 1000000; + lhs.tv_usec = product - lhs.tv_sec * 1000000; + return lhs; +} + +timeval operator/(timeval lhs, double scalar) { + lhs /= scalar; + return lhs; +} + +timeval& operator*=(timeval& lhs, double scalar) { + int64_t product = lhs.tv_sec * 1000000. + lhs.tv_usec; + product *= scalar; + lhs.tv_sec = product / 1000000; + lhs.tv_usec = product - lhs.tv_sec * 1000000; + return lhs; +} + +timeval operator*(timeval lhs, double scalar) { + lhs *= scalar; + return lhs; +} + +timeval operator*(double scalar, timeval rhs) { + rhs *= scalar; + return rhs; +} + +bool operator==(const timeval& lhs, const timeval& rhs) { + int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; + int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; + return lhs64 == rhs64; +} +bool operator!=(const timeval& lhs, const timeval& rhs) { + return !operator==(lhs, rhs); +} +bool operator<(const timeval& lhs, const timeval& rhs) { + int64_t lhs64 = lhs.tv_sec * 1000000. + lhs.tv_usec; + int64_t rhs64 = rhs.tv_sec * 1000000. + rhs.tv_usec; + return lhs64 < rhs64; +} +bool operator>(const timeval& lhs, const timeval& rhs) { + return operator<(rhs, lhs); +} +bool operator<=(const timeval& lhs, const timeval& rhs) { + return !operator>(lhs, rhs); +} +bool operator>=(const timeval& lhs, const timeval& rhs) { + return !operator<(lhs, rhs); +} + +double timevalOperations::toDouble(const timeval timeval) { + double result = timeval.tv_sec * 1000000. + timeval.tv_usec; + return result / 1000000.; +} + +timeval timevalOperations::toTimeval(const double seconds) { + timeval tval; + tval.tv_sec = seconds; + tval.tv_usec = seconds *(double) 1e6 - (tval.tv_sec *1e6); + return tval; +} diff --git a/ipc/CommandMessage.cpp b/ipc/CommandMessage.cpp index dbea8533..513debd3 100644 --- a/ipc/CommandMessage.cpp +++ b/ipc/CommandMessage.cpp @@ -1,124 +1,96 @@ -/** - * @file CommandMessage.cpp - * @brief This file defines the CommandMessage class. - * @date 20.06.2013 - * @author baetz - */ - -#include "../devicehandlers/DeviceHandlerMessage.h" -#include "../health/HealthMessage.h" #include "CommandMessage.h" -#include "../memory/MemoryMessage.h" -#include "../modes/ModeMessage.h" -#include "../monitoring/MonitoringMessage.h" -#include "../subsystem/modes/ModeSequenceMessage.h" -#include "../tmstorage/TmStoreMessage.h" -#include "../parameters/ParameterMessage.h" - -namespace messagetypes { -void clearMissionMessage(CommandMessage* message); -} - +#include "CommandMessageCleaner.h" +#include CommandMessage::CommandMessage() { - this->messageSize = COMMAND_MESSAGE_SIZE; - setCommand(CMD_NONE); + MessageQueueMessage::setMessageSize(DEFAULT_COMMAND_MESSAGE_SIZE); + setCommand(CMD_NONE); } CommandMessage::CommandMessage(Command_t command, uint32_t parameter1, - uint32_t parameter2) { - this->messageSize = COMMAND_MESSAGE_SIZE; - setCommand(command); - setParameter(parameter1); - setParameter2(parameter2); + uint32_t parameter2) { + MessageQueueMessage::setMessageSize(DEFAULT_COMMAND_MESSAGE_SIZE); + setCommand(command); + setParameter(parameter1); + setParameter2(parameter2); } Command_t CommandMessage::getCommand() const { - Command_t command; - memcpy(&command, getData(), sizeof(Command_t)); - return command; + Command_t command; + std::memcpy(&command, MessageQueueMessage::getData(), sizeof(Command_t)); + return command; } void CommandMessage::setCommand(Command_t command) { - memcpy(getData(), &command, sizeof(command)); + std::memcpy(MessageQueueMessage::getData(), &command, sizeof(Command_t)); +} + +uint8_t CommandMessage::getMessageType() const { + // first byte of command ID. + return getCommand() >> 8 & 0xff; } uint32_t CommandMessage::getParameter() const { - uint32_t parameter1; - memcpy(¶meter1, getData() + sizeof(Command_t), sizeof(parameter1)); - return parameter1; + uint32_t parameter1; + std::memcpy(¶meter1, this->getData(), sizeof(parameter1)); + return parameter1; } void CommandMessage::setParameter(uint32_t parameter1) { - memcpy(getData() + sizeof(Command_t), ¶meter1, sizeof(parameter1)); + std::memcpy(this->getData(), ¶meter1, sizeof(parameter1)); } uint32_t CommandMessage::getParameter2() const { - uint32_t parameter2; - memcpy(¶meter2, getData() + sizeof(Command_t) + sizeof(uint32_t), - sizeof(parameter2)); - return parameter2; + uint32_t parameter2; + std::memcpy(¶meter2, this->getData() + sizeof(uint32_t), + sizeof(parameter2)); + return parameter2; } void CommandMessage::setParameter2(uint32_t parameter2) { - memcpy(getData() + sizeof(Command_t) + sizeof(uint32_t), ¶meter2, - sizeof(parameter2)); + std::memcpy(this->getData() + sizeof(uint32_t), ¶meter2, + sizeof(parameter2)); } -void CommandMessage::clearCommandMessage() { - switch((getCommand()>>8) & 0xff){ - case messagetypes::MODE_COMMAND: - ModeMessage::clear(this); - break; - case messagetypes::HEALTH_COMMAND: - HealthMessage::clear(this); - break; - case messagetypes::MODE_SEQUENCE: - ModeSequenceMessage::clear(this); - break; - case messagetypes::ACTION: - ActionMessage::clear(this); - break; - case messagetypes::DEVICE_HANDLER_COMMAND: - DeviceHandlerMessage::clear(this); - break; - case messagetypes::MEMORY: - MemoryMessage::clear(this); - break; - case messagetypes::MONITORING: - MonitoringMessage::clear(this); - break; - case messagetypes::TM_STORE: - TmStoreMessage::clear(this); - break; - case messagetypes::PARAMETER: - ParameterMessage::clear(this); - break; - default: - messagetypes::clearMissionMessage(this); - break; - } +uint32_t CommandMessage::getParameter3() const { + uint32_t parameter3; + std::memcpy(¶meter3, this->getData() + 2 * sizeof(uint32_t), + sizeof(parameter3)); + return parameter3; } -bool CommandMessage::isClearedCommandMessage() { - return getCommand() == CMD_NONE; +void CommandMessage::setParameter3(uint32_t parameter3) { + std::memcpy(this->getData() + 2 * sizeof(uint32_t), ¶meter3, + sizeof(parameter3)); } size_t CommandMessage::getMinimumMessageSize() const { - return COMMAND_MESSAGE_SIZE; + return MINIMUM_COMMAND_MESSAGE_SIZE; +} + +void CommandMessage::clearCommandMessage() { + clear(); +} + +void CommandMessage::clear() { + CommandMessageCleaner::clearCommandMessage(this); +} + +bool CommandMessage::isClearedCommandMessage() { + return getCommand() == CMD_NONE; } void CommandMessage::setToUnknownCommand() { - Command_t initialCommand = getCommand(); - clearCommandMessage(); - setReplyRejected(UNKNOWN_COMMAND, initialCommand); + Command_t initialCommand = getCommand(); + this->clear(); + setReplyRejected(UNKNOWN_COMMAND, initialCommand); } void CommandMessage::setReplyRejected(ReturnValue_t reason, - Command_t initialCommand) { + Command_t initialCommand) { setCommand(REPLY_REJECTED); - setParameter(reason); - setParameter2(initialCommand); + setParameter(reason); + setParameter2(initialCommand); } ReturnValue_t CommandMessage::getReplyRejectedReason( @@ -129,3 +101,11 @@ ReturnValue_t CommandMessage::getReplyRejectedReason( } return reason; } + +uint8_t* CommandMessage::getData() { + return MessageQueueMessage::getData() + sizeof(Command_t); +} + +const uint8_t* CommandMessage::getData() const { + return MessageQueueMessage::getData() + sizeof(Command_t); +} diff --git a/ipc/CommandMessage.h b/ipc/CommandMessage.h index e984ad3d..28822dd0 100644 --- a/ipc/CommandMessage.h +++ b/ipc/CommandMessage.h @@ -1,114 +1,88 @@ -/** - * @file CommandMessage.h - * @brief This file defines the CommandMessage class. - * @date 20.06.2013 - * @author baetz - */ +#ifndef FSFW_IPC_COMMANDMESSAGE_H_ +#define FSFW_IPC_COMMANDMESSAGE_H_ -#ifndef COMMANDMESSAGE_H_ -#define COMMANDMESSAGE_H_ - - -#include "FwMessageTypes.h" -#include +#include "CommandMessageIF.h" #include "MessageQueueMessage.h" +#include "FwMessageTypes.h" -#define MAKE_COMMAND_ID( number ) ((MESSAGE_ID << 8) + (number)) -typedef ReturnValue_t Command_t; - -class CommandMessage : public MessageQueueMessage { +/** + * @brief Default command message used to pass command messages between tasks. + * Primary message type for IPC. Contains sender, 2-byte command ID + * field, and 3 4-byte parameter + * @details + * It operates on an external memory which is contained inside a + * class implementing MessageQueueMessageIF by taking its address. + * This allows for a more flexible designs of message implementations. + * The pointer can be passed to different message implementations without + * the need of unnecessary copying. + * + * The command message is based of the generic MessageQueueMessage which + * currently has an internal message size of 28 bytes. + * @author Bastian Baetz + */ +class CommandMessage: public MessageQueueMessage, public CommandMessageIF { public: - static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_MESSAGE; - static const ReturnValue_t UNKNOWN_COMMAND = MAKE_RETURN_CODE(0x01); - - - static const uint8_t MESSAGE_ID = messagetypes::COMMAND; - static const Command_t CMD_NONE = MAKE_COMMAND_ID( 0 );//!< Used internally, will be ignored - static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID( 3 ); - static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID( 0xD1 );//!< Reply indicating that the current command was rejected, par1 should contain the error code + /** + * Default size can accomodate 3 4-byte parameters. + */ + static constexpr size_t DEFAULT_COMMAND_MESSAGE_SIZE = + CommandMessageIF::MINIMUM_COMMAND_MESSAGE_SIZE + + 3 * sizeof(uint32_t); /** - * This is the size of a message as it is seen by the MessageQueue - */ - static const size_t COMMAND_MESSAGE_SIZE = HEADER_SIZE - + sizeof(Command_t) + 2 * sizeof(uint32_t); - - /** - * Default Constructor, does not initialize anything. - * - * This constructor should be used when receiving a Message, as the content is filled by the MessageQueue. + * @brief Default Constructor, does not initialize anything. + * @details + * This constructor should be used when receiving a Message, as the + * content is filled by the MessageQueue. */ CommandMessage(); /** - * This constructor creates a new message with all message content initialized + * This constructor creates a new message with all message content + * initialized * * @param command The DeviceHandlerCommand_t that will be sent * @param parameter1 The first parameter * @param parameter2 The second parameter */ - CommandMessage(Command_t command, - uint32_t parameter1, uint32_t parameter2); + CommandMessage(Command_t command, uint32_t parameter1, uint32_t parameter2); /** - * Default Destructor + * @brief Default Destructor */ - virtual ~CommandMessage() { - } + virtual ~CommandMessage() {} - /** - * Read the DeviceHandlerCommand_t that is stored in the message, usually used after receiving - * - * @return the Command stored in the Message - */ - Command_t getCommand() const; + /** + * Read the DeviceHandlerCommand_t that is stored in the message, + * usually used after receiving. + * + * @return the Command stored in the Message + */ + virtual Command_t getCommand() const override; + /** + * Set the command type of the message. Default implementation also + * sets the message type, which will be the first byte of the command ID. + * @param the Command to be sent + */ + virtual void setCommand(Command_t command); - /** - * Set the DeviceHandlerCOmmand_t of the message - * - * @param the Command to be sent - */ - void setCommand(Command_t command); + virtual uint8_t* getData() override; + virtual const uint8_t* getData() const override; /** * Get the first parameter of the message - * * @return the first Parameter of the message */ uint32_t getParameter() const; - /** * Set the first parameter of the message - * * @param the first parameter of the message */ void setParameter(uint32_t parameter1); - - /** - * Get the second parameter of the message - * - * @return the second Parameter of the message - */ uint32_t getParameter2() const; - - /** - * Set the second parameter of the message - * - * @param the second parameter of the message - */ void setParameter2(uint32_t parameter2); - - /** - * Set the command to CMD_NONE and try to find - * the correct class to handle a more detailed - * clear. - * Also, calls a mission-specific clearMissionMessage - * function to separate between framework and mission - * messages. Not optimal, may be replaced by totally - * different auto-delete solution (e.g. smart pointers). - * - */ - void clearCommandMessage(); + uint32_t getParameter3() const; + void setParameter3(uint32_t parameter3); /** * check if a message was cleared @@ -117,18 +91,41 @@ public: */ bool isClearedCommandMessage(); - /** * Sets the command to REPLY_REJECTED with parameter UNKNOWN_COMMAND. * Is needed quite often, so we better code it once only. */ - void setToUnknownCommand(); - void setReplyRejected(ReturnValue_t reason, Command_t initialCommand = CMD_NONE); - ReturnValue_t getReplyRejectedReason( - Command_t *initialCommand = nullptr) const; + void setToUnknownCommand() override; - size_t getMinimumMessageSize() const; + /** + * A command message can be rejected and needs to offer a function + * to set a rejected reply + * @param reason + * @param initialCommand + */ + void setReplyRejected(ReturnValue_t reason, + Command_t initialCommand) override; + /** + * Corrensonding getter function. + * @param initialCommand + * @return + */ + ReturnValue_t getReplyRejectedReason( + Command_t* initialCommand = nullptr) const override; + + + virtual void clear() override; + void clearCommandMessage(); + + /** + * Extract message ID, which is the first byte of the command ID for the + * default implementation. + * @return + */ + virtual uint8_t getMessageType() const override; + + /** MessageQueueMessageIF functions used for minimum size check. */ + size_t getMinimumMessageSize() const override; }; - -#endif /* COMMANDMESSAGE_H_ */ +#endif /* FSFW_IPC_COMMANDMESSAGE_H_ */ diff --git a/ipc/CommandMessageCleaner.cpp b/ipc/CommandMessageCleaner.cpp new file mode 100644 index 00000000..6a99b4d2 --- /dev/null +++ b/ipc/CommandMessageCleaner.cpp @@ -0,0 +1,45 @@ +#include "../ipc/CommandMessageCleaner.h" + +#include "../devicehandlers/DeviceHandlerMessage.h" +#include "../health/HealthMessage.h" +#include "../memory/MemoryMessage.h" +#include "../modes/ModeMessage.h" +#include "../monitoring/MonitoringMessage.h" +#include "../subsystem/modes/ModeSequenceMessage.h" +#include "../tmstorage/TmStoreMessage.h" +#include "../parameters/ParameterMessage.h" + +void CommandMessageCleaner::clearCommandMessage(CommandMessage* message) { + switch(message->getMessageType()){ + case messagetypes::MODE_COMMAND: + ModeMessage::clear(message); + break; + case messagetypes::HEALTH_COMMAND: + HealthMessage::clear(message); + break; + case messagetypes::MODE_SEQUENCE: + ModeSequenceMessage::clear(message); + break; + case messagetypes::ACTION: + ActionMessage::clear(message); + break; + case messagetypes::DEVICE_HANDLER_COMMAND: + DeviceHandlerMessage::clear(message); + break; + case messagetypes::MEMORY: + MemoryMessage::clear(message); + break; + case messagetypes::MONITORING: + MonitoringMessage::clear(message); + break; + case messagetypes::TM_STORE: + TmStoreMessage::clear(message); + break; + case messagetypes::PARAMETER: + ParameterMessage::clear(message); + break; + default: + messagetypes::clearMissionMessage(message); + break; + } +} diff --git a/ipc/CommandMessageCleaner.h b/ipc/CommandMessageCleaner.h new file mode 100644 index 00000000..2bf4a193 --- /dev/null +++ b/ipc/CommandMessageCleaner.h @@ -0,0 +1,16 @@ +#ifndef FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ +#define FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ +#include "../ipc/CommandMessage.h" + +namespace messagetypes { +// Implemented in config. +void clearMissionMessage(CommandMessage* message); +} + +class CommandMessageCleaner { +public: + static void clearCommandMessage(CommandMessage* message); +}; + + +#endif /* FRAMEWORK_IPC_COMMANDMESSAGECLEANER_H_ */ diff --git a/ipc/CommandMessageIF.h b/ipc/CommandMessageIF.h new file mode 100644 index 00000000..aafa40ef --- /dev/null +++ b/ipc/CommandMessageIF.h @@ -0,0 +1,73 @@ +#ifndef FSFW_IPC_COMMANDMESSAGEIF_H_ +#define FSFW_IPC_COMMANDMESSAGEIF_H_ + +#include "MessageQueueMessageIF.h" +#include "FwMessageTypes.h" +#include "../returnvalues/HasReturnvaluesIF.h" + +#define MAKE_COMMAND_ID( number ) ((MESSAGE_ID << 8) + (number)) +typedef uint16_t Command_t; + +class CommandMessageIF { +public: + /** + * Header consists of sender ID and command ID. + */ + static constexpr size_t HEADER_SIZE = MessageQueueMessageIF::HEADER_SIZE + + sizeof(Command_t); + /** + * This minimum size is derived from the interface requirement to be able + * to set a rejected reply, which contains a returnvalue and the initial + * command. + */ + static constexpr size_t MINIMUM_COMMAND_MESSAGE_SIZE = + CommandMessageIF::HEADER_SIZE + sizeof(ReturnValue_t) + + sizeof(Command_t); + + static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_MESSAGE; + static const ReturnValue_t UNKNOWN_COMMAND = MAKE_RETURN_CODE(0x01); + + static const uint8_t MESSAGE_ID = messagetypes::COMMAND; + //! Used internally, shall be ignored + static const Command_t CMD_NONE = MAKE_COMMAND_ID( 0 ); + static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID( 1 ); + //! Reply indicating that the current command was rejected, + //! par1 should contain the error code + static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID( 2 ); + + virtual ~CommandMessageIF() {}; + + /** + * A command message shall have a uint16_t command ID field. + * @return + */ + virtual Command_t getCommand() const = 0; + /** + * A command message shall have a uint8_t message type ID field. + * @return + */ + virtual uint8_t getMessageType() const = 0; + + /** + * A command message can be rejected and needs to offer a function + * to set a rejected reply + * @param reason + * @param initialCommand + */ + virtual void setReplyRejected(ReturnValue_t reason, + Command_t initialCommand) = 0; + /** + * Corrensonding getter function. + * @param initialCommand + * @return + */ + virtual ReturnValue_t getReplyRejectedReason( + Command_t* initialCommand = nullptr) const = 0; + + virtual void setToUnknownCommand() = 0; + + virtual void clear() = 0; + +}; + +#endif /* FSFW_IPC_COMMANDMESSAGEIF_H_ */ diff --git a/ipc/MessageQueueIF.h b/ipc/MessageQueueIF.h index 9fff5287..b0347db9 100644 --- a/ipc/MessageQueueIF.h +++ b/ipc/MessageQueueIF.h @@ -1,15 +1,15 @@ -#ifndef FRAMEWORK_IPC_MESSAGEQUEUEIF_H_ -#define FRAMEWORK_IPC_MESSAGEQUEUEIF_H_ +#ifndef FSFW_IPC_MESSAGEQUEUEIF_H_ +#define FSFW_IPC_MESSAGEQUEUEIF_H_ // COULDDO: We could support blocking calls +#include "messageQueueDefinitions.h" #include "MessageQueueMessage.h" -#include "MessageQueueSenderIF.h" #include "../returnvalues/HasReturnvaluesIF.h" + class MessageQueueIF { public: - - static const MessageQueueId_t NO_QUEUE = MessageQueueSenderIF::NO_QUEUE; //!< Ugly hack. + static const MessageQueueId_t NO_QUEUE = 0; static const uint8_t INTERFACE_ID = CLASS_ID::MESSAGE_QUEUE_IF; /** diff --git a/ipc/MessageQueueMessage.cpp b/ipc/MessageQueueMessage.cpp index 05dde1f5..dcd4def3 100644 --- a/ipc/MessageQueueMessage.cpp +++ b/ipc/MessageQueueMessage.cpp @@ -1,13 +1,27 @@ #include "MessageQueueMessage.h" #include "../serviceinterface/ServiceInterfaceStream.h" - -#include +#include "../globalfunctions/arrayprinter.h" +#include MessageQueueMessage::MessageQueueMessage() : - messageSize(this->HEADER_SIZE) { + messageSize(getMinimumMessageSize()) { memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); } +MessageQueueMessage::MessageQueueMessage(uint8_t* data, size_t size) : + messageSize(this->HEADER_SIZE + size) { + if (size <= this->MAX_DATA_SIZE) { + memcpy(this->getData(), data, size); + this->messageSize = this->HEADER_SIZE + size; + } + else { + sif::warning << "MessageQueueMessage: Passed size larger than maximum" + "allowed size! Setting content to 0" << std::endl; + memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); + this->messageSize = this->HEADER_SIZE; + } +} + MessageQueueMessage::~MessageQueueMessage() { } @@ -37,29 +51,34 @@ void MessageQueueMessage::setSender(MessageQueueId_t setId) { memcpy(this->internalBuffer, &setId, sizeof(MessageQueueId_t)); } -MessageQueueMessage::MessageQueueMessage(uint8_t* data, uint32_t size) : - messageSize(this->HEADER_SIZE + size) { - if (size <= this->MAX_DATA_SIZE) { - memcpy(this->getData(), data, size); - } else { - memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); - this->messageSize = this->HEADER_SIZE; +void MessageQueueMessage::print(bool printWholeMessage) { + sif::debug << "MessageQueueMessage content: " << std::endl; + if(printWholeMessage) { + arrayprinter::print(getData(), getMaximumMessageSize()); } -} - -size_t MessageQueueMessage::getMinimumMessageSize() { - return this->HEADER_SIZE; -} - -void MessageQueueMessage::print() { - sif::debug << "MessageQueueMessage has size: " << this->messageSize << std::hex - << std::endl; - for (uint8_t count = 0; count < this->messageSize; count++) { - sif::debug << (uint32_t) this->internalBuffer[count] << ":"; + else { + arrayprinter::print(getData(), getMessageSize()); } - sif::debug << std::dec << std::endl; + } void MessageQueueMessage::clear() { memset(this->getBuffer(), 0, this->MAX_MESSAGE_SIZE); } + +size_t MessageQueueMessage::getMessageSize() const { + return this->messageSize; +} + +void MessageQueueMessage::setMessageSize(size_t messageSize) { + this->messageSize = messageSize; +} + +size_t MessageQueueMessage::getMinimumMessageSize() const { + return this->MIN_MESSAGE_SIZE; +} + +size_t MessageQueueMessage::getMaximumMessageSize() const { + return this->MAX_MESSAGE_SIZE; +} + diff --git a/ipc/MessageQueueMessage.h b/ipc/MessageQueueMessage.h index aa3559d6..5234f64f 100644 --- a/ipc/MessageQueueMessage.h +++ b/ipc/MessageQueueMessage.h @@ -1,118 +1,149 @@ -#ifndef MESSAGEQUEUEMESSAGE_H_ -#define MESSAGEQUEUEMESSAGE_H_ +#ifndef FSFW_IPC_MESSAGEQUEUEMESSAGE_H_ +#define FSFW_IPC_MESSAGEQUEUEMESSAGE_H_ -#include "MessageQueueSenderIF.h" -#include +#include "../ipc/MessageQueueMessageIF.h" +#include /** - * \brief This class is the representation and data organizer for interprocess messages. + * @brief This class is the representation and data organizer + * for interprocess messages. + * @details + * To facilitate and standardize interprocess communication, this class was + * created to handle a lightweight "interprocess message protocol". * - * \details To facilitate and standardize interprocess communication, this class was created - * to handle a lightweight "interprocess message protocol". It adds a header with the - * sender's queue id to every sent message and defines the maximum total message size. - * Specialized messages, such as device commanding messages, can be created by inheriting - * from this class and filling the buffer provided by getData with additional content. - * If larger amounts of data must be sent between processes, the data shall be stored in - * the IPC Store object and only the storage id is passed in a queue message. - * The class is used both to generate and send messages and to receive messages from - * other tasks. - * \ingroup message_queue + * It adds a header with the sender's queue id to every sent message and + * defines the maximum total message size. Specialized messages, such as + * device commanding messages, can be created by inheriting from this class + * and filling the buffer provided by getData with additional content. + * + * If larger amounts of data must be sent between processes, the data shall + * be stored in the IPC Store object and only the storage id is passed in a + * queue message.The class is used both to generate and send messages and to + * receive messages from other tasks. + * @ingroup message_queue */ -class MessageQueueMessage { +class MessageQueueMessage: public MessageQueueMessageIF { public: /** - * \brief This constant defines the maximum size of the data content, excluding the header. - * \details It may be changed if necessary, but in general should be kept as small as possible. + * @brief The class is initialized empty with this constructor. + * @details + * The messageSize attribute is set to the header's size and the whole + * content is set to zero. + */ + MessageQueueMessage(); + /** + * @brief With this constructor the class is initialized with + * the given content. + * @details + * If the passed message size fits into the buffer, the passed data is + * copied to the internal buffer and the messageSize information is set. + * Otherwise, messageSize is set to the header's size and the whole + * content is set to zero. + * @param data The data to be put in the message. + * @param size Size of the data to be copied. Must be smaller than + * MAX_MESSAGE_SIZE and larger than MIN_MESSAGE_SIZE. + */ + MessageQueueMessage(uint8_t* data, size_t size); + + /** + * @brief As no memory is allocated in this class, + * the destructor is empty. + */ + virtual ~MessageQueueMessage(); + + /** + * @brief The size information of each message is stored in + * this attribute. + * @details + * It is public to simplify usage and to allow for passing the size + * address as a pointer. Care must be taken when inheriting from this class, + * as every child class is responsible for managing the size information by + * itself. When using the class to receive a message, the size information + * is updated automatically. + * + * Please note that the minimum size is limited by the size of the header + * while the maximum size is limited by the maximum allowed message size. + */ + size_t messageSize; + /** + * @brief This constant defines the maximum size of the data content, + * excluding the header. + * @details + * It may be changed if necessary, but in general should be kept + * as small as possible. */ static const size_t MAX_DATA_SIZE = 24; + /** - * \brief This constants defines the size of the header, which is added to every message. + * @brief This constant defines the maximum total size in bytes + * of a sent message. + * @details + * It is the sum of the maximum data and the header size. Be aware that + * this constant is used to define the buffer sizes for every message + * queue in the system. So, a change here may have significant impact on + * the required resources. */ - static const size_t HEADER_SIZE = sizeof(MessageQueueId_t); + static constexpr size_t MAX_MESSAGE_SIZE = MAX_DATA_SIZE + HEADER_SIZE; /** - * \brief This constant defines the maximum total size in bytes of a sent message. - * \details It is the sum of the maximum data and the header size. Be aware that this constant - * is used to define the buffer sizes for every message queue in the system. So, a change - * here may have significant impact on the required resources. + * @brief Defines the minimum size of a message where only the + * header is included */ - static const size_t MAX_MESSAGE_SIZE = MAX_DATA_SIZE + HEADER_SIZE; + static constexpr size_t MIN_MESSAGE_SIZE = HEADER_SIZE; private: /** - * \brief This is the internal buffer that contains the actual message data. + * @brief This is the internal buffer that contains the + * actual message data. */ uint8_t internalBuffer[MAX_MESSAGE_SIZE]; public: /** - * \brief The size information of each message is stored in this attribute. - * \details It is public to simplify usage and to allow for passing the variable's address as a - * pointer. Care must be taken when inheriting from this class, as every child class is - * responsible for managing the size information by itself. When using the class to - * receive a message, the size information is updated automatically. + * @brief This method is used to get the complete data of the message. */ - size_t messageSize; + const uint8_t* getBuffer() const override; /** - * \brief The class is initialized empty with this constructor. - * \details The messageSize attribute is set to the header's size and the whole content is set to - * zero. + * @brief This method is used to get the complete data of the message. */ - MessageQueueMessage(); + uint8_t* getBuffer() override; /** - * \brief With this constructor the class is initialized with the given content. - * \details If the passed message size fits into the buffer, the passed data is copied to the - * internal buffer and the messageSize information is set. Otherwise, messageSize - * is set to the header's size and the whole content is set to zero. - * \param data The data to be put in the message. - * \param size Size of the data to be copied. Must be smaller than MAX_MESSAGE_SIZE. + * @brief This method is used to fetch the data content of the message. + * @details + * It shall be used by child classes to add data at the right position. */ - MessageQueueMessage(uint8_t* data, uint32_t size); + const uint8_t* getData() const override; /** - * \brief As no memory is allocated in this class, the destructor is empty. + * @brief This method is used to fetch the data content of the message. + * @details + * It shall be used by child classes to add data at the right position. */ - virtual ~MessageQueueMessage(); + uint8_t* getData() override; /** - * \brief This method is used to get the complete data of the message. + * @brief This method is used to extract the sender's message + * queue id information from a received message. */ - const uint8_t* getBuffer() const; + MessageQueueId_t getSender() const override; /** - * \brief This method is used to get the complete data of the message. + * @brief With this method, the whole content + * and the message size is set to zero. */ - uint8_t* getBuffer(); + void clear() override; + /** - * \brief This method is used to fetch the data content of the message. - * \details It shall be used by child classes to add data at the right position. + * @brief This method is used to set the sender's message queue id + * information prior to ing the message. + * @param setId + * The message queue id that identifies the sending message queue. */ - const uint8_t* getData() const; + void setSender(MessageQueueId_t setId) override; + + virtual size_t getMessageSize() const override; + virtual void setMessageSize(size_t messageSize) override; + virtual size_t getMinimumMessageSize() const override; + virtual size_t getMaximumMessageSize() const override; + /** - * \brief This method is used to fetch the data content of the message. - * \details It shall be used by child classes to add data at the right position. + * @brief This is a debug method that prints the content. */ - uint8_t* getData(); - /** - * \brief This method is used to extract the sender's message queue id information from a - * received message. - */ - MessageQueueId_t getSender() const; - /** - * \brief With this method, the whole content and the message size is set to zero. - */ - void clear(); - /** - * \brief This is a debug method that prints the content (till messageSize) to the debug output. - */ - void print(); - /** - * \brief This method is used to set the sender's message queue id information prior to - * sending the message. - * \param setId The message queue id that identifies the sending message queue. - */ - void setSender(MessageQueueId_t setId); - /** - * \brief This helper function is used by the MessageQueue class to check the size of an - * incoming message. - * \details The method must be overwritten by child classes if size checks shall be more strict. - * @return The default implementation returns HEADER_SIZE. - */ - virtual size_t getMinimumMessageSize(); + void print(bool printWholeMessage); }; -#endif /* MESSAGEQUEUEMESSAGE_H_ */ +#endif /* FSFW_IPC_MESSAGEQUEUEMESSAGE_H_ */ diff --git a/ipc/MessageQueueMessageIF.h b/ipc/MessageQueueMessageIF.h new file mode 100644 index 00000000..b5a30c08 --- /dev/null +++ b/ipc/MessageQueueMessageIF.h @@ -0,0 +1,80 @@ +#ifndef FRAMEWORK_IPC_MESSAGEQUEUEMESSAGEIF_H_ +#define FRAMEWORK_IPC_MESSAGEQUEUEMESSAGEIF_H_ + +#include +#include +#include + +class MessageQueueMessageIF { +public: + + /** + * @brief This constants defines the size of the header, + * which is added to every message. + */ + static const size_t HEADER_SIZE = sizeof(MessageQueueId_t); + + virtual ~MessageQueueMessageIF() {}; + + /** + * @brief With this method, the whole content and the message + * size is set to zero. + * @details + * Implementations should also take care to clear data which is stored + * indirectly (e.g. storage data). + */ + virtual void clear() = 0; + + /** + * @brief Get read-only pointer to the complete data of the message. + * @return + */ + virtual const uint8_t* getBuffer() const = 0; + + /** + * @brief This method is used to get the complete data of the message. + */ + virtual uint8_t* getBuffer() = 0; + + /** + * @brief This method is used to set the sender's message queue id + * information prior to sending the message. + * @param setId + * The message queue id that identifies the sending message queue. + */ + virtual void setSender(MessageQueueId_t setId) = 0; + + /** + * @brief This method is used to extract the sender's message queue id + * information from a received message. + */ + virtual MessageQueueId_t getSender() const = 0; + + /** + * @brief This method is used to fetch the data content of the message. + * @details + * It shall be used by child classes to add data at the right position. + */ + virtual const uint8_t* getData() const = 0; + /** + * @brief This method is used to fetch the data content of the message. + * @details + * It shall be used by child classes to add data at the right position. + */ + virtual uint8_t* getData() = 0; + + /** + * Get constant message size of current message implementation. + * @return + */ + virtual size_t getMessageSize() const = 0; + + virtual void setMessageSize(size_t messageSize) = 0; + virtual size_t getMinimumMessageSize() const = 0; + virtual size_t getMaximumMessageSize() const = 0; + +}; + + + +#endif /* FRAMEWORK_IPC_MESSAGEQUEUEMESSAGEIF_H_ */ diff --git a/ipc/MessageQueueSenderIF.h b/ipc/MessageQueueSenderIF.h index d9692f54..7eea5146 100644 --- a/ipc/MessageQueueSenderIF.h +++ b/ipc/MessageQueueSenderIF.h @@ -1,37 +1,26 @@ -#ifndef FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_ -#define FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_ +#ifndef FSFW_IPC_MESSAGEQUEUESENDERIF_H_ +#define FSFW_IPC_MESSAGEQUEUESENDERIF_H_ +#include "../ipc/MessageQueueIF.h" +#include "../ipc/MessageQueueMessageIF.h" #include "../objectmanager/ObjectManagerIF.h" -class MessageQueueMessage; - - -//TODO: Actually, the definition of this ID to be a uint32_t is not ideal and breaks layering. -//However, it is difficult to keep layering, as the ID is stored in many places and sent around in -//MessageQueueMessage. -//Ideally, one would use the (current) object_id_t only, however, doing a lookup of queueIDs for every -//call does not sound ideal. -//In a first step, I'll circumvent the issue by not touching it, maybe in a second step. -//This also influences Interface design (getCommandQueue) and some other issues.. -typedef uint32_t MessageQueueId_t; class MessageQueueSenderIF { public: - static const MessageQueueId_t NO_QUEUE = 0; virtual ~MessageQueueSenderIF() {} /** - * Allows sending messages without actually "owing" a message queue. + * Allows sending messages without actually "owning" a message queue. * Not sure whether this is actually a good idea. - * Must be implemented by a subclass. */ static ReturnValue_t sendMessage(MessageQueueId_t sendTo, - MessageQueueMessage* message, MessageQueueId_t sentFrom = - MessageQueueSenderIF::NO_QUEUE, bool ignoreFault=false); + MessageQueueMessage* message, + MessageQueueId_t sentFrom = MessageQueueIF::NO_QUEUE, + bool ignoreFault = false); private: MessageQueueSenderIF() {} }; - -#endif /* FRAMEWORK_IPC_MESSAGEQUEUESENDERIF_H_ */ +#endif /* FSFW_IPC_MESSAGEQUEUESENDERIF_H_ */ diff --git a/ipc/messageQueueDefinitions.h b/ipc/messageQueueDefinitions.h new file mode 100644 index 00000000..d250da8a --- /dev/null +++ b/ipc/messageQueueDefinitions.h @@ -0,0 +1,18 @@ +#ifndef FSFW_IPC_MESSAGEQUEUEDEFINITIONS_H_ +#define FSFW_IPC_MESSAGEQUEUEDEFINITIONS_H_ + +#include + +/* + * TODO: Actually, the definition of this ID to be a uint32_t is not ideal and + * breaks layering. However, it is difficult to keep layering, as the ID is + * stored in many places and sent around in MessageQueueMessage. + * Ideally, one would use the (current) object_id_t only, however, doing a + * lookup of queueIDs for every call does not sound ideal. + * In a first step, I'll circumvent the issue by not touching it, + * maybe in a second step. This also influences Interface design + * (getCommandQueue) and some other issues.. + */ +using MessageQueueId_t = uint32_t; + +#endif /* FSFW_IPC_MESSAGEQUEUEDEFINITIONS_H_ */ diff --git a/modes/ModeHelper.cpp b/modes/ModeHelper.cpp index cb62c468..f464a743 100644 --- a/modes/ModeHelper.cpp +++ b/modes/ModeHelper.cpp @@ -36,7 +36,7 @@ ReturnValue_t ModeHelper::handleModeCommand(CommandMessage* message) { commandedMode = mode; commandedSubmode = submode; - if ((parentQueueId != MessageQueueSenderIF::NO_QUEUE) + if ((parentQueueId != MessageQueueIF::NO_QUEUE) && (theOneWhoCommandedAMode != parentQueueId)) { owner->setToExternalControl(); } @@ -74,7 +74,7 @@ ReturnValue_t ModeHelper::initialize(MessageQueueId_t parentQueueId) { void ModeHelper::modeChanged(Mode_t mode, Submode_t submode) { forced = false; CommandMessage reply; - if (theOneWhoCommandedAMode != MessageQueueSenderIF::NO_QUEUE) { + if (theOneWhoCommandedAMode != MessageQueueIF::NO_QUEUE) { if ((mode != commandedMode) || (submode != commandedSubmode)) { ModeMessage::setModeMessage(&reply, ModeMessage::REPLY_WRONG_MODE_REPLY, mode, submode); @@ -86,12 +86,12 @@ void ModeHelper::modeChanged(Mode_t mode, Submode_t submode) { owner->getCommandQueue()); } if (theOneWhoCommandedAMode != parentQueueId - && parentQueueId != MessageQueueSenderIF::NO_QUEUE) { + && parentQueueId != MessageQueueIF::NO_QUEUE) { ModeMessage::setModeMessage(&reply, ModeMessage::REPLY_MODE_INFO, mode, submode); MessageQueueSenderIF::sendMessage(parentQueueId, &reply, owner->getCommandQueue()); } - theOneWhoCommandedAMode = MessageQueueSenderIF::NO_QUEUE; + theOneWhoCommandedAMode = MessageQueueIF::NO_QUEUE; } void ModeHelper::startTimer(uint32_t timeoutMs) { diff --git a/objectmanager/frameworkObjects.h b/objectmanager/frameworkObjects.h index 4a30e70a..4d08f084 100644 --- a/objectmanager/frameworkObjects.h +++ b/objectmanager/frameworkObjects.h @@ -4,11 +4,13 @@ namespace 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, + PUS_SERVICE_1_VERIFICATION = 0x53000001, + PUS_SERVICE_2_DEVICE_ACCESS = 0x53000002, + PUS_SERVICE_5_EVENT_REPORTING = 0x53000005, + PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008, + PUS_SERVICE_9_TIME_MGMT = 0x53000009, + PUS_SERVICE_17_TEST = 0x53000017, + PUS_SERVICE_200_MODE_MGMT = 0x53000200, //Generic IDs for IPC, modes, health, events HEALTH_TABLE = 0x53010000, diff --git a/osal/FreeRTOS/BinSemaphUsingTask.cpp b/osal/FreeRTOS/BinSemaphUsingTask.cpp index 8c831bbe..dd1e48ca 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.cpp +++ b/osal/FreeRTOS/BinSemaphUsingTask.cpp @@ -1,95 +1,95 @@ -#include "../../osal/FreeRTOS/BinSemaphUsingTask.h" -#include "../../osal/FreeRTOS/TaskManagement.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() { - handle = TaskManagement::getCurrentTaskHandle(); - if(handle == nullptr) { - sif::error << "Could not retrieve task handle. Please ensure the" - "constructor was called inside a task." << std::endl; - } - xTaskNotifyGive(handle); -} - -BinarySemaphoreUsingTask::~BinarySemaphoreUsingTask() { - // Clear notification value on destruction. - xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); -} - -ReturnValue_t BinarySemaphoreUsingTask::acquire(TimeoutType timeoutType, - uint32_t timeoutMs) { - TickType_t timeout = 0; - if(timeoutType == TimeoutType::POLLING) { - timeout = 0; - } - else if(timeoutType == TimeoutType::WAITING){ - timeout = pdMS_TO_TICKS(timeoutMs); - } - else { - timeout = portMAX_DELAY; - } - return acquireWithTickTimeout(timeoutType, timeout); -} - -ReturnValue_t BinarySemaphoreUsingTask::acquireWithTickTimeout( - TimeoutType timeoutType, TickType_t timeoutTicks) { - BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SemaphoreIF::SEMAPHORE_TIMEOUT; - } -} - -ReturnValue_t BinarySemaphoreUsingTask::release() { - return release(this->handle); -} - -ReturnValue_t BinarySemaphoreUsingTask::release( - TaskHandle_t taskHandle) { - if(getSemaphoreCounter(taskHandle) == 1) { - return SemaphoreIF::SEMAPHORE_NOT_OWNED; - } - BaseType_t returncode = xTaskNotifyGive(taskHandle); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - // This should never happen. - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -TaskHandle_t BinarySemaphoreUsingTask::getTaskHandle() { - return handle; -} - -uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() const { - return getSemaphoreCounter(this->handle); -} - -uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter( - TaskHandle_t taskHandle) { - uint32_t notificationValue; - xTaskNotifyAndQuery(taskHandle, 0, eNoAction, ¬ificationValue); - return notificationValue; -} - -// Be careful with the stack size here. This is called from an ISR! -ReturnValue_t BinarySemaphoreUsingTask::releaseFromISR( - TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) { - if(getSemaphoreCounterFromISR(taskHandle, higherPriorityTaskWoken) == 1) { - return SemaphoreIF::SEMAPHORE_NOT_OWNED; - } - vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken); - return HasReturnvaluesIF::RETURN_OK; -} - -uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR( - TaskHandle_t taskHandle, BaseType_t* higherPriorityTaskWoken) { - uint32_t notificationValue = 0; - xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, ¬ificationValue, - higherPriorityTaskWoken); - return notificationValue; -} +#include "../../osal/FreeRTOS/BinSemaphUsingTask.h" +#include "../../osal/FreeRTOS/TaskManagement.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() { + handle = TaskManagement::getCurrentTaskHandle(); + if(handle == nullptr) { + sif::error << "Could not retrieve task handle. Please ensure the" + "constructor was called inside a task." << std::endl; + } + xTaskNotifyGive(handle); +} + +BinarySemaphoreUsingTask::~BinarySemaphoreUsingTask() { + // Clear notification value on destruction. + xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); +} + +ReturnValue_t BinarySemaphoreUsingTask::acquire(TimeoutType timeoutType, + uint32_t timeoutMs) { + TickType_t timeout = 0; + if(timeoutType == TimeoutType::POLLING) { + timeout = 0; + } + else if(timeoutType == TimeoutType::WAITING){ + timeout = pdMS_TO_TICKS(timeoutMs); + } + else { + timeout = portMAX_DELAY; + } + return acquireWithTickTimeout(timeoutType, timeout); +} + +ReturnValue_t BinarySemaphoreUsingTask::acquireWithTickTimeout( + TimeoutType timeoutType, TickType_t timeoutTicks) { + BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t BinarySemaphoreUsingTask::release() { + return release(this->handle); +} + +ReturnValue_t BinarySemaphoreUsingTask::release( + TaskHandle_t taskHandle) { + if(getSemaphoreCounter(taskHandle) == 1) { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + BaseType_t returncode = xTaskNotifyGive(taskHandle); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + // This should never happen. + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +TaskHandle_t BinarySemaphoreUsingTask::getTaskHandle() { + return handle; +} + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() const { + return getSemaphoreCounter(this->handle); +} + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter( + TaskHandle_t taskHandle) { + uint32_t notificationValue; + xTaskNotifyAndQuery(taskHandle, 0, eNoAction, ¬ificationValue); + return notificationValue; +} + +// Be careful with the stack size here. This is called from an ISR! +ReturnValue_t BinarySemaphoreUsingTask::releaseFromISR( + TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) { + if(getSemaphoreCounterFromISR(taskHandle, higherPriorityTaskWoken) == 1) { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken); + return HasReturnvaluesIF::RETURN_OK; +} + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR( + TaskHandle_t taskHandle, BaseType_t* higherPriorityTaskWoken) { + uint32_t notificationValue = 0; + xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, ¬ificationValue, + higherPriorityTaskWoken); + return notificationValue; +} diff --git a/osal/FreeRTOS/BinSemaphUsingTask.h b/osal/FreeRTOS/BinSemaphUsingTask.h index 2d2cf159..f3c0b0ea 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.h +++ b/osal/FreeRTOS/BinSemaphUsingTask.h @@ -1,76 +1,76 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ -#define FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ - -#include "../../returnvalues/HasReturnvaluesIF.h" -#include "../../tasks/SemaphoreIF.h" - -#include -#include - -/** - * @brief Binary Semaphore implementation using the task notification value. - * The notification value should therefore not be used - * for other purposes. - * @details - * Additional information: https://www.freertos.org/RTOS-task-notifications.html - * and general semaphore documentation. - */ -class BinarySemaphoreUsingTask: public SemaphoreIF, - public HasReturnvaluesIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; - - //! @brief Default ctor - BinarySemaphoreUsingTask(); - //! @brief Default dtor - virtual~ BinarySemaphoreUsingTask(); - - ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, - uint32_t timeoutMs = portMAX_DELAY) override; - ReturnValue_t release() override; - uint8_t getSemaphoreCounter() const override; - static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle); - static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle, - BaseType_t* higherPriorityTaskWoken); - - /** - * Same as acquire() with timeout in FreeRTOS ticks. - * @param timeoutTicks - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure - */ - ReturnValue_t acquireWithTickTimeout( - TimeoutType timeoutType = TimeoutType::BLOCKING, - TickType_t timeoutTicks = portMAX_DELAY); - - /** - * Get handle to the task related to the semaphore. - * @return - */ - TaskHandle_t getTaskHandle(); - - /** - * Wrapper function to give back semaphore from handle - * @param semaphore - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure - */ - static ReturnValue_t release(TaskHandle_t taskToNotify); - - /** - * Wrapper function to give back semaphore from handle when called from an ISR - * @param semaphore - * @param higherPriorityTaskWoken This will be set to pdPASS if a task with - * a higher priority was unblocked. A context switch should be requested - * from an ISR if this is the case (see TaskManagement functions) - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure - */ - static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, - BaseType_t * higherPriorityTaskWoken); - -protected: - TaskHandle_t handle; -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ +#define FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ + +#include "../../returnvalues/HasReturnvaluesIF.h" +#include "../../tasks/SemaphoreIF.h" + +#include +#include + +/** + * @brief Binary Semaphore implementation using the task notification value. + * The notification value should therefore not be used + * for other purposes. + * @details + * Additional information: https://www.freertos.org/RTOS-task-notifications.html + * and general semaphore documentation. + */ +class BinarySemaphoreUsingTask: public SemaphoreIF, + public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + + //! @brief Default ctor + BinarySemaphoreUsingTask(); + //! @brief Default dtor + virtual~ BinarySemaphoreUsingTask(); + + ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, + uint32_t timeoutMs = portMAX_DELAY) override; + ReturnValue_t release() override; + uint8_t getSemaphoreCounter() const override; + static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle); + static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle, + BaseType_t* higherPriorityTaskWoken); + + /** + * Same as acquire() with timeout in FreeRTOS ticks. + * @param timeoutTicks + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + ReturnValue_t acquireWithTickTimeout( + TimeoutType timeoutType = TimeoutType::BLOCKING, + TickType_t timeoutTicks = portMAX_DELAY); + + /** + * Get handle to the task related to the semaphore. + * @return + */ + TaskHandle_t getTaskHandle(); + + /** + * Wrapper function to give back semaphore from handle + * @param semaphore + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + static ReturnValue_t release(TaskHandle_t taskToNotify); + + /** + * Wrapper function to give back semaphore from handle when called from an ISR + * @param semaphore + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with + * a higher priority was unblocked. A context switch should be requested + * from an ISR if this is the case (see TaskManagement functions) + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, + BaseType_t * higherPriorityTaskWoken); + +protected: + TaskHandle_t handle; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ */ diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index f1c78473..8cc3c495 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -1,108 +1,108 @@ -#include "../../osal/FreeRTOS/BinarySemaphore.h" -#include "../../osal/FreeRTOS/TaskManagement.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -BinarySemaphore::BinarySemaphore() { - handle = xSemaphoreCreateBinary(); - if(handle == nullptr) { - sif::error << "Semaphore: Binary semaph creation failure" << std::endl; - } - // Initiated semaphore must be given before it can be taken. - xSemaphoreGive(handle); -} - -BinarySemaphore::~BinarySemaphore() { - vSemaphoreDelete(handle); -} - -BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { - handle = xSemaphoreCreateBinary(); - if(handle == nullptr) { - sif::error << "Binary semaphore creation failure" << std::endl; - } - xSemaphoreGive(handle); -} - -BinarySemaphore& BinarySemaphore::operator =( - BinarySemaphore&& s) { - if(&s != this) { - handle = xSemaphoreCreateBinary(); - if(handle == nullptr) { - sif::error << "Binary semaphore creation failure" << std::endl; - } - xSemaphoreGive(handle); - } - return *this; -} - -ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType, - uint32_t timeoutMs) { - TickType_t timeout = 0; - if(timeoutType == TimeoutType::POLLING) { - timeout = 0; - } - else if(timeoutType == TimeoutType::WAITING){ - timeout = pdMS_TO_TICKS(timeoutMs); - } - else { - timeout = portMAX_DELAY; - } - return acquireWithTickTimeout(timeoutType, timeout); -} - -ReturnValue_t BinarySemaphore::acquireWithTickTimeout(TimeoutType timeoutType, - TickType_t timeoutTicks) { - if(handle == nullptr) { - return SemaphoreIF::SEMAPHORE_INVALID; - } - - BaseType_t returncode = xSemaphoreTake(handle, timeoutTicks); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SemaphoreIF::SEMAPHORE_TIMEOUT; - } -} - -ReturnValue_t BinarySemaphore::release() { - return release(handle); -} - -ReturnValue_t BinarySemaphore::release(SemaphoreHandle_t semaphore) { - if (semaphore == nullptr) { - return SemaphoreIF::SEMAPHORE_INVALID; - } - BaseType_t returncode = xSemaphoreGive(semaphore); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SemaphoreIF::SEMAPHORE_NOT_OWNED; - } -} - -uint8_t BinarySemaphore::getSemaphoreCounter() const { - return uxSemaphoreGetCount(handle); -} - -SemaphoreHandle_t BinarySemaphore::getSemaphore() { - return handle; -} - - -// Be careful with the stack size here. This is called from an ISR! -ReturnValue_t BinarySemaphore::releaseFromISR( - SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) { - if (semaphore == nullptr) { - return SemaphoreIF::SEMAPHORE_INVALID; - } - BaseType_t returncode = xSemaphoreGiveFromISR(semaphore, - higherPriorityTaskWoken); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SemaphoreIF::SEMAPHORE_NOT_OWNED; - } -} +#include "../../osal/FreeRTOS/BinarySemaphore.h" +#include "../../osal/FreeRTOS/TaskManagement.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +BinarySemaphore::BinarySemaphore() { + handle = xSemaphoreCreateBinary(); + if(handle == nullptr) { + sif::error << "Semaphore: Binary semaph creation failure" << std::endl; + } + // Initiated semaphore must be given before it can be taken. + xSemaphoreGive(handle); +} + +BinarySemaphore::~BinarySemaphore() { + vSemaphoreDelete(handle); +} + +BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { + handle = xSemaphoreCreateBinary(); + if(handle == nullptr) { + sif::error << "Binary semaphore creation failure" << std::endl; + } + xSemaphoreGive(handle); +} + +BinarySemaphore& BinarySemaphore::operator =( + BinarySemaphore&& s) { + if(&s != this) { + handle = xSemaphoreCreateBinary(); + if(handle == nullptr) { + sif::error << "Binary semaphore creation failure" << std::endl; + } + xSemaphoreGive(handle); + } + return *this; +} + +ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType, + uint32_t timeoutMs) { + TickType_t timeout = 0; + if(timeoutType == TimeoutType::POLLING) { + timeout = 0; + } + else if(timeoutType == TimeoutType::WAITING){ + timeout = pdMS_TO_TICKS(timeoutMs); + } + else { + timeout = portMAX_DELAY; + } + return acquireWithTickTimeout(timeoutType, timeout); +} + +ReturnValue_t BinarySemaphore::acquireWithTickTimeout(TimeoutType timeoutType, + TickType_t timeoutTicks) { + if(handle == nullptr) { + return SemaphoreIF::SEMAPHORE_INVALID; + } + + BaseType_t returncode = xSemaphoreTake(handle, timeoutTicks); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t BinarySemaphore::release() { + return release(handle); +} + +ReturnValue_t BinarySemaphore::release(SemaphoreHandle_t semaphore) { + if (semaphore == nullptr) { + return SemaphoreIF::SEMAPHORE_INVALID; + } + BaseType_t returncode = xSemaphoreGive(semaphore); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } +} + +uint8_t BinarySemaphore::getSemaphoreCounter() const { + return uxSemaphoreGetCount(handle); +} + +SemaphoreHandle_t BinarySemaphore::getSemaphore() { + return handle; +} + + +// Be careful with the stack size here. This is called from an ISR! +ReturnValue_t BinarySemaphore::releaseFromISR( + SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) { + if (semaphore == nullptr) { + return SemaphoreIF::SEMAPHORE_INVALID; + } + BaseType_t returncode = xSemaphoreGiveFromISR(semaphore, + higherPriorityTaskWoken); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } +} diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 5a32088a..c6cedc53 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -1,107 +1,107 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ -#define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ - -#include "../../returnvalues/HasReturnvaluesIF.h" -#include "../../tasks/SemaphoreIF.h" - -#include -#include - -/** - * @brief OS Tool to achieve synchronization of between tasks or between - * task and ISR. The default semaphore implementation creates a - * binary semaphore, which can only be taken once. - * @details - * Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html - * - * Please note that if the semaphore implementation is only related to - * the synchronization of one task, the new task notifications can be used, - * also see the BinSemaphUsingTask and CountingSemaphUsingTask classes. - * These use the task notification value instead of a queue and are - * faster and more efficient. - * - * @author R. Mueller - * @ingroup osal - */ -class BinarySemaphore: public SemaphoreIF, - public HasReturnvaluesIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; - - //! @brief Default ctor - BinarySemaphore(); - //! @brief Copy ctor, deleted explicitely. - BinarySemaphore(const BinarySemaphore&) = delete; - //! @brief Copy assignment, deleted explicitely. - BinarySemaphore& operator=(const BinarySemaphore&) = delete; - //! @brief Move ctor - BinarySemaphore (BinarySemaphore &&); - //! @brief Move assignment - BinarySemaphore & operator=(BinarySemaphore &&); - //! @brief Destructor - virtual ~BinarySemaphore(); - - uint8_t getSemaphoreCounter() const override; - - /** - * Take the binary semaphore. - * 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 example by an ISR or another task. - * @param timeoutMs - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout - */ - ReturnValue_t acquire(TimeoutType timeoutType = - TimeoutType::BLOCKING, uint32_t timeoutMs = portMAX_DELAY) override; - - /** - * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. - * @param timeoutTicks - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout - */ - ReturnValue_t acquireWithTickTimeout(TimeoutType timeoutType = - TimeoutType::BLOCKING, TickType_t timeoutTicks = portMAX_DELAY); - - /** - * Release the binary semaphore. - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is - * already available. - */ - ReturnValue_t release() override; - - /** - * Get Handle to the semaphore. - * @return - */ - SemaphoreHandle_t getSemaphore(); - - /** - * Wrapper function to give back semaphore from handle - * @param semaphore - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is - * already available. - */ - static ReturnValue_t release(SemaphoreHandle_t semaphore); - - /** - * Wrapper function to give back semaphore from handle when called from an ISR - * @param semaphore - * @param higherPriorityTaskWoken This will be set to pdPASS if a task with - * a higher priority was unblocked. A context switch from an ISR should - * then be requested (see TaskManagement functions) - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is - * already available. - */ - static ReturnValue_t releaseFromISR(SemaphoreHandle_t semaphore, - BaseType_t * higherPriorityTaskWoken); - -protected: - SemaphoreHandle_t handle; -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ +#define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ + +#include "../../returnvalues/HasReturnvaluesIF.h" +#include "../../tasks/SemaphoreIF.h" + +#include +#include + +/** + * @brief OS Tool to achieve synchronization of between tasks or between + * task and ISR. The default semaphore implementation creates a + * binary semaphore, which can only be taken once. + * @details + * Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html + * + * Please note that if the semaphore implementation is only related to + * the synchronization of one task, the new task notifications can be used, + * also see the BinSemaphUsingTask and CountingSemaphUsingTask classes. + * These use the task notification value instead of a queue and are + * faster and more efficient. + * + * @author R. Mueller + * @ingroup osal + */ +class BinarySemaphore: public SemaphoreIF, + public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + + //! @brief Default ctor + BinarySemaphore(); + //! @brief Copy ctor, deleted explicitely. + BinarySemaphore(const BinarySemaphore&) = delete; + //! @brief Copy assignment, deleted explicitely. + BinarySemaphore& operator=(const BinarySemaphore&) = delete; + //! @brief Move ctor + BinarySemaphore (BinarySemaphore &&); + //! @brief Move assignment + BinarySemaphore & operator=(BinarySemaphore &&); + //! @brief Destructor + virtual ~BinarySemaphore(); + + uint8_t getSemaphoreCounter() const override; + + /** + * Take the binary semaphore. + * 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 example by an ISR or another task. + * @param timeoutMs + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout + */ + ReturnValue_t acquire(TimeoutType timeoutType = + TimeoutType::BLOCKING, uint32_t timeoutMs = portMAX_DELAY) override; + + /** + * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. + * @param timeoutTicks + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout + */ + ReturnValue_t acquireWithTickTimeout(TimeoutType timeoutType = + TimeoutType::BLOCKING, TickType_t timeoutTicks = portMAX_DELAY); + + /** + * Release the binary semaphore. + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is + * already available. + */ + ReturnValue_t release() override; + + /** + * Get Handle to the semaphore. + * @return + */ + SemaphoreHandle_t getSemaphore(); + + /** + * Wrapper function to give back semaphore from handle + * @param semaphore + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is + * already available. + */ + static ReturnValue_t release(SemaphoreHandle_t semaphore); + + /** + * Wrapper function to give back semaphore from handle when called from an ISR + * @param semaphore + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with + * a higher priority was unblocked. A context switch from an ISR should + * then be requested (see TaskManagement functions) + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is + * already available. + */ + static ReturnValue_t releaseFromISR(SemaphoreHandle_t semaphore, + BaseType_t * higherPriorityTaskWoken); + +protected: + SemaphoreHandle_t handle; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.cpp b/osal/FreeRTOS/CountingSemaphUsingTask.cpp index e66671ac..a47341bc 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.cpp +++ b/osal/FreeRTOS/CountingSemaphUsingTask.cpp @@ -1,114 +1,114 @@ -#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" -#include "../../osal/FreeRTOS/TaskManagement.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount, - uint8_t initCount): maxCount(maxCount) { - if(initCount > maxCount) { - sif::error << "CountingSemaphoreUsingTask: Max count bigger than " - "intial cout. Setting initial count to max count." << std::endl; - initCount = maxCount; - } - - handle = TaskManagement::getCurrentTaskHandle(); - if(handle == nullptr) { - sif::error << "CountingSemaphoreUsingTask: Could not retrieve task " - "handle. Please ensure the constructor was called inside a " - "task." << std::endl; - } - - uint32_t oldNotificationValue; - xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, - &oldNotificationValue); - if(oldNotificationValue != 0) { - sif::warning << "CountinSemaphoreUsingTask: Semaphore initiated but " - "current notification value is not 0. Please ensure the " - "notification value is not used for other purposes!" << std::endl; - } - for(int i = 0; i < initCount; i++) { - xTaskNotifyGive(handle); - } -} - -CountingSemaphoreUsingTask::~CountingSemaphoreUsingTask() { - // Clear notification value on destruction. - // If this is not desired, don't call the destructor - // (or implement a boolean which disables the reset) - xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); -} - -ReturnValue_t CountingSemaphoreUsingTask::acquire(TimeoutType timeoutType, - uint32_t timeoutMs) { - TickType_t timeout = 0; - if(timeoutType == TimeoutType::POLLING) { - timeout = 0; - } - else if(timeoutType == TimeoutType::WAITING){ - timeout = pdMS_TO_TICKS(timeoutMs); - } - else { - timeout = portMAX_DELAY; - } - return acquireWithTickTimeout(timeoutType, timeout); - -} - -ReturnValue_t CountingSemaphoreUsingTask::acquireWithTickTimeout( - TimeoutType timeoutType, TickType_t timeoutTicks) { - // Decrement notfication value without resetting it. - BaseType_t oldCount = ulTaskNotifyTake(pdFALSE, timeoutTicks); - if (getSemaphoreCounter() == oldCount - 1) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SemaphoreIF::SEMAPHORE_TIMEOUT; - } -} - -ReturnValue_t CountingSemaphoreUsingTask::release() { - if(getSemaphoreCounter() == maxCount) { - return SemaphoreIF::SEMAPHORE_NOT_OWNED; - } - return release(handle); -} - -ReturnValue_t CountingSemaphoreUsingTask::release( - TaskHandle_t taskToNotify) { - BaseType_t returncode = xTaskNotifyGive(taskToNotify); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - // This should never happen. - return HasReturnvaluesIF::RETURN_FAILED; - } -} - - -uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() const { - uint32_t notificationValue = 0; - xTaskNotifyAndQuery(handle, 0, eNoAction, ¬ificationValue); - return notificationValue; -} - -TaskHandle_t CountingSemaphoreUsingTask::getTaskHandle() { - return handle; -} - -ReturnValue_t CountingSemaphoreUsingTask::releaseFromISR( - TaskHandle_t taskToNotify, BaseType_t* higherPriorityTaskWoken) { - vTaskNotifyGiveFromISR(taskToNotify, higherPriorityTaskWoken); - return HasReturnvaluesIF::RETURN_OK; -} - -uint8_t CountingSemaphoreUsingTask::getSemaphoreCounterFromISR( - TaskHandle_t task, BaseType_t* higherPriorityTaskWoken) { - uint32_t notificationValue; - xTaskNotifyAndQueryFromISR(task, 0, eNoAction, ¬ificationValue, - higherPriorityTaskWoken); - return notificationValue; -} - -uint8_t CountingSemaphoreUsingTask::getMaxCount() const { - return maxCount; -} +#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" +#include "../../osal/FreeRTOS/TaskManagement.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount, + uint8_t initCount): maxCount(maxCount) { + if(initCount > maxCount) { + sif::error << "CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count." << std::endl; + initCount = maxCount; + } + + handle = TaskManagement::getCurrentTaskHandle(); + if(handle == nullptr) { + sif::error << "CountingSemaphoreUsingTask: Could not retrieve task " + "handle. Please ensure the constructor was called inside a " + "task." << std::endl; + } + + uint32_t oldNotificationValue; + xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, + &oldNotificationValue); + if(oldNotificationValue != 0) { + sif::warning << "CountinSemaphoreUsingTask: Semaphore initiated but " + "current notification value is not 0. Please ensure the " + "notification value is not used for other purposes!" << std::endl; + } + for(int i = 0; i < initCount; i++) { + xTaskNotifyGive(handle); + } +} + +CountingSemaphoreUsingTask::~CountingSemaphoreUsingTask() { + // Clear notification value on destruction. + // If this is not desired, don't call the destructor + // (or implement a boolean which disables the reset) + xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); +} + +ReturnValue_t CountingSemaphoreUsingTask::acquire(TimeoutType timeoutType, + uint32_t timeoutMs) { + TickType_t timeout = 0; + if(timeoutType == TimeoutType::POLLING) { + timeout = 0; + } + else if(timeoutType == TimeoutType::WAITING){ + timeout = pdMS_TO_TICKS(timeoutMs); + } + else { + timeout = portMAX_DELAY; + } + return acquireWithTickTimeout(timeoutType, timeout); + +} + +ReturnValue_t CountingSemaphoreUsingTask::acquireWithTickTimeout( + TimeoutType timeoutType, TickType_t timeoutTicks) { + // Decrement notfication value without resetting it. + BaseType_t oldCount = ulTaskNotifyTake(pdFALSE, timeoutTicks); + if (getSemaphoreCounter() == oldCount - 1) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t CountingSemaphoreUsingTask::release() { + if(getSemaphoreCounter() == maxCount) { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + return release(handle); +} + +ReturnValue_t CountingSemaphoreUsingTask::release( + TaskHandle_t taskToNotify) { + BaseType_t returncode = xTaskNotifyGive(taskToNotify); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + // This should never happen. + return HasReturnvaluesIF::RETURN_FAILED; + } +} + + +uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() const { + uint32_t notificationValue = 0; + xTaskNotifyAndQuery(handle, 0, eNoAction, ¬ificationValue); + return notificationValue; +} + +TaskHandle_t CountingSemaphoreUsingTask::getTaskHandle() { + return handle; +} + +ReturnValue_t CountingSemaphoreUsingTask::releaseFromISR( + TaskHandle_t taskToNotify, BaseType_t* higherPriorityTaskWoken) { + vTaskNotifyGiveFromISR(taskToNotify, higherPriorityTaskWoken); + return HasReturnvaluesIF::RETURN_OK; +} + +uint8_t CountingSemaphoreUsingTask::getSemaphoreCounterFromISR( + TaskHandle_t task, BaseType_t* higherPriorityTaskWoken) { + uint32_t notificationValue; + xTaskNotifyAndQueryFromISR(task, 0, eNoAction, ¬ificationValue, + higherPriorityTaskWoken); + return notificationValue; +} + +uint8_t CountingSemaphoreUsingTask::getMaxCount() const { + return maxCount; +} diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.h b/osal/FreeRTOS/CountingSemaphUsingTask.h index e3733382..8977258c 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.h +++ b/osal/FreeRTOS/CountingSemaphUsingTask.h @@ -1,102 +1,102 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ -#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ - -#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" -#include "../../tasks/SemaphoreIF.h" - -extern "C" { -#include -#include -} - -/** - * @brief Couting Semaphore implementation which uses the notification value - * of the task. The notification value should therefore not be used - * for other purposes. - * @details - * Additional information: https://www.freertos.org/RTOS-task-notifications.html - * and general semaphore documentation. - */ -class CountingSemaphoreUsingTask: public SemaphoreIF { -public: - CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount); - virtual ~CountingSemaphoreUsingTask(); - - /** - * Acquire the counting semaphore. - * If no semaphores are available, the task will be blocked - * for a maximum of #timeoutMs or until one is given back, - * for example by an ISR or another task. - * @param timeoutMs - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout - */ - ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, - uint32_t timeoutMs = portMAX_DELAY) override; - - /** - * Release a semaphore, increasing the number of available counting - * semaphores up to the #maxCount value. - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are - * already available. - */ - ReturnValue_t release() override; - - uint8_t getSemaphoreCounter() const override; - /** - * Get the semaphore counter from an ISR. - * @param task - * @param higherPriorityTaskWoken This will be set to pdPASS if a task with - * a higher priority was unblocked. A context switch should be requested - * from an ISR if this is the case (see TaskManagement functions) - * @return - */ - static uint8_t getSemaphoreCounterFromISR(TaskHandle_t task, - BaseType_t* higherPriorityTaskWoken); - - /** - * Acquire with a timeout value in ticks - * @param timeoutTicks - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout - */ - ReturnValue_t acquireWithTickTimeout( - TimeoutType timeoutType = TimeoutType::BLOCKING, - TickType_t timeoutTicks = portMAX_DELAY); - - /** - * Get handle to the task related to the semaphore. - * @return - */ - TaskHandle_t getTaskHandle(); - - /** - * Release semaphore of task by supplying task handle - * @param taskToNotify - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are - * already available. - */ - static ReturnValue_t release(TaskHandle_t taskToNotify); - /** - * Release seamphore of a task from an ISR. - * @param taskToNotify - * @param higherPriorityTaskWoken This will be set to pdPASS if a task with - * a higher priority was unblocked. A context switch should be requested - * from an ISR if this is the case (see TaskManagement functions) - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are - * already available. - */ - static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, - BaseType_t* higherPriorityTaskWoken); - - uint8_t getMaxCount() const; - -private: - TaskHandle_t handle; - const uint8_t maxCount; -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ +#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ + +#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" +#include "../../tasks/SemaphoreIF.h" + +extern "C" { +#include +#include +} + +/** + * @brief Couting Semaphore implementation which uses the notification value + * of the task. The notification value should therefore not be used + * for other purposes. + * @details + * Additional information: https://www.freertos.org/RTOS-task-notifications.html + * and general semaphore documentation. + */ +class CountingSemaphoreUsingTask: public SemaphoreIF { +public: + CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount); + virtual ~CountingSemaphoreUsingTask(); + + /** + * Acquire the counting semaphore. + * If no semaphores are available, the task will be blocked + * for a maximum of #timeoutMs or until one is given back, + * for example by an ISR or another task. + * @param timeoutMs + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout + */ + ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, + uint32_t timeoutMs = portMAX_DELAY) override; + + /** + * Release a semaphore, increasing the number of available counting + * semaphores up to the #maxCount value. + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are + * already available. + */ + ReturnValue_t release() override; + + uint8_t getSemaphoreCounter() const override; + /** + * Get the semaphore counter from an ISR. + * @param task + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with + * a higher priority was unblocked. A context switch should be requested + * from an ISR if this is the case (see TaskManagement functions) + * @return + */ + static uint8_t getSemaphoreCounterFromISR(TaskHandle_t task, + BaseType_t* higherPriorityTaskWoken); + + /** + * Acquire with a timeout value in ticks + * @param timeoutTicks + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout + */ + ReturnValue_t acquireWithTickTimeout( + TimeoutType timeoutType = TimeoutType::BLOCKING, + TickType_t timeoutTicks = portMAX_DELAY); + + /** + * Get handle to the task related to the semaphore. + * @return + */ + TaskHandle_t getTaskHandle(); + + /** + * Release semaphore of task by supplying task handle + * @param taskToNotify + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are + * already available. + */ + static ReturnValue_t release(TaskHandle_t taskToNotify); + /** + * Release seamphore of a task from an ISR. + * @param taskToNotify + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with + * a higher priority was unblocked. A context switch should be requested + * from an ISR if this is the case (see TaskManagement functions) + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are + * already available. + */ + static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, + BaseType_t* higherPriorityTaskWoken); + + uint8_t getMaxCount() const; + +private: + TaskHandle_t handle; + const uint8_t maxCount; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ */ diff --git a/osal/FreeRTOS/CountingSemaphore.cpp b/osal/FreeRTOS/CountingSemaphore.cpp index 0b218e54..d1310a6a 100644 --- a/osal/FreeRTOS/CountingSemaphore.cpp +++ b/osal/FreeRTOS/CountingSemaphore.cpp @@ -1,43 +1,43 @@ -#include "../../osal/FreeRTOS/CountingSemaphore.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" -#include "../../osal/FreeRTOS/TaskManagement.h" - -#include - -// Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in -// free FreeRTOSConfig.h file. -CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): - maxCount(maxCount), initCount(initCount) { - if(initCount > maxCount) { - sif::error << "CountingSemaphoreUsingTask: Max count bigger than " - "intial cout. Setting initial count to max count." << std::endl; - initCount = maxCount; - } - - handle = xSemaphoreCreateCounting(maxCount, initCount); - if(handle == nullptr) { - sif::error << "CountingSemaphore: Creation failure" << std::endl; - } -} - -CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): - maxCount(other.maxCount), initCount(other.initCount) { - handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); - if(handle == nullptr) { - sif::error << "CountingSemaphore: Creation failure" << std::endl; - } -} - -CountingSemaphore& CountingSemaphore::operator =( - CountingSemaphore&& other) { - handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); - if(handle == nullptr) { - sif::error << "CountingSemaphore: Creation failure" << std::endl; - } - return * this; -} - - -uint8_t CountingSemaphore::getMaxCount() const { - return maxCount; -} +#include "../../osal/FreeRTOS/CountingSemaphore.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../osal/FreeRTOS/TaskManagement.h" + +#include + +// Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in +// free FreeRTOSConfig.h file. +CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): + maxCount(maxCount), initCount(initCount) { + if(initCount > maxCount) { + sif::error << "CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count." << std::endl; + initCount = maxCount; + } + + handle = xSemaphoreCreateCounting(maxCount, initCount); + if(handle == nullptr) { + sif::error << "CountingSemaphore: Creation failure" << std::endl; + } +} + +CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): + maxCount(other.maxCount), initCount(other.initCount) { + handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); + if(handle == nullptr) { + sif::error << "CountingSemaphore: Creation failure" << std::endl; + } +} + +CountingSemaphore& CountingSemaphore::operator =( + CountingSemaphore&& other) { + handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); + if(handle == nullptr) { + sif::error << "CountingSemaphore: Creation failure" << std::endl; + } + return * this; +} + + +uint8_t CountingSemaphore::getMaxCount() const { + return maxCount; +} diff --git a/osal/FreeRTOS/CountingSemaphore.h b/osal/FreeRTOS/CountingSemaphore.h index 9432ed81..ae2f62ae 100644 --- a/osal/FreeRTOS/CountingSemaphore.h +++ b/osal/FreeRTOS/CountingSemaphore.h @@ -1,34 +1,34 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ -#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ -#include "../../osal/FreeRTOS/BinarySemaphore.h" - -/** - * @brief Counting semaphores, which can be acquire more than once. - * @details - * See: https://www.freertos.org/CreateCounting.html - * API of counting semaphores is almost identical to binary semaphores, - * so we just inherit from binary semaphore and provide the respective - * constructors. - */ -class CountingSemaphore: public BinarySemaphore { -public: - CountingSemaphore(const uint8_t maxCount, uint8_t initCount); - //! @brief Copy ctor, disabled - CountingSemaphore(const CountingSemaphore&) = delete; - //! @brief Copy assignment, disabled - CountingSemaphore& operator=(const CountingSemaphore&) = delete; - //! @brief Move ctor - CountingSemaphore (CountingSemaphore &&); - //! @brief Move assignment - CountingSemaphore & operator=(CountingSemaphore &&); - - /* Same API as binary semaphore otherwise. acquire() can be called - * until there are not semaphores left and release() can be called - * until maxCount is reached. */ - uint8_t getMaxCount() const; -private: - const uint8_t maxCount; - uint8_t initCount = 0; -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ +#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ +#include "../../osal/FreeRTOS/BinarySemaphore.h" + +/** + * @brief Counting semaphores, which can be acquire more than once. + * @details + * See: https://www.freertos.org/CreateCounting.html + * API of counting semaphores is almost identical to binary semaphores, + * so we just inherit from binary semaphore and provide the respective + * constructors. + */ +class CountingSemaphore: public BinarySemaphore { +public: + CountingSemaphore(const uint8_t maxCount, uint8_t initCount); + //! @brief Copy ctor, disabled + CountingSemaphore(const CountingSemaphore&) = delete; + //! @brief Copy assignment, disabled + CountingSemaphore& operator=(const CountingSemaphore&) = delete; + //! @brief Move ctor + CountingSemaphore (CountingSemaphore &&); + //! @brief Move assignment + CountingSemaphore & operator=(CountingSemaphore &&); + + /* Same API as binary semaphore otherwise. acquire() can be called + * until there are not semaphores left and release() can be called + * until maxCount is reached. */ + uint8_t getMaxCount() const; +private: + const uint8_t maxCount; + uint8_t initCount = 0; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ diff --git a/osal/FreeRTOS/FixedTimeslotTask.cpp b/osal/FreeRTOS/FixedTimeslotTask.cpp index 4873dde4..062686e2 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.cpp +++ b/osal/FreeRTOS/FixedTimeslotTask.cpp @@ -8,7 +8,7 @@ const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE; FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority, TaskStackSize setStack, TaskPeriod overallPeriod, void (*setDeadlineMissedFunc)()) : - started(false), handle(NULL), pst(overallPeriod * 1000) { + started(false), handle(nullptr), pst(overallPeriod * 1000) { configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle); // All additional attributes are applied to the object. @@ -62,8 +62,10 @@ ReturnValue_t FixedTimeslotTask::startTask() { ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep) { - if (objectManager->get(componentId) != nullptr) { - pst.addSlot(componentId, slotTimeMs, executionStep, this); + ExecutableObjectIF* handler = + objectManager->get(componentId); + if (handler != nullptr) { + pst.addSlot(componentId, slotTimeMs, executionStep, handler, this); return HasReturnvaluesIF::RETURN_OK; } @@ -85,6 +87,8 @@ void FixedTimeslotTask::taskFunctionality() { // start time for the first entry. auto slotListIter = pst.current; + pst.intializeSequenceAfterTaskCreation(); + //The start time for the first entry is read. uint32_t intervalMs = slotListIter->pollingTimeMs; TickType_t interval = pdMS_TO_TICKS(intervalMs); @@ -143,10 +147,6 @@ void FixedTimeslotTask::checkMissedDeadline(const TickType_t xLastWakeTime, } void FixedTimeslotTask::handleMissedDeadline() { -#ifdef DEBUG - sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) << - " missed deadline!\n" << std::flush; -#endif if(deadlineMissedFunc != nullptr) { this->deadlineMissedFunc(); } diff --git a/osal/FreeRTOS/FixedTimeslotTask.h b/osal/FreeRTOS/FixedTimeslotTask.h index 84264c4c..7d2cdb70 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.h +++ b/osal/FreeRTOS/FixedTimeslotTask.h @@ -1,12 +1,11 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ -#define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ +#ifndef FSFW_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ +#define FSFW_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ #include "FreeRTOSTaskIF.h" -#include "../../devicehandlers/FixedSlotSequence.h" +#include "../../tasks/FixedSlotSequence.h" #include "../../tasks/FixedTimeslotTaskIF.h" #include "../../tasks/Typedef.h" - #include #include @@ -99,4 +98,4 @@ protected: void handleMissedDeadline(); }; -#endif /* FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ */ +#endif /* FSFW_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ */ diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index 3bbd4d9d..6c8e1de9 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -1,5 +1,6 @@ #include "MessageQueue.h" +#include "../../objectmanager/ObjectManagerIF.h" #include "../../serviceinterface/ServiceInterfaceStream.h" // TODO I guess we should have a way of checking if we are in an ISR and then use the "fromISR" versions of all calls @@ -101,7 +102,8 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, reinterpret_cast(message->getBuffer()), 0); if (result != pdPASS) { if (!ignoreFault) { - InternalErrorReporterIF* internalErrorReporter = objectManager->get( + InternalErrorReporterIF* internalErrorReporter = + objectManager->get( objects::INTERNAL_ERROR_REPORTER); if (internalErrorReporter != NULL) { internalErrorReporter->queueMessageNotSent(); diff --git a/osal/FreeRTOS/PeriodicTask.cpp b/osal/FreeRTOS/PeriodicTask.cpp index 990d38d6..5c0a840d 100644 --- a/osal/FreeRTOS/PeriodicTask.cpp +++ b/osal/FreeRTOS/PeriodicTask.cpp @@ -133,10 +133,6 @@ TaskHandle_t PeriodicTask::getTaskHandle() { } void PeriodicTask::handleMissedDeadline() { -#ifdef DEBUG - sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) << - " missed deadline!\n" << std::flush; -#endif if(deadlineMissedFunc != nullptr) { this->deadlineMissedFunc(); } diff --git a/osal/FreeRTOS/QueueFactory.cpp b/osal/FreeRTOS/QueueFactory.cpp index e639179a..153d9b51 100644 --- a/osal/FreeRTOS/QueueFactory.cpp +++ b/osal/FreeRTOS/QueueFactory.cpp @@ -1,18 +1,21 @@ +#include "../../ipc/MessageQueueSenderIF.h" #include "../../ipc/QueueFactory.h" #include "MessageQueue.h" -QueueFactory* QueueFactory::factoryInstance = NULL; +QueueFactory* QueueFactory::factoryInstance = nullptr; ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, - MessageQueueMessage* message, MessageQueueId_t sentFrom,bool ignoreFault) { - return MessageQueue::sendMessageFromMessageQueue(sendTo,message,sentFrom,ignoreFault); + MessageQueueMessage* message, MessageQueueId_t sentFrom, + bool ignoreFault) { + return MessageQueue::sendMessageFromMessageQueue(sendTo,message, + sentFrom,ignoreFault); } QueueFactory* QueueFactory::instance() { - if (factoryInstance == NULL) { + if (factoryInstance == nullptr) { factoryInstance = new QueueFactory; } return factoryInstance; @@ -24,9 +27,9 @@ QueueFactory::QueueFactory() { QueueFactory::~QueueFactory() { } -MessageQueueIF* QueueFactory::createMessageQueue(uint32_t message_depth, +MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) { - return new MessageQueue(message_depth, maxMessageSize); + return new MessageQueue(messageDepth, maxMessageSize); } void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { diff --git a/osal/FreeRTOS/SemaphoreFactory.cpp b/osal/FreeRTOS/SemaphoreFactory.cpp index 8575cf4a..beb0d096 100644 --- a/osal/FreeRTOS/SemaphoreFactory.cpp +++ b/osal/FreeRTOS/SemaphoreFactory.cpp @@ -1,59 +1,59 @@ -#include "../../osal/FreeRTOS/BinarySemaphore.h" -#include "../../osal/FreeRTOS/BinSemaphUsingTask.h" -#include "../../osal/FreeRTOS/CountingSemaphore.h" -#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" -#include "../../tasks/SemaphoreFactory.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; - -static const uint32_t USE_REGULAR_SEMAPHORES = 0; -static const uint32_t USE_TASK_NOTIFICATIONS = 1; - -SemaphoreFactory::SemaphoreFactory() { -} - -SemaphoreFactory::~SemaphoreFactory() { - delete factoryInstance; -} - -SemaphoreFactory* SemaphoreFactory::instance() { - if (factoryInstance == nullptr){ - factoryInstance = new SemaphoreFactory(); - } - return SemaphoreFactory::factoryInstance; -} - -SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) { - if(argument == USE_REGULAR_SEMAPHORES) { - return new BinarySemaphore(); - } - else if(argument == USE_TASK_NOTIFICATIONS) { - return new BinarySemaphoreUsingTask(); - } - else { - sif::warning << "SemaphoreFactory: Invalid argument, return regular" - "binary semaphore" << std::endl; - return new BinarySemaphore(); - } -} - -SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount, - uint8_t initCount, uint32_t argument) { - if(argument == USE_REGULAR_SEMAPHORES) { - return new CountingSemaphore(maxCount, initCount); - } - else if(argument == USE_TASK_NOTIFICATIONS) { - return new CountingSemaphoreUsingTask(maxCount, initCount); - } - else { - sif::warning << "SemaphoreFactory: Invalid argument, return regular" - "binary semaphore" << std::endl; - return new CountingSemaphore(maxCount, initCount); - } - -} - -void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { - delete semaphore; -} +#include "../../osal/FreeRTOS/BinarySemaphore.h" +#include "../../osal/FreeRTOS/BinSemaphUsingTask.h" +#include "../../osal/FreeRTOS/CountingSemaphore.h" +#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" +#include "../../tasks/SemaphoreFactory.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; + +static const uint32_t USE_REGULAR_SEMAPHORES = 0; +static const uint32_t USE_TASK_NOTIFICATIONS = 1; + +SemaphoreFactory::SemaphoreFactory() { +} + +SemaphoreFactory::~SemaphoreFactory() { + delete factoryInstance; +} + +SemaphoreFactory* SemaphoreFactory::instance() { + if (factoryInstance == nullptr){ + factoryInstance = new SemaphoreFactory(); + } + return SemaphoreFactory::factoryInstance; +} + +SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) { + if(argument == USE_REGULAR_SEMAPHORES) { + return new BinarySemaphore(); + } + else if(argument == USE_TASK_NOTIFICATIONS) { + return new BinarySemaphoreUsingTask(); + } + else { + sif::warning << "SemaphoreFactory: Invalid argument, return regular" + "binary semaphore" << std::endl; + return new BinarySemaphore(); + } +} + +SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount, + uint8_t initCount, uint32_t argument) { + if(argument == USE_REGULAR_SEMAPHORES) { + return new CountingSemaphore(maxCount, initCount); + } + else if(argument == USE_TASK_NOTIFICATIONS) { + return new CountingSemaphoreUsingTask(maxCount, initCount); + } + else { + sif::warning << "SemaphoreFactory: Invalid argument, return regular" + "binary semaphore" << std::endl; + return new CountingSemaphore(maxCount, initCount); + } + +} + +void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { + delete semaphore; +} diff --git a/osal/FreeRTOS/TaskManagement.cpp b/osal/FreeRTOS/TaskManagement.cpp index 16682d36..b77f12a9 100644 --- a/osal/FreeRTOS/TaskManagement.cpp +++ b/osal/FreeRTOS/TaskManagement.cpp @@ -1,24 +1,24 @@ -#include "../../osal/FreeRTOS/TaskManagement.h" - -void TaskManagement::vRequestContextSwitchFromTask() { - vTaskDelay(0); -} - -void TaskManagement::requestContextSwitch( - CallContext callContext = CallContext::TASK) { - if(callContext == CallContext::ISR) { - // This function depends on the partmacro.h definition for the specific device - vRequestContextSwitchFromISR(); - } else { - vRequestContextSwitchFromTask(); - } -} - -TaskHandle_t TaskManagement::getCurrentTaskHandle() { - return xTaskGetCurrentTaskHandle(); -} - -size_t TaskManagement::getTaskStackHighWatermark( - TaskHandle_t task) { - return uxTaskGetStackHighWaterMark(task) * sizeof(StackType_t); -} +#include "../../osal/FreeRTOS/TaskManagement.h" + +void TaskManagement::vRequestContextSwitchFromTask() { + vTaskDelay(0); +} + +void TaskManagement::requestContextSwitch( + CallContext callContext = CallContext::TASK) { + if(callContext == CallContext::ISR) { + // This function depends on the partmacro.h definition for the specific device + vRequestContextSwitchFromISR(); + } else { + vRequestContextSwitchFromTask(); + } +} + +TaskHandle_t TaskManagement::getCurrentTaskHandle() { + return xTaskGetCurrentTaskHandle(); +} + +size_t TaskManagement::getTaskStackHighWatermark( + TaskHandle_t task) { + return uxTaskGetStackHighWaterMark(task) * sizeof(StackType_t); +} diff --git a/osal/FreeRTOS/TaskManagement.h b/osal/FreeRTOS/TaskManagement.h index 43003d76..4b7fe3eb 100644 --- a/osal/FreeRTOS/TaskManagement.h +++ b/osal/FreeRTOS/TaskManagement.h @@ -1,64 +1,64 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ -#define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ - -#include "../../returnvalues/HasReturnvaluesIF.h" - -extern "C" { -#include -#include -} -#include - -/** - * Architecture dependant portmacro.h function call. - * Should be implemented in bsp. - */ -extern void vRequestContextSwitchFromISR(); - -/*! - * Used by functions to tell if they are being called from - * within an ISR or from a regular task. This is required because FreeRTOS - * has different functions for handling semaphores and messages from within - * an ISR and task. - */ -enum class CallContext { - TASK = 0x00,//!< task_context - ISR = 0xFF //!< isr_context -}; - - -class TaskManagement { -public: - /** - * @brief In this function, a function dependant on the portmacro.h header - * 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 - * to unblock and a context switch is required. - */ - static void requestContextSwitch(CallContext callContext); - - /** - * If task preemption in FreeRTOS is disabled, a context switch - * can be requested manually by calling this function. - */ - static void vRequestContextSwitchFromTask(void); - - /** - * @return The current task handle - */ - static TaskHandle_t getCurrentTaskHandle(); - - /** - * Get returns the minimum amount of remaining stack space in words - * that was a available to the task since the task started executing. - * Please note that the actual value in bytes depends - * on the stack depth type. - * 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 - * words. - */ - static size_t getTaskStackHighWatermark( - TaskHandle_t task = nullptr); -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ +#define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ + +#include "../../returnvalues/HasReturnvaluesIF.h" + +extern "C" { +#include +#include +} +#include + +/** + * Architecture dependant portmacro.h function call. + * Should be implemented in bsp. + */ +extern void vRequestContextSwitchFromISR(); + +/*! + * Used by functions to tell if they are being called from + * within an ISR or from a regular task. This is required because FreeRTOS + * has different functions for handling semaphores and messages from within + * an ISR and task. + */ +enum class CallContext { + TASK = 0x00,//!< task_context + ISR = 0xFF //!< isr_context +}; + + +class TaskManagement { +public: + /** + * @brief In this function, a function dependant on the portmacro.h header + * 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 + * to unblock and a context switch is required. + */ + static void requestContextSwitch(CallContext callContext); + + /** + * If task preemption in FreeRTOS is disabled, a context switch + * can be requested manually by calling this function. + */ + static void vRequestContextSwitchFromTask(void); + + /** + * @return The current task handle + */ + static TaskHandle_t getCurrentTaskHandle(); + + /** + * Get returns the minimum amount of remaining stack space in words + * that was a available to the task since the task started executing. + * Please note that the actual value in bytes depends + * on the stack depth type. + * 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 + * words. + */ + static size_t getTaskStackHighWatermark( + TaskHandle_t task = nullptr); +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ */ diff --git a/osal/linux/BinarySemaphore.cpp b/osal/linux/BinarySemaphore.cpp index 5216ff37..8c0eeae7 100644 --- a/osal/linux/BinarySemaphore.cpp +++ b/osal/linux/BinarySemaphore.cpp @@ -1,149 +1,149 @@ -#include "../../osal/linux/BinarySemaphore.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -extern "C" { -#include -#include -} - -BinarySemaphore::BinarySemaphore() { - // Using unnamed semaphores for now - initSemaphore(); -} - -BinarySemaphore::~BinarySemaphore() { - sem_destroy(&handle); -} - -BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { - initSemaphore(); -} - -BinarySemaphore& BinarySemaphore::operator =( - BinarySemaphore&& s) { - initSemaphore(); - return * this; -} - -ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType, - uint32_t timeoutMs) { - int result = 0; - if(timeoutType == TimeoutType::POLLING) { - result = sem_trywait(&handle); - } - else if(timeoutType == TimeoutType::BLOCKING) { - result = sem_wait(&handle); - } - else if(timeoutType == TimeoutType::WAITING){ - timespec timeOut; - clock_gettime(CLOCK_REALTIME, &timeOut); - uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec; - nseconds += timeoutMs * 1000000; - timeOut.tv_sec = nseconds / 1000000000; - timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000; - result = sem_timedwait(&handle, &timeOut); - if(result != 0 and errno == EINVAL) { - sif::debug << "BinarySemaphore::acquire: Invalid time value possible" - << std::endl; - } - } - if(result == 0) { - return HasReturnvaluesIF::RETURN_OK; - } - - switch(errno) { - case(EAGAIN): - // Operation could not be performed without blocking (for sem_trywait) - case(ETIMEDOUT): - // Semaphore is 0 - return SemaphoreIF::SEMAPHORE_TIMEOUT; - case(EINVAL): - // Semaphore invalid - return SemaphoreIF::SEMAPHORE_INVALID; - case(EINTR): - // Call was interrupted by signal handler - sif::debug << "BinarySemaphore::acquire: Signal handler interrupted." - "Code " << strerror(errno) << std::endl; - /* No break */ - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -ReturnValue_t BinarySemaphore::release() { - return BinarySemaphore::release(&this->handle); -} - -ReturnValue_t BinarySemaphore::release(sem_t *handle) { - ReturnValue_t countResult = checkCount(handle, 1); - if(countResult != HasReturnvaluesIF::RETURN_OK) { - return countResult; - } - - int result = sem_post(handle); - if(result == 0) { - return HasReturnvaluesIF::RETURN_OK; - } - - switch(errno) { - case(EINVAL): - // Semaphore invalid - return SemaphoreIF::SEMAPHORE_INVALID; - case(EOVERFLOW): - // SEM_MAX_VALUE overflow. This should never happen - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -uint8_t BinarySemaphore::getSemaphoreCounter() const { - // And another ugly cast :-D - return getSemaphoreCounter(const_cast(&this->handle)); -} - -uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) { - int value = 0; - int result = sem_getvalue(handle, &value); - if (result == 0) { - return value; - } - else if(result != 0 and errno == EINVAL) { - // Could be called from interrupt, use lightweight printf - printf("BinarySemaphore::getSemaphoreCounter: Invalid semaphore\n"); - return 0; - } - else { - // This should never happen. - return 0; - } -} - -void BinarySemaphore::initSemaphore(uint8_t initCount) { - auto result = sem_init(&handle, true, initCount); - if(result == -1) { - switch(errno) { - case(EINVAL): - // Value exceeds SEM_VALUE_MAX - case(ENOSYS): - // System does not support process-shared semaphores - sif::error << "BinarySemaphore: Init failed with" << strerror(errno) - << std::endl; - } - } -} - -ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) { - int value = getSemaphoreCounter(handle); - if(value >= maxCount) { - if(maxCount == 1 and value > 1) { - // Binary Semaphore special case. - // This is a config error use lightweight printf is this is called - // from an interrupt - printf("BinarySemaphore::release: Value of binary semaphore greater" - " than 1!\n"); - return HasReturnvaluesIF::RETURN_FAILED; - } - return SemaphoreIF::SEMAPHORE_NOT_OWNED; - } - return HasReturnvaluesIF::RETURN_OK; -} +#include "../../osal/linux/BinarySemaphore.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +extern "C" { +#include +#include +} + +BinarySemaphore::BinarySemaphore() { + // Using unnamed semaphores for now + initSemaphore(); +} + +BinarySemaphore::~BinarySemaphore() { + sem_destroy(&handle); +} + +BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { + initSemaphore(); +} + +BinarySemaphore& BinarySemaphore::operator =( + BinarySemaphore&& s) { + initSemaphore(); + return * this; +} + +ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType, + uint32_t timeoutMs) { + int result = 0; + if(timeoutType == TimeoutType::POLLING) { + result = sem_trywait(&handle); + } + else if(timeoutType == TimeoutType::BLOCKING) { + result = sem_wait(&handle); + } + else if(timeoutType == TimeoutType::WAITING){ + timespec timeOut; + clock_gettime(CLOCK_REALTIME, &timeOut); + uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec; + nseconds += timeoutMs * 1000000; + timeOut.tv_sec = nseconds / 1000000000; + timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000; + result = sem_timedwait(&handle, &timeOut); + if(result != 0 and errno == EINVAL) { + sif::debug << "BinarySemaphore::acquire: Invalid time value possible" + << std::endl; + } + } + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + switch(errno) { + case(EAGAIN): + // Operation could not be performed without blocking (for sem_trywait) + case(ETIMEDOUT): + // Semaphore is 0 + return SemaphoreIF::SEMAPHORE_TIMEOUT; + case(EINVAL): + // Semaphore invalid + return SemaphoreIF::SEMAPHORE_INVALID; + case(EINTR): + // Call was interrupted by signal handler + sif::debug << "BinarySemaphore::acquire: Signal handler interrupted." + "Code " << strerror(errno) << std::endl; + /* No break */ + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t BinarySemaphore::release() { + return BinarySemaphore::release(&this->handle); +} + +ReturnValue_t BinarySemaphore::release(sem_t *handle) { + ReturnValue_t countResult = checkCount(handle, 1); + if(countResult != HasReturnvaluesIF::RETURN_OK) { + return countResult; + } + + int result = sem_post(handle); + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + switch(errno) { + case(EINVAL): + // Semaphore invalid + return SemaphoreIF::SEMAPHORE_INVALID; + case(EOVERFLOW): + // SEM_MAX_VALUE overflow. This should never happen + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +uint8_t BinarySemaphore::getSemaphoreCounter() const { + // And another ugly cast :-D + return getSemaphoreCounter(const_cast(&this->handle)); +} + +uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) { + int value = 0; + int result = sem_getvalue(handle, &value); + if (result == 0) { + return value; + } + else if(result != 0 and errno == EINVAL) { + // Could be called from interrupt, use lightweight printf + printf("BinarySemaphore::getSemaphoreCounter: Invalid semaphore\n"); + return 0; + } + else { + // This should never happen. + return 0; + } +} + +void BinarySemaphore::initSemaphore(uint8_t initCount) { + auto result = sem_init(&handle, true, initCount); + if(result == -1) { + switch(errno) { + case(EINVAL): + // Value exceeds SEM_VALUE_MAX + case(ENOSYS): + // System does not support process-shared semaphores + sif::error << "BinarySemaphore: Init failed with" << strerror(errno) + << std::endl; + } + } +} + +ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) { + int value = getSemaphoreCounter(handle); + if(value >= maxCount) { + if(maxCount == 1 and value > 1) { + // Binary Semaphore special case. + // This is a config error use lightweight printf is this is called + // from an interrupt + printf("BinarySemaphore::release: Value of binary semaphore greater" + " than 1!\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/osal/linux/BinarySemaphore.h b/osal/linux/BinarySemaphore.h index 4181de85..e9bb8bb6 100644 --- a/osal/linux/BinarySemaphore.h +++ b/osal/linux/BinarySemaphore.h @@ -1,81 +1,81 @@ -#ifndef FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ -#define FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ - -#include "../../returnvalues/HasReturnvaluesIF.h" -#include "../../tasks/SemaphoreIF.h" - -extern "C" { -#include -} - -/** - * @brief OS Tool to achieve synchronization of between tasks or between - * task and ISR. The default semaphore implementation creates a - * binary semaphore, which can only be taken once. - * @details - * See: http://www.man7.org/linux/man-pages/man7/sem_overview.7.html - * @author R. Mueller - * @ingroup osal - */ -class BinarySemaphore: public SemaphoreIF, - public HasReturnvaluesIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; - - //! @brief Default ctor - BinarySemaphore(); - //! @brief Copy ctor, deleted explicitely. - BinarySemaphore(const BinarySemaphore&) = delete; - //! @brief Copy assignment, deleted explicitely. - BinarySemaphore& operator=(const BinarySemaphore&) = delete; - //! @brief Move ctor - BinarySemaphore (BinarySemaphore &&); - //! @brief Move assignment - BinarySemaphore & operator=(BinarySemaphore &&); - //! @brief Destructor - virtual ~BinarySemaphore(); - - void initSemaphore(uint8_t initCount = 1); - - uint8_t getSemaphoreCounter() const override; - static uint8_t getSemaphoreCounter(sem_t* handle); - - /** - * Take the binary semaphore. - * 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 example by an ISR or another task. - * @param timeoutMs - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout - */ - ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, - uint32_t timeoutMs = 0) override; - - /** - * Release the binary semaphore. - * @return -@c RETURN_OK on success - * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is - * already available. - */ - virtual ReturnValue_t release() override; - /** - * This static function can be used to release a semaphore by providing - * its handle. - * @param handle - * @return - */ - static ReturnValue_t release(sem_t* handle); - - /** Checks the validity of the semaphore count against a specified - * known maxCount - * @param handle - * @param maxCount - * @return - */ - static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount); -protected: - sem_t handle; -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ +#ifndef FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ +#define FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ + +#include "../../returnvalues/HasReturnvaluesIF.h" +#include "../../tasks/SemaphoreIF.h" + +extern "C" { +#include +} + +/** + * @brief OS Tool to achieve synchronization of between tasks or between + * task and ISR. The default semaphore implementation creates a + * binary semaphore, which can only be taken once. + * @details + * See: http://www.man7.org/linux/man-pages/man7/sem_overview.7.html + * @author R. Mueller + * @ingroup osal + */ +class BinarySemaphore: public SemaphoreIF, + public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + + //! @brief Default ctor + BinarySemaphore(); + //! @brief Copy ctor, deleted explicitely. + BinarySemaphore(const BinarySemaphore&) = delete; + //! @brief Copy assignment, deleted explicitely. + BinarySemaphore& operator=(const BinarySemaphore&) = delete; + //! @brief Move ctor + BinarySemaphore (BinarySemaphore &&); + //! @brief Move assignment + BinarySemaphore & operator=(BinarySemaphore &&); + //! @brief Destructor + virtual ~BinarySemaphore(); + + void initSemaphore(uint8_t initCount = 1); + + uint8_t getSemaphoreCounter() const override; + static uint8_t getSemaphoreCounter(sem_t* handle); + + /** + * Take the binary semaphore. + * 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 example by an ISR or another task. + * @param timeoutMs + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout + */ + ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, + uint32_t timeoutMs = 0) override; + + /** + * Release the binary semaphore. + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is + * already available. + */ + virtual ReturnValue_t release() override; + /** + * This static function can be used to release a semaphore by providing + * its handle. + * @param handle + * @return + */ + static ReturnValue_t release(sem_t* handle); + + /** Checks the validity of the semaphore count against a specified + * known maxCount + * @param handle + * @param maxCount + * @return + */ + static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount); +protected: + sem_t handle; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ diff --git a/osal/linux/Clock.cpp b/osal/linux/Clock.cpp index b14f2a97..4de18f83 100644 --- a/osal/linux/Clock.cpp +++ b/osal/linux/Clock.cpp @@ -6,8 +6,8 @@ #include #include #include +#include -//#include uint16_t Clock::leapSeconds = 0; MutexIF* Clock::timeMutex = NULL; diff --git a/osal/linux/CountingSemaphore.cpp b/osal/linux/CountingSemaphore.cpp index ef32539b..18339399 100644 --- a/osal/linux/CountingSemaphore.cpp +++ b/osal/linux/CountingSemaphore.cpp @@ -1,54 +1,54 @@ -#include "../../osal/linux/CountingSemaphore.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): - maxCount(maxCount), initCount(initCount) { - if(initCount > maxCount) { - sif::error << "CountingSemaphoreUsingTask: Max count bigger than " - "intial cout. Setting initial count to max count." << std::endl; - initCount = maxCount; - } - - initSemaphore(initCount); -} - -CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): - maxCount(other.maxCount), initCount(other.initCount) { - initSemaphore(initCount); -} - -CountingSemaphore& CountingSemaphore::operator =( - CountingSemaphore&& other) { - initSemaphore(other.initCount); - return * this; -} - -ReturnValue_t CountingSemaphore::release() { - ReturnValue_t result = checkCount(&handle, maxCount); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return CountingSemaphore::release(&this->handle); -} - -ReturnValue_t CountingSemaphore::release(sem_t* handle) { - int result = sem_post(handle); - if(result == 0) { - return HasReturnvaluesIF::RETURN_OK; - } - - switch(errno) { - case(EINVAL): - // Semaphore invalid - return SemaphoreIF::SEMAPHORE_INVALID; - case(EOVERFLOW): - // SEM_MAX_VALUE overflow. This should never happen - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -uint8_t CountingSemaphore::getMaxCount() const { - return maxCount; -} - +#include "../../osal/linux/CountingSemaphore.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + +CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): + maxCount(maxCount), initCount(initCount) { + if(initCount > maxCount) { + sif::error << "CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count." << std::endl; + initCount = maxCount; + } + + initSemaphore(initCount); +} + +CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): + maxCount(other.maxCount), initCount(other.initCount) { + initSemaphore(initCount); +} + +CountingSemaphore& CountingSemaphore::operator =( + CountingSemaphore&& other) { + initSemaphore(other.initCount); + return * this; +} + +ReturnValue_t CountingSemaphore::release() { + ReturnValue_t result = checkCount(&handle, maxCount); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return CountingSemaphore::release(&this->handle); +} + +ReturnValue_t CountingSemaphore::release(sem_t* handle) { + int result = sem_post(handle); + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + switch(errno) { + case(EINVAL): + // Semaphore invalid + return SemaphoreIF::SEMAPHORE_INVALID; + case(EOVERFLOW): + // SEM_MAX_VALUE overflow. This should never happen + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +uint8_t CountingSemaphore::getMaxCount() const { + return maxCount; +} + diff --git a/osal/linux/CountingSemaphore.h b/osal/linux/CountingSemaphore.h index afe21a61..e0fbb992 100644 --- a/osal/linux/CountingSemaphore.h +++ b/osal/linux/CountingSemaphore.h @@ -1,37 +1,37 @@ -#ifndef FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ -#define FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ -#include "../../osal/linux/BinarySemaphore.h" - -/** - * @brief Counting semaphores, which can be acquired more than once. - * @details - * See: https://www.freertos.org/CreateCounting.html - * API of counting semaphores is almost identical to binary semaphores, - * so we just inherit from binary semaphore and provide the respective - * constructors. - */ -class CountingSemaphore: public BinarySemaphore { -public: - CountingSemaphore(const uint8_t maxCount, uint8_t initCount); - //! @brief Copy ctor, disabled - CountingSemaphore(const CountingSemaphore&) = delete; - //! @brief Copy assignment, disabled - CountingSemaphore& operator=(const CountingSemaphore&) = delete; - //! @brief Move ctor - CountingSemaphore (CountingSemaphore &&); - //! @brief Move assignment - CountingSemaphore & operator=(CountingSemaphore &&); - - ReturnValue_t release() override; - static ReturnValue_t release(sem_t* sem); - /* Same API as binary semaphore otherwise. acquire() can be called - * until there are not semaphores left and release() can be called - * until maxCount is reached. */ - - uint8_t getMaxCount() const; -private: - const uint8_t maxCount; - uint8_t initCount = 0; -}; - -#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ +#ifndef FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ +#define FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ +#include "../../osal/linux/BinarySemaphore.h" + +/** + * @brief Counting semaphores, which can be acquired more than once. + * @details + * See: https://www.freertos.org/CreateCounting.html + * API of counting semaphores is almost identical to binary semaphores, + * so we just inherit from binary semaphore and provide the respective + * constructors. + */ +class CountingSemaphore: public BinarySemaphore { +public: + CountingSemaphore(const uint8_t maxCount, uint8_t initCount); + //! @brief Copy ctor, disabled + CountingSemaphore(const CountingSemaphore&) = delete; + //! @brief Copy assignment, disabled + CountingSemaphore& operator=(const CountingSemaphore&) = delete; + //! @brief Move ctor + CountingSemaphore (CountingSemaphore &&); + //! @brief Move assignment + CountingSemaphore & operator=(CountingSemaphore &&); + + ReturnValue_t release() override; + static ReturnValue_t release(sem_t* sem); + /* Same API as binary semaphore otherwise. acquire() can be called + * until there are not semaphores left and release() can be called + * until maxCount is reached. */ + + uint8_t getMaxCount() const; +private: + const uint8_t maxCount; + uint8_t initCount = 0; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ diff --git a/osal/linux/FixedTimeslotTask.cpp b/osal/linux/FixedTimeslotTask.cpp index 858a39a7..247a34ed 100644 --- a/osal/linux/FixedTimeslotTask.cpp +++ b/osal/linux/FixedTimeslotTask.cpp @@ -1,5 +1,5 @@ -#include "../../serviceinterface/ServiceInterfaceStream.h" #include "FixedTimeslotTask.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" #include @@ -39,13 +39,16 @@ uint32_t FixedTimeslotTask::getPeriodMs() const { ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep) { - if (objectManager->get(componentId) != nullptr) { - pst.addSlot(componentId, slotTimeMs, executionStep, this); + ExecutableObjectIF* executableObject = + objectManager->get(componentId); + if (executableObject != nullptr) { + pst.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; + " not found, not adding it to pst" << std::dec << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } @@ -58,6 +61,9 @@ void FixedTimeslotTask::taskFunctionality() { if (!started) { suspend(); } + + pst.intializeSequenceAfterTaskCreation(); + //The start time for the first entry is read. uint64_t lastWakeTime = getCurrentMonotonicTimeMs(); uint64_t interval = pst.getIntervalToNextSlotMs(); diff --git a/osal/linux/FixedTimeslotTask.h b/osal/linux/FixedTimeslotTask.h index 42802b1d..5c5c1814 100644 --- a/osal/linux/FixedTimeslotTask.h +++ b/osal/linux/FixedTimeslotTask.h @@ -1,9 +1,9 @@ -#ifndef FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ -#define FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ +#ifndef FSFW_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ +#define FSFW_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ -#include "../../tasks/FixedTimeslotTaskIF.h" -#include "../../devicehandlers/FixedSlotSequence.h" #include "PosixThread.h" +#include "../../tasks/FixedTimeslotTaskIF.h" +#include "../../tasks/FixedSlotSequence.h" #include class FixedTimeslotTask: public FixedTimeslotTaskIF, public PosixThread { @@ -74,4 +74,4 @@ private: bool started; }; -#endif /* FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */ +#endif /* FSFW_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */ diff --git a/osal/linux/QueueFactory.cpp b/osal/linux/QueueFactory.cpp index afeca547..0860950c 100644 --- a/osal/linux/QueueFactory.cpp +++ b/osal/linux/QueueFactory.cpp @@ -1,8 +1,14 @@ #include "../../ipc/QueueFactory.h" +#include "MessageQueue.h" + +#include "../../ipc/messageQueueDefinitions.h" +#include "../../ipc/MessageQueueSenderIF.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" + #include #include -#include "MessageQueue.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" + + #include QueueFactory* QueueFactory::factoryInstance = nullptr; diff --git a/osal/linux/SemaphoreFactory.cpp b/osal/linux/SemaphoreFactory.cpp index bcb5d16f..e4710933 100644 --- a/osal/linux/SemaphoreFactory.cpp +++ b/osal/linux/SemaphoreFactory.cpp @@ -1,33 +1,33 @@ -#include "../../tasks/SemaphoreFactory.h" -#include "BinarySemaphore.h" -#include "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) { - return new BinarySemaphore(); -} - -SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount, - uint8_t initCount, uint32_t arguments) { - return new CountingSemaphore(maxCount, initCount); -} - -void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { - delete semaphore; -} +#include "../../tasks/SemaphoreFactory.h" +#include "BinarySemaphore.h" +#include "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) { + return new BinarySemaphore(); +} + +SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount, + uint8_t initCount, uint32_t arguments) { + return new CountingSemaphore(maxCount, initCount); +} + +void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { + delete semaphore; +} diff --git a/returnvalues/FwClassIds.h b/returnvalues/FwClassIds.h index e547025b..53add6a0 100644 --- a/returnvalues/FwClassIds.h +++ b/returnvalues/FwClassIds.h @@ -56,7 +56,6 @@ enum { DEVICE_COMMUNICATION_IF, //DC BSP, //BSP TIME_STAMPER_IF, //TSI 53 - //TODO This will shift all IDs for FLP SGP4PROPAGATOR_CLASS, //SGP4 54 MUTEX_IF, //MUX 55 MESSAGE_QUEUE_IF,//MQI 56 diff --git a/serialize/SerialBufferAdapter.cpp b/serialize/SerialBufferAdapter.cpp index 812cd34b..1c11afd4 100644 --- a/serialize/SerialBufferAdapter.cpp +++ b/serialize/SerialBufferAdapter.cpp @@ -1,129 +1,129 @@ -#include "../serialize/SerialBufferAdapter.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include - -template -SerialBufferAdapter::SerialBufferAdapter(const uint8_t* buffer, - count_t bufferLength, bool serializeLength) : - serializeLength(serializeLength), - constBuffer(buffer), buffer(nullptr), - bufferLength(bufferLength) {} - -template -SerialBufferAdapter::SerialBufferAdapter(uint8_t* buffer, - count_t bufferLength, bool serializeLength) : - serializeLength(serializeLength), constBuffer(buffer), buffer(buffer), - bufferLength(bufferLength) {} - - -template -SerialBufferAdapter::~SerialBufferAdapter() { -} - -template -ReturnValue_t SerialBufferAdapter::serialize(uint8_t** buffer, - size_t* size, size_t maxSize, Endianness streamEndianness) const { - if (serializeLength) { - ReturnValue_t result = SerializeAdapter::serialize(&bufferLength, - buffer, size, maxSize, streamEndianness); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - - if (*size + bufferLength > maxSize) { - return BUFFER_TOO_SHORT; - } - - if (this->constBuffer != nullptr) { - std::memcpy(*buffer, this->constBuffer, bufferLength); - } - else if (this->buffer != nullptr) { - // This will propably be never reached, constBuffer should always be - // set if non-const buffer is set. - std::memcpy(*buffer, this->buffer, bufferLength); - } - else { - return HasReturnvaluesIF::RETURN_FAILED; - } - *size += bufferLength; - (*buffer) += bufferLength; - return HasReturnvaluesIF::RETURN_OK; - -} - -template -size_t SerialBufferAdapter::getSerializedSize() const { - if (serializeLength) { - return bufferLength + SerializeAdapter::getSerializedSize(&bufferLength); - } else { - return bufferLength; - } -} - -template -ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer, - size_t* size, Endianness streamEndianness) { - if (this->buffer == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - - if(serializeLength){ - count_t lengthField = 0; - ReturnValue_t result = SerializeAdapter::deSerialize(&lengthField, - buffer, size, streamEndianness); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - if(lengthField > bufferLength) { - return TOO_MANY_ELEMENTS; - } - bufferLength = lengthField; - } - - if (bufferLength <= *size) { - *size -= bufferLength; - std::memcpy(this->buffer, *buffer, bufferLength); - (*buffer) += bufferLength; - return HasReturnvaluesIF::RETURN_OK; - } - else { - return STREAM_TOO_SHORT; - } -} - -template -uint8_t * SerialBufferAdapter::getBuffer() { - if(buffer == nullptr) { - sif::error << "Wrong access function for stored type !" - " Use getConstBuffer()." << std::endl; - return nullptr; - } - return buffer; -} - -template -const uint8_t * SerialBufferAdapter::getConstBuffer() { - if(constBuffer == nullptr) { - sif::error << "SerialBufferAdapter::getConstBuffer:" - " Buffers are unitialized!" << std::endl; - return nullptr; - } - return constBuffer; -} - -template -void SerialBufferAdapter::setBuffer(uint8_t* buffer, - count_t bufferLength) { - this->buffer = buffer; - this->constBuffer = buffer; - this->bufferLength = bufferLength; -} - - -//forward Template declaration for linker -template class SerialBufferAdapter; -template class SerialBufferAdapter; -template class SerialBufferAdapter; -template class SerialBufferAdapter; - +#include "../serialize/SerialBufferAdapter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include + +template +SerialBufferAdapter::SerialBufferAdapter(const uint8_t* buffer, + count_t bufferLength, bool serializeLength) : + serializeLength(serializeLength), + constBuffer(buffer), buffer(nullptr), + bufferLength(bufferLength) {} + +template +SerialBufferAdapter::SerialBufferAdapter(uint8_t* buffer, + count_t bufferLength, bool serializeLength) : + serializeLength(serializeLength), constBuffer(buffer), buffer(buffer), + bufferLength(bufferLength) {} + + +template +SerialBufferAdapter::~SerialBufferAdapter() { +} + +template +ReturnValue_t SerialBufferAdapter::serialize(uint8_t** buffer, + size_t* size, size_t maxSize, Endianness streamEndianness) const { + if (serializeLength) { + ReturnValue_t result = SerializeAdapter::serialize(&bufferLength, + buffer, size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + + if (*size + bufferLength > maxSize) { + return BUFFER_TOO_SHORT; + } + + if (this->constBuffer != nullptr) { + std::memcpy(*buffer, this->constBuffer, bufferLength); + } + else if (this->buffer != nullptr) { + // This will propably be never reached, constBuffer should always be + // set if non-const buffer is set. + std::memcpy(*buffer, this->buffer, bufferLength); + } + else { + return HasReturnvaluesIF::RETURN_FAILED; + } + *size += bufferLength; + (*buffer) += bufferLength; + return HasReturnvaluesIF::RETURN_OK; + +} + +template +size_t SerialBufferAdapter::getSerializedSize() const { + if (serializeLength) { + return bufferLength + SerializeAdapter::getSerializedSize(&bufferLength); + } else { + return bufferLength; + } +} + +template +ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer, + size_t* size, Endianness streamEndianness) { + if (this->buffer == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + if(serializeLength){ + count_t lengthField = 0; + ReturnValue_t result = SerializeAdapter::deSerialize(&lengthField, + buffer, size, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(lengthField > bufferLength) { + return TOO_MANY_ELEMENTS; + } + bufferLength = lengthField; + } + + if (bufferLength <= *size) { + *size -= bufferLength; + std::memcpy(this->buffer, *buffer, bufferLength); + (*buffer) += bufferLength; + return HasReturnvaluesIF::RETURN_OK; + } + else { + return STREAM_TOO_SHORT; + } +} + +template +uint8_t * SerialBufferAdapter::getBuffer() { + if(buffer == nullptr) { + sif::error << "Wrong access function for stored type !" + " Use getConstBuffer()." << std::endl; + return nullptr; + } + return buffer; +} + +template +const uint8_t * SerialBufferAdapter::getConstBuffer() { + if(constBuffer == nullptr) { + sif::error << "SerialBufferAdapter::getConstBuffer:" + " Buffers are unitialized!" << std::endl; + return nullptr; + } + return constBuffer; +} + +template +void SerialBufferAdapter::setBuffer(uint8_t* buffer, + count_t bufferLength) { + this->buffer = buffer; + this->constBuffer = buffer; + this->bufferLength = bufferLength; +} + + +//forward Template declaration for linker +template class SerialBufferAdapter; +template class SerialBufferAdapter; +template class SerialBufferAdapter; +template class SerialBufferAdapter; + diff --git a/serialize/SerialBufferAdapter.h b/serialize/SerialBufferAdapter.h index c3dfcd8f..9a89e18b 100644 --- a/serialize/SerialBufferAdapter.h +++ b/serialize/SerialBufferAdapter.h @@ -1,78 +1,78 @@ -#ifndef SERIALBUFFERADAPTER_H_ -#define SERIALBUFFERADAPTER_H_ - -#include "../serialize/SerializeIF.h" -#include "../serialize/SerializeAdapter.h" - -/** - * This adapter provides an interface for SerializeIF to serialize or deserialize - * buffers with no length header but a known size. - * - * Additionally, the buffer length can be serialized too and will be put in - * front of the serialized buffer. - * - * Can be used with SerialLinkedListAdapter by declaring a SerializeElement with - * SerialElement>. - * Right now, the SerialBufferAdapter must always - * be initialized with the buffer and size ! - * - * \ingroup serialize - */ -template -class SerialBufferAdapter: public SerializeIF { -public: - - /** - * Constructor for constant uint8_t buffer. Length field can be serialized optionally. - * Type of length can be supplied as template type. - * @param buffer - * @param bufferLength - * @param serializeLength - */ - SerialBufferAdapter(const uint8_t* buffer, count_t bufferLength, - bool serializeLength = false); - - /** - * Constructor for non-constant uint8_t buffer. - * Length field can be serialized optionally. - * Type of length can be supplied as template type. - * @param buffer - * @param bufferLength - * @param serializeLength Length field will be serialized with size count_t - */ - SerialBufferAdapter(uint8_t* buffer, count_t bufferLength, - bool serializeLength = false); - - virtual ~SerialBufferAdapter(); - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const override; - - virtual size_t getSerializedSize() const override; - - /** - * @brief This function deserializes a buffer into the member buffer. - * @details - * 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, - * consider using SerialFixedArrayListAdapter instead. - * @param buffer [out] Resulting buffer - * @param size remaining size to deserialize, should be larger than buffer - * + size field size - * @param bigEndian - * @return - */ - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) override; - - uint8_t * getBuffer(); - const uint8_t * getConstBuffer(); - void setBuffer(uint8_t* buffer, count_t bufferLength); -private: - bool serializeLength = false; - const uint8_t *constBuffer = nullptr; - uint8_t *buffer = nullptr; - count_t bufferLength = 0; -}; - -#endif /* SERIALBUFFERADAPTER_H_ */ +#ifndef SERIALBUFFERADAPTER_H_ +#define SERIALBUFFERADAPTER_H_ + +#include "../serialize/SerializeIF.h" +#include "../serialize/SerializeAdapter.h" + +/** + * This adapter provides an interface for SerializeIF to serialize or deserialize + * buffers with no length header but a known size. + * + * Additionally, the buffer length can be serialized too and will be put in + * front of the serialized buffer. + * + * Can be used with SerialLinkedListAdapter by declaring a SerializeElement with + * SerialElement>. + * Right now, the SerialBufferAdapter must always + * be initialized with the buffer and size ! + * + * \ingroup serialize + */ +template +class SerialBufferAdapter: public SerializeIF { +public: + + /** + * Constructor for constant uint8_t buffer. Length field can be serialized optionally. + * Type of length can be supplied as template type. + * @param buffer + * @param bufferLength + * @param serializeLength + */ + SerialBufferAdapter(const uint8_t* buffer, count_t bufferLength, + bool serializeLength = false); + + /** + * Constructor for non-constant uint8_t buffer. + * Length field can be serialized optionally. + * Type of length can be supplied as template type. + * @param buffer + * @param bufferLength + * @param serializeLength Length field will be serialized with size count_t + */ + SerialBufferAdapter(uint8_t* buffer, count_t bufferLength, + bool serializeLength = false); + + virtual ~SerialBufferAdapter(); + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const override; + + virtual size_t getSerializedSize() const override; + + /** + * @brief This function deserializes a buffer into the member buffer. + * @details + * 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, + * consider using SerialFixedArrayListAdapter instead. + * @param buffer [out] Resulting buffer + * @param size remaining size to deserialize, should be larger than buffer + * + size field size + * @param bigEndian + * @return + */ + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override; + + uint8_t * getBuffer(); + const uint8_t * getConstBuffer(); + void setBuffer(uint8_t* buffer, count_t bufferLength); +private: + bool serializeLength = false; + const uint8_t *constBuffer = nullptr; + uint8_t *buffer = nullptr; + count_t bufferLength = 0; +}; + +#endif /* SERIALBUFFERADAPTER_H_ */ diff --git a/storagemanager/ConstStorageAccessor.cpp b/storagemanager/ConstStorageAccessor.cpp new file mode 100644 index 00000000..842f1ce8 --- /dev/null +++ b/storagemanager/ConstStorageAccessor.cpp @@ -0,0 +1,88 @@ +#include "ConstStorageAccessor.h" +#include "StorageManagerIF.h" + +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../globalfunctions/arrayprinter.h" + +ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId): + storeId(storeId) {} + +ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId, + StorageManagerIF* store): + storeId(storeId), store(store) { + internalState = AccessState::ASSIGNED; +} + +ConstStorageAccessor::~ConstStorageAccessor() { + if(deleteData and store != nullptr) { + store->deleteData(storeId); + } +} + +ConstStorageAccessor::ConstStorageAccessor(ConstStorageAccessor&& other): + constDataPointer(other.constDataPointer), storeId(other.storeId), + size_(other.size_), store(other.store), deleteData(other.deleteData), + internalState(other.internalState) { + // This prevent premature deletion + other.store = nullptr; +} + +ConstStorageAccessor& ConstStorageAccessor::operator=( + ConstStorageAccessor&& other) { + constDataPointer = other.constDataPointer; + storeId = other.storeId; + store = other.store; + size_ = other.size_; + deleteData = other.deleteData; + this->store = other.store; + // This prevents premature deletion + other.store = nullptr; + return *this; +} + +const uint8_t* ConstStorageAccessor::data() const { + return constDataPointer; +} + +size_t ConstStorageAccessor::size() const { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + } + return size_; +} + +ReturnValue_t ConstStorageAccessor::getDataCopy(uint8_t *pointer, + size_t maxSize) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(size_ > maxSize) { + sif::error << "StorageAccessor: Supplied buffer not large enough" + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::copy(constDataPointer, constDataPointer + size_, pointer); + return HasReturnvaluesIF::RETURN_OK; +} + +void ConstStorageAccessor::release() { + deleteData = false; +} + +store_address_t ConstStorageAccessor::getId() const { + return storeId; +} + +void ConstStorageAccessor::print() const { + if(internalState == AccessState::UNINIT or constDataPointer == nullptr) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return; + } + arrayprinter::print(constDataPointer, size_); +} + +void ConstStorageAccessor::assignStore(StorageManagerIF* store) { + internalState = AccessState::ASSIGNED; + this->store = store; +} diff --git a/storagemanager/ConstStorageAccessor.h b/storagemanager/ConstStorageAccessor.h new file mode 100644 index 00000000..96d2dca2 --- /dev/null +++ b/storagemanager/ConstStorageAccessor.h @@ -0,0 +1,116 @@ +#ifndef FSFW_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ +#define FSFW_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ + +#include "storeAddress.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include + +class StorageManagerIF; + +/** + * @brief Helper classes to facilitate safe access to storages which is also + * conforming to RAII principles + * @details + * Accessor class which can be returned by pool manager or passed and set by + * pool managers to have safe access to the pool resources. + * + * These helper can be used together with the StorageManager classes to manage + * access to a storage. It can take care of thread-safety while also providing + * mechanisms to automatically clear storage data. + */ +class ConstStorageAccessor { + //! StorageManager classes have exclusive access to private variables. + template + friend class PoolManager; + template + friend class LocalPool; +public: + /** + * @brief Simple constructor which takes the store ID of the storage + * entry to access. + * @param storeId + */ + ConstStorageAccessor(store_address_t storeId); + ConstStorageAccessor(store_address_t storeId, StorageManagerIF* store); + + /** + * @brief The destructor in default configuration takes care of + * deleting the accessed pool entry and unlocking the mutex + */ + virtual ~ConstStorageAccessor(); + + /** + * @brief Returns a pointer to the read-only data + * @return + */ + const uint8_t* data() const; + + /** + * @brief Copies the read-only data to the supplied pointer + * @param pointer + */ + virtual ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize); + + /** + * @brief Calling this will prevent the Accessor from deleting the data + * when the destructor is called. + */ + void release(); + + /** + * Get the size of the data + * @return + */ + size_t size() const; + + /** + * Get the storage ID. + * @return + */ + store_address_t getId() const; + + void print() const; + + /** + * @brief Move ctor and move assignment allow returning accessors as + * a returnvalue. They prevent resource being free prematurely. + * Refer to: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ + * move-constructors-and-move-assignment-operators-cpp.md + * @param + * @return + */ + ConstStorageAccessor& operator= (ConstStorageAccessor&&); + ConstStorageAccessor(ConstStorageAccessor&&); + + //! The copy ctor and copy assignemnt should be deleted implicitely + //! according to https://foonathan.net/2019/02/special-member-functions/ + //! but I still deleted them to make it more explicit. (remember rule of 5). + ConstStorageAccessor& operator=(const ConstStorageAccessor&) = delete; + ConstStorageAccessor(const ConstStorageAccessor&) = delete; +protected: + const uint8_t* constDataPointer = nullptr; + store_address_t storeId; + size_t size_ = 0; + //! Managing pool, has to assign itself. + StorageManagerIF* store = nullptr; + bool deleteData = true; + + enum class AccessState { + UNINIT, + ASSIGNED + }; + //! Internal state for safety reasons. + AccessState internalState = AccessState::UNINIT; + /** + * Used by the pool manager instances to assign themselves to the + * accessor. This is necessary to delete the data when the acessor + * exits the scope ! The internal state will be considered read + * when this function is called, so take care all data is set properly as + * well. + * @param + */ + void assignStore(StorageManagerIF*); +}; + + +#endif /* FSFW_STORAGEMANAGER_CONSTSTORAGEACCESSOR_H_ */ diff --git a/storagemanager/LocalPool.h b/storagemanager/LocalPool.h index ad3deee1..3a94c03d 100644 --- a/storagemanager/LocalPool.h +++ b/storagemanager/LocalPool.h @@ -1,18 +1,14 @@ -/** - * @file LocalPool - * @date 02.02.2012 - * @author Bastian Baetz - * @brief This file contains the definition of the LocalPool class. - */ -#ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ -#define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ +#ifndef FSFW_STORAGEMANAGER_LOCALPOOL_H_ +#define FSFW_STORAGEMANAGER_LOCALPOOL_H_ -#include "../objectmanager/SystemObject.h" -#include "../serviceinterface/ServiceInterfaceStream.h" #include "StorageManagerIF.h" +#include "../objectmanager/SystemObject.h" #include "../objectmanager/ObjectManagerIF.h" +#include "../serviceinterface/ServiceInterfaceStream.h" #include "../internalError/InternalErrorReporterIF.h" -#include +#include "../storagemanager/StorageAccessor.h" +#include + /** * @brief The LocalPool class provides an intermediate data storage with @@ -27,6 +23,7 @@ * 0xFFFF-1 bytes. * It is possible to store empty packets in the pool. * The local pool is NOT thread-safe. + * @author Bastian Baetz */ template class LocalPool: public SystemObject, public StorageManagerIF { @@ -39,7 +36,7 @@ public: /** * @brief This is the default constructor for a pool manager instance. * @details By passing two arrays of size NUMBER_OF_POOLS, the constructor - * allocates memory (with \c new) for store and size_list. These + * allocates memory (with @c new) for store and size_list. These * regions are all set to zero on start up. * @param setObjectId The object identifier to be set. This allows for * multiple instances of LocalPool in the system. @@ -73,10 +70,17 @@ public: size_t size, bool ignoreFault = false) override; ReturnValue_t getFreeElement(store_address_t* storageId,const size_t size, uint8_t** p_data, bool ignoreFault = false) override; + + ConstAccessorPair getData(store_address_t packet_id) override; + ReturnValue_t getData(store_address_t packet_id, ConstStorageAccessor&) override; ReturnValue_t getData(store_address_t packet_id, const uint8_t** packet_ptr, size_t * size) override; + + AccessorPair modifyData(store_address_t packet_id) override; + ReturnValue_t modifyData(store_address_t packet_id, StorageAccessor&) override; ReturnValue_t modifyData(store_address_t packet_id, uint8_t** packet_ptr, size_t * size) override; + virtual ReturnValue_t deleteData(store_address_t) override; virtual ReturnValue_t deleteData(uint8_t* ptr, size_t size, store_address_t* storeId = NULL) override; @@ -84,7 +88,7 @@ public: ReturnValue_t initialize() override; protected: /** - * With this helper method, a free element of \c size is reserved. + * With this helper method, a free element of @c size is reserved. * @param size The minimum packet size that shall be reserved. * @param[out] address Storage ID of the reserved data. * @return - #RETURN_OK on success, @@ -97,7 +101,8 @@ protected: private: /** * Indicates that this element is free. - * This value limits the maximum size of a pool. Change to larger data type if increase is required. + * This value limits the maximum size of a pool. Change to larger data type + * if increase is required. */ static const uint32_t STORAGE_FREE = 0xFFFFFFFF; /** @@ -123,7 +128,9 @@ private: * is also dynamically allocated there. */ uint32_t* size_list[NUMBER_OF_POOLS]; - bool spillsToHigherPools; //!< A variable to determine whether higher n pools are used if the store is full. + //! A variable to determine whether higher n pools are used if + //! the store is full. + bool spillsToHigherPools; /** * @brief This method safely stores the given data in the given packet_id. * @details It also sets the size in size_list. The method does not perform @@ -180,4 +187,4 @@ private: #include "LocalPool.tpp" -#endif /* FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ */ +#endif /* FSFW_STORAGEMANAGER_LOCALPOOL_H_ */ diff --git a/storagemanager/LocalPool.tpp b/storagemanager/LocalPool.tpp index 08685de2..5e61efe4 100644 --- a/storagemanager/LocalPool.tpp +++ b/storagemanager/LocalPool.tpp @@ -1,5 +1,9 @@ -#ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ -#define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ +#ifndef FSFW_STORAGEMANAGER_LOCALPOOL_TPP_ +#define FSFW_STORAGEMANAGER_LOCALPOOL_TPP_ + +#ifndef FSFW_STORAGEMANAGER_LOCALPOOL_H_ +#error Include LocalPool.h before LocalPool.tpp! +#endif template inline LocalPool::LocalPool(object_id_t setObjectId, @@ -122,8 +126,9 @@ inline LocalPool::~LocalPool(void) { } template -inline ReturnValue_t LocalPool::addData(store_address_t* storageId, - const uint8_t* data, size_t size, bool ignoreFault) { +inline ReturnValue_t LocalPool::addData( + store_address_t* storageId, const uint8_t* data, size_t size, + bool ignoreFault) { ReturnValue_t status = reserveSpace(size, storageId, ignoreFault); if (status == RETURN_OK) { write(*storageId, data, size); @@ -144,15 +149,55 @@ inline ReturnValue_t LocalPool::getFreeElement( return status; } +template +inline ConstAccessorPair LocalPool::getData( + store_address_t storeId) { + uint8_t* tempData = nullptr; + ConstStorageAccessor constAccessor(storeId, this); + ReturnValue_t status = modifyData(storeId, &tempData, &constAccessor.size_); + constAccessor.constDataPointer = tempData; + return ConstAccessorPair(status, std::move(constAccessor)); +} + +template +inline ReturnValue_t LocalPool::getData(store_address_t storeId, + ConstStorageAccessor& storeAccessor) { + uint8_t* tempData = nullptr; + ReturnValue_t status = modifyData(storeId, &tempData, &storeAccessor.size_); + storeAccessor.assignStore(this); + storeAccessor.constDataPointer = tempData; + return status; +} + template inline ReturnValue_t LocalPool::getData( store_address_t packet_id, const uint8_t** packet_ptr, size_t* size) { - uint8_t* tempData = NULL; + uint8_t* tempData = nullptr; ReturnValue_t status = modifyData(packet_id, &tempData, size); *packet_ptr = tempData; return status; } +template +inline AccessorPair LocalPool::modifyData( + store_address_t storeId) { + StorageAccessor accessor(storeId, this); + ReturnValue_t status = modifyData(storeId, &accessor.dataPointer, + &accessor.size_); + accessor.assignConstPointer(); + return AccessorPair(status, std::move(accessor)); +} + +template +inline ReturnValue_t LocalPool::modifyData( + store_address_t storeId, StorageAccessor& storeAccessor) { + storeAccessor.assignStore(this); + ReturnValue_t status = modifyData(storeId, &storeAccessor.dataPointer, + &storeAccessor.size_); + storeAccessor.assignConstPointer(); + return status; +} + template inline ReturnValue_t LocalPool::modifyData( store_address_t packet_id, uint8_t** packet_ptr, size_t* size) { @@ -242,8 +287,8 @@ inline ReturnValue_t LocalPool::initialize() { } internalErrorReporter = objectManager->get( objects::INTERNAL_ERROR_REPORTER); - if (internalErrorReporter == NULL){ - return RETURN_FAILED; + if (internalErrorReporter == nullptr){ + return ObjectManagerIF::INTERNAL_ERR_REPORTER_UNINIT; } //Check if any pool size is large than the maximum allowed. @@ -251,10 +296,10 @@ inline ReturnValue_t LocalPool::initialize() { if (element_sizes[count] >= STORAGE_FREE) { sif::error << "LocalPool::initialize: Pool is too large! " "Max. allowed size is: " << (STORAGE_FREE - 1) << std::endl; - return RETURN_FAILED; + return StorageManagerIF::POOL_TOO_LARGE; } } return RETURN_OK; } -#endif +#endif /* FSFW_STORAGEMANAGER_LOCALPOOL_TPP_ */ diff --git a/storagemanager/PoolManager.h b/storagemanager/PoolManager.h index 0b101d66..8cc6c065 100644 --- a/storagemanager/PoolManager.h +++ b/storagemanager/PoolManager.h @@ -1,17 +1,18 @@ -#ifndef POOLMANAGER_H_ -#define POOLMANAGER_H_ - +#ifndef FSFW_STORAGEMANAGER_POOLMANAGER_H_ +#define FSFW_STORAGEMANAGER_POOLMANAGER_H_ #include "LocalPool.h" +#include "StorageAccessor.h" #include "../ipc/MutexHelper.h" + /** * @brief The PoolManager class provides an intermediate data storage with * a fixed pool size policy for inter-process communication. * @details Uses local pool calls but is thread safe by protecting the call * with a lock. + * @author Bastian Baetz */ - template class PoolManager : public LocalPool { public: @@ -19,16 +20,25 @@ public: const uint16_t element_sizes[NUMBER_OF_POOLS], const uint16_t n_elements[NUMBER_OF_POOLS]); - //! @brief In the PoolManager's destructor all allocated memory is freed. + /** + * @brief In the PoolManager's destructor all allocated memory + * is freed. + */ virtual ~PoolManager(); - //! @brief LocalPool overrides for thread-safety. + /** + * @brief LocalPool overrides for thread-safety. Decorator function + * which wraps LocalPool calls with a mutex protection. + */ ReturnValue_t deleteData(store_address_t) override; ReturnValue_t deleteData(uint8_t* buffer, size_t size, - store_address_t* storeId = NULL) override; - ReturnValue_t modifyData(store_address_t packet_id, uint8_t** packet_ptr, - size_t* size) override; + store_address_t* storeId = nullptr) override; + + void setMutexTimeout(uint32_t mutexTimeoutMs); protected: + //! Default mutex timeout value to prevent permanent blocking. + uint32_t mutexTimeoutMs = 20; + ReturnValue_t reserveSpace(const uint32_t size, store_address_t* address, bool ignoreFault) override; @@ -43,4 +53,4 @@ protected: #include "PoolManager.tpp" -#endif /* POOLMANAGER_H_ */ +#endif /* FSFW_STORAGEMANAGER_POOLMANAGER_H_ */ diff --git a/storagemanager/PoolManager.tpp b/storagemanager/PoolManager.tpp index 0e946b66..2be44ece 100644 --- a/storagemanager/PoolManager.tpp +++ b/storagemanager/PoolManager.tpp @@ -1,6 +1,10 @@ #ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ #define FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ +#ifndef FSFW_STORAGEMANAGER_POOLMANAGER_H_ +#error Include PoolManager.h before PoolManager.tpp! +#endif + template inline PoolManager::PoolManager(object_id_t setObjectId, const uint16_t element_sizes[NUMBER_OF_POOLS], @@ -17,7 +21,7 @@ inline PoolManager::~PoolManager(void) { template inline ReturnValue_t PoolManager::reserveSpace( const uint32_t size, store_address_t* address, bool ignoreFault) { - MutexHelper mutexHelper(mutex,MutexIF::BLOCKING); + MutexHelper mutexHelper(mutex,MutexIF::WAITING, mutexTimeoutMs); ReturnValue_t status = LocalPool::reserveSpace(size, address,ignoreFault); return status; @@ -29,7 +33,7 @@ inline ReturnValue_t PoolManager::deleteData( // debug << "PoolManager( " << translateObject(getObjectId()) << // " )::deleteData from store " << packet_id.pool_index << // ". id is "<< packet_id.packet_index << std::endl; - MutexHelper mutexHelper(mutex,MutexIF::BLOCKING); + MutexHelper mutexHelper(mutex,MutexIF::WAITING, mutexTimeoutMs); ReturnValue_t status = LocalPool::deleteData(packet_id); return status; } @@ -37,19 +41,16 @@ inline ReturnValue_t PoolManager::deleteData( template inline ReturnValue_t PoolManager::deleteData(uint8_t* buffer, size_t size, store_address_t* storeId) { - MutexHelper mutexHelper(mutex,MutexIF::BLOCKING); + MutexHelper mutexHelper(mutex,MutexIF::WAITING, mutexTimeoutMs); ReturnValue_t status = LocalPool::deleteData(buffer, size, storeId); return status; } template -inline ReturnValue_t PoolManager::modifyData( - store_address_t packet_id, uint8_t** packet_ptr, size_t* size) { - MutexHelper mutexHelper(mutex,MutexIF::BLOCKING); - ReturnValue_t status = LocalPool::modifyData(packet_id, - packet_ptr, size); - return status; +inline void PoolManager::setMutexTimeout( + uint32_t mutexTimeoutMs) { + this->mutexTimeout = mutexTimeoutMs; } -#endif +#endif /* FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ */ diff --git a/storagemanager/StorageAccessor.cpp b/storagemanager/StorageAccessor.cpp new file mode 100644 index 00000000..9c2f936a --- /dev/null +++ b/storagemanager/StorageAccessor.cpp @@ -0,0 +1,67 @@ +#include "StorageAccessor.h" +#include "StorageManagerIF.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +StorageAccessor::StorageAccessor(store_address_t storeId): + ConstStorageAccessor(storeId) { +} + +StorageAccessor::StorageAccessor(store_address_t storeId, + StorageManagerIF* store): + ConstStorageAccessor(storeId, store) { +} + +StorageAccessor& StorageAccessor::operator =( + StorageAccessor&& other) { + // Call the parent move assignment and also assign own member. + dataPointer = other.dataPointer; + StorageAccessor::operator=(std::move(other)); + return * this; +} + +// Call the parent move ctor and also transfer own member. +StorageAccessor::StorageAccessor(StorageAccessor&& other): + ConstStorageAccessor(std::move(other)), dataPointer(other.dataPointer) { +} + +ReturnValue_t StorageAccessor::getDataCopy(uint8_t *pointer, size_t maxSize) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(size_ > maxSize) { + sif::error << "StorageAccessor: Supplied buffer not large " + "enough" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::copy(dataPointer, dataPointer + size_, pointer); + return HasReturnvaluesIF::RETURN_OK; +} + +uint8_t* StorageAccessor::data() { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + } + return dataPointer; +} + +ReturnValue_t StorageAccessor::write(uint8_t *data, size_t size, + uint16_t offset) { + if(internalState == AccessState::UNINIT) { + sif::warning << "StorageAccessor: Not initialized!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + if(offset + size > size_) { + sif::error << "StorageAccessor: Data too large for pool " + "entry!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + std::copy(data, data + size, dataPointer + offset); + return HasReturnvaluesIF::RETURN_OK; +} + +void StorageAccessor::assignConstPointer() { + constDataPointer = dataPointer; +} + + diff --git a/storagemanager/StorageAccessor.h b/storagemanager/StorageAccessor.h new file mode 100644 index 00000000..5cf15d50 --- /dev/null +++ b/storagemanager/StorageAccessor.h @@ -0,0 +1,45 @@ +#ifndef FSFW_STORAGEMANAGER_STORAGEACCESSOR_H_ +#define FSFW_STORAGEMANAGER_STORAGEACCESSOR_H_ + +#include "ConstStorageAccessor.h" + +class StorageManagerIF; + +/** + * @brief Child class for modifyable data. Also has a normal pointer member. + */ +class StorageAccessor: public ConstStorageAccessor { + //! StorageManager classes have exclusive access to private variables. + template + friend class PoolManager; + template + friend class LocalPool; +public: + StorageAccessor(store_address_t storeId); + StorageAccessor(store_address_t storeId, StorageManagerIF* store); + + /** + * @brief Move ctor and move assignment allow returning accessors as + * a returnvalue. They prevent resource being freed prematurely. + * See: https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/cpp/ + * move-constructors-and-move-assignment-operators-cpp.md + * @param + * @return + */ + StorageAccessor& operator=(StorageAccessor&&); + StorageAccessor(StorageAccessor&&); + + ReturnValue_t write(uint8_t *data, size_t size, + uint16_t offset = 0); + uint8_t* data(); + ReturnValue_t getDataCopy(uint8_t *pointer, size_t maxSize) override; + +private: + //! Non-const pointer for modifyable data. + uint8_t* dataPointer = nullptr; + //! For modifyable data, the const pointer is assigned to the normal + //! pointer by the pool manager so both access functions can be used safely + void assignConstPointer(); +}; + +#endif /* FSFW_STORAGEMANAGER_STORAGEACCESSOR_H_ */ diff --git a/storagemanager/StorageManagerIF.h b/storagemanager/StorageManagerIF.h index 7c194d72..834e7563 100644 --- a/storagemanager/StorageManagerIF.h +++ b/storagemanager/StorageManagerIF.h @@ -1,60 +1,17 @@ -#ifndef STORAGEMANAGERIF_H_H -#define STORAGEMANAGERIF_H_H +#ifndef FSFW_STORAGEMANAGER_STORAGEMANAGERIF_H_ +#define FSFW_STORAGEMANAGER_STORAGEMANAGERIF_H_ + +#include "StorageAccessor.h" +#include "storeAddress.h" #include "../events/Event.h" #include "../returnvalues/HasReturnvaluesIF.h" -#include -/** - * @brief This union defines the type that identifies where a data packet is - * stored in the store. - * It consists of a raw part to read it as raw value and - * a structured part to use it in pool-like stores. - */ -union store_address_t { - /** - * Default Constructor, initializing to INVALID_ADDRESS - */ - store_address_t():raw(0xFFFFFFFF){} +#include +#include - /** - * Constructor to create an address object using the raw address - * @param rawAddress - */ - store_address_t(uint32_t rawAddress):raw(rawAddress){} - - /** - * Constructor to create an address object using pool - * and packet indices - * - * @param poolIndex - * @param packetIndex - */ - store_address_t(uint16_t poolIndex, uint16_t packetIndex): - pool_index(poolIndex),packet_index(packetIndex) {} - - /** - * A structure with two elements to access the store address pool-like. - */ - struct { - /** - * The index in which pool the packet lies. - */ - uint16_t pool_index; - /** - * The position in the chosen pool. - */ - uint16_t packet_index; - }; - /** - * Alternative access to the raw value. - */ - uint32_t raw; - - bool operator==(const store_address_t& other) const { - return raw == other.raw; - } -}; +using AccessorPair = std::pair; +using ConstAccessorPair = std::pair; /** * @brief This class provides an interface for intermediate data storage. @@ -77,6 +34,7 @@ public: static const ReturnValue_t ILLEGAL_STORAGE_ID = MAKE_RETURN_CODE(3); //!< This return code indicates that data was requested with an illegal storage ID. static const ReturnValue_t DATA_DOES_NOT_EXIST = MAKE_RETURN_CODE(4); //!< This return code indicates that the requested ID was valid, but no data is stored there. static const ReturnValue_t ILLEGAL_ADDRESS = MAKE_RETURN_CODE(5); + static const ReturnValue_t POOL_TOO_LARGE = MAKE_RETURN_CODE(6); //!< Pool size too large on initialization. static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::OBSW; static const Event GET_DATA_FAILED = MAKE_EVENT(0, SEVERITY::LOW); @@ -122,6 +80,29 @@ public: */ virtual ReturnValue_t deleteData(uint8_t* buffer, size_t size, store_address_t* storeId = nullptr) = 0; + + + /** + * @brief Access the data by supplying a store ID. + * @details + * A pair consisting of the retrieval result and an instance of a + * ConstStorageAccessor class is returned + * @param storeId + * @return Pair of return value and a ConstStorageAccessor instance + */ + virtual ConstAccessorPair getData(store_address_t storeId) = 0; + + /** + * @brief Access the data by supplying a store ID and a helper + * instance + * @param storeId + * @param constAccessor Wrapper function to access store data. + * @return + */ + virtual ReturnValue_t getData(store_address_t storeId, + ConstStorageAccessor& constAccessor) = 0; + + /** * @brief getData returns an address to data and the size of the data * for a given packet_id. @@ -135,8 +116,30 @@ public: */ virtual ReturnValue_t getData(store_address_t packet_id, const uint8_t** packet_ptr, size_t* size) = 0; + + /** - * Same as above, but not const and therefore modifiable. + * Modify data by supplying a store ID + * @param storeId + * @return Pair of return value and StorageAccessor helper + */ + virtual AccessorPair modifyData(store_address_t storeId) = 0; + + /** + * Modify data by supplying a store ID and a StorageAccessor helper instance. + * @param storeId + * @param accessor Helper class to access the modifiable data. + * @return + */ + virtual ReturnValue_t modifyData(store_address_t storeId, + StorageAccessor& accessor) = 0; + + /** + * Get pointer and size of modifiable data by supplying the storeId + * @param packet_id + * @param packet_ptr [out] Pointer to pointer of data to set + * @param size [out] Pointer to size to set + * @return */ virtual ReturnValue_t modifyData(store_address_t packet_id, uint8_t** packet_ptr, size_t* size) = 0; @@ -155,6 +158,7 @@ public: */ virtual ReturnValue_t getFreeElement(store_address_t* storageId, const size_t size, uint8_t** p_data, bool ignoreFault = false ) = 0; + /** * Clears the whole store. * Use with care! @@ -162,4 +166,4 @@ public: virtual void clearStore() = 0; }; -#endif /* STORAGEMANAGERIF_H_ */ +#endif /* FSFW_STORAGEMANAGER_STORAGEMANAGERIF_H_ */ diff --git a/storagemanager/storeAddress.h b/storagemanager/storeAddress.h new file mode 100644 index 00000000..044c0790 --- /dev/null +++ b/storagemanager/storeAddress.h @@ -0,0 +1,55 @@ +#ifndef FSFW_STORAGEMANAGER_STOREADDRESS_H_ +#define FSFW_STORAGEMANAGER_STOREADDRESS_H_ + +#include + +/** + * This union defines the type that identifies where a data packet is + * stored in the store. It comprises of a raw part to read it as raw value and + * a structured part to use it in pool-like stores. + */ +union store_address_t { + /** + * Default Constructor, initializing to INVALID_ADDRESS + */ + store_address_t():raw(0xFFFFFFFF){} + /** + * Constructor to create an address object using the raw address + * + * @param rawAddress + */ + store_address_t(uint32_t rawAddress):raw(rawAddress){} + + /** + * Constructor to create an address object using pool + * and packet indices + * + * @param poolIndex + * @param packetIndex + */ + store_address_t(uint16_t poolIndex, uint16_t packetIndex): + pool_index(poolIndex),packet_index(packetIndex){} + /** + * A structure with two elements to access the store address pool-like. + */ + struct { + /** + * The index in which pool the packet lies. + */ + uint16_t pool_index; + /** + * The position in the chosen pool. + */ + uint16_t packet_index; + }; + /** + * Alternative access to the raw value. + */ + uint32_t raw; + + bool operator==(const store_address_t& other) const { + return raw == other.raw; + } +}; + +#endif /* FSFW_STORAGEMANAGER_STOREADDRESS_H_ */ diff --git a/tasks/FixedSequenceSlot.cpp b/tasks/FixedSequenceSlot.cpp new file mode 100644 index 00000000..f5d82178 --- /dev/null +++ b/tasks/FixedSequenceSlot.cpp @@ -0,0 +1,17 @@ +#include "FixedSequenceSlot.h" +#include "PeriodicTaskIF.h" +#include + +FixedSequenceSlot::FixedSequenceSlot(object_id_t handlerId, uint32_t setTime, + int8_t setSequenceId, ExecutableObjectIF* executableObject, + PeriodicTaskIF* executingTask) : handlerId(handlerId), + pollingTimeMs(setTime), opcode(setSequenceId) { + if(executableObject == nullptr) { + return; + } + this->executableObject = executableObject; + this->executableObject->setTaskIF(executingTask); +} + +FixedSequenceSlot::~FixedSequenceSlot() {} + diff --git a/devicehandlers/FixedSequenceSlot.h b/tasks/FixedSequenceSlot.h similarity index 53% rename from devicehandlers/FixedSequenceSlot.h rename to tasks/FixedSequenceSlot.h index 73504955..1744ec19 100644 --- a/devicehandlers/FixedSequenceSlot.h +++ b/tasks/FixedSequenceSlot.h @@ -1,41 +1,41 @@ -/** - * @file FixedSequenceSlot.h - * @brief This file defines the PollingSlot class. - * @date 19.12.2012 - * @author baetz - */ - -#ifndef FIXEDSEQUENCESLOT_H_ -#define FIXEDSEQUENCESLOT_H_ +#ifndef FSFW_TASKS_FIXEDSEQUENCESLOT_H_ +#define FSFW_TASKS_FIXEDSEQUENCESLOT_H_ +#include "ExecutableObjectIF.h" #include "../objectmanager/ObjectManagerIF.h" -#include "../tasks/ExecutableObjectIF.h" + class PeriodicTaskIF; /** - * @brief This class is the representation of a single polling sequence table entry. - * - * @details The PollingSlot class is the representation of a single polling - * sequence table entry. + * @brief This class is the representation of a single polling sequence + * table entry. + * @details + * The PollingSlot class is the representation of a single polling + * sequence table entry. + * @author baetz */ class FixedSequenceSlot { public: FixedSequenceSlot( object_id_t handlerId, uint32_t setTimeMs, - int8_t setSequenceId, PeriodicTaskIF* executingTask ); + int8_t setSequenceId, ExecutableObjectIF* executableObject, + PeriodicTaskIF* executingTask); virtual ~FixedSequenceSlot(); + object_id_t handlerId; + /** - * @brief Handler identifies which device handler object is executed in this slot. + * @brief Handler identifies which object is executed in this slot. */ - ExecutableObjectIF* handler; + ExecutableObjectIF* executableObject = nullptr; /** * @brief This attribute defines when a device handler object is executed. - * - * @details The pollingTime attribute identifies the time the handler is executed in ms. - * It must be smaller than the period length of the polling sequence. + * @details + * The pollingTime attribute identifies the time the handler is + * executed in ms. It must be smaller than the period length of the + * polling sequence. */ - uint32_t pollingTimeMs; + uint32_t pollingTimeMs; /** * @brief This value defines the type of device communication. @@ -43,7 +43,7 @@ public: * @details The state of this value decides what communication routine is * called in the PST executable or the device handler object. */ - uint8_t opcode; + uint8_t opcode; /** * @brief Operator overload for the comparison operator to @@ -57,4 +57,4 @@ public: }; -#endif /* FIXEDSEQUENCESLOT_H_ */ +#endif /* FSFW_TASKS_FIXEDSEQUENCESLOT_H_ */ diff --git a/devicehandlers/FixedSlotSequence.cpp b/tasks/FixedSlotSequence.cpp similarity index 53% rename from devicehandlers/FixedSlotSequence.cpp rename to tasks/FixedSlotSequence.cpp index 38d4dcea..e5db4301 100644 --- a/devicehandlers/FixedSlotSequence.cpp +++ b/tasks/FixedSlotSequence.cpp @@ -1,5 +1,6 @@ #include "FixedSlotSequence.h" #include "../serviceinterface/ServiceInterfaceStream.h" +#include FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) : lengthMs(setLengthMs) { @@ -12,7 +13,7 @@ FixedSlotSequence::~FixedSlotSequence() { } void FixedSlotSequence::executeAndAdvance() { - current->handler->performOperation(current->opcode); + current->executableObject->performOperation(current->opcode); // if (returnValue != RETURN_OK) { // this->sendErrorMessage( returnValue ); // } @@ -80,44 +81,82 @@ uint32_t FixedSlotSequence::getLengthMs() const { return this->lengthMs; } +void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs, + int8_t executionStep, ExecutableObjectIF* executableObject, + PeriodicTaskIF* executingTask) { + this->slotList.insert(FixedSequenceSlot(componentId, slotTimeMs, + executionStep, executableObject, executingTask)); + this->current = slotList.begin(); +} + ReturnValue_t FixedSlotSequence::checkSequence() const { if(slotList.empty()) { - sif::error << "Fixed Slot Sequence: Slot list is empty!" << std::endl; + sif::error << "FixedSlotSequence::checkSequence:" + << " Slot list is empty!" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } - auto slotIt = slotList.begin(); - uint32_t count = 0; - uint32_t time = 0; - while (slotIt != slotList.end()) { - if (slotIt->handler == nullptr) { - sif::error << "FixedSlotSequene::initialize: ObjectId does not exist!" - << std::endl; - count++; - } else if (slotIt->pollingTimeMs < time) { - sif::error << "FixedSlotSequence::initialize: Time: " - << slotIt->pollingTimeMs - << " is smaller than previous with " << time << std::endl; - count++; - } else { - // All ok, print slot. - //info << "Current slot polling time: " << std::endl; - //info << std::dec << slotIt->pollingTimeMs << std::endl; + if(customCheckFunction != nullptr) { + ReturnValue_t result = customCheckFunction(slotList); + if(result != HasReturnvaluesIF::RETURN_OK) { + // Continue for now but print error output. + sif::error << "FixedSlotSequence::checkSequence:" + << " Custom check failed!" << std::endl; } - time = slotIt->pollingTimeMs; - slotIt++; } - //info << "Number of elements in slot list: " + + uint32_t errorCount = 0; + uint32_t time = 0; + for(const auto& slot: slotList) { + if (slot.executableObject == nullptr) { + errorCount++; + } + else if (slot.pollingTimeMs < time) { + sif::error << "FixedSlotSequence::checkSequence: Time: " + << slot.pollingTimeMs << " is smaller than previous with " + << time << std::endl; + errorCount++; + } + else { + // All ok, print slot. + //sif::info << "Current slot polling time: " << std::endl; + //sif::info << std::dec << slotIt->pollingTimeMs << std::endl; + } + time = slot.pollingTimeMs; + + } + //sif::info << "Number of elements in slot list: " // << slotList.size() << std::endl; - if (count > 0) { + if (errorCount > 0) { return HasReturnvaluesIF::RETURN_FAILED; } return HasReturnvaluesIF::RETURN_OK; } -void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs, - int8_t executionStep, PeriodicTaskIF* executingTask) { - this->slotList.insert(FixedSequenceSlot(componentId, slotTimeMs, executionStep, - executingTask)); - this->current = slotList.begin(); + +ReturnValue_t FixedSlotSequence::intializeSequenceAfterTaskCreation() const { + std::set uniqueObjects; + uint32_t count = 0; + for(const auto& slot: slotList) { + // Ensure that each unique object is initialized once. + if(uniqueObjects.find(slot.executableObject) == uniqueObjects.end()) { + ReturnValue_t result = + slot.executableObject->initializeAfterTaskCreation(); + if(result != HasReturnvaluesIF::RETURN_OK) { + count++; + } + uniqueObjects.emplace(slot.executableObject); + } + } + if (count > 0) { + sif::error << "FixedSlotSequence::intializeSequenceAfterTaskCreation:" + "Counted " << count << " failed initializations!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void FixedSlotSequence::addCustomCheck(ReturnValue_t + (*customCheckFunction)(const SlotList&)) { + this->customCheckFunction = customCheckFunction; } diff --git a/devicehandlers/FixedSlotSequence.h b/tasks/FixedSlotSequence.h similarity index 58% rename from devicehandlers/FixedSlotSequence.h rename to tasks/FixedSlotSequence.h index be6dc2d1..077dd10b 100644 --- a/devicehandlers/FixedSlotSequence.h +++ b/tasks/FixedSlotSequence.h @@ -1,26 +1,30 @@ -#ifndef FRAMEWORK_DEVICEHANDLERS_FIXEDSLOTSEQUENCE_H_ -#define FRAMEWORK_DEVICEHANDLERS_FIXEDSLOTSEQUENCE_H_ +#ifndef FSFW_TASKS_FIXEDSLOTSEQUENCE_H_ +#define FSFW_TASKS_FIXEDSLOTSEQUENCE_H_ #include "FixedSequenceSlot.h" #include "../objectmanager/SystemObject.h" + #include /** - * @brief This class is the representation of a Polling Sequence Table in software. - * + * @brief This class is the representation of a + * Polling Sequence Table in software. * @details * The FixedSlotSequence object maintains the dynamic execution of - * device handler objects. + * objects with stricter timing requirements for the FixedTimeslotTask. * - * The main idea is to create a list of device handlers, to announce all - * handlers to thepolling sequence and to maintain a list of - * polling slot objects. This slot list represents the Polling Sequence Table - * in software. + * The main idea is to create a list of executable objects (for example + * device handlers), to announce all handlers to the polling sequence and to + * maintain a list of polling slot objects. + * This slot list represents the Polling Sequence Table in software. * * Each polling slot contains information to indicate when and - * which device handler shall be executed within a given polling period. - * The sequence is then executed by iterating through this slot list. - * Handlers are invoking by calling a certain function stored in the handler list. + * which executable object shall be executed within a given polling period. + * When adding a slot, a pointer to the executing task, a pointer to the + * executable object and a step number can be passed. The step number will be + * passed to the periodic handler. + * The sequence is executed by iterating through the slot sequence and + * executing the executable object in the correct timeslot. */ class FixedSlotSequence { public: @@ -29,41 +33,44 @@ public: /** * @brief The constructor of the FixedSlotSequence object. - * - * @details The constructor takes two arguments, the period length and the init function. - * * @param setLength The period length, expressed in ms. */ FixedSlotSequence(uint32_t setLengthMs); /** * @brief The destructor of the FixedSlotSequence object. - * - * @details The destructor frees all allocated memory by iterating through the slotList - * and deleting all allocated resources. + * @details + * The destructor frees all allocated memory by iterating through the + * slotList and deleting all allocated resources. */ virtual ~FixedSlotSequence(); /** * @brief This is a method to add an PollingSlot object to slotList. * - * @details Here, a polling slot object is added to the slot list. It is appended - * to the end of the list. The list is currently NOT reordered. - * Afterwards, the iterator current is set to the beginning of the list. - * @param Object ID of the object to add - * @param setTime Value between (0 to 1) * slotLengthMs, when a FixedTimeslotTask - * will be called inside the slot period. - * @param setSequenceId ID which can be used to distinguish - * different task operations + * @details + * Here, a polling slot object is added to the slot list. It is appended + * to the end of the list. The list is currently NOT reordered. + * Afterwards, the iterator current is set to the beginning of the list. + * @param handlerId ID of the object to add + * @param setTime + * Value between (0 to 1) * slotLengthMs, when a FixedTimeslotTask + * will be called inside the slot period. + * @param setSequenceId + * ID which can be used to distinguish different task operations. This + * value will be passed to the executable function. * @param * @param */ void addSlot(object_id_t handlerId, uint32_t setTime, int8_t setSequenceId, + ExecutableObjectIF* executableObject, PeriodicTaskIF* executingTask); /** - * Checks if the current slot shall be executed immediately after the one before. - * This allows to distinguish between grouped and not grouped handlers. + * @brief Checks if the current slot shall be executed immediately + * after the one before. + * @details + * This allows to distinguish between grouped and separated handlers. * @return - @c true if the slot has the same polling time as the previous * - @c false else */ @@ -125,12 +132,32 @@ public: SlotListIter current; /** - * Iterate through slotList and check successful creation. + * @brief Check and initialize slot list. + * @details * Checks if timing is ok (must be ascending) and if all handlers were found. * @return */ ReturnValue_t checkSequence() const; + /** + * @brief A custom check can be injected for the respective slot list. + * @details + * This can be used by the developer to check the validity of a certain + * sequence. The function will be run in the #checkSequence function. + * The general check will be continued for now if the custom check function + * fails but a diagnostic debug output will be given. + * @param customCheckFunction + */ + void addCustomCheck(ReturnValue_t (*customCheckFunction)(const SlotList &)); + + /** + * @brief Perform any initialization steps required after the executing + * task has been created. This function should be called from the + * executing task! + * @return + */ + ReturnValue_t intializeSequenceAfterTaskCreation() const; + protected: /** @@ -146,7 +173,9 @@ protected: */ SlotList slotList; + ReturnValue_t (*customCheckFunction)(const SlotList&) = nullptr; + uint32_t lengthMs; }; -#endif /* FIXEDSLOTSEQUENCE_H_ */ +#endif /* FSFW_TASKS_FIXEDSLOTSEQUENCE_H_ */ diff --git a/tasks/SemaphoreFactory.h b/tasks/SemaphoreFactory.h index 2c41a135..01c09d1b 100644 --- a/tasks/SemaphoreFactory.h +++ b/tasks/SemaphoreFactory.h @@ -1,50 +1,50 @@ -#ifndef FSFW_TASKS_SEMAPHOREFACTORY_H_ -#define FSFW_TASKS_SEMAPHOREFACTORY_H_ - -#include "../tasks/SemaphoreIF.h" - -/** - * Creates Semaphore. - * This class is a "singleton" interface, i.e. it provides an - * interface, but also is the base class for a singleton. - */ -class SemaphoreFactory { -public: - virtual ~SemaphoreFactory(); - /** - * Returns the single instance of SemaphoreFactory. - * The implementation of #instance is found in its subclasses. - * Thus, we choose link-time variability of the instance. - */ - static SemaphoreFactory* instance(); - - /** - * Create a binary semaphore. - * Creator function for a binary semaphore which may only be acquired once - * @param argument Can be used to pass implementation specific information. - * @return Pointer to newly created semaphore class instance. - */ - SemaphoreIF* createBinarySemaphore(uint32_t arguments = 0); - /** - * Create a counting semaphore. - * Creator functons for a counting semaphore which may be acquired multiple - * times. - * @param count Semaphore can be taken count times. - * @param initCount Initial count value. - * @param argument Can be used to pass implementation specific information. - * @return - */ - SemaphoreIF* createCountingSemaphore(const uint8_t maxCount, - uint8_t initCount, uint32_t arguments = 0); - - void deleteSemaphore(SemaphoreIF* semaphore); - -private: - /** - * External instantiation is not allowed. - */ - SemaphoreFactory(); - static SemaphoreFactory* factoryInstance; -}; - -#endif /* FSFW_TASKS_SEMAPHOREFACTORY_H_ */ +#ifndef FSFW_TASKS_SEMAPHOREFACTORY_H_ +#define FSFW_TASKS_SEMAPHOREFACTORY_H_ + +#include "../tasks/SemaphoreIF.h" + +/** + * Creates Semaphore. + * This class is a "singleton" interface, i.e. it provides an + * interface, but also is the base class for a singleton. + */ +class SemaphoreFactory { +public: + virtual ~SemaphoreFactory(); + /** + * Returns the single instance of SemaphoreFactory. + * The implementation of #instance is found in its subclasses. + * Thus, we choose link-time variability of the instance. + */ + static SemaphoreFactory* instance(); + + /** + * Create a binary semaphore. + * Creator function for a binary semaphore which may only be acquired once + * @param argument Can be used to pass implementation specific information. + * @return Pointer to newly created semaphore class instance. + */ + SemaphoreIF* createBinarySemaphore(uint32_t arguments = 0); + /** + * Create a counting semaphore. + * Creator functons for a counting semaphore which may be acquired multiple + * times. + * @param count Semaphore can be taken count times. + * @param initCount Initial count value. + * @param argument Can be used to pass implementation specific information. + * @return + */ + SemaphoreIF* createCountingSemaphore(const uint8_t maxCount, + uint8_t initCount, uint32_t arguments = 0); + + void deleteSemaphore(SemaphoreIF* semaphore); + +private: + /** + * External instantiation is not allowed. + */ + SemaphoreFactory(); + static SemaphoreFactory* factoryInstance; +}; + +#endif /* FSFW_TASKS_SEMAPHOREFACTORY_H_ */ diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h index 30d4ed88..dd327e23 100644 --- a/tasks/SemaphoreIF.h +++ b/tasks/SemaphoreIF.h @@ -1,68 +1,68 @@ -#ifndef FRAMEWORK_TASKS_SEMAPHOREIF_H_ -#define FRAMEWORK_TASKS_SEMAPHOREIF_H_ -#include "../returnvalues/FwClassIds.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include - -/** - * @brief Generic interface for semaphores, which can be used to achieve - * task synchronization. This is a generic interface which can be - * used for both binary semaphores and counting semaphores. - * @details - * A semaphore is a synchronization primitive. - * See: https://en.wikipedia.org/wiki/Semaphore_(programming) - * A semaphore can be used to achieve task synchonization and track the - * availability of resources by using either the binary or the counting - * semaphore types. - * - * 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. - */ -class SemaphoreIF { -public: - /** - * Different types of timeout for the mutex lock. - */ - enum TimeoutType { - POLLING, //!< If mutex is not available, return immediately - WAITING, //!< Wait a specified time for the mutex to become available - BLOCKING //!< Block indefinitely until the mutex becomes available. - }; - - virtual~ SemaphoreIF() {}; - - static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; - //! Semaphore timeout - static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1); - //! 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_INVALID = MAKE_RETURN_CODE(3); - - /** - * Generic call to acquire a 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 - * for a maximum of timeoutMs while trying to acquire the semaphore. - * This can be used to achieve task synchrnization. - * @param timeoutMs - * @return - c RETURN_OK for successfull acquisition - */ - virtual ReturnValue_t acquire(TimeoutType timeoutType = - TimeoutType::BLOCKING, uint32_t timeoutMs = 0) = 0; - - /** - * Corrensponding call to release a semaphore. - * @return -@c RETURN_OK for successfull release - */ - virtual ReturnValue_t release() = 0; - - /** - * If the semaphore is a counting semaphore then the semaphores current - * 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 - * semaphore is not available. - */ - virtual uint8_t getSemaphoreCounter() const = 0; -}; - -#endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */ +#ifndef FRAMEWORK_TASKS_SEMAPHOREIF_H_ +#define FRAMEWORK_TASKS_SEMAPHOREIF_H_ +#include "../returnvalues/FwClassIds.h" +#include "../returnvalues/HasReturnvaluesIF.h" +#include + +/** + * @brief Generic interface for semaphores, which can be used to achieve + * task synchronization. This is a generic interface which can be + * used for both binary semaphores and counting semaphores. + * @details + * A semaphore is a synchronization primitive. + * See: https://en.wikipedia.org/wiki/Semaphore_(programming) + * A semaphore can be used to achieve task synchonization and track the + * availability of resources by using either the binary or the counting + * semaphore types. + * + * 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. + */ +class SemaphoreIF { +public: + /** + * Different types of timeout for the mutex lock. + */ + enum TimeoutType { + POLLING, //!< If mutex is not available, return immediately + WAITING, //!< Wait a specified time for the mutex to become available + BLOCKING //!< Block indefinitely until the mutex becomes available. + }; + + virtual~ SemaphoreIF() {}; + + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + //! Semaphore timeout + static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1); + //! 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_INVALID = MAKE_RETURN_CODE(3); + + /** + * Generic call to acquire a 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 + * for a maximum of timeoutMs while trying to acquire the semaphore. + * This can be used to achieve task synchrnization. + * @param timeoutMs + * @return - c RETURN_OK for successfull acquisition + */ + virtual ReturnValue_t acquire(TimeoutType timeoutType = + TimeoutType::BLOCKING, uint32_t timeoutMs = 0) = 0; + + /** + * Corrensponding call to release a semaphore. + * @return -@c RETURN_OK for successfull release + */ + virtual ReturnValue_t release() = 0; + + /** + * If the semaphore is a counting semaphore then the semaphores current + * 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 + * semaphore is not available. + */ + virtual uint8_t getSemaphoreCounter() const = 0; +}; + +#endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */ diff --git a/tmtcservices/VerificationReporter.cpp b/tmtcservices/VerificationReporter.cpp index 43e712a2..7e40bd27 100644 --- a/tmtcservices/VerificationReporter.cpp +++ b/tmtcservices/VerificationReporter.cpp @@ -1,55 +1,59 @@ -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "VerificationReporter.h" #include "AcceptsVerifyMessageIF.h" #include "PusVerificationReport.h" -#include "VerificationReporter.h" -object_id_t VerificationReporter::messageReceiver = 0; +#include "../ipc/MessageQueueIF.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../objectmanager/frameworkObjects.h" + +object_id_t VerificationReporter::messageReceiver = + objects::PUS_SERVICE_1_VERIFICATION; VerificationReporter::VerificationReporter() : - acknowledgeQueue() { + acknowledgeQueue(MessageQueueIF::NO_QUEUE) { } -VerificationReporter::~VerificationReporter() { - //Default, empty -} +VerificationReporter::~VerificationReporter() {} void VerificationReporter::sendSuccessReport(uint8_t set_report_id, TcPacketBase* current_packet, uint8_t set_step) { - if (this->acknowledgeQueue == 0) { + if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); } PusVerificationMessage message(set_report_id, current_packet->getAcknowledgeFlags(), current_packet->getPacketId(), current_packet->getPacketSequenceControl(), 0, set_step); - ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, &message); + ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, + &message); if (status != HasReturnvaluesIF::RETURN_OK) { - sif::error - << "VerificationReporter::sendSuccessReport: Error writing to queue. Code: " - << (uint16_t) status << std::endl; + sif::error << "VerificationReporter::sendSuccessReport: Error writing " + << "to queue. Code: " << std::hex << status << std::dec + << std::endl; } } void VerificationReporter::sendSuccessReport(uint8_t set_report_id, uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, uint8_t set_step) { - if (this->acknowledgeQueue == 0) { + if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); } PusVerificationMessage message(set_report_id, ackFlags, tcPacketId, tcSequenceControl, 0, set_step); - ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, &message); + ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, + &message); if (status != HasReturnvaluesIF::RETURN_OK) { - sif::error - << "VerificationReporter::sendSuccessReport: Error writing to queue. Code: " - << (uint16_t) status << std::endl; + sif::error << "VerificationReporter::sendSuccessReport: Error writing " + << "to queue. Code: " << std::hex << status << std::dec + << std::endl; } } void VerificationReporter::sendFailureReport(uint8_t report_id, TcPacketBase* current_packet, ReturnValue_t error_code, uint8_t step, uint32_t parameter1, uint32_t parameter2) { - if (this->acknowledgeQueue == 0) { + if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); } PusVerificationMessage message(report_id, @@ -57,11 +61,12 @@ void VerificationReporter::sendFailureReport(uint8_t report_id, current_packet->getPacketId(), current_packet->getPacketSequenceControl(), error_code, step, parameter1, parameter2); - ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, &message); + ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, + &message); if (status != HasReturnvaluesIF::RETURN_OK) { - sif::error - << "VerificationReporter::sendFailureReport Error writing to queue. Code: " - << (uint16_t) status << std::endl; + sif::error << "VerificationReporter::sendFailureReport: Error writing " + << "to queue. Code: " << std::hex << "0x" << status << std::dec + << std::endl; } } @@ -69,27 +74,33 @@ void VerificationReporter::sendFailureReport(uint8_t report_id, uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, ReturnValue_t error_code, uint8_t step, uint32_t parameter1, uint32_t parameter2) { - if (this->acknowledgeQueue == 0) { + if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); } PusVerificationMessage message(report_id, ackFlags, tcPacketId, tcSequenceControl, error_code, step, parameter1, parameter2); - ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, &message); + ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, + &message); if (status != HasReturnvaluesIF::RETURN_OK) { - sif::error - << "VerificationReporter::sendFailureReport Error writing to queue. Code: " - << (uint16_t) status << std::endl; + sif::error << "VerificationReporter::sendFailureReport: Error writing " + << "to queue. Code: " << std::hex << "0x" << status << std::dec + << std::endl; } } void VerificationReporter::initialize() { + if(messageReceiver == objects::NO_OBJECT) { + sif::warning << "VerificationReporter::initialize: Verification message" + " receiver object ID not set yet in Factory!" << std::endl; + return; + } AcceptsVerifyMessageIF* temp = objectManager->get( messageReceiver); - if (temp != NULL) { - this->acknowledgeQueue = temp->getVerificationQueue(); - } else { - sif::error - << "VerificationReporter::VerificationReporter: Configuration error." - << std::endl; + if (temp == nullptr) { + sif::error << "VerificationReporter::initialize: Message " + << "receiver invalid. Make sure it is set up properly and " + << "implementsAcceptsVerifyMessageIF" << std::endl; + return; } + this->acknowledgeQueue = temp->getVerificationQueue(); } diff --git a/tmtcservices/VerificationReporter.h b/tmtcservices/VerificationReporter.h index 29a273c5..f26fa54f 100644 --- a/tmtcservices/VerificationReporter.h +++ b/tmtcservices/VerificationReporter.h @@ -1,31 +1,50 @@ -#ifndef VERIFICATIONREPORTER_H_ -#define VERIFICATIONREPORTER_H_ +#ifndef FSFW_TMTCSERVICES_VERIFICATIONREPORTER_H_ +#define FSFW_TMTCSERVICES_VERIFICATIONREPORTER_H_ -#include "../objectmanager/ObjectManagerIF.h" #include "PusVerificationReport.h" +#include "../objectmanager/ObjectManagerIF.h" namespace Factory{ void setStaticFrameworkObjectIds(); } +/** + * @brief This helper object is used to forward verification messages + * which are generated by the Flight Software Framework. + * @details + * The messages can be relayed to an arbitrary object, for example a dedicated + * Verification Reporter. The destination is set by setting the static framework + * Id VerificationReporter::messageReceiver. The default verification reporter + * will be the PUS service 1, which sends verification messages according + * to the PUS standard. + * + */ class VerificationReporter { friend void (Factory::setStaticFrameworkObjectIds)(); public: VerificationReporter(); virtual ~VerificationReporter(); - void sendSuccessReport( uint8_t set_report_id, TcPacketBase* current_packet, uint8_t set_step = 0 ); - void sendSuccessReport(uint8_t set_report_id, uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, uint8_t set_step = 0); - void sendFailureReport( uint8_t report_id, TcPacketBase* current_packet, ReturnValue_t error_code = 0, - uint8_t step = 0, uint32_t parameter1 = 0, uint32_t parameter2 = 0 ); + + void sendSuccessReport( uint8_t set_report_id, TcPacketBase* current_packet, + uint8_t set_step = 0 ); + void sendSuccessReport(uint8_t set_report_id, uint8_t ackFlags, + uint16_t tcPacketId, uint16_t tcSequenceControl, + uint8_t set_step = 0); + + void sendFailureReport( uint8_t report_id, TcPacketBase* current_packet, + ReturnValue_t error_code = 0, + uint8_t step = 0, uint32_t parameter1 = 0, + uint32_t parameter2 = 0 ); void sendFailureReport(uint8_t report_id, - uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, ReturnValue_t error_code = 0, uint8_t step = 0, + uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, + ReturnValue_t error_code = 0, uint8_t step = 0, uint32_t parameter1 = 0, uint32_t parameter2 = 0); + void initialize(); + private: static object_id_t messageReceiver; MessageQueueId_t acknowledgeQueue; - - }; -#endif /* VERIFICATIONREPORTER_H_ */ +#endif /* FSFW_TMTCSERVICES_VERIFICATIONREPORTER_H_ */