从Java创建设备驱动程序数据包

huangapple go评论75阅读模式
英文:

Creating device driver packets from Java

问题

现在我有一些空闲时间,决定创建一个Java程序,将我的XBee(即zigbee)芯片连接到我的新SmartThings智能中心。我在这方面找到了一个很好的教程,通过手动创建数据包来实现(https://nzfalco.jimdofree.com/electronic-projects/xbee-to-smartthings/)。我的下一个任务是创建一组Java例程,用于创建、发送、接收和访问所需的数据包(即一系列字节)。

在为其他项目使用C语言做过类似的事情之后,我最初的想法是简单地创建一个包含数据包结构的类并发送它。类似于这样:

class DeviceAnnounce {
    public byte frameId;
    public byte addr64[];
    public byte addr16[];
    public byte capability;
};

问题在于似乎没有办法将这个“结构”转换为要发送到设备的字节数组。

接下来我想,Java运行时内置了序列化功能。所以我在类中添加了Serializable接口,并使用writeObject()方法将实例转换为字节流。问题在于writeObject()不仅转换了您的字节,还包括了对象的定义在编码中。这对于将对象读写到磁盘非常有用,但它没有创建我需要发送到xbee设备的数据包。

最后,我以比较复杂的方式编写了代码,明确地为我的类添加了一个创建字节数组的方法。

class DeviceAnnounce {
    public DeviceAnnounce(byte frameId, byte[] addr64, byte[] addr16, byte capability) {
        super();
        this.frameId = frameId;
        this.addr64 = addr64;
        this.addr16 = addr16;
        this.capability = capability;
    }

    public byte frameId;
    public byte addr64[];
    public byte addr16[];
    public byte capability;

    byte[] getBytes() throws IOException {
        byte[] data = new byte[12];
        data[0] = frameId;
        data[1] = addr64[7];
        data[2] = addr64[6];
        data[3] = addr64[5];
        data[4] = addr64[4];
        data[5] = addr64[3];
        data[6] = addr64[2];
        data[7] = addr64[1];
        data[8] = addr64[0];
        data[9] = addr16[1];
        data[10] = addr16[0];
        data[11] = capability;
        return data;
    }

    @Override
    public String toString() {
        return "DeviceAnnounce [frameId=" + frameId + ", addr64=" + HexUtils.prettyHexString(addr64) + ", addr16="
                + HexUtils.prettyHexString(addr16) + ", capability=" + capability + "]";
    }
}

这样做是可行的,但我一直在想肯定有更好的方法。现在是一个关键问题,有没有办法将一个POJO对象转换为简单的字节流或字节数组?

英文:

Now that I have some spare time on my hands, I decided to create a Java program to connect my XBee (i.e. zigbee) chips to my new SmartThings hub. I found a nice tutorial on doing this by creating the packets by hand (https://nzfalco.jimdofree.com/electronic-projects/xbee-to-smartthings/). My next task is to create a set of Java routines to create, send, receive, and access the required packets (i.e. a sequence of bytes).

Having done similar in C for other projects, my first thought was to simple create a class with the packet structure and send it. Something like this:

class DeviceAnnounce {
public byte frameId;
public byte addr64[];
public byte addr16[];
public byte capability;
};

Problem is there does not appear to be a way to cast this "structure" to an array of bytes to send to the device.

Next I thought, we have a serialize capability built into the Java runtime. So I added Serializable to the class and used the writeObject() method to convert the instance into a byte stream. Problem here is that writeObject() converts not only your bytes, but includes the definition of the object in the encoding. Works great for reading and writing object to disk, but it's not creating the packet I need to send to the xbee device.

I finally coded it the hard way, explicitly adding a method to my class that creates the byte array.

class DeviceAnnounce {
public DeviceAnnounce(byte frameId, byte[] addr64, byte[] addr16, byte capability) {
super();
this.frameId = frameId;
this.addr64 = addr64;
this.addr16 = addr16;
this.capability = capability;
}
public byte frameId;
public byte addr64[];
public byte addr16[];
public byte capability;
byte[] getBytes() throws IOException {
byte[] data=new byte[12];
data[0]=frameId;
data[1]=addr64[7];
data[2]=addr64[6];
data[3]=addr64[5];
data[4]=addr64[4];
data[5]=addr64[3];
data[6]=addr64[2];
data[7]=addr64[1];
data[8]=addr64[0];
data[9]=addr16[1];
data[10]=addr16[0];
data[11]=capability;
return data;
}
@Override
public String toString() {
return "DeviceAnnounce [frameId=" + frameId + ", addr64=" + HexUtils.prettyHexString(addr64) + ", addr16="
+ HexUtils.prettyHexString(addr16) + ", capability=" + capability + "]";
}

}

It works, but I keep thinking there must be a better way. Now the 64 dollar (or maybe bit) question. Is there a way to convert a POJO into a simple byte stream/array?

答案1

得分: 1

为了构建用于传输的字节块,我建议使用内置的 ByteBuffer,该类提供了对大端或小端的 16 位、32 位和64位整数等帮助函数。

您应该在使用这些值时将它们存储起来,例如:

public byte frameId;
public long addr64;
public short addr16;
public byte capability;

byte[] getBytes() throws IOException {
    ByteBuffer buf = ByteBuffer.allocate(12)
            .order(ByteOrder.BIG_ENDIAN/*网络字节序*/);
    buf.put(frameId);
    buf.putLong(addr64);
    buf.putShort(addr16);
    buf.put(capability);
    return buf.array(); // 或者返回 ByteBuffer 本身
}
英文:

To build a block of bytes for transmitting, I recommend using the built-in ByteBuffer, which e.g. has helpers for 16-, 32-, and 64-bit integers in big- or little-endian.

You should then store the values as you use them, e.g.

public byte frameId;
public long addr64;
public short addr16;
public byte capability;
byte[] getBytes() throws IOException {
ByteBuffer buf = ByteBuffer.allocate(12)
.order(ByteOrder.BIG_ENDIAN/*Network Byte Order*/);
buf.put(frameId);
buf.putLong(addr64);
buf.putShort(addr16);
buf.put(capability);
return buf.array(); // or return the ByteBuffer itself
}

huangapple
  • 本文由 发表于 2020年4月9日 23:40:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/61124886.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定