https://bitbucket.org/hudson/magic-lantern
Tip revision: c326bc9a68a6bde8f07621fd89cb1cf9c67080f4 authored by a1ex on 22 October 2013, 21:31:00 UTC
Close branch 60d.
Close branch 60d.
Tip revision: c326bc9
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 "dryos.h"
#include "bmp.h"
#include "version.h"
#include "config.h"
#include "menu.h"
#include "property.h"
#include "lens.h"
#include "gui.h"
void move_lv_afframe(int dx, int dy);
void movie_start();
void movie_end();
void display_trap_focus_info();
void display_lcd_remote_icon(int x0, int y0);
CONFIG_INT( "interval.timer.index", interval_timer_index, 2 );
CONFIG_INT( "focus.trap", trap_focus, 0);
CONFIG_INT( "focus.trap.delay", trap_focus_delay, 1000); // min. delay between two shots in trap focus
CONFIG_INT( "audio.release-level", audio_release_level, 10);
CONFIG_INT( "interval.movie.duration.index", interval_movie_duration_index, 2);
//~ CONFIG_INT( "flash_and_no_flash", flash_and_no_flash, 0);
CONFIG_INT( "silent.pic.mode", silent_pic_mode, 0 ); // 0 = off, 1 = normal, 2 = hi-res, 3 = long-exp, 4 = slit-scan
CONFIG_INT( "silent.pic.submode", silent_pic_submode, 0); // simple, burst, fullhd
#define silent_pic_burst (silent_pic_submode == 1)
#define silent_pic_fullhd (silent_pic_submode == 2)
CONFIG_INT( "silent.pic.highres", silent_pic_highres, 0); // index of matrix size (2x1 .. 5x5)
CONFIG_INT( "silent.pic.sweepdelay", silent_pic_sweepdelay, 350);
CONFIG_INT( "silent.pic.slitscan.skipframes", silent_pic_slitscan_skipframes, 1);
CONFIG_INT( "silent.pic.longexp.time.index", silent_pic_longexp_time_index, 5);
CONFIG_INT( "silent.pic.longexp.method", silent_pic_longexp_method, 0);
CONFIG_INT( "zoom.enable.face", zoom_enable_face, 1);
CONFIG_INT( "zoom.disable.x5", zoom_disable_x5, 0);
CONFIG_INT( "zoom.disable.x10", zoom_disable_x10, 0);
CONFIG_INT( "bulb.duration.index", bulb_duration_index, 2);
//~ CONFIG_INT( "lcd.release", lcd_release_running, 0);
CONFIG_INT( "mlu.mode", mlu_mode, 2); // off, on, auto
//New option for the sensitivty of the motion release
CONFIG_INT( "motion.release-level", motion_detect_level, 8);
int get_silent_pic_mode() { return silent_pic_mode; } // silent pic will disable trap focus
CONFIG_INT("intervalometer.wait", intervalometer_wait, 1);
int intervalometer_running = 0;
int audio_release_running = 0;
int motion_detect = 0;
//int motion_detect_level = 8;
int drive_mode_bk = -1;
int gui_state = 0;
CONFIG_INT("quick.review.allow.zoom", quick_review_allow_zoom, 1);
PROP_HANDLER(PROP_GUI_STATE)
{
gui_state = buf[0];
if (gui_state == 3 && image_review_time == 0xff && quick_review_allow_zoom && !intervalometer_running)
{
fake_simple_button(BGMT_PLAY);
}
return prop_cleanup(token, property);
}
int timer_values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20, 25, 30, 35, 40, 45, 50, 55, 60, 120, 180, 240, 300, 360, 420, 480, 540, 600, 660, 720, 780, 840, 900, 1200, 1800, 2700, 3600, 5400, 7200, 9000, 10800, 14400, 18000, 21600, 25200, 28800};
int timer_values_ms[] = {100, 200, 300, 500, 700, 1000, 2000, 3000, 5000, 7000, 10000, 15000, 20000, 30000, 50000, 60000, 120000, 180000, 300000, 600000, 900000, 1800000};
typedef int (*CritFunc)(int);
// crit returns negative if the tested value is too high, positive if too low, 0 if perfect
static int bin_search(int lo, int hi, CritFunc crit)
{
if (lo >= hi-1) return lo;
int m = (lo+hi)/2;
int c = crit(m);
if (c == 0) return m;
if (c > 0) return bin_search(m, hi, crit);
return bin_search(lo, m, crit);
}
static void
interval_timer_display( void * priv, int x, int y, int selected )
{
if (shooting_mode != SHOOTMODE_MOVIE || silent_pic_mode)
{
int d = timer_values[*(int*)priv];
if (!d)
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Take pics like crazy"
);
else
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Take a pic every: %d%s",
d < 60 ? d : d/60,
d < 60 ? "s" : "min"
);
}
else
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Record %ds, pause %ds",
timer_values[interval_movie_duration_index],
timer_values[*(int*)priv]
);
}
menu_draw_icon(x, y, intervalometer_running ? MNI_PERCENT : MNI_WARNING, (*(int*)priv) * 100 / COUNT(timer_values));
}
static void
interval_timer_toggle( void * priv )
{
unsigned * ptr = priv;
*ptr = mod(*ptr + 1, COUNT(timer_values));
}
static void
interval_timer_toggle_reverse( void * priv )
{
unsigned * ptr = priv;
*ptr = mod(*ptr - 1, COUNT(timer_values));
}
static void
interval_movie_duration_toggle( void * priv )
{
if (shooting_mode == SHOOTMODE_MOVIE && silent_pic_mode == 0)
interval_movie_duration_index = mod(interval_movie_duration_index + 1, COUNT(timer_values));
}
static void
intervalometer_display( void * priv, int x, int y, int selected )
{
int p = *(int*)priv;
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Intervalometer : %s%s",
p ? "ON" : "OFF",
p ? (intervalometer_wait ? ",Wait" : ",NoWait") : ""
);
}
static void
lcd_release_display( void * priv, int x, int y, int selected )
{
int v = (*(int*)priv);
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"LCD Remote Shot : %s",
v == 1 ? "Near" : v == 2 ? (mlu_mode ? "Away/MLU" : "Away") : v == 3 ? "Wave" : "OFF"
);
if (v) display_lcd_remote_icon(x-25, y+5);
menu_draw_icon(x, y, v ? -1 : MNI_OFF, 0);
}
static void
audio_release_display( void * priv, int x, int y, int selected )
{
//~ if (audio_release_running)
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Audio RemoteShot: %s, level=%d",
audio_release_running ? "ON" : "OFF",
audio_release_level
);
/*else
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Audio RemoteShot: OFF"
);*/
//~ menu_draw_icon(x, y, audio_release_running ? MNI_PERCENT : MNI_OFF, audio_release_level * 100 / 30);
}
static void
audio_release_level_toggle(void* priv)
{
audio_release_level = mod(audio_release_level - 5 + 1, 26) + 5;
}
static void
audio_release_level_toggle_reverse(void* priv)
{
audio_release_level = mod(audio_release_level - 5 - 1, 26) + 5;
}
//GUI Functions for the motion detect sensitivity.
static void
motion_release_level_toggle(void* priv)
{
motion_detect_level = mod(motion_detect_level - 1 + 1, 31) + 1;
}
static void
motion_release_level_toggle_reverse(void* priv)
{
motion_detect_level = mod(motion_detect_level - 1 - 1, 31) + 1;
}
static void
motion_detect_display( void * priv, int x, int y, int selected )
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Motion Detect : %s, level=%d",
motion_detect == 0 ? "OFF" :
motion_detect == 1 ? "EXP" :
motion_detect == 2 ? "DIF" : "err",
motion_detect_level
);
menu_draw_icon(x, y, MNI_BOOL_LV(motion_detect), 0);
}
int get_trap_focus() { return trap_focus; }
/*
void set_flash_firing(int mode)
{
lens_wait_readytotakepic(64);
mode = COERCE(mode, 0, 2);
prop_request_change(PROP_STROBO_FIRING, &mode, 4);
}
static void
flash_and_no_flash_display( void * priv, int x, int y, int selected )
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Flash / No flash: %s",
strobo_firing == 2 ? "N/A" :
flash_and_no_flash ? "ON " : "OFF"
);
}
static void
flash_and_no_flash_toggle( void * priv )
{
flash_and_no_flash = !flash_and_no_flash;
if (!flash_and_no_flash)
set_flash_firing(0); // force on
}*/
//2 4 6 9 12 16 20 25
//~ static const int16_t silent_pic_sweep_modes_l[] = {2, 2, 2, 3, 3, 4, 4, 5};
//~ static const int16_t silent_pic_sweep_modes_c[] = {1, 2, 3, 3, 4, 4, 5, 5};
//~ #define SILENTPIC_NL COERCE(silent_pic_sweep_modes_l[COERCE(silent_pic_highres,0,COUNT(silent_pic_sweep_modes_l)-1)], 0, 5)
//~ #define SILENTPIC_NC COERCE(silent_pic_sweep_modes_c[COERCE(silent_pic_highres,0,COUNT(silent_pic_sweep_modes_c)-1)], 0, 5)
static void
silent_pic_display( void * priv, int x, int y, int selected )
{
if (silent_pic_mode == 0)
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Silent/Slit Pic : OFF"
);
}
else if (silent_pic_mode == 1)
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Silent Picture : %s",
silent_pic_burst ? "Burst" :
silent_pic_fullhd ? "FullHD" : "Single"
);
}
/* else if (silent_pic_mode == 2)
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Silent Pic HiRes: %dx%d",
SILENTPIC_NL,
SILENTPIC_NC
);
bmp_printf(FONT_MED, x + 430, y+5, "%dx%d", SILENTPIC_NC*(1024-8), SILENTPIC_NL*(680-8));
}
else if (silent_pic_mode == 3)
{
int t = timer_values_ms[mod(silent_pic_longexp_time_index, COUNT(timer_values_ms))];
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Silent Pic LongX: %s%ds,%s",
t < 1000 ? "0." : "",
t < 1000 ? t / 100 : t / 1000,
silent_pic_longexp_method ? "MAX" : "AVG"
);
}*/
else if (silent_pic_mode == 4)
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Slit-scan Pic : 1ln/%dclk",
silent_pic_slitscan_skipframes
);
}
menu_draw_icon(x, y, MNI_BOOL_LV(silent_pic_mode), 0);
}
static void silent_pic_mode_toggle(void* priv)
{
silent_pic_mode = mod(silent_pic_mode + 1, 5); // off, normal, hi-res, long-exp, slit
if (silent_pic_mode == 3) silent_pic_mode = 4; // skip longx, not working
if (silent_pic_mode == 2) silent_pic_mode = 4; // skip hi-res
}
static void silent_pic_toggle(int sign)
{
if (silent_pic_mode == 1)
silent_pic_submode = mod(silent_pic_submode + 1, 3);
/*else if (silent_pic_mode == 2)
silent_pic_highres = mod(silent_pic_highres + sign, COUNT(silent_pic_sweep_modes_c));
else if (silent_pic_mode == 3)
{
if (sign < 0)
{
silent_pic_longexp_method = !silent_pic_longexp_method;
}
else
{
silent_pic_longexp_time_index = mod(silent_pic_longexp_time_index + 1, COUNT(timer_values_ms));
}
}*/
else if (silent_pic_mode == 4)
silent_pic_slitscan_skipframes = mod(silent_pic_slitscan_skipframes + sign - 1, 4) + 1;
}
static void silent_pic_toggle_forward(void* priv)
{ silent_pic_toggle(1); }
static void silent_pic_toggle_reverse(void* priv)
{ silent_pic_toggle(-1); }
int afframe[26];
PROP_HANDLER( PROP_LV_AFFRAME ) {
memcpy(afframe, buf, 0x68);
return prop_cleanup( token, property );
}
void get_afframe_pos(int W, int H, int* x, int* y)
{
*x = (afframe[2] + afframe[4]/2) * W / afframe[0];
*y = (afframe[3] + afframe[5]/2) * H / afframe[1];
}
int face_zoom_request = 0;
int hs = 0;
PROP_HANDLER( PROP_HALF_SHUTTER ) {
int v = *(int*)buf;
if (zoom_enable_face)
{
if (v == 0 && lv_drawn() && lvaf_mode == 2 && gui_state == 0 && !recording) // face detect
face_zoom_request = 1;
}
/* if (v && gui_menu_shown() && !is_menu_active("Focus"))
{
gui_stop_menu();
}*/
return prop_cleanup( token, property );
}
/*int sweep_lv_on = 0;
static void
sweep_lv_start(void* priv)
{
sweep_lv_on = 1;
}*/
int center_lv_aff = 0;
void center_lv_afframe()
{
center_lv_aff = 1;
}
void center_lv_afframe_do()
{
if (!lv_drawn() || gui_menu_shown() || gui_state != GUISTATE_IDLE) return;
int cx = (afframe[0] - afframe[4])/2;
int cy = (afframe[1] - afframe[5])/2;
if (afframe[2] == cx && afframe[3] == cy)
{
move_lv_afframe(10,10);
msleep(100);
}
afframe[2] = cx;
afframe[3] = cy;
prop_request_change(PROP_LV_AFFRAME, afframe, 0x68);
}
void move_lv_afframe(int dx, int dy)
{
if (!lv_drawn() || gui_menu_shown() || gui_state != GUISTATE_IDLE) return;
afframe[2] = COERCE(afframe[2] + dx, 500, afframe[0] - afframe[4]);
afframe[3] = COERCE(afframe[3] + dy, 500, afframe[1] - afframe[5]);
prop_request_change(PROP_LV_AFFRAME, afframe, 0x68);
}
/*
static void
sweep_lv()
{
if (recording) return;
if (!lv_drawn()) return;
gui_stop_menu();
msleep(2000);
int zoom = 5;
prop_request_change(PROP_LV_DISPSIZE, &zoom, 4);
msleep(2000);
int i,j;
for (i = 0; i < 5; i++)
{
for (j = 0; j < 5; j++)
{
bmp_printf(FONT_LARGE, 50, 50, "AFF %d, %d ", i, j);
afframe[2] = 250 + 918 * j;
afframe[3] = 434 + 490 * i;
prop_request_change(PROP_LV_AFFRAME, afframe, 0x68);
msleep(100);
}
}
zoom = 1;
prop_request_change(PROP_LV_DISPSIZE, &zoom, 4);
}*/
#if 0 // does not work... out of memory?
uint8_t* read_entire_file(const char * filename, int* buf_size)
{
bmp_printf(FONT_LARGE, 0, 40, "read %s ", filename);
msleep(1000);
*buf_size = 0;
unsigned size;
if( FIO_GetFileSize( filename, &size ) != 0 )
goto getfilesize_fail;
DEBUG("File '%s' size %d bytes", filename, size);
bmp_printf(FONT_LARGE, 0, 40, "size %d ", size);
msleep(1000);
uint8_t * buf = alloc_dma_memory( size );
if( !buf )
{
DebugMsg( DM_MAGIC, 3, "%s: alloc_dma_memory failed", filename );
goto malloc_fail;
}
bmp_printf(FONT_LARGE, 0, 40, "alloc %x ", buf);
msleep(1000);
size_t rc = read_file( filename, buf, size );
if( rc != size )
goto read_fail;
bmp_printf(FONT_LARGE, 0, 40, "read ok ");
msleep(1000);
// Since the read was into uncacheable memory, it will
// be very slow to access. Copy it into a cached buffer
// and release the uncacheable space.
//~ uint8_t * fast_buf = AllocateMemory( size + 32);
//~ if( !fast_buf )
//~ goto fail_buf_copy;
//~ bmp_printf(FONT_LARGE, 0, 40, "alloc fast %x ", fast_buf);
//~ msleep(1000);
//~ memcpy(fast_buf, buf, size);
//~ free_dma_memory( buf );
*buf_size = size;
bmp_printf(FONT_LARGE, 0, 40, "almost done ");
msleep(1000);
return buf;
fail_buf_copy:
read_fail:
free_dma_memory( buf );
malloc_fail:
getfilesize_fail:
DEBUG("failed");
return NULL;
}
static void
convert_yuv_to_bmp(char* file_yuv, char* file_bmp)
{
int yuv_size;
int width, height;
void* yuv = read_entire_file(file_yuv, &yuv_size);
if (!yuv)
{
bmp_printf(FONT_LARGE, 0, 40, "read error %s", file_yuv);
msleep(1000);
return;
}
if (yuv_size == 1056*704*2)
{
width = 1056;
height = 704;
}
else if (yuv_size == 1720*974*2)
{
width = 1720;
height = 974;
}
else
{
bmp_printf(FONT_LARGE, 0, 40, "unk yuv size: %d ", yuv_size);
free_dma_memory(yuv);
return;
}
int bmp_size = width * height * 3;
void* bmpbuf = AllocateMemory(bmp_size + 32);
if (!bmpbuf)
{
bmp_printf(FONT_LARGE, 0, 40, "malloc error");
free_dma_memory(yuv);
return;
}
// AJ equations for YUV -> RGB
// anyone wants to optimize this?
#define Y(i) (*(uint8_t*)(yuv + i * 2 + 1))
#define U(i) (*(int8_t*)(yuv + i * 4))
#define V(i) (*(int8_t*)(yuv + i * 4 + 2))
#define R(i) (*(uint8_t*)(bmpbuf + i * 3))
#define G(i) (*(uint8_t*)(bmpbuf + i * 3 + 1))
#define B(i) (*(uint8_t*)(bmpbuf + i * 3 + 2))
int i;
int N = width*height;
for (i = 0; i < N; i++)
{
R(i) = COERCE( Y(i) + 1.403 * V(i/2), 0, 255);
G(i) = COERCE( Y(i) - 0.344 * U(i/2) - 0.714 * V(i/2), 0, 255);
B(i) = COERCE( Y(i) + 1.770 * U(i/2), 0, 255);
}
#undef Y
#undef U
#undef V
#undef R
#undef G
#undef B
struct bmp_file_t bmp;
bmp.signature = 0x4D42;
bmp.size = bmp_size + sizeof(bmp);
bmp.res_0 = 0;
bmp.res_1 = 0;
bmp.image = 54; // offset
bmp.hdr_size = 40;
bmp.width = width;
bmp.height = height;
bmp.planes = 1;
bmp.bits_per_pixel = 24;
bmp.compression = 0;
bmp.image_size = bmp_size; // yuv buffers are always multiples of 16
bmp.hpix_per_meter = 2835; // from wikipedia
bmp.vpix_per_meter = 2835; // from wikipedia
bmp.num_colors = 0;
bmp.num_imp_colors = 0;
FILE *f;
FIO_RemoveFile(file_bmp);
f = FIO_CreateFile(file_bmp);
if (f == INVALID_PTR)
{
bmp_printf(FONT_SMALL, 120, 40, "FCreate: Err %s", file_bmp);
free_dma_memory(yuv);
FreeMemory(bmpbuf);
return;
}
FIO_WriteFile(f, &bmp, sizeof(bmp));
FIO_WriteFile(f, &bmpbuf, bmp_size);
FIO_CloseFile(f);
free_dma_memory(yuv);
FreeMemory(bmpbuf);
}
static void
convert_all_yuvs_to_bmp_folder(char* folder) // folder includes /
{
struct fio_file file;
struct fio_dirent * dirent = FIO_FindFirstEx( folder, &file );
if( IS_ERROR(dirent) )
{
bmp_printf( FONT_LARGE, 40, 40,
"%s: dirent=%08x!",
__func__,
(unsigned) dirent
);
return;
}
int k = 0;
do {
if (file.mode & 0x20) // regular file
{
char* s = strstr(file.name, ".422");
if (s)
{
char yuvname[100];
char bmpname[100];
snprintf(yuvname, sizeof(yuvname), "%s%s", folder, file.name);
*s = 0;
snprintf(bmpname, sizeof(yuvname), "%s%s.BMP", folder, file.name);
bmp_printf(FONT_MED, 0, 40, "bmp %s \nyuv %s ", bmpname, yuvname);
msleep(1000);
convert_yuv_to_bmp(yuvname, bmpname);
msleep(1000);
return;
}
}
} while( FIO_FindNextEx( dirent, &file ) == 0);
}
static void
convert_all_yuvs_to_bmp()
{
convert_yuv_to_bmp("B:/DCIM/100CANON/1324-001.422", "B:/DCIM/100CANON/1324-001.BMP");
return;
bmp_printf(FONT_MED, 0, 40, "yuv to bmp...");
struct fio_file file;
struct fio_dirent * dirent = FIO_FindFirstEx( "B:/DCIM/", &file );
if( IS_ERROR(dirent) )
{
bmp_printf( FONT_LARGE, 40, 40,
"%s: dirent=%08x!",
__func__,
(unsigned) dirent
);
return;
}
int k = 0;
do {
if ((file.mode & 0x10) && (file.name[0] != '.')) // directory
{
char folder[100];
snprintf(folder, sizeof(folder), "B:/DCIM/%s/", file.name);
convert_all_yuvs_to_bmp_folder(folder);
}
} while( FIO_FindNextEx( dirent, &file ) == 0);
}
int convert_yuv_bmp_flag = 0;
static void
convert_all_yuvs_start()
{
convert_yuv_bmp_flag = 1;
}
#endif
void vsync(volatile int* addr)
{
int i;
int v0 = *addr;
for (i = 0; i < 100; i++)
{
if (*addr != v0) return;
msleep(1);
}
bmp_printf(FONT_MED, 30, 100, "vsync failed");
}
static char* silent_pic_get_name()
{
static char imgname[100];
static int silent_number = 1; // cache this number for speed (so it won't check all files until 10000 to find the next free number)
static int prev_file_number = -1;
static int prev_folder_number = -1;
if (prev_file_number != file_number) silent_number = 1;
if (prev_folder_number != folder_number) silent_number = 1;
prev_file_number = file_number;
prev_folder_number = folder_number;
if (intervalometer_running)
{
//~ int timelapse_number;
for ( ; silent_number < 100000000; silent_number++)
{
snprintf(imgname, sizeof(imgname), "B:/DCIM/%03dCANON/%08d.422", folder_number, silent_number);
unsigned size;
if( FIO_GetFileSize( imgname, &size ) != 0 ) break;
if (size == 0) break;
}
}
else
{
for ( ; silent_number < 1000; silent_number++)
{
snprintf(imgname, sizeof(imgname), "B:/DCIM/%03dCANON/%04d-%03d.422", folder_number, file_number, silent_number);
unsigned size;
if( FIO_GetFileSize( imgname, &size ) != 0 ) break;
if (size == 0) break;
}
}
bmp_printf(FONT_MED, 100, 130, "%s ", imgname);
return imgname;
}
/*
int ms100_clock = 0;
static void
ms100_clock_task( void )
{
while(1)
{
msleep(100);
ms100_clock += 100;
}
}
TASK_CREATE( "ms100_clock_task", ms100_clock_task, 0, 0x19, 0x1000 );*/
// not working
/*
static void
silent_pic_take_longexp()
{
struct vram_info * vram = get_yuv422_hd_vram();
uint8_t* buf = AllocateMemory(vram->pitch * vram->width * 2);
if (!buf)
{
bmp_printf(FONT_MED, 100, 100, "Psst! Not enough memory :( ");
return;
}
FreeMemory(buf);
char* imgname = silent_pic_get_name();
//~
//~ FIO_RemoveFile(imgname);
//~ FILE* f = FIO_CreateFile(imgname);
//~ if (f == INVALID_PTR)
//~ {
//~ bmp_printf(FONT_SMALL, 120, 40, "FCreate: Err %s", imgname);
//~ return;
//~ }
//~
//~ ms100_clock = 0;
//~ int tmax = timer_values_ms[silent_pic_longexp_time_index];
//~ while (ms100_clock < tmax)
//~ {
//~ bmp_printf(FONT_MED, 100, 100, "Psst! Taking a long-exp silent pic (%d/%d)... ", ms100_clock, tmax);
//~ int ans = FIO_WriteFile(f, vram->vram, vram->height * vram->pitch);
//~ msleep(10);
//~ }
//~ FIO_CloseFile(f);
//~
bmp_printf(FONT_MED, 100, 100, "Psst! Just took a long-exp silent pic ");
if (!silent_pic_burst) // single mode
{
while (get_halfshutter_pressed()) msleep(100);
}
}*/
static int
silent_pic_ensure_movie_mode()
{
if (silent_pic_fullhd && shooting_mode != SHOOTMODE_MOVIE)
{
set_shooting_mode(SHOOTMODE_MOVIE);
msleep(1000);
}
if (silent_pic_fullhd && !recording)
{
movie_start();
return 1;
}
return 0;
}
static void
silent_pic_stop_dummy_movie()
{
movie_end();
char name[100];
snprintf(name, sizeof(name), "B:/DCIM/%03dCANON/MVI_%04d.THM", folder_number, file_number);
FIO_RemoveFile(name);
snprintf(name, sizeof(name), "B:/DCIM/%03dCANON/MVI_%04d.MOV", folder_number, file_number);
FIO_RemoveFile(name);
}
static void
silent_pic_take_simple()
{
int movie_started = silent_pic_ensure_movie_mode();
struct vram_info * vram = get_yuv422_hd_vram();
char* imgname = silent_pic_get_name();
bmp_printf(FONT_MED, 100, 100, "Psst! Taking a pic ");
//~ vsync(vram->vram + vram->pitch * vram->height - 100);
dump_seg(vram->vram, vram->pitch * vram->height, imgname);
bmp_printf(FONT_MED, 100, 100, "Psst! Just took a pic ");
if (movie_started) silent_pic_stop_dummy_movie();
if (!silent_pic_burst) // single mode
{
while (get_halfshutter_pressed()) msleep(100);
}
}
void
silent_pic_take_lv_dbg()
{
struct vram_info * vram = get_yuv422_vram();
int silent_number;
char imgname[100];
for (silent_number = 0 ; silent_number < 1000; silent_number++) // may be slow after many pics
{
snprintf(imgname, sizeof(imgname), "B:/VRAM%d.422", silent_number);
unsigned size;
if( FIO_GetFileSize( imgname, &size ) != 0 ) break;
if (size == 0) break;
}
dump_seg(vram->vram, vram->pitch * vram->height, imgname);
}
/*static void
silent_pic_take_sweep()
{
if (recording) return;
if (!lv_drawn()) return;
if ((af_mode & 0xF) != 3 )
{
bmp_printf(FONT_MED, 100, 100, "Please switch to Manual Focus.");
return;
}
bmp_printf(FONT_MED, 100, 100, "Psst! Preparing for high-res pic ");
while (get_halfshutter_pressed()) msleep(100);
gui_stop_menu();
msleep(100);
int afx0 = afframe[2];
int afy0 = afframe[3];
int zoom = 5;
prop_request_change(PROP_LV_DISPSIZE, &zoom, 4);
msleep(1000);
struct vram_info * vram = get_yuv422_hd_vram();
char* imgname = silent_pic_get_name();
FIO_RemoveFile(imgname);
FILE* f = FIO_CreateFile(imgname);
if (f == INVALID_PTR)
{
bmp_printf(FONT_SMALL, 120, 40, "FCreate: Err %s", imgname);
return;
}
int i,j;
int NL = SILENTPIC_NL;
int NC = SILENTPIC_NC;
int x0 = (SENSOR_RES_X - NC * 1024) / 2;
int y0 = (SENSOR_RES_Y - NL * 680) / 2;
for (i = 0; i < NL; i++)
{
for (j = 0; j < NC; j++)
{
// afframe[2,3]: x,y
// range obtained by moving the zoom window: 250 ... 3922, 434 ... 2394 => upper left corner
// full-res: 5202x3465
// buffer size: 1024x680
bmp_printf(FONT_MED, 100, 100, "Psst! Taking a high-res pic [%d,%d] ", i, j);
afframe[2] = x0 + 1024 * j;
afframe[3] = y0 + 680 * i;
prop_request_change(PROP_LV_AFFRAME, afframe, 0x68);
//~ msleep(500);
msleep(silent_pic_sweepdelay);
int ans = FIO_WriteFile(f, vram->vram, 1024 * 680 * 2);
//~ bmp_printf(FONT_MED, 20, 150, "=> %d", ans);
msleep(50);
}
}
FIO_CloseFile(f);
// restore
zoom = 1;
prop_request_change(PROP_LV_DISPSIZE, &zoom, 4);
msleep(1000);
afframe[2] = afx0;
afframe[3] = afy0;
prop_request_change(PROP_LV_AFFRAME, afframe, 0x68);
bmp_printf(FONT_MED, 100, 100, "Psst! Just took a high-res pic ");
}*/
static void
silent_pic_take_slitscan(int interactive)
{
return;
if (recording) return; // vsync fails
if (!lv_drawn()) return;
gui_stop_menu();
while (get_halfshutter_pressed()) msleep(100);
msleep(500);
clrscr();
uint8_t * const lvram = UNCACHEABLE(YUV422_LV_BUFFER);
int lvpitch = YUV422_LV_PITCH;
uint8_t * const bvram = bmp_vram();
if (!bvram) return;
#define BMPPITCH 960
struct vram_info * vram = get_yuv422_hd_vram();
bmp_printf(FONT_MED, 100, 100, "Psst! Taking a slit-scan pic (%dx%d)", vram->width, vram->height);
char* imgname = silent_pic_get_name();
FIO_RemoveFile(imgname);
FILE* f = FIO_CreateFile(imgname);
if (f == INVALID_PTR)
{
bmp_printf(FONT_SMALL, 120, 40, "FCreate: Err %s", imgname);
return;
}
int i;
for (i = 0; i < vram->height; i++)
{
int k;
for (k = 0; k < silent_pic_slitscan_skipframes; k++)
vsync(CLK_25FPS);
FIO_WriteFile(f, YUV422_HD_BUFFER + i * vram->pitch, vram->pitch);
int y = i * 480 / vram->height;
uint16_t * const v_row = (uint16_t*)( lvram + y * lvpitch ); // 1 pixel
uint8_t * const b_row = (uint8_t*)( bvram + y * BMPPITCH); // 1 pixel
uint16_t* lvp; // that's a moving pointer through lv vram
uint8_t* bp; // through bmp vram
for (lvp = v_row, bp = b_row; lvp < v_row + 720 ; lvp++, bp++)
*bp = ((*lvp) * 41 >> 16) + 38;
if (get_halfshutter_pressed())
{
FIO_CloseFile(f);
FIO_RemoveFile(imgname);
clrscr();
bmp_printf(FONT_MED, 100, 100, "Slit-scan cancelled.");
while (get_halfshutter_pressed()) msleep(100);
return;
}
}
FIO_CloseFile(f);
bmp_printf(FONT_MED, 100, 100, "Psst! Just took a slit-scan pic ");
if (!interactive) return;
// wait half-shutter press and clear the screen
while (!get_halfshutter_pressed()) msleep(100);
clrscr();
while (get_halfshutter_pressed()) msleep(100);
clrscr();
}
static void
silent_pic_take(int interactive) // for remote release, set interactive=0
{
if (!lv_drawn()) return;
int g = get_global_draw();
set_global_draw(0);
if (silent_pic_mode == 1) // normal
silent_pic_take_simple();
//~ else if (silent_pic_mode == 2) // hi-res
//~ silent_pic_take_sweep();
//~ else if (silent_pic_mode == 3) // long exposure
//~ silent_pic_take_longexp();
else if (silent_pic_mode == 4) // slit-scan
silent_pic_take_slitscan(interactive);
set_global_draw(g);
}
static void
iso_display( void * priv, int x, int y, int selected )
{
int fnt = selected ? MENU_FONT_SEL : MENU_FONT;
bmp_printf(
fnt,
x, y,
"ISO : %s",
lens_info.iso ? "" : "Auto"
);
bmp_printf(FONT_MED, x + 550, y+5, "[Q]=Auto");
fnt = FONT(
fnt,
is_native_iso(lens_info.iso) ? COLOR_YELLOW :
is_lowgain_iso(lens_info.iso) ? COLOR_GREEN2 : FONT_FG(fnt),
FONT_BG(fnt));
if (lens_info.iso)
{
bmp_printf(
fnt,
x + 14 * font_large.width, y,
"%d", lens_info.iso
);
}
menu_draw_icon(x, y, lens_info.iso ? MNI_PERCENT : MNI_AUTO, (lens_info.raw_iso - codes_iso[1]) * 100 / (codes_iso[COUNT(codes_iso)-1] - codes_iso[1]));
}
int is_native_iso(int iso)
{
switch(iso)
{
case 100:
case 200:
case 400:
case 800:
case 1600:
case 3200:
case 6400:
case 12800:
case 25600:
return 1;
}
return 0;
}
int is_lowgain_iso(int iso)
{
switch(iso)
{
case 160:
case 320:
case 640:
case 1250:
case 2500:
return 1;
}
return 0;
}
int is_round_iso(int iso)
{
return is_native_iso(iso) || is_lowgain_iso(iso);
}
CONFIG_INT("iso.round.only", iso_round_only, 0);
void
iso_toggle( int sign )
{
int i = raw2index_iso(lens_info.raw_iso);
int k;
for (k = 0; k < 10; k++)
{
i = mod(i + sign, COUNT(codes_iso));
while (iso_round_only && !is_round_iso(values_iso[i]))
i = mod(i + sign, COUNT(codes_iso));
lens_set_rawiso(codes_iso[i]);
msleep(100);
int j = raw2index_iso(lens_info.raw_iso);
if (i == j) break;
}
menu_show_only_selected();
}
static void
iso_toggle_forward( void * priv )
{
iso_toggle(1);
}
static void
iso_toggle_reverse( void * priv )
{
iso_toggle(-1);
}
PROP_INT(PROP_ISO_AUTO, iso_auto_code);
static int measure_auto_iso()
{
// temporary changes during measurement:
// * max auto iso => 12800
// * iso: 800 => 2 or 3 stops down, 3 or 4 stops up
// * AE shift to keep the same exposure
uint16_t ma = max_auto_iso;
uint16_t ma0 = (ma & 0xFF00) | 0x80;
int is0 = lens_info.raw_iso;
int ae0 = lens_info.ae;
int dif = 0x60 - is0;
lens_set_rawiso(is0 + dif); // = 0x60 = ISO 800
lens_set_ae(ae0 - dif);
prop_request_change(PROP_MAX_AUTO_ISO, &ma0, 2);
int iso_auto_mode = 0;
prop_request_change(PROP_ISO, &iso_auto_mode, 4); // force iso auto
msleep(500);
while (iso_auto_code == 0)
{
SW1(1,100);
SW1(0,100);
}
int ans = iso_auto_code;
// restore stuff back
prop_request_change(PROP_MAX_AUTO_ISO, &ma, 2);
lens_set_rawiso(is0);
lens_set_ae(ae0);
return ans;
}
static void iso_auto_quick()
{
if (MENU_MODE) return;
lens_set_rawiso(measure_auto_iso());
}
int iso_auto_flag = 0;
static void iso_auto()
{
if (lv_drawn()) iso_auto_flag = 1; // it takes some time, so it's better to do it in another task
else
{
iso_auto_quick();
iso_auto_quick(); // sometimes it gets better result the second time
}
}
void get_under_and_over_exposure_autothr(int* under, int* over)
{
int thr_lo = 0;
int thr_hi = 255;
*under = 0;
*over = 0;
while (*under < 50 && *over < 50 && thr_lo < thr_hi)
{
thr_lo += 10;
thr_hi -= 10;
get_under_and_over_exposure(thr_lo, thr_hi, under, over);
}
}
int crit_iso(int iso_index)
{
if (!lv_drawn()) return 0;
if (iso_index >= 0)
{
lens_set_rawiso(codes_iso[iso_index]);
msleep(500);
}
int under, over;
get_under_and_over_exposure_autothr(&under, &over);
menu_show_only_selected();
return under - over;
}
static void iso_auto_run()
{
menu_show_only_selected();
if (lens_info.raw_iso == 0) { lens_set_rawiso(96); msleep(500); }
int c0 = crit_iso(-1); // test current iso
int i;
if (c0 > 0) i = bin_search(raw2index_iso(lens_info.raw_iso), COUNT(codes_iso), crit_iso);
else i = bin_search(get_htp() ? 9 : 1, raw2index_iso(lens_info.raw_iso)+1, crit_iso);
lens_set_rawiso(codes_iso[i]);
//~ clrscr();
}
static void
shutter_display( void * priv, int x, int y, int selected )
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Shutter : 1/%d",
lens_info.shutter
);
bmp_printf(FONT_MED, x + 550, y+5, "[Q]=Auto");
menu_draw_icon(x, y, MNI_PERCENT, (lens_info.raw_shutter - codes_shutter[1]) * 100 / (codes_shutter[COUNT(codes_shutter)-1] - codes_shutter[1]));
}
static void
shutter_toggle( int sign)
{
int i = raw2index_shutter(lens_info.raw_shutter);
int k;
for (k = 0; k < 10; k++)
{
i = mod(i + sign, COUNT(codes_shutter));
lens_set_rawshutter(codes_shutter[i]);
msleep(100);
int j = raw2index_shutter(lens_info.raw_shutter);
if (i == j) break;
}
menu_show_only_selected();
}
static void
shutter_toggle_forward( void * priv )
{
shutter_toggle(1);
}
static void
shutter_toggle_reverse( void * priv )
{
shutter_toggle(-1);
}
static void shutter_auto_quick()
{
if (MENU_MODE) return;
if (lens_info.raw_iso == 0) return; // does not work on Auto ISO
int ciso = lens_info.raw_iso;
int steps = measure_auto_iso() - ciso; // read delta exposure and compute new shutter value
int newshutter = COERCE(lens_info.raw_shutter - steps, 96, 152);
lens_set_rawiso(ciso); // restore iso
lens_set_rawshutter(newshutter); // set new shutter value
}
int shutter_auto_flag = 0;
static void shutter_auto()
{
if (lv_drawn()) shutter_auto_flag = 1; // it takes some time, so it's better to do it in another task
else
{
shutter_auto_quick();
shutter_auto_quick();
}
}
int crit_shutter(int shutter_index)
{
if (!lv_drawn()) return 0;
if (shutter_index >= 0)
{
lens_set_rawshutter(codes_shutter[shutter_index]);
msleep(500);
}
int under, over;
get_under_and_over_exposure_autothr(&under, &over);
menu_show_only_selected();
return over - under;
}
static void shutter_auto_run()
{
menu_show_only_selected();
int c0 = crit_shutter(-1); // test current shutter
int i;
if (c0 > 0) i = bin_search(raw2index_shutter(lens_info.raw_shutter), COUNT(codes_shutter), crit_shutter);
else i = bin_search(1, raw2index_shutter(lens_info.raw_shutter)+1, crit_shutter);
lens_set_rawshutter(codes_shutter[i]);
//~ clrscr();
}
static void
aperture_display( void * priv, int x, int y, int selected )
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Aperture : f/%d.%d",
lens_info.aperture / 10,
lens_info.aperture % 10
);
menu_draw_icon(x, y, lens_info.aperture ? MNI_PERCENT : MNI_WARNING, (lens_info.raw_aperture - codes_aperture[1]) * 100 / (codes_shutter[COUNT(codes_aperture)-1] - codes_aperture[1]));
}
static void
aperture_toggle( int sign)
{
int amin = codes_aperture[1];
int amax = codes_aperture[COUNT(codes_aperture)-1];
int a = lens_info.raw_aperture;
int a0 = a;
int k;
for (k = 0; k < 20; k++)
{
a += sign;
if (a > amax) a = amin;
if (a < amin) a = amax;
lens_set_rawaperture(a);
msleep(100);
if (lens_info.raw_aperture != a0) break;
}
menu_show_only_selected();
}
static void
aperture_toggle_forward( void * priv )
{
aperture_toggle(1);
}
static void
aperture_toggle_reverse( void * priv )
{
aperture_toggle(-1);
}
void
kelvin_toggle( 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;
}
k = (k/KELVIN_STEP) * KELVIN_STEP;
k = KELVIN_MIN + mod(k - KELVIN_MIN + sign * KELVIN_STEP, KELVIN_MAX - KELVIN_MIN + KELVIN_STEP);
lens_set_kelvin(k);
menu_show_only_selected();
}
static void
kelvin_toggle_forward( void * priv )
{
kelvin_toggle(1);
}
static void
kelvin_toggle_reverse( void * priv )
{
kelvin_toggle(-1);
}
PROP_INT( PROP_WB_KELVIN_PH, wb_kelvin_ph );
static void
kelvin_display( void * priv, int x, int y, int selected )
{
if (lens_info.wb_mode == WB_KELVIN)
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"WhiteBalance: %dK%s",
lens_info.kelvin,
lens_info.kelvin == wb_kelvin_ph ? "" : "*"
);
menu_draw_icon(x, y, MNI_PERCENT, (lens_info.kelvin - KELVIN_MIN) * 100 / (KELVIN_MAX - KELVIN_MIN));
}
else
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"WhiteBalance: %s",
(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 ? "CFL" :
(lens_info.wb_mode == 5 ? "Flash" :
(lens_info.wb_mode == 6 ? "Custom" :
(lens_info.wb_mode == 8 ? "Shade" :
"unknown"))))))))
);
menu_draw_icon(x, y, MNI_AUTO, 0);
}
bmp_printf(FONT_MED, x + 550, y+5, "[Q]=Auto");
}
int kelvin_auto_flag = 0;
int wbs_gm_auto_flag = 0;
static void kelvin_auto()
{
if (lv_drawn()) kelvin_auto_flag = 1;
else
{
bmp_printf(FONT_LARGE, 20,450, "Only works in LiveView");
msleep(1000);
bmp_printf(FONT_LARGE, 20,450, " ");
}
}
static void wbs_gm_auto()
{
if (lv_drawn()) wbs_gm_auto_flag = 1;
else
{
bmp_printf(FONT_LARGE, 20,450, "Only works in LiveView");
msleep(1000);
bmp_printf(FONT_LARGE, 20,450, " ");
}
}
int crit_kelvin(int k)
{
if (!lv_drawn()) return 0;
if (k > 0)
{
lens_set_kelvin(k * KELVIN_STEP);
msleep(500);
}
int Y, U, V;
get_spot_yuv(100, &Y, &U, &V);
menu_show_only_selected();
int R = Y + 1437 * V / 1024;
//~ int G = Y - 352 * U / 1024 - 731 * V / 1024;
int B = Y + 1812 * U / 1024;
return B - R;
}
int crit_wbs_gm(int k)
{
if (!lv_drawn()) return 0;
if (k < 10 && k > -10)
{
lens_set_wbs_gm(k);
msleep(500);
menu_show_only_selected();
}
int Y, U, V;
get_spot_yuv(100, &Y, &U, &V);
int R = Y + 1437 * V / 1024;
int G = Y - 352 * U / 1024 - 731 * V / 1024;
int B = Y + 1812 * U / 1024;
menu_show_only_selected();
return (R+B)/2 - G;
}
static void kelvin_auto_run()
{
menu_show_only_selected();
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);
//~ clrscr();
}
static void wbs_gm_auto_run()
{
menu_show_only_selected();
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);
}
static void
wbs_gm_display( void * priv, int x, int y, int selected )
{
int gm = lens_info.wbs_gm;
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"WBShift G/M : %s%d",
gm > 0 ? "Green " : (gm < 0 ? "Magenta " : ""),
ABS(gm)
);
menu_draw_icon(x, y, MNI_PERCENT, (-lens_info.wbs_gm + 9) * 100 / 18);
bmp_printf(FONT_MED, x + 550, y+5, "[Q]=Auto");
}
static void
wbs_gm_toggle( 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);
menu_show_only_selected();
}
static void
wbs_gm_toggle_forward( void * priv )
{
wbs_gm_toggle(-1);
}
static void
wbs_gm_toggle_reverse( void * priv )
{
wbs_gm_toggle(1);
}
static void
contrast_toggle( 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);
menu_show_only_selected();
}
static void
contrast_toggle_forward( void * priv )
{
contrast_toggle(1);
}
static void
contrast_toggle_reverse( void * priv )
{
contrast_toggle(-1);
}
static void
contrast_display( void * priv, int x, int y, int selected )
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Contrast : %d ",
lens_get_contrast()
);
menu_draw_icon(x, y, MNI_PERCENT, (lens_get_contrast() + 4) * 100 / 8);
}
static void
sharpness_toggle( int sign )
{
int c = lens_get_sharpness();
if (c < 0 || c > 7) return;
int newc = mod(c + sign, 8);
lens_set_sharpness(newc);
menu_show_only_selected();
}
static void
sharpness_toggle_forward( void * priv )
{
sharpness_toggle(1);
}
static void
sharpness_toggle_reverse( void * priv )
{
sharpness_toggle(-1);
}
static void
sharpness_display( void * priv, int x, int y, int selected )
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Sharpness : %d ",
lens_get_sharpness()
);
menu_draw_icon(x, y, MNI_PERCENT, (lens_get_sharpness() + 4) * 100 / 8);
}
static void
saturation_toggle( 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);
menu_show_only_selected();
}
static void
saturation_toggle_forward( void * priv )
{
saturation_toggle(1);
}
static void
saturation_toggle_reverse( void * priv )
{
saturation_toggle(-1);
}
static void
saturation_display( void * priv, int x, int y, int selected )
{
int s = lens_get_saturation();
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
(s >= -4 && s <= 4) ?
"Saturation : %d " :
"Saturation : 0x%X",
s
);
menu_draw_icon(x, y, s >= -4 && s <= 4 ? MNI_PERCENT : MNI_OFF, (s + 4) * 100 / 8);
}
static void
picstyle_display( void * priv, int x, int y, int selected )
{
int p = lens_info.raw_picstyle;
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"PictureStyle: %s ",
p == 0x81 ? "Standard" :
p == 0x82 ? "Portrait" :
p == 0x83 ? "Landscape" :
p == 0x84 ? "Neutral" :
p == 0x85 ? "Faithful" :
p == 0x86 ? "Monochrome" :
p == 0x21 ? "User Def 1" :
p == 0x22 ? "User Def 2" :
p == 0x23 ? "User Def 3" : "Unknown"
);
menu_draw_icon(x, y, MNI_ON, 0);
}
static void
picstyle_toggle( int sign )
{
int p = lens_info.picstyle;
p = mod(p + sign - 1, 9) + 1;
p = get_prop_picstyle_from_index(p);
if (p) prop_request_change(PROP_PICTURE_STYLE, &p, 4);
menu_show_only_selected();
}
static void
picstyle_toggle_forward( void * priv )
{
picstyle_toggle(1);
}
static void
picstyle_toggle_reverse( void * priv )
{
picstyle_toggle(-1);
}
PROP_INT(PROP_STROBO_AECOMP, flash_ae);
static void
flash_ae_toggle( int sign )
{
int ae = (int8_t)flash_ae;
int newae = ae + sign * (ABS(ae) <= 16 ? 4 : 8);
if (newae > 24) newae = -80;
if (newae < -80) newae = 24;
ae &= 0xFF;
prop_request_change(PROP_STROBO_AECOMP, &newae, 4);
}
static void
flash_ae_toggle_forward( void * priv )
{
flash_ae_toggle(1);
}
static void
flash_ae_toggle_reverse( void * priv )
{
flash_ae_toggle(-1);
}
static void
flash_ae_display( void * priv, int x, int y, int selected )
{
int ae_ev = ((int8_t)flash_ae) * 10 / 8;
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Flash AEcomp: %d.%d EV",
ae_ev / 10,
ABS(ae_ev % 10)
);
menu_draw_icon(x, y, MNI_PERCENT, (ae_ev + 80) * 100 / (24+80));
}
uint32_t cfn1[2];
uint32_t cfn2[1];
uint32_t cfn3[2];
uint32_t cfn4[2];
PROP_HANDLER( PROP_CFN1 )
{
cfn1[0] = buf[0];
cfn1[1] = buf[1];
return prop_cleanup( token, property );
}
PROP_HANDLER( PROP_CFN2 )
{
cfn2[0] = buf[0];
return prop_cleanup( token, property );
}
PROP_HANDLER( PROP_CFN3 )
{
cfn3[0] = buf[0];
cfn3[1] = buf[1] & 0xFFFF;
return prop_cleanup( token, property );
}
PROP_HANDLER( PROP_CFN4 )
{
cfn3[0] = buf[0];
cfn3[1] = buf[1] & 0xFFFF;
return prop_cleanup( token, property );
}
int get_htp()
{
if (cfn2[0] & 0x1000000) return 1;
return 0;
}
void set_htp(int enable)
{
if (enable) cfn2[0] |= 0x1000000;
else cfn2[0] &= ~0x1000000;
prop_request_change(PROP_CFN2, cfn2, CFN2_LEN);
}
void set_mlu(int enable)
{
if (enable) cfn3[1] |= 0x100;
else cfn3[1] &= ~0x100;
prop_request_change(PROP_CFN3, cfn3, CFN3_LEN);
}
int get_mlu()
{
return cfn3[1] & 0x100;
}
void set_alo(int value)
{
value = COERCE(value, 0, 3);
prop_request_change(PROP_ALO, &value, 4);
}
// 0 = off, 1 = alo, 2 = htp
int get_ladj()
{
if (get_htp()) return 2;
if (alo != ALO_OFF) return 1;
return 0;
}
static void
ladj_toggle( int sign )
{
int ladj = get_ladj();
ladj = mod(ladj + sign, 3);
if (ladj == 0)
{
set_htp(0);
set_alo(ALO_OFF);
}
else if (ladj == 1)
{
set_htp(0);
set_alo(ALO_HIGH);
}
else
{
set_htp(1); // this disables ALO
}
menu_show_only_selected();
}
static void
ladj_toggle_forward( void * priv )
{
ladj_toggle(1);
}
static void
ladj_toggle_reverse( void * priv )
{
ladj_toggle(-1);
}
static void
ladj_display( void * priv, int x, int y, int selected )
{
int htp = get_htp();
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Light Adjust: %s",
(htp ? "HTP" :
(alo == ALO_STD ? "ALO std" :
(alo == ALO_LOW ? "ALO low" :
(alo == ALO_HIGH ? "ALO strong " :
(alo == ALO_OFF ? "OFF" : "err")))))
);
menu_draw_icon(x, y, alo != ALO_OFF ? MNI_ON : htp ? MNI_AUTO : MNI_OFF, 0);
}
static void
zoom_display( void * priv, int x, int y, int selected )
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"LiveView Zoom : %s%s %s",
zoom_disable_x5 ? "" : "x5",
zoom_disable_x10 ? "" : "x10",
zoom_enable_face ? ":-)" : ""
);
menu_draw_icon(x, y, MNI_BOOL(zoom_enable_face || zoom_disable_x5 || zoom_disable_x10), 0);
}
static void zoom_toggle(void* priv)
{
// x5 x10
// x5
// x10
if (!zoom_disable_x5 && !zoom_disable_x10) // both enabled
{
zoom_disable_x5 = 0;
zoom_disable_x10 = 1;
}
else if (!zoom_disable_x10)
{
zoom_disable_x5 = 0;
zoom_disable_x10 = 0;
}
else
{
zoom_disable_x5 = 1;
zoom_disable_x10 = 0;
}
}
int hdr_steps = 1;
CONFIG_INT("hdr.stepsize", hdr_stepsize, 8);
static void
hdr_display( void * priv, int x, int y, int selected )
{
if (hdr_steps == 1)
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"HDR Bracketing : OFF"
);
}
else
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"HDR Bracketing : %dx%d%sEV",
hdr_steps,
hdr_stepsize / 8,
((hdr_stepsize/4) % 2) ? ".5" : ""
);
}
menu_draw_icon(x, y, MNI_BOOL(hdr_steps != 1), 0);
}
static void
hdr_steps_toggle( void * priv )
{
hdr_steps = mod(hdr_steps + (hdr_steps <= 2 ? 0 : 1), 10) + 1;
}
static void
hdr_stepsize_toggle( void * priv )
{
hdr_stepsize = (hdr_stepsize < 8) ? MAX(hdr_stepsize * 2, 4) : (hdr_stepsize/8)*8 + 8;
if (hdr_stepsize > 40) hdr_stepsize = 0;
}
static void
hdr_reset( void * priv )
{
hdr_steps = 1;
hdr_stepsize = 8;
}
int is_bulb_mode()
{
if (shooting_mode == SHOOTMODE_BULB) return 1;
if (shooting_mode != SHOOTMODE_M) return 0;
if (lens_info.raw_shutter != 0xC) return 0;
return 1;
}
static void
bulb_take_pic(int duration)
{
if (!is_bulb_mode())
{
bmp_printf(FONT_LARGE, 0, 30, "Pls select bulb mode");
return;
}
if (drive_mode != DRIVE_SINGLE) lens_set_drivemode(DRIVE_SINGLE);
if (get_mlu()) { lens_take_picture(64); msleep(2000); }
SW1(1,100);
SW2(1,100);
int i;
int d = duration/1000;
for (i = 0; i < d; i++)
{
bmp_printf(FONT_LARGE, 30, 30, "Bulb timer: %d%s", d < 60 ? d : d/60, d < 60 ? "s" : "min");
msleep(1000);
if (lens_info.job_state == 0) break;
}
SW2(0,100);
SW1(0,100);
}
static void bulb_toggle_fwd(void* priv)
{
bulb_duration_index = mod(bulb_duration_index + 1, COUNT(timer_values));
}
static void bulb_toggle_rev(void* priv)
{
bulb_duration_index = mod(bulb_duration_index - 1, COUNT(timer_values));
}
static void
bulb_display( void * priv, int x, int y, int selected )
{
int d = timer_values[bulb_duration_index];
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Bulb Timer %s: %d%s",
is_bulb_mode() ? " " : "(N/A)",
d < 60 ? d : d/60,
d < 60 ? "s" : "min"
);
menu_draw_icon(x, y, !bulb_duration_index ? MNI_OFF : is_bulb_mode() ? MNI_PERCENT : MNI_WARNING, bulb_duration_index * 100 / COUNT(timer_values));
}
static void
mlu_display( void * priv, int x, int y, int selected )
{
//~ int d = timer_values[bulb_duration_index];
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Mirror Lockup : %s",
mlu_mode == 1 ? "ON" : mlu_mode == 2 ? "Timer+Remote" : "OFF"
);
menu_draw_icon(x, y, MNI_BOOL_AUTO(mlu_mode), 0);
}
static void
intervalometer_wait_toggle(void* priv)
{
intervalometer_wait = !intervalometer_wait;
}
static void
picq_display( void * priv, int x, int y, int selected )
{
int raw = pic_quality & 0x60000;
int rawsize = pic_quality & 0xF;
int jpegtype = pic_quality >> 24;
int jpegsize = (pic_quality >> 8) & 0xF;
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Picture Quality : %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_draw_icon(x, y, MNI_ON, 0);
}
static void picq_toggle_rawsize(void* priv)
{
int p = pic_quality;
int r = p & 0xF;
r = mod(r+1, 3);
int newp = (p & 0xfffffff0) | r;
set_pic_quality(newp);
}
static void picq_toggle_raw_on_off(void* priv)
{
int raw = pic_quality & 0x60000;
int newp;
if (raw)
{
int jt = (pic_quality >> 24) & 0xF;
if (jt == 4) newp = PICQ_LARGE_FINE;
else newp = (pic_quality & 0xf0f1fff0) | (jt << 24);
}
else newp = pic_quality | 0x60000;
console_printf("%x\n", newp);
set_pic_quality(newp);
}
static void picq_toggle_raw(void* priv)
{
int raw = pic_quality & 0x60000;
int rsize = pic_quality & 0xF;
if (raw && rsize < 2) picq_toggle_rawsize(0);
else picq_toggle_raw_on_off(0);
}
static void picq_toggle_jpegsize(void* priv)
{
int js = (pic_quality >> 8) & 0xF;
js = mod(js+1, 3);
int newp = (pic_quality & 0xfffff0ff) | (js << 8);
set_pic_quality(newp);
}
static void picq_toggle_jpegtype(void* priv)
{
int jt = (pic_quality >> 24) & 0xF;
jt = mod(jt-1, 3) + 2;
int newp = (pic_quality & 0xf0ffffff) | (jt << 24);
int raw = pic_quality & 0x60000;
int rawsize = pic_quality & 0xF;
if (jt == 4) newp = PICQ_RAW + rawsize;
set_pic_quality(newp);
}
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);
}
struct menu_entry shoot_menus[] = {
{
.display = hdr_display,
.select = hdr_steps_toggle,
.select_reverse = hdr_stepsize_toggle,
.select_auto = hdr_reset,
.help = "Exposure bracketing, useful for HDR images."
},
{
.priv = &interval_timer_index,
.display = interval_timer_display,
.select = interval_timer_toggle,
.select_reverse = interval_timer_toggle_reverse,
.select_auto = interval_movie_duration_toggle,
.help = "Intervalometer setting: duration between two shots."
},
{
.priv = &intervalometer_running,
.select = menu_binary_toggle,
.display = intervalometer_display,
.select_auto = intervalometer_wait_toggle,
.help = "Intervalometer. For precise timing, choose NoWait [Q]."
},
/*{
.priv = &lcd_release_running,
.select = menu_quaternary_toggle,
.select_reverse = menu_quaternary_toggle_reverse,
.display = lcd_release_display,
},*/
{
.priv = &audio_release_running,
.select = menu_binary_toggle,
.display = audio_release_display,
.select_auto = audio_release_level_toggle,
.select_reverse = audio_release_level_toggle_reverse,
.help = "Clap your hands or pop a balloon to take a picture."
},
{
.priv = &motion_detect,
.select = menu_ternary_toggle,
.display = motion_detect_display,
.select_auto = motion_release_level_toggle,
.select_reverse = motion_release_level_toggle_reverse,
.help = "LV Motion detection: EXPosure change / frame DIFference."
},
/* {
.select = flash_and_no_flash_toggle,
.display = flash_and_no_flash_display,
.help = "Take odd pictures with flash, even pictures without flash."
},*/
{
.priv = &silent_pic_mode,
.select = silent_pic_mode_toggle,
.select_reverse = silent_pic_toggle_reverse,
.select_auto = silent_pic_toggle_forward,
.display = silent_pic_display,
.help = "Take pics in LiveView without increasing shutter count."
},
{
.display = bulb_display,
.select = bulb_toggle_fwd,
.select_reverse = bulb_toggle_rev,
.select_auto = bulb_toggle_fwd,
.help = "Bulb timer for very long exposures, useful for astrophotos"
},
{
.priv = &mlu_mode,
.display = mlu_display,
.select = menu_ternary_toggle,
.help = "MLU setting can be linked with self-timer and LCD remote."
},
/*{
.display = picq_display,
.select = picq_toggle_raw,
.select_reverse = picq_toggle_jpegsize,
.select_auto = picq_toggle_jpegtype,
}
{
.display = picq_display,
.select = picq_toggle,
.help = "Experimental SRAW/MRAW mode. You may get corrupted files."
}*/
};
static struct menu_entry vid_menus[] = {
{
.priv = &zoom_enable_face,
.select = menu_binary_toggle,
.select_reverse = zoom_toggle,
.display = zoom_display,
.help = "Disable x5 or x10, or enable zoom during Face Detection :)"
},
};
struct menu_entry expo_menus[] = {
{
.display = iso_display,
.select = iso_toggle_forward,
.select_reverse = iso_toggle_reverse,
.select_auto = iso_auto,
.help = "Adjust ISO in 1/8EV steps. Press [Q] for auto tuning."
},
{
.display = kelvin_display,
.select = kelvin_toggle_forward,
.select_reverse = kelvin_toggle_reverse,
.select_auto = kelvin_auto,
.help = "Adjust Kelvin WB. Press [Q] for auto tuning."
},
{
.display = wbs_gm_display,
.select = wbs_gm_toggle_forward,
.select_reverse = wbs_gm_toggle_reverse,
.select_auto = wbs_gm_auto,
.help = "Green-Magenta white balance shift, for fluorescent lights."
},
{
.display = shutter_display,
.select = shutter_toggle_forward,
.select_reverse = shutter_toggle_reverse,
.select_auto = shutter_auto,
.help = "Shutter in 1/8EV steps. ML shows it with 2 nonzero digits."
},
{
.display = aperture_display,
.select = aperture_toggle_forward,
.select_reverse = aperture_toggle_reverse,
.help = "Adjust aperture. Useful if the wheel stops working."
},
{
.display = ladj_display,
.select = ladj_toggle_forward,
.select_reverse = ladj_toggle_reverse,
.help = "Enable/disable HTP and ALO from the same place."
},
{
.display = picstyle_display,
.select = picstyle_toggle_forward,
.select_reverse = picstyle_toggle_reverse,
.help = "Change current picture style."
},
{
.display = contrast_display,
.select = contrast_toggle_forward,
.select_reverse = contrast_toggle_reverse,
//~ .select_auto = contrast_auto,
.help = "Adjust contrast in current picture style."
},
{
.display = saturation_display,
.select = saturation_toggle_forward,
.select_reverse = saturation_toggle_reverse,
.help = "Adjust saturation in current picture style."
},
{
.display = flash_ae_display,
.select = flash_ae_toggle_forward,
.select_reverse = flash_ae_toggle_reverse,
.help = "Flash exposure compensation, from -10EV to +3EV."
},
/*{
.display = sharpness_display,
.select = sharpness_toggle_forward,
.select_reverse = sharpness_toggle_reverse,
},*/
};
void hdr_create_script(int steps, int skip0, int focus_stack)
{
if (steps <= 1) return;
DEBUG();
FILE * f = INVALID_PTR;
char name[100];
int f0 = skip0 ? file_number_also : file_number_also+1;
snprintf(name, sizeof(name), "B:/DCIM/%03dCANON/%s_%04d.sh", folder_number, focus_stack ? "FST" : "HDR", f0);
DEBUG("name=%s", name);
FIO_RemoveFile(name);
f = FIO_CreateFile(name);
if ( f == INVALID_PTR )
{
bmp_printf( FONT_LARGE, 30, 30, "FCreate: Err %s", name );
return;
}
DEBUG();
my_fprintf(f, "#!/usr/bin/env bash\n");
my_fprintf(f, "\n# %s_%04d.JPG from IMG_%04d.JPG ... IMG_%04d.JPG\n\n", focus_stack ? "FST" : "HDR", f0, f0, 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);
int i;
for( i = 0; i < steps; i++ )
{
my_fprintf(f, "IMG_%04d.JPG ", mod(f0 + i, 10000));
}
my_fprintf(f, "\n");
DEBUG();
FIO_CloseFile(f);
DEBUG();
}
void hdr_shutter_release()
{
lens_wait_readytotakepic(64);
if (!silent_pic_mode || !lv_drawn())
{
if (get_mlu()) { lens_take_picture(64); msleep(500); }
lens_take_picture(64);
}
else { msleep(300); silent_pic_take(0); }
}
// skip0: don't take the middle exposure
void hdr_take_pics(int steps, int step_size, int skip0)
{
if (step_size) hdr_create_script(steps, skip0, 0);
int i;
if ((lens_info.iso && shooting_mode == SHOOTMODE_M) || (shooting_mode == SHOOTMODE_MOVIE))
{
const int s = lens_info.raw_shutter;
for( i = -steps/2; i <= steps/2; i ++ )
{
if (skip0 && (i == 0)) continue;
bmp_printf(FONT_LARGE, 0, 200, "%d ", i);
int new_s = COERCE(s - step_size * i, 0x10, 160);
lens_set_rawshutter( new_s );
hdr_shutter_release();
}
msleep(100);
lens_set_rawshutter( s );
}
else
{
const int ae = lens_get_ae();
for( i = -steps/2; i <= steps/2; i ++ )
{
if (skip0 && (i == 0)) continue;
bmp_printf(FONT_LARGE, 0, 200, "%d ", i);
int new_ae = ae + step_size * i;
lens_set_ae( new_ae );
hdr_shutter_release();
}
lens_set_ae( ae );
}
}
void movie_start()
{
if (shooting_type != 3 && shooting_mode != SHOOTMODE_MOVIE)
{
bmp_printf(FONT_LARGE, 30, 30, "Not in movie (%d,%d) ", shooting_type, shooting_mode);
return;
}
if (recording)
{
bmp_printf(FONT_LARGE, 30, 30, "Already recording ");
return;
}
while (get_halfshutter_pressed()) msleep(100);
call("MovieStart");
while (recording != 2) msleep(100);
msleep(500);
}
void movie_end()
{
if (shooting_type != 3 && shooting_mode != SHOOTMODE_MOVIE)
{
bmp_printf(FONT_LARGE, 30, 30, "Not in movie (%d,%d) ", shooting_type, shooting_mode);
return;
}
if (!recording)
{
bmp_printf(FONT_LARGE, 30, 30, "Not recording ");
return;
}
while (get_halfshutter_pressed()) msleep(100);
msleep(500);
call("MovieEnd");
while (recording) msleep(100);
msleep(500);
}
static void
hdr_take_mov(int steps, int step_size)
{
int g = get_global_draw();
set_global_draw(0);
clrscr();
movie_start();
int i;
const int s = lens_info.raw_shutter;
for( i = -steps/2; i <= steps/2; i ++ )
{
bmp_printf(FONT_LARGE, 30, 30, "%d ", i);
int new_s = COERCE(s - step_size * i, 96, 152);
lens_set_rawshutter( new_s );
msleep(timer_values[interval_movie_duration_index] * 1000);
}
lens_set_rawshutter( s );
movie_end();
set_global_draw(g);
}
// take a HDR shot (sequence of stills or a small movie)
// to be used with the intervalometer
void hdr_shot(int skip0, int wait)
{
//~ bmp_printf(FONT_LARGE, 50, 50, "SKIP%d", skip0);
//~ msleep(2000);
if (is_bulb_mode())
{
bulb_take_pic(timer_values[bulb_duration_index] * 1000);
}
else if (shooting_mode == SHOOTMODE_MOVIE && !silent_pic_mode)
{
hdr_take_mov(hdr_steps, hdr_stepsize);
}
else if (hdr_steps > 1)
{
if (drive_mode != DRIVE_SINGLE && drive_mode != DRIVE_CONTINUOUS)
lens_set_drivemode(DRIVE_CONTINUOUS);
if (hdr_steps == 2)
hdr_take_pics(hdr_steps, hdr_stepsize/2, 1);
else
hdr_take_pics(hdr_steps, hdr_stepsize, skip0);
while (lens_info.job_state) msleep(500);
}
else // regular pic
{
if (wait)
{
hdr_take_pics(0,0,0);
}
else
{
if (!silent_pic_mode || !lv_drawn()) lens_take_picture(0);
else silent_pic_take(0);
return;
}
}
while (lens_info.job_state) msleep(500);
}
int remote_shot_flag = 0;
void schedule_remote_shot() { remote_shot_flag = 1; }
int movie_start_flag = 0;
void schedule_movie_start() { movie_start_flag = 1; }
int is_movie_start_scheduled() { return movie_start_flag; }
int movie_end_flag = 0;
void schedule_movie_end() { movie_end_flag = 1; }
void get_out_of_play_mode()
{
if (gui_state == GUISTATE_QR)
{
fake_simple_button(BGMT_PLAY);
msleep(200);
fake_simple_button(BGMT_PLAY);
}
else if (PLAY_MODE)
{
fake_simple_button(BGMT_PLAY);
}
while (PLAY_MODE) msleep(100);
msleep(500);
}
// take one shot, a sequence of HDR shots, or start a movie
// to be called by remote triggers
void remote_shot()
{
// save zoom value (x1, x5 or x10)
int zoom = lv_dispsize;
if (is_bulb_mode())
{
bulb_take_pic(timer_values[bulb_duration_index] * 1000);
}
else if (hdr_steps > 1)
{
hdr_shot(0,1);
}
else
{
if (silent_pic_mode && lv_drawn())
silent_pic_take(0);
else if (shooting_mode == SHOOTMODE_MOVIE)
movie_start();
else
lens_take_picture(64); // hdr_shot messes with the self timer mode
}
msleep(200);
if (get_mlu() && lens_info.job_state < 10) return;
while (lens_info.job_state >= 10) msleep(500);
msleep(1000);
while (gui_state != GUISTATE_IDLE) msleep(100);
msleep(500);
// restore zoom
if (lv_drawn() && !recording && zoom > 1) prop_request_change(PROP_LV_DISPSIZE, &zoom, 4);
}
void iso_refresh_display()
{
if (lv_drawn())
{
update_lens_display(lens_info);
return;
}
int bg = bmp_getpixel(680, 40);
uint32_t fnt = FONT(FONT_MED, COLOR_FG_NONLV, bg);
int iso = lens_info.iso;
if (iso)
{}//~ bmp_printf(fnt, 560, 27, "ISO %5d", iso);
else
bmp_printf(fnt, 560, 27, "ISO AUTO");
}
void display_shooting_info() // called from debug task
{
if (lv_drawn()) return;
int bg = bmp_getpixel(314, 260);
uint32_t fnt = FONT(FONT_MED, COLOR_FG_NONLV, bg);
if (lens_info.wb_mode == WB_KELVIN)
{
bmp_printf(fnt, 360, 279, "%5dK", lens_info.kelvin);
}
if (lens_info.wbs_gm || lens_info.wbs_ba)
{
bg = bmp_getpixel(15, 430);
fnt = FONT(FONT_MED, COLOR_FG_NONLV, bg);
int ba = lens_info.wbs_ba;
if (ba) bmp_printf(fnt, 320 + 2 * font_med.width, 450, "%s%d", ba > 0 ? "A" : "B", ABS(ba));
else bmp_printf(fnt, 320 + 2 * font_med.width, 450, " ");
int gm = lens_info.wbs_gm;
if (gm) bmp_printf(fnt, 320, 450, "%s%d", gm > 0 ? "G" : "M", ABS(gm));
else bmp_printf(fnt, 320, 450, " ");
}
iso_refresh_display();
bg = bmp_getpixel(15, 430);
fnt = FONT(FONT_MED, COLOR_FG_NONLV, bg);
if (hdr_steps > 1)
bmp_printf(fnt, 190, 450, "HDR %dx%dEV", hdr_steps, hdr_stepsize/8);
else
bmp_printf(fnt, 190, 450, " ");
//~ bmp_printf(fnt, 400, 450, "Flash:%s",
//~ strobo_firing == 0 ? " ON" :
//~ strobo_firing == 1 ? "OFF" : "Auto"
//~ strobo_firing < 2 && flash_and_no_flash ? "/T" : " "
//~ );
bmp_printf(fnt, 40, 460, get_mlu() ? "MLU" : " ");
//~ display_lcd_remote_info();
display_trap_focus_info();
}
void display_expsim_status()
{
static int prev_expsim = 0;
if (!expsim)
{
int x = 610 + 2 * font_med.width;
int y = 400;
bmp_printf( FONT(FONT_MED, COLOR_WHITE, 0), x, y, "ExpSim" );
draw_line(x-5, y + font_med.height * 3/4, x + font_med.width * 6, y + font_med.height * 1/4, COLOR_WHITE);
}
else
{
if (expsim != prev_expsim) redraw_nosem(); // this function is inside a BMP_SEM
}
prev_expsim = expsim;
}
void display_shooting_info_lv()
{
//~ display_lcd_remote_info();
display_trap_focus_info();
display_expsim_status();
}
void display_trap_focus_info()
{
int show, fg, bg, x, y;
static int show_prev = 0;
if (lv_drawn())
{
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(35, 365);
fg = trap_focus == 2 || FOCUS_CONFIRMATION_AF_PRESSED ? COLOR_RED : COLOR_FG_NONLV;
x = 35; y = 365;
if (show || show_prev) bmp_printf(FONT(FONT_MED, fg, bg), x, y, show ? "TRAP FOCUS" : " ");
}
show_prev = show;
}
// may be unreliable
int wait_for_lv_err_msg(int wait) // 1 = msg appeared, 0 = did not appear
{
int i;
for (i = 0; i <= wait/20; i++)
{
int msgcolor = 3; // may give wrong results if cropmark uses this color; may be camera-dependent
if (bmp_getpixel(300,150) == msgcolor &&
bmp_getpixel(60,250) == msgcolor &&
bmp_getpixel(400,300) == msgcolor
) return 1;
msleep(20);
}
return 0;
}
int wave_count = 0;
int wave_count_countdown = 0;
int display_sensor_active = 0;
/*PROP_HANDLER(PROP_DISPSENSOR_CTRL)
{
int on = !buf[0];
int off = !on;
if (on == display_sensor_active) // false alarm
goto end;
display_sensor_active = on;
if (lcd_release_running && lens_info.job_state == 0 && gui_state == GUISTATE_IDLE && !intervalometer_running)
{
if (gui_menu_shown()) goto end;
if (lcd_release_running == 1 && off) goto end;
if (lcd_release_running == 2 && on && !get_mlu()) goto end;
if (lcd_release_running == 3) { wave_count++; wave_count_countdown = 75; }
if (lcd_release_running == 3 && wave_count < 5) goto end;
if (lcd_release_running == 3 && recording) schedule_movie_end(); // wave mode is allowed to stop movies
else schedule_remote_shot();
wave_count = 0;
}
else wave_count = 0;
end:
return prop_cleanup(token, property);
}*/
/*
void display_lcd_remote_info()
{
int x0 = 480;
int cl_on = COLOR_RED;
int cl_off = lv_drawn() ? COLOR_WHITE : COLOR_FG_NONLV;
int cl = display_sensor ? cl_on : cl_off;
int bg = lv_drawn() ? 0 : bmp_getpixel(x0 - 20, 1);
if (lcd_release_running == 1)
{
draw_circle(x0, 10, 8, cl);
draw_circle(x0, 10, 7, cl);
draw_line(x0-5,10-5,x0+5,10+5,cl);
draw_line(x0-5,10+5,x0+5,10-5,cl);
}
else if (lcd_release_running == 2)
{
draw_circle(x0, 10, 8, cl);
draw_circle(x0, 10, 7, cl);
draw_circle(x0, 10, 1, cl);
draw_circle(x0, 10, 2, cl);
}
else if (lcd_release_running == 3)
{
int yup = 5;
int ydn = 15;
int step = 5;
int k;
for (k = 0; k < 2; k++)
{
draw_line(x0 - 2*step, ydn, x0 - 1*step, yup, wave_count > 0 ? cl_on : cl_off);
draw_line(x0 - 1*step, yup, x0 - 0*step, ydn, wave_count > 1 ? cl_on : cl_off);
draw_line(x0 - 0*step, ydn, x0 + 1*step, yup, wave_count > 2 ? cl_on : cl_off);
draw_line(x0 + 1*step, yup, x0 + 2*step, ydn, wave_count > 3 ? cl_on : cl_off);
draw_line(x0 + 2*step, ydn, x0 + 3*step, yup, wave_count > 4 ? cl_on : cl_off);
x0++;
}
}
if (gui_menu_shown()) return;
static unsigned int prev_lr = 0;
if (prev_lr != lcd_release_running) bmp_fill(bg, x0 - 20, y0, 40, 20);
prev_lr = lcd_release_running;
}*/
void intervalometer_stop()
{
if (intervalometer_running)
{
bmp_printf(FONT_MED, 20, (lv_drawn() ? 40 : 3), "Stopped ");
intervalometer_running = 0;
//~ display_on();
}
}
// this syncs with real-time clock
void wait_till_next_second()
{
struct tm now;
LoadCalendarFromRTC( &now );
int s = now.tm_sec;
while (now.tm_sec == s)
{
LoadCalendarFromRTC( &now );
msleep(20);
}
}
int sw1_pressed = 0;
static void
shoot_task( void* unused )
{
int i = 0;
menu_add( "Shoot", shoot_menus, COUNT(shoot_menus) );
menu_add( "Expo", expo_menus, COUNT(expo_menus) );
msleep(1000);
menu_add( "Tweak", vid_menus, COUNT(vid_menus) );
// :-)
struct tm now;
LoadCalendarFromRTC( &now );
if (now.tm_mday == 1 && now.tm_mon == 3)
{
toggle_mirror_display();
}
while(1)
{
msleep(10);
if (wave_count_countdown)
{
wave_count_countdown--;
if (!wave_count_countdown) wave_count = 0;
}
if (iso_auto_flag)
{
iso_auto_run();
iso_auto_flag = 0;
}
if (shutter_auto_flag)
{
shutter_auto_run();
shutter_auto_flag = 0;
}
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;
}
if (remote_shot_flag)
{
remote_shot();
remote_shot_flag = 0;
}
if (movie_start_flag)
{
movie_start();
movie_start_flag = 0;
}
if (movie_end_flag)
{
movie_end();
movie_end_flag = 0;
}
if (!lv_drawn()) // MLU
{
if (mlu_mode == 0 && get_mlu()) set_mlu(0);
if (mlu_mode == 1 && !get_mlu()) set_mlu(1);
if (mlu_mode == 2)
{
if ((drive_mode == DRIVE_SELFTIMER_2SEC || drive_mode == DRIVE_SELFTIMER_REMOTE/* || lcd_release_running == 2*/) && (hdr_steps < 2))
{
if (!get_mlu()) set_mlu(1);
}
else
{
if (get_mlu()) set_mlu(0);
}
}
}
if (lv_drawn() && face_zoom_request && lv_dispsize == 1 && !recording)
{
if (lvaf_mode == 2 && wait_for_lv_err_msg(200)) // zoom request in face detect mode; temporary switch to live focus mode
{
int afmode = 1;
int zoom = 5;
int afx = afframe[2];
int afy = afframe[3];
prop_request_change(PROP_LVAF_MODE, &afmode, 4);
msleep(100);
afframe[2] = afx;
afframe[3] = afy;
prop_request_change(PROP_LV_AFFRAME, afframe, 0x68);
msleep(1);
prop_request_change(PROP_LV_DISPSIZE, &zoom, 4);
msleep(1);
}
else if (lvaf_mode == 1) // back from temporary live focus mode
{
int afmode = 2;
prop_request_change(PROP_LVAF_MODE, &afmode, 4);
msleep(100);
face_zoom_request = 0;
//~ bmp_printf(FONT_LARGE, 10, 50, " ");
}
else // cancel zoom request
{
msleep(100);
face_zoom_request = 0;
//~ bmp_printf(FONT_LARGE, 10, 50, "Zoom :(");
}
}
if (zoom_disable_x5 && lv_dispsize == 5)
{
int zoom = 10;
prop_request_change(PROP_LV_DISPSIZE, &zoom, 4);
msleep(100);
}
if (zoom_disable_x10 && lv_dispsize == 10)
{
int zoom = 1;
prop_request_change(PROP_LV_DISPSIZE, &zoom, 4);
msleep(100);
}
/*if (sweep_lv_on)
{
sweep_lv();
sweep_lv_on = 0;
}*/
if (center_lv_aff)
{
center_lv_afframe_do();
center_lv_aff = 0;
}
// avoid camera shake for HDR shots => force self timer
if (hdr_steps > 1 && get_halfshutter_pressed() && drive_mode != DRIVE_SELFTIMER_2SEC)
{
drive_mode_bk = drive_mode;
lens_set_drivemode(DRIVE_SELFTIMER_2SEC);
}
// restore drive mode if it was changed
if (!get_halfshutter_pressed() && drive_mode_bk >= 0)
{
lens_set_drivemode(drive_mode_bk);
drive_mode_bk = -1;
}
if (bulb_duration_index && 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() && gui_state == GUISTATE_IDLE;
int is_idle_and_pressed = get_halfshutter_pressed() && gui_state == GUISTATE_IDLE;
if (was_idle_not_pressed && is_idle_and_pressed)
{
int d = timer_values[bulb_duration_index];
while (get_halfshutter_pressed())
{
bmp_printf(FONT_LARGE, 0, 0, "[HS] Bulb timer: %d%s", d < 60 ? d : d/60, d < 60 ? "s" : "min");
msleep(100);
}
bmp_printf(FONT_LARGE, 0, 0, "[2s] Bulb timer: %d%s", d < 60 ? d : d/60, d < 60 ? "s" : "min");
msleep(1000);
if (gui_state != GUISTATE_IDLE) continue;
bmp_printf(FONT_LARGE, 0, 0, "[1s] Bulb timer: %d%s", d < 60 ? d : d/60, d < 60 ? "s" : "min");
msleep(1000);
if (gui_state != GUISTATE_IDLE) continue;
bulb_take_pic(d * 1000);
}
was_idle_not_pressed = is_idle_not_pressed;
}
if (lens_info.job_state) // just took a picture, maybe we should take another one
{
if (hdr_steps > 1) hdr_shot(1,1); // skip the middle exposure, which was just taken
}
// toggle flash on/off for next picture
/*if (shooting_mode != SHOOTMODE_MOVIE && flash_and_no_flash && strobo_firing < 2 && strobo_firing != file_number % 2)
{
strobo_firing = file_number % 2;
set_flash_firing(strobo_firing);
}*/
//~ static int sw1_countdown = 0;
// trap focus (outside LV) and all the preconditions
int tfx = trap_focus && (af_mode & 0xF) == 3 && gui_state == GUISTATE_IDLE && !gui_menu_shown() && !intervalometer_running;
// same for motion detect
int mdx = motion_detect && gui_state == GUISTATE_IDLE && !gui_menu_shown() && lv_drawn();
//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;
// emulate half-shutter press (for trap focus or motion detection)
/* this can cause the camera not to shutdown properly...
if (!lv_drawn() && ((tfx && trap_focus == 2) || mdx ))
{
if (trap_focus == 2 && (cfn[2] & 0xF00) != 0) bmp_printf(FONT_MED, 0, 0, "Set CFn9 to 0 (AF on half-shutter press)");
if (!sw1_countdown) // press half-shutter periodically
{
if (sw1_pressed) { SW1(0,10); sw1_pressed = 0; }
{ SW1(1,10); sw1_pressed = 1; }
sw1_countdown = motion_detect ? 2 : 10;
}
else
{
sw1_countdown--;
}
}
else // cleanup sw1
if (sw1_pressed) { SW1(0,10); sw1_pressed = 0; } */
if (tfx) // MF
{
if ((!lv_drawn() && FOCUS_CONFIRMATION) || get_lv_focus_confirmation())
{
remote_shot();
msleep(trap_focus_delay);
}
}
if (mdx)
{
K = COERCE(K+1, 0, 1000);
//~ bmp_printf(FONT_MED, 0, 50, "K= %d ", K);
if (motion_detect == 1)
{
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(100, &y, &u, &v);
aev = y / 2;
if (K > 50) bmp_printf(FONT_MED, 0, 50, "Average exposure: %3d New exposure: %3d ", old_ae_avg/100, aev);
if (K > 50 && ABS(old_ae_avg/100 - aev) >= (int)motion_detect_level)
{
remote_shot();
msleep(trap_focus_delay);
K = 0;
}
old_ae_avg = old_ae_avg * 90/100 + aev * 10;
}
else if (motion_detect == 2)
{
int d = get_spot_motion(100, get_global_draw());
if (K > 50) bmp_printf(FONT_MED, 0, 50, "Motion level: %d ", d);
if (K > 50 && d >= (int)motion_detect_level)
{
remote_shot();
msleep(trap_focus_delay);
K = 0;
}
}
}
if (silent_pic_mode && lv_drawn() && get_halfshutter_pressed())
{
silent_pic_take(1);
}
// force powersave mode for intervalometer in silent mode
if (intervalometer_running)
{
if (gui_menu_shown() || gui_state == GUISTATE_PLAYMENU) continue;
if (timer_values[interval_timer_index])
{
card_led_blink(5, 50, 50);
wait_till_next_second();
}
if (gui_menu_shown() || gui_state == GUISTATE_PLAYMENU) continue;
if (get_halfshutter_pressed()) continue;
hdr_shot(0, intervalometer_wait);
// simulate a half-shutter press to avoid mirror going up
// once per minute is enough and easy to check
static int prev_min = 0;
LoadCalendarFromRTC( &now );
if (lv_drawn() && now.tm_min != prev_min)
{
prev_min = now.tm_min;
SW1(1,10);
SW1(0,10);
}
for (i = 0; i < timer_values[interval_timer_index] - 1; i++)
{
card_led_blink(1, 50, 0);
wait_till_next_second();
if (intervalometer_running) bmp_printf(FONT_MED, 20, (lv_drawn() ? 40 : 3), "Press PLAY or MENU to stop the intervalometer...%d ", timer_values[interval_timer_index] - i - 1);
else break;
if (gui_menu_shown() || gui_state == GUISTATE_PLAYMENU) continue;
while (get_halfshutter_pressed()) msleep(100);
if (!lv_drawn())
{
SW1(1,10); // prevent camera from entering in "deep sleep" mode
SW1(0,10); // (some kind of sleep where it won't wake up from msleep)
}
//~ if (shooting_mode != SHOOTMODE_MOVIE)
//~ {
//~ if (lens_info.shutter > 100 && !silent_pic_mode) bmp_printf(FONT_MED, 0, 70, "Tip: use shutter speeds slower than 1/100 to prevent flicker.");
//~ else if (shooting_mode != SHOOTMODE_M || lens_info.iso == 0) bmp_printf(FONT_MED, 0, 70, "Tip: use fully manual exposure to prevent flicker. ");
//~ else if ((af_mode & 0xF) != 3) bmp_printf(FONT_MED, 0, 70, "Tip: use manual focus ");
//~ }
}
}
else
{
if (audio_release_running)
{
static int countdown = 0;
if (gui_state != GUISTATE_IDLE || gui_menu_shown()) countdown = 50;
if (countdown) { countdown--; continue; }
extern struct audio_level audio_levels[];
bmp_printf(FONT_MED, 20, lv_drawn() ? 40 : 3, "Audio release ON (%d / %d) ", audio_levels[0].peak / audio_levels[0].avg, audio_release_level);
if (audio_levels[0].peak > audio_levels[0].avg * (int)audio_release_level)
{
remote_shot();
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) msleep(100);
}
}
}
}
}
TASK_CREATE( "shoot_task", shoot_task, 0, 0x1a, 0x1000 );