Removed W5100 demo code.

The W5100 demo programs are now available at https://github.com/oliverschmidt/uthernet
This commit is contained in:
Oliver Schmidt 2016-02-13 18:34:38 +01:00
parent 51abda7b8d
commit ac653f55bd
9 changed files with 1 additions and 1892 deletions

View File

@ -1,273 +0,0 @@
/******************************************************************************
Copyright (c) 2015, Oliver Schmidt
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL OLIVER SCHMIDT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
// Both pragmas are obligatory to have cc65 generate code
// suitable to access the W5100 auto-increment registers.
#pragma optimize (on)
#pragma static-locals (on)
#include "w5100.h"
#define MIN(a,b) (((a)<(b))?(a):(b))
static volatile byte* w5100_mode;
static volatile byte* w5100_addr_hi;
static volatile byte* w5100_addr_lo;
volatile byte* w5100_data;
static void set_addr(word addr)
{
*w5100_addr_hi = addr >> 8;
*w5100_addr_lo = addr;
}
static byte get_byte(word addr)
{
set_addr(addr);
return *w5100_data;
}
static void set_byte(word addr, byte data)
{
set_addr(addr);
*w5100_data = data;
}
static word get_word(word addr)
{
set_addr(addr);
{
// The variables are necessary to have cc65 generate code
// suitable to access the W5100 auto-increment registers.
byte data_hi = *w5100_data;
byte data_lo = *w5100_data;
return data_hi << 8 | data_lo;
}
}
static void set_word(word addr, word data)
{
set_addr(addr);
{
// The variables are necessary to have cc65 generate code
// suitable to access the W5100 auto-increment registers.
byte data_hi = data >> 8;
byte data_lo = data;
*w5100_data = data_hi;
*w5100_data = data_lo;
}
}
static void set_bytes(word addr, byte data[], word size)
{
set_addr(addr);
{
word i;
for (i = 0; i < size; ++i)
*w5100_data = data[i];
}
}
byte w5100_init(word base_addr, byte *ip_addr,
byte *submask,
byte *gateway)
{
w5100_mode = (byte*)base_addr;
w5100_addr_hi = (byte*)base_addr + 1;
w5100_addr_lo = (byte*)base_addr + 2;
w5100_data = (byte*)base_addr + 3;
// Assert Indirect Bus I/F mode & Address Auto-Increment
*w5100_mode |= 0x03;
// Retry Time-value Register: Default ?
if (get_word(0x0017) != 2000)
return 0;
// S/W Reset
*w5100_mode = 0x80;
while (*w5100_mode & 0x80)
;
// Indirect Bus I/F mode & Address Auto-Increment
*w5100_mode = 0x03;
// RX Memory Size Register: Assign 8KB to Socket 0
set_byte(0x001A, 0x03);
// TX Memory Size Register: Assign 8KB to Socket 0
set_byte(0x001B, 0x03);
// Source Hardware Address Register
{
static byte mac_addr[6] = {0x00, 0x08, 0xDC, // OUI of WIZnet
0x11, 0x11, 0x11};
set_bytes(0x0009, mac_addr, sizeof(mac_addr));
}
// Source IP Address Register
set_bytes(0x000F, ip_addr, 4);
// Subnet Mask Register
set_bytes(0x0005, submask, 4);
// Gateway IP Address Register
set_bytes(0x0001, gateway, 4);
return 1;
}
byte w5100_connect(byte *server_addr, word server_port)
{
// Socket 0 Mode Register: TCP
set_byte(0x0400, 0x01);
// Socket 0 Source Port Register
set_word(0x0404, 6502);
// Socket 0 Command Register: OPEN
set_byte(0x0401, 0x01);
// Socket 0 Status Register: SOCK_INIT ?
while (get_byte(0x0403) != 0x13)
;
// Socket 0 Destination IP Address Register
set_bytes(0x040C, server_addr, 4);
// Socket 0 Destination Port Register
set_word(0x0410, server_port);
// Socket 0 Command Register: CONNECT
set_byte(0x0401, 0x04);
while (1)
{
// Socket 0 Status Register
switch (get_byte(0x0403))
{
case 0x00: return 0; // Socket Status: SOCK_CLOSED
case 0x17: return 1; // Socket Status: SOCK_ESTABLISHED
}
}
}
byte w5100_connected(void)
{
// Socket 0 Status Register: SOCK_ESTABLISHED ?
return get_byte(0x0403) == 0x17;
}
void w5100_disconnect(void)
{
// Socket 0 Command Register: Command Pending ?
while (get_byte(0x0401))
;
// Socket 0 Command Register: DISCON
set_byte(0x0401, 0x08);
// Socket 0 Status Register: SOCK_CLOSED ?
while (get_byte(0x0403))
// Wait for disconnect to allow for reconnect
;
}
word w5100_data_request(byte do_send)
{
// Socket 0 Command Register: Command Pending ?
if (get_byte(0x0401))
return 0;
// Reread of nonzero RX Received Size Register / TX Free Size Register
// until its value settles ...
// - is present in the WIZnet driver - getSn_RX_RSR() / getSn_TX_FSR()
// - was additionally tested on 6502 machines to be actually necessary
{
word size = 0;
word prev_size;
do
{
prev_size = size;
{
static word reg[2] = {0x0426, // Socket 0 RX Received Size Register
0x0420}; // Socket 0 TX Free Size Register
size = get_word(reg[do_send]);
}
}
while (size != prev_size);
if (!size)
return 0;
{
static word reg[2] = {0x0428, // Socket 0 RX Read Pointer Register
0x0424}; // Socket 0 TX Write Pointer Register
static word bas[2] = {0x6000, // Socket 0 RX Memory Base
0x4000}; // Socket 0 TX Memory Base
static word lim[2] = {0x8000, // Socket 0 RX Memory Limit
0x6000}; // Socket 0 TX Memory Limit
// Calculate and set physical address
word addr = get_word(reg[do_send]) & 0x1FFF | bas[do_send];
set_addr(addr);
// Access to *w5100_data is limited both by ...
// - size of received / free space
// - end of physical address space
return MIN(size, lim[do_send] - addr);
}
}
}
void w5100_data_commit(byte do_send, word size)
{
{
static word reg[2] = {0x0428, // Socket 0 RX Read Pointer Register
0x0424}; // Socket 0 TX Write Pointer Register
set_word(reg[do_send], get_word(reg[do_send]) + size);
}
{
static byte cmd[2] = {0x40, // Socket Command: RECV
0x20}; // Socket Command: SEND
// Socket 0 Command Register
set_byte(0x0401, cmd[do_send]);
}
// Do NOT wait for command completion here, rather
// let W5100 operation overlap with 6502 operation
}

View File

@ -1,189 +0,0 @@
/******************************************************************************
Copyright (c) 2014, Oliver Schmidt
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL OLIVER SCHMIDT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
/******************************************************************************
Some notes by Oliver Schmidt on the WIZnet W5100 Ethernet controller:
1. Operation Modes
1.1 MAC-Raw
In MAC-Raw mode the W5100 behaves pretty much like a CS8900A or a LAN91C96. The
W5100 is usually only configured with a MAC address which is used by the W5100
to limit incoming frames to those sent to its MAC address (or broadcasts).
1.2 IP-Raw
IP-Raw mode is usable to implement non-UDP/non-TCP IP protocols like ICMP. The
W5100 is usually configured with a full IP profile (IP addr, netmask, gateway).
It transparently takes care of incoming/outgoing ARP and optionally of incoming
ICMP Echo (aka Ping).
1.3 UDP
UDP mode is pretty simlar to IP-Raw mode but additionally takes care of header
checksum calculation.
1.4 TCP
TCP mode is rather different from the other modes. Incoming/outgoing data isn't
delimited by headers like in all other modes. Rather the W5100 behaves like a
BSD socket delivering/taking a data stream - in chunks not necessarily related
to data packets received/sent. The W5100 transparently takes care of TCP flow
control by sending ACK packets. It advertises a receive window identical to the
free space in the its receive memory buffer.
The W5100 offers up to 4 'sockets' allowing to specify the operation mode for
each socket individually. However MAC-Raw mode is only available for the first
socket. It is possible to combine MAC-Raw mode with other modes for the other
sockets - which is called 'hybrid TCP/IP stack'. I have no personal experience
with this hybrid TCP/IP stack and see open questions:
- Are packets delivered to other sockets filtered from the first socket?
- Who takes care of incoming ARP and incoming ICMP Echo?
The W5100 divides its 16kB memory buffer statically into 8kB for receive and
8kB for send (in contrast to the CS8900A and the LAN91C96 which both do dynamic
receive/send buffer division). When using several sockets it is additionally
necessary to statically assign the two 8kB memory buffers to the sockets.
2. Memory Buffer Access
In 6502 machines the W5100 is accessed using its indirect bus interface. This
interface optionally allows for pointer auto-increment (like the CS8900A and
the LAN91C96). However in contrast to those two Ethernet controllers the W5100
does NOT virtualize access to its memory buffer! So when reading/writing data
from/to the W5100 and reaching the end of the memory buffer assigned to the
socket it's the responsibility of the 6502 program to continue reading/writing
at the begin of the memory buffer. Please note that the pointer auto-increment
does NOT take care of that wraparound operation! I have implemented several
ways to handle this difficulty.
2.1 Copy Split
If it is necessary or desired to have the interface to the upper layers being
based on a receive/send buffer and one can afford the memory for a little more
code than it is appropriate to check in advance if receive/send will require a
wraparound and in that case split the copy from/to the buffer into two copy
operations. That approach is used in all WIZnet code and I implemented it in
pretty optimized 6502 code for the Contiki/IP65 MAC-Raw mode driver located in
drivers/w5100.s - however the copy split technique is in general applicable to
all W5100 operation modes.
2.2 Shadow Register
When it comes to using as little memory as possible I consider it in general
questionable if a buffer is the right interface paradigm. In many scenarios it
makes more sense to read/write bytes individually. This allows i.e. to directly
write bytes from individual already existing data structures to the W5100 or
analyze bytes directly on reading from the W5100 to decide on processing of
subsequent bytes - and maybe ignore them altogether. This approach splits a
receive/send operation into three phases: The initialization, the individual
byte read/write and the finalization. The initialization sets up a 16-bit
shadow register to be as far away from overflow as the auto-increment pointer
is away from the necessary wraparound. The individual byte read/write then
increments the shadow register and on its overflow resets the auto-increment
pointer to the begin of the memory buffer. I implemented this approach in two
drivers using heavily size-optimized 6502 code for the W5100 UDP mode and TCP
mode showing that the shadow register technique yields the smallest code. They
are located in supplement/w5100_udp.s and supplement/w5100_tcp.s with C test
programs located in test/w5100_udp_main.c and test/w5100_tcp_main.c. There's a
Win32 communication peer for the test programs located in test/w5100_peer.c.
2.3 TCP Stream Split
A correct BSD TCP socket program never presumes to be able to read/write any
amount of data. Rather it is always prepared to call recv()/send() as often as
necessary to receive/send the expected amount data in whatever chunks - and the
very same holds true for any program using the W5100 TCP mode! But this already
necessary complexity in the upper layers allows to handle W5100 memory buffer
wraparounds transparently by artificially limiting the size of a read/write
operation to the end of the memory buffer if necessary. The next read/write
operation then works with the begin of the memory buffer. This approach shares
the benefits of the shadow register technique while avoiding its performance
penalties coming from maintaining the shadow register. Additionally it allows
the upper layers to directly access the auto-increment W5100 data register for
individual byte read/write because it is known to stay within the memory buffer
limits. Therefore the TCP stream split technique avoids both the overhead of a
buffer as well as the overhead of function calls for individual bytes. It sort
of combines the best of both sides but it means larger code than the shadow
register technique and is only applicable to the W5100 TCP mode. I implemented
the TCP stream split technique in a C-only driver located in supplement/w5100.c
with a test program representing the upper layers located in test/w5100_main.c
being compatible with test/w5100_peer.c.
******************************************************************************/
#ifndef _W5100_H_
#define _W5100_H_
typedef unsigned char byte;
typedef unsigned short word;
word w5100_data_request(byte do_send);
void w5100_data_commit(byte do_send, word size);
// After w5100_receive_request() every read operation returns the next byte
// from the server.
// After w5100_send_request() every write operation prepares the next byte
// to be sent to the server.
extern volatile byte* w5100_data;
// Initialize W5100 Ethernet controller with indirect bus interface located
// at <base_addr>. Use <ip_addr>, <submask> and <gateway> to configure the
// TCP/IP stack.
// Return <1> if a W5100 was found at <base_addr>, return <0> otherwise.
byte w5100_init(word base_addr, byte *ip_addr,
byte *submask,
byte *gateway);
// Connect to server with IP address <server_addr> on TCP port <server_port>.
// Use <6502> as fixed local port.
// Return <1> if the connection is established, return <0> otherwise.
byte w5100_connect(byte *server_addr, word server_port);
// Check if still connected to server.
// Return <1> if the connection is established, return <0> otherwise.
byte w5100_connected(void);
// Disconnect from server.
void w5100_disconnect(void);
// Request to receive data from the server.
// Return maximum number of bytes to be received by reading from *w5100_data.
#define w5100_receive_request() w5100_data_request(0)
// Commit receiving of <size> bytes from server. <size> may be smaller than
// the return value of w5100_receive_request(). Not commiting at all just
// makes the next request receive the same data again.
#define w5100_receive_commit(size) w5100_data_commit(0, (size))
// Request to send data to the server.
// Return maximum number of bytes to be send by writing to *w5100_data.
#define w5100_send_request() w5100_data_request(1)
// Commit sending of <size> bytes to server. <size> is usually smaller than
// the return value of w5100_send_request(). Not commiting at all just turns
// the w5100_send_request() - and the writes to *w5100_data - into NOPs.
#define w5100_send_commit(size) w5100_data_commit(1, (size))
#endif

View File

@ -1,458 +0,0 @@
.feature c_comments
/******************************************************************************
Copyright (c) 2014, Oliver Schmidt
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL OLIVER SCHMIDT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
.export _w5100_init, _w5100_done
.export _w5100_recv_init, _w5100_recv_byte, _w5100_recv_done
.export _w5100_send_init, _w5100_send_byte, _w5100_send_done
ptr := $06 ; 2 byte pointer value
sha := $08 ; 2 byte physical addr shadow ($F000-$FFFF)
adv := $EB ; 2 byte pointer register advancement
tmp := $ED ; 1 byte temporary value
bas := $EE ; 1 byte socket 1 Base Address (hibyte)
mode := $C0B4
addr := $C0B5
data := $C0B7
;------------------------------------------------------------------------------
_w5100_init:
; Input
; AX: Address of ip_parms (serverip, cfg_ip, cfg_netmask ,cfg_gateway)
; Output
; A: Nonzero if connected to server
; Remark
; The ip_parms are only accessed during this function.
; Set ip_parms pointer
sta ptr
stx ptr+1
; S/W Reset
lda #$80
sta mode
: lda mode
bmi :-
; Indirect Bus I/F mode, Address Auto-Increment
lda #$03
sta mode
; Gateway IP Address Register: IP address of router on local network
ldx #$00 ; Hibyte
ldy #$01 ; Lobyte
jsr set_addr
ldy #3*4 ; ip_parms::cfg_gateway
jsr set_ipv4value
; Subnet Mask Register: Netmask of local network
; -> addr is already set
ldy #2*4 ; ip_parms::cfg_netmask
jsr set_ipv4value
; Source Hardware Address Register: MAC Address
; -> addr is already set
ldx #$00
: lda mac,x
sta data
inx
cpx #$06
bcc :-
; Source IP Address Register: IP address of local machine
; -> addr is already set
ldy #1*4 ; ip_parms::cfg_ip
jsr set_ipv4value
; RX Memory Size Register: Assign 4KB each to sockets 0 and 1
ldx #$00 ; Hibyte
ldy #$1A ; Lobyte
jsr set_addr
lda #$0A
sta data
; TX Memory Size Register: Assign 4KB each to sockets 0 and 1
; -> addr is already set
; -> A is still $0A
sta data
; Socket 1 Mode Register: TCP
ldy #$00
jsr set_addrsocket1
lda #$01
sta data
; Socket 1 Source Port Register: 6502
ldy #$04
jsr set_addrsocket1
jsr set_data6502
; Socket 1 Destination IP Address Register: Destination IP address
ldy #$0C
jsr set_addrsocket1
ldy #0*4 ; ip_parms::serverip
jsr set_ipv4value
; Socket 1 Destination Port Register: 6502
; -> addr is already set
jsr set_data6502
; Socket 1 Command Register: OPEN
lda #$01
jsr set_cmdsocket1
; Socket 1 Command Register: CONNECT
lda #$04
jsr set_cmdsocket1
; Socket 1 Status Register: SOCK_CLOSED or SOCK_ESTABLISHED ?
: ldy #$03
jsr set_addrsocket1
lda data
beq error ; SOCK_CLOSED (:= 0)
cmp #$17 ; SOCK_ESTABLISHED
bne :- ; Intermediate status -> retry
; Return success
beq success ; Always
;------------------------------------------------------------------------------
set_ipv4value:
ldx #$03
: lda (ptr),y
iny
sta data
dex
bpl :-
rts
;------------------------------------------------------------------------------
set_data6502:
lda #<6502
ldx #>6502
stx data ; Hibyte
sta data ; Lobyte
rts
;------------------------------------------------------------------------------
_w5100_done:
; Input
; None
; Output
; None
; Remark
; Disconnect from the server.
; Check for completion of previous command
jsr get_cmdsocket1
; Socket 1 Command Register: DISCON
lda #$08
set_cmdsocket1:
; Socket 1 Command Register: command
jsr set_addrcmdreg1
sta data
get_cmdsocket1:
; Check for completion of command
; Socket 1 Command Register: 0 ?
: jsr set_addrcmdreg1
lda data
bne :- ; Not completed -> retry
rts
;------------------------------------------------------------------------------
_w5100_recv_init:
; Input
; None
; Output
; AX: Number of bytes to receive or -1 if not connected anymore
; Remark
; To be called before recv_byte.
; Socket 1 Status Register: SOCK_ESTABLISHED ?
ldy #$03
jsr set_addrsocket1
lda data
cmp #$17
beq :+
; Return -1
lda #<$FFFF
tax
rts
; Socket 1 RX Received Size Register: 0 or volatile ?
: lda #$26 ; Socket RX Received Size Register
jsr prolog
bne error
; Save pointer advancement
stx adv ; Lobyte
sta adv+1 ; Hibyte
; Socket 1 RX Read Pointer Register
; -> addr already set
; Calculate and set pyhsical address
ldx #>$7000 ; Socket 1 RX Base Address
jsr set_addrphysical
; Return pointer advancement
lda adv
ldx adv+1
rts
;------------------------------------------------------------------------------
_w5100_send_init:
; Input
; AX: Number of bytes to send
; Output
; A: Nonzero if ready to send
; Remark
; To be called before send_byte.
; Set pointer advancement
sta adv
stx adv+1
; Socket 1 TX Free Size Register: 0 or volatile ?
lda #$20 ; Socket TX Free Size Register
jsr prolog
bne error
; Socket 1 TX Free Size Register: < advancement ?
cpx adv ; Lobyte
sbc adv+1 ; Hibyte
bcc error ; Not enough free size
; Socket 1 TX Write Pointer Register
ldy #$24
jsr set_addrsocket1
; Calculate and set pyhsical address
ldx #>$5000 ; Socket 1 TX Base Address
jsr set_addrphysical
success:
; Return success
lda #$01
ldx #>$0000 ; Required by cc65 C callers
rts
;------------------------------------------------------------------------------
error:
lda #<$0000
tax
rts
;------------------------------------------------------------------------------
prolog:
; Check for completion of previous command
; Socket 1 Command Register: 0 ?
jsr set_addrcmdreg1
ldx data
bne :++ ; Not completed -> Z = 0
; Socket Size Register: not 0 ?
tay ; Select Size Register
jsr get_wordsocket1
stx ptr ; Lobyte
sta ptr+1 ; Hibyte
ora ptr
bne :+
inx ; -> Z = 0
rts
; Socket Size Register: volatile ?
: jsr get_wordsocket1
cpx ptr ; Lobyte
bne :+ ; Volatile size -> Z = 0
cmp ptr+1 ; Hibyte
; bne :+ ; Volatile size -> Z = 0
: rts
;------------------------------------------------------------------------------
_w5100_recv_byte:
; Input
; None
; Output
; A: Byte received
; Remark
; May be called as often as indicated by recv_init.
; Read byte
lda data
; Increment physical addr shadow lobyte
inc sha
beq incsha
ldx #>$0000 ; Required by cc65 C callers
rts
;------------------------------------------------------------------------------
_w5100_send_byte:
; Input
; A: Byte to send
; Output
; None
; Remark
; Should be called as often as indicated to send_init.
; Write byte
sta data
; Increment physical addr shadow lobyte
inc sha
beq incsha
rts
incsha:
; Increment physical addr shadow hibyte
inc sha+1
beq set_addrbase
ldx #>$0000 ; Required by cc65 C callers (_w5100_recv_byte)
rts
;------------------------------------------------------------------------------
_w5100_recv_done:
; Input
; None
; Output
; None
; Remark
; Mark data indicated by recv_init as processed (independently from how
; often recv_byte was called), if not called then next call of recv_init
; will just indicate the very same data again.
; Set parameters for commit code
lda #$40 ; RECV
ldy #$28 ; Socket RX Read Pointer Register
bne epilog ; Always
;------------------------------------------------------------------------------
_w5100_send_done:
; Input
; None
; Output
; None
; Remark
; Actually send data indicated to send_init (independently from how often
; send_byte was called), if not called then send_init (and send_byte) are
; just NOPs.
; Set parameters for commit code
lda #$20 ; SEND
ldy #$24 ; Socket TX Write Pointer Register
epilog:
; Advance pointer register
jsr set_addrsocket1
tay ; Save command
clc
lda ptr
adc adv
tax
lda ptr+1
adc adv+1
sta data ; Hibyte
stx data ; Lobyte
; Set command register
tya ; Restore command
jsr set_addrcmdreg1
sta data
rts
;------------------------------------------------------------------------------
set_addrphysical:
lda data ; Hibyte
ldy data ; Lobyte
sty ptr
sta ptr+1
and #>$0FFF ; Socket Mask Address (hibyte)
stx bas ; Socket Base Address (hibyte)
ora bas
tax
ora #>$F000 ; Move sha/sha+1 to $F000-$FFFF
sty sha
sta sha+1
set_addr:
stx addr ; Hibyte
sty addr+1 ; Lobyte
ldx #>$0000 ; Required by cc65 C callers (_w5100_recv_byte)
rts
;------------------------------------------------------------------------------
set_addrcmdreg1:
ldy #$01 ; Socket Command Register
set_addrsocket1:
ldx #>$0500 ; Socket 1 register base address
bne set_addr ; Always
;------------------------------------------------------------------------------
set_addrbase:
ldx bas ; Socket Base Address (hibyte)
ldy #<$0000 ; Socket Base Address (lobyte)
beq set_addr ; Always
;------------------------------------------------------------------------------
get_wordsocket1:
jsr set_addrsocket1
lda data ; Hibyte
ldx data ; Lobyte
rts
;------------------------------------------------------------------------------
.rodata
mac: .byte $00, $08, $DC ; OUI of WIZnet
.byte $11, $11, $11

View File

@ -1,446 +0,0 @@
.feature c_comments
/******************************************************************************
Copyright (c) 2014, Oliver Schmidt
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL OLIVER SCHMIDT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
.export _w5100_init
.export _w5100_recv_init, _w5100_recv_byte, _w5100_recv_done
.export _w5100_send_init, _w5100_send_byte, _w5100_send_done
ptr := $06 ; 2 byte pointer value
sha := $08 ; 2 byte physical addr shadow ($F000-$FFFF)
adv := $EB ; 2 byte pointer register advancement
len := $ED ; 2 byte frame length
tmp := $FA ; 1 byte temporary value
bas := $FB ; 1 byte socket 1 Base Address (hibyte)
mode := $C0B4
addr := $C0B5
data := $C0B7
;------------------------------------------------------------------------------
_w5100_init:
; Input
; AX: Address of ip_parms (serverip, cfg_ip, cfg_netmask, cfg_gateway)
; Output
; None
; Remark
; The ip_parms are only accessed during this function.
; Set ip_parms pointer
sta ptr
stx ptr+1
; S/W Reset
lda #$80
sta mode
: lda mode
bmi :-
; Indirect Bus I/F mode, Address Auto-Increment
lda #$03
sta mode
; Gateway IP Address Register: IP address of router on local network
ldx #$00 ; Hibyte
ldy #$01 ; Lobyte
jsr set_addr
ldy #3*4 ; ip_parms::cfg_gateway
jsr set_ipv4value
; Subnet Mask Register: Netmask of local network
; -> addr is already set
ldy #2*4 ; ip_parms::cfg_netmask
jsr set_ipv4value
; Source Hardware Address Register: MAC Address
; -> addr is already set
ldx #$00
: lda mac,x
sta data
inx
cpx #$06
bcc :-
; Source IP Address Register: IP address of local machine
; -> addr is already set
ldy #1*4 ; ip_parms::cfg_ip
jsr set_ipv4value
; RX Memory Size Register: Assign 4KB each to sockets 0 and 1
ldx #$00 ; Hibyte
ldy #$1A ; Lobyte
jsr set_addr
lda #$0A
sta data
; TX Memory Size Register: Assign 4KB each to sockets 0 and 1
; -> addr is already set
; -> A is still $0A
sta data
; Socket 1 Source Port Register: 6502
ldy #$04
jsr set_addrsocket1
jsr set_data6502
; Socket 1 Destination IP Address Register: Destination IP address
; This has to be the last call to set_ipv4value because it writes
; as a side effect to 'hdr' and it is the destination IP address
; that has to be present in 'hdr' after initialization
ldy #$0C
jsr set_addrsocket1
ldy #0*4 ; ip_parms::serverip
jsr set_ipv4value
; Socket 1 Destination Port Register: 6502
; -> addr is already set
jsr set_data6502
; Socket 1 Mode Register: UDP
ldy #$00
jsr set_addrsocket1
lda #$02
sta data
; Socket 1 Command Register: OPEN
; -> addr is already set
lda #$01
sta data
rts
;------------------------------------------------------------------------------
set_ipv4value:
ldx #$03
: lda (ptr),y
iny
sta data
sta hdr+2,x
dex
bpl :-
rts
;------------------------------------------------------------------------------
set_data6502:
lda #<6502
ldx #>6502
stx data ; Hibyte
sta data ; Lobyte
rts
;------------------------------------------------------------------------------
_w5100_recv_init:
; Input
; None
; Output
; AX: Number of bytes to receive
; Remark
; To be called before recv_byte.
; Socket 1 RX Received Size Register: 0 or volatile ?
lda #$26 ; Socket RX Received Size Register
jsr prolog
bne error
; Socket 1 RX Read Pointer Register
; -> addr already set
; Calculate and set pyhsical address
ldx #>$7000 ; Socket 1 RX Base Address
jsr set_addrphysical
; Compare peer IP addr and peer port with expected values
; in 'hdr' and set C(arry flag) if there's a mismatch
clc
ldx #$05
stx tmp
: jsr _w5100_recv_byte ; Doesn't trash C
ldx tmp
eor hdr,x ; Doesn't trash C
beq :+
sec
: dec tmp
bpl :--
php ; Save C
; Read data length
jsr _w5100_recv_byte ; Hibyte
sta len+1
jsr _w5100_recv_byte ; Lobyte
sta len
; Add 8 byte header to set pointer advancement
clc
adc #<$0008
sta adv
lda len+1
adc #>$0008
sta adv+1
; Skip frame if it doesn't originate from our
; expected communicaion peer
plp ; Restore C
bcs _w5100_recv_done
; Return data length
lda len
ldx len+1
rts
;------------------------------------------------------------------------------
_w5100_send_init:
; Input
; AX: Number of bytes to send
; Output
; A: Nonzero if ready to send
; Remark
; To be called before send_byte.
; Set pointer advancement
sta adv
stx adv+1
; Socket 1 TX Free Size Register: 0 or volatile ?
lda #$20 ; Socket TX Free Size Register
jsr prolog
bne error
; Socket 1 TX Free Size Register: < advancement ?
cpx adv ; Lobyte
sbc adv+1 ; Hibyte
bcc error ; Not enough free size
; Socket 1 TX Write Pointer Register
ldy #$24
jsr set_addrsocket1
; Calculate and set pyhsical address
ldx #>$5000 ; Socket 1 TX Base Address
jsr set_addrphysical
; Return success
lda #$01
ldx #>$0000 ; Required by cc65 C callers
rts
;------------------------------------------------------------------------------
error:
lda #<$0000
tax
rts
;------------------------------------------------------------------------------
prolog:
; Check for completion of previous command
; Socket 1 Command Register: 0 ?
jsr set_addrcmdreg1
ldx data
bne :++ ; Not completed -> Z = 0
; Socket Size Register: not 0 ?
tay ; Select Size Register
jsr get_wordsocket1
stx ptr ; Lobyte
sta ptr+1 ; Hibyte
ora ptr
bne :+
inx ; -> Z = 0
rts
; Socket Size Register: volatile ?
: jsr get_wordsocket1
cpx ptr ; Lobyte
bne :+ ; Volatile size -> Z = 0
cmp ptr+1 ; Hibyte
; bne :+ ; Volatile size -> Z = 0
: rts
;------------------------------------------------------------------------------
_w5100_recv_byte:
; Input
; None
; Output
; A: Byte received
; Remark
; May be called as often as indicated by recv_init.
; Read byte
lda data
; Increment physical addr shadow lobyte
inc sha
beq incsha
ldx #>$0000 ; Required by cc65 C callers
rts
;------------------------------------------------------------------------------
_w5100_send_byte:
; Input
; A: Byte to send
; Output
; None
; Remark
; Should be called as often as indicated to send_init.
; Write byte
sta data
; Increment physical addr shadow lobyte
inc sha
beq incsha
rts
incsha:
; Increment physical addr shadow hibyte
inc sha+1
beq set_addrbase
ldx #>$0000 ; Required by cc65 C callers (_w5100_recv_byte)
rts
;------------------------------------------------------------------------------
_w5100_recv_done:
; Input
; None
; Output
; None
; Remark
; Mark data indicated by recv_init as processed (independently from how
; often recv_byte was called), if not called then next call of recv_init
; will just indicate the very same data again.
; Set parameters for commit code
lda #$40 ; RECV
ldy #$28 ; Socket RX Read Pointer Register
bne epilog ; Always
;------------------------------------------------------------------------------
_w5100_send_done:
; Input
; None
; Output
; None
; Remark
; Actually send data indicated to send_init (independently from how often
; send_byte was called), if not called then send_init (and send_byte) are
; just NOPs.
; Set parameters for commit code
lda #$20 ; SEND
ldy #$24 ; Socket TX Write Pointer Register
epilog:
; Advance pointer register
jsr set_addrsocket1
tay ; Save command
clc
lda ptr
adc adv
tax
lda ptr+1
adc adv+1
sta data ; Hibyte
stx data ; Lobyte
; Set command register
tya ; Restore command
jsr set_addrcmdreg1
sta data
; Return error (_w5100_recv_init)
bne error ; Always
;------------------------------------------------------------------------------
set_addrphysical:
lda data ; Hibyte
ldy data ; Lobyte
sty ptr
sta ptr+1
and #>$0FFF ; Socket Mask Address (hibyte)
stx bas ; Socket Base Address (hibyte)
ora bas
tax
ora #>$F000 ; Move sha/sha+1 to $F000-$FFFF
sty sha
sta sha+1
set_addr:
stx addr ; Hibyte
sty addr+1 ; Lobyte
ldx #>$0000 ; Required by cc65 C callers (_w5100_recv_byte)
rts
;------------------------------------------------------------------------------
set_addrcmdreg1:
ldy #$01 ; Socket Command Register
set_addrsocket1:
ldx #>$0500 ; Socket 1 register base address
bne set_addr ; Always
;------------------------------------------------------------------------------
set_addrbase:
ldx bas ; Socket Base Address (hibyte)
ldy #<$0000 ; Socket Base Address (lobyte)
beq set_addr ; Always
;------------------------------------------------------------------------------
get_wordsocket1:
jsr set_addrsocket1
lda data ; Hibyte
ldx data ; Lobyte
rts
;------------------------------------------------------------------------------
.rodata
mac: .byte $00, $08, $DC ; OUI of WIZnet
.byte $11, $11, $11
;------------------------------------------------------------------------------
.data
hdr: .word 6502 ; Destination Port
.res 4 ; Destination IP Address

View File

@ -145,21 +145,9 @@ ip65demo.dsk: httpd.bin httpd-slotscan.bin
java -jar $(AC) -cc65 $@ webserver-slot3 B < httpd.bin
java -jar $(AC) -cc65 $@ webserver-slotscan B < httpd-slotscan.bin
w5100.bin: ../supplement/w5100.c w5100_main.c
cl65 -o $@ -t apple2enh -m $(basename $@).map $^
w5100_%.bin: ../supplement/w5100_%.s w5100_%_main.c
cl65 -o $@ -t apple2enh -m $(basename $@).map $^
w5100.dsk: w5100.bin w5100_udp.bin w5100_tcp.bin
cp prodos.dsk $@
java -jar $(AC) -cc65 $@ w5100 bin < w5100.bin
java -jar $(AC) -cc65 $@ w5100.udp bin < w5100_udp.bin
java -jar $(AC) -cc65 $@ w5100.tcp bin < w5100_tcp.bin
clean:
make -C ../ip65 clean
make -C ../drivers clean
-rm -f ../supplement/*.o
-rm -f *.o *.prg *.bin *.com *.vicprg *.map
-rm -f ip65.d64 ip65.dsk ip65.atr ip65demo.dsk w5100.dsk
-rm -f ip65.d64 ip65.dsk ip65.atr ip65demo.dsk

View File

@ -1,112 +0,0 @@
// Both pragmas are obligatory to have cc65 generate code
// suitable to access the W5100 auto-increment registers.
#pragma optimize (on)
#pragma static-locals (on)
#include <stdio.h>
#include <conio.h>
#include "../supplement/w5100.h"
#define MIN(a,b) (((a)<(b))?(a):(b))
byte ip_addr[4] = {192, 168, 0, 123};
byte submask[4] = {255, 255, 255, 0};
byte gateway[4] = {192, 168, 0, 1};
byte server[4] = {192, 168, 0, 2}; // IP addr of machine running w5100_peer.c
void main(void)
{
char key;
videomode(VIDEOMODE_80COL);
printf("Init\n");
if (!w5100_init(0xC0B4, ip_addr,
submask,
gateway))
{
printf("No Hardware Found\n");
return;
}
printf("Connect\n");
if (!w5100_connect(server, 6502))
{
printf("Faild To Connect To %d.%d.%d.%d\n", server[0],
server[1],
server[2],
server[3]);
return;
}
printf("Connected To %d.%d.%d.%d\n", server[0],
server[1],
server[2],
server[3]);
printf("(S)end or e(X)it\n");
do
{
word len, all;
if (kbhit())
{
key = cgetc();
}
else
{
key = '\0';
}
if (key == 's')
{
all = 500;
printf("Send Len %d", all);
do
{
word i;
while (!(len = w5100_send_request()))
{
printf("!");
}
len = MIN(all, len);
for (i = 0; i < len; ++i)
{
*w5100_data = 500 - all + i;
}
w5100_send_commit(len);
all -= len;
}
while (all);
printf(".\n");
}
len = w5100_receive_request();
if (len)
{
word i;
printf("Recv Len %d", len);
for (i = 0; i < len; ++i)
{
if ((i % 24) == 0)
{
printf("\n$%04X:", i);
}
printf(" %02X", *w5100_data);
}
w5100_receive_commit(len);
printf(".\n");
}
if (!w5100_connected())
{
printf("Disconnect\n");
return;
}
}
while (key != 'x');
w5100_disconnect();
printf("Done\n");
}

View File

@ -1,197 +0,0 @@
#include <stdio.h>
#include <conio.h>
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
static void dump(unsigned char *buf, unsigned len)
{
unsigned i;
for (i = 0; i < len; ++i)
{
if ((i % 24) == 0)
{
printf("\n$%04X:", i);
}
printf(" %02X", buf[i]);
}
printf(".\n");
}
void main(void)
{
printf("Init\n");
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
return;
}
SOCKET udp = socket(AF_INET, SOCK_DGRAM , IPPROTO_UDP);
if (udp == INVALID_SOCKET)
{
return;
}
SOCKET srv = socket(AF_INET, SOCK_STREAM , IPPROTO_TCP);
if (srv == INVALID_SOCKET)
{
return;
}
u_long arg = 1;
if (ioctlsocket(udp, FIONBIO, &arg) == SOCKET_ERROR)
{
return;
}
if (ioctlsocket(srv, FIONBIO, &arg) == SOCKET_ERROR)
{
return;
}
SOCKADDR_IN local;
local.sin_family = AF_INET;
local.sin_addr.s_addr = INADDR_ANY;
local.sin_port = htons(6502);
if (bind(udp, (SOCKADDR *)&local, sizeof(local)) == SOCKET_ERROR)
{
return;
}
if (bind(srv, (SOCKADDR *)&local, sizeof(local)) == SOCKET_ERROR)
{
return;
}
if (listen(srv, 1) == SOCKET_ERROR)
{
return;
}
SOCKADDR_IN remote;
remote.sin_addr.s_addr = INADDR_NONE;
SOCKET tcp = INVALID_SOCKET;
printf("(S)end or e(X)it\n");
char key;
do
{
int len;
unsigned char buf[1500];
if (kbhit())
{
key = getch();
}
else
{
key = '\0';
}
if (key == 's')
{
if (remote.sin_addr.s_addr == INADDR_NONE && tcp == INVALID_SOCKET)
{
printf("Peer Unknown As Yet\n", len);
}
else
{
unsigned i;
len = 500;
for (i = 0; i < len; ++i)
{
buf[i] = i;
}
if (tcp == INVALID_SOCKET)
{
printf("Send Len %d To %s", len, inet_ntoa(remote.sin_addr));
if (sendto(udp, buf, len, 0, (SOCKADDR *)&remote, sizeof(remote)) == SOCKET_ERROR)
{
return;
}
}
else
{
printf("Send Len %d", len);
if (send(tcp, buf, len, 0) == SOCKET_ERROR)
{
return;
}
}
printf(".\n");
}
}
unsigned remote_size = sizeof(remote);
len = recvfrom(udp, buf, sizeof(buf), 0, (SOCKADDR *)&remote, &remote_size);
if (len == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
return;
}
}
else if (len)
{
printf("Recv Len %d From %s", len, inet_ntoa(remote.sin_addr));
dump(buf, len);
}
if (tcp == INVALID_SOCKET)
{
SOCKADDR_IN conn;
unsigned conn_size = sizeof(conn);
tcp = accept(srv, (SOCKADDR *)&conn, &conn_size);
if (tcp == INVALID_SOCKET)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
return;
}
}
else
{
printf("Connect From %s\n", inet_ntoa(conn.sin_addr));
u_long arg = 1;
if (ioctlsocket(tcp, FIONBIO, &arg) == SOCKET_ERROR)
{
return;
}
}
}
else
{
len = recv(tcp, buf, sizeof(buf), 0);
if (len == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
return;
}
}
else if (len)
{
printf("Recv Len %d", len);
dump(buf, len);
}
else
{
printf("Disconnect\n");
closesocket(tcp);
tcp = INVALID_SOCKET;
}
}
Sleep(10);
}
while (key != 'x');
closesocket(udp);
closesocket(tcp);
closesocket(srv);
WSACleanup();
printf("Done\n");
}

View File

@ -1,108 +0,0 @@
#include <stdio.h>
#include <conio.h>
unsigned char __fastcall__ w5100_init(void *parms);
void w5100_done(void);
int w5100_recv_init(void);
unsigned char w5100_recv_byte(void);
void w5100_recv_done(void);
unsigned char __fastcall__ w5100_send_init(unsigned int len);
void __fastcall__ w5100_send_byte(unsigned char val);
void w5100_send_done(void);
struct
{
unsigned char serverip [4];
unsigned char cfg_ip [4];
unsigned char cfg_netmask[4];
unsigned char cfg_gateway[4];
}
parms =
{
{192, 168, 0, 2}, // IP addr of machine running w5100_peer.c
{192, 168, 0, 123},
{255, 255, 255, 0},
{192, 168, 0, 1}
};
void main(void)
{
char key;
videomode(VIDEOMODE_80COL);
printf("Init\n");
if (!w5100_init(&parms))
{
printf("Faild To Connect To %d.%d.%d.%d\n", parms.serverip[0],
parms.serverip[1],
parms.serverip[2],
parms.serverip[3]);
return;
}
printf("Connected To %d.%d.%d.%d\n", parms.serverip[0],
parms.serverip[1],
parms.serverip[2],
parms.serverip[3]);
printf("(S)end or e(X)it\n");
do
{
unsigned len;
if (kbhit())
{
key = cgetc();
}
else
{
key = '\0';
}
if (key == 's')
{
unsigned i;
len = 500;
printf("Send Len %d", len);
while (!w5100_send_init(len))
{
printf("!");
}
for (i = 0; i < len; ++i)
{
w5100_send_byte(i);
}
w5100_send_done();
printf(".\n");
}
len = w5100_recv_init();
if (len == -1)
{
printf("Disconnect\n");
return;
}
else if (len)
{
unsigned i;
printf("Recv Len %d", len);
for (i = 0; i < len; ++i)
{
if ((i % 24) == 0)
{
printf("\n$%04X:", i);
}
printf(" %02X", w5100_recv_byte());
}
w5100_recv_done();
printf(".\n");
}
}
while (key != 'x');
w5100_done();
printf("Done\n");
}

View File

@ -1,96 +0,0 @@
#include <stdio.h>
#include <conio.h>
void __fastcall__ w5100_init(void *parms);
unsigned int w5100_recv_init(void);
unsigned char w5100_recv_byte(void);
void w5100_recv_done(void);
unsigned char __fastcall__ w5100_send_init(unsigned int len);
void __fastcall__ w5100_send_byte(unsigned char val);
void w5100_send_done(void);
struct
{
unsigned char serverip [4];
unsigned char cfg_ip [4];
unsigned char cfg_netmask[4];
unsigned char cfg_gateway[4];
}
parms =
{
{192, 168, 0, 2}, // IP addr of machine running w5100_peer.c
{192, 168, 0, 123},
{255, 255, 255, 0},
{192, 168, 0, 1}
};
void main(void)
{
char key;
videomode(VIDEOMODE_80COL);
printf("Init\n");
w5100_init(&parms);
printf("(S)end or e(X)it\n");
do
{
unsigned len;
if (kbhit())
{
key = cgetc();
}
else
{
key = '\0';
}
if (key == 's')
{
unsigned i;
len = 500;
printf("Send Len %d To %d.%d.%d.%d", len, parms.serverip[0],
parms.serverip[1],
parms.serverip[2],
parms.serverip[3]);
while (!w5100_send_init(len))
{
printf("!");
}
for (i = 0; i < len; ++i)
{
w5100_send_byte(i);
}
w5100_send_done();
printf(".\n");
}
len = w5100_recv_init();
if (len)
{
unsigned i;
printf("Recv Len %d From %d.%d.%d.%d", len, parms.serverip[0],
parms.serverip[1],
parms.serverip[2],
parms.serverip[3]);
for (i = 0; i < len; ++i)
{
if ((i % 24) == 0)
{
printf("\n$%04X:", i);
}
printf(" %02X", w5100_recv_byte());
}
w5100_recv_done();
printf(".\n");
}
}
while (key != 'x');
printf("Done\n");
}