|
4 | 4 | * SPDX-License-Identifier: Apache-2.0 |
5 | 5 | */ |
6 | 6 |
|
| 7 | +#include <stdio.h> |
| 8 | + |
7 | 9 | #include <zephyr/drivers/video.h> |
8 | 10 | #include <zephyr/drivers/video-controls.h> |
9 | 11 | #include <zephyr/logging/log.h> |
@@ -67,6 +69,7 @@ int video_init_ctrl(struct video_ctrl *ctrl, const struct device *dev, uint32_t |
67 | 69 | int ret; |
68 | 70 | uint32_t flags; |
69 | 71 | enum video_ctrl_type type; |
| 72 | + struct video_ctrl *vc; |
70 | 73 | struct video_device *vdev = video_find_vdev(dev); |
71 | 74 |
|
72 | 75 | if (!vdev) { |
@@ -95,6 +98,14 @@ int video_init_ctrl(struct video_ctrl *ctrl, const struct device *dev, uint32_t |
95 | 98 | ctrl->def = def; |
96 | 99 | ctrl->val = def; |
97 | 100 |
|
| 101 | + /* Insert in an ascending order of ctrl's id */ |
| 102 | + SYS_DLIST_FOR_EACH_CONTAINER(&vdev->ctrls, vc, node) { |
| 103 | + if (vc->id > ctrl->id) { |
| 104 | + sys_dlist_insert(&vc->node, &ctrl->node); |
| 105 | + return 0; |
| 106 | + } |
| 107 | + } |
| 108 | + |
98 | 109 | sys_dlist_append(&vdev->ctrls, &ctrl->node); |
99 | 110 |
|
100 | 111 | return 0; |
@@ -173,3 +184,131 @@ int video_set_ctrl(const struct device *dev, struct video_control *control) |
173 | 184 |
|
174 | 185 | return 0; |
175 | 186 | } |
| 187 | + |
| 188 | +static inline const char *video_get_ctrl_name(uint32_t id) |
| 189 | +{ |
| 190 | + switch (id) { |
| 191 | + /* User controls */ |
| 192 | + case VIDEO_CID_BRIGHTNESS: |
| 193 | + return "Brightness"; |
| 194 | + case VIDEO_CID_CONTRAST: |
| 195 | + return "Contrast"; |
| 196 | + case VIDEO_CID_SATURATION: |
| 197 | + return "Saturation"; |
| 198 | + case VIDEO_CID_HUE: |
| 199 | + return "Hue"; |
| 200 | + case VIDEO_CID_EXPOSURE: |
| 201 | + return "Exposure"; |
| 202 | + case VIDEO_CID_GAIN: |
| 203 | + return "Gain"; |
| 204 | + case VIDEO_CID_HFLIP: |
| 205 | + return "Horizontal Flip"; |
| 206 | + case VIDEO_CID_VFLIP: |
| 207 | + return "Vertical Flip"; |
| 208 | + case VIDEO_CID_POWER_LINE_FREQUENCY: |
| 209 | + return "Power Line Frequency"; |
| 210 | + |
| 211 | + /* Camera controls */ |
| 212 | + case VIDEO_CID_ZOOM_ABSOLUTE: |
| 213 | + return "Zoom, Absolute"; |
| 214 | + |
| 215 | + /* JPEG encoder controls */ |
| 216 | + case VIDEO_CID_JPEG_COMPRESSION_QUALITY: |
| 217 | + return "Compression Quality"; |
| 218 | + |
| 219 | + /* Image processing controls */ |
| 220 | + case VIDEO_CID_PIXEL_RATE: |
| 221 | + return "Pixel Rate"; |
| 222 | + case VIDEO_CID_TEST_PATTERN: |
| 223 | + return "Test Pattern"; |
| 224 | + default: |
| 225 | + return NULL; |
| 226 | + } |
| 227 | +} |
| 228 | + |
| 229 | +int video_query_ctrl(const struct device *dev, struct video_ctrl_query *cq) |
| 230 | +{ |
| 231 | + int ret; |
| 232 | + struct video_device *vdev; |
| 233 | + struct video_ctrl *ctrl = NULL; |
| 234 | + |
| 235 | + if (cq->id & VIDEO_CTRL_FLAG_NEXT_CTRL) { |
| 236 | + vdev = video_find_vdev(dev); |
| 237 | + cq->id &= ~VIDEO_CTRL_FLAG_NEXT_CTRL; |
| 238 | + while (vdev) { |
| 239 | + SYS_DLIST_FOR_EACH_CONTAINER(&vdev->ctrls, ctrl, node) { |
| 240 | + if (ctrl->id > cq->id) { |
| 241 | + goto fill_query; |
| 242 | + } |
| 243 | + } |
| 244 | + vdev = video_find_vdev(vdev->src_dev); |
| 245 | + } |
| 246 | + return -ENOTSUP; |
| 247 | + } |
| 248 | + |
| 249 | + ret = video_find_ctrl(dev, cq->id, &ctrl); |
| 250 | + if (ret) { |
| 251 | + return ret; |
| 252 | + } |
| 253 | + |
| 254 | +fill_query: |
| 255 | + cq->id = ctrl->id; |
| 256 | + cq->type = ctrl->type; |
| 257 | + cq->flags = ctrl->flags; |
| 258 | + cq->min = ctrl->min; |
| 259 | + cq->max = ctrl->max; |
| 260 | + cq->step = ctrl->step; |
| 261 | + cq->def = ctrl->def; |
| 262 | + cq->name = video_get_ctrl_name(cq->id); |
| 263 | + |
| 264 | + return 0; |
| 265 | +} |
| 266 | + |
| 267 | +void video_print_ctrl(const struct device *const dev, const struct video_ctrl_query *const cq) |
| 268 | +{ |
| 269 | + uint8_t i = 0; |
| 270 | + const char *type = NULL; |
| 271 | + char typebuf[8]; |
| 272 | + |
| 273 | + __ASSERT(dev && cq, "Invalid arguments"); |
| 274 | + |
| 275 | + /* Get type of the control */ |
| 276 | + switch (cq->type) { |
| 277 | + case VIDEO_CTRL_TYPE_BOOLEAN: |
| 278 | + type = "bool"; |
| 279 | + break; |
| 280 | + case VIDEO_CTRL_TYPE_INTEGER: |
| 281 | + type = "int"; |
| 282 | + break; |
| 283 | + case VIDEO_CTRL_TYPE_INTEGER64: |
| 284 | + type = "int64"; |
| 285 | + break; |
| 286 | + case VIDEO_CTRL_TYPE_MENU: |
| 287 | + type = "menu"; |
| 288 | + break; |
| 289 | + case VIDEO_CTRL_TYPE_STRING: |
| 290 | + type = "string"; |
| 291 | + break; |
| 292 | + default: |
| 293 | + break; |
| 294 | + } |
| 295 | + snprintf(typebuf, sizeof(typebuf), "(%s)", type); |
| 296 | + |
| 297 | + /* Get current value of the control */ |
| 298 | + struct video_control vc = {.id = cq->id}; |
| 299 | + |
| 300 | + video_get_ctrl(dev, &vc); |
| 301 | + |
| 302 | + /* Print the control information */ |
| 303 | + if (cq->type == VIDEO_CTRL_TYPE_INTEGER64) { |
| 304 | + LOG_INF("%32s 0x%08x %-8s (flags=0x%02x) : min=%lld max=%lld step=%lld " |
| 305 | + "default=%lld value=%lld ", |
| 306 | + cq->name, cq->id, typebuf, cq->flags, cq->range.min64, cq->range.max64, |
| 307 | + cq->range.step64, cq->range.def64, vc.val64); |
| 308 | + } else { |
| 309 | + LOG_INF("%32s 0x%08x %-8s (flags=0x%02x) : min=%d max=%d step=%d default=%d " |
| 310 | + "value=%d ", |
| 311 | + cq->name, cq->id, typebuf, cq->flags, cq->range.min, cq->range.max, |
| 312 | + cq->range.step, cq->range.def, vc.val); |
| 313 | + } |
| 314 | +} |
0 commit comments