NesC는 TinyOS의 실행 모델과 구조적인 개념을 표현하기 위하여 C언어를 확장하여 만든 새로운 프로그래밍 언어
NesC와 같은 컴포넌트 모델 언어는 여러 개의 컴포넌트 블록(block)들을 컴파일 시 연결하여 하나의 애플리케이션 형태로 조합한다.
센서 노드에 올라갈 하나의 애플리케이션을 위해 꼭 필요한 라이브러리 및 시스템 컴포넌트들만을 선택하여 컴파일하기 때문에 매우 효과적으로 코드 크기를 줄인다.
NesC의 문법은 기존에 많이 사용되고 있는 C언어와 유사하지만 다른 특징이 있다.
형태 - 컴포넌트 기반
잠정 - 기존에 비해 편리함(필요한 컴포넌트들만 연결해 주면 원하는 프로그램 작성 가능)
- 동시성 모델 지원("Task"와 "H/W Event handler" 사용)
- 데이터 경쟁 조건 - 두 종류의 task간의 선점(Preemption)으로 발생할 수 있는 데이터 경쟁 조건(Data Race Condition)을 컴파일 시에 감지 가능
코드사이즈 - 매우작음(소규모 임베디드 장비에 최적화)
제한점 - 동적 메모리 할당 없음
NesC의 특징 요약
Application
하나 이상의 컴포넌트로 구성되며, 실제 센서 노드에서 실행 가능한 하느의 프로그램
Interface
두 개의 컴포넌트 사이를 연결하기 위해 정의된 함수들의 모임.
컴포넌트는 여러개의 interface 를 사용할수 있으며 interface를 이용하여 command 및 event 가 처리된다.
두 컴포넌트 사이의 인터페이스를 연결하는 것을 wiring 이라고 한다.
NesC에서 사용하는 용어
Component
Component - NesC Application을 구성하는 기본 블록으로, 컴포넌트를 정의하는 configuration과 module로 구분된다.
Configuration - 하나의 NesC Application에 사용되는 컴포넌트들을 선언하고, 이들간의 연결(wiring)을 어떻게 정의할 것인가에 대해 기술
Module - 새로운 컴포넌트의 동작 및 다른 컴포넌트들과의 연동을 실제로 구현하는 곳
Keyword
1. provides : 정의된 인터페이스가 해당 컴포넌트에 의하여 제공
2. uses : 정의된 인터페이스가 모듈에서 프로그램 시 사용
3. command : 상위 컴포넌트에게 제공하는 인터페이스 함수
4. event : 상위 컴포넌트들에게 signal해주는 인터페이스 callback 함수
인터페이스
NesC에서 인터페이스는 양방향성을 가지며, 제공자(provider)와 사용자(user)가 되는 컴포넌트를 연결하는 포트의 역할을 수행
inerface는 커맨드(command)와 이벤트(event) 타입의 함수로 정의
일반적인 기술 형태
interface identifier{
command result_t function_name(....);
event result_t function_name(.....);
}
기술된 identifier 는 이 인터페이스 의 이름을 의미하고, function_name은 이 인터페이스가 제공하는 함수 이름을 의미한다.
제공되는 인터페이스의 형태는 커맨드(command)와 이벤트(event)로 나눌 수 있음
인터페이스의 선언형
command
이 인터페이스를 제공하는 컴포넌트의 module 부분에 구현
현 컴포넌트를 사용하는 상위 컴포넌트에서 'call' 명령을 통해 호출
Event
이 인터페이스를 사용하고 있는 컴포넌트에 원형이 구현
인터럽트나 조건이 만족될 경우, 어떤 정보를 상위 컴포넌트에게 전달하기 위해 'signal' 명령을 통해 호출
커맨드 함수는 상위 컴포넌트로부터 호출되며 그 구현 내용은 현재 컴포넌트의 실제 동작을 기술 하고 있는 모듈 파일에 존재 해야함
이벤트 함수는 이벤트가 완료됨을 상위 컴포넌트에게 알려주기 위해 존재
인터페이스 종류
Read.nc
ADC에 인터페이스
I2CPacket.nc
I2C버스 프로토콜 인터페이스
Leds.nc
LED 추출 인터페이스
LogWrite.nc
Radio.nc
Receive.nc
Send.nc
StdControl.nc
Timer.nc
컴포넌트
TinyOS에서는 앞으로 설명한 인터페이스를 통해 다른 컴포넌트와의 연결 및 서로간의 함수 호출이 가능
하나의 컴포넌트는 자신이 사용할 하위 컴포넌트들을 선언하고, 그들간의 연결을 정의하는 configuration 파일과 자신의 구현내용을 기술하고 있는 모듈파일로 이루어짐
일반적으로 <컴포넌트 이름>.nc 또는 <컴포넌트 이름>C.nc 와 같은 파일명은 인터페이스난 configuration 에서 사용
<컴포넌트 이름>P.nc 혹은 <컴포넌트 이름>M.nc 같은 형식은 모듈을 위해 사용되는 파일
1) Configuration 파일
컴포넌트들 사이의 연결을 Wiring 이라고 하며, 그 종류는 세가지 타입이 있다.
interface 1 = interface 2
2개의 인터페이스가 같음을 의미, 해당 인터페이스가 provide될때 사용됨
interface 1 -> interface 2
인터페이스의 구성함수가 링크외어 있음을 의미
즉, interface1에서 사용한 인터페이스 함수들은 interface2에 구현되어 있음을 나타냄
interface <- interface 2
interface 2 -> interface1 과 동일한 표기 방법
Wiring은 모듈 사이의 인터페이스를 연결하는 것을 의미하며, 이때 연결되는 인터페이스들 간의 이름은 같아야 함
컴파일 시, 인터페이스 함수의 매개변수가 다음 조건에 해당하면 에러가 발생
1. 매개변수가 정수가 아닌경우
2. 한쪽의 인터페이스만 매개변수를 가진 경우
3. 매개변수 값이 원하는 값보다 크거나 작은 경우
4. 타입이 맞지 않을 경우
2) 모듈(module)
모듈 파일에는 해당 컴포넌트의 실제 구현에 대한 내용이 기술
Case1.
module identifier {
provides {
interface a;
interface b;
}
uses {
interface x;
interface y;
}implementation
} implementaion {
...
...
}
Case 2.
module identifier {
provides interface a;
provides interface b;
uses interface x;
uses interface y;
} implemetation {
....
....
}
module 뒤의 identifier 는 구현할 컴포넌트 이름을 의미
{ } 안에는 모듈에서 제공(provide)하는 인터페이스와 사용(use)할 인터페이스를 정의한다.
provide에 기술된 인터페이스의 커맨드 함수들은 implementation{} 부분에 꼭 구현되어야 한다.
Task와 이벤트
TinyOS에서 처리되는 작업들은 크게 Task와 Event로 나눔
TinyOS에서의 Task는 간단한 컴퓨팅 연산이나 함수 호출 등에 사용되는 프로세스로서 FIFO큐를 통해 차례로 실행됨
TinyOS에서는 저장된 모든 Task가 끝난 후, 큐가 비어 있을 경우에는 다른 Task가 생성되기 전가지 CPU의 전원을 최소하하여 소모 에너지를 낮추는 기법을 가지고 있음
Task는 다른 Task에 의해 선점되지 않지만 이벤트에 의해서는 선점됨
이벤트는 특정 하드웨어 인터럽트나 특정 조건에 만족했을 경우호출되는 작업들로서 다른 Task보다 먼저 실행되는 특징
일반적으로 인터럽트에 의해 어떤 이벤트가 발생되면 연결된 컴포넌트들에 따라 연속적으로 상위 컴포넌트들에 연결된 event 함수가 호출되며, 동시에 그에 따른 처리 함수들이 Task 형태로 만들어져 큐(Queue)에 저장됨
즉, TinyOS는 이벤트가 발생함으로써 처리해야 할 작업들이 생성되는 event driven OS형식을 취하게 됨
레이스 컨디션
TinyOS는 코드 작성의 관점에서 보면 두가지 형태로 구분
하나는 인터럽트에 의해서 발생되어 진행되는 비동기적 코드이며, 다른 하나는 FIFO 큐에 의해 순서대로 진행되는 동기적 코드.
비동기적 코드는 인터럽트에 의해서 갑작스럽게 시작되기 때문에, 전역 변수를 사용하는 경우에는 레이스 컨디션이 발생
레이스 컨디션 제거하는 방법
1. 전역 변수를 사용하지 않음
2. 인터럽트를 사용하지 않음
3. 코드를 짧게 구성하여 인터럽로부터 자유로운 코드를 구성
4. atomic을 사용
5. 레이스 컨디션을 유발하는 변수 앞에 norace를 붙임
atomic 안에 기술된 프로그램은 선정되지 않고 실행되기 때문에 레이스 컨디션 문제를 피함
atomic {
sharedvar = sharedvar + 1;
....
}
TinyOS 명명법
TinyOS Naming Convention
기존의 코드 분석 및 개발하는 코드의 가독성을 높이는 데 도움
Interface
동사나 명사가 사용되며, 여러 단어를 조합할 경우 각 단어의 첫 글자는 대문자로 표기
예) ADC, Range, SendMsg
Components
명사가 사용되며, 여러 단어를 조합할 경우 각 단어의 첫 글자는 대문자로 표기
컴포넌트는 대문자 C로 끝나거나 M으로 끝나는 이름이 있음
대문자 C는 "Component"를 나타내며, 인터페이스와 구분
대문자 M은 "Module"를 나타내며, 하나의 컴포넌트가 configuration과 모듈 모두를 가질 때 서로를 구분하기 위해 사용
예) Counter, IntToRfm, TimerC, TimerM, UARTM
Files
모든 파일은 파일안에 포함된 타입(type)의 이름을 사용하며 nesC 파일은 ".nc"로 끝난다.
Applications
대문자 C가 제거된 최상위 레벨 컴포넌트 이름을 사용
Commands, Events, Tasks
동사를 사용하며, 여러 단어를 조합할 경우 첫 번째 단어를 제외한 각 단어의 첫번째 글자는 대문자로 표기
Variables
명사를 사용하며, 여러 단어를 조합할 경우 첫 번째 단어를 제외한 각 단어의 첫 번째 글자는 대문자로 표기
Constants
항상 대문자이어야 하며 "_"는 각 단어 사이에 사용
예) TOS_UART_ADDR, TOS_BCAST_ADDR
NesC 소스 문서화
NesC 컴파일러는 NesC 소스코드를 자동으로 문서화하는 기능을 제공
생성된 문서는 기본적으로 컴포넌트를 기반으로 생성되며, 각 소스 파일마다 하나의 HTML 파일이 생성
다만, C파일이나 헤더 파일에 포함된 내용은 문서화 되지 않음
프로그래머는 특별한 형태의 코멘트(Comment)를 넣음으로써 생성된 문서에도 코멘트를 넣을수 있음
NesC에서 문서 코멘트는 "/**"로 시작되어 "**/"로 끝남
문서화 parser 는 문서 코멘트 안에서 다음 의 커맨드를 인식한다.
@param paramname text text 함수의 파라미터를 설명
@return text text text 함수의 리턴값을 설명
@author text text text 파일 저자를 열거
@modified text text text 수정사항을 설명
NesC 소스 문서화는 예제 폴더 안에서 "make docs zigbex" 명령을 통해 doc 폴더 안에 생성
TOSSIM
TOSSIM은 TinyOS 기반의 이벤트 시뮬레이터
개발한 TinyOS 애플리케이션을 센서 노드를 위해 컴파일하지 않고 TOSSIM 프레임워크를 위해 컴파일 함으로써 PC에서 개발한 애플리케이션의 동작을 확인해 볼수 있음
이는 사용자가 실제 센서 노드 없이도 개발된 애플리케이션이나 알고리즘을 설정된 환경속에서 디버깅, 테스트, 그리고 분석을 반복적으로 수행함으로써 개발 시간을 단축시키고 프로그램의 안정성을 증대
TOSSIM의 주요 목적은 TinyOS 애플리케이션에 충실한 시뮬레이션을 만드는 것이기 때문에 하드웨어가 아닌 소프트웨어 레벨의 TinyOS 코드와 애플리케이션을 시뮬레이션하는 것에 집중
TOSSIM의 특징
충실도(Fidelity)
기본적으로 TOSSIM은 최하위 레벨(Very Low Level)에서의 TinyOS 행동을 시뮬레이션
실제 하드웨어 통신, 센서 값 측정 등 실제 하드웨어에서 일어나는 행동들이 시뮬레이션 되며 나머지 다른 TinyOS의 동작은 모두 실제 코드를 따라 실행
시간(Time)
TOSSIM은 시스템 인터럽트의 정확한 시간을 측정하지만 실행 시간(Execution Time)을 모델링하지 않음
즉, 가상 시간(4MHz)을 중심으로 동작되도록 설계
모델(Models)
TOSSIM 자체는 실제 세계를 모델링하지 않음
bit 에러와 같은 실제 세계에서 일어나는 현상을 추상화
빌드(Building)
TOSSIM은 TinyOS 코드로부터 바로 빌드
TOSSIM은 예제 폴더 안에서 "make pc" 명령을 통해 생성