2

I am currently developing an application for my ESP32 for which I need to use the Lua-C-API. My goal would be to call a Lua function named "add" from C and flash the program on the ESP32.

So, in the Lua code ("add.lua") I define function "add":

    -- add two numbers
    function add ( x, y )
    return x + y
    end    

My C code for calling the interface is the following:

/* Function luaadd */
int luaadd (lua_State* L, int x, int y ) {

    int sum;

    /* the function name */
    lua_getglobal(L, "add");

    /* the first argument */
    lua_pushnumber(L, x);

    /* the second argument */
    lua_pushnumber(L, y);

    /* call the function with 2 arguments, return 1 result */
    lua_call(L, 2, 1);

    /* get the result */
    sum = (int)lua_tointeger(L, -1);
    lua_pop(L, 1);
    return sum;
    }

    /* Main function */
    void app_main()
    {
       initialize_nvs();
       #if CONFIG_STORE_HISTORY
           initialize_filesystem();
       #endif
       initialize_console();

       /* initialize Lua */
       lua_State* L = luaL_newstate();
       luaL_openlibs(L);
       openlibs(L);
       luaopen_base(L);            /* opens the basic library */
       luaopen_table(L);            /* opens the table library */
       luaopen_io(L);               /* opens the I/O library */
       luaopen_string(L);           /* opens the string lib. */
       luaopen_math(L);             /* opens the math lib. */

       /* load Lua file */
       if (luaL_loadfile(L, "add.lua")){
           printf("Error loading file: %s", lua_tostring(L, -1));
       }

       /* call the add function */
       int sum;
       sum = luaadd(L, 10, 15 );

       /* print the result */
       printf( "The sum is %d\n", sum );

       /* cleanup Lua */
       lua_close(L);

       /* print 'Finished' to console */
       printf("Finished");
   }

And this is the entire C file:

    #include <modules.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdarg.h>
    #include <string.h>
    #include "esp_system.h"
    #include "esp_log.h"
    #include "esp_console.h"
    #include "esp_vfs_dev.h"
    #include "driver/uart.h"
    #include "linenoise/linenoise.h"
    #include "argtable3/argtable3.h"
    #include "esp_vfs_fat.h"
    #include "nvs.h"
    #include "nvs_flash.h"
    #include "lua.h"
    #include "lauxlib.h"
    #include "lualib.h"
    #include "sb.h"
    #include <unistd.h>
    #include <errno.h>
    #include <unistd.h>

    static const char* TAG = "Console";

    /* Console command history can be stored to and loaded from a file.
     * The easiest way to do this is to use FATFS filesystem on top of
     * wear_levelling library.
     */
    #if CONFIG_STORE_HISTORY

    #define MOUNT_PATH "/data"
    #define HISTORY_PATH MOUNT_PATH "/history.txt"

    static void initialize_filesystem()
    {
        static wl_handle_t wl_handle;
        const esp_vfs_fat_mount_config_t mount_config = {
                .max_files = 4,
                .format_if_mount_failed = true
        };
        esp_err_t err = esp_vfs_fat_spiflash_mount(MOUNT_PATH,         "storage", &mount_config, &wl_handle);
        if (err != ESP_OK) {
            ESP_LOGE(TAG, "Failed to mount FATFS (0x%x)", err);
            return;
        }
    }
    #endif // CONFIG_STORE_HISTORY

    static void initialize_nvs()
    {
        esp_err_t err = nvs_flash_init();
        if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
            ESP_ERROR_CHECK( nvs_flash_erase() );
            err = nvs_flash_init();
        }
        ESP_ERROR_CHECK(err);
    }

    static void initialize_console()
    {
        /* Disable buffering on stdin and stdout */
        setvbuf(stdin, NULL, _IONBF, 0);
        setvbuf(stdout, NULL, _IONBF, 0);

        /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
        esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
        /* Move the caret to the beginning of the next line on '\n' */
        esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);

        /* Install UART driver for interrupt-driven reads and writes */
        ESP_ERROR_CHECK( uart_driver_install(CONFIG_CONSOLE_UART_NUM,
        256, 0, 0, NULL, 0) );

        /* Tell VFS to use UART driver */
        esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM);

        /* Initialize the console */
        esp_console_config_t console_config = {
                .max_cmdline_args = 8,
                .max_cmdline_length = 256,
                #if CONFIG_LOG_COLORS
                    .hint_color = atoi(LOG_COLOR_CYAN)
                #endif
                };
        ESP_ERROR_CHECK( esp_console_init(&console_config) );

        /* Configure linenoise line completion library */
        /* Enable multiline editing. If not set, long commands will scroll within
         * single line.
         */
        linenoiseSetMultiLine(1);

        /* Tell linenoise where to get command completions and hints */
        linenoiseSetCompletionCallback(&esp_console_get_completion);
        linenoiseSetHintsCallback((linenoiseHintsCallback*)  &esp_console_get_hint);

        /* Set command history size */
        linenoiseHistorySetMaxLen(100);

        #if CONFIG_STORE_HISTORY
            /* Load command history from filesystem */
            linenoiseHistoryLoad(HISTORY_PATH);
        #endif
    }

    int luaadd (lua_State* L, int x, int y )
    {
        int sum;

        /* the function name */
        lua_getglobal(L, "add");

        /* the first argument */
        lua_pushnumber(L, x);

        /* the second argument */
        lua_pushnumber(L, y);

        /* call the function with 2 arguments, return 1 result */
        lua_call(L, 2, 1);

        /* get the result */
        sum = (int)lua_tointeger(L, -1);
        lua_pop(L, 1);

        return sum;
    }

    void app_main()
    {
       initialize_nvs();
       #if CONFIG_STORE_HISTORY
           initialize_filesystem();
       #endif
       initialize_console();

       /* initialize Lua */
       lua_State* L = luaL_newstate();
       luaL_openlibs(L);
       openlibs(L);
       luaopen_base(L);            /* opens the basic library */
       luaopen_table(L);            /* opens the table library */
       luaopen_io(L);               /* opens the I/O library */
       luaopen_string(L);           /* opens the string lib. */
       luaopen_math(L);             /* opens the math lib. */

       /* load Lua file */
       if (luaL_loadfile(L, "add.lua")){
           printf("Error loading file: %s", lua_tostring(L, -1));
       }

       /* call the add function */
       int sum;
       sum = luaadd(L, 10, 15 );

       /* print the result */
       printf( "The sum is %d\n", sum );

       /* cleanup Lua */
       lua_close(L);

       /* print 'Finished' to console */
       printf("Finished");
   }

When I now flash this onto my ESP32 I get the following message:

Error loading file: cannot open add.lua: No such file or directoryPANIC: unprotected error in call to Lua API (attempt to call a nil value) abort() was called at PC 0x4016b808 on core 0

Do you know how to solve the problem? My "add.lua" file is in the same directory as the C file.

letsintegreat
  • 3,328
  • 4
  • 18
  • 39
777
  • 31
  • 4

2 Answers2

1

As stated in this post, you need ./add.lua to load your file from the current directory. You can also try with an absolute path.

piarston
  • 1,685
  • 1
  • 13
  • 25
  • Thanks a lot for your help! However, using an absolute path as well as "./add.lua" did not help in my case. – 777 May 10 '18 at 10:21
  • Have you already looked at https://askubuntu.com/questions/133389/no-such-file-or-directory-but-the-file-exists ? Maybe it can help? – piarston May 10 '18 at 11:48
1

luaL_loadfile only loads the file but does not execute its contents. The function add is only defined when the file is executed. Use luaL_dofile to load and execute a file.

lhf
  • 70,581
  • 9
  • 108
  • 149
  • Thank you. I tried luaL_dofile. However, this won't work because the file "add.lua" cannot be found (nevertheless executed) at all. – 777 May 10 '18 at 11:06