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/**
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
60enum
61{
62 CommandHelp,
63 CommandWidth,
64 CommandHeight,
65 CommandOutput,
66 CommandVerbose,
67 CommandCamSelect,
68 CommandSensorMode,
69 CommandGpsd,
70};
71
72
73static 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
85static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]);
86
87
88void 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 */
107void 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 */
119void 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 */
132int 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