blob: 0ab72934859dc0d99396aa71ef88a50db7aa7431 [file] [log] [blame]
RoomModel room.basic.service.timing {
import room.basic.types.* from "Types.room"
async ActorClass ATimingService {
Interface {
SPP timer: PTimer
}
Structure {
usercode1 '''
#include "osal/etTime.h"
#define ET_NB_OF_TCBS 30
typedef struct etTCB etTimerControlBlock;
struct etTCB {
etTime expTime;
etTime pTime;
int32 portIdx;
etTimerControlBlock* next;
};'''
usercode2 '''/*uc2*/'''
usercode3 '''/*uc3*/'''
ServiceImplementation of timer
Attribute tcbs [30]: tcb
Attribute usedTcbsRoot: tcb ref
Attribute freeTcbsRoot: tcb ref
}
Behavior {
Operation getTcb(): tcb ref '''
etTimerControlBlock* temp = freeTcbsRoot;
if(freeTcbsRoot!=0) {
freeTcbsRoot=freeTcbsRoot->next;
temp->next=0;
}
return temp;'''
Operation returnTcb(block: tcb ref) '''
block->next=freeTcbsRoot;
freeTcbsRoot=block;'''
Operation removeTcbFromUsedList(idx: int32) '''
etTimerControlBlock* temp=usedTcbsRoot;
etTimerControlBlock* temp2=usedTcbsRoot;
if (temp==0) return;
if (usedTcbsRoot->portIdx == idx){
/* element found, the first one */
usedTcbsRoot = usedTcbsRoot->next;
returnTcb(temp);
return;
}
temp=temp->next;
while(temp!=0){
if(temp->portIdx==idx){
temp2->next=temp->next;
returnTcb(temp);
return;
}else{
/* try next */
temp2=temp;
temp=temp->next;
}
}'''
Operation putTcbToUsedList(block: tcb ref) '''
etTimerControlBlock* temp=usedTcbsRoot;
etTimerControlBlock* temp2=usedTcbsRoot;
if (temp==0){
/* list empty put new block to root */
block->next=0;
usedTcbsRoot=block;
return;
}
while(1){
if (temp != 0){
if (isTimeGreater(&block->expTime,&temp->expTime)){
/* try next position */
temp2=temp;
temp=temp->next;
}else{
/* right position found */
block->next=temp;
if(temp==usedTcbsRoot){
usedTcbsRoot=block;
}else{
temp2->next=block;
}
return;
}
}else{
/* end of list reached */
block->next=0;
temp2->next=block;
return;
}
}'''
Operation isTimeGreater(t1: targetTime ref, t2: targetTime ref): boolean '''
if (t1->sec > t2->sec) return ET_TRUE;
if (t1->sec < t2->sec) return ET_FALSE;
if (t1->nSec > t2->nSec) return ET_TRUE;
return ET_FALSE;'''
Operation addTime(t1: targetTime ref, t2: targetTime ref) '''
t1->sec += t2->sec;
t1->nSec += t2->nSec;
while(t1->nSec >= 1000000000L){
t1->sec++;
t1->nSec-=1000000000L;
}'''
// Operation printList(){
// "etTimerControlBlock* temp=usedTcbsRoot;"
// " printf(\"list: \");"
// " while (temp!=0){"
// " printf(\"(%ld,%ld),\",temp->expTime.sec,temp->expTime.nSec);"
// " temp=temp->next;"
// " }"
// " printf(\"\\n\");"
// }
StateMachine {
Transition tr0: initial -> Operational {
action '''
int i;
usedTcbsRoot=0;
freeTcbsRoot=&tcbs[0];
tcbs[ET_NB_OF_TCBS-1].next=0;
for (i=0;i<ET_NB_OF_TCBS-1;i++){
tcbs[i].next=&tcbs[i+1];
}'''
}
Transition tr1: Operational -> Operational {
triggers {
<startTimeout: timer>
}
action '''
etTimerControlBlock* transitionDatar = getTcb();
etTime t;
if (transitionDatar!= 0){
t.sec=transitionData/1000;
t.nSec=(transitionData%1000)*1000000L;
transitionDatar->pTime.sec = 0;
transitionDatar->pTime.nSec = 0;
transitionDatar->portIdx=((etReplSubPort*)ifitem)->index;
getTimeFromTarget(&(transitionDatar->expTime));
addTime(&(transitionDatar->expTime),&t);
putTcbToUsedList(transitionDatar);
}'''
}
Transition tr3: Operational -> Operational {
triggers {
<startTimer: timer>
}
action '''
etTimerControlBlock* transitionDatar = getTcb();
etTime t;
if (transitionDatar!= 0){
t.sec=transitionData/1000;
t.nSec=(transitionData%1000)*1000000L;
transitionDatar->pTime = t;
transitionDatar->portIdx=((etReplSubPort*)ifitem)->index;
getTimeFromTarget(&(transitionDatar->expTime));
addTime(&(transitionDatar->expTime),&t);
putTcbToUsedList(transitionDatar);
}'''
}
Transition tr4: Operational -> Operational {
triggers {
<kill: timer>
}
action '''removeTcbFromUsedList(((etReplSubPort*)ifitem)->index);'''
}
State Operational {
entry '''/* prepare */'''
do '''
/* maintain timers */
etTimerControlBlock* temp;
etTime t;
getTimeFromTarget(&t);
while (usedTcbsRoot !=0 ){
if (isTimeGreater(&t,&(usedTcbsRoot->expTime))){
timer[usedTcbsRoot->portIdx].timeout();
temp=usedTcbsRoot;
usedTcbsRoot=usedTcbsRoot->next;
if((temp->pTime.sec==0)&&(temp->pTime.nSec==0)){
/* single shot timer */
returnTcb(temp);
}else{
/* periodic timer */
addTime(&temp->expTime,&temp->pTime);
putTcbToUsedList(temp);
}
}else{
break;
}
}'''
}
}
}
}
/*
* Protocol for periodic timers and single shot timeouts
*/
ProtocolClass PTimer {
usercode1 '''
#define ET_TIMER_RUNNING 0x01
#define ET_TIMER_PERIODIC 0x02'''
usercode2 '''/*uc2*/'''
incoming {
/* starts a periodic timer (time in milliseconds) */
Message startTimer(uint32)
/* starts a single shot timeout (time in milliseconds) */
Message startTimeout(uint32)
/* kills single shot timeouts and periodic timers */
Message kill()
}
outgoing {
/* fires when timeout or timer has expired */
Message timeout()
}
conjugated PortClass
{
handle incoming startTimer '''
if (status==0){
status=ET_TIMER_RUNNING | ET_TIMER_PERIODIC;
etPort_sendMessage(self, PTimer_IN_startTimer, sizeof(int32), &data__et);
}'''
handle incoming startTimeout '''
if (status==0){
status = ET_TIMER_RUNNING;
etPort_sendMessage(self, PTimer_IN_startTimeout, sizeof(int32), &data__et);
}'''
handle outgoing timeout '''
/* TODO: clear active bit in case of single shot timer */
if (status!=0){
if (status==ET_TIMER_RUNNING){
/* single shot timer */
status=0;
}
/* msg to fsm */
(*receiveMessageFunc)(actor, self, msg);
}'''
handle incoming kill '''
if (status!=0){
status=0;
etPort_sendMessage(self, PTimer_IN_kill, 0,NULL);
}'''
Attribute status: int8 = "0"
}
}
ExternalType tcb -> "etTimerControlBlock" default "{{0,0},{0,0},0,NULL}"
ExternalType targetTime -> "etTime" default "{0,0}"
}