001 /*----------------------------------------------------------------------------*/
002 /* Copyright (c) FIRST 2008-2012. All Rights Reserved. */
003 /* Open Source Software - may be modified and shared by FRC teams. The code */
004 /* must be accompanied by the FIRST BSD license file in the root directory of */
005 /* the project. */
006 /*----------------------------------------------------------------------------*/
007 package edu.wpi.first.wpilibj.camera;
008
009 import com.sun.cldc.jna.BlockingFunction;
010 import com.sun.cldc.jna.Function;
011 import com.sun.cldc.jna.NativeLibrary;
012 import com.sun.cldc.jna.Pointer;
013 import com.sun.cldc.jna.TaskExecutor;
014 import com.sun.squawk.VM;
015 import edu.wpi.first.wpilibj.DriverStation;
016 import edu.wpi.first.wpilibj.communication.UsageReporting;
017 import edu.wpi.first.wpilibj.image.ColorImage;
018 import edu.wpi.first.wpilibj.image.HSLImage;
019 import edu.wpi.first.wpilibj.image.NIVisionException;
020 import edu.wpi.first.wpilibj.parsing.ISensor;
021 import edu.wpi.first.wpilibj.util.BoundaryException;
022
023 //TODO figure out where to use finally to free resources
024 //TODO go through old camera code and make sure all features are implemented
025 //TODO make work with all three passwords
026 //TODO get images of different types
027 //TODO continue attempting to connect until succesful
028 //TODO optimize and use Pointers in all locations which make sense - possibly JNA memcpy?
029 /**
030 * This class is a singleton used to configure and get images from the axis camera.
031 * @author dtjones
032 */
033 public class AxisCamera implements ISensor {
034
035 private static AxisCamera m_instance = null;
036
037 /**
038 * Enumaration representing the different values which exposure may be set to.
039 */
040 public static class ExposureT {
041
042 /**
043 * The integer value of the enumeration.
044 */
045 public final int value;
046 static final ExposureT[] allValues = new ExposureT[4];
047 /**
048 * The Axis camera automatically determines what exposure level to use.
049 */
050 public static final ExposureT automatic = new ExposureT(0);
051 /**
052 * Hold the current exposure level.
053 */
054 public static final ExposureT hold = new ExposureT(1);
055 /**
056 * Set exposure for flicker free 50 hz.
057 */
058 public static final ExposureT flickerfree50 = new ExposureT(2);
059 /**
060 * Set exposure for flicker free 60 hz.
061 */
062 public static final ExposureT flickerfree60 = new ExposureT(3);
063
064 private ExposureT(int value) {
065 this.value = value;
066 allValues[value] = this;
067 }
068
069 private static ExposureT get(int val) {
070 return allValues[val];
071 }
072 }
073
074 /**
075 * Enumeration representing the different values which white balence may be
076 * set to.
077 */
078 public static class WhiteBalanceT {
079
080 /**
081 * The integer value of the enumeration.
082 */
083 public final int value;
084 static final WhiteBalanceT[] allValues = new WhiteBalanceT[7];
085 /**
086 * The axis camera automatically adjusts the whit balance.
087 */
088 public static final WhiteBalanceT automatic = new WhiteBalanceT(0);
089 /**
090 * Hold the current white balance.
091 */
092 public static final WhiteBalanceT hold = new WhiteBalanceT(1);
093 /**
094 * White balance for outdoors.
095 */
096 public static final WhiteBalanceT fixedOutdoor1 = new WhiteBalanceT(2);
097 /**
098 * White balance for outdoors.
099 */
100 public static final WhiteBalanceT fixedOutdoor2 = new WhiteBalanceT(3);
101 /**
102 * White balance for indoors.
103 */
104 public static final WhiteBalanceT fixedIndoor = new WhiteBalanceT(4);
105 /**
106 * White balance for fourescent lighting.
107 */
108 public static final WhiteBalanceT fixedFlour1 = new WhiteBalanceT(5);
109 /**
110 * White balance for fourescent lighting.
111 */
112 public static final WhiteBalanceT fixedFlour2 = new WhiteBalanceT(6);
113
114 private WhiteBalanceT(int value) {
115 this.value = value;
116 allValues[value] = this;
117 }
118
119 private static WhiteBalanceT get(int value) {
120 return allValues[value];
121 }
122 }
123
124 /**
125 * Enumeration representing the image resoultion provided by the camera.
126 */
127 public static class ResolutionT {
128
129 /**
130 * The integer value of the enumeration.
131 */
132 public final int value;
133 /**
134 * Number of pixels wide.
135 */
136 public final int width;
137 /**
138 * Number of pixels tall.
139 */
140 public final int height;
141 static final ResolutionT[] allValues = new ResolutionT[4];
142 /**
143 * Image is 640 pixels wide by 480 tall
144 */
145 public static final ResolutionT k640x480 = new ResolutionT(0, 640, 480);
146 /**
147 * Image is 640 pixels wide by 360 tall
148 */
149 public static final ResolutionT k640x360 = new ResolutionT(1, 640, 360);
150 /**
151 * Image is 320 pixels wide by 240 tall
152 */
153 public static final ResolutionT k320x240 = new ResolutionT(2, 320, 240);
154 /**
155 * Image is 160 pixels wide by 120 tall
156 */
157 public static final ResolutionT k160x120 = new ResolutionT(3, 160, 120);
158
159 private ResolutionT(int value, int horizontal, int vertical) {
160 this.value = value;
161 this.width = horizontal;
162 this.height = vertical;
163 allValues[value] = this;
164 }
165
166 private static ResolutionT get(int value) {
167 return allValues[value];
168 }
169 }
170
171 /**
172 * Enumeration representing the orientation of the picture.
173 */
174 public static class RotationT {
175
176 /**
177 * The integer value of the enumeration.
178 */
179 public final int value;
180 static final RotationT[] allValues = new RotationT[2];
181 /**
182 * Picture is right side up.
183 */
184 public static final RotationT k0 = new RotationT(0);
185 /**
186 * Picture is rotated 180 degrees.
187 */
188 public static final RotationT k180 = new RotationT(1);
189
190 private RotationT(int value) {
191 this.value = value;
192 allValues[value] = this;
193 }
194
195 private static RotationT get(int value) {
196 return allValues[value];
197 }
198 }
199
200 /**
201 * Enumeration representing the exposure priority.
202 */
203 public static class ExposurePriorityT {
204
205 /**
206 * The integer value of the enumeration.
207 */
208 public final int value;
209 static final ExposurePriorityT[] allValues = new ExposurePriorityT[3];
210 /**
211 * Prioritize image quality.
212 */
213 public static final ExposurePriorityT imageQuality = new ExposurePriorityT(0);
214 /**
215 * No prioritization.
216 */
217 public static final ExposurePriorityT none = new ExposurePriorityT(50);
218 /**
219 * Prioritize frame rate.
220 */
221 public static final ExposurePriorityT frameRate = new ExposurePriorityT(100);
222
223 private ExposurePriorityT(int value) {
224 this.value = value;
225 allValues[value / 50] = this;
226 }
227
228 private static ExposurePriorityT get(int value) {
229 return allValues[value / 50];
230 }
231 }
232
233 /**
234 * Get a reference to the AxisCamera, or initialize the AxisCamera if it
235 * has not yet been initialized. If the camera is connected to the
236 * Ethernet switch on the robot, then this address should be 10.x.y.11
237 * where x.y are your team number subnet address (same as the other IP
238 * addresses on the robot network).
239 * @param address A string containing the IP address for the camera in the
240 * form "10.x.y.2" for cameras on the Ethernet switch or "192.168.0.90"
241 * for cameras connected to the 2nd Ethernet port on an 8-slot cRIO.
242 * @return A reference to the AxisCamera.
243 */
244 public static synchronized AxisCamera getInstance(String address) {
245 if (m_instance == null) {
246 m_instance = new AxisCamera(address);
247 UsageReporting.report(UsageReporting.kResourceType_AxisCamera, 2);
248 }
249 return m_instance;
250 }
251
252 /**
253 * Get a reference to the AxisCamera, or initialize the AxisCamera if it
254 * has not yet been initialized. By default this will connect to a camera
255 * with an IP address of 10.x.y.11 with the preference that the camera be
256 * connected to the Ethernet switch on the robot rather than port 2 of the
257 * 8-slot cRIO.
258 * @return A reference to the AxisCamera.
259 */
260 public static synchronized AxisCamera getInstance() {
261 if (m_instance == null) {
262 DriverStation.getInstance().waitForData();
263 int teamNumber = DriverStation.getInstance().getTeamNumber();
264 String address = "10."+(teamNumber/100)+"."+(teamNumber%100)+".11";
265 m_instance = new AxisCamera(address);
266 UsageReporting.report(UsageReporting.kResourceType_AxisCamera, 1);
267 }
268
269 return m_instance;
270 }
271 private static final Function cameraStartFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraStart");
272
273 /**
274 * Axis camera constructor that calls the C++ library to actually create the instance.
275 * @param IPAddress
276 */
277 AxisCamera(String IPAddress) {
278 Pointer ptr = Pointer.createStringBuffer(IPAddress);
279 cameraStartFn.call1(ptr);
280 }
281 private static final TaskExecutor cameraTaskExecutor = new TaskExecutor("camera task executor");
282 private static final BlockingFunction getImageFn = NativeLibrary.getDefaultInstance().getBlockingFunction("AxisCameraGetImage");
283
284 static {
285 getImageFn.setTaskExecutor(cameraTaskExecutor);
286 }
287
288 /**
289 * Get an image from the camera. Be sure to free the image when you are done with it.
290 * @return A new image from the camera.
291 */
292 public ColorImage getImage() throws AxisCameraException, NIVisionException {
293 ColorImage image = new HSLImage();
294 if (getImageFn.call1(image.image) == 0) {
295 image.free();
296 throw new AxisCameraException("No image available");
297 }
298 return image;
299 }
300 // Mid-stream gets & writes
301 private static final Function writeBrightnessFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteBrightness");
302
303 /**
304 * Write the brightness for the camera to use.
305 * @param brightness This must be an integer between 0 and 100, with 100 being the brightest
306 */
307 public void writeBrightness(int brightness) {
308 BoundaryException.assertWithinBounds(brightness, 0, 100);
309 writeBrightnessFn.call1(brightness);
310 }
311 private static final Function getBrightnessFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetBrightness");
312
313 /**
314 * Get the current brightness of the AxisCamera
315 * @return An integer representing the current brightness of the axis
316 * camera with 0 being the darkest and 100 being the brightest.
317 */
318 public int getBrightness() {
319 return getBrightnessFn.call0();
320 }
321 private static final Function writeWhiteBalenceFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteWhiteBalance");
322
323 /**
324 * Write the WhiteBalance for the camera to use.
325 * @param whiteBalance The value to set the white balance to on the camera.
326 */
327 public void writeWhiteBalance(WhiteBalanceT whiteBalance) {
328 writeWhiteBalenceFn.call1(whiteBalance.value);
329 }
330 private static final Function getWhiteBalanceFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetWhiteBalance");
331
332 /**
333 * Get the white balance set on the camera.
334 * @return The white balance currently set on the camera.
335 */
336 public WhiteBalanceT getWhiteBalance() {
337 return WhiteBalanceT.get(getWhiteBalanceFn.call0());
338 }
339 private static final Function writeColorLevelFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteColorLevel");
340
341 /**
342 * Set the color level of images returned from the camera.
343 * @param value This must be an integer from 0 to 100 with 0 being black and white.
344 */
345 public void writeColorLevel(int value) {
346 BoundaryException.assertWithinBounds(value, 0, 100);
347 writeColorLevelFn.call1(value);
348 }
349 private static final Function getColorLevelFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetColorLevel");
350
351 /**
352 * Get the color level of images being retunred from the camera.
353 * @return The color level of images being returned from the camera. 0 is black and white.
354 */
355 public int getColorLevel() {
356 return getColorLevelFn.call0();
357 }
358 private static final Function writeExposureControlFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteExposureControl");
359
360 /**
361 * Write the exposure mode for the camera to use.
362 * @param value The expsure mode for the camera to use.
363 */
364 public void writeExposureControl(ExposureT value) {
365 writeExposureControlFn.call1(value.value);
366 }
367 private static final Function getExposureControlFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetExposureControl");
368
369 /**
370 * Get the exposure mode that the camera is using.
371 * @return The exposure mode that the camera is using.
372 */
373 public ExposureT getExposureControl() {
374 return ExposureT.get(getExposureControlFn.call0());
375 }
376 private static final Function writeExposurePriorityFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteExposurePriority");
377
378 /**
379 * Write the exposure priority for the camera to use.
380 * @param value The exposure priority to use.
381 */
382 public void writeExposurePriority(ExposurePriorityT value) {
383 writeExposurePriorityFn.call1(value.value);
384 }
385 private static final Function getExposurePriorityFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetExposurePriority");
386
387 /**
388 * Get the exposure priority that the camera is using.
389 * @return The exposure priority that the camera is using
390 */
391 public ExposurePriorityT getExposurePriority() {
392 return ExposurePriorityT.get(getExposurePriorityFn.call0());
393 }
394 // New-Stream gets & writes
395 private static final Function writeResolutionFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteResolution");
396
397 /**
398 * Set the resolution of the images to return.
399 * @param value The resolution imaga for the camera to return.
400 */
401 public void writeResolution(ResolutionT value) {
402 writeResolutionFn.call1(value.value);
403 }
404 private static final Function getResolutionFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetResolution");
405
406 /**
407 * Get the resolution fo the images that the camera is returning.
408 * @return The resolution of the images that the camera is returning.
409 */
410 public ResolutionT getResolution() {
411 return ResolutionT.get(getResolutionFn.call0());
412 }
413 private static final Function writeCompressionFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteCompression");
414
415 /**
416 * Write the level of JPEG compression to use on images returned from the camera.
417 * @param value The level of JPEG compression to use from 0 to 100 with 0 being the least compression.
418 */
419 public void writeCompression(int value) {
420 BoundaryException.assertWithinBounds(value, 0, 100);
421 writeCompressionFn.call1(value);
422 }
423 private static final Function getCompressionFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetCompression");
424
425 /**
426 * Get the compression of the images eing returned by the camera.
427 * @return The level of compression of the image being returned from the
428 * camera with 0 being the least and 100 being the greatest.
429 */
430 public int getCompression() {
431 return getCompressionFn.call0();
432 }
433 private static final Function writeRotationFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteRotation");
434
435 /**
436 * Write the rotation of images for the camera to return.
437 * @param value The rotation to be applied to images from the camera.
438 */
439 public void writeRotation(RotationT value) {
440 writeRotationFn.call1(value.value);
441 }
442 private static final Function getRotationFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetRotation");
443
444 /**
445 * Get the rotation of the images returned from the camera.
446 * @return The rotation of the images returned from the camera.
447 */
448 public RotationT getRotation() {
449 return RotationT.get(getRotationFn.call0());
450 }
451 private static final Function freshImageFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraFreshImage");
452
453 /**
454 * Has the current image from the camera been retrieved yet.
455 * @return true if the latest image from the camera has not been retrieved yet.
456 */
457 public boolean freshImage() {
458 return freshImageFn.call0() == 0 ? false : true;
459 }
460 private static final Function getMaxFPSFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetMaxFPS");
461
462 /**
463 * Get the maximum frames per second that the camera will generate.
464 * @return the max fps.
465 */
466 public int getMaxFPS() {
467 return getMaxFPSFn.call0();
468 }
469 private static final Function writeMaxFPSFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteMaxFPS");
470
471 /**
472 * Set the maximum frames per second that the camera will generate.
473 * @param value the new max fps
474 */
475 public void writeMaxFPS(int value) {
476 writeMaxFPSFn.call1(value);
477 }
478 private static final Function deleteInstanceFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraDeleteInstance");
479
480 static {
481 VM.addShutdownHook(new Thread() {
482
483 public void run() {
484 deleteInstanceFn.call0();
485 }
486 });
487 }
488 }