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 /**
29 * \file RaspiCommonSettings.c
30 *
31 * Description
32 *
33 * Handles general settings applicable to all the camera applications
34 */
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <ctype.h>
39 #include <string.h>
40 #include <memory.h>
41 #include <unistd.h>
42 #include <errno.h>
43 #include <sysexits.h>
44
45 #include "interface/vcos/vcos.h"
46 #include "interface/mmal/mmal.h"
47 #include "interface/mmal/mmal_logging.h"
48 #include "interface/mmal/mmal_buffer.h"
49 #include "interface/mmal/util/mmal_util.h"
50 #include "interface/mmal/util/mmal_util_params.h"
51 #include "interface/mmal/util/mmal_default_components.h"
52 #include "interface/mmal/util/mmal_connection.h"
53 #include "interface/mmal/mmal_parameters_camera.h"
54
55 #include "RaspiCommonSettings.h"
56 #include "RaspiCLI.h"
57 #include "RaspiHelpers.h"
58 #include "RaspiGPS.h"
59
60 enum
61 {
62 CommandHelp,
63 CommandWidth,
64 CommandHeight,
65 CommandOutput,
66 CommandVerbose,
67 CommandCamSelect,
68 CommandSensorMode,
69 CommandGpsd,
70 };
71
72 static COMMAND_LIST cmdline_commands[] =
73 {
74 { CommandHelp, "-help", "?", "This help information", 0 },
75 { CommandWidth, "-width", "w", "Set image width <size>", 1 },
76 { CommandHeight, "-height", "h", "Set image height <size>", 1 },
77 { CommandOutput, "-output", "o", "Output filename <filename> (to write to stdout, use '-o -'). If not specified, no file is saved", 1 },
78 { CommandVerbose, "-verbose", "v", "Output verbose information during run", 0 },
79 { CommandCamSelect, "-camselect","cs", "Select camera <number>. Default 0", 1 },
80 { CommandSensorMode,"-mode", "md", "Force sensor mode. 0=auto. See docs for other modes available", 1},
81 { CommandGpsd, "-gpsdexif", "gps","Apply real-time GPS information to output (e.g. EXIF in JPG, annotation in video (requires " LIBGPS_SO_VERSION ")", 0},
82 };
83
84 static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]);
85
raspicommonsettings_set_defaults(RASPICOMMONSETTINGS_PARAMETERS * state)86 void raspicommonsettings_set_defaults(RASPICOMMONSETTINGS_PARAMETERS *state)
87 {
88 strncpy(state->camera_name, "(Unknown)", MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN);
89 // We dont set width and height since these will be specific to the app being built.
90 state->width = 0;
91 state->height = 0;
92 state->filename = NULL;
93 state->verbose = 0;
94 state->cameraNum = 0;
95 state->sensor_mode = 0;
96 state->gps = 0;
97 };
98
99 /**
100 * Dump parameters as human readable to stderr
101 *
102 * @param state Pointer to parameter block
103 *
104 */
raspicommonsettings_dump_parameters(RASPICOMMONSETTINGS_PARAMETERS * state)105 void raspicommonsettings_dump_parameters(RASPICOMMONSETTINGS_PARAMETERS *state)
106 {
107 fprintf(stderr, "Camera Name %s\n", state->camera_name);
108 fprintf(stderr, "Width %d, Height %d, filename %s\n", state->width,
109 state->height, state->filename);
110 fprintf(stderr, "Using camera %d, sensor mode %d\n\n", state->cameraNum, state->sensor_mode);
111 fprintf(stderr, "GPS output %s\n\n", state->gps ? "Enabled" : "Disabled");
112 };
113
114 /**
115 * Display help for command line options for this module
116 */
raspicommonsettings_display_help()117 void raspicommonsettings_display_help()
118 {
119 fprintf(stdout, "\nCommon Settings commands\n\n");
120 raspicli_display_help(cmdline_commands, cmdline_commands_size);
121 }
122
123 /**
124 * Parse a possible command pair - command and parameter
125 * @param arg1 Command
126 * @param arg2 Parameter (could be NULL)
127 * @return How many parameters were used, 0,1,2
128 */
raspicommonsettings_parse_cmdline(RASPICOMMONSETTINGS_PARAMETERS * state,const char * arg1,const char * arg2,void (* app_help)(char *))129 int raspicommonsettings_parse_cmdline(RASPICOMMONSETTINGS_PARAMETERS *state, const char *arg1, const char *arg2, void (*app_help)(char*))
130 {
131 int command_id, used = 0, num_parameters;
132
133 if (!arg1)
134 return 0;
135
136 command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, arg1, &num_parameters);
137
138 // If invalid command, or we are missing a parameter, drop out
139 if (command_id==-1 || (command_id != -1 && num_parameters > 0 && arg2 == NULL))
140 return 0;
141
142 switch (command_id)
143 {
144 case CommandHelp:
145 {
146 display_valid_parameters(basename(get_app_name()), app_help);
147 exit(0);
148 break;
149 }
150 case CommandWidth: // Width > 0
151 if (sscanf(arg2, "%u", &state->width) == 1)
152 used = 2;
153 break;
154
155 case CommandHeight: // Height > 0
156 if (sscanf(arg2, "%u", &state->height) == 1)
157 used = 2;
158 break;
159
160 case CommandOutput: // output filename
161 {
162 int len = strlen(arg2);
163 if (len)
164 {
165 // Ensure that any %<char> is either %% or %d.
166 const char *percent = arg2;
167
168 while(*percent && (percent=strchr(percent, '%')) != NULL)
169 {
170 int digits=0;
171 percent++;
172 while(isdigit(*percent))
173 {
174 percent++;
175 digits++;
176 }
177 if(!((*percent == '%' && !digits) || *percent == 'd'))
178 {
179 used = 0;
180 fprintf(stderr, "Filename contains %% characters, but not %%d or %%%% - sorry, will fail\n");
181 break;
182 }
183 percent++;
184 }
185
186 state->filename = malloc(len + 10); // leave enough space for any timelapse generated changes to filename
187 vcos_assert(state->filename);
188 if (state->filename)
189 strncpy(state->filename, arg2, len+1);
190 used = 2;
191 }
192 else
193 used = 0;
194 break;
195 }
196
197 case CommandVerbose: // display lots of data during run
198 state->verbose = 1;
199 used = 1;
200 break;
201
202 case CommandCamSelect: //Select camera input port
203 {
204 if (sscanf(arg2, "%u", &state->cameraNum) == 1)
205 used = 2;
206 break;
207 }
208
209 case CommandSensorMode:
210 {
211 if (sscanf(arg2, "%u", &state->sensor_mode) == 1)
212 used = 2;
213 break;
214 }
215
216 case CommandGpsd:
217 state->gps = 1;
218 used = 1;
219 break;
220 }
221
222 return used;
223 }
224