RTE(Run-Time Enviroment)
- tool에 의해 자동 generation
- 하는 일
- communication infrastructure 제공 : component와 component 사이에서 port를 통해 이루어지는 통신을 담당, component에 달려있는 port의 코드는 RTE에 자동 생성된다.
-> Inter-ECU(다른 ECU에서), Intra-ECU(같은 ECU에서)
- arrange for real-time scheduling : TASK에 priority를 줘서 실시간 scheduling을 하는데 TASK도 RTE가 자동 생성
- OS에 대한 abstraction 제공 : Runnable entity(TASK에 의해 호출되는 코드)
Internal Behavior
- 하나의 atomic component type에 하나의 IB가 만들어진다.
- 코드가 어떤 기능이 실행되는지 정도를 기술하여 모델링하는 것
- 목적 : port는 RTE에 의해 자동생성, component 안에 있는 코드는 개발자가 생성. 이 둘 사이에 서로 연동하겠다는 약속이 생겨야 한다.
- Runnable entity 속에는 point들이 정의되어 있고, 이 point는 port를 어떤식으로 호출하겠다라는 방식을 정의해놓는다. 그러면 RTE는 point에 해당하는 함수를 자동 생성한다. 호출하는 방법은 RTE API를 보면 알 수 있고 .h파일에 만들어진다.
- 하는 일
RTE 속에 있는 port와 TASK 사이에 서로 어떻게 연동되는지 규정한다.
- Runnable Entity 정의
- Point 정의
- Event 정의
두 가지 종류가 있다.
- Runnable entity의 실행 Timing을 규정해주는 event
- Runnable entity에게 port의 상태를 알려주는 event
Software Component Internal Behavior
- Runnable entity는 event가 반드시 할당된다.
- Runnable entity의 실행은 주어진 event가 발생하는 시점이다. Event는 RTE가 발생시킨다.
- Timing events
- Communication events
- Mode switch events
- Runnable entity는 function인데 TASK에서 호출한다. RTE 내의 TASK 내에서 호출된다. -> Runnable entity는 TASK의 body이다.
Runnable Categories
- ECU configuration을 할 때 runnable entity를 TASK에 mapping시킨다. 이 때 runnable category는 해당 TASK를 basic 혹은 extended TASK에 mapping 시켜야 할지의 기준이 된다.
- Category는 어떻게 정해지느냐 : IB를 정할 때 runnable entity를 만든다. 이때 어떻게 point를 정의해주느냐에 따라 결정된다. Point 때문에 만들어지는 RTE_API에서 blocking API가 만들어지느냐 non-blocking API가 만들어지느냐에 따라 결정된다.
- Category 1
- Runnable entity가 non-blocking(waiting x)
-> start, execute, terminate
- Category 1을 가지는 runnable entity의 TASK는 basci task가 될 수 있다.
- explicit communication을 하느냐 안하느냐에 따라
- Category 2
- Runnable entity가 block될 수 있다.
-> start, execute, wait for interaction and (optionally) terminate
- Category 2를 가지는 runnable entity가 할당된 TASK는 extended task가 되어야 한다.
Implementing Runnable Entities
- IB에서 runnable entity를 모델링한 다음 실제 코딩을 하는 것이다. IB에서 RE를 정의하면 RTE generation할 때 해당 RE에 대한 헤더가 생긴다.
- 코드를 사람이 만들때 개발자는 runnable entity가 RTE TASK에 의해서 호출될 때는 첫번째 파라미터 instance_handle 값이 자동적으로 결정되서 넘어오는 것이라고 알고, 그 값을 받아서 그것을 이용해서 RTE 내에 있는 다른 함수를 호출할 때 instance_handle값을 그대로 넘겨주면 된다.
Multiple Instantiation
모델링을 하고, TASK code, RTE code는 자동으로 생성되고 RE는 헤딩 부분만 자동 생성되고 그 안에 코드는 사람이 작성한다. 필요하면 function들도 같이 작성한다. RE가 돌아갈 때는 RTE 속에 정의된 TASK가 RE를 호출해줄 때만 돌아간다. RTE Event를 통해 TASK를 호출하고 TASK는 RE를 호출한다. 그리고 port에 있는 data를 handling하고 싶을 때, TASK에서 RE를 호출하고 RE에서 RTE_API를 호출함으로써 port에 있는 data를 handling한다. RTE_API를 호출할 때 첫번째 파라미터에 어떤 instance_handle을 주느냐에 따라 a 혹은 b를 사용하게 된다. RTE가 TASK에서 RE를 호출할 때 instance_handle 값을 미리 넘겨준다.
RTE Generator
- Contract phase
- VFB model, IB model까지
- header file만 생성
- RE에 대한 header file + RTE_API의 header file
- RTE phase
- VFB model, IB model, System config, ECU config까지
- header file에 정의된 함수의 body + TASK
- RTE 전체가 generation
RTE Events
- Timing Event
주기적으로
- Data Received Event
특정 port에 data가 도착했을 때
- Data Received Error Event
data가 도착할 때 error가 발생했을 때
- Asynchronous Server Call Returns Event
C-S에서 server를 asynchronous하게 호출하고 결과값이 도착했다는 것을 알려줄 때
- Operation Invoked Event
C-S쪽에서 server쪽에 만들어줘야 한다. Client 쪽에는 호출하는 API를 만들어준다.
- Data Send Completed Event
acknowledgement가 발생했을 때
- Data Write Completed Event
acknowledgement가 발생했을 때
- Mode Swtich Event
- Mode Switched Ack Event
- Background Event
idle task에서 돌아가는 event
- Internal Trigger Occurred Event
OSEK에서 ActivateTask와 같다.
- External Trigger Occurred Event
OSEK에서 ActivateTask와 같다.
Concurrency and Reentrancy of a RunnableEntity
- SW-C type 하나가 정의되면 type model에 대해서 IB 모델 하나가 정의된 것이고 그 안에 여러 개의 RE를 정의할 수 있다. Support Multiple Instantiation은 해당 IB에 대해서 정의된다. 해당 component type 하나에 대해서 multiple instantiation을 가능하게 할 거냐를 지정한다. canBeInvoked Concurrently라는 attribute는 RE 하나하나에 대해서 정의되는데 해당 TASK에 대해서 multiple activation이 가능하느냐를 규정한다.
- supportsMultipleInstantiation canBeInvokedConcurrently
- FALSE FALSE : RE가 규정되면 instance가 하나만 존재, multiple activation 불가능 -> synchronization, mutual exclusion을 고민할 필요가 없다.
- TRUE FALSE : RE가 규정되면 memory에 RE에 대한 코드는 한 개지만 RTE 내에 포트는 여러 개가 있을 수 있다. RE 자체에서는 multiple activation이 안된다. 한 instance안에서 여러 번 activation할 수 없다. Instance handle을 쓴다.
-> Inter Runnable Variable이나 Per Instance Memory를 정의하면 canBeInvokedConcurrently를 FALSE라고 해도 코드 자체에서 sysnchronization을 할 필요가 없다. 그렇지 않은 경우에는 sysnchronization 책임이 코드에 있다.
- FALSE/TRUE TRUE : RE에 대해서 multiple activation이 이루어진다. -> synchronization을 꼭 고려해야 한다.
-> RE사이에 공유하는 변수가 있을 때 option을 어떻게 규정하느냐에 따라서 global 변수를 사용하면서 생기는 mutual exclusion, synchronization 문제에 대한 책임을 RTE가 알아서 할 수 있는지 코드가 져야하는지를 결정한다.
Communication Specifications
- 포트의 성격을 정의해주는 것이다.
- Sender-Receiver
- Acknowledgment Request : data를 제대로 받았는지에 대한 receiver의 acknowledgment를 받을 것인지
- Intial value
- Invalidation
- Queued Data Buffering
- Alive Timeout : receiver쪽에 생성, sender가 살아있다면 1초에 한번씩을 data를 보내야한다. 그렇지 않으면 sender가 죽었다고 생각한다.
Implicit/Explicit communication
| Implicit/Explicit | Port | API |
---|
Send | Implicit | DataWriteAccess | IWrite |
Send | Explicit | DataSendPoint | RTE_SEND(Q), RTE_Write(unQ) |
Receiver | Implicit | DataReadAccess | IRead |
Receiver | Explicit | DataReceivePoint | RTE_RECV(Q), RTE_Read(unQ) |
Sending to a Port
- Implicit
- implicit : RE가 실행되면 API를 호출하여 data를 보내도 실제로 가지는 않고 port에다만 써지는 것(buffer에 카피)이다. 그 다음 RE가 terminate될 때 최종적으로 있는 data가 한 번 send된다. -> non-Queued
- Point : DataWriteAccess -> API : IWrite
- Explicit
- explicit : RE에서 API를 호출할때마다 실제로 data를 send한다.
- Point : DataSendPoint -> API : RTE_Write(unQ), RTE_Send(Q)
Receiving from a Port
- data가 port까지만 온다. RE가 API를 통해 호출을 해야 port에 있는 data가 넘어온다. 문제는 RE가 언제 data가 온지 어떻게 아냐는 것이다.
- Implicit
- implicit : RE가 시작될 때 연결되어 있는 send port로부터 data를 하나 받아온 다음에 API에서 receive API를 호출할 때마다 그 data만 읽어온다. 처음 받은 data만 받아온다.
- Point : DataReadAccess -> API : IRead
- Explicit
- explicit : RE에서 data를 읽어올 수 있는 API를 호출할 때마다 data를 받아온다. 새로운 data를 계속 받아온다.
- Point : DataReceivePoint -> API : RTE_Read(unQ), RTE_Recv(Q)
DataReceivePoint를 지정해주면 위의 API가 생기는 것은 똑같은데 wait point를 추가로 RE에 지정했느냐 안했느냐에 따라 non-blocking API가 생기거나 blocking API가 생긴다.
- 방법
- Polling
- 주기적으로 API를 호출함으로써 data를 가져온다.
- RE에 Timing event를 걸어 주기적으로 data를 읽는다. -> Timing event와 non-blocking RTE_API를 활용한다.
- 무조건 처음에 AUTOSTART처럼 시켜놓고 loof를 만든다. -> 이 방법은 CPU를 너무 많이 잡아먹는다.
- Event
- port가 DataReceiveEvent를 만들어 RE를 돌린다. Data가 도착하면 DataReceiveEvent가 발생하여 RE가 돈다. 그때 API를 호출해서 data를 읽어온다. -> DRE와 non-blocking RTE_API를 활용한다.
- RE가 API를 호출하면 API가 새로운 데이터가 오지 않았다면 waiting, 새로운 데이터가 오면 그때 data를 읽어서 보낸다. -> wait point 사용함으로 RTE_API는 blocking API이다.
Client-Server Communication
- synchronization
client가 server에 요청하고 data 받을 때까지 block
timer도 줄 수 있다.
- asynchronization : API 2개 필요 call과 result -> sender-receiver의 receive상황과 비슷하다.