mirror of
https://github.com/bobbimanners/emailler.git
synced 2025-04-30 18:37:05 +00:00
Introduced C interface to IP65.
The IP5 usage of ld65 segments and zeropage variables was made compatible with cc65 C programs already a while ago. This commit is the next logical step which is to introduce the actual C interface to IP65. IP65 for C programs shares the the ip65.lib / ip65_tcp.lib with IP65 for assembler programs. However the various libraries from the 'drivers' are not reused. Instead there's exactly one library for every target named ip65_<target>.lib. Those libraries contain only functions used by ip65.lib / ip65_tcp.lib. TODOs: - Introduce c64_timer.s and atr_timer.s. - Add a C interface to the rest of the IP65 functionality (especially TCP).
This commit is contained in:
parent
32a66c5d7c
commit
6680772b04
@ -1,3 +1,5 @@
|
||||
# For assembler programs
|
||||
# ----------------------
|
||||
# c64rrnet.lib : C64 with RR-Net (or clone) (default base addr: $de0x)
|
||||
# c64eth64.lib : C64 with ETH64 (default base addr: $de0x)
|
||||
# c64wiz811.lib : C64 with WIZ811MJ (default base addr: $de0x)
|
||||
@ -9,20 +11,32 @@
|
||||
# atrdragon.lib : ATARI 8-bit with Dragon Cart (default base addr: $d500)
|
||||
# vic20rrnet.lib : VIC20 with RR-Net or clone (default base addr: $980x)
|
||||
|
||||
# For C programs
|
||||
# --------------
|
||||
# ip65_c64.lib : C64 with RR-Net or ETH64 or WIZ811MJ (default base addr: $de0x)
|
||||
# ip65_apple2.lib : Apple ][ with Uthernet or LANceGS or Uthernet II (default slot: #3)
|
||||
# ip65_atari.lib : ATARI 8-bit with Dragon Cart (default base addr: $d500)
|
||||
|
||||
DRIVERS=\
|
||||
c64rrnet.lib \
|
||||
c64eth64.lib \
|
||||
c64wiz811.lib \
|
||||
c64combo.lib \
|
||||
ip65_c64.lib \
|
||||
a2uther.lib \
|
||||
a2lancegs.lib \
|
||||
a2uther2.lib \
|
||||
a2combo.lib \
|
||||
ip65_apple2.lib \
|
||||
atrdragon.lib \
|
||||
ip65_atari.lib \
|
||||
vic20rrnet.lib
|
||||
|
||||
all: $(DRIVERS)
|
||||
|
||||
$(DRIVERS):
|
||||
ar65 a $@ $^
|
||||
|
||||
%.o: %.s
|
||||
ca65 -D DYN_DRV=0 $<
|
||||
|
||||
@ -35,6 +49,10 @@ C64OBJS=\
|
||||
c64vt100.o \
|
||||
cbmcharconv.o
|
||||
|
||||
C64_OBJS=\
|
||||
c64timer.o \
|
||||
c64_input.o
|
||||
|
||||
A2OBJS=\
|
||||
a2print.o \
|
||||
a2timer.o \
|
||||
@ -44,6 +62,10 @@ A2OBJS=\
|
||||
a2vt100.o \
|
||||
a2charconv.o
|
||||
|
||||
A2_OBJS=\
|
||||
a2_timer.o \
|
||||
a2_input.o
|
||||
|
||||
ATROBJS=\
|
||||
atrprint.o \
|
||||
atrtimer.o \
|
||||
@ -54,6 +76,10 @@ ATROBJS=\
|
||||
atrvt100font.o \
|
||||
atrcharconv.o
|
||||
|
||||
ATR_OBJS=\
|
||||
atrtimer.o \
|
||||
atr_input.o
|
||||
|
||||
VIC20OBJS=\
|
||||
vic20print.o \
|
||||
vic20timer.o \
|
||||
@ -63,35 +89,52 @@ VIC20OBJS=\
|
||||
vic20vt100.o \
|
||||
cbmcharconv.o
|
||||
|
||||
c64rrnet.lib: rr-net.o cs8900a.o cs8900adriver.o ethernet.o c64init.o $(C64OBJS)
|
||||
ar65 a $@ $^
|
||||
CS8900AOBJS=\
|
||||
cs8900a.o \
|
||||
cs8900adriver.o \
|
||||
ethernet.o
|
||||
|
||||
c64eth64.lib: eth64.o lan91c96.o lan91c96driver.o ethernet.o c64init.o $(C64OBJS)
|
||||
ar65 a $@ $^
|
||||
LAN91C96OBJS=\
|
||||
lan91c96.o \
|
||||
lan91c96driver.o \
|
||||
ethernet.o
|
||||
|
||||
c64wiz811.lib: wiz811mj.o w5100.o w5100driver.o ethernet.o c64init.o $(C64OBJS)
|
||||
ar65 a $@ $^
|
||||
W5100OBJS=\
|
||||
w5100.o \
|
||||
w5100driver.o \
|
||||
ethernet.o
|
||||
|
||||
c64combo.lib: rr-net.o cs8900a.o eth64.o lan91c96.o wiz811mj.o w5100.o ethernetcombo.o c64init.o $(C64OBJS)
|
||||
ar65 a $@ $^
|
||||
COMBOOBJS=\
|
||||
cs8900a.o \
|
||||
lan91c96.o \
|
||||
w5100.o \
|
||||
ethernetcombo.o
|
||||
|
||||
a2uther.lib: uthernet.o cs8900a.o cs8900adriver.o ethernet.o a2init.o $(A2OBJS)
|
||||
ar65 a $@ $^
|
||||
c64rrnet.lib: c64init.o rr-net.o $(CS8900AOBJS) $(C64OBJS)
|
||||
|
||||
a2lancegs.lib: lancegs.o lan91c96.o lan91c96driver.o ethernet.o a2init.o $(A2OBJS)
|
||||
ar65 a $@ $^
|
||||
c64eth64.lib: c64init.o eth64.o $(LAN91C96OBJS) $(C64OBJS)
|
||||
|
||||
a2uther2.lib: uthernet2.o w5100.o w5100driver.o ethernet.o a2init.o $(A2OBJS)
|
||||
ar65 a $@ $^
|
||||
c64wiz811.lib: c64init.o wiz811mj.o $(W5100OBJS) $(C64OBJS)
|
||||
|
||||
a2combo.lib: uthernet.o cs8900a.o lancegs.o lan91c96.o uthernet2.o w5100.o ethernetcombo.o a2initcombo.o $(A2OBJS)
|
||||
ar65 a $@ $^
|
||||
c64combo.lib: c64init.o rr-net.o eth64.o wiz811mj.o $(COMBOOBJS) $(C64OBJS)
|
||||
|
||||
atrdragon.lib: dragoncart.o cs8900a.o cs8900adriver.o ethernet.o atrinit.o $(ATROBJS)
|
||||
ar65 a $@ $^
|
||||
ip65_c64.lib: c64init.o rr-net.o eth64.o wiz811mj.o $(COMBOOBJS) $(C64_OBJS)
|
||||
|
||||
vic20rrnet.lib: vic20-rr-net.o cs8900a.o cs8900adriver.o ethernet.o vic20init.o $(VIC20OBJS)
|
||||
ar65 a $@ $^
|
||||
a2uther.lib: a2init.o uthernet.o $(CS8900AOBJS) $(A2OBJS)
|
||||
|
||||
a2lancegs.lib: a2init.o lancegs.o $(LAN91C96OBJS) $(A2OBJS)
|
||||
|
||||
a2uther2.lib: a2init.o uthernet2.o $(W5100OBJS) $(A2OBJS)
|
||||
|
||||
a2combo.lib: a2initcombo.o uthernet.o lancegs.o uthernet2.o $(COMBOOBJS) $(A2OBJS)
|
||||
|
||||
ip65_apple2.lib: a2initcombo.o uthernet.o lancegs.o uthernet2.o $(COMBOOBJS) $(A2_OBJS)
|
||||
|
||||
atrdragon.lib: atrinit.o dragoncart.o $(CS8900AOBJS) $(ATROBJS)
|
||||
|
||||
ip65_atari.lib: atrinit.o dragoncart.o $(CS8900AOBJS) $(ATR_OBJS)
|
||||
|
||||
vic20rrnet.lib: vic20init.o vic20-rr-net.o $(CS8900AOBJS) $(VIC20OBJS)
|
||||
|
||||
clean:
|
||||
-rm -f *.o
|
||||
|
46
drivers/a2_input.s
Normal file
46
drivers/a2_input.s
Normal file
@ -0,0 +1,46 @@
|
||||
.export check_for_abort_key
|
||||
.export abort_key
|
||||
.exportzp abort_key_default = $9b
|
||||
.exportzp abort_key_disable = $80
|
||||
|
||||
|
||||
.data
|
||||
|
||||
abort_key: .byte $9b ; ESC
|
||||
|
||||
|
||||
.code
|
||||
|
||||
; check whether the abort key is being pressed
|
||||
; inputs: none
|
||||
; outputs: sec if abort key pressed, clear otherwise
|
||||
check_for_abort_key:
|
||||
lda $c000 ; current key pressed
|
||||
cmp abort_key
|
||||
bne :+
|
||||
bit $c010 ; clear the keyboard strobe
|
||||
sec
|
||||
rts
|
||||
: clc
|
||||
rts
|
||||
|
||||
|
||||
|
||||
; -- LICENSE FOR a2_inputc.s --
|
||||
; The contents of this file are subject to the Mozilla Public License
|
||||
; Version 1.1 (the "License"); you may not use this file except in
|
||||
; compliance with the License. You may obtain a copy of the License at
|
||||
; http://www.mozilla.org/MPL/
|
||||
;
|
||||
; Software distributed under the License is distributed on an "AS IS"
|
||||
; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
; License for the specific language governing rights and limitations
|
||||
; under the License.
|
||||
;
|
||||
; The Original Code is ip65.
|
||||
;
|
||||
; The Initial Developer of the Original Code is Jonno Downes,
|
||||
; jonno@jamtronix.com.
|
||||
; Portions created by the Initial Developer are Copyright (C) 2009
|
||||
; Jonno Downes. All Rights Reserved.
|
||||
; -- LICENSE END --
|
73
drivers/a2_timer.s
Normal file
73
drivers/a2_timer.s
Normal file
@ -0,0 +1,73 @@
|
||||
; timer routines
|
||||
;
|
||||
; unfortunately the standard Apple 2 has no CIA or VBI, so for the moment, we will
|
||||
; make each call to 'timer_read' delay for a little while
|
||||
; this kludge will make the polling loops work at least
|
||||
;
|
||||
; timer_read is meant to return a counter with millisecond resolution
|
||||
|
||||
.include "../inc/common.i"
|
||||
|
||||
.export timer_init
|
||||
.export timer_read
|
||||
.export timer_seconds
|
||||
|
||||
|
||||
.bss
|
||||
|
||||
current_time_value: .res 2
|
||||
|
||||
|
||||
.code
|
||||
|
||||
; reset timer to 0
|
||||
; inputs: none
|
||||
; outputs: none
|
||||
timer_init:
|
||||
ldax #0
|
||||
stax current_time_value
|
||||
rts
|
||||
|
||||
; this SHOULD just read the current timer value
|
||||
; but since a standard apple 2 has no dedicated timing circuit,
|
||||
; each call to this function actually delays a while, then updates the current value
|
||||
; inputs: none
|
||||
; outputs: AX = current timer value (roughly equal to number of milliseconds since the last call to 'timer_init')
|
||||
timer_read:
|
||||
bit $c082 ; switch in ROM
|
||||
lda #111
|
||||
jsr $fca8 ; wait for about 33ms
|
||||
clc
|
||||
lda #33
|
||||
adc current_time_value
|
||||
sta current_time_value
|
||||
bcc :+
|
||||
inc current_time_value+1
|
||||
: ldax current_time_value
|
||||
bit $c080 ; switch in LC bank 2 for R/O
|
||||
rts
|
||||
|
||||
timer_seconds:
|
||||
lda #0
|
||||
rts
|
||||
|
||||
|
||||
|
||||
; -- LICENSE FOR a2_timerc.s --
|
||||
; The contents of this file are subject to the Mozilla Public License
|
||||
; Version 1.1 (the "License"); you may not use this file except in
|
||||
; compliance with the License. You may obtain a copy of the License at
|
||||
; http://www.mozilla.org/MPL/
|
||||
;
|
||||
; Software distributed under the License is distributed on an "AS IS"
|
||||
; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
; License for the specific language governing rights and limitations
|
||||
; under the License.
|
||||
;
|
||||
; The Original Code is ip65.
|
||||
;
|
||||
; The Initial Developer of the Original Code is Jonno Downes,
|
||||
; jonno@jamtronix.com.
|
||||
; Portions created by the Initial Developer are Copyright (C) 2009
|
||||
; Jonno Downes. All Rights Reserved.
|
||||
; -- LICENSE END --
|
49
drivers/atr_input.s
Normal file
49
drivers/atr_input.s
Normal file
@ -0,0 +1,49 @@
|
||||
.include "atari.inc"
|
||||
|
||||
.export check_for_abort_key
|
||||
.export abort_key
|
||||
.exportzp abort_key_default = 1
|
||||
.exportzp abort_key_disable = 0
|
||||
|
||||
|
||||
.data
|
||||
|
||||
abort_key: .byte 1
|
||||
|
||||
|
||||
.code
|
||||
|
||||
; check whether the abort key is being pressed
|
||||
; inputs: none
|
||||
; outputs: sec if abort key pressed, clear otherwise
|
||||
check_for_abort_key:
|
||||
lda abort_key ; is "abort" enabled?
|
||||
beq nokey ; no
|
||||
lda BRKKEY
|
||||
bne nokey
|
||||
dec BRKKEY
|
||||
sec
|
||||
rts
|
||||
nokey:
|
||||
clc
|
||||
rts
|
||||
|
||||
|
||||
;-- LICENSE FOR atr_inputs.s --
|
||||
; The contents of this file are subject to the Mozilla Public License
|
||||
; Version 1.1 (the "License"); you may not use this file except in
|
||||
; compliance with the License. You may obtain a copy of the License at
|
||||
; http://www.mozilla.org/MPL/
|
||||
;
|
||||
; Software distributed under the License is distributed on an "AS IS"
|
||||
; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
; License for the specific language governing rights and limitations
|
||||
; under the License.
|
||||
;
|
||||
; The Original Code is ip65.
|
||||
;
|
||||
; The Initial Developer of the Original Code is Jonno Downes,
|
||||
; jonno@jamtronix.com.
|
||||
; Portions created by the Initial Developer are Copyright (C) 2009
|
||||
; Jonno Downes. All Rights Reserved.
|
||||
; -- LICENSE END --
|
54
drivers/c64_input.s
Normal file
54
drivers/c64_input.s
Normal file
@ -0,0 +1,54 @@
|
||||
.export check_for_abort_key
|
||||
.export abort_key
|
||||
.exportzp abort_key_default = $3f
|
||||
.exportzp abort_key_disable = $ff
|
||||
|
||||
|
||||
.data
|
||||
|
||||
abort_key: .byte $3f ; RUN/STOP
|
||||
|
||||
|
||||
.code
|
||||
|
||||
; check whether the abort key is being pressed
|
||||
; inputs: none
|
||||
; outputs: sec if abort key pressed, clear otherwise
|
||||
check_for_abort_key:
|
||||
lda $cb ; current key pressed
|
||||
cmp abort_key
|
||||
bne no_key
|
||||
@flush_loop:
|
||||
ldy #$ff
|
||||
jsr $f142 ; not officially documented - where F13E (GETIN) falls through to if device # is 0 (KEYBD)
|
||||
cpy #$ff ; Y gets modified iff there's a character available - this approach allows to read ^@ as 0
|
||||
bne @flush_loop
|
||||
lda $cb ; current key pressed
|
||||
cmp abort_key
|
||||
beq @flush_loop
|
||||
sec
|
||||
rts
|
||||
no_key:
|
||||
clc
|
||||
rts
|
||||
|
||||
|
||||
|
||||
; -- LICENSE FOR c64_input.s --
|
||||
; The contents of this file are subject to the Mozilla Public License
|
||||
; Version 1.1 (the "License"); you may not use this file except in
|
||||
; compliance with the License. You may obtain a copy of the License at
|
||||
; http://www.mozilla.org/MPL/
|
||||
;
|
||||
; Software distributed under the License is distributed on an "AS IS"
|
||||
; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
; License for the specific language governing rights and limitations
|
||||
; under the License.
|
||||
;
|
||||
; The Original Code is ip65.
|
||||
;
|
||||
; The Initial Developer of the Original Code is Jonno Downes,
|
||||
; jonno@jamtronix.com.
|
||||
; Portions created by the Initial Developer are Copyright (C) 2009
|
||||
; Jonno Downes. All Rights Reserved.
|
||||
; -- LICENSE END --
|
181
inc/ip65.h
Normal file
181
inc/ip65.h
Normal file
@ -0,0 +1,181 @@
|
||||
#ifndef _IP65_H
|
||||
#define _IP65_H
|
||||
|
||||
// Error codes
|
||||
//
|
||||
#define IP65_ERROR_PORT_IN_USE $80
|
||||
#define IP65_ERROR_TIMEOUT_ON_RECEIVE $81
|
||||
#define IP65_ERROR_TRANSMIT_FAILED $82
|
||||
#define IP65_ERROR_TRANSMISSION_REJECTED_BY_PEER $83
|
||||
#define IP65_ERROR_INPUT_TOO_LARGE $84
|
||||
#define IP65_ERROR_DEVICE_FAILURE $85
|
||||
#define IP65_ERROR_ABORTED_BY_USER $86
|
||||
#define IP65_ERROR_LISTENER_NOT_AVAILABLE $87
|
||||
#define IP65_ERROR_CONNECTION_RESET_BY_PEER $89
|
||||
#define IP65_ERROR_CONNECTION_CLOSED $8A
|
||||
#define IP65_ERROR_FILE_ACCESS_FAILURE $90
|
||||
#define IP65_ERROR_MALFORMED_URL $A0
|
||||
#define IP65_ERROR_DNS_LOOKUP_FAILED $A1
|
||||
|
||||
// Last error code
|
||||
//
|
||||
extern unsigned char ip65_error;
|
||||
|
||||
// MAC address of local machine (will be overwritten if ip65_init is called)
|
||||
//
|
||||
extern unsigned char cfg_mac[6];
|
||||
|
||||
// IP address of local machine (will be overwritten if dhcp_init is called)
|
||||
//
|
||||
extern unsigned long cfg_ip;
|
||||
|
||||
// Netmask of local network (will be overwritten if dhcp_init is called)
|
||||
//
|
||||
extern unsigned long cfg_netmask;
|
||||
|
||||
// IP address of router on local network (will be overwritten if dhcp_init is called)
|
||||
//
|
||||
extern unsigned long cfg_gateway;
|
||||
|
||||
// IP address of dns server to use (will be overwritten if dhcp_init is called)
|
||||
//
|
||||
extern unsigned long cfg_dns;
|
||||
|
||||
// Will be set to address of DHCP server that configuration was obtained from
|
||||
//
|
||||
extern unsigned long dhcp_server;
|
||||
|
||||
//
|
||||
//
|
||||
extern unsigned char* tcp_packet;
|
||||
extern unsigned int tcp_packet_len;
|
||||
|
||||
// Initialise the IP stack
|
||||
//
|
||||
// This calls the individual protocol & driver initialisations, so this is
|
||||
// the only *_init routine that must be called by a user application,
|
||||
// except for dhcp_init which must also be called if the application
|
||||
// is using DHCP rather than hardcoded IP configuration.
|
||||
//
|
||||
// Inputs: None
|
||||
// Output: 1 if there was an error, 0 otherwise
|
||||
//
|
||||
unsigned char ip65_init(void);
|
||||
|
||||
// Main IP polling loop
|
||||
//
|
||||
// This routine should be periodically called by an application at any time
|
||||
// that an inbound packet needs to be handled.
|
||||
// It is 'non-blocking', i.e. it will return if there is no packet waiting to be
|
||||
// handled. Any inbound packet will be handed off to the appropriate handler.
|
||||
//
|
||||
// Inputs: None
|
||||
// Output: 1 if no packet was waiting or packet handling caused error, 0 otherwise
|
||||
//
|
||||
unsigned char ip65_process(void);
|
||||
|
||||
// Generate a 'random' 16 bit word
|
||||
//
|
||||
// Entropy comes from the last ethernet frame, counters, and timer.
|
||||
//
|
||||
// Inputs: None
|
||||
// Output: Pseudo-random 16 bit number
|
||||
//
|
||||
unsigned int ip65_random_word(void);
|
||||
|
||||
// Convert 4 octets (IP address, netmask) into a string representing a dotted quad
|
||||
//
|
||||
// The string is returned in a statically allocated buffer, which subsequent calls
|
||||
// will overwrite.
|
||||
//
|
||||
// Inputs: quad: IP address
|
||||
// Output: Null terminated string containing dotted quad (e.g. "192.168.1.0")
|
||||
//
|
||||
char* __fastcall__ dotted_quad(unsigned long quad);
|
||||
|
||||
// Convert a string representing a dotted quad (IP address, netmask) into 4 octets
|
||||
//
|
||||
// Inputs: quad: Null terminated string containing dotted quad (e.g. "192.168.1.0"),
|
||||
// to simplify URL parsing, a ':' or '/' can also terminate the string.
|
||||
// Output: IP address, 0 on error
|
||||
//
|
||||
unsigned long __fastcall__ parse_dotted_quad(char* quad);
|
||||
|
||||
// Minimal DHCP client implementation
|
||||
//
|
||||
// IP addresses are requested from a DHCP server (aka 'leased') but are not renewed
|
||||
// or released. Although this is not correct behaviour according to the DHCP RFC,
|
||||
// this works fine in practice in a typical home network environment.
|
||||
//
|
||||
// Inputs: None (although ip65_init should be called first)
|
||||
// Output: 0 if IP config has been sucesfully obtained and cfg_ip, cfg_netmask,
|
||||
// cfg_gateway and cfg_dns will be set per response from dhcp server.
|
||||
// dhcp_server will be set to address of server that provided configuration.
|
||||
// 1 if there was an error
|
||||
//
|
||||
unsigned char dhcp_init(void);
|
||||
|
||||
// Resolve a string containing a hostname (or a dotted quad) to an IP address
|
||||
//
|
||||
// Inputs: hostname: pointer to null terminated string that contains either
|
||||
// a DNS hostname (e.g. "host.example.com") or an address
|
||||
// in "dotted quad" format (e.g. "192.168.1.0").
|
||||
// Output: IP address of the hostname, 0 on error
|
||||
//
|
||||
unsigned long __fastcall__ dns_resolve(const char* hostname);
|
||||
|
||||
// Send a ping (ICMP echo request) to a remote host, and wait for a response
|
||||
//
|
||||
// Inputs: dest: Destination IP address
|
||||
// Output: 0 if no response, otherwise time (in miliseconds) for host to respond
|
||||
//
|
||||
unsigned int __fastcall__ icmp_ping(unsigned long dest);
|
||||
|
||||
// Add a UDP listener
|
||||
//
|
||||
// Inputs: port: UDP port to listen on
|
||||
// callback: Vector to call when UDP packet arrives on specified port
|
||||
// Output: 1 if too may listeners already installed, 0 otherwise
|
||||
//
|
||||
unsigned char __fastcall__ udp_add_listener(unsigned int port, void (*callback)(void));
|
||||
|
||||
// Remove a UDP listener
|
||||
//
|
||||
// Inputs: port: UDP port to stop listening on
|
||||
// Output: 0 if handler found and removed,
|
||||
// 1 if handler for specified port not found
|
||||
//
|
||||
unsigned char __fastcall__ udp_remove_listener(unsigned int port);
|
||||
|
||||
// Access to received UDP packet
|
||||
//
|
||||
// Access to the four items below is only valid in the context of a callback
|
||||
// added with udp_add_listener.
|
||||
//
|
||||
extern unsigned char udp_recv_buf[1476]; // Buffer with data received
|
||||
unsigned int udp_recv_len(void); // Length of data received
|
||||
unsigned long udp_recv_src(void); // Source IP address
|
||||
unsigned int udp_recv_src_port(void); // Source port
|
||||
|
||||
// Send a UDP packet
|
||||
//
|
||||
// If the correct MAC address can't be found in the ARP cache then
|
||||
// an ARP request is sent - and the UDP packet is NOT sent. The caller
|
||||
// should wait a while calling ip65_process (to allow time for an ARP
|
||||
// response to arrive) and then call upd_send again. This behavior
|
||||
// makes sense as a UDP packet may get lost in transit at any time
|
||||
// so the caller should to be prepared to resend it after a while
|
||||
// anyway.
|
||||
//
|
||||
// Inputs: buf: Pointer to buffer containing data to be sent
|
||||
// len: Length of data to send (exclusive of any headers)
|
||||
// dest: Destination IP address
|
||||
// dest_port: Destination port
|
||||
// src_port: Source port
|
||||
// Output: 1 if an error occured, 0 otherwise
|
||||
//
|
||||
unsigned char __fastcall__ udp_send(const unsigned char* buf, unsigned int len,
|
||||
unsigned long dest, unsigned int dest_port,
|
||||
unsigned int src_port);
|
||||
|
||||
#endif
|
@ -13,14 +13,20 @@ IP65OBJS=\
|
||||
arithmetic.o \
|
||||
arp.o \
|
||||
config.o \
|
||||
config_c.o \
|
||||
copymem.o \
|
||||
dhcp.o \
|
||||
dhcp_c.o \
|
||||
dns.o \
|
||||
dns_c.o \
|
||||
dottedquad.o \
|
||||
dottedquad_c.o \
|
||||
eth.o \
|
||||
http.o \
|
||||
httpd.o \
|
||||
icmp_c.o \
|
||||
ip65.o \
|
||||
ip65_c.o \
|
||||
tftp.o \
|
||||
timer.o \
|
||||
output_buffer.o \
|
||||
@ -28,6 +34,7 @@ IP65OBJS=\
|
||||
sntp.o \
|
||||
string_utils.o \
|
||||
udp.o \
|
||||
udp_c.o \
|
||||
url.o
|
||||
|
||||
ip65.lib: $(IP65OBJS) ip.o icmp.o
|
||||
|
27
ip65/config_c.s
Normal file
27
ip65/config_c.s
Normal file
@ -0,0 +1,27 @@
|
||||
.include "../inc/common.i"
|
||||
|
||||
.export _cfg_mac
|
||||
.export _cfg_ip
|
||||
.export _cfg_netmask
|
||||
.export _cfg_gateway
|
||||
.export _cfg_dns
|
||||
.export _dhcp_server
|
||||
|
||||
.import cfg_mac
|
||||
.import cfg_ip
|
||||
.import cfg_netmask
|
||||
.import cfg_gateway
|
||||
.import cfg_dns
|
||||
.import dhcp_server
|
||||
|
||||
_cfg_mac := cfg_mac
|
||||
|
||||
_cfg_ip := cfg_ip
|
||||
|
||||
_cfg_netmask := cfg_netmask
|
||||
|
||||
_cfg_gateway := cfg_gateway
|
||||
|
||||
_cfg_dns := cfg_dns
|
||||
|
||||
_dhcp_server := dhcp_server
|
12
ip65/dhcp_c.s
Normal file
12
ip65/dhcp_c.s
Normal file
@ -0,0 +1,12 @@
|
||||
.include "../inc/common.i"
|
||||
|
||||
.export _dhcp_init
|
||||
|
||||
.import dhcp_init
|
||||
|
||||
_dhcp_init:
|
||||
jsr dhcp_init
|
||||
ldx #$00
|
||||
txa
|
||||
rol
|
||||
rts
|
25
ip65/dns_c.s
Normal file
25
ip65/dns_c.s
Normal file
@ -0,0 +1,25 @@
|
||||
.include "../inc/common.i"
|
||||
|
||||
.export _dns_resolve
|
||||
|
||||
.import dns_set_hostname
|
||||
.import dns_resolve
|
||||
.import dns_ip
|
||||
|
||||
.importzp sreg
|
||||
|
||||
_dns_resolve:
|
||||
jsr dns_set_hostname
|
||||
bcs error
|
||||
jsr dns_resolve
|
||||
bcs error
|
||||
ldax dns_ip+2
|
||||
stax sreg
|
||||
ldax dns_ip
|
||||
rts
|
||||
|
||||
error:
|
||||
ldx #$00
|
||||
txa
|
||||
stax sreg
|
||||
rts
|
92
ip65/dottedquad_c.s
Normal file
92
ip65/dottedquad_c.s
Normal file
@ -0,0 +1,92 @@
|
||||
.include "../inc/common.i"
|
||||
|
||||
.export _dotted_quad
|
||||
.export _parse_dotted_quad
|
||||
|
||||
.import parse_dotted_quad
|
||||
.import dotted_quad_value
|
||||
|
||||
.importzp sreg, tmp1, tmp2, tmp3
|
||||
|
||||
|
||||
.bss
|
||||
|
||||
dotted_quad: .res 4*4 ; "xxx.xxx.xxx.xxx\0"
|
||||
|
||||
.code
|
||||
|
||||
_dotted_quad:
|
||||
stax dotted_quad_value
|
||||
ldax sreg
|
||||
stax dotted_quad_value+2
|
||||
|
||||
ldx #$00
|
||||
ldy #$00
|
||||
: jsr convert_byte
|
||||
inx
|
||||
cpx #4
|
||||
bcc :-
|
||||
|
||||
dey
|
||||
lda #$00
|
||||
sta dotted_quad,y ; replace last dot with '\0'
|
||||
ldax #dotted_quad
|
||||
rts
|
||||
|
||||
convert_byte:
|
||||
; hex to bcd routine taken from Andrew Jacob's code at http://www.6502.org/source/integers/hex2dec-more.htm
|
||||
sed ; switch to decimal mode
|
||||
lda #$00 ; ensure the result is clear
|
||||
sta tmp1 ; BCD low
|
||||
sta tmp2 ; BCD high
|
||||
lda #8 ; the number of source bits
|
||||
sta tmp3
|
||||
: asl dotted_quad_value,x ; shift out one bit
|
||||
lda tmp1 ; and add into result
|
||||
adc tmp1
|
||||
sta tmp1
|
||||
lda tmp2 ; propagating any carry
|
||||
adc tmp2
|
||||
sta tmp2
|
||||
dec tmp3 ; and repeat for next bit
|
||||
bne :-
|
||||
cld ; back to binary
|
||||
|
||||
lda tmp2
|
||||
beq :+
|
||||
ora #'0'
|
||||
sta dotted_quad,y ; write x00 if not 0
|
||||
iny
|
||||
: lda tmp1
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
beq :+
|
||||
ora #'0'
|
||||
sta dotted_quad,y ; write 0x0 if not 0
|
||||
iny
|
||||
: lda tmp1
|
||||
and #$0F
|
||||
ora #'0'
|
||||
sta dotted_quad,y ; write 00x
|
||||
iny
|
||||
|
||||
lda #'.'
|
||||
sta dotted_quad,y ; write dot
|
||||
iny
|
||||
rts
|
||||
|
||||
_parse_dotted_quad:
|
||||
jsr parse_dotted_quad
|
||||
bcs error
|
||||
ldax dotted_quad_value+2
|
||||
stax sreg
|
||||
ldax dotted_quad_value
|
||||
rts
|
||||
|
||||
error:
|
||||
ldx #$00
|
||||
txa
|
||||
stax sreg
|
||||
rts
|
18
ip65/icmp_c.s
Normal file
18
ip65/icmp_c.s
Normal file
@ -0,0 +1,18 @@
|
||||
.include "../inc/common.i"
|
||||
|
||||
.export _icmp_ping
|
||||
|
||||
.import icmp_echo_ip
|
||||
.import icmp_ping
|
||||
|
||||
.importzp sreg
|
||||
|
||||
_icmp_ping:
|
||||
stax icmp_echo_ip
|
||||
ldax sreg
|
||||
stax icmp_echo_ip+2
|
||||
jsr icmp_ping
|
||||
bcc :+
|
||||
ldx #$00
|
||||
txa
|
||||
: rts
|
29
ip65/ip65_c.s
Normal file
29
ip65/ip65_c.s
Normal file
@ -0,0 +1,29 @@
|
||||
.include "../inc/common.i"
|
||||
|
||||
.export _ip65_init
|
||||
.export _ip65_process
|
||||
.export _ip65_random_word
|
||||
.export _ip65_error
|
||||
|
||||
.import ip65_init
|
||||
.import ip65_process
|
||||
.import ip65_random_word
|
||||
.import ip65_error
|
||||
|
||||
_ip65_init:
|
||||
jsr ip65_init
|
||||
ldx #$00
|
||||
txa
|
||||
rol
|
||||
rts
|
||||
|
||||
_ip65_process:
|
||||
jsr ip65_process
|
||||
ldx #$00
|
||||
txa
|
||||
rol
|
||||
rts
|
||||
|
||||
_ip65_random_word := ip65_random_word
|
||||
|
||||
_ip65_error := ip65_error
|
83
ip65/udp_c.s
Normal file
83
ip65/udp_c.s
Normal file
@ -0,0 +1,83 @@
|
||||
.include "../inc/common.i"
|
||||
|
||||
.export _udp_add_listener
|
||||
.export _udp_remove_listener
|
||||
.export _udp_recv_buf
|
||||
.export _udp_recv_len
|
||||
.export _udp_recv_src
|
||||
.export _udp_recv_src_port
|
||||
.export _udp_send
|
||||
|
||||
.import udp_add_listener
|
||||
.import udp_remove_listener
|
||||
.import ip_inp
|
||||
.import udp_inp
|
||||
.import udp_send
|
||||
|
||||
.import udp_callback
|
||||
.importzp ip_src
|
||||
.importzp udp_src_port
|
||||
.importzp udp_len
|
||||
.importzp udp_data
|
||||
.import udp_send_len
|
||||
.import udp_send_dest
|
||||
.import udp_send_dest_port
|
||||
.import udp_send_src_port
|
||||
|
||||
.import popax, popeax
|
||||
.importzp sreg
|
||||
|
||||
_udp_add_listener:
|
||||
stax udp_callback
|
||||
jsr popax
|
||||
jsr udp_add_listener
|
||||
ldx #$00
|
||||
txa
|
||||
rol
|
||||
rts
|
||||
|
||||
_udp_remove_listener:
|
||||
jsr udp_remove_listener
|
||||
ldx #$00
|
||||
txa
|
||||
rol
|
||||
rts
|
||||
|
||||
_udp_recv_buf := udp_inp+udp_data
|
||||
|
||||
_udp_recv_len:
|
||||
lda udp_inp+udp_len+1
|
||||
ldx udp_inp+udp_len
|
||||
sec
|
||||
sbc #udp_data
|
||||
bcs :+
|
||||
dex
|
||||
: rts
|
||||
|
||||
_udp_recv_src:
|
||||
ldax ip_inp+ip_src+2
|
||||
stax sreg
|
||||
ldax ip_inp+ip_src
|
||||
rts
|
||||
|
||||
_udp_recv_src_port:
|
||||
lda udp_inp+udp_src_port+1
|
||||
ldx udp_inp+udp_src_port
|
||||
rts
|
||||
|
||||
_udp_send:
|
||||
stax udp_send_src_port
|
||||
jsr popax
|
||||
stax udp_send_dest_port
|
||||
jsr popeax
|
||||
stax udp_send_dest
|
||||
ldax sreg
|
||||
stax udp_send_dest+2
|
||||
jsr popax
|
||||
stax udp_send_len
|
||||
jsr popax
|
||||
jsr udp_send
|
||||
ldx #$00
|
||||
txa
|
||||
rol
|
||||
rts
|
@ -29,6 +29,7 @@ UDP =\
|
||||
parsequerystring \
|
||||
sntp \
|
||||
tftp \
|
||||
udp \
|
||||
vt100
|
||||
|
||||
TCP =\
|
||||
@ -91,6 +92,8 @@ vt100.com: ATARI_CFG = ../apps/atrtelnet.cfg
|
||||
%-slotscan.o: %.s
|
||||
ca65 -D A2_SLOT_SCAN -o $@ $<
|
||||
|
||||
%.o: %.c
|
||||
|
||||
%.prg: %.o ip65 drivers $(INCFILES)
|
||||
ld65 -o $*.prg -C c64.cfg -m $*.c64.map -vm $< $(IP65LIB) $(C64DRIVERLIB) c64.lib
|
||||
|
||||
@ -103,6 +106,18 @@ vt100.com: ATARI_CFG = ../apps/atrtelnet.cfg
|
||||
%.vicprg: %.o ip65 drivers $(INCFILES)
|
||||
ld65 -o $*.vicprg -C vic20-32k.cfg -m $*.vic.map -vm $< $(IP65LIB) $(VICDRIVERLIB) vic20.lib
|
||||
|
||||
%.prg: %.c ip65 drivers $(INCFILES)
|
||||
cl65 -o $*.prg -O -t c64 -m $*.c64.map -vm $< $(IP65LIB) ../drivers/ip65_c64.lib
|
||||
rm $*.o
|
||||
|
||||
%.bin: %.c ip65 drivers $(INCFILES)
|
||||
cl65 -o $*.bin -O -t apple2 -m $*.a2.map -vm $< $(IP65LIB) ../drivers/ip65_apple2.lib
|
||||
rm $*.o
|
||||
|
||||
%.com: %.c ip65 drivers $(INCFILES)
|
||||
cl65 -o $*.com -O -t atari -m $*.atr.map -vm $< $(IP65LIB) ../drivers/ip65_atari.lib
|
||||
rm $*.o
|
||||
|
||||
ip65test.d64: prg
|
||||
$(C1541) -format ip65,00 d64 $@
|
||||
$(C1541) -attach $@ -write dns.prg dns,p
|
||||
@ -114,6 +129,7 @@ ip65test.d64: prg
|
||||
$(C1541) -attach $@ -write ping.prg ping,p
|
||||
$(C1541) -attach $@ -write sntp.prg sntp,p
|
||||
$(C1541) -attach $@ -write tftp.prg tftp,p
|
||||
$(C1541) -attach $@ -write udp.prg udp,p
|
||||
$(C1541) -attach $@ -write vt100.prg vt100,p
|
||||
|
||||
ip65test.dsk: bin
|
||||
@ -128,6 +144,7 @@ ip65test.dsk: bin
|
||||
java -jar $(AC) -cc65 $@ ping bin < ping.bin
|
||||
java -jar $(AC) -cc65 $@ sntp bin < sntp.bin
|
||||
java -jar $(AC) -cc65 $@ tftp bin < tftp.bin
|
||||
java -jar $(AC) -cc65 $@ udp bin < udp.bin
|
||||
java -jar $(AC) -cc65 $@ vt100 bin < vt100.bin
|
||||
|
||||
ip65test.atr: com
|
||||
@ -143,12 +160,16 @@ ip65test.atr: com
|
||||
cp ping.com atr/ping.com
|
||||
cp sntp.com atr/sntp.com
|
||||
cp tftp.com atr/tftp.com
|
||||
cp udp.com atr/udp.com
|
||||
cp vt100.com atr/vt100.com
|
||||
$(DIR2ATR) -b Dos25 1040 $@ atr
|
||||
rm -r atr
|
||||
|
||||
%.exe: %.c
|
||||
cl /Fe:$@ $^
|
||||
|
||||
clean:
|
||||
make -C ../ip65 clean
|
||||
make -C ../drivers clean
|
||||
-rm -f *.o *.prg *.bin *.com *.vicprg *.map
|
||||
-rm -f *.o *.prg *.bin *.com *.vicprg *.map *.obj *.exe
|
||||
-rm -f ip65test.d64 ip65test.dsk ip65test.atr
|
||||
|
212
test/peer.c
Normal file
212
test/peer.c
Normal file
@ -0,0 +1,212 @@
|
||||
#include <stdio.h>
|
||||
#include <conio.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
|
||||
#define LEN 200
|
||||
|
||||
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("(U)DP, (T)CP or e(X)it\n");
|
||||
char key;
|
||||
do
|
||||
{
|
||||
int len;
|
||||
unsigned char buf[1500];
|
||||
|
||||
if (kbhit())
|
||||
{
|
||||
key = getch();
|
||||
}
|
||||
else
|
||||
{
|
||||
key = '\0';
|
||||
}
|
||||
|
||||
if (key == 'u')
|
||||
{
|
||||
if (remote.sin_addr.s_addr == INADDR_NONE)
|
||||
{
|
||||
printf("Peer Unknown As Yet\n", len);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
len = LEN;
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
buf[i] = i;
|
||||
}
|
||||
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;
|
||||
}
|
||||
printf(".\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (key == 't')
|
||||
{
|
||||
if (tcp == INVALID_SOCKET)
|
||||
{
|
||||
printf("No Connection\n", len);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
len = LEN;
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
buf[i] = i;
|
||||
}
|
||||
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");
|
||||
}
|
114
test/udp.c
Normal file
114
test/udp.c
Normal file
@ -0,0 +1,114 @@
|
||||
#include <cc65.h>
|
||||
#include <conio.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../inc/ip65.h"
|
||||
|
||||
#define LEN 500
|
||||
#define SRV "192.168.0.10"
|
||||
|
||||
char buf[LEN];
|
||||
|
||||
void error_exit(void)
|
||||
{
|
||||
printf("Error $%X\n", ip65_error);
|
||||
if (doesclrscrafterexit())
|
||||
{
|
||||
printf("Press any key\n");
|
||||
cgetc();
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void udp_recv(void)
|
||||
{
|
||||
unsigned len = udp_recv_len();
|
||||
unsigned i;
|
||||
|
||||
printf("Recv Len %u From %s", len, dotted_quad(udp_recv_src()));
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
if ((i % 11) == 0)
|
||||
{
|
||||
printf("\n$%04X:", i);
|
||||
}
|
||||
printf(" %02X", udp_recv_buf[i]);
|
||||
}
|
||||
printf(".\n");
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned long srv;
|
||||
char key;
|
||||
|
||||
for (i = 0; i < LEN; ++i)
|
||||
buf[i] = i;
|
||||
|
||||
if(!(srv = parse_dotted_quad(SRV)))
|
||||
{
|
||||
error_exit();
|
||||
}
|
||||
|
||||
printf("Init\n");
|
||||
if (ip65_init())
|
||||
{
|
||||
error_exit();
|
||||
}
|
||||
|
||||
printf("DHCP\n");
|
||||
if (dhcp_init())
|
||||
{
|
||||
error_exit();
|
||||
}
|
||||
|
||||
printf("IP Addr: %s\n", dotted_quad(cfg_ip));
|
||||
printf("Netmask: %s\n", dotted_quad(cfg_netmask));
|
||||
printf("Gateway: %s\n", dotted_quad(cfg_gateway));
|
||||
printf("DNS Srv: %s\n", dotted_quad(cfg_dns));
|
||||
|
||||
printf("Listen\n");
|
||||
if (udp_add_listener(6502, udp_recv))
|
||||
{
|
||||
error_exit();
|
||||
}
|
||||
|
||||
printf("(U)DP or e(X)it\n");
|
||||
do
|
||||
{
|
||||
ip65_process();
|
||||
|
||||
if (kbhit())
|
||||
{
|
||||
key = cgetc();
|
||||
}
|
||||
else
|
||||
{
|
||||
key = '\0';
|
||||
}
|
||||
|
||||
if (key == 'u')
|
||||
{
|
||||
printf("Send Len %d To %s", LEN, SRV);
|
||||
if (udp_send(buf, LEN, srv, 6502, 6502))
|
||||
{
|
||||
printf("!\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(".\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
while (key != 'x');
|
||||
|
||||
printf("Unlisten\n");
|
||||
if (udp_remove_listener(6502))
|
||||
{
|
||||
error_exit();
|
||||
}
|
||||
|
||||
printf("Done\n");
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user