https://bitbucket.org/daniel_fort/magic-lantern
Raw File
Tip revision: b6ae96e9c87e35a18d21c8b86d5c68d86b94824a authored by a1ex on 22 December 2011, 19:44:16 UTC
Minor bottom bar tweak
Tip revision: b6ae96e
fps-engio.c
/** 
 * FPS control with engio calls (talking to DIGIC!)
 * This method is portable: works on all cameras.
 * 
 **/
 
/**
 * 
 * Notes by g3gg0:
 * 
 * okay i found how to directly change the sensor frame rate without patching and copying memory areas.
 * it doesnt matter which mode is selected.
 * 
 * on 600D v1.0.1 it is calling engio_write() with a buffer that writes the rate.
 * 
 * unsigned long frame_rate[] = {
 *      0xC0F06014, 0xFFFF, // timer register
 *      0xC0F06000, 0x01,   // coherent update
 *      0xFFFFFFFF          // end of commands
 * };
 *
 * void run_test()
 * {
 *     void (*engio_write)(unsigned int) = 0xFF1E1D20;
 *     frame_rate[1] = 0xFFFF; // timer value as usual
 *     engio_write(frame_rate);
 * }
 * 
 * 
 **/

#include "dryos.h"
#include "bmp.h"
#include "property.h"
#include "menu.h"
#include "lens.h"
#include "config.h"

static int is_current_mode_ntsc()
{
    if (video_mode_fps == 30 || video_mode_fps == 60 || video_mode_fps == 24) return 1;
    return 0;
}

#ifdef CONFIG_500D
    #define TG_FREQ_PAL  24660000
    #define TG_FREQ_NTSC 23136840
#else
    #ifdef CONFIG_50D
        #define TG_FREQ_PAL  40000000
        #define TG_FREQ_NTSC 42197760
    #else
        #define TG_FREQ_PAL  50000000
        #define TG_FREQ_NTSC 52747200
    #endif
#endif

#define FPS_x1000_TO_TIMER_PAL(fps_x1000) (TG_FREQ_PAL/(fps_x1000))
#define FPS_x1000_TO_TIMER_NTSC(fps_x1000) (TG_FREQ_NTSC/(fps_x1000))
#define TIMER_TO_FPS_x1000_PAL(t) (TG_FREQ_PAL/(t))
#define TIMER_TO_FPS_x1000_NTSC(t) (TG_FREQ_NTSC/(t))

static int fps_override = 0;

static unsigned long frame_rate[] = {
    0xC0F06014, 0xFFFF, /* timer register */
    0xC0F06000, 0x01, /* coherent update */
    0xFFFFFFFF /* end of commands */ };

static int fps_get_timer(int fps)
{
    int ntsc = is_current_mode_ntsc();

    int fps_x1000 = fps * 1000;

    // convert fps into timer ticks (for sensor drive speed)
    int fps_timer = ntsc ? FPS_x1000_TO_TIMER_NTSC(fps_x1000*1000/1001) : FPS_x1000_TO_TIMER_PAL(fps_x1000);

    // NTSC is 29.97, not 30
    // also try to round it in order to avoid flicker
    if (ntsc)
    {
        int timer_120hz = FPS_x1000_TO_TIMER_NTSC(120000*1000/1001);
        int fps_timer_rounded = ((fps_timer + timer_120hz/2) / timer_120hz) * timer_120hz;
        if (ABS(TIMER_TO_FPS_x1000_NTSC(fps_timer_rounded) - fps_x1000 + 1) < 500) fps_timer = fps_timer_rounded;
    }
    else
    {
        int timer_100hz = FPS_x1000_TO_TIMER_PAL(100000);
        int fps_timer_rounded = ((fps_timer + timer_100hz/2) / timer_100hz) * timer_100hz;
        if (ABS(TIMER_TO_FPS_x1000_PAL(fps_timer_rounded) - fps_x1000 + 1) < 500) fps_timer = fps_timer_rounded;
    }

    return fps_timer & 0xFFFF;
}

static void fps_setup(int fps)
{
    if (fps) frame_rate[1] = fps_get_timer(fps);

    unsigned safe_limit = fps_get_timer(70);
#ifdef CONFIG_550D
    safe_limit = fps_get_timer(video_mode_fps); // no overcranking possible
    if (video_mode_crop)
    {
        frame_rate[1] = safe_limit;
        return; // freeze
    }
#endif
#ifdef CONFIG_500D
    safe_limit = fps_get_timer(lv_dispsize > 1 ? 24 : video_mode_resolution == 0 ? 21 : 32);
#endif
#ifdef CONFIG_5D2
    safe_limit = fps_get_timer(video_mode_resolution == 0 ? 35 : 37);
#endif
#ifdef CONFIG_50D
    safe_limit = fps_get_timer(31);
#endif

    // no more than 30fps in photo mode
    if (!is_movie_mode()) safe_limit = MAX(safe_limit, fps_get_timer(30));
    
    frame_rate[1] = MAX(frame_rate[1], safe_limit);

    engio_write(frame_rate);
}

static int fps_get_current_x1000()
{
    if (!fps_override) return video_mode_fps * 1000;
    int fps_timer = frame_rate[1];
    int ntsc = is_current_mode_ntsc();
    int fps_x1000 = ntsc ? TIMER_TO_FPS_x1000_NTSC(fps_timer) : TIMER_TO_FPS_x1000_PAL(fps_timer);
    return fps_x1000;
}

static void
fps_print(
    void *          priv,
    int         x,
    int         y,
    int         selected
)
{
    int current_fps = fps_get_current_x1000();
    
    char msg[30];
    snprintf(msg, sizeof(msg), "%d (%d.%03d)", 
        (current_fps+500)/1000, 
        current_fps/1000, current_fps%1000
        );
    
    bmp_printf(
        selected ? MENU_FONT_SEL : MENU_FONT,
        x, y,
        "FPS override  : %s",
        fps_override ? msg : "OFF"
    );
    
    extern int sound_recording_mode;
    if (fps_override && sound_recording_mode != 1)
        menu_draw_icon(x, y, MNI_WARNING, (intptr_t)"Turn off sound recording from Canon menu!");
    menu_draw_icon(x, y, MNI_BOOL(fps_override), 0);
    //~ bmp_hexdump(FONT_SMALL, 0, 400, SENSOR_TIMING_TABLE, 32);
}

static void flip_zoom()
{
    if (!lv) return;
    if (is_movie_mode())
    {
        if (recording) return;
        if (video_mode_crop) return;
    }
    
    // flip zoom mode back and forth to apply settings instantly
    int zoom0 = lv_dispsize;
    int zoom1 = zoom0 == 10 ? 5 : zoom0 == 5 ? 1 : 10;
    prop_request_change(PROP_LV_DISPSIZE, &zoom1, 4);
    prop_request_change(PROP_LV_DISPSIZE, &zoom0, 4);
}

static int current_fps = 0;

static void reset_fps(void* priv, int delta)
{
    fps_override = 0;
    current_fps = video_mode_fps;
    
    if (!recording) flip_zoom(); // this will force reconfiguring fps with Canon settings
    else fps_setup(video_mode_fps);
}

static void set_fps(void* priv, int delta)
{
    // first click won't change value
    current_fps = (fps_get_current_x1000() + 500) / 1000; // rounded value
    if (fps_override) current_fps = COERCE(current_fps + delta, 4, 70);
    
    fps_setup(current_fps);
    
    fps_override = 1;
}


static struct menu_entry fps_menu[] = {
    {
        .name = "FPS override", 
        .priv = &fps_override,
        .select = set_fps,
        .select_auto = reset_fps,
        .display = fps_print,
        .show_liveview = 1,
        .help = "Changes FPS and forces shutter at 1/fps. Turn off sound!"
    },
};

static void fps_init()
{
    menu_add( "Movie", fps_menu, COUNT(fps_menu) );
}

INIT_FUNC("fps", fps_init);

static void fps_task()
{
    while(1)
    {
        if (fps_override && lv && !gui_menu_shown())
			fps_setup(current_fps);
        msleep(1000);
    }
}

TASK_CREATE("fps_task", fps_task, 0, 0x1d, 0x1000 );


void fps_mvr_log(FILE* mvr_logfile)
{
    int f = fps_get_current_x1000();
    if (fps_override)
		my_fprintf(mvr_logfile, "FPS+Tv override: %d (%d.%03d)\n", (f+500)/1000, f/1000, f%1000);
}

// FPS has a side effect: to force shutter speed at 1/fps. Let the bottom bar show this.
int is_hard_exposure_override_active() { return fps_override; }
int get_shutter_override_degrees_x10() { return fps_override ? 3600 : 0; }
back to top