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:
parent
2bc5586ff9
commit
81e7f040fc
@ -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"
|
||||
|
146
doc/buildall.lua
146
doc/buildall.lua
@ -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()
|
||||
|
@ -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",
|
||||
|
@ -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 > 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 > 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."
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.]]
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
|
@ -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
123
doc/en/arch_rfs.txt
Normal 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$$
|
@ -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
283
doc/en/sermux.txt
Normal 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$$
|
@ -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;
|
||||
}
|
||||
|
@ -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
65
inc/eluarpc.h
Normal 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
|
@ -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
|
||||
|
@ -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 );
|
||||
|
@ -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 );
|
||||
|
@ -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
16
inc/sermux.h
Normal 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
|
@ -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
|
||||
|
@ -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
33
mux.py
Normal 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
13
mux_src/config.h
Normal 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
372
mux_src/main.c
Normal 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
349
mux_src/main.c.allthreads
Normal 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
755
mux_src/main.c.old
Normal 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
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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
|
40
rfs_server_src/deskutils.c
Normal file
40
rfs_server_src/deskutils.c
Normal 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;
|
||||
}
|
12
rfs_server_src/deskutils.h
Normal file
12
rfs_server_src/deskutils.h
Normal 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
|
@ -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 );
|
||||
}
|
||||
|
||||
|
@ -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
451
rfs_server_src/main.c
Normal 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
45
rfs_server_src/net.h
Normal 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
|
50
rfs_server_src/net_posix.c
Normal file
50
rfs_server_src/net_posix.c
Normal 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
102
rfs_server_src/net_win32.c
Normal 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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
12
rfs_server_src/rfs.h
Normal 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
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
300
rfs_server_src/serial_win32.c
Normal file
300
rfs_server_src/serial_win32.c
Normal 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;
|
||||
}
|
||||
|
@ -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 )
|
@ -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
40
rfs_server_src/type.h
Normal 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__
|
57
src/buf.c
57
src/buf.c
@ -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;
|
||||
}
|
||||
|
97
src/common.c
97
src/common.c
@ -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
|
||||
|
@ -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
218
src/common_uart.c
Normal 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
359
src/eluarpc.c
Normal 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;
|
||||
}
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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')
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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__
|
||||
|
117
src/platform/at91sam7x/platform_int.c
Normal file
117
src/platform/at91sam7x/platform_int.c
Normal 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 )
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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 )
|
||||
|
113
src/platform/avr32/platform_int.c
Normal file
113
src/platform/avr32/platform_int.c
Normal 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 )
|
@ -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
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
// Bogus defines for common.c
|
||||
#define CON_UART_ID 0
|
||||
#define CON_UART_SPEED 0
|
||||
#define CON_TIMER_ID 0
|
||||
|
||||
// *****************************************************************************
|
||||
|
@ -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"
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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__
|
||||
|
109
src/platform/lm3s/platform_int.c
Normal file
109
src/platform/lm3s/platform_int.c
Normal 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 )
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 ];
|
||||
|
@ -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__
|
||||
|
||||
|
@ -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 }
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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 )
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
// Bogus defines for common.c
|
||||
#define CON_UART_ID 0
|
||||
#define CON_UART_SPEED 0
|
||||
#define CON_TIMER_ID 0
|
||||
|
||||
// *****************************************************************************
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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
|
||||
|
@ -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__
|
||||
|
||||
|
130
src/platform/stm32/platform_int.c
Normal file
130
src/platform/stm32/platform_int.c
Normal 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 }
|
||||
};
|
@ -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, '!');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 ];
|
||||
|
||||
|
@ -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 ];
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
72
src/shell.c
72
src/shell.c
@ -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 }
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user