Committing changes in driver files for paper evaluation
[iot2.git] / benchmarks / drivers / Java / AmcrestCamera / AmcrestCamera.java
1 package iotcode.AmcrestCamera;
2
3 // IoT Packages
4 import iotcode.annotation.*;
5 import iotcode.interfaces.*;
6 import iotruntime.IoTHTTP;
7 import iotruntime.slave.IoTSet;
8 import iotruntime.slave.IoTDeviceAddress;
9
10 // Standard Java Packages
11 import java.io.IOException;
12 import java.io.DataInputStream;
13 import java.io.InputStream;
14 import java.io.BufferedInputStream;
15 import java.io.ByteArrayInputStream;
16 import java.io.IOException;
17 import java.io.ByteArrayOutputStream;
18 import java.io.File;
19 import java.awt.image.BufferedImage;
20 import java.awt.image.ColorModel;
21 import java.awt.image.WritableRaster;
22 import java.awt.image.BufferedImage;
23 import javax.imageio.ImageIO;
24 import java.util.Base64;
25 import java.util.Arrays;
26 import java.util.Date;
27 import java.util.List;
28 import java.util.ArrayList;
29 import java.util.Set;
30 import java.util.HashSet;
31 import java.util.concurrent.locks.Lock;
32 import java.util.concurrent.locks.ReadWriteLock;
33 import java.util.concurrent.locks.ReentrantReadWriteLock;
34 import java.util.concurrent.atomic.AtomicBoolean;
35 import java.util.Iterator;
36 import javax.imageio.ImageIO;
37 import java.util.concurrent.CopyOnWriteArrayList;
38 import java.util.concurrent.Semaphore;
39
40 // RMI Packages
41 import java.rmi.Remote;
42 import java.rmi.RemoteException;
43
44 // Checker annotations
45 //import iotchecker.qual.*;
46
47 public class AmcrestCamera implements Camera {
48
49         /*******************************************************************************************************************************************
50         **
51         **  Variables
52         **
53         *******************************************************************************************************************************************/
54         private String credentialUsername = "";
55         private String credentialPassword = "";
56         private DataInputStream dataInStream = null;
57         private boolean isStreamConnected = false;
58         private byte[] latestImage = null;
59         private ReadWriteLock imageReadWriteLock = new ReentrantReadWriteLock();
60         private Lock imageReadLock = imageReadWriteLock.readLock();
61         private Lock imageWriteLock = imageReadWriteLock.writeLock();
62         private AtomicBoolean newFrameAvailable = new AtomicBoolean(false);
63         private ReadWriteLock timestampReadWriteLock = new ReentrantReadWriteLock();
64         private Lock timestampReadLock = timestampReadWriteLock.readLock();
65         private Lock timestampWriteLock = timestampReadWriteLock.writeLock();
66         private Date latestImageTimestamp = null;
67         private List <CameraSmartCallback> callbackList =
68             new CopyOnWriteArrayList <CameraSmartCallback> ();
69         private AtomicBoolean doEnd = new AtomicBoolean(false);
70         private IoTDeviceAddress deviceAddress = null;
71         private AtomicBoolean didInit = new AtomicBoolean();
72         private AtomicBoolean didStart = new AtomicBoolean();
73         static Semaphore settingsSettings = new Semaphore(1);
74
75         /*******************************************************************************************************************************************
76         **
77         **  Threads
78         **
79         *******************************************************************************************************************************************/
80         private Thread callbackThread = null;
81         private Thread workerThread = null;
82
83
84         /*******************************************************************************************************************************************
85         **
86         **  IoT Sets and Relations
87         **
88         *******************************************************************************************************************************************/
89
90         // IoTSet of Device Addresses.
91         // Will be filled with only 1 address.
92         @config private IoTSet<IoTDeviceAddress> cam_addresses;
93
94         public AmcrestCamera(String _credentialUsername, String _credentialPassword, IoTSet<IoTDeviceAddress> _camAddresses) throws RemoteException {
95                 credentialUsername = _credentialUsername;
96                 credentialPassword = _credentialPassword;
97                 cam_addresses = _camAddresses;
98         }
99
100         public AmcrestCamera(String _credentialUsername, String _credentialPassword) throws RemoteException {
101                 credentialUsername = _credentialUsername;
102                 credentialPassword = _credentialPassword;
103         }
104
105         /*******************************************************************************************************************************************
106         **
107         **  Camera Interface Methods
108         **
109         *******************************************************************************************************************************************/
110
111         public byte[] getLatestFrame() {
112
113                 byte[] newImage = null;
114
115                 imageReadLock.lock();
116                 try {
117                         if (latestImage != null) {
118                                 newImage = Arrays.copyOf(latestImage, latestImage.length);
119                         }
120                 } catch (Exception x) {
121                         x.printStackTrace();
122                 }
123                 imageReadLock.unlock();
124
125                 return newImage;
126         }
127
128         public long getTimestamp() {
129                 timestampReadLock.lock();
130                 Date ret = (Date)latestImageTimestamp.clone();
131                 timestampReadLock.unlock();
132                 long retLong = ret.getTime();
133                 return retLong;
134         }
135
136         public void registerCallback(CameraSmartCallback _callbackTo) {
137                 callbackList.add(_callbackTo);
138         }
139
140         public boolean setFPS(int _fps) {
141                 try {
142                         settingsSettings.acquire();
143
144                         String camUrlString = "/cgi-bin/configManager.cgi?action=setConfig&Encode[0].MainFormat[0].Video.FPS=" + Integer.toString(_fps);
145
146                         try {
147
148                                 String credsPreBase64 = credentialUsername + ":" + credentialPassword;
149                                 String credsBase64 = Base64.getEncoder().encodeToString(credsPreBase64.getBytes("utf-8"));
150                                 String httpAuthCredentials = "Basic " + credsBase64;
151
152                                 IoTHTTP httpConnection = new IoTHTTP(deviceAddress);
153                                 httpConnection.setURL(camUrlString);
154                                 httpConnection.openConnection();
155                                 httpConnection.setDoInput(true);
156                                 httpConnection.setRequestProperty("Authorization", httpAuthCredentials);
157                                 httpConnection.connect();
158                                 
159                                 InputStream is = httpConnection.getInputStream();
160                                 BufferedInputStream bis = new BufferedInputStream(is);
161                                 DataInputStream din = new DataInputStream(bis);
162                                 
163                                 // wait for a response
164                                 try {
165                                         Thread.sleep(1000);
166                                 } catch (InterruptedException ie) {
167                                 }
168
169                                 byte[] byteBuf = new byte[100];
170                                 try {
171                                         int r = din.read(byteBuf, 0, byteBuf.length);
172                                         String retString = new String(byteBuf);
173
174                                         if (!retString.substring(0, 2).equals("OK")) {
175                                                 httpConnection.disconnect();
176                                                 return false;
177                                         }
178
179                                 } catch (Exception e) {
180                                         httpConnection.disconnect();
181                                         return false;
182                                         // e.printStackTrace();
183                                 }
184                                 
185                                 httpConnection.disconnect();
186                         } catch (IOException e) {
187                                 return false;
188                         } catch (Exception e) {
189                                 return false;
190                         }
191                 } catch (Exception e) {
192                         e.printStackTrace();
193                 }
194                 settingsSettings.release();
195
196                 return true;
197         }
198
199         public int getMaxFPS() {
200                 // Hard coded since this is hardware dependant
201                 return 30;
202         }
203
204         public int getMinFPS() {
205                 // Hard coded since this is hardware dependant
206                 return 5;
207         }
208
209         public List<Resolution> getSupportedResolutions() {
210
211                 // Hard coded since this is hardware dependant
212                 List<Resolution> ret = new ArrayList<Resolution>();
213                 ret.add(Resolution.RES_1080P);
214                 ret.add(Resolution.RES_720P);
215                 ret.add(Resolution.RES_VGA);
216                 return ret;
217         }
218
219         public boolean setResolution(Resolution _res) {
220
221                 try {
222                         settingsSettings.acquire();
223
224
225                         String camUrlString = "/cgi-bin/configManager.cgi?action=setConfig";
226
227                         if (_res == Resolution.RES_1080P) {
228                                 camUrlString += "&Encode[0].MainFormat[0].Video.Height=1080&Encode[0].MainFormat[0].Video.Width=1920";
229
230                         } else if (_res == Resolution.RES_720P) {
231                                 camUrlString += "&Encode[0].MainFormat[0].Video.Height=720&Encode[0].MainFormat[0].Video.Width=1280";
232
233                         } else if (_res == Resolution.RES_VGA) {
234                                 camUrlString += "&Encode[0].MainFormat[0].Video.Height=480&Encode[0].MainFormat[0].Video.Width=640";
235                         }
236
237                         try {
238
239                                 String credsPreBase64 = credentialUsername + ":" + credentialPassword;
240                                 String credsBase64 = Base64.getEncoder().encodeToString(credsPreBase64.getBytes("utf-8"));
241                                 String httpAuthCredentials = "Basic " + credsBase64;
242
243                                 IoTHTTP httpConnection = new IoTHTTP(deviceAddress);
244                                 httpConnection.setURL(camUrlString);
245                                 httpConnection.openConnection();
246                                 httpConnection.setDoInput(true);
247                                 httpConnection.setRequestProperty("Authorization", httpAuthCredentials);
248                                 httpConnection.connect();
249
250                                 InputStream is = httpConnection.getInputStream();
251                                 BufferedInputStream bis = new BufferedInputStream(is);
252                                 DataInputStream din = new DataInputStream(bis);
253
254                                 // wait for a response
255                                 try {
256                                         Thread.sleep(1000);
257                                 } catch (InterruptedException ie) {
258                                 }
259
260                                 byte[] byteBuf = new byte[100];
261                                 try {
262                                         int r = din.read(byteBuf, 0, byteBuf.length);
263                                         String retString = new String(byteBuf);
264
265                                         if (!retString.substring(0, 2).equals("OK")) {
266                                                 httpConnection.disconnect();
267                                                 return false;
268                                         }
269
270                                 } catch (Exception e) {
271                                         httpConnection.disconnect();
272                                         return false;
273                                         // e.printStackTrace();
274                                 }
275
276                                 httpConnection.disconnect();
277                         } catch (IOException e) {
278                                 return false;
279                         } catch (Exception e) {
280                                 return false;
281                         }
282                 } catch (Exception e) {
283                         e.printStackTrace();
284                 }
285
286                 settingsSettings.release();
287
288                 return true;
289         }
290
291         public void start() {
292
293                 if (didStart.compareAndSet(false, true) == false) {
294                         return; // already started
295                 }
296
297                 doEnd.set(false);
298
299                 if (!streamConnect()) {
300                         return;
301                 }
302
303                 callbackThread = new Thread(new Runnable() {
304                         public void run() {
305                                 doCallbacks();
306                         }
307                 });
308                 callbackThread.start();
309
310                 workerThread = new Thread(new Runnable() {
311                         public void run() {
312                                 doWork();
313                         }
314                 });
315                 workerThread.start();
316         }
317
318         public void stop() {
319                 if (didStart.compareAndSet(true, false) == false) {
320                         return; // already stopped
321                 }
322
323                 doEnd.set(true);
324
325                 try {
326                         callbackThread.join();
327                         workerThread.join();
328                 } catch (Exception e) {
329                         e.printStackTrace();
330                 }
331
332                 streamDisconnect();
333         }
334
335         public void init() {
336                 if (didInit.compareAndSet(false, true) == false) {
337                         return; // already init
338                 }
339
340                 // get the device address and save it for later use when creating HTTP connections
341                 Iterator itr = cam_addresses.iterator();
342                 deviceAddress = (IoTDeviceAddress)itr.next();
343
344                 System.out.println("Address: " + deviceAddress.getCompleteAddress());
345         }
346
347         /*******************************************************************************************************************************************
348         **
349         **  Helper Methods
350         **
351         *******************************************************************************************************************************************/
352         private byte[] readFromStream(int num) {
353                 byte[] byteBuf = new byte[num];
354                 try {
355                         dataInStream.readFully(byteBuf, 0, byteBuf.length);
356                 } catch (Exception e) {
357                         e.printStackTrace();
358                 }
359
360                 return byteBuf;
361         }
362
363         private void findBoundry() {
364                 String boundary = "**************";
365                 while (true) {
366                         byte b = readFromStream(1)[0];
367                         boundary = boundary.substring(1);
368                         boundary += (char)b;
369
370                         if (boundary.equals("--myboundary\r\n")) {
371                                 break;
372                         }
373                 }
374         }
375
376         private String getLine() {
377                 String line = "";
378                 while (true) {
379                         byte b = readFromStream(1)[0];
380                         char c = (char)b;
381
382                         if (c == '\n') {
383                                 break;
384                         } else if (c != '\r') {
385                                 line += c;
386                         }
387                 }
388
389                 return line;
390         }
391
392         private BufferedImage parseImage() {
393
394                 findBoundry();
395
396                 String contentTypeString = getLine();
397                 String contentLengthString = getLine();
398
399                 // remove the new line characters \r\n
400                 readFromStream(2);
401
402                 int imageDataLength = Integer.parseInt(contentLengthString.substring(16));
403
404                 byte[] imageDataBuf = readFromStream(imageDataLength);
405
406                 // remove the new line characters \r\n
407                 readFromStream(2);
408
409
410                 try {
411                         InputStream imageInStream = new ByteArrayInputStream(imageDataBuf);
412                         return ImageIO.read(imageInStream);
413
414                 } catch (Exception e) {
415                         e.printStackTrace();
416                         System.out.println("Has Exception");
417
418                 }
419
420                 return null;
421         }
422
423         private boolean streamConnect() {
424
425                 try {
426
427                         String credsPreBase64 = credentialUsername + ":" + credentialPassword;
428                         String credsBase64 = Base64.getEncoder().encodeToString(credsPreBase64.getBytes("utf-8"));
429                         String httpAuthCredentials = "Basic " + credsBase64;
430
431                         IoTHTTP httpConnection = new IoTHTTP(deviceAddress);
432                         httpConnection.setURL("/cgi-bin/mjpg/video.cgi?channel=0&subtype=1");
433                         //httpConnection.setURL("/cgi-bin/mjpg/video.cgi?channel=0&subtype=1", credentialUsername, credentialPassword);
434                         httpConnection.openConnection();
435                         httpConnection.setDoInput(true);
436                         httpConnection.setRequestProperty("Authorization", httpAuthCredentials);
437                         httpConnection.connect();
438
439                         InputStream is = httpConnection.getInputStream();
440                         BufferedInputStream bis = new BufferedInputStream(is);
441                         dataInStream = new DataInputStream(bis);
442
443                         isStreamConnected = true;
444
445                 } catch (IOException e) {
446                         isStreamConnected = false;
447
448                 } catch (Exception e) {
449                         isStreamConnected = false;
450                 }
451
452                 return isStreamConnected;
453         }
454
455         private void streamDisconnect() {
456                 try {
457                         if (isStreamConnected) {
458                                 dataInStream.close();
459                                 isStreamConnected = false;
460                         }
461                 } catch (Exception e) {
462                 }
463         }
464
465         private void doCallbacks() {
466
467                 while (!doEnd.get()) {
468                         if (newFrameAvailable.compareAndSet(true, false)) {
469
470                                 for (CameraSmartCallback c : callbackList) {
471
472                                         c.newCameraFrameAvailable(this.getLatestFrame(), this.getTimestamp());
473                                         //c.newCameraFrameAvailable(this);
474                                 }
475                         } else {
476
477                                 // Sleep for 15 millisec to give time for new frame to arrive
478                                 try {
479                                         Thread.sleep(15);
480                                 } catch (InterruptedException ie) {
481                                 }
482                         }
483                 }
484
485         }
486
487         private void doWork() {
488
489                 // parse the images that are loaded into the buffer
490                 while (!doEnd.get()) {
491
492                         BufferedImage img = parseImage();
493
494                         if (img != null) {
495
496                                 timestampWriteLock.lock();
497                                 latestImageTimestamp = new Date();
498                                 timestampWriteLock.unlock();
499
500                                 imageWriteLock.lock();
501
502                                 try {
503                                         ByteArrayOutputStream baos = new ByteArrayOutputStream();
504                                         ImageIO.write(img, "jpg", baos);
505                                         baos.flush();
506                                         latestImage = baos.toByteArray();
507                                         baos.close();
508
509                                 } catch (Exception e) {
510
511                                 }
512                                 imageWriteLock.unlock();
513
514                                 newFrameAvailable.set(true);
515                         }
516
517                         try {
518                                 if (dataInStream.available() > 120000) {
519                                         dataInStream.skip(120000);
520                                 }
521                         } catch (Exception e) {
522                         }
523                 }
524
525         }
526         
527         /* TODO: Uncomment this part to do camera test
528         public static void main(String[] args) throws Exception {
529
530                 System.out.println("Running AmcrestCamera!");
531
532                 IoTDeviceAddress iotDevAdd = new IoTDeviceAddress(args[0], 12345, 80, false, false);
533                 Set<IoTDeviceAddress> set = new HashSet<IoTDeviceAddress>();
534                 set.add(iotDevAdd);
535                 IoTSet<IoTDeviceAddress> iotset = new IoTSet<IoTDeviceAddress>(set);
536         
537                 AmcrestCamera cam = new AmcrestCamera(args[1], args[2], iotset);
538                 cam.init();
539                 cam.setFPS(15);
540                 cam.setResolution(Resolution.RES_VGA);
541                 cam.start();
542
543             while (true) {
544
545             }
546
547         }*/
548 }
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564