1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <getopt.h> /* getopt_long() */
5 #include <fcntl.h> /* low-level i/o */
6 #include <inttypes.h>
7 #include <unistd.h>
8 #include <errno.h>
9 #include <sys/ioctl.h>
10 #include <pthread.h>
11
12 #include <linux/videodev2.h>
13 #include "uAPI2/rk_aiq_user_api2_sysctl.h"
14 #include "common/mediactl/mediactl.h"
15
16 #define CLEAR(x) memset(&(x), 0, sizeof(x))
17 #define DBG(...) do { if(!silent) printf("DBG: " __VA_ARGS__);} while(0)
18 #define ERR(...) do { fprintf(stderr, "ERR: " __VA_ARGS__); } while (0)
19
20
21 /* Private v4l2 event */
22 #define CIFISP_V4L2_EVENT_STREAM_START \
23 (V4L2_EVENT_PRIVATE_START + 1)
24 #define CIFISP_V4L2_EVENT_STREAM_STOP \
25 (V4L2_EVENT_PRIVATE_START + 2)
26
27 #define RKAIQ_FILE_PATH_LEN 64
28 #define RKAIQ_FLASH_NUM_MAX 2
29
30 /* 1 vicap + 2 mipi + 1 bridge + 1 redundance */
31 #define MAX_MEDIA_NODES 16
32
33 #define IQ_PATH "/etc/iqfiles/"
34
35 static int silent = 0;
36 static int width = 2688;
37 static int height = 1520;
38 static int has_mul_cam = 0;
39
40 struct rkaiq_media_info {
41 char sd_isp_path[RKAIQ_FILE_PATH_LEN];
42 char vd_params_path[RKAIQ_FILE_PATH_LEN];
43 char vd_stats_path[RKAIQ_FILE_PATH_LEN];
44 char mainpath[RKAIQ_FILE_PATH_LEN];
45 char sensor_entity_name[32];
46
47 char mdev_path[32];
48 int available;
49 rk_aiq_sys_ctx_t* aiq_ctx;
50
51 pthread_t pid;
52 };
53
54 static struct rkaiq_media_info media_infos[MAX_MEDIA_NODES];
55
errno_exit(const char * s)56 static void errno_exit(const char *s)
57 {
58 ERR("%s error %d, %s\n", s, errno, strerror(errno));
59 exit(EXIT_FAILURE);
60 }
61
xioctl(int fh,int request,void * arg)62 static int xioctl(int fh, int request, void *arg)
63 {
64 int r;
65
66 do {
67 r = ioctl(fh, request, arg);
68 } while (-1 == r && EINTR == errno);
69
70 return r;
71 }
72
73
rkaiq_get_devname(struct media_device * device,const char * name,char * dev_name)74 static int rkaiq_get_devname(struct media_device *device, const char *name, char *dev_name)
75 {
76 const char *devname;
77 struct media_entity *entity = NULL;
78
79 entity = media_get_entity_by_name(device, name, strlen(name));
80 if (!entity)
81 return -1;
82
83 devname = media_entity_get_devname(entity);
84
85 if (!devname) {
86 fprintf(stderr, "can't find %s device path!", name);
87 return -1;
88 }
89
90 strncpy(dev_name, devname, RKAIQ_FILE_PATH_LEN);
91
92 DBG("get %s devname: %s\n", name, dev_name);
93
94 return 0;
95 }
96
rkaiq_get_media_info(struct rkaiq_media_info * media_info)97 int rkaiq_get_media_info(struct rkaiq_media_info *media_info)
98 {
99 struct media_device *device = NULL;
100 const char *sensor_name;
101 int ret;
102
103 device = media_device_new (media_info->mdev_path);
104 if (!device)
105 return -ENOMEM;
106 /* Enumerate entities, pads and links. */
107 ret = media_device_enumerate (device);
108 if (ret)
109 return ret;
110 if (!ret) {
111 /* Try rkisp */
112 ret = rkaiq_get_devname(device, "rkisp-isp-subdev",
113 media_info->sd_isp_path);
114 ret |= rkaiq_get_devname(device, "rkisp-input-params",
115 media_info->vd_params_path);
116 ret |= rkaiq_get_devname(device, "rkisp-statistics",
117 media_info->vd_stats_path);
118 ret |= rkaiq_get_devname(device, "rkisp_mainpath",
119 media_info->mainpath);
120 }
121 if (ret) {
122 fprintf(stderr, "Cound not find rkisp dev names, skipped %s\n", media_info->mdev_path);
123 media_device_unref (device);
124 return ret;
125 }
126
127 sensor_name = rk_aiq_uapi2_sysctl_getBindedSnsEntNmByVd(media_info->mainpath);
128 if (sensor_name == NULL || strlen(sensor_name) == 0) {
129 fprintf(stderr, "ERR: No sensor attached to %s\n", media_info->mdev_path);
130 media_device_unref (device);
131 return -EINVAL;
132 }
133
134 strcpy(media_info->sensor_entity_name, sensor_name);
135
136 media_device_unref (device);
137
138 return ret;
139 }
140
init_engine(struct rkaiq_media_info * media_info)141 static void init_engine(struct rkaiq_media_info *media_info)
142 {
143 int index;
144
145 media_info->aiq_ctx = rk_aiq_uapi2_sysctl_init(media_info->sensor_entity_name,
146 IQ_PATH, NULL, NULL);
147 if (has_mul_cam)
148 rk_aiq_uapi2_sysctl_setMulCamConc(media_info->aiq_ctx, 1);
149
150 if (rk_aiq_uapi2_sysctl_prepare(media_info->aiq_ctx,
151 width, height, RK_AIQ_WORKING_MODE_NORMAL)) {
152 ERR("rkaiq engine prepare failed !\n");
153 exit(-1);
154 }
155 }
156
start_engine(struct rkaiq_media_info * media_info)157 static void start_engine(struct rkaiq_media_info *media_info)
158 {
159 DBG("device manager start\n");
160 rk_aiq_uapi2_sysctl_start(media_info->aiq_ctx);
161 if (media_info->aiq_ctx == NULL) {
162 ERR("rkisp_init engine failed\n");
163 exit(-1);
164 } else {
165 DBG("rkisp_init engine succeed\n");
166 }
167 }
168
stop_engine(struct rkaiq_media_info * media_info)169 static void stop_engine(struct rkaiq_media_info *media_info)
170 {
171 rk_aiq_uapi2_sysctl_stop(media_info->aiq_ctx, false);
172 }
173
deinit_engine(struct rkaiq_media_info * media_info)174 static void deinit_engine(struct rkaiq_media_info *media_info)
175 {
176 rk_aiq_uapi2_sysctl_deinit(media_info->aiq_ctx);
177 }
178
179 // blocked func
wait_stream_event(int fd,unsigned int event_type,int time_out_ms)180 static int wait_stream_event(int fd, unsigned int event_type, int time_out_ms)
181 {
182 int ret;
183 struct v4l2_event event;
184
185 CLEAR(event);
186
187 do {
188 /*
189 * xioctl instead of poll.
190 * Since poll() cannot wait for input before stream on,
191 * it will return an error directly. So, use ioctl to
192 * dequeue event and block until sucess.
193 */
194 ret = xioctl(fd, VIDIOC_DQEVENT, &event);
195 if (ret == 0 && event.type == event_type)
196 return 0;
197 } while (true);
198
199 return -1;
200
201 }
202
subscrible_stream_event(struct rkaiq_media_info * media_info,int fd,bool subs)203 static int subscrible_stream_event(struct rkaiq_media_info *media_info, int fd, bool subs)
204 {
205 struct v4l2_event_subscription sub;
206 int ret = 0;
207
208 CLEAR(sub);
209 sub.type = CIFISP_V4L2_EVENT_STREAM_START;
210 ret = xioctl(fd,
211 subs ? VIDIOC_SUBSCRIBE_EVENT : VIDIOC_UNSUBSCRIBE_EVENT,
212 &sub);
213 if (ret) {
214 ERR("can't subscribe %s start event!\n", media_info->vd_params_path);
215 exit(EXIT_FAILURE);
216 }
217
218 CLEAR(sub);
219 sub.type = CIFISP_V4L2_EVENT_STREAM_STOP;
220 ret = xioctl(fd,
221 subs ? VIDIOC_SUBSCRIBE_EVENT : VIDIOC_UNSUBSCRIBE_EVENT,
222 &sub);
223 if (ret) {
224 ERR("can't subscribe %s stop event!\n", media_info->vd_params_path);
225 }
226
227 DBG("subscribe events from %s success !\n", media_info->vd_params_path);
228
229 return 0;
230 }
231
parse_args(int argc,char ** argv)232 void parse_args(int argc, char **argv)
233 {
234 int c;
235 int digit_optind = 0;
236
237 while (1) {
238 int this_option_optind = optind ? optind : 1;
239 int option_index = 0;
240 static struct option long_options[] = {
241 {"silent", no_argument, 0, 's' },
242 {"help", no_argument, 0, 'h' },
243 {0, 0, 0, 0 }
244 };
245
246 c = getopt_long(argc, argv, "sh", long_options, &option_index);
247 if (c == -1)
248 break;
249
250 switch (c) {
251 case 'w':
252 width = atoi(optarg);
253 break;
254 case 'h':
255 height = atoi(optarg);
256 break;
257 case 's':
258 silent = 1;
259 break;
260 case '?':
261 ERR("Usage: %s to start 3A engine\n"
262 " --silent, optional, subpress debug log\n",
263 argv[0]);
264 exit(-1);
265
266 default:
267 ERR("?? getopt returned character code %c ??\n", c);
268 }
269 }
270 }
271
engine_thread(void * arg)272 void *engine_thread(void *arg)
273 {
274 int ret = 0;
275 int isp_fd;
276 unsigned int stream_event = -1;
277 struct rkaiq_media_info *media_info;
278
279 media_info = (struct rkaiq_media_info *) arg;
280
281 isp_fd = open(media_info->vd_params_path, O_RDWR);
282 if (isp_fd < 0) {
283 ERR("open %s failed %s\n", media_info->vd_params_path, strerror(errno));
284 return NULL;
285 }
286
287 init_engine(media_info);
288 subscrible_stream_event(media_info, isp_fd, true);
289
290 for (;;) {
291 start_engine(media_info);
292 DBG("%s: wait stream start event...\n", media_info->mdev_path);
293 wait_stream_event(isp_fd, CIFISP_V4L2_EVENT_STREAM_START, -1);
294 DBG("%s: wait stream start event success ...\n", media_info->mdev_path);
295
296 DBG("%s: wait stream stop event...\n", media_info->mdev_path);
297 wait_stream_event(isp_fd, CIFISP_V4L2_EVENT_STREAM_STOP, -1);
298 DBG("%s: wait stream stop event success ...\n", media_info->mdev_path);
299
300 stop_engine(media_info);
301 }
302
303 subscrible_stream_event(media_info, isp_fd, false);
304 deinit_engine(media_info);
305 close(isp_fd);
306
307 return NULL;
308 }
309
main(int argc,char ** argv)310 int main(int argc, char **argv)
311 {
312 int ret, i;
313 int threads = 0;
314
315 /* Line buffered so that printf can flash every line if redirected to
316 * no-interactive device.
317 */
318 setlinebuf(stdout);
319
320 parse_args(argc, argv);
321
322 for (i = 0; i < MAX_MEDIA_NODES; i++) {
323 sprintf(media_infos[i].mdev_path, "/dev/media%d", i);
324 if (rkaiq_get_media_info(&media_infos[i])) {
325 ERR("Bad media topology for: %s\n", media_infos[i].mdev_path);
326 media_infos[i].available = 0;
327 continue;
328 }
329 media_infos[i].available = 1;
330 threads++;
331 }
332
333 if (threads > 1)
334 has_mul_cam = 1;
335
336 for (i = 0; i < MAX_MEDIA_NODES; i++) {
337 if (!media_infos[i].available)
338 continue;
339 ret = pthread_create(&media_infos[i].pid, NULL, engine_thread, &media_infos[i]);
340 if (ret) {
341 media_infos[i].pid = 0;
342 ERR("Failed to create camera engine thread for: %s\n", media_infos[i].mdev_path);
343 errno_exit("Create thread failed");
344 }
345 }
346
347 for (i = 0; i < MAX_MEDIA_NODES; i++) {
348 if (!media_infos[i].available || media_infos[i].pid == 0)
349 continue;
350 pthread_join(media_infos[i].pid, NULL);
351 }
352
353 return 0;
354 }
355