[libcamera-devel,v2,4/7] libcamera: v4l2_controls: Construct from a list of ids

Message ID 20190827095008.11405-5-jacopo@jmondi.org
State Superseded
Delegated to: Jacopo Mondi
Headers show
Series
  • libcamera: camera_sensor: Collect camera location and sizes
Related show

Commit Message

Jacopo Mondi Aug. 27, 2019, 9:50 a.m. UTC
Add a constructor for the V4L2ControlList class that accepts a list of
V4L2 control IDs (V4L2_CID_*). The constructor returns a V4L2ControlList
instance to be used for reading controls only.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 src/libcamera/include/v4l2_controls.h |  3 +++
 src/libcamera/v4l2_controls.cpp       | 17 +++++++++++++++++
 2 files changed, 20 insertions(+)

Comments

Niklas Söderlund Aug. 28, 2019, 11:18 a.m. UTC | #1
Hi Jacopo,

Thanks for your work.

On 2019-08-27 11:50:04 +0200, Jacopo Mondi wrote:
> Add a constructor for the V4L2ControlList class that accepts a list of
> V4L2 control IDs (V4L2_CID_*). The constructor returns a V4L2ControlList
> instance to be used for reading controls only.
> 
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>  src/libcamera/include/v4l2_controls.h |  3 +++
>  src/libcamera/v4l2_controls.cpp       | 17 +++++++++++++++++
>  2 files changed, 20 insertions(+)
> 
> diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h
> index 10b726504951..86c84e06d741 100644
> --- a/src/libcamera/include/v4l2_controls.h
> +++ b/src/libcamera/include/v4l2_controls.h
> @@ -65,6 +65,9 @@ public:
>  	using iterator = std::vector<V4L2Control>::iterator;
>  	using const_iterator = std::vector<V4L2Control>::const_iterator;
>  
> +	V4L2ControlList() {}
> +	V4L2ControlList(std::vector<unsigned int> ids);
> +
>  	iterator begin() { return controls_.begin(); }
>  	const_iterator begin() const { return controls_.begin(); }
>  	iterator end() { return controls_.end(); }
> diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp
> index 84258d9954d0..eeb325cbfff9 100644
> --- a/src/libcamera/v4l2_controls.cpp
> +++ b/src/libcamera/v4l2_controls.cpp
> @@ -202,6 +202,23 @@ V4L2ControlInfo::V4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl)
>   * and prepare to be re-used for a new control write/read sequence.
>   */
>  
> +/**
> + * \brief Construct a V4L2ControlList from a list of V4L2 controls identifiers
> + * \param ids A list of V4L2 control identifiers (V4L2_CID_*)
> + *
> + * Construct a V4L2ControlList from a list of control identifiers without any
> + * value associated. This constructor is particularly useful to create a
> + * V4L2ControlList that is used to read the values of all controls in the
> + * \a ids list. The created V4L2ControlList should not be used to write control
> + * values unless it is cleared first and then controls with an associated value
> + * are manually added to it.
> + */

Do you think it would be worth it to add some code to enforce that no 
controls can be written if it's initialized with this constructor?

> +V4L2ControlList::V4L2ControlList(std::vector<unsigned int> ids)
> +{
> +	for (auto id : ids)
> +		add(id);
> +}
> +
>  /**
>   * \typedef V4L2ControlList::iterator
>   * \brief Iterator on the V4L2 controls contained in the instance
> -- 
> 2.23.0
> 
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
Jacopo Mondi Aug. 28, 2019, 4:28 p.m. UTC | #2
Hi Niklas,

On Wed, Aug 28, 2019 at 01:18:40PM +0200, Niklas Söderlund wrote:
> Hi Jacopo,
>
> Thanks for your work.
>
> On 2019-08-27 11:50:04 +0200, Jacopo Mondi wrote:
> > Add a constructor for the V4L2ControlList class that accepts a list of
> > V4L2 control IDs (V4L2_CID_*). The constructor returns a V4L2ControlList
> > instance to be used for reading controls only.
> >
> > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > ---
> >  src/libcamera/include/v4l2_controls.h |  3 +++
> >  src/libcamera/v4l2_controls.cpp       | 17 +++++++++++++++++
> >  2 files changed, 20 insertions(+)
> >
> > diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h
> > index 10b726504951..86c84e06d741 100644
> > --- a/src/libcamera/include/v4l2_controls.h
> > +++ b/src/libcamera/include/v4l2_controls.h
> > @@ -65,6 +65,9 @@ public:
> >  	using iterator = std::vector<V4L2Control>::iterator;
> >  	using const_iterator = std::vector<V4L2Control>::const_iterator;
> >
> > +	V4L2ControlList() {}
> > +	V4L2ControlList(std::vector<unsigned int> ids);
> > +
> >  	iterator begin() { return controls_.begin(); }
> >  	const_iterator begin() const { return controls_.begin(); }
> >  	iterator end() { return controls_.end(); }
> > diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp
> > index 84258d9954d0..eeb325cbfff9 100644
> > --- a/src/libcamera/v4l2_controls.cpp
> > +++ b/src/libcamera/v4l2_controls.cpp
> > @@ -202,6 +202,23 @@ V4L2ControlInfo::V4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl)
> >   * and prepare to be re-used for a new control write/read sequence.
> >   */
> >
> > +/**
> > + * \brief Construct a V4L2ControlList from a list of V4L2 controls identifiers
> > + * \param ids A list of V4L2 control identifiers (V4L2_CID_*)
> > + *
> > + * Construct a V4L2ControlList from a list of control identifiers without any
> > + * value associated. This constructor is particularly useful to create a
> > + * V4L2ControlList that is used to read the values of all controls in the
> > + * \a ids list. The created V4L2ControlList should not be used to write control
> > + * values unless it is cleared first and then controls with an associated value
> > + * are manually added to it.
> > + */
>
> Do you think it would be worth it to add some code to enforce that no
> controls can be written if it's initialized with this constructor?
>

How would you do so? The most naive implementation that comes to mind
it's to add a 'writable' flag to initialize to true only if the
control has a value assigned and check for the flag
V4L2Device::setControls()

> > +V4L2ControlList::V4L2ControlList(std::vector<unsigned int> ids)
> > +{
> > +	for (auto id : ids)
> > +		add(id);
> > +}
> > +
> >  /**
> >   * \typedef V4L2ControlList::iterator
> >   * \brief Iterator on the V4L2 controls contained in the instance
> > --
> > 2.23.0
> >
> > _______________________________________________
> > libcamera-devel mailing list
> > libcamera-devel@lists.libcamera.org
> > https://lists.libcamera.org/listinfo/libcamera-devel
>
> --
> Regards,
> Niklas Söderlund
Niklas Söderlund Aug. 29, 2019, 8:10 a.m. UTC | #3
On 2019-08-28 18:28:43 +0200, Jacopo Mondi wrote:
> Hi Niklas,
> 
> On Wed, Aug 28, 2019 at 01:18:40PM +0200, Niklas Söderlund wrote:
> > Hi Jacopo,
> >
> > Thanks for your work.
> >
> > On 2019-08-27 11:50:04 +0200, Jacopo Mondi wrote:
> > > Add a constructor for the V4L2ControlList class that accepts a list of
> > > V4L2 control IDs (V4L2_CID_*). The constructor returns a V4L2ControlList
> > > instance to be used for reading controls only.
> > >
> > > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > > ---
> > >  src/libcamera/include/v4l2_controls.h |  3 +++
> > >  src/libcamera/v4l2_controls.cpp       | 17 +++++++++++++++++
> > >  2 files changed, 20 insertions(+)
> > >
> > > diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h
> > > index 10b726504951..86c84e06d741 100644
> > > --- a/src/libcamera/include/v4l2_controls.h
> > > +++ b/src/libcamera/include/v4l2_controls.h
> > > @@ -65,6 +65,9 @@ public:
> > >  	using iterator = std::vector<V4L2Control>::iterator;
> > >  	using const_iterator = std::vector<V4L2Control>::const_iterator;
> > >
> > > +	V4L2ControlList() {}
> > > +	V4L2ControlList(std::vector<unsigned int> ids);
> > > +
> > >  	iterator begin() { return controls_.begin(); }
> > >  	const_iterator begin() const { return controls_.begin(); }
> > >  	iterator end() { return controls_.end(); }
> > > diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp
> > > index 84258d9954d0..eeb325cbfff9 100644
> > > --- a/src/libcamera/v4l2_controls.cpp
> > > +++ b/src/libcamera/v4l2_controls.cpp
> > > @@ -202,6 +202,23 @@ V4L2ControlInfo::V4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl)
> > >   * and prepare to be re-used for a new control write/read sequence.
> > >   */
> > >
> > > +/**
> > > + * \brief Construct a V4L2ControlList from a list of V4L2 controls identifiers
> > > + * \param ids A list of V4L2 control identifiers (V4L2_CID_*)
> > > + *
> > > + * Construct a V4L2ControlList from a list of control identifiers without any
> > > + * value associated. This constructor is particularly useful to create a
> > > + * V4L2ControlList that is used to read the values of all controls in the
> > > + * \a ids list. The created V4L2ControlList should not be used to write control
> > > + * values unless it is cleared first and then controls with an associated value
> > > + * are manually added to it.
> > > + */
> >
> > Do you think it would be worth it to add some code to enforce that no
> > controls can be written if it's initialized with this constructor?
> >
> 
> How would you do so? The most naive implementation that comes to mind
> it's to add a 'writable' flag to initialize to true only if the
> control has a value assigned and check for the flag
> V4L2Device::setControls()

I'm not sure how to best implement it, but the constraint is so specific 
it looked like something that could be described in code. Now that I dig 
thru the code with fresh eyes I can't find the rational for the 
V4L2ControlList needs to be cleared before it's attempted to be used for 
writing.

The control values are initialized to 0 using this new constructor and 
if used for writing V4L2Device::setControls() will validate that the 
control exists on the device and bail before writing anything if one the 
controls do not exist.

What reason do you think there is for the need to manually add controls 
with a specific value before writing? This is just a specialisation 
where all values are initialized to 0, at least in my mind I might be 
missing something ;-)

> 
> > > +V4L2ControlList::V4L2ControlList(std::vector<unsigned int> ids)
> > > +{
> > > +	for (auto id : ids)
> > > +		add(id);
> > > +}
> > > +
> > >  /**
> > >   * \typedef V4L2ControlList::iterator
> > >   * \brief Iterator on the V4L2 controls contained in the instance
> > > --
> > > 2.23.0
> > >
> > > _______________________________________________
> > > libcamera-devel mailing list
> > > libcamera-devel@lists.libcamera.org
> > > https://lists.libcamera.org/listinfo/libcamera-devel
> >
> > --
> > Regards,
> > Niklas Söderlund
Jacopo Mondi Aug. 29, 2019, 8:56 a.m. UTC | #4
Hi Niklas,

On Thu, Aug 29, 2019 at 10:10:10AM +0200, Niklas Söderlund wrote:
> On 2019-08-28 18:28:43 +0200, Jacopo Mondi wrote:
> > Hi Niklas,
> >
> > On Wed, Aug 28, 2019 at 01:18:40PM +0200, Niklas Söderlund wrote:
> > > Hi Jacopo,
> > >
> > > Thanks for your work.
> > >
> > > On 2019-08-27 11:50:04 +0200, Jacopo Mondi wrote:
> > > > Add a constructor for the V4L2ControlList class that accepts a list of
> > > > V4L2 control IDs (V4L2_CID_*). The constructor returns a V4L2ControlList
> > > > instance to be used for reading controls only.
> > > >
> > > > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > > > ---
> > > >  src/libcamera/include/v4l2_controls.h |  3 +++
> > > >  src/libcamera/v4l2_controls.cpp       | 17 +++++++++++++++++
> > > >  2 files changed, 20 insertions(+)
> > > >
> > > > diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h
> > > > index 10b726504951..86c84e06d741 100644
> > > > --- a/src/libcamera/include/v4l2_controls.h
> > > > +++ b/src/libcamera/include/v4l2_controls.h
> > > > @@ -65,6 +65,9 @@ public:
> > > >  	using iterator = std::vector<V4L2Control>::iterator;
> > > >  	using const_iterator = std::vector<V4L2Control>::const_iterator;
> > > >
> > > > +	V4L2ControlList() {}
> > > > +	V4L2ControlList(std::vector<unsigned int> ids);
> > > > +
> > > >  	iterator begin() { return controls_.begin(); }
> > > >  	const_iterator begin() const { return controls_.begin(); }
> > > >  	iterator end() { return controls_.end(); }
> > > > diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp
> > > > index 84258d9954d0..eeb325cbfff9 100644
> > > > --- a/src/libcamera/v4l2_controls.cpp
> > > > +++ b/src/libcamera/v4l2_controls.cpp
> > > > @@ -202,6 +202,23 @@ V4L2ControlInfo::V4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl)
> > > >   * and prepare to be re-used for a new control write/read sequence.
> > > >   */
> > > >
> > > > +/**
> > > > + * \brief Construct a V4L2ControlList from a list of V4L2 controls identifiers
> > > > + * \param ids A list of V4L2 control identifiers (V4L2_CID_*)
> > > > + *
> > > > + * Construct a V4L2ControlList from a list of control identifiers without any
> > > > + * value associated. This constructor is particularly useful to create a
> > > > + * V4L2ControlList that is used to read the values of all controls in the
> > > > + * \a ids list. The created V4L2ControlList should not be used to write control
> > > > + * values unless it is cleared first and then controls with an associated value
> > > > + * are manually added to it.
> > > > + */
> > >
> > > Do you think it would be worth it to add some code to enforce that no
> > > controls can be written if it's initialized with this constructor?
> > >
> >
> > How would you do so? The most naive implementation that comes to mind
> > it's to add a 'writable' flag to initialize to true only if the
> > control has a value assigned and check for the flag
> > V4L2Device::setControls()
>
> I'm not sure how to best implement it, but the constraint is so specific
> it looked like something that could be described in code. Now that I dig
> thru the code with fresh eyes I can't find the rational for the
> V4L2ControlList needs to be cleared before it's attempted to be used for
> writing.
>
> The control values are initialized to 0 using this new constructor and
> if used for writing V4L2Device::setControls() will validate that the
> control exists on the device and bail before writing anything if one the
> controls do not exist.

Yes, it validates the control exists
https://git.linuxtv.org/libcamera.git/tree/src/libcamera/v4l2_device.cpp#n251

but it will silently set the value of the v4l2 control to write to 0
https://git.linuxtv.org/libcamera.git/tree/src/libcamera/v4l2_device.cpp#n265

One could
        V4L2ControlList list = { V4L2_CID_..., V4L2_CID_... };
        device->setControls(&list);

and if the controls in the list accept 0 as a value, set all controls
to 0 maybe unintentionally.

>
> What reason do you think there is for the need to manually add controls
> with a specific value before writing? This is just a specialisation
> where all values are initialized to 0, at least in my mind I might be
> missing something ;-)
>
We have no guarantee the controls in the list accept 0, or that they
even accepts integers at all (even if, we only support integers
controls at the moment).

We cannot prevent anyone from shooting on his own foot, but to
me documenting that the list should only be used for reading, or
enforcing it in the code as you suggested, is a good thing...

> >
> > > > +V4L2ControlList::V4L2ControlList(std::vector<unsigned int> ids)
> > > > +{
> > > > +	for (auto id : ids)
> > > > +		add(id);
> > > > +}
> > > > +
> > > >  /**
> > > >   * \typedef V4L2ControlList::iterator
> > > >   * \brief Iterator on the V4L2 controls contained in the instance
> > > > --
> > > > 2.23.0
> > > >
> > > > _______________________________________________
> > > > libcamera-devel mailing list
> > > > libcamera-devel@lists.libcamera.org
> > > > https://lists.libcamera.org/listinfo/libcamera-devel
> > >
> > > --
> > > Regards,
> > > Niklas Söderlund
>
>
>
> --
> Regards,
> Niklas Söderlund
Niklas Söderlund Aug. 29, 2019, 9:08 a.m. UTC | #5
Hi Jacopo,

On 2019-08-29 10:56:57 +0200, Jacopo Mondi wrote:
> Hi Niklas,
> 
> On Thu, Aug 29, 2019 at 10:10:10AM +0200, Niklas Söderlund wrote:
> > On 2019-08-28 18:28:43 +0200, Jacopo Mondi wrote:
> > > Hi Niklas,
> > >
> > > On Wed, Aug 28, 2019 at 01:18:40PM +0200, Niklas Söderlund wrote:
> > > > Hi Jacopo,
> > > >
> > > > Thanks for your work.
> > > >
> > > > On 2019-08-27 11:50:04 +0200, Jacopo Mondi wrote:
> > > > > Add a constructor for the V4L2ControlList class that accepts a list of
> > > > > V4L2 control IDs (V4L2_CID_*). The constructor returns a V4L2ControlList
> > > > > instance to be used for reading controls only.
> > > > >
> > > > > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > > > > ---
> > > > >  src/libcamera/include/v4l2_controls.h |  3 +++
> > > > >  src/libcamera/v4l2_controls.cpp       | 17 +++++++++++++++++
> > > > >  2 files changed, 20 insertions(+)
> > > > >
> > > > > diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h
> > > > > index 10b726504951..86c84e06d741 100644
> > > > > --- a/src/libcamera/include/v4l2_controls.h
> > > > > +++ b/src/libcamera/include/v4l2_controls.h
> > > > > @@ -65,6 +65,9 @@ public:
> > > > >  	using iterator = std::vector<V4L2Control>::iterator;
> > > > >  	using const_iterator = std::vector<V4L2Control>::const_iterator;
> > > > >
> > > > > +	V4L2ControlList() {}
> > > > > +	V4L2ControlList(std::vector<unsigned int> ids);
> > > > > +
> > > > >  	iterator begin() { return controls_.begin(); }
> > > > >  	const_iterator begin() const { return controls_.begin(); }
> > > > >  	iterator end() { return controls_.end(); }
> > > > > diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp
> > > > > index 84258d9954d0..eeb325cbfff9 100644
> > > > > --- a/src/libcamera/v4l2_controls.cpp
> > > > > +++ b/src/libcamera/v4l2_controls.cpp
> > > > > @@ -202,6 +202,23 @@ V4L2ControlInfo::V4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl)
> > > > >   * and prepare to be re-used for a new control write/read sequence.
> > > > >   */
> > > > >
> > > > > +/**
> > > > > + * \brief Construct a V4L2ControlList from a list of V4L2 controls identifiers
> > > > > + * \param ids A list of V4L2 control identifiers (V4L2_CID_*)
> > > > > + *
> > > > > + * Construct a V4L2ControlList from a list of control identifiers without any
> > > > > + * value associated. This constructor is particularly useful to create a
> > > > > + * V4L2ControlList that is used to read the values of all controls in the
> > > > > + * \a ids list. The created V4L2ControlList should not be used to write control
> > > > > + * values unless it is cleared first and then controls with an associated value
> > > > > + * are manually added to it.
> > > > > + */
> > > >
> > > > Do you think it would be worth it to add some code to enforce that no
> > > > controls can be written if it's initialized with this constructor?
> > > >
> > >
> > > How would you do so? The most naive implementation that comes to mind
> > > it's to add a 'writable' flag to initialize to true only if the
> > > control has a value assigned and check for the flag
> > > V4L2Device::setControls()
> >
> > I'm not sure how to best implement it, but the constraint is so specific
> > it looked like something that could be described in code. Now that I dig
> > thru the code with fresh eyes I can't find the rational for the
> > V4L2ControlList needs to be cleared before it's attempted to be used for
> > writing.
> >
> > The control values are initialized to 0 using this new constructor and
> > if used for writing V4L2Device::setControls() will validate that the
> > control exists on the device and bail before writing anything if one the
> > controls do not exist.
> 
> Yes, it validates the control exists
> https://git.linuxtv.org/libcamera.git/tree/src/libcamera/v4l2_device.cpp#n251
> 
> but it will silently set the value of the v4l2 control to write to 0
> https://git.linuxtv.org/libcamera.git/tree/src/libcamera/v4l2_device.cpp#n265
> 
> One could
>         V4L2ControlList list = { V4L2_CID_..., V4L2_CID_... };
>         device->setControls(&list);
> 
> and if the controls in the list accept 0 as a value, set all controls
> to 0 maybe unintentionally.

Absolutely, that's what I'm saying :-) We already have this feature with 
the following code:

     V4L2ControlList list;
     list.add(V4L2_CID_...);
     list.add(V4L2_CID_...);
     device->setControls(&list);

So this new constructor is just a more convenient way to do the above 
and I see no real reason to block this use-case as the behaviour is well 
defined. If V4L2ControlList::add() value argument did not have an 
default value set I agree this would be a slightly different change.

If we add logic to prevent a V4L2ControlList initialized with this new 
constructor from being written we should also block V4L2ControlList 
where controls where added with just an id an no explicit value from 
being written.

> 
> >
> > What reason do you think there is for the need to manually add controls
> > with a specific value before writing? This is just a specialisation
> > where all values are initialized to 0, at least in my mind I might be
> > missing something ;-)
> >
> We have no guarantee the controls in the list accept 0, or that they
> even accepts integers at all (even if, we only support integers
> controls at the moment).
> 
> We cannot prevent anyone from shooting on his own foot, but to
> me documenting that the list should only be used for reading, or
> enforcing it in the code as you suggested, is a good thing...
> 
> > >
> > > > > +V4L2ControlList::V4L2ControlList(std::vector<unsigned int> ids)
> > > > > +{
> > > > > +	for (auto id : ids)
> > > > > +		add(id);
> > > > > +}
> > > > > +
> > > > >  /**
> > > > >   * \typedef V4L2ControlList::iterator
> > > > >   * \brief Iterator on the V4L2 controls contained in the instance
> > > > > --
> > > > > 2.23.0
> > > > >
> > > > > _______________________________________________
> > > > > libcamera-devel mailing list
> > > > > libcamera-devel@lists.libcamera.org
> > > > > https://lists.libcamera.org/listinfo/libcamera-devel
> > > >
> > > > --
> > > > Regards,
> > > > Niklas Söderlund
> >
> >
> >
> > --
> > Regards,
> > Niklas Söderlund
Jacopo Mondi Aug. 29, 2019, 9:13 a.m. UTC | #6
Hi Niklas,

On Thu, Aug 29, 2019 at 11:08:25AM +0200, Niklas Söderlund wrote:
> Hi Jacopo,
>
> On 2019-08-29 10:56:57 +0200, Jacopo Mondi wrote:
> > Hi Niklas,
> >
> > On Thu, Aug 29, 2019 at 10:10:10AM +0200, Niklas Söderlund wrote:
> > > On 2019-08-28 18:28:43 +0200, Jacopo Mondi wrote:
> > > > Hi Niklas,
> > > >
> > > > On Wed, Aug 28, 2019 at 01:18:40PM +0200, Niklas Söderlund wrote:
> > > > > Hi Jacopo,
> > > > >
> > > > > Thanks for your work.
> > > > >
> > > > > On 2019-08-27 11:50:04 +0200, Jacopo Mondi wrote:
> > > > > > Add a constructor for the V4L2ControlList class that accepts a list of
> > > > > > V4L2 control IDs (V4L2_CID_*). The constructor returns a V4L2ControlList
> > > > > > instance to be used for reading controls only.
> > > > > >
> > > > > > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > > > > > ---
> > > > > >  src/libcamera/include/v4l2_controls.h |  3 +++
> > > > > >  src/libcamera/v4l2_controls.cpp       | 17 +++++++++++++++++
> > > > > >  2 files changed, 20 insertions(+)
> > > > > >
> > > > > > diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h
> > > > > > index 10b726504951..86c84e06d741 100644
> > > > > > --- a/src/libcamera/include/v4l2_controls.h
> > > > > > +++ b/src/libcamera/include/v4l2_controls.h
> > > > > > @@ -65,6 +65,9 @@ public:
> > > > > >  	using iterator = std::vector<V4L2Control>::iterator;
> > > > > >  	using const_iterator = std::vector<V4L2Control>::const_iterator;
> > > > > >
> > > > > > +	V4L2ControlList() {}
> > > > > > +	V4L2ControlList(std::vector<unsigned int> ids);
> > > > > > +
> > > > > >  	iterator begin() { return controls_.begin(); }
> > > > > >  	const_iterator begin() const { return controls_.begin(); }
> > > > > >  	iterator end() { return controls_.end(); }
> > > > > > diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp
> > > > > > index 84258d9954d0..eeb325cbfff9 100644
> > > > > > --- a/src/libcamera/v4l2_controls.cpp
> > > > > > +++ b/src/libcamera/v4l2_controls.cpp
> > > > > > @@ -202,6 +202,23 @@ V4L2ControlInfo::V4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl)
> > > > > >   * and prepare to be re-used for a new control write/read sequence.
> > > > > >   */
> > > > > >
> > > > > > +/**
> > > > > > + * \brief Construct a V4L2ControlList from a list of V4L2 controls identifiers
> > > > > > + * \param ids A list of V4L2 control identifiers (V4L2_CID_*)
> > > > > > + *
> > > > > > + * Construct a V4L2ControlList from a list of control identifiers without any
> > > > > > + * value associated. This constructor is particularly useful to create a
> > > > > > + * V4L2ControlList that is used to read the values of all controls in the
> > > > > > + * \a ids list. The created V4L2ControlList should not be used to write control
> > > > > > + * values unless it is cleared first and then controls with an associated value
> > > > > > + * are manually added to it.
> > > > > > + */
> > > > >
> > > > > Do you think it would be worth it to add some code to enforce that no
> > > > > controls can be written if it's initialized with this constructor?
> > > > >
> > > >
> > > > How would you do so? The most naive implementation that comes to mind
> > > > it's to add a 'writable' flag to initialize to true only if the
> > > > control has a value assigned and check for the flag
> > > > V4L2Device::setControls()
> > >
> > > I'm not sure how to best implement it, but the constraint is so specific
> > > it looked like something that could be described in code. Now that I dig
> > > thru the code with fresh eyes I can't find the rational for the
> > > V4L2ControlList needs to be cleared before it's attempted to be used for
> > > writing.
> > >
> > > The control values are initialized to 0 using this new constructor and
> > > if used for writing V4L2Device::setControls() will validate that the
> > > control exists on the device and bail before writing anything if one the
> > > controls do not exist.
> >
> > Yes, it validates the control exists
> > https://git.linuxtv.org/libcamera.git/tree/src/libcamera/v4l2_device.cpp#n251
> >
> > but it will silently set the value of the v4l2 control to write to 0
> > https://git.linuxtv.org/libcamera.git/tree/src/libcamera/v4l2_device.cpp#n265
> >
> > One could
> >         V4L2ControlList list = { V4L2_CID_..., V4L2_CID_... };
> >         device->setControls(&list);
> >
> > and if the controls in the list accept 0 as a value, set all controls
> > to 0 maybe unintentionally.
>
> Absolutely, that's what I'm saying :-) We already have this feature with
> the following code:
>
>      V4L2ControlList list;
>      list.add(V4L2_CID_...);
>      list.add(V4L2_CID_...);
>      device->setControls(&list);
>
> So this new constructor is just a more convenient way to do the above
> and I see no real reason to block this use-case as the behaviour is well
> defined. If V4L2ControlList::add() value argument did not have an
> default value set I agree this would be a slightly different change.
>
> If we add logic to prevent a V4L2ControlList initialized with this new
> constructor from being written we should also block V4L2ControlList
> where controls where added with just an id an no explicit value from
> being written.
>

Indeed, this applies to all controls added without a value, not just
the lists constructed with the newly introduced constructor, which is
just a shortcut to what you have here described...

> >
> > >
> > > What reason do you think there is for the need to manually add controls
> > > with a specific value before writing? This is just a specialisation
> > > where all values are initialized to 0, at least in my mind I might be
> > > missing something ;-)
> > >
> > We have no guarantee the controls in the list accept 0, or that they
> > even accepts integers at all (even if, we only support integers
> > controls at the moment).
> >
> > We cannot prevent anyone from shooting on his own foot, but to
> > me documenting that the list should only be used for reading, or
> > enforcing it in the code as you suggested, is a good thing...
> >
> > > >
> > > > > > +V4L2ControlList::V4L2ControlList(std::vector<unsigned int> ids)
> > > > > > +{
> > > > > > +	for (auto id : ids)
> > > > > > +		add(id);
> > > > > > +}
> > > > > > +
> > > > > >  /**
> > > > > >   * \typedef V4L2ControlList::iterator
> > > > > >   * \brief Iterator on the V4L2 controls contained in the instance
> > > > > > --
> > > > > > 2.23.0
> > > > > >
> > > > > > _______________________________________________
> > > > > > libcamera-devel mailing list
> > > > > > libcamera-devel@lists.libcamera.org
> > > > > > https://lists.libcamera.org/listinfo/libcamera-devel
> > > > >
> > > > > --
> > > > > Regards,
> > > > > Niklas Söderlund
> > >
> > >
> > >
> > > --
> > > Regards,
> > > Niklas Söderlund
>
>
>
> --
> Regards,
> Niklas Söderlund
Laurent Pinchart Sept. 3, 2019, 8:17 p.m. UTC | #7
Hi Jacopo,

Thank you for the patch.

On Tue, Aug 27, 2019 at 11:50:04AM +0200, Jacopo Mondi wrote:
> Add a constructor for the V4L2ControlList class that accepts a list of
> V4L2 control IDs (V4L2_CID_*). The constructor returns a V4L2ControlList
> instance to be used for reading controls only.

I tend to understand "for reading controls only" as meaning for reading
controls and nothing else than controls. Is it just me ? Should this be
expressed as "to be used only for reading controls" ?

> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>  src/libcamera/include/v4l2_controls.h |  3 +++
>  src/libcamera/v4l2_controls.cpp       | 17 +++++++++++++++++
>  2 files changed, 20 insertions(+)
> 
> diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h
> index 10b726504951..86c84e06d741 100644
> --- a/src/libcamera/include/v4l2_controls.h
> +++ b/src/libcamera/include/v4l2_controls.h
> @@ -65,6 +65,9 @@ public:
>  	using iterator = std::vector<V4L2Control>::iterator;
>  	using const_iterator = std::vector<V4L2Control>::const_iterator;
>  
> +	V4L2ControlList() {}
> +	V4L2ControlList(std::vector<unsigned int> ids);

How about using an initializer_list<unsigned int> instead of a vector ?

> +
>  	iterator begin() { return controls_.begin(); }
>  	const_iterator begin() const { return controls_.begin(); }
>  	iterator end() { return controls_.end(); }
> diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp
> index 84258d9954d0..eeb325cbfff9 100644
> --- a/src/libcamera/v4l2_controls.cpp
> +++ b/src/libcamera/v4l2_controls.cpp
> @@ -202,6 +202,23 @@ V4L2ControlInfo::V4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl)
>   * and prepare to be re-used for a new control write/read sequence.
>   */
>  
> +/**
> + * \brief Construct a V4L2ControlList from a list of V4L2 controls identifiers
> + * \param ids A list of V4L2 control identifiers (V4L2_CID_*)
> + *
> + * Construct a V4L2ControlList from a list of control identifiers without any
> + * value associated. This constructor is particularly useful to create a

s/value/values/

> + * V4L2ControlList that is used to read the values of all controls in the
> + * \a ids list. The created V4L2ControlList should not be used to write control

s/should/shall/

> + * values unless it is cleared first and then controls with an associated value
> + * are manually added to it.
> + */
> +V4L2ControlList::V4L2ControlList(std::vector<unsigned int> ids)
> +{
> +	for (auto id : ids)

Let's not abuse auto, this is clearly a case where you can write the
full type instead.

> +		add(id);
> +}
> +
>  /**
>   * \typedef V4L2ControlList::iterator
>   * \brief Iterator on the V4L2 controls contained in the instance

Patch

diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h
index 10b726504951..86c84e06d741 100644
--- a/src/libcamera/include/v4l2_controls.h
+++ b/src/libcamera/include/v4l2_controls.h
@@ -65,6 +65,9 @@  public:
 	using iterator = std::vector<V4L2Control>::iterator;
 	using const_iterator = std::vector<V4L2Control>::const_iterator;
 
+	V4L2ControlList() {}
+	V4L2ControlList(std::vector<unsigned int> ids);
+
 	iterator begin() { return controls_.begin(); }
 	const_iterator begin() const { return controls_.begin(); }
 	iterator end() { return controls_.end(); }
diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp
index 84258d9954d0..eeb325cbfff9 100644
--- a/src/libcamera/v4l2_controls.cpp
+++ b/src/libcamera/v4l2_controls.cpp
@@ -202,6 +202,23 @@  V4L2ControlInfo::V4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl)
  * and prepare to be re-used for a new control write/read sequence.
  */
 
+/**
+ * \brief Construct a V4L2ControlList from a list of V4L2 controls identifiers
+ * \param ids A list of V4L2 control identifiers (V4L2_CID_*)
+ *
+ * Construct a V4L2ControlList from a list of control identifiers without any
+ * value associated. This constructor is particularly useful to create a
+ * V4L2ControlList that is used to read the values of all controls in the
+ * \a ids list. The created V4L2ControlList should not be used to write control
+ * values unless it is cleared first and then controls with an associated value
+ * are manually added to it.
+ */
+V4L2ControlList::V4L2ControlList(std::vector<unsigned int> ids)
+{
+	for (auto id : ids)
+		add(id);
+}
+
 /**
  * \typedef V4L2ControlList::iterator
  * \brief Iterator on the V4L2 controls contained in the instance