TinyOS bug程序的执行01(T-Check中的bug)

来源:互联网 发布:理财大视野数据靠谱吗 编辑:程序博客网 时间:2024/05/17 08:16

bug1:串行栈bug + bug2

背景知识介绍

  1. 内容涉及到BaseStation节点与PC端数据通信的基本实现;
    注意:TinyOS2.X中数据包的格式是与平台无关的,因此PC端的程序可以与任意节点通信,而TinyOS1.X中的数据包与平台相关。

串行栈的相关知识

  1. TinyOS2.X串口协议栈(即在节点上)的4个功能组件从下至上的分别为:
    1、原始UART:功能为:为串口通信提供字节级数据的收发(例如:UartC组件提供的SerialByteCom接口) + 刷新缓存的功能(UartC组件提供的SerialFlush接口)
    2、编码器/装帧器:将原始字节数据转换为串口协议数据包格式.(该层的HdlcTranslaterC组件使用了SerialByteComm接口和提供了SerialFrameComm接口)
    3、传输协议:负责接收或发送协议数据包(Serial组件提供了面向字节的接口用于收发数据包),提供如下两个接口;
    ②、发送(SendBytePacket接口):从分派器发送到Uart
    ①、接收(ReceiveBytePacket):从Uart接收到的数据传到分派器(会有一个确认操作,因此会有延迟)
    4、分派器:负责处理协议组件接收的数据包(SerialDispatcherC组件)
    ①、使用了SendBytePacket和ReceiveBytePacket,提供Send和Receive接口
    ②、接收数据的过程:SerialDispatcherC收到SerialC发送的一个字节数据后,然后调用offset()确定偏移量,再将数据填充到message_t结构的缓存中。
  2. SerialActiveMessageC组件的简单介绍
    1、该组件是串行通信栈中顶层的配置组件
  3. 在串口栈中,数据包在连接过程中有如下格式,各协议字段分别和特定的组件对应
    1、帧字节(编码器/装帧器) + 协议字节(SerialP) + 序列字节(SerialP) + 数据包格式分派字节(SerialDispatcherC) + 有效负载payload(SerialDispatcher) + CR校验序列(Serial) + 帧字节
    2、payload:由组件SerialDispatcher读入的连续数据包。

MIG

  1. MIG(Message Interface Generator)消息接口产生器:通过该接口自动生成一个java类,用于将平台应用程序中的二进制数据打包成相应的消息数据类,来能耗的解析和显示。
  2. TestSerial应用程序就是用到了MIG:该程序中,利用MIG来生成对于BlinkToRadio数据包的msg代码
  3. 生成相应MSG代码历来与MakeFile文件,详情见《TinyOS是用编程》P141。

数据包源

  1. “数据包源”是传感器节点和PC直接通信的媒介,可用于接收节点上传的数据包,并向节点发送数据包。TinyOS常用的方式是串行代理连接(SerialForwarder)方式。
    (应该可以这样理解:串行栈位于节点上,而数据包源位于PC端)
  2. 数据包源的格式例如:serial@COM1:115200表示:串口使用直接连接方式 + 使用串口端口COM1 + 波特率为115200B
  3. SerialForwarder程序实现从串口中读取数据并在互联网中转发

串口通信测试TestSerial程序

  1. 程序功能:测试PC和节点之间的正常通信,节点和PC美妙会通过串口互发一个数据包。节点收到数据包在LED灯上打印,而PC收到数据包则打印数据包内容。
  2. TestSerial源码分析:
    http://blog.sina.com.cn/s/blog_5bce66f00100sj3d.html
    1、TestSerial.h文件
//定义数据包的有效数据typedef nx_struct test_serial_msg {  nx_uint16_t counter;  //计数   } test_serial_msg_t;

2、TestSerialC.nc

module TestSerialC {  uses {    // 串口的开关接口    interface SplitControl as Control;    interface Leds;    interface Boot;    interface Receive;    interface AMSend;    interface Timer<TMilli> as MilliTimer;    interface Packet;  }}implementation {  message_t packet;//数据包  bool locked = FALSE;//节点是否忙,同busy,发送数据时true,发送成功后置为false  uint16_t counter = 0;//数据包计数  event void Boot.booted() {    call Control.start(); //打开串口操作;向下找startDone。  }  //时间每次启动调用的函数  event void MilliTimer.fired() {    counter++;       if (locked) {      return;    }    else {      //设置数据包的有效负载,rcm指向数据包的有效负载      test_serial_msg_t* rcm = (test_serial_msg_t*)call Packet.getPayload(&packet, sizeof(test_serial_msg_t));      if (rcm == NULL) {return;}      //所发的数据超界      if (call Packet.maxPayloadLength() < sizeof(test_serial_msg_t)) {    return;      }      //设置有效负载的数据(即数据包的数据)      rcm->counter = counter;       //发送该数据包三个参数分别为:目的地址 + 数据包 + 有效负载的长度。寻找sendDone      if (call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(test_serial_msg_t)) == SUCCESS) {    locked = TRUE;      }    }  }  //接收数据程序,接收到数据后三位设置led灯,三个参数分别为:数据包 + 有效负载 + 有效负载长度。  event message_t* Receive.receive(message_t* bufPtr,                   void* payload, uint8_t len) {    if (len != sizeof(test_serial_msg_t)) {return bufPtr;}    else {      test_serial_msg_t* rcm = (test_serial_msg_t*)payload;      if (rcm->counter & 0x1) {    call Leds.led0On();      }      else {    call Leds.led0Off();      }      if (rcm->counter & 0x2) {    call Leds.led1On();      }      else {    call Leds.led1Off();      }      if (rcm->counter & 0x4) {    call Leds.led2On();      }      else {    call Leds.led2Off();      }      return bufPtr;    }  }  event void AMSend.sendDone(message_t* bufPtr, error_t error) {    if (&packet == bufPtr) {      locked = FALSE;//发送成功,节点空闲    }  }  event void Control.startDone(error_t err) {    if (err == SUCCESS) {      call MilliTimer.startPeriodic(1000);  //开始成功,调用计时器,每隔一秒触发fired    }  }  event void Control.stopDone(error_t err) {} //结束成功}

3、TestSerialAppC.nc

#include "TestSerial.h"configuration TestSerialAppC {}implementation {  components TestSerialC as App, LedsC, MainC;  components SerialActiveMessageC as AM;  components new TimerMilliC();  App.Boot -> MainC.Boot;  App.Control -> AM;  //参数化接口  App.Receive -> AM.Receive[AM_TEST_SERIAL_MSG];  App.AMSend -> AM.AMSend[AM_TEST_SERIAL_MSG];  App.Leds -> LedsC;  App.MilliTimer -> TimerMilliC;  App.Packet -> AM;}

4、TestSerial.java实现PC端实现与串口的连接和数据收发通信:

import java.io.IOException;import net.tinyos.message.*;import net.tinyos.packet.*;import net.tinyos.util.*;public class TestSerial implements MessageListener {  private MoteIF moteIF;  public TestSerial(MoteIF moteIF) {    this.moteIF = moteIF;    this.moteIF.registerListener(new TestSerialMsg(), this); //为节点添加监听事件  }  //发送数据包,由PC发给节点发送数据  public void sendPackets() {    int counter = 0;    TestSerialMsg payload = new TestSerialMsg();    try {      while (true) {    System.out.println("Sending packet " + counter); //输出接收的数据包,接收数据包的个数    payload.set_counter(counter);    moteIF.send(0, payload);//计算机给节点发送数据    counter++;    try {Thread.sleep(1000);}    catch (InterruptedException exception) {}      }    }    catch (IOException exception) {      System.err.println("Exception thrown when sending packets. Exiting.");      System.err.println(exception);    }  }  //接收节点向PC发送的数据,MessageListener的实现  public void messageReceived(int to, Message message) {    TestSerialMsg msg = (TestSerialMsg)message;    System.out.println("Received packet sequence number " + msg.get_counter());  }  private static void usage() {    System.err.println("usage: TestSerial [-comm <source>]");  }  //调用程序,传入参数为-comm serial@/dev/ttyUSB0:telosb  public static void main(String[] args) throws Exception {    String source = null;    if (args.length == 2) {      if (!args[0].equals("-comm")) {    usage();//提示信息    System.exit(1);      }      source = args[1]; //参数serial@/dev/ttyUSB0:telosb    }    else if (args.length != 0) {      usage();      System.exit(1);    }    PhoenixSource phoenix;  //??????    if (source == null) {      phoenix = BuildSource.makePhoenix(PrintStreamMessenger.err);    }    else {      phoenix = BuildSource.makePhoenix(source, PrintStreamMessenger.err);//连接串口    }    MoteIF mif = new MoteIF(phoenix);//设置节点    TestSerial serial = new TestSerial(mif);    serial.sendPackets();  }}

Bug3:DIP bug

涉及的背景知识:TinyOS中的网络协议。
背景知识介绍
TinyOS中两种基本的多跳路由协议:分发协议和汇聚协议。

  1. 分发(Dissemination)协议实现的功能:将小数据项可靠地传送到网络中每一个节点。
  2. 分发协议中有一个共享变量,当共享变量发生改变时会通知应用程序,从而实现整个网络最终的一致性(即实现共享变量的网络一致性),网络中每一个共享变量都有一个该数据的副本。

相关的接口和组件

  1. 分发协议涉及的接口:
//读取网络中的共享数据并且更新interface DisseminationValue<typedef t>{    command const t *get();//获取分发变量的指针;    command void set(const t *);//为该变量设置值(例如初始值)    event void changed();//当分发(共享)的变量值发生改变时,触发该事件   }//产生(或者说是更新)需要分发的共享数据,interface DisseminationUpdate<typedef t>{command void change(t *newVal);//更新要发粪的值}
0 0