자동차 전자 제어기(ECU) 소프트웨어가 거대해지고 복잡해짐에 따라 소프트웨어를 독립적인 부품처럼 분리하고 재사용하는 아키텍처가 필수가 되었습니다. AUTOSAR(AUTomotive Open System ARchitecture)는 이를 위해 애플리케이션 로직을 SWC(Software Component) 단위로 모듈화하고, 컴포넌트 간의 모든 통신을 규격화된 포트(Port)와 포트 인터페이스(Port Interface)를 통해 처리하도록 설계했습니다.
하지만 실제 전장 프로젝트에서 설계를 진행하다 보면 다음과 같은 실무적인 의문들을 자주 마주하게 됩니다.
- 포트(Port)와 포트 인터페이스(Port Interface)는 개념적으로 어떻게 다른가?
- RTE API에서
Rte_Read와Rte_IRead는 왜 구분되어 있으며, 데이터 일관성에 어떤 영향을 주는가? - 같은 SWC 내부에 존재하는 두 개 이상의 러너블(Runnable) 간 데이터는 포트로 연결해야 하는가, 전역변수로 다뤄야 하는가?
이 글에서는 포트와 포트 인터페이스의 기본 원리부터 시작하여 S/R, C/S 인터페이스, Explicit/Implicit 데이터 접근 방식, 그리고 동일 SWC 내 러너블 간 통신 메커니즘인 IRV(Inter-Runnable Variable)까지 실무 관점에서 체계적으로 정리합니다.
1. 포트(Port)와 포트 인터페이스(Port Interface)의 개념 구분
AUTOSAR에서 컴포넌트 간 통신을 구성할 때 가장 먼저 이해해야 할 기초는 포트와 포트 인터페이스의 관계입니다.
- 포트(Port): SWC의 외부에 노출된 통신 창구(엔드포인트)입니다.
- P-Port (Provide Port,
O): 데이터를 송신하거나 특정 기능을 외부에 제공하는 포트입니다. - R-Port (Require Port,
)): 데이터를 수신하거나 외부의 서비스를 호출하는 포트입니다. - PR-Port (Provide-Require Port): 양방향으로 데이터를 송수신하거나 서비스를 교환하는 복합 포트입니다.
- P-Port (Provide Port,
- 포트 인터페이스(Port Interface): 포트를 통해 무엇을 주고받을지 정의한 계약 규격(Contract)입니다. 전달할 데이터의 타입, 구조, 혹은 호출할 함수의 시그니처와 에러 코드 등을 기술합니다.
벽에 설치된 콘센트 구멍이 포트라면, 그 콘센트가 지원하는 전압 규격(220V 60Hz)이 포트 인터페이스에 해당합니다. 동일한 인터페이스 규격을 만족해야만 두 포트를 연결할 수 있습니다.
VFB(Virtual Function Bus)와 위치 투명성(Location Transparency)
SWC 내부 로직은 상대방 SWC가 어디에 배치되어 있는지 알지 못하며, 알 필요도 없습니다.
[SWC 1] ── (P-Port) ──> [ RTE / VFB ] ──> (R-Port) ──> [SWC 2]
│
┌────────────────┴────────────────┐
▼ ▼
[ Case A: 단일 ECU ] [ Case B: 복수 ECU ]
메모리 버퍼 복사 / OS 이벤트 COM 스택 / CAN / Ethernet 전송
- 두 SWC가 같은 코어 내 동일 태스크에 있다면 단순 메모리 참조나 버퍼 복사로 처리됩니다.
- 두 SWC가 서로 다른 ECU에 물리적으로 떨어져 있다면, RTE 아래의 BSW(COM 스택, CAN, Ethernet 드라이버)가 네트워크 프레임으로 직렬화하여 전송합니다.
이처럼 통신 인프라와 애플리케이션 코드를 완전히 분리해 주는 특성을 위치 투명성(Location Transparency)이라고 합니다.
2. 주요 포트 인터페이스 종류
AUTOSAR 사양에는 다양한 목적의 포트 인터페이스가 정의되어 있습니다.
| 인터페이스 종류 | 통신 모델 | 주요 목적 | 대표 사용 예시 |
|---|---|---|---|
| Sender-Receiver (S/R) | 일방향 데이터 전달 (생산자-소비자) | 센서값, 상태 플래그 주기적 공유 | 차량 속도, 조향각, 휠 RPM |
| Client-Server (C/S) | 양방향 서비스 호출 (RPC 모델) | 특정 기능 실행 요청 및 반환값 수신 | 플래시 메모리 쓰기, 진단 세션 제어 |
| Mode Switch (M/S) | 상태 전이 통보 | 시스템/ECU 모드 전환 관리 | Startup, Run, Sleep, PostRun 전이 |
| Trigger | 이벤트 트리거 (데이터 없음) | 특정 시점의 실행 기동 통지 | 인터럽트 기반 연산 실행 요청 |
| Parameter | 상수 / 캘리브레이션 | 제어 파라미터 값 공유 | 제어기 PID 게인값, 오프셋 설정 |
| NvData | 비휘발성 데이터 접근 | NVRAM 데이터 읽기/쓰기 인터페이스 | 누적 주행거리, 고장 코드(DTC) 이력 |
2.1 Sender-Receiver (S/R) 인터페이스
S/R 인터페이스는 하나 이상의 데이터 요소(Data Element)로 구성됩니다. 송신자(Sender)가 데이터를 보내면 하나 이상의 수신자(Receiver)가 이를 전달받는 일대일 또는 일대다(1:N) 통신을 지원합니다.
데이터 버퍼 처리 방식에 따라 두 가지로 구분됩니다.
- Non-queued (기본 모드)
- 새로운 데이터가 도착하면 기존 버퍼의 데이터를 덮어씁니다.
- 주기적으로 갱신되는 센서 데이터처럼 항상 최신값이 중요한 경우에 사용합니다.
- Queued
- 수신 측에 FIFO 큐가 생성되어 데이터가 순차적으로 저장됩니다.
- 큐가 가득 차면 설정에 따라 오버플로우 에러가 발생하거나 가장 오래된 데이터가 유실됩니다.
- 누락 없이 모든 이벤트를 순서대로 처리해야 하는 경우에 사용합니다.
2.2 Client-Server (C/S) 인터페이스
C/S 인터페이스는 클라이언트가 서버에 작업을 요청하고 결과를 받는 모델입니다. 하나 이상의 오퍼레이션(Operation)을 가질 수 있습니다.
- 인자 방향(Argument Direction):
IN: 클라이언트에서 서버로 전달하는 입력값OUT: 서버가 처리 후 클라이언트에 돌려주는 출력값INOUT: 입출력 겸용 값
- 에러 처리:
RTE 표준 반환값:RTE_E_OK,RTE_E_TIMEOUT등 통신 인프라 상태 반환Application Errors: 인터페이스에 정의된 사용자 정의 오류 (예:ERR_RANGE_OVER,ERR_BUSY)
- 호출 방식:
- 동기(Synchronous): 서버의 처리가 끝날 때까지 클라이언트 러너블의 실행이 블로킹됩니다.
- 비동기(Asynchronous): 클라이언트는 호출(
Rte_Call) 직후 반환되며, 별도 시점에 완료 여부를 확인(Rte_Result)하거나 서버 완료 이벤트를 받아 결과를 처리합니다.
3. 데이터 접근 방식: Explicit(명시적) vs Implicit(묵시적) 통신
S/R 인터페이스 모델링에서 가장 중요한 설정 중 하나는 데이터 접근 모드(Data Access Mode)입니다. 같은 S/R 인터페이스라도 접근 방식을 Explicit으로 하느냐, Implicit으로 하느냐에 따라 생성되는 C API와 메모리 동작 메커니즘이 완전히 달라집니다.
3.1 Explicit Communication (명시적 통신)
개발자가 러너블 코드 내부에서 API를 호출하는 바로 그 시점에 RTE 버퍼를 직접 읽거나 씁니다.
- 생성 API 형태:
/* 반환값으로 에러 코드를 넘기고, 포인터 변수에 실제 값을 채워 넣음 */ Std_ReturnType Rte_Read_<Port>_<DataElement>(<DataType>* data); Std_ReturnType Rte_Write_<Port>_<DataElement>(<DataType> data); - 동작 특징:
- 호출 시점의 가장 최신 데이터를 즉시 가져올 수 있습니다.
- 별도의 복사 버퍼를 최소화하여 메모리 사용량이 적습니다.
- 주의점 (데이터 불일치 문제):
- 러너블 실행 도중 더 높은 우선순위의 태스크가 끼어들어(Preemption) 동일한 데이터 요소를 갱신하면, 러너블 앞부분에서 읽은 값과 뒷부분에서 읽은 값이 달라질 수 있습니다.
3.2 Implicit Communication (묵시적 통신)
러너블이 실행되기 직전, RTE가 해당 러너블이 참조하는 모든 입력 데이터의 스냅샷(Local Copy)을 만듭니다. 러너블이 실행되는 동안에는 오직 이 로컬 복사본만을 읽습니다. 출력 데이터 또한 로컬 버퍼에 임시 저장되었다가 러너블이 완전히 종료되는 시점에 RTE가 실제 버퍼로 한 번에 반영합니다.
- 생성 API 형태:
/* 포인터 없이 값 자체를 직접 반환 (주로 인라인 함수나 매크로로 생성) */ <DataType> Rte_IRead_<Runnable>_<Port>_<DataElement>(void); void Rte_IWrite_<Runnable>_<Port>_<DataElement>(<DataType> data); - 동작 특징:
- 데이터 일관성(Data Consistency) 보장: 러너블 실행 도중 외부에서 어떤 태스크가 데이터를 덮어쓰더라도 해당 러너블이 관찰하는 값은 변하지 않습니다.
- 알고리즘 연산(조향 제어, 모터 속도 제어 등) 중간에 기준값이 바뀌어 연산 결과가 튀는 현상을 원천 차단합니다.
- 주의점:
- 러너블마다 로컬 스냅샷 버퍼 공간이 추가로 필요하므로 RAM 소모량이 증가합니다.
- 러너블 실행 중간에 도착한 새로운 데이터는 다음 실행 주기까지 반영되지 않습니다.
3.3 Explicit vs Implicit 비교
| 항목 | Explicit Access (명시적) | Implicit Access (묵시적) |
|---|---|---|
| API 접두사 | Rte_Read_... / Rte_Write_... |
Rte_IRead_... / Rte_IWrite_... |
| 버퍼 접근 시점 | API 호출 시점 즉시 접근 | 러너블 시작 시 일괄 읽기 / 종료 시 일괄 반영 |
| 데이터 일관성 | 실행 도중 값 변동 가능 (Race Condition 주의) | 완벽한 일관성(Atomic Snapshot) 보장 |
| 반환값 | 통신 상태 코드 (Std_ReturnType) |
데이터 값 자체 (DataType) |
| RAM 메모리 | 상대적으로 적음 | 상대적으로 많음 (스냅샷 버퍼 필요) |
| 권장 용도 | 단순 상태 조회, 즉각적인 최신성이 중요한 데이터 | 제어 알고리즘 연산, 멀티태스크/멀티코어 환경 |
4. 동일 SWC 내 러너블 간 데이터 교환: Inter-Runnable Variable (IRV)
시스템 설계 시 빈번하게 나타나는 요구사항 중 하나는 "동일한 SWC 내에 존재하는 서로 다른 러너블 간의 데이터 전달"입니다.
예를 들어 10ms 주기로 센서 원시 데이터를 필터링하는 러너블(Producer)이 있고, 100ms 주기로 이 필터링된 값을 기반으로 고장 진단을 수행하는 러너블(Consumer)이 있을 때입니다.
왜 포트 루프백이나 C 전역변수(static)를 쓰지 않는가?
- 포트 루프백(Loopback)의 비효율성
- SWC 외부에 P-Port와 R-Port를 만들어서 자기 자신끼리 연결할 수 있습니다.
- 하지만 이렇게 하면 불필요한 포트와 커넥터가 증가하고, 내부 전용 데이터가 외부에 노출되어 모듈 캡슐화가 깨지며, RTE 설정 복잡도와 오버헤드가 늘어납니다.
- C 전역변수(
static) 직접 사용의 위험성- 두 러너블의 주기가 다르면 OS 상에서 서로 다른 Task에 매핑될 가능성이 높습니다.
- 공유 전역변수에 동시 접근할 때 데이터 오염(Race condition)을 막기 위해 개발자가 직접 인터럽트 락이나 OS Resource를 제어해야 하며, 이는 AUTOSAR의 추상화 규칙을 위배합니다.
이 문제를 해결하기 위해 AUTOSAR는 SWC 내부 전용 공유 변수인 IRV(Inter-Runnable Variable)를 표준 메커니즘으로 제공합니다. RTE가 러너블 간의 태스크 매핑과 우선순위를 분석하여 최적의 동기화 코드(뮤텍스, 락, 이중 버퍼 등)를 자동으로 생성해 줍니다.
4.1 IRV의 두 가지 모드
IRV 역시 일반 포트 통신과 마찬가지로 Implicit과 Explicit 두 가지 모드로 구성할 수 있습니다.
1) Implicit IRV
러너블 진입 시점에 값을 읽고, 종료 시점에 값을 기록합니다. 실행 도중 일관성이 유지됩니다.
/* 읽기 (Consumer) */
uint32 val = Rte_IrvIRead_Runnable_100ms_FilteredSpeed();
/* 쓰기 (Producer) */
Rte_IrvIWrite_Runnable_10ms_FilteredSpeed(calculated_speed);
2) Explicit IRV
러너블 내부에서 함수를 호출하는 시점에 즉시 읽거나 씁니다.
/* 읽기 (Consumer) */
uint32 val = Rte_IrvRead_Runnable_100ms_FilteredSpeed();
/* 쓰기 (Producer) */
Rte_IrvWrite_Runnable_10ms_FilteredSpeed(calculated_speed);
5. 포트 연결(Connector)과 호환성 규칙
설계된 포트들은 상위 레벨(Composition)에서 커넥터(Connector)를 통해 물리적/논리적으로 결합됩니다.
[ Upper Composition Component ]
+-----------------------------------------------------------------+
| Delegation Connector |
| ┌───) (External System Port) |
| │ |
| │ +-------------------+ +-------------------+ |
| └──>) R-Port | | P-Port O───┐ |
| | SWC A | | SWC B | │ │
| | P-Port O============>) R-Port | │ │
| +-------------------+ +-------------------+ │ │
| Assembly │ │
| Connector │ │
+---------------------------------------------------------------│-+
└──> Delegation
- Assembly Connector: 동일 계층 내 두 SWC의 P-Port와 R-Port를 1:1로 직접 연결합니다.
- Delegation Connector: 하위 SWC의 포트를 상위 Composition의 외부 경계 포트로 위임(전달)할 때 사용합니다.
포트 호환성(Port Compatibility) 검증 규칙
ARXML 모델링 단계에서 P-Port와 R-Port를 연결하기 위해서는 다음 조건이 반드시 일치해야 유효성 검사(Validation)를 통과합니다.
- 포트 인터페이스 타입 일치: S/R 포트는 S/R 포트끼리, C/S 포트는 C/S 포트끼리만 연결할 수 있습니다.
- 데이터 요소 및 오퍼레이션 서명 일치:
- S/R의 경우 데이터 요소의 이름, 개수, 데이터 타입(Base Type, Constraints)이 일치해야 합니다.
- C/S의 경우 오퍼레이션 이름, 매개변수 개수, 인자 방향(
IN,OUT,INOUT), 반환 타입 및 Application Error 정의가 완전히 호환되어야 합니다.
- 큐(Queue) 속성 일치: P-Port가 Non-queued인데 R-Port가 Queued이거나 그 반대일 수 없습니다.
6. 실무 설계 흐름 및 요약
새로운 통신 요구사항을 구현할 때 다음 의사결정 트리를 참고하면 설계 실수를 줄일 수 있습니다.
[ 통신 요구사항 분석 ]
│
▼
Q1. 데이터 전달인가, 원격 작업/함수 호출인가?
├─> 작업 요청 / 결과 반환 ──────> [ Client-Server (C/S) ]
└─> 상태값 / 데이터 공유
│
▼
Q2. 동일 SWC 내부 러너블 간 통신인가?
├─> Yes (내부 통신) ─────────────> [ Inter-Runnable Variable (IRV) ]
└─> No (SWC 간 통신) ───────────> [ Sender-Receiver (S/R) ]
│
▼
Q3. 연산 도중 데이터 일관성(스냅샷)이 필수적인가?
├─> Yes (제어 알고리즘, 멀티코어) ─> [ Implicit Access (`Rte_IRead/IWrite`) ]
└─> No (실시간 단순 모니터링) ────> [ Explicit Access (`Rte_Read/Write`) ]
실무 설계 시 주의해야 할 점
- ECU 간 통신에서 동기식 C/S 남발 금지
동기식 C/S 호출은 서버의 처리가 끝날 때까지 호출자(Client) 러너블을 멈추게(Wait/Blocking) 만듭니다. 만약 서버 SWC가 다른 ECU에 위치하여 CAN이나 Ethernet 통신을 거쳐야 한다면, 네트워크 지연으로 인해 클라이언트 태스크의 데드라인을 놓치는 치명적인 문제가 발생할 수 있습니다. ECU 간 통신에는 S/R을 사용하거나 비동기(Asynchronous) C/S를 채택해야 합니다. - 대용량 구조체에서의 Implicit 통신 버퍼 비용
Implicit 통신은 스냅샷 복사본을 생성하므로 데이터 일관성을 지키는 데 매우 안전하지만, 고화질 이미지 버퍼나 수 킬로바이트 단위의 구조체에 무분별하게 적용할 경우 RAM 사용량이 급격히 늘어납니다. - SWC 내부 데이터는 포트 대신 IRV 활용
SWC 내부 러너블끼리의 데이터 교환은 외부 포트 루프백 대신 반드시 IRV를 사용해야 인터페이스 오버헤드를 줄이고 데이터 은닉성을 유지할 수 있습니다.