diff --git a/.gitignore b/.gitignore index 50a490b8..5bb02714 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,8 @@ inc/romfiles.h .sconf_temp/ .sconsign.dblite config.log +mux* +rfs_server* +doc/dist +doc/cache diff --git a/SConstruct b/SConstruct index 50bf5daa..a79e1e50 100644 --- a/SConstruct +++ b/SConstruct @@ -1,5 +1,6 @@ import os, sys, shutil, string -import platform as syspl +import platform as syspl +import glob # Helper: "normalize" a name to make it a suitable C macro name def cnorm( name ): @@ -116,89 +117,6 @@ board_list = { 'SAM7-EX256' : [ 'AT91SAM7X256', 'AT91SAM7X512' ], cpu_list = sum([board_list[i] for i in board_list],[]) - -# ROMFS file list "groups" -# To include a file in a ROMFS build, include it in a group here (or create one -# if you need) and make sure the group is included on your platform's file_list -# definition (right after this). - -# The following table will be left here just as an example -# eLua examples were removed from the distro since v0.8 -#romfs = { 'bisect' : [ 'bisect.lua' ], -# 'hangman' : [ 'hangman.lua' ], -# 'lhttpd' : [ 'index.pht', 'lhttpd.lua', 'test.lua' ], -# 'led' : [ 'led.lua' ], -# 'piano' : [ 'piano.lua' ], -# 'pwmled' : [ 'pwmled.lua' ], -# 'tvbgone' : [ 'tvbgone.lua', 'codes.bin' ], -# 'hello' : [ 'hello.lua' ], -# 'info' : [ 'info.lua' ], -# 'morse' : [ 'morse.lua' ], -# 'dualpwm' : [ 'dualpwm.lua' ], -# 'adcscope' : [ 'adcscope.lua' ], -# 'adcpoll' : [ 'adcpoll.lua' ], -# 'life' : [ 'life.lua' ], -# 'logo' : ['logo.lua', 'logo.bin' ], -# 'pong' : [ 'pong.lua' ], -# 'spaceship' : [ 'spaceship.lua' ], -# 'tetrives' : [ 'tetrives.lua' ], -# 'snake' : [ 'snake.lua' ], -# 'dataflash' : [ 'dataflash.lua' ], -# 'pachube' : [ 'pachube_demo.lua' ], -# 'inttest' : [ 'inttest.lua' ] -# } - -romfs = { - } - -# List of board/romfs data combinations -# The following table will be left here just as an example -# eLua examples were removed from the distro since v0.8 -#file_list = { 'SAM7-EX256' : [ 'bisect', 'hangman' , 'led', 'piano', 'hello', 'info', 'morse' ], -# 'EK-LM3S1968' : [ 'bisect', 'hangman', 'pong', 'led', 'piano', 'pwmled', 'hello', 'info', 'morse', 'adcscope', 'adcpoll', 'logo', 'spaceship', 'tetrives', 'snake' ], -# 'EK-LM3S8962' : [ 'lhttpd','bisect', 'led', 'pachube' ], -# 'EK-LM3S6965' : [ 'bisect', 'hangman', 'pong', 'led', 'piano', 'pwmled', 'hello', 'info', 'morse', 'adcscope', 'adcpoll', 'logo', 'tetrives' ], -# 'EK-LM3S9B92' : [ 'bisect', 'hangman', 'led', 'pwmled', 'hello', 'info', 'adcscope','adcpoll', 'life' ], -# 'STR9-COMSTICK' : [ 'bisect', 'hangman', 'led', 'hello', 'info' ], -# 'STR-E912' : [ 'bisect', 'hangman', 'led', 'hello', 'info', 'piano', 'adcscope' ], -# 'PC' : [ 'bisect', 'hello', 'info', 'life', 'hangman' ], -# 'SIM' : [ 'bisect', 'hello', 'info', 'life', 'hangman' ], -# 'LPC-H2888' : [ 'bisect', 'hangman', 'led', 'hello', 'info' ], -# 'MOD711' : [ 'bisect', 'hangman', 'led', 'hello', 'info', 'dualpwm' ], -# 'STM3210E-EVAL' : [ 'bisect', 'hello', 'info' ], -# 'ATEVK1100' : [ 'bisect', 'hangman', 'led', 'hello', 'info', 'dataflash' ], -# 'ATEVK1101' : [ 'bisect', 'led', 'hello', 'info', 'dataflash' ], -# 'ET-STM32' : [ 't' ], -# 'EAGLE-100' : [ 'bisect', 'hangman', 'lhttpd', 'led', 'hello', 'info' ], -# 'ELUA-PUC' : [ 'bisect', 'hangman', 'led', 'hello', 'info', 'pwmled', 'adcscope', 'adcpoll', 'inttest' ], -# 'MBED' : [ 'bisect', 'hangman', 'hello', 'info', 'led', 'pwmled', 'dualpwm', 'life', 'adcscope', 'adcpoll' ], -# 'MIZAR32' : [ ], -# 'NETDUINO': [ ], -#} - -file_list = { 'SAM7-EX256' : [ ], - 'EK-LM3S1968' : [ ], - 'EK-LM3S8962' : [ ], - 'EK-LM3S6965' : [ ], - 'EK-LM3S9B92' : [ ], - 'STR9-COMSTICK' : [ ], - 'STR-E912' : [ ], - 'PC' : [ ], - 'SIM' : [ ], - 'LPC-H2888' : [ ], - 'MOD711' : [ ], - 'STM3210E-EVAL' : [ ], - 'ATEVK1100' : [ ], - 'ATEVK1101' : [ ], - 'ET-STM32' : [ ], - 'EAGLE-100' : [ ], - 'ELUA-PUC' : [ ], - 'MBED' : [ ], - 'MIZAR32' : [ ], - 'NETDUINO': [ ], -} - - comp = Environment( tools = [], OBJSUFFIX = ".o", PROGSUFFIX = ".elf", @@ -469,12 +387,11 @@ if not GetOption( 'help' ): # Make ROM File System first if not GetOption( 'clean' ): print "Building ROM File System..." - romdir = "romfs" flist = [] - for sample in file_list[ comp['board'] ]: - flist += romfs[ sample ] + for sample in glob.glob("romfs/*"): + flist += [ sample ] import mkfs - mkfs.mkfs( romdir, "romfiles", flist, comp['romfs'], compcmd ) + mkfs.mkfs( ".", "romfiles", flist, comp['romfs'], compcmd ) print if os.path.exists( "inc/romfiles.h" ): os.remove( "inc/romfiles.h" ) diff --git a/build_elua.lua b/build_elua.lua index 2caa3584..059bf714 100755 --- a/build_elua.lua +++ b/build_elua.lua @@ -205,96 +205,6 @@ for k, v in pairs( board_list ) do end end --- ROMFS file list "groups" --- To include a file in a ROMFS build, include it in a group here (or create one --- if you need) and make sure the group is included on your platform's file_list --- definition (right after this). - --- The following table will be left here just as an example --- eLua examples were removed from the distro since v0.8 ---[[ -local romfs = -{ - bisect = { 'bisect.lua' }, - hangman = { 'hangman.lua' }, - lhttpd = { 'index.pht', 'lhttpd.lua', 'test.lua' }, - led = { 'led.lua' }, - piano = { 'piano.lua' }, - pwmled = { 'pwmled.lua' }, - tvbgone = { 'tvbgone.lua', 'codes.bin' }, - hello = { 'hello.lua' }, - info = { 'info.lua' }, - morse = { 'morse.lua' }, - dualpwm = { 'dualpwm.lua' }, - adcscope = { 'adcscope.lua' }, - adcpoll = { 'adcpoll.lua' }, - life = { 'life.lua' }, - logo = {'logo.lua', 'logo.bin' }, - pong = { 'pong.lua' }, - spaceship = { 'spaceship.lua' }, - tetrives = { 'tetrives.lua' }, - snake = { 'snake.lua' }, - dataflash = { 'dataflash.lua' }, - pachube = { 'pachube_demo.lua' }, - inttest = { 'inttest.lua' } -} ---]] - -local romfs = {} - --- List of board/romfs data combinations --- The following table will be left here just as an example --- eLua examples were removed from the distro since v0.8 ---[[ -local file_list = -{ - [ 'SAM7-EX256' ] = { 'bisect', 'hangman' , 'led', 'piano', 'hello', 'info', 'morse' }, - [ 'EK-LM3S1968' ] = { 'bisect', 'hangman', 'pong', 'led', 'piano', 'pwmled', 'hello', 'info', 'morse', 'adcscope', 'adcpoll', 'logo', 'spaceship', 'tetrives', 'snake' }, - [ 'EK-LM3S8962' ] = { 'lhttpd','bisect', 'led', 'pachube' }, - [ 'EK-LM3S6965' ] = { 'bisect', 'hangman', 'pong', 'led', 'piano', 'pwmled', 'hello', 'info', 'morse', 'adcscope', 'adcpoll', 'logo', 'tetrives' }, - [ 'EK-LM3S9B92' ] = { 'bisect', 'hangman', 'led', 'pwmled', 'hello', 'info', 'adcscope','adcpoll', 'life' }, - [ 'STR9-COMSTICK' ] = { 'bisect', 'hangman', 'led', 'hello', 'info' }, - [ 'STR-E912' ] = { 'bisect', 'hangman', 'led', 'hello', 'info', 'piano', 'adcscope' }, - [ 'PC' ] = { 'bisect', 'hello', 'info', 'life', 'hangman' }, - [ 'SIM' ] = { 'bisect', 'hello', 'info', 'life', 'hangman' }, - [ 'LPC-H2888' ] = { 'bisect', 'hangman', 'led', 'hello', 'info' }, - [ 'MOD711' ] = { 'bisect', 'hangman', 'led', 'hello', 'info', 'dualpwm' }, - [ 'STM3210E-EVAL' ] = { 'bisect', 'hello', 'info' }, - [ 'ATEVK1100' ] = { 'bisect', 'hangman', 'led', 'hello', 'info', 'dataflash' }, - [ 'ATEVK1101' ] = { 'bisect', 'led', 'hello', 'info', 'dataflash' }, - [ 'ET-STM32' ] = { 't' }, - [ 'EAGLE-100' ] = { 'bisect', 'hangman', 'lhttpd', 'led', 'hello', 'info' }, - [ 'ELUA-PUC' ] = { 'bisect', 'hangman', 'led', 'hello', 'info', 'pwmled', 'adcscope', 'adcpoll', 'inttest' }, - [ 'MBED' ] = { 'bisect', 'hangman', 'hello', 'info', 'led', 'pwmled', 'dualpwm', 'life', 'adcscope', 'adcpoll' }, - [ 'MIZAR32' ] = { }, - [ 'NETDUINO' ] = { }, -} ---]] - -local file_list = -{ - [ 'SAM7-EX256' ] = {}, - [ 'EK-LM3S1968' ] = {}, - [ 'EK-LM3S8962' ] = {}, - [ 'EK-LM3S6965' ] = {}, - [ 'EK-LM3S9B92' ] = {}, - [ 'STR9-COMSTICK' ] = {}, - [ 'STR-E912' ] = {}, - [ 'PC' ] = {}, - [ 'SIM' ] = {}, - [ 'LPC-H2888' ] = {}, - [ 'MOD711' ] = {}, - [ 'STM3210E-EVAL' ] = {}, - [ 'ATEVK1100' ] = {}, - [ 'ATEVK1101' ] = {}, - [ 'ET-STM32' ] = {}, - [ 'EAGLE-100' ] = {}, - [ 'ELUA-PUC' ] = {}, - [ 'MBED' ] = {}, - [ 'MIZAR32' ] = {}, - [ 'NETDUINO'] = {}, -} - builder:add_option( 'target', 'build "regular" float lua or integer-only "lualong"', 'lua', { 'lua', 'lualong' } ) builder:add_option( 'cpu', 'build for the specified CPU (board will be inferred, if possible)', 'auto', { cpu_list, 'auto' } ) builder:add_option( 'allocator', 'select memory allocator', 'auto', { 'newlib', 'multiple', 'simple', 'auto' } ) @@ -489,13 +399,10 @@ source_files = source_files .. uip_files .. specific_files -- ROM file system builder local function make_romfs() print "Building ROM file system ..." - local romdir = "romfs" local flist = {} - for _, sample in pairs( file_list[ comp.board:upper() ] ) do - table.insert( flist, romfs[ sample ] ) - end + flist = utils.string_to_table( utils.get_files( 'romfs', function( fname ) return not fname:find( "%.gitignore" ) end ) ) flist = utils.linearize_array( flist ) - if not mkfs.mkfs( romdir, "romfiles", flist, comp.romfs, fscompcmd ) then return -1 end + if not mkfs.mkfs( ".", "romfiles", flist, comp.romfs, fscompcmd ) then return -1 end if utils.is_file( "inc/romfiles.h" ) then -- Read both the old and the new file local oldfile = io.open( "inc/romfiles.h", "rb" ) diff --git a/inc/desktop/platform_conf.h b/inc/desktop/platform_conf.h index f9210134..fd2b631f 100644 --- a/inc/desktop/platform_conf.h +++ b/inc/desktop/platform_conf.h @@ -10,7 +10,10 @@ #define LUARPC_ENABLE_SERIAL #define LUA_PLATFORM_LIBS_ROM \ - _ROM( AUXLIB_RPC, luaopen_rpc, rpc_map ) + _ROM( AUXLIB_RPC, luaopen_rpc, rpc_map )\ + _ROM( AUXLIB_BITARRAY, luaopen_bitarray, bitarray_map )\ + _ROM( AUXLIB_PACK, luaopen_pack, pack_map )\ + _ROM( AUXLIB_BIT, luaopen_bit, bit_map ) #endif diff --git a/mux.lua b/mux.lua index 8085bca9..704e4dbf 100644 --- a/mux.lua +++ b/mux.lua @@ -6,13 +6,13 @@ builder:init( args ) builder:set_build_mode( builder.BUILD_DIR_LINEARIZED ) local flist = "main.c" -local rfs_flist = "main.c server.c log.c deskutils.c" +local rfs_flist = "main.c server.c log.c deskutils.c rfs_transports.c" local cdefs = "RFS_UDP_TRANSPORT RFS_INSIDE_MUX_MODE" local socklib if utils.is_windows() then cdefs = cdefs .. " WIN32_BUILD" rfs_flist = rfs_flist .. " os_io_win32.c serial_win32.c net_win32.c" - exeprefix = "exe" + exeprefix = ".exe" socklib = "ws2_32" else rfs_flist = rfs_flist .. " os_io_posix.c serial_posix.c net_posix.c" diff --git a/mux.py b/mux.py index 2dc638a9..6fa51a08 100644 --- a/mux.py +++ b/mux.py @@ -1,7 +1,7 @@ import os, sys, platform flist = "main.c" -rfs_flist = "main.c server.c log.c deskutils.c" +rfs_flist = "main.c server.c log.c deskutils.c rfs_transports.c" cdefs = "-DRFS_UDP_TRANSPORT -DRFS_INSIDE_MUX_MODE" socklib = '' ptlib = '' diff --git a/mux_src/main.c b/mux_src/main.c index 6892b6ce..5d7e56ca 100644 --- a/mux_src/main.c +++ b/mux_src/main.c @@ -145,7 +145,12 @@ static int parse_transport( const char* s ) #define FIRST_SERVICE_IDX 3 #define MIN_ARGC_COUNT 4 +#ifdef _MSC_VER +#define strcasecmp _stricmp +int main( int argc, char *argv[] ) +#else int main( int argc, char **argv ) +#endif { unsigned i; SERVICE_DATA *tservice; @@ -165,9 +170,9 @@ int main( int argc, char **argv ) log_err( "Usage: %s [] ... [] [-v]\n", argv[ 0 ] ); log_err( " mode: \n" ); log_err( " 'mux': serial multiplexer mode\n" ); - log_err( " 'rfsmux:: combined RFS and multiplexer mode.\n" ); - log_err( " transport: ',, ('flow' specifies the flow control type and can be 'none' or 'rtscts').\n" ); - log_err( " vcom1, ..., vcomn: multiplexer serial ports." ); + log_err( " 'rfsmux:': combined RFS and multiplexer mode.\n" ); + log_err( " transport: ',,' ('flow' specifies the flow control type and can be 'none' or 'rtscts').\n" ); + log_err( " vcom1, ..., vcomn: multiplexer serial ports.\n" ); log_err( " Use '-v' for verbose output.\n" ); return 1; } diff --git a/mux_src/mux.vcxproj b/mux_src/mux.vcxproj new file mode 100644 index 00000000..c83bba85 --- /dev/null +++ b/mux_src/mux.vcxproj @@ -0,0 +1,107 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + {68EE7183-C1E2-41A9-AADA-3456B4773685} + Win32Proj + mux + + + + Application + true + MultiByte + + + Application + false + true + MultiByte + + + + + + + + + + + + + true + ..\rfs_server_src;..\inc;..\inc\remotefs;$(IncludePath) + + + false + ..\rfs_server_src;..\inc;..\inc\remotefs;$(IncludePath) + + + + + + Level3 + Disabled + WIN32_BUILD;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + Ws2_32.lib;%(AdditionalDependencies) + + + + + + + Level3 + + + MaxSpeed + true + true + WIN32_BUILD;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + Ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/mux_src/mux.vcxproj.filters b/mux_src/mux.vcxproj.filters new file mode 100644 index 00000000..b04d17fc --- /dev/null +++ b/mux_src/mux.vcxproj.filters @@ -0,0 +1,69 @@ + + + + + source + + + source + + + source + + + source + + + source + + + source + + + source + + + source + + + source + + + source + + + + + headers + + + headers + + + headers + + + headers + + + headers + + + headers + + + headers + + + headers + + + + + {edd07642-0c4f-4725-9e8f-641858b5e631} + + + {7234826d-2dcc-404c-9472-998da14f1314} + + + \ No newline at end of file diff --git a/rfs_server.lua b/rfs_server.lua index b482b6fd..a2586690 100644 --- a/rfs_server.lua +++ b/rfs_server.lua @@ -20,12 +20,12 @@ if utils.is_windows() then print "SIM target not supported under Windows" os.exit( 1 ) end - flist = "main.c server.c os_io_win32.c log.c net_win32.c serial_win32.c deskutils.c" + flist = "main.c server.c os_io_win32.c log.c net_win32.c serial_win32.c deskutils.c rfs_transports.c" cdefs = cdefs .. " WIN32_BUILD" - exeprefix = "exe" + exeprefix = ".exe" socklib = 'ws2_32' else - flist = mainname .. " server.c os_io_posix.c log.c net_posix.c serial_posix.c deskutils.c" + flist = mainname .. " server.c os_io_posix.c log.c net_posix.c serial_posix.c deskutils.c rfs_transports.c" end local output = sim == 0 and 'rfs_server' or 'rfs_sim_server' diff --git a/rfs_server.py b/rfs_server.py index da8d50e2..bca6263f 100644 --- a/rfs_server.py +++ b/rfs_server.py @@ -13,12 +13,12 @@ if platform.system() == "Windows": if sim == '1': print "SIM target not supported under Windows" os.exit( 1 ) - flist = "main.c server.c os_io_win32.c log.c net_win32.c serial_win32.c deskutils.c" + flist = "main.c server.c os_io_win32.c log.c net_win32.c serial_win32.c deskutils.c rfs_transports.c" cdefs = cdefs + " -DWIN32_BUILD" exeprefix = ".exe" socklib = '-lws2_32' else: - flist = "%s server.c os_io_posix.c log.c net_posix.c serial_posix.c deskutils.c" % mainname + flist = "%s server.c os_io_posix.c log.c net_posix.c serial_posix.c deskutils.c rfs_transports.c" % mainname exeprefix = "" if sim == '0': diff --git a/rfs_server_src/main.c b/rfs_server_src/main.c index ce3a58d0..c692f488 100644 --- a/rfs_server_src/main.c +++ b/rfs_server_src/main.c @@ -15,413 +15,7 @@ #include #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 [-v]\n", argv[ 0 ] ); - log_err( " Serial transport: 'ser:,, ('flow' defines the flow control and can be either 'none' or 'rtscts')\n" ); - log_err( " UDP transport: 'udp:'\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; -} +#include "rfs_transports.h" #ifdef RFS_STANDALONE_MODE int main( int argc, const char **argv ) diff --git a/rfs_server_src/rfs_server.vcxproj b/rfs_server_src/rfs_server.vcxproj new file mode 100644 index 00000000..1b4ee199 --- /dev/null +++ b/rfs_server_src/rfs_server.vcxproj @@ -0,0 +1,105 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + {4A3A33C6-6A0C-4C82-8C07-A6896BAFB4FA} + Win32Proj + rfs_server + + + + Application + true + MultiByte + + + Application + false + true + MultiByte + + + + + + + + + + + + + true + .\;..\inc;..\inc\remotefs;$(IncludePath) + + + false + .\;..\inc;..\inc\remotefs;$(IncludePath) + + + + + + Level3 + Disabled + RFS_STANDALONE_MODE;WIN32_BUILD;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + Ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + RFS_STANDALONE_MODE;WIN32_BUILD;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + Ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/rfs_server_src/rfs_server.vcxproj.filters b/rfs_server_src/rfs_server.vcxproj.filters new file mode 100644 index 00000000..dc7d0df9 --- /dev/null +++ b/rfs_server_src/rfs_server.vcxproj.filters @@ -0,0 +1,69 @@ + + + + + source + + + source + + + source + + + source + + + source + + + source + + + source + + + source + + + source + + + source + + + + + headers + + + headers + + + headers + + + headers + + + headers + + + headers + + + headers + + + headers + + + + + {337cdfd6-7a94-45a7-9773-202c632d5000} + + + {ed41819a-7341-42c2-b1ee-525a54aeeee1} + + + \ No newline at end of file diff --git a/rfs_server_src/rfs_transports.c b/rfs_server_src/rfs_transports.c new file mode 100644 index 00000000..03904f14 --- /dev/null +++ b/rfs_server_src/rfs_transports.c @@ -0,0 +1,413 @@ +// 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 +#include +#include +#include +#include +#include "rfs.h" +#include "deskutils.h" +#include "rfs_transports.h" + +// **************************************************************************** +// Local variables + + +u8 rfs_buffer[ MAX_PACKET_SIZE + ELUARPC_WRITE_REQUEST_EXTRA ]; +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 ); +} + +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 ); +} + +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; +} + +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 = 0; + 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 [-v]\n", argv[ 0 ] ); + log_err( " Serial transport: 'ser:,, ('flow' defines the flow control and can be either 'none' or 'rtscts')\n" ); + log_err( " UDP transport: 'udp:'\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; +} + diff --git a/rfs_server_src/rfs_transports.h b/rfs_server_src/rfs_transports.h new file mode 100644 index 00000000..ad99370c --- /dev/null +++ b/rfs_server_src/rfs_transports.h @@ -0,0 +1,22 @@ +#ifndef _RFS_TRANSPORTS_H +#define _RFS_TRANSPORTS_H + +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; + +#define MAX_PACKET_SIZE 4096 + +extern const RFS_TRANSPORT_DATA *p_transport_data; +extern const RFS_TRANSPORT_DATA mem_transport_data; +extern const RFS_TRANSPORT_DATA udp_transport_data; +extern const RFS_TRANSPORT_DATA ser_transport_data; +extern u8 rfs_buffer[ MAX_PACKET_SIZE + ELUARPC_WRITE_REQUEST_EXTRA ]; + +#endif \ No newline at end of file diff --git a/rfs_server_src/serial_win32.c b/rfs_server_src/serial_win32.c index ae7bb873..eb7b03e9 100644 --- a/rfs_server_src/serial_win32.c +++ b/rfs_server_src/serial_win32.c @@ -8,17 +8,24 @@ #include "serial.h" #define WIN_ERROR ( HANDLE )-1 -#define WIN_MAX_PORT_NAME 1024 +#define WIN_MAX_PORT_NAME MAX_PATH #define MAX_HANDLES 1024 -static HANDLE sel_handlers[ MAX_HANDLES ]; -static int sel_handler_map[ MAX_HANDLES ]; +static HANDLE sel_handlers[ MAX_HANDLES ]; // XXX: consider making this an static variable of ser_select_byte +static int sel_handler_map[ MAX_HANDLES ]; // XXX: consider making this an static variable of ser_select_byte + +static void init_ov( OVERLAPPED* o ) +{ + HANDLE temp = o->hEvent; + memset( o, 0, sizeof( OVERLAPPED ) ); + o->hEvent = temp; +} // 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 ); @@ -29,18 +36,18 @@ static int ser_win32_set_timeouts( HANDLE hComm, DWORD ri, DWORD rtm, DWORD rtc, timeouts.ReadTotalTimeoutMultiplier = rtc; timeouts.WriteTotalTimeoutConstant = wtm; timeouts.WriteTotalTimeoutMultiplier = wtc; - if( SetCommTimeouts( hComm, &timeouts ) == FALSE ) - { - CloseHandle( hComm ); - return SER_ERR; - } - + 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 ) @@ -55,8 +62,8 @@ 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'; + + 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 ) @@ -70,10 +77,17 @@ ser_handler ser_open( const char* sername ) memset( hnd, 0, sizeof( SERIAL_DATA ) ); hnd->hnd = hComm; hnd->fWaitingOnRead = FALSE; - if( ( hnd->o.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) ) == NULL ) + if( ( hnd->o.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) ) == NULL ) + { + free( hnd ); return SER_HANDLER_INVALID; - if( ( hnd->o_wr.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) ) == NULL ) - return SER_HANDLER_INVALID; + } + if( ( hnd->o_wr.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) ) == NULL ) + { + free( hnd ); + CloseHandle( hnd->o.hEvent ); + return SER_HANDLER_INVALID; + } return hnd; } @@ -81,7 +95,7 @@ ser_handler ser_open( const char* sername ) void ser_close( ser_handler id ) { CloseHandle( id->o.hEvent ); - CloseHandle( id->o_wr.hEvent ); + CloseHandle( id->o_wr.hEvent ); CloseHandle( id->hnd ); free( id ); } @@ -90,12 +104,13 @@ int ser_setup( ser_handler id, u32 baud, int databits, int parity, int stopbits, { HANDLE hComm = id->hnd; DCB dcb; - - if( GetCommState( hComm, &dcb ) == FALSE ) - { - CloseHandle( hComm ); - return SER_ERR; - } + dcb.DCBlength = sizeof(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 ); @@ -120,59 +135,63 @@ int ser_setup( ser_handler id, u32 baud, int databits, int parity, int stopbits, dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; dcb.fOutxCtsFlow = TRUE; } - if( SetCommState( hComm, &dcb ) == 0 ) + if( SetCommState( hComm, &dcb ) == FALSE ) { 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 ) +static u32 ser_read_internal( ser_handler id, u32 timeout ) { HANDLE hComm = id->hnd; DWORD readbytes = 0; - - if( !id->fWaitingOnRead ) + DWORD dwRes = WaitForSingleObject( id->o.hEvent, timeout == SER_INF_TIMEOUT ? INFINITE : timeout ); + if( dwRes == WAIT_OBJECT_0 ) { - if( ReadFile( hComm, dest, maxsize, &readbytes, &id->o ) == FALSE ) - { - if( GetLastError() != ERROR_IO_PENDING ) - return 0; - else - id->fWaitingOnRead = TRUE; - } - else - return readbytes; + 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 ); + return readbytes; +} + +// Read up to the specified number of bytes, return bytes actually read +u32 ser_read( ser_handler id, u8* dest, u32 maxsize, u32 timeout ) +{ + DWORD readbytes = 0; 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; + readbytes = ser_read_internal( id, timeout ); + dest[0] = id->databuf; + } + else + { + init_ov( &id->o ); + if( ReadFile( id->hnd, dest, maxsize, &readbytes, &id->o ) ) + return readbytes; + if( GetLastError() != ERROR_IO_PENDING ) + return 0; + id->fWaitingOnRead = TRUE; // XXX: consider removing statement + readbytes = ser_read_internal( id, timeout ); + } + id->fWaitingOnRead = FALSE; return readbytes; } @@ -180,41 +199,25 @@ u32 ser_read( ser_handler id, u8* dest, u32 maxsize, u32 timeout ) int ser_read_byte( ser_handler id, u32 timeout ) { u8 data; - int res = ser_read( id, &data, 1, timeout ); - - return res == 1 ? data : -1; + return ser_read( id, &data, 1, timeout ) == 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 + DWORD written; + + init_ov( &id->o_wr ); + if( WriteFile( hComm, src, size, &written, &id->o_wr ) ) return written; + if( GetLastError() != ERROR_IO_PENDING ) + return 0; + if( !GetOverlappedResult( hComm, &id->o_wr, &written, TRUE ) ) + written = 0; + ResetEvent( id->o_wr.hEvent ); - 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; + return written; } // Write a byte to the serial port @@ -228,73 +231,57 @@ u32 ser_write_byte( ser_handler id, u8 data ) // otherwise int ser_select_byte( ser_handler *pobjects, unsigned nobjects, int timeout ) { - int i, idx; - DWORD readbytes; + int i; + DWORD readbytes, dwRes; int res = -1; unsigned num_wait = 0; ser_handler hnd; - HANDLE temp; - + + if( nobjects >= MAXIMUM_WAIT_OBJECTS ) + return -1; + // 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; - } + init_ov( &pobjects[ i ]->o ); + if( ReadFile( pobjects[ i ]->hnd, &pobjects[ i ]->databuf, 1, &readbytes, &pobjects[ i ]->o ) ) + return readbytes != 1 ? -1 : pobjects[ i ]->databuf | ( i << 8 ); + if( GetLastError() != ERROR_IO_PENDING ) + return -1; + pobjects[ i ]->fWaitingOnRead = TRUE; + } + sel_handler_map[ num_wait ] = i; + sel_handlers[ num_wait ++ ] = pobjects[ i ]->o.hEvent; } - - if( num_wait > 0 ) + + if( num_wait == 0 ) + return -1; + + dwRes = WaitForMultipleObjects( num_wait, sel_handlers, FALSE, timeout == SER_INF_TIMEOUT ? INFINITE : timeout ); + if( dwRes >= WAIT_OBJECT_0 && dwRes < WAIT_OBJECT_0 + num_wait ) { - 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 = 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 ++ ) { - 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 ); + CancelIo( hnd->hnd ); } - 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; + WaitForMultipleObjects( num_wait, sel_handlers, TRUE, INFINITE ); + for( i = 0; i < num_wait; i ++ ) + ResetEvent( pobjects[ sel_handler_map[ i ] ]->o.hEvent ); + } + + return res; } diff --git a/romfs/.gitignore b/romfs/.gitignore new file mode 100644 index 00000000..a5baada1 --- /dev/null +++ b/romfs/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore + diff --git a/rpc-lua.py b/rpc-lua.py index 2c65700c..a5a5d3ac 100644 --- a/rpc-lua.py +++ b/rpc-lua.py @@ -1,33 +1,35 @@ import os, sys, platform output = 'luarpc' -cdefs = ['-DLUA_CROSS_COMPILER','-DLUA_RPC'] +cdefs = "-DLUA_CROSS_COMPILER -DLUA_RPC" # Lua source files and include path lua_files = """lapi.c lcode.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c ltm.c lundump.c lvm.c lzio.c lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c ltablib.c lstrlib.c loadlib.c linit.c lua.c print.c lrotable.c""" lua_full_files = " " + " ".join( [ "src/lua/%s" % name for name in lua_files.split() ] ) -lua_full_files += " src/modules/luarpc.c src/luarpc_desktop_serial.c " +lua_full_files += " src/modules/luarpc.c src/modules/lpack.c src/modules/bitarray.c src/modules/bit.c src/luarpc_desktop_serial.c " -external_libs = ['m'] +external_libs = '-lm' if platform.system() == "Windows": lua_full_files += " src/serial/serial_win32.c" - cdefs.append("-DWIN32_BUILD") + cdefs += " -DWIN32_BUILD" else: lua_full_files += " src/serial/serial_posix.c" - external_libs += ['readline'] - cdefs.append("-DLUA_USE_READLINE") + external_libs += " -lreadline" + cdefs += " -DLUA_USE_READLINE" -local_include = ['src/lua', 'inc', 'src/modules', 'inc/desktop']; +local_include = "-Isrc/lua -Iinc -Isrc/modules -Iinc/desktop" + +# Compiler/linker options +cccom = "gcc -O2 -g %s -Wall %s -c $SOURCE -o $TARGET" % ( local_include, cdefs ) +linkcom = "gcc -o $TARGET $SOURCES %s" % external_libs # Env for building the program -comp = Environment( CPPPATH = local_include, - CCFLAGS = cdefs, +comp = Environment( CCCOM = cccom, + LINKCOM = linkcom, ENV = os.environ ) # Debug -comp.PrependUnique(CCFLAGS=['-g']) - Decider( 'MD5-timestamp' ) -Default( comp.Program( output, Split( lua_full_files ), LIBS=external_libs ) ) +Default( comp.Program( output, Split( lua_full_files ) ) ) diff --git a/src/common_uart.c b/src/common_uart.c index 5ea7ee40..0de329e8 100644 --- a/src/common_uart.c +++ b/src/common_uart.c @@ -147,10 +147,15 @@ void platform_uart_send( unsigned id, u8 data ) static elua_int_c_handler prev_uart_rx_handler; static void cmn_uart_rx_inthandler( elua_int_resnum resnum ) -{ +{ + int data; + if( buf_is_enabled( BUF_ID_UART, resnum ) || resnum == SERMUX_PHYS_ID ) - cmn_rx_handler( resnum, platform_s_uart_recv( resnum, 0 ) ); - + { + while( -1 != ( data = platform_s_uart_recv( resnum, 0 ) ) ) + cmn_rx_handler( resnum, ( u8 )data ); + } + // Chain to previous handler if( prev_uart_rx_handler != NULL ) prev_uart_rx_handler( resnum ); diff --git a/src/elua_uip.c b/src/elua_uip.c index d101218d..ace6604c 100644 --- a/src/elua_uip.c +++ b/src/elua_uip.c @@ -40,13 +40,7 @@ static u32 periodic_timer, arp_timer; static void device_driver_send() { - if( uip_len <= TOTAL_HEADER_LENGTH ) - platform_eth_send_packet( uip_buf, uip_len ); - else - { - platform_eth_send_packet( uip_buf, TOTAL_HEADER_LENGTH ); - platform_eth_send_packet( ( u8* )uip_appdata, uip_len - TOTAL_HEADER_LENGTH ); - } + platform_eth_send_packet( uip_buf, uip_len ); } // This gets called on both Ethernet RX interrupts and timer requests, @@ -202,7 +196,7 @@ static int elua_uip_telnet_socket = -1; // Utility function for TELNET: parse input buffer, skipping over // TELNET specific sequences // Returns the length of the buffer after processing -static void elua_uip_telnet_handle_input( struct elua_uip_state* s ) +static void elua_uip_telnet_handle_input( volatile struct elua_uip_state* s ) { u8 *dptr = ( u8* )uip_appdata; char *orig = ( char* )s->ptr; @@ -272,7 +266,7 @@ volatile static elua_net_ip elua_uip_accept_remote; void elua_uip_appcall() { - struct elua_uip_state *s; + volatile struct elua_uip_state *s; elua_net_size temp; int sockno; diff --git a/src/luarpc_desktop_serial.c b/src/luarpc_desktop_serial.c index 2507b05f..b3f2960a 100644 --- a/src/luarpc_desktop_serial.c +++ b/src/luarpc_desktop_serial.c @@ -41,7 +41,7 @@ void transport_open( Transport *tpt, const char *path ) } ser_setup( tpt->fd, 115200, SER_DATABITS_8, SER_PARITY_NONE, SER_STOPBITS_1 ); - ser_set_timeout_ms( tpt->fd, 1000 ); + ser_set_timeout_ms( tpt->fd, 10000 ); } // Open Listener / Server diff --git a/src/modules/bitarray.c b/src/modules/bitarray.c index 8ec04c5e..1df3283c 100644 --- a/src/modules/bitarray.c +++ b/src/modules/bitarray.c @@ -3,7 +3,7 @@ #include "lua.h" #include "lualib.h" #include "lauxlib.h" -#include "platform.h" +#include "type.h" #include "auxmods.h" #include "lrotable.h" #include @@ -175,15 +175,15 @@ static int bitarray_set( lua_State *L ) switch( pa->elsize ) { case 8: - pa->values[ idx ] = val;; + pa->values[ idx ] = ( u8 )newval; break; case 16: - *( ( u16* )pa->values + idx ) = val; + *( ( u16* )pa->values + idx ) = ( u16 )newval; break; case 32: - *( ( u32* )pa->values + idx ) = val; + *( ( u32* )pa->values + idx ) = ( u32 )newval; break; } return 0; diff --git a/src/modules/spi.c b/src/modules/spi.c index 83088d80..c2acc9db 100644 --- a/src/modules/spi.c +++ b/src/modules/spi.c @@ -58,7 +58,7 @@ static int spi_rw_helper( lua_State *L, int withread ) { spi_data_type value; const char *sval; - int total = lua_gettop( L ), i, id; + int total = lua_gettop( L ), i, j, id; size_t len, residx = 1; id = luaL_checkinteger( L, 1 ); @@ -79,9 +79,9 @@ static int spi_rw_helper( lua_State *L, int withread ) else if( lua_isstring( L, i ) ) { sval = lua_tolstring( L, i, &len ); - for( i = 0; i < len; i ++ ) + for( j = 0; j < len; j ++ ) { - value = platform_spi_send_recv( id, sval[ i ] ); + value = platform_spi_send_recv( id, sval[ j ] ); if( withread ) { lua_pushnumber( L, value ); diff --git a/src/platform/avr32/EVK1100/evk1100_conf.h b/src/platform/avr32/EVK1100/evk1100_conf.h index 61acf6a6..11999228 100644 --- a/src/platform/avr32/EVK1100/evk1100_conf.h +++ b/src/platform/avr32/EVK1100/evk1100_conf.h @@ -23,6 +23,10 @@ //#define BUILD_SERMUX #define BUILD_ADC +#define BUILD_UIP +//#define BUILD_DHCPC +#define BUILD_DNS + // ***************************************************************************** // UART/Timer IDs configuration data (used in main.c) @@ -66,6 +70,11 @@ #else #define ADCLINE #endif +#ifdef BUILD_UIP +#define NETLINE _ROM( AUXLIB_NET, luaopen_net, net_map ) +#else +#define NETLINE +#endif #if defined( BUILD_RPC ) #define RPCLINE _ROM( AUXLIB_RPC, luaopen_rpc, rpc_map ) @@ -80,8 +89,9 @@ _ROM( AUXLIB_PWM, luaopen_pwm, pwm_map )\ _ROM( AUXLIB_SPI, luaopen_spi, spi_map )\ _ROM( AUXLIB_TMR, luaopen_tmr, tmr_map )\ - ADCLINE\ _ROM( AUXLIB_TERM, luaopen_term, term_map )\ + ADCLINE\ + NETLINE\ _ROM( AUXLIB_CPU, luaopen_cpu, cpu_map )\ _ROM( AUXLIB_ELUA, luaopen_elua, elua_map )\ RPCLINE\ @@ -174,4 +184,26 @@ // ***************************************************************************** // CPU constants that should be exposed to the eLua "cpu" module + +// Static TCP/IP configuration +#define ELUA_CONF_IPADDR0 192 +#define ELUA_CONF_IPADDR1 168 +#define ELUA_CONF_IPADDR2 1 +#define ELUA_CONF_IPADDR3 10 + +#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 + #endif // #ifndef __EVK1100_CONF_H__ diff --git a/src/platform/avr32/MIZAR32/mizar32_conf.h b/src/platform/avr32/MIZAR32/mizar32_conf.h index 8ae33a1d..cab9aa32 100644 --- a/src/platform/avr32/MIZAR32/mizar32_conf.h +++ b/src/platform/avr32/MIZAR32/mizar32_conf.h @@ -8,6 +8,7 @@ #define __MIZAR32_CONF_H__ #include "sdramc.h" +#include "sermux.h" #include "buf.h" // ***************************************************************************** @@ -15,18 +16,27 @@ #define BUILD_MMCFS //#define BUILD_XMODEM -//#define BUILD_SHELL -//#define BUILD_ROMFS +#define BUILD_SHELL +#define BUILD_ROMFS //#define BUILD_TERM -#define BUILD_CON_GENERIC +//#define BUILD_CON_GENERIC //#define BUILD_RPC #define BUF_ENABLE_UART #define BUILD_C_INT_HANDLERS //#define BUILD_ADC +#define BUILA_LUA_INT_HANDLERS +//#define BUILD_RFS +//#define BUILD_SERMUX + +#define BUILD_UIP +//#define BUILD_DHCPC +#define BUILD_DNS +#define BUILD_CON_TCP // ***************************************************************************** // UART/Timer IDs configuration data (used in main.c) +//#define CON_UART_ID ( SERMUX_SERVICE_ID_FIRST + 1 ) #define CON_UART_ID 0 #define CON_UART_SPEED 115200 #define CON_TIMER_ID 0 @@ -65,6 +75,11 @@ #else #define ADCLINE #endif +#ifdef BUILD_UIP +#define NETLINE _ROM( AUXLIB_NET, luaopen_net, net_map ) +#else +#define NETLINE +#endif #if defined( BUILD_RPC ) #define RPCLINE _ROM( AUXLIB_RPC, luaopen_rpc, rpc_map ) @@ -77,8 +92,9 @@ _ROM( AUXLIB_UART, luaopen_uart, uart_map )\ _ROM( AUXLIB_PIO, luaopen_pio, pio_map )\ _ROM( AUXLIB_PWM, luaopen_pwm, pwm_map )\ + _ROM( AUXLIB_SPI, luaopen_spi, spi_map )\ _ROM( AUXLIB_TMR, luaopen_tmr, tmr_map )\ - _ROM( AUXLIB_TERM, luaopen_term, term_map )\ + NETLINE\ _ROM( AUXLIB_CPU, luaopen_cpu, cpu_map )\ _ROM( AUXLIB_ELUA, luaopen_elua, elua_map )\ ADCLINE\ @@ -87,11 +103,14 @@ _ROM( AUXLIB_PACK, luaopen_pack, pack_map )\ _ROM( LUA_MATHLIBNAME, luaopen_math, math_map ) +#if MINIMAL_ROM_MODULES_TO_FIT_IN_120KB /* Minimal ROM modules, to fit in 120KB */ #undef LUA_PLATFORM_LIBS_ROM #define LUA_PLATFORM_LIBS_ROM\ _ROM( AUXLIB_PIO, luaopen_pio, pio_map )\ _ROM( AUXLIB_TMR, luaopen_tmr, tmr_map )\ + NETLINE +#endif // ***************************************************************************** // Configuration data @@ -165,12 +184,49 @@ // Interrupt queue size #define PLATFORM_INT_QUEUE_LOG_SIZE 5 +#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 + +// Static TCP/IP configuration + +#define ELUA_CONF_IPADDR0 192 +#define ELUA_CONF_IPADDR1 168 +#define ELUA_CONF_IPADDR2 1 +#define ELUA_CONF_IPADDR3 10 + +#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 + #endif // #ifndef __MIZAR32_CONF_H__ diff --git a/src/platform/avr32/conf.lua b/src/platform/avr32/conf.lua index 9aba6075..126cf2a8 100644 --- a/src/platform/avr32/conf.lua +++ b/src/platform/avr32/conf.lua @@ -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 platform_int.c adc.c pwm.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 adc.c pwm.c ethernet.c" addm( "FORAVR32" ) -- See board.h for possible BOARD values. diff --git a/src/platform/avr32/conf.py b/src/platform/avr32/conf.py index 255845e4..13f5f79d 100644 --- a/src/platform/avr32/conf.py +++ b/src/platform/avr32/conf.py @@ -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 platform_int.c adc.c pwm.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 adc.c pwm.c ethernet.c" comp.Append(CPPDEFINES = 'FORAVR32') # See board.h for possible BOARD values. diff --git a/src/platform/avr32/ethernet.c b/src/platform/avr32/ethernet.c new file mode 100644 index 00000000..d0a8eb33 --- /dev/null +++ b/src/platform/avr32/ethernet.c @@ -0,0 +1,814 @@ +/* This source file is part of the ATMEL AVR32-UC3-SoftwareFramework-1.6.0 Release */ + +/*This file has been prepared for Doxygen automatic documentation generation.*/ +/*! \file ********************************************************************* + * + * \brief MACB driver for EVK1100 board. + * + * This file defines a useful set of functions for the MACB interface on + * AVR32 devices. + * + * - Compiler: IAR EWAVR32 and GNU GCC for AVR32 + * - Supported devices: All AVR32 devices with a MACB module can be used. + * - AppNote: + * + * \author Atmel Corporation: http://www.atmel.com \n + * Support and FAQ: http://support.atmel.no/ + * + *****************************************************************************/ + +/* Copyright (c) 2009 Atmel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an Atmel + * AVR product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE + * + */ +/* + * ported on elua world by nuccio raciti , enjoy. + */ +#include +#include +#include + +#include "compiler.h" + +#include "platform_conf.h" + +#ifdef BUILD_UIP + +#include "ethernet.h" + +/* Size of each receive buffer - DO NOT CHANGE. */ +#define RX_BUFFER_SIZE 128 + + +/* The buffer addresses written into the descriptors must be aligned so the +last two bits are zero. These bits have special meaning for the MACB +peripheral and cannot be used as part of the address. */ +#define ADDRESS_MASK ( ( unsigned long ) 0xFFFFFFFC ) + +/* Bit used within the address stored in the descriptor to mark the last +descriptor in the array. */ +#define RX_WRAP_BIT ( ( unsigned long ) 0x02 ) + +/* A short delay is used to wait for a buffer to become available, should +one not be immediately available when trying to transmit a frame. */ +#define BUFFER_WAIT_DELAY ( 2 ) + +#include "ethernet.h" +#include "intc.h" +#include "elua_uip.h" + +#ifndef FREERTOS_USED +#define portENTER_CRITICAL Disable_global_interrupt +#define portEXIT_CRITICAL Enable_global_interrupt +#define portENTER_SWITCHING_ISR() +#define portEXIT_SWITCHING_ISR() +#endif + +#define TIMEOUT 500 + + +/* Buffer written to by the MACB DMA. Must be aligned as described by the +comment above the ADDRESS_MASK definition. */ + +static volatile char pcRxBuffer[ ETHERNET_CONF_NB_RX_BUFFERS * RX_BUFFER_SIZE ] __attribute__ ((aligned (4))); +/* Buffer read by the MACB DMA. Must be aligned as described by the comment +above the ADDRESS_MASK definition. */ + +static volatile char pcTxBuffer[ ETHERNET_CONF_NB_TX_BUFFERS * ETHERNET_CONF_TX_BUFFER_SIZE ] __attribute__ ((aligned (4))); + +/* Descriptors used to communicate between the program and the MACB peripheral. +These descriptors hold the locations and state of the Rx and Tx buffers. +Alignment value chosen from RBQP and TBQP registers description in datasheet. */ + +static volatile AVR32_TxTdDescriptor xTxDescriptors[ ETHERNET_CONF_NB_TX_BUFFERS ] __attribute__ ((aligned (8))); +static volatile AVR32_RxTdDescriptor xRxDescriptors[ ETHERNET_CONF_NB_RX_BUFFERS ] __attribute__ ((aligned (8))); + +/* The IP and Ethernet addresses are read from the header files. */ +unsigned char cMACAddress[ 6 ] = { ETHERNET_CONF_ETHADDR0,ETHERNET_CONF_ETHADDR1,ETHERNET_CONF_ETHADDR2,ETHERNET_CONF_ETHADDR3,ETHERNET_CONF_ETHADDR4,ETHERNET_CONF_ETHADDR5 }; + +/*-----------------------------------------------------------*/ + +/* See the header file for descriptions of public functions. */ + +/* + * Prototype for the MACB interrupt function - called by the asm wrapper. + */ + +__attribute__((__interrupt__)) void vMACB_ISR(void); + + +/* + * Initialise both the Tx and Rx descriptors used by the MACB. + */ +static void prvSetupDescriptors(volatile avr32_macb_t *macb); + +// +// Restore ownership of all Rx buffers to the MACB. +// +static void vResetMacbRxFrames( void ); + +/* + * Write our MAC address into the MACB. + */ +static void prvSetupMACAddress(volatile avr32_macb_t *macb); + +/* + * Configure the MACB for interrupts. + */ +static void prvSetupMACBInterrupt(volatile avr32_macb_t *macb); + +/* + * Some initialisation functions. + */ +static Bool prvProbePHY(volatile avr32_macb_t *macb); +static unsigned long ulReadMDIO(volatile avr32_macb_t *macb, unsigned short usAddress); +static void vWriteMDIO(volatile avr32_macb_t *macb, unsigned short usAddress, unsigned short usValue); + + +/* Holds the index to the next buffer from which data will be read. */ +volatile unsigned long ulNextRxBuffer = 0; + + +long lMACBSend(volatile avr32_macb_t *macb, const void *pvFrom, unsigned long ulLength, long lEndOfFrame) +{ + const unsigned char *pcFrom = pvFrom; + static unsigned long uxTxBufferIndex = 0; + void *pcBuffer; + unsigned long ulLastBuffer, ulDataBuffered = 0, ulDataRemainingToSend, ulLengthToSend; + + /* If the length of data to be transmitted is greater than each individual + transmit buffer then the data will be split into more than one buffer. + Loop until the entire length has been buffered. */ + while( ulDataBuffered < ulLength ) + { + // Is a buffer available ? + while( !( xTxDescriptors[ uxTxBufferIndex ].U_Status.status & AVR32_TRANSMIT_OK ) ) + { + // There is no room to write the Tx data to the Tx buffer. + // Wait a short while, then try again. + __asm__ __volatile__ ("nop"); + } + + portENTER_CRITICAL(); + { + // Get the address of the buffer from the descriptor, + // then copy the data into the buffer. + pcBuffer = ( void * ) xTxDescriptors[ uxTxBufferIndex ].addr; + + // How much can we write to the buffer ? + ulDataRemainingToSend = ulLength - ulDataBuffered; + if( ulDataRemainingToSend <= ETHERNET_CONF_TX_BUFFER_SIZE ) + { + // We can write all the remaining bytes. + ulLengthToSend = ulDataRemainingToSend; + } + else + { + // We can't write more than ETH_TX_BUFFER_SIZE in one go. + ulLengthToSend = ETHERNET_CONF_TX_BUFFER_SIZE; + } + // Copy the data into the buffer. + memcpy( pcBuffer, &( pcFrom[ ulDataBuffered ] ), ulLengthToSend ); + ulDataBuffered += ulLengthToSend; + // Is this the last data for the frame ? + if( lEndOfFrame && ( ulDataBuffered >= ulLength ) ) + { + // No more data remains for this frame so we can start the transmission. + ulLastBuffer = AVR32_LAST_BUFFER; + } + else + { + // More data to come for this frame. + ulLastBuffer = 0; + } + // Fill out the necessary in the descriptor to get the data sent, + // then move to the next descriptor, wrapping if necessary. + if( uxTxBufferIndex >= ( ETHERNET_CONF_NB_TX_BUFFERS - 1 ) ) + { + xTxDescriptors[ uxTxBufferIndex ].U_Status.status = ( ulLengthToSend & ( unsigned long ) AVR32_LENGTH_FRAME ) + | ulLastBuffer + | AVR32_TRANSMIT_WRAP; + uxTxBufferIndex = 0; + } else + { + xTxDescriptors[ uxTxBufferIndex ].U_Status.status = ( ulLengthToSend & ( unsigned long ) AVR32_LENGTH_FRAME ) + | ulLastBuffer; + uxTxBufferIndex++; + } + /* If this is the last buffer to be sent for this frame we can + start the transmission. */ + if( ulLastBuffer ) + macb->ncr |= AVR32_MACB_TSTART_MASK; + + } + portEXIT_CRITICAL(); + } + + return PASS; +} + + +unsigned long ulMACBInputLength(void) +{ + register unsigned long ulIndex , ulLength = 0; + unsigned int uiTemp; + volatile unsigned long ulEventStatus; + + // Check if the MACB encountered a problem. + ulEventStatus = AVR32_MACB.rsr; + if( ulEventStatus & AVR32_MACB_RSR_BNA_MASK ) + { // MACB couldn't get ownership of a buffer. This could typically + // happen if the total numbers of Rx buffers is tailored too small + // for a noisy network with big frames. + // We might as well restore ownership of all buffers to the MACB to + // restart from a clean state. + vResetMacbRxFrames(); + return( ulLength ); + } + + // Skip any fragments. We are looking for the first buffer that contains + // data and has the SOF (start of frame) bit set. + while( ( xRxDescriptors[ ulNextRxBuffer ].addr & AVR32_OWNERSHIP_BIT ) + && !( xRxDescriptors[ ulNextRxBuffer ].U_Status.status & AVR32_SOF ) ) + { + // Ignoring this buffer. Mark it as free again. + uiTemp = xRxDescriptors[ ulNextRxBuffer ].addr; + xRxDescriptors[ ulNextRxBuffer ].addr = uiTemp & ~( AVR32_OWNERSHIP_BIT ); + ulNextRxBuffer++; + if( ulNextRxBuffer >= ETHERNET_CONF_NB_RX_BUFFERS ) + { + ulNextRxBuffer = 0; + } + } + + // We are going to walk through the descriptors that make up this frame, + // but don't want to alter ulNextRxBuffer as this would prevent vMACBRead() + // from finding the data. Therefore use a copy of ulNextRxBuffer instead. + ulIndex = ulNextRxBuffer; + + // Walk through the descriptors until we find the last buffer for this frame. + // The last buffer will give us the length of the entire frame. + while ( xRxDescriptors[ ulIndex ].addr & AVR32_OWNERSHIP_BIT ) + { + ulLength = xRxDescriptors[ ulIndex ].U_Status.status & AVR32_LENGTH_FRAME; + if (ulLength) break; //return ulLength + + // Increment to the next buffer, wrapping if necessary. + if( ++ulIndex >= ETHERNET_CONF_NB_RX_BUFFERS ) ulIndex = 0; + + // Is the descriptor valid? + if (!(xRxDescriptors[ ulIndex ].addr & AVR32_OWNERSHIP_BIT)) break; //return 0 + + // Is it a SOF? If so, the head packet is bad and should be discarded + if (xRxDescriptors[ ulIndex ].U_Status.status & AVR32_SOF) + { + // Mark the buffers of the CURRENT, FAULTY packet available. + unsigned int i = ulNextRxBuffer; + do{ + // Ignore the faulty frame. Mark its buffers as owned by the MACB. + uiTemp = xRxDescriptors[ i ].addr; + xRxDescriptors[ i ].addr = uiTemp & ~(AVR32_OWNERSHIP_BIT); + if (++i>=ETHERNET_CONF_NB_RX_BUFFERS) i=0; + }while (i!=ulIndex); + ulNextRxBuffer=ulIndex; + // We have the start of a new packet, look at that one instead. + } + } + return ulLength; +} +/*-----------------------------------------------------------*/ + +void vMACBRead(void *pvTo, unsigned long ulSectionLength, unsigned long ulTotalFrameLength) +{ + unsigned char *pcTo = pvTo; + static unsigned long ulSectionBytesReadSoFar = 0, ulBufferPosition = 0, ulFrameBytesReadSoFar = 0; + static const unsigned char *pcSource; + register unsigned long ulBytesRemainingInBuffer, ulRemainingSectionBytes; + unsigned int uiTemp; + + // Read ulSectionLength bytes from the Rx buffers. + // This is not necessarily any correspondence between the length of our Rx buffers, + // and the length of the data we are returning or the length of the data being requested. + // Therefore, between calls we have to remember not only which buffer we are currently + // processing, but our position within that buffer. + // This would be greatly simplified if PBUF_POOL_BUFSIZE could be guaranteed to be greater + // than the size of each Rx buffer, and that memory fragmentation did not occur. + + // This function should only be called after a call to ulMACBInputLength(). + // This will ensure ulNextRxBuffer is set to the correct buffer. */ + + // vMACBRead is called with pcTo set to NULL to indicate that we are about + // to read a new frame. Any fragments remaining in the frame we were + // processing during the last call should be dropped. + if( pcTo == NULL ) + { + // How many bytes are indicated as being in this buffer? + // If none then the buffer is completely full and the frame is contained within more + // than one buffer. + // Reset our state variables ready for the next read from this buffer. + pcSource = ( unsigned char * )( xRxDescriptors[ ulNextRxBuffer ].addr & ADDRESS_MASK ); + ulFrameBytesReadSoFar = ( unsigned long ) 0; + ulBufferPosition = ( unsigned long ) 0; + } + else + { + // Loop until we have obtained the required amount of data. + ulSectionBytesReadSoFar = 0; + while( ulSectionBytesReadSoFar < ulSectionLength ) + { + // We may have already read some data from this buffer. + // How much data remains in the buffer? + ulBytesRemainingInBuffer = ( RX_BUFFER_SIZE - ulBufferPosition ); + + // How many more bytes do we need to read before we have the + // required amount of data? + ulRemainingSectionBytes = ulSectionLength - ulSectionBytesReadSoFar; + + // Do we want more data than remains in the buffer? + if( ulRemainingSectionBytes > ulBytesRemainingInBuffer ) + { + // We want more data than remains in the buffer so we can + // write the remains of the buffer to the destination, then move + // onto the next buffer to get the rest. + memcpy( &( pcTo[ ulSectionBytesReadSoFar ] ), &( pcSource[ ulBufferPosition ] ), ulBytesRemainingInBuffer ); + ulSectionBytesReadSoFar += ulBytesRemainingInBuffer; + ulFrameBytesReadSoFar += ulBytesRemainingInBuffer; + + // Mark the buffer as free again. + uiTemp = xRxDescriptors[ ulNextRxBuffer ].addr; + xRxDescriptors[ ulNextRxBuffer ].addr = uiTemp & ~( AVR32_OWNERSHIP_BIT ); + // Move onto the next buffer. + ulNextRxBuffer++; + + if( ulNextRxBuffer >= ETHERNET_CONF_NB_RX_BUFFERS ) + { + ulNextRxBuffer = ( unsigned long ) 0; + } + + // Reset the variables for the new buffer. + pcSource = ( unsigned char * )( xRxDescriptors[ ulNextRxBuffer ].addr & ADDRESS_MASK ); + ulBufferPosition = ( unsigned long ) 0; + } + else + { + // We have enough data in this buffer to send back. + // Read out enough data and remember how far we read up to. + memcpy( &( pcTo[ ulSectionBytesReadSoFar ] ), &( pcSource[ ulBufferPosition ] ), ulRemainingSectionBytes ); + + // There may be more data in this buffer yet. + // Increment our position in this buffer past the data we have just read. + ulBufferPosition += ulRemainingSectionBytes; + ulSectionBytesReadSoFar += ulRemainingSectionBytes; + ulFrameBytesReadSoFar += ulRemainingSectionBytes; + + // Have we now finished with this buffer? + if( ( ulBufferPosition >= RX_BUFFER_SIZE ) || ( ulFrameBytesReadSoFar >= ulTotalFrameLength ) ) + { + // Mark the buffer as free again. + uiTemp = xRxDescriptors[ ulNextRxBuffer ].addr; + xRxDescriptors[ ulNextRxBuffer ].addr = uiTemp & ~( AVR32_OWNERSHIP_BIT ); + // Move onto the next buffer. + ulNextRxBuffer++; + + if( ulNextRxBuffer >= ETHERNET_CONF_NB_RX_BUFFERS ) + { + ulNextRxBuffer = 0; + } + + pcSource = ( unsigned char * )( xRxDescriptors[ ulNextRxBuffer ].addr & ADDRESS_MASK ); + ulBufferPosition = 0; + } + } + } + } +} + +/*-----------------------------------------------------------*/ +void vMACBFlushCurrentPacket(unsigned long ulTotalFrameLength) +{ + unsigned int uiTemp; + long int lTotalFrameLen = (long int)ulTotalFrameLength; + + while( lTotalFrameLen > 0 ) + { + // Ignoring this buffer. Mark it as free again. + uiTemp = xRxDescriptors[ ulNextRxBuffer ].addr; + xRxDescriptors[ ulNextRxBuffer ].addr = uiTemp & ~( AVR32_OWNERSHIP_BIT ); + + // Move on to the next buffer. + ulNextRxBuffer++; + ulNextRxBuffer = ulNextRxBuffer%ETHERNET_CONF_NB_RX_BUFFERS; + + lTotalFrameLen -= RX_BUFFER_SIZE; + } +} + + +/*-----------------------------------------------------------*/ +void vMACBSetMACAddress(const unsigned char *MACAddress) +{ + memcpy(cMACAddress, MACAddress, sizeof(cMACAddress)); +} + +Bool xMACBInit(volatile avr32_macb_t *macb) +{ + Bool global_interrupt_enabled = Is_global_interrupt_enabled(); + volatile unsigned long status; + + //vDisableMACBOperations(macb); + + // set up registers + macb->ncr = 0; + macb->tsr = ~0UL; + macb->rsr = ~0UL; + + if (global_interrupt_enabled) Disable_global_interrupt(); + macb->idr = ~0UL; + status = macb->isr; + if (global_interrupt_enabled) Enable_global_interrupt(); + + // RMII used, set 0 to the USRIO Register + macb->usrio &= ~AVR32_MACB_RMII_MASK; + + // Load our MAC address into the MACB. + prvSetupMACAddress(macb); + + // Setup the buffers and descriptors. + prvSetupDescriptors(macb); + +#if ETHERNET_CONF_SYSTEM_CLOCK <= 20000000 + macb->ncfgr |= (AVR32_MACB_NCFGR_CLK_DIV8 << AVR32_MACB_NCFGR_CLK_OFFSET); +#elif ETHERNET_CONF_SYSTEM_CLOCK <= 40000000 + macb->ncfgr |= (AVR32_MACB_NCFGR_CLK_DIV16 << AVR32_MACB_NCFGR_CLK_OFFSET); +#elif ETHERNET_CONF_SYSTEM_CLOCK <= 80000000 + macb->ncfgr |= AVR32_MACB_NCFGR_CLK_DIV32 << AVR32_MACB_NCFGR_CLK_OFFSET; +#elif ETHERNET_CONF_SYSTEM_CLOCK <= 160000000 + macb->ncfgr |= AVR32_MACB_NCFGR_CLK_DIV64 << AVR32_MACB_NCFGR_CLK_OFFSET; +#else +# error System clock too fast +#endif + + // Are we connected? + if( prvProbePHY(macb) == TRUE ) + { + // Enable the interrupt! + portENTER_CRITICAL(); + { + prvSetupMACBInterrupt(macb); + } + portEXIT_CRITICAL(); + // Enable Rx and Tx, plus the stats register. + macb->ncr = AVR32_MACB_NCR_TE_MASK | AVR32_MACB_NCR_RE_MASK; + return (TRUE); + } + return (FALSE); +} + +void vDisableMACBOperations (volatile avr32_macb_t *macb) +{ + Bool global_interrupt_enabled = Is_global_interrupt_enabled(); + + // write the MACB control register : disable Tx & Rx + macb->ncr &= ~((1 << AVR32_MACB_RE_OFFSET) | (1 << AVR32_MACB_TE_OFFSET)); + + // We no more want to interrupt on Rx and Tx events. + if (global_interrupt_enabled) Disable_global_interrupt(); + macb->idr = AVR32_MACB_IER_RCOMP_MASK | AVR32_MACB_IER_TCOMP_MASK; + macb->isr; + if (global_interrupt_enabled) Enable_global_interrupt(); +} + + +void vClearMACBTxBuffer(void) +{ + static unsigned long uxNextBufferToClear = 0; + + // Called on Tx interrupt events to set the AVR32_TRANSMIT_OK bit in each + // Tx buffer within the frame just transmitted. This marks all the buffers + // as available again. + + // The first buffer in the frame should have the bit set automatically. */ + if( xTxDescriptors[ uxNextBufferToClear ].U_Status.status & AVR32_TRANSMIT_OK ) + { + // Loop through the other buffers in the frame. + while( !( xTxDescriptors[ uxNextBufferToClear ].U_Status.status & AVR32_LAST_BUFFER ) ) + { + uxNextBufferToClear++; + + if( uxNextBufferToClear >= ETHERNET_CONF_NB_TX_BUFFERS ) + { + uxNextBufferToClear = 0; + } + + xTxDescriptors[ uxNextBufferToClear ].U_Status.status |= AVR32_TRANSMIT_OK; + } + + // Start with the next buffer the next time a Tx interrupt is called. + uxNextBufferToClear++; + + // Do we need to wrap back to the first buffer? + if( uxNextBufferToClear >= ETHERNET_CONF_NB_TX_BUFFERS ) + { + uxNextBufferToClear = 0; + } + } +} + +static void prvSetupDescriptors(volatile avr32_macb_t *macb) +{ + unsigned long xIndex; + unsigned long ulAddress; + + // Initialise xRxDescriptors descriptor. + for( xIndex = 0; xIndex < ETHERNET_CONF_NB_RX_BUFFERS; ++xIndex ) + { + // Calculate the address of the nth buffer within the array. + ulAddress = ( unsigned long )( pcRxBuffer + ( xIndex * RX_BUFFER_SIZE ) ); + + // Write the buffer address into the descriptor. + // The DMA will place the data at this address when this descriptor is being used. + // No need to mask off the bottom bits of the address (these have special meaning + // for the MACB) because pcRxBuffer is 4Bytes-aligned. + xRxDescriptors[ xIndex ].addr = ulAddress; + } + + // The last buffer has the wrap bit set so the MACB knows to wrap back + // to the first buffer. + xRxDescriptors[ ETHERNET_CONF_NB_RX_BUFFERS - 1 ].addr |= RX_WRAP_BIT; + + // Initialise xTxDescriptors. + for( xIndex = 0; xIndex < ETHERNET_CONF_NB_TX_BUFFERS; ++xIndex ) + { + // Calculate the address of the nth buffer within the array. + ulAddress = ( unsigned long )( pcTxBuffer + ( xIndex * ETHERNET_CONF_TX_BUFFER_SIZE ) ); + + // Write the buffer address into the descriptor. + // The DMA will read data from here when the descriptor is being used. + xTxDescriptors[ xIndex ].addr = ulAddress; + xTxDescriptors[ xIndex ].U_Status.status = AVR32_TRANSMIT_OK; + } + + // The last buffer has the wrap bit set so the MACB knows to wrap back + // to the first buffer. + xTxDescriptors[ ETHERNET_CONF_NB_TX_BUFFERS - 1 ].U_Status.status = AVR32_TRANSMIT_WRAP | AVR32_TRANSMIT_OK; + + // Tell the MACB where to find the descriptors. + macb->rbqp = ( unsigned long )xRxDescriptors; + macb->tbqp = ( unsigned long )xTxDescriptors; + + // Do not copy the FCS field of received frames to memory. + macb->ncfgr |= ( AVR32_MACB_NCFGR_DRFCS_MASK ); + +} + +//! +//! \brief Restore ownership of all Rx buffers to the MACB. +//! +static void vResetMacbRxFrames( void ) +{ + register unsigned long ulIndex; + unsigned int uiTemp; + + + // Disable MACB frame reception. + AVR32_MACB.ncr &= ~(AVR32_MACB_NCR_RE_MASK); + + // Restore ownership of all Rx buffers to the MACB. + for( ulIndex = 0; ulIndex < ETHERNET_CONF_NB_RX_BUFFERS; ++ulIndex ) + { + // Mark the buffer as owned by the MACB. + uiTemp = xRxDescriptors[ ulIndex ].addr; + xRxDescriptors[ ulIndex ].addr = uiTemp & ~( AVR32_OWNERSHIP_BIT ); + } + + // Reset the Buffer-not-available bit and the overrun bit. + AVR32_MACB.rsr = AVR32_MACB_RSR_BNA_MASK | AVR32_MACB_RSR_OVR_MASK; // Clear + AVR32_MACB.rsr; // We read to force the previous operation. + + // Reset the MACB starting point. + AVR32_MACB.rbqp = ( unsigned long )xRxDescriptors; + + // Reset the index to the next buffer from which data will be read. + ulNextRxBuffer = 0; + + // Enable MACB frame reception. + AVR32_MACB.ncr |= AVR32_MACB_NCR_RE_MASK; +} + + +static void prvSetupMACAddress(volatile avr32_macb_t *macb) +{ + // Must be written SA1L then SA1H. + macb->sa1b = ( ( unsigned long ) cMACAddress[ 3 ] << 24 ) | + ( ( unsigned long ) cMACAddress[ 2 ] << 16 ) | + ( ( unsigned long ) cMACAddress[ 1 ] << 8 ) | + cMACAddress[ 0 ]; + + macb->sa1t = ( ( unsigned long ) cMACAddress[ 5 ] << 8 ) | + cMACAddress[ 4 ]; +} + +static void prvSetupMACBInterrupt(volatile avr32_macb_t *macb) +{ + + // Setup the interrupt for MACB. + // Register the interrupt handler to the interrupt controller at interrupt level 2 + INTC_register_interrupt((__int_handler)&vMACB_ISR, AVR32_MACB_IRQ, AVR32_INTC_INT2); + + // We want to interrupt on Rx and Tx events + macb->ier = AVR32_MACB_IER_RCOMP_MASK | AVR32_MACB_IER_TCOMP_MASK ; +} + +/*! Read a register on MDIO bus (access to the PHY) + * This function is looping until PHY gets ready + * + * \param macb Input. instance of the MACB to use + * \param usAddress Input. register to set. + * + * \return unsigned long data that has been read + */ +static unsigned long ulReadMDIO(volatile avr32_macb_t *macb, unsigned short usAddress) +{ + unsigned long value, status; + u16 timeout = 0; + + // initiate transaction : enable management port + macb->ncr |= AVR32_MACB_NCR_MPE_MASK; + // Write the PHY configuration frame to the MAN register + macb->man = (AVR32_MACB_SOF_MASK & (0x01<nsr; + } while (!(status & AVR32_MACB_NSR_IDLE_MASK) && (timeout++ < TIMEOUT)); + // read the register value in maintenance register + value = macb->man & 0x0000ffff; + // disable management port + macb->ncr &= ~AVR32_MACB_NCR_MPE_MASK; + // return the read value + return (value); +} + +/*! Write a given value to a register on MDIO bus (access to the PHY) + * This function is looping until PHY gets ready + * + * \param *macb Input. instance of the MACB to use + * \param usAddress Input. register to set. + * \param usValue Input. value to write. + * + */ +static void vWriteMDIO(volatile avr32_macb_t *macb, unsigned short usAddress, unsigned short usValue) +{ + unsigned long status; + u16 timeout = 0; + + // initiate transaction : enable management port + macb->ncr |= AVR32_MACB_NCR_MPE_MASK; + // Write the PHY configuration frame to the MAN register + macb->man = (( AVR32_MACB_SOF_MASK & (0x01<nsr; + } while (!(status & AVR32_MACB_NSR_IDLE_MASK) && (timeout++ < TIMEOUT)); + // disable management port + macb->ncr &= ~AVR32_MACB_NCR_MPE_MASK; +} + +static Bool prvProbePHY(volatile avr32_macb_t *macb) +{ + volatile unsigned long mii_status, phy_ctrl; + volatile unsigned long config; + unsigned long upper, lower, mode, advertise, lpa; + volatile unsigned long physID; + + // Read Phy Identifier register 1 & 2 + lower = ulReadMDIO(macb, PHY_PHYSID2); + upper = ulReadMDIO(macb, PHY_PHYSID1); + // get Phy ID, ignore Revision + physID = ((upper << 16) & 0xFFFF0000) | (lower & 0xFFF0); + // check if it match config + if (physID == ETHERNET_CONF_PHY_ID) + { + // read RBR + mode = ulReadMDIO(macb, PHY_RBR); + // set RMII mode if not done + if ((mode & RBR_RMII) != RBR_RMII) + { + // force RMII flag if strap options are wrong + mode |= RBR_RMII; + vWriteMDIO(macb, PHY_RBR, mode); + } + + advertise = ADVERTISE_CSMA | ADVERTISE_ALL; + // write advertise register + vWriteMDIO(macb, PHY_ADVERTISE, advertise); + // read Control register + config = ulReadMDIO(macb, PHY_BMCR); + // read Phy Control register + phy_ctrl = ulReadMDIO(macb, PHY_PHYCR); + // enable Auto MDIX + phy_ctrl |= PHYCR_MDIX_EN; + // reset auto-negociation capability + config |= (BMCR_ANRESTART | BMCR_ANENABLE); + // update Phy ctrl register + vWriteMDIO(macb, PHY_PHYCR, phy_ctrl); + + // update ctrl register + vWriteMDIO(macb, PHY_BMCR, config); + + // loop while link status isn't OK + do { + mii_status = ulReadMDIO(macb, PHY_BMSR); + } while (!(mii_status & BMSR_LSTATUS)); + + // read the LPA configuration of the PHY + lpa = ulReadMDIO(macb, PHY_LPA); + + // read the MACB config register + config = AVR32_MACB.ncfgr; + + // if 100MB needed + if ((lpa & advertise) & (LPA_100HALF | LPA_100FULL)) + config |= AVR32_MACB_SPD_MASK; + else + config &= ~(AVR32_MACB_SPD_MASK); + + // if FULL DUPLEX needed + if ((lpa & advertise) & (LPA_10FULL | LPA_100FULL)) + config |= AVR32_MACB_FD_MASK; + else + config &= ~(AVR32_MACB_FD_MASK); + + // write the MACB config register + macb->ncfgr = config; + + return TRUE; + } + return FALSE; +} + +/* + * The MACB ISR. Handles both Tx and Rx complete interrupts. + */ +__attribute__((__interrupt__)) void vMACB_ISR(void) +{ + // Variable definitions can be made now. + volatile unsigned long ulIntStatus, ulEventStatus; + + // Find the cause of the interrupt. + ulIntStatus = AVR32_MACB.isr; + ulEventStatus = AVR32_MACB.rsr; + + if( ( ulIntStatus & AVR32_MACB_IDR_RCOMP_MASK ) || ( ulEventStatus & AVR32_MACB_REC_MASK ) ) + { + // A frame has been received, signal the IP task so it can process + // the Rx descriptors. + elua_uip_mainloop(); + AVR32_MACB.rsr = AVR32_MACB_REC_MASK; // Clear + AVR32_MACB.rsr; // Read to force the previous write + } + + if( ulIntStatus & AVR32_MACB_TCOMP_MASK ) + { + // A frame has been transmitted. Mark all the buffers used by the + // frame just transmitted as free again. + vClearMACBTxBuffer(); + AVR32_MACB.tsr = AVR32_MACB_TSR_COMP_MASK; // Clear + AVR32_MACB.tsr; // Read to force the previous write + } +} +#endif diff --git a/src/platform/avr32/ethernet.h b/src/platform/avr32/ethernet.h new file mode 100644 index 00000000..7eeab831 --- /dev/null +++ b/src/platform/avr32/ethernet.h @@ -0,0 +1,492 @@ +/* This header file is part of the ATMEL AVR32-UC3-SoftwareFramework-1.6.0 Release */ + +/*This file has been prepared for Doxygen automatic documentation generation.*/ +/*! \file ********************************************************************* + * + * \brief MACB driver. + * + * This file defines a useful set of functions for the MACB interface on + * AVR32 devices. + * + * - Compiler: IAR EWAVR32 and GNU GCC for AVR32 + * - Supported devices: All AVR32 devices with a MACB module can be used. + * - AppNote: + * + * \author Atmel Corporation: http://www.atmel.com \n + * Support and FAQ: http://support.atmel.no/ + * + *****************************************************************************/ + +/* Copyright (c) 2009 Atmel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an Atmel + * AVR product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE + * + */ + +#ifndef AVR32_ETHERNET_H +#define AVR32_ETHERNET_H + +#include + +#include "compiler.h" + + +/*! \name Rx Ring descriptor flags + */ +//! @{ +#define AVR32_MACB_RX_USED_OFFSET 0 +#define AVR32_MACB_RX_USED_SIZE 1 +#define AVR32_MACB_RX_WRAP_OFFSET 1 +#define AVR32_MACB_RX_WRAP_SIZE 1 +#define AVR32_MACB_RX_LEN_OFFSET 0 +#define AVR32_MACB_RX_LEN_SIZE 12 +#define AVR32_MACB_RX_OFFSET_OFFSET 12 +#define AVR32_MACB_RX_OFFSET_SIZE 2 +#define AVR32_MACB_RX_SOF_OFFSET 14 +#define AVR32_MACB_RX_SOF_SIZE 1 +#define AVR32_MACB_RX_EOF_OFFSET 15 +#define AVR32_MACB_RX_EOF_SIZE 1 +#define AVR32_MACB_RX_CFI_OFFSET 16 +#define AVR32_MACB_RX_CFI_SIZE 1 +//! @} + +/*! \name Tx Ring descriptor flags + */ +//! @{ +#define AVR32_MACB_TX_LEN_OFFSET 0 +#define AVR32_MACB_TX_LEN_SIZE 11 +#define AVR32_MACB_TX_EOF_OFFSET 15 +#define AVR32_MACB_TX_EOF_SIZE 1 +#define AVR32_MACB_TX_NOCRC_OFFSET 16 +#define AVR32_MACB_TX_NOCRC_SIZE 1 +#define AVR32_MACB_TX_EMF_OFFSET 27 +#define AVR32_MACB_TX_EMF_SIZE 1 +#define AVR32_MACB_TX_UNR_OFFSET 28 +#define AVR32_MACB_TX_UNR_SIZE 1 +#define AVR32_MACB_TX_MAXRETRY_OFFSET 29 +#define AVR32_MACB_TX_MAXRETRY_SIZE 1 +#define AVR32_MACB_TX_WRAP_OFFSET 30 +#define AVR32_MACB_TX_WRAP_SIZE 1 +#define AVR32_MACB_TX_USED_OFFSET 31 +#define AVR32_MACB_TX_USED_SIZE 1 +//! @} + +/*! \name Generic MII registers. + */ +//! @{ +#define PHY_BMCR 0x00 //!< Basic mode control register +#define PHY_BMSR 0x01 //!< Basic mode status register +#define PHY_PHYSID1 0x02 //!< PHYS ID 1 +#define PHY_PHYSID2 0x03 //!< PHYS ID 2 +#define PHY_ADVERTISE 0x04 //!< Advertisement control reg +#define PHY_LPA 0x05 //!< Link partner ability reg +//! @} + + +#define PHY_RBR 0x17 //!< RMII Bypass reg +#define PHY_MICR 0x11 //!< Interrupt Control reg +#define PHY_MISR 0x12 //!< Interrupt Status reg +#define PHY_PHYCR 0x19 //!< Phy CTRL reg + +/*! \name Basic mode control register. + */ +//! @{ +#define BMCR_RESV 0x007f //!< Unused... +#define BMCR_CTST 0x0080 //!< Collision test +#define BMCR_FULLDPLX 0x0100 //!< Full duplex +#define BMCR_ANRESTART 0x0200 //!< Auto negotiation restart +#define BMCR_ISOLATE 0x0400 //!< Disconnect PHY from MII +#define BMCR_PDOWN 0x0800 //!< Powerdown the PHY +#define BMCR_ANENABLE 0x1000 //!< Enable auto negotiation +#define BMCR_SPEED100 0x2000 //!< Select 100Mbps +#define BMCR_LOOPBACK 0x4000 //!< TXD loopback bits +#define BMCR_RESET 0x8000 //!< Reset the PHY +//! @} + +/*! \name Basic mode status register. + */ +//! @{ +#define BMSR_ERCAP 0x0001 //!< Ext-reg capability +#define BMSR_JCD 0x0002 //!< Jabber detected +#define BMSR_LSTATUS 0x0004 //!< Link status +#define BMSR_ANEGCAPABLE 0x0008 //!< Able to do auto-negotiation +#define BMSR_RFAULT 0x0010 //!< Remote fault detected +#define BMSR_ANEGCOMPLETE 0x0020 //!< Auto-negotiation complete +#define BMSR_RESV 0x00c0 //!< Unused... +#define BMSR_ESTATEN 0x0100 //!< Extended Status in R15 +#define BMSR_100FULL2 0x0200 //!< Can do 100BASE-T2 HDX +#define BMSR_100HALF2 0x0400 //!< Can do 100BASE-T2 FDX +#define BMSR_10HALF 0x0800 //!< Can do 10mbps, half-duplex +#define BMSR_10FULL 0x1000 //!< Can do 10mbps, full-duplex +#define BMSR_100HALF 0x2000 //!< Can do 100mbps, half-duplex +#define BMSR_100FULL 0x4000 //!< Can do 100mbps, full-duplex +#define BMSR_100BASE4 0x8000 //!< Can do 100mbps, 4k packets +//! @} + +/*! \name Advertisement control register. + */ +//! @{ +#define ADVERTISE_SLCT 0x001f //!< Selector bits +#define ADVERTISE_CSMA 0x0001 //!< Only selector supported +#define ADVERTISE_10HALF 0x0020 //!< Try for 10mbps half-duplex +#define ADVERTISE_1000XFULL 0x0020 //!< Try for 1000BASE-X full-duplex +#define ADVERTISE_10FULL 0x0040 //!< Try for 10mbps full-duplex +#define ADVERTISE_1000XHALF 0x0040 //!< Try for 1000BASE-X half-duplex +#define ADVERTISE_100HALF 0x0080 //!< Try for 100mbps half-duplex +#define ADVERTISE_1000XPAUSE 0x0080 //!< Try for 1000BASE-X pause +#define ADVERTISE_100FULL 0x0100 //!< Try for 100mbps full-duplex +#define ADVERTISE_1000XPSE_ASYM 0x0100 //!< Try for 1000BASE-X asym pause +#define ADVERTISE_100BASE4 0x0200 //!< Try for 100mbps 4k packets +#define ADVERTISE_PAUSE_CAP 0x0400 //!< Try for pause +#define ADVERTISE_PAUSE_ASYM 0x0800 //!< Try for asymetric pause +#define ADVERTISE_RESV 0x1000 //!< Unused... +#define ADVERTISE_RFAULT 0x2000 //!< Say we can detect faults +#define ADVERTISE_LPACK 0x4000 //!< Ack link partners response +#define ADVERTISE_NPAGE 0x8000 //!< Next page bit +//! @} + +#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | ADVERTISE_CSMA) +#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \ + ADVERTISE_100HALF | ADVERTISE_100FULL) + +/*! \name Link partner ability register. + */ +//! @{ +#define LPA_SLCT 0x001f //!< Same as advertise selector +#define LPA_10HALF 0x0020 //!< Can do 10mbps half-duplex +#define LPA_1000XFULL 0x0020 //!< Can do 1000BASE-X full-duplex +#define LPA_10FULL 0x0040 //!< Can do 10mbps full-duplex +#define LPA_1000XHALF 0x0040 //!< Can do 1000BASE-X half-duplex +#define LPA_100HALF 0x0080 //!< Can do 100mbps half-duplex +#define LPA_1000XPAUSE 0x0080 //!< Can do 1000BASE-X pause +#define LPA_100FULL 0x0100 //!< Can do 100mbps full-duplex +#define LPA_1000XPAUSE_ASYM 0x0100 //!< Can do 1000BASE-X pause asym +#define LPA_100BASE4 0x0200 //!< Can do 100mbps 4k packets +#define LPA_PAUSE_CAP 0x0400 //!< Can pause +#define LPA_PAUSE_ASYM 0x0800 //!< Can pause asymetrically +#define LPA_RESV 0x1000 //!< Unused... +#define LPA_RFAULT 0x2000 //!< Link partner faulted +#define LPA_LPACK 0x4000 //!< Link partner acked us +#define LPA_NPAGE 0x8000 //!< Next page bit + +#define LPA_DUPLEX (LPA_10FULL | LPA_100FULL) +#define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4) +//! @} + + +/*! RMII Bypass Register */ +#define RBR_RMII 0x0020 //!< RMII Mode +/*! \name Interrupt Ctrl Register. + */ +//! @{ +#define MICR_INTEN 0x0002 //!< Enable interrupts +#define MICR_INTOE 0x0001 //!< Enable INT output +//! @} + +/*! \name Interrupt Status Register. + */ +//! @{ +#define MISR_ED_INT_EN 0x0040 //!< Energy Detect enabled +#define MISR_LINK_INT_EN 0x0020 //!< Link status change enabled +#define MISR_SPD_INT_EN 0x0010 //!< Speed change enabled +#define MISR_DP_INT_EN 0x0008 //!< Duplex mode change enabled +#define MISR_ANC_INT_EN 0x0004 //!< Auto-Neg complete enabled +#define MISR_FHF_INT_EN 0x0002 //!< False Carrier enabled +#define MISR_RHF_INT_EN 0x0001 //!< Receive Error enabled +#define MISR_ED_INT 0x4000 //!< Energy Detect +#define MISR_LINK_INT 0x2000 //!< Link status change +#define MISR_SPD_INT 0x1000 //!< Speed change +#define MISR_DP_INT 0x0800 //!< Duplex mode change +#define MISR_ANC_INT 0x0400 //!< Auto-Neg complete +#define MISR_FHF_INT 0x0200 //!< False Carrier +#define MISR_RHF_INT 0x0100 //!< Receive Error +//! @} + +/*! \name Phy Ctrl Register. + */ +//! @{ +#define PHYCR_MDIX_EN 0x8000 //!< Enable Auto MDIX +#define PHYCR_MDIX_FORCE 0x4000 //!< Force MDIX crossed +//! @} + +/* Size of each receive buffer - DO NOT CHANGE. */ +#define RX_BUFFER_SIZE 128 + + +/* The buffer addresses written into the descriptors must be aligned so the +last two bits are zero. These bits have special meaning for the MACB +peripheral and cannot be used as part of the address. */ +#define ADDRESS_MASK ( ( unsigned long ) 0xFFFFFFFC ) + +/* Bit used within the address stored in the descriptor to mark the last +descriptor in the array. */ +#define RX_WRAP_BIT ( ( unsigned long ) 0x02 ) + +/* A short delay is used to wait for a buffer to become available, should +one not be immediately available when trying to transmit a frame. */ +#define BUFFER_WAIT_DELAY ( 2 ) + + +/*! location of net config file on the file system */ +#define ETHERNET_CONFIG_FILE "A:/CFG/net.txt" + +/*! Phy Address (set through strap options) */ +#define ETHERNET_CONF_PHY_ADDR 0x01 +#define ETHERNET_CONF_PHY_ID 0x20005C90 + +/*! Number of receive buffers. Max ethernet frame size is 1526. A Rx buffer is +128 Bytes long. So 12 Rx buffers are necessary to store one max sized frame. +Multiply that by 2 for performance. */ +#define ETHERNET_CONF_NB_RX_BUFFERS 24 + +/*! USE_RMII_INTERFACE must be defined as 1 to use an RMII interface, or 0 +to use an MII interface. */ +#define ETHERNET_CONF_USE_RMII_INTERFACE 1 + +/*! Number of Transmit buffers */ +#define ETHERNET_CONF_NB_TX_BUFFERS 10 + +/*! Size of each Transmit buffer. */ +#define ETHERNET_CONF_TX_BUFFER_SIZE 512 + +/*! Clock definition */ +#define ETHERNET_CONF_SYSTEM_CLOCK 60000000 + +/*! Allow Auto Negociation */ +#define ETHERNET_CONF_AN_ENABLE 1 + +/*! Use auto cross capability. Used by default. */ +#define ETHERNET_CONF_AUTO_CROSS_ENABLE 1 +/*! Use direct cable. Ignored when ETHERNET_CONF_AN_ENABLE and + ETHERNET_CONF_AUTO_CROSS_ENABLE are enabled. */ +#define ETHERNET_CONF_CROSSED_LINK 0 + +/* ethernet default parameters */ +/*! MAC address definition. The MAC address must be unique on the network. */ +#define ETHERNET_CONF_ETHADDR0 0x00 +#define ETHERNET_CONF_ETHADDR1 0x04 +#define ETHERNET_CONF_ETHADDR2 0x25 +#define ETHERNET_CONF_ETHADDR3 0x00 +#define ETHERNET_CONF_ETHADDR4 0x01 +#define ETHERNET_CONF_ETHADDR5 0x02 + + + +/*! set to 1 if Phy status changes handle an interrupt */ +#define ETHERNET_CONF_USE_PHY_IT 0 + + +/*! Packet structure. + */ +//! @{ +typedef struct +{ + unsigned char *data; + unsigned int len; +} macb_packet_t; +//! @} + +/*! Receive Transfer descriptor structure. + */ +//! @{ +typedef struct _AVR32_RxTdDescriptor { + unsigned int addr; + union + { + unsigned int status; + struct { + unsigned int BroadCast:1; + unsigned int MultiCast:1; + unsigned int UniCast:1; + unsigned int ExternalAdd:1; + unsigned int Res1:1; + unsigned int Sa1Match:1; + unsigned int Sa2Match:1; + unsigned int Sa3Match:1; + unsigned int Sa4Match:1; + unsigned int TypeID:1; + unsigned int VlanTag:1; + unsigned int PriorityTag:1; + unsigned int VlanPriority:3; + unsigned int Cfi:1; + unsigned int EndOfFrame:1; + unsigned int StartOfFrame:1; + unsigned int Rxbuf_off:2; + unsigned int Res0:1; + unsigned int Length:11; + }S_Status; + }U_Status; +}AVR32_RxTdDescriptor, *AVR32P_RxTdDescriptor; +//! @} + +/*! Transmit Transfer descriptor structure. + */ +//! @{ +typedef struct _AVR32_TxTdDescriptor { + unsigned int addr; + union + { + unsigned int status; + struct { + unsigned int BuffUsed:1; + unsigned int Wrap:1; + unsigned int TransmitError:1; + unsigned int TransmitUnderrun:1; + unsigned int BufExhausted:1; + unsigned int Res1:10; + unsigned int NoCrc:1; + unsigned int LastBuff:1; + unsigned int Res0:4; + unsigned int Length:11; + }S_Status; + }U_Status; +}AVR32_TxTdDescriptor, *AVR32P_TxTdDescriptor; +//! @} + + +/*! Mask for frame used. */ +#define AVR32_OWNERSHIP_BIT 0x00000001 + +/*! Receive status defintion. + */ +//! @{ +#define AVR32_BROADCAST_ADDR ((unsigned int) (1 << 31)) //* Broadcat address detected +#define AVR32_MULTICAST_HASH ((unsigned int) (1 << 30)) //* MultiCast hash match +#define AVR32_UNICAST_HASH ((unsigned int) (1 << 29)) //* UniCast hash match +#define AVR32_EXTERNAL_ADDR ((unsigned int) (1 << 28)) //* External Address match +#define AVR32_SA1_ADDR ((unsigned int) (1 << 26)) //* Specific address 1 match +#define AVR32_SA2_ADDR ((unsigned int) (1 << 25)) //* Specific address 2 match +#define AVR32_SA3_ADDR ((unsigned int) (1 << 24)) //* Specific address 3 match +#define AVR32_SA4_ADDR ((unsigned int) (1 << 23)) //* Specific address 4 match +#define AVR32_TYPE_ID ((unsigned int) (1 << 22)) //* Type ID match +#define AVR32_VLAN_TAG ((unsigned int) (1 << 21)) //* VLAN tag detected +#define AVR32_PRIORITY_TAG ((unsigned int) (1 << 20)) //* PRIORITY tag detected +#define AVR32_VLAN_PRIORITY ((unsigned int) (7 << 17)) //* PRIORITY Mask +#define AVR32_CFI_IND ((unsigned int) (1 << 16)) //* CFI indicator +#define AVR32_EOF ((unsigned int) (1 << 15)) //* EOF +#define AVR32_SOF ((unsigned int) (1 << 14)) //* SOF +#define AVR32_RBF_OFFSET ((unsigned int) (3 << 12)) //* Receive Buffer Offset Mask +#define AVR32_LENGTH_FRAME ((unsigned int) 0x0FFF) //* Length of frame +//! @} + +/* Transmit Status definition */ +//! @{ +#define AVR32_TRANSMIT_OK ((unsigned int) (1 << 31)) //* +#define AVR32_TRANSMIT_WRAP ((unsigned int) (1 << 30)) //* Wrap bit: mark the last descriptor +#define AVR32_TRANSMIT_ERR ((unsigned int) (1 << 29)) //* RLE:transmit error +#define AVR32_TRANSMIT_UND ((unsigned int) (1 << 28)) //* Transmit Underrun +#define AVR32_BUF_EX ((unsigned int) (1 << 27)) //* Buffers exhausted in mid frame +#define AVR32_TRANSMIT_NO_CRC ((unsigned int) (1 << 16)) //* No CRC will be appended to the current frame +#define AVR32_LAST_BUFFER ((unsigned int) (1 << 15)) //* +//! @} + + +/** + * \brief Initialise the MACB driver. + * + * \param *macb Base address of the MACB + * + * \return TRUE if success, FALSE otherwise. + */ +extern Bool xMACBInit(volatile avr32_macb_t *macb); + +/** + * \brief Send ulLength bytes from pcFrom. This copies the buffer to one of the + * MACB Tx buffers, then indicates to the MACB that the buffer is ready. + * If lEndOfFrame is true then the data being copied is the end of the frame + * and the frame can be transmitted. + * + * \param *macb Base address of the MACB + * \param *pvFrom Address of the data buffer + * \param ulLength Length of the frame + * \param lEndOfFrame Flag for End Of Frame + * + * \return length sent. + */ +extern long lMACBSend(volatile avr32_macb_t *macb, const void *pvFrom, unsigned long ulLength, long lEndOfFrame); + +/** + * \brief Frames can be read from the MACB in multiple sections. + * Read ulSectionLength bytes from the MACB receive buffers to pcTo. + * ulTotalFrameLength is the size of the entire frame. Generally vMACBRead + * will be repetedly called until the sum of all the ulSectionLenths totals + * the value of ulTotalFrameLength. + * + * \param *pvTo Address of the buffer + * \param ulSectionLength Length of the buffer + * \param ulTotalFrameLength Length of the frame + */ +extern void vMACBRead(void *pvTo, unsigned long ulSectionLength, unsigned long ulTotalFrameLength); + +/** + * \brief Flush the current received packet. + * + * \param ulTotalFrameLength Length of the packet to flush + */ +extern void vMACBFlushCurrentPacket(unsigned long ulTotalFrameLength); + +/** + * \brief Called by the Tx interrupt, this function traverses the buffers used to + * hold the frame that has just completed transmission and marks each as + * free again. + */ +extern void vClearMACBTxBuffer(void); + +/** + * \brief Suspend on a semaphore waiting either for the semaphore to be obtained + * or a timeout. The semaphore is used by the MACB ISR to indicate that + * data has been received and is ready for processing. + * + * \param ulTimeOut time to wait for an input + * + */ +extern void vMACBWaitForInput(unsigned long ulTimeOut); + +/** + * \brief Function to get length of the next frame in the receive buffers + * + * \return the length of the next frame in the receive buffers. + */ +extern unsigned long ulMACBInputLength(void); + +/** + * \brief Set the MACB Physical address (SA1B & SA1T registers). + * + * \param *MACAddress the MAC address to set. + */ +extern void vMACBSetMACAddress(const unsigned char *MACAddress); + +/** + * \brief Disable MACB operations (Tx and Rx). + * + * \param *macb Base address of the MACB + */ +extern void vDisableMACBOperations(volatile avr32_macb_t *macb); + + +#endif diff --git a/src/platform/avr32/platform.c b/src/platform/avr32/platform.c index 67a63ffa..8832d72b 100644 --- a/src/platform/avr32/platform.c +++ b/src/platform/avr32/platform.c @@ -15,6 +15,17 @@ #include "platform_conf.h" #include "common.h" #include "buf.h" +#include "spi.h" +#ifdef BUILD_MMCFS +#include "diskio.h" +#endif + +#ifdef BUILD_UIP +#include "ethernet.h" +#include "uip_arp.h" +#include "elua_uip.h" +#include "uip-conf.h" +#endif // Platform-specific includes #include @@ -30,8 +41,21 @@ #include "adc.h" #include "pwm.h" +// UIP sys tick data +// NOTE: when using virtual timers, SYSTICKHZ and VTMR_FREQ_HZ should have the +// same value, as they're served by the same timer (the systick) +#define SYSTICKHZ 4 +#define SYSTICKMS (1000 / SYSTICKHZ) + +#ifdef BUILD_UIP +static int eth_timer_fired; +#endif + // **************************************************************************** // Platform initialization +#ifdef BUILD_UIP +u32 platform_ethernet_setup(void); +#endif extern int pm_configure_clocks( pm_freq_param_t *param ); @@ -51,7 +75,20 @@ __attribute__((__interrupt__)) static void tmr_int_handler() tc_read_sr( tc, VTMR_CH ); cmn_virtual_timer_cb(); -} + +#ifdef BUILD_MMCFS + disk_timerproc(); +#endif + +#ifdef BUILD_UIP + // Indicate that a SysTick interrupt has occurred. + eth_timer_fired = 1; + + // Generate a fake Ethernet interrupt. This will perform the actual work + // of incrementing the timers and taking the appropriate actions. + platform_eth_force_interrupt(); +#endif +} #endif const u32 uart_base_addr[ ] = { @@ -188,6 +225,11 @@ int platform_init() pwm_init(); #endif + +#ifdef BUILD_UIP + platform_ethernet_setup(); +#endif + #ifdef ELUA_BOARD_MIZAR32 // If BUF_ENABLE_UART is enabled on Mizar32 (which it is by default) but the // serial board is not plugged in, we get an infinite number of interrupts @@ -814,7 +856,6 @@ int platform_adc_start_sequence( ) #endif - // **************************************************************************** // PWM functions @@ -964,3 +1005,87 @@ u32 platform_pwm_op( unsigned id, int op, u32 data) } return 0; } + +// **************************************************************************** +// Network support + +#ifdef BUILD_UIP +static const gpio_map_t MACB_GPIO_MAP = +{ + {AVR32_MACB_MDC_0_PIN, AVR32_MACB_MDC_0_FUNCTION }, + {AVR32_MACB_MDIO_0_PIN, AVR32_MACB_MDIO_0_FUNCTION }, + {AVR32_MACB_RXD_0_PIN, AVR32_MACB_RXD_0_FUNCTION }, + {AVR32_MACB_TXD_0_PIN, AVR32_MACB_TXD_0_FUNCTION }, + {AVR32_MACB_RXD_1_PIN, AVR32_MACB_RXD_1_FUNCTION }, + {AVR32_MACB_TXD_1_PIN, AVR32_MACB_TXD_1_FUNCTION }, + {AVR32_MACB_TX_EN_0_PIN, AVR32_MACB_TX_EN_0_FUNCTION }, + {AVR32_MACB_RX_ER_0_PIN, AVR32_MACB_RX_ER_0_FUNCTION }, + {AVR32_MACB_RX_DV_0_PIN, AVR32_MACB_RX_DV_0_FUNCTION }, + {AVR32_MACB_TX_CLK_0_PIN, AVR32_MACB_TX_CLK_0_FUNCTION} +}; + +u32 platform_ethernet_setup() +{ + static struct uip_eth_addr sTempAddr; + // Assign GPIO to MACB + gpio_enable_module(MACB_GPIO_MAP, sizeof(MACB_GPIO_MAP) / sizeof(MACB_GPIO_MAP[0])); + + // initialize MACB & Phy Layers + if (xMACBInit(&AVR32_MACB) == FALSE ) { + return PLATFORM_ERR; + } + + sTempAddr.addr[0] = ETHERNET_CONF_ETHADDR0; + sTempAddr.addr[1] = ETHERNET_CONF_ETHADDR1; + sTempAddr.addr[2] = ETHERNET_CONF_ETHADDR2; + sTempAddr.addr[3] = ETHERNET_CONF_ETHADDR3; + sTempAddr.addr[4] = ETHERNET_CONF_ETHADDR4; + sTempAddr.addr[5] = ETHERNET_CONF_ETHADDR5; + + // Initialize the eLua uIP layer + elua_uip_init( &sTempAddr ); + return PLATFORM_OK; +} + +void platform_eth_send_packet( const void* src, u32 size ) +{ + lMACBSend(&AVR32_MACB,src, size, TRUE); +} + +u32 platform_eth_get_packet_nb( void* buf, u32 maxlen ) +{ + u32 len; + + /* Obtain the size of the packet. */ + len = ulMACBInputLength(); + + if (len > maxlen) { + return 0; + } + + if( len ) { + /* Let the driver know we are going to read a new packet. */ + vMACBRead( NULL, 0, len ); + vMACBRead( buf, len, len ); + } + + return len; +} + +void platform_eth_force_interrupt() +{ + elua_uip_mainloop(); +} + +u32 platform_eth_get_elapsed_time() +{ + if( eth_timer_fired ) + { + eth_timer_fired = 0; + return SYSTICKMS; + } + else + return 0; +} + +#endif diff --git a/src/platform/avr32/uip-conf.h b/src/platform/avr32/uip-conf.h new file mode 100644 index 00000000..f453d044 --- /dev/null +++ b/src/platform/avr32/uip-conf.h @@ -0,0 +1,137 @@ +//***************************************************************************** +// +// uip-conf.h - uIP Project Specific Configuration File +// +//***************************************************************************** + +#ifndef __UIP_AVR32_CONF_H__ +#define __UIP_AVR32_CONF_H__ + +#include "platform_conf.h" + +// +// 8 bit datatype +// This typedef defines the 8-bit type used throughout uIP. +// +typedef unsigned char u8_t; + +// +// 16 bit datatype +// This typedef defines the 16-bit type used throughout uIP. +// +typedef unsigned short u16_t; + +// +// Statistics datatype +// This typedef defines the dataype used for keeping statistics in +// uIP. +// +typedef unsigned short uip_stats_t; + +// +// Ping IP address assignment +// Use first incoming "ping" packet to derive host IP address +// +#define UIP_CONF_PINGADDRCONF 0 + +// +// TCP support on or off +// +#define UIP_CONF_TCP 1 + +// +// UDP support on or off +// +#define UIP_CONF_UDP 1 + +// +// UDP checksums on or off +// (not currently supported ... should be 0) +// +#define UIP_CONF_UDP_CHECKSUMS 1 + +// +// UDP Maximum Connections +// +#define UIP_CONF_UDP_CONNS 4 + +// +// Maximum number of TCP connections. +// +#define UIP_CONF_MAX_CONNECTIONS 4 + +// +// Maximum number of listening TCP ports. +// +#define UIP_CONF_MAX_LISTENPORTS 4 + +// +// Size of advertised receiver's window +// +//#define UIP_CONF_RECEIVE_WINDOW 400 + +// +// Size of ARP table +// +#define UIP_CONF_ARPTAB_SIZE 4 + +// +// uIP buffer size. +// +#define UIP_CONF_BUFFER_SIZE 1024 + +// +// uIP statistics on or off +// +#define UIP_CONF_STATISTICS 0 + +// +// Logging on or off +// +#define UIP_CONF_LOGGING 0 + +// +// Broadcast Support +// +#define UIP_CONF_BROADCAST 1 + +// +// Link-Level Header length +// +#define UIP_CONF_LLH_LEN 14 + +// +// CPU byte order. +// +#define UIP_CONF_BYTE_ORDER UIP_BIG_ENDIAN + +// +// Here we include the header file for the application we are using in +// this example +#include "elua_uip.h" +#include "dhcpc.h" + +// +// Define the uIP Application State type (both TCP and UDP) +// +typedef struct elua_uip_state uip_tcp_appstate_t; +typedef struct dhcpc_state uip_udp_appstate_t; + +// +// UIP_APPCALL: the name of the application function. This function +// must return void and take no arguments (i.e., C type "void +// appfunc(void)"). +// +#ifndef UIP_APPCALL +#define UIP_APPCALL elua_uip_appcall +#endif + +#ifndef UIP_ADP_APPCALL +#define UIP_UDP_APPCALL elua_uip_udp_appcall +#endif + +// Added for eLua: DHCP TIMER ID +#define ELUA_DHCP_TIMER_ID 1 +#define CLOCK_SECOND 1000000UL + +#endif // __UIP_CONF_H_ diff --git a/src/platform/lpc17xx/platform_conf.h b/src/platform/lpc17xx/platform_conf.h index 1e7339a8..0cd935be 100644 --- a/src/platform/lpc17xx/platform_conf.h +++ b/src/platform/lpc17xx/platform_conf.h @@ -16,7 +16,7 @@ #define BUILD_CON_GENERIC #define BUILD_ADC #define BUILD_SEMIFS -#define BUILD_LUARPC +#define BUILD_RPC // ***************************************************************************** // UART/Timer IDs configuration data (used in main.c) @@ -36,6 +36,13 @@ #define ADCLINE #endif +// RPC +#if defined( BUILD_RPC ) +#define RPCLINE _ROM( AUXLIB_RPC, luaopen_rpc, rpc_map ) +#else +#define RPCLINE +#endif + // The name of the platform specific libs table #define PS_LIB_TABLE_NAME "mbed" @@ -50,6 +57,7 @@ _ROM( AUXLIB_BIT, luaopen_bit, bit_map )\ _ROM( AUXLIB_CPU, luaopen_cpu, cpu_map )\ _ROM( AUXLIB_PWM, luaopen_pwm, pwm_map )\ + RPCLINE\ _ROM( LUA_MATHLIBNAME, luaopen_math, math_map )\ _ROM( AUXLIB_ELUA, luaopen_elua, elua_map )\ _ROM( PS_LIB_TABLE_NAME, luaopen_platform, platform_map ) diff --git a/src/platform/str9/91x_ssp.c b/src/platform/str9/91x_ssp.c new file mode 100644 index 00000000..ab63e49c --- /dev/null +++ b/src/platform/str9/91x_ssp.c @@ -0,0 +1,466 @@ +/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** +* File Name : 91x_ssp.c +* Author : MCD Application Team +* Version : V2.1 +* Date : 12/22/2008 +* Description : This file provides all the SSP firmware functions. +******************************************************************************** +* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS +* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +*******************************************************************************/ + +/* Includes ------------------------------------------------------------------*/ +#include "91x_ssp.h" +#include "91x_scu.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ + +/* SSP peripheral Enable */ +#define SSP_Enable 0x0002 +#define SSP_Disable 0xFFFD + +/* SSP Loop Back Mode Enable */ +#define SSP_LoopBackMode_Enable 0x0001 +#define SSP_LoopBackMode_Disable 0xFFFE + +/* SSP Flag Mask */ +#define SSP_Flag_Mask 0x001F + +/* SSP DMA transmit/ receive enable/disable Masks */ +#define SSP_DMA_TransmitEnable 0x0002 +#define SSP_DMA_TransmitDisable 0xFFFD +#define SSP_DMA_ReceiveEnable 0x0001 +#define SSP_DMA_ReceiveDisable 0xFFFE + +/* SSP Masks */ +#define SSP_FrameFormat_Mask 0xFFCF +#define SSP_DataSize_Mask 0xFFF0 +#define SSP_ClockRate_Mask 0x00FF +#define SSP_ClockPrescaler_Mask 0xFF00 + +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************* +* Function Name : SSP_DeInit +* Description : Deinitializes the SSPx peripheral registers to their default +* reset values. +* Input : SSPx: where x can be 0 or 1 to select the SSP peripheral. +* Output : None +* Return : None +*******************************************************************************/ +void SSP_DeInit(SSP_TypeDef* SSPx) +{ + if(SSPx == SSP0) + { + /* Reset the SSP0 registers values*/ + SCU_APBPeriphReset(__SSP0,ENABLE); + SCU_APBPeriphReset(__SSP0,DISABLE); + } + else if (SSPx == SSP1) + { + /* Reset the SSP1 registers values*/ + SCU_APBPeriphReset(__SSP1,ENABLE); + SCU_APBPeriphReset(__SSP1,DISABLE); + } +} + +/******************************************************************************* +* Function Name : SSP_Init +* Description : Initializes the SSPx peripheral according to the specified +* parameters in the SSP_InitTypeDef structure. +* Input : - SSPx: where x can be 0 or 1 to select the SSP peripheral. +* - SSP_InitStruct: pointer to a SSP_InitTypeDef structure that +* contains the configuration information for the specified SSP +* peripheral. +* Output : None +* Return : None +*******************************************************************************/ +void SSP_Init(SSP_TypeDef* SSPx, SSP_InitTypeDef* SSP_InitStruct) +{ + if(SSP_InitStruct->SSP_FrameFormat == SSP_FrameFormat_Motorola) + { + /* Set the Motorola frame format */ + SSPx->CR0 &= SSP_FrameFormat_Motorola; + /* Configure the Clock polarity */ + if(SSP_InitStruct->SSP_CPOL == SSP_CPOL_High) + { + /* SCK is held high when no data is being transfered */ + SSPx->CR0 |= SSP_CPOL_High; + } + else + { + /* SCK is held low when no data is being transfered */ + SSPx->CR0 &= SSP_CPOL_Low; + } + /* Configure the Clock Phase */ + if(SSP_InitStruct->SSP_CPHA == SSP_CPHA_2Edge) + { + /* Data captured on second clock edge */ + SSPx->CR0 |= SSP_CPHA_2Edge; + } + else + { + /* Data captured on first clock edge */ + SSPx->CR0 &= SSP_CPHA_1Edge; + } + } + /* Configure the Frame format */ + else + { + /* Clear the FRF[1:0] bits */ + SSPx->CR0 &= SSP_FrameFormat_Mask; + /* Set the TI frame format */ + SSPx->CR0 |= SSP_InitStruct->SSP_FrameFormat; + } + /* Configure the Mode */ + if(SSP_InitStruct->SSP_Mode == SSP_Mode_Slave) + { + /* Set the slave mode */ + SSPx->CR1 |= SSP_Mode_Slave; + /* Configure the Slave output */ + if(SSP_InitStruct->SSP_SlaveOutput == SSP_SlaveOutput_Disable) + { + /* Slave output disabled */ + SSPx->CR1 |= SSP_SlaveOutput_Disable; + } + else + { + /* Slave output enabled */ + SSPx->CR1 &= SSP_SlaveOutput_Enable; + } + } + else + { + /* Set the master mode */ + SSPx->CR1 &= SSP_Mode_Master; + /* Clear clock rate SCR[7:0] bits */ + SSPx->CR0 &= SSP_ClockRate_Mask; + /* Set the serial clock rate */ + SSPx->CR0 |= (SSP_InitStruct->SSP_ClockRate<<8); + /* Clear clock prescaler CPSDVSR[7:0] bits */ + SSPx->PR &= SSP_ClockPrescaler_Mask; + /* Set the serial clock prescaler */ + SSPx->PR |= SSP_InitStruct->SSP_ClockPrescaler; + } + + /* Clear data size DSS[3:0] bits */ + SSPx->CR0 &= SSP_DataSize_Mask; + /* Set the data size */ + SSPx->CR0 |= SSP_InitStruct->SSP_DataSize; +} +/******************************************************************************* +* Function Name : SSP_StructInit +* Description : Fills in a SSP_InitTypeDef structure with the reset value of +* each parameter. +* Input : SSP_InitStruct : pointer to a SSP_InitTypeDef structure + which will be initialized. +* Output : None +* Return : None +*******************************************************************************/ +void SSP_StructInit(SSP_InitTypeDef* SSP_InitStruct) +{ + /* Initialize the SSP_FrameFormat member */ + SSP_InitStruct->SSP_FrameFormat = SSP_FrameFormat_Motorola; + + /* Initialize the SSP_Mode member */ + SSP_InitStruct->SSP_Mode = SSP_Mode_Master; + + /* Initialize the SSP_CPOL member */ + SSP_InitStruct->SSP_CPOL = SSP_CPOL_Low; + + /* Initialize the SSP_CPHA member */ + SSP_InitStruct->SSP_CPHA = SSP_CPHA_1Edge; + + /* Initialize the SSP_DataSize member */ + SSP_InitStruct->SSP_DataSize = SSP_DataSize_8b; + + /* Initialize the SSP_SlaveOutput member */ + SSP_InitStruct->SSP_SlaveOutput = SSP_SlaveOutput_Enable; + + /* Initialize the SSP_ClockRate member */ + SSP_InitStruct->SSP_ClockRate = 0; + + /* Initialize the SSP_ClockPrescaler member */ + SSP_InitStruct->SSP_ClockPrescaler = 0; +} + +/******************************************************************************* +* Function Name : SSP_Cmd +* Description : Enables or disables the specified SSP peripheral. +* Input : - SSPx: where x can be 0 or 1 to select the SSP peripheral. +* - NewState: new state of the SSPx peripheral. This parameter +* can be: ENABLE or DISABLE. +* Output : None +* Return : None +*******************************************************************************/ +void SSP_Cmd(SSP_TypeDef* SSPx, FunctionalState NewState) +{ + if(NewState == ENABLE) + { + /* Enable the SSP peripheral */ + SSPx->CR1 |= SSP_Enable; + } + else + { + /* Disable the SSP peripheral */ + SSPx->CR1 &= SSP_Disable; + } +} + +/******************************************************************************* +* Function Name : SSP_ITConfig +* Description : Enables or disables the specified SSP interrupts. +* Input : - SSPx: where x can be 0 or 1 to select the SSP peripheral. +* - SSP_IT: specifies the SSP interrupts sources to be enabled +* or disabled. This parameter can be any combination of the +* following values: +* - SSP_IT_TxFifo: Transmit FIFO half empty or less interrupt +* - SSP_IT_RxFifo: Receive FIFO half full or less interrupt +* - SSP_IT_RxTimeOut: Receive timeout interrupt +* - SSP_IT_RxOverrun: Receive overrun interrupt +* - NewState: new state of the specified SSP interrupts. +* This parameter can be: ENABLE or DISABLE. +* Output : None +* Return : None +*******************************************************************************/ +void SSP_ITConfig(SSP_TypeDef* SSPx, u16 SSP_IT, FunctionalState NewState) +{ + if(NewState == ENABLE) + { + /* Enable the selected SSP interrupts */ + SSPx->IMSCR |= SSP_IT; + } + else + { + /* Disable the selected SSP interrupts */ + SSPx->IMSCR &= ~SSP_IT; + } +} + +/******************************************************************************* +* Function Name : SSP_DMACmd +* Description : Configures the SSP0 DMA interface. +* Input : - SSPx: where x can be 0 or 1 to select the SSP peripheral. +* - SSP_DMATransfert : specifies the DMA transfert to be +* enabled or disabled. This parameter can be one of the +* following values: +* - SSP_DMA_Transmit: transmit Fifo DMA transfert +* - SSP_DMA_Receive : receive Fifo DMA transfert +* - NewState: new state of the DMA transfert. +* This parameter can be: ENABLE or DISABLE. +* Output : None +* Return : None +*******************************************************************************/ +void SSP_DMACmd(SSP_TypeDef* SSPx, u16 SSP_DMATransfert, FunctionalState NewState) +{ + if(NewState == ENABLE) + { + if(SSP_DMATransfert == SSP_DMA_Transmit) + { + /* Enable DMA for the transmit FIFO */ + SSPx->DMACR |= SSP_DMA_TransmitEnable; + } + else + { + /* Enable DMA for the receive FIFO */ + SSPx->DMACR |= SSP_DMA_ReceiveEnable; + } + } + else + { + if(SSP_DMATransfert == SSP_DMA_Transmit) + { + /* Disable DMA for the transmit FIFO */ + SSPx->DMACR &= SSP_DMA_TransmitDisable; + } + else + { + /* Disable DMA for the receive FIFO */ + SSPx->DMACR &= SSP_DMA_ReceiveDisable; + } + } +} + +/******************************************************************************* +* Function Name : SSP_SendData. +* Description : Transmits a Data through the SSP peripheral. +* Input : - SSPx: where x can be 0 or 1 to select the SSP peripheral. +* - Data : Data to be transmitted. +* Output : None +* Return : None +*******************************************************************************/ +void SSP_SendData(SSP_TypeDef* SSPx, u16 Data) +{ + /* Write in the DR register the data to be sent */ + SSPx->DR = Data; +} + +/******************************************************************************* +* Function Name : SSP_ReceiveData. +* Description : Returns the most recent received data by the SSP peripheral. +* Input : SSPx: where x can be 0 or 1 to select the SSP peripheral. +* Output : None +* Return : The value of the received data. +*******************************************************************************/ +u16 SSP_ReceiveData(SSP_TypeDef* SSPx) +{ + /* Return the data in the DR register */ + return SSPx->DR; +} + +/******************************************************************************* +* Function Name : SSP_LoopBackConfig +* Description : Enable or disable the Loop back mode for the selected SSPx peripheral. +* Input : - SSPx: where x can be 0 or 1 to select the SSP peripheral. +* - NewState: new state of the Loop Back mode. +* This parameter can be: ENABLE or DISABLE. +* Output : None +* Return : None. +*******************************************************************************/ +void SSP_LoopBackConfig(SSP_TypeDef* SSPx, FunctionalState NewState) +{ + if(NewState == ENABLE) + { + /* Enable loop back mode */ + SSPx->CR1 |= SSP_LoopBackMode_Enable; + } + else + { + /* Disable loop back mode */ + SSPx->CR1 &= SSP_LoopBackMode_Disable; + } +} + + + +/******************************************************************************* +* Function Name : SSP_GetFlagStatus +* Description : Checks whether the specified SSP flag is set or not. +* Input : - SSPx: where x can be 0 or 1 to select the SSP peripheral. +* - SSP_FLAG: flag to check. This parameter can be one of the +* following values: +* - SSP_FLAG_Busy: busy flag +* - SSP_FLAG_RxFifoFull: Receive FIFO full flag +* - SSP_FLAG_RxFifoNotEmpty: Receive FIFO not empty flag +* - SSP_FLAG_TxFifoNotFull: Transmit FIFO not full flag +* - SSP_FLAG_TxFifoEmpty: Transmit FIFO empty flag +* - SSP_FLAG_TxFifo: Transmit FIFO half empty or less flag +* - SSP_FLAG_RxFifo: Receive FIFO half full or less flag +* - SSP_FLAG_RxTimeOut: Receive timeout flag +* - SSP_FLAG_RxOverrun: Receive overrun flag +* Output : None +* Return : The new state of SSP_Flag (SET or RESET). +*******************************************************************************/ +FlagStatus SSP_GetFlagStatus(SSP_TypeDef* SSPx, u16 SSP_FLAG) +{ + u32 SSPReg = 0, FlagPos = 0; + u32 StatusReg = 0; + + /* Get the SSP register index */ + SSPReg = SSP_FLAG >> 5; + + /* Get the flag position */ + FlagPos = SSP_FLAG & SSP_Flag_Mask; + + /* Find the register of the flag to check */ + if(SSPReg == 1) + { + /* The flag to check is in SR register */ + StatusReg = SSPx->SR; + } + else if (SSPReg == 2) + { + /* The flag to check is in RISR register */ + StatusReg = SSPx->RISR; + } + + /* Check the status of the specified SSP flag */ + if((StatusReg & (1 << FlagPos)) != RESET) + { + /* Return SET if the SSP flag is set */ + return SET; + } + else + { + /* Return RESET if the SSP flag is reset */ + return RESET; + } +} + +/******************************************************************************* +* Function Name : SSP_ClearFlag +* Description : Clears the SSPx flags. +* Input : - SSPx: where x can be 0 or 1 to select the SSP peripheral. +* - SSP_FLAG: flags to clear. This parameter one of the +* following values: +* - SSP_FLAG_RxTimeOut: Receive timeout flag +* - SSP_FLAG_RxOverrun: Receive overrun flag +* Output : None +* Return : None +*******************************************************************************/ +void SSP_ClearFlag(SSP_TypeDef* SSPx, u16 SSP_FLAG) +{ + u8 FlagPos = 0; + + /* Get the flag position */ + FlagPos = SSP_FLAG & SSP_Flag_Mask; + + /* Clear the selected SSP flag */ + SSPx->ICR = (1 << FlagPos); +} + +/******************************************************************************* +* Function Name : SSP_GetITStatus +* Description : Checks whether the specified SSP interrupt flag is set or not. +* Input : - SSPx: where x can be 0 or 1 to select the SSP peripheral. +* - SSP_IT: interrupt flag to check. This parameter can be one +* of the following values: +* - SSP_IT_TxFifo: Transmit FIFO half empty or less interrupt +* - SSP_IT_RxFifo: Receive FIFO half full or less interrupt +* - SSP_IT_RxTimeOut: Receive timeout interrupt +* - SSP_IT_RxOverrun: Receive overrun interrupt +* Output : None +* Return : The new state of SSP_IT flag (SET or RESET). +*******************************************************************************/ +ITStatus SSP_GetITStatus(SSP_TypeDef* SSPx, u16 SSP_IT) +{ + /* Check the status of the specified interrupt flag */ + if((SSPx->MISR & SSP_IT) != RESET) + { + /* Return SET if the SSP interrupt flag is set */ + return SET; + } + else + { + /* Return RESET if SSP interrupt flag is reset */ + return RESET; + } +} + +/******************************************************************************* +* Function Name : SSP_ClearITPendingBit +* Description : Clears the pending interrupt flags. +* Input : - SSPx: where x can be 0 or 1 to select the SSP peripheral. +* - SSP_IT: interrupts pending bits to clear. This parameter +* can be any combination of the following values: +* - SSP_IT_RxTimeOut: Receive timeout interrupt +* - SSP_IT_RxOverrun: Receive overrun interrupt +* Output : None +* Return : None +*******************************************************************************/ +void SSP_ClearITPendingBit(SSP_TypeDef* SSPx, u16 SSP_IT) +{ + /* Clear the selected SSP interrupts pending bits */ + SSPx->ICR = SSP_IT; +} + +/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ + diff --git a/src/platform/str9/91x_ssp.h b/src/platform/str9/91x_ssp.h new file mode 100644 index 00000000..bb49baf4 --- /dev/null +++ b/src/platform/str9/91x_ssp.h @@ -0,0 +1,116 @@ +/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** +* File Name : 91x_ssp.h +* Author : MCD Application Team +* Version : V2.1 +* Date : 12/22/2008 +* Description : This file contains all the functions prototypes for the +* SSP firmware library. +******************************************************************************** +* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS +* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +*******************************************************************************/ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __91x_SSP_H +#define __91x_SSP_H + +/* Includes ------------------------------------------------------------------*/ +#include "91x_map.h" + +/* Exported types ------------------------------------------------------------*/ +/* SSP Init structure definition */ +typedef struct +{ + u16 SSP_FrameFormat ; + u16 SSP_Mode ; + u16 SSP_CPOL ; + u16 SSP_CPHA ; + u16 SSP_DataSize ; + u16 SSP_SlaveOutput ; + u8 SSP_ClockRate ; + u8 SSP_ClockPrescaler ; +}SSP_InitTypeDef; + +/* Exported constants --------------------------------------------------------*/ +/* SSP Frame Format Select */ +#define SSP_FrameFormat_TI 0x0010 +#define SSP_FrameFormat_Motorola 0xFFCF +#define SSP_FrameFormat_Microwire 0x0020 + +/* SSP Master/Slave Select */ +#define SSP_Mode_Master 0xFFFB +#define SSP_Mode_Slave 0x0004 + +/* SSP Clock Polarity */ +#define SSP_CPOL_Low 0xFFBF +#define SSP_CPOL_High 0x0040 + +/* SSP Clock Phase */ +#define SSP_CPHA_1Edge 0xFF7F +#define SSP_CPHA_2Edge 0x0080 + +/* SSP Data Size */ +#define SSP_DataSize_16b 0x000F +#define SSP_DataSize_15b 0x000E +#define SSP_DataSize_14b 0x000D +#define SSP_DataSize_13b 0x000C +#define SSP_DataSize_12b 0x000B +#define SSP_DataSize_11b 0x000A +#define SSP_DataSize_10b 0x0009 +#define SSP_DataSize_9b 0x0008 +#define SSP_DataSize_8b 0x0007 +#define SSP_DataSize_7b 0x0006 +#define SSP_DataSize_6b 0x0005 +#define SSP_DataSize_5b 0x0004 +#define SSP_DataSize_4b 0x0003 + +/* SSP Slave output config */ +#define SSP_SlaveOutput_Enable 0xFFF7 +#define SSP_SlaveOutput_Disable 0x0008 + +/* SSP Interrupts */ +#define SSP_IT_TxFifo 0x0008 +#define SSP_IT_RxFifo 0x0004 +#define SSP_IT_RxTimeOut 0x0002 +#define SSP_IT_RxOverrun 0x0001 + +/* SSP Flags */ +#define SSP_FLAG_Busy 0x0024 +#define SSP_FLAG_RxFifoFull 0x0023 +#define SSP_FLAG_RxFifoNotEmpty 0x0022 +#define SSP_FLAG_TxFifoNotFull 0x0021 +#define SSP_FLAG_TxFifoEmpty 0x0020 +#define SSP_FLAG_TxFifo 0x0043 +#define SSP_FLAG_RxFifo 0x0042 +#define SSP_FLAG_RxTimeOut 0x0041 +#define SSP_FLAG_RxOverrun 0x0040 + +/* SSP DMA Requests */ +#define SSP_DMA_Transmit 0x0002 +#define SSP_DMA_Receive 0x0001 + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +void SSP_DeInit(SSP_TypeDef* SSPx); +void SSP_Init(SSP_TypeDef* SSPx, SSP_InitTypeDef* SSP_InitStruct); +void SSP_StructInit(SSP_InitTypeDef* SSP_InitStruct); +void SSP_Cmd(SSP_TypeDef* SSPx, FunctionalState NewState); +void SSP_ITConfig(SSP_TypeDef* SSPx, u16 SSP_IT, FunctionalState NewState); +void SSP_DMACmd(SSP_TypeDef* SSPx, u16 SSP_DMATransfert, FunctionalState NewState); +void SSP_SendData(SSP_TypeDef* SSPx, u16 Data); +u16 SSP_ReceiveData(SSP_TypeDef* SSPx); +void SSP_LoopBackConfig(SSP_TypeDef* SSPx, FunctionalState NewState); +FlagStatus SSP_GetFlagStatus(SSP_TypeDef* SSPx, u16 SSP_FLAG); +void SSP_ClearFlag(SSP_TypeDef* SSPx, u16 SSP_FLAG); +ITStatus SSP_GetITStatus(SSP_TypeDef* SSPx, u16 SSP_IT); +void SSP_ClearITPendingBit(SSP_TypeDef* SSPx, u16 SSP_IT); + +#endif /* __91x_SSP_H */ + +/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ + diff --git a/src/platform/str9/conf.lua b/src/platform/str9/conf.lua index 0b7808a1..e1b5cec8 100644 --- a/src/platform/str9/conf.lua +++ b/src/platform/str9/conf.lua @@ -2,7 +2,7 @@ local cpumode = ( builder:get_option( 'cpumode' ) or 'arm' ):lower() -specific_files = "startup912.s startup_generic.s platform.c 91x_scu.c 91x_fmi.c 91x_gpio.c 91x_uart.c 91x_tim.c 91x_vic.c interrupt.c str9_pio.c 91x_i2c.c 91x_wiu.c 91x_adc.c platform_int.c" +specific_files = "startup912.s startup_generic.s platform.c 91x_scu.c 91x_fmi.c 91x_gpio.c 91x_uart.c 91x_tim.c 91x_vic.c interrupt.c str9_pio.c 91x_i2c.c 91x_wiu.c 91x_adc.c platform_int.c 91x_ssp.c" local ldscript = "str912fw44.lds" diff --git a/src/platform/str9/conf.py b/src/platform/str9/conf.py index 7bc9cf7b..014767e0 100644 --- a/src/platform/str9/conf.py +++ b/src/platform/str9/conf.py @@ -2,7 +2,7 @@ cpumode = ARGUMENTS.get( 'cpumode', 'arm' ).lower() -specific_files = "startup912.s startup_generic.s platform.c 91x_scu.c 91x_fmi.c 91x_gpio.c 91x_uart.c 91x_tim.c 91x_vic.c interrupt.c str9_pio.c 91x_i2c.c 91x_wiu.c 91x_adc.c platform_int.c" +specific_files = "startup912.s startup_generic.s platform.c 91x_scu.c 91x_fmi.c 91x_gpio.c 91x_uart.c 91x_tim.c 91x_vic.c interrupt.c str9_pio.c 91x_i2c.c 91x_wiu.c 91x_adc.c platform_int.c 91x_ssp.c" # Check CPU if comp[ 'cpu' ] == 'STR912FAW44': diff --git a/src/platform/str9/platform.c b/src/platform/str9/platform.c index 4247868a..7c809bb2 100644 --- a/src/platform/str9/platform.c +++ b/src/platform/str9/platform.c @@ -24,6 +24,8 @@ #include "buf.h" #include "elua_adc.h" #include "91x_adc.h" +#include "91x_ssp.h" +#include "utils.h" // **************************************************************************** // Platform initialization @@ -51,6 +53,8 @@ static void platform_config_scu() SCU_PCLKDivisorConfig(SCU_PCLK_Div2); /* Set the HCLK Clock to MCLK */ SCU_HCLKDivisorConfig(SCU_HCLK_Div1); + /* Set the BRCLK Clock to MCLK */ + SCU_BRCLKDivisorConfig(SCU_BRCLK_Div1); // Enable VIC clock SCU_AHBPeriphClockConfig(__VIC, ENABLE); @@ -80,6 +84,12 @@ static void platform_config_scu() // Enable the ADC clocks SCU_APBPeriphClockConfig(__ADC, ENABLE); + + // Enable the SSP clocks + SCU_APBPeriphClockConfig(__SSP0,ENABLE); + SCU_APBPeriphReset(__SSP0,DISABLE); + SCU_APBPeriphClockConfig(__SSP1,ENABLE); + SCU_APBPeriphReset(__SSP1,DISABLE); } // Port/pin definitions of the eLua UART connection for different boards @@ -142,12 +152,13 @@ int platform_init() TIM_CounterCmd( base, TIM_START ); } + cmn_platform_init(); + #ifdef BUILD_ADC // Setup ADCs platform_setup_adcs(); #endif - - cmn_platform_init(); + #ifdef VTMR_TIMER_ID platform_s_timer_set_match_int( VTMR_TIMER_ID, 1000000 / VTMR_FREQ_HZ, PLATFORM_TIMER_INT_CYCLIC ); #endif @@ -785,6 +796,99 @@ int platform_i2c_recv_byte( unsigned id, int ack ) return I2C_ReceiveData( pi2c ); } +// **************************************************************************** +// SPI + +#define SPI_MAX_PRESCALER ( 254 * 256 ) +#define SPI_MIN_PRESCALER 2 + +u32 platform_spi_setup( unsigned id, int mode, u32 clock, unsigned cpol, unsigned cpha, unsigned databits ) +{ + const u32 basefreq = CPU_FREQUENCY; + u32 prescaler, divider = 1, temp, mindiff = 0xFFFFFFFF, minp; + GPIO_InitTypeDef GPIO_InitStructure; + SSP_InitTypeDef SSP_InitStructure; + + clock = UMIN( clock, basefreq >> 1 ); + prescaler = UMIN( basefreq / clock, SPI_MAX_PRESCALER ); + if( basefreq / prescaler > clock ) + prescaler ++; + if( prescaler & 1 ) + prescaler ++; + if( prescaler > 254 ) + { + temp = prescaler; + for( prescaler = minp = 2; prescaler <= 254; prescaler += 2 ) + { + divider = temp / prescaler; + if( divider <= 255 ) + { + if( ABSDIFF( divider * prescaler, temp ) < mindiff ) + { + mindiff = ABSDIFF( divider * prescaler, temp ); + minp = prescaler; + if( mindiff == 0 ) + break; + } + } + } + prescaler = minp; + divider = temp / prescaler; + } + + // GPIO setup + // Fixed assignment: + // P5.4 - SCLK + // P5.5 - MOSI + // P5.6 - MISO + // P5.7 - CS (not explicitly handled by the SPI module) + GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput; + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5; + GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull ; + GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt2 ; + GPIO_Init(GPIO5, &GPIO_InitStructure); + GPIO_InitStructure.GPIO_Direction = GPIO_PinInput; + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; + GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Enable; + GPIO_InitStructure.GPIO_Alternate = GPIO_InputAlt1 ; + GPIO_Init(GPIO5, &GPIO_InitStructure); + + // Actual SPI setup + SSP_DeInit(SSP0); + SSP_InitStructure.SSP_FrameFormat = SSP_FrameFormat_Motorola; + SSP_InitStructure.SSP_Mode = SSP_Mode_Master; + SSP_InitStructure.SSP_CPOL = cpol == 0 ? SSP_CPOL_Low : SSP_CPOL_High; + SSP_InitStructure.SSP_CPHA = cpha == 0 ? SSP_CPHA_1Edge : SSP_CPHA_2Edge; + SSP_InitStructure.SSP_DataSize = databits - 1; + SSP_InitStructure.SSP_ClockRate = divider - 1; + SSP_InitStructure.SSP_ClockPrescaler = prescaler; + SSP_Init(SSP0, &SSP_InitStructure); + + // Enable peripheral + SSP_Cmd(SSP0, ENABLE); + + // All done + return basefreq / ( prescaler * divider ); +} + +spi_data_type platform_spi_send_recv( unsigned id, spi_data_type data ) +{ + // Send byte through the SSP0 peripheral + SSP0->DR = data; + // Loop while Transmit FIFO is full + while(SSP_GetFlagStatus(SSP0, SSP_FLAG_TxFifoEmpty) == RESET); + // Loop while Receive FIFO is empty + while(SSP_GetFlagStatus(SSP0, SSP_FLAG_RxFifoNotEmpty) == RESET); + // Return the byte read from the SSP bus + return SSP0->DR; +} + +void platform_spi_select( unsigned id, int is_select ) +{ + id = id; + is_select = is_select; +} + // **************************************************************************** // Platform specific modules go here @@ -811,7 +915,6 @@ LUALIB_API int luaopen_platform( lua_State *L ) lua_newtable( L ); luaL_register( L, NULL, str9_pio_map ); lua_setfield( L, -2, "pio" ); - return 1; #endif // #if LUA_OPTIMIZE_MEMORY > 0 } diff --git a/src/platform/str9/platform_conf.h b/src/platform/str9/platform_conf.h index 7b7dc3ec..3c02dd47 100644 --- a/src/platform/str9/platform_conf.h +++ b/src/platform/str9/platform_conf.h @@ -46,7 +46,7 @@ // Number of resources (0 if not available/not implemented) #define NUM_PIO 10 -#define NUM_SPI 0 +#define NUM_SPI 1 #define NUM_UART 3 #define NUM_PWM 4 #define NUM_ADC 8 @@ -130,6 +130,8 @@ u32 SCU_GetMCLKFreqValue(); _ROM( AUXLIB_CPU, luaopen_cpu, cpu_map)\ _ROM( AUXLIB_CPU, luaopen_elua, elua_map)\ _ROM( AUXLIB_I2C, luaopen_i2c, i2c_map)\ + _ROM( AUXLIB_SPI, luaopen_spi, spi_map)\ + _ROM( AUXLIB_ELUA, luaopen_elua, elua_map)\ RPCLINE\ _ROM( AUXLIB_PWM, luaopen_pwm, pwm_map)\ _ROM( LUA_MATHLIBNAME, luaopen_math, math_map )\ diff --git a/src/platform/str9/startup912.s b/src/platform/str9/startup912.s index e1b4e89d..e5cda537 100644 --- a/src/platform/str9/startup912.s +++ b/src/platform/str9/startup912.s @@ -135,8 +135,6 @@ DAbt_Handler: B DAbt_Handler IRQ_Handler: B ASM_IRQ_Handler /* should never get here as IRQ is via VIC slot... */ FIQ_Handler: B FIQ_Handler - .text - # Generic IRQ handler ASM_IRQ_Handler: sub lr, lr ,#4