https://bitbucket.org/daniel_fort/magic-lantern
Raw File
Tip revision: f278363ada6400aa8e2dc7d2772f82a86718b5e6 authored by Daniel Fort on 23 September 2018, 03:54:38 UTC
mlv_dump: Applied mlv_dump_bruteforce-v2.patch
Tip revision: f278363
adv_int.c
//
//  adv_int.c

//  Copyright (c) 2013 David Milligan
//


#include <module.h>
#include <dryos.h>
#include <property.h>
#include <bmp.h>
#include <menu.h>
#include <config.h>
#include <raw.h>
#include <lens.h>
#include <math.h>
#include <shoot.h>
#include <focus.h>
#include <beep.h>

#define TRUE  1
#define FALSE 0
#define LINE_BUF_SIZE 512
#define MAX_PATH 100
#define STR_INT_MAX_LEN 20
#define FILE_BUF_SIZE 4096
#define SECONDS_IN_DAY 86400
#define MAX_TIME 5000

struct keyframe
{
    struct keyframe * next;
    int time;
    int shutter;
    int aperture;
    int iso;
    int focus;
    int interval_time;
    int kelvin;
    int bulb_duration;
    struct menu_entry menu_entry;
};

static CONFIG_INT("adv_int.enabled", adv_int, 0);
static CONFIG_INT("adv_int.use_global_time", adv_int_use_global_time, 0);
static CONFIG_INT("adv_int.loop_after", adv_int_loop_after, 0);
static CONFIG_INT("adv_int.external", adv_int_external, 0);
static int adv_int_external_pic_count = 0;
static int keyframe_shutter = 0;
static int keyframe_aperture = 0;
static int keyframe_iso = 0;
static int keyframe_focus = 0;
static int keyframe_time = 1;
static int keyframe_interval_time = 0;
static int keyframe_kelvin = 0;
static int keyframe_bulb_duration = 0;

static struct keyframe * keyframes = NULL;

static struct keyframe * current_keyframe = NULL;
static struct keyframe * last_keyframe = NULL;


static MENU_UPDATE_FUNC(update_keyframe_menu)
{
    for(struct keyframe * current = keyframes; current; current = current->next)
    {
        if(&(current->menu_entry) == entry)
        {
            if(adv_int_use_global_time)
                MENU_SET_NAME("T=%02d:%02d:%02d", current->time / 3600 % 24, current->time / 60 % 60, current->time % 60);
            else
                MENU_SET_NAME("T=%d", current->time);
            if(current->shutter)
                MENU_APPEND_RINFO("Tv=%s ",lens_format_shutter(current->shutter));
            if(current->aperture)
                MENU_APPEND_RINFO("Av=%d ", current->aperture);
                //how to convert raw to aperture ??
                //MENU_APPEND_RINFO("Av="SYM_F_SLASH"%d.%d ",raw2aperture(current->aperture) / 10, raw2aperture(current->aperture) % 10);
            if(current->iso)
                MENU_APPEND_RINFO("ISO=%d ",raw2iso(current->iso));
            if(current->focus)
                MENU_APPEND_RINFO("fcs=%d ",current->focus);
            if(current->interval_time)
                MENU_APPEND_RINFO("int=%d ",current->interval_time);
            if(current->kelvin)
                MENU_APPEND_RINFO("wb=%d ",current->kelvin);
            if(current->bulb_duration)
                MENU_APPEND_RINFO("bulb=%d ",current->bulb_duration);
            break;
        }
    }
}

static void add_keyframe_menu(struct keyframe * kfr)
{
    if (kfr)
    {
        kfr->menu_entry.update = update_keyframe_menu;
        menu_add("List Keyframes", &(kfr->menu_entry), 1);
    }
}

/*
 * Creates a new keyframe struct and inserts it in the list based on it's time (insertion sort)
 */
static struct keyframe * new_keyframe(struct keyframe * list, int time)
{
    if(!keyframes)
    {
        keyframes = malloc(sizeof(struct keyframe));
        if(keyframes)
        {
            memset(keyframes, 0, sizeof(struct keyframe));
            keyframes->time = time;
            add_keyframe_menu(keyframes);
        }
        return keyframes;
    }
    //search for any keyframes with this time, replace it if it already exists
    struct keyframe * current = keyframes;
    while(current)
    {
        if(current->time == time)
        {
            current->aperture = 0;
            current->focus = 0;
            current->iso = 0;
            current->shutter = 0;
            current->kelvin = 0;
            current->interval_time = 0;
            current->bulb_duration = 0;
            return current;
        }
        current = current->next;
    }
    
    struct keyframe * new_kfr = NULL;
    
    if(keyframes && time < keyframes->time)
    {
        //insert as new root
        new_kfr = malloc(sizeof(struct keyframe));
        if(new_kfr)
        {
            memset(new_kfr, 0, sizeof(struct keyframe));
            new_kfr->time = time;
            new_kfr->next = keyframes;
            keyframes = new_kfr;
            add_keyframe_menu(new_kfr);
        }
        return new_kfr;
        
    }
    else
    {
        //find where to insert new keyframe
        current = keyframes;
        while(current->next)
        {
            if(current->next && current->next->time > time)
                break;
            current = current->next;
        }
        new_kfr = malloc(sizeof(struct keyframe));
        if(new_kfr)
        {
            memset(new_kfr, 0, sizeof(struct keyframe));
            new_kfr->time = time;
            new_kfr->next = current->next;
            current->next = new_kfr;
            add_keyframe_menu(new_kfr);
        }
        return new_kfr;
    }
}

static void delete_keyframe(struct keyframe * kfr)
{
    if(kfr)
    {
        menu_remove("List Keyframes", &(kfr->menu_entry), 1);
        delete_keyframe(kfr->next);
        kfr->next = NULL;
        free(kfr);
    }
}

static int keyframe_exists(int time)
{
    for(struct keyframe * current = keyframes; current; current = current->next)
    {
        if(current->time == time)
            return TRUE;
    }
    return FALSE;
}

static MENU_SELECT_FUNC(adv_int_new_keyframe)
{
    //beep();
    struct keyframe * kfr = new_keyframe(keyframes, keyframe_time);
    if(kfr)
    {
        kfr->time = keyframe_time;
        kfr->shutter = keyframe_shutter ? lens_info.raw_shutter : 0;
        kfr->aperture = keyframe_aperture ? lens_info.raw_aperture : 0;
        kfr->iso = keyframe_iso ? lens_info.raw_iso : 0;
        kfr->focus = keyframe_focus;
        kfr->interval_time = keyframe_interval_time;
        kfr->kelvin = keyframe_kelvin;
        kfr->bulb_duration = keyframe_bulb_duration;
        NotifyBox(2000, "Keyframe Created for %d", keyframe_time);
    }
    else
    {
        NotifyBox(2000, "Error: could not create keyframe", keyframe_time);
    }
}

static int get_global_time()
{
    struct tm now;
    LoadCalendarFromRTC(&now);
    return now.tm_sec + (60 * now.tm_min) + (3600 * now.tm_hour);
}

static int read_char(char* source, size_t * source_pos, char* out, size_t source_size)
{
    if (*source_pos >= source_size) return 0;
    *out = source[(*source_pos)++];
    return 1;
}

static int read_line(char* source, size_t * source_pos, size_t source_size, char * buf, size_t buf_size)
{
    size_t len = 0;
    
    while( len < buf_size )
    {
        int rc = read_char(source, source_pos, buf+len, source_size);
        if( rc <= 0 )
            return -1;
        
        if( buf[len] == '\r' )
            continue;
        if( buf[len] == '\n' )
        {
            buf[len] = '\0';
            return len;
        }
        
        len++;
    }
    
    return -1;
}

static int parse_next_int(char* source, size_t max_len)
{
    if(source)
    {
        char temp[STR_INT_MAX_LEN];
        size_t pos = 0;
        while(pos < max_len && isdigit(source[pos]) && pos < STR_INT_MAX_LEN)
        {
            temp[pos] = source[pos];
            pos++;
        }
        temp[pos] = '\0';
        if(strlen(temp) > 0)
            return atoi(temp);
        else
            return 0;
    }
    else
    {
        return 0;
    }
}

//for some reason I can't link to strstr
static char* my_strstr(char* source, const char* search)
{
    if(source && search && strlen(source) > 0 && strlen(search) > 0)
    {
        for (size_t pos = 0; pos < strlen(source) - strlen(search); pos++)
        {
            int found = TRUE;
            for(size_t i = 0; i < strlen(search); i++)
            {
                if(source[pos + i] != search[i])
                {
                    found = FALSE;
                    break;
                }
            }
            if(found)
                return source + pos;
        }
    }
    return NULL;
}

static int parse_property(const char * property, char * source, size_t max_len)
{
    if(source)
    {
        char * loc = my_strstr(source, property);
        return loc ? parse_next_int(loc + strlen(property), max_len) : 0;
    }
    return 0;
}

static MENU_SELECT_FUNC(adv_int_load)
{
    char filename[MAX_PATH];
    char line_temp[LINE_BUF_SIZE];
    int success = FALSE;
    
    snprintf(filename,MAX_PATH,"%sSEQ.TXT",get_config_dir());
    
    FILE* f = FIO_OpenFile(filename, O_RDONLY | O_SYNC);
    if(f)
    {
        char* buffer = fio_malloc(FILE_BUF_SIZE);
        if(buffer)
        {
            if(FIO_ReadFile(f, buffer, FILE_BUF_SIZE - 1))
            {
                size_t buf_pos = 0;
                while(read_line(buffer, &buf_pos, FILE_BUF_SIZE, line_temp, LINE_BUF_SIZE) > 0)
                {
                    int kfr_time = parse_next_int(line_temp, LINE_BUF_SIZE);
                    struct keyframe * new_kfr = new_keyframe(keyframes, kfr_time);
                    if(new_kfr)
                    {
                        new_kfr->shutter = parse_property("tv=", line_temp, LINE_BUF_SIZE);
                        new_kfr->aperture = parse_property("av=", line_temp, LINE_BUF_SIZE);
                        new_kfr->iso = parse_property("iso=", line_temp, LINE_BUF_SIZE);
                        new_kfr->focus = parse_property("fcs=", line_temp, LINE_BUF_SIZE);
                        new_kfr->interval_time = parse_property("int=", line_temp, LINE_BUF_SIZE);
                        new_kfr->kelvin = parse_property("wb=", line_temp, LINE_BUF_SIZE);
                        new_kfr->bulb_duration = parse_property("bulb=", line_temp, LINE_BUF_SIZE);
                    }
                }
                success = TRUE;
            }
            else
                NotifyBox(2000, "Error: Could not read file");
            fio_free(buffer);
             
        }
        else
            NotifyBox(2000, "Error: Could not create buffer");
        
        FIO_CloseFile(f);
    }
    else
        NotifyBox(2000, "Error: Could not open file");
    
    if(success)
        NotifyBox(2000, "Sequence File Loaded");
}

static MENU_SELECT_FUNC(adv_int_save)
{
    char filename[MAX_PATH];
    
    snprintf(filename,MAX_PATH,"%sSEQ.TXT",get_config_dir());
    
    FILE* f = FIO_CreateFile(filename);
    if(f)
    {
        for(struct keyframe * current = keyframes; current; current = current->next)
        {
            my_fprintf(f,"%d:", current->time);
            if(current->shutter)
                my_fprintf(f, "tv=%d ", current->shutter);
            if(current->aperture)
                my_fprintf(f, "av=%d ", current->aperture);
            if(current->iso)
                my_fprintf(f, "iso=%d ", current->iso);
            if(current->focus)
                my_fprintf(f, "fcs=%d ", current->focus);
            if(current->interval_time)
                my_fprintf(f, "int=%d ", current->interval_time);
            if(current->kelvin)
                my_fprintf(f, "wb=%d ", current->kelvin);
            if(current->bulb_duration)
                my_fprintf(f, "bulb=%d ", current->bulb_duration);
            my_fprintf(f,"\n");
            
        }
        FIO_CloseFile(f);
        beep();
        NotifyBox(2000, "Keyframe Sequence Saved");
    }
    else
    {
        NotifyBox(2000, "Error saving file");
    }
}

static MENU_SELECT_FUNC(adv_int_clear)
{
    delete_keyframe(keyframes);
    keyframes = NULL;
    NotifyBox(2000, "All Keyframes Cleared");
}

static MENU_UPDATE_FUNC(time_menu_update)
{
    if(adv_int_use_global_time)
    {
        entry->unit = UNIT_TIME;
        MENU_SET_VALUE("%02d:%02d:%02d ", keyframe_time / 60 / 60 % 24, keyframe_time / 60 % 60, keyframe_time % 60);
        int now = get_global_time();
        MENU_SET_RINFO("%02d:%02d:%02d", now / 60 / 60 % 24, now / 60 % 60, now % 60);
    }
    else
    {
        entry->unit = UNIT_DEC;
        int seconds = get_config_var("interval.time") * keyframe_time;
        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);
        }
        
        MENU_SET_RINFO("%s", msg);
        
    }
    if(keyframe_exists(keyframe_time))
        MENU_SET_WARNING(MENU_WARN_NOT_WORKING,"This keyframe already exists, will be overwritten");
}

static MENU_SELECT_FUNC(new_keyframe_menu_select)
{
    if(adv_int_use_global_time && keyframe_time < get_global_time())
        keyframe_time = get_global_time();
    
    menu_open_submenu(priv, delta);
}


static MENU_UPDATE_FUNC(shutter_menu_update)
{
    MENU_SET_RINFO("%s", lens_format_shutter(lens_info.raw_shutter));
    if(shooting_mode == SHOOTMODE_BULB)
        MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "This feature does not work in BULB mode (use Bulb Duration)");
}

static MENU_UPDATE_FUNC(aperture_menu_update)
{
    //copied/modified from shoot.c
    
    int a = lens_info.aperture;
    if (!a || !lens_info.lens_exists) // for unchipped lenses, always display zero
        a = 0;
    MENU_SET_RINFO(SYM_F_SLASH"%d.%d", a / 10, a % 10);
    
    if (!lens_info.aperture)
    {
        MENU_SET_WARNING(MENU_WARN_NOT_WORKING, lens_info.lens_exists ? "Aperture is automatic - cannot adjust manually." : "Manual lens - cannot adjust aperture.");
    }
}

static MENU_UPDATE_FUNC(iso_menu_update)
{
    MENU_SET_RINFO("ISO%d", lens_info.iso);
}

/************************************************************/
/* From shoot.c */

static MENU_UPDATE_FUNC(shutter_display)
{
    MENU_SET_VALUE("%s", lens_format_shutter(lens_info.raw_shutter));
    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 - codes_shutter[1]) * 100 / (codes_shutter[COUNT(codes_shutter)-1] - codes_shutter[1]));
        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
}

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.lens_exists) // 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.lens_exists ? "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
}

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
}

/************************************************************/

static MENU_SELECT_FUNC(kelvin_menu_select)
{
    int * val = (int*)priv;
    if(delta < 0)
    {
        if(*val == 0)
            *val = KELVIN_MAX;
        else if(*val <= KELVIN_MIN)
            *val = 0;
        else
            *val -= KELVIN_STEP;
    }
    else if(delta > 0)
    {
        if(*val == 0)
            *val = KELVIN_MIN;
        else if(*val >= KELVIN_MAX)
            *val = 0;
        else
            *val += KELVIN_STEP;
    }
    
}

static MENU_UPDATE_FUNC(kelvin_menu_update)
{
    if(keyframe_kelvin)
    {
        MENU_SET_VALUE("%dK", keyframe_kelvin);
        MENU_SET_ENABLED(TRUE);
    }
    else
    {
        MENU_SET_VALUE("OFF");
        MENU_SET_ENABLED(FALSE);
    }
}

static MENU_UPDATE_FUNC(loop_after_menu_update)
{
    if(adv_int_use_global_time)
    {
        MENU_SET_VALUE("OFF");
        MENU_SET_ENABLED(FALSE);
        MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "This feature does not work with global time keyframes");
    }
    else if(!adv_int_loop_after)
    {
        MENU_SET_VALUE("OFF");
        MENU_SET_ENABLED(FALSE);
    }
    else
    {
        MENU_SET_ENABLED(TRUE);
    }
    
}

static MENU_UPDATE_FUNC(bulb_duration_update)
{
    if(shooting_mode != SHOOTMODE_BULB)
        MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "This feature only works in BULB mode");
}

static void step_focus(int mf_steps)
{
    if (mf_steps && !is_manual_focus())
    {
        while (lens_info.job_state) msleep(100);
        msleep(300);
        exit_play_qr_mode();
        if (!lv)
        {
            msleep(500);
            if (!lv) force_liveview();
        }
        set_lv_zoom(5);
        msleep(1000);
        NotifyBox(1000, "Focusing...");
        lens_focus_enqueue_step(-mf_steps);
        msleep(1000);
        set_lv_zoom(1);
        msleep(500);
    }
}

static int current_focus_offset = 0;
static void focus_to(int offset)
{
    if(offset - current_focus_offset != 0)
    {
        NotifyBox(2000, "Focusing %d steps to offset %d",offset - current_focus_offset, offset);
        step_focus(offset - current_focus_offset);
        current_focus_offset = offset;
    }
}

static int compute_ramp(int start_val, int end_val, int start_time, int end_time, int time)
{
    return (time - start_time) * (end_val - start_val) / (end_time - start_time) + start_val;
}

static unsigned int adv_int_cbr()
{
    if(adv_int && keyframes)
    {
        int current_time = adv_int_external ? adv_int_external_pic_count++ : get_interval_count();
        if(!adv_int_use_global_time && adv_int_loop_after)
            current_time = (current_time - 1) % adv_int_loop_after + 1;
        //the sequence just started
        if(current_time == 1)
        {
            current_focus_offset = 0;
            current_keyframe = keyframes;
            last_keyframe = keyframes;
        }
        if(adv_int_use_global_time)
        {
            if(current_time == 1)
            {
                current_time = get_global_time();
                //we need to search the keyframe list in case we start at a time past the first keyframe
                while(current_keyframe && current_time > current_keyframe->time)
                {
                    last_keyframe = current_keyframe;
                    current_keyframe = current_keyframe->next;
                }
            }
            else
            {
                current_time = get_global_time();
            }
        }
        
        //we are inbetween keyframes so ramp from previous keyframe to the next
        if(last_keyframe && current_keyframe &&
           current_time >= last_keyframe->time)
        {
            int ramp_time = MIN(current_time, current_keyframe->time);
            NotifyBox(2000,"Ramping %d%%", compute_ramp(0, 100, last_keyframe->time,current_keyframe->time, ramp_time));
            //ramp values from previous keyframe to next keyframe
            if(current_keyframe->shutter && last_keyframe->shutter)
            {
                int computed = compute_ramp(last_keyframe->shutter, current_keyframe->shutter, last_keyframe->time,current_keyframe->time, ramp_time);
                lens_set_rawshutter(round_shutter(computed, 16));
            }
            if(current_keyframe->aperture && last_keyframe->aperture)
            {
                int computed = compute_ramp(last_keyframe->aperture, current_keyframe->aperture, last_keyframe->time,current_keyframe->time, ramp_time);
                lens_set_rawaperture(round_aperture(computed));
            }
            if(current_keyframe->iso && last_keyframe->iso)
            {
                int computed = compute_ramp(last_keyframe->iso, current_keyframe->iso, last_keyframe->time,current_keyframe->time, ramp_time);
                lens_set_rawiso(computed / 8 * 8); //round to nearest analog ISO
            }
            if(current_keyframe->focus != last_keyframe->focus)
            {
                int computed = compute_ramp(last_keyframe->focus, current_keyframe->focus, last_keyframe->time,current_keyframe->time, ramp_time);
                focus_to(computed);
            }
            if(current_keyframe->interval_time && last_keyframe->interval_time)
            {
                int computed = compute_ramp(last_keyframe->interval_time, current_keyframe->interval_time, last_keyframe->time,current_keyframe->time, ramp_time);
                set_config_var("interval.time", computed);
            }
            if(current_keyframe->kelvin && last_keyframe->kelvin)
            {
                int computed = compute_ramp(last_keyframe->kelvin, current_keyframe->kelvin, last_keyframe->time,current_keyframe->time, ramp_time);
                lens_set_kelvin(computed);
            }
            if(current_keyframe->bulb_duration && last_keyframe->bulb_duration)
            {
                int computed = compute_ramp(last_keyframe->bulb_duration, current_keyframe->bulb_duration, last_keyframe->time,current_keyframe->time, ramp_time);
                set_config_var("bulb.duration", computed);
            }
        }
        
        //we reached the keyframe so go to next
        while(current_keyframe && current_time >= current_keyframe->time)
        {
            last_keyframe = current_keyframe;
            current_keyframe = current_keyframe->next;
        }
    }
    return 0;
}

static int running = 0;

static void adv_int_task()
{
    adv_int_cbr();
    running = 0;
}

PROP_HANDLER(PROP_GUI_STATE)
{
    int* data = (int*)buf;
    if (data[0] == GUISTATE_QR)
    {
        if (adv_int_external && !running)
        {
            running = 1;
            task_create("adv_int_task", 0x1c, 0x1000, adv_int_task, (void*)0);
        }
    }
}

static struct menu_entry adv_int_menu[] =
{
    {
        .name = "Advanced Intervalometer",
        .priv = &adv_int,
        .select = menu_open_submenu,
        .max = 1,
        .works_best_in = DEP_M_MODE,
        .help = "Advanced intervalometer ramping",
        .children =  (struct menu_entry[])
        {
            {
                .name = "Enabled",
                .priv = &adv_int,
                .max = 1,
                .help = "Enable advanced intervalometer ramping"
            },
            {
                .name = "Use Global Time",
                .priv = &adv_int_use_global_time,
                .max = 1,
                .help = "Set keyframes by global time (time of day)",
                .help2 = "You should clear all keyframes when switching this setting"
            },
            {
                .name = "Loop After",
                .priv = &adv_int_loop_after,
                .update = loop_after_menu_update,
                .max = 5000,
                .icon_type = IT_BOOL,
                .help = "Loops keyframe sequence after x frames"
            },
            {
                .name = "External Source",
                .priv = &adv_int_external,
                .max = 1,
                .icon_type = IT_BOOL,
                .help = "Use this module with an external intervalometer"
            },
            {
                .name = "List Keyframes",
                .select = menu_open_submenu,
                .submenu_width = 710,
                .help = "Lists all keyframes",
                .children =  (struct menu_entry[]) {
                    MENU_EOL
                }
            },
            {
                .name = "Load...",
                .select = adv_int_load,
                .help = "Load keyframes from file"
            },
            {
                .name = "Save...",
                .select = adv_int_save,
                .help = "Save current keyframes to file"
            },
            {
                .name = "Clear",
                .select = adv_int_clear,
                .help = "Clears all keyframes"
            },
            {
                .name = "New Keyframe...",
                .select = new_keyframe_menu_select,
                .submenu_width = 710,
                .icon_type = IT_ACTION,
                .help = "Create a new keyframe from the current camera settings",
                .children =  (struct menu_entry[])
                {
                    {
                        .name = "Create Keyframe",
                        .select = adv_int_new_keyframe,
                        .help = "Create a new keyframe from the current camera settings"
                    },
                    {
                        .name = "Keyframe Time",
                        .priv = &keyframe_time,
                        .update = time_menu_update,
                        .min = 1,
                        .max = SECONDS_IN_DAY,
                        .unit = UNIT_DEC,
                        .help = "The frame at which to apply this keyframe",
                        .help2 = "* Computed time inacurate if ramping interval time"
                    },
                    {
                        .name = "Shutter ",
                        .priv = &keyframe_shutter,
                        .select = menu_open_submenu,
                        .update = shutter_menu_update,
                        .max = 1,
                        .icon_type = IT_BOOL,
                        .works_best_in = DEP_M_MODE,
                        .help = "Include current Shutter in Keyframe",
                        .children = (struct menu_entry[])
                        {
                            {
                                .name = "Enabled",
                                .priv = &keyframe_shutter,
                                .max = 1,
                                .icon_type = IT_BOOL,
                                .help = "Include current Shutter in Keyframe"
                            },
                            {
                                .name = "Adjust 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_SHOW_LIVEVIEW,
                            },
                            MENU_EOL
                        }
                    },
                    {
                        .name = "Aperture ",
                        .priv = &keyframe_aperture,
                        .select = menu_open_submenu,
                        .update = aperture_menu_update,
                        .max = 1,
                        .icon_type = IT_BOOL,
                        .works_best_in = DEP_M_MODE,
                        .help = "Include current Aperture in Keyframe",
                        .children = (struct menu_entry[])
                        {
                            {
                                .name = "Enabled",
                                .priv = &keyframe_aperture,
                                .max = 1,
                                .icon_type = IT_BOOL,
                                .help = "Include current Aperture in Keyframe"
                            },
                            {
                                .name = "Adjust 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_SHOW_LIVEVIEW,
                            },
                            MENU_EOL
                        }
                    },
                    {
                        .name = "ISO ",
                        .priv = &keyframe_iso,
                        .select = menu_open_submenu,
                        .update = iso_menu_update,
                        .max = 1,
                        .icon_type = IT_BOOL,
                        .help = "Include current ISO in Keyframe",
                        .children = (struct menu_entry[])
                        {
                            {
                                .name = "Enabled",
                                .priv = &keyframe_iso,
                                .max = 1,
                                .icon_type = IT_BOOL,
                                .help = "Include current ISO in Keyframe"
                            },
                            {
                                .name = "Adjust ISO",
                                .update = iso_display,
                                .select = iso_toggle,
                                .help  = "Adjust and fine-tune ISO. Also displays APEX Sv value.",
                                .edit_mode = EM_SHOW_LIVEVIEW,
                            },
                            MENU_EOL
                        }
                    },
                    {
                        .name = "Focus",
                        .priv = &keyframe_focus,
                        .min = -5000,
                        .max = 5000,
                        .unit = UNIT_DEC,
                        .help = "The focus offset in steps",
                        .depends_on = DEP_AUTOFOCUS,
                        .works_best_in = DEP_LIVEVIEW,
                    },
                    {
                        .name = "Interval Time",
                        .priv = &keyframe_interval_time,
                        .min = 0,
                        .max = 28800,
                        .unit = UNIT_TIME,
                        .help = "Changes the interval between shots",
                    },
                    {
                        .name = "Bulb Duration",
                        .priv = &keyframe_bulb_duration,
                        .update = bulb_duration_update,
                        .min = 0,
                        .max = 28800,
                        .unit = UNIT_TIME,
                        .depends_on = DEP_PHOTO_MODE,
                        .help = "Changes duration of the bulb timer",
                    },
                    {
                        .name = "White Balance",
                        .update = kelvin_menu_update,
                        .select = kelvin_menu_select,
                        .priv = &keyframe_kelvin,
                        .help = "Changes the Kelvin white balance",
                    },
                    MENU_EOL,
                }
            },
            MENU_EOL
        }
    }
};

static unsigned int adv_int_init()
{
    menu_add("Intervalometer", adv_int_menu, COUNT(adv_int_menu));
    return 0;
}

static unsigned int adv_int_deinit()
{
    delete_keyframe(keyframes);
    keyframes = NULL;
    return 0;
}

MODULE_CBRS_START()
    MODULE_CBR(CBR_INTERVALOMETER, adv_int_cbr, 0)
MODULE_CBRS_END()

MODULE_INFO_START()
    MODULE_INIT(adv_int_init)
    MODULE_DEINIT(adv_int_deinit)
MODULE_INFO_END()

MODULE_PROPHANDLERS_START()
    MODULE_PROPHANDLER(PROP_GUI_STATE)
MODULE_PROPHANDLERS_END()

MODULE_CONFIGS_START()
    MODULE_CONFIG(adv_int)
    MODULE_CONFIG(adv_int_use_global_time)
    MODULE_CONFIG(adv_int_loop_after)
    MODULE_CONFIG(adv_int_external)
MODULE_CONFIGS_END()
back to top