前面我们已经打下了BLIP+RPL的基础,本次例程将全部使用 并添加UART的pppd拨号实现边界路由器;这个例程是核心中的核心;使用它我们可以查看网络路由表而不是再只是通过抓包来自己分析;使用它访问其他的zigbee节点,如下一篇带来的实验CoAPServer;
例程目录:tinyos-main-release_tinyos_2_1_2\apps\cc2538_Test\PppRouter
Makefile文件:前面的介绍大家应该已经清楚了写法,现在开始省略
PppRouterC.nc文件:
#include <iprouting.h>
#include "ppp.h"
configuration PppRouterC {
} implementation {
components PppRouterP;
components MainC;
PppRouterP.Boot -> MainC;
components LedsC as LedsC;
PppRouterP.Leds -> LedsC;
components PppDaemonC;
PppRouterP.PppControl -> PppDaemonC;
components PppIpv6C;
PppDaemonC.PppProtocol[PppIpv6C.ControlProtocol] -> PppIpv6C.PppControlProtocol;
PppDaemonC.PppProtocol[PppIpv6C.Protocol] -> PppIpv6C.PppProtocol;
PppIpv6C.Ppp -> PppDaemonC;
PppIpv6C.LowerLcpAutomaton -> PppDaemonC;
PppRouterP.Ipv6LcpAutomaton -> PppIpv6C;
PppRouterP.PppIpv6 -> PppIpv6C;
PppRouterP.Ppp -> PppDaemonC;
#if defined(PLATFORM_TELOSB) || defined(PLATFORM_EPIC)
components PlatformHdlcUartC as HdlcUartC;
#else
components DefaultHdlcUartC as HdlcUartC;
#endif
PppDaemonC.HdlcUart -> HdlcUartC;
PppDaemonC.UartControl -> HdlcUartC;
// SDH : don't bother including the PppPrintfC by default
// components PppPrintfC, PppC;;
// PppPrintfC.Ppp -> PppDaemonC;
// PppDaemonC.PppProtocol[PppPrintfC.Protocol] -> PppPrintfC;
// PppPrintfC.Ppp -> PppC;
components IPStackC, IPForwardingEngineP, IPPacketC;
IPForwardingEngineP.IPForward[ROUTE_IFACE_PPP] -> PppRouterP.IPForward;
PppRouterP.IPControl -> IPStackC;
PppRouterP.ForwardingTable -> IPStackC;
PppRouterP.IPPacket -> IPPacketC;
#ifdef RPL_ROUTING
components RPLRoutingC, RplBorderRouterP;
PppRouterP.RootControl -> RPLRoutingC;
RplBorderRouterP.ForwardingEvents -> IPStackC.ForwardingEvents[ROUTE_IFACE_PPP];
RplBorderRouterP.IPPacket -> IPPacketC;
#endif
// UDP shell on port 2000
components UDPShellC;
// prints the routing table
components RouteCmdC;
#ifdef IN6_PREFIX
components StaticIPAddressTosIdC; // Use TOS_NODE_ID in address
//components StaticIPAddressC; // Use LocalIeee154 in address
#else
components Dhcp6C;
components Dhcp6ClientC;
PppRouterP.Dhcp6Info -> Dhcp6ClientC;
#endif
}
注意 components UDPShellC;
components RouteCmdC;这两个组件,自行去查看底层代码,原来测试命令中的route,heip等是他们定义的,参考他们的写法自己可以定义其他命令,如温度等
PppRouterP.nc文件:
<span style="font-family: Arial, Helvetica, sans-serif;">/*********************************************************************************************************************************************************</span>
*实验7----zigbee 边界路由实验
*节点需求数 >= 2
*编译命令make cc2538cb blip id.xx (xx为1~65533)
*测试命令:
*1,sudo /usr/bin/pppd-hack/sbin/pppd debug passive noauth nodetach 115200 /dev/ttyUSB0 nocrtscts nocdtrcts lcp-echo-interval 0 noccp noip ipv6 ::23,::24 连接边界路由
*2,新打开shell,执行sudo ifconfig ppp0 add fec0::100/64
*3,3.1和3.2为两种测试方法,采取一种即可
* 3.1执行nc6 -u fec0::1 2000
* route
* ping6 ff02::xx(xx为1~65533,且为烧写的测试节点号
* 3.2
* ping6 ff02::xx(xx为1~65533,且为烧写的测试节点号
* 也可以参考\apps\cc2538_Test\PppRouter下的README.blip进行测试,但是注意第一步命令pppd的区别
* 更多命令支持请参考tinyos-main-release_tinyos_2_1_2\tos\lib\net\blip\shell的UDPShellP.nc文件,如help等,也可以自己添加入传感器等等
********************************************************************************************************************************************************/
#include <stdio.h>
#include <lib6lowpan/ip.h>
#include <lib6lowpan/nwbyte.h>
#include <lib6lowpan/ip_malloc.h>
#include <dhcp6.h>
#include "pppipv6.h"
#include "blip_printf.h"
module PppRouterP {
provides {
interface IPForward;
}
uses {
interface Boot;
interface Leds;
interface SplitControl as IPControl;
interface SplitControl as PppControl;
interface LcpAutomaton as Ipv6LcpAutomaton;
interface PppIpv6;
interface Ppp;
interface ForwardingTable;
interface RootControl;
interface Dhcp6Info;
interface IPPacket;
}
} implementation {
event void PppIpv6.linkUp() {}
event void PppIpv6.linkDown() {}
event void Ipv6LcpAutomaton.transitionCompleted (LcpAutomatonState_e state) { }
event void Ipv6LcpAutomaton.thisLayerUp () { }
event void Ipv6LcpAutomaton.thisLayerDown () { }
event void Ipv6LcpAutomaton.thisLayerStarted () { }
event void Ipv6LcpAutomaton.thisLayerFinished () { }
event void PppControl.startDone (error_t error) { }
event void PppControl.stopDone (error_t error) { }
event void IPControl.startDone (error_t error) {
struct in6_addr dhcp6_group;
// add a route to the dhcp group on PPP, not the radio (which is the default)
inet_pton6(DH6ADDR_ALLAGENT, &dhcp6_group);
call ForwardingTable.addRoute(dhcp6_group.s6_addr, 128, NULL, ROUTE_IFACE_PPP);
// add a default route through the PPP link
call ForwardingTable.addRoute(NULL, 0, NULL, ROUTE_IFACE_PPP);
}
event void IPControl.stopDone (error_t error) { }
event void Boot.booted() {
error_t rc;
#ifndef PRINTFUART_ENABLED
rc = call Ipv6LcpAutomaton.open();
rc = call PppControl.start();
#endif
#ifdef RPL_ROUTING
call RootControl.setRoot();
#endif
#ifndef IN6_PREFIX
call Dhcp6Info.useUnicast(FALSE);
#endif
call IPControl.start();
}
event error_t PppIpv6.receive(const uint8_t* data,
unsigned int len) {
struct ip6_hdr *iph = (struct ip6_hdr *)data;
void *payload = (iph + 1);
call Leds.led0Toggle();
signal IPForward.recv(iph, payload, NULL);
return SUCCESS;
}
command error_t IPForward.send(struct in6_addr *next_hop,
struct ip6_packet *msg,
void *data) {
size_t len = iov_len(msg->ip6_data) + sizeof(struct ip6_hdr);
error_t rc;
frame_key_t key;
const uint8_t* fpe;
uint8_t* fp;
if (!call PppIpv6.linkIsUp())
return EOFF;
// get an output frame
fp = call Ppp.getOutputFrame(PppProtocol_Ipv6, &fpe, FALSE, &key);
if ((! fp) || ((fpe - fp) < len)) {
if (fp) {
call Ppp.releaseOutputFrame(key);
}
call Leds.led2Toggle();
return ENOMEM;
}
// copy the header and body into the frame
memcpy(fp, &msg->ip6_hdr, sizeof(struct ip6_hdr));
iov_read(msg->ip6_data, 0, len, fp + sizeof(struct ip6_hdr));
rc = call Ppp.fixOutputFrameLength(key, fp + len);
if (SUCCESS == rc) {
rc = call Ppp.sendOutputFrame(key);
}
call Leds.led1Toggle();
return rc;
}
event void Ppp.outputFrameTransmitted (frame_key_t key,
error_t err) { }
}
阅读代码可以发现PRINTFUART_ENABLED不要开启,不然ppp模块是编译去除的;
源码是pppd的例程部分和发送数据接收数据的处理
RplBorderRouterP.nc文件:
#include <lib6lowpan/ip.h>
#include <iprouting.h>
#include <RPL.h>
module RplBorderRouterP {
uses {
interface ForwardingEvents;
interface IPPacket;
}
} implementation {
event bool ForwardingEvents.initiate(struct ip6_packet *pkt,
struct in6_addr *next_hop) {
return TRUE;
}
event bool ForwardingEvents.approve(struct ip6_packet *pkt,
struct in6_addr *next_hop) {
int off;
uint8_t nxt = IPV6_HOP;
if (pkt->ip6_inputif == ROUTE_IFACE_PPP)
return FALSE;
/* remove any RPL options in the hop-by-hop header by converting
them to a PadN option */
off = call IPPacket.findHeader(pkt->ip6_data, pkt->ip6_hdr.ip6_nxt, &nxt);
if (off < 0) return TRUE;
call IPPacket.delTLV(pkt->ip6_data, off, RPL_HBH_RANK_TYPE);
return TRUE;
}
event void ForwardingEvents.linkResult(struct in6_addr *dest, struct send_info *info) {
}
}
这个components是缺省写法,大家以后可以学习他的写法来偷懒,没有编写configuration和interface文件;
文件中的事件是网络路由事件;
本例程带有测试视频;截图神马的就忽略了,其中的pppd命令使用自己安装的pppd_hack的原因是因为当主机是XP的时候,虚拟机使用pppd命令,出现假死,当主机是WIN8的时候,虚拟机同样的使用pppd时正常的;于是我干脆自己安装了pppd_hack,这样主机XP或WIN8就都可以了;pppd_hack虚拟机已经安装好,参考的lab11的blip测试网页安装,百度网盘也有安装包;
可以先烧写一个Ppprouter节点连接PC,按照视频启动pppd连接,可以输入路由表查看命令,查看本机路由;
再准备一个UDPECHO节点,编译烧写,再在虚拟机查看Ppprouter节点路由表或者登陆UDPECHO节点,查看一下它的路由表;
当然你也可以先跳过UDPECHO;我自己就基本不测试他,可以pppd连接后,直接跳过测试,进入下一部CoAPServer节点实验实行ping6测试,coap的led控制!