/**************************************************************************
* File name : CyclicExecutive.java
*
* This file is part a SCJ Level 0 and Level 1 implementation,
* based on SCJ Draft, Version 0.94 25 June 2013.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This SCJ Level 0 and Level 1 implementation is distributed in the hope
* that it will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this SCJ Level 0 and Level 1 implementation.
* If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2012
* @authors Anders P. Ravn, Aalborg University, DK
* Stephan E. Korsholm and Hans Søndergaard,
* VIA University College, DK
*************************************************************************/
package javax.safetycritical;
import javax.realtime.AbsoluteTime;
import javax.realtime.Clock;
import javax.realtime.RelativeTime;
import javax.safetycritical.annotate.Level;
import javax.safetycritical.annotate.Phase;
import javax.safetycritical.annotate.SCJAllowed;
/**
* A <code>CyclicExecutive</code> represents a Level 0 mission. Every mission
* in a Level 0 application must be a subclass of <code>CyclicExecutive</code>.
*
* @version 1.2; - December 2013
*
* @author Anders P. Ravn, Aalborg University,
* <A HREF="mailto:apr@cs.aau.dk">apr@cs.aau.dk</A>, <br>
* Hans Søndergaard, VIA University College, Denmark,
* <A HREF="mailto:hso@viauc.dk">hso@via.dk</A>
*/
@SCJAllowed
public abstract class CyclicExecutive extends Mission {
Clock rtClock;
AbsoluteTime next;
RelativeTime deltaTime;
@SCJAllowed
public CyclicExecutive() {
this.rtClock = Clock.getRealtimeClock();
this.next = rtClock.getTime();
this.deltaTime = new RelativeTime(rtClock);
}
/**
* Every <code>CyclicExecutive</code> shall provide its own cyclic schedule, which is represented
* by an instance of the <code>CyclicSchedule</code> class. Application programmers are expected to override
* the <code>getSchedule</code> method to provide a schedule that is appropriate for the mission.<br>
* Level 0 infrastructure code invokes the <code>getSchedule</code> method on the mission returned from
* <code>MissionSequencer.getNextMission</code> after invoking the mission's <code>initialize</code> method
* in order to obtain the desired cyclic schedule. <br>
* Upon entry into the <code>getSchedule</code> method, this mission's <code>MissionMemory</code> area shall be the
* active allocation context. The value returned from <code>getSchedule</code> must reside in the current
* mission's <code>MissionMemory</code> area or in some enclosing scope. <br>
* Infrastructure code shall check that all of the <code>PeriodicEventHandler</code> objects referenced
* from within the returned <code>CyclicSchedule</code> object have been registered for execution with this mission.
*
* @param handlers The handlers that have been registered with <code>this Mission</code>.
* The handler objects must reside in an enclosing scope of <code>this</code>.
* @return A cyclic schedule for the handlers.
*/
@SCJAllowed(Level.INFRASTRUCTURE)
public abstract CyclicSchedule getSchedule(PeriodicEventHandler[] handlers);
void runInitialize() {
// overrides the method in class Mission and is called in mission memory
phaseOfMission = Phase.INITIALIZE;
msSetForMission = new ManagedSchedulableSet();
initialize();
}
/**
* Implementation of a cyclic executive.
* Is invoked in a mission memory scope.
*/
void runExecute()
// overrides the method in class Mission and is called in mission memory
{
// The following four lines of code: to meet the precondition in getSchedule.
ManagedSchedulable[] msObjects = Mission.getMission().msSetForMission.managedSchObjects;
PeriodicEventHandler[] pevs = new PeriodicEventHandler[Mission.getMission().msSetForMission.noOfRegistered];
for (int i = 0; i < pevs.length; i++)
pevs[i] = (PeriodicEventHandler)msObjects[i];
CyclicSchedule schedule = getSchedule(pevs) ;
/**
* local reference to frames
*/
final Frame[] frames = schedule.getFrames();
/**
* step is the minor cycle counter
*/
int step = 0;
while (!missionTerminate) {
PeriodicEventHandler[] handlers = frames[step].handlers;
int n = handlers.length;
for (int handlerIdx = 0; handlerIdx < n; handlerIdx++) {
handlers[handlerIdx].privateMemory.enter(handlers[handlerIdx]);
}
// wait for frame.duration to expire
waitForNextFrame(frames[step].duration);
// index to next frame
step = (step + 1) % frames.length;
}
}
void runCleanup(MissionMemory missMem)
//overrides the method in class Mission and is called in mission memory
{
vm.ClockInterruptHandler.instance.disable();
Mission.getMission().msSetForMission.terminateMSObjects();
cleanUp();
missMem.resetArea();
vm.ClockInterruptHandler.instance.enable();
}
private void waitForNextFrame(RelativeTime duration) {
next.add(duration, next);
vm.RealtimeClock.delayNativeUntil(next);
}
// Used in feasible below
/*static private int find(PeriodicEventHandler[] handlerList,
PeriodicEventHandler h) {
for (int i = handlerList.length - 1; i >= 0; i--)
if (handlerList[i] == h)
return i;
return -1;
}*/
// Used in JML annotations
// boolean feasible(PeriodicEventHandler[] handlerList, CyclicSchedule schedule) {
// // checks a cyclic schedule. It is assumed, conservatively, that every handler runs to its deadline.
//
// RelativeTime[] nextDeadline = new RelativeTime[handlerList.length];
// for (int h = 0; h < handlerList.length; h++)
// nextDeadline[h] = new RelativeTime(
// handlerList[h].release.getDeadline());
//
// Frame[] frames = schedule.getFrames();
//
// RelativeTime next = new RelativeTime();
//
// for (int step = 0; step < frames.length; step++) {
// PeriodicEventHandler[] handlers = frames[step].handlers;
// PeriodicEventHandler hx;
// int n = handlers.length;
// RelativeTime startFrame = new RelativeTime(next);
//
// for (int handlerIdx = 0; handlerIdx < n; handlerIdx++) {
// hx = handlers[handlerIdx];
// // check handler declared
// int h = find(handlerList, hx);
// if (h < 0)
// return false;
// // run handler hx
// next.add(hx.release.getDeadline());
// // check against absolute deadline
// if (next.compareTo(nextDeadline[h]) > 0)
// return false;
// nextDeadline[h].add(((PeriodicParameters) hx.release)
// .getPeriod());
// }
// // advance to next frame
// if (next.compareTo(startFrame.add(frames[step].duration)) > 0)
// return false;
// next.add(frames[step].duration);
// }
// // the schedule was OK for handlers in the frames
// // check no handler left behind.
// for (int h = 0; h < handlerList.length; h++)
// if (nextDeadline[h].compareTo(next) <= 0)
// return false;
//
// return true;
// }
}