Ở các bài trước, chúng ta đã nói về cách các software component được tổ chức và kết nối với nhau qua port, composition và connector. Bây giờ hãy nhìn vào bên trong một software component: code thực sự nằm ở đâu, và ai quyết định khi nào code đó chạy?

Câu trả lời là hai khái niệm đi cùng nhau: Runnable (đoạn code cần chạy) và Event (điều kiện khiến nó chạy).

I. Runnable là gì?

Runnable (hay runnable entity) là đoạn code nhỏ nhất được định nghĩa trên một software component. Nói đơn giản, mỗi runnable tương ứng với một hàm C nằm trong component đó.

Có vài điều cần nhớ:

  • Mỗi hàm trong file C phải được khai báo thành một Runnable trong cấu hình AUTOSAR, và khai báo luôn các interface mà nó truy cập.
  • Runnable cùng với Event sẽ được hệ điều hành (OS) lên lịch để chạy.
  • Composition SWC và Parameter SWC không có runnable, vì chúng không đi kèm file C chứa chức năng nào.

Ví dụ

Giả sử một file C của AUTOSAR định nghĩa bốn hàm: Sum, Diff, Mul, Div. Cả bốn đều được coi là runnable, nên ta phải tạo cấu hình runnable cho từng hàm. Ví dụ trong component SWC_1, ta định nghĩa runnable Sum, rồi làm tương tự với ba hàm còn lại.

Trong cấu hình, runnable nằm trong thẻ Runnable Entity. Với hàm Sum (cộng hai số), ta khai báo:

  • Data Read Access: đọc dữ liệu thô từ hai receiver port, tạm gọi là X và Y.
  • Data Write Access: ghi kết quả (tổng của hai số) ra provider port.
  • Symbol: tên hàm C chính xác. Đây là thông tin quan trọng, vì OS dùng đúng tên này để gọi hàm.

💡 Symbol phải khớp hoàn toàn với tên hàm trong file C. Sai một ký tự là OS không tìm thấy hàm để gọi.

II. Runnable truy cập interface như thế nào?

Ngoài đọc và ghi dữ liệu, runnable còn có nhiều tùy chọn khác để mô tả chi tiết hơn. Để dễ nhớ, ta gom chúng theo cách sử dụng.

1. Truy cập dữ liệu (Sender-Receiver): explicit và implicit

Trước hết cần phân biệt hai kiểu giao tiếp mà ta có thể chọn khi đọc hoặc ghi port:

  • Explicit (tường minh): dữ liệu được gửi và nhận nguyên trạng. RTE không quan tâm tính nhất quán của thông điệp, chỉ chuyển dữ liệu qua lại giữa các port.
  • Implicit (ngầm định): RTE đảm bảo tính nhất quán của dữ liệu giữa các bên nhận, bằng cách tạo bộ đệm riêng cho từng receiver.

Hai kiểu này tương ứng với các cấu hình khác nhau:

Cấu hình Dùng cho
Data Read Access / Data Write Access Giao tiếp implicit: RTE lo tính nhất quán giữa sender và nhiều receiver
Data Received by Argument / by Value Giao tiếp explicit khi đọc port
Data Send Giao tiếp queued (xếp hàng): RTE tạo hàng đợi lưu dữ liệu từ sender rồi chuyển cho receiver khi được yêu cầu

2. Truy cập tham số (Parameter)

Tham số hiệu chỉnh (calibration) chỉ đọc được, không ghi được từ phần mềm. Vì vậy chỉ có một cấu hình duy nhất là Parameter Access, dùng để khai báo runnable sẽ đọc một tham số calibration.

3. Mode Switch

Với port thuộc loại mode switch, có hai lựa chọn:

  • Mode Access Point: dùng khi runnable có receiver port và chỉ cần đọc mode hiện tại.
  • Mode Switch Point: dùng khi runnable có provider port, tức là hàm tự quyết định và đặt (chuyển) mode.

4. Truy cập biến cục bộ (Local Interface)

Các biến cục bộ không gắn với port nào, vì chúng không được gửi hay nhận từ component bên ngoài. Thay vào đó là các interface nằm trong phạm vi nội bộ của component, ví dụ IRV (Inter-Runnable Variable): biến dùng chung giữa các runnable trong cùng một component.

Truy cập kiểu này được khai báo bằng Read Local Variable và Write Local Variable.

5. Client-Server

Như đã thấy ở phần client-server, client có thể gọi server theo hai cách:

  • Đồng bộ (synchronous): khai báo bằng Synchronous Server Call Point.
  • Bất đồng bộ (asynchronous): server được kích hoạt, kết quả trả về sau. Để đọc kết quả, ta dùng Asynchronous Server Call Result Point.

6. Trigger

Trigger có hai loại: internal và external. Chúng gắn với các trigger port và được cấu hình dựa trên trigger interface.

7. Thuộc tính chung

  • Can be invoked concurrently (true/false): cho biết runnable có được phép gọi đệ quy hoặc song song trên nhiều task khác nhau hay không. Thiết lập này quan trọng khi OS lên lịch cho runnable.
  • Symbol: như đã nói, phải khớp với tên hàm C.

Tóm lại, cấu hình của runnable phải chứa toàn bộ thông tin về các interface và port mà nó truy cập, bằng một hoặc nhiều tùy chọn ở trên.

III. Event là gì?

Event là cấu hình bổ sung cho runnable, cho OS biết khi nào và bằng cách nào phải gọi (lên lịch) runnable.

Runnable được ánh xạ tới các RTE Event, rồi OS và lớp RTE phối hợp để đảm bảo hàm được gọi đúng như mong đợi. Khi OS cần khởi động runnable lúc event xảy ra, RTE Event có thể tham chiếu trực tiếp tới runnable cần chạy. Khi mô tả component dùng tính năng này, OS có trách nhiệm khởi động runnable lúc event xảy ra.

ℹ️ AUTOSAR không phân loại event như dưới đây. Đây là cách gom nhóm theo mục đích sử dụng để dễ hiểu và dễ nhớ.

1. Event chung

Event Ý nghĩa
Init Event Runnable chỉ được gọi một lần, dùng để khởi tạo phần mềm lúc khởi động
Timing Event OS gọi runnable theo chu kỳ. Ví dụ cần gọi mỗi 100 ms thì tạo timing event và ánh xạ runnable vào đó
Trigger Event (External / Internal Trigger Occurred) Runnable chỉ chạy khi có trigger xảy ra, gắn với một trigger interface
Background Event Runnable chạy nền, OS gọi chúng khi core đang rảnh

2. Event của Client-Server

  • Operation Invoked Event: dùng ở phía server. Runnable được gọi khi client yêu cầu server thực thi, bằng lời gọi đồng bộ hoặc bất đồng bộ.
  • Asynchronous Server Call Returns Event: phát sinh khi một lời gọi server bất đồng bộ hoàn tất. Runnable gắn với event này sẽ được gọi lúc đó.

3. Event liên quan đến dữ liệu

Runnable cũng có thể được kích hoạt dựa trên dữ liệu:

  • Data Write Completed / Data Send Completed: gắn với provider port. Gọi runnable khi dữ liệu đã được gửi đi trên port.
  • Data Received / Data Receive Error: gắn với receiver port. Kích hoạt khi nhận được dữ liệu, hoặc khi có lỗi lúc nhận.

Loại event này thường dùng để tối ưu thời gian chạy: chức năng chỉ chạy khi cần, không chạy liên tục.

4. Event liên quan đến Mode

Gắn với port có interface mode switch. Các mode dùng khi hệ thống có những trạng thái định trước, và event đặc biệt giúp tận dụng mode hiệu quả hơn.

  • Mode Switch Event: kích hoạt runnable khi một mode đổi trạng thái. Ví dụ với mode của đèn pha, ta có thể gọi một runnable mỗi khi đèn chuyển sang ON hoặc OFF.
  • Mode Manager Error Event và Mode Switch Acknowledgement Event: dùng khi có lỗi xảy ra, hoặc khi việc chuyển mode được xác nhận.

IV. Ghép Runnable với Event

Quay lại ví dụ SWC_1 có bốn runnable. Mỗi runnable phải được ánh xạ tới một event để được kích hoạt:

Mỗi runnable ánh xạ tới một event

Runnable Event Khi nào được gọi
Sum Timing Event Luôn luôn, theo chu kỳ thời gian cố định
Diff Operation Invoked Event Mỗi khi client gọi qua port client-server
Mul Data Received Event Mỗi khi có dữ liệu mới trên một receiver port
Div Mode Switch Event Chỉ khi một mode cụ thể được kích hoạt

V. Cấu hình mẫu

Dưới đây là dạng cấu hình ARXML (rút gọn, chỉ giữ các phần chính). Event được khai báo phía trên, bên cạnh các runnable, và loại event được phân biệt bằng tên thẻ, mỗi loại có thuộc tính riêng.

<RUNNABLE-ENTITY>
  <SHORT-NAME>Sum</SHORT-NAME>
  <CAN-BE-INVOKED-CONCURRENTLY>false</CAN-BE-INVOKED-CONCURRENTLY>
  <!-- DATA-READ-ACCESSES: đọc X và Y từ hai receiver port -->
  <!-- DATA-WRITE-ACCESSES: ghi kết quả ra provider port -->
  <SYMBOL>Sum</SYMBOL>
</RUNNABLE-ENTITY>

<TIMING-EVENT>
  <SHORT-NAME>TE_Sum_100ms</SHORT-NAME>
  <START-ON-EVENT-REF DEST="RUNNABLE-ENTITY">.../Sum</START-ON-EVENT-REF>
  <PERIOD>0.1</PERIOD>
</TIMING-EVENT>

Một vài điểm cần để ý:

  • Timing Event tham chiếu tới runnable cần gọi và có thêm thuộc tính period. Chu kỳ tính theo giây, nên 0.1 nghĩa là 100 ms.
  • Init Event chỉ gọi một lần và không có period, chỉ có tham chiếu tới runnable chạy lúc khởi tạo.
  • Data Received Event gắn với một receiver port: có tham chiếu tới port đó và runnable cần gọi.
  • Operation Invoked Event dành cho client-server, đặt phía server (nơi có provider port): có tham chiếu tới provider port và operation của client-server interface tương ứng.

VI. Tổng kết

  • Runnable là hàm C nhỏ nhất trên component. Mỗi hàm phải được khai báo thành runnable cùng với các interface nó truy cập, và Symbol phải khớp tên hàm.
  • Composition SWC và Parameter SWC không có runnable.
  • Cách truy cập interface (dữ liệu implicit/explicit, parameter, mode, biến cục bộ, client-server, trigger) được cấu hình ngay trong runnable.
  • Event cho OS biết khi nào gọi runnable: theo chu kỳ, khi khởi tạo, khi có trigger, khi có dữ liệu, khi client gọi, hoặc khi mode đổi.
  • Mỗi runnable cần được ánh xạ tới một event để thực sự được kích hoạt.

Hy vọng bài này giúp bạn chọn được event phù hợp với từng nhu cầu của phần mềm.