Cooja 中自定义 Java Mote 使用 Collect-View

来源:互联网 发布:网络视频广告收入 编辑:程序博客网 时间:2024/05/22 04:24

Cooja 中自定义 Java Mote 使用 Collect-View

受到网上一文的启发。可知 Collect-View中tools/collect-view/src/contiki/collect/ 下的三个类SensorInfo.java、SensorData.java、CollectServer.java 极为重要。经过分析我们知道节点的数据是保存在一个整型数组(如 int[] Value = new int[30] 必须是30,分析SensorData.java 可知)中, SensorInfo 是一个接口,它规定了一个整型数组中每个索引位置的意义,如 Value[0]=30 (必须是30), Value[4] 是一个节点ID的数值Value[1~2]是该组数据更新的时间戳等。
实现原理:节点将 Value[30] 以字符串形式写到一个文件上(但这个字符串前部还需要加上一个系统时间的字符串,分析SensorData.java可知,格式如下图1)。我们可以操作打开文件,读取这一行字符串,用 CollectServer 下的 handleIncomingData(long systemTime, String line) 进行解析,该方法的作用是根据字符串生成 SensorData 对象,并显示数据。
图1:
这里写图片描述

根据我的实验举例:
首先,我要说清楚的是我定义了 AbstractMote 抽象类,并定义了 Mote 和 Sink 类继承于 AbstractMote,分别代表仿真实验中的普通节点和 Sink 节点。使用 Collect-View 插件收集数据的思想是,实验中所有节点将自身的数据按要求写到一个文件中,再用 Collect-View 对象来进行读取并显示。
我在 AbstractMote 类中添加了以下代码(可见,我将数据写在了 SensorDataFile.txt 文件)

public int[] value = new int[30]; //用于保存节点的信息数据    /**     * 更新传感器数据数组     * @param index     * @param value     */    public void updateSensorData() {        //SensorData中 this.nodeTime = ((values[TIMESTAMP1] << 16) + values[TIMESTAMP2]) * 1000L;        this.value[SensorInfo.DATA_LEN] = SensorInfo.VALUES_COUNT; //格式要求        this.value[SensorInfo.NODE_ID] = this.addr.intValue();        this.value[SensorInfo.NUM_NEIGHBORS] = this.neighbors_number;        this.value[SensorInfo.BEACON_INTERVAL] = this.cnt_beacon_max;        this.value[SensorInfo.BATTERY_INDICATOR] = (int) this.battery.getBatteryLevel();        this.value[SensorInfo.TIMESTAMP1] = ((int)(System.currentTimeMillis()/1000L)>>16);//vaule中是以秒为单位        this.value[SensorInfo.TIMESTAMP2] = ((int)(System.currentTimeMillis()/1000L));    }    /**     * 传感器数据数组转换为String (前面多加一个系统时间)     * @return     */    public String sensorDataToString() {        StringBuilder sb = new StringBuilder();        sb.append(System.currentTimeMillis()).append(' ');        for(int i=0; i< value.length; i++) {            sb.append(Integer.toString(value[i])).append(' ');        }        return sb.toString().trim();    }    /**     * 将String写入文件     * @param line     */    public void writeSensorData(String line) {        File file = new File("SensorDataFile.txt");        BufferedWriter out = null;        try {            out = new BufferedWriter(new FileWriter(file, true));            out.write(line);            out.newLine();            out.close();        } catch (IOException e) {            e.printStackTrace();        }    }    /**     * 周期性调度     */    public void updateSensorDataTask() {        this.updateSensorData();        String line = this.sensorDataToString();        this.writeSensorData(line);    }

节点周期性调度 updateSensorDataTask() 进行一次数据的更新显示,调度的时间根据自身要求设置,它是节点更新数据到 Collect-View 的时间。具体过程首先 updateSensorData() 对 value[] 数组中的数组进行更新,sensorDataToString() 将数组转化为加上一个系统时间的字符串,最后 writeSensorData() 将其写到文件上。
数据写到了文件上,那么接下来就是读取数据了。接下来是读取过程:(不断的读,开线程),我在这里自定义一个类 CollectInfo 来完成此工作。由于读取到的字符串需要 CollectServer 对象来进行解析,所以定义了一个有参的构造函数。代码中有一个睡眠操作,这个可以根据需要设置睡眠的时间,它决定了 Collect-View 的刷新周期。 CollectInfo 类如下:

public class CollectInfo implements Runnable {    private CollectServer collectServer;    public CollectInfo(CollectServer collectServer) {        this.collectServer = collectServer;    }    @Override    public void run() {        while (true) {            File file = new File("SensorDataFile.txt");            if (file.exists() && file.canRead()) {                String line;                BufferedReader in = null;                try {                    in = new BufferedReader(new FileReader(file));                    try {                        while ((line = in.readLine()) != null) {                            this.collectServer.handleIncomingData(System.currentTimeMillis(), line);                        }                        in.close();                        file.delete();                    } catch (IOException e) {                        e.printStackTrace();                    }                } catch (FileNotFoundException e) {                    e.printStackTrace();                }            }            try {                Thread.currentThread().sleep(10000);            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }    }}

在我的实验中,我是用 Sink 节点来开启收集数据的图形化界面的,于是我在 Sink 节点的初始化函数中,添加了下列代码

        this.collectServer = new CollectServer();        this.collectServer.start();//启动收集数据的界面        this.collectInfo = new CollectInfo(this.collectServer);        new Thread(this.collectInfo).start();//开始收集数据

但这里有一点要注意!! CollectServer 中只有一个 start(SerialConnecction connection) 的启动函数,形参是 Collect-View 中实现的接口类,因为我这里没有用到,所以我在 CollectServer 中重载了一个无参 start() 启动函数,只添加启动的语句。代码如下:

/**   * 无参重载函数   * 用于启动收集数据的图形化界面   */  public void start() {    if (hasStarted) {        throw new IllegalStateException("already started");    }    hasStarted = true;    SwingUtilities.invokeLater(new Runnable() {        public void run() {            window.setVisible(true);        }    });  }

实验结果:由上述代码中 updateSensorData() 可知我关注的节点信息,其中有两个是节点邻居数和电量信息。进行实验结果如下:
这里写图片描述
这里写图片描述

本人学生,能力有限,花了三天做了这个小实验,匆忙写下这博客做为备忘的同时也与大家分享。有分析不到之处望大家谅解与指正,谢谢!

0 0