1
0
mirror of https://github.com/elua/elua.git synced 2025-01-08 20:56:17 +08:00

merged remotefs_int branch on trunk, not fully tested yet

This commit is contained in:
Bogdan Marinescu 2011-01-16 00:23:19 +00:00
parent 2bc5586ff9
commit 81e7f040fc
92 changed files with 5251 additions and 1538 deletions

View File

@ -415,7 +415,7 @@ if not GetOption( 'help' ):
# 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
src/salloc.c src/luarpc_elua_uart.c src/elua_int.c src/linenoise.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
newlib_files = " src/newlib/devman.c src/newlib/stubs.c src/newlib/genstd.c src/newlib/stdtcp.c"

View File

@ -1,5 +1,6 @@
require "lfs"
require "eluadoc"
require "md5"
-- Uncomment this when generating offline docs
local is_offline = true
@ -20,6 +21,7 @@ for k, v in ipairs( languages ) do
end
local sf = string.format
local cache_invalid = false
-------------------------------------------------------------------------------
-- Indexes into our menu table (defined in docdata.lua)
@ -170,6 +172,74 @@ local function copy_dir( src, dst )
copy_dir_rec( src, newdir )
end
-------------------------------------------------------------------------------
-- Cache helpers
local function read_md5( filename )
local fullname = string.format( "cache/%s.cache", filename )
local f = io.open( fullname, "rb" )
if not f then return "" end
local d = f:read( "*a" )
f:close()
return d
end
local function write_md5( filename, d )
local fullname = string.format( "cache/%s.cache", filename )
local f = io.open( fullname, "wb" )
if not f then return false end
f:write( d )
f:close()
return true
end
local function file_md5( filename )
local f = io.open( filename, "rb" )
if not f then return "" end
local d = f:read( "*a" )
f:close()
return md5.sumhexa( d )
end
-------------------------------------------------------------------------------
-- Table utils (from http://lua-users.org/wiki/TableUtils)
function table.val_to_str( v )
if "string" == type( v ) then
v = string.gsub( v, "\n", "\\n" )
if string.match( string.gsub(v,"[^'\"]",""), '^"+$' ) then
return "'" .. v .. "'"
end
return '"' .. string.gsub(v,'"', '\\"' ) .. '"'
else
return "table" == type( v ) and table.tostring( v ) or tostring( v )
end
end
function table.key_to_str ( k )
if "string" == type( k ) and string.match( k, "^[_%a][_%a%d]*$" ) then
return k
else
return "[" .. table.val_to_str( k ) .. "]"
end
end
function table.tostring( tbl )
local result, done = {}, {}
for k, v in ipairs( tbl ) do
table.insert( result, table.val_to_str( v ) )
done[ k ] = true
end
for k, v in pairs( tbl ) do
if not done[ k ] then
table.insert( result,
table.key_to_str( k ) .. "=" .. table.val_to_str( v ) )
end
end
return "{" .. table.concat( result, "," ) .. "}"
end
-------------------------------------------------------------------------------
-- Build the list of files that must be processed starting from the menu data
@ -374,6 +444,19 @@ local function gen_html_page( fname, lang )
end
local orig = f:read( "*a" )
f:close()
-- Check cache
local cfilename = string.format( "%s_%s", lang, fname )
local oldsum = read_md5( cfilename )
local crtsum = md5.sumhexa( orig )
if oldsum == crtsum then
if not cache_invalid then
return nil, "#cached#"
end
else
write_md5( cfilename, crtsum )
end
local asciimode = fullname:find( "%.txt" )
-- Check the presence of $$HEADER$$ and $$FOOTER$$
@ -489,13 +572,17 @@ local args = { ... }
local destdir = "dist"
local destdiridx = 1
if #args > 2 then
print "Usage: buildall.lua [destdir] [-online]"
print "Usage: buildall.lua [destdir] [-online] [-clean]"
print "Use -online to generate online documentation (includes BerliOS logo and counter)"
print "Use -clean to clear the cache and generate clean documentation"
return
end
local cleancache = false
for i = 1, #args do
if args[ i ] == "-online" then
is_offline = false
elseif args[ i ] == "-clean" then
cleancache = true
else
destdir = args[ i ]
end
@ -538,15 +625,42 @@ else
print( string.format( "%s is not a directory", destdir ) )
return
end
for k in lfs.dir( destdir ) do
if k ~= "." and k ~= ".." then
rm_dir_rec( destdir )
lfs.mkdir( destdir )
break
rm_dir_rec( destdir )
lfs.mkdir( destdir )
end
-- If the cache must be cleared, do it now
if cleancache then
local attr = lfs.attributes( 'cache' )
if attr then
if attr.mode ~= "directory" then
print( "'cache' is not a directory" )
return
end
rm_dir_rec( 'cache' )
lfs.mkdir( 'cache' )
end
end
-- Create the cache directory if it doesn't exist
local attr = lfs.attributes( 'cache' )
if not attr then
if not lfs.mkdir( 'cache' ) then
print( "Unable to create cache directory" )
return
end
end
-- Set the global "cache invalid" flag
-- It is set to 'true' if the content of docdata.lua changes
local crtdocsum = md5.sumhexa( table.tostring( themenu ) )
local oldsum = read_md5( "docdata" )
cache_invalid = crtdocsum ~= oldsum
if cache_invalid then
write_md5( "docdata", crtdocsum )
print "Cache invalidated"
end
print "\nProcessing HTML templates..."
indent_print()
flist = get_file_list()
@ -554,10 +668,13 @@ for _, lang in ipairs( languages ) do
for fname, entry in pairs( flist ) do
io.write( string.format( "Processing %s %s...", fname, entry.item[ name_idx ] and "" or "(hidden entry)" ) )
local res, err = gen_html_page( fname, lang )
if not res then
print( "***" .. err )
if err == "#cached#" then
-- This file is already in the cache
print( " (cached)" )
elseif not res then
print( "***" .. err )
else
local g = io.open( string.format( "%s/%s_%s", destdir, lang, fname ), "wb" )
local g = io.open( string.format( "cache/%s_%s", lang, fname ), "wb" )
if not g then
print( string.format( "Unable to open %s for writing", fname ) )
else
@ -565,6 +682,17 @@ for _, lang in ipairs( languages ) do
g:close()
end
end
-- Copy file from cache to destination directory
local srcf = io.open( string.format( "cache/%s_%s", lang, fname ), "rb" )
local destf = io.open( string.format( "%s/%s_%s", destdir, lang, fname ), "wb" )
if not srcf or not destf then
print "Unable to copy file from cache to dist"
return
end
local content = srcf:read( "*a" )
destf:write( content )
srcf:close()
destf:close()
end
end
regular_print()

View File

@ -106,6 +106,7 @@ local menu =
{ "Linenoise", "linenoise.html" },
{ "Cross-compiling", "using.html#cross" },
{ "LuaRPC", "using.html#rpc" },
{ "The serial multiplexer", "sermux.html" }
},
},
{ { "Code examples", "Exemplos de Código" }, "examples.html" },
@ -113,7 +114,8 @@ local menu =
{ "eLua file systems", "filesystems.html",
{
{ { "Read-Only FS in MCU Flash", "O ROM File System em Flash" }, "arch_romfs.html" },
{ "R/W FAT FS in SD/MMC Cards", "fatfs.html" }
{ "R/W FAT FS in SD/MMC Cards", "fatfs.html" },
{ "Remote file system (RFS)", "arch_rfs.html" }
}
},
{ "eLua interrupt handlers", "inthandlers.html",

View File

@ -40,7 +40,26 @@ enum
#define PLATFORM_UART_INFINITE_TIMEOUT (-1)]],
name = "UART timeout",
desc = "This constant is used as a special timeout value (infinite timeout) in the UART functions that expect a timeout as argument.",
}
},
{ text = [[// Virtual UART IDs
#define SERMUX_SERVICE_ID_FIRST 0xD0
#define SERMUX_SERVICE_ID_LAST 0xD7
]],
name = "Virtual UART IDs",
desc = "If @sermux.html@virtual UART@ support is enabled these constants define the IDs of the virtual UARTs in the system (defined in %inc/sermux.h%).",
},
{ text = [[// Flow control type
#define PLATFORM_UART_FLOW_NONE 0
#define PLATFORM_UART_FLOW_RTS 1
#define PLATFORM_UART_FLOW_CTS 2
]],
name = "Flow control type",
desc = "Used to set the flow control type on a serial interface. These constans can be ORed together ($PLATFORM_UART_FLOW_RTS | PLATFORM_UART_FLOW_CTS$)",
},
},
-- Functions
@ -69,7 +88,19 @@ enum
},
{ sig = "void #platform_uart_send#( unsigned id, u8 data );",
desc = "Send data to an UART interface.",
desc = [[Send data to an UART interface. This is a blocking operation (it doesn't return until the data was sent).<br>
This function is "split" in two parts: a platform-independent part that is implemented in %src/common.c% and a platform-dependent part that must be implemented
by each platform in a function named @#platform_s_uart_send@platform_s_uart_send@.]],
args =
{
"$id$ - UART interface ID.",
"$data$ - data to be sent.",
},
},
{ sig = "void #platform_s_uart_send#( unsigned id, u8 data );",
desc = [[This is the platform-dependent part of @#platform_uart_send@platform_uart_send@. It doesn't need to take care of @sermux.html@virtual UARTs@ or other system
configuration parameters, it just needs to instruct the CPU to send the data on the specified ID. This function will always be called with a physical uart ID.]],
args =
{
"$id$ - UART interface ID.",
@ -80,7 +111,7 @@ enum
{ sig = "int #platform_uart_recv#( unsigned id, unsigned timer_id, s32 timeout );",
link = "platform_uart_recv",
desc = [[Receive data from the UART interface (blocking/non blocking with timeout/immediate).<br>
This function is "split" in two parts: a platform-independent part that is implemented in %src/common.c%, and a platform-dependent part that must be implemented by each
This function is "split" in two parts: a platform-independent part that is implemented in %src/common.c% and a platform-dependent part that must be implemented by each
platform in a function named @#platform_s_uart_recv@platform_s_uart_recv@.]],
args =
{
@ -104,7 +135,7 @@ enum
{ sig = "int #platform_s_uart_recv#( unsigned id, s32 timeout );",
link = "platform_s_uart_recv",
desc = [[This is the platform-dependent part of the UART receive function @#platform_uart_recv@platform_uart_recv@, and is in fact a "subset" of the full function
desc = [[This is the platform-dependent part of the UART receive function @#platform_uart_recv@platform_uart_recv@ and is in fact a "subset" of the full function
(thus being easier to implement by each platform in part). In particular, it never needs to deal with the $timeout &gt; 0$ case, which is handled by @#platform_uart_recv@platform_uart_recv@.]],
args =
{
@ -120,131 +151,43 @@ enum
"if $timeout = 0$ and data from the UART is available when the function is called it is returned, otherwise -1 is returned",
"if $timeout$ = @#uart_timeout@PLATFORM_UART_INIFINITE_TIMEOUT@ it returns the data read from the UART after it becomes available"
}
}
}
}
data_pt =
{
-- Title
title = "eLua platform interface - UART",
-- Menu name
menu_name = "UART",
-- Overview
overview = "This part of the platform interface groups functions related to the UART interface(s) of the MCU.",
-- Data structures, constants and types
structures =
{
{ text = [[// Parity
enum
{
PLATFORM_UART_PARITY_EVEN,
PLATFORM_UART_PARITY_ODD,
PLATFORM_UART_PARITY_NONE
};]],
name = "UART parity",
desc = "Constants used to specify the UART parity mode."
},
{ text = [[// Stop bits
enum
{
PLATFORM_UART_STOPBITS_1,
PLATFORM_UART_STOPBITS_1_5,
PLATFORM_UART_STOPBITS_2
};]],
name = "UART stop bits",
desc = "Constants used to specify the number of UART stop bits.",
},
{ text = [[// "Infinite timeout" constant for recv
#define PLATFORM_UART_INFINITE_TIMEOUT (-1)]],
name = "UART timeout",
desc = "This constant is used as a special timeout value (infinite timeout) in the UART functions that expect a timeout as argument.",
}
},
-- Functions
funcs =
{
{ sig = "int #platform_uart_exists#( unsigned id );",
desc = [[Checks if the platform has the hardware UART specified as argument. Implemented in %src/common.c%, it uses the $NUM_UART$ macro that must be defined in the
platform's $platform_conf.h$ file (see @arch_overview.html#platforms@here@ for details). For example:</p>
~#define NUM_UART 2 $// The platform has 2 UART interfaces$~<p>]],
args = "$id$ - UART interface ID",
ret = "1 if the specified UART exists, 0 otherwise"
},
{ sig = "u32 #platform_uart_setup#( unsigned id, u32 baud, int databits, int parity, int stopbits );",
desc = "This function is used to initialize the parameters of the UART interface.",
args =
{
"$id$ - UART interface ID.",
"$baud$ - baud rate.",
"$databits$ - number of databits (maximum 8).",
"$parity$ - parity type (can be either $PLATFORM_UART_PARITY_EVEN$, $PLATFORM_UART_PARITY_ODD$ or $PLATFORM_UART_PARITY_NONE$, see @#uart_parity@here@).",
[[$stopbits$ - number of stop bits (can be either $PLATFORM_UART_STOPBITS_1$, $PLATFORM_UART_STOPBITS_1_5$ or $PLATFORM_UART_STOPBITS_2$, see
@#uart_stop_bits@here@).]],
},
ret = "the actual baud rate. Depending on the hardware, this may have a different value than the $baud$ argument.",
},
{ sig = "void #platform_uart_send#( unsigned id, u8 data );",
desc = "Send data to an UART interface.",
args =
{
"$id$ - UART interface ID.",
"$data$ - data to be sent.",
},
},
{ sig = "int #platform_uart_recv#( unsigned id, unsigned timer_id, s32 timeout );",
link = "platform_uart_recv",
desc = [[Receive data from the UART interface (blocking/non blocking with timeout/immediate).<br>
This function is "split" in two parts: a platform-independent part that is implemented in %src/common.c%, and a platform-dependent part that must be implemented by each
platform in a function named @#platform_s_uart_recv@platform_s_uart_recv@.]],
args =
{
"$id$ - UART interface ID.",
"$timer_id$ - the ID of the timer used in this operation (see @arch_platform_timers.html@here@ for details). See also the description of the $timeout$ argument.",
[[$timeout$ - specifies a timeout for the receive operation as follows:
<ul>
<li>$timeout > 0$: the timer with the specified $timer_id$ will be used to timeout the receive operation after $timeout$ microseconds.</li>
<li>$timeout = 0$: the function returns immediately regardless of data being available or not. $timer_id$ is ignored.</li>
<li>$timeout$ = @#uart_timeout@PLATFORM_UART_INFINITE_TIMEOUT@: the function waits indefinitely for UART data to be available and returns it. In this mode the function doesn't
time out, so $timer_id$ is ignored.</li>
</ul>]],
},
ret =
{
"if $timeout > 0$ and data from the UART is available in $timeout$ microseconds of less it is returned, otherwise -1 is returned",
"if $timeout = 0$ and data from the UART is available when the function is called it is returned, otherwise -1 is returned",
"if $timeout$ = @#uart_timeout@PLATFORM_UART_INIFINITE_TIMEOUT@ it returns the data read from the UART after it becomes available"
}
},
{ sig = "int #platform_s_uart_recv#( unsigned id, s32 timeout );",
link = "platform_s_uart_recv",
desc = [[This is the platform-dependent part of the UART receive function @#platform_uart_recv@platform_uart_recv@, and is in fact a "subset" of the full function
(thus being easier to implement by each platform in part). In particular, it never needs to deal with the $timeout &gt; 0$ case, which is handled by @#platform_uart_recv@platform_uart_recv@.]],
args =
{
"$id$ - UART interface ID.",
[[$timeout$ - specifies a timeout for the receive operation as follows:
<ul>
<li>$timeout = 0$: the function returns immediately regardless of data being available or not.</li>
<li>$timeout$ = @#uart_timeout@PLATFORM_UART_INFINITE_TIMEOUT@: the function waits indefinitely for UART data to be available and returns it.</li>
</ul>]],
},
ret =
{
"if $timeout = 0$ and data from the UART is available when the function is called it is returned, otherwise -1 is returned",
"if $timeout$ = @#uart_timeout@PLATFORM_UART_INIFINITE_TIMEOUT@ it returns the data read from the UART after it becomes available"
}
}
},
{ sig = "int #platform_uart_set_buffer#( unsigned id, unsigned log2size );",
desc = "Sets the buffer for the specified UART. This function is fully implemented in %src/common.c%.",
args =
{
"$id$ - UART interface ID.",
"$data$ - the base 2 logarithm of the buffer size or 0 to disable buffering on the UART. Note that disabling buffering on a virtual UART is an invalid operation."
},
ret = "$PLATFORM_OK$ if the operation succeeded, $PLATFORM_ERR$ otherwise."
},
{ sig = "int #platform_uart_set_flow_control#( unsigned id, int type );",
desc = [[Sets the flow control type.<br>
This function is "split" in two parts: a platform independent part that is implemented in %src/common.c% and a platform-dependent part that must be implemented by each
platform in a function named @#platform_s_uart_set_flow_control@platform_s_uart_set_flow_control@.]],
args =
{
"$id$ - UART interface ID.",
[[$type$ - the desired flow control. It can be either $PLATFORM_UART_FLOW_NONE$, $PLATFORM_UART_FLOW_RTS$ or $PLATFORM_UART_FLOW_CTS$ or a bitwise combination of these constants
(see @#flow_control_type@here@ for details).]]
},
ret = "$PLATFORM_OK$ if the operation succeeded, $PLATFORM_ERR$ otherwise."
},
{ sig = "int #platform_s_uart_set_flow_control#( unsigned id, int type );",
desc = [[This is the platform-dependent part of the UART set flow control function @#platform_uart_set_flow_control@platform_uart_set_flow_control@ and is in fact a "subset" of the
full function (thus being easier to implement by each platform in part). In particular, it never needs to deal with virtual UARTs.]],
args =
{
"$id$ - UART interface ID.",
[[$type$ - the desired flow control. It can be either $PLATFORM_UART_FLOW_NONE$, $PLATFORM_UART_FLOW_RTS$ or $PLATFORM_UART_FLOW_CTS$ or a bitwise combination of these constants
(see @#flow_control_type@here@ for details).]]
},
ret = "$PLATFORM_OK$ if the operation succeeded, $PLATFORM_ERR$ otherwise."
},
}
}

View File

@ -12,11 +12,24 @@ data_en =
-- Overview
overview = [[This module contains functions for accessing the serial ports (UARTs) of the eLua CPU.]],
-- Data structures, constants and types
structures =
{
{ text = [[uart.VUART0
uart.VUART1
.............
uart.VUART7]],
name = "UART constants",
desc = [[If @sermux.html@virtual UART@ support is enabled in eLua these constants are automatically defined
to the IDs of the virtual UARTs in the system.]]
}
},
-- Functions
funcs =
{
{ sig = "baud = #uart.setup#( id, baud, databits, parity, stopbits )",
desc = "Setup the serial port",
desc = "Setup the serial port. Note that you can't call this function for a @sermux.html@virtual UART@.",
args =
{
"$id$ - the ID of the serial port",
@ -72,8 +85,26 @@ blocking operation, or a positive number that specifies the inter-char timeout i
$timeout$ is neither $uart.NO_TIMEOUT$, nor $uart.INF_TIMEOUT$).]]
},
ret = [[The data read from the serial port as a string (or as a number if $format$ is $'*n'$). If a timeout occures, only the data read before the timeout is returned. If the function times out while trying to read the first character, the empty string is returned]]
},
{ sig = "#uart.set_buffer#( id, bufsize )",
desc = "Sets the size of the UART buffer. Note that calling this function with bufsize = 0 for a @sermux.html@virtual UART@ is not allowed.",
args =
{
"$id$ - the ID of the serial port",
"$bufsize$ - the size of the buffer (must be a power of 2) or 0 to disable buffering on the specified UART."
},
},
{ sig = "#uart.set_flow_control#( id, type )",
desc = "Sets the flow control on the UART. Note that this function works only on physical ports, it will return an error if called on a virtual UART.",
args =
{
"$id$ - the ID of the serial port.",
[[$type$ - the flow control type, it can be either $uart.FLOW_NONE$ (no flow control), $uart.FLOW_RTS$ for RTS flow control, $uart.FLOW_CTS$ for CTS flow control or
$uart.FLOW_RTS + uart.FLOW_CTS$ for full RTS/CTS flow control.]]
}
}
},
}

View File

@ -67,6 +67,43 @@ const elua_int_descriptor elua_int_table[ INT_ELUA_LAST ] =
_platform_int.c_ should implement a function named *platform_int_init* (defined in _inc/platform.h_) that must initialize all the required hardware and the internal data structures of
the interrupt subsystem. This function should be called from *platform_init*.
5. *Implement the interrupt handlers*
+
There are two simple requirements for the interrupt handlers: clear the hardware interrupt flag (if needed) and call *cmn_int_handler* (_src/common.c_) to connect the handler with the
eLua interrupt code. An example is given below:
+
[subs="quotes"]
-------------------------------
// EINT3 (INT_GPIO) interrupt handler
static void int_handler_eint3()
{
elua_int_id id = ELUA_INT_INVALID_INTERRUPT;
pio_code resnum = 0;
int pidx, pin;
EXTINT |= 1 << EINT3_BIT; // clear interrupt
// Look for interrupt source
// In can only be GPIO0/GPIO2, as the EXT interrupts are not (yet) used
pidx = ( IO_INT_STAT & 1 ) ? 0 : 1;
if( *posedge_status[ pidx ] )
{
id = INT_GPIO_POSEDGE;
pin = intlog2( *posedge_status[ pidx ] );
}
else
{
id = INT_GPIO_NEGEDGE;
pin = intlog2( *negedge_status[ pidx ] );
}
resnum = PLATFORM_IO_ENCODE( pidx * 2, pin, PLATFORM_IO_ENC_PIN );
[bblue]** *intclr_regs[ pidx ] = 1 << pin**;
// Run the interrupt through eLua
[bblue]**cmn_int_handler( id, resnum )**;
VICVectAddr = 0; // ACK interrupt
}
-------------------------------
That's it. If you followed all these steps correctly, your platform should be fully able to support interrupt handlers (as described link:inthandlers.html[here]). Check the *lpc24xx*
platform implementation (_src/platform/lpc24xx_) for a full example.
@ -93,7 +130,8 @@ The table below lists all the valid interrupt names currently known to eLua. If
^| Name ^| Meaning
| INT_GPIO_POSEDGE | Interrupt on a positive edge on a GPIO pin
| INT_GPIO_NEGEDGE | Interrupt on a negative edge on a GPIO pin
| INT_TMR_MATCH | Interrupt on timer match
| INT_TMR_MATCH | Interrupt on timer match
| INT_UART_RX | Interrupt on UART character received
|===================================================================
// $$FOOTER$$

123
doc/en/arch_rfs.txt Normal file
View File

@ -0,0 +1,123 @@
// $$HEADER$$
eLua remote file system
-----------------------
*(v0.8 and above)* The RFS (Remote File System) is a file system that allows the
user to "share" a directory on a PC with eLua over a serial connection. eLua will be able to access files
on the shared PC directory just as they were local files; they can be opened,
read, written, closed and so on. Developing in eLua becomes much easier with this
file system: one can simply edit the source file on the desktop machine, using
his favourite text editor, and run the file on the eLua board using *lua /rfs/<file>.lua*.
The file can also be copied to (or from) the link:fatfs.html[SD/MMC file system] using the
*cp* command in the link:using.html#shell[eLua shell].
Enabling RFS in eLua
~~~~~~~~~~~~~~~~~~~~
This is the easy part, just follow the instruction in the link:building.html[building page].
You need to define the following macros for RFS:
[width="90%", cols="<2s,<5", options="header"]
|===================================================================
^| Option ^| Meaning
| BUILD_RFS | Enable RFS support in eLua
| RFS_BUFFER_SIZE | Size of the RFS buffer. Needs to be one of the *BUF_SIZE_xxx* constants defined in _inc/buf.h_
| RFS_UART_ID | The ID of the UART that will be used by RFS. This is the physical connection over which the PC directory will be shared.
| RFS_UART_SPEED | Communication speed of the RFS UART interface.
| RFS_TIMER_ID | The ID of a timer that will be used by RFS for internal operations
| RFS_FLOW_TYPE | Flow control type on the serial RFS interface, see link:arch_platform_uart.html#flow_control_type[here] for details.
If not specified it defaults to \'no flow control'.
| RFS_TIMEOUT | RFS operations timeout (in microseconds). If during a RFS operation no data is received from the PC side for the
specified timeout, the RFS operation terminates with error.
|===================================================================
RFS server on the PC side
~~~~~~~~~~~~~~~~~~~~~~~~~
RFS needs a program running on the PC side, the *RFS server*. This is the program
that implements the actual directory sharing (eLua connects to this program via
the *RFS_UART_ID* UART). The RFS server was succesfully built and tested under
Windows 7 (32 bit) and Linux (Ubuntu 10.10 64 bit). To build it you need:
- a build environment. This means gcc under Linux (see for example link:tc_arm.html[here] for instruction on how to install a toolchain in
Ubuntu Linux) and a gcc-based development environment under Windows. How to install a gcc-based development environment under Windows is
beyond the scope of this tutorial, but check http://www.mingw.org/[here] and http://tdm-gcc.tdragon.net/[here] for possible solution
(RFS server was compiled and tested under Win32 using the second soluation, the tdm gcc compiler).
- scons. See link:building_win.html[here] for details on how to install scons on Windows, or link:building_unix.html[here] for details on how
to install scons on Linux.
If the above requirements are met, building the RFS server is a simple matter of invoking this command from the eLua source tree base directory:
----------------------
scons -f rfs_server.py
----------------------
After this you should end up with a *rfs_server.exe* file in Windows or a *rfs_server* file in Linux. Running it without arguments prints
the usage help:
----------------------------------------------
Usage: rfs_server <transport> <dirname> [-v]
Serial transport: 'ser:<sername>,<serspeed>,<flow> ('flow' defines the flow control and can be either 'none' or 'rtscts')
UDP transport: 'udp:<port>'
Use -v for verbose output.
----------------------------------------------
Note that currently the UDP transport is only implemented in the RFS server, not in eLua, so you can only use the serial transport. +
*<dirname>* is the name of the directory that will be shared with eLua. In Win32, a proper server invocation can look like this:
-------------------------------------
rfs_server ser:com5,115200 c:\elua\fs
-------------------------------------
This shares the *c:\elua\fs* directory on COM5 at baud 115200 (note that the baud must match the *RFS_UART_SPEED* configuration macro). +
In Linux:
-----------------------------------------------------------
./rfs_server ser:/dev/ttyUSB0,115200,rtscts /home/user/work/fs
-----------------------------------------------------------
This shares the */home/user/work/fs* directory on port /dev/ttyUSB0 at baud 115200. +
Once the RFS server is in place, you can use it from eLua just like you'd use any other file system. For the previous example, if you have a file
named */home/user/work/fs/test.lua* and you want to run in eLua, you just need to do this from the eLua shell:
-----------------------
elua# lua /rfs/test.lua
-----------------------
Notes
~~~~~
Some things you should consider when using the RFS:
- the code is still in beta. It works well most of the time, but sometimes it simply crashes. If this happens, please consider submitting a bug report.
- using hardware flow control is strongly encouraged. To do this:
1. make sure that your eLua board has support for hardware flow control (see link:refman_gen_uart.html#platform_uart_set_flow_control[here] for details).
2. specify the correct *RFS_FLOW_TYPE* value at build time (it should be *PLATFORM_UART_FLOW_RTS | PLATFORM_UART_FLOW_CTS*).
3. make sure that the serial cable connecting the PC and the eLua board also supports flow control. Some simple serial connection cables have only the RX, TX and GND wires.
RTS/CTS flow control requires at least RX, TX, RTS, CTS and GND wires arranged in a null-modem configuration.
4. start *rfs_server* specifying _rtscts_ as part of the _<transport>_ parameter (see above).
- eLua has a global filename size limit of 30 characters, so don't put files with longer names in the shared directory, it might lead to unexpec ted
behaviour.
- the file sharing "protocol" is an extremely simple one, it doesn't make provisions for error correction and has only very basic error detection.
So, if there are serial communication problems on the connection used by RFS, you might encounter RFS errors (timeouts, invalid operations and so on).
If the errors persist, simply restart *rfs_server* and reset the eLua board.
- try not to share directories on devices that might go to sleep unexpectedly, such as an USB HDD attached to the PC, or a network storage device
with a HDD that might also go to sleep. If you try to make an operation on such a shared directory and the device is asleep, it will take a while
until it wakes up and during this time RFS will most likely time out (see *RFS_TIMEOUT* macro above). This, in turn, might confuse RFS completely and
give strange errors, like being unable to list the contents of the directory on the eLua board. If this happens, restart *rfs_server*, reset the
eLua board and try again.
- for reasons similar to the above, if you're running your server on a
hosted virtual machine (ex: Virtualbox, VMWare, ...), make sure the VM
host has a steady clock and does not keep entering and leaving some
energy-saving mode that changes the clock speed. If you work on this
configuration (usually on laptops), just go to your energy-savings
preferences and chose one that will not change the clock during the serial
transfers. This is not mandatory for all scenarios. Just keep this in mind
if you have some issues and change it only if needed.
- the larger *RFS_BUFFER_SIZE* is, the better the performance, but obviously RAM consumption also increases.
- some serial ports built around USB to RS232 adapters seem to confuse *rfs_server* sometimes. If RFS won't work after you tried all the above
instructions, or if *rfs_server* terminates unexpectedly, unplugging and plugging the USB cable of the RS232 adapter and restarting *rfs_server*
will most likely solve your problem.
- if you find a bug in the RFS server and wish to report it, try to reproduce the problem again, but this time run *rfs_server* with *-v* (verbose).
The resulting logs may help us identify the problem.
If you like the RFS, but dislike the idea of having to connect your eLua board to the PC with two serial connections (one for the console and another
one for the RFS) check link:sermux.html[here] for a possible solution to this.
// $$FOOTER$$

View File

@ -3,8 +3,9 @@ $$HEADER$$
<p>You can compile and use more than one file system in <b>eLua</b>, as listed below:</p>
<ul>
<li><b>the ROM file system</b>: a very simple, very low footprint read-only file system that can be included in the <b>eLua</b> binary image. Check <a href="arch_romfs.html">here</a> for details.</li>
<li><b>the FAT file system</b>: a read-write FAT filesystem implementation (platform independent) that can currently be used with SD/MMC memory cards. Check <a href="fatfs.html">here</a> for
<li><b>the FAT file system</b>: a read-write FAT file system implementation (platform independent) that can currently be used with SD/MMC memory cards. Check <a href="fatfs.html">here</a> for
details. <b>(new in 0.7)</b></li>
<li><b>the remote file system (RFS)</b>: a read-write file system that allows eLua to 'share' a directory on a PC, effectively accesing
its contents as if it was a local file system. Check <a href="arch_rfs.html">here</a> for details. <b>(new in 0.8)</b></li>
</ul>
$$FOOTER$$

283
doc/en/sermux.txt Normal file
View File

@ -0,0 +1,283 @@
// $$HEADER$$
The eLua serial multiplexer
---------------------------
*(v0.8 and above)* The *serial multiplexer* is an optional eLua component that allows
using several serial ports over a single physical serial link connection. It can be a
very convenient feature, since some eLua components (such as link:using.html#rpc[the RPC mechanism]
or link:arfs_rfs.html[the remote file system]) need a serial link to the PC and
it's very incovenient (or even impossible sometimes) to connect the eLua board
to the PC with 2 or more serial cables. A common use scenario for the serial
multiplexer is to have the eLua shell and RFS running over a single physical
connection to the PC, a very convenient method that will probably appeal to most
eLua users.
How does it work?
~~~~~~~~~~~~~~~~~
On the eLua side a number of virtual serial ports are defined. The eLua code
can use these ports just like they would use a physical port, simply by specifing
a virtual port ID instead of a physical port ID. On the PC side, two things are
needed:
- a program that can (de)multiplex UART requests from the eLua board. It is called
*mux* and it is part of the standard eLua distribution.
- a mechanism for creating and using "virtual serial ports" on the PC itself. These
are actually pairs of virtual UARTs that are connected internally (inside
the OS) via a null-modem cable mechanism, which means that when you type something
on one port you can see its output on its pair (and the other way around).
See below for details on how to use virtual serial ports in Linux and Windows.
Virtual serial ports in Linux
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Linux already supports the virtual serial port mechanism described above via the
standard UNIX pseudo terminals, see http://en.wikipedia.org/wiki/Pseudo_terminal[here]
for details. Note that the multiplexer supports only BSD PTYs (*dev/ttypx*) and not
Unix98 PTYs (*/dev/ptmx*). They are quite standard (although they are becoming
obsolete in some Linux distributions) so you shouldn't have any problems with them.
A quick check for BSD PTYs is to look in your */dev* directory for *ttypx* and *ptypx* files.
If they aren't there, you need to enable support for BSD PTYs in your system. How to
do this is OS dependent and beyond the scope of this tutorial, so google is your friend.
For an example on how to enable them in Ubuntu check
http://ubuntuforums.org/showthread.php?t=1147994[this link].
Once they are enabled you can get a quick feel of how their work. */dev/ttypx* and */dev/ptypx*
are paired by default, so any transmit/receive at one end is mirrored at the other end.
A simple experiment:
- start two shell sessions
- execute *screen /dev/ttyp0 115200* in one of the shells
- execute *screen /dev/ptyp0 115200* in the other shell
Now everything you type in one of the shell sessions should be visible in the other one.
Virtual serial ports in Windows
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Windows doesn't have out-of-the-box support for virtual serial ports, but
fortunately there's an extremely nice open source program that does exactly
what eLua needs. It is called http://com0com.sourceforge.net/[com0com]. Download it,
install it, then open the com0com serial port manager to create your virtual
serial port pairs. Then give it a little spin to get used to how it works. Supposing
that you created COM10 and COM11 as a virtual serial port pair, try this:
- start your terminal emulator program. My preffered terminal emulator program in
Windows is http://www.ayera.com/teraterm/[TeraTerm], but you can use any emulator
you want. Open COM10 at baud 115200.
- start another instance of the terminal emulator, but this time open COM11 at baud 115200.
Now everything you type in one of the terminal emulators should be visible in the other one.
NOTE: com0com can create pairs of serial ports with unusual names, for example *CNCA1* and *CNCB1*.
While they work fine with eLua's serial multiplexer, they might not work equally well with terminal
emulator programs, so you're advised to stick with standard port names (*COMx*).
Enabling the serial multiplexer in Lua
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This is the easy part, just follow the instruction in the link:building.html[building page].
You need to define the following macros for the serial multiplexer:
[width="90%", cols="<2s,<5", options="header"]
|===================================================================
^| Option ^| Meaning
| BUILD_SERMUX | Enable serial multiplexer support in eLua.
| SERMUX_PHYS_ID | The ID of the physical UART interface used by the serial multiplexer.
| SERMUX_PHYS_SPEED | Communication speed of the multiplexer UART interface.
| SERMUX_FLOW_TYPE | Flow control type on the physical serial multiplexer interface, see link:arch_platform_uart.html#flow_control_type[here] for details.
If not specified it defaults to \'no flow control'.
| SERMUX_NUM_VUART | The number of virtual UART interfaces. This number can't be higher than 8.
| SERMUX_BUFFER_SIZES | An array of *SERMUX_NUM_VUART* integers that specify the buffer sizes for the virtual
UART interfaces. Note that a virtual UART *MUST* have a buffer associated with it. The sizes are specified as
*BUF_SIZE_xxx* constants defined in _inc/buf.h_
|===================================================================
As a simple example, let's change the configuration of an eLua board that uses UART 0
as its console UART to use a serial multiplexer with 2 ports (one for RFS and the other
one for console) over UART 0. The original configuration (in _src/platform/<platform>/platform_conf.h_)
will look like this:
------------------------------------
#define CON_UART_ID 0
#define CON_UART_SPEED 115200
------------------------------------
The new configuration should be similar to the one below:
[subs="quotes"]
------------------------------------
#include "sermux.h" [bblue]**// for virtual uart IDs**
#include "buf.h" [bblue]**// for buffer sizes**
#define BUILD_SERMUX [bblue]**// enable serial multiplexer support**
#define CON_UART_ID ( SERMUX_SERVICE_ID_FIRST + 1 ) [bblue]**// console runs on the second virtual UART**
#define CON_BUF_SIZE BUF_SIZE_128 [bblue]**// size of console UART buffer, cannot be 0**
#define RFS_UART_ID ( SERMUX_SERVICE_ID_FIRST ) [bblue]**// RFS runs on the first virtual UART**
#define RFS_BUFFER_SIZE BUF_SIZE_512 [bblue]**// size of the RFS UART buffer, cannot be 0**
// Serial multiplexer data
#define SERMUX_PHYS_ID 0 [bblue]**// multiplexer runs on UART 0**
#define SERMUX_PHYS_SPEED 115200 [bblue]**// multiplexer runs at 115200 baud**
#define SERMUX_NUM_VUART 2 [bblue]**// multiplexer creates 2 virtual UARTs**
#define SERMUX_BUFFER_SIZES { RFS_BUFFER_SIZE, CON_BUF_SIZE } [bblue]**// buffer sizes for the virtual UARTs**
------------------------------------
This sequence of macro definitions will enable serial multiplexer support in eLua and will allow the
code to use two *virtual UARTs*. The virtual UART IDs start at *SERMUX_SERVICE_ID_FIRST*. A maximum
of 8 virtual UARTs are supported by the system. In this particular example the first virtual UART
is assigned to RFS and the second one to the system console.
IMPORTANT: when using the RFS in a virtual UART configuration, remember that *RFS_UART_ID must be the
first virtual UART ID in the system (SERMUX_SERVICE_ID_FIRST)*. Otherwise, the serial multiplexer will
NOT work properly in *rfsmux* mode. Check xref:rfsmux[here] for details, and link:arch_rfs.html[here]
for more details about the RFS.
Serial multiplexer on the PC side
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The serial multiplexer needs a program running on the PC side, the *mux server*. This is
the program that implements the actual serial port multiplexing (eLua connects to this program via
the *SERMUX_PHYS_ID* UART). The mux server was succesfully built and tested under
Windows 7 (32 bit) and Linux (Ubuntu 64 bit). To build it you need:
- a build environment. This means gcc under Linux (see for example link:tc_arm.html[here] for instruction on how to install a toolchain in
Ubuntu Linux) and a gcc-based development environment under Windows. How to install a gcc-based development environment under Windows is
beyond the scope of this tutorial, but check http://www.mingw.org/[here] and http://tdm-gcc.tdragon.net/[here] for possible solution
(the mux server was compiled and tested under Win32 using the second soluation, the tdm gcc compiler).
- scons. See link:building_win.html[here] for details on how to install scons on Windows, or link:building_unix.html[here] for details on how
to install scons on Linux.
If the above requirements are met, building the mux server is a simple matter of invoking this command from the eLua source tree base directory:
---------------
scons -f mux.py
---------------
After this you should end up with a *mux.exe* file in Windows, or a *mux* file in Linux. Running it without arguments prints
the usage help:
---------------
Usage: mux <mode> <transport> <vcom1> [<vcom2>] ... [<vcomn>] [-v]
mode:
'mux': serial multiplexer mode
'rfsmux:<directory>: combined RFS and multiplexer mode.
transport: '<port>,<baud>,<flow> ('flow' specifies the flow control type and can be 'none' or 'rtscts').
vcom1, ..., vcomn: multiplexer serial ports. Use '-v' for verbose output.
---------------
Using the multiplexer in "mux" mode
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is the basic use scenario for the serial multiplexer. Im this mode *mux* will
simply multiplex the serial connection with the eLua board with a number of virtual
serial ports in the system.
This is best understood by an example. We'll ask *mux*
to multiplex two serial ports for us, these will be *dev/ptyp0* (and its pair */dev/ttyp0*)
and */dev/ptyp1* (and its pair */dev/ttyp1*) in Linux and COM10 (and its pair COM11)
and COM20 (and its pair COM21) in Windows. The physical UART is /dev/ttyUSB0 in
Linux and COM5 in Windows. So, to run it in Linux, execute this:
-------------------------------------------------------
./mux.exe mux /dev/ttyUSB0,115200,rtscts /dev/ptyp0 /dev/ptyp1
-------------------------------------------------------
In Windows:
-------------------------------
mux mux com5,115200,rtscts com10 com20
-------------------------------
And now let's put this to good use. Remember that in the previous paragraph we
built an eLua configuration that assigned RFS to the first virtual UART (which corresponds
to the *vcom1* argument of *mux*) and the console to the second one (which corresponds
to the *vcom2* argument of *mux*). To make this happen on the PC, we start
the respective services on the UART pairs of the *vcomx* arguments of *mux*.
In Linux:
-----------------------------------------------------
./rfs_server ser:/dev/ttyp0,115200,none /home/user/work/fs
screen /dev/ttyp1 115200
-----------------------------------------------------
In Windows:
----------
rfs_server ser:com11,115200,none c:\elua\fs
(also run TeraTerm or your preffered terminal emulator on port COM21 at 115200 baud)
----------
Reset your eLua board, and you're ready to go! *mux* will send all the RFS requests
to */dev/ptyp0* (or COM10) which in turn gets automatically redirected to */dev/ttyp0*
(or COM11) and will redirect all console I/O to */dev/ptyp1* (or COM20)
which in turn gets automatically redirected to */dev/ptyp1* (or COM21).
Although this works, there is a simpler, more convenient way to do it if RFS
support is needed: use the *rfsmux* mode instead.
[[rfsmux]]
Using the multiplexer in "rfsmux" mode
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To make things easier for RFS users *mux* includes a special operation mode (*rfsmux*)
that automatically "talks" to the RFS server. The user doesn't need to manually assign
a virtual UART for the RFS server and start the RFS server. In this mode *mux* uses a special
internal communication channel to the RFS server (that doesn't require a virtual UART).
A strict requirement for this mode is that *eLua must be configured to assign the first
virtual UART ID (SERMUX_SERVICE_ID_FIRST) to the RFS server (RFS_UART_ID)*. If this
doesn't happen, *rfsmux* mode will not work anymore (but note that you still can use the
*mux* mode described above with this setup).
This is best understood by an example. We'll ask *mux* to share a directory and
to multiplex one single serial port for us (we'll use it for the console), this
will be *dev/ptyp0* (and its pair */dev/ttyp0*) in Linux and COM10 (and its pair COM11)
in Windows. The physical UART is /dev/ttyUSB0 in Linux and COM5 in Windows.
So, to run it in Linux, execute this:
------------------------------------------------------------------
./mux.exe rfsmux:/home/user/work/fs /dev/ttyUSB0,115200,rtscts /dev/ptyp0
------------------------------------------------------------------
In Windows:
---------------------------------------
mux rfsmux:c:\elua\fs com5,115200,rtscts com10
---------------------------------------
All that's left now is to run the terminal emulator. In Linux:
------------------------
screen /dev/ttyp0 115200
------------------------
In Windows simply start TeraTerm or your preffered terminal emulator on port COM11 at 115200 baud.
Reset your eLua board, and you're ready to go! *mux* will send all the RFS requests
to the RFS server via its internal channel and will redirect all console I/O to */dev/ptyp0* (or COM10)
which in turn gets automatically redirected to */dev/ttyp0* (or COM11).
Notes
~~~~~
Some things you should consider when using the serial multiplexer:
- the code is still in beta. It works well most of the time, but sometimes it simply crashes. If this happens, please consider submitting a bug report.
- if your eLua board has two hardware serial ports that you can use and the PC has also two free serial ports, consider disabling the serial multiplexer completely. Run RFS on a hardware
port and the system console on the other hardware port instead. This is both more realiable and more efficient.
- to avoid problems with the serial multiplexer use this sequence to start it:
1. start *mux*
2. start the terminal emulator
3. reset the eLua board
- using hardware flow control is strongly encouraged. To do this:
1. make sure that your eLua board has support for hardware flow control (see link:refman_gen_uart.html#platform_uart_set_flow_control[here] for details).
2. specify the correct *SERMUX_FLOW_TYPE* value at build time (it should be *PLATFORM_UART_FLOW_RTS | PLATFORM_UART_FLOW_CTS*).
3. make sure that the serial cable connecting the PC and the eLua board also supports flow control. Some simple serial connection cables have only the RX, TX and GND wires.
RTS/CTS flow control requires at least RX, TX, RTS, CTS and GND wires arranged in a null-modem configuration.
4. start *mux* specifying _rtscts_ as part of the _<transport>_ parameter (see above).
- the serial multiplexer "protocol" is an extremely simple one, it doesn't make provisions for error correction or detection, and it might loose
synchronization if there are errors on the serial line. So, if it starts behaving abnormally, you might want to restart *mux* (and *rfs_server*
if you're running it with *mux*) and reset your eLua board.
- some serial ports built around USB to RS232 adapters seem to confuse *mux* sometimes. If *mux* won't work after you tried all the above
instructions, or if *mux* terminates unexpectedly, unplugging and plugging the USB cable of the RS232 adapter and restarting *mux*
will most likely solve your problem.
- if you get an *"Error on select, aborting program"* error from *mux*, keep in mind that this is normal if you run a terminal emulator (*screen*)
under Linux on a virtual UART and then close it (by exiting *screen*). However, it is not normal if it happens under other circumstances in Linux,
or if it happens in Windows. In these cases, please consider submitting a bug report.
- if the serial multiplexer is enabled on the eLua board it's not possible to use the board with a regular terminal emulator anymore (without
running *mux*), although it might appear so. eLua will send some output to the terminal emulator, but it won't be able to accept any input from it.
- if you find a bug in *mux* and wish to report it, try to reproduce the problem again, but this time run *mux* with *-v* (verbose).
The resulting logs may help us identify the problem.
// $$FOOTER$$

View File

@ -323,8 +323,8 @@ div.admonitionblock {
margin-bottom: 1.0em;
}
div.admonitionblock {
margin-top: 2.0em;
margin-bottom: 2.0em;
margin-top: 1.0em;
margin-bottom: 1.0em;
margin-right: 10%;
color: #606060;
}

View File

@ -18,6 +18,7 @@ void cmn_int_handler( elua_int_id id, elua_int_resnum resnum );
int cmn_tmr_int_set_status( elua_int_resnum resnum, int status );
int cmn_tmr_int_get_status( elua_int_resnum resnum );
int cmn_tmr_int_get_flag( elua_int_resnum resnum, int clear );
void cmn_uart_setup_sermux();
unsigned int intlog2( unsigned int v );

65
inc/eluarpc.h Normal file
View File

@ -0,0 +1,65 @@
// Lightweight remote procedure call layer
#ifndef __ELUARPC_H__
#define __ELUARPC_H__
#include "type.h"
#define PACKET_SIG 0x18AFC284UL
// Error codes
#define ELUARPC_OK 0
#define ELUARPC_ERR 1
#define ELUARPC_OP_RES_MOD 0x80
// Protocol constants
#define ELUARPC_START_OFFSET 4
#define ELUARPC_START_SIZE 6
#define ELUARPC_END_SIZE 6
#define ELUARPC_RESPONSE_SIZE 1
#define ELUARPC_PTR_HEADER_SIZE 6
#define ELUARPC_SMALL_PTR_HEADER_SIZE 4
#define ELUARPC_U32_SIZE 5
#define ELUARPC_U16_SIZE 3
#define ELUARPC_U8_SIZE 2
#define ELUARPC_OP_ID_SIZE 2
#define ELUARPC_READ_BUF_OFFSET ( ELUARPC_START_OFFSET + ELUARPC_START_SIZE + ELUARPC_RESPONSE_SIZE + ELUARPC_PTR_HEADER_SIZE )
#define ELUARPC_SMALL_READ_BUF_OFFSET ( ELUARPC_START_OFFSET + ELUARPC_START_SIZE + ELUARPC_RESPONSE_SIZE + ELUARPC_SMALL_PTR_HEADER_SIZE )
#define ELUARPC_WRITE_REQUEST_EXTRA ( ELUARPC_START_OFFSET + ELUARPC_START_SIZE + ELUARPC_OP_ID_SIZE + ELUARPC_U32_SIZE + ELUARPC_PTR_HEADER_SIZE + ELUARPC_END_SIZE )
// Public interface
// Get request ID
int eluarpc_get_request_id( const u8 *p, u8 *pid );
// Replace a flag with another flag
u32 eluarpc_replace_flag( u32 val, u32 origflag, u32 newflag );
// Get packet size
int eluarpc_get_packet_size( const u8 *p, u16 *psize );
// Generic write function
// Specifiers: o - operation
// r - response
// c - u8
// h - u16
// l - u32
// i - int
// L - s32
// p - ptr (given as ptr, len, len is an u32)
// P - ptr (given as ptr, len, len is an u16)
void eluarpc_gen_write( u8 *p, const char *fmt, ... );
// Generic read function
// Specifiers: o - operation
// r - response
// c - u8
// h - u16
// l - u32
// L - s32
// i - int
// p - ptr (returned as ptr, len, len is an u32)
// P - ptr (returned as ptr, len, len is an u16)
int eluarpc_gen_read( const u8 *p, const char *fmt, ... );
#endif

View File

@ -136,12 +136,21 @@ enum
// "Infinite timeout" constant for recv
#define PLATFORM_UART_INFINITE_TIMEOUT (-1)
// Flow control types (this is a bit mask, one can specify PLATFORM_UART_FLOW_RTS | PLATFORM_UART_FLOW_CTS )
#define PLATFORM_UART_FLOW_NONE 0
#define PLATFORM_UART_FLOW_RTS 1
#define PLATFORM_UART_FLOW_CTS 2
// The platform UART functions
int platform_uart_exists( unsigned id );
u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int stopbits );
int platform_uart_set_buffer( unsigned id, unsigned size );
void platform_uart_send( unsigned id, u8 data );
void platform_s_uart_send( unsigned id, u8 data );
int platform_uart_recv( unsigned id, unsigned timer_id, s32 timeout );
int platform_s_uart_recv( unsigned id, s32 timeout );
int platform_uart_set_flow_control( unsigned id, int type );
int platform_s_uart_set_flow_control( unsigned id, int type );
// *****************************************************************************
// Timer subsection

View File

@ -11,7 +11,7 @@
// RFS client send/receive functions
typedef u32 ( *p_rfsc_send )( const u8 *p, u32 size );
typedef u32 ( *p_rfsc_recv )( u8 *p, u32 size, u32 timeout );
typedef u32 ( *p_rfsc_recv )( u8 *p, u32 size, s32 timeout );
// Public interface
void rfsc_setup( u8 *pbuf, p_rfsc_send rfsc_send_func, p_rfsc_recv rfsc_recv_func, u32 timeout );

View File

@ -5,12 +5,6 @@
#include "type.h"
#define PACKET_SIG 0x18AFC284UL
// Error codes
#define REMOTEFS_OK 0
#define REMOTEFS_ERR 1
// Operation IDs
#define RFS_OP_OPEN 0x01
#define RFS_OP_FIRST RFS_OP_OPEN
@ -24,17 +18,6 @@
#define RFS_OP_LAST RFS_OP_CLOSEDIR
#define RFS_OP_RES_MOD 0x80
// Protocol constants
#define RFS_START_OFFSET 4
#define RFS_START_SIZE 6
#define RFS_END_SIZE 6
#define RFS_RESPONSE_SIZE 1
#define RFS_PTR_HEADER_SIZE 6
#define RFS_U32_SIZE 5
#define RFS_OP_ID_SIZE 2
#define RFS_READ_BUF_OFFSET ( RFS_START_OFFSET + RFS_START_SIZE + RFS_RESPONSE_SIZE + RFS_PTR_HEADER_SIZE )
#define RFS_WRITE_REQUEST_EXTRA ( RFS_START_OFFSET + RFS_START_SIZE + RFS_OP_ID_SIZE + RFS_U32_SIZE + RFS_PTR_HEADER_SIZE + RFS_END_SIZE )
// Platform independent constants for "flags" in "open"
#define RFS_OPEN_FLAG_APPEND 0x01
#define RFS_OPEN_FLAG_CREAT 0x02
@ -57,16 +40,6 @@
// Max filename size on a RFS instance
#define RFS_MAX_FNAME_SIZE 31
// Public interface
// Get request ID
int remotefs_get_request_id( const u8 *p, u8 *pid );
// Replace a flag with another flag
u32 remotefs_replace_flag( u32 val, u32 origflag, u32 newflag );
// Get packet size
int remotefs_get_packet_size( const u8 *p, u16 *psize );
// Function: int open(const char *pathname,int flags, mode_t mode)
void remotefs_open_write_response( u8 *p, int result );
int remotefs_open_read_response( const u8 *p, int *presult );

View File

@ -11,6 +11,7 @@
#define TYPE_START 0x05
#define TYPE_END 0x06
#define TYPE_OP_ID 0x07
#define TYPE_SMALL_PTR 0x08
#define TYPE_PKT_SIZE 0xA5
#endif

16
inc/sermux.h Normal file
View File

@ -0,0 +1,16 @@
// Serial multiplexer definitions
#ifndef __SERMUX_H__
#define __SERMUX_H__
#define SERMUX_SERVICE_ID_FIRST 0xD0
#define SERMUX_SERVICE_ID_LAST 0xD7
#define SERMUX_SERVICE_MAX ( SERMUX_SERVICE_ID_LAST - SERMUX_SERVICE_ID_FIRST + 1 )
#define SERMUX_ESCAPE_CHAR 0xC0
#define SERMUX_FORCE_SID_CHAR 0xFF
#define SERMUX_ESCAPE_XOR_MASK 0x20
#define SERMUX_ESC_MASK 0x100
#endif

View File

@ -8,6 +8,12 @@
#define UMAX( x, y ) ( ( x ) >= ( y ) ? ( x ) : ( y ) )
#define UABS( x ) ( ( x ) >= 0 ? ( x ) : -( x ) )
// Implement a very simple try-catch ike mechanism using setmp/longjmp,
// mostly to avoid goto's :)
#define EXC_DECLARE static jmp_buf exception_buf
#define EXC_TRY if( setjmp( exception_buf ) == 0 )
#define EXC_CATCH else
#define EXC_THROW() longjmp( exception_buf, 1 )
// Macro version of Duff's device found in
// "A Reusable Duff Device" by Ralf Holly

View File

@ -57,4 +57,32 @@
#endif // #ifndef BUILD_TERM
#endif // #ifdef BUILD_LINENOISE
// For BUF_ENABLE_UART we also need C interrupt handlers support and specific INT_UART_RX support
#if defined( BUF_ENABLE_UART )
#if !defined( BUILD_C_INT_HANDLERS )
#error "Buffering support on UART neeeds C interrupt handlers support, define BUILD_C_INT_HANDLERS in your platform_conf.h"
#endif
#if !defined( INT_UART_RX )
#error "Buffering support on UART needs support for the INT_UART_RX interrupt"
#endif
#endif
// Virtual UARTs need buffering and a few specific macros
#if defined( BUILD_SERMUX )
#if !defined( BUF_ENABLE_UART )
#error "Virtual UARTs need buffering support, enable BUF_ENABLE_UART"
#endif
#endif
// CON_BUF_SIZE needs BUF_ENABLE_UART and CON_UART_ID
#if defined( CON_BUF_SIZE )
#if !defined( BUF_ENABLE_UART )
#error "Console buffering needs BUF_ENABLE_UART"
#endif
#if !defined( CON_UART_ID )
#error "Console buffering needs CON_UART_ID defined to the UART ID of the console device"
#endif
#endif
#endif // #ifndef __VALIDATE_H__

33
mux.py Normal file
View File

@ -0,0 +1,33 @@
import os, sys, platform
flist = "main.c"
rfs_flist = "main.c server.c log.c deskutils.c"
cdefs = "-DRFS_UDP_TRANSPORT -DRFS_INSIDE_MUX_MODE"
socklib = ''
ptlib = ''
if platform.system() == "Windows":
cdefs = cdefs + " -DWIN32_BUILD"
rfs_flist = rfs_flist + " os_io_win32.c serial_win32.c net_win32.c"
exeprefix = ".exe"
socklib = '-lws2_32'
else:
rfs_flist = rfs_flist + " os_io_posix.c serial_posix.c net_posix.c"
exeprefix = ""
socklib = ''
output = "mux%s" % exeprefix
rfs_full_files = " " + " ".join( [ "rfs_server_src/%s" % name for name in rfs_flist.split() ] )
full_files = " " + " ".join( [ "mux_src/%s" % name for name in flist.split() ] ) + rfs_full_files + " src/remotefs/remotefs.c src/eluarpc.c"
local_include = "-Imux_src -Irfs_server_src -Iinc -Iinc/remotefs"
# Compiler/linker options
cccom = "gcc -m32 -O0 -g %s -Wall %s -c $SOURCE -o $TARGET" % ( local_include, cdefs )
linkcom = "gcc -m32 -o $TARGET $SOURCES %s" % socklib
# Env for building the program
comp = Environment( CCCOM = cccom,
LINKCOM = linkcom,
ENV = os.environ )
Decider( 'MD5' )
Default( comp.Program( output, Split( full_files ) ) )

13
mux_src/config.h Normal file
View File

@ -0,0 +1,13 @@
// Service multiplexer configurator
#ifndef __CONFIG_H__
#define __CONFIG_H__
#include "sermux.h"
#define SER_TIMEOUT_MS 100
#define NET_TIMEOUT_MS 100
#define MEM_BUF_SIZE ( 6 * 1024 )
#endif

372
mux_src/main.c Normal file
View File

@ -0,0 +1,372 @@
// Service multiplexer
#include "net.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <ctype.h>
#include "config.h"
#include "log.h"
#include "type.h"
#include "serial.h"
#include "sermux.h"
#include "rfs.h"
#include "deskutils.h"
// ****************************************************************************
// Data structures and local variables
#define MODE_MUX 1
#define MODE_RFSMUX 2
#define HND_TRANSPORT_OFFSET 0
#define HND_FIRST_VOFFSET 1
#define RFS_PSEUDO_SELIDX 0xFF
// Send/receive/init function pointers
typedef u32 ( *p_recv_func )( u8 *p, u32 size );
typedef u32 ( *p_send_func )( const u8 *p, u32 size );
typedef int ( *p_init_func )( void );
// Serial thread buffer structure
typedef struct {
const char *pname;
ser_handler fd;
} SERVICE_DATA;
// Serial transport data structure
typedef struct {
ser_handler fd;
const char *pname;
long speed;
int flow;
} TRANSPORT_SER;
static SERVICE_DATA *services;
static unsigned vport_num;
static TRANSPORT_SER *transport_data;
static p_send_func transport_send;
static p_init_func transport_init;
static int service_id_in = -1, service_id_out = -1;
static ser_handler transport_hnd = SER_HANDLER_INVALID;
static int mux_mode;
static int verbose_mode;
static int rfs_service_id = -1, service_offset;
// ***************************************************************************
// Serial transport implementation
static u32 transport_ser_send( const u8 *p, u32 size )
{
TRANSPORT_SER *pser = ( TRANSPORT_SER* )transport_data;
return ser_write( pser->fd, p, size );
}
static int transport_ser_init()
{
TRANSPORT_SER *pser = ( TRANSPORT_SER* )transport_data;
if( ( pser->fd = ser_open( pser->pname ) ) == ( ser_handler )-1 )
{
log_err( "Unable to open %s\n", pser->pname );
return 0;
}
if( ser_setup( pser->fd, pser->speed, 8, SER_PARITY_NONE, SER_STOPBITS_1, pser->flow ) != SER_OK )
{
log_err( "Unable to setup serial port %s\n", pser->pname );
return 0;
}
transport_hnd = pser->fd;
while( ser_read_byte( pser->fd, SER_NO_TIMEOUT ) != -1 );
log_msg( "Running serial transport on port %s at %u baud (8N1)\n", pser->pname, ( unsigned )pser->speed );
return 1;
}
// ****************************************************************************
// Utility functions and helpers
static void transport_send_byte( u8 data )
{
transport_send( &data, 1 );
}
// Transport parser
static int parse_transport( const char* s )
{
const char *c, *c2;
static TRANSPORT_SER tser;
char *temp;
if( ( c = strchr( s, ',' ) ) == NULL )
{
log_err( "Invalid serial transport syntax.\n" );
return 0;
}
tser.pname = l_strndup( s, c - s );
if( ( c2 = strchr( c + 1, ',' ) ) == NULL )
{
log_err( "Invalid serial transport syntax.\n" );
return 0;
}
temp = l_strndup( c + 1, c2 - c - 1 );
if( secure_atoi( temp, &tser.speed ) == 0 )
{
log_err( "Invalid port speed\n" );
return 0;
}
free( temp );
if( !strcmp( c2 + 1, "none" ) )
tser.flow = SER_FLOW_NONE;
else if( !strcmp( c2 + 1, "rtscts" ) )
tser.flow = SER_FLOW_RTSCTS;
else
{
log_err( "Invalid flow control type.\n" );
return 0;
}
transport_data = &tser;
transport_send = transport_ser_send;
transport_init = transport_ser_init;
return 1;
}
// ****************************************************************************
// Program entry point
#define MODE_IDX 1
#define MAIN_TRANSPORT_IDX 2
#define FIRST_SERVICE_IDX 3
#define MIN_ARGC_COUNT 4
int main( int argc, char **argv )
{
unsigned i;
SERVICE_DATA *tservice;
int c, prev_sent = -1;
int temp;
int got_esc = 0;
char* rfs_dir_name;
ser_handler *phandlers;
int selidx;
u16 rfs_size = 0;
u8 *rfs_ptr;
// Interpret arguments
setvbuf( stdout, NULL, _IONBF, 0 );
if( argc < MIN_ARGC_COUNT )
{
log_err( "Usage: %s <mode> <transport> <vcom1> [<vcom2>] ... [<vcomn>] [-v]\n", argv[ 0 ] );
log_err( " mode: \n" );
log_err( " 'mux': serial multiplexer mode\n" );
log_err( " 'rfsmux:<directory>: combined RFS and multiplexer mode.\n" );
log_err( " transport: '<port>,<baud>,<flow> ('flow' specifies the flow control type and can be 'none' or 'rtscts').\n" );
log_err( " vcom1, ..., vcomn: multiplexer serial ports." );
log_err( " Use '-v' for verbose output.\n" );
return 1;
}
// Check mode
if( !strcmp( argv[ MODE_IDX ], "mux" ) )
mux_mode = MODE_MUX;
else if( !strncmp( argv[ MODE_IDX ], "rfsmux:", strlen( "rfsmux:" ) ) )
{
rfs_dir_name = argv[ MODE_IDX ] + strlen( "rfsmux:" );
mux_mode = MODE_RFSMUX;
rfs_service_id = SERMUX_SERVICE_ID_FIRST;
service_offset = 1;
}
else
{
log_err( "Invalid mode.\n" );
return 1;
}
// Check verbose
i = argc - 1;
if( !strcasecmp( argv[ i ], "-v" ) )
{
i --;
log_init( LOG_ALL );
verbose_mode = 1;
}
else
log_init( LOG_NONE );
// Get number of virtual UARTs
if( ( vport_num = i - FIRST_SERVICE_IDX + 1 ) > SERMUX_SERVICE_MAX )
{
log_err( "Too many service ports, maximum is %d\n", SERMUX_SERVICE_MAX );
return 1;
}
// Parse transport data and initialize it
if( parse_transport( argv[ MAIN_TRANSPORT_IDX ] ) == 0 )
return 1;
if( transport_init() == 0 )
return 1;
// Open all the service ports
if( ( services = ( SERVICE_DATA* )malloc( sizeof( SERVICE_DATA ) * vport_num ) ) == NULL )
{
log_err( "Not enough memory\n" );
return 1;
}
if( ( phandlers = ( ser_handler* )malloc( sizeof( ser_handler ) * ( vport_num + 1 ) ) ) == NULL )
{
log_err( "Not enough memory\n" );
return 1;
}
phandlers[ HND_TRANSPORT_OFFSET ] = transport_hnd;
memset( services, 0, sizeof( SERVICE_DATA ) * vport_num );
for( i = 0; i < vport_num; i ++ )
{
tservice = services + i;
if( ( tservice->fd = ser_open( argv[ i + FIRST_SERVICE_IDX ] ) ) == SER_HANDLER_INVALID )
{
log_err( "Unable to open port %s\n", argv[ i + FIRST_SERVICE_IDX ] );
return 1;
}
if( ser_setup( tservice->fd, transport_data->speed, SER_DATABITS_8, SER_PARITY_NONE, SER_STOPBITS_1, SER_FLOW_NONE ) != SER_OK )
{
log_err( "Unable to setup serial port %s\n", argv[ i + FIRST_SERVICE_IDX ] );
return 1;
}
tservice->pname = argv[ i + FIRST_SERVICE_IDX ];
phandlers[ i + HND_FIRST_VOFFSET ] = tservice->fd;
}
// Setup RFS server in RFSMUX mode
if( mux_mode == MODE_RFSMUX )
{
char *args[] = { "dummy", "mem", rfs_dir_name, NULL };
if( verbose_mode )
args[ 3 ] = "-v";
if( rfs_init( verbose_mode ? 4 : 3, ( const char ** )args ) != 0 )
return 1;
}
log_msg( "Starting service multiplexer on %u port(s)\n", vport_num );
// Main service thread
while( 1 )
{
if( rfs_size > 0 ) // Response packet from RFS
{
c = *rfs_ptr ++;
rfs_size --;
selidx = RFS_PSEUDO_SELIDX;
}
else
{
if( ( c = ser_select_byte( phandlers, vport_num + 1, SER_INF_TIMEOUT ) ) == -1 )
{
log_err( "Error on select, aborting program\n" );
return 1;
}
selidx = c >> 8;
c = c & 0xFF;
}
//log_msg( "Got byte %d from idx %d\n", c, selidx );
if( selidx == HND_TRANSPORT_OFFSET ) // Got byte on transport interface
{
// Interpret byte
if( c != SERMUX_ESCAPE_CHAR )
{
if( c >= SERMUX_SERVICE_ID_FIRST && c <= SERMUX_SERVICE_ID_LAST )
{
log_msg( "Changed service_id_in from %d(%X) to %d(%X).\n", service_id_in, service_id_in, c, c );
service_id_in = c;
}
else if( c == SERMUX_FORCE_SID_CHAR )
{
if( prev_sent == -1 )
{
log_err( "Protocol error: got request to resend service ID when the last char sent was not set.\n" );
return 1;
}
log_msg( "Got request to resend service_id_out %d(%X).\n", service_id_out, service_id_out );
// Re-transmit the last data AND the service ID
transport_send_byte( service_id_out );
if( prev_sent & SERMUX_ESC_MASK )
transport_send_byte( SERMUX_ESCAPE_CHAR );
transport_send_byte( prev_sent & 0xFF );
prev_sent = -1;
}
else
{
if( got_esc )
{
// Got an escape last time, check the char now (with the 5th bit flipped)
c ^= SERMUX_ESCAPE_XOR_MASK;
if( c != SERMUX_ESCAPE_CHAR && c != SERMUX_FORCE_SID_CHAR && ( c < SERMUX_SERVICE_ID_FIRST || c > SERMUX_SERVICE_ID_LAST ) )
{
log_err( "Protocol error: invalid escape sequence\n" );
return 1;
}
got_esc = 0;
}
if( service_id_in == -1 )
{
transport_send_byte( SERMUX_FORCE_SID_CHAR );
log_msg( "Requested resend of service ID for byte %3d ('%c').\n", c, isprint( c ) ? c : ' ' );
}
else
{
if( service_id_in == rfs_service_id ) // this request is for the RFS server
{
rfs_mem_read_request_packet( c );
if( rfs_mem_has_response() ) // we have a response from the RFS server
{
rfs_mem_write_response( &rfs_size, &rfs_ptr );
rfs_mem_start_request(); // initialize the RFS server for a new request
}
}
else
{
//log_msg( "Sending byte %d to %s\n", c, services[ service_id_in - SERMUX_SERVICE_ID_FIRST - service_offset ].pname );
ser_write_byte( services[ service_id_in - SERMUX_SERVICE_ID_FIRST - service_offset ].fd, c );
}
}
}
}
else
got_esc = 1;
}
else
{
// No byte to read, there must be something to send
if( selidx == RFS_PSEUDO_SELIDX )
temp = SERMUX_SERVICE_ID_FIRST;
else
temp = SERMUX_SERVICE_ID_FIRST + selidx - HND_FIRST_VOFFSET + service_offset;
prev_sent = c;
// Send the service ID first if needed
if( temp != service_id_out )
{
log_msg( "Changed service_id_out from %d(%X) to %d(%X).\n", service_id_out, service_id_out, temp, temp );
transport_send_byte( temp );
}
// Then send the actual data byte, escaping it if needed
if( c == SERMUX_ESCAPE_CHAR || c == SERMUX_FORCE_SID_CHAR || ( c >= SERMUX_SERVICE_ID_FIRST && c <= SERMUX_SERVICE_ID_LAST ) )
{
transport_send_byte( SERMUX_ESCAPE_CHAR );
transport_send_byte( ( u8 )c ^ SERMUX_ESCAPE_XOR_MASK );
prev_sent = SERMUX_ESC_MASK | ( ( u8 )c ^ SERMUX_ESCAPE_XOR_MASK );
}
else
transport_send_byte( c );
service_id_out = temp;
}
}
return 0;
}

349
mux_src/main.c.allthreads Normal file
View File

@ -0,0 +1,349 @@
// Service multiplexer
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include "config.h"
#include "log.h"
#include "type.h"
#include "serial.h"
// ****************************************************************************
// Data structures and local variables
#define TRANSPORT_TYPE_ERROR 0
#define TRANSPORT_TYPE_SER 1
// Service ID of the transport thread
#define TRANSPORT_SERVICE_ID -1
// Send/receive/init function pointers
typedef u32 ( *p_recv_func )( u8 *p, u32 size );
typedef u32 ( *p_send_func )( const u8 *p, u32 size );
typedef int ( *p_init_func )( void );
// Serial thread buffer structure
typedef struct
{
pthread_t tid;
const char *pname;
ser_handler fd;
int service_id;
} THREAD_DATA;
// Serial transport data structure
typedef struct
{
ser_handler fd;
const char *pname;
long speed;
} TRANSPORT_SER;
// Service/transport data
typedef struct
{
int id;
u8 data;
} DATA;
static THREAD_DATA *threads;
static unsigned vport_num;
static void *transport_data;
static int transport_type;
static p_recv_func transport_recv;
static p_send_func transport_send;
static p_init_func transport_init;
static long service_baud;
static sem_t mux_w_sem, mux_r_sem;
static DATA mux_data;
static int service_id_in = -1, service_id_out = -1;
// ***************************************************************************
// Serial transport implementation
static u32 transport_ser_recv( u8 *p, u32 size )
{
TRANSPORT_SER *pser = ( TRANSPORT_SER* )transport_data;
return ser_read( pser->fd, p, size, SER_INF_TIMEOUT );
}
static u32 transport_ser_send( const u8 *p, u32 size )
{
TRANSPORT_SER *pser = ( TRANSPORT_SER* )transport_data;
return ser_write( pser->fd, p, size );
}
static int transport_ser_init()
{
TRANSPORT_SER *pser = ( TRANSPORT_SER* )transport_data;
if( ( pser->fd = ser_open( pser->pname ) ) == ( ser_handler )-1 )
{
fprintf( stderr, "Unable to open %s\n", pser->pname );
return 0;
}
if( ser_setup( pser->fd, pser->speed, 8, SER_PARITY_NONE, SER_STOPBITS_1 ) != SER_OK )
{
fprintf( stderr, "Unable to setup serial port %s\n", pser->pname );
return 0;
}
while( ser_read_byte( pser->fd, SER_NO_TIMEOUT ) != -1 );
printf( "Running serial transport on port %s at %u baud (8N1)\n", pser->pname, ( unsigned )pser->speed );
return 1;
}
// ****************************************************************************
// Utility functions and helpers
static void transport_send_byte( u8 data )
{
transport_send( &data, 1 );
}
static int transport_read_byte()
{
u8 c;
return transport_recv( &c, 1 ) == 1 ? c : -1;
}
// Secure atoi
static int secure_atoi( const char *str, long *pres )
{
char *end_ptr;
long s1;
errno = 0;
s1 = strtol( str, &end_ptr, 10 );
if( ( s1 == LONG_MIN || s1 == LONG_MAX ) && errno != 0 )
return 0;
else if( end_ptr == str )
return 0;
else if( s1 > INT_MAX || s1 < INT_MIN )
return 0;
else if( '\0' != *end_ptr )
return 0;
*pres = s1;
return 1;
}
// Transport parser
static int parse_transport( const char* s )
{
const char *c;
static TRANSPORT_SER tser;
if( strstr( s, "ser:" ) == s )
{
s += strlen( "ser:" );
if( ( c = strchr( s, ',' ) ) == NULL )
{
fprintf( stderr, "Invalid serial transport syntax\n" );
return 0;
}
if( secure_atoi( c + 1, &tser.speed ) == 0 )
{
fprintf( stderr, "Invalid port speed\n" );
return 0;
}
tser.pname = strndup( s, c - s );
transport_data = &tser;
transport_send = transport_ser_send;
transport_recv = transport_ser_recv;
transport_init = transport_ser_init;
transport_type = TRANSPORT_TYPE_SER;
return 1;
}
fprintf( stderr, "Error: unsupported transport\n" );
return 0;
}
// ***************************************************************************
// Service thread
static void* service_thread( void* data )
{
THREAD_DATA *pdata = ( THREAD_DATA*) data;
int sdata;
log_msg( "Starting service thread for port %s\n", pdata->pname );
while( 1 )
{
if( ( sdata = ser_read_byte( pdata->fd, SER_INF_TIMEOUT ) ) == -1 )
continue;
sem_wait( &mux_w_sem );
mux_data.data = sdata;
mux_data.id = pdata->service_id;
sem_post( &mux_r_sem );
}
return NULL;
}
// ****************************************************************************
// Transport thread
static void* transport_thread( void* data )
{
int sdata;
log_msg( "Starting transport thread\n" );
while( 1 )
{
if( ( sdata = transport_read_byte() ) == -1 )
continue;
sem_wait( &mux_w_sem );
mux_data.data = sdata;
mux_data.id = TRANSPORT_SERVICE_ID;
sem_post( &mux_r_sem );
}
return NULL;
}
// ****************************************************************************
// Program entry point
#define MAIN_TRANSPORT_IDX 1
#define SERVICE_BAUD_IDX 2
#define FIRST_SERVICE_IDX 3
int main( int argc, char **argv )
{
unsigned i;
THREAD_DATA *tdata;
int c;
int temp, sdata;
int got_esc = 0;
DATA data;
// Interpret arguments
if( argc < 4 )
{
fprintf( stderr, "Usage: %s <transport> <baud> <vcom1> [<vcom2>] ... [<vcomn>] [-v]\n", argv[ 0 ] );
return 1;
}
i = argc - 1;
if( !strcasecmp( argv[ i ], "-v" ) )
{
i --;
log_init( LOG_ALL );
}
else
log_init( LOG_NONE );
if( ( vport_num = i - 2 ) > SERVICE_MAX )
{
fprintf( stderr, "Too many service ports, maximum is %d\n", SERVICE_MAX );
return 1;
}
if( parse_transport( argv[ MAIN_TRANSPORT_IDX ] ) == 0 )
return 1;
if( secure_atoi( argv[ SERVICE_BAUD_IDX ], &service_baud ) == 0 )
{
fprintf( stderr, "Invalid service baud\n" );
return 1;
}
if( transport_init() == 0 )
return 1;
// Create global sync objects
sem_init( &mux_w_sem, 0, 1 );
sem_init( &mux_r_sem, 0, 0 );
// Open all the service ports and create their corresponding threads
if( ( threads = ( THREAD_DATA* )malloc( sizeof( THREAD_DATA ) * ( vport_num + 1 ) ) ) == NULL )
{
fprintf( stderr, "Not enough memory\n" );
return 1;
}
for( i = 0; i <= vport_num; i ++ )
{
tdata = threads + i;
if( i < vport_num )
{
if( ( tdata->fd = ser_open( argv[ i + FIRST_SERVICE_IDX ] ) ) == ( ser_handler )-1 )
{
fprintf( stderr, "Unable to open port %s\n", argv[ i + FIRST_SERVICE_IDX ] );
return 1;
}
if( ser_setup( tdata->fd, service_baud, SER_DATABITS_8, SER_PARITY_NONE, SER_STOPBITS_1 ) != SER_OK )
{
fprintf( stderr, "Unable to setup serial port %s\n", argv[ i + FIRST_SERVICE_IDX ] );
return 1;
}
tdata->pname = argv[ i + FIRST_SERVICE_IDX ];
tdata->service_id = i + SERVICE_ID_FIRST;
}
if( pthread_create( &tdata->tid, NULL, i == vport_num ? transport_thread : service_thread, ( void* )tdata ) )
{
fprintf( stderr, "Unable to create thread\n" );
return 1;
}
}
printf( "Starting service multiplexer on %u port(s)\n", vport_num );
// Main service thread
while( 1 )
{
sem_wait( &mux_r_sem );
data = mux_data;
sem_post( &mux_w_sem );
if( data.id == TRANSPORT_SERVICE_ID )
{
// Read one byte, interpret it
c = data.data;
if( c != ESCAPE_CHAR )
{
if( c >= SERVICE_ID_FIRST && c <= SERVICE_ID_LAST )
service_id_in = c;
else
{
if( got_esc )
{
// Got an escape last time, check the char now (with the 5th bit flipped)
c ^= ESCAPE_XOR_MASK;
if( c != ESCAPE_CHAR && c < SERVICE_ID_FIRST && c > SERVICE_ID_LAST )
{
fprintf( stderr, "Protocol error: invalid escape sequence\n" );
return 1;
}
got_esc = 0;
}
if( service_id_in == -1 )
{
fprintf( stderr, "Protocol error: service ID not specified\n" );
return 1;
}
ser_write_byte( threads[ service_id_in - SERVICE_ID_FIRST ].fd, c );
}
}
else
got_esc = 1;
}
else
{
temp = data.id;
sdata = data.data;
if( temp != service_id_out )
transport_send_byte( temp );
// Then send the actual data byte, escaping it if needed
if( sdata == ESCAPE_CHAR || ( sdata >= SERVICE_ID_FIRST && sdata <= SERVICE_ID_LAST ) )
{
transport_send_byte( ESCAPE_CHAR );
transport_send_byte( ( u8 )sdata ^ ESCAPE_XOR_MASK );
}
else
transport_send_byte( sdata );
service_id_out = temp;
}
}
return 0;
}

755
mux_src/main.c.old Normal file
View File

@ -0,0 +1,755 @@
// Service multiplexer
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include "config.h"
#include "log.h"
#include "type.h"
#include "serial.h"
#include "os_io.h"
#include "pnet.h"
// External RFS functions
extern int rfs_server_init( unsigned server_port, const char* dirname );
extern void rfs_server_cleanup();
extern void* rfs_thread( void* data );
extern volatile int rfs_thread_should_die;
// ****************************************************************************
// Data structures and local variables
#define TRANSPORT_TYPE_ERROR 0
#define TRANSPORT_TYPE_SER 1
#define TRANSPORT_TYPE_UDP 2
#define TRANSPORT_TYPE_TEXTCTRL 3
// Service ID of the transport thread
#define TRANSPORT_SERVICE_ID ( -1 )
#define THREAD_STOP_SERVICE_ID ( -2 )
// Thread indexes in the threads array
#ifdef MUX_THREAD_MODE
#define TEXTCTRL_THREAD_IDX 1
#else
#define TEXTCTRL_THREAD_IDX ( -1 )
#endif
#define RFS_UDP_THREAD_IDX 0
// Send/receive/init function pointers for transport
typedef u32 ( *p_recv_func )( u8 *p, u32 size );
typedef u32 ( *p_send_func )( const u8 *p, u32 size );
typedef int ( *p_init_func )( void );
typedef void ( *p_cleanup_func )( void );
// Thread function type
typedef void* ( *p_thread_func )( void* );
// Thread structure
typedef struct
{
pthread_t tid;
int thread_created;
volatile int thread_should_die;
int type;
union
{
const char *pname;
unsigned port;
};
union
{
ser_handler fd;
SOCKET s;
};
int service_id;
struct sockaddr_in server;
union
{
sem_t udp_sem;
sem_t textctrl_sem;
};
int textctrl_data;
u8 *udp_buf;
} THREAD_DATA;
// Serial transport data structure
typedef struct
{
ser_handler fd;
char *pname;
long speed;
} TRANSPORT_SER;
// Service/transport data
typedef struct
{
int id;
u8 data;
} DATA;
static THREAD_DATA *threads;
static unsigned vport_num;
static void *transport_data;
static int transport_type;
static p_recv_func transport_recv;
static p_send_func transport_send;
static p_init_func transport_init;
static p_cleanup_func transport_cleanup;
static long service_baud;
static sem_t mux_w_sem, mux_r_sem;
static DATA mux_data;
static int service_id_in = -1, service_id_out = -1;
static pthread_t rfs_thread_id;
static int rfs_thread_created;
volatile int mux_thread_running;
// *****************************************************************************
// wxTextCtrl "transport" helpers
#ifdef MUX_THREAD_MODE
// wxTextCtrl buffer data
typedef struct
{
int *pdata;
unsigned r_idx, w_idx, total;
sem_t count_sem;
} TEXTCTRL_DATA;
static TEXTCTRL_DATA textctrl_data;
int mux_textctrl_init( unsigned total )
{
if( ( textctrl_data.pdata = ( int* )malloc( total * sizeof( int ) ) ) == NULL )
{
log_err( "Unable to alloc textctrl buffer\n" );
return 0;
}
textctrl_data.r_idx = textctrl_data.w_idx = 0;
textctrl_data.total = total;
sem_init( &textctrl_data.count_sem, 0, 0 );
return 1;
}
void mux_textctrl_cleanup()
{
free( textctrl_data.pdata );
sem_destroy( &textctrl_data.count_sem );
}
void textctrl_get_char( int c )
{
#if 0
textctrl_data.pdata[ textctrl_data.w_idx ] = c;
textctrl_data.w_idx = ( textctrl_data.w_idx + 1 ) % textctrl_data.total;
printf( "!" );
sem_post( &textctrl_data.count_sem );
#else
THREAD_DATA *pdata = threads + TEXTCTRL_THREAD_IDX;
pdata->textctrl_data = c;
sem_post( &pdata->textctrl_sem );
#endif
}
extern void textctrl_put_char( int c );
#else // #ifdef MUX_THREAD_MODE
static void textctrl_put_char( int c )
{
}
static void textctrl_get_char( int c )
{
}
#endif // #ifdef MUX_THREAD_MODE
// *****************************************************************************
// Serial transport implementation
static u32 transport_ser_recv( u8 *p, u32 size )
{
TRANSPORT_SER *pser = ( TRANSPORT_SER* )transport_data;
return ser_read( pser->fd, p, size, SER_TIMEOUT_MS );
}
static u32 transport_ser_send( const u8 *p, u32 size )
{
TRANSPORT_SER *pser = ( TRANSPORT_SER* )transport_data;
return ser_write( pser->fd, p, size );
}
static int transport_ser_init()
{
TRANSPORT_SER *pser = ( TRANSPORT_SER* )transport_data;
if( ( pser->fd = ser_open( pser->pname ) ) == ( ser_handler )-1 )
{
log_err( "Unable to open %s\n", pser->pname );
return 0;
}
if( ser_setup( pser->fd, pser->speed, 8, SER_PARITY_NONE, SER_STOPBITS_1 ) != SER_OK )
{
log_err( "Unable to setup serial port %s\n", pser->pname );
return 0;
}
while( ser_read_byte( pser->fd, SER_NO_TIMEOUT ) != -1 );
log_msg( "Running serial transport on port %s at %u baud (8N1)\n", pser->pname, ( unsigned )pser->speed );
return 1;
}
static void transport_ser_cleanup()
{
TRANSPORT_SER *pser = ( TRANSPORT_SER* )transport_data;
if( pser->fd && pser->fd != ( ser_handler )-1 )
ser_close( pser->fd );
free( pser->pname );
}
// ****************************************************************************
// Utility functions and helpers
static void transport_send_byte( u8 data )
{
transport_send( &data, 1 );
}
static int transport_read_byte()
{
u8 c;
return transport_recv( &c, 1 ) == 1 ? c : -1;
}
// Secure atoi
static int secure_atoi( const char *str, long *pres )
{
char *end_ptr;
long s1;
errno = 0;
s1 = strtol( str, &end_ptr, 10 );
if( ( s1 == LONG_MIN || s1 == LONG_MAX ) && errno != 0 )
return 0;
else if( end_ptr == str )
return 0;
else if( s1 > INT_MAX || s1 < INT_MIN )
return 0;
else if( '\0' != *end_ptr )
return 0;
*pres = s1;
return 1;
}
// Local strndup function to compensate the lack of strndup in Windows
static char* l_strndup( const char* s, size_t n )
{
char* p;
if( ( p = ( char* )malloc( n + 1 ) ) == NULL )
return NULL;
p [ 0 ] = p[ n ] = '\0';
strncpy( p, s, n );
return p;
}
// Transport parser
static int parse_transport( const char* s )
{
const char *c;
static TRANSPORT_SER tser;
if( strstr( s, "ser:" ) == s )
{
s += strlen( "ser:" );
if( ( c = strchr( s, ',' ) ) == NULL )
{
log_err( "Invalid serial transport syntax\n" );
return 0;
}
if( secure_atoi( c + 1, &tser.speed ) == 0 )
{
log_err( "Invalid port speed\n" );
return 0;
}
tser.pname = l_strndup( s, c - s );
transport_data = &tser;
transport_send = transport_ser_send;
transport_recv = transport_ser_recv;
transport_init = transport_ser_init;
transport_cleanup = transport_ser_cleanup;
transport_type = TRANSPORT_TYPE_SER;
return 1;
}
log_err( "Error: unsupported transport\n" );
return 0;
}
// ***************************************************************************
// Service threads
static void* service_thread_ser( void* data )
{
THREAD_DATA *pdata = ( THREAD_DATA* )data;
int sdata;
log_msg( "Starting serial service thread for port %s\n", pdata->pname );
while( 1 )
{
if( ( sdata = ser_read_byte( pdata->fd, SER_TIMEOUT_MS ) ) == -1 )
{
if( pdata->thread_should_die )
break;
else
continue;
}
sem_wait( &mux_w_sem );
mux_data.data = sdata;
mux_data.id = pdata->service_id;
sem_post( &mux_r_sem );
}
return NULL;
}
static void* service_thread_udp( void* data )
{
THREAD_DATA *pdata = ( THREAD_DATA* )data;
socklen_t fromlen;
struct sockaddr_in from;
int readbytes, i;
fd_set fds;
struct timeval tv;
log_msg( "Starting UDP service thread for port %d\n", pdata->port );
while( 1 )
{
FD_ZERO( &fds );
FD_SET( pdata->s, &fds );
tv.tv_sec = 0;
tv.tv_usec = NET_TIMEOUT_MS * 1000;
if( select( pdata->s + 1, &fds, NULL, NULL, &tv ) <= 0 )
{
if( pdata->thread_should_die )
break;
else
continue;
}
fromlen = sizeof( from );
readbytes = recvfrom( pdata->s, pdata->udp_buf, UDP_BUF_SIZE, 0, ( struct sockaddr* )&from, &fromlen );
for( i = 0; i < readbytes; i ++ )
{
if( pdata->thread_should_die )
break;
sem_wait( &mux_w_sem );
mux_data.data = pdata->udp_buf[ i ];
mux_data.id = pdata->service_id;
sem_post( &mux_r_sem );
}
if( pdata->thread_should_die )
break;
}
return NULL;
}
static void* service_thread_textctrl( void* data )
{
#ifdef MUX_THREAD_MODE
int c;
THREAD_DATA *pdata = ( THREAD_DATA* )data;
log_msg( "Starting wxTextCtrl service thread\n" );
while( 1 )
{
#if 0
sem_wait( &textctrl_data.count_sem );
if( ( c = textctrl_data.pdata[ textctrl_data.r_idx ] ) == -1 )
break;
textctrl_data.r_idx = ( textctrl_data.r_idx + 1 ) % textctrl_data.total;
#else
sem_wait( &pdata->textctrl_sem );
if( ( c = pdata->textctrl_data ) == -1 )
break;
#endif
sem_wait( &mux_w_sem );
mux_data.data = c;
mux_data.id = pdata->service_id;
sem_post( &mux_r_sem );
}
#endif
return NULL;
}
static const p_thread_func mux_service_funcs[] = { NULL, service_thread_ser, service_thread_udp, service_thread_textctrl };
// *****************************************************************************
// Transport thread
static void* transport_thread( void* data )
{
int sdata;
THREAD_DATA *pdata = ( THREAD_DATA* )data;
log_msg( "Starting transport thread\n" );
while( 1 )
{
if( ( sdata = transport_read_byte() ) == -1 )
{
if( pdata->thread_should_die )
break;
else
continue;
}
sem_wait( &mux_w_sem );
mux_data.data = sdata;
mux_data.id = TRANSPORT_SERVICE_ID;
sem_post( &mux_r_sem );
}
return NULL;
}
// *****************************************************************************
// Transport aware byte send function
static void byte_send( THREAD_DATA *data, u8 d )
{
if( data->type == TRANSPORT_TYPE_SER )
ser_write_byte( data->fd, d );
else if( data->type == TRANSPORT_TYPE_UDP )
sendto( data->s, &d, 1, 0, ( struct sockaddr* )&data->server, sizeof( data->server ) );
else
textctrl_put_char( d );
}
// ****************************************************************************
// Program entry point
#define MAIN_TRANSPORT_IDX 1
#define SERVICE_BAUD_IDX 2
#define RFS_DIRNAME_IDX 3
#define FIRST_SERVICE_IDX 4
int mux_init( int argc, char **argv )
{
unsigned i;
THREAD_DATA *tdata;
struct hostent *hp;
// Setup networking in Windows
#ifdef WIN32_BUILD
// The socket subsystem must be initialized if working in Windows
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 0 );
err = WSAStartup( wVersionRequested, &wsaData );
if( err != 0 )
{
log_err( "Unable to initialize the socket subsystem\n" );
return 1;
}
#endif // #ifdef WIN32_BUILD
// Interpret arguments
if( argc < FIRST_SERVICE_IDX + 1 )
{
log_err( "Usage: %s <transport> <baud> <rfs_dir_name> <vcom1> [<vcom2>] ... [<vcomn>] [-v]\n", argv[ 0 ] );
return 1;
}
i = argc - 1;
if( !strcasecmp( argv[ i ], "-v" ) )
{
i --;
log_init( LOG_ALL );
}
else
log_init( LOG_NONE );
if( ( vport_num = i - 3 ) > SERVICE_MAX )
{
log_err( "Too many service ports, maximum is %d\n", SERVICE_MAX );
return 1;
}
if( parse_transport( argv[ MAIN_TRANSPORT_IDX ] ) == 0 )
return 1;
if( secure_atoi( argv[ SERVICE_BAUD_IDX ], &service_baud ) == 0 )
{
log_err( "Invalid service baud\n" );
return 1;
}
if( !os_isdir( argv[ RFS_DIRNAME_IDX ] ) )
{
log_err( "Invalid directory %s\n", argv[ RFS_DIRNAME_IDX ] );
return 1;
}
if( transport_init() == 0 )
return 1;
if( rfs_server_init( RFS_SERVER_PORT, argv[ RFS_DIRNAME_IDX ] ) == 0 )
return 1;
// Create global sync objects
sem_init( &mux_w_sem, 0, 1 );
sem_init( &mux_r_sem, 0, 0 );
// Open all the service ports and create their corresponding threads
if( ( threads = ( THREAD_DATA* )malloc( sizeof( THREAD_DATA ) * ( vport_num + 2 ) ) ) == NULL )
{
log_err( "Not enough memory\n" );
return 1;
}
memset( threads, 0, sizeof( THREAD_DATA ) * ( vport_num + 2 ) );
// Thread map:
// index 0 : UDP thread (ALWAYS first service ID!)
// 1 ... vport_num : actual serial ports
// (1 is connected to the console wxTextCtrl in frontend mode)
// vport_num + 1: transport thread
for( i = 0; i <= vport_num + 1; i ++ )
{
tdata = threads + i;
tdata->thread_should_die = 0;
if( i <= vport_num )
{
if( i == TEXTCTRL_THREAD_IDX )
{
sem_init( &tdata->textctrl_sem, 0, 0 );
tdata->type = TRANSPORT_TYPE_TEXTCTRL;
}
else if( i == RFS_UDP_THREAD_IDX )
{
tdata->s = INVALID_SOCKET_VALUE;
if( ( tdata->udp_buf = ( u8* )malloc( UDP_BUF_SIZE ) ) == NULL )
{
log_err( "Unable to allocate UDP buffer\n" );
return 1;
}
// UDP thread
if( ( tdata->s = socket( AF_INET, SOCK_DGRAM, 0 ) ) == INVALID_SOCKET_VALUE )
{
log_err( "Error creating socket\n" );
return 1;
}
tdata->server.sin_family = AF_INET;
hp = gethostbyname( "127.0.0.1" );
memcpy( &tdata->server.sin_addr, hp->h_addr, hp->h_length );
tdata->server.sin_port = htons( RFS_SERVER_PORT );
tdata->type = TRANSPORT_TYPE_UDP;
tdata->port = RFS_SERVER_PORT;
sem_init( &tdata->udp_sem, 0, 0 );
}
else
{
// Serial thread
if( ( tdata->fd = ser_open( argv[ i - 1 + FIRST_SERVICE_IDX ] ) ) == ( ser_handler )-1 )
{
log_err( "Unable to open port %s\n", argv[ i - 1 + FIRST_SERVICE_IDX ] );
return 1;
}
if( ser_setup( tdata->fd, service_baud, SER_DATABITS_8, SER_PARITY_NONE, SER_STOPBITS_1 ) != SER_OK )
{
log_err( "Unable to setup serial port %s\n", argv[ i - 1 + FIRST_SERVICE_IDX ] );
return 1;
}
tdata->type = TRANSPORT_TYPE_SER;
tdata->pname = argv[ i - 1 + FIRST_SERVICE_IDX ];
}
tdata->service_id = i + SERVICE_ID_FIRST;
}
if( pthread_create( &tdata->tid, NULL, i <= vport_num ? mux_service_funcs[ tdata->type ] : transport_thread, tdata ) )
{
log_err( "Unable to create transport thread\n" );
return 1;
}
tdata->thread_created = 1;
}
// Create rfs_server thread
if( pthread_create( &rfs_thread_id, NULL, rfs_thread, argv[ RFS_DIRNAME_IDX ] ) )
{
log_err( "Unable to create RFS thread\n" );
return 1;
}
rfs_thread_created = 1;
return 0;
}
void mux_cleanup()
{
unsigned i;
THREAD_DATA *tdata;
if( threads )
{
// Thread map:
// index 0 : UDP thread (ALWAYS first service ID!)
// 1 ... vport_num : actual serial ports
// vport_num + 1: transport thread
for( i = 0; i <= vport_num + 1; i ++ )
{
tdata = threads + i;
if( tdata->thread_created == 1 )
{
if( i == TEXTCTRL_THREAD_IDX )
textctrl_get_char( -1 );
tdata->thread_should_die = 1;
pthread_join( tdata->tid, NULL );
}
if( i <= vport_num )
{
if( i == TEXTCTRL_THREAD_IDX )
sem_destroy( &tdata->textctrl_sem );
else if( i == RFS_UDP_THREAD_IDX )
{
free( tdata->udp_buf );
if( tdata->s != INVALID_SOCKET_VALUE )
socket_close( tdata->s );
sem_destroy( &tdata->udp_sem );
}
else
{
// Serial thread
if( tdata->fd && tdata->fd != ( ser_handler )-1 )
ser_close( tdata->fd );
}
}
}
free( threads );
threads = NULL;
}
if( rfs_thread_created )
{
rfs_thread_should_die = 1;
pthread_join( rfs_thread_id, NULL );
}
rfs_server_cleanup();
transport_cleanup();
sem_destroy( &mux_w_sem );
sem_destroy( &mux_r_sem );
// Re-init globals
vport_num = 0;
transport_type = TRANSPORT_TYPE_ERROR;
service_baud = 0;
service_id_in = -1;
service_id_out = -1;
rfs_thread_created = 0;
mux_thread_running = 0;
}
#if defined( MUX_STANDALONE_MODE )
#define RETVAL 1
#define RETVAL_TYPE int
#elif defined( MUX_THREAD_MODE )
#define RETVAL NULL
#define RETVAL_TYPE void*
void mux_thread_stop()
{
sem_wait( &mux_w_sem );
mux_data.id = THREAD_STOP_SERVICE_ID;
sem_post( &mux_r_sem );
}
#else
#error "Operating mode (standalone or thread) not defined"
#endif
RETVAL_TYPE mux_thread( void *pdata )
{
int c, prev_sent = -1;
int temp, sdata;
int got_esc = 0;
DATA data;
log_msg( "Starting service multiplexer on %u port(s) and RFS server\n", vport_num );
// Main service thread
while( 1 )
{
sem_wait( &mux_r_sem );
data = mux_data;
sem_post( &mux_w_sem );
if( data.id == THREAD_STOP_SERVICE_ID )
break;
if( data.id == TRANSPORT_SERVICE_ID )
{
// Read one byte, interpret it
c = data.data;
if( c != ESCAPE_CHAR )
{
if( c >= SERVICE_ID_FIRST && c <= SERVICE_ID_LAST )
service_id_in = c;
else if( c == FORCE_SID_CHAR && prev_sent != -1 )
{
// Re-transmit the last data AND the service ID
transport_send_byte( service_id_out );
if( prev_sent & ESC_MASK )
transport_send_byte( ESCAPE_CHAR );
transport_send_byte( prev_sent & 0xFF );
}
else
{
if( got_esc )
{
// Got an escape last time, check the char now (with the 5th bit flipped)
c ^= ESCAPE_XOR_MASK;
if( c != ESCAPE_CHAR && c != FORCE_SID_CHAR && ( c < SERVICE_ID_FIRST || c > SERVICE_ID_LAST ) )
{
log_err( "Protocol error: invalid escape sequence\n" );
break;
}
got_esc = 0;
}
if( service_id_in == -1 )
{
transport_send_byte( FORCE_SID_CHAR );
log_msg( "Requested resend of service ID\n" );
}
else
byte_send( threads + service_id_in - SERVICE_ID_FIRST, c );
}
}
else
got_esc = 1;
}
else
{
temp = data.id;
sdata = data.data;
if( temp != service_id_out )
transport_send_byte( temp );
prev_sent = sdata;
// Then send the actual data byte, escaping it if needed
if( sdata == ESCAPE_CHAR || sdata == FORCE_SID_CHAR || ( sdata >= SERVICE_ID_FIRST && sdata <= SERVICE_ID_LAST ) )
{
transport_send_byte( ESCAPE_CHAR );
transport_send_byte( ( u8 )sdata ^ ESCAPE_XOR_MASK );
prev_sent = ESC_MASK | ( ( u8 )sdata ^ ESCAPE_XOR_MASK );
}
else
transport_send_byte( sdata );
service_id_out = temp;
}
}
mux_thread_running = 0;
return RETVAL;
}
#ifdef MUX_STANDALONE_MODE
int main( int argc, char **argv )
{
if( mux_init( argc, argv ) )
return RETVAL;
return mux_thread( NULL );
}
#endif

View File

@ -3,7 +3,8 @@ import os, sys, platform
sim = ARGUMENTS.get( 'sim', '0' )
flist = ""
cdefs = ""
cdefs = "-DRFS_STANDALONE_MODE"
socklib = ''
if sim == '0':
mainname = "main.c"
else:
@ -12,30 +13,27 @@ if platform.system() == "Windows":
if sim == '1':
print "SIM target not supported under Windows"
os.exit( 1 )
flist = "main.c server.c client.c os_io_win32.c log.c"
cdefs = "-DWIN32_BUILD"
exeprefix = "exe"
flist = "main.c server.c os_io_win32.c log.c net_win32.c serial_win32.c deskutils.c"
cdefs = cdefs + " -DWIN32_BUILD"
exeprefix = ".exe"
socklib = '-lws2_32'
else:
flist = "%s server.c client.c os_io_posix.c log.c" % mainname
exeprefix = "elf"
flist = "%s server.c os_io_posix.c log.c net_posix.c serial_posix.c deskutils.c" % mainname
exeprefix = ""
if sim == '0':
output = 'rfs_server.%s' % exeprefix
output = 'rfs_server%s' % exeprefix
else:
output = 'rfs_sim_server.%s' % exeprefix
output = 'rfs_sim_server%s' % exeprefix
#endif
full_files = " " + " ".join( [ "rfs_server/%s" % name for name in flist.split() ] )
full_files = full_files + " src/remotefs/remotefs.c"
if platform.system() == "Windows":
full_files = full_files + " rfs_server/serial_win32.c"
else:
full_files = full_files + " rfs_server/serial_posix.c"
local_include = "-Irfs_server -Iinc/remotefs"
full_files = " " + " ".join( [ "rfs_server_src/%s" % name for name in flist.split() ] )
full_files = full_files + " src/remotefs/remotefs.c src/eluarpc.c"
local_include = "-Irfs_server_src -Iinc/remotefs -Iinc"
# Compiler/linker options
cccom = "gcc -m32 -O0 -g %s -Wall %s -c $SOURCE -o $TARGET" % ( local_include, cdefs )
linkcom = "gcc -m32 -o $TARGET $SOURCES"
linkcom = "gcc -m32 -o $TARGET $SOURCES %s" % socklib
# Env for building the program
comp = Environment( CCCOM = cccom,

View File

@ -1,139 +0,0 @@
// Remote filesystem client
#include <string.h>
#include "remotefs.h"
#include "client.h"
#include "os_io.h"
// ****************************************************************************
// Client local data
static u8 *rfsc_buffer;
static p_rfsc_send rfsc_send;
static p_rfsc_recv rfsc_recv;
static u32 rfsc_timeout;
// ****************************************************************************
// Client helpers
static int rfsch_send_request_read_response()
{
u16 temp16;
// Send request
if( remotefs_get_packet_size( rfsc_buffer, &temp16 ) == REMOTEFS_ERR )
return CLIENT_ERR;
if( rfsc_send( rfsc_buffer, temp16 ) != temp16 )
return CLIENT_ERR;
// Get response
// First the length, then the rest of the data
if( rfsc_recv( rfsc_buffer, RFS_START_OFFSET, rfsc_timeout ) != RFS_START_OFFSET )
return CLIENT_ERR;
if( remotefs_get_packet_size( rfsc_buffer, &temp16 ) == REMOTEFS_ERR )
return CLIENT_ERR;
if( rfsc_recv( rfsc_buffer + RFS_START_OFFSET, temp16 - RFS_START_OFFSET, rfsc_timeout ) != temp16 - RFS_START_OFFSET )
return CLIENT_ERR;
return CLIENT_OK;
}
// ****************************************************************************
// Client public interface
void rfsc_setup( u8 *pbuf, p_rfsc_send rfsc_send_func, p_rfsc_recv rfsc_recv_func, u32 timeout )
{
rfsc_buffer = pbuf;
rfsc_send = rfsc_send_func;
rfsc_recv = rfsc_recv_func;
rfsc_timeout = timeout;
}
void rfsc_set_timeout( u32 timeout )
{
rfsc_timeout = timeout;
}
int rfsc_open( const char* pathname, int flags, int mode )
{
int fd;
// Make the request
remotefs_open_write_request( rfsc_buffer, pathname, os_open_sys_flags_to_rfs_flags( flags ), mode );
// Send the request / get the respone
if( rfsch_send_request_read_response() == CLIENT_ERR )
return -1;
// Interpret the response
if( remotefs_open_read_response( rfsc_buffer, &fd ) == REMOTEFS_ERR )
return -1;
return fd;
}
s32 rfsc_write( int fd, const void *buf, u32 count )
{
// Make the request
remotefs_write_write_request( rfsc_buffer, fd, buf, count );
// Send the request / get the response
if( rfsch_send_request_read_response() == CLIENT_ERR )
return -1;
// Interpret the response
if( remotefs_write_read_response( rfsc_buffer, &count ) == REMOTEFS_ERR )
return -1;
return ( s32 )count;
}
s32 rfsc_read( int fd, void *buf, u32 count )
{
const u8 *resbuf;
// Make the request
remotefs_read_write_request( rfsc_buffer, fd, count );
// Send the request / get the response
if( rfsch_send_request_read_response() == CLIENT_ERR )
return -1;
// Interpret the response
if( remotefs_read_read_response( rfsc_buffer, &resbuf, &count ) == REMOTEFS_ERR )
return -1;
memcpy( buf, resbuf, count );
return ( s32 )count;
}
s32 rfsc_lseek( int fd, s32 offset, int whence )
{
s32 res;
// Make the request
remotefs_lseek_write_request( rfsc_buffer, fd, offset, os_lseek_sys_whence_to_rfs_whence( whence ) );
// Send the request / get the response
if( rfsch_send_request_read_response() == CLIENT_ERR )
return -1;
// Interpret the response
if( remotefs_lseek_read_response( rfsc_buffer, &res ) == REMOTEFS_ERR )
return -1;
return res;
}
int rfsc_close( int fd )
{
int res;
// Make the request
remotefs_close_write_request( rfsc_buffer, fd );
// Send the request / get the response
if( rfsch_send_request_read_response() == CLIENT_ERR )
return -1;
// Interpret the response
if( remotefs_close_read_response( rfsc_buffer, &res ) == REMOTEFS_ERR )
return -1;
return res;
}

View File

@ -1,26 +0,0 @@
// Remote filesystem client
#ifndef __CLIENT_H__
#define __CLIENT_H__
#include "type.h"
// Error codes
#define CLIENT_OK 0
#define CLIENT_ERR 1
// RFS client send/receive functions
typedef u32 ( *p_rfsc_send )( const u8 *p, u32 size );
typedef u32 ( *p_rfsc_recv )( u8 *p, u32 size, u32 timeout );
// Public interface
void rfsc_setup( u8 *pbuf, p_rfsc_send rfsc_send_func, p_rfsc_recv rfsc_recv_func, u32 timeout );
void rfsc_set_timeout( u32 timeout );
int rfsc_open( const char* pathname, int flags, int mode );
s32 rfsc_write( int fd, const void *buf, u32 count );
s32 rfsc_read( int fd, void *buf, u32 count );
s32 rfsc_lseek( int fd, s32 offset, int whence );
int rfsc_close( int fd );
#endif

View File

@ -1,165 +0,0 @@
// Remote FS server
#include "remotefs.h"
#include "serial.h"
#include "server.h"
#include "type.h"
#include "log.h"
#include "os_io.h"
#include <stdio.h>
#include <limits.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
// ****************************************************************************
// Local variables
#define MAX_PACKET_SIZE 4096
static u8 rfs_buffer[ MAX_PACKET_SIZE + RFS_WRITE_REQUEST_EXTRA ];
static ser_handler ser;
// ****************************************************************************
// Helpers
static void flush_serial()
{
// Flush all data in serial port
ser_set_timeout_ms( ser, SER_NO_TIMEOUT );
while( ser_read_byte( ser ) != -1 );
ser_set_timeout_ms( ser, SER_INF_TIMEOUT );
}
// Read a packet from the serial port
static void read_request_packet()
{
u16 temp16;
u32 readbytes;
while( 1 )
{
// First read the length
if( ( readbytes = ser_read( ser, rfs_buffer, RFS_START_OFFSET ) ) != RFS_START_OFFSET )
{
log_msg( "read_request_packet: ERROR reading packet length. Requested %d bytes, got %d bytes\n", RFS_START_OFFSET, readbytes );
flush_serial();
continue;
}
if( remotefs_get_packet_size( rfs_buffer, &temp16 ) == REMOTEFS_ERR )
{
log_msg( "read_request_packet: ERROR getting packet size.\n" );
flush_serial();
continue;
}
// Then the rest of the data
if( ( readbytes = ser_read( ser, rfs_buffer + RFS_START_OFFSET, temp16 - RFS_START_OFFSET ) ) != temp16 - RFS_START_OFFSET )
{
log_msg( "read_request_packet: ERROR reading full packet, got %u bytes, expected %u bytes\n", ( unsigned )readbytes, ( unsigned )temp16 - RFS_START_OFFSET );
flush_serial();
continue;
}
else
break;
}
}
// Send a packet to the serial port
static void send_response_packet()
{
u16 temp16;
// Send request
if( remotefs_get_packet_size( rfs_buffer, &temp16 ) != REMOTEFS_ERR )
{
log_msg( "send_response_packet: sending response packet of %u bytes\n", ( unsigned )temp16 );
ser_write( ser, rfs_buffer, temp16 );
}
}
// Secure atoi
static int secure_atoi( const char *str, long *pres )
{
char *end_ptr;
long s1;
errno = 0;
s1 = strtol( str, &end_ptr, 10 );
if( ( s1 == LONG_MIN || s1 == LONG_MAX ) && errno != 0 )
return 0;
else if( end_ptr == str )
return 0;
else if( s1 > INT_MAX || s1 < INT_MIN )
return 0;
else if( '\0' != *end_ptr )
return 0;
*pres = s1;
return 1;
}
// ****************************************************************************
// Entry point
#define PORT_ARG_IDX 1
#define SPEED_ARG_IDX 2
#define DIRNAME_ARG_IDX 3
#define VERBOSE_ARG_IDX 4
int main( int argc, const char **argv )
{
long serspeed;
if( argc < 4 )
{
fprintf( stderr, "Usage: %s <port> <speed> <dirname> [-v]\n", argv[ 0 ] );
fprintf( stderr, "(use -v for verbose output).\n");
return 1;
}
if( secure_atoi( argv[ SPEED_ARG_IDX ], &serspeed ) == 0 )
{
fprintf( stderr, "Invalid speed\n" );
return 1;
}
if( !os_isdir( argv[ DIRNAME_ARG_IDX ] ) )
{
fprintf( stderr, "Invalid directory %s\n", argv[ DIRNAME_ARG_IDX ] );
return 1;
}
if( ( argc >= 5 ) && !strcmp( argv[ VERBOSE_ARG_IDX ], "-v" ) )
log_init( LOG_ALL );
else
log_init( LOG_NONE );
// Setup RFS server
server_setup( argv[ DIRNAME_ARG_IDX ] );
// Setup serial port
if( ( ser = ser_open( argv[ PORT_ARG_IDX ] ) ) == ( ser_handler )-1 )
{
fprintf( stderr, "Cannot open port %s\n", argv[ PORT_ARG_IDX ] );
return 1;
}
if( ser_setup( ser, ( u32 )serspeed, SER_DATABITS_8, SER_PARITY_NONE, SER_STOPBITS_1 ) != SER_OK )
{
fprintf( stderr, "Unable to initialize serial port\n" );
return 1;
}
flush_serial();
// User report
printf( "Running RFS server on port %s (%u baud) in directory %s\n", argv[ PORT_ARG_IDX ], ( unsigned )serspeed, argv[ DIRNAME_ARG_IDX ] );
// Enter the server endless loop
while( 1 )
{
read_request_packet();
server_execute_request( rfs_buffer );
send_response_packet();
}
ser_close( ser );
return 0;
}

View File

@ -1,17 +0,0 @@
// Type definitions for the remote file system
#ifndef __RTYPE_H__
#define __RTYPE_H__
// Type codes
#define TYPE_INT_8 0x01
#define TYPE_INT_16 0x02
#define TYPE_INT_32 0x03
#define TYPE_PTR 0x04
#define TYPE_START 0x05
#define TYPE_END 0x06
#define TYPE_OP_ID 0x07
#define TYPE_PKT_SIZE 0xA5
#endif

View File

@ -1,150 +0,0 @@
// Serial inteface implementation for POSIX-compliant systems
#include <windows.h>
#include <string.h>
#include <stdio.h>
#include "type.h"
#include "serial.h"
#define WIN_ERROR ( HANDLE )-1
#define WIN_MAX_PORT_NAME 1024
// Helper: set timeout
static int ser_win32_set_timeouts( HANDLE hComm, DWORD ri, DWORD rtm, DWORD rtc, DWORD wtm, DWORD wtc )
{
COMMTIMEOUTS timeouts;
if( GetCommTimeouts( hComm, &timeouts ) == FALSE )
{
CloseHandle( hComm );
return SER_ERR;
}
timeouts.ReadIntervalTimeout = ri;
timeouts.ReadTotalTimeoutConstant = rtm;
timeouts.ReadTotalTimeoutMultiplier = rtc;
timeouts.WriteTotalTimeoutConstant = wtm;
timeouts.WriteTotalTimeoutMultiplier = wtc;
if( SetCommTimeouts( hComm, &timeouts ) == FALSE )
{
CloseHandle( hComm );
return SER_ERR;
}
return SER_OK;
}
// Open the serial port
ser_handler ser_open( const char* sername )
{
char portname[ WIN_MAX_PORT_NAME + 1 ];
HANDLE hComm;
portname[ 0 ] = portname[ WIN_MAX_PORT_NAME ] = '\0';
_snprintf( portname, WIN_MAX_PORT_NAME, "\\\\.\\%s", sername );
hComm = CreateFile( portname, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0 );
if( hComm == INVALID_HANDLE_VALUE )
return WIN_ERROR;
if( !SetupComm( hComm, 2048, 2048 ) )
return WIN_ERROR;
return hComm;
}
// Close the serial port
void ser_close( ser_handler id )
{
CloseHandle( id );
}
int ser_setup( ser_handler id, u32 baud, int databits, int parity, int stopbits )
{
HANDLE hComm = ( HANDLE )id;
DCB dcb;
if( GetCommState( hComm, &dcb ) == FALSE )
{
CloseHandle( hComm );
return SER_ERR;
}
dcb.BaudRate = baud;
dcb.ByteSize = databits;
dcb.Parity = parity == SER_PARITY_NONE ? NOPARITY : ( parity == SER_PARITY_EVEN ? EVENPARITY : ODDPARITY );
dcb.StopBits = stopbits == SER_STOPBITS_1 ? ONESTOPBIT : ( stopbits == SER_STOPBITS_1_5 ? ONE5STOPBITS : TWOSTOPBITS );
dcb.fBinary = TRUE;
dcb.fDsrSensitivity = FALSE;
dcb.fParity = parity != SER_PARITY_NONE ? TRUE : FALSE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
dcb.fNull = FALSE;
/**/ dcb.fAbortOnError = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fDsrSensitivity = FALSE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fOutxCtsFlow = FALSE;
if( SetCommState( hComm, &dcb ) == 0 )
{
CloseHandle( hComm );
return SER_ERR;
}
if( ser_win32_set_timeouts( hComm, 0, 0, 0, 0, 0 ) == SER_ERR )
{
CloseHandle( hComm );
return SER_ERR;
}
FlushFileBuffers( hComm );
return SER_OK;
}
// Read up to the specified number of bytes, return bytes actually read
u32 ser_read( ser_handler id, u8* dest, u32 maxsize )
{
HANDLE hComm = ( HANDLE )id;
DWORD readbytes;
if( ReadFile( hComm, dest, maxsize, &readbytes, NULL ) == FALSE )
return 0;
return readbytes;
}
// Read a single byte and return it (or -1 for error)
int ser_read_byte( ser_handler id )
{
u8 data;
int res = ser_read( id, &data, 1 );
//printf( "READ %02X, res is %d\n", data, res );
return res == 1 ? data : -1;
}
// Write up to the specified number of bytes, return bytes actually written
u32 ser_write( ser_handler id, const u8 *src, u32 size )
{
HANDLE hComm = ( HANDLE )id;
DWORD written;
if( WriteFile( hComm, src, size, &written, NULL ) == FALSE )
return 0;
return written;
}
// Write a byte to the serial port
u32 ser_write_byte( ser_handler id, u8 data )
{
return ser_write( id, &data, 1 );
}
// Set communication timeout
void ser_set_timeout_ms( ser_handler id, u32 timeout )
{
if( timeout == SER_NO_TIMEOUT )
ser_win32_set_timeouts( id, MAXDWORD, 0, 0, 0, 0 );
else if( timeout == SER_INF_TIMEOUT )
ser_win32_set_timeouts( id, 0, 0, 0, 0, 0 );
else
ser_win32_set_timeouts( id, 0, 0, timeout, 0, 0 );
}

View File

@ -1,24 +0,0 @@
// Type definitions for the remote file system
#ifndef __TYPE_H__
#define __TYPE_H__
typedef char s8;
typedef unsigned char u8;
typedef short s16;
typedef unsigned short u16;
typedef long s32;
typedef unsigned long u32;
typedef long long s64;
typedef unsigned long long u64;
// Define serial port "handle" type for each platform
// [TODO] for now, only UNIX is supported
#ifdef WIN32_BUILD
#include <windows.h>
typedef HANDLE ser_handler;
#else // assume POSIX here
typedef int ser_handler;
#endif
#endif

View File

@ -0,0 +1,40 @@
// Utility functions for desktop programs
#include "deskutils.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
// Secure atoi
int secure_atoi( const char *str, long *pres )
{
char *end_ptr;
long s1;
errno = 0;
s1 = strtol( str, &end_ptr, 10 );
if( ( s1 == LONG_MIN || s1 == LONG_MAX ) && errno != 0 )
return 0;
else if( end_ptr == str )
return 0;
else if( s1 > INT_MAX || s1 < INT_MIN )
return 0;
else if( '\0' != *end_ptr )
return 0;
*pres = s1;
return 1;
}
// Local strndup function to compensate the lack of strndup in Windows
char* l_strndup( const char* s, size_t n )
{
char* p;
if( ( p = ( char* )malloc( n + 1 ) ) == NULL )
return NULL;
p [ 0 ] = p[ n ] = '\0';
strncpy( p, s, n );
return p;
}

View File

@ -0,0 +1,12 @@
// Utility functions for desktop programs
#ifndef __DESKUTILS_H__
#define __DESKUTILS_H__
#include "type.h"
#include <stddef.h>
int secure_atoi( const char *str, long *pres );
char* l_strndup( const char* s, size_t n );
#endif

View File

@ -22,3 +22,14 @@ void log_msg( const char *msg, ... )
va_end( va );
}
}
void log_err( const char *msg, ... )
{
va_list va;
va_start( va, msg );
vfprintf( stderr, msg, va );
va_end( va );
}

View File

@ -9,5 +9,8 @@
void log_init( int level );
void log_msg( const char *msg, ... );
void log_err( const char* msg, ... );
#define LOG_SET_MODULE
#endif

451
rfs_server_src/main.c Normal file
View File

@ -0,0 +1,451 @@
// Remote FS server
#include "net.h"
#include "remotefs.h"
#include "eluarpc.h"
#include "serial.h"
#include "server.h"
#include "type.h"
#include "log.h"
#include "os_io.h"
#include <stdio.h>
#include <limits.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "rfs.h"
#include "deskutils.h"
// ****************************************************************************
// Local definitions
typedef void ( *p_read_request )( void );
typedef void ( *p_send_response )( void );
typedef void ( *p_cleanup )( void );
typedef struct
{
p_read_request f_read_request;
p_send_response f_send_response;
p_cleanup f_cleanup;
} RFS_TRANSPORT_DATA;
// ****************************************************************************
// Local variables
#define MAX_PACKET_SIZE 4096
static u8 rfs_buffer[ MAX_PACKET_SIZE + ELUARPC_WRITE_REQUEST_EXTRA ];
static const RFS_TRANSPORT_DATA *p_transport_data;
// ****************************************************************************
// Serial transport implementation
static ser_handler ser;
static void flush_serial()
{
// Flush all data in serial port
while( ser_read_byte( ser, SER_NO_TIMEOUT ) != -1 );
}
// Read a packet from the serial port
static void ser_read_request_packet()
{
u16 temp16;
u32 readbytes;
while( 1 )
{
// First read the length
if( ( readbytes = ser_read( ser, rfs_buffer, ELUARPC_START_OFFSET, SER_INF_TIMEOUT ) ) != ELUARPC_START_OFFSET )
{
log_msg( "read_request_packet: ERROR reading packet length. Requested %d bytes, got %d bytes\n", ELUARPC_START_OFFSET, readbytes );
flush_serial();
continue;
}
if( eluarpc_get_packet_size( rfs_buffer, &temp16 ) == ELUARPC_ERR )
{
log_msg( "read_request_packet: ERROR getting packet size.\n" );
flush_serial();
continue;
}
// Then the rest of the data
if( ( readbytes = ser_read( ser, rfs_buffer + ELUARPC_START_OFFSET, temp16 - ELUARPC_START_OFFSET, SER_INF_TIMEOUT ) ) != temp16 - ELUARPC_START_OFFSET )
{
log_msg( "read_request_packet: ERROR reading full packet, got %u bytes, expected %u bytes\n", ( unsigned )readbytes, ( unsigned )temp16 - ELUARPC_START_OFFSET );
flush_serial();
continue;
}
else
break;
}
}
// Send a packet to the serial port
static void ser_send_response_packet()
{
u16 temp16;
// Send request
if( eluarpc_get_packet_size( rfs_buffer, &temp16 ) != ELUARPC_ERR )
{
log_msg( "send_response_packet: sending response packet of %u bytes\n", ( unsigned )temp16 );
ser_write( ser, rfs_buffer, temp16 );
}
}
static int ser_server_init( const char *portname, int serspeed, int flow )
{
// Setup serial port
if( ( ser = ser_open( portname ) ) == SER_HANDLER_INVALID )
{
log_err( "Cannot open port %s\n", portname );
return 0;
}
if( ser_setup( ser, ( u32 )serspeed, SER_DATABITS_8, SER_PARITY_NONE, SER_STOPBITS_1, flow ) != SER_OK )
{
log_err( "Unable to initialize serial port\n" );
return 0;
}
flush_serial();
// User report
log_msg( "Running RFS server on serial port %s (%u baud).\n", portname, ( unsigned )serspeed );
return 1;
}
static void ser_cleanup()
{
ser_close( ser );
}
static const RFS_TRANSPORT_DATA ser_transport_data = { ser_read_request_packet, ser_send_response_packet, ser_cleanup };
// ****************************************************************************
// UDP transport implementation
static NET_SOCKET trans_socket = INVALID_SOCKET_VALUE;
static struct sockaddr_in trans_from;
// Helper: read (blocking) the specified number of bytes
static void udp_read_helper( u8 *dest, u32 size )
{
socklen_t fromlen;
int readbytes;
while( size )
{
fromlen = sizeof( trans_from );
readbytes = net_recvfrom( trans_socket, ( char* )dest, size, 0, ( struct sockaddr* )&trans_from, &fromlen, NET_INF_TIMEOUT );
size -= readbytes;
if( size == 0 )
break;
dest += readbytes;
}
}
static void udp_read_request_packet()
{
u16 temp16;
while( 1 )
{
// First read the length
udp_read_helper( rfs_buffer, ELUARPC_START_OFFSET );
if( eluarpc_get_packet_size( rfs_buffer, &temp16 ) == ELUARPC_ERR )
{
log_msg( "read_request_packet: ERROR getting packet size.\n" );
continue;
}
// Then the rest of the data
udp_read_helper( rfs_buffer + ELUARPC_START_OFFSET, temp16 - ELUARPC_START_OFFSET );
break;
}
}
static void udp_send_response_packet()
{
u16 temp16;
// Send request
if( eluarpc_get_packet_size( rfs_buffer, &temp16 ) != ELUARPC_ERR )
{
log_msg( "send_response_packet: sending response packet of %u bytes\n", ( unsigned )temp16 );
net_sendto( trans_socket, ( char* )rfs_buffer, temp16, 0, ( struct sockaddr* )&trans_from, sizeof( trans_from ) );
}
}
static int udp_server_init( unsigned server_port )
{
int length;
struct sockaddr_in server;
if( ( trans_socket = net_create_socket( AF_INET, SOCK_DGRAM, 0 ) ) == INVALID_SOCKET_VALUE )
{
log_err( "Unable to create socket\n" );
return 1;
}
length = sizeof( server );
memset( &server, 0, sizeof( server ) );
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( server_port );
if( bind( net_socket( trans_socket ), ( struct sockaddr * )&server, length ) < 0 )
{
log_err( "Unable to bind socket\n" );
return 0;
}
log_msg( "Running RFS server on UDP port %u.\n", ( unsigned )server_port );
return 1;
}
static void udp_cleanup()
{
net_close( trans_socket );
}
static const RFS_TRANSPORT_DATA udp_transport_data = { udp_read_request_packet, udp_send_response_packet, udp_cleanup };
// ****************************************************************************
// Memory transport implementation
// Read state machine
enum
{
MEM_STATE_READ_LENGTH,
MEM_STATE_READ_REQUEST,
MEM_STATE_REQUEST_DONE
};
static int mem_read_len;
static int mem_expected_len;
static int mem_read_state;
static int mem_response_flag;
void rfs_mem_start_request()
{
mem_read_state = MEM_STATE_READ_LENGTH;
mem_read_len = mem_expected_len = 0;
mem_response_flag = 0;
}
int rfs_mem_read_request_packet( int c )
{
u16 temp16;
int res = 1;
if( c == -1 )
{
rfs_mem_start_request();
return 0;
}
switch( mem_read_state )
{
case MEM_STATE_READ_LENGTH:
rfs_buffer[ mem_read_len ++ ] = c;
if( mem_read_len == ELUARPC_START_OFFSET )
{
mem_read_len = 0;
if( eluarpc_get_packet_size( rfs_buffer, &temp16 ) == ELUARPC_ERR )
{
log_msg( "RFS read_request_packet: ERROR getting packet size.\n" );
mem_read_state = MEM_STATE_REQUEST_DONE;
res = 0;
}
else
{
mem_read_state = MEM_STATE_READ_REQUEST;
mem_expected_len = temp16 - ELUARPC_START_OFFSET;
}
}
break;
case MEM_STATE_READ_REQUEST:
rfs_buffer[ ELUARPC_START_OFFSET + mem_read_len ] = c;
mem_read_len ++;
if( mem_read_len == mem_expected_len )
{
mem_read_state = MEM_STATE_REQUEST_DONE;
mem_response_flag = 1;
}
break;
}
return res;
}
int rfs_mem_has_response()
{
return mem_response_flag;
}
void rfs_mem_write_response( u16 *plen, u8 **pdata )
{
// Execute request
server_execute_request( rfs_buffer );
// Send response
if( eluarpc_get_packet_size( rfs_buffer, plen ) != ELUARPC_ERR )
{
log_msg( "send_response_packet: sending response packet of %u bytes\n", ( unsigned )*plen );
*pdata = rfs_buffer;
}
else
{
log_msg( "ERROR in send_response_packet!\n" );
*plen = 0;
}
}
static int mem_server_init()
{
rfs_mem_start_request();
log_msg( "RFS: using memory transport.\n" );
return 1;
}
static const RFS_TRANSPORT_DATA mem_transport_data = { NULL, NULL, NULL };
// ****************************************************************************
// Helper functions
// Transport parser
static int parse_transport_and_init( const char* s )
{
const char *c, *c2;
char *temps, *tempb;
long tempi;
int flow;
if( strstr( s, "ser:" ) == s )
{
p_transport_data = &ser_transport_data;
s += strlen( "ser:" );
if( ( c = strchr( s, ',' ) ) == NULL )
{
log_err( "Invalid serial transport syntax\n" );
return 0;
}
temps = l_strndup( s, c - s );
if( ( c2 = strchr( c + 1, ',' ) ) == NULL )
{
log_err( "Invalid serial transport syntax.\n" );
return 0;
}
tempb = l_strndup( c + 1, c2 - c - 1 );
if( secure_atoi( tempb, &tempi ) == 0 )
{
log_err( "Invalid port speed\n" );
return 0;
}
free( tempb );
if( !strcmp( c2 + 1, "none" ) )
flow = SER_FLOW_NONE;
else if( !strcmp( c2 + 1, "rtscts" ) )
flow = SER_FLOW_RTSCTS;
else
{
log_err( "Invalid flow control type.\n" );
return 0;
}
tempi = ser_server_init( temps, tempi, flow );
free( temps );
return tempi;
}
else if( strstr( s, "udp:" ) == s )
{
p_transport_data = &udp_transport_data;
s += strlen( "udp:" );
if( secure_atoi( s, &tempi ) == 0 )
{
log_err( "Invalid port number\n" );
return 0;
}
if( net_init() == 0 )
{
log_err( "Unable to initialize network\n" );
return 0;
}
return udp_server_init( tempi );
}
else if( !strcmp( s, "mem" ) )
{
// Direct memory transport, only used with mux in rfsmux mode
p_transport_data = &mem_transport_data;
return mem_server_init( tempi );
}
log_err( "Error: unsupported transport\n" );
return 0;
}
// *****************************************************************************
// Entry point
#define TRANSPORT_ARG_IDX 1
#define DIRNAME_ARG_IDX 2
#define VERBOSE_ARG_IDX 3
#define MIN_ARGC_COUNT 3
#define VERBOSE_ARGC_COUNT 4
int rfs_init( int argc, const char **argv )
{
setvbuf( stdout, NULL, _IONBF, 0 );
if( argc < MIN_ARGC_COUNT )
{
log_err( "Usage: %s <transport> <dirname> [-v]\n", argv[ 0 ] );
log_err( " Serial transport: 'ser:<sername>,<serspeed>,<flow> ('flow' defines the flow control and can be either 'none' or 'rtscts')\n" );
log_err( " UDP transport: 'udp:<port>'\n" );
log_err( "Use -v for verbose output.\n" );
return 1;
}
if( ( argc >= VERBOSE_ARGC_COUNT ) && !strcmp( argv[ VERBOSE_ARG_IDX ], "-v" ) )
log_init( LOG_ALL );
else
log_init( LOG_NONE );
if( !os_isdir( argv[ DIRNAME_ARG_IDX ] ) )
{
log_err( "Invalid directory %s\n", argv[ DIRNAME_ARG_IDX ] );
return 1;
}
if( parse_transport_and_init( argv[ TRANSPORT_ARG_IDX ] ) == 0 )
return 1;
// Setup RFS server
server_setup( argv[ DIRNAME_ARG_IDX ] );
log_msg( "Sharing directory %s\n", argv[ DIRNAME_ARG_IDX ] );
return 0;
}
#ifdef RFS_STANDALONE_MODE
int main( int argc, const char **argv )
{
// Initialize data
if( rfs_init( argc, argv ) != 0 )
return 1;
// 'mem' transport doesn't work in this mode
if( p_transport_data == &mem_transport_data )
{
log_err( "Invalid transport in standalone mode.\n" );
return 1;
}
// Enter the server endless loop
while( 1 )
{
p_transport_data->f_read_request();
server_execute_request( rfs_buffer );
p_transport_data->f_send_response();
}
p_transport_data->f_cleanup();
return 0;
}
#endif

45
rfs_server_src/net.h Normal file
View File

@ -0,0 +1,45 @@
// Network functions
#ifndef __NETINIT_H__
#define __NETINIT_H__
typedef int net_ssize_t;
#ifdef WIN32_BUILD
#include <winsock2.h>
#include <windows.h>
typedef int socklen_t;
#define INVALID_SOCKET_VALUE NULL
typedef struct
{
SOCKET s;
OVERLAPPED o;
} NET_DATA;
typedef NET_DATA* NET_SOCKET;
#define net_socket( d ) ( d )->s
typedef HANDLE net_sync_object;
#else // #ifdef WIN32_BUILD
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/select.h>
typedef int NET_SOCKET;
#define INVALID_SOCKET_VALUE ( -1 )
#define net_socket( s ) s
typedef int net_sync_object;
#endif // #ifdef WIN32_BUILD
#define NET_INF_TIMEOUT ( -1 )
int net_init();
NET_SOCKET net_create_socket( int domain, int type, int protocol );
net_ssize_t net_recvfrom( NET_SOCKET s, void *buf, size_t len, int flags, struct sockaddr* from, socklen_t *fromlen, int timeout );
net_ssize_t net_sendto( NET_SOCKET s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen );
int net_close( NET_SOCKET s );
net_sync_object net_get_sync_object( NET_SOCKET s );
#endif

View File

@ -0,0 +1,50 @@
// Network functions (POSIX)
#include "net.h"
#include "log.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <sys/select.h>
#include <unistd.h>
int net_init()
{
return 1;
}
NET_SOCKET net_create_socket( int domain, int type, int protocol )
{
return socket( domain, type, protocol );
}
net_ssize_t net_recvfrom( NET_SOCKET s, void *buf, size_t len, int flags, struct sockaddr* from, socklen_t *fromlen, int timeout )
{
fd_set fds;
struct timeval tv;
FD_ZERO( &fds );
FD_SET( s, &fds );
tv.tv_sec = timeout / 1000000;
tv.tv_usec = ( timeout % 1000000 ) * 1000;
if( select( s + 1, &fds, NULL, NULL, timeout == NET_INF_TIMEOUT ? NULL : &tv ) <= 0 )
return 0;
return recvfrom( s, buf, len, flags, from, fromlen );
}
net_ssize_t net_sendto( NET_SOCKET s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen )
{
return sendto( s, buf, len, flags, to, tolen );
}
int net_close( NET_SOCKET s )
{
return close( s );
}
net_sync_object net_get_sync_object( NET_SOCKET s )
{
return s;
}

102
rfs_server_src/net_win32.c Normal file
View File

@ -0,0 +1,102 @@
// Network functions (WIN32)
#include "net.h"
#include <stdlib.h>
#include <string.h>
#include "log.h"
int net_init()
{
// The socket subsystem must be initialized if working in Windows
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 0 );
err = WSAStartup( wVersionRequested, &wsaData );
if( err != 0 )
{
log_err( "Unable to initialize the socket subsystem\n" );
return 0;
}
return 1;
}
NET_SOCKET net_create_socket( int domain, int type, int protocol )
{
SOCKET s;
NET_SOCKET d;
if( ( s = WSASocket( domain, type, protocol, NULL, 0, WSA_FLAG_OVERLAPPED ) ) == INVALID_SOCKET )
return INVALID_SOCKET_VALUE;
if( ( d = malloc( sizeof( NET_DATA ) ) ) == NULL )
{
closesocket( s );
return INVALID_SOCKET_VALUE;
}
memset( d, 0, sizeof( NET_DATA ) );
d->s = s;
if( ( d->o.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) ) == NULL )
{
closesocket( s );
return INVALID_SOCKET_VALUE;
}
return d;
}
net_ssize_t net_recvfrom( NET_SOCKET s, void *buf, size_t len, int flags, struct sockaddr* from, socklen_t *fromlen, int timeout )
{
DWORD readbytes = 0;
DWORD rflags = ( DWORD )flags;
BOOL dwRes;
DWORD selflags;
WSABUF datadesc = { len, buf };
ResetEvent( s->o.hEvent );
if( WSARecvFrom( s->s, &datadesc, 1, &readbytes, &rflags, from, fromlen, &s->o, NULL ) == SOCKET_ERROR )
{
if( WSAGetLastError() != WSA_IO_PENDING )
return 0;
}
else
return readbytes;
dwRes = WaitForSingleObject( s->o.hEvent, timeout == NET_INF_TIMEOUT ? INFINITE : timeout );
if( dwRes == WAIT_OBJECT_0 )
{
if( !WSAGetOverlappedResult( s->s, &s->o, &readbytes, TRUE, &selflags ) )
readbytes = 0;
}
else if( dwRes == WAIT_TIMEOUT )
{
WSAGetOverlappedResult( s->s, &s->o, &readbytes, TRUE, &selflags );
readbytes = 0;
}
return readbytes;
}
net_ssize_t net_sendto( NET_SOCKET s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen )
{
DWORD wrotebytes;
WSABUF datadesc = { len, ( char* )buf };
if( WSASendTo( s->s, &datadesc, 1, &wrotebytes, flags, to, tolen, NULL, NULL ) == SOCKET_ERROR )
return 0;
return wrotebytes;
}
int net_close( NET_SOCKET s )
{
closesocket( s->s );
CloseHandle( s->o.hEvent );
free( s );
return 0;
}
net_sync_object net_get_sync_object( NET_SOCKET s )
{
return s->o.hEvent;
}

View File

@ -9,20 +9,21 @@
#include <string.h>
#include "os_io.h"
#include "remotefs.h"
#include "eluarpc.h"
int os_open( const char *pathname, int flags, int mode )
{
int realflags = 0;
// Translate RFS flags to POSIX flags
realflags = remotefs_replace_flag( flags, RFS_OPEN_FLAG_APPEND, O_APPEND );
realflags |= remotefs_replace_flag( flags, RFS_OPEN_FLAG_CREAT, O_CREAT );
realflags |= remotefs_replace_flag( flags, RFS_OPEN_FLAG_EXCL, O_EXCL );
realflags |= remotefs_replace_flag( flags, RFS_OPEN_FLAG_TRUNC, O_TRUNC );
realflags |= remotefs_replace_flag( flags, RFS_OPEN_FLAG_SYNC, O_SYNC );
realflags |= remotefs_replace_flag( flags, RFS_OPEN_FLAG_RDONLY, O_RDONLY );
realflags |= remotefs_replace_flag( flags, RFS_OPEN_FLAG_WRONLY, O_WRONLY );
realflags |= remotefs_replace_flag( flags, RFS_OPEN_FLAG_RDWR, O_RDWR );
realflags = eluarpc_replace_flag( flags, RFS_OPEN_FLAG_APPEND, O_APPEND );
realflags |= eluarpc_replace_flag( flags, RFS_OPEN_FLAG_CREAT, O_CREAT );
realflags |= eluarpc_replace_flag( flags, RFS_OPEN_FLAG_EXCL, O_EXCL );
realflags |= eluarpc_replace_flag( flags, RFS_OPEN_FLAG_TRUNC, O_TRUNC );
realflags |= eluarpc_replace_flag( flags, RFS_OPEN_FLAG_SYNC, O_SYNC );
realflags |= eluarpc_replace_flag( flags, RFS_OPEN_FLAG_RDONLY, O_RDONLY );
realflags |= eluarpc_replace_flag( flags, RFS_OPEN_FLAG_WRONLY, O_WRONLY );
realflags |= eluarpc_replace_flag( flags, RFS_OPEN_FLAG_RDWR, O_RDWR );
return open( pathname, realflags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
}
@ -31,14 +32,14 @@ u32 os_open_sys_flags_to_rfs_flags( int sysflags )
int rfsflags = 0;
// Translate RFS flags to POSIX flags
rfsflags = remotefs_replace_flag( sysflags, O_APPEND, RFS_OPEN_FLAG_APPEND );
rfsflags |= remotefs_replace_flag( sysflags, O_CREAT, RFS_OPEN_FLAG_CREAT );
rfsflags |= remotefs_replace_flag( sysflags, O_EXCL, RFS_OPEN_FLAG_EXCL );
rfsflags |= remotefs_replace_flag( sysflags, O_TRUNC, RFS_OPEN_FLAG_TRUNC );
rfsflags |= remotefs_replace_flag( sysflags, O_SYNC, RFS_OPEN_FLAG_SYNC );
rfsflags |= remotefs_replace_flag( sysflags, O_RDONLY, RFS_OPEN_FLAG_RDONLY );
rfsflags |= remotefs_replace_flag( sysflags, O_WRONLY, RFS_OPEN_FLAG_WRONLY );
rfsflags |= remotefs_replace_flag( sysflags, O_RDWR, RFS_OPEN_FLAG_RDWR );
rfsflags = eluarpc_replace_flag( sysflags, O_APPEND, RFS_OPEN_FLAG_APPEND );
rfsflags |= eluarpc_replace_flag( sysflags, O_CREAT, RFS_OPEN_FLAG_CREAT );
rfsflags |= eluarpc_replace_flag( sysflags, O_EXCL, RFS_OPEN_FLAG_EXCL );
rfsflags |= eluarpc_replace_flag( sysflags, O_TRUNC, RFS_OPEN_FLAG_TRUNC );
rfsflags |= eluarpc_replace_flag( sysflags, O_SYNC, RFS_OPEN_FLAG_SYNC );
rfsflags |= eluarpc_replace_flag( sysflags, O_RDONLY, RFS_OPEN_FLAG_RDONLY );
rfsflags |= eluarpc_replace_flag( sysflags, O_WRONLY, RFS_OPEN_FLAG_WRONLY );
rfsflags |= eluarpc_replace_flag( sysflags, O_RDWR, RFS_OPEN_FLAG_RDWR );
return rfsflags;
}

View File

@ -7,22 +7,24 @@
#include <share.h>
#include <windows.h>
#include <string.h>
#include <stdio.h>
#include "os_io.h"
#include "remotefs.h"
#include "eluarpc.h"
int os_open( const char *pathname, int flags, int mode )
{
int realflags = 0;
// Translate RFS flags to POSIX flags
realflags = remotefs_replace_flag( flags, RFS_OPEN_FLAG_APPEND, _O_APPEND );
realflags |= remotefs_replace_flag( flags, RFS_OPEN_FLAG_CREAT, _O_CREAT );
realflags |= remotefs_replace_flag( flags, RFS_OPEN_FLAG_EXCL, _O_EXCL );
realflags |= remotefs_replace_flag( flags, RFS_OPEN_FLAG_TRUNC, _O_TRUNC );
realflags |= remotefs_replace_flag( flags, RFS_OPEN_FLAG_RDONLY, _O_RDONLY );
realflags |= remotefs_replace_flag( flags, RFS_OPEN_FLAG_WRONLY, _O_WRONLY );
realflags |= remotefs_replace_flag( flags, RFS_OPEN_FLAG_RDWR, _O_RDWR );
return _sopen( pathname, realflags, _SH_DENYNO, _S_IREAD | _S_IWRITE );
realflags = eluarpc_replace_flag( flags, RFS_OPEN_FLAG_APPEND, _O_APPEND );
realflags |= eluarpc_replace_flag( flags, RFS_OPEN_FLAG_CREAT, _O_CREAT );
realflags |= eluarpc_replace_flag( flags, RFS_OPEN_FLAG_EXCL, _O_EXCL );
realflags |= eluarpc_replace_flag( flags, RFS_OPEN_FLAG_TRUNC, _O_TRUNC );
realflags |= eluarpc_replace_flag( flags, RFS_OPEN_FLAG_RDONLY, _O_RDONLY );
realflags |= eluarpc_replace_flag( flags, RFS_OPEN_FLAG_WRONLY, _O_WRONLY );
realflags |= eluarpc_replace_flag( flags, RFS_OPEN_FLAG_RDWR, _O_RDWR );
return _sopen( pathname, realflags | _O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE );
}
u32 os_open_sys_flags_to_rfs_flags( int sysflags )
@ -30,13 +32,13 @@ u32 os_open_sys_flags_to_rfs_flags( int sysflags )
int rfsflags = 0;
// Translate RFS flags to POSIX flags
rfsflags = remotefs_replace_flag( sysflags, _O_APPEND, RFS_OPEN_FLAG_APPEND );
rfsflags |= remotefs_replace_flag( sysflags, _O_CREAT, RFS_OPEN_FLAG_CREAT );
rfsflags |= remotefs_replace_flag( sysflags, _O_EXCL, RFS_OPEN_FLAG_EXCL );
rfsflags |= remotefs_replace_flag( sysflags, _O_TRUNC, RFS_OPEN_FLAG_TRUNC );
rfsflags |= remotefs_replace_flag( sysflags, _O_RDONLY, RFS_OPEN_FLAG_RDONLY );
rfsflags |= remotefs_replace_flag( sysflags, _O_WRONLY, RFS_OPEN_FLAG_WRONLY );
rfsflags |= remotefs_replace_flag( sysflags, _O_RDWR, RFS_OPEN_FLAG_RDWR );
rfsflags = eluarpc_replace_flag( sysflags, _O_APPEND, RFS_OPEN_FLAG_APPEND );
rfsflags |= eluarpc_replace_flag( sysflags, _O_CREAT, RFS_OPEN_FLAG_CREAT );
rfsflags |= eluarpc_replace_flag( sysflags, _O_EXCL, RFS_OPEN_FLAG_EXCL );
rfsflags |= eluarpc_replace_flag( sysflags, _O_TRUNC, RFS_OPEN_FLAG_TRUNC );
rfsflags |= eluarpc_replace_flag( sysflags, _O_RDONLY, RFS_OPEN_FLAG_RDONLY );
rfsflags |= eluarpc_replace_flag( sysflags, _O_WRONLY, RFS_OPEN_FLAG_WRONLY );
rfsflags |= eluarpc_replace_flag( sysflags, _O_RDWR, RFS_OPEN_FLAG_RDWR );
return rfsflags;
}
@ -133,6 +135,7 @@ void os_readdir( u32 d, const char **pname )
{
if( ( win32_dir_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == 0 )
{
realname[ 0 ] = realname[ RFS_MAX_FNAME_SIZE ] = '\0';
if( win32_dir_data.cFileName[ 0 ] )
strncpy( realname, win32_dir_data.cFileName, RFS_MAX_FNAME_SIZE );
else

12
rfs_server_src/rfs.h Normal file
View File

@ -0,0 +1,12 @@
// RFS public interface (used by mux)
#ifndef __RFS_H__
#define __RFS_H__
int rfs_init( int argc, const char **argv );
void rfs_mem_start_request();
int rfs_mem_read_request_packet( int c );
int rfs_mem_has_response();
void rfs_mem_write_response( u16 *plen, u8 **pdata );
#endif

View File

@ -28,14 +28,18 @@
#define SER_DATABITS_7 7
#define SER_DATABITS_8 8
#define SER_FLOW_NONE 0
#define SER_FLOW_RTSCTS 1
// Serial access functions (to be implemented by each platform)
ser_handler ser_open( const char *sername );
void ser_close( ser_handler id );
int ser_setup( ser_handler id, u32 baud, int databits, int parity, int stopbits );
u32 ser_read( ser_handler id, u8* dest, u32 maxsize );
int ser_read_byte( ser_handler id );
int ser_setup( ser_handler id, u32 baud, int databits, int parity, int stopbits, int flow );
u32 ser_read( ser_handler id, u8* dest, u32 maxsize, u32 timeout );
int ser_read_byte( ser_handler id, u32 timeout );
u32 ser_write( ser_handler id, const u8 *src, u32 size );
u32 ser_write_byte( ser_handler id, u8 data );
void ser_set_timeout_ms( ser_handler id, u32 timeout );
int ser_select_byte( ser_handler *pobjects, unsigned nobjects, int timeout );
#endif

View File

@ -10,8 +10,8 @@
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
static u32 ser_timeout = SER_INF_TIMEOUT;
#include <sys/ioctl.h>
#include "log.h"
// Open the serial port
ser_handler ser_open( const char* sername )
@ -19,7 +19,7 @@ ser_handler ser_open( const char* sername )
int fd;
if( ( fd = open( sername, O_RDWR | O_NOCTTY | O_NDELAY ) ) == -1 )
perror( "ser_open: unable to open port" );
return SER_HANDLER_INVALID;
else
fcntl( fd, F_SETFL, 0 );
return ( ser_handler )fd;
@ -65,20 +65,21 @@ static int ser_number_of_bits_to_id( int nb )
return 0;
}
int ser_setup( ser_handler id, u32 baud, int databits, int parity, int stopbits )
int ser_setup( ser_handler id, u32 baud, int databits, int parity, int stopbits, int flow )
{
struct termios termdata;
int hnd = ( int )id;
usleep( 200000 );
tcgetattr( hnd, &termdata );
tcdrain( hnd );
// Baud rate
cfsetispeed( &termdata, ser_baud_to_id( baud ) );
cfsetospeed( &termdata, ser_baud_to_id( baud ) );
// Parity / stop bits
if ( stopbits == SER_STOPBITS_2)
if( stopbits == SER_STOPBITS_2 )
termdata.c_cflag |= CSTOPB;
else
termdata.c_cflag &= ~CSTOPB;
@ -96,16 +97,20 @@ int ser_setup( ser_handler id, u32 baud, int databits, int parity, int stopbits
{
termdata.c_cflag |= PARENB;
termdata.c_cflag |= PARODD;
}
}
// Data bits
// Data bits
termdata.c_cflag |= ( CLOCAL | CREAD );
termdata.c_cflag &= ~CSIZE;
termdata.c_cflag |= ser_number_of_bits_to_id( databits );
// Disable HW and SW flow control
termdata.c_cflag &= ~CRTSCTS;
if( flow == SER_FLOW_NONE )
termdata.c_cflag &= ~CRTSCTS;
else
termdata.c_cflag |= CRTSCTS;
termdata.c_iflag &= ~( IXON | IXOFF | IXANY );
termdata.c_iflag |= IGNBRK;
// Raw input
termdata.c_lflag &= ~( ICANON | ECHO | ECHOE | ISIG );
@ -119,61 +124,45 @@ int ser_setup( ser_handler id, u32 baud, int databits, int parity, int stopbits
else
termdata.c_iflag |= ( INPCK | ISTRIP );
termdata.c_cc[ VMIN ] = 1;
termdata.c_cc[ VMIN ] = 0;
termdata.c_cc[ VTIME ] = 0;
// Set the attibutes now
tcsetattr( hnd, TCSANOW, &termdata );
// Flush everything
tcflush( hnd, TCIOFLUSH );
// And set blocking mode by default
fcntl( id, F_SETFL, 0 );
// Set the attibutes now
tcsetattr( hnd, TCSANOW, &termdata );
// And set non-blocking mode by default
fcntl( hnd, F_SETFL, FNDELAY );
// All done
return SER_OK;
}
// Read up to the specified number of bytes, return bytes actually read
u32 ser_read( ser_handler id, u8* dest, u32 maxsize )
u32 ser_read( ser_handler id, u8* dest, u32 maxsize, u32 timeout )
{
struct termios termdata;
fd_set readfs;
struct timeval tv;
int retval;
tcgetattr( id, &termdata );
if( ser_timeout == SER_INF_TIMEOUT )
{
termdata.c_cc[ VMIN ] = maxsize;
termdata.c_cc[ VTIME ] = 0;
tcsetattr( id, TCSANOW, &termdata );
return ( u32 )read( ( int )id, dest, maxsize );
}
else
{
fd_set readfs;
struct timeval tv;
int retval;
termdata.c_cc[ VMIN ] = 1;
termdata.c_cc[ VTIME ] = 0;
tcsetattr( id, TCSANOW, &termdata );
FD_ZERO( &readfs );
FD_SET( ( int )id, &readfs );
tv.tv_sec = ser_timeout / 1000000;
tv.tv_usec = ( ser_timeout % 1000000 ) * 1000;
retval = select( ( int )id + 1, &readfs, NULL, NULL, &tv );
if( retval == -1 || retval == 0 )
return 0;
else
return ( u32 )read( ( int )id, dest, maxsize );
}
FD_ZERO( &readfs );
FD_SET( ( int )id, &readfs );
tv.tv_sec = timeout / 1000;
tv.tv_usec = ( timeout % 1000 ) * 1000;
retval = select( ( int )id + 1, &readfs, NULL, NULL, timeout == SER_INF_TIMEOUT ? NULL : &tv );
if( retval == -1 || retval == 0 )
return 0;
else
return ( u32 )read( id, dest, maxsize );
}
// Read a single byte and return it (or -1 for error)
int ser_read_byte( ser_handler id )
int ser_read_byte( ser_handler id, u32 timeout )
{
u8 data;
int res = ser_read( id, &data, 1 );
int res = ser_read( id, &data, 1, timeout );
return res == 1 ? data : -1;
}
@ -184,6 +173,7 @@ u32 ser_write( ser_handler id, const u8 *src, u32 size )
u32 res;
res = ( u32 )write( ( int )id, src, size );
tcdrain( ( int )id );
return res;
}
@ -193,9 +183,40 @@ u32 ser_write_byte( ser_handler id, u8 data )
return ( u32 )write( id, &data, 1 );
}
// Set communication timeout
void ser_set_timeout_ms( ser_handler id, u32 timeout )
// Perform 'select' on the specified handler(s), returning a single byte
// if it could be read (plus the object ID in the upper 8 bits) and -1
// otherwise
int ser_select_byte( ser_handler *pobjects, unsigned nobjects, int timeout )
{
ser_timeout = timeout;
int i, maxfd = -1;
fd_set readfs;
struct timeval tv;
int res = -1;
u8 data;
FD_ZERO( &readfs );
for( i = 0; i < nobjects; i ++ )
{
FD_SET( pobjects[ i ], &readfs );
if( pobjects[ i ] > maxfd )
maxfd = pobjects[ i ];
}
tv.tv_sec = timeout / 1000;
tv.tv_usec = ( timeout % 1000 ) * 1000;
res = select( maxfd + 1, &readfs, NULL, NULL, timeout == SER_INF_TIMEOUT ? NULL : &tv );
if( res <= 0 )
return -1;
res = -1;
for( i = 0; i < nobjects; i ++ )
if( FD_ISSET( pobjects[ i ], &readfs ) )
{
res = read( pobjects[ i ], &data, 1 );
if( res != 1 )
return -1;
res = data | ( i << 8 );
break;
}
return res;
}

View File

@ -0,0 +1,300 @@
// Serial inteface implementation for POSIX-compliant systems
#include <windows.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "type.h"
#include "serial.h"
#define WIN_ERROR ( HANDLE )-1
#define WIN_MAX_PORT_NAME 1024
#define MAX_HANDLES 1024
static HANDLE sel_handlers[ MAX_HANDLES ];
static int sel_handler_map[ MAX_HANDLES ];
// Helper: set timeout
static int ser_win32_set_timeouts( HANDLE hComm, DWORD ri, DWORD rtm, DWORD rtc, DWORD wtm, DWORD wtc )
{
COMMTIMEOUTS timeouts;
if( GetCommTimeouts( hComm, &timeouts ) == FALSE )
{
CloseHandle( hComm );
return SER_ERR;
}
timeouts.ReadIntervalTimeout = ri;
timeouts.ReadTotalTimeoutConstant = rtm;
timeouts.ReadTotalTimeoutMultiplier = rtc;
timeouts.WriteTotalTimeoutConstant = wtm;
timeouts.WriteTotalTimeoutMultiplier = wtc;
if( SetCommTimeouts( hComm, &timeouts ) == FALSE )
{
CloseHandle( hComm );
return SER_ERR;
}
return SER_OK;
}
// Helper: set communication timeout
static int ser_set_timeout_ms( HANDLE hComm, u32 timeout )
{
if( timeout == SER_NO_TIMEOUT )
return ser_win32_set_timeouts( hComm, MAXDWORD, 0, 0, 0, 0 );
else if( timeout == SER_INF_TIMEOUT )
return ser_win32_set_timeouts( hComm, 0, 0, 0, 0, 0 );
else
return ser_win32_set_timeouts( hComm, 0, 0, timeout, 0, 0 );
}
// Open the serial port
ser_handler ser_open( const char* sername )
{
char portname[ WIN_MAX_PORT_NAME + 1 ];
HANDLE hComm;
ser_handler hnd;
portname[ 0 ] = portname[ WIN_MAX_PORT_NAME ] = '\0';
_snprintf( portname, WIN_MAX_PORT_NAME, "\\\\.\\%s", sername );
hComm = CreateFile( portname, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0 );
if( hComm == INVALID_HANDLE_VALUE )
return SER_HANDLER_INVALID;
if( !SetupComm( hComm, 2048, 2048 ) )
return SER_HANDLER_INVALID;
if( ser_set_timeout_ms( hComm, SER_INF_TIMEOUT ) != SER_OK )
return SER_HANDLER_INVALID;
if( ( hnd = malloc( sizeof( SERIAL_DATA ) ) ) == NULL )
return SER_HANDLER_INVALID;
memset( hnd, 0, sizeof( SERIAL_DATA ) );
hnd->hnd = hComm;
hnd->fWaitingOnRead = FALSE;
if( ( hnd->o.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) ) == NULL )
return SER_HANDLER_INVALID;
if( ( hnd->o_wr.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) ) == NULL )
return SER_HANDLER_INVALID;
return hnd;
}
// Close the serial port
void ser_close( ser_handler id )
{
CloseHandle( id->o.hEvent );
CloseHandle( id->o_wr.hEvent );
CloseHandle( id->hnd );
free( id );
}
int ser_setup( ser_handler id, u32 baud, int databits, int parity, int stopbits, int flow )
{
HANDLE hComm = id->hnd;
DCB dcb;
if( GetCommState( hComm, &dcb ) == FALSE )
{
CloseHandle( hComm );
return SER_ERR;
}
dcb.BaudRate = baud;
dcb.ByteSize = databits;
dcb.Parity = parity == SER_PARITY_NONE ? NOPARITY : ( parity == SER_PARITY_EVEN ? EVENPARITY : ODDPARITY );
dcb.StopBits = stopbits == SER_STOPBITS_1 ? ONESTOPBIT : ( stopbits == SER_STOPBITS_1_5 ? ONE5STOPBITS : TWOSTOPBITS );
dcb.fBinary = TRUE;
dcb.fDsrSensitivity = FALSE;
dcb.fParity = parity != SER_PARITY_NONE ? TRUE : FALSE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
dcb.fNull = FALSE;
/**/ dcb.fAbortOnError = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fDsrSensitivity = FALSE;
if( flow == SER_FLOW_NONE )
{
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fOutxCtsFlow = FALSE;
}
else
{
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
dcb.fOutxCtsFlow = TRUE;
}
if( SetCommState( hComm, &dcb ) == 0 )
{
CloseHandle( hComm );
return SER_ERR;
}
if( ser_win32_set_timeouts( hComm, 0, 0, 0, 0, 0 ) == SER_ERR )
{
CloseHandle( hComm );
return SER_ERR;
}
FlushFileBuffers( hComm );
return SER_OK;
}
// Read up to the specified number of bytes, return bytes actually read
u32 ser_read( ser_handler id, u8* dest, u32 maxsize, u32 timeout )
{
HANDLE hComm = id->hnd;
DWORD readbytes = 0;
if( !id->fWaitingOnRead )
{
if( ReadFile( hComm, dest, maxsize, &readbytes, &id->o ) == FALSE )
{
if( GetLastError() != ERROR_IO_PENDING )
return 0;
else
id->fWaitingOnRead = TRUE;
}
else
return readbytes;
}
if( id->fWaitingOnRead )
{
DWORD dwRes = WaitForSingleObject( id->o.hEvent, timeout == SER_INF_TIMEOUT ? INFINITE : timeout );
if( dwRes == WAIT_OBJECT_0 )
{
if( !GetOverlappedResult( hComm, &id->o, &readbytes, TRUE ) )
readbytes = 0;
}
else if( dwRes == WAIT_TIMEOUT )
{
CancelIo( hComm );
GetOverlappedResult( hComm, &id->o, &readbytes, TRUE );
readbytes = 0;
}
ResetEvent( id->o.hEvent );
}
id->fWaitingOnRead = FALSE;
return readbytes;
}
// Read a single byte and return it (or -1 for error)
int ser_read_byte( ser_handler id, u32 timeout )
{
u8 data;
int res = ser_read( id, &data, 1, timeout );
return res == 1 ? data : -1;
}
// Write up to the specified number of bytes, return bytes actually written
u32 ser_write( ser_handler id, const u8 *src, u32 size )
{
HANDLE hComm = id->hnd;
DWORD written = 0;
BOOL fWaitingOnWrite = FALSE;
HANDLE temp = id->o_wr.hEvent;
memset( &id->o_wr, 0, sizeof( OVERLAPPED ) );
id->o_wr.hEvent = temp;
if( WriteFile( hComm, src, size, &written, &id->o_wr ) == FALSE )
{
if( GetLastError() != ERROR_IO_PENDING )
return 0;
else
fWaitingOnWrite = TRUE;
}
else
return written;
if( fWaitingOnWrite )
{
DWORD dwRes = WaitForSingleObject( id->o_wr.hEvent, INFINITE );
if( dwRes == WAIT_OBJECT_0 )
if( !GetOverlappedResult( hComm, &id->o_wr, &written, FALSE ) )
written = 0;
ResetEvent( id->o_wr.hEvent );
}
return written;
}
// Write a byte to the serial port
u32 ser_write_byte( ser_handler id, u8 data )
{
return ser_write( id, &data, 1 );
}
// Perform 'select' on the specified handler(s), returning a single byte
// if it could be read (plus the object ID in the upper 8 bits) and -1
// otherwise
int ser_select_byte( ser_handler *pobjects, unsigned nobjects, int timeout )
{
int i, idx;
DWORD readbytes;
int res = -1;
unsigned num_wait = 0;
ser_handler hnd;
HANDLE temp;
// Try to read directly first
for( i = 0; i < nobjects; i ++ )
{
temp = pobjects[ i ]->o.hEvent;
memset( &pobjects[ i ]->o, 0, sizeof( OVERLAPPED ) );
pobjects[ i ]->o.hEvent = temp;
if( !pobjects[ i ]->fWaitingOnRead )
{
if( ReadFile( pobjects[ i ]->hnd, &pobjects[ i ]->databuf, 1, &readbytes, &pobjects[ i ]->o ) == FALSE )
{
if( GetLastError() != ERROR_IO_PENDING )
return -1;
else
{
pobjects[ i ]->fWaitingOnRead = TRUE;
sel_handler_map[ num_wait ] = i;
sel_handlers[ num_wait ++ ] = pobjects[ i ]->o.hEvent;
}
}
else
{
if( readbytes == 1 )
return pobjects[ i ]->databuf | ( i << 8 );
else
return -1;
}
}
else
{
sel_handler_map[ num_wait ] = i;
sel_handlers[ num_wait ++ ] = pobjects[ i ]->o.hEvent;
}
}
if( num_wait > 0 )
{
idx = -1;
DWORD dwRes = WaitForMultipleObjects( num_wait, sel_handlers, FALSE, timeout == SER_INF_TIMEOUT ? INFINITE : timeout );
if( dwRes >= WAIT_OBJECT_0 && dwRes < WAIT_OBJECT_0 + num_wait )
{
i = idx = dwRes - WAIT_OBJECT_0;
hnd = pobjects[ sel_handler_map[ i ] ];
hnd->fWaitingOnRead = FALSE;
if( GetOverlappedResult( hnd->hnd, &hnd->o, &readbytes, TRUE ) && readbytes == 1 )
res = hnd->databuf | ( sel_handler_map[ i ] << 8 );
ResetEvent( hnd->o.hEvent );
}
else if( dwRes == WAIT_TIMEOUT )
{
for( i = 0; i < num_wait; i ++ )
{
hnd = pobjects[ sel_handler_map[ i ] ];
hnd->fWaitingOnRead = FALSE;
CancelIo( hnd->hnd );
GetOverlappedResult( hnd->hnd, &hnd->o, &readbytes, TRUE );
ResetEvent( hnd->o.hEvent );
}
}
}
return res;
}

View File

@ -1,8 +1,10 @@
// Remote filesystem server implementation
#include <string.h>
#include <stdlib.h>
#include "server.h"
#include "remotefs.h"
#include "eluarpc.h"
#include "type.h"
#include "os_io.h"
#include "log.h"
@ -10,19 +12,6 @@
static char* server_basedir;
static char server_fullname[ PLATFORM_MAX_FNAME_LEN + 1 ];
#ifdef DEBUG
#include <stdio.h>
#define LOG0(str) printf( str"\n" )
#define LOG1(str, arg1) printf( str"\n", arg1 )
#define LOG2(str, arg1, arg2) printf( str"\n", arg1, arg2 )
#define LOG3(str, arg1, arg2, arg3) printf( str"\n", arg1, arg2, arg3 )
#else
#define LOG0(str)
#define LOG1(str, arg1)
#define LOG2(str, arg1, arg2)
#define LOG3(str, arg1, arg2, arg3)
#endif
typedef int ( *p_server_handler )( u8 *p );
// *****************************************************************************
@ -36,7 +25,7 @@ static int server_open( u8 *p )
// Validate request
log_msg( "server_open: request handler starting\n" );
if( remotefs_open_read_request( p, &filename, &flags, &mode ) == REMOTEFS_ERR )
if( remotefs_open_read_request( p, &filename, &flags, &mode ) == ELUARPC_ERR )
{
log_msg( "server_open: unable to read request\n" );
return SERVER_ERR;
@ -64,7 +53,7 @@ static int server_write( u8 *p )
u32 count;
log_msg( "server_write: request handler starting\n" );
if( remotefs_write_read_request( p, &fd, &buf, &count ) == REMOTEFS_ERR )
if( remotefs_write_read_request( p, &fd, &buf, &count ) == ELUARPC_ERR )
{
log_msg( "server_write: unable to read request\n" );
return SERVER_ERR;
@ -82,13 +71,13 @@ static int server_read( u8 *p )
u32 count;
log_msg( "server_read: request handler starting\n" );
if( remotefs_read_read_request( p, &fd, &count ) == REMOTEFS_ERR )
if( remotefs_read_read_request( p, &fd, &count ) == ELUARPC_ERR )
{
log_msg( "server_read: unable to read request\n" );
return SERVER_ERR;
}
log_msg( "server_read: fd = %d, count = %u\n", fd, ( unsigned )count );
count = ( u32 )os_read( fd, p + RFS_READ_BUF_OFFSET, count );
count = ( u32 )os_read( fd, p + ELUARPC_READ_BUF_OFFSET, count );
log_msg( "server_read: OS response is %u\n", ( unsigned )count );
remotefs_read_write_response( p, count );
return SERVER_OK;
@ -99,7 +88,7 @@ static int server_close( u8 *p )
int fd;
log_msg( "server_close: request handler starting\n" );
if( remotefs_close_read_request( p, &fd ) == REMOTEFS_ERR )
if( remotefs_close_read_request( p, &fd ) == ELUARPC_ERR )
{
log_msg( "server_close: unable to read request\n" );
return SERVER_ERR;
@ -117,7 +106,7 @@ static int server_lseek( u8 *p )
s32 offset;
log_msg( "server_lseek: request handler starting\n" );
if( remotefs_lseek_read_request( p, &fd, &offset, &whence ) == REMOTEFS_ERR )
if( remotefs_lseek_read_request( p, &fd, &offset, &whence ) == ELUARPC_ERR )
{
log_msg( "server_lseek: unable to read request\n" );
return SERVER_ERR;
@ -136,7 +125,7 @@ static int server_opendir( u8 *p )
char separator[ 2 ] = { PLATFORM_PATH_SEPARATOR, 0 };
log_msg( "server_opendir: request handler starting\n" );
if( remotefs_opendir_read_request( p, &name ) == REMOTEFS_ERR )
if( remotefs_opendir_read_request( p, &name ) == ELUARPC_ERR )
{
log_msg( "server_opendir: unable to read request\n" );
return SERVER_ERR;
@ -160,12 +149,12 @@ static int server_opendir( u8 *p )
static int server_readdir( u8 *p )
{
const char* name;
u32 fsize, d;
u32 fsize = 0, d;
int fd;
char separator[ 2 ] = { PLATFORM_PATH_SEPARATOR, 0 };
log_msg( "server_readdir: request handler starting\n" );
if( remotefs_readdir_read_request( p, &d ) == REMOTEFS_ERR )
if( remotefs_readdir_read_request( p, &d ) == ELUARPC_ERR )
{
log_msg( "server_readdir: unable to read request\n" );
return SERVER_ERR;
@ -207,7 +196,7 @@ static int server_closedir( u8 *p )
int res;
log_msg( "server_closedir: request handler starting\n" );
if( remotefs_closedir_read_request( p, &d ) == REMOTEFS_ERR )
if( remotefs_closedir_read_request( p, &d ) == ELUARPC_ERR )
{
log_msg( "server_closedir: unable to read request\n" );
return SERVER_ERR;
@ -232,12 +221,17 @@ void server_setup( const char* basedir )
server_basedir = strdup( basedir );
}
void server_cleanup()
{
free( server_basedir );
server_basedir = NULL;
}
int server_execute_request( u8 *pdata )
{
u8 req;
// Decode request
if( remotefs_get_request_id( pdata, &req ) == REMOTEFS_ERR )
if( eluarpc_get_request_id( pdata, &req ) == ELUARPC_ERR )
return SERVER_ERR;
log_msg( "server_execute_request: got request with ID %d\n", req );
if( req >= RFS_OP_FIRST && req <= RFS_OP_LAST )

View File

@ -11,6 +11,7 @@
// Server function
void server_setup( const char *basedir );
void server_cleanup();
int server_execute_request( u8 *pdata );
#endif

40
rfs_server_src/type.h Normal file
View File

@ -0,0 +1,40 @@
// Type definitions for the remote file system
#ifndef __TYPE_H__
#define __TYPE_H__
typedef char s8;
typedef unsigned char u8;
typedef short s16;
typedef unsigned short u16;
typedef long s32;
typedef unsigned long u32;
typedef long long s64;
typedef unsigned long long u64;
#ifdef WIN32_BUILD
#include <windows.h>
typedef struct
{
HANDLE hnd;
OVERLAPPED o;
OVERLAPPED o_wr;
BOOL fWaitingOnRead;
u8 databuf;
} SERIAL_DATA;
typedef SERIAL_DATA* ser_handler;
#define SER_HANDLER_INVALID ( NULL )
typedef HANDLE sync_object;
#else // #ifdef WIN32_BUILD
// Assume POSIX here
typedef int ser_handler;
#define SER_HANDLER_INVALID ( -1 )
typedef int sync_object;
#endif // #ifdef WIN32_BUILD
#endif // #ifndef __TYPE_H__

View File

@ -1,23 +1,31 @@
// eLua "char device" buffering system
#include "platform_conf.h"
#include <stdio.h>
#if defined( BUF_ENABLE_UART ) || defined( BUF_ENABLE_ADC )
#define BUF_ENABLE
#endif
#ifdef BUILD_SERMUX
#define NUM_TOTAL_UART ( NUM_UART + SERMUX_NUM_VUART )
#else
#define NUM_TOTAL_UART ( NUM_UART )
#endif
#ifdef BUF_ENABLE
#include "buf.h"
#include "type.h"
#include "platform.h"
#include "utils.h"
#include "sermux.h"
#include <stdlib.h>
#include <string.h>
// [TODO]? Following code might need a C99 compiler (for 0-sized arrays)
#ifdef BUF_ENABLE_UART
static buf_desc buf_desc_uart[ NUM_UART ];
static buf_desc buf_desc_uart[ NUM_TOTAL_UART ];
#else
static buf_desc buf_desc_uart[ 0 ];
#endif
@ -33,7 +41,7 @@
static const buf_desc* buf_desc_array[ BUF_ID_TOTAL ] =
{
buf_desc_uart,
buf_desc_adc,
buf_desc_adc
};
// Helper macros
@ -48,6 +56,21 @@ static const buf_desc* buf_desc_array[ BUF_ID_TOTAL ] =
#define READ16( p ) p
#define WRITE16( p, x ) p = x
// Helper: check 'resnum' (for virtual UARTs)
// UART resource ID translation to buffer ID translation (for serial multiplexer support)
#ifdef BUILD_SERMUX
static unsigned bufh_check_resnum( unsigned resid, unsigned resnum )
{
if( resid == BUF_ID_UART && resnum >= SERMUX_SERVICE_ID_FIRST )
return resnum - SERMUX_SERVICE_ID_FIRST + NUM_UART;
else
return resnum;
}
#define BUF_CHECK_RESNUM( resid, resnum ) resnum = bufh_check_resnum( resid, resnum )
#else
#define BUF_CHECK_RESNUM( resid, resnum )
#endif
// Initialize the buffer of the specified resource
// resid - resource ID (BUF_ID_UART ...)
// resnum - resource number (0, 1, 2...)
@ -57,6 +80,7 @@ static const buf_desc* buf_desc_array[ BUF_ID_TOTAL ] =
// Returns 1 on success, 0 on failure
int buf_set( unsigned resid, unsigned resnum, u8 logsize, u8 logdsize )
{
BUF_CHECK_RESNUM( resid, resnum );
BUF_GETPTR( resid, resnum );
pbuf->logdsize = logdsize;
@ -76,6 +100,7 @@ int buf_set( unsigned resid, unsigned resnum, u8 logsize, u8 logdsize )
// Marks buffer as empty
void buf_flush( unsigned resid, unsigned resnum )
{
BUF_CHECK_RESNUM( resid, resnum );
BUF_GETPTR( resid, resnum );
pbuf->rptr = pbuf->wptr = pbuf->count = 0;
@ -89,17 +114,21 @@ void buf_flush( unsigned resid, unsigned resnum )
// [TODO] maybe add a buffer overflow flag
int buf_write( unsigned resid, unsigned resnum, t_buf_data *data )
{
BUF_CHECK_RESNUM( resid, resnum );
BUF_GETPTR( resid, resnum );
const char* s = ( const char* )data;
char* d = ( char* )( pbuf->buf + pbuf->wptr );
if( pbuf->logsize == BUF_SIZE_NONE )
return PLATFORM_ERR;
if( pbuf->count > BUF_REALSIZE( pbuf ) )
{
fprintf( stderr, "[ERROR] Buffer overflow on resid=%d, resnum=%d!\n", resid, resnum );
return PLATFORM_ERR;
}
DUFF_DEVICE_8( BUF_REALDSIZE( pbuf ), *d++ = *s++ );
BUF_MOD_INCR( pbuf, wptr );
if( pbuf->count == BUF_REALSIZE( pbuf ) )
BUF_MOD_INCR( pbuf, rptr );
else
pbuf->count ++;
return PLATFORM_OK;
@ -110,6 +139,7 @@ int buf_write( unsigned resid, unsigned resnum, t_buf_data *data )
// resnum - resource number (0, 1, 2...)
int buf_is_enabled( unsigned resid, unsigned resnum )
{
BUF_CHECK_RESNUM( resid, resnum );
BUF_GETPTR( resid, resnum );
return pbuf->logsize != BUF_SIZE_NONE;
@ -118,14 +148,16 @@ int buf_is_enabled( unsigned resid, unsigned resnum )
// Return the size of the buffer in number
unsigned buf_get_size( unsigned resid, unsigned resnum )
{
BUF_CHECK_RESNUM( resid, resnum );
BUF_GETPTR( resid, resnum );
return BUF_REALSIZE( pbuf );
return pbuf->logsize == BUF_SIZE_NONE ? 0 : BUF_REALSIZE( pbuf );
}
// Return the size of the data in the buffer
unsigned buf_get_count( unsigned resid, unsigned resnum )
{
BUF_CHECK_RESNUM( resid, resnum );
BUF_GETPTR( resid, resnum );
return READ16( pbuf->count );
@ -140,21 +172,22 @@ unsigned buf_get_count( unsigned resid, unsigned resnum )
// PLATFORM_UNDERFLOW on buffer empty
int buf_read( unsigned resid, unsigned resnum, t_buf_data *data )
{
BUF_CHECK_RESNUM( resid, resnum );
BUF_GETPTR( resid, resnum );
int old_status;
if( READ16( pbuf->count ) == 0 )
return PLATFORM_UNDERFLOW;
int old_status;
const char* s = ( const char* )( pbuf->buf + pbuf->rptr );
char* d = ( char* )data;
if( pbuf->logsize == BUF_SIZE_NONE || READ16( pbuf->count ) == 0 )
return PLATFORM_UNDERFLOW;
DUFF_DEVICE_8( BUF_REALDSIZE( pbuf ), *d++ = *s++ );
old_status = platform_cpu_set_global_interrupts( PLATFORM_CPU_DISABLE );
pbuf->count --;
BUF_MOD_INCR( pbuf, rptr );
platform_cpu_set_global_interrupts( old_status );
BUF_MOD_INCR( pbuf, rptr );
return PLATFORM_OK;
}

View File

@ -14,7 +14,9 @@
#include "term.h"
#include "xmodem.h"
#include "elua_int.h"
#include "sermux.h"
// [TODO] the new builder should automatically do this
#if defined( BUILD_LUA_INT_HANDLERS ) || defined( BUILD_C_INT_HANDLERS )
#define BUILD_INT_HANDLERS
@ -26,10 +28,26 @@ extern const elua_int_descriptor elua_int_table[ INT_ELUA_LAST ];
#endif // #if defined( BUILD_LUA_INT_HANDLERS ) || defined( BUILD_C_INT_HANDLERS )
// [TODO] the new builder should automatically do this
#ifndef VTMR_NUM_TIMERS
#define VTMR_NUM_TIMERS 0
#endif // #ifndef VTMR_NUM_TIMERS
// [TODO] the new builder should automatically do this
#ifndef CON_BUF_SIZE
#define CON_BUF_SIZE 0
#endif // #ifndef CON_BUF_SIZE
// [TODO] the new builder should automatically do this
#ifndef SERMUX_FLOW_TYPE
#define SERMUX_FLOW_TYPE PLATFORM_UART_FLOW_NONE
#endif
// [TODO] the new builder should automatically do this
#ifndef CON_FLOW_TYPE
#define CON_FLOW_TYPE PLATFORM_UART_FLOW_NONE
#endif
// ****************************************************************************
// XMODEM support code
@ -169,6 +187,27 @@ void cmn_platform_init()
platform_int_init();
#endif
#ifdef BUILD_SERMUX
unsigned i;
unsigned bufsizes[] = SERMUX_BUFFER_SIZES;
// Setup the serial multiplexer
platform_uart_setup( SERMUX_PHYS_ID, SERMUX_PHYS_SPEED, 8, PLATFORM_UART_PARITY_NONE, PLATFORM_UART_STOPBITS_1 );
platform_uart_set_flow_control( SERMUX_PHYS_ID, SERMUX_FLOW_TYPE );
cmn_uart_setup_sermux();
// Set buffers for all virtual UARTs
for( i = 0; i < sizeof( bufsizes ) / sizeof( unsigned ); i ++ )
platform_uart_set_buffer( i + SERMUX_SERVICE_ID_FIRST, bufsizes[ i ] );
#endif // #ifdef BUILD_SERMUX
#if defined( CON_UART_ID ) && CON_UART_ID < SERMUX_SERVICE_ID_FIRST
// Setup console UART
platform_uart_setup( CON_UART_ID, CON_UART_SPEED, 8, PLATFORM_UART_PARITY_NONE, PLATFORM_UART_STOPBITS_1 );
platform_uart_set_flow_control( CON_UART_ID, CON_FLOW_TYPE );
platform_uart_set_buffer( CON_UART_ID, CON_BUF_SIZE );
#endif // #if defined( CON_UART_ID ) && CON_UART_ID < SERMUX_SERVICE_ID_FIRST
// Set the send/recv functions
std_set_send_func( uart_send );
std_set_get_func( uart_recv );
@ -211,64 +250,6 @@ int platform_pio_has_pin( unsigned port, unsigned pin )
#error "You must define either PIO_PINS_PER_PORT of PIO_PIN_ARRAY in platform_conf.h"
#endif
}
// ****************************************************************************
// UART functions
// The platform UART functions
int platform_uart_exists( unsigned id )
{
return id < NUM_UART;
}
// Helper function for buffers
static int cmn_recv_helper( unsigned id, s32 timeout )
{
#ifdef BUF_ENABLE_UART
t_buf_data data;
if( buf_is_enabled( BUF_ID_UART, id ) )
{
if( timeout == 0 )
{
if ( ( buf_read( BUF_ID_UART, id, &data ) ) == PLATFORM_UNDERFLOW )
return -1;
}
else
{
while( ( buf_read( BUF_ID_UART, id, &data ) ) == PLATFORM_UNDERFLOW );
}
return ( int )data;
}
else
#endif
return platform_s_uart_recv( id, timeout );
}
int platform_uart_recv( unsigned id, unsigned timer_id, s32 timeout )
{
timer_data_type tmr_start, tmr_crt;
int res;
if( timeout == 0 )
return cmn_recv_helper( id, timeout );
else if( timeout == PLATFORM_UART_INFINITE_TIMEOUT )
return cmn_recv_helper( id, timeout );
else
{
// Receive char with the specified timeout
tmr_start = platform_timer_op( timer_id, PLATFORM_TIMER_OP_START, 0 );
while( 1 )
{
if( ( res = cmn_recv_helper( id, 0 ) ) >= 0 )
break;
tmr_crt = platform_timer_op( timer_id, PLATFORM_TIMER_OP_READ, 0 );
if( platform_timer_get_diff_us( timer_id, tmr_crt, tmr_start ) >= timeout )
break;
}
return res;
}
}
// ****************************************************************************
// CAN functions

View File

@ -237,7 +237,7 @@ u32 platform_timer_get_diff_us( unsigned id, timer_data_type end, timer_data_typ
#ifdef BUILD_INT_HANDLERS
int platform_timer_set_match_int( unsigned id, u32 period_us, int type )
{
#if VTMR_NUM_TIMERS > 0
#if VTMR_NUM_TIMERS > 0 && defined( CMN_TIMER_INT_SUPPORT )
if( TIMER_IS_VIRTUAL( id ) )
return vtmr_set_match_int( id, period_us, type );
else
@ -247,7 +247,7 @@ int platform_timer_set_match_int( unsigned id, u32 period_us, int type )
int cmn_tmr_int_set_status( elua_int_resnum resnum, int status )
{
#if VTMR_NUM_TIMERS > 0
#if VTMR_NUM_TIMERS > 00 && defined( CMN_TIMER_INT_SUPPORT )
if( TIMER_IS_VIRTUAL( resnum ) )
return vtmr_int_set_status( resnum, status );
#endif
@ -259,7 +259,7 @@ int cmn_tmr_int_set_status( elua_int_resnum resnum, int status )
int cmn_tmr_int_get_status( elua_int_resnum resnum )
{
#if VTMR_NUM_TIMERS > 0
#if VTMR_NUM_TIMERS > 00 && defined( CMN_TIMER_INT_SUPPORT )
if( TIMER_IS_VIRTUAL( resnum ) )
return vtmr_int_get_status( resnum );
#endif
@ -271,7 +271,7 @@ int cmn_tmr_int_get_status( elua_int_resnum resnum )
int cmn_tmr_int_get_flag( elua_int_resnum resnum, int clear )
{
#if VTMR_NUM_TIMERS > 0
#if VTMR_NUM_TIMERS > 00 && defined( CMN_TIMER_INT_SUPPORT )
if( TIMER_IS_VIRTUAL( resnum ) )
return vtmr_int_get_flag( resnum, clear );
#endif

218
src/common_uart.c Normal file
View File

@ -0,0 +1,218 @@
// Common implementation: UART functions
#include "common.h"
#include "platform.h"
#include "platform_conf.h"
#include "buf.h"
#include "elua_int.h"
#include "sermux.h"
// ****************************************************************************
// UART functions
#ifdef BUILD_SERMUX
int uart_service_id_in = -1;
int uart_service_id_out = -1;
u8 uart_got_esc = 0;
int uart_last_sent = -1;
// [TODO] add interrupt support for virtual UARTs
#else // #ifdef BUILD_SERMUX
#define SERMUX_PHYS_ID ( 0xFFFF )
#endif // #ifdef BUILD_SERMUX
// The platform UART functions
int platform_uart_exists( unsigned id )
{
#ifdef BUILD_SERMUX
return id < NUM_UART || ( id >= SERMUX_SERVICE_ID_FIRST && id < SERMUX_SERVICE_ID_FIRST + SERMUX_NUM_VUART );
#else // #ifdef BUILD_SERMUX
return id < NUM_UART;
#endif // #ifdef BUILD_SERMUX
}
// Helper function for buffers
static int cmn_recv_helper( unsigned id, s32 timeout )
{
#ifdef BUF_ENABLE_UART
t_buf_data data;
if( buf_is_enabled( BUF_ID_UART, id ) )
{
if( timeout == 0 )
{
if ( ( buf_read( BUF_ID_UART, id, &data ) ) == PLATFORM_UNDERFLOW )
return -1;
}
else
{
while( ( buf_read( BUF_ID_UART, id, &data ) ) == PLATFORM_UNDERFLOW );
}
return ( int )data;
}
else
#endif // #ifdef BUF_ENABLE_UART
return platform_s_uart_recv( id, timeout );
}
int platform_uart_recv( unsigned id, unsigned timer_id, s32 timeout )
{
timer_data_type tmr_start, tmr_crt;
int res;
if( timeout == 0 )
return cmn_recv_helper( id, timeout );
else if( timeout == PLATFORM_UART_INFINITE_TIMEOUT )
return cmn_recv_helper( id, timeout );
else
{
// Receive char with the specified timeout
tmr_start = platform_timer_op( timer_id, PLATFORM_TIMER_OP_START, 0 );
while( 1 )
{
if( ( res = cmn_recv_helper( id, 0 ) ) >= 0 )
break;
tmr_crt = platform_timer_op( timer_id, PLATFORM_TIMER_OP_READ, 0 );
if( platform_timer_get_diff_us( timer_id, tmr_crt, tmr_start ) >= timeout )
break;
}
return res;
}
}
static void cmn_rx_handler( int usart_id, u8 data )
{
#ifdef BUILD_SERMUX
if( usart_id == SERMUX_PHYS_ID )
{
if( data != SERMUX_ESCAPE_CHAR )
{
if( ( data >= SERMUX_SERVICE_ID_FIRST ) && data < ( SERMUX_SERVICE_ID_FIRST + SERMUX_NUM_VUART ) )
uart_service_id_in = data;
else if( ( data == SERMUX_FORCE_SID_CHAR ) && ( uart_last_sent != -1 ) )
{
// Retransmit service ID and last char
platform_s_uart_send( SERMUX_PHYS_ID, uart_service_id_out );
if( uart_last_sent & SERMUX_ESC_MASK )
platform_s_uart_send( SERMUX_PHYS_ID, SERMUX_ESCAPE_CHAR );
platform_s_uart_send( SERMUX_PHYS_ID, uart_last_sent & 0xFF );
uart_last_sent = -1;
}
else
{
// Check for an escaped char
if( uart_got_esc )
{
data ^= SERMUX_ESCAPE_XOR_MASK;
uart_got_esc = 0;
}
if( uart_service_id_in == -1 ) // request full restransmit if needed
platform_s_uart_send( SERMUX_PHYS_ID, SERMUX_FORCE_SID_CHAR );
else
buf_write( BUF_ID_UART, uart_service_id_in, ( t_buf_data* )&data );
}
}
else
uart_got_esc = 1;
}
else
#endif // #ifdef BUILD_SERMUX
buf_write( BUF_ID_UART, usart_id, ( t_buf_data* )&data );
}
// Send: version with and without mux
void platform_uart_send( unsigned id, u8 data )
{
#ifdef BUILD_SERMUX
if( id >= SERMUX_SERVICE_ID_FIRST && id < SERMUX_SERVICE_ID_FIRST + SERMUX_NUM_VUART )
{
if( id != uart_service_id_out )
platform_s_uart_send( SERMUX_PHYS_ID, id );
uart_last_sent = data;
if( data == SERMUX_ESCAPE_CHAR || data == SERMUX_FORCE_SID_CHAR || ( data >= SERMUX_SERVICE_ID_FIRST && data <= SERMUX_SERVICE_ID_LAST ) )
{
platform_s_uart_send( SERMUX_PHYS_ID, SERMUX_ESCAPE_CHAR );
platform_s_uart_send( SERMUX_PHYS_ID, data ^ SERMUX_ESCAPE_XOR_MASK );
uart_last_sent = SERMUX_ESC_MASK | ( data ^ SERMUX_ESCAPE_XOR_MASK );
}
else
platform_s_uart_send( SERMUX_PHYS_ID, data );
uart_service_id_out = id;
}
else
#endif // #ifdef BUILD_SERMUX
platform_s_uart_send( id, data );
}
#ifdef BUF_ENABLE_UART
static elua_int_c_handler prev_uart_rx_handler;
static void cmn_uart_rx_inthandler( elua_int_resnum resnum )
{
if( buf_is_enabled( BUF_ID_UART, resnum ) || resnum == SERMUX_PHYS_ID )
cmn_rx_handler( resnum, platform_s_uart_recv( resnum, 0 ) );
// Chain to previous handler
if( prev_uart_rx_handler != NULL )
prev_uart_rx_handler( resnum );
}
#endif // #ifdef BUF_ENABLE_UART
int platform_uart_set_buffer( unsigned id, unsigned log2size )
{
if( id == SERMUX_PHYS_ID ) // mere mortals aren't allowed to mess with VUART physical interface buffering
return PLATFORM_ERR;
#ifdef BUF_ENABLE_UART
if( log2size == 0 )
{
if( id >= SERMUX_SERVICE_ID_FIRST ) // Virtual UARTs need buffers no matter what
return PLATFORM_ERR;
// Disable buffering
buf_set( BUF_ID_UART, id, BUF_SIZE_NONE, BUF_DSIZE_U8 );
}
else
{
// Enable buffering
if( buf_set( BUF_ID_UART, id, log2size, BUF_DSIZE_U8 ) == PLATFORM_ERR )
return PLATFORM_ERR;
if( id >= SERMUX_SERVICE_ID_FIRST ) // No need for aditional setup on virtual UARTs
return PLATFORM_OK;
// Enable UART RX interrupt
if( platform_cpu_set_interrupt( INT_UART_RX, id, PLATFORM_CPU_ENABLE ) != PLATFORM_INT_OK )
return PLATFORM_ERR;
// Setup our C handler
if( elua_int_get_c_handler( INT_UART_RX ) != cmn_uart_rx_inthandler )
prev_uart_rx_handler = elua_int_set_c_handler( INT_UART_RX, cmn_uart_rx_inthandler );
}
return PLATFORM_OK;
#else // BUF_ENABLE_UART
return PLATFORM_ERR;
#endif // BUF_ENABLE_UART
}
#ifdef BUILD_SERMUX
// Setup the serial multiplexer
void cmn_uart_setup_sermux()
{
// Enable UART RX interrupt
if( platform_cpu_set_interrupt( INT_UART_RX, SERMUX_PHYS_ID, PLATFORM_CPU_ENABLE ) == PLATFORM_INT_OK )
{
// Setup our C handler
if( elua_int_get_c_handler( INT_UART_RX ) != cmn_uart_rx_inthandler )
prev_uart_rx_handler = elua_int_set_c_handler( INT_UART_RX, cmn_uart_rx_inthandler );
}
else // We don't have a choice but to get stuck here, as we can't print an error anyway, since the console most likely lives on a virtual UART
while( 1 );
}
#endif // #ifdef BUILD_SERMUX
int platform_uart_set_flow_control( unsigned id, int type )
{
#ifndef PLATFORM_UART_SET_FLOW_CONTROL // the backend does not implement flow control
return PLATFORM_ERR;
#else // #ifndef PLATFORM_UART_SET_FLOW_CONTROL
if( id >= SERMUX_SERVICE_ID_FIRST )
return PLATFORM_ERR;
return platform_s_uart_set_flow_control( id, type );
#endif // #ifndef PLATFORM_UART_SET_FLOW_CONTROL
}

359
src/eluarpc.c Normal file
View File

@ -0,0 +1,359 @@
// eLua RPC mechanism
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include "type.h"
#include "eluarpc.h"
#include "rtype.h"
static u8 eluarpc_err_flag;
// *****************************************************************************
// Internal functions: fdata serialization
static u8 *eluarpc_write_u8( u8 *p, u8 fdata )
{
*p ++ = TYPE_INT_8;
*p ++ = fdata;
return p;
}
static u8* eluarpc_write_op_id( u8 *p, u8 fdata )
{
*p ++ = TYPE_OP_ID;
*p ++ = fdata;
return p;
}
static u8 *eluarpc_write_u16( u8 *p, u16 fdata )
{
*p ++ = TYPE_INT_16;
*p ++ = fdata & 0xFF;
*p ++ = ( fdata >> 8 ) & 0xFF;
return p;
}
static u8 *eluarpc_write_u32( u8 *p, u32 fdata )
{
*p ++ = TYPE_INT_32;
*p ++ = fdata & 0xFF;
*p ++ = ( fdata >> 8 ) & 0xFF;
*p ++ = ( fdata >> 16 ) & 0xFF;
*p ++ = ( fdata >> 24 ) & 0xFF;
return p;
}
static u8 *eluarpc_write_ptr( u8 *p, const void* src, u32 srclen )
{
*p ++ = TYPE_PTR;
p = eluarpc_write_u32( p, srclen );
if( src )
memcpy( p, src, srclen );
return p + srclen;
}
static u8 *eluarpc_write_small_ptr( u8 *p, const void* src, u16 srclen )
{
*p ++ = TYPE_SMALL_PTR;
p = eluarpc_write_u16( p, srclen );
if( src )
memcpy( p, src, srclen );
return p + srclen;
}
// *****************************************************************************
// Internal functions: fdata deserialization
static const u8* eluarpc_read_expect( const u8 *p, u8 fdata )
{
if( *p ++ != fdata )
eluarpc_err_flag = ELUARPC_ERR;
return p;
}
static const u8 *eluarpc_read_u8( const u8 *p, u8 *pfdata )
{
p = eluarpc_read_expect( p, TYPE_INT_8 );
*pfdata = *p ++;
return p;
}
static const u8 *eluarpc_read_op_id( const u8 *p, u8 *pfdata )
{
p = eluarpc_read_expect( p, TYPE_OP_ID );
*pfdata = *p ++;
return p;
}
static const u8* eluarpc_expect_op_id( const u8 *p, u8 id )
{
u8 temp;
p = eluarpc_read_expect( p, TYPE_OP_ID );
temp = *p ++;
if( temp != id )
eluarpc_err_flag = ELUARPC_ERR;
return p;
}
static const u8 *eluarpc_read_u16( const u8 *p, u16 *pfdata )
{
p = eluarpc_read_expect( p, TYPE_INT_16 );
*pfdata = *p ++;
*pfdata |= ( u32 )( *p ++ ) << 8;
return p;
}
static const u8 *eluarpc_read_u32( const u8 *p, u32 *pfdata )
{
p = eluarpc_read_expect( p, TYPE_INT_32 );
*pfdata = *p ++;
*pfdata |= ( u32 )( *p ++ ) << 8;
*pfdata |= ( u32 )( *p ++ ) << 16;
*pfdata |= ( u32 )( *p ++ ) << 24;
return p;
}
static const u8 *eluarpc_read_ptr( const u8 *p, void* src, u32 *psrclen )
{
p = eluarpc_read_expect( p, TYPE_PTR );
p = eluarpc_read_u32( p, psrclen );
if( src && p )
memcpy( src, p, *psrclen );
return p + *psrclen;
}
static const u8 *eluarpc_read_small_ptr( const u8 *p, void* src, u16 *psrclen )
{
p = eluarpc_read_expect( p, TYPE_SMALL_PTR );
p = eluarpc_read_u16( p, psrclen );
if( src && p )
memcpy( src, p, *psrclen );
return p + *psrclen;
}
// *****************************************************************************
// Internal functions: packet handling (read and write)
static u8* eluarpc_packet_ptr;
static u8* eluarpc_start_packet( u8 *p )
{
eluarpc_packet_ptr = p;
p += ELUARPC_START_OFFSET;
*p ++ = TYPE_START;
p = eluarpc_write_u32( p, PACKET_SIG );
return p;
}
static u8* eluarpc_end_packet( u8 *p )
{
u16 len;
*p ++ = TYPE_END;
p = eluarpc_write_u32( p, ~PACKET_SIG );
len = p - eluarpc_packet_ptr;
p = eluarpc_packet_ptr;
*p ++ = TYPE_PKT_SIZE;
eluarpc_write_u16( p, len );
return p;
}
static const u8* eluarpc_match_packet_start( const u8 *p )
{
u32 fdata;
p += ELUARPC_START_OFFSET;
p = eluarpc_read_expect( p, TYPE_START );
p = eluarpc_read_u32( p, &fdata );
if( fdata != PACKET_SIG )
eluarpc_err_flag = ELUARPC_ERR;
return p;
}
static const u8* eluarpc_match_packet_end( const u8 *p )
{
u32 fdata;
p = eluarpc_read_expect( p, TYPE_END );
p = eluarpc_read_u32( p, &fdata );
if( fdata != ~PACKET_SIG )
eluarpc_err_flag = ELUARPC_ERR;
return p;
}
// *****************************************************************************
// Function serialization and deserialization
int eluarpc_get_request_id( const u8 *p, u8 *pid )
{
eluarpc_err_flag = ELUARPC_OK;
p = eluarpc_match_packet_start( p );
p = eluarpc_read_op_id( p, pid );
return eluarpc_err_flag;
}
u32 eluarpc_replace_flag( u32 val, u32 origflag, u32 newflag )
{
return ( val & origflag ) ? newflag : 0;
}
int eluarpc_get_packet_size( const u8 *p, u16 *psize )
{
eluarpc_err_flag = ELUARPC_OK;
p = eluarpc_read_expect( p, TYPE_PKT_SIZE );
p = eluarpc_read_u16( p, psize );
return eluarpc_err_flag;
}
// Generic write function
// Specifiers: o - operation
// r - response
// c - u8
// h - u16
// l - u32
// i - int
// L - s32
// p - ptr (given as ptr, len, len is an u32)
// P - ptr (given as ptr, len, len is an u16)
void eluarpc_gen_write( u8 *p, const char *fmt, ... )
{
va_list ap;
const void *ptr;
u32 ptrlen;
va_start( ap, fmt );
p = eluarpc_start_packet( p );
while( *fmt )
switch( *fmt ++ )
{
case 'o':
p = eluarpc_write_op_id( p, va_arg( ap, int ) );
break;
case 'r':
*p++ = ELUARPC_OP_RES_MOD | ( u8 )va_arg( ap, int );
break;
case 'c':
p = eluarpc_write_u8( p, ( u8 )va_arg( ap, int ) );
break;
case 'h':
p = eluarpc_write_u16( p, ( u16 )va_arg( ap, int ) );
break;
case 'i':
p = eluarpc_write_u32( p, ( u32 )va_arg( ap, int ) );
break;
case 'l':
p = eluarpc_write_u32( p, ( u32 )va_arg( ap, u32 ) );
break;
case 'L':
p = eluarpc_write_u32( p, ( u32 )va_arg( ap, s32 ) );
break;
case 'p':
ptr = va_arg( ap, void* );
ptrlen = ( u32 )va_arg( ap, u32 );
p = eluarpc_write_ptr( p, ptr, ptrlen );
break;
case 'P':
ptr = va_arg( ap, void * );
ptrlen = ( u16 )va_arg( ap, int );
p = eluarpc_write_small_ptr( p, ptr, ptrlen );
break;
}
eluarpc_end_packet( p );
}
// Generic read function
// Specifiers: o - operation
// r - response
// c - u8
// h - u16
// l - u32
// L - s32
// i - int
// p - ptr (returned as ptr, len, len is an u32)
// P - ptr (returned as ptr, len, len is an u16)
int eluarpc_gen_read( const u8 *p, const char *fmt, ... )
{
va_list ap;
const void *pptr;
u32 *ptrlen;
const u8 *tempptr;
u32 temp32;
u16 temp16;
u16 *sptrlen;
va_start( ap, fmt );
eluarpc_err_flag = ELUARPC_OK;
p = eluarpc_match_packet_start( p );
while( *fmt )
switch( *fmt ++ )
{
case 'o':
p = eluarpc_expect_op_id( p, va_arg( ap, int ) );
break;
case 'r':
p = eluarpc_read_expect( p, ELUARPC_OP_RES_MOD | ( u8 )va_arg( ap, int ) );
break;
case 'c':
p = eluarpc_read_u8( p, ( u8* )va_arg( ap, void * ) );
break;
case 'h':
p = eluarpc_read_u16( p, ( u16* )va_arg( ap, void * ) );
break;
case 'l':
p = eluarpc_read_u32( p, ( u32* )va_arg( ap, void * ) );
break;
case 'L':
p = eluarpc_read_u32( p, &temp32 );
*( s32 *)va_arg( ap, void * ) = ( s32 )temp32;
break;
case 'i':
p = eluarpc_read_u32( p, &temp32 );
*( int* )va_arg( ap, void * ) = ( int )temp32;
break;
case 'p':
pptr = va_arg( ap, void** );
ptrlen = ( u32* )va_arg( ap, void* );
tempptr = p;
p = eluarpc_read_ptr( p, NULL, &temp32 );
if( p == tempptr + ELUARPC_PTR_HEADER_SIZE )
*( const u8** )pptr = NULL;
else
*( const u8** )pptr = tempptr + ELUARPC_PTR_HEADER_SIZE;
if( ptrlen )
*ptrlen = temp32;
break;
case 'P':
pptr = va_arg( ap, void** );
sptrlen = ( u16* )va_arg( ap, void* );
tempptr = p;
p = eluarpc_read_small_ptr( p, NULL, &temp16 );
if( p == tempptr + ELUARPC_SMALL_PTR_HEADER_SIZE )
*( const u8** )pptr = NULL;
else
*( const u8** )pptr = tempptr + ELUARPC_SMALL_PTR_HEADER_SIZE;
if( sptrlen )
*sptrlen = temp16;
break;
}
eluarpc_match_packet_end( p );
return eluarpc_err_flag;
}

View File

@ -13,6 +13,7 @@
#include <string.h>
#define MAX_VTIMER_NAME_LEN 6
#define MIN_VTIMER_NAME_LEN 5
// Helper function for the read/start functions
static int tmrh_timer_op( lua_State* L, int op )
@ -147,7 +148,7 @@ static int tmr_mt_index( lua_State* L )
char* pend;
long res;
if( strlen( key ) > MAX_VTIMER_NAME_LEN || strlen( key ) < 5 )
if( strlen( key ) > MAX_VTIMER_NAME_LEN || strlen( key ) < MIN_VTIMER_NAME_LEN )
return 0;
if( strncmp( key, "VIRT", 4 ) )
return 0;

View File

@ -6,8 +6,12 @@
#include "platform.h"
#include "auxmods.h"
#include "lrotable.h"
#include "common.h"
#include "sermux.h"
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "platform_conf.h"
// Modes for the UART read function
enum
@ -26,6 +30,8 @@ static int uart_setup( lua_State* L )
id = luaL_checkinteger( L, 1 );
MOD_CHECK_ID( uart, id );
if( id >= SERMUX_SERVICE_ID_FIRST )
return luaL_error( L, "uart.setup can't be called on virtual UARTs" );
baud = luaL_checkinteger( L, 2 );
databits = luaL_checkinteger( L, 3 );
parity = luaL_checkinteger( L, 4 );
@ -64,6 +70,7 @@ static int uart_write( lua_State* L )
}
return 0;
}
static int uart_read( lua_State* L )
{
int id, res, mode, issign;
@ -115,6 +122,8 @@ static int uart_read( lua_State* L )
cres = ( char )res;
count ++;
issign = ( count == 1 ) && ( ( res == '-' ) || ( res == '+' ) );
// [TODO] this only works for lines that actually end with '\n', other line endings
// are not supported.
if( ( cres == '\n' ) && ( mode == UART_READ_MODE_LINE ) )
break;
if( !isdigit( cres ) && !issign && ( mode == UART_READ_MODE_NUMBER ) )
@ -168,6 +177,62 @@ static int uart_getchar( lua_State* L )
return 1;
}
// Lua: uart.set_buffer( id, size )
static int uart_set_buffer( lua_State *L )
{
int id = luaL_checkinteger( L, 1 );
u32 size = ( u32 )luaL_checkinteger( L, 2 );
MOD_CHECK_ID( uart, id );
if( size && ( size & ( size - 1 ) ) )
return luaL_error( L, "the buffer size must be a power of 2 or 0" );
if( size == 0 && id >= SERMUX_SERVICE_ID_FIRST )
return luaL_error( L, "disabling buffers on virtual UARTs is not allowed" );
if( platform_uart_set_buffer( id, intlog2( size ) ) == PLATFORM_ERR )
return luaL_error( L, "unable to set UART buffer" );
return 0;
}
// Lua: uart.set_flow_control( id, type )
static int uart_set_flow_control( lua_State *L )
{
int id = luaL_checkinteger( L, 1 );
int type = luaL_checkinteger( L, 2 );
MOD_CHECK_ID( uart, id );
if( platform_uart_set_flow_control( id, type ) != PLATFORM_OK )
return luaL_error( L, "unable to set the flow control on interface %d", id );
return 0;
}
#ifdef BUILD_SERMUX
#define MAX_VUART_NAME_LEN 6
#define MIN_VUART_NAME_LEN 6
// __index metafunction for UART
// Look for all VUARTx timer identifiers
static int uart_mt_index( lua_State* L )
{
const char *key = luaL_checkstring( L ,2 );
char* pend;
long res;
if( strlen( key ) > MAX_VUART_NAME_LEN || strlen( key ) < MIN_VUART_NAME_LEN )
return 0;
if( strncmp( key, "VUART", 5 ) )
return 0;
res = strtol( key + 5, &pend, 10 );
if( *pend != '\0' )
return 0;
if( res >= SERMUX_NUM_VUART )
return 0;
lua_pushinteger( L, SERMUX_SERVICE_ID_FIRST + res );
return 1;
}
#endif // #ifdef BUILD_SERMUX
// Module function map
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
@ -177,6 +242,8 @@ const LUA_REG_TYPE uart_map[] =
{ LSTRKEY( "write" ), LFUNCVAL( uart_write ) },
{ LSTRKEY( "read" ), LFUNCVAL( uart_read ) },
{ LSTRKEY( "getchar" ), LFUNCVAL( uart_getchar ) },
{ LSTRKEY( "set_buffer" ), LFUNCVAL( uart_set_buffer ) },
{ LSTRKEY( "set_flow_control" ), LFUNCVAL( uart_set_flow_control ) },
#if LUA_OPTIMIZE_MEMORY > 0
{ LSTRKEY( "PAR_EVEN" ), LNUMVAL( PLATFORM_UART_PARITY_EVEN ) },
{ LSTRKEY( "PAR_ODD" ), LNUMVAL( PLATFORM_UART_PARITY_ODD ) },
@ -186,6 +253,13 @@ const LUA_REG_TYPE uart_map[] =
{ LSTRKEY( "STOP_2" ), LNUMVAL( PLATFORM_UART_STOPBITS_2 ) },
{ LSTRKEY( "NO_TIMEOUT" ), LNUMVAL( 0 ) },
{ LSTRKEY( "INF_TIMEOUT" ), LNUMVAL( PLATFORM_UART_INFINITE_TIMEOUT ) },
{ LSTRKEY( "FLOW_NONE" ), LNUMVAL( PLATFORM_UART_FLOW_NONE ) },
{ LSTRKEY( "FLOW_RTS" ), LNUMVAL( PLATFORM_UART_FLOW_RTS ) },
{ LSTRKEY( "FLOW_CTS" ), LNUMVAL( PLATFORM_UART_FLOW_CTS ) },
#endif
#if LUA_OPTIMIZE_MEMORY > 0 && defined( BUILD_SERMUX )
{ LSTRKEY( "__metatable" ), LROVAL( uart_map ) },
{ LSTRKEY( "__index" ), LFUNCVAL( uart_mt_index ) },
#endif
{ LNILKEY, LNILVAL }
};
@ -208,7 +282,12 @@ LUALIB_API int luaopen_uart( lua_State *L )
// Add the "none" and "infinite" constant used in recv()
MOD_REG_NUMBER( L, "NO_TIMEOUT", 0 );
MOD_REG_NUMBER( L, "INF_TIMEOUT", PLATFORM_UART_INFINITE_TIMEOUT );
// Add the UART flow constants
MOD_REG_NUMBER( L, "FLOW_RTS", PLATFORM_UART_FLOW_RTS );
MOD_REG_NUMBER( L, "FLOW_CTS", PLATFORM_UART_FLOW_CTS );
return 1;
#endif // #if LUA_OPTIMIZE_MEMORY > 0
}

View File

@ -2,7 +2,7 @@
cpumode = ARGUMENTS.get( 'cpumode', 'thumb' ).lower()
specific_files = "board_cstartup.s board_lowlevel.c board_memories.c usart.c pmc.c pio.c platform.c tc.c pwmc.c aic.c"
specific_files = "board_cstartup.s board_lowlevel.c board_memories.c usart.c pmc.c pio.c platform.c tc.c pwmc.c aic.c platform_int.c"
if comp[ 'cpu' ] == 'AT91SAM7X256':
ldscript = "flash256.lds"
comp.Append(CPPDEFINES = 'at91sam7x256')

View File

@ -56,29 +56,10 @@ static void __attribute__((naked)) ISR_Tc2()
}
#endif
// Buffered UART support
#ifdef BUF_ENABLE_UART
static volatile u32 c;
static AT91S_USART* pbase = CON_UART_ID == 0 ? AT91C_BASE_US0 : AT91C_BASE_US1;
void __uart_rx_handler_helper()
{
c = pbase->US_CSR;
c = pbase->US_RHR;
buf_write( BUF_ID_UART, CON_UART_ID, ( t_buf_data* )&c );
}
static void __attribute__((naked)) uart_rx_handler()
{
INT_STUB( __uart_rx_handler_helper );
}
#endif
int platform_init()
{
int i;
unsigned int mode = AT91C_US_USMODE_NORMAL | AT91C_US_CLKS_CLOCK | AT91C_US_CHRL_8_BITS |
AT91C_US_PAR_NONE | AT91C_US_NBSTOP_1_BIT | AT91C_US_CHMODE_NORMAL;
// Enable the peripherals we use in the PMC
PMC_EnablePeripheral( AT91C_ID_US0 );
PMC_EnablePeripheral( AT91C_ID_US1 );
@ -87,27 +68,7 @@ int platform_init()
PMC_EnablePeripheral( AT91C_ID_TC0 );
PMC_EnablePeripheral( AT91C_ID_TC1 );
PMC_EnablePeripheral( AT91C_ID_TC2 );
PMC_EnablePeripheral( AT91C_ID_PWMC );
// Configure pins
PIO_Configure( platform_uart_pins[ CON_UART_ID ], PIO_LISTSIZE( platform_uart_pins[ CON_UART_ID ] ) );
// Configure the USART in the desired mode @115200 bauds
AT91S_USART *pusart = CON_UART_ID == 0 ? AT91C_BASE_US0 : AT91C_BASE_US1;
USART_Configure( pusart, mode, CON_UART_SPEED, BOARD_MCK );
// Enable receiver & transmitter
USART_SetTransmitterEnabled( pusart, 1 );
USART_SetReceiverEnabled( pusart, 1 );
#if defined( BUF_ENABLE_UART ) && defined( CON_BUF_SIZE )
// Enable buffering on the console UART
buf_set( BUF_ID_UART, CON_UART_ID, CON_BUF_SIZE, BUF_DSIZE_U8 );
// Set interrupt handler and interrupt flag on UART
unsigned uart_id = CON_UART_ID == 0 ? AT91C_ID_US0 : AT91C_ID_US1;
AIC_DisableIT( uart_id );
AIC_ConfigureIT( uart_id, 0, uart_rx_handler );
pusart->US_IER = AT91C_US_RXRDY;
AIC_EnableIT( uart_id );
#endif
PMC_EnablePeripheral( AT91C_ID_PWMC );
// Configure the timers
AT91C_BASE_TCB->TCB_BMR = 0x15;
@ -260,7 +221,7 @@ u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int st
return baud;
}
void platform_uart_send( unsigned id, u8 data )
void platform_s_uart_send( unsigned id, u8 data )
{
AT91S_USART* base = id == 0 ? AT91C_BASE_US0 : AT91C_BASE_US1;

View File

@ -6,6 +6,9 @@
#include "auxmods.h"
#include "board.h"
#include "stacks.h"
#include "buf.h"
#include "elua_int.h"
#include "sermux.h"
// *****************************************************************************
// Define here what components you want for this platform
@ -16,11 +19,15 @@
#define BUILD_TERM
#define BUILD_CON_GENERIC
//#define BUILD_RPC
#define BUILD_RFS
#define BUILD_SERMUX
#define BUILD_C_INT_HANDLERS
// *****************************************************************************
// UART/Timer IDs configuration data (used in main.c)
#define CON_UART_ID 0
#define CON_UART_ID ( SERMUX_SERVICE_ID_FIRST + 1 )
//#define CON_UART_ID 0
#define CON_UART_SPEED 115200
#define CON_TIMER_ID 0
#define TERM_LINES 25
@ -104,4 +111,22 @@
#define MEM_START_ADDRESS { ( void* )end }
#define MEM_END_ADDRESS { ( void* )( SRAM_ORIGIN + SRAM_SIZE - STACK_SIZE_TOTAL - 1 ) }
#define RFS_BUFFER_SIZE BUF_SIZE_512
#define RFS_UART_ID ( SERMUX_SERVICE_ID_FIRST )
#define RFS_TIMER_ID 0
#define RFS_TIMEOUT 100000
#define RFS_UART_SPEED 115200
#define SERMUX_PHYS_ID 0
#define SERMUX_PHYS_SPEED 115200
#define SERMUX_NUM_VUART 2
#define SERMUX_BUFFER_SIZES { RFS_BUFFER_SIZE, CON_BUF_SIZE }
// Interrupt list
#define INT_UART_RX ELUA_INT_FIRST_ID
#define INT_ELUA_LAST INT_UART_RX
#define PLATFORM_CPU_CONSTANTS\
_C( INT_UART_RX )
#endif // #ifndef __PLATFORM_CONF_H__

View File

@ -0,0 +1,117 @@
// AVR32 interrupt support
#include "platform_conf.h"
#if defined( BUILD_C_INT_HANDLERS ) || defined( BUILD_LUA_INT_HANDLERS )
// Generic headers
#include "platform.h"
#include "elua_int.h"
#include "common.h"
// Platform includes
#include "aic.h"
#include <board.h>
// "Stubs" used for our interrupt handlers
// Just a trick to avoid interworking and some other complications
#define INT_STUB( func )\
asm volatile(\
"push {lr}\n\t"\
"bl " #func "\n\t"\
"pop {r0}\n\t"\
"bx r0\n\t"\
)\
// ****************************************************************************
// Interrupt handlers
// ----------------------------------------------------------------------------
// UART_RX interrupt
static const int usart_int_ids[] = { AT91C_ID_US0, AT91C_ID_US1 };
static AT91S_USART* const usart_bases[] = { AT91C_BASE_US0, AT91C_BASE_US1 };
static void uart_common_rx_handler( int resnum )
{
cmn_int_handler( INT_UART_RX, resnum );
AT91C_BASE_AIC->AIC_ICCR = 1 << usart_int_ids[ resnum ];
AT91C_BASE_AIC->AIC_EOICR = 0;
}
void __uart0_rx_handler_helper()
{
uart_common_rx_handler( 0 );
}
static void __attribute__((naked)) uart0_rx_handler()
{
INT_STUB( __uart0_rx_handler_helper );
}
void __uart1_rx_handler_helper()
{
uart_common_rx_handler( 1 );
}
static void __attribute__((naked)) uart1_rx_handler()
{
INT_STUB( __uart1_rx_handler_helper );
}
// ****************************************************************************
// Interrupt: INT_UART_RX
static int int_uart_rx_get_status( elua_int_resnum resnum )
{
volatile AT91S_USART *pusart = ( volatile AT91S_USART* )usart_bases[ resnum ];
return ( pusart->US_IMR & AT91C_US_RXRDY ) ? 1 : 0;
}
static int int_uart_rx_set_status( elua_int_resnum resnum, int status )
{
volatile AT91S_USART *pusart = ( volatile AT91S_USART* )usart_bases[ resnum ];
int prev = int_uart_rx_get_status( resnum );
if( status == PLATFORM_CPU_ENABLE )
pusart->US_IER = AT91C_US_RXRDY;
else
pusart->US_IDR = AT91C_US_RXRDY;
return prev;
}
static int int_uart_rx_get_flag( elua_int_resnum resnum, int clear )
{
volatile AT91S_USART *pusart = ( volatile AT91S_USART* )usart_bases[ resnum ];
( void )clear; // Note: this interrupt will be cleared automatically when the RHR is read
return( pusart->US_CSR & AT91C_US_RXRDY ) ? 1 : 0;
}
// ****************************************************************************
// Interrupt initialization
typedef void ( *phandler )();
static phandler phandlers[] = { uart0_rx_handler, uart1_rx_handler };
void platform_int_init()
{
unsigned i;
for( i = 0; i < NUM_UART; i ++ )
{
AIC_ConfigureIT( usart_int_ids[ i ], 0, phandlers[ i ] );
AIC_EnableIT( usart_int_ids[ i ] );
}
}
// ****************************************************************************
// Interrupt table
// Must have a 1-to-1 correspondence with the interrupt enum in platform_conf.h!
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 }
};
#endif // #if defined( BUILD_C_INT_HANDLERS ) || defined( BUILD_LUA_INT_HANDLERS )

View File

@ -4,6 +4,8 @@
#define __EVK1100_CONF_H__
#include "sdramc.h"
#include "sermux.h"
#include "buf.h"
// *****************************************************************************
// Define here what components you want for this platform
@ -15,11 +17,16 @@
#define BUILD_TERM
#define BUILD_CON_GENERIC
//#define BUILD_RPC
#define BUILD_C_INT_HANDLERS
#define BUILA_LUA_INT_HANDLERS
#define BUILD_RFS
#define BUILD_SERMUX
// *****************************************************************************
// UART/Timer IDs configuration data (used in main.c)
#define CON_UART_ID 0
#define CON_UART_ID ( SERMUX_SERVICE_ID_FIRST + 1 )
//#define CON_UART_ID 0
#define CON_UART_SPEED 115200
#define CON_TIMER_ID 0
#define TERM_LINES 25
@ -101,8 +108,6 @@
// Enable RX buffering on UART
#define BUF_ENABLE_UART
#define CON_BUF_SIZE BUF_SIZE_128
// REMEMBER to change next line if buffering is enabled and CON_UART_ID is not 0!
#define CON_UART_IRQ AVR32_USART0_IRQ
// SD/MMC Filesystem Setup
#define MMCFS_TICK_HZ 10
@ -127,6 +132,24 @@
#define MEM_START_ADDRESS { ( void* )end, ( void* )SDRAM }
#define MEM_END_ADDRESS { ( void* )( 0x10000 - STACK_SIZE_TOTAL - 1 ), ( void* )( SDRAM + SDRAM_SIZE - 1 ) }
#define RFS_BUFFER_SIZE BUF_SIZE_512
#define RFS_UART_ID ( SERMUX_SERVICE_ID_FIRST )
#define RFS_TIMER_ID 0
#define RFS_TIMEOUT 100000
#define RFS_UART_SPEED 115200
#define SERMUX_PHYS_ID 0
#define SERMUX_PHYS_SPEED 115200
#define SERMUX_NUM_VUART 2
#define SERMUX_BUFFER_SIZES { RFS_BUFFER_SIZE, CON_BUF_SIZE }
// Interrupt list
#define INT_UART_RX ELUA_INT_FIRST_ID
#define INT_ELUA_LAST INT_UART_RX
#define PLATFORM_CPU_CONSTANTS\
_C( INT_UART_RX )
// *****************************************************************************
// CPU constants that should be exposed to the eLua "cpu" module

View File

@ -13,6 +13,7 @@
#define BUILD_TERM
#define BUILD_CON_GENERIC
//#define BUILD_RPC
#define BUILD_C_INT_HANDLERS
// *****************************************************************************
// UART/Timer IDs configuration data (used in main.c)
@ -89,8 +90,6 @@
// Enable RX buffering on UART
#define BUF_ENABLE_UART
#define CON_BUF_SIZE BUF_SIZE_128
// REMEMBER to change next line if buffering is enabled and CON_UART_ID is not 0!
#define CON_UART_IRQ AVR32_USART1_IRQ
// SD/MMC Filesystem Setup
#define MMCFS_TICK_HZ 10
@ -115,7 +114,13 @@
#define MEM_START_ADDRESS { ( void* )end }
#define MEM_END_ADDRESS { ( void* )( AVR32_SRAM_SIZE - STACK_SIZE_TOTAL - 1 ) }
// Interrupt list
#define INT_UART_RX ELUA_INT_FIRST_ID
#define INT_ELUA_LAST INT_UART_RX
#define PLATFORM_CPU_CONSTANTS\
_C( INT_UART_RX )
// *****************************************************************************
// CPU constants that should be exposed to the eLua "cpu" module

View File

@ -1,6 +1,6 @@
# Configuration file for the AVR32 microcontrollers
specific_files = "crt0.s trampoline.s platform.c exception.s intc.c pm.c flashc.c pm_conf_clocks.c usart.c gpio.c tc.c spi.c"
specific_files = "crt0.s trampoline.s platform.c exception.s intc.c pm.c flashc.c pm_conf_clocks.c usart.c gpio.c tc.c spi.c platform_int.c"
comp.Append(CPPDEFINES = 'FORAVR32')
# See board.h for possible BOARD values.

View File

@ -47,7 +47,7 @@ __attribute__((__interrupt__)) static void tmr_int_handler()
}
#endif
static const u32 uart_base_addr[ ] = {
const u32 uart_base_addr[ ] = {
AVR32_USART0_ADDRESS,
AVR32_USART1_ADDRESS,
AVR32_USART2_ADDRESS,
@ -56,20 +56,6 @@ static const u32 uart_base_addr[ ] = {
#endif
};
// Buffered UART support
#ifdef BUF_ENABLE_UART
__attribute__((__interrupt__)) static void uart_rx_handler()
{
int c;
t_buf_data temp;
volatile avr32_usart_t *pusart = ( volatile avr32_usart_t* )uart_base_addr[ CON_UART_ID ];
usart_read_char( pusart, &c );
temp = ( t_buf_data )c;
buf_write( BUF_ID_UART, CON_UART_ID, &temp );
}
#endif
extern void alloc_init();
int platform_init()
@ -124,19 +110,7 @@ int platform_init()
#ifdef AVR32_SDRAMC
sdramc_init( REQ_CPU_FREQ );
#endif
// Setup UART for eLua
platform_uart_setup( CON_UART_ID, CON_UART_SPEED, 8, PLATFORM_UART_PARITY_NONE, PLATFORM_UART_STOPBITS_1 );
#if defined( BUF_ENABLE_UART ) && defined( CON_BUF_SIZE )
// Enable buffering on the console UART
buf_set( BUF_ID_UART, CON_UART_ID, CON_BUF_SIZE, BUF_DSIZE_U8 );
// Set interrupt handler and interrupt flag on UART
INTC_register_interrupt( &uart_rx_handler, CON_UART_IRQ, AVR32_INTC_INT0 );
volatile avr32_usart_t *pusart = ( volatile avr32_usart_t* )uart_base_addr[ CON_UART_ID ];
pusart->ier = AVR32_USART_IER_RXRDY_MASK;
Enable_global_interrupt();
#endif
// Setup timers
for( i = 0; i < 3; i ++ )
{
@ -439,11 +413,12 @@ u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int st
return baud;
}
void platform_uart_send( unsigned id, u8 data )
void platform_s_uart_send( unsigned id, u8 data )
{
volatile avr32_usart_t *pusart = ( volatile avr32_usart_t* )uart_base_addr[ id ];
usart_putchar( pusart, data );
while( !usart_tx_ready( pusart ) );
pusart->thr = ( data << AVR32_USART_THR_TXCHR_OFFSET ) & AVR32_USART_THR_TXCHR_MASK;
}
int platform_s_uart_recv( unsigned id, s32 timeout )

View File

@ -0,0 +1,113 @@
// AVR32 interrupt support
#include "platform_conf.h"
#if defined( BUILD_C_INT_HANDLERS ) || defined( BUILD_LUA_INT_HANDLERS )
// Generic headers
#include "platform.h"
#include "elua_int.h"
#include "common.h"
// Platform includes
#include <avr32/io.h>
#include "usart.h"
#include "intc.h"
// ****************************************************************************
// Interrupt handlers
// ----------------------------------------------------------------------------
// UART_RX interrupt
#ifndef AVR32_USART2_IRQ
#define AVR32_USART2_IRQ ( -1 )
#endif
#ifndef AVR32_USART3_IRQ
#define AVR32_USART3_IRQ ( -1 )
#endif
extern const u32 uart_base_addr[];
static int usart_irqs[] = { AVR32_USART0_IRQ, AVR32_USART1_IRQ, AVR32_USART2_IRQ, AVR32_USART3_IRQ };
static void uart_common_rx_handler( int resnum )
{
cmn_int_handler( INT_UART_RX, resnum );
}
__attribute__((__interrupt__)) static void uart0_rx_handler()
{
uart_common_rx_handler( 0 );
}
__attribute__((__interrupt__)) static void uart1_rx_handler()
{
uart_common_rx_handler( 1 );
}
__attribute__((__interrupt__)) static void uart2_rx_handler()
{
uart_common_rx_handler( 2 );
}
__attribute__((__interrupt__)) static void uart3_rx_handler()
{
uart_common_rx_handler( 3 );
}
// ****************************************************************************
// Interrupt: INT_UART_RX
static int int_uart_rx_get_status( elua_int_resnum resnum )
{
volatile avr32_usart_t *pusart = ( volatile avr32_usart_t* )uart_base_addr[ resnum ];
return ( pusart->imr & AVR32_USART_IMR_RXRDY_MASK ) ? 1 : 0;
}
static int int_uart_rx_set_status( elua_int_resnum resnum, int status )
{
volatile avr32_usart_t *pusart = ( volatile avr32_usart_t* )uart_base_addr[ resnum ];
int prev = int_uart_rx_get_status( resnum );
if( status == PLATFORM_CPU_ENABLE )
pusart->ier = AVR32_USART_IER_RXRDY_MASK;
else
pusart->idr = AVR32_USART_IDR_RXRDY_MASK;
return prev;
}
static int int_uart_rx_get_flag( elua_int_resnum resnum, int clear )
{
volatile avr32_usart_t *pusart = ( volatile avr32_usart_t* )uart_base_addr[ resnum ];
( void )clear; // the flag is automatically cleared after reading the UART char
return ( pusart->csr & AVR32_USART_CSR_RXRDY_MASK ) ? 1 : 0;
}
// ****************************************************************************
// Interrupt initialization
typedef void ( *phandler )();
static phandler phandlers[] = { uart0_rx_handler, uart1_rx_handler, uart2_rx_handler, uart3_rx_handler };
void platform_int_init()
{
unsigned i;
for( i = 0; i < NUM_UART; i ++ )
INTC_register_interrupt( phandlers[ i ], usart_irqs[ i ], AVR32_INTC_INT0 );
Enable_global_interrupt();
}
// ****************************************************************************
// Interrupt table
// Must have a 1-to-1 correspondence with the interrupt enum in platform_conf.h!
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 }
};
#endif // #if defined( BUILD_C_INT_HANDLERS ) || defined( BUILD_LUA_INT_HANDLERS )

View File

@ -146,7 +146,7 @@ u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int st
return 0;
}
void platform_uart_send( unsigned id, u8 data )
void platform_s_uart_send( unsigned id, u8 data )
{
}
@ -180,6 +180,19 @@ int platform_cpu_get_global_interrupts()
return 0;
}
// ****************************************************************************
// "Dummy" CPU functions
int platform_cpu_set_global_interrupts( int status )
{
return 0;
}
int platform_cpu_get_global_interrupts()
{
return 0;
}
// ****************************************************************************
// Allocator support

View File

@ -28,6 +28,7 @@
// Bogus defines for common.c
#define CON_UART_ID 0
#define CON_UART_SPEED 0
#define CON_TIMER_ID 0
// *****************************************************************************

View File

@ -1,5 +1,5 @@
# Configuration file for the LM3S microcontroller
specific_files = "startup_gcc.c platform.c uart.c sysctl.c gpio.c ssi.c timer.c pwm.c ethernet.c systick.c flash.c interrupt.c cpu.c adc.c can.c"
specific_files = "startup_gcc.c platform.c uart.c sysctl.c gpio.c ssi.c timer.c pwm.c ethernet.c systick.c flash.c interrupt.c cpu.c adc.c can.c platform_int.c"
if comp[ 'board' ] == 'EK-LM3S1968' or comp[ 'board' ] == 'EK-LM3S6965' or comp[ 'board' ] == 'EK-LM3S8962':
specific_files = specific_files + " rit128x96x4.c disp.c"

View File

@ -402,52 +402,17 @@ void platform_spi_select( unsigned id, int is_select )
// Different configurations for LM3S8962, LM3S6918 (2 UARTs) and LM3S6965, LM3S9B92 (3 UARTs)
// All possible LM3S uarts defs
static const u32 uart_base[] = { UART0_BASE, UART1_BASE, UART2_BASE };
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 };
#ifdef BUF_ENABLE_UART
void UARTIntHandler()
{
u32 temp;
int c;
temp = MAP_UARTIntStatus(uart_base[ CON_UART_ID ], true);
MAP_UARTIntClear(uart_base[ CON_UART_ID ], temp);
while( MAP_UARTCharsAvail( uart_base[ CON_UART_ID ] ) )
{
c = MAP_UARTCharGetNonBlocking( uart_base[ CON_UART_ID ] );
buf_write( BUF_ID_UART, CON_UART_ID, ( t_buf_data* )&c );
}
}
#endif
static void uarts_init()
{
unsigned i;
for( i = 0; i < NUM_UART; i ++ )
MAP_SysCtlPeripheralEnable(uart_sysctl[ i ]);
// Special case for UART 0
// Configure the UART for 115,200, 8-N-1 operation.
MAP_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
MAP_UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), CON_UART_SPEED,
(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
UART_CONFIG_PAR_NONE));
#if defined( BUF_ENABLE_UART ) && defined( CON_BUF_SIZE )
// Enable buffering on the console UART
buf_set( BUF_ID_UART, CON_UART_ID, CON_BUF_SIZE, BUF_DSIZE_U8 );
// Set interrupt handler and interrupt flag on UART
IntEnable(INT_UART0);
MAP_UARTIntEnable( uart_base[ CON_UART_ID ], UART_INT_RX | UART_INT_RT );
#endif
}
u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int stopbits )
@ -484,7 +449,7 @@ u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int st
return baud;
}
void platform_uart_send( unsigned id, u8 data )
void platform_s_uart_send( unsigned id, u8 data )
{
MAP_UARTCharPut( uart_base[ id ], data );
}

View File

@ -8,6 +8,7 @@
#include "hw_types.h"
#include "stacks.h"
#include "sysctl.h"
#include "elua_int.h"
// *****************************************************************************
// Define here what components you want for this platform
@ -26,6 +27,7 @@
#define BUILD_ADC
#define BUILD_RPC
//#define BUILD_CON_TCP
#define BUILD_C_INT_HANDLERS
// *****************************************************************************
// UART/Timer IDs configuration data (used in main.c)
@ -165,8 +167,8 @@
#define NUM_CAN 1
// Enable RX buffering on UART
//#define BUF_ENABLE_UART
//#define CON_BUF_SIZE BUF_SIZE_128
#define BUF_ENABLE_UART
#define CON_BUF_SIZE BUF_SIZE_128
// ADC Configuration Params
#define ADC_BIT_RESOLUTION 10
@ -236,6 +238,10 @@
#define MEM_START_ADDRESS { ( void* )end }
#define MEM_END_ADDRESS { ( void* )( SRAM_BASE + SRAM_SIZE - STACK_SIZE_TOTAL - 1 ) }
// Interrupt list
#define INT_UART_RX ELUA_INT_FIRST_ID
#define INT_ELUA_LAST INT_UART_RX
// *****************************************************************************
// CPU constants that should be exposed to the eLua "cpu" module
@ -289,6 +295,7 @@
_C( INT_USB0 ),\
_C( INT_PWM3 ),\
_C( INT_UDMA ),\
_C( INT_UDMAERR )
_C( INT_UDMAERR ),\
_C( INT_UART_RX )
#endif // #ifndef __PLATFORM_CONF_H__

View File

@ -0,0 +1,109 @@
// AVR32 interrupt support
#include "platform_conf.h"
#if defined( BUILD_C_INT_HANDLERS ) || defined( BUILD_LUA_INT_HANDLERS )
// Generic headers
#include "platform.h"
#include "elua_int.h"
#include "common.h"
// Platform includes
#ifdef FORLM3S9B92
#define TARGET_IS_TEMPEST_RB1
#include "lm3s9b92.h"
#elif FORLM3S8962
#include "lm3s8962.h"
#elif FORLM3S6965
#include "lm3s6965.h"
#elif FORLM3S6918
#include "lm3s6918.h"
#endif
#include "rom.h"
#include "rom_map.h"
#include "hw_ints.h"
#include "uart.h"
#include "interrupt.h"
// ****************************************************************************
// Interrupt handlers
// ----------------------------------------------------------------------------
// 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 );
while( MAP_UARTCharsAvail( uart_base[ resnum ] ) )
cmn_int_handler( INT_UART_RX, resnum );
}
void uart0_handler()
{
uart_common_rx_handler( 0 );
}
void uart1_handler()
{
uart_common_rx_handler( 1 );
}
void uart2_handler()
{
uart_common_rx_handler( 2 );
}
// ****************************************************************************
// Interrupt: INT_UART_RX
static int int_uart_rx_get_status( elua_int_resnum resnum )
{
return ( MAP_UARTIntStatus( uart_base[ resnum ], false ) & uart_int_mask ) == uart_int_mask ? 1 : 0;
}
static int int_uart_rx_set_status( elua_int_resnum resnum, int status )
{
int prev = int_uart_rx_get_status( resnum );
if( status == PLATFORM_CPU_ENABLE )
MAP_UARTIntEnable( uart_base[ resnum ], uart_int_mask );
else
MAP_UARTIntDisable( uart_base[ resnum ], uart_int_mask );
return prev;
}
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;
if( clear )
MAP_UARTIntClear( uart_base[ resnum ], uart_int_mask );
return flag;
}
// ****************************************************************************
// Interrupt initialization
void platform_int_init()
{
IntEnable( INT_UART0 );
IntEnable( INT_UART1 );
IntEnable( INT_UART2 );
}
// ****************************************************************************
// Interrupt table
// Must have a 1-to-1 correspondence with the interrupt enum in platform_conf.h!
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 }
};
#endif // #if defined( BUILD_C_INT_HANDLERS ) || defined( BUILD_LUA_INT_HANDLERS )

View File

@ -46,6 +46,11 @@ extern void CANIntHandler();
#include "hw_memmap.h"
#include "platform_conf.h"
extern void uart0_handler();
extern void uart1_handler();
extern void uart2_handler();
//*****************************************************************************
//
// The entry point for the application.
@ -84,12 +89,16 @@ void (* const g_pfnVectors[])(void) =
IntDefaultHandler, // GPIO Port C
IntDefaultHandler, // GPIO Port D
IntDefaultHandler, // GPIO Port E
#ifdef BUF_ENABLE_UART
UARTIntHandler, // UART0 Rx and Tx
#if defined( BUILD_C_INT_HANDLERS ) || defined( BUILD_LUA_INT_HANDLERS )
uart0_handler, // UART0 Rx and Tx
#else
IntDefaultHandler,
#endif
#if defined( BUILD_C_INT_HANDLERS ) || defined( BUILD_LUA_INT_HANDLERS )
uart1_handler, // UART1 Rx and Tx
#else
IntDefaultHandler, // UART1 Rx and Tx
#endif
IntDefaultHandler, // SSI0 Rx and Tx
IntDefaultHandler, // I2C0 Master and Slave
IntDefaultHandler, // PWM Fault
@ -123,7 +132,11 @@ void (* const g_pfnVectors[])(void) =
IntDefaultHandler, // GPIO Port F
IntDefaultHandler, // GPIO Port G
IntDefaultHandler, // 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
IntDefaultHandler, // Timer 3 subtimer B

View File

@ -61,9 +61,6 @@ int platform_init()
platform_setup_timers();
//platform_setup_pwm();
// Initialize console UART
platform_uart_setup( CON_UART_ID, CON_UART_SPEED, 8, PLATFORM_UART_PARITY_NONE, PLATFORM_UART_STOPBITS_1 );
#ifdef BUILD_ADC
// Setup ADCs
platform_setup_adcs();
@ -212,7 +209,7 @@ u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int st
return baud; // FIXME: find a way to actually get baud
}
void platform_uart_send( unsigned id, u8 data )
void platform_s_uart_send( unsigned id, u8 data )
{
UART_Send(uart[ id ], &data, 1, BLOCKING);
}

View File

@ -139,9 +139,6 @@ int platform_init()
platform_setup_timers();
platform_setup_pwm();
// Initialize console UART
platform_uart_setup( CON_UART_ID, CON_UART_SPEED, 8, PLATFORM_UART_PARITY_NONE, PLATFORM_UART_STOPBITS_1 );
#ifdef BUILD_ADC
// Setup ADCs
platform_setup_adcs();
@ -381,7 +378,7 @@ u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int st
return ( Fpclk_UART >> 4 ) / temp;
}
void platform_uart_send( unsigned id, u8 data )
void platform_s_uart_send( unsigned id, u8 data )
{
PREG UxTHR = ( PREG )uart_thr[ id ];
PREG UxLSR = ( PREG )uart_lsr[ id ];

View File

@ -8,6 +8,7 @@
#include "target.h"
#include "buf.h"
#include "elua_int.h"
#include "sermux.h"
// *****************************************************************************
// Define here what components you want for this platform
@ -19,13 +20,16 @@
#define BUILD_CON_GENERIC
#define BUILD_ADC
#define BUILD_RPC
#define BUILD_RFS
#define BUILD_SERMUX
#define BUILD_LUA_INT_HANDLERS
#define BUILD_C_INT_HANDLERS
// *****************************************************************************
// UART/Timer IDs configuration data (used in main.c)
#define CON_UART_ID 0
#define CON_UART_ID ( SERMUX_SERVICE_ID_FIRST + 1 )
//#define CON_UART_ID 0
#define CON_UART_SPEED 115200
#define CON_TIMER_ID 0
#define TERM_LINES 25
@ -90,9 +94,8 @@
// Interrupt data
#define PLATFORM_INT_QUEUE_LOG_SIZE BUF_SIZE_32
// Enable RX buffering on UART
// [TODO] make this happen
//#define BUF_ENABLE_UART
//#define CON_BUF_SIZE BUF_SIZE_128
#define BUF_ENABLE_UART
#define CON_BUF_SIZE BUF_SIZE_128
// ADC Configuration Params
#define ADC_BIT_RESOLUTION 10
@ -119,6 +122,18 @@
// Use #define PIO_PINS_PER_PORT 0 if this isn't needed
#define PIO_PINS_PER_PORT 32
// Remote file system data
#define RFS_BUFFER_SIZE BUF_SIZE_512
#define RFS_UART_ID ( SERMUX_SERVICE_ID_FIRST )
#define RFS_TIMER_ID 0
#define RFS_TIMEOUT 100000
#define RFS_UART_SPEED 115200
#define SERMUX_PHYS_ID 0
#define SERMUX_PHYS_SPEED 115200
#define SERMUX_NUM_VUART 2
#define SERMUX_BUFFER_SIZES { RFS_BUFFER_SIZE, CON_BUF_SIZE }
// Allocator data: define your free memory zones here in two arrays
// (start address and end address)
#define SRAM_ORIGIN 0x40000000
@ -156,7 +171,8 @@
#define INT_GPIO_POSEDGE ELUA_INT_FIRST_ID
#define INT_GPIO_NEGEDGE ( ELUA_INT_FIRST_ID + 1 )
#define INT_TMR_MATCH ( ELUA_INT_FIRST_ID + 2 )
#define INT_ELUA_LAST INT_TMR_MATCH
#define INT_UART_RX ( ELUA_INT_FIRST_ID + 3 )
#define INT_ELUA_LAST INT_UART_RX
#define PLATFORM_CPU_CONSTANTS\
_C( IO_PINSEL0 ),\
@ -172,7 +188,8 @@
_C( IO_PINSEL10 ),\
_C( INT_GPIO_POSEDGE ),\
_C( INT_GPIO_NEGEDGE ),\
_C( INT_TMR_MATCH )
_C( INT_TMR_MATCH ),\
_C( INT_UART_RX )
#endif // #ifndef __PLATFORM_CONF_H__

View File

@ -10,10 +10,14 @@
#include "irq.h"
#include "LPC23xx.h"
#include "target.h"
#include "uart.h"
// ****************************************************************************
// Interrupt handlers
// ----------------------------------------------------------------------------
// GPIO
static PREG const posedge_status[] = { ( PREG )&IO0_INT_STAT_R, ( PREG )&IO2_INT_STAT_R };
static PREG const negedge_status[] = { ( PREG )&IO0_INT_STAT_F, ( PREG )&IO2_INT_STAT_F };
static PREG const intclr_regs[] = { ( PREG )&IO0_INT_CLR, ( PREG )&IO2_INT_CLR };
@ -49,6 +53,40 @@ static void int_handler_eint3()
VICVectAddr = 0; // ACK interrupt
}
// ----------------------------------------------------------------------------
// UART
static PREG const uart_ier[] = { ( PREG )&U0IER, ( PREG )&U1IER, ( PREG )&U2IER, ( PREG )&U3IER };
static PREG const uart_iir[] = { ( PREG )&U0IIR, ( PREG )&U1IIR, ( PREG )&U2IIR, ( PREG )&U3IIR };
// Common UART interrupt handler
static void uart_rx_common_handler( elua_int_resnum resnum )
{
cmn_int_handler( INT_UART_RX, resnum );
VICVectAddr = 0;
}
// Interrupt handlers for individual UARTs
static void int_handler_uart0()
{
uart_rx_common_handler( 0 );
}
static void int_handler_uart1()
{
uart_rx_common_handler( 1 );
}
static void int_handler_uart2()
{
uart_rx_common_handler( 2 );
}
static void int_handler_uart3()
{
uart_rx_common_handler( 3 );
}
// ****************************************************************************
// GPIO helper functions
@ -151,25 +189,64 @@ static int int_gpio_negedge_get_flag( elua_int_resnum resnum, int clear )
static int int_tmr_match_set_status( elua_int_resnum resnum, int status )
{
return PLATFORM_INT_NOT_HANDLED;
return PLATFORM_INT_BAD_RESNUM;
}
static int int_tmr_match_get_status( elua_int_resnum resnum )
{
return PLATFORM_INT_NOT_HANDLED;
return PLATFORM_INT_BAD_RESNUM;
}
static int int_tmr_match_get_flag( elua_int_resnum resnum, int clear )
{
return PLATFORM_INT_NOT_HANDLED;
return PLATFORM_INT_BAD_RESNUM;
}
// ****************************************************************************
// Interrupt: INT_UART_RX
static int int_uart_rx_get_status( elua_int_resnum resnum )
{
PREG UxIER = uart_ier[ resnum ];
return ( *UxIER & IER_RBR ) ? 1 : 0;
}
static int int_uart_rx_set_status( elua_int_resnum resnum, int status )
{
PREG UxIER = uart_ier[ resnum ];
int prev = int_uart_rx_get_status( resnum );
if( status == PLATFORM_CPU_ENABLE )
*UxIER |= IER_RBR;
else
*UxIER &= ~IER_RBR;
return prev;
}
static int int_uart_rx_get_flag( elua_int_resnum resnum, int clear )
{
PREG UxIIR = uart_iir[ resnum ];
// 'clear' is not needed here, the interrupt will be cleared when reading the RBR register
( void )clear;
if( ( *UxIIR & IIR_PEND ) == 0 )
return ( ( *UxIIR >> 1 ) & 0x07 ) == IIR_RDA;
return 0;
}
// ****************************************************************************
// Interrupt initialization
typedef void ( *p_handler )();
void platform_int_init()
{
install_irq( EINT3_INT, int_handler_eint3, HIGHEST_PRIORITY - 1 );
install_irq( EINT3_INT, int_handler_eint3, HIGHEST_PRIORITY + 1 );
install_irq( UART0_INT, int_handler_uart0, HIGHEST_PRIORITY + 2 );
install_irq( UART1_INT, int_handler_uart1, HIGHEST_PRIORITY + 3 );
install_irq( UART2_INT, int_handler_uart2, HIGHEST_PRIORITY + 4 );
install_irq( UART3_INT, int_handler_uart3, HIGHEST_PRIORITY + 5 );
}
// ****************************************************************************
@ -180,6 +257,7 @@ const elua_int_descriptor elua_int_table[ INT_ELUA_LAST ] =
{
{ 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 }
{ int_tmr_match_set_status, int_tmr_match_get_status, int_tmr_match_get_flag },
{ int_uart_rx_set_status, int_uart_rx_get_status, int_uart_rx_get_flag }
};

View File

@ -4,7 +4,7 @@
#define __STACKS_H__
#define STACK_SIZE_USR 8192
#define STACK_SIZE_IRQ 64
#define STACK_SIZE_IRQ 128
#define STACK_SIZE_TOTAL ( STACK_SIZE_USR + STACK_SIZE_IRQ )
#endif

View File

@ -28,9 +28,6 @@ int platform_init()
// Initialize CPU
lpc288x_init();
// Initialize UART
uart_init( CON_UART_SPEED, 8, PLATFORM_UART_PARITY_NONE, PLATFORM_UART_STOPBITS_1 );
// Initialize timers
T0CTRL = 0;
T1CTRL = 0;
@ -112,10 +109,11 @@ pio_type platform_pio_op( unsigned port, pio_type pinmask, int op )
u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int stopbits )
{
( void )id;
return uart_init( baud, databits, parity, stopbits );
}
void platform_uart_send( unsigned id, u8 data )
void platform_s_uart_send( unsigned id, u8 data )
{
uart_write( data );
}

View File

@ -128,7 +128,7 @@ u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int st
return 0;
}
void platform_uart_send( unsigned id, u8 data )
void platform_s_uart_send( unsigned id, u8 data )
{
}

View File

@ -31,6 +31,7 @@
// Bogus defines for common.c
#define CON_UART_ID 0
#define CON_UART_SPEED 0
#define CON_TIMER_ID 0
// *****************************************************************************

View File

@ -8,7 +8,7 @@ comp.Append(CPPPATH = ['src/platform/%s/FWLib/library/inc' % platform])
fwlib_files = " ".join(glob.glob("src/platform/%s/FWLib/library/src/*.c" % platform))
#print "FWLib: %s " % fwlib_files
specific_files = "core_cm3.c system_stm32f10x.c startup_stm32f10x_hd.s platform.c stm32f10x_it.c lcd.c lua_lcd.c"
specific_files = "core_cm3.c system_stm32f10x.c startup_stm32f10x_hd.s platform.c stm32f10x_it.c lcd.c lua_lcd.c platform_int.c"
ldscript = "stm32.ld"

View File

@ -140,28 +140,24 @@ static void NVIC_Configuration(void)
#endif
/* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* Priority group 0 disables interrupt nesting completely */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
// Lower the priority of the SysTick interrupt to let the
// UART interrupt preempt it
nvic_init_structure.NVIC_IRQChannel = SysTick_IRQn;
nvic_init_structure.NVIC_IRQChannelPreemptionPriority = 0;
nvic_init_structure.NVIC_IRQChannelSubPriority = 1;
nvic_init_structure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic_init_structure);
#ifdef BUILD_ADC
nvic_init_structure_adc.NVIC_IRQChannel = DMA1_Channel1_IRQn;
nvic_init_structure_adc.NVIC_IRQChannelPreemptionPriority = 1;
nvic_init_structure_adc.NVIC_IRQChannelSubPriority = 3;
nvic_init_structure_adc.NVIC_IRQChannelPreemptionPriority = 0;
nvic_init_structure_adc.NVIC_IRQChannelSubPriority = 2;
nvic_init_structure_adc.NVIC_IRQChannelCmd = DISABLE;
NVIC_Init(&nvic_init_structure_adc);
#endif
#if defined( BUF_ENABLE_UART ) && defined( CON_BUF_SIZE )
/* Enable the USART1 Interrupt */
// [TODO]: this is hardcoded, and it shouldn't be
nvic_init_structure.NVIC_IRQChannel = USART3_IRQn;
nvic_init_structure.NVIC_IRQChannelSubPriority = 0;
nvic_init_structure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic_init_structure);
nvic_init_structure.NVIC_IRQChannel = USART1_IRQn;
nvic_init_structure.NVIC_IRQChannelSubPriority = 0;
nvic_init_structure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic_init_structure);
#endif
}
// ****************************************************************************
@ -532,43 +528,12 @@ void platform_spi_select( unsigned id, int is_select )
// TODO: Support timeouts.
// All possible STM32 uarts defs
static USART_TypeDef *const usart[] = { USART1, USART2, USART3, UART4, UART5 };
USART_TypeDef *const stm32_usart[] = { USART1, USART2, USART3, UART4, UART5 };
static GPIO_TypeDef *const usart_gpio_rx_port[] = { GPIOA, GPIOA, GPIOB, GPIOC, GPIOD };
static GPIO_TypeDef *const usart_gpio_tx_port[] = { GPIOA, GPIOA, GPIOB, GPIOC, GPIOC };
static const u16 usart_gpio_rx_pin[] = { GPIO_Pin_10, GPIO_Pin_3, GPIO_Pin_11, GPIO_Pin_11, GPIO_Pin_2 };
static const u16 usart_gpio_tx_pin[] = { GPIO_Pin_9, GPIO_Pin_2, GPIO_Pin_10, GPIO_Pin_10, GPIO_Pin_12 };
#ifdef BUF_ENABLE_UART
static void all_usart_irqhandler( int usart_id )
{
int c;
if( USART_GetITStatus( usart[ usart_id ], USART_IT_RXNE ) != RESET )
{
/* Read one byte from the receive data register */
c = USART_ReceiveData( usart[ usart_id ] );
buf_write( BUF_ID_UART, usart_id, ( t_buf_data* )&c );
}
}
void USART1_IRQHandler( void )
{
all_usart_irqhandler( 0 );
}
void USART2_IRQHandler(void)
{
all_usart_irqhandler( 1 );
}
void USART3_IRQHandler(void)
{
all_usart_irqhandler( 2 );
}
#endif
static void usart_init(u32 id, USART_InitTypeDef * initVals)
{
/* Configure USART IO */
@ -586,43 +551,20 @@ static void usart_init(u32 id, USART_InitTypeDef * initVals)
GPIO_Init(usart_gpio_rx_port[id], &GPIO_InitStructure);
/* Configure USART */
USART_Init(usart[id], initVals);
#if defined( BUF_ENABLE_UART ) && defined( CON_BUF_SIZE )
/* Enable USART1 Receive and Transmit interrupts */
USART_ITConfig(usart[id], USART_IT_RXNE, ENABLE);
//USART_ITConfig(usart[id], USART_IT_TXE, ENABLE);
#endif
USART_Init(stm32_usart[id], initVals);
/* Enable USART */
USART_Cmd(usart[id], ENABLE);
USART_Cmd(stm32_usart[id], ENABLE);
}
static void uarts_init()
{
USART_InitTypeDef USART_InitStructure;
// Enable clocks.
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
// Configure the U(S)ART
USART_InitStructure.USART_BaudRate = CON_UART_SPEED;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
#if defined( BUF_ENABLE_UART ) && defined( CON_BUF_SIZE )
buf_set( BUF_ID_UART, CON_UART_ID, CON_BUF_SIZE, BUF_DSIZE_U8 );
#endif
usart_init(CON_UART_ID, &USART_InitStructure);
}
u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int stopbits )
@ -681,26 +623,46 @@ u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int st
return TRUE;
}
void platform_uart_send( unsigned id, u8 data )
void platform_s_uart_send( unsigned id, u8 data )
{
while(USART_GetFlagStatus(usart[id], USART_FLAG_TXE) == RESET)
while(USART_GetFlagStatus(stm32_usart[id], USART_FLAG_TXE) == RESET)
{
}
USART_SendData(usart[id], data);
USART_SendData(stm32_usart[id], data);
}
int platform_s_uart_recv( unsigned id, s32 timeout )
{
if( timeout == 0 )
{
if (USART_GetFlagStatus(usart[id], USART_FLAG_RXNE) == RESET)
if (USART_GetFlagStatus(stm32_usart[id], USART_FLAG_RXNE) == RESET)
return -1;
else
return USART_ReceiveData(usart[id]);
return USART_ReceiveData(stm32_usart[id]);
}
// Receive char blocking
while(USART_GetFlagStatus(usart[id], USART_FLAG_RXNE) == RESET);
return USART_ReceiveData(usart[id]);
while(USART_GetFlagStatus(stm32_usart[id], USART_FLAG_RXNE) == RESET);
return USART_ReceiveData(stm32_usart[id]);
}
int platform_s_uart_set_flow_control( unsigned id, int type )
{
USART_TypeDef *usart = stm32_usart[ id ];
int temp = 0;
if( type == PLATFORM_UART_FLOW_NONE )
{
usart->CR3 &= ~USART_HardwareFlowControl_RTS_CTS;
return PLATFORM_OK;
}
if( id >= 3 ) // on STM32 only USART1 through USART3 have hardware flow control ([TODO] but only on high density devices?)
return PLATFORM_ERR;
if( type & PLATFORM_UART_FLOW_RTS )
temp |= USART_HardwareFlowControl_RTS;
if( type & PLATFORM_UART_FLOW_CTS )
temp |= USART_HardwareFlowControl_CTS;
usart->CR3 |= temp;
return PLATFORM_OK;
}
// ****************************************************************************
@ -816,6 +778,10 @@ u32 platform_s_timer_op( unsigned id, int op, u32 data )
return res;
}
int platform_s_timer_set_match_int( unsigned id, u32 period_us, int type )
{
return PLATFORM_TIMER_INT_INVALID_ID;
}
// ****************************************************************************
// PWMs

View File

@ -7,6 +7,8 @@
#include "type.h"
#include "stacks.h"
#include "stm32f10x.h"
#include "elua_int.h"
#include "sermux.h"
// *****************************************************************************
// Define here what components you want for this platform
@ -25,6 +27,10 @@
//#define BUILD_RFS
//#define BUILD_CON_TCP
#define BUILD_LINENOISE
#define BUILD_C_INT_HANDLERS
#define BUILD_LUA_INT_HANDLERS
#define PLATFORM_UART_SET_FLOW_CONTROL
// *****************************************************************************
// UART/Timer IDs configuration data (used in main.c)
@ -80,30 +86,6 @@
LCDLINE\
_ROM( AUXLIB_ELUA, luaopen_elua, elua_map )\
_ROM( LUA_MATHLIBNAME, luaopen_math, math_map )
// *****************************************************************************
// Configuration data
// Static TCP/IP configuration
#define ELUA_CONF_IPADDR0 192
#define ELUA_CONF_IPADDR1 168
#define ELUA_CONF_IPADDR2 1
#define ELUA_CONF_IPADDR3 13
#define ELUA_CONF_NETMASK0 255
#define ELUA_CONF_NETMASK1 255
#define ELUA_CONF_NETMASK2 255
#define ELUA_CONF_NETMASK3 0
#define ELUA_CONF_DEFGW0 192
#define ELUA_CONF_DEFGW1 168
#define ELUA_CONF_DEFGW2 1
#define ELUA_CONF_DEFGW3 1
#define ELUA_CONF_DNS0 192
#define ELUA_CONF_DNS1 168
#define ELUA_CONF_DNS2 1
#define ELUA_CONF_DNS3 1
// *****************************************************************************
// Configuration data
@ -181,5 +163,17 @@ u32 platform_s_cpu_get_frequency();
#define MEM_START_ADDRESS { ( void* )end }
#define MEM_END_ADDRESS { ( void* )( SRAM_BASE + SRAM_SIZE - STACK_SIZE_TOTAL - 1 ) }
// Interrupt queue size
#define PLATFORM_INT_QUEUE_LOG_SIZE 5
// Interrupt list
#define INT_TMR_MATCH ELUA_INT_FIRST_ID
#define INT_UART_RX ( ELUA_INT_FIRST_ID + 1 )
#define INT_ELUA_LAST INT_UART_RX
#define PLATFORM_CPU_CONSTANTS\
_C( INT_TMR_MATCH ),\
_C( INT_UART_RX )
#endif // #ifndef __PLATFORM_CONF_H__

View File

@ -0,0 +1,130 @@
// STM32 interrupt support
// Generic headers
#include "platform.h"
#include "platform_conf.h"
#include "elua_int.h"
#include "common.h"
// Platform-specific headers
#include "stm32f10x.h"
// ****************************************************************************
// Interrupt handlers
extern USART_TypeDef *const stm32_usart[];
static void all_usart_irqhandler( int resnum )
{
int temp;
temp = USART_GetFlagStatus( stm32_usart[ resnum ], USART_FLAG_ORE );
cmn_int_handler( INT_UART_RX, resnum );
if( temp == SET )
for( temp = 0; temp < 10; temp ++ )
platform_s_uart_send( resnum, '@' );
}
void USART1_IRQHandler()
{
all_usart_irqhandler( 0 );
}
void USART2_IRQHandler()
{
all_usart_irqhandler( 1 );
}
void USART3_IRQHandler()
{
all_usart_irqhandler( 2 );
}
void UART4_IRQHandler()
{
all_usart_irqhandler( 3 );
}
void UART5_IRQHandler()
{
all_usart_irqhandler( 4 );
}
// ****************************************************************************
// Interrupt: INT_TMR_MATCH
static int int_tmr_match_set_status( elua_int_resnum resnum, int status )
{
return PLATFORM_INT_NOT_HANDLED;
}
static int int_tmr_match_get_status( elua_int_resnum resnum )
{
return PLATFORM_INT_NOT_HANDLED;
}
static int int_tmr_match_get_flag( elua_int_resnum resnum, int clear )
{
return PLATFORM_INT_NOT_HANDLED;
}
// ****************************************************************************
// Interrupt: INT_UART_RX
static int int_uart_rx_get_status( elua_int_resnum resnum )
{
return USART_GetITStatus( stm32_usart[ resnum ], USART_IT_RXNE ) == SET ? 1 : 0;
}
static int int_uart_rx_set_status( elua_int_resnum resnum, int status )
{
int prev = int_uart_rx_get_status( resnum );
USART_ITConfig( stm32_usart[ resnum ], USART_IT_RXNE, status == PLATFORM_CPU_ENABLE ? ENABLE : DISABLE );
return prev;
}
static int int_uart_rx_get_flag( elua_int_resnum resnum, int clear )
{
int status = USART_GetFlagStatus( stm32_usart[ resnum ], USART_FLAG_RXNE ) == SET ? 1 : 0;
if( clear )
USART_ClearFlag( stm32_usart[ resnum ], USART_FLAG_RXNE );
return status;
}
// ****************************************************************************
// Initialize interrupt subsystem
// UART IRQ table
#if defined( STM32F10X_LD )
static const u8 uart_irq_table[] = { USART1_IRQn, USART2_IRQn };
#elseif defined( STM32F10X_MD )
static const u8 uart_irq_table[] = { USART1_IRQn, USART2_IRQn, USART3_IRQn };
#else // high density devices
static const u8 uart_irq_table[] = { USART1_IRQn, USART2_IRQn, USART3_IRQn, UART4_IRQn, UART5_IRQn };
#endif
void platform_int_init()
{
NVIC_InitTypeDef nvic_init_structure;
unsigned i;
// Enable all USART interrupts in the NVIC
nvic_init_structure.NVIC_IRQChannelPreemptionPriority = 0;
nvic_init_structure.NVIC_IRQChannelSubPriority = 0;
nvic_init_structure.NVIC_IRQChannelCmd = ENABLE;
for( i = 0; i < sizeof( uart_irq_table ) / sizeof( u8 ); i ++ )
{
nvic_init_structure.NVIC_IRQChannel = uart_irq_table[ i ];
NVIC_Init( &nvic_init_structure );
}
}
// ****************************************************************************
// Interrupt table
// Must have a 1-to-1 correspondence with the interrupt enum in platform_conf.h!
const elua_int_descriptor elua_int_table[ INT_ELUA_LAST ] =
{
{ int_tmr_match_set_status, int_tmr_match_get_status, int_tmr_match_get_flag },
{ int_uart_rx_set_status, int_uart_rx_get_status, int_uart_rx_get_flag }
};

View File

@ -51,7 +51,7 @@ void NMI_Handler(void)
#if 0
int fputc(int ch, FILE *f)
{
platform_uart_send(0, ch);
platform_s_uart_send(0, ch);
return ch;
}
#endif
@ -121,10 +121,10 @@ void MemManage_Handler(void)
/* Go to infinite loop when Memory Manage exception occurs */
while (1)
{
platform_uart_send(0, ' ');
platform_uart_send(0, 'M');
platform_uart_send(0, 'M');
platform_uart_send(0, '!');
platform_s_uart_send(0, ' ');
platform_s_uart_send(0, 'M');
platform_s_uart_send(0, 'M');
platform_s_uart_send(0, '!');
}
}
@ -138,10 +138,10 @@ void BusFault_Handler(void)
/* Go to infinite loop when Bus Fault exception occurs */
while (1)
{
platform_uart_send(0, ' ');
platform_uart_send(0, 'B');
platform_uart_send(0, 'F');
platform_uart_send(0, '!');
platform_s_uart_send(0, ' ');
platform_s_uart_send(0, 'B');
platform_s_uart_send(0, 'F');
platform_s_uart_send(0, '!');
}
}
@ -155,10 +155,10 @@ void UsageFault_Handler(void)
/* Go to infinite loop when Usage Fault exception occurs */
while (1)
{
platform_uart_send(0, ' ');
platform_uart_send(0, 'U');
platform_uart_send(0, 'F');
platform_uart_send(0, '!');
platform_s_uart_send(0, ' ');
platform_s_uart_send(0, 'U');
platform_s_uart_send(0, 'F');
platform_s_uart_send(0, '!');
}
}

View File

@ -49,9 +49,6 @@ int platform_init()
// Initialize clocks
clock_init();
// Setup UART1 for operation
platform_uart_setup( CON_UART_ID, CON_UART_SPEED, 8, PLATFORM_UART_PARITY_NONE, PLATFORM_UART_STOPBITS_1 );
// Initialize Timer 0 for XMODEM
platform_timer_op( 0, PLATFORM_TIMER_OP_SET_CLOCK, 39000 );
@ -176,7 +173,7 @@ u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int st
return baud;
}
void platform_uart_send( unsigned id, u8 data )
void platform_s_uart_send( unsigned id, u8 data )
{
UART_TypeDef* pport = ( UART_TypeDef* )uart_periph[ id ];

View File

@ -129,7 +129,6 @@ int platform_init()
// UART setup
platform_gpio_uart_setup();
platform_uart_setup( CON_UART_ID, CON_UART_SPEED, 8, PLATFORM_UART_PARITY_NONE, PLATFORM_UART_STOPBITS_1 );
// Initialize timers
for( i = 0; i < NUM_PHYS_TIMER; i ++ )
@ -261,7 +260,7 @@ u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int st
return baud;
}
void platform_uart_send( unsigned id, u8 data )
void platform_s_uart_send( unsigned id, u8 data )
{
UART_TypeDef* p_uart = ( UART_TypeDef* )uarts[ id ];

View File

@ -4,6 +4,21 @@
#include "remotefs.h"
#include "client.h"
#include "os_io.h"
#include "eluarpc.h"
#include <stdio.h>
#include "platform_conf.h"
#include "buf.h"
#ifdef BUILD_RFS
#if 0
#define RFSDEBUG printf
#else
void RFSDEBUG( const char* dummy, ... )
{
}
#endif
// ****************************************************************************
// Client local data
@ -19,6 +34,7 @@ static u32 rfsc_timeout;
static int rfsch_send_request_read_response()
{
u16 temp16;
u32 readbytes;
#ifndef ELUA_CPU_LINUX
// Empty receive buffer
@ -26,19 +42,34 @@ static int rfsch_send_request_read_response()
#endif
// Send request
if( remotefs_get_packet_size( rfsc_buffer, &temp16 ) == REMOTEFS_ERR )
if( eluarpc_get_packet_size( rfsc_buffer, &temp16 ) == ELUARPC_ERR )
{
RFSDEBUG( "[RFS] get packet size error\n" );
return CLIENT_ERR;
}
if( rfsc_send( rfsc_buffer, temp16 ) != temp16 )
{
RFSDEBUG( "[RFS] rfsc_send error\n" );
return CLIENT_ERR;
}
// Get response
// First the length, then the rest of the data
if( rfsc_recv( rfsc_buffer, RFS_START_OFFSET, rfsc_timeout ) != RFS_START_OFFSET )
if( ( readbytes = rfsc_recv( rfsc_buffer, ELUARPC_START_OFFSET, rfsc_timeout ) ) != ELUARPC_START_OFFSET )
{
RFSDEBUG( "[RFS] rfsc_recv (1) error: expected %u, got %u\n", ( unsigned )( temp16 - ELUARPC_START_OFFSET ), ( unsigned )readbytes );
return CLIENT_ERR;
if( remotefs_get_packet_size( rfsc_buffer, &temp16 ) == REMOTEFS_ERR )
}
if( eluarpc_get_packet_size( rfsc_buffer, &temp16 ) == ELUARPC_ERR )
{
RFSDEBUG( "[RFS] eluarpc_get_packet_size() error\n" );
return CLIENT_ERR;
if( rfsc_recv( rfsc_buffer + RFS_START_OFFSET, temp16 - RFS_START_OFFSET, rfsc_timeout ) != temp16 - RFS_START_OFFSET )
}
if( ( readbytes = rfsc_recv( rfsc_buffer + ELUARPC_START_OFFSET, temp16 - ELUARPC_START_OFFSET, rfsc_timeout ) ) != temp16 - ELUARPC_START_OFFSET )
{
RFSDEBUG( "[RFS] rfsc_recv (2) error: expected %u, got %u\n", ( unsigned )( temp16 - ELUARPC_START_OFFSET ), ( unsigned )readbytes );
return CLIENT_ERR;
}
return CLIENT_OK;
}
@ -70,7 +101,7 @@ int rfsc_open( const char* pathname, int flags, int mode )
return -1;
// Interpret the response
if( remotefs_open_read_response( rfsc_buffer, &fd ) == REMOTEFS_ERR )
if( remotefs_open_read_response( rfsc_buffer, &fd ) == ELUARPC_ERR )
return -1;
return fd;
}
@ -85,7 +116,7 @@ s32 rfsc_write( int fd, const void *buf, u32 count )
return -1;
// Interpret the response
if( remotefs_write_read_response( rfsc_buffer, &count ) == REMOTEFS_ERR )
if( remotefs_write_read_response( rfsc_buffer, &count ) == ELUARPC_ERR )
return -1;
return ( s32 )count;
}
@ -102,7 +133,7 @@ s32 rfsc_read( int fd, void *buf, u32 count )
return -1;
// Interpret the response
if( remotefs_read_read_response( rfsc_buffer, &resbuf, &count ) == REMOTEFS_ERR )
if( remotefs_read_read_response( rfsc_buffer, &resbuf, &count ) == ELUARPC_ERR )
return -1;
memcpy( buf, resbuf, count );
return ( s32 )count;
@ -120,7 +151,7 @@ s32 rfsc_lseek( int fd, s32 offset, int whence )
return -1;
// Interpret the response
if( remotefs_lseek_read_response( rfsc_buffer, &res ) == REMOTEFS_ERR )
if( remotefs_lseek_read_response( rfsc_buffer, &res ) == ELUARPC_ERR )
return -1;
return res;
}
@ -137,7 +168,7 @@ int rfsc_close( int fd )
return -1;
// Interpret the response
if( remotefs_close_read_response( rfsc_buffer, &res ) == REMOTEFS_ERR )
if( remotefs_close_read_response( rfsc_buffer, &res ) == ELUARPC_ERR )
return -1;
return res;
}
@ -152,7 +183,7 @@ u32 rfsc_opendir( const char* name )
return 0;
// Interpret the response
if( remotefs_opendir_read_response( rfsc_buffer, &res ) == REMOTEFS_ERR )
if( remotefs_opendir_read_response( rfsc_buffer, &res ) == ELUARPC_ERR )
return 0;
return res;
}
@ -168,7 +199,7 @@ void rfsc_readdir( u32 d, const char **pname, u32 *psize, u32 *ptime )
}
// Interpret the response
if( remotefs_readdir_read_response( rfsc_buffer, pname, psize, ptime ) == REMOTEFS_ERR )
if( remotefs_readdir_read_response( rfsc_buffer, pname, psize, ptime ) == ELUARPC_ERR )
*pname = NULL;
}
@ -182,8 +213,9 @@ int rfsc_closedir( u32 d )
return -1;
// Interpret the response
if( remotefs_closedir_read_response( rfsc_buffer, &res ) == REMOTEFS_ERR )
if( remotefs_closedir_read_response( rfsc_buffer, &res ) == ELUARPC_ERR )
return -1;
return res;
}
#endif // #ifdef BUILD_RFS

View File

@ -5,20 +5,21 @@
#include <fcntl.h>
#include "os_io.h"
#include "remotefs.h"
#include "eluarpc.h"
u32 os_open_sys_flags_to_rfs_flags( int sysflags )
{
int rfsflags = 0;
// Translate RFS flags to POSIX flags
rfsflags = remotefs_replace_flag( sysflags, O_APPEND, RFS_OPEN_FLAG_APPEND );
rfsflags |= remotefs_replace_flag( sysflags, O_CREAT, RFS_OPEN_FLAG_CREAT );
rfsflags |= remotefs_replace_flag( sysflags, O_EXCL, RFS_OPEN_FLAG_EXCL );
rfsflags |= remotefs_replace_flag( sysflags, O_TRUNC, RFS_OPEN_FLAG_TRUNC );
rfsflags |= remotefs_replace_flag( sysflags, O_SYNC, RFS_OPEN_FLAG_SYNC );
rfsflags |= remotefs_replace_flag( sysflags, O_RDONLY, RFS_OPEN_FLAG_RDONLY );
rfsflags |= remotefs_replace_flag( sysflags, O_WRONLY, RFS_OPEN_FLAG_WRONLY );
rfsflags |= remotefs_replace_flag( sysflags, O_RDWR, RFS_OPEN_FLAG_RDWR );
rfsflags = eluarpc_replace_flag( sysflags, O_APPEND, RFS_OPEN_FLAG_APPEND );
rfsflags |= eluarpc_replace_flag( sysflags, O_CREAT, RFS_OPEN_FLAG_CREAT );
rfsflags |= eluarpc_replace_flag( sysflags, O_EXCL, RFS_OPEN_FLAG_EXCL );
rfsflags |= eluarpc_replace_flag( sysflags, O_TRUNC, RFS_OPEN_FLAG_TRUNC );
rfsflags |= eluarpc_replace_flag( sysflags, O_SYNC, RFS_OPEN_FLAG_SYNC );
rfsflags |= eluarpc_replace_flag( sysflags, O_RDONLY, RFS_OPEN_FLAG_RDONLY );
rfsflags |= eluarpc_replace_flag( sysflags, O_WRONLY, RFS_OPEN_FLAG_WRONLY );
rfsflags |= eluarpc_replace_flag( sysflags, O_RDWR, RFS_OPEN_FLAG_RDWR );
return rfsflags;
}

View File

@ -5,7 +5,9 @@
#include "type.h"
#include "platform.h"
#include "remotefs.h"
#include "eluarpc.h"
#include "client.h"
#include "sermux.h"
#include "buf.h"
#include <fcntl.h>
#ifdef ELUA_SIMULATOR
@ -15,11 +17,16 @@
#ifdef BUILD_RFS
// [TODO] the new builder should automatically do this
#ifndef RFS_FLOW_TYPE
#define RFS_FLOW_TYPE PLATFORM_UART_FLOW_NONE
#endif
// Our RFS buffer
// Compute the usable buffer size starting from RFS_BUFFER_SIZE (which is the
// size of the serial buffer). A complete packet must fit in RFS_BUFFER_SIZE
// bytes. Computed this to be large enough for a WRITE request.
#define RFS_REAL_BUFFER_SIZE ( ( 1 << RFS_BUFFER_SIZE ) - RFS_WRITE_REQUEST_EXTRA )
#define RFS_REAL_BUFFER_SIZE ( ( 1 << RFS_BUFFER_SIZE ) - ELUARPC_WRITE_REQUEST_EXTRA )
static u8 rfs_buffer[ 1 << RFS_BUFFER_SIZE ];
#ifdef ELUA_SIMULATOR
@ -124,7 +131,7 @@ static u32 rfs_send( const u8 *p, u32 size )
return size;
}
static u32 rfs_recv( u8 *p, u32 size, u32 timeout )
static u32 rfs_recv( u8 *p, u32 size, s32 timeout )
{
u32 cnt = 0;
int data;
@ -150,7 +157,7 @@ static u32 rfs_send( const u8 *p, u32 size )
return ( u32 )hostif_write( rfs_write_fd, p, size );
}
static u32 rfs_recv( u8 *p, u32 size, u32 timeout )
static u32 rfs_recv( u8 *p, u32 size, s32 timeout )
{
timeout = timeout;
return ( u32 )hostif_read( rfs_read_fd, p, size );
@ -173,12 +180,6 @@ static const DM_DEVICE rfs_device =
const DM_DEVICE *remotefs_init()
{
#if defined( RFS_UART_ID ) && defined( RFS_UART_SPEED )
// Initialize RFS UART
platform_uart_setup( RFS_UART_ID, RFS_UART_SPEED, 8, PLATFORM_UART_PARITY_NONE, PLATFORM_UART_STOPBITS_1 );
// [TODO] this isn't exactly right
buf_set( BUF_ID_UART, RFS_UART_ID, RFS_BUFFER_SIZE, BUF_DSIZE_U8 );
#endif
#ifdef ELUA_CPU_LINUX
// Open our read/write pipes
rfs_read_fd = hostif_open( RFS_SRV_WRITE_PIPE, O_RDONLY, 0 );
@ -188,6 +189,15 @@ const DM_DEVICE *remotefs_init()
hostif_putstr( "unable to open read/write pipes\n" );
return NULL;
}
#elif RFS_UART_ID < SERMUX_SERVICE_ID_FIRST // if RFS runs on a virtual UART, buffers are already set in common.c
// Initialize RFS UART
platform_uart_setup( RFS_UART_ID, RFS_UART_SPEED, 8, PLATFORM_UART_PARITY_NONE, PLATFORM_UART_STOPBITS_1 );
platform_uart_set_flow_control( RFS_UART_ID, RFS_FLOW_TYPE );
if( platform_uart_set_buffer( RFS_UART_ID, RFS_BUFFER_SIZE ) == PLATFORM_ERR )
{
printf( "WARNING: unable to initialize RFS filesystem\n" );
return NULL;
}
#endif
rfsc_setup( rfs_buffer, rfs_send, rfs_recv, RFS_TIMEOUT );
return &rfs_device;

View File

@ -4,340 +4,31 @@
#include <stdarg.h>
#include "type.h"
#include "remotefs.h"
#include "eluarpc.h"
#include "rtype.h"
static u8 remotefs_err_flag;
// *****************************************************************************
// Internal functions: data serialization
static u8 *remotefs_write_u8( u8 *p, u8 data )
{
*p ++ = TYPE_INT_8;
*p ++ = data;
return p;
}
static u8* remotefs_write_op_id( u8 *p, u8 data )
{
*p ++ = TYPE_OP_ID;
*p ++ = data;
return p;
}
static u8 *remotefs_write_u16( u8 *p, u16 data )
{
*p ++ = TYPE_INT_16;
*p ++ = data & 0xFF;
*p ++ = ( data >> 8 ) & 0xFF;
return p;
}
static u8 *remotefs_write_u32( u8 *p, u32 data )
{
*p ++ = TYPE_INT_32;
*p ++ = data & 0xFF;
*p ++ = ( data >> 8 ) & 0xFF;
*p ++ = ( data >> 16 ) & 0xFF;
*p ++ = ( data >> 24 ) & 0xFF;
return p;
}
static u8 *remotefs_write_ptr( u8 *p, const void* src, u32 srclen )
{
*p ++ = TYPE_PTR;
p = remotefs_write_u32( p, srclen );
if( src )
memcpy( p, src, srclen );
return p + srclen;
}
// *****************************************************************************
// Internal functions: data deserialization
static const u8* remotefs_read_expect( const u8 *p, u8 data )
{
if( *p ++ != data )
remotefs_err_flag = REMOTEFS_ERR;
return p;
}
static const u8 *remotefs_read_u8( const u8 *p, u8 *pdata )
{
p = remotefs_read_expect( p, TYPE_INT_8 );
*pdata = *p ++;
return p;
}
static const u8 *remotefs_read_op_id( const u8 *p, u8 *pdata )
{
p = remotefs_read_expect( p, TYPE_OP_ID );
*pdata = *p ++;
return p;
}
static const u8* remotefs_expect_op_id( const u8 *p, u8 id )
{
u8 temp;
p = remotefs_read_expect( p, TYPE_OP_ID );
temp = *p ++;
if( temp != id )
remotefs_err_flag = REMOTEFS_ERR;
return p;
}
static const u8 *remotefs_read_u16( const u8 *p, u16 *pdata )
{
p = remotefs_read_expect( p, TYPE_INT_16 );
*pdata = *p ++;
*pdata |= ( *p ++ ) << 8;
return p;
}
static const u8 *remotefs_read_u32( const u8 *p, u32 *pdata )
{
p = remotefs_read_expect( p, TYPE_INT_32 );
*pdata = *p ++;
*pdata |= ( *p ++ ) << 8;
*pdata |= ( *p ++ ) << 16;
*pdata |= ( *p ++ ) << 24;
return p;
}
static const u8 *remotefs_read_ptr( const u8 *p, void* src, u32 *psrclen )
{
p = remotefs_read_expect( p, TYPE_PTR );
p = remotefs_read_u32( p, psrclen );
if( src && p )
memcpy( src, p, *psrclen );
return p + *psrclen;
}
// *****************************************************************************
// Internal functions: packet handling (read and write)
static u8* remotefs_packet_ptr;
static u8* remotefs_start_packet( u8 *p )
{
remotefs_packet_ptr = p;
p += RFS_START_OFFSET;
*p ++ = TYPE_START;
p = remotefs_write_u32( p, PACKET_SIG );
return p;
}
static u8* remotefs_end_packet( u8 *p )
{
u16 len;
*p ++ = TYPE_END;
p = remotefs_write_u32( p, ~PACKET_SIG );
len = p - remotefs_packet_ptr;
p = remotefs_packet_ptr;
*p ++ = TYPE_PKT_SIZE;
remotefs_write_u16( p, len );
return p;
}
static const u8* remotefs_match_packet_start( const u8 *p )
{
u32 data;
p += RFS_START_OFFSET;
p = remotefs_read_expect( p, TYPE_START );
p = remotefs_read_u32( p, &data );
if( data != PACKET_SIG )
remotefs_err_flag = REMOTEFS_ERR;
return p;
}
static const u8* remotefs_match_packet_end( const u8 *p )
{
u32 data;
p = remotefs_read_expect( p, TYPE_END );
p = remotefs_read_u32( p, &data );
if( data != ~PACKET_SIG )
remotefs_err_flag = REMOTEFS_ERR;
return p;
}
// *****************************************************************************
// Function serialization and deserialization
int remotefs_get_request_id( const u8 *p, u8 *pid )
{
remotefs_err_flag = REMOTEFS_OK;
p = remotefs_match_packet_start( p );
p = remotefs_read_op_id( p, pid );
return remotefs_err_flag;
}
u32 remotefs_replace_flag( u32 val, u32 origflag, u32 newflag )
{
return ( val & origflag ) ? newflag : 0;
}
int remotefs_get_packet_size( const u8 *p, u16 *psize )
{
remotefs_err_flag = REMOTEFS_OK;
p = remotefs_read_expect( p, TYPE_PKT_SIZE );
p = remotefs_read_u16( p, psize );
return remotefs_err_flag;
}
// Generic write function
// Specifiers: o - operation
// r - response
// c - u8
// h - u16
// l - u32
// i - int
// L - s32
// p - ptr (given as ptr, len, len is an u32)
void remotefs_gen_write( u8 *p, const char *fmt, ... )
{
va_list ap;
const void *ptr;
u32 ptrlen;
va_start( ap, fmt );
p = remotefs_start_packet( p );
while( *fmt )
switch( *fmt ++ )
{
case 'o':
p = remotefs_write_op_id( p, va_arg( ap, int ) );
break;
case 'r':
*p++ = RFS_OP_RES_MOD | ( u8 )va_arg( ap, int );
break;
case 'c':
p = remotefs_write_u8( p, ( u8 )va_arg( ap, int ) );
break;
case 'h':
p = remotefs_write_u16( p, ( u16 )va_arg( ap, int ) );
break;
case 'i':
p = remotefs_write_u32( p, ( u32 )va_arg( ap, int ) );
break;
case 'l':
p = remotefs_write_u32( p, ( u32 )va_arg( ap, u32 ) );
break;
case 'L':
p = remotefs_write_u32( p, ( u32 )va_arg( ap, s32 ) );
break;
case 'p':
ptr = va_arg( ap, void * );
ptrlen = ( u32 )va_arg( ap, long );
p = remotefs_write_ptr( p, ptr, ptrlen );
break;
}
remotefs_end_packet( p );
}
// Generic read function
// Specifiers: o - operation
// r - response
// c - u8
// h - u16
// l - u32
// L - s32
// i - int
// p - ptr (returned as ptr, len, len is an u32)
int remotefs_gen_read( const u8 *p, const char *fmt, ... )
{
va_list ap;
const void *pptr;
u32 *ptrlen;
const u8 *tempptr;
u32 temp32;
va_start( ap, fmt );
remotefs_err_flag = REMOTEFS_OK;
p = remotefs_match_packet_start( p );
while( *fmt )
switch( *fmt ++ )
{
case 'o':
p = remotefs_expect_op_id( p, va_arg( ap, int ) );
break;
case 'r':
p = remotefs_read_expect( p, RFS_OP_RES_MOD | ( u8 )va_arg( ap, int ) );
break;
case 'c':
p = remotefs_read_u8( p, ( u8* )va_arg( ap, void* ) );
break;
case 'h':
p = remotefs_read_u16( p, ( u16* )va_arg( ap, void* ) );
break;
case 'l':
p = remotefs_read_u32( p, ( u32* )va_arg( ap, void* ) );
break;
case 'L':
p = remotefs_read_u32( p, &temp32 );
*( s32 *)va_arg( ap, void* ) = ( s32 )temp32;
break;
case 'i':
p = remotefs_read_u32( p, &temp32 );
*( int* )va_arg( ap, void* ) = ( int )temp32;
break;
case 'p':
pptr = va_arg( ap, void** );
ptrlen = va_arg( ap, void* );
tempptr = p;
p = remotefs_read_ptr( p, NULL, &temp32 );
if( p == tempptr + RFS_PTR_HEADER_SIZE )
*( const u8** )pptr = NULL;
else
*( const u8** )pptr = tempptr + RFS_PTR_HEADER_SIZE;
if( ptrlen )
*ptrlen = temp32;
break;
}
remotefs_match_packet_end( p );
return remotefs_err_flag;
}
// *****************************************************************************
// Operation: open
// open: int open( const char *pathname,int flags, mode_t mode )
void remotefs_open_write_response( u8 *p, int result )
{
remotefs_gen_write( p, "ri", RFS_OP_OPEN, result );
eluarpc_gen_write( p, "ri", RFS_OP_OPEN, result );
}
int remotefs_open_read_response( const u8 *p, int *presult )
{
return remotefs_gen_read( p, "ri", RFS_OP_OPEN, presult );
return eluarpc_gen_read( p, "ri", RFS_OP_OPEN, presult );
}
void remotefs_open_write_request( u8 *p, const char* pathname, int flags, int mode )
{
remotefs_gen_write( p, "opii", RFS_OP_OPEN, pathname, strlen( pathname ) + 1, flags, mode );
eluarpc_gen_write( p, "opii", RFS_OP_OPEN, pathname, strlen( pathname ) + 1, flags, mode );
}
int remotefs_open_read_request( const u8 *p, const char **ppathname, int *pflags, int *pmode )
{
return remotefs_gen_read( p, "opii", RFS_OP_OPEN, ppathname, NULL, pflags, pmode );
return eluarpc_gen_read( p, "opii", RFS_OP_OPEN, ppathname, NULL, pflags, pmode );
}
// *****************************************************************************
@ -346,22 +37,22 @@ int remotefs_open_read_request( const u8 *p, const char **ppathname, int *pflags
void remotefs_write_write_response( u8 *p, u32 result )
{
remotefs_gen_write( p, "rl", RFS_OP_WRITE, result );
eluarpc_gen_write( p, "rl", RFS_OP_WRITE, result );
}
int remotefs_write_read_response( const u8 *p, u32 *presult )
{
return remotefs_gen_read( p, "rl", RFS_OP_WRITE, presult );
return eluarpc_gen_read( p, "rl", RFS_OP_WRITE, presult );
}
void remotefs_write_write_request( u8 *p, int fd, const void *buf, u32 count )
{
remotefs_gen_write( p, "oip", RFS_OP_WRITE, fd, buf, count );
eluarpc_gen_write( p, "oip", RFS_OP_WRITE, fd, buf, count );
}
int remotefs_write_read_request( const u8 *p, int *pfd, const void **pbuf, u32 *pcount )
{
return remotefs_gen_read( p, "oip", RFS_OP_WRITE, pfd, pbuf, pcount );
return eluarpc_gen_read( p, "oip", RFS_OP_WRITE, pfd, pbuf, pcount );
}
// *****************************************************************************
@ -370,22 +61,22 @@ int remotefs_write_read_request( const u8 *p, int *pfd, const void **pbuf, u32 *
void remotefs_read_write_response( u8 *p, u32 readbytes )
{
remotefs_gen_write( p, "rp", RFS_OP_READ, NULL, readbytes );
eluarpc_gen_write( p, "rp", RFS_OP_READ, NULL, readbytes );
}
int remotefs_read_read_response( const u8 *p, const u8 **ppdata, u32 *preadbytes )
{
return remotefs_gen_read( p, "rp", RFS_OP_READ, ppdata, preadbytes );
return eluarpc_gen_read( p, "rp", RFS_OP_READ, ppdata, preadbytes );
}
void remotefs_read_write_request( u8 *p, int fd, u32 count )
{
remotefs_gen_write( p, "oil", RFS_OP_READ, fd, count );
eluarpc_gen_write( p, "oil", RFS_OP_READ, fd, count );
}
int remotefs_read_read_request( const u8 *p, int *pfd, u32 *pcount )
{
return remotefs_gen_read( p, "oil", RFS_OP_READ, pfd, pcount );
return eluarpc_gen_read( p, "oil", RFS_OP_READ, pfd, pcount );
}
// *****************************************************************************
@ -394,22 +85,22 @@ int remotefs_read_read_request( const u8 *p, int *pfd, u32 *pcount )
void remotefs_close_write_response( u8 *p, int result )
{
remotefs_gen_write( p, "ri", RFS_OP_CLOSE, result );
eluarpc_gen_write( p, "ri", RFS_OP_CLOSE, result );
}
int remotefs_close_read_response( const u8 *p, int *presult )
{
return remotefs_gen_read( p, "ri", RFS_OP_CLOSE, presult );
return eluarpc_gen_read( p, "ri", RFS_OP_CLOSE, presult );
}
void remotefs_close_write_request( u8 *p, int fd )
{
remotefs_gen_write( p, "oi", RFS_OP_CLOSE, fd );
eluarpc_gen_write( p, "oi", RFS_OP_CLOSE, fd );
}
int remotefs_close_read_request( const u8 *p, int *pfd )
{
return remotefs_gen_read( p, "oi", RFS_OP_CLOSE, pfd );
return eluarpc_gen_read( p, "oi", RFS_OP_CLOSE, pfd );
}
// *****************************************************************************
@ -418,22 +109,22 @@ int remotefs_close_read_request( const u8 *p, int *pfd )
void remotefs_lseek_write_response( u8 *p, s32 result )
{
remotefs_gen_write( p, "rL", RFS_OP_LSEEK, result );
eluarpc_gen_write( p, "rL", RFS_OP_LSEEK, result );
}
int remotefs_lseek_read_response( const u8 *p, s32 *presult )
{
return remotefs_gen_read( p, "rL", RFS_OP_LSEEK, presult );
return eluarpc_gen_read( p, "rL", RFS_OP_LSEEK, presult );
}
void remotefs_lseek_write_request( u8 *p, int fd, s32 offset, int whence )
{
remotefs_gen_write( p, "oiLi", RFS_OP_LSEEK, fd, offset, whence );
eluarpc_gen_write( p, "oiLi", RFS_OP_LSEEK, fd, offset, whence );
}
int remotefs_lseek_read_request( const u8 *p, int *pfd, s32 *poffset, int *pwhence )
{
return remotefs_gen_read( p, "oiLi", RFS_OP_LSEEK, pfd, poffset, pwhence );
return eluarpc_gen_read( p, "oiLi", RFS_OP_LSEEK, pfd, poffset, pwhence );
}
// ****************************************************************************
@ -442,22 +133,22 @@ int remotefs_lseek_read_request( const u8 *p, int *pfd, s32 *poffset, int *pwhen
void remotefs_opendir_write_response( u8 *p, u32 d )
{
remotefs_gen_write( p, "rl", RFS_OP_OPENDIR, d );
eluarpc_gen_write( p, "rl", RFS_OP_OPENDIR, d );
}
int remotefs_opendir_read_response( const u8 *p, u32 *pd )
{
return remotefs_gen_read( p, "rl", RFS_OP_OPENDIR, pd );
return eluarpc_gen_read( p, "rl", RFS_OP_OPENDIR, pd );
}
void remotefs_opendir_write_request( u8 *p, const char* name )
{
remotefs_gen_write( p, "op", RFS_OP_OPENDIR, name, strlen( name ) + 1 );
eluarpc_gen_write( p, "op", RFS_OP_OPENDIR, name, strlen( name ) + 1 );
}
int remotefs_opendir_read_request( const u8 *p, const char **pname )
{
return remotefs_gen_read( p, "op", RFS_OP_OPENDIR, pname, NULL );
return eluarpc_gen_read( p, "op", RFS_OP_OPENDIR, pname, NULL );
}
// ****************************************************************************
@ -467,22 +158,22 @@ int remotefs_opendir_read_request( const u8 *p, const char **pname )
void remotefs_readdir_write_response( u8 *p, const char *name, u32 size, u32 ftime )
{
remotefs_gen_write( p, "rpll", RFS_OP_READDIR, name, name ? strlen( name ) + 1 : 0, size, ftime );
eluarpc_gen_write( p, "rpll", RFS_OP_READDIR, name, name ? strlen( name ) + 1 : 0, size, ftime );
}
int remotefs_readdir_read_response( const u8 *p, const char **pname, u32 *psize, u32 *pftime )
{
return remotefs_gen_read( p, "rpll", RFS_OP_READDIR, pname, NULL, psize, pftime );
return eluarpc_gen_read( p, "rpll", RFS_OP_READDIR, pname, NULL, psize, pftime );
}
void remotefs_readdir_write_request( u8 *p, u32 d )
{
remotefs_gen_write( p, "ol", RFS_OP_READDIR, d );
eluarpc_gen_write( p, "ol", RFS_OP_READDIR, d );
}
int remotefs_readdir_read_request( const u8 *p, u32 *pd )
{
return remotefs_gen_read( p, "ol", RFS_OP_READDIR, pd );
return eluarpc_gen_read( p, "ol", RFS_OP_READDIR, pd );
}
// ****************************************************************************
@ -491,22 +182,22 @@ int remotefs_readdir_read_request( const u8 *p, u32 *pd )
void remotefs_closedir_write_response( u8 *p, int d )
{
remotefs_gen_write( p, "ri", RFS_OP_CLOSEDIR, d );
eluarpc_gen_write( p, "ri", RFS_OP_CLOSEDIR, d );
}
int remotefs_closedir_read_response( const u8 *p, int *pd )
{
return remotefs_gen_read( p, "ri", RFS_OP_CLOSEDIR, pd );
return eluarpc_gen_read( p, "ri", RFS_OP_CLOSEDIR, pd );
}
void remotefs_closedir_write_request( u8 *p, u32 d )
{
remotefs_gen_write( p, "ol", RFS_OP_CLOSEDIR, d );
eluarpc_gen_write( p, "ol", RFS_OP_CLOSEDIR, d );
}
int remotefs_closedir_read_request( const u8 *p, u32 *pd )
{
return remotefs_gen_read( p, "ol", RFS_OP_CLOSEDIR, pd );
return eluarpc_gen_read( p, "ol", RFS_OP_CLOSEDIR, pd );
}

View File

@ -12,9 +12,12 @@
#include "platform.h"
#include "elua_net.h"
#include "devman.h"
#include "buf.h"
#include "remotefs.h"
#include "eluarpc.h"
#include "linenoise.h"
#include "platform_conf.h"
#include "platform_conf.h"
#ifdef BUILD_SHELL
// Shell alternate ' ' char
@ -54,6 +57,7 @@ static void shell_help( char* args )
printf( " cat or type - lists file contents\n" );
printf( " lua [args] - run Lua with the given arguments\n" );
printf( " recv - receive a file via XMODEM and execute it\n" );
printf( " cp <src> <dst> - copy source file 'src' to 'dst'\n" );
printf( " ver - print eLua version\n" );
}
@ -235,6 +239,71 @@ static void shell_cat( char *args )
printf( "Usage: cat (or type) <filename1> [<filename2> ...]\n" );
}
// '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( char *args )
{
char *p1, *p2;
int res = 0;
FILE *fps = NULL, *fpd = NULL;
void *buf = NULL;
size_t datalen, total = 0;
if( *args )
{
p1 = strchr( args, ' ' );
if( p1 )
{
*p1 = 0;
p2 = strchr( p1 + 1, ' ' );
if( p2 )
{
*p2 = 0;
// First file is at args, second one at p1 + 1
if( ( fps = fopen( args, "rb" ) ) == NULL )
printf( "Unable to open %s for reading\n", args );
else
{
if( ( fpd = fopen( p1 + 1, "wb" ) ) == NULL )
printf( "Unable to open %s for writing\n", p1 + 1 );
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 );
fwrite( buf, 1, datalen, fpd );
total += datalen;
if( datalen < SHELL_COPY_BUFSIZE )
break;
}
printf( "%u bytes copied\n", ( unsigned int )total );
res = 1;
}
}
}
}
}
}
if( !res )
printf( "Syntax error.\n" );
if( fps )
fclose( fps );
if( fpd )
fclose( fpd );
if( buf )
free( buf );
}
// Insert shell commands here
static const SHELL_COMMAND shell_commands[] =
{
@ -247,6 +316,7 @@ static const SHELL_COMMAND shell_commands[] =
{ "dir", shell_ls },
{ "cat", shell_cat },
{ "type", shell_cat },
{ "cp", shell_cp },
{ NULL, NULL }
};