/*
* Copyright (c) 2011 Matthew Doll <mdoll at homenet.me>.
*
* This file is part of HomeNet.
*
* HomeNet is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HomeNet is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HomeNet. If not, see <http://www.gnu.org/licenses/>.
*/
package homenet;
import java.util.*;
/**
*
* @author mdoll
*/
public class Packet implements Cloneable {
final static int PACKET_LENGTH = 0;
final static int PACKET_SETTINGS = 1;
final static int PACKET_FROM = 2;
final static int PACKET_TO = 4;
final static int PACKET_TTL = 4;
final static int PACKET_ID = 6;
final static int PACKET_COMMAND = 7;
final static int PACKET_PAYLOAD = 8;
final static int CMD_BATTERYLEVEL = 0x03;
final static int CMD_MEMORYFREE = 0x04;
final static int CMD_PING = 0x33;
final static int CMD_PONG = 0x3E;
final static int CMD_ACK = 0x11;
final static int CMD_GETNODEID = 0x21;
final static int CMD_SETNODEID = 0x22;
final static int CMD_GETDEVICE = 0x23;
final static int CMD_SETDEVICE = 0x24;
final static int CMD_AUTOSENDSTART = 0xB1;
final static int CMD_AUTOSENDSTOP = 0xB2;
final static int CMD_ON = 0xC0;
final static int CMD_OFF = 0xC1;
final static int CMD_LEVEL = 0xC2;
final static int CMD_CLEAR = 0xC3;
final static int CMD_GETVALUE = 0xD0;
final static int CMD_GETBYTE = 0xD1;
final static int CMD_GETSTRING = 0xD2;
final static int CMD_GETINT = 0xD3;
final static int CMD_GETFLOAT = 0xD4;
final static int CMD_GETLONG = 0xD5;
final static int CMD_GETBINARY = 0xD6;
final static int CMD_SETVALUE = 0xE0;
final static int CMD_SETBYTE = 0xE1;
final static int CMD_SETSTRING = 0xE2;
final static int CMD_SETINT = 0xE3;
final static int CMD_SETFLOAT = 0xE4;
final static int CMD_SETLONG = 0xE5;
final static int CMD_SETBINARY = 0xE6;
final static int CMD_REPLYVALUE = 0xF0;
final static int CMD_REPLYBYTE = 0xF1;
final static int CMD_REPLYSTRING = 0xF2;
final static int CMD_REPLYINT = 0xF3;
final static int CMD_REPLYFLOAT = 0xF4;
final static int CMD_REPLYLONG = 0xF5;
final static int CMD_REPLYBINARY = 0xF6;
final static int CMD_MULTIPACKET = 0xA0;
//an enum might be better here
final static int STATUS_CLEAR = 0;
final static int STATUS_RECEIVING = 1;
final static int STATUS_RECEIVED = 2;
final static int STATUS_WAITING = 3;
final static int STATUS_READY = 4;
final static int STATUS_SENDING = 5;
final static int STATUS_SENT = 6;
final static int STATUS_ACK = 7;
final static int STATUS_SUCCESS = 8;
final static int STATUS_FAILED = 9;
final static int OFFSET_PACKET = 10;
final static int OFFSET_HEADER = 8;
final static int OFFSET_FOOTER = 2;
final static int PACKET_TCP = 1;
final static int PACKET_UDP = 2;
final static int PACKET_BROADCAST = 3;
final static int PACKET_BUFFER = 10;
final static int PACKET_TIMEOUT = 100;
final static int PACKET_RETRY = 1;
final static int DEVICE_UPDATE = 1000;
//schedule timer (millis) = DEVICE_SCHEDULE * DEVICE_UPDATE;
final static int DEVICE_SCHEDULE = 1;
final static int NODE_BOOT_TIME = 3000;
//These Should not be public but I need to rewrite some of the stack
public String toPort = null;
public String fromPort = "self";
public int status;
public byte[] data = new byte[66];
public Date received;
public Packet() {
received = new Date();
}
public Packet(byte[] packet) {
received = new Date();
data = packet;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String getToPort() {
return toPort;
}
public String getFromPort() {
return fromPort;
}
public int getStatus() {
return status;
}
public int getLength() {
return data[PACKET_LENGTH] & 0xFF;
}
public int getSettings() {
return data[PACKET_SETTINGS] & 0x0F;
}
public int getType() {
return data[PACKET_SETTINGS] & 0x0F;
}
public int getFromNode() {
return (((int) (data[PACKET_FROM]) &0xff ) << 4) | (int) ((data[PACKET_FROM + 1] & 0xff) >> 4);
}
public int getFromDevice() {
return data[PACKET_FROM + 1] & 0x0F;
}
public int getToNode() {
return (((int) (data[PACKET_TO] & 0xff) << 4)) | ((data[PACKET_TO + 1] & 0xff) >> 4);
}
public int getToDevice() {
return data[PACKET_TO + 1] & 0x0F;
}
public int getId() {
return data[PACKET_ID] & 0xff;
}
public int getCommand() {
return data[PACKET_COMMAND] & 0xff;
}
public Payload getPayload() {
Payload payload = new Payload();
for (int i = 0; i < getPayloadLength(); i++) {
payload.data[i] = data[i + OFFSET_HEADER];
}
return payload;
}
public int getPayloadAt(int place) {
if ((getLength() - OFFSET_FOOTER) > (OFFSET_HEADER + place)) {
return data[OFFSET_HEADER + place] & 0xFF;
}
return -1;
}
public int getPayloadLength() {
return (data[PACKET_LENGTH] - OFFSET_PACKET) & 0xFF;
}
public int getChecksum() {
return (((int) (data[getLength() - OFFSET_FOOTER] & 0xff )) << 8) | (data[getLength() - 1] & 0xff);
}
public Date getTimestamp() {
return received;
}
public byte[] getData() {
byte[] packet = new byte[getLength()];
packet = Arrays.copyOfRange(data, 0, getLength());
return packet;
}
public void setToPort(String value) {
toPort = value;
}
public void setFromPort(String value) {
fromPort = value;
}
public void setStatus(int value) {
status = value;
}
public void setLength(int value) {
data[PACKET_LENGTH] = (byte) (value & 0xFF);
}
public void setSettings(int value) {
data[PACKET_SETTINGS] |= (byte) (value & 0x0F);
}
public void setType(int value) {
data[PACKET_SETTINGS] |= (byte) (value & 0x0F);
}
public void setFromNode(int value) {
data[PACKET_FROM] = (byte) ((value >> 4) & 0xFF);
data[PACKET_FROM + 1] &= 0x0F; //clear bottom 4 bits
data[PACKET_FROM + 1] |= (byte) ((value << 4) & 0xF0);
}
public void setToNode(int value) {
data[PACKET_TO] = (byte) ((value >> 4) & 0xFF);
data[PACKET_TO + 1] &= 0x0F; //clear bottom 4 bits
data[PACKET_TO + 1] |= (byte) ((value << 4) & 0xF0);
}
public void setFromDevice(int value) {
data[PACKET_FROM + 1] &= (byte) (0xF0); //clear top 4 bits
data[PACKET_FROM + 1] |= (byte) (value & 0x0F);
}
public void setToDevice(int value) {
data[PACKET_TO + 1] &= (byte) (0xF0); //clear top 4 bits
data[PACKET_TO + 1] |= (byte) (value & 0x0F);
}
public void setId(int value) {
data[PACKET_ID] = (byte) (value & 0xFF);
}
public void setCommand(int value) {
data[PACKET_COMMAND] = (byte) (value & 0xFF);
}
public void setPayload(final Payload payload) {
setPayloadLength(payload.length);
System.arraycopy(payload.data, 0, data, OFFSET_HEADER, payload.length);
}
public void setPayloadLength(int value) {
data[PACKET_LENGTH] = (byte) (value + OFFSET_PACKET);
}
static int crc16_update(int crc, int a) {
crc ^= a;
for (int i = 0; i < 8; ++i) {
if ((crc & 1) == 1) {
crc = (crc >> 1) ^ 0xA001;
} else {
crc = (crc >> 1);
}
}
return crc & 0xFFFF;
}
}