| 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}" |
| } |