From 4ba06834483c4c480ac3f16e71d6f3073b9363e1 Mon Sep 17 00:00:00 2001 From: richardbarry Date: Sat, 27 May 2006 13:55:53 +0000 Subject: [PATCH] New Demo files for Tern E-Engine controller port. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@7 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- Demo/WizNET_DEMO_TERN_186/186.cfg | 145 ++ Demo/WizNET_DEMO_TERN_186/AE.LIB | Bin 0 -> 19456 bytes Demo/WizNET_DEMO_TERN_186/FreeRTOSConfig.h | 77 + Demo/WizNET_DEMO_TERN_186/HTTPTask.c | 289 +++ Demo/WizNET_DEMO_TERN_186/HTTPTask.h | 39 + Demo/WizNET_DEMO_TERN_186/RTOSDemo.DSW | Bin 0 -> 5788 bytes Demo/WizNET_DEMO_TERN_186/RTOSDemo.ide | Bin 0 -> 56498 bytes Demo/WizNET_DEMO_TERN_186/RTOSDemo.mbt | Bin 0 -> 873 bytes Demo/WizNET_DEMO_TERN_186/RTOSDemo.mrt | Bin 0 -> 27340 bytes Demo/WizNET_DEMO_TERN_186/RTOSDemo.rom | Bin 0 -> 120976 bytes Demo/WizNET_DEMO_TERN_186/i2chip_hw.c | 239 +++ Demo/WizNET_DEMO_TERN_186/include/SOCKET.H | 247 +++ Demo/WizNET_DEMO_TERN_186/include/TYPES.H | 64 + Demo/WizNET_DEMO_TERN_186/include/ae.H | 264 +++ Demo/WizNET_DEMO_TERN_186/include/i2chip_hw.h | 309 +++ .../include/utils/system_common.h | 12 + Demo/WizNET_DEMO_TERN_186/main.c | 196 ++ Demo/WizNET_DEMO_TERN_186/serial/serial.c | 442 ++++ Demo/WizNET_DEMO_TERN_186/socket.c | 1861 +++++++++++++++++ 19 files changed, 4184 insertions(+) create mode 100644 Demo/WizNET_DEMO_TERN_186/186.cfg create mode 100644 Demo/WizNET_DEMO_TERN_186/AE.LIB create mode 100644 Demo/WizNET_DEMO_TERN_186/FreeRTOSConfig.h create mode 100644 Demo/WizNET_DEMO_TERN_186/HTTPTask.c create mode 100644 Demo/WizNET_DEMO_TERN_186/HTTPTask.h create mode 100644 Demo/WizNET_DEMO_TERN_186/RTOSDemo.DSW create mode 100644 Demo/WizNET_DEMO_TERN_186/RTOSDemo.ide create mode 100644 Demo/WizNET_DEMO_TERN_186/RTOSDemo.mbt create mode 100644 Demo/WizNET_DEMO_TERN_186/RTOSDemo.mrt create mode 100644 Demo/WizNET_DEMO_TERN_186/RTOSDemo.rom create mode 100644 Demo/WizNET_DEMO_TERN_186/i2chip_hw.c create mode 100644 Demo/WizNET_DEMO_TERN_186/include/SOCKET.H create mode 100644 Demo/WizNET_DEMO_TERN_186/include/TYPES.H create mode 100644 Demo/WizNET_DEMO_TERN_186/include/ae.H create mode 100644 Demo/WizNET_DEMO_TERN_186/include/i2chip_hw.h create mode 100644 Demo/WizNET_DEMO_TERN_186/include/utils/system_common.h create mode 100644 Demo/WizNET_DEMO_TERN_186/main.c create mode 100644 Demo/WizNET_DEMO_TERN_186/serial/serial.c create mode 100644 Demo/WizNET_DEMO_TERN_186/socket.c diff --git a/Demo/WizNET_DEMO_TERN_186/186.cfg b/Demo/WizNET_DEMO_TERN_186/186.cfg new file mode 100644 index 000000000..f7e61706c --- /dev/null +++ b/Demo/WizNET_DEMO_TERN_186/186.cfg @@ -0,0 +1,145 @@ +// 186.cfg +// You must select RAM, ROM for your controller 04-26-2000 +// Your TERN controller is installed with SRAM and ROM with different sizes. +// For debug, 128K or 512K SRAM can be selected +// For build a ROM, you need to select the ROM size. +// How to select ? +// 1) commend out the unwanted #define RAM size line with "//" +// 2) delete the "//" preceding the wanted #define RAM size line +// + +// #define RAM 32 // 32KB SRAM installed +#define RAM 128 // 128KB SRAM installed +// #define RAM 512 // 512KB SRAM installed + +// #define ROM 32 // Use 32KB ROM chip 27C256-70 +#define ROM 64 // Use 64KB ROM chip 27C512-70 +// #define ROM 128 // Use 128KB ROM chip 27C010-70 +// #define ROM 256 // Use 256KB ROM chip 27C020-70 +// #define ROM 512 // Use 512KB ROM chip 27C040-70, Change Jumper on board + + +cputype Am186ES // AMD188/6 based controllers + +#if defined(__PDREMOTE__) + +#if RAM == 32 +map 0x00000 to 0x00fff as reserved // interrupt vector table +map 0x01000 to 0x03fff as rdwr // System RAM area (60KB RAM) +map 0x04000 to 0x07fff as rdonly // Simulated EPROM area (64KB RAM) +map 0x08000 to 0xfffff as reserved // No access allowed +#define CODE_START 0x0400 // Start of application code, STEP2 ! + +#elif RAM == 128 +map 0x00000 to 0x00fff as reserved // interrupt vector table +map 0x01000 to 0x07fff as rdwr // System RAM area (60KB RAM) +map 0x08000 to 0x1ffff as rdonly // Simulated EPROM area (64KB RAM) +map 0x20000 to 0xfffff as reserved // No access allowed +#define CODE_START 0x0800 // Start of application code + +#elif RAM == 512 +map 0x00000 to 0x00fff as reserved // interrupt vector table +map 0x01000 to 0x07fff as rdwr // System RAM area (60KB RAM) +map 0x08000 to 0x7ffff as rdonly // Simulated EPROM area(480KB RAM) +map 0x80000 to 0xfffff as reserved // No access allowed +#define CODE_START 0x0800 // Start of application code +#endif + +#define DATA_START 0x0100 // Start of application data +#define BOOT_START 0x1fc0 // Start of initialization code + +#else +#if ROM == 32 +map 0x00000 to 0x1ffff as rdwr // 128KB RAM address space +map 0x20000 to 0xf7fff as reserved // No access +map 0xF8000 to 0xfffff as rdonly // 32KB EPROM address space +#define CODE_START 0xF800 // Start of application code +#elif ROM == 64 +map 0x00000 to 0x1ffff as rdwr // 128KB RAM address space +map 0x20000 to 0xEffff as reserved // No access +map 0xF0000 to 0xfffff as rdonly // 64KB EPROM address space +#define CODE_START 0xF000 // Start of application code +#elif ROM == 128 +map 0x00000 to 0x1ffff as rdwr // 128KB RAM address space +map 0x20000 to 0xDffff as reserved // No access +map 0xE0000 to 0xfffff as rdonly // 128KB EPROM address space +#define CODE_START 0xE000 // Start of application code +#elif ROM == 256 +map 0x00000 to 0x1ffff as rdwr // 128KB RAM address space +map 0x20000 to 0xBffff as reserved // No access +map 0xC0000 to 0xfffff as rdonly // 256KB EPROM address space +#define CODE_START 0xC000 // Start of application code +#elif ROM == 512 +map 0x00000 to 0x1ffff as rdwr // 128KB RAM address space +map 0x20000 to 0x7ffff as reserved // No access +map 0x80000 to 0xfffff as rdonly // 512KB EPROM address space +#define CODE_START 0x8000 // Start of application code +#endif + +#define DATA_START 0x0040 // Start of application data +#define BOOT_START 0xffc0 // Start of initialization code + +initcode reset \ // Reset vector to program entry point + umcs = 0x80bf \ // 512K ROM, 3 wait states + lmcs = 0x7fbf \ // 512K RAM, 3 wait states + mpcs = 0xa0bf \ + mmcs = 0x81ff \ + pacs = 0x007f + +class ??LOCATE = BOOT_START // Chip select initialization +output ??LOCATE + +#if ROM == 32 // 27C256-90 EPROM or FLASH +hexfile binary offset=0xf8000 size=32 // for 27C256, bin file +#elif ROM == 64 // 27C512-90 EPROM or FLASH +hexfile binary offset=0xF0000 size=64 // for 27C512 +#elif ROM == 128 // 27C010-90 EPROM or FLASH +hexfile binary offset=0xE0000 size=128 // for 27C010 +#elif ROM == 256 // 27C020-90 EPROM or FLASH +hexfile binary offset=0xC0000 size=256 // for 27C020 +#elif ROM == 512 // 27C040-90 EPROM or FLASH +hexfile Intel86 offset=0x80000 size=512 // for 27C040, output .HEX file +#endif + +#endif + + +// +// Start of common configuration file settings. +// + +absfile axe86 // Paradigm C++ debugging output +listfile segments // Absolute segment map + +dup DATA ROMDATA // Make a copy of initialized data +dup FAR_DATA ROMFARDATA // Make a copy of far initialized data + +#if defined(__COMPFARDATA__) // Compress and display results +compress ROMFARDATA +display compression +#endif + +class CODE = CODE_START // Application code +class DATA = DATA_START // Application data + +order DATA \ // RAM class organization + BSS \ + NVRAM \ + EDATA \ + STACK \ + FAR_DATA ENDFAR_DATA \ + FAR_BSS ENDFAR_BSS \ + FAR_HEAP ENDFAR_HEAP + +order CODE \ // EPROM class organization + INITDATA EXITDATA \ + FAR_CONST ENDFAR_CONST \ + ROMDATA ENDROMDATA \ + ROMFARDATA ENDROMFARDATA + +output CODE \ // Classes in the output file(s) + INITDATA EXITDATA \ + FAR_CONST ENDFAR_CONST \ + ROMDATA ENDROMDATA \ + ROMFARDATA ENDROMFARDATA + \ No newline at end of file diff --git a/Demo/WizNET_DEMO_TERN_186/AE.LIB b/Demo/WizNET_DEMO_TERN_186/AE.LIB new file mode 100644 index 0000000000000000000000000000000000000000..dcfffa152ba435a47ae2ef3d66b24628ceaa3fc3 GIT binary patch literal 19456 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 +#include + +/* Tern includes. */ +#include "utils\system_common.h" +#include "i2chip_hw.h" +#include "socket.h" + +/* FreeRTOS.org includes. */ +#include +#include +#include + +/* The standard http port on which we are going to listen. */ +#define httpPORT 80 + +#define httpTX_WAIT 2 + +/* Network address configuration. */ +const unsigned portCHAR ucMacAddress[] = { 12, 128, 12, 34, 56, 78 }; +const unsigned portCHAR ucGatewayAddress[] = { 192, 168, 2, 1 }; +const unsigned portCHAR ucIPAddress[] = { 172, 25, 218, 210 }; +const unsigned portCHAR ucSubnetMask[] = { 255, 255, 255, 0 }; + +/* The number of sockets this task is going to handle. */ +#define httpSOCKET_NUM 3 +unsigned portCHAR ucConnection[ httpSOCKET_NUM ]; + +/* The maximum data buffer size we can handle. */ +#define httpSOCKET_BUFFER_SIZE 2048 + +/* Standard HTTP response. */ +#define httpOUTPUT_OK "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" + +/* Hard coded HTML components. Other data is generated dynamically. */ +#define HTML_OUTPUT_BEGIN "\ +\ +

FreeRTOS.orgtm + Tern E-Enginetm

\ +FreeRTOS.org Homepage

\ +


Task status table:\r\n\ +

Task          State  Priority  Stack	#
\ +************************************************
" + +#define HTML_OUTPUT_END "\ +
" + +/*-----------------------------------------------------------*/ + +/* + * Initialise the data structures used to hold the socket status. + */ +static void prvHTTPInit( void ); + +/* + * Setup the Ethernet interface with the network addressing information. + */ +static void prvNetifInit( void ); + +/* + * Generate the dynamic components of the served WEB page and transmit the + * entire page through the socket. + */ +static void prvTransmitHTTP( unsigned portCHAR socket ); +/*-----------------------------------------------------------*/ + +/* This variable is simply incremented by the idle task hook so the number of +iterations the idle task has performed can be displayed as part of the served +page. */ +unsigned portLONG ulIdleLoops = 0UL; + +/* Data buffer shared by sockets. */ +unsigned portCHAR ucSocketBuffer[ httpSOCKET_BUFFER_SIZE ]; + +/* The semaphore used by the Ethernet ISR to signal that the task should wake +and process whatever caused the interrupt. */ +xSemaphoreHandle xTCPSemaphore = NULL; + +/*-----------------------------------------------------------*/ +void vHTTPTask( void * pvParameters ) +{ +portSHORT i, sLen; +unsigned portCHAR ucState; + + ( void ) pvParameters; + + /* Create the semaphore used to communicate between this task and the + WIZnet ISR. */ + vSemaphoreCreateBinary( xTCPSemaphore ); + + /* Make sure everything is setup before we start. */ + prvNetifInit(); + prvHTTPInit(); + + for( ;; ) + { + /* Wait until the ISR tells us there is something to do. */ + xSemaphoreTake( xTCPSemaphore, portMAX_DELAY ); + + /* Check each socket. */ + for( i = 0; i < httpSOCKET_NUM; i++ ) + { + ucState = select( i, SEL_CONTROL ); + + switch (ucState) + { + case SOCK_ESTABLISHED : /* new connection established. */ + + if( ( sLen = select( i, SEL_RECV ) ) > 0 ) + { + if( sLen > httpSOCKET_BUFFER_SIZE ) + { + sLen = httpSOCKET_BUFFER_SIZE; + } + + disable(); + + sLen = recv( i, ucSocketBuffer, sLen ); + + if( ucConnection[ i ] == 1 ) + { + /* This is our first time processing a HTTP + request on this connection. */ + prvTransmitHTTP( i ); + ucConnection[i] = 0; + } + enable(); + } + break; + + case SOCK_CLOSE_WAIT : + + close(i); + break; + + case SOCK_CLOSED : + + ucConnection[i] = 1; + socket( i, SOCK_STREAM, 80, 0x00 ); + NBlisten( i ); /* reinitialize socket. */ + break; + } + } + } +} +/*-----------------------------------------------------------*/ + +static void prvHTTPInit( void ) +{ +unsigned portCHAR ucIndex; + + /* There are 4 total sockets available; we will claim 3 for HTTP. */ + for(ucIndex = 0; ucIndex < httpSOCKET_NUM; ucIndex++) + { + socket( ucIndex, SOCK_STREAM, httpPORT, 0x00 ); + NBlisten( ucIndex ); + ucConnection[ ucIndex ] = 1; + } +} +/*-----------------------------------------------------------*/ + +static void prvNetifInit( void ) +{ + i2chip_init(); + initW3100A(); + + setMACAddr( ( unsigned portCHAR * ) ucMacAddress ); + setgateway( ( unsigned portCHAR * ) ucGatewayAddress ); + setsubmask( ( unsigned portCHAR * ) ucSubnetMask ); + setIP( ( unsigned portCHAR * ) ucIPAddress ); + + /* See definition of 'sysinit' in socket.c + - 8 KB transmit buffer, and 8 KB receive buffer available. These buffers + are shared by all 4 channels. + - (0x55, 0x55) configures the send and receive buffers at + httpSOCKET_BUFFER_SIZE bytes for each of the 4 channels. */ + sysinit( 0x55, 0x55 ); +} +/*-----------------------------------------------------------*/ + +static void prvTransmitHTTP(unsigned portCHAR socket) +{ +extern portSHORT usCheckStatus; + + /* Send the http and html headers. */ + send( socket, ( unsigned portCHAR * ) httpOUTPUT_OK, strlen( httpOUTPUT_OK ) ); + send( socket, ( unsigned portCHAR * ) HTML_OUTPUT_BEGIN, strlen( HTML_OUTPUT_BEGIN ) ); + + /* Generate then send the table showing the status of each task. */ + vTaskList( ucSocketBuffer ); + send( socket, ( unsigned portCHAR * ) ucSocketBuffer, strlen( ucSocketBuffer ) ); + + /* Send the number of times the idle task has looped. */ + sprintf( ucSocketBuffer, "


The idle task has looped 0x%08lx times
", ulIdleLoops ); + send( socket, ( unsigned portCHAR * ) ucSocketBuffer, strlen( ucSocketBuffer ) ); + + /* Send the tick count. */ + sprintf( ucSocketBuffer, "The tick count is 0x%08lx
", xTaskGetTickCount() ); + send( socket, ( unsigned portCHAR * ) ucSocketBuffer, strlen( ucSocketBuffer ) ); + + /* Show a message indicating whether or not the check task has discovered + an error in any of the standard demo tasks. */ + if( usCheckStatus == 0 ) + { + sprintf( ucSocketBuffer, "No errors detected." ); + send( socket, ( unsigned portCHAR * ) ucSocketBuffer, strlen( ucSocketBuffer ) ); + } + else + { + sprintf( ucSocketBuffer, "An error has been detected in at least one task %x.

", usCheckStatus ); + send( socket, ( unsigned portCHAR * ) ucSocketBuffer, strlen( ucSocketBuffer ) ); + } + + /* Finish the page off. */ + send( socket, (unsigned portCHAR*)HTML_OUTPUT_END, strlen(HTML_OUTPUT_END)); + + /* Must make sure the data is gone before closing the socket. */ + while( !tx_empty( socket ) ) + { + vTaskDelay( httpTX_WAIT ); + } + close(socket); +} +/*-----------------------------------------------------------*/ + +void vApplicationIdleHook( void ) +{ + ulIdleLoops++; +} + + + + + + + + + + + + + + + + + + + + diff --git a/Demo/WizNET_DEMO_TERN_186/HTTPTask.h b/Demo/WizNET_DEMO_TERN_186/HTTPTask.h new file mode 100644 index 000000000..3961fb1e6 --- /dev/null +++ b/Demo/WizNET_DEMO_TERN_186/HTTPTask.h @@ -0,0 +1,39 @@ +/* + FreeRTOS V4.0.1 - Copyright (C) 2003-2006 Richard Barry. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + FreeRTOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with FreeRTOS; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + A special exception to the GPL can be applied should you wish to distribute + a combined work that includes FreeRTOS, without being obliged to provide + the source code for any proprietary components. See the licensing section + of http://www.FreeRTOS.org for full details of how and when the exception + can be applied. + + *************************************************************************** + See http://www.FreeRTOS.org for documentation, latest information, license + and contact details. Please ensure to read the configuration and relevant + port sections of the online documentation. + *************************************************************************** +*/ + +#ifndef HTTP_TASK_H +#define HTTP_TASK_H + +void vHTTPTask( void *pvParameters ); + +#endif + diff --git a/Demo/WizNET_DEMO_TERN_186/RTOSDemo.DSW b/Demo/WizNET_DEMO_TERN_186/RTOSDemo.DSW new file mode 100644 index 0000000000000000000000000000000000000000..789ec352070aaa9c316afe35cbb006f4e2abaa9f GIT binary patch literal 5788 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 literal 0 HcmV?d00001 diff --git a/Demo/WizNET_DEMO_TERN_186/RTOSDemo.mbt b/Demo/WizNET_DEMO_TERN_186/RTOSDemo.mbt new file mode 100644 index 0000000000000000000000000000000000000000..9af2d521a33dfc356ab2be167c10342ac2f3162c GIT binary patch literal 873 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 literal 0 HcmV?d00001 diff --git a/Demo/WizNET_DEMO_TERN_186/RTOSDemo.rom b/Demo/WizNET_DEMO_TERN_186/RTOSDemo.rom new file mode 100644 index 0000000000000000000000000000000000000000..74ecd1f947a735b636158e34437f114779487772 GIT binary patch literal 120976 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 Vc_>l3C+(cHPl8`st>a1b{{r#tsm}la literal 0 HcmV?d00001 diff --git a/Demo/WizNET_DEMO_TERN_186/i2chip_hw.c b/Demo/WizNET_DEMO_TERN_186/i2chip_hw.c new file mode 100644 index 000000000..eb513ef1b --- /dev/null +++ b/Demo/WizNET_DEMO_TERN_186/i2chip_hw.c @@ -0,0 +1,239 @@ +/* +******************************************************************************** +* TERN, Inc. +* (c) Copyright 2005, http://www.tern.com +* +* - Created to support i2chip module on a variety of TERN hardware platforms. +******************************************************************************** +*/ + +#include +#include "i2chip_hw.h" + +#ifdef I2CHIP_MMC +#include "mmc.h" +#endif + +void i2chip_init(void) +{ + +#ifdef TERN_586 +/* + poke(MMCR,_BOOTCSCTL_,peek(MMCR,_BOOTCSCTL_)&0xffc9); // ROM 1 wait + poke(MMCR,_ROMCS2CTL_,peek(MMCR,_ROMCS2CTL_)&0xffc8); // SRAM 0 wait + + pokeb(MMCR, _GPCSRT_, 24); // set the GP CS recovery time, 12 works + pokeb(MMCR, _GPCSPW_, 128); // set the GP CS width, 64 works + pokeb(MMCR, _GPCSOFF_, 16); // set the GP CS offset, 8 works + pokeb(MMCR, _GPRDW_, 80); // set the GP RD pulse width, 50 works + pokeb(MMCR, _GPRDOFF_, 30); // set the GP RD offset, 15 works + pokeb(MMCR, _GPWRW_, 80); // set the GP WR pulse width, 50 + pokeb(MMCR, _GPWROFF_, 30); // set the GP WR offset, 15 +*/ + +#ifdef TERN_5E + pokeb(MMCR, _GPCSDW_, peekb(MMCR, _GPCSDW_)&0xf7); // set /CS3-/CSM Data Width=8 + pokeb(MMCR, _CSPFS_, peekb(MMCR, _CSPFS_)|0x08); // set the GP CS3 PIN Function + poke(MMCR, _PAR15_, 0x2000); // set CS3 I/O region + poke(MMCR, _PAR15_+2, 0x2dff); // set CS3 I/O region, 512 bytes + + pokeb(MMCR, _GPCSDW_, peekb(MMCR, _GPCSDW_)&0x7f); // CS7=J4.3 Data Width=8, /CSI +// pokeb(MMCR, _GPCSDW_, peekb(MMCR, _GPCSDW_)|0x80); // CS7=J4.3 Data Width=16 + pokeb(MMCR, _CSPFS_, peekb(MMCR, _CSPFS_)|0x80); // set the GP CS7 PIN Function + poke(MMCR, _PAR7_, 0x4000); // set CS7 I/O region + poke(MMCR, _PAR7_+2, 0x3dff); // set CS7 I/O region, 512 bytes +#else + // If it's not 5E, then it must be 5P... in which case, we use PCS0 and + // PCS1 as the chip-selects. + pokeb(MMCR, _GPCSDW_, peekb(MMCR, _GPCSDW_)&0xfe); // CS0 Data Width=8 + poke(MMCR, _PIOPFS31_16_, peek(MMCR,_PIOPFS31_16_)|0x0800); // P27=/CS0 + poke(MMCR, _PAR13_, 0x1800); // CS0 I/O region + poke(MMCR, _PAR13_+2, 0x21ff); // CS0 I/O RW, 512 bytes, start 0x1800 +#endif + +a HLPRsetvect(0x47, (void far *) spu_m_isr); + HLPRsetvect(0x4f, (void far *) spu_1_isr); + HLPRsetvect(0x57, (void far *) spu_2_isr); +#endif // 186, or RE + +#ifdef TERN_186 + pio_init(18, 0); // P18=CTS1 for /PCS2 + +#ifdef TERN_16_BIT + outport(0xfff2, 2); // AUXCON, MCS, Bus 16-bit +#endif + +#ifdef I2CHIP_MCS_DIRECT + outport(0xffa0,0xc0bf); // UMCS, 256K ROM, disable AD15-0 + outport(0xfff0,inport(0xfff0)|0x4000 ); // SYSCON, MCS0 0x80000-0xbffff + outport(0xffa8,0xa0bf ); // MPCS, MCS0=P14, 64KB, PCS I/O, + outport(0xffa6,0x81ff); // MMCS, base 0x80000, + outport(0xffa2,0x7fbf); // 512K RAM, + outport(0xffa4,0x007d); // PACS, base 0, + +#else + + outport( 0xffa0,0xc0bf); // UMCS, 256K ROM, 3 wait, disable AD15-0 + outport( 0xfff0,inport(0xfff0)|0x4000 ); // SYSCON, MCS0 0x80000-0xbffff +// outport( 0xffa8,0xa0bc ); // MPCS, MCS0=P14, 64KB, PCS I/O 0 wait +// outport( 0xffa8,0xa0bd ); // MPCS, MCS0=P14, 64KB, PCS I/O 1 wait + outport( 0xffa8,0xa0bf ); // MPCS, MCS0=P14, 64KB, PCS I/O 1 wait +#endif // I2CHIP_MCS_DIRECT + +#ifndef TERN_RE // 80 MHz R- boards can't tolerate zero wait state. + outport( 0xffa6,0x81ff ); // MMCS, base 0x80000 + outport(0xffa2,0x7fbe); // 512K RAM, 0 wait states + outport(0xffa4,0x007d); // PACS, base 0, 0 wait +#endif + pio_init(14,0); // Enable /MCS0 + +#endif // TERN_186 + + +#ifdef I2CHIP_WINDOW +#ifdef I2CHIP_SHIFTED_ADDRESS + pio_init(12, 2); // Configure P12 as A7, an output we'll be using. + pio_wr(12, 0); // Set A7 low, initially. +#endif + WINDOW_RESTORE_BASE; // Equivalent to calling mmc_window(7, 0); +#endif +} + +#ifdef I2CHIP_WINDOW + +void i2chip_set_page(u_int page) +{ + u_int new_page = page; + +#ifdef I2CHIP_SHIFTED_ADDRESS + if (page & 0x01) // ... we're checking the right-most bit in the page. + outport(0xff74, inport(0xff74) | 0x1000 ); // Using P12 as A7... + else + outport(0xff74, inport(0xff74) & 0xefff ); + + new_page = page >> 1; +#endif + +#ifdef I2CHIP_MMC + mmc_window(7, new_page); // See mmc.c +#endif +#ifdef I2CHIP_P51 + p51_window(new_page); +#endif +} + +static u_int s_addr = 0xffff; +u_char far* i2chip_mkptr(u_int addr) +{ + if ((s_addr & 0xff00) == (addr & 0xff00)) // No point... no point... + return MK_FP(WINDOW_BASE_SEGM, addr & 0xff); + + s_addr = addr ; + + // So the argument to this function is... what again? + // I think it should be the highest 16-bits... or, in other words, + // FP_SEG of a huge ptr. + // Ok, and the *return* value should be a UINT value for the new + // segment address to be used, if it's at all needed. TODO + I2CHIP_SET_PAGE(s_addr >> 8); // Portable version +// outportb(0x00, addr>>8); // quicker version + + return MK_FP(WINDOW_BASE_SEGM, addr & 0xff); +} + +void i2chip_set_window(u_int window_addr) +{ + s_addr = window_addr; + I2CHIP_SET_PAGE(s_addr >> 8); +} + +// Still inside #define I2CHIP_WINDOW ... + +u_int i2chip_get_window(void) +{ + return s_addr & 0xff00; +} + +void i2chip_push_window(u_int addr) +{ + I2CHIP_SET_PAGE(addr>>8); +} + +void i2chip_pop_window(void) +{ + I2CHIP_SET_PAGE(s_addr >> 8); +} + +#ifdef I2CHIP_WINDOW_IO +u_char io_read_value(u_char far* addr) +{ + // return value ... we assume the page is already set. So, instead, + // we just go ahead and output valeu. + return inportb(I2CHIP_BASE_SEG + (FP_OFF(addr) & 0xff)); +} + +void io_write_value(u_char far* addr, u_char value) +{ + // Get the last whatever bytes... and write value. + outportb(I2CHIP_BASE_SEG + (FP_OFF(addr) & 0xff), value); +} + +#endif // I2CHIP_WINDOW_IO + + +#ifdef I2CHIP_P51 +void p51_window(unsigned int page) +{ +asm xor ax, ax +asm mov ax, page +#ifdef I2CHIP_WINDOW_IO +asm mov dx, 1040h +asm out dx, al +#else +asm out 040h, al +#endif +// use J1.19=/CS6 +} +#endif // I2CHIP_P51 + +#endif // I2CHIP_WINDOW + +#ifdef TERN_586 +/* +// Function: spu_m_isr +// P22=Master PIC IR7, interrupt vector=0x47, /INTA +*/ +void interrupt far spu_m_isr(void) +{ +disable(); +// Issue the EOI to interrupt controller +outportb(_MPICOCW2_IO,0x67); // Specific EQI for master IR7 +enable(); +} + +/* +// Function: spu_1_isr +// P10=slave1 PIC IR7, Master IR2, interrupt vector=0x4f, /INTC +*/ +void interrupt far spu_1_isr(void) +{ +disable(); +// Issue the EOI to interrupt controller + outportb(_S1PICOCW2_IO,0x67); // Specific EOI for slave 1 IR7 + outportb(_MPICOCW2_IO,0x62); // Specific EQI for master IR2 +enable(); +} + +/* +// Function: spu_2_isr +// P20=Slave2 PIC IR7, Master IR5, interrupt vector=0x57, GPIRQ7=PIO16 GP timer1 +*/ +void interrupt far spu_2_isr(void) +{ +disable(); +// Issue the EOI to interrupt controller + outportb(_S2PICOCW2_IO,0x67); // Specific EOI for slave 1 IR7 + outportb(_MPICOCW2_IO,0x65); // Specific EQI for master IR5 +enable(); +} +#endif diff --git a/Demo/WizNET_DEMO_TERN_186/include/SOCKET.H b/Demo/WizNET_DEMO_TERN_186/include/SOCKET.H new file mode 100644 index 000000000..b3f7b6cf2 --- /dev/null +++ b/Demo/WizNET_DEMO_TERN_186/include/SOCKET.H @@ -0,0 +1,247 @@ +/* +******************************************************************************** +* TERN, Inc. +* (c) Copyright 2005, http://www.tern.com +* +* - Derived based on development version provided by Wiznet. +* +* Filename : socket.h +* Programmer(s): +* Created : 2002/06/20 +* Modified : +* 2002/09/27 : - Renaming +* INT_STATUS --> INT_REG +* STATUS(i) --> INT_STATUS(i) +* C_STATUS(i) --> SOCK_STATUS(i) +* 2003/11/06 : Ported for use with TERN controller. Note all byte access is at even addresses +* 2005/10/8 : Modified constants for easier initialization. +* +* Description : Header file of W3100A for TERN embedded controller +******************************************************************************** +*/ +#ifndef __SOCKET_H__ +#define __SOCKET_H__ + +#include "types.h" +#include "i2chip_hw.h" +#include + +/*******************************************************************/ +#define MAX_SOCK_NUM 4 // Concurrent maxmium number of socket + +#define I2CHIP_C0_CR 0x00 +#define I2CHIP_C1_CR 0x01 +#define I2CHIP_C2_CR 0x02 +#define I2CHIP_C3_CR 0x03 +#define I2CHIP_C0_ISR 0x04 +#define I2CHIP_C1_ISR 0x05 +#define I2CHIP_C2_ISR 0x06 +#define I2CHIP_C3_ISR 0x07 +#define I2CHIP_IR 0x08 +#define I2CHIP_IMR 0x09 + +#define I2CHIP_IDM_OR 0x0C +#define I2CHIP_IDM_AR0 0x0D +#define I2CHIP_IDM_AR1 0x0E +#define I2CHIP_IDM_DR 0x0F +#define I2CHIP_C0_RW_PR 0x10 +#define I2CHIP_C0_RR_PR 0x14 +#define I2CHIP_C0_TA_PR 0x18 +#define I2CHIP_C1_RW_PR 0x1C +#define I2CHIP_C1_RR_PR 0x20 +#define I2CHIP_C1_TA_PR 0x24 +#define I2CHIP_C2_RW_PR 0x28 +#define I2CHIP_C2_RR_PR 0x2C +#define I2CHIP_C2_TA_PR 0x30 +#define I2CHIP_C3_RW_PR 0x34 +#define I2CHIP_C3_RR_PR 0x38 +#define I2CHIP_C3_TA_PR 0x3C +#define I2CHIP_C0_TW_PR 0x40 +#define I2CHIP_C0_TR_PR 0x44 +#define I2CHIP_C1_TW_PR 0x4C +#define I2CHIP_C1_TR_PR 0x50 +#define I2CHIP_C2_TW_PR 0x58 +#define I2CHIP_C2_TR_PR 0x5C +#define I2CHIP_C3_TW_PR 0x64 +#define I2CHIP_C3_TR_PR 0x68 +#define I2CHIP_GAR 0x80 +#define I2CHIP_SMR 0x84 +#define I2CHIP_SHAR 0x88 +#define I2CHIP_SIPR 0x8E +#define I2CHIP_IRTR 0x92 +#define I2CHIP_RCR 0x94 +#define I2CHIP_RMSR 0x95 +#define I2CHIP_TMSR 0x96 +#define I2CHIP_C0_SSR 0xA0 +#define I2CHIP_C0_SOPR 0xA1 +#define I2CHIP_C0_DIR 0xA8 +#define I2CHIP_CO_DPR 0xAC +#define I2CHIP_C0_SPR 0xAE +#define I2CHIP_C0_IPR 0xB0 +#define I2CHIP_C0_TOSR 0xB1 +#define I2CHIP_C0_MSSR 0xB2 + +#define I2CHIP_C1_SSR 0xB8 +#define I2CHIP_C1_SOPR 0xB9 +#define I2CHIP_C1_DIR 0xC0 +#define I2CHIP_C1_DPR 0xC4 +#define I2CHIP_C1_SPR 0xC6 +#define I2CHIP_C1_IPR 0xC8 +#define I2CHIP_C1_TOSR 0xC9 +#define I2CHIP_C1_MSSR 0xCA + +#define I2CHIP_C2_SSR 0xD0 +#define I2CHIP_C2_SOPR 0xD1 +#define I2CHIP_C2_DIR 0xD8 +#define I2CHIP_C2_DPR 0xDC +#define I2CHIP_C2_SPR 0xDE +#define I2CHIP_C2_IPR 0xE0 +#define I2CHIP_C2_TOSR 0xE1 +#define I2CHIP_C2_MSSR 0xE2 + +#define I2CHIP_C3_SSR 0xE8 +#define I2CHIP_C3_SOPR 0xE9 +#define I2CHIP_C3_DIR 0xF0 +#define I2CHIP_C3_DPR 0xF4 +#define I2CHIP_C3_SPR 0xF6 +#define I2CHIP_C3_IPR 0xF8 +#define I2CHIP_C3_TOSR 0xF9 +#define I2CHIP_C3_MSSR 0xFA + +#define MAX_SEGMENT_SIZE 1460 // Maximum TCP transmission packet size +#define MAX_BUF_SIZE1 0 + + +/* SOCKET OPTION(Settting OPT_PROTOCOL REG.) */ +#define SOCKOPT_BROADCAST 0x80 // Transmission, Reception of broadcasting data +#define SOCKOPT_NDTIMEOUT 0x40 // Setting timeout +#define SOCKOPT_NDACK 0x20 // Setting No Delayed Ack(TCP) +#define SOCKOPT_SWS 0x10 // Setting Silly Window Syndrome(TCP) + +/* OPTION(Setting OPT_PROTOCOL REG.) for MAC LAYER RAW MODE */ +#define MACLOPT_RXERR 0x80 // Setting reception of error packet +#define MACLOPT_BROADCAST 0x40 // Setting reception of broadcast packet +#define MACLOPT_PROMISC 0x20 // Setting reception of promiscuous packet + +/* Distinguish TCP / UDP / IP RAW / MAC RAW (Setting OPT_PROTOCOL REG.) */ +#define SOCK_CLOSEDM 0x00 // unused socket +#define SOCK_STREAM 0x01 // TCP +#define SOCK_DGRAM 0x02 // UDP +#define SOCK_IPL_RAW 0x03 // IP LAYER RAW SOCK +#define SOCK_MACL_RAW 0x04 // MAC LAYER RAW SOCK + +/* Setting IP PROTOCOL */ +#define IPPROTO_IP 0 // dummy for IP +#define IPPROTO_ICMP 1 // control message protocol +#define IPPROTO_IGMP 2 // internet group management protocol +#define IPPROTO_GGP 3 // gateway^2 (deprecated) +#define IPPROTO_TCP 6 // tcp +#define IPPROTO_PUP 12 // pup +#define IPPROTO_UDP 17 // user datagram protocol +#define IPPROTO_IDP 22 // xns idp +#define IPPROTO_ND 77 // UNOFFICIAL net disk proto +#define IPPROTO_RAW 255 // raw IP packet + +/* Select parameter to use */ +#define SEL_CONTROL 0 //Confirm socket status +#define SEL_SEND 1 // Confirm Tx free buffer size +#define SEL_RECV 2 // Confirm Rx data size + +/* Command variables */ +#define CSYS_INIT 0x01 // To set up network information(mac address, gateway address, + // subnet mask, source ip) +#define CSOCK_INIT 0x02 // To initialize socket +#define CCONNECT 0x04 // To establish connection as tcp client mode +#define CLISTEN 0x08 // To wait for connection request as tcp server mode +#define CCLOSE 0x10 // To terminate connection +#define CSEND 0x20 // To send data +#define CRECV 0x40 // To receive data +#define CSW_RESET 0x80 // To do software reset + +#define CSET_MEMORY_TEST 0x80 // To set the memory test bit +#define CRESET_MEMORY_TEST 0x00 // To clear the memory test bit + +/* Status Variables */ +#define SSYS_INIT_OK 0x01 // Completion of CSYS_INIT command +#define SSOCK_INIT_OK 0x02 // Completion of CSOCK_INIT command +#define SESTABLISHED 0x04 // Completion of connection setup +#define SCLOSED 0x08 // Completion of CCLOSED command +#define SSEND_OK 0x20 // Completion of sending data +#define SRECV_OK 0x40 // Completion of receiving data + +/* Socket Status Vabiables */ +#define SOCK_CLOSED 0x00 // Status of connection closed +#define SOCK_ARP 0x01 // Status of ARP +#define SOCK_LISTEN 0x02 // Status of waiting for TCP connection setup +#define SOCK_SYNSENT 0x03 // Status of setting up TCP connection +#define SOCK_SYNSENT_ACK 0x04 // Status of setting up TCP connection +#define SOCK_SYNRECV 0x05 // Status of setting up TCP connection +#define SOCK_ESTABLISHED 0x06 // Status of TCP connection established +#define SOCK_CLOSE_WAIT 0x07 // Status of closing TCP connection +#define SOCK_LAST_ACK 0x08 // Status of closing TCP connection +#define SOCK_FIN_WAIT1 0x09 // Status of closing TCP connection +#define SOCK_FIN_WAIT2 0x0A // Status of closing TCP connection +#define SOCK_CLOSING 0x0B // Status of closing TCP connection +#define SOCK_TIME_WAIT 0x0C // Status of closing TCP connection +#define SOCK_RESET 0x0D // Status of closing TCP connection +#define SOCK_INIT 0x0E // Status of socket initialization +#define SOCK_UDP 0x0F // Status of UDP +#define SOCK_RAW 0x10 // Status of IP RAW + +/* TERN Behavior Parameters */ +#define TERN_TDMA_THRES 10000 // Use DMA for transmits if data > thres bytes. +#define TERN_RDMA_THRES 10000 // Use DMA for receives if data > thres bytes. + // High thres value effectively disables DMA + +void far interrupt in4_isr_i2chip(void); + +//void ISR_ESTABLISHED(SOCKET s); +//void ISR_CLOSED(SOCKET s); +//void ISR_RX(SOCKET s); + +void initW3100A(void); +void sysinit(u_char sbufsize, u_char rbufsize); +void setsubmask(u_char * addr); +void setgateway(u_char * addr); +void setMACAddr(u_char * addr); +void setIP(u_char * addr); + +char socket(SOCKET s, u_char protocol, u_int port, u_char flag); + +void setIPprotocol(SOCKET s, u_char ipprotocol); + +void setINTMask(u_char mask); +void settimeout(u_char * val); +void setTOS(SOCKET s, u_char tos); + +void GetDestAddr(SOCKET s, u_char* addr); + +//void setbroadcast(SOCKET s); + +char connect(SOCKET s, u_char far * addr, u_int port); +char NBconnect(SOCKET s, u_char far * addr, u_int port); + +//char listen(SOCKET s, u_char far * addr, u_int far * port); +char NBlisten(SOCKET s); + +void initseqnum(SOCKET s); + +int send(SOCKET s, u_char far * buf, u_int len); +int send_in(SOCKET s, u_char far * buf, u_int len); +int recv(SOCKET s, u_char far * buf, u_int len); + +u_int sendto(SOCKET , u_char far * buf, u_int, u_char * addr, u_int); +u_int sendto_in(SOCKET , u_char far *, u_int); +u_int recvfrom(SOCKET , u_char far * buf, u_int, u_char * addr, u_int *); + +u_int read_data(SOCKET s, u_int src_offset, u_char far * dst, u_int len); +u_int write_data(SOCKET s, u_char far * src, u_int dst_offset, u_int len); + +void close(SOCKET s); +char reset_sock(SOCKET s); + +u_int select(SOCKET s, u_char func); +void recv_clear(SOCKET s); +u_char tx_empty(SOCKET s); + +#endif // __SOCKET_H__ diff --git a/Demo/WizNET_DEMO_TERN_186/include/TYPES.H b/Demo/WizNET_DEMO_TERN_186/include/TYPES.H new file mode 100644 index 000000000..eb4551e94 --- /dev/null +++ b/Demo/WizNET_DEMO_TERN_186/include/TYPES.H @@ -0,0 +1,64 @@ +/* +******************************************************************************** +* Wiznet. +* 5F Simmtech Bldg., 228-3, Nonhyun-dong, Kangnam-gu, +* Seoul, Korea +* +* (c) Copyright 2002, Wiznet, Seoul, Korea +* +* Filename : types.h +* Programmer(s): +* Created : 2002/01/ +* Modified : +* Description : Define of data type. +******************************************************************************** +*/ + +#ifndef _TYPES_H_ +#define _TYPES_H_ + +#ifndef NULL +# define NULL ((void *) 0) +#endif + +typedef enum { false, true } bool; + +#ifndef _SIZE_T +#define _SIZE_T +typedef unsigned int size_t; +#endif + +typedef unsigned char BYTE; // 8-bit value +typedef unsigned char UCHAR; // 8-bit value +typedef int INT; // 16-bit value +typedef unsigned int UINT; // 16-bit value +typedef unsigned short USHORT; // 16-bit value +typedef unsigned short WORD; // 16-bit value +typedef unsigned long ULONG; // 32-bit value +typedef unsigned long DWORD; // 32-bit value + +// bsd +typedef unsigned char u_char; // 8-bit value +typedef unsigned short u_short; // 16-bit value +typedef unsigned int u_int; // 16-bit value +typedef unsigned long u_long; // 32-bit value + +typedef UCHAR SOCKET; + + +/* Type for treating 4 byte variables with byte by byte */ +typedef union un_l2cval + { + u_long lVal; + u_char cVal[4]; + }; + +/* Type for treating 2 byte variables with byte by byte */ +typedef union un_i2cval + { + u_int iVal; + u_char cVal[2]; + }; + +#endif // _TYPES_H_ + diff --git a/Demo/WizNET_DEMO_TERN_186/include/ae.H b/Demo/WizNET_DEMO_TERN_186/include/ae.H new file mode 100644 index 000000000..060c7efb0 --- /dev/null +++ b/Demo/WizNET_DEMO_TERN_186/include/ae.H @@ -0,0 +1,264 @@ +#ifndef _AE_H_ +#define _AE_H_ + +/********************************************************************* + ae.h headers for AM188ES 6-20-99 7-16-98 +*********************************************************************/ +/* Data structure for Serial operation */ + +typedef struct { + unsigned char ready; /* TRUE when ready */ + unsigned char baud; + unsigned int mode; + unsigned char iflag; /* interrupt status */ + unsigned char* in_buf; /* Input buffer */ + unsigned int in_tail; /* Input buffer TAIL ptr */ + unsigned int in_head; /* Input buffer HEAD ptr */ + unsigned int in_size; /* Input buffer size */ + unsigned int in_crcnt; /* Input count */ + unsigned char in_mt; /* Input buffer FLAG */ + unsigned char in_full; /* input buffer full */ + unsigned char* out_buf; /* Output buffer */ + unsigned int out_tail; /* Output buffer TAIL ptr */ + unsigned int out_head; /* Output buffer HEAD ptr */ + unsigned int out_size; /* Output buffer size */ + unsigned char out_full; /* Output buffer FLAG */ + unsigned char out_mt; /* Output buffer MT */ + unsigned char tmso; // transmit macro service operation + unsigned char rts; + unsigned char dtr; + unsigned char en485; + unsigned char err; + unsigned char node; + unsigned char cr; /* scc CR register */ + unsigned char slave; + unsigned int in_segm; /* input buffer segment */ + unsigned int in_offs; /* input buffer offset */ + unsigned int out_segm; /* output buffer segment */ + unsigned int out_offs; /* output buffer offset */ + unsigned char byte_delay; /* V25 macro service byte delay */ +} COM; + + +typedef struct{ + unsigned char sec1; + unsigned char sec10; + unsigned char min1; + unsigned char min10; + unsigned char hour1; + unsigned char hour10; + unsigned char day1; + unsigned char day10; + unsigned char mon1; + unsigned char mon10; + unsigned char year1; + unsigned char year10; + unsigned char wk; +} TIM; + +void ae_init(void); +void ae_reset(void); +void led(int i); //P12 used for led +void delay_ms(int m); +void delay0(unsigned int t); +void HLPRsetvect( + unsigned int wVec, /* Interrupt vector number */ + void far *ih /* Interrupt handler to install */ + ); + +void clka_en(int i); +void clkb_en(int i); +void pwr_save_en(int i); +void hitwd(void); + +// +// reset ee to remain enabled for reads +// where s = segment register value pointing to ee starting addr. +// for example = 0x8000 +// +void amd_ee_read_reset(unsigned int s); + +// +// sec=0x00-0x07 for AM29F010, 16K/sector +// sec=0 0x00000-0x03fff +// sec=1 0x04000-0x07fff +// sec=2 0x08000-0x0bfff +// sec=3 0x0c000-0x0ffff +// sec=4 0x10000-0x13fff +// sec=5 0x14000-0x17fff +// sec=6 0x18000-0x1bfff +// sec=7 0x1c000-0x1ffff +// +// sec=0x10-0x17 for AM29F040 +// sec=10 0x00000-0x0ffff +// sec=11 0x10000-0x1ffff +// sec=12 0x20000-0x2ffff +// sec=13 0x30000-0x3ffff +// sec=14 0x40000-0x4ffff +// sec=15 0x50000-0x5ffff +// sec=16 0x60000-0x6ffff +// sec=17 0x70000-0x7ffff +// segm=segment register value pointing to ee address 0 +// returns: if pass, return(0); +// if fail, return(1); +// +int amd_ee_sec_erase(unsigned int segm, unsigned char sec ); + +// +// write one byte dat to AM29F040, at address of s:o +// Approximately 70 us for 0 wait, 80us for 1 wait. +// where s=segment register, it is fixed to 0x8000 +// o=offset register +// returns: if pass, return(0); +// if fail, return(1); +// +// Be aware of that a data bit "0" can not be programmed back to a "1" !!! +// Attempting to do so will hang up the system !!! +// you can program the "1"s to "0"s. +// Only erase operation can convert "0"s to "1"s +// +// + +int amd_ee_byte_pro_512(unsigned int s, unsigned int o, unsigned char dat); + +// +// write one byte dat to AM29F010, at address of s:o, 80us per byte approx. +// where s=segment register, you may use s=0x8000-0xe000 +// o=offset register +// returns: if pass, return(0); +// if fail, return(1); +// +// Be aware of that a data bit "0" can not be programmed back to a "1" !!! +// Attempting to do so will hang up the system !!! +// you can program the "1"s to "0"s. +// Only erase operation can convert "0"s to "1"s +// + +int amd_ee_byte_pro_128(unsigned int s, unsigned int o, unsigned char dat); + +// +// unsigned char rtc_rds(char* time_string); +// put a time string into time_string, based on the reading of RTC. +// At least 15 bytes of buffer must be available for the time_string +// returns 0, if RTC OK, or returns 1, if problem +// +unsigned char rtc_rds(char* time_string); +int rtc_rd(TIM *r); +void rtc_init(unsigned char*); +unsigned char r_rd(void); +int r_out(unsigned char v); + + +void t2_init(unsigned int tm,unsigned int ta,void interrupt far(*t2_isr)()); +void t1_init(unsigned int tm,unsigned int ta,unsigned int tb,void interrupt far(*t1_isr)()); +void t0_init(unsigned int tm,unsigned int ta,unsigned int tb,void interrupt far(*t0_isr)()); +unsigned int t2_rd(void); +unsigned int t1_rd(void); +unsigned int t0_rd(void); + +// Analog to Digital conversion using TLC2543 on the A-Engine-88/86 +// Input: +// unsigned char c = input channel +// c = 0, input ch = AD0 +// c = 1, input ch = AD1 +// c = 2, input ch = AD2 +// c = 3, input ch = AD3 +// c = 4, input ch = AD4 +// c = 5, input ch = AD5 +// c = 6, input ch = AD6 +// c = 7, input ch = AD7 +// c = 8, input ch = AD8 +// c = 9, input ch = AD9 +// c = a, input ch = AD10 +// In order to operate ADC, P11 must be input. +// P11 is shared by RTC, EE. It must be high while power on/reset +// For AE88, using PPI for ADC, I20,I21,I22 must be output +// For AE86, using PAL for ADC, T0=CLK, T1=DIN, T2=ADCS +// Enter the ae_ad12(unsigned char c); EE is stopped first. +// Enter the ae86_ad12(unsigned char c); EE is stopped first. +// +// Output: 12 bit AD data of the previous channel ! +// Unipolar: +// (Vref+ - Vref-)=0x7ff +// Vref- = 0x000 +// Vref+ = 0xfff +// +// +int ae_ad12(unsigned char c); + +// outportb(0x120,1); // T0=0, CLK +// outportb(0x128,1); // T1=0, DIN +// outportb(0x130,1); // T2=0, ADCS +int ae86_ad12(unsigned char c); + +void nmi_init(void interrupt far (* nmi_isr)()); +void int0_init(unsigned char i, void interrupt far (*int0_isr)()); +void int1_init(unsigned char i, void interrupt far (*int1_isr)()); +void int2_init(unsigned char i, void interrupt far (*int2_isr)()); +void int3_init(unsigned char i, void interrupt far (*int3_isr)()); +void int4_init(unsigned char i, void interrupt far (*int4_isr)()); +void int5_init(unsigned char i, void interrupt far (*int5_isr)()); +void int6_init(unsigned char i, void interrupt far (*int6_isr)()); + + +// +// void pio_init(char bit, char mode) +// where bit=0-31 +// mode=0, Normal operation +// mode=1, Input with pullup/down +// mode=2, Output +// mode=3, input without pull +// +void pio_init(char bit, char mode); + + +// +// void pio_wr(char bit, char dat) +// where bit=0-31 +// dat=0/1 +// +void pio_wr(char bit, char dat); + +// +// unsigned int pio_rd(char port) +// return P15-P0, if port=0 +// return P31-P16, if port=1 +// +unsigned int pio_rd(char port); + +// setup I/O wait states for I/O instructions +// where wait = 0-7 +// wait=0, wait states = 0, I/O enable for 100 ns +// wait=1, wait states = 1, I/O enable for 100+25 ns +// wait=2, wait states = 2, I/O enable for 100+50 ns +// wait=3, wait states = 3, I/O enable for 100+75 ns +// wait=4, wait states = 5, I/O enable for 100+125 ns +// wait=5, wait states = 7, I/O enable for 100+175 ns +// wait=6, wait states = 9, I/O enable for 100+225 ns +// wait=7, wait states = 15, I/O enable for 100+375 ns +void io_wait(char wait); + +unsigned int crc16(unsigned char *wptr, unsigned int count); + +/****************************************************** + void ae_da(int dat1, int dat2) + output dat to U11 DAC of AE88 + Requires P12=CLK, P26=DI, P29=LD/CS as output pins ! + where dat1 for channel A, dat2 for channel B; dat1/2 = 0-4095 +*******************************************************/ +void ae_da(int dat1, int dat2); + +/****************************************************** + void ae86_da(int dat1, int dat2) + output dat to U15 DAC of AE86 + Requires T0=CLK=0x120, T1=DI=0x128, T3=LD/CS=0x138 + where dat1 for channel A, dat2 for channel B; dat1/2 = 0-4095 + Output 0-2.5V at VA=J4.16, VB=J4.18 +*******************************************************/ +void ae86_da(int dat1, int dat2); +void interrupt reset_io_trap(); + +#endif + + + \ No newline at end of file diff --git a/Demo/WizNET_DEMO_TERN_186/include/i2chip_hw.h b/Demo/WizNET_DEMO_TERN_186/include/i2chip_hw.h new file mode 100644 index 000000000..2ea32c139 --- /dev/null +++ b/Demo/WizNET_DEMO_TERN_186/include/i2chip_hw.h @@ -0,0 +1,309 @@ +/* +******************************************************************************** +* TERN, Inc. +* (c) Copyright 2005, http://www.tern.com +* +* - Created to support i2chip module on a variety of TERN hardware platforms. +******************************************************************************** +*/ + +#ifndef _I2CHIP_HW_H_ +#define _I2CHIP_HW_H_ + +#include "types.h" + +#ifdef TERN_SC // SensorCore controller, has mapping identical to the RL +#define TERN_RL +#endif + +#ifdef TERN_RL // R-Engine-L controller, with mapping at MCS0. +#define I2CHIP_MCS_DIRECT +#define I2CHIP_INT4 +#define TERN_RE +#endif // TERN_RL + +#ifdef TERN_5E +#define TERN_586 +#endif + +#ifdef TERN_RD +#define TERN_RE +#endif // TERN_RD + +#ifdef TERN_RE +#define TERN_186 +#endif + +#ifdef TERN_P51 +void p51_window(unsigned int page); +#define I2CHIP_WINDOW +#define I2CHIP_P51 +#ifdef TERN_186 +#define I2CHIP_INT4 +#define TERN_16_BIT +#endif // TERN_186 +#ifdef TERN_586 +#define I2CHIP_INT0 +#define I2CHIP_WINDOW_IO +#endif // TERN_586 +#endif // TERN_P51 + +#ifdef TERN_CEYE +#define TERN_EE // C-Eye configured with onboard i2chip, same as EE +#endif + +#ifdef TERN_EE +#define TERN_186 +#define I2CHIP_MCS_DIRECT +#define I2CHIP_INT4 +#define TERN_16_BIT +#endif // TERN_EE + +#ifdef TERN_MMC +#define I2CHIP_WINDOW +#define I2CHIP_MMC +#ifdef TERN_RD +#define I2CHIP_INT3 +#else +#ifdef TERN_186 +#define I2CHIP_INT4 +#endif // TERN_186 +#endif // TERN_RD +#ifdef TERN_586 +#define I2CHIP_INT0 +#define I2CHIP_WINDOW_IO +#endif // TERN_586 +#endif // TERN_MMC + +#ifdef TERN_586 +#include "586.h" +void interrupt far int0_isr(void); +void interrupt far spu_m_isr(void); +void interrupt far spu_1_isr(void); +void interrupt far spu_2_isr(void); +#define MMCR 0xdf00 +#endif // TERN_586 + +#ifdef TERN_186 +#ifndef TERN_RE +#include "ae.h" +#else +#include "re.h" +#define I2CHIP_SHIFTED_ADDRESS +#endif +#endif + + +#ifndef I2CHIP_MCS_DIRECT +#ifndef I2CHIP_WINDOW +#ifndef I2CHIP_WINDOW_IO +#error You must define the TERN address mapping used to drive the I2CHIP module! +#endif // I2CHIP_WINDOW_IO +#endif // I2CHIP_MMC_WINDOW +#endif // I2CHIP_MCS_DIRECT + +#ifndef I2CHIP_INT0 +#ifndef I2CHIP_INT3 +#ifndef I2CHIP_INT4 +#ifndef I2CHIP_POLL +#error You must specify an interrupt/polling mechanism for the I2CHIP module! +#endif // I2CHIP_POLL +#endif // I2CHIP_INT3 +#endif // I2CHIP_INT4 +#endif // I2CHIP_INT0 + +#ifdef I2CHIP_POLL +#define I2CHIP_POLL_ISR(a) { delay_ms(20); disable(); a(); enable(); } +#define INT_INIT(isr) +#define INT_EOI +#endif // I2CHIP_POLL + +#ifdef I2CHIP_INT4 +#define INT_INIT(isr) int4_init(1, isr) +#define INT_EOI outport(0xff22,0x0010) +#define I2CHIP_POLL_ISR(a) +#endif + +#ifdef I2CHIP_INT3 +#define INT_INIT(isr) int3_init(1, isr) +#define INT_EOI outport(0xff22,0x000f) +#define I2CHIP_POLL_ISR(a) +#endif + +#ifdef I2CHIP_INT0 +#define INT_INIT(isr) int0_init(1, isr) +#define INT_EOI outportb(_MPICOCW2_IO,0x61); // 586 only EOI +#define I2CHIP_POLL_ISR(a) +#endif + + +#ifdef I2CHIP_SHIFTED_ADDRESS +#define SA_OFFSET(a) ((a) << 1) +#else +#define SA_OFFSET(a) a +#endif // I2CHIP_SHIFTED_ADDRESS ... *if* + + +// -------------------- WINDOW-RELATED DEFINES ---------------------- +#ifdef I2CHIP_WINDOW +void i2chip_set_page(u_int addr); +#define I2CHIP_SET_PAGE(p) i2chip_set_page(p) + +u_char far* i2chip_mkptr(u_int addr); +void i2chip_push_window(u_int addr); +void i2chip_pop_window(void); +u_int i2chip_get_window(void); +void i2chip_set_window(u_int window_addr); + +// Set to command window. +// Note that if you're using other MMC chips within your application, you will +// need to call this function regularly, if you've changed the MMC chip/page +// selection via mmc_window(). The driver code otherwise assume that you never +// change away from chip 7, page 0. +#define WINDOW_RESTORE_BASE i2chip_mkptr(0) + +// ----------------------- I2CHIP_WINDOW_IO ---------------------------- +#ifdef I2CHIP_WINDOW_IO + +#ifdef TERN_5E +#define I2CHIP_BASE_SEG 0x2000 // Address offset for W3100A +#else +#define I2CHIP_BASE_SEG 0x1800 // Address offset for W3100A +#endif + +#define COMMAND_BASE_SEG 0x0000 +#define SEND_DATA_BUF 0x4000 // Internal Tx buffer address of W3100A +#define RECV_DATA_BUF 0x6000 // Internal Rx buffer address of W3100A +#define WINDOW_BASE_SEGM COMMAND_BASE_SEG + +#define MK_FP_WINDOW(a, b) i2chip_mkptr(a+SA_OFFSET(b)) +#define MK_FP_SA MK_FP_WINDOW + +u_char io_read_value(u_char far* addr); +void io_write_value(u_char far* addr, u_char value); +#define READ_VALUE(a) io_read_value(a) +#define WRITE_VALUE(a, v) io_write_value(a, v) + +#define WINDOW_PTR_INC(a) \ + if ((FP_OFF(a) & 0xff) == 0xff) \ + a = MK_FP_WINDOW(i2chip_get_window() + 0x100, 0); \ + else \ + a++; + +#endif // I2CHIP_WINDOW_IO + +// -------------------- !NOT! I2CHIP_WINDOW_IO ---------------------------- +#ifndef I2CHIP_WINDOW_IO + +#define READ_VALUE(a) *(a) +#define WRITE_VALUE(a, v) *(a) = v + +#define WINDOW_BASE_SEGM 0x8000 +#define MK_FP_WINDOW(a, b) i2chip_mkptr(a+SA_OFFSET(b)) +#define MK_FP_SA MK_FP_WINDOW + +#ifdef I2CHIP_SHIFTED_ADDRESS +#define COMMAND_BASE_SEG 0x0000 +#define SEND_DATA_BUF 0x8000 +#define RECV_DATA_BUF 0xC000 +#define WINDOW_PTR_INC(a) \ + if ((FP_OFF(a) & 0xff) == 0xfe) \ + a = MK_FP_WINDOW(i2chip_get_window() + 0x100, 0); \ + else \ + a+=2; +#else +#define COMMAND_BASE_SEG 0x0000 +#define SEND_DATA_BUF 0x4000 +#define RECV_DATA_BUF 0x6000 +#define WINDOW_PTR_INC(a) \ + if ((FP_OFF(a) & 0xff) == 0xff) \ + a = MK_FP_WINDOW(i2chip_get_window() + 0x100, 0); \ + else \ + a++; +#endif // I2CHIP_SHIFTED_ADDRESS +#endif // NOT I2CHIP_WINDOW_IO + +#endif // I2CHIP_WINDOW + +// -------------------- I2CHIP_DIRECT ---------------------------- +#ifdef I2CHIP_MCS_DIRECT + +#define READ_VALUE(a) *(a) +#define WRITE_VALUE(a, v) *(a) = v + +#define I2CHIP_BASE_SEG 0x8000 +#define MK_FP_SA(a, b) MK_FP(a, SA_OFFSET(b)) +#define WINDOW_PTR_INC(a) a+=SA_OFFSET(1); +#define WINDOW_RESTORE_BASE +#define MK_FP_WINDOW MK_FP_SA +#define WINDOW_BASE_SEG I2CHIP_BASE_SEG +#define COMMAND_BASE_SEG I2CHIP_BASE_SEG + +#ifdef I2CHIP_SHIFTED_ADDRESS +#define SEND_DATA_BUF 0x8800 // Internal Tx buffer address of W3100A +#define RECV_DATA_BUF 0x8C00 // Internal Rx buffer address of W3100A +#else +#define SEND_DATA_BUF 0x8400 // Internal Tx buffer address of W3100A +#define RECV_DATA_BUF 0x8600 // Internal Rx buffer address of W3100A +#endif // I2CHIP_SHIFTED_ADDRESS + +#endif // I2CHIP_MCS_DIRECT + +/* Internal register set of W3100A */ +#define COMMAND(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, i))) +#define INT_STATUS(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, I2CHIP_C0_ISR + i))) +#define INT_REG ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, I2CHIP_IR))) +#define INTMASK ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, I2CHIP_IMR))) +#define RESETSOCK ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, 0x0A))) + +#define RX_PTR_BASE I2CHIP_C0_RW_PR +#define RX_PTR_SIZE (I2CHIP_C1_RW_PR - I2CHIP_C0_RW_PR) + +#define RX_WR_PTR(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, RX_PTR_BASE + RX_PTR_SIZE * i))) +#define RX_RD_PTR(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, RX_PTR_BASE + RX_PTR_SIZE * i + 0x04))) +#define RX_ACK_PTR(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, TX_PTR_BASE + TX_PTR_SIZE * i + 0x08))) + +#define TX_PTR_BASE I2CHIP_C0_TW_PR +#define TX_PTR_SIZE (I2CHIP_C1_TW_PR - I2CHIP_C0_TW_PR) + +#define TX_WR_PTR(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, TX_PTR_BASE + TX_PTR_SIZE * i))) +#define TX_RD_PTR(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, TX_PTR_BASE + TX_PTR_SIZE * i + 0x04))) +#define TX_ACK_PTR(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, RX_PTR_BASE + RX_PTR_SIZE * i + 0x08))) + +/* Shadow Register Pointer Define */ +/* For windowing purposes, these are definitely outside the first 256-byte Window... +therefore, use the MK_FP_WINDOW macros instead. */ +#define SHADOW_RXWR_PTR(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, 0x1E0 + 3*i))) +#define SHADOW_RXRD_PTR(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, 0x1E1 + 3*i))) +#define SHADOW_TXACK_PTR(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, 0x1E2 + 3*i))) +#define SHADOW_TXWR_PTR(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, 0x1F0 + 3*i))) +#define SHADOW_TXRD_PTR(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, 0x1F1 + 3*i))) + +#define SOCK_BASE I2CHIP_C0_SSR +#define SOCK_SIZE (I2CHIP_C1_SSR - I2CHIP_C0_SSR) + +#define SOCK_STATUS(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, SOCK_BASE + SOCK_SIZE * i))) +#define OPT_PROTOCOL(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, SOCK_BASE + SOCK_SIZE * i + 0x01))) +#define DST_HA_PTR(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, SOCK_BASE + SOCK_SIZE * i + 0x02))) +#define DST_IP_PTR(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, SOCK_BASE + SOCK_SIZE * i + 0x08))) +#define DST_PORT_PTR(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, SOCK_BASE + SOCK_SIZE * i + 0x0C))) +#define SRC_PORT_PTR(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, SOCK_BASE + SOCK_SIZE * i + 0x0E))) +#define IP_PROTOCOL(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, SOCK_BASE + SOCK_SIZE * i + 0x10))) +#define TOS(i) ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG,SOCK_BASE + SOCK_SIZE * i + 0x11))) +#define MSS(i) ((u_int far *)(MK_FP_WINDOW(COMMAND_BASE_SEG, SOCK_BASE + SOCK_SIZE * i + 0x12))) +#define P_WINDOW(i) ((u_int far *)(MK_FP_WINDOW(COMMAND_BASE_SEG,SOCK_BASE + SOCK_SIZE * i + 0x14))) +#define WINDOW(i) ((u_int far*)(MK_FP_WINDOW(COMMAND_BASE_SEG, SOCK_BASE + SOCK_SIZE * i + 0x16))) + +#define GATEWAY_PTR ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG,I2CHIP_GAR))) +#define SUBNET_MASK_PTR ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG,I2CHIP_SMR))) + +#define SRC_HA_PTR ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG,I2CHIP_SHAR))) +#define SRC_IP_PTR ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG,I2CHIP_SIPR))) +#define TIMEOUT_PTR ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG,I2CHIP_IRTR))) + +#define RX_DMEM_SIZE ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG,I2CHIP_RMSR))) +#define TX_DMEM_SIZE ((u_char far *)(MK_FP_WINDOW(COMMAND_BASE_SEG,I2CHIP_TMSR))) + +void i2chip_init(void); + +#endif // _irchip_hw_h diff --git a/Demo/WizNET_DEMO_TERN_186/include/utils/system_common.h b/Demo/WizNET_DEMO_TERN_186/include/utils/system_common.h new file mode 100644 index 000000000..1a40cf80d --- /dev/null +++ b/Demo/WizNET_DEMO_TERN_186/include/utils/system_common.h @@ -0,0 +1,12 @@ +#ifndef _SYSTEM_COMMON_H_ +#define _SYSTEM_COMMON_H_ + +typedef unsigned char UCHAR8; +typedef unsigned int UINT16; + +#define RETURN_OK 0 // Non-zero return values are always + // error values. +#define RETURN_ILLEGAL 1 // Some sort of illegal argument. +#define RETURN_MEM 2 // Out of memory space. + +#endif // _SYSTEM_COMMON_H_ \ No newline at end of file diff --git a/Demo/WizNET_DEMO_TERN_186/main.c b/Demo/WizNET_DEMO_TERN_186/main.c new file mode 100644 index 000000000..9a686d3bf --- /dev/null +++ b/Demo/WizNET_DEMO_TERN_186/main.c @@ -0,0 +1,196 @@ +/* + FreeRTOS V4.0.1 - Copyright (C) 2003-2006 Richard Barry. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + FreeRTOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with FreeRTOS; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + A special exception to the GPL can be applied should you wish to distribute + a combined work that includes FreeRTOS, without being obliged to provide + the source code for any proprietary components. See the licensing section + of http://www.FreeRTOS.org for full details of how and when the exception + can be applied. + + *************************************************************************** + See http://www.FreeRTOS.org for documentation, latest information, license + and contact details. Please ensure to read the configuration and relevant + port sections of the online documentation. + *************************************************************************** +*/ + +/* + * Creates all the demo application tasks then starts the scheduler. In + * addition to the standard demo application tasks main() creates the + * HTTPServer task, and a "Check" task. The Check task periodically inspects + * all the other tasks in the system to see if any errors have been reported. + * The error status is then displayed on the served WEB page. + */ + +/* Tern includes. */ +#include +#include + +/* FreeRTOS.org includes. */ +#include +#include + +/* Demo application includes. */ +#include "HTTPTask.h" +#include "integer.h" +#include "PollQ.h" +#include "semtest.h" +#include "dynamic.h" +#include "BlockQ.h" +#include "Death.h" +#include "serial.h" +#include "comtest.h" + +/* How often should the "check" task execute? */ +#define mainCHECK_DELAY ( 3000 / portTICK_RATE_MS ) + +/* Priorities allocated to the various tasks. */ +#define mainQUEUE_POLL_PRIORITY ( tskIDLE_PRIORITY + 2 ) +#define mainCHECK_TASK_PRIORITY ( tskIDLE_PRIORITY + 4 ) +#define mainSEM_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 ) +#define mainBLOCK_Q_PRIORITY ( tskIDLE_PRIORITY + 2 ) +#define mainHTTP_TASK_PRIORITY ( tskIDLE_PRIORITY + 3 ) +#define mainSUICIDE_TASKS_PRIORITY ( tskIDLE_PRIORITY + 1 ) +#define mainCOM_TEST_PRIORITY ( tskIDLE_PRIORITY + 2 ) + +/* Used to indicate the error status. A value of 0 means that an error has not +been detected in any task. A non zero value indicates which group of demo +tasks has reported an error. See prvCheckTask() for bit definitions. */ +unsigned portSHORT usCheckStatus = 0; + +/*-----------------------------------------------------------*/ + +/* + * Setup any hardware required by the demo - other than the RTOS tick which + * is configured when the scheduler is started. + */ +static void prvSetupHardware( void ); + +/* + * Periodically inspect all the other tasks, updating usCheckStatus should an + * error be discovered in any task. + */ +static void prvCheckTask( void *pvParameters ); +/*-----------------------------------------------------------*/ + +void main(void) +{ + prvSetupHardware(); + + /* Start the HTTP server task. */ + xTaskCreate( vHTTPTask, "WizNet", configMINIMAL_STACK_SIZE, NULL, mainHTTP_TASK_PRIORITY, NULL ); + + /* Start the demo/test application tasks. See the demo application + section of the FreeRTOS.org WEB site for more information. */ + vStartIntegerMathTasks( tskIDLE_PRIORITY ); + vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY ); + vStartSemaphoreTasks( mainSEM_TEST_PRIORITY ); + vStartDynamicPriorityTasks(); + vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY ); + vStartComTestTasks( mainCOM_TEST_PRIORITY, serCOM2, ser57600 ); + + /* Start the task that checks the other demo tasks for errors. */ + xTaskCreate( prvCheckTask, "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL ); + + /* The suicide tasks must be created last as they monitor the number of + tasks in the system to ensure there are no more or fewer than expected + compared to the number that were executing when the task started. */ + vCreateSuicidalTasks( mainSUICIDE_TASKS_PRIORITY ); + + /* Finally start the scheduler. */ + vTaskStartScheduler(); + + /* Should not get here! */ + for( ;; ); +} +/*-----------------------------------------------------------*/ + +static void prvSetupHardware( void ) +{ + ae_init(); +} +/*-----------------------------------------------------------*/ + +static void prvCheckTask( void *pvParameters ) +{ + ( void ) pvParameters; + + /* Check all the demo tasks to ensure that they are all still running, and + that none of them have detected an error. */ + for( ;; ) + { + /* Block until it is time to check again. */ + vTaskDelay( mainCHECK_DELAY ); + + if( xAreIntegerMathsTaskStillRunning() != pdTRUE ) + { + usCheckStatus |= 0x01; + } + + if( xArePollingQueuesStillRunning() != pdTRUE ) + { + usCheckStatus |= 0x02; + } + + if( xAreSemaphoreTasksStillRunning() != pdTRUE ) + { + usCheckStatus |= 0x04; + } + + if( xAreDynamicPriorityTasksStillRunning() != pdTRUE ) + { + usCheckStatus |= 0x08; + } + + if( xAreBlockingQueuesStillRunning() != pdTRUE ) + { + usCheckStatus |= 0x10; + } + + if( xIsCreateTaskStillRunning() != pdTRUE ) + { + usCheckStatus |= 0x20; + } + + if( xAreComTestTasksStillRunning() != pdTRUE ) + { + usCheckStatus |= 0x40; + } + } +} +/*-----------------------------------------------------------*/ + +/* This is included to prevent link errors - allowing the 'full' version of +the comtest tasks to be used. It can be ignored. */ +void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend ) +{ + ( void ) ppcMessageToSend; +} + + + + + + + + + + + + diff --git a/Demo/WizNET_DEMO_TERN_186/serial/serial.c b/Demo/WizNET_DEMO_TERN_186/serial/serial.c new file mode 100644 index 000000000..628e147f5 --- /dev/null +++ b/Demo/WizNET_DEMO_TERN_186/serial/serial.c @@ -0,0 +1,442 @@ +/* + FreeRTOS V4.0.1 - Copyright (C) 2003-2006 Richard Barry. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + FreeRTOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with FreeRTOS; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + A special exception to the GPL can be applied should you wish to distribute + a combined work that includes FreeRTOS, without being obliged to provide + the source code for any proprietary components. See the licensing section + of http://www.FreeRTOS.org for full details of how and when the exception + can be applied. + + *************************************************************************** + See http://www.FreeRTOS.org for documentation, latest information, license + and contact details. Please ensure to read the configuration and relevant + port sections of the online documentation. + *************************************************************************** +*/ + + +#include +#include +#include "FreeRTOS.h" +#include "portasm.h" +#include "queue.h" +#include "task.h" +#include "semphr.h" + +#define serMAX_PORTS ( ( unsigned portSHORT ) 2 ) + +#define serPORT_0_INT_REG ( 0xff44 ) +#define serPORT_0_BAUD_REG ( 0xff88 ) +#define serPORT_0_RX_REG ( 0xff86 ) +#define serPORT_0_TX_REG ( 0xff84 ) +#define serPORT_0_STATUS_REG ( 0xff82 ) +#define serPORT_0_CTRL_REG ( 0xff80 ) +#define serPORT_0_IRQ ( 0x14 ) + +#define serPORT_1_INT_REG ( 0xff42 ) +#define serPORT_1_BAUD_REG ( 0xff18 ) +#define serPORT_1_RX_REG ( 0xff16 ) +#define serPORT_1_TX_REG ( 0xff14 ) +#define serPORT_1_STATUS_REG ( 0xff12 ) +#define serPORT_1_CTRL_REG ( 0xff10 ) +#define serPORT_1_IRQ ( 0x11 ) + +#define serTX_EMPTY ( ( unsigned portSHORT ) 0x40 ) +#define serRX_READY ( ( unsigned portSHORT ) 0x80 ) + +#define serRESET_PIC( usEOI_TYPE ) portOUTPUT_WORD( ( unsigned portSHORT ) 0xff22, usEOI_TYPE ) +#define serTX_HOLD_EMPTY_INT ( ( unsigned portSHORT ) 0x100 ) + +#define serENABLE_INTERRUPTS ( ( unsigned portSHORT ) 0x80 ) +#define serMODE ( ( unsigned portSHORT ) 0x01 ) +#define serENABLE_TX_MACHINES ( ( unsigned portSHORT ) 0x40 ) +#define serENABLE_RX_MACHINES ( ( unsigned portSHORT ) 0x20 ) +#define serINTERRUPT_MASK ( ( unsigned portSHORT ) 0x08 ) +#define serCLEAR_ALL_STATUS_BITS ( ( unsigned portSHORT ) 0x00 ) +#define serINTERRUPT_PRIORITY ( ( unsigned portSHORT ) 0x01 ) /*< Just below the scheduler priority. */ + +#define serDONT_BLOCK ( ( portTickType ) 0 ) + +typedef enum +{ + serCOM1 = 0, + serCOM2, + serCOM3, + serCOM4, + serCOM5, + serCOM6, + serCOM7, + serCOM8 +} eCOMPort; + +typedef enum +{ + serNO_PARITY, + serODD_PARITY, + serEVEN_PARITY, + serMARK_PARITY, + serSPACE_PARITY +} eParity; + +typedef enum +{ + serSTOP_1, + serSTOP_2 +} eStopBits; + +typedef enum +{ + serBITS_5, + serBITS_6, + serBITS_7, + serBITS_8 +} eDataBits; + +typedef enum +{ + ser50 = 0, + ser75, + ser110, + ser134, + ser150, + ser200, + ser300, + ser600, + ser1200, + ser1800, + ser2400, + ser4800, + ser9600, + ser19200, + ser38400, + ser57600, + ser115200 +} eBaud; + +typedef struct xCOM_PORT +{ + /* Hardware parameters for this port. */ + portSHORT sTxInterruptOn; + unsigned portSHORT usIntReg; + unsigned portSHORT usBaudReg; + unsigned portSHORT usRxReg; + unsigned portSHORT usTxReg; + unsigned portSHORT usStatusReg; + unsigned portSHORT usCtrlReg; + + unsigned portSHORT usIRQVector; + + /* Queues used for communications with com test task. */ + xQueueHandle xRxedChars; + xQueueHandle xCharsForTx; + + /* This semaphore does nothing useful except test a feature of the + scheduler. */ + xSemaphoreHandle xTestSem; + +} xComPort; + +static xComPort xPorts[ serMAX_PORTS ] = +{ + { pdFALSE, serPORT_0_INT_REG, serPORT_0_BAUD_REG, serPORT_0_RX_REG, serPORT_0_TX_REG, serPORT_0_STATUS_REG, serPORT_0_CTRL_REG, serPORT_0_IRQ, NULL, NULL, NULL }, + { pdFALSE, serPORT_1_INT_REG, serPORT_1_BAUD_REG, serPORT_1_RX_REG, serPORT_1_TX_REG, serPORT_1_STATUS_REG, serPORT_1_CTRL_REG, serPORT_1_IRQ, NULL, NULL, NULL } +}; + +typedef xComPort * xComPortHandle; + +/** + * Lookup the baud rate from the enum. + */ +static unsigned portLONG prvBaud( eBaud eWantedBaud ); + +/* These prototypes are repeated here so we don't have to include the serial header. This allows +the xComPortHandle structure details to be private to this file. */ +xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength ); +portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, portCHAR *pcRxedChar, portTickType xBlockTime ); +portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, portCHAR cOutChar, portTickType xBlockTime ); +void vSerialClose( xComPortHandle xPort ); +portSHORT sSerialWaitForSemaphore( xComPortHandle xPort ); +/*-----------------------------------------------------------*/ + +static portSHORT xComPortISR( xComPort * const pxPort ); + +#define vInterruptOn( pxPort, usInterrupt ) \ +{ \ +unsigned portSHORT usIn; \ + \ + portENTER_CRITICAL(); \ + { \ + if( pxPort->sTxInterruptOn == pdFALSE ) \ + { \ + usIn = portINPUT_WORD( pxPort->usCtrlReg ); \ + portOUTPUT_WORD( pxPort->usCtrlReg, usIn | usInterrupt ); \ + \ + pxPort->sTxInterruptOn = pdTRUE; \ + } \ + } \ + portEXIT_CRITICAL(); \ +} +/*-----------------------------------------------------------*/ + +#define vInterruptOff( pxPort, usInterrupt ) \ +{ \ + unsigned portSHORT usIn = portINPUT_WORD( pxPort->usCtrlReg ); \ + if( usIn & usInterrupt ) \ + { \ + portOUTPUT_WORD( pxPort->usCtrlReg, usIn & ~usInterrupt); \ + pxPort->sTxInterruptOn = pdFALSE; \ + } \ +} +/*-----------------------------------------------------------*/ + + +/* Define an interrupt handler for each port */ +#define COM_IRQ_WRAPPER(N) \ + static void __interrupt COM_IRQ##N##_WRAPPER( void ) \ + { \ + if( xComPortISR( &( xPorts[##N##] ) ) ) \ + { \ + portEND_SWITCHING_ISR(); \ + } \ + } + + + +COM_IRQ_WRAPPER( 0 ) +COM_IRQ_WRAPPER( 1 ) + +static pxISR xISRs[ serMAX_PORTS ] = +{ + COM_IRQ0_WRAPPER, + COM_IRQ1_WRAPPER +}; + +/*-----------------------------------------------------------*/ + +static unsigned portLONG prvBaud( eBaud eWantedBaud ) +{ + switch( eWantedBaud ) + { + case ser50 : return 50UL; + case ser75 : return 75UL; + case ser110 : return 110UL; + case ser134 : return 134UL; + case ser150 : return 150UL; + case ser200 : return 200UL; + case ser300 : return 300UL; + case ser600 : return 600UL; + case ser1200 : return 1200UL; + case ser1800 : return 1800UL; + case ser2400 : return 2400UL; + case ser4800 : return 4800UL; + case ser19200 : return 19200UL; + case ser38400 : return 38400UL; + case ser57600 : return 57600UL; + case ser115200 : return 115200UL; + default : return 9600UL; + } +} + +/*-----------------------------------------------------------*/ + +xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength ) +{ +unsigned portSHORT usPort; +xComPortHandle pxPort = NULL; +unsigned portLONG ulBaudDiv; + + /* BAUDDIV = ( Microprocessor Clock / Baud Rate ) / 16 */ + ulBaudDiv = ( configCPU_CLOCK_HZ / prvBaud( eWantedBaud ) ) / 16UL; + + /* Only n, 8, 1 is supported so these parameters are not required for this + port. */ + ( void ) eWantedParity; + ( void ) eWantedDataBits; + ( void ) eWantedStopBits; + + /* Currently only n,8,1 is supported. */ + + usPort = ( unsigned portSHORT ) ePort; + + if( usPort < serMAX_PORTS ) + { + pxPort = &( xPorts[ usPort ] ); + + portENTER_CRITICAL(); + { + unsigned portSHORT usInWord; + + /* Create the queues used by the com test task. */ + pxPort->xRxedChars = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( portCHAR ) ); + pxPort->xCharsForTx = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( portCHAR ) ); + + /* Create the test semaphore. This does nothing useful except test a feature of the scheduler. */ + vSemaphoreCreateBinary( pxPort->xTestSem ); + + /* There is no ISR here already to restore later. */ + setvect( ( portSHORT ) pxPort->usIRQVector, xISRs[ usPort ] ); + + usInWord = portINPUT_WORD( pxPort->usIntReg ); + usInWord &= ~serINTERRUPT_MASK; + usInWord |= serINTERRUPT_PRIORITY; + portOUTPUT_WORD( pxPort->usIntReg, usInWord ); + + portOUTPUT_WORD( pxPort->usBaudReg, ( unsigned portSHORT ) ulBaudDiv ); + portOUTPUT_WORD( pxPort->usCtrlReg, serENABLE_INTERRUPTS | serMODE | serENABLE_TX_MACHINES | serENABLE_RX_MACHINES ); + + portOUTPUT_WORD( pxPort->usStatusReg, serCLEAR_ALL_STATUS_BITS ); + } + portEXIT_CRITICAL(); + } + + return pxPort; +} /*lint !e715 Some parameters are not used as only a subset of the serial port functionality is currently implemented. */ +/*-----------------------------------------------------------*/ + +void vSerialPutString( xComPortHandle pxPort, const portCHAR * const pcString, unsigned portSHORT usStringLength ) +{ +unsigned portSHORT usByte; +portCHAR *pcNextChar; + + pcNextChar = ( portCHAR * ) pcString; + + for( usByte = 0; usByte < usStringLength; usByte++ ) + { + xQueueSend( pxPort->xCharsForTx, pcNextChar, serDONT_BLOCK ); + pcNextChar++; + } + + vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT ); +} +/*-----------------------------------------------------------*/ + +portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, portCHAR *pcRxedChar, portTickType xBlockTime ) +{ + /* Get the next character from the buffer, note that this routine is only + called having checked that the is (at least) one to get */ + if( xQueueReceive( pxPort->xRxedChars, pcRxedChar, xBlockTime ) ) + { + return pdTRUE; + } + else + { + return pdFALSE; + } +} +/*-----------------------------------------------------------*/ + +portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, portCHAR cOutChar, portTickType xBlockTime ) +{ + if( xQueueSend( pxPort->xCharsForTx, &cOutChar, xBlockTime ) != pdPASS ) + { + return pdFAIL; + } + + vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT ); + + return pdPASS; +} +/*-----------------------------------------------------------*/ + +portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort ) +{ +const portTickType xBlockTime = ( portTickType ) 0xffff; + + /* This function does nothing interesting, but test the + semaphore from ISR mechanism. */ + return xSemaphoreTake( xPort->xTestSem, xBlockTime ); +} +/*-----------------------------------------------------------*/ + +void vSerialClose( xComPortHandle xPort ) +{ +unsigned portSHORT usOutput; + + /* Turn off the interrupts. We may also want to delete the queues and/or + re-install the original ISR. */ + + portENTER_CRITICAL(); + { + usOutput = portINPUT_WORD( xPort->usCtrlReg ); + + usOutput &= ~serENABLE_INTERRUPTS; + usOutput &= ~serENABLE_TX_MACHINES; + usOutput &= ~serENABLE_RX_MACHINES; + portOUTPUT_WORD( xPort->usCtrlReg, usOutput ); + + usOutput = portINPUT_WORD( xPort->usIntReg ); + usOutput |= serINTERRUPT_MASK; + portOUTPUT_WORD( xPort->usIntReg, usOutput ); + } + portEXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ +unsigned short usStatus; +static portBASE_TYPE xComPortISR( xComPort * const pxPort ) +{ +unsigned portSHORT usStatusRegister; +portCHAR cChar; +portBASE_TYPE xTaskWokenByPost = pdFALSE, xAnotherTaskWokenByPost = pdFALSE, xTaskWokenByTx = pdFALSE; + + /* NOTE: THIS IS NOT AN EFFICIENT ISR AS IT IS DESIGNED SOLELY TO TEST + THE SCHEDULER FUNCTIONALITY. REAL APPLICATIONS SHOULD NOT USE THIS + FUNCTION. */ + + usStatusRegister = portINPUT_WORD( pxPort->usStatusReg ); + + if( usStatusRegister & serRX_READY ) + { + cChar = ( portCHAR ) portINPUT_WORD( pxPort->usRxReg ); + xTaskWokenByPost = xQueueSendFromISR( pxPort->xRxedChars, &cChar, xTaskWokenByPost ); + + /* Also release the semaphore - this does nothing interesting and is just a test. */ + xAnotherTaskWokenByPost = xSemaphoreGiveFromISR( pxPort->xTestSem, xAnotherTaskWokenByPost ); + } + else if( pxPort->sTxInterruptOn && ( usStatusRegister & serTX_EMPTY ) ) + { + if( xQueueReceiveFromISR( pxPort->xCharsForTx, &cChar, &xTaskWokenByTx ) == pdTRUE ) + { + portOUTPUT_WORD( pxPort->usTxReg, ( unsigned portSHORT ) cChar ); + } + else + { + /* Queue empty, nothing to send */ + vInterruptOff( pxPort, serTX_HOLD_EMPTY_INT ); + } + } + + serRESET_PIC( pxPort->usIRQVector ); + + /* If posting to the queue woke a task that was blocked on the queue we may + want to switch to the woken task - depending on its priority relative to + the task interrupted by this ISR. */ + if( xTaskWokenByPost || xAnotherTaskWokenByPost || xTaskWokenByTx) + { + return pdTRUE; + } + else + { + return pdFALSE; + } +} + + + + + diff --git a/Demo/WizNET_DEMO_TERN_186/socket.c b/Demo/WizNET_DEMO_TERN_186/socket.c new file mode 100644 index 000000000..b749b16ab --- /dev/null +++ b/Demo/WizNET_DEMO_TERN_186/socket.c @@ -0,0 +1,1861 @@ +/* +******************************************************************************** +* TERN, Inc. +* (c) Copyright 2005, http://www.tern.com +* +* MODIFIED BY RICHARD BARRY TO ADD SEMAPHORE FOR COMMUNICATION BETWEEN THE +* WIZnet ISR AND THE HTTP TASK. +* +* - Derived based on development version provided by Wiznet. +* +* Filename : socket.h +* Programmer(s): +* Created : 2002/06/20 +* Modified : +* 2002/09/27 : - Renaming +* INT_STATUS --> INT_REG +* STATUS(i) --> INT_STATUS(i) +* C_STATUS(i) --> SOCK_STATUS(i) +* 2003/11/06 : Ported for use with TERN controller. Note all byte access is at even addresses +* 2005/10/8 : Modified constants for easier initialization. +* +* Description : Header file of W3100A for TERN embedded controller +******************************************************************************** +*/ +/* +############################################################################### +File Include Section +############################################################################### +*/ +#include "i2chip_hw.h" +#include "socket.h" +#include "types.h" +#include +#include + +#include +#include +#include + + +/* +############################################################################### +Local Variable Declaration Section +############################################################################### +*/ +u_char I_STATUS[4]; // Store Interrupt Status according to channels +u_int Local_Port; // Designate Local Port +union un_l2cval SEQ_NUM; // Set initial sequence number + +u_long SMASK[MAX_SOCK_NUM]; // Variable to store MASK of Tx in each channel, + // on setting dynamic memory size. +u_long RMASK[MAX_SOCK_NUM]; // Variable to store MASK of Rx in each channel, + // on setting dynamic memory size. +int SSIZE[MAX_SOCK_NUM]; // Maximun Tx memory size by each channel +int RSIZE[MAX_SOCK_NUM]; // Maximun Rx memory size by each channel + +u_int SBUFBASEADDRESS[MAX_SOCK_NUM]; // Maximun Tx memory base address by each channel +u_int RBUFBASEADDRESS[MAX_SOCK_NUM]; // Maximun Rx memory base address by each channel + +/* +############################################################################### +Function Implementation Section +############################################################################### +*/ + +/* +******************************************************************************** +* Interrupt handling function of the W3100A +* +* Description : +* Stores the status information that each function waits for in the global variable I_STATUS +* for transfer. I_STATUS stores the interrupt status value for each channel. +* Arguments : None +* Returns : None +* Note : Internal Function +******************************************************************************** +*/ + +portBASE_TYPE prvProcessISR( void ) +{ +unsigned char status; +extern xSemaphoreHandle xTCPSemaphore; +portBASE_TYPE xSwitchRequired = pdFALSE; + +#ifdef I2CHIP_WINDOW +u_int current_window = i2chip_get_window(); +#endif + +status = READ_VALUE(INT_REG); + + +if (status) + { + xSwitchRequired = pdTRUE; + // channel 0 interrupt(sysinit, sockinit, established, closed, timeout, send_ok, recv_ok) + if (status & 0x01) + { + I_STATUS[0] = READ_VALUE(INT_STATUS(0)); + +// if (I_STATUS[0] & SESTABLISHED) +// ISR_ESTABLISHED(0); +// if (I_STATUS[0] & SCLOSED) +// ISR_CLOSED(0); + + WRITE_VALUE(INT_REG, 0x01); + } + + // channel 1 interrupt(sysinit, sockinit, established, closed, timeout, send_ok, recv_ok) + if (status & 0x02) + { + I_STATUS[1] = READ_VALUE(INT_STATUS(1)); + +// if (I_STATUS[1] & SESTABLISHED) +// ISR_ESTABLISHED(1); +// if (I_STATUS[1] & SCLOSED) +// ISR_CLOSED(1); + + WRITE_VALUE(INT_REG, 0x02); + } + + // channel 2 interrupt(sysinit, sockinit, established, closed, timeout, send_ok, recv_ok) + if (status & 0x04) + { + I_STATUS[2] = READ_VALUE(INT_STATUS(2)); + +// if (I_STATUS[2] & SESTABLISHED) +// ISR_ESTABLISHED(2); +// if (I_STATUS[2] & SCLOSED) +// ISR_CLOSED(2); + + WRITE_VALUE(INT_REG, 0x04); + } + + // channel 3 interrupt(sysinit, sockinit, established, closed, timeout, send_ok, recv_ok) + if (status & 0x08) + { + I_STATUS[3] = READ_VALUE(INT_STATUS(3)); + +// if (I_STATUS[3] & SESTABLISHED) ISR_ESTABLISHED(3); +// if (I_STATUS[3] & SCLOSED) ISR_CLOSED(3); + + WRITE_VALUE(INT_REG, 0x08); + } + + // channel 0 receive interrupt + if (status & 0x10) + { +// ISR_RX(0); + WRITE_VALUE(INT_REG, 0x10); + } + + // channel 1 receive interrupt + if (status & 0x20) + { +// ISR_RX(1); + WRITE_VALUE(INT_REG, 0x20); + } + + // channel 2 receive interrupt + if (status & 0x40) + { +// ISR_RX(2); + WRITE_VALUE(INT_REG, 0x40); + } + + // channel 3 receive interrupt + if (status & 0x80) + { +// ISR_RX(3); + WRITE_VALUE(INT_REG, 0x80); + } + status = READ_VALUE(INT_REG); + } + +WRITE_VALUE(INT_REG, 0xFF); + +#ifdef I2CHIP_WINDOW +i2chip_set_window(current_window); +#endif + + if( xSwitchRequired == pdTRUE ) + { + xSwitchRequired = xSemaphoreGiveFromISR( xTCPSemaphore, pdFALSE ); + } + + return xSwitchRequired; +} + +void far interrupt in4_isr_i2chip(void) +{ + if( prvProcessISR() == pdTRUE ) + { + portEND_SWITCHING_ISR(); + } + + INT_EOI; +} + +/* +**************************************************************************************************** +* Established connection interrupt handling function. +* +* Description : +* Called upon connection establishment, and may be inserted in user code if needed by +* the programmer. +* Arguments : None +* Returns : None +* Note : Internal Function +**************************************************************************************************** +*/ +/* +void ISR_ESTABLISHED(SOCKET s) +{ +// TO ADD YOUR CODE +} +*/ + +/* +**************************************************************************************************** +* Closed connection interrupt handling function +* +* Description : +* Called upon connection closure, and may be inserted in user code if needed by the programmer. +* Arguments : None +* Returns : None +* Note : Internal Function +**************************************************************************************************** +*/ +/* +void ISR_CLOSED(SOCKET s) +{ +// TO ADD YOUR CODE +} +*/ + +/* +**************************************************************************************************** +* Received data interrupt handling function +* +* Description : +* Called upon receiving data, and may be inserted in user code if needed by the programmer. +* Arguments : None +* Returns : None +* Note : Internal Function +**************************************************************************************************** +*/ +/* +void ISR_RX(SOCKET s) +{ +// TO ADD YOUR CODE +} +*/ + +/* +**************************************************************************************************** +* W3100A Initialization Function +* +* Description: Reset of W3100A S/W and Registeration of i386 interrupt +* Arguments : None. +* Returns : None. +* Note : +**************************************************************************************************** +*/ +void initW3100A(void) +{ + +// Install interrupt handler for i2Chip +INT_INIT(in4_isr_i2chip); + + +Local_Port = 1000; // This default value will be set if you didn't designate it when you + // create a socket. If you don't designate port number and create a + // socket continuously, the port number will be assigned with + // incremented by one to Local_Port +SEQ_NUM.lVal = 4294967293ul; // Sets the initial SEQ# to be used for TCP communication. + // (It should be ramdom value) +WRITE_VALUE(COMMAND(0), CSW_RESET); // Software RESET +} + +/* +**************************************************************************************************** +* W3100A initialization function +* +* Description : +* Sets the Tx, Rx memory size by each channel, source MAC, source IP, gateway, and subnet mask +* to be used by the W3100A to the designated values. +* May be called when reflecting modified network information or Tx, Rx memory size on the W3100A +* Include Ping Request for ARP update (In case that a device embedding W3100A is directly +* connected to Router) +* Arguments : sbufsize - Tx memory size (00 - 1KByte, 01- 2KBtye, 10 - 4KByte, 11 - 8KByte) +* bit 1-0 : Tx memory size of channel #0 +* bit 3-2 : Tx memory size of channel #1 +* bit 5-4 : Tx memory size of channel #2 +* bit 7-6 : Tx memory size of channel #3 +* rbufsize - Rx memory size (00 - 1KByte, 01- 2KBtye, 10 - 4KByte, 11 - 8KByte) +* bit 1-0 : Rx memory size of channel #0 +* bit 3-2 : Rx memory size of channel #1 +* bit 5-4 : Rx memory size of channel #2 +* bit 7-6 : Rx memory size of channel #3 +* Returns : None +* Note : API Function +* Maximum memory size for Tx, Rx in W3100A is 8KBytes, +* In the range of 8KBytes, the memory size could be allocated dynamically by +* each channel +* Be attentive to sum of memory size shouldn't exceed 8Kbytes +* and to data transmission and receiption from non-allocated channel may cause +* some problems. +* If 8KBytes memory already is assigned to centain channel, other 3 channels +* couldn't be used, for there's no available memory. +* If two 4KBytes memory are assigned to two each channels, other 2 channels couldn't +* be used, for there's no available memory. +* (Example of memory assignment) +* sbufsize => 00000011, rbufsize => 00000011 : +* Assign 8KBytes for Tx and Rx to channel #0, Cannot use channel #1,#2,#3 +* sbufsize => 00001010, rbufsize => 00001010 : +* Assign 4KBytes for Tx and Rx to each channel #0,#1 respectively. Cannot use +* channel #2,#3 +* sbufsize => 01010101, rbufsize => 01010101 : +* Assign 2KBytes for Tx and Rx to each all channels respectively. +* sbufsize => 00010110, rbufsize => 01010101 : +* Assign 4KBytes for Tx, 2KBytes for Rx to channel #0 +* s 2KBytes for Tx, 2KBytes for Rx to channel #1 +* 2KBytes for Tx, 2KBytes for Rx to channel #2 +* 2KBytes is available exclusively for Rx in channel #3. There's no memory for Tx. +**************************************************************************************************** +*/ +void sysinit(u_char sbufsize, u_char rbufsize) +{ +char i; +int ssum,rsum; + +ssum = 0; +rsum = 0; + +// Set Tx memory size for each channel +WRITE_VALUE(TX_DMEM_SIZE, sbufsize); + +// Set Rx memory size for each channel +WRITE_VALUE(RX_DMEM_SIZE, rbufsize); + +// Set Base Address of Tx memory for channel #0 +SBUFBASEADDRESS[0] = 0; + +// Set Base Address of Rx memory for channel #0 +RBUFBASEADDRESS[0] = 0; + +// Set maximum memory size for Tx and Rx, mask, base address of memory by each channel +for(i = 0 ; i < MAX_SOCK_NUM; i++) + { + SSIZE[i] = 0; + RSIZE[i] = 0; + if(ssum < 8192) + { + switch((sbufsize >> i*2) & 0x03) // Set maximum Tx memory size + { + case 0: + SSIZE[i] = 1024; + SMASK[i] = 0x000003FF; + break; + + case 1: + SSIZE[i] = 2048; + SMASK[i] = 0x000007FF; + break; + + case 2: + SSIZE[i] = 4096; + SMASK[i] = 0x00000FFF; + break; + + case 3: + SSIZE[i] = 8192; + SMASK[i] = 0x00001FFF; + break; + } + } + if(rsum < 8192) + { + switch((rbufsize >> i*2) & 0x03) // Set maximum Rx memory size + { + case 0: + RSIZE[i] = 1024; + RMASK[i] = 0x000003FF; + break; + + case 1: + RSIZE[i] = 2048; + RMASK[i] = 0x000007FF; + break; + + case 2: + RSIZE[i] = 4096; + RMASK[i] = 0x00000FFF; + break; + + case 3: + RSIZE[i] = 8192; + RMASK[i] = 0x00001FFF; + break; + } + } + ssum += SSIZE[i]; + rsum += RSIZE[i]; + + // Set base address of Tx and Rx memory for channel #1,#2,#3 + if(i != 0) + { + SBUFBASEADDRESS[i] = ssum - SSIZE[i]; + RBUFBASEADDRESS[i] = rsum - RSIZE[i]; + } + } + + WRITE_VALUE(COMMAND(0), CSYS_INIT); + +while(!(I_STATUS[0] & SSYS_INIT_OK)) + I2CHIP_POLL_ISR(in4_isr_i2chip); + +#ifdef __PING__ + { + u_char xdata pingbuf[8]; + setIPprotocol(0, IPPROTO_ICMP); + socket(0, SOCK_IPL_RAW, 3000,0); // Create a socket for ARP update + + pingbuf[0] = 8; // ICMP TYPE + pingbuf[1] = 0; // ICMP CODE + pingbuf[2] = 0xf7; // CHECKSUM (already calculated) + pingbuf[3] = 0xfd; + pingbuf[4] = 0; // ID + pingbuf[5] = 1; + pingbuf[6] = 0; // SEQ # + pingbuf[7] = 1; + pingbuf[8] = 0; // Data 1 Byte + + sendto(0, pingbuf, 9, GATEWAY_PTR,3000); // Ping Request + close(0); + printf("Route MAC Update Success"); + } +#endif +} + +/* +**************************************************************************************************** +* Function to set subnet mask +* +* Description: +* Arguments : addr--> Pointer that has the value to be set +* Returns : None. +* Note : +**************************************************************************************************** +*/ +void setsubmask(u_char * addr) +{ +u_char i; +u_char far* sm_ptr = SUBNET_MASK_PTR; // We can only convert to 'regular' + // pointer if we're confident arithmetic + // won't take us out of current window. + +for (i = 0; i < 4; i++) + { + WRITE_VALUE(sm_ptr + SA_OFFSET(i), addr[i]); + } +} + +/* +**************************************************************************************************** +* Function to set gateway IP +* +* Description: +* Arguments : addr--> Pointer that has Gateway IP to be set +* Returns : None. +* Note : +**************************************************************************************************** +*/ +void setgateway(u_char * addr) +{ +u_char i; +u_char far* gw_ptr = GATEWAY_PTR; // We can only convert to 'regular' + // pointer if we're confident arithmetic + // won't take us out of current window. +for (i = 0; i < 4; i++) + { + WRITE_VALUE(gw_ptr + SA_OFFSET(i), addr[i]); + } +} + +/* +**************************************************************************************************** +* Function to set W3100A IP +* +* Description: +* Arguments : addr--> Pointer that has Source IP to be set +* Returns : None. +* Note : +**************************************************************************************************** +*/ +void setIP(u_char * addr) +{ +u_char i; +u_char far* src_ptr = SRC_IP_PTR; // We can only convert to 'regular' + // pointer if we're confident arithmetic + // won't take us out of current window. + +for (i = 0; i < 4; i++) + { + WRITE_VALUE(src_ptr + SA_OFFSET(i), addr[i]); + } +} + +// DEBUG +void getIP(u_char* addr) +{ +u_char i; +u_char far* src_ptr = SRC_IP_PTR; // We can only convert to 'regular' + // pointer if we're confident arithmetic + // won't take us out of current window. + +for (i = 0; i < 4; i++) + addr[i] = READ_VALUE(src_ptr + SA_OFFSET(i)); +} + + +/* +**************************************************************************************************** +* Function to set MAC +* +* Description: +* Arguments : addr--> Pointer that has MAC to be set +* Returns : None. +* Note : +**************************************************************************************************** +*/ +void setMACAddr(u_char * addr) +{ +u_char i; +u_char far* ha_ptr = SRC_HA_PTR; // We can only convert to 'regular' + // pointer if we're confident arithmetic + // won't take us out of current window. + +for (i = 0; i < 6; i++) + { + WRITE_VALUE(ha_ptr + SA_OFFSET(i), addr[i]); + } +} + +/* +**************************************************************************************************** +* Function to set TCP timeout +* +* Description: The function that used to adjust time to resend TCP +* Arguments : val --> Pointer that has the value to be set +* Upper 2 byte:Initial timeout value +* Last 1 byte:The count to retry till timeout +* Returns : None. +* Note : +**************************************************************************************************** +*/ +void settimeout(u_char * val) +{ +u_char i; +u_char far* tout_ptr = TIMEOUT_PTR; // We can only convert to 'regular' + // pointer if we're confident arithmetic + // won't take us out of current window. + +for (i = 0; i < 3; i++) + { + WRITE_VALUE(tout_ptr + SA_OFFSET(i), val[i]); + } +} + +/* +**************************************************************************************************** +* Function to set interrupt mask. +* +* Description: +* Arguments : mask--> Mask value to be set ('1'-> interrupt ) +* Returns : None. +* Note : +**************************************************************************************************** +*/ +void setINTMask(u_char mask) +{ +WRITE_VALUE(INTMASK, mask); +} + +/* +**************************************************************************************************** +* Function to set enable in sending and receiving of broadcast data +* +* Description: Enable to process of broadcating data in UDP or IP RAW mode. +* Arguments : s --> Channel No. to be set +* Returns : None. +* Note : +**************************************************************************************************** +*/ +void setbroadcast(SOCKET s) +{ +u_char val = READ_VALUE(OPT_PROTOCOL(s)); +WRITE_VALUE(OPT_PROTOCOL(s), val | SOCKOPT_BROADCAST); +} + +/* +**************************************************************************************************** +* Function to set process protocol in IP RAW mode. +* +* Description: +* Arguments : s--> Channel No. to be set +* tos-->Protocol Value to be set +* Returns : None. +* Note : +**************************************************************************************************** +*/ +void setTOS(SOCKET s, u_char tos) +{ +WRITE_VALUE(TOS(s), tos); +} + +/* +**************************************************************************************************** +* Upper layer protocol setup function in IP RAW Mode +* +* Description : Upper layer protocol setup function in protocol field of IP header when +* developing upper layer protocol like ICMP, IGMP, EGP etc. by using IP Protocol +* Arguments : s - Channel number +* ipprotocol - Upper layer protocol setting value of IP Protocol +* (Possible to use designated IPPROTO_ in header file) +* Returns : None +* Note : API Function +* This function should be called before calling socket() that is, before +* socket initialization. +**************************************************************************************************** +*/ +void setIPprotocol(SOCKET s, u_char ipprotocol) +{ +WRITE_VALUE(IP_PROTOCOL(s), ipprotocol); +} + +/* +**************************************************************************************************** +* Initialization function to appropriate channel +* +* Description : Initialize designated channel and wait until W3100 has done. +* Arguments : s - channel number +* protocol - designate protocol for channel +* SOCK_STREAM(0x01) -> TCP. +* SOCK_DGRAM(0x02) -> UDP. +* SOCK_IPL_RAW(0x03) -> IP LAYER RAW. +* SOCK_MACL_RAW(0x04) -> MAC LAYER RAW. +* port - designate source port for appropriate channel +* flag - designate option to be used in appropriate. +* SOCKOPT_BROADCAST(0x80) -> Send/receive broadcast message in UDP +* SOCKOPT_NDTIMEOUT(0x40) -> Use register value which designated TIMEOUT +* value +* SOCKOPT_NDACK(0x20) -> When not using no delayed ack +* SOCKOPT_SWS(0x10) -> When not using silly window syndrome +* Returns : When succeeded : Channel number, failed :-1 +* Note : API Function +**************************************************************************************************** +*/ +char socket(SOCKET s, u_char protocol, u_int port, u_char flag) +{ +u_char k; + +//Designate socket protocol and option +WRITE_VALUE(OPT_PROTOCOL(s), protocol | flag); + +// setup designated port number +if (port != 0) + { + k = (u_char)((port & 0xff00) >> 8); + WRITE_VALUE(SRC_PORT_PTR(s), k); + k = (u_char)(port & 0x00ff); + WRITE_VALUE(SRC_PORT_PTR(s) + SA_OFFSET(1), k); + } +else + { + // Designate random port number which is managed by local when you didn't designate source port + Local_Port++; + + WRITE_VALUE(SRC_PORT_PTR(s), (u_char)((Local_Port & 0xff00) >> 8)); + WRITE_VALUE(SRC_PORT_PTR(s) + SA_OFFSET(1), (u_char)(Local_Port & 0x00ff)); + } + +// SOCK_INIT +I_STATUS[s] = 0; +WRITE_VALUE(COMMAND(s), CSOCK_INIT); + +// Waiting Interrupt to CSOCK_INIT +while (I_STATUS[s] == 0) + I2CHIP_POLL_ISR(in4_isr_i2chip); + +if (!(I_STATUS[s] & SSOCK_INIT_OK)) + return(-1); + +initseqnum(s); // Use initial seq# with random number + +return(s); +} + +/* +**************************************************************************************************** +* Connection establishing function to designated peer. +* +* Description : This function establish a connection to the peer by designated channel, +* and wait until the connection is established successfully. (TCP client mode) +* Arguments : s - channel number +* addr - destination IP Address +* port - destination Port Number +* Returns : when succeeded : 1, failed : -1 +* Note : API Function +**************************************************************************************************** +*/ +char connect(SOCKET s, u_char far * addr, u_int port) +{ + +if (port != 0) + { //designate destination port + WRITE_VALUE(DST_PORT_PTR(s), (u_char)((port & 0xff00) >> 8)); + WRITE_VALUE(DST_PORT_PTR(s) + SA_OFFSET(1), (u_char)(port & 0x00ff)); + } +else + return(-1); + + WRITE_VALUE(DST_IP_PTR(s), addr[0]); //designate destination IP address + WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(1), addr[1]); + WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(2), addr[2]); + WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(3), addr[3]); + +I_STATUS[s] = 0; + + WRITE_VALUE(COMMAND(s), CCONNECT); // CONNECT + I2CHIP_POLL_ISR(in4_isr_i2chip); + +// Wait until connection is established successfully +while (I_STATUS[s] == 0) + { + // When failed, appropriate channel will be closed and return an error + if (select(s, SEL_CONTROL) == SOCK_CLOSED) + return -1; + } + +if (!(I_STATUS[s] & SESTABLISHED)) + return(-1); + +return(1); +} + +/* +**************************************************************************************************** +* Connection establishing function to designated peer. (Non-blocking Mode) +* +* Description : This function establish a connection to the peer by designated channel. +* +* Arguments : s - channel number +* addr - destination IP Address +* port - destination Port Number +* Returns : when succeeded : 1, failed : -1 +* Note : API Function +**************************************************************************************************** +*/ +char NBconnect(SOCKET s, u_char far * addr, u_int port) +{ + +if (port != 0) + { //designate destination port + WRITE_VALUE(DST_PORT_PTR(s), (u_char) ((port & 0xff00) >> 8) ); + WRITE_VALUE(DST_PORT_PTR(s) + SA_OFFSET(1), (u_char)(port & 0x00ff)); + } +else + return(-1); + + WRITE_VALUE(DST_IP_PTR(s), addr[0]); //designate destination IP address + WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(1), addr[1]); + WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(2), addr[2]); + WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(3), addr[3]); + +I_STATUS[s] = 0; + +WRITE_VALUE(COMMAND(s), CCONNECT); // CONNECT +return(1); +} + +/* +**************************************************************************************************** +* Waits for connection request from a peer (Blocking Mode) +* +* Description : Wait for connection request from a peer through designated channel (TCP Server mode) +* Arguments : s - channel number +* addr - IP Address of the peer when a connection is established +* port - Port number of the peer when a connection is established +* Returns : When succeeded : 1, failed : -1 +* Note : API Function +**************************************************************************************************** +*/ +/* +char listen(SOCKET s, u_char far * addr, u_int far * port) +{ +u_int i; + +I_STATUS[s] = 0; + +// LISTEN +COMMAND(s) = CLISTEN; + +// Wait until connection is established +while (I_STATUS[s] == 0) + { + // When failed to connect, the designated channel will be closed and return an error. + if (select(s, SEL_CONTROL) == SOCK_CLOSED) + return -1; + } + +// Receive IP address and port number of the peer connected +if (I_STATUS[s] & SESTABLISHED) + { + i = *DST_PORT_PTR(s); + *port = (u_int)((i & 0xff00) >> 8); + i = *(DST_PORT_PTR(s) + 2); + i = (u_int)(i & 0x00ff); + *port += (i << 8); + + addr[0] = *DST_IP_PTR(s); + addr[1] = *(DST_IP_PTR(s) + 2); + addr[2] = *(DST_IP_PTR(s) + 4); + addr[3] = *(DST_IP_PTR(s) + 6); + } +else + return(-1); + +return(1); +} +*/ + +/* +**************************************************************************************************** +* Waits for connection request from a peer (Non-blocking Mode) +* +* Description : Wait for connection request from a peer through designated channel (TCP Server mode) +* Arguments : s - channel number +* Returns : None +* Note : API Function +**************************************************************************************************** +*/ +char NBlisten(SOCKET s) +{ +I_STATUS[s] = 0; + +// LISTEN +WRITE_VALUE(COMMAND(s), CLISTEN); + +return(1); +} + +/* +**************************************************************************************************** +* Create random value for initial Seq# when establishing TCP connection +* +* Description : In this function, you can add some source codes to create random number for +* initial Seq#. In real, TCP initial SEQ# should be random value. +* (Currently, we're using static value in EVB/DK.) +* Arguments : s - channel number +* Returns : None +* Note : API Function +**************************************************************************************************** +*/ +void initseqnum(SOCKET s) +{ +// Designate initial seq# +// If you have random number generation function, assign random number instead of SEQ_NUM.lVal++. +SEQ_NUM.lVal++; + +//randomize(); +//SEQ_NUM.lVal = rand(); + +WRITE_VALUE(TX_WR_PTR(s), SEQ_NUM.cVal[0]); +WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(1), SEQ_NUM.cVal[1]); +WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(2), SEQ_NUM.cVal[2]); +WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(3), SEQ_NUM.cVal[3]); +delay0(2); + +WRITE_VALUE(TX_RD_PTR(s), SEQ_NUM.cVal[0]); +WRITE_VALUE(TX_RD_PTR(s) + SA_OFFSET(1), SEQ_NUM.cVal[1]); +WRITE_VALUE(TX_RD_PTR(s) + SA_OFFSET(2), SEQ_NUM.cVal[2]); +WRITE_VALUE(TX_RD_PTR(s) + SA_OFFSET(3), SEQ_NUM.cVal[3]); +delay0(2); + +WRITE_VALUE(TX_ACK_PTR(s), SEQ_NUM.cVal[0]); +WRITE_VALUE(TX_ACK_PTR(s) + SA_OFFSET(1), SEQ_NUM.cVal[1]); +WRITE_VALUE(TX_ACK_PTR(s) + SA_OFFSET(2), SEQ_NUM.cVal[2]); +WRITE_VALUE(TX_ACK_PTR(s) + SA_OFFSET(3), SEQ_NUM.cVal[3]); +delay0(2); +} + +/* +**************************************************************************************************** +* Function for sending TCP data. +* +* Description : Function for sending TCP data and Composed of the send() and send_in() functions. +* The send() function is an application I/F function. +* It continues to call the send_in() function to complete the sending of the data up to the +* size of the data to be sent when the application is called. +* The send_in() function receives the return value (the size of the data sent), calculates +* the size of the data to be sent, and calls the send_in() function again if there is any +* data left to be sent. +* Arguments : s - channel number +* buf - Pointer pointing data to send +* len - data size to send +* Returns : Succeed: sent data size, Failed: -1; +* Note : API Function +**************************************************************************************************** +*/ +int send(SOCKET s, u_char far * buf, u_int len) +{ +int ptr, size; +u_char huge* huge_buf = (u_char huge*)buf; +u_char far* local_buf = (u_char far*)huge_buf; + +if (len <= 0) + return (0); +else + { + ptr = 0; + do + { + size = send_in(s, local_buf + ptr, len); + if (size == -1) + return -1; + len = len - size; + ptr += size; + } while ( len > 0); + } +return ptr; +} + +/* +**************************************************************************************************** +* Internal function for sending TCP data. +* +* Description : Called by the send() function for TCP transmission. +* It first calculates the free transmit buffer size +* and compares it with the size of the data to be transmitted to determine the transmission size. +* After calculating the data size, it copies data from TX_WR_PTR. +* It waits if there is a previous send command in process. +* When the send command is cleared, it updates the TX_WR_PTR up to the size to be transmitted + and performs the send command. +* Arguments : s - channel number +* buf - Pointer pointing data to send +* len - data size to send +* Returns : Succeeded: sent data size, Failed: -1 +* Note : Internal Function +**************************************************************************************************** +*/ +int send_in(SOCKET s, u_char far * buf, u_int len) +{ +u_char k; +u_int size; +union un_l2cval wr_ptr, ack_ptr; +unsigned int offset; + +S_START: +disable(); // CT: Shadow register access should not conflict with ISR. +k = READ_VALUE(SHADOW_TXWR_PTR(s)); +WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. +delay0(2); +wr_ptr.cVal[3] = READ_VALUE(TX_WR_PTR(s)); +wr_ptr.cVal[2] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(1)); +wr_ptr.cVal[1] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(2)); +wr_ptr.cVal[0] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(3)); + +k = READ_VALUE(SHADOW_TXACK_PTR(s)); +WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. +delay0(2); +ack_ptr.cVal[3] = READ_VALUE(TX_ACK_PTR(s)); +ack_ptr.cVal[2] = READ_VALUE(TX_ACK_PTR(s) + SA_OFFSET(1)); +ack_ptr.cVal[1] = READ_VALUE(TX_ACK_PTR(s) + SA_OFFSET(2)); +ack_ptr.cVal[0] = READ_VALUE(TX_ACK_PTR(s) + SA_OFFSET(3)); +enable(); + +// Suppress compiler errors that k is not used +k = k; + +// Calculate send free buffer size +if (wr_ptr.lVal >= ack_ptr.lVal) + size = (u_int)(SSIZE[s] - (wr_ptr.lVal - ack_ptr.lVal)); +else + size = (u_int)(SSIZE[s] - (0 - ack_ptr.lVal + wr_ptr.lVal)); + +// Recalulate after some delay because of error in pointer calculation +if (size > SSIZE[s]) + { + if (select(s, SEL_CONTROL) != SOCK_ESTABLISHED) + return -1; + delay_ms(1); + goto S_START; + } + +// Wait when previous sending has not finished yet and there's no free buffer +if (size == 0) + { + if (select(s, SEL_CONTROL) != SOCK_ESTABLISHED) + return -1; + + delay_ms(1); + goto S_START; + } +else if (size < len) + { + len = size; + } + +// Calculate pointer to data copy +offset = (UINT)(wr_ptr.lVal & SMASK[s]); + +// copy data +write_data(s, buf, offset, len); + +while (READ_VALUE(COMMAND(s)) & CSEND) + { + // Confirm previous send command + if (select(s, SEL_CONTROL) != SOCK_ESTABLISHED) + return -1; + } + +// update tx_wr_ptr +wr_ptr.lVal = wr_ptr.lVal + len; +WRITE_VALUE(TX_WR_PTR(s), wr_ptr.cVal[3]); +WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(1), wr_ptr.cVal[2]); +WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(2), wr_ptr.cVal[1]); +WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(3), wr_ptr.cVal[0]); + +delay0(1); + +// SEND +WRITE_VALUE(COMMAND(s), CSEND); + +return(len); +} + +/* +**************************************************************************************************** +* TCP data receiving function. +* +* Description : This function is to clear out any received TCP data. +* Arguments : s - channel number +* Returns : None +* Note : API Fcuntion +**************************************************************************************************** +*/ +void recv_clear(SOCKET s) +{ +u_char k; +u_int size; +union un_l2cval wr_ptr, rd_ptr; + +disable(); +k = READ_VALUE(SHADOW_RXWR_PTR(s)); +WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. +delay0(2); +wr_ptr.cVal[3] = READ_VALUE(RX_WR_PTR(s)); +wr_ptr.cVal[2] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(1)); +wr_ptr.cVal[1] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(2)); +wr_ptr.cVal[0] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(3)); + +k = READ_VALUE(SHADOW_RXRD_PTR(s)); +WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. +delay0(2); +rd_ptr.cVal[3] = READ_VALUE(RX_RD_PTR(s)); +rd_ptr.cVal[2] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(1)); +rd_ptr.cVal[1] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(2)); +rd_ptr.cVal[0] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(3)); +enable(); + +// Suppress compiler errors that k is not used +k = k; + +// calculate received data size +if (wr_ptr.lVal >= rd_ptr.lVal) + size = (u_int)(wr_ptr.lVal - rd_ptr.lVal); +else + size = (u_int)(0 - rd_ptr.lVal + wr_ptr.lVal); + +// Update rx_rd_ptr +rd_ptr.lVal += size; +WRITE_VALUE(RX_RD_PTR(s), rd_ptr.cVal[3]); +WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(1), rd_ptr.cVal[2]); +WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(2), rd_ptr.cVal[1]); +WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(3), rd_ptr.cVal[0]); + +// RECV + WRITE_VALUE(COMMAND(s), CRECV); +} + +/* +**************************************************************************************************** +* TCP data receiving function. +* +* Description : This function is for receiving TCP data. +* The recv() function is an application I/F function. It will read up to len chars if there are + enough characters in the buffer, otherwise will onl read the number of characters availiable +* Arguments : s - channel number +* buf - Pointer where the data to be received is copied +* len - Size of the data to be received +* Returns : Succeeded: received data size, Failed: -1 +* Note : API Fcuntion +**************************************************************************************************** +*/ +int recv(SOCKET s, u_char far * buf, u_int len) +{ +u_char k; +u_int size; +union un_l2cval wr_ptr, rd_ptr; +unsigned int offset; + +// If out length is 0, then we do not need to do anything +if (len <= 0) + return (0); + +disable(); +k = READ_VALUE(SHADOW_RXWR_PTR(s)); +WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. +delay0(2); +wr_ptr.cVal[3] = READ_VALUE(RX_WR_PTR(s)); +wr_ptr.cVal[2] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(1)); +wr_ptr.cVal[1] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(2)); +wr_ptr.cVal[0] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(3)); + +k = READ_VALUE(SHADOW_RXRD_PTR(s)); +WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. +delay0(2); +rd_ptr.cVal[3] = READ_VALUE(RX_RD_PTR(s)); +rd_ptr.cVal[2] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(1)); +rd_ptr.cVal[1] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(2)); +rd_ptr.cVal[0] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(3)); +enable(); + +// Suppress compiler errors that k is not used +k = k; + +// calculate IIM7010A received data size +if (wr_ptr.lVal == rd_ptr.lVal) + return(0); +else if (wr_ptr.lVal >= rd_ptr.lVal) + size = (u_int)(wr_ptr.lVal - rd_ptr.lVal); +else + size = (u_int)(0 - rd_ptr.lVal + wr_ptr.lVal); + +// Make sure we do not try to read more characters than what is availiable in the IIM7010 buffer +if (size < len) + len = size; + +// Calculate pointer to be copied received data +offset = ((UINT)(rd_ptr.lVal & RMASK[s])); + +// Copy received data +size = read_data(s, offset, buf, len); + +// Update rx_rd_ptr +rd_ptr.lVal += size; +WRITE_VALUE(RX_RD_PTR(s), rd_ptr.cVal[3]); +WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(1), rd_ptr.cVal[2]); +WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(2), rd_ptr.cVal[1]); +WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(3), rd_ptr.cVal[0]); + +// RECV + WRITE_VALUE(COMMAND(s), CRECV); +return(size); +} + + +/* +**************************************************************************************************** +* UDP data sending function. +* +* Description : Composed of the sendto()and sendto_in() functions. +* The send() function is an application I/F function. +* It continues to call the send_in() function to complete the sending of the data up to the +* size of the data to be sent +* when the application is called.Unlike TCP transmission, it designates the destination address +* and the port. +* Arguments : s - channel port +* buf - Pointer pointing data to send +* len - data size to send +* addr - destination IP address to send data +* port - destination port number to send data +* Returns : Sent data size +* Note : API Function +**************************************************************************************************** +*/ +u_int sendto(SOCKET s, u_char far * buf, u_int len, u_char * addr, u_int port) +{ +//char val; +u_int ptr, size; + +// Wait until previous send commnad has completed. +while(READ_VALUE(COMMAND(s)) & CSEND) + { + if(select(s, SEL_CONTROL) == SOCK_CLOSED) + return -1; // Error. + } + +// Designate destination port number. +if (port != 0) + { + WRITE_VALUE(DST_PORT_PTR(s), (u_char)((port & 0xff00) >> 8)); + WRITE_VALUE(DST_PORT_PTR(s) + SA_OFFSET(1), (u_char)(port & 0x00ff)); + } + +// Designate destination IP address +WRITE_VALUE(DST_IP_PTR(s), addr[0]); +WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(1), addr[1]); +WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(2), addr[2]); +WRITE_VALUE(DST_IP_PTR(s) + SA_OFFSET(3), addr[3]); + +if (len <= 0) + return (0); +else + { + ptr = 0; + do + { + size = sendto_in(s, buf + ptr, len); + len = len - size; + ptr += size; + } while ( len > 0); + } +return ptr; +} + +/* +**************************************************************************************************** +* UDP data sending function. +* +* Description : An internal function that is the same as the send_in() function of the TCP. +* Arguments : s - Channel number +* buf - Pointer indicating the data to send +* len - data size to send +* Returns : Sent data size +* Note : Internal Function +**************************************************************************************************** +*/ +u_int sendto_in(SOCKET s, u_char far * buf, u_int len) +{ +u_char k; +u_int size; +union un_l2cval wr_ptr, rd_ptr; +unsigned int offset; + +S2_START: +disable(); +k = READ_VALUE(SHADOW_TXWR_PTR(s)); +WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. +delay0(2); +wr_ptr.cVal[3] = READ_VALUE(TX_WR_PTR(s)); +wr_ptr.cVal[2] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(1)); +wr_ptr.cVal[1] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(2)); +wr_ptr.cVal[0] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(3)); + +k = READ_VALUE(SHADOW_TXRD_PTR(s)); +WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. +delay0(2); +rd_ptr.cVal[3] = READ_VALUE(TX_RD_PTR(s)); +rd_ptr.cVal[2] = READ_VALUE(TX_RD_PTR(s) + SA_OFFSET(1)); +rd_ptr.cVal[1] = READ_VALUE(TX_RD_PTR(s) + SA_OFFSET(2)); +rd_ptr.cVal[0] = READ_VALUE(TX_RD_PTR(s) + SA_OFFSET(3)); +enable(); + +// Suppress compiler errors that k is not used +k = k; + +// Calculate free buffer size to send +if (wr_ptr.lVal >= rd_ptr.lVal) + size = (u_int)(SSIZE[s] - (wr_ptr.lVal - rd_ptr.lVal)); +else + size = (u_int)(SSIZE[s] - (0 - rd_ptr.lVal + wr_ptr.lVal)); + +// Recalulate after some delay because of error in pointer caluation +if (size > SSIZE[s]) + { + delay_ms(1); + goto S2_START; + } + +// Wait when previous sending has not finished yet and there's no free buffer +if (size == 0) + { + delay_ms(1); + goto S2_START; + + } +else if (size < len) + { + len = size; + } + +// Calculate pointer to copy data pointer +offset =(UINT)(wr_ptr.lVal & SMASK[s]); + +// copy data +write_data(s, buf, offset, len); + +// Confirm previous send command +while (READ_VALUE(COMMAND(s)) & CSEND) + { + if(select(s, SEL_CONTROL)==SOCK_CLOSED) + return -1; // Error + } + +// update tx_wr_ptr +wr_ptr.lVal = wr_ptr.lVal + len; +WRITE_VALUE(TX_WR_PTR(s), wr_ptr.cVal[3]); +WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(1), wr_ptr.cVal[2]); +WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(2), wr_ptr.cVal[1]); +WRITE_VALUE(TX_WR_PTR(s) + SA_OFFSET(3), wr_ptr.cVal[0]); + +delay0(1); + +// SEND +WRITE_VALUE(COMMAND(s), CSEND); + +return(len); +} + +/* +**************************************************************************************************** +* UDP data receiving function. +* +* Description : Function for receiving UDP and IP layer RAW mode data, and handling the data header. +* Arguments : s - channel number +* buf - Pointer where the data to be received is copied +* len - Size of the data to be received +* addr - Peer IP address for receiving +* port - Peer port number for receiving +* Returns : Received data size +* Note : API Function +**************************************************************************************************** +*/ +u_int recvfrom(SOCKET s, u_char far *buf, u_int len, u_char *addr, u_int *port) +{ +struct _UDPHeader // When receiving UDP data, header added by W3100A + { + union + { + struct + { + u_int size; + u_char addr[4]; + u_int port; + } header; + u_char stream[8]; + } u; + } UDPHeader; + +u_int ret; +union un_l2cval wr_ptr, rd_ptr; +u_long size; +u_char k; +unsigned int offset; + +if(select(s,SEL_CONTROL)==SOCK_CLOSED) + return -1; + +disable(); +k = READ_VALUE(SHADOW_RXWR_PTR(s)); +WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. +delay0(2); +wr_ptr.cVal[3] = READ_VALUE(RX_WR_PTR(s)); +wr_ptr.cVal[2] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(1)); +wr_ptr.cVal[1] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(2)); +wr_ptr.cVal[0] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(3)); + +k = READ_VALUE(SHADOW_RXRD_PTR(s)); +WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. +delay0(2); +rd_ptr.cVal[3] = READ_VALUE(RX_RD_PTR(s)); +rd_ptr.cVal[2] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(1)); +rd_ptr.cVal[1] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(2)); +rd_ptr.cVal[0] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(3)); +enable(); + +// Suppress compiler errors that k is not used +k = k; + +// Calculate received data size +if (len <= 0) + return (0); +else if (wr_ptr.lVal >= rd_ptr.lVal) + size = wr_ptr.lVal - rd_ptr.lVal; +else + size = 0 - rd_ptr.lVal + wr_ptr.lVal; + +if (size == 0) + return 0; + + // Calulate received data pointer +offset = ((UINT)(rd_ptr.lVal & RMASK[s])); + +// When UDP data +if (( READ_VALUE(OPT_PROTOCOL(s)) & 0x07) == SOCK_DGRAM) + { + // Copy W3100A UDP header + read_data(s, offset, UDPHeader.u.stream, 8); + + // Read UDP Packet size + size = UDPHeader.u.stream[0]; + size = (size << 8) + UDPHeader.u.stream[1]; + + // Read IP address of the peer + addr[0] = UDPHeader.u.header.addr[0]; + addr[1] = UDPHeader.u.header.addr[1]; + addr[2] = UDPHeader.u.header.addr[2]; + addr[3] = UDPHeader.u.header.addr[3]; + + // Read Port number of the peer + *port = UDPHeader.u.stream[6]; + *port = (*port << 8) + UDPHeader.u.stream[7]; + + // Increase read pointer by 8, because already read as UDP header size + rd_ptr.lVal += 8; + + // Calculate UDP data copy pointer + offset = ((UINT)(rd_ptr.lVal & RMASK[s])); + + // Calculate data size of current UDP Packet from UDP header + size = size - 8; + + // Copy one UDP data packet to user-specific buffer + ret = read_data(s, offset, buf, (u_int)size); + + // Increase read pointer by UDP packet data size + rd_ptr.lVal += ret; + } +else if ((READ_VALUE(OPT_PROTOCOL(s)) & 0x07) == SOCK_IPL_RAW) // When IP layer RAW mode data + { + // Copy W3100A IP Raw header + read_data(s, offset, UDPHeader.u.stream, 6); + + // Read IP layer RAW Packet size + size = UDPHeader.u.stream[0]; + size = (size << 8) + UDPHeader.u.stream[1]; + + // Read IP address of the peer + addr[0] = UDPHeader.u.header.addr[0]; + addr[1] = UDPHeader.u.header.addr[1]; + addr[2] = UDPHeader.u.header.addr[2]; + addr[3] = UDPHeader.u.header.addr[3]; + + // Increase read pointer by 6, because already read as IP RAW header size + rd_ptr.lVal += 6; + + // Calculate IP layer raw mode data pointer + offset = ((UINT)(rd_ptr.lVal & RMASK[s])); + + // Copy one IP Raw data packet to user-specific buffer + ret = read_data(s, offset, buf, (u_int)size); + rd_ptr.lVal = rd_ptr.lVal + (ret - 4); + } + + // Update rx_rd_ptr + WRITE_VALUE(RX_RD_PTR(s), rd_ptr.cVal[3]); + WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(1), rd_ptr.cVal[2]); + WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(2), rd_ptr.cVal[1]); + WRITE_VALUE(RX_RD_PTR(s) + SA_OFFSET(3), rd_ptr.cVal[0]); + + // RECV + WRITE_VALUE(COMMAND(s), CRECV); + +// Real received size return +return(ret); +} + +/* +**************************************************************************************************** +* Channel closing function. +* +* Description : Function for closing the connection of the designated channel. +* Arguments : s - channel number +* Returns : None +* Note : API Function +**************************************************************************************************** +*/ +void close(SOCKET s) +{ +u_int len; + +I_STATUS[s] = 0; + +if (select(s, SEL_CONTROL) == SOCK_CLOSED) + return; // Already closed + +// When closing, if there's data which have not processed, Insert some source codes to handle this +// Or before application call close(), handle those data first and call close() later. + +len = select(s, SEL_SEND); +if (len == SSIZE[s]) + { + // CLOSE + WRITE_VALUE(COMMAND(s), CCLOSE); + // TODO: The 'SCLOSED' status value is only set briefly as part of the close, + // and will otherwise quickly return to normal. That means your code might + // become 'stuck' at this point even if the packet has closed normally. + // Rather than a while() call, it might be preferred to time out on this + // close check and return to the application after some time. + while(!(I_STATUS[s] & SCLOSED)) + I2CHIP_POLL_ISR(in4_isr_i2chip); + } +} + +u_char tx_empty(SOCKET s) +{ + return (select(s, SEL_SEND) == SSIZE[s]); +} + +/* +**************************************************************************************************** +* Channel closing function. +* +* Description : Function for closing the connection of the designated channel. +* Arguments : s - channel number +* Returns : None +* Note : API Function +**************************************************************************************************** +*/ +char reset_sock(SOCKET s) +{ +u_char c; + +c = 1 << s; + +// RESET +WRITE_VALUE(RESETSOCK, c); +return (1); +} + +/* +**************************************************************************************************** +* Function handling the channel socket information. +* +* Description : Return socket information of designated channel +* Arguments : s - channel number +* func - SEL_CONTROL(0x00) -> return socket status +* SEL_SEND(0x01) -> return free transmit buffer size +* SEL_RECV(0x02) -> return received data size +* Returns : socket status or free transmit buffer size or received data size +* Note : API Function +**************************************************************************************************** +*/ +u_int select(SOCKET s, u_char func) +{ +u_int val; +union un_l2cval rd_ptr, wr_ptr, ack_ptr; +u_char k; + +switch (func) + { + // socket status information + case SEL_CONTROL : + val = READ_VALUE(SOCK_STATUS(s)); + break; + + // Calculate send free buffer size + case SEL_SEND : + disable(); + k = READ_VALUE(SHADOW_TXWR_PTR(s)); + WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. + delay0(2); + wr_ptr.cVal[3] = READ_VALUE(TX_WR_PTR(s)); + wr_ptr.cVal[2] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(1)); + wr_ptr.cVal[1] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(2)); + wr_ptr.cVal[0] = READ_VALUE(TX_WR_PTR(s) + SA_OFFSET(3)); + + if (( READ_VALUE(OPT_PROTOCOL(s)) & 0x07) == SOCK_STREAM) // TCP + { + k = READ_VALUE(SHADOW_TXACK_PTR(s)); + WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. + delay0(2); + ack_ptr.cVal[3] = READ_VALUE(TX_ACK_PTR(s)); + ack_ptr.cVal[2] = READ_VALUE(TX_ACK_PTR(s) + SA_OFFSET(1)); + ack_ptr.cVal[1] = READ_VALUE(TX_ACK_PTR(s) + SA_OFFSET(2)); + ack_ptr.cVal[0] = READ_VALUE(TX_ACK_PTR(s) + SA_OFFSET(3)); + enable(); + + if (wr_ptr.lVal >= ack_ptr.lVal) + val = (u_int)(SSIZE[s] - (wr_ptr.lVal - ack_ptr.lVal)); + else + val = (u_int)(SSIZE[s] - (0 - ack_ptr.lVal + wr_ptr.lVal)); + } + else // UDP, IP RAW ... (except TCP) + { + k = READ_VALUE(SHADOW_TXRD_PTR(s)); + WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. + delay0(2); + rd_ptr.cVal[3] = READ_VALUE(TX_RD_PTR(s)); + rd_ptr.cVal[2] = READ_VALUE(TX_RD_PTR(s) + SA_OFFSET(1)); + rd_ptr.cVal[1] = READ_VALUE(TX_RD_PTR(s) + SA_OFFSET(2)); + rd_ptr.cVal[0] = READ_VALUE(TX_RD_PTR(s) + SA_OFFSET(3)); + enable(); + + if (wr_ptr.lVal >= rd_ptr.lVal) + val = (u_int)(SSIZE[s] - (wr_ptr.lVal - rd_ptr.lVal)); + else + val = (u_int)(SSIZE[s] - (0 - rd_ptr.lVal + wr_ptr.lVal)); + } + break; + + // Calculate received data size + case SEL_RECV : + disable(); + k = READ_VALUE(SHADOW_RXWR_PTR(s)); + WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. + delay0(2); + wr_ptr.cVal[3] = READ_VALUE(RX_WR_PTR(s)); + wr_ptr.cVal[2] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(1)); + wr_ptr.cVal[1] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(2)); + wr_ptr.cVal[0] = READ_VALUE(RX_WR_PTR(s) + SA_OFFSET(3)); + + k = READ_VALUE(SHADOW_RXRD_PTR(s)); + WINDOW_RESTORE_BASE; // Needed whenever we touch a shadow ptr; different window. + delay0(2); + rd_ptr.cVal[3] = READ_VALUE(RX_RD_PTR(s)); + rd_ptr.cVal[2] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(1)); + rd_ptr.cVal[1] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(2)); + rd_ptr.cVal[0] = READ_VALUE(RX_RD_PTR(s) + SA_OFFSET(3)); + enable(); + + if (wr_ptr.lVal == rd_ptr.lVal) + val = 0; + else if (wr_ptr.lVal > rd_ptr.lVal) + val = (u_int)(wr_ptr.lVal - rd_ptr.lVal); + else + val = (u_int)(0 - rd_ptr.lVal + wr_ptr.lVal); + break; + + default : + val = -1; + break; + } +// Suppress compiler errors that k is not used +k = k; +return(val); +} + +// +// unsigned char dma_read_i2chip (unsigned int i2_segm, unsigned int i2_offs, +// unsigned int cnt, unsigned int des_segm, unsigned int des_offs); +// Using DMA0 to read data from i2chip buffer into destination SRAM. +// where: +// unsigned int cnt = number of sectors, 512-byte per sector +// unsigned int des_segm = segment of destination SRAM data memory +// unsigned int des_offs = offset of destination SRAM data memory +// unsigned int i2_segm = segment of i2chip buffer mapped in memory +// unsigned int i2_offs = offset of i2chip buffer mapped in memory +// return DMA counter value +// +unsigned int dma_read_i2chip(u_char far* i2_src, u_char far* des, u_int cnt) +{ + u_int des_segm, des_offs; + u_int i2_segm, i2_offs; + u_long temp; + + temp = ((long)FP_SEG(des) << 4) + ((long)FP_OFF(des)); + des_segm = (u_int)(temp >> 16); + des_offs = (u_int)(temp & 0xffff); + + temp = ((long)FP_SEG(i2_src) << 4) + ((long)FP_OFF(i2_src)); + i2_segm = (u_int)(temp >> 16); + i2_offs = (u_int)(temp & 0xffff); + + outport(0xffc6, des_segm); /* D0DSTH destination SRAM segment */ + outport(0xffc4, des_offs); /* D0DSTL destination SRAM offset */ + outport(0xffc2, i2_segm); /* D0SRCH=SP0RD */ + outport(0xffc0, i2_offs); /* D0SRCL=SP0RD */ + outport(0xffc8, cnt); // D0TC counter + outport(0xfff8,0x0504); // PLLCON, 0203=10M,050f=40M, 051f=80MHz +// DMA0 mem-mem, 16-bit, unsync, Start moving data line below + outport(0xffca, 0xb60e); /* D0CON 1011 0110 0000 1111 */ +// outport(0xffca, 0xb42e); // 1011 0100 0010 1110 + while( inport(0xffc8) ); /* D0TC counter=0, DMA complete */ + outport(0xfff8,0x051f); // PLLCON, 0203=10M,050f=40M, 051f=80MHz +return( inport(0xffc8) ); // counter +} + +// +// unsigned int dma_write_i2chip (unsigned int src_segm, unsigned int src_offs, +// unsigned int cnt, unsigned int i2_segm, unsigned int i2_offs); +// Using DMA0 to write data from memory into i2chip. +// where: +// unsigned int cnt = number of 16-bit DMA transfers +// unsigned int src_segm = segment of the source SRAM data memory +// unsigned int src_offs = offset of the source SRAM data memory +// unsigned int i2_segm = segment of i2chip buffer mapped in memory +// unsigned int i2_offs = offset of i2chip buffer mapped in memory +// return DMA counter value +// +unsigned int dma_write_i2chip(u_char far* src, u_char far* i2_dest, u_int cnt) +{ + u_int src_segm, src_offs; + u_int i2_segm, i2_offs; + u_long temp; + + temp = (FP_SEG(src) << 4) + (FP_OFF(src)); + src_segm = (u_int)(temp >> 4); + src_offs = (u_int)(temp & 0xffff); + + temp = (FP_SEG(i2_dest) << 4) + (FP_OFF(i2_dest)); + i2_segm = (u_int)(temp >> 4); + i2_offs = (u_int)(temp & 0xffff); + + outport(0xffc8, cnt); // D0TC counter + outport(0xffc6, i2_segm); // D0DSTH=i2chip buffer segment + outport(0xffc4, i2_offs); // D0DSTL=i2chip buffer offset + outport(0xffc2, src_segm); /* D0SRCH=SP0RD */ + outport(0xffc0, src_offs); /* D0SRCL=SP0RD */ +// outport(0xfff8,0x050f); // PLLCON, 0203=10M,050f=40M, 051f=80MHz +// DMA0 mem-mem, 16-bit, unsync, Start moving data line below + outport(0xffca, 0xb60f); /* D0CON 1011 0110 0000 1111 */ + while( inport(0xffc8) ); /* D0TC counter=0, DMA complete */ +// outport(0xfff8,0x051f); // PLLCON, 0203=10M,050f=40M, 051f=80MHz + +return( inport(0xffc8) ); // counter +} + +/* +**************************************************************************************************** +* Copies the receive buffer data of the W3100A to the system buffer. +* +* Description : Copies the receive buffer data of the W3100A to the system buffer. +* It is called from the recv()or recvfrom() function. +* Arguments : s - channel number +* src - receive buffer pointer of W3100A +* dst - system buffer pointer +* len - data size to copy +* Returns : copied data size +* Note : Internal Function +**************************************************************************************************** +*/ +u_int read_data(SOCKET s, u_int offset, u_char far * dst, u_int len) +{ + u_int i, size, size1; + u_char far* src = (u_char far*)(MK_FP_WINDOW(RECV_DATA_BUF, + RBUFBASEADDRESS[s] + offset)); +// src = (u_char far*)(MK_FP_WINDOW(RECV_DATA_BUF, +// 0)); + + if (len == 0) + { + WINDOW_RESTORE_BASE; // Needed whenever we do a call to MK_FP_WINDOW. + return 0; + } + + if ((offset + len) > RSIZE[s]) + { + size = (u_int)(RSIZE[s] - offset); + + if (size > TERN_RDMA_THRES) + { + dma_read_i2chip(src, dst, size); + } + else + { + for (i = 0; i < size; i++) + { + *dst++ = READ_VALUE(src); + WINDOW_PTR_INC(src); + + } + } + + size1 = len - size; + src = (u_char far *)(MK_FP_WINDOW(RECV_DATA_BUF, (RBUFBASEADDRESS[s]))); + + if (size1 > TERN_RDMA_THRES) + { + dma_read_i2chip(src, dst, size); + } + else + { + for (i = 0; i < size1; i++) + { + *dst++ = READ_VALUE(src); + WINDOW_PTR_INC(src); + } + } + } + else + { + if (len > TERN_RDMA_THRES) + { + dma_read_i2chip(src, dst, size); + } + else + { + for (i = 0; i < len; i++) + { + *dst++ = READ_VALUE(src); + WINDOW_PTR_INC(src); + } + } + } + WINDOW_RESTORE_BASE; // Needed whenever we do a call to MK_FP_WINDOW. + return len; +} + + +/* +**************************************************************************************************** +* Copies the system buffer data to the transmit buffer of the W3100A. +* +* Description : Copies the system buffer data to the transmit buffer of the W3100A. +* It is called from the send_in()or sendto_in() function. +* Arguments : s - channel number +* src - system buffer pointer +* dst - send buffer pointer of W3100A +* len - data size to copy +* Returns : copied data size +* Note : Internal Function +**************************************************************************************************** +*/ +u_int write_data(SOCKET s, u_char far * src, u_int offset, u_int len) +{ + u_int i, size, size1; + u_char far* dst = (u_char far*)MK_FP_WINDOW(SEND_DATA_BUF, + SBUFBASEADDRESS[s] + offset); + + if (len == 0) + { + WINDOW_RESTORE_BASE; // Needed whenever we do a call to MK_FP_WINDOW. + return 0; + } + + if ((offset + len) > SSIZE[s]) + { + size = (u_int)(SSIZE[s] - offset); + + for (i = 0; i < size; i++) + { + WRITE_VALUE(dst, *src++); + WINDOW_PTR_INC(dst); + } + + size1 = len - size; + dst = (u_char far *)(MK_FP_WINDOW(SEND_DATA_BUF, (SBUFBASEADDRESS[s]))); + + for (i = 0; i < size1; i++) + { + WRITE_VALUE(dst, *src++); + WINDOW_PTR_INC(dst); + } + } + else + { + for (i = 0; i < len; i++) + { + WRITE_VALUE(dst, *src++); + WINDOW_PTR_INC(dst); + } + } + WINDOW_RESTORE_BASE; // Needed whenever we do a call to MK_FP_WINDOW. + return len; +} + + + -- 2.39.5