git-svn-id: http://svn.code.sf.net/p/netboot65/code@167 93682198-c243-4bdb-bd91-e943c89aac3b

This commit is contained in:
jonnosan 2009-07-30 10:43:37 +00:00
parent 9f811d4f3e
commit 675f2cc4b9
23 changed files with 803 additions and 383 deletions

View File

@ -13,6 +13,8 @@ SEGMENTS {
IP65_DEFAULTS: load = RAM, run=RAM, type = ro , define = yes;
DATA: load = RAM, run=RAM, type = rw , define = yes;
BSS: load=RAM, type = bss, define = yes;
TCP_VARS: load = RAM, type = bss;
APP_SCRATCH: load = RAM, type = bss;
ZEROPAGE: load = ZP, type = zp;
IP65ZP: load = IP65ZP, type = zp;
}

View File

@ -1,7 +1,7 @@
# CA65 config for a 16KB cart
MEMORY {
IP65ZP: start = $A3, size = $11, type = rw, define = yes;
IP65ZP: start = $A3, size = $13, type = rw, define = yes;
HEADER: start = $8000, size = $18, file = %O;
DEFAULTS: start = $8018, size = $1E, file = %O;
ROM: start = $8036, size = $3FC8, define = yes, file = %O;

View File

@ -18,13 +18,13 @@ DRIVERS=\
all: $(DRIVERS)
apple2prog.lib: a2print.o uthernet.o a2timer.o a2kernal.o a2input.o
apple2prog.lib: a2print.o uthernet.o a2timer.o a2kernal.o a2input.o a2charconv.o
ar65 a $@ $^
c64prog.lib: c64print.o rr-net.o c64timer.o c64kernal.o c64inputs.o c64_disk_access.o
c64prog.lib: c64print.o rr-net.o c64timer.o c64kernal.o c64inputs.o c64_disk_access.o c64charconv.o
ar65 a $@ $^
c64nb65.lib: c64print.o rr-net.o c64timer_nb65.o c64kernal.o c64inputs.o c64_disk_access.o
c64nb65.lib: c64print.o rr-net.o c64timer_nb65.o c64kernal.o c64inputs.o c64_disk_access.o c64charconv.o
ar65 a $@ $^
clean:

View File

@ -0,0 +1,19 @@
;ASCII/PETSCII conversion tables
;cribbed from http://www.ffd2.com/fridge/misc/petcom.c
.export ascii_to_native
.export native_to_ascii
;given an A2 Screen Code char in A, return equivalent ASCII
native_to_ascii:
;just strip high bit
and #$7f
rts
;given an ASCII char in A, return equivalent A2 Screen Code
ascii_to_native:
;set high bit
ora #$80
rts

View File

@ -1,12 +1,40 @@
.export get_key
.export check_for_abort_key
.export get_filtered_input
.export filter_text
.export filter_ip
.export filter_dns
.export filter_number
.export get_key_ip65
.export get_key_if_available
.import ip65_process
.import print_a
.import print_hex
.importzp copy_src
.include "../inc/common.i"
allowed_ptr=copy_src ;reuse zero page
.code
;use Apple 2 monitor ROM function to read from keyboard
;inputs: none
;outputs: A contains ASCII code of key pressed
get_key:
lda #$a0
jmp $fd1b
;inputs: none
;outputs: A contains ASCII value of key just pressed (0 if no key pressed)
get_key_if_available:
bit $c000 ;Key down?
bmi get_key
lda #0
rts
;check whether the escape key is being pressed
;inputs: none
@ -20,3 +48,139 @@ rts
:
clc
rts
;process inbound ip packets while waiting for a keypress
get_key_ip65:
jsr ip65_process
bit $c000 ;Key down?
bpl get_key_ip65
jmp get_key
;cribbed from http://codebase64.org/doku.php?id=base:robust_string_input
;======================================================================
;Input a string and store it in GOTINPUT, terminated with a null byte.
;AX is a pointer to the allowed list of characters, null-terminated.
;set AX to $0000 for no filter on input
;max # of chars in y returns num of chars entered in y.
;======================================================================
; Main entry
get_filtered_input:
sty MAXCHARS
stax temp_allowed
;Zero characters received.
lda #$00
sta INPUT_Y
;Wait for a character.
@input_get:
jsr get_key_ip65
;convert to standard ASCII by turning off high bit
and #$7f
sta LASTCHAR
cmp #$08 ;Delete
beq @delete
cmp #$0d ;Return
beq @input_done
;End reached?
lda INPUT_Y
cmp MAXCHARS
beq @input_get
;Check the allowed list of characters.
ldax temp_allowed
stax allowed_ptr ;since we are reusing this zero page, it may not stil be the same value since last time!
ldy #$00
lda allowed_ptr+1 ;was the input filter point nul?
beq @input_ok
@check_allowed:
lda (allowed_ptr),y ;Overwritten
beq @input_get ;Reached end of list (0)
cmp LASTCHAR
beq @input_ok ;Match found
;Not end or match, keep checking
iny
jmp @check_allowed
@input_ok:
lda LASTCHAR ;Get the char back
ldy INPUT_Y
sta GOTINPUT,y ;Add it to string
inc INPUT_Y ;Next character
jsr print_a
;Not yet.
jmp @input_get
@input_done:
ldy INPUT_Y
beq @no_input
lda #$00
sta GOTINPUT,y ;Zero-terminate
clc
ldax #GOTINPUT
rts
@no_input:
sec
rts
; Delete last character.
@delete:
;First, check if we're at the beginning. If so, just exit.
lda INPUT_Y
bne @delete_ok
jmp @input_get
;At least one character entered.
@delete_ok:
;Move pointer back.
dec INPUT_Y
;Store a zero over top of last character, just in case no other characters are entered.
ldy INPUT_Y
lda #$00
sta GOTINPUT,y
;Print the backspace char
lda #$88
jsr print_a
;Print the a space
lda #$a0
jsr print_a
;Print the backspace char
lda #$88
jsr print_a
;Wait for next char
jmp @input_get
;=================================================
;Some example filters
;=================================================
filter_text:
.byte ",+!#$%&'()* "
filter_dns:
.byte "-ABCDEFGHIJKLMNOPQRSTUVWXYZ"
filter_ip:
.byte "."
filter_number:
.byte "1234567890",0
;=================================================
.bss
temp_allowed: .res 2
MAXCHARS: .res 1
LASTCHAR: .res 1
INPUT_Y: .res 1
GOTINPUT: .res 40

View File

@ -11,7 +11,7 @@
;outputs: none
print_a:
ora #$80 ;turn ASCII into Apple 2 screen codes
jmp $fdf0
jmp $fded
;use Apple 2 monitor ROM function to move to new line

View File

@ -0,0 +1,55 @@
;ASCII/PETSCII conversion tables
;cribbed from http://www.ffd2.com/fridge/misc/petcom.c
.export ascii_to_native
.export native_to_ascii
;given a PETSCII char in A, return equivalent ASCII
native_to_ascii:
tax
lda petscii_to_ascii_table,x
rts
;given an ASCII char in A, return equivalent PETSCII
ascii_to_native:
tax
lda ascii_to_petscii_table,x
rts
.rodata
ascii_to_petscii_table:
.byte $00,$01,$02,$03,$04,$05,$06,$07,$14,$09,$0d,$11,$93,$0a,$0e,$0f
.byte $10,$0b,$12,$13,$08,$15,$16,$17,$18,$19,$1a,$1b,$1c,$1d,$1e,$1f
.byte $20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$2a,$2b,$2c,$2d,$2e,$2f
.byte $30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3a,$3b,$3c,$3d,$3e,$3f
.byte $40,$c1,$c2,$c3,$c4,$c5,$c6,$c7,$c8,$c9,$ca,$cb,$cc,$cd,$ce,$cf
.byte $d0,$d1,$d2,$d3,$d4,$d5,$d6,$d7,$d8,$d9,$da,$5b,$5c,$5d,$5e,$5f
.byte $c0,$41,$42,$43,$44,$45,$46,$47,$48,$49,$4a,$4b,$4c,$4d,$4e,$4f
.byte $50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$5a,$db,$dc,$dd,$de,$df
.byte $80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8a,$8b,$8c,$8d,$8e,$8f
.byte $90,$91,$92,$0c,$94,$95,$96,$97,$98,$99,$9a,$9b,$9c,$9d,$9e,$9f
.byte $a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7,$a8,$a9,$aa,$ab,$ac,$ad,$ae,$af
.byte $b0,$b1,$b2,$b3,$b4,$b5,$b6,$b7,$b8,$b9,$ba,$bb,$bc,$bd,$be,$bf
.byte $60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$6a,$6b,$6c,$6d,$6e,$6f
.byte $70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$7a,$7b,$7c,$7d,$7e,$7f
.byte $e0,$e1,$e2,$e3,$e4,$e5,$e6,$e7,$e8,$e9,$ea,$eb,$ec,$ed,$ee,$ef
.byte $f0,$f1,$f2,$f3,$f4,$f5,$f6,$f7,$f8,$f9,$fa,$fb,$fc,$fd,$fe,$ff
petscii_to_ascii_table:
.byte $00,$01,$02,$03,$04,$05,$06,$07,$14,$09,$0d,$11,$93,$0a,$0e,$0f
.byte $10,$0b,$12,$13,$08,$15,$16,$17,$18,$19,$1a,$1b,$1c,$1d,$1e,$1f
.byte $20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$2a,$2b,$2c,$2d,$2e,$2f
.byte $30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3a,$3b,$3c,$3d,$3e,$3f
.byte $40,$61,$62,$63,$64,$65,$66,$67,$68,$69,$6a,$6b,$6c,$6d,$6e,$6f
.byte $70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$7a,$5b,$5c,$5d,$5e,$5f
.byte $c0,$c1,$c2,$c3,$c4,$c5,$c6,$c7,$c8,$c9,$ca,$cb,$cc,$cd,$ce,$cf
.byte $d0,$d1,$d2,$d3,$d4,$d5,$d6,$d7,$d8,$d9,$da,$db,$dc,$dd,$de,$df
.byte $80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8a,$8b,$8c,$8d,$8e,$8f
.byte $90,$91,$92,$0c,$94,$95,$96,$97,$98,$99,$9a,$9b,$9c,$9d,$9e,$9f
.byte $20,$a1,$a2,$a3,$a4,$a5,$a6,$a7,$a8,$a9,$aa,$ab,$ac,$ad,$ae,$af
.byte $b0,$b1,$b2,$b3,$b4,$b5,$b6,$b7,$b8,$b9,$ba,$bb,$bc,$bd,$be,$bf
.byte $60,$41,$42,$43,$44,$45,$46,$47,$48,$49,$4a,$4b,$4c,$4d,$4e,$4f
.byte $50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$5a,$7b,$7c,$7d,$7e,$7f
.byte $a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7,$a8,$a9,$aa,$ab,$ac,$ad,$ae,$af
.byte $b0,$b1,$b2,$b3,$b4,$b5,$b6,$b7,$b8,$b9,$ba,$bb,$bc,$bd,$be,$bf

View File

@ -71,7 +71,7 @@ check_for_abort_key:
; Main entry
get_filtered_input:
sty MAXCHARS
stax allowed_ptr
stax temp_allowed
;Zero characters received.
lda #$00
@ -94,6 +94,9 @@ get_filtered_input:
beq @input_get
;Check the allowed list of characters.
ldax temp_allowed
stax allowed_ptr ;since we are reusing this zero page, it may not stil be the same value since last time!
ldy #$00
lda allowed_ptr+1 ;was the input filter point nul?
beq @input_ok
@ -170,6 +173,7 @@ filter_number:
;=================================================
.bss
temp_allowed: .res 2
MAXCHARS: .res 1
LASTCHAR: .res 1
INPUT_Y: .res 1

View File

@ -5,3 +5,4 @@ KEYCODE_LEFT=$88
KEYCODE_RIGHT=$95
KEYCODE_ABORT=$9B
.define KEYNAME_ABORT "ESC"
.export KEYCODE_ABORT

View File

@ -13,3 +13,4 @@ KEYCODE_F7=$88
KEYCODE_F8=$8c
KEYCODE_ABORT=$03 ;RUN/STOP
.define KEYNAME_ABORT "RUN/STOP"
.export KEYCODE_ABORT

View File

@ -19,7 +19,9 @@
.export gateway_msg
.export dns_server_msg
.export tftp_server_msg
.import ip65_error
.export print_errorcode
.import arp_cache
.importzp ac_size
@ -321,6 +323,13 @@ print_hex:
pla
rts
print_errorcode:
ldax #error_code
jsr print
lda ip65_error
jsr print_hex
jmp print_cr
.rodata
hexdigits:
.byte "0123456789ABCDEF"
@ -366,3 +375,7 @@ ok_msg:
dns_lookup_failed_msg:
.byte "DNS LOOKUP FAILED", 0
error_code:
.asciiz "ERROR CODE: "

View File

@ -18,7 +18,7 @@
.importzp copy_src
.importzp copy_dest
.import copymem
.import ascii_to_native
.import tcp_connect
.import tcp_send
.import tcp_send_data_len
@ -126,14 +126,14 @@ display_resource_in_buffer:
;if this is a text file, just convert ascii->petscii and print to screen
@show_one_char:
jsr get_next_byte
tax ;this both sets up X as index into ascii_to_petscii_table, and sets Z flag
tax ;this sets Z flag
bne :+
lda #1
sta this_is_last_page
jmp @get_keypress
:
lda ascii_to_petscii_table,x
jsr ascii_to_native
jsr print_a
lda $d6
cmp #DISPLAY_LINES
@ -210,8 +210,7 @@ display_resource_in_buffer:
jsr get_next_byte
cmp #$09
beq @skip_to_end_of_line
tax
lda ascii_to_petscii_table,x
jsr ascii_to_native
jsr print_a
jmp @next_byte
@ -525,11 +524,12 @@ load_resource_into_buffer:
stx dl_loop_counter
stx dl_loop_counter+1
lda resource_selector_length
beq @empty_selector
stax tcp_send_data_len
ldax #resource_selector
jsr tcp_send
@empty_selector:
;send the tab and query string (if supplied)
lda displayed_resource_type
cmp #'7' ;is it a 'search' resource?

View File

@ -5,11 +5,16 @@
; .include "../inc/common.i"
; .include "../inc/commonprint.i"
; .include "../inc/net.i"
; .include "../inc/char_conv.i"
; .include "../inc/c64keycodes.i"
; 3) define a routine called 'exit_telnet'
; 4) define a buffer called 'scratch_buffer'
; 5) define a zero page var called buffer_ptr
.import telnet_connect
.import telnet_local_echo
.import telnet_line_mode
.import telnet_use_native_charset
.import telnet_port
.import telnet_ip
.code
telnet_main_entry:
;prompt for a hostname, then resolve to an IP address
@ -75,26 +80,24 @@ telnet_main_entry:
jmp @char_mode_input
@ascii_mode:
lda #0
sta character_set
sta line_mode
sta telnet_use_native_charset
sta telnet_line_mode
lda #1
sta local_echo
lda #telnet_state_normal
sta telnet_state
sta telnet_local_echo
jmp @after_mode_set
@petscii_mode:
lda #1
sta character_set
sta telnet_use_native_charset
lda #0
sta local_echo
sta line_mode
sta telnet_local_echo
sta telnet_line_mode
jmp @after_mode_set
@line_mode:
lda #0
sta character_set
sta telnet_use_native_charset
lda #1
sta local_echo
sta line_mode
sta telnet_local_echo
sta telnet_line_mode
@after_mode_set:
@ -103,12 +106,12 @@ telnet_main_entry:
ldax #connecting_in
jsr print
lda character_set
lda telnet_use_native_charset
beq @a_mode
ldax #petscii
jmp @c_mode
@a_mode:
lda line_mode
lda telnet_line_mode
bne @l_mode
ldax #ascii
jmp @c_mode
@ -118,334 +121,16 @@ telnet_main_entry:
jsr print
ldax #mode
jsr print
telnet_connect:
ldax #telnet_callback
stax nb65_param_buffer+NB65_TCP_CALLBACK
ldx #3
@copy_dest_ip:
lda telnet_ip,x
sta nb65_param_buffer+NB65_TCP_REMOTE_IP,x
dex
bpl @copy_dest_ip
ldax telnet_port
stax nb65_param_buffer+NB65_TCP_PORT
ldax #nb65_param_buffer
nb65call #NB65_TCP_CONNECT
bcc @connect_ok
jsr print_cr
print_failed
jsr print_errorcode
jmp telnet_main_entry
@connect_ok:
print_ok
jsr print_cr
lda #0
sta connection_closed
@main_polling_loop:
jsr NB65_PERIODIC_PROCESSING_VECTOR
lda connection_closed
beq @not_disconnected
ldax #disconnected
jsr print
jmp telnet_main_entry
@not_disconnected:
lda line_mode
beq @not_line_mode
nb65call #NB65_INPUT_STRING
stax buffer_ptr
ldy #0
@copy_one_char:
lda (buffer_ptr),y
tax
lda petscii_to_ascii_table,x
beq @end_of_input_string
sta scratch_buffer,y
iny
bne @copy_one_char
@end_of_input_string:
lda #$0d
sta scratch_buffer,y
iny
lda #$0a
sta scratch_buffer,y
iny
sty nb65_param_buffer+NB65_TCP_PAYLOAD_LENGTH
lda #0
sta nb65_param_buffer+NB65_TCP_PAYLOAD_LENGTH+1
jsr print_cr
jmp @no_more_input
@not_line_mode:
;is there anything in the input buffer?
lda $c6 ;NDX - chars in keyboard buffer
beq @main_polling_loop
lda #0
sta nb65_param_buffer+NB65_TCP_PAYLOAD_LENGTH
sta nb65_param_buffer+NB65_TCP_PAYLOAD_LENGTH+1
@get_next_char:
jsr $ffe4 ;getkey - 0 means no input
; pha
; jsr print_hex
; pla
tax
beq @no_more_input
cmp #$03 ;RUN/STOP
bne @not_runstop
lda #0
sta $cb ;overwrite "current key pressed" else it's seen by the tcp stack and the close aborts
ldax #closing_connection
jsr print
nb65call #NB65_TCP_CLOSE_CONNECTION
bcs @error_on_disconnect
ldax #disconnected
jsr print
jmp telnet_main_entry
@error_on_disconnect:
jsr print_errorcode
jsr print_cr
jmp telnet_main_entry
@not_runstop:
lda character_set
bne @no_conversion_required
txa
cmp #$0d
bne @not_cr
;if we get a CR in ascii mode, send CR/LF
ldy nb65_param_buffer+NB65_TCP_PAYLOAD_LENGTH
sta scratch_buffer,y
inc nb65_param_buffer+NB65_TCP_PAYLOAD_LENGTH
ldx #$0a
jmp @no_conversion_required
@not_cr:
lda petscii_to_ascii_table,x
tax
@no_conversion_required:
txa
ldy nb65_param_buffer+NB65_TCP_PAYLOAD_LENGTH
sta scratch_buffer,y
inc nb65_param_buffer+NB65_TCP_PAYLOAD_LENGTH
jmp @get_next_char
@no_more_input:
ldax #scratch_buffer
stax nb65_param_buffer+NB65_TCP_PAYLOAD_POINTER
ldax #nb65_param_buffer
nb65call #NB65_SEND_TCP_PACKET
bcs @error_on_send
jmp @main_polling_loop
@error_on_send:
ldax #transmission_error
jsr print
jsr print_errorcode
jmp telnet_main_entry
;tcp callback - will be executed whenever data arrives on the TCP connection
telnet_callback:
ldax #nb65_param_buffer
nb65call #NB65_GET_INPUT_PACKET_INFO
lda nb65_param_buffer+NB65_PAYLOAD_LENGTH+1
cmp #$ff
bne @not_eof
lda #1
sta connection_closed
rts
@not_eof:
ldax nb65_param_buffer+NB65_PAYLOAD_POINTER
stax buffer_ptr
lda nb65_param_buffer+NB65_PAYLOAD_LENGTH
sta buffer_length
lda nb65_param_buffer+NB65_PAYLOAD_LENGTH+1
sta buffer_length+1
;since we don't check the buffer length till the end of the loop, set 'buffer length' to be 1 less than the actual number of bytes
dec buffer_length
bpl :+
dec buffer_length+1
:
ldy #0
sty iac_response_buffer_length
@next_byte:
lda (buffer_ptr),y
tax
lda character_set
beq :+
jmp @no_conversion_req
:
lda line_mode
beq :+
jmp@convert_to_petscii
:
;if we get here, we are in ASCII 'char at a time' mode, so look for (and process) Telnet style IAC bytes
lda telnet_state
cmp #telnet_state_got_command
beq @waiting_for_option
cmp #telnet_state_got_iac
beq @waiting_for_command
; we must be in 'normal' mode
txa
cmp #255
beq :+
jmp @not_iac
:
lda #telnet_state_got_iac
sta telnet_state
jmp @byte_processed
@waiting_for_command:
txa
sta telnet_command
cmp #$fb ;WILL
beq @option
cmp #$fc ;WONT
beq @option
cmp #$fd ; DO
beq @option
cmp #$fe ;DONT
beq @option
;we got a command we don't understand - just ignore it
lda #telnet_state_normal
sta telnet_state
jmp @byte_processed
@option:
lda #telnet_state_got_command
sta telnet_state
jmp @byte_processed
@waiting_for_option:
;we have now got IAC, <command>, <option>
txa
sta telnet_option
lda telnet_command
cmp #$fb
beq @iac_will
cmp #$fc
beq @iac_wont
;if we get here, then it's a "do" or "don't", both of which we should send a "wont" back for
;(since there are no "do" options we actually honour)
lda #$fc ;wont
@add_iac_response:
ldx iac_response_buffer_length
sta iac_response_buffer+1,x
lda #255
sta iac_response_buffer,x
lda telnet_option
sta iac_response_buffer+2,x
inc iac_response_buffer_length
inc iac_response_buffer_length
inc iac_response_buffer_length
lda #telnet_state_normal
sta telnet_state
jmp @byte_processed
@iac_will:
lda telnet_option
cmp #$01 ;ECHO
beq @will_echo
cmp #$03 ;DO SUPPRESS GA
beq @will_suppress_ga
@iac_wont:
lda #$fe ;dont
jmp @add_iac_response
@will_echo:
lda #0
sta local_echo
lda #$fd ;DO
jmp @add_iac_response
@will_suppress_ga:
lda #0
sta line_mode
lda #$fd ;DO
jmp @add_iac_response
@not_iac:
@convert_to_petscii:
lda ascii_to_petscii_table,x
tax
@no_conversion_req:
tya
pha
txa
jsr print_a
pla
tay
@byte_processed:
iny
bne :+
inc buffer_ptr+1
:
dec buffer_length
lda #$ff
cmp buffer_length
beq :+
jmp @next_byte
:
dec buffer_length+1
bmi @finished
jmp @next_byte
@finished:
lda iac_response_buffer_length
beq @no_iac_response
ldx #0
stax nb65_param_buffer+NB65_TCP_PAYLOAD_LENGTH
ldax #iac_response_buffer
stax nb65_param_buffer+NB65_TCP_PAYLOAD_POINTER
ldax #nb65_param_buffer
nb65call #NB65_SEND_TCP_PACKET
@no_iac_response:
rts
jsr telnet_connect
jmp telnet_main_entry
;constants
closing_connection: .byte "CLOSING CONNECTION",13,0
connecting_in: .byte "CONNECTING IN ",0
ascii: .byte "ASCII",0
petscii: .byte "PETSCII",0
line: .byte "LINE",0
mode: .byte " MODE",13,0
disconnected: .byte 13,"CONNECTION CLOSED",13,0
remote_host: .byte "HOSTNAME (LEAVE BLANK TO QUIT)",13,": ",0
remote_port: .byte "PORT # (LEAVE BLANK FOR DEFAULT)",13,": ",0
char_mode_prompt: .byte "MODE - A=ASCII, P=PETSCII, L=LINE",13,0
transmission_error: .byte "ERROR WHILE SENDING ",0
;variables
.segment "APP_SCRATCH"
telnet_ip: .res 4
telnet_port: .res 2
connection_closed: .res 1
character_set: .res 1
buffer_offset: .res 1
local_echo: .res 1
line_mode: .res 1
telnet_state: .res 1
telnet_command: .res 1
telnet_option: .res 1
telnet_state_normal = 0
telnet_state_got_iac = 1
telnet_state_got_command = 2
;nb65_param_buffer DS.B $20
buffer_length: .res 2
iac_response_buffer: .res 256
iac_response_buffer_length: .res 1

View File

@ -26,8 +26,8 @@ ETHOBJS= \
dottedquad.o \
output_buffer.o\
tftp.o \
arithmetic.o\
telnet.o \
arithmetic.o\
all: ip65.lib ip65_tcp.lib

View File

@ -452,17 +452,13 @@ send_dhcprequest:
: lda dhcp_server,x
sta output_buffer+dhcp_options+11,x
lda #$ff ;bugfix by ShadowM - DHCP request should be broadcast
sta udp_send_dest,x
dex
bpl :-
;bugfix by ShadowM - DHCP request should be broadcast
lda #$ff
ldx #3
: sta udp_send_dest,x
dex
bpl :-
lda #$FF ;option FF = end of options
;A still = option FF = end of options
sta output_buffer+dhcp_options+17
ldax #dhcp_options+18

356
client/ip65/telnet.s Normal file
View File

@ -0,0 +1,356 @@
;telnet implementation
;
.include "../inc/common.i"
.import tcp_connect
.import tcp_callback
.import tcp_connect_ip
.import tcp_listen
.importzp KEYCODE_ABORT
.import tcp_inbound_data_ptr
.import tcp_inbound_data_length
.import tcp_send
.import tcp_send_data_len
.import tcp_close
.import print_a
.import print_cr
.import ip65_process
.import get_key_ip65
.import get_filtered_input
.import ok_msg
.import failed_msg
.import print
.import print_errorcode
.import native_to_ascii
.import ascii_to_native
.export telnet_connect
.export telnet_local_echo
.export telnet_line_mode
.export telnet_use_native_charset
.export telnet_port
.export telnet_ip
.segment "IP65ZP" : zeropage
; pointer for moving through buffers
buffer_ptr: .res 2 ; source pointer
.code
telnet_connect:
ldax #telnet_callback
stax tcp_callback
ldx #3
@copy_dest_ip:
lda telnet_ip,x
sta tcp_connect_ip,x
dex
bpl @copy_dest_ip
ldax telnet_port
jsr tcp_connect
bcc @connect_ok
jsr print_cr
ldax #failed_msg
jsr print
jsr print_errorcode
rts
@connect_ok:
ldax #ok_msg
jsr print
jsr print_cr
lda #0
sta connection_closed
@main_polling_loop:
jsr ip65_process
lda connection_closed
beq @not_disconnected
ldax #disconnected
jsr print
rts
@not_disconnected:
lda telnet_line_mode
beq @not_line_mode
ldy #40 ;max chars
ldax #$0000
jsr get_filtered_input
stax buffer_ptr
ldy #0
@copy_one_char:
lda (buffer_ptr),y
jsr native_to_ascii
beq @end_of_input_string
sta scratch_buffer,y
iny
bne @copy_one_char
@end_of_input_string:
lda #$0d
sta scratch_buffer,y
iny
lda #$0a
sta scratch_buffer,y
iny
sty tcp_send_data_len
lda #0
sta tcp_send_data_len+1
jsr print_cr
jmp @send_char
@not_line_mode:
jsr get_key_ip65
tax
; beq @send_char
cmp #KEYCODE_ABORT
bne @not_abort
ldax #closing_connection
jsr print
jsr tcp_close
bcs @error_on_disconnect
ldax #disconnected
jsr print
rts
@error_on_disconnect:
jsr print_errorcode
jsr print_cr
rts
@not_abort:
lda #0
sta tcp_send_data_len
sta tcp_send_data_len+1
lda telnet_use_native_charset
bne @no_conversion_required
txa
cmp #$0d
bne @not_cr
;if we get a CR in ascii mode, send CR/LF
ldy tcp_send_data_len
sta scratch_buffer,y
inc tcp_send_data_len
ldx #$0a
jmp @no_conversion_required
@not_cr:
txa
jsr native_to_ascii
tax
@no_conversion_required:
txa
ldy tcp_send_data_len
sta scratch_buffer,y
inc tcp_send_data_len
@send_char:
ldax #scratch_buffer
jsr tcp_send
bcs @error_on_send
jmp @main_polling_loop
@error_on_send:
ldax #transmission_error
jsr print
jsr print_errorcode
rts
;tcp callback - will be executed whenever data arrives on the TCP connection
telnet_callback:
lda tcp_inbound_data_length+1
cmp #$ff
bne @not_eof
lda #1
sta connection_closed
rts
@not_eof:
ldax tcp_inbound_data_ptr
stax buffer_ptr
lda tcp_inbound_data_length
sta buffer_length
lda tcp_inbound_data_length+1
sta buffer_length+1
;since we don't check the buffer length till the end of the loop, set 'buffer length' to be 1 less than the actual number of bytes
dec buffer_length
bpl :+
dec buffer_length+1
:
ldy #0
sty iac_response_buffer_length
@next_byte:
lda (buffer_ptr),y
tax
lda telnet_use_native_charset
beq :+
jmp @no_conversion_req
:
lda telnet_line_mode
beq :+
jmp@convert_to_native
:
;if we get here, we are in ASCII 'char at a time' mode, so look for (and process) Telnet style IAC bytes
lda telnet_state
cmp #telnet_state_got_command
beq @waiting_for_option
cmp #telnet_state_got_iac
beq @waiting_for_command
; we must be in 'normal' mode
txa
cmp #255
beq :+
jmp @not_iac
:
lda #telnet_state_got_iac
sta telnet_state
jmp @byte_processed
@waiting_for_command:
txa
sta telnet_command
cmp #$fb ;WILL
beq @option
cmp #$fc ;WONT
beq @option
cmp #$fd ; DO
beq @option
cmp #$fe ;DONT
beq @option
;we got a command we don't understand - just ignore it
lda #telnet_state_normal
sta telnet_state
jmp @byte_processed
@option:
lda #telnet_state_got_command
sta telnet_state
jmp @byte_processed
@waiting_for_option:
;we have now got IAC, <command>, <option>
txa
sta telnet_option
lda telnet_command
cmp #$fb
beq @iac_will
cmp #$fc
beq @iac_wont
;if we get here, then it's a "do" or "don't", both of which we should send a "wont" back for
;(since there are no "do" options we actually honour)
lda #$fc ;wont
@add_iac_response:
ldx iac_response_buffer_length
sta iac_response_buffer+1,x
lda #255
sta iac_response_buffer,x
lda telnet_option
sta iac_response_buffer+2,x
inc iac_response_buffer_length
inc iac_response_buffer_length
inc iac_response_buffer_length
lda #telnet_state_normal
sta telnet_state
jmp @byte_processed
@iac_will:
lda telnet_option
cmp #$01 ;ECHO
beq @will_echo
cmp #$03 ;DO SUPPRESS GA
beq @will_suppress_ga
@iac_wont:
lda #$fe ;dont
jmp @add_iac_response
@will_echo:
lda #0
sta telnet_local_echo
lda #$fd ;DO
jmp @add_iac_response
@will_suppress_ga:
lda #0
sta telnet_line_mode
lda #$fd ;DO
jmp @add_iac_response
@not_iac:
@convert_to_native:
txa
cmp #$0a ;suppress LF (since it probably follows a CR which will have done the LF as well)
beq @byte_processed
jsr ascii_to_native
tax
@no_conversion_req:
tya
pha
txa
; pha
; jsr print_hex
; pla
jsr print_a
pla
tay
@byte_processed:
iny
bne :+
inc buffer_ptr+1
:
dec buffer_length
lda #$ff
cmp buffer_length
beq :+
jmp @next_byte
:
dec buffer_length+1
bmi @finished
jmp @next_byte
@finished:
lda iac_response_buffer_length
beq @no_iac_response
ldx #0
stax tcp_send_data_len
ldax #iac_response_buffer
jsr tcp_send
@no_iac_response:
rts
;constants
closing_connection: .byte "CLOSING CONNECTION",13,0
disconnected: .byte 13,"CONNECTION CLOSED",13,0
transmission_error: .byte "ERROR WHILE SENDING ",0
;variables
.segment "APP_SCRATCH"
telnet_ip: .res 4
telnet_port: .res 2
connection_closed: .res 1
telnet_use_native_charset: .res 1
buffer_offset: .res 1
telnet_local_echo: .res 1
telnet_line_mode: .res 1
telnet_state: .res 1
telnet_command: .res 1
telnet_option: .res 1
telnet_state_normal = 0
telnet_state_got_iac = 1
telnet_state_got_command = 2
buffer_length: .res 2
iac_response_buffer: .res 64
iac_response_buffer_length: .res 1
scratch_buffer : .res 40

View File

@ -45,7 +45,6 @@
.include "../inc/menu.i"
.if (BANKSWITCH_SUPPORT=$03)
.include "../inc/char_conv.i"
.include "../inc/gopher.i"
.include "../inc/telnet.i"
.endif
@ -74,6 +73,7 @@
.import print_dotted_quad
.import print_hex
.import print_errorcode
.import print_ip_config
.import ok_msg
.import failed_msg
@ -576,12 +576,6 @@ net_apps_menu:
.endif
print_errorcode:
ldax #error_code
jsr print
nb65call #NB65_GET_LAST_ERROR
jsr print_hex
jmp print_cr
bad_boot:
jsr wait_for_keypress
@ -691,9 +685,6 @@ tftp_download_fail_msg:
tftp_download_ok_msg:
.byte "DOWNLOAD OK", 13, 0
error_code:
.asciiz "ERROR CODE: "
current:
.byte "CURRENT ",0
@ -707,7 +698,7 @@ tftp_file:
.asciiz "BOOTC64.PRG"
no_files_on_server:
.byte "TFTP SERVER HAS NO MATCHING FILES",13,0
.byte "NO MATCHING FILES",13,0
press_a_key_to_continue:
.byte "PRESS A KEY TO CONTINUE",13,0

View File

@ -30,7 +30,10 @@ all: \
testdottedquad.pg2\
testdottedquad.prg\
test_tcp.prg \
a2_gopher.pg2 \
a2_telnet.pg2 \
a2_netapps.dsk \
%.o: %.c
$(CC) -c $(CFLAGS) $<
@ -46,12 +49,22 @@ test_tcp.prg: test_tcp.o $(IP65TCPLIB) $(C64PROGLIB) $(INCFILES) ../cfg/c64prg.c
#gopher_browser.prg: gopher_browser.o $(IP65TCPLIB) $(C64PROGLIB) $(INCFILES) ../cfg/c64prg.cfg ../inc/gopher.i
# $(LD) -m gopher_browser.map -vm -C ../cfg/c64prg.cfg -o gopher_browser.prg $(AFLAGS) $< $(IP65TCPLIB) $(C64PROGLIB)
a2_gopher.pg2: a2_gopher.o $(IP65TCPLIB) $(APPLE2PROGLIB) $(INCFILES) ../cfg/a2bin.cfg ../inc/gopher.i
$(LD) -C ../cfg/a2bin.cfg -o a2_gopher.pg2 $(AFLAGS) $< $(IP65TCPLIB) $(APPLE2PROGLIB)
a2_telnet.pg2: a2_telnet.o $(IP65TCPLIB) $(APPLE2PROGLIB) $(INCFILES) ../cfg/a2bin.cfg
$(LD) -C ../cfg/a2bin.cfg -m a2_telnet.map -vm -o a2_telnet.pg2 $(AFLAGS) $< $(IP65TCPLIB) $(APPLE2PROGLIB)
%.pg2: %.o $(IP65LIB) $(APPLE2PROGLIB) $(INCFILES) ../cfg/a2bin.cfg
$(LD) -C ../cfg/a2bin.cfg -o $*.pg2 $(AFLAGS) $< $(IP65LIB) $(APPLE2PROGLIB)
ip65test.dsk: testdns.pg2 testdottedquad.pg2 testtftp.pg2
a2_netapps.dsk: a2_gopher.pg2 a2_telnet.pg2
ripxplore.rb --init BeautifulBoot a2_netapps.dsk -a a2_gopher.pg2 -t AppleBinary
ripxplore.rb a2_netapps.dsk -a a2_telnet.pg2 -t AppleBinary
ip65test.dsk: testdns.pg2 testdottedquad.pg2 testtftp.pg2
ripxplore.rb --init BeautifulBoot ip65test.dsk -a testdns.pg2 -t AppleBinary
ripxplore.rb ip65test.dsk -a testdns.pg2 -t AppleBinary
ripxplore.rb ip65test.dsk -a testtftp.pg2 -t AppleBinary
ripxplore.rb ip65test.dsk -a testdottedquad.pg2 -t AppleBinary
ripxplore.rb ip65test.dsk -a testdns.pg2 -t AppleBinary
@ -62,6 +75,7 @@ test_disk_io.d64: test_disk_io.prg
clean:
rm -f *.o *.pg2 *.prg
rm -f ip65test.dsk
rm -f a2_netapps.dsk
distclean: clean
rm -f *~

47
client/test/a2_gopher.s Normal file
View File

@ -0,0 +1,47 @@
;C64 gopher browser
;july 2009 - jonno @ jamtronix.com
.include "../inc/common.i"
.include "../inc/commonprint.i"
.include "../inc/net.i"
.include "../inc/c64keycodes.i"
.include "../inc/gopher.i"
.import __CODE_LOAD__
.import __CODE_SIZE__
.import __RODATA_SIZE__
.import __DATA_SIZE__
.import get_key
.segment "EXEHDR" ;this is what gets put an the start of the file on the Apple 2
.addr __CODE_LOAD__-3 ; Start address
.word __CODE_SIZE__+__RODATA_SIZE__+__DATA_SIZE__+4 ; Size
jmp init
.code
init:
jsr cls
ldax #title
jsr print
jsr print_cr
init_ip_via_dhcp
jsr print_ip_config
@loop_forever:
jsr prompt_for_gopher_resource ;only returns if no server was entered.
jsr print_cr
jmp @loop_forever
exit_gopher:
rts
.rodata
title:
.byte " GOPHER ][",13," jonno@jamtronix.com",13,0
resolving:
.byte "RESOLVING ",0

78
client/test/a2_telnet.s Normal file
View File

@ -0,0 +1,78 @@
;A2 telnet
;july 2009 (at Mt Keira Fest!) - jonno @ jamtronix.com
.include "../inc/common.i"
.include "../inc/commonprint.i"
.include "../inc/net.i"
.include "../inc/a2keycodes.i"
.import __CODE_LOAD__
.import __CODE_SIZE__
.import __RODATA_SIZE__
.import __DATA_SIZE__
.import get_key
.import cls
.import telnet_connect
.import telnet_local_echo
.import telnet_line_mode
.import telnet_use_native_charset
.import telnet_port
.import telnet_ip
.import cfg_init
.segment "EXEHDR" ;this is what gets put an the start of the file on the Apple 2
.addr __CODE_LOAD__-3 ; Start address
.word __CODE_SIZE__+__RODATA_SIZE__+__DATA_SIZE__+4 ; Size
jmp init
.code
init:
jsr cls
jsr $c300
ldax #title
jsr print
jsr print_cr
jsr cfg_init
; jsr print_ip_config
; jsr get_key
init_ip_via_dhcp
jsr print_ip_config
@loop_forever:
ldx #3
@copy_telnet_ip_loop:
lda remote_host,x
sta telnet_ip,x
dex
bpl @copy_telnet_ip_loop
ldax #23
stax telnet_port
lda #0
sta telnet_use_native_charset
sta telnet_line_mode
lda #1
sta telnet_local_echo
jsr telnet_connect
jmp @loop_forever
exit_telnet:
rts
.rodata
title: .byte " TELNET ][",13," jonno@jamtronix.com",13,0
resolving:
.byte "RESOLVING ",0
remote_host:
.byte 10,5,2,1
padding: .byte 0,0,0,0,0

View File

@ -247,8 +247,6 @@ fname_end:
.rodata
error_code:
.byte "ERROR CODE: $",0
press_a_key_to_continue:
.byte "PRESS A KEY TO CONTINUE",13,0

View File

@ -1,10 +1,9 @@
.include "../inc/common.i"
.include "../inc/commonprint.i"
.include "../inc/net.i"
.include "../inc/char_conv.i"
.import exit_to_basic
.import ascii_to_native
.import parse_dotted_quad
.import dotted_quad_value
@ -332,8 +331,7 @@ tcp_callback_routine:
@print_one_byte:
jsr get_next_byte
tax
lda ascii_to_petscii_table,x
jsr ascii_to_native
jsr print_a
inc get_next_byte+1
@ -616,8 +614,6 @@ number17:
tcp_dest_ip:
; .byte 10,5,1,1
.byte 74,207,242,229
error_code:
.asciiz "ERROR CODE: $"
looping:
.asciiz "LOOPING..."

Binary file not shown.