mirror of
https://github.com/elua/elua.git
synced 2025-01-08 20:56:17 +08:00
Merge branch 'master' into luabuild
Conflicts: .gitignore src/common_tmr.c src/platform/lm3s/platform.c src/platform/lm3s/platform_conf.h src/platform/sim/platform_conf.h src/platform/stm32/platform_conf.h src/platform/str9/platform_conf.h utils/build.lua Also fixed some minor issues in the builder.
This commit is contained in:
commit
463f0bceda
2
.gitignore
vendored
2
.gitignore
vendored
@ -20,4 +20,6 @@ inc/git_version.h
|
||||
*.*~
|
||||
luac.cross*
|
||||
boards/*.h
|
||||
sdcard.img
|
||||
core
|
||||
|
||||
|
21
CHANGELOG
21
CHANGELOG
@ -1,9 +1,26 @@
|
||||
xx.yy.zzzz Bogdan Marinescu <bogdan.marinescu@gmail.com>
|
||||
04.04.2013 Bogdan Marinescu <bogdan.marinescu@gmail.com>
|
||||
Dado Sutter <dadosutter@gmail.com>
|
||||
James Snyder <jbsnyder@gmail.com>
|
||||
|
||||
* Official release 0.9
|
||||
* New feature: system timer ([TODO] add link)
|
||||
* New feature: system timer (micro-second accurate timer on all platforms)
|
||||
* New feature: WOFS (write-once file system), a writeable file system that uses
|
||||
the internal MCU Flash memory as storage
|
||||
* New feature: advanced shell (more shell commands, file masks)
|
||||
* New feature: support for multiple SD cards
|
||||
* New memory optimizations: pseudo read-only strings in Lua, reading Lua bytecode
|
||||
directly from Flash, NaN packing for Lua TValues
|
||||
* Directory support in file systems (currently MMCFS only)
|
||||
* Support for various new CPUs and boards
|
||||
* Direct USB CDC support on some platforms
|
||||
* New 64-bit integer-only compilation mode (lualonglong)
|
||||
* New interrupts and Various interrupt support code on different platforms
|
||||
* 'recv' is now able to save files too, not only execute them
|
||||
* Various fixes and performance improvements in the serial multiplexer code
|
||||
* Bug fixes on all platforms
|
||||
* RPC fixes and improvements
|
||||
* The shell commands are now callable from the 'elua' module
|
||||
* Updated documentation
|
||||
|
||||
02.02.2011 Bogdan Marinescu <bogdan.marinescu@gmail.com>
|
||||
Dado Sutter <dadosutter@gmail.com>
|
||||
|
@ -385,8 +385,13 @@ if not GetOption( 'help' ):
|
||||
# Additional libraries
|
||||
local_libs = ''
|
||||
|
||||
# Shell files
|
||||
shell_files = """ src/shell/shell.c src/shell/shell_adv_cp_mv.c src/shell/shell_adv_rm.c src/shell/shell_cat.c src/shell/shell_help.c
|
||||
src/shell/shell_ls.c src/shell/shell_lua.c src/shell/shell_mkdir.c src/shell/shell_recv.c src/shell/shell_ver.c
|
||||
src/shell/shell_wofmt.c """
|
||||
|
||||
# Application files
|
||||
app_files = """ src/main.c src/romfs.c src/semifs.c src/xmodem.c src/shell.c src/term.c src/common.c src/common_tmr.c src/buf.c src/elua_adc.c src/dlmalloc.c
|
||||
app_files = """ src/main.c src/romfs.c src/semifs.c src/xmodem.c src/term.c src/common.c src/common_tmr.c src/buf.c src/elua_adc.c src/dlmalloc.c
|
||||
src/salloc.c src/luarpc_elua_uart.c src/elua_int.c src/linenoise.c src/common_uart.c src/eluarpc.c """
|
||||
|
||||
# Newlib related files
|
||||
@ -421,7 +426,7 @@ if not GetOption( 'help' ):
|
||||
execfile( "src/platform/%s/conf.py" % platform )
|
||||
|
||||
# Complete file list
|
||||
source_files = Split( app_files + specific_files + newlib_files + uip_files + lua_full_files + module_files + rfs_files )
|
||||
source_files = Split( app_files + specific_files + newlib_files + uip_files + lua_full_files + module_files + rfs_files + shell_files )
|
||||
|
||||
comp = conf.Finish()
|
||||
|
||||
|
@ -10,6 +10,7 @@ return {
|
||||
term = { lines = 25, cols = 80 },
|
||||
cints = true,
|
||||
lm3s_disp = true,
|
||||
lm3s_pio = true,
|
||||
rpc = { uart = 0, speed = 115200 },
|
||||
adc = { buf_size = 2, first_timer = 0, num_timers = "NUM_TIMER" },
|
||||
tcpip = { ip = "192.168.1.100", dns = "192.168.1.1", gw = "192.168.1.1", netmask = "255.255.255.0" },
|
||||
|
@ -289,7 +289,7 @@ if not utils.is_dir( outd ) then
|
||||
end
|
||||
|
||||
-- Output file
|
||||
output = outd .. utils.dir_sep .. 'elua_' .. comp.target .. '_' .. comp.board:lower()
|
||||
output = outd .. utils.dir_sep .. 'elua_' .. comp.target .. '_' .. comp.board:lower() .. ".elf"
|
||||
builder:set_build_dir( builder:get_build_dir() .. utils.dir_sep .. comp.board:lower() )
|
||||
|
||||
-- User report
|
||||
@ -429,7 +429,6 @@ ascmd = ascmd or builder:asm_cmd{ flags = asflags, defines = cdefs, includes = i
|
||||
builder:set_compile_cmd( compcmd )
|
||||
builder:set_link_cmd( linkcmd )
|
||||
builder:set_asm_cmd( ascmd )
|
||||
builder:set_exe_extension( ".elf" )
|
||||
|
||||
-- Create the ROMFS target
|
||||
local romfs_target = builder:target( "#phony:romfs", nil, make_romfs )
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
module( ..., package.seeall )
|
||||
|
||||
package.path = package.path .. ";utils/?.lua;config/?.lua"
|
||||
package.path = "utils/?.lua;config/?.lua;" .. package.path
|
||||
|
||||
local comps = require "components"
|
||||
local cfgs = require "configurations"
|
||||
|
@ -4,7 +4,7 @@ local builder = b.new_builder( ".build/cross-lua" )
|
||||
local utils = b.utils
|
||||
local sf = string.format
|
||||
builder:init( args )
|
||||
builder:set_build_mode( builder.BUILD_DIR )
|
||||
builder:set_build_mode( builder.BUILD_DIR_LINEARIZED )
|
||||
|
||||
local output = 'luac.cross'
|
||||
local cdefs = '-DLUA_CROSS_COMPILER'
|
||||
|
@ -130,7 +130,9 @@ local menu =
|
||||
{ "Linenoise", "linenoise.html" },
|
||||
{ "Cross-compiling", "using.html#cross" },
|
||||
{ "LuaRPC", "using.html#rpc" },
|
||||
{ "The serial multiplexer", "sermux.html" }
|
||||
{ "The serial multiplexer", "sermux.html" },
|
||||
{ nil, "simple_shell.html", nil, "Simple shell" },
|
||||
{ nil, "advanced_shell.html", nil, "Advanced shell" },
|
||||
},
|
||||
},
|
||||
{ { "Code examples", "Exemplos de Código" }, "examples.html" },
|
||||
|
217
doc/en/advanced_shell.txt
Normal file
217
doc/en/advanced_shell.txt
Normal file
@ -0,0 +1,217 @@
|
||||
// $$HEADER$$
|
||||
The advanced shell
|
||||
------------------
|
||||
The advanced shell is an extension to the link:simple_shell.html[simple shell]. It adds some new
|
||||
features to the simple shell:
|
||||
|
||||
- file masks
|
||||
- more file operations (rename and move)
|
||||
- recursive operations (for example recursive copies of directories)
|
||||
|
||||
A detailed description of the advanced shell commands and the structure of the file masks are given below.
|
||||
|
||||
[width="90%", cols="^, ^, ^, ^", grid="none"]
|
||||
|==============================================================================================
|
||||
| link:#cmd_help[help] | link:#cmd_ver[ver] | link:#cmd_recv[recv] | link:#cmd_lua[lua]
|
||||
| link:#cmd_ls[ls] | link:#cmd_ls[dir] | link:#cmd_cat[cat] | link:#cmd_cat[type]
|
||||
| link:#cmd_cp[cp] | link:#cmd_exit[exit] | link:#cmd_wofmt[wofmt] | link:#cmd_mkdir[mkdir]
|
||||
| link:#cmd_rm[rm] | link:#cmd_mv[mv] | |
|
||||
|==============================================================================================
|
||||
|
||||
File masks
|
||||
----------
|
||||
|
||||
WARNING: Read this section carefully, eLua's idea of file masks ia different from what you might have
|
||||
encountered in various operating systems.
|
||||
|
||||
The advanced shell supports file masks for various file operations (for example _cp_). A file mask can
|
||||
match zero, one or more files. In order to match more than one file, it uses two special characters:
|
||||
|
||||
- _?_: this matches *exactly one character*
|
||||
- _*_: this matches *zero or more characters*, non-greedy (it stops at the first non-special character).
|
||||
Any *?* characters immediately following the *** will be ignored.
|
||||
|
||||
This is probably best understood by some examples. Given the filenames below:
|
||||
|
||||
-----
|
||||
a
|
||||
ab
|
||||
abcd
|
||||
abba
|
||||
aaba
|
||||
aaab
|
||||
bbbcd
|
||||
dccdb
|
||||
-----
|
||||
|
||||
this is how various file masks work:
|
||||
|
||||
- _*_ : all the files above
|
||||
- _a*_ : a, ab, abcd, abba, aaba, aaab
|
||||
- _a*b_ : ab, aaab
|
||||
- _a*?b_ : ab, aaab
|
||||
- _a*b?_ : aaba
|
||||
- _*b*_ : ab, abcd, abba, aaba, aaab, bbbcd, dccdb
|
||||
- _????_ : abcd, abba, aaba, aaab
|
||||
- _a?*b_ : aaab
|
||||
|
||||
[[cmd_help]]
|
||||
help
|
||||
~~~~
|
||||
By itself, it shows a list of all shell commands. If a shell command is given after *help*, it displays
|
||||
detailed information about the given command. Examples:
|
||||
|
||||
------
|
||||
# help
|
||||
# help ls
|
||||
------
|
||||
|
||||
[[cmd_ver]]
|
||||
ver
|
||||
~~~
|
||||
Print the version of the eLua image installed on the board. If the image is not an official one, an
|
||||
abbreviation of the git SHA1 revision used for building the image will be shown in the version number.
|
||||
|
||||
[[cmd_recv]]
|
||||
recv
|
||||
~~~~
|
||||
Allows you to receive from the PC running the terminal emulator program, a Lua file (either source or compiled
|
||||
bytecode) via XMODEM and either execute it on your board or save it to a file. To use this feature, your eLua
|
||||
target image must be built with support for XMODEM (see link:building.html[building] for details). Also, your
|
||||
terminal emulation program must support sending files via the XMODEM protocol. Both XMODEM with checksum
|
||||
and XMODEM with CRC are supported, but only XMODEM with 128 byte packets is allowed (XMODEM with 1K packets won't work).
|
||||
|
||||
To start the transfer, enter *recv* at the shell prompt. eLua will respond with "Waiting for file ...". At this point
|
||||
you can send the file to the eLua board via XMODEM. eLua will receive and execute the file. Don't worry when you
|
||||
see 'C' characters suddenly appearing on your terminal after you enter this command, this is how the XMODEM transfer
|
||||
is initiated. If you want to save the data to a file instead of executing it, use *recv <filename>* instead.
|
||||
|
||||
Since XMODEM is a protocol that uses serial lines, this command is not available if you're running your console
|
||||
over TCP/IP instead of a serial link. If you'd like to send compiled bytecode to eLua instead of source code,
|
||||
please check link:using.html#cross[this section] first. Examples:
|
||||
|
||||
--------------------
|
||||
# recv
|
||||
# recv /mmc/temp.lua
|
||||
--------------------
|
||||
|
||||
[[cmd_lua]]
|
||||
lua
|
||||
~~~
|
||||
This command allows you to start the Lua interpreter, optionally passing command line parameters, just as you would do
|
||||
from a desktop machine. There are some differences from the desktop Lua version in command line parsing:
|
||||
|
||||
- the command line can't be longer than 50 chars
|
||||
- character escaping is not implemented. For example, the next command won't work because of the ' (simple quotes) escape sequences:
|
||||
|
||||
eLua# lua -e 'print(\'Hello, World!\')' -i
|
||||
Press CTRL+Z to exit Lua
|
||||
lua: (command line):1: unexpected symbol near ''
|
||||
+
|
||||
However, if you use both '' (simple quotes) and "" (double quotes) for string quoting, it will work:
|
||||
|
||||
eLua# lua -e 'print("Hello, World")' -i
|
||||
Press CTRL+Z to exit Lua
|
||||
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
|
||||
Hello, World
|
||||
|
||||
- if you want to execute a file from the link:"arch_romfs.html"[ROM file system] (or from another file system), remember to prefix it
|
||||
with _/rom_. For example, to execute *hello.lua*, do this:
|
||||
|
||||
eLua# lua /rom/hello.lua
|
||||
|
||||
[[cmd_ls]]
|
||||
ls or dir
|
||||
~~~~~~~~~
|
||||
Shows a list of all the files in the file systems used by eLua, as well as their size and the total size of the given file system.
|
||||
Syntax:
|
||||
|
||||
------------------
|
||||
# ls [<path>] [-R]
|
||||
------------------
|
||||
|
||||
If *path* is given, the listing is restricted to the file mask specified by *path*. If *-R* is given, *ls* will recurse through all
|
||||
the directories in *path* or through all the directories in all the available filesystems if *path* is not specified.
|
||||
|
||||
[[cmd_cat]]
|
||||
cat or type
|
||||
~~~~~~~~~~~
|
||||
Prints the content of (usually text) files on the console. Examples:
|
||||
|
||||
-------------------------------------
|
||||
eLua# cat /rom/test.lua /mmc/temp.txt
|
||||
eLua# cat /mmc/autorun.lua
|
||||
-------------------------------------
|
||||
|
||||
[[cmd_cp]]
|
||||
cp
|
||||
~~
|
||||
Copies a file or a directory. This command can be used to copy data between different file systems (for example between the MMC file
|
||||
system and the RFS file system). Syntax:
|
||||
|
||||
-------------------------------------
|
||||
# cp <src> <dest> [-R] [-f] [-c] [-s]
|
||||
-------------------------------------
|
||||
|
||||
- *<src>* is the source file or directory. It can be a file mask.
|
||||
- *<dest>* is the destination. If it does not exist, it will be created. It can't be a file mask.
|
||||
- *-R*: (optional) copy files and directories recursively.
|
||||
- *-f*: (optional) force file overwrite on *<dest>*. The default is to ask for confirmation before overriding.
|
||||
- *-c*: (optional) confirm each file copy operation.
|
||||
- *-s*: (optional) run the command normally, but don't actually copy anything. Useful to check the outcome of the operation before
|
||||
actually executing it.
|
||||
|
||||
[[cmd_exit]]
|
||||
exit
|
||||
~~~~
|
||||
Exits the shell. This only makes sense if eLua is compiled with terminal support over TCP/IP , as it closes the telnet session to the
|
||||
eLua board. Otherwise it just terminates the shell and blocks forever until you reset your board.
|
||||
|
||||
[[cmd_wofmt]]
|
||||
wofmt
|
||||
~~~~~
|
||||
"Formats" the link:arch_wofs.html[WOFS file system], erasing its current contents. The user is asked to confirm this operation.
|
||||
|
||||
[[cmd_mkdir]]
|
||||
mkdir
|
||||
~~~~~
|
||||
Creates a new directory. The filesystem must have directory support in order fir this to work. Example:
|
||||
|
||||
----------------
|
||||
# mkdir /mmc/dir
|
||||
----------------
|
||||
|
||||
[[cmd_rm]]
|
||||
rm
|
||||
~~
|
||||
Removes files and directories. Syntax:
|
||||
|
||||
------------------------------
|
||||
# rm <filemask> [-R] [-c] [-s]
|
||||
------------------------------
|
||||
|
||||
- *<filemask>*: specify the file(s) or directories that are to be removed
|
||||
- *-R*: (optional) remove directories recursively. Use this flag to remove a directory with *rm*
|
||||
- *-c*: (optional) confirm each remove operation.
|
||||
- *-s*: (optional) run the command normally, but don't actually remove anything. Useful to check the outcome of the operation before
|
||||
actually executing it.
|
||||
|
||||
[[cmd_mv]]
|
||||
mv
|
||||
~~
|
||||
Moves a file or a directory. This command can be used to move data between different file systems (for example between the MMC file
|
||||
system and the RFS file system). Syntax:
|
||||
|
||||
-------------------------------------
|
||||
# mv <src> <dest> [-R] [-f] [-c] [-s]
|
||||
-------------------------------------
|
||||
|
||||
- *<src>* is the source file or directory. It can be a file mask.
|
||||
- *<dest>* is the destination. If it does not exist, it will be created. It can't be a file mask.
|
||||
- *-R*: (optional) move files and directories recursively.
|
||||
- *-f*: (optional) force file overwrite on *<dest>*. The default is to ask for confirmation before overriding.
|
||||
- *-c*: (optional) confirm each file move operation.
|
||||
- *-s*: (optional) run the command normally, but don't actually move anything. Useful to check the outcome of the operation before
|
||||
actually executing it.
|
||||
|
||||
// $$FOOTER$$
|
@ -1,75 +0,0 @@
|
||||
$$HEADER$$
|
||||
<h3>The ROM file system</h3>
|
||||
<p>The ROM file system (ROMFS) is a small, read-only file system built for <b>eLua</b>. It is integrated with the C
|
||||
library, so you can use standard POSIX calls (fopen/fread/fwrite...) to access it. It is also accessible directly from Lua via the <b>io</b> module.
|
||||
The files in the file system are part of the <b>eLua</b> binary image, thus they can't be modified after the image is
|
||||
built. For the same reason, you can't add/delete files after the image is built. ROMFS doesn't support
|
||||
sub-directories.</p>
|
||||
<p>ROMFS is integrated with <a href="building.html">the build system</a> for maximum flexibility on various platforms. As a result, you can select the ROMFS contents for each board on which
|
||||
<b>eLua</b> runs. Moreover, you can specify what <b>applications</b> (instead of individual files) go to the file system, as a real application might need more than a single Lua program
|
||||
to run (for example a HTTP page with all its dependencies).</p>
|
||||
<h2>Using ROMFS</h2>
|
||||
<p>To use ROMFS, you have to copy the required files to the <i>romfs/</i> directory, before building eLua.
|
||||
Keep in mind that the maximum file name of a ROMFS file is 14 characters, including the dot between the file
|
||||
name and its extension. Make sure that the file names from <i>romfs/</i> follow this rule. Then edit the main build script (<b>SConstruct</b>) to add a new application
|
||||
or to modify an existing one.
|
||||
All the applications that can be included in ROMFS are defined in the <b>romfs</b> array in <b>SConstruct</b>. Each application in the <b>romfs</b> array lists its files, as shown below
|
||||
(note that <b>ltthpd</b>, <b>tvbgone</b> and <b>pong</b> applications require more than one file in order to run):</p>
|
||||
<p><pre><code>romfs = {
|
||||
'bisect' : [ 'bisect.lua' ],
|
||||
'hangman' : [ 'hangman.lua' ],
|
||||
'lhttpd' : [ 'index.pht', 'lhttpd.lua', 'test.lua' ],
|
||||
'pong' : [ 'pong.lua', 'LM3S.lua' ],
|
||||
'led' : [ 'led.lua' ],
|
||||
'piano' : [ 'piano.lua' ],
|
||||
'pwmled' : [ 'pwmled.lua' ],
|
||||
'tvbgone' : [ 'tvbgone.lua', 'codes.bin' ],
|
||||
'hello' : [ 'hello.lua' ],
|
||||
'info' : [ 'info.lua' ],
|
||||
'morse' : [ 'morse.lua' ],
|
||||
'dualpwm' : [ 'dualpwm.lua' ],
|
||||
'adcscope' : [ 'adcscope.lua' ],
|
||||
'life' : [ 'life.lua' ]
|
||||
}</code></pre></p>
|
||||
<p>After this, you need to decide the application-to-board mapping. This is defined in another array in <b>SConsctruct</b>, named <b>file_list</b>. The definition of this array is shown below,
|
||||
the format is self-explanatory:</p>
|
||||
<p><pre><code>file_list = {
|
||||
'SAM7-EX256' : [ 'bisect', 'hangman' , 'led', 'piano', 'hello', 'info', 'morse' ],
|
||||
'EK-LM3S8962' : [ 'bisect', 'hangman', 'lhttpd', 'pong', 'led', 'piano', 'pwmled', 'tvbgone', 'hello', 'info', 'morse', 'adcscope' ],
|
||||
'EK-LM3S6965' : [ 'bisect', 'hangman', 'lhttpd', 'pong', 'led', 'piano', 'pwmled', 'tvbgone', 'hello', 'info', 'morse', 'adcscope' ],
|
||||
'STR9-COMSTICK' : [ 'bisect', 'hangman', 'led', 'hello', 'info' ],
|
||||
'PC' : [ 'bisect', 'hello', 'info', 'life' ],
|
||||
'LPC-H2888' : [ 'bisect', 'hangman', 'led', 'hello', 'info' ],
|
||||
'MOD711' : [ 'bisect', 'hangman', 'led', 'hello', 'info', 'dualpwm' ],
|
||||
'STM3210E-EVAL' : [ 'bisect', 'hello', 'info' ],
|
||||
'ATEVK1100' : [ 'bisect', 'hangman', 'led', 'hello', 'info' ],
|
||||
'ET-STM32' : [ 'hello', 'hangman', 'info', 'bisect' ],
|
||||
'EAGLE-100' : [ 'bisect', 'hangman', 'lhttpd', 'led', 'hello', 'info' ]
|
||||
}
|
||||
</code></pre></p>
|
||||
<p>What's left to do is <a href="building.html">build eLua</a>. As part of the build process, <b>mkfs.py</b> will be called, which will read the contents of the <i>romfs/</i> directory and
|
||||
output a C header file that contains a binary description of the file system. To use ROMFS from C code, whevener you want to access a file, prefix its name with <b>/rom/</b>. For example,
|
||||
if you want to open the <b>a.txt</b> file in ROMFS, you should call fopen like this:</p>
|
||||
<p><pre><code>f = fopen( "/rom/a.txt", "rb" )</code></pre></p>
|
||||
<p>If you want to execute one file from the ROM file system with Lua, simply do this from the shell:</p>
|
||||
<p><pre><code>eLua# lua /rom/bisect.lua</code></pre></p>
|
||||
<p>Or directly from Lua:</p>
|
||||
<p><pre><code>> dofile "/rom/bisect.lua"</code></pre></p>
|
||||
<a name="mode" /><h2>ROMFS modes</h2>
|
||||
<p>Starting with version 0.7, the ROMFS can be added to the <b>eLua</b> binary image in 3 different ways:</p>
|
||||
<ul>
|
||||
<li><b>verbatim</b>: this is the default option. All the files are copied to the ROMFS directly, without any processing.</li>
|
||||
<li><b>compress</b>: compress the Lua source code by using <a href="http://luaforge.net/projects/luasrcdiet/">LuaSrcDiet</a> (included in <b>eLua</b>), a program
|
||||
that can decrease the size of a Lua source file by applying different transformations. Every
|
||||
Lua source file (extension <b>.lua</b>) from ROMFS is fed through LuaSrcDiet and the result is written in the <b>eLua</b> binary image. This option can yield
|
||||
pretty good compression, the only downside being that the compressed Lua source files aren't generally easily readable. However, this isn't really a problem in
|
||||
most practical cases.</li>
|
||||
<li><b>compile</b>: precompile the Lua source code to bytecode. Every Lua source file (extension <b>.lua</b>) from ROMFS is fed through the Lua cross compiler
|
||||
(see <a href="using.html#cross">here</a> for details on cross compilation and its benefits) and the result is written in the <b>eLua</b> binary image. This option
|
||||
might decrease or increase the physical size of the ROMFS image, but its real benefits are increased speed (because <b>eLua</b> doesn't need to compile the Lua
|
||||
code to bytecode first) and decreased RAM consumption (the Lua parser might get quite memory-hungry at times, which in turn might lead to stack overflows and very
|
||||
hard to find bugs). <b>NOTE</b>: this option is not available if eLua is compiled in 64-bit integer only mode (lualonglong).</li>
|
||||
</ul>
|
||||
<p>See <a href="building.html#buildoptions">here</a> for instructions on how to specify the ROMFS compilation mode.</p>
|
||||
$$FOOTER$$
|
||||
|
57
doc/en/arch_romfs.txt
Normal file
57
doc/en/arch_romfs.txt
Normal file
@ -0,0 +1,57 @@
|
||||
// $$HEADER$$
|
||||
The ROM file system
|
||||
-------------------
|
||||
The ROM file system (ROMFS) is a small, read-only file system built for eLua<. It is integrated with the C
|
||||
library, so you can use standard POSIX calls (fopen/fread/fwrite...) to access it. It is also accessible directly
|
||||
from Lua via the *io* module. The files in the file system are part of the eLua binary image, thus they can't be
|
||||
modified after the image is built. For the same reason, you can't add/delete files after the image is built.
|
||||
ROMFS doesn't support directories. ROMFS is integrated with link:building.html[the build system] for maximum flexibility.
|
||||
|
||||
Using ROMFS
|
||||
~~~~~~~~~~~
|
||||
To use ROMFS, all you have to do is copy the files you need on your eLua image to the _romfs/_ directory. The
|
||||
build system will automatically take care of including the files in _romfs/_ in your eLua image. So all that's
|
||||
left to do is link:building.html[build eLua]. As part of the build process, the *mkfs* script will be called,
|
||||
which will read the contents of the _romfs/_ directory and output a C header file that contains a binary
|
||||
description of the file system.
|
||||
|
||||
To use ROMFS from C code, whevener you want to access a file, prefix its name with */rom*. For example,
|
||||
if you want to open the *a.txt* file in ROMFS, you should call fopen like this:
|
||||
|
||||
-------------------------------
|
||||
f = fopen( "/rom/a.txt", "rb" )
|
||||
-------------------------------
|
||||
|
||||
If you want to execute one file from the ROM file system with Lua, simply do this from the shell:
|
||||
|
||||
-------------------------
|
||||
eLua# lua /rom/bisect.lua
|
||||
-------------------------
|
||||
|
||||
Or directly from Lua:
|
||||
|
||||
--------------------------
|
||||
> dofile "/rom/bisect.lua"
|
||||
--------------------------
|
||||
|
||||
[[mode]]
|
||||
ROMFS modes
|
||||
~~~~~~~~~~~
|
||||
Starting with version 0.7, the ROMFS can be added to the <b>eLua</b> binary image in 3 different ways:
|
||||
|
||||
- *verbatim*: this is the default option. All the files are copied to the ROMFS directly, without any processing.
|
||||
- *compress*: compress the Lua source code by using http://luaforge.net/projects/luasrcdiet/[LuaSrcDiet] (included in
|
||||
eLua), a program that can decrease the size of a Lua source file by applying different transformations. Every Lua source
|
||||
file (extension *.lua*) from ROMFS is fed through LuaSrcDiet and the result is written in the eLua binary image. This
|
||||
option can yield pretty good compression, the only downside being that the compressed Lua source files aren't generally
|
||||
easily readable. However, this isn't really a problem in most practical cases.
|
||||
- *compile*: precompile the Lua source code to bytecode. Every Lua source file (extension *.lua*) from ROMFS is fed through
|
||||
the Lua cross compiler (see link:using.html#cross[here] for details on cross compilation and its benefits) and the result is
|
||||
written in the eLua binary image. This option might decrease or increase the physical size of the ROMFS image, but its real
|
||||
benefits are increased speed (because eLua doesn't need to compile the Lua code to bytecode first) and decreased RAM consumption
|
||||
(the Lua parser might get quite memory-hungry at times, which in turn might lead to stack overflows and very hard to find bugs).
|
||||
This option is not available if eLua is compiled in 64-bit integer only mode (lualonglong).
|
||||
|
||||
See link:building.html#buildoptions[here] for instructions on how to specify the ROMFS compilation mode.
|
||||
|
||||
// $$FOOTER$$
|
@ -108,7 +108,7 @@ the WOFS image via *wofmt*, as already explained). Its signature is also in _inc
|
||||
int platform_flash_erase_sector( u32 sector_id );
|
||||
-------------------------------------------------
|
||||
|
||||
Check this link TODO for more details about the flash platform interface.
|
||||
Check link:arch_platform_flash.html[this link] for more details about the flash platform interface.
|
||||
If all the above requirements are met, just define *BUILD_WOFS* in your _platform_conf.h_ file, compile
|
||||
and burn your eLua image and you'll have a WOFS instance up and running. Check link:building.html[here]
|
||||
for more details about the configuration of your eLua image.
|
||||
|
@ -55,6 +55,7 @@ _LPC1768=http://www.nxp.com/#/pip/pip=%5Bpip=LPC1769_68_67_66_65_64_63%5D|pp=%5B
|
||||
_AT32UC3B0256=http://www.atmel.com/dyn/products/product_card.asp?part_id=4174[AT32UC3B0256]
|
||||
_AT32UC3A0128=http://www.atmel.com/dyn/products/product_card.asp?part_id=4126[AT32UC3A0128]
|
||||
_LM3S1968=http://www.luminarymicro.com/products/lm3s1968_microcontroller.html[LM3S1968]
|
||||
_LM3S9D92=http://www.ti.com/product/lm3s9d92[LM3S9D92]
|
||||
|
||||
# Boards
|
||||
_EK-LM3S8962=http://www.luminarymicro.com/products/lm3s8962_can_ethernet_evaluation_kit.html[EK-LM3S8962]
|
||||
@ -74,6 +75,7 @@ _mbed=http://mbed.org/[mbed]
|
||||
_Mizar32=http://simplemachines.it/mizar32[Mizar32]
|
||||
_ATEVK1101=http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4175[ATEVK1101]
|
||||
_EK-LM3S1968=http://www.luminarymicro.com/products/lm3s1968_evaluation_kits.html[EK-LM3S1968]
|
||||
_SolderCore=http://soldercore.com/products/soldercore[SolderCore]
|
||||
|
||||
# Generic modules
|
||||
_mcpu=link:refman_gen_cpu.html[cpu]
|
||||
|
@ -76,7 +76,7 @@ o|BUILD_MMCFS |Enable the eLua SD/MMC FAT filesystem support. To enable:
|
||||
|
||||
#define BUILD_MMCFS
|
||||
|
||||
xref:static[Static configuration data dependencies]: *MMCFS_CS_PORT, MMCFS_CS_PIN, MMCFS_SPI_NUM*
|
||||
xref:static[Static configuration data dependencies]: *MMCFS_CS_PORT, MMCFS_CS_PIN, MMCFS_SPI_NUM, MMCFS_NUM_CARDS, MMCFS_CS_PORT_ARRAY, MMCFS_CS_PIN_ARRAY, MMCFS_SPI_NUM_ARRAY*
|
||||
|
||||
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.
|
||||
@ -236,10 +236,18 @@ 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_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_NUM_CARDS |Specify the number of SD cards in the system. Only needed if MMCFS support is enabled. If not specified, it defaults to 1.
|
||||
|
||||
o|MMCFS_SPI_NUM |Specify the SPI peripheral to be used by MMCFS. Only needed if MMCFS support is enabled.
|
||||
o|MMCFS_CS_PORT +
|
||||
MMCFS_CS_PORT_ARRAY +
|
||||
MMCFS_CS_PIN +
|
||||
MMCFS_CS_PIN_ARRAY |Specify the port(s) and pin(s) to be used as chip select for MMCFS control of an SD/MMC card over SPI. Only needed if MMCFS support is enabled. If *MMCFS_NUM_CARDS* is
|
||||
greater than 1, you need to define *MMCFS_CS_PORT_ARRAY* and *MMCFS_CS_PIN_ARRAY* as C arrays with the ports and pins used as CS signals for each card in the system, otherwise you only
|
||||
need to define *MMCFS_CS_PORT* and *MMCFS_CS_PIN*
|
||||
|
||||
o|MMCFS_SPI_NUM +
|
||||
MMCFS_SPI_NUM_ARRAY |Specify the SPI peripheral(s) to be used by MMCFS. Only needed if MMCFS support is enabled. If *MMCFS_NUM_CARDS* is greater than 1, you need to define *MMCFS_SPI_NUM_ARRAY*
|
||||
as a C array with the IDs of each SPI peripheral used by each card in the system, otherwise you only need to define *MMCS_SPI_NUM*.
|
||||
|
||||
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:
|
||||
|
@ -44,10 +44,12 @@ in your <b>eLua</b> binary image, as described on the <a href="building.html">bu
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><b>New in 0.9</b>: it's possible to use more than one SD card on your <b>eLua</b> board. Refer to <a href="building.html">building page</a> for more details.</p><br/>
|
||||
<p>Once configured, connected, and <b>eLua</b> has started up, you are ready to work with the files on your card. To open a file on the SD/MMC card, all you need to do is to prefix its name with <i>/mmc/</i>, like this:</p>
|
||||
<p><pre><code># lua /mmc/info.lua </code></pre></p>
|
||||
<p>Similarly, if you wanted to access a text file <b>a.txt</b> from your card, you could use fopen like this:</p>
|
||||
<p><pre><code>f = fopen( "/mmc/a.txt", "rb" )</code></pre></p>
|
||||
<p><b>New in 0.9</b>: if more than one SD card is configured in the system, their corresponding names will end with a single digit that specifies the card ID in the system (<i>/mmc0</i>, <i>/mmc1</i> and so on).</p>
|
||||
$$FOOTER$$
|
||||
|
||||
|
||||
|
127
doc/en/simple_shell.txt
Normal file
127
doc/en/simple_shell.txt
Normal file
@ -0,0 +1,127 @@
|
||||
// $$HEADER$$
|
||||
The simple shell
|
||||
----------------
|
||||
The simple shell is a good compromise between functionality and the size of the eLua firmware image.
|
||||
A detailed description of the shell commands is given below.
|
||||
|
||||
[width="90%", cols="^, ^, ^, ^", grid="none"]
|
||||
|=============
|
||||
| link:#cmd_help[help] | link:#cmd_ver[ver] | link:#cmd_recv[recv] | link:#cmd_lua[lua]
|
||||
| link:#cmd_ls[ls] | link:#cmd_ls[dir] | link:#cmd_cat[cat] | link:#cmd_cat[type]
|
||||
| link:#cmd_cp[cp] | link:#cmd_exit[exit] | link:#cmd_wofmt[wofmt] | link:#cmd_mkdir[mkdir]
|
||||
|=============
|
||||
|
||||
[[cmd_help]]
|
||||
help
|
||||
~~~~
|
||||
By itself, it shows a list of all shell commands. If a shell command is given after *help*, it displays
|
||||
detailed information about the given command. Examples:
|
||||
|
||||
------
|
||||
# help
|
||||
# help ls
|
||||
------
|
||||
|
||||
[[cmd_ver]]
|
||||
ver
|
||||
~~~
|
||||
Print the version of the eLua image installed on the board. If the image is not an official one, an
|
||||
abbreviation of the git SHA1 revision used for building the image will be shown in the version number.
|
||||
|
||||
[[cmd_recv]]
|
||||
recv
|
||||
~~~~
|
||||
Allows you to receive from the PC running the terminal emulator program, a Lua file (either source or compiled
|
||||
bytecode) via XMODEM and either execute it on your board or save it to a file. To use this feature, your eLua
|
||||
target image must be built with support for XMODEM (see link:building.html[building] for details). Also, your
|
||||
terminal emulation program must support sending files via the XMODEM protocol. Both XMODEM with checksum
|
||||
and XMODEM with CRC are supported, but only XMODEM with 128 byte packets is allowed (XMODEM with 1K packets won't work).
|
||||
|
||||
To start the transfer, enter *recv* at the shell prompt. eLua will respond with "Waiting for file ...". At this point
|
||||
you can send the file to the eLua board via XMODEM. eLua will receive and execute the file. Don't worry when you
|
||||
see 'C' characters suddenly appearing on your terminal after you enter this command, this is how the XMODEM transfer
|
||||
is initiated. If you want to save the data to a file instead of executing it, use *recv <filename>* instead.
|
||||
|
||||
Since XMODEM is a protocol that uses serial lines, this command is not available if you're running your console
|
||||
over TCP/IP instead of a serial link. If you'd like to send compiled bytecode to eLua instead of source code,
|
||||
please check link:using.html#cross[this section] first. Examples:
|
||||
|
||||
--------------------
|
||||
$ recv
|
||||
$ recv /mmc/temp.lua
|
||||
--------------------
|
||||
|
||||
[[cmd_lua]]
|
||||
lua
|
||||
~~~
|
||||
This command allows you to start the Lua interpreter, optionally passing command line parameters, just as you would do
|
||||
from a desktop machine. There are some differences from the desktop Lua version in command line parsing:
|
||||
|
||||
- the command line can't be longer than 50 chars
|
||||
- character escaping is not implemented. For example, the next command won't work because of the ' (simple quotes) escape sequences:
|
||||
|
||||
eLua# lua -e 'print(\'Hello, World!\')' -i
|
||||
Press CTRL+Z to exit Lua
|
||||
lua: (command line):1: unexpected symbol near ''
|
||||
+
|
||||
However, if you use both '' (simple quotes) and "" (double quotes) for string quoting, it will work:
|
||||
|
||||
eLua# lua -e 'print("Hello, World")' -i
|
||||
Press CTRL+Z to exit Lua
|
||||
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
|
||||
Hello, World
|
||||
|
||||
- if you want to execute a file from the link:"arch_romfs.html"[ROM file system] (or from another file system), remember to prefix it
|
||||
with _/rom_. For example, to execute *hello.lua*, do this:
|
||||
|
||||
eLua# lua /rom/hello.lua
|
||||
|
||||
[[cmd_ls]]
|
||||
ls or dir
|
||||
~~~~~~~~~
|
||||
Shows a list of all the files in the file systems used by eLua, as well as their size and the total size of the given file system.
|
||||
|
||||
[[cmd_cat]]
|
||||
cat or type
|
||||
~~~~~~~~~~~
|
||||
Prints the content of (usually text) files on the console. Examples:
|
||||
|
||||
-------------------------------------
|
||||
eLua# cat /rom/test.lua /mmc/temp.txt
|
||||
eLua# cat /mmc/autorun.lua
|
||||
-------------------------------------
|
||||
|
||||
[[cmd_cp]]
|
||||
cp
|
||||
~~
|
||||
Copies a file to another file. This command can be used to copy files between different file systems (for example between the MMC file
|
||||
system and the RFS file system). The first argument is the source, the second one is the destination. Example:
|
||||
|
||||
------------------------------------
|
||||
eLua# cp /rom/data.bin /rfs/data.bin
|
||||
------------------------------------
|
||||
|
||||
Note that both *source* and *destination* must be file names (for example, _cp /rom/data.bin /rfs_ will not work, since _/rfs_ is not
|
||||
a valid file name).
|
||||
|
||||
[[cmd_exit]]
|
||||
exit
|
||||
~~~~
|
||||
Exits the shell. This only makes sense if eLua is compiled with terminal support over TCP/IP , as it closes the telnet session to the
|
||||
eLua board. Otherwise it just terminates the shell and blocks forever until you reset your board.
|
||||
|
||||
[[cmd_wofmt]]
|
||||
wofmt
|
||||
~~~~~
|
||||
"Formats" the link:arch_wofs.html[WOFS file system], erasing its current contents. The user is asked to confirm this operation.
|
||||
|
||||
[[cmd_mkdir]]
|
||||
mkdir
|
||||
~~~~~
|
||||
Creates a new directory. The filesystem must have directory support in order fir this to work. Example:
|
||||
|
||||
--------------------
|
||||
elua# mkdir /mmc/dir
|
||||
--------------------
|
||||
|
||||
// $$FOOTER$$
|
@ -41,6 +41,7 @@ The list of CPUs and boards currently supported by eLua is given below:
|
||||
| _STM32F103RE | Cortex-M3 o| STM32 | _ET-STM32Stamp | _sok
|
||||
| _AT32UC3A0128 | AVR32 o| AVR32 | _Mizar32 | _sok
|
||||
| _I386 | x86 o| i386 | PCs/emulators | _sok
|
||||
| _LM3S9D92 | Cortex-M3 o| LM3S | _SolderCore | _sok
|
||||
|=====================================================================================
|
||||
|
||||
[[systmr]]
|
||||
@ -91,6 +92,7 @@ The relationship between a module and its implementation on a particular platfor
|
||||
| _STM32F103ZE | _sok | _sok | _sok | _sok | _sok | _sni | _sok | _sok | _sok | _sok | _sok | _sok | _sni | _sok | _sok | _sni
|
||||
| _STM32F103RE | _sok | _sok | _sok | _sok | _sok | _sni | _sok | _sok | _sok | _sok | _sok | _sok | _sok | _sok | _sok | _sni
|
||||
| _I386 | _sna | _sna | _sni | _sni | _sna | _sni | _sni | _sna | _sok | _sok | _sok | _sok | _sna | _sni | _sna | _sna
|
||||
| _LM3S9D92 | _sok | _snt | _sok | _sok | _sok | _sok | _sok | _snt | _sok | _sok | _sok | _sok | _sok | _snt | _sok | _sni
|
||||
|================================================================================================================================================
|
||||
|
||||
[[plat_notes]]
|
||||
|
@ -1,5 +1,11 @@
|
||||
$$HEADER$$
|
||||
<h3>Building GCC for i386</h3>
|
||||
|
||||
<p><span class="warning">NOTE</span>: these instructions are obsolete. Most likely,
|
||||
they are not applicable to newer versions of the various components (binutils, gcc,
|
||||
newlib). If you need an i386 toolchain, there is rarely a need to build one yourself.
|
||||
Instead, get a pre-built one, for example from <a href="https://sourcery.mentor.com/GNUToolchain/subscription28188?lite=IA32">Mentor Graphics</a>.</p><br />
|
||||
|
||||
<p>At first, the idea of an i386 "cross" compiler under Linux seems
|
||||
strange. After all, you're already running Linux on a i386 compatible
|
||||
architecture. But the compiler is sometimes tied in mysterious ways
|
||||
|
@ -1,6 +1,12 @@
|
||||
$$HEADER$$
|
||||
<h3>Building GCC for ARM</h3>
|
||||
|
||||
<p><span class="warning">NOTE</span>: these instructions are obsolete. Most likely,
|
||||
they are not applicable to newer versions of the various components (binutils, gcc,
|
||||
newlib). If you need an ARM toolchain, there is rarely a need to build one yourself.
|
||||
Instead, get a pre-built one, for example from <a href="http://www.mentor.com/embedded-software/sourcery-tools/sourcery-codebench/editions/lite-edition/request?id=e023fac2-e611-476b-a702-90eabb2aeca8&downloadlite=scblite2012&fmpath=/embedded-software/sourcery-tools/sourcery-codebench/editions/lite-edition/form">Mentor Graphics</a> or
|
||||
<a href="https://launchpad.net/gcc-arm-embedded/">gcc-arm-embedded</a>.</p><br />
|
||||
|
||||
<p> This tutorial explains how you can create a GCC+Newlib toolchain
|
||||
that can be used to compile programs for the ARM architecture, thus
|
||||
making it possible to compile programs for the large number of ARM CPUs
|
||||
|
@ -1,5 +1,12 @@
|
||||
$$HEADER$$
|
||||
<h3>Building GCC for Cortex</h3>
|
||||
|
||||
<p><span class="warning">NOTE</span>: these instructions are obsolete. Most likely,
|
||||
they are not applicable to newer versions of the various components (binutils, gcc,
|
||||
newlib). If you need an ARM toolchain, there is rarely a need to build one yourself.
|
||||
Instead, get a pre-built one, for example from <a href="http://www.mentor.com/embedded-software/sourcery-tools/sourcery-codebench/editions/lite-edition/request?id=e023fac2-e611-476b-a702-90eabb2aeca8&downloadlite=scblite2012&fmpath=/embedded-software/sourcery-tools/sourcery-codebench/editions/lite-edition/form">Mentor Graphics</a> or
|
||||
<a href="https://launchpad.net/gcc-arm-embedded/">gcc-arm-embedded</a>.</p><br />
|
||||
|
||||
<p>This tutorial explains how you can create a GCC+Newlib toolchain
|
||||
that can be used to compile programs for the Cortex (Thumb2)
|
||||
architecture, thus making it possible to use GCC to compile programs
|
||||
|
@ -1,358 +0,0 @@
|
||||
$$HEADER$$
|
||||
<h3>Using eLua</h3>
|
||||
<p>So, you already <a href="building.html">built</a> and <a href="installing.html">installed</a>
|
||||
<b>eLua</b>, now it is time to (finally) have some fun with it :)
|
||||
You can compile <b>eLua</b> with either console over UART (the default and by far the most popular)
|
||||
or console over TCP/IP (still experimental, but working quite well). See <a href="building.html">building eLua</a> for details on how to select
|
||||
the second option above.</p>
|
||||
<a name="uart"><h3>Using eLua over serial connections</h3></a>
|
||||
<p>All you need to use <b>eLua</b> over a serial connection is your <b>eLua</b>
|
||||
board connected to a PC running a terminal emulator program.<br>If
|
||||
you're using Windows, we recommend <a href="http://www.ayera.com/teraterm/">TeraTerm</a>.
|
||||
It's a freeware, it's very powerful and also easy to use. The native Hyper Terminal progam can do
|
||||
too, as well as any most other terminal emulator programs.<br>On
|
||||
Linux,
|
||||
you'll probably be stucked with minicom. It is not exactly intuitive
|
||||
and it runs in text mode, but it's still very powerful. If you
|
||||
google for "minicom tutorial" you'll get the hang of it in no time. You
|
||||
can try any other terminal emulator, as long as you set it up
|
||||
properly and it gives you the option of transferring files
|
||||
via XMODEM, which is what <b>eLua</b> uses at the moment. These are the main
|
||||
settings you need to look at:</p>
|
||||
|
||||
<ul><li>port setup: 115200 baud (38400 for <a href="installing_str7.html">STR7)</a>, 8N1(8 data bits, no parity, one stop bit). </li><li>hardware flow control: none</li><li>newline handling: "CR" on receive, "CR+LF" on send (some terminal programs won't give you a choice here). </li></ul>
|
||||
|
||||
|
||||
<p>Also, depending on the type of your board, you'll need some way to
|
||||
connect the board to a serial port on your PC or to USB if you're
|
||||
using an USB to serial converter. For example (as already explained <a href="installing_lm3s.html">here)</a>,
|
||||
the USB port on the LM3Sxxxx boards is dual, so you can use it as an USB
|
||||
to serial converter after downloading your firmware, thus you don't
|
||||
need any other type of connection. The same is true for the
|
||||
STR9-Comstick board. On the other hand, for the SAM7-EX256 board you'll
|
||||
need to connect a serial cable to the "RS232" connector, provided that
|
||||
the jumpers are already set as explained <a href="installing_at91sam7x.html">here</a> and on the MOD711 you will need to add an RS232 converter chip.
|
||||
There's no universal rule here, it all depends on your board. Feel free to
|
||||
ask if you need help in our <a href="https://lists.berlios.de/mailman/listinfo/elua-dev">discussion
|
||||
list</a>
|
||||
</p>
|
||||
<a name="tcpip"><h3>Using eLua over TCP/IP connections</h3></a>
|
||||
<p>Things are even easier if you decide to enable console over TCP/IP:</p>
|
||||
<ul>
|
||||
<li>make sure you know the address of your board. If you enabled static IPs (see <a href="building.html">building</a>) remember what you chose for the static IP; if DHCP
|
||||
(the default) is used instead, your
|
||||
DHCP server should've added the address of the <b>eLua</b> board to your DNS. The board name is always "elua"
|
||||
in our code examples too, so if you execute "ping elua" from a shell you should see that the board is
|
||||
alive.</li>
|
||||
<li>telnet to the address of the board (or simply "telnet elua" if DHCP is used), and you'll be greeted with the shell prompt (if the shell is
|
||||
enabled; see the next paragraph for details).
|
||||
Note that you can only have one active telnet session to the <b>eLua</b> board at a given time.</li>
|
||||
</ul>
|
||||
|
||||
<p>If you're under Windows, make sure you're using a proper telnet client, which basically means "just about everything <b>but</b> the
|
||||
built-in telnet client".
|
||||
<a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/">PuTTY</a> is a very good and popular choice.</p>
|
||||
|
||||
<a name="pc"><h3>Using standalone eLua on PC</h3></a>
|
||||
<p>If you build <b>eLua</b> for the i386 platform, you can boot your PC directly in <b>eLua</b>! No underlying OS, nothing but plain <b>eLua</b>. It won't have any actual peripherals to
|
||||
access, but it can use the <b>term</b> module to run <i>hangman.lua</i> and <i>life.lua</i>, as well as other
|
||||
code examples and games, which makes it a nice demo :) Follow <a href="installing_i386.html">
|
||||
this link</a> for specific informations about the i386 port. </p>
|
||||
|
||||
<a name="shell"><h3>The eLua shell</h3></a>
|
||||
<p>No matter what's your physical connection (serial, TCP/IP or you PC's monitor after booting <b>eLua</b>), after you setup the PC-<b>eLua</b> board connection and press
|
||||
the "RESET" button on your board or simply press ENTER if you're using the serial connection, you should see the <b>eLua</b> shell prompt (if you enabled the shell in your build, as described <a href="building.html">here</a>). The shell is a simple
|
||||
interactive command interpreter that allows you to:</p>
|
||||
<ul>
|
||||
<li>get help on shell usage with the help command</li>
|
||||
<li>query the eLua version running on your platform</li>
|
||||
<li>upload a Lua source file via XMODEM and execute in on board</li>
|
||||
<li>run the Lua interpreter in interactive mode just like you'd do on a desktop machine</li>
|
||||
<li>run a Lua program from the eLua File System</li>
|
||||
<li>list file names and sizes on eLua file systems</li>
|
||||
<li>print contents from a (text) file in the eLua File System</li>
|
||||
<li>list file contents</li>
|
||||
</ul>
|
||||
<p>A detailed description of the current shell commands is given below.</p>
|
||||
|
||||
<h2>help</h2>
|
||||
<p>Show a list of all shell commands.</p>
|
||||
<pre><code>$ help</code></pre>
|
||||
|
||||
<h2>ver</h2>
|
||||
<p>Print the version of the <b>eLua</b> image installed on the board. Currently, the version only increments for official releases, so if there's inter-release code in the
|
||||
development tree, this isn't reflected in the version number.</p>
|
||||
<pre><code>$ ver</code></pre>
|
||||
|
||||
<h2>recv</h2>
|
||||
<p>Allows you to receive from the PC running the terminal emulator program, a Lua file (either source or compiled bytecode) via
|
||||
XMODEM and execute it on your board.</p>
|
||||
<pre><code>$ recv</code></pre>
|
||||
<p>To use this, your <b>eLua</b> target image must be built with support for XMODEM
|
||||
(see <a href="building.html">building</a> for details). Also, your terminal emulation program must
|
||||
support sending files via the XMODEM protocol. Both XMODEM with checksum and XMODEM with CRC are supported, but only XMODEM with 128
|
||||
byte packets is allowed (XMODEM with 1K packets won't work).
|
||||
To use this feature, enter "recv" at the shell prompt. <b>eLua</b> will respond with
|
||||
"Waiting for file ...". At this point you can send the file to the eLua board
|
||||
via XMODEM. eLua will receive and execute the file. Don't worry when you see 'C'
|
||||
characters suddenly appearing on your terminal after you enter this command,
|
||||
this is how the XMODEM transfer is initiated.<br>
|
||||
Since XMODEM is a protocol that uses serial lines, this command is not available if you're using terminal over TCP/IP.<br>
|
||||
If you'd like to send compiled bytecode to <b>eLua</b> instead of source code, please check <a href="using.html#cross">this section</a> first.
|
||||
</p>
|
||||
|
||||
<h2>lua</h2>
|
||||
<p>This command allows you to start the Lua interpreter, optionally passing command line parameters, just
|
||||
as you would do from a desktop machine.</p>
|
||||
<pre><code>$ lua</code></pre>
|
||||
<p> There are some diferences from the the Lua in desktop version:</p>
|
||||
<ul>
|
||||
<li>the command line can't be longer than 50 chars</li>
|
||||
<li>character escaping is not implemented. For example, the next command won't work
|
||||
because of the ' (simple quotes) escape sequences:
|
||||
<pre>
|
||||
<code>eLua# lua -e 'print(\'Hello, World!\')' -i
|
||||
Press CTRL+Z to exit Lua
|
||||
lua: (command line):1: unexpected symbol near ''
|
||||
</code>
|
||||
</pre>
|
||||
<p>However, if you use both '' (simple quotes) and "" (double quotes) for string quoting, it will work:</p>
|
||||
<pre>
|
||||
<code>eLua# lua -e 'print("Hello, World")' -i
|
||||
Press CTRL+Z to exit Lua
|
||||
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
|
||||
Hello,World
|
||||
</code>
|
||||
</pre></li>
|
||||
<li>
|
||||
If you want to execute a file from the <a href="arch_romfs.html">ROM file system</a> (or from another file system), remember to prefix it with <i>/rom</i>. For example, to execute <b>hello.lua</b>, do this:
|
||||
<pre><code>$ lua /rom/hello.lua</code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>ls or dir</h2>
|
||||
<p>Shows a list of all the files in the file systems used by <b>eLua</b>, as well as their size and the total size of the given file system.</p>
|
||||
<pre><code>$ ls
|
||||
$ dir
|
||||
</code></pre>
|
||||
|
||||
<h2>cat or type</h2>
|
||||
<p>Prints the content of (usually text) files on the console.</p>
|
||||
<pre><code>$ cat <i>filename1</i> [<i>filename2 filename3 ...</i>]
|
||||
$ type <i>filename1</i> [<i>filename2 filename3 ...</i>]</code></pre>
|
||||
|
||||
<h2>cp</h2>
|
||||
<p>Copies a file to another file. This command can be used to copy files between different file systems (for example between the MMC file system and the RFS file system).</p>
|
||||
<pre><code>$ cp <i>source</i> <i>destination</i></code></pre>
|
||||
<p>Note that both <b>source</b> and <b>destination</b> must be file names.</p>
|
||||
|
||||
<h2>exit</h2>
|
||||
<p>Exits the shell. This only makes sense if <b>eLua</b> is compiled with terminal support over TCP/IP , as it closes the telnet session to the <b>eLua</b> board. Otherwise it just
|
||||
terminates the shell and blocks forever until you reset your board.</p>
|
||||
<pre><code>$ exit</code></pre>
|
||||
|
||||
<h2>wofmt</h2>
|
||||
<p>"Formats" the <a href="arch_wofs.html">WOFS file system</a>, erasing its current contents. The user is asked to confirm this operation.</p>
|
||||
<pre><code>$ wofmt</code></pre>
|
||||
|
||||
<a name="cross"><h3>Cross-compiling your eLua programs</h3></a>
|
||||
<p><i>Cross-compilation</i> is the process of compiling a program on one hardware platform for a
|
||||
different hardware platform. For example, the process of compiling the <b>eLua</b> binary image on
|
||||
a PC for your <b>eLua</b> board is cross-compiling. Lua can be cross-compiled, too. By cross-compiling Lua
|
||||
to bytecode on a PC and executing the resulting bytecode directly on your <b>eLua</b>
|
||||
board you have some important advantages:</p>
|
||||
<ul>
|
||||
<li><b>speed</b>: the Lua compiler on the <b>eLua</b> board doesn't have to compile your Lua
|
||||
source code, it just executes the compiled bytecode.</li>
|
||||
<li><b>memory</b>: f you're executing bytecode directly, no more
|
||||
memory is "wasted" on the <b>eLua</b> board for compiling the Lua code to bytecode.
|
||||
Many times this could be a "life saver". If you're trying to run Lua code
|
||||
directly on your board and you're getting "not enough memory" errors, you
|
||||
might be able to overcome this by compiling the Lua program on the PC and
|
||||
running the bytecode instead. Also, compiling large Lua programs on your
|
||||
<b>eLua</b> board can lead to stack overflows, which in turn leads to very
|
||||
hard to find errors.</li>
|
||||
</ul>
|
||||
<p>In order to use cross-compilation, the two Lua targets (in this case your desktop PC and your <b>eLua</b> board) must be compatible
|
||||
(they should have the same data types, with the same size and the same memory
|
||||
representation). This isn't true all the time. For example, some gcc toolchains for ARM targets use a very specific representation for double precision numbers (called FPA
|
||||
format) by default, which makes bytecode files generated on the PC with the regular Lua compiler useless on
|
||||
ARM boards. Other toolchains don't have this problem. Other targets (like AVR32) are big endian, as opposed to Intel PCs that are little endian.</p>
|
||||
<p>To overcome this kind of problems, a "Lua cross-compilation patch" was posted on the
|
||||
Lua mailing list a while ago, and it was further modified as part of the <b>eLua</b>
|
||||
project to work with ARM targets. This is how to use it (the following
|
||||
instructions were tested on Linux, not Windows, but they should work on Windows
|
||||
too with little or no tweaking):</p>
|
||||
<ul>
|
||||
<li>first, make sure that your PC has already a build system installed (gcc,
|
||||
binutils, libc, headers...). You'll also need scons. The good news is that
|
||||
you should have it already installed, since otherwise you won't be able to
|
||||
build even regular <b>eLua</b> (see <a href="building.html">building</a> for more in-depth instructions).</li>
|
||||
<li>from the <b>eLua</b> base directory, issue this command:
|
||||
<pre><code>$ scons -f cross-lua.py</code></pre></li>
|
||||
</ul>
|
||||
<p>You should get a file called <i>luac</i> in the same directory after this. It's almost the same as the regular Lua compiler, but it has a few arguments that deal with differences between different targets (shown below in bold):</p>
|
||||
<pre><code>usage: ./luac [options] [filenames].
|
||||
Available options are:
|
||||
- process stdin
|
||||
-l list
|
||||
-o name output to file 'name' (default is "luac.out")
|
||||
-p parse only
|
||||
-s strip debug information
|
||||
-v show version information
|
||||
<b>-cci bits cross-compile with given integer size
|
||||
-ccn type bits cross-compile with given lua_Number type and size
|
||||
-cce endian cross-compile with given endianness ('big' or 'little')</b>
|
||||
-- stop handling options</code></pre>
|
||||
<p>All it's left to do now is to use the table below to figure out what are the right parameters for using the cross-compiler:</p>
|
||||
<table style="text-align: left;" class="table_center">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th style="text-align: left;">eLua image type</th>
|
||||
<th style="text-align: center;">Architecture</th>
|
||||
<th style="text-align: center;">Compiler</th>
|
||||
<th style="text-align: center;">Command</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Floating point (lua)</td>
|
||||
<td>ARM7TDMI<br>Cortex-M3<br>ARM966E-S</td>
|
||||
<td><a href="toolchains.html">arm-gcc</a></td>
|
||||
<td><code>./luac -ccn float_arm 64 -cce little -o <script.luac> -s <script.lua></code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Floating point (lua)</td>
|
||||
<td>ARM7TDMI<br>Cortex-M3<br>ARM966E-S</td>
|
||||
<td><a href="toolchains.html">codesourcery</a></td>
|
||||
<td><code>./luac -ccn float 64 -cce little -o <script.luac> -s <script.lua></code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Integer (lualong)</td>
|
||||
<td>ARM7TDMI<br>Cortex-M3<br>ARM966E-S</td>
|
||||
<td><a href="toolchains.html">arm-gcc<br>codesourcery</a></td>
|
||||
<td><code>./luac -ccn int 32 -cce little -o <script.luac> -s <script.lua></code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Floating point (lua)</td>
|
||||
<td>AVR32</td>
|
||||
<td><a href="toolchains.html">avr32-gcc</a></td>
|
||||
<td><code>./luac -ccn float 64 -cce big -o <script.luac> -s <script.lua></code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Integer (lualong)</td>
|
||||
<td>AVR32</td>
|
||||
<td><a href="toolchains.html">avr32-gcc</a></td>
|
||||
<td><code>./luac -ccn int 32 -cce big -o <script.luac> -s <script.lua></code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>(note that if for some reason you want to cross-compile <b>eLua</b> for the x86 target you can use the regular Lua compiler).<br>
|
||||
You can omit the <i>-s</i> (strip) parameter from compilation, but this will result in larger bytecode files (as the debug information is not stripped if you don't use <i>-s</i>).</p>
|
||||
<p>You can use your bytecode file in two ways:</p>
|
||||
<ul>
|
||||
<li>write it to <a href="arch_romfs.html">the ROM file system</a> and execute it from there.</li>
|
||||
<li>use the <i>recv</i> command from <a href="using.html#shell">the shell</a> to upload it to the board using a serial connection.</li>
|
||||
<li>write it to an sd/mmc card and, if your board supports it, execute it
|
||||
from there.</li>
|
||||
</ul>
|
||||
|
||||
<a name="rpc"><h3>Controlling eLua with LuaRPC</h3></a>
|
||||
<p><i>Remote procedure calls</i> (RPC) allow one program to communicate with another and call functions or subroutines within the second program. For example one might want to programmatically control an array of LEDs connected to an eLua embedded device from a desktop Lua state. A simple implementation might be a protocol that would allow one to send numeric or text-based commands that would cause code to be executed in eLua that would change the state of the LEDs. As one needs new commands to change these LEDs, one would need to upload a new Lua program to handle changing functionality. In contrast to this ad-hoc method for remote calls, LuaRPC provides a more general way to manipulate the state and execution of a remote Lua environment.</p>
|
||||
<p>When a client is connected to a LuaRPC server, it can interact with it in the following ways:</p>
|
||||
<ul>
|
||||
<li>assign values to new or existing variables in the server state</li>
|
||||
<li>get values from variables in the server state</li>
|
||||
<li>call functions to be executed on the server side using parameters of serializable types, with return values being sent back to the client</li>
|
||||
<li>create local userdata helpers (aliases) which provide short-hand access to remote state</li>
|
||||
</ul>
|
||||
|
||||
<h2>Building the Desktop Client/Server</h2>
|
||||
<ul>
|
||||
<li>first, make sure that your PC has already a build system installed (gcc,
|
||||
binutils, libc, headers...). You'll also need scons. The good news is that
|
||||
you should have it already installed, since otherwise you won't be able to
|
||||
build even regular <b>eLua</b> (see <a href="building.html">building</a> for more in-depth instructions).</li>
|
||||
<li>from the <b>eLua</b> base directory, issue this command:
|
||||
<pre><code>$ scons -f rpc-lua.py</code></pre></li>
|
||||
</ul>
|
||||
<p>You should get a file called <i>luarpc</i> in the same directory which, when started, should give you a normal Lua interpreter with a built-in rpc module.</p>
|
||||
|
||||
<h2>Building eLua with RPC Boot</h2>
|
||||
|
||||
<p>See <a href="building.html">building</a> for details and requirements for the building process. In order to boot into RPC mode, the RPC <a href="building.html#components">component</a> will need to be enabled, and appropriate <a href="building.html#static">static configuration data</a> need to be set. To build <b>eLua</b> to boot into RPC mode, include
|
||||
<b>boot=luarpc</b> in the <a href="building.html#buildoptions">build options</a>.</p>
|
||||
|
||||
|
||||
<h2>LuaRPC Basics</h2>
|
||||
<p>In terms of the LED example from the beginning of this section, one could directly call pio module functions from the desktop side, experimenting with responses. If the experimentation developed into a program this could be tested both on the desktop side and on the microcontroller by making aliases to eLua modules in local Lua state. Such aliasing can be done as follows:</p>
|
||||
<pre><code>-- open connection from Linux host serial port to eLua
|
||||
slave,err = rpc.connect("/dev/ttyUSB0")
|
||||
|
||||
-- make a local helper pointing to pio module in eLua
|
||||
pio = slave.pio
|
||||
|
||||
-- define function to set direction and value of port B
|
||||
function set_port_val(val)
|
||||
pio.port.setdir( pio.OUTPUT, pio.PB )
|
||||
pio.port.setval( val, pio.PB )
|
||||
end
|
||||
|
||||
set_port_val(23)</pre></code>
|
||||
<p>When we run this locally, calling and indexing helpers are translated into appropriate actions on the server. If we were done with modifications to the above function and wanted it to execute in eLua rather than using local aliases, which will result in a great deal of RPC traffic every time the function is called, we can send the function to the remote side:</p>
|
||||
<pre><code>-- cross-compile local chunk for function and send to server
|
||||
slave.set_port_val = set_port_val
|
||||
|
||||
-- call function on server device
|
||||
slave.set_port_val(23)</pre></code>
|
||||
|
||||
<p>In addition to functions, we can also copy most other Lua types from client to server using simple assignment. Due to Lua's internal workings the opposite operation of copying Lua types from server to client requires an additional metamethod:</p>
|
||||
<pre><code>-- make table on remote server
|
||||
slave.remote_table = {}
|
||||
|
||||
-- put data in table
|
||||
slave.remote_table.rval = 42
|
||||
|
||||
-- get data back from server, print
|
||||
local_table = slave.remote_table:get()
|
||||
print(local_table.rval)</pre></code>
|
||||
|
||||
<p>While these examples are trivial, they serve to illustrate a compelling development paradigm that gives one a great deal of flexibility for development and testing with an embedded target.</p>
|
||||
|
||||
<h2>Serializable Lua Types</h2>
|
||||
<p>Most Lua types can be transferred between the client and server states. The following list indicates which ones can be transferred, and where there are known exceptions:</p>
|
||||
|
||||
<table style="text-align: left;" class="table_center">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th style="text-align: left;">Serializable Types</th>
|
||||
<th style="text-align: center;">Exceptions and Notes</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>numbers</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>strings</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>booleans</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>tables</td>
|
||||
<td>no circular references</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>functions</td>
|
||||
<td>no upvalues</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>nil</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
$$FOOTER$$
|
||||
|
254
doc/en/using.txt
Normal file
254
doc/en/using.txt
Normal file
@ -0,0 +1,254 @@
|
||||
// $$HEADER$$
|
||||
Using eLua
|
||||
----------
|
||||
So, you already link:building.html[built] and link:installing.html[installed] eLua, now it is time to (finally) have some fun with it :)
|
||||
You can compile eLua with either console over UART (the default and by far the most popular) or console over TCP/IP (still experimental,
|
||||
but working quite well). See link:building.html[building eLua] for details on how to choose between serial and TCP/IP console.
|
||||
|
||||
[[uart]]
|
||||
Using eLua over serial connections
|
||||
----------------------------------
|
||||
All you need to use eLua over a serial connection is your eLua board connected to a PC running a terminal emulator program.
|
||||
|
||||
If you're using Windows, we recommend http://www.ayera.com/teraterm/[TeraTerm]. It's a freeware, it's very powerful and
|
||||
also easy to use. The native Hyper Terminal progam can do too, as well as any most other terminal emulator programs.
|
||||
|
||||
On Linux, you'll probably be stucked with minicom. It is not exactly intuitive and it runs in text mode, but it's still
|
||||
very powerful. If you google for "minicom tutorial" you'll get the hang of it in no time. You can try any other terminal emulator,
|
||||
as long as you set it up properly and it gives you the option of transferring files via XMODEM, which is what eLua uses at the
|
||||
moment. These are the main settings you need to look at:
|
||||
|
||||
- port setup: 115200 baud (38400 for link:installing_str7.html[STR7]), 8N1(8 data bits, no parity, one stop bit).
|
||||
- flow control: none, unless your eLua image is configured to use hardware flow control/
|
||||
- newline handling: "CR" on receive, "CR+LF" on send (some terminal programs won't give you a choice here).
|
||||
|
||||
Also, depending on the type of your board, you'll need some way to connect the board to a serial port on your PC or to USB if
|
||||
you're using an USB to serial converter. For example (as already explained link:installing_lm3s.html[here]), the USB port on
|
||||
the LM3Sxxxx boards is dual, so you can use it as an USB to serial converter after downloading your firmware, thus you don't
|
||||
need any other type of connection. The same is true for the STR9-comStick board. On the other hand, for the SAM7-EX256 board you'll
|
||||
need to connect a serial cable to the "RS232" connector, provided that the jumpers are already set as explained
|
||||
link:installing_at91sam7x.html[here] and on the MOD711 you will need to add an RS232 converter chip. There's no universal rule here,
|
||||
it all depends on your board. Feel free to ask if you need help in our https://lists.berlios.de/mailman/listinfo/elua-dev"[discussion list].
|
||||
|
||||
[[tcpip]]
|
||||
Using eLua over TCP/IP connections
|
||||
----------------------------------
|
||||
Things are even easier if you decide to enable console over TCP/IP:
|
||||
|
||||
- make sure you know the address of your board. If you enabled static IPs (link:building.html[building]) remember what you chose for the
|
||||
static IP; if DHCP (the default) is used instead, your DHCP server should've added the address of the eLua board to your DNS. The board
|
||||
name is always "elua" in our code examples too, so if you execute "ping elua" from a shell you should see that the board is alive.
|
||||
- telnet to the address of the board (or simply "telnet elua" if your DNS is properly set), and you'll be greeted with the shell prompt
|
||||
(if the shell is enabled; see the next paragraph for details). Note that you can only have one active telnet session to the eLua board
|
||||
at any given time.
|
||||
|
||||
If you're under Windows, make sure you're using a proper telnet client, which basically means "just about everything *but* the
|
||||
built-in telnet client". http://www.chiark.greenend.org.uk/~sgtatham/putty/[PuTTY] is a very good and popular choice.
|
||||
|
||||
[[pc]]
|
||||
Using standalone eLua on PC
|
||||
---------------------------
|
||||
If you build eLua for the i386 platform, you can boot your PC directly in eLua! No underlying OS, nothing but plain eLua.
|
||||
It won't have any actual peripherals to access, but it can use the *term* module to run _hangman.lua_ and _life.lua_, as well
|
||||
as other code examples and games, which makes it a nice demo :) Follow link:installing_i386.html[this link] for specific
|
||||
informations about the i386 port.
|
||||
|
||||
[[shell]]
|
||||
The eLua shell
|
||||
--------------
|
||||
No matter what's your physical connection (serial, TCP/IP or you PC's monitor after booting eLua), after you setup the
|
||||
PC-eLua board connection and press the "RESET" button on your board or simply press ENTER if you're using the serial connection,
|
||||
you should see the eLua< shell prompt (if you enabled the shell in your build, as described link:building.html[here]). The shell
|
||||
is a simple interactive command interpreter that allows you to:
|
||||
|
||||
- get help on shell usage with the help command,
|
||||
- query the eLua version running on your platform,
|
||||
- upload a Lua source file via XMODEM and execute in on board,
|
||||
- run the Lua interpreter in interactive mode just like you'd do on a desktop machine.
|
||||
- run a Lua program from a link:filesystems.html[file system].
|
||||
- list file names and sizes on eLua file systems.
|
||||
- list file contents
|
||||
- execute file operations (copy, rename, move, delete)
|
||||
|
||||
eLua has two different versions of the shell (check link:building.html[here] for information about how to enable each of them):
|
||||
|
||||
- the basic version is small (to keep the eLua image small), but functional. The documentation for the basic shell can be found link:simple_shell.html[here].
|
||||
- the advanced shell (new in *0.9*) adds file masks, file operations and other goodies to the basic shell. If you have enough flash on your
|
||||
MCU, this is almost certainly the version that you want. The documentation for the advanced shell can be found link:advanced_shell.html[here].
|
||||
|
||||
[[cross]]
|
||||
Cross-compiling your eLua programs
|
||||
----------------------------------
|
||||
_Cross-compilation_ is the process of compiling a program on one hardware platform for a different hardware platform (for
|
||||
example, the process of compiling the eLua binary image ona PC for your eLua board). Lua can be cross-compiled, too. By
|
||||
cross-compiling Lua to bytecode on a PC and executing the resulting bytecode directly on your eLua board you have some
|
||||
important advantages:
|
||||
|
||||
- speed: the Lua compiler on the eLua board doesn't have to compile your Lua source code, it just executes the compiled bytecode.
|
||||
- memory: if you're executing bytecode directly, no more memory is "wasted" on the eLua board for compiling the Lua code
|
||||
to bytecode. Many times this could be a "life saver". If you're trying to run Lua code directly on your board and you're
|
||||
getting "not enough memory" errors, you might be able to overcome this by compiling the Lua program on the PC and running the
|
||||
bytecode instead. Also, compiling large Lua programs on your eLua board can lead to stack overflows, which in turn leads to very
|
||||
hard to find errors.
|
||||
|
||||
WARNING: Currently, cross-compilation is not implemented for 64-bit integer only Lua (lualonglong).
|
||||
|
||||
In order to use cross-compilation, the two Lua targets (in this case your desktop PC and your eLua board) must be compatible
|
||||
(they should have the same data types, with the same size and the same memory representation). This isn't true all the time.
|
||||
For example, some gcc toolchains for ARM targets use a very specific representation for double precision numbers (called FPA
|
||||
format) by default, which makes bytecode files generated on the PC with the regular Lua compiler useless on ARM boards. Other
|
||||
toolchains don't have this problem. Other targets (like AVR32) are big endian, as opposed to Intel PCs that are little endian.
|
||||
|
||||
To overcome these kind of problems, a "Lua cross-compilation patch" was posted on the Lua mailing list a while ago, and it was
|
||||
further modified as part of the eLua project to work with ARM targets. This is how to use it (the following instructions were
|
||||
tested on Linux, not Windows, but they should work on Windows too with little or no tweaking):
|
||||
|
||||
- first, make sure that your PC has already a build system installed (gcc, binutils, libc, headers...). You'll also need scons.
|
||||
The good news is that you should have it already installed, since otherwise you won't be able to build even regular eLua
|
||||
(see link:building.html[building] for more in-depth instructions).
|
||||
|
||||
- from the eLua base directory, issue this command:
|
||||
|
||||
$ scons -f cross-lua.py
|
||||
|
||||
You should get a file called _luac_ in the same directory as a result. It's almost the same as the regular Lua compiler, but it
|
||||
has a few arguments that deal with differences between different targets (shown below in bold):
|
||||
|
||||
[subs="quotes"]
|
||||
------------------------------------
|
||||
usage: ./luac [options] [filenames].
|
||||
Available options are:
|
||||
- process stdin
|
||||
-l list
|
||||
-o name output to file 'name' (default is "luac.out")
|
||||
-p parse only
|
||||
-s strip debug information
|
||||
-v show version information
|
||||
*-cci bits cross-compile with given integer size*
|
||||
*-ccn type bits cross-compile with given lua_Number type and size*
|
||||
*-cce endian cross-compile with given endianness ('big' or 'little')*
|
||||
-- stop handling options
|
||||
------------------------------------
|
||||
|
||||
All it's left to do now is to use the table below to figure out what are the right parameters for using the cross-compiler:
|
||||
|
||||
[width="90%", cols="^,^,^,2^", options="header"]
|
||||
|===============================================================
|
||||
^|Image type ^|Arch ^|Compiler ^|Command
|
||||
|Floating point (lua) |ARM7TDMI _br Cortex-M3 _br ARM966E-S |link:toolchains.html[arm-gcc] |./luac *-ccn float_arm 64 -cce little* -o <script.luac> -s <script.lua>
|
||||
|Floating point (lua) |ARM7TDMI _br Cortex-M3 _br ARM966E-S |link:toolchains.html[codesoucery] |./luac *-ccn float 64 -cce little* -o <script.luac> -s <script.lua>
|
||||
|Integer (lualong) |ARM7TDMI _br Cortex-M3 _br ARM966E-S |link:toolchains.html[arm-gcc] _br link:toolchains.html[codesourcery] |./luac *-ccn int 32 -cce little* -o <script.luac> -s <script.lua>
|
||||
|Floating point (lua) |AVR32 |link:toolchains.html[avr32-gcc] |./luac *-ccn float 64 -cce big* -o <script.luac> -s <script.lua>
|
||||
|Integer (lualong) |AVR32 |link:toolchains.html[avr32-gcc] |./luac *-ccn int 32 -cce big* -o <script.luac> -s <script.lua>
|
||||
|===============================================================
|
||||
|
||||
You can omit the _-s_ (strip) parameter from compilation, but this will result in larger bytecode files (as the debug information is not stripped if you don't use _-s_).
|
||||
|
||||
You can use your bytecode file in multiple ways:
|
||||
|
||||
- write it to link:arch_romfs.html[the ROM file system] and execute it from there.
|
||||
- use the _recv_ command from link:using.html#shell[the shell] to upload it to the board using a serial connection.
|
||||
- write it to an sd/mmc card and, if your board supports it, execute it from there.
|
||||
|
||||
[[rpc]]
|
||||
Controlling eLua with LuaRPC
|
||||
----------------------------
|
||||
_Remote procedure calls_ (RPC) allow one program to communicate with another and call functions or subroutines within
|
||||
the second program. For example one might want to programmatically control an array of LEDs connected to an eLua embedded
|
||||
device from a desktop Lua state. A simple implementation might be a protocol that would allow one to send numeric or
|
||||
text-based commands that would cause code to be executed in eLua that would change the state of the LEDs. As one needs
|
||||
new commands to change these LEDs, one would need to upload a new Lua program to handle changing functionality. In contrast
|
||||
to this ad-hoc method for remote calls, LuaRPC provides a more general way to manipulate the state and execution of a remote
|
||||
Lua environment.
|
||||
|
||||
When a client is connected to a LuaRPC server, it can interact with it in the following ways:
|
||||
|
||||
- assign values to new or existing variables in the server state
|
||||
- get values from variables in the server state
|
||||
- call functions to be executed on the server side using parameters of serializable types, with return values being sent back to the client
|
||||
- create local userdata helpers (aliases) which provide short-hand access to remote state
|
||||
|
||||
Building the Desktop Client/Server
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
- first, make sure that your PC has already a build system installed (gcc, binutils, libc, headers...). You'll also need scons. The good news is that
|
||||
you should have it already installed, since otherwise you won't be able to build even regular eLua (see link:building.html[building] for more instructions).
|
||||
- from the <b>eLua</b> base directory, issue this command:
|
||||
|
||||
$ scons -f rpc-lua.py
|
||||
|
||||
You should get a file called _luarpc_ in the same directory which, when started, should give you a normal Lua interpreter with a built-in rpc module.
|
||||
|
||||
Building eLua with RPC Boot
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
See link:building.html[building] for details and requirements for the building process. In order to boot into RPC mode, the RPC
|
||||
link:building.html#components[component] will need to be enabled, and appropriate link:building.html#static[static configuration data] needs to be set.
|
||||
To build eLua to boot into RPC mode, include *boot=luarpc* in the link:building.html#buildoptions[build options].
|
||||
|
||||
LuaRPC Basics
|
||||
~~~~~~~~~~~~~
|
||||
In terms of the LED example from the beginning of this section, one could directly call pio module functions from the desktop
|
||||
side, experimenting with responses. If the experimentation developed into a program this could be tested both on the desktop side
|
||||
and on the microcontroller by making aliases to eLua modules in local Lua state. Such aliasing can be done as follows:
|
||||
|
||||
-------------------------------------------------------
|
||||
-- open connection from Linux host serial port to eLua
|
||||
slave,err = rpc.connect("/dev/ttyUSB0")
|
||||
|
||||
-- make a local helper pointing to pio module in eLua
|
||||
pio = slave.pio
|
||||
|
||||
-- define function to set direction and value of port B
|
||||
function set_port_val(val)
|
||||
pio.port.setdir( pio.OUTPUT, pio.PB )
|
||||
pio.port.setval( val, pio.PB )
|
||||
end
|
||||
|
||||
set_port_val(23)
|
||||
-------------------------------------------------------
|
||||
|
||||
When we run this locally, calling and indexing helpers are translated into appropriate actions on the server. If we were done with
|
||||
modifications to the above function and wanted it to execute in eLua rather than using local aliases, which will result in a great deal
|
||||
of RPC traffic every time the function is called, we can send the function to the remote side:
|
||||
|
||||
------------------------------------------------------------
|
||||
-- cross-compile local chunk for function and send to server
|
||||
slave.set_port_val = set_port_val
|
||||
|
||||
-- call function on server device
|
||||
slave.set_port_val(23)
|
||||
------------------------------------------------------------
|
||||
|
||||
In addition to functions, we can also copy most other Lua types from client to server using simple assignment. Due to Lua's internal
|
||||
workings the opposite operation of copying Lua types from server to client requires an additional metamethod:
|
||||
|
||||
--------------------------------------
|
||||
-- make table on remote server
|
||||
slave.remote_table = {}
|
||||
|
||||
-- put data in table
|
||||
slave.remote_table.rval = 42
|
||||
|
||||
-- get data back from server, print
|
||||
local_table = slave.remote_table:get()
|
||||
print(local_table.rval)
|
||||
--------------------------------------
|
||||
|
||||
While these examples are trivial, they serve to illustrate a compelling development paradigm that gives one a great deal of flexibility for development and testing with an embedded target.
|
||||
|
||||
Serializable Lua Types
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
Most Lua types can be transferred between the client and server states. The following list indicates which ones can be transferred, and where there are known exceptions:
|
||||
|
||||
[width="90%", cols="^,^", options="header"]
|
||||
|===============================================================
|
||||
^|Serializable types ^|Exceptions and notes
|
||||
| Numbers |
|
||||
| Strings |
|
||||
| Booleans |
|
||||
| Tables | No circular references
|
||||
| Functions | No upvalues
|
||||
| nil |
|
||||
|===============================================================
|
||||
|
||||
// $$FOOTER$$
|
||||
|
29
inc/common.h
29
inc/common.h
@ -6,6 +6,7 @@
|
||||
#include "elua_int.h"
|
||||
#include "lua.h"
|
||||
#include "platform.h"
|
||||
#include "devman.h"
|
||||
|
||||
// Virtual timers data
|
||||
// VTMR_FIRST_ID must be LARGER than PLATFORM_TIMER_SYS_ID (as declared in platform.h)
|
||||
@ -13,6 +14,25 @@
|
||||
#define VTMR_GET_ID( x ) ( ( x ) - VTMR_FIRST_ID )
|
||||
#define TIMER_IS_VIRTUAL( x ) ( ( VTMR_NUM_TIMERS > 0 ) && ( ( x ) >= VTMR_FIRST_ID ) && ( ( x ) < VTMR_NUM_TIMERS + VTMR_FIRST_ID ) )
|
||||
|
||||
// FS interface
|
||||
#define CMN_FS_INFO_BEFORE_READDIR 0
|
||||
#define CMN_FS_INFO_INSIDE_READDIR 1
|
||||
#define CMN_FS_INFO_AFTER_CLOSEDIR 2
|
||||
#define CMN_FS_INFO_MEMORY_ERROR 3
|
||||
#define CMN_FS_INFO_OPENDIR_FAILED 4
|
||||
#define CMN_FS_INFO_READDIR_FAILED 5
|
||||
#define CMN_FS_INFO_DIRECTORY_DONE 6
|
||||
|
||||
#define CMN_FS_TYPE_DIR 0
|
||||
#define CMN_FS_TYPE_FILE 1
|
||||
#define CMN_FS_TYPE_PATTERN 2
|
||||
#define CMN_FS_TYPE_ERROR 3
|
||||
#define CMN_FS_TYPE_FILE_NOT_FOUND 4
|
||||
#define CMN_FS_TYPE_DIR_NOT_FOUND 5
|
||||
#define CMN_FS_TYPE_UNKNOWN_NOT_FOUND 6
|
||||
|
||||
typedef int ( *p_cmn_fs_walker_cb )( const char*, const struct dm_dirent*, void*, int );
|
||||
|
||||
// Functions exported by the common platform layer
|
||||
void cmn_platform_init();
|
||||
void cmn_virtual_timer_cb();
|
||||
@ -27,10 +47,19 @@ void cmn_systimer_set_interrupt_freq( u32 freq_hz );
|
||||
void cmn_systimer_set_interrupt_period_us( u32 period );
|
||||
void cmn_systimer_periodic();
|
||||
timer_data_type cmn_systimer_get();
|
||||
// Filesystem-related functions
|
||||
int cmn_fs_walkdir( const char *path, p_cmn_fs_walker_cb cb, void *pdata, int recursive );
|
||||
char* cmn_fs_split_path( const char *path, const char **pmask );
|
||||
int cmn_fs_get_type( const char* path );
|
||||
char* cmn_fs_path_join( const char *first, ... );
|
||||
int cmn_fs_is_root_dir( const char *path );
|
||||
int cmn_fs_check_directory( const char *path );
|
||||
|
||||
void cmn_uart_setup_sermux();
|
||||
|
||||
unsigned int intlog2( unsigned int v );
|
||||
char lastchar( const char *s );
|
||||
char firstchar( const char *s );
|
||||
const char* cmn_str64( u64 x );
|
||||
void cmn_get_timeout_data( lua_State *L, int pidx, unsigned *pid, timer_data_type *ptimeout );
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "type.h"
|
||||
#include <reent.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
// Maximum number of devices in the system
|
||||
#define DM_MAX_DEVICES 16
|
||||
@ -29,18 +30,26 @@
|
||||
#define DM_STDOUT_NUM 1
|
||||
#define DM_STDERR_NUM 2
|
||||
|
||||
// Directory entry flags
|
||||
#define DM_DIRENT_FLAG_DIR 1
|
||||
|
||||
// Our platform independent "dirent" structure (for opendir/readdir)
|
||||
struct dm_dirent {
|
||||
u32 fsize;
|
||||
const char *fname;
|
||||
u32 ftime;
|
||||
u8 flags;
|
||||
};
|
||||
typedef struct {
|
||||
u8 devid;
|
||||
void *userdata;
|
||||
} DM_DIR;
|
||||
|
||||
#define DM_DIRENT_IS_DIR( ent ) ( ( ( ent )->flags & DM_DIRENT_FLAG_DIR ) != 0 )
|
||||
|
||||
// A device structure with pointers to all the device functions
|
||||
typedef int mkdir_mode_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int ( *p_open_r )( struct _reent *r, const char *path, int flags, int mode, void *pdata );
|
||||
@ -52,6 +61,10 @@ typedef struct
|
||||
struct dm_dirent* ( *p_readdir_r )( struct _reent *r, void *dir, void *pdata );
|
||||
int ( *p_closedir_r )( struct _reent *r, void* dir, void *pdata );
|
||||
const char* ( *p_getaddr_r )( struct _reent *r, int fd, void *pdata );
|
||||
int ( *p_mkdir_r )( struct _reent *r, const char *pathname, mkdir_mode_t mode, void *pdata );
|
||||
int ( *p_unlink_r )( struct _reent *r, const char *fname, void *pdata );
|
||||
int ( *p_rmdir_r )( struct _reent *r, const char *fname, void *pdata );
|
||||
int ( *p_rename_r )( struct _reent *r, const char *oldname, const char *newname, void *pdata );
|
||||
} DM_DEVICE;
|
||||
|
||||
// Additional registration data for each FS (per FS instance)
|
||||
|
40
inc/shell.h
40
inc/shell.h
@ -3,13 +3,43 @@
|
||||
#ifndef __SHELL_H__
|
||||
#define __SHELL_H__
|
||||
|
||||
#define SHELL_WELCOMEMSG "\neLua %s Copyright (C) 2007-2011 www.eluaproject.net\n"
|
||||
#define SHELL_PROMPT "eLua# "
|
||||
#define SHELL_ERRMSG "Invalid command, type 'help' for help\n"
|
||||
#define SHELL_MAXSIZE 50
|
||||
#define SHELL_MAX_LUA_ARGS 8
|
||||
#include "type.h"
|
||||
|
||||
#define SHELL_WELCOMEMSG "\neLua %s Copyright (C) 2007-2011 www.eluaproject.net\n"
|
||||
#define SHELL_PROMPT "eLua# "
|
||||
#define SHELL_ERRMSG "Invalid command, type 'help' for help\n"
|
||||
#define SHELL_MAXSIZE 50
|
||||
#define SHELL_MAX_LUA_ARGS 8
|
||||
|
||||
// Shell command handler function
|
||||
typedef void( *p_shell_handler )( int argc, char **argv );
|
||||
|
||||
// Command/handler pair structure
|
||||
typedef struct
|
||||
{
|
||||
const char* cmd;
|
||||
p_shell_handler handler_func;
|
||||
} SHELL_COMMAND;
|
||||
|
||||
int shell_init();
|
||||
void shell_start();
|
||||
const SHELL_COMMAND* shellh_execute_command( char* cmd, int interactive_mode );
|
||||
int shellh_cp_file( const char *src, const char *dst, int flags );
|
||||
void shellh_not_implemented_handler( int argc, char **argv );
|
||||
void shellh_show_help( const char *cmd, const char *helptext );
|
||||
|
||||
#define SHELL_SHOW_HELP( cmd ) shellh_show_help( #cmd, shell_help_##cmd )
|
||||
|
||||
// Helpers for various functions
|
||||
int shellh_ask_yes_no();
|
||||
|
||||
// Flags for various operations
|
||||
#define SHELL_F_RECURSIVE 1
|
||||
#define SHELL_F_FORCE_DESTINATION 2
|
||||
#define SHELL_F_ASK_CONFIRMATION 4
|
||||
#define SHELL_F_SIMULATE_ONLY 8
|
||||
#define SHELL_F_SILENT 16
|
||||
#define SHELL_F_MOVE 32
|
||||
|
||||
#endif // #ifndef __SHELL_H__
|
||||
|
||||
|
@ -87,6 +87,11 @@
|
||||
#error "Console buffering needs CON_UART_ID defined to the UART ID of the console device"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// BUILD_ADVANCED_SHELL needs BUILD_SHELL
|
||||
#if defined( BUILD_ADVANCED_SHELL ) && !defined( BUILD_SHELL )
|
||||
#error "BUILD_ADVANCED_SHELL needs BUILD_SHELL"
|
||||
#endif
|
||||
|
||||
#endif // #ifndef __VALIDATE_H__
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
#ifndef __VERSION_H__
|
||||
#define __VERSION_H__
|
||||
|
||||
#define ELUA_VERSION v0.8
|
||||
#define ELUA_STR_VERSION "v0.8"
|
||||
#define ELUA_VERSION v0.9
|
||||
#define ELUA_STR_VERSION "v0.9"
|
||||
|
||||
#endif
|
||||
|
18
src/common.c
18
src/common.c
@ -544,6 +544,24 @@ unsigned int intlog2( unsigned int v )
|
||||
return r;
|
||||
}
|
||||
|
||||
char lastchar( const char *s )
|
||||
{
|
||||
unsigned len;
|
||||
|
||||
if( !s )
|
||||
return '\0';
|
||||
len = strlen( s );
|
||||
if( len == 0 )
|
||||
return '\0';
|
||||
else
|
||||
return s[ len - 1 ];
|
||||
}
|
||||
|
||||
char firstchar( const char *s )
|
||||
{
|
||||
return s ? s[ 0 ]: '\0';
|
||||
}
|
||||
|
||||
// 64-bits integer printf support seems to be broken in some versions of Newlib...
|
||||
const char* cmn_str64( u64 x )
|
||||
{
|
||||
|
301
src/common_fs.c
Normal file
301
src/common_fs.c
Normal file
@ -0,0 +1,301 @@
|
||||
// Common file system related operations
|
||||
|
||||
#include "common.h"
|
||||
#include <stdio.h>
|
||||
#include "devman.h"
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define SAFE_CLOSEDIR( dir ) \
|
||||
do { \
|
||||
dm_closedir( dir ); \
|
||||
dir = NULL; \
|
||||
} while( 0 )
|
||||
|
||||
// Returns 1 if 'str' matches the given pattern, 0 otherwise
|
||||
// '?' matches a single char
|
||||
// "*" matches one or more chars, NON-GREEDY
|
||||
static int cmn_pattern_matches( const char *str, const char *pattern )
|
||||
{
|
||||
int pidx, sidx;
|
||||
|
||||
pidx = sidx = 0;
|
||||
while( pattern[ pidx ] != 0 )
|
||||
{
|
||||
if( pattern[ pidx ] == '*' )
|
||||
{
|
||||
pidx ++;
|
||||
// Eat all '?' chars after the '*'
|
||||
while( pattern[ pidx ] == '?' )
|
||||
pidx ++;
|
||||
if( pattern[ pidx ] == 0 ) // '*' in the last position matches everything
|
||||
return 1;
|
||||
while( str[ sidx ] != pattern[ pidx ] && str[ sidx ] != 0 )
|
||||
sidx ++;
|
||||
if( str[ sidx ++ ] == 0 )
|
||||
return 0;
|
||||
}
|
||||
else if( pattern[ pidx ] == '?' )
|
||||
{
|
||||
if( str[ sidx ++ ] == 0 )
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( pattern[ pidx ] != str[ sidx ++ ] )
|
||||
return 0;
|
||||
}
|
||||
pidx ++;
|
||||
}
|
||||
return str[ sidx ] == 0;
|
||||
}
|
||||
|
||||
// Splits a path into "directory" and "filemask" name
|
||||
// Returns a pointer to the directory name. The pointer is dynamically
|
||||
// allocated and it MUST be freed by the caller!
|
||||
// Also returns a pointer to the file mask in "pmask" as a side effect
|
||||
// Returns NULL on error
|
||||
char *cmn_fs_split_path( const char *path, const char **pmask )
|
||||
{
|
||||
static const char *all_mask = "*";
|
||||
FILE *fp;
|
||||
|
||||
if( !path || strlen( path ) < 2 || path[ 0 ] != '/' )
|
||||
return NULL;
|
||||
// /fs -> always a directory ('/'), mask is *
|
||||
if( strchr( path + 1, '/' ) == NULL )
|
||||
{
|
||||
*pmask = all_mask;
|
||||
return strdup( path );
|
||||
}
|
||||
// /fs/dir1/dir2/dirn/ -> always a directory (note the final '/' ), mask is '*'
|
||||
if( path[ strlen( path ) - 1 ] == '/' )
|
||||
{
|
||||
*pmask = all_mask;
|
||||
return strndup( path, strlen( path ) - 1 );
|
||||
}
|
||||
// At this point, we don't know if 'path' reffers to a file or to a directory
|
||||
// So try to open it. If it can be opened, it is a file. Otherwise it is a directory.
|
||||
// But first check for '*' or '?' chars in path (which means it is definitely a file spec)
|
||||
*pmask = strrchr( path, '/' ) + 1;
|
||||
if( strchr( path, '*' ) || strchr( path, '?' ) )
|
||||
return strndup( path, *pmask - path - 1 );
|
||||
if( ( fp = fopen( path, "r" ) ) != NULL )
|
||||
{
|
||||
fclose( fp );
|
||||
return strndup( path, *pmask - path - 1 );
|
||||
}
|
||||
// It is a path, so return it as-is
|
||||
*pmask = all_mask;
|
||||
return strdup( path );
|
||||
}
|
||||
|
||||
// Returns the type of the path given as argument
|
||||
// This can be either CMN_FS_TYPE_DIR, CMN_FS_TYPE_FILE or CMN_FS_TYPE_PATTERN
|
||||
// Note that CMN_FS_TYPE_DIR is NOT actually checked. A name with a '/' in the
|
||||
// last position or a name with a single '/' (for example /rom/ and /rom respectively)
|
||||
// is assumed to be a directory. Otherwise, if the 'path' is not a mask and also
|
||||
// not a regular file, it is assumed to be a directory
|
||||
int cmn_fs_get_type( const char *path )
|
||||
{
|
||||
FILE *fp;
|
||||
DM_DIR *d;
|
||||
|
||||
if( !path || strlen( path ) < 2 || path[ 0 ] != '/' )
|
||||
return CMN_FS_TYPE_ERROR;
|
||||
// /fs -> always a directory ('/'), mask is *
|
||||
if( strchr( path + 1, '/' ) == NULL )
|
||||
return CMN_FS_TYPE_DIR;
|
||||
// /fs/dir1/dir2/dirn/ -> always a directory (note the final '/' ), mask is '*'
|
||||
if( path[ strlen( path ) - 1 ] == '/' )
|
||||
{
|
||||
if( ( d = dm_opendir( path ) ) == NULL )
|
||||
return CMN_FS_TYPE_DIR_NOT_FOUND;
|
||||
dm_closedir( d );
|
||||
return CMN_FS_TYPE_DIR;
|
||||
}
|
||||
// At this point, we don't know if 'path' reffers to a file or to a directory
|
||||
// So try to open it. If it can be opened, it is a file. Otherwise it is a directory.
|
||||
// But first check for '*' or '?' chars in path (which means it is definitely a file spec)
|
||||
if( strchr( path, '*' ) || strchr( path, '?' ) )
|
||||
return CMN_FS_TYPE_PATTERN;
|
||||
if( ( fp = fopen( path, "r" ) ) != NULL )
|
||||
{
|
||||
fclose( fp );
|
||||
return CMN_FS_TYPE_FILE;
|
||||
}
|
||||
if( ( d = dm_opendir( path ) ) == NULL )
|
||||
return CMN_FS_TYPE_UNKNOWN_NOT_FOUND;
|
||||
dm_closedir( d );
|
||||
return CMN_FS_TYPE_DIR;
|
||||
}
|
||||
|
||||
// Join the given elements in a single PATH
|
||||
// The memory for the final buffer is dynamically allocated and MUST be
|
||||
// freed by the caller
|
||||
char *cmn_fs_path_join( const char *first, ... )
|
||||
{
|
||||
unsigned total = 0;
|
||||
va_list ap;
|
||||
const char *tmp = first;
|
||||
char *res;
|
||||
|
||||
va_start( ap, first );
|
||||
// Get total length first
|
||||
while( tmp )
|
||||
{
|
||||
if( strlen( tmp ) > 0 )
|
||||
{
|
||||
total += strlen( tmp ) + ( lastchar( tmp ) == '/' ? 0 : 1 );
|
||||
if( firstchar( tmp ) == '/' )
|
||||
total --;
|
||||
}
|
||||
tmp = va_arg( ap, const char* );
|
||||
}
|
||||
va_end( ap );
|
||||
if( total == 0 || ( ( res = ( char* )malloc( total + 2 ) ) == NULL ) )
|
||||
return NULL;
|
||||
strcpy( res, "/" );
|
||||
va_start( ap, first );
|
||||
tmp = first;
|
||||
while( tmp )
|
||||
{
|
||||
if( strlen( tmp ) > 0 )
|
||||
{
|
||||
strcat( res, tmp + ( firstchar( tmp ) == '/' ? 1 : 0 ) );
|
||||
if( lastchar( res ) != '/' )
|
||||
strcat( res, "/" );
|
||||
}
|
||||
tmp = va_arg( ap, const char* );
|
||||
}
|
||||
res[ strlen( res ) - 1 ] = '\0';
|
||||
va_end( ap );
|
||||
return res;
|
||||
}
|
||||
|
||||
// This is a generic file/directory walker. It is used by all shell
|
||||
// operations that have something to do with files (ls, cp, rm...)
|
||||
// It receives an initial path, which may contain also a pattern specification
|
||||
// (see cmn_pattern_matches above). If "recursive" is true, it will
|
||||
// recursively find all files and directories underneath 'path' that match
|
||||
// the optional pattern in 'path'. When a file is called, the "callback" is
|
||||
// called. The callback is a function with the following signature:
|
||||
// void walker_cb( const char *path, const struct dm_entry *ent, void *pdata, int info );
|
||||
// 'path' is the full path of the file/directory found by the walker
|
||||
// 'ent' is the directory entry (as defined in devman.h)
|
||||
// 'pdata' is the callback state, passed to the callback function exactly
|
||||
// as given to the walker function.
|
||||
// 'info' gives more information about why/where the callback was called:
|
||||
// CMN_FS_INFO_BEFORE_READDIR
|
||||
// CMN_FS_INFO_INSIDE_READDIR
|
||||
// CMN_FS_INFO_AFTER_CLOSEDIR
|
||||
// CMN_FS_INFO_DIRECTORY_DONE
|
||||
// CMN_FS_INFO_MEMORY_ERROR -> called after a memory allocation failed
|
||||
// CMN_FS_INFO_OPENDIR_FAILED
|
||||
// CMN_FS_INFO_READDIR_FAILED
|
||||
// The callback can return 0 (stop walking the directory and calling the callback)
|
||||
// or 1 (keep on calling the callback). If a 0 was returned, this will also be the
|
||||
// result returned by the walker, otherwise 1 is returned
|
||||
static int cmn_fs_actual_walkdir( const char *path, const char *pattern, p_cmn_fs_walker_cb cb, void *pdata, int recursive )
|
||||
{
|
||||
DM_DIR *d;
|
||||
struct dm_dirent *ent;
|
||||
int hasdirs, isdir;
|
||||
char *fullname;
|
||||
|
||||
if( ( d = dm_opendir( path ) ) != NULL )
|
||||
{
|
||||
if( cb( path, NULL, pdata, CMN_FS_INFO_BEFORE_READDIR ) == 0 )
|
||||
goto abort;
|
||||
while( ( ent = dm_readdir( d ) ) != NULL )
|
||||
{
|
||||
isdir = ( ent->flags & DM_DIRENT_FLAG_DIR ) != 0;
|
||||
if( !cmn_pattern_matches( ent->fname, pattern ) )
|
||||
continue;
|
||||
if( cb( path, ent, pdata, CMN_FS_INFO_INSIDE_READDIR ) == 0 )
|
||||
goto abort;
|
||||
if( isdir )
|
||||
hasdirs = 1;
|
||||
}
|
||||
SAFE_CLOSEDIR( d );
|
||||
if( cb( path, ent, pdata, CMN_FS_INFO_AFTER_CLOSEDIR ) == 0 )
|
||||
goto abort;
|
||||
if( recursive && hasdirs )
|
||||
{
|
||||
if( ( d = dm_opendir( path ) ) != NULL )
|
||||
{
|
||||
while( ( ent = dm_readdir( d ) ) != NULL )
|
||||
{
|
||||
if( ent->flags & DM_DIRENT_FLAG_DIR )
|
||||
{
|
||||
if( ( fullname = cmn_fs_path_join( path, ent->fname, NULL ) ) != NULL )
|
||||
{
|
||||
hasdirs = cmn_fs_actual_walkdir( fullname, pattern, cb, pdata, 1 );
|
||||
free( fullname );
|
||||
if( hasdirs == 0 )
|
||||
goto abort;
|
||||
}
|
||||
else
|
||||
if( cb( path, NULL, pdata, CMN_FS_INFO_MEMORY_ERROR ) == 0 )
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
SAFE_CLOSEDIR( d );
|
||||
}
|
||||
else
|
||||
if( cb( path, NULL, pdata, CMN_FS_INFO_OPENDIR_FAILED ) == 0 )
|
||||
return 0;
|
||||
}
|
||||
if( cb( path, ent, pdata, CMN_FS_INFO_DIRECTORY_DONE ) == 0 )
|
||||
goto abort;
|
||||
}
|
||||
else
|
||||
if( cb( path, NULL, pdata, CMN_FS_INFO_OPENDIR_FAILED ) == 0 )
|
||||
return 0;
|
||||
return 1;
|
||||
abort:
|
||||
if( d )
|
||||
dm_closedir( d );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmn_fs_walkdir( const char *path, p_cmn_fs_walker_cb cb, void *pdata, int recursive )
|
||||
{
|
||||
char *actpath;
|
||||
const char *pattern;
|
||||
|
||||
if( ( actpath = cmn_fs_split_path( path, &pattern ) ) == NULL )
|
||||
return 0;
|
||||
cmn_fs_actual_walkdir( actpath, pattern, cb, pdata, recursive );
|
||||
free( actpath );
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cmn_fs_is_root_dir( const char *path )
|
||||
{
|
||||
if( !path )
|
||||
return 0;
|
||||
if( path[ 0 ] != '/' )
|
||||
return 0;
|
||||
if( ( path = strchr( path + 1, '/' ) ) == NULL )
|
||||
return 1;
|
||||
if( *( path + 1 ) == 0 )
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if the directory in the given argument (if applicable)
|
||||
// can be opened
|
||||
int cmn_fs_check_directory( const char *path )
|
||||
{
|
||||
DM_DIR *d;
|
||||
|
||||
if( ( d = dm_opendir( path ) ) == NULL )
|
||||
return 0;
|
||||
dm_closedir( d );
|
||||
return 1;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef BUILD_INT_HANDLERS
|
||||
extern const elua_int_descriptor elua_int_table[ INT_ELUA_LAST ];
|
||||
extern const elua_int_descriptor elua_int_table[ INT_ELUA_LAST ];
|
||||
#endif // #ifdef BUILD_INT_HANDLERS
|
||||
|
||||
#ifndef PLATFORM_HAS_SYSTIMER
|
||||
@ -33,9 +33,9 @@ extern const elua_int_descriptor elua_int_table[ INT_ELUA_LAST ];
|
||||
static volatile u32 vtmr_counters[ VTMR_NUM_TIMERS ];
|
||||
static volatile s8 vtmr_reset_idx = -1;
|
||||
|
||||
#if defined( BUILD_INT_HANDLERS ) && ( INT_TMR_MATCH != ELUA_INT_INVALID_INTERRUPT )
|
||||
#if defined( BUILD_INT_HANDLERS ) && defined( INT_TMR_MATCH )
|
||||
#define CMN_TIMER_INT_SUPPORT
|
||||
#endif // #if defined( BUILD_INT_HANDLERS ) && ( INT_TMR_MATCH != ELUA_INT_INVALID_INTERRUPT )
|
||||
#endif // #if defined( BUILD_INT_HANDLERS ) && defined( INT_TMR_MATCH )
|
||||
|
||||
#ifdef CMN_TIMER_INT_SUPPORT
|
||||
static volatile u32 vtmr_period_limit[ VTMR_NUM_TIMERS ];
|
||||
@ -331,44 +331,56 @@ int platform_timer_set_match_int( unsigned id, timer_data_type period_us, int ty
|
||||
|
||||
int cmn_tmr_int_set_status( elua_int_resnum resnum, int status )
|
||||
{
|
||||
elua_int_p_set_status ps;
|
||||
#if VTMR_NUM_TIMERS > 00 && defined( CMN_TIMER_INT_SUPPORT )
|
||||
if( TIMER_IS_VIRTUAL( resnum ) )
|
||||
return vtmr_int_set_status( resnum, status );
|
||||
#endif
|
||||
if( resnum == PLATFORM_TIMER_SYS_ID )
|
||||
return PLATFORM_INT_BAD_RESNUM;
|
||||
#ifdef INT_TMR_MATCH
|
||||
elua_int_p_set_status ps;
|
||||
if( ( ps = elua_int_table[ INT_TMR_MATCH - ELUA_INT_FIRST_ID ].int_set_status ) == NULL )
|
||||
return PLATFORM_INT_NOT_HANDLED;
|
||||
return ps( resnum, status );
|
||||
#else
|
||||
return PLATFORM_INT_INVALID;
|
||||
#endif
|
||||
}
|
||||
|
||||
int cmn_tmr_int_get_status( elua_int_resnum resnum )
|
||||
{
|
||||
elua_int_p_get_status pg;
|
||||
#if VTMR_NUM_TIMERS > 00 && defined( CMN_TIMER_INT_SUPPORT )
|
||||
if( TIMER_IS_VIRTUAL( resnum ) )
|
||||
return vtmr_int_get_status( resnum );
|
||||
#endif
|
||||
if( resnum == PLATFORM_TIMER_SYS_ID )
|
||||
return PLATFORM_INT_BAD_RESNUM;
|
||||
#ifdef INT_TMR_MATCH
|
||||
elua_int_p_get_status pg;
|
||||
if( ( pg = elua_int_table[ INT_TMR_MATCH - ELUA_INT_FIRST_ID ].int_get_status ) == NULL )
|
||||
return PLATFORM_INT_NOT_HANDLED;
|
||||
return pg( resnum );
|
||||
#else
|
||||
return PLATFORM_INT_INVALID;
|
||||
#endif
|
||||
}
|
||||
|
||||
int cmn_tmr_int_get_flag( elua_int_resnum resnum, int clear )
|
||||
{
|
||||
elua_int_p_get_flag pf;
|
||||
#if VTMR_NUM_TIMERS > 00 && defined( CMN_TIMER_INT_SUPPORT )
|
||||
if( TIMER_IS_VIRTUAL( resnum ) )
|
||||
return vtmr_int_get_flag( resnum, clear );
|
||||
#endif
|
||||
if( resnum == PLATFORM_TIMER_SYS_ID )
|
||||
return PLATFORM_INT_BAD_RESNUM;
|
||||
#ifdef INT_TMR_MATCH
|
||||
elua_int_p_get_flag pf;
|
||||
if( ( pf = elua_int_table[ INT_TMR_MATCH - ELUA_INT_FIRST_ID ].int_get_flag ) == NULL )
|
||||
return PLATFORM_INT_NOT_HANDLED;
|
||||
return pf( resnum, clear );
|
||||
#else
|
||||
return PLATFORM_INT_INVALID;
|
||||
#endif
|
||||
}
|
||||
|
||||
#else // #ifdef BUILD_INT_HANDLERS
|
||||
|
293
src/elua_mmc.c
293
src/elua_mmc.c
@ -6,9 +6,16 @@
|
||||
// web site by Jesus Alvarez & James Snyder for eLua.
|
||||
|
||||
#include "platform_conf.h"
|
||||
#ifdef BUILD_MMCFS
|
||||
#if defined( BUILD_MMCFS ) && !defined( ELUA_SIMULATOR )
|
||||
#include "platform.h"
|
||||
#include "diskio.h"
|
||||
#include "mmcfs.h"
|
||||
|
||||
#ifndef MMCFS_NUM_CARDS
|
||||
#define NUM_CARDS 1
|
||||
#else
|
||||
#define NUM_CARDS MMCFS_NUM_CARDS
|
||||
#endif
|
||||
|
||||
/* Definitions for MMC/SDC command */
|
||||
#define CMD0 (0x40+0) /* GO_IDLE_STATE */
|
||||
@ -27,22 +34,32 @@
|
||||
#define CMD55 (0x40+55) /* APP_CMD */
|
||||
#define CMD58 (0x40+58) /* READ_OCR */
|
||||
|
||||
#ifndef MMCFS_SPI_NUM
|
||||
#if !defined( MMCFS_SPI_NUM ) && !defined( MMCFS_SPI_NUM_ARRAY )
|
||||
#error "MMC not supported on this board"
|
||||
#endif
|
||||
|
||||
#if defined( MMCFS_CS_PORT )
|
||||
const u8 mmcfs_cs_ports[ NUM_CARDS ] = { MMCFS_CS_PORT };
|
||||
static const u8 mmcfs_cs_pins[ NUM_CARDS ] = { MMCFS_CS_PIN };
|
||||
static const u8 mmcfs_spi_nums[ NUM_CARDS ] = { MMCFS_SPI_NUM };
|
||||
#elif defined( MMCFS_CS_PORT_ARRAY )
|
||||
const u8 mmcfs_cs_ports[ NUM_CARDS ] = MMCFS_CS_PORT_ARRAY;
|
||||
static const u8 mmcfs_cs_pins[ NUM_CARDS ] = MMCFS_CS_PIN_ARRAY;
|
||||
static const u8 mmcfs_spi_nums[ NUM_CARDS ] = MMCFS_SPI_NUM_ARRAY;
|
||||
#endif
|
||||
|
||||
// asserts the CS pin to the card
|
||||
static
|
||||
void SELECT (void)
|
||||
void SELECT (BYTE id)
|
||||
{
|
||||
platform_pio_op( MMCFS_CS_PORT , ( ( u32 ) 1 << MMCFS_CS_PIN ), PLATFORM_IO_PIN_CLEAR );
|
||||
platform_pio_op( mmcfs_cs_ports[ id ] , ( ( u32 ) 1 << mmcfs_cs_pins[ id ] ), PLATFORM_IO_PIN_CLEAR );
|
||||
}
|
||||
|
||||
// de-asserts the CS pin to the card
|
||||
static
|
||||
void DESELECT (void)
|
||||
void DESELECT (BYTE id)
|
||||
{
|
||||
platform_pio_op( MMCFS_CS_PORT, ( ( u32 ) 1 << MMCFS_CS_PIN ), PLATFORM_IO_PIN_SET );
|
||||
platform_pio_op( mmcfs_cs_ports[ id ], ( ( u32 ) 1 << mmcfs_cs_pins[ id ] ), PLATFORM_IO_PIN_SET );
|
||||
}
|
||||
|
||||
|
||||
@ -52,20 +69,13 @@ void DESELECT (void)
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
static volatile
|
||||
DSTATUS Stat = STA_NOINIT; /* Disk status */
|
||||
static volatile DSTATUS Stat[ NUM_CARDS ]; /* Disk status */
|
||||
|
||||
static volatile timer_data_type Timer1 = 0;
|
||||
static volatile timer_data_type Timer2 = 0;
|
||||
static BYTE TriesLeft[ NUM_CARDS ];
|
||||
|
||||
static
|
||||
BYTE TriesLeft = 2;
|
||||
static BYTE CardType[ NUM_CARDS ]; /* b0:MMC, b1:SDC, b2:Block addressing */
|
||||
|
||||
static
|
||||
BYTE CardType; /* b0:MMC, b1:SDC, b2:Block addressing */
|
||||
|
||||
static
|
||||
BYTE PowerFlag = 0; /* indicates if "power" is on */
|
||||
static BYTE PowerFlag[ NUM_CARDS ]; /* indicates if "power" is on */
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
@ -74,9 +84,9 @@ BYTE PowerFlag = 0; /* indicates if "power" is on */
|
||||
|
||||
|
||||
static
|
||||
void xmit_spi (BYTE dat)
|
||||
void xmit_spi (BYTE id, BYTE dat)
|
||||
{
|
||||
platform_spi_send_recv( MMCFS_SPI_NUM, dat );
|
||||
platform_spi_send_recv( mmcfs_spi_nums[ id ], dat );
|
||||
}
|
||||
|
||||
|
||||
@ -85,20 +95,20 @@ void xmit_spi (BYTE dat)
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
BYTE rcvr_spi (void)
|
||||
BYTE rcvr_spi (BYTE id)
|
||||
{
|
||||
DWORD rcvdat;
|
||||
|
||||
rcvdat = platform_spi_send_recv( MMCFS_SPI_NUM, 0xFF );
|
||||
rcvdat = platform_spi_send_recv( mmcfs_spi_nums[ id ], 0xFF );
|
||||
|
||||
return ( BYTE )rcvdat;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void rcvr_spi_m (BYTE *dst)
|
||||
void rcvr_spi_m (BYTE id, BYTE *dst)
|
||||
{
|
||||
*dst = rcvr_spi();
|
||||
*dst = rcvr_spi( id );
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
@ -106,14 +116,15 @@ void rcvr_spi_m (BYTE *dst)
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
BYTE wait_ready (void)
|
||||
BYTE wait_ready (BYTE id)
|
||||
{
|
||||
BYTE res;
|
||||
timer_data_type Timer2;
|
||||
|
||||
Timer2 = platform_timer_read( PLATFORM_TIMER_SYS_ID );
|
||||
rcvr_spi();
|
||||
rcvr_spi( id );
|
||||
do
|
||||
res = rcvr_spi(); /* Wait for ready in timeout of 500ms. */
|
||||
res = rcvr_spi( id ); /* Wait for ready in timeout of 500ms. */
|
||||
while ( ( res != 0xFF ) && ( platform_timer_get_diff_crt( PLATFORM_TIMER_SYS_ID, Timer2 ) < 500000 ) );
|
||||
|
||||
return res;
|
||||
@ -124,16 +135,16 @@ BYTE wait_ready (void)
|
||||
/* required after card power up to get it into SPI mode */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static
|
||||
void send_initial_clock_train(void)
|
||||
void send_initial_clock_train(BYTE id)
|
||||
{
|
||||
unsigned int i;
|
||||
/* Ensure CS is held high. */
|
||||
DESELECT();
|
||||
DESELECT(id);
|
||||
|
||||
/* Send 10 bytes over the SSI. This causes the clock to wiggle the */
|
||||
/* required number of times. */
|
||||
for(i = 0 ; i < 10 ; i++)
|
||||
rcvr_spi();
|
||||
rcvr_spi(id);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
@ -143,7 +154,7 @@ void send_initial_clock_train(void)
|
||||
/* is nothing to do in these functions and chk_power always returns 1. */
|
||||
|
||||
static
|
||||
void power_on (void)
|
||||
void power_on (BYTE id)
|
||||
{
|
||||
/*
|
||||
* This doesn't really turn the power on, but initializes the
|
||||
@ -151,23 +162,23 @@ void power_on (void)
|
||||
*/
|
||||
|
||||
// Setup CS pin & deselect
|
||||
platform_pio_op( MMCFS_CS_PORT, ( ( u32 ) 1 << MMCFS_CS_PIN ), PLATFORM_IO_PIN_DIR_OUTPUT );
|
||||
platform_pio_op( mmcfs_cs_ports[ id ], ( ( u32 ) 1 << mmcfs_cs_pins[ id ] ), PLATFORM_IO_PIN_DIR_OUTPUT );
|
||||
//platform_pio_op( MMCFS_CS_PORT, ( ( u32 ) 1 << MMCFS_CS_PIN ), PLATFORM_IO_PIN_PULLUP );
|
||||
DESELECT();
|
||||
DESELECT( id );
|
||||
|
||||
// Setup SPI
|
||||
platform_spi_setup( MMCFS_SPI_NUM, PLATFORM_SPI_MASTER, 400000, 0, 0, 8 );
|
||||
platform_spi_setup( mmcfs_spi_nums[ id ], PLATFORM_SPI_MASTER, 400000, 0, 0, 8 );
|
||||
|
||||
/* Set DI and CS high and apply more than 74 pulses to SCLK for the card */
|
||||
/* to be able to accept a native command. */
|
||||
send_initial_clock_train();
|
||||
send_initial_clock_train(id);
|
||||
|
||||
PowerFlag = 1;
|
||||
PowerFlag[id] = 1;
|
||||
}
|
||||
|
||||
// set the SSI speed to the max setting
|
||||
static
|
||||
void set_max_speed(void)
|
||||
void set_max_speed(BYTE id)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
@ -177,48 +188,49 @@ void set_max_speed(void)
|
||||
i = 12500000;
|
||||
|
||||
/* Configure the SPI port */
|
||||
platform_spi_setup( MMCFS_SPI_NUM, PLATFORM_SPI_MASTER, i, 0, 0, 8 );
|
||||
platform_spi_setup( mmcfs_spi_nums[ id ], PLATFORM_SPI_MASTER, i, 0, 0, 8 );
|
||||
}
|
||||
|
||||
static
|
||||
void power_off (void)
|
||||
void power_off (BYTE id)
|
||||
{
|
||||
PowerFlag = 0;
|
||||
PowerFlag[ id ] = 0;
|
||||
}
|
||||
|
||||
static
|
||||
int chk_power(void) /* Socket power state: 0=off, 1=on */
|
||||
int chk_power(BYTE id) /* Socket power state: 0=off, 1=on */
|
||||
{
|
||||
return PowerFlag;
|
||||
return PowerFlag[ id ];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Receive a data packet from MMC */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
BOOL rcvr_datablock (
|
||||
BYTE *buff, /* Data buffer to store received data */
|
||||
BYTE id, /* Disk ID */
|
||||
BYTE *buff, /* Data buffer to store received data */
|
||||
UINT btr /* Byte count (must be even number) */
|
||||
)
|
||||
{
|
||||
BYTE token;
|
||||
timer_data_type Timer1;
|
||||
|
||||
Timer1 = platform_timer_read( PLATFORM_TIMER_SYS_ID );
|
||||
do { /* Wait for data packet in timeout of 100ms */
|
||||
token = rcvr_spi();
|
||||
token = rcvr_spi(id);
|
||||
} while ( ( token == 0xFF ) &&
|
||||
platform_timer_get_diff_crt( PLATFORM_TIMER_SYS_ID, Timer1 ) < 100000 );
|
||||
if(token != 0xFE) return FALSE; /* If not valid data token, retutn with error */
|
||||
|
||||
do { /* Receive the data block into buffer */
|
||||
rcvr_spi_m(buff++);
|
||||
rcvr_spi_m(buff++);
|
||||
rcvr_spi_m(id, buff++);
|
||||
rcvr_spi_m(id, buff++);
|
||||
} while (btr -= 2);
|
||||
rcvr_spi(); /* Discard CRC */
|
||||
rcvr_spi();
|
||||
rcvr_spi(id); /* Discard CRC */
|
||||
rcvr_spi(id);
|
||||
|
||||
return TRUE; /* Return with success */
|
||||
}
|
||||
@ -232,25 +244,26 @@ BOOL rcvr_datablock (
|
||||
#if _READONLY == 0
|
||||
static
|
||||
BOOL xmit_datablock (
|
||||
const BYTE *buff, /* 512 byte data block to be transmitted */
|
||||
BYTE id, /* Disk ID */
|
||||
const BYTE *buff, /* 512 byte data block to be transmitted */
|
||||
BYTE token /* Data/Stop token */
|
||||
)
|
||||
{
|
||||
BYTE resp, wc;
|
||||
|
||||
|
||||
if (wait_ready() != 0xFF) return FALSE;
|
||||
if (wait_ready(id) != 0xFF) return FALSE;
|
||||
|
||||
xmit_spi(token); /* Xmit data token */
|
||||
xmit_spi(id,token); /* Xmit data token */
|
||||
if (token != 0xFD) { /* Is data token */
|
||||
wc = 0;
|
||||
do { /* Xmit the 512 byte data block to MMC */
|
||||
xmit_spi(*buff++);
|
||||
xmit_spi(*buff++);
|
||||
xmit_spi(id,*buff++);
|
||||
xmit_spi(id,*buff++);
|
||||
} while (--wc);
|
||||
xmit_spi(0xFF); /* CRC (Dummy) */
|
||||
xmit_spi(0xFF);
|
||||
resp = rcvr_spi(); /* Reveive data response */
|
||||
xmit_spi(id,0xFF); /* CRC (Dummy) */
|
||||
xmit_spi(id,0xFF);
|
||||
resp = rcvr_spi(id); /* Reveive data response */
|
||||
if ((resp & 0x1F) != 0x05) /* If not accepted, return with error */
|
||||
return FALSE;
|
||||
}
|
||||
@ -267,6 +280,7 @@ BOOL xmit_datablock (
|
||||
|
||||
static
|
||||
BYTE send_cmd (
|
||||
BYTE id, /* Disk ID */
|
||||
BYTE cmd, /* Command byte */
|
||||
DWORD arg /* Argument */
|
||||
)
|
||||
@ -274,24 +288,24 @@ BYTE send_cmd (
|
||||
BYTE n, res;
|
||||
|
||||
|
||||
if (wait_ready() != 0xFF) return 0xFF;
|
||||
if (wait_ready(id) != 0xFF) return 0xFF;
|
||||
|
||||
/* Send command packet */
|
||||
xmit_spi(cmd); /* Command */
|
||||
xmit_spi((BYTE)(arg >> 24)); /* Argument[31..24] */
|
||||
xmit_spi((BYTE)(arg >> 16)); /* Argument[23..16] */
|
||||
xmit_spi((BYTE)(arg >> 8)); /* Argument[15..8] */
|
||||
xmit_spi((BYTE)arg); /* Argument[7..0] */
|
||||
xmit_spi(id,cmd); /* Command */
|
||||
xmit_spi(id,(BYTE)(arg >> 24)); /* Argument[31..24] */
|
||||
xmit_spi(id,(BYTE)(arg >> 16)); /* Argument[23..16] */
|
||||
xmit_spi(id,(BYTE)(arg >> 8)); /* Argument[15..8] */
|
||||
xmit_spi(id,(BYTE)arg); /* Argument[7..0] */
|
||||
n = 0;
|
||||
if (cmd == CMD0) n = 0x95; /* CRC for CMD0(0) */
|
||||
if (cmd == CMD8) n = 0x87; /* CRC for CMD8(0x1AA) */
|
||||
xmit_spi(n);
|
||||
xmit_spi(id,n);
|
||||
|
||||
/* Receive command response */
|
||||
if (cmd == CMD12) rcvr_spi(); /* Skip a stuff byte when stop reading */
|
||||
if (cmd == CMD12) rcvr_spi(id); /* Skip a stuff byte when stop reading */
|
||||
n = 10; /* Wait for a valid response in timeout of 10 attempts */
|
||||
do
|
||||
res = rcvr_spi();
|
||||
res = rcvr_spi(id);
|
||||
while ((res & 0x80) && --n);
|
||||
|
||||
return res; /* Return with the response value */
|
||||
@ -305,6 +319,16 @@ BYTE send_cmd (
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
void elua_mmc_init()
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0; i < NUM_CARDS; i ++ )
|
||||
{
|
||||
Stat[ i ] = STA_NOINIT;
|
||||
TriesLeft[ i ] = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Initialize Disk Drive */
|
||||
@ -315,62 +339,61 @@ DSTATUS disk_initialize (
|
||||
)
|
||||
{
|
||||
BYTE n, ty, ocr[4];
|
||||
timer_data_type Timer1;
|
||||
|
||||
|
||||
if (drv) return STA_NOINIT; /* Supports only single drive */
|
||||
if (Stat & STA_NODISK) return Stat; /* No card in the socket */
|
||||
if (Stat[drv] & STA_NODISK) return Stat[drv]; /* No card in the socket */
|
||||
|
||||
do
|
||||
{
|
||||
power_on(); /* Force socket power on */
|
||||
power_on(drv); /* Force socket power on */
|
||||
|
||||
SELECT(); /* CS = L */
|
||||
SELECT(drv); /* CS = L */
|
||||
ty = 0;
|
||||
if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
|
||||
if (send_cmd(drv,CMD0, 0) == 1) { /* Enter Idle state */
|
||||
Timer1 = platform_timer_read( PLATFORM_TIMER_SYS_ID );
|
||||
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDC Ver2+ */
|
||||
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();
|
||||
if (send_cmd(drv,CMD8, 0x1AA) == 1) { /* SDC Ver2+ */
|
||||
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi(drv);
|
||||
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
|
||||
do {
|
||||
if (send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 1UL << 30) == 0) break; /* ACMD41 with HCS bit */
|
||||
if (send_cmd(drv,CMD55, 0) <= 1 && send_cmd(drv,CMD41, 1UL << 30) == 0) break; /* ACMD41 with HCS bit */
|
||||
} while ( platform_timer_get_diff_crt( PLATFORM_TIMER_SYS_ID, Timer1 ) < 1000000 );
|
||||
if ( ( platform_timer_get_diff_crt( PLATFORM_TIMER_SYS_ID, Timer1 ) < 1000000 )
|
||||
&& send_cmd(CMD58, 0) == 0) { /* Check CCS bit (it seems pointless to check the timer here*/
|
||||
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();
|
||||
&& send_cmd(drv,CMD58, 0) == 0) { /* Check CCS bit (it seems pointless to check the timer here*/
|
||||
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi(drv);
|
||||
ty = (ocr[0] & 0x40) ? 6 : 2;
|
||||
}
|
||||
}
|
||||
} else { /* SDC Ver1 or MMC */
|
||||
ty = (send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 0) <= 1) ? 2 : 1; /* SDC : MMC */
|
||||
ty = (send_cmd(drv,CMD55, 0) <= 1 && send_cmd(drv,CMD41, 0) <= 1) ? 2 : 1; /* SDC : MMC */
|
||||
do {
|
||||
if (ty == 2) {
|
||||
if (send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 0) == 0) break; /* ACMD41 */
|
||||
if (send_cmd(drv,CMD55, 0) <= 1 && send_cmd(drv,CMD41, 0) == 0) break; /* ACMD41 */
|
||||
} else {
|
||||
if (send_cmd(CMD1, 0) == 0) break; /* CMD1 */
|
||||
if (send_cmd(drv,CMD1, 0) == 0) break; /* CMD1 */
|
||||
}
|
||||
} while ( platform_timer_get_diff_crt( PLATFORM_TIMER_SYS_ID, Timer1 ) < 1000000 );
|
||||
if ( ( platform_timer_get_diff_crt( PLATFORM_TIMER_SYS_ID, Timer1 ) >= 1000000 )
|
||||
|| send_cmd(CMD16, 512) != 0 ) /* Select R/W block length */
|
||||
|| send_cmd(drv,CMD16, 512) != 0 ) /* Select R/W block length */
|
||||
ty = 0;
|
||||
}
|
||||
}
|
||||
CardType = ty;
|
||||
DESELECT(); /* CS = H */
|
||||
rcvr_spi(); /* Idle (Release DO) */
|
||||
CardType[drv] = ty;
|
||||
DESELECT(drv); /* CS = H */
|
||||
rcvr_spi(drv); /* Idle (Release DO) */
|
||||
|
||||
if (TriesLeft)
|
||||
TriesLeft--;
|
||||
if (TriesLeft[drv])
|
||||
TriesLeft[drv]--;
|
||||
|
||||
if (ty) { /* Initialization succeded */
|
||||
Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */
|
||||
set_max_speed();
|
||||
Stat[drv] &= ~STA_NOINIT; /* Clear STA_NOINIT */
|
||||
set_max_speed(drv);
|
||||
} else { /* Initialization failed */
|
||||
power_off();
|
||||
power_off(drv);
|
||||
}
|
||||
|
||||
} while( TriesLeft > 0 && ty == 0 );
|
||||
} while( TriesLeft[drv] > 0 && ty == 0 );
|
||||
|
||||
return Stat;
|
||||
return Stat[drv];
|
||||
}
|
||||
|
||||
|
||||
@ -383,8 +406,7 @@ DSTATUS disk_status (
|
||||
BYTE drv /* Physical drive nmuber (0) */
|
||||
)
|
||||
{
|
||||
if (drv) return STA_NOINIT; /* Supports only single drive */
|
||||
return Stat;
|
||||
return Stat[drv];
|
||||
}
|
||||
|
||||
|
||||
@ -400,30 +422,30 @@ DRESULT disk_read (
|
||||
BYTE count /* Sector count (1..255) */
|
||||
)
|
||||
{
|
||||
if (drv || !count) return RES_PARERR;
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||
if (!count) return RES_PARERR;
|
||||
if (Stat[drv] & STA_NOINIT) return RES_NOTRDY;
|
||||
|
||||
if (!(CardType & 4)) sector *= 512; /* Convert to byte address if needed */
|
||||
if (!(CardType[drv] & 4)) sector *= 512; /* Convert to byte address if needed */
|
||||
|
||||
SELECT(); /* CS = L */
|
||||
SELECT(drv); /* CS = L */
|
||||
|
||||
if (count == 1) { /* Single block read */
|
||||
if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */
|
||||
&& rcvr_datablock(buff, 512))
|
||||
if ((send_cmd(drv,CMD17, sector) == 0) /* READ_SINGLE_BLOCK */
|
||||
&& rcvr_datablock(drv,buff, 512))
|
||||
count = 0;
|
||||
}
|
||||
else { /* Multiple block read */
|
||||
if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */
|
||||
if (send_cmd(drv,CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */
|
||||
do {
|
||||
if (!rcvr_datablock(buff, 512)) break;
|
||||
if (!rcvr_datablock(drv,buff, 512)) break;
|
||||
buff += 512;
|
||||
} while (--count);
|
||||
send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
|
||||
send_cmd(drv,CMD12, 0); /* STOP_TRANSMISSION */
|
||||
}
|
||||
}
|
||||
|
||||
DESELECT(); /* CS = H */
|
||||
rcvr_spi(); /* Idle (Release DO) */
|
||||
DESELECT(drv); /* CS = H */
|
||||
rcvr_spi(drv); /* Idle (Release DO) */
|
||||
|
||||
return count ? RES_ERROR : RES_OK;
|
||||
}
|
||||
@ -442,35 +464,35 @@ DRESULT disk_write (
|
||||
BYTE count /* Sector count (1..255) */
|
||||
)
|
||||
{
|
||||
if (drv || !count) return RES_PARERR;
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||
if (Stat & STA_PROTECT) return RES_WRPRT;
|
||||
if (!count) return RES_PARERR;
|
||||
if (Stat[drv] & STA_NOINIT) return RES_NOTRDY;
|
||||
if (Stat[drv] & STA_PROTECT) return RES_WRPRT;
|
||||
|
||||
if (!(CardType & 4)) sector *= 512; /* Convert to byte address if needed */
|
||||
if (!(CardType[drv] & 4)) sector *= 512; /* Convert to byte address if needed */
|
||||
|
||||
SELECT(); /* CS = L */
|
||||
SELECT(drv); /* CS = L */
|
||||
|
||||
if (count == 1) { /* Single block write */
|
||||
if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
|
||||
&& xmit_datablock(buff, 0xFE))
|
||||
if ((send_cmd(drv, CMD24, sector) == 0) /* WRITE_BLOCK */
|
||||
&& xmit_datablock(drv, buff, 0xFE))
|
||||
count = 0;
|
||||
}
|
||||
else { /* Multiple block write */
|
||||
if (CardType & 2) {
|
||||
send_cmd(CMD55, 0); send_cmd(CMD23, count); /* ACMD23 */
|
||||
if (CardType[drv] & 2) {
|
||||
send_cmd(drv, CMD55, 0); send_cmd(drv, CMD23, count); /* ACMD23 */
|
||||
}
|
||||
if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
|
||||
if (send_cmd(drv, CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
|
||||
do {
|
||||
if (!xmit_datablock(buff, 0xFC)) break;
|
||||
if (!xmit_datablock(drv, buff, 0xFC)) break;
|
||||
buff += 512;
|
||||
} while (--count);
|
||||
if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
|
||||
if (!xmit_datablock(drv, 0, 0xFD)) /* STOP_TRAN token */
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
DESELECT(); /* CS = H */
|
||||
rcvr_spi(); /* Idle (Release DO) */
|
||||
DESELECT(drv); /* CS = H */
|
||||
rcvr_spi(drv); /* Idle (Release DO) */
|
||||
|
||||
return count ? RES_ERROR : RES_OK;
|
||||
}
|
||||
@ -493,23 +515,21 @@ DRESULT disk_ioctl (
|
||||
WORD csize;
|
||||
|
||||
|
||||
if (drv) return RES_PARERR;
|
||||
|
||||
res = RES_ERROR;
|
||||
|
||||
if (ctrl == CTRL_POWER) {
|
||||
switch (*ptr) {
|
||||
case 0: /* Sub control code == 0 (POWER_OFF) */
|
||||
if (chk_power())
|
||||
power_off(); /* Power off */
|
||||
if (chk_power(drv))
|
||||
power_off(drv); /* Power off */
|
||||
res = RES_OK;
|
||||
break;
|
||||
case 1: /* Sub control code == 1 (POWER_ON) */
|
||||
power_on(); /* Power on */
|
||||
power_on(drv); /* Power on */
|
||||
res = RES_OK;
|
||||
break;
|
||||
case 2: /* Sub control code == 2 (POWER_GET) */
|
||||
*(ptr+1) = (BYTE)chk_power();
|
||||
*(ptr+1) = (BYTE)chk_power(drv);
|
||||
res = RES_OK;
|
||||
break;
|
||||
default :
|
||||
@ -517,13 +537,13 @@ DRESULT disk_ioctl (
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||
if (Stat[drv] & STA_NOINIT) return RES_NOTRDY;
|
||||
|
||||
SELECT(); /* CS = L */
|
||||
SELECT(drv); /* CS = L */
|
||||
|
||||
switch (ctrl) {
|
||||
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
|
||||
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
|
||||
if ((send_cmd(drv,CMD9, 0) == 0) && rcvr_datablock(drv,csd, 16)) {
|
||||
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
|
||||
csize = csd[9] + ((WORD)csd[8] << 8) + 1;
|
||||
*(DWORD*)buff = (DWORD)csize << 10;
|
||||
@ -542,26 +562,26 @@ DRESULT disk_ioctl (
|
||||
break;
|
||||
|
||||
case CTRL_SYNC : /* Make sure that data has been written */
|
||||
if (wait_ready() == 0xFF)
|
||||
if (wait_ready(drv) == 0xFF)
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
case MMC_GET_CSD : /* Receive CSD as a data block (16 bytes) */
|
||||
if (send_cmd(CMD9, 0) == 0 /* READ_CSD */
|
||||
&& rcvr_datablock(ptr, 16))
|
||||
if (send_cmd(drv,CMD9, 0) == 0 /* READ_CSD */
|
||||
&& rcvr_datablock(drv, ptr, 16))
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
case MMC_GET_CID : /* Receive CID as a data block (16 bytes) */
|
||||
if (send_cmd(CMD10, 0) == 0 /* READ_CID */
|
||||
&& rcvr_datablock(ptr, 16))
|
||||
if (send_cmd(drv, CMD10, 0) == 0 /* READ_CID */
|
||||
&& rcvr_datablock(drv, ptr, 16))
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
case MMC_GET_OCR : /* Receive OCR as an R3 resp (4 bytes) */
|
||||
if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */
|
||||
if (send_cmd(drv, CMD58, 0) == 0) { /* READ_OCR */
|
||||
for (n = 0; n < 4; n++)
|
||||
*ptr++ = rcvr_spi();
|
||||
*ptr++ = rcvr_spi(drv);
|
||||
res = RES_OK;
|
||||
}
|
||||
|
||||
@ -574,8 +594,8 @@ DRESULT disk_ioctl (
|
||||
res = RES_PARERR;
|
||||
}
|
||||
|
||||
DESELECT(); /* CS = H */
|
||||
rcvr_spi(); /* Idle (Release DO) */
|
||||
DESELECT(drv); /* CS = H */
|
||||
rcvr_spi(drv); /* Idle (Release DO) */
|
||||
}
|
||||
|
||||
return res;
|
||||
@ -602,4 +622,5 @@ DWORD get_fattime (void)
|
||||
;
|
||||
|
||||
}
|
||||
#endif /* ifdef BUILD_MMCFS */
|
||||
#endif // #if defined( BUILD_MMCFS ) && !defined( ELUA_SIMULATOR )
|
||||
|
||||
|
222
src/elua_mmc_sim.c
Normal file
222
src/elua_mmc_sim.c
Normal file
@ -0,0 +1,222 @@
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* MMC/SD emulator for the eLua simulator */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#include "platform_conf.h"
|
||||
#if defined( BUILD_MMCFS ) && defined( ELUA_SIMULATOR )
|
||||
#include "platform.h"
|
||||
#include "hostif.h"
|
||||
#include "diskio.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define SD_CARD_SIM_NAME "sdcard.img"
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
Module Private Functions
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
static volatile
|
||||
DSTATUS Stat = STA_NOINIT; /* Disk status */
|
||||
|
||||
static
|
||||
BYTE PowerFlag = 0; /* indicates if "power" is on */
|
||||
|
||||
static int fd = -1;
|
||||
static long imgsize;
|
||||
|
||||
static
|
||||
void power_on (void)
|
||||
{
|
||||
PowerFlag = 1;
|
||||
}
|
||||
|
||||
static
|
||||
void power_off (void)
|
||||
{
|
||||
PowerFlag = 0;
|
||||
}
|
||||
|
||||
static
|
||||
int chk_power(void) /* Socket power state: 0=off, 1=on */
|
||||
{
|
||||
return PowerFlag;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
Public Functions
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Initialize Disk Drive */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_initialize (
|
||||
BYTE drv /* Physical drive nmuber (0) */
|
||||
)
|
||||
{
|
||||
if( drv )
|
||||
return STA_NOINIT;
|
||||
|
||||
if( fd != -1 )
|
||||
return Stat;
|
||||
|
||||
fd = hostif_open( SD_CARD_SIM_NAME, 2, 0666 );
|
||||
|
||||
if( fd == -1 )
|
||||
printf( "[SDSIM] Unable to open " SD_CARD_SIM_NAME "\n" );
|
||||
else
|
||||
{
|
||||
Stat = 0;
|
||||
imgsize = hostif_lseek( fd, 0, SEEK_END );
|
||||
hostif_lseek( fd, 0, SEEK_SET );
|
||||
printf( "[SDSIM] found SD card image, size=%ld bytes\n", imgsize );
|
||||
}
|
||||
return Stat;
|
||||
}
|
||||
|
||||
void elua_mmc_init()
|
||||
{
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Get Disk Status */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
|
||||
DSTATUS disk_status (
|
||||
BYTE drv /* Physical drive nmuber (0) */
|
||||
)
|
||||
{
|
||||
if (drv) return STA_NOINIT; /* Supports only single drive */
|
||||
return Stat;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Read Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_read (
|
||||
BYTE drv, /* Physical drive nmuber (0) */
|
||||
BYTE *buff, /* Pointer to the data buffer to store read data */
|
||||
DWORD sector, /* Start sector number (LBA) */
|
||||
BYTE count /* Sector count (1..255) */
|
||||
)
|
||||
{
|
||||
if (drv || !count) return RES_PARERR;
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||
|
||||
if( hostif_lseek( fd, sector * 512, SEEK_SET ) == -1 )
|
||||
return RES_ERROR;
|
||||
if( hostif_read( fd, buff, count * 512 ) != count * 512 )
|
||||
return RES_ERROR;
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Write Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_write (
|
||||
BYTE drv, /* Physical drive nmuber (0) */
|
||||
const BYTE *buff, /* Pointer to the data to be written */
|
||||
DWORD sector, /* Start sector number (LBA) */
|
||||
BYTE count /* Sector count (1..255) */
|
||||
)
|
||||
{
|
||||
if (drv || !count) return RES_PARERR;
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||
|
||||
if( hostif_lseek( fd, sector * 512, SEEK_SET ) == -1 )
|
||||
return RES_ERROR;
|
||||
if( hostif_write( fd, buff, count * 512 ) != count * 512 )
|
||||
return RES_ERROR;
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Miscellaneous Functions */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_ioctl (
|
||||
BYTE drv, /* Physical drive nmuber (0) */
|
||||
BYTE ctrl, /* Control code */
|
||||
void *buff /* Buffer to send/receive control data */
|
||||
)
|
||||
{
|
||||
DRESULT res;
|
||||
BYTE *ptr = buff;
|
||||
|
||||
if (drv) return RES_PARERR;
|
||||
res = RES_ERROR;
|
||||
|
||||
if (ctrl == CTRL_POWER) {
|
||||
switch (*ptr) {
|
||||
case 0: /* Sub control code == 0 (POWER_OFF) */
|
||||
if (chk_power())
|
||||
power_off(); /* Power off */
|
||||
res = RES_OK;
|
||||
break;
|
||||
case 1: /* Sub control code == 1 (POWER_ON) */
|
||||
power_on(); /* Power on */
|
||||
res = RES_OK;
|
||||
break;
|
||||
case 2: /* Sub control code == 2 (POWER_GET) */
|
||||
*(ptr+1) = (BYTE)chk_power();
|
||||
res = RES_OK;
|
||||
break;
|
||||
default :
|
||||
res = RES_PARERR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||
|
||||
switch (ctrl) {
|
||||
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
|
||||
*(DWORD*)buff = imgsize / 512;
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
case GET_SECTOR_SIZE : /* Get sectors on the disk (WORD) */
|
||||
*(WORD*)buff = 512;
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
case CTRL_SYNC : /* Make sure that data has been written */
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf( "[SDSIM] unhandled IOCTL %d\n", ctrl );
|
||||
res = RES_PARERR;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------*/
|
||||
/* User Provided Timer Function for FatFs module */
|
||||
/*---------------------------------------------------------*/
|
||||
/* This is a real time clock service to be called from */
|
||||
/* FatFs module. Any valid time must be returned even if */
|
||||
/* the system does not support a real time clock. */
|
||||
|
||||
DWORD get_fattime (void)
|
||||
{
|
||||
|
||||
return ((2007UL-1980) << 25) // Year = 2007
|
||||
| (6UL << 21) // Month = June
|
||||
| (5UL << 16) // Day = 5
|
||||
| (11U << 11) // Hour = 11
|
||||
| (38U << 5) // Min = 38
|
||||
| (0U >> 1) // Sec = 0
|
||||
;
|
||||
|
||||
}
|
||||
#endif // #if defined( BUILD_MMCFS ) && defined( ELUA_SIMULATOR )
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "type.h"
|
||||
#include "integer.h"
|
||||
#include "devman.h"
|
||||
#include "platform_conf.h"
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function and Buffer Configurations
|
||||
@ -29,7 +30,7 @@
|
||||
/ f_truncate and useless f_getfree. */
|
||||
|
||||
|
||||
#define _FS_MINIMIZE 1 /* 0, 1, 2 or 3 */
|
||||
#define _FS_MINIMIZE 0
|
||||
/* The _FS_MINIMIZE option defines minimization level to remove some functions.
|
||||
/
|
||||
/ 0: Full function.
|
||||
@ -119,7 +120,11 @@
|
||||
/ Physical Drive Configurations
|
||||
/----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef MMCFS_NUM_CARDS
|
||||
#define _DRIVES 1
|
||||
#else
|
||||
#define _DRIVES MMCFS_NUM_CARDS
|
||||
#endif
|
||||
/* Number of volumes (logical drives) to be used. */
|
||||
|
||||
|
||||
|
@ -62,13 +62,6 @@ static void save (LexState *ls, int c) {
|
||||
|
||||
|
||||
void luaX_init (lua_State *L) {
|
||||
int i;
|
||||
for (i=0; i<NUM_RESERVED; i++) {
|
||||
TString *ts = luaS_new(L, luaX_tokens[i]);
|
||||
luaS_fix(ts); /* reserved words are never collected */
|
||||
lua_assert(strlen(luaX_tokens[i])+1 <= TOKEN_LEN);
|
||||
ts->tsv.reserved = cast_byte(i+1); /* reserved word */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -422,17 +415,19 @@ static int llex (LexState *ls, SemInfo *seminfo) {
|
||||
else if (isalpha(ls->current) || ls->current == '_') {
|
||||
/* identifier or reserved word */
|
||||
TString *ts;
|
||||
int i;
|
||||
do {
|
||||
save_and_next(ls);
|
||||
} while (isalnum(ls->current) || ls->current == '_');
|
||||
/* look for reserved word */
|
||||
save(ls, '\0');
|
||||
for (i = 0; i < NUM_RESERVED; i++)
|
||||
if (!strcmp(luaX_tokens[i], luaZ_buffer(ls->buff)))
|
||||
return i + FIRST_RESERVED;
|
||||
ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
|
||||
luaZ_bufflen(ls->buff));
|
||||
if (ts->tsv.reserved > 0) /* reserved word? */
|
||||
return ts->tsv.reserved - 1 + FIRST_RESERVED;
|
||||
else {
|
||||
seminfo->ts = ts;
|
||||
return TK_NAME;
|
||||
}
|
||||
luaZ_bufflen(ls->buff) - 1);
|
||||
seminfo->ts = ts;
|
||||
return TK_NAME;
|
||||
}
|
||||
else {
|
||||
int c = ls->current;
|
||||
|
@ -360,7 +360,6 @@ typedef union TString {
|
||||
L_Umaxalign dummy; /* ensures maximum alignment for strings */
|
||||
struct {
|
||||
CommonHeader;
|
||||
lu_byte reserved;
|
||||
unsigned int hash;
|
||||
size_t len;
|
||||
} tsv;
|
||||
|
@ -126,9 +126,9 @@ void luaR_getcstr(char *dest, const TString *src, size_t maxsize) {
|
||||
|
||||
/* Return 1 if the given pointer is a rotable */
|
||||
#ifdef LUA_META_ROTABLES
|
||||
extern char stext[];
|
||||
extern char etext[];
|
||||
extern char stext;
|
||||
extern char etext;
|
||||
int luaR_isrotable(void *p) {
|
||||
return stext <= ( char* )p && ( char* )p <= etext;
|
||||
return &stext <= ( char* )p && ( char* )p <= &etext;
|
||||
}
|
||||
#endif
|
||||
|
@ -65,7 +65,6 @@ static TString *newlstr (lua_State *L, const char *str, size_t l,
|
||||
ts->tsv.hash = h;
|
||||
ts->tsv.marked = luaC_white(G(L));
|
||||
ts->tsv.tt = LUA_TSTRING;
|
||||
ts->tsv.reserved = 0;
|
||||
if (!readonly) {
|
||||
memcpy(ts+1, str, l*sizeof(char));
|
||||
((char *)(ts+1))[l] = '\0'; /* ending 0 */
|
||||
|
134
src/mmcfs.c
134
src/mmcfs.c
@ -6,25 +6,38 @@
|
||||
#include "devman.h"
|
||||
#include <stdio.h>
|
||||
#include "ioctl.h"
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "platform_conf.h"
|
||||
#ifdef BUILD_MMCFS
|
||||
#include "ff.h"
|
||||
#include "diskio.h"
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MMCFS_MAX_FDS 4
|
||||
static FIL mmcfs_fd_table[ MMCFS_MAX_FDS ];
|
||||
static int mmcfs_num_fd;
|
||||
|
||||
extern void elua_mmc_init();
|
||||
|
||||
#ifndef MMCFS_NUM_CARDS
|
||||
#define NUM_CARDS 1
|
||||
#else
|
||||
#define NUM_CARDS MMCFS_NUM_CARDS
|
||||
#endif
|
||||
|
||||
// Data structures used by FatFs
|
||||
static FATFS mmc_fs;
|
||||
static FATFS mmc_fs[ NUM_CARDS ];
|
||||
static FIL mmc_fileObject;
|
||||
//static DIR mmc_dir;
|
||||
//static FILINFO mmc_fileInfo;
|
||||
|
||||
#define PATH_BUF_SIZE 40
|
||||
static char mmc_pathBuf[PATH_BUF_SIZE];
|
||||
typedef struct
|
||||
{
|
||||
DIR *dir;
|
||||
struct dm_dirent *pdm;
|
||||
} MMCFS_DIRENT_DATA;
|
||||
|
||||
static int mmcfs_find_empty_fd( void )
|
||||
{
|
||||
@ -40,6 +53,8 @@ static int mmcfs_open_r( struct _reent *r, const char *path, int flags, int mode
|
||||
{
|
||||
int fd;
|
||||
int mmc_mode;
|
||||
char *mmc_pathBuf;
|
||||
int drv_num = *( int* )pdata;
|
||||
|
||||
if (mmcfs_num_fd == MMCFS_MAX_FDS)
|
||||
{
|
||||
@ -48,10 +63,15 @@ static int mmcfs_open_r( struct _reent *r, const char *path, int flags, int mode
|
||||
}
|
||||
|
||||
// Default to top directory if none given
|
||||
mmc_pathBuf[0] = 0;
|
||||
if (strchr(path, '/') == NULL)
|
||||
strcat(mmc_pathBuf, "/");
|
||||
strcat(mmc_pathBuf, path);
|
||||
asprintf( &mmc_pathBuf, "%d:/%s", drv_num, path );
|
||||
else
|
||||
asprintf( &mmc_pathBuf, "%d:%s", drv_num, path );
|
||||
if( mmc_pathBuf == NULL )
|
||||
{
|
||||
r->_errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Scrub binary flag, if defined
|
||||
#ifdef O_BINARY
|
||||
@ -62,6 +82,7 @@ static int mmcfs_open_r( struct _reent *r, const char *path, int flags, int mode
|
||||
if ((flags & O_ACCMODE) != O_RDONLY)
|
||||
{
|
||||
r->_errno = EROFS;
|
||||
free( mmc_pathBuf );
|
||||
return -1;
|
||||
}
|
||||
mmc_mode = FA_OPEN_EXISTING & FA_READ;
|
||||
@ -78,6 +99,7 @@ static int mmcfs_open_r( struct _reent *r, const char *path, int flags, int mode
|
||||
else
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
free( mmc_pathBuf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -90,6 +112,7 @@ static int mmcfs_open_r( struct _reent *r, const char *path, int flags, int mode
|
||||
else
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
free( mmc_pathBuf );
|
||||
return -1;
|
||||
}
|
||||
#endif // _FS_READONLY
|
||||
@ -98,6 +121,7 @@ static int mmcfs_open_r( struct _reent *r, const char *path, int flags, int mode
|
||||
if (f_open(&mmc_fileObject, mmc_pathBuf, mmc_mode) != FR_OK)
|
||||
{
|
||||
r->_errno = ENOENT;
|
||||
free( mmc_pathBuf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -106,6 +130,7 @@ static int mmcfs_open_r( struct _reent *r, const char *path, int flags, int mode
|
||||
fd = mmcfs_find_empty_fd();
|
||||
memcpy(mmcfs_fd_table + fd, &mmc_fileObject, sizeof(FIL));
|
||||
mmcfs_num_fd ++;
|
||||
free( mmc_pathBuf );
|
||||
return fd;
|
||||
}
|
||||
|
||||
@ -184,23 +209,47 @@ static off_t mmcfs_lseek_r( struct _reent *r, int fd, off_t off, int whence, voi
|
||||
}
|
||||
|
||||
// opendir
|
||||
static DIR mmc_dir;
|
||||
static void* mmcfs_opendir_r( struct _reent *r, const char* dname, void *pdata )
|
||||
{
|
||||
void* res = NULL;
|
||||
if( !dname || strlen( dname ) == 0 || ( strlen( dname ) == 1 && !strcmp( dname, "/" ) ) )
|
||||
res = f_opendir( &mmc_dir, "/" ) != FR_OK ? NULL : &mmc_dir;
|
||||
MMCFS_DIRENT_DATA *pd = ( MMCFS_DIRENT_DATA* )malloc( sizeof( MMCFS_DIRENT_DATA ) );
|
||||
int drv_num = *( int* )pdata;
|
||||
char *pname = NULL;
|
||||
|
||||
if( !pd )
|
||||
return NULL;
|
||||
memset( pd, 0, sizeof( MMCFS_DIRENT_DATA ) );
|
||||
if( ( pd->dir = ( DIR* )malloc( sizeof( DIR ) ) ) == NULL )
|
||||
goto out;
|
||||
if( ( pd->pdm = ( struct dm_dirent* )malloc( sizeof( struct dm_dirent ) ) ) == NULL )
|
||||
goto out;
|
||||
if( !dname || strlen( dname ) == 0 )
|
||||
asprintf( &pname, "%d:/", drv_num );
|
||||
else
|
||||
asprintf( &pname, "%d:%s", drv_num, dname );
|
||||
res = f_opendir( pd->dir, pname ) != FR_OK ? NULL : pd;
|
||||
out:
|
||||
if( res == NULL )
|
||||
{
|
||||
if( pd->dir )
|
||||
free( pd->dir );
|
||||
if( pd->pdm )
|
||||
free( pd->pdm );
|
||||
free( pd );
|
||||
}
|
||||
if( pname )
|
||||
free( pname );
|
||||
return res;
|
||||
}
|
||||
|
||||
// readdir
|
||||
extern struct dm_dirent dm_shared_dirent;
|
||||
extern char dm_shared_fname[ DM_MAX_FNAME_LENGTH + 1 ];
|
||||
static struct dm_dirent* mmcfs_readdir_r( struct _reent *r, void *d, void *pdata )
|
||||
{
|
||||
DIR *pdir = ( DIR* )d;
|
||||
MMCFS_DIRENT_DATA *pd = ( MMCFS_DIRENT_DATA* )d;
|
||||
DIR *pdir = pd->dir;
|
||||
FILINFO mmc_file_info;
|
||||
struct dm_dirent* pent = &dm_shared_dirent;
|
||||
struct dm_dirent* pent = pd->pdm;
|
||||
char *fn;
|
||||
#if _USE_LFN
|
||||
static char lfn[_MAX_LFN * (_DF1S ? 2 : 1) + 1];
|
||||
@ -213,15 +262,18 @@ static struct dm_dirent* mmcfs_readdir_r( struct _reent *r, void *d, void *pdata
|
||||
if( f_readdir( pdir, &mmc_file_info ) != FR_OK ) // return NULL on read error
|
||||
return NULL;
|
||||
if( mmc_file_info.fname[ 0 ] == '\0' ) // return NULL when listing is done
|
||||
return NULL;
|
||||
if( ( mmc_file_info.fattrib & AM_DIR ) == 0 ) // if we have a file, exit loop
|
||||
break;
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
#if _USE_LFN
|
||||
fn = *mmc_file_info.lfname ? mmc_file_info.lfname : mmc_file_info.fname;
|
||||
#else
|
||||
fn = mmc_file_info.fname;
|
||||
#endif
|
||||
if( ( mmc_file_info.fattrib & AM_DIR ) != 0 ) // if we have a file, exit loop
|
||||
pent->flags = DM_DIRENT_FLAG_DIR;
|
||||
else
|
||||
pent->flags = 0;
|
||||
strncpy( dm_shared_fname, fn, DM_MAX_FNAME_LENGTH );
|
||||
pent->fname = dm_shared_fname;
|
||||
pent->fsize = mmc_file_info.fsize;
|
||||
@ -232,9 +284,29 @@ static struct dm_dirent* mmcfs_readdir_r( struct _reent *r, void *d, void *pdata
|
||||
// closedir
|
||||
static int mmcfs_closedir_r( struct _reent *r, void *d, void *pdata )
|
||||
{
|
||||
MMCFS_DIRENT_DATA *pd = ( MMCFS_DIRENT_DATA* )d;
|
||||
|
||||
free( pd->dir );
|
||||
free( pd->pdm );
|
||||
free( pd );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmcfs_mkdir_r( struct _reent *r, const char *name, mkdir_mode_t mode, void *pdata )
|
||||
{
|
||||
return f_mkdir( name );
|
||||
}
|
||||
|
||||
static int mmcfs_unlink_r( struct _reent *r, const char *fname, void *pdata )
|
||||
{
|
||||
return f_unlink( fname );
|
||||
}
|
||||
|
||||
static int mmcfs_rename_r( struct _reent *r, const char *oldname, const char *newname, void *pdata )
|
||||
{
|
||||
return f_rename( oldname, newname );
|
||||
}
|
||||
|
||||
// MMC device descriptor structure
|
||||
static const DM_DEVICE mmcfs_device =
|
||||
{
|
||||
@ -246,15 +318,37 @@ static const DM_DEVICE mmcfs_device =
|
||||
mmcfs_opendir_r, // opendir
|
||||
mmcfs_readdir_r, // readdir
|
||||
mmcfs_closedir_r, // closedir
|
||||
NULL // getaddr
|
||||
NULL, // getaddr
|
||||
mmcfs_mkdir_r, // mkdir
|
||||
mmcfs_unlink_r, // unlink
|
||||
mmcfs_unlink_r, // rmdir
|
||||
mmcfs_rename_r // rename
|
||||
};
|
||||
|
||||
int mmcfs_init()
|
||||
{
|
||||
// Mount the MMC file system using logical disk 0
|
||||
if ( f_mount( 0, &mmc_fs ) != FR_OK )
|
||||
elua_mmc_init();
|
||||
#if NUM_CARDS == 1
|
||||
static int cid = 0;
|
||||
// A single MMCFS
|
||||
if ( f_mount( 0, mmc_fs ) != FR_OK )
|
||||
return DM_ERR_INIT;
|
||||
return dm_register( "/mmc", NULL, &mmcfs_device );
|
||||
return dm_register( "/mmc", &cid, &mmcfs_device );
|
||||
#else // #if NUM_CARDS == 1
|
||||
int i;
|
||||
static char names[ NUM_CARDS ][ 6 ];
|
||||
static int ids[ NUM_CARDS ];
|
||||
|
||||
// [TODO] add more error checking!
|
||||
for( i = 0; i < NUM_CARDS; i ++ )
|
||||
if( f_mount( i, mmc_fs + i ) == FR_OK )
|
||||
{
|
||||
ids[ i ] = i;
|
||||
sprintf( names[ i ], "/mmc%d", i );
|
||||
dm_register( names[ i ], ids + i, &mmcfs_device );
|
||||
}
|
||||
return DM_OK;
|
||||
#endif // #if NUM_CARDS == 1
|
||||
}
|
||||
|
||||
#else // #ifdef BUILD_MMCFS
|
||||
|
@ -9,7 +9,9 @@
|
||||
#include "legc.h"
|
||||
#include "platform_conf.h"
|
||||
#include "linenoise.h"
|
||||
#include "shell.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined( USE_GIT_REVISION )
|
||||
#include "git_version.h"
|
||||
@ -59,6 +61,22 @@ static int elua_save_history( lua_State *L )
|
||||
#endif // #ifdef BUILD_LINENOISE
|
||||
}
|
||||
|
||||
// Lua: elua.shell( <shell_command> )
|
||||
static int elua_shell( lua_State *L )
|
||||
{
|
||||
const char *pcmd = luaL_checkstring( L, 1 );
|
||||
char *cmdcpy;
|
||||
|
||||
// "+2" below comes from the string terminator (+1) and the '\n'
|
||||
// that will be added by the shell code (+1)
|
||||
if( ( cmdcpy = ( char* )malloc( strlen( pcmd ) + 2 ) ) == NULL )
|
||||
return luaL_error( L, "not enough memory for elua_shell" );
|
||||
strcpy( cmdcpy, pcmd );
|
||||
shellh_execute_command( cmdcpy, 0 );
|
||||
free( cmdcpy );
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Module function map
|
||||
#define MIN_OPT_LEVEL 2
|
||||
#include "lrodefs.h"
|
||||
@ -67,6 +85,7 @@ const LUA_REG_TYPE elua_map[] =
|
||||
{ LSTRKEY( "egc_setup" ), LFUNCVAL( elua_egc_setup ) },
|
||||
{ LSTRKEY( "version" ), LFUNCVAL( elua_version ) },
|
||||
{ LSTRKEY( "save_history" ), LFUNCVAL( elua_save_history ) },
|
||||
{ LSTRKEY( "shell" ), LFUNCVAL( elua_shell ) },
|
||||
#if LUA_OPTIMIZE_MEMORY > 0
|
||||
{ LSTRKEY( "EGC_NOT_ACTIVE" ), LNUMVAL( EGC_NOT_ACTIVE ) },
|
||||
{ LSTRKEY( "EGC_ON_ALLOC_FAILURE" ), LNUMVAL( EGC_ON_ALLOC_FAILURE ) },
|
||||
|
@ -45,8 +45,10 @@ void *alloca(size_t);
|
||||
// Support for Compiling with & without rotables
|
||||
#ifdef LUA_OPTIMIZE_MEMORY
|
||||
#define LUA_ISCALLABLE( state, idx ) ( lua_isfunction( state, idx ) || lua_islightfunction( state, idx ) )
|
||||
#define LUA_ISATABLE( state, idx ) ( lua_istable( state, idx ) || lua_isrotable( state, idx ) )
|
||||
#else
|
||||
#define LUA_ISCALLABLE( state, idx ) lua_isfunction( state, idx )
|
||||
#define LUA_ISATABLE( state, idx ) lua_istable( state, idx )
|
||||
#endif
|
||||
|
||||
// Prototypes for Local Functions
|
||||
@ -1232,16 +1234,16 @@ static void read_cmd_call( Transport *tpt, lua_State *L )
|
||||
// @@@ also strtok is not thread safe
|
||||
token = strtok( funcname, "." );
|
||||
lua_getglobal( L, token );
|
||||
if( LUA_ISCALLABLE( L, -1 ) || lua_istable( L, -1 ) ) // only continue if non-nil
|
||||
if( LUA_ISCALLABLE( L, -1 ) || LUA_ISATABLE( L, -1 ) ) // only continue if non-nil
|
||||
{
|
||||
token = strtok( NULL, "." );
|
||||
|
||||
// loop over remainder of string, leaving token with last value if
|
||||
// indexing fails
|
||||
while( token != NULL && ( LUA_ISCALLABLE( L, -1 ) || lua_istable( L, -1 ) ) )
|
||||
while( token != NULL && ( LUA_ISCALLABLE( L, -1 ) || LUA_ISATABLE( L, -1 ) ) )
|
||||
{
|
||||
lua_getfield( L, -1, token );
|
||||
if ( LUA_ISCALLABLE( L, -1 ) || lua_istable( L, -1 ) )
|
||||
if ( LUA_ISCALLABLE( L, -1 ) || LUA_ISATABLE( L, -1 ) )
|
||||
{
|
||||
lua_remove( L, -2 );
|
||||
token = strtok( NULL, "." );
|
||||
@ -1291,7 +1293,7 @@ static void read_cmd_call( Transport *tpt, lua_State *L )
|
||||
const char *msg;
|
||||
if ( lua_isnil( L, -1 ) )
|
||||
msg = "undefined: ";
|
||||
else if ( lua_istable( L, -1 ) )
|
||||
else if ( LUA_ISATABLE( L, -1 ) )
|
||||
msg = "can't call table";
|
||||
else
|
||||
msg = "not table/func: ";
|
||||
|
@ -15,6 +15,10 @@
|
||||
#define MAX_VTIMER_NAME_LEN 6
|
||||
#define MIN_VTIMER_NAME_LEN 5
|
||||
|
||||
#if defined( BUILD_LUA_INT_HANDLERS ) && defined( INT_TMR_MATCH )
|
||||
#define HAS_TMR_MATCH_INT
|
||||
#endif
|
||||
|
||||
// Helper function for the read/start functions
|
||||
static int tmrh_timer_op( lua_State* L, int op )
|
||||
{
|
||||
@ -135,7 +139,7 @@ static int tmr_getclock( lua_State* L )
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef BUILD_LUA_INT_HANDLERS
|
||||
#ifdef HAS_TMR_MATCH_INT
|
||||
// Lua: set_match_int( id, timeout, type )
|
||||
static int tmr_set_match_int( lua_State *L )
|
||||
{
|
||||
@ -153,7 +157,7 @@ static int tmr_set_match_int( lua_State *L )
|
||||
return luaL_error( L, "match interrupt cannot be set on this timer" );
|
||||
return 0;
|
||||
}
|
||||
#endif // #ifdef BUILD_LUA_INT_HANDLERS
|
||||
#endif // #ifdef HAS_TMR_MATCH_INT
|
||||
|
||||
#if VTMR_NUM_TIMERS > 0
|
||||
// __index metafunction for TMR
|
||||
@ -192,7 +196,7 @@ const LUA_REG_TYPE tmr_map[] =
|
||||
{ LSTRKEY( "getmaxdelay" ), LFUNCVAL( tmr_getmaxdelay ) },
|
||||
{ LSTRKEY( "setclock" ), LFUNCVAL( tmr_setclock ) },
|
||||
{ LSTRKEY( "getclock" ), LFUNCVAL( tmr_getclock ) },
|
||||
#ifdef BUILD_LUA_INT_HANDLERS
|
||||
#ifdef HAS_TMR_MATCH_INT
|
||||
{ LSTRKEY( "set_match_int" ), LFUNCVAL( tmr_set_match_int ) },
|
||||
#endif
|
||||
#if LUA_OPTIMIZE_MEMORY > 0 && VTMR_NUM_TIMERS > 0
|
||||
@ -223,10 +227,10 @@ LUALIB_API int luaopen_tmr( lua_State *L )
|
||||
lua_setmetatable( L, -2 );
|
||||
#endif // #if VTMR_NUM_TIMERS > 0
|
||||
MOD_REG_NUMBER( L, "SYS_TIMER", PLATFORM_TIMER_SYS_ID );
|
||||
#ifdef BUILD_LUA_INT_HANDLERS
|
||||
#ifdef HAS_TMR_MATCH_INT
|
||||
MOD_REG_NUMBER( L, "INT_ONESHOT", PLATFORM_TIMER_INT_ONESHOT );
|
||||
MOD_REG_NUMBER( L, "INT_CYCLIC", PLATFORM_TIMER_INT_CYCLIC );
|
||||
#endif //#ifdef BUILD_LUA_INT_HANDLERS
|
||||
#endif //#ifdef HAS_TMR_MATCH_INT
|
||||
return 1;
|
||||
#endif // #if LUA_OPTIMIZE_MEMORY > 0
|
||||
}
|
||||
|
@ -142,7 +142,11 @@ static const DM_DEVICE std_device =
|
||||
NULL, // opendir
|
||||
NULL, // readdir
|
||||
NULL, // closedir
|
||||
NULL // getaddr
|
||||
NULL, // getaddr
|
||||
NULL, // mkdir
|
||||
NULL, // unlink
|
||||
NULL, // rmdir
|
||||
NULL // rename
|
||||
};
|
||||
|
||||
int std_register()
|
||||
|
@ -93,7 +93,11 @@ static const DM_DEVICE std_device =
|
||||
NULL, // opendir
|
||||
NULL, // readdir
|
||||
NULL, // closedir
|
||||
NULL // getaddr
|
||||
NULL, // getaddr
|
||||
NULL, // mkdir
|
||||
NULL, // unlink
|
||||
NULL, // rmdir
|
||||
NULL // rename
|
||||
};
|
||||
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "genstd.h"
|
||||
#include "utils.h"
|
||||
#include "salloc.h"
|
||||
#include "shell.h"
|
||||
|
||||
#ifdef USE_MULTIPLE_ALLOCATOR
|
||||
#include "dlmalloc.h"
|
||||
@ -96,6 +97,11 @@ int _open_r( struct _reent *r, const char *name, int flags, int mode )
|
||||
return DM_MAKE_DESC( devid, res );
|
||||
}
|
||||
|
||||
int open( const char *name, int flags, mode_t mode )
|
||||
{
|
||||
return _open_r( _REENT, name, flags, 0 );
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// _close_r
|
||||
int _close_r( struct _reent *r, int file )
|
||||
@ -114,6 +120,11 @@ int _close_r( struct _reent *r, int file )
|
||||
return pinst->pdev->p_close_r( r, DM_GET_FD( file ), pinst->pdata );
|
||||
}
|
||||
|
||||
int close( int file )
|
||||
{
|
||||
return _close_r( _REENT, file );
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// _fstat_r (not implemented)
|
||||
int _fstat_r( struct _reent *r, int file, struct stat *st )
|
||||
@ -163,6 +174,11 @@ _ssize_t _read_r( struct _reent *r, int file, void *ptr, size_t len )
|
||||
return pinst->pdev->p_read_r( r, DM_GET_FD( file ), ptr, len, pinst->pdata );
|
||||
}
|
||||
|
||||
_ssize_t read( int file, void *ptr, size_t len )
|
||||
{
|
||||
return _read_r( _REENT, file, ptr, len );
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// _write_r
|
||||
_ssize_t _write_r( struct _reent *r, int file, const void *ptr, size_t len )
|
||||
@ -181,6 +197,134 @@ _ssize_t _write_r( struct _reent *r, int file, const void *ptr, size_t len )
|
||||
return pinst->pdev->p_write_r( r, DM_GET_FD( file ), ptr, len, pinst->pdata );
|
||||
}
|
||||
|
||||
_ssize_t write( int file, const void *ptr, size_t len )
|
||||
{
|
||||
return _write_r( _REENT, file, ptr, len );
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// _mkdir_r
|
||||
int _mkdir_r( struct _reent *r, const char *path, mkdir_mode_t mode )
|
||||
{
|
||||
char* actname;
|
||||
int devid;
|
||||
const DM_INSTANCE_DATA *pinst;
|
||||
|
||||
// Look for device, return error if not found or if function not implemented
|
||||
if( ( devid = find_dm_entry( path, &actname ) ) == -1 )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
pinst = dm_get_instance_at( devid );
|
||||
if( pinst->pdev->p_mkdir_r == NULL )
|
||||
{
|
||||
r->_errno = EPERM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Device found, call its function
|
||||
return pinst->pdev->p_mkdir_r( r, actname - 1, mode, pinst->pdata );
|
||||
}
|
||||
|
||||
int mkdir( const char *path, mode_t mode )
|
||||
{
|
||||
return _mkdir_r( _REENT, path, mode );
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// _unlink_r
|
||||
int _unlink_r( struct _reent *r, const char *fname )
|
||||
{
|
||||
char* actname;
|
||||
int devid;
|
||||
const DM_INSTANCE_DATA *pinst;
|
||||
|
||||
// Look for device, return error if not found or if function not implemented
|
||||
if( ( devid = find_dm_entry( fname, &actname ) ) == -1 )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
pinst = dm_get_instance_at( devid );
|
||||
if( pinst->pdev->p_unlink_r == NULL )
|
||||
{
|
||||
r->_errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Device found, call its function
|
||||
return pinst->pdev->p_unlink_r( r, actname, pinst->pdata );
|
||||
}
|
||||
|
||||
int unlink( const char *path )
|
||||
{
|
||||
return _unlink_r( _REENT, path );
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// rmdir
|
||||
|
||||
int rmdir( const char *path )
|
||||
{
|
||||
char* actname;
|
||||
int devid;
|
||||
const DM_INSTANCE_DATA *pinst;
|
||||
|
||||
// Look for device, return error if not found or if function not implemented
|
||||
if( ( devid = find_dm_entry( path, &actname ) ) == -1 )
|
||||
{
|
||||
_REENT->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
pinst = dm_get_instance_at( devid );
|
||||
if( pinst->pdev->p_rmdir_r == NULL )
|
||||
{
|
||||
_REENT->_errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Device found, call its function
|
||||
return pinst->pdev->p_rmdir_r( _REENT, actname, pinst->pdata );
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// rename
|
||||
|
||||
int _rename_r( struct _reent *r, const char *oldname, const char *newname )
|
||||
{
|
||||
char *actname_old, *actname_new;
|
||||
int devid_old, devid_new;
|
||||
const DM_INSTANCE_DATA *pinst;
|
||||
|
||||
// Look for device, return error if not found or if function not implemented
|
||||
if( ( devid_old = find_dm_entry( oldname, &actname_old ) ) == -1 )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
if( ( devid_new = find_dm_entry( newname, &actname_new ) ) == -1 )
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
if( devid_old == devid_new )
|
||||
{
|
||||
pinst = dm_get_instance_at( devid_old );
|
||||
if( pinst->pdev->p_rename_r == NULL )
|
||||
{
|
||||
r->_errno = EPERM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Device found, call its function
|
||||
return pinst->pdev->p_rename_r( r, actname_old, actname_new, pinst->pdata );
|
||||
}
|
||||
// Cannot rename between different devices (EXDEV)
|
||||
r->_errno = EXDEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Miscellaneous functions
|
||||
|
||||
@ -215,12 +359,6 @@ clock_t _times_r( struct _reent* r, struct tms *buf )
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _unlink_r( struct _reent *r, const char *name )
|
||||
{
|
||||
r->_errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _link_r( struct _reent *r, const char *c1, const char *c2 )
|
||||
{
|
||||
r->_errno = ENOSYS;
|
||||
@ -254,11 +392,24 @@ int _vfprintf_r( struct _reent *r, FILE *stream, const char *format, va_list ap
|
||||
return _vfiprintf_r( r, stream, format, ap );
|
||||
}
|
||||
|
||||
extern int _svfiprintf_r( struct _reent *r, FILE *stream, const char *format, va_list ap );
|
||||
int _svfprintf_r( struct _reent *r, FILE *stream, const char *format, va_list ap )
|
||||
{
|
||||
return _svfiprintf_r( r, stream, format, ap );
|
||||
}
|
||||
|
||||
extern int __svfiscanf_r(struct _reent *,FILE *, _CONST char *,va_list);
|
||||
int __svfscanf_r( struct _reent *r, FILE *stream, const char *format, va_list ap )
|
||||
{
|
||||
return __svfiscanf_r( r, stream, format, ap );
|
||||
}
|
||||
|
||||
extern int __ssvfiscanf_r(struct _reent *,FILE *, _CONST char *,va_list);
|
||||
int __ssvfscanf_r( struct _reent *r, FILE *stream, const char *format, va_list ap )
|
||||
{
|
||||
return __ssvfiscanf_r( r, stream, format, ap );
|
||||
}
|
||||
|
||||
#endif // #ifdef LUA_NUMBER_INTEGRAL
|
||||
|
||||
// ****************************************************************************
|
||||
|
@ -11,6 +11,7 @@ function add_platform_components( t, board, cpu )
|
||||
if board == 'EK-LM3S1968' or board == 'EK-LM3S6965' or board == 'EK-LM3S8962' then
|
||||
t.lm3s_disp = { macro = 'ENABLE_DISP' }
|
||||
end
|
||||
t.lm3s_pio = { macro = 'ENABLE_LM3S_GPIO' }
|
||||
end
|
||||
|
||||
-- Add specific configuration to the 'configs' table
|
||||
@ -19,11 +20,11 @@ end
|
||||
|
||||
-- Return an array of all the available platform modules for the given cpu
|
||||
function get_platform_modules( board, cpu )
|
||||
m = { pio = { guards = { 'ENABLE_LM3S_GPIO' }, lib = '"pio"', map = "lm3s_pio_map", open = false } }
|
||||
board = board:upper()
|
||||
if board == 'EK-LM3S1968' or board == 'EK-LM3S6965' or board == 'EK-LM3S8962' then
|
||||
return {
|
||||
disp = { guards = { 'ENABLE_DISP' }, lib = '"disp"', open = false }
|
||||
}
|
||||
m.disp = { guards = { 'ENABLE_DISP' }, lib = '"disp"', open = false }
|
||||
end
|
||||
return m
|
||||
end
|
||||
|
||||
|
@ -10,7 +10,7 @@ if cpu == 'LM3S9B92' or board == 'LM3S9D92' then
|
||||
addi( sf( 'src/platform/%s/usblib/device', platform ) )
|
||||
end
|
||||
|
||||
specific_files = "startup_gcc.c platform.c platform_int.c"
|
||||
specific_files = "startup_gcc.c platform.c platform_int.c lm3s_pio.c"
|
||||
local fwlib_files = utils.get_files( "src/platform/" .. platform .. "/driverlib", ".*%.c$" )
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@ end
|
||||
|
||||
if board == 'EK-LM3S9B92' then
|
||||
ldscript = "lm3s-9b92.ld"
|
||||
elseif board == 'SOLDERCORE' or board == 'EK-LM3S9D92' then
|
||||
elseif board == 'SOLDERCORE' or board == "EK-LM3S9D92" then
|
||||
ldscript = "lm3s-9d92.ld"
|
||||
else
|
||||
ldscript = "lm3s.ld"
|
||||
|
@ -13,7 +13,7 @@ if comp[ 'cpu' ] == 'LM3S9B92' or comp[ 'cpu' ] == 'LM3S9D92':
|
||||
|
||||
fwlib_files = " ".join(glob.glob("src/platform/%s/driverlib/*.c" % platform))
|
||||
|
||||
specific_files = "startup_gcc.c platform.c platform_int.c"
|
||||
specific_files = "startup_gcc.c platform.c platform_int.c lm3s_pio.c"
|
||||
|
||||
if comp[ 'board' ] == 'EK-LM3S1968' or comp[ 'board' ] == 'EK-LM3S6965' or comp[ 'board' ] == 'EK-LM3S8962':
|
||||
specific_files = specific_files + " rit128x96x4.c disp.c"
|
||||
|
@ -1903,18 +1903,6 @@
|
||||
#define WDT_LOCK_UNLOCKED 0x00000000 // Unlocked
|
||||
#define WDT_LOCK_LOCKED 0x00000001 // Locked
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// The following are defines for the bit fields in the GPIO_O_LOCK register.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#define GPIO_LOCK_M 0xFFFFFFFF // GPIO Lock
|
||||
#define GPIO_LOCK_UNLOCKED 0x00000000 // The GPIOCR register is unlocked
|
||||
// and may be modified
|
||||
#define GPIO_LOCK_LOCKED 0x00000001 // The GPIOCR register is locked
|
||||
// and may not be modified
|
||||
#define GPIO_LOCK_KEY 0x4C4F434B // Unlocks the GPIO_CR register
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// The following are defines for the bit fields in the GPIO_PCTL register for
|
||||
|
519
src/platform/lm3s/lm3s_pio.c
Normal file
519
src/platform/lm3s/lm3s_pio.c
Normal file
@ -0,0 +1,519 @@
|
||||
// LM3S specific PIO support
|
||||
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
#include "platform.h"
|
||||
#include "lrotable.h"
|
||||
#include "platform_conf.h"
|
||||
#include "inc/hw_gpio.h"
|
||||
#include "gpio.h"
|
||||
#include "auxmods.h"
|
||||
#include <string.h>
|
||||
|
||||
#if LUA_OPTIMIZE_MEMORY == 0
|
||||
#error lm3s.pio can only be compiled with LTR on (optram=true)
|
||||
#endif
|
||||
|
||||
// Alternate function setting is not available on all CPUs
|
||||
#if defined( ELUA_CPU_LM3S9B92 ) || defined( ELUA_CPU_LM3S9D92 )
|
||||
#define LM3S_HAS_ALTERNATE_PIO
|
||||
#endif
|
||||
|
||||
// ****************************************************************************
|
||||
// Alternate function handling
|
||||
|
||||
#ifdef LM3S_HAS_ALTERNATE_PIO
|
||||
|
||||
// List all alternative pin functions here. Long live gpio.h...
|
||||
#define LM3S_ALTERNATE_FUNCTIONS\
|
||||
_M( PA0_U0RX ),\
|
||||
_M( PA0_I2C1SCL ),\
|
||||
_M( PA0_U1RX ),\
|
||||
_M( PA1_U0TX ),\
|
||||
_M( PA1_I2C1SDA ),\
|
||||
_M( PA1_U1TX ),\
|
||||
_M( PA2_SSI0CLK ),\
|
||||
_M( PA2_TXD2 ),\
|
||||
_M( PA2_PWM4 ),\
|
||||
_M( PA2_I2S0RXSD ),\
|
||||
_M( PA3_SSI0FSS ),\
|
||||
_M( PA3_TXD1 ),\
|
||||
_M( PA3_PWM5 ),\
|
||||
_M( PA3_I2S0RXMCLK ),\
|
||||
_M( PA4_SSI0RX ),\
|
||||
_M( PA4_TXD0 ),\
|
||||
_M( PA4_PWM6 ),\
|
||||
_M( PA4_CAN0RX ),\
|
||||
_M( PA4_I2S0TXSCK ),\
|
||||
_M( PA5_SSI0TX ),\
|
||||
_M( PA5_RXDV ),\
|
||||
_M( PA5_PWM7 ),\
|
||||
_M( PA5_CAN0TX ),\
|
||||
_M( PA5_I2S0TXWS ),\
|
||||
_M( PA6_I2C1SCL ),\
|
||||
_M( PA6_CCP1 ),\
|
||||
_M( PA6_RXCK ),\
|
||||
_M( PA6_PWM0 ),\
|
||||
_M( PA6_PWM4 ),\
|
||||
_M( PA6_CAN0RX ),\
|
||||
_M( PA6_USB0EPEN ),\
|
||||
_M( PA6_U1CTS ),\
|
||||
_M( PA7_I2C1SDA ),\
|
||||
_M( PA7_CCP4 ),\
|
||||
_M( PA7_RXER ),\
|
||||
_M( PA7_PWM1 ),\
|
||||
_M( PA7_PWM5 ),\
|
||||
_M( PA7_CAN0TX ),\
|
||||
_M( PA7_CCP3 ),\
|
||||
_M( PA7_USB0PFLT ),\
|
||||
_M( PA7_U1DCD ),\
|
||||
_M( PB0_CCP0 ),\
|
||||
_M( PB0_PWM2 ),\
|
||||
_M( PB0_U1RX ),\
|
||||
_M( PB1_CCP2 ),\
|
||||
_M( PB1_PWM3 ),\
|
||||
_M( PB1_CCP1 ),\
|
||||
_M( PB1_U1TX ),\
|
||||
_M( PB2_I2C0SCL ),\
|
||||
_M( PB2_IDX0 ),\
|
||||
_M( PB2_CCP3 ),\
|
||||
_M( PB2_CCP0 ),\
|
||||
_M( PB2_USB0EPEN ),\
|
||||
_M( PB3_I2C0SDA ),\
|
||||
_M( PB3_FAULT0 ),\
|
||||
_M( PB3_FAULT3 ),\
|
||||
_M( PB3_USB0PFLT ),\
|
||||
_M( PB4_U2RX ),\
|
||||
_M( PB4_CAN0RX ),\
|
||||
_M( PB4_IDX0 ),\
|
||||
_M( PB4_U1RX ),\
|
||||
_M( PB4_EPI0S23 ),\
|
||||
_M( PB5_C0O ),\
|
||||
_M( PB5_CCP5 ),\
|
||||
_M( PB5_CCP6 ),\
|
||||
_M( PB5_CCP0 ),\
|
||||
_M( PB5_CAN0TX ),\
|
||||
_M( PB5_CCP2 ),\
|
||||
_M( PB5_U1TX ),\
|
||||
_M( PB5_EPI0S22 ),\
|
||||
_M( PB6_CCP1 ),\
|
||||
_M( PB6_CCP7 ),\
|
||||
_M( PB6_C0O ),\
|
||||
_M( PB6_FAULT1 ),\
|
||||
_M( PB6_IDX0 ),\
|
||||
_M( PB6_CCP5 ),\
|
||||
_M( PB6_I2S0TXSCK ),\
|
||||
_M( PB7_NMI ),\
|
||||
_M( PB7_RXD1 ),\
|
||||
_M( PC0_TCK ),\
|
||||
_M( PC1_TMS ),\
|
||||
_M( PC2_TDI ),\
|
||||
_M( PC3_TDO ),\
|
||||
_M( PC4_CCP5 ),\
|
||||
_M( PC4_PHA0 ),\
|
||||
_M( PC4_TXD3 ),\
|
||||
_M( PC4_PWM6 ),\
|
||||
_M( PC4_CCP2 ),\
|
||||
_M( PC4_CCP4 ),\
|
||||
_M( PC4_EPI0S2 ),\
|
||||
_M( PC4_CCP1 ),\
|
||||
_M( PC5_CCP1 ),\
|
||||
_M( PC5_C1O ),\
|
||||
_M( PC5_C0O ),\
|
||||
_M( PC5_FAULT2 ),\
|
||||
_M( PC5_CCP3 ),\
|
||||
_M( PC5_USB0EPEN ),\
|
||||
_M( PC5_EPI0S3 ),\
|
||||
_M( PC6_CCP3 ),\
|
||||
_M( PC6_PHB0 ),\
|
||||
_M( PC6_C2O ),\
|
||||
_M( PC6_PWM7 ),\
|
||||
_M( PC6_U1RX ),\
|
||||
_M( PC6_CCP0 ),\
|
||||
_M( PC6_USB0PFLT ),\
|
||||
_M( PC6_EPI0S4 ),\
|
||||
_M( PC7_CCP4 ),\
|
||||
_M( PC7_PHB0 ),\
|
||||
_M( PC7_CCP0 ),\
|
||||
_M( PC7_U1TX ),\
|
||||
_M( PC7_USB0PFLT ),\
|
||||
_M( PC7_C1O ),\
|
||||
_M( PC7_EPI0S5 ),\
|
||||
_M( PD0_PWM0 ),\
|
||||
_M( PD0_CAN0RX ),\
|
||||
_M( PD0_IDX0 ),\
|
||||
_M( PD0_U2RX ),\
|
||||
_M( PD0_U1RX ),\
|
||||
_M( PD0_CCP6 ),\
|
||||
_M( PD0_RXDV ),\
|
||||
_M( PD0_I2S0RXSCK ),\
|
||||
_M( PD0_U1CTS ),\
|
||||
_M( PD1_PWM1 ),\
|
||||
_M( PD1_CAN0TX ),\
|
||||
_M( PD1_PHA0 ),\
|
||||
_M( PD1_U2TX ),\
|
||||
_M( PD1_U1TX ),\
|
||||
_M( PD1_CCP7 ),\
|
||||
_M( PD1_TXER ),\
|
||||
_M( PD1_I2S0RXWS ),\
|
||||
_M( PD1_U1DCD ),\
|
||||
_M( PD1_CCP2 ),\
|
||||
_M( PD1_PHB1 ),\
|
||||
_M( PD2_U1RX ),\
|
||||
_M( PD2_CCP6 ),\
|
||||
_M( PD2_PWM2 ),\
|
||||
_M( PD2_CCP5 ),\
|
||||
_M( PD2_EPI0S20 ),\
|
||||
_M( PD3_U1TX ),\
|
||||
_M( PD3_CCP7 ),\
|
||||
_M( PD3_PWM3 ),\
|
||||
_M( PD3_CCP0 ),\
|
||||
_M( PD3_EPI0S21 ),\
|
||||
_M( PD4_CCP0 ),\
|
||||
_M( PD4_CCP3 ),\
|
||||
_M( PD4_TXD3 ),\
|
||||
_M( PD4_I2S0RXSD ),\
|
||||
_M( PD4_U1RI ),\
|
||||
_M( PD4_EPI0S19 ),\
|
||||
_M( PD5_CCP2 ),\
|
||||
_M( PD5_CCP4 ),\
|
||||
_M( PD5_TXD2 ),\
|
||||
_M( PD5_I2S0RXMCLK ),\
|
||||
_M( PD5_U2RX ),\
|
||||
_M( PD5_EPI0S28 ),\
|
||||
_M( PD6_FAULT0 ),\
|
||||
_M( PD6_TXD1 ),\
|
||||
_M( PD6_I2S0TXSCK ),\
|
||||
_M( PD6_U2TX ),\
|
||||
_M( PD6_EPI0S29 ),\
|
||||
_M( PD7_IDX0 ),\
|
||||
_M( PD7_C0O ),\
|
||||
_M( PD7_CCP1 ),\
|
||||
_M( PD7_TXD0 ),\
|
||||
_M( PD7_I2S0TXWS ),\
|
||||
_M( PD7_U1DTR ),\
|
||||
_M( PD7_EPI0S30 ),\
|
||||
_M( PE0_PWM4 ),\
|
||||
_M( PE0_SSI1CLK ),\
|
||||
_M( PE0_CCP3 ),\
|
||||
_M( PE0_EPI0S8 ),\
|
||||
_M( PE0_USB0PFLT ),\
|
||||
_M( PE1_PWM5 ),\
|
||||
_M( PE1_SSI1FSS ),\
|
||||
_M( PE1_FAULT0 ),\
|
||||
_M( PE1_CCP2 ),\
|
||||
_M( PE1_CCP6 ),\
|
||||
_M( PE1_EPI0S9 ),\
|
||||
_M( PE2_CCP4 ),\
|
||||
_M( PE2_SSI1RX ),\
|
||||
_M( PE2_PHB1 ),\
|
||||
_M( PE2_PHA0 ),\
|
||||
_M( PE2_CCP2 ),\
|
||||
_M( PE2_EPI0S24 ),\
|
||||
_M( PE3_CCP1 ),\
|
||||
_M( PE3_SSI1TX ),\
|
||||
_M( PE3_PHA1 ),\
|
||||
_M( PE3_PHB0 ),\
|
||||
_M( PE3_CCP7 ),\
|
||||
_M( PE3_EPI0S25 ),\
|
||||
_M( PE4_CCP3 ),\
|
||||
_M( PE4_CAN2RX ),\
|
||||
_M( PE4_FAULT0 ),\
|
||||
_M( PE4_U2TX ),\
|
||||
_M( PE4_CCP2 ),\
|
||||
_M( PE4_RXD0 ),\
|
||||
_M( PE4_I2S0TXWS ),\
|
||||
_M( PE5_CCP5 ),\
|
||||
_M( PE5_CAN2TX ),\
|
||||
_M( PE5_I2S0TXSD ),\
|
||||
_M( PE6_PWM4 ),\
|
||||
_M( PE6_C1O ),\
|
||||
_M( PE6_U1CTS ),\
|
||||
_M( PE7_PWM5 ),\
|
||||
_M( PE7_C2O ),\
|
||||
_M( PE7_U1DCD ),\
|
||||
_M( PF0_CAN1RX ),\
|
||||
_M( PF0_PHB0 ),\
|
||||
_M( PF0_PWM0 ),\
|
||||
_M( PF0_RXCK ),\
|
||||
_M( PF0_I2S0TXSD ),\
|
||||
_M( PF0_U1DSR ),\
|
||||
_M( PF1_CAN1TX ),\
|
||||
_M( PF1_IDX1 ),\
|
||||
_M( PF1_PWM1 ),\
|
||||
_M( PF1_RXER ),\
|
||||
_M( PF1_I2S0TXMCLK ),\
|
||||
_M( PF1_U1RTS ),\
|
||||
_M( PF1_CCP3 ),\
|
||||
_M( PF2_LED1 ),\
|
||||
_M( PF2_PWM4 ),\
|
||||
_M( PF2_PHYINT ),\
|
||||
_M( PF2_PWM2 ),\
|
||||
_M( PF2_SSI1CLK ),\
|
||||
_M( PF3_LED0 ),\
|
||||
_M( PF3_PWM5 ),\
|
||||
_M( PF3_MDC ),\
|
||||
_M( PF3_PWM3 ),\
|
||||
_M( PF3_SSI1FSS ),\
|
||||
_M( PF4_CCP0 ),\
|
||||
_M( PF4_C0O ),\
|
||||
_M( PF4_MDIO ),\
|
||||
_M( PF4_FAULT0 ),\
|
||||
_M( PF4_EPI0S12 ),\
|
||||
_M( PF4_SSI1RX ),\
|
||||
_M( PF5_CCP2 ),\
|
||||
_M( PF5_C1O ),\
|
||||
_M( PF5_RXD3 ),\
|
||||
_M( PF5_EPI0S15 ),\
|
||||
_M( PF5_SSI1TX ),\
|
||||
_M( PF6_CCP1 ),\
|
||||
_M( PF6_C2O ),\
|
||||
_M( PF6_RXD2 ),\
|
||||
_M( PF6_PHA0 ),\
|
||||
_M( PF6_I2S0TXMCLK ),\
|
||||
_M( PF6_U1RTS ),\
|
||||
_M( PF7_CCP4 ),\
|
||||
_M( PF7_RXD1 ),\
|
||||
_M( PF7_PHB0 ),\
|
||||
_M( PF7_EPI0S12 ),\
|
||||
_M( PF7_FAULT1 ),\
|
||||
_M( PG0_U2RX ),\
|
||||
_M( PG0_PWM0 ),\
|
||||
_M( PG0_I2C1SCL ),\
|
||||
_M( PG0_PWM4 ),\
|
||||
_M( PG0_USB0EPEN ),\
|
||||
_M( PG0_EPI0S13 ),\
|
||||
_M( PG1_U2TX ),\
|
||||
_M( PG1_PWM1 ),\
|
||||
_M( PG1_I2C1SDA ),\
|
||||
_M( PG1_PWM5 ),\
|
||||
_M( PG1_EPI0S14 ),\
|
||||
_M( PG2_PWM0 ),\
|
||||
_M( PG2_COL ),\
|
||||
_M( PG2_FAULT0 ),\
|
||||
_M( PG2_IDX1 ),\
|
||||
_M( PG2_I2S0RXSD ),\
|
||||
_M( PG3_PWM1 ),\
|
||||
_M( PG3_CRS ),\
|
||||
_M( PG3_FAULT2 ),\
|
||||
_M( PG3_FAULT0 ),\
|
||||
_M( PG3_I2S0RXMCLK ),\
|
||||
_M( PG4_CCP3 ),\
|
||||
_M( PG4_RXD0 ),\
|
||||
_M( PG4_FAULT1 ),\
|
||||
_M( PG4_EPI0S15 ),\
|
||||
_M( PG4_PWM6 ),\
|
||||
_M( PG4_U1RI ),\
|
||||
_M( PG5_CCP5 ),\
|
||||
_M( PG5_TXEN ),\
|
||||
_M( PG5_IDX0 ),\
|
||||
_M( PG5_FAULT1 ),\
|
||||
_M( PG5_PWM7 ),\
|
||||
_M( PG5_I2S0RXSCK ),\
|
||||
_M( PG5_U1DTR ),\
|
||||
_M( PG6_PHA1 ),\
|
||||
_M( PG6_TXCK ),\
|
||||
_M( PG6_PWM6 ),\
|
||||
_M( PG6_FAULT1 ),\
|
||||
_M( PG6_I2S0RXWS ),\
|
||||
_M( PG6_U1RI ),\
|
||||
_M( PG7_PHB1 ),\
|
||||
_M( PG7_TXER ),\
|
||||
_M( PG7_PWM7 ),\
|
||||
_M( PG7_CCP5 ),\
|
||||
_M( PG7_EPI0S31 ),\
|
||||
_M( PH0_CCP6 ),\
|
||||
_M( PH0_PWM2 ),\
|
||||
_M( PH0_EPI0S6 ),\
|
||||
_M( PH0_PWM4 ),\
|
||||
_M( PH1_CCP7 ),\
|
||||
_M( PH1_PWM3 ),\
|
||||
_M( PH1_EPI0S7 ),\
|
||||
_M( PH1_PWM5 ),\
|
||||
_M( PH2_IDX1 ),\
|
||||
_M( PH2_C1O ),\
|
||||
_M( PH2_FAULT3 ),\
|
||||
_M( PH2_EPI0S1 ),\
|
||||
_M( PH2_TXD3 ),\
|
||||
_M( PH3_PHB0 ),\
|
||||
_M( PH3_FAULT0 ),\
|
||||
_M( PH3_USB0EPEN ),\
|
||||
_M( PH3_EPI0S0 ),\
|
||||
_M( PH3_TXD2 ),\
|
||||
_M( PH4_USB0PFLT ),\
|
||||
_M( PH4_EPI0S10 ),\
|
||||
_M( PH4_TXD1 ),\
|
||||
_M( PH4_SSI1CLK ),\
|
||||
_M( PH5_EPI0S11 ),\
|
||||
_M( PH5_TXD0 ),\
|
||||
_M( PH5_FAULT2 ),\
|
||||
_M( PH5_SSI1FSS ),\
|
||||
_M( PH6_EPI0S26 ),\
|
||||
_M( PH6_RXDV ),\
|
||||
_M( PH6_PWM4 ),\
|
||||
_M( PH6_SSI1RX ),\
|
||||
_M( PH7_RXCK ),\
|
||||
_M( PH7_EPI0S27 ),\
|
||||
_M( PH7_PWM5 ),\
|
||||
_M( PH7_SSI1TX ),\
|
||||
_M( PJ0_RXER ),\
|
||||
_M( PJ0_EPI0S16 ),\
|
||||
_M( PJ0_PWM0 ),\
|
||||
_M( PJ0_I2C1SCL ),\
|
||||
_M( PJ1_EPI0S17 ),\
|
||||
_M( PJ1_USB0PFLT ),\
|
||||
_M( PJ1_PWM1 ),\
|
||||
_M( PJ1_I2C1SDA ),\
|
||||
_M( PJ2_EPI0S18 ),\
|
||||
_M( PJ2_CCP0 ),\
|
||||
_M( PJ2_FAULT0 ),\
|
||||
_M( PJ3_EPI0S19 ),\
|
||||
_M( PJ3_U1CTS ),\
|
||||
_M( PJ3_CCP6 ),\
|
||||
_M( PJ4_EPI0S28 ),\
|
||||
_M( PJ4_U1DCD ),\
|
||||
_M( PJ4_CCP4 ),\
|
||||
_M( PJ5_EPI0S29 ),\
|
||||
_M( PJ5_U1DSR ),\
|
||||
_M( PJ5_CCP2 ),\
|
||||
_M( PJ6_EPI0S30 ),\
|
||||
_M( PJ6_U1RTS ),\
|
||||
_M( PJ6_CCP1 ),\
|
||||
_M( PJ7_U1DTR ),\
|
||||
_M( PJ7_CCP0 ),
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *name;
|
||||
u32 val;
|
||||
} LM3S_PIN_DATA;
|
||||
|
||||
#define _M( x ) { #x, GPIO_##x }
|
||||
static const LM3S_PIN_DATA lm3s_pin_data[] =
|
||||
{
|
||||
LM3S_ALTERNATE_FUNCTIONS
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static int lm3s_pio_mt_index( lua_State *L )
|
||||
{
|
||||
const char *key = luaL_checkstring( L, 2 );
|
||||
unsigned i = 0;
|
||||
|
||||
while( lm3s_pin_data[ i ].name != NULL )
|
||||
{
|
||||
if( !strcmp( lm3s_pin_data[ i ].name, key ) )
|
||||
{
|
||||
lua_pushnumber( L, ( lua_Number )lm3s_pin_data[ i ].val );
|
||||
return 1;
|
||||
}
|
||||
i ++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Lua: lm3s.pio.set_function( func1, func2, ..., funcn )
|
||||
static int lm3s_pio_set_function( lua_State *L )
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for( i = 1; i <= lua_gettop( L ); i ++ )
|
||||
GPIOPinConfigure( ( u32 )luaL_checknumber( L, i ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // #ifdef LM3S_HAS_ALTERNATE_PIO
|
||||
|
||||
// ****************************************************************************
|
||||
// Other LM3S PIO specific functions
|
||||
|
||||
extern const u32 pio_base[];
|
||||
|
||||
// Helper: check a port/pin specification
|
||||
// Return 1 if OK, 0 if false
|
||||
// Set port and pin in args as side effect
|
||||
static int lm3s_pioh_check_pio_spec( int v, int *pport, int *ppin )
|
||||
{
|
||||
*pport = PLATFORM_IO_GET_PORT( v );
|
||||
*ppin = PLATFORM_IO_GET_PIN( v );
|
||||
if( PLATFORM_IO_IS_PORT( v ) || !platform_pio_has_port( *pport ) || !platform_pio_has_pin( *pport, *ppin ) )
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Lua: lm3s.pio.set_strength( drive, pin1, pin2, ..., pinn )
|
||||
static int lm3s_pio_set_strength( lua_State *L )
|
||||
{
|
||||
int port = 0, pin = 0;
|
||||
u8 pins;
|
||||
u32 base;
|
||||
u32 drive = luaL_checkinteger( L, 1 );
|
||||
unsigned i;
|
||||
|
||||
for( i = 2; i <= lua_gettop( L ); i ++ )
|
||||
{
|
||||
if( !lm3s_pioh_check_pio_spec( luaL_checkinteger( L, i ), &port, &pin ) )
|
||||
return luaL_error( L, "invalid pin '%u'", luaL_checkinteger( L, i ) );
|
||||
base = pio_base[ port ];
|
||||
pins = 1 << pin;
|
||||
// The next sequence is taken from gpio.c
|
||||
HWREG(base + GPIO_O_DR2R) = ((drive & 1) ?
|
||||
(HWREG(base + GPIO_O_DR2R) | pins) :
|
||||
(HWREG(base + GPIO_O_DR2R) & ~(pins)));
|
||||
HWREG(base + GPIO_O_DR4R) = ((drive & 2) ?
|
||||
(HWREG(base + GPIO_O_DR4R) | pins) :
|
||||
(HWREG(base + GPIO_O_DR4R) & ~(pins)));
|
||||
HWREG(base + GPIO_O_DR8R) = ((drive & 4) ?
|
||||
(HWREG(base + GPIO_O_DR8R) | pins) :
|
||||
(HWREG(base + GPIO_O_DR8R) & ~(pins)));
|
||||
HWREG(base + GPIO_O_SLR) = ((drive & 8) ?
|
||||
(HWREG(base + GPIO_O_SLR) | pins) :
|
||||
(HWREG(base + GPIO_O_SLR) & ~(pins)));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Lua: lm3s.pio.set_direction( dir, pin1, pin2, ..., pinn )
|
||||
static int lm3s_pio_set_direction( lua_State *L )
|
||||
{
|
||||
int port = 0, pin = 0;
|
||||
u32 base, dir;
|
||||
u8 pins;
|
||||
unsigned i;
|
||||
|
||||
dir = ( u32 )luaL_checkinteger( L, 1 );
|
||||
for( i = 2; i <= lua_gettop( L ); i ++ )
|
||||
{
|
||||
if( !lm3s_pioh_check_pio_spec( luaL_checkinteger( L, i ), &port, &pin ) )
|
||||
return luaL_error( L, "invalid pin '%u'", luaL_checkinteger( L, i ) );
|
||||
base = pio_base[ port ];
|
||||
pins = 1 << pin;
|
||||
GPIODirModeSet( base, pins, dir );
|
||||
HWREG( base + GPIO_O_DEN ) |= pins;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Module function map
|
||||
#define MIN_OPT_LEVEL 2
|
||||
#include "lrodefs.h"
|
||||
const LUA_REG_TYPE lm3s_pio_map[] =
|
||||
{
|
||||
#ifdef LM3S_HAS_ALTERNATE_PIO
|
||||
{ LSTRKEY( "__index" ), LFUNCVAL( lm3s_pio_mt_index ) },
|
||||
{ LSTRKEY( "__metatable" ), LROVAL( lm3s_pio_map ) },
|
||||
{ LSTRKEY( "set_function" ), LFUNCVAL( lm3s_pio_set_function ) },
|
||||
#endif // #ifdef LM3S_HAS_ALTERNATE_PIO
|
||||
{ LSTRKEY( "set_strength" ), LFUNCVAL( lm3s_pio_set_strength ) },
|
||||
{ LSTRKEY( "MA_2" ), LNUMVAL( GPIO_STRENGTH_2MA ) },
|
||||
{ LSTRKEY( "MA_4" ), LNUMVAL( GPIO_STRENGTH_4MA ) },
|
||||
{ LSTRKEY( "MA_8" ), LNUMVAL( GPIO_STRENGTH_8MA ) },
|
||||
{ LSTRKEY( "MA_8SC" ), LNUMVAL( GPIO_STRENGTH_8MA_SC ) },
|
||||
{ LSTRKEY( "set_direction" ), LFUNCVAL( lm3s_pio_set_direction ) },
|
||||
{ LSTRKEY( "GPIO_IN" ), LNUMVAL( GPIO_DIR_MODE_IN ) },
|
||||
{ LSTRKEY( "GPIO_OUT" ), LNUMVAL( GPIO_DIR_MODE_OUT ) },
|
||||
{ LSTRKEY( "HW" ), LNUMVAL( GPIO_DIR_MODE_HW ) },
|
||||
{ LNILKEY, LNILVAL }
|
||||
};
|
||||
|
@ -75,7 +75,7 @@
|
||||
// UIP sys tick data
|
||||
// NOTE: when using virtual timers, SYSTICKHZ and VTMR_FREQ_HZ should have the
|
||||
// same value, as they're served by the same timer (the systick)
|
||||
#define SYSTICKHZ 4
|
||||
#define SYSTICKHZ 5
|
||||
#define SYSTICKMS (1000 / SYSTICKHZ)
|
||||
|
||||
// ****************************************************************************
|
||||
@ -162,18 +162,18 @@ int platform_init()
|
||||
// Same configuration on LM3S8962, LM3S6965, LM3S6918 (8 ports)
|
||||
// 9B92 has 9 ports (Port J in addition to A-H)
|
||||
#if defined( FORLM3S9B92 ) || defined( FORLM3S9D92 )
|
||||
static const u32 pio_base[] = { GPIO_PORTA_BASE, GPIO_PORTB_BASE, GPIO_PORTC_BASE, GPIO_PORTD_BASE,
|
||||
const u32 pio_base[] = { GPIO_PORTA_BASE, GPIO_PORTB_BASE, GPIO_PORTC_BASE, GPIO_PORTD_BASE,
|
||||
GPIO_PORTE_BASE, GPIO_PORTF_BASE, GPIO_PORTG_BASE, GPIO_PORTH_BASE,
|
||||
GPIO_PORTJ_BASE };
|
||||
|
||||
static const u32 pio_sysctl[] = { SYSCTL_PERIPH_GPIOA, SYSCTL_PERIPH_GPIOB, SYSCTL_PERIPH_GPIOC, SYSCTL_PERIPH_GPIOD,
|
||||
const u32 pio_sysctl[] = { SYSCTL_PERIPH_GPIOA, SYSCTL_PERIPH_GPIOB, SYSCTL_PERIPH_GPIOC, SYSCTL_PERIPH_GPIOD,
|
||||
SYSCTL_PERIPH_GPIOE, SYSCTL_PERIPH_GPIOF, SYSCTL_PERIPH_GPIOG, SYSCTL_PERIPH_GPIOH,
|
||||
SYSCTL_PERIPH_GPIOJ };
|
||||
#else
|
||||
static const u32 pio_base[] = { GPIO_PORTA_BASE, GPIO_PORTB_BASE, GPIO_PORTC_BASE, GPIO_PORTD_BASE,
|
||||
const u32 pio_base[] = { GPIO_PORTA_BASE, GPIO_PORTB_BASE, GPIO_PORTC_BASE, GPIO_PORTD_BASE,
|
||||
GPIO_PORTE_BASE, GPIO_PORTF_BASE, GPIO_PORTG_BASE, GPIO_PORTH_BASE };
|
||||
|
||||
static const u32 pio_sysctl[] = { SYSCTL_PERIPH_GPIOA, SYSCTL_PERIPH_GPIOB, SYSCTL_PERIPH_GPIOC, SYSCTL_PERIPH_GPIOD,
|
||||
const u32 pio_sysctl[] = { SYSCTL_PERIPH_GPIOA, SYSCTL_PERIPH_GPIOB, SYSCTL_PERIPH_GPIOC, SYSCTL_PERIPH_GPIOD,
|
||||
SYSCTL_PERIPH_GPIOE, SYSCTL_PERIPH_GPIOF, SYSCTL_PERIPH_GPIOG, SYSCTL_PERIPH_GPIOH };
|
||||
#endif
|
||||
|
||||
@ -449,6 +449,7 @@ const u32 uart_base[] = { UART0_BASE, UART1_BASE, UART2_BASE };
|
||||
static const u32 uart_sysctl[] = { SYSCTL_PERIPH_UART0, SYSCTL_PERIPH_UART1, SYSCTL_PERIPH_UART2 };
|
||||
static const u32 uart_gpio_base[] = { GPIO_PORTA_BASE, GPIO_PORTD_BASE, GPIO_PORTG_BASE };
|
||||
static const u8 uart_gpio_pins[] = { GPIO_PIN_0 | GPIO_PIN_1, GPIO_PIN_2 | GPIO_PIN_3, GPIO_PIN_0 | GPIO_PIN_1 };
|
||||
static const u32 uart_gpiofunc[] = { GPIO_PA0_U0RX, GPIO_PA1_U0TX, GPIO_PD2_U1RX, GPIO_PD3_U1TX, GPIO_PG0_U2RX, GPIO_PG1_U2TX };
|
||||
|
||||
static void uarts_init()
|
||||
{
|
||||
@ -463,7 +464,9 @@ u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int st
|
||||
|
||||
if( id < NUM_UART )
|
||||
{
|
||||
MAP_GPIOPinTypeUART(uart_gpio_base [ id ], uart_gpio_pins[ id ]);
|
||||
MAP_GPIOPinConfigure( uart_gpiofunc[ id << 1 ] );
|
||||
MAP_GPIOPinConfigure( uart_gpiofunc[ ( id << 1 ) + 1 ] );
|
||||
MAP_GPIOPinTypeUART( uart_gpio_base[ id ], uart_gpio_pins[ id ] );
|
||||
|
||||
switch( databits )
|
||||
{
|
||||
@ -490,6 +493,8 @@ u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int st
|
||||
|
||||
MAP_UARTConfigSetExpClk( uart_base[ id ], MAP_SysCtlClockGet(), baud, config );
|
||||
MAP_UARTConfigGetExpClk( uart_base[ id ], MAP_SysCtlClockGet(), &baud, &config );
|
||||
|
||||
MAP_UARTEnable( uart_base[ id ] );
|
||||
}
|
||||
return baud;
|
||||
}
|
||||
@ -519,7 +524,7 @@ int platform_s_uart_set_flow_control( unsigned id, int type )
|
||||
// Same on LM3S8962, LM3S6965, LM3S6918 and LM3S9B92 (4 timers)
|
||||
|
||||
// All possible LM3S timers defs
|
||||
static const u32 timer_base[] = { TIMER0_BASE, TIMER1_BASE, TIMER2_BASE, TIMER3_BASE };
|
||||
const u32 timer_base[] = { TIMER0_BASE, TIMER1_BASE, TIMER2_BASE, TIMER3_BASE };
|
||||
static const u32 timer_sysctl[] = { SYSCTL_PERIPH_TIMER0, SYSCTL_PERIPH_TIMER1, SYSCTL_PERIPH_TIMER2, SYSCTL_PERIPH_TIMER3 };
|
||||
|
||||
static void timers_init()
|
||||
@ -595,6 +600,33 @@ timer_data_type platform_timer_read_sys()
|
||||
return cmn_systimer_get();
|
||||
}
|
||||
|
||||
u8 lm3s_timer_int_periodic_flag[ NUM_TIMER ];
|
||||
int platform_s_timer_set_match_int( unsigned id, timer_data_type period_us, int type )
|
||||
{
|
||||
u32 base = timer_base[ id ];
|
||||
u64 final;
|
||||
|
||||
if( period_us == 0 )
|
||||
{
|
||||
MAP_TimerDisable( base, TIMER_A );
|
||||
MAP_TimerIntDisable( base, TIMER_TIMA_TIMEOUT );
|
||||
MAP_TimerIntClear( base, TIMER_TIMA_TIMEOUT );
|
||||
MAP_TimerLoadSet( base, TIMER_A, 0xFFFFFFFF );
|
||||
MAP_TimerEnable( base, TIMER_A );
|
||||
return PLATFORM_TIMER_INT_OK;
|
||||
}
|
||||
final = ( ( u64 )period_us * MAP_SysCtlClockGet() ) / 1000000;
|
||||
if( final == 0 )
|
||||
return PLATFORM_TIMER_INT_TOO_SHORT;
|
||||
if( final > 0xFFFFFFFFULL )
|
||||
return PLATFORM_TIMER_INT_TOO_LONG;
|
||||
lm3s_timer_int_periodic_flag[ id ] = type;
|
||||
MAP_TimerDisable( base, TIMER_A );
|
||||
MAP_TimerIntClear( base, TIMER_TIMA_TIMEOUT );
|
||||
MAP_TimerLoadSet( base, TIMER_A, ( u32 )final - 1 );
|
||||
return PLATFORM_TIMER_INT_OK;
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// PWMs
|
||||
// Similar on LM3S8962 and LM3S6965
|
||||
|
@ -28,18 +28,32 @@
|
||||
#include "rom.h"
|
||||
#include "rom_map.h"
|
||||
#include "hw_ints.h"
|
||||
#include "hw_gpio.h"
|
||||
#include "hw_timer.h"
|
||||
#include "gpio.h"
|
||||
#include "uart.h"
|
||||
#include "interrupt.h"
|
||||
#include "driverlib/timer.h"
|
||||
|
||||
#define GPIO_INT_POSEDGE_ENABLED 1
|
||||
#define GPIO_INT_NEGEDGE_ENABLED 2
|
||||
#define GPIO_INT_BOTH_ENABLED ( GPIO_INT_POSEDGE_ENABLED | GPIO_INT_NEGEDGE_ENABLED )
|
||||
|
||||
// ****************************************************************************
|
||||
// Interrupt handlers
|
||||
|
||||
extern const u32 uart_base[];
|
||||
extern const u32 pio_base[];
|
||||
static const int uart_int_mask = UART_INT_RX | UART_INT_RT;
|
||||
static const u8 gpio_int_ids[] = { INT_GPIOA, INT_GPIOB, INT_GPIOC, INT_GPIOD, INT_GPIOE, INT_GPIOF,
|
||||
INT_GPIOG, INT_GPIOH, INT_GPIOJ };
|
||||
extern const u32 timer_base[];
|
||||
extern u8 lm3s_timer_int_periodic_flag[ NUM_TIMER ];
|
||||
static const u8 timer_int_ids[] = { INT_TIMER0A, INT_TIMER1A, INT_TIMER2A, INT_TIMER3A };
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// UART_RX interrupt
|
||||
|
||||
extern const u32 uart_base[];
|
||||
static const int uart_int_mask = UART_INT_RX | UART_INT_RT;
|
||||
|
||||
static void uart_common_rx_handler( int resnum )
|
||||
{
|
||||
MAP_UARTIntClear( uart_base[ resnum ], uart_int_mask );
|
||||
@ -62,6 +76,128 @@ void uart2_handler()
|
||||
uart_common_rx_handler( 2 );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// GPIO interrupts (POSEDGE/NEGEDGE)
|
||||
|
||||
static void gpio_common_handler( int port )
|
||||
{
|
||||
u32 base = pio_base[ port ];
|
||||
u8 pin, pinmask;
|
||||
u32 ibe = HWREG( base + GPIO_O_IBE );
|
||||
u32 iev = HWREG( base + GPIO_O_IEV );
|
||||
|
||||
// Check each pin in turn
|
||||
for( pin = 0, pinmask = 1; pin < 8; pin ++, pinmask <<= 1 )
|
||||
if( HWREG( base + GPIO_O_MIS ) & pinmask ) // interrupt on pin
|
||||
{
|
||||
if( MAP_GPIOPinRead( base, pinmask ) && ( ( ibe & pinmask ) || ( iev & pinmask ) ) ) // high level and posedge interrupt enabled
|
||||
cmn_int_handler( INT_GPIO_POSEDGE, PLATFORM_IO_ENCODE( port, pin, 0 ) );
|
||||
else if( ( ibe & pinmask ) || !( iev & pinmask ) ) // low level and negedge interrupt enabled
|
||||
cmn_int_handler( INT_GPIO_NEGEDGE, PLATFORM_IO_ENCODE( port, pin, 0 ) );
|
||||
HWREG( base + GPIO_O_ICR ) = pinmask;
|
||||
}
|
||||
}
|
||||
|
||||
void gpioa_handler()
|
||||
{
|
||||
gpio_common_handler( 0 );
|
||||
}
|
||||
|
||||
void gpiob_handler()
|
||||
{
|
||||
gpio_common_handler( 1 );
|
||||
}
|
||||
|
||||
void gpioc_handler()
|
||||
{
|
||||
gpio_common_handler( 2 );
|
||||
}
|
||||
|
||||
void gpiod_handler()
|
||||
{
|
||||
gpio_common_handler( 3 );
|
||||
}
|
||||
|
||||
void gpioe_handler()
|
||||
{
|
||||
gpio_common_handler( 4 );
|
||||
}
|
||||
|
||||
void gpiof_handler()
|
||||
{
|
||||
gpio_common_handler( 5 );
|
||||
}
|
||||
|
||||
void gpiog_handler()
|
||||
{
|
||||
gpio_common_handler( 6 );
|
||||
}
|
||||
|
||||
void gpioh_handler()
|
||||
{
|
||||
gpio_common_handler( 7 );
|
||||
}
|
||||
|
||||
void gpioj_handler()
|
||||
{
|
||||
gpio_common_handler( 8 );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Timer interrupts
|
||||
|
||||
static void tmr_common_handler( elua_int_resnum id )
|
||||
{
|
||||
u32 base = timer_base[ id ];
|
||||
|
||||
MAP_TimerIntClear( base, TIMER_TIMA_TIMEOUT );
|
||||
if( lm3s_timer_int_periodic_flag[ id ] != PLATFORM_TIMER_INT_CYCLIC )
|
||||
{
|
||||
MAP_TimerIntDisable( base, TIMER_TIMA_TIMEOUT );
|
||||
MAP_TimerLoadSet( base, TIMER_A, 0xFFFFFFFF );
|
||||
}
|
||||
cmn_int_handler( INT_TMR_MATCH, id );
|
||||
}
|
||||
|
||||
void tmr0_handler()
|
||||
{
|
||||
tmr_common_handler( 0 );
|
||||
}
|
||||
|
||||
void tmr1_handler()
|
||||
{
|
||||
tmr_common_handler( 1 );
|
||||
}
|
||||
|
||||
void tmr2_handler()
|
||||
{
|
||||
tmr_common_handler( 2 );
|
||||
}
|
||||
|
||||
void tmr3_handler()
|
||||
{
|
||||
tmr_common_handler( 3 );
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Helpers
|
||||
|
||||
// Get GPIO interrupt status as a mask
|
||||
static int inth_gpio_get_int_status( elua_int_resnum resnum )
|
||||
{
|
||||
const u32 portbase = pio_base[ PLATFORM_IO_GET_PORT( resnum ) ];
|
||||
const u8 pinmask = 1 << PLATFORM_IO_GET_PIN( resnum );
|
||||
|
||||
if( ( HWREG( portbase + GPIO_O_IM ) & pinmask ) == 0 )
|
||||
return 0;
|
||||
if( ( HWREG( portbase + GPIO_O_IBE ) & pinmask ) != 0 )
|
||||
return GPIO_INT_BOTH_ENABLED;
|
||||
else if( ( HWREG( portbase + GPIO_O_IEV ) & pinmask ) != 0 )
|
||||
return GPIO_INT_POSEDGE_ENABLED;
|
||||
else
|
||||
return GPIO_INT_NEGEDGE_ENABLED;
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Interrupt: INT_UART_RX
|
||||
|
||||
@ -84,21 +220,191 @@ static int int_uart_rx_set_status( elua_int_resnum resnum, int status )
|
||||
static int int_uart_rx_get_flag( elua_int_resnum resnum, int clear )
|
||||
{
|
||||
|
||||
int flag = ( UARTIntStatus( uart_base[ resnum ], false ) & uart_int_mask ) == uart_int_mask ? 1 : 0;
|
||||
int flag = ( MAP_UARTIntStatus( uart_base[ resnum ], false ) & uart_int_mask ) == uart_int_mask ? 1 : 0;
|
||||
|
||||
if( clear )
|
||||
MAP_UARTIntClear( uart_base[ resnum ], uart_int_mask );
|
||||
return flag;
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Interrupt: INT_GPIO_POSEDGE
|
||||
|
||||
static int int_gpio_posedge_get_status( elua_int_resnum resnum )
|
||||
{
|
||||
int port = PLATFORM_IO_GET_PORT( resnum ), pin = PLATFORM_IO_GET_PIN( resnum );
|
||||
unsigned long type;
|
||||
|
||||
if( ( HWREG( pio_base[ port ] + GPIO_O_IM ) & ( 1 << pin ) ) == 0 )
|
||||
return 0;
|
||||
type = MAP_GPIOIntTypeGet( pio_base[ port ], pin );
|
||||
return ( type == GPIO_RISING_EDGE || type == GPIO_BOTH_EDGES ) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int int_gpio_posedge_set_status( elua_int_resnum resnum, int status )
|
||||
{
|
||||
unsigned long portbase = pio_base[ PLATFORM_IO_GET_PORT( resnum ) ];
|
||||
u8 pinmask = 1 << PLATFORM_IO_GET_PIN( resnum );
|
||||
int prev = int_gpio_posedge_get_status( resnum );
|
||||
int crtstat = inth_gpio_get_int_status( resnum );
|
||||
|
||||
if( status == PLATFORM_CPU_ENABLE )
|
||||
{
|
||||
// If already configured for falling edge, set both edges
|
||||
// Otherwise set only posedge
|
||||
if( crtstat & GPIO_INT_NEGEDGE_ENABLED )
|
||||
HWREG( portbase + GPIO_O_IBE ) |= pinmask;
|
||||
else
|
||||
HWREG( portbase + GPIO_O_IEV ) |= pinmask;
|
||||
MAP_GPIOPinIntEnable( portbase, pinmask );
|
||||
}
|
||||
else
|
||||
{
|
||||
// If configured for both, enable only falling edge
|
||||
// Otherwise disable interrupts completely
|
||||
if( crtstat == GPIO_INT_BOTH_ENABLED )
|
||||
{
|
||||
HWREG( portbase + GPIO_O_IBE ) &= ( u8 )~pinmask;
|
||||
HWREG( portbase + GPIO_O_IEV ) &= ( u8 )~pinmask;
|
||||
}
|
||||
else if( crtstat == GPIO_INT_POSEDGE_ENABLED )
|
||||
MAP_GPIOPinIntDisable( portbase, pinmask );
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
static int int_gpio_posedge_get_flag( elua_int_resnum resnum, int clear )
|
||||
{
|
||||
unsigned long portbase = pio_base[ PLATFORM_IO_GET_PORT( resnum ) ];
|
||||
u8 pinmask = 1 << PLATFORM_IO_GET_PIN( resnum );
|
||||
|
||||
if( MAP_GPIOPinRead( portbase, pinmask ) == 0 )
|
||||
return 0;
|
||||
if( MAP_GPIOPinIntStatus( portbase, true ) & pinmask )
|
||||
{
|
||||
if( clear )
|
||||
MAP_GPIOPinIntClear( portbase, pinmask );
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Interrupt: INT_GPIO_NEGEDGE
|
||||
|
||||
static int int_gpio_negedge_get_status( elua_int_resnum resnum )
|
||||
{
|
||||
int port = PLATFORM_IO_GET_PORT( resnum ), pin = PLATFORM_IO_GET_PIN( resnum );
|
||||
unsigned long type;
|
||||
|
||||
if( ( HWREG( pio_base[ port ] + GPIO_O_IM ) & ( 1 << pin ) ) == 0 )
|
||||
return 0;
|
||||
type = MAP_GPIOIntTypeGet( pio_base[ port ], pin );
|
||||
return ( type == GPIO_FALLING_EDGE || type == GPIO_BOTH_EDGES ) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int int_gpio_negedge_set_status( elua_int_resnum resnum, int status )
|
||||
{
|
||||
unsigned long portbase = pio_base[ PLATFORM_IO_GET_PORT( resnum ) ];
|
||||
u8 pinmask = 1 << PLATFORM_IO_GET_PIN( resnum );
|
||||
int prev = int_gpio_posedge_get_status( resnum );
|
||||
int crtstat = inth_gpio_get_int_status( resnum );
|
||||
|
||||
if( status == PLATFORM_CPU_ENABLE )
|
||||
{
|
||||
// If already configured for rising edge, set both edges
|
||||
// Otherwise set only negedge
|
||||
if( crtstat & GPIO_INT_POSEDGE_ENABLED )
|
||||
HWREG( portbase + GPIO_O_IBE ) |= pinmask;
|
||||
else
|
||||
HWREG( portbase + GPIO_O_IEV ) &= ( u8 )~pinmask;
|
||||
MAP_GPIOPinIntEnable( portbase, pinmask );
|
||||
}
|
||||
else
|
||||
{
|
||||
// If configured for both, enable only rising edge
|
||||
// Otherwise disable interrupts completely
|
||||
if( crtstat == GPIO_INT_BOTH_ENABLED )
|
||||
{
|
||||
HWREG( portbase + GPIO_O_IBE ) &= ( u8 )~pinmask;
|
||||
HWREG( portbase + GPIO_O_IEV ) |= pinmask;
|
||||
}
|
||||
else if( crtstat == GPIO_INT_NEGEDGE_ENABLED )
|
||||
MAP_GPIOPinIntDisable( portbase, pinmask );
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
static int int_gpio_negedge_get_flag( elua_int_resnum resnum, int clear )
|
||||
{
|
||||
unsigned long portbase = pio_base[ PLATFORM_IO_GET_PORT( resnum ) ];
|
||||
u8 pinmask = 1 << PLATFORM_IO_GET_PIN( resnum );
|
||||
|
||||
if( MAP_GPIOPinRead( portbase, pinmask ) != 0 )
|
||||
return 0;
|
||||
if( MAP_GPIOPinIntStatus( portbase, true ) & pinmask )
|
||||
{
|
||||
if( clear )
|
||||
MAP_GPIOPinIntClear( portbase, pinmask );
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Interrupt: INT_TMR_MATCH
|
||||
|
||||
#define tmr_is_enabled( base ) ( ( HWREG( base + TIMER_O_CTL ) & TIMER_CTL_TAEN ) != 0 )
|
||||
|
||||
static int int_tmr_match_get_status( elua_int_resnum resnum )
|
||||
{
|
||||
u32 base = timer_base[ resnum ];
|
||||
|
||||
return ( tmr_is_enabled( base ) && ( HWREG( base + TIMER_O_IMR ) & TIMER_TIMA_TIMEOUT ) ) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int int_tmr_match_set_status( elua_int_resnum resnum, int status )
|
||||
{
|
||||
int prev = int_tmr_match_get_status( resnum );
|
||||
u32 base = timer_base[ resnum ];
|
||||
|
||||
if( status == PLATFORM_CPU_ENABLE )
|
||||
{
|
||||
MAP_TimerEnable( base, TIMER_A );
|
||||
MAP_TimerIntEnable( base, TIMER_TIMA_TIMEOUT );
|
||||
}
|
||||
else
|
||||
{
|
||||
MAP_TimerIntDisable( base, TIMER_TIMA_TIMEOUT );
|
||||
MAP_TimerDisable( base, TIMER_A );
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
static int int_tmr_match_get_flag( elua_int_resnum resnum, int clear )
|
||||
{
|
||||
u32 base = timer_base[ resnum ];
|
||||
int status = MAP_TimerIntStatus( base, true ) & TIMER_TIMA_TIMEOUT;
|
||||
|
||||
if( clear )
|
||||
MAP_TimerIntClear( base, TIMER_TIMA_TIMEOUT );
|
||||
return status && tmr_is_enabled( base ) ? 1 : 0;
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Interrupt initialization
|
||||
|
||||
void platform_int_init()
|
||||
{
|
||||
IntEnable( INT_UART0 );
|
||||
IntEnable( INT_UART1 );
|
||||
IntEnable( INT_UART2 );
|
||||
unsigned i;
|
||||
|
||||
MAP_IntEnable( INT_UART0 );
|
||||
MAP_IntEnable( INT_UART1 );
|
||||
MAP_IntEnable( INT_UART2 );
|
||||
for( i = 0; i < sizeof( gpio_int_ids ) / sizeof( u8 ); i ++ )
|
||||
MAP_IntEnable( gpio_int_ids[ i ] ) ;
|
||||
for( i = 0; i < sizeof( timer_int_ids ) / sizeof( u8 ); i ++ )
|
||||
MAP_IntEnable( timer_int_ids[ i ] );
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
@ -107,7 +413,63 @@ void platform_int_init()
|
||||
|
||||
const elua_int_descriptor elua_int_table[ INT_ELUA_LAST ] =
|
||||
{
|
||||
{ int_uart_rx_set_status, int_uart_rx_get_status, int_uart_rx_get_flag }
|
||||
{ int_uart_rx_set_status, int_uart_rx_get_status, int_uart_rx_get_flag },
|
||||
{ int_gpio_posedge_set_status, int_gpio_posedge_get_status, int_gpio_posedge_get_flag },
|
||||
{ int_gpio_negedge_set_status, int_gpio_negedge_get_status, int_gpio_negedge_get_flag },
|
||||
{ int_tmr_match_set_status, int_tmr_match_get_status, int_tmr_match_get_flag }
|
||||
};
|
||||
|
||||
#else // #if defined( BUILD_C_INT_HANDLERS ) || defined( BUILD_LUA_INT_HANDLERS )
|
||||
|
||||
void gpioa_handler()
|
||||
{
|
||||
}
|
||||
|
||||
void gpiob_handler()
|
||||
{
|
||||
}
|
||||
|
||||
void gpioc_handler()
|
||||
{
|
||||
}
|
||||
|
||||
void gpiod_handler()
|
||||
{
|
||||
}
|
||||
|
||||
void gpioe_handler()
|
||||
{
|
||||
}
|
||||
|
||||
void gpiof_handler()
|
||||
{
|
||||
}
|
||||
|
||||
void gpiog_handler()
|
||||
{
|
||||
|
||||
void gpioh_handler()
|
||||
{
|
||||
|
||||
void gpioj_handler()
|
||||
{
|
||||
}
|
||||
|
||||
void tmr0_handler()
|
||||
{
|
||||
}
|
||||
|
||||
void tmr1_handler()
|
||||
{
|
||||
}
|
||||
|
||||
void tmr2_handler()
|
||||
{
|
||||
}
|
||||
|
||||
void tmr3_handler()
|
||||
{
|
||||
}
|
||||
|
||||
#endif // #if defined( BUILD_C_INT_HANDLERS ) || defined( BUILD_LUA_INT_HANDLERS )
|
||||
|
||||
|
@ -5,8 +5,12 @@
|
||||
|
||||
#include "elua_int.h"
|
||||
|
||||
// Interrupt list
|
||||
#define INT_UART_RX ELUA_INT_FIRST_ID
|
||||
#define INT_ELUA_LAST INT_UART_RX
|
||||
#define INT_GPIO_POSEDGE ( ELUA_INT_FIRST_ID + 1 )
|
||||
#define INT_GPIO_NEGEDGE ( ELUA_INT_FIRST_ID + 2 )
|
||||
#define INT_TMR_MATCH ( ELUA_INT_FIRST_ID + 3 )
|
||||
#define INT_ELUA_LAST INT_TMR_MATCH
|
||||
|
||||
#endif // #ifndef __PLATFORM_INTS_H__
|
||||
|
||||
|
@ -53,7 +53,19 @@ extern void CANIntHandler();
|
||||
extern void uart0_handler();
|
||||
extern void uart1_handler();
|
||||
extern void uart2_handler();
|
||||
|
||||
extern void gpioa_handler();
|
||||
extern void gpiob_handler();
|
||||
extern void gpioc_handler();
|
||||
extern void gpiod_handler();
|
||||
extern void gpioe_handler();
|
||||
extern void gpiof_handler();
|
||||
extern void gpiog_handler();
|
||||
extern void gpioh_handler();
|
||||
extern void gpioj_handler();
|
||||
extern void tmr0_handler();
|
||||
extern void tmr1_handler();
|
||||
extern void tmr2_handler();
|
||||
extern void tmr3_handler();
|
||||
#if defined( BUILD_USB_CDC )
|
||||
extern void USB0DeviceIntHandler(void);
|
||||
#endif
|
||||
@ -92,11 +104,11 @@ void (* const g_pfnVectors[])(void) =
|
||||
0, // Reserved
|
||||
IntDefaultHandler, // The PendSV handler
|
||||
SysTickIntHandler, // The SysTick handler
|
||||
IntDefaultHandler, // GPIO Port A
|
||||
IntDefaultHandler, // GPIO Port B
|
||||
IntDefaultHandler, // GPIO Port C
|
||||
IntDefaultHandler, // GPIO Port D
|
||||
IntDefaultHandler, // GPIO Port E
|
||||
gpioa_handler, // GPIO Port A
|
||||
gpiob_handler, // GPIO Port B
|
||||
gpioc_handler, // GPIO Port C
|
||||
gpiod_handler, // GPIO Port D
|
||||
gpioe_handler, // GPIO Port E
|
||||
#if defined( BUILD_C_INT_HANDLERS ) || defined( BUILD_LUA_INT_HANDLERS )
|
||||
uart0_handler, // UART0 Rx and Tx
|
||||
#else
|
||||
@ -126,27 +138,27 @@ void (* const g_pfnVectors[])(void) =
|
||||
IntDefaultHandler, // ADC Sequence 3
|
||||
#endif
|
||||
IntDefaultHandler, // Watchdog timer
|
||||
IntDefaultHandler, // Timer 0 subtimer A
|
||||
tmr0_handler, // Timer 0 subtimer A
|
||||
IntDefaultHandler, // Timer 0 subtimer B
|
||||
IntDefaultHandler, // Timer 1 subtimer A
|
||||
tmr1_handler, // Timer 1 subtimer A
|
||||
IntDefaultHandler, // Timer 1 subtimer B
|
||||
IntDefaultHandler, // Timer 2 subtimer A
|
||||
tmr2_handler, // Timer 2 subtimer A
|
||||
IntDefaultHandler, // Timer 2 subtimer B
|
||||
IntDefaultHandler, // Analog Comparator 0
|
||||
IntDefaultHandler, // Analog Comparator 1
|
||||
IntDefaultHandler, // Analog Comparator 2
|
||||
IntDefaultHandler, // System Control (PLL, OSC, BO)
|
||||
IntDefaultHandler, // FLASH Control
|
||||
IntDefaultHandler, // GPIO Port F
|
||||
IntDefaultHandler, // GPIO Port G
|
||||
IntDefaultHandler, // GPIO Port H
|
||||
gpiof_handler, // GPIO Port F
|
||||
gpiog_handler, // GPIO Port G
|
||||
gpioh_handler, // GPIO Port H
|
||||
#if defined( BUILD_C_INT_HANDLERS ) || defined( BUILD_LUA_INT_HANDLERS )
|
||||
uart2_handler, // UART2 Rx and Tx
|
||||
#else
|
||||
IntDefaultHandler, // UART2 Rx and Tx
|
||||
#endif
|
||||
IntDefaultHandler, // SSI1 Rx and Tx
|
||||
IntDefaultHandler, // Timer 3 subtimer A
|
||||
tmr3_handler, // Timer 3 subtimer A
|
||||
IntDefaultHandler, // Timer 3 subtimer B
|
||||
IntDefaultHandler, // I2C1 Master and Slave
|
||||
IntDefaultHandler, // Quadrature Encoder 1
|
||||
@ -162,9 +174,9 @@ void (* const g_pfnVectors[])(void) =
|
||||
IntDefaultHandler, // Hibernate
|
||||
#if defined( BUILD_USB_CDC )
|
||||
USB0DeviceIntHandler, // USB0
|
||||
#else
|
||||
#else // #if defined( BUILD_USB_CDC )
|
||||
IntDefaultHandler, // USB0
|
||||
#endif
|
||||
#endif // #if defined( BUILD_USB_CDC )
|
||||
IntDefaultHandler, // PWM Generator 3
|
||||
IntDefaultHandler, // uDMA Software Transfer
|
||||
IntDefaultHandler, // uDMA Error
|
||||
@ -174,10 +186,10 @@ void (* const g_pfnVectors[])(void) =
|
||||
IntDefaultHandler, // ADC1 Sequence 3
|
||||
IntDefaultHandler, // I2S0
|
||||
IntDefaultHandler, // External Bus Interface 0
|
||||
IntDefaultHandler // GPIO Port J
|
||||
#else
|
||||
gpioj_handler // GPIO Port J
|
||||
#else // #if defined( FORLM3S9B92 ) || defined( FORLM3S9D92 )
|
||||
IntDefaultHandler // Hibernate
|
||||
#endif
|
||||
#endif // #if defined( FORLM3S9B92 ) || defined( FORLM3S9D92 )
|
||||
};
|
||||
|
||||
//*****************************************************************************
|
||||
|
@ -30,10 +30,6 @@ typedef volatile signed long vs32;
|
||||
typedef volatile signed short vs16;
|
||||
typedef volatile signed char vs8;
|
||||
|
||||
#ifndef _TIME48_C_
|
||||
typedef enum { FALSE = 0, TRUE = !FALSE } bool;
|
||||
#endif
|
||||
|
||||
typedef enum { RESET = 0, SET = !RESET } FlagStatus, ITStatus;
|
||||
|
||||
typedef enum { DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
|
||||
|
@ -865,20 +865,20 @@ u32 platform_spi_setup( unsigned id, int mode, u32 clock, unsigned cpol, unsigne
|
||||
{
|
||||
// GPIO setup
|
||||
// Fixed assignment:
|
||||
// P5.4 - SCLK
|
||||
// P5.5 - MOSI
|
||||
// P5.6 - MISO
|
||||
// P5.7 - CS
|
||||
// P2.4 - SCLK
|
||||
// P2.5 - MOSI
|
||||
// P2.6 - MISO
|
||||
// P2.7 - CS
|
||||
GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput;
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
|
||||
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull;
|
||||
GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt2;
|
||||
GPIO_Init(GPIO5, &GPIO_InitStructure);
|
||||
GPIO_Init(GPIO2, &GPIO_InitStructure);
|
||||
GPIO_InitStructure.GPIO_Direction = GPIO_PinInput;
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
|
||||
GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Enable;
|
||||
GPIO_InitStructure.GPIO_Alternate = GPIO_InputAlt1 ;
|
||||
GPIO_Init(GPIO5, &GPIO_InitStructure);
|
||||
GPIO_Init(GPIO2, &GPIO_InitStructure);
|
||||
|
||||
// Actual SPI setup
|
||||
SSP_DeInit(SSP0);
|
||||
|
@ -1,6 +1,18 @@
|
||||
#ifndef __TYPE_H__
|
||||
#define __TYPE_H__
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE (0)
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE (1)
|
||||
#endif
|
||||
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned long DWORD;
|
||||
|
@ -111,6 +111,7 @@ static struct dm_dirent* rfs_readdir_r( struct _reent *r, void *d, void *pdata )
|
||||
static struct dm_dirent ent;
|
||||
|
||||
rfsc_readdir( ( u32 )d, &ent.fname, &ent.fsize, &ent.ftime );
|
||||
ent.flags = 0;
|
||||
if( ent.fname == NULL )
|
||||
return NULL;
|
||||
return &ent;
|
||||
@ -179,7 +180,11 @@ static const DM_DEVICE rfs_device =
|
||||
rfs_opendir_r, // opendir
|
||||
rfs_readdir_r, // readdir
|
||||
rfs_closedir_r, // closedir
|
||||
NULL // getaddr
|
||||
NULL, // getaddr
|
||||
NULL, // mkdir
|
||||
NULL, // unlink
|
||||
NULL, // rmdir
|
||||
NULL // rename
|
||||
};
|
||||
|
||||
int remotefs_init()
|
||||
|
@ -362,7 +362,7 @@ static struct dm_dirent* romfs_readdir_r( struct _reent *r, void *d, void *pdata
|
||||
unsigned j;
|
||||
FSDATA *pfsdata = ( FSDATA* )pdata;
|
||||
int is_deleted;
|
||||
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
if( romfsh_read8( off, pfsdata ) == WOFS_END_MARKER_CHAR )
|
||||
@ -381,6 +381,7 @@ static struct dm_dirent* romfs_readdir_r( struct _reent *r, void *d, void *pdata
|
||||
pent->fsize = romfsh_read8( off, pfsdata ) + ( romfsh_read8( off + 1, pfsdata ) << 8 );
|
||||
pent->fsize += ( romfsh_read8( off + 2, pfsdata ) << 16 ) + ( romfsh_read8( off + 3, pfsdata ) << 24 );
|
||||
pent->ftime = 0;
|
||||
pent->flags = 0;
|
||||
off += ROMFS_SIZE_LEN;
|
||||
off += pent->fsize;
|
||||
if( romfsh_is_wofs( pfsdata ) )
|
||||
@ -426,6 +427,10 @@ static const DM_DEVICE romfs_device =
|
||||
romfs_readdir_r, // readdir
|
||||
romfs_closedir_r, // closedir
|
||||
romfs_getaddr_r, // getaddr
|
||||
NULL, // mkdir
|
||||
NULL, // unlink
|
||||
NULL, // rmdir
|
||||
NULL // rename
|
||||
};
|
||||
|
||||
// ****************************************************************************
|
||||
|
@ -237,6 +237,7 @@ static struct dm_dirent* semifs_readdir_r( struct _reent *r, void *d, void *pdat
|
||||
pent->fname = dm_shared_fname;
|
||||
pent->fsize = semifs_file_info->size;
|
||||
pent->ftime = 0; // need to convert from struct to UNIX time?!
|
||||
pent->flags = 0;
|
||||
return pent;
|
||||
}
|
||||
|
||||
@ -257,7 +258,11 @@ static const DM_DEVICE semifs_device =
|
||||
semifs_opendir_r, // opendir
|
||||
semifs_readdir_r, // readdir
|
||||
semifs_closedir_r, // closedir
|
||||
NULL // getaddr
|
||||
NULL, // getaddr
|
||||
NULL, // mkdir
|
||||
NULL, // unlink
|
||||
NULL, // rmdir
|
||||
NULL // rename
|
||||
};
|
||||
|
||||
int semifs_init()
|
||||
|
519
src/shell.c
519
src/shell.c
@ -1,519 +0,0 @@
|
||||
// eLua shell
|
||||
|
||||
#include "shell.h"
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
#include "xmodem.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "platform.h"
|
||||
#include "elua_net.h"
|
||||
#include "devman.h"
|
||||
#include "buf.h"
|
||||
#include "remotefs.h"
|
||||
#include "eluarpc.h"
|
||||
#include "linenoise.h"
|
||||
#include "term.h"
|
||||
#include "romfs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#if defined( USE_GIT_REVISION )
|
||||
#include "git_version.h"
|
||||
#else
|
||||
#include "version.h"
|
||||
#endif
|
||||
|
||||
#include "platform_conf.h"
|
||||
#ifdef BUILD_SHELL
|
||||
|
||||
// Shell alternate ' ' char
|
||||
#define SHELL_ALT_SPACE '\x07'
|
||||
#define SHELL_MAX_ARGS 10
|
||||
|
||||
// EOF is different in UART mode and TCP/IP mode
|
||||
#ifdef BUILD_CON_GENERIC
|
||||
#define SHELL_EOF_STRING "CTRL+Z"
|
||||
#else
|
||||
#define SHELL_EOF_STRING "CTRL+D"
|
||||
#endif
|
||||
|
||||
// Shell command handler function
|
||||
typedef void( *p_shell_handler )( int argc, char **argv );
|
||||
|
||||
// Command/handler pair structure
|
||||
typedef struct
|
||||
{
|
||||
const char* cmd;
|
||||
p_shell_handler handler_func;
|
||||
} SHELL_COMMAND;
|
||||
|
||||
// Shell data
|
||||
static char* shell_prog;
|
||||
|
||||
// ****************************************************************************
|
||||
// Shell functions
|
||||
|
||||
// 'help' handler
|
||||
static void shell_help( int argc, char **argv )
|
||||
{
|
||||
( void )argc;
|
||||
( void )argv;
|
||||
printf( "Shell commands:\n" );
|
||||
printf( " exit - exit from this shell\n" );
|
||||
printf( " help - print this help\n" );
|
||||
printf( " ls or dir - lists filesystems files and sizes\n" );
|
||||
printf( " cat or type - lists file contents\n" );
|
||||
printf( " lua [args] - run Lua with the given arguments\n" );
|
||||
printf( " recv [path] - receive a file via XMODEM. If path is given save it there, otherwise run it.\n");
|
||||
printf( " cp <src> <dst> - copy source file 'src' to 'dst'\n" );
|
||||
printf( " wofmt - format the internal WOFS\n" );
|
||||
printf( " ver - print eLua version\n" );
|
||||
}
|
||||
|
||||
// 'lua' handler
|
||||
static void shell_lua( int argc, char **argv )
|
||||
{
|
||||
printf( "Press " SHELL_EOF_STRING " to exit Lua\n" );
|
||||
lua_main( argc, argv );
|
||||
clearerr( stdin );
|
||||
}
|
||||
|
||||
// 'recv' handler
|
||||
static void shell_recv( int argc, char **argv )
|
||||
{
|
||||
#ifndef BUILD_XMODEM
|
||||
printf( "XMODEM support not compiled, unable to recv\n" );
|
||||
#else // #ifndef BUILD_XMODEM
|
||||
|
||||
char *p;
|
||||
long actsize;
|
||||
lua_State* L;
|
||||
|
||||
if( argc > 2 )
|
||||
{
|
||||
printf( "Usage: recv [path]\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if( ( shell_prog = malloc( XMODEM_INITIAL_BUFFER_SIZE ) ) == NULL )
|
||||
{
|
||||
printf( "Unable to allocate memory\n" );
|
||||
return;
|
||||
}
|
||||
printf( "Waiting for file ... " );
|
||||
if( ( actsize = xmodem_receive( &shell_prog ) ) < 0 )
|
||||
{
|
||||
free( shell_prog );
|
||||
shell_prog = NULL;
|
||||
if( actsize == XMODEM_ERROR_OUTOFMEM )
|
||||
printf( "file too big\n" );
|
||||
else
|
||||
printf( "XMODEM error\n" );
|
||||
return;
|
||||
}
|
||||
// Eliminate the XMODEM padding bytes
|
||||
p = shell_prog + actsize - 1;
|
||||
while( *p == '\x1A' )
|
||||
p --;
|
||||
p ++;
|
||||
printf( "done, got %u bytes\n", ( unsigned )( p - shell_prog ) );
|
||||
|
||||
// we've received an argument, try saving it to a file
|
||||
if( argc == 2 )
|
||||
{
|
||||
FILE *foutput = fopen( argv[ 1 ], "w" );
|
||||
size_t file_sz = p - shell_prog;
|
||||
if( foutput == NULL )
|
||||
{
|
||||
printf( "unable to open file %s\n", argv[ 1 ] );
|
||||
free( shell_prog );
|
||||
shell_prog = NULL;
|
||||
return;
|
||||
}
|
||||
if( fwrite( shell_prog, sizeof( char ), file_sz, foutput ) == file_sz )
|
||||
printf( "received and saved as %s\n", argv[ 1 ] );
|
||||
else
|
||||
printf( "unable to save file %s (no space left on target?)\n", argv[ 1 ] );
|
||||
fclose( foutput );
|
||||
}
|
||||
else // no arg, running the file with lua.
|
||||
{
|
||||
if( ( L = lua_open() ) == NULL )
|
||||
{
|
||||
printf( "Unable to create Lua state\n" );
|
||||
free( shell_prog );
|
||||
shell_prog = NULL;
|
||||
return;
|
||||
}
|
||||
luaL_openlibs( L );
|
||||
if( luaL_loadbuffer( L, shell_prog, p - shell_prog, "xmodem" ) != 0 )
|
||||
printf( "Error: %s\n", lua_tostring( L, -1 ) );
|
||||
else
|
||||
if( lua_pcall( L, 0, LUA_MULTRET, 0 ) != 0 )
|
||||
printf( "Error: %s\n", lua_tostring( L, -1 ) );
|
||||
lua_close( L );
|
||||
}
|
||||
free( shell_prog );
|
||||
shell_prog = NULL;
|
||||
#endif // #ifndef BUILD_XMODEM
|
||||
}
|
||||
|
||||
// 'ver' handler
|
||||
static void shell_ver( int argc, char **argv )
|
||||
{
|
||||
( void )argc;
|
||||
( void )argv;
|
||||
printf( "eLua version %s\n", ELUA_STR_VERSION );
|
||||
printf( "For more information visit www.eluaproject.net and wiki.eluaproject.net\n" );
|
||||
}
|
||||
|
||||
// 'ls' and 'dir' handler
|
||||
static void shell_ls( int argc, char **argv )
|
||||
{
|
||||
const DM_INSTANCE_DATA *pinst;
|
||||
unsigned dev, i;
|
||||
DM_DIR *d;
|
||||
struct dm_dirent *ent;
|
||||
u32 total;
|
||||
|
||||
( void )argc;
|
||||
( void )argv;
|
||||
// Iterate through all devices, looking for the ones that can do "opendir"
|
||||
for( dev = 0; dev < dm_get_num_devices(); dev ++ )
|
||||
{
|
||||
pinst = dm_get_instance_at( dev );
|
||||
if( pinst->pdev->p_opendir_r == NULL || pinst->pdev->p_readdir_r == NULL || pinst->pdev->p_closedir_r == NULL )
|
||||
continue;
|
||||
d = dm_opendir( pinst->name );
|
||||
if( d )
|
||||
{
|
||||
total = 0;
|
||||
printf( "\n%s", pinst->name );
|
||||
while( ( ent = dm_readdir( d ) ) != NULL )
|
||||
{
|
||||
printf( "\n%s", ent->fname );
|
||||
for( i = strlen( ent->fname ); i <= DM_MAX_FNAME_LENGTH; i++ )
|
||||
printf( " " );
|
||||
printf( "%u bytes", ( unsigned )ent->fsize );
|
||||
total = total + ent->fsize;
|
||||
}
|
||||
printf( "\n\nTotal on %s: %u bytes\n", pinst->name, ( unsigned )total );
|
||||
dm_closedir( d );
|
||||
}
|
||||
}
|
||||
printf( "\n" );
|
||||
}
|
||||
|
||||
// 'cat' and 'type' handler
|
||||
static void shell_cat( int argc, char **argv )
|
||||
{
|
||||
FILE *fp;
|
||||
int c;
|
||||
unsigned i;
|
||||
|
||||
if( argc < 2 )
|
||||
{
|
||||
printf( "Usage: cat (or type) <filename1> [<filename2> ...]\n" );
|
||||
return;
|
||||
}
|
||||
for( i = 1; i < argc; i ++ )
|
||||
{
|
||||
if( ( fp = fopen( argv[ i ] , "rb" ) ) != NULL )
|
||||
{
|
||||
c = fgetc( fp );
|
||||
while( c != EOF )
|
||||
{
|
||||
printf("%c", (char) c );
|
||||
c = fgetc( fp );
|
||||
}
|
||||
fclose ( fp );
|
||||
}
|
||||
else
|
||||
printf( "Unable to open '%s'\n", argv[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
// 'copy' handler
|
||||
#ifdef BUILD_RFS
|
||||
#define SHELL_COPY_BUFSIZE ( ( 1 << RFS_BUFFER_SIZE ) - ELUARPC_WRITE_REQUEST_EXTRA )
|
||||
#else
|
||||
#define SHELL_COPY_BUFSIZE 256
|
||||
#endif
|
||||
static void shell_cp( int argc, char **argv )
|
||||
{
|
||||
FILE *fps = NULL, *fpd = NULL;
|
||||
void *buf = NULL;
|
||||
size_t datalen, datawrote, total = 0;
|
||||
|
||||
if( argc != 3 )
|
||||
{
|
||||
printf( "Usage: cp <source> <destination>\n" );
|
||||
return;
|
||||
}
|
||||
if( ( fps = fopen( argv[ 1 ], "rb" ) ) == NULL )
|
||||
printf( "Unable to open %s for reading\n", argv[ 1 ] );
|
||||
else
|
||||
{
|
||||
if( ( fpd = fopen( argv[ 2 ], "wb" ) ) == NULL )
|
||||
printf( "Unable to open %s for writing\n", argv[ 2 ] );
|
||||
else
|
||||
{
|
||||
// Alloc memory
|
||||
if( ( buf = malloc( SHELL_COPY_BUFSIZE ) ) == NULL )
|
||||
printf( "Not enough memory\n" );
|
||||
else
|
||||
{
|
||||
// Do the actual copy
|
||||
while( 1 )
|
||||
{
|
||||
datalen = fread( buf, 1, SHELL_COPY_BUFSIZE, fps );
|
||||
datawrote = fwrite( buf, 1, datalen, fpd );
|
||||
if( datawrote < datalen )
|
||||
{
|
||||
printf( "Copy error (no space left on target?)\n" );
|
||||
break;
|
||||
}
|
||||
total += datalen;
|
||||
if( datalen < SHELL_COPY_BUFSIZE )
|
||||
break;
|
||||
}
|
||||
fflush( fpd );
|
||||
printf( "%u bytes copied\n", ( unsigned int )total );
|
||||
}
|
||||
}
|
||||
}
|
||||
if( fps )
|
||||
fclose( fps );
|
||||
if( fpd )
|
||||
fclose( fpd );
|
||||
if( buf )
|
||||
free( buf );
|
||||
}
|
||||
|
||||
// 'wofmt' handler
|
||||
static void shell_wofmt( int argc, char **argv )
|
||||
{
|
||||
#ifndef BUILD_WOFS
|
||||
printf( "WOFS not enabled.\n" );
|
||||
#else // #ifndef BUILD_WOFS
|
||||
int c;
|
||||
|
||||
printf( "Formatting the internal WOFS will DESTROY ALL THE FILES FROM WOFS.\n" );
|
||||
while( 1 )
|
||||
{
|
||||
printf( "Are you sure you want to continue? [y/n] " );
|
||||
c = term_getch( TERM_INPUT_WAIT );
|
||||
printf( "%c\n", isprint( c ) ? c : ' ' );
|
||||
c = tolower( c );
|
||||
if( c == 'n' )
|
||||
return;
|
||||
else if( c == 'y' )
|
||||
break;
|
||||
}
|
||||
printf( "Formatting ... " );
|
||||
if( !wofs_format() )
|
||||
{
|
||||
printf( "\ni*** ERROR ***: unable to erase the internal flash. WOFS might be compromised.\n" );
|
||||
printf( "It is advised to re-flash the eLua image.\n" );
|
||||
}
|
||||
else
|
||||
printf( " done.\n" );
|
||||
#endif // #ifndef BUILD_WOFS
|
||||
}
|
||||
|
||||
// Insert shell commands here
|
||||
static const SHELL_COMMAND shell_commands[] =
|
||||
{
|
||||
{ "help", shell_help },
|
||||
{ "lua", shell_lua },
|
||||
{ "recv", shell_recv },
|
||||
{ "ver", shell_ver },
|
||||
{ "exit", NULL },
|
||||
{ "ls", shell_ls },
|
||||
{ "dir", shell_ls },
|
||||
{ "cat", shell_cat },
|
||||
{ "type", shell_cat },
|
||||
{ "cp", shell_cp },
|
||||
{ "wofmt", shell_wofmt },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
// Execute the eLua "shell" in an infinite loop
|
||||
void shell_start()
|
||||
{
|
||||
char cmd[ SHELL_MAXSIZE + 1 ];
|
||||
char *p, *temp;
|
||||
const SHELL_COMMAND* pcmd;
|
||||
int i, inside_quotes;
|
||||
char quote_char;
|
||||
int argc;
|
||||
char *argv[ SHELL_MAX_ARGS ];
|
||||
|
||||
printf( SHELL_WELCOMEMSG, ELUA_STR_VERSION );
|
||||
while( 1 )
|
||||
{
|
||||
while( linenoise_getline( LINENOISE_ID_SHELL, cmd, SHELL_MAXSIZE - 1, SHELL_PROMPT ) == -1 )
|
||||
{
|
||||
printf( "\n" );
|
||||
clearerr( stdin );
|
||||
}
|
||||
if( strlen( cmd ) == 0 )
|
||||
continue;
|
||||
linenoise_addhistory( LINENOISE_ID_SHELL, cmd );
|
||||
if( cmd[ strlen( cmd ) - 1 ] != '\n' )
|
||||
strcat( cmd, "\n" );
|
||||
|
||||
// Change '\r', '\n' and '\t' chars to ' ' to ease processing
|
||||
p = cmd;
|
||||
while( *p )
|
||||
{
|
||||
if( *p == '\r' || *p == '\n' || *p == '\t' )
|
||||
*p = ' ';
|
||||
p ++;
|
||||
}
|
||||
|
||||
// Transform ' ' characters inside a '' or "" quoted string in
|
||||
// a 'special' char. We do this to let the user execute something
|
||||
// like "lua -e 'quoted string'" without disturbing the quoted
|
||||
// string in any way.
|
||||
for( i = 0, inside_quotes = 0, quote_char = '\0'; i < strlen( cmd ); i ++ )
|
||||
if( ( cmd[ i ] == '\'' ) || ( cmd[ i ] == '"' ) )
|
||||
{
|
||||
if( !inside_quotes )
|
||||
{
|
||||
inside_quotes = 1;
|
||||
quote_char = cmd[ i ];
|
||||
}
|
||||
else
|
||||
{
|
||||
if( cmd[ i ] == quote_char )
|
||||
{
|
||||
inside_quotes = 0;
|
||||
quote_char = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( ( cmd[ i ] == ' ' ) && inside_quotes )
|
||||
cmd[ i ] = SHELL_ALT_SPACE;
|
||||
if( inside_quotes )
|
||||
{
|
||||
printf( "Invalid quoted string\n" );
|
||||
continue;
|
||||
}
|
||||
|
||||
// Transform consecutive sequences of spaces into a single space
|
||||
p = strchr( cmd, ' ' );
|
||||
while( p )
|
||||
{
|
||||
temp = p + 1;
|
||||
while( *temp && *temp == ' ' )
|
||||
memmove( temp, temp + 1, strlen( temp ) );
|
||||
p = strchr( p + 1, ' ' );
|
||||
}
|
||||
if( !strcmp( cmd, " " ) )
|
||||
continue;
|
||||
|
||||
// Skip over the initial space char if it exists
|
||||
p = cmd;
|
||||
if( *p == ' ' )
|
||||
p ++;
|
||||
|
||||
// Add a final space if it does not exist
|
||||
if( p[ strlen( p ) - 1 ] != ' ' )
|
||||
strcat( p, " " );
|
||||
|
||||
// Compute argc/argv
|
||||
for( argc = 0; argc < SHELL_MAX_ARGS; argc ++ )
|
||||
argv[ argc ] = NULL;
|
||||
argc = 0;
|
||||
while( ( temp = strchr( p, ' ' ) ) != NULL )
|
||||
{
|
||||
*temp = 0;
|
||||
if( argc == SHELL_MAX_ARGS )
|
||||
{
|
||||
printf( "Error: too many arguments\n" );
|
||||
argc = -1;
|
||||
break;
|
||||
}
|
||||
argv[ argc ++ ] = p;
|
||||
p = temp + 1;
|
||||
}
|
||||
|
||||
if( argc == -1 )
|
||||
continue;
|
||||
|
||||
// Additional argument processing happens here
|
||||
for( i = 0; i < argc; i ++ )
|
||||
{
|
||||
p = argv[ i ];
|
||||
// Put back spaces if needed
|
||||
for( inside_quotes = 0; inside_quotes < strlen( argv[ i ] ); inside_quotes ++ )
|
||||
{
|
||||
if( p[ inside_quotes ] == SHELL_ALT_SPACE )
|
||||
argv[ i ][ inside_quotes ] = ' ';
|
||||
}
|
||||
// Remove quotes
|
||||
if( ( p[ 0 ] == '\'' || p [ 0 ] == '"' ) && ( p[ 0 ] == p[ strlen( p ) - 1 ] ) )
|
||||
{
|
||||
argv[ i ] = p + 1;
|
||||
p[ strlen( p ) - 1 ] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
// Match user command with shell's commands
|
||||
i = 0;
|
||||
while( 1 )
|
||||
{
|
||||
pcmd = shell_commands + i;
|
||||
if( pcmd->cmd == NULL )
|
||||
{
|
||||
printf( SHELL_ERRMSG );
|
||||
break;
|
||||
}
|
||||
if( !strcasecmp( pcmd->cmd, argv[ 0 ] ) )
|
||||
{
|
||||
// Special case: the "exit" command has a NULL handler
|
||||
if( pcmd->handler_func )
|
||||
pcmd->handler_func( argc, argv );
|
||||
break;
|
||||
}
|
||||
i ++;
|
||||
}
|
||||
// Check for 'exit' command
|
||||
if( pcmd->cmd && !pcmd->handler_func )
|
||||
#ifdef BUILD_UIP
|
||||
{
|
||||
if( ( i = elua_net_get_telnet_socket() ) != -1 )
|
||||
elua_net_close( i );
|
||||
}
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
|
||||
}
|
||||
// Shell exit point
|
||||
if( shell_prog )
|
||||
free( shell_prog );
|
||||
}
|
||||
|
||||
// Initialize the shell, returning 1 for OK and 0 for error
|
||||
int shell_init()
|
||||
{
|
||||
shell_prog = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else // #ifdef BUILD_SHELL
|
||||
|
||||
int shell_init()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void shell_start()
|
||||
{
|
||||
}
|
||||
|
||||
#endif // #ifdef BUILD_SHELL
|
415
src/shell/shell.c
Normal file
415
src/shell/shell.c
Normal file
@ -0,0 +1,415 @@
|
||||
// eLua shell
|
||||
|
||||
#include "shell.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "platform.h"
|
||||
#include "elua_net.h"
|
||||
#include "linenoise.h"
|
||||
#include "term.h"
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include "common.h"
|
||||
|
||||
#include "platform_conf.h"
|
||||
#ifdef BUILD_SHELL
|
||||
|
||||
#if defined( USE_GIT_REVISION )
|
||||
#include "git_version.h"
|
||||
#else
|
||||
#include "version.h"
|
||||
#endif
|
||||
|
||||
// Shell alternate ' ' char
|
||||
#define SHELL_ALT_SPACE '\x07'
|
||||
#define SHELL_MAX_ARGS 10
|
||||
|
||||
// External shell function declaration
|
||||
#define SHELL_FUNC( func ) extern void func( int argc, char **argv )
|
||||
|
||||
// Shell data
|
||||
char* shell_prog;
|
||||
|
||||
// Extern implementations of shell functions
|
||||
SHELL_FUNC( shell_ls );
|
||||
SHELL_FUNC( shell_cp );
|
||||
SHELL_FUNC( shell_adv_mv );
|
||||
SHELL_FUNC( shell_adv_rm );
|
||||
SHELL_FUNC( shell_recv );
|
||||
SHELL_FUNC( shell_help );
|
||||
SHELL_FUNC( shell_cat );
|
||||
SHELL_FUNC( shell_lua );
|
||||
SHELL_FUNC( shell_ver );
|
||||
SHELL_FUNC( shell_mkdir );
|
||||
SHELL_FUNC( shell_wofmt );
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
|
||||
// Helper: ask yes/no
|
||||
// Returns 1 for yes, 0 for no
|
||||
int shellh_ask_yes_no( const char *prompt )
|
||||
{
|
||||
int c;
|
||||
|
||||
if( prompt )
|
||||
printf( "%s ", prompt );
|
||||
while( 1 )
|
||||
{
|
||||
c = term_getch( TERM_INPUT_WAIT );
|
||||
if( c == 'y' || c == 'Y' )
|
||||
{
|
||||
printf( "y\n" );
|
||||
return 1;
|
||||
}
|
||||
if( c == 'n' || c == 'N' )
|
||||
{
|
||||
printf( "n\n" );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Will never get here
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef BUILD_RFS
|
||||
#define SHELL_COPY_BUFSIZE ( ( 1 << RFS_BUFFER_SIZE ) - ELUARPC_WRITE_REQUEST_EXTRA )
|
||||
#else
|
||||
#define SHELL_COPY_BUFSIZE 256
|
||||
#endif
|
||||
|
||||
// Dummy log function
|
||||
static int shellh_dummy_printf( const char *fmt, ... )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef int ( *p_logf )( const char *fmt, ... );
|
||||
|
||||
// Helper: copy one file to another file
|
||||
// Return 1 for success, 0 for error
|
||||
int shellh_cp_file( const char *psrcname, const char *pdestname, int flags )
|
||||
{
|
||||
int fds = -1, fdd = -1;
|
||||
int res = 0;
|
||||
char *buf = NULL;
|
||||
ssize_t datalen, datawrote;
|
||||
u32 total = 0;
|
||||
p_logf plog = ( flags & SHELL_F_SILENT ) ? shellh_dummy_printf : printf;
|
||||
|
||||
if( !strcasecmp( psrcname, pdestname ) )
|
||||
{
|
||||
plog( "Cannot copy '%s' into itself.\n", psrcname );
|
||||
goto done;
|
||||
}
|
||||
// If operation confirmation is enabled, ask the user first
|
||||
if( flags & SHELL_F_ASK_CONFIRMATION )
|
||||
{
|
||||
printf( "Copy '%s' to '%s' ? [y/n] ", psrcname, pdestname );
|
||||
if( shellh_ask_yes_no( NULL ) == 0 )
|
||||
goto done;
|
||||
}
|
||||
// Open source file
|
||||
if( ( fds = open( psrcname, O_RDONLY, 0 ) ) == -1 )
|
||||
{
|
||||
plog( "Error: unable to open source file '%s'\n", psrcname );
|
||||
goto done;
|
||||
}
|
||||
// If the destination exists and we need to ask for confirmation, do it now
|
||||
if( ( flags & SHELL_F_FORCE_DESTINATION ) == 0 )
|
||||
{
|
||||
if( ( fdd = open( pdestname, O_RDONLY, 0 ) ) != -1 )
|
||||
{
|
||||
close( fdd );
|
||||
fdd = -1;
|
||||
printf( "Destination '%s' already exists, are you sure you want to overwrite it ? [y/n] ", pdestname );
|
||||
if( shellh_ask_yes_no( NULL ) == 0 )
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
// Allocate buffer
|
||||
if( ( buf = ( char* )malloc( SHELL_COPY_BUFSIZE ) ) == NULL )
|
||||
{
|
||||
plog( "ERROR: unable to allocate buffer for copy operation.\n" );
|
||||
goto done;
|
||||
}
|
||||
plog( "Copying '%s' to '%s' ... ", psrcname, pdestname );
|
||||
if( ( flags & SHELL_F_SIMULATE_ONLY ) == 0 )
|
||||
{
|
||||
// Open destination file
|
||||
if( ( fdd = open( pdestname, O_WRONLY | O_CREAT | O_TRUNC, 0 ) ) == -1 )
|
||||
{
|
||||
plog( "ERROR: unable to open '%s' for writing.\n", pdestname );
|
||||
goto done;
|
||||
}
|
||||
// Do the actual copy
|
||||
while( 1 )
|
||||
{
|
||||
if( ( datalen = read( fds, buf, SHELL_COPY_BUFSIZE ) ) == -1 )
|
||||
{
|
||||
plog( "Error reading source file '%s'.\n", psrcname );
|
||||
goto done;
|
||||
}
|
||||
if( ( datawrote = write( fdd, buf, datalen ) ) == -1 )
|
||||
{
|
||||
plog( "Error writing destination file '%s'.\n", pdestname );
|
||||
goto done;
|
||||
}
|
||||
if( datawrote < datalen )
|
||||
{
|
||||
plog( "Copy error (no space left on target?)\n" );
|
||||
goto done;
|
||||
}
|
||||
total += datalen;
|
||||
if( datalen < SHELL_COPY_BUFSIZE )
|
||||
break;
|
||||
}
|
||||
}
|
||||
plog( "done (%u bytes).\n", ( unsigned )total );
|
||||
res = 1;
|
||||
done:
|
||||
if( fds != -1 )
|
||||
close( fds );
|
||||
if( fdd != -1 )
|
||||
close( fdd );
|
||||
if( buf )
|
||||
free( buf );
|
||||
return res;
|
||||
}
|
||||
|
||||
// 'Not implemented' handler for shell comands
|
||||
void shellh_not_implemented_handler( int argc, char **argv )
|
||||
{
|
||||
printf( SHELL_ERRMSG );
|
||||
}
|
||||
|
||||
// Shows the help for the given command
|
||||
void shellh_show_help( const char *cmd, const char *helptext )
|
||||
{
|
||||
printf( "Usage: %s %s", cmd, helptext );
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Public interface
|
||||
|
||||
// Insert shell commands here
|
||||
static const SHELL_COMMAND shell_commands[] =
|
||||
{
|
||||
{ "help", shell_help },
|
||||
{ "lua", shell_lua },
|
||||
{ "recv", shell_recv },
|
||||
{ "ver", shell_ver },
|
||||
{ "exit", NULL },
|
||||
{ "ls", shell_ls },
|
||||
{ "dir", shell_ls },
|
||||
{ "cat", shell_cat },
|
||||
{ "type", shell_cat },
|
||||
{ "cp", shell_cp },
|
||||
{ "wofmt", shell_wofmt },
|
||||
{ "mkdir", shell_mkdir },
|
||||
{ "rm", shell_adv_rm },
|
||||
{ "mv", shell_adv_mv },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
// Executes the given shell command
|
||||
// 'interactive_mode' is 1 if invoked directly from the interactive shell,
|
||||
// 0 otherwise
|
||||
// Returns a pointer to the shell_command that was executed, NULL for error
|
||||
const SHELL_COMMAND* shellh_execute_command( char* cmd, int interactive_mode )
|
||||
{
|
||||
char *p, *temp;
|
||||
const SHELL_COMMAND* pcmd;
|
||||
int i, inside_quotes;
|
||||
char quote_char;
|
||||
int argc;
|
||||
char *argv[ SHELL_MAX_ARGS ];
|
||||
|
||||
if( strlen( cmd ) == 0 )
|
||||
return NULL;
|
||||
|
||||
if( cmd[ strlen( cmd ) - 1 ] != '\n' )
|
||||
strcat( cmd, "\n" );
|
||||
|
||||
// Change '\r', '\n' and '\t' chars to ' ' to ease processing
|
||||
p = cmd;
|
||||
while( *p )
|
||||
{
|
||||
if( *p == '\r' || *p == '\n' || *p == '\t' )
|
||||
*p = ' ';
|
||||
p ++;
|
||||
}
|
||||
|
||||
// Transform ' ' characters inside a '' or "" quoted string in
|
||||
// a 'special' char. We do this to let the user execute something
|
||||
// like "lua -e 'quoted string'" without disturbing the quoted
|
||||
// string in any way.
|
||||
for( i = 0, inside_quotes = 0, quote_char = '\0'; i < strlen( cmd ); i ++ )
|
||||
if( ( cmd[ i ] == '\'' ) || ( cmd[ i ] == '"' ) )
|
||||
{
|
||||
if( !inside_quotes )
|
||||
{
|
||||
inside_quotes = 1;
|
||||
quote_char = cmd[ i ];
|
||||
}
|
||||
else
|
||||
{
|
||||
if( cmd[ i ] == quote_char )
|
||||
{
|
||||
inside_quotes = 0;
|
||||
quote_char = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( ( cmd[ i ] == ' ' ) && inside_quotes )
|
||||
cmd[ i ] = SHELL_ALT_SPACE;
|
||||
if( inside_quotes )
|
||||
{
|
||||
printf( "Invalid quoted string\n" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Transform consecutive sequences of spaces into a single space
|
||||
p = strchr( cmd, ' ' );
|
||||
while( p )
|
||||
{
|
||||
temp = p + 1;
|
||||
while( *temp && *temp == ' ' )
|
||||
memmove( temp, temp + 1, strlen( temp ) );
|
||||
p = strchr( p + 1, ' ' );
|
||||
}
|
||||
if( !strcmp( cmd, " " ) )
|
||||
return NULL;
|
||||
|
||||
// Skip over the initial space char if it exists
|
||||
p = cmd;
|
||||
if( *p == ' ' )
|
||||
p ++;
|
||||
|
||||
// Add a final space if it does not exist
|
||||
if( p[ strlen( p ) - 1 ] != ' ' )
|
||||
strcat( p, " " );
|
||||
|
||||
// Compute argc/argv
|
||||
for( argc = 0; argc < SHELL_MAX_ARGS; argc ++ )
|
||||
argv[ argc ] = NULL;
|
||||
argc = 0;
|
||||
while( ( temp = strchr( p, ' ' ) ) != NULL )
|
||||
{
|
||||
*temp = 0;
|
||||
if( argc == SHELL_MAX_ARGS )
|
||||
{
|
||||
printf( "Error: too many arguments\n" );
|
||||
argc = -1;
|
||||
break;
|
||||
}
|
||||
argv[ argc ++ ] = p;
|
||||
p = temp + 1;
|
||||
}
|
||||
|
||||
if( argc == -1 )
|
||||
return NULL;
|
||||
|
||||
// Additional argument processing happens here
|
||||
for( i = 0; i < argc; i ++ )
|
||||
{
|
||||
p = argv[ i ];
|
||||
// Put back spaces if needed
|
||||
for( inside_quotes = 0; inside_quotes < strlen( argv[ i ] ); inside_quotes ++ )
|
||||
{
|
||||
if( p[ inside_quotes ] == SHELL_ALT_SPACE )
|
||||
argv[ i ][ inside_quotes ] = ' ';
|
||||
}
|
||||
// Remove quotes
|
||||
if( ( p[ 0 ] == '\'' || p [ 0 ] == '"' ) && ( p[ 0 ] == p[ strlen( p ) - 1 ] ) )
|
||||
{
|
||||
argv[ i ] = p + 1;
|
||||
p[ strlen( p ) - 1 ] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
// Match user command with shell's commands
|
||||
i = 0;
|
||||
while( 1 )
|
||||
{
|
||||
pcmd = shell_commands + i;
|
||||
if( pcmd->cmd == NULL )
|
||||
{
|
||||
printf( SHELL_ERRMSG );
|
||||
break;
|
||||
}
|
||||
if( !strcasecmp( pcmd->cmd, argv[ 0 ] ) )
|
||||
{
|
||||
// Special case: the "exit" command has a NULL handler
|
||||
// Special case: "lua" is not allowed in non-interactive mode
|
||||
if( pcmd->handler_func && ( interactive_mode || strcasecmp( pcmd->cmd, "lua" ) ) )
|
||||
pcmd->handler_func( argc, argv );
|
||||
break;
|
||||
}
|
||||
i ++;
|
||||
}
|
||||
|
||||
// Special case: "exit" is not allowed in non-interactive mode
|
||||
if( !interactive_mode && !strcasecmp( pcmd->cmd, "exit" ) )
|
||||
return NULL;
|
||||
return pcmd;
|
||||
}
|
||||
|
||||
// Execute the eLua "shell" in an infinite loop
|
||||
void shell_start()
|
||||
{
|
||||
char cmd[ SHELL_MAXSIZE + 1 ];
|
||||
const SHELL_COMMAND *pcmd;
|
||||
int i;
|
||||
|
||||
printf( SHELL_WELCOMEMSG, ELUA_STR_VERSION );
|
||||
while( 1 )
|
||||
{
|
||||
while( linenoise_getline( LINENOISE_ID_SHELL, cmd, SHELL_MAXSIZE - 1, SHELL_PROMPT ) == -1 )
|
||||
{
|
||||
printf( "\n" );
|
||||
clearerr( stdin );
|
||||
}
|
||||
if( strlen( cmd ) == 0 )
|
||||
continue;
|
||||
linenoise_addhistory( LINENOISE_ID_SHELL, cmd );
|
||||
pcmd = shellh_execute_command( cmd, 1 );
|
||||
// Check for 'exit' command
|
||||
if( pcmd && pcmd->cmd && !pcmd->handler_func )
|
||||
#ifdef BUILD_UIP
|
||||
{
|
||||
if( ( i = elua_net_get_telnet_socket() ) != -1 )
|
||||
elua_net_close( i );
|
||||
}
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
// Shell exit point
|
||||
if( shell_prog )
|
||||
free( shell_prog );
|
||||
}
|
||||
|
||||
// Initialize the shell, returning 1 for OK and 0 for error
|
||||
int shell_init()
|
||||
{
|
||||
shell_prog = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else // #ifdef BUILD_SHELL
|
||||
|
||||
int shell_init()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void shell_start()
|
||||
{
|
||||
}
|
||||
|
||||
#endif // #ifdef BUILD_SHELL
|
||||
|
295
src/shell/shell_adv_cp_mv.c
Normal file
295
src/shell/shell_adv_cp_mv.c
Normal file
@ -0,0 +1,295 @@
|
||||
// Advanced shell: 'cp' and 'mv' implementation
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "type.h"
|
||||
#include "platform_conf.h"
|
||||
|
||||
#ifdef BUILD_ADVANCED_SHELL
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *pdestdir;
|
||||
const char *psrcdir;
|
||||
const char *dloc;
|
||||
u8 flags;
|
||||
} SHELL_CP_STATE;
|
||||
|
||||
const char shell_help_cp[] = "<source> <destination> [-R] [-f] [-c] [-s]\n"
|
||||
" <source>: source file/directory/file mask.\n"
|
||||
" <destination>: destination file/directory.\n"
|
||||
" [-R]: recursive\n"
|
||||
" [-f]: force destination override (default is to ask confirmation).\n"
|
||||
" [-c]: confirm each operation.\n"
|
||||
" [-s]: simulate only (no actual operation).\n";
|
||||
const char shell_help_summary_cp[] = "copy files";
|
||||
|
||||
#define shell_help_mv shell_help_cp
|
||||
const char shell_help_summary_mv[] = "move/rename files";
|
||||
|
||||
int shellh_cp_or_mv_file( const char *psrc, const char *pdest, int flags )
|
||||
{
|
||||
if( flags & SHELL_F_MOVE )
|
||||
{
|
||||
if( rename( psrc, pdest ) == -1 )
|
||||
{
|
||||
if( errno != EXDEV )
|
||||
{
|
||||
printf( "Unable to rename '%s'.\n", psrc );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "Moved '%s' to '%s'.\n", psrc, pdest );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if( !shellh_cp_file( psrc, pdest, flags ) )
|
||||
return 0;
|
||||
if( flags & SHELL_F_MOVE )
|
||||
{
|
||||
if( unlink( psrc ) == -1 )
|
||||
{
|
||||
printf( "Unable to remove original file '%s'.\n", psrc );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// copy/move callback
|
||||
static int shellh_cp_walkdir_cb( const char *path, const struct dm_dirent *pent, void *pdata, int info )
|
||||
{
|
||||
SHELL_CP_STATE *ps = ( SHELL_CP_STATE* )pdata;
|
||||
char *tmp = NULL, *tmp2 = NULL;
|
||||
int res = 1;
|
||||
DM_DIR *d = NULL;
|
||||
|
||||
switch( info )
|
||||
{
|
||||
case CMN_FS_INFO_BEFORE_READDIR:
|
||||
if( strstr( path, ps->psrcdir ) != path )
|
||||
{
|
||||
printf( "ERROR: unable to handle directory '%s' (internal error?), aborting.\n", path );
|
||||
goto done_err;
|
||||
}
|
||||
// Need to create this directory if it does not exist
|
||||
if( ( tmp = ( char* )cmn_fs_path_join( ps->pdestdir, path + strlen( ps->psrcdir ) - strlen( ps->dloc ), NULL ) ) == NULL )
|
||||
{
|
||||
printf( "Not enough memory.\n" );
|
||||
goto done_err;
|
||||
}
|
||||
if( ( d = dm_opendir( tmp ) ) != NULL )
|
||||
goto done;
|
||||
printf( "Creating directory %s ... ", tmp );
|
||||
if( ( ps->flags & SHELL_F_SIMULATE_ONLY ) == 0 )
|
||||
{
|
||||
if( mkdir( tmp, 0 ) == -1 )
|
||||
{
|
||||
printf( "ERROR! (aborting).\n" );
|
||||
goto done_err;
|
||||
}
|
||||
else
|
||||
printf( "done.\n" );
|
||||
}
|
||||
else
|
||||
printf( "done.\n" );
|
||||
goto done;
|
||||
|
||||
case CMN_FS_INFO_INSIDE_READDIR:
|
||||
if( !DM_DIRENT_IS_DIR( pent ) )
|
||||
{
|
||||
if( strstr( path, ps->psrcdir ) != path )
|
||||
{
|
||||
printf( "ERROR: unable to handle directory '%s' (internal error?), aborting.\n", path );
|
||||
goto done_err;
|
||||
}
|
||||
if( ( tmp = cmn_fs_path_join( path, pent->fname, NULL ) ) == NULL )
|
||||
{
|
||||
printf( "Not enough memory.\n" );
|
||||
goto done_err;
|
||||
}
|
||||
if( ( tmp2 = cmn_fs_path_join( ps->pdestdir, path + strlen( ps->psrcdir ) - strlen( ps->dloc ), pent->fname, NULL ) ) == NULL )
|
||||
{
|
||||
printf( "Not enough memory.\n" );
|
||||
goto done_err;
|
||||
}
|
||||
shellh_cp_or_mv_file( tmp, tmp2, ps->flags );
|
||||
}
|
||||
goto done;
|
||||
|
||||
case CMN_FS_INFO_OPENDIR_FAILED:
|
||||
printf( "ERROR: unable to read directory '%s', aborting.\n", path );
|
||||
goto done_err;
|
||||
|
||||
default:
|
||||
goto done;
|
||||
}
|
||||
done_err:
|
||||
res = 0;
|
||||
done:
|
||||
if( tmp )
|
||||
free( tmp );
|
||||
if( tmp2 )
|
||||
free( tmp2 );
|
||||
if( d )
|
||||
dm_closedir( d );
|
||||
return res;
|
||||
}
|
||||
|
||||
static void shellh_adv_cp_mv_common( int argc, char **argv, int is_move )
|
||||
{
|
||||
const char *srcpath = NULL, *dstpath = NULL;
|
||||
unsigned i, flags = is_move ? SHELL_F_MOVE : 0;
|
||||
int srctype, dsttype;
|
||||
char *srcdir = NULL, *dstdir = NULL, *tmp = NULL;
|
||||
const char *srcfile, *dstfile;
|
||||
SHELL_CP_STATE state;
|
||||
|
||||
if( argc < 3 )
|
||||
{
|
||||
if( is_move )
|
||||
SHELL_SHOW_HELP( mv );
|
||||
else
|
||||
SHELL_SHOW_HELP( cp );
|
||||
return;
|
||||
}
|
||||
for( i = 1; i < argc; i ++ )
|
||||
{
|
||||
if( !strcmp( argv[ i ], "-R" ) )
|
||||
flags |= SHELL_F_RECURSIVE;
|
||||
else if( !strcmp( argv[ i ], "-f" ) )
|
||||
flags |= SHELL_F_FORCE_DESTINATION;
|
||||
else if( !strcmp( argv[ i ], "-c" ) )
|
||||
flags |= SHELL_F_ASK_CONFIRMATION;
|
||||
else if( !strcmp( argv[ i ], "-s" ) )
|
||||
flags |= SHELL_F_SIMULATE_ONLY;
|
||||
else if( argv[ i ][ 0 ] == '/' )
|
||||
{
|
||||
if( !srcpath )
|
||||
srcpath = argv[ i ];
|
||||
else if( !dstpath )
|
||||
dstpath = argv[ i ];
|
||||
else
|
||||
printf( "WARNING: ignoring argument '%s'\n", argv[ i ] );
|
||||
}
|
||||
else
|
||||
printf( "WARNING: ignoring argument '%s'\n", argv[ i ] );
|
||||
}
|
||||
if( !srcpath || !dstpath )
|
||||
{
|
||||
printf( "Source and/or destination not specified.\n" );
|
||||
return;
|
||||
}
|
||||
srctype = cmn_fs_get_type( srcpath );
|
||||
if( ( dsttype = cmn_fs_get_type( dstpath ) ) == CMN_FS_TYPE_PATTERN )
|
||||
{
|
||||
printf( "Invalid destination '%s'.\n", dstpath );
|
||||
goto done;
|
||||
}
|
||||
if( srctype == CMN_FS_TYPE_ERROR || srctype == CMN_FS_TYPE_FILE_NOT_FOUND ||
|
||||
srctype == CMN_FS_TYPE_DIR_NOT_FOUND || srctype == CMN_FS_TYPE_UNKNOWN_NOT_FOUND ||
|
||||
dsttype == CMN_FS_TYPE_ERROR || dsttype == CMN_FS_TYPE_DIR_NOT_FOUND )
|
||||
{
|
||||
printf( "%d %d\n", srctype, dsttype );
|
||||
printf( "Invalid source and/or destination.\n" );
|
||||
return;
|
||||
}
|
||||
srcdir = cmn_fs_split_path( srcpath, &srcfile );
|
||||
dstdir = cmn_fs_split_path( dstpath, &dstfile );
|
||||
// Check valid source/destination combinations
|
||||
if( srctype == CMN_FS_TYPE_FILE )
|
||||
{
|
||||
if( dsttype == CMN_FS_TYPE_FILE || dsttype == CMN_FS_TYPE_FILE_NOT_FOUND || dsttype == CMN_FS_TYPE_UNKNOWN_NOT_FOUND ) // direct file-to-file operation
|
||||
{
|
||||
shellh_cp_or_mv_file( srcpath, dstpath, flags );
|
||||
goto done;
|
||||
}
|
||||
else if( dsttype == CMN_FS_TYPE_DIR ) // copy/move to destination dir with the same name
|
||||
{
|
||||
if( ( tmp = cmn_fs_path_join( dstdir, srcfile, NULL ) ) == NULL )
|
||||
{
|
||||
printf( "Not enough memory.\n" );
|
||||
goto done;
|
||||
}
|
||||
shellh_cp_or_mv_file( srcpath, tmp, flags );
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "Invalid destination.\n" );
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( dsttype == CMN_FS_TYPE_FILE || dsttype == CMN_FS_TYPE_FILE_NOT_FOUND )
|
||||
{
|
||||
printf( "Invalid destination '%s'.\n", dstpath );
|
||||
goto done;
|
||||
}
|
||||
memset( &state, 0, sizeof( state ) );
|
||||
state.dloc = NULL;
|
||||
if( ( flags & SHELL_F_RECURSIVE ) != 0 )
|
||||
state.dloc = strrchr( srcdir, '/' );
|
||||
if( state.dloc == NULL )
|
||||
state.dloc = "";
|
||||
state.flags = flags;
|
||||
state.pdestdir = dstdir;
|
||||
state.psrcdir = srcdir;
|
||||
cmn_fs_walkdir( srcpath, shellh_cp_walkdir_cb, &state, flags & SHELL_F_RECURSIVE );
|
||||
}
|
||||
done:
|
||||
if( srcdir )
|
||||
free( srcdir );
|
||||
if( dstdir )
|
||||
free( dstdir );
|
||||
if( tmp )
|
||||
free( tmp );
|
||||
}
|
||||
|
||||
void shell_cp( int argc, char **argv )
|
||||
{
|
||||
shellh_adv_cp_mv_common( argc, argv, 0 );
|
||||
}
|
||||
|
||||
void shell_adv_mv( int argc, char **argv )
|
||||
{
|
||||
shellh_adv_cp_mv_common( argc, argv, 1 );
|
||||
}
|
||||
|
||||
#else // #ifdef BUILD_ADVANCED_SHELL
|
||||
|
||||
const char shell_help_cp[] = "cp <source> <destination>\n"
|
||||
" <source>: source file/directory/file mask.\n"
|
||||
" <destination>: destination file/directory.\n";
|
||||
const char shell_help_summary_cp[] = "copy files";
|
||||
|
||||
const char shell_help_mv[] = "";
|
||||
const char shell_help_summary_mv[] = "";
|
||||
|
||||
void shell_cp( int argc, char **argv )
|
||||
{
|
||||
if( argc != 3 )
|
||||
{
|
||||
SHELL_SHOW_HELP( cp );
|
||||
return;
|
||||
}
|
||||
shellh_cp_file( argv[ 1 ], argv[ 2 ], 0 );
|
||||
}
|
||||
|
||||
void shell_adv_mv( int argc, char **argv )
|
||||
{
|
||||
shellh_not_implemented_handler( argc, argv );
|
||||
}
|
||||
|
||||
#endif // #ifdef BUILD_ADVANCED_SHELL
|
||||
|
153
src/shell/shell_adv_rm.c
Normal file
153
src/shell/shell_adv_rm.c
Normal file
@ -0,0 +1,153 @@
|
||||
// Advanced shell: 'rm' implementation
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "type.h"
|
||||
#include "platform_conf.h"
|
||||
|
||||
#ifdef BUILD_ADVANCED_SHELL
|
||||
|
||||
const char shell_help_rm[] = "<filemask> [-R] [-c] [-s]\n"
|
||||
" <filemask>: file, directory or file mask to remove.\n"
|
||||
" -R: remove recursively.\n"
|
||||
" -c: confirm each remove.\n"
|
||||
" -s: simulate only (no actual operation).\n";
|
||||
const char shell_help_summary_rm[] = "remove files";
|
||||
|
||||
// helper: remove a single file and/or directory
|
||||
static void shellh_rm_one( const char* path, int flags )
|
||||
{
|
||||
int ftype = cmn_fs_get_type( path );
|
||||
int res = 0;
|
||||
|
||||
if( flags & SHELL_F_ASK_CONFIRMATION )
|
||||
{
|
||||
printf( "Are you sure you want to remove %s ? [y/n] ", path );
|
||||
if( shellh_ask_yes_no( NULL ) == 0 )
|
||||
return;
|
||||
}
|
||||
if( ( flags & SHELL_F_SIMULATE_ONLY ) == 0 )
|
||||
{
|
||||
if( ftype == CMN_FS_TYPE_FILE )
|
||||
res = unlink( path );
|
||||
else if( ftype == CMN_FS_TYPE_DIR )
|
||||
res = rmdir( path );
|
||||
else
|
||||
{
|
||||
printf( "WARNING: invalid argument '%s'\n", path );
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( res )
|
||||
{
|
||||
if( ( flags & SHELL_F_SILENT ) == 0 )
|
||||
printf( "WARNING: unable to remove %s\n", path );
|
||||
}
|
||||
else
|
||||
printf( "Removed %s\n", path );
|
||||
}
|
||||
|
||||
static int shellh_rm_walkdir_cb( const char *path, const struct dm_dirent *pent, void *pdata, int info )
|
||||
{
|
||||
u8 *pflags = ( u8* )pdata;
|
||||
char *tmp = NULL;
|
||||
int res = 1;
|
||||
|
||||
switch( info )
|
||||
{
|
||||
case CMN_FS_INFO_BEFORE_READDIR:
|
||||
goto done;
|
||||
|
||||
case CMN_FS_INFO_INSIDE_READDIR:
|
||||
if( ( tmp = cmn_fs_path_join( path, pent->fname, NULL ) ) == NULL )
|
||||
{
|
||||
printf( "Not enough memory.\n" );
|
||||
goto done_err;
|
||||
}
|
||||
if( cmn_fs_get_type( tmp ) == CMN_FS_TYPE_FILE )
|
||||
shellh_rm_one( tmp, *pflags );
|
||||
goto done;
|
||||
|
||||
case CMN_FS_INFO_OPENDIR_FAILED:
|
||||
printf( "ERROR: unable to read directory '%s', aborting.\n", path );
|
||||
goto done_err;
|
||||
|
||||
case CMN_FS_INFO_DIRECTORY_DONE:
|
||||
if( ( *pflags & SHELL_F_RECURSIVE ) && !cmn_fs_is_root_dir( path ) )
|
||||
shellh_rm_one( path, *pflags | SHELL_F_SILENT );
|
||||
goto done;
|
||||
|
||||
default:
|
||||
goto done;
|
||||
}
|
||||
done_err:
|
||||
res = 0;
|
||||
done:
|
||||
if( tmp )
|
||||
free( tmp );
|
||||
return res;
|
||||
}
|
||||
|
||||
void shell_adv_rm( int argc, char **argv )
|
||||
{
|
||||
const char *fmask = NULL;
|
||||
unsigned i, flags = 0;
|
||||
int masktype;
|
||||
|
||||
if( argc < 2 )
|
||||
{
|
||||
SHELL_SHOW_HELP( rm );
|
||||
return;
|
||||
}
|
||||
for( i = 1; i < argc; i ++ )
|
||||
{
|
||||
if( argv[ i ][ 0 ] == '/' )
|
||||
{
|
||||
if( !fmask )
|
||||
fmask = argv[ i ];
|
||||
else
|
||||
printf( "Warning: ignoring argument '%s'\n", argv[ i ] );
|
||||
}
|
||||
else if( !strcmp( argv[ i ], "-R" ) )
|
||||
flags |= SHELL_F_RECURSIVE;
|
||||
else if( !strcmp( argv[ i ], "-c" ) )
|
||||
flags |= SHELL_F_ASK_CONFIRMATION;
|
||||
else if( !strcmp( argv[ i ], "-s" ) )
|
||||
flags |= SHELL_F_SIMULATE_ONLY;
|
||||
else
|
||||
printf( "Warning: ignoring argument '%s'\n", argv[ i ] );
|
||||
}
|
||||
if( !fmask )
|
||||
{
|
||||
printf( "rm target not specified.\n" );
|
||||
return;
|
||||
}
|
||||
masktype = cmn_fs_get_type( fmask );
|
||||
if( masktype == CMN_FS_TYPE_FILE )
|
||||
shellh_rm_one( fmask, flags );
|
||||
else if( masktype == CMN_FS_TYPE_ERROR || masktype == CMN_FS_TYPE_FILE_NOT_FOUND || masktype == CMN_FS_TYPE_DIR_NOT_FOUND || masktype == CMN_FS_TYPE_UNKNOWN_NOT_FOUND )
|
||||
printf( "Invalid argument '%s'.\n", fmask );
|
||||
else if( masktype == CMN_FS_TYPE_DIR && ( ( flags & SHELL_F_RECURSIVE ) == 0 ) )
|
||||
printf( "'%s': unable to remove directory (use '-R').\n", fmask );
|
||||
else
|
||||
cmn_fs_walkdir( fmask, shellh_rm_walkdir_cb, &flags, flags & SHELL_F_RECURSIVE );
|
||||
}
|
||||
|
||||
#else // #ifdef BUILD_ADVANCED_SHELL
|
||||
|
||||
const char shell_help_rm[] = "";
|
||||
const char shell_help_summary_rm[] = "";
|
||||
|
||||
void shell_adv_rm( int argc, char **argv )
|
||||
{
|
||||
shellh_not_implemented_handler( argc, argv );
|
||||
}
|
||||
|
||||
#endif // #ifdef BUILD_ADVANCED_SHELL
|
||||
|
47
src/shell/shell_cat.c
Normal file
47
src/shell/shell_cat.c
Normal file
@ -0,0 +1,47 @@
|
||||
// Shell: 'cat' implementation
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "type.h"
|
||||
#include "platform_conf.h"
|
||||
|
||||
const char shell_help_cat[] = "<file> [<file2>] ... [<filen>]"
|
||||
" <file>: the file to list.\n"
|
||||
" [<file2>] ... [<filen>]: other files to list.\n";
|
||||
const char shell_help_summary_cat[] = "list the contents of a file";
|
||||
|
||||
void shell_cat( int argc, char **argv )
|
||||
{
|
||||
FILE *fp;
|
||||
int c;
|
||||
unsigned i;
|
||||
|
||||
if( argc < 2 )
|
||||
{
|
||||
shellh_show_help( argv[ 0 ], shell_help_cat );
|
||||
return;
|
||||
}
|
||||
for( i = 1; i < argc; i ++ )
|
||||
{
|
||||
if( ( fp = fopen( argv[ i ] , "rb" ) ) != NULL )
|
||||
{
|
||||
c = fgetc( fp );
|
||||
while( c != EOF )
|
||||
{
|
||||
printf("%c", (char) c );
|
||||
c = fgetc( fp );
|
||||
}
|
||||
fclose ( fp );
|
||||
}
|
||||
else
|
||||
printf( "Unable to open '%s'\n", argv[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
|
113
src/shell/shell_help.c
Normal file
113
src/shell/shell_help.c
Normal file
@ -0,0 +1,113 @@
|
||||
// Shell: 'help' implementation
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "type.h"
|
||||
#include "platform_conf.h"
|
||||
|
||||
// External help text declaration
|
||||
#define SHELL_HELP( topic ) extern const char shell_help_##topic[];\
|
||||
extern const char shell_help_summary_##topic[]
|
||||
#define SHELL_INFO( cmd ) { #cmd, shell_help_summary_##cmd, shell_help_##cmd }
|
||||
#define SHELL_INFO_ALIAS( cmd, alias ) { #cmd, shell_help_summary_##alias, shell_help_##alias }
|
||||
|
||||
// Help data
|
||||
typedef struct
|
||||
{
|
||||
const char *cmd;
|
||||
const char *help_summary;
|
||||
const char *help_full;
|
||||
} SHELL_HELP_DATA;
|
||||
|
||||
SHELL_HELP( cp );
|
||||
SHELL_HELP( rm );
|
||||
SHELL_HELP( ls );
|
||||
SHELL_HELP( recv );
|
||||
SHELL_HELP( cat );
|
||||
SHELL_HELP( lua );
|
||||
SHELL_HELP( ver );
|
||||
SHELL_HELP( mkdir );
|
||||
SHELL_HELP( wofmt );
|
||||
// 'mv' is special, as it uses the main help text from 'cp'
|
||||
extern const char shell_help_summary_mv[];
|
||||
|
||||
// 'Help' help data is local for ovious reasons
|
||||
static const char shell_help_help[] = "[<command>]\n"
|
||||
" [<command>] - the command to get help on.\n"
|
||||
"Without arguments it shows a summary of all the shell commands.\n";
|
||||
static const char shell_help_summary_help[] = "shell help";
|
||||
|
||||
// Also put the help for 'exit' here
|
||||
static const char shell_help_exit[] = "\n"
|
||||
"Exits the shell.\n";
|
||||
static const char shell_help_summary_exit[] = "exit the shell";
|
||||
|
||||
static const SHELL_HELP_DATA shell_help_data[] =
|
||||
{
|
||||
SHELL_INFO( help ),
|
||||
SHELL_INFO( lua ),
|
||||
SHELL_INFO( ls ),
|
||||
SHELL_INFO_ALIAS( dir, ls ),
|
||||
SHELL_INFO( cat ),
|
||||
SHELL_INFO_ALIAS( type, cat ),
|
||||
SHELL_INFO( recv ),
|
||||
SHELL_INFO( cp ),
|
||||
// Yes, 'mv' is still special
|
||||
{ "mv", shell_help_summary_mv, shell_help_cp },
|
||||
SHELL_INFO( rm ),
|
||||
SHELL_INFO( ver ),
|
||||
SHELL_INFO( mkdir ),
|
||||
SHELL_INFO( wofmt ),
|
||||
SHELL_INFO( exit ),
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
void shell_help( int argc, char **argv )
|
||||
{
|
||||
const SHELL_HELP_DATA *ph;
|
||||
|
||||
if( argc > 2 )
|
||||
{
|
||||
SHELL_SHOW_HELP( help );
|
||||
return;
|
||||
}
|
||||
ph = shell_help_data;
|
||||
if( argc == 1 )
|
||||
{
|
||||
// List commands and their summary
|
||||
// It is assumed that a command with an empty summary does not
|
||||
// actually exist (helpful for conditional compilation)
|
||||
printf( "Shell commands:\n" );
|
||||
while( 1 )
|
||||
{
|
||||
if( ph->cmd == NULL )
|
||||
break;
|
||||
if( strlen( ph->help_summary ) > 0 )
|
||||
printf( " %-6s - %s\n", ph->cmd, ph->help_summary );
|
||||
ph ++;
|
||||
}
|
||||
printf( "For more information use 'help <command>'.\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
while( 1 )
|
||||
{
|
||||
if( ph->cmd == NULL )
|
||||
break;
|
||||
if( !strcmp( ph->cmd, argv[ 1 ] ) && strlen( ph->help_summary ) > 0 )
|
||||
{
|
||||
printf( "%s - %s\nUsage: %s %s", ph->cmd, ph->help_summary, ph->cmd, ph->help_full );
|
||||
return;
|
||||
}
|
||||
ph ++;
|
||||
}
|
||||
printf( "Unknown command '%s'.\n", argv[ 1 ] );
|
||||
}
|
||||
}
|
||||
|
151
src/shell/shell_ls.c
Normal file
151
src/shell/shell_ls.c
Normal file
@ -0,0 +1,151 @@
|
||||
// Shell: 'ls' implementation
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "type.h"
|
||||
#include "platform_conf.h"
|
||||
|
||||
#ifdef BUILD_ADVANCED_SHELL
|
||||
|
||||
// State for walkdir
|
||||
typedef struct
|
||||
{
|
||||
u32 dir_total;
|
||||
u32 total;
|
||||
u8 ndirs;
|
||||
} SHELL_LS_STATE;
|
||||
|
||||
const char shell_help_ls[] = "[<path>] [-R]\n"
|
||||
" [<path>]: path to list.\n"
|
||||
" [-R]: recursive\n";
|
||||
const char shell_help_summary_ls[] = "lists files and directories";
|
||||
|
||||
// 'ls' and 'dir' handler
|
||||
// Syntax: ls [dir] [-R]
|
||||
// directory walker callback
|
||||
static int shellh_ls_walkdir_cb( const char *path, const struct dm_dirent *pent, void *pdata, int info )
|
||||
{
|
||||
SHELL_LS_STATE *ps = ( SHELL_LS_STATE* )pdata;
|
||||
|
||||
switch( info )
|
||||
{
|
||||
case CMN_FS_INFO_BEFORE_READDIR:
|
||||
ps->dir_total = 0;
|
||||
printf( "%s\n", path );
|
||||
if( ps->ndirs != 0xFF )
|
||||
ps->ndirs ++;
|
||||
break;
|
||||
|
||||
case CMN_FS_INFO_INSIDE_READDIR:
|
||||
printf( " %-30s", pent->fname );
|
||||
if( DM_DIRENT_IS_DIR( pent ) )
|
||||
printf( "<DIR>\n" );
|
||||
else
|
||||
{
|
||||
printf( "%u bytes\n", ( unsigned )pent->fsize );
|
||||
ps->dir_total += pent->fsize;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMN_FS_INFO_AFTER_CLOSEDIR:
|
||||
printf( "Total on %s: %u bytes\n\n", path, ( unsigned )ps->dir_total );
|
||||
ps->total += ps->dir_total;
|
||||
break;
|
||||
|
||||
case CMN_FS_INFO_OPENDIR_FAILED:
|
||||
printf( "WARNING: unable to open %s\n", path );
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void shell_ls( int argc, char **argv )
|
||||
{
|
||||
const DM_INSTANCE_DATA *pinst;
|
||||
unsigned i;
|
||||
int recursive = 0;
|
||||
char *pname = NULL;
|
||||
const char *crtname;
|
||||
SHELL_LS_STATE state;
|
||||
|
||||
for( i = 1; i < argc; i ++ )
|
||||
{
|
||||
if( !strcmp( argv[ i ], "-R" ) )
|
||||
recursive = 1;
|
||||
else if( argv[ i ][ 0 ] == '/' && !pname )
|
||||
pname = argv[ i ];
|
||||
else
|
||||
printf( "Warning: ignoring argument '%s' of ls\n", argv[ i ] );
|
||||
}
|
||||
// Iterate through all devices, looking for the ones that can do "opendir"
|
||||
// or the ones that match 'pname' (if that is specified)
|
||||
for( i = 0; i < dm_get_num_devices(); i ++ )
|
||||
{
|
||||
pinst = dm_get_instance_at( i );
|
||||
if( pinst->pdev->p_opendir_r == NULL || pinst->pdev->p_readdir_r == NULL || pinst->pdev->p_closedir_r == NULL )
|
||||
continue;
|
||||
if( pname && strncmp( pinst->name, pname, strlen( pinst->name ) ) )
|
||||
continue;
|
||||
crtname = pname ? pname : pinst->name;
|
||||
memset( &state, 0, sizeof( state ) );
|
||||
cmn_fs_walkdir( crtname, shellh_ls_walkdir_cb, &state, recursive );
|
||||
if( recursive && ( state.ndirs > 1 ) )
|
||||
printf( "Total on %s with all subdirectories: %u bytes\n\n", crtname, ( unsigned )state.total );
|
||||
}
|
||||
}
|
||||
|
||||
#else // #ifdef BUILD_ADVANCED_SHELL
|
||||
|
||||
const char shell_help_ls[] = "list files and directories";
|
||||
const char shell_help_summary_ls[] = "lists files and directories";
|
||||
|
||||
void shell_ls( int argc, char **argv )
|
||||
{
|
||||
const DM_INSTANCE_DATA *pinst;
|
||||
unsigned dev, i;
|
||||
DM_DIR *d;
|
||||
struct dm_dirent *ent;
|
||||
u32 total;
|
||||
|
||||
( void )argc;
|
||||
( void )argv;
|
||||
// Iterate through all devices, looking for the ones that can do "opendir"
|
||||
for( dev = 0; dev < dm_get_num_devices(); dev ++ )
|
||||
{
|
||||
pinst = dm_get_instance_at( dev );
|
||||
if( pinst->pdev->p_opendir_r == NULL || pinst->pdev->p_readdir_r == NULL || pinst->pdev->p_closedir_r == NULL )
|
||||
continue;
|
||||
d = dm_opendir( pinst->name );
|
||||
if( d )
|
||||
{
|
||||
total = 0;
|
||||
printf( "\n%s", pinst->name );
|
||||
while( ( ent = dm_readdir( d ) ) != NULL )
|
||||
{
|
||||
printf( "\n%s", ent->fname );
|
||||
for( i = strlen( ent->fname ); i <= DM_MAX_FNAME_LENGTH; i++ )
|
||||
printf( " " );
|
||||
if( ent->flags & DM_DIRENT_FLAG_DIR )
|
||||
printf( "<DIR>" );
|
||||
else
|
||||
{
|
||||
printf( "%u bytes", ( unsigned )ent->fsize );
|
||||
total = total + ent->fsize;
|
||||
}
|
||||
}
|
||||
printf( "\n\nTotal on %s: %u bytes\n", pinst->name, ( unsigned )total );
|
||||
dm_closedir( d );
|
||||
}
|
||||
}
|
||||
printf( "\n" );
|
||||
}
|
||||
|
||||
|
||||
#endif // #ifdef BUILD_ADVANCED_SHELL
|
||||
|
36
src/shell/shell_lua.c
Normal file
36
src/shell/shell_lua.c
Normal file
@ -0,0 +1,36 @@
|
||||
// Shell: 'lua' implementation
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "type.h"
|
||||
#include "platform_conf.h"
|
||||
|
||||
// EOF is different in UART mode and TCP/IP mode
|
||||
#ifdef BUILD_CON_GENERIC
|
||||
#define SHELL_EOF_STRING "CTRL+Z"
|
||||
#else
|
||||
#define SHELL_EOF_STRING "CTRL+D"
|
||||
#endif
|
||||
|
||||
const char shell_help_lua[] = "[-e <stat>] [-l <name>] [-i] [-v] [<script>]\n"
|
||||
" [<script>]: execute the given script.\n"
|
||||
" [-e <stat>]: execute string 'stat'.\n"
|
||||
" [-l <name>]: require library 'name'.\n"
|
||||
" [-i]: enter interactive mode after executing 'script'.\n"
|
||||
" [-v]: show version information.\n"
|
||||
"Without arguments it executes the interactive Lua interpreter.\n";
|
||||
const char shell_help_summary_lua[] = "start a Lua session";
|
||||
|
||||
void shell_lua( int argc, char **argv )
|
||||
{
|
||||
printf( "Press " SHELL_EOF_STRING " to exit Lua\n" );
|
||||
lua_main( argc, argv );
|
||||
clearerr( stdin );
|
||||
}
|
||||
|
29
src/shell/shell_mkdir.c
Normal file
29
src/shell/shell_mkdir.c
Normal file
@ -0,0 +1,29 @@
|
||||
// Shell: 'mkdir' implementation
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "type.h"
|
||||
#include "platform_conf.h"
|
||||
|
||||
const char shell_help_mkdir[] = "<path>\n"
|
||||
" <path>: the directory to create.\n";
|
||||
const char shell_help_summary_mkdir[] = "create directories";
|
||||
|
||||
void shell_mkdir( int argc, char **argv )
|
||||
{
|
||||
if( argc != 2 )
|
||||
{
|
||||
SHELL_SHOW_HELP( mkdir );
|
||||
return;
|
||||
}
|
||||
if( mkdir( argv[ 1 ], 0 ) != 0 )
|
||||
printf( "Error creating directory '%s'\n", argv[ 1 ] );
|
||||
printf( "Created directory '%s'.\n", argv[ 1 ] );
|
||||
}
|
||||
|
107
src/shell/shell_recv.c
Normal file
107
src/shell/shell_recv.c
Normal file
@ -0,0 +1,107 @@
|
||||
// Shell: 'recv' implementation
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "type.h"
|
||||
#include "platform_conf.h"
|
||||
#include "xmodem.h"
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#ifdef BUILD_XMODEM
|
||||
|
||||
const char shell_help_recv[] = "[<path>]\n"
|
||||
" [<path>] - the data received via XMODEM will be saved to this file.\n"
|
||||
"Without arguments it runs Lua to execute the data it receives.\n";
|
||||
const char shell_help_summary_recv[] = "receive files via XMODEM";
|
||||
|
||||
extern char *shell_prog;
|
||||
|
||||
void shell_recv( int argc, char **argv )
|
||||
{
|
||||
char *p;
|
||||
long actsize;
|
||||
lua_State* L;
|
||||
|
||||
if( argc > 2 )
|
||||
{
|
||||
SHELL_SHOW_HELP( recv );
|
||||
return;
|
||||
}
|
||||
|
||||
if( ( shell_prog = malloc( XMODEM_INITIAL_BUFFER_SIZE ) ) == NULL )
|
||||
{
|
||||
printf( "Unable to allocate memory\n" );
|
||||
return;
|
||||
}
|
||||
printf( "Waiting for file ... " );
|
||||
if( ( actsize = xmodem_receive( &shell_prog ) ) < 0 )
|
||||
{
|
||||
if( actsize == XMODEM_ERROR_OUTOFMEM )
|
||||
printf( "file too big\n" );
|
||||
else
|
||||
printf( "XMODEM error\n" );
|
||||
goto exit;
|
||||
}
|
||||
// Eliminate the XMODEM padding bytes
|
||||
p = shell_prog + actsize - 1;
|
||||
while( *p == '\x1A' )
|
||||
p --;
|
||||
p ++;
|
||||
printf( "done, got %u bytes\n", ( unsigned )( p - shell_prog ) );
|
||||
|
||||
// we've received an argument, try saving it to a file
|
||||
if( argc == 2 )
|
||||
{
|
||||
FILE *foutput = fopen( argv[ 1 ], "w" );
|
||||
size_t file_sz = p - shell_prog;
|
||||
if( foutput == NULL )
|
||||
{
|
||||
printf( "unable to open file %s\n", argv[ 1 ] );
|
||||
goto exit;
|
||||
}
|
||||
if( fwrite( shell_prog, sizeof( char ), file_sz, foutput ) == file_sz )
|
||||
printf( "received and saved as %s\n", argv[ 1 ] );
|
||||
else
|
||||
printf( "unable to save file %s (no space left on target?)\n", argv[ 1 ] );
|
||||
fclose( foutput );
|
||||
}
|
||||
else // no arg, running the file with lua.
|
||||
{
|
||||
if( ( L = lua_open() ) == NULL )
|
||||
{
|
||||
printf( "Unable to create Lua state\n" );
|
||||
goto exit;
|
||||
}
|
||||
luaL_openlibs( L );
|
||||
if( luaL_loadbuffer( L, shell_prog, p - shell_prog, "xmodem" ) != 0 )
|
||||
printf( "Error: %s\n", lua_tostring( L, -1 ) );
|
||||
else
|
||||
if( lua_pcall( L, 0, LUA_MULTRET, 0 ) != 0 )
|
||||
printf( "Error: %s\n", lua_tostring( L, -1 ) );
|
||||
lua_close( L );
|
||||
}
|
||||
exit:
|
||||
free( shell_prog );
|
||||
shell_prog = NULL;
|
||||
}
|
||||
|
||||
#else // #ifdef BUILD_XMODEM
|
||||
|
||||
const char shell_help_recv[] = "";
|
||||
const char shell_help_summary_recv[] = "";
|
||||
|
||||
void shell_recv( int argc, char **argv )
|
||||
{
|
||||
shellh_not_implemented_handler( argc, argv );
|
||||
}
|
||||
|
||||
#endif // #ifdef BUILD_XMODEM
|
||||
|
34
src/shell/shell_ver.c
Normal file
34
src/shell/shell_ver.c
Normal file
@ -0,0 +1,34 @@
|
||||
// Shell: 'ver' implementation
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "type.h"
|
||||
#include "platform_conf.h"
|
||||
|
||||
#if defined( USE_GIT_REVISION )
|
||||
#include "git_version.h"
|
||||
#else
|
||||
#include "version.h"
|
||||
#endif
|
||||
|
||||
const char shell_help_ver[] = "\n"
|
||||
"This displays the git revision of the tree used to build eLua or an official version number if applicable.\n";
|
||||
const char shell_help_summary_ver[] = "show version information";
|
||||
|
||||
void shell_ver( int argc, char **argv )
|
||||
{
|
||||
if( argc != 1 )
|
||||
{
|
||||
SHELL_SHOW_HELP( ver );
|
||||
return;
|
||||
}
|
||||
printf( "eLua version %s\n", ELUA_STR_VERSION );
|
||||
printf( "For more information visit www.eluaproject.net and wiki.eluaproject.net\n" );
|
||||
}
|
||||
|
52
src/shell/shell_wofmt.c
Normal file
52
src/shell/shell_wofmt.c
Normal file
@ -0,0 +1,52 @@
|
||||
// Shell: 'wofmt' implementation
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "type.h"
|
||||
#include "platform_conf.h"
|
||||
#include "romfs.h"
|
||||
|
||||
#ifdef BUILD_WOFS
|
||||
|
||||
const char shell_help_wofmt[] = "\n"
|
||||
"Formats the WOFS, initializing it to a blank state.\n";
|
||||
const char shell_help_summary_wofmt[] = "WOFS format";
|
||||
|
||||
void shell_wofmt( int argc, char **argv )
|
||||
{
|
||||
if( argc != 1 )
|
||||
{
|
||||
SHELL_SHOW_HELP( wofmt );
|
||||
return;
|
||||
}
|
||||
printf( "Formatting the internal WOFS will DESTROY ALL THE FILES FROM WOFS.\n" );
|
||||
if( shellh_ask_yes_no( "Are you sure you want to continue? [y/n] " ) == 0 )
|
||||
return;
|
||||
printf( "Formatting ..." );
|
||||
if( !wofs_format() )
|
||||
{
|
||||
printf( "\ni*** ERROR ***: unable to erase the internal flash. WOFS might be compromised.\n" );
|
||||
printf( "It is advised to re-flash the eLua image.\n" );
|
||||
}
|
||||
else
|
||||
printf( " done.\n" );
|
||||
}
|
||||
|
||||
#else // #ifdef BUILD_WOFS
|
||||
|
||||
const char shell_help_wofmt[] = "";
|
||||
const char shell_help_summary_wofmt[] = "";
|
||||
|
||||
void shell_wofmt( int argc, char **argv )
|
||||
{
|
||||
shellh_not_implemented_handler( argc, argv );
|
||||
}
|
||||
|
||||
#endif // #ifdef BUILD_WOFS
|
||||
|
@ -313,7 +313,7 @@ end
|
||||
-------------------------------------------------------------------------------
|
||||
-- Builder public interface
|
||||
|
||||
builder = { KEEP_DIR = 0, BUILD_DIR = 1, BUILD_DIR_LINEARIZED = 2 }
|
||||
builder = { KEEP_DIR = 0, BUILD_DIR_LINEARIZED = 1 }
|
||||
|
||||
---------------------------------------
|
||||
-- Initialization and option handling
|
||||
@ -336,6 +336,9 @@ builder.new = function( build_dir )
|
||||
self.runlist = {}
|
||||
self.disp_mode = 'all'
|
||||
self.cmdline_macros = {}
|
||||
self.c_targets = {}
|
||||
self.preprocess_mode = false
|
||||
self.asm_mode = false
|
||||
return self
|
||||
end
|
||||
|
||||
@ -365,7 +368,7 @@ builder.init = function( self, args )
|
||||
-- Add the default options
|
||||
local opts = self.opts
|
||||
opts:add_option( "build_mode", 'choose location of the object files', self.KEEP_DIR,
|
||||
{ keep_dir = self.KEEP_DIR, build_dir = self.BUILD_DIR, build_dir_linearized = self.BUILD_DIR_LINEARIZED } )
|
||||
{ keep_dir = self.KEEP_DIR, build_dir_linearized = self.BUILD_DIR_LINEARIZED } )
|
||||
opts:add_option( "build_dir", 'choose build directory', self.build_dir )
|
||||
opts:add_option( "disp_mode", 'set builder display mode', 'summary', { 'all', 'summary' } )
|
||||
-- Apply default values to all options
|
||||
@ -377,10 +380,14 @@ builder.init = function( self, args )
|
||||
for i = 1, #args do
|
||||
local a = args[ i ]
|
||||
if a:upper() == "-C" then -- clean option (-c)
|
||||
self.clean_mode = true
|
||||
self.clean_mode = true
|
||||
elseif a:upper() == '-H' then -- help option (-h)
|
||||
self:_show_help()
|
||||
os.exit( 1 )
|
||||
elseif a:upper() == "-E" then -- preprocess
|
||||
self.preprocess_mode = true
|
||||
elseif a:upper() == "-S" then -- generate assembler
|
||||
self.asm_mode = true
|
||||
elseif a:find( '-D' ) == 1 and #a > 2 then -- this is a macro definition that will be auomatically added to the compiler flags
|
||||
table.insert( self.cmdline_macros, a:sub( 3 ) )
|
||||
elseif a:find( '=' ) then -- builder argument (key=value)
|
||||
@ -420,6 +427,8 @@ builder._show_help = function( self )
|
||||
print( "[builder] Valid options:" )
|
||||
print( " -h: help (this text)" )
|
||||
print( " -c: clean target" )
|
||||
print( " -E: generate preprocessed output for single file targets" )
|
||||
print( " -S: generate assembler output for single file targets" )
|
||||
self.opts:show_help()
|
||||
end
|
||||
|
||||
@ -560,6 +569,13 @@ end
|
||||
-- Return a compile command based on the specified args
|
||||
builder.compile_cmd = function( self, args )
|
||||
args.defines = { args.defines, self.cmdline_macros }
|
||||
if self.preprocess_mode then
|
||||
args.comptype = "-E"
|
||||
elseif self.asm_mode then
|
||||
args.comptype = "-S"
|
||||
else
|
||||
args.comptype = "-c"
|
||||
end
|
||||
return self:_generic_cmd( args )
|
||||
end
|
||||
|
||||
@ -567,6 +583,7 @@ end
|
||||
builder.asm_cmd = function( self, args )
|
||||
args.defines = { args.defines, self.cmdline_macros }
|
||||
args.compiler = args.assembler
|
||||
args.comptype = self.preprocess_mode and "-E" or "-c"
|
||||
return self:_generic_cmd( args )
|
||||
end
|
||||
|
||||
@ -640,16 +657,11 @@ builder.obj_name = function( self, name, ext )
|
||||
end
|
||||
local objname = utils.replace_extension( name, r )
|
||||
-- KEEP_DIR: object file in the same directory as source file
|
||||
-- BUILD_DIR: object file in the build directory
|
||||
-- BUILD_DIR_LINEARIZED: object file in the build directory, linearized filename
|
||||
if self.build_mode == self.KEEP_DIR then
|
||||
return objname
|
||||
elseif self.build_mode == self.BUILD_DIR_LINEARIZED then
|
||||
return self.build_dir .. utils.dir_sep .. linearize_fname( objname )
|
||||
else
|
||||
local si, ei, path, fname = objname:find( "(.+)/(.-)$" )
|
||||
if not si then fname = objname end
|
||||
return self.build_dir .. utils.dir_sep .. fname
|
||||
end
|
||||
end
|
||||
|
||||
@ -676,6 +688,12 @@ end
|
||||
builder.create_compile_targets = function( self, ftable, res )
|
||||
if type( ftable ) == 'string' then ftable = utils.string_to_table( ftable ) end
|
||||
res = res or {}
|
||||
ccmd, oname = "-c", "o"
|
||||
if self.preprocess_mode then
|
||||
ccmd, oname = '-E', "pre"
|
||||
elseif self.asm_mode then
|
||||
ccmd, oname = '-S', 's'
|
||||
end
|
||||
-- Build dependencies for all targets
|
||||
for i = 1, #ftable do
|
||||
local isasm = ftable[ i ]:find( "%.c$" ) == nil
|
||||
@ -686,11 +704,11 @@ builder.create_compile_targets = function( self, ftable, res )
|
||||
local deps = self:get_dep_filename( ftable[ i ] )
|
||||
local target
|
||||
if not isasm then
|
||||
local depcmd = skip and self.comp_cmd or ( self.c_dep_cmd or self.comp_cmd:gsub( "-c ", sf( "-c -MD -MF %s ", deps ) ) )
|
||||
target = self:c_target( self:obj_name( ftable[ i ] ), { self:get_registered_target( deps ) or ftable[ i ] }, depcmd )
|
||||
local depcmd = skip and self.comp_cmd or ( self.c_dep_cmd or self.comp_cmd:gsub( ccmd .. " ", sf( ccmd .. " -MD -MF %s ", deps ) ) )
|
||||
target = self:c_target( self:obj_name( ftable[ i ], oname ), { self:get_registered_target( deps ) or ftable[ i ] }, depcmd )
|
||||
else
|
||||
local depcmd = skip and self._asm_cmd or ( self.asm_dep_cmd or self._asm_cmd:gsub( "-c ", sf( "-c -MD -MF %s ", deps ) ) )
|
||||
target = self:asm_target( self:obj_name( ftable[ i ] ), { self:get_registered_target( deps ) or ftable[ i ] }, depcmd )
|
||||
local depcmd = skip and self._asm_cmd or ( self.asm_dep_cmd or self._asm_cmd:gsub( ccmd .. " ", sf( ccmd .. " -MD -MF %s ", deps ) ) )
|
||||
target = self:asm_target( self:obj_name( ftable[ i ], oname ), { self:get_registered_target( deps ) or ftable[ i ] }, depcmd )
|
||||
end
|
||||
-- Pre build step: replace dependencies with the ones from the compiler generated dependency file
|
||||
if not skip then
|
||||
@ -706,6 +724,9 @@ builder.create_compile_targets = function( self, ftable, res )
|
||||
end
|
||||
end )
|
||||
end
|
||||
target.srcname = ftable[ i ]
|
||||
-- TODO: check clean mode?
|
||||
if not isasm then self.c_targets[ #self.c_targets + 1 ] = target end
|
||||
table.insert( res, target )
|
||||
end
|
||||
return res
|
||||
@ -734,18 +755,35 @@ builder.build = function( self, target )
|
||||
print( utils.col_red( "[builder] Error: build target not specified" ) )
|
||||
os.exit( 1 )
|
||||
end
|
||||
if not self.targets[ t ] then
|
||||
print( utils.col_red( sf( "[builder] Error: target '%s' not found", t ) ) )
|
||||
print( "Available targets: " )
|
||||
for k, v in pairs( self.targets ) do
|
||||
if not is_phony( k ) then
|
||||
print( sf( " %s - %s", k, v.help or "(no help available)" ) )
|
||||
local trg
|
||||
-- Look for single targets (C source files)
|
||||
for _, ct in pairs( self.c_targets ) do
|
||||
if ct.srcname == t then
|
||||
trg = ct
|
||||
break
|
||||
end
|
||||
end
|
||||
if not trg then
|
||||
if not self.targets[ t ] then
|
||||
print( sf( "[builder] Error: target '%s' not found", t ) )
|
||||
print( "Available targets: " )
|
||||
print( " all source files" )
|
||||
for k, v in pairs( self.targets ) do
|
||||
if not is_phony( k ) then
|
||||
print( sf( " %s - %s", k, v.help or "(no help available)" ) )
|
||||
end
|
||||
end
|
||||
if self.deftarget and not is_phony( self.deftarget ) then
|
||||
print( sf( "Default target is '%s'", self.deftarget ) )
|
||||
end
|
||||
os.exit( 1 )
|
||||
else
|
||||
if self.preprocess_mode or self.asm_mode then
|
||||
print( "[builder] Error: preprocess (-E) or asm (-S) works only with single file targets." )
|
||||
os.exit( 1 )
|
||||
end
|
||||
trg = self.targets[ t ].target
|
||||
end
|
||||
if self.deftarget and not is_phony( self.deftarget ) then
|
||||
print( sf( "Default target is '%s'", self.deftarget ) )
|
||||
end
|
||||
os.exit( 1 )
|
||||
end
|
||||
self:_create_build_dir()
|
||||
-- At this point check if we have a change in the state that would require a rebuild
|
||||
@ -756,7 +794,7 @@ builder.build = function( self, target )
|
||||
self.global_force_rebuild = false
|
||||
end
|
||||
-- Do the actual build
|
||||
local res = self.targets[ t ].target:build()
|
||||
local res = trg:build()
|
||||
if not res then print( utils.col_yellow( sf( '[builder] %s: up to date', t ) ) ) end
|
||||
if self.clean_mode then
|
||||
os.remove( self.build_dir .. utils.dir_sep .. ".builddata.comp" )
|
||||
|
@ -16,7 +16,8 @@ local boards =
|
||||
{ board = 'ATEVK1101', options = '' },
|
||||
'ET-STM32', 'EAGLE-100', 'ELUA-PUC', 'MBED',
|
||||
{ board = 'MIZAR32', options = "target=lualong" },
|
||||
{ board = 'PC', options = "" }
|
||||
{ board = 'PC', options = "" },
|
||||
'NETDUINO', 'EK-LM3S9D92', 'SOLDERCORE'
|
||||
}
|
||||
|
||||
local function docmd( cmd )
|
||||
|
Loading…
x
Reference in New Issue
Block a user