https://bitbucket.org/hudson/magic-lantern
Raw File
Tip revision: 71a5a35e73fdd312b466ee5ebf4a8330036537fa authored by Daniel Fort on 26 June 2017, 13:47:32 UTC
Corrected YUV422_LV_BUFFER_DISPLAY_ADDR value and enabled display filters: http://www.magiclantern.fm/forum/index.php?topic=9741.msg186289#msg186289
Tip revision: 71a5a35
lua_dryos.c
/***
 DryOS functions
 
 @author Magic Lantern Team
 @copyright 2014
 @license GPL
 @module dryos
 */

#include <dryos.h>
#include <fio-ml.h>
#include <fileprefix.h>
#include <string.h>
#include <config.h>

#include "lua_common.h"

static int luaCB_card_index(lua_State * L);
static int luaCB_card_newindex(lua_State * L);
static int luaCB_directory_index(lua_State * L);
static int luaCB_directory_newindex(lua_State * L);

/***
 Calls an eventproc (a function from the camera firmware which can be called by name).
 See Eventprocs. Dangerous - you need to compile Lua yourself in order to enable it.
 @tparam string function the name of the function to call
 @param[opt] arg argument to pass to the call
 @function call
 */
static int luaCB_dryos_call(lua_State * L)
{
#if 1
    return luaL_error(L,
        "dryos.call() is disabled for safety reasons.\n"
        "If you know what you are doing, just remove this message and recompile.\n"
    );
#endif

    LUA_PARAM_STRING(function_name, 1);
    int result = 0;
    int argc = lua_gettop(L);
    
    if(argc <= 1)
    {
        result = call(function_name);
    }
    else if(lua_isinteger(L, 2))
    {
        int arg = lua_tointeger(L, 2);
        result = call(function_name, arg);
    }
    else if(lua_isnumber(L, 2))
    {
        float arg = lua_tonumber(L, 2);
        result = call(function_name, arg);
    }
    else if(lua_isstring(L, 2))
    {
        const char * arg = lua_tostring(L, 2);
        result = call(function_name, arg);
    }
    
    lua_pushinteger(L, result);
    return 1;
}

const char * lua_dryos_directory_fields[] =
{
    "exists",
    "create",
    "children",
    "files",
    "parent",
    NULL
};

const char * lua_dryos_card_fields[] =
{
    "cluster_size",
    "drive_letter",
    "file_number",
    "folder_number",
    "free_space",
    "type",
    NULL
};

/***
 Creates a @{directory} object that is used to get information about a directory
 
 This function does not actually create a directory on the file system, it just creates
 an object that represents a directory. To actually create the directory in the file system
 call directory:create()
 @usage
 local mydir = dryos.directory("mydir")
 if mydir.exists == false then
    mydir:create()
 end
 for i,v in ipairs(mydir:files()) do 
    print("filename: "..v)
 end
 @tparam string path
 @treturn directory
 @function directory
 */
static int luaCB_dryos_directory(lua_State * L)
{
    LUA_PARAM_STRING(path, 1);
    lua_newtable(L);
    if (strlen(path) == 0 || !strcmp(path, "/"))
    {
        struct card_info * ml_card = get_ml_card();
        if (ml_card == NULL) return luaL_error(L, "Could not get ML card");
        lua_pushfstring(L, "%s:/", ml_card->drive_letter);
    }
    else if (path[strlen(path) - 1] != '/')
    {
        lua_pushfstring(L, "%s/", path);
    }
    else
    {
        lua_pushvalue(L, 1);
    }
    lua_setfield(L, -2, "path");
    lua_newtable(L);
    lua_pushcfunction(L, luaCB_directory_index);
    lua_setfield(L, -2, "__index");
    lua_pushcfunction(L, luaCB_directory_newindex);
    lua_setfield(L, -2, "__newindex");
    lua_pushcfunction(L, luaCB_pairs);
    lua_setfield(L, -2, "__pairs");
    lua_pushlightuserdata(L, lua_dryos_directory_fields);
    lua_setfield(L, -2, "fields");
    lua_setmetatable(L, -2);
    return 1;
}

/***
 Deletes a file from the card.
 @tparam string filename
 @treturn bool success
 @function remove
 */
static int luaCB_dryos_remove(lua_State * L)
{
    LUA_PARAM_STRING(filename, 1);
    lua_pushboolean(L, FIO_RemoveFile(filename) == 0);
    return 1;
}

static void setfield (lua_State *L, const char *key, int value) {
    lua_pushinteger(L, value);
    lua_setfield(L, -2, key);
}

static void setboolfield (lua_State *L, const char *key, int value) {
    if (value < 0)  /* undefined? */
        return;  /* does not set field */
    lua_pushboolean(L, value);
    lua_setfield(L, -2, key);
}

static int luaCB_dryos_index(lua_State * L)
{
    LUA_PARAM_STRING_OPTIONAL(key, 2, "");
    /// Get the value of the seconds clock
    // @tfield int clock
    if(!strcmp(key, "clock")) lua_pushinteger(L, get_seconds_clock());
    /// Get the value of the milliseconds clock
    // @tfield int ms_clock
    else if(!strcmp(key, "ms_clock")) lua_pushinteger(L, get_ms_clock_value());
    /// Get/Set the image filename prefix
    // @tfield string prefix
    else if(!strcmp(key, "prefix")) lua_pushstring(L, get_file_prefix());
    /// Get the DCIM directory
    // @tfield directory dcim_dir
    else if(!strcmp(key, "dcim_dir"))
    {
        lua_pushcfunction(L, luaCB_dryos_directory);
        lua_pushstring(L, get_dcim_dir());
        lua_call(L, 1, 1);
    }
    /// Get the ML config directory
    // @tfield directory config_dir
    else if(!strcmp(key, "config_dir"))
    {
        lua_pushcfunction(L, luaCB_dryos_directory);
        lua_pushstring(L, get_config_dir());
        lua_call(L, 1, 1);
    }
    /// Get the card ML started from
    // @tfield card ml_card
    else if(!strcmp(key, "ml_card"))
    {
        lua_newtable(L);
        struct card_info * card = get_ml_card();
        if(!card) return luaL_error(L, "Error getting ml_card");
        lua_pushlightuserdata(L, card);
        lua_setfield(L, -2, "_card_ptr");
        lua_pushfstring(L, "%s:/", card->drive_letter);
        lua_setfield(L, -2, "path");
        lua_newtable(L);
        lua_pushcfunction(L, luaCB_card_index);
        lua_setfield(L, -2, "__index");
        lua_pushcfunction(L, luaCB_card_newindex);
        lua_setfield(L, -2, "__newindex");
        lua_pushcfunction(L, luaCB_pairs);
        lua_setfield(L, -2, "__pairs");
        lua_pushlightuserdata(L, lua_dryos_card_fields);
        lua_setfield(L, -2, "fields");
        lua_setmetatable(L, -2);
    }
    /// Get the shooting card
    // @tfield card shooting_card
    else if(!strcmp(key, "shooting_card"))
    {
        lua_newtable(L);
        struct card_info * card = get_shooting_card();
        if(!card) return luaL_error(L, "Error getting shooting_card");
        lua_pushlightuserdata(L, card);
        lua_setfield(L, -2, "_card_ptr");
        lua_pushfstring(L, "%s:/", card->drive_letter);
        lua_setfield(L, -2, "path");
        lua_newtable(L);
        lua_pushcfunction(L, luaCB_card_index);
        lua_setfield(L, -2, "__index");
        lua_pushcfunction(L, luaCB_card_newindex);
        lua_setfield(L, -2, "__newindex");
        lua_pushcfunction(L, luaCB_pairs);
        lua_setfield(L, -2, "__pairs");
        lua_pushlightuserdata(L, lua_dryos_card_fields);
        lua_setfield(L, -2, "fields");
        lua_setmetatable(L, -2);
    }
    /// Gets a table representing the current date/time
    // @tfield date date
    else if(!strcmp(key, "date"))
    {
        /// Represents a date/time
        // @type date
        struct tm tm;
        LoadCalendarFromRTC(&tm);
        lua_newtable(L);
        /// Second
        // @tfield int sec
        setfield(L, "sec", tm.tm_sec);
        /// Minute
        // @tfield int min
        setfield(L, "min", tm.tm_min);
        /// Hour
        // @tfield int hour
        setfield(L, "hour", tm.tm_hour);
        /// Day
        // @tfield int day
        setfield(L, "day", tm.tm_mday);
        /// Month
        // @tfield int month
        setfield(L, "month", tm.tm_mon+1);
        /// Year
        // @tfield int year
        setfield(L, "year", tm.tm_year+1900);
        /// Day of week
        // @tfield int wday
        setfield(L, "wday", tm.tm_wday+1);
        /// Day of year
        // @tfield int yday
        setfield(L, "yday", tm.tm_yday+1);
        /// Daylight Savings
        // @tfield bool isdst
        setboolfield(L, "isdst", tm.tm_isdst);
    }
    else lua_rawget(L, 1);
    return 1;
}

static int luaCB_dryos_newindex(lua_State * L)
{
    LUA_PARAM_STRING_OPTIONAL(key, 2, "");
    if(!strcmp(key, "clock") || !strcmp(key, "ms_clock") || !strcmp(key, "date") || !strcmp(key, "ml_card") || !strcmp(key, "dcim_dir"))
    {
        return luaL_error(L, "'%s' is readonly!", key);
    }
    else if(!strcmp(key, "prefix"))
    {
        static char prefix[8];
        LUA_PARAM_STRING(new_prefix, 3);
        strncpy(prefix, new_prefix, 7);
        file_prefix_set(prefix);
    }
    else
    {
        lua_rawset(L, 1);
    }
    return 0;
}

/// Represents a directory
// @type directory

/***
 Creates a directory
 @treturn bool whether or not the directory was sucessfully created
 @function create
 */
static int luaCB_directory_create(lua_State * L)
{
    if(!lua_istable(L, 1)) return luaL_argerror(L, 1, "expected table");
    lua_getfield(L, 1, "path");
    const char * path = lua_tostring(L, -1);
    lua_pushinteger(L, FIO_CreateDirectory(path));
    return 1;
}

/***
 Get a table (of @{directory} objects) containing this directory's child directories
 @treturn {directory,...}
 @function children
 */
static int luaCB_directory_children(lua_State * L)
{
    if(!lua_istable(L, 1)) return luaL_argerror(L, 1, "expected table");
    if(lua_getfield(L, 1, "path") != LUA_TSTRING) return luaL_error(L, "invalid directory path");
    const char * path = lua_tostring(L, -1);
    struct fio_file file;
    struct fio_dirent * dirent = FIO_FindFirstEx(path, &file);
    int index = 1;
    if(!IS_ERROR(dirent))
    {
        lua_newtable(L);
        do
        {
            if (file.mode & ATTR_DIRECTORY)
            {
                //call the directory constructor
                lua_pushcfunction(L, luaCB_dryos_directory);
                lua_pushfstring(L, "%s%s/", path, file.name);
                lua_call(L, 1, 1);
                lua_seti(L, -2, index++);
            }
        }
        while(FIO_FindNextEx(dirent, &file) == 0);
        FIO_FindClose(dirent);
    }
    else
    {
        return luaL_error(L, "error reading directory '%s'", path);
    }
    
    return 1;
}

/***
 Get a table (of @{string}s) that are the file names of this directory's files
 @treturn {string,...}
 @function files
 */
static int luaCB_directory_files(lua_State * L)
{
    if(!lua_istable(L, 1)) return luaL_argerror(L, 1, "expected table");
    if(lua_getfield(L, 1, "path") != LUA_TSTRING) return luaL_error(L, "invalid directory path");
    const char * path = lua_tostring(L, -1);
    struct fio_file file;
    struct fio_dirent * dirent = FIO_FindFirstEx(path, &file);
    int index = 1;
    if(!IS_ERROR(dirent))
    {
        lua_newtable(L);
        do
        {
            if (!(file.mode & ATTR_DIRECTORY))
            {
                lua_pushfstring(L, "%s%s", path, file.name);
                lua_seti(L, -2, index++);
            }
        }
        while(FIO_FindNextEx(dirent, &file) == 0);
        FIO_FindClose(dirent);
    }
    else
    {
        return luaL_error(L, "error reading directory: '%s'", path);
    }
    
    return 1;
}

static int luaCB_directory_index(lua_State * L)
{
    if(!lua_istable(L, 1)) return luaL_argerror(L, 1, "expected table");
    LUA_PARAM_STRING_OPTIONAL(key, 2, "");
    /// Get the full path of the directory
    // @tfield string path
    if(!strcmp(key, "path")) return lua_rawget(L, 1);
    
    if(lua_getfield(L, 1, "path") != LUA_TSTRING) return luaL_error(L, "invalid directory path");
    const char * path = lua_tostring(L, -1);
    lua_pop(L, 1);
    /// Get whether or not the directory exists
    // @tfield bool exists
    if(!strcmp(key, "exists")) lua_pushboolean(L, is_dir(path));
    else if(!strcmp(key, "create")) lua_pushcfunction(L, luaCB_directory_create);
    else if(!strcmp(key, "children")) lua_pushcfunction(L, luaCB_directory_children);
    else if(!strcmp(key, "files")) lua_pushcfunction(L, luaCB_directory_files);
    /// Get a @{directory} object that represents the current directory's parent
    // @tfield directory parent
    else if(!strcmp(key, "parent"))
    {
        size_t len = strlen(path);
        if ((len > 3 || ((len == 2 || len == 3) && path[1] != ':')) && path[len - 1] == '/')
        {
            char * parent_path = copy_string(path);
            parent_path[len - 1] = 0x0;
            char * last = strrchr(parent_path, '/');
            if (last) *(last + 1) = 0x0;
            else parent_path[0] = 0x0;
            
            //call the directory constructor
            lua_pushcfunction(L, luaCB_dryos_directory);
            lua_pushstring(L, parent_path);
            lua_call(L, 1, 1);
            free(parent_path);
            return 1;
        }
        else
        {
            return 0;
        }
        
    }
    else lua_rawget(L, 1);
    return 1;
}

static int luaCB_directory_newindex(lua_State * L)
{
    return luaL_error(L, "'directory' type is readonly");
}

/// Represents a card (storage media)
// Inherits from @{directory}
// @type card

static int luaCB_card_index(lua_State * L)
{
    if(!lua_istable(L, 1)) return luaL_argerror(L, 1, "expected table");
    LUA_PARAM_STRING_OPTIONAL(key, 2, "");
    if(lua_getfield(L, 1, "_card_ptr") == LUA_TLIGHTUSERDATA)
    {
        struct card_info * card = lua_touserdata(L, -1);
        /// Get the cluster size
        // @tfield int cluster_size
        if(!strcmp(key, "cluster_size")) lua_pushinteger(L, card->cluster_size);
        /// Get the drive letter
        // @tfield string drive_letter
        else if(!strcmp(key, "drive_letter")) lua_pushstring(L, card->drive_letter);
        /// Get the current Canon file number
        // @tfield int file_number
        else if(!strcmp(key, "file_number")) lua_pushinteger(L, card->file_number);
        /// Get the current Canon folder number
        // @tfield int folder_number
        else if(!strcmp(key, "folder_number")) lua_pushinteger(L, card->folder_number);
        /// Get the current free space (in MiB)
        // @tfield int free_space
        else if(!strcmp(key, "free_space")) lua_pushinteger(L, get_free_space_32k(card) * 1024 / 32);
        /// Get the type of card
        // @tfield string type
        else if(!strcmp(key, "type")) lua_pushstring(L, card->type);
        else return luaCB_directory_index(L);
    }
    else
    {
        return luaL_error(L, "could not get lightuserdata for card");
    }
    return 1;
}
static int luaCB_card_newindex(lua_State * L)
{
    return luaL_error(L, "'card' type is readonly");
}

static const char * lua_dryos_fields[] =
{
    "clock",
    "ms_clock",
    "prefix",
    "dcim_dir",
    "config_dir",
    "ml_card",
    "shooting_card",
    "date",
    NULL
};

const luaL_Reg dryoslib[] =
{
    {"call", luaCB_dryos_call},
    {"directory", luaCB_dryos_directory},
    {"remove", luaCB_dryos_remove},
    {NULL, NULL}
};

LUA_LIB(dryos)
back to top