520 likes | 824 Views
Ubiquitous Sensor Networks. Ubiquitous Sensor Networks. #4 : Wireless Forwarding Ad-hoc Network with Flooding, Gossiping, LEACH Protocols (Hanback’s zigbeX & TinyOS ver.1.1.7). 2007. 3. 23. DoHyun. Ji. Contents. 2. 3. 1. Gossiping Protocol. LEACH Protocol. Flooding Protocol.
E N D
Ubiquitous Sensor Networks Ubiquitous Sensor Networks #4 : Wireless Forwarding Ad-hoc Network with Flooding, Gossiping, LEACH Protocols (Hanback’s zigbeX & TinyOS ver.1.1.7) 2007. 3. 23 DoHyun. Ji
Contents 2 3 1 Gossiping Protocol LEACH Protocol Flooding Protocol
1. Flooding Protocol • Ad-hoc Network • 특정 목적지로 데이터 전송을 위해 각 노드가 자유로운 망을 형성 • 형성된 망을 통해 목적지 노드로 데이터 포워딩, 멀티홉 통신의 구현 • 특정 AP나 기지국이 불필요하여 설치 및 운영이 간편 • Flooding Protocol • 패킷 전송은 항상 Broadcast 형태로 진행 • Implosion – Sequence Number for each Packet • TTL(Time to Live) – Hop Limit • 실제 사용은 최초 라우팅 경로 설정용(RIP와 유사) • 같은 패킷을 두 번 이상 수신할 수 있음(Overlap) • 각 노드의 RF 출력에 의존 • 목적 노드가 데이터를 수신했음에도 계속 포워딩될 수 있음 • 많은 전력 소모
1. Flooding Protocol • Configuration – TempMon.nc • Makefile includes TempMon; includes MH; configuration TempMon{ } Implementation { components Main, TempMonM, TimerC, Temp, GenericComm as Comm,QueuedSend, SimpleTime, #ifdef FLOODING // FLOODING 이 define 된 경우 MHFloodingRouter as Router; #endif #ifdef GOSSIPING MHGossipingRouter as Router; #endif #ifdef LEACH MHLeachRouter as Router; #endif COMPONENT=TempMon SENSORBOARD=basicsb PFLAGS= -I. -I./Queue -DFLOODING -DSIM=10 include ../../../../apps/Makerules
1. Flooding Protocol • Configuration – TempMon.nc (con’d) & headers Main.StdControl -> TempMonM.StdControl; Main.StdControl -> Router.StdControl; // 라우팅 프로토콜 연결 Main.StdControl -> Comm.Control; Main.StdControl -> QueuedSend.StdControl; Main.StdControl -> Temp.StdControl; Main.StdControl -> TimerC.StdControl; Main.StdControl -> SimpleTime.StdControl; TempMonM.ADC -> Temp.TempADC; TempMonM.Timer -> TimerC.Timer[unique("Timer")]; TempMonM.Send -> Router.Send[AM_TEMPMONMSG]; // 전송 컴포넌트 연결 TempMonM.GlobalTime -> Router.GlobalTime; Router.ReceiveMsg[AM_TEMPMONMSG] -> Comm.ReceiveMsg[AM_TEMPMONMSG]; } /* tempMon.h */ enum { TIMER_RATE = 5000, // Send a message every 5 seconds AM_TEMPMONMSG = 10, }; typedef struct TempMonMsg { uint16_t address; uint32_t timestamp; uint16_t reading; } __attribute__ ((packed)) TempMonMsg; /* MH.h */ ... FLOODING_MAX_HOP_COUNT = 100, FLOODING_LOG_LENGTH = 250, ... /* MH.h */ typedef struct MHMessage { uint16_t sendingNode; uint16_t originNode; uint16_t seqNo; uint16_t hopCount; uint8_t data[(TOSH_DATA_LENGTH - 8)]; } __attribute__ ((packed)) MHMessage;
1. Flooding Protocol • Module – TempMonM.nc includes TempMon; module TempMonM { provides { interface StdControl; } uses { interface Send; interface ADC; interface Timer; interface GlobalTime; } } implementation { norace uint16_t sensorReading; // 각 센싱 프로세스를 고정 bool sendBusy; // 전송 상태 변수 TOS_Msg mhMsg; // 전송될 데이터의 메시지 타잎 command result_t StdControl.init(){ ... } command result_t StdControl.start() { call ADC.getData(); // ADC 읽어오기 return call Timer.start(TIMER_REPEAT, TIMER_RATE); } event result_t Timer.fired(){ call ADC.getData(); // ADC 읽어오기 // 모든 노드의 글로벌 시간이 동기화 되었을때만 전송 if (call GlobalTime.isSynchronised() == SUCCESS) { post sendData(); } return SUCCESS; }
1. Flooding Protocol • Module – TempMonM.nc (con’d) task void sendData() { uint16_t length; TempMonMsg *pDataMsg = (TempMonMsg *) call Send.getBuffer(&mhMsg, &length); // 전송중에는 보내지 않음 if (sendBusy == TRUE) { return; } // 전송용 메시지에 데이터 담기 pDataMsg->address = TOS_LOCAL_ADDRESS; pDataMsg->timestamp = call GlobalTime.getGlobalTime(); pDataMsg->reading = sensorReading; // 실제 전송 if ((call Send.send(&mhMsg, sizeof(TempMonMsg))) == SUCCESS) { atomic sendBusy = TRUE; dbg(DBG_TEMP, "TempMonM - Message sent successfully\n"); } else { dbg(DBG_TEMP, "TempMonM - Message not sent\n"); } }
1. Flooding Protocol • Configuration – MHFloodingRouter.nc includes MH; configuration MHFloodingRouter{ provides { interface StdControl; interface Receive[uint8_t id]; // 수신용 인터페이스 interface Send[uint8_t id]; interface Intercept[uint8_t id]; interface GlobalTime; // 각 모트가 sync 해야할 글로벌 타임 } uses { interface ReceiveMsg[uint8_t id]; } } implementation { components MHEngineM, MHFloodingPSM, GenericComm as Comm, QueuedSend, TimerC, SimpleTime, TimeSyncM, LedsC; StdControl = MHEngineM.StdControl; // 멀티홉에 필수적인 MHEngine, 기타 컴포넌트들 Receive = MHEngineM.Receive; // 모든 인터페이스를 멀티홉 처리를 담당하는 MHEngine에 연결 Send = MHEngineM.Send; ReceiveMsg = MHEngineM.ReceiveMsg; Intercept = MHEngineM.Intercept; GlobalTime = TimeSyncM.GlobalTime; MHEngineM.CommStdControl -> Comm.Control;
1. Flooding Protocol • Configuration – MHFloodingRouter.nc (con’d) #ifdef SIM MHEngineM.SimTimer -> TimerC.Timer[unique("Timer")]; #endif MHEngineM.SubControl -> QueuedSend.StdControl; MHEngineM.SendMsg -> QueuedSend.SendMsg; MHEngineM.SubControl -> MHFloodingPSM.StdControl; MHEngineM.RouteSelect -> MHFloodingPSM.RouteSelect; // Flooding 프로토콜이 구현된 MHFlooingPSM 에 연결 MHEngineM.Leds -> LedsC.Leds; TimeSyncM.Leds -> LedsC.Leds; // LED MHEngineM.SubControl -> TimeSyncM.StdControl; TimeSyncM.Timer -> TimerC.Timer[unique("Timer")]; // Timer TimeSyncM.Time -> SimpleTime.Time; TimeSyncM.ReceiveMsg -> Comm.ReceiveMsg[AM_TIMESYNC]; // 수신한 메시지 큐 TimeSyncM.SendMsg -> QueuedSend.SendMsg[AM_TIMESYNC]; // 보낼 메시지 큐 MHEngineM.GlobalTime -> TimeSyncM.GlobalTime; // 노드간의 sync를 위한 변수 }
1. Flooding Protocol • Module – MHFloodingPSM.nc (con’d) includes AM; includes MH; module MHFloodingPSM{ provides { interface StdControl; interface RouteSelect; } } // RouteSelect 인터페이스 사용 implementation{ typedef struct LogEntry{ uint16_t id; // 로그 기록용 구조체 uint16_t seqno; // seq 번호 } LogEntry; enum{ MAX_HOP_COUNT = FLOODING_MAX_HOP_COUNT, // 최대 Hop count 설정 MAX_SEQ_NO = 30000, // 최대 Sequence 번호 설정 LOG_LENGTH = FLOODING_LOG_LENGTH // 최대 Log 길이 설정 }; uint16_t seqNo; // Sequence 번호 변수 LogEntry messageLog[LOG_LENGTH]; // 로그 기록용 구조체 배열 uint16_t entries; // 로그 엔트리 개수 기록 변수 uint16_t index; // 로그 기록용 인덱스 변수
1. Flooding Protocol • Module – MHFloodingPSM.nc (con’d) static uint16_t getSeqNo() { // 다음 Sequence 번호 가져오기 uint16_t temp = seqNo++; seqNo = seqNo % MAX_SEQ_NO; return temp; } static void addLogEntry(uint16_t id, uint16_t seqno) { // 새로운 로그 기록 if (entries < LOG_LENGTH) { entries++; } messageLog[index].id = id; messageLog[index++].seqno = seqno; index = index % LOG_LENGTH; } static bool inLog(uint16_t id, uint16_t seqno) { // 로그 검색, 기존에 전송한 패킷인지 검사 int i; for (i = 0; i < entries; i++) { if ((messageLog[i].id == id) && (messageLog[i].seqno == seqno)) { return TRUE; } } return FALSE; }
1. Flooding Protocol • Module – MHFloodingPSM.nc (con’d) command result_t StdControl.init() { seqNo = 0; entries = 0; index = 0; // 각 변수 초기화 return SUCCESS; } command result_t StdControl.start() { return SUCCESS; } command result_t StdControl.stop() { return SUCCESS; } command bool RouteSelect.isActive() { return TRUE; // Flooding 이 진행중일때는 항상 True 리턴 } command result_t RouteSelect.initializeFields(TOS_MsgPtr msg, uint8_t id) { // 새로운 패킷의 초기화 ( 목적지 주소, 홉 Count 기록) MHMessage *pMHMsg = (MHMessage *) &msg->data[0]; pMHMsg->originNode = pMHMsg->sendingNode = TOS_LOCAL_ADDRESS; pMHMsg->hopCount = 0; return SUCCESS; }
1. Flooding Protocol • Module – MHFloodingPSM.nc (con’d) command result_t RouteSelect.selectRoute(TOS_MsgPtr msg, uint8_t id){ MHMessage *pMHMsg = (MHMessage *) &msg->data[0]; // 데이터를 메시지 구조체에 저장 if ((pMHMsg->originNode == TOS_LOCAL_ADDRESS) && (pMHMsg->hopCount == 0)) { pMHMsg->seqNo = getSeqNo(); // 패킷이 local 노드에서 생성된 경우 } else if (inLog(pMHMsg->originNode, pMHMsg->seqNo) == FALSE) { pMHMsg->sendingNode = TOS_LOCAL_ADDRESS; // 패킷이 다른 노드에서 전달 되어온 경우 pMHMsg->hopCount++; /// 홉 증가 } else { // 비정상 패킷 dbg(DBG_TEMP, "MHFloodingPSM - Failed to select route for duplicate packet\n"); return FAIL; } if (TOS_LOCAL_ADDRESS == BASE_STATION_ADDRESS) { msg->addr = TOS_UART_ADDR; // 자신이 sink(수집) 노드인경우 메시지의 목적지 주소를 UART(Serial)로 변경 } else { msg->addr = TOS_BCAST_ADDR; // 그 외는 Broadcast } if (pMHMsg->hopCount < MAX_HOP_COUNT || msg->addr == TOS_UART_ADDR) { addLogEntry(pMHMsg->originNode, pMHMsg->seqNo); // TTL이 유효하거나, 자신이 sink노드인경우 로그에 추가 dbg(DBG_TEMP, "MHFloodingPSM - Route selected\n"); return SUCCESS; } dbg(DBG_TEMP, "MHFloodingPSM - Failed to select route\n"); // 위의 경우에 속하지 않으면(TTL이 만료) return FAIL; // 패킷 폐기 }
1. Flooding Protocol • Result – Run TinyViz using double cygwin windows • On first cygwin window • On Second cygwin window (after executing #1)
1. Flooding Protocol • Result (con’d) - TinyViz
2. Gossiping Protocol • Gossiping Protocol • Many Problems in Flooding Protocol • 확률적 패킷 전송 • 1Hop 이내에 Advertise 패킷 전송 • Unicast Packet Forwarding • Best Case : 최소 노드를 거쳐서 패킷 전송 • Worst Case : 패킷의 손실 • Multi-Advertise 패킷 기법 • Delivery Ratio 고려(Flooding ≥ Gossiping)
2. Gossiping Protocol • Configuration – TempMon.nc • Makefile includes TempMon; includes MH; configuration TempMon{ } Implementation { components Main, TempMonM, TimerC, Temp, GenericComm as Comm,QueuedSend, SimpleTime, #ifdef FLOODING MHFloodingRouter as Router; #endif #ifdef GOSSIPING // GOSSIPING 이 define 된 경우 MHGossipingRouter as Router; #endif #ifdef LEACH MHLeachRouter as Router; #endif COMPONENT=TempMon SENSORBOARD=basicsb PFLAGS= -I. -I./Queue -DGOSSIPING -DSIM=10 include ../../../../apps/Makerules
2. Gossiping Protocol • Configuration – TempMon.nc (con’d) & headers Main.StdControl -> TempMonM.StdControl; Main.StdControl -> Router.StdControl; // 라우팅 프로토콜 연결 Main.StdControl -> Comm.Control; Main.StdControl -> QueuedSend.StdControl; Main.StdControl -> Temp.StdControl; Main.StdControl -> TimerC.StdControl; Main.StdControl -> SimpleTime.StdControl; TempMonM.ADC -> Temp.TempADC; TempMonM.Timer -> TimerC.Timer[unique("Timer")]; TempMonM.Send -> Router.Send[AM_TEMPMONMSG]; // 전송 컴포넌트 연결 TempMonM.GlobalTime -> Router.GlobalTime; Router.ReceiveMsg[AM_TEMPMONMSG] -> Comm.ReceiveMsg[AM_TEMPMONMSG]; } /* tempMon.h */ enum { TIMER_RATE = 5000, // Send a message every 5 seconds AM_TEMPMONMSG = 10, }; typedef struct TempMonMsg { uint16_t address; uint32_t timestamp; uint16_t reading; } __attribute__ ((packed)) TempMonMsg; /* MH.h */ ... GOSSIPING_MAX_HOP_COUNT = 250, GOSSIPING_NEIGHBOUR_TABLE_SIZE = 32, GOSSIPING_ROUTE_UPDATE_RATE = 10000, ... /* MH.h */ typedef struct MHMessage { uint16_t sendingNode; uint16_t originNode; uint16_t seqNo; uint16_t hopCount; uint8_t data[(TOSH_DATA_LENGTH - 8)]; } __attribute__ ((packed)) MHMessage;
2. Gossiping Protocol • Configuration – MHGossipingRouter.nc includes MH; configuration MHGossipingRouter{ provides { interface StdControl; interface Receive[uint8_t id]; interface Send[uint8_t id]; interface Intercept[uint8_t id]; interface GlobalTime; } uses { interface ReceiveMsg[uint8_t id]; } } implementation{ components MHEngineM, MHGossipingPSM, GenericComm as Comm, QueuedSend, TimerC, RandomLFSR, SimpleTime, TimeSyncM, LedsC; StdControl = MHEngineM.StdControl; Receive = MHEngineM.Receive; Send = MHEngineM.Send; ReceiveMsg = MHEngineM.ReceiveMsg; Intercept = MHEngineM.Intercept; GlobalTime = TimeSyncM.GlobalTime; MHEngineM.CommStdControl -> Comm.Control;
2. Gossiping Protocol • Configuration – MHGossipingRouter.nc (con’d) #ifdef SIM MHEngineM.SimTimer -> TimerC.Timer[unique("Timer")]; #endif MHEngineM.SubControl -> QueuedSend.StdControl; MHEngineM.SendMsg -> QueuedSend.SendMsg; MHEngineM.SubControl -> MHGossipingPSM.StdControl; MHEngineM.RouteSelect -> MHGossipingPSM.RouteSelect; // Gossiping 프로토콜 컴포넌트에 연결 MHEngineM.Leds -> LedsC.Leds; MHEngineM.SubControl -> TimeSyncM.StdControl; MHEngineM.GlobalTime -> TimeSyncM.GlobalTime; MHGossipingPSM.Timer -> TimerC.Timer[unique("Timer")]; MHGossipingPSM.ReceiveMsg -> Comm.ReceiveMsg[AM_MHMESSAGE]; MHGossipingPSM.SendMsg -> QueuedSend.SendMsg[AM_MHMESSAGE]; MHGossipingPSM.Random -> RandomLFSR.Random; MHGossipingPSM.Leds -> LedsC.Leds; TimeSyncM.Leds -> LedsC.Leds; TimeSyncM.Timer -> TimerC.Timer[unique("Timer")]; TimeSyncM.Time -> SimpleTime.Time; TimeSyncM.ReceiveMsg -> Comm.ReceiveMsg[AM_TIMESYNC]; TimeSyncM.SendMsg -> QueuedSend.SendMsg[AM_TIMESYNC]; }
2. Gossiping Protocol • Module – MHGossipingPSM.nc includes AM; includes MH; module MHGossipingPSM { provides { interface StdControl; interface RouteSelect; } uses { interface Timer; interface ReceiveMsg; interface SendMsg; interface Random; interface Leds; } }
2. Gossiping Protocol • Module – MHGossipingPSM.nc (con’d) implementation{ typedef struct RoutePacket { uint16_t nodeID; } __attribute__ ((packed)) RoutePacket; typedef struct NeighbourTable { // 이웃들의 정보를 기록할 구조체 uint16_t nodeID; // 노드 ID uint16_t receivedCount; // 수신한 메시지 카운트 uint16_t timerTicks; // 최종 패킷을 받은 후 경과한 시간(Tick) bool nodeAlive; // 노드의 상태(Alive or Dead) uint16_t strength; // 연결(Link) 강도 } NeighbourTable; enum { MAX_HOP_COUNT = GOSSIPING_MAX_HOP_COUNT, // 최대 Hop count 설정 NEIGHBOUR_TABLE_SIZE = GOSSIPING_NEIGHBOUR_TABLE_SIZE, // 이웃 노드 Table 크기 NEIGHBOUR_DEAD_TICKS = 5, // 죽은 이웃 노드 감지 시간 ROUTE_UPDATE_RATE = GOSSIPING_ROUTE_UPDATE_RATE // 라우팅 테이블 갱신률 }; TOS_Msg routeMsg; // 라우팅될 메시지를 담을 구조체 bool sendRouteBusy; // 전송 플래그(Busy or Not) NeighbourTable neighbourTable[NEIGHBOUR_TABLE_SIZE]; // 이웃 노드 기록 Table 구조체 배열 uint16_t entries; // 현재 기록된 이웃 수
2. Gossiping Protocol • Module – MHGossipingPSM.nc (con’d) static void updateTableEntry(uint16_t id, uint16_t strength) { int entryIndex, lowestStrengthIndex, nodeDeadIndex; uint16_t lowestStrength = 0; lowestStrengthIndex = nodeDeadIndex = entries; for (entryIndex = 0; entryIndex < entries; entryIndex++) { // 테이블 검색 if (neighbourTable[entryIndex].nodeID == id) { // 이미 존재하는 경우 break; } else if ((neighbourTable[entryIndex].nodeAlive == FALSE) && (nodeDeadIndex == entries)) { nodeDeadIndex = entryIndex; // 해당 이웃 노드가 죽은 경우 } else if ((neighbourTable[entryIndex].strength < lowestStrength) || (lowestStrengthIndex == entries)) { lowestStrengthIndex = entryIndex; // 가장 신호가 약한 노드 골라내기 lowestStrength = neighbourTable[entryIndex].strength; } }
2. Gossiping Protocol • Module – MHGossipingPSM.nc (con’d) if (entryIndex < entries) { // 이웃 테이블의 엔트리 갱신 dbg(DBG_TEMP, "MHGossipingPSM - Updating entry for node %i in neighbour table\n", id); neighbourTable[entryIndex].receivedCount++; neighbourTable[entryIndex].timerTicks = 0; neighbourTable[entryIndex].nodeAlive = TRUE; neighbourTable[entryIndex].strength = strength; } else if (nodeDeadIndex != entries) { // 죽은 노드는 다른 노드로 대체 dbg(DBG_TEMP, "MHGossipingPSM - Replacing dead node %i for node %i in neighbour table\n", neighbourTable[nodeDeadIndex].nodeID, id); neighbourTable[nodeDeadIndex].nodeID = id; neighbourTable[nodeDeadIndex].receivedCount = 1; ………………………………... } else if (entries < NEIGHBOUR_TABLE_SIZE) { // 아직 테이블이 가득차지 않았다면 새로운 엔트리 추가 dbg(DBG_TEMP, "MHGossipingPSM - Adding entry for node %i in neighbour table\n", id); neighbourTable[entries].nodeID = id; ……………………………….. } else if (strength > lowestStrength) { // 신호 세기가 약한 노드는 다른 노드로 대체 { dbg(DBG_TEMP, "MHGossipingPSM - Replacing node %i for node %i in neighbour table\n", ………………………………… } }
2. Gossiping Protocol • Module – MHGossipingPSM.nc (con’d) task void updateTable() { // 테이블 갱신 int i; for (i = 0; i < entries; i++) { if (neighbourTable[i].nodeAlive == TRUE) {// 무한 Tick 현상을 제거하기 위해 살아있는 노드만 갱신 neighbourTable[i].timerTicks++; if (neighbourTable[i].timerTicks >= NEIGHBOUR_DEAD_TICKS) { dbg(DBG_TEMP, "MHGossipingPSM - Setting node %i as dead in neighbour table\n", neighbourTable[i].nodeID); neighbourTable[i].nodeAlive = FALSE; } } } } task void advertise() { // 주기적 advertise 패킷 전송 RoutePacket *pRP = (RoutePacket *) &routeMsg.data[0]; uint8_t length = sizeof(RoutePacket); if (sendRouteBusy == TRUE) { return; } // 채널이 사용중일때는 전송 중지 pRP->nodeID = TOS_LOCAL_ADDRESS; if (call SendMsg.send(TOS_BCAST_ADDR, length, &routeMsg) == SUCCESS) { // 전송하기 atomic { call Leds.redToggle(); } // 전송중일때는 빨간 LED 깜빡이기 dbg(DBG_TEMP, "MHGossipingPSM - Advertising presence\n"); atomic sendRouteBusy = TRUE; } }
2. Gossiping Protocol • Module – MHGossipingPSM.nc (con’d) command result_t StdControl.init() { entries = 0; sendRouteBusy = FALSE; call Random.init(); // 각 변수 초기화 return SUCCESS; } command result_t StdControl.start() { return call Timer.start(TIMER_REPEAT, ROUTE_UPDATE_RATE); } command result_t StdControl.stop() { return call Timer.stop(); } command bool RouteSelect.isActive() { // 이웃에서 작동중인 노드의 존재 유무 검사 int i; bool alive = FALSE; for (i = 0; i < entries; i++) { if (neighbourTable[i].nodeAlive == TRUE) { alive = TRUE; break; } } return alive; }
2. Gossiping Protocol • Module – MHGossipingPSM.nc (con’d) command result_t RouteSelect.selectRoute(TOS_MsgPtr msg, uint8_t id) { MHMessage *pMHMsg = (MHMessage *) &msg->data[0]; if (pMHMsg->sendingNode != TOS_LOCAL_ADDRESS) { pMHMsg->sendingNode = TOS_LOCAL_ADDRESS; pMHMsg->hopCount++; // 다른 노드로부터 패킷을 수신한 경우 } if (TOS_LOCAL_ADDRESS == BASE_STATION_ADDRESS) { msg->addr = TOS_UART_ADDR; // 패킷이 local 노드에서 생성된 경우, 목적지 주소를 UART(Serial)로 설정 } else if (entries > 0) { // 외부의 패킷이면 이웃 entry 에서 한 노드를 랜덤하게 선택한다 uint16_t num = call Random.rand() % entries; int i; for (i = 0; i < entries; i++) { // 살아있는 노드인경우 현재 메시지의 다음 경로로 지정 if (neighbourTable[num].nodeAlive == TRUE) { msg->addr = neighbourTable[num].nodeID; break; } else { num++; num = num % entries; } } // 엔트리 검색에서 라우팅이 가능한 어떤 노드도 발견하지 못한 경우 if (i == entries) { dbg(DBG_TEMP, "MHGossipingPSM - Failed to select route\n"); return FAIL; } } else { dbg(DBG_TEMP, "MHGossipingPSM - Failed to select route\n"); return FAIL; } if (pMHMsg->hopCount < MAX_HOP_COUNT || msg->addr == TOS_UART_ADDR) { // TTL 유효 or UART dbg(DBG_TEMP, "MHGossipingPSM - Route selected\n"); // 라우팅 성공 return SUCCESS; } dbg(DBG_TEMP, "MHGossipingPSM - Failed to select route - hop count exceeded\n"); return FAIL; // 패킷 폐기 }
2. Gossiping Protocol • Module – MHGossipingPSM.nc (con’d) command result_t RouteSelect.initializeFields(TOS_MsgPtr msg, uint8_t id) { MHMessage *pMHMsg = (MHMessage *) &msg->data[0]; pMHMsg->originNode = pMHMsg->sendingNode = TOS_LOCAL_ADDRESS; pMHMsg->hopCount = 0; // 메시지의 각 필드 초기화 return SUCCESS; } event result_t Timer.fired() { // 타이머 만료시 post updateTable(); //이웃 테이블 갱신 post advertise(); return SUCCESS; } event TOS_MsgPtr ReceiveMsg.receive(TOS_MsgPtr m) { // 메시지를 수신했을 때 (Advertise) RoutePacket *pRP = (RoutePacket *) m->data; atomic { call Leds.redToggle(); } // 빨간 LED 깜빡이기 dbg(DBG_TEMP, "MHGossipingPSM - Advertisment received from node %i\n", pRP->nodeID); updateTableEntry(pRP->nodeID, m->strength); return m; } event result_t SendMsg.sendDone(TOS_MsgPtr msg, result_t success) { // 라우팅 메시지가 본내진 경우 atomic sendRouteBusy = FALSE; return SUCCESS; }
2. Gossiping Protocol • Result - TinyViz
3. LEACH Protocol • LEACH Protocol • Low-Energy Adaptive Clustering Hierarchy • 인접 노드들끼리 대표 노드(coordinator) 선출 • 센싱 데이터는 대표 노드를 통해서만 전송 • 모든 노드들이 전송에 참여하지 않아도 됨 • Best Case : 높은 Delivery Ratio • 대표 노드는 전력 소모가 심하므로 주기적으로 대표 노드 변경 • Worst Case : 대표 노드가 Sink 노드와 전송이 불가능한 상황 • 모든 노드가 전송 전력을 최대로 설정한다는 가정의 한계 • 대표 노드간의 MH 구성 또는 대표노드와 Sink 노드간 Topology 구성이 요구됨.
3. LEACH Protocol • Configuration – TempMon.nc • Makefile includes TempMon; includes MH; configuration TempMon{ } Implementation { components Main, TempMonM, TimerC, Temp, GenericComm as Comm,QueuedSend, SimpleTime, #ifdef FLOODING MHFloodingRouter as Router; #endif #ifdef GOSSIPING MHGossipingRouter as Router; #endif #ifdef LEACH // LEACH 가 define 된 경우 MHLeachRouter as Router; #endif COMPONENT=TempMon SENSORBOARD=basicsb PFLAGS= -I. -I./Queue -DLEACH -DLEACH_PROBABILITY=25 -DSIM=10 include ../../../../apps/Makerules
3. LEACH Protocol • Configuration – TempMon.nc (con’d) & headers Main.StdControl -> TempMonM.StdControl; Main.StdControl -> Router.StdControl; // 라우팅 프로토콜 연결 Main.StdControl -> Comm.Control; Main.StdControl -> QueuedSend.StdControl; Main.StdControl -> Temp.StdControl; Main.StdControl -> TimerC.StdControl; Main.StdControl -> SimpleTime.StdControl; TempMonM.ADC -> Temp.TempADC; TempMonM.Timer -> TimerC.Timer[unique("Timer")]; TempMonM.Send -> Router.Send[AM_TEMPMONMSG]; // 전송 컴포넌트 연결 TempMonM.GlobalTime -> Router.GlobalTime; Router.ReceiveMsg[AM_TEMPMONMSG] -> Comm.ReceiveMsg[AM_TEMPMONMSG]; } /* tempMon.h */ enum { TIMER_RATE = 5000, // Send a message every 5 seconds AM_TEMPMONMSG = 10, }; typedef struct TempMonMsg { uint16_t address; uint32_t timestamp; uint16_t reading; } __attribute__ ((packed)) TempMonMsg; /* MH.h */ ... LEACH_ROUTE_UPDATE_RATE = 10000, // 10 sec LEACH_ROUND_LENGTH = 600000, // 10 min LEACH_NEIGHBOUR_TABLE_SIZE = 32 ... /* MH.h */ typedef struct MHMessage { uint16_t sendingNode; uint16_t originNode; uint16_t seqNo; uint16_t hopCount; uint8_t data[(TOSH_DATA_LENGTH - 8)]; } __attribute__ ((packed)) MHMessage;
3. LEACH Protocol • Configuration – MHLeachRouter.nc includes MH; configuration MHLeachRouter{ provides { interface StdControl; interface Receive[uint8_t id]; interface Send[uint8_t id]; interface Intercept[uint8_t id]; interface GlobalTime; } uses { interface ReceiveMsg[uint8_t id]; } } Implementation{ components MHEngineM, MHLeachPSM, GenericComm as Comm, QueuedSend, TimerC, RandomLFSR, SimpleTime, TimeSyncM, LedsC;// MHEngine, MHLeachPSM 컴포넌트 연결 StdControl = MHEngineM.StdControl; Receive = MHEngineM.Receive; Send = MHEngineM.Send; ReceiveMsg = MHEngineM.ReceiveMsg; Intercept = MHEngineM.Intercept; GlobalTime = TimeSyncM.GlobalTime; MHEngineM.CommStdControl -> Comm.Control;
3. LEACH Protocol • Configuration – MHLeachRouter.nc (con’d) #ifdef SIM MHEngineM.SimTimer -> TimerC.Timer[unique("Timer")]; #endif MHEngineM.SubControl -> QueuedSend.StdControl; MHEngineM.SendMsg -> QueuedSend.SendMsg; MHEngineM.SubControl -> MHLeachPSM.StdControl; MHEngineM.RouteSelect -> MHLeachPSM.RouteSelect; // Leach 프로토콜이 구현된 MHLeachPSM 에 연결 MHLeachPSM.StatusTimer -> TimerC.Timer[unique("Timer")]; MHLeachPSM.RoundTimer -> TimerC.Timer[unique("Timer")]; MHLeachPSM.ReceiveMsg -> Comm.ReceiveMsg[AM_MHMESSAGE]; MHLeachPSM.SendMsg -> QueuedSend.SendMsg[AM_MHMESSAGE]; // 메시지 큐 MHLeachPSM.Random -> RandomLFSR.Random; // 랜덤값 발생 MHEngineM.Leds -> LedsC.Leds; TimeSyncM.Leds -> LedsC.Leds; MHLeachPSM.Leds -> LedsC.Leds; MHEngineM.SubControl -> TimeSyncM.StdControl; TimeSyncM.Timer -> TimerC.Timer[unique("Timer")]; TimeSyncM.Time -> SimpleTime.Time; TimeSyncM.ReceiveMsg -> Comm.ReceiveMsg[AM_TIMESYNC]; TimeSyncM.SendMsg -> QueuedSend.SendMsg[AM_TIMESYNC]; // 메시지 큐 MHEngineM.GlobalTime -> TimeSyncM.GlobalTime; }
3. LEACH Protocol • Module – MHLeachPSM.nc includes AM; includes MH; module MHLeachPSM { provides { interface StdControl; interface RouteSelect; // Leach 프로토콜 Router 인터페이스 } uses { interface Timer as RoundTimer; interface Timer as StatusTimer; interface ReceiveMsg; interface SendMsg; interface Random; interface Leds; } }
3. LEACH Protocol • Module – MHLeachPSM.nc (con’d) implementation { typedef struct RoutePacket { // 라우팅할 패킷 구조체 uint16_t addr; // Broadcast 주소로 지정된 패킷은 상태 구분 메시지로 간주 uint16_t nodeID; // 특적 목적지가 지정된 패킷은 Fowarding 요청으로 간주 uint16_t depth; uint8_t round; bool isClusterHead; // cluster coordinator 여부를 가지는 플래그 bool becomeClusterHead; // cluster coordinator 가 되는 노드가 가지는 플래그 } __attribute__ ((packed)) RoutePacket; typedef struct NeighbourTable { uint16_t nodeID; bool isClusterHead; // 이웃 노드 라우팅 테이블 uint16_t depth; // 라우팅 계층의 깊이 uint8_t timerTicks; bool nodeAlive; // 노드가 살아있는지 여부 uint16_t strength; // 신호의 세기 } NeighbourTable;
3. LEACH Protocol • Module – MHLeachPSM.nc (con’d) enum { ROUND_LENGTH = LEACH_ROUND_LENGTH, ROUTE_UPDATE_RATE = LEACH_ROUTE_UPDATE_RATE, NEIGHBOUR_TABLE_SIZE = LEACH_NEIGHBOUR_TABLE_SIZE, NEIGHBOUR_DEAD_TICKS = 5, TIMEOUT_TICKS = 5, // cluster coordinator 가 되기전까지의 대기시간(Tick 단위) PARENT_INVALID = 0xeeee, INFINITY = 0xffff, ROUND_INVALID = 0xff, PROBABILITY = LEACH_PROBABILITY // 확률 설정 }; uint8_t round; // Current LEACH round uint16_t parentID; bool isClusterHead; uint16_t depth; // 라우팅 트리에서의 깊이 uint8_t ticks; // cluster coordinator 없이 전송한 시간(누적) TOS_Msg routeMsg; // 라우팅 정보를 저장할 메시지 구조체 bool sendRouteBusy; // 노드의 전송 상태 플래그(Busy or not) uint16_t addr; NeighbourTable neighbours[NEIGHBOUR_TABLE_SIZE]; // 이웃 노드의 라우팅 정보를 저장하는 테이블 배열 uint16_t tableEntries;
3. LEACH Protocol • Module – MHLeachPSM.nc (con’d) static void updateTable() { // 라우팅 테이블 업데이트 int i; for (i = 0; i < tableEntries; i++) { // 노드가 살아있는 경우만 테이블 갱신, 무한 tick 현상 예방 if (neighbours[i].nodeAlive == TRUE) { neighbours[i].timerTicks++; if (neighbours[i].timerTicks >= NEIGHBOUR_DEAD_TICKS) dbg(DBG_TEMP, "MHLeachPSM - Setting node %i as dead in neighbour table\n", neighbours[i].nodeID); neighbours[i].nodeAlive = FALSE; } } }
3. LEACH Protocol • Module – MHLeachPSM.nc (con’d) static void updateTableEntry(uint16_t id, uint16_t treeDepth, bool isHead, uint16_t strength) { int i; // 테이블에서 엔트리를 검색, 죽은 노드와 가장 높은 Hop 노드는 걸러냄 uint16_t maxLeafDepth, maxHeadDepth; int maxLeafIndex, maxHeadIndex, nodeDead; maxLeafDepth = maxHeadDepth = 0; // sink 노드( ID = 0 ) 만이 Depth 가 0 maxLeafIndex = maxHeadIndex = nodeDead = tableEntries; for (i = 0; i < tableEntries; i++) { if (neighbours[i].nodeID == id) { break; }// 노드가 엔트리를 가진경우 else if ((neighbours[i].nodeAlive == FALSE) && (nodeDead == tableEntries)) { nodeDead = i; // 노드가 죽은경우 } else if ((neighbours[i].isClusterHead == TRUE) && (neighbours[i].depth > maxHeadDepth)) { maxHeadDepth = neighbours[i].depth;// 노드가 cluster coordinator 인 동시에 Depth가 가장 큰 경우 maxHeadIndex = i; } else if (neighbours[i].depth > maxLeafDepth) { // 노드가 leaf 노드인 동시에 Depth가 가장 큰 경우 maxLeafDepth = neighbours[i].depth; maxLeafIndex = i; } }
3. LEACH Protocol • Module – MHLeachPSM.nc (con’d) if (i < tableEntries) { // 테이블 업데이트 dbg(DBG_TEMP, "MHLeachPSM - Updating node %i in neighbour table\n", id); neighbours[i].isClusterHead = isHead; neighbours[i].depth = treeDepth; neighbours[i].timerTicks = 0; neighbours[i].nodeAlive = TRUE; neighbours[i].strength = strength; } else if (nodeDead != tableEntries) { // 죽은 노드 엔트리 교체 neighbours[nodeDead].nodeID, id); } else if (tableEntries < NEIGHBOUR_TABLE_SIZE) { // 테이블에 여유 공간이 있는 경우 neighbours[tableEntries].nodeID = id; } else if ((isHead == TRUE) && (maxLeafIndex != tableEntries)) { // leaf 노드와 cluster coordinator 교체 neighbours[maxLeafIndex].nodeID, id); } else if ((maxLeafIndex != tableEntries) && (maxLeafDepth > treeDepth)) { // leaf 노드중 더 낮은 깊이의 노드로 교체 neighbours[maxLeafIndex].nodeID, id); } else if ((isHead == TRUE) && (maxHeadIndex != tableEntries) && (maxHeadDepth > treeDepth)) { neighbours[maxHeadIndex].nodeID = id // cluster coordinator 노드를 sink 노드에 더 가까운 노드로 교체 } }
3. LEACH Protocol • Module – MHLeachPSM.nc (con’d) static void selectParent() { // 각 노드의 부모노드 선택 int i; uint16_t minLeafDepth, minHeadDepth; int minLeafIndex, minHeadIndex; ticks++; minLeafDepth = minHeadDepth = INFINITY; minLeafIndex = minHeadIndex = tableEntries; for (i = 0; i < tableEntries; i++) { if ((neighbours[i].isClusterHead == TRUE) && (neighbours[i].depth < minHeadDepth)) { minHeadDepth = neighbours[i].depth; // 노드가 cluster coordinator 인 동시에 가장 낮은 깊이일 때 minHeadIndex = i; } else if (neighbours[i].depth < minLeafDepth) { // 노드가 leaf 노드인 동시에 가장 낮은 깊이일 때 minLeafDepth = neighbours[i].depth; minLeafIndex = i; } }
3. LEACH Protocol • Module – MHLeachPSM.nc (con’d) if (minHeadIndex != tableEntries) { // 가장 낮은 깊이의 cluster coordinator parentID = neighbours[minHeadIndex].nodeID; depth = neighbours[minHeadIndex].depth + 1; ticks = 0; dbg(DBG_TEMP, "MHLeachPSM - New parent selected (ID: %i)\n", parentID); return; } else if (ticks >= TIMEOUT_TICKS) { // leaf 노드로부터의 연결이 timeout 된 경우 if (minLeafIndex != tableEntries) { atomic addr = neighbours[minLeafIndex].nodeID; // 매 time tick 마다 대표가 될 적절한 노드가 있는지 검사 } ticks = 0; // timeout reset } parentID = PARENT_INVALID; dbg(DBG_TEMP, "MHLeachPSM - Could not select new parent\n"); depth = INFINITY; }
3. LEACH Protocol • Module – MHLeachPSM.nc (con’d) static void nextRound() { round = (round + 1) % ROUND_INVALID; } // 다음 노드 찾기 static bool isNewRound(uint8_t r) { // 비정상적인 노드 advertising if (r == ROUND_INVALID) { return FALSE; } // 아직 round 배정을 받지 못한 경우 else if (round == ROUND_INVALID) { return TRUE; } else { uint8_t previous; if (round == 0) { previous = ROUND_INVALID - 1; } else { previous = round--; } if ((r != round) && (r != previous)) { return TRUE; } else { return FALSE; } } }
3. LEACH Protocol • Module – MHLeachPSM.nc (con’d) task void advertise() { RoutePacket *pRP = (RoutePacket *) &routeMsg.data[0]; // 라우팅 정보 저장용 패킷 구조체 포인팅 uint8_t length = sizeof(RoutePacket); if (sendRouteBusy == TRUE) { return; } // 노드가 전송중일때는 전종 작업 중단 pRP->addr = addr; atomic addr = TOS_BCAST_ADDR; // broadcast pRP->nodeID = TOS_LOCAL_ADDRESS; // local 주소 지정 pRP->depth = depth; pRP->round = round; pRP->isClusterHead = isClusterHead; if (pRP->addr != TOS_BCAST_ADDR) { // forwarding 요청에 대한 필드 설정 dbg(DBG_TEMP, "MHLeachPSM - Requesting node %i become a cluster head\n", pRP->addr); pRP->becomeClusterHead = TRUE; } else { pRP->becomeClusterHead = FALSE; } // 포워딩 되므로 cluster coordinator 가 아님 if (call SendMsg.send(TOS_BCAST_ADDR, length, &routeMsg) == SUCCESS) { atomic { call Leds.redToggle(); } // RF 전송중에는 빨간 LED 깜박이기 dbg(DBG_TEMP, "MHLeachPSM - Advertising presence (Cluster Head: %i)\n", (int) isClusterHead); atomic sendRouteBusy = TRUE; // 전송중 플래그 활성화 } }
3. LEACH Protocol • Module – MHLeachPSM.nc (con’d) static void init() { tableEntries = 0; ticks = 0; addr = TOS_BCAST_ADDR; // Normal route packet - no forwarding request if (TOS_LOCAL_ADDRESS == BASE_STATION_ADDRESS) { round = 0; parentID = TOS_UART_ADDR; // 메시지의 목적지가 자기자신(Local)인 경우 UART(Serial) 전송 isClusterHead = TRUE; depth = 0; } else { round = ROUND_INVALID; parentID = PARENT_INVALID; isClusterHead = FALSE; depth = INFINITY; } }
3. LEACH Protocol • Module – MHLeachPSM.nc (con’d) static void startNewRound(uint8_t r) { // 새로운 round[cluster coordinator 변경] 시작 // 노드 상태에 따라 결정, (확률, 난수) uint16_t probability = ((uint16_t) PROBABILITY) * (0xffff / 100); uint16_t randNo = call Random.rand(); bool clusterStatus = randNo < probability; dbg(DBG_TEMP, "MHLeachPSM - Round %i started (Cluster Head: %i)\n", r, (int) clusterStatus); atomic { round = r; ticks = 0; tableEntries = 0; parentID = PARENT_INVALID; // 대표 노드이므로 depth = INFINITY; addr = TOS_BCAST_ADDR; isClusterHead = clusterStatus; } }
3. LEACH Protocol • Module – MHLeachPSM.nc (con’d) command result_t StdControl.init() { init(); return call Random.init(); // 초기화 } command result_t StdControl.start() { // sink 노드부터 cluster coordinator round 시작 if (TOS_LOCAL_ADDRESS == BASE_STATION_ADDRESS) { call RoundTimer.start(TIMER_REPEAT, ROUND_LENGTH); // sink 노드인경우 } return call StatusTimer.start(TIMER_REPEAT, ROUTE_UPDATE_RATE); } command result_t StdControl.stop() { call RoundTimer.stop(); return call StatusTimer.stop(); } command bool RouteSelect.isActive() { if (parentID != PARENT_INVALID) { return TRUE; } return FALSE; }
3. LEACH Protocol • Module – MHLeachPSM.nc (con’d) command result_t RouteSelect.selectRoute(TOS_MsgPtr msg, uint8_t id) { MHMessage *pMHMsg = (MHMessage *) &msg->data[0]; // MH 메시지 전송용 구조체 포인터 // 패킷이 자기 자신으로부터 생겨난 경우 ↓ if ((pMHMsg->originNode == TOS_LOCAL_ADDRESS) && (pMHMsg->hopCount == 0)) { if (parentID != PARENT_INVALID) { // 부모노드는 없음 dbg(DBG_TEMP, "MHLeachPSM - Routing to node %i\n", parentID); msg->addr = parentID; return SUCCESS; } } else { // 자신이 아닌 다른 곳에서 온 패킷인 경우 if ((isClusterHead == TRUE) && (parentID != PARENT_INVALID)) { // 대표노드일때만 pMHMsg->sendingNode = TOS_LOCAL_ADDRESS; pMHMsg->hopCount++; // hop count 올리기 dbg(DBG_TEMP, "MHLeachPSM - Routing to node %i\n", parentID); msg->addr = parentID; return SUCCESS; } dbg(DBG_TEMP, "MHLeachPSM - Could not select route\n"); return FAIL; } }
3. LEACH Protocol • Module – MHLeachPSM.nc (con’d) command result_t RouteSelect.initializeFields(TOS_MsgPtr msg, uint8_t id) { MHMessage *pMHMsg = (MHMessage *) &msg->data[0]; // MH 메시지용 자료 형변환 pMHMsg->originNode = pMHMsg->sendingNode = TOS_LOCAL_ADDRESS; pMHMsg->hopCount = 0; // 메시지에 기본값들 부여, TTL =0 return SUCCESS; } event result_t RoundTimer.fired() { // 라우팅 타이머 만료시 dbg(DBG_TEMP, "MHLeachPSM - Round Timer fired\n"); nextRound(); // 새로운 대표노드 선택 return SUCCESS; } event result_t StatusTimer.fired() { // 노드 상태 타이머 만료시 if ((TOS_LOCAL_ADDRESS != BASE_STATION_ADDRESS) && (round != ROUND_INVALID)) { updateTable(); selectParent(); } post advertise(); return SUCCESS; } event result_t SendMsg.sendDone(TOS_MsgPtr msg, result_t success) { atomic sendRouteBusy = FALSE; // 전송 완료시 return SUCCESS; }
3. LEACH Protocol • Module – MHLeachPSM.nc (con’d) event TOS_MsgPtr ReceiveMsg.receive(TOS_MsgPtr m) { atomic { call Leds.redToggle(); } // 전송중에는 빨간 LED 깜박이기 if (TOS_LOCAL_ADDRESS != BASE_STATION_ADDRESS) { // sink 노드는 다른 노드의 정보가 불필요 RoutePacket *pRP = (RoutePacket *) m->data; if (pRP->round != ROUND_INVALID) { // 비정상적인 round 인 경우 if (isNewRound(pRP->round) == TRUE) { startNewRound(pRP->round); // 새로운 round 시작 } else if (pRP->addr == TOS_LOCAL_ADDRESS) { // 패킷이 현재 노드에 forwarding 요청을 하는경우 isClusterHead = pRP->becomeClusterHead; if (pRP->becomeClusterHead == TRUE) { // cluster coordinator 로 설정되었을 때 dbg(DBG_TEMP, "MHLeachPSM - Becoming cluster head at request of node %i\n", pRP->nodeID); } } dbg(DBG_TEMP, "MHLeachPSM - Received advert (Origin ID: %i, Cluster Head: %i,Depth: %i)\n", pRP->nodeID, (int) pRP->isClusterHead, pRP->depth); updateTableEntry(pRP->nodeID, pRP->depth, pRP->isClusterHead, m->strength); } } return m; }