https://bitbucket.org/daniel_fort/magic-lantern
Raw File
Tip revision: f2c67846d70537da8ab1125733fc93ffed088047 authored by a1ex on 19 June 2016, 18:08:29 UTC
Close branch lua_stdio.
Tip revision: f2c6784
api_test.lua
-- Test routines for the scripting API
-- Very incomplete

function printf(s,...)
    -- fixme: newlines (io.write doesn't work)
    print(s:format(...))
end

function request_mode(mode, mode_str)
    while camera.mode ~= mode do
        printf("Please switch to %s mode.", mode_str, mode)
        while camera.mode ~= mode do
            console.show()
            msleep(1000)
        end
    end
end

function round(x)
    -- https://scriptinghelpers.org/questions/4850/how-do-i-round-numbers-in-lua-answered
    return x + 0.5 - (x + 0.5) % 1
end

function api_tests()
    menu.close()
    console.clear()
    console.show()
    printf("Testing module 'camera'...")
    printf("Camera    : %s (%s) %s", camera.model, camera.model_short, camera.firmware)
    printf("Lens      : %s", lens.name)
    printf("Shoot mode: %s", camera.mode)
    printf("Shutter   : %s (raw %s, %ss, %sms, apex %s)", camera.shutter, camera.shutter.raw, camera.shutter.value, camera.shutter.ms, camera.shutter.apex)
    printf("Aperture  : %s (raw %s, f/%s, apex %s)", camera.aperture, camera.aperture.raw, camera.aperture.value, camera.aperture.apex)
    printf("Av range  : %s..%s (raw %s..%s, f/%s..f/%s, apex %s..%s)",
        camera.aperture.min, camera.aperture.max,
        camera.aperture.min.raw, camera.aperture.max.raw,
        camera.aperture.min.value, camera.aperture.max.value,
        camera.aperture.min.apex, camera.aperture.max.apex
    )
    printf("ISO       : %s (raw %s, %s, apex %s)", camera.iso, camera.iso.raw, camera.iso.value, camera.iso.apex)
    printf("EC        : %s (raw %s, %s EV)", camera.ec, camera.ec.raw, camera.ec.value)
    printf("Flash EC  : %s (raw %s, %s EV)", camera.flash_ec, camera.flash_ec.raw, camera.flash_ec.value)
    printf("Kelvin    : %s", camera.kelvin)
    
    request_mode(MODE.M, "M")
    printf("Setting shutter to random values...")
    for k = 1,100 do
        method = math.random(1,4)
        if method == 1 then
            local s = math.random(1,30)
            camera.shutter.value = s
            d = math.abs(math.log(camera.shutter.value,2) - math.log(s,2))
        elseif method == 2 then
            local ms = math.random(1,30000)
            camera.shutter.ms = ms
            d = math.abs(math.log(camera.shutter.ms,2) - math.log(ms,2))
        elseif method == 3 then
            local apex = math.random(-5*100,12*100)/100
            camera.shutter.apex = apex
            d = math.abs(camera.shutter.apex - apex)
        elseif method == 4 then
            local raw = math.random(16,152)
            camera.shutter.raw = raw
            d = math.abs(camera.shutter.raw - raw) / 8
        end

        -- difference between requested and actual shutter speed should be max 1.5/8 EV
        -- (most cameras accept 0, 3/8, 4/8, 5/8, 1 EV, the largest gap being 3/8 EV,
        --  and you should always get the nearest valid shutter speed)
        if d > 1.5/8 + 1e-3 then
            printf("Error: shutter delta %s EV", d)
        end

        -- seconds and ms fields should be consistent
        if math.abs(camera.shutter.value - camera.shutter.ms/1000) > 1e-3 then
            printf("Error: shutter %ss != %sms", camera.shutter.value, camera.shutter.ms)
        end
        
        -- seconds and apex should be consistent
        -- see http://dougkerr.net/Pumpkin/articles/APEX.pdf
        expected_apex = math.log(1/camera.shutter.value,2)
        if math.abs(expected_apex - camera.shutter.apex) > 0.01 then
            printf("Error: shutter %ss != Tv%s, expected %s", camera.shutter.value, camera.shutter.apex, expected_apex)
        end
        
        -- setting shutter to the same value, using any method (s,ms,apex,raw)
        -- should not change anything
        for i,field in pairs{"value","ms","apex","raw"} do
            apex  = camera.shutter.apex
            value = camera.shutter.value
            ms    = camera.shutter.ms
            raw   = camera.shutter.raw
            
            -- ms is integer, so tests at very low values will fail because of roundoff errors
            -- however, if we have set the shutter in ms from the beginning, it will work fine
            if field == "ms" and ms < 10 and method ~= 2 then
                -- how do you write "continue" in Lua?!
                field = "value"
            end
            
            camera.shutter[field] = _G[field]
            
            if camera.shutter.value ~= value then
                printf("Error: shutter set to %s=%s, got %ss, expected %ss", field, _G[field], camera.shutter.value, value)
            end
            if camera.shutter.ms ~= ms then
                printf("Error: shutter set to %s=%s, got %sms, expected %sms", field, _G[field], camera.shutter.ms, ms)
            end
            if camera.shutter.apex ~= apex then
                printf("Error: shutter set to %s=%s, got Tv%s, expected Tv%s", field, _G[field], camera.shutter.apex, apex)
            end
            if camera.shutter.raw ~= raw then
                printf("Error: shutter set to %s=%s, got %s, expected %s (raw)", field, _G[field], camera.shutter.raw, raw)
            end
        end
    end

    request_mode(MODE.M, "M")
    printf("Setting ISO to random values...")
    for k = 1,100 do
        method = math.random(1,3)
        if method == 1 then
            local iso = math.random(100, 6400)
            camera.iso.value = iso
            d = math.abs(math.log(camera.iso.value,2) - math.log(iso,2))
        elseif method == 2 then
            local apex = math.random(5*100,11*100)/100
            camera.iso.apex = apex
            d = math.abs(camera.iso.apex - apex)
        elseif method == 3 then
            local raw = math.random(72, 120)
            camera.iso.raw = raw
            d = math.abs(camera.iso.raw - raw) / 8
        end

        -- difference between requested and actual ISO should be max 1/3 EV
        if d > 1/3 then
            printf("Error: ISO delta %s EV", d)
        end

        -- ISO and Sv (APEX) should be consistent
        expected_apex = math.log(camera.iso.value/3.125, 2)
        if math.abs(expected_apex - camera.iso.apex) > 0.2 then
            printf("Error: ISO %s != Sv%s, expected %s", camera.iso.value, camera.iso.apex, expected_apex)
        end

        -- setting ISO to the same value, using any method (value,apex,raw)
        -- should not change anything
        for i,field in pairs{"value","apex","raw"} do
            apex  = camera.iso.apex
            value = camera.iso.value
            raw   = camera.iso.raw
            
            camera.iso[field] = _G[field]
            
            if camera.iso.value ~= value then
                printf("Error: ISO set to %s=%s, got %s, expected %s", field, _G[field], camera.iso.value, value)
            end
            if camera.iso.apex ~= apex then
                printf("Error: ISO set to %s=%s, got Sv%s, expected Sv%s", field, _G[field], camera.iso.apex, apex)
            end
            if camera.iso.raw ~= raw then
                printf("Error: ISO set to %s=%s, got %s, expected %s (raw)", field, _G[field], camera.iso.raw, raw)
            end
        end
    end

    if camera.aperture.min.raw == camera.aperture.max.raw then
        printf("This lens does not have variable aperture (skipping test).")
    else
        request_mode(MODE.M, "M")
        printf("Setting aperture to random values...")
        for k = 1,100 do
            method = math.random(1,3)
            extra_tol = 0
            if method == 1 then
                local av = math.random(round(camera.aperture.min.value*10), round(camera.aperture.max.value*10)) / 10
                camera.aperture.value = av
                d = math.abs(math.log(camera.aperture.value,2) - math.log(av,2)) * 2
                -- when checking the result, allow a larger difference (0.1 units) - see note below
                extra_tol = math.abs(math.log(av,2) - math.log(av-0.1,2)) * 2
            elseif method == 2 then
                local apex = math.random(round(camera.aperture.min.apex*100), round(camera.aperture.max.apex*100)) / 100
                camera.aperture.apex = apex
                d = math.abs(camera.aperture.apex - apex)
            elseif method == 3 then
                local raw = math.random(camera.aperture.min.raw, camera.aperture.max.raw)
                camera.aperture.raw = raw
                d = math.abs(camera.aperture.raw - raw) / 8
            end

            -- difference between requested and actual aperture should be max 1.5/8 EV
            -- note: when using F-numbers, the difference may be larger, because of the rounding done
            -- to match Canon values (e.g. raw 48 would be f/5.66 (f/5.7), instead of Canon's f/5.6)
            if (d > 1.5/8 + extra_tol) then
                printf("Error: aperture delta %s EV (expected < %s, f/%s, method=%d)", d, 1.5/8 + extra_tol, camera.aperture, method)
            end

            -- aperture and Av (APEX) should be consistent
            expected_apex = math.log(camera.aperture.value, 2) * 2
            if math.abs(expected_apex - camera.aperture.apex) > 0.2 then
                printf("Error: aperture %s != Av%s, expected %s", camera.aperture.value, camera.aperture.apex, expected_apex)
            end

            -- setting aperture to the same value, using any method (value,apex,raw)
            -- should not change anything
            for i,field in pairs{"value","apex","raw"} do
                apex  = camera.aperture.apex
                value = camera.aperture.value
                raw   = camera.aperture.raw
                
                camera.aperture[field] = _G[field]
                
                if camera.aperture.value ~= value then
                    printf("Error: aperture set to %s=%s, got %s, expected %s", field, _G[field], camera.aperture.value, value)
                end
                if camera.aperture.apex ~= apex then
                    printf("Error: aperture set to %s=%s, got Sv%s, expected Sv%s", field, _G[field], camera.aperture.apex, apex)
                end
                if camera.aperture.raw ~= raw then
                    printf("Error: aperture set to %s=%s, got %s, expected %s (raw)", field, _G[field], camera.aperture.raw, raw)
                end
            end
        end
    end

    request_mode(MODE.AV, "Av")
    printf("Setting EC to random values...")
    for k = 1,100 do
        method = math.random(1,2)
        if method == 1 then
            local ec = math.random(-2*100, 2*100) / 100
            camera.ec.value = ec
            d = math.abs(camera.ec.value - ec,2)
        elseif method == 2 then
            local raw = math.random(-16, 16)
            camera.ec.raw = raw
            d = math.abs(camera.ec.raw - raw) / 8
        end

        -- difference between requested and actual EC should be max 1.5/8 EV
        if d > 1.5/8 then
            printf("Error: EC delta %s EV", d)
        end

        -- EC and raw should be consistent
        expected_ec = camera.ec.raw / 8
        if math.abs(expected_ec - camera.ec.value) > 0.001 then
            printf("Error: EC raw %s != %s EV, expected %s EV", camera.ec.raw, camera.ec.value, expected_ec)
        end

        -- setting EC to the same value, using any method (value,raw)
        -- should not change anything
        for i,field in pairs{"value","raw"} do
            value = camera.ec.value
            raw   = camera.ec.raw
            
            camera.ec[field] = _G[field]
            
            if camera.ec.value ~= value then
                printf("Error: EC set to %s=%s, got %s, expected %s EV", field, _G[field], camera.ec.value, value)
            end
            if camera.ec.raw ~= raw then
                printf("Error: EC set to %s=%s, got %s, expected %s (raw)", field, _G[field], camera.ec.raw, raw)
            end
        end
    end

    -- copy/paste & replace from EC (those two should behave in the same way)
    printf("Setting Flash EC to random values...")
    for k = 1,100 do
        method = math.random(1,2)
        if method == 1 then
            local fec = math.random(-2*100, 2*100) / 100
            camera.flash_ec.value = fec
            d = math.abs(camera.flash_ec.value - fec,2)
        elseif method == 2 then
            local raw = math.random(-16, 16)
            camera.flash_ec.raw = raw
            d = math.abs(camera.flash_ec.raw - raw) / 8
        end

        -- difference between requested and actual EC should be max 1.5/8 EV
        if d > 1.5/8 then
            printf("Error: FEC delta %s EV", d)
        end

        -- EC and raw should be consistent
        expected_fec = camera.flash_ec.raw / 8
        if math.abs(expected_fec - camera.flash_ec.value) > 0.001 then
            printf("Error: FEC raw %s != %s EV, expected %s EV", camera.flash_ec.raw, camera.flash_ec.value, expected_fec)
        end

        -- setting EC to the same value, using any method (value,raw)
        -- should not change anything
        for i,field in pairs{"value","raw"} do
            value = camera.flash_ec.value
            raw   = camera.flash_ec.raw
            
            camera.flash_ec[field] = _G[field]
            
            if camera.flash_ec.value ~= value then
                printf("Error: FEC set to %s=%s, got %s, expected %s EV", field, _G[field], camera.flash_ec.value, value)
            end
            if camera.flash_ec.raw ~= raw then
                printf("Error: FEC set to %s=%s, got %s, expected %s (raw)", field, _G[field], camera.flash_ec.raw, raw)
            end
        end
    end

    printf("Done!")

    key.wait()
    console.hide()
end

testmenu = menu.new
{
    name = "Script API tests",
    select = function(this) task.create(api_tests) end,
}

back to top