diff --git a/pus/newSchedulingImplementation/ScheduleTable.cpp b/pus/newSchedulingImplementation/ScheduleTable.cpp new file mode 100644 index 00000000..61442dd5 --- /dev/null +++ b/pus/newSchedulingImplementation/ScheduleTable.cpp @@ -0,0 +1,221 @@ +#include "ScheduleTable.h" + + +/*ctor + * max_Commands: maximum number of commands in schedule + * max_Subschedules: maximum number of subschedules + */ + + +ScheduleTable::ScheduleTable(object_id_t objectid, uint8_t max_Commands, uint8_t max_Subschedules):SystemObject(objectid) + ,schedule(max_Commands)/*TBD*/,statusMap(max_Subschedules){ + +} + +ScheduleTable::~ScheduleTable(){ + + +} + +ReturnValue_t ScheduleTable::setStatus(bool state){ + + for (statusIterator=statusMap.begin();statusIterator!=statusMap.end(); statusIterator++){ + + statusIterator->second.status=State; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t ScheduleTable::setStatusInMap(bool state,subscheduleId_t subscheduleId){ + + ReturnValue_t result = statusMap.exists(subscheduleId); + + if (result!= HasReturnvaluesIF::RETURN_OK){ + return result; + } + + statusIterator = statusMap.find(subschduleId); + statusIterator->second.status=state; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t ScheduleTable::addCommandEntry(timeval TcTime,store_address_t TcAddress,subscheduleId_t SubscheduleId){ + + commandInfo newCommandInfo = {TcAddress, SubscheduleId}; + result = schedule.insert(TcTime,newCommandInfo); + if (result != HasRetrnvaluesIF::RETURN_OK){ + return result; + } + statusIterator = statusMap.find(subscheduleId); + //would above return null? + statusIterator->second.tcCount ++; + + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t ScheduleTable:: addSubschedule(subscheduleId_t subscheduleId){ + // default status is false + return statusMap.insert(subscheduleId,{false,0}); +} + +ReturnValue_t ScheduleTable:: shiftMap(timeval timeOffset){ + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + schedule.clear(); + scheduleIterator = schedule.begin(); + for (scheduleIterator=schedule.begin();scheduleIterator!=schedule.end(); scheduleIterator++){ + result = shiftCommand(scheduleIterator, timeOffset); + if (result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + } + + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t ScheduleTable::shiftInMap(timeval timeOffset, subscheduleId_t subscheduleId){ + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + scheduleIterator = schedule.begin(); + for (scheduleIterator=schedule.begin();scheduleIterator!=schedule.end(); schdeuleIterator++){ + + if ((scheduleIterator->second.subschedule)==subscheduleId){ + result = shiftCommand(scheduleIterator, timeOffset); + if (result !=HasReturnvaluesIF::RETURN_OK){ + return result; + } + }else{ + continue; + } + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t ScheduleTable::shiftCommand(OnboardSchedule_map::iterator it, timeval time_delta){ + + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + timeval tctime; + //TODO check syntax + timeradd(it.first, &time_delta , &tctime); + commandInfo copyCommand= it->second; + result = schedule.erase(it); + if (result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + // expect no errors, as we already used the iterator + result =schedule.insert(tctime, copyCommand); + //should not happen really. + return result; +} + + +timeval ScheduleTable::findStart(subscheduleId_t subscheduleId){ + + scheduleIterator = schedule.begin(); + timeval startTime= (*scheduleIterator).first; + if (subscheduleId == 0){ + return startTime; + } + + timeval checkTime; + for (scheduleIterator = schedule.begin(); scheduleIterator!=schedule.end();scheduleIterator++){ + if ((scheduleIterator->second.subschedule)==subscheduleId){ + checkTime= scheduleIterator->first; + if (checkTime < startTime){ + startTime=checkTime; + } + }else{ + continue; + } + return startTime; + } +} + +bool ScheduleTable::isNew(subscheduleId_t subscheduleId){ + bool newId = true; + ReturnValue_t result = statusMap.exists(SubscheduleId); + + if (result != HasReturnvaluesIF::RETURN_OK){ + NewId= true; + } + else { + NewId= false; + } + + return NewId; +} + +void scheduleTable::goToStart(){ + scheduleIterator = schedule.begin(); +} + +void scheduleTable::getNextTc(timeval OnboardTime, stor_address_t *address){ + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + commandReached = false; + timeval time; + while ( !commandReached){ + + subscheduleId_t subscheduleId = scheduleIterator->second.subschedule; + statusItertaor = statusMap.find (subscheduleId); + if (statusIterator-> second.status != true){ + schdeuleIterator++; + continue; + } + + time = scheduleIterator.first; + if (OnboardTime > time){ + address = scheduleIterator-> second.commandAddress; + commandReached = true; + //do sth with result?? + result = schedule.erase(&scheduleIterator); + scheduleIterator++; + statusIterator->second.tccount --; + if (statusIterator-> second.tccount ==0){ + result = status.erase(&statusIterator); + //for now I do nothing with the fail here + + } + } + + } +} + + +void scheduleTable::clearScheduleMap(){ + schedule.clear(); + statusMap.clear(); +} + + + + +/* + +void scheduleTable::printAll(uint8_t* pointer, uint32_t maxSize) { + + uint32_t size = 0; + uint16_t count = scheduleMap.scheduleSize();//should iterate and add all subschedule sizes + ReturnValue_t result = SerializeAdapter::serialize(&count, + &pointer, &size, maxSize, true); + + for (scheduleIterator = schedule.begin(), scheduleIterator != schedule.end() && result == HasReturnvaluesIF::RETURN_OK; + ++iter) { + for (subscheduleIterator = (scheduleIterator->second).begin(); + subscheduleIterator != (scheduleIterator->second).end()&& result == HasReturnvaluesIF::RETURN_OK; + subscheduleIterator++ ){ + result = SerializeAdapter::serialize(&scheduleIterator->first, + &pointer, &size, maxSize, true); + uint8_t health = iter->second; + result = SerializeAdapter::serialize(&, &pointer, &size, + maxSize, true); + } + +} + +scheduleSize() + +//how much the size should be? +uint16_t count = 0; +*/ +*/ diff --git a/pus/newSchedulingImplementation/ScheduleTable.h b/pus/newSchedulingImplementation/ScheduleTable.h new file mode 100644 index 00000000..dd79a881 --- /dev/null +++ b/pus/newSchedulingImplementation/ScheduleTable.h @@ -0,0 +1,58 @@ + +#ifndef SCHEDULETABLE_H_ +#define SCHEDULETABLE_H_ + +#include "ScheduleTableIF.h" +#include "../objectmanager/SystemObject.h" +#include "../container/FixedOrderedMultiMap.h" +//include time + + +typedef struct { + Store_address_t commandAddress; + subscheduleId_t subschedule; +} commandInfo; + +typedef struct { + bool status; + uint8_t tcCount; +} subscheduleInfo; +typedef FixedOrderedMultimap Schedule_Map; + +typedef FixedOrderedMultimap Subschedule_Status; + +class ScheduleTable: public ScheduleTableIF , + public SystemObject { + +public: + +ScheduleTable(object_id_t objectid, uint8_t max_Commands, uint8_t max_Subschedules); +virtual ~ScheduleTable(); + +ReturnValue_t setStatus(bool state)override; + ReturnValue_t setStatusInMap(bool state,subscheduleId_t subscheduleId)override; + + ReturnValue_t addCommandEntry(timeval TcTime,store_address_t TcAddress,subscheduleId_t subscheduleId) override; + ReturnValue_t addSubschedule(subscheduleId_t subscheduleId)override; + + ReturnValue_t shiftinMap(timeval timeOffset, subscheduleId_t subscheduleId)override; + ReturnValue_t shiftMap(timeval timeOffset)override; + ReturnValue_t shiftOneSubschedule(Schedule_map::iterator it, timeval time_delta)override; + void getNextTc(timeval OnboardTime,store_address_t *address)override; +timeval findStart(subscheduleId_t subscheduleId = 0)override; +bool isNew(subscheduleId_t subscheduleId)override; +void goToStart()override; + void clearScheduleMap()override; +//add Interface Id +static const uint8_t INTERFACE_ID = CLASS_ID::SCHEDULE_TABLE; + +protected: + +OnboardSchedule_Map schedule; +Subschedule_Status statusMap; + +Schedule_Map::iterator scheduleIterator; +Subschedule_Status::iterator statusIterator; + +private: +ReturnValue_t shiftCommand(OnboardSchedule_Map::iterator it, timeval time_delta); diff --git a/pus/newSchedulingImplementation/ScheduleTableIF.h b/pus/newSchedulingImplementation/ScheduleTableIF.h new file mode 100644 index 00000000..715def9b --- /dev/null +++ b/pus/newSchedulingImplementation/ScheduleTableIF.h @@ -0,0 +1,35 @@ +#ifndef SCHEDULETABLEIF_H_ +#define SCHEDULETANLEIF_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" + + +class ScheduleTableIF : public HasReturnvaluesIF { + +//any inheritance??? +//any friend class? I don't see any now, as there is only the scheduling service accessing this table. + +public: + +virtual ~ScheduleTableIF(); + +virtual ReturnValue_t addCommandEntry(timeval TcTime, store_address_t TcAddress,subscheduleId_t subSchedule= 0)= 0; +virtual ReturnValue_t getNextTC(timeval OnboardTime,timeval* time,store_address_t* address) = 0; +virtual timeval findStart(subscheduleId_t subscheduleId) = 0; +virtual void goToStart()=0; +virtual bool isNew(subscheduleId_t subscheduleId) = 0; +virtual ReturnValue_t addSubschedule(subscheduleId)= 0; +virtual ReturnValue_t shiftMap(timeval timeOffset) = 0; +virtual ReturnValue_t shiftInMap(timeval timeOffset,subscheduleId_t subscheduleId)= 0; +virtual void clearScheduleMap()= 0; +virtual ReturnValue_t setStatus(bool state) = 0; +virtual ReturnValue_t setStatusInMap(bool state, subscheduleId_t subScheduleId) = 0; + + +//TODO print entries +//TODO delete an entry + + + + + diff --git a/pus/newSchedulingImplementation/Scheduling.cpp b/pus/newSchedulingImplementation/Scheduling.cpp new file mode 100644 index 00000000..8567fd71 --- /dev/null +++ b/pus/newSchedulingImplementation/Scheduling.cpp @@ -0,0 +1,504 @@ +/* + * Scheduling.cpp + * + * Created on: Dec 4, 2019 + * Author: mala + */ +#include "Scheduling.h" + +#include +#include "../events/EventManagerIF.h" +#include "../ipc/QueueFactory.h" + +//#include //not yet implemented, but necessary? + +/*figure out if we would like to act on any events, + *also the sizes of queue and pool and schedule and subschedule. + *also maybe a default true for subscheduling enabled? +*/ +//the size of TC pool for ESBO? TODO +//Maybe given that we move it to framework, it should be set from user config? TODO + + +const uint16_t OPS_Scheduling::POOL_SIZES [N_POOLS] = {32,64,128,256}; +const uint16_t OPS_Scheduling::N_ELEMENTS[N_POOLS]= {900,40,30,30}; + + +//TODO TC_QUEUE construction, helper construction +OPS_Scheduling::OPS_Scheduling(uint16_t apid, bool HasInitialSchedule, bool HasSubschedules): + PusServiceBase(object::PUS_Scheduler, apid,SERVICE::Onboard_Scheduling),SchedulingEnabled(true),NoTimeError(false) + ,CommandStorage(objects::PUS_SCHEDULING_STORAGE, POOL_SIZES,N_ELEMENTS,false,true), loadingIsComplete(false), + supportSubschedule (HasSubschedules),loadIninitialSchedule(HasInitialSchedule) + { + eventQueue = QueueFactory::instance()->createMessageQueue(); + commandQueue = QueueFactory::instance()->createMessageQueue(); + + } + +OPS_Scheduling::~OPS_Scheduling(); + +ReturnValue_t OPS_Scheduling::handleRequest(uint8_t subservice){ + switch (subservice){ + case subServices::ENABLE_RELEASE_OF_TC: + return enableScheduling(); + case subServices::DISABLE_RELEASE_OF_TC: + return disableScheduling(); + case subServices::ENABLE_SUBSCHEDULE: + return enable_Subschedule(currentPacket.getApplicationData()); + case subServices::DISABLE_SUBSCHEDULE: + return disable_Subschedule(currentPacket.getApplicationData()); + case subServices::RESET_SCHEDULE: + return resetSchedule(); + case subServices::TIMESHIFT_SCHEDULE: + return shift_Schedule(currentPacket.getApplicationData(), currentPacket.getApplicationDataSize()); + case subServices::TIMESHIFT_SUBSCHEDULE: + return shift_SubSchedule(currentPacket.getApplicationData(), currentPacket.getApplicationDataSize()); + case subServices::INSERT_TC_SCHEDULE: + //With Ramses, we only have fixed length packet sizes, so we need to only put one command in one packet. + return insertCommandinSchedule(currentPacket.getApplicationData(), currentPacket.getApplicationDataSize()); + //TODO report schedule + //case REPORT_SCHEDULE: + //return Create_Schedule_Report(); + + //delete TC, we should discuss if based on what criteria we delete it + //case DELETE_TC + //return Delete_Command(currentPacket.getApplicationData()); + default: + return AcceptsTelecommandsIF::INVALID_SUBSERVICE; + } +} + +Returnvalue_t OPS_Scheduling::initialize() +{ +//base class init + Returnvalue_t result= PusServiceBase::initialize(); + if (result!= RETURN_OK){ + return result; + } +//storage init + result= commandStorage.initialize(); + if (result!=RETURN_OK){ + return result; + } +//helper init + /*result = scheduleHelper.initialize(); + if (result !=HasReturnvaluesIF::RETURN_OK){ + return result; + }*/ + scheduleMap = objectManager->get(objects::SCHEDULE_TABLE); + if (scheduleTable == NULL){ + return HasReturnValuesIF::RETURN_FAILED; + } + + + //queue initialization + + AcceptsTelecommandsIF* distributor = objectManager->get< + AcceptsTelecommandsIF>(objects::CCSDS_PACKET_DISTRIBUTOR); + if (distributor == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + commandQueue.setDefaultDestination(distributor->getRequestQueue()); + + //event manager initialization + + EventManagerIF* eventManager = objectManager->get( + objects::EVENT_MANAGER); + if (eventManager == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + //listening to what?? + result = eventManager->registerListener(eventQueue->getId(), true); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + //this list to be edited, after we have the time manager and know what events we declare + //result = eventManager->subscribeToEventRange(eventReceptionQueue.getId(), + //EVENT::getEventId(TimeManager::TIME_WAS_SET), + //EVENT::getEventId(TimeManager::TIME_JUMP_DETECTED), false); + //if (result != HasReturnvaluesIF::RETURN_OK) { + //return result; + //} + result = eventManager->subscribeToAllEventsFrom(eventReceptionQueue.getId(), + objects::SYSTEM); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + //we should check time error before loading, required by insertTc + //TODO checkEvents first to get timeset + + //load schedule: initialization does not fail fully if loading fails + + if (loadInitialSchedule){ + + scheduleLoader = objectManager->get( + objects::SCHEDULE_LOADER); + if (scheduleLoader != NULL){ + result = scheduleLoader->initializeLoader(); + if (result!=RETURN_OK){ + triggerEvent (SCHEDULE_LOAD_FAILED); + }else{ + result = loadSchedule(); + } + + } else if (scheduleLoader == NULL) { + triggerEvent (SCHEDULE_LOAD_FAILED); + }else { + //nothing + } + } + return HasreturnvaluesIF::RETURN_OK; + +} + + ReturnValue_t OPS_Scheduling::loadSchedule(){ + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + uint8_t *data; + size_t size; + while (!loadingIsComplete){ + + result = scheduleLoader->getCommandPacket(**data, &size); + if (result!= HasReturnvaluesIF::RETURN_OK){ + loadingIsComplete= true; + break; + } + //needs set system time! + result = insertCommandinSchedule(data, size); + tcCounter++; + if (result!= HasReturnvaluesIF:: RETURN_OK){ //only when map is full, normally should not reach here + // we can report how many commands are transferred + triggerEvent(SCHEDULE_LOADED_INCOMPLETE,tcCounter); + break; + } + } + } + } + +//complete +ReturnValue_t OPS_Scheduling::enableScheduling() +{ +if (NoTimeError){ + SchedulingEnabled = true; + return HasReturnvaluesIF::RETURN_OK; +} +else { + return TIME_ERROR; +} +} + + +void OPS_Scheduling::disableScheduling() +{ + if (SchedulingEnabled){ + triggerEvent(OPS_SCHEDULE_DISABLED); + SchedulingEnabled = false; + } +} + +//default subscheduleId is zero, which translates to enable/disable all subschedules +//set status is only a subschedule/group-specific feature. + +ReturnValue_t OPS_Scheduling::enable_Subschedule(SubscheduleId_t subScheduleId) +{ + /*bool state = STATE_ENABLED; + return scheduleHelper.setScheduleStatus(state, subScheduleId); +*/ + ReturnValue_t result; + if (subScheduleId == 0){ + result = scheduleMap->setStatus(true); + }else{ + result = scheduleMap->setStatusInMap(true, subScheduleId); + } + + return result; +} + + +//complete +ReturnValue_t OPS_Scheduling::disable_Subschedule (SubscheduleId_t subScheduleId) +{ +/* bool state = STATE_DISABLED; + return scheduleHelper.setScheduleStatus(state , subScheduleId);*/ + ReturnValue_t result; + if (subScheduleId == 0){ + result = scheduleMap->setStatus(false); + }else{ + result = scheduleMap->setStatusInMap(false, subScheduleId); + } + + return result; +} + +//complete +ReturnValue_t OPS_Scheduling::performService() +{ + + Do_Schedule(); + Check_Events(); + return HasReturnvaluesIF::RETURN_OK; + +} + + +//complete +ReturnValue_t OPS_Scheduling::insertCommandinSchedule(const uint8_t* data, uint16_t size) +{ + +uint32_t dataLength = 0; +ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; +//get subschedule from packet 1st byte +if (supportSubschedule){ + SubscheduleId_t subscheduleId = 0; + getSubschedule(&subscheduleId,data); + data++; + size --; +} +timeval TcTime; +timeval OnboardTime; +//TODO, SSC time format is different +CCSDSTime::convertFromCUC(&TcTime, CCSDSTime::P_FIELD_CUC_6B_CCSDS, data, &dataLength, size) +data += dataLength; +size-= dataLength; + +if (NoTimeError){ + OSAL::getClock_timeval(&OnboardTime); + if (TcTime < OnboardTime){ + return COMMAND_EXPIRED; + } +}else{ + //does nothing and continue +} + + TcPacketBase NewCommand(data); + if (NewCommand.getFullSize()!=size){ + return ILLEGAL_APPLICATION_DATA; + } + store_address_t TcAddress; + result = CommandStorage.addData(&TcAddress, NewCommand.getWholeData(),NewCommand.getFullSize()); + if (result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + //Helper should have both options +if (supportSubschedule){ + //result = scheduleHelper.addCommandtoSchedule(TcTime,TcAddress, subscheduleId); + bool newSubSchedule = scheduleMap->isNew(subSchedule); + if (newSubschedule){ + result = scheduleMap->addsubSchedule(); + if (result !=HasReturnvaluesIF::RETURN_OK){ + return result; + } + } + return scheduleMap->addCommandEntry(TcTime, TcAddress,subSchedule); + +}else{ + //result = scheduleHelper.addCommandtoSchedule(TcTime,TcAddress); + return scheduleMap->addCommandEntry(TcTime, TcAddress); +} +//TODO check if it works with RETURN_OK, result is passed from Map +/* if (result!= HasReturnvaluesIF::RETURN_OK){ + return SCHEDULE_MAP_FULL; + }*/ +} + + + +//only if subschedule supported +void OPS_Scheduling::get_Subschedule( SubscheduleId_t* subscheduleId,const uint8_t* data) +{ + + *subschdeuleId = *data; + +} + + +//done +ReturnValue_t OPS_Scheduling::resetSchedule() +{ + //scheduleHelper.clearSchedule(); + scheduleMap->clearScheduleMap(); + CommandStorage.clearStore(); + SchedulingEnabled= false; + return HasReturnvaluesIF::RETURN_OK; +} + + + +Returnvalue_t OPS_Scheduling::shift_Schedule (const uint8_t* data, uint16_t size){ + + + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + timeval time_offset; + uint32_t time_length; + //here the pfield is changed for the epoch not to be CCSDS, the time field is 6 bytes as usual + + CCSDSTime::convertFromCUC(&time_offset, CCSDSTime::P_FIELD_CUC_6B_Agency, data, size, &time_length); + + result = shiftIsValid(time_offset); + if (result !=HasReturnvaluesIF::RETURN_OK){ + return INVALID_SHIFT; + } + //TODO shift returns replies from map, check if it works + //result = scheduleHelper.shiftSchedule(time_offset) + + result = scheduleMap->shiftMap(timeOffset) + if (result == HasReturnvaluesIF::RETURN_OK){ + return SCHEDULE_SCHIFTED; + }else{ + return SCHEDULE_SHIFT_FAILED; + } +} + +//it is only for subschedule support case +Returnvalue_t OPS_Scheduling::shift_SubSchedule (const uint8_t* data, uint16_t size){ + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + timeval timeOffset; + SubschedulId_t subScheduleId = 0; + uint32_t dataLength = 0; + + get_Subschedule(&subScheduleId, data); + data ++; + size --; + CCSDSTime::convertFromCUC(&time_offset, CCSDSTime::P_FIELD_CUC_6B_Agency, data, size, &dataLength); + + //result = scheduleHelper.shiftIsValid(timeOffset, subSchedule); + result = shiftIsValid(time_offset); + if (result !=HasReturnvaluesIF::RETURN_OK){ + return INVALID_SHIFT; + } + //TODO shift returns replies from map, check if it works + //result = scheduleHelper.shiftSchedule(timeOffset, subScheduleId); + bool newSubschedule = scheduleMap->isNew(subscheduleId); + if (newSubschedule){ + return SCHEDULE_SHIFT_FAILED; + } + result= scheduleMap->shiftInMap(timeOffset,subscheduleId); + if (result == HasReturnvaluesIF::RETURN_OK){ + return SCHEDULE_SCHIFTED; + }else{ + return SCHEDULE_SHIFT_FAILED; + } +} + + +ReturnValue_t OPS_Scheduling::shiftIsValid(timeval timeOffset, SubscheduleId_t subscheduleId){ +//can be improved, putting it zero is not the best option + //maybe overloading +timeval scheduleStart = ScheduleMap->FindStart(subscheduleId) + +timeval checkTime;//clean this up +timeradd(&scheduleStart, &timeOffset ,&checkTime); +timeval OnboardTime; +OSAL::getClock_timeval(&OnboardTime); +if (checkTimegoToStart(); + //scheduleHelper.startScheduleIteration(); + //Clock::getClock_timeval(&OnboardTime) + //what is the precison? would this work for schedule?? + OSAL::getClock_timeval(&OnboardTime); + + while (!reachedEnd()){ + //scheduleHelper.getNextValidCommand(OnboardTime, &TcAddress); + scheduleMap->getNextTc(OnboardTime, address); + releaseCommand(TcAddress); + commandStorage.deleteData(TcAddress); + } + } + } +bool OPS_Scheduling::reachedEnd(){ + //check syntax TODO + if(scheduleMap->scheduleIterator == scheduleMap->schedule.end()){ + return true; + }else{ + return false; + } +} + +void releaseCommand(store_address_t address){ + const uint8_t* pakcet; + uint32_t size; + ReturnValue_t result = commandStorage.getData(TcAddress, &packet, &size); + TcPacketStored Telecommand(packet,size); + if(Telecommand.getWholeData()==NULL){ + triggerEvent(COMMAND_LOST); + } else { + message.setStorageId(Telecommand.getStoreAddress()); + result=commandQueue.sendToDefault(&message); + if (result!=HasReturnvaluesIF::RETURN_OK){ + triggerEvent(COMMAND_LOST,result); + } + } + Telecommand.deletePacket(); +} + + + +//still not working TODO +/*ReturnValue_t OPS_Scheduling::Create_Schedule_Report(){ + + //How big the packet can be?? + //what happens if it is bigger than the maximum size? + + ScheduleReportTmpacket schedulePacket; + + OnboardSchedule_map::iterator it = Schedule.begin(); + Subschedule_map::iterator sub_it = NULL; + const uint8_t* tcPacket; + uint32_t size; + timeval tctime; + SubscheduleId_t subscheduleId; + for (it = Schedule.begin();it!=Schedule.end();it++){ + subscheduleId = *it.first; + sub_it = ((*it).second).begin(); + while (sub_it!=((*it).second).end()){ + tcime = *sub_it.first; + result = commandStorage->getData(*sub_it.second, &tcPacket, &tcLen); + schedulePacket.appendCommand(subscheduleId,tctime,tcPacket,tcLen); + this->tcCounter++; + } + } + schedulePacket.setCount(tcCounter); + TmPacketStored tmPacketStored(this->apid, this->serviceId, + subService, this->packetCounter, &schedukeReportPacket); + ReturnValue_t result = tmPacketStored.sendPacket(requestQueue.getDefaultDestination(), requestQueue.getId()); + if (result == HasReturnvaluesIF::RETURN_OK) { + this->packetCounter++; + } +}*/ + + +/*void OPS_Scheduling::Check_Events() { + EventMessage message; + for (ReturnValue_t result = eventQueue.receiveMessage(&message); + result == HasReturnvaluesIF::RETURN_OK; + result = eventQueue.receiveMessage(&message)) { + //based on time manager events, react + if (message.getEvent() == TimeManager::TIME_JUMP_DETECTED) { + DisableScheduling(); + } + if (message.getEvent() == TimeManager::TIME_WAS_SET) { + NoTimeError = true; + } + //Disable schedule in case a high severity event (soft reboot, safe mode, ..) comes from SYSTEM. + if (message.getReporter() == objects::SYSTEM + && message.getSeverity() == SEVERITY::HIGH) { + + DisableScheduling(); + + } + } + }*/ + + diff --git a/pus/newSchedulingImplementation/Scheduling.h b/pus/newSchedulingImplementation/Scheduling.h new file mode 100644 index 00000000..db10e08e --- /dev/null +++ b/pus/newSchedulingImplementation/Scheduling.h @@ -0,0 +1,153 @@ +/* + * Scheduling.h + * + * Created on: Nov 5, 2019 + * Author: mala + */ + + + +#ifndef STUDIO_TMTCSERVICES_SCHEDULING_H_ +#define STUDIO_TMTCSERVICES_SCHEDULING_H_ + + +#include +#include +#include +#include +#include "ScheduleTableIF.h" + +//make sure this alias works in global scope + +typedef uint8_t SubscheduleId_t; + + +/** + * @brief manages onboard time-based schedule, PUS service 11 + * @details + * + * This service is responsible in managing an onboard time-based schedule of telecommands. + * The schedule can be through this service enabled, disabled, and time-shifted + * It can support subschedules. subschedules can be created,enabled and disabled, and time-shifted + * + * The service stores the schedule in the ScheduleMap, which has a ScheduleMapIF. + * Current Map includes subschedules, but it can be replaced by implementing the interface + * The service also can pre-load commands through scheduleLoaderIF. + * scheduleLoader and scheduleTable should be instantiated in factory + * + * right now we do not have control over one single command,in terms of + * shift/disable/delete. it might be required in future though, + + *The following constants are in standards but not implemented in this version + *Time margin declared static const Time_Based_Schedule_Margin + *Time between specified release time and actual release time , maximum, declared + * + * @author M.Taheran + * + */ + +class OPS_Scheduling: public PusServiceBase { + + +public: + + OPS_Scheduling(uint16_t apid,bool HasInitialSchedule, bool HasSubschedules); + virtual ~OPS_Scheduling(); + ReturnValue_t handleRequest(uint8_t subservice) override; + ReturnValue_t performService() override; + ReturnValue_t initialize() override; + + +protected: + + ScheduleTableIF* scheduleMap = nullptr; + ScheduleLoaderIF * scheduleLoader = nullptr; + bool loadInitialSchedule; + bool supportSubschedules; + +private: + + + +enum class subServices { + + + static const uint8_t ENABLE_RELEASE_OF_TC = 1, + static const uint8_t DISABLE_RELEASE_OF_TC =2, + static const uint8_t ENABLE_SUBSCHEDULE = 20, + static const uint8_t DISABLE_SUBSCHEDULE = 21, + + //static const uint8_t DELETE_TC = 5;//not implemented + static const uint8_t RESET_SCHEDULE = 3, + static const uint8_t TIMESHIFT_SCHEDULE = 15, + static const uint8_t TIMESHIFT_SUBSCHEDULE = 8, + static const uint8_t INSERT_TC_SCHEDULE = 4, + //TODO + //static const uint8_t REPORT_SCHEDULE = 16;//TM is type 10 +}; + //Interface and subsystem ID to be included in mission config + + static const unit8_t INTERFACE_ID = CLASS_ID::OPS_SCHEDULING_SERVICE; + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::OPS_SCHEDULER; + + //list of return codes, tbc + static const ReturnValue_t TIME_ERROR = MAKE_RETURN_CODE (1); + static const ReturnValue_t COMMAND_EXPIRED = MAKE_RETURN_CODE (2); + static const ReturnValue_t ILLEGAL_APPLICATION_DATA= MAKE_RETURN_CODE (3); + //static const ReturnValue_t SCHEDULE_MAP_FULL= MAKE_RETURN_CODE (4); + static const ReturnValue_t INVALID_SHIFT= MAKE_RETURN_CODE (4); + static const ReturnValue_t SCHEDULE_SHIFTED= MAKE_RETURN_CODE (5); + static const ReturnValue_t SCHEDULE_SHIFT_FAILED= MAKE_RETURN_CODE (6); + + //list of events,tbc + + static const Event = OPS_SCHEDULE_DISABLED = MAKE_EVENT(1, SEVERITY::MEDIUM); + static const Event = COMMAND_LOST = MAKE_EVENT (2, SEVERITY::LOW); + static const Event = SCHEDULE_LOAD_FAILED = MAKE_EVENT (3, SEVERITY::MEDIUM); + static const Event = SCHEDULE_LOADED_INCOMPLETE = MAKE_EVENT (4, SEVERITY::LOW); + + MessageQueueIF* commandQueue = nullptr; + MessageQueueIF* eventQueue = nullptr; + + + static const uint8_t N_POOLS = 4; + static const uint16_t POOL_SIZES[N_POOLS]; + static const uint16_t N_ELEMENTS[N_POOLS]; + LocalPool commandStorage; + + //only used for reporting on incomplete loading + + uint8_t tcCounter = 0; + bool SchedulingEnabled; + bool NoTimeError; + + +Returnvalue_t enableScheduling(); +void disableScheduling(); +ReturnValue_t enable_Subschedule (SubscheduleId_t SubScheduleID=0); +ReturnValue_t disable_Subschedule(SubscheduleId_t SubScheduleID=0); +Returnvalue_t resetSchedule(); +Returnvalue_t insertCommandinSchedule(const uint8_t* data, uint16_t size); +void do_Schedule(); +void check_Events(); + +Returnvalue_t shift_Schedule (const uint8_t* data, uint16_t size); +Returnvalue_t shift_SubSchedule (const uint8_t* data, uint16_t size); +void shift_Subschedule_Map(OnboardSchedule_map::iterator it, timeval time_delta); +void get_Subschedule(SubscheduleId_t* SubscheduleId,const uint8_t* data, uint32_t maxlength, uint32_t* foundlength, bool* NewId = false); + +ReturnValue_t loadSchedule(); +void releaseCommand(store_address_t address); + +//TODO +//ReturnValue_t Create_Schedule_Report(); + + + + + + + + + +#endif /* STUDIO_TMTCSERVICES_SCHEDULING_H_ */ diff --git a/pus/newSchedulingImplementation/schedlueLoaderIF.h b/pus/newSchedulingImplementation/schedlueLoaderIF.h new file mode 100644 index 00000000..096387e7 --- /dev/null +++ b/pus/newSchedulingImplementation/schedlueLoaderIF.h @@ -0,0 +1,29 @@ +#ifndef SCHEDULELOADERIF_H_ +#define SCHEDULELOADERIF_H_ + +#include<> + +//either has returnvalues or include HasReturnValueIF.h +class ScheduleLoaderIF: public HasReturnValuesIF { + +public: + + /*this interface is used to get commands from another object + * and pass to scheduling to load at first. commands are get one by one + * in an application data packet. + haven't used it for anything else yet. changes come after + we implement the JSON system + */ + //ctor specific to implementation + static const uint8_t INTERFACE_ID = CLASS_ID::SCHEDULE_LOADER_IF; + //add ReturnValues + //TBD + + virtual ~ScheduleLoaderIF(); + //not sure if needed, might be. + virtual ReturnValue_t initializeLoader() = 0; + virtual ReturnValue_t getCommandPacket(uint8_t **data, uint32_t *size)= 0; + +}; + +#endif