Cleaning up benchmarks and drivers code.
[iot2.git] / benchmarks / drivers / Java / EspAlarm / EspAlarm.java
1 package iotcode.EspAlarm;
2
3 // Standard Java Packages
4 import java.io.*;
5 import java.net.*;
6 import java.util.concurrent.Semaphore;
7 import java.util.concurrent.atomic.AtomicBoolean;
8 import java.security.InvalidParameterException;
9 import java.util.Date;
10 import java.util.Iterator;
11 import java.nio.charset.StandardCharsets;
12 import java.util.List;
13 import java.util.ArrayList;
14
15 // IoT Packages
16 import iotruntime.IoTUDP;
17 import iotruntime.slave.IoTDeviceAddress;
18 import iotruntime.slave.IoTSet;
19 import iotcode.interfaces.ZoneState;
20 import iotcode.interfaces.Alarm;
21 import iotcode.annotation.*;
22
23 /** Class EspAlarm for the ESP8266 plrg Alarm.
24  *
25  * @author      Ali Younis <ayounis @ uci.edu>, Rahmadi Trimananda <rtrimana @ uci.edu>
26  * @version     1.0
27  * @since       2016-12-21
28  */
29
30 public class EspAlarm implements Alarm {
31
32         /*******************************************************************************************************************************************
33         **
34         **  Variables
35         **
36         *******************************************************************************************************************************************/
37
38         private IoTUDP communicationSockect;
39         private Semaphore socketMutex = new Semaphore(1);
40         private AtomicBoolean sendSocketFlag = new AtomicBoolean(false);
41         private AtomicBoolean doingRead = new AtomicBoolean(false);
42         private AtomicBoolean didInit = new AtomicBoolean(false);
43         private Semaphore settingZone = new Semaphore(1);
44
45         /*******************************************************************************************************************************************
46         **
47         **  Threads
48         **
49         *******************************************************************************************************************************************/
50
51         // Main worker thread will do the receive loop
52         Thread workerThread = null;
53
54
55         /*******************************************************************************************************************************************
56         **
57         **  IoT Sets and Relations
58         **
59         *******************************************************************************************************************************************/
60
61         // IoTSet of Device Addresses.
62         // Will be filled with only 1 address.
63         @config private IoTSet<IoTDeviceAddress> alm_Addresses;
64
65         /* TODO: Use this constructor to test this driver manually
66         public EspSprinkler(IoTUDP _udp) {
67                 communicationSockect = _udp;
68         }*/
69
70         public EspAlarm() {
71                 communicationSockect = null;
72         }
73
74
75         /*******************************************************************************************************************************************
76         **
77         **  Interface Methods
78         **
79         *******************************************************************************************************************************************/
80
81         /** Method to set the state of a specified zone. Interface implementation.
82          *
83          *   @param _zone [int]             : zone number to set.
84          *   @param _onOff [boolean]        : the state to set the zone to, on or off.
85          *   @param _onDurationSeconds [int]: the duration to set the state on to, if -1 then infinite.
86          *
87          *   @return [void] None.
88          */
89         public void setZone(int _zone, boolean _onOff, int _onDurationSeconds) {
90
91                 try {
92                         settingZone.acquire();
93                         String sendString = "SET,";
94                         sendString += Integer.toString(_zone);
95                         sendString += ", ";
96
97                         if (_onOff) {
98                                 sendString += "1";
99                         } else {
100                                 sendString += "0";
101                         }
102                         sendString += ", ";
103                         sendString += Integer.toString(_onDurationSeconds);
104
105                         sendPacket(sendString.getBytes(StandardCharsets.UTF_8));
106                 } catch (Exception e) {
107                         e.printStackTrace();
108                 }
109                 settingZone.release();
110         }
111
112
113         /** Method to get the current state of all the zones. Interface implementation.
114          *
115          *   @param None.
116          *
117          *   @return [List<ZoneState>] list of the states for the zones.
118          */
119         public List<ZoneState> getZoneStates() {
120                 doingRead.set(true);
121                 sendGetInformation();
122
123                 try {
124                         Thread.sleep(100);
125                 } catch (Exception e) {
126                         e.printStackTrace();
127                 }
128
129                 int loopCount = 0;
130                 while (true) {
131                         // Communication resource is busy so try again later
132                         if (sendSocketFlag.get()) {
133                                 continue;
134                         }
135
136                         try {
137                                 socketMutex.acquire();
138                         } catch (InterruptedException e) {
139                         }
140
141                         byte[] dat = null;
142                         try {
143                                 dat = communicationSockect.recieveData(1024);
144                         } catch (java.net.SocketTimeoutException e) {
145                                 // Timeout occurred
146
147                         } catch (IOException e) {
148                                 // Problem but might be able to recover??
149                                 e.printStackTrace();
150
151                         }
152
153                         // Never forget to release!
154                         socketMutex.release();
155
156                         // A packed arrived
157                         if (dat != null) {
158                                 doingRead.set(false);
159                                 return parseGetResponse(dat);
160
161                                 // return new ArrayList<ZoneState>();
162                         } else {
163                                 try {
164                                         Thread.sleep(100);
165                                 } catch (Exception e) {
166                                         e.printStackTrace();
167                                 }
168                                 loopCount++;
169
170                                 if (loopCount > 3) {
171                                         sendGetInformation();
172                                         loopCount = 0;
173                                 }
174                         }
175                 }
176         }
177
178
179         /** Method to get the number of zones this sprinkler can control. Interface implementation.
180          *
181          *   @param None.
182          *
183          *   @return [int] number of zones that can be controlled.
184          */
185         public int getNumberOfZones() {
186                 return 9;
187         }
188
189
190         /** Method to get whether or not this sprinkler can control durations. Interface implementation.
191          *
192          *   @param None.
193          *
194          *   @return [boolean] boolean if this sprinkler can do durations.
195          */
196         public boolean doesHaveZoneTimers() {
197                 return true;
198         }
199
200
201         /** Method to initialize the sprinkler. Interface implementation.
202          *
203          *   @param None.
204          *
205          *   @return [void] None.
206          */
207         public void init() {
208
209                 if (didInit.compareAndSet(false, true) == false) {
210                         return; // already init
211                 }
212
213                 try {
214                         Iterator itr = alm_Addresses.iterator();
215                         IoTDeviceAddress deviceAddress = (IoTDeviceAddress)itr.next();
216                         System.out.println("Address: " + deviceAddress.getCompleteAddress());
217
218                         // Create the communication channel
219                         communicationSockect = new IoTUDP(deviceAddress);
220                 } catch (Exception e) {
221                         e.printStackTrace();
222                 }
223
224
225                 // Launch the worker function in a separate thread.
226                 workerThread = new Thread(new Runnable() {
227                         public void run() {
228                                 workerFunction();
229                         }
230                 });
231                 workerThread.start();
232         }
233
234
235         /*******************************************************************************************************************************************
236         **
237         **  Private Handlers
238         **
239         *******************************************************************************************************************************************/
240
241         /** Method to send the get information udp packet to get the latest sprinkler state.
242          *
243          *   @param None.
244          *
245          *   @return [void] None.
246          */
247         public void sendGetInformation() {
248                 String sendString = "GET";
249                 sendPacket(sendString.getBytes(StandardCharsets.UTF_8));
250         }
251
252
253         /** Method to parse the UDP packet data into a meaningful representation.
254          *
255          *   @param _packetData [byte[]] raw packet data from the udp packet.
256          *
257          *   @return [List<ZoneState>] Parsed zone data.
258          */
259         private List<ZoneState> parseGetResponse(byte[] _packetData) {
260                 String recString = new String(_packetData);
261                 List<ZoneState> retStates = new ArrayList<ZoneState>();
262
263                 String[] lines = recString.split("\n");
264
265                 for (int i = 0; i < 9; i++) {
266                         String[] splitSting = lines[i].split(",");
267
268                         int zoneNum = Integer.parseInt(splitSting[0].trim());
269                         int onOffInt = Integer.parseInt(splitSting[1].trim());
270                         boolean onOff = onOffInt != 0;
271                         int duration = Integer.parseInt(splitSting[2].trim());
272
273                         ZoneState zTmp = new ZoneState();
274                         zTmp.zoneNumber = zoneNum;
275                         zTmp.onOffState = onOff;
276                         zTmp.duration = duration;
277                         retStates.add(zTmp);
278                 }
279
280                 return retStates;
281         }
282
283
284         /** Method to parse the UDP packet data into a meaningful representation.
285          *
286          *   @param _packetData [byte[]] bytes to send over the udp channel.
287          *
288          *   @return [void] None.
289          */
290         private void sendPacket(byte[] _packetData) {
291                 // System.out.println("About to send");
292                 sendSocketFlag.set(true);
293
294                 try {
295                         socketMutex.acquire();
296                 } catch (InterruptedException e) {
297                         System.out.println("mutex Error");
298                 }
299
300                 try {
301                         communicationSockect.sendData(_packetData);
302
303                 } catch (IOException e) {
304                         System.out.println("Socket Send Error");
305                 }
306
307                 sendSocketFlag.set(false);
308                 socketMutex.release();
309         }
310
311
312         /** Method to constantly flush the udp socket expect when we wish to read the incoming data.
313          *
314          *   @param None.
315          *
316          *   @return [void] None.
317          */
318         private void workerFunction() {
319                 try {
320                         // Need timeout on receives since we are not sure if a packet will be available
321                         // for processing so don't block waiting
322                         communicationSockect.setSoTimeout(50);
323                 } catch (IOException e) {
324                 }
325
326
327
328                 while (true) {
329
330                         // Communication resource is busy so try again later
331                         if (sendSocketFlag.get()) {
332                                 continue;
333                         }
334
335                         if (doingRead.get()) {
336                                 continue;
337                         }
338
339                         try {
340                                 socketMutex.acquire();
341                         } catch (InterruptedException e) {
342                         }
343
344                         byte[] dat = null;
345                         try {
346                                 dat = communicationSockect.recieveData(1024);
347                         } catch (java.net.SocketTimeoutException e) {
348                                 // Timeout occurred
349
350                         } catch (IOException e) {
351                                 // Problem but might be able to recover??
352                                 e.printStackTrace();
353
354                         }
355
356                         // Never forget to release!
357                         socketMutex.release();
358
359                         // Wait a bit as to not tie up system resources
360                         try {
361                                 Thread.sleep(100);
362                         } catch (Exception e) {
363
364                         }
365                 }
366         }
367
368 }
369
370