arch/sim: add v4l2 driver for sim

communicate with Linux host v4l2 drivers

Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
This commit is contained in:
Peter Bee
2022-11-22 16:13:36 +08:00
committed by Xiang Xiao
parent 77504aa1b5
commit a5a1a68a25
8 changed files with 800 additions and 10 deletions

View File

@@ -265,6 +265,33 @@ endchoice
endif
config SIM_VIDEO
bool "Simulated video support"
depends on VIDEO
default y
if SIM_VIDEO
choice
prompt "Simulated video device type"
default SIM_VIDEO_V4L2
config SIM_VIDEO_V4L2
bool "V4L2 camera support on sim"
depends on HOST_LINUX
endchoice
config HOST_VIDEO_DEV_PATH
string "Host video device path"
default "/dev/video0"
config SIM_VIDEO_DEV_PATH
string "NuttX video device path"
default "/dev/video"
endif
menu "Simulated Graphics/Input"
config SIM_X11FB
@@ -462,10 +489,10 @@ config SIM_UART_NUMBER
Under simulation, a NuttX port can be bound to a serial
port on the host machine. This way NuttX can access the
host's hardware directly.
There are two possibilities regarding the host's port:
it can be either a physical one, or a simulated one.
In case of a physical port, NuttX will be able to open
this port and communicate with any actual hardware that
it is connected to. This is useful for testing code that
@@ -473,18 +500,18 @@ config SIM_UART_NUMBER
In order for this to work, NuttX port name must be set to
the same name that the host is using for this port (e.g.
/dev/ttyUSB0).
Alternativelly, a "simulated" host port may be used to.
This is useful if you need to also simulate the external
hardware, or to have NuttX communicate with any other
software in your system.
You can create a "simulated" port in your host,
by running:
socat PTY,link=/dev/ttySIM0 PTY,link=/dev/ttyNX0
stty -F /dev/ttySIM0 raw
stty -F /dev/ttyNX0 raw
This will create two new ports on your system.
NuttX will use the ttySIM0 port, and another software
may open and use the ttyNX0 port.
@@ -498,7 +525,7 @@ config SIM_UART_BUFFER_SIZE
---help---
The size of the transmit and receive buffers of the
simulated UART ports.
Note that all ports will have the same buffer size.
config SIM_UART0_NAME
@@ -508,7 +535,7 @@ config SIM_UART0_NAME
---help---
This is the name of the simulated UART port.
The port will be mounted in NuttX under this name.
A UART port must also exist on the host system
with the exact same name specified here.
@@ -519,7 +546,7 @@ config SIM_UART1_NAME
---help---
This is the name of the simulated UART port.
The port will be mounted in NuttX under this name.
A UART port must also exist on the host system
with the exact same name specified here.
@@ -530,7 +557,7 @@ config SIM_UART2_NAME
---help---
This is the name of the simulated UART port.
The port will be mounted in NuttX under this name.
A UART port must also exist on the host system
with the exact same name specified here.
@@ -541,7 +568,7 @@ config SIM_UART3_NAME
---help---
This is the name of the simulated UART port.
The port will be mounted in NuttX under this name.
A UART port must also exist on the host system
with the exact same name specified here.

View File

@@ -204,6 +204,12 @@ ifeq ($(CONFIG_SIM_SOUND_ALSA),y)
STDLIBS += -lmad
endif
ifeq ($(CONFIG_SIM_VIDEO_V4L2),y)
HOSTSRCS += sim_host_v4l2.c
CSRCS += sim_video.c
STDLIBS += -lv4l2
endif
ifeq ($(CONFIG_SIM_HOSTFS),y)
HOSTSRCS += sim_hostfs.c

View File

@@ -0,0 +1,364 @@
/****************************************************************************
* arch/sim/src/sim/posix/sim_host_v4l2.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <linux/videodev2.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include "sim_hostvideo.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define MAX_REQBUFS 3
#define WARN(fmt, ...) \
syslog(LOG_WARNING, "sim_host_video: " fmt "\n", ##__VA_ARGS__)
/****************************************************************************
* Private Types
****************************************************************************/
struct host_video_dev_s
{
int fd;
void *addrs[MAX_REQBUFS];
size_t buflen[MAX_REQBUFS];
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
static int host_video_ioctl(int fd, int request, void *arg)
{
int r;
do
{
r = ioctl(fd, request, arg);
}
while (-1 == r && EINTR == errno);
return r;
}
/****************************************************************************
* Public Functions
****************************************************************************/
bool host_video_is_available(const char *host_video_dev_path)
{
return access(host_video_dev_path, F_OK) == 0;
}
struct host_video_dev_s *host_video_init(const char *host_video_dev_path)
{
int fd;
struct host_video_dev_s *vdev;
fd = open(host_video_dev_path, O_RDWR | O_NONBLOCK);
if (fd < 0)
{
perror(host_video_dev_path);
return NULL;
}
vdev = calloc(1, sizeof(*vdev));
if (vdev == NULL)
{
perror("host_video_init failed");
close(fd);
return NULL;
}
vdev->fd = fd;
return vdev;
}
int host_video_dq_buf(struct host_video_dev_s *vdev, uint8_t *addr,
uint32_t size)
{
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
/* Dequeue a buffer */
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_DQBUF, &buf))
{
switch (errno)
{
case EAGAIN:
/* No buffer in the outgoing queue */
return 0;
default:
perror("VIDIOC_DQBUF");
return -errno;
}
}
if (size > buf.bytesused)
{
size = buf.bytesused;
}
memcpy(addr, vdev->addrs[buf.index], size);
if (-1 == ioctl(vdev->fd, VIDIOC_QBUF, &buf))
{
perror("VIDIOC_QBUF");
return -errno;
}
return size;
}
int host_video_uninit(struct host_video_dev_s *vdev)
{
if (vdev != NULL)
{
close(vdev->fd);
free(vdev);
}
return 0;
}
int host_video_start_capture(struct host_video_dev_s *vdev)
{
struct v4l2_buffer buf;
struct v4l2_requestbuffers reqbuf;
enum v4l2_buf_type type;
int i;
/* VIDIOC_REQBUFS initiate user pointer I/O */
memset(&reqbuf, 0, sizeof(reqbuf));
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_MMAP;
reqbuf.count = MAX_REQBUFS;
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_REQBUFS, &reqbuf))
{
perror("VIDIOC_REQBUFS");
return -errno;
}
if (reqbuf.count < 2)
{
errno = ENOMEM;
perror("Not enough buffers");
return -ENOMEM;
}
for (i = 0; i < reqbuf.count; i++)
{
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_QUERYBUF, &buf))
{
perror("VIDIOC_QUERYBUF");
goto err_out;
}
vdev->addrs[i] = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
MAP_SHARED, vdev->fd, buf.m.offset);
if (vdev->addrs[i] == MAP_FAILED)
{
perror("Mmap failed");
goto err_out;
}
vdev->buflen[i] = buf.length;
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_QBUF, &buf))
{
perror("VIDIOC_QBUF");
goto err_out;
}
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_STREAMON, &type))
{
perror("VIDIOC_STREAMON");
goto err_out;
}
return 0;
err_out:
while (i--)
{
munmap(vdev->addrs[i], vdev->buflen[i]);
vdev->addrs[i] = NULL;
vdev->buflen[i] = 0;
}
return -errno;
}
int host_video_stop_capture(struct host_video_dev_s *vdev)
{
enum v4l2_buf_type type;
int i;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_STREAMOFF, &type))
{
perror("VIDIOC_STREAMOFF");
return -errno;
}
for (i = 0; i < MAX_REQBUFS; i++)
{
if (vdev->buflen[i] == 0)
{
break;
}
munmap(vdev->addrs[i], vdev->buflen[i]);
vdev->addrs[i] = NULL;
vdev->buflen[i] = 0;
}
return 0;
}
int host_video_set_fmt(struct host_video_dev_s *vdev,
uint16_t width, uint16_t height, uint32_t fmt,
uint32_t denom, uint32_t numer)
{
struct v4l2_format v4l2_fmt;
struct v4l2_streamparm streamparm;
memset(&v4l2_fmt, 0, sizeof(v4l2_fmt));
v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_fmt.fmt.pix.width = width;
v4l2_fmt.fmt.pix.height = height;
v4l2_fmt.fmt.pix.pixelformat = fmt;
v4l2_fmt.fmt.pix.field = V4L2_FIELD_NONE;
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_S_FMT, &v4l2_fmt))
{
perror("VIDIOC_S_FMT");
return -errno;
}
memset(&streamparm, 0, sizeof(streamparm));
streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_G_PARM, &streamparm))
{
perror("VIDIOC_G_PARM");
return -errno;
}
streamparm.parm.capture.capturemode |= V4L2_CAP_TIMEPERFRAME;
streamparm.parm.capture.timeperframe.numerator = numer;
streamparm.parm.capture.timeperframe.denominator = denom;
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_S_PARM, &streamparm))
{
perror("VIDIOC_S_PARM");
return -errno;
}
return 0;
}
int host_video_try_fmt(struct host_video_dev_s *vdev,
uint16_t width, uint16_t height, uint32_t fmt,
uint32_t denom, uint32_t numer)
{
struct v4l2_format v4l2_fmt;
struct v4l2_frmivalenum v4l2_frmival;
memset(&v4l2_fmt, 0, sizeof(v4l2_fmt));
v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_fmt.fmt.pix.width = width;
v4l2_fmt.fmt.pix.height = height;
v4l2_fmt.fmt.pix.pixelformat = fmt;
v4l2_fmt.fmt.pix.field = V4L2_FIELD_NONE;
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_TRY_FMT, &v4l2_fmt))
{
perror("VIDIOC_TRY_FMT");
return -errno;
}
if (v4l2_fmt.fmt.pix.pixelformat != fmt)
{
WARN("Pixel format not supported");
return -EINVAL;
}
/* Need not check frame interval for STILL type */
if (!denom)
{
memset(&v4l2_frmival, 0, sizeof(v4l2_frmival));
v4l2_frmival.width = width;
v4l2_frmival.height = height;
v4l2_frmival.pixel_format = fmt;
while (host_video_ioctl(vdev->fd, VIDIOC_ENUM_FRAMEINTERVALS,
&v4l2_frmival) == 0)
{
if (v4l2_frmival.type == V4L2_FRMSIZE_TYPE_DISCRETE &&
v4l2_frmival.discrete.denominator == denom &&
v4l2_frmival.discrete.numerator == numer)
{
return 0;
}
v4l2_frmival.index++;
}
WARN("Invalid frame interval, fallback to default");
}
return 0;
}

View File

@@ -0,0 +1,55 @@
/****************************************************************************
* arch/sim/src/sim/sim_hostvideo.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_SIM_SRC_SIM_SIM_HOSTVIDEO_H
#define __ARCH_SIM_SRC_SIM_SIM_HOSTVIDEO_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdbool.h>
#include <stdint.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
struct host_video_dev_s;
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
bool host_video_is_available(const char *host_video_dev_path);
struct host_video_dev_s *host_video_init(const char *host_video_dev_path);
int host_video_uninit(struct host_video_dev_s *vdev);
int host_video_start_capture(struct host_video_dev_s *vdev);
int host_video_stop_capture(struct host_video_dev_s *vdev);
int host_video_dq_buf(struct host_video_dev_s *vdev, uint8_t *addr,
uint32_t size);
int host_video_set_fmt(struct host_video_dev_s *vdev,
uint16_t width, uint16_t height, uint32_t fmt,
uint32_t denom, uint32_t numer);
int host_video_try_fmt(struct host_video_dev_s *vdev,
uint16_t width, uint16_t height, uint32_t fmt,
uint32_t denom, uint32_t numer);
#endif /* __ARCH_SIM_SRC_SIM_SIM_HOSTVIDEO_H */

View File

@@ -195,6 +195,10 @@ static int sim_loop_task(int argc, char **argv)
sim_audio_loop();
#endif
#ifdef CONFIG_SIM_VIDEO
sim_video_loop();
#endif
#ifdef CONFIG_MOTOR_FOC_DUMMY
/* Update simulated FOC device */

View File

@@ -357,6 +357,13 @@ struct spi_dev_s *sim_spi_initialize(const char *filename);
int sim_spi_uninitialize(struct spi_dev_s *dev);
#endif
/* up_video.c ***************************************************************/
#ifdef CONFIG_SIM_VIDEO
int sim_video_initialize(void);
void sim_video_loop(void);
#endif
/* Debug ********************************************************************/
#ifdef CONFIG_STACK_COLORATION

View File

@@ -0,0 +1,314 @@
/****************************************************************************
* arch/sim/src/sim/sim_video.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <errno.h>
#include <string.h>
#include <nuttx/video/imgsensor.h>
#include <nuttx/video/imgdata.h>
#include <nuttx/video/video.h>
#include "sim_hostvideo.h"
#include "sim_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
typedef struct
{
imgdata_capture_t capture_cb;
uint32_t buf_size;
uint8_t *next_buf;
struct host_video_dev_s *vdev;
} sim_video_priv_t;
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* Video image sensor operations */
static bool sim_video_is_available(void);
static int sim_video_init(void);
static int sim_video_uninit(void);
static const char *sim_video_get_driver_name(void);
static int sim_video_validate_frame_setting(imgsensor_stream_type_t type,
uint8_t nr_datafmt,
imgsensor_format_t *datafmts,
imgsensor_interval_t *interval);
static int sim_video_start_capture(imgsensor_stream_type_t type,
uint8_t nr_datafmt,
imgsensor_format_t *datafmts,
imgsensor_interval_t *interval);
static int sim_video_stop_capture(imgsensor_stream_type_t type);
/* Video image data operations */
static int sim_video_data_init(void);
static int sim_video_data_uninit(void);
static int sim_video_data_validate_frame_setting(uint8_t nr_datafmt,
imgdata_format_t *datafmt,
imgdata_interval_t *interv);
static int sim_video_data_start_capture(uint8_t nr_datafmt,
imgdata_format_t *datafmt,
imgdata_interval_t *interval,
imgdata_capture_t callback);
static int sim_video_data_stop_capture(void);
static int sim_video_data_validate_buf(uint8_t *addr, uint32_t size);
static int sim_video_data_set_buf(uint8_t *addr, uint32_t size);
static uint32_t imgdata_fmt_to_v4l2(uint32_t pixelformat);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct imgsensor_ops_s g_sim_video_ops =
{
.is_available = sim_video_is_available,
.init = sim_video_init,
.uninit = sim_video_uninit,
.get_driver_name = sim_video_get_driver_name,
.validate_frame_setting = sim_video_validate_frame_setting,
.start_capture = sim_video_start_capture,
.stop_capture = sim_video_stop_capture,
};
static const struct imgdata_ops_s g_sim_video_data_ops =
{
.init = sim_video_data_init,
.uninit = sim_video_data_uninit,
.validate_buf = sim_video_data_validate_buf,
.set_buf = sim_video_data_set_buf,
.validate_frame_setting = sim_video_data_validate_frame_setting,
.start_capture = sim_video_data_start_capture,
.stop_capture = sim_video_data_stop_capture,
};
static sim_video_priv_t g_sim_video_priv;
/****************************************************************************
* Private Functions
****************************************************************************/
/* Sensor op functions are mostly dummy */
static bool sim_video_is_available(void)
{
return host_video_is_available(CONFIG_HOST_VIDEO_DEV_PATH);
}
static int sim_video_init(void)
{
return 0;
}
static int sim_video_uninit(void)
{
return 0;
}
static const char *sim_video_get_driver_name(void)
{
return "V4L2 NuttX Sim Driver";
}
static int sim_video_validate_frame_setting(imgsensor_stream_type_t type,
uint8_t nr_fmt,
imgsensor_format_t *fmt,
imgsensor_interval_t *interval)
{
return 0;
}
static int sim_video_start_capture(imgsensor_stream_type_t type,
uint8_t nr_fmt,
imgsensor_format_t *fmt,
imgsensor_interval_t *interval)
{
return 0;
}
static int sim_video_stop_capture(imgsensor_stream_type_t type)
{
return 0;
}
/* Data op functions do all the real work */
static int sim_video_data_init(void)
{
memset(&g_sim_video_priv, 0, sizeof(g_sim_video_priv));
g_sim_video_priv.vdev = host_video_init(CONFIG_HOST_VIDEO_DEV_PATH);
if (g_sim_video_priv.vdev == NULL)
{
return -ENODEV;
}
return 0;
}
static int sim_video_data_uninit(void)
{
return host_video_uninit(g_sim_video_priv.vdev);
}
static int sim_video_data_validate_buf(uint8_t *addr, uint32_t size)
{
if (!addr || ((uintptr_t)(addr) & 0x1f))
{
return -EINVAL;
}
return 0;
}
static int sim_video_data_set_buf(uint8_t *addr, uint32_t size)
{
g_sim_video_priv.next_buf = addr;
g_sim_video_priv.buf_size = size;
return 0;
}
static int sim_video_data_validate_frame_setting(uint8_t nr_datafmt,
imgdata_format_t *datafmt,
imgdata_interval_t *interv)
{
uint32_t v4l2_fmt;
if (nr_datafmt > 1)
{
return -ENOTSUP;
}
v4l2_fmt = imgdata_fmt_to_v4l2(datafmt->pixelformat);
return host_video_try_fmt(g_sim_video_priv.vdev, datafmt->width,
datafmt->height, v4l2_fmt, interv->denominator,
interv->numerator);
}
static int sim_video_data_start_capture(uint8_t nr_datafmt,
imgdata_format_t *datafmt,
imgdata_interval_t *interval,
imgdata_capture_t callback)
{
int ret;
ret = host_video_set_fmt(g_sim_video_priv.vdev,
datafmt[IMGDATA_FMT_MAIN].width,
datafmt[IMGDATA_FMT_MAIN].height,
imgdata_fmt_to_v4l2(
datafmt[IMGDATA_FMT_MAIN].pixelformat),
interval->denominator, interval->numerator);
if (ret < 0)
{
return ret;
}
g_sim_video_priv.capture_cb = callback;
return host_video_start_capture(g_sim_video_priv.vdev);
}
static int sim_video_data_stop_capture(void)
{
g_sim_video_priv.next_buf = NULL;
return host_video_stop_capture(g_sim_video_priv.vdev);
}
/* Helper functions */
static uint32_t imgdata_fmt_to_v4l2(uint32_t pixelformat)
{
uint32_t fourcc;
switch (pixelformat)
{
case IMGDATA_PIX_FMT_YUV420P:
fourcc = V4L2_PIX_FMT_YUV420;
break;
case IMGDATA_PIX_FMT_YUYV:
fourcc = V4L2_PIX_FMT_YUYV;
break;
case IMGDATA_PIX_FMT_JPEG_WITH_SUBIMG:
fourcc = V4L2_PIX_FMT_JPEG;
break;
case IMGDATA_PIX_FMT_JPEG:
fourcc = V4L2_PIX_FMT_JPEG;
break;
case IMGDATA_PIX_FMT_RGB565:
fourcc = V4L2_PIX_FMT_RGB565;
break;
case IMGDATA_PIX_FMT_UYVY:
fourcc = V4L2_PIX_FMT_UYVY;
break;
default:
/* Unsupported format */
fourcc = 0;
}
return fourcc;
}
/****************************************************************************
* Public Functions
****************************************************************************/
int sim_video_initialize(void)
{
imgsensor_register(&g_sim_video_ops);
imgdata_register(&g_sim_video_data_ops);
return 0;
}
int sim_video_uninitialize(void)
{
return 0;
}
void sim_video_loop(void)
{
int ret;
if (g_sim_video_priv.next_buf)
{
ret = host_video_dq_buf(g_sim_video_priv.vdev,
g_sim_video_priv.next_buf,
g_sim_video_priv.buf_size);
if (ret > 0)
{
g_sim_video_priv.capture_cb(0, ret);
}
}
}

View File

@@ -47,6 +47,7 @@
#include <nuttx/serial/uart_rpmsg.h>
#include <nuttx/timers/oneshot.h>
#include <nuttx/video/fb.h>
#include <nuttx/video/video.h>
#include <nuttx/timers/oneshot.h>
#include <nuttx/wireless/pktradio.h>
#include <nuttx/wireless/bluetooth/bt_null.h>
@@ -291,6 +292,18 @@ int sim_bringup(void)
}
#endif
#ifdef CONFIG_SIM_VIDEO
/* Initialize and register the simulated video driver */
ret = video_initialize(CONFIG_SIM_VIDEO_DEV_PATH);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: video_initialize() failed: %d\n", ret);
}
sim_video_initialize();
#endif
#ifdef CONFIG_LCD
ret = board_lcd_initialize();