Adding Code for Linux
This commit is contained in:
211
osal/linux/Clock.cpp
Normal file
211
osal/linux/Clock.cpp
Normal file
@ -0,0 +1,211 @@
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <framework/timemanager/Clock.h>
|
||||
|
||||
|
||||
#include <sys/sysinfo.h>
|
||||
#include <linux/sysinfo.h>
|
||||
#include <unistd.h>
|
||||
|
||||
//#include <fstream>
|
||||
uint16_t Clock::leapSeconds = 0;
|
||||
MutexIF* Clock::timeMutex = NULL;
|
||||
|
||||
uint32_t Clock::getTicksPerSecond(void){
|
||||
uint32_t ticks = sysconf(_SC_CLK_TCK);
|
||||
return ticks;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
|
||||
timespec timeUnix;
|
||||
timeval timeTimeval;
|
||||
convertTimeOfDayToTimeval(time,&timeTimeval);
|
||||
timeUnix.tv_sec = timeTimeval.tv_sec;
|
||||
timeUnix.tv_nsec = (__syscall_slong_t) timeTimeval.tv_usec * 1000;
|
||||
|
||||
int status = clock_settime(CLOCK_REALTIME,&timeUnix);
|
||||
if(status!=0){
|
||||
//TODO errno
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::setClock(const timeval* time) {
|
||||
timespec timeUnix;
|
||||
timeUnix.tv_sec = time->tv_sec;
|
||||
timeUnix.tv_nsec = (__syscall_slong_t) time->tv_usec * 1000;
|
||||
int status = clock_settime(CLOCK_REALTIME,&timeUnix);
|
||||
if(status!=0){
|
||||
//TODO errno
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
||||
timespec timeUnix;
|
||||
int status = clock_gettime(CLOCK_REALTIME,&timeUnix);
|
||||
if(status!=0){
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
time->tv_sec = timeUnix.tv_sec;
|
||||
time->tv_usec = timeUnix.tv_nsec / 1000.0;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
|
||||
timeval timeVal;
|
||||
ReturnValue_t result = getClock_timeval(&timeVal);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
||||
return result;
|
||||
}
|
||||
*time = (uint64_t)timeVal.tv_sec*1e6 + timeVal.tv_usec;
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getUptime(timeval* uptime) {
|
||||
//TODO This is not posix compatible and delivers only seconds precision
|
||||
struct sysinfo sysInfo;
|
||||
int result = sysinfo(&sysInfo);
|
||||
if(result != 0){
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
uptime->tv_sec = sysInfo.uptime;
|
||||
uptime->tv_usec = 0;
|
||||
|
||||
|
||||
//Linux specific file read but more precise
|
||||
// double uptimeSeconds;
|
||||
// if(std::ifstream("/proc/uptime",std::ios::in) >> uptimeSeconds){
|
||||
// uptime->tv_sec = uptimeSeconds;
|
||||
// uptime->tv_usec = uptimeSeconds *(double) 1e6 - (uptime->tv_sec *1e6);
|
||||
// }
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
|
||||
timeval uptime;
|
||||
ReturnValue_t result = getUptime(&uptime);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
||||
return result;
|
||||
}
|
||||
*uptimeMs = uptime.tv_sec * 1e3 + uptime.tv_usec / 1e3;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
|
||||
timespec timeUnix;
|
||||
int status = clock_gettime(CLOCK_REALTIME,&timeUnix);
|
||||
if(status != 0){
|
||||
//TODO errno
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
struct tm* timeInfo;
|
||||
timeInfo = gmtime(&timeUnix.tv_sec);
|
||||
time->year = timeInfo->tm_year + 1900;
|
||||
time->month = timeInfo->tm_mon+1;
|
||||
time->day = timeInfo->tm_mday;
|
||||
time->hour = timeInfo->tm_hour;
|
||||
time->minute = timeInfo->tm_min;
|
||||
time->second = timeInfo->tm_sec;
|
||||
time->usecond = timeUnix.tv_nsec / 1000.0;
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
|
||||
timeval* to) {
|
||||
|
||||
tm fromTm;
|
||||
//Note: Fails for years before AD
|
||||
fromTm.tm_year = from->year - 1900;
|
||||
fromTm.tm_mon = from->month - 1;
|
||||
fromTm.tm_mday = from->day;
|
||||
fromTm.tm_hour = from->hour;
|
||||
fromTm.tm_min = from->minute;
|
||||
fromTm.tm_sec = from->second;
|
||||
|
||||
to->tv_sec = mktime(&fromTm);
|
||||
to->tv_usec = from->usecond;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
|
||||
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24.
|
||||
/ 3600.;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
|
||||
//SHOULDDO: works not for dates in the past (might have less leap seconds)
|
||||
if (timeMutex == NULL) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
uint16_t leapSeconds;
|
||||
ReturnValue_t result = getLeapSeconds(&leapSeconds);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
timeval leapSeconds_timeval = { 0, 0 };
|
||||
leapSeconds_timeval.tv_sec = leapSeconds;
|
||||
|
||||
//initial offset between UTC and TAI
|
||||
timeval UTCtoTAI1972 = { 10, 0 };
|
||||
|
||||
timeval TAItoTT = { 32, 184000 };
|
||||
|
||||
*tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT;
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
|
||||
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
leapSeconds = leapSeconds_;
|
||||
|
||||
result = timeMutex->unlockMutex();
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
|
||||
if(timeMutex==NULL){
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
*leapSeconds_ = leapSeconds;
|
||||
|
||||
result = timeMutex->unlockMutex();
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::checkOrCreateClockMutex(){
|
||||
if(timeMutex==NULL){
|
||||
MutexFactory* mutexFactory = MutexFactory::instance();
|
||||
if (mutexFactory == NULL) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
timeMutex = mutexFactory->createMutex();
|
||||
if (timeMutex == NULL) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
89
osal/linux/FixedTimeslotTask.cpp
Normal file
89
osal/linux/FixedTimeslotTask.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <framework/osal/linux/FixedTimeslotTask.h>
|
||||
|
||||
|
||||
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
|
||||
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN;
|
||||
|
||||
FixedTimeslotTask::FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_, uint32_t periodMs_):PosixThread(name_,priority_,stackSize_),pst(periodMs_),started(false) {
|
||||
}
|
||||
|
||||
FixedTimeslotTask::~FixedTimeslotTask() {
|
||||
|
||||
}
|
||||
|
||||
void* FixedTimeslotTask::taskEntryPoint(void* arg) {
|
||||
//The argument is re-interpreted as PollingTask.
|
||||
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(arg));
|
||||
//The task's functionality is called.
|
||||
originalTask->taskFunctionality();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ReturnValue_t FixedTimeslotTask::startTask() {
|
||||
started = true;
|
||||
createTask(&taskEntryPoint,this);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
|
||||
return PosixThread::sleep((uint64_t)ms*1000000);
|
||||
}
|
||||
|
||||
uint32_t FixedTimeslotTask::getPeriodMs() const {
|
||||
return pst.getLengthMs();
|
||||
}
|
||||
|
||||
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
|
||||
uint32_t slotTimeMs, int8_t executionStep) {
|
||||
pst.addSlot(componentId, slotTimeMs, executionStep, this);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t FixedTimeslotTask::checkSequence() const {
|
||||
return pst.checkSequence();
|
||||
}
|
||||
|
||||
void FixedTimeslotTask::taskFunctionality() {
|
||||
//Like FreeRTOS pthreads are running as soon as they are created
|
||||
if (!started) {
|
||||
suspend();
|
||||
}
|
||||
// A local iterator for the Polling Sequence Table is created to find the start time for the first entry.
|
||||
std::list<FixedSequenceSlot*>::iterator it = pst.current;
|
||||
|
||||
//The start time for the first entry is read.
|
||||
uint64_t lastWakeTime = getCurrentMonotonicTimeMs();
|
||||
uint64_t interval = pst.getIntervalToNextSlotMs();
|
||||
|
||||
|
||||
//The task's "infinite" inner loop is entered.
|
||||
while (1) {
|
||||
if (pst.slotFollowsImmediately()) {
|
||||
//Do nothing
|
||||
} else {
|
||||
//The interval for the next polling slot is selected.
|
||||
interval = this->pst.getIntervalToPreviousSlotMs();
|
||||
//The period is checked and restarted with the new interval.
|
||||
//If the deadline was missed, the deadlineMissedFunc is called.
|
||||
if(!PosixThread::delayUntil(&lastWakeTime,interval)) {
|
||||
//No time left on timer -> we missed the deadline
|
||||
missedDeadlineCounter();
|
||||
}
|
||||
}
|
||||
//The device handler for this slot is executed and the next one is chosen.
|
||||
this->pst.executeAndAdvance();
|
||||
}
|
||||
}
|
||||
|
||||
void FixedTimeslotTask::missedDeadlineCounter() {
|
||||
FixedTimeslotTask::deadlineMissedCount++;
|
||||
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
|
||||
error << "PST missed " << FixedTimeslotTask::deadlineMissedCount
|
||||
<< " deadlines." << std::endl;
|
||||
}
|
||||
}
|
58
osal/linux/FixedTimeslotTask.h
Normal file
58
osal/linux/FixedTimeslotTask.h
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_
|
||||
#define FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_
|
||||
|
||||
#include <framework/tasks/FixedTimeslotTaskIF.h>
|
||||
#include <framework/devicehandlers/FixedSlotSequence.h>
|
||||
#include <framework/osal/linux/PosixThread.h>
|
||||
#include <pthread.h>
|
||||
|
||||
class FixedTimeslotTask: public FixedTimeslotTaskIF, public PosixThread {
|
||||
public:
|
||||
FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_, uint32_t periodMs_);
|
||||
virtual ~FixedTimeslotTask();
|
||||
|
||||
virtual ReturnValue_t startTask();
|
||||
|
||||
virtual ReturnValue_t sleepFor(uint32_t ms);
|
||||
|
||||
virtual uint32_t getPeriodMs() const;
|
||||
|
||||
virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep);
|
||||
virtual ReturnValue_t checkSequence() const;
|
||||
|
||||
/**
|
||||
* This static function can be used as #deadlineMissedFunc.
|
||||
* It counts missedDeadlines and prints the number of missed deadlines every 10th time.
|
||||
*/
|
||||
static void missedDeadlineCounter();
|
||||
|
||||
/**
|
||||
* A helper variable to count missed deadlines.
|
||||
*/
|
||||
static uint32_t deadlineMissedCount;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief This function holds the main functionality of the thread.
|
||||
*
|
||||
*
|
||||
* @details Holding the main functionality of the task, this method is most important.
|
||||
* It links the functionalities provided by FixedSlotSequence with the OS's System Calls
|
||||
* to keep the timing of the periods.
|
||||
*/
|
||||
virtual void taskFunctionality();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief This is the entry point in a new thread.
|
||||
*
|
||||
* @details This method, that is the entry point in the new thread and calls taskFunctionality of the child class.
|
||||
* Needs a valid pointer to the derived class.
|
||||
*/
|
||||
static void* taskEntryPoint(void* arg);
|
||||
FixedSlotSequence pst;
|
||||
|
||||
bool started;
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */
|
14
osal/linux/InternalErrorCodes.cpp
Normal file
14
osal/linux/InternalErrorCodes.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include <framework/osal/InternalErrorCodes.h>
|
||||
|
||||
ReturnValue_t InternalErrorCodes::translate(uint8_t code) {
|
||||
//TODO This class can be removed
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
InternalErrorCodes::InternalErrorCodes() {
|
||||
}
|
||||
|
||||
InternalErrorCodes::~InternalErrorCodes() {
|
||||
|
||||
}
|
||||
|
258
osal/linux/MessageQueue.cpp
Normal file
258
osal/linux/MessageQueue.cpp
Normal file
@ -0,0 +1,258 @@
|
||||
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||
#include <fcntl.h> /* For O_* constants */
|
||||
#include <sys/stat.h> /* For mode constants */
|
||||
#include <mqueue.h>
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
#include <framework/osal/linux/MessageQueue.h>
|
||||
|
||||
|
||||
MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) :
|
||||
id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(
|
||||
NULL) {
|
||||
//debug << "MessageQueue::MessageQueue: Creating a queue" << std::endl;
|
||||
mq_attr attributes;
|
||||
this->id = 0;
|
||||
//Set attributes
|
||||
attributes.mq_curmsgs = 0;
|
||||
attributes.mq_maxmsg = message_depth;
|
||||
attributes.mq_msgsize = max_message_size;
|
||||
attributes.mq_flags = 0; //Flags are ignored on Linux during mq_open
|
||||
|
||||
//Set the name of the queue
|
||||
sprintf(name, "/Q%u\n", queueCounter++);
|
||||
|
||||
//Create a nonblocking queue if the name is available (the queue is Read and writable for the owner as well as the group)
|
||||
mqd_t tempId = mq_open(name, O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL,
|
||||
S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP | S_IROTH | S_IWOTH, &attributes);
|
||||
if (tempId == -1) {
|
||||
//An error occured during open
|
||||
//We need to distinguish if it is caused by an already created queue
|
||||
if (errno == EEXIST) {
|
||||
//There's another queue with the same name
|
||||
//We unlink the other queue
|
||||
int status = mq_unlink(name);
|
||||
if (status != 0) {
|
||||
error << "mq_unlink Failed with status: " << strerror(errno)
|
||||
<< std::endl;
|
||||
} else {
|
||||
//Successful unlinking, try to open again
|
||||
mqd_t tempId = mq_open(name,
|
||||
O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL,
|
||||
S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP, &attributes);
|
||||
if (tempId != -1) {
|
||||
//Successful mq_open
|
||||
this->id = tempId;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
//Failed either the first time or the second time
|
||||
error << "MessageQueue::MessageQueue: Creating Queue " << std::hex
|
||||
<< name << std::dec << " failed with status: "
|
||||
<< strerror(errno) << std::endl;
|
||||
} else {
|
||||
//Successful mq_open call
|
||||
this->id = tempId;
|
||||
}
|
||||
}
|
||||
|
||||
MessageQueue::~MessageQueue() {
|
||||
int status = mq_close(this->id);
|
||||
if(status != 0){
|
||||
error << "MessageQueue::Destructor: mq_close Failed with status: " << strerror(errno) <<std::endl;
|
||||
}
|
||||
status = mq_unlink(name);
|
||||
if(status != 0){
|
||||
error << "MessageQueue::Destructor: mq_unlink Failed with status: " << strerror(errno) <<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
|
||||
MessageQueueMessage* message, bool ignoreFault) {
|
||||
return sendMessageFrom(sendTo, message, this->getId(), false);
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) {
|
||||
return sendToDefaultFrom(message, this->getId());
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) {
|
||||
if (this->lastPartner != 0) {
|
||||
return sendMessageFrom(this->lastPartner, message, this->getId());
|
||||
} else {
|
||||
//TODO: Good returnCode
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message,
|
||||
MessageQueueId_t* receivedFrom) {
|
||||
ReturnValue_t status = this->receiveMessage(message);
|
||||
*receivedFrom = this->lastPartner;
|
||||
return status;
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) {
|
||||
unsigned int messagePriority = 0;
|
||||
int status = mq_receive(id,reinterpret_cast<char*>(message->getBuffer()),message->MAX_MESSAGE_SIZE,&messagePriority);
|
||||
if (status > 0) {
|
||||
this->lastPartner = message->getSender();
|
||||
//Check size of incoming message.
|
||||
if (message->messageSize < message->getMinimumMessageSize()) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}else if(status==0){
|
||||
//Success but no message received
|
||||
return MessageQueueIF::EMPTY;
|
||||
} else {
|
||||
//No message was received. Keep lastPartner anyway, I might send something later.
|
||||
//But still, delete packet content.
|
||||
memset(message->getData(), 0, message->MAX_DATA_SIZE);
|
||||
switch(errno){
|
||||
case EAGAIN:
|
||||
//O_NONBLOCK or MQ_NONBLOCK was set and there are no messages currently on the specified queue.
|
||||
return MessageQueueIF::EMPTY;
|
||||
case EBADF:
|
||||
//mqdes doesn't represent a valid queue open for reading.
|
||||
error << "MessageQueue::receive: configuration error " << strerror(errno) << std::endl;
|
||||
/*NO BREAK*/
|
||||
case EINVAL:
|
||||
/*
|
||||
* This value indicates one of the following:
|
||||
* * The pointer to the buffer for storing the received message, msg_ptr, is NULL.
|
||||
* * The number of bytes requested, msg_len is less than zero.
|
||||
* * msg_len is anything other than the mq_msgsize of the specified queue, and the QNX extended option MQ_READBUF_DYNAMIC hasn't been set in the queue's mq_flags.
|
||||
*/
|
||||
error << "MessageQueue::receive: configuration error " << strerror(errno) << std::endl;
|
||||
/*NO BREAK*/
|
||||
case EMSGSIZE:
|
||||
/*
|
||||
* This value indicates one of the following:
|
||||
* * the QNX extended option MQ_READBUF_DYNAMIC hasn't been set, and the given msg_len is shorter than the mq_msgsize for the given queue.
|
||||
* * the extended option MQ_READBUF_DYNAMIC has been set, but the given msg_len is too short for the message that would have been received.
|
||||
*/
|
||||
error << "MessageQueue::receive: configuration error " << strerror(errno) << std::endl;
|
||||
/*NO BREAK*/
|
||||
case EINTR:
|
||||
//The operation was interrupted by a signal.
|
||||
default:
|
||||
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
MessageQueueId_t MessageQueue::getLastPartner() const {
|
||||
return this->lastPartner;
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||
mq_attr attrib;
|
||||
int status = mq_getattr(id,&attrib);
|
||||
if(status != 0){
|
||||
switch(errno){
|
||||
case EBADF:
|
||||
//mqdes doesn't represent a valid message queue.
|
||||
error << "MessageQueue::flush configuration error, called flush with an invalid queue ID" << std::endl;
|
||||
/*NO BREAK*/
|
||||
case EINVAL:
|
||||
//mq_attr is NULL
|
||||
default:
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
*count = attrib.mq_curmsgs;
|
||||
attrib.mq_curmsgs = 0;
|
||||
status = mq_setattr(id,&attrib,NULL);
|
||||
if(status != 0){
|
||||
switch(errno){
|
||||
case EBADF:
|
||||
//mqdes doesn't represent a valid message queue.
|
||||
error << "MessageQueue::flush configuration error, called flush with an invalid queue ID" << std::endl;
|
||||
/*NO BREAK*/
|
||||
case EINVAL:
|
||||
/*
|
||||
* This value indicates one of the following:
|
||||
* * mq_attr is NULL.
|
||||
* * MQ_MULT_NOTIFY had been set for this queue, and the given mq_flags includes a 0 in the MQ_MULT_NOTIFY bit. Once MQ_MULT_NOTIFY has been turned on, it may never be turned off.
|
||||
*
|
||||
*/
|
||||
default:
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
MessageQueueId_t MessageQueue::getId() const {
|
||||
return this->id;
|
||||
}
|
||||
|
||||
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
|
||||
this->defaultDestination = defaultDestination;
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
|
||||
MessageQueueMessage* message, MessageQueueId_t sentFrom,
|
||||
bool ignoreFault) {
|
||||
|
||||
message->setSender(sentFrom);
|
||||
int result = mq_send(sendTo,
|
||||
reinterpret_cast<const char*>(message->getBuffer()), message->messageSize,0);
|
||||
|
||||
//TODO: Check if we're in ISR.
|
||||
if (result != 0 && !ignoreFault) {
|
||||
if (internalErrorReporter == NULL) {
|
||||
internalErrorReporter = objectManager->get<InternalErrorReporterIF>(
|
||||
objects::INTERNAL_ERROR_REPORTER);
|
||||
}
|
||||
if (internalErrorReporter != NULL) {
|
||||
internalErrorReporter->queueMessageNotSent();
|
||||
}
|
||||
switch(errno){
|
||||
case EAGAIN:
|
||||
//The O_NONBLOCK flag was set when opening the queue, or the MQ_NONBLOCK flag was set in its attributes, and the specified queue is full.
|
||||
return MessageQueueIF::FULL;
|
||||
case EBADF:
|
||||
//mq_des doesn't represent a valid message queue descriptor, or mq_des wasn't opened for writing.
|
||||
error << "MessageQueue::sendMessage: Configuration error " << strerror(errno) << " in mq_send mqSendTo: " << sendTo << " sent from " << sentFrom << std::endl;
|
||||
/*NO BREAK*/
|
||||
case EINTR:
|
||||
//The call was interrupted by a signal.
|
||||
case EINVAL:
|
||||
/*
|
||||
* This value indicates one of the following:
|
||||
* * msg_ptr is NULL.
|
||||
* * msg_len is negative.
|
||||
* * msg_prio is greater than MQ_PRIO_MAX.
|
||||
* * msg_prio is less than 0.
|
||||
* * MQ_PRIO_RESTRICT is set in the mq_attr of mq_des, and msg_prio is greater than the priority of the calling process.
|
||||
* */
|
||||
error << "MessageQueue::sendMessage: Configuration error " << strerror(errno) << " in mq_send" << std::endl;
|
||||
/*NO BREAK*/
|
||||
case EMSGSIZE:
|
||||
//The msg_len is greater than the msgsize associated with the specified queue.
|
||||
default:
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message,
|
||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
||||
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
|
||||
}
|
||||
|
||||
MessageQueueId_t MessageQueue::getDefaultDestination() const {
|
||||
return this->defaultDestination;
|
||||
}
|
||||
|
||||
bool MessageQueue::isDefaultDestinationSet() const {
|
||||
return (defaultDestination != NO_QUEUE);
|
||||
}
|
||||
|
||||
uint16_t MessageQueue::queueCounter = 0;
|
169
osal/linux/MessageQueue.h
Normal file
169
osal/linux/MessageQueue.h
Normal file
@ -0,0 +1,169 @@
|
||||
#ifndef MESSAGEQUEUE_H_
|
||||
#define MESSAGEQUEUE_H_
|
||||
|
||||
#include <framework/internalError/InternalErrorReporterIF.h>
|
||||
#include <framework/ipc/MessageQueueIF.h>
|
||||
#include <framework/ipc/MessageQueueMessage.h>
|
||||
/**
|
||||
* @brief This class manages sending and receiving of message queue messages.
|
||||
*
|
||||
* @details Message queues are used to pass asynchronous messages between processes.
|
||||
* They work like post boxes, where all incoming messages are stored in FIFO
|
||||
* order. This class creates a new receiving queue and provides methods to fetch
|
||||
* received messages. Being a child of MessageQueueSender, this class also provides
|
||||
* methods to send a message to a user-defined or a default destination. In addition
|
||||
* it also provides a reply method to answer to the queue it received its last message
|
||||
* from.
|
||||
* The MessageQueue should be used as "post box" for a single owning object. So all
|
||||
* message queue communication is "n-to-one".
|
||||
* For creating the queue, as well as sending and receiving messages, the class makes
|
||||
* use of the operating system calls provided.
|
||||
* \ingroup message_queue
|
||||
*/
|
||||
class MessageQueue : public MessageQueueIF {
|
||||
public:
|
||||
/**
|
||||
* @brief The constructor initializes and configures the message queue.
|
||||
* @details By making use of the according operating system call, a message queue is created
|
||||
* and initialized. The message depth - the maximum number of messages to be
|
||||
* buffered - may be set with the help of a parameter, whereas the message size is
|
||||
* automatically set to the maximum message queue message size. The operating system
|
||||
* sets the message queue id, or i case of failure, it is set to zero.
|
||||
* @param message_depth The number of messages to be buffered before passing an error to the
|
||||
* sender. Default is three.
|
||||
* @param max_message_size With this parameter, the maximum message size can be adjusted.
|
||||
* This should be left default.
|
||||
*/
|
||||
MessageQueue( size_t message_depth = 3, size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE );
|
||||
/**
|
||||
* @brief The destructor deletes the formerly created message queue.
|
||||
* @details This is accomplished by using the delete call provided by the operating system.
|
||||
*/
|
||||
virtual ~MessageQueue();
|
||||
/**
|
||||
* @brief This operation sends a message to the given destination.
|
||||
* @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its
|
||||
* queue id as "sentFrom" parameter.
|
||||
* @param sendTo This parameter specifies the message queue id of the destination message queue.
|
||||
* @param message A pointer to a previously created message, which is sent.
|
||||
* @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
|
||||
*/
|
||||
virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo,
|
||||
MessageQueueMessage* message, bool ignoreFault = false );
|
||||
/**
|
||||
* @brief This operation sends a message to the default destination.
|
||||
* @details As in the sendMessage method, this function uses the sendToDefault call of the
|
||||
* MessageQueueSender parent class and adds its queue id as "sentFrom" information.
|
||||
* @param message A pointer to a previously created message, which is sent.
|
||||
*/
|
||||
virtual ReturnValue_t sendToDefault( MessageQueueMessage* message );
|
||||
/**
|
||||
* @brief This operation sends a message to the last communication partner.
|
||||
* @details This operation simplifies answering an incoming message by using the stored
|
||||
* lastParnter information as destination. If there was no message received yet
|
||||
* (i.e. lastPartner is zero), an error code is returned.
|
||||
* @param message A pointer to a previously created message, which is sent.
|
||||
*/
|
||||
ReturnValue_t reply( MessageQueueMessage* message );
|
||||
|
||||
/**
|
||||
* @brief This function reads available messages from the message queue and returns the sender.
|
||||
* @details It works identically to the other receiveMessage call, but in addition returns the
|
||||
* sender's queue id.
|
||||
* @param message A pointer to a message in which the received data is stored.
|
||||
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
|
||||
*/
|
||||
ReturnValue_t receiveMessage(MessageQueueMessage* message,
|
||||
MessageQueueId_t *receivedFrom);
|
||||
|
||||
/**
|
||||
* @brief This function reads available messages from the message queue.
|
||||
* @details If data is available it is stored in the passed message pointer. The message's
|
||||
* original content is overwritten and the sendFrom information is stored in the
|
||||
* lastPartner attribute. Else, the lastPartner information remains untouched, the
|
||||
* message's content is cleared and the function returns immediately.
|
||||
* @param message A pointer to a message in which the received data is stored.
|
||||
*/
|
||||
ReturnValue_t receiveMessage(MessageQueueMessage* message);
|
||||
/**
|
||||
* Deletes all pending messages in the queue.
|
||||
* @param count The number of flushed messages.
|
||||
* @return RETURN_OK on success.
|
||||
*/
|
||||
ReturnValue_t flush(uint32_t* count);
|
||||
/**
|
||||
* @brief This method returns the message queue id of the last communication partner.
|
||||
*/
|
||||
MessageQueueId_t getLastPartner() const;
|
||||
/**
|
||||
* @brief This method returns the message queue id of this class's message queue.
|
||||
*/
|
||||
MessageQueueId_t getId() const;
|
||||
/**
|
||||
* \brief With the sendMessage call, a queue message is sent to a receiving queue.
|
||||
* \details This method takes the message provided, adds the sentFrom information and passes
|
||||
* it on to the destination provided with an operating system call. The OS's return
|
||||
* value is returned.
|
||||
* \param sendTo This parameter specifies the message queue id to send the message to.
|
||||
* \param message This is a pointer to a previously created message, which is sent.
|
||||
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message.
|
||||
* This variable is set to zero by default.
|
||||
* \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
|
||||
*/
|
||||
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault = false );
|
||||
/**
|
||||
* \brief The sendToDefault method sends a queue message to the default destination.
|
||||
* \details In all other aspects, it works identical to the sendMessage method.
|
||||
* \param message This is a pointer to a previously created message, which is sent.
|
||||
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message.
|
||||
* This variable is set to zero by default.
|
||||
*/
|
||||
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false );
|
||||
/**
|
||||
* \brief This method is a simple setter for the default destination.
|
||||
*/
|
||||
void setDefaultDestination(MessageQueueId_t defaultDestination);
|
||||
/**
|
||||
* \brief This method is a simple getter for the default destination.
|
||||
*/
|
||||
MessageQueueId_t getDefaultDestination() const;
|
||||
|
||||
bool isDefaultDestinationSet() const;
|
||||
private:
|
||||
/**
|
||||
* @brief The class stores the queue id it got assigned from the operating system in this attribute.
|
||||
* If initialization fails, the queue id is set to zero.
|
||||
*/
|
||||
MessageQueueId_t id;
|
||||
/**
|
||||
* @brief In this attribute, the queue id of the last communication partner is stored
|
||||
* to allow for replying.
|
||||
*/
|
||||
MessageQueueId_t lastPartner;
|
||||
/**
|
||||
* @brief The message queue's name -a user specific information for the operating system- is
|
||||
* generated automatically with the help of this static counter.
|
||||
*/
|
||||
/**
|
||||
* \brief This attribute stores a default destination to send messages to.
|
||||
* \details It is stored to simplify sending to always-the-same receiver. The attribute may
|
||||
* be set in the constructor or by a setter call to setDefaultDestination.
|
||||
*/
|
||||
MessageQueueId_t defaultDestination;
|
||||
|
||||
/**
|
||||
* \brief This attribute stores a reference to the internal error reporter for reporting full queues.
|
||||
* \details In the event of a full destination queue, the reporter will be notified. The reference is set
|
||||
* by lazy loading
|
||||
*/
|
||||
InternalErrorReporterIF *internalErrorReporter;
|
||||
|
||||
/**
|
||||
* The name of the message queue, stored for unlinking
|
||||
*/
|
||||
char name[5];
|
||||
|
||||
static uint16_t queueCounter;
|
||||
};
|
||||
|
||||
#endif /* MESSAGEQUEUE_H_ */
|
98
osal/linux/Mutex.cpp
Normal file
98
osal/linux/Mutex.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
#include <framework/osal/linux/Mutex.h>
|
||||
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||
#include <framework/timemanager/Clock.h>
|
||||
|
||||
const uint32_t MutexIF::NO_TIMEOUT = 0;
|
||||
uint8_t Mutex::count = 0;
|
||||
|
||||
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
|
||||
Mutex::Mutex() {
|
||||
pthread_mutexattr_t mutexAttr;
|
||||
int status = pthread_mutexattr_init(&mutexAttr);
|
||||
if (status != 0) {
|
||||
error << "Mutex: Attribute init failed with: " << strerror(status) << std::endl;
|
||||
}
|
||||
status = pthread_mutexattr_setprotocol(&mutexAttr, PTHREAD_PRIO_INHERIT);
|
||||
if (status != 0) {
|
||||
error << "Mutex: Attribute set PRIO_INHERIT failed with: " << strerror(status)
|
||||
<< std::endl;
|
||||
}
|
||||
status = pthread_mutex_init(&mutex, &mutexAttr);
|
||||
if (status != 0) {
|
||||
error << "Mutex: creation with name, id " << mutex.__data.__count
|
||||
<< ", " << " failed with " << strerror(status) << std::endl;
|
||||
}
|
||||
//After a mutex attributes object has been used to initialize one or more mutexes, any function affecting the attributes object (including destruction) shall not affect any previously initialized mutexes.
|
||||
status = pthread_mutexattr_destroy(&mutexAttr);
|
||||
if (status != 0) {
|
||||
error << "Mutex: Attribute destroy failed with " << strerror(status) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
//No Status check yet
|
||||
pthread_mutex_destroy(&mutex);
|
||||
}
|
||||
|
||||
ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) {
|
||||
int status = 0;
|
||||
if (timeoutMs != MutexIF::NO_TIMEOUT) {
|
||||
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;
|
||||
status = pthread_mutex_timedlock(&mutex, &timeOut);
|
||||
} else {
|
||||
status = pthread_mutex_lock(&mutex);
|
||||
}
|
||||
switch (status) {
|
||||
case EINVAL:
|
||||
//The mutex was created with the protocol attribute having the value PTHREAD_PRIO_PROTECT and the calling thread's priority is higher than the mutex's current priority ceiling.
|
||||
return WRONG_ATTRIBUTE_SETTING;
|
||||
//The process or thread would have blocked, and the abs_timeout parameter specified a nanoseconds field value less than zero or greater than or equal to 1000 million.
|
||||
//The value specified by mutex does not refer to an initialized mutex object.
|
||||
//return MUTEX_NOT_FOUND;
|
||||
case EBUSY:
|
||||
//The mutex could not be acquired because it was already locked.
|
||||
return MUTEX_ALREADY_LOCKED;
|
||||
case ETIMEDOUT:
|
||||
//The mutex could not be locked before the specified timeout expired.
|
||||
return MUTEX_TIMEOUT;
|
||||
case EAGAIN:
|
||||
//The mutex could not be acquired because the maximum number of recursive locks for mutex has been exceeded.
|
||||
return MUTEX_MAX_LOCKS;
|
||||
case EDEADLK:
|
||||
//A deadlock condition was detected or the current thread already owns the mutex.
|
||||
return CURR_THREAD_ALREADY_OWNS_MUTEX;
|
||||
case 0:
|
||||
//Success
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
default:
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
};
|
||||
}
|
||||
|
||||
ReturnValue_t Mutex::unlockMutex() {
|
||||
int status = pthread_mutex_unlock(&mutex);
|
||||
switch (status) {
|
||||
case EINVAL:
|
||||
//The value specified by mutex does not refer to an initialized mutex object.
|
||||
return MUTEX_NOT_FOUND;
|
||||
case EAGAIN:
|
||||
//The mutex could not be acquired because the maximum number of recursive locks for mutex has been exceeded.
|
||||
return MUTEX_MAX_LOCKS;
|
||||
case EPERM:
|
||||
//The current thread does not own the mutex.
|
||||
return CURR_THREAD_DOES_NOT_OWN_MUTEX;
|
||||
case 0:
|
||||
//Success
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
default:
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
};
|
||||
}
|
18
osal/linux/Mutex.h
Normal file
18
osal/linux/Mutex.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef OS_RTEMS_MUTEX_H_
|
||||
#define OS_RTEMS_MUTEX_H_
|
||||
|
||||
#include <framework/ipc/MutexIF.h>
|
||||
#include <pthread.h>
|
||||
|
||||
class Mutex : public MutexIF {
|
||||
public:
|
||||
Mutex();
|
||||
virtual ~Mutex();
|
||||
virtual ReturnValue_t lockMutex(uint32_t timeoutMs);
|
||||
virtual ReturnValue_t unlockMutex();
|
||||
private:
|
||||
pthread_mutex_t mutex;
|
||||
static uint8_t count;
|
||||
};
|
||||
|
||||
#endif /* OS_RTEMS_MUTEX_H_ */
|
23
osal/linux/MutexFactory.cpp
Normal file
23
osal/linux/MutexFactory.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include <framework/ipc/MutexFactory.h>
|
||||
#include <framework/osal/linux/Mutex.h>
|
||||
|
||||
//TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
|
||||
MutexFactory* MutexFactory::factoryInstance = new MutexFactory();
|
||||
|
||||
MutexFactory::MutexFactory() {
|
||||
}
|
||||
|
||||
MutexFactory::~MutexFactory() {
|
||||
}
|
||||
|
||||
MutexFactory* MutexFactory::instance() {
|
||||
return MutexFactory::factoryInstance;
|
||||
}
|
||||
|
||||
MutexIF* MutexFactory::createMutex() {
|
||||
return new Mutex();
|
||||
}
|
||||
|
||||
void MutexFactory::deleteMutex(MutexIF* mutex) {
|
||||
delete mutex;
|
||||
}
|
72
osal/linux/PeriodicPosixTask.cpp
Normal file
72
osal/linux/PeriodicPosixTask.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
#include <framework/tasks/ExecutableObjectIF.h>
|
||||
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||
#include <errno.h>
|
||||
#include <framework/osal/linux/PeriodicPosixTask.h>
|
||||
|
||||
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()):PosixThread(name_,priority_,stackSize_),objectList(),started(false),periodMs(period_),deadlineMissedFunc(
|
||||
deadlineMissedFunc_) {
|
||||
|
||||
}
|
||||
|
||||
PeriodicPosixTask::~PeriodicPosixTask() {
|
||||
//Not Implemented
|
||||
}
|
||||
|
||||
void* PeriodicPosixTask::taskEntryPoint(void* arg) {
|
||||
//The argument is re-interpreted as PollingTask.
|
||||
PeriodicPosixTask *originalTask(reinterpret_cast<PeriodicPosixTask*>(arg));
|
||||
//The task's functionality is called.
|
||||
originalTask->taskFunctionality();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
|
||||
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
|
||||
object);
|
||||
if (newObject == NULL) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
objectList.push_back(newObject);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) {
|
||||
return PosixThread::sleep((uint64_t)ms*1000000);
|
||||
}
|
||||
|
||||
|
||||
ReturnValue_t PeriodicPosixTask::startTask(void){
|
||||
started = true;
|
||||
createTask(&taskEntryPoint,this);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
void PeriodicPosixTask::taskFunctionality(void){
|
||||
if(!started){
|
||||
suspend();
|
||||
}
|
||||
uint64_t lastWakeTime = getCurrentMonotonicTimeMs();
|
||||
//The task's "infinite" inner loop is entered.
|
||||
while (1) {
|
||||
for (ObjectList::iterator it = objectList.begin();
|
||||
it != objectList.end(); ++it) {
|
||||
(*it)->performOperation();
|
||||
}
|
||||
if(!PosixThread::delayUntil(&lastWakeTime,periodMs)){
|
||||
char name[20] = {0};
|
||||
int status = pthread_getname_np(pthread_self(),name,sizeof(name));
|
||||
if(status==0){
|
||||
error << "ObjectTask: " << name << " Deadline missed." << std::endl;
|
||||
}else{
|
||||
error << "ObjectTask: X Deadline missed. " << status << std::endl;
|
||||
}
|
||||
if (this->deadlineMissedFunc != NULL) {
|
||||
this->deadlineMissedFunc();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t PeriodicPosixTask::getPeriodMs() const {
|
||||
return periodMs;
|
||||
}
|
76
osal/linux/PeriodicPosixTask.h
Normal file
76
osal/linux/PeriodicPosixTask.h
Normal file
@ -0,0 +1,76 @@
|
||||
#ifndef FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_
|
||||
#define FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_
|
||||
|
||||
#include <framework/tasks/PeriodicTaskIF.h>
|
||||
#include <framework/objectmanager/ObjectManagerIF.h>
|
||||
#include <framework/osal/linux/PosixThread.h>
|
||||
#include <framework/tasks/ExecutableObjectIF.h>
|
||||
#include <vector>
|
||||
|
||||
class PeriodicPosixTask: public PosixThread, public PeriodicTaskIF {
|
||||
public:
|
||||
PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, uint32_t period_, void(*deadlineMissedFunc_)());
|
||||
virtual ~PeriodicPosixTask();
|
||||
/**
|
||||
* @brief The method to start the task.
|
||||
* @details The method starts the task with the respective system call.
|
||||
* Entry point is the taskEntryPoint method described below.
|
||||
* The address of the task object is passed as an argument
|
||||
* to the system call.
|
||||
*/
|
||||
ReturnValue_t startTask(void);
|
||||
/**
|
||||
* Adds an object to the list of objects to be executed.
|
||||
* The objects are executed in the order added.
|
||||
* @param object Id of the object to add.
|
||||
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
|
||||
*/
|
||||
ReturnValue_t addComponent(object_id_t object);
|
||||
|
||||
uint32_t getPeriodMs() const;
|
||||
|
||||
ReturnValue_t sleepFor(uint32_t ms);
|
||||
|
||||
private:
|
||||
typedef std::vector<ExecutableObjectIF*> ObjectList; //!< Typedef for the List of objects.
|
||||
/**
|
||||
* @brief This attribute holds a list of objects to be executed.
|
||||
*/
|
||||
ObjectList objectList;
|
||||
|
||||
/**
|
||||
* @brief Flag to indicate that the task was started and is allowed to run
|
||||
*/
|
||||
bool started;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Period of the task in milliseconds
|
||||
*/
|
||||
uint32_t periodMs;
|
||||
/**
|
||||
* @brief The function containing the actual functionality of the task.
|
||||
* @details The method sets and starts
|
||||
* the task's period, then enters a loop that is repeated indefinitely. Within the loop, all performOperation methods of the added
|
||||
* objects are called. Afterwards the task will be blocked until the next period.
|
||||
* On missing the deadline, the deadlineMissedFunction is executed.
|
||||
*/
|
||||
virtual void taskFunctionality(void);
|
||||
/**
|
||||
* @brief This is the entry point in a new thread.
|
||||
*
|
||||
* @details This method, that is the entry point in the new thread and calls taskFunctionality of the child class.
|
||||
* Needs a valid pointer to the derived class.
|
||||
*/
|
||||
static void* taskEntryPoint(void* arg);
|
||||
/**
|
||||
* @brief The pointer to the deadline-missed function.
|
||||
* @details This pointer stores the function that is executed if the task's deadline is missed.
|
||||
* So, each may react individually on a timing failure. The pointer may be NULL,
|
||||
* then nothing happens on missing the deadline. The deadline is equal to the next execution
|
||||
* of the periodic task.
|
||||
*/
|
||||
void (*deadlineMissedFunc)();
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ */
|
188
osal/linux/PosixThread.cpp
Normal file
188
osal/linux/PosixThread.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
#include <framework/osal/linux/PosixThread.h>
|
||||
|
||||
|
||||
PosixThread::~PosixThread() {
|
||||
//No deletion and no free of Stack Pointer
|
||||
}
|
||||
|
||||
ReturnValue_t PosixThread::sleep(uint64_t ns) {
|
||||
//TODO sleep might be better with timer instead of sleep()
|
||||
timespec time;
|
||||
time.tv_sec = ns/1000000000;
|
||||
time.tv_nsec = ns - time.tv_sec*1e9;
|
||||
|
||||
//Remaining Time is not set here
|
||||
int status = nanosleep(&time,NULL);
|
||||
if(status != 0){
|
||||
switch(errno){
|
||||
case EINTR:
|
||||
//The nanosleep() function was interrupted by a signal.
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
case EINVAL:
|
||||
//The rqtp argument specified a nanosecond value less than zero or greater than or equal to 1000 million.
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
default:
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
void PosixThread::suspend() {
|
||||
//Wait for SIGUSR1
|
||||
int caughtSig = 0;
|
||||
sigset_t waitSignal;
|
||||
sigemptyset(&waitSignal);
|
||||
sigaddset(&waitSignal, SIGUSR1);
|
||||
sigwait(&waitSignal, &caughtSig);
|
||||
if (caughtSig != SIGUSR1) {
|
||||
error << "FixedTimeslotTask: Unknown Signal received: " << caughtSig
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void PosixThread::resume(){
|
||||
/* Signal the thread to start. Makes sense to call kill to start or? ;)
|
||||
*
|
||||
* According to Posix raise(signal) will call pthread_kill(pthread_self(), sig),
|
||||
* but as the call must be done from the thread itsself this is not possible here
|
||||
*/
|
||||
pthread_kill(thread,SIGUSR1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool PosixThread::delayUntil(uint64_t* const prevoiusWakeTime_ms,
|
||||
const uint64_t delayTime_ms) {
|
||||
uint64_t nextTimeToWake_ms;
|
||||
bool shouldDelay = false;
|
||||
//Get current Time
|
||||
const uint64_t currentTime_ms = getCurrentMonotonicTimeMs();
|
||||
/* Generate the tick time at which the task wants to wake. */
|
||||
nextTimeToWake_ms = (*prevoiusWakeTime_ms) + delayTime_ms;
|
||||
|
||||
if (currentTime_ms < *prevoiusWakeTime_ms) {
|
||||
/* The tick count has overflowed since this function was
|
||||
lasted called. In this case the only time we should ever
|
||||
actually delay is if the wake time has also overflowed,
|
||||
and the wake time is greater than the tick time. When this
|
||||
is the case it is as if neither time had overflowed. */
|
||||
if ((nextTimeToWake_ms < *prevoiusWakeTime_ms)
|
||||
&& (nextTimeToWake_ms > currentTime_ms)) {
|
||||
shouldDelay = true;
|
||||
}
|
||||
} else {
|
||||
/* The tick time has not overflowed. In this case we will
|
||||
delay if either the wake time has overflowed, and/or the
|
||||
tick time is less than the wake time. */
|
||||
if ((nextTimeToWake_ms < *prevoiusWakeTime_ms)
|
||||
|| (nextTimeToWake_ms > currentTime_ms)) {
|
||||
shouldDelay = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the wake time ready for the next call. */
|
||||
|
||||
(*prevoiusWakeTime_ms) = nextTimeToWake_ms;
|
||||
|
||||
if (shouldDelay) {
|
||||
uint64_t sleepTime = nextTimeToWake_ms - currentTime_ms;
|
||||
PosixThread::sleep(sleepTime * 1000000ull);
|
||||
return true;
|
||||
}
|
||||
//We are shifting the time in case the deadline was missed like rtems
|
||||
(*prevoiusWakeTime_ms) = currentTime_ms;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
uint64_t PosixThread::getCurrentMonotonicTimeMs(){
|
||||
timespec timeNow;
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &timeNow);
|
||||
uint64_t currentTime_ms = (uint64_t) timeNow.tv_sec * 1000
|
||||
+ timeNow.tv_nsec / 1000000;
|
||||
|
||||
return currentTime_ms;
|
||||
}
|
||||
|
||||
PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_):thread(0),priority(priority_),stackSize(stackSize_) {
|
||||
strcpy(name,name_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
|
||||
debug << "PosixThread::createTask" << std::endl;
|
||||
/*
|
||||
* The attr argument points to a pthread_attr_t structure whose contents
|
||||
are used at thread creation time to determine attributes for the new
|
||||
thread; this structure is initialized using pthread_attr_init(3) and
|
||||
related functions. If attr is NULL, then the thread is created with
|
||||
default attributes.
|
||||
*/
|
||||
pthread_attr_t attributes;
|
||||
int status = pthread_attr_init(&attributes);
|
||||
if(status != 0){
|
||||
error << "Posix Thread attribute init failed with: " << strerror(status) << std::endl;
|
||||
}
|
||||
void* sp;
|
||||
status = posix_memalign(&sp, sysconf(_SC_PAGESIZE), stackSize);
|
||||
if(status != 0){
|
||||
error << "Posix Thread stack init failed with: " << strerror(status) << std::endl;
|
||||
}
|
||||
|
||||
status = pthread_attr_setstack(&attributes, sp, stackSize);
|
||||
if(status != 0){
|
||||
error << "Posix Thread attribute setStack failed with: " << strerror(status) << std::endl;
|
||||
}
|
||||
|
||||
status = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED);
|
||||
if(status != 0){
|
||||
error << "Posix Thread attribute setinheritsched failed with: " << strerror(status) << std::endl;
|
||||
}
|
||||
|
||||
//TODO FIFO -> This needs root privileges for the process
|
||||
status = pthread_attr_setschedpolicy(&attributes,SCHED_FIFO);
|
||||
if(status != 0){
|
||||
error << "Posix Thread attribute schedule policy failed with: " << strerror(status) << std::endl;
|
||||
}
|
||||
|
||||
sched_param scheduleParams;
|
||||
scheduleParams.__sched_priority = priority;
|
||||
status = pthread_attr_setschedparam(&attributes, &scheduleParams);
|
||||
if(status != 0){
|
||||
error << "Posix Thread attribute schedule params failed with: " << strerror(status) << std::endl;
|
||||
}
|
||||
|
||||
//Set Signal Mask for suspend until startTask is called
|
||||
sigset_t waitSignal;
|
||||
sigemptyset(&waitSignal);
|
||||
sigaddset(&waitSignal, SIGUSR1);
|
||||
status = pthread_sigmask(SIG_BLOCK, &waitSignal, NULL);
|
||||
if(status != 0){
|
||||
error << "Posix Thread sigmask failed failed with: " << strerror(status) << " errno: " << strerror(errno) << std::endl;
|
||||
}
|
||||
|
||||
|
||||
status = pthread_create(&thread,&attributes,fnc_,arg_);
|
||||
if(status != 0){
|
||||
error << "Posix Thread create failed with: " << strerror(status) << std::endl;
|
||||
}
|
||||
|
||||
status = pthread_setname_np(thread,name);
|
||||
if(status != 0){
|
||||
error << "Posix Thread setname failed with: " << strerror(status) << std::endl;
|
||||
}
|
||||
|
||||
status = pthread_attr_destroy(&attributes);
|
||||
if(status!=0){
|
||||
error << "Posix Thread attribute destroy failed with: " << strerror(status) << std::endl;
|
||||
}
|
||||
}
|
74
osal/linux/PosixThread.h
Normal file
74
osal/linux/PosixThread.h
Normal file
@ -0,0 +1,74 @@
|
||||
#ifndef FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_
|
||||
#define FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <framework/returnvalues/HasReturnvaluesIF.h>
|
||||
|
||||
class PosixThread {
|
||||
public:
|
||||
PosixThread(const char* name_, int priority_, size_t stackSize_);
|
||||
virtual ~PosixThread();
|
||||
/**
|
||||
* Set the Thread to sleep state
|
||||
* @param ns Nanosecond sleep time
|
||||
* @return Returns Failed if sleep fails
|
||||
*/
|
||||
static ReturnValue_t sleep(uint64_t ns);
|
||||
/**
|
||||
* @brief Function to suspend the task until SIGUSR1 was received
|
||||
*
|
||||
* @details Will be called in the beginning to suspend execution until startTask() is called explicitly.
|
||||
*/
|
||||
void suspend();
|
||||
|
||||
/**
|
||||
* @brief Function to allow a other thread to start the thread again from suspend state
|
||||
*
|
||||
* @details Restarts the Thread after suspend call
|
||||
*/
|
||||
void resume();
|
||||
|
||||
|
||||
/**
|
||||
* Delay function similar to FreeRtos delayUntil function
|
||||
*
|
||||
* @param prevoiusWakeTime_ms Needs the previous wake time and returns the next wakeup time
|
||||
* @param delayTime_ms Time period to delay
|
||||
*
|
||||
* @return False If deadline was missed; True if task was delayed
|
||||
*/
|
||||
static bool delayUntil(uint64_t* const prevoiusWakeTime_ms, const uint64_t delayTime_ms);
|
||||
|
||||
/**
|
||||
* Returns the current time in milliseconds from CLOCK_MONOTONIC
|
||||
*
|
||||
* @return current time in milliseconds from CLOCK_MONOTONIC
|
||||
*/
|
||||
static uint64_t getCurrentMonotonicTimeMs();
|
||||
|
||||
protected:
|
||||
pthread_t thread;
|
||||
|
||||
/**
|
||||
* @brief Function that has to be called by derived class because the derived class pointer has to be valid as argument
|
||||
* @details This function creates a pthread with the given parameters. As the function requires a pointer to the derived object
|
||||
* it has to be called after the this pointer of the derived object is valid. Sets the taskEntryPoint as
|
||||
* function to be called by new a thread.
|
||||
* @param name_ Name of the task
|
||||
* @param priority_ Priority of the task according to POSIX
|
||||
* @param stackSize_ Size of the stack attached to that task
|
||||
* @param arg_ argument of the taskEntryPoint function, needs to be this pointer of derived class
|
||||
*/
|
||||
void createTask(void* (*fnc_)(void*),void* arg_);
|
||||
|
||||
private:
|
||||
char name[10];
|
||||
int priority;
|
||||
size_t stackSize;
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ */
|
68
osal/linux/QueueFactory.cpp
Normal file
68
osal/linux/QueueFactory.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
#include <framework/ipc/QueueFactory.h>
|
||||
#include <mqueue.h>
|
||||
#include <errno.h>
|
||||
#include <framework/osal/linux/MessageQueue.h>
|
||||
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||
#include <cstring>
|
||||
|
||||
QueueFactory* QueueFactory::factoryInstance = NULL;
|
||||
|
||||
|
||||
ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo,
|
||||
MessageQueueMessage* message, MessageQueueId_t sentFrom) {
|
||||
message->setSender(sentFrom);
|
||||
int result = mq_send(sendTo,
|
||||
reinterpret_cast<const char*>(message->getBuffer()), message->messageSize,0);
|
||||
|
||||
//TODO: Check if we're in ISR.
|
||||
if (result != 0) {
|
||||
//TODO Translate error
|
||||
switch(errno){
|
||||
case EAGAIN:
|
||||
//The O_NONBLOCK flag was set when opening the queue, or the MQ_NONBLOCK flag was set in its attributes, and the specified queue is full.
|
||||
return MessageQueueIF::FULL;
|
||||
case EBADF:
|
||||
//mq_des doesn't represent a valid message queue descriptor, or mq_des wasn't opened for writing.
|
||||
error << "MessageQueueSenderIF::sendMessage: Configuration error " << strerror(errno) << " in mq_send mqSendTo: " << sendTo << " sent from " << sentFrom << std::endl;
|
||||
/*NO BREAK*/
|
||||
case EINTR:
|
||||
//The call was interrupted by a signal.
|
||||
case EINVAL:
|
||||
/*
|
||||
* This value indicates one of the following:
|
||||
* * msg_ptr is NULL.
|
||||
* * msg_len is negative.
|
||||
* * msg_prio is greater than MQ_PRIO_MAX.
|
||||
* * msg_prio is less than 0.
|
||||
* * MQ_PRIO_RESTRICT is set in the mq_attr of mq_des, and msg_prio is greater than the priority of the calling process.
|
||||
* */
|
||||
case EMSGSIZE:
|
||||
//The msg_len is greater than the msgsize associated with the specified queue.
|
||||
default:
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
QueueFactory* QueueFactory::instance() {
|
||||
if (factoryInstance == NULL) {
|
||||
factoryInstance = new QueueFactory;
|
||||
}
|
||||
return factoryInstance;
|
||||
}
|
||||
|
||||
QueueFactory::QueueFactory() {
|
||||
}
|
||||
|
||||
QueueFactory::~QueueFactory() {
|
||||
}
|
||||
|
||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t message_depth,
|
||||
uint32_t max_message_size) {
|
||||
return new MessageQueue(message_depth, max_message_size);
|
||||
}
|
||||
|
||||
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) {
|
||||
delete queue;
|
||||
}
|
34
osal/linux/TaskFactory.cpp
Normal file
34
osal/linux/TaskFactory.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include <framework/osal/linux/FixedTimeslotTask.h>
|
||||
#include <framework/osal/linux/PeriodicPosixTask.h>
|
||||
#include <framework/tasks/TaskFactory.h>
|
||||
#include <framework/returnvalues/HasReturnvaluesIF.h>
|
||||
|
||||
//TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
|
||||
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
|
||||
|
||||
TaskFactory::~TaskFactory() {
|
||||
}
|
||||
|
||||
TaskFactory* TaskFactory::instance() {
|
||||
return TaskFactory::factoryInstance;
|
||||
}
|
||||
|
||||
PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_,TaskPriority taskPriority_,TaskStackSize stackSize_,TaskPeriod periodInSeconds_,TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
||||
return static_cast<PeriodicTaskIF*>(new PeriodicPosixTask(name_, taskPriority_,stackSize_,periodInSeconds_ * 1000,deadLineMissedFunction_));
|
||||
}
|
||||
|
||||
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,TaskPriority taskPriority_,TaskStackSize stackSize_,TaskPeriod periodInSeconds_,TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
||||
return static_cast<FixedTimeslotTaskIF*>(new FixedTimeslotTask(name_, taskPriority_,stackSize_,periodInSeconds_*1000));
|
||||
}
|
||||
|
||||
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
|
||||
//TODO not implemented
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
|
||||
return PosixThread::sleep(delayMs*1000000ull);
|
||||
}
|
||||
|
||||
TaskFactory::TaskFactory() {
|
||||
}
|
41
osal/linux/Timer.cpp
Normal file
41
osal/linux/Timer.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||
#include <errno.h>
|
||||
#include <framework/osal/linux/Timer.h>
|
||||
|
||||
Timer::Timer() {
|
||||
sigevent sigEvent;
|
||||
sigEvent.sigev_notify = SIGEV_NONE;
|
||||
sigEvent.sigev_signo = 0;
|
||||
sigEvent.sigev_value.sival_ptr = &timerId;
|
||||
int status = timer_create(CLOCK_MONOTONIC, &sigEvent, &timerId);
|
||||
if(status!=0){
|
||||
error << "Timer creation failed with: " << status << " errno: " << errno << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
Timer::~Timer() {
|
||||
timer_delete(timerId);
|
||||
}
|
||||
|
||||
int Timer::setTimer(uint32_t intervalMs) {
|
||||
itimerspec timer;
|
||||
timer.it_value.tv_sec = intervalMs / 1000;
|
||||
timer.it_value.tv_nsec = (intervalMs * 1000000) % (1000000000);
|
||||
timer.it_interval.tv_sec = 0;
|
||||
timer.it_interval.tv_nsec = 0;
|
||||
return timer_settime(timerId, 0, &timer, NULL);
|
||||
}
|
||||
|
||||
|
||||
int Timer::getTimer(uint32_t* remainingTimeMs){
|
||||
itimerspec timer;
|
||||
timer.it_value.tv_sec = 0;
|
||||
timer.it_value.tv_nsec = 0;
|
||||
timer.it_interval.tv_sec = 0;
|
||||
timer.it_interval.tv_nsec = 0;
|
||||
int status = timer_gettime(timerId, &timer);
|
||||
|
||||
*remainingTimeMs = timer.it_value.tv_sec * 1000 + timer.it_value.tv_nsec / 1000000;
|
||||
|
||||
return status;
|
||||
}
|
45
osal/linux/Timer.h
Normal file
45
osal/linux/Timer.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef FRAMEWORK_OSAL_LINUX_TIMER_H_
|
||||
#define FRAMEWORK_OSAL_LINUX_TIMER_H_
|
||||
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* This class is a helper for the creation of a Clock Monotonic timer which does not trigger a signal
|
||||
*/
|
||||
class Timer {
|
||||
public:
|
||||
/**
|
||||
* Creates the Timer sets the timerId Member
|
||||
*/
|
||||
Timer();
|
||||
/**
|
||||
* Deletes the timer
|
||||
*
|
||||
* Careful! According to POSIX documentation:
|
||||
* The treatment of any pending signal generated by the deleted timer is unspecified.
|
||||
*/
|
||||
virtual ~Timer();
|
||||
|
||||
/**
|
||||
* Set the timer given in timerId to the given interval
|
||||
*
|
||||
* @param intervalMs Interval in ms to be set
|
||||
* @return 0 on Success 1 else
|
||||
*/
|
||||
int setTimer(uint32_t intervalMs);
|
||||
|
||||
/**
|
||||
* Get the remaining time of the timer
|
||||
*
|
||||
* @param remainingTimeMs Pointer to integer value which is used to return the remaining time
|
||||
* @return 0 on Success 1 else (see timer_getime documentation of posix function)
|
||||
*/
|
||||
int getTimer(uint32_t* remainingTimeMs);
|
||||
|
||||
private:
|
||||
timer_t timerId;
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_OSAL_LINUX_TIMER_H_ */
|
Reference in New Issue
Block a user