Moving Java drivers; Creating iotruntime socket connections for C++; First version...
[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
22 //import iotchecker.qual.*;
23 import iotcode.annotation.*;
24
25 /** Class EspAlarm for the ESP8266 plrg Alarm.
26  *
27  * @author      Ali Younis <ayounis @ uci.edu>, Rahmadi Trimananda <rtrimana @ uci.edu>
28  * @version     1.0
29  * @since       2016-12-21
30  */
31
32 public class EspAlarm implements Alarm {
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> alm_Addresses;
66
67         /*public EspSprinkler(IoTUDP _udp) {
68                 communicationSockect = _udp;
69         }*/
70
71         public EspAlarm() {
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 = alm_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                         //ZoneState zTmp = new ZoneState(zoneNum, onOff, duration);
275                         ZoneState zTmp = new ZoneState();
276                         zTmp.zoneNumber = zoneNum;
277                         zTmp.onOffState = onOff;
278                         zTmp.duration = duration;
279                         retStates.add(zTmp);
280                 }
281
282                 return retStates;
283         }
284
285
286         /** Method to parse the UDP packet data into a meaningful representation.
287          *
288          *   @param _packetData [byte[]] bytes to send over the udp channel.
289          *
290          *   @return [void] None.
291          */
292         private void sendPacket(byte[] _packetData) {
293                 // System.out.println("About to send");
294                 sendSocketFlag.set(true);
295
296                 try {
297                         socketMutex.acquire();
298                 } catch (InterruptedException e) {
299                         System.out.println("mutex Error");
300                 }
301
302                 try {
303                         communicationSockect.sendData(_packetData);
304
305                 } catch (IOException e) {
306                         System.out.println("Socket Send Error");
307                 }
308
309                 sendSocketFlag.set(false);
310                 socketMutex.release();
311         }
312
313
314         /** Method to constantly flush the udp socket expect when we wish to read the incoming data.
315          *
316          *   @param None.
317          *
318          *   @return [void] None.
319          */
320         private void workerFunction() {
321                 try {
322                         // Need timeout on receives since we are not sure if a packet will be available
323                         // for processing so don't block waiting
324                         communicationSockect.setSoTimeout(50);
325                 } catch (IOException e) {
326                 }
327
328
329
330                 while (true) {
331
332                         // Communication resource is busy so try again later
333                         if (sendSocketFlag.get()) {
334                                 continue;
335                         }
336
337                         if (doingRead.get()) {
338                                 continue;
339                         }
340
341                         try {
342                                 socketMutex.acquire();
343                         } catch (InterruptedException e) {
344                         }
345
346                         byte[] dat = null;
347                         try {
348                                 dat = communicationSockect.recieveData(1024);
349                         } catch (java.net.SocketTimeoutException e) {
350                                 // Timeout occurred
351
352                         } catch (IOException e) {
353                                 // Problem but might be able to recover??
354                                 e.printStackTrace();
355
356                         }
357
358                         // Never forget to release!
359                         socketMutex.release();
360
361                         // Wait a bit as to not tie up system resources
362                         try {
363                                 Thread.sleep(100);
364                         } catch (Exception e) {
365
366                         }
367                 }
368         }
369
370 }
371
372