Skip to content

Commit b9ce6f4

Browse files
committed
drivers: video: emul_imager: use the shared imager implementation
Make the emulated imager use the shared implementation of all imagers, making shared implementation of the image sensor drivers be tested by CI. Signed-off-by: Josuah Demangeon <me@josuah.net>
1 parent 541f190 commit b9ce6f4

File tree

3 files changed

+93
-224
lines changed

3 files changed

+93
-224
lines changed

drivers/video/video_emul_imager.c

Lines changed: 62 additions & 223 deletions
Original file line numberDiff line numberDiff line change
@@ -46,27 +46,12 @@ enum emul_imager_fmt_id {
4646
YUYV_320x240,
4747
};
4848

49-
struct emul_imager_mode {
50-
uint8_t fps;
51-
/* List of registers lists to configure the various properties of the sensor.
52-
* This permits to deduplicate the list of registers in case some lare sections
53-
* are repeated across modes, such as the resolution for different FPS.
54-
*/
55-
const struct video_reg *regs[3];
56-
/* More fields can be added according to the needs of the sensor driver */
57-
};
58-
59-
struct emul_imager_config {
60-
struct i2c_dt_spec i2c;
61-
};
62-
49+
/* Wrapper over the struct video_imager_data that extends it with other fields */
6350
struct emul_imager_data {
64-
/* First field is a line buffer for I/O emulation purpose */
65-
uint8_t framebuffer[320 * sizeof(uint16_t)];
66-
/* Other fields are shared with real hardware drivers */
67-
const struct emul_imager_mode *mode;
68-
enum emul_imager_fmt_id fmt_id;
69-
struct video_format fmt;
51+
/* The first field is the default data used by all image sensors */
52+
struct video_imager_data imager;
53+
/* A line buffer for I/O emulation purpose */
54+
uint8_t linebuffer[320 * sizeof(uint16_t)];
7055
};
7156

7257
/* All the I2C registers sent on various scenario */
@@ -108,47 +93,50 @@ static const struct video_reg emul_imager_60fps[] = {
10893
};
10994

11095
/* Description of "modes", that pick lists of registesr that will be all sentto the imager */
111-
struct emul_imager_mode emul_imager_rgb565_320x240_modes[] = {
96+
static struct video_imager_mode emul_imager_rgb565_320x240_modes[] = {
11297
{.fps = 15, .regs = {emul_imager_320x240, emul_imager_rgb565, emul_imager_15fps}},
11398
{.fps = 30, .regs = {emul_imager_320x240, emul_imager_rgb565, emul_imager_30fps}},
11499
{.fps = 60, .regs = {emul_imager_320x240, emul_imager_rgb565, emul_imager_60fps}},
115100
{0},
116101
};
117-
struct emul_imager_mode emul_imager_yuyv_320x240_modes[] = {
102+
static struct video_imager_mode emul_imager_yuyv_320x240_modes[] = {
118103
{.fps = 15, .regs = {emul_imager_320x240, emul_imager_yuyv, emul_imager_15fps}},
119104
{.fps = 30, .regs = {emul_imager_320x240, emul_imager_yuyv, emul_imager_30fps}},
120105
{0},
121106
};
122107

123-
/* Summary of all the modes of all the frame formats, with indexes matching those of fmts[]. */
124-
static const struct emul_imager_mode *emul_imager_modes[] = {
108+
static const struct video_imager_mode *emul_imager_modes[] = {
125109
[RGB565_320x240] = emul_imager_rgb565_320x240_modes,
126110
[YUYV_320x240] = emul_imager_yuyv_320x240_modes,
127111
};
128-
129-
/* Video device capabilities where the supported resolutions and pixel formats are listed.
130-
* The format ID is used as index to fetch the matching mode from the list above.
131-
*/
132-
#define EMUL_IMAGER_VIDEO_FORMAT_CAP(format, width, height) \
133-
{ \
134-
/* For a real imager, the width and height would be macro parameters */ \
135-
.pixelformat = (format), \
136-
.width_min = (width), \
137-
.width_max = (width), \
138-
.width_step = 0, \
139-
.height_min = (height), \
140-
.height_max = (height), \
141-
.height_step = 0, \
142-
}
143-
static const struct video_format_cap fmts[] = {
144-
[RGB565_320x240] = EMUL_IMAGER_VIDEO_FORMAT_CAP(VIDEO_PIX_FMT_RGB565, 320, 240),
145-
[YUYV_320x240] = EMUL_IMAGER_VIDEO_FORMAT_CAP(VIDEO_PIX_FMT_YUYV, 320, 240),
112+
static const struct video_format_cap emul_imager_fmts[] = {
113+
[RGB565_320x240] = VIDEO_IMAGER_FORMAT_CAP(VIDEO_PIX_FMT_RGB565, 320, 240),
114+
[YUYV_320x240] = VIDEO_IMAGER_FORMAT_CAP(VIDEO_PIX_FMT_YUYV, 320, 240),
146115
{0},
147116
};
148117

118+
static int emul_imager_set_fmt(const struct device *const dev, enum video_endpoint_id ep,
119+
struct video_format *fmt)
120+
{
121+
struct emul_imager_data *data = dev->data;
122+
123+
/* For the purpose of simulation, fill the image line buffer with 50% gray, this data
124+
* will be collected by the video_emul_rx driver.
125+
*/
126+
if (fmt->pixelformat == VIDEO_PIX_FMT_RGB565) {
127+
for (int i = 0; i < sizeof(data->linebuffer) / sizeof(uint16_t); i++) {
128+
((uint16_t *)data->linebuffer)[i] = sys_cpu_to_le16(0x7bef);
129+
}
130+
} else {
131+
memset(data->linebuffer, 0x7f, sizeof(data->linebuffer));
132+
}
133+
134+
return video_imager_set_fmt(dev, ep, fmt);
135+
}
136+
149137
static int emul_imager_set_ctrl(const struct device *dev, unsigned int cid, void *value)
150138
{
151-
const struct emul_imager_config *cfg = dev->config;
139+
const struct video_imager_config *cfg = dev->config;
152140

153141
switch (cid) {
154142
case EMUL_IMAGER_CID_CUSTOM:
@@ -160,7 +148,7 @@ static int emul_imager_set_ctrl(const struct device *dev, unsigned int cid, void
160148

161149
static int emul_imager_get_ctrl(const struct device *dev, unsigned int cid, void *value)
162150
{
163-
const struct emul_imager_config *cfg = dev->config;
151+
const struct video_imager_config *cfg = dev->config;
164152
uint32_t reg = 0;
165153
int ret;
166154

@@ -176,178 +164,30 @@ static int emul_imager_get_ctrl(const struct device *dev, unsigned int cid, void
176164
return ret;
177165
}
178166

179-
/* Customize this function according to your "struct emul_imager_mode". */
180-
static int emul_imager_set_mode(const struct device *dev, const struct emul_imager_mode *mode)
181-
{
182-
const struct emul_imager_config *cfg = dev->config;
183-
struct emul_imager_data *data = dev->data;
184-
int ret;
185-
186-
if (data->mode == mode) {
187-
return 0;
188-
}
189-
190-
LOG_DBG("Applying mode %p at %d FPS", mode, mode->fps);
191-
192-
/* Apply all the configuration registers for that mode */
193-
for (int i = 0; i < 2; i++) {
194-
ret = video_write_cci_multi(&cfg->i2c, mode->regs[i]);
195-
if (ret < 0) {
196-
goto err;
197-
}
198-
}
199-
200-
data->mode = mode;
201-
return 0;
202-
err:
203-
LOG_ERR("Could not apply mode %p (%u FPS)", mode, mode->fps);
204-
return ret;
205-
}
206-
207-
static int emul_imager_set_frmival(const struct device *dev, enum video_endpoint_id ep,
208-
struct video_frmival *frmival)
209-
{
210-
struct emul_imager_data *data = dev->data;
211-
struct video_frmival_enum fie = {.format = &data->fmt, .discrete = *frmival};
212-
213-
if (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL) {
214-
return -EINVAL;
215-
}
216-
217-
video_closest_frmival(dev, ep, &fie);
218-
LOG_DBG("Applying frame interval number %u", fie.index);
219-
return emul_imager_set_mode(dev, &emul_imager_modes[data->fmt_id][fie.index]);
220-
}
221-
222-
static int emul_imager_get_frmival(const struct device *dev, enum video_endpoint_id ep,
223-
struct video_frmival *frmival)
224-
{
225-
struct emul_imager_data *data = dev->data;
226-
227-
if (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL) {
228-
return -EINVAL;
229-
}
230-
231-
frmival->numerator = 1;
232-
frmival->denominator = data->mode->fps;
233-
return 0;
234-
}
235-
236-
static int emul_imager_enum_frmival(const struct device *dev, enum video_endpoint_id ep,
237-
struct video_frmival_enum *fie)
238-
{
239-
const struct emul_imager_mode *mode;
240-
size_t fmt_id;
241-
int ret;
242-
243-
if (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL) {
244-
return -EINVAL;
245-
}
246-
247-
ret = video_format_caps_index(fmts, fie->format, &fmt_id);
248-
if (ret < 0) {
249-
return ret;
250-
}
251-
252-
mode = &emul_imager_modes[fmt_id][fie->index];
253-
254-
fie->type = VIDEO_FRMIVAL_TYPE_DISCRETE;
255-
fie->discrete.numerator = 1;
256-
fie->discrete.denominator = mode->fps;
257-
fie->index++;
258-
259-
return mode->fps == 0;
260-
}
261-
262-
static int emul_imager_set_fmt(const struct device *const dev, enum video_endpoint_id ep,
263-
struct video_format *fmt)
264-
{
265-
struct emul_imager_data *data = dev->data;
266-
size_t fmt_id;
267-
int ret;
268-
269-
if (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL) {
270-
return -EINVAL;
271-
}
272-
273-
if (memcmp(&data->fmt, fmt, sizeof(data->fmt)) == 0) {
274-
return 0;
275-
}
276-
277-
ret = video_format_caps_index(fmts, fmt, &fmt_id);
278-
if (ret < 0) {
279-
LOG_ERR("Format %x %ux%u not found", fmt->pixelformat, fmt->width, fmt->height);
280-
return ret;
281-
}
282-
283-
ret = emul_imager_set_mode(dev, &emul_imager_modes[fmt_id][0]);
284-
if (ret < 0) {
285-
return ret;
286-
}
287-
288-
/* For the purpose of simulation, fill the image line buffer with 50% gray, this data
289-
* will be collected by the video_emul_rx driver.
290-
*/
291-
if (fmt->pixelformat == VIDEO_PIX_FMT_RGB565) {
292-
for (int i = 0; i < fmt->width; i++) {
293-
((uint16_t *)data->framebuffer)[i] = sys_cpu_to_le16(0x7bef);
294-
}
295-
} else {
296-
memset(data->framebuffer, 0x7f, fmt->pitch);
297-
}
298-
299-
data->fmt_id = fmt_id;
300-
data->fmt = *fmt;
301-
return 0;
302-
}
303-
304-
static int emul_imager_get_fmt(const struct device *dev, enum video_endpoint_id ep,
305-
struct video_format *fmt)
306-
{
307-
struct emul_imager_data *data = dev->data;
308-
309-
if (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL) {
310-
return -EINVAL;
311-
}
312-
313-
*fmt = data->fmt;
314-
return 0;
315-
}
316-
317-
static int emul_imager_get_caps(const struct device *dev, enum video_endpoint_id ep,
318-
struct video_caps *caps)
319-
{
320-
if (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL) {
321-
return -EINVAL;
322-
}
323-
324-
caps->format_caps = fmts;
325-
return 0;
326-
}
327-
328167
static int emul_imager_set_stream(const struct device *dev, bool enable)
329168
{
330-
const struct emul_imager_config *cfg = dev->config;
169+
const struct video_imager_config *cfg = dev->config;
331170

332171
return video_write_cci_reg(&cfg->i2c, EMUL_IMAGER_REG_CTRL, enable ? 1 : 0);
333172
}
334173

335174
static DEVICE_API(video, emul_imager_driver_api) = {
175+
/* Local implementation */
336176
.set_ctrl = emul_imager_set_ctrl,
337177
.get_ctrl = emul_imager_get_ctrl,
338-
.set_frmival = emul_imager_set_frmival,
339-
.get_frmival = emul_imager_get_frmival,
340-
.enum_frmival = emul_imager_enum_frmival,
341-
.set_format = emul_imager_set_fmt,
342-
.get_format = emul_imager_get_fmt,
343-
.get_caps = emul_imager_get_caps,
344178
.set_stream = emul_imager_set_stream,
179+
.set_format = emul_imager_set_fmt,
180+
/* Default implementation */
181+
.set_frmival = video_imager_set_frmival,
182+
.get_frmival = video_imager_get_frmival,
183+
.enum_frmival = video_imager_enum_frmival,
184+
.get_format = video_imager_get_fmt,
185+
.get_caps = video_imager_get_caps,
345186
};
346187

347188
int emul_imager_init(const struct device *dev)
348189
{
349-
const struct emul_imager_config *cfg = dev->config;
350-
struct video_format fmt;
190+
const struct video_imager_config *cfg = dev->config;
351191
uint32_t sensor_id;
352192
int ret;
353193

@@ -358,43 +198,42 @@ int emul_imager_init(const struct device *dev)
358198

359199
ret = video_read_cci_reg(&cfg->i2c, EMUL_IMAGER_REG_SENSOR_ID, &sensor_id);
360200
if (ret < 0 || sensor_id != EMUL_IMAGER_SENSOR_ID) {
361-
LOG_ERR("Failed to get a correct sensor ID 0x%x", sensor_id);
362-
return ret;
363-
}
364-
365-
ret = video_write_cci_multi(&cfg->i2c, emul_imager_init_regs);
366-
if (ret < 0) {
367-
LOG_ERR("Could not set initial registers");
201+
LOG_ERR("Failed to get a correct sensor ID 0x%x", sensor_id);
368202
return ret;
369203
}
370204

371-
fmt.pixelformat = fmts[0].pixelformat;
372-
fmt.width = fmts[0].width_min;
373-
fmt.height = fmts[0].height_min;
374-
fmt.pitch = fmt.width * 2;
375-
376-
ret = emul_imager_set_fmt(dev, VIDEO_EP_OUT, &fmt);
377-
if (ret < 0) {
378-
LOG_ERR("Failed to set to default format %x %ux%u",
379-
fmt.pixelformat, fmt.width, fmt.height);
380-
}
381-
382-
return 0;
205+
return video_imager_init(dev, emul_imager_init_regs, 0);
383206
}
384207

385208
#define EMUL_IMAGER_DEFINE(inst) \
386209
static struct emul_imager_data emul_imager_data_##inst; \
387210
\
388-
static const struct emul_imager_config emul_imager_cfg_##inst = { \
211+
static struct video_imager_data video_imager_data_##inst; \
212+
\
213+
static const struct video_imager_config video_imager_cfg_##inst = { \
389214
.i2c = I2C_DT_SPEC_INST_GET(inst), \
215+
.modes = emul_imager_modes, \
216+
.fmts = emul_imager_fmts, \
217+
.data = &video_imager_data_##inst, \
218+
.write_multi = video_write_cci_multi, \
390219
}; \
391220
\
392221
DEVICE_DT_INST_DEFINE(inst, &emul_imager_init, NULL, &emul_imager_data_##inst, \
393-
&emul_imager_cfg_##inst, POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, \
222+
&video_imager_cfg_##inst, POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, \
394223
&emul_imager_driver_api);
395224

396225
DT_INST_FOREACH_STATUS_OKAY(EMUL_IMAGER_DEFINE)
397226

227+
/* Simulated MIPI bus */
228+
229+
const uint8_t *video_emul_imager_get_linebuffer(const struct device *dev, size_t *pitch)
230+
{
231+
struct emul_imager_data *data = dev->data;
232+
233+
*pitch = sizeof(data->linebuffer);
234+
return data->linebuffer;
235+
}
236+
398237
/* Simulated I2C bus */
399238

400239
static int emul_imager_transfer_i2c(const struct emul *target, struct i2c_msg msgs[], int num_msgs,

drivers/video/video_emul_imager.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright (c) 2025 tinyVision.ai Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_DRIVERS_VIDEO_EMUL_IMAGER_H_
8+
#define ZEPHYR_DRIVERS_VIDEO_EMUL_IMAGER_H_
9+
10+
/**
11+
* @brief Acces the 1-line buffer written to by the image sensor driver
12+
*
13+
* This 1-line buffer simulates the MIPI link going between an image sensor and a video receiver
14+
* peripheral.
15+
*
16+
* @param dev Image sensor device to query the buffer from.
17+
* @param pitch Pointer filled with the size of this buffer in bytes.
18+
* @retval The 1-line buffer from this device.
19+
*/
20+
const uint8_t *video_emul_imager_get_linebuffer(const struct device *dev, size_t *pitch);
21+
22+
#endif /* ZEPHYR_DRIVERS_VIDEO_EMUL_IMAGER_H_ */

0 commit comments

Comments
 (0)