Cleaning up code for runtime, installer, RMI, compiler for the Java side
[iot2.git] / iotjava / iotruntime / zigbee / IoTZigbee.java
1 package iotruntime.zigbee;
2
3 // Java packages
4 import java.io.IOException;
5 import java.net.DatagramPacket;
6 import java.net.DatagramSocket;
7 import java.net.InetAddress;
8 import java.net.SocketException;
9 import java.net.UnknownHostException;
10 import java.util.concurrent.atomic.AtomicBoolean;
11 import java.util.List;
12 import java.util.ArrayList;
13 import java.util.Map;
14 import java.util.HashMap;
15 import java.util.concurrent.ConcurrentHashMap;
16 import java.util.Set;
17 import java.util.HashSet;
18 import java.nio.charset.StandardCharsets;
19 import java.util.concurrent.Semaphore;
20
21 import iotruntime.slave.IoTZigbeeAddress;
22 import iotruntime.slave.IoTDeviceAddress;
23
24 /** Class IoTZigbee
25  *
26  * @author      Ali Younis <ayounis @ uci.edu>, Changwoo Lee, Jiawei Gu
27  * @version     1.0
28  * @since       2016-04-12
29  */
30 public final class IoTZigbee {
31
32         public final int SOCKET_SEND_BUFFER_SIZE = 1024;
33         public final int SOCKET_RECEIVE_BUFFER_SIZE = 1024;
34         public final int SHORT_ADDRESS_UPDATE_TIME_MSEC = 10000;
35         public final int SHORT_ADDRESS_UPDATE_TIME_FAST_MSEC = 500;
36         public final int RESEND_WAIT_TIME = 500;
37
38         /**
39          * IoTZigbee class properties
40          */
41
42         // UDP connection stuff
43         private final String strHostAddress;
44         private final int iSrcPort;
45         private final int iDstPort;
46         private DatagramSocket socket;  // the socket interface that we are guarding
47         private boolean didClose;               // make sure that the clean up was done correctly
48
49         private final IoTZigbeeAddress zigbeeAddress;
50
51         // list that holds the callbacks
52         private List<IoTZigbeeCallback> callbackList = new ArrayList<IoTZigbeeCallback>();
53
54         /**
55          * IoTZigbee class concurrency and concurrency control
56          */
57         private Thread receiveThread = null;
58
59         private AtomicBoolean endTask = new AtomicBoolean(false);
60         private AtomicBoolean didSuccesfullySendAddress = new AtomicBoolean(false);
61
62         /**
63          * Class constructor
64          */
65         public IoTZigbee(IoTDeviceAddress iotDevAdd, IoTZigbeeAddress zigAddress) throws SocketException, IOException, InterruptedException {
66
67                 strHostAddress = iotDevAdd.getHostAddress();
68                 iSrcPort = iotDevAdd.getSourcePortNumber();
69                 iDstPort = iotDevAdd.getDestinationPortNumber();
70                 didClose = false;
71                 zigbeeAddress = zigAddress;
72
73                 socket = new DatagramSocket(iSrcPort);
74                 socket.setSendBufferSize(SOCKET_SEND_BUFFER_SIZE);
75                 socket.setReceiveBufferSize(SOCKET_RECEIVE_BUFFER_SIZE);
76
77                 receiveThread = new Thread(new Runnable() {
78                         public void run() {
79                                 receieveWorker();
80                         }
81                 });
82                 receiveThread.start();
83         }
84
85         public void init() throws IOException {
86                 while (!didSuccesfullySendAddress.get()) {
87
88                         sendDeviceAddress();
89
90                         try {
91                                 Thread.sleep(RESEND_WAIT_TIME);
92                         } catch (Exception e) {
93                                 e.printStackTrace();
94                         }
95                 }
96         }
97
98         // Created by Changwoo
99         public void sendChangeSwtichRequest(int packetId, int clusterId, int profileId, int value, int deviceEndpoint) throws IOException {
100                 String message = "type: zcl_change_switch_request\n";
101                 message += "packet_id: " + String.format("%04x", packetId) + "\n";
102                 message += "value: " + String.format("%01x", value) + "\n";
103                 message += "cluster_id: " + String.format("%04x", clusterId) + "\n";
104                 message += "profile_id: " + String.format("%04x", profileId) + "\n";
105                 message += "device_address_long: " + zigbeeAddress.getAddress() + "\n";
106                 message += "device_endpoint: " + String.format("%02x", deviceEndpoint) + "\n";
107                 DatagramPacket sendPacket = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(strHostAddress), iDstPort);
108                 socket.send(sendPacket);
109         }
110
111         // Created by Jiawei
112         public void sendLockOrUnlockDoorRequest(int packetId, int clusterId, int profileId, int deviceEndpoint, int value) throws IOException {
113                 String message = "type: zcl_lock_or_unlock_door_request\n";
114                 message += "packet_id: " + String.format("%04x", packetId) + "\n";
115                 message += "value: " + String.format("%01x", value) + "\n";
116                 message += "cluster_id: " + String.format("%04x", clusterId) + "\n";
117                 message += "profile_id: " + String.format("%04x", profileId) + "\n";
118                 message += "device_address_long: " + zigbeeAddress.getAddress() + "\n";
119                 message += "device_endpoint: " + String.format("%02x", deviceEndpoint) + "\n";
120                 DatagramPacket sendPacket = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(strHostAddress), iDstPort);
121                 socket.send(sendPacket);
122         }
123
124         // Created by Jiawei
125         public void sendReadDoorStatusRequest(int packetId, int clusterId, int profileId, int deviceEndpoint, int framecontrol, 
126                 int commandframe, int attribute_id) throws IOException {
127                 String message = "type: zcl_read_door_status_request\n";
128                 message += "packet_id: " + String.format("%04x", packetId) + "\n";
129                 message += "framecontrol: " + String.format("%02x", framecontrol) + "\n";
130                 message += "cluster_id: " + String.format("%04x", clusterId) + "\n";
131                 message += "profile_id: " + String.format("%04x", profileId) + "\n";
132                 message += "device_address_long: " + zigbeeAddress.getAddress() + "\n";
133                 message += "device_endpoint: " + String.format("%02x", deviceEndpoint) + "\n";
134                 message += "commandframe: " + String.format("%02x", commandframe) + "\n";
135                 message += "attribute_id: " + String.format("%04x", attribute_id) + "\n";
136                 DatagramPacket sendPacket = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(strHostAddress), iDstPort);
137                 socket.send(sendPacket);
138         }
139
140         // Created by Changwoo
141         public void sendBroadcastingRouteRecordRequest(int packetId) throws IOException {
142                 String message = "type: zdo_broadcast_route_record_request\n";
143                 message += "packet_id: " + String.format("%04x", packetId) + "\n";
144                 message += "device_address_long: " + zigbeeAddress.getAddress() + "\n";
145                 DatagramPacket sendPacket = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(strHostAddress), iDstPort);
146                 socket.send(sendPacket);
147         }
148
149         // Created by Changwoo
150         public void sendEnrollmentResponse(int packetId, int clusterId, int profileId, int deviceEndpoint) throws IOException {
151                 String message = "type: zcl_enrollment_response\n";
152                 message += "packet_id: " + String.format("%04x", packetId) + "\n";
153                 message += "device_address_long: " + zigbeeAddress.getAddress() + "\n";
154                 message += "cluster_id: " + String.format("%04x", clusterId) + "\n";
155                 message += "profile_id: " + String.format("%04x", profileId) + "\n";
156                 message += "device_endpoint: " + String.format("%02x", deviceEndpoint) + "\n";
157                 DatagramPacket sendPacket = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(strHostAddress), iDstPort);
158                 socket.send(sendPacket);
159         }
160
161         // Created by Changwoo
162         public void sendWriteAttributesCommand(int packetId, int clusterId, int profileId, int deviceEndpoint) throws IOException {
163                 String message = "type: zcl_write_attributes\n";
164                 message += "packet_id: " + String.format("%04x", packetId) + "\n";
165                 message += "device_address_long: " + zigbeeAddress.getAddress() + "\n";
166                 message += "cluster_id: " + String.format("%04x", clusterId) + "\n";
167                 message += "profile_id: " + String.format("%04x", profileId) + "\n";
168                 message += "device_endpoint: " + String.format("%02x", deviceEndpoint) + "\n";
169                 DatagramPacket sendPacket = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(strHostAddress), iDstPort);
170                 socket.send(sendPacket);
171         }
172
173         // Created by Changwoo
174         public void sendManagementPermitJoiningRequest(int packetId, int clusterId, int deviceEndpoint) throws IOException {
175                 String message = "type: management_permit_joining_request\n";
176                 message += "packet_id: " + String.format("%04x", packetId) + "\n";
177                 message += "device_address_long: " + zigbeeAddress.getAddress() + "\n";
178                 message += "cluster_id: " + String.format("%04x", clusterId) + "\n";
179                 message += "device_endpoint: " + String.format("%02x", deviceEndpoint) + "\n";
180                 DatagramPacket sendPacket = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(strHostAddress), iDstPort);
181                 socket.send(sendPacket);
182         }
183
184         public void sendBindRequest(int packetId, int clusterId, int deviceEndpoint) throws IOException {
185                 String message = "type: zdo_bind_request\n";
186                 message += "packet_id: " + String.format("%04x", packetId) + "\n";
187                 message += "device_address_long: " + zigbeeAddress.getAddress() + "\n";
188                 message += "cluster_id: " + String.format("%04x", clusterId) + "\n";
189                 message += "device_endpoint: " + String.format("%02x", deviceEndpoint) + "\n";
190                 DatagramPacket sendPacket = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(strHostAddress), iDstPort);
191                 socket.send(sendPacket);
192         }
193
194         public void sendUnBindRequest(int packetId, int clusterId, int deviceEndpoint) throws IOException {
195                 String message = "type: zdo_unbind_request\n";
196                 message += "packet_id: " + String.format("%04x", packetId) + "\n";
197                 message += "device_address_long: " + zigbeeAddress.getAddress() + "\n";
198                 message += "cluster_id: " + String.format("%04x", clusterId) + "\n";
199                 message += "device_endpoint: " + String.format("%02x", deviceEndpoint) + "\n";
200                 DatagramPacket sendPacket = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(strHostAddress), iDstPort);
201                 socket.send(sendPacket);
202         }
203
204         public void sendReadAttributesCommand(int packetId, int clusterId, int profileId, int deviceEndpoint, List<Integer> attributeIds) throws IOException {
205                 String message = "type: zcl_read_attributes\n";
206                 message += "packet_id: " + String.format("%04x", packetId) + "\n";
207                 message += "device_address_long: " + zigbeeAddress.getAddress() + "\n";
208                 message += "cluster_id: " + String.format("%04x", clusterId) + "\n";
209                 message += "profile_id: " + String.format("%04x", profileId) + "\n";
210                 message += "device_endpoint: " + String.format("%02x", deviceEndpoint) + "\n";
211
212                 message += "attribute_ids: ";
213
214                 for (Integer i : attributeIds) {
215                         message += String.format("%04x", i) + ",";
216                 }
217
218                 message = message.substring(0, message.length() - 1);
219                 message += "\n";
220
221                 DatagramPacket sendPacket = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(strHostAddress), iDstPort);
222                 socket.send(sendPacket);
223         }
224
225         public void sendConfigureReportingCommand(int packetId, int clusterId, int profileId, int src_endpoint, int dest_endpoint, 
226                 int attributeId, int dataType, int minReportingInterval, int maxReportingInterval, byte[] reportableChange) throws IOException {
227                 String message = "type: zcl_configure_reporting\n";
228                 message += "packet_id: " + String.format("%04x", packetId) + "\n";
229                 message += "device_address_long: " + zigbeeAddress.getAddress() + "\n";
230                 message += "cluster_id: " + String.format("%04x", clusterId) + "\n";
231                 message += "profile_id: " + String.format("%04x", profileId) + "\n";
232                 message += "src_endpoint: " + String.format("%02x", src_endpoint) + "\n";
233                 message += "device_endpoint: " + String.format("%02x", dest_endpoint) + "\n";
234                 message += "attribute_id: " + String.format("%04x", attributeId) + "\n";
235                 message += "data_type: " + String.format("%02x", dataType) + "\n";
236                 message += "min_reporting_interval: " + String.format("%04x", minReportingInterval) + "\n";
237                 message += "max_reporting_interval: " + String.format("%04x", maxReportingInterval) + "\n";
238
239                 if (reportableChange != null) {
240                         message += "reportable_change: ";
241                         for (Byte b : reportableChange) {
242                                 message += String.format("%02x", (int)b);
243                         }
244                         message += "\n";
245                 }
246
247                 DatagramPacket sendPacket = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(strHostAddress), iDstPort);
248                 socket.send(sendPacket);
249         }
250
251         public void sendConfigureReportingCommand(int packetId, int clusterId, int profileId, int dest_endpoint, int attributeId, int dataType, 
252             int minReportingInterval, int maxReportingInterval, byte[] reportableChange) throws IOException {
253                 sendConfigureReportingCommand(packetId, clusterId, profileId, 0x00, dest_endpoint, attributeId, dataType, minReportingInterval, 
254                     maxReportingInterval, reportableChange);
255         }
256
257         public void registerCallback(IoTZigbeeCallback callbackTo) {
258                 callbackList.add(callbackTo);
259         }
260
261         public void close() throws InterruptedException {
262                 endTask.set(true);
263
264                 // wait for the threads to end
265                 receiveThread.join();
266
267                 socket.close();
268                 didClose = true;
269         }
270
271         /**
272          * close() called by the garbage collector right before trashing object
273          */
274         public void Finalize() throws SocketException, InterruptedException {
275
276                 if (!didClose) {
277                         close();
278                         throw new SocketException("Socket not closed before object destruction, must call close method.");
279                 }
280         }
281
282         private void sendDeviceAddress() throws IOException {
283                 String message = "type: send_address\n";
284                 message += "packet_id: 00\n";
285                 message += "device_address_long: " + zigbeeAddress.getAddress() + "\n";
286                 DatagramPacket sendPacket = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(strHostAddress), iDstPort);
287                 socket.send(sendPacket);
288         }
289
290         private void receieveWorker() {
291                 while (!(endTask.get())) {
292
293                         byte[] recBuffer = new byte[SOCKET_RECEIVE_BUFFER_SIZE];
294                         try {
295                                 DatagramPacket recPacket = new DatagramPacket(recBuffer, recBuffer.length);
296                                 socket.receive(recPacket);
297
298                                 // Convert the UDP data into a string format
299                                 String dataString = new String(recPacket.getData());
300
301                                 // split the data by line so we can start procesisng
302                                 String[] lines = dataString.split("\n");
303
304                                 Map<String, String> packetData = new HashMap<String, String>();
305                                 for (String line : lines) {
306
307                                         // trim the line
308                                         String trimmedLine = line.trim();
309                                         // make sure this is a valid data line and not just blank
310                                         if (trimmedLine.length() == 0) {
311                                                 continue;
312                                         }
313
314                                         // Split the data into parts
315                                         String[] parts = trimmedLine.split(":");
316                                         parts[0] = parts[0].trim();
317                                         parts[1] = parts[1].trim();
318                                         packetData.put(parts[0], parts[1]);
319                                 }
320
321                                 if (packetData.get("type").equals("send_address_response")) {
322                                         didSuccesfullySendAddress.set(true);
323
324                                 } else {
325                                         IoTZigbeeMessage callbackMessage = null;
326
327                                         // Created by Changwoo
328                                         if (packetData.get("type").equals("zcl_zone_status_change_notification")){
329                                                 int packetId = Integer.parseInt(packetData.get("packet_id"), 16);
330                                                 int clusterId = Integer.parseInt(packetData.get("cluster_id"), 16);
331                                                 int profileId = Integer.parseInt(packetData.get("profile_id"), 16);
332                                                 int status = Integer.parseInt(packetData.get("status"), 10);
333                                                 boolean successOrFail = false;
334                                                 if(packetData.get("attributes").equals("success")) successOrFail=true;
335                                                 callbackMessage = new IoTZigbeeMessageZclZoneStatusChangeNotification(packetId, clusterId, profileId, status, successOrFail);
336
337                                         // Created by Changwoo
338                                         } else if (packetData.get("type").equals("zcl_write_attributes_response")) {
339
340                                                 int packetId = Integer.parseInt(packetData.get("packet_id"), 16);
341                                                 int clusterId = Integer.parseInt(packetData.get("cluster_id"), 16);
342                                                 int profileId = Integer.parseInt(packetData.get("profile_id"), 16);
343                                                 boolean successOrFail = false;
344                                                 if(packetData.get("attributes").equals("success")) successOrFail=true;
345                                                 
346                                                 callbackMessage = new IoTZigbeeMessageZclWriteAttributesResponse(packetId, clusterId, profileId, successOrFail);
347
348                                         } else if (packetData.get("type").equals("zcl_read_attributes_response")) {
349                                                 int packetId = Integer.parseInt(packetData.get("packet_id"), 16);
350                                                 int clusterId = Integer.parseInt(packetData.get("cluster_id"), 16);
351                                                 int profileId = Integer.parseInt(packetData.get("profile_id"), 16);
352
353                                                 List<IoTZigbeeMessageZclReadAttributesResponse.Attribute> attrList = new 
354                                                     ArrayList<IoTZigbeeMessageZclReadAttributesResponse.Attribute>();
355
356                                                 String[] attributes = packetData.get("attributes").split(";");
357                                                 for (String attr : attributes) {
358                                                         attr = attr.trim();
359                                                         String[] parts = attr.split(",");
360
361                                                         if (parts.length == 2) {
362                                                                 parts[0] = parts[0].trim();
363                                                                 parts[1] = parts[1].trim();
364
365                                                                 IoTZigbeeMessageZclReadAttributesResponse.Attribute at = new 
366                                                                     IoTZigbeeMessageZclReadAttributesResponse.Attribute(Integer.parseInt(parts[0], 16), 0, false, null);
367                                                                 attrList.add(at);
368                                                         } else {
369                                                                 parts[0] = parts[0].trim();
370                                                                 parts[1] = parts[1].trim();
371                                                                 parts[2] = parts[2].trim();
372                                                                 parts[3] = parts[3].trim();
373                                                                 IoTZigbeeMessageZclReadAttributesResponse.Attribute at = new 
374                                                                     IoTZigbeeMessageZclReadAttributesResponse.Attribute(Integer.parseInt(parts[0], 16), 
375                                                                     Integer.parseInt(parts[1], 16), true, hexStringToByteArray(parts[3]));
376                                                                 attrList.add(at);
377                                                         }
378                                                 }
379
380                                                 callbackMessage = new IoTZigbeeMessageZclReadAttributesResponse(packetId, clusterId, profileId, attrList);
381
382                                         } else if (packetData.get("type").equals("zcl_configure_reporting_response")) {
383                                                 int packetId = Integer.parseInt(packetData.get("packet_id"), 16);
384                                                 int clusterId = Integer.parseInt(packetData.get("cluster_id"), 16);
385                                                 int profileId = Integer.parseInt(packetData.get("profile_id"), 16);
386
387                                                 if (packetData.get("attributes").equals("all_success")) {
388                                                         callbackMessage = new IoTZigbeeMessageZclConfigureReportingResponse(packetId, clusterId, profileId, true, null);
389                                                 } else {
390                                                         List<IoTZigbeeMessageZclConfigureReportingResponse.Attribute> attrList = new 
391                                                             ArrayList<IoTZigbeeMessageZclConfigureReportingResponse.Attribute>();
392
393                                                         String[] attributes = packetData.get("attributes").split(";");
394                                                         for (String attr : attributes) {
395                                                                 attr = attr.trim();
396                                                                 String[] parts = attr.split(",");
397                                                                 parts[0] = parts[0].trim();
398                                                                 parts[1] = parts[1].trim();
399                                                                 parts[2] = parts[2].trim();
400                                                                 IoTZigbeeMessageZclConfigureReportingResponse.Attribute at = new 
401                                                                     IoTZigbeeMessageZclConfigureReportingResponse.Attribute(Integer.parseInt(parts[0], 16), 
402                                                                     parts[1].equals("success"), parts[2].equals("reported"));
403                                                                 attrList.add(at);
404                                                         }
405                                                         callbackMessage = new IoTZigbeeMessageZclConfigureReportingResponse(packetId, clusterId, profileId, false, attrList);
406                                                 }
407
408                                         } else if (packetData.get("type").equals("zcl_report_attributes")) {
409                                                 int packetId = Integer.parseInt(packetData.get("packet_id"), 16);
410                                                 int clusterId = Integer.parseInt(packetData.get("cluster_id"), 16);
411                                                 int profileId = Integer.parseInt(packetData.get("profile_id"), 16);
412
413                                                 List<IoTZigbeeMessageZclReportAttributes.Attribute> attrList = new ArrayList<IoTZigbeeMessageZclReportAttributes.Attribute>();
414
415                                                 String[] attributes = packetData.get("attributes").split(";");
416                                                 for (String attr : attributes) {
417                                                         attr = attr.trim();
418                                                         String[] parts = attr.split(",");
419
420                                                         parts[0] = parts[0].trim();
421                                                         parts[1] = parts[1].trim();
422                                                         parts[2] = parts[2].trim();
423                                                         IoTZigbeeMessageZclReportAttributes.Attribute at = new 
424                                                             IoTZigbeeMessageZclReportAttributes.Attribute(Integer.parseInt(parts[0], 16), 
425                                                             Integer.parseInt(parts[1], 16), hexStringToByteArray(parts[2]));
426                                                         attrList.add(at);
427                                                 }
428
429                                                 callbackMessage = new IoTZigbeeMessageZclReportAttributes(packetId, clusterId, profileId, attrList);
430
431                                         } else if (packetData.get("type").equals("zcl_read_attributes")) {
432                                                 int packetId = Integer.parseInt(packetData.get("packet_id"), 16);
433                                                 boolean success = packetData.get("response").equals("success");
434
435                                                 if (success) {
436                                                         callbackMessage = new IoTZigbeeMessageZclReadAttributes(packetId, success, "");
437                                                 } else {
438                                                         callbackMessage = new IoTZigbeeMessageZclReadAttributes(packetId, success, packetData.get("reason"));
439                                                 }
440
441                                         } else if (packetData.get("type").equals("zcl_configure_reporting")) {
442                                                 int packetId = Integer.parseInt(packetData.get("packet_id"), 16);
443                                                 boolean success = packetData.get("response").equals("success");
444
445                                                 if (success) {
446                                                         callbackMessage = new IoTZigbeeMessageZclConfigureReporting(packetId, success, "");
447                                                 } else {
448                                                         callbackMessage = new IoTZigbeeMessageZclConfigureReporting(packetId, success, packetData.get("reason"));
449                                                 }
450
451                                         } else if (packetData.get("type").equals("zdo_bind_request")) {
452                                                 int packetId = Integer.parseInt(packetData.get("packet_id"), 16);
453                                                 boolean success = packetData.get("response").equals("success");
454
455                                                 if (success) {
456                                                         callbackMessage = new IoTZigbeeMessageZdoBindResponse(packetId, success, "");
457                                                 } else {
458                                                         callbackMessage = new IoTZigbeeMessageZdoBindResponse(packetId, success, packetData.get("reason"));
459                                                 }
460                                         }
461
462                                         else if (packetData.get("type").equals("zdo_unbind_request")) {
463                                                 int packetId = Integer.parseInt(packetData.get("packet_id"), 16);
464                                                 boolean success = packetData.get("response").equals("success");
465
466                                                 if (success) {
467                                                         callbackMessage = new IoTZigbeeMessageZdoUnBindResponse(packetId, success, "");
468                                                 } else {
469                                                         callbackMessage = new IoTZigbeeMessageZdoUnBindResponse(packetId, success, packetData.get("reason"));
470                                                 }
471                                         }
472
473                                         if (callbackMessage != null) {
474                                                 for (IoTZigbeeCallback c : callbackList) {
475                                                         c.newMessageAvailable(callbackMessage);
476                                                 }
477                                         }
478                                 }
479
480                         } catch (Exception e) {
481                                 e.printStackTrace();
482                         }
483                 }
484         }
485
486         public static String changeHexEndianness(String hexData) {
487
488                 List<String> pairedValues = new ArrayList<String>();
489                 for (int i = 0; i < hexData.length(); i += 2) {
490                         String part = hexData.substring(i, Math.min(i + 2, hexData.length()));
491                         pairedValues.add(part);
492                 }
493
494                 String retString  = "";
495                 for (int i = (pairedValues.size() - 1); i >= 0; i--) {
496                         retString += pairedValues.get(i);
497                 }
498                 return retString;
499         }
500
501         // taken from: http://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java
502         public static byte[] hexStringToByteArray(String s) {
503                 int len = s.length();
504                 byte[] data = new byte[len / 2];
505                 for (int i = 0; i < len; i += 2) {
506                         data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
507                                               + Character.digit(s.charAt(i + 1), 16));
508                 }
509                 return data;
510         }
511
512 }
513
514