1/*
2Copyright (c) 2018, Raspberry Pi (Trading) Ltd.
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <ctype.h>
31#include <string.h>
32#include <memory.h>
33#include <unistd.h>
34#include <stdint.h>
35
36
37#include "interface/vcos/vcos.h"
38#include "interface/mmal/mmal.h"
39#include "interface/mmal/mmal_logging.h"
40#include "interface/mmal/util/mmal_default_components.h"
41#include "interface/mmal/mmal_parameters_camera.h"
42#include "interface/mmal/util/mmal_connection.h"
43
44#include "RaspiCLI.h"
45#include "RaspiPreview.h"
46#include "RaspiCamControl.h"
47#include "RaspiCommonSettings.h"
48
49#ifndef GIT_COMMIT_ID
50#define GIT_COMMIT_ID "Not found"
51#endif
52
53#if (GIT_TAINTED > 0)
54#define TAINTED " Tainted"
55#else
56#define TAINTED ""
57#endif
58
59static const char *app_name;
60
61void print_app_details(FILE *fd)
62{
63 if (!app_name)
64 app_name = "Un-named";
65
66 fprintf(fd, "\n\"%s\" Camera App (commit %s%s)\n\n", basename(app_name), GIT_COMMIT_ID, TAINTED);
67}
68
69void display_valid_parameters(char *name, void (*app_help)(char*))
70{
71 print_app_details(stdout);
72
73 // This should be defined in the main app source code
74 if (app_help)
75 (*app_help)(name);
76
77 // general settings
78 raspicommonsettings_display_help();
79
80 // Help for preview options
81 raspipreview_display_help();
82
83 // Now display any help information from the camcontrol code
84 raspicamcontrol_display_help();
85
86 fprintf(stdout, "\n");
87}
88
89
90void get_sensor_defaults(int camera_num, char *camera_name, int *width, int *height )
91{
92 MMAL_COMPONENT_T *camera_info;
93 MMAL_STATUS_T status;
94
95 // Default to the OV5647 setup
96 strncpy(camera_name, "OV5647", MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN);
97
98 // Try to get the camera name and maximum supported resolution
99 status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA_INFO, &camera_info);
100 if (status == MMAL_SUCCESS)
101 {
102 MMAL_PARAMETER_CAMERA_INFO_T param;
103 param.hdr.id = MMAL_PARAMETER_CAMERA_INFO;
104 param.hdr.size = sizeof(param)-4; // Deliberately undersize to check firmware version
105 status = mmal_port_parameter_get(camera_info->control, &param.hdr);
106
107 if (status != MMAL_SUCCESS)
108 {
109 // Running on newer firmware
110 param.hdr.size = sizeof(param);
111 status = mmal_port_parameter_get(camera_info->control, &param.hdr);
112 if (status == MMAL_SUCCESS && param.num_cameras > camera_num)
113 {
114 // Take the parameters from the first camera listed.
115 if (*width == 0)
116 *width = param.cameras[camera_num].max_width;
117 if (*height == 0)
118 *height = param.cameras[camera_num].max_height;
119 strncpy(camera_name, param.cameras[camera_num].camera_name, MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN);
120 camera_name[MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN-1] = 0;
121 }
122 else
123 vcos_log_error("Cannot read camera info, keeping the defaults for OV5647");
124 }
125 else
126 {
127 // Older firmware
128 // Nothing to do here, keep the defaults for OV5647
129 }
130
131 mmal_component_destroy(camera_info);
132 }
133 else
134 {
135 vcos_log_error("Failed to create camera_info component");
136 }
137
138 // default to OV5647 if nothing detected..
139 if (*width == 0)
140 *width = 2592;
141 if (*height == 0)
142 *height = 1944;
143}
144
145void set_app_name(const char *name)
146{
147 app_name = name;
148}
149
150const char *get_app_name()
151{
152 return app_name;
153}
154
155
156/**
157 * Connect two specific ports together
158 *
159 * @param output_port Pointer the output port
160 * @param input_port Pointer the input port
161 * @param Pointer to a mmal connection pointer, reassigned if function successful
162 * @return Returns a MMAL_STATUS_T giving result of operation
163 *
164 */
165MMAL_STATUS_T connect_ports(MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_CONNECTION_T **connection)
166{
167 MMAL_STATUS_T status;
168
169 status = mmal_connection_create(connection, output_port, input_port, MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT);
170
171 if (status == MMAL_SUCCESS)
172 {
173 status = mmal_connection_enable(*connection);
174 if (status != MMAL_SUCCESS)
175 mmal_connection_destroy(*connection);
176 }
177
178 return status;
179}
180
181/**
182 * Checks if specified port is valid and enabled, then disables it
183 *
184 * @param port Pointer the port
185 *
186 */
187void check_disable_port(MMAL_PORT_T *port)
188{
189 if (port && port->is_enabled)
190 mmal_port_disable(port);
191}
192
193/**
194 * Handler for sigint signals
195 *
196 * @param signal_number ID of incoming signal.
197 *
198 */
199void default_signal_handler(int signal_number)
200{
201 if (signal_number == SIGUSR1)
202 {
203 // Handle but ignore - prevents us dropping out if started in none-signal mode
204 // and someone sends us the USR1 signal anyway
205 }
206 else
207 {
208 // Going to abort on all other signals
209 vcos_log_error("Aborting program\n");
210 exit(130);
211 }
212
213}
214
215/**
216 * Convert a MMAL status return value to a simple boolean of success
217 * ALso displays a fault if code is not success
218 *
219 * @param status The error code to convert
220 * @return 0 if status is success, 1 otherwise
221 */
222int mmal_status_to_int(MMAL_STATUS_T status)
223{
224 if (status == MMAL_SUCCESS)
225 return 0;
226 else
227 {
228 switch (status)
229 {
230 case MMAL_ENOMEM :
231 vcos_log_error("Out of memory");
232 break;
233 case MMAL_ENOSPC :
234 vcos_log_error("Out of resources (other than memory)");
235 break;
236 case MMAL_EINVAL:
237 vcos_log_error("Argument is invalid");
238 break;
239 case MMAL_ENOSYS :
240 vcos_log_error("Function not implemented");
241 break;
242 case MMAL_ENOENT :
243 vcos_log_error("No such file or directory");
244 break;
245 case MMAL_ENXIO :
246 vcos_log_error("No such device or address");
247 break;
248 case MMAL_EIO :
249 vcos_log_error("I/O error");
250 break;
251 case MMAL_ESPIPE :
252 vcos_log_error("Illegal seek");
253 break;
254 case MMAL_ECORRUPT :
255 vcos_log_error("Data is corrupt \attention FIXME: not POSIX");
256 break;
257 case MMAL_ENOTREADY :
258 vcos_log_error("Component is not ready \attention FIXME: not POSIX");
259 break;
260 case MMAL_ECONFIG :
261 vcos_log_error("Component is not configured \attention FIXME: not POSIX");
262 break;
263 case MMAL_EISCONN :
264 vcos_log_error("Port is already connected ");
265 break;
266 case MMAL_ENOTCONN :
267 vcos_log_error("Port is disconnected");
268 break;
269 case MMAL_EAGAIN :
270 vcos_log_error("Resource temporarily unavailable. Try again later");
271 break;
272 case MMAL_EFAULT :
273 vcos_log_error("Bad address");
274 break;
275 default :
276 vcos_log_error("Unknown status error");
277 break;
278 }
279
280 return 1;
281 }
282}
283
284
285uint64_t get_microseconds64()
286{
287 struct timespec spec;
288 uint64_t us;
289
290 clock_gettime(CLOCK_MONOTONIC_RAW, &spec);
291
292 us = spec.tv_sec * 1000000ULL;
293 us += spec.tv_nsec / 1000;
294
295 return us;
296}
297