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, &param.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, &param.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