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