- TinyOS와 NesC
TinyOS는 미국 UC Berkeley 대학에서 개발된 무선 센서 네트워크를 위한 전용 운영체제 이다.
이름에서도 알 수 있듯이, TinyOS 기반의 프로그램들은 매우 작은 용량의 크기(대부분 30Kbytes 이하)로 컴파일되며, 무선 센서 노드의 일반적인 특징(최소한의 하드웨어, 작은 메모리, 낮은 CPU 성능 그리고 한정된 에너지)를 고려하여 최적화된 운영체제이다. TinyOS는 보다 편리한 프로그램 개발을 위해 클래스 형태의 컴포넌트(Componet) 구조를 가지는 NesC 언어로 구현되어 있다.
- NesC
NesC와 같은 컴포넌트 모델 언어는 여러 개의 컴포넌트 블록(Block)들을 컴파일 시 연결[와이어링wiring)]하여 하나의 애플리케이션 형태로 조합한다. 또한 센서 노드에 올라갈 하나의 애플리케이션을 위해, 꼭 필요한 라이브러리 및 커널 컴포넌트들만을 선택하여 컴파일하기 때문에 매우 효과적으로 코드 크기를 줄일 수 있다. NesC의 문법은 기존에 많이 사용되고 있는 C 언어와 비슷하지만 표 1-1과 같은 차이점이 있다.
표 1-1 NesC의 특징 분석
NesC 특징 | |
형태 |
컴포넌트 기반 |
개발 |
기존 C에 비해 편리함 - 필요한 컴포넌트들만 연결해 주면 원하는 프로그램 작성 가능 동시성 모델 지원 - “Task"와 "H/W Event Handler" 두 스레드(thread) 사용 데이터 경쟁 조건 - 두 종류의 스레드 사이의 선점(preemption)으로 발생할 수 있는 데이터 경쟁 조건(data race condition)을 컴파일 시에 감지 가능 |
코드크기 |
매우 작음 - 소규모 임베디드 장비에 최적화 |
제한점 |
동적 메모리 없음 |
컴포넌트는 어려운 개념이 아니고, C++나 자바와 같은 객체 언어에서 사용하는 클래스와 비슷한 의미라고 생각하면 이해하기 편할 것이다. NesC에서 사용하는 컴포넌트 관련 용어들은 표 1-2에 기술되어 있다.
표 1-2 NesC에서 사용하는 용어
용어 및 내용 | |
application |
하나 이상의 컴포넌트로 구성되며, 실제 센서노드에서 실행 가능한 하나의 프로그램 |
interface |
2개의 컴포넌트 사이를 연결하기 위해 정의된 포트로, 컴포넌트는 여러 개의 interface를 사용할 수 있으며, 이 interface를 이용하여 command 및 event가 처리된다. 두 컴포넌트 사이의 연결 통로(인터페이스)를 연결하는 것을 와이어링(wiring)이라고 한다. |
component |
component - NesC application을 구성하는 기본 블록으로, 컴포넌를 정의하는 configuration과 module로 구분된다. |
configuration - 하나의 NesC application에 사용되는 컴포넌트들을 선언하고, 이들 간을 연결(와이어링)을 어떻게 정의할 것인가에 대한 기술한다. configuration도 하나의 컴포넌트로서 정의된다. | |
module - 새로운 컴포넌트의 동작 및 다른 컴포넌트들과의 연동을 실제로 구현하는 곳이다. |
- interface 일반적인 형태
interface identifier {
command result_t function_name prototype
event result_t function_name prototype
}
identifier : 이 인터페이스를 제공하는 컴포넌트의 이름을 의미한다.
function_name : 이 인터페이스가 제공하는 함수 이름을 의미한다.
command, event : 인터페이스 형태
인터페이스의 선언형
command |
event |
command로 정의된 함수는 현 컴포넌트의 module 부분에 구현된 함수로서, 현 컴포넌트를 사용하는 상위 컴포넌트에서 'call' 명령을 통해 호출된다. |
event로 정의된 함수는 현 컴포넌트를 사용하는 상위 컴포넌트에 구현되어야 하는 함수로서, 특정 인터럽트나 조건이 만족되었을 경우, 현 컴포넌트가 어떤 정보를 상위 컴포넌트에게 전달하기 위해 'signal' 명령을 통해 호출된다. |
- 컴포넌트 일반적인 형태
configuration identifire{
prvoides{
interface interface_name1
}
}
implementation{
components identifierM, com1, com2 ...
interface_name1 = identifierM.interface_name1
identifierM.interface_name2 -> com1.interface_name3
com1.interface_name3 <- identifierM.interface_name2
}
identifier : 선언된 컴포넌트 이름을 의미하며, 그 안에는 현 컴포넌트에서 제공하는 인터페이스(interface_name1)가 선언되어 있다.
implementation : 현 컴포넌트에서 사용할 하부 컴포넌트들(identifierM, com1, com2...)이 차례대로 선언된다. 그 중 identifierM이라는 이름의 컴포넌트는 현 컴포넌트의 실제 구현 부분인 module 파일을 나타내고 있는 것으로 다른 하부 컴포넌트인 com1, com2와 구별된다.
와이어링 : 와이어링은 모듈 사이의 인터페이스 간 연결 방법을 나타내는 것으로, 그들 간의 인터페이스 이름이 같아야 한다. 컴파일 시 인터페이스 함수의 매개변수가 다음 조건에 해당하면 에러가 발생한다.
1. 매개변수가 정수가 아닌 경우
2. 한쪽의 인터페이스만 매개변수를 가진 경우
3. 매개변수 값이 원하는 값보다 크거나 작은 경우
4. 타입이 맞지 않을 경우
일단 와이어링이 되면 인터페이스에 정의된 command, event 함수의 사용이 가능하게 된다.
interface1 = interface2
2개의 interface가 같음을 의미하며, 양쪽 interface가 서로 같은 제공자이거나 사용자인 경우와 한쪽은 제공자이고 다른 쪽은 사용자인 경우를 의미한다.
interface1 -> interface2
interface의 구성 함수가 링크되어 있음을 의미한다. 즉, interface1에서 사용한 함수가 interface2에 구현되어 있음을 나타낸다.
interface1 <- interface2
interface2 -> interface1과 동일한 표기 방법이다.