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