diff mbox series

[09/10] v4l2-ctl: add fixed point support

Message ID d56c43b4e411413e1f4224cc8929a1cffd7257b9.1705503477.git.hverkuil-cisco@xs4all.nl
State New
Headers show
Series [01/10,DO,NOT,MERGE] Sync with audio repo | expand

Commit Message

Hans Verkuil Jan. 17, 2024, 3:02 p.m. UTC
Correctly report fixed point control values.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
---
 utils/v4l2-ctl/v4l2-ctl-common.cpp | 156 ++++++++++++++++++++++++-----
 1 file changed, 131 insertions(+), 25 deletions(-)
diff mbox series

Patch

diff --git a/utils/v4l2-ctl/v4l2-ctl-common.cpp b/utils/v4l2-ctl/v4l2-ctl-common.cpp
index c089c332..4b3308f3 100644
--- a/utils/v4l2-ctl/v4l2-ctl-common.cpp
+++ b/utils/v4l2-ctl/v4l2-ctl-common.cpp
@@ -417,6 +417,55 @@  static bool fill_subset(const struct v4l2_query_ext_ctrl &qc, ctrl_subset &subse
 	return false;
 }
 
+static void print_fp(__s64 v, unsigned int fraction_bits)
+{
+	__s64 i, f, mask;
+
+	if (!fraction_bits) {
+		printf("%lld", v);
+		return;
+	}
+
+	mask = (1ULL << fraction_bits) - 1;
+
+	/*
+	 * Note: this function does not support fixed point u64 with
+	 * fraction_bits set to 64. At the moment there is no U64
+	 * control type, but if that is added, then this code will have
+	 * to add support for it.
+	 */
+	if (fraction_bits >= 63)
+		i = v < 0 ? -1 : 0;
+	else
+		i = v / (1LL << fraction_bits);
+
+	f = (v & mask) ? (v < 0 ? -((-v) & mask) : (v & mask)) : 0;
+
+	if (!f) {
+		printf("%lld", i);
+	} else if (fraction_bits < 20) {
+		__u64 div = 1ULL << fraction_bits;
+
+		if (!i && f < 0)
+			printf("-%lld/%llu", -f, div);
+		else if (!i)
+			printf("%lld/%llu", f, div);
+		else if (i < 0 || f < 0)
+			printf("-%lld-%llu/%llu", -i, -f, div);
+		else
+			printf("%lld+%llu/%llu", i, f, div);
+	} else {
+		if (!i && f < 0)
+			printf("-%lld/(2^%u)", -f, fraction_bits);
+		else if (!i)
+			printf("%lld/(2^%u)", f, fraction_bits);
+		else if (i < 0 || f < 0)
+			printf("-%lld-%llu/(2^%u)", -i, -f, fraction_bits);
+		else
+			printf("%lld+%llu/(2^%u)", i, f, fraction_bits);
+	}
+}
+
 static void print_array(const v4l2_query_ext_ctrl &qc, const v4l2_ext_control &ctrl,
 			const ctrl_subset &subset)
 {
@@ -452,7 +501,10 @@  static void print_array(const v4l2_query_ext_ctrl &qc, const v4l2_ext_control &c
 		switch (qc.type) {
 		case V4L2_CTRL_TYPE_U8:
 			for (i = from; i <= to; i++) {
-				printf("%4u", ctrl.p_u8[idx + i]);
+				if (qc.fraction_bits)
+					print_fp(ctrl.p_u8[idx + i], qc.fraction_bits);
+				else
+					printf("%4u", ctrl.p_u8[idx + i]);
 				if (i < to)
 					printf(", ");
 			}
@@ -460,7 +512,10 @@  static void print_array(const v4l2_query_ext_ctrl &qc, const v4l2_ext_control &c
 			break;
 		case V4L2_CTRL_TYPE_U16:
 			for (i = from; i <= to; i++) {
-				printf("%6u", ctrl.p_u16[idx + i]);
+				if (qc.fraction_bits)
+					print_fp(ctrl.p_u16[idx + i], qc.fraction_bits);
+				else
+					printf("%6u", ctrl.p_u16[idx + i]);
 				if (i < to)
 					printf(", ");
 			}
@@ -468,7 +523,10 @@  static void print_array(const v4l2_query_ext_ctrl &qc, const v4l2_ext_control &c
 			break;
 		case V4L2_CTRL_TYPE_U32:
 			for (i = from; i <= to; i++) {
-				printf("%10u", ctrl.p_u32[idx + i]);
+				if (qc.fraction_bits)
+					print_fp(ctrl.p_u32[idx + i], qc.fraction_bits);
+				else
+					printf("%10u", ctrl.p_u32[idx + i]);
 				if (i < to)
 					printf(", ");
 			}
@@ -476,7 +534,10 @@  static void print_array(const v4l2_query_ext_ctrl &qc, const v4l2_ext_control &c
 			break;
 		case V4L2_CTRL_TYPE_INTEGER:
 			for (i = from; i <= to; i++) {
-				printf("%10i", ctrl.p_s32[idx + i]);
+				if (qc.fraction_bits)
+					print_fp(ctrl.p_s32[idx + i], qc.fraction_bits);
+				else
+					printf("%10d", ctrl.p_s32[idx + i]);
 				if (i < to)
 					printf(", ");
 			}
@@ -484,7 +545,10 @@  static void print_array(const v4l2_query_ext_ctrl &qc, const v4l2_ext_control &c
 			break;
 		case V4L2_CTRL_TYPE_INTEGER64:
 			for (i = from; i <= to; i++) {
-				printf("%12lli", ctrl.p_s64[idx + i]);
+				if (qc.fraction_bits)
+					print_fp(ctrl.p_s64[idx + i], qc.fraction_bits);
+				else
+					printf("%12lld", ctrl.p_s64[idx + i]);
 				if (i < to)
 					printf(", ");
 			}
@@ -524,13 +588,13 @@  static void print_value(int fd, const v4l2_query_ext_ctrl &qc, const v4l2_ext_co
 	if (qc.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD) {
 		switch (qc.type) {
 		case V4L2_CTRL_TYPE_U8:
-			printf("%u", *ctrl.p_u8);
+			print_fp(*ctrl.p_u8, qc.fraction_bits);
 			break;
 		case V4L2_CTRL_TYPE_U16:
-			printf("%u", *ctrl.p_u16);
+			print_fp(*ctrl.p_u16, qc.fraction_bits);
 			break;
 		case V4L2_CTRL_TYPE_U32:
-			printf("%u", *ctrl.p_u32);
+			print_fp(*ctrl.p_u32, qc.fraction_bits);
 			break;
 		case V4L2_CTRL_TYPE_STRING:
 			printf("'%s'", safename(ctrl.string).c_str());
@@ -546,7 +610,7 @@  static void print_value(int fd, const v4l2_query_ext_ctrl &qc, const v4l2_ext_co
 	}
 	switch (qc.type) {
 	case V4L2_CTRL_TYPE_INTEGER64:
-		printf("%lld", ctrl.value64);
+		print_fp(ctrl.value64, qc.fraction_bits);
 		break;
 	case V4L2_CTRL_TYPE_MENU:
 	case V4L2_CTRL_TYPE_INTEGER_MENU:
@@ -561,7 +625,7 @@  static void print_value(int fd, const v4l2_query_ext_ctrl &qc, const v4l2_ext_co
 			printf("%d (%lld 0x%llx)", ctrl.value, qmenu.value, qmenu.value);
 		break;
 	default:
-		printf("%d", ctrl.value);
+		print_fp(ctrl.value, qc.fraction_bits);
 		break;
 	}
 }
@@ -574,14 +638,30 @@  static void print_qctrl(int fd, const v4l2_query_ext_ctrl &qc,
 
 	switch (qc.type) {
 	case V4L2_CTRL_TYPE_INTEGER:
-		printf("%31s %#8.8x (int)    : min=%lld max=%lld step=%lld default=%lld",
-				s.c_str(), qc.id, qc.minimum, qc.maximum,
-				qc.step, qc.default_value);
+		printf("%31s %#8.8x (int)    :", s.c_str(), qc.id);
+		if (qc.fraction_bits) {
+			printf(" min="); print_fp(qc.minimum, qc.fraction_bits);
+			printf(" max="); print_fp(qc.maximum, qc.fraction_bits);
+			printf(" step="); print_fp(qc.step, qc.fraction_bits);
+			printf(" default="); print_fp(qc.default_value, qc.fraction_bits);
+		} else {
+			printf(" min=%lld max=%lld step=%lld default=%lld",
+			       qc.minimum, qc.maximum,
+			       qc.step, qc.default_value);
+		}
 		break;
 	case V4L2_CTRL_TYPE_INTEGER64:
-		printf("%31s %#8.8x (int64)  : min=%lld max=%lld step=%lld default=%lld",
-				s.c_str(), qc.id, qc.minimum, qc.maximum,
-				qc.step, qc.default_value);
+		printf("%31s %#8.8x (int64)  :", s.c_str(), qc.id);
+		if (qc.fraction_bits) {
+			printf(" min="); print_fp(qc.minimum, qc.fraction_bits);
+			printf(" max="); print_fp(qc.maximum, qc.fraction_bits);
+			printf(" step="); print_fp(qc.step, qc.fraction_bits);
+			printf(" default="); print_fp(qc.default_value, qc.fraction_bits);
+		} else {
+			printf(" min=%lld max=%lld step=%lld default=%lld",
+			       qc.minimum, qc.maximum,
+			       qc.step, qc.default_value);
+		}
 		break;
 	case V4L2_CTRL_TYPE_STRING:
 		printf("%31s %#8.8x (str)    : min=%lld max=%lld step=%lld",
@@ -609,19 +689,43 @@  static void print_qctrl(int fd, const v4l2_query_ext_ctrl &qc,
 				s.c_str(), qc.id, qc.maximum, qc.default_value);
 		break;
 	case V4L2_CTRL_TYPE_U8:
-		printf("%31s %#8.8x (u8)     : min=%lld max=%lld step=%lld default=%lld",
-				s.c_str(), qc.id, qc.minimum, qc.maximum,
-				qc.step, qc.default_value);
+		printf("%31s %#8.8x (u8)     :", s.c_str(), qc.id);
+		if (qc.fraction_bits) {
+			printf(" min="); print_fp(qc.minimum, qc.fraction_bits);
+			printf(" max="); print_fp(qc.maximum, qc.fraction_bits);
+			printf(" step="); print_fp(qc.step, qc.fraction_bits);
+			printf(" default="); print_fp(qc.default_value, qc.fraction_bits);
+		} else {
+			printf(" min=%lld max=%lld step=%lld default=%lld",
+			       qc.minimum, qc.maximum,
+			       qc.step, qc.default_value);
+		}
 		break;
 	case V4L2_CTRL_TYPE_U16:
-		printf("%31s %#8.8x (u16)    : min=%lld max=%lld step=%lld default=%lld",
-				s.c_str(), qc.id, qc.minimum, qc.maximum,
-				qc.step, qc.default_value);
+		printf("%31s %#8.8x (u16)    :", s.c_str(), qc.id);
+		if (qc.fraction_bits) {
+			printf(" min="); print_fp(qc.minimum, qc.fraction_bits);
+			printf(" max="); print_fp(qc.maximum, qc.fraction_bits);
+			printf(" step="); print_fp(qc.step, qc.fraction_bits);
+			printf(" default="); print_fp(qc.default_value, qc.fraction_bits);
+		} else {
+			printf(" min=%lld max=%lld step=%lld default=%lld",
+			       qc.minimum, qc.maximum,
+			       qc.step, qc.default_value);
+		}
 		break;
 	case V4L2_CTRL_TYPE_U32:
-		printf("%31s %#8.8x (u32)    : min=%lld max=%lld step=%lld default=%lld",
-				s.c_str(), qc.id, qc.minimum, qc.maximum,
-				qc.step, qc.default_value);
+		printf("%31s %#8.8x (u32)    :", s.c_str(), qc.id);
+		if (qc.fraction_bits) {
+			printf(" min="); print_fp(qc.minimum, qc.fraction_bits);
+			printf(" max="); print_fp(qc.maximum, qc.fraction_bits);
+			printf(" step="); print_fp(qc.step, qc.fraction_bits);
+			printf(" default="); print_fp(qc.default_value, qc.fraction_bits);
+		} else {
+			printf(" min=%lld max=%lld step=%lld default=%lld",
+			       qc.minimum, qc.maximum,
+			       qc.step, qc.default_value);
+		}
 		break;
 	case V4L2_CTRL_TYPE_AREA:
 		printf("%31s %#8.8x (area)   :", s.c_str(), qc.id);
@@ -710,6 +814,8 @@  static void print_qctrl(int fd, const v4l2_query_ext_ctrl &qc,
 		for (i = 0; i < qc.nr_of_dims; i++)
 			printf("[%u]", qc.dims[i]);
 	}
+	if (qc.fraction_bits)
+		printf(" fraction_bits=%u", qc.fraction_bits);
 	if (qc.flags)
 		printf(" flags=%s", ctrlflags2s(qc.flags).c_str());
 	printf("\n");