diff --git a/include/libcamera/internal/control_serializer.h b/include/libcamera/internal/control_serializer.h index 8a63ae44..307ecba5 100644 --- a/include/libcamera/internal/control_serializer.h +++ b/include/libcamera/internal/control_serializer.h @@ -47,9 +47,13 @@ private: static void store(const ControlValue &value, ByteStreamBuffer &buffer); static void store(const ControlInfo &info, ByteStreamBuffer &buffer); + void populateControlValueEntry(struct ipa_control_value_entry &entry, + const ControlValue &value, + uint32_t offset); + ControlValue loadControlValue(ByteStreamBuffer &buffer, - bool isArray = false, unsigned int count = 1); - ControlInfo loadControlInfo(ByteStreamBuffer &buffer); + ControlType type, + bool isArray, unsigned int count); unsigned int serial_; unsigned int serialSeed_; diff --git a/include/libcamera/ipa/ipa_controls.h b/include/libcamera/ipa/ipa_controls.h index 980668c8..6af962ff 100644 --- a/include/libcamera/ipa/ipa_controls.h +++ b/include/libcamera/ipa/ipa_controls.h @@ -15,7 +15,7 @@ namespace libcamera { extern "C" { #endif -#define IPA_CONTROLS_FORMAT_VERSION 1 +#define IPA_CONTROLS_FORMAT_VERSION 2 enum ipa_controls_id_map_type { IPA_CONTROL_ID_MAP_CONTROLS, @@ -34,20 +34,26 @@ struct ipa_controls_header { }; struct ipa_control_value_entry { - uint32_t id; uint8_t type; uint8_t is_array; uint16_t count; uint32_t offset; - uint32_t padding[1]; + uint32_t reserved[2]; +}; + +struct ipa_control_list_entry { + uint32_t id; + struct ipa_control_value_entry value; }; struct ipa_control_info_entry { uint32_t id; uint32_t type; - uint32_t offset; uint8_t direction; - uint8_t padding[3]; + uint8_t padding[7]; + struct ipa_control_value_entry min; + struct ipa_control_value_entry max; + struct ipa_control_value_entry def; }; #ifdef __cplusplus diff --git a/src/libcamera/control_serializer.cpp b/src/libcamera/control_serializer.cpp index 050f8512..843e2772 100644 --- a/src/libcamera/control_serializer.cpp +++ b/src/libcamera/control_serializer.cpp @@ -144,7 +144,7 @@ void ControlSerializer::reset() size_t ControlSerializer::binarySize(const ControlValue &value) { - return sizeof(ControlType) + value.data().size_bytes(); + return value.data().size_bytes(); } size_t ControlSerializer::binarySize(const ControlInfo &info) @@ -164,7 +164,8 @@ size_t ControlSerializer::binarySize(const ControlInfo &info) size_t ControlSerializer::binarySize(const ControlInfoMap &infoMap) { size_t size = sizeof(struct ipa_controls_header) - + infoMap.size() * sizeof(struct ipa_control_info_entry); + + infoMap.size() * (sizeof(struct ipa_control_info_entry) + + 3 * sizeof(struct ipa_control_value_entry)); for (const auto &ctrl : infoMap) size += binarySize(ctrl.second); @@ -184,7 +185,7 @@ size_t ControlSerializer::binarySize(const ControlInfoMap &infoMap) size_t ControlSerializer::binarySize(const ControlList &list) { size_t size = sizeof(struct ipa_controls_header) - + list.size() * sizeof(struct ipa_control_value_entry); + + list.size() * sizeof(struct ipa_control_list_entry); for (const auto &ctrl : list) size += binarySize(ctrl.second); @@ -195,16 +196,17 @@ size_t ControlSerializer::binarySize(const ControlList &list) void ControlSerializer::store(const ControlValue &value, ByteStreamBuffer &buffer) { - const ControlType type = value.type(); - buffer.write(&type); buffer.write(value.data()); } -void ControlSerializer::store(const ControlInfo &info, ByteStreamBuffer &buffer) +void ControlSerializer::populateControlValueEntry(struct ipa_control_value_entry &entry, + const ControlValue &value, + uint32_t offset) { - store(info.min(), buffer); - store(info.max(), buffer); - store(info.def(), buffer); + entry.type = value.type(); + entry.is_array = value.isArray(); + entry.count = value.numElements(); + entry.offset = offset; } /** @@ -232,7 +234,8 @@ int ControlSerializer::serialize(const ControlInfoMap &infoMap, /* Compute entries and data required sizes. */ size_t entriesSize = infoMap.size() - * sizeof(struct ipa_control_info_entry); + * (sizeof(struct ipa_control_info_entry) + + 3 * sizeof(struct ipa_control_value_entry)); size_t valuesSize = 0; for (const auto &ctrl : infoMap) valuesSize += binarySize(ctrl.second); @@ -280,11 +283,18 @@ int ControlSerializer::serialize(const ControlInfoMap &infoMap, struct ipa_control_info_entry entry; entry.id = id->id(); entry.type = id->type(); - entry.offset = values.offset(); entry.direction = static_cast(id->direction()); - entries.write(&entry); - store(info, values); + populateControlValueEntry(entry.min, info.min(), values.offset()); + store(info.min(), values); + + populateControlValueEntry(entry.max, info.max(), values.offset()); + store(info.max(), values); + + populateControlValueEntry(entry.def, info.def(), values.offset()); + store(info.def(), values); + + entries.write(&entry); } if (buffer.overflow()) @@ -341,7 +351,7 @@ int ControlSerializer::serialize(const ControlList &list, else idMapType = IPA_CONTROL_ID_MAP_V4L2; - size_t entriesSize = list.size() * sizeof(struct ipa_control_value_entry); + size_t entriesSize = list.size() * sizeof(struct ipa_control_list_entry); size_t valuesSize = 0; for (const auto &ctrl : list) valuesSize += binarySize(ctrl.second); @@ -365,12 +375,9 @@ int ControlSerializer::serialize(const ControlList &list, unsigned int id = ctrl.first; const ControlValue &value = ctrl.second; - struct ipa_control_value_entry entry; + struct ipa_control_list_entry entry; entry.id = id; - entry.type = value.type(); - entry.is_array = value.isArray(); - entry.count = value.numElements(); - entry.offset = values.offset(); + populateControlValueEntry(entry.value, value, values.offset()); entries.write(&entry); store(value, values); @@ -383,12 +390,10 @@ int ControlSerializer::serialize(const ControlList &list, } ControlValue ControlSerializer::loadControlValue(ByteStreamBuffer &buffer, + ControlType type, bool isArray, unsigned int count) { - ControlType type; - buffer.read(&type); - ControlValue value; value.reserve(type, isArray, count); @@ -397,15 +402,6 @@ ControlValue ControlSerializer::loadControlValue(ByteStreamBuffer &buffer, return value; } -ControlInfo ControlSerializer::loadControlInfo(ByteStreamBuffer &b) -{ - ControlValue min = loadControlValue(b); - ControlValue max = loadControlValue(b); - ControlValue def = loadControlValue(b); - - return ControlInfo(min, max, def); -} - /** * \fn template T ControlSerializer::deserialize(ByteStreamBuffer &buffer) * \brief Deserialize an object from a binary buffer @@ -483,8 +479,7 @@ ControlInfoMap ControlSerializer::deserialize(ByteStreamBuffer & ControlInfoMap::Map ctrls; for (unsigned int i = 0; i < hdr->entries; ++i) { - const struct ipa_control_info_entry *entry = - entries.read(); + const auto *entry = entries.read(); if (!entry) { LOG(Serializer, Error) << "Out of data"; return {}; @@ -511,15 +506,43 @@ ControlInfoMap ControlSerializer::deserialize(ByteStreamBuffer & const ControlId *controlId = idMap->at(entry->id); ASSERT(controlId); - if (entry->offset != values.offset()) { + const ipa_control_value_entry &min_entry = entry->min; + const ipa_control_value_entry &max_entry = entry->max; + const ipa_control_value_entry &def_entry = entry->def; + + if (min_entry.offset != values.offset()) { LOG(Serializer, Error) - << "Bad data, entry offset mismatch (entry " + << "Bad data, entry offset mismatch (min entry " << i << ")"; return {}; } + ControlValue min = + loadControlValue(values, static_cast(min_entry.type), + min_entry.is_array, min_entry.count); + + if (max_entry.offset != values.offset()) { + LOG(Serializer, Error) + << "Bad data, entry offset mismatch (max entry " + << i << ")"; + return {}; + } + ControlValue max = + loadControlValue(values, static_cast(max_entry.type), + max_entry.is_array, max_entry.count); + + if (def_entry.offset != values.offset()) { + LOG(Serializer, Error) + << "Bad data, entry offset mismatch (def entry " + << i << ")"; + return {}; + } + ControlValue def = + loadControlValue(values, static_cast(def_entry.type), + def_entry.is_array, def_entry.count); + /* Create and store the ControlInfo. */ - ctrls.emplace(controlId, loadControlInfo(values)); + ctrls.emplace(controlId, ControlInfo(min, max, def)); } /* @@ -618,12 +641,12 @@ ControlList ControlSerializer::deserialize(ByteStreamBuffer &buffer ControlList ctrls(*idMap); for (unsigned int i = 0; i < hdr->entries; ++i) { - const struct ipa_control_value_entry *entry = - entries.read(); - if (!entry) { + auto *list_entry = entries.read(); + if (!list_entry) { LOG(Serializer, Error) << "Out of data"; return {}; } + const ipa_control_value_entry *entry = &list_entry->value; if (entry->offset != values.offset()) { LOG(Serializer, Error) @@ -632,8 +655,9 @@ ControlList ControlSerializer::deserialize(ByteStreamBuffer &buffer return {}; } - ctrls.set(entry->id, - loadControlValue(values, entry->is_array, entry->count)); + ctrls.set(list_entry->id, + loadControlValue(values, static_cast(entry->type), + entry->is_array, entry->count)); } return ctrls; diff --git a/src/libcamera/ipa_controls.cpp b/src/libcamera/ipa_controls.cpp index 12d92ebe..61af7433 100644 --- a/src/libcamera/ipa_controls.cpp +++ b/src/libcamera/ipa_controls.cpp @@ -26,28 +26,28 @@ * The following diagram describes the layout of the ControlList packet. * * ~~~~ - * +-------------------------+ . . - * Header / | ipa_controls_header | | | - * | | | | | - * \ | | | | - * +-------------------------+ | | - * / | ipa_control_value_entry | | hdr.data_offset | - * | | #0 | | | - * Control | +-------------------------+ | | - * value | | ... | | | - * entries | +-------------------------+ | | - * | | ipa_control_value_entry | | hdr.size | - * \ | #hdr.entries - 1 | | | - * +-------------------------+ | | - * | empty space (optional) | | | - * +-------------------------+ <--´ . | - * / | ... | | entry[n].offset | - * Data | | ... | | | - * section | | value data for entry #n | <-----´ | - * \ | ... | | - * +-------------------------+ | - * | empty space (optional) | | - * +-------------------------+ <-------------------------´ + * +-------------------------+ . . + * Header / | ipa_controls_header | | | + * | | | | | + * \ | | | | + * +-------------------------+ | | + * / | ipa_control_list_entry | | hdr.data_offset | + * | | #0 | | | + * Control | +-------------------------+ | | + * value | | ... | | | + * entries | +-------------------------+ | | + * | | ipa_control_list_entry | | hdr.size | + * \ | #hdr.entries - 1 | | | + * +-------------------------+ | | + * | empty space (optional) | | | + * +-------------------------+ <--´ . | + * / | ... | | entry[n].value.offset | + * Data | | ... | | | + * section | | value data for entry #n | <-----´ | + * \ | ... | | + * +-------------------------+ | + * | empty space (optional) | | + * +-------------------------+ <-----------------------------´ * ~~~~ * * The packet header contains the size of the packet, the number of entries, and @@ -56,12 +56,14 @@ * offset ipa_controls_header::data_offset from the beginning of the packet, and * shall be aligned to a multiple of 8 bytes. * - * Entries are described by the ipa_control_value_entry structure. They contain - * the numerical ID of the control, its type, and the number of control values. + * Entries are described by the ipa_control_list_entry structure. They contain + * the numerical ID of the control and an ipa_control_value_entry structure, + * which contains the type and the number of control values. * - * The control values are stored in the data section in the platform's native - * format. The ipa_control_value_entry::offset field stores the offset from the - * beginning of the data section to the values. + * The control values are stored (as ipa_control_list_entry) in the data + * section in the platform's native format. The ipa_control_value_entry::offset + * field stores the offset from the beginning of the data section to the + * values. * * All control values in the data section shall be stored in the same order as * the respective control entries, shall be aligned to a multiple of 8 bytes, @@ -74,59 +76,65 @@ * The following diagram describes the layout of the ControlInfoMap packet. * * ~~~~ - * +-------------------------+ . . - * Header / | ipa_controls_header | | | - * | | | | | - * \ | | | | - * +-------------------------+ | | - * / | ipa_control_info_entry | | hdr.data_offset | - * | | #0 | | | - * Control | +-------------------------+ | | - * info | | ... | | | - * entries | +-------------------------+ | | - * | | ipa_control_info_entry | | hdr.size | - * \ | #hdr.entries - 1 | | | - * +-------------------------+ | | - * | empty space (optional) | | | - * +-------------------------+ <--´ . | - * / | ... | | entry[n].offset | - * Data | | ... | | | - * section | | info data for entry #n | <-----´ | - * \ | ... | | - * +-------------------------+ | - * | empty space (optional) | | - * +-------------------------+ <-------------------------´ + * +------------------------------+ . . + * Header / | ipa_controls_header | | | + * | | | | | + * \ | | | | + * +------------------------------+ | | + * / | ipa_control_info_entry | | hdr.data_offset | + * | | #0 | | | + * Control | +------------------------------+ | | + * info | | ... | | | + * entries | +------------------------------+ | | + * | | ipa_control_info_entry | | | + * \ | #hdr.entries - 1 | | | + * +------------------------------+ | | + * | empty space (optional) | | | + * +------------------------------+ <--´ . . . | + * / | ... | | entry[n].min.offset | + * | | ... | | | | | + * Data | | ... | | | entry[n].max.offset | + * section | | min value data for entry #n | <-----´ | | | + * | | max value data for entry #n | <-------´ | entry[n].def.offset | + * | | def value data for entry #n | <---------´ | + * | | ... | | + * \ | ... | | + * +------------------------------+ | + * | empty space (optional) | | + * +------------------------------+ <-------------------------------´ * ~~~~ * * The packet header is identical to the ControlList packet header. * * Entries are described by the ipa_control_info_entry structure. They contain - * the numerical ID and type of the control. The control info data is stored - * in the data section as described by the following diagram. + * the numerical ID, direction (in/out) of the control, and three + * ipa_control_value_entry structures for the min, max, and def ControlValues + * that make up the ControlInfo. * - * ~~~~ - * +-------------------------+ . - * / | ... | | entry[n].offset - * | +-------------------------+ <-----´ - * | | minimum value (#n) | \ - * Data | +-------------------------+ | - * section | | maximum value (#n) | | Entry #n - * | +-------------------------+ | - * | | default value (#n) | / - * | +-------------------------+ - * \ | ... | - * +-------------------------+ - * ~~~~ + * The control info has no associated data in the data section; + * instead the three control values for min, max, and def are stored in the data section * - * The minimum, maximum and default values are stored in the platform's native - * data format. The ipa_control_info_entry::offset field stores the offset from - * the beginning of the data section to the info data. * - * Info data in the data section shall be stored in the same order as the - * entries array, shall be aligned to a multiple of 8 bytes, and shall be - * contiguous in memory. + * The control values are stored (as ipa_control_list_entry) in the data + * section in the platform's native format. The ipa_control_value_entry::offset + * field stores the offset from the beginning of the data section to the + * values. * - * As for the ControlList packet, empty spaces may be present between the end of + * ipa_control_value_entry structures contain the relevant + * ControlValue information for the ControlInfo's min, max, and def + * respectively, and their associated data is stored in the data section. + * + * The control info has no associated data in the data section. Instead the + * minimum, maximum, and default control values of the control info are stored + * n the data section in the platform's native data format. The + * ipa_control_value_entry::offset field stores the offset from the beginning + * of the data section to the control value data. + * + * All control values in the data section shall be stored in the same order as + * the respective control info entries, in the order of min, max, def, and shall be + * aligned to a multiple of 8 bytes, and shall be contiguous in memory. + * + * As with the ControlList packet, empty spaces may be present between the end of * the entries array and the data section, and after the data section. They * shall be ignored when parsing the packet. */ @@ -192,8 +200,6 @@ static_assert(sizeof(ipa_controls_header) == 32, /** * \struct ipa_control_value_entry * \brief Description of a serialized ControlValue entry - * \var ipa_control_value_entry::id - * The numerical ID of the control * \var ipa_control_value_entry::type * The type of the control (defined by enum ControlType) * \var ipa_control_value_entry::is_array @@ -203,13 +209,25 @@ static_assert(sizeof(ipa_controls_header) == 32, * \var ipa_control_value_entry::offset * The offset in bytes from the beginning of the data section to the control * value data (shall be a multiple of 8 bytes). - * \var ipa_control_value_entry::padding - * Padding bytes (shall be set to 0) + * \var ipa_control_value_entry::reserved + * Reserved for future extensions */ static_assert(sizeof(ipa_control_value_entry) == 16, "Invalid ABI size change for struct ipa_control_value_entry"); +/** + * \struct ipa_control_list_entry + * \brief Description of a serialized ControlList entry + * \var ipa_control_list_entry::id + * The numerical ID of the control + * \var ipa_control_list_entry::value + * The description of the serialized ControlValue + */ + +static_assert(sizeof(ipa_control_list_entry) == 20, + "Invalid ABI size change for struct ipa_control_list_entry"); + /** * \struct ipa_control_info_entry * \brief Description of a serialized ControlInfo entry @@ -217,8 +235,6 @@ static_assert(sizeof(ipa_control_value_entry) == 16, * The numerical ID of the control * \var ipa_control_info_entry::type * The type of the control (defined by enum ControlType) - * \var ipa_control_info_entry::offset - * The offset in bytes from the beginning of the data section to the control * info data (shall be a multiple of 8 bytes) * \var ipa_control_info_entry::direction * The directions in which the control is allowed to be sent. This is a flags @@ -226,9 +242,15 @@ static_assert(sizeof(ipa_control_value_entry) == 16, * metadata). \sa ControlId::Direction * \var ipa_control_info_entry::padding * Padding bytes (shall be set to 0) + * \var ipa_control_info_entry::min + * The description of the serialized ControlValue (min) + * \var ipa_control_info_entry::max + * The description of the serialized ControlValue (max) + * \var ipa_control_info_entry::def + * The description of the serialized ControlValue (def) */ -static_assert(sizeof(ipa_control_info_entry) == 16, +static_assert(sizeof(ipa_control_info_entry) == 64, "Invalid ABI size change for struct ipa_control_info_entry"); } /* namespace libcamera */