001/**
002 * Copyright 2017, Digi International Inc.
003 *
004 * This Source Code Form is subject to the terms of the Mozilla Public
005 * License, v. 2.0. If a copy of the MPL was not distributed with this
006 * file, you can obtain one at http://mozilla.org/MPL/2.0/.
007 *
008 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 
009 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 
010 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 
011 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
012 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
013 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
014 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
015 */
016package com.digi.xbee.api.packet;
017
018import java.io.ByteArrayOutputStream;
019import java.io.IOException;
020import java.util.Arrays;
021import java.util.LinkedHashMap;
022
023import org.slf4j.Logger;
024import org.slf4j.LoggerFactory;
025
026import com.digi.xbee.api.utils.HexUtils;
027
028/**
029 * This class represents a basic and unknown XBee packet where the payload is
030 * set as a byte array without a defined structure.
031 * 
032 * @see XBeeAPIPacket
033 */
034public class UnknownXBeePacket extends XBeeAPIPacket {
035        
036        // Constants.
037        private static final int MIN_API_PAYLOAD_LENGTH = 1; // 1 (Frame type)
038        
039        // Variables
040        protected byte[] rfData;
041        
042        private Logger logger;
043        
044        /**
045         * Creates a new {@code UnknownXBeePacket} from the given payload.
046         * 
047         * @param payload The API frame payload. The first byte will be the frame 
048         *                type.
049         *                The byte array must be in {@code OperatingMode.API} mode.
050         * 
051         * @return Parsed Unknown packet.
052         * 
053         * @throws IllegalArgumentException if {@code payload.length < }{@value #MIN_API_PAYLOAD_LENGTH}.
054         * @throws NullPointerException if {@code payload == null}.
055         */
056        public static UnknownXBeePacket createPacket(byte[] payload) {
057                if (payload == null)
058                        throw new NullPointerException("Unknown packet payload cannot be null.");
059                
060                // 1 (Frame type)
061                if (payload.length < MIN_API_PAYLOAD_LENGTH)
062                        throw new IllegalArgumentException("Incomplete Unknown packet.");
063                
064                // payload[0] is the frame type.
065                int apiID = payload[0] & 0xFF;
066                int index = 1;
067                
068                byte[] commandData = null;
069                if (index < payload.length)
070                        commandData = Arrays.copyOfRange(payload, index, payload.length);
071                
072                return new UnknownXBeePacket(apiID, commandData);
073        }
074        
075        /**
076         * Class constructor. Instantiates an XBee packet with the given packet 
077         * data.
078         * 
079         * @param apiIDValue The XBee API integer value of the packet.
080         * @param rfData The XBee RF Data.
081         * 
082         * @throws IllegalArgumentException if {@code apiIDValue < 0} or
083         *                                  if {@code apiIDValue > 255}.
084         */
085        public UnknownXBeePacket(int apiIDValue, byte[] rfData) {
086                super(apiIDValue);
087                this.rfData = rfData;
088                this.logger = LoggerFactory.getLogger(UnknownXBeePacket.class);
089        }
090        
091        /*
092         * (non-Javadoc)
093         * @see com.digi.xbee.api.packet.XBeeAPIPacket#getAPIPacketSpecificData()
094         */
095        @Override
096        protected byte[] getAPIPacketSpecificData() {
097                ByteArrayOutputStream data = new ByteArrayOutputStream();
098                try {
099                        if (rfData != null)
100                                data.write(rfData);
101                } catch (IOException e) {
102                        logger.error(e.getMessage(), e);
103                }
104                return data.toByteArray();
105        }
106        
107        /*
108         * (non-Javadoc)
109         * @see com.digi.xbee.api.packet.XBeeAPIPacket#needsAPIFrameID()
110         */
111        @Override
112        public boolean needsAPIFrameID() {
113                return false;
114        }
115        
116        /**
117         * Sets the XBee RF Data.
118         * 
119         * @param rfData The new XBee RF Data.
120         */
121        public void setRFData(byte[] rfData) {
122                if (rfData == null)
123                        this.rfData = null;
124                else
125                        this.rfData = Arrays.copyOf(rfData, rfData.length);
126        }
127        
128        /**
129         * Returns the XBee RF Data of the packet.
130         * 
131         * @return The RF Data.
132         */
133        public byte[] getRFData() {
134                if (rfData == null)
135                        return null;
136                return Arrays.copyOf(rfData, rfData.length);
137        }
138        
139        /*
140         * (non-Javadoc)
141         * @see com.digi.xbee.api.packet.XBeeAPIPacket#isBroadcast()
142         */
143        @Override
144        public boolean isBroadcast() {
145                return false;
146        }
147        
148        /*
149         * (non-Javadoc)
150         * @see com.digi.xbee.api.packet.XBeeAPIPacket#getAPIPacketParameters()
151         */
152        @Override
153        protected LinkedHashMap<String, String> getAPIPacketParameters() {
154                LinkedHashMap<String, String> parameters = new LinkedHashMap<String, String>();
155                if (rfData != null)
156                        parameters.put("RF Data", HexUtils.prettyHexString(HexUtils.byteArrayToHexString(rfData)));
157                return parameters;
158        }
159}