2010년 5월 13일 목요일

T2에서의 ADC Mapping

* Configuration *
generic configuration TestC() {
  provides interface DeviceMetadata;
  provides interface Read<uint16_t> as Test;
  provides interface ReadStream<uint16_t>;
}
implementation {
  components new AdcReadClientC();
  Test = ADCReadClientC;
  components new AdcReadStreamClientC();
  ReadStream = AdcReadStreamClientC;
  components TestP;
  DeviceMetadata = TestP;
  AdcReadClientC.AdcConfigure –> TestP;
  AdcReadStreamClientC.AdcConfigure –> TestP;
}

* Module *
#include “Msp430Adc12.h”
module TestP {
  provides interface DeviceMetadata;
  provides interface AdcConfigure<const msp430adc12_channel_config_t *>
}
implementation {
  msp430adc12_channel_config_t config = {
    inch:INPUT_CHANNEL_A2,
    sref:REFERENCE_VREFplus_AVss,
    ref2_5v:REFVOLT_LEVEL_1_5,
    adc12ssel:SHT_SOURCE_ACLK,
    adc12div:SHT_CLOCK_DIV_1,
    sht:SAMPLE_HOLD_4_CYCLES,
    sampcon_ssel:SAMPCON_SOURCE_SMCLK,
    sampcon_id:SAMPCON_CLOCK_DIV_1
  };
  command uint8_t DeviceMetadata.getSignificantBits() {
    return 12;
  }
  async command const msp430adc12_channel_config_t * AdcConfigure.getConfiguration() {
    return &config;
  }
}

위와 같이 컴포넌트를 작성하여 최상위 어플리케이션에서 wiring을 통해 사용하면 된다.

TinyOS에서 CC2420 동작 원리

현재 IEEE 802.15.4 프로토콜의 MAC layer 표준에 상응하는 2.4GHz대역의 CC2420이 센서 네트워크 플랫폼의 radio chip으로 많이 사용되고 있다. TinyOS 에도 CC2420에 대한 부분이 포함되어 있으며 이는 CC2420을 동작하게 하는 드라이버 부분과 backoff 및 CCA 알고리즘이 추가 구현되어 있다.
이 문서는 TinyOS에서 구현된 CC2420의 동작 원리를 분석하여, RF 메커니즘의 이해를 돕고자 하는데 그 의의가 있다.

1. IEEE 802.15.4 프로토콜


IEEE 802.15.4 의 standard feature는 다음과 같다.
The IEEE 802.15.4-2003 standard
• Data rates of 250 kbps, 40 kbps, and 20 kbps.
• Two addressing modes; 16-bit short and 64-bit IEEE addressing.
• Support for critical latency devices, such as joysticks.
• CSMA-CA channel access.
• Automatic network establishment by the coordinator.
• Fully handshaked protocol for transfer reliability.
• Power management to ensure low power consumption.
• 16 channels in the 2.4GHz ISM band, 10 channels in the 915MHz I and one 
channel in the 868MHz band.
또한, CC2420의 간단한 specification을 보면 다음과 같다.
The IEEE 802.15.4-2003 standard
• true single-chip 2.4 GHz (16 channels in ISM band)
• Max data rate : 250Kbps
• Low current consumption (RX: 19.7 mA, TX: 17.4 mA)
위와 같이, CC2420은 IEEE 802.15.4 MAC hardware를 지원 가능하다. CSMA-CA에 대한 부분은 tinyos에서 B-MAC이란 MAC protocol을 사용해서 보완하고 있다.

2. CC2420 driver

CC2420은 MCU와 4-wire SPI-bus configuration interface (SI, SO, SCLK and CSn). 로 연결되어 SPI통신을 통한 동작을 기본으로 한다.














CSN은 SPI Chip select로, SPI 통신의 enable/disable을 담당한다. 일반적으로 low상태일 때, enable이 되고, High 일 때, disable이 된다. SI는 SPI Bus의 Input으로 사용되고, SO는 SPI Bus의 Output으로 사용된다. SCLK는 SPI Bus의 serial clock으로 사용된다.
atmega에서는 SPI를 컨트롤하는 레지스터를 갖고 있어서, 간단한 설정만으로도 SPI통신이 가능하다. 하지만 msp430 계열은 SPI를 컨트롤하는 레지스터가 없기 때문에, UART를 SPI mode로 변경하여 사용한다. TinyOS에서는 SPI mode의 초기화를 각 architectre별로 다음과 같이 구현하고 있다.
------------------------------------------------------------------------------
Atmega - 128


TOSH_MAKE_SPI_SCK_OUTPUT();
TOSH_MAKE_MISO_INPUT(); // miso
TOSH_MAKE_MOSI_OUTPUT(); // mosi
sbi (SPSR, SPI2X); // Double speed spi clock
sbi(SPCR, MSTR); // Set master mode
cbi(SPCR, CPOL); // Set proper polarity...
cbi(SPCR, CPHA); // ...and phase
cbi(SPCR, SPR1); // set clock, fosc/2 (~3.6 Mhz)
cbi(SPCR, SPR0);
// sbi(SPCR, SPIE); // enable spi port interrupt
sbi(SPCR, SPE); // enable spi port
------------------------------------------------------------------------------
------------------------------------------------------------------------------
MSP430


async command void USARTControl.setModeSPI() {
//check if we are already in SPI mode
  if(call USARTControl.getMode() == USART_SPI)
    return;
  call USARTControl.disableUART();
  call USARTControl.disableI2C();
  atomic {
    TOSH_SEL_SIMO1_MODFUNC();
    TOSH_SEL_SOMI1_MODFUNC();
    TOSH_SEL_UCLK1_MODFUNC();
    IE2 &= ~(UTXIE1 | URXIE1); // interrupt disable
    U1CTL |= SWRST;
    U1CTL |= CHAR | SYNC | MM; // 8-bit char, spi-mode, USART as master
    U1CTL &= ~(0x20); U1TCTL = STC ; // 3-pin
    U1TCTL |= CKPH; // half-cycle delayed UCLK
    if (l_ssel & 0x80) {
      U1TCTL &= ~(SSEL_0 | SSEL_1 | SSEL_2 | SSEL_3);
      U1TCTL |= (l_ssel & 0x7F);
    }
    else {
      U1TCTL &= ~(SSEL_0 | SSEL_1 | SSEL_2 | SSEL_3);
      U1TCTL |= SSEL_SMCLK; // use SMCLK, assuming 1MHz
    }
    if (l_br != 0) {
      U1BR0 = l_br & 0x0FF;
      U1BR1 = (l_br >> 8) & 0x0FF;
    }
    else {
      U1BR0 = 0x02; // as fast as possible
      U1BR1 = 0x00;
    }
    U1MCTL = 0;
    ME2 &= ~(UTXE1 | URXE1); //USART UART module disable
    ME2 |= USPIE1; // USART SPI module enable
    U1CTL &= ~SWRST;
    IFG2 &= ~(UTXIFG1 | URXIFG1);
    IE2 &= ~(UTXIE1 | URXIE1); // interrupt disabled
  }
  return;
}
------------------------------------------------------------------------------
위에서 보듯이, atmega는 6~7번의 레지스터 세팅으로 SPI 통신을 초기화 할 수 있지만, msp430은 일반적인 UART 설정을 기본으로 초기화한다. 실제로, 일반 UART 초기화와의 차이점은 SPI module disable/enable을 제어하는 레지스터의 설정밖에 없다.(USPIEx) 초기화 후에, 간단한 SPI read/write function을 기본으로 작성된 여러가지 함수를 이용해서 CC2420을 제어하게 된다. 몇몇 중요 함수들의 예는 다음과 같다.

HPLCC2420.cmd(uint8_t addr) :
• CC2420으로 하나의 command를 보내고, 수신된 status 값을 리턴한다.
HPLCC2420.read(uint8_t addr) :
• CC2420으로부터 16-bit 레지스터 값을 받아온다.
HPLCC2420FIFO.readRXFIFO (uint8_t length, uint8_t *data) :
• RX FIFO 큐로부터 length만큼 값을 받아오고, data에 저장한다.
HPLCC2420FIFO.writeTXFIFO(uint8_t length, uint8_t *data) :
• data에 저장된 length만큼의 데이터를 TX FIFO에 write한다.

이제 이 함수들을 어떻게 사용하여 CC2420을 제어하는지 살펴보자.
CC2420의 드라이버 및 B-MAC이 구현된 부분은 /opt/tinyos-1.x/tos/lib/CC2420Radio 이다. 각 architecture별로 구현된 SPI/SPI응용 함수들을 이용하여 CC2420의 제어가 가능하다.
드라이버에서 가장 처음에 하는 일은 CC2420의 power on, reset toggle 을 하는 것이다.
------------------------------------------------------------------------------
//turn on power
call CC2420Control.VREFOn();
// toggle reset
TOSH_CLR_CC_RSTN_PIN();TOSH_wait();
TOSH_SET_CC_RSTN_PIN();TOSH_wait();
------------------------------------------------------------------------------
그 다음은 CC2420의 crystal을 enable시킴으로서, CC2420의 동작을 위한 최소한의 하드웨어 설정을 마친다. CC2420으로 CC2420_SXOSCON(0x01)이란 command를 보내면 crystal이 동작하게 된다.
------------------------------------------------------------------------------
async command result_t CC2420Control.OscillatorOn() {
......
status = call HPLChipcon.cmd(CC2420_SXOSCON); //turn-on crystal
......
------------------------------------------------------------------------------
CC2420의 send 모드는 크게 두가지로 나눌 수 있다. 채널이 clear될 때까지 기다리다가 clear되는 순간 전송을 하는 방식과, 채널의 상태에 관계없이 전송을 하는 방식이다.
------------------------------------------------------------------------------
async command result_t CC2420Control.TxMode() {
call HPLChipcon.cmd(CC2420_STXON);
return SUCCESS;
}
//Shift the CC2420 Radio into transmit mode when the next clear channel
is detected.
async command result_t CC2420Control.TxModeOnCCA() {
call HPLChipcon.cmd(CC2420_STXONCCA);
return SUCCESS;
}
------------------------------------------------------------------------------
CC2420의 receive모드는 다음과 같다
------------------------------------------------------------------------------
async command result_t CC2420Control.RxMode() {
call HPLChipcon.cmd(CC2420_SRXON);
return SUCCESS;
}
------------------------------------------------------------------------------
CC2420Control 에 모듈의 초기화, TX/RX 모드 함수, RF power및 frequency 설정을 하는 기본 함수들이 포함되어 있다면, CC2420Radio는 송/수신에 직접적이면서 복잡한 함수들이 포함되어 있다. 송신 함수는 sendPacket(), startSend(), tryToSend()함수로 구현되어 있다. startSend는 말그대로 송신을 시작하는 함수로, TXFIFO에 송신할 패킷을 length만큼 write하게 된다. 이 함수가 종료되면 패킷들이 FIFO에서 송출되기를 기다린다.
------------------------------------------------------------------------------
task void startSend() {
// flush the tx fifo of stale data
if (!(call HPLChipcon.cmd(CC2420_SFLUSHTX))) {
sendFailed();
return;
}
// write the txbuf data to the TXFIFO
if (!(call HPLChipconFIFO.writeTXFIFO(txlength+1,(uint8_t*)txbufptr))) {
sendFailed();
return;
}
}
------------------------------------------------------------------------------
sendPacket은 RF로 패킷을 보내는 함수이다. tryToSend에서 call되어 사용되어 지며, 채널이 clear되면 전송되는 방식을 사용한다.
------------------------------------------------------------------------------
void sendPacket() {
uint8_t status;
call HPLChipcon.cmd(CC2420_STXONCCA);
status = call HPLChipcon.cmd(CC2420_SNOP);
……..
}
------------------------------------------------------------------------------
tryToSend는 CCA핀을 read했을 때, High상태라면, 즉 채널이 clear하다면 sendPacket을 call하여 패킷을 전송하고, 채널이 사용중이라면 normal operation을 계속해서 수행한다.
------------------------------------------------------------------------------
void tryToSend() {
…………..
// if a FIFO overflow occurs or if the data length is invalid, flush
// the RXFIFO to get back to a normal state.
if ((!TOSH_READ_CC_FIFO_PIN() && !TOSH_READ_CC_FIFOP_PIN())) {
flushRXFIFO();
}
if (TOSH_READ_RADIO_CCA_PIN()) {
atomic stateRadio = TX_STATE;
sendPacket();
}
else {
// if we tried a bunch of times, the radio may be in a bad state
// flushing the RXFIFO returns the radio to a non-overflow state
// and it continue normal operation (and thus send our packet)
if (countRetry-- <= 0) {
flushRXFIFO();
countRetry = MAX_SEND_TRIES;
if (!post startSend())
sendFailed();
return;
}
……………
}
------------------------------------------------------------------------------
tryToSend는 startSend가 종료되는 시점에 실행이 된다. 즉 startSend에서 TXFIFO를 채우면 HPLChipconFIFO.TXFIFODone()이 실행되고, 이 함수안에서 tryToSend를 실행하게 되어, FIFO에 write된 패킷이 무선으로 전송된다.
rxMode로 설정되어 있을 때, 같은 주파수대의 패킷이 들어오면, FIFOP에 interrupt가 발생한다. Interrupt가 발생했을 때, FIFOP.fired 라는 인터럽트 함수가 실행하게 되고, 이는 수신된 패킷을 RXFIFO로 write한다. RXFIFO로 값이 모두 들어오면, HPLChipconFIFO.RXFIFODone()라는 함수가 실행된다.
------------------------------------------------------------------------------
async event result_t FIFOP.fired() {
…………..
/** Check for RXFIFO overflow **/
if (!TOSH_READ_CC_FIFO_PIN()){
flushRXFIFO();
return SUCCESS;
}
atomic {
if (post delayedRXFIFOtask()) {
call FIFOP.disable();
}
else {
flushRXFIFO();
}
}
// return SUCCESS to keep FIFOP events occurring
return SUCCESS;
}
------------------------------------------------------------------------------
HPLChipconFIFO.RXFIFODone()이 실행되면 데이터 예외처리를 거쳐서 정상적인 length의 패킷을 rxbufptr 버퍼에 저장한다. rxbufptr에 할당이 되는 *data는 TOS_MsgPtr 의 구조체 변수 크기에 맞게 바이트 단위로 parsing되서 저장된다. length가 길면 패킷은 버려지고, 짧으면 crc, RSSI, LQI값을 맟춰서 할당한다.
------------------------------------------------------------------------------
async event result_t HPLChipconFIFO.RXFIFODone(uint8_t length, uint8_t *data){
…………….
rxbufptr = (TOS_MsgPtr)data;
……………
if (rxbufptr->length > TOSH_DATA_LENGTH) {
flushRXFIFO();
atomic bPacketReceiving = FALSE;
return SUCCESS;
}
// adjust destination to the right byte order
rxbufptr->addr = fromLSB16(rxbufptr->addr);
// if the length is shorter, we have to move the CRC bytes
rxbufptr->crc = data[length-1] >> 7;
// put in RSSI
rxbufptr->strength = data[length-2];
// put in LQI
rxbufptr->lqi = data[length-1] & 0x7F;
……………
}
------------------------------------------------------------------------------
지금까지 TinyOS에서의 CC2420이 마이크로 컨트롤러와 어떻게 통신을 하고 동작을 하는지를 알아보았다.  물론 위의 설명은 CC2420의 동작원리를 충분히 이해하기엔 너무 개략적이고 의미 중심적이다. 따라서 윗글은 CC2420소스를 처음 접하여 분석하고자 하는 분에게 소스의 전반적인 구성을 이해하는데 참조할 수 있는 자료라 할 수 있겠다.
- hybus -

2010년 5월 11일 화요일

Dissemination

Dissemination 프로토콜은 네트워크 전체에 동일한 데이터를 전달하고 이들의 일관성을 유지시키는 서비스이다. 이를 위해 각 노드는 이 데이터의 복사본을 저장하며, 나중에 해당 데이터의 값이 변경될 경우 이를 알리고, 네트워크 전체에 걸쳐 이 데이터가 일관된 값을 갖게 될 때까지 패킷들을 교환한다. 초기에는 대부분의 노드들이 이전 값(stale value)을 갖는 불안정한 상태를 갖겠지만, 이 과정을 통해 시간이 지나면서 최근 값(up-to-data value)을 갖도록 네트워크 전체가 수렴한다.



이 기법은 패킷 손실이나, 일시적인 통신 단절등에 상당히 잘 견디며, 단순히 패킷을 노드 간에 반복 전달하는데 그치는 플러딩(flooding) 방식과는 달리 Dissemination 기법은 네트워크에 연결되어 있는 모든 노드들이 궁극적으로는 일관된 값을 갖도록 보장한다. 전송할 데이터의 크기에 따라 이 프로토콜의 성능은 크게 다르며, 수십 KB의 데이터를 dissemination하는 것은 몇 Bytes를 전송하는 경우와는 약간 다른 프로토콜을 요구하는데, 자세히 살펴보면 근본적으로는 매우 유사하다. Dissemination 프로토콜을 제어와 데이터 트래픽으로 나눠보면, 데이터 트래픽 프로토콜은 데이터의 크기에 밀접한 관련이 있지만, 제어 트래픽 프로토콜은 동일하거나 비슷한 경향을 보인다. 예를 들어, UC Berkely에서 개발한 Deluge 바이너리 프로그래밍 서비스는 바이너리(실행 프로그램)에 대한 메타 정보를 전파한다. 이 과정에서 노드들이 자신들이 갖고 있는 바이너리의 정보가 전달받은 정보와 다르면, 그들은 자신의 노드에 있는 바이너리가 잘못되었거나 새로운 바이너리가 필요하다는 것을 알 수 있다.

이 기법에서는 어떤 노드라도 네트워크에게 자신이 새로운 값을 생성했다고 알림으로 네트워크 전체가 일관된 상태로 수렴하도록 요구할 수 있다. 그리고, 모든 노드들이 이 값에 동의하면 네트워크 전체에 걸쳐 동일한 값으로 수렴한다. 이와 같은 방법으로 작은 데이터들을 Dissemination 할 수 있다면 센서 네트워크의 중요한 기능을 담당할 수 있다. 예를 들면, 작은 프로그램을 네트워크에 전달하거나 네트워크의 재구성, 질의 또는 명령, 재프로그램등을 지원할 수 있다.

Collection

Collection은 센서 네트워크의 각 노드에서 발생한 데이터들을 PC 호스트 등의 베이스 스테이션으로 전달하는 기능을 수행한다. 이 경우 일반적으로 베이스 스테이션에 연결된 싱크 노드를 루트로 갖는 Collection Tree를 구성하며, 하나의 네트워크에서 이와 같은 트리는 여러 개 생성될 수 있다.


TinyOS에서는 트리를 구성하기 위해 CTP(Collection Tree Protocol)을 사용한다. 네트워크에서 임의의 노드가 자신이 루트라고 알리면 네트워크의 노드들은 루트 노드를 중심으로 라우팅 트리들을 구성한다. 이 때 각 노드들은 루트 노드로 향하는 경로를 설정하기 위해 라우팅 기울기(routing gradient)를 계산한다. 즉, 각 노드는 싱크 노드와의 근접성을 측정하고, 이를 바탕으로 싱크 노드에 최대한 근접하는 링크를 선택하며 점진적으로 경로를 설정해 간다.

CTP는 라우팅 기울기로 ETX(Expected transmissions) 값을 사용한다. 루트 노드의 ETX 값은 0으로 정의하며, 어떤 노드의 ETX 값은 자신의 부모 노드가 갖는 ETX 값과 해당 노드에서 부모 노드로의 링크가 갖는 ETX 값을 더한 값을 갖는다. 이와 같은 상황에서 임의의 노드는 루트 노드로의 경로 설정 시에 가장 낮은 ETX 값을 갖는 링크를 선택하고, 이 링크에 연결된 노드를 부모 노드로 기록하며, 이 과정이 루트 노드를 시작으로 전체 네트워크에 이르기까지 반복된다.




위 그림은 CTP를 구성하는 컴포넌트들을 나타내고 있으며, 이 가운데 CtpP 컴포넌트가 핵심 기능을 제공한다. 특히 CtpP는 한 홉(Hop) 간 ETX 값을 측정하기 위해 LinkEstimatorP 컴포넌트를 포함하며, 이 값을 이용해 다음 라우팅 링크를 결정하기 위해 CtpRoutingEngineP 컴포넌트를 사용한다. 마지막으로 라우팅 링크로의 패킷 전송을 위해 CtpForwardingEngineP 컴포넌트가 사용된다. 보다 상세한 수준의 컴포넌트는 TinyOS에서 제공하는 docs 유틸리티를 활용하여 컴포넌트들의 연결 구조를 파악할 수 있다.

이와 같은 구성으로 CTP가 구현되어 있으며 위에서 설명한 동작방식을 통해 센서 네트워크 내의 임의의 노드가 데이터를 생성하면, 자신의 부모 노드를 향해 데이터를 전달(forwarding)한다. 이를 통해 루트는 자신의 하위에 있는 모든 노드로부터 발생한 데이터를 수집하는 역할을 담당한다.

네트워크가 여러 루트를 가졌을 때, Tree 형태의 forest를 구성하게 된다.



하지만 단순한 Colletcion 프로토콜은 여러 문제에 직면한다. 가령 전달 경로에 루프(loop)가 생기거나, 데이터의 중복 전송 문제 등이 발생할 수 있다. 이 때문에 일반적으로 분산된 트리를 구성하는 알고리즘에 제한을 둔다. 다음은 이와 같은 알고리즘이 해결해야 할 과제들이다.

▪Loop detection
자손 중 하나를 부모 노드로 선택하는 상황 검출

▪Duplicate suppression
네트워크에서 패킷의 중복 전송 원인이 되는 ACK의 손실을 탐지

▪Link estimation
한 홉간의 이웃과의 Link quality를 측정

▪Self-interference
다음 패킷의 경로를 이전 패킷들과 간섭이 생기는 경로로 라우팅하는 것을 방지

2010년 5월 10일 월요일

리눅스 권한 설정

리눅스에서 권한 설정은 chmod(change mode) 명령을 이용한다.

리눅스는 사용자 번호(UID)와 그룹번호(GID)를 가지고 모든 사용자를 구분하는데, 파일은 그것을 생성한 소유자에게 속해 있으며 이 명령을 통해 폴더 및 파일에 대한 접근 권한을 줄 수 있다.

  • chmod [option] octal-mode file(s)
  • chmod [option] symbolic-mode file(s)

option

-R 서브 디렉토리의 파일까지 재귀적으로 실행
-f 자기 소유가 아닌 파일에 변경 시도
-v 변경되는 모드에 대해 출력

octal-mode

image

symbolic-mode

image

참고로 chmod –R 777 /share * 명령을 이용하면 share 폴더에 있는 하위 폴더의 파일내용까지도 파일소유자, 그룹, 기타 사용자까지 모두 읽기, 쓰기, 실행을 허용한다는 것이다.

2010년 5월 2일 일요일

TOSH_uwait();

TOSH_uwait();에 포함되는 단위는 usec(microsec) 이다.
참고로 TOSH_uwait(10000); == 10ms == 0.01sec 가 된다.

이 함수는 /opt/tinyos-1.x/tos/platform/msp430/msp430hardware.h 에 정의 되어 있다.