https://bitbucket.org/hudson/magic-lantern
Tip revision: 5cef4841ad57b98597523923dae27abe8a20b2bc authored by alex@thinkpad on 25 April 2016, 17:04:59 UTC
Image buffers: fix help
Image buffers: fix help
Tip revision: 5cef484
shoot.c
/** \file
* Shooting experiments: intervalometer, LCD RemoteShot. More to come.
*
* (C) 2010 Alex Dumitrache, broscutamaker@gmail.com
*/
/*
* Magic Lantern is Copyright (C) 2009 Trammell Hudson <hudson+ml@osresearch.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "shoot.h"
#include "dryos.h"
#include "util.h"
#include "bmp.h"
#include "version.h"
#include "config.h"
#include "menu.h"
#include "property.h"
#include "lens.h"
#include "gui.h"
#include "math.h"
#include "raw.h"
#include "histogram.h"
#include "fileprefix.h"
#include "beep.h"
#include "zebra.h"
#include "cropmarks.h"
#include "focus.h"
#include "picstyle.h"
#include "imgconv.h"
#include "fps.h"
#include "lvinfo.h"
#include "powersave.h"
#ifdef FEATURE_LCD_SENSOR_REMOTE
#include "lcdsensor.h"
#endif
/* only included for clock CBRs (to be removed after refactoring) */
#include "battery.h"
#include "tskmon.h"
#if defined(CONFIG_MODULES)
#include "module.h"
#endif
static CONFIG_INT( "shoot.num", pics_to_take_at_once, 0);
static CONFIG_INT( "shoot.af", shoot_use_af, 0 );
static int snap_sim = 0;
void move_lv_afframe(int dx, int dy);
void display_trap_focus_info();
#ifdef FEATURE_LCD_SENSOR_REMOTE
void display_lcd_remote_icon(int x0, int y0);
#endif
void intervalometer_stop();
void wait_till_next_second();
void zoom_sharpen_step();
int take_fast_pictures( int number );
#if !defined(AUDIO_REM_SHOT_POS_X) && !defined(AUDIO_REM_SHOT_POS_Y)
#define AUDIO_REM_SHOT_POS_X 20
#define AUDIO_REM_SHOT_POS_Y 40
#endif
int display_idle()
{
extern thunk ShootOlcApp_handler;
if (lv) return liveview_display_idle();
else return gui_state == GUISTATE_IDLE && !gui_menu_shown() &&
((!DISPLAY_IS_ON && CURRENT_DIALOG_MAYBE == 0) || (intptr_t)get_current_dialog_handler() == (intptr_t)&ShootOlcApp_handler);
}
int uniwb_is_active()
{
return
lens_info.wb_mode == WB_CUSTOM &&
ABS((int)lens_info.WBGain_R - 1024) < 100 &&
ABS((int)lens_info.WBGain_G - 1024) < 100 &&
ABS((int)lens_info.WBGain_B - 1024) < 100;
}
//~ CONFIG_INT("iso_selection", iso_selection, 0);
static CONFIG_INT("hdr.enabled", hdr_enabled, 0);
static PROP_INT(PROP_AEB, aeb_setting);
int is_hdr_bracketing_enabled()
{
#ifdef FEATURE_HDR_BRACKETING
return (hdr_enabled && !aeb_setting); // when Canon bracketing is active, ML bracketing should not run
#else
return 0;
#endif
}
// The min and max EV delta encoded in 1/8 of EV
#define HDR_STEPSIZE_MIN 4
#define HDR_STEPSIZE_MAX 64
static CONFIG_INT("hdr.type", hdr_type, 0); // exposure, aperture, flash
CONFIG_INT("hdr.frames", hdr_steps, 1);
CONFIG_INT("hdr.ev_spacing", hdr_stepsize, 16);
static CONFIG_INT("hdr.delay", hdr_delay, 1);
static CONFIG_INT("hdr.seq", hdr_sequence, 1);
static CONFIG_INT("hdr.iso", hdr_iso, 0);
static CONFIG_INT("hdr.scripts", hdr_scripts, 0); //1 enfuse, 2 align+enfuse, 3 only list images
#ifdef CONFIG_BULB
static int hdr_first_shot_bulb = 0;
#endif
static CONFIG_INT( "interval.enabled", interval_enabled, 0 );
static CONFIG_INT( "interval.trigger", interval_trigger, 0 );
static CONFIG_INT( "interval.time", interval_time, 10 );
static CONFIG_INT( "interval.start.time", interval_start_time, 3 );
static CONFIG_INT( "interval.stop.after", interval_stop_after, 0 );
static CONFIG_INT( "interval.scripts", interval_scripts, 0); //1 bash, 2 ms-dos, 3 text
//~ static CONFIG_INT( "interval.stop.after", interval_stop_after, 0 );
#define INTERVAL_TRIGGER_LEAVE_MENU 0
#define INTERVAL_TRIGGER_HALF_SHUTTER 1
#define INTERVAL_TRIGGER_TAKE_PIC 2
static int intervalometer_pictures_taken = 0;
static int intervalometer_next_shot_time = 0;
#define TRAP_NONE 0
#define TRAP_ERR_CFN 1
#define TRAP_IDLE 2
#define TRAP_ACTIVE 3
#ifdef FEATURE_TRAP_FOCUS
static uint32_t trap_focus_continuous_state = 0;
static uint32_t trap_focus_msg = 0;
#endif
CONFIG_INT( "focus.trap", trap_focus, 0);
static CONFIG_INT( "audio.release-level", audio_release_level, 10);
static CONFIG_INT( "flash_and_no_flash", flash_and_no_flash, 0);
static CONFIG_INT( "lv_3rd_party_flash", lv_3rd_party_flash, 0);
//~ static CONFIG_INT( "zoom.enable.face", zoom_enable_face, 0);
static CONFIG_INT( "zoom.disable.x5", zoom_disable_x5, 0);
static CONFIG_INT( "zoom.disable.x10", zoom_disable_x10, 0);
static CONFIG_INT( "zoom.sharpen", zoom_sharpen, 0);
static CONFIG_INT( "zoom.halfshutter", zoom_halfshutter, 0);
static CONFIG_INT( "zoom.focus_ring", zoom_focus_ring, 0);
CONFIG_INT( "zoom.auto.exposure", zoom_auto_exposure, 0);
#ifdef FEATURE_BULB_TIMER
static int bulb_duration_change(struct config_var * var, int old_value, int new_value);
static CONFIG_INT_UPDATE( "bulb.duration", bulb_duration, 5, bulb_duration_change);
static CONFIG_INT ( "bulb.timer", bulb_timer, 0);
static CONFIG_INT ( "bulb.display.mode", bulb_display_mode, 0);
#else
static int bulb_duration = 0;
static int bulb_display_mode = 0;
#endif
static CONFIG_INT( "mlu.auto", mlu_auto, 0);
static CONFIG_INT( "mlu.mode", mlu_mode, 1);
#define MLU_ALWAYS_ON (mlu_auto && mlu_mode == 0)
#define MLU_SELF_TIMER (mlu_auto && mlu_mode == 1)
#define MLU_HANDHELD (mlu_auto && mlu_mode == 2)
#ifdef FEATURE_MLU_HANDHELD_DEBUG
static int mlu_handled_debug = 0;
#endif
#ifndef CONFIG_5DC
static CONFIG_INT("mlu.handheld.delay", mlu_handheld_delay, 4);
static CONFIG_INT("mlu.handheld.shutter", mlu_handheld_shutter, 1); // restrict it to shutter speeds where the improvement is noticeable
#else
#define mlu_handheld_shutter 0
#endif
extern int lcd_release_running;
extern int lens_mlu_delay;
//New option for the sensitivty of the motion release
static CONFIG_INT( "motion.release-level", motion_detect_level, 8);
static CONFIG_INT( "motion.delay", motion_detect_delay, 0);
static CONFIG_INT( "motion.trigger", motion_detect_trigger, 0);
static CONFIG_INT( "motion.dsize", motion_detect_size, 1);
static CONFIG_INT( "motion.position", motion_detect_position, 0);
static CONFIG_INT("bulb.ramping.man.focus", bramp_manual_speed_focus_steps_per_shot, 0);
static int intervalometer_running = 0;
int is_intervalometer_running() { return intervalometer_running; }
int motion_detect = 0; //int motion_detect_level = 8;
#ifdef FEATURE_AUDIO_REMOTE_SHOT
static int audio_release_running = 0;
#endif
#define TIME_MAX_VALUE 28800 //8 hours
#ifdef FEATURE_INTERVALOMETER
int get_interval_count()
{
return intervalometer_pictures_taken;
}
int get_interval_time()
{
return interval_time;
}
void set_interval_time(int seconds)
{
interval_time = seconds;
}
#endif
static const char* format_time_hours_minutes_seconds(int seconds)
{
static char msg[50];
msg[0] = '\0';
if (seconds >= 3600)
{
STR_APPEND(msg, "%dh", seconds / 3600);
seconds = seconds % 3600;
}
if (seconds >= 60)
{
STR_APPEND(msg, "%dm", seconds / 60);
seconds = seconds % 60;
}
if (seconds || !msg[0])
{
STR_APPEND(msg, "%ds", seconds);
}
return msg;
}
int get_bulb_shutter_raw_equiv()
{
return shutterf_to_raw(bulb_duration);
}
static void seconds_clock_update();
static volatile int seconds_clock = 0;
static volatile int miliseconds_clock = 0;
static volatile uint64_t microseconds_clock = 0;
int get_seconds_clock() { return seconds_clock; }
int get_ms_clock_value() { seconds_clock_update(); return miliseconds_clock; }
uint64_t get_us_clock_value() { seconds_clock_update(); return microseconds_clock; }
int get_ms_clock_value_fast() { return miliseconds_clock; } // fast, but less accurate
/**
* useful for things that shouldn't be done more often than X ms
*
* for example:
int aux;
for (int i = 0; i < 1000; i++)
{
process(i);
if (should_run_polling_action(500, &aux))
NotifyBox(1000, "Progress: %d/%d ", i, 1000);
}
or:
void process_step() // called periodically
{
do_one_iteration();
static int aux = 0;
if (should_run_polling_action(500, &aux))
NotifyBox(1000, "some progress update");
}
*/
int should_run_polling_action(int period_ms, int* last_updated_time)
{
if (miliseconds_clock >= (*last_updated_time) + period_ms)
{
*last_updated_time = miliseconds_clock;
return 1;
}
return 0;
}
static void do_this_every_second() // called every second
{
#ifdef FEATURE_INTERVALOMETER
if (intervalometer_running && lens_info.job_state == 0 && !gui_menu_shown() && !get_halfshutter_pressed())
info_led_blink(1, 50, 0);
#endif
#ifdef CONFIG_BATTERY_INFO
RefreshBatteryLevel_1Hz();
#endif
reset_pre_shutdown_flag_step();
#ifdef FEATURE_SHOW_CPU_USAGE
task_update_loads();
#endif
#ifdef CONFIG_TSKMON
if (!RECORDING_RAW)
{
tskmon_stack_check_all();
}
#endif
#ifdef FEATURE_SHOW_OVERLAY_FPS
static int k = 0; k++;
if (k%10 == 0) update_lv_fps();
#endif
#ifdef FEATURE_SHOW_STATE_FPS
static int j=0; j++;
if(j%10 == 0) update_state_fps();
#endif
// TODO: update bitrate.c to use this approach too
#if defined(CONFIG_5D3) || defined(CONFIG_6D)
if (RECORDING_H264)
{
extern void measure_bitrate();
measure_bitrate();
lens_display_set_dirty();
}
#endif
}
#ifndef TIMER_GET_VALUE
#define TIMER_GET_VALUE() *(volatile uint32_t*)0xC0242014
#endif
#define TIMER_MAX 1048576
// called every 200ms or on request
static void
seconds_clock_update()
{
/* do not use semaphores as this code should be very fast */
int old_stat = cli();
static uint32_t prev_timer = 0;
uint32_t timer_value = TIMER_GET_VALUE();
// this timer rolls over every 1048576 ticks
// and 1000000 ticks = 1 second
// so 1 rollover is done every 1.05 seconds roughly
/* update microsecond timer with simple overflow handling thanks to the timer overflowing at 2^n */
uint32_t usec_delta = (timer_value - prev_timer + TIMER_MAX) & (TIMER_MAX - 1);
microseconds_clock += usec_delta; /* overflow after 584942 years */
/* msec and seconds clock derieve from high precision counter */
miliseconds_clock = microseconds_clock / 1000; /* overflow after 24 days */
seconds_clock = microseconds_clock / 1000000; /* overflow after 68 years */
prev_timer = timer_value;
sei(old_stat);
}
static void
seconds_clock_task( void* unused )
{
TASK_LOOP
{
seconds_clock_update();
static int prev_s_clock = 0;
if (prev_s_clock != seconds_clock)
{
#if defined(CONFIG_MODULES)
module_exec_cbr(CBR_SECONDS_CLOCK);
#endif
do_this_every_second();
prev_s_clock = seconds_clock;
}
msleep(200);
}
}
TASK_CREATE( "clock_task", seconds_clock_task, 0, 0x19, 0x2000 );
#ifdef FEATURE_INTERVALOMETER
static MENU_UPDATE_FUNC(timelapse_calc_display)
{
int d = get_interval_time();
d = MAX(d, raw2shutter_ms(lens_info.raw_shutter)/1000);
int total_shots = interval_stop_after ? (int)MIN((int)interval_stop_after, (int)avail_shot) : (int)avail_shot;
int total_time_s = d * total_shots;
int total_time_m = total_time_s / 60;
int fps = video_mode_fps;
if (!fps) fps = video_system_pal ? 25 : 30;
MENU_SET_WARNING(MENU_WARN_INFO,
"Timelapse: %dh%02dm, %d shots, %d fps => %02dm%02ds.",
total_time_m / 60,
total_time_m % 60,
total_shots, fps,
(total_shots / fps) / 60,
(total_shots / fps) % 60
);
}
static MENU_UPDATE_FUNC(interval_timer_display)
{
int d = CURRENT_VALUE;
if (!d)
{
MENU_SET_NAME("Take pics...");
MENU_SET_VALUE("like crazy");
}
MENU_SET_ICON(MNI_PERCENT, CURRENT_VALUE * 100 / TIME_MAX_VALUE);
MENU_SET_ENABLED(1);
if (auto_power_off_time && auto_power_off_time <= d)
MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "Check auto power off setting (currently %ds).", auto_power_off_time);
timelapse_calc_display(entry, info);
}
static MENU_UPDATE_FUNC(interval_start_after_display)
{
MENU_SET_ICON(MNI_PERCENT, CURRENT_VALUE * 100 / TIME_MAX_VALUE);
if (auto_power_off_time && auto_power_off_time <= interval_start_time)
MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "Check auto power off setting (currently %ds).", auto_power_off_time);
if(interval_trigger == INTERVAL_TRIGGER_TAKE_PIC)
MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "Has no effect when trigger is set to take a pic");
}
static MENU_UPDATE_FUNC(interval_stop_after_display)
{
int d = CURRENT_VALUE;
MENU_SET_VALUE(
d ? "%d shots"
: "%s",
d ? d : (intptr_t) "Disabled"
);
MENU_SET_ENABLED(d);
if (d > avail_shot)
MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "Not enough space for %d shots (only for %d).", d, avail_shot);
timelapse_calc_display(entry, info);
}
static MENU_UPDATE_FUNC(interval_trigger_update)
{
if(interval_trigger == INTERVAL_TRIGGER_TAKE_PIC)
{
MENU_SET_WARNING(MENU_WARN_INFO, "Also useful to trigger off of motion or trap focus");
}
}
/* interface with ETTR module */
static menu_update_func auto_ettr_intervalometer_warning = MODULE_FUNCTION(auto_ettr_intervalometer_warning);
static void(*auto_ettr_intervalometer_wait)(void) = MODULE_FUNCTION(auto_ettr_intervalometer_wait);
static MENU_UPDATE_FUNC(intervalometer_display)
{
if (CURRENT_VALUE)
{
int d = get_interval_time();
MENU_SET_VALUE("ON, %s",
format_time_hours_minutes_seconds(d)
);
int d_start = interval_start_time;
if (auto_power_off_time && auto_power_off_time <= MAX(d, d_start))
MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "Check auto power off setting (currently %ds).", auto_power_off_time);
#ifdef CONFIG_MODULES
auto_ettr_intervalometer_warning(entry, info);
#endif
}
else
{
MENU_SET_VALUE("OFF");
}
if (shooting_mode != SHOOTMODE_M && !is_bulb_mode())
MENU_SET_WARNING(MENU_WARN_ADVICE, "Use M mode to avoid exposure flicker.");
else if (lens_info.raw_aperture != lens_info.raw_aperture_min)
MENU_SET_WARNING(MENU_WARN_ADVICE, "Shoot wide-open or unscrew lens to avoid aperture flicker.");
else if (raw2shutter_ms(lens_info.raw_shutter) < 10)
MENU_SET_WARNING(MENU_WARN_ADVICE, "Use slow shutter speeds to avoid shutter flicker.");
else if (lens_info.wb_mode == 0)
MENU_SET_WARNING(MENU_WARN_ADVICE, "Use manual white balance to avoid WB flicker.");
else if (shoot_use_af && !is_manual_focus())
MENU_SET_WARNING(MENU_WARN_ADVICE, "Disable autofocus.");
else if (lens_info.IS && lens_info.IS != 8)
MENU_SET_WARNING(MENU_WARN_ADVICE, "Disable image stabilization.");
if (entry->selected) timelapse_calc_display(entry, info);
}
#endif
#ifdef FEATURE_AUDIO_REMOTE_SHOT
static MENU_UPDATE_FUNC(audio_release_display)
{
if (audio_release_running)
{
MENU_SET_VALUE("ON, level=%d", audio_release_level);
MENU_SET_SHORT_VALUE("%d", audio_release_level);
}
}
#endif
#ifdef FEATURE_MOTION_DETECT
//GUI Functions for the motion detect sensitivity.
static MENU_UPDATE_FUNC(motion_detect_display)
{
if (motion_detect)
{
MENU_SET_VALUE(
"%s, level=%d",
motion_detect_trigger == 0 ? "EXP" : motion_detect_trigger == 1 ? "DIF" : "STDY",
motion_detect_level
);
MENU_SET_SHORT_VALUE(
"%s,%d",
motion_detect_trigger == 0 ? "EXP" : motion_detect_trigger == 1 ? "DIF" : "STDY",
motion_detect_level
);
}
if (motion_detect_trigger == 2)
MENU_SET_WARNING(MENU_WARN_ADVICE, "Press shutter halfway and be careful (tricky feature).");
if (motion_detect_trigger < 2 && !lv)
MENU_SET_WARNING(MENU_WARN_ADVICE, "With current settings, motion detect only works in LiveView.");
}
#endif
int get_trap_focus() { return trap_focus; }
#if defined(CONFIG_PHOTO_MODE_INFO_DISPLAY)
static void double_buffering_start(int ytop, int height)
{
// use double buffering to avoid flicker
bmp_vram(); // make sure parameters are up to date
ytop = MIN(ytop, BMP_H_PLUS - height);
memcpy(bmp_vram_idle() + BM(0,ytop), bmp_vram_real() + BM(0,ytop), height * BMPPITCH);
bmp_draw_to_idle(1);
}
static void double_buffering_end(int ytop, int height)
{
// done drawing, copy image to main BMP buffer
bmp_draw_to_idle(0);
bmp_vram(); // make sure parameters are up to date
ytop = MIN(ytop, BMP_H_PLUS - height);
memcpy(bmp_vram_real() + BM(0,ytop), bmp_vram_idle() + BM(0,ytop), height * BMPPITCH);
bzero32(bmp_vram_idle() + BM(0,ytop), height * BMPPITCH);
}
#endif
void set_flash_firing(int mode)
{
lens_wait_readytotakepic(64);
mode = COERCE(mode, 0, 2);
prop_request_change(PROP_STROBO_FIRING, &mode, 4);
}
#ifdef FEATURE_FLASH_NOFLASH
#ifndef FEATURE_FLASH_TWEAKS
#error This requires FEATURE_FLASH_TWEAKS
#endif
static MENU_UPDATE_FUNC(flash_and_no_flash_display)
{
if (strobo_firing == 2)
MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "Flash is automatic, can't adjust.");
}
#endif
static volatile int afframe_ack = 0;
#ifdef CONFIG_LIVEVIEW
static int afframe[128];
PROP_HANDLER( PROP_LV_AFFRAME ) {
ASSERT(len <= sizeof(afframe));
if (!lv)
{
/* I'm not interested in the values of this property outside LiveView */
return;
}
#ifdef FEATURE_SPOTMETER
spotmeter_erase();
#endif
crop_set_dirty(10);
afframe_set_dirty();
memcpy(afframe, buf, len);
afframe_ack = 1;
}
#else
static int afframe[100]; // dummy
#endif
void get_afframe_pos(int W, int H, int* x, int* y)
{
if (!afframe[0])
{
/* property did not fire? return center position */
*x = W/2;
*y = H/2;
return;
}
*x = (afframe[2] + afframe[4]/2) * W / afframe[0];
*y = (afframe[3] + afframe[5]/2) * H / afframe[1];
}
/* get sensor resolution, as specified by PROP_LV_AFFRAME */
/* (to get valid values, one has to go to LiveView at least once) */
void get_afframe_sensor_res(int* W, int* H)
{
if (W) *W = afframe[0];
if (H) *H = afframe[1];
}
#ifdef FEATURE_LV_ZOOM_SETTINGS
PROP_HANDLER( PROP_HALF_SHUTTER ) {
zoom_sharpen_step();
}
static int zoom_was_triggered_by_halfshutter = 0;
PROP_HANDLER(PROP_LV_DISPSIZE)
{
/* note: 129 is a special screen before zooming in, on newer cameras */
ASSERT(buf[0] == 1 || buf[0]==129 || buf[0] == 5 || buf[0] == 10);
zoom_sharpen_step();
if (buf[0] == 1) zoom_was_triggered_by_halfshutter = 0;
}
#endif // FEATURE_LV_ZOOM_SETTINGS
void set_lv_zoom(int zoom)
{
if (!lv) return;
if (RECORDING) return;
if (is_movie_mode() && video_mode_crop) return;
zoom = COERCE(zoom, 1, 10);
if (zoom > 1 && zoom < 10) zoom = 5;
idle_globaldraw_dis();
#ifdef CONFIG_ZOOM_HALFSHUTTER_UILOCK
int hs = get_halfshutter_pressed();
if (hs) SW1(0,0);
gui_uilock(UILOCK_EVERYTHING);
#endif
prop_request_change_wait(PROP_LV_DISPSIZE, &zoom, 4, 1000);
#ifdef CONFIG_ZOOM_HALFSHUTTER_UILOCK
gui_uilock(UILOCK_NONE);
if (hs) SW1(1,0);
#endif
msleep(150);
idle_globaldraw_en();
}
int get_mlu_delay(int raw)
{
return
raw == 6 ? 750 :
raw >= 7 ? (raw - 6) * 1000 :
raw * 100;
}
#ifdef FEATURE_MLU_HANDHELD
static void mlu_take_pic()
{
#if defined(CONFIG_5D2) || defined(CONFIG_50D) // not sure about 7D
SW1(1,00);
SW2(1,250);
SW2(0,50);
SW1(0,50);
#elif defined(CONFIG_40D)
call("FA_Release");
#else
call("Release"); // new cameras (including 500D)
#endif
}
static int mlu_shake_running = 0;
static void mlu_shake_task()
{
#ifdef FEATURE_MLU_HANDHELD_DEBUG
if (mlu_handled_debug) { msleep(1000); NotifyBox(5000, "Taking pic..."); msleep(1000); }
#endif
//~ beep();
msleep(get_mlu_delay(mlu_handheld_delay));
SW1(0,0); SW2(0,0);
mlu_take_pic();
mlu_shake_running = 0;
}
#ifdef FEATURE_MLU_HANDHELD_DEBUG
static char mlu_msg[1000] = "";
#endif
int handle_mlu_handheld(struct event * event)
{
if (MLU_HANDHELD && !lv)
{
extern int ml_taking_pic;
if (ml_taking_pic) return 1; // do not use this feature for pictures initiated by ML code
if (is_hdr_bracketing_enabled()) return 1; // may interfere with HDR bracketing
if (trap_focus) return 1; // may not play nice with trap focus
if (is_bulb_mode()) return 1; // not good in bulb mode
if (aeb_setting) return 1; // not working with Canon bracketing
#ifdef FEATURE_MLU_HANDHELD_DEBUG
if (mlu_handled_debug && event->param == GMT_OLC_INFO_CHANGED)
{
STR_APPEND(mlu_msg, "%8x ", MEM(event->obj));
static int k = 0; k++;
if (k % 5 == 0) { STR_APPEND(mlu_msg, "\n"); }
}
#endif
if (event->param == GMT_OLC_INFO_CHANGED
&& ((MEM(event->obj) & 0x00FFF001) == 0x80001) // OK on 5D3, 5D2, 550D, 600D, 500D, maybe others
&& !mlu_shake_running)
{
mlu_shake_running = 1;
task_create("mlu_pic", 0x1a, 0x1000, mlu_shake_task, 0);
return 1;
}
static int mlu_should_be_cleared = 0;
if (event->param == BGMT_PRESS_HALFSHUTTER)
{
if (mlu_handheld_shutter && (lens_info.raw_shutter < 64 || lens_info.raw_shutter > 112)) // 1/2 ... 1/125
return 1;
if (!get_mlu())
{
info_led_on();
mlu_should_be_cleared = 1;
set_mlu(1);
}
}
if (event->param == BGMT_UNPRESS_HALFSHUTTER && mlu_should_be_cleared)
{
if (get_mlu()) set_mlu(0);
mlu_should_be_cleared = 0;
info_led_off();
}
}
return 1;
}
#endif // FEATURE_MLU_HANDHELD
#ifdef CONFIG_RAW_LIVEVIEW
int focus_box_get_raw_crop_offset(int* delta_x, int* delta_y)
{
/* are we in x5/x10 zoom mode? */
if (lv && lv_dispsize > 1)
{
/* find out where we are inside the raw frame */
#ifdef CONFIG_DIGIC_V
uint32_t pos1 = shamem_read(0xc0f09050);
uint32_t pos2 = shamem_read(0xc0f09054);
#else
uint32_t pos1 = shamem_read(0xc0f0851C);
uint32_t pos2 = shamem_read(0xc0f08520);
#endif
int x1 = pos1 & 0xFFFF;
int x2 = pos2 & 0xFFFF;
int y1 = pos1 >> 16;
int y2 = pos2 >> 16;
/* does it look alright? */
if (x1 && x2 && y1 && y2 &&
x2 > x1 + 100 && y2 > y1 + 100)
{
int w = afframe[4];
int h = afframe[5];
/* convert everything in focus box coords (pixels) */
int scale_x = w * 100 / (x2-x1);
int scale_y = h * 100 / (y2-y1);
/* where we are inside the raw frame, in focus box coords */
int here_x = (x1+x2) * scale_x / 200;
int here_y = (y1+y2) * scale_y / 200;
here_y += raw_info.active_area.y1 / (lv_dispsize == 5 ? 4 : 8); /* don't ask me why */
/* we want to be in the center */
int dest_x = raw_info.active_area.x1 + raw_info.jpeg.width / 2;
int dest_y = raw_info.active_area.y1 + raw_info.jpeg.height / 2;
/* how far we are from there? */
*delta_x = dest_x - here_x;
*delta_y = dest_y - here_y;
return 1;
}
}
/* phuck! */
*delta_x = 0;
*delta_y = 0;
return 0;
}
#endif
#ifdef FEATURE_LV_FOCUS_BOX_SNAP
extern int focus_box_lv_jump;
#ifdef FEATURE_LV_FOCUS_BOX_SNAP_TO_X5_RAW
static CONFIG_INT("focus.box.raw.x5.x", focus_box_raw_x5_x, 0);
static CONFIG_INT("focus.box.raw.x5.y", focus_box_raw_x5_y, 0);
static CONFIG_INT("focus.box.raw.x5.w", focus_box_raw_x5_w, 0);
static CONFIG_INT("focus.box.raw.x5.h", focus_box_raw_x5_h, 0);
#endif
static int center_lv_aff = 0;
void center_lv_afframe()
{
center_lv_aff = 1;
}
void center_lv_afframe_do()
{
#ifdef CONFIG_LIVEVIEW
if (!lv || gui_menu_shown() || gui_state != GUISTATE_IDLE) return;
int pos_x[9];
int pos_y[9];
int n =
focus_box_lv_jump == 0 ? 1 :
focus_box_lv_jump == 1 ? 3 :
focus_box_lv_jump == 2 ? 5 :
focus_box_lv_jump == 3 ? 5 :
focus_box_lv_jump == 4 ? 9 :
2 ;
int W = afframe[0];
int H = afframe[1];
int Xtl = afframe[2];
int Ytl = afframe[3];
int w = afframe[4];
int h = afframe[5];
// center position
pos_x[0] = W/2;
pos_y[0] = H/2;
if (focus_box_lv_jump == 1)
{
// top
pos_x[1] = W / 2;
pos_y[1] = H*2/8;
// right
pos_x[2] = W*6/8;
pos_y[2] = H / 2;
}
else if (focus_box_lv_jump == 2)
{
// top
pos_x[1] = W / 2;
pos_y[1] = H*2/8;
// right
pos_x[2] = W*6/8;
pos_y[2] = H / 2;
// bottom
pos_x[3] = W / 2;
pos_y[3] = H*6/8;
// left
pos_x[4] = W*2/8;
pos_y[4] = H / 2;
}
else if (focus_box_lv_jump == 3)
{
// top left
pos_x[1] = W*2/6;
pos_y[1] = H*2/6;
// top right
pos_x[2] = W*4/6;
pos_y[2] = H*2/6;
// bottom right
pos_x[3] = W*4/6;
pos_y[3] = H*4/6;
// bottom left
pos_x[4] = W*2/6;
pos_y[4] = H*4/6;
}
else if (focus_box_lv_jump == 4)
{
// top left
pos_x[1] = W*2/6;
pos_y[1] = H*2/6;
// top
pos_x[2] = W / 2;
pos_y[2] = H*2/8;
// top right
pos_x[3] = W*4/6;
pos_y[3] = H*2/6;
// right
pos_x[4] = W*6/8;
pos_y[4] = H / 2;
// bottom right
pos_x[5] = W*4/6;
pos_y[5] = H*4/6;
// bottom
pos_x[6] = W / 2;
pos_y[6] = H*6/8;
// bottom left
pos_x[7] = W*2/6;
pos_y[7] = H*4/6;
// left
pos_x[8] = W*2/8;
pos_y[8] = H / 2;
}
#ifdef FEATURE_LV_FOCUS_BOX_SNAP_TO_X5_RAW
else if (focus_box_lv_jump == 5)
{
pos_x[1] = pos_x[0];
pos_y[1] = pos_y[0];
if (lv_dispsize > 1)
{
/* center on the raw frame */
raw_lv_request();
if (raw_update_params())
{
int delta_x, delta_y;
if (focus_box_get_raw_crop_offset(&delta_x, &delta_y))
{
/* be careful not to change the raw window */
int gap_left = (raw_info.jpeg.width - vram_hd.width) / 2 - delta_x;
int gap_top = (raw_info.jpeg.height - vram_hd.height) / 2 - delta_y;
int gap_right = (raw_info.jpeg.width - vram_hd.width) / 2 + delta_x;
int gap_bottom = (raw_info.jpeg.height - vram_hd.height) / 2 + delta_y;
if (gap_left < 200) delta_x -= (200 - gap_left);
if (gap_top < 50) delta_y -= (50 - gap_top);
if (gap_right < 200) delta_x += (200 - gap_right);
if (gap_bottom < 50) delta_y += (50 - gap_bottom);
/* focus box is here */
int Xc = Xtl + w/2;
int Yc = Ytl + h/2;
//~ NotifyBox(2000, "aff(%d,%d)\nhere (%d,%d)\ndest (%d,%d)\ntotal (%d,%d)", Xc, Yc, here_x, here_y, dest_x, dest_y, W, H);
/* and we'll move it here */
pos_x[1] = Xc + delta_x;
pos_y[1] = Yc + delta_y;
/* disable centering in x5 mode, since we will lose the framing */
pos_x[0] = pos_x[1];
pos_y[0] = pos_y[1];
/* save the position for 1x mode, where we no longer know the raw parameters */
focus_box_raw_x5_x = pos_x[1];
focus_box_raw_x5_y = pos_y[1];
focus_box_raw_x5_w = raw_info.jpeg.width;
focus_box_raw_x5_h = raw_info.jpeg.height;
}
else NotifyBox(2000, "Boo...");
}
else NotifyBox(2000, "Raw err");
raw_lv_release();
}
else
{
if (focus_box_raw_x5_x && focus_box_raw_x5_y)
{
/* flip between center and saved position */
pos_x[1] = focus_box_raw_x5_x;
pos_y[1] = focus_box_raw_x5_y;
/* draw a cropmark showing the raw zoom area */
int extent_x = BM2LV_DX(os.x_ex);
int extent_y = BM2LV_DY(os.y_ex);
int xl = pos_x[1] * extent_x / W;
int yl = pos_y[1] * extent_y / H;
int wl = focus_box_raw_x5_w * extent_x / W;
int hl = focus_box_raw_x5_h * extent_y / H;
int x = LV2BM_X(xl);
int y = LV2BM_Y(yl);
int w = LV2BM_DX(wl);
int h = LV2BM_DY(hl);
bmp_draw_rect(COLOR_WHITE, x-w/2, y-h/2, w, h);
bmp_draw_rect(COLOR_BLACK, x-w/2-1, y-h/2-1, w+2, h+2);
redraw_after(1000);
}
else NotifyBox(2000, "Try zooming first");
}
}
#endif
// now let's see where we are
int current = -1;
int Xc = Xtl + w/2;
int Yc = Ytl + h/2;
int emin = 200;
for (int i = 0; i < n; i++)
{
int e = MAX(ABS(pos_x[i] - Xc), ABS(pos_y[i] - Yc));
if (e < emin)
{
current = i;
emin = e;
}
}
int next = MOD(current + 1, n);
//~ bmp_printf(FONT_MED, 50, 50, "%d %d %d %d ", Xc, Yc, pos_x[0], pos_y[0]);
move_lv_afframe(pos_x[next] - Xc, pos_y[next] - Yc);
#endif
}
#endif
void move_lv_afframe(int dx, int dy)
{
#ifdef CONFIG_LIVEVIEW
if (!liveview_display_idle()) return;
if (is_movie_mode() && video_mode_crop) return;
if (RECORDING && is_manual_focus()) // prop handler won't trigger, clear spotmeter
clear_lv_afframe();
static int aff[128];
memcpy(aff, afframe, sizeof(aff));
aff[2] = COERCE(aff[2] + dx, 500, aff[0] - aff[4]);
aff[3] = COERCE(aff[3] + dy, 500, aff[1] - aff[5]);
// some cameras apply an offset to X position, when AF is on (not quite predictable)
// e.g. 60D and 5D2 apply the offset in AF mode, 550D doesn't seem to apply any
// so... we'll try to guess this offset and compensate for this quirk
int af = !is_manual_focus();
static int off_x = 0;
int x1 = aff[2];
if (af) aff[2] -= off_x;
afframe_ack = 0;
prop_request_change(PROP_LV_AFFRAME, aff, 0);
if (af)
{
for (int i = 0; i < 15; i++)
{
msleep(20);
if (afframe_ack) break;
}
int x2 = afframe[2];
if (afframe_ack && ABS(x2 - x1) > 160) // the focus box didn't quite end up where we wanted, so... adjust the offset and try again
{
int delta = (x2 - x1);
off_x += delta;
aff[2] = x1 - off_x;
prop_request_change(PROP_LV_AFFRAME, aff, 0);
}
}
#endif
}
static struct semaphore * set_maindial_sem = 0;
#ifdef FEATURE_PLAY_EXPOSURE_FUSION
int expfuse_running = 0;
static int expfuse_num_images = 0;
/*
static void add_yuv_acc16bit_src8bit(void* acc, void* src, int numpix)
{
ASSERT(acc);
ASSERT(src);
int16_t* accs = acc;
uint16_t* accu = acc;
int8_t* srcs = src;
uint8_t* srcu = src;
int i;
for (i = 0; i < numpix; i++)
{
accs[i*2] += srcs[i*2]; // chroma, signed
accu[i*2+1] += srcu[i*2+1]; // luma, unsigned
}
}*/
/*static void div_yuv_by_const_dst8bit_src16bit(void* dst, void* src, int numpix, int den)
{
ASSERT(dst);
ASSERT(src);
int8_t* dsts = dst;
uint8_t* dstu = dst;
int16_t* srcs = src;
uint16_t* srcu = src;
int i;
for (i = 0; i < numpix; i++)
{
dsts[i*2] = srcs[i*2] / den; // chroma, signed
dstu[i*2+1] = srcu[i*2+1] / den; // luma, unsigned
}
}*/
// octave:
// x = linspace(0,1,256);
// f = @(x) exp(-(x-0.5).^2 ./ 0.32) # mean=0.5, sigma=0.4
// sprintf("0x%02x, ",f(x) * 100)
static uint8_t gauss_lut[] = {0x2d, 0x2e, 0x2e, 0x2f, 0x30, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x34, 0x34, 0x35, 0x35, 0x36, 0x37, 0x37, 0x38, 0x38, 0x39, 0x39, 0x3a, 0x3b, 0x3b, 0x3c, 0x3c, 0x3d, 0x3e, 0x3e, 0x3f, 0x3f, 0x40, 0x41, 0x41, 0x42, 0x42, 0x43, 0x44, 0x44, 0x45, 0x45, 0x46, 0x46, 0x47, 0x48, 0x48, 0x49, 0x49, 0x4a, 0x4a, 0x4b, 0x4c, 0x4c, 0x4d, 0x4d, 0x4e, 0x4e, 0x4f, 0x4f, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52, 0x53, 0x53, 0x54, 0x54, 0x55, 0x55, 0x56, 0x56, 0x57, 0x57, 0x58, 0x58, 0x58, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x61, 0x61, 0x61, 0x61, 0x60, 0x60, 0x60, 0x60, 0x5f, 0x5f, 0x5f, 0x5f, 0x5e, 0x5e, 0x5e, 0x5d, 0x5d, 0x5d, 0x5c, 0x5c, 0x5c, 0x5b, 0x5b, 0x5a, 0x5a, 0x5a, 0x59, 0x59, 0x58, 0x58, 0x58, 0x57, 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x54, 0x53, 0x53, 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f, 0x4e, 0x4e, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x46, 0x46, 0x45, 0x45, 0x44, 0x44, 0x43, 0x42, 0x42, 0x41, 0x41, 0x40, 0x3f, 0x3f, 0x3e, 0x3e, 0x3d, 0x3c, 0x3c, 0x3b, 0x3b, 0x3a, 0x39, 0x39, 0x38, 0x38, 0x37, 0x37, 0x36, 0x35, 0x35, 0x34, 0x34, 0x33, 0x32, 0x32, 0x31, 0x31, 0x30, 0x30, 0x2f, 0x2e, 0x2e, 0x2d};
static void weighted_mean_yuv_init_acc32bit_ws16bit(void* acc, void* weightsum, int numpix)
{
bzero32(acc, numpix*8);
bzero32(weightsum, numpix*4);
}
static void weighted_mean_yuv_add_acc32bit_src8bit_ws16bit(void* acc, void* src, void* weightsum, int numpix)
{
int32_t* accs = acc;
uint32_t* accu = acc;
int8_t* srcs = src;
uint8_t* srcu = src;
uint16_t* ws = weightsum;
int i;
for (i = 0; i < numpix; i++)
{
int w = gauss_lut[srcu[i*2+1]];
accs[i*2] += srcs[i*2] * w; // chroma, signed
accu[i*2+1] += srcu[i*2+1] * w; // luma, unsigned
ws[i] += w;
}
}
static void weighted_mean_yuv_div_dst8bit_src32bit_ws16bit(void* dst, void* src, void* weightsum, int numpix)
{
int8_t* dsts = dst;
uint8_t* dstu = dst;
int32_t* srcs = src;
uint32_t* srcu = src;
uint16_t* ws = weightsum;
int i;
for (i = 0; i < numpix; i++)
{
int wt = ws[i];
dsts[i*2] = srcs[i*2] / wt; // chroma, signed
dstu[i*2+1] = COERCE(srcu[i*2+1] / wt, 0, 255); // luma, unsigned
}
}
#endif
void next_image_in_play_mode(int dir)
{
if (!PLAY_MODE) return;
void* buf_lv = get_yuv422_vram()->vram;
// ask for next image
fake_simple_button(dir > 0 ? BGMT_WHEEL_DOWN : BGMT_WHEEL_UP);
int k = 0;
// wait for image buffer location to be flipped => next image was loaded
while (get_yuv422_vram()->vram == buf_lv && k < 50)
{
msleep(100);
k++;
}
}
#ifdef FEATURE_PLAY_COMPARE_IMAGES
void playback_compare_images_task(int dir)
{
ASSERT(set_maindial_sem);
take_semaphore(set_maindial_sem, 0);
enter_play_mode();
if (!PLAY_MODE)
{
NotifyBox(1000, "CompareImages: Not in PLAY mode");
return;
}
if (dir == 0) // reserved for intervalometer
{
next_image_in_play_mode(-1);
dir = 1;
}
void* current_buf;
int w = get_yuv422_vram()->width;
int h = get_yuv422_vram()->height;
int buf_size = w * h * 2;
void* aux_buf = tmp_malloc(buf_size);
if (!aux_buf) goto cleanup;
current_buf = get_yuv422_vram()->vram;
yuv_halfcopy(aux_buf, current_buf, w, h, 1);
next_image_in_play_mode(dir);
current_buf = get_yuv422_vram()->vram;
yuv_halfcopy(aux_buf, current_buf, w, h, 0);
current_buf = get_yuv422_vram()->vram;
memcpy(current_buf, aux_buf, buf_size);
cleanup:
if (aux_buf) free(aux_buf);
give_semaphore(set_maindial_sem);
}
void playback_compare_images(int dir)
{
task_create("playcompare_task", 0x1c, 0, playback_compare_images_task, (void*)dir);
}
#endif
#ifdef FEATURE_PLAY_EXPOSURE_FUSION
void expfuse_preview_update_task(int dir)
{
ASSERT(set_maindial_sem);
take_semaphore(set_maindial_sem, 0);
/* fixme: buf_acc should be kept unchanged between calls,
* but freed at the end */
void* buf_acc = (void*)YUV422_HD_BUFFER_1;
void* buf_ws = (void*)YUV422_HD_BUFFER_2;
void* buf_lv = get_yuv422_vram()->vram;
if (!buf_lv) goto end;
int numpix = get_yuv422_vram()->width * get_yuv422_vram()->height;
if (!expfuse_running)
{
// first image
weighted_mean_yuv_init_acc32bit_ws16bit(buf_acc, buf_ws, numpix);
weighted_mean_yuv_add_acc32bit_src8bit_ws16bit(buf_acc, buf_lv, buf_ws, numpix);
expfuse_num_images = 1;
expfuse_running = 1;
}
next_image_in_play_mode(dir);
buf_lv = get_yuv422_vram()->vram; // refresh
if (!buf_lv) goto end;
// add new image
weighted_mean_yuv_add_acc32bit_src8bit_ws16bit(buf_acc, buf_lv, buf_ws, numpix);
weighted_mean_yuv_div_dst8bit_src32bit_ws16bit(buf_lv, buf_acc, buf_ws, numpix);
expfuse_num_images++;
bmp_printf(FONT_MED, 0, 0, "%d images ", expfuse_num_images);
//~ bmp_printf(FONT_LARGE, 0, 480 - font_large.height, "Do not press Delete!");
end:
if (buf_acc) free(buf_acc);
if (buf_ws) free(buf_ws);
give_semaphore(set_maindial_sem);
}
void expfuse_preview_update(int dir)
{
task_create("expfuse_task", 0x1c, 0, expfuse_preview_update_task, (void*)dir);
}
#endif
#ifdef FEATURE_PLAY_EXPOSURE_ADJUST
// soft-film curve from ufraw-mod, +/- 1 EV
// a = exposure - 1 (from linear units)
// y = (1 - 1/(1+a*x)) / (1 - 1/(1+a)), x from 0 to 1
static const uint8_t exp_inc[256] = {0x00,0x01,0x03,0x05,0x07,0x09,0x0b,0x0d,0x0f,0x11,0x13,0x15,0x16,0x18,0x1a,0x1c,0x1e,0x1f,0x21,0x23,0x25,0x26,0x28,0x2a,0x2b,0x2d,0x2f,0x30,0x32,0x34,0x35,0x37,0x38,0x3a,0x3c,0x3d,0x3f,0x40,0x42,0x43,0x45,0x46,0x48,0x49,0x4b,0x4c,0x4d,0x4f,0x50,0x52,0x53,0x54,0x56,0x57,0x59,0x5a,0x5b,0x5d,0x5e,0x5f,0x61,0x62,0x63,0x65,0x66,0x67,0x68,0x6a,0x6b,0x6c,0x6d,0x6f,0x70,0x71,0x72,0x73,0x75,0x76,0x77,0x78,0x79,0x7a,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x82,0x83,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0xb3,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb8,0xb9,0xba,0xbb,0xbc,0xbc,0xbd,0xbe,0xbf,0xc0,0xc0,0xc1,0xc2,0xc3,0xc3,0xc4,0xc5,0xc6,0xc6,0xc7,0xc8,0xc9,0xc9,0xca,0xcb,0xcb,0xcc,0xcd,0xce,0xce,0xcf,0xd0,0xd0,0xd1,0xd2,0xd3,0xd3,0xd4,0xd5,0xd5,0xd6,0xd7,0xd7,0xd8,0xd9,0xd9,0xda,0xdb,0xdb,0xdc,0xdd,0xdd,0xde,0xde,0xdf,0xe0,0xe0,0xe1,0xe2,0xe2,0xe3,0xe3,0xe4,0xe5,0xe5,0xe6,0xe6,0xe7,0xe8,0xe8,0xe9,0xe9,0xea,0xeb,0xeb,0xec,0xec,0xed,0xed,0xee,0xef,0xef,0xf0,0xf0,0xf1,0xf1,0xf2,0xf2,0xf3,0xf4,0xf4,0xf5,0xf5,0xf6,0xf6,0xf7,0xf7,0xf8,0xf8,0xf9,0xf9,0xfa,0xfa,0xfb,0xfb,0xfc,0xfc,0xfd,0xfd,0xfe,0xff};
static const uint8_t exp_dec[256] = {0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x15,0x15,0x16,0x16,0x17,0x18,0x18,0x19,0x19,0x1a,0x1b,0x1b,0x1c,0x1c,0x1d,0x1e,0x1e,0x1f,0x20,0x20,0x21,0x21,0x22,0x23,0x23,0x24,0x25,0x25,0x26,0x27,0x27,0x28,0x29,0x29,0x2a,0x2b,0x2b,0x2c,0x2d,0x2e,0x2e,0x2f,0x30,0x30,0x31,0x32,0x32,0x33,0x34,0x35,0x35,0x36,0x37,0x38,0x38,0x39,0x3a,0x3b,0x3b,0x3c,0x3d,0x3e,0x3e,0x3f,0x40,0x41,0x42,0x42,0x43,0x44,0x45,0x46,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8b,0x8c,0x8d,0x8e,0x8f,0x91,0x92,0x93,0x94,0x96,0x97,0x98,0x99,0x9b,0x9c,0x9d,0x9f,0xa0,0xa1,0xa3,0xa4,0xa5,0xa7,0xa8,0xaa,0xab,0xac,0xae,0xaf,0xb1,0xb2,0xb3,0xb5,0xb6,0xb8,0xb9,0xbb,0xbc,0xbe,0xbf,0xc1,0xc3,0xc4,0xc6,0xc7,0xc9,0xca,0xcc,0xce,0xcf,0xd1,0xd3,0xd4,0xd6,0xd8,0xd9,0xdb,0xdd,0xdf,0xe0,0xe2,0xe4,0xe6,0xe8,0xe9,0xeb,0xed,0xef,0xf1,0xf3,0xf5,0xf7,0xf9,0xfb,0xfd,0xff};
// when overexposing, chroma should drop to 0
static const uint8_t chroma_cor[256] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFD,0xFD,0xFD,0xFD,0xFD,0xFD,0xFD,0xFD,0xFD,0xFC,0xFC,0xFC,0xFC,0xFB,0xFB,0xFA,0xFA,0xF9,0xF8,0xF7,0xF5,0xF3,0xEE,0xE6,0xCC,0x70,0x0};
void expo_adjust_playback(int dir)
{
#ifdef CONFIG_5DC
static int expo_value = 0;
if (dir == 0)
{
if (expo_value) EngDrvOut(0xC0F140c0, 0x80);
expo_value = 0; return;
}
expo_value = COERCE(expo_value + dir, -3, 1);
//~ expo_value = expo_value + dir;
NotifyBox(1000, "%s%d", expo_value > 0 ? "+" : "", expo_value);
BmpDDev_take_semaphore();
if (expo_value > 0)
{
EngDrvOut(0xC0F14080, 0xfc0000);
EngDrvOut(0xC0F140c0, 0xFF);
}
else if (expo_value < 0)
{
EngDrvOut(0xC0F14080, 0x1000000 * (-expo_value-1));
EngDrvOut(0xC0F140c0, 0x80);
}
else
{
EngDrvOut(0xC0F14080, 0xfc0000);
EngDrvOut(0xC0F140c0, 0x80);
}
EngDrvOut(0xC0F14078, 1);
BmpDDev_give_semaphore();
#else
ASSERT(set_maindial_sem);
take_semaphore(set_maindial_sem, 0);
uint8_t* current_buf = get_yuv422_vram()->vram;
if (!current_buf) goto end;
int w = get_yuv422_vram()->width;
int h = get_yuv422_vram()->height;
int buf_size = w * h * 2;
for (int i = 0; i < buf_size; i += 4)
{
if (dir > 0)
{
uint8_t* luma1 = ¤t_buf[i+1];
uint8_t* luma2 = ¤t_buf[i+3];
int luma_avg = (*luma1 + *luma2) / 2;
/* if luma is scaled by 1.3, scale chroma by 1.2 */
/* doesn't make any sense, but looks good */
/* if chroma is scaled by the same amount of luma, the colors are often too strong */
/* if scaling by "half" (e.g. 1.15 instead of 1.3), the colors look a bit dull */
int chroma_scaling = (int)((exp_inc[luma_avg] * 2 + luma_avg) / 3) * 1024 / (luma_avg);
// scale luma values individually with the curve LUT
*luma1 = exp_inc[*luma1];
*luma2 = exp_inc[*luma2];
// when overexposing, chroma should drop to 0
luma_avg = (*luma1 + *luma2) / 2;
chroma_scaling = chroma_scaling * (int)chroma_cor[luma_avg] / 256;
int8_t* chroma1 = (int8_t*)¤t_buf[i];
int8_t* chroma2 = (int8_t*)¤t_buf[i+2];
// scale both chroma values with the same factor, to keep the hue unchanged
int chroma1_ex = (int)*chroma1 * chroma_scaling / 1024;
int chroma2_ex = (int)*chroma2 * chroma_scaling / 1024;
// gracefully handle overflow in one chroma channel - if any of them exceeds 127, reduce both of them and keep the ratio unchanged
if (ABS(chroma1_ex) > 127 || ABS(chroma2_ex) > 127)
{
int chroma_max = MAX(ABS(chroma1_ex), ABS(chroma2_ex));
chroma1_ex = chroma1_ex * 127 / chroma_max;
chroma2_ex = chroma2_ex * 127 / chroma_max;
}
*chroma1 = chroma1_ex;
*chroma2 = chroma2_ex;
}
else
{
uint8_t* luma1 = ¤t_buf[i+1];
uint8_t* luma2 = ¤t_buf[i+3];
int luma_avg = (*luma1 + *luma2) / 2;
int chroma_scaling = (int)((exp_dec[luma_avg] * 2 + luma_avg) / 3) * 1024 / (luma_avg);
*luma1 = exp_dec[*luma1];
*luma2 = exp_dec[*luma2];
// chroma scaling for underexposing is simpler - no more overflows to deal with
// but the process is not 100% reversible, although the approximation is pretty good
int8_t* chroma1 = (int8_t*)¤t_buf[i];
int8_t* chroma2 = (int8_t*)¤t_buf[i+2];
*chroma1 = (int)*chroma1 * chroma_scaling / 1024;
*chroma2 = (int)*chroma2 * chroma_scaling / 1024;
}
}
end:
give_semaphore(set_maindial_sem);
#endif
}
#endif
void ensure_movie_mode()
{
#ifdef CONFIG_MOVIE
if (!is_movie_mode())
{
#ifdef CONFIG_50D
GUI_SetLvMode(2);
GUI_SetMovieSize_b(1);
#elif defined(CONFIG_5D2)
GUI_SetLvMode(2);
#else
while (!is_movie_mode())
{
NotifyBox(2000, "Please switch to Movie mode.");
msleep(500);
}
#endif
msleep(500);
}
if (!lv) force_liveview();
#endif
}
void ensure_photo_mode()
{
while (is_movie_mode())
{
NotifyBox(2000, "Please switch to photo mode.");
msleep(500);
}
msleep(500);
}
#ifdef FEATURE_EXPO_ISO
static MENU_UPDATE_FUNC(iso_icon_update)
{
if (lens_info.iso)
MENU_SET_ICON(MNI_PERCENT, (lens_info.raw_iso - codes_iso[1]) * 100 / (codes_iso[COUNT(codes_iso)-1] - codes_iso[1]));
else
MENU_SET_ICON(MNI_AUTO, 0);
}
static MENU_UPDATE_FUNC(iso_display)
{
MENU_SET_VALUE(
"%s",
lens_info.iso ? "" : "Auto"
);
if (lens_info.iso)
{
if (lens_info.raw_iso == lens_info.iso_equiv_raw)
{
MENU_SET_VALUE(
"%d", raw2iso(lens_info.iso_equiv_raw)
);
if (!menu_active_but_hidden())
{
int Sv = APEX_SV(lens_info.iso_equiv_raw) * 10/8;
MENU_SET_RINFO(
"Sv%s%d.%d",
FMT_FIXEDPOINT1(Sv)
);
}
}
else
{
int dg = lens_info.iso_equiv_raw - lens_info.raw_iso;
dg = dg * 10/8;
MENU_SET_VALUE(
"%d",
raw2iso(lens_info.iso_equiv_raw)
);
MENU_SET_RINFO(
"%d,%s%d.%dEV",
raw2iso(lens_info.raw_iso),
FMT_FIXEDPOINT1S(dg)
);
}
}
iso_icon_update(entry, info);
MENU_SET_SHORT_NAME(" "); // obvious from value
}
#endif
int is_native_iso(int iso)
{
switch(iso)
{
case 100:
case 200:
case 400:
case 800:
case 1600:
case 3200:
#if defined(CONFIG_DIGIC_V)
case 6400: // on digic 4, those are digital gains applied to 3200 ISO
case 12800:
case 25600:
#endif
return 1;
}
return 0;
}
int is_lowgain_iso(int iso)
{
switch(iso)
{
case 160: // ISO 200 - 1/3EV
case 320: // ISO 400 - 1/3EV
case 640: // ISO 800 - 1/3EV
case 1250: // ISO 1600 - 1/3EV
case 2500: // ISO 3200 - 1/3EV
#if defined(CONFIG_DIGIC_V)
case 5000:
case 10000:
#endif
return 1;
}
return 0;
}
int is_round_iso(int iso)
{
return is_native_iso(iso) || is_lowgain_iso(iso) || iso == 0
|| iso == 6400 || iso == 12800 || iso == 25600;
}
#ifdef FEATURE_EXPO_ISO
// fixme: these don't work well
static void
analog_iso_toggle( void * priv, int sign )
{
int r = lens_info.raw_iso;
unsigned int a; int d;
split_iso(r, &a, &d);
a = COERCE(a + sign * 8, MIN_ISO, MAX_ANALOG_ISO);
lens_set_rawiso(a + d);
}
static void
digital_iso_toggle( void * priv, int sign )
{
int r = lens_info.raw_iso;
unsigned int a; int d;
split_iso(r, &a, &d);
d = COERCE(d + sign, -3, (a == MAX_ANALOG_ISO ? 16 : 4));
while (d > 8 && d < 16) d += sign;
lens_set_rawiso(a + d);
}
void
iso_toggle( void * priv, int sign )
{
int (*iso_checker)(int) = is_round_iso;
if (is_movie_mode())
{
extern int bv_auto;
if (lens_info.raw_iso && priv != (void*)-1)
if ((lens_info.raw_iso <= MIN_ISO && sign < 0) ||
(lens_info.raw_iso >= (bv_auto ? MAX_ISO_BV : MAX_ISO) && sign > 0))
{
if (lens_set_rawiso(0)) // ISO auto
return;
}
int digic_gain = get_digic_iso_gain_movie();
if (digic_gain != 1024) // keep the DIGIC gain, toggle ISO in full-stops
iso_checker = is_native_iso;
}
int i = raw2index_iso(lens_info.raw_iso);
int i0 = i;
int k;
for (k = 0; k < 10; k++)
{
i = MOD(i + sign, COUNT(codes_iso));
while (!iso_checker(values_iso[i]))
i = MOD(i + sign, COUNT(codes_iso));
if (priv == (void*)-1 && SGN(i - i0) != sign) // wrapped around
break;
if (priv == (void*)-1 && i == 0)
break; // no auto iso allowed from shortcuts
// did Canon accept our ISO? stop here
if (lens_set_rawiso(codes_iso[i]) && lens_info.raw_iso == codes_iso[i])
break;
}
}
#endif // FEATURE_EXPO_ISO
#ifdef FEATURE_EXPO_SHUTTER
static MENU_UPDATE_FUNC(shutter_display)
{
if (is_movie_mode())
{
int s = get_current_shutter_reciprocal_x1000();
int deg = 3600 * fps_get_current_x1000() / s;
deg = (deg + 5) / 10;
MENU_SET_VALUE(
"%s, %d"SYM_DEGREE,
lens_format_shutter_reciprocal(s, 5),
deg);
}
else
{
MENU_SET_VALUE(
"%s",
lens_format_shutter(lens_info.raw_shutter)
);
}
/*
if (is_movie_mode())
{
int xc = x + font_large.width * (strlen(msg) - 1);
draw_circle(xc + 2, y + 7, 3, COLOR_WHITE);
draw_circle(xc + 2, y + 7, 4, COLOR_WHITE);
}
*/
if (!menu_active_but_hidden())
{
int Tv = APEX_TV(lens_info.raw_shutter) * 10/8;
if (lens_info.raw_shutter) MENU_SET_RINFO(
"Tv%s%d.%d",
FMT_FIXEDPOINT1(Tv)
);
}
if (lens_info.raw_shutter)
{
MENU_SET_ICON(MNI_PERCENT, (lens_info.raw_shutter - SHUTTER_MIN) * 100 / (SHUTTER_MAX - SHUTTER_MIN));
MENU_SET_ENABLED(1);
}
else
MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "Shutter speed is automatic - cannot adjust manually.");
MENU_SET_SHORT_NAME(" "); // obvious from value
}
void
shutter_toggle(void* priv, int sign)
{
if (!lens_info.raw_shutter) return;
int i = raw2index_shutter(lens_info.raw_shutter);
int k;
for (k = 0; k < 15; k++)
{
int new_i = i;
new_i = MOD(new_i + sign, COUNT(codes_shutter));
//~ bmp_printf(FONT_MED, 100, 300, "%d -> %d ", codes_shutter[i0], codes_shutter[new_i]);
if (priv == (void*)-1 && (new_i == 0 || i + sign != new_i)) // wrapped around
break;
i = new_i;
if (codes_shutter[i] == 0) continue;
if (is_movie_mode() && codes_shutter[i] < SHUTTER_1_25) { k--; continue; } /* there are many values to skip */
if (lens_set_rawshutter(codes_shutter[i])) break;
}
}
#endif // FEATURE_EXPO_SHUTTER
#ifdef FEATURE_EXPO_APERTURE
static MENU_UPDATE_FUNC(aperture_display)
{
int a = lens_info.aperture;
int av = APEX_AV(lens_info.raw_aperture) * 10/8;
if (!a || !lens_info.name[0]) // for unchipped lenses, always display zero
a = av = 0;
MENU_SET_VALUE(
SYM_F_SLASH"%d.%d",
a / 10,
a % 10,
av / 8,
(av % 8) * 10/8
);
if (!menu_active_but_hidden())
{
if (a) MENU_SET_RINFO(
"Av%s%d.%d",
FMT_FIXEDPOINT1(av)
);
}
if (!lens_info.aperture)
{
MENU_SET_WARNING(MENU_WARN_NOT_WORKING, lens_info.name[0] ? "Aperture is automatic - cannot adjust manually." : "Manual lens - cannot adjust aperture.");
MENU_SET_ICON(MNI_PERCENT_OFF, 0);
}
else
{
MENU_SET_ICON(MNI_PERCENT, (lens_info.raw_aperture - lens_info.raw_aperture_min) * 100 / (lens_info.raw_aperture_max - lens_info.raw_aperture_min));
MENU_SET_ENABLED(1);
}
MENU_SET_SHORT_NAME(" "); // obvious from value
}
void
aperture_toggle( void* priv, int sign)
{
if (!lens_info.name[0]) return; // only chipped lenses can change aperture
if (!lens_info.raw_aperture) return;
int amin = codes_aperture[1];
int amax = codes_aperture[COUNT(codes_aperture)-1];
int a = lens_info.raw_aperture;
for (int k = 0; k < 4; k++)
{
do {
a += sign;
if (priv == (void*)-1) // don't wrap around
{
if (a > amax) { a = amax; break; }
if (a < amin) { a = amin; break; }
}
else // allow wrap around
{
if (a > amax) a = amin;
if (a < amin) a = amax;
}
if (lens_info.raw_aperture_min >= lens_info.raw_aperture_max) break;
}
while (a < lens_info.raw_aperture_min || a > lens_info.raw_aperture_max);
if (lens_set_rawaperture(a)) break;
}
}
#endif
#ifdef FEATURE_WHITE_BALANCE
void kelvin_toggle( void* priv, int sign )
{
int k;
switch (lens_info.wb_mode)
{
case WB_SUNNY: k = 5200; break;
case WB_SHADE: k = 7000; break;
case WB_CLOUDY: k = 6000; break;
case WB_TUNGSTEN: k = 3200; break;
case WB_FLUORESCENT: k = 4000; break;
case WB_FLASH: k = 6500; break; // maybe?
default: k = lens_info.kelvin;
}
int step = KELVIN_STEP;
if (k + sign * step > 7000)
step *= 5;
k = (k/step) * step;
if (priv == (void*)-1) // no wrap around
k = COERCE(k + sign * step, KELVIN_MIN, KELVIN_MAX);
else // allow wrap around
k = KELVIN_MIN + MOD(k - KELVIN_MIN + sign * step, KELVIN_MAX - KELVIN_MIN + step);
lens_set_kelvin(k);
}
PROP_INT( PROP_WB_KELVIN_PH, wb_kelvin_ph );
static MENU_UPDATE_FUNC(kelvin_display)
{
if (lens_info.wb_mode == WB_KELVIN)
{
MENU_SET_VALUE(
"%dK",
lens_info.kelvin
);
MENU_SET_ICON(MNI_PERCENT, (lens_info.kelvin - KELVIN_MIN) * 100 / (KELVIN_MAX - KELVIN_MIN));
if (lens_info.kelvin != wb_kelvin_ph)
MENU_SET_WARNING(MENU_WARN_ADVICE, "Extended WB values are only applied to movies, not photos.");
}
else
{
MENU_SET_VALUE(
uniwb_is_active() ? "UniWB" :
lens_info.wb_mode == 0 ? "Auto" :
lens_info.wb_mode == 1 ? "Sunny" :
lens_info.wb_mode == 2 ? "Cloudy" :
lens_info.wb_mode == 3 ? "Tungsten":
lens_info.wb_mode == 4 ? "Fluor." :
lens_info.wb_mode == 5 ? "Flash" :
lens_info.wb_mode == 6 ? "Custom" :
lens_info.wb_mode == 8 ? "Shade" :
"unknown"
);
MENU_SET_ICON(MNI_AUTO, 0);
}
}
static MENU_UPDATE_FUNC(kelvin_wbs_display)
{
kelvin_display(entry, info);
if (lens_info.wbs_gm)
{
MENU_APPEND_RINFO(
" %s%d",
lens_info.wbs_gm > 0 ? "G" : "M", ABS(lens_info.wbs_gm)
);
}
if (lens_info.wbs_ba)
{
MENU_APPEND_RINFO(
" %s%d",
lens_info.wbs_ba > 0 ? "A" : "B", ABS(lens_info.wbs_ba)
);
}
MENU_SET_SHORT_NAME(" "); // obvious from value
MENU_SET_SHORT_VALUE("%s%s", info->value, info->rinfo); // squeeze both on the same field
}
static int kelvin_auto_flag = 0;
static int wbs_gm_auto_flag = 0;
static void kelvin_auto()
{
if (lv) kelvin_auto_flag = 1;
}
static void wbs_gm_auto()
{
if (lv) wbs_gm_auto_flag = 1;
}
void kelvin_n_gm_auto()
{
if (lv)
{
kelvin_auto_flag = 1;
wbs_gm_auto_flag = 1;
}
}
static MENU_UPDATE_FUNC(wb_custom_gain_display)
{
int p = (intptr_t) entry->priv;
int raw_value =
p==1 ? lens_info.WBGain_R :
p==2 ? lens_info.WBGain_G :
lens_info.WBGain_B ;
int multiplier = 1000 * 1024 / raw_value;
MENU_SET_NAME(
"%s multiplier",
p==1 ? "R" : p==2 ? "G" : "B"
);
MENU_SET_VALUE(
"%d.%03d",
multiplier/1000, multiplier%1000
);
if (lens_info.wb_mode != WB_CUSTOM)
MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "Custom white balance is not active => not used.");
int ll = log_length(125);
int lh = log_length(8000);
int l = log_length(raw_value);
MENU_SET_ICON(MNI_PERCENT, (l-lh) * 100 / (ll-lh));
}
static void
wb_custom_gain_toggle( void * priv, int delta )
{
int p = (intptr_t) priv;
int deltaR = p == 1 ? -delta * 16 * MAX(1, lens_info.WBGain_R/1024) : 0;
int deltaG = p == 2 ? -delta * 16 * MAX(1, lens_info.WBGain_G/1024) : 0;
int deltaB = p == 3 ? -delta * 16 * MAX(1, lens_info.WBGain_B/1024) : 0;
lens_set_custom_wb_gains(lens_info.WBGain_R + deltaR, lens_info.WBGain_G + deltaG, lens_info.WBGain_B + deltaB);
}
static int crit_kelvin(int k)
{
if (!lv) return 0;
if (k > 0)
{
lens_set_kelvin(k * KELVIN_STEP);
msleep(750);
}
int Y, U, V;
get_spot_yuv(100, &Y, &U, &V);
int R,G,B;
yuv2rgb(Y,U,V,&R,&G,&B);
NotifyBox(5000, "Adjusting white balance...");
return B - R;
}
static int crit_wbs_gm(int k)
{
if (!lv) return 0;
k = COERCE(k, -10, 10);
lens_set_wbs_gm(k);
msleep(750);
int Y, U, V;
get_spot_yuv(100, &Y, &U, &V);
int R,G,B;
yuv2rgb(Y,U,V,&R,&G,&B);
NotifyBox(5000, "Adjusting white balance shift...");
//~ BMP_LOCK( draw_ml_bottombar(0,0); )
return (R+B)/2 - G;
}
static void kelvin_auto_run()
{
if (EXT_MONITOR_RCA) { NotifyBox(2000, "Not working on SD monitors."); return; }
gui_stop_menu();
int c0 = crit_kelvin(-1); // test current kelvin
int i;
if (c0 > 0) i = bin_search(lens_info.kelvin/KELVIN_STEP, KELVIN_MAX/KELVIN_STEP + 1, crit_kelvin);
else i = bin_search(KELVIN_MIN/KELVIN_STEP, lens_info.kelvin/KELVIN_STEP + 1, crit_kelvin);
lens_set_kelvin(i * KELVIN_STEP);
//~ NotifyBoxHide();
//~ redraw();
}
static void wbs_gm_auto_run()
{
if (EXT_MONITOR_RCA) { NotifyBox(2000, "Not working on SD monitors."); return; }
gui_stop_menu();
int c0 = crit_wbs_gm(100); // test current value
int i;
if (c0 > 0) i = bin_search(lens_info.wbs_gm, 10, crit_wbs_gm);
else i = bin_search(-9, lens_info.wbs_gm + 1, crit_wbs_gm);
lens_set_wbs_gm(i);
NotifyBoxHide();
redraw();
}
static MENU_UPDATE_FUNC(wbs_gm_display)
{
int gm = lens_info.wbs_gm;
MENU_SET_VALUE(
"%s%d",
gm > 0 ? "Green " : (gm < 0 ? "Magenta " : ""),
ABS(gm)
);
MENU_SET_ENABLED(gm);
if (gm) MENU_SET_ICON(MNI_PERCENT_ALLOW_OFF, (-gm+9) * 100 / 18);
else MENU_SET_ICON(MNI_PERCENT_OFF, 50);
}
static void
wbs_gm_toggle( void * priv, int sign )
{
int gm = lens_info.wbs_gm;
int newgm = MOD((gm + 9 - sign), 19) - 9;
newgm = newgm & 0xFF;
prop_request_change(PROP_WBS_GM, &newgm, 4);
}
static MENU_UPDATE_FUNC(wbs_ba_display)
{
int ba = lens_info.wbs_ba;
MENU_SET_VALUE(
"%s%d",
ba > 0 ? "Amber " : (ba < 0 ? "Blue " : ""),
ABS(ba)
);
MENU_SET_ENABLED(ba);
if (ba) MENU_SET_ICON(MNI_PERCENT_ALLOW_OFF, (ba+9) * 100 / 18);
else MENU_SET_ICON(MNI_PERCENT_OFF, 50);
}
static void
wbs_ba_toggle( void * priv, int sign )
{
int ba = lens_info.wbs_ba;
int newba = MOD((ba + 9 + sign), 19) - 9;
newba = newba & 0xFF;
prop_request_change(PROP_WBS_BA, &newba, 4);
}
#endif
#ifdef FEATURE_PICSTYLE
static void
contrast_toggle( void * priv, int sign )
{
int c = lens_get_contrast();
if (c < -4 || c > 4) return;
int newc = MOD((c + 4 + sign), 9) - 4;
lens_set_contrast(newc);
}
static MENU_UPDATE_FUNC(contrast_display)
{
int s = lens_get_contrast();
MENU_SET_VALUE(
"%d",
s
);
MENU_SET_ICON(MNI_PERCENT, (s+4) * 100 / 8);
}
static void
sharpness_toggle( void * priv, int sign )
{
int c = lens_get_sharpness();
if (c < 0 || c > 7) return;
int newc = MOD(c + sign, 8);
lens_set_sharpness(newc);
}
static MENU_UPDATE_FUNC(sharpness_display)
{
int s = lens_get_sharpness();
MENU_SET_VALUE(
"%d ",
s
);
MENU_SET_ICON(MNI_PERCENT, s * 100 / 7);
}
static void
saturation_toggle( void * priv, int sign )
{
int c = lens_get_saturation();
if (c < -4 || c > 4) return;
int newc = MOD((c + 4 + sign), 9) - 4;
lens_set_saturation(newc);
}
static MENU_UPDATE_FUNC(saturation_display)
{
int s = lens_get_saturation();
int ok = (s >= -4 && s <= 4);
MENU_SET_VALUE(
ok ?
"%d " :
"N/A",
s
);
MENU_SET_ENABLED(ok);
if (ok) MENU_SET_ICON(MNI_PERCENT, (s+4) * 100 / 8);
else { MENU_SET_ICON(MNI_OFF, 0); MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "N/A"); }
}
static void
color_tone_toggle( void * priv, int sign )
{
int c = lens_get_color_tone();
if (c < -4 || c > 4) return;
int newc = MOD((c + 4 + sign), 9) - 4;
lens_set_color_tone(newc);
}
static MENU_UPDATE_FUNC(color_tone_display)
{
int s = lens_get_color_tone();
int ok = (s >= -4 && s <= 4);
MENU_SET_VALUE(
ok ?
"%d " :
"N/A",
s
);
MENU_SET_ENABLED(ok);
if (ok) MENU_SET_ICON(MNI_PERCENT, (s+4) * 100 / 8);
else { MENU_SET_ICON(MNI_OFF, 0); MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "N/A"); }
}
static CONFIG_INT("picstyle.rec", picstyle_rec, 0);
static int picstyle_before_rec = 0; // if you use a custom picstyle during REC, the old one will be saved here
static char user_picstyle_name_1[50] = "";
static char user_picstyle_name_2[50] = "";
static char user_picstyle_name_3[50] = "";
static char user_picstyle_shortname_1[10] = "";
static char user_picstyle_shortname_2[10] = "";
static char user_picstyle_shortname_3[10] = "";
static void copy_picstyle_name(char* fullname, char* shortname, char* name)
{
snprintf(fullname, 50, "%s", name);
// CineStyle => CineS
// Flaat_10p => Fl10p
// Flaat_2 => Flaa2
// Flaat03 => Fla03
int L = strlen(name);
shortname[0] = name[0];
shortname[1] = name[1];
shortname[2] = name[2];
shortname[3] = name[3];
shortname[4] = name[4];
shortname[5] = '\0';
if (isdigit(name[L-3]))
shortname[2] = name[L-3];
if (isdigit(name[L-3]) || isdigit(name[L-2]))
shortname[3] = name[L-2];
if (isdigit(name[L-3]) || isdigit(name[L-2]) || isdigit(name[L-1]))
shortname[4] = name[L-1];
}
PROP_HANDLER(PROP_PC_FLAVOR1_PARAM)
{
copy_picstyle_name(user_picstyle_name_1, user_picstyle_shortname_1, (char*) buf + 4);
}
PROP_HANDLER(PROP_PC_FLAVOR2_PARAM)
{
copy_picstyle_name(user_picstyle_name_2, user_picstyle_shortname_2, (char*) buf + 4);
}
PROP_HANDLER(PROP_PC_FLAVOR3_PARAM)
{
copy_picstyle_name(user_picstyle_name_3, user_picstyle_shortname_3, (char*) buf + 4);
}
static PROP_INT(PROP_PICSTYLE_OF_USERDEF1, picstyle_of_user1);
static PROP_INT(PROP_PICSTYLE_OF_USERDEF2, picstyle_of_user2);
static PROP_INT(PROP_PICSTYLE_OF_USERDEF3, picstyle_of_user3);
const char* get_picstyle_name(int raw_picstyle)
{
return
raw_picstyle == 0x81 ? "Standard" :
raw_picstyle == 0x82 ? "Portrait" :
raw_picstyle == 0x83 ? "Landscape" :
raw_picstyle == 0x84 ? "Neutral" :
raw_picstyle == 0x85 ? "Faithful" :
raw_picstyle == 0x86 ? "Monochrome" :
raw_picstyle == 0x87 ? "Auto" :
raw_picstyle == 0x21 ? (picstyle_of_user1 < 0x80 ? user_picstyle_name_1 : "UserDef1") :
raw_picstyle == 0x22 ? (picstyle_of_user2 < 0x80 ? user_picstyle_name_2 : "UserDef2") :
raw_picstyle == 0x23 ? (picstyle_of_user3 < 0x80 ? user_picstyle_name_3 : "UserDef3") :
"Unknown";
}
const char* get_picstyle_shortname(int raw_picstyle)
{
return
raw_picstyle == 0x81 ? "Std." :
raw_picstyle == 0x82 ? "Port." :
raw_picstyle == 0x83 ? "Land." :
raw_picstyle == 0x84 ? "Neut." :
raw_picstyle == 0x85 ? "Fait." :
raw_picstyle == 0x86 ? "Mono." :
raw_picstyle == 0x87 ? "Auto" :
raw_picstyle == 0x21 ? (picstyle_of_user1 < 0x80 ? user_picstyle_shortname_1 : "User1") :
raw_picstyle == 0x22 ? (picstyle_of_user2 < 0x80 ? user_picstyle_shortname_2 : "User2") :
raw_picstyle == 0x23 ? (picstyle_of_user3 < 0x80 ? user_picstyle_shortname_3 : "User3") :
"Unk.";
}
static MENU_UPDATE_FUNC(picstyle_display)
{
int i = picstyle_rec && RECORDING ? picstyle_before_rec : (int)lens_info.picstyle;
MENU_SET_VALUE(
get_picstyle_name(get_prop_picstyle_from_index(i))
);
if (picstyle_rec && is_movie_mode())
{
MENU_SET_RINFO(
"REC:%s",
get_picstyle_name(get_prop_picstyle_from_index(picstyle_rec))
);
}
else MENU_SET_RINFO(
"%d,%d,%d,%d",
lens_get_from_other_picstyle_sharpness(i),
lens_get_from_other_picstyle_contrast(i),
ABS(lens_get_from_other_picstyle_saturation(i)) < 10 ? lens_get_from_other_picstyle_saturation(i) : 0,
ABS(lens_get_from_other_picstyle_color_tone(i)) < 10 ? lens_get_from_other_picstyle_color_tone(i) : 0
);
MENU_SET_ENABLED(1);
}
static MENU_UPDATE_FUNC(picstyle_display_submenu)
{
int p = get_prop_picstyle_from_index(lens_info.picstyle);
MENU_SET_VALUE(
"%s",
get_picstyle_name(p)
);
MENU_SET_ENABLED(1);
}
static void
picstyle_toggle(void* priv, int sign )
{
if (RECORDING) return;
int p = lens_info.picstyle;
p = MOD(p + sign - 1, NUM_PICSTYLES) + 1;
if (p)
{
p = get_prop_picstyle_from_index(p);
prop_request_change(PROP_PICTURE_STYLE, &p, 4);
}
}
#ifdef FEATURE_REC_PICSTYLE
static MENU_UPDATE_FUNC(picstyle_rec_sub_display)
{
if (!picstyle_rec)
{
MENU_SET_VALUE("OFF");
return;
}
MENU_SET_VALUE(
get_picstyle_name(get_prop_picstyle_from_index(picstyle_rec))
);
//~ MENU_SET_RINFO(
if (info->can_custom_draw) bmp_printf(MENU_FONT_GRAY, info->x_val, info->y + font_large.height,
"%d,%d,%d,%d",
lens_get_from_other_picstyle_sharpness(picstyle_rec),
lens_get_from_other_picstyle_contrast(picstyle_rec),
ABS(lens_get_from_other_picstyle_saturation(picstyle_rec)) < 10 ? lens_get_from_other_picstyle_saturation(picstyle_rec) : 0,
ABS(lens_get_from_other_picstyle_color_tone(picstyle_rec)) < 10 ? lens_get_from_other_picstyle_color_tone(picstyle_rec) : 0
);
}
static void
picstyle_rec_sub_toggle( void * priv, int delta )
{
if (RECORDING) return;
picstyle_rec = MOD(picstyle_rec+ delta, NUM_PICSTYLES+1);
}
static void rec_picstyle_change(int rec)
{
static int prev = -1;
if (picstyle_rec)
{
if (prev == 0 && rec) // will start recording
{
picstyle_before_rec = lens_info.picstyle;
int p = get_prop_picstyle_from_index(picstyle_rec);
if (p)
{
NotifyBox(2000, "Picture Style : %s", get_picstyle_name(p));
prop_request_change(PROP_PICTURE_STYLE, &p, 4);
}
}
else if (prev == 2 && rec == 0) // recording => will stop
{
int p = get_prop_picstyle_from_index(picstyle_before_rec);
if (p)
{
NotifyBox(2000, "Picture Style : %s", get_picstyle_name(p));
prop_request_change(PROP_PICTURE_STYLE, &p, 4);
}
picstyle_before_rec = 0;
}
}
prev = rec;
}
#endif // REC pic style
#endif // pic style
/* to be refactored with CBR */
extern void rec_notify_trigger(int rec);
#ifdef CONFIG_50D
PROP_HANDLER(PROP_SHOOTING_TYPE)
{
/* there might be a false trigger at startup - issue #1992 */
extern int ml_started;
if (!ml_started) return;
int rec = (shooting_type == 4 ? 2 : 0);
#ifdef FEATURE_REC_NOTIFY
rec_notify_trigger(rec);
#endif
#ifdef FEATURE_REC_PICSTYLE
rec_picstyle_change(rec);
#endif
#ifdef CONFIG_MOVIE_RECORDING_50D_SHUTTER_HACK
extern void shutter_btn_rec_do(int rec); /* movtweaks.c */
shutter_btn_rec_do(rec);
#endif
}
void mvr_rec_start_shoot(){}
#else
void mvr_rec_start_shoot(int rec)
{
#ifdef FEATURE_REC_NOTIFY
rec_notify_trigger(rec);
#endif
#ifdef FEATURE_REC_PICSTYLE
rec_picstyle_change(rec);
#endif
}
#endif
#ifdef FEATURE_FLASH_TWEAKS
static void
flash_ae_toggle(void* priv, int sign )
{
int ae = lens_info.flash_ae;
int newae = ae + sign * (ABS(ae + sign) <= 24 ? 4 : 8);
lens_set_flash_ae(newae);
}
static MENU_UPDATE_FUNC(flash_ae_display)
{
int ae_ev = (lens_info.flash_ae) * 10 / 8;
MENU_SET_VALUE(
"%s%d.%d EV",
FMT_FIXEDPOINT1S(ae_ev)
);
MENU_SET_ENABLED(ae_ev);
}
#endif
#ifdef FEATURE_EXPO_ISO_HTP
static void
htp_toggle( void * priv )
{
int htp = get_htp();
if (htp)
set_htp(0);
else
set_htp(1);
}
static MENU_UPDATE_FUNC(htp_display)
{
int htp = get_htp();
MENU_SET_VALUE(htp ? "ON" : "OFF");
MENU_SET_ENABLED(htp);
}
#endif
#ifdef FEATURE_LV_ZOOM_SETTINGS
static void zoom_x5_x10_toggle(void* priv, int delta)
{
*(int*)priv = ! *(int*)priv;
if (zoom_disable_x5 && zoom_disable_x10) // can't disable both at the same time
{
if (priv == &zoom_disable_x5) zoom_disable_x10 = 0;
else zoom_disable_x5 = 0;
}
}
static void zoom_halfshutter_step()
{
#ifdef CONFIG_LIVEVIEW
if (!lv) return;
if (RECORDING) return;
if (zoom_halfshutter && is_manual_focus())
{
int hs = get_halfshutter_pressed();
if (hs && lv_dispsize == 1 && display_idle())
{
#ifdef CONFIG_ZOOM_HALFSHUTTER_UILOCK
msleep(500);
#else
msleep(50);
#endif
int hs2 = get_halfshutter_pressed();
if (hs2 && lv && lv_dispsize == 1 && display_idle())
{
zoom_was_triggered_by_halfshutter = 1;
int zoom = zoom_disable_x10 ? 5 : 10;
set_lv_zoom(zoom);
}
}
if (!hs && lv_dispsize > 1 && zoom_was_triggered_by_halfshutter)
{
zoom_was_triggered_by_halfshutter = 0;
set_lv_zoom(1);
}
}
#endif
}
static int zoom_focus_ring_disable_time = 0;
static int zoom_focus_ring_flag = 0;
void zoom_focus_ring_trigger() // called from prop handler
{
if (RECORDING) return;
if (lv_dispsize > 1) return;
if (gui_menu_shown()) return;
if (!DISPLAY_IS_ON) return;
int zfr = (zoom_focus_ring == 1 && is_manual_focus());
if (!zfr) return;
zoom_focus_ring_flag = 1;
}
void zoom_focus_ring_engage() // called from shoot_task
{
if (RECORDING) return;
if (lv_dispsize > 1) return;
if (gui_menu_shown()) return;
if (!DISPLAY_IS_ON) return;
int zfr = (zoom_focus_ring && is_manual_focus());
if (!zfr) return;
zoom_focus_ring_disable_time = miliseconds_clock + 5000;
int zoom = zoom_disable_x10 ? 5 : 10;
set_lv_zoom(zoom);
}
static void zoom_focus_ring_step()
{
int zfr = (zoom_focus_ring && is_manual_focus());
if (!zfr) return;
if (RECORDING) return;
if (!DISPLAY_IS_ON) return;
if (zoom_focus_ring_disable_time && miliseconds_clock > zoom_focus_ring_disable_time && !get_halfshutter_pressed())
{
if (lv_dispsize > 1) set_lv_zoom(1);
zoom_focus_ring_disable_time = 0;
}
}
/*
int zoom_x5_x10_step()
{
if (zoom_disable_x5 && lv_dispsize == 5)
{
set_lv_zoom(10);
return 1;
}
if (zoom_disable_x10 && lv_dispsize == 10)
{
set_lv_zoom(1);
return 1;
}
return 0;
}*/
int handle_zoom_x5_x10(struct event * event)
{
if (!lv) return 1;
if (RECORDING) return 1;
if (!zoom_disable_x5 && !zoom_disable_x10) return 1;
#ifdef CONFIG_600D
if (get_disp_pressed()) return 1;
#endif
if (event->param == BGMT_PRESS_ZOOMIN_MAYBE && liveview_display_idle() && !gui_menu_shown())
{
set_lv_zoom(lv_dispsize > 1 ? 1 : zoom_disable_x5 ? 10 : 5);
return 0;
}
return 1;
}
// called from some prop_handlers (shoot.c and zebra.c)
void zoom_sharpen_step()
{
#ifdef FEATURE_LV_ZOOM_SHARP_CONTRAST
if (!zoom_sharpen) return;
static int co = 100;
static int sa = 100;
static int sh = 100;
if (zoom_sharpen && lv && lv_dispsize > 1 && (!HALFSHUTTER_PRESSED || zoom_was_triggered_by_halfshutter) && !gui_menu_shown()) // bump contrast/sharpness
{
if (co == 100)
{
co = lens_get_contrast();
sh = lens_get_sharpness();
sa = lens_get_saturation();
lens_set_contrast(4);
lens_set_sharpness(7);
lens_set_saturation(MAX(0, sa));
}
}
else // restore contrast/sharpness
{
if (co < 100)
{
lens_set_contrast(co);
lens_set_sharpness(sh);
lens_set_saturation(sa);
co = sa = sh = 100;
}
}
#endif
}
#ifdef CONFIG_EXPSIM
static void restore_expsim(int es)
{
for (int i = 0; i < 50; i++)
{
lens_wait_readytotakepic(64);
set_expsim(es);
msleep(300);
if (get_expsim() == es) return;
}
NotifyBox(5000, "Could not restore ExpSim :(");
info_led_blink(5, 50, 50);
}
#endif
// to be called from shoot_task
static void zoom_auto_exposure_step()
{
#ifdef FEATURE_LV_ZOOM_AUTO_EXPOSURE
if (!zoom_auto_exposure) return;
static int es = -1;
// static int aem = -1;
if (lv && lv_dispsize > 1 && !gui_menu_shown())
{
// photo mode: disable ExpSim
// movie mode 5D2: disable ExpSim
// movie mode small cams: not working (changing PROP_AE_MODE_MOVIE causes issues)
// note: turning off the tweak on half-shutter interferes with autofocus
if (is_movie_mode())
{
#ifdef CONFIG_5D2
if (es == -1)
{
es = get_expsim();
set_expsim(0);
}
/* #else // unstable
#ifndef CONFIG_50D
if (aem == -1)
{
aem = ae_mode_movie;
int x = 0;
prop_request_change(PROP_AE_MODE_MOVIE, &x, 4);
}
#endif */
#endif
}
else // photo mode
{
if (es == -1)
{
es = get_expsim();
set_expsim(0);
}
}
}
else // restore things back
{
if (es >= 0)
{
restore_expsim(es);
es = -1;
}
/* if (aem >= 0)
{
prop_request_change(PROP_AE_MODE_MOVIE, &aem, 4);
aem = -1;
}*/
}
#endif
}
#endif // FEATURE_LV_ZOOM_SETTINGS
#ifdef FEATURE_HDR_BRACKETING
static MENU_UPDATE_FUNC(hdr_check_excessive_settings)
{
char what[10] = "";
if (hdr_steps > 7)
{
snprintf(what, sizeof(what), "%d frames", hdr_steps);
}
else if (hdr_stepsize < 8 && hdr_steps > 5)
{
snprintf(what, sizeof(what), "0.5 EV", hdr_steps);
}
if (what[0])
{
MENU_SET_WARNING(MENU_WARN_ADVICE, "%s unnecessary and may cause excessive shutter wear.", what);
}
}
static MENU_UPDATE_FUNC(hdr_display)
{
if (!hdr_enabled)
{
MENU_SET_VALUE("OFF");
}
else
{
// trick: when steps=1 (auto) it will display A :)
char hdr_steps_str[10];
if(hdr_steps == 1)
{
snprintf(hdr_steps_str, 10, "%s", "A");
}
else
{
snprintf(hdr_steps_str, 10, "%d", hdr_steps);
}
MENU_SET_VALUE("%s%sx%d%sEV",
hdr_type == 0 ? "" : hdr_type == 1 ? "F " : "DOF ",
hdr_steps_str,
hdr_stepsize / 8,
((hdr_stepsize/4) % 2) ? ".5" : ""
);
MENU_SET_RINFO("%s%s%s",
hdr_sequence == 0 ? "0--" : hdr_sequence == 1 ? "0-+" : "0++",
hdr_delay ? ", 2s" : "",
hdr_iso == 1 ? ", ISO" : hdr_iso == 2 ? ", iso" : ""
);
}
if (aeb_setting)
{
MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "Turn off Canon bracketing (AEB)!");
}
hdr_check_excessive_settings(entry, info);
}
static MENU_UPDATE_FUNC(hdr_steps_update)
{
if(hdr_steps <= 1)
{
MENU_SET_VALUE("Autodetect");
}
else
{
MENU_SET_VALUE("%d", hdr_steps);
if (shooting_mode == SHOOTMODE_M && hdr_type == 0 && hdr_iso == 0)
{
int hdr_sequence_calc = 0;
int hdr_sequence_calc_old = 0;
int hdr_sequence_calc1 = 0;
int hdr_sequence_calc_shutter = 0;
#ifdef CONFIG_BULB
if(is_bulb_mode())
{
hdr_sequence_calc_shutter = shutter_ms_to_raw(bulb_duration*1000);
}
else
#endif
{
hdr_sequence_calc_shutter = lens_info.raw_shutter;
}
if (hdr_sequence == 0)
{
hdr_sequence_calc = hdr_sequence_calc_shutter + (hdr_stepsize*(hdr_steps-1));
}
else if (hdr_sequence == 1)
{
if (hdr_steps % 2 != 0)
{
hdr_sequence_calc = hdr_sequence_calc_shutter + (hdr_stepsize*(hdr_steps-1)/2);
hdr_sequence_calc1 = hdr_sequence_calc_shutter - (hdr_stepsize*(hdr_steps-1)/2);
}
else
{
hdr_sequence_calc = hdr_sequence_calc_shutter + (hdr_stepsize*(hdr_steps)/2);
hdr_sequence_calc1 = hdr_sequence_calc_shutter - (hdr_stepsize*(hdr_steps-2)/2);
}
}
else if (hdr_sequence == 2)
{
hdr_sequence_calc = hdr_sequence_calc_shutter - (hdr_stepsize*(hdr_steps-1));
}
hdr_sequence_calc_old = hdr_sequence_calc;
if (hdr_sequence_calc > FASTEST_SHUTTER_SPEED_RAW)
{
hdr_sequence_calc = FASTEST_SHUTTER_SPEED_RAW;
}
char hdr_sequence_calc_char[32];
char hdr_sequence_calc_char1[32];
if (hdr_sequence == 1 && hdr_steps != 2)
{
snprintf(hdr_sequence_calc_char, sizeof(hdr_sequence_calc_char), "%s", lens_format_shutter(hdr_sequence_calc1));
snprintf(hdr_sequence_calc_char1, sizeof(hdr_sequence_calc_char1), "%s", lens_format_shutter(hdr_sequence_calc));
}
else
{
snprintf(hdr_sequence_calc_char, sizeof(hdr_sequence_calc_char), "%s", lens_format_shutter(hdr_sequence_calc_shutter));
snprintf(hdr_sequence_calc_char1, sizeof(hdr_sequence_calc_char1), "%s", lens_format_shutter(hdr_sequence_calc));
}
if (hdr_sequence_calc_old > FASTEST_SHUTTER_SPEED_RAW)
{
MENU_SET_RINFO("%s ... %sE", hdr_sequence_calc_char, hdr_sequence_calc_char1);
}
else
{
MENU_SET_RINFO("%s ... %s", hdr_sequence_calc_char, hdr_sequence_calc_char1);
}
}
}
hdr_check_excessive_settings(entry, info);
}
// 0,4,8,12,16, 24, 32, 40
static MENU_SELECT_FUNC(hdr_stepsize_toggle)
{
int h = hdr_stepsize;
delta *= (h+delta < 16 ? 4 : 8);
h += delta;
// Why not COERCE()? Because we need to wrap the value around
if (h > HDR_STEPSIZE_MAX) h = HDR_STEPSIZE_MIN;
if (h < HDR_STEPSIZE_MIN) h = HDR_STEPSIZE_MAX;
hdr_stepsize = h;
}
#endif
int is_bulb_mode()
{
#ifdef CONFIG_BULB
if (shooting_mode == SHOOTMODE_BULB) return 1;
if (shooting_mode != SHOOTMODE_M) return 0;
if (lens_info.raw_shutter != 0xC) return 0;
return 1;
#else
return 0;
#endif
}
void ensure_bulb_mode()
{
#ifdef CONFIG_BULB
while (lens_info.job_state) msleep(100);
#ifdef CONFIG_SEPARATE_BULB_MODE
int a = lens_info.raw_aperture;
set_shooting_mode(SHOOTMODE_BULB);
if (get_expsim() == 2) set_expsim(1);
lens_set_rawaperture(a);
#else
if (shooting_mode != SHOOTMODE_M)
set_shooting_mode(SHOOTMODE_M);
int shutter = SHUTTER_BULB;
prop_request_change( PROP_SHUTTER, &shutter, 4 );
prop_request_change( PROP_SHUTTER_AUTO, &shutter, 4 ); /* todo: is this really needed? */
#endif
SetGUIRequestMode(0);
while (!display_idle()) msleep(100);
#endif
}
// returns old drive mode if changed, -1 if nothing changed
int set_drive_single()
{
if (drive_mode != DRIVE_SINGLE
#ifdef DRIVE_SILENT
&& drive_mode != DRIVE_SILENT
#endif
)
{
int orig_mode = drive_mode;
#ifdef DRIVE_SILENT
lens_set_drivemode(DRIVE_SILENT);
#else
lens_set_drivemode(DRIVE_SINGLE);
#endif
return orig_mode;
}
return -1;
}
// goes to Bulb mode and takes a pic with the specified duration (ms)
// returns nonzero if user canceled, zero otherwise
int
bulb_take_pic(int duration)
{
int canceled = 0;
#ifdef CONFIG_BULB
extern int ml_taking_pic;
if (ml_taking_pic) return 1;
ml_taking_pic = 1;
//~ NotifyBox(2000, "Bulb: %d ", duration); msleep(2000);
duration = MAX(duration, BULB_MIN_EXPOSURE) + BULB_EXPOSURE_CORRECTION;
int s0r = lens_info.raw_shutter; // save settings (for restoring them back)
int m0r = shooting_mode;
ensure_bulb_mode();
lens_setup_af(AF_DISABLE);
msleep(100);
int d0 = -1;
int initial_delay = 300;
switch (drive_mode)
{
case DRIVE_SELFTIMER_2SEC:
duration += 2000;
initial_delay = 2000;
break;
case DRIVE_SELFTIMER_REMOTE:
duration += 10000;
initial_delay = 10000;
break;
default:
d0 = set_drive_single();
mlu_lock_mirror_if_needed();
}
//~ NotifyBox(3000, "BulbStart (%d)", duration); msleep(1000);
SW1(1,300);
int t_start = get_ms_clock_value();
int t_end = t_start + duration;
SW2(1, initial_delay);
#ifdef FEATURE_BULB_TIMER_SHOW_PREVIOUS_PIC
int display_forced_on = 0;
#endif
//~ msleep(duration);
//int d = duration/1000;
while (get_ms_clock_value() <= t_end - 1500)
{
msleep(100);
// number of seconds that passed
static int prev_s = 0;
int s = (get_ms_clock_value() - t_start) / 1000;
if (s == prev_s) continue;
prev_s = s;
// check the following at every second:
if (bulb_display_mode == 1)
{
/* for 550D and other cameras that may keep the display on during bulb exposures -> turn it off */
if (DISPLAY_IS_ON && s==1) fake_simple_button(BGMT_INFO);
}
#ifdef FEATURE_BULB_TIMER_SHOW_PREVIOUS_PIC
else if (bulb_display_mode == 2)
{
/* remaining time */
int r = duration/1000 - s;
if (s == 2 && r > 3)
{
/* turn off the display at the beginning of the exposure */
/* not too early, since it may get stuck */
/* also, no point in turning it on for very short exposures */
display_on();
display_forced_on = 1;
}
else if (r == 2 && display_forced_on)
{
/* don't forget to turn it off at the end, because Canon firmware expects it this way */
/* note: this loop ends at 1.5s, so you can't use r==1 */
display_off();
}
if (DISPLAY_IS_ON)
{
clrscr();
bmp_printf(FONT_LARGE, 50, 50, "Remaining: %d", r);
#ifdef FEATURE_INTERVALOMETER
if(intervalometer_running)
{
static char msg[60];
snprintf(msg, sizeof(msg),
" Intervalometer: %s \n"
" Pictures taken: %d ",
format_time_hours_minutes_seconds(intervalometer_next_shot_time - seconds_clock),
intervalometer_pictures_taken);
if (interval_stop_after) { STR_APPEND(msg, "/ %d", interval_stop_after); }
bmp_printf(FONT_LARGE, 50, 310, msg);
}
#endif
}
}
#endif
// tell how many minutes the exposure will take
if (s == 2)
{
int d = duration / 1000;
if (d/60) { beep_times(d/60); msleep(500); }
}
// turn off the LED - no light pollution, please :)
// but blink it quickly every 10 seconds to have some feedback
if (s % 10 == 1) { _card_led_on(); msleep(10); _card_led_off(); }
// blink twice every minute, and beep as many times as elapsed minutes
if (s % 60 == 1) { msleep(200); _card_led_on(); msleep(10); _card_led_off(); if (s/60) beep_times(s/60); }
// exposure was canceled earlier by user
if (job_state_ready_to_take_pic())
{
canceled = 1;
beep();
break;
}
}
while (get_ms_clock_value() < t_end && !job_state_ready_to_take_pic())
msleep(MIN_MSLEEP);
//~ NotifyBox(3000, "BulbEnd");
SW2(0,0);
SW1(0,0);
lens_wait_readytotakepic(64);
lens_cleanup_af();
if (d0 >= 0) lens_set_drivemode(d0);
prop_request_change( PROP_SHUTTER, &s0r, 4 );
prop_request_change( PROP_SHUTTER_AUTO, &s0r, 4);
set_shooting_mode(m0r);
msleep(200);
ml_taking_pic = 0;
#endif
return canceled;
}
#ifdef FEATURE_BULB_TIMER
static int bulb_duration_change(struct config_var * var, int old_value, int new_value)
{
#ifdef FEATURE_EXPO_OVERRIDE
/* refresh bulb ExpSim */
*(var->value) = new_value;
bv_auto_update();
#endif
return 1;
}
static MENU_UPDATE_FUNC(bulb_display)
{
if (bulb_timer)
MENU_SET_VALUE(
format_time_hours_minutes_seconds(bulb_duration)
);
#ifdef FEATURE_INTERVALOMETER
if (!bulb_timer && is_bulb_mode())
{
// even if it's not enabled, bulb timer value will be used
// for intervalometer and other long exposure tools
MENU_SET_VALUE(
"%s%s",
format_time_hours_minutes_seconds(bulb_duration),
bulb_timer || interval_enabled ? "" : " (OFF)"
);
MENU_SET_WARNING(MENU_WARN_INFO, "Long exposure tools may use bulb timer value, even if BT is disabled.");
MENU_SET_RINFO(SYM_WARNING);
}
#endif
if (!is_bulb_mode()) MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "Bulb timer only works in BULB mode");
if (entry->selected && intervalometer_running) timelapse_calc_display(entry, info);
}
#endif
#ifdef FEATURE_MLU
static void mlu_selftimer_update()
{
if (MLU_SELF_TIMER)
{
int mlu_auto_value = (drive_mode == DRIVE_SELFTIMER_2SEC || drive_mode == DRIVE_SELFTIMER_REMOTE) ? 1 : 0;
int mlu_current_value = get_mlu();
if (mlu_auto_value != mlu_current_value)
{
set_mlu(mlu_auto_value); // shooting mode, ML decides to toggle MLU
}
}
}
static void
mlu_update()
{
if (mlu_mode == 0)
set_mlu(mlu_auto ? 1 : 0);
else if (mlu_mode == 1)
{
if (mlu_auto) mlu_selftimer_update();
else set_mlu(0);
}
else
set_mlu(0);
}
static void
mlu_toggle_mode( void * priv, int delta )
{
#ifdef FEATURE_MLU_HANDHELD
mlu_mode = MOD(mlu_mode + delta, 3);
#else
mlu_mode = !mlu_mode;
#endif
mlu_update();
}
static void
mlu_toggle( void * priv, int delta )
{
#ifndef CONFIG_1100D
mlu_auto = !mlu_auto;
mlu_update();
#endif
}
static MENU_UPDATE_FUNC(mlu_display)
{
MENU_SET_VALUE(
MLU_SELF_TIMER ? (get_mlu() ? "SelfTimer (ON)" : "SelfTimer (OFF)")
: MLU_HANDHELD ? (mlu_handheld_shutter ? "HandH,1/2-1/125" : "Handheld")
: MLU_ALWAYS_ON ? "Always ON"
: get_mlu() ? "ON" : "OFF"
);
if (mlu_mode == 2 &&
(
is_hdr_bracketing_enabled() ||
trap_focus ||
is_bulb_mode() ||
intervalometer_running ||
motion_detect ||
aeb_setting ||
#ifdef FEATURE_AUDIO_REMOTE_SHOT
audio_release_running ||
#endif
0)
)
{
static char msg[60];
snprintf(msg, sizeof(msg), "Handhedld MLU does not work with %s.",
is_hdr_bracketing_enabled() ? "HDR bracketing" :
trap_focus ? "trap focus" :
is_bulb_mode() ? "bulb shots" :
intervalometer_running ? "intervalometer" :
motion_detect ? "motion detection" :
aeb_setting ? "Canon bracketing (AEB)" :
#ifdef FEATURE_AUDIO_REMOTE_SHOT
audio_release_running ? "audio remote" :
#endif
"?!"
);
MENU_SET_WARNING(MENU_WARN_NOT_WORKING, msg);
}
}
#endif // FEATURE_MLU
#ifdef FEATURE_PICQ_DANGEROUS
static MENU_UPDATE_FUNC(picq_display)
{
int raw = pic_quality & 0x60000;
int rawsize = pic_quality & 0xF;
int jpegtype = pic_quality >> 24;
int jpegsize = (pic_quality >> 8) & 0xF;
MENU_SET_VALUE(
"%s%s%s%s%s",
rawsize == 1 ? "M" : rawsize == 2 ? "S" : "",
raw ? "RAW" : "",
jpegtype != 4 && raw ? "+" : "",
jpegtype == 4 ? "" : jpegsize == 0 ? "Large" : jpegsize == 1 ? "Med" : "Small",
jpegtype == 2 ? "Coarse" : jpegtype == 3 ? "Fine" : ""
);
MENU_SET_ENABLED(1);
}
static int picq_next(int p)
{
switch(pic_quality)
{
case PICQ_RAW: return PICQ_MRAW;
case PICQ_MRAW: return PICQ_SRAW;
case PICQ_SRAW: return PICQ_RAW_JPG_LARGE_FINE;
case PICQ_RAW_JPG_LARGE_FINE: return PICQ_MRAW_JPG_LARGE_FINE;
case PICQ_MRAW_JPG_LARGE_FINE: return PICQ_SRAW_JPG_LARGE_FINE;
case PICQ_SRAW_JPG_LARGE_FINE: return PICQ_SRAW_JPG_MED_FINE;
case PICQ_SRAW_JPG_MED_FINE: return PICQ_SRAW_JPG_SMALL_FINE;
case PICQ_SRAW_JPG_SMALL_FINE: return PICQ_LARGE_FINE;
case PICQ_LARGE_FINE: return PICQ_MED_FINE;
case PICQ_MED_FINE: return PICQ_SMALL_FINE;
}
return PICQ_RAW;
}
static void picq_toggle(void* priv)
{
int newp = picq_next(pic_quality);
set_pic_quality(newp);
}
#endif
#ifdef FEATURE_EXPO_LOCK
static CONFIG_INT("expo.lock", expo_lock, 0);
static CONFIG_INT("expo.lock.tv", expo_lock_tv, 0);
static CONFIG_INT("expo.lock.av", expo_lock_av, 1);
static CONFIG_INT("expo.lock.iso", expo_lock_iso, 1);
// keep this constant
static int expo_lock_value = INT_MAX;
static MENU_UPDATE_FUNC(expo_lock_display)
{
if (expo_lock)
{
MENU_SET_VALUE(
"%s%s%s",
expo_lock_tv ? "Tv," : "",
expo_lock_av ? "Av," : "",
expo_lock_iso ? "ISO," : ""
);
info->value[strlen(info->value)-1] = 0; // trim last comma
}
if (lens_info.name[0] && lens_info.raw_aperture && lens_info.raw_shutter && lens_info.raw_iso && !menu_active_but_hidden())
{
int Av = APEX_AV(lens_info.raw_aperture);
int Tv = APEX_TV(lens_info.raw_shutter);
int Sv = APEX_SV(lens_info.iso_equiv_raw);
int Bv = Av + Tv - Sv;
Bv = Bv * 10/8;
MENU_SET_RINFO(
"Bv%s%d.%d",
FMT_FIXEDPOINT1(Bv)
);
}
if (is_hdr_bracketing_enabled())
MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "This feature does not work with HDR bracketing.");
}
// Tv + Av - Sv, in APEX units
static int expo_lock_get_current_value()
{
return APEX_TV(lens_info.raw_shutter) + APEX_AV(lens_info.raw_aperture) - APEX_SV(lens_info.iso_equiv_raw);
}
// returns the remainder
static int expo_lock_adjust_tv(int delta)
{
if (!delta) return 0;
int old_tv = lens_info.raw_shutter;
int new_tv = old_tv + delta;
new_tv = COERCE(new_tv, 16, FASTEST_SHUTTER_SPEED_RAW);
new_tv = round_shutter(new_tv, 16);
lens_set_rawshutter(new_tv);
msleep(100);
return delta - lens_info.raw_shutter + old_tv;
}
static int expo_lock_adjust_av(int delta)
{
if (!delta) return 0;
if (!lens_info.raw_aperture) return delta; // manual lens
int old_av = lens_info.raw_aperture;
int new_av = old_av + delta;
new_av = COERCE(new_av, lens_info.raw_aperture_min, lens_info.raw_aperture_max);
new_av = round_aperture(new_av);
lens_set_rawaperture(new_av);
msleep(100);
return delta - lens_info.raw_aperture + old_av;
}
static int expo_lock_adjust_iso(int delta)
{
if (!delta) return 0;
int old_iso = lens_info.raw_iso;
int delta_r = ((delta + 4 * SGN(delta)) / 8) * 8;
int new_iso = COERCE(old_iso - delta_r, MIN_ISO, MAX_ANALOG_ISO);
/* for very fast adjustments: stop at max auto ISO;
* will try to adjust something else before going above max auto ISO */
int max_auto_iso = auto_iso_range & 0xFF;
if (new_iso > max_auto_iso && old_iso < max_auto_iso)
new_iso = max_auto_iso;
lens_set_rawiso(new_iso);
msleep(100);
return delta - old_iso + lens_info.raw_iso;
}
void expo_lock_update_value()
{
expo_lock_value = expo_lock_get_current_value();
}
static void expo_lock_step()
{
if (!expo_lock)
{
expo_lock_update_value();
return;
}
if (shooting_mode != SHOOTMODE_M) return;
if (!lens_info.raw_iso) return;
#ifdef ISO_ADJUSTMENT_ACTIVE
if (ISO_ADJUSTMENT_ACTIVE) return; /* careful with disabling this one: does expo lock work when changing ISO from Canon menu? (try both ISO->Tv and ISO->Av, movie/photo, LV or outside LV) */
#endif
if (is_hdr_bracketing_enabled()) return;
int max_auto_iso = auto_iso_range & 0xFF;
if (expo_lock_value == INT_MAX)
expo_lock_update_value();
static int p_tv = 0;
static int p_av = 0;
static int p_iso = 0;
if (!p_tv) p_tv = lens_info.raw_shutter;
if (!p_av) p_av = lens_info.raw_aperture;
if (!p_iso) p_iso = lens_info.raw_iso;
int r_iso = lens_info.raw_iso;
int r_tv = lens_info.raw_shutter;
int r_av = lens_info.raw_aperture;
static int what_changed = 0; // 1=iso, 2=Tv, 3=Av
if (p_iso != r_iso) what_changed = 1; // iso changed
else if (p_tv != r_tv) what_changed = 2;
else if (p_av != r_av) what_changed = 3;
p_iso = r_iso;
p_tv = r_tv;
p_av = r_av;
// let's see if user changed some setting for which exposure isn't locked => update expo reference value
if ((what_changed == 1 && !expo_lock_iso) ||
(what_changed == 2 && !expo_lock_tv) ||
(what_changed == 3 && !expo_lock_av))
{
expo_lock_update_value();
return;
}
int diff = expo_lock_value - expo_lock_get_current_value();
//~ NotifyBox(1000, "%d %d ", diff, what_changed);
if (diff >= -1 && diff <= 1)
return; // difference is too small, ignore it
if (what_changed == 1 && expo_lock_iso)
{
int current_value = expo_lock_get_current_value();
int delta = expo_lock_value - current_value;
if (expo_lock_iso == 1)
{
delta = expo_lock_adjust_tv(delta);
if (ABS(delta) >= 4) delta = expo_lock_adjust_av(delta);
}
else
{
delta = expo_lock_adjust_av(delta);
if (ABS(delta) >= 4) delta = expo_lock_adjust_tv(delta);
}
//~ delta = expo_lock_adjust_iso(delta);
}
else if (what_changed == 2 && expo_lock_tv)
{
int current_value = expo_lock_get_current_value();
int delta = expo_lock_value - current_value;
if (expo_lock_tv == 1 || (lens_info.raw_iso > max_auto_iso - 8 && delta < 0))
{
delta = expo_lock_adjust_av(delta);
if (ABS(delta) > 4) delta = expo_lock_adjust_iso(delta);
}
else
{
if (ABS(delta) > 4) delta = expo_lock_adjust_iso(delta);
if (ABS(delta) >= 8) delta = expo_lock_adjust_av(delta);
}
//~ delta = expo_lock_adjust_tv(delta, 0);
}
else if (what_changed == 3 && expo_lock_av)
{
int current_value = expo_lock_get_current_value();
int delta = expo_lock_value - current_value;
if (expo_lock_av == 1 || (lens_info.raw_iso > max_auto_iso - 8 && delta < 0))
{
delta = expo_lock_adjust_tv(delta);
if (ABS(delta) > 4) delta = expo_lock_adjust_iso(delta);
}
else
{
if (ABS(delta) > 4) delta = expo_lock_adjust_iso(delta);
if (ABS(delta) >= 8) delta = expo_lock_adjust_tv(delta);
}
//~ delta = expo_lock_adjust_av(delta);
}
p_tv = lens_info.raw_shutter;
p_av = lens_info.raw_aperture;
p_iso = lens_info.raw_iso;
}
#endif
#ifdef FEATURE_EXPO_PRESET
static CONFIG_INT("expo.preset", expo_preset, 0);
static CONFIG_INT("expo.pre.iso", pre_iso, 1234);
static CONFIG_INT("expo.pre.tv", pre_tv, 1234);
static CONFIG_INT("expo.pre.av", pre_av, 1234);
static CONFIG_INT("expo.pre.kelvin", pre_kelvin, 1234);
static void expo_preset_toggle()
{
int c_iso = lens_info.raw_iso;
int c_tv = lens_info.raw_shutter;
int c_av = lens_info.raw_aperture;
int c_kelvin = lens_info.kelvin;
if (pre_iso == 1234) pre_iso = c_iso;
if (pre_tv == 1234) pre_tv = c_tv;
if (pre_av == 1234) pre_av = c_av;
if (pre_kelvin == 1234) pre_kelvin = c_kelvin;
int ap = values_aperture[raw2index_aperture(pre_av)];
if (lv)
NotifyBox(2000,
SYM_ISO"%d "SYM_1_SLASH"%d "SYM_F_SLASH"%d.%d %dK",
raw2iso(pre_iso),
(int)roundf(1/raw2shutterf(pre_tv)),
ap/10, ap%10,
lens_info.wb_mode == WB_KELVIN ? pre_kelvin : 0
);
else
beep();
if (pre_tv != SHUTTER_BULB) lens_set_rawshutter(pre_tv); else ensure_bulb_mode();
lens_set_rawiso(pre_iso);
lens_set_rawaperture(pre_av);
if (lens_info.wb_mode == WB_KELVIN)
lens_set_kelvin(pre_kelvin);
pre_iso = c_iso;
pre_tv = c_tv;
pre_av = c_av;
pre_kelvin = c_kelvin;
}
int handle_expo_preset(struct event * event)
{
if (!expo_preset) return 1;
if ((event->param == BGMT_PRESS_SET && expo_preset == 1) ||
(event->param == BGMT_INFO && expo_preset == 2))
{
if (display_idle())
{
expo_preset_toggle();
return 0;
}
}
return 1;
}
#endif // FEATURE_EXPO_PRESET
static MENU_UPDATE_FUNC(pics_at_once_update)
{
if (!pics_to_take_at_once)
{
MENU_SET_ENABLED(0);
}
if (is_hdr_bracketing_enabled())
{
MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "No burst bracketing series, please.");
}
}
static MENU_UPDATE_FUNC(use_af_update)
{
if (is_hdr_bracketing_enabled())
{
MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "Autofocus and bracketing don't mix.");
}
}
// in lcdsensor.c
extern MENU_UPDATE_FUNC(lcd_release_display);
extern int voice_tags; // beep.c
static struct menu_entry shoot_menus[] = {
#ifdef FEATURE_HDR_BRACKETING
{
.name = "Advanced Bracket",
.priv = &hdr_enabled,
.update = hdr_display,
.max = 1,
.help = "Advanced bracketing (expo, flash, DOF). Press shutter once.",
.works_best_in = DEP_PHOTO_MODE | DEP_M_MODE | DEP_MANUAL_ISO,
.submenu_width = 710,
.children = (struct menu_entry[]) {
{
.name = "Bracket type",
.priv = &hdr_type,
.max = 2,
.icon_type = IT_DICE,
.choices = CHOICES("Exposure (Tv,Ae)", "Exposure (Flash)", "DOF (Aperture)"),
.help = "Choose the variables to bracket:",
.help2 = "Expo bracket. M: changes shutter. Others: changes AEcomp.\n"
"Flash bracket: change flash exposure compensation.\n"
"DOF bracket: keep exposure constant, change Av/Tv ratio.",
},
{
.name = "Frames",
.priv = &hdr_steps,
.min = 1,
.max = 12,
.update = hdr_steps_update,
.icon_type = IT_PERCENT,
.choices = CHOICES("Autodetect", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"),
.help = "Number of bracketed shots. Can be computed automatically.",
},
{
.name = "EV increment",
.priv = &hdr_stepsize,
.select = hdr_stepsize_toggle,
.update = hdr_check_excessive_settings,
.min = HDR_STEPSIZE_MIN,
.max = HDR_STEPSIZE_MAX,
.unit = UNIT_1_8_EV,
.icon_type = IT_PERCENT,
.help = "Exposure difference between two frames.",
},
{
.name = "Sequence",
.priv = &hdr_sequence,
.max = 2,
.icon_type = IT_DICE,
.choices = CHOICES("0 - --", "0 - + -- ++", "0 + ++"),
.help = "Bracketing sequence order / type. Zero is always first.",
.help2 =
"Take darker images.\n"
"Take dark, bright, even darker, even brigther images, in that order\n"
"Take brighter images.\n"
},
#ifndef CONFIG_5DC
{
.name = "2-second delay",
.priv = &hdr_delay,
.max = 1,
.help = "Delay before starting the exposure.",
.help2 = "Only used if you start bracketing by pressing the shutter.",
.choices = CHOICES("OFF", "Auto"),
},
#endif
{
.name = "ISO shifting",
.priv = &hdr_iso,
.max = 2,
.help = "Also use ISO as bracket variable. Range: 100 - max AutoISO.",
.help2 = " \n"
"Full: try ISO bracket first. If out of range, use main var.\n"
"Half: Bracket with both ISO (50%) and main variable (50%).\n",
.choices = CHOICES("OFF", "Full", "Half"),
.icon_type = IT_DICE_OFF,
},
MENU_EOL
},
},
#endif
#ifdef FEATURE_INTERVALOMETER
{
.name = "Intervalometer",
.priv = &interval_enabled,
.max = 1,
.update = intervalometer_display,
.help = "Take pictures at fixed intervals (for timelapse).",
.submenu_width = 700,
.works_best_in = DEP_PHOTO_MODE,
.children = (struct menu_entry[]) {
{
.name = "Take a pic every",
.priv = &interval_time,
.max = TIME_MAX_VALUE,
.update = interval_timer_display,
.icon_type = IT_PERCENT,
.unit = UNIT_TIME,
.help = "Duration between two shots.",
},
{
.name = "Start trigger",
.priv = &interval_trigger,
.update = interval_trigger_update,
.max = 2,
.choices = CHOICES("Leave Menu", "Half Shutter", "Take a Pic"),
.help = "How to trigger the intervalometer start:",
.help2 = "When you exit ML menu, or at camera startup.\n"
"On half-shutter press.\n"
"After you take the first picture.",
},
{
.name = "Start after",
.priv = &interval_start_time,
.max = TIME_MAX_VALUE,
.update = interval_start_after_display,
.icon_type = IT_PERCENT,
.unit = UNIT_TIME,
.help = "Start the intervalometer after X seconds / minutes / hours.",
},
{
.name = "Stop after",
.priv = &interval_stop_after,
.max = 5000, // 5000 shots
.unit = UNIT_DEC,
.update = interval_stop_after_display,
.icon_type = IT_PERCENT_LOG_OFF,
.help = "Stop the intervalometer after taking X shots.",
},
MENU_EOL
},
},
#endif
MENU_PLACEHOLDER("Post Deflicker"),
#ifdef FEATURE_BULB_TIMER
{
.name = "Bulb Timer",
.priv = &bulb_timer,
.update = bulb_display,
.max = 1,
.help = "For very long exposures (several minutes).",
.help2 = "To trigger, hold shutter pressed halfway for 1 second.",
.depends_on = DEP_PHOTO_MODE,
.submenu_width = 710,
.children = (struct menu_entry[]) {
{
.name = "Exposure duration",
.priv = &bulb_duration,
.max = TIME_MAX_VALUE,
.icon_type = IT_PERCENT,
.unit = UNIT_TIME
},
{
.name = "Display during exposure",
.priv = &bulb_display_mode,
#ifdef FEATURE_BULB_TIMER_SHOW_PREVIOUS_PIC
.max = 2,
#else
.max = 1, /* just option to turn it off */
#endif
.icon_type = IT_DICE_OFF,
.choices = CHOICES("Don't change", "Turn off", "Show previous pic"),
.help = "Turn the screen on/off while taking bulb exposure.",
},
MENU_EOL
},
},
#endif
#ifdef FEATURE_LCD_SENSOR_REMOTE
{
.name = "LCDsensor Remote",
.priv = &lcd_release_running,
.max = 3,
.update = lcd_release_display,
.choices = CHOICES("OFF", "Near", "Away", "Wave"),
.help = "Use the LCD face sensor as a simple remote (avoids shake).",
},
#endif
#ifdef FEATURE_AUDIO_REMOTE_SHOT
{
.name = "Audio RemoteShot",
.priv = &audio_release_running,
.max = 1,
.update = audio_release_display,
.help = "Clap your hands or pop a balloon to take a picture.",
//.essential = FOR_PHOTO,
.children = (struct menu_entry[]) {
{
.name = "Trigger level (dB)",
.priv = &audio_release_level,
.min = 1,
.max = 20,
.help = "Picture taken when sound level becomes X dB above average.",
},
MENU_EOL
},
},
#endif
#ifdef FEATURE_MOTION_DETECT
{
.name = "Motion Detect",
.priv = &motion_detect,
.max = 1,
.update = motion_detect_display,
.help = "Take a picture when subject is moving or exposure changes.",
.works_best_in = DEP_PHOTO_MODE,
.submenu_width = 650,
.children = (struct menu_entry[]) {
{
.name = "Trigger by",
.priv = &motion_detect_trigger,
.max = 2,
.choices = CHOICES("Expo. change", "Frame diff.", "Steady hands"),
.icon_type = IT_DICE,
.help = "Choose when the picture should be taken:",
.help2 = "EXP: reacts to exposure changes (large movements).\n"
"DIF: detects smaller movements that do not change exposure.\n"
"STDY: take pic if there's little or no motion (cam steady).",
},
{
.name = "Trigger level",
.priv = &motion_detect_level,
.min = 1,
.max = 30,
.help = "Higher values = less sensitive to motion.",
},
{
.name = "Detect Size",
.priv = &motion_detect_size,
.max = 2,
.choices = CHOICES("Small", "Medium", "Large"),
.help = "Size of the area on which motion shall be detected.",
},
{
.name = "Delay",
.priv = &motion_detect_delay,
.max = 10,
.min = 0,
.icon_type = IT_PERCENT_OFF,
.choices = CHOICES("OFF", "0.1s", "0.2s", "0.3s", "0.4s", "0.5s", "0.6s", "0.7s", "0.8s", "0.9s", "1s"),
.help = "Delay between the detected motion and the picture taken.",
},
MENU_EOL
}
},
#endif
MENU_PLACEHOLDER("Silent Picture"),
#ifdef FEATURE_MLU_HANDHELD
#ifndef FEATURE_MLU
#error This requires FEATURE_MLU.
#endif
#endif
#ifdef FEATURE_MLU
{
// 5DC can't do handheld MLU
// 5D3 can do, but doesn't need it (it has silent mode with little or no vibration)
.name = "Mirror Lockup",
.priv = &mlu_auto,
.update = mlu_display,
.select = mlu_toggle,
.max = 1,
.depends_on = DEP_PHOTO_MODE | DEP_NOT_LIVEVIEW,
#ifdef FEATURE_MLU_HANDHELD
.help = "MLU tricks: hand-held or self-timer modes.",
#elif defined(CONFIG_5DC)
.help = "You can toggle MLU w. DirectPrint or link it to self-timer.",
#else
.help = "You can link MLU with self-timer (handy).",
#endif
.submenu_width = 700,
.children = (struct menu_entry[]) {
{
.name = "MLU mode",
.priv = &mlu_mode,
.select = mlu_toggle_mode,
#ifdef FEATURE_MLU_HANDHELD
.max = 2,
#else
.max = 1,
#endif
.choices = CHOICES("Always ON", "Self-Timer", "Handheld"),
.help = "Choose when mirror lock-up should be active:",
.help2 = "Always ON: just the Canon mode, press shutter twice.\n"
"Self-Timer: MLU setting will be linked to Canon self-timer.\n"
"Handheld: trick to reduce camera shake. Press shutter once.",
},
#ifdef FEATURE_MLU_HANDHELD
{
.name = "Handheld Shutter",
.priv = &mlu_handheld_shutter,
.max = 1,
.icon_type = IT_DICE,
.choices = CHOICES("All values", "1/2...1/125"),
.help = "At what shutter speeds you want to use handheld MLU."
},
{
.name = "Handheld Delay",
.priv = &mlu_handheld_delay,
.min = 1,
.max = 7,
.icon_type = IT_PERCENT,
.choices = CHOICES("0.1s", "0.2s", "0.3s", "0.4s", "0.5s", "0.75s", "1s"),
.help = "Delay between mirror and shutter movement."
},
#endif
#ifdef FEATURE_MLU_HANDHELD_DEBUG
#ifndef FEATURE_MLU_HANDHELD
#error This requires FEATURE_MLU_HANDHELD.
#endif
{
.name = "Handheld Debug",
.priv = &mlu_handled_debug,
.max = 1,
.help = "Check whether the 'mirror up' event is detected correctly."
},
#endif
{
.name = "Normal MLU Delay",
.priv = &lens_mlu_delay,
.min = 5,
.max = 11,
.icon_type = IT_PERCENT,
.choices = CHOICES("0.5s", "0.75s", "1s", "2s", "3s", "4s", "5s"),
.help = "MLU delay used with intervalometer, bracketing etc.",
},
MENU_EOL
},
},
#endif
#ifdef FEATURE_PICQ_DANGEROUS
{
.update = picq_display,
.select = picq_toggle,
.help = "Experimental SRAW/MRAW mode. You may get corrupted files."
},
#endif
#ifdef FEATURE_VOICE_TAGS
{
.name = "Voice Tags",
.priv = &voice_tags,
.max = 1,
.help = "After you take a picture, press SET to add a voice tag.",
.help2 = "For playback, go to Audio -> Sound Recorder.",
.works_best_in = DEP_PHOTO_MODE,
},
#endif
#ifdef FEATURE_LV_3RD_PARTY_FLASH
#ifndef FEATURE_FLASH_TWEAKS
#error This requires FEATURE_FLASH_TWEAKS.
#endif
#endif
#ifdef FEATURE_FLASH_TWEAKS
{
.name = "Flash Tweaks",
.select = menu_open_submenu,
.help = "Flash exposure compensation, 3rd party flash in LiveView...",
.depends_on = DEP_PHOTO_MODE,
.children = (struct menu_entry[]) {
{
.name = "Flash expo comp.",
.priv = &lens_info.flash_ae,
.min = FLASH_MIN_EV * 8,
.max = FLASH_MAX_EV * 8,
.update = flash_ae_display,
.select = flash_ae_toggle,
.help = "Flash exposure compensation, from -10EV to +3EV.",
.icon_type = IT_PERCENT_OFF,
.edit_mode = EM_MANY_VALUES,
.depends_on = DEP_PHOTO_MODE,
},
#ifdef FEATURE_FLASH_NOFLASH
{
.name = "Flash / No flash",
.update = flash_and_no_flash_display,
.priv = &flash_and_no_flash,
.max = 1,
.depends_on = DEP_PHOTO_MODE,
.help = "Take odd pictures with flash, even pictures without flash.",
},
#endif
#ifdef FEATURE_LV_3RD_PARTY_FLASH
{
.name = "3rd p. flash LV",
.priv = &lv_3rd_party_flash,
.max = 1,
.depends_on = DEP_LIVEVIEW | DEP_PHOTO_MODE,
.help = "A trick to allow 3rd party flashes to fire in LiveView.",
.help2 = "!!! DISABLE THIS OPTION WHEN YOU ARE NOT USING IT !!! ",
},
#endif
MENU_EOL,
},
},
#endif
{
.name = "Shoot Preferences",
.select = menu_open_submenu,
.help = "Autofocus, number of pics to take at once...",
.depends_on = DEP_PHOTO_MODE,
.submenu_width = 710,
.children = (struct menu_entry[]) {
{
.name = "Pics at once",
.priv = &pics_to_take_at_once,
.max = 8,
.choices = CHOICES("1 (OFF)", "2", "3", "4", "5", "6", "7", "8", "9"),
.update = pics_at_once_update,
.icon_type = IT_PERCENT_OFF,
.help = "How many pictures to take at once (for each trigger event).",
.help2 = "For intervalometer, motion detect, trap focus, audio remote.",
},
#ifdef CONFIG_PROP_REQUEST_CHANGE
{
.name = "Use Autofocus",
.priv = &shoot_use_af,
.update = use_af_update,
.max = 1,
.help = "For intervalometer, audio remote shot and motion detect.",
.help2 = "Be careful, won't take pics if it can't autofocus.",
.icon_type = IT_BOOL,
.depends_on = DEP_AUTOFOCUS,
.works_best_in = DEP_NOT_LIVEVIEW,
},
#endif
#if defined(FEATURE_HDR_BRACKETING) || defined(FEATURE_FOCUS_STACKING)
{
.name = "Post scripts",
.priv = &hdr_scripts,
.max = 3,
.help = "Post-processing scripts for bracketing and focus stacking.",
.choices = CHOICES("OFF", "Enfuse", "Align+Enfuse", "File List"),
},
#endif
#ifdef FEATURE_INTERVALOMETER
{
.name = "Intervalometer Script",
.priv = &interval_scripts,
.max = 3,
.help = "Scripts for sorting intervalometer sequences.",
.choices = CHOICES("OFF", "Bash", "MS-DOS", "File List"),
},
#endif
#ifdef FEATURE_SNAP_SIM
{
.name = "Snap Simulation",
.priv = &snap_sim,
.max = 1,
.icon_type = IT_BOOL,
.choices = CHOICES(
"OFF",
"Blink"
#ifdef CONFIG_BEEP
" & Beep"
#endif
),
.help = "You can take virtual (fake) pictures just for testing.",
},
#endif
MENU_EOL,
},
}
};
#ifdef FEATURE_ZOOM_TRICK_5D3
extern int zoom_trick;
#endif
struct menu_entry tweak_menus_shoot[] = {
#ifdef FEATURE_LV_ZOOM_SETTINGS
{
.name = "LiveView zoom tweaks",
.select = menu_open_submenu,
.submenu_width = 650,
.icon_type = IT_SUBMENU,
.help = "Disable x5 or x10, boost contrast/sharpness...",
.depends_on = DEP_LIVEVIEW,
.children = (struct menu_entry[]) {
{
.name = "Zoom x5",
.priv = &zoom_disable_x5,
.max = 1,
.choices = CHOICES("ON", "Disable"),
.select = zoom_x5_x10_toggle,
.help = "Disable x5 zoom in LiveView.",
.icon_type = IT_DISABLE_SOME_FEATURE,
},
{
.name = "Zoom x10",
.priv = &zoom_disable_x10,
.max = 1,
.select = zoom_x5_x10_toggle,
.choices = CHOICES("ON", "Disable"),
.help = "Disable x10 zoom in LiveView.",
.icon_type = IT_DISABLE_SOME_FEATURE,
},
#ifdef FEATURE_LV_ZOOM_AUTO_EXPOSURE
#ifndef CONFIG_EXPSIM
#error This requires CONFIG_EXPSIM.
#endif
{
.name = "Auto exposure on Zoom",
.priv = &zoom_auto_exposure,
.max = 1,
.help = "Auto adjusts exposure, so you can focus manually wide open.",
#ifndef CONFIG_5D2
.depends_on = DEP_PHOTO_MODE,
#endif
},
#endif
#ifdef FEATURE_LV_ZOOM_SHARP_CONTRAST
{
.name = "Increase SharpContrast",
.priv = &zoom_sharpen,
.max = 1,
.help = "Increase sharpness and contrast when you zoom in LiveView."
},
#endif
{
.name = "Zoom on HalfShutter",
.priv = &zoom_halfshutter,
.max = 1,
.help = "Enable zoom when you hold the shutter halfway pressed.",
.depends_on = DEP_MANUAL_FOCUS,
},
{
.name = "Zoom with Focus Ring",
.priv = &zoom_focus_ring,
.max = 1,
.help = "Zoom when you turn the focus ring (only some Canon lenses).",
.depends_on = DEP_MANUAL_FOCUS,
},
#ifdef FEATURE_ZOOM_TRICK_5D3
#ifdef CONFIG_6D
{
.name = "Double Click",
.priv = &zoom_trick,
.max = 2,
.help = "Double-click top-right button in LV. Shortcuts or Zoom.",
.choices = CHOICES("OFF", "Zoom", "Shortcuts"),
},
#else // 5D3
{
.name = "Zoom with old button",
.priv = &zoom_trick,
.max = 1,
.help = "Use the old Zoom In button, as in 5D2. Double-click in LV.",
.choices = CHOICES("OFF", "ON (!)"),
},
#endif
#endif
MENU_EOL
},
},
#endif
};
extern int lvae_iso_max;
extern int lvae_iso_min;
extern int lvae_iso_speed;
extern MENU_UPDATE_FUNC(digic_iso_print_movie);
extern MENU_SELECT_FUNC(digic_iso_toggle_movie);
extern int digic_black_level;
extern MENU_UPDATE_FUNC(digic_black_print);
extern int digic_shadow_lift;
static struct menu_entry expo_menus[] = {
#ifdef FEATURE_WHITE_BALANCE
{
.name = "White Balance",
.update = kelvin_wbs_display,
.select = kelvin_toggle,
.help = "Adjust Kelvin white balance and GM/BA WBShift.",
.help2 = "Advanced: WBShift, RGB multipliers, Push-button WB...",
.edit_mode = EM_MANY_VALUES_LV,
.submenu_width = 700,
.children = (struct menu_entry[]) {
{
.name = "White Balance",
.update = kelvin_display,
.select = kelvin_toggle,
.help = "Adjust Kelvin white balance.",
.edit_mode = EM_MANY_VALUES_LV,
},
{
.name = "WBShift G/M",
.update = wbs_gm_display,
.select = wbs_gm_toggle,
.min = -9,
.max = 9,
.icon_type = IT_PERCENT_OFF,
.help = "Green-Magenta white balance shift, for fluorescent lights.",
.edit_mode = EM_MANY_VALUES_LV,
},
{
.name = "WBShift B/A",
.update = wbs_ba_display,
.select = wbs_ba_toggle,
.min = -9,
.max = 9,
.icon_type = IT_PERCENT_OFF,
.help = "Blue-Amber WBShift; 1 unit = 5 mireks on Kelvin axis.",
.edit_mode = EM_MANY_VALUES_LV,
},
{
.name = "R multiplier",
.priv = (void *)(1),
.update = wb_custom_gain_display,
.select = wb_custom_gain_toggle,
.icon_type = IT_PERCENT,
.help = "RED channel multiplier, for custom white balance.",
.edit_mode = EM_MANY_VALUES_LV,
},
{
.name = "G multiplier",
.priv = (void *)(2),
.update = wb_custom_gain_display,
.select = wb_custom_gain_toggle,
.icon_type = IT_PERCENT,
.help = "GREEN channel multiplier, for custom white balance.",
.edit_mode = EM_MANY_VALUES_LV,
},
{
.name = "B multiplier",
.priv = (void *)(3),
.update = wb_custom_gain_display,
.select = wb_custom_gain_toggle,
.icon_type = IT_PERCENT,
.help = "BLUE channel multiplier, for custom white balance.",
.edit_mode = EM_MANY_VALUES_LV,
},
/*{
.name = "Auto adjust Kelvin",
.select = kelvin_auto,
.help = "LiveView: adjust Kelvin value once for the current scene."
},
{
.name = "Auto adjust Green-Magenta",
.select = wbs_gm_auto,
.help = "LiveView: adjust Green-Magenta once for the current scene."
},*/
{
.name = "Auto adjust Kelvin + G/M",
.select = kelvin_n_gm_auto,
.help = "LiveView: adjust Kelvin and G-M once (Push-button WB).",
.depends_on = DEP_LIVEVIEW,
},
MENU_EOL
},
},
#endif
#ifdef FEATURE_EXPO_ISO_HTP
#ifndef FEATURE_EXPO_ISO
#error This requires FEATURE_EXPO_ISO.
#endif
#endif
#ifdef FEATURE_EXPO_ISO
{
.name = "ISO",
.update = iso_display,
.select = iso_toggle,
.help = "Adjust and fine-tune ISO. Also displays APEX Sv value.",
.help2 = "Advanced: digital ISO tweaks, HTP, ISO 50, ISO 800.000...",
.edit_mode = EM_MANY_VALUES_LV,
.submenu_width = 650,
.children = (struct menu_entry[]) {
{
.name = "Equivalent ISO",
.help = "ISO equivalent (analog + digital components).",
.priv = &lens_info.iso_equiv_raw,
.unit = UNIT_ISO,
.select = iso_toggle,
.edit_mode = EM_MANY_VALUES_LV,
.update = iso_icon_update,
},
{
.name = "Canon analog ISO",
.help = "Analog ISO component (ISO at which the sensor is driven).",
.priv = &lens_info.iso_analog_raw,
.unit = UNIT_ISO,
.select = analog_iso_toggle,
.edit_mode = EM_MANY_VALUES_LV,
.depends_on = DEP_MANUAL_ISO,
.update = iso_icon_update,
},
{
.name = "Canon digital ISO",
.help = "Canon's digital ISO component. Strongly recommended: 0.",
.priv = &lens_info.iso_digital_ev,
.unit = UNIT_1_8_EV,
.select = digital_iso_toggle,
.edit_mode = EM_MANY_VALUES_LV,
.depends_on = DEP_MANUAL_ISO,
.icon_type = IT_DICE_OFF,
},
#ifdef FEATURE_EXPO_ISO_DIGIC
{
.name = "ML digital ISO",
.update = digic_iso_print_movie,
.select = digic_iso_toggle_movie,
.help = "ISO tweaks. Negative gain has better highlight roll-off.",
.edit_mode = EM_MANY_VALUES_LV,
.depends_on = DEP_MOVIE_MODE | DEP_MANUAL_ISO,
.icon_type = IT_DICE_OFF,
},
#endif
#ifdef FEATURE_EXPO_ISO_HTP
{
.name = "Highlight Tone P.",
.select = (void (*)(void *,int))htp_toggle,
.update = htp_display,
.icon_type = IT_BOOL,
.help = "Highlight Tone Priority. Use with negative ML digital ISO.",
},
#endif
/*
#ifdef FEATURE_EXPO_ISO_DIGIC
{
.name = "ISO Selection",
.priv = &iso_selection,
.max = 1,
.help = "What ISOs should be available from main menu and shortcuts.",
.choices = CHOICES("C 100/160x", "ML ISOs"),
.icon_type = IT_DICE,
},
#endif
*/
#if 0 // unstable
{
.name = "Min Movie AutoISO",
.priv = &lvae_iso_min,
.min = 72,
.max = 120,
.unit = UNIT_ISO,
.help = "Minimum value for Auto ISO in movie mode.",
.edit_mode = EM_MANY_VALUES_LV,
},
{
.name = "Max Movie AutoISO",
.priv = &lvae_iso_max,
.min = 72,
.max = 120,
.unit = UNIT_ISO,
.help = "Maximum value for Auto ISO in movie mode.",
.edit_mode = EM_MANY_VALUES_LV,
},
{
.name = "A-ISO smoothness",
.priv = &lvae_iso_speed,
.min = 3,
.max = 30,
.help = "Speed for movie Auto ISO. Low values = smooth transitions.",
.edit_mode = EM_MANY_VALUES_LV,
},
#endif
MENU_EOL
},
},
#endif
#ifdef FEATURE_EXPO_SHUTTER
{
.name = "Shutter",
.update = shutter_display,
.select = shutter_toggle,
.icon_type = IT_PERCENT,
.help = "Fine-tune shutter value. Displays APEX Tv or degrees equiv.",
.edit_mode = EM_MANY_VALUES_LV,
},
#endif
#ifdef FEATURE_EXPO_APERTURE
{
.name = "Aperture",
.update = aperture_display,
.select = aperture_toggle,
.icon_type = IT_PERCENT,
.help = "Adjust aperture. Also displays APEX aperture (Av) in stops.",
.depends_on = DEP_CHIPPED_LENS,
.edit_mode = EM_MANY_VALUES_LV,
},
#endif
#ifdef FEATURE_PICSTYLE
{
.name = "Picture Style",
.update = picstyle_display,
.select = picstyle_toggle,
.priv = &lens_info.picstyle,
.help = "Change current picture style.",
.edit_mode = EM_MANY_VALUES_LV,
.icon_type = IT_DICE,
.choices = (const char *[]) {
#if NUM_PICSTYLES == 10 // 600D, 5D3...
"Auto",
#endif
"Standard", "Portrait", "Landscape", "Neutral", "Faithful", "Monochrome", "UserDef1", "UserDef2", "UserDef3" },
.min = 1,
.max = NUM_PICSTYLES,
.submenu_width = 550,
.submenu_height = 300,
//~ .show_liveview = 1,
//~ //.essential = FOR_PHOTO | FOR_MOVIE,
.children = (struct menu_entry[]) {
{
.name = "Picture Style",
.priv = &lens_info.picstyle,
.min = 1,
.max = NUM_PICSTYLES,
.choices = (const char *[]) {
#if NUM_PICSTYLES == 10 // 600D, 5D3...
"Auto",
#endif
"Standard", "Portrait", "Landscape", "Neutral", "Faithful", "Monochrome", "UserDef1", "UserDef2", "UserDef3" },
.update = picstyle_display_submenu,
.select = picstyle_toggle,
.help = "Change current picture style.",
//~ .show_liveview = 1,
.edit_mode = EM_MANY_VALUES_LV,
.icon_type = IT_DICE,
},
{
.name = "Sharpness",
.update = sharpness_display,
.select = sharpness_toggle,
.help = "Adjust sharpness in current picture style.",
.edit_mode = EM_MANY_VALUES_LV,
},
{
.name = "Contrast",
.update = contrast_display,
.select = contrast_toggle,
.help = "Adjust contrast in current picture style.",
.edit_mode = EM_MANY_VALUES_LV,
},
{
.name = "Saturation",
.update = saturation_display,
.select = saturation_toggle,
.help = "Adjust saturation in current picture style.",
.edit_mode = EM_MANY_VALUES_LV,
},
{
.name = "Color Tone",
.update = color_tone_display,
.select = color_tone_toggle,
.help = "Adjust color tone in current picture style.",
.edit_mode = EM_MANY_VALUES_LV,
},
#ifdef FEATURE_REC_PICSTYLE
{
.name = "REC-PicStyle",
.priv = &picstyle_rec,
.max = NUM_PICSTYLES,
.icon_type = IT_DICE_OFF,
.update = picstyle_rec_sub_display,
.select = picstyle_rec_sub_toggle,
.choices = (const char *[]) {"OFF",
#if NUM_PICSTYLES == 10 // 600D, 5D3...
"Auto",
#endif
"Standard", "Portrait", "Landscape", "Neutral", "Faithful", "Monochrome", "UserDef1", "UserDef2", "UserDef3" },
.help = "You can use a different picture style when recording.",
.depends_on = DEP_MOVIE_MODE,
},
#endif
MENU_EOL
},
},
#endif
MENU_PLACEHOLDER("Auto ETTR"),
#ifdef FEATURE_EXPO_LOCK
{
.name = "Expo. Lock",
.priv = &expo_lock,
.max = 1,
.update = expo_lock_display,
.help = "In M mode, adjust Tv/Av/ISO without changing exposure.",
.help2 = "It may change the way you use M mode. Maybe I'm just crazy.",
.depends_on = DEP_M_MODE | DEP_MANUAL_ISO,
.children = (struct menu_entry[]) {
{
.name = "Tv -> ",
.priv = &expo_lock_tv,
.max = 2,
.icon_type = IT_DICE_OFF,
.choices = CHOICES("OFF", "Av,ISO", "ISO,Av"),
.help = "When you change Tv, ML adjusts Av and ISO to keep exposure.",
},
{
.name = "Av -> ",
.priv = &expo_lock_av,
.max = 2,
.icon_type = IT_DICE_OFF,
.choices = CHOICES("OFF", "Tv,ISO", "ISO,Tv"),
.help = "When you change Av, ML adjusts Tv and ISO to keep exposure.",
},
{
.name = "ISO -> ",
.priv = &expo_lock_iso,
.max = 2,
.icon_type = IT_DICE_OFF,
.choices = CHOICES("OFF", "Tv,Av", "Av,Tv"),
.help = "When you change ISO, ML adjusts Tv and Av to keep exposure.",
},
MENU_EOL
},
},
#endif
#ifdef FEATURE_EXPO_PRESET
{
.name = "Expo. Presets",
.priv = &expo_preset,
.max = 2,
.choices = CHOICES("OFF", "Press SET", "Press " INFO_BTN_NAME),
.help = "Quickly toggle between two expo presets (ISO,Tv,Av,Kelvin).",
.works_best_in = DEP_M_MODE,
},
#endif
MENU_PLACEHOLDER("Dual ISO"),
};
// for firing HDR shots - avoids random misfire due to low polling frequency
static int picture_was_taken_flag = 0;
void hdr_flag_picture_was_taken()
{
picture_was_taken_flag = 1;
}
#if defined(FEATURE_HDR_BRACKETING) || defined(FEATURE_FOCUS_STACKING)
int hdr_script_get_first_file_number(int skip0)
{
return MOD(get_shooting_card()->file_number + 1 - (skip0 ? 1 : 0), 10000);
}
// create a post script for HDR bracketing or focus stacking,
// starting from file number f0 till the current file_number
void hdr_create_script(int f0, int focus_stack)
{
if (!hdr_scripts) return;
#ifdef FEATURE_SNAP_SIM
if (snap_sim) return; // no script for virtual shots
#endif
int steps = MOD(get_shooting_card()->file_number - f0 + 1, 10000);
if (steps <= 1) return;
char name[100];
snprintf(name, sizeof(name), "%s/%s_%04d.%s", get_dcim_dir(), focus_stack ? "FST" : "HDR", f0, hdr_scripts == 3 ? "txt" : "sh");
FILE * f = FIO_CreateFile(name);
if (!f)
{
bmp_printf( FONT_LARGE, 30, 30, "FIO_CreateFile: error for %s", name );
return;
}
if (hdr_scripts == 1)
{
my_fprintf(f, "#!/usr/bin/env bash\n");
my_fprintf(f, "\n# %s_%04d.JPG from %s%04d.JPG ... %s%04d.JPG\n\n", focus_stack ? "FST" : "HDR", f0, get_file_prefix(), f0, get_file_prefix(), MOD(f0 + steps - 1, 10000));
my_fprintf(f, "enfuse \"$@\" %s --output=%s_%04d.JPG ", focus_stack ? "--exposure-weight=0 --saturation-weight=0 --contrast-weight=1 --hard-mask" : "", focus_stack ? "FST" : "HDR", f0);
for(int i = 0; i < steps; i++ )
{
my_fprintf(f, "%s%04d.JPG ", get_file_prefix(), MOD(f0 + i, 10000));
}
my_fprintf(f, "\n");
}
else if (hdr_scripts == 2)
{
my_fprintf(f, "#!/usr/bin/env bash\n");
my_fprintf(f, "\n# %s_%04d.JPG from %s%04d.JPG ... %s%04d.JPG with aligning first\n\n", focus_stack ? "FST" : "HDR", f0, get_file_prefix(), f0, get_file_prefix(), MOD(f0 + steps - 1, 10000));
my_fprintf(f, "align_image_stack -m -a %s_AIS_%04d", focus_stack ? "FST" : "HDR", f0);
for(int i = 0; i < steps; i++ )
{
my_fprintf(f, " %s%04d.JPG", get_file_prefix(), MOD(f0 + i, 10000));
}
my_fprintf(f, "\n");
my_fprintf(f, "enfuse \"$@\" %s --output=%s_%04d.JPG %s_AIS_%04d*\n", focus_stack ? "--contrast-window-size=9 --exposure-weight=0 --saturation-weight=0 --contrast-weight=1 --hard-mask" : "", focus_stack ? "FST" : "HDR", f0, focus_stack ? "FST" : "HDR", f0);
my_fprintf(f, "rm %s_AIS_%04d*\n", focus_stack ? "FST" : "HDR", f0);
}
else if (hdr_scripts == 3)
{
for(int i = 0; i < steps; i++ )
{
my_fprintf(f, " %s%04d.JPG", get_file_prefix(), MOD(f0 + i, 10000));
}
}
FIO_CloseFile(f);
NotifyBox(5000, "Saved %s\n%s%04d.JPG ... %s%04d.JPG", name + 17, get_file_prefix(), f0, get_file_prefix(), MOD(f0 + steps - 1, 10000));
}
#endif // HDR/FST
#ifdef FEATURE_INTERVALOMETER
// create a post script for sorting intervalometer sequences,
// starting from file number f0 till the current file_number
void interval_create_script(int f0)
{
if (!interval_scripts) return;
int steps = MOD(get_shooting_card()->file_number - f0 + 1, 10000);
if (steps <= 1) return;
char name[100];
if(interval_scripts == 1)
{
snprintf(name, sizeof(name), "%s/INTERVAL.sh", get_dcim_dir());
}
else if(interval_scripts == 2)
{
snprintf(name, sizeof(name), "%s/INTERVAL.bat", get_dcim_dir());
}
else if(interval_scripts == 3)
{
snprintf(name, sizeof(name), "%s/INTERVAL.txt", get_dcim_dir());
}
else
{
return;
}
int append_header = !is_file(name);
FILE * f = FIO_CreateFileOrAppend(name);
if (!f)
{
bmp_printf( FONT_LARGE, 30, 30, "FIO_CreateFileOrAppend: error for %s", name );
return;
}
if (interval_scripts == 1)
{
if (append_header)
{
my_fprintf(f, "#!/bin/bash \n");
}
my_fprintf(f, "\nmkdir INT_%04d\n", f0);
for(int i = 0; i < steps; i++ )
{
my_fprintf(f, "mv %s%04d.* INT_%04d\n", get_file_prefix(), MOD(f0 + i, 10000), f0);
}
}
else if (interval_scripts == 2)
{
my_fprintf(f, "\nMD INT_%04d\n", f0);
for(int i = 0; i < steps; i++ )
{
my_fprintf(f, "MOVE %s%04d.* INT_%04d\n", get_file_prefix(), MOD(f0 + i, 10000), f0);
}
}
else if(interval_scripts == 3)
{
my_fprintf(f, "\n*** New Sequence ***\n");
for(int i = 0; i < steps; i++ )
{
my_fprintf(f, "%s%04d.*\n", get_file_prefix(), MOD(f0 + i, 10000));
}
}
FIO_CloseFile(f);
NotifyBox(5000, "Saved %s", name);
}
#endif // FEATURE_INTERVALOMETER
// normal pic, silent pic, bulb pic...
// returns zero if successful, nonzero otherwise (user canceled, module error, etc)
int take_a_pic(int should_af)
{
int canceled = 0;
#ifdef FEATURE_SNAP_SIM
if (snap_sim) {
beep();
_card_led_on();
display_off();
msleep(250);
display_on();
_card_led_off();
msleep(100);
return canceled;
}
#endif
#ifdef CONFIG_MODULES
int cbr_result = 0;
if ((cbr_result = module_exec_cbr(CBR_CUSTOM_PICTURE_TAKING)) == CBR_RET_CONTINUE)
#endif
{
if (is_bulb_mode())
{
/* bulb mode? take a bulb exposure with bulb timer settings */
canceled = bulb_take_pic(bulb_duration * 1000);
}
else
{
lens_take_picture(64, should_af);
}
}
#ifdef CONFIG_MODULES
else
{
return cbr_result != CBR_RET_STOP;
}
#endif
lens_wait_readytotakepic(64);
return canceled;
}
// do a part of the bracket (half or full) with ISO
// return the remainder EV to be done normally (shutter, flash, whatever)
static int hdr_iso00;
static int hdr_iso_shift(int ev_x8)
{
hdr_iso00 = lens_info.raw_iso;
int iso0 = hdr_iso00;
if (!iso0) iso0 = lens_info.raw_iso_auto;
if (hdr_iso && iso0) // dynamic range optimization
{
if (ev_x8 < 0)
{
int iso_delta = MIN(iso0 - MIN_ISO, -ev_x8 / (hdr_iso == 2 ? 2 : 1)); // lower ISO, down to ISO 100
// if we are going to hit shutter speed limit, use more iso shifting, to get the correct bracket
int rs = lens_info.raw_shutter;
int rc = rs - (ev_x8 + iso_delta);
if (rc >= FASTEST_SHUTTER_SPEED_RAW)
iso_delta = MIN(iso0 - MIN_ISO, iso_delta + rc - FASTEST_SHUTTER_SPEED_RAW + 1);
iso_delta = (iso_delta+6)/8*8; // round to full stops; also, prefer lower ISOs
ev_x8 += iso_delta;
hdr_set_rawiso(iso0 - iso_delta);
}
else if (ev_x8 > 0)
{
int max_auto_iso = auto_iso_range & 0xFF;
int iso_delta = MIN(max_auto_iso - iso0, ev_x8 / (hdr_iso == 2 ? 2 : 1)); // raise ISO, up to max auto iso
iso_delta = (iso_delta)/8*8; // round to full stops; also, prefer lower ISOs
if (iso_delta < 0) iso_delta = 0;
ev_x8 -= iso_delta;
hdr_set_rawiso(iso0 + iso_delta);
}
}
return ev_x8;
}
static void hdr_iso_shift_restore()
{
hdr_set_rawiso(hdr_iso00);
}
// Here, you specify the correction in 1/8 EV steps (for shutter or exposure compensation)
// The function chooses the best method for applying this correction (as exposure compensation, altering shutter value, or bulb timer)
// And then it takes a picture
// .. and restores settings back
// Return value: 1 if OK, 0 if it couldn't set some parameter (but it will still take the shot)
static int hdr_shutter_release(int ev_x8)
{
int ans = 1;
//~ NotifyBox(2000, "hdr_shutter_release: %d", ev_x8); msleep(2000);
lens_wait_readytotakepic(64);
int manual = (shooting_mode == SHOOTMODE_M || is_movie_mode() || is_bulb_mode());
int dont_change_exposure = ev_x8 == 0 && !is_hdr_bracketing_enabled() && !is_bulb_mode();
if (dont_change_exposure)
{
take_a_pic(AF_DONT_CHANGE);
return 1;
}
// let's see if we have to do some other type of bracketing (aperture or flash)
int av0 = lens_info.raw_aperture;
if (is_hdr_bracketing_enabled())
{
if (hdr_type == 1) // flash => just set it
{
ev_x8 = hdr_iso_shift(ev_x8);
int fae0 = lens_info.flash_ae;
ans = hdr_set_flash_ae(fae0 + ev_x8) == 1;
take_a_pic(AF_DONT_CHANGE);
hdr_set_flash_ae(fae0);
hdr_iso_shift_restore();
return ans;
}
else if (hdr_type == 2) // aperture
{
ev_x8 = COERCE(-ev_x8, lens_info.raw_aperture_min - av0, lens_info.raw_aperture_max - av0);
ans = hdr_set_rawaperture(av0 + ev_x8) == 1;
if (!manual) ev_x8 = 0; // no need to compensate, Canon meter does it
// don't return, do the normal exposure bracketing
}
}
if (!manual) // auto modes
{
hdr_iso_shift(ev_x8); // don't change the EV value
int ae0 = lens_info.ae;
ans &= (hdr_set_ae(ae0 + ev_x8) == 1);
take_a_pic(AF_DONT_CHANGE);
hdr_set_ae(ae0);
hdr_iso_shift_restore();
}
else // manual mode or bulb
{
ev_x8 = hdr_iso_shift(ev_x8);
// apply EV correction in both "domains" (milliseconds and EV)
int ms = raw2shutter_ms(lens_info.raw_shutter);
#ifdef CONFIG_BULB
if(hdr_first_shot_bulb)
{
ms = bulb_duration*1000;
}
#endif
int msc = ms * roundf(1000.0f * powf(2, ev_x8 / 8.0f))/1000;
int rs = lens_info.raw_shutter;
#ifdef CONFIG_BULB
if(hdr_first_shot_bulb)
{
rs = shutter_ms_to_raw(bulb_duration*1000);
}
#endif
if (rs == 0) // shouldn't happen
{
msleep(1000);
rs = lens_info.raw_shutter; // maybe lucky this time?
ASSERT(rs);
}
int rc = rs - ev_x8;
int s0r = lens_info.raw_shutter; // save settings (for restoring them back)
#if defined(CONFIG_5D2) || defined(CONFIG_50D)
int expsim0 = get_expsim();
#endif
//~ NotifyBox(2000, "ms=%d msc=%d rs=%x rc=%x", ms,msc,rs,rc); msleep(2000);
#ifdef CONFIG_BULB
// then choose the best option (bulb for long exposures, regular for short exposures)
if (msc >= 20000 || is_bulb_mode())
{
bulb_take_pic(msc);
}
else
#endif
{
#if defined(CONFIG_5D2) || defined(CONFIG_50D)
if (get_expsim() == 2) { set_expsim(1); msleep(300); } // can't set shutter slower than 1/30 in movie mode
#endif
ans &= (hdr_set_rawshutter(rc) == 1);
take_a_pic(AF_DONT_CHANGE);
}
if (drive_mode == DRIVE_SELFTIMER_2SEC) msleep(2500);
if (drive_mode == DRIVE_SELFTIMER_REMOTE) msleep(10500);
// restore settings back
//~ set_shooting_mode(m0r);
#ifdef CONFIG_BULB
if(!hdr_first_shot_bulb)
#endif
{
hdr_set_rawshutter(s0r);
}
hdr_iso_shift_restore();
#if defined(CONFIG_5D2) || defined(CONFIG_50D)
if (expsim0 == 2) set_expsim(expsim0);
#endif
}
if (is_hdr_bracketing_enabled() && hdr_type == 2) // aperture bracket - restore initial value
hdr_set_rawaperture(av0);
lens_wait_readytotakepic(64);
return ans;
}
#ifdef FEATURE_HDR_BRACKETING
static int hdr_check_cancel(int init)
{
static int m;
if (init)
{
m = shooting_mode;
return 0;
}
extern int ml_started;
if (!ml_started)
return 0;
// cancel bracketing
if (shooting_mode != m || MENU_MODE)
{
beep();
lens_wait_readytotakepic(64);
NotifyBox(5000, "Bracketing stopped.");
return 1;
}
return 0;
}
static void ensure_play_or_qr_mode_after_shot()
{
/* wait until picture was captured */
msleep(300);
while (!job_state_ready_to_take_pic())
{
msleep(100);
}
msleep(500);
/* wait for Canon code to go into either QR/PLAY mode,
* or back to the shooting screen (LiveView or not) */
for (int i = 0; i < 20; i++)
{
msleep(100);
if (PLAY_OR_QR_MODE && DISPLAY_IS_ON)
break;
if (display_idle())
break;
}
/* image review disabled? */
if (!PLAY_OR_QR_MODE)
{
/* check this one once again, just in case */
while (!job_state_ready_to_take_pic())
{
msleep(100);
}
/* force PLAY mode */
enter_play_mode();
}
}
static void hdr_check_for_under_or_over_exposure(int* under, int* over)
{
if (hdr_type == 2) // DOF bracket => just repeat until reaching the limits
{
*under = 1;
*over = 1;
return;
}
ensure_play_or_qr_mode_after_shot();
int under_numpix, over_numpix;
int total_numpix = get_under_and_over_exposure(20, 235, &under_numpix, &over_numpix);
int po = over_numpix * 10000 / total_numpix;
int pu = under_numpix * 10000 / total_numpix;
if (over_numpix > 0) po = MAX(po, 1);
if (under_numpix > 0) pu = MAX(pu, 1);
*over = po > 15; // 0.15 % highlight ignore
*under = pu > 250; // 2.50 % shadow ignore
bmp_printf(
FONT_LARGE, 50, 50,
"Under:%3d.%02d%%\n"
"Over :%3d.%02d%%",
pu/100, pu%100, 0,
po/100, po%100, 0
);
msleep(500);
}
static int hdr_shutter_release_then_check_for_under_or_over_exposure(int ev_x8, int* under, int* over)
{
int ans = hdr_shutter_release(ev_x8);
hdr_check_for_under_or_over_exposure(under, over);
return ans;
}
static void hdr_auto_take_pics(int step_size, int skip0)
{
int i;
// make sure it won't autofocus
lens_setup_af(AF_DISABLE);
// be careful: don't return without restoring the setting back!
hdr_check_cancel(1);
int UNDER = 1;
int OVER = 1;
int under, over;
// first frame for the bracketing script
int f0 = hdr_script_get_first_file_number(skip0);
// first exposure is always at 0 EV (and might be skipped)
if (!skip0) hdr_shutter_release_then_check_for_under_or_over_exposure(0, &under, &over);
else hdr_check_for_under_or_over_exposure(&under, &over);
if (!under) UNDER = 0; if (!over) OVER = 0;
if (hdr_check_cancel(0)) goto end;
switch (hdr_sequence)
{
case 1: // 0 - + -- ++
{
for( i = 1; i <= 20; i ++ )
{
if (OVER)
{
int ok = hdr_shutter_release_then_check_for_under_or_over_exposure(-step_size * i, &under, &over);
if (!under) UNDER = 0; if (!over) OVER = 0;
if (!ok) OVER = 0; // Canon limit reached, don't continue this sequence
if (hdr_check_cancel(0)) goto end;
}
if (UNDER)
{
int ok = hdr_shutter_release_then_check_for_under_or_over_exposure(step_size * i, &under, &over);
if (!under) UNDER = 0; if (!over) OVER = 0;
if (!ok) UNDER = 0; // Canon limit reached, don't continue this sequence
if (hdr_check_cancel(0)) goto end;
}
}
break;
}
case 0: // 0 - -- => will only check highlights
{
for( i = 1; i < 20; i ++ )
{
if (OVER)
{
int ok = hdr_shutter_release_then_check_for_under_or_over_exposure(-step_size * i, &under, &over);
if (!under) UNDER = 0; if (!over) OVER = 0;
if (!ok) OVER = 0;
if (hdr_check_cancel(0)) goto end;
}
}
break;
}
case 2: // 0 + ++
{
for( i = 1; i < 20; i ++ )
{
if (UNDER)
{
int ok = hdr_shutter_release_then_check_for_under_or_over_exposure(step_size * i, &under, &over);
if (!under) UNDER = 0; if (!over) OVER = 0;
if (!ok) UNDER = 0;
if (hdr_check_cancel(0)) goto end;
}
}
break;
}
}
hdr_create_script(f0, 0);
end:
lens_cleanup_af();
}
// skip0: don't take the middle exposure
static void hdr_take_pics(int steps, int step_size, int skip0)
{
if (steps < 2) // auto number of steps, based on highlight/shadow levels
{
hdr_auto_take_pics(step_size, skip0);
return;
}
//~ NotifyBox(2000, "hdr_take_pics: %d, %d, %d", steps, step_size, skip0); msleep(2000);
int i;
// make sure it won't autofocus
lens_setup_af(AF_DISABLE);
// be careful: don't return without restoring the setting back!
hdr_check_cancel(1);
// first frame for the bracketing script
int f0 = hdr_script_get_first_file_number(skip0);
// first exposure is always at 0 EV (and might be skipped)
if (!skip0) hdr_shutter_release(0);
if (hdr_check_cancel(0)) goto end;
while (HALFSHUTTER_PRESSED)
{
msleep(100);
}
#ifdef CONFIG_BULB
// first exposure is bulb mode
if(is_bulb_mode() && bulb_timer)
{
hdr_first_shot_bulb = 1;
}
#endif
switch (hdr_sequence)
{
case 1: // 0 - + -- ++
{
for( i = 1; i <= steps/2; i ++ )
{
hdr_shutter_release(-step_size * i);
if (hdr_check_cancel(0)) goto end;
if (steps % 2 == 0 && i == steps/2) break;
hdr_shutter_release(step_size * i);
if (hdr_check_cancel(0)) goto end;
}
break;
}
case 0: // 0 - --
case 2: // 0 + ++
{
for( i = 1; i < steps; i ++ )
{
#ifdef CONFIG_BULB
//do not skip frames with Bulb Timer
if(hdr_first_shot_bulb)
{
while (lens_info.job_state) msleep(100);
}
#endif
hdr_shutter_release(step_size * i * (hdr_sequence == 2 ? 1 : -1));
if (hdr_check_cancel(0)) goto end;
}
break;
}
}
#ifdef CONFIG_BULB
if(hdr_first_shot_bulb)
{
ensure_bulb_mode();
hdr_first_shot_bulb = 0;
}
#endif
hdr_create_script(f0, 0);
end:
lens_cleanup_af();
}
#endif
static void press_rec_button()
{
#if defined(CONFIG_50D) || defined(CONFIG_5D2)
fake_simple_button(BGMT_PRESS_SET);
#else
fake_simple_button(BGMT_LV);
#endif
}
void movie_start()
{
#ifdef CONFIG_MOVIE
while (get_halfshutter_pressed()) msleep(100);
if (!job_state_ready_to_take_pic()) return;
ensure_movie_mode();
if (RECORDING)
{
NotifyBox(2000, "Already recording ");
return;
}
#if defined(CONFIG_500D) || defined(CONFIG_50D) || defined(CONFIG_5D2) // record button is used in ML menu => won't start recording
//~ gui_stop_menu(); msleep(1000);
while (gui_menu_shown())
{
gui_stop_menu();
msleep(1000);
}
#endif
while (get_halfshutter_pressed()) msleep(100);
press_rec_button();
for (int i = 0; i < 30; i++)
{
msleep(100);
if (RECORDING_H264_STARTED) break; // recording started
}
msleep(500);
#endif
}
void movie_end()
{
#ifdef CONFIG_MOVIE
if (shooting_type != 3 && !is_movie_mode())
{
NotifyBox(2000, "movie_end: not movie mode (%d,%d) ", shooting_type, shooting_mode);
return;
}
if (NOT_RECORDING)
{
NotifyBox(2000, "movie_end: not recording ");
return;
}
while (get_halfshutter_pressed()) msleep(100);
msleep(500);
press_rec_button();
// wait until it stops recording, but not more than 2s
for (int i = 0; i < 20; i++)
{
msleep(100);
if (NOT_RECORDING) break;
}
msleep(500);
#endif
}
// take one picture or a HDR / focus stack sequence
// to be used with the intervalometer, focus stack, etc
// AF is disabled (don't enable it here, it will only introduce weird bugs)
void hdr_shot(int skip0, int wait)
{
NotifyBoxHide();
#ifdef FEATURE_HDR_BRACKETING
if (is_hdr_bracketing_enabled())
{
//~ NotifyBox(1000, "HDR shot (%dx%dEV)...", hdr_steps, hdr_stepsize/8); msleep(1000);
lens_wait_readytotakepic(64);
int drive_mode_bak = set_drive_single();
hdr_take_pics(hdr_steps, hdr_stepsize, skip0);
lens_wait_readytotakepic(64);
if (drive_mode_bak >= 0) lens_set_drivemode(drive_mode_bak);
}
else // regular pic (not HDR)
#endif
{
lens_setup_af(AF_DISABLE);
hdr_shutter_release(0);
lens_cleanup_af();
}
lens_wait_readytotakepic(64);
picture_was_taken_flag = 0;
}
int remote_shot_flag = 0; // also in lcdsensor.c
void schedule_remote_shot() { remote_shot_flag = 1; }
static int movie_start_flag = 0;
void schedule_movie_start() { movie_start_flag = 1; }
//~ int is_movie_start_scheduled() { return movie_start_flag; }
static int movie_end_flag = 0;
void schedule_movie_end() { movie_end_flag = 1; }
/* exit from PLAY or QR modes (to LiveView or plain photo mode) */
void exit_play_qr_mode()
{
/* not there? */
if (!PLAY_OR_QR_MODE) return;
/* request new mode */
SetGUIRequestMode(0);
/* wait up to 2 seconds */
for (int i = 0; i < 20 && PLAY_MODE; i++)
{
msleep(100);
}
/* wait a little extra for the new mode to settle */
msleep(200);
/* if in LiveView, wait for the first frame */
if (lv)
{
wait_lv_frames(1);
}
}
/* enter PLAY mode */
void enter_play_mode()
{
if (PLAY_MODE) return;
/* request new mode */
SetGUIRequestMode(DLG_PLAY);
/* wait up to 2 seconds to enter the PLAY mode */
for (int i = 0; i < 20 && !PLAY_MODE; i++)
{
msleep(100);
}
/* also wait for display to come up, up to 1 second */
for (int i = 0; i < 10 && !DISPLAY_IS_ON; i++)
{
msleep(100);
}
/* wait a little extra for the new mode to settle */
msleep(200);
}
// take one shot, a sequence of HDR shots, or start a movie
// to be called by remote triggers
void remote_shot(int wait)
{
// save zoom value (x1, x5 or x10)
int zoom = lv_dispsize;
#ifdef FEATURE_FOCUS_STACKING
if (is_focus_stack_enabled())
{
focus_stack_run(0);
}
else
#endif
if (is_movie_mode())
{
movie_start();
}
else if (is_hdr_bracketing_enabled())
{
hdr_shot(0, wait);
}
else
{
take_fast_pictures(pics_to_take_at_once+1);
}
if (!wait) return;
lens_wait_readytotakepic(64);
msleep(500);
while (gui_state != GUISTATE_IDLE) msleep(100);
msleep(500);
// restore zoom
if (lv && NOT_RECORDING && zoom > 1) set_lv_zoom(zoom);
picture_was_taken_flag = 0;
}
static void display_expsim_status()
{
#ifdef CONFIG_EXPSIM
get_yuv422_vram();
static int prev_expsim = 0;
int x = 610 + font_med.width;
int y = os.y_max - os.off_169 - font_med.height - 5;
if (!get_expsim())
{
bmp_printf( FONT(FONT_MED, COLOR_WHITE, 0), x, y, " ExpSim " );
draw_line(x-5 + font_med.width, y + font_med.height * 3/4, x + font_med.width * 7, y + font_med.height * 1/4, COLOR_WHITE);
}
else
{
if (get_expsim() != prev_expsim)// redraw();
bmp_printf( FONT(FONT_MED, COLOR_WHITE, 0), x, y, " " );
}
prev_expsim = get_expsim();
#endif
}
void display_shooting_info_lv()
{
#ifndef CONFIG_5D2
#ifdef FEATURE_LCD_SENSOR_REMOTE
int screen_layout = get_screen_layout();
int audio_meters_at_top = audio_meters_are_drawn()
&& (screen_layout == SCREENLAYOUT_3_2);
display_lcd_remote_icon(450, audio_meters_at_top ? 25 : 3);
#endif
#endif
display_trap_focus_info();
display_expsim_status();
}
static void display_trap_focus_msg()
{
#ifdef FEATURE_TRAP_FOCUS
#ifndef DISPLAY_TRAP_FOCUSMSG_POS_X
#define DISPLAY_TRAP_FOCUSMSG_POS_X 10
#define DISPLAY_TRAP_FOCUSMSG_POS_Y 10
#endif
int bg = bmp_getpixel(DISPLAY_TRAP_FOCUS_POS_X, DISPLAY_TRAP_FOCUS_POS_Y);
int fg = COLOR_FG_NONLV;
char *msg = " \n \n ";
switch(trap_focus_msg)
{
case TRAP_ERR_CFN:
msg = "Trap Focus: \nCFn Fail. Set AF\n to shutter btn ";
break;
case TRAP_IDLE:
msg = "Trap Focus: \nIDLE, press half\nshutter shortly ";
break;
case TRAP_ACTIVE:
msg = "Trap Focus: \nACTIVE, keys are\ncurrently locked";
break;
}
static int dirty = 0;
if (trap_focus_msg)
{
bmp_printf(
FONT(FONT_MED, fg, bg) | FONT_ALIGN_LEFT | FONT_ALIGN_FILL,
DISPLAY_TRAP_FOCUSMSG_POS_X, DISPLAY_TRAP_FOCUSMSG_POS_Y,
msg
);
dirty = 1;
}
else if (dirty) // clean old message, if any
{
redraw();
dirty = 0;
}
#endif
}
void display_trap_focus_info()
{
#ifdef FEATURE_TRAP_FOCUS
int show, fg, bg, x, y;
static int show_prev = 0;
if (lv)
{
show = trap_focus && can_lv_trap_focus_be_active();
int active = show && get_halfshutter_pressed();
bg = active ? COLOR_BG : 0;
fg = active ? COLOR_RED : COLOR_BG;
x = 8; y = 160;
if (show || show_prev)
{
bmp_printf(FONT(FONT_MED, fg, bg), x, y, show ? "TRAP \nFOCUS" : " \n ");
}
}
else
{
show = (trap_focus && ((af_mode & 0xF) == 3) && lens_info.raw_aperture);
bg = bmp_getpixel(DISPLAY_TRAP_FOCUS_POS_X, DISPLAY_TRAP_FOCUS_POS_Y);
fg = HALFSHUTTER_PRESSED ? COLOR_RED : COLOR_FG_NONLV;
x = DISPLAY_TRAP_FOCUS_POS_X; y = DISPLAY_TRAP_FOCUS_POS_Y;
if (show || show_prev) bmp_printf(FONT(FONT_MED, fg, bg), x, y, show ? DISPLAY_TRAP_FOCUS_MSG : DISPLAY_TRAP_FOCUS_MSG_BLANK);
display_trap_focus_msg();
}
show_prev = show;
#endif
}
void intervalometer_stop()
{
#ifdef FEATURE_INTERVALOMETER
if (intervalometer_running)
{
intervalometer_running = 0;
NotifyBox(2000, "Intervalometer stopped.");
interval_create_script(MOD(get_shooting_card()->file_number - intervalometer_pictures_taken + 1, 10000));
//~ display_on();
}
#endif
}
static void intervalometer_check_trigger()
{
if (interval_enabled)
{
if (gui_menu_shown()) /* in ML menu */
{
/* if we use the Leave Menu option, just trigger it (will start running as soon as we are leaving the menu) */
/* if we use some other trigger, disable it and require a re-trigger (maybe we changed some setting) */
intervalometer_running = (interval_trigger == INTERVAL_TRIGGER_LEAVE_MENU);
}
else /* outside menu */
{
if (!intervalometer_running)
{
/* intervalometer expecting some kind of trigger? say so */
if (interval_trigger != INTERVAL_TRIGGER_LEAVE_MENU)
{
bmp_printf(FONT_LARGE, 50, 310,
" Intervalometer: waiting for %s...\n",
interval_trigger == INTERVAL_TRIGGER_HALF_SHUTTER ? "half-shutter" : "first picture"
);
}
if (interval_trigger == INTERVAL_TRIGGER_HALF_SHUTTER)
{
/* trigger intervalometer start on half shutter */
if (get_halfshutter_pressed())
{
/* require a somewhat long press to avoid trigger on menu close */
msleep(500);
if (get_halfshutter_pressed())
{
beep();
redraw();
intervalometer_running = 1;
while (get_halfshutter_pressed()) msleep(100);
}
}
}
/* INTERVAL_TRIGGER_TAKE_PIC was already handled in the HDR bracketing trigger */
}
}
}
else
{
/* if intervalometer is disabled from menu, make sure it's not running */
intervalometer_running = 0;
}
}
int handle_intervalometer(struct event * event)
{
#ifdef FEATURE_INTERVALOMETER
// stop intervalometer with MENU or PLAY
if (!IS_FAKE(event) && (event->param == BGMT_MENU || event->param == BGMT_PLAY) && !gui_menu_shown())
intervalometer_stop();
#endif
return 1;
}
// this syncs with DIGIC clock from clock_task
void wait_till_next_second()
{
int prev_t = get_seconds_clock();
while (1)
{
int t = get_seconds_clock();
if (t != prev_t) break;
prev_t = t;
msleep(20);
}
}
#ifdef FEATURE_MLU_DIRECT_PRINT_SHORTCUT
// use direct print button to toggle MLU and display its status
int handle_mlu_toggle(struct event * event)
{
if (event->param == BGMT_PRESS_DIRECT_PRINT && display_idle())
{
int m = !get_mlu();
set_mlu(m);
if (mlu_auto)
{
static int prev_drive_mode = DRIVE_SINGLE;
if (m)
{
if (drive_mode != DRIVE_SELFTIMER_REMOTE) prev_drive_mode = drive_mode;
lens_set_drivemode(DRIVE_SELFTIMER_REMOTE);
}
else
{
lens_set_drivemode(prev_drive_mode);
}
}
return 0;
}
return 1;
}
#endif
#ifdef FEATURE_MLU
PROP_HANDLER(PROP_DRIVE)
{
drive_mode = buf[0];
mlu_selftimer_update();
}
static void mlu_step()
{
if (lv) return;
#ifdef FEATURE_MLU_DIRECT_PRINT_SHORTCUT
int mlu = get_mlu();
static int prev_mlu = 0;
if (mlu) info_led_on();
else if (prev_mlu) info_led_off();
prev_mlu = mlu;
#endif
if (MLU_ALWAYS_ON)
{
if (!get_mlu()) set_mlu(1);
}
}
#endif
// continuous, hi-speed, silent continuous, depending on the camera
int is_continuous_drive()
{
return
(
drive_mode == DRIVE_CONTINUOUS
#ifdef DRIVE_HISPEED_CONTINUOUS
|| drive_mode == DRIVE_HISPEED_CONTINUOUS
#endif
#ifdef DRIVE_SILENT_CONTINUOUS
|| drive_mode == DRIVE_SILENT_CONTINUOUS
#endif
);
}
int take_fast_pictures( int number )
{
int canceled = 0;
// take fast pictures
#ifdef CONFIG_PROP_REQUEST_CHANGE
if ( number > 1 && is_continuous_drive() && !is_bulb_mode() && !snap_sim)
{
lens_setup_af(shoot_use_af ? AF_ENABLE : AF_DISABLE);
// continuous mode - simply hold shutter pressed
int f0 = get_shooting_card()->file_number;
SW1(1,100);
SW2(1,100);
while (MOD(f0 + number - get_shooting_card()->file_number + 10, 10000) > 10 && get_halfshutter_pressed()) {
msleep(10);
}
SW2(0,100);
SW1(0,100);
#if defined(CONFIG_7D)
/* on EOS 7D the code to trigger SW1/SW2 is buggy that the metering somehow locks up.
* This causes the camera not to shut down when the card door is opened.
* There is a workaround: Just wait until shooting is possible again and then reset SW1.
* Then the camera will shut down clean.
*/
lens_wait_readytotakepic(64);
SW1(0,0);
#endif
lens_cleanup_af();
}
else
#endif
{
for (int i = 0; i < number; i++)
{
canceled = take_a_pic(shoot_use_af ? AF_ENABLE : AF_DISABLE);
if(canceled) break;
}
}
return canceled;
}
#ifdef FEATURE_MOTION_DETECT
static void md_take_pics() // for motion detection
{
if (motion_detect_delay > 1) {
for (int t=0; t<(int)motion_detect_delay; t++) {
bmp_printf(FONT_MED, 0, 80, " Taking picture in %d.%ds ", (int)(motion_detect_delay-t)/10, (int)(motion_detect_delay-t)%10);
msleep(100);
int mdx = motion_detect && (liveview_display_idle() || (lv && !DISPLAY_IS_ON)) && NOT_RECORDING && !gui_menu_shown();
if (!mdx) return;
}
}
take_fast_pictures( pics_to_take_at_once+1 );
// wait until liveview comes back
lens_wait_readytotakepic(64);
for (int i = 0; i < 50; i++)
{
msleep(100);
if (lv) break;
}
msleep(1000);
}
#endif
static struct msg_queue * shoot_task_mqueue = NULL;
/* cause an immediate redraw of the shooting task infos. not used yet, but can be triggered by model-specific code */
void shoot_task_redraw()
{
if(shoot_task_mqueue)
{
msg_queue_post(shoot_task_mqueue, 1);
}
}
static void misc_shooting_info()
{
if (!DISPLAY_IS_ON) return;
/* from ph_info_disp.c */
extern void display_shortcut_key_hints_lv();
extern void display_shooting_info();
display_shortcut_key_hints_lv();
if (get_global_draw())
{
#ifdef CONFIG_PHOTO_MODE_INFO_DISPLAY
if (!lv && display_idle())
BMP_LOCK
(
display_shooting_info();
#ifndef FEATURE_FLEXINFO
free_space_show_photomode();
#endif
)
#endif
if (lv && !gui_menu_shown())
{
BMP_LOCK (
display_shooting_info_lv();
)
#ifdef CONFIG_MOVIE_AE_WARNING
#if defined(CONFIG_5D2)
static int ae_warned = 0;
if (is_movie_mode() && !lens_info.raw_shutter && RECORDING && MVR_FRAME_NUMBER < 10)
{
if (!ae_warned && !gui_menu_shown())
{
msleep(2000);
bmp_printf(SHADOW_FONT(FONT_MED), 50, 50,
"!!! Auto exposure !!!\n"
"Use M mode and set 'LV display: Movie' from Expo menu");
msleep(4000);
redraw();
ae_warned = 1;
}
}
else ae_warned = 0;
#else
if (is_movie_mode() && !ae_mode_movie && lv_dispsize == 1)
{
static int ae_warned = 0;
if (!ae_warned && !gui_menu_shown())
{
bmp_printf(SHADOW_FONT(FONT_MED), 50, 50,
"!!! Auto exposure !!!\n"
"Set 'Movie Exposure -> Manual' from Canon menu");
msleep(2000);
redraw();
ae_warned = 1;
}
}
#endif
#endif
if (EXT_MONITOR_RCA)
{
static int rca_warned = 0;
if (!rca_warned && !gui_menu_shown())
{
msleep(2000);
if (EXT_MONITOR_RCA) // check again
{
bmp_printf(SHADOW_FONT(FONT_LARGE), 50, 50,
"SD monitors NOT fully supported!\n"
"RGB tools and MZoom won't work. ");
msleep(4000);
redraw();
rca_warned = 1;
}
}
}
}
}
}
static void
shoot_task( void* unused )
{
/* this is used to determine if a feature is active that requires high task rate */
int priority_feature_enabled = 0;
/* creating a message queue primarily for interrupting sleep to repaint immediately */
shoot_task_mqueue = (void*)msg_queue_create("shoot_task_mqueue", 1);
#ifdef FEATURE_MLU
mlu_selftimer_update();
#endif
#ifdef FEATURE_INTERVALOMETER
if (interval_enabled && interval_trigger == 0)
{
/* auto-start intervalometer, but wait for at least 15 seconds */
/* (to give the user a chance to turn it off) */
intervalometer_running = 1;
intervalometer_next_shot_time = seconds_clock + MAX(interval_start_time, 15);
}
#endif
/*int loops = 0;
int loops_abort = 0;*/
TASK_LOOP
{
int msg;
int delay = 50;
/* specify the maximum wait time */
if(!DISPLAY_IS_ON)
{
delay = 200;
}
if(priority_feature_enabled)
{
delay = MIN_MSLEEP;
}
int err = msg_queue_receive(shoot_task_mqueue, (struct event**)&msg, delay);
priority_feature_enabled = 0;
/* when we received a message, redraw immediately */
if (k%5 == 0 || !err) misc_shooting_info();
#if defined(CONFIG_MODULES)
module_exec_cbr(CBR_SHOOT_TASK);
#endif
#ifdef FEATURE_MLU_HANDHELD_DEBUG
if (mlu_handled_debug) big_bmp_printf(FONT_MED, 50, 100, "%s", mlu_msg);
#endif
#ifdef FEATURE_LCD_SENSOR_REMOTE
if (lcd_release_running)
priority_feature_enabled = 1;
#endif
#ifdef FEATURE_WHITE_BALANCE
if (kelvin_auto_flag)
{
kelvin_auto_run();
kelvin_auto_flag = 0;
}
if (wbs_gm_auto_flag)
{
wbs_gm_auto_run();
wbs_gm_auto_flag = 0;
}
#endif
#ifdef FEATURE_LCD_SENSOR_REMOTE
lcd_release_step();
#endif
#ifdef FEATURE_EXPO_LOCK
expo_lock_step();
#endif
if (remote_shot_flag)
{
remote_shot(1);
remote_shot_flag = 0;
}
#ifdef CONFIG_MOVIE
if (movie_start_flag)
{
movie_start();
movie_start_flag = 0;
}
if (movie_end_flag)
{
movie_end();
movie_end_flag = 0;
}
#endif
#ifdef FEATURE_LV_ZOOM_SETTINGS
if (zoom_focus_ring_flag)
{
zoom_focus_ring_engage();
zoom_focus_ring_flag = 0;
}
zoom_halfshutter_step();
zoom_focus_ring_step();
#endif
#ifdef FEATURE_MLU
mlu_step();
#endif
#ifdef FEATURE_LV_FOCUS_BOX_SNAP
if (center_lv_aff)
{
center_lv_afframe_do();
center_lv_aff = 0;
}
#endif
#ifdef FEATURE_LV_ZOOM_SETTINGS
zoom_auto_exposure_step();
#endif
#if defined(FEATURE_HDR_BRACKETING)
// avoid camera shake for HDR shots => force self timer
static int drive_mode_bk = -1;
if ((is_hdr_bracketing_enabled() && hdr_delay) && drive_mode != DRIVE_SELFTIMER_2SEC && drive_mode != DRIVE_SELFTIMER_REMOTE)
{
priority_feature_enabled = 1;
if (get_halfshutter_pressed())
{
drive_mode_bk = drive_mode;
#ifndef CONFIG_5DC
lens_set_drivemode(DRIVE_SELFTIMER_2SEC);
#endif
info_led_on();
msleep(100);
}
}
// restore drive mode if it was changed
if (!get_halfshutter_pressed() && drive_mode_bk >= 0)
{
msleep(50);
lens_set_drivemode(drive_mode_bk);
drive_mode_bk = -1;
info_led_off();
msleep(100);
}
#endif
#ifdef FEATURE_BULB_TIMER
if (bulb_timer && is_bulb_mode() && !gui_menu_shown())
{
// look for a transition of half-shutter during idle state
static int was_idle_not_pressed = 0;
int is_idle_not_pressed = !get_halfshutter_pressed() && display_idle();
int is_idle_and_pressed = get_halfshutter_pressed() && display_idle();
int trigger_condition = was_idle_not_pressed && is_idle_and_pressed;
was_idle_not_pressed = is_idle_not_pressed;
if (trigger_condition)
{
info_led_on();
// need to keep halfshutter pressed for one second
for (int i = 0; i < 10; i++)
{
msleep(100);
if (!get_halfshutter_pressed() || !job_state_ready_to_take_pic()) break;
}
if (!get_halfshutter_pressed() || !job_state_ready_to_take_pic()) { info_led_off(); continue; }
beep();
info_led_blink(1,50,50); // short blink so you know bulb timer was triggered
info_led_on();
int d = bulb_duration;
NotifyBox(10000, "[HalfShutter] Bulb timer: %s", format_time_hours_minutes_seconds(d));
while (get_halfshutter_pressed())
{
msleep(100);
}
int m0 = shooting_mode;
wait_till_next_second();
NotifyBox(2000, "[2s] Bulb timer: %s", format_time_hours_minutes_seconds(d));
info_led_on();
wait_till_next_second();
if (get_halfshutter_pressed() || !display_idle() || m0 != shooting_mode || !job_state_ready_to_take_pic())
{
NotifyBox(2000, "Bulb timer canceled.");
info_led_off();
continue;
}
NotifyBox(2000, "[1s] Bulb timer: %s", format_time_hours_minutes_seconds(d));
info_led_on();
wait_till_next_second();
if (get_halfshutter_pressed() || !display_idle() || m0 != shooting_mode || !job_state_ready_to_take_pic())
{
NotifyBox(2000, "Bulb timer canceled.");
info_led_off();
continue;
}
info_led_off();
bulb_take_pic(d * 1000);
}
}
#endif
if (picture_was_taken_flag) // just took a picture, maybe we should take another one
{
if (NOT_RECORDING)
{
#ifdef FEATURE_HDR_BRACKETING
if (is_hdr_bracketing_enabled())
{
lens_wait_readytotakepic(64);
hdr_shot(1,1); // skip the middle exposure, which was just taken
lens_wait_readytotakepic(64);
}
#endif
#ifdef FEATURE_INTERVALOMETER
if(interval_enabled && interval_trigger == INTERVAL_TRIGGER_TAKE_PIC && !intervalometer_running)
{
intervalometer_running = 1;
intervalometer_pictures_taken = 1;
int dt = get_interval_time();
intervalometer_next_shot_time = COERCE(intervalometer_next_shot_time + dt, seconds_clock, seconds_clock + dt);
#ifdef CONFIG_MODULES
module_exec_cbr(CBR_INTERVALOMETER);
#endif
}
#endif
}
picture_was_taken_flag = 0;
}
#ifdef FEATURE_FLASH_TWEAKS
#ifdef FEATURE_FLASH_NOFLASH
// toggle flash on/off for next picture
if (!is_movie_mode() && flash_and_no_flash && strobo_firing < 2 && strobo_firing != get_shooting_card()->file_number % 2)
{
strobo_firing = get_shooting_card()->file_number % 2;
set_flash_firing(strobo_firing);
}
static int prev_flash_and_no_flash;
if (!flash_and_no_flash && prev_flash_and_no_flash && strobo_firing==1)
set_flash_firing(0);
prev_flash_and_no_flash = flash_and_no_flash;
#endif
#ifdef FEATURE_LV_3RD_PARTY_FLASH
/* when pressing half-shutter in LV mode, this code will first switch to photo mode, wait for half-
shutter release and then switches back. this will fire external flashes when running in LV mode.
*/
if (lv_3rd_party_flash && !is_movie_mode())
{
if (lv && get_halfshutter_pressed())
{
/* timeout after 2 minutes */
uint32_t loops = 1200;
/* unpress half-shutter, maybe not really needed but might prevent confusion of gui tasks */
SW1(0,100);
/* switch into normal mode */
fake_simple_button(BGMT_LV);
while (lv && loops--)
{
msleep(100);
}
msleep(200);
/* re-press half-shutter */
SW1(1,200);
bmp_printf(FONT_MED, 0, 0, "(take pic or release half-shutter)");
/* timeout after 2 minutes */
loops = 1200;
/* and wait for being released again */
while (get_halfshutter_pressed() && loops--) msleep(100);
if(loops)
{
/* switch into LV mode again */
fake_simple_button(BGMT_LV);
}
}
}
#endif
#endif
#ifdef FEATURE_TRAP_FOCUS
// trap focus (outside LV) and all the preconditions
int tfx = trap_focus && is_manual_focus() && display_idle() && !intervalometer_running && !is_movie_mode();
static int trap_focus_display_time = 0;
/* in continuous mode force half shutter being pressed */
switch(trap_focus_continuous_state)
{
case 0:
/* do this only in continuous mode */
if(trap_focus == 2)
{
if(cfn_get_af_button_assignment()!=0)
{
if(should_run_polling_action(250, &trap_focus_display_time) && !gui_menu_shown())
{
trap_focus_msg = TRAP_ERR_CFN;
}
}
else if(HALFSHUTTER_PRESSED)
{
/* user requested enabling trap focus */
trap_focus_continuous_state = 1;
}
else
{
if(should_run_polling_action(250, &trap_focus_display_time) && !gui_menu_shown())
{
trap_focus_msg = TRAP_IDLE;
}
}
}
else
{
trap_focus_msg = TRAP_NONE;
}
break;
case 1:
/* wait for user to release his shutter button, then set it on our own */
if(!HALFSHUTTER_PRESSED)
{
trap_focus_continuous_state = 2;
SW1(1,50);
}
break;
case 2:
info_led_off();
priority_feature_enabled = 1;
/* some abort situation happened? */
if(gui_menu_shown() || !display_idle() || !HALFSHUTTER_PRESSED || !tfx || trap_focus != 2)
{
trap_focus_continuous_state = 0;
SW1(0,50);
}
else
{
if(should_run_polling_action(250, &trap_focus_display_time))
{
trap_focus_msg = TRAP_ACTIVE;
}
}
break;
case 3:
/* re-enable after pic was taken */
trap_focus_continuous_state = 1;
priority_feature_enabled = 1;
SW1(1,50);
break;
}
#endif
#ifdef FEATURE_MOTION_DETECT
if (motion_detect && motion_detect_trigger < 2 && !lv && display_idle() && !gui_menu_shown())
{
// plain photo mode, go to LiveView
force_liveview();
}
// same for motion detect
int mdx = motion_detect && (liveview_display_idle() || (lv && !DISPLAY_IS_ON)) && NOT_RECORDING && !gui_menu_shown() && !intervalometer_running;
#else
int mdx = 0;
#endif
#ifdef FEATURE_TRAP_FOCUS
if (tfx) // MF
{
static int info_led_turned_on = 0;
if (HALFSHUTTER_PRESSED)
{
info_led_on();
info_led_turned_on = 1;
}
else if (info_led_turned_on)
{
info_led_off();
info_led_turned_on = 0;
}
if ((!lv && FOCUS_CONFIRMATION) || get_lv_focus_confirmation())
{
take_fast_pictures(pics_to_take_at_once+1);
/* continuous shooting active? */
if (trap_focus_continuous_state)
{
/* wait the review time then re-engage again */
if (image_review_time)
{
msleep(2000);
}
trap_focus_continuous_state = 3;
}
}
}
#endif
#ifdef FEATURE_MOTION_DETECT
//Reset the counter so that if you go in and out of live view, it doesn't start clicking away right away.
static int K = 0;
if(!mdx) K = 0;
if (mdx)
{
priority_feature_enabled = 1;
K = COERCE(K+1, 0, 1000);
//~ bmp_printf(FONT_MED, 0, 50, "K= %d ", K);
int xcb = os.x0 + os.x_ex/2;
int ycb = os.y0 + os.y_ex/2;
int detect_size =
motion_detect_size == 0 ? 80 :
motion_detect_size == 1 ? 120 :
200 ;
// center the motion detection window on focus box
{
get_afframe_pos(os.x_ex, os.y_ex, &xcb, &ycb);
xcb += os.x0;
ycb += os.y0;
xcb = COERCE(xcb, os.x0 + (int)detect_size, os.x_max - (int)motion_detect_size );
ycb = COERCE(ycb, os.y0 + (int)detect_size, os.y_max - (int)motion_detect_size );
}
if (motion_detect_trigger == 0)
{
int aev = 0;
//If the new value has changed by more than the detection level, shoot.
static int old_ae_avg = 0;
int y,u,v;
//TODO: maybe get the spot yuv of the target box
get_spot_yuv_ex(detect_size, xcb-os.x_max/2, ycb-os.y_max/2, &y, &u, &v, 1, 1);
aev = y / 2;
if (K > 40) bmp_printf(FONT_MED, 0, 20, "Average exposure: %3d New exposure: %3d ", old_ae_avg/100, aev);
if (K > 40 && ABS(old_ae_avg/100 - aev) >= (int)motion_detect_level)
{
md_take_pics();
K = 0;
}
if (K == 40) idle_force_powersave_in_1s();
old_ae_avg = old_ae_avg * 90/100 + aev * 10;
}
else if (motion_detect_trigger == 1)
{
int d = get_spot_motion(detect_size, xcb, ycb, get_global_draw());
if (K > 20) bmp_printf(FONT_MED, 0, 20, "Motion level: %d ", d);
if (K > 20 && d >= (int)motion_detect_level)
{
md_take_pics();
K = 0;
}
if (K == 40) idle_force_powersave_in_1s();
}
else if (motion_detect_trigger == 2)
{
int hs = HALFSHUTTER_PRESSED;
static int prev_hs = 0;
static int prev_d[30];
if (hs)
{
int d = get_spot_motion(detect_size, xcb, ycb, get_global_draw());
for (int i = 29; i > 0; i--)
prev_d[i] = prev_d[i-1];
prev_d[0] = d;
int dmax = 0;
for (int i = 0; i < 30; i++)
{
dmax = MAX(dmax, prev_d[i]);
}
int steady = (dmax <= motion_detect_level);
for (int i = 1; i < 30; i++)
{
int d = MIN(prev_d[i], 30);
bmp_draw_rect(d <= motion_detect_level ? COLOR_CYAN : COLOR_RED, 60 - i*2, 100 - d, 1, d);
bmp_draw_rect(steady ? COLOR_GREEN1 : COLOR_BLACK, 60 - i*2, 100 - 30, 1, 30 - d);
}
bmp_printf(FONT_MED, 0, 20, "Motion level: %d ", dmax);
if (steady)
{
md_take_pics();
}
}
else
{
if (prev_hs) redraw();
prev_d[0] = 100;
}
prev_hs = hs;
}
}
// this is an attempt to make "steady hands" detection work outside liveview too (well, sort of)
// when you press shutter halfway, LiveView will be enabled temporarily (with display off)
// and once the motion detect engine says "camera steady", the picture is taken and LiveView is turned off
static int lv_forced_by_md = 0;
if (!mdx && motion_detect && motion_detect_trigger == 2 && !lv && display_idle() && get_halfshutter_pressed())
{
priority_feature_enabled = 1;
for (int i = 0; i < 10; i++)
{
if (!get_halfshutter_pressed()) break;
msleep(50);
}
if (!get_halfshutter_pressed()) continue;
SW1(0,50);
fake_simple_button(BGMT_LV);
for (int i = 0; i < 20; i++)
{
if (lv && DISPLAY_IS_ON) display_off();
msleep(50);
}
if (lv)
{
SW1(1,50);
lv_forced_by_md = 1;
info_led_on();
}
}
if (lv_forced_by_md && lv && DISPLAY_IS_ON) display_off();
if (lv_forced_by_md && lv && !get_halfshutter_pressed())
{
info_led_off();
fake_simple_button(BGMT_LV);
msleep(500);
lv_forced_by_md = 0;
}
#endif // motion detect
#ifdef FEATURE_INTERVALOMETER
#define SECONDS_REMAINING (intervalometer_next_shot_time - seconds_clock)
#define SECONDS_ELAPSED (seconds_clock - seconds_clock_0)
intervalometer_check_trigger();
if (intervalometer_running)
{
int seconds_clock_0 = seconds_clock;
int display_turned_off = 0;
//~ int images_compared = 0;
msleep(20);
while (SECONDS_REMAINING > 0 && !ml_shutdown_requested)
{
int dt = get_interval_time();
msleep(dt < 5 ? 20 : 300);
intervalometer_check_trigger();
if (!intervalometer_running) break; // from inner loop only
if (gui_menu_shown() || get_halfshutter_pressed())
{
wait_till_next_second();
if (intervalometer_pictures_taken == 0)
{
intervalometer_next_shot_time = seconds_clock + MAX(interval_start_time, 1);
}
else
{
intervalometer_next_shot_time++;
if (!gui_menu_shown()) beep();
}
continue;
}
static char msg[60];
snprintf(msg, sizeof(msg),
" Intervalometer: %s \n"
" Pictures taken: %d ",
format_time_hours_minutes_seconds(SECONDS_REMAINING),
intervalometer_pictures_taken);
if (interval_stop_after) { STR_APPEND(msg, "/ %d", interval_stop_after); }
bmp_printf(FONT_LARGE, 50, 310, msg);
if (interval_stop_after && (int)intervalometer_pictures_taken >= (int)(interval_stop_after))
intervalometer_stop();
if (PLAY_MODE && SECONDS_ELAPSED >= image_review_time)
{
exit_play_qr_mode();
}
if (lens_info.job_state == 0 && liveview_display_idle() && intervalometer_running && !display_turned_off)
{
idle_force_powersave_now();
display_turned_off = 1; // ... but only once per picture (don't be too aggressive)
}
}
if (interval_stop_after && (int)intervalometer_pictures_taken >= (int)(interval_stop_after))
intervalometer_stop();
if (PLAY_MODE) exit_play_qr_mode();
if (!intervalometer_running) continue; // back to start of shoot_task loop
if (gui_menu_shown() || get_halfshutter_pressed()) continue;
int dt = get_interval_time();
// compute the moment for next shot; make sure it stays somewhat in sync with the clock :)
//~ intervalometer_next_shot_time = intervalometer_next_shot_time + dt;
intervalometer_next_shot_time = COERCE(intervalometer_next_shot_time + dt, seconds_clock, seconds_clock + dt);
#ifdef FEATURE_MLU
mlu_step(); // who knows who has the idea of changing drive mode with intervalometer active :)
#endif
int canceled = 0;
if (dt == 0) // crazy mode - needs to be fast
{
int num = interval_stop_after ? interval_stop_after : 9000;
canceled = take_fast_pictures(num);
intervalometer_pictures_taken += num - 1;
}
else if (is_hdr_bracketing_enabled())
{
hdr_shot(0, 1);
}
else
{
// count this as 1 picture
canceled = take_fast_pictures(pics_to_take_at_once+1);
}
if(canceled)
intervalometer_stop();
intervalometer_next_shot_time = MAX(intervalometer_next_shot_time, seconds_clock);
intervalometer_pictures_taken++;
#ifdef CONFIG_MODULES
auto_ettr_intervalometer_wait();
module_exec_cbr(CBR_INTERVALOMETER);
#endif
idle_force_powersave_now();
}
else // intervalometer not running
#endif // FEATURE_INTERVALOMETER
{
#ifdef FEATURE_INTERVALOMETER
if (intervalometer_pictures_taken)
{
interval_create_script(MOD(get_shooting_card()->file_number - intervalometer_pictures_taken + 1, 10000));
}
intervalometer_pictures_taken = 0;
intervalometer_next_shot_time = seconds_clock + MAX(interval_start_time, 1);
#endif
#ifdef FEATURE_AUDIO_REMOTE_SHOT
#if defined(CONFIG_7D) || defined(CONFIG_6D) || defined(CONFIG_650D) || defined(CONFIG_700D) || defined(CONFIG_EOSM)
/* experimental for 7D now, has to be made generic */
static int last_audio_release_running = 0;
if(audio_release_running != last_audio_release_running)
{
last_audio_release_running = audio_release_running;
if(audio_release_running)
{
//Enable Audio IC In Photo Mode if off
if (!is_movie_mode())
{
SoundDevActiveIn(0);
}
}
}
#endif
if (audio_release_running)
{
static int countdown = 0;
if (!display_idle()) countdown = 20;
if (countdown) { countdown--; }
struct audio_level * audio_levels = get_audio_levels();
static int avg_prev0 = 1000;
static int avg_prev1 = 1000;
static int avg_prev2 = 1000;
static int avg_prev3 = 1000;
int current_pulse_level = audio_level_to_db(audio_levels[0].peak_fast) - audio_level_to_db(avg_prev3);
if (countdown == 0)
{
bmp_printf(FONT(FONT_MED, COLOR_FG_NONLV, (lv ? COLOR_BG : bmp_getpixel(AUDIO_REM_SHOT_POS_X-2, AUDIO_REM_SHOT_POS_Y))), (lv ? 2 : AUDIO_REM_SHOT_POS_X), (lv ? 30 : AUDIO_REM_SHOT_POS_Y), "Audio release ON (%2d / %2d)", current_pulse_level, audio_release_level);
if (current_pulse_level > (int)audio_release_level)
{
remote_shot(1);
msleep(100);
/* Initial forced sleep is necesarry when using camera self timer,
* otherwise remote_shot returns right after the countdown
* and the loop below seems to miss the actual picture taking.
* This means we will trigger again on the sound of the shutter
* (and again, and again, ...)
* TODO: should this be fixed in remote_shot itself? */
while (lens_info.job_state && !ml_shutdown_requested) msleep(100);
countdown = 20;
}
}
avg_prev3 = avg_prev2;
avg_prev2 = avg_prev1;
avg_prev1 = avg_prev0;
avg_prev0 = audio_levels[0].avg;
}
#endif
}
}
}
TASK_CREATE( "shoot_task", shoot_task, 0, 0x1a, 0x2000 );
static void shoot_init()
{
set_maindial_sem = create_named_semaphore("set_maindial_sem", 1);
menu_add( "Shoot", shoot_menus, COUNT(shoot_menus) );
menu_add( "Expo", expo_menus, COUNT(expo_menus) );
//~ menu_add( "Tweaks", vid_menus, COUNT(vid_menus) );
#ifdef FEATURE_EXPO_OVERRIDE
extern struct menu_entry expo_override_menus[];
menu_add( "Expo", expo_override_menus, 1 );
#endif
#ifdef FEATURE_EXPSIM
extern struct menu_entry expo_tweak_menus[];
menu_add( "Expo", expo_tweak_menus, 1 );
#endif
}
INIT_FUNC("shoot", shoot_init);
void iso_refresh_display() // in photo mode
{
#ifdef FEATURE_INTERMEDIATE_ISO_PHOTO_DISPLAY
if (!lv && display_idle())
{
if (lens_info.raw_iso % 8 != 0)
{
int bg = bmp_getpixel(MENU_DISP_ISO_POS_X, MENU_DISP_ISO_POS_Y-10);
bmp_fill(bg, MENU_DISP_ISO_POS_X, MENU_DISP_ISO_POS_Y-10, 175, 85);
char msg[30];
snprintf(msg, sizeof(msg), "%d ", raw2iso(lens_info.raw_iso));
int w = bfnt_draw_char(ICON_ISO, MENU_DISP_ISO_POS_X + 5, MENU_DISP_ISO_POS_Y + 10, COLOR_FG_NONLV, bg);
bmp_printf(FONT(FONT_CANON, COLOR_FG_NONLV, bg), MENU_DISP_ISO_POS_X + w + 10, MENU_DISP_ISO_POS_Y + 10, msg);
}
}
#endif
}