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