├── .clang-format ├── .gitignore ├── LICENCE ├── Makefile ├── README.md ├── RaspiCLI.c ├── RaspiCLI.h ├── adv7282m_modes.h ├── camera_i2c ├── imx219_modes.h ├── imx477_modes.h ├── ov5647_modes.h ├── raspiraw.c ├── raw_header.h ├── res ├── Screenshot179.png ├── out.0123.ppm.d.png ├── out.1000.ppm.d.png ├── out.3000.ppm.d.png └── out.360fps.25xSlower.2.anim.gif ├── rpi3-gpiovirtbuf └── tools ├── 1280x720 ├── 1296x720_S ├── 1296x730_s ├── 1640x1232 ├── 1640x922 ├── 1920x1080 ├── 2592x1944_s ├── 320x240 ├── 3280x2464 ├── 640x128 ├── 640x128_s ├── 640x240 ├── 640x240_B ├── 640x240_B_s ├── 640x240_s ├── 640x32 ├── 640x400_s ├── 640x416_s ├── 640x480 ├── 640x480_s ├── 640x64 ├── 640x64_s ├── double ├── double.c ├── gifenc.sh └── raw2ogg2anim /.clang-format: -------------------------------------------------------------------------------- 1 | # One way to run clang-format is `clang-format-9 -i --style=file *.{h,c} tools/double.c` 2 | BasedOnStyle: LLVM 3 | IndentWidth: 8 4 | UseTab: Always 5 | BreakBeforeBraces: Allman 6 | AllowShortIfStatementsOnASingleLine: false 7 | IndentCaseLabels: false 8 | AlignConsecutiveMacros: true 9 | ColumnLimit: 120 10 | Cpp11BracedListStyle: false 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | raspiraw 2 | *.ppm 3 | *.raw 4 | *.jpg 5 | *.o 6 | *.d 7 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017, Raspberry Pi (Trading) Ltd 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the copyright holder nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE ?= 2 | 3 | CC ?= gcc 4 | CC := $(CROSS_COMPILE)$(CC) 5 | CFLAGS ?= -I/opt/vc/include -pipe -W -Wall -Wextra -g -O0 -MD 6 | LDFLAGS ?= 7 | LIBS := -L/opt/vc/lib -lrt -lbcm_host -lvcos -lmmal_core -lmmal_util -lmmal_vc_client -lvcsm -lpthread 8 | 9 | %.o : %.c 10 | $(CC) $(CFLAGS) -c -o $@ $< 11 | 12 | all: raspiraw 13 | 14 | OBJS := raspiraw.o RaspiCLI.o 15 | raspiraw: $(OBJS) 16 | $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) 17 | 18 | clean: 19 | -rm -f *.o *.d 20 | -rm -f raspiraw 21 | 22 | -include $(OBJS:.o=.d) 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This repo is deprecated, and only kept for reference. 2 | 3 | Raspiraw: An example app that receives data directly from CSI sensors 4 | on the Raspberry Pi. 5 | 6 | The register sets for OV5647 and IMX219 are often under NDA, which means 7 | that support can not be offered over their contents without breaking 8 | those NDAs. Anything added here by RPF/RPT has to be demonstrable as 9 | already being in the public domain, or from 3rd parties having 10 | reverse engineered how the firmware is working (eg by listening to the 11 | I2C communications). 12 | 13 | 14 | The raw Bayer format frames captured by **raspiraw** can be converted to .ppm images by modified **dcraw** image processing app: [https://github.com/6by9/dcraw](https://github.com/6by9/dcraw) 15 | 16 | Supported sensors: 17 | 18 | adv7282m 19 | imx219 20 | ov5647 21 | 22 | ## raspiraw command line options 23 | 24 | Table of contents: 25 | 26 | $ raspiraw 27 | 28 | raspiraw Camera App 0.0.1 29 | 30 | -?, --help : This help information 31 | -md, --mode : Set sensor mode 32 | -hf, --hflip : Set horizontal flip 33 | -vf, --vflip : Set vertical flip 34 | -e, --ss : Set the sensor exposure time (not calibrated units) 35 | -g, --gain : Set the sensor gain code (not calibrated units) 36 | -o, --output : Set the output filename 37 | -hd, --header : Write the BRCM header to the output file 38 | -t, --timeout : Time (in ms) before shutting down (if not specified, set to 5s) 39 | -sr, --saverate : Save every Nth frame 40 | -b, --bitdepth : Set output raw bit depth (8, 10, 12 or 16, if not specified, set to sensor native) 41 | -c, --cameranum : Set camera number to use (0=CAM0, 1=CAM1). 42 | -eus, --expus : Set the sensor exposure time in micro seconds. 43 | -y, --i2c : Set the I2C bus to use. 44 | -r, --regs : Change (current mode) regs 45 | -hi, --hinc : Set horizontal odd/even inc reg 46 | -vi, --vinc : Set vertical odd/even inc reg 47 | -f, --fps : Set framerate regs 48 | -w, --width : Set current mode width 49 | -h, --height : Set current mode height 50 | -tp, --top : Set current mode top 51 | -hd0, --header0 : Sets filename to write the BRCM header to 52 | -ts, --tstamps : Sets filename to write timestamps to 53 | -emp, --empty : Write empty output files 54 | $ 55 | 56 | ## base options 57 | 58 | ... 59 | 60 | -md, --mode : Set sensor mode 61 | 62 | Range is 1-7. 63 | 64 | ... 65 | 66 | -o, --output : Set the output filename 67 | 68 | For recording more than one frame specify "C printf integer format strings" as part of the filename. 69 | Example: ... -o /dev/shm/out.%04d.raw ... 70 | 71 | -hd, --header : Write the BRCM header to the output file 72 | 73 | If selected, this prepeneds each stored frame with a 32KB header (needed for **dcraw** being able to process the raw frame). An alternative (needed for high framerate capturing) is option -hd0 (see below section), which allows **dcraw** to process the captured frames later as well. 74 | 75 | ... 76 | 77 | -sr, --saverate : Save every Nth frame 78 | 79 | Per default this is 20, allowing to capture frames to slow SD cards. In high framerate section, storing on (fast) ramdisk allows to use "-sr 1" (store all frames). 80 | 81 | ... 82 | 83 | -y, --i2c : Set the I2C bus to use. 84 | 85 | Range is 0-2. 86 | 87 | 88 | ## high frame rate options 89 | 90 | Lookup ov5647, imx219 or adv7282m data sheets for register details. 91 | 92 | #### I2C register setting options 93 | 94 | -r, --regs : Change (current mode) regs 95 | 96 | Allows to change sensor regs in selected sensor mode. Format is a semicolon separated string of assignments. 97 | An assignment consists of a 4 hex digits register address, followed by a comma and one or more 2 hex digit byte values. 98 | Restriction: Only registers present in selected sensor mode can be modified. Example argument: "380A,003C;3802,78;3806,05FB". 99 | In case more than one byte appears after the comma, the byte values get written to next addresses. 100 | 101 | -hi, --hinc : Set horizontal odd/even inc reg 102 | 103 | Sets the horizontal odd and even increment numbers. Argument is a 2 hex digits byte. "-hi xy" is convenience shortcut for "3814,xy" in --regs for ov5647 sensor. Lookup the sensor mode registers for your sensor header file for default values. TODO: Needs to be extended to deal with the other sensors as well. 104 | 105 | -vi, --vinc : Set vertical odd/even inc reg 106 | 107 | Sets the vertical odd and even increment numbers. Argument is a 2 hex digits byte. "-vi xy" is convenience shortcut for "3815,xy" in --regs for ov5647 sensor. TODO: Needs to be extended to deal with the other sensors as well. 108 | 109 | -f, --fps : Set frame rate regs 110 | 111 | Sets the requested frame rate; argument is a floating point number. All sensors but adv7282m sensor are supported. 112 | 113 | #### Sensor mode setting options 114 | 115 | The following options allow to overwrite some sensor mode settings for current sensor mode. 116 | 117 | -w, --width : Set current mode width 118 | 119 | Sets the width value of current mode. 120 | 121 | -h, --height : Set current mode height 122 | 123 | Sets the height value of current mode, and sensor mode regs. 124 | 125 | -tp, --top : Set current mode top 126 | 127 | Sets top line in case --vinc setting jumps two or more lines. The tools *_B* modes make use of it to capture bottom half of fov. 128 | 129 | 130 | #### File output settings 131 | 132 | -hd0, --header0 : Write the BRCM header to output file 133 | 134 | For high frame rate modes writing BRCM header to each file is a bottleneck. 135 | So this option is a replacement for "--header"/"-hd" option. 136 | Instead of writing header to each frame file, it is written to specified output file only. 137 | For decoding ith frame with **dcraw** later, you need to concatenate specified output file and frame i and store somewhere, then **dcraw** that file. 138 | 139 | -ts, --tstamps : Write timestamps to output file 140 | 141 | With this option timestamps for the captured frames get written to specified output file. 142 | This happens after video has been captured, so does not negatively affect capture frame rate. 143 | Format: "delta,index,timestamp\n" 144 | 145 | Timestamp distribution analysis can be easily done this way: 146 | 147 | $ cut -f1 -d, tstamps.csv | sort -n | uniq -c 148 | 1 149 | 13 1499 150 | 17 1500 151 | 31 1501 152 | 147 1502 153 | 376 1503 154 | 22 1504 155 | 33 1505 156 | 14 1506 157 | 3 1507 158 | 1 3005 159 | 2 3006 160 | $ 161 | 162 | 163 | This shows that frame deltas are 1503µs ± 4µs, which corresponds to 1,000,000/1503=665.3fps. 164 | Three frame skips happened during recording, and their indices can be easily determined by: 165 | 166 | $ grep "^3" tstamps.csv 167 | 3006,2,6027843627 168 | 3005,85,6027969857 169 | 3006,554,6028676146 170 | $ 171 | 172 | So we know that frames 0085-0553 have no frame skips. All tools do this timestamp analysis for you. 173 | 174 | 175 | -emp, --empty : Write empty output files 176 | 177 | This option allows to determine the maximal frame rate **raspiraw** callback will be triggered. Only empty files will be written for the frames, but the filenames allow to count how many. This would be an example use: 178 | 179 | raspiraw -md 7 -t 3000 -emp {some options from this section} -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null 180 | 181 | Using **/dev/shm** ramdisk for storage is essential for high frame rates. You precede this command by "rm /dev/shm/out.*.raw" and do "ls -l /dev/shm/out.*.raw | wc --lines" afterwards to determine the number of frames written ("-sr 1" means saverate 1 or writing all frames received from camera). "--empty" option allows to determine upper bounds for the absolute maximal frame rate achievable for a given set of high frame rate options. 182 | 183 | 184 | 185 | #### Examples: 186 | 187 | This is an example making use of most high frame rate command line options: 188 | 189 | $ rm /dev/shm/out.*.raw 190 | $ raspiraw -md 7 -t 1000 -ts tstamps.csv -hd0 hd0.32k -h 64 --vinc 1F --fps 660 -r "380A,0040;3802,78;3806,0603" -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null 191 | Using i2C device /dev/i2c-0 192 | $ ls -l /dev/shm/out.*.raw | wc --lines 193 | 660 194 | $ 195 | 196 | This command captures video from ov5647 camera on CSI-2 interface: 197 | * based on 640x480 mode (-md 7) 198 | * captures for 1s (-t 1000) 199 | * stores µs timestamps in file tstamps.csv (-ts) 200 | * stores BCRM header needed for **dcraw** only once in file hd0.32k (-hd0) 201 | * sets frame capture height to 64 (-h 64) 202 | * increases line skipping to 1 and 15 instead of 3 and 5. Results in doubling vertical covered area (--vinc 1F, sum 8 vs 16). 1F shows colors (see below), 3D result is pale 203 | * asks for 660 fps (--fps 660) 204 | * sets some ov5647 registers (380A,0040;3802,78;3806,0603) 205 | * sets saverate to 1 (save all frames) 206 | * outputs in "/dev/shm" ramdisk files starting with "out.0001.raw" 207 | * redirects standard error output (lots of mmal messages) to /dev/null (2>/dev/null) 208 | 209 | For being able to convert frame 123 captured frame with **dcraw** these steps are necessary (because of -hd0): 210 | 211 | cat hd0.32k /dev/shm/out.0123.raw > out.0123.raw 212 | dcraw out.0123.raw 213 | 214 | Since line scanning speed was doubled, the captured 128x64 frames need to be stretched by factor 2. 215 | You can use this small C code and know exactly what happens, or any other stretching program (gimp, netpbm tools, ...), the result is still a .ppm format file: 216 | [double.c](tools/double.c) 217 | 218 | double out.0123.ppm > out.0123.ppm.d 219 | 220 | This frame was captured with 665fps. It is surprisingly colorful despite only 1.5ms shutter time: 221 | ![600fps sample frame just described](res/out.0123.ppm.d.png) 222 | 223 | 224 | Currently the capturing tools do not use --regs option anymore. This option keeps available trying out things quickly. 225 | 226 | 227 | #### Creation of .ogg video from **dcraw** processed and stretched .ppm frames 228 | 229 | First you need to convert the .ppm frames you are interested in into .png format, eg. with netpbm tools: 230 | 231 | pnmtopng out.0123.ppm.d > out.0123.ppm.d.png 232 | 233 | This gstreamer pipeline creates .ogg video. You can choose frame rate the video should play with (eg. 1fps for very slow motion), and start index of the frames to be taken. 234 | 235 | gst-launch-1.0 multifilesrc location="out.%04d.ppm.d.png" index=300 caps="image/png,framerate=\(fraction\)1/1" ! pngdec ! videorate ! videoconvert ! videorate ! theoraenc ! oggmux ! filesink location="$1.ogg" 236 | 237 | This is now part of raw2ogg2anim tool. 238 | 239 | #### Creation of animated .gif from .ogg video 240 | 241 | You can create high quality animated .gif from .ogg video with ffmpeg based [gifenc.sh](tools/gifenc.sh). You only need to adjust **fps** and **scale** in **filters** variable of that script to match what you want. 242 | 243 | gifenc.sh $1.ogg $1.anim.gif 244 | 245 | Sample: 360fps 640x120 (rescaled to 640x240) video taken with v1 camera, played 25x slowed down: 246 | ![360fps sample video](res/out.360fps.25xSlower.2.anim.gif) 247 | 248 | This is now part of raw2ogg2anim tool. 249 | 250 | ## raspiraw usage 251 | 252 | #### do once 253 | 254 | You have to clone the repo. 255 | Then change directory `cd raspiraw` and build the code by running `make`. Optionally you can define the compiler with `CC=gcc make` or `CC=clang make`. 256 | Finally add this line to your `~/.bashrc`. 257 | 258 | $ tail -1 ~/.bashrc 259 | PATH=~/raspiraw:~/raspiraw/tools:$PATH 260 | $ 261 | 262 | #### do once after reboot or use of raspistill/raspivid 263 | 264 | Execute camera_i2c to make raspiraw work. 265 | 266 | $ camera_i2c 267 | setting GPIO for board revsion: a01041 268 | A+, B+, and B2 all revisions - I2C 0 on GPIOs 28 & 29. GPIOs 32 & 41 for LED and power 269 | $ 270 | 271 | 272 | #### tools usage 273 | 274 | There are quite soome tools in [tools directory](tools/). 275 | They allow to do a video capture with frame delay and frame skip analysis with 276 | just a single command. 277 | And to repeat the command if you do not like the analysis. 278 | 279 | There are several tools for capturing. [640x128_s](tools/640x128_s) creates 640x128 280 | frames while only capturing 64 lines. Stretching is needed in post processing. 281 | [640x128](tools/640x128) captures 640x128 frames as well, but all 128 lines. There 282 | is a minor difference in viewing the frames, and a bigger difference in capturing 283 | framerate that can be achieved. Stretched 640x128 frames can be captured at 665(502) 284 | fps on Pi 2B/3B(Pi Zero[W]), whereas full capturing of 128 lines allows for 350fps 285 | (only). 286 | 287 | This table gives modes and framerates possible with raspiraw. 288 | 289 | |format | Pi Zero [W] | Pi 2B/3B | 290 | |:-------------|------------:|-----------:| 291 | |640x480 | 90 | 90 | 292 | |640x480_s | 180 | 180 | 293 | |640x240[_B] | 180 | 180 | 294 | |640x240[_B]_s | 360 | 360 | 295 | |640x128 / _s | 350 / 502 | 350 / 665 | 296 | |640x64 / _s | 502 / 543 | 665 / 750 | 297 | |640x32 | 543 | 750 | 298 | |640x416_s | 210 | 210 | 299 | |640x400_s | 220 | 220 | 300 | |2592x1944_s | 30 | 30 | 301 | |1296x730_s | 98 | 98 | 302 | |1296x720_S | 190 | 190 | 303 | |framerate for normal / stretched | _B is "bottom half" | _S is "4th rows" 304 | 305 | Sample: 306 | 307 | $ 640x128_s 1200 308 | removing /dev/shm/out.*.raw 309 | capturing frames for 1200ms with 659fps requested 310 | 794 frames were captured at 665fps 311 | frame delta time[us] distribution 312 | 1 313 | 168 1502 314 | 623 1503 315 | 2 3006 316 | after skip frame indices (middle column) 317 | 3006,2,9698007408 318 | 3006,275,9698419172 319 | $ 320 | 321 | [raw2ogg2anim ](tools/raw2ogg2anim) is script allowing you to create an .ogg video 322 | and an animated .gif. 323 | Specify output file prefix for .ogg video and .anim.gif animated gif created. Then 324 | specify frame start and stop index as well, and the target framerate. Optionally 325 | you can add "d"/"dd" argument for stretching each frame by factor of 2/4 vertically 326 | before generation of output. "d"/"dd" option is used by "_s"/"_S" mode tools. 327 | 328 | $ ~/raspiraw/tools/raw2ogg2anim 329 | format: raw2ogg2anim vname first last fps [d[d]] 330 | $ 331 | 332 | ## Where is the limit? 333 | 334 | Above sample did capture 640x128 frames (stretched) at 665fps. It is possible to 335 | capture 640x64 stretched frames with 900fps! 336 | [https://www.raspberrypi.org/forums/viewtopic.php?f=63&t=109523&p=1246776#p1246776](https://www.raspberrypi.org/forums/viewtopic.php?f=63&t=109523&p=1246776#p1246776) 337 | 338 | ![900fps sample frame just described](res/out.3000.ppm.d.png) 339 | 340 | Sharp and well lighted video can be taken with NoIR camera with lense and 3W 341 | infrared LED. This is 640x128 frame from video taken at 665fps: 342 | 343 | ![665fps NoIR camera with lense sample frame](res/out.1000.ppm.d.png) 344 | 345 | This is 1296x720_S format frame taken at 190fps, only every 4th row gets captured 346 | (allowing for high framerate while keeping fov), and post processing has to call 347 | "double" tool two times for each frame: 348 | ![1296x720_S mode sample frame](res/Screenshot179.png) 349 | -------------------------------------------------------------------------------- /RaspiCLI.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013, Broadcom Europe Ltd 3 | Copyright (c) 2013, James Hughes 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | * Neither the name of the copyright holder nor the 14 | names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /** 30 | * \file RaspiCLI.c 31 | * Code for handling command line parameters 32 | * 33 | * \date 4th March 2013 34 | * \Author: James Hughes 35 | * 36 | * Description 37 | * 38 | * Some functions/structures for command line parameter parsing 39 | * 40 | */ 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include "interface/vcos/vcos.h" 47 | 48 | #include "RaspiCLI.h" 49 | 50 | /** 51 | * Convert a string from command line to a comand_id from the list 52 | * 53 | * @param commands Array of command to check 54 | * @param num_command Number of commands in the array 55 | * @param arg String to search for in the list 56 | * @param num_parameters Returns the number of parameters used by the command 57 | * 58 | * @return command ID if found, -1 if not found 59 | * 60 | */ 61 | int raspicli_get_command_id(const COMMAND_LIST *commands, const int num_commands, const char *arg, int *num_parameters) 62 | { 63 | int command_id = -1; 64 | int j; 65 | 66 | vcos_assert(commands); 67 | vcos_assert(num_parameters); 68 | vcos_assert(arg); 69 | 70 | if (!commands || !num_parameters || !arg) 71 | return -1; 72 | 73 | for (j = 0; j < num_commands; j++) 74 | { 75 | if (!strcmp(arg, commands[j].command) || !strcmp(arg, commands[j].abbrev)) 76 | { 77 | // match 78 | command_id = commands[j].id; 79 | *num_parameters = commands[j].num_parameters; 80 | break; 81 | } 82 | } 83 | 84 | return command_id; 85 | } 86 | 87 | /** 88 | * Display the list of commands in help format 89 | * 90 | * @param commands Array of command to check 91 | * @param num_command Number of commands in the arry 92 | * 93 | * 94 | */ 95 | void raspicli_display_help(const COMMAND_LIST *commands, const int num_commands) 96 | { 97 | int i; 98 | 99 | vcos_assert(commands); 100 | 101 | if (!commands) 102 | return; 103 | 104 | for (i = 0; i < num_commands; i++) 105 | { 106 | fprintf(stdout, "-%s, -%s\t: %s\n", commands[i].abbrev, commands[i].command, commands[i].help); 107 | } 108 | } 109 | 110 | /** 111 | * Function to take a string, a mapping, and return the int equivalent 112 | * @param str Incoming string to match 113 | * @param map Mapping data 114 | * @param num_refs The number of items in the mapping data 115 | * @return The integer match for the string, or -1 if no match 116 | */ 117 | int raspicli_map_xref(const char *str, const XREF_T *map, int num_refs) 118 | { 119 | int i; 120 | 121 | for (i = 0; i < num_refs; i++) 122 | { 123 | if (!strcasecmp(str, map[i].mode)) 124 | { 125 | return map[i].mmal_mode; 126 | } 127 | } 128 | return -1; 129 | } 130 | 131 | /** 132 | * Function to take a mmal enum (as int) and return the string equivalent 133 | * @param en Incoming int to match 134 | * @param map Mapping data 135 | * @param num_refs The number of items in the mapping data 136 | * @return const pointer to string, or NULL if no match 137 | */ 138 | const char *raspicli_unmap_xref(const int en, XREF_T *map, int num_refs) 139 | { 140 | int i; 141 | 142 | for (i = 0; i < num_refs; i++) 143 | { 144 | if (en == map[i].mmal_mode) 145 | { 146 | return map[i].mode; 147 | } 148 | } 149 | return NULL; 150 | } 151 | -------------------------------------------------------------------------------- /RaspiCLI.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013, Broadcom Europe Ltd 3 | Copyright (c) 2013, James Hughes 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | * Neither the name of the copyright holder nor the 14 | names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #ifndef RASPICLI_H_ 30 | #define RASPICLI_H_ 31 | 32 | typedef struct 33 | { 34 | int id; 35 | char *command; 36 | char *abbrev; 37 | char *help; 38 | int num_parameters; 39 | } COMMAND_LIST; 40 | 41 | /// Cross reference structure, mode string against mode id 42 | typedef struct xref_t 43 | { 44 | char *mode; 45 | int mmal_mode; 46 | } XREF_T; 47 | 48 | void raspicli_display_help(const COMMAND_LIST *commands, const int num_commands); 49 | int raspicli_get_command_id(const COMMAND_LIST *commands, const int num_commands, const char *arg, int *num_parameters); 50 | 51 | int raspicli_map_xref(const char *str, const XREF_T *map, int num_refs); 52 | const char *raspicli_unmap_xref(const int en, XREF_T *map, int num_refs); 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /adv7282m_modes.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015-2017, Raspberry Pi Foundation 3 | Copyright (c) 2015, Dave Stevenson 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | * Neither the name of the copyright holder nor the 14 | names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #ifndef ADV7282M_MODES_H_ 30 | #define ADV7282M_MODES_H_ 31 | 32 | // Setup taken from the Linux kernel drivers/media/i2c/adv7180.c driver 33 | // settings for ADV7282-M. 34 | 35 | #define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM 0x0 36 | #define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM_PED 0x1 37 | #define ADV7180_STD_AD_PAL_N_NTSC_J_SECAM 0x2 38 | #define ADV7180_STD_AD_PAL_N_NTSC_M_SECAM 0x3 39 | #define ADV7180_STD_NTSC_J 0x4 40 | #define ADV7180_STD_NTSC_M 0x5 41 | #define ADV7180_STD_PAL60 0x6 42 | #define ADV7180_STD_NTSC_443 0x7 43 | #define ADV7180_STD_PAL_BG 0x8 44 | #define ADV7180_STD_PAL_N 0x9 45 | #define ADV7180_STD_PAL_M 0xa 46 | #define ADV7180_STD_PAL_M_PED 0xb 47 | #define ADV7180_STD_PAL_COMB_N 0xc 48 | #define ADV7180_STD_PAL_COMB_N_PED 0xd 49 | #define ADV7180_STD_PAL_SECAM 0xe 50 | #define ADV7180_STD_PAL_SECAM_PED 0xf 51 | 52 | #define ADV7180_REG_INPUT_CONTROL 0x0000 53 | #define ADV7180_INPUT_CONTROL_INSEL_MASK 0x0f 54 | 55 | #define ADV7182_REG_INPUT_VIDSEL 0x0002 56 | 57 | #define ADV7180_REG_OUTPUT_CONTROL 0x0003 58 | #define ADV7180_REG_EXTENDED_OUTPUT_CONTROL 0x0004 59 | #define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5 60 | 61 | #define ADV7180_REG_AUTODETECT_ENABLE 0x0007 62 | #define ADV7180_AUTODETECT_DEFAULT 0x7f 63 | /* Contrast */ 64 | #define ADV7180_REG_CON 0x0008 /*Unsigned */ 65 | #define ADV7180_CON_MIN 0 66 | #define ADV7180_CON_DEF 128 67 | #define ADV7180_CON_MAX 255 68 | /* Brightness*/ 69 | #define ADV7180_REG_BRI 0x000a /*Signed */ 70 | #define ADV7180_BRI_MIN -128 71 | #define ADV7180_BRI_DEF 0 72 | #define ADV7180_BRI_MAX 127 73 | /* Hue */ 74 | #define ADV7180_REG_HUE 0x000b /*Signed, inverted */ 75 | #define ADV7180_HUE_MIN -127 76 | #define ADV7180_HUE_DEF 0 77 | #define ADV7180_HUE_MAX 128 78 | 79 | #define ADV7180_REG_CTRL 0x000e 80 | #define ADV7180_CTRL_IRQ_SPACE 0x20 81 | 82 | #define ADV7180_REG_PWR_MAN 0x0f 83 | #define ADV7180_PWR_MAN_ON 0x04 84 | #define ADV7180_PWR_MAN_OFF 0x24 85 | #define ADV7180_PWR_MAN_RES 0x80 86 | 87 | #define ADV7180_REG_STATUS1 0x0010 88 | #define ADV7180_STATUS1_IN_LOCK 0x01 89 | #define ADV7180_STATUS1_AUTOD_MASK 0x70 90 | #define ADV7180_STATUS1_AUTOD_NTSM_M_J 0x00 91 | #define ADV7180_STATUS1_AUTOD_NTSC_4_43 0x10 92 | #define ADV7180_STATUS1_AUTOD_PAL_M 0x20 93 | #define ADV7180_STATUS1_AUTOD_PAL_60 0x30 94 | #define ADV7180_STATUS1_AUTOD_PAL_B_G 0x40 95 | #define ADV7180_STATUS1_AUTOD_SECAM 0x50 96 | #define ADV7180_STATUS1_AUTOD_PAL_COMB 0x60 97 | #define ADV7180_STATUS1_AUTOD_SECAM_525 0x70 98 | 99 | #define ADV7180_REG_IDENT 0x0011 100 | #define ADV7180_ID_7180 0x18 101 | 102 | #define ADV7180_REG_STATUS3 0x0013 103 | #define ADV7180_REG_ANALOG_CLAMP_CTL 0x0014 104 | #define ADV7180_REG_SHAP_FILTER_CTL_1 0x0017 105 | #define ADV7180_REG_CTRL_2 0x001d 106 | #define ADV7180_REG_VSYNC_FIELD_CTL_1 0x0031 107 | #define ADV7180_REG_MANUAL_WIN_CTL_1 0x003d 108 | #define ADV7180_REG_MANUAL_WIN_CTL_2 0x003e 109 | #define ADV7180_REG_MANUAL_WIN_CTL_3 0x003f 110 | #define ADV7180_REG_LOCK_CNT 0x0051 111 | #define ADV7180_REG_CVBS_TRIM 0x0052 112 | #define ADV7180_REG_CLAMP_ADJ 0x005a 113 | #define ADV7180_REG_RES_CIR 0x005f 114 | #define ADV7180_REG_DIFF_MODE 0x0060 115 | 116 | #define ADV7180_REG_ICONF1 0x2040 117 | #define ADV7180_ICONF1_ACTIVE_LOW 0x01 118 | #define ADV7180_ICONF1_PSYNC_ONLY 0x10 119 | #define ADV7180_ICONF1_ACTIVE_TO_CLR 0xC0 120 | /* Saturation */ 121 | #define ADV7180_REG_SD_SAT_CB 0x00e3 /*Unsigned */ 122 | #define ADV7180_REG_SD_SAT_CR 0x00e4 /*Unsigned */ 123 | #define ADV7180_SAT_MIN 0 124 | #define ADV7180_SAT_DEF 128 125 | #define ADV7180_SAT_MAX 255 126 | 127 | #define ADV7180_IRQ1_LOCK 0x01 128 | #define ADV7180_IRQ1_UNLOCK 0x02 129 | #define ADV7180_REG_ISR1 0x2042 130 | #define ADV7180_REG_ICR1 0x2043 131 | #define ADV7180_REG_IMR1 0x2044 132 | #define ADV7180_REG_IMR2 0x2048 133 | #define ADV7180_IRQ3_AD_CHANGE 0x08 134 | #define ADV7180_REG_ISR3 0x204A 135 | #define ADV7180_REG_ICR3 0x204B 136 | #define ADV7180_REG_IMR3 0x204C 137 | #define ADV7180_REG_IMR4 0x2050 138 | 139 | #define ADV7180_REG_NTSC_V_BIT_END 0x00E6 140 | #define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND 0x4F 141 | 142 | #define ADV7180_REG_VPP_SLAVE_ADDR 0xFD 143 | #define ADV7180_REG_CSI_SLAVE_ADDR 0xFE 144 | 145 | #define ADV7180_REG_ACE_CTRL1 0x4080 146 | #define ADV7180_REG_ACE_CTRL5 0x4084 147 | #define ADV7180_REG_FLCONTROL 0x40e0 148 | #define ADV7180_FLCONTROL_FL_ENABLE 0x1 149 | 150 | #define ADV7180_REG_RST_CLAMP 0x809c 151 | #define ADV7180_REG_AGC_ADJ1 0x80b6 152 | #define ADV7180_REG_AGC_ADJ2 0x80c0 153 | 154 | #define ADV7180_CSI_REG_PWRDN 0x00 155 | #define ADV7180_CSI_PWRDN 0x80 156 | 157 | #define ADV7180_INPUT_CVBS_AIN1 0x00 158 | #define ADV7180_INPUT_CVBS_AIN2 0x01 159 | #define ADV7180_INPUT_CVBS_AIN3 0x02 160 | #define ADV7180_INPUT_CVBS_AIN4 0x03 161 | #define ADV7180_INPUT_CVBS_AIN5 0x04 162 | #define ADV7180_INPUT_CVBS_AIN6 0x05 163 | #define ADV7180_INPUT_SVIDEO_AIN1_AIN2 0x06 164 | #define ADV7180_INPUT_SVIDEO_AIN3_AIN4 0x07 165 | #define ADV7180_INPUT_SVIDEO_AIN5_AIN6 0x08 166 | #define ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3 0x09 167 | #define ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0a 168 | 169 | #define ADV7182_INPUT_CVBS_AIN1 0x00 170 | #define ADV7182_INPUT_CVBS_AIN2 0x01 171 | #define ADV7182_INPUT_CVBS_AIN3 0x02 172 | #define ADV7182_INPUT_CVBS_AIN4 0x03 173 | #define ADV7182_INPUT_CVBS_AIN5 0x04 174 | #define ADV7182_INPUT_CVBS_AIN6 0x05 175 | #define ADV7182_INPUT_CVBS_AIN7 0x06 176 | #define ADV7182_INPUT_CVBS_AIN8 0x07 177 | #define ADV7182_INPUT_SVIDEO_AIN1_AIN2 0x08 178 | #define ADV7182_INPUT_SVIDEO_AIN3_AIN4 0x09 179 | #define ADV7182_INPUT_SVIDEO_AIN5_AIN6 0x0a 180 | #define ADV7182_INPUT_SVIDEO_AIN7_AIN8 0x0b 181 | #define ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3 0x0c 182 | #define ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0d 183 | #define ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2 0x0e 184 | #define ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4 0x0f 185 | #define ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6 0x10 186 | #define ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8 0x11 187 | 188 | #define ADV7180_DEFAULT_BASE_I2C_ADDR 0x21 189 | #define ADV7180_DEFAULT_CSI_I2C_ADDR 0x44 190 | #define ADV7180_DEFAULT_VPP_I2C_ADDR 0x42 191 | 192 | #define V4L2_CID_ADV_FAST_SWITCH (V4L2_CID_USER_ADV7180_BASE + 0x00) 193 | 194 | // clang-format off 195 | // Allman/Linux style braces in these macros result in odd formatting. 196 | 197 | #define adv7180_write(STT, reg, dat) {reg, dat} 198 | #define adv7180_csi_write(STT, reg, dat) {reg, dat} 199 | #define adv7180_vpp_write(STT, reg, dat) {reg, dat} 200 | 201 | #define SET_BASE {0xFFFF, ADV7180_DEFAULT_BASE_I2C_ADDR} 202 | #define SET_CSI {0xFFFF, ADV7180_DEFAULT_CSI_I2C_ADDR} 203 | #define SET_VPP {0xFFFF, ADV7180_DEFAULT_VPP_I2C_ADDR} 204 | 205 | // clang-format on 206 | 207 | struct sensor_regs adv7282_pal[] = { 208 | // init_device 209 | adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES), 210 | { 0xFFFE, 100 }, 211 | 212 | // adv7182_init 213 | adv7180_write(state, ADV7180_REG_CSI_SLAVE_ADDR, ADV7180_DEFAULT_CSI_I2C_ADDR << 1), 214 | 215 | adv7180_write(state, ADV7180_REG_VPP_SLAVE_ADDR, ADV7180_DEFAULT_VPP_I2C_ADDR << 1), 216 | 217 | /* ADI recommended writes for improved video quality */ 218 | adv7180_write(state, 0x0080, 0x51), 219 | adv7180_write(state, 0x0081, 0x51), 220 | adv7180_write(state, 0x0082, 0x68), 221 | 222 | /* ADI required writes */ 223 | adv7180_write(state, ADV7180_REG_OUTPUT_CONTROL, 0x4e), 224 | adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 0x57), 225 | adv7180_write(state, ADV7180_REG_CTRL_2, 0xc0), 226 | 227 | adv7180_write(state, 0x0013, 0x00), 228 | 229 | // adv7182_set_std 230 | adv7180_write(state, ADV7182_REG_INPUT_VIDSEL, ADV7180_STD_PAL_BG << 4), 231 | 232 | // adv7180_set_field_mode 233 | SET_CSI, 234 | adv7180_csi_write(state, 0x01, 0x20), 235 | adv7180_csi_write(state, 0x02, 0x28), 236 | adv7180_csi_write(state, 0x03, 0x38), 237 | adv7180_csi_write(state, 0x04, 0x30), 238 | adv7180_csi_write(state, 0x05, 0x30), 239 | adv7180_csi_write(state, 0x06, 0x80), 240 | adv7180_csi_write(state, 0x07, 0x70), 241 | adv7180_csi_write(state, 0x08, 0x50), 242 | SET_VPP, 243 | adv7180_vpp_write(state, 0xa3, 0x00), 244 | adv7180_vpp_write(state, 0x5b, 0x00), 245 | adv7180_vpp_write(state, 0x55, 0x80), 246 | 247 | // s_input 248 | SET_BASE, 249 | adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ADV7180_INPUT_CVBS_AIN1), 250 | 251 | /* Reset clamp circuitry - ADI recommended writes */ 252 | adv7180_write(state, ADV7180_REG_RST_CLAMP, 0x00), 253 | adv7180_write(state, ADV7180_REG_RST_CLAMP, 0xff), 254 | 255 | // input_type = adv7182_get_input_type(input), 256 | 257 | // switch (input_type) { 258 | // case ADV7182_INPUT_TYPE_CVBS: 259 | // case ADV7182_INPUT_TYPE_DIFF_CVBS: 260 | /* ADI recommends to use the SH1 filter */ 261 | adv7180_write(state, ADV7180_REG_SHAP_FILTER_CTL_1, 0x41), 262 | // break, 263 | // default: 264 | // adv7180_write(state, ADV7180_REG_SHAP_FILTER_CTL_1, 0x01), 265 | // break, 266 | // } 267 | 268 | //[ADV7182_INPUT_TYPE_CVBS] = { 0xCD, 0x4E, 0x80 }, 269 | // for (i = 0, i < ARRAY_SIZE(adv7182_lbias_settings[0]), i++) 270 | // adv7180_write(state, ADV7180_REG_CVBS_TRIM + i, lbias[i]), 271 | adv7180_write(state, ADV7180_REG_CVBS_TRIM + 0, 0xCD), 272 | adv7180_write(state, ADV7180_REG_CVBS_TRIM + 1, 0x4E), 273 | adv7180_write(state, ADV7180_REG_CVBS_TRIM + 2, 0x80), 274 | 275 | // if (input_type == ADV7182_INPUT_TYPE_DIFF_CVBS) { 276 | /* ADI required writes to make differential CVBS work */ 277 | //} else { 278 | adv7180_write(state, ADV7180_REG_RES_CIR, 0xf0), 279 | adv7180_write(state, ADV7180_REG_CLAMP_ADJ, 0xd0), 280 | adv7180_write(state, ADV7180_REG_DIFF_MODE, 0x10), 281 | adv7180_write(state, ADV7180_REG_AGC_ADJ1, 0x9c), 282 | adv7180_write(state, ADV7180_REG_AGC_ADJ2, 0x00), 283 | 284 | // adv7180_set_power 285 | adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_ON), 286 | 287 | SET_CSI, 288 | adv7180_csi_write(state, 0xDE, 0x02), 289 | adv7180_csi_write(state, 0xD2, 0xF7), 290 | adv7180_csi_write(state, 0xD8, 0x65), 291 | adv7180_csi_write(state, 0xE0, 0x09), 292 | adv7180_csi_write(state, 0x2C, 0x00), 293 | adv7180_csi_write(state, 0x1D, 0x80), 294 | adv7180_csi_write(state, 0x00, 0x00), 295 | SET_BASE, 296 | }; 297 | 298 | struct sensor_regs adv7282_ntsc[] = {}; 299 | 300 | struct mode_def adv7282_modes[] = { 301 | { 302 | .regs = adv7282_pal, 303 | .num_regs = NUM_ELEMENTS(adv7282_pal), 304 | .width = 720, 305 | .height = 576, 306 | .encoding = MMAL_ENCODING_UYVY, 307 | .order = 0, 308 | .native_bit_depth = 0, 309 | .image_id = 0x1E, 310 | .data_lanes = 1, 311 | .min_vts = 0, 312 | .line_time_ns = 0, 313 | .timing = { 2, 6, 2, 6, 0 }, 314 | .term = { 1, 1 }, 315 | .black_level = 0, 316 | }, 317 | { 318 | .regs = adv7282_ntsc, 319 | .num_regs = NUM_ELEMENTS(adv7282_ntsc), 320 | .width = 720, 321 | .height = 480, 322 | .encoding = MMAL_ENCODING_UYVY, 323 | .order = 0, 324 | .native_bit_depth = 0, 325 | .image_id = 0x1E, 326 | .data_lanes = 1, 327 | .min_vts = 0, 328 | .line_time_ns = 0, 329 | .timing = { 2, 6, 2, 6, 0 }, 330 | .term = { 1, 1 }, 331 | .black_level = 0, 332 | }, 333 | }; 334 | 335 | struct sensor_regs adv7282_stop[] = { 336 | // adv7180_set_power 337 | SET_BASE, 338 | adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_OFF), 339 | SET_CSI, 340 | adv7180_csi_write(state, 0x00, 0x80), 341 | }; 342 | 343 | // ID register settings taken from 344 | // http://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1298623.html 345 | struct sensor_def adv7282 = { 346 | .name = "adv7282", 347 | .modes = adv7282_modes, 348 | .num_modes = NUM_ELEMENTS(adv7282_modes), 349 | .stop = adv7282_stop, 350 | .num_stop_regs = NUM_ELEMENTS(adv7282_stop), 351 | 352 | .i2c_addr = ADV7180_DEFAULT_BASE_I2C_ADDR, 353 | .i2c_addressing = 1, 354 | .i2c_ident_length = 1, 355 | .i2c_ident_reg = 0x1100, 356 | .i2c_ident_value = 0x42, 357 | 358 | .vflip_reg = 0, 359 | .vflip_reg_bit = 0, 360 | .hflip_reg = 0, 361 | .hflip_reg_bit = 0, 362 | 363 | .exposure_reg = 0, 364 | .exposure_reg_num_bits = 0, 365 | 366 | .gain_reg = 0, 367 | .gain_reg_num_bits = 0, 368 | }; 369 | 370 | #endif 371 | -------------------------------------------------------------------------------- /camera_i2c: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Setup GPIO and I2C ports for raspicam 4 | 5 | # Broadcom GPIO numbers used here 6 | 7 | # http://elinux.org/RPi_HardwareHistory#Board_Revision_History 8 | 9 | rev=`cat /proc/cpuinfo | grep Revision | awk '{print substr($NF,length($NF)-5,6)}'` 10 | kernel=`uname -r | head --bytes 1` 11 | 12 | echo "setting GPIO for board revsion: $rev" 13 | 14 | case $rev in 15 | # Old revision code encodings first 16 | '0002'|'0003') 17 | echo "B Rev1 - I2C 1 on GPIOs 2 & 3. GPIOs 5 & 27 for LED and power" 18 | if [ "$kernel" = "4" ] 19 | then 20 | # i2c on these pins 21 | raspi-gpio set 0 ip 22 | raspi-gpio set 0 a0 23 | raspi-gpio set 1 ip 24 | raspi-gpio set 1 a0 25 | fi 26 | #shutdown 27 | raspi-gpio set 27 op dh 28 | #LED 29 | raspi-gpio set 5 op dh 30 | # 31 | echo "Use 'raspiraw -y 1' to communicate with the sensor" 32 | ;; 33 | 34 | '0004'|'0005'|'0006'|'000d'|'000e'|'000f') 35 | echo "B Rev2 - I2C 0 on GPIOs 0 & 1. GPIOs 5 & 21 for LED and power" 36 | # i2c on these pins 37 | if [ "$kernel" = "4" ] 38 | then 39 | raspi-gpio set 0 ip 40 | raspi-gpio set 0 a0 41 | raspi-gpio set 1 ip 42 | raspi-gpio set 1 a0 43 | fi 44 | #shutdown 45 | raspi-gpio set 21 dh 46 | #LED 47 | raspi-gpio set 5 dh 48 | ;; 49 | 50 | '0010'|'0012'|'0013'|'1041') 51 | echo "A+, B+, B2, B2 (2837), and Zero (not W) all revisions - I2C 0 on GPIOs 28 & 29. GPIOs 32 & 41 for LED and power" 52 | if [ "$kernel" = "4" ] 53 | then 54 | # i2c can be on pins 0 and 1, so make sure they are not set to alt0 55 | raspi-gpio set 0 ip 56 | raspi-gpio set 1 ip 57 | # i2c on these pins 58 | raspi-gpio set 28 ip 59 | raspi-gpio set 28 a0 60 | raspi-gpio set 29 ip 61 | raspi-gpio set 29 a0 62 | fi 63 | #shutdown 64 | raspi-gpio set 41 dh 65 | #LED 66 | raspi-gpio set 32 dh 67 | ;; 68 | 69 | '0011'|'0014') 70 | echo "Compute Module/ CM3 - I2C 0 on GPIO 0 & 1. GPIOs 2 & 3 for LED and power" 71 | echo "Warning: This is just a default setting for cam1." 72 | echo "Download dt-blob.bin from https://www.raspberrypi.org/documentation/hardware/computemodule/dt-blob-cam1.bin and place it in /boot/." 73 | echo "For cable connection, see https://www.raspberrypi.org/documentation/hardware/computemodule/cmio-camera.md" 74 | if [ "$kernel" = "4" ] 75 | then 76 | # i2c can be on pins 28 and 29, so make sure they are not set to alt0 77 | raspi-gpio set 28 ip 78 | raspi-gpio set 29 ip 79 | # i2c on these pins 80 | raspi-gpio set 0 ip 81 | raspi-gpio set 0 a0 82 | raspi-gpio set 1 ip 83 | raspi-gpio set 1 a0 84 | fi 85 | # shutdown 86 | raspi-gpio set 3 out 87 | raspi-gpio set 3 dh 88 | # LED 89 | raspi-gpio set 2 out 90 | raspi-gpio set 2 dh 91 | ;; 92 | 93 | *) 94 | # New format revision encodings 95 | board_type=`cat /proc/cpuinfo | grep Revision | awk '{print substr($NF,length($NF)-2,2)}'` 96 | 97 | case $board_type in 98 | '02'|'03'|'04'|'09') 99 | echo "A+, B+, B2, B2 (2837), and Zero (not W) all revisions - I2C 0 on GPIOs 28 & 29. GPIOs 32 & 41 for LED and power" 100 | if [ "$kernel" = "4" ] 101 | then 102 | # i2c can be on pins 0 and 1, so make sure they are not set to alt0 103 | raspi-gpio set 0 ip 104 | raspi-gpio set 1 ip 105 | # i2c on these pins 106 | raspi-gpio set 28 ip 107 | raspi-gpio set 28 a0 108 | raspi-gpio set 29 ip 109 | raspi-gpio set 29 a0 110 | fi 111 | #shutdown 112 | raspi-gpio set 41 dh 113 | #LED 114 | raspi-gpio set 32 dh 115 | ;; 116 | 117 | '0c') 118 | echo "PiZero W - I2C 0 on GPIO 28 & 29. GPIOs 40 & 44 for LED and power" 119 | if [ "$kernel" = "4" ] 120 | then 121 | # i2c can be on pins 0 and 1, so make sure they are not set to alt0 122 | raspi-gpio set 0 ip 123 | raspi-gpio set 1 ip 124 | # i2c on these pins 125 | raspi-gpio set 28 ip 126 | raspi-gpio set 28 a0 127 | raspi-gpio set 29 ip 128 | raspi-gpio set 29 a0 129 | fi 130 | # shutdown 131 | raspi-gpio set 44 dh 132 | # LED 133 | raspi-gpio set 40 dh 134 | ;; 135 | 136 | '0a') 137 | echo "Compute Module/ CM3 - I2C 0 on GPIO 0 & 1. GPIOs 2 & 3 for LED and power" 138 | echo "Warning: This is just a default setting for cam1." 139 | echo "Download dt-blob.bin from https://www.raspberrypi.org/documentation/hardware/computemodule/dt-blob-cam1.bin and place it in /boot/." 140 | echo "For cable connection, see https://www.raspberrypi.org/documentation/hardware/computemodule/cmio-camera.md" 141 | if [ "$kernel" = "4" ] 142 | then 143 | # i2c can be on pins 28 and 29, so make sure they are not set to alt0 144 | raspi-gpio set 28 ip 145 | raspi-gpio set 29 ip 146 | # i2c on these pins 147 | raspi-gpio set 0 ip 148 | raspi-gpio set 0 a0 149 | raspi-gpio set 1 ip 150 | raspi-gpio set 1 a0 151 | fi 152 | # shutdown 153 | raspi-gpio set 3 out 154 | raspi-gpio set 3 dh 155 | # LED 156 | raspi-gpio set 2 out 157 | raspi-gpio set 2 dh 158 | ;; 159 | 160 | '08'|'0d'|'0e') 161 | echo "Raspberry Pi3B / Pi3B+ / 3A" 162 | # https://www.raspberrypi.org/forums/viewtopic.php?f=38&t=120702&start=100 163 | # Pins 44&45 Alt1=i2c0, alt2=i2c1 164 | if [ "$kernel" = "4" ] 165 | then 166 | # i2c0 can be on pins 0 and 1, so make sure they are not set to alt0 167 | raspi-gpio set 0 ip 168 | raspi-gpio set 1 ip 169 | raspi-gpio set 28 ip 170 | raspi-gpio set 29 ip 171 | # i2c on these pins 172 | raspi-gpio set 44 ip 173 | raspi-gpio set 44 a1 174 | raspi-gpio set 45 ip 175 | raspi-gpio set 45 a1 176 | fi 177 | #shutdown 178 | # you need this one: https://github.com/6by9/rpi3-gpiovirtbuf 179 | #raspi-gpio set 41 1 180 | `dirname $0`/rpi3-gpiovirtbuf s 133 1 181 | #LED 182 | #raspi-gpio set 32 1 183 | ;; 184 | 185 | '11') 186 | echo "4B(1G/2G/4G/8G)" 187 | # https://www.raspberrypi.org/forums/viewtopic.php?f=38&t=120702&start=100 188 | # Pins 44&45 Alt1=i2c0, alt2=i2c1 189 | # i2c0 can be on pins 0 and 1, so make sure they are not set to alt0 190 | if [ "$kernel" = "4" ] 191 | then 192 | # Do NOT alter 28&29 as they are used by the ethernet PHY. 193 | raspi-gpio set 0 ip 194 | raspi-gpio set 1 ip 195 | # i2c on these pins 196 | raspi-gpio set 44 ip 197 | raspi-gpio set 44 a1 198 | raspi-gpio set 45 ip 199 | raspi-gpio set 45 a1 200 | fi 201 | #shutdown 202 | # you need this one: https://github.com/6by9/rpi3-gpiovirtbuf 203 | #raspi-gpio set 41 1 204 | `dirname $0`/rpi3-gpiovirtbuf s 133 1 205 | #LED 206 | #raspi-gpio set 32 1 207 | ;; 208 | 209 | '12') 210 | echo "PiZero2W" 211 | # Pins 44&45 Alt1=i2c0, alt2=i2c1 212 | # i2c0 can be on pins 0 and 1, so make sure they are not set to alt0 213 | if [ "$kernel" = "4" ] 214 | then 215 | # Do NOT alter 28&29 as they are used by the ethernet PHY. 216 | raspi-gpio set 0 ip 217 | raspi-gpio set 1 ip 218 | # i2c on these pins 219 | raspi-gpio set 44 ip 220 | raspi-gpio set 44 a1 221 | raspi-gpio set 45 ip 222 | raspi-gpio set 45 a1 223 | fi 224 | #shutdown 225 | raspi-gpio set 40 dh 226 | # No LED line. 227 | ;; 228 | 229 | '13') 230 | # Pi400 231 | echo "Failed: Pi400 doesn't have a camera connector" 232 | ;; 233 | 234 | '14') 235 | # CM4 236 | echo "CM4 - assume CAM1 on 44&45" 237 | if [ "$kernel" = "4" ] 238 | then 239 | # i2c can be on pins 44 and 45, so make sure they are not set to alt0 240 | raspi-gpio set 44 ip 241 | raspi-gpio set 45 ip 242 | # i2c on these pins 243 | raspi-gpio set 0 ip 244 | raspi-gpio set 0 a0 245 | raspi-gpio set 1 ip 246 | raspi-gpio set 1 a0 247 | fi 248 | # shutdown 249 | `dirname $0`/rpi3-gpiovirtbuf s 133 1 250 | ;; 251 | 252 | *) 253 | echo "Failed: don't know how to set GPIO for this board! Type is $board_type" 254 | ;; 255 | 256 | esac 257 | ;; 258 | esac 259 | 260 | if [ "$kernel" = "4" ] 261 | then 262 | echo "Use i2c-0 for the sensor (-y 0)" 263 | else 264 | echo "Use i2c-10 for the sensor (-y 10)" 265 | fi 266 | -------------------------------------------------------------------------------- /imx219_modes.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Raspberry Pi Foundation 3 | Copyright (c) 2017, Dave Stevenson 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | * Neither the name of the copyright holder nor the 14 | names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | // These values are copied from 30 | // https://www.raspberrypi.org/forums/viewtopic.php?f=43&t=162722&p=1052339 31 | // Raspberry Pi can not discuss these settings as we have information from 32 | // Sony under NDA. 33 | 34 | // REQUESTS FOR SUPPORT ABOUT THESE REGISTER VALUES WILL 35 | // BE IGNORED BY PI TOWERS. 36 | 37 | #ifndef IMX219MODES_H_ 38 | #define IMX219MODES_H_ 39 | 40 | // clang-format off 41 | // We want to preserve 1 register per line. 42 | 43 | struct sensor_regs imx219_8MPix[] = { 44 | // 3280x2464@15 FPS 45 | {0x0100, 0x00}, // 0=OFF, 1=Stream, 2=MAX 46 | {0x30EB, 0x05}, 47 | {0x30EB, 0x0C}, 48 | {0x300A, 0xFF}, 49 | {0x300B, 0xFF}, 50 | {0x30EB, 0x05}, 51 | {0x30EB, 0x09}, 52 | {0x0114, 0x01}, // CSI MIPI Lanes [1:0] (0x01=2, 0x03=4) 53 | {0x0128, 0x00}, // DPHY_CNTRL 54 | {0x012A, 0x18}, // EXCK_FREQ [15:8] 55 | {0x012B, 0x00}, // EXCK_FREQ [7:0] 56 | {0x0157, 0x00}, // Analog Gain 57 | {0x0158, 0x01}, // Digital Gain [15:8] 58 | {0x0159, 0x00}, // Digital Gain [7:0] 59 | {0x015A, 0x01}, // Shutter/Integration Time [15:8] 60 | {0x015B, 0x00}, // Shutter/Integration Time [7:0] 61 | {0x0160, 0x09}, // Frame Length [15:8] 62 | {0x0161, 0xC8}, // Frame Length [7:0] 63 | {0x0162, 0x0D}, // Line Length [15:8] 64 | {0x0163, 0x78}, // Line Length [7:0] 65 | {0x0164, 0x00}, 66 | {0x0165, 0x00}, 67 | {0x0166, 0x0C}, 68 | {0x0167, 0xCF}, 69 | {0x0168, 0x00}, 70 | {0x0169, 0x00}, 71 | {0x016A, 0x09}, 72 | {0x016B, 0x9F}, 73 | {0x016C, 0x0C}, 74 | {0x016D, 0xD0}, 75 | {0x016E, 0x09}, 76 | {0x016F, 0xA0}, 77 | {0x0170, 0x01}, // X_ODD_INC [2:0] 78 | {0x0171, 0x01}, // Y_ODD_INC [2:0] 79 | {0x0172, 0x03}, 80 | {0x0174, 0x00}, // Binning Mode H_A 81 | {0x0175, 0x00}, // Binning Mode V_A 82 | {0x018C, 0x0A}, // CSI Data Format [15:8] 83 | {0x018D, 0x0A}, // CSI Data Format [7:0] 84 | {0x0301, 0x05}, // VTPXCK_DIV 85 | {0x0303, 0x01}, // VTSYCK_DIV 86 | {0x0304, 0x03}, // PREPLLCK_VT_DIV [3:0] 87 | {0x0305, 0x03}, // PREPLLCK_OP_DIV [3:0] 88 | {0x0306, 0x00}, // PLL_VT_MPY [10:8] 89 | {0x0307, 0x2B}, // PLL_VT_MPY [7:0] 90 | {0x0309, 0x0A}, // OPPXCK_DIV [4:0] 91 | {0x030B, 0x01}, // OPSYCK_DIV 92 | {0x030C, 0x00}, // PLL_OP_MPY [10:8] 93 | {0x030D, 0x55}, // PLL_OP_MPY [7:0] 94 | {0x455E, 0x00}, // CIS Tuning ? 95 | {0x471E, 0x4B}, // CIS Tuning ? 96 | {0x4767, 0x0F}, // CIS Tuning ? 97 | {0x4750, 0x14}, // CIS Tuning ? 98 | {0x4540, 0x00}, // CIS Tuning ? 99 | {0x47B4, 0x14}, // CIS Tuning ? 100 | {0x4713, 0x30}, // CIS Tuning ? 101 | {0x478B, 0x10}, // CIS Tuning ? 102 | {0x478F, 0x10}, // CIS Tuning ? 103 | {0x4797, 0x0E}, // CIS Tuning ? 104 | {0x479B, 0x0E}, // CIS Tuning ? 105 | {0x0100, 0x01} 106 | }; 107 | 108 | // Register setting provided on 109 | // https://www.raspberrypi.org/forums/viewtopic.php?f=43&t=109137&start=350#p1259865 110 | // with the addreg macro removed. 111 | struct sensor_regs imx219_mode1[] = 112 | { 113 | {0x0100, 0x00}, 114 | {0x30eb, 0x05}, 115 | {0x30eb, 0x0c}, 116 | {0x300a, 0xff}, 117 | {0x300b, 0xff}, 118 | {0x30eb, 0x05}, 119 | {0x30eb, 0x09}, 120 | {0x0114, 0x01}, 121 | {0x0128, 0x00}, 122 | {0x012a, 0x18}, 123 | {0x012b, 0x00}, 124 | {0x0162, 0x0d}, 125 | {0x0163, 0x78}, 126 | {0x0164, 0x02}, 127 | {0x0165, 0xa8}, 128 | {0x0166, 0x0a}, 129 | {0x0167, 0x27}, 130 | {0x0168, 0x02}, 131 | {0x0169, 0xb4}, 132 | {0x016a, 0x06}, 133 | {0x016b, 0xeb}, 134 | {0x016c, 0x07}, 135 | {0x016d, 0x80}, 136 | {0x016e, 0x04}, 137 | {0x016f, 0x38}, 138 | {0x0170, 0x01}, 139 | {0x0171, 0x01}, 140 | {0x0174, 0x00}, 141 | {0x0175, 0x00}, 142 | {0x018c, 0x0a}, 143 | {0x018d, 0x0a}, 144 | {0x0301, 0x05}, 145 | {0x0303, 0x01}, 146 | {0x0304, 0x03}, 147 | {0x0305, 0x03}, 148 | {0x0306, 0x00}, 149 | {0x0307, 0x39}, 150 | {0x0309, 0x0a}, 151 | {0x030b, 0x01}, 152 | {0x030c, 0x00}, 153 | {0x030d, 0x72}, 154 | {0x455e, 0x00}, 155 | {0x471e, 0x4b}, 156 | {0x4767, 0x0f}, 157 | {0x4750, 0x14}, 158 | {0x4540, 0x00}, 159 | {0x47b4, 0x14}, 160 | {0x4713, 0x30}, 161 | {0x478b, 0x10}, 162 | {0x478f, 0x10}, 163 | {0x4793, 0x10}, 164 | {0x4797, 0x0e}, 165 | {0x479b, 0x0e}, 166 | 167 | {0x0172, 0x03}, 168 | {0x0157, 0x00}, 169 | {0x0160, 0x06}, 170 | {0x0161, 0xe3}, 171 | {0x0162, 0x0d}, 172 | {0x0163, 0x78}, 173 | {0x015a, 0x00}, 174 | {0x015b, 0x31}, 175 | {0x0100, 0x01}, 176 | }; 177 | 178 | struct sensor_regs imx219_mode2[] = 179 | { 180 | {0x0100, 0x00}, 181 | {0x30eb, 0x0c}, 182 | {0x30eb, 0x05}, 183 | {0x300a, 0xff}, 184 | {0x300b, 0xff}, 185 | {0x30eb, 0x05}, 186 | {0x30eb, 0x09}, 187 | {0x0114, 0x01}, 188 | {0x0128, 0x00}, 189 | {0x012a, 0x18}, 190 | {0x012b, 0x00}, 191 | {0x0164, 0x00}, 192 | {0x0165, 0x00}, 193 | {0x0166, 0x0c}, 194 | {0x0167, 0xcf}, 195 | {0x0168, 0x00}, 196 | {0x0169, 0x00}, 197 | {0x016a, 0x09}, 198 | {0x016b, 0x9f}, 199 | {0x016c, 0x0c}, 200 | {0x016d, 0xd0}, 201 | {0x016e, 0x09}, 202 | {0x016f, 0xa0}, 203 | {0x0170, 0x01}, 204 | {0x0171, 0x01}, 205 | {0x0174, 0x00}, 206 | {0x0175, 0x00}, 207 | {0x018c, 0x0a}, 208 | {0x018d, 0x0a}, 209 | {0x0301, 0x05}, 210 | {0x0303, 0x01}, 211 | {0x0304, 0x03}, 212 | {0x0305, 0x03}, 213 | {0x0306, 0x00}, 214 | {0x0307, 0x39}, 215 | {0x0309, 0x0a}, 216 | {0x030b, 0x01}, 217 | {0x030c, 0x00}, 218 | {0x030d, 0x72}, 219 | {0x0624, 0x0c}, 220 | {0x0625, 0xd0}, 221 | {0x0626, 0x09}, 222 | {0x0627, 0xa0}, 223 | {0x455e, 0x00}, 224 | {0x471e, 0x4b}, 225 | {0x4767, 0x0f}, 226 | {0x4750, 0x14}, 227 | {0x4540, 0x00}, 228 | {0x47b4, 0x14}, 229 | {0x4713, 0x30}, 230 | {0x478b, 0x10}, 231 | {0x478f, 0x10}, 232 | {0x4793, 0x10}, 233 | {0x4797, 0x0e}, 234 | {0x479b, 0x0e}, 235 | 236 | {0x0172, 0x03}, 237 | {0x0157, 0x00}, 238 | {0x0160, 0x0d}, 239 | {0x0161, 0xc6}, 240 | {0x0162, 0x0d}, 241 | {0x0163, 0x78}, 242 | {0x015a, 0x00}, 243 | {0x015b, 0x31}, 244 | {0x0100, 0x01}, 245 | }; 246 | 247 | struct sensor_regs imx219_mode3[] = 248 | { 249 | {0x0100, 0x00}, 250 | {0x30eb, 0x0c}, 251 | {0x30eb, 0x05}, 252 | {0x300a, 0xff}, 253 | {0x300b, 0xff}, 254 | {0x30eb, 0x05}, 255 | {0x30eb, 0x09}, 256 | {0x0114, 0x01}, 257 | {0x0128, 0x00}, 258 | {0x012a, 0x18}, 259 | {0x012b, 0x00}, 260 | {0x0164, 0x00}, 261 | {0x0165, 0x00}, 262 | {0x0166, 0x0c}, 263 | {0x0167, 0xcf}, 264 | {0x0168, 0x00}, 265 | {0x0169, 0x00}, 266 | {0x016a, 0x09}, 267 | {0x016b, 0x9f}, 268 | {0x016c, 0x0c}, 269 | {0x016d, 0xd0}, 270 | {0x016e, 0x09}, 271 | {0x016f, 0xa0}, 272 | {0x0170, 0x01}, 273 | {0x0171, 0x01}, 274 | {0x0174, 0x00}, 275 | {0x0175, 0x00}, 276 | {0x018c, 0x0a}, 277 | {0x018d, 0x0a}, 278 | {0x0301, 0x05}, 279 | {0x0303, 0x01}, 280 | {0x0304, 0x03}, 281 | {0x0305, 0x03}, 282 | {0x0306, 0x00}, 283 | {0x0307, 0x39}, 284 | {0x0309, 0x0a}, 285 | {0x030b, 0x01}, 286 | {0x030c, 0x00}, 287 | {0x030d, 0x72}, 288 | {0x0624, 0x0c}, 289 | {0x0625, 0xd0}, 290 | {0x0626, 0x09}, 291 | {0x0627, 0xa0}, 292 | {0x455e, 0x00}, 293 | {0x471e, 0x4b}, 294 | {0x4767, 0x0f}, 295 | {0x4750, 0x14}, 296 | {0x4540, 0x00}, 297 | {0x47b4, 0x14}, 298 | {0x4713, 0x30}, 299 | {0x478b, 0x10}, 300 | {0x478f, 0x10}, 301 | {0x4793, 0x10}, 302 | {0x4797, 0x0e}, 303 | {0x479b, 0x0e}, 304 | {0x0172, 0x03}, 305 | {0x0157, 0x00}, 306 | {0x0160, 0x0d}, 307 | {0x0161, 0xc6}, 308 | {0x0162, 0x0d}, 309 | {0x0163, 0x78}, 310 | {0x015a, 0x00}, 311 | {0x015b, 0x31}, 312 | {0x0100, 0x01}, 313 | }; 314 | 315 | struct sensor_regs imx219_mode4[] = 316 | { 317 | {0x0100, 0x00}, 318 | {0x30eb, 0x0c}, 319 | {0x30eb, 0x05}, 320 | {0x300a, 0xff}, 321 | {0x300b, 0xff}, 322 | {0x30eb, 0x05}, 323 | {0x30eb, 0x09}, 324 | {0x0114, 0x01}, 325 | {0x0128, 0x00}, 326 | {0x012a, 0x18}, 327 | {0x012b, 0x00}, 328 | {0x0164, 0x00}, 329 | {0x0165, 0x00}, 330 | {0x0166, 0x0c}, 331 | {0x0167, 0xcf}, 332 | {0x0168, 0x00}, 333 | {0x0169, 0x00}, 334 | {0x016a, 0x09}, 335 | {0x016b, 0x9f}, 336 | {0x016c, 0x06}, 337 | {0x016d, 0x68}, 338 | {0x016e, 0x04}, 339 | {0x016f, 0xd0}, 340 | {0x0170, 0x01}, 341 | {0x0171, 0x01}, 342 | {0x0174, 0x01}, 343 | {0x0175, 0x01}, 344 | {0x018c, 0x0a}, 345 | {0x018d, 0x0a}, 346 | {0x0301, 0x05}, 347 | {0x0303, 0x01}, 348 | {0x0304, 0x03}, 349 | {0x0305, 0x03}, 350 | {0x0306, 0x00}, 351 | {0x0307, 0x39}, 352 | {0x0309, 0x0a}, 353 | {0x030b, 0x01}, 354 | {0x030c, 0x00}, 355 | {0x030d, 0x72}, 356 | {0x455e, 0x00}, 357 | {0x471e, 0x4b}, 358 | {0x4767, 0x0f}, 359 | {0x4750, 0x14}, 360 | {0x4540, 0x00}, 361 | {0x47b4, 0x14}, 362 | {0x4713, 0x30}, 363 | {0x478b, 0x10}, 364 | {0x478f, 0x10}, 365 | {0x4793, 0x10}, 366 | {0x4797, 0x0e}, 367 | {0x479b, 0x0e}, 368 | {0x0172, 0x03}, 369 | {0x0157, 0x00}, 370 | {0x0160, 0x05}, 371 | {0x0161, 0x2a}, 372 | {0x0162, 0x0d}, 373 | {0x0163, 0x78}, 374 | {0x015a, 0x00}, 375 | {0x015b, 0x31}, 376 | {0x0100, 0x01}, 377 | }; 378 | 379 | struct sensor_regs imx219_mode5[] = 380 | { 381 | {0x0100, 0x00}, 382 | {0x30eb, 0x0c}, 383 | {0x30eb, 0x05}, 384 | {0x300a, 0xff}, 385 | {0x300b, 0xff}, 386 | {0x30eb, 0x05}, 387 | {0x30eb, 0x09}, 388 | {0x0114, 0x01}, 389 | {0x0128, 0x00}, 390 | {0x012a, 0x18}, 391 | {0x012b, 0x00}, 392 | {0x0164, 0x00}, 393 | {0x0165, 0x00}, 394 | {0x0166, 0x0c}, 395 | {0x0167, 0xcf}, 396 | {0x0168, 0x01}, 397 | {0x0169, 0x36}, 398 | {0x016a, 0x08}, 399 | {0x016b, 0x69}, 400 | {0x016c, 0x06}, 401 | {0x016d, 0x68}, 402 | {0x016e, 0x03}, 403 | {0x016f, 0x9a}, 404 | {0x0170, 0x01}, 405 | {0x0171, 0x01}, 406 | {0x0174, 0x01}, 407 | {0x0175, 0x01}, 408 | {0x018c, 0x0a}, 409 | {0x018d, 0x0a}, 410 | {0x0301, 0x05}, 411 | {0x0303, 0x01}, 412 | {0x0304, 0x03}, 413 | {0x0305, 0x03}, 414 | {0x0306, 0x00}, 415 | {0x0307, 0x39}, 416 | {0x0309, 0x0a}, 417 | {0x030b, 0x01}, 418 | {0x030c, 0x00}, 419 | {0x030d, 0x72}, 420 | {0x455e, 0x00}, 421 | {0x471e, 0x4b}, 422 | {0x4767, 0x0f}, 423 | {0x4750, 0x14}, 424 | {0x4540, 0x00}, 425 | {0x47b4, 0x14}, 426 | {0x4713, 0x30}, 427 | {0x478b, 0x10}, 428 | {0x478f, 0x10}, 429 | {0x4793, 0x10}, 430 | {0x4797, 0x0e}, 431 | {0x479b, 0x0e}, 432 | {0x0172, 0x03}, 433 | {0x0157, 0x00}, 434 | {0x0160, 0x05}, 435 | {0x0161, 0x2a}, 436 | {0x0162, 0x0d}, 437 | {0x0163, 0x78}, 438 | {0x015a, 0x00}, 439 | {0x015b, 0x31}, 440 | {0x0100, 0x01}, 441 | }; 442 | 443 | struct sensor_regs imx219_mode6[] = 444 | { 445 | {0x0100, 0x00}, 446 | {0x30eb, 0x05}, 447 | {0x30eb, 0x0c}, 448 | {0x300a, 0xff}, 449 | {0x300b, 0xff}, 450 | {0x30eb, 0x05}, 451 | {0x30eb, 0x09}, 452 | {0x0114, 0x01}, 453 | {0x0128, 0x00}, 454 | {0x012a, 0x18}, 455 | {0x012b, 0x00}, 456 | {0x0164, 0x01}, 457 | {0x0165, 0x68}, 458 | {0x0166, 0x0b}, 459 | {0x0167, 0x67}, 460 | {0x0168, 0x02}, 461 | {0x0169, 0x00}, 462 | {0x016a, 0x07}, 463 | {0x016b, 0x9f}, 464 | {0x016c, 0x05}, 465 | {0x016d, 0x00}, 466 | {0x016e, 0x02}, 467 | {0x016f, 0xd0}, 468 | {0x0170, 0x01}, 469 | {0x0171, 0x01}, 470 | {0x0174, 0x03}, 471 | {0x0175, 0x03}, 472 | {0x018c, 0x0a}, 473 | {0x018d, 0x0a}, 474 | {0x0301, 0x05}, 475 | {0x0303, 0x01}, 476 | {0x0304, 0x03}, 477 | {0x0305, 0x03}, 478 | {0x0306, 0x00}, 479 | {0x0307, 0x39}, 480 | {0x0309, 0x0a}, 481 | {0x030b, 0x01}, 482 | {0x030c, 0x00}, 483 | {0x030d, 0x72}, 484 | {0x455e, 0x00}, 485 | {0x471e, 0x4b}, 486 | {0x4767, 0x0f}, 487 | {0x4750, 0x14}, 488 | {0x4540, 0x00}, 489 | {0x47b4, 0x14}, 490 | {0x4713, 0x30}, 491 | {0x478b, 0x10}, 492 | {0x478f, 0x10}, 493 | {0x4793, 0x10}, 494 | {0x4797, 0x0e}, 495 | {0x479b, 0x0e}, 496 | {0x0172, 0x03}, 497 | {0x0157, 0x00}, 498 | {0x0160, 0x02}, 499 | {0x0161, 0x39}, 500 | {0x0162, 0x0d}, 501 | {0x0163, 0xe7}, 502 | {0x015a, 0x00}, 503 | {0x015b, 0x2f}, 504 | {0x0100, 0x01}, 505 | }; 506 | 507 | struct sensor_regs imx219_mode7[] = 508 | { 509 | {0x0100, 0x00}, 510 | {0x30eb, 0x05}, 511 | {0x30eb, 0x0c}, 512 | {0x300a, 0xff}, 513 | {0x300b, 0xff}, 514 | {0x30eb, 0x05}, 515 | {0x30eb, 0x09}, 516 | {0x0114, 0x01}, 517 | {0x0128, 0x00}, 518 | {0x012a, 0x18}, 519 | {0x012b, 0x00}, 520 | {0x0164, 0x03}, 521 | {0x0165, 0xe8}, 522 | {0x0166, 0x08}, 523 | {0x0167, 0xe7}, 524 | {0x0168, 0x02}, 525 | {0x0169, 0xf0}, 526 | {0x016a, 0x06}, 527 | {0x016b, 0xaf}, 528 | {0x016c, 0x02}, 529 | {0x016d, 0x80}, 530 | {0x016e, 0x01}, 531 | {0x016f, 0xe0}, 532 | {0x0170, 0x01}, 533 | {0x0171, 0x01}, 534 | {0x0174, 0x03}, 535 | {0x0175, 0x03}, 536 | {0x018c, 0x0a}, 537 | {0x018d, 0x0a}, 538 | {0x0301, 0x05}, 539 | {0x0303, 0x01}, 540 | {0x0304, 0x03}, 541 | {0x0305, 0x03}, 542 | {0x0306, 0x00}, 543 | {0x0307, 0x39}, 544 | {0x0309, 0x0a}, 545 | {0x030b, 0x01}, 546 | {0x030c, 0x00}, 547 | {0x030d, 0x72}, 548 | {0x455e, 0x00}, 549 | {0x471e, 0x4b}, 550 | {0x4767, 0x0f}, 551 | {0x4750, 0x14}, 552 | {0x4540, 0x00}, 553 | {0x47b4, 0x14}, 554 | {0x4713, 0x30}, 555 | {0x478b, 0x10}, 556 | {0x478f, 0x10}, 557 | {0x4793, 0x10}, 558 | {0x4797, 0x0e}, 559 | {0x479b, 0x0e}, 560 | {0x0172, 0x03}, 561 | {0x0157, 0x00}, 562 | {0x0160, 0x02}, 563 | {0x0161, 0x39}, 564 | {0x0162, 0x0d}, 565 | {0x0163, 0xe7}, 566 | {0x015a, 0x00}, 567 | {0x015b, 0x2f}, 568 | {0x0100, 0x01}, 569 | }; 570 | 571 | // clang-format on 572 | 573 | struct mode_def imx219_modes[] = { 574 | { 575 | .regs = imx219_8MPix, 576 | .num_regs = NUM_ELEMENTS(imx219_8MPix), 577 | .width = 3280, 578 | .height = 2464, 579 | .encoding = 0, 580 | .order = BAYER_ORDER_BGGR, 581 | .native_bit_depth = 10, 582 | .image_id = 0x2B, 583 | .data_lanes = 2, 584 | .min_vts = 2504, 585 | .line_time_ns = 18904, 586 | .timing = { 0, 0, 0, 0, 0 }, 587 | .term = { 0, 0 }, 588 | .black_level = 66, 589 | }, 590 | { 591 | .regs = imx219_mode1, 592 | .num_regs = NUM_ELEMENTS(imx219_mode1), 593 | .width = 1920, 594 | .height = 1080, 595 | .encoding = 0, 596 | .order = BAYER_ORDER_BGGR, 597 | .native_bit_depth = 10, 598 | .image_id = 0x2B, 599 | .data_lanes = 2, 600 | .min_vts = 1084, 601 | .line_time_ns = 18904, 602 | .timing = { 0, 0, 0, 0, 0 }, 603 | .term = { 0, 0 }, 604 | .black_level = 66, 605 | }, 606 | { 607 | .regs = imx219_mode2, 608 | .num_regs = NUM_ELEMENTS(imx219_mode2), 609 | .width = 3280, 610 | .height = 2464, 611 | .encoding = 0, 612 | .order = BAYER_ORDER_BGGR, 613 | .native_bit_depth = 10, 614 | .image_id = 0x2B, 615 | .data_lanes = 2, 616 | .min_vts = 2468, 617 | .line_time_ns = 18904, 618 | .timing = { 0, 0, 0, 0, 0 }, 619 | .term = { 0, 0 }, 620 | .black_level = 66, 621 | }, 622 | { 623 | .regs = imx219_mode3, 624 | .num_regs = NUM_ELEMENTS(imx219_mode3), 625 | .width = 3280, 626 | .height = 2464, 627 | .encoding = 0, 628 | .order = BAYER_ORDER_BGGR, 629 | .native_bit_depth = 10, 630 | .image_id = 0x2B, 631 | .data_lanes = 2, 632 | .min_vts = 2468, 633 | .line_time_ns = 18904, 634 | .timing = { 0, 0, 0, 0, 0 }, 635 | .term = { 0, 0 }, 636 | .black_level = 66, 637 | }, 638 | { 639 | .regs = imx219_mode4, 640 | .num_regs = NUM_ELEMENTS(imx219_mode4), 641 | .width = 1640, 642 | .height = 1232, 643 | .encoding = 0, 644 | .order = BAYER_ORDER_BGGR, 645 | .native_bit_depth = 10, 646 | .image_id = 0x2B, 647 | .data_lanes = 2, 648 | .min_vts = 1236, 649 | .line_time_ns = 18904, 650 | .timing = { 0, 0, 0, 0, 0 }, 651 | .term = { 0, 0 }, 652 | .black_level = 66, 653 | }, 654 | { 655 | .regs = imx219_mode5, 656 | .num_regs = NUM_ELEMENTS(imx219_mode5), 657 | .width = 1640, 658 | .height = 922, 659 | .encoding = 0, 660 | .order = BAYER_ORDER_BGGR, 661 | .native_bit_depth = 10, 662 | .image_id = 0x2B, 663 | .data_lanes = 2, 664 | .min_vts = 926, 665 | .line_time_ns = 18904, 666 | .timing = { 0, 0, 0, 0, 0 }, 667 | .term = { 0, 0 }, 668 | .black_level = 66, 669 | }, 670 | { 671 | .regs = imx219_mode6, 672 | .num_regs = NUM_ELEMENTS(imx219_mode6), 673 | .width = 1280, 674 | .height = 720, 675 | .encoding = 0, 676 | .order = BAYER_ORDER_BGGR, 677 | .native_bit_depth = 10, 678 | .image_id = 0x2B, 679 | .data_lanes = 2, 680 | .min_vts = 724, 681 | .line_time_ns = 19517, 682 | .timing = { 0, 0, 0, 0, 0 }, 683 | .term = { 0, 0 }, 684 | .black_level = 66, 685 | }, 686 | { 687 | .regs = imx219_mode7, 688 | .num_regs = NUM_ELEMENTS(imx219_mode7), 689 | .width = 640, 690 | .height = 480, 691 | .encoding = 0, 692 | .order = BAYER_ORDER_BGGR, 693 | .native_bit_depth = 10, 694 | .image_id = 0x2B, 695 | .data_lanes = 2, 696 | .min_vts = 484, 697 | .line_time_ns = 19517, 698 | .timing = { 0, 0, 0, 0, 0 }, 699 | .term = { 0, 0 }, 700 | .black_level = 66, 701 | }, 702 | }; 703 | 704 | // From 705 | // https://android.googlesource.com/kernel/bcm/+/android-bcm-tetra-3.10-lollipop-wear-release/drivers/media/video/imx219.c 706 | struct sensor_regs imx219_stop[] = { 707 | // to power down 708 | { 0x0100, 0x00 }, // disable streaming 709 | }; 710 | 711 | // ID, exposure, and gain register settings taken from 712 | // https://android.googlesource.com/kernel/bcm/+/android-bcm-tetra-3.10-lollipop-wear-release/drivers/media/video/imx219.c 713 | // Flip settings taken from 714 | // https://github.com/rellimmot/Sony-IMX219-Raspberry-Pi-V2-CMOS/blob/master/imx219mipiraw_Sensor.c#L585 715 | struct sensor_def imx219 = { 716 | .name = "imx219", 717 | .modes = imx219_modes, 718 | .num_modes = NUM_ELEMENTS(imx219_modes), 719 | .stop = imx219_stop, 720 | .num_stop_regs = NUM_ELEMENTS(imx219_stop), 721 | 722 | .i2c_addr = 0x10, 723 | .i2c_addressing = 2, 724 | .i2c_ident_length = 2, 725 | .i2c_ident_reg = 0x0000, 726 | .i2c_ident_value = 0x1902, // 0x0219 bytes reversed 727 | 728 | .vflip_reg = 0x172, 729 | .vflip_reg_bit = 1, 730 | .hflip_reg = 0x172, 731 | .hflip_reg_bit = 0, 732 | 733 | .exposure_reg = 0x015A, 734 | .exposure_reg_num_bits = 16, 735 | 736 | .vts_reg = 0x0160, 737 | .vts_reg_num_bits = 16, 738 | 739 | .gain_reg = 0x0157, 740 | .gain_reg_num_bits = 8, // Only valid up to 230. 741 | }; 742 | 743 | #endif 744 | -------------------------------------------------------------------------------- /imx477_modes.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020, Raspberry Pi Foundation 3 | Copyright (c) 2020, Dave Stevenson 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | * Neither the name of the copyright holder nor the 14 | names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #ifndef IMX477MODES_H_ 30 | #define IMX477MODES_H_ 31 | 32 | // clang-format off 33 | // We want to preserve 1 register per line. 34 | 35 | struct sensor_regs imx477_common_init[] = { 36 | {0x0100, 0x00}, 37 | {0x0136, 0x18}, 38 | {0x0137, 0x00}, 39 | {0xe000, 0x00}, 40 | {0xe07a, 0x01}, 41 | {0x0808, 0x02}, 42 | {0x4AE9, 0x18}, 43 | {0x4AEA, 0x08}, 44 | {0xF61C, 0x04}, 45 | {0xF61E, 0x04}, 46 | {0x4AE9, 0x21}, 47 | {0x4AEA, 0x80}, 48 | {0x38a8, 0x1F}, 49 | {0x38a9, 0xFF}, 50 | {0x38aa, 0x1F}, 51 | {0x38ab, 0xFF}, 52 | {0x55d4, 0x00}, 53 | {0x55d5, 0x00}, 54 | {0x55d6, 0x07}, 55 | {0x55d7, 0xFF}, 56 | {0x55e8, 0x07}, 57 | {0x55e9, 0xFF}, 58 | {0x55ea, 0x00}, 59 | {0x55eb, 0x00}, 60 | {0x574c, 0x07}, 61 | {0x574d, 0xFF}, 62 | {0x574e, 0x00}, 63 | {0x574f, 0x00}, 64 | {0x5754, 0x00}, 65 | {0x5755, 0x00}, 66 | {0x5756, 0x07}, 67 | {0x5757, 0xFF}, 68 | {0x5973, 0x04}, 69 | {0x5974, 0x01}, 70 | {0x5d13, 0xC3}, 71 | {0x5d14, 0x58}, 72 | {0x5d15, 0xA3}, 73 | {0x5d16, 0x1D}, 74 | {0x5d17, 0x65}, 75 | {0x5d18, 0x8C}, 76 | {0x5d1a, 0x06}, 77 | {0x5d1b, 0xA9}, 78 | {0x5d1c, 0x45}, 79 | {0x5d1d, 0x3A}, 80 | {0x5d1e, 0xAB}, 81 | {0x5d1f, 0x15}, 82 | {0x5d21, 0x0E}, 83 | {0x5d22, 0x52}, 84 | {0x5d23, 0xAA}, 85 | {0x5d24, 0x7D}, 86 | {0x5d25, 0x57}, 87 | {0x5d26, 0xA8}, 88 | {0x5d37, 0x5A}, 89 | {0x5d38, 0x5A}, 90 | {0x5d77, 0x7F}, 91 | {0x7B75, 0x0E}, 92 | {0x7B76, 0x0B}, 93 | {0x7B77, 0x08}, 94 | {0x7B78, 0x0A}, 95 | {0x7B79, 0x47}, 96 | {0x7B7C, 0x00}, 97 | {0x7B7D, 0x00}, 98 | {0x8D1F, 0x00}, 99 | {0x8D27, 0x00}, 100 | {0x9004, 0x03}, 101 | {0x9200, 0x50}, 102 | {0x9201, 0x6C}, 103 | {0x9202, 0x71}, 104 | {0x9203, 0x00}, 105 | {0x9204, 0x71}, 106 | {0x9205, 0x01}, 107 | {0x9371, 0x6A}, 108 | {0x9373, 0x6A}, 109 | {0x9375, 0x64}, 110 | {0x991A, 0x00}, 111 | {0x996B, 0x8C}, 112 | {0x996C, 0x64}, 113 | {0x996D, 0x50}, 114 | {0x9A4C, 0x0D}, 115 | {0x9A4D, 0x0D}, 116 | {0xA001, 0x0A}, 117 | {0xA003, 0x0A}, 118 | {0xA005, 0x0A}, 119 | {0xA006, 0x01}, 120 | {0xA007, 0xC0}, 121 | {0xA009, 0xC0}, 122 | {0x3D8A, 0x01}, 123 | {0x4421, 0x04}, 124 | {0x7B3B, 0x01}, 125 | {0x7B4C, 0x00}, 126 | {0x9905, 0x00}, 127 | {0x9907, 0x00}, 128 | {0x9909, 0x00}, 129 | {0x990B, 0x00}, 130 | {0x9944, 0x3C}, 131 | {0x9947, 0x3C}, 132 | {0x994A, 0x8C}, 133 | {0x994B, 0x50}, 134 | {0x994C, 0x1B}, 135 | {0x994D, 0x8C}, 136 | {0x994E, 0x50}, 137 | {0x994F, 0x1B}, 138 | {0x9950, 0x8C}, 139 | {0x9951, 0x1B}, 140 | {0x9952, 0x0A}, 141 | {0x9953, 0x8C}, 142 | {0x9954, 0x1B}, 143 | {0x9955, 0x0A}, 144 | {0x9A13, 0x04}, 145 | {0x9A14, 0x04}, 146 | {0x9A19, 0x00}, 147 | {0x9A1C, 0x04}, 148 | {0x9A1D, 0x04}, 149 | {0x9A26, 0x05}, 150 | {0x9A27, 0x05}, 151 | {0x9A2C, 0x01}, 152 | {0x9A2D, 0x03}, 153 | {0x9A2F, 0x05}, 154 | {0x9A30, 0x05}, 155 | {0x9A41, 0x00}, 156 | {0x9A46, 0x00}, 157 | {0x9A47, 0x00}, 158 | {0x9C17, 0x35}, 159 | {0x9C1D, 0x31}, 160 | {0x9C29, 0x50}, 161 | {0x9C3B, 0x2F}, 162 | {0x9C41, 0x6B}, 163 | {0x9C47, 0x2D}, 164 | {0x9C4D, 0x40}, 165 | {0x9C6B, 0x00}, 166 | {0x9C71, 0xC8}, 167 | {0x9C73, 0x32}, 168 | {0x9C75, 0x04}, 169 | {0x9C7D, 0x2D}, 170 | {0x9C83, 0x40}, 171 | {0x9C94, 0x3F}, 172 | {0x9C95, 0x3F}, 173 | {0x9C96, 0x3F}, 174 | {0x9C97, 0x00}, 175 | {0x9C98, 0x00}, 176 | {0x9C99, 0x00}, 177 | {0x9C9A, 0x3F}, 178 | {0x9C9B, 0x3F}, 179 | {0x9C9C, 0x3F}, 180 | {0x9CA0, 0x0F}, 181 | {0x9CA1, 0x0F}, 182 | {0x9CA2, 0x0F}, 183 | {0x9CA3, 0x00}, 184 | {0x9CA4, 0x00}, 185 | {0x9CA5, 0x00}, 186 | {0x9CA6, 0x1E}, 187 | {0x9CA7, 0x1E}, 188 | {0x9CA8, 0x1E}, 189 | {0x9CA9, 0x00}, 190 | {0x9CAA, 0x00}, 191 | {0x9CAB, 0x00}, 192 | {0x9CAC, 0x09}, 193 | {0x9CAD, 0x09}, 194 | {0x9CAE, 0x09}, 195 | {0x9CBD, 0x50}, 196 | {0x9CBF, 0x50}, 197 | {0x9CC1, 0x50}, 198 | {0x9CC3, 0x40}, 199 | {0x9CC5, 0x40}, 200 | {0x9CC7, 0x40}, 201 | {0x9CC9, 0x0A}, 202 | {0x9CCB, 0x0A}, 203 | {0x9CCD, 0x0A}, 204 | {0x9D17, 0x35}, 205 | {0x9D1D, 0x31}, 206 | {0x9D29, 0x50}, 207 | {0x9D3B, 0x2F}, 208 | {0x9D41, 0x6B}, 209 | {0x9D47, 0x42}, 210 | {0x9D4D, 0x5A}, 211 | {0x9D6B, 0x00}, 212 | {0x9D71, 0xC8}, 213 | {0x9D73, 0x32}, 214 | {0x9D75, 0x04}, 215 | {0x9D7D, 0x42}, 216 | {0x9D83, 0x5A}, 217 | {0x9D94, 0x3F}, 218 | {0x9D95, 0x3F}, 219 | {0x9D96, 0x3F}, 220 | {0x9D97, 0x00}, 221 | {0x9D98, 0x00}, 222 | {0x9D99, 0x00}, 223 | {0x9D9A, 0x3F}, 224 | {0x9D9B, 0x3F}, 225 | {0x9D9C, 0x3F}, 226 | {0x9D9D, 0x1F}, 227 | {0x9D9E, 0x1F}, 228 | {0x9D9F, 0x1F}, 229 | {0x9DA0, 0x0F}, 230 | {0x9DA1, 0x0F}, 231 | {0x9DA2, 0x0F}, 232 | {0x9DA3, 0x00}, 233 | {0x9DA4, 0x00}, 234 | {0x9DA5, 0x00}, 235 | {0x9DA6, 0x1E}, 236 | {0x9DA7, 0x1E}, 237 | {0x9DA8, 0x1E}, 238 | {0x9DA9, 0x00}, 239 | {0x9DAA, 0x00}, 240 | {0x9DAB, 0x00}, 241 | {0x9DAC, 0x09}, 242 | {0x9DAD, 0x09}, 243 | {0x9DAE, 0x09}, 244 | {0x9DC9, 0x0A}, 245 | {0x9DCB, 0x0A}, 246 | {0x9DCD, 0x0A}, 247 | {0x9E17, 0x35}, 248 | {0x9E1D, 0x31}, 249 | {0x9E29, 0x50}, 250 | {0x9E3B, 0x2F}, 251 | {0x9E41, 0x6B}, 252 | {0x9E47, 0x2D}, 253 | {0x9E4D, 0x40}, 254 | {0x9E6B, 0x00}, 255 | {0x9E71, 0xC8}, 256 | {0x9E73, 0x32}, 257 | {0x9E75, 0x04}, 258 | {0x9E94, 0x0F}, 259 | {0x9E95, 0x0F}, 260 | {0x9E96, 0x0F}, 261 | {0x9E97, 0x00}, 262 | {0x9E98, 0x00}, 263 | {0x9E99, 0x00}, 264 | {0x9EA0, 0x0F}, 265 | {0x9EA1, 0x0F}, 266 | {0x9EA2, 0x0F}, 267 | {0x9EA3, 0x00}, 268 | {0x9EA4, 0x00}, 269 | {0x9EA5, 0x00}, 270 | {0x9EA6, 0x3F}, 271 | {0x9EA7, 0x3F}, 272 | {0x9EA8, 0x3F}, 273 | {0x9EA9, 0x00}, 274 | {0x9EAA, 0x00}, 275 | {0x9EAB, 0x00}, 276 | {0x9EAC, 0x09}, 277 | {0x9EAD, 0x09}, 278 | {0x9EAE, 0x09}, 279 | {0x9EC9, 0x0A}, 280 | {0x9ECB, 0x0A}, 281 | {0x9ECD, 0x0A}, 282 | {0x9F17, 0x35}, 283 | {0x9F1D, 0x31}, 284 | {0x9F29, 0x50}, 285 | {0x9F3B, 0x2F}, 286 | {0x9F41, 0x6B}, 287 | {0x9F47, 0x42}, 288 | {0x9F4D, 0x5A}, 289 | {0x9F6B, 0x00}, 290 | {0x9F71, 0xC8}, 291 | {0x9F73, 0x32}, 292 | {0x9F75, 0x04}, 293 | {0x9F94, 0x0F}, 294 | {0x9F95, 0x0F}, 295 | {0x9F96, 0x0F}, 296 | {0x9F97, 0x00}, 297 | {0x9F98, 0x00}, 298 | {0x9F99, 0x00}, 299 | {0x9F9A, 0x2F}, 300 | {0x9F9B, 0x2F}, 301 | {0x9F9C, 0x2F}, 302 | {0x9F9D, 0x00}, 303 | {0x9F9E, 0x00}, 304 | {0x9F9F, 0x00}, 305 | {0x9FA0, 0x0F}, 306 | {0x9FA1, 0x0F}, 307 | {0x9FA2, 0x0F}, 308 | {0x9FA3, 0x00}, 309 | {0x9FA4, 0x00}, 310 | {0x9FA5, 0x00}, 311 | {0x9FA6, 0x1E}, 312 | {0x9FA7, 0x1E}, 313 | {0x9FA8, 0x1E}, 314 | {0x9FA9, 0x00}, 315 | {0x9FAA, 0x00}, 316 | {0x9FAB, 0x00}, 317 | {0x9FAC, 0x09}, 318 | {0x9FAD, 0x09}, 319 | {0x9FAE, 0x09}, 320 | {0x9FC9, 0x0A}, 321 | {0x9FCB, 0x0A}, 322 | {0x9FCD, 0x0A}, 323 | {0xA14B, 0xFF}, 324 | {0xA151, 0x0C}, 325 | {0xA153, 0x50}, 326 | {0xA155, 0x02}, 327 | {0xA157, 0x00}, 328 | {0xA1AD, 0xFF}, 329 | {0xA1B3, 0x0C}, 330 | {0xA1B5, 0x50}, 331 | {0xA1B9, 0x00}, 332 | {0xA24B, 0xFF}, 333 | {0xA257, 0x00}, 334 | {0xA2AD, 0xFF}, 335 | {0xA2B9, 0x00}, 336 | {0xB21F, 0x04}, 337 | {0xB35C, 0x00}, 338 | {0xB35E, 0x08}, 339 | {0x0112, 0x0C}, 340 | {0x0113, 0x0C}, 341 | {0x0114, 0x01}, 342 | {0x0350, 0x00}, 343 | {0xBCF1, 0x02}, 344 | }; 345 | 346 | // 12 mpix 10fps 347 | struct sensor_regs imx477_4056x3040_regs[] = { 348 | {0x0342, 0x5d}, 349 | {0x0343, 0xc0}, 350 | {0x0344, 0x00}, 351 | {0x0345, 0x00}, 352 | {0x0346, 0x00}, 353 | {0x0347, 0x00}, 354 | {0x0348, 0x0f}, 355 | {0x0349, 0xd7}, 356 | {0x034a, 0x0b}, 357 | {0x034b, 0xdf}, 358 | {0x00e3, 0x00}, 359 | {0x00e4, 0x00}, 360 | {0x00fc, 0x0a}, 361 | {0x00fd, 0x0a}, 362 | {0x00fe, 0x0a}, 363 | {0x00ff, 0x0a}, 364 | {0x0220, 0x00}, 365 | {0x0221, 0x11}, 366 | {0x0381, 0x01}, 367 | {0x0383, 0x01}, 368 | {0x0385, 0x01}, 369 | {0x0387, 0x01}, 370 | {0x0900, 0x00}, 371 | {0x0901, 0x11}, 372 | {0x0902, 0x02}, 373 | {0x3140, 0x02}, 374 | {0x3c00, 0x00}, 375 | {0x3c01, 0x03}, 376 | {0x3c02, 0xa2}, 377 | {0x3f0d, 0x01}, 378 | {0x5748, 0x07}, 379 | {0x5749, 0xff}, 380 | {0x574a, 0x00}, 381 | {0x574b, 0x00}, 382 | {0x7b75, 0x0a}, 383 | {0x7b76, 0x0c}, 384 | {0x7b77, 0x07}, 385 | {0x7b78, 0x06}, 386 | {0x7b79, 0x3c}, 387 | {0x7b53, 0x01}, 388 | {0x9369, 0x5a}, 389 | {0x936b, 0x55}, 390 | {0x936d, 0x28}, 391 | {0x9304, 0x00}, 392 | {0x9305, 0x00}, 393 | {0x9e9a, 0x2f}, 394 | {0x9e9b, 0x2f}, 395 | {0x9e9c, 0x2f}, 396 | {0x9e9d, 0x00}, 397 | {0x9e9e, 0x00}, 398 | {0x9e9f, 0x00}, 399 | {0xa2a9, 0x60}, 400 | {0xa2b7, 0x00}, 401 | {0x0401, 0x00}, 402 | {0x0404, 0x00}, 403 | {0x0405, 0x10}, 404 | {0x0408, 0x00}, 405 | {0x0409, 0x00}, 406 | {0x040a, 0x00}, 407 | {0x040b, 0x00}, 408 | {0x040c, 0x0f}, 409 | {0x040d, 0xd8}, 410 | {0x040e, 0x0b}, 411 | {0x040f, 0xe0}, 412 | {0x034c, 0x0f}, 413 | {0x034d, 0xd8}, 414 | {0x034e, 0x0b}, 415 | {0x034f, 0xe0}, 416 | {0x0301, 0x05}, 417 | {0x0303, 0x02}, 418 | {0x0305, 0x04}, 419 | {0x0306, 0x01}, 420 | {0x0307, 0x5e}, 421 | {0x0309, 0x0c}, 422 | {0x030b, 0x02}, 423 | {0x030d, 0x02}, 424 | {0x030e, 0x00}, 425 | {0x030f, 0x96}, 426 | {0x0310, 0x01}, 427 | {0x0820, 0x07}, 428 | {0x0821, 0x08}, 429 | {0x0822, 0x00}, 430 | {0x0823, 0x00}, 431 | {0x080a, 0x00}, 432 | {0x080b, 0x7f}, 433 | {0x080c, 0x00}, 434 | {0x080d, 0x4f}, 435 | {0x080e, 0x00}, 436 | {0x080f, 0x77}, 437 | {0x0810, 0x00}, 438 | {0x0811, 0x5f}, 439 | {0x0812, 0x00}, 440 | {0x0813, 0x57}, 441 | {0x0814, 0x00}, 442 | {0x0815, 0x4f}, 443 | {0x0816, 0x01}, 444 | {0x0817, 0x27}, 445 | {0x0818, 0x00}, 446 | {0x0819, 0x3f}, 447 | {0xe04c, 0x00}, 448 | {0xe04d, 0x7f}, 449 | {0xe04e, 0x00}, 450 | {0xe04f, 0x1f}, 451 | {0x3e20, 0x01}, 452 | {0x3e37, 0x00}, 453 | {0x3f50, 0x00}, 454 | {0x3f56, 0x02}, 455 | {0x3f57, 0xae}, 456 | {0x0101, 0x00}, 457 | {0x0202, 0x0b}, 458 | {0x0203, 0x80}, 459 | {0x0204, 0x00}, 460 | {0x0205, 0x00}, 461 | {0x0340, 0x0c}, 462 | {0x0341, 0x00}, 463 | {0x0100, 0x01}, 464 | }; 465 | 466 | // 2x2 binned. 40fps 467 | struct sensor_regs imx477_2028x1520_regs[] = { 468 | {0x0342, 0x31}, 469 | {0x0343, 0xc4}, 470 | {0x0344, 0x00}, 471 | {0x0345, 0x00}, 472 | {0x0346, 0x00}, 473 | {0x0347, 0x00}, 474 | {0x0348, 0x0f}, 475 | {0x0349, 0xd7}, 476 | {0x034a, 0x0b}, 477 | {0x034b, 0xdf}, 478 | {0x0220, 0x00}, 479 | {0x0221, 0x11}, 480 | {0x0381, 0x01}, 481 | {0x0383, 0x01}, 482 | {0x0385, 0x01}, 483 | {0x0387, 0x01}, 484 | {0x0900, 0x01}, 485 | {0x0901, 0x12}, 486 | {0x0902, 0x02}, 487 | {0x3140, 0x02}, 488 | {0x3c00, 0x00}, 489 | {0x3c01, 0x03}, 490 | {0x3c02, 0xa2}, 491 | {0x3f0d, 0x01}, 492 | {0x5748, 0x07}, 493 | {0x5749, 0xff}, 494 | {0x574a, 0x00}, 495 | {0x574b, 0x00}, 496 | {0x7b53, 0x01}, 497 | {0x9369, 0x73}, 498 | {0x936b, 0x64}, 499 | {0x936d, 0x5f}, 500 | {0x9304, 0x00}, 501 | {0x9305, 0x00}, 502 | {0x9e9a, 0x2f}, 503 | {0x9e9b, 0x2f}, 504 | {0x9e9c, 0x2f}, 505 | {0x9e9d, 0x00}, 506 | {0x9e9e, 0x00}, 507 | {0x9e9f, 0x00}, 508 | {0xa2a9, 0x60}, 509 | {0xa2b7, 0x00}, 510 | {0x0401, 0x01}, 511 | {0x0404, 0x00}, 512 | {0x0405, 0x20}, 513 | {0x0408, 0x00}, 514 | {0x0409, 0x00}, 515 | {0x040a, 0x00}, 516 | {0x040b, 0x00}, 517 | {0x040c, 0x0f}, 518 | {0x040d, 0xd8}, 519 | {0x040e, 0x0b}, 520 | {0x040f, 0xe0}, 521 | {0x034c, 0x07}, 522 | {0x034d, 0xec}, 523 | {0x034e, 0x05}, 524 | {0x034f, 0xf0}, 525 | {0x0301, 0x05}, 526 | {0x0303, 0x02}, 527 | {0x0305, 0x04}, 528 | {0x0306, 0x01}, 529 | {0x0307, 0x5e}, 530 | {0x0309, 0x0c}, 531 | {0x030b, 0x02}, 532 | {0x030d, 0x02}, 533 | {0x030e, 0x00}, 534 | {0x030f, 0x96}, 535 | {0x0310, 0x01}, 536 | {0x0820, 0x07}, 537 | {0x0821, 0x08}, 538 | {0x0822, 0x00}, 539 | {0x0823, 0x00}, 540 | {0x080a, 0x00}, 541 | {0x080b, 0x7f}, 542 | {0x080c, 0x00}, 543 | {0x080d, 0x4f}, 544 | {0x080e, 0x00}, 545 | {0x080f, 0x77}, 546 | {0x0810, 0x00}, 547 | {0x0811, 0x5f}, 548 | {0x0812, 0x00}, 549 | {0x0813, 0x57}, 550 | {0x0814, 0x00}, 551 | {0x0815, 0x4f}, 552 | {0x0816, 0x01}, 553 | {0x0817, 0x27}, 554 | {0x0818, 0x00}, 555 | {0x0819, 0x3f}, 556 | {0xe04c, 0x00}, 557 | {0xe04d, 0x7f}, 558 | {0xe04e, 0x00}, 559 | {0xe04f, 0x1f}, 560 | {0x3e20, 0x01}, 561 | {0x3e37, 0x00}, 562 | {0x3f50, 0x00}, 563 | {0x3f56, 0x01}, 564 | {0x3f57, 0x6c}, 565 | {0x0101, 0x00}, 566 | {0x0202, 0x05}, 567 | {0x0203, 0xf0}, 568 | {0x0204, 0x00}, 569 | {0x0205, 0x00}, 570 | {0x0340, 0x06}, 571 | {0x0341, 0x20}, 572 | {0x0100, 0x01}, 573 | }; 574 | 575 | // 1080p cropped mode 576 | struct sensor_regs imx477_2028x1080_regs[] = { 577 | {0x0342, 0x31}, 578 | {0x0343, 0xc4}, 579 | {0x0344, 0x00}, 580 | {0x0345, 0x00}, 581 | {0x0346, 0x01}, 582 | {0x0347, 0xb8}, 583 | {0x0348, 0x0f}, 584 | {0x0349, 0xd7}, 585 | {0x034a, 0x0a}, 586 | {0x034b, 0x27}, 587 | {0x0220, 0x00}, 588 | {0x0221, 0x11}, 589 | {0x0381, 0x01}, 590 | {0x0383, 0x01}, 591 | {0x0385, 0x01}, 592 | {0x0387, 0x01}, 593 | {0x0900, 0x01}, 594 | {0x0901, 0x12}, 595 | {0x0902, 0x02}, 596 | {0x3140, 0x02}, 597 | {0x3c00, 0x00}, 598 | {0x3c01, 0x03}, 599 | {0x3c02, 0xa2}, 600 | {0x3f0d, 0x01}, 601 | {0x5748, 0x07}, 602 | {0x5749, 0xff}, 603 | {0x574a, 0x00}, 604 | {0x574b, 0x00}, 605 | {0x7b53, 0x01}, 606 | {0x9369, 0x73}, 607 | {0x936b, 0x64}, 608 | {0x936d, 0x5f}, 609 | {0x9304, 0x00}, 610 | {0x9305, 0x00}, 611 | {0x9e9a, 0x2f}, 612 | {0x9e9b, 0x2f}, 613 | {0x9e9c, 0x2f}, 614 | {0x9e9d, 0x00}, 615 | {0x9e9e, 0x00}, 616 | {0x9e9f, 0x00}, 617 | {0xa2a9, 0x60}, 618 | {0xa2b7, 0x00}, 619 | {0x0401, 0x01}, 620 | {0x0404, 0x00}, 621 | {0x0405, 0x20}, 622 | {0x0408, 0x00}, 623 | {0x0409, 0x00}, 624 | {0x040a, 0x00}, 625 | {0x040b, 0x00}, 626 | {0x040c, 0x0f}, 627 | {0x040d, 0xd8}, 628 | {0x040e, 0x04}, 629 | {0x040f, 0x38}, 630 | {0x034c, 0x07}, 631 | {0x034d, 0xec}, 632 | {0x034e, 0x04}, 633 | {0x034f, 0x38}, 634 | {0x0301, 0x05}, 635 | {0x0303, 0x02}, 636 | {0x0305, 0x04}, 637 | {0x0306, 0x01}, 638 | {0x0307, 0x5e}, 639 | {0x0309, 0x0c}, 640 | {0x030b, 0x02}, 641 | {0x030d, 0x02}, 642 | {0x030e, 0x00}, 643 | {0x030f, 0x96}, 644 | {0x0310, 0x01}, 645 | {0x0820, 0x07}, 646 | {0x0821, 0x08}, 647 | {0x0822, 0x00}, 648 | {0x0823, 0x00}, 649 | {0x080a, 0x00}, 650 | {0x080b, 0x7f}, 651 | {0x080c, 0x00}, 652 | {0x080d, 0x4f}, 653 | {0x080e, 0x00}, 654 | {0x080f, 0x77}, 655 | {0x0810, 0x00}, 656 | {0x0811, 0x5f}, 657 | {0x0812, 0x00}, 658 | {0x0813, 0x57}, 659 | {0x0814, 0x00}, 660 | {0x0815, 0x4f}, 661 | {0x0816, 0x01}, 662 | {0x0817, 0x27}, 663 | {0x0818, 0x00}, 664 | {0x0819, 0x3f}, 665 | {0xe04c, 0x00}, 666 | {0xe04d, 0x7f}, 667 | {0xe04e, 0x00}, 668 | {0xe04f, 0x1f}, 669 | {0x3e20, 0x01}, 670 | {0x3e37, 0x00}, 671 | {0x3f50, 0x00}, 672 | {0x3f56, 0x01}, 673 | {0x3f57, 0x6c}, 674 | {0x0101, 0x00}, 675 | {0x0202, 0x04}, 676 | {0x0203, 0x40}, 677 | {0x0204, 0x00}, 678 | {0x0205, 0x00}, 679 | {0x0340, 0x04}, 680 | {0x0341, 0x6e}, 681 | {0x0100, 0x01}, 682 | }; 683 | 684 | // 4x4 binned. 120fps 685 | struct sensor_regs imx477_1012x760_regs[] = { 686 | {0x420b, 0x01}, 687 | {0x990c, 0x00}, 688 | {0x990d, 0x08}, 689 | {0x9956, 0x8c}, 690 | {0x9957, 0x64}, 691 | {0x9958, 0x50}, 692 | {0x9a48, 0x06}, 693 | {0x9a49, 0x06}, 694 | {0x9a4a, 0x06}, 695 | {0x9a4b, 0x06}, 696 | {0x9a4c, 0x06}, 697 | {0x9a4d, 0x06}, 698 | {0x0112, 0x0a}, 699 | {0x0113, 0x0a}, 700 | {0x0114, 0x01}, 701 | {0x0342, 0x14}, 702 | {0x0343, 0x60}, 703 | {0x0344, 0x00}, 704 | {0x0345, 0x00}, 705 | {0x0346, 0x00}, 706 | {0x0347, 0x00}, 707 | {0x0348, 0x0f}, 708 | {0x0349, 0xd3}, 709 | {0x034a, 0x0b}, 710 | {0x034b, 0xdf}, 711 | {0x00e3, 0x00}, 712 | {0x00e4, 0x00}, 713 | {0x00fc, 0x0a}, 714 | {0x00fd, 0x0a}, 715 | {0x00fe, 0x0a}, 716 | {0x00ff, 0x0a}, 717 | {0x0220, 0x00}, 718 | {0x0221, 0x11}, 719 | {0x0381, 0x01}, 720 | {0x0383, 0x01}, 721 | {0x0385, 0x01}, 722 | {0x0387, 0x03}, 723 | {0x0900, 0x01}, 724 | {0x0901, 0x22}, 725 | {0x0902, 0x02}, 726 | {0x3140, 0x02}, 727 | {0x3c00, 0x00}, 728 | {0x3c01, 0x01}, 729 | {0x3c02, 0x9c}, 730 | {0x3f0d, 0x00}, 731 | {0x5748, 0x00}, 732 | {0x5749, 0x00}, 733 | {0x574a, 0x00}, 734 | {0x574b, 0xa4}, 735 | {0x7b75, 0x0e}, 736 | {0x7b76, 0x09}, 737 | {0x7b77, 0x08}, 738 | {0x7b78, 0x06}, 739 | {0x7b79, 0x34}, 740 | {0x7b53, 0x00}, 741 | {0x9369, 0x73}, 742 | {0x936b, 0x64}, 743 | {0x936d, 0x5f}, 744 | {0x9304, 0x03}, 745 | {0x9305, 0x80}, 746 | {0x9e9a, 0x3f}, 747 | {0x9e9b, 0x3f}, 748 | {0x9e9c, 0x3f}, 749 | {0x9e9d, 0x27}, 750 | {0x9e9e, 0x27}, 751 | {0x9e9f, 0x27}, 752 | {0xa2a9, 0x27}, 753 | {0xa2b7, 0x03}, 754 | {0x0401, 0x01}, 755 | {0x0404, 0x00}, 756 | {0x0405, 0x20}, 757 | {0x0408, 0x00}, 758 | {0x0409, 0x00}, 759 | {0x040a, 0x00}, 760 | {0x040b, 0x00}, 761 | {0x040c, 0x07}, 762 | {0x040d, 0xea}, 763 | {0x040e, 0x02}, 764 | {0x040f, 0xf8}, 765 | {0x034c, 0x03}, 766 | {0x034d, 0xf4}, 767 | {0x034e, 0x02}, 768 | {0x034f, 0xf8}, 769 | {0x0301, 0x05}, 770 | {0x0303, 0x02}, 771 | {0x0305, 0x02}, 772 | {0x0306, 0x00}, 773 | {0x0307, 0xaf}, 774 | {0x0309, 0x0a}, 775 | {0x030b, 0x02}, 776 | {0x030d, 0x02}, 777 | {0x030e, 0x00}, 778 | {0x030f, 0x96}, 779 | {0x0310, 0x01}, 780 | {0x0820, 0x07}, 781 | {0x0821, 0x08}, 782 | {0x0822, 0x00}, 783 | {0x0823, 0x00}, 784 | {0x080a, 0x00}, 785 | {0x080b, 0x6f}, 786 | {0x080c, 0x00}, 787 | {0x080d, 0x3f}, 788 | {0x080e, 0x00}, 789 | {0x080f, 0xff}, 790 | {0x0810, 0x00}, 791 | {0x0811, 0x4f}, 792 | {0x0812, 0x00}, 793 | {0x0813, 0x47}, 794 | {0x0814, 0x00}, 795 | {0x0815, 0x37}, 796 | {0x0816, 0x00}, 797 | {0x0817, 0xe7}, 798 | {0x0818, 0x00}, 799 | {0x0819, 0x2f}, 800 | {0xe04c, 0x00}, 801 | {0xe04d, 0x5f}, 802 | {0xe04e, 0x00}, 803 | {0xe04f, 0x1f}, 804 | {0x3e20, 0x01}, 805 | {0x3e37, 0x00}, 806 | {0x3f50, 0x00}, 807 | {0x3f56, 0x00}, 808 | {0x3f57, 0x96}, 809 | {0x0101, 0x00}, 810 | {0x0202, 0x03}, 811 | {0x0203, 0x00}, 812 | {0x0204, 0x00}, 813 | {0x0205, 0x00}, 814 | {0x0340, 0x03}, 815 | {0x0341, 0x2e}, 816 | {0x0100, 0x01}, 817 | }; 818 | 819 | // clang-format on 820 | 821 | struct mode_def imx477_modes[] = { 822 | { 823 | .regs = imx477_4056x3040_regs, 824 | .num_regs = NUM_ELEMENTS(imx477_4056x3040_regs), 825 | .width = 4056, 826 | .height = 3040, 827 | .encoding = 0, 828 | .order = BAYER_ORDER_RGGB, 829 | .native_bit_depth = 12, 830 | .image_id = 0x2C, 831 | .data_lanes = 2, 832 | .min_vts = 3072, 833 | .line_time_ns = 0x5dc0, 834 | .timing = { 0, 0, 0, 0, 0 }, 835 | .term = { 0, 0 }, 836 | .black_level = 256, 837 | }, 838 | { 839 | .regs = imx477_2028x1520_regs, 840 | .num_regs = NUM_ELEMENTS(imx477_2028x1520_regs), 841 | .width = 2028, 842 | .height = 1520, 843 | .encoding = 0, 844 | .order = BAYER_ORDER_RGGB, 845 | .native_bit_depth = 12, 846 | .image_id = 0x2C, 847 | .data_lanes = 2, 848 | .min_vts = 1568, 849 | .line_time_ns = 0x31c4, 850 | .timing = { 0, 0, 0, 0, 0 }, 851 | .term = { 0, 0 }, 852 | .black_level = 256, 853 | }, 854 | { 855 | .regs = imx477_2028x1080_regs, 856 | .num_regs = NUM_ELEMENTS(imx477_2028x1080_regs), 857 | .width = 2028, 858 | .height = 1080, 859 | .encoding = 0, 860 | .order = BAYER_ORDER_RGGB, 861 | .native_bit_depth = 12, 862 | .image_id = 0x2C, 863 | .data_lanes = 2, 864 | .min_vts = 1134, 865 | .line_time_ns = 0x31c4, 866 | .timing = { 0, 0, 0, 0, 0 }, 867 | .term = { 0, 0 }, 868 | .black_level = 256, 869 | }, 870 | { 871 | .regs = imx477_1012x760_regs, 872 | .num_regs = NUM_ELEMENTS(imx477_1012x760_regs), 873 | .width = 1012, 874 | .height = 760, 875 | .encoding = 0, 876 | .order = BAYER_ORDER_RGGB, 877 | .native_bit_depth = 10, 878 | .image_id = 0x2B, 879 | .data_lanes = 2, 880 | .min_vts = 814, 881 | .line_time_ns = 0x1460, 882 | .timing = { 0, 0, 0, 0, 0 }, 883 | .term = { 0, 0 }, 884 | .black_level = 64, 885 | }, 886 | }; 887 | 888 | struct sensor_regs imx477_stop[] = { 889 | // to power down */ 890 | { 0x0100, 0x00 }, // disable streaming 891 | }; 892 | 893 | struct sensor_def imx477 = { 894 | .name = "imx477", 895 | .common_init = imx477_common_init, 896 | .num_common_init = NUM_ELEMENTS(imx477_common_init), 897 | .modes = imx477_modes, 898 | .num_modes = NUM_ELEMENTS(imx477_modes), 899 | .stop = imx477_stop, 900 | .num_stop_regs = NUM_ELEMENTS(imx477_stop), 901 | 902 | .i2c_addr = 0x1A, 903 | .i2c_addressing = 2, 904 | .i2c_ident_length = 2, 905 | .i2c_ident_reg = 0x0016, 906 | .i2c_ident_value = 0x7704, // Bytes reversed 907 | 908 | .vflip_reg = 0x0101, 909 | .vflip_reg_bit = 1, 910 | .hflip_reg = 0x0101, 911 | .hflip_reg_bit = 0, 912 | 913 | .exposure_reg = 0x0202, 914 | .exposure_reg_num_bits = 16, 915 | 916 | .vts_reg = 0x0340, 917 | .vts_reg_num_bits = 16, 918 | 919 | .gain_reg = 0x0204, 920 | .gain_reg_num_bits = 10, 921 | }; 922 | 923 | #endif 924 | -------------------------------------------------------------------------------- /ov5647_modes.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015-2017, Raspberry Pi Foundation 3 | Copyright (c) 2015, Dave Stevenson 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | * Neither the name of the copyright holder nor the 14 | names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | // These register settings were as logged off the line 30 | // by jbeale. There is a datasheet for OV5647 floating 31 | // about on the internet, but the Pi Foundation/Trading have 32 | // information from Omnivision under NDA, therefore 33 | // we can not offer support on this. 34 | // There is some information/discussion on the Freescale 35 | // i.MX6 forums about supporting OV5647 on that board. 36 | // There may be information available there that is of use. 37 | // 38 | // REQUESTS FOR SUPPORT ABOUT THESE REGISTER VALUES WILL 39 | // BE IGNORED. 40 | 41 | #ifndef OV5647MODES_H_ 42 | #define OV5647MODES_H_ 43 | 44 | // clang-format off 45 | // We want to preserve 1 register per line. 46 | 47 | struct sensor_regs ov5647_5MPix[] = { 48 | {0x0100, 0x00}, 49 | {0x0103, 0x01}, 50 | {0x3034, 0x1a}, 51 | {0x3035, 0x21}, 52 | {0x3036, 0x69}, 53 | {0x303c, 0x11}, 54 | {0x3106, 0xf5}, 55 | //{0x3821, 0x00}, //Written again later 56 | //{0x3820, 0x00}, //Written again later 57 | {0x3827, 0xec}, 58 | {0x370c, 0x03}, 59 | {0x3612, 0x5b}, 60 | {0x3618, 0x04}, 61 | {0x5000, 0x06}, 62 | {0x5002, 0x40}, 63 | {0x5003, 0x08}, 64 | {0x5a00, 0x08}, 65 | {0x3000, 0x00}, 66 | {0x3001, 0x00}, 67 | {0x3002, 0x00}, 68 | {0x3016, 0x08}, 69 | {0x3017, 0xe0}, 70 | {0x3018, 0x44}, 71 | {0x301c, 0xf8}, 72 | {0x301d, 0xf0}, 73 | {0x3a18, 0x00}, 74 | {0x3a19, 0xf8}, 75 | {0x3c01, 0x80}, 76 | {0x3b07, 0x0c}, 77 | {0x380c, 0x0b}, 78 | {0x380d, 0x1c}, 79 | {0x380e, 0x07}, 80 | {0x380f, 0xb0}, 81 | {0x3814, 0x11}, 82 | {0x3815, 0x11}, 83 | {0x3708, 0x64}, 84 | {0x3709, 0x12}, 85 | {0x3808, 0x0a}, 86 | {0x3809, 0x20}, 87 | {0x380a, 0x07}, 88 | {0x380b, 0x98}, 89 | {0x3800, 0x00}, 90 | {0x3801, 0x00}, 91 | {0x3802, 0x00}, 92 | {0x3803, 0x00}, 93 | {0x3804, 0x0a}, 94 | {0x3805, 0x3f}, 95 | {0x3806, 0x07}, 96 | {0x3807, 0xa3}, 97 | {0x3811, 0x10}, 98 | {0x3813, 0x06}, 99 | {0x3630, 0x2e}, 100 | {0x3632, 0xe2}, 101 | {0x3633, 0x23}, 102 | {0x3634, 0x44}, 103 | {0x3636, 0x06}, 104 | {0x3620, 0x64}, 105 | {0x3621, 0xe0}, 106 | {0x3600, 0x37}, 107 | {0x3704, 0xa0}, 108 | {0x3703, 0x5a}, 109 | {0x3715, 0x78}, 110 | {0x3717, 0x01}, 111 | {0x3731, 0x02}, 112 | {0x370b, 0x60}, 113 | {0x3705, 0x1a}, 114 | {0x3f05, 0x02}, 115 | {0x3f06, 0x10}, 116 | {0x3f01, 0x0a}, 117 | {0x3a08, 0x01}, 118 | {0x3a09, 0x28}, 119 | {0x3a0a, 0x00}, 120 | {0x3a0b, 0xf6}, 121 | {0x3a0d, 0x08}, 122 | {0x3a0e, 0x06}, 123 | {0x3a0f, 0x58}, 124 | {0x3a10, 0x50}, 125 | {0x3a1b, 0x58}, 126 | {0x3a1e, 0x50}, 127 | {0x3a11, 0x60}, 128 | {0x3a1f, 0x28}, 129 | {0x4001, 0x02}, 130 | {0x4004, 0x04}, 131 | {0x4000, 0x09}, 132 | {0x4837, 0x16}, 133 | {0x4800, 0x24}, 134 | {0x3503, 0x03}, 135 | {0x3820, 0x41}, 136 | {0x3821, 0x03}, 137 | {0x350A, 0x00}, 138 | {0x350B, 0x23}, 139 | {0x3212, 0x00}, 140 | {0x3500, 0x00}, 141 | {0x3501, 0x04}, 142 | {0x3502, 0x60}, 143 | {0x3212, 0x10}, 144 | {0x3212, 0xA0}, 145 | {0x0100, 0x01} 146 | }; 147 | 148 | struct sensor_regs ov5647_mode1[] = { 149 | {0x0100, 0x00}, 150 | {0x0103, 0x01}, 151 | {0x3034, 0x1A}, 152 | {0x3035, 0x21}, 153 | {0x3036, 0x62}, 154 | {0x303C, 0x11}, 155 | {0x3106, 0xF5}, 156 | {0x3827, 0xEC}, 157 | {0x370C, 0x03}, 158 | {0x3612, 0x5B}, 159 | {0x3618, 0x04}, 160 | {0x5000, 0x06}, 161 | {0x5002, 0x40}, 162 | {0x5003, 0x08}, 163 | {0x5A00, 0x08}, 164 | {0x3000, 0x00}, 165 | {0x3001, 0x00}, 166 | {0x3002, 0x00}, 167 | {0x3016, 0x08}, 168 | {0x3017, 0xE0}, 169 | {0x3018, 0x44}, 170 | {0x301C, 0xF8}, 171 | {0x301D, 0xF0}, 172 | {0x3A18, 0x00}, 173 | {0x3A19, 0xF8}, 174 | {0x3C01, 0x80}, 175 | {0x3B07, 0x0C}, 176 | {0x380C, 0x09}, 177 | {0x380D, 0x70}, 178 | {0x3814, 0x11}, 179 | {0x3815, 0x11}, 180 | {0x3708, 0x64}, 181 | {0x3709, 0x12}, 182 | {0x3808, 0x07}, 183 | {0x3809, 0x80}, 184 | {0x380A, 0x04}, 185 | {0x380B, 0x38}, 186 | {0x3800, 0x01}, 187 | {0x3801, 0x5C}, 188 | {0x3802, 0x01}, 189 | {0x3803, 0xB2}, 190 | {0x3804, 0x08}, 191 | {0x3805, 0xE3}, 192 | {0x3806, 0x05}, 193 | {0x3807, 0xF1}, 194 | {0x3811, 0x04}, 195 | {0x3813, 0x02}, 196 | {0x3630, 0x2E}, 197 | {0x3632, 0xE2}, 198 | {0x3633, 0x23}, 199 | {0x3634, 0x44}, 200 | {0x3636, 0x06}, 201 | {0x3620, 0x64}, 202 | {0x3621, 0xE0}, 203 | {0x3600, 0x37}, 204 | {0x3704, 0xA0}, 205 | {0x3703, 0x5A}, 206 | {0x3715, 0x78}, 207 | {0x3717, 0x01}, 208 | {0x3731, 0x02}, 209 | {0x370B, 0x60}, 210 | {0x3705, 0x1A}, 211 | {0x3F05, 0x02}, 212 | {0x3F06, 0x10}, 213 | {0x3F01, 0x0A}, 214 | {0x3A08, 0x01}, 215 | {0x3A09, 0x4B}, 216 | {0x3A0A, 0x01}, 217 | {0x3A0B, 0x13}, 218 | {0x3A0D, 0x04}, 219 | {0x3A0E, 0x03}, 220 | {0x3A0F, 0x58}, 221 | {0x3A10, 0x50}, 222 | {0x3A1B, 0x58}, 223 | {0x3A1E, 0x50}, 224 | {0x3A11, 0x60}, 225 | {0x3A1F, 0x28}, 226 | {0x4001, 0x02}, 227 | {0x4004, 0x04}, 228 | {0x4000, 0x09}, 229 | {0x4837, 0x19}, 230 | {0x4800, 0x34}, 231 | {0x3503, 0x03}, 232 | {0x3820, 0x00}, 233 | {0x3821, 0x02}, 234 | {0x380E, 0x04}, 235 | {0x380F, 0x66}, 236 | {0x350A, 0x00}, 237 | {0x350B, 0x10}, 238 | {0x3500, 0x00}, 239 | {0x3501, 0x15}, 240 | {0x3502, 0x20}, 241 | {0x3212, 0xA0}, 242 | {0x0100, 0x01}, 243 | }; 244 | 245 | struct sensor_regs ov5647_mode2[] = { 246 | {0x0100, 0x00}, 247 | {0x0103, 0x01}, 248 | {0x3034, 0x1A}, 249 | {0x3035, 0x21}, 250 | {0x3036, 0x69}, 251 | {0x303C, 0x11}, 252 | {0x3106, 0xF5}, 253 | {0x3827, 0xEC}, 254 | {0x370C, 0x03}, 255 | {0x3612, 0x5B}, 256 | {0x3618, 0x04}, 257 | {0x5000, 0x06}, 258 | {0x5002, 0x40}, 259 | {0x5003, 0x08}, 260 | {0x5A00, 0x08}, 261 | {0x3000, 0x00}, 262 | {0x3001, 0x00}, 263 | {0x3002, 0x00}, 264 | {0x3016, 0x08}, 265 | {0x3017, 0xE0}, 266 | {0x3018, 0x44}, 267 | {0x301C, 0xF8}, 268 | {0x301D, 0xF0}, 269 | {0x3A18, 0x00}, 270 | {0x3A19, 0xF8}, 271 | {0x3C01, 0x80}, 272 | {0x3B07, 0x0C}, 273 | {0x380C, 0x0B}, 274 | {0x380D, 0x1C}, 275 | {0x3814, 0x11}, 276 | {0x3815, 0x11}, 277 | {0x3708, 0x64}, 278 | {0x3709, 0x12}, 279 | {0x3808, 0x0A}, 280 | {0x3809, 0x20}, 281 | {0x380A, 0x07}, 282 | {0x380B, 0x98}, 283 | {0x3800, 0x00}, 284 | {0x3801, 0x00}, 285 | {0x3802, 0x00}, 286 | {0x3803, 0x00}, 287 | {0x3804, 0x0A}, 288 | {0x3805, 0x3F}, 289 | {0x3806, 0x07}, 290 | {0x3807, 0xA3}, 291 | {0x3811, 0x10}, 292 | {0x3813, 0x06}, 293 | {0x3630, 0x2E}, 294 | {0x3632, 0xE2}, 295 | {0x3633, 0x23}, 296 | {0x3634, 0x44}, 297 | {0x3636, 0x06}, 298 | {0x3620, 0x64}, 299 | {0x3621, 0xE0}, 300 | {0x3600, 0x37}, 301 | {0x3704, 0xA0}, 302 | {0x3703, 0x5A}, 303 | {0x3715, 0x78}, 304 | {0x3717, 0x01}, 305 | {0x3731, 0x02}, 306 | {0x370B, 0x60}, 307 | {0x3705, 0x1A}, 308 | {0x3F05, 0x02}, 309 | {0x3F06, 0x10}, 310 | {0x3F01, 0x0A}, 311 | {0x3A08, 0x01}, 312 | {0x3A09, 0x28}, 313 | {0x3A0A, 0x00}, 314 | {0x3A0B, 0xF6}, 315 | {0x3A0D, 0x08}, 316 | {0x3A0E, 0x06}, 317 | {0x3A0F, 0x58}, 318 | {0x3A10, 0x50}, 319 | {0x3A1B, 0x58}, 320 | {0x3A1E, 0x50}, 321 | {0x3A11, 0x60}, 322 | {0x3A1F, 0x28}, 323 | {0x4001, 0x02}, 324 | {0x4004, 0x04}, 325 | {0x4000, 0x09}, 326 | {0x4837, 0x16}, 327 | {0x4800, 0x24}, 328 | {0x3503, 0x03}, 329 | {0x3820, 0x00}, 330 | {0x3821, 0x02}, 331 | {0x380E, 0x08}, 332 | {0x380F, 0x03}, 333 | {0x350A, 0x00}, 334 | {0x350B, 0x10}, 335 | {0x3500, 0x00}, 336 | {0x3501, 0x13}, 337 | {0x3502, 0x40}, 338 | {0x3212, 0xA0}, 339 | {0x0100, 0x01}, 340 | }; 341 | 342 | struct sensor_regs ov5647_mode3[] = { 343 | {0x0100, 0x00}, 344 | {0x0103, 0x01}, 345 | {0x3034, 0x1A}, 346 | {0x3035, 0x21}, 347 | {0x3036, 0x34}, 348 | {0x303C, 0x11}, 349 | {0x3106, 0xF5}, 350 | {0x3827, 0xEC}, 351 | {0x370C, 0x03}, 352 | {0x3612, 0x5B}, 353 | {0x3618, 0x04}, 354 | {0x5000, 0x06}, 355 | {0x5002, 0x40}, 356 | {0x5003, 0x08}, 357 | {0x5A00, 0x08}, 358 | {0x3000, 0x00}, 359 | {0x3001, 0x00}, 360 | {0x3002, 0x00}, 361 | {0x3016, 0x08}, 362 | {0x3017, 0xE0}, 363 | {0x3018, 0x44}, 364 | {0x301C, 0xF8}, 365 | {0x301D, 0xF0}, 366 | {0x3A18, 0x00}, 367 | {0x3A19, 0xF8}, 368 | {0x3C01, 0x80}, 369 | {0x3B07, 0x0C}, 370 | {0x380C, 0x1F}, 371 | {0x380D, 0x1B}, 372 | {0x3814, 0x11}, 373 | {0x3815, 0x11}, 374 | {0x3708, 0x64}, 375 | {0x3709, 0x12}, 376 | {0x3808, 0x0A}, 377 | {0x3809, 0x20}, 378 | {0x380A, 0x07}, 379 | {0x380B, 0x98}, 380 | {0x3800, 0x00}, 381 | {0x3801, 0x00}, 382 | {0x3802, 0x00}, 383 | {0x3803, 0x00}, 384 | {0x3804, 0x0A}, 385 | {0x3805, 0x3F}, 386 | {0x3806, 0x07}, 387 | {0x3807, 0xA3}, 388 | {0x3811, 0x10}, 389 | {0x3813, 0x06}, 390 | {0x3630, 0x2E}, 391 | {0x3632, 0xE2}, 392 | {0x3633, 0x23}, 393 | {0x3634, 0x44}, 394 | {0x3636, 0x06}, 395 | {0x3620, 0x64}, 396 | {0x3621, 0xE0}, 397 | {0x3600, 0x37}, 398 | {0x3704, 0xA0}, 399 | {0x3703, 0x5A}, 400 | {0x3715, 0x78}, 401 | {0x3717, 0x01}, 402 | {0x3731, 0x02}, 403 | {0x370B, 0x60}, 404 | {0x3705, 0x1A}, 405 | {0x3F05, 0x02}, 406 | {0x3F06, 0x10}, 407 | {0x3F01, 0x0A}, 408 | {0x3A08, 0x01}, 409 | {0x3A09, 0x28}, 410 | {0x3A0A, 0x00}, 411 | {0x3A0B, 0xF6}, 412 | {0x3A0D, 0x08}, 413 | {0x3A0E, 0x06}, 414 | {0x3A0F, 0x58}, 415 | {0x3A10, 0x50}, 416 | {0x3A1B, 0x58}, 417 | {0x3A1E, 0x50}, 418 | {0x3A11, 0x60}, 419 | {0x3A1F, 0x28}, 420 | {0x4001, 0x02}, 421 | {0x4004, 0x04}, 422 | {0x4000, 0x09}, 423 | {0x4837, 0x16}, 424 | {0x4800, 0x24}, 425 | {0x3503, 0x03}, 426 | {0x3820, 0x00}, 427 | {0x3821, 0x02}, 428 | {0x380E, 0x15}, 429 | {0x380F, 0x56}, 430 | {0x350A, 0x00}, 431 | {0x350B, 0x10}, 432 | {0x3500, 0x00}, 433 | {0x3501, 0x03}, 434 | {0x3502, 0x60}, 435 | {0x3212, 0xA0}, 436 | {0x0100, 0x01}, 437 | }; 438 | 439 | struct sensor_regs ov5647_mode4[] = { 440 | {0x0100, 0x00}, 441 | {0x0103, 0x01}, 442 | {0x3034, 0x1A}, 443 | {0x3035, 0x21}, 444 | {0x3036, 0x62}, 445 | {0x303C, 0x11}, 446 | {0x3106, 0xF5}, 447 | {0x3827, 0xEC}, 448 | {0x370C, 0x03}, 449 | {0x3612, 0x59}, 450 | {0x3618, 0x00}, 451 | {0x5000, 0x06}, 452 | {0x5002, 0x40}, 453 | {0x5003, 0x08}, 454 | {0x5A00, 0x08}, 455 | {0x3000, 0x00}, 456 | {0x3001, 0x00}, 457 | {0x3002, 0x00}, 458 | {0x3016, 0x08}, 459 | {0x3017, 0xE0}, 460 | {0x3018, 0x44}, 461 | {0x301C, 0xF8}, 462 | {0x301D, 0xF0}, 463 | {0x3A18, 0x00}, 464 | {0x3A19, 0xF8}, 465 | {0x3C01, 0x80}, 466 | {0x3B07, 0x0C}, 467 | {0x3800, 0x00}, 468 | {0x3801, 0x00}, 469 | {0x3802, 0x00}, 470 | {0x3803, 0x00}, 471 | {0x3804, 0x0A}, 472 | {0x3805, 0x3F}, 473 | {0x3806, 0x07}, 474 | {0x3807, 0xA3}, 475 | {0x3808, 0x05}, 476 | {0x3809, 0x10}, 477 | {0x380A, 0x03}, 478 | {0x380B, 0xCC}, 479 | {0x380C, 0x07}, 480 | {0x380D, 0x68}, 481 | {0x3811, 0x10}, 482 | {0x3813, 0x06}, 483 | {0x3814, 0x31}, 484 | {0x3815, 0x31}, 485 | {0x3630, 0x2E}, 486 | {0x3632, 0xE2}, 487 | {0x3633, 0x23}, 488 | {0x3634, 0x44}, 489 | {0x3636, 0x06}, 490 | {0x3620, 0x64}, 491 | {0x3621, 0xE0}, 492 | {0x3600, 0x37}, 493 | {0x3704, 0xA0}, 494 | {0x3703, 0x5A}, 495 | {0x3715, 0x78}, 496 | {0x3717, 0x01}, 497 | {0x3731, 0x02}, 498 | {0x370B, 0x60}, 499 | {0x3705, 0x1A}, 500 | {0x3F05, 0x02}, 501 | {0x3F06, 0x10}, 502 | {0x3F01, 0x0A}, 503 | {0x3A08, 0x01}, 504 | {0x3A09, 0x28}, 505 | {0x3A0A, 0x00}, 506 | {0x3A0B, 0xF6}, 507 | {0x3A0D, 0x08}, 508 | {0x3A0E, 0x06}, 509 | {0x3A0F, 0x58}, 510 | {0x3A10, 0x50}, 511 | {0x3A1B, 0x58}, 512 | {0x3A1E, 0x50}, 513 | {0x3A11, 0x60}, 514 | {0x3A1F, 0x28}, 515 | {0x4001, 0x02}, 516 | {0x4004, 0x04}, 517 | {0x4000, 0x09}, 518 | {0x4837, 0x16}, 519 | {0x4800, 0x24}, 520 | {0x3503, 0x03}, 521 | {0x3820, 0x41}, 522 | {0x3821, 0x03}, 523 | {0x380E, 0x05}, 524 | {0x380F, 0x9B}, 525 | {0x350A, 0x00}, 526 | {0x350B, 0x10}, 527 | {0x3500, 0x00}, 528 | {0x3501, 0x1A}, 529 | {0x3502, 0xF0}, 530 | {0x3212, 0xA0}, 531 | {0x0100, 0x01}, 532 | }; 533 | 534 | struct sensor_regs ov5647_mode5[] = { 535 | {0x0100, 0x00}, 536 | {0x0103, 0x01}, 537 | {0x3034, 0x1A}, 538 | {0x3035, 0x21}, 539 | {0x3036, 0x62}, 540 | {0x303C, 0x11}, 541 | {0x3106, 0xF5}, 542 | {0x3827, 0xEC}, 543 | {0x370C, 0x03}, 544 | {0x3612, 0x59}, 545 | {0x3618, 0x00}, 546 | {0x5000, 0x06}, 547 | {0x5002, 0x40}, 548 | {0x5003, 0x08}, 549 | {0x5A00, 0x08}, 550 | {0x3000, 0x00}, 551 | {0x3001, 0x00}, 552 | {0x3002, 0x00}, 553 | {0x3016, 0x08}, 554 | {0x3017, 0xE0}, 555 | {0x3018, 0x44}, 556 | {0x301C, 0xF8}, 557 | {0x301D, 0xF0}, 558 | {0x3A18, 0x00}, 559 | {0x3A19, 0xF8}, 560 | {0x3C01, 0x80}, 561 | {0x3B07, 0x0C}, 562 | {0x3800, 0x00}, 563 | {0x3801, 0x00}, 564 | // NB This value IS INCORRECT, but has been incorrect for long enough 565 | // that changing it will cause complaints due to changing FOV. 566 | // (It should be (0x3802, 00), (0x3803, F0) to give a symmetric crop). 567 | // Correct the value so debug_mode isn't set, but the result is the same. 568 | {0x3802, 0x00}, 569 | {0x3803, 0x00}, 570 | {0x3804, 0x0A}, 571 | {0x3805, 0x3F}, 572 | //For a symmetric crop, use (0x3806, 0x06}, (0x3807,0xB3) 573 | {0x3806, 0x05}, 574 | {0x3807, 0xbf}, 575 | {0x3808, 0x05}, 576 | {0x3809, 0x10}, 577 | {0x380A, 0x02}, 578 | {0x380B, 0xDA}, 579 | {0x380C, 0x07}, 580 | {0x380D, 0x68}, 581 | {0x3811, 0x10}, 582 | {0x3813, 0x06}, 583 | {0x3814, 0x31}, 584 | {0x3815, 0x31}, 585 | {0x3630, 0x2E}, 586 | {0x3632, 0xE2}, 587 | {0x3633, 0x23}, 588 | {0x3634, 0x44}, 589 | {0x3636, 0x06}, 590 | {0x3620, 0x64}, 591 | {0x3621, 0xE0}, 592 | {0x3600, 0x37}, 593 | {0x3704, 0xA0}, 594 | {0x3703, 0x5A}, 595 | {0x3715, 0x78}, 596 | {0x3717, 0x01}, 597 | {0x3731, 0x02}, 598 | {0x370B, 0x60}, 599 | {0x3705, 0x1A}, 600 | {0x3F05, 0x02}, 601 | {0x3F06, 0x10}, 602 | {0x3F01, 0x0A}, 603 | {0x3A08, 0x01}, 604 | {0x3A09, 0x28}, 605 | {0x3A0A, 0x00}, 606 | {0x3A0B, 0xF6}, 607 | {0x3A0D, 0x08}, 608 | {0x3A0E, 0x06}, 609 | {0x3A0F, 0x58}, 610 | {0x3A10, 0x50}, 611 | {0x3A1B, 0x58}, 612 | {0x3A1E, 0x50}, 613 | {0x3A11, 0x60}, 614 | {0x3A1F, 0x28}, 615 | {0x4001, 0x02}, 616 | {0x4004, 0x04}, 617 | {0x4000, 0x09}, 618 | {0x4837, 0x16}, 619 | {0x4800, 0x24}, 620 | {0x3503, 0x03}, 621 | {0x3820, 0x41}, 622 | {0x3821, 0x03}, 623 | {0x380E, 0x05}, 624 | {0x380F, 0x9B}, 625 | {0x350A, 0x00}, 626 | {0x350B, 0x10}, 627 | {0x3500, 0x00}, 628 | {0x3501, 0x1A}, 629 | {0x3502, 0xF0}, 630 | {0x3212, 0xA0}, 631 | {0x0100, 0x01}, 632 | }; 633 | 634 | struct sensor_regs ov5647_mode6[] = { 635 | {0x0100, 0x00}, 636 | {0x0103, 0x01}, 637 | {0x3036, 0x46}, 638 | {0x303C, 0x11}, 639 | {0x370C, 0x03}, 640 | {0x3612, 0x59}, 641 | {0x3618, 0x00}, 642 | {0x5000, 0x06}, 643 | {0x5003, 0x08}, 644 | {0x5A00, 0x08}, 645 | {0x301D, 0xF0}, 646 | {0x3A18, 0x00}, 647 | {0x3A19, 0xF8}, 648 | {0x3C01, 0x80}, 649 | {0x3B07, 0x0C}, 650 | {0x380C, 0x07}, 651 | {0x380D, 0x3C}, 652 | {0x3814, 0x71}, 653 | {0x3815, 0x71}, 654 | {0x3708, 0x64}, 655 | {0x3709, 0x52}, 656 | {0x3808, 0x02}, 657 | {0x3809, 0x80}, 658 | {0x380A, 0x01}, 659 | {0x380B, 0xE0}, 660 | {0x3800, 0x00}, 661 | {0x3801, 0x10}, 662 | {0x3802, 0x00}, 663 | {0x3803, 0x00}, 664 | {0x3804, 0x0A}, 665 | {0x3805, 0x2F}, 666 | {0x3806, 0x07}, 667 | {0x3807, 0x9F}, 668 | {0x3630, 0x2E}, 669 | {0x3632, 0xE2}, 670 | {0x3633, 0x23}, 671 | {0x3634, 0x44}, 672 | {0x3620, 0x64}, 673 | {0x3621, 0xE0}, 674 | {0x3600, 0x37}, 675 | {0x3704, 0xA0}, 676 | {0x3703, 0x5A}, 677 | {0x3715, 0x78}, 678 | {0x3717, 0x01}, 679 | {0x3731, 0x02}, 680 | {0x370B, 0x60}, 681 | {0x3705, 0x1A}, 682 | {0x3F05, 0x02}, 683 | {0x3F06, 0x10}, 684 | {0x3F01, 0x0A}, 685 | {0x3A08, 0x01}, 686 | {0x3A09, 0x2E}, 687 | {0x3A0A, 0x00}, 688 | {0x3A0B, 0xFB}, 689 | {0x3A0D, 0x02}, 690 | {0x3A0E, 0x01}, 691 | {0x3A0F, 0x58}, 692 | {0x3A10, 0x50}, 693 | {0x3A1B, 0x58}, 694 | {0x3A1E, 0x50}, 695 | {0x3A11, 0x60}, 696 | {0x3A1F, 0x28}, 697 | {0x4001, 0x02}, 698 | {0x4004, 0x02}, 699 | {0x4000, 0x09}, 700 | {0x3000, 0x00}, 701 | {0x3001, 0x00}, 702 | {0x3002, 0x00}, 703 | {0x3017, 0xE0}, 704 | {0x3636, 0x06}, 705 | {0x3016, 0x08}, 706 | {0x3827, 0xEC}, 707 | {0x3018, 0x44}, 708 | {0x3035, 0x21}, 709 | {0x3106, 0xF5}, 710 | {0x3034, 0x1A}, 711 | {0x301C, 0xF8}, 712 | {0x4800, 0x34}, 713 | {0x3503, 0x03}, 714 | {0x3820, 0x41}, 715 | {0x3821, 0x03}, 716 | {0x380E, 0x02}, 717 | {0x380F, 0xEC}, 718 | {0x350A, 0x00}, 719 | {0x350B, 0x10}, 720 | {0x3500, 0x00}, 721 | {0x3501, 0x13}, 722 | {0x3502, 0xB0}, 723 | {0x3212, 0xA0}, 724 | {0x0100, 0x01}, 725 | }; 726 | 727 | struct sensor_regs ov5647_mode7[] = { 728 | {0x0100, 0x00}, 729 | {0x0103, 0x01}, 730 | {0x3034, 0x1A}, 731 | {0x3035, 0x21}, 732 | {0x3036, 0x69}, 733 | {0x303C, 0x11}, 734 | {0x3106, 0xF5}, 735 | {0x3827, 0xEC}, 736 | {0x370C, 0x0F}, 737 | {0x3612, 0x59}, 738 | {0x3618, 0x00}, 739 | {0x5000, 0x06}, 740 | {0x5002, 0x40}, 741 | {0x5003, 0x08}, 742 | {0x5A00, 0x08}, 743 | {0x3000, 0x00}, 744 | {0x3001, 0x00}, 745 | {0x3002, 0x00}, 746 | {0x3016, 0x08}, 747 | {0x3017, 0xE0}, 748 | {0x3018, 0x44}, 749 | {0x301C, 0xF8}, 750 | {0x301D, 0xF0}, 751 | {0x3A18, 0x00}, 752 | {0x3A19, 0xF8}, 753 | {0x3C01, 0x80}, 754 | {0x3B07, 0x0C}, 755 | {0x380C, 0x07}, 756 | {0x380D, 0x3C}, 757 | {0x3814, 0x71}, 758 | {0x3815, 0x35}, 759 | {0x3708, 0x64}, 760 | {0x3709, 0x52}, 761 | {0x3808, 0x02}, 762 | {0x3809, 0x80}, 763 | {0x380A, 0x01}, 764 | {0x380B, 0xE0}, 765 | {0x3800, 0x00}, 766 | {0x3801, 0x10}, 767 | {0x3802, 0x00}, 768 | {0x3803, 0x00}, 769 | {0x3804, 0x0A}, 770 | {0x3805, 0x2F}, 771 | {0x3806, 0x07}, 772 | {0x3807, 0x9F}, 773 | {0x3630, 0x2E}, 774 | {0x3632, 0xE2}, 775 | {0x3633, 0x23}, 776 | {0x3634, 0x44}, 777 | {0x3636, 0x06}, 778 | {0x3620, 0x64}, 779 | {0x3621, 0xE0}, 780 | {0x3600, 0x37}, 781 | {0x3704, 0xA0}, 782 | {0x3703, 0x5A}, 783 | {0x3715, 0x78}, 784 | {0x3717, 0x01}, 785 | {0x3731, 0x02}, 786 | {0x370B, 0x60}, 787 | {0x3705, 0x1A}, 788 | {0x3F05, 0x02}, 789 | {0x3F06, 0x10}, 790 | {0x3F01, 0x0A}, 791 | {0x3A08, 0x01}, 792 | {0x3A09, 0x2E}, 793 | {0x3A0A, 0x00}, 794 | {0x3A0B, 0xFB}, 795 | {0x3A0D, 0x02}, 796 | {0x3A0E, 0x01}, 797 | {0x3A0F, 0x58}, 798 | {0x3A10, 0x50}, 799 | {0x3A1B, 0x58}, 800 | {0x3A1E, 0x50}, 801 | {0x3A11, 0x60}, 802 | {0x3A1F, 0x28}, 803 | {0x4001, 0x02}, 804 | {0x4004, 0x02}, 805 | {0x4000, 0x09}, 806 | {0x4837, 0x17}, 807 | {0x4800, 0x34}, 808 | {0x3503, 0x03}, 809 | {0x3820, 0x41}, 810 | {0x3821, 0x03}, 811 | {0x380E, 0x03}, 812 | {0x380F, 0x12}, 813 | {0x350A, 0x00}, 814 | {0x350B, 0x10}, 815 | {0x3500, 0x00}, 816 | {0x3501, 0x1D}, 817 | {0x3502, 0x80}, 818 | {0x3212, 0xA0}, 819 | {0x0100, 0x01}, 820 | }; 821 | 822 | // clang-format on 823 | 824 | struct mode_def ov5647_modes[] = { 825 | { 826 | .regs = ov5647_5MPix, 827 | .num_regs = NUM_ELEMENTS(ov5647_5MPix), 828 | .width = 2592, 829 | .height = 1944, 830 | .encoding = 0, 831 | .order = BAYER_ORDER_GBRG, 832 | .native_bit_depth = 10, 833 | .image_id = 0x2B, 834 | .data_lanes = 2, 835 | .min_vts = 1968, 836 | .line_time_ns = 32503, 837 | .timing = { 0, 0, 0, 0, 0 }, 838 | .term = { 0, 0 }, 839 | .black_level = 16, 840 | .binning = 1, 841 | }, 842 | { 843 | .regs = ov5647_mode1, 844 | .num_regs = NUM_ELEMENTS(ov5647_mode1), 845 | .width = 1920, 846 | .height = 1080, 847 | .encoding = 0, 848 | .order = BAYER_ORDER_GBRG, 849 | .native_bit_depth = 10, 850 | .image_id = 0x2B, 851 | .data_lanes = 2, 852 | .min_vts = 1104, 853 | .line_time_ns = 29584, 854 | .timing = { 0, 0, 0, 0, 0 }, 855 | .term = { 0, 0 }, 856 | .black_level = 16, 857 | .binning = 1, 858 | }, 859 | { 860 | .regs = ov5647_mode2, 861 | .num_regs = NUM_ELEMENTS(ov5647_mode2), 862 | .width = 2592, 863 | .height = 1944, 864 | .encoding = 0, 865 | .order = BAYER_ORDER_GBRG, 866 | .native_bit_depth = 10, 867 | .image_id = 0x2B, 868 | .data_lanes = 2, 869 | .min_vts = 1968, 870 | .line_time_ns = 32503, 871 | .timing = { 0, 0, 0, 0, 0 }, 872 | .term = { 0, 0 }, 873 | .black_level = 16, 874 | .binning = 1, 875 | }, 876 | { 877 | .regs = ov5647_mode3, 878 | .num_regs = NUM_ELEMENTS(ov5647_mode3), 879 | .width = 2592, 880 | .height = 1944, 881 | .encoding = 0, 882 | .order = BAYER_ORDER_GBRG, 883 | .native_bit_depth = 10, 884 | .image_id = 0x2B, 885 | .data_lanes = 2, 886 | .min_vts = 1968, 887 | .line_time_ns = 183789, 888 | .timing = { 0, 0, 0, 0, 0 }, 889 | .term = { 0, 0 }, 890 | .black_level = 16, 891 | .binning = 1, 892 | }, 893 | { 894 | .regs = ov5647_mode4, 895 | .num_regs = NUM_ELEMENTS(ov5647_mode4), 896 | .width = 1296, 897 | .height = 976, 898 | .encoding = 0, 899 | .order = BAYER_ORDER_GBRG, 900 | .native_bit_depth = 10, 901 | .image_id = 0x2B, 902 | .data_lanes = 2, 903 | .min_vts = 996, 904 | .line_time_ns = 23216, 905 | .timing = { 0, 0, 0, 0, 0 }, 906 | .term = { 0, 0 }, 907 | .black_level = 16, 908 | .binning = 2, 909 | }, 910 | { 911 | .regs = ov5647_mode5, 912 | .num_regs = NUM_ELEMENTS(ov5647_mode5), 913 | .width = 1296, 914 | .height = 730, 915 | .encoding = 0, 916 | .order = BAYER_ORDER_GBRG, 917 | .native_bit_depth = 10, 918 | .image_id = 0x2B, 919 | .data_lanes = 2, 920 | .min_vts = 754, 921 | .line_time_ns = 23216, 922 | .timing = { 0, 0, 0, 0, 0 }, 923 | .term = { 0, 0 }, 924 | .black_level = 16, 925 | .binning = 2, 926 | }, 927 | { 928 | .regs = ov5647_mode6, 929 | .num_regs = NUM_ELEMENTS(ov5647_mode6), 930 | .width = 640, 931 | .height = 480, 932 | .encoding = 0, 933 | .order = BAYER_ORDER_GBRG, 934 | .native_bit_depth = 10, 935 | .image_id = 0x2B, 936 | .data_lanes = 2, 937 | .min_vts = 484, 938 | .line_time_ns = 31749, 939 | .timing = { 0, 0, 0, 0, 0 }, 940 | .term = { 0, 0 }, 941 | .black_level = 16, 942 | .binning = 4, 943 | }, 944 | { 945 | .regs = ov5647_mode7, 946 | .num_regs = NUM_ELEMENTS(ov5647_mode7), 947 | .width = 640, 948 | .height = 480, 949 | .encoding = 0, 950 | .order = BAYER_ORDER_GBRG, 951 | .native_bit_depth = 10, 952 | .image_id = 0x2B, 953 | .data_lanes = 2, 954 | .min_vts = 484, 955 | .line_time_ns = 21165, 956 | .timing = { 0, 0, 0, 0, 0 }, 957 | .term = { 0, 0 }, 958 | .black_level = 16, 959 | .binning = 4, 960 | }, 961 | }; 962 | 963 | struct sensor_regs ov5647_stop[] = { 964 | { 0x0100, 0x00 }, 965 | }; 966 | 967 | static int ov5647_set_crop(const struct sensor_def *sensor, struct mode_def *sensor_mode, 968 | const struct raspiraw_crop *cfg) 969 | { 970 | if (cfg->hinc >= 0) 971 | { 972 | modReg(sensor_mode, 0x3814, 0, 7, cfg->hinc, EQUAL); 973 | } 974 | 975 | if (cfg->vinc >= 0) 976 | { 977 | modReg(sensor_mode, 0x3815, 0, 7, cfg->vinc, EQUAL); 978 | } 979 | 980 | if (cfg->width > 0) 981 | { 982 | sensor_mode->width = cfg->width; 983 | modReg(sensor_mode, 0x3808, 0, 3, cfg->width >> 8, EQUAL); 984 | modReg(sensor_mode, 0x3809, 0, 7, cfg->width & 0xFF, EQUAL); 985 | } 986 | 987 | if (cfg->height > 0) 988 | { 989 | sensor_mode->height = cfg->height; 990 | modReg(sensor_mode, 0x380A, 0, 3, cfg->height >> 8, EQUAL); 991 | modReg(sensor_mode, 0x380B, 0, 7, cfg->height & 0xFF, EQUAL); 992 | } 993 | 994 | if (cfg->left > 0) 995 | { 996 | int val = cfg->left * sensor_mode->binning; 997 | modReg(sensor_mode, 0x3800, 0, 3, val >> 8, EQUAL); 998 | modReg(sensor_mode, 0x3801, 0, 7, val & 0xFF, EQUAL); 999 | } 1000 | 1001 | if (cfg->top > 0) 1002 | { 1003 | int val = cfg->top * sensor_mode->binning; 1004 | modReg(sensor_mode, 0x3802, 0, 3, val >> 8, EQUAL); 1005 | modReg(sensor_mode, 0x3803, 0, 7, val & 0xFF, EQUAL); 1006 | } 1007 | 1008 | return 0; 1009 | } 1010 | 1011 | // ID register settings taken from 1012 | // http://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1298623.html 1013 | struct sensor_def ov5647 = { 1014 | .name = "ov5647", 1015 | .modes = ov5647_modes, 1016 | .num_modes = NUM_ELEMENTS(ov5647_modes), 1017 | .stop = ov5647_stop, 1018 | .num_stop_regs = NUM_ELEMENTS(ov5647_stop), 1019 | 1020 | .i2c_addr = 0x36, 1021 | .i2c_addressing = 2, 1022 | .i2c_ident_length = 2, 1023 | .i2c_ident_reg = 0x300A, 1024 | .i2c_ident_value = 0x4756, // 0x5647 byte swapped 1025 | 1026 | .vflip_reg = 0x3820, 1027 | .vflip_reg_bit = 0, 1028 | .hflip_reg = 0x3821, 1029 | .hflip_reg_bit = 0, 1030 | 1031 | .exposure_reg = 0x3500, 1032 | .exposure_reg_num_bits = 20, 1033 | 1034 | .vts_reg = 0x380E, 1035 | .vts_reg_num_bits = 16, // total vertical size [15:8] and [7:0] (ov5647 1036 | // preliminary datasheet is inaccurate) 1037 | 1038 | .gain_reg = 0x350A, 1039 | .gain_reg_num_bits = 10, 1040 | 1041 | .set_crop = ov5647_set_crop, 1042 | }; 1043 | 1044 | #endif 1045 | -------------------------------------------------------------------------------- /raspiraw.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Raspberry Pi Foundation 3 | Copyright (c) 2015, Dave Stevenson 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | * Neither the name of the copyright holder nor the 14 | names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #define VERSION_STRING "0.0.3" 30 | 31 | #define _GNU_SOURCE 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include 40 | #include 41 | #define I2C_SLAVE_FORCE 0x0706 42 | #include "bcm_host.h" 43 | #include "interface/vcos/vcos.h" 44 | 45 | #include "interface/mmal/mmal.h" 46 | #include "interface/mmal/mmal_buffer.h" 47 | #include "interface/mmal/mmal_logging.h" 48 | #include "interface/mmal/util/mmal_connection.h" 49 | #include "interface/mmal/util/mmal_default_components.h" 50 | #include "interface/mmal/util/mmal_util.h" 51 | #include "interface/mmal/util/mmal_util_params.h" 52 | 53 | #include "interface/vcsm/user-vcsm.h" 54 | 55 | #include "RaspiCLI.h" 56 | 57 | #include 58 | 59 | #include "raw_header.h" 60 | 61 | #define DEFAULT_I2C_DEVICE 10 62 | #define ALT_I2C_DEVICE 0 63 | 64 | #define I2C_DEVICE_NAME_LEN 13 // "/dev/i2c-XXX"+NULL 65 | 66 | struct brcm_raw_header *brcm_header = NULL; 67 | 68 | enum bayer_order 69 | { 70 | // Carefully ordered so that an hflip is ^1, 71 | // and a vflip is ^2. 72 | BAYER_ORDER_BGGR, 73 | BAYER_ORDER_GBRG, 74 | BAYER_ORDER_GRBG, 75 | BAYER_ORDER_RGGB 76 | }; 77 | 78 | struct sensor_regs 79 | { 80 | uint16_t reg; 81 | uint16_t data; 82 | }; 83 | 84 | struct mode_def 85 | { 86 | struct sensor_regs *regs; 87 | int num_regs; 88 | int width; 89 | int height; 90 | MMAL_FOURCC_T encoding; 91 | enum bayer_order order; 92 | int native_bit_depth; 93 | uint8_t image_id; 94 | uint8_t data_lanes; 95 | int min_vts; 96 | int line_time_ns; 97 | uint32_t timing[5]; 98 | uint32_t term[2]; 99 | int black_level; 100 | 101 | int binning; /* Binning or skipping factor */ 102 | }; 103 | 104 | struct raspiraw_crop 105 | { 106 | int hinc; 107 | int vinc; 108 | int width; 109 | int height; 110 | int left; 111 | int top; 112 | }; 113 | 114 | struct sensor_def 115 | { 116 | char *name; 117 | struct sensor_regs *common_init; 118 | int num_common_init; 119 | struct mode_def *modes; 120 | int num_modes; 121 | struct sensor_regs *stop; 122 | int num_stop_regs; 123 | 124 | uint8_t i2c_addr; // Device I2C slave address 125 | int i2c_addressing; // Length of register address values 126 | int i2c_data_size; // Length of register data to write 127 | 128 | // Detecting the device 129 | int i2c_ident_length; // Length of I2C ID register 130 | uint16_t i2c_ident_reg; // ID register address 131 | uint16_t i2c_ident_value; // ID register value 132 | 133 | // Flip configuration 134 | uint16_t vflip_reg; // Register for VFlip 135 | int vflip_reg_bit; // Bit in that register for VFlip 136 | uint16_t hflip_reg; // Register for HFlip 137 | int hflip_reg_bit; // Bit in that register for HFlip 138 | int flips_dont_change_bayer_order; // Some sensors do not change the 139 | // Bayer order by adjusting X/Y 140 | // starts to compensate. 141 | 142 | uint16_t exposure_reg; 143 | int exposure_reg_num_bits; 144 | 145 | uint16_t vts_reg; 146 | int vts_reg_num_bits; 147 | 148 | uint16_t gain_reg; 149 | int gain_reg_num_bits; 150 | 151 | int (*set_crop)(const struct sensor_def *, struct mode_def *, const struct raspiraw_crop *cfg); 152 | }; 153 | 154 | // The process first loads the cleaned up dump of the registers 155 | // than updates the known registers to the proper values 156 | // based on: http://www.seeedstudio.com/wiki/images/3/3c/Ov5647_full.pdf 157 | enum operation 158 | { 159 | EQUAL, // Set bit to value 160 | SET, // Set bit 161 | CLEAR, // Clear bit 162 | XOR // Xor bit 163 | }; 164 | 165 | void modReg(struct mode_def *mode, uint16_t reg, int startBit, int endBit, int value, enum operation op); 166 | 167 | #define NUM_ELEMENTS(a) (sizeof(a) / sizeof(a[0])) 168 | 169 | #include "adv7282m_modes.h" 170 | #include "imx219_modes.h" 171 | #include "imx477_modes.h" 172 | #include "ov5647_modes.h" 173 | 174 | const struct sensor_def *sensors[] = { &ov5647, &imx219, &adv7282, &imx477, NULL }; 175 | 176 | enum 177 | { 178 | CommandHelp, 179 | CommandMode, 180 | CommandHFlip, 181 | CommandVFlip, 182 | CommandExposure, 183 | CommandGain, 184 | CommandOutput, 185 | CommandWriteHeader, 186 | CommandTimeout, 187 | CommandSaveRate, 188 | CommandBitDepth, 189 | CommandCameraNum, 190 | CommandExposureus, 191 | CommandI2cBus, 192 | CommandAwbGains, 193 | CommandRegs, 194 | CommandHinc, 195 | CommandVinc, 196 | CommandFps, 197 | CommandWidth, 198 | CommandHeight, 199 | CommandLeft, 200 | CommandTop, 201 | CommandVts, 202 | CommandLine, 203 | CommandWriteHeader0, 204 | CommandWriteHeaderG, 205 | CommandWriteTimestamps, 206 | CommandWriteEmpty, 207 | CommandDecodeMetadata, 208 | CommandAwb, 209 | CommandNoPreview, 210 | CommandProcessing, 211 | CommandPreview, 212 | CommandFullScreen, 213 | CommandOpacity, 214 | CommandProcessingYUV, 215 | CommandOutputYUV, 216 | }; 217 | 218 | static COMMAND_LIST cmdline_commands[] = { 219 | // clang-format off 220 | { CommandHelp, "-help", "?", "This help information", 0 }, 221 | { CommandMode, "-mode", "md", "Set sensor mode ", 1 }, 222 | { CommandHFlip, "-hflip", "hf", "Set horizontal flip", 0 }, 223 | { CommandVFlip, "-vflip", "vf", "Set vertical flip", 0 }, 224 | { CommandExposure, "-ss", "e", "Set the sensor exposure time (not calibrated units)", 0 }, 225 | { CommandGain, "-gain", "g", "Set the sensor gain code (not calibrated units)", 0 }, 226 | { CommandOutput, "-output", "o", "Set the output filename", 0 }, 227 | { CommandWriteHeader, "-header", "hd", "Write the BRCM header to the output file", 0 }, 228 | { CommandTimeout, "-timeout", "t", "Time (in ms) before shutting down (if not specified, set to 5s)", 1 }, 229 | { CommandSaveRate, "-saverate", "sr", "Save every Nth frame", 1 }, 230 | { CommandBitDepth, "-bitdepth", "b", "Set output raw bit depth (8, 10, 12 or 16, if not specified, set to sensor native)", 1 }, 231 | { CommandCameraNum, "-cameranum", "c", "Set camera number to use (0=CAM0, 1=CAM1).", 1 }, 232 | { CommandExposureus, "-expus", "eus", "Set the sensor exposure time in micro seconds.", -1 }, 233 | { CommandI2cBus, "-i2c", "y", "Set the I2C bus to use.", -1 }, 234 | { CommandAwbGains, "-awbgains", "awbg", "Set the AWB gains to use.", 1 }, 235 | { CommandRegs, "-regs", "r", "Change (current mode) regs", 0 }, 236 | { CommandHinc, "-hinc", "hi", "Set horizontal odd/even inc reg", -1 }, 237 | { CommandVinc, "-vinc", "vi", "Set vertical odd/even inc reg", -1 }, 238 | { CommandFps, "-fps", "f", "Set framerate regs", -1 }, 239 | { CommandWidth, "-width", "w", "Set current mode width", -1 }, 240 | { CommandHeight, "-height", "h", "Set current mode height", -1 }, 241 | { CommandLeft, "-left", "lt", "Set current mode left", -1 }, 242 | { CommandTop, "-top", "tp", "Set current mode top", -1 }, 243 | { CommandWriteHeader0, "-header0", "hd0", "Sets filename to write the BRCM header to", 0 }, 244 | { CommandWriteHeaderG, "-headerg", "hdg", "Sets filename to write the .pgm header to", 0 }, 245 | { CommandWriteTimestamps, "-tstamps", "ts", "Sets filename to write timestamps to", 0 }, 246 | { CommandWriteEmpty, "-empty", "emp", "Write empty output files", 0 }, 247 | { CommandDecodeMetadata, "-metadata", "m", "Decode register metadata", 0 }, 248 | { CommandAwb, "-awb", "awb", "Use a simple grey-world AWB algorithm", 0 }, 249 | { CommandNoPreview, "-nopreview", "n", "Do not send the stream to the display", 0 }, 250 | { CommandProcessing, "-processing", "P", "Pass images into an image processing function", 0 }, 251 | { CommandPreview, "-preview", "p", "Preview window settings <'x,y,w,h'>", 1 }, 252 | { CommandFullScreen, "-fullscreen", "fs", "Fullscreen preview mode", 0 }, 253 | { CommandOpacity, "-opacity", "op", "Preview window opacity (0-255)", 1 }, 254 | { CommandProcessingYUV, "-processing_yuv", "PY", "Pass processed YUV images into an image processing function", 0 }, 255 | { CommandOutputYUV, "-output_yuv", "oY", "Set the output filename for YUV data", 0 }, 256 | // clang-format on 257 | }; 258 | 259 | static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]); 260 | 261 | typedef struct pts_node 262 | { 263 | int idx; 264 | int64_t pts; 265 | struct pts_node *nxt; 266 | } * PTS_NODE_T; 267 | 268 | #define DEFAULT_PREVIEW_LAYER 3 269 | 270 | typedef struct raspiraw_params 271 | { 272 | struct raspiraw_crop crop; 273 | int mode; 274 | int hflip; 275 | int vflip; 276 | int exposure; 277 | int gain; 278 | char *output; 279 | int capture; 280 | int write_header; 281 | int timeout; 282 | int saverate; 283 | int bit_depth; 284 | int camera_num; 285 | int exposure_us; 286 | int i2c_bus; 287 | double awb_gains_r; 288 | double awb_gains_b; 289 | char *regs; 290 | double fps; 291 | char *write_header0; 292 | char *write_headerg; 293 | char *write_timestamps; 294 | int write_empty; 295 | PTS_NODE_T ptsa; 296 | PTS_NODE_T ptso; 297 | int decodemetadata; 298 | int awb; 299 | int no_preview; 300 | int processing; 301 | int fullscreen; // 0 is use previewRect, non-zero to use full screen 302 | int opacity; // Opacity of window - 0 = transparent, 255 = opaque 303 | MMAL_RECT_T 304 | preview_window; // Destination rectangle for the preview window. 305 | int capture_yuv; 306 | char *output_yuv; 307 | int processing_yuv; 308 | } RASPIRAW_PARAMS_T; 309 | 310 | typedef struct 311 | { 312 | RASPIRAW_PARAMS_T *cfg; 313 | 314 | MMAL_POOL_T *rawcam_pool; 315 | MMAL_PORT_T *rawcam_output; 316 | 317 | MMAL_POOL_T *isp_ip_pool; 318 | MMAL_PORT_T *isp_ip; 319 | 320 | MMAL_QUEUE_T *awb_queue; 321 | int awb_thread_quit; 322 | MMAL_PARAMETER_AWB_GAINS_T wb_gains; 323 | 324 | MMAL_QUEUE_T *processing_queue; 325 | int processing_thread_quit; 326 | } RASPIRAW_CALLBACK_T; 327 | 328 | typedef struct 329 | { 330 | RASPIRAW_PARAMS_T *cfg; 331 | 332 | MMAL_POOL_T *isp_op_pool; 333 | MMAL_PORT_T *isp_output; 334 | 335 | MMAL_POOL_T *vr_ip_pool; 336 | MMAL_PORT_T *vr_ip; 337 | 338 | MMAL_QUEUE_T *processing_yuv_queue; 339 | int processing_yuv_thread_quit; 340 | } RASPIRAW_ISP_CALLBACK_T; 341 | 342 | void update_regs(const struct sensor_def *sensor, struct mode_def *mode, int hflip, int vflip, int exposure, int gain); 343 | 344 | static int i2c_rd(int fd, uint8_t i2c_addr, uint16_t reg, uint8_t *values, uint32_t n, const struct sensor_def *sensor) 345 | { 346 | int err; 347 | uint8_t buf[2] = { reg >> 8, reg & 0xff }; 348 | struct i2c_rdwr_ioctl_data msgset; 349 | struct i2c_msg msgs[2] = { 350 | { 351 | .addr = i2c_addr, 352 | .flags = 0, 353 | .len = 2, 354 | .buf = buf, 355 | }, 356 | { 357 | .addr = i2c_addr, 358 | .flags = I2C_M_RD, 359 | .len = n, 360 | .buf = values, 361 | }, 362 | }; 363 | 364 | if (sensor->i2c_addressing == 1) 365 | { 366 | msgs[0].len = 1; 367 | } 368 | msgset.msgs = msgs; 369 | msgset.nmsgs = 2; 370 | 371 | err = ioctl(fd, I2C_RDWR, &msgset); 372 | // vcos_log_error("Read i2c addr %02X, reg %04X (len %d), value %02X, 373 | // err %d", i2c_addr, msgs[0].buf[0], msgs[0].len, values[0], err); 374 | if (err != (int)msgset.nmsgs) 375 | return -1; 376 | 377 | return 0; 378 | } 379 | 380 | const struct sensor_def *probe_sensor(int fd) 381 | { 382 | const struct sensor_def **sensor_list = &sensors[0]; 383 | const struct sensor_def *sensor = NULL; 384 | 385 | while (*sensor_list != NULL) 386 | { 387 | uint16_t reg = 0; 388 | sensor = *sensor_list; 389 | vcos_log_error("Probing sensor %s on addr %02X", sensor->name, sensor->i2c_addr); 390 | if (sensor->i2c_ident_length <= 2) 391 | { 392 | if (!i2c_rd(fd, sensor->i2c_addr, sensor->i2c_ident_reg, (uint8_t *)®, 393 | sensor->i2c_ident_length, sensor)) 394 | { 395 | if (reg == sensor->i2c_ident_value) 396 | { 397 | vcos_log_error("Found sensor %s at address %02X", sensor->name, 398 | sensor->i2c_addr); 399 | break; 400 | } 401 | } 402 | } 403 | sensor_list++; 404 | sensor = NULL; 405 | } 406 | return sensor; 407 | } 408 | 409 | void send_regs(int fd, const struct sensor_def *sensor, const struct sensor_regs *regs, int num_regs) 410 | { 411 | int i; 412 | for (i = 0; i < num_regs; i++) 413 | { 414 | if (regs[i].reg == 0xFFFF) 415 | { 416 | if (ioctl(fd, I2C_SLAVE_FORCE, regs[i].data) < 0) 417 | { 418 | vcos_log_error("Failed to set I2C address to %02X", regs[i].data); 419 | } 420 | } 421 | else if (regs[i].reg == 0xFFFE) 422 | { 423 | vcos_sleep(regs[i].data); 424 | } 425 | else 426 | { 427 | if (sensor->i2c_addressing == 1) 428 | { 429 | unsigned char msg[3] = { regs[i].reg, regs[i].data & 0xFF }; 430 | int len = 2; 431 | 432 | if (sensor->i2c_data_size == 2) 433 | { 434 | msg[1] = (regs[i].data >> 8) & 0xFF; 435 | msg[2] = regs[i].data & 0xFF; 436 | len = 3; 437 | } 438 | if (write(fd, msg, len) != len) 439 | { 440 | vcos_log_error("Failed to write register index %d " 441 | "(%02X val %02X)", 442 | i, regs[i].reg, regs[i].data); 443 | } 444 | } 445 | else 446 | { 447 | unsigned char msg[4] = { regs[i].reg >> 8, regs[i].reg, regs[i].data }; 448 | int len = 3; 449 | 450 | if (sensor->i2c_data_size == 2) 451 | { 452 | msg[2] = regs[i].data >> 8; 453 | msg[3] = regs[i].data; 454 | len = 4; 455 | } 456 | if (write(fd, msg, len) != len) 457 | { 458 | vcos_log_error("Failed to write register index %d", i); 459 | } 460 | } 461 | } 462 | } 463 | } 464 | 465 | void start_camera_streaming(const struct sensor_def *sensor, struct mode_def *mode, int fd) 466 | { 467 | if (ioctl(fd, I2C_SLAVE_FORCE, sensor->i2c_addr) < 0) 468 | { 469 | vcos_log_error("Failed to set I2C address"); 470 | return; 471 | } 472 | if (sensor->common_init) 473 | send_regs(fd, sensor, sensor->common_init, sensor->num_common_init); 474 | send_regs(fd, sensor, mode->regs, mode->num_regs); 475 | vcos_log_error("Now streaming..."); 476 | } 477 | 478 | void stop_camera_streaming(const struct sensor_def *sensor, int fd) 479 | { 480 | if (ioctl(fd, I2C_SLAVE_FORCE, sensor->i2c_addr) < 0) 481 | { 482 | vcos_log_error("Failed to set I2C address"); 483 | return; 484 | } 485 | send_regs(fd, sensor, sensor->stop, sensor->num_stop_regs); 486 | } 487 | 488 | /** 489 | * Allocates and generates a filename based on the 490 | * user-supplied pattern and the frame number. 491 | * On successful return, finalName and tempName point to malloc()ed strings 492 | * which must be freed externally. (On failure, returns nulls that 493 | * don't need free()ing.) 494 | * 495 | * @param finalName pointer receives an 496 | * @param pattern sprintf pattern with %d to be replaced by frame 497 | * @param frame for timelapse, the frame number 498 | * @return Returns a MMAL_STATUS_T giving result of operation 499 | */ 500 | 501 | MMAL_STATUS_T create_filenames(char **finalName, char *pattern, int frame) 502 | { 503 | *finalName = NULL; 504 | if (0 > asprintf(finalName, pattern, frame)) 505 | { 506 | return MMAL_ENOMEM; // It may be some other error, but it is not 507 | // worth getting it right 508 | } 509 | return MMAL_SUCCESS; 510 | } 511 | 512 | void decodemetadataline(uint8_t *data, int bpp) 513 | { 514 | int c = 1; 515 | uint8_t tag, dta; 516 | uint16_t reg = -1; 517 | 518 | if (data[0] == 0x0a) 519 | { 520 | 521 | while (data[c] != 0x07) 522 | { 523 | tag = data[c++]; 524 | if (bpp == 10 && (c % 5) == 4) 525 | c++; 526 | if (bpp == 12 && (c % 3) == 2) 527 | c++; 528 | dta = data[c++]; 529 | 530 | if (tag == 0xaa) 531 | reg = (reg & 0x00ff) | (dta << 8); 532 | else if (tag == 0xa5) 533 | reg = (reg & 0xff00) | dta; 534 | else if (tag == 0x5a) 535 | vcos_log_error("Register 0x%04x = 0x%02x", reg++, dta); 536 | else if (tag == 0x55) 537 | vcos_log_error("Skip 0x%04x", reg++); 538 | else 539 | vcos_log_error("Metadata decode failed %x %x %x", reg, tag, dta); 540 | } 541 | } 542 | else 543 | vcos_log_error("Doesn't looks like register set %x!=0x0a", data[0]); 544 | } 545 | 546 | int encoding_to_bpp(uint32_t encoding) 547 | { 548 | switch (encoding) 549 | { 550 | case MMAL_ENCODING_BAYER_SBGGR10P: 551 | case MMAL_ENCODING_BAYER_SGBRG10P: 552 | case MMAL_ENCODING_BAYER_SGRBG10P: 553 | case MMAL_ENCODING_BAYER_SRGGB10P: 554 | return 10; 555 | case MMAL_ENCODING_BAYER_SBGGR12P: 556 | case MMAL_ENCODING_BAYER_SGBRG12P: 557 | case MMAL_ENCODING_BAYER_SGRBG12P: 558 | case MMAL_ENCODING_BAYER_SRGGB12P: 559 | return 12; 560 | default: 561 | return 8; 562 | }; 563 | } 564 | 565 | static void buffers_to_rawcam(RASPIRAW_CALLBACK_T *dev) 566 | { 567 | MMAL_BUFFER_HEADER_T *buffer; 568 | 569 | while ((buffer = mmal_queue_get(dev->rawcam_pool->queue)) != NULL) 570 | { 571 | mmal_port_send_buffer(dev->rawcam_output, buffer); 572 | // vcos_log_error("Buffer %p to rawcam\n", buffer); 573 | } 574 | } 575 | 576 | static void callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) 577 | { 578 | static int count = 0; 579 | RASPIRAW_CALLBACK_T *dev = (RASPIRAW_CALLBACK_T *)port->userdata; 580 | RASPIRAW_PARAMS_T *cfg = (RASPIRAW_PARAMS_T *)dev->cfg; 581 | MMAL_STATUS_T status; 582 | 583 | // vcos_log_error("Buffer %p returned, filled %d, timestamp %llu, flags %04X", buffer, buffer->length, 584 | // buffer->pts, buffer->flags); 585 | if (cfg->capture) 586 | { 587 | 588 | if (!(buffer->flags & MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO) && (((count++) % cfg->saverate) == 0)) 589 | { 590 | // Save every Nth frame 591 | // SD card access is too slow to do much more. 592 | FILE *file; 593 | char *filename = NULL; 594 | if (create_filenames(&filename, cfg->output, count) == MMAL_SUCCESS) 595 | { 596 | file = fopen(filename, "wb"); 597 | if (file) 598 | { 599 | if (cfg->ptso) // make sure previous 600 | // malloc() was 601 | // successful 602 | { 603 | cfg->ptso->idx = count; 604 | cfg->ptso->pts = buffer->pts; 605 | cfg->ptso->nxt = malloc(sizeof(*cfg->ptso->nxt)); 606 | cfg->ptso = cfg->ptso->nxt; 607 | } 608 | if (!cfg->write_empty) 609 | { 610 | if (cfg->write_header) 611 | fwrite(brcm_header, BRCM_RAW_HEADER_LENGTH, 1, file); 612 | fwrite(buffer->user_data, buffer->length, 1, file); 613 | } 614 | fclose(file); 615 | } 616 | free(filename); 617 | } 618 | } 619 | } 620 | 621 | if (cfg->decodemetadata && (buffer->flags & MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO)) 622 | { 623 | int bpp = encoding_to_bpp(port->format->encoding); 624 | int pitch = mmal_encoding_width_to_stride(port->format->encoding, port->format->es->video.width); 625 | 626 | vcos_log_error("First metadata line"); 627 | decodemetadataline(buffer->user_data, bpp); 628 | vcos_log_error("Second metadata line"); 629 | decodemetadataline(buffer->user_data + pitch, bpp); 630 | } 631 | 632 | /* Pass the buffers off to any other MMAL sinks. */ 633 | if (buffer->length && !(buffer->flags & MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO)) 634 | { 635 | if (dev->isp_ip) 636 | { 637 | MMAL_BUFFER_HEADER_T *out = mmal_queue_get(dev->isp_ip_pool->queue); 638 | if (out) 639 | { 640 | // vcos_log_error("replicate buffer %p for isp", buffer); 641 | mmal_buffer_header_replicate(out, buffer); 642 | out->data = buffer->data; 643 | out->alloc_size = buffer->alloc_size; 644 | status = mmal_port_send_buffer(dev->isp_ip, out); 645 | if (status != MMAL_SUCCESS) 646 | vcos_log_error("Failed to send buffer " 647 | "%p to isp - %d", 648 | buffer, status); 649 | } 650 | } 651 | 652 | /* Pass to the AWB thread */ 653 | if (dev->awb_queue) 654 | { 655 | /* Relying on the AWB thread to release this 656 | * buffer`refcount */ 657 | mmal_buffer_header_acquire(buffer); 658 | mmal_queue_put(dev->awb_queue, buffer); 659 | // vcos_log_error("send buffer %p to awb", buffer); 660 | } 661 | 662 | /* Pass to the processing thread */ 663 | if (dev->processing_queue) 664 | { 665 | /* Relying on the processing thread to release this 666 | * buffer`refcount */ 667 | mmal_buffer_header_acquire(buffer); 668 | mmal_queue_put(dev->processing_queue, buffer); 669 | // vcos_log_error("send buffer %p to awb", buffer); 670 | } 671 | } 672 | 673 | mmal_buffer_header_release(buffer); 674 | 675 | buffers_to_rawcam(dev); 676 | } 677 | 678 | static void buffers_to_isp_op(RASPIRAW_ISP_CALLBACK_T *dev) 679 | { 680 | MMAL_BUFFER_HEADER_T *buffer; 681 | 682 | while ((buffer = mmal_queue_get(dev->isp_op_pool->queue)) != NULL) 683 | { 684 | mmal_port_send_buffer(dev->isp_output, buffer); 685 | // vcos_log_error("Buffer %p to isp op\n", buffer); 686 | } 687 | } 688 | 689 | static void yuv_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) 690 | { 691 | static int count = 0; 692 | RASPIRAW_ISP_CALLBACK_T *yuv_cb = (RASPIRAW_ISP_CALLBACK_T *)port->userdata; 693 | RASPIRAW_PARAMS_T *cfg = (RASPIRAW_PARAMS_T *)yuv_cb->cfg; 694 | MMAL_STATUS_T status; 695 | 696 | // vcos_log_error("Buffer %p returned, filled %d, timestamp %llu, flags 697 | // %04X", buffer, buffer->length, buffer->pts, buffer->flags); 698 | if (cfg->capture_yuv) 699 | { 700 | 701 | if (!(buffer->flags & MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO) && (((count++) % cfg->saverate) == 0)) 702 | { 703 | // Save every Nth frame 704 | // SD card access is too slow to do much more. 705 | FILE *file; 706 | char *filename = NULL; 707 | if (create_filenames(&filename, cfg->output_yuv, count) == MMAL_SUCCESS) 708 | { 709 | file = fopen(filename, "wb"); 710 | if (file) 711 | { 712 | if (!cfg->write_empty) 713 | { 714 | fwrite(buffer->user_data, buffer->length, 1, file); 715 | } 716 | fclose(file); 717 | } 718 | free(filename); 719 | } 720 | } 721 | } 722 | 723 | /* Pass the buffers off to any other MMAL sinks. */ 724 | if (buffer->length && !(buffer->flags & MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO)) 725 | { 726 | if (yuv_cb->vr_ip) 727 | { 728 | MMAL_BUFFER_HEADER_T *out = mmal_queue_get(yuv_cb->vr_ip_pool->queue); 729 | if (out) 730 | { 731 | // vcos_log_error("replicate buffer %p for vr", 732 | // buffer); 733 | mmal_buffer_header_replicate(out, buffer); 734 | out->data = buffer->data; 735 | out->alloc_size = buffer->alloc_size; 736 | status = mmal_port_send_buffer(yuv_cb->vr_ip, out); 737 | if (status != MMAL_SUCCESS) 738 | vcos_log_error("Failed to send buffer %p to video " 739 | "render - %d", 740 | buffer, status); 741 | } 742 | } 743 | 744 | /* Pass to the processing thread */ 745 | if (yuv_cb->processing_yuv_queue) 746 | { 747 | /* Relying on the processing thread to release this 748 | * buffer's refcount */ 749 | mmal_buffer_header_acquire(buffer); 750 | mmal_queue_put(yuv_cb->processing_yuv_queue, buffer); 751 | // vcos_log_error("send buffer %p to yuv processing", 752 | // buffer); 753 | } 754 | } 755 | 756 | mmal_buffer_header_release(buffer); 757 | 758 | buffers_to_isp_op(yuv_cb); 759 | } 760 | 761 | uint32_t order_and_bit_depth_to_encoding(enum bayer_order order, int bit_depth) 762 | { 763 | // BAYER_ORDER_BGGR, 764 | // BAYER_ORDER_GBRG, 765 | // BAYER_ORDER_GRBG, 766 | // BAYER_ORDER_RGGB 767 | const uint32_t depth8[] = { MMAL_ENCODING_BAYER_SBGGR8, MMAL_ENCODING_BAYER_SGBRG8, MMAL_ENCODING_BAYER_SGRBG8, 768 | MMAL_ENCODING_BAYER_SRGGB8 }; 769 | const uint32_t depth10[] = { MMAL_ENCODING_BAYER_SBGGR10P, MMAL_ENCODING_BAYER_SGBRG10P, 770 | MMAL_ENCODING_BAYER_SGRBG10P, MMAL_ENCODING_BAYER_SRGGB10P }; 771 | const uint32_t depth12[] = { 772 | MMAL_ENCODING_BAYER_SBGGR12P, 773 | MMAL_ENCODING_BAYER_SGBRG12P, 774 | MMAL_ENCODING_BAYER_SGRBG12P, 775 | MMAL_ENCODING_BAYER_SRGGB12P, 776 | }; 777 | const uint32_t depth16[] = { 778 | MMAL_ENCODING_BAYER_SBGGR16, 779 | MMAL_ENCODING_BAYER_SGBRG16, 780 | MMAL_ENCODING_BAYER_SGRBG16, 781 | MMAL_ENCODING_BAYER_SRGGB16, 782 | }; 783 | if (order < 0 || order > 3) 784 | { 785 | vcos_log_error("order out of range - %d", order); 786 | return 0; 787 | } 788 | 789 | switch (bit_depth) 790 | { 791 | case 8: 792 | return depth8[order]; 793 | case 10: 794 | return depth10[order]; 795 | case 12: 796 | return depth12[order]; 797 | case 16: 798 | return depth16[order]; 799 | } 800 | vcos_log_error("%d not one of the handled bit depths", bit_depth); 801 | return 0; 802 | } 803 | 804 | /** 805 | * Parse the incoming command line and put resulting parameters in to the state 806 | * 807 | * @param argc Number of arguments in command line 808 | * @param argv Array of pointers to strings from command line 809 | * @param state Pointer to state structure to assign any discovered parameters 810 | * to 811 | * @return non-0 if failed for some reason, 0 otherwise 812 | */ 813 | static int parse_cmdline(int argc, char **argv, RASPIRAW_PARAMS_T *cfg) 814 | { 815 | // Parse the command line arguments. 816 | // We are looking for -- or - 817 | 818 | int valid = 1; 819 | int i; 820 | 821 | for (i = 1; i < argc && valid; i++) 822 | { 823 | int command_id, num_parameters, len; 824 | 825 | if (!argv[i]) 826 | continue; 827 | 828 | if (argv[i][0] != '-') 829 | { 830 | valid = 0; 831 | continue; 832 | } 833 | 834 | // Assume parameter is valid until proven otherwise 835 | valid = 1; 836 | 837 | command_id = 838 | raspicli_get_command_id(cmdline_commands, cmdline_commands_size, &argv[i][1], &num_parameters); 839 | 840 | // If we found a command but are missing a parameter, continue 841 | // (and we will drop out of the loop) 842 | if (command_id != -1 && num_parameters > 0 && (i + 1 >= argc)) 843 | continue; 844 | 845 | // We are now dealing with a command line option 846 | switch (command_id) 847 | { 848 | case CommandHelp: 849 | raspicli_display_help(cmdline_commands, cmdline_commands_size); 850 | // exit straight away if help requested 851 | return -1; 852 | 853 | case CommandMode: 854 | if (sscanf(argv[i + 1], "%d", &cfg->mode) != 1) 855 | valid = 0; 856 | else 857 | i++; 858 | break; 859 | 860 | case CommandHFlip: 861 | cfg->hflip = 1; 862 | break; 863 | 864 | case CommandVFlip: 865 | cfg->vflip = 1; 866 | break; 867 | 868 | case CommandExposure: 869 | if (sscanf(argv[i + 1], "%d", &cfg->exposure) != 1) 870 | valid = 0; 871 | else 872 | i++; 873 | break; 874 | 875 | case CommandGain: 876 | if (sscanf(argv[i + 1], "%d", &cfg->gain) != 1) 877 | valid = 0; 878 | else 879 | i++; 880 | break; 881 | 882 | case CommandOutput: // output filename 883 | { 884 | len = strlen(argv[i + 1]); 885 | if (len) 886 | { 887 | // We use sprintf to append the frame number for 888 | // timelapse mode Ensure that any % is 889 | // either %% or %d. 890 | const char *percent = argv[i + 1]; 891 | while (valid && *percent && (percent = strchr(percent, '%')) != NULL) 892 | { 893 | int digits = 0; 894 | percent++; 895 | while (isdigit(*percent)) 896 | { 897 | percent++; 898 | digits++; 899 | } 900 | if (!((*percent == '%' && !digits) || *percent == 'd')) 901 | { 902 | valid = 0; 903 | fprintf(stderr, "Filename contains %% " 904 | "characters, but not " 905 | "%%d or %%%% - sorry, " 906 | "will fail\n"); 907 | } 908 | percent++; 909 | } 910 | cfg->output = malloc(len + 10); // leave enough space for any timelapse 911 | // generated changes to filename 912 | if (cfg->output) 913 | { 914 | strncpy(cfg->output, argv[i + 1], len + 1); 915 | i++; 916 | cfg->capture = 1; 917 | } 918 | else 919 | { 920 | fprintf(stderr, "internal error - " 921 | "allocation fail\n"); 922 | valid = 0; 923 | } 924 | } 925 | else 926 | { 927 | valid = 0; 928 | } 929 | break; 930 | } 931 | 932 | case CommandWriteHeader: 933 | cfg->write_header = 1; 934 | break; 935 | 936 | case CommandTimeout: // Time to run for in milliseconds 937 | if (sscanf(argv[i + 1], "%u", &cfg->timeout) == 1) 938 | { 939 | i++; 940 | } 941 | else 942 | valid = 0; 943 | break; 944 | 945 | case CommandSaveRate: 946 | if (sscanf(argv[i + 1], "%u", &cfg->saverate) == 1) 947 | { 948 | i++; 949 | } 950 | else 951 | valid = 0; 952 | break; 953 | 954 | case CommandBitDepth: 955 | if (sscanf(argv[i + 1], "%u", &cfg->bit_depth) == 1) 956 | { 957 | i++; 958 | } 959 | else 960 | valid = 0; 961 | break; 962 | 963 | case CommandCameraNum: 964 | if (sscanf(argv[i + 1], "%u", &cfg->camera_num) == 1) 965 | { 966 | i++; 967 | if (cfg->camera_num != 0 && cfg->camera_num != 1) 968 | { 969 | fprintf(stderr, 970 | "Invalid camera number " 971 | "specified (%d)." 972 | " It should be 0 or 1.\n", 973 | cfg->camera_num); 974 | valid = 0; 975 | } 976 | } 977 | else 978 | valid = 0; 979 | break; 980 | 981 | case CommandExposureus: 982 | if (sscanf(argv[i + 1], "%d", &cfg->exposure_us) != 1) 983 | valid = 0; 984 | else 985 | i++; 986 | break; 987 | 988 | case CommandI2cBus: 989 | if (sscanf(argv[i + 1], "%d", &cfg->i2c_bus) != 1) 990 | valid = 0; 991 | else 992 | i++; 993 | break; 994 | 995 | case CommandAwbGains: 996 | { 997 | double r, b; 998 | int args; 999 | 1000 | args = sscanf(argv[i + 1], "%lf,%lf", &r, &b); 1001 | 1002 | if (args != 2 || r > 8.0 || b > 8.0) 1003 | valid = 0; 1004 | 1005 | cfg->awb_gains_r = r; 1006 | cfg->awb_gains_b = b; 1007 | 1008 | i++; 1009 | break; 1010 | } 1011 | 1012 | case CommandRegs: // register changes 1013 | { 1014 | len = strlen(argv[i + 1]); 1015 | cfg->regs = malloc(len + 1); 1016 | vcos_assert(cfg->regs); 1017 | strncpy(cfg->regs, argv[i + 1], len + 1); 1018 | i++; 1019 | break; 1020 | } 1021 | 1022 | case CommandHinc: 1023 | if (strlen(argv[i + 1]) != 2 || sscanf(argv[i + 1], "%x", &cfg->crop.hinc) != 1) 1024 | valid = 0; 1025 | else 1026 | i++; 1027 | break; 1028 | 1029 | case CommandVinc: 1030 | if (strlen(argv[i + 1]) != 2 || sscanf(argv[i + 1], "%x", &cfg->crop.vinc) != 1) 1031 | valid = 0; 1032 | else 1033 | i++; 1034 | break; 1035 | 1036 | case CommandFps: 1037 | if (sscanf(argv[i + 1], "%lf", &cfg->fps) != 1) 1038 | valid = 0; 1039 | else 1040 | i++; 1041 | break; 1042 | 1043 | case CommandWidth: 1044 | if (sscanf(argv[i + 1], "%d", &cfg->crop.width) != 1) 1045 | valid = 0; 1046 | else 1047 | i++; 1048 | break; 1049 | 1050 | case CommandHeight: 1051 | if (sscanf(argv[i + 1], "%d", &cfg->crop.height) != 1) 1052 | valid = 0; 1053 | else 1054 | i++; 1055 | break; 1056 | 1057 | case CommandLeft: 1058 | if (sscanf(argv[i + 1], "%d", &cfg->crop.left) != 1) 1059 | valid = 0; 1060 | else 1061 | i++; 1062 | break; 1063 | 1064 | case CommandTop: 1065 | if (sscanf(argv[i + 1], "%d", &cfg->crop.top) != 1) 1066 | valid = 0; 1067 | else 1068 | i++; 1069 | break; 1070 | 1071 | case CommandWriteHeader0: 1072 | len = strlen(argv[i + 1]); 1073 | cfg->write_header0 = malloc(len + 1); 1074 | vcos_assert(cfg->write_header0); 1075 | strncpy(cfg->write_header0, argv[i + 1], len + 1); 1076 | i++; 1077 | break; 1078 | 1079 | case CommandWriteHeaderG: 1080 | len = strlen(argv[i + 1]); 1081 | cfg->write_headerg = malloc(len + 1); 1082 | vcos_assert(cfg->write_headerg); 1083 | strncpy(cfg->write_headerg, argv[i + 1], len + 1); 1084 | i++; 1085 | break; 1086 | 1087 | case CommandWriteTimestamps: 1088 | len = strlen(argv[i + 1]); 1089 | cfg->write_timestamps = malloc(len + 1); 1090 | vcos_assert(cfg->write_timestamps); 1091 | strncpy(cfg->write_timestamps, argv[i + 1], len + 1); 1092 | i++; 1093 | cfg->ptsa = malloc(sizeof(*cfg->ptsa)); 1094 | cfg->ptso = cfg->ptsa; 1095 | break; 1096 | 1097 | case CommandWriteEmpty: 1098 | cfg->write_empty = 1; 1099 | break; 1100 | 1101 | case CommandDecodeMetadata: 1102 | cfg->decodemetadata = 1; 1103 | break; 1104 | 1105 | case CommandAwb: 1106 | vcos_log_error("Let's do AWB"); 1107 | cfg->awb = 1; 1108 | break; 1109 | 1110 | case CommandNoPreview: 1111 | cfg->no_preview = 1; 1112 | break; 1113 | 1114 | case CommandProcessing: 1115 | cfg->processing = 1; 1116 | break; 1117 | case CommandPreview: // Preview window 1118 | { 1119 | int tmp; 1120 | 1121 | tmp = sscanf(argv[i + 1], "%d,%d,%d,%d", &cfg->preview_window.x, &cfg->preview_window.y, 1122 | &cfg->preview_window.width, &cfg->preview_window.height); 1123 | 1124 | // Failed to get any window parameters, so revert to 1125 | // full screen 1126 | if (tmp != 4) 1127 | cfg->fullscreen = 1; 1128 | else 1129 | cfg->fullscreen = 0; 1130 | 1131 | i++; 1132 | 1133 | break; 1134 | } 1135 | 1136 | case CommandFullScreen: // Want full screen preview mode 1137 | // (overrides display rect) 1138 | cfg->fullscreen = 1; 1139 | 1140 | i++; 1141 | break; 1142 | 1143 | case CommandOpacity: // Define preview window opacity 1144 | if (sscanf(argv[i + 1], "%u", &cfg->opacity) != 1) 1145 | cfg->opacity = 255; 1146 | else 1147 | i++; 1148 | break; 1149 | 1150 | case CommandProcessingYUV: 1151 | cfg->processing_yuv = 1; 1152 | break; 1153 | 1154 | case CommandOutputYUV: // output filename 1155 | { 1156 | len = strlen(argv[i + 1]); 1157 | if (len) 1158 | { 1159 | // We use sprintf to append the frame number for 1160 | // timelapse mode Ensure that any % is 1161 | // either %% or %d. 1162 | const char *percent = argv[i + 1]; 1163 | while (valid && *percent && (percent = strchr(percent, '%')) != NULL) 1164 | { 1165 | int digits = 0; 1166 | percent++; 1167 | while (isdigit(*percent)) 1168 | { 1169 | percent++; 1170 | digits++; 1171 | } 1172 | if (!((*percent == '%' && !digits) || *percent == 'd')) 1173 | { 1174 | valid = 0; 1175 | fprintf(stderr, "Filename contains %% " 1176 | "characters, but not " 1177 | "%%d or %%%% - sorry, " 1178 | "will fail\n"); 1179 | } 1180 | percent++; 1181 | } 1182 | cfg->output_yuv = malloc(len + 10); // leave enough space for any timelapse 1183 | // generated changes to filename 1184 | if (cfg->output_yuv) 1185 | { 1186 | strncpy(cfg->output_yuv, argv[i + 1], len + 1); 1187 | i++; 1188 | cfg->capture_yuv = 1; 1189 | } 1190 | else 1191 | { 1192 | fprintf(stderr, "internal error - " 1193 | "allocation fail\n"); 1194 | valid = 0; 1195 | } 1196 | } 1197 | else 1198 | { 1199 | valid = 0; 1200 | } 1201 | break; 1202 | } 1203 | 1204 | default: 1205 | valid = 0; 1206 | break; 1207 | } 1208 | } 1209 | 1210 | if (!valid) 1211 | { 1212 | fprintf(stderr, "Invalid command line option (%s)\n", argv[i - 1]); 1213 | return 1; 1214 | } 1215 | 1216 | return 0; 1217 | } 1218 | 1219 | uint32_t get_pixel(int x, int y, uint32_t encoding, int stride, uint8_t *data) 1220 | { 1221 | uint32_t val; 1222 | const uint8_t raw10_masks[4] = { 0x03, 0x0c, 0x30, 0xc0 }; 1223 | const uint8_t raw10_shifts[4] = { 0, 2, 4, 6 }; 1224 | const uint8_t raw12_masks[2] = { 0x0f, 0xf0 }; 1225 | const uint8_t raw12_shifts[2] = { 0, 4 }; 1226 | 1227 | switch (encoding) 1228 | { 1229 | case MMAL_ENCODING_BAYER_SBGGR8: 1230 | case MMAL_ENCODING_BAYER_SGBRG8: 1231 | case MMAL_ENCODING_BAYER_SGRBG8: 1232 | case MMAL_ENCODING_BAYER_SRGGB8: 1233 | val = data[x + (y * stride)]; 1234 | break; 1235 | 1236 | case MMAL_ENCODING_BAYER_SBGGR10P: 1237 | case MMAL_ENCODING_BAYER_SGBRG10P: 1238 | case MMAL_ENCODING_BAYER_SGRBG10P: 1239 | case MMAL_ENCODING_BAYER_SRGGB10P: 1240 | val = data[x + (x / 4) + (y * stride)] << 2; 1241 | val |= (data[x + (x / 4) + 4 + (y * stride)] & raw10_masks[x & 3]) >> raw10_shifts[x & 3]; 1242 | break; 1243 | 1244 | case MMAL_ENCODING_BAYER_SBGGR12P: 1245 | case MMAL_ENCODING_BAYER_SGBRG12P: 1246 | case MMAL_ENCODING_BAYER_SGRBG12P: 1247 | case MMAL_ENCODING_BAYER_SRGGB12P: 1248 | val = data[x + (x / 2) + (y * stride)] << 4; 1249 | val |= (data[x + (x / 2) + 2 + (y * stride)] & raw12_masks[x & 1]) >> raw12_shifts[x & 1]; 1250 | break; 1251 | 1252 | case MMAL_ENCODING_BAYER_SBGGR16: 1253 | case MMAL_ENCODING_BAYER_SGBRG16: 1254 | case MMAL_ENCODING_BAYER_SGRBG16: 1255 | case MMAL_ENCODING_BAYER_SRGGB16: 1256 | { 1257 | /* CHECK ME: are the MSB and LSB the right way around? */ 1258 | uint16_t *data16 = (uint16_t *)data; 1259 | val = data16[x + (y * stride / 2)]; 1260 | break; 1261 | } 1262 | } 1263 | return val; 1264 | } 1265 | 1266 | enum channels 1267 | { 1268 | RED, 1269 | GREEN1, 1270 | GREEN2, 1271 | BLUE 1272 | }; 1273 | 1274 | uint64_t get_channel(enum channels chan, uint32_t encoding, uint64_t *sums) 1275 | { 1276 | const int bggr[4] = { BLUE, GREEN1, GREEN2, RED }; 1277 | const int rggb[4] = { RED, GREEN1, GREEN2, BLUE }; 1278 | const int gbrg[4] = { GREEN1, BLUE, RED, GREEN2 }; 1279 | const int grbg[4] = { GREEN1, RED, BLUE, GREEN2 }; 1280 | 1281 | switch (encoding) 1282 | { 1283 | case MMAL_ENCODING_BAYER_SBGGR8: 1284 | case MMAL_ENCODING_BAYER_SBGGR10P: 1285 | case MMAL_ENCODING_BAYER_SBGGR12P: 1286 | case MMAL_ENCODING_BAYER_SBGGR16: 1287 | return sums[bggr[chan]]; 1288 | 1289 | case MMAL_ENCODING_BAYER_SRGGB8: 1290 | case MMAL_ENCODING_BAYER_SRGGB10P: 1291 | case MMAL_ENCODING_BAYER_SRGGB12P: 1292 | case MMAL_ENCODING_BAYER_SRGGB16: 1293 | return sums[rggb[chan]]; 1294 | 1295 | case MMAL_ENCODING_BAYER_SGBRG8: 1296 | case MMAL_ENCODING_BAYER_SGBRG10P: 1297 | case MMAL_ENCODING_BAYER_SGBRG12P: 1298 | case MMAL_ENCODING_BAYER_SGBRG16: 1299 | return sums[gbrg[chan]]; 1300 | 1301 | case MMAL_ENCODING_BAYER_SGRBG8: 1302 | case MMAL_ENCODING_BAYER_SGRBG10P: 1303 | case MMAL_ENCODING_BAYER_SGRBG12P: 1304 | case MMAL_ENCODING_BAYER_SGRBG16: 1305 | return sums[grbg[chan]]; 1306 | 1307 | default: 1308 | return 0; 1309 | } 1310 | } 1311 | 1312 | static void run_awb_calcs(RASPIRAW_CALLBACK_T *dev, MMAL_BUFFER_HEADER_T *buffer) 1313 | { 1314 | int x, y, count = 0; 1315 | uint64_t sums[4] = { 0 }; // Sums for each of the 4 channels 1316 | int r_ave, g_ave, b_ave; 1317 | uint32_t encoding = dev->rawcam_output->format->encoding; 1318 | int stride = mmal_encoding_width_to_stride(encoding, dev->rawcam_output->format->es->video.width); 1319 | 1320 | if (!dev->wb_gains.hdr.id) 1321 | { 1322 | dev->wb_gains.hdr.id = MMAL_PARAMETER_CUSTOM_AWB_GAINS; 1323 | dev->wb_gains.hdr.size = sizeof(dev->wb_gains); 1324 | dev->wb_gains.r_gain.num = 256; 1325 | dev->wb_gains.r_gain.den = 256; 1326 | dev->wb_gains.b_gain.num = 256; 1327 | dev->wb_gains.b_gain.den = 256; 1328 | } 1329 | 1330 | for (x = 8; x < dev->rawcam_output->format->es->video.crop.width; x += 16) 1331 | { 1332 | for (y = 8; y < dev->rawcam_output->format->es->video.crop.height; y += 16) 1333 | { 1334 | sums[0] += get_pixel(x, y, encoding, stride, buffer->user_data); 1335 | sums[1] += get_pixel(x + 1, y, encoding, stride, buffer->user_data); 1336 | sums[2] += get_pixel(x, y + 1, encoding, stride, buffer->user_data); 1337 | sums[3] += get_pixel(x + 1, y + 1, encoding, stride, buffer->user_data); 1338 | count++; 1339 | } 1340 | } 1341 | 1342 | r_ave = get_channel(RED, encoding, sums) / vcos_max(count, 1); 1343 | g_ave = (get_channel(GREEN1, encoding, sums) + get_channel(GREEN2, encoding, sums)) / vcos_max(count * 2, 1); 1344 | b_ave = get_channel(BLUE, encoding, sums) / vcos_max(count, 1); 1345 | 1346 | /* FIXME: Do a moving average filter for smoother changes in values */ 1347 | dev->wb_gains.r_gain.num = ((g_ave << 8) / (r_ave + 1)); 1348 | dev->wb_gains.b_gain.num = ((g_ave << 8) / (b_ave + 1)); // +1 to protect against div by 0*/ 1349 | 1350 | if (dev->isp_ip) 1351 | mmal_port_parameter_set(dev->isp_ip, &dev->wb_gains.hdr); 1352 | } 1353 | 1354 | static void *awb_thread_task(void *arg) 1355 | { 1356 | RASPIRAW_CALLBACK_T *dev = (RASPIRAW_CALLBACK_T *)arg; 1357 | MMAL_BUFFER_HEADER_T *buffer; 1358 | 1359 | while (!dev->awb_thread_quit) 1360 | { 1361 | // Being lazy and using a timed wait instead of setting up a 1362 | // mechanism for skipping this when destroying the thread 1363 | buffer = mmal_queue_timedwait(dev->awb_queue, 1000); 1364 | if (!buffer) 1365 | continue; 1366 | if (!mmal_queue_length(dev->awb_queue)) 1367 | { 1368 | /* If more buffers in the queue, loop so we're working 1369 | * on the latest one 1370 | */ 1371 | run_awb_calcs(dev, buffer); 1372 | } 1373 | 1374 | mmal_buffer_header_release(buffer); 1375 | buffers_to_rawcam(dev); 1376 | } 1377 | 1378 | return NULL; 1379 | } 1380 | 1381 | static void *processing_thread_task(void *arg) 1382 | { 1383 | RASPIRAW_CALLBACK_T *dev = (RASPIRAW_CALLBACK_T *)arg; 1384 | MMAL_BUFFER_HEADER_T *buffer; 1385 | 1386 | while (!dev->processing_thread_quit) 1387 | { 1388 | // Being lazy and using a timed wait instead of setting up a 1389 | // mechanism for skipping this when destroying the thread 1390 | buffer = mmal_queue_timedwait(dev->processing_queue, 1000); 1391 | if (!buffer) 1392 | continue; 1393 | if (!mmal_queue_length(dev->processing_queue)) 1394 | { 1395 | /* If more buffers in the queue, loop so we're working 1396 | * on the latest one 1397 | */ 1398 | // DO SOME FORM OF PROCESSING ON THE RAW BAYER DATA HERE 1399 | // buffer->user_data points to the data, with 1400 | // buffer->length being the length of the data. 1401 | } 1402 | 1403 | mmal_buffer_header_release(buffer); 1404 | buffers_to_rawcam(dev); 1405 | } 1406 | 1407 | return NULL; 1408 | } 1409 | 1410 | static void isp_ip_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) 1411 | { 1412 | RASPIRAW_CALLBACK_T *dev = (RASPIRAW_CALLBACK_T *)port->userdata; 1413 | 1414 | mmal_buffer_header_release(buffer); 1415 | buffers_to_rawcam(dev); 1416 | } 1417 | 1418 | static void *processing_yuv_thread_task(void *arg) 1419 | { 1420 | RASPIRAW_ISP_CALLBACK_T *yuv_cb = (RASPIRAW_ISP_CALLBACK_T *)arg; 1421 | MMAL_BUFFER_HEADER_T *buffer; 1422 | 1423 | while (!yuv_cb->processing_yuv_thread_quit) 1424 | { 1425 | // Being lazy and using a timed wait instead of setting up a 1426 | // mechanism for skipping this when destroying the thread 1427 | buffer = mmal_queue_timedwait(yuv_cb->processing_yuv_queue, 1000); 1428 | if (!buffer) 1429 | continue; 1430 | if (!mmal_queue_length(yuv_cb->processing_yuv_queue)) 1431 | { 1432 | /* If more buffers in the queue, loop so we're working 1433 | * on the latest one 1434 | */ 1435 | // DO SOME FORM OF PROCESSING ON THE YUV DATA HERE 1436 | // buffer->user_data points to the data, with 1437 | // buffer->length being the length of the data. 1438 | } 1439 | 1440 | mmal_buffer_header_release(buffer); 1441 | buffers_to_isp_op(yuv_cb); 1442 | } 1443 | 1444 | return NULL; 1445 | } 1446 | 1447 | static void vr_ip_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) 1448 | { 1449 | RASPIRAW_ISP_CALLBACK_T *dev = (RASPIRAW_ISP_CALLBACK_T *)port->userdata; 1450 | 1451 | mmal_buffer_header_release(buffer); 1452 | buffers_to_isp_op(dev); 1453 | } 1454 | 1455 | int main(int argc, char **argv) 1456 | { 1457 | RASPIRAW_PARAMS_T cfg = { 0 }; 1458 | RASPIRAW_CALLBACK_T dev = { .cfg = &cfg, .rawcam_pool = NULL, .rawcam_output = NULL }; 1459 | RASPIRAW_ISP_CALLBACK_T yuv_cb = { 1460 | .cfg = &cfg, 1461 | }; 1462 | uint32_t encoding; 1463 | const struct sensor_def *sensor; 1464 | struct mode_def *sensor_mode = NULL; 1465 | VCOS_THREAD_T awb_thread; 1466 | VCOS_THREAD_T processing_thread; 1467 | VCOS_THREAD_T processing_yuv_thread; 1468 | char i2c_device_name[I2C_DEVICE_NAME_LEN]; 1469 | int i2c_fd; 1470 | 1471 | // Initialise any non-zero config values. 1472 | cfg.exposure = -1; 1473 | cfg.gain = -1; 1474 | cfg.timeout = 5000; 1475 | cfg.saverate = 20; 1476 | cfg.bit_depth = -1; 1477 | cfg.camera_num = -1; 1478 | cfg.exposure_us = -1; 1479 | cfg.i2c_bus = -1; 1480 | cfg.crop.hinc = -1; 1481 | cfg.crop.vinc = -1; 1482 | cfg.fps = -1; 1483 | cfg.crop.width = -1; 1484 | cfg.crop.height = -1; 1485 | cfg.crop.left = -1; 1486 | cfg.crop.top = -1; 1487 | cfg.opacity = 255; 1488 | cfg.fullscreen = 1; 1489 | 1490 | bcm_host_init(); 1491 | vcos_log_register("RaspiRaw", VCOS_LOG_CATEGORY); 1492 | 1493 | if (argc == 1) 1494 | { 1495 | fprintf(stdout, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING); 1496 | 1497 | raspicli_display_help(cmdline_commands, cmdline_commands_size); 1498 | exit(-1); 1499 | } 1500 | 1501 | // Parse the command line and put options in to our status structure 1502 | if (parse_cmdline(argc, argv, &cfg)) 1503 | { 1504 | exit(-1); 1505 | } 1506 | 1507 | if (cfg.i2c_bus == -1) 1508 | { 1509 | snprintf(i2c_device_name, sizeof(i2c_device_name), "/dev/i2c-%d", DEFAULT_I2C_DEVICE); 1510 | i2c_fd = open(i2c_device_name, O_RDWR); 1511 | if (!i2c_fd) 1512 | { 1513 | snprintf(i2c_device_name, sizeof(i2c_device_name), "/dev/i2c-%d", ALT_I2C_DEVICE); 1514 | i2c_fd = open(i2c_device_name, O_RDWR); 1515 | } 1516 | } 1517 | else 1518 | { 1519 | snprintf(i2c_device_name, sizeof(i2c_device_name), "/dev/i2c-%d", cfg.i2c_bus); 1520 | i2c_fd = open(i2c_device_name, O_RDWR); 1521 | } 1522 | 1523 | if (!i2c_fd) 1524 | { 1525 | printf("Failed to open I2C device %s\n", i2c_device_name); 1526 | return -1; 1527 | } 1528 | 1529 | printf("Using I2C device %s\n", i2c_device_name); 1530 | 1531 | sensor = probe_sensor(i2c_fd); 1532 | if (!sensor) 1533 | { 1534 | vcos_log_error("No sensor found. Aborting"); 1535 | return -1; 1536 | } 1537 | 1538 | if (cfg.mode >= 0 && cfg.mode < sensor->num_modes) 1539 | { 1540 | sensor_mode = &sensor->modes[cfg.mode]; 1541 | } 1542 | 1543 | if (!sensor_mode) 1544 | { 1545 | vcos_log_error("Invalid mode %d - aborting", cfg.mode); 1546 | return -2; 1547 | } 1548 | 1549 | if (cfg.regs) 1550 | { 1551 | int r, b; 1552 | char *p, *q; 1553 | 1554 | p = strtok(cfg.regs, ";"); 1555 | while (p) 1556 | { 1557 | vcos_assert(strlen(p) > 6); 1558 | vcos_assert(p[4] == ','); 1559 | vcos_assert(strlen(p) % 2); 1560 | p[4] = '\0'; 1561 | q = p + 5; 1562 | sscanf(p, "%4x", &r); 1563 | while (*q) 1564 | { 1565 | vcos_assert(isxdigit(q[0])); 1566 | vcos_assert(isxdigit(q[1])); 1567 | 1568 | sscanf(q, "%2x", &b); 1569 | vcos_log_error("%04x: %02x", r, b); 1570 | 1571 | modReg(sensor_mode, r, 0, 7, b, EQUAL); 1572 | 1573 | ++r; 1574 | q += 2; 1575 | } 1576 | p = strtok(NULL, ";"); 1577 | } 1578 | } 1579 | 1580 | if (cfg.crop.hinc >= 0 || cfg.crop.vinc >= 0 || cfg.crop.width > 0 || cfg.crop.width > 0 || cfg.crop.top >= 0 || 1581 | cfg.crop.left >= 0) 1582 | { 1583 | if (sensor->set_crop) 1584 | { 1585 | if (sensor->set_crop(sensor, sensor_mode, &cfg.crop)) 1586 | { 1587 | vcos_log_error("Failed setting manual crops. Aborting"); 1588 | return -1; 1589 | } 1590 | } 1591 | else 1592 | { 1593 | vcos_log_error("This sensor does not currently support " 1594 | "manual cropping settings. Aborting"); 1595 | return -1; 1596 | } 1597 | } 1598 | 1599 | if (cfg.fps > 0) 1600 | { 1601 | int n = 1000000000 / (sensor_mode->line_time_ns * cfg.fps); 1602 | modReg(sensor_mode, sensor->vts_reg + 0, 0, 7, n >> 8, EQUAL); 1603 | modReg(sensor_mode, sensor->vts_reg + 1, 0, 7, n & 0xFF, EQUAL); 1604 | } 1605 | 1606 | if (cfg.bit_depth == -1) 1607 | { 1608 | cfg.bit_depth = sensor_mode->native_bit_depth; 1609 | } 1610 | 1611 | if (cfg.write_headerg && (cfg.bit_depth != sensor_mode->native_bit_depth)) 1612 | { 1613 | // needs change after fix for 1614 | // https://github.com/6by9/raspiraw/issues/2 1615 | vcos_log_error("--headerG supported for native bit depth only"); 1616 | exit(-1); 1617 | } 1618 | 1619 | if (cfg.exposure_us != -1) 1620 | { 1621 | cfg.exposure = ((int64_t)cfg.exposure_us * 1000) / sensor_mode->line_time_ns; 1622 | vcos_log_error("Setting exposure to %d from time %dus", cfg.exposure, cfg.exposure_us); 1623 | } 1624 | 1625 | update_regs(sensor, sensor_mode, cfg.hflip, cfg.vflip, cfg.exposure, cfg.gain); 1626 | if (sensor_mode->encoding == 0) 1627 | encoding = order_and_bit_depth_to_encoding(sensor_mode->order, cfg.bit_depth); 1628 | else 1629 | encoding = sensor_mode->encoding; 1630 | if (!encoding) 1631 | { 1632 | vcos_log_error("Failed to map bitdepth %d and order %d into encoding\n", cfg.bit_depth, 1633 | sensor_mode->order); 1634 | return -3; 1635 | } 1636 | vcos_log_error("Encoding %08X", encoding); 1637 | 1638 | if (cfg.awb) 1639 | { 1640 | VCOS_STATUS_T vcos_status; 1641 | printf("Setup awb thread\n"); 1642 | vcos_status = vcos_thread_create(&awb_thread, "awb-thread", NULL, awb_thread_task, &dev); 1643 | if (vcos_status != VCOS_SUCCESS) 1644 | { 1645 | printf("Failed to create awb thread\n"); 1646 | return -4; 1647 | } 1648 | dev.awb_queue = mmal_queue_create(); 1649 | if (!dev.awb_queue) 1650 | { 1651 | printf("Failed to create awb queue\n"); 1652 | return -4; 1653 | } 1654 | } 1655 | else 1656 | printf("No AWB\n"); 1657 | 1658 | if (cfg.processing) 1659 | { 1660 | VCOS_STATUS_T vcos_status; 1661 | printf("Setup processing thread\n"); 1662 | vcos_status = 1663 | vcos_thread_create(&processing_thread, "processing-thread", NULL, processing_thread_task, &dev); 1664 | if (vcos_status != VCOS_SUCCESS) 1665 | { 1666 | printf("Failed to create processing thread\n"); 1667 | return -4; 1668 | } 1669 | dev.processing_queue = mmal_queue_create(); 1670 | if (!dev.processing_queue) 1671 | { 1672 | printf("Failed to create processing queue\n"); 1673 | return -4; 1674 | } 1675 | } 1676 | 1677 | MMAL_COMPONENT_T *rawcam = NULL, *isp = NULL, *render = NULL; 1678 | MMAL_STATUS_T status; 1679 | MMAL_PORT_T *output = NULL; 1680 | MMAL_POOL_T *pool = NULL, *yuv_pool = NULL; 1681 | MMAL_PARAMETER_CAMERA_RX_CONFIG_T rx_cfg; 1682 | MMAL_PARAMETER_CAMERA_RX_TIMING_T rx_timing; 1683 | unsigned int i; 1684 | 1685 | bcm_host_init(); 1686 | vcos_log_register("RaspiRaw", VCOS_LOG_CATEGORY); 1687 | 1688 | status = mmal_component_create("vc.ril.rawcam", &rawcam); 1689 | if (status != MMAL_SUCCESS) 1690 | { 1691 | vcos_log_error("Failed to create rawcam"); 1692 | return -1; 1693 | } 1694 | status = mmal_port_parameter_set_boolean(rawcam->output[0], MMAL_PARAMETER_ZERO_COPY, MMAL_TRUE); 1695 | if (status != MMAL_SUCCESS) 1696 | { 1697 | vcos_log_error("Failed to set zero copy"); 1698 | goto component_disable; 1699 | } 1700 | 1701 | status = mmal_component_create("vc.ril.isp", &isp); 1702 | if (status != MMAL_SUCCESS) 1703 | { 1704 | vcos_log_error("Failed to create isp"); 1705 | goto component_destroy; 1706 | } 1707 | status = mmal_port_parameter_set_boolean(isp->input[0], MMAL_PARAMETER_ZERO_COPY, MMAL_TRUE); 1708 | if (status != MMAL_SUCCESS) 1709 | { 1710 | vcos_log_error("Failed to set zero copy"); 1711 | goto component_disable; 1712 | } 1713 | status = mmal_port_parameter_set_boolean(isp->output[0], MMAL_PARAMETER_ZERO_COPY, MMAL_TRUE); 1714 | if (status != MMAL_SUCCESS) 1715 | { 1716 | vcos_log_error("Failed to set zero copy"); 1717 | goto component_disable; 1718 | } 1719 | 1720 | status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &render); 1721 | if (status != MMAL_SUCCESS) 1722 | { 1723 | vcos_log_error("Failed to create render"); 1724 | goto component_destroy; 1725 | } 1726 | status = mmal_port_parameter_set_boolean(render->input[0], MMAL_PARAMETER_ZERO_COPY, MMAL_TRUE); 1727 | if (status != MMAL_SUCCESS) 1728 | { 1729 | vcos_log_error("Failed to set zero copy"); 1730 | goto component_disable; 1731 | } 1732 | 1733 | output = rawcam->output[0]; 1734 | 1735 | rx_cfg.hdr.id = MMAL_PARAMETER_CAMERA_RX_CONFIG; 1736 | rx_cfg.hdr.size = sizeof(rx_cfg); 1737 | status = mmal_port_parameter_get(output, &rx_cfg.hdr); 1738 | if (status != MMAL_SUCCESS) 1739 | { 1740 | vcos_log_error("Failed to get cfg"); 1741 | goto component_destroy; 1742 | } 1743 | if (sensor_mode->encoding || cfg.bit_depth == sensor_mode->native_bit_depth) 1744 | { 1745 | rx_cfg.unpack = MMAL_CAMERA_RX_CONFIG_UNPACK_NONE; 1746 | rx_cfg.pack = MMAL_CAMERA_RX_CONFIG_PACK_NONE; 1747 | } 1748 | else 1749 | { 1750 | switch (sensor_mode->native_bit_depth) 1751 | { 1752 | case 8: 1753 | rx_cfg.unpack = MMAL_CAMERA_RX_CONFIG_UNPACK_8; 1754 | break; 1755 | case 10: 1756 | rx_cfg.unpack = MMAL_CAMERA_RX_CONFIG_UNPACK_10; 1757 | break; 1758 | case 12: 1759 | rx_cfg.unpack = MMAL_CAMERA_RX_CONFIG_UNPACK_12; 1760 | break; 1761 | case 14: 1762 | rx_cfg.unpack = MMAL_CAMERA_RX_CONFIG_UNPACK_16; 1763 | break; 1764 | case 16: 1765 | rx_cfg.unpack = MMAL_CAMERA_RX_CONFIG_UNPACK_16; 1766 | break; 1767 | default: 1768 | vcos_log_error("Unknown native bit depth %d", sensor_mode->native_bit_depth); 1769 | rx_cfg.unpack = MMAL_CAMERA_RX_CONFIG_UNPACK_NONE; 1770 | break; 1771 | } 1772 | switch (cfg.bit_depth) 1773 | { 1774 | case 8: 1775 | rx_cfg.pack = MMAL_CAMERA_RX_CONFIG_PACK_8; 1776 | break; 1777 | case 10: 1778 | rx_cfg.pack = MMAL_CAMERA_RX_CONFIG_PACK_RAW10; 1779 | break; 1780 | case 12: 1781 | rx_cfg.pack = MMAL_CAMERA_RX_CONFIG_PACK_RAW12; 1782 | break; 1783 | case 14: 1784 | rx_cfg.pack = MMAL_CAMERA_RX_CONFIG_PACK_14; 1785 | break; 1786 | case 16: 1787 | rx_cfg.pack = MMAL_CAMERA_RX_CONFIG_PACK_16; 1788 | break; 1789 | default: 1790 | vcos_log_error("Unknown output bit depth %d", cfg.bit_depth); 1791 | rx_cfg.pack = MMAL_CAMERA_RX_CONFIG_PACK_NONE; 1792 | break; 1793 | } 1794 | } 1795 | vcos_log_error("Set pack to %d, unpack to %d", rx_cfg.unpack, rx_cfg.pack); 1796 | if (sensor_mode->data_lanes) 1797 | rx_cfg.data_lanes = sensor_mode->data_lanes; 1798 | if (sensor_mode->image_id) 1799 | rx_cfg.image_id = sensor_mode->image_id; 1800 | status = mmal_port_parameter_set(output, &rx_cfg.hdr); 1801 | if (status != MMAL_SUCCESS) 1802 | { 1803 | vcos_log_error("Failed to set cfg"); 1804 | goto component_destroy; 1805 | } 1806 | 1807 | rx_timing.hdr.id = MMAL_PARAMETER_CAMERA_RX_TIMING; 1808 | rx_timing.hdr.size = sizeof(rx_timing); 1809 | status = mmal_port_parameter_get(output, &rx_timing.hdr); 1810 | if (status != MMAL_SUCCESS) 1811 | { 1812 | vcos_log_error("Failed to get timing"); 1813 | goto component_destroy; 1814 | } 1815 | if (sensor_mode->timing[0]) 1816 | rx_timing.timing1 = sensor_mode->timing[0]; 1817 | if (sensor_mode->timing[1]) 1818 | rx_timing.timing2 = sensor_mode->timing[1]; 1819 | if (sensor_mode->timing[2]) 1820 | rx_timing.timing3 = sensor_mode->timing[2]; 1821 | if (sensor_mode->timing[3]) 1822 | rx_timing.timing4 = sensor_mode->timing[3]; 1823 | if (sensor_mode->timing[4]) 1824 | rx_timing.timing5 = sensor_mode->timing[4]; 1825 | if (sensor_mode->term[0]) 1826 | rx_timing.term1 = sensor_mode->term[0]; 1827 | if (sensor_mode->term[1]) 1828 | rx_timing.term2 = sensor_mode->term[1]; 1829 | vcos_log_error("Timing %u/%u, %u/%u/%u, %u/%u", rx_timing.timing1, rx_timing.timing2, rx_timing.timing3, 1830 | rx_timing.timing4, rx_timing.timing5, rx_timing.term1, rx_timing.term2); 1831 | status = mmal_port_parameter_set(output, &rx_timing.hdr); 1832 | if (status != MMAL_SUCCESS) 1833 | { 1834 | vcos_log_error("Failed to set timing"); 1835 | goto component_destroy; 1836 | } 1837 | 1838 | if (cfg.camera_num != -1) 1839 | { 1840 | vcos_log_error("Set camera_num to %d", cfg.camera_num); 1841 | status = mmal_port_parameter_set_int32(output, MMAL_PARAMETER_CAMERA_NUM, cfg.camera_num); 1842 | if (status != MMAL_SUCCESS) 1843 | { 1844 | vcos_log_error("Failed to set camera_num"); 1845 | goto component_destroy; 1846 | } 1847 | } 1848 | 1849 | status = mmal_component_enable(rawcam); 1850 | if (status != MMAL_SUCCESS) 1851 | { 1852 | vcos_log_error("Failed to enable rawcam"); 1853 | goto component_destroy; 1854 | } 1855 | status = mmal_component_enable(isp); 1856 | if (status != MMAL_SUCCESS) 1857 | { 1858 | vcos_log_error("Failed to enable isp"); 1859 | goto component_destroy; 1860 | } 1861 | status = mmal_component_enable(render); 1862 | if (status != MMAL_SUCCESS) 1863 | { 1864 | vcos_log_error("Failed to enable render"); 1865 | goto component_destroy; 1866 | } 1867 | 1868 | output->format->es->video.crop.width = sensor_mode->width; 1869 | output->format->es->video.crop.height = sensor_mode->height; 1870 | output->format->es->video.width = VCOS_ALIGN_UP(sensor_mode->width, 16); 1871 | output->format->es->video.height = VCOS_ALIGN_UP(sensor_mode->height, 16); 1872 | output->format->encoding = encoding; 1873 | 1874 | status = mmal_port_format_commit(output); 1875 | if (status != MMAL_SUCCESS) 1876 | { 1877 | vcos_log_error("Failed port_format_commit"); 1878 | goto component_disable; 1879 | } 1880 | 1881 | output->buffer_size = output->buffer_size_recommended; 1882 | output->buffer_num = output->buffer_num_recommended; 1883 | 1884 | if (cfg.capture) 1885 | { 1886 | if (cfg.write_header || cfg.write_header0) 1887 | { 1888 | brcm_header = (struct brcm_raw_header *)malloc(BRCM_RAW_HEADER_LENGTH); 1889 | if (brcm_header) 1890 | { 1891 | memset(brcm_header, 0, BRCM_RAW_HEADER_LENGTH); 1892 | brcm_header->id = BRCM_ID_SIG; 1893 | brcm_header->version = HEADER_VERSION; 1894 | brcm_header->mode.width = sensor_mode->width; 1895 | brcm_header->mode.height = sensor_mode->height; 1896 | // FIXME: Ought to check that the sensor is 1897 | // producing Bayer rather than just assuming. 1898 | brcm_header->mode.format = VC_IMAGE_BAYER; 1899 | switch (sensor_mode->order) 1900 | { 1901 | case BAYER_ORDER_BGGR: 1902 | brcm_header->mode.bayer_order = VC_IMAGE_BAYER_BGGR; 1903 | break; 1904 | case BAYER_ORDER_GBRG: 1905 | brcm_header->mode.bayer_order = VC_IMAGE_BAYER_GBRG; 1906 | break; 1907 | case BAYER_ORDER_GRBG: 1908 | brcm_header->mode.bayer_order = VC_IMAGE_BAYER_GRBG; 1909 | break; 1910 | case BAYER_ORDER_RGGB: 1911 | brcm_header->mode.bayer_order = VC_IMAGE_BAYER_RGGB; 1912 | break; 1913 | } 1914 | switch (cfg.bit_depth) 1915 | { 1916 | case 8: 1917 | brcm_header->mode.bayer_format = VC_IMAGE_BAYER_RAW8; 1918 | break; 1919 | case 10: 1920 | brcm_header->mode.bayer_format = VC_IMAGE_BAYER_RAW10; 1921 | break; 1922 | case 12: 1923 | brcm_header->mode.bayer_format = VC_IMAGE_BAYER_RAW12; 1924 | break; 1925 | case 14: 1926 | brcm_header->mode.bayer_format = VC_IMAGE_BAYER_RAW14; 1927 | break; 1928 | case 16: 1929 | brcm_header->mode.bayer_format = VC_IMAGE_BAYER_RAW16; 1930 | break; 1931 | } 1932 | if (cfg.write_header0) 1933 | { 1934 | // Save bcrm_header into one file only 1935 | FILE *file; 1936 | file = fopen(cfg.write_header0, "wb"); 1937 | if (file) 1938 | { 1939 | fwrite(brcm_header, BRCM_RAW_HEADER_LENGTH, 1, file); 1940 | fclose(file); 1941 | } 1942 | } 1943 | } 1944 | } 1945 | else if (cfg.write_headerg) 1946 | { 1947 | // Save pgm_header into one file only 1948 | FILE *file; 1949 | file = fopen(cfg.write_headerg, "wb"); 1950 | if (file) 1951 | { 1952 | fprintf(file, "P5\n%d %d\n255\n", sensor_mode->width, sensor_mode->height); 1953 | fclose(file); 1954 | } 1955 | } 1956 | } 1957 | 1958 | MMAL_PORT_T *port; 1959 | port = isp->input[0]; 1960 | status = mmal_format_full_copy(port->format, output->format); 1961 | if (status != MMAL_SUCCESS) 1962 | { 1963 | vcos_log_error("Failed to copy port format"); 1964 | goto pool_destroy; 1965 | } 1966 | status = mmal_port_format_commit(port); 1967 | if (status != MMAL_SUCCESS) 1968 | { 1969 | vcos_log_error("Failed to commit port format on isp input"); 1970 | goto pool_destroy; 1971 | } 1972 | 1973 | port->buffer_num = output->buffer_num; 1974 | 1975 | if (port->buffer_size != output->buffer_size) 1976 | { 1977 | vcos_log_error("rawcam output and isp input are different " 1978 | "sizes - this could end badly"); 1979 | vcos_log_error("rawcam %u, isp %u", port->buffer_size, output->buffer_size); 1980 | } 1981 | 1982 | port = isp->output[0]; 1983 | port->format->es->video.crop.width = sensor_mode->width; 1984 | port->format->es->video.crop.height = sensor_mode->height; 1985 | while (port->format->es->video.crop.width > 1920) 1986 | { 1987 | // Display can only go up to a certain resolution before 1988 | // underflowing 1989 | port->format->es->video.crop.width /= 2; 1990 | port->format->es->video.crop.height /= 2; 1991 | } 1992 | port->format->es->video.width = VCOS_ALIGN_UP(port->format->es->video.crop.width, 32); 1993 | port->format->es->video.height = VCOS_ALIGN_UP(port->format->es->video.crop.height, 16); 1994 | port->format->encoding = MMAL_ENCODING_I420; 1995 | port->buffer_num = 6; // Go for 6 output buffers to give some slack 1996 | status = mmal_port_format_commit(port); 1997 | if (status != MMAL_SUCCESS) 1998 | { 1999 | vcos_log_error("Failed to commit port format on isp output"); 2000 | goto pool_destroy; 2001 | } 2002 | 2003 | if (sensor_mode->black_level) 2004 | { 2005 | status = 2006 | mmal_port_parameter_set_uint32(isp->input[0], MMAL_PARAMETER_BLACK_LEVEL, sensor_mode->black_level); 2007 | if (status != MMAL_SUCCESS) 2008 | { 2009 | vcos_log_error("Failed to set black level - try " 2010 | "updating firmware"); 2011 | } 2012 | } 2013 | 2014 | if (cfg.awb_gains_r && cfg.awb_gains_b) 2015 | { 2016 | MMAL_PARAMETER_AWB_GAINS_T param = { { MMAL_PARAMETER_CUSTOM_AWB_GAINS, sizeof(param) }, 2017 | { 0, 0 }, 2018 | { 0, 0 } }; 2019 | 2020 | param.r_gain.num = (unsigned int)(cfg.awb_gains_r * 65536); 2021 | param.b_gain.num = (unsigned int)(cfg.awb_gains_b * 65536); 2022 | param.r_gain.den = param.b_gain.den = 65536; 2023 | status = mmal_port_parameter_set(isp->input[0], ¶m.hdr); 2024 | if (status != MMAL_SUCCESS) 2025 | { 2026 | vcos_log_error("Failed to set white balance"); 2027 | } 2028 | } 2029 | 2030 | /* Set up the rawcam output callback */ 2031 | 2032 | // Create buffer headers for rawcam to isp/awb/raw processing 2033 | // Rawcam output. 2034 | // Need to manually create the pool so that we have control over mem 2035 | // handles, not letting MMAL core handle the magic. 2036 | vcos_log_error("Create pool of %d buffers of size %d", output->buffer_num, output->buffer_size); 2037 | pool = mmal_port_pool_create(output, output->buffer_num, 0); 2038 | if (!pool) 2039 | { 2040 | vcos_log_error("Failed to create pool"); 2041 | goto component_disable; 2042 | } 2043 | for (i = 0; i < output->buffer_num; i++) 2044 | { 2045 | MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(pool->queue); 2046 | if (!buffer) 2047 | vcos_log_error("Where did my buffer go?"); 2048 | else 2049 | { 2050 | unsigned int vcsm_handle = 2051 | vcsm_malloc_cache(output->buffer_size, VCSM_CACHE_TYPE_HOST, "mmal_vc_port buffer"); 2052 | unsigned int vc_handle = vcsm_vc_hdl_from_hdl(vcsm_handle); 2053 | uint8_t *mem = (uint8_t *)vcsm_lock(vcsm_handle); 2054 | if (!mem || !vc_handle) 2055 | { 2056 | LOG_ERROR("could not allocate %i bytes of " 2057 | "shared memory (handle %x)", 2058 | (int)output->buffer_size, vcsm_handle); 2059 | if (mem) 2060 | vcsm_unlock_hdl(vcsm_handle); 2061 | if (vcsm_handle) 2062 | vcsm_free(vcsm_handle); 2063 | } 2064 | else 2065 | { 2066 | buffer->data = (void *)vc_handle; 2067 | buffer->alloc_size = output->buffer_size; 2068 | buffer->user_data = mem; 2069 | } 2070 | } 2071 | mmal_buffer_header_release(buffer); 2072 | } 2073 | dev.rawcam_output = rawcam->output[0]; 2074 | dev.rawcam_pool = pool; 2075 | 2076 | // ISP input 2077 | vcos_log_error("Create pool of %d buffers of size %d", isp->input[0]->buffer_num, isp->input[0]->buffer_size); 2078 | dev.isp_ip_pool = mmal_port_pool_create(isp->input[0], isp->input[0]->buffer_num, 0); 2079 | if (!dev.isp_ip_pool) 2080 | { 2081 | vcos_log_error("Failed to create isp_ip_pool"); 2082 | goto component_disable; 2083 | } 2084 | dev.isp_ip = isp->input[0]; 2085 | 2086 | isp->input[0]->userdata = (struct MMAL_PORT_USERDATA_T *)&dev; 2087 | status = mmal_port_enable(isp->input[0], isp_ip_cb); 2088 | if (status != MMAL_SUCCESS) 2089 | { 2090 | vcos_log_error("Failed to enable isp ip port"); 2091 | goto pool_destroy; 2092 | } 2093 | 2094 | // Set up YUV/RGB processing outputs 2095 | yuv_pool = mmal_port_pool_create(isp->output[0], isp->output[0]->buffer_num, 0); 2096 | if (!yuv_pool) 2097 | { 2098 | vcos_log_error("Failed to create yuv pool"); 2099 | goto component_disable; 2100 | } 2101 | for (i = 0; i < isp->output[0]->buffer_num; i++) 2102 | { 2103 | MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(yuv_pool->queue); 2104 | if (!buffer) 2105 | vcos_log_error("Where did my buffer go?"); 2106 | else 2107 | { 2108 | unsigned int vcsm_handle = 2109 | vcsm_malloc_cache(isp->output[0]->buffer_size, VCSM_CACHE_TYPE_HOST, "mmal_vc_port buffer"); 2110 | unsigned int vc_handle = vcsm_vc_hdl_from_hdl(vcsm_handle); 2111 | uint8_t *mem = (uint8_t *)vcsm_lock(vcsm_handle); 2112 | if (!mem || !vc_handle) 2113 | { 2114 | LOG_ERROR("could not allocate %i bytes of " 2115 | "shared memory (handle %x)", 2116 | (int)isp->output[0]->buffer_size, vcsm_handle); 2117 | if (mem) 2118 | vcsm_unlock_hdl(vcsm_handle); 2119 | if (vcsm_handle) 2120 | vcsm_free(vcsm_handle); 2121 | } 2122 | else 2123 | { 2124 | buffer->data = (void *)vc_handle; 2125 | buffer->alloc_size = isp->output[0]->buffer_size; 2126 | buffer->user_data = mem; 2127 | } 2128 | } 2129 | mmal_buffer_header_release(buffer); 2130 | } 2131 | isp->output[0]->userdata = (struct MMAL_PORT_USERDATA_T *)&yuv_cb; 2132 | status = mmal_port_enable(isp->output[0], yuv_callback); 2133 | if (status != MMAL_SUCCESS) 2134 | { 2135 | vcos_log_error("Failed to enable isp op port"); 2136 | goto pool_destroy; 2137 | } 2138 | yuv_cb.isp_output = isp->output[0]; 2139 | yuv_cb.isp_op_pool = yuv_pool; 2140 | 2141 | if (!cfg.no_preview) 2142 | { 2143 | MMAL_DISPLAYREGION_T param; 2144 | param.hdr.id = MMAL_PARAMETER_DISPLAYREGION; 2145 | param.hdr.size = sizeof(MMAL_DISPLAYREGION_T); 2146 | 2147 | param.set = MMAL_DISPLAY_SET_LAYER; 2148 | param.layer = DEFAULT_PREVIEW_LAYER; 2149 | 2150 | param.set |= MMAL_DISPLAY_SET_ALPHA; 2151 | param.alpha = cfg.opacity; 2152 | 2153 | if (cfg.fullscreen) 2154 | { 2155 | param.set |= MMAL_DISPLAY_SET_FULLSCREEN; 2156 | param.fullscreen = 1; 2157 | } 2158 | else 2159 | { 2160 | param.set |= (MMAL_DISPLAY_SET_DEST_RECT | MMAL_DISPLAY_SET_FULLSCREEN); 2161 | param.fullscreen = 0; 2162 | param.dest_rect = cfg.preview_window; 2163 | } 2164 | 2165 | status = mmal_port_parameter_set(render->input[0], ¶m.hdr); 2166 | 2167 | if (status != MMAL_SUCCESS && status != MMAL_ENOSYS) 2168 | { 2169 | vcos_log_error("unable to set preview port parameters (%u)", status); 2170 | } 2171 | 2172 | status = mmal_format_full_copy(render->input[0]->format, isp->output[0]->format); 2173 | if (status != MMAL_SUCCESS) 2174 | { 2175 | vcos_log_error("Failed to copy port format - isp to render"); 2176 | goto pool_destroy; 2177 | } 2178 | status = mmal_port_format_commit(render->input[0]); 2179 | if (status != MMAL_SUCCESS) 2180 | { 2181 | vcos_log_error("Failed to commit port format on render input"); 2182 | goto pool_destroy; 2183 | } 2184 | 2185 | render->input[0]->buffer_num = isp->output[0]->buffer_num; 2186 | 2187 | yuv_cb.vr_ip_pool = mmal_port_pool_create(render->input[0], render->input[0]->buffer_num, 0); 2188 | if (!yuv_cb.vr_ip_pool) 2189 | { 2190 | vcos_log_error("Failed to create vr_ip_pool"); 2191 | goto component_disable; 2192 | } 2193 | yuv_cb.vr_ip = render->input[0]; 2194 | 2195 | render->input[0]->userdata = (struct MMAL_PORT_USERDATA_T *)&yuv_cb; 2196 | 2197 | status = mmal_port_enable(render->input[0], vr_ip_cb); 2198 | if (status != MMAL_SUCCESS) 2199 | { 2200 | vcos_log_error("Failed to enable vr ip port"); 2201 | goto pool_destroy; 2202 | } 2203 | } 2204 | if (cfg.processing_yuv) 2205 | { 2206 | VCOS_STATUS_T vcos_status; 2207 | printf("Setup processing thread\n"); 2208 | vcos_status = vcos_thread_create(&processing_yuv_thread, "processing-yuv-thread", NULL, 2209 | processing_yuv_thread_task, &yuv_cb); 2210 | if (vcos_status != VCOS_SUCCESS) 2211 | { 2212 | printf("Failed to create processing yuv thread\n"); 2213 | return -4; 2214 | } 2215 | yuv_cb.processing_yuv_queue = mmal_queue_create(); 2216 | if (!yuv_cb.processing_yuv_queue) 2217 | { 2218 | printf("Failed to create processing yuv queue\n"); 2219 | return -4; 2220 | } 2221 | } 2222 | 2223 | output->userdata = (struct MMAL_PORT_USERDATA_T *)&dev; 2224 | status = mmal_port_enable(output, callback); 2225 | if (status != MMAL_SUCCESS) 2226 | { 2227 | vcos_log_error("Failed to enable port"); 2228 | goto pool_destroy; 2229 | } 2230 | 2231 | buffers_to_rawcam(&dev); 2232 | buffers_to_isp_op(&yuv_cb); 2233 | 2234 | start_camera_streaming(sensor, sensor_mode, i2c_fd); 2235 | 2236 | vcos_sleep(cfg.timeout); 2237 | 2238 | stop_camera_streaming(sensor, i2c_fd); 2239 | 2240 | port_disable: 2241 | if (cfg.capture) 2242 | { 2243 | status = mmal_port_disable(output); 2244 | if (status != MMAL_SUCCESS) 2245 | { 2246 | vcos_log_error("Failed to disable port"); 2247 | return -1; 2248 | } 2249 | } 2250 | pool_destroy: 2251 | if (pool) 2252 | mmal_port_pool_destroy(output, pool); 2253 | component_disable: 2254 | if (brcm_header) 2255 | free(brcm_header); 2256 | status = mmal_component_disable(render); 2257 | if (status != MMAL_SUCCESS) 2258 | { 2259 | vcos_log_error("Failed to disable render"); 2260 | } 2261 | status = mmal_component_disable(isp); 2262 | if (status != MMAL_SUCCESS) 2263 | { 2264 | vcos_log_error("Failed to disable isp"); 2265 | } 2266 | status = mmal_component_disable(rawcam); 2267 | if (status != MMAL_SUCCESS) 2268 | { 2269 | vcos_log_error("Failed to disable rawcam"); 2270 | } 2271 | component_destroy: 2272 | if (rawcam) 2273 | mmal_component_destroy(rawcam); 2274 | if (isp) 2275 | mmal_component_destroy(isp); 2276 | if (render) 2277 | mmal_component_destroy(render); 2278 | 2279 | if (cfg.awb) 2280 | { 2281 | dev.awb_thread_quit = 1; 2282 | vcos_thread_join(&awb_thread, NULL); 2283 | } 2284 | 2285 | if (cfg.processing) 2286 | { 2287 | dev.processing_thread_quit = 1; 2288 | vcos_thread_join(&processing_thread, NULL); 2289 | } 2290 | 2291 | if (cfg.write_timestamps) 2292 | { 2293 | // Save timestamps 2294 | FILE *file; 2295 | file = fopen(cfg.write_timestamps, "wb"); 2296 | if (file) 2297 | { 2298 | int64_t old = 0; 2299 | PTS_NODE_T aux; 2300 | for (aux = cfg.ptsa; aux != cfg.ptso; aux = aux->nxt) 2301 | { 2302 | if (aux == cfg.ptsa) 2303 | { 2304 | fprintf(file, ",%d,%lld\n", aux->idx, aux->pts); 2305 | } 2306 | else 2307 | { 2308 | fprintf(file, "%lld,%d,%lld\n", aux->pts - old, aux->idx, aux->pts); 2309 | } 2310 | old = aux->pts; 2311 | } 2312 | fclose(file); 2313 | } 2314 | 2315 | while (cfg.ptsa != cfg.ptso) 2316 | { 2317 | PTS_NODE_T aux = cfg.ptsa->nxt; 2318 | free(cfg.ptsa); 2319 | cfg.ptsa = aux; 2320 | } 2321 | free(cfg.ptso); 2322 | } 2323 | close(i2c_fd); 2324 | 2325 | return 0; 2326 | } 2327 | 2328 | void modRegBit(struct mode_def *mode, uint16_t reg, int bit, int value, enum operation op) 2329 | { 2330 | int i = 0; 2331 | uint16_t val; 2332 | while (i < mode->num_regs && mode->regs[i].reg != reg) 2333 | i++; 2334 | if (i == mode->num_regs) 2335 | { 2336 | vcos_log_error("Reg: %04X not found!\n", reg); 2337 | return; 2338 | } 2339 | val = mode->regs[i].data; 2340 | 2341 | switch (op) 2342 | { 2343 | case EQUAL: 2344 | val = val & ~(1 << bit); 2345 | val = val | (value << bit); 2346 | break; 2347 | case SET: 2348 | val = val | (1 << bit); 2349 | break; 2350 | case CLEAR: 2351 | val = val & ~(1 << bit); 2352 | break; 2353 | case XOR: 2354 | val = val ^ (value << bit); 2355 | break; 2356 | } 2357 | mode->regs[i].data = val; 2358 | } 2359 | 2360 | void modReg(struct mode_def *mode, uint16_t reg, int startBit, int endBit, int value, enum operation op) 2361 | { 2362 | int i; 2363 | for (i = startBit; i <= endBit; i++) 2364 | { 2365 | modRegBit(mode, reg, i, value >> i & 1, op); 2366 | } 2367 | } 2368 | 2369 | void update_regs(const struct sensor_def *sensor, struct mode_def *mode, int hflip, int vflip, int exposure, int gain) 2370 | { 2371 | if (sensor->vflip_reg) 2372 | { 2373 | modRegBit(mode, sensor->vflip_reg, sensor->vflip_reg_bit, vflip, XOR); 2374 | if (vflip && !sensor->flips_dont_change_bayer_order) 2375 | mode->order ^= 2; 2376 | } 2377 | 2378 | if (sensor->hflip_reg) 2379 | { 2380 | modRegBit(mode, sensor->hflip_reg, sensor->hflip_reg_bit, hflip, XOR); 2381 | if (hflip && !sensor->flips_dont_change_bayer_order) 2382 | mode->order ^= 1; 2383 | } 2384 | 2385 | if (sensor->exposure_reg && exposure != -1) 2386 | { 2387 | if (exposure < 0 || exposure >= (1 << sensor->exposure_reg_num_bits)) 2388 | { 2389 | vcos_log_error("Invalid exposure:%d, exposure range is 0 to %u!\n", exposure, 2390 | (1 << sensor->exposure_reg_num_bits) - 1); 2391 | } 2392 | else 2393 | { 2394 | uint8_t val; 2395 | int i, j = VCOS_ALIGN_DOWN(sensor->exposure_reg_num_bits - 1, 8); 2396 | int num_regs = (sensor->exposure_reg_num_bits + 7) >> 3; 2397 | for (i = 0; i < num_regs; i++, j -= 8) 2398 | { 2399 | val = (exposure >> j) & 0xFF; 2400 | modReg(mode, sensor->exposure_reg + i, 0, 7, val, EQUAL); 2401 | vcos_log_error("Set exposure %04X to %02X", sensor->exposure_reg + i, val); 2402 | } 2403 | } 2404 | } 2405 | if (sensor->vts_reg && exposure != -1 && exposure >= mode->min_vts) 2406 | { 2407 | if (exposure < 0 || exposure >= (1 << sensor->vts_reg_num_bits)) 2408 | { 2409 | vcos_log_error("Invalid exposure:%d, vts range is 0 to %u!\n", exposure, 2410 | (1 << sensor->vts_reg_num_bits) - 1); 2411 | } 2412 | else 2413 | { 2414 | uint8_t val; 2415 | int i, j = VCOS_ALIGN_DOWN(sensor->vts_reg_num_bits - 1, 8); 2416 | int num_regs = (sensor->vts_reg_num_bits + 7) >> 3; 2417 | 2418 | for (i = 0; i < num_regs; i++, j -= 8) 2419 | { 2420 | val = (exposure >> j) & 0xFF; 2421 | modReg(mode, sensor->vts_reg + i, 0, 7, val, EQUAL); 2422 | vcos_log_error("Set vts %04X to %02X", sensor->vts_reg + i, val); 2423 | } 2424 | } 2425 | } 2426 | if (sensor->gain_reg && gain != -1) 2427 | { 2428 | if (gain < 0 || gain >= (1 << sensor->gain_reg_num_bits)) 2429 | { 2430 | vcos_log_error("Invalid gain:%d, gain range is 0 to %u\n", gain, 2431 | (1 << sensor->gain_reg_num_bits) - 1); 2432 | } 2433 | else 2434 | { 2435 | uint8_t val; 2436 | int i, j = VCOS_ALIGN_DOWN(sensor->gain_reg_num_bits - 1, 8); 2437 | int num_regs = (sensor->gain_reg_num_bits + 7) >> 3; 2438 | 2439 | for (i = 0; i < num_regs; i++, j -= 8) 2440 | { 2441 | val = (gain >> j) & 0xFF; 2442 | modReg(mode, sensor->gain_reg + i, 0, 7, val, EQUAL); 2443 | vcos_log_error("Set gain %04X to %02X", sensor->gain_reg + i, val); 2444 | } 2445 | } 2446 | } 2447 | } 2448 | -------------------------------------------------------------------------------- /raw_header.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Raspberry Pi Trading 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 20 | ANY 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 | #ifndef RAWHEADER_H_ 29 | #define RAWHEADER_H_ 30 | 31 | #include "interface/vctypes/vc_image_types.h" 32 | 33 | #define BRCM_ID_SIG 0x4D435242 /* 'BRCM' */ 34 | #define HEADER_VERSION 111 35 | 36 | #define BRCM_RAW_HEADER_LENGTH 32768 // 1024 37 | 38 | struct brcm_camera_mode 39 | { 40 | uint8_t name[32]; 41 | uint16_t width; 42 | uint16_t height; 43 | uint16_t padding_right; 44 | uint16_t padding_down; 45 | uint32_t dummy[6]; 46 | uint16_t transform; 47 | uint16_t format; 48 | uint8_t bayer_order; 49 | uint8_t bayer_format; 50 | }; 51 | 52 | struct brcm_raw_header 53 | { 54 | uint32_t id; // Must be set to "BRCM" 55 | uint32_t version; // Header version id 56 | uint32_t offset; // Offset to the image data 57 | uint32_t preamble_pad; // pad to address 16 58 | 59 | // offset 16 0x10 60 | uint8_t block1[160]; // 160 bytes long. 61 | 62 | // offset 176 0xB0 63 | struct brcm_camera_mode mode; 64 | uint8_t cam_mode_pad[16 - (sizeof(struct brcm_camera_mode) & 15)]; 65 | }; 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /res/Screenshot179.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypi/raspiraw/b770dd2b3302d6ba33996e0451aefc0eb20b97e9/res/Screenshot179.png -------------------------------------------------------------------------------- /res/out.0123.ppm.d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypi/raspiraw/b770dd2b3302d6ba33996e0451aefc0eb20b97e9/res/out.0123.ppm.d.png -------------------------------------------------------------------------------- /res/out.1000.ppm.d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypi/raspiraw/b770dd2b3302d6ba33996e0451aefc0eb20b97e9/res/out.1000.ppm.d.png -------------------------------------------------------------------------------- /res/out.3000.ppm.d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypi/raspiraw/b770dd2b3302d6ba33996e0451aefc0eb20b97e9/res/out.3000.ppm.d.png -------------------------------------------------------------------------------- /res/out.360fps.25xSlower.2.anim.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypi/raspiraw/b770dd2b3302d6ba33996e0451aefc0eb20b97e9/res/out.360fps.25xSlower.2.anim.gif -------------------------------------------------------------------------------- /rpi3-gpiovirtbuf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypi/raspiraw/b770dd2b3302d6ba33996e0451aefc0eb20b97e9/rpi3-gpiovirtbuf -------------------------------------------------------------------------------- /tools/1280x720: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | fps=90 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 6 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 720 --top 0 --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[2-9]" tstamps.csv 21 | 22 | skips=`grep "^[2-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/1296x720_S: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | fps=190 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 5 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 180 --top 0 --vinc F1 --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[1-46-9]" tstamps.csv 21 | 22 | skips=`grep "^[1-46-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/1296x730_s: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | fps=98 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 5 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 365 --top 0 --vinc 71 --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[2-9]" tstamps.csv 21 | 22 | skips=`grep "^[2-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/1640x1232: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | fps=40 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 4 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 1232 --top 0 --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[13-9]" tstamps.csv 21 | 22 | skips=`grep "^[13-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/1640x922: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | fps=40 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 5 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 922 --top 0 --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[13-9]" tstamps.csv 21 | 22 | skips=`grep "^[13-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/1920x1080: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | fps=30 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 1 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 1080 --top 0 --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[124-9]" tstamps.csv 21 | 22 | skips=`grep "^[124-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/2592x1944_s: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | fps=30 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 2 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 972 --top 0 --vinc 31 --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[1-24-9]" tstamps.csv 21 | 22 | skips=`grep "^[1-24-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/320x240: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | fps=180 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 7 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 240 --width 320 --top 0 --left 0 --vinc 1F --hinc F1 --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[1-46-9]" tstamps.csv 21 | 22 | skips=`grep "^[1-46-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/3280x2464: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | fps=15 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 3 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 2464 --top 0 --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[1-57-9]" tstamps.csv 21 | 22 | skips=`grep "^[1-57-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/640x128: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | fps=349 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 7 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 128 --top 0 --vinc 17 --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[13-9]" tstamps.csv 21 | 22 | skips=`grep "^[13-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/640x128_s: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | if [ "`cat /proc/cpuinfo | grep Revision | grep 9000`" = "" ]; then fps=659; else fps=499; fi 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 7 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 64 --top 0 --vinc 1F --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[2-9]" tstamps.csv 21 | 22 | skips=`grep "^[2-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/640x240: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | fps=180 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 7 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 240 --top 0 --vinc 17 --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[1-46-9]" tstamps.csv 21 | 22 | skips=`grep "^[1-46-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/640x240_B: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | fps=180 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 7 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 240 --top 240 --vinc 17 --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[1-46-9]" tstamps.csv 21 | 22 | skips=`grep "^[1-46-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/640x240_B_s: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | fps=359 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 7 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 120 --top 240 --vinc 1F --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[4-9]" tstamps.csv 21 | 22 | skips=`grep "^[4-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/640x240_s: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | fps=359 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 7 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 120 --top 0 --vinc 1F --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[4-9]" tstamps.csv 21 | 22 | skips=`grep "^[4-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/640x32: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | if [ "`cat /proc/cpuinfo | grep Revision | grep 9000`" = "" ]; then fps=749; else fps=539; fi 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 7 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 32 --top 0 --vinc 17 --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | # echo "press CTRL-C to stop, or ENTER to show frame skip indices ..." 20 | # read 21 | echo "after skip frame indices (middle column)" 22 | grep "^[2-9]" tstamps.csv 23 | 24 | skips=`grep "^[2-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 25 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 26 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 27 | echo "$per% frame skips" 28 | -------------------------------------------------------------------------------- /tools/640x400_s: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | fps=220 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 7 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 200 --top 0 --vinc 1F --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[1-35-9]" tstamps.csv 21 | 22 | skips=`grep "^[1-35-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/640x416_s: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | fps=210 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 7 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 208 --top 0 --vinc 1F --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[1-35-9]" tstamps.csv 21 | 22 | skips=`grep "^[1-35-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/640x480: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | if [ "$2" = "" ]; then fps=90; else fps=$2; fi 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 7 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 480 --top 0 --vinc 17 --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | D=`echo "0123456789" | sed "s/\`echo $((1000000/$fps)) | cut -b1\`//"` 20 | 21 | echo "after skip frame indices (middle column)" 22 | grep "^[$D]" tstamps.csv | sed "s/^/> /" 23 | 24 | skips=`grep "^[$D]" tstamps.csv | wc --lines | cut -f1 -d\ ` 25 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 26 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 27 | echo "$per% frame skips" 28 | -------------------------------------------------------------------------------- /tools/640x480_s: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | fps=180 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 7 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 240 --top 0 --vinc 1F --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | echo "after skip frame indices (middle column)" 20 | grep "^[1-46-9]" tstamps.csv 21 | 22 | skips=`grep "^[1-46-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 23 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 24 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 25 | echo "$per% frame skips" 26 | -------------------------------------------------------------------------------- /tools/640x64: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | if [ "`cat /proc/cpuinfo | grep Revision | grep 9000`" = "" ]; then fps=659; else fps=499; fi 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 7 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 64 --top 0 --vinc 17 --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | # echo "press CTRL-C to stop, or ENTER to show frame skip indices ..." 20 | # read 21 | echo "after skip frame indices (middle column)" 22 | grep "^[2-9]" tstamps.csv 23 | 24 | skips=`grep "^[2-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 25 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 26 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 27 | echo "$per% frame skips" 28 | -------------------------------------------------------------------------------- /tools/640x64_s: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then echo "format: `basename $0` ms"; exit; fi 4 | 5 | echo "removing /dev/shm/out.*.raw" 6 | rm -f /dev/shm/out.*.raw 7 | 8 | if [ "`cat /proc/cpuinfo | grep Revision | grep 9000`" = "" ]; then fps=749; else fps=539; fi 9 | echo "capturing frames for ${1}ms with ${fps}fps requested" 10 | raspiraw -md 7 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 32 --top 0 --vinc 1F --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null 11 | 12 | us=`cut -f1 -d, tstamps.csv | sort -n | uniq -c | sort -n | tail -1 | cut -b9-` 13 | l=`ls -l /dev/shm/out.*.raw | wc --lines` 14 | echo "$l frames were captured at $((1000000 / $us))fps" 15 | 16 | echo "frame delta time[us] distribution" 17 | cut -f1 -d, tstamps.csv | sort -n | uniq -c 18 | 19 | # echo "press CTRL-C to stop, or ENTER to show frame skip indices ..." 20 | # read 21 | echo "after skip frame indices (middle column)" 22 | grep "^[2-9]" tstamps.csv 23 | 24 | skips=`grep "^[2-9]" tstamps.csv | wc --lines | cut -f1 -d\ ` 25 | stamps=`wc --lines tstamps.csv | cut -f1 -d\ ` 26 | per=`expr \( 100 \* $skips \) / \( $skips + $stamps \)` 27 | echo "$per% frame skips" 28 | -------------------------------------------------------------------------------- /tools/double: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raspberrypi/raspiraw/b770dd2b3302d6ba33996e0451aefc0eb20b97e9/tools/double -------------------------------------------------------------------------------- /tools/double.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | FILE *src = fopen(argv[1], "rb"); 8 | char line[9999], m; 9 | int w, h, f, i; 10 | 11 | assert(src); 12 | fgets(line, 9999, src); 13 | assert(0 == strcmp(line, "P6\n") || 0 == strcmp(line, "P5\n")); 14 | m = line[1]; 15 | fgets(line, 9999, src); 16 | assert(2 == sscanf(line, "%d %d", &w, &h)); 17 | fgets(line, 9999, src); 18 | assert(1 == sscanf(line, "%d", &f)); 19 | assert(3 * w < 9999); 20 | assert(9 <= printf("P%c\n%d %d\n%d\n", m, w, 2 * h, f)); 21 | 22 | f = (m == '5') ? 1 : 3; 23 | 24 | for (i = 0; i < h; ++i) 25 | { 26 | assert(f * w == fread(line, 1, f * w, src)); 27 | assert(f * w == fwrite(line, 1, f * w, stdout)); 28 | assert(f * w == fwrite(line, 1, f * w, stdout)); 29 | } 30 | 31 | h = ftell(src); 32 | fseek(src, 0, SEEK_END); 33 | assert(h == ftell(src)); 34 | 35 | fclose(src); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /tools/gifenc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # doc: http://blog.pkh.me/p/21-high-quality-gif-with-ffmpeg.html 4 | # needs: ffmpeg 5 | 6 | palette="/tmp/palette.png" 7 | 8 | #filters="fps=15,scale=320:-1:flags=lanczos" 9 | filters="fps=25,scale=640:-1:flags=lanczos" 10 | 11 | ffmpeg -v warning -i $1 -vf "$filters,palettegen" -y $palette 12 | ffmpeg -v warning -i $1 -i $palette -lavfi "$filters [x]; [x][1:v] paletteuse" -y $2 13 | -------------------------------------------------------------------------------- /tools/raw2ogg2anim: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # needs: dcraw, double, netpbm tools, gstreamer, gifenc.sh 4 | 5 | if [ "$4" = "" ]; then echo "format: `basename $0` vname first last fps [d[d]]"; exit; fi 6 | 7 | echo "removing old auxiliary files" 8 | rm -f out.*.raw out.*.ppm out.*.ppm.[dDT] out.*.ppm.d.png 9 | 10 | echo "copying /dev/shm/out.????.raw files" 11 | for((f=$2; f<=$3; ++f)) 12 | do 13 | # cp /dev/shm/out.$(printf "%04d" $f).raw . 14 | cat hd0.32k /dev/shm/out.$(printf "%04d" $f).raw >out.$(printf "%04d" $f).raw 15 | echo -en "$f \r" 16 | done 17 | echo 18 | 19 | echo "dcraw each .raw file (to .ppm)" 20 | for f in out.*.raw 21 | do 22 | dcraw $f 23 | echo -en "$f \r" 24 | done 25 | echo 26 | 27 | echo ".ppm -> .ppm.d" 28 | for f in out.*.ppm 29 | do 30 | if [ "$5" = "" ]; then 31 | ln -s $f $f.d 32 | else 33 | if [ "$5" = "d" ]; then 34 | double $f > $f.d 35 | else 36 | double $f > $f.D 37 | double $f.D > $f.d 38 | fi 39 | fi 40 | echo -en "$f \r" 41 | done 42 | echo 43 | 44 | echo ".ppm.d -> .ppm.d.png" 45 | for f in out.*.ppm.d 46 | do 47 | pnmtopng $f > $f.png 48 | echo -en "$f \r" 49 | done 50 | echo 51 | 52 | echo "now creating $1.ogg" 53 | gst-launch-1.0 multifilesrc location="out.%04d.ppm.d.png" index=$2 caps="image/png,framerate=\(fraction\)$4/1" ! pngdec ! videorate ! videoconvert ! videorate ! theoraenc ! oggmux ! filesink location="$1.ogg" 54 | 55 | echo "now creating $1.anim.gif" 56 | gifenc.sh $1.ogg $1.anim.gif 57 | 58 | echo "done" 59 | --------------------------------------------------------------------------------