001package jmri.jmrix.ieee802154.xbee;
002
003import com.digi.xbee.api.models.XBee16BitAddress;
004import com.digi.xbee.api.models.XBee64BitAddress;
005import com.digi.xbee.api.models.XBeeTransmitOptions;
006import com.digi.xbee.api.packet.XBeeAPIPacket;
007import com.digi.xbee.api.packet.common.ATCommandPacket;
008import com.digi.xbee.api.packet.common.RemoteATCommandPacket;
009import com.digi.xbee.api.packet.common.TransmitPacket;
010import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
011
012import java.util.Arrays;
013
014/**
015 * This is a wrapper class for a Digi XBeeAPIPacket.
016 *
017 * @author Paul Bender Copyright (C) 2013
018 */
019public class XBeeMessage extends jmri.jmrix.ieee802154.IEEE802154Message {
020
021    private XBeeAPIPacket xbm = null;
022
023    /**
024     * Suppress the default ctor, as the length must always be specified
025     */
026    protected XBeeMessage() {
027    }
028
029    public XBeeMessage(int l) {
030        super(l);
031    }
032
033    /**
034     * This ctor interprets the String as the exact sequence to send,
035     * byte-for-byte.
036     * @param m message
037     * @param l length
038     *
039     */
040    public XBeeMessage(String m, int l) {
041        super(m, l);
042    }
043
044    /**
045     * This ctor interprets the byte array as a sequence of characters to send.
046     *
047     * @param a Array of bytes to send
048     * @param l length
049     */
050    public XBeeMessage(byte[] a, int l) {
051        super(Arrays.toString(a), l);
052    }
053
054    /**
055     * This ctor interprets the parameter as an XBeeAPIPacket message. This is the
056     * message form that will generally be used by the implementation.
057     *
058     * @param request an XBeeAPIPacket of bytes to send
059     */
060    public XBeeMessage(XBeeAPIPacket request) {
061        _nDataChars = request.getPacketData().length;
062        byte[] data = request.getPacketData();
063        _dataChars = new int[_nDataChars];
064        for(int i=0;i<_nDataChars;i++) {
065           _dataChars[i] = data[i];
066        }
067        xbm = request;
068    }
069
070    @Override
071    public boolean replyExpected() {
072        return false;
073    }
074
075    public XBeeAPIPacket getXBeeRequest() {
076        return xbm;
077    }
078
079    public void setXBeeRequest(XBeeAPIPacket request) {
080        xbm = request;
081    }
082
083    @Override
084    public String toMonitorString() {
085        if (xbm != null) {
086            return xbm.toPrettyString();
087        } else {
088            return toString();
089        }
090    }
091
092    @Override
093    public String toString() {
094        String s = "";
095        if (xbm != null) {
096            byte[] packet = xbm.getPacketData();
097            for (byte b : packet) {
098                s = jmri.util.StringUtil.appendTwoHexFromInt(b, s);
099            }
100        }
101        return s;
102    }
103
104    /**
105     * check whether the message has a valid parity
106     */
107    @Override
108    public boolean checkParity() {
109        int len = getNumDataElements();
110        int chksum = 0x00;  /* the seed */
111
112        int loop;
113
114        for (loop = 0; loop < len - 1; loop++) {  // calculate contents for data part
115            chksum ^= getElement(loop);
116        }
117        return ((chksum & 0xFF) == getElement(len - 1));
118    }
119
120    @Override
121    public void setParity() {
122        int len = getNumDataElements();
123        int chksum = 0x00;  /* the seed */
124
125        int loop;
126
127        for (loop = 0; loop < len - 1; loop++) {  // calculate contents for data part
128            chksum ^= getElement(loop);
129        }
130        setElement(len - 1, chksum & 0xFF);
131    }
132
133    // a few canned messages
134    public static XBeeMessage getHardwareVersionRequest() {
135        return new XBeeMessage(new ATCommandPacket(0, "HV", ""));
136    }
137
138    public static XBeeMessage getFirmwareVersionRequest() {
139        return new XBeeMessage(new ATCommandPacket(0, "VR", ""));
140    }
141
142    /**
143     * Get an XBee Message requesting a digital output pin be turned on or off.
144     * @param address XBee Address of the node.  This can be either 
145     16 bit or 64 bit.
146     * @param pin the DIO Pin on the XBee to use.
147     * @param on boolean value stating whether the pin should be turned
148     *        on (true) or off (false)
149     * @return XBeeMessage with a message requesting a digital IO pin be turned on or off.
150     */
151    @SuppressFBWarnings( value = {"BC_UNCONFIRMED_CAST"}, justification="The passed address must be either a 16 bit address or a 64 bit address, and we check to see if the address is a 16 bit address, so it is redundant to also check for a 64 bit address")
152    public static XBeeMessage getRemoteDoutMessage(Object address, int pin, boolean on) {
153        byte[] onValue = {0x5};
154        byte[] offValue = {0x4};
155        if (address instanceof XBee16BitAddress) {
156            return new XBeeMessage(new RemoteATCommandPacket(XBeeAPIPacket.NO_FRAME_ID,XBee64BitAddress.COORDINATOR_ADDRESS,(XBee16BitAddress) address, XBeeTransmitOptions.NONE,"D" + pin, on ? onValue : offValue));
157        } else {
158            return new XBeeMessage(new RemoteATCommandPacket(XBeeAPIPacket.NO_FRAME_ID,(XBee64BitAddress) address,XBee16BitAddress.UNKNOWN_ADDRESS,XBeeTransmitOptions.NONE, "D" + pin, on ? onValue : offValue));
159        }
160    }
161
162    /**
163     * Get an XBee Message requesting the status of a digital IO pin.
164     * @param address XBee Address of the node.  This can be either 
165     16 bit or 64 bit.
166     * @param pin the DIO Pin on the XBee to use.
167     * @return XBeeMessage with a digital IO pin status request.
168     */
169    @SuppressFBWarnings( value = {"BC_UNCONFIRMED_CAST"}, justification="The passed address must be either a 16 bit address or a 64 bit address, and we check to see if the address is a 16 bit address, so it is redundant to also check for a 64 bit address")
170    public static XBeeMessage getRemoteDoutMessage(Object address, int pin) {
171        if (address instanceof com.digi.xbee.api.models.XBee16BitAddress) {
172            return new XBeeMessage(new RemoteATCommandPacket(XBeeAPIPacket.NO_FRAME_ID,XBee64BitAddress.COORDINATOR_ADDRESS,(XBee16BitAddress) address,XBeeTransmitOptions.NONE,"D" + pin, ""));
173        } else {
174            return new XBeeMessage(new RemoteATCommandPacket(XBeeAPIPacket.NO_FRAME_ID,(XBee64BitAddress) address,XBee16BitAddress.UNKNOWN_ADDRESS,XBeeTransmitOptions.NONE,"D" + pin, ""));
175        }
176    }
177
178    /**
179     * Get an XBee Message requesting an IO sample from the node.
180     * @param address XBee Address of the node.  This can be either 
181     * @return XBeeMessage with a force IO sample request.
182     16 bit or 64 bit.
183     */
184    @SuppressFBWarnings( value = {"BC_UNCONFIRMED_CAST"}, justification="The passed address must be either a 16 bit address or a 64 bit address, and we check to see if the address is a 16 bit address, so it is redundant to also check for a 64 bit address")
185    public static XBeeMessage getForceSampleMessage(Object address) {
186        if (address instanceof com.digi.xbee.api.models.XBee16BitAddress) {
187            return new XBeeMessage(new RemoteATCommandPacket(XBeeAPIPacket.NO_FRAME_ID, XBee64BitAddress.COORDINATOR_ADDRESS, (XBee16BitAddress) address, XBeeTransmitOptions.NONE, "IS", ""));
188        } else {
189            return new XBeeMessage(new RemoteATCommandPacket(XBeeAPIPacket.NO_FRAME_ID, (XBee64BitAddress) address, XBee16BitAddress.UNKNOWN_ADDRESS, XBeeTransmitOptions.NONE, "IS", ""));
190        }
191    }
192
193    /**
194     * Get an XBee Message requesting data be sent to the serial port
195     * on a remote node.
196     * @param address XBee Address of the node.  This can be either 
197     16 bit or 64 bit.
198     * @param payload An byte array containing the bytes to be transfered, as the low order word of the integer.
199     * @return XBeeMessage with remote transmission request for the provided address containing the provided payload.
200     */
201    @SuppressFBWarnings( value = {"BC_UNCONFIRMED_CAST"}, justification="The passed address must be either a 16 bit address or a 64 bit address, and we check to see if the address is a 16 bit address, so it is redundant to also check for a 64 bit address")
202    public static XBeeMessage getRemoteTransmissionRequest(Object address, byte[] payload) {
203        if (address instanceof com.digi.xbee.api.models.XBee16BitAddress) {
204            return getRemoteTransmissionRequest((com.digi.xbee.api.models.XBee16BitAddress) address, payload);
205        } else {
206            return getRemoteTransmissionRequest((com.digi.xbee.api.models.XBee64BitAddress) address, payload);
207        }
208    }
209
210    /**
211     * Get an XBee Message requesting data be sent to the serial port
212     * on a remote node.
213     * @param address XBee16BitAddress of the node.
214     * @param payload A byte array containing the bytes to be transfered, as the low order word of the integer.
215     * @return XBeeMessage with remote transmission request for the provided address containing the provided payload.
216     */
217    public static XBeeMessage getRemoteTransmissionRequest(XBee16BitAddress address, byte[] payload) {
218        return new XBeeMessage(new TransmitPacket(XBeeAPIPacket.NO_FRAME_ID,XBee64BitAddress.COORDINATOR_ADDRESS,address,255,XBeeTransmitOptions.NONE,payload));
219    }
220 
221    /**
222     * Get an XBee Message requesting data be sent to the serial port
223     * on a remote node.
224     * @param address XBee64BitAddress of the node.
225     * @param payload A byte array containing the bytes to be transfered, as the low order word of the integer.
226     * @return XBeeMessage with remote transmission request for the provided address containing the provided payload.
227     */
228    public static XBeeMessage getRemoteTransmissionRequest(XBee64BitAddress address, byte[] payload) {
229        return new XBeeMessage(new TransmitPacket(XBeeAPIPacket.NO_FRAME_ID,address,XBee16BitAddress.UNKNOWN_ADDRESS,255,0,payload));
230    }
231
232}
233