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