001/** 002 * Copyright (c) 2014 Digi International Inc., 003 * All rights not expressly granted are reserved. 004 * 005 * This Source Code Form is subject to the terms of the Mozilla Public 006 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 007 * You can obtain one at http://mozilla.org/MPL/2.0/. 008 * 009 * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 010 * ======================================================================= 011 */ 012package com.digi.xbee.api.packet; 013 014import java.io.ByteArrayOutputStream; 015import java.io.IOException; 016import java.util.Arrays; 017import java.util.LinkedHashMap; 018 019import org.slf4j.Logger; 020import org.slf4j.LoggerFactory; 021 022import com.digi.xbee.api.utils.HexUtils; 023 024/** 025 * This class represents a basic and Generic XBee packet where the payload is 026 * set as a byte array without a defined structure. 027 * 028 * @see XBeeAPIPacket 029 */ 030public class GenericXBeePacket extends XBeeAPIPacket { 031 032 // Constants. 033 private static final int MIN_API_PAYLOAD_LENGTH = 1; // 1 (Frame type) 034 035 // Variables. 036 private byte[] rfData; 037 038 private Logger logger; 039 040 /** 041 * Creates a new {@code GenericXBeePacket} from the given payload. 042 * 043 * @param payload The API frame payload. It must start with the frame type 044 * corresponding to a Generic packet ({@code 0xFF}). 045 * The byte array must be in {@code OperatingMode.API} mode. 046 * 047 * @return Parsed Generic packet. 048 * 049 * @throws IllegalArgumentException if {@code payload[0] != APIFrameType.GENERIC.getValue()} or 050 * if {@code payload.length < }{@value #MIN_API_PAYLOAD_LENGTH}. 051 * @throws NullPointerException if {@code payload == null}. 052 */ 053 public static GenericXBeePacket createPacket(byte[] payload) { 054 if (payload == null) 055 throw new NullPointerException("Generic packet payload cannot be null."); 056 057 // 1 (Frame type) 058 if (payload.length < MIN_API_PAYLOAD_LENGTH) 059 throw new IllegalArgumentException("Incomplete Generic packet."); 060 061 if ((payload[0] & 0xFF) != APIFrameType.GENERIC.getValue()) 062 throw new IllegalArgumentException("Payload is not a Generic packet."); 063 064 // payload[0] is the frame type. 065 int index = 1; 066 067 byte[] commandData = null; 068 if (index < payload.length) 069 commandData = Arrays.copyOfRange(payload, index, payload.length); 070 071 return new GenericXBeePacket(commandData); 072 } 073 074 /** 075 * Class constructor. Instantiates an XBee packet with the given packet 076 * data. 077 * 078 * @param rfData The XBee RF Data. 079 */ 080 public GenericXBeePacket(byte[] rfData) { 081 super(APIFrameType.GENERIC); 082 this.rfData = rfData; 083 this.logger = LoggerFactory.getLogger(GenericXBeePacket.class); 084 } 085 086 /* 087 * (non-Javadoc) 088 * @see com.digi.xbee.api.packet.XBeeAPIPacket#getAPIPacketSpecificData() 089 */ 090 @Override 091 protected byte[] getAPIPacketSpecificData() { 092 ByteArrayOutputStream data = new ByteArrayOutputStream(); 093 try { 094 if (rfData != null) 095 data.write(rfData); 096 } catch (IOException e) { 097 logger.error(e.getMessage(), e); 098 } 099 return data.toByteArray(); 100 } 101 102 /* 103 * (non-Javadoc) 104 * @see com.digi.xbee.api.packet.XBeeAPIPacket#needsAPIFrameID() 105 */ 106 @Override 107 public boolean needsAPIFrameID() { 108 return false; 109 } 110 111 /** 112 * Sets the XBee RF Data. 113 * 114 * @param rfData The new XBee RF Data. 115 */ 116 public void setRFData(byte[] rfData) { 117 this.rfData = rfData; 118 } 119 120 /** 121 * Returns the XBee RF Data of the packet. 122 * 123 * @return The RF Data. 124 */ 125 public byte[] getRFData() { 126 return rfData; 127 } 128 129 /* 130 * (non-Javadoc) 131 * @see com.digi.xbee.api.packet.XBeeAPIPacket#isBroadcast() 132 */ 133 @Override 134 public boolean isBroadcast() { 135 return false; 136 } 137 138 /* 139 * (non-Javadoc) 140 * @see com.digi.xbee.api.packet.XBeeAPIPacket#getAPIPacketParameters() 141 */ 142 @Override 143 protected LinkedHashMap<String, String> getAPIPacketParameters() { 144 LinkedHashMap<String, String> parameters = new LinkedHashMap<String, String>(); 145 if (rfData != null) 146 parameters.put("RF Data", HexUtils.prettyHexString(HexUtils.byteArrayToHexString(rfData))); 147 return parameters; 148 } 149}