00001 #include <asm/types.h>
00002 #include <sys/types.h>
00003 #include <sys/syscall.h>
00004 #include <sys/prctl.h>
00005 #include <linux/capability.h>
00006
00007 #include <pthread.h>
00008 #include <poll.h>
00009
00010 #include <stdio.h>
00011 #include <stdlib.h>
00012 #include <string.h>
00013 #include <unistd.h>
00014 #include <math.h>
00015
00016 #include <sys/fcntl.h>
00017 #include <sys/ioctl.h>
00018 #include <sys/mman.h>
00019 #include <sys/time.h>
00020 #include <time.h>
00021
00022 #include <errno.h>
00023 #include <malloc.h>
00024 #include <linux/videodev2.h>
00025
00026 #include "../Debug.h"
00027 #include "FCam/Event.h"
00028 #include "V4L2Sensor.h"
00029 #warning make sure to point isp_user to the right place before long!
00030 #include "/elphel/git/linux-omap-2.6/drivers/media/video/isp/isp_user.h"
00031
00032
00033
00034 namespace FCam { namespace F2 {
00035
00036 V4L2Sensor *V4L2Sensor::instance(std::string fname) {
00037 std::map<std::string, V4L2Sensor *>::iterator i;
00038 i = instances_.find(fname);
00039 if (i == instances_.end()) {
00040 instances_[fname] = new V4L2Sensor(fname);
00041 }
00042
00043 return instances_[fname];
00044 };
00045
00046 V4L2Sensor::V4L2Sensor(std::string fname) : state(CLOSED), filename(fname) {
00047
00048 }
00049
00050 std::map<std::string, V4L2Sensor *> V4L2Sensor::instances_;
00051
00052 void V4L2Sensor::open() {
00053 if (state != CLOSED) {
00054 printf("Sensor is already open!\n");
00055 return;
00056 }
00057
00058 fd = ::open(filename.c_str(), O_RDWR | O_NONBLOCK, 0);
00059
00060 if (fd < 0) {
00061 error(Event::DriverError,"V4L2Sensor: Error opening device %s: %s", filename.c_str(), strerror(errno));
00062 return;
00063 }
00064
00065 state = IDLE;
00066 }
00067
00068 void V4L2Sensor::close() {
00069 switch(state) {
00070 case STREAMING:
00071 stopStreaming();
00072 case IDLE:
00073 ::close(fd);
00074 case CLOSED:
00075 break;
00076 }
00077 state = CLOSED;
00078 }
00079
00080 int V4L2Sensor::getFD() {
00081 if (state == CLOSED) {
00082 return -1;
00083 }
00084 return fd;
00085 }
00086
00087 void V4L2Sensor::startStreaming(Mode m,
00088 const HistogramConfig &histogram,
00089 const SharpnessMapConfig &sharpness) {
00090
00091 if (state != IDLE) {
00092 printf("Can only initiate streaming if sensor is idle\n");
00093 return;
00094 }
00095
00096 struct v4l2_format fmt;
00097
00098 memset(&fmt, 0, sizeof(struct v4l2_format));
00099
00100 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00101 fmt.fmt.pix.width = m.width;
00102 fmt.fmt.pix.height = m.height;
00103 if (m.type == UYVY) {
00104 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
00105 } else if (m.type == RAW) {
00106 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SGRBG10;
00107 } else {
00108 error(Event::InternalError, "V4L2Sensor: Unknown image format requested");
00109 return;
00110 }
00111 fmt.fmt.pix.field = V4L2_FIELD_NONE;
00112
00113
00114 if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) {
00115 error(Event::DriverError,"VIDIOC_S_FMT: %s", strerror(errno));
00116 return;
00117 }
00118
00119 currentMode.width = fmt.fmt.pix.width;
00120 currentMode.height = fmt.fmt.pix.height;
00121 currentMode.type = (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) ? UYVY : RAW;
00122
00123 struct v4l2_requestbuffers req;
00124 memset(&req, 0, sizeof(req));
00125 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00126 req.memory = V4L2_MEMORY_MMAP;
00127 req.count = 8;
00128
00129 if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0) {
00130 error(Event::DriverError,"VIDIOC_REQBUFS: %s", strerror(errno));
00131 return;
00132 }
00133
00134 buffers.resize(req.count);
00135
00136 for (size_t i = 0; i < buffers.size(); i++) {
00137 v4l2_buffer buf;
00138 memset(&buf, 0, sizeof(v4l2_buffer));
00139 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00140 buf.memory = V4L2_MEMORY_MMAP;
00141 buf.index = i;
00142
00143 if (ioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) {
00144 error(Event::DriverError,"VIDIOC_QUERYBUF: %s", strerror(errno));
00145 return;
00146 }
00147
00148 buffers[i].index = i;
00149 buffers[i].length = buf.length;
00150 buffers[i].data =
00151 (unsigned char *)mmap(NULL, buffers[i].length, PROT_READ | PROT_WRITE,
00152 MAP_SHARED, fd, buf.m.offset);
00153
00154 if (buffers[i].data == MAP_FAILED) {
00155 error(Event::InternalError, "V4L2Sensor: mmap failed: %s", strerror(errno));
00156 return;
00157 }
00158 }
00159
00160 for (size_t i = 0; i < buffers.size(); i++) {
00161 releaseFrame(&buffers[i]);
00162 }
00163
00164
00165 setHistogramConfig(histogram);
00166 setSharpnessMapConfig(sharpness);
00167
00168 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00169 if (ioctl(fd, VIDIOC_STREAMON, &type) < 0) {
00170 error(Event::DriverError,"VIDIOC_STREAMON: %s", strerror(errno));
00171 return;
00172 }
00173
00174 dprintf(DBG_MAJOR, "Sensor now streaming\n");
00175 state = STREAMING;
00176 }
00177
00178
00179 void V4L2Sensor::stopStreaming() {
00180 if (state != STREAMING) {
00181 printf("Camera is already not streaming!\n");
00182 return;
00183 }
00184
00185 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00186 if (ioctl(fd, VIDIOC_STREAMOFF, &type) < 0) {
00187 error(Event::DriverError,"VIDIOC_STREAMOFF: %s", strerror(errno));
00188 return;
00189 }
00190
00191 for (size_t i = 0; i < buffers.size(); i++) {
00192 if (munmap(buffers[i].data, buffers[i].length)) {
00193 error(Event::InternalError, "V4L2Sensor: munmap failed: %s", strerror(errno));
00194 }
00195 }
00196
00197 state = IDLE;
00198 }
00199
00200
00201
00202 V4L2Sensor::V4L2Frame *V4L2Sensor::acquireFrame(bool blocking) {
00203 if (state != STREAMING) {
00204 printf("Can't acquire a frame when not streaming!\n");
00205 return NULL;
00206 }
00207
00208
00209
00210 v4l2_buffer buf;
00211 memset(&buf, 0, sizeof(v4l2_buffer));
00212 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00213 buf.memory = V4L2_MEMORY_MMAP;
00214
00215 if (blocking) {
00216 struct pollfd p = {fd, POLLIN, 0};
00217 poll(&p, 1, -1);
00218 if (!(p.revents & POLLIN)) {
00219 error(Event::DriverError,"Poll returned without data being available: %s", strerror(errno));
00220 return NULL;
00221 }
00222 }
00223
00224 if (ioctl(fd, VIDIOC_DQBUF, &buf) < 0) {
00225 if (errno == EAGAIN && !blocking) {
00226 return NULL;
00227 }
00228
00229 error(Event::DriverError,"VIDIOC_DQBUF: %s", strerror(errno));
00230 return NULL;
00231 }
00232
00233
00234 buffers[buf.index].processingDoneTime = Time(buf.timestamp);
00235 return &(buffers[buf.index]);
00236 }
00237
00238
00239
00240 Histogram V4L2Sensor::getHistogram(Time t, const HistogramConfig &conf) {
00241
00242
00243 if (!conf.enabled) {
00244 return Histogram();
00245 }
00246
00247
00248 struct isp_hist_data hist_data;
00249 unsigned buf[64 * 4];
00250 Time h;
00251 int tries = 3;
00252 while (--tries > 0) {
00253 hist_data.hist_statistics_buf = buf;
00254 hist_data.update = REQUEST_STATISTICS;
00255
00256
00257
00258 hist_data.frame_number = NEWEST_FRAME;
00259 hist_data.curr_frame = 0;
00260 hist_data.config_counter = 0;
00261 hist_data.ts.tv_sec = 0;
00262 hist_data.ts.tv_usec = 0;
00263
00264 if (ioctl(fd, VIDIOC_PRIVATE_ISP_HIST_REQ, &hist_data)) {
00265 error(Event::DriverError, "V4L2Sensor::getHistogram: VIDIOC_PRIVATE_ISP_HIST_REQ: %s\n",strerror(errno));
00266 return Histogram();
00267 }
00268
00269
00270
00271 h = Time(hist_data.ts);
00272
00273 if ((t - h) < 6000) {
00274 break;
00275 }
00276 usleep(10000);
00277 }
00278 if (tries != 2) dprintf(DBG_MINOR, "V4L2Sensor::getHistogram: Waited for the histogram %d times\n", 2-tries);
00279 if (!tries) {
00280 error(Event::DriverError, "Histogram cannot be found\n");
00281 return Histogram();
00282 }
00283
00284 while ((t-h) < -4000) {
00285
00286 if (hist_data.frame_number == 0) hist_data.frame_number = 4095;
00287 else hist_data.frame_number--;
00288
00289 if (ioctl(fd, VIDIOC_PRIVATE_ISP_HIST_REQ, &hist_data)) {
00290 error(Event::DriverError, "V4L2Sensor::getHistogram: VIDIOC_PRIVATE_ISP_HIST_REQ: %s\n", strerror(errno));
00291 return Histogram();
00292 }
00293
00294 h = Time(hist_data.ts);
00295 }
00296 Histogram hist(64, 3, conf.region);
00297 for (int i = 0; i < 64; i++) {
00298 hist(i, 0) = buf[64 + i];
00299 hist(i, 1) = buf[i];
00300 hist(i, 2) = buf[128 + i];
00301 }
00302 return hist;
00303 }
00304
00305 SharpnessMap V4L2Sensor::getSharpnessMap(Time t, const SharpnessMapConfig &conf) {
00306 if (!conf.enabled) {
00307 return SharpnessMap();
00308 }
00309
00310
00311 struct isp_af_data af_data;
00312 af_data.frame_number = NEWEST_FRAME;
00313 af_data.update = REQUEST_STATISTICS;
00314 af_data.curr_frame = 0;
00315 af_data.config_counter = 0;
00316 af_data.xtrastats.ts.tv_sec = 0;
00317 af_data.xtrastats.ts.tv_usec = 0;
00318 unsigned buf[16*12*12];
00319 af_data.af_statistics_buf = buf;
00320
00321 if (ioctl(fd, VIDIOC_PRIVATE_ISP_AF_REQ, &af_data)) {
00322 error(Event::DriverError, "V4L2Sensor::getSharpnessMap: VIDIOC_PRIVATE_ISP_AF_REQ: %s\n", strerror(errno) );
00323 return SharpnessMap();
00324 }
00325
00326 Time s(af_data.xtrastats.ts);
00327 if ((t - s) > 6000) {
00328 warning(Event::DriverError, "Missing sharpness: (%d)\n", t-s );
00329 }
00330
00331 while ((t-s) < -2000) {
00332
00333 if (af_data.frame_number == 0) af_data.frame_number = 4095;
00334 else af_data.frame_number--;
00335
00336 if (ioctl(fd, VIDIOC_PRIVATE_ISP_AF_REQ, &af_data)) {
00337 error(Event::DriverError, "V4L2Sensor::getSharpnessMap: VIDIOC_PRIVATE_ISP_AF_REQ: %s\n", strerror(errno) );
00338 return SharpnessMap();
00339 }
00340 s = Time(af_data.xtrastats.ts);
00341 }
00342 SharpnessMap m(Size(16,12), 3);
00343 unsigned *bufPtr = &buf[0];
00344 for (int y = 0; y < m.size().height; y++) {
00345 for (int x = 0; x < m.size().width; x++) {
00346 m(x, y, 0) = bufPtr[1];
00347 m(x, y, 1) = bufPtr[5];
00348 m(x, y, 2) = bufPtr[9];
00349 bufPtr += 12;
00350 }
00351 }
00352
00353 return m;
00354 }
00355
00356 void V4L2Sensor::setHistogramConfig(const HistogramConfig &histogram) {
00357 if (!histogram.enabled) return;
00358
00359
00360 isp_pipeline_stats pstats;
00361 if (ioctl(fd, VIDIOC_PRIVATE_ISP_PIPELINE_STATS_REQ, &pstats) < 0) {
00362 error(Event::DriverError, "V4L2Sensor::setHistogramConfig: VIDIOC_PRIVATE_ISP_PIPELINE_STATS_REQ: %s\n", strerror(errno));
00363 return;
00364 }
00365
00366 dprintf(4, "CCDC output: %d x %d\n", pstats.ccdc_out_w, pstats.ccdc_out_h);
00367 dprintf(4, "PRV output: %d x %d\n", pstats.prv_out_w, pstats.prv_out_h);
00368 dprintf(4, "RSZ input: %d x %d + %d, %d\n",
00369 pstats.rsz_in_w, pstats.rsz_in_h,
00370 pstats.rsz_in_x, pstats.rsz_in_y);
00371 dprintf(4, "RSZ output: %d x %d\n", pstats.rsz_out_w, pstats.rsz_out_h);
00372
00373 struct isp_hist_config hist_cfg;
00374 hist_cfg.enable = 1;
00375 hist_cfg.source = HIST_SOURCE_CCDC;
00376 hist_cfg.input_bit_width = 10;
00377 hist_cfg.num_acc_frames = 1;
00378 hist_cfg.hist_bins = HIST_BINS_64;
00379 hist_cfg.cfa = HIST_CFA_BAYER;
00380
00381
00382
00383
00384 hist_cfg.wg[0] = 35;
00385 hist_cfg.wg[1] = 35;
00386 hist_cfg.wg[2] = 35;
00387 hist_cfg.wg[3] = 35;
00388 hist_cfg.num_regions = 1;
00389
00390
00391 unsigned x = ((unsigned)histogram.region.x * pstats.ccdc_out_w) / currentMode.width;
00392 unsigned y = ((unsigned)histogram.region.y * pstats.ccdc_out_h) / currentMode.height;
00393 unsigned w = ((unsigned)histogram.region.width * pstats.ccdc_out_w) / currentMode.width;
00394 unsigned h = ((unsigned)histogram.region.height * pstats.ccdc_out_h) / currentMode.height;
00395 if (x > pstats.ccdc_out_w) x = pstats.ccdc_out_w-1;
00396 if (y > pstats.ccdc_out_h) y = pstats.ccdc_out_h-1;
00397 if (w > pstats.ccdc_out_w) w = pstats.ccdc_out_w-x;
00398 if (h > pstats.ccdc_out_h) h = pstats.ccdc_out_h-y;
00399 hist_cfg.reg_hor[0] = (x << 16) | w;
00400 hist_cfg.reg_ver[0] = (y << 16) | h;
00401 dprintf(4, "Histogram size: %d x %d + %d, %d\n", w, h, x, y);
00402
00403 dprintf(DBG_MINOR, "Enabling histogram generator\n");
00404
00405 if (ioctl(fd, VIDIOC_PRIVATE_ISP_HIST_CFG, &hist_cfg)) {
00406 error(Event::DriverError, "VIDIOC_PRIVATE_ISP_HIST_CFG: %s", strerror(errno));
00407 return;
00408 }
00409
00410 currentHistogram = histogram;
00411 currentHistogram.buckets = 64;
00412 }
00413
00414 void V4L2Sensor::setSharpnessMapConfig(const SharpnessMapConfig &sharpness) {
00415 if (!sharpness.enabled) return;
00416
00417
00418 Size size = Size(16, 12);
00419
00420
00421 isp_pipeline_stats pstats;
00422 if (ioctl(fd, VIDIOC_PRIVATE_ISP_PIPELINE_STATS_REQ, &pstats) < 0) {
00423 error(Event::DriverError, "VIDIOC_PRIVATE_ISP_PIPELINE_STATS_REQ: %s", strerror(errno));
00424 return;
00425 }
00426
00427 struct af_configuration af_config;
00428
00429 af_config.alaw_enable = H3A_AF_ALAW_DISABLE;
00430 af_config.hmf_config.enable = H3A_AF_HMF_ENABLE;
00431 af_config.hmf_config.threshold = 10;
00432 af_config.rgb_pos = RG_GB_BAYER;
00433 af_config.iir_config.hz_start_pos = 0;
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448 af_config.iir_config.coeff_set0[0] = 32;
00449
00450 af_config.iir_config.coeff_set0[1] = 4096-27;
00451 af_config.iir_config.coeff_set0[2] = 6;
00452
00453 af_config.iir_config.coeff_set0[3] = 16;
00454 af_config.iir_config.coeff_set0[4] = 4096-32;
00455 af_config.iir_config.coeff_set0[5] = 16;
00456
00457 af_config.iir_config.coeff_set0[6] = 0;
00458 af_config.iir_config.coeff_set0[7] = 0;
00459
00460 af_config.iir_config.coeff_set0[8] = 32;
00461 af_config.iir_config.coeff_set0[9] = 0;
00462 af_config.iir_config.coeff_set0[10] = 0;
00463
00464
00465
00466 af_config.iir_config.coeff_set1[0] = 32;
00467
00468 af_config.iir_config.coeff_set1[1] = 0;
00469 af_config.iir_config.coeff_set1[2] = 0;
00470
00471 af_config.iir_config.coeff_set1[3] = 16;
00472 af_config.iir_config.coeff_set1[4] = 4096-32;
00473 af_config.iir_config.coeff_set1[5] = 16;
00474
00475 af_config.iir_config.coeff_set1[6] = 0;
00476 af_config.iir_config.coeff_set1[7] = 0;
00477
00478 af_config.iir_config.coeff_set1[8] = 32;
00479 af_config.iir_config.coeff_set1[9] = 0;
00480 af_config.iir_config.coeff_set1[10] = 0;
00481
00482 af_config.mode = ACCUMULATOR_SUMMED;
00483 af_config.af_config = H3A_AF_CFG_ENABLE;
00484 int paxWidth = ((pstats.ccdc_out_w-4) / (2*size.width))*2;
00485 int paxHeight = ((pstats.ccdc_out_h-4) / (2*size.height))*2;
00486
00487 if (paxWidth > 256) {
00488 error(Event::InternalError, "AF paxels are too wide. Use a higher resolution sharpness map\n");
00489 return;
00490 }
00491 if (paxHeight > 256) {
00492 error(Event::InternalError, "AF paxels are too tall. Use a higher resolution sharpness map\n");
00493 return;
00494 }
00495 if (paxWidth < 16) {
00496 error(Event::InternalError, "AF paxels are too narrow. Use a lower resolution sharpness map\n");
00497 return;
00498 }
00499 if (paxHeight < 2) {
00500 error(Event::InternalError, "AF paxels are too short. Use a lower resolution sharpness map\n");
00501 return;
00502 }
00503
00504 dprintf(4, "V4L2Sensor::setSharpnessMapConfig: Using %d x %d paxels for af\n", paxWidth, paxHeight);
00505 af_config.paxel_config.width = (paxWidth-2)/2;
00506 af_config.paxel_config.height = (paxHeight-2)/2;
00507 af_config.paxel_config.hz_start = (pstats.ccdc_out_w - size.width * paxWidth)/2;
00508 af_config.paxel_config.vt_start = (pstats.ccdc_out_h - size.height * paxHeight)/2;
00509 af_config.paxel_config.hz_cnt = size.width-1;
00510 af_config.paxel_config.vt_cnt = size.height-1;
00511 af_config.paxel_config.line_incr = 0;
00512
00513 dprintf(DBG_MINOR, "Enabling sharpness detector\n");
00514 if (ioctl(fd, VIDIOC_PRIVATE_ISP_AF_CFG, &af_config)) {
00515 error(Event::DriverError, "VIDIOC_PRIVATE_ISP_AF_CFG: %s", strerror(errno));
00516 return;
00517 }
00518
00519 currentSharpness = sharpness;
00520 }
00521
00522 void V4L2Sensor::releaseFrame(V4L2Frame *frame) {
00523
00524
00525
00526
00527
00528 v4l2_buffer buf;
00529 memset(&buf, 0, sizeof(v4l2_buffer));
00530 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00531 buf.memory = V4L2_MEMORY_MMAP;
00532 buf.index = frame->index;
00533
00534 if (ioctl(fd, VIDIOC_QBUF, &buf) < 0) {
00535 error(Event::DriverError, "VIDIOC_QBUF: %s", strerror(errno));
00536 return;
00537 }
00538 }
00539
00540 void V4L2Sensor::setControl(unsigned int id, int value) {
00541 if (state == CLOSED) return;
00542 v4l2_control ctrl;
00543 ctrl.id = id;
00544 ctrl.value = value;
00545 if (ioctl(fd, VIDIOC_S_CTRL, &ctrl) < 0) {
00546
00547 error(Event::DriverError, "VIDIOC_S_CTRL: %s", strerror(errno));
00548 return;
00549 }
00550 }
00551
00552 int V4L2Sensor::getControl(unsigned int id) {
00553 if (state == CLOSED) return -1;
00554 v4l2_control ctrl;
00555 ctrl.id = id;
00556 if (ioctl(fd, VIDIOC_G_CTRL, &ctrl) < 0) {
00557 error(Event::DriverError, "VIDIOC_G_CTRL: %s", strerror(errno));
00558 return -1;
00559 }
00560
00561 return ctrl.value;
00562 }
00563
00564 void V4L2Sensor::setExposure(int e) {
00565 if (state == CLOSED) return;
00566
00567 struct v4l2_control ctrl;
00568 ctrl.id = V4L2_CID_EXPOSURE;
00569 ctrl.value = e;
00570 if (ioctl(fd, VIDIOC_S_CTRL, &ctrl) < 0) {
00571 error(Event::DriverError,"VIDIOC_S_CTRL: %s", strerror(errno));
00572 return;
00573 }
00574
00575 }
00576
00577 int V4L2Sensor::getExposure() {
00578 if (state == CLOSED) return -1;
00579
00580 struct v4l2_control ctrl;
00581 ctrl.id = V4L2_CID_EXPOSURE;
00582
00583 if (ioctl(fd, VIDIOC_G_CTRL, &ctrl) < 0) {
00584 error(Event::DriverError,"VIDIOC_G_CTRL: %s", strerror(errno));
00585 return -1;
00586 }
00587
00588 return ctrl.value;
00589 }
00590
00591 #define V4L2_CID_FRAME_TIME (V4L2_CTRL_CLASS_CAMERA | 0x10ff)
00592
00593 void V4L2Sensor::setFrameTime(int e) {
00594 if (state == CLOSED) return;
00595
00596 struct v4l2_control ctrl;
00597 ctrl.id = V4L2_CID_FRAME_TIME;
00598 ctrl.value = e;
00599 if (ioctl(fd, VIDIOC_S_CTRL, &ctrl) < 0) {
00600 error(Event::DriverError,"VIDIOC_S_CTRL: %s", strerror(errno));
00601 return;
00602 }
00603 }
00604
00605 int V4L2Sensor::getFrameTime() {
00606 if (state == CLOSED) return -1;
00607
00608 struct v4l2_control ctrl;
00609 ctrl.id = V4L2_CID_FRAME_TIME;
00610
00611 if (ioctl(fd, VIDIOC_G_CTRL, &ctrl) < 0) {
00612 error(Event::DriverError,"VIDIOC_G_CTRL: %s", strerror(errno));
00613 return -1;
00614 }
00615
00616 return ctrl.value;
00617 }
00618
00619 void V4L2Sensor::setGain(float g) {
00620 if (state == CLOSED) return;
00621
00622 unsigned int gain;
00623 struct v4l2_control ctrl;
00624
00625 gain = (int)(g * 32.0 + 0.5);
00626
00627 ctrl.id = V4L2_CID_GAIN;
00628 ctrl.value = gain;
00629 if (ioctl(fd, VIDIOC_S_CTRL, &ctrl) < 0) {
00630 error(Event::DriverError,"VIDIOC_S_CTRL: %s", strerror(errno));
00631 return;
00632 }
00633 }
00634
00635 float V4L2Sensor::getGain() {
00636 if (state == CLOSED) return -1.0f;
00637
00638 struct v4l2_control ctrl;
00639
00640 ctrl.id = V4L2_CID_GAIN;
00641 if (ioctl(fd, VIDIOC_G_CTRL, &ctrl) < 0) {
00642 error(Event::DriverError,"VIDIOC_G_CTRL: %s", strerror(errno));
00643 return -1.0f;
00644 }
00645
00646 return ctrl.value / 32.0f;
00647 }
00648 }}
00649
00650