https://bitbucket.org/hudson/magic-lantern
Raw File
Tip revision: 40f1f03cba7fbf0469837ab41cb0a4ccc788cf3f authored by Giovanni C on 02 September 2013, 21:36:35 UTC
Close branch unlimited-bracketing-shots
Tip revision: 40f1f03
library_ml.c
#include "interpreter.h"

#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)

#define UNPRESS -10000 // generic unpress code
#define NO_KEY -1
#define AF_ON 12345

static void LibSleep(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int ms = (int)roundf(Param[0]->Val->FP * 1000.0f);
    script_msleep(ms);
}

static void LibBeep(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    beep();
}

static void LibBeeps(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    beep_times(Param[0]->Val->Integer);
}

static void LibBeepCustom(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    beep_custom(Param[0]->Val->Integer, Param[1]->Val->Integer, Param[2]->Val->Integer);
}

static void LibConsoleShow(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    console_show();
}

static void LibConsoleHide(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    console_hide();
}

static void LibCls(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    console_clear();
}

static void LibScreenshot(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    #ifdef FEATURE_SCREENSHOT
    take_screenshot(1);
    #else
    console_printf("screenshot: not available\n");
    #endif
}

static void LibRand(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->Integer = rand();
}

struct _tm { int hour; int minute; int second; int year; int month; int day; };
static void LibGetTime(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    struct tm now;
    script_LoadCalendarFromRTC(&now);
    
    static struct _tm t;
    t.hour = now.tm_hour;
    t.minute = now.tm_min;
    t.second = now.tm_sec;
    t.year = now.tm_year + 1900;
    t.month = now.tm_mon + 1;
    t.day = now.tm_mday;
    ReturnValue->Val->Pointer = &t;
}

static void LibGetUptime(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->FP = get_ms_clock_value() / 1000.0f;
}

static void LibTakePic(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    take_a_pic(AF_DONT_CHANGE, 0);
}

static void LibBulbPic(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int ms = (int)roundf(Param[0]->Val->FP * 1000.0f);
    bulb_take_pic(ms);
}

static void LibTakeFastPics(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int num = Param[0]->Val->Integer;
    take_fast_pictures(num);
}

static void LibWaitPic(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int f0 = file_number;
    while (file_number == f0) msleep(20);
    lens_wait_readytotakepic(64);
}

static void LibMovieStart(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    movie_start();
}

static void LibMovieEnd(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    movie_end();
}

static void LibPress(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int btn = Param[0]->Val->Integer;
    if (btn < 0) return;
    
    switch (btn)
    {
        case AF_ON:
        {
            int x = 1;
            prop_request_change(PROP_REMOTE_AFSTART_BUTTON, &x, 4);
            msleep(50);
            return;
        }
        case BGMT_PRESS_HALFSHUTTER:
            SW1(1,50);
            return;
        case BGMT_PRESS_FULLSHUTTER:
            SW2(1,50);
            return;
        default:
            if (btn >= 0) fake_simple_button(btn);
    }
}

static void LibUnpress(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int press = Param[0]->Val->Integer;
    if (press < 0) return;

    int unpress = 0;
    switch (press)
    {
        case AF_ON:
        {
            int x = 0;
            prop_request_change(PROP_REMOTE_AFSTART_BUTTON, &x, 4);
            msleep(50);
            return;
        }
        case BGMT_PRESS_HALFSHUTTER:
            SW1(0,50);
            return;
        case BGMT_PRESS_FULLSHUTTER:
            SW2(0,50);
            return;
        case BGMT_PRESS_SET:
            unpress = BGMT_UNPRESS_SET;
            break;
        #ifdef BGMT_UNPRESS_ZOOMIN_MAYBE
        case BGMT_PRESS_ZOOMIN_MAYBE:
            unpress = BGMT_UNPRESS_ZOOMIN_MAYBE;
            break;
        #endif
        #ifdef BGMT_PRESS_ZOOMOUT_MAYBE
        case BGMT_PRESS_ZOOMOUT_MAYBE:
            unpress = BGMT_UNPRESS_ZOOMOUT_MAYBE;
            break;
        #endif
        
        #ifdef BGMT_UNPRESS_UDLR
        case BGMT_PRESS_LEFT:
        case BGMT_PRESS_RIGHT:
        case BGMT_PRESS_UP:
        case BGMT_PRESS_DOWN:
            unpress = BGMT_UNPRESS_UDLR;
            break;
        #else
        case BGMT_PRESS_LEFT: 
            unpress = BGMT_UNPRESS_LEFT; 
            break;
        case BGMT_PRESS_RIGHT: 
            unpress = BGMT_UNPRESS_RIGHT; 
            break;
        case BGMT_PRESS_UP: 
            unpress = BGMT_UNPRESS_UP; 
            break;
        case BGMT_PRESS_DOWN: 
            unpress = BGMT_UNPRESS_DOWN; 
            break;
        #endif
        
        default:
            // this button does not have an unpress code
            return;
    }
    ASSERT(unpress > 0);
    fake_simple_button(unpress);
}

static void LibClick(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    LibPress(Parser, ReturnValue, Param, NumArgs);
    LibUnpress(Parser, ReturnValue, Param, NumArgs);
}

static volatile int key_pressed = -1;
static volatile int waiting_for_key_last_request = 0; // will expire after 1 second

static void queue_cleanup()
{
    int t = get_ms_clock_value();
    if (t > waiting_for_key_last_request + 700) // events from queue are too old, discard them
    {
        while (script_key_dequeue() != -1)
            { /* send to /dev/null */ };
    }
}

static void LibWaitKey(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    queue_cleanup();
    
    int key_pressed;
    console_set_status_text("Waiting key press...");
    while ((key_pressed = script_key_dequeue()) == -1)
    {
        waiting_for_key_last_request = get_ms_clock_value();
        script_msleep(20);
    }
    console_set_status_text("Script running...");
    
    ReturnValue->Val->Integer = key_pressed;
}

static void LibLastKey(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    queue_cleanup();

    console_set_status_text("Script uses keys...");
    waiting_for_key_last_request = get_ms_clock_value();
    ReturnValue->Val->Integer = script_key_dequeue();
}

EXTERN int handle_picoc_lib_keys(struct event * event)
{
    if (IS_FAKE(event))
        return 1; // so we can pass certain keys back to Canon code from script, e.g. if (key == ERASE) click(ERASE);

    if (get_ms_clock_value() > waiting_for_key_last_request + 1000)
    {
        waiting_for_key_last_request = 0;
        console_set_status_text("Script running...");
    }

    if (!waiting_for_key_last_request)
        return 1;

    if (handle_scrollwheel_fast_clicks(event)==0) return 0;
    
    switch (event->param)
    {
        case BGMT_PRESS_LEFT:
            console_printf("{LEFT}\n");
            goto key_can_block;

        case BGMT_PRESS_RIGHT:
            console_printf("{RIGHT}\n");
            goto key_can_block;

        case BGMT_PRESS_UP:
            console_printf("{UP}\n");
            goto key_can_block;

        case BGMT_PRESS_DOWN:
            console_printf("{DOWN}\n");
            goto key_can_block;

        case BGMT_WHEEL_UP:
            console_printf("{WHEEL_UP}\n");
            goto key_can_block;

        case BGMT_WHEEL_DOWN:
            console_printf("{WHEEL_DOWN}\n");
            goto key_can_block;

        case BGMT_WHEEL_LEFT:
            console_printf("{WHEEL_LEFT}\n");
            goto key_can_block;

        case BGMT_WHEEL_RIGHT:
            console_printf("{WHEEL_RIGHT}\n");
            goto key_can_block;

        #ifdef BGMT_JOY_CENTER
        case BGMT_JOY_CENTER:
            event->param = BGMT_PRESS_SET;
            // fallthru
        #endif

        case BGMT_PRESS_SET:
            console_printf("{SET}\n");
            goto key_can_block;

        case BGMT_MENU:
            console_printf("{MENU}\n");
            goto key_can_block;

        case BGMT_PLAY:
            console_printf("{PLAY}\n");
            goto key_can_block;

        case BGMT_TRASH:
            console_printf("{ERASE}\n");
            goto key_can_block;

        case BGMT_INFO:
            console_printf("{INFO}\n");
            goto key_can_block;

        case BGMT_LV:
            console_printf("{LV}\n");
            goto key_can_block;

        #ifdef BGMT_Q
        case BGMT_Q:
            console_printf("{Q}\n");
            goto key_can_block;
        #endif

        case BGMT_PRESS_ZOOMIN_MAYBE:
            console_printf("{ZOOM_IN}\n");
            goto key_can_block;

        #ifdef BGMT_PRESS_ZOOMOUT_MAYBE
        case BGMT_PRESS_ZOOMOUT_MAYBE:
            console_printf("{ZOOM_OUT}\n");
            goto key_can_block;
        #endif
            
        case BGMT_PRESS_HALFSHUTTER:
            console_printf("{SHOOT_HALF}\n");
            goto key_cannot_block;
        
        case BGMT_UNPRESS_HALFSHUTTER:
            console_printf("{UNPRESS}\n");
            script_key_enqueue(UNPRESS);
            return 1;

        case BGMT_UNPRESS_SET:
        #ifdef BGMT_UNPRESS_UDLR
        case BGMT_UNPRESS_UDLR:
        #else
        case BGMT_UNPRESS_LEFT:
        case BGMT_UNPRESS_RIGHT:
        case BGMT_UNPRESS_UP:
        case BGMT_UNPRESS_DOWN:
        #endif
        #ifdef BGMT_UNPRESS_ZOOMIN_MAYBE
        case BGMT_UNPRESS_ZOOMIN_MAYBE:
        #endif
            console_printf("{UNPRESS}\n");
            script_key_enqueue(UNPRESS);
            return 0;
        
        default:
            // unknown event, pass to canon code
            return 1;
    }
    
key_can_block:
    script_key_enqueue(event->param);
    return 0;

key_cannot_block:
    script_key_enqueue(event->param);
    return 1;
}

static void LibGetTv(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->FP = APEX_TV(lens_info.raw_shutter) / 8.0f;
}
static void LibGetAv(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->FP = APEX_AV(lens_info.raw_aperture) / 8.0f;
}
static void LibGetSv(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->FP = APEX_SV(lens_info.raw_iso) / 8.0f;
}
static void LibSetTv(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int tv = (int)roundf(Param[0]->Val->FP * 8.0f);
    lens_set_rawshutter(-APEX_TV(-tv));
}
static void LibSetAv(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int av = (int)roundf(Param[0]->Val->FP * 8.0f);
    lens_set_rawaperture(-APEX_AV(-av));
}
static void LibSetSv(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int sv = (int)roundf(Param[0]->Val->FP * 8.0f);
    lens_set_rawiso(-APEX_SV(-sv));
}

static void LibGetShutter(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->FP = raw2shutterf(lens_info.raw_shutter);
}
static void LibGetAperture(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->FP = lens_info.aperture / 10.0f;
}
static void LibGetISO(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->Integer = lens_info.iso;
}
static void LibSetShutter(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    lens_set_rawshutter(shutterf_to_raw(Param[0]->Val->FP));
}
static void LibSetAperture(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int val = (int)roundf(Param[0]->Val->FP * 10.0f);
    lens_set_aperture(val);
}
static void LibSetISO(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    lens_set_iso(Param[0]->Val->Integer);
}

static void LibGetRawShutter(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->Integer = lens_info.raw_shutter;
}
static void LibGetRawAperture(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->Integer = lens_info.raw_aperture;
}
static void LibGetRawISO(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->Integer = lens_info.raw_iso;
}
static void LibSetRawShutter(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    lens_set_rawshutter(Param[0]->Val->Integer);
}
static void LibSetRawAperture(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    lens_set_rawaperture(Param[0]->Val->Integer);
}
static void LibSetRawISO(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    lens_set_rawiso(Param[0]->Val->Integer);
}

static void LibGetAE(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->FP = lens_info.ae / 8.0f;
}
static void LibSetAE(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int ae = (int)roundf(Param[0]->Val->FP * 8.0f);
    lens_set_ae(ae);
}

static void LibGetFlashAE(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->FP = lens_info.flash_ae / 8.0f;
}
static void LibSetFlashAE(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int ae = (int)roundf(Param[0]->Val->FP * 8.0f);
    lens_set_flash_ae(ae);
}

// canon codes: 0=on, 1=off, 2=auto
// ml: 0=off, 1=on, 2=auto
int strobo_fix_logic(int mode)
{
    if (mode == 0) return 1;
    else if (mode == 1) return 0;
    return mode;
}
static void LibGetFlash(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->Integer = strobo_fix_logic(strobo_firing);
}
static void LibSetFlash(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    set_flash_firing(strobo_fix_logic(Param[0]->Val->Integer));
}

REGISTER_PROP_HANDLER(PROP_POPUP_BUILTIN_FLASH, NULL);
static void LibPopFlash(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int req = 1;
    prop_request_change(PROP_POPUP_BUILTIN_FLASH, &req, 4);
}

static void LibGetKelvin(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->Integer = lens_info.kelvin;
}
static void LibSetKelvin(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    lens_set_kelvin(Param[0]->Val->Integer);
}
static void LibGetGreen(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->Integer = lens_info.wbs_gm;
}
static void LibSetGreen(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    lens_set_wbs_gm(Param[0]->Val->Integer);
}

static void LibFocus(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    LensFocus(Param[0]->Val->Integer);
}

static void LibFocusSetup(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    LensFocusSetup(Param[0]->Val->Integer, Param[1]->Val->Integer, Param[2]->Val->Integer);
}

static void LibGetFocusConfirm(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->Integer = FOCUS_CONFIRMATION;
}

static int af_dirty = 0;
static void LibSetAF(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    af_dirty = 1;
    lens_setup_af(Param[0]->Val->Integer);
}

static void LibResetAF(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    lens_cleanup_af();
}

// called when script finishes
EXTERN void script_cleanup_af() { if (af_dirty) lens_cleanup_af(); }

static void LibGetAFMA(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    #ifdef CONFIG_AFMA
    ReturnValue->Val->Integer = get_afma(Param[0]->Val->Integer);
    #else
    console_printf("get_afma: not available\n");
    #endif
}

static void LibSetAFMA(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    #ifdef CONFIG_AFMA
    set_afma(Param[0]->Val->Integer, Param[1]->Val->Integer);
    #else
    console_printf("set_afma: not available\n");
    #endif
}

struct _dof { char* lens_name; int focal_len; int focus_dist; int dof; int far; int near; int hyperfocal; };
static void LibGetDofInfo(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    static struct _dof d;
    d.lens_name = lens_info.name;
    d.focal_len = lens_info.focal_len;
    d.focus_dist = lens_info.focus_dist;
    d.far = lens_info.dof_far;
    d.near = lens_info.dof_near;
    d.dof = d.far - d.near;
    d.hyperfocal = lens_info.hyperfocal;
    ReturnValue->Val->Pointer = &d;
}

static void LibMicOut(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    #ifdef FEATURE_MIC_POWER
    mic_out(Param[0]->Val->Integer);
    // todo: will also work on 600D, http://www.magiclantern.fm/forum/index.php?topic=4577.msg26886#msg26886
    #else
    console_printf("mic_out: not available\n");
    #endif
}

static void LibSetLed(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int led = Param[0]->Val->Integer;
    int val = Param[1]->Val->Integer;
    if (led)
    {
        if (val) info_led_on();
        else info_led_off();
    }
    else
    {
        if (val) _card_led_on();
        else _card_led_off();
    }
}

static void LibNotifyBox(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int ms = (int)roundf(Param[0]->Val->FP * 1000.0f);
    char msg[512];

    struct OutputStream StrStream;
    
    extern void SPutc(unsigned char Ch, union OutputStreamInfo *Stream);
    StrStream.Putch = &SPutc;
    StrStream.i.Str.Parser = Parser;
    StrStream.i.Str.WritePos = msg;
    
    // there doesn't seem to be any bounds checking :(

    GenericPrintf(Parser, ReturnValue, Param+1, NumArgs-1, &StrStream);
    PrintCh(0, &StrStream);

    NotifyBox(ms, msg);
}

static void LibBmpPrintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int fnt = Param[0]->Val->Integer;
    int x = Param[1]->Val->Integer;
    int y = Param[2]->Val->Integer;
    char msg[512];

    struct OutputStream StrStream;
    
    extern void SPutc(unsigned char Ch, union OutputStreamInfo *Stream);
    StrStream.Putch = &SPutc;
    StrStream.i.Str.Parser = Parser;
    StrStream.i.Str.WritePos = msg;
    
    // there doesn't seem to be any bounds checking :(

    GenericPrintf(Parser, ReturnValue, Param+3, NumArgs-3, &StrStream);
    PrintCh(0, &StrStream);

    bmp_printf(fnt, x, y, "%s", msg);
}

static void LibBmpPrintfCenter(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int fnt = Param[0]->Val->Integer;
    int x = Param[1]->Val->Integer;
    int y = Param[2]->Val->Integer;
    char msg[512];

    struct OutputStream StrStream;
    
    extern void SPutc(unsigned char Ch, union OutputStreamInfo *Stream);
    StrStream.Putch = &SPutc;
    StrStream.i.Str.Parser = Parser;
    StrStream.i.Str.WritePos = msg;
    
    // there doesn't seem to be any bounds checking :(

    GenericPrintf(Parser, ReturnValue, Param+3, NumArgs-3, &StrStream);
    PrintCh(0, &StrStream);

    bmp_printf(
        fnt, 
        x - fontspec_font(fnt)->width * strlen(msg) / 2, 
        y - fontspec_font(fnt)->height/2, 
        "%s", 
        msg
    );
}

static void LibClrScr(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    clrscr();
}

static void LibGetPixel(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int x = Param[0]->Val->Integer;
    int y = Param[1]->Val->Integer;
    ReturnValue->Val->Integer = bmp_getpixel(x, y);
}

static void LibPutPixel(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int x = Param[0]->Val->Integer;
    int y = Param[1]->Val->Integer;
    int color = Param[2]->Val->Integer;
    bmp_putpixel(x, y, color);
}

static void LibDrawLine(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int x1 = Param[0]->Val->Integer;
    int y1 = Param[1]->Val->Integer;
    int x2 = Param[2]->Val->Integer;
    int y2 = Param[3]->Val->Integer;
    int color = Param[4]->Val->Integer;
    draw_line(x1, y1, x2, y2, color);
}

static void LibDrawLinePolar(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int x = Param[0]->Val->Integer;
    int y = Param[1]->Val->Integer;
    int radius = Param[2]->Val->Integer;
    int angle = (int)roundf(Param[3]->Val->FP * 10.0);
    int color = Param[4]->Val->Integer;
    draw_angled_line(x, y, radius, angle, color);
}

static void LibDrawCircle(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int x = Param[0]->Val->Integer;
    int y = Param[1]->Val->Integer;
    int radius = Param[2]->Val->Integer;
    int color = Param[3]->Val->Integer;
    draw_circle(x, y, radius, color);
}

static void LibFillCircle(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int x = Param[0]->Val->Integer;
    int y = Param[1]->Val->Integer;
    int radius = Param[2]->Val->Integer;
    int color = Param[3]->Val->Integer;
    fill_circle(x, y, radius, color);
}

static void LibDrawRect(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int x = Param[0]->Val->Integer;
    int y = Param[1]->Val->Integer;
    int w = Param[2]->Val->Integer;
    int h = Param[3]->Val->Integer;
    int color = Param[4]->Val->Integer;
    bmp_draw_rect(color, x, y, w, h);
}

static void LibFillRect(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int x = Param[0]->Val->Integer;
    int y = Param[1]->Val->Integer;
    int w = Param[2]->Val->Integer;
    int h = Param[3]->Val->Integer;
    int color = Param[4]->Val->Integer;
    bmp_fill(color, x, y, w, h);
}

static void LibDoubleBufferStart(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    bmp_draw_to_idle(1);
}

static void LibDoubleBufferEnd(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    console_show_status();
    bmp_draw_to_idle(0);
    bmp_idle_copy(1,0);
}

static void LibSetCanonGUI(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int enabled = Param[0]->Val->Integer;
    if (enabled)
        canon_gui_enable_front_buffer(1);
    else
        canon_gui_disable_front_buffer();
}

static void LibSetGuiMode(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int mode = Param[0]->Val->Integer;
#ifndef CONFIG_5DC
    SetGUIRequestMode(mode);
#endif
}

static void LibGetGuiMode(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->Integer = CURRENT_DIALOG_MAYBE;
}

static void LibMenuOpen(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    gui_open_menu();
}

static void LibMenuClose(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    gui_stop_menu();
}

static void LibMenuSelect(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    char* tab = Param[0]->Val->Pointer;
    char* entry = Param[1]->Val->Pointer;
    select_menu_by_name(tab, entry);
}

static void LibMenuGet(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    char* tab = Param[0]->Val->Pointer;
    char* entry = Param[1]->Val->Pointer;
    ReturnValue->Val->Integer = menu_get_value_from_script(tab, entry);
}

static void LibMenuGetStr(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    char* tab = Param[0]->Val->Pointer;
    char* entry = Param[1]->Val->Pointer;
    
    if (gui_menu_shown())
    {
        console_printf("menu_get_str: close ML menu first\n");
        ReturnValue->Val->Pointer = "(err)";
    }
    ReturnValue->Val->Pointer = (char*) menu_get_str_value_from_script(tab, entry);
}

static void LibMenuSet(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    char* tab = Param[0]->Val->Pointer;
    char* entry = Param[1]->Val->Pointer;
    int value = Param[2]->Val->Integer;
    ReturnValue->Val->Integer = menu_set_value_from_script(tab, entry, value);
}

static void LibMenuSetStr(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    char* tab = Param[0]->Val->Pointer;
    char* entry = Param[1]->Val->Pointer;
    char* value = Param[2]->Val->Pointer;
    
    if (gui_menu_shown())
    {
        console_printf("menu_set_str: close ML menu first\n");
        ReturnValue->Val->Integer = 0;
    }
    ReturnValue->Val->Integer = menu_set_str_value_from_script(tab, entry, value, 0xdeadbeaf);
}

static void LibGetLVBuf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->Pointer = get_yuv422_vram();
}

static void LibGetHDBuf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->Pointer = get_yuv422_hd_vram();
}

struct yuv { int Y; int U; int V; };
struct rgb { int R; int G; int B; };

static void LibGetPixelYUV(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int x = Param[0]->Val->Integer;
    int y = Param[1]->Val->Integer;
    
    uint32_t* lv = (uint32_t*)(get_yuv422_vram()->vram);
    uint32_t uyvy = lv[N2LV(x,y)/4];
    static struct yuv yuv;
    uyvy_split(uyvy, &yuv.Y, &yuv.U, &yuv.V);
    ReturnValue->Val->Pointer = &yuv;
}

static void LibGetPixelRGB(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int x = Param[0]->Val->Integer;
    int y = Param[1]->Val->Integer;
    
    uint32_t* lv = (uint32_t*)(get_yuv422_vram()->vram);
    uint32_t uyvy = lv[N2LV(x,y)/4];
    struct yuv yuv;
    static struct rgb rgb;
    uyvy_split(uyvy, &yuv.Y, &yuv.U, &yuv.V);
    yuv2rgb(yuv.Y, yuv.U, yuv.V, &rgb.R, &rgb.G, &rgb.B);
    ReturnValue->Val->Pointer = &rgb;
}

static void LibGetSpotYUV(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int x = Param[0]->Val->Integer;
    int y = Param[1]->Val->Integer;
    int s = Param[2]->Val->Integer;
    
    x = N2BM_X(x);
    y = N2BM_Y(y);
    s = N2BM_DX(s);
    
    int xc = os.x0 + os.x_ex/2;
    int yc = os.y0 + os.y_ex/2;
    
    static struct yuv yuv;
    get_spot_yuv_ex(s/2, x - xc, y - yc, &yuv.Y, &yuv.U, &yuv.V, 1, 0);
    ReturnValue->Val->Pointer = &yuv;
}

static void LibGetSpotRGB(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    int x = Param[0]->Val->Integer;
    int y = Param[1]->Val->Integer;
    int s = Param[2]->Val->Integer;
    
    x = N2BM_X(x);
    y = N2BM_Y(y);
    s = N2BM_DX(s);
    
    int xc = os.x0 + os.x_ex/2;
    int yc = os.y0 + os.y_ex/2;
    
    struct yuv yuv;
    static struct rgb rgb;
    get_spot_yuv_ex(s/2, x - xc, y - yc, &yuv.Y, &yuv.U, &yuv.V, 1, 0);
    yuv2rgb(yuv.Y, yuv.U, yuv.V, &rgb.R, &rgb.G, &rgb.B);
    ReturnValue->Val->Pointer = &rgb;
}

static void LibDisplayOn(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    display_on();
}
static void LibDisplayOff(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    display_off();
}
static void LibDisplayIsOn(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->Integer = DISPLAY_IS_ON;
}
static void LibLVPause(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    PauseLiveView();
    display_off();
}
static void LibLVResume(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ResumeLiveView();
}

static void LibCacheLocked(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->Integer = script_cache_locked();
}
static void LibCacheLock(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    script_cache_lock();
}
static void LibCacheUnlock(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    script_cache_unlock();
}
static void LibCacheFake(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    uint32_t address = Param[0]->Val->Integer;
    uint32_t data = Param[1]->Val->Integer;
    uint32_t type = Param[2]->Val->Integer;
    
    ReturnValue->Val->Integer = script_cache_fake(address, data, type);
}

static void LibGetModel(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->Pointer = camera_model;
}

static void LibGetFirmware(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
    ReturnValue->Val->Pointer = firmware_version;
}


/* list of all library functions and their prototypes */
struct LibraryFunction PlatformLibrary[] =
{
    /** General-purpose functions **/
    {LibSleep,          "void sleep(float seconds);"    },  // sleep X seconds
    {LibBeep,           "void beep();"                  },  // short beep sound
    {LibBeeps,          "void beeps(int num);"          },  // short consecutive beeps
    {LibBeepCustom,     "void beep_custom(int duration, int frequency, int wait);"},  // beep sound with custom frequency and duration
    {LibConsoleShow,    "void console_show();"          },  // show the script console
    {LibConsoleHide,    "void console_hide();"          },  // hide the script console
    {LibCls,            "void cls();"                   },  // clear the script console
    {LibScreenshot,     "void screenshot();"            },  // take a screenshot (BMP+422)
    {LibRand,           "unsigned int rand();"          },  // random numbers

    /** Date/time **/
    
    /**
     * struct tm 
     * {
     *      int hour; 
     *      int minute; 
     *      int second;
     *      int year; 
     *      int month; 
     *      int day; 
     * }
     */
    
    {LibGetTime,        "struct tm * get_time();"       },  // get current date/time
    {LibGetUptime,      "float get_uptime();"           },  // get uptime, in seconds, 1ms resolution (from DIGIC clock)

    /** Picture taking **/
    {LibTakePic,        "void takepic();"               },  // take a picture
    {LibBulbPic,        "void bulbpic(float seconds);"  },  // take a picture in bulb mode
    {LibTakeFastPics,   "void take_fast_pics(int number);" },  // take N pictures in burst mode
    
    {LibWaitPic,        "void wait_pic();"              },  // waits until you take a picture (e.g. for starting a custom bracket sequence)
    
    /** Video recording **/
    {LibMovieStart,     "void movie_start();"           },  // start recording
    {LibMovieEnd,       "void movie_end();"             },  // stop recording

    /** Key press emulation **/
    
    /**
     * Available button codes:
     *      LEFT, RIGHT, UP, DOWN, SET, MENU, PLAY, ERASE, LV, INFO, ZOOM_IN
     *      SHOOT_FULL, SHOOT_HALF
     *      Q, ZOOM_OUT (if present on your camera)
     *      UNPRESS (for key input only)
     */
    
    {LibPress,          "void press(int button);"       },  // "press" a button
    {LibUnpress,        "void unpress(int button);"     },  // "unpress" a button
    {LibClick,          "void click(int button);"       },  // "press" and then "unpress" a button
    
    /** Key input **/

    /**
     * Two methods:
     * - blocking:      int key = wait_key();      // waits for key to be pressed, then returns the key code
     * - non-blocking:  int key = last_key();     // returns the last key code without waiting (or -1)
     * 
     * Keys are trapped when you call one of those, and also 1 second after. This lets you write loops like:
     * 
     * while(1)
     * {
     *     int key = wait_key();
     * 
     *     // process the key
     *     if (key == SET) { ... }
     * }
     * 
     * or
     * 
     * while(1)
     * {
     *     int key = last_key();
     * 
     *     // process the key
     *     if (key == SET) { ... }
     * 
     *     sleep(0.1);
     * }
     */

    {LibWaitKey,        "int wait_key();"               },  // waits until you press some key, then returns key code
    {LibLastKey,        "int last_key();"               },  // returns last key pressed, without waiting

    /** Exposure settings **/
    
    // APEX units
    {LibGetTv,        "float get_tv();"                 },
    {LibGetAv,        "float get_av();"                 },
    {LibGetSv,        "float get_sv();"                 },
    {LibSetTv,        "void set_tv(float tv);"          },
    {LibSetAv,        "void set_av(float av);"          },
    {LibSetSv,        "void set_sv(float sv);"          },

    // Conventional units ( ISO 100, 1.0/4000, 2.8 )
    {LibGetISO,        "int get_iso();"                 },
    {LibGetShutter,    "float get_shutter();"           },
    {LibGetAperture,   "float get_aperture();"          },
    {LibSetISO,        "void set_iso(int iso);"         },
    {LibSetShutter,    "void set_shutter(float s);"     },
    {LibSetAperture,   "void set_aperture(float s);"    },

    // Raw units (1/8 EV steps)
    {LibGetRawISO,      "int get_rawiso();"             },
    {LibGetRawShutter,  "int get_rawshutter();"         },
    {LibGetRawAperture, "int get_rawaperture();"        },
    {LibSetRawISO,      "void set_rawiso(int raw);"     },
    {LibSetRawShutter,  "void set_rawshutter(int raw);" },
    {LibSetRawAperture, "void set_rawaperture(int raw);"},
    
    /** Exposure compensation (in EV) **/
    {LibGetAE,          "float get_ae();"               },
    {LibSetAE,          "void set_ae(float ae);"        },

    /** Flash functions **/
    {LibGetFlash,       "int get_flash();"              }, // 1=enabled, 0=disabled, 2=auto
    {LibSetFlash,       "int set_flash(int enabled);"   },
    {LibPopFlash,       "int pop_flash();"              }, // pop-up built-in flash
    {LibGetFlashAE,     "float get_flash_ae();"         },
    {LibSetFlashAE,     "void set_flash_ae(float ae);"  }, // flash exposure compensation

    /** White balance **/
    {LibGetKelvin,      "int get_kelvin();"             },
    {LibGetGreen,       "int get_green();"              },
    {LibSetKelvin,      "void set_kelvin(int k);"       }, // from 1500 to 15000
    {LibSetGreen,       "void set_green(int gm);"       }, // green-magenta shift, from -9 to 9

    /** Focus **/
    {LibFocus,          "void focus(int steps);"                }, // move the focus ring by X steps
    {LibFocusSetup,     "void focus_setup(int stepsize, int delay, int wait);" }, // see Focus -> Focus Settings menu
    {LibGetFocusConfirm, "int get_focus_confirm();"             }, // return AF confirmation state (outside LiveView, with shutter halfway pressed)
    
    {LibSetAF,          "void set_af(int af);"                  }, // enable or disable AF for half-shutter press
    {LibResetAF,        "void reset_af(int af);"                }, // restore the original setting from Canon menu (CFn) (auto-called when script finishes)

    // AFMA modes: AFMA_MODE_AUTODETECT, AFMA_MODE_DISABLED, AFMA_MODE_ALL_LENSES, AFMA_MODE_PER_LENS, AFMA_MODE_PER_LENS_WIDE, AFMA_MODE_PER_LENS_TELE
    {LibGetAFMA,        "int get_afma(int mode);"               }, // get AF microadjust value
    {LibSetAFMA,        "void set_afma(int value, int mode);"   }, // set AF microadjust value
    
    /**
     * struct dof 
     * {
     *      char* lens_name; 
     *      int focal_len; 
     *      int focus_dist; 
     *      int dof; int far; 
     *      int near; 
     *      int hyperfocal; 
     * }
     */
    
    {LibGetDofInfo,     "struct dof * get_dof();"   },
    
    /** Low-level I/O **/
    {LibMicOut,          "void mic_out(int value);"                                  }, // digital output via microphone jack, by toggling mic power
    {LibSetLed,          "void set_led(int led, int value);"                         }, // set LED state; 1 = card LED, 2 = blue LED

#if 0
    {LibMicPrintf,       "void mic_printf(int baud, char* fmt, ...);"                }, // UART via microphone jack
    {LibWavPrintf,       "void wav_printf(int baud, char* fmt, ...);"                }, // UART via audio out (WAV)
    {LibLedPrintf,       "void led_printf(int baud, char* fmt, ...);"                }, // UART via card LED
    
    {LibMorseLedPrintf,  "void morse_led_printf(float dit_duration, char* fmt, ...);"    }, // Morse via card LED
    {LibMorseWavPrintf,  "void morse_wav_printf(float dit_duration, char* fmt, ...);"    }, // Morse via audio out (WAV)
#endif

    /** Graphics **/
    /**
    * Graphics constants:
    * 
    * Colors:
    *     COLOR_EMPTY, COLOR_BLACK, COLOR_WHITE, COLOR_BG,
    *     COLOR_RED, COLOR_DARK_RED, COLOR_GREEN1, COLOR_GREEN2, COLOR_BLUE, COLOR_LIGHT_BLUE,
    *     COLOR_CYAN, COLOR_MAGENTA, COLOR_YELLOW, COLOR_ORANGE,
    *     COLOR_ALMOST_BLACK, COLOR_ALMOST_WHITE,
    *     COLOR_GRAY(percent)
    *
    * Fonts: 
    *     FONT_LARGE, FONT_MED, FONT_SMALL
    *     FONT(fnt, fg, bg)
    *     SHADOW_FONT(fnt)
    *     e.g. FONT(FONT_LARGE, COLOR_YELLOW, COLOR_BLACK) or SHADOW_FONT(FONT_MED)
    */
    
    {LibClrScr,         "void clrscr();"                                                            },  // clear screen
    {LibGetPixel,       "int get_pixel(int x, int y);"                                              },
    {LibPutPixel,       "void put_pixel(int x, int y, int color);"                                  },
    {LibDrawLine,       "void draw_line(int x1, int y1, int x2, int y2, int color);"                },
    {LibDrawLinePolar,  "void draw_line_polar(int x, int y, int radius, float angle, int color);"   },
    {LibDrawCircle,     "void draw_circle(int x, int y, int radius, int color);"                    },
    {LibFillCircle,     "void fill_circle(int x, int y, int radius, int color);"                    },
    {LibDrawRect,       "void draw_rect(int x, int y, int w, int h, int color);"                    },
    {LibFillRect,       "void fill_rect(int x, int y, int w, int h, int color);"                    },
    
    {LibDoubleBufferStart, "void double_buffering_start();"                                         }, // start double buffering, for flicker-free drawing
    {LibDoubleBufferEnd,   "void double_buffering_end();"                                           }, // finish double buffering and update the screen

    /** Text output **/
    {LibBmpPrintf,      "void bmp_printf(int fnt, int x, int y, char* fmt, ...);"                   },
    {LibBmpPrintfCenter,"void bmp_printf_center(int fnt, int x, int y, char* fmt, ...);"            },
    {LibNotifyBox,      "void notify_box(float duration, char* fmt, ...);"                          },

    /** Interaction with Canon GUI **/
    {LibSetCanonGUI,    "void set_canon_gui(int enabled);"                          }, // allow disabling Canon graphics
    {LibSetGuiMode,     "void set_gui_mode(int mode);"    }, // set Canon GUI mode (current dialog, 0=idle, 1=play, 2=menu, others camera-specific)
    {LibGetGuiMode,     "int get_gui_mode();"    },

    /** Interaction with ML menus **/
    // Tip: to get a list with menus and possible values, go to Prefs -> Config File -> Export as PicoC script
    // You can also use these functions to create custom presets.
    { LibMenuOpen,       "void menu_open();"                                     }, // open ML menu
    { LibMenuClose,      "void menu_close();"                                    }, // close ML menu
    { LibMenuSelect,     "void menu_select(char* tab, char* entry);"             }, // select a menu tab and entry (e.g. Overlay, Focus Peak)
    { LibMenuGet,        "int menu_get(char* tab, char* entry);"                 }, // return the raw (integer) value from a menu entry
    { LibMenuSet,        "int menu_set(char* tab, char* entry, int value);"      }, // set a menu entry to some arbitrary value; 1 = success, 0 = failure
    { LibMenuGetStr,     "char* menu_get_str(char* tab, char* entry);"           }, // return the displayed (string) value from a menu entry
    { LibMenuSetStr,     "int menu_set_str(char* tab, char* entry, char* value);"}, // set a menu entry to some arbitrary string value (cycles until it gets it); 1 = success, 0 = failure

    /** Image analysis **/

    /**
     * 
     * Don't expect too much; it's quite slow to operate at pixel level due to interpreter overhead.
     * Consider using plain C for this task.
     * 
     * Functions that operate on larger data sets (e.g. spotmeter, histogram analysis) should be fast enough.
     * 
     * struct yuv
     * {
     *      int Y; // 0...255
     *      int U; // -128...127
     *      int V; // -128...127
     * }
     * 
     * struct rgb
     * {
     *      int R; // 0...255
     *      int G; // 0...255
     *      int B; // 0...255
     * }
     */

    // The following functions operate on normalized coordinates (720x480)
    // This means they should work on external monitors without extra care, for example.
    // Details: http://magiclantern.wikia.com/wiki/VRAM/Geometry
    { LibGetPixelYUV,    "struct yuv * get_pixel_yuv(int x, int y);"            }, // get the YUV components of a pixel from LiveView buffer
    { LibGetPixelRGB,    "struct rgb * get_pixel_rgb(int x, int y);"            }, // similar for RGB
    { LibGetSpotYUV,     "struct yuv * get_spot_yuv(int x, int y, int size);"   }, // spotmeter: average pixels from a (small) box and return average YUV.
    { LibGetSpotRGB,     "struct rgb * get_spot_rgb(int x, int y, int size);"   }, // similar for RGB

    /**
     * For low-level image processing
     * 
     * struct vram
     * {
     *      void* buffer;
     *      int width;
     *      int pitch;
     *      int height;
     * }
     */
    { LibGetLVBuf,       "struct vram * get_lv_vram();" },        // get LiveView image buffer
    { LibGetHDBuf,       "struct vram * get_hd_vram();" },        // get LiveView recording buffer

#if 0 // not yet implemented
    /** MLU, HTP, misc settings */
    {LibGetMLU,         "int get_mlu();"                },
    {LibGetHTP,         "int get_htp();"                },
    {LibGetALO,         "int get_alo();"                },
    {LibSetMLU,         "void set_mlu(int mlu);"        },
    {LibSetHTP,         "void set_htp(int htp);"        },
    {LibSetALO,         "void set_alo(int alo);"        },
    
    { LibYUV2RGB,        "struct rgb * yuv2rgb(struct yuv * pixel);"            }, // convert from YUV to RGB
    { LibRGB2YUV,        "struct yuv * rgb2yuv(struct rgb * pixel);"            }, // convert from YUV to RGB
    { LibGetHistoRange,  "float get_histo_range(int from, int to);"             }, // percent of values between <from> and <to> in histogram data
    { LibGetHistoPercentile, "int get_histo_percentile(int p);"                 }, // brightness value at percentile p. For median, use p=50. See http://en.wikipedia.org/wiki/Percentile .
    
    /** Audio stuff */
    { LibAudioGetLevel,  "int audio_get_level(int channel, int type);" }, // channel: 0/1; type: INSTANT, AVG, PEAK, PEAK_FAST
    { LibAudioLevelToDB, "int audio_level_to_db(int level)"            }, // conversion from 16-bit signed to dB
#endif

    /** Powersaving **/
    { LibDisplayOn,     "void display_on();"           },
    { LibDisplayOff,    "void display_off();"          },
    { LibDisplayIsOn,   "int display_is_on();"         },

    { LibLVPause,       "void lv_pause();"             }, // pause LiveView without dropping the mirror
    { LibLVResume,      "void lv_resume();"            },
    
    /** Cache hacking **/
    { LibCacheLocked,   "unsigned int cache_locked();" },
    { LibCacheLock,     "void cache_lock();"           },
    { LibCacheUnlock,   "void cache_unlock();"         },
    { LibCacheFake,     "void cache_fake(unsigned int address, unsigned int data, unsigned int type);" },
    
    /** Camera info **/
    { LibGetModel,      "char* get_model();"           },
    { LibGetFirmware,   "char* get_firmware();"        },
    { NULL,         NULL }
};

static void lib_parse(const char* definition)
{
    PicocParse("ml lib", definition, strlen(definition), TRUE, TRUE, FALSE);
}

#define READONLY_VAR(x) VariableDefinePlatformVar(NULL, #x, &IntType, (union AnyValue *)&x,      FALSE);

#define CONST(var, value) lib_parse("#define " #var " " STR(value));
#define CONST0(var)       lib_parse("#define " #var " " STR(var));

void PlatformLibraryInit()
{
    lib_parse("struct tm { int hour; int minute; int second; int year; int month; int day; };");
    lib_parse("struct dof { char* lens_name; int focal_len; int focus_dist; int dof; int far; int near; int hyperfocal; };");
    lib_parse("struct vram { void* buffer; int width; int pitch; int height; };");
    lib_parse("struct yuv { int Y; int U; int V; };");
    lib_parse("struct rgb { int R; int G; int B; };");

    LibraryAdd(&GlobalTable, "platform library", &PlatformLibrary[0]);

    /** Button codes */
    CONST(LEFT,         BGMT_PRESS_LEFT)
    CONST(RIGHT,        BGMT_PRESS_RIGHT)
    CONST(UP,           BGMT_PRESS_UP)
    CONST(DOWN,         BGMT_PRESS_DOWN)
    CONST(WHEEL_LEFT,   BGMT_WHEEL_LEFT)
    CONST(WHEEL_RIGHT,  BGMT_WHEEL_RIGHT)
    CONST(WHEEL_UP,     BGMT_WHEEL_UP)
    CONST(WHEEL_DOWN,   BGMT_WHEEL_DOWN)
    CONST(SET,          BGMT_PRESS_SET)
    CONST(MENU,         BGMT_MENU)
    CONST(PLAY,         BGMT_PLAY)
    CONST(ERASE,        BGMT_TRASH)
    CONST(INFO,         BGMT_INFO)
    CONST(LV,           BGMT_LV)
    CONST(ZOOM_IN,      BGMT_PRESS_ZOOMIN_MAYBE)
    CONST(SHOOT_HALF,   BGMT_PRESS_HALFSHUTTER)
    CONST(SHOOT_FULL,   BGMT_PRESS_FULLSHUTTER)

    #ifdef BGMT_Q
    CONST(Q,            BGMT_Q)
    #else
    CONST(Q,            -1)
    #endif

    #ifdef BGMT_PRESS_ZOOMOUT_MAYBE
    CONST(ZOOM_OUT,     BGMT_PRESS_ZOOMOUT_MAYBE)
    #else
    CONST(ZOOM_OUT,     -1)
    #endif

    CONST0(UNPRESS)
    CONST0(NO_KEY)
    CONST0(AF_ON)
    CONST0(HALFSHUTTER_PRESSED)

    /** Color codes */
    CONST0(COLOR_EMPTY)
    CONST0(COLOR_BLACK)
    CONST0(COLOR_WHITE)
    CONST0(COLOR_BG)

    CONST0(COLOR_RED)
    CONST0(COLOR_DARK_RED)
    CONST0(COLOR_GREEN1)
    CONST0(COLOR_GREEN2)
    CONST0(COLOR_BLUE)
    CONST0(COLOR_LIGHT_BLUE)
    CONST0(COLOR_CYAN)
    CONST0(COLOR_MAGENTA)
    CONST0(COLOR_YELLOW)
    CONST0(COLOR_ORANGE)

    CONST0(COLOR_ALMOST_BLACK) // 38
    CONST0(COLOR_ALMOST_WHITE) // 79
    lib_parse("#define COLOR_GRAY(percent) (38 + (percent) * 41 / 100)"); // COLOR_GRAY(50) is 50% gray

    /** Font constants */
    CONST0(FONT_LARGE)
    CONST0(FONT_MED)
    CONST0(FONT_SMALL)
    CONST0(FONT_MASK)
    CONST0(SHADOW_MASK)
    
    lib_parse("#define FONT(font,fg,bg) (((font) & (FONT_MASK | SHADOW_MASK)) | ((bg) & 0xFF) << 8 | ((fg) & 0xFF) << 0)");
    lib_parse("#define SHADOW_FONT(fnt) ((fnt) | SHADOW_MASK)");

    /** Common operators */
    lib_parse("#define MIN(a,b) ((a) < (b) ? (a) : (b))");
    lib_parse("#define MAX(a,b) ((a) > (b) ? (a) : (b))");
    lib_parse("#define COERCE(x,lo,hi) MAX(MIN((x),(hi)),(lo))");
    lib_parse("#define ABS(a) ((a) < (0) ? -(a) : (a))");
    lib_parse("#define SGN(a) ((a) > 0 ? 1 : (a) < 0 ? -1 : 0)");
    
    CONST0(M_PI);

    /** cache hacking */
    CONST0(TYPE_DCACHE);
    CONST0(TYPE_ICACHE);
    
    /** AFMA */
    CONST0(AFMA_MODE_AUTODETECT);
    CONST0(AFMA_MODE_DISABLED);
    CONST0(AFMA_MODE_PER_LENS);
    CONST0(AFMA_MODE_PER_LENS_WIDE);
    CONST0(AFMA_MODE_PER_LENS_TELE);
    
    /** common properties */

    READONLY_VAR(lv)
    READONLY_VAR(recording)
}
back to top