55#include < cstring>
66#include < errno.h>
77#include < vector>
8+ #include < numeric>
89#include < sys/ioctl.h>
910#include < linux/usb/video.h>
1011#include < linux/uvcvideo.h>
@@ -21,6 +22,18 @@ using namespace std;
2122#include " logger.hpp"
2223#include " camera.hpp"
2324
25+ int array_gcd (const uint8_t *arr, uint16_t size)
26+ {
27+ int result = arr[0 ];
28+ for (int i = 1 ; i < size; ++i)
29+ {
30+ result = gcd (arr[i], result);
31+ if (result == 1 )
32+ return 1 ;
33+ }
34+ return result;
35+ }
36+
2437/* *
2538 * @brief Obtain the id of any device path
2639 *
@@ -264,21 +277,51 @@ void CameraInstruction::logDebugCtrl(string prefixMsg, const uint8_t *control, c
264277}
265278
266279/* *
267- * @brief We remarked that sometimes the min instruction provided by the camera is not consistent
268- * i.e. its patern does not look right when compared to the current or max control.
280+ * @brief Compute the resolution control instruction composed of 0 or 1
281+ * by comparing two controls instruction
282+ * we assume isReachable(first, res, second, size) is true
269283 *
270- * @return false if minCtrl is nullptr or not coherent, otherwise true
284+ * @param first the first instruction
285+ * @param second the second instruction
286+ * @param res the resolution instruction will be stored in it
287+ * @param size of the instructions
271288 */
272- bool CameraInstruction::isMinConsistent ( ) noexcept
289+ void CameraInstruction::computeResCtrl ( const uint8_t *first, const uint8_t *second, uint8_t *res, const uint16_t size ) noexcept
273290{
274- if (minCtrl == nullptr )
275- return false ;
291+ int secondGcd = array_gcd (second, size);
276292
277- for (unsigned i = 0 ; i < ctrlSize; ++i)
278- if (minCtrl[i] > curCtrl[i] || minCtrl[i] > maxCtrl[i])
279- return false ;
293+ if (secondGcd > 1 )
294+ for (unsigned i = 0 ; i < size; ++i)
295+ res[i] = (second[i] - first[i]) / secondGcd;
296+ else
297+ for (unsigned i = 0 ; i < size; ++i)
298+ res[i] = (uint8_t )second[i] != first[i];
299+ }
280300
281- return true ;
301+ /* *
302+ * @brief Check if a resolution control allow to reach a control from another
303+ *
304+ * @param base instruction from which the resolution must be added
305+ * @param res the resolution control
306+ * @param toReach the instruction to reach
307+ * @param size of the instructions
308+ * @return true if reacheable, otherwise false
309+ */
310+ bool CameraInstruction::isReachable (const uint8_t *base, const uint8_t *res, const uint8_t *toReach, const uint16_t size) noexcept
311+ {
312+ int it = 256 ;
313+ for (unsigned i = 0 ; i < size; ++i)
314+ {
315+ if (res[i] != 0 )
316+ {
317+ int newit = (toReach[i] - base[i]) / res[i]; // # iterations required for that value
318+ if (newit < 0 || (newit != it && it != 256 )) // negative iteration or not all value have the same # iterations
319+ return false ;
320+ it = newit;
321+ }
322+ }
323+
324+ return it != 256 ;
282325}
283326
284327/* *
@@ -301,35 +344,55 @@ CameraInstruction::CameraInstruction(Camera &camera, uint8_t unit, uint8_t selec
301344
302345 // get the current control value
303346 curCtrl = new uint8_t [ctrlSize];
304- if (camera.getUvcQuery (UVC_GET_CUR, unit, selector, ctrlSize, curCtrl))
347+ if (camera.getUvcQuery (UVC_GET_CUR, unit, selector, ctrlSize, curCtrl) == 1 )
348+ throw CameraInstructionException (camera.device , unit, selector);
349+
350+ // ensure the control can be modified
351+ if (camera.setUvcQuery (unit, selector, ctrlSize, curCtrl) == 1 )
305352 throw CameraInstructionException (camera.device , unit, selector);
306- logDebugCtrl (" current:" , curCtrl, ctrlSize);
307353
308354 // try to get the maximum control value (it does not necessary exists)
309355 maxCtrl = new uint8_t [ctrlSize];
310- if (camera.getUvcQuery (UVC_GET_MAX, unit, selector, ctrlSize, maxCtrl))
311- memset (maxCtrl, 255 , ctrlSize * sizeof (uint8_t )); // use the 255 array
312- logDebugCtrl (" maximum:" , maxCtrl, ctrlSize);
356+ if (camera.getUvcQuery (UVC_GET_MAX, unit, selector, ctrlSize, maxCtrl) == 1 )
357+ throw CameraInstructionException (camera.device , unit, selector);
313358
314359 // try get the minimum control value (it does not necessary exists)
315360 minCtrl = new uint8_t [ctrlSize];
316- if (camera.getUvcQuery (UVC_GET_MIN, unit, selector, ctrlSize, minCtrl))
317- logDebugCtrl (" minimum:" , minCtrl, ctrlSize);
318- else
361+ if (camera.getUvcQuery (UVC_GET_MIN, unit, selector, ctrlSize, minCtrl) == 1 )
319362 {
320363 delete[] minCtrl;
321364 minCtrl = nullptr ;
322365 }
323366
324367 // try to get the resolution control value (it does not necessary exists)
368+ // and check if it is consistent
325369 resCtrl = new uint8_t [ctrlSize];
326- if (camera.getUvcQuery (UVC_GET_RES, unit, selector, ctrlSize, resCtrl))
370+ if (camera.getUvcQuery (UVC_GET_RES, unit, selector, ctrlSize, resCtrl) == 1 ||
371+ !isReachable (curCtrl, resCtrl, maxCtrl, ctrlSize))
327372 {
328373 Logger::debug (" Computing the resolution control." );
329- for (unsigned i = 0 ; i < ctrlSize; ++i)
330- resCtrl[i] = (uint8_t )curCtrl[i] != maxCtrl[i]; // step of 0 or 1
374+
375+ if (minCtrl != nullptr )
376+ {
377+ computeResCtrl (minCtrl, curCtrl, resCtrl, ctrlSize);
378+ if (!isReachable (minCtrl, resCtrl, curCtrl, ctrlSize))
379+ {
380+ Logger::debug (" Minimum not consistent, it will be ignored." );
381+ delete[] minCtrl;
382+ minCtrl = nullptr ;
383+ computeResCtrl (curCtrl, maxCtrl, resCtrl, ctrlSize);
384+ }
385+ }
386+ else
387+ computeResCtrl (curCtrl, maxCtrl, resCtrl, ctrlSize);
331388 }
389+
390+ logDebugCtrl (" current:" , curCtrl, ctrlSize);
391+ logDebugCtrl (" maximum:" , maxCtrl, ctrlSize);
392+ if (minCtrl != nullptr )
393+ logDebugCtrl (" minimum:" , minCtrl, ctrlSize);
332394 logDebugCtrl (" resolution:" , resCtrl, ctrlSize);
395+ Logger::debug ((" unit: " + to_string ((int )unit) + " selector: " + to_string ((int )selector)).c_str ());
333396}
334397
335398/* *
@@ -465,14 +528,15 @@ uint8_t CameraInstruction::getSelector() const noexcept
465528}
466529
467530/* *
468- * @brief If a minimun control instruction exists and is consistent,
531+ * @brief If a minimun control instruction exists
532+ * and is not already the current,
469533 * set the current control instruction with that value
470534 *
471535 * @return true if success, otherwise false
472536 */
473537bool CameraInstruction::trySetMinAsCur () noexcept
474538{
475- if (! isMinConsistent () )
539+ if (minCtrl == nullptr || memcmp (curCtrl, minCtrl, ctrlSize * sizeof ( uint8_t )) == 0 )
476540 return false ;
477541
478542 memcpy (curCtrl, minCtrl, ctrlSize * sizeof (uint8_t ));
@@ -488,7 +552,8 @@ const char *CameraException::what()
488552 return message.c_str ();
489553}
490554
491- CameraInstructionException::CameraInstructionException (string device, uint8_t unit, uint8_t selector) : message(" ERROR: Impossible to obtain the instruction on " + device + " for unit: " + to_string((int )unit) + " selector:" + to_string((int )selector)) {}
555+ CameraInstructionException::CameraInstructionException (string device, uint8_t unit, uint8_t selector)
556+ : message(" ERROR: Impossible to obtain the instruction on " + device + " for unit: " + to_string((int )unit) + " selector:" + to_string((int )selector)) {}
492557
493558const char *CameraInstructionException::what ()
494559{
0 commit comments