mirror of
https://github.com/elua/elua.git
synced 2025-01-25 01:02:54 +08:00
Updated the interrupt model in Lua, now it looks exactly the same as the C one (one interrupt handler per interrupt ID, setting an interrupt handler returns the previous one so they can be chained). Documentation and interrupt sample updated to reflect this. Also, building.html is now building.txt (AsciiDoc). Be patient while it is processed :)
This commit is contained in:
parent
253cb702a7
commit
7aff94d194
@ -134,12 +134,23 @@ This mechanism is also used to expose interrupt IDs to the CPU module, check @in
|
||||
ret = "$clock$ - the CPU clock (in Hertz)."
|
||||
},
|
||||
|
||||
{ sig = "#cpu.set_int_handler#( handler )",
|
||||
desc = "Sets the Lua interrupt handler to function *handler*. Only available if interrupt support is enabled, check @inthandlers.html@here@ for details.",
|
||||
args = "$handler$ - the Lua interrupt handler function, or *nil* to disable the Lua interrupt handler feature."
|
||||
{ sig = "prev_handler = #cpu.set_int_handler#( id, handler )",
|
||||
desc = "Sets the Lua interrupt handler for interrupt *id* to function *handler*. *handler* can be #nil# to disable the interrupt handler. Only available if interrupt support is enabled, check @inthandlers.html@here@ for details.",
|
||||
args =
|
||||
{
|
||||
"$id$ - the interrup ID.",
|
||||
"$handler$ - the Lua interrupt handler function, or *nil* to disable the Lua interrupt handler feature."
|
||||
},
|
||||
ret = "$prev_handler$ - the previous interrupt handler for interrupt *id*, or *nil* if an interrupt handler was not set for interrupt *id*."
|
||||
},
|
||||
|
||||
{ sig = "#cpu.get_int_flag#( id, resnum, [clear] )",
|
||||
{ sig = "handler = #cpu.get_int_handler#( id )",
|
||||
desc = "Returns the Lua interrupt handler for interrupt *id*",
|
||||
args = "$id$ - the interrup ID.",
|
||||
ret = "$handler$ - the interrupt handler for interrupt *id*, or *nil* if an interrupt handler is not set for interrupt *id*."
|
||||
},
|
||||
|
||||
{ sig = "#cpu.get_int_flag#( id, resnum, [clear] )",
|
||||
desc = "Get the interrupt pending flag of an interrupt ID/resource ID combination, and optionally clear the pending flag. Only available if interrupt support is enabled, check @inthandlers.html@here@ for details.",
|
||||
args =
|
||||
{
|
||||
|
@ -1,420 +0,0 @@
|
||||
$$HEADER$$
|
||||
<h3>Building eLua</h3>
|
||||
<p>If you decide to build your own <b>eLua</b> binary image (instead of <a href="downloads.html">downloading
|
||||
one</a>) you need to download the source code (see <a href="downloads.html#source">here</a> for details) and follow the
|
||||
platform specific eLua build instructions (provided for <a href="building_unix.html">Linux</a> and <a href="building_win.html">Windows</a>) to setup your build environment.
|
||||
Then follow the instructions below to build your eLua binary image.</p>
|
||||
<a name="configuring" /><h3>Configuring the build image</h3>
|
||||
<p><b>eLua</b> has a very flexible build system that
|
||||
can be used to select the components that are going to be part of the <b>eLua</b>
|
||||
binary image and to set the compile time (static) configuration.
|
||||
To use it, you need to edit a single configuration file (<i>platform_conf.h</i>)
|
||||
located in the platform specific directory (<i>src/platform/<platform
|
||||
name>/platform_conf.h)</i>. The configuration parameters
|
||||
are described in detail in the next paragraphs.</p>
|
||||
<a name="components"><h2>Configuring components</h2></a>
|
||||
<p>An <b>eLua component</b> is a feature that can be
|
||||
enabled to add functionality to <b>eLua</b> itself,
|
||||
without modifying its API (which is the part that the programmer uses
|
||||
to write <b>eLua</b> programs). An example of component configuration from
|
||||
<i>platform_conf.h</i> is given below:</p>
|
||||
<pre><code>// *****************************************************************************
|
||||
// Define here what components you want for this platform
|
||||
|
||||
#define BUILD_XMODEM
|
||||
#define BUILD_SHELL
|
||||
#define BUILD_ROMFS
|
||||
#define BUILD_MMCFS
|
||||
#define BUILD_TERM
|
||||
#define BUILD_UIP
|
||||
#define BUILD_DHCPC
|
||||
#define BUILD_DNS
|
||||
#define BUILD_CON_GENERIC
|
||||
#define BUILD_ADC
|
||||
#define BUILD_RPC</code></pre>
|
||||
<p>The components that can be configured in <b>eLua</b> are:</p>
|
||||
<table class="table_center">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th style="text-align: left;">Name</th>
|
||||
<th style="text-align: center;">Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">BUILD_XMODEM</td>
|
||||
<td>Define this to build support for XMODEM receive. If
|
||||
enabled, you can use the "recv" command from the shell to receive a Lua
|
||||
file (either source code or precompiled byte code) and run in on the
|
||||
target. Works only over RS-232 connections (although in theory it's
|
||||
possible to make it work over any kind of transport).
|
||||
To enable:
|
||||
<pre><code>#define BUILD_XMODEM</code></pre>
|
||||
<a href="building.html#static">Static configuration data dependencies:</a> <b>CON_UART_ID, CON_UART_SPEED, CON_TIMER_ID</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">BUILD_SHELL</td>
|
||||
<td>This build the <b>eLua</b> shell (see <a href="using.html">using eLua</a> for details on the
|
||||
shell). If the shell is not enabled, the code looks for a file called <i>/rom/autorun.lua</i>
|
||||
and executes it. If this file is not found, a regular Lua intepreter is
|
||||
started on the target.<br>
|
||||
To enable the shell over a serial connection:
|
||||
<pre><code>#define BUILD_SHELL
|
||||
#define BUILD_CON_GENERIC</code></pre>
|
||||
To enable the shell over a TCP/IP connection:
|
||||
<pre><code>#define BUILD_SHELL
|
||||
#define BUILD_CON_TCP</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">BUILD_ROMFS</td>
|
||||
<td>Enable the <b>eLua</b> read-only
|
||||
filesystem. See the <a href="arch_romfs.html">ROMFS
|
||||
documentation</a> for details about using the ROM file system.
|
||||
To enable:
|
||||
<pre><code>#define BUILD_ROMFS</code></pre></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">BUILD_MMCFS</td>
|
||||
<td>Enable the <b>eLua</b> SD/MMC FAT
|
||||
filesystem support.
|
||||
To enable:
|
||||
<pre><code>#define BUILD_MMCFS</code></pre>
|
||||
<a href="building.html#static">Static configuration data dependencies:</a> <b>MMCFS_TICK_HZ, MMCFS_TICK_MS, MMCFS_CS_PORT, MMCFS_CS_PIN, MMCFS_SPI_NUM</b></td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">BUILD_TERM</td>
|
||||
<td>Enable ANSI terminal support. It allows <b>eLua</b>
|
||||
to interact with terminals that support ANSI escape sequences (more details <a href="arch_con_term.html">here</a>).
|
||||
Currently it works only over RS-232 connections, although this is not a
|
||||
strict requirement. You need to enable this if you want to use the <a href="refman_gen_term.html">term module</a>.
|
||||
To enable:
|
||||
<pre><code>#define BUILD_TERM</code></pre>
|
||||
<a href="building.html#static">Static configuration data dependencies:</a> <b>CON_UART_ID, CON_UART_SPEED, CON_TIMER_ID, TERM_LINES, TERM_COLS</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">BUILD_UIP</td>
|
||||
<td>Enable TCP/IP networking support. You need to enable
|
||||
this if you want to use the <a href="refman_gen_net.html">net
|
||||
module</a>. Also, your platform must implement the uIP support
|
||||
functions (see the <a href="arch_platform.html">platform
|
||||
interface</a> documentation for details).
|
||||
To enable:
|
||||
<pre><code>#define BUILD_UIP</code></pre>
|
||||
<a href="building.html#static">Static configuration data dependencies:</a> <b>ELUA_CONF_IPADDR0..3, ELUA_CONF_NETMASK0..3, ELUA_CONF_DEFGW0..3,
|
||||
ELUA_CONF_DNS0..3</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">BUILD_DHCPC</td>
|
||||
<td>If BUILD_UIP is enabled, you can enable this to include
|
||||
a DHCP client in the TCP/IP networking subsystem.
|
||||
To enable:
|
||||
<pre><code>#define BUILD_UIP
|
||||
#define BUILD_DHCPC</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">BUILD_DNS</td>
|
||||
<td>If BUILD_UIP is enabled, you can enable this to include
|
||||
a minimal DNS resolver in the TCP/IP networking subsystem.
|
||||
To enable:
|
||||
<pre><code>#define BUILD_UIP
|
||||
#define BUILD_DNS</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">BUILD_CON_GENERIC</td>
|
||||
<td>Generic console support (details <a href="arch_con_term.html">here</a>). Enables console access
|
||||
(stdio/stdout/stderr) via a serial transport (currently RS-232, but
|
||||
others can be supported). Enable this if you want to use console
|
||||
input/output over your RS-232 connection. Don't enable this if you need
|
||||
console input/ouput over Ethernet (see the next option).
|
||||
To enable:
|
||||
<pre><code>#define BUILD_CON_GENERIC</code></pre>
|
||||
<a href="building.html#static">Static configuration data dependencies:</a> <b>CON_UART_ID, CON_UART_SPEED, CON_TIMER_ID</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">BUILD_CON_TCP</td>
|
||||
<td>Console input/output over TCP/IP connections only (details <a href="arch_con_term.html">here</a>). Use
|
||||
this if you want to use your <b>eLua</b> board over a
|
||||
telnet session. Don't enable this if you need console input/output over
|
||||
serial transports (see the previous option).
|
||||
To enable:
|
||||
<pre><code>#define BUILD_UIP
|
||||
#define BUILD_CON_TCP</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">BUILD_ADC</td>
|
||||
<td>Define this to build support for ADC peripherals. This must be enabled to use the <a href="refman_gen_adc.html">adc module</a>, or the <a href="arch_platform_adc.html">adc platform interface</a>.
|
||||
To enable:
|
||||
<pre><code>#define BUILD_ADC</code></pre>
|
||||
<a href="building.html#static">Static configuration data dependencies:</a> <b>ADC_BIT_RESOLUTION, ADC_TIMER_FIRST_ID, ADC_NUM_TIMERS, BUF_ENABLE_ADC, ADC_BUF_SIZE</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">BUILD_RPC</td>
|
||||
<td>Define this to build support for LuaRPC. This must be enabled to use the <a href="refman_gen_rpc.html">rpc module</a>.
|
||||
To enable:
|
||||
<pre><code>#define BUILD_RPC</code></pre>
|
||||
<a href="building.html#static">Static configuration data dependencies</a> (ONLY if built with boot=luarpc): <b>RPC_UART_ID, RPC_TIMER_ID</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<a name="confmodules"><h2>Configuring modules</h2></a>
|
||||
<p>You can also choose the modules that are going to be part of
|
||||
the <b>eLua</b> image. Unlike components, the modules have
|
||||
a direct impact on the <b>eLua</b> API, so choose them
|
||||
carefully. Disabling a module will save Flash space (and potentially
|
||||
RAM) but will also completely remove the possibility of using that
|
||||
module from <b>eLua</b>.</p>
|
||||
<p>The modules included in the build are specified by the
|
||||
LUA_PLATFORM_LIBS_ROM macro. An example is given below: </p>
|
||||
<pre><code>#define LUA_PLATFORM_LIBS_ROM\
|
||||
_ROM( AUXLIB_PIO, luaopen_pio, pio_map )\
|
||||
_ROM( AUXLIB_TMR, luaopen_tmr, tmr_map )\
|
||||
_ROM( AUXLIB_PD, luaopen_pd, pd_map )\
|
||||
_ROM( AUXLIB_UART, luaopen_uart, uart_map )\
|
||||
_ROM( AUXLIB_TERM, luaopen_term, term_map )\
|
||||
_ROM( AUXLIB_PWM, luaopen_pwm, pwm_map )\
|
||||
_ROM( AUXLIB_PACK, luaopen_pack, pack_map )\
|
||||
_ROM( AUXLIB_BIT, luaopen_bit, bit_map )\
|
||||
_ROM( AUXLIB_CPU, luaopen_cpu, cpu_map )\
|
||||
ROM( LUA_MATHLIBNAME, luaopen_math, math_map )</code></pre>
|
||||
<p>Each module is defined by a <b>_ROM( module_name,
|
||||
module_init_function, module_map_array )</b> macro, where:
|
||||
</p>
|
||||
<ul>
|
||||
<li><b>module_name</b> is the name by which the
|
||||
module can be used from Lua</li>
|
||||
<li><b>module_init_function</b> is a function
|
||||
called by the Lua runtime when the module is initialized</li>
|
||||
<li><b>module_map_array</b> is a list of all the
|
||||
functions and constants exported by a module</li>
|
||||
</ul>
|
||||
<p>Please note that this notation is specific to LTR (the <b>L</b>ua
|
||||
<b>T</b>iny <b>R</b>AM patch) and it's not the
|
||||
only way to specify the list of modules included in the build (although
|
||||
it is the most common one). Check the <a href="arch_ltr.html#config">LTR
|
||||
section</a> for more information about LTR.</p>
|
||||
<p>For the full list of modules that can be enabled or disabled
|
||||
via <i>platform_conf.h</i> check <a href="refman_gen.html">the
|
||||
eLua reference manual</a>.</p>
|
||||
<a name="static"><h2>Static configuration data</h2></a>
|
||||
<p>"Static configuration" refers to the compile-time
|
||||
configuration. Static configuration parameters are hard-coded in the
|
||||
firmware image and can't be changed at run-time. The table below lists
|
||||
the static configuration parameters and their semantics.
|
||||
</p>
|
||||
<table class="table_center">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th style="text-align: left;">Name</th>
|
||||
<th style="text-align: center;">Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">CON_UART_ID<br>CON_UART_SPEED<br>CON_TIMER_ID<br></td>
|
||||
<td>Used to configure console input/output over UART. The
|
||||
specified UART id will be used for console input/output, at the
|
||||
specified speed. The data format is always 8N1 (8 data bits, no parity,
|
||||
1 stop bits) at this point. The specified timer ID will be used for the console subsystem. These
|
||||
variables are also used by the XMODEM and TERM implementations.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">TERM_LINES<br>TERM_COLS<br>
|
||||
</td>
|
||||
<td>Used to configure the ANSI terminal support (if enabled
|
||||
in the build). Used to specify (respectively) the number of lines and
|
||||
columns of the ANSI terminal.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">ELUA_CONF_IPADDR0..3<br>
|
||||
ELUA_CONF_NETMASK0..3<br>
|
||||
ELUA_CONF_DEFGW0..3<br>
|
||||
ELUA_CONF_DNS0..3</td>
|
||||
<td>Used by the TCP/IP implementation when the DHCP client
|
||||
is not enabled, or when it is enabled but can't be contacted. Specifies
|
||||
the IP address, network mask, default gateway and DNS server. Only
|
||||
needed if BUILD_UIP is enabled.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">VTMR_NUM_TIMERS<br>
|
||||
VTMR_FREQ_HZ</td>
|
||||
<td>Specify the virtual timers configuration for the
|
||||
platform (refer to <a href="refman_gen_tmr.html">the timer module
|
||||
documentation</a> for details). Define VTMR_NUM_TIMERS to 0 if
|
||||
this feature is not used.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">MMCFS_TICK_HZ<br>
|
||||
MMCFS_TICK_MS</td>
|
||||
<td>Specify the rate at which SD/MMC timer function <i>disk_timerproc()</i> are being called by the platform. On most platforms MMCFS_TICK_HZ will match VTMR_FREQ_HZ. Only needed if MMCFS support is enabled.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">MMCFS_CS_PORT<br>
|
||||
MMCFS_CS_PIN</td>
|
||||
<td>Specify the port and pin to be used as chip select for MMCFS control of an SD/MMC card over SPI. Only needed if MMCFS support is enabled.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">MMCFS_SPI_NUM</td>
|
||||
<td>Specify the SPI peripheral to be used by MMCFS. Only needed if MMCFS support is enabled.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">PLATFORM_CPU_CONSTANTS</td>
|
||||
<td>If the <a href="refman_gen_cpu.html">cpu module</a>
|
||||
is enabled, this defines a list of platform-specific constants (for
|
||||
example interrupt masks) that can be accessed using the
|
||||
cpu.<constant name> notation. Each constant name must be
|
||||
specified instead of a specific costruct (<i>_C(<constant
|
||||
name></i>). For example:
|
||||
<pre><code>#define PLATFORM_CPU_CONSTANTS\<br> _C( INT_GPIOA ),\<br> _C( INT_GPIOB ),\<br> _C( INT_GPIOC ),\<br> _C( INT_GPIOD ),\<br> _C( INT_GPIOE )<br></code></pre>
|
||||
After compilation, you can access these constants using <i>cpu.INT_GPIOx</i>.
|
||||
Note that the implementation of this feature needs virtually no RAM at
|
||||
all, so you can define as many constants as you want here. </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">BUF_ENABLE_ADC</td>
|
||||
<td>If the <a href="refman_gen_adc.html">adc module</a> is enabled, this controls whether or not the ADC will create a buffer so that more than one sample per channel can be held in a buffer before being returned through adc.getsample or adc.getsamples. If disabled, only one conversion result will be buffered. This option does NOT affect the behavior of the moving average filter.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">ADC_BUF_SIZE</td>
|
||||
<td>If the <a href="refman_gen_adc.html">adc module</a> is enabled, and
|
||||
BUF_ENABLE_ADC is defined, this will define the default buffer length
|
||||
allocated at startup. This does not limit buffer sizes, it only defines the
|
||||
default length. Appropriate values range from BUF_SIZE_2 to BUF_SIZE_32768,
|
||||
with the numeric component at the end being in powers of 2.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">ADC_BIT_RESOLUTION
|
||||
</td>
|
||||
<td>If the <a href="refman_gen_adc.html">adc module</a> is enabled, this will
|
||||
define the number of bits per adc conversion result. This is used to determine
|
||||
the maximum conversion value that can be returned by the ADC.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">RPC_UART_ID
|
||||
</td>
|
||||
<td>If the <a href="refman_gen_rpc.html">rpc module</a> is enabled and boot mode is set to luarpc, this selects which uart luarpc will listen on for incoming client connections.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">RPC_TIMER_ID
|
||||
</td>
|
||||
<td>If the <a href="refman_gen_rpc.html">rpc module</a> is enabled and boot mode is set to luarpc, this selects which timer will be used with the uart selected with RPC_UART_ID.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: rgb(255, 102, 0);">EGC_INITIAL_MODE<br />EGC_INITIAL_MEMLIMIT</td>
|
||||
<td><b>(version 0.7 or above)</b> Configure the default (compile time) operation mode and memory limit of the emergency garbage collector (see <a href="elua_egc.html">here</a> for details
|
||||
about the EGC patch). If not specified, <b>EGC_INITIAL_MODE</b> defaults to <b>EGC_NOT_ACTIVE</b> (emergency garbage collector disabled) and <b>EGC_INITIAL_MEMLIMIT</b> defaults to 0.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The rest of the static configuration data parameters are meant
|
||||
to be modified mainly by developers and thus they're not listed here.<br>
|
||||
One more thing you might want to configure for your build is the
|
||||
contents of the ROM file system. See the <a href="arch_romfs.html">ROMFS
|
||||
documentation</a> for details on how to do this.</p>
|
||||
<a name="buildoptions" /><h3>Invoking the build system</h3>
|
||||
<p>Once you have everything in place, all you have to do is to
|
||||
invoke the build system (scons) with the right arguments. This is a
|
||||
fairly easy step, although it might look intimidating because of the
|
||||
multitude of options than can be given to scons. They are used to fine
|
||||
tune the final image to your specific needs, but unless your needs are
|
||||
very special you won't need to modify them, so don't worry about the
|
||||
aparent complexity. The examples at the end of this section will show
|
||||
how easy it is to use the build system in practice.
|
||||
</p>
|
||||
<pre><code>$ scons <br> [target=lua | lualong]<br> [cpu=at91sam7x256 | at91sam7x512 | i386 | str912fw44 | lm3s8962 | <br> lm3s6965 | lm3s6918 | lpc2888 | str711fr2 | at32uc3a0512 | stm32f103ze<br> [board=ek-lm3s8962 | ek-lm3s6965 | eagle-100 | str9-comstick | sam7-ex256 | <br> lpc-h2888 | mod711 | pc | atevk1100 | stm3210e-eval ]<br> [cpumode=arm | thumb] <br> [allocator = newlib | multiple | simple]<br> [toolchain = <toolchain name>]<br> [optram = 0 | 1]<br> [romfs = verbatim | compress | compile]<br> [prog]<br></code></pre>
|
||||
<p>Your build target is specified by two paramters: cpu and
|
||||
board. "cpu" gives the name of your CPU, and "board" the name of the
|
||||
board. A board can be associated with more than one CPU. This allows
|
||||
the build system to be very flexible. You can use these two options
|
||||
together or separately, as shown below:</p>
|
||||
<ul>
|
||||
<li><b>cpu=name</b>: build for the specified CPU. A
|
||||
board name will be assigned by the build system automatically.</li>
|
||||
<li><b>board=name</b>: build for the specified
|
||||
board. The CPU name will be inferred by the build system automatically.</li>
|
||||
<li><b>cpu=name board=name</b>: build for the
|
||||
specified board and CPU. The build script won't allow invalid CPU/board
|
||||
combinations.</li>
|
||||
</ul>
|
||||
<p>For board/CPU assignment look at the beginning of the
|
||||
SConstruct file (the <i>platform_list</i> array), it's
|
||||
self-explanatory.<br>
|
||||
The other options are as follows:</p>
|
||||
<ul>
|
||||
<li><b>target=lua | lualong</b>: specify if you
|
||||
want to build "regular" Lua (with floating point support) or integer
|
||||
only Lua (lualong). The default is "lua". "lualong" runs faster on
|
||||
targets that lack a floating point co-processor (which is the case for
|
||||
all current <b>eLua</b> targets) but it completely lacks
|
||||
support for floating point operations, it can only handle integers.</li>
|
||||
<li><b>cpumode=arm | thumb</b>: for ARM targets
|
||||
(not Cortex) this specifies the compilation mode. Its default value is
|
||||
'thumb' for AT91SAM7X targets and 'arm' for STR9 and LPC2888 targets.</li>
|
||||
<li><b>allocator = newlib | multiple | simple</b>:
|
||||
choose between the default newlib allocator (newlib) which is an older
|
||||
version of dlmalloc, the multiple memory spaces allocator (multiple)
|
||||
which is a newer version of dlmalloc that can handle multiple memory
|
||||
spaces, and a very simple memory allocator (simple) that is slow and
|
||||
doesn't handle fragmentation very well, but it requires very few
|
||||
resources (Flash/RAM). You should use the 'multiple' allocator only if
|
||||
you need to support multiple memory spaces. The default value is
|
||||
'newlib' for all CPUs except 'lpc2888' and 'at32uc3a0512', since the
|
||||
LPC-H2888 and ATEVK1100 board come with external SDRAM memory and thus
|
||||
are an ideal target for 'multiple'. You should use 'simple' only on
|
||||
very resource-constrained systems.
|
||||
</li>
|
||||
<li><b>toolchain=<toolchain name></b>:
|
||||
this specifies the name of the toolchain used to build the image. See <a href="toolchains.html#configuration">this link</a> for
|
||||
details.</li>
|
||||
<li><b>optram=0 | 1</b>: enables of disables the
|
||||
LTR patch, see the <a href="arch_ltr.html">LTR documentation</a>
|
||||
for more details. The default is 1, which enables the LTR patch.</li>
|
||||
<li><b>prog</b>: by default, the above 'scons'
|
||||
command will build only the 'elf' (executable) file. Specify "prog" to
|
||||
build also the platform-specific programming file where appropriate
|
||||
(for example, on a AT91SAM7X256 this results in a .bin file that can be
|
||||
programmed in the CPU). </li>
|
||||
<li><b>romfs = verbatim | compress | compile</b>: ROMFS compilation mode, check <a href="arch_romfs.html#mode">here</a> for details (<b>new in 0.7</b>).</li>
|
||||
<li><b>boot = standard | luarpc</b>: Boot mode. 'standard' will boot to either a shell or lua interactive prompt. 'luarpc' boots with a waiting rpc server, using a UART & timer as specified in <a href="building.html#static">static configuration data</a> (<b>new in 0.7</b>).</li>
|
||||
</ul>
|
||||
<p>The output will be a file named elua_<i>[target]</i>_<i>[cpu]</i>.elf
|
||||
(and also another file with the same name but ending in .bin/.hex if
|
||||
"prog" was specified for platforms that need these files for
|
||||
programming).<br>
|
||||
If you want the equivalent of a "make clean", invoke "scons" as shown
|
||||
above, but add a "-c" at the end of the command line. "scons -c" is
|
||||
also recommended after you reconfigure your build image, as scons seems
|
||||
to "overlook" the changes to these files on some occasions.</p>
|
||||
<p><b>A few examples:</b></p>
|
||||
<pre><code>$ scons cpu=at91sam7x256 -c <br></code></pre>
|
||||
<p>Clear previously built intermediate files.</p>
|
||||
<pre><code>$ scons cpu=at91sam7x256<br></code></pre>
|
||||
<p>Build eLua for the AT91SAM7X256 CPU. The board name is
|
||||
detected as sam7-ex256.</p>
|
||||
<pre><code>$ scons board=sam7-ex256<br></code></pre>
|
||||
<p>Build eLua for the SAM7-EX256 board. The CPU is detected as
|
||||
AT91SAM7X256.</p>
|
||||
<pre><code>$ scons board=sam7-ex256 cpu=at91sam7x512<br></code></pre>
|
||||
<p>Build eLua for the SAM7-EX256 board, but "overwrite" the
|
||||
default CPU. This is useful when you'd like to see how the specified
|
||||
board would behave (in terms of resources) with a different CPU (in the
|
||||
case of the SAM7-EX256 board it's possible to switch the on-board
|
||||
AT91SAM7X256 CPU for an AT91SAM7X512 which has the same pinout but
|
||||
comes with more Flash/RAM memory).</p>
|
||||
<pre><code>$ scons cpu=lpc2888 prog </code></pre>
|
||||
<p>Build eLua for the lpc2888 CPU. The board name is detected as
|
||||
LPC-H2888. Also,
|
||||
the bin file required for target programming is generated. The
|
||||
allocator is automatically detected as "multiple".</p>
|
||||
<pre><code>$ scons cpu=lm3s8962 toolchain=codesourcery prog</code></pre>
|
||||
<p>Build the image for the Cortex LM3S8962 CPU, but use the
|
||||
CodeSourcery toolchain instead of the default toolchain (which is a
|
||||
"generic" ARM GCC toolchain, usually the one built by following
|
||||
the tutorials from this site.</p>
|
||||
$$FOOTER$$
|
||||
|
344
doc/en/building.txt
Normal file
344
doc/en/building.txt
Normal file
@ -0,0 +1,344 @@
|
||||
// $$HEADER$$
|
||||
Building eLua
|
||||
-------------
|
||||
If you decide to build your own binary image (instead of link:downloads.html"[downloading one] you need to download the source code
|
||||
(see link:downloads.html#source[here] for details) and follow the platform specific eLua build instructions (provided for link:building_unix.html[Linux]
|
||||
and link:building_win.html[Windows]) to setup your build environment.
|
||||
|
||||
Then follow the instructions below to configure and build your eLua binary image.
|
||||
|
||||
[[configuring]]
|
||||
Configuring the build image
|
||||
---------------------------
|
||||
eLua has a very flexible build system that can be used to select the components that are going to be part of the eLua
|
||||
binary image and also to set the compile time (static) configuration. To use it, you need to edit a single configuration file
|
||||
(_platform_conf.h_) located in the platform specific directory (_src/platform/<platform_name>/platform_conf.h)_. The configuration
|
||||
parameters are described in detail in the next paragraphs.
|
||||
|
||||
[[components]]
|
||||
Configuring components
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
An eLua *component* is a feature that can be enabled to add functionality to eLua itself, without modifying its API. An example of
|
||||
component configuration from _platform_conf.h_ is given below:
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
// *****************************************************************************
|
||||
// Define here what components you want for this platform
|
||||
|
||||
#define BUILD_XMODEM
|
||||
#define BUILD_SHELL
|
||||
#define BUILD_ROMFS
|
||||
#define BUILD_MMCFS
|
||||
#define BUILD_TERM
|
||||
#define BUILD_UIP
|
||||
#define BUILD_DHCPC
|
||||
#define BUILD_DNS
|
||||
#define BUILD_CON_GENERIC
|
||||
#define BUILD_ADC
|
||||
#define BUILD_RPC
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
The components that can be configured in <b>eLua</b> are:
|
||||
|
||||
[width="100%", cols="<2,<9", options="header", style="asciidoc"]
|
||||
|===================================================================
|
||||
^|Name ^|Meaning
|
||||
o|BUILD_XMODEM |Define this to build support for XMODEM receive. If
|
||||
enabled, you can use the "recv" command from the shell to receive a Lua
|
||||
file (either source code or precompiled byte code) and run in on the
|
||||
target. Works only over RS-232 connections (although in theory it's
|
||||
possible to make it work over any kind of transport). To enable:
|
||||
|
||||
#define BUILD_XMODEM
|
||||
|
||||
link:#static[Static configuration data dependencies]: **CON_UART_ID, CON_UART_SPEED, CON_TIMER_ID**
|
||||
|
||||
o|BUILD_SHELL |This builds the eLua shell (see link:using.html[using eLua] for details on the shell).
|
||||
If the shell is not enabled, the code looks for a file called _/rom/autorun.lua_
|
||||
and executes it. If this file is not found, a regular Lua intepreter is
|
||||
started on the target. +
|
||||
To enable the shell over a serial connection:
|
||||
|
||||
#define BUILD_SHELL
|
||||
#define BUILD_CON_GENERIC
|
||||
|
||||
To enable the shell over a TCP/IP connection:
|
||||
|
||||
#define BUILD_SHELL
|
||||
#define BUILD_CON_TCP
|
||||
|
||||
o|BUILD_ROMFS |Enable the eLua read-only filesystem. See the link:arch_romfs.html[ROMFS documentation] for details
|
||||
about using the ROM file system. To enable:
|
||||
|
||||
#define BUILD_ROMFS
|
||||
|
||||
o|BUILD_MMCFS |Enable the eLua SD/MMC FAT filesystem support. To enable:
|
||||
|
||||
#define BUILD_MMCFS
|
||||
|
||||
xref:static[Static configuration data dependencies]: *MMCFS_TICK_HZ, MMCFS_TICK_MS, MMCFS_CS_PORT, MMCFS_CS_PIN, MMCFS_SPI_NUM*
|
||||
|
||||
o|BUILD_TERM |Enable ANSI terminal support. It allows eLua to interact with terminals that support ANSI escape sequences
|
||||
(more details link:arch_con_term.html[here]). Currently it works only over RS-232 connections, although this is not a strict requirement.
|
||||
You need to enable this if you want to use the link:refman_gen_term.html[term module]. To enable:
|
||||
|
||||
#define BUILD_TERM
|
||||
|
||||
link:#static[Static configuration data dependencies]: *CON_UART_ID, CON_UART_SPEED, CON_TIMER_ID, TERM_LINES, TERM_COLS*
|
||||
|
||||
o|BUILD_UIP |<Enable TCP/IP networking support. You need to enable this if you want to use the link:refman_gen_net.html[net module].
|
||||
Also, your platform must implement the uIP support functions (see the link:arch_platform.html[platform interface documentation] for details).
|
||||
To enable:
|
||||
|
||||
#define BUILD_UIP
|
||||
|
||||
link:#static[Static configuration data dependencies]: *ELUA_CONF_IPADDR0...3, ELUA_CONF_NETMASK0...3, ELUA_CONF_DEFGW0...3, ELUA_CONF_DNS0...3*
|
||||
|
||||
o|BUILD_DHCPC |If BUILD_UIP is enabled, you can enable this to include a DHCP client in the TCP/IP networking subsystem. To enable:
|
||||
|
||||
#define BUILD_UIP
|
||||
#define BUILD_DHCPC
|
||||
|
||||
o|BUILD_DNS |If BUILD_UIP is enabled, you can enable this to include a minimal DNS resolver in the TCP/IP networking subsystem. To enable:
|
||||
|
||||
#define BUILD_UIP
|
||||
#define BUILD_DNS
|
||||
|
||||
o|BUILD_CON_GENERIC |Generic console support (details link:arch_con_term.html[here]). Enables console access
|
||||
(stdio/stdout/stderr) via a serial transport (currently RS-232, but others can be supported). Enable this if you want to use console
|
||||
input/output over your RS-232 connection. Don't enable this if you need console input/ouput over Ethernet (see the next option). To enable:
|
||||
|
||||
#define BUILD_CON_GENERIC
|
||||
|
||||
link:#static[Static configuration data dependencies]: *CON_UART_ID, CON_UART_SPEED, CON_TIMER_ID*
|
||||
|
||||
o|BUILD_CON_TCP |Console input/output over TCP/IP connections only (details link:arch_con_term.html[here]). Enable this if you want to use
|
||||
your eLua board over a telnet session. Don't enable this if you need console input/output over serial transports (see the previous option). To enable:
|
||||
|
||||
#define BUILD_UIP
|
||||
#define BUILD_CON_TCP
|
||||
|
||||
o|BUILD_ADC |Define this to build support for ADC peripherals. This must be enabled to use the link:refman_gen_adc.html[adc module] or
|
||||
the link:arch_platform_adc.html[adc platform interface]. To enable:
|
||||
|
||||
#define BUILD_ADC
|
||||
|
||||
link:#static[Static configuration data dependencies]: *ADC_BIT_RESOLUTION, ADC_TIMER_FIRST_ID, ADC_NUM_TIMERS, BUF_ENABLE_ADC, ADC_BUF_SIZE*
|
||||
|
||||
o|BUILD_RPC |Define this to build support for LuaRPC. This must be enabled to use the link:refman_gen_rpc.html[rpc module]. To enable:
|
||||
|
||||
#define BUILD_RPC
|
||||
|
||||
link:#static[Static configuration data dependencies]: (ONLY if built with boot=luarpc): *RPC_UART_ID, RPC_TIMER_ID*
|
||||
|
||||
o|BUILD_C_INT_HANDLERS |Enable generic interrupt support in the C code, check link:inthandlers.html[here] for details.
|
||||
|
||||
o|BUILD_LUA_INT_HANDLERS |Enable generic interrupt support in the Lua code, check link:inthandlers.html[here] for details. +
|
||||
xref:static[Static configuration data dependencies]: *PLATFORM_INT_QUEUE_LOG_SIZE*
|
||||
|===================================================================
|
||||
|
||||
[[confmodules]]
|
||||
Configuring modules
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
You can also choose the modules that are going to be part of the eLua image. Unlike components, the modules have a direct impact on the
|
||||
eLua API, so choose them carefully. Disabling a module will save Flash space (and potentially RAM) but will also completely remove the
|
||||
possibility of using that module from eLua.
|
||||
|
||||
The modules included in the build are specified by the *LUA_PLATFORM_LIBS_ROM* macro. An example is given below:
|
||||
|
||||
-------------------------------------------------
|
||||
#define LUA_PLATFORM_LIBS_ROM\
|
||||
_ROM( AUXLIB_PIO, luaopen_pio, pio_map )\
|
||||
_ROM( AUXLIB_TMR, luaopen_tmr, tmr_map )\
|
||||
_ROM( AUXLIB_PD, luaopen_pd, pd_map )\
|
||||
_ROM( AUXLIB_UART, luaopen_uart, uart_map )\
|
||||
_ROM( AUXLIB_TERM, luaopen_term, term_map )\
|
||||
_ROM( AUXLIB_PWM, luaopen_pwm, pwm_map )\
|
||||
_ROM( AUXLIB_PACK, luaopen_pack, pack_map )\
|
||||
_ROM( AUXLIB_BIT, luaopen_bit, bit_map )\
|
||||
_ROM( AUXLIB_CPU, luaopen_cpu, cpu_map )\
|
||||
ROM( LUA_MATHLIBNAME, luaopen_math, math_map )
|
||||
-------------------------------------------------
|
||||
|
||||
Each module is defined by a **_ROM( module_name, module_init_function, module_map_array )** macro, where:
|
||||
|
||||
* *module_name* is the name by which the module can be used from Lua.
|
||||
* *module_init_function* is a function called by the Lua runtime when the module is initialized.
|
||||
* *module_map_array* is a list of all the functions and constants exported by a module.
|
||||
|
||||
Please note that this notation is specific to LTR (the **L**ua **T**iny **R**AM patch) and it's not the only way to specify
|
||||
the list of modules included in the build (although it is the most common one). Check the link:arch_ltr.html#config[LTR section]
|
||||
for more information about LTR.
|
||||
|
||||
For the full list of modules that can be enabled or disabled via _platform_conf.h_ check link:refman_gen.html[the reference manual].
|
||||
|
||||
[[static]]
|
||||
Static configuration data
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
"Static configuration" refers to the compile-time configuration. Static configuration parameters are hard-coded in the firmware image and can't be changed
|
||||
at run-time. The table below lists the static configuration parameters and their semantics.
|
||||
|
||||
[width="100%", cols="<3,<10", options="header", style="asciidoc"]
|
||||
|===================================================================
|
||||
^|Name ^|Meaning
|
||||
o|CON_UART_ID +
|
||||
CON_UART_SPEED +
|
||||
CON_TIMER_ID |Used to configure console input/output over UART. The specified UART id will be used for console input/output, at the
|
||||
specified speed. The data format is always 8N1 (8 data bits, no parity, 1 stop bits)t. The specified timer ID will be used for the console subsystem. These
|
||||
variables are also used by the XMODEM and TERM implementations.
|
||||
|
||||
o|TERM_LINES +
|
||||
TERM_COLS |Used to configure the ANSI terminal support (if enabled in the build). Used to specify (respectively) the number of lines and
|
||||
columns of the ANSI terminal.
|
||||
|
||||
o|ELUA_CONF_IPADDR0...3 +
|
||||
ELUA_CONF_NETMASK0..3 +
|
||||
ELUA_CONF_DEFGW0..3
|
||||
ELUA_CONF_DNS0..3 |Used by the TCP/IP implementation when the DHCP client is not enabled, or when it is enabled but can't be contacted. Specifies
|
||||
the IP address, network mask, default gateway and DNS server. Only needed if BUILD_UIP is enabled.
|
||||
|
||||
o|VTMR_NUM_TIMERS +
|
||||
VTMR_FREQ_HZ |Specify the virtual timers configuration for the platform (refer to link:refman_gen_tmr.html[the timer module documentation] for details). Define VTMR_NUM_TIMERS to 0
|
||||
if this feature is not used.
|
||||
|
||||
o|MMCFS_TICK_HZ +
|
||||
MMCFS_TICK_MS |Specify the rate at which SD/MMC timer function _disk_timerproc()_ are being called by the platform. On most platforms MMCFS_TICK_HZ will match VTMR_FREQ_HZ.
|
||||
Only needed if MMCFS support is enabled.
|
||||
|
||||
o|MMCFS_CS_PORT +
|
||||
MMCFS_CS_PIN |Specify the port and pin to be used as chip select for MMCFS control of an SD/MMC card over SPI. Only needed if MMCFS support is enabled.
|
||||
|
||||
o|MMCFS_SPI_NUM |Specify the SPI peripheral to be used by MMCFS. Only needed if MMCFS support is enabled.
|
||||
|
||||
o|PLATFORM_CPU_CONSTANTS |If the link:refman_gen_cpu.html[cpu module] is enabled, this defines a list of platform-specific constants (for example interrupt masks) that can be accessed
|
||||
using the *cpu.<constant name>* notation. Each constant name must be specified instead of a specific costruct (__ _C(<constant name>__ ). For example:
|
||||
|
||||
|
||||
#define PLATFORM_CPU_CONSTANTS
|
||||
_C( INT_GPIOA ),\
|
||||
_C( INT_GPIOB ),\
|
||||
_C( INT_GPIOC ),\
|
||||
_C( INT_GPIOD ),\
|
||||
_C( INT_GPIOE )
|
||||
|
||||
After compilation, you can access these constants using _cpu.INT_GPIOx_. Note that the implementation of this feature needs virtually no RAM at all, so you can define as many constants
|
||||
as you want here.
|
||||
|
||||
o|BUF_ENABLE_ADC |If the link:refman_gen_adc.html[adc module] is enabled, this controls whether or not the ADC will create a buffer so that more than one sample per channel can be
|
||||
held in a buffer before being returned through *adc.getsample* or *adc.getsamples*. If disabled, only one conversion result will be buffered. This option does NOT affect the behavior
|
||||
of the moving average filter.
|
||||
|
||||
o|ADC_BUF_SIZE |If the link:refman_gen_adc.html[adc module] is enabled, and BUF_ENABLE_ADC is defined, this will define the default buffer length allocated at startup. This does
|
||||
not limit buffer sizes, it only defines the default length. Appropriate values range from BUF_SIZE_2 to BUF_SIZE_32768, with the numeric component at the end being in powers of 2.
|
||||
|
||||
o|ADC_BIT_RESOLUTION |If the link:refman_gen_adc.html[adc module] is enabled, this will define the number of bits per adc conversion result. This is used to determine the maximum conversion
|
||||
value that can be returned by the ADC.
|
||||
|
||||
o|RPC_UART_ID |If the link:refman_gen_rpc.html[rpc module] is enabled and boot mode is set to luarpc, this selects which uart luarpc will listen on for incoming client connections.
|
||||
|
||||
o|RPC_TIMER_ID |If the link:refman_gen_rpc.html[rpc module] is enabled and boot mode is set to luarpc, this selects which timer will be used with the uart selected with RPC_UART_ID.
|
||||
|
||||
o|EGC_INITIAL_MODE +
|
||||
EGC_INITIAL_MEMLIMIT |**(version 0.7 or above)**Configure the default (compile time) operation mode and memory limit of the emergency garbage collector link:elua_egc.html[here] for details
|
||||
about the EGC patch). If not specified, *EGC_INITIAL_MODE* defaults to *EGC_NOT_ACTIVE* (emergency garbage collector disabled) and *EGC_INITIAL_MEMLIMIT* defaults to 0.
|
||||
|
||||
o|PLATFORM_INT_QUEUE_LOG_SIZE |If Lua interrupt support is enabled, this defines the base 2 logarithm of the size of the interrupt queue. Check link:inthandlers.html[here] for details.
|
||||
|===================================================================
|
||||
|
||||
The rest of the static configuration data parameters are meant to be modified mainly by developers and thus they're not listed here. +
|
||||
One more thing you might want to configure for your build is the contents of the ROM file system. See the link:arch_romfs.html[ROMFS documentation] for details on how to do this.
|
||||
|
||||
[[buildoptions]]
|
||||
Invoking the build system
|
||||
-------------------------
|
||||
Once you have everything in place, all you have to do is to invoke the build system (scons) with the right arguments. This is a fairly easy step, although it might look intimidating
|
||||
because of the multitude of options than can be given to scons. They are used to fine tune the final image to your specific needs, but unless your needs are very special you won't need
|
||||
to modify them, so don't worry about the aparent complexity. The examples at the end of this section will show how easy it is to use the build system in practice.
|
||||
|
||||
------------------------------------
|
||||
$ scons
|
||||
[target=lua | lualong]
|
||||
[cpu=<cpuname>]
|
||||
[board=<boardname>]
|
||||
[cpumode=arm | thumb]
|
||||
[allocator = newlib | multiple | simple]
|
||||
[toolchain = <toolchain name>]
|
||||
[optram = 0 | 1]
|
||||
[romfs = verbatim | compress | compile]
|
||||
[prog]
|
||||
------------------------------------
|
||||
|
||||
Your build target is specified by two paramters: *cpu* and *board*. "cpu" gives the name of your CPU, and "board" the name of the board. A board can be associated with more than
|
||||
one CPU. This allows the build system to be very flexible. You can use these two options together or separately, as shown below:
|
||||
|
||||
* **cpu=name**: build for the specified CPU. A board name will be assigned by the build system automatically.
|
||||
* **board=name**: build for the specified board. The CPU name will be inferred by the build system automatically.
|
||||
* **cpu=name board=name**: build for the specified board and CPU. The build script won't allow invalid CPU/board combinations.
|
||||
|
||||
For board/CPU assignment look at the beginning of the SConstruct file (the _platform_list</i> _), it's self-explanatory. +
|
||||
The other options are as follows:
|
||||
|
||||
* **target=lua | lualong**: specify if you want to build "regular" Lua (with floating point support) or integer only Lua (lualong). The default is "lua". "lualong" runs faster on
|
||||
targets that don't have a floating point co-processor, but it completely lacks support for floating point operations, it can only handle integers.
|
||||
|
||||
* **cpumode=arm | thumb**: for ARM targets (not Cortex) this specifies the compilation mode. Its default value is 'thumb' for AT91SAM7X targets and 'arm' for STR9, LPC2888 and LPC2468 targets.
|
||||
|
||||
* **allocator = newlib | multiple | simple**: choose between the default newlib allocator (newlib) which is an older version of dlmalloc, the multiple memory spaces allocator (multiple)
|
||||
which is a newer version of dlmalloc that can handle multiple memory spaces, and a very simple memory allocator (simple) that is slow and doesn't handle fragmentation very well, but it
|
||||
requires very few resources (Flash/RAM). You should use the 'multiple' allocator only if you need to support multiple memory spaces (for example boards that have external RAM). You should
|
||||
use 'simple' only on very resource-constrained systems.
|
||||
|
||||
* **toolchain=<toolchain name>**: this specifies the name of the toolchain used to build the image. See link:toolchains.html#configuration[this link] for details.
|
||||
|
||||
* **optram=0 | 1**: enables of disables the LTR patch, see the link:arch_ltr.html[LTR documentation] for more details. The default is 1, which enables the LTR patch.
|
||||
|
||||
* *prog*: by default, the above 'scons' command will build only the 'elf' (executable) file. Specify "prog" to build also the platform-specific programming file where appropriate
|
||||
(for example, on a AT91SAM7X256 this results in a .bin file that can be programmed in the CPU).
|
||||
|
||||
* **romfs = verbatim | compress | compile**: ROMFS compilation mode, check link:arch_romfs.html#mode[here] for details (*new in 0.7*).
|
||||
|
||||
* **boot = standard | luarpc**: Boot mode. 'standard' will boot to either a shell or lua interactive prompt. 'luarpc' boots with a waiting rpc server, using a UART & timer as specified in
|
||||
link:building.html#static[static configuration data] (*new in 0.7*).
|
||||
|
||||
The output will be a file named elua_**[target]**_**[cpu]**.elf (and also another file with the same name but ending in .bin/.hex if "prog" was specified for platforms that need these files
|
||||
for programming). +
|
||||
If you want the equivalent of a "make clean", invoke "scons" as shown above, but add a "-c" at the end of the command line. +
|
||||
|
||||
**A few examples:**
|
||||
|
||||
---------------------------
|
||||
$ scons cpu=at91sam7x256 -c
|
||||
---------------------------
|
||||
Clear previously built intermediate files.
|
||||
|
||||
------------------------
|
||||
$ scons cpu=at91sam7x256
|
||||
------------------------
|
||||
Build eLua for the AT91SAM7X256 CPU. The board name is detected as sam7-ex256.
|
||||
|
||||
|
||||
------------------------
|
||||
$ scons board=sam7-ex256
|
||||
------------------------
|
||||
Build eLua for the SAM7-EX256 board. The CPU is detected as AT91SAM7X256.
|
||||
|
||||
-----------------------------------------
|
||||
$ scons board=sam7-ex256 cpu=at91sam7x512
|
||||
-----------------------------------------
|
||||
Build eLua for the SAM7-EX256 board, but "overwrite" the default CPU. This is useful when you'd like to see how the specified board would behave (in terms of resources) with a different
|
||||
CPU (in thecase of the SAM7-EX256 board it's possible to switch the on-board AT91SAM7X256 CPU for an AT91SAM7X512 which has the same pinout but comes with more Flash/RAM memory).
|
||||
|
||||
------------------------
|
||||
$ scons cpu=lpc2888 prog
|
||||
------------------------
|
||||
Build eLua for the lpc2888 CPU. The board name is detected as LPC-H2888. Also, the bin file required for target programming is generated. The allocator is automatically detected as "multiple".
|
||||
|
||||
------------------------------------------------
|
||||
$ scons cpu=lm3s8962 toolchain=codesourcery prog
|
||||
------------------------------------------------
|
||||
Build the image for the Cortex LM3S8962 CPU, but use the CodeSourcery toolchain instead of the default toolchain (which is a "generic" ARM GCC toolchain, usually the one built by following
|
||||
the tutorials from this site.
|
||||
|
||||
// $$FOOTER$$
|
||||
|
@ -3,7 +3,7 @@ eLua interrupt handlers
|
||||
-----------------------
|
||||
|
||||
Starting with version link:TODO[0.8], eLua supports interrupt handlers written in Lua. Once an interrupt handler is set in the Lua code, it will be called each time a supported
|
||||
interrupt is generated. A *supported interrupt* is any interrupt that is handled by the platform C code (see link:#cints[here] for more details).
|
||||
interrupt is generated. A *supported interrupt* is any interrupt that is handled by the platform C code (see link:arch_ints.html[here] for more details).
|
||||
|
||||
[red]*IMPORTANT*: before learning how to use interrupt handlers in Lua, please keep in mind that Lua interrupt handlers don't work the same way as
|
||||
regular \(C) interrupt handlers. As Lua doesn't have direct suport for interrupts, they have to be emulated. eLua emulates them using a queue that is populated with
|
||||
@ -26,30 +26,32 @@ handler. After all the interrupts are handled and the queue is emptied, the hook
|
||||
with an infinite or very large timeout; in general, any function from a Lua library that doesn't return immediately (or after a short ammount of time) will block the VM.
|
||||
Care must be taken to avoid such operations as much as possible, otherwise the interrupt support code won't run properly.
|
||||
|
||||
* There is a single interrupt handler in Lua, as opposed to the many hardware interrupt handlers usually found on the eLua targets. It is however easy to differentiate
|
||||
between different interrupt sources, as will be explained in the next paragraph.
|
||||
* There is a single interrupt handler per interrupt type in Lua (the same holds true for C interrupt support), as opposed to the many hardware interrupts
|
||||
handlers usually found on the eLua targets. It is however easy to differentiate between different interrupt sources, as will be explained in the next
|
||||
paragraph.
|
||||
|
||||
* Lua interrupt handlers are never reentrant.
|
||||
|
||||
While this might seem restrictive, Lua interrupt handlers work quite well in practical situations. As an added bonus, since they are implemented by C support code, there's nothing
|
||||
preventing eLua from implementing "custom interrupts" (software generated interrupts that don't correspond to a hardware interrupt on the CPU), such as serial interrupt on
|
||||
char match (generate an interrupt when a certain char is received on the serial port, for example a newline), timer interrupts for link:TODO[virtual timers], TCP/UDP data
|
||||
packet received interrupt, and many others.
|
||||
packet received interrupt and many others.
|
||||
|
||||
Using interrupt handlers in Lua
|
||||
--------------------------------
|
||||
To enable Lua interrupt handler, define *BUILD_LUA_INT_HANDLERS* in _platform_conf.h_. Setting up interrupt handlers is a straightforward process, most of the required
|
||||
functionality is provided by the _mcpu module:
|
||||
To enable Lua interrupt handler, define *BUILD_LUA_INT_HANDLERS* and *PLTATFORM_INT_QUEUE_LOG_SIZE* in _platform_conf.h_ (see link:building.html[here] for details). Setting up interrupt
|
||||
handlers is a straightforward process, most of the required functionality is provided by the _mcpu module:
|
||||
|
||||
* use _cpu.set_int_handler_ to set the interrupt handler function (call with *nil* to disable interrupt handling in Lua code).
|
||||
* use _cpu.set_int_handler( int_id, handler )_ to set the interrupt handler function for the specified interrupt (call with *nil* to disable the interrupt
|
||||
handler for that interrupt). _cpu.set_int_handler_ returns the previous interrupt handler for *int_id* (or *nil* is an interrupt handler was not previously
|
||||
set for the interrupt). In most cases, your interrupt handler should call the previous handler to ensure proper interrupt management.
|
||||
|
||||
* use _cpu.sei( int_id, resnum1, [resnum2], ..., [resnumn])_ and _cpu.cli( int_id, resnum1, [resnum2], ..., [resnumn])_ to enable/disable specific CPU interrupts
|
||||
that will trigger the interrupt handler. You can also use _cpu.sei()_ and _cpu.cli_ (without parameters) to enable/disable global interrupts on the CPU, although this
|
||||
is not recommended.
|
||||
|
||||
The interrupt handler receives two arguments: the interrupt *type* (all the interrupt types are mapped to constants from the _mcpu module) and a
|
||||
*resource ID( that specifies the target resource for the interrupt. This depends on the interrupt type; it can be a timer ID for a timer overflow interrupt, a GPIO port/pin combination
|
||||
for a GPIO interrupt on pin change, a SPI interface ID for a SPI data available interrupt, and so on.
|
||||
The interrupt handler receives the *resource ID* that specifies the resource that fired the interrupt. It can be a timer ID for a timer overflow interrupt,
|
||||
a GPIO port/pin combination for a GPIO interrupt on pin change, a SPI interface ID for a SPI data available interrupt, and so on.
|
||||
|
||||
An example that uses the above concepts and knows how to handle two different interrupt types is presented below:
|
||||
|
||||
@ -58,36 +60,58 @@ An example that uses the above concepts and knows how to handle two different in
|
||||
local vtmrid = tmr.VIRT0
|
||||
local to = 1500000
|
||||
|
||||
-- This is the interrupt handler
|
||||
[bblue]*local function handler( id, resnum )*
|
||||
print( string.format( "Got interrupt with id %d and resnum %d", id, resnum ) )
|
||||
-- Identify interrupt
|
||||
if id == [bblue]*cpu.INT_GPIO_POSEDGE* or id == [bblue]*cpu.INT_GPIO_NEGEDGE* then
|
||||
local port, pin = pio.decode( resnum )
|
||||
print( string.format( "Port is %d, pin is %d", port, pin ) )
|
||||
elseif [bblue]*id == cpu.INT_TMR_MATCH* then
|
||||
-- Timer interrupt on match is one shot, need to rearm to get a periodic timer interrupt
|
||||
print "Timer interrupt!"
|
||||
end
|
||||
local prev_tmr, new_prev_tmr, prev_gpio
|
||||
|
||||
-- This is the timer interrupt handler
|
||||
[bblue]*local function tmr_handler( resnum )*
|
||||
print( string.format( "Timer interrupt for id %d", resnum ) )
|
||||
if prev_tmr then prev_tmr( resnum ) end
|
||||
end
|
||||
|
||||
[bblue]*cpu.set_int_handler( handler )* -- set interrupt handler
|
||||
[bblue]*tmr.set_match_int( vtmrid, to, tmr.INT_CYCLIC )* -- enable periodic timer interrupt for virtual timer 0
|
||||
[bblue]*cpu.sei( cpu.INT_GPIO_NEGEDGE, pio.P0_0 )* -- enable GPIO interrupt on change (negative edge) for pin 0 of port 0
|
||||
[bblue]*cpu.sei( cpu.INT_TMR_MATCH, vtmrid )* -- enable timer match interrupt on virtual timer 0
|
||||
-- This is the timer interrupt handler that gets set after tmr_handler
|
||||
[bblue]*local function new_tmr_handler( resnum )*
|
||||
print( string.format( "NEW HANDLER: timer interrupt for id %d", resnum ) )
|
||||
-- This will chain to the previous interrupt handler (tmr_handler above)
|
||||
if new_prev_tmr then new_prev_tmr( resnum ) end
|
||||
end
|
||||
|
||||
local tmrid = 0
|
||||
-- This is the GPIO interrupt on change (falling edge) interrupt
|
||||
[bblue]*local function gpio_negedge_handler( id, resnum )*
|
||||
local port, pin = pio.decode( resnum )
|
||||
print( string.format( "GPIO NEGEDGE interrupt on port %d, pin %d", port, pin ) )
|
||||
if prev_gpio then prev_gpio( resnum ) end
|
||||
end
|
||||
|
||||
-- Set timer interrupt handler
|
||||
[bblue]*prev_tmr = cpu.set_int_handler( cpu.INT_TMR_MATCH, tmr_handler )*
|
||||
-- Set GPIO interrupt on change (negative edge) interrupt handler
|
||||
[bblue]*prev_gpio = cpu.set_int_handler( cpu.INT_GPIO_NEGEDGE, gpio_negedge_handler )*
|
||||
-- Setup periodic timer interrupt for virtual timer 0
|
||||
[bblue]*tmr.set_match_int( vtmrid, to, tmr.INT_CYCLIC )*
|
||||
-- Enable GPIO interrupt on change (negative edge) for pin 0 of port 0
|
||||
[bblue]*cpu.sei( cpu.INT_GPIO_NEGEDGE, pio.P0_0 )*
|
||||
-- Enable timer match interrupt on virtual timer 0
|
||||
[bblue]*cpu.sei( cpu.INT_TMR_MATCH, vtmrid )*
|
||||
|
||||
local tmrid, count = 0, 0
|
||||
-- Enter an infinite loop that prints "Outside interrupt" every second
|
||||
-- This output will be interleaved with the interrupt handler timeout:
|
||||
-- the timer interrupt message will appear every 1.5 seconds
|
||||
-- the GPIO message will appear each time pin 0 of port 0 changes state from 1 to 0
|
||||
while true do
|
||||
print "Outside interrupt"
|
||||
for i = 1, 1000 do tmr.delay( tmrid, 1000 ) end
|
||||
for i = 1, 1000 do
|
||||
tmr.delay( tmrid, 1000 )
|
||||
count = count + 1
|
||||
end
|
||||
if count == 5 then -- Set new handler after 5 seconds
|
||||
print "Setting new handler for INT_TMR_MATCH"
|
||||
[bblue]*new_prev_tmr = cpu.set_int_handler( cpu.INT_TMR_MATCH, new_tmr_handler )*
|
||||
end
|
||||
end
|
||||
-------------------------------
|
||||
|
||||
This is the most common use case for Lua interrupts, but it's not the only one. Another way to use interrupts from eLua uses polling instead of interrupt handlers: directly
|
||||
This is the most common use case for Lua interrupts, but it's not the only one. Another way to use interrupts from eLua uses *polling* instead of interrupt handlers: directly
|
||||
check the interrupt flags and execute a certain action when one of them becomes set. For this, use the _cpu.get_int_flag( id, resnum, [clear] )_ function from the _mcpu module,
|
||||
which returns the specified interrupt's status for resource *resnum*. *clear* is an optional boolean parameter, specifying if the interrupt flag should be cleared if it is set.
|
||||
It defaults to *true*, and in most cases it shouldn't be changed. Using this feature, it becomes easy to wait for one or more interrupt flag(s) to be set. To use interrupt
|
||||
@ -137,8 +161,7 @@ elua_int_c_handler elua_int_get_c_handler( elua_int_id inttype )::
|
||||
Returns the interrupt handler for interrupt *inttype*
|
||||
|
||||
*elua_int_c_handler* is a function that doesn't return anything and receives a single parameter of type *elua_int_resnum* to differentiate between the sources (GPIO pin, UART id, timer id
|
||||
and so on) that can trigger the interrupt *inttype*. Note that the C interrupt model defines an interrupt handler per interrupt type, as opposed to the Lua interrupt model that defines
|
||||
a single interrupt handler for all interrupt types.
|
||||
and so on) that can trigger the interrupt *inttype*. This is similar in functionality with the Lua handlers.
|
||||
|
||||
To work with interrupts from C code use these functions defined by the link:TODO[CPU platform interface]:
|
||||
|
||||
|
@ -320,7 +320,7 @@ div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
|
||||
div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
|
||||
div.admonitionblock {
|
||||
margin-top: 1.0em;
|
||||
margin-bottom: 1.5em;
|
||||
margin-bottom: 1.0em;
|
||||
}
|
||||
div.admonitionblock {
|
||||
margin-top: 2.0em;
|
||||
@ -410,6 +410,10 @@ div.admonitionblock td.content {
|
||||
border-left: 3px solid #aaaaaa;
|
||||
}
|
||||
|
||||
div.tableblock {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
div.exampleblock > div.content {
|
||||
border-left: 3px solid #aaaaaa;
|
||||
padding-left: 0.5em;
|
||||
@ -680,3 +684,18 @@ dd {
|
||||
display: block;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
div.tableblock div.paragraph p {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.literalblock div.content pre {
|
||||
border: 0px;
|
||||
background: #ffffff;
|
||||
font-family: "Courier New",Courier,monospace;
|
||||
font-size: 110%;
|
||||
overflow: auto;
|
||||
padding: 0;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
@ -1,26 +1,45 @@
|
||||
local vtmrid = tmr.VIRT0
|
||||
local to = 1500000
|
||||
local uartid = 0
|
||||
|
||||
local function handler( id, resnum )
|
||||
print( string.format( "Got interrupt with id %d and resnum %d", id, resnum ) )
|
||||
if id == cpu.INT_GPIO_POSEDGE or id == cpu.INT_GPIO_NEGEDGE then
|
||||
local port, pin = pio.decode( resnum )
|
||||
print( string.format( "Port is %d, pin is %d", port, pin ) )
|
||||
elseif id == cpu.INT_TMR_MATCH then
|
||||
print "Timer interrupt!"
|
||||
end
|
||||
end
|
||||
|
||||
cpu.set_int_handler( handler )
|
||||
tmr.set_match_int( vtmrid, to, tmr.INT_CYCLIC )
|
||||
cpu.sei( cpu.INT_GPIO_NEGEDGE, pio.P0_0 )
|
||||
cpu.sei( cpu.INT_TMR_MATCH, vtmrid )
|
||||
|
||||
local tmrid = 0
|
||||
while true do
|
||||
print "Outside interrupt"
|
||||
for i = 1, 1000 do tmr.delay( tmrid, 1000 ) end
|
||||
if uart.getchar( uartid, 0 ) ~= "" then break end
|
||||
end
|
||||
|
||||
local vtmrid = tmr.VIRT0
|
||||
local to = 1500000
|
||||
local uartid = 0
|
||||
local new_prev_tmr, prev_tmr, prev_gpio
|
||||
|
||||
local function tmr_handler( resnum )
|
||||
print( string.format( "Timer interrupt for timer %d", resnum ) )
|
||||
if prev_tmr then prev_tmr( resnum ) end
|
||||
end
|
||||
|
||||
local function new_tmr_handler( resnum )
|
||||
print( string.format( "NEW HANDLER: timer interrupt for timer %d", resnum ) )
|
||||
if new_prev_tmr then new_prev_tmr( resnum ) end
|
||||
end
|
||||
|
||||
local function gpio_negedge_handler( resnum )
|
||||
local port, pin = pio.decode( resnum )
|
||||
print( string.format( "Port is %d, pin is %d", port, pin ) )
|
||||
if prev_gpio then prev_gpio( resnum ) end
|
||||
end
|
||||
|
||||
prev_tmr = cpu.set_int_handler( cpu.INT_TMR_MATCH, tmr_handler )
|
||||
prev_gpio = cpu.set_int_handler( cpu.INT_GPIO_NEGEDGE, gpio_negedge_handler )
|
||||
tmr.set_match_int( vtmrid, to, tmr.INT_CYCLIC )
|
||||
cpu.sei( cpu.INT_GPIO_NEGEDGE, pio.P0_0 )
|
||||
cpu.sei( cpu.INT_TMR_MATCH, vtmrid )
|
||||
|
||||
local tmrid, count = 0, 0
|
||||
while true do
|
||||
print "Outside interrupt"
|
||||
for i = 1, 1000 do tmr.delay( tmrid, 1000 ) end
|
||||
if uart.getchar( uartid, 0 ) ~= "" then break end
|
||||
count = count + 1
|
||||
if count == 5 then
|
||||
print "Changing timer interrupt handler"
|
||||
new_prev_tmr = cpu.set_int_handler( cpu.INT_TMR_MATCH, new_tmr_handler )
|
||||
end
|
||||
end
|
||||
|
||||
tmr.set_match_int( vtmrid, 0, tmr.INT_CYCLIC );
|
||||
cpu.cli( cpu.INT_GPIO_NEGEDGE, pio.P0_0 )
|
||||
cpu.cli( cpu.INT_TMR_MATCH, vtmrid )
|
||||
cpu.set_int_handler( cpu.INT_TMR_MATCH, nil );
|
||||
cpu.set_int_handler( cpu.INT_GPIO_NEGEDGE, nil );
|
||||
|
||||
|
@ -25,10 +25,6 @@ static u32 elua_int_flags[ LUA_INT_MAX_SOURCES / 32 ];
|
||||
#define INT_IDX_SHIFT ( PLATFORM_INT_QUEUE_LOG_SIZE )
|
||||
#define INT_IDX_MASK ( ( 1 << INT_IDX_SHIFT ) - 1 )
|
||||
|
||||
// We need to know if there is a global interrupt handler set in Lua
|
||||
// (this comes from src/modules/cpu.c)
|
||||
extern u8 cpu_is_int_handler_active();
|
||||
|
||||
// Our hook function (called by the Lua VM)
|
||||
static void elua_int_hook( lua_State *L, lua_Debug *ar )
|
||||
{
|
||||
@ -40,26 +36,25 @@ static void elua_int_hook( lua_State *L, lua_Debug *ar )
|
||||
elua_int_queue[ elua_int_read_idx ].id = ELUA_INT_EMPTY_SLOT;
|
||||
elua_int_read_idx = ( elua_int_read_idx + 1 ) & INT_IDX_MASK;
|
||||
|
||||
// Call Lua handler
|
||||
if( cpu_is_int_handler_active() )
|
||||
if( elua_int_is_enabled( crt.id ) )
|
||||
{
|
||||
lua_rawgeti( L, LUA_REGISTRYINDEX, LUA_INT_HANDLER_KEY );
|
||||
lua_pushinteger( L, crt.id );
|
||||
lua_pushinteger( L, crt.resnum );
|
||||
lua_call( L, 2, 0 );
|
||||
// Call Lua handler
|
||||
// Get interrupt handler table
|
||||
lua_rawgeti( L, LUA_REGISTRYINDEX, LUA_INT_HANDLER_KEY ); // inttable
|
||||
lua_rawgeti( L, -1, crt.id ); // inttable f
|
||||
if( !lua_isnil( L, -1 ) )
|
||||
{
|
||||
lua_pushinteger( L, crt.resnum ); // inttable f resnum
|
||||
lua_call( L, 1, 0 ); // inttable
|
||||
}
|
||||
else
|
||||
lua_remove( L, -1 ); // inttable
|
||||
lua_remove( L, -1 );
|
||||
}
|
||||
|
||||
old_status = platform_cpu_set_global_interrupts( PLATFORM_CPU_DISABLE );
|
||||
if( elua_int_queue[ elua_int_read_idx ].id == ELUA_INT_EMPTY_SLOT ) // no more interrupts in the queue, so clear the hook
|
||||
lua_sethook( L, NULL, 0, 0 );
|
||||
else if( !cpu_is_int_handler_active() )
|
||||
{
|
||||
// The interrupt handler was deactivated in the Lua code, but there are still interrupts in the queue
|
||||
// So reset the queue and clear the hook
|
||||
memset( elua_int_queue, ELUA_INT_EMPTY_SLOT, sizeof( elua_int_queue ) );
|
||||
elua_int_read_idx = elua_int_write_idx = 0;
|
||||
lua_sethook( L, NULL, 0, 0 );
|
||||
}
|
||||
platform_cpu_set_global_interrupts( old_status );
|
||||
}
|
||||
|
||||
@ -72,7 +67,7 @@ int elua_int_add( elua_int_id inttype, elua_int_resnum resnum )
|
||||
|
||||
// If Lua is not running (no Lua state), or no Lua interrupt handler is set,
|
||||
// or the interrupt is not enabled, don't do anything
|
||||
if( lua_getstate() == NULL || !cpu_is_int_handler_active() || !elua_int_is_enabled( inttype ) )
|
||||
if( lua_getstate() == NULL || !elua_int_is_enabled( inttype ) )
|
||||
return PLATFORM_ERR;
|
||||
|
||||
// If there's no more room in the queue, set the overflow flag and return
|
||||
|
@ -24,8 +24,10 @@
|
||||
#include "ltm.h"
|
||||
#include "platform_conf.h"
|
||||
// BogdanM: modified for Lua interrupt support
|
||||
#ifndef LUA_CROSS_COMPILER
|
||||
#include "elua_int.h"
|
||||
#include "platform.h"
|
||||
#endif
|
||||
|
||||
#define state_size(x) (sizeof(x) + LUAI_EXTRASPACE)
|
||||
#define fromstate(l) (cast(lu_byte *, (l)) - LUAI_EXTRASPACE)
|
||||
@ -226,11 +228,14 @@ lua_State *lua_open(void) {
|
||||
lua_State *lua_getstate(void) {
|
||||
return lua_crtstate;
|
||||
}
|
||||
|
||||
LUA_API void lua_close (lua_State *L) {
|
||||
#ifndef LUA_CROSS_COMPILER
|
||||
int oldstate = platform_cpu_set_global_interrupts( PLATFORM_CPU_DISABLE );
|
||||
lua_sethook( L, NULL, 0, 0 );
|
||||
lua_crtstate = NULL;
|
||||
lua_pushnil( L );
|
||||
lua_rawseti( L, LUA_REGISTRYINDEX, LUA_INT_HANDLER_KEY );
|
||||
elua_int_cleanup();
|
||||
platform_cpu_set_global_interrupts( oldstate );
|
||||
#endif
|
||||
@ -247,6 +252,5 @@ LUA_API void lua_close (lua_State *L) {
|
||||
lua_assert(G(L)->tmudata == NULL);
|
||||
luai_userstateclose(L);
|
||||
close_state(L);
|
||||
// BogdanM: modified for eLua interrupt support
|
||||
}
|
||||
|
||||
|
@ -95,6 +95,8 @@ static int cpuh_cli( lua_State *L, int hwmode )
|
||||
if( lua_gettop( L ) > 0 )
|
||||
{
|
||||
id = ( elua_int_id )luaL_checkinteger( L, 1 );
|
||||
if( id < ELUA_INT_FIRST_ID || id > INT_ELUA_LAST )
|
||||
return luaL_error( L, "invalid interrupt ID" );
|
||||
for( i = 2; i <= lua_gettop( L ); i ++ )
|
||||
{
|
||||
resnum = ( elua_int_resnum )luaL_checkinteger( L, i );
|
||||
@ -133,6 +135,17 @@ static int cpuh_sei( lua_State *L, int hwmode )
|
||||
if( lua_gettop( L ) > 0 )
|
||||
{
|
||||
id = ( elua_int_id )luaL_checkinteger( L, 1 );
|
||||
if( id < ELUA_INT_FIRST_ID || id > INT_ELUA_LAST )
|
||||
return luaL_error( L, "invalid interrupt ID" );
|
||||
if( !hwmode )
|
||||
{
|
||||
// Check if we have a handler for this interrupt
|
||||
lua_rawgeti( L, LUA_REGISTRYINDEX, LUA_INT_HANDLER_KEY ); // inttable
|
||||
lua_rawgeti( L, -1, id ); // inttable f
|
||||
if( lua_isnil( L, -1 ) )
|
||||
return luaL_error( L, "no handler is set for this interrupt, set a handler before enabling it.\n" );
|
||||
lua_pop( L, 2 );
|
||||
}
|
||||
for( i = 2; i <= lua_gettop( L ); i ++ )
|
||||
{
|
||||
resnum = ( elua_int_resnum )luaL_checkinteger( L, i );
|
||||
@ -216,29 +229,44 @@ static int cpu_mt_index( lua_State *L )
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_LUA_INT_HANDLERS
|
||||
static u8 cpu_int_handler_active;
|
||||
|
||||
u8 cpu_is_int_handler_active()
|
||||
{
|
||||
return cpu_int_handler_active;
|
||||
}
|
||||
|
||||
// lua: cpu.set_int_handler( f )
|
||||
// Lua: prevhandler = cpu.set_int_handler( id, f )
|
||||
static int cpu_set_int_handler( lua_State *L )
|
||||
{
|
||||
if( lua_type( L, 1 ) == LUA_TNIL )
|
||||
cpu_int_handler_active = 0;
|
||||
else if( lua_type( L, 1 ) == LUA_TFUNCTION || lua_type( L, 1 ) == LUA_TLIGHTFUNCTION )
|
||||
int id = ( int )luaL_checkinteger( L, 1 );
|
||||
|
||||
if( id < ELUA_INT_FIRST_ID || id > INT_ELUA_LAST )
|
||||
return luaL_error( L, "invalid interrupt ID" );
|
||||
if( lua_type( L, 2 ) == LUA_TFUNCTION || lua_type( L, 2 ) == LUA_TLIGHTFUNCTION || lua_type( L, 2 ) == LUA_TNIL )
|
||||
{
|
||||
lua_settop( L, 1 );
|
||||
lua_rawseti( L, LUA_REGISTRYINDEX, LUA_INT_HANDLER_KEY );
|
||||
cpu_int_handler_active = 1;
|
||||
if( lua_type( L, 2 ) == LUA_TNIL && elua_int_is_enabled( id ) )
|
||||
return luaL_error( L, "interrupt is enabled, disable it before setting its handler to nil.\n" );
|
||||
lua_settop( L, 2 ); // id f
|
||||
lua_rawgeti( L, LUA_REGISTRYINDEX, LUA_INT_HANDLER_KEY ); // id f inttable
|
||||
lua_rawgeti( L, -1, id ); // id f inttable prevf
|
||||
lua_replace( L, 1 ); // prevf f inttable
|
||||
lua_pushvalue( L, 2 ); // prevf f inttable f
|
||||
lua_rawseti( L, -2, id ); // prevf f inttable
|
||||
lua_pop( L, 2 ); // prevf
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return luaL_error( L, "invalid argument (must be a function or nil)" );
|
||||
return luaL_error( L, "invalid handler type (must be a function or nil)" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Lua: handler = cpu.get_int_handler( id )
|
||||
static int cpu_get_int_handler( lua_State *L )
|
||||
{
|
||||
int id = ( int )luaL_checkinteger( L, 1 );
|
||||
|
||||
if( id < ELUA_INT_FIRST_ID || id > INT_ELUA_LAST )
|
||||
return luaL_error( L, "invalid interrupt ID" );
|
||||
lua_rawgeti( L, LUA_REGISTRYINDEX, LUA_INT_HANDLER_KEY );
|
||||
lua_rawgeti( L, -1, id );
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Lua: flag = get_int_flag( id, resnum, [clear] )
|
||||
// 'clear' default to true if not specified
|
||||
static int cpu_get_int_flag( lua_State *L )
|
||||
@ -287,6 +315,7 @@ const LUA_REG_TYPE cpu_map[] =
|
||||
{ LSTRKEY( "clock" ), LFUNCVAL( cpu_clock ) },
|
||||
#ifdef BUILD_LUA_INT_HANDLERS
|
||||
{ LSTRKEY( "set_int_handler" ), LFUNCVAL( cpu_set_int_handler ) },
|
||||
{ LSTRKEY( "get_int_handler" ), LFUNCVAL( cpu_get_int_handler ) },
|
||||
{ LSTRKEY( "get_int_flag" ), LFUNCVAL( cpu_get_int_flag) },
|
||||
#endif
|
||||
#if defined( PLATFORM_CPU_CONSTANTS ) && LUA_OPTIMIZE_MEMORY > 0
|
||||
@ -301,8 +330,11 @@ const LUA_REG_TYPE cpu_map[] =
|
||||
LUALIB_API int luaopen_cpu( lua_State *L )
|
||||
{
|
||||
#ifdef BUILD_LUA_INT_HANDLERS
|
||||
cpu_int_handler_active = 0;
|
||||
#endif
|
||||
// Create interrupt table
|
||||
lua_newtable( L );
|
||||
lua_rawseti( L, LUA_REGISTRYINDEX, LUA_INT_HANDLER_KEY );
|
||||
#endif //#ifdef BUILD_LUA_INT_HANDLERS
|
||||
|
||||
#if LUA_OPTIMIZE_MEMORY > 0
|
||||
return 0;
|
||||
#else // #if LUA_OPTIMIZE_MEMORY > 0
|
||||
|
Loading…
x
Reference in New Issue
Block a user