mirror of
https://github.com/bobbimanners/emailler.git
synced 2025-01-11 10:29:56 +00:00
git-svn-id: http://svn.code.sf.net/p/netboot65/code@111 93682198-c243-4bdb-bd91-e943c89aac3b
This commit is contained in:
parent
d0fb0d16ed
commit
ce3609f2bb
@ -5,7 +5,7 @@ MEMORY {
|
|||||||
IP65ZP: start = $A3, size = $0E, type = rw, define = yes;
|
IP65ZP: start = $A3, size = $0E, type = rw, define = yes;
|
||||||
HEADER: start = $8000, size = $18, file = %O;
|
HEADER: start = $8000, size = $18, file = %O;
|
||||||
ROM: start = $8018, size = $1F00, define = yes, file = %O;
|
ROM: start = $8018, size = $1F00, define = yes, file = %O;
|
||||||
RAM: start = $C080, size = $0f80, define = yes;
|
RAM: start = $C010, size = $0fE0, define = yes;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,14 +24,17 @@ get_key:
|
|||||||
;inputs: none
|
;inputs: none
|
||||||
;outputs: sec if RUN/STOP pressed, clear otherwise
|
;outputs: sec if RUN/STOP pressed, clear otherwise
|
||||||
check_for_abort_key:
|
check_for_abort_key:
|
||||||
lda $cb ;current key pressed
|
lda $cb ;current key pressed
|
||||||
cmp #$3F
|
cmp #$3F
|
||||||
bne :+
|
bne @not_abort
|
||||||
jsr $ffe4 ;get the keypress out of the buffer
|
@flush_loop:
|
||||||
sec
|
jsr $ffe4
|
||||||
:
|
bne @flush_loop
|
||||||
clc
|
sec
|
||||||
rts
|
rts
|
||||||
|
@not_abort:
|
||||||
|
clc
|
||||||
|
rts
|
||||||
|
|
||||||
;cribbed from http://codebase64.org/doku.php?id=base:robust_string_input
|
;cribbed from http://codebase64.org/doku.php?id=base:robust_string_input
|
||||||
;======================================================================
|
;======================================================================
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
.bss
|
.bss
|
||||||
|
|
||||||
;global scratch buffer that DHCP/DNS and others can use while building outbound packets.
|
;global scratch buffer that DHCP/DNS/TFTP and others can use while building outbound packets.
|
||||||
;you need to be careful if using this that you don't call a function that also uses it.
|
;you need to be careful if using this that you don't call a function that also uses it.
|
||||||
;if this is reversed for higher level protocols, the likelyhood of collision is low.
|
;if this is reversed for higher level protocols, the likelyhood of collision is low.
|
||||||
.export output_buffer
|
.export output_buffer
|
||||||
output_buffer: .res 256
|
output_buffer: .res 520
|
@ -1,5 +1,5 @@
|
|||||||
;minimal tftp implementation (client only)
|
;minimal tftp implementation (client only)
|
||||||
;supports file download (not upload) and custom directory listing (using non-standard tftp opcode of 0x65)
|
;supports file download and upload and custom directory listing (using non-standard tftp opcode of 0x65)
|
||||||
|
|
||||||
|
|
||||||
TFTP_MAX_RESENDS=10
|
TFTP_MAX_RESENDS=10
|
||||||
@ -15,12 +15,13 @@
|
|||||||
.export tftp_load_address
|
.export tftp_load_address
|
||||||
.export tftp_ip
|
.export tftp_ip
|
||||||
.export tftp_download
|
.export tftp_download
|
||||||
|
.export tftp_upload
|
||||||
.export tftp_directory_listing
|
.export tftp_directory_listing
|
||||||
.export tftp_data_block_length
|
.export tftp_data_block_length
|
||||||
.export tftp_set_callback_vector
|
.export tftp_set_callback_vector
|
||||||
.export tftp_data_block_length
|
.export tftp_data_block_length
|
||||||
.export tftp_clear_callbacks
|
.export tftp_clear_callbacks
|
||||||
.import output_buffer
|
|
||||||
.import ip65_process
|
.import ip65_process
|
||||||
.import ip65_error
|
.import ip65_error
|
||||||
|
|
||||||
@ -29,7 +30,7 @@
|
|||||||
.import output_buffer
|
.import output_buffer
|
||||||
.import udp_callback
|
.import udp_callback
|
||||||
.import udp_send
|
.import udp_send
|
||||||
|
.import check_for_abort_key
|
||||||
.import udp_inp
|
.import udp_inp
|
||||||
.import ip_inp
|
.import ip_inp
|
||||||
.importzp ip_src
|
.importzp ip_src
|
||||||
@ -58,7 +59,6 @@ tftp_filename: .res 2 ;name of file to d/l or filemask to get directory listing
|
|||||||
;packet offsets
|
;packet offsets
|
||||||
tftp_inp = udp_inp + udp_data
|
tftp_inp = udp_inp + udp_data
|
||||||
tftp_outp = output_buffer
|
tftp_outp = output_buffer
|
||||||
;= output_buffer
|
|
||||||
|
|
||||||
;everything after filename in a request at a relative address, not fixed, so don't bother defining offset constants
|
;everything after filename in a request at a relative address, not fixed, so don't bother defining offset constants
|
||||||
|
|
||||||
@ -69,22 +69,22 @@ tftp_load_address: .res 2 ;address file will be (or was) downloaded to
|
|||||||
tftp_ip: .res 4 ;ip address of tftp server - set to 255.255.255.255 (broadcast) to send request to all tftp servers on local lan
|
tftp_ip: .res 4 ;ip address of tftp server - set to 255.255.255.255 (broadcast) to send request to all tftp servers on local lan
|
||||||
|
|
||||||
tftp_data_block_length: .res 2
|
tftp_data_block_length: .res 2
|
||||||
|
tftp_send_len: .res 2
|
||||||
tftp_current_memloc: .res 2
|
tftp_current_memloc: .res 2
|
||||||
|
|
||||||
; tftp state machine
|
; tftp state machine
|
||||||
tftp_initializing = 1 ; initial state
|
tftp_initializing = 1 ; initial state
|
||||||
tftp_rrq_sent=2 ; sent the read request, waiting for some data
|
tftp_initial_request_sent=2 ; sent the RRQ or WRQ, waiting for some data
|
||||||
tftp_receiving_file=3 ; we have received the first packet of file data
|
tftp_transmission_in_progress=3 ; we have sent/received the first packet of file data
|
||||||
tftp_complete=4 ; we have received the final packet of file data
|
tftp_complete=4 ; we have sent/received the final packet of file data
|
||||||
tftp_error=5 ; we got an error
|
tftp_error=5 ; we got an error
|
||||||
|
|
||||||
tftp_state: .res 1 ; current activity
|
tftp_state: .res 1 ; current activity
|
||||||
tftp_timer: .res 1
|
tftp_timer: .res 1
|
||||||
tftp_resend_counter: .res 1
|
tftp_resend_counter: .res 1
|
||||||
tftp_break_inner_loop: .res 1
|
tftp_break_inner_loop: .res 1
|
||||||
tftp_expected_block_number: .res 1
|
tftp_current_block_number: .res 2
|
||||||
tftp_block_number_to_ack: .res 1
|
tftp_actual_server_port: .res 2 ;this is read from the reply - it is not (usually) the port # we send the RRQ or WRQ to
|
||||||
tftp_actual_server_port: .res 2 ;this is read from the reply - it is not (usually) the port # we send the RRQ to
|
|
||||||
tftp_actual_server_ip: .res 4 ;this is read from the reply - it may not be the IP we sent to (e.g. if we send to broadcast)
|
tftp_actual_server_ip: .res 4 ;this is read from the reply - it may not be the IP we sent to (e.g. if we send to broadcast)
|
||||||
|
|
||||||
tftp_just_set_new_load_address: .res 1
|
tftp_just_set_new_load_address: .res 1
|
||||||
@ -93,15 +93,34 @@ tftp_opcode: .res 2 ; will be set to 4 if we are doing a RRQ, or 7 if we are doi
|
|||||||
|
|
||||||
.code
|
.code
|
||||||
|
|
||||||
|
;uploads a file to a tftp server
|
||||||
|
; inputs:
|
||||||
|
; tftp_ip: ip address of host to download from (set to 255.255.255.255 for broadcast)
|
||||||
|
; tftp_filename: pointer to null terminated name of file to download
|
||||||
|
; of file should be loaded into (e.g. if downloading a C64 'prg' file)
|
||||||
|
; a callback vector should have been set with tftp_set_callback_vector
|
||||||
|
; outputs: carry flag is set if there was an error
|
||||||
|
; if a callback vector has been set with tftp_set_callback_vector
|
||||||
|
; then the specified routine will be called once for each 512 byte packet
|
||||||
|
; sent from the tftp server (each time AX will point at data block just arrived,
|
||||||
|
; and tftp_data_block_length will contain number of bytes in that data block)
|
||||||
|
; otherwise, the buffer at tftp_load_address will be filled
|
||||||
|
; with file downloaded.
|
||||||
|
; tftp_load_address: will be set to the actual address loaded into (NB - this field is
|
||||||
|
; ignored if a callback vector has been set with tftp_set_callback_vector)
|
||||||
|
tftp_upload:
|
||||||
|
ldax #$0200 ;opcode 02 = WRQ
|
||||||
|
jmp set_tftp_opcode
|
||||||
|
|
||||||
; query a tftp server for a directory listing (uses a non-standard tftp opcode,
|
; query a tftp server for a directory listing (uses a non-standard tftp opcode,
|
||||||
; currently only supported by tftp server built in to 'netboot65' server)
|
; currently only supported by tftp server built in to 'netboot65' server)
|
||||||
; inputs:
|
; inputs:
|
||||||
; tftp_ip: ip address of host to download from (set to 255.255.255.255 for broadcast)
|
; tftp_ip: ip address of host to download from (set to 255.255.255.255 for broadcast)
|
||||||
; tftp_filename: pointer to null terminated filemask (e.g. "*.prg",0)
|
; tftp_filename: pointer to null terminated filemask (e.g. "*.prg",0)
|
||||||
; tftp_load_address: memory location that dir will be stored in (NB - this field is
|
; tftp_load_address: memory location that dir will be stored in (NB - this field is
|
||||||
; ignored if a callback vector has been set with tftp_set_download_callback)
|
; ignored if a callback vector has been set with tftp_set_callback_vector)
|
||||||
; outputs: carry flag is set if there was an error, clear otherwise
|
; outputs: carry flag is set if there was an error, clear otherwise
|
||||||
; if a callback vector has been set with tftp_set_download_callback
|
; if a callback vector has been set with tftp_set_callback_vector
|
||||||
; then the specified routine will be called once for each 512 byte packet
|
; then the specified routine will be called once for each 512 byte packet
|
||||||
; sent from the tftp server (each time AX will point at data block just arrived,
|
; sent from the tftp server (each time AX will point at data block just arrived,
|
||||||
; and tftp_data_block_length will contain number of bytes in that data block)
|
; and tftp_data_block_length will contain number of bytes in that data block)
|
||||||
@ -124,27 +143,28 @@ tftp_directory_listing:
|
|||||||
; treat first 2 bytes received from tftp server as memory address that rest
|
; treat first 2 bytes received from tftp server as memory address that rest
|
||||||
; of file should be loaded into (e.g. if downloading a C64 'prg' file)
|
; of file should be loaded into (e.g. if downloading a C64 'prg' file)
|
||||||
; outputs: carry flag is set if there was an error
|
; outputs: carry flag is set if there was an error
|
||||||
; if a callback vector has been set with tftp_set_download_callback
|
; if a callback vector has been set with tftp_set_callback_vector
|
||||||
; then the specified routine will be called once for each 512 byte packet
|
; then the specified routine will be called once for each 512 byte packet
|
||||||
; sent from the tftp server (each time AX will point at data block just arrived,
|
; sent from the tftp server (each time AX will point at data block just arrived,
|
||||||
; and tftp_data_block_length will contain number of bytes in that data block)
|
; and tftp_data_block_length will contain number of bytes in that data block)
|
||||||
; otherwise, the buffer at tftp_load_address will be filled
|
; otherwise, the buffer at tftp_load_address will be filled
|
||||||
; with file downloaded.
|
; with file downloaded.
|
||||||
; tftp_load_address: will be set to the actual address loaded into (NB - this field is
|
; tftp_load_address: will be set to the actual address loaded into (NB - this field is
|
||||||
; ignored if a callback vector has been set with tftp_set_download_callback)
|
; ignored if a callback vector has been set with tftp_set_callback_vector)
|
||||||
tftp_download:
|
tftp_download:
|
||||||
ldax #$0100 ;opcode 01 = RRQ
|
ldax #$0100 ;opcode 01 = RRQ
|
||||||
set_tftp_opcode:
|
set_tftp_opcode:
|
||||||
stax tftp_opcode
|
stax tftp_opcode
|
||||||
lda #tftp_initializing
|
lda #tftp_initializing
|
||||||
sta tftp_state
|
sta tftp_state
|
||||||
sta tftp_expected_block_number ;(tftp_initializing=1)
|
ldx #00
|
||||||
|
stax tftp_current_block_number ;(tftp_initializing=1)
|
||||||
ldax tftp_load_address
|
ldax tftp_load_address
|
||||||
stax tftp_current_memloc
|
stax tftp_current_memloc
|
||||||
ldax #tftp_in
|
ldax #tftp_in
|
||||||
stax udp_callback
|
stax udp_callback
|
||||||
lda #$69
|
lda #$69
|
||||||
inc tftp_client_port_low_byte ;each call to resolve uses a different client address
|
inc tftp_client_port_low_byte ;each transfer uses a different client port
|
||||||
ldx tftp_client_port_low_byte ;so we don't get confused by late replies to a previous call
|
ldx tftp_client_port_low_byte ;so we don't get confused by late replies to a previous call
|
||||||
jsr udp_add_listener
|
jsr udp_add_listener
|
||||||
|
|
||||||
@ -187,20 +207,25 @@ set_tftp_opcode:
|
|||||||
jsr send_ack ;send the ack for the last block
|
jsr send_ack ;send the ack for the last block
|
||||||
lda #$69
|
lda #$69
|
||||||
ldx tftp_client_port_low_byte
|
ldx tftp_client_port_low_byte
|
||||||
jsr udp_remove_listener
|
jsr udp_remove_listener
|
||||||
rts
|
rts
|
||||||
|
|
||||||
@not_complete:
|
@not_complete:
|
||||||
cmp #tftp_receiving_file
|
cmp #tftp_transmission_in_progress
|
||||||
bne @not_receiving
|
bne @not_transmitting
|
||||||
jsr send_ack
|
jsr send_tftp_packet
|
||||||
jmp @inner_delay_loop
|
jmp @inner_delay_loop
|
||||||
@not_receiving:
|
@not_transmitting:
|
||||||
jsr send_request_packet
|
jsr send_request_packet
|
||||||
|
|
||||||
@inner_delay_loop:
|
@inner_delay_loop:
|
||||||
|
jsr ip65_process
|
||||||
jsr ip65_process
|
jsr check_for_abort_key
|
||||||
|
bcc @no_abort
|
||||||
|
lda #NB65_ERROR_ABORTED_BY_USER
|
||||||
|
sta ip65_error
|
||||||
|
jmp @exit_with_error
|
||||||
|
@no_abort:
|
||||||
lda tftp_break_inner_loop
|
lda tftp_break_inner_loop
|
||||||
bne @outer_delay_loop
|
bne @outer_delay_loop
|
||||||
jsr timer_read
|
jsr timer_read
|
||||||
@ -259,7 +284,7 @@ send_request_packet:
|
|||||||
ldax #tftp_outp
|
ldax #tftp_outp
|
||||||
jsr udp_send
|
jsr udp_send
|
||||||
bcs @error_in_send
|
bcs @error_in_send
|
||||||
lda #tftp_rrq_sent
|
lda #tftp_initial_request_sent
|
||||||
sta tftp_state
|
sta tftp_state
|
||||||
rts
|
rts
|
||||||
@error_in_send:
|
@error_in_send:
|
||||||
@ -271,8 +296,13 @@ send_request_packet:
|
|||||||
send_ack:
|
send_ack:
|
||||||
ldax #$0400 ;opcode 04 = ACK
|
ldax #$0400 ;opcode 04 = ACK
|
||||||
stax tftp_outp
|
stax tftp_outp
|
||||||
ldx tftp_block_number_to_ack
|
ldx tftp_current_block_number
|
||||||
|
lda tftp_current_block_number+1
|
||||||
|
dex
|
||||||
stax tftp_outp+2
|
stax tftp_outp+2
|
||||||
|
ldax #04
|
||||||
|
stax tftp_send_len
|
||||||
|
send_tftp_packet: ;TFTP block should be created in tftp_outp, we just add the UDP&IP stuff and send
|
||||||
lda #$69
|
lda #$69
|
||||||
ldx tftp_client_port_low_byte
|
ldx tftp_client_port_low_byte
|
||||||
stax udp_send_src_port
|
stax udp_send_src_port
|
||||||
@ -288,10 +318,11 @@ send_ack:
|
|||||||
ldx tftp_actual_server_port
|
ldx tftp_actual_server_port
|
||||||
lda tftp_actual_server_port+1
|
lda tftp_actual_server_port+1
|
||||||
stax udp_send_dest_port
|
stax udp_send_dest_port
|
||||||
ldax #04
|
ldax tftp_send_len
|
||||||
stax udp_send_len
|
stax udp_send_len
|
||||||
|
|
||||||
ldax #tftp_outp
|
ldax #tftp_outp
|
||||||
|
; .byte $92
|
||||||
jsr udp_send
|
jsr udp_send
|
||||||
rts
|
rts
|
||||||
|
|
||||||
@ -334,15 +365,13 @@ tftp_in:
|
|||||||
@dont_set_load_address:
|
@dont_set_load_address:
|
||||||
lda tftp_inp+3 ;get the (low byte) of the data block
|
lda tftp_inp+3 ;get the (low byte) of the data block
|
||||||
|
|
||||||
; bmi @recv_error ;if we get to block $80, we've d/led more than 64k!
|
cmp tftp_current_block_number
|
||||||
cmp tftp_expected_block_number
|
|
||||||
beq :+
|
beq :+
|
||||||
jmp @not_expected_block_number
|
jmp @not_expected_block_number
|
||||||
:
|
:
|
||||||
;this is the block we wanted
|
;this is the block we wanted
|
||||||
sta tftp_block_number_to_ack
|
inc tftp_current_block_number
|
||||||
inc tftp_expected_block_number
|
lda #tftp_transmission_in_progress
|
||||||
lda #tftp_receiving_file
|
|
||||||
sta tftp_state
|
sta tftp_state
|
||||||
lda #TFTP_MAX_RESENDS
|
lda #TFTP_MAX_RESENDS
|
||||||
sta tftp_resend_counter
|
sta tftp_resend_counter
|
||||||
@ -384,7 +413,8 @@ tftp_in:
|
|||||||
@got_pointer_to_tftp_data:
|
@got_pointer_to_tftp_data:
|
||||||
|
|
||||||
jsr tftp_callback_vector
|
jsr tftp_callback_vector
|
||||||
|
jsr send_ack
|
||||||
|
|
||||||
lda udp_inp+4 ;check the length of the UDP packet
|
lda udp_inp+4 ;check the length of the UDP packet
|
||||||
cmp #02
|
cmp #02
|
||||||
bne @last_block
|
bne @last_block
|
||||||
@ -392,7 +422,47 @@ tftp_in:
|
|||||||
lda udp_inp+5
|
lda udp_inp+5
|
||||||
cmp #$0c
|
cmp #$0c
|
||||||
bne @last_block
|
bne @last_block
|
||||||
|
|
||||||
@not_data_block:
|
@not_data_block:
|
||||||
|
|
||||||
|
cmp #3
|
||||||
|
beq :+
|
||||||
|
jmp @not_ack
|
||||||
|
:
|
||||||
|
;it's an ACK, so we must be sending a file
|
||||||
|
ldx tftp_inp+3 ;get the (low byte) of the data block
|
||||||
|
inx
|
||||||
|
cpx tftp_current_block_number
|
||||||
|
beq :+
|
||||||
|
jmp @not_expected_block_number
|
||||||
|
:
|
||||||
|
;the last block we sent was acked so now we need to send the next one
|
||||||
|
;
|
||||||
|
ldax #output_buffer+4
|
||||||
|
jsr tftp_callback_vector ;this (caller supplied) routine should fill the buffer with up to 512 bytes
|
||||||
|
stax tftp_data_block_length
|
||||||
|
clc
|
||||||
|
adc #4
|
||||||
|
bcc :+
|
||||||
|
inx
|
||||||
|
:
|
||||||
|
stax tftp_send_len
|
||||||
|
ldax #$0300 ;opcode 03 = DATA
|
||||||
|
stax tftp_outp
|
||||||
|
ldx tftp_current_block_number
|
||||||
|
lda tftp_current_block_number+1
|
||||||
|
stax tftp_outp+2
|
||||||
|
jsr send_tftp_packet
|
||||||
|
inc tftp_current_block_number
|
||||||
|
bcc :+
|
||||||
|
inc tftp_current_block_number+1
|
||||||
|
:
|
||||||
|
|
||||||
|
lda tftp_data_block_length+1 ;get length of data we just sent (high byte)
|
||||||
|
cmp #2
|
||||||
|
beq @last_block
|
||||||
|
|
||||||
|
@not_ack:
|
||||||
@not_expected_block_number:
|
@not_expected_block_number:
|
||||||
rts
|
rts
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ nb65_std_cart.bin: nb65_std_cart.o $(IP65LIB) $(C64NB65LIB) $(INCFILES) ../cfg/r
|
|||||||
ruby fix_cart.rb $@ 8192
|
ruby fix_cart.rb $@ 8192
|
||||||
|
|
||||||
nb65_rrnet.bin: nb65_rrnet.o $(IP65LIB) $(C64NB65LIB) $(INCFILES) ../cfg/rrbin.cfg
|
nb65_rrnet.bin: nb65_rrnet.o $(IP65LIB) $(C64NB65LIB) $(INCFILES) ../cfg/rrbin.cfg
|
||||||
$(LD) -m nb65_rrnet.map -vm -C ../cfg/rrbin.cfg -o $@ $< $(IP65LIB) $(C64NB65LIB)
|
$(LD) -m nb65_rrnet.map -Ln nb65_rr.lab -vm -C ../cfg/rrbin.cfg -o $@ $< $(IP65LIB) $(C64NB65LIB)
|
||||||
ruby fix_cart.rb $@ 8193
|
ruby fix_cart.rb $@ 8193
|
||||||
|
|
||||||
utherboot.pg2: utherboot.o $(IP65LIB) $(APPLE2PROGLIB) $(INCFILES) ../cfg/a2language_card.cfg
|
utherboot.pg2: utherboot.o $(IP65LIB) $(APPLE2PROGLIB) $(INCFILES) ../cfg/a2language_card.cfg
|
||||||
|
@ -72,8 +72,9 @@
|
|||||||
.import __DATA_RUN__
|
.import __DATA_RUN__
|
||||||
.import __DATA_SIZE__
|
.import __DATA_SIZE__
|
||||||
.import cfg_tftp_server
|
.import cfg_tftp_server
|
||||||
tftp_dir_buffer = $6000
|
tftp_dir_buffer = $6020
|
||||||
|
nb65_param_buffer = $6000
|
||||||
|
|
||||||
.data
|
.data
|
||||||
exit_cart:
|
exit_cart:
|
||||||
.if (BANKSWITCH_SUPPORT=$02)
|
.if (BANKSWITCH_SUPPORT=$02)
|
||||||
@ -90,7 +91,6 @@ call_downloaded_prg:
|
|||||||
|
|
||||||
.bss
|
.bss
|
||||||
|
|
||||||
nb65_param_buffer: .res $20
|
|
||||||
|
|
||||||
|
|
||||||
.segment "CARTRIDGE_HEADER"
|
.segment "CARTRIDGE_HEADER"
|
||||||
@ -161,6 +161,8 @@ ldax #init_msg
|
|||||||
nb65call #NB65_INITIALIZE
|
nb65call #NB65_INITIALIZE
|
||||||
|
|
||||||
main_menu:
|
main_menu:
|
||||||
|
lda #21 ;make sure we are in upper case
|
||||||
|
sta $d018
|
||||||
jsr cls
|
jsr cls
|
||||||
ldax #netboot65_msg
|
ldax #netboot65_msg
|
||||||
jsr print
|
jsr print
|
||||||
@ -285,13 +287,14 @@ main_menu:
|
|||||||
|
|
||||||
jsr select_option_from_menu
|
jsr select_option_from_menu
|
||||||
bcc @tftp_filename_set
|
bcc @tftp_filename_set
|
||||||
lda #21 ;switch back to upper case
|
|
||||||
sta $d018
|
|
||||||
jmp main_menu
|
jmp main_menu
|
||||||
@tftp_filename_set:
|
@tftp_filename_set:
|
||||||
jsr download
|
jsr download
|
||||||
bcc @file_downloaded_ok
|
bcc @file_downloaded_ok
|
||||||
jmp bad_boot
|
@tftp_boot_failed:
|
||||||
|
jsr wait_for_keypress
|
||||||
|
jmp main_menu
|
||||||
|
|
||||||
|
|
||||||
@dir_failed:
|
@dir_failed:
|
||||||
ldax #tftp_dir_listing_fail_msg
|
ldax #tftp_dir_listing_fail_msg
|
||||||
@ -306,7 +309,7 @@ main_menu:
|
|||||||
ldax #no_files_on_server
|
ldax #no_files_on_server
|
||||||
jsr print
|
jsr print
|
||||||
|
|
||||||
jmp bad_boot
|
jmp @tftp_boot_failed
|
||||||
|
|
||||||
@file_downloaded_ok:
|
@file_downloaded_ok:
|
||||||
|
|
||||||
|
@ -15,6 +15,16 @@ INCFILES=\
|
|||||||
../inc/common.i\
|
../inc/common.i\
|
||||||
../inc/commonprint.i\
|
../inc/commonprint.i\
|
||||||
../inc/net.i\
|
../inc/net.i\
|
||||||
|
|
||||||
|
all: \
|
||||||
|
ip65test.dsk \
|
||||||
|
testdns.prg \
|
||||||
|
testdns.pg2 \
|
||||||
|
testtftp.prg \
|
||||||
|
testtftp.pg2\
|
||||||
|
test_cart_api.prg\
|
||||||
|
testdottedquad.pg2\
|
||||||
|
testdottedquad.prg\
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) -c $(CFLAGS) $<
|
$(CC) -c $(CFLAGS) $<
|
||||||
@ -28,21 +38,14 @@ INCFILES=\
|
|||||||
%.pg2: %.o $(IP65LIB) $(APPLE2NETLIB) $(INCFILES) ../cfg/a2bin.cfg
|
%.pg2: %.o $(IP65LIB) $(APPLE2NETLIB) $(INCFILES) ../cfg/a2bin.cfg
|
||||||
$(LD) -C ../cfg/a2bin.cfg -o $*.pg2 $(AFLAGS) $< $(IP65LIB) $(APPLE2PROGLIB)
|
$(LD) -C ../cfg/a2bin.cfg -o $*.pg2 $(AFLAGS) $< $(IP65LIB) $(APPLE2PROGLIB)
|
||||||
|
|
||||||
ip65test.dsk: testdns.pg2 testdottedquad.pg2
|
ip65test.dsk: testdns.pg2 testdottedquad.pg2 testtftp.pg2
|
||||||
ripxplore.rb --init BeautifulBoot ip65test.dsk -a testdns.pg2 -t AppleBinary
|
ripxplore.rb --init BeautifulBoot 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 testdottedquad.pg2 -t AppleBinary
|
||||||
|
ripxplore.rb ip65test.dsk -a testdns.pg2 -t AppleBinary
|
||||||
all: \
|
|
||||||
ip65test.dsk \
|
|
||||||
testdns.prg \
|
|
||||||
test_cart_api.prg \
|
|
||||||
testdns.pg2 \
|
|
||||||
testdottedquad.pg2 \
|
|
||||||
testdottedquad.prg \
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o
|
rm -f *.o *.pg2 *.prg
|
||||||
rm -f testdns.prg testdns.map testdns.pg2 testdottedquad.prg testdottedquad.pg2
|
|
||||||
rm -f ip65test.dsk
|
rm -f ip65test.dsk
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
|
100
client/test/testtftp.s
Normal file
100
client/test/testtftp.s
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
.include "../inc/common.i"
|
||||||
|
.include "../inc/commonprint.i"
|
||||||
|
.include "../inc/net.i"
|
||||||
|
|
||||||
|
.import exit_to_basic
|
||||||
|
|
||||||
|
.import cfg_get_configuration_ptr
|
||||||
|
.import copymem
|
||||||
|
.importzp copy_src
|
||||||
|
.importzp copy_dest
|
||||||
|
|
||||||
|
|
||||||
|
.import __CODE_LOAD__
|
||||||
|
.import __CODE_SIZE__
|
||||||
|
.import __RODATA_SIZE__
|
||||||
|
.import __DATA_SIZE__
|
||||||
|
.import tftp_upload
|
||||||
|
.import tftp_set_callback_vector
|
||||||
|
.import tftp_ip
|
||||||
|
.importzp tftp_filename
|
||||||
|
|
||||||
|
.segment "STARTUP" ;this is what gets put at the start of the file on the C64
|
||||||
|
|
||||||
|
.word basicstub ; load address
|
||||||
|
|
||||||
|
basicstub:
|
||||||
|
.word @nextline
|
||||||
|
.word 2003
|
||||||
|
.byte $9e
|
||||||
|
.byte <(((init / 1000) .mod 10) + $30)
|
||||||
|
.byte <(((init / 100 ) .mod 10) + $30)
|
||||||
|
.byte <(((init / 10 ) .mod 10) + $30)
|
||||||
|
.byte <(((init ) .mod 10) + $30)
|
||||||
|
.byte 0
|
||||||
|
@nextline:
|
||||||
|
.word 0
|
||||||
|
|
||||||
|
.segment "EXEHDR" ;this is what gets put an the start of the file on the Apple 2
|
||||||
|
.addr __CODE_LOAD__-$11 ; Start address
|
||||||
|
.word __CODE_SIZE__+__RODATA_SIZE__+__DATA_SIZE__+4 ; Size
|
||||||
|
jmp init
|
||||||
|
|
||||||
|
.code
|
||||||
|
|
||||||
|
init:
|
||||||
|
jsr print_cr
|
||||||
|
init_ip_via_dhcp
|
||||||
|
jsr print_ip_config
|
||||||
|
|
||||||
|
ldax #upload_callback
|
||||||
|
jsr tftp_set_callback_vector
|
||||||
|
lda #0
|
||||||
|
sta block_number
|
||||||
|
ldax #test_file
|
||||||
|
stax tftp_filename
|
||||||
|
lda #$ff
|
||||||
|
ldx #$3
|
||||||
|
:
|
||||||
|
sta tftp_ip,x
|
||||||
|
dex
|
||||||
|
bpl :-
|
||||||
|
|
||||||
|
ldax #sending
|
||||||
|
jsr print
|
||||||
|
jsr tftp_upload
|
||||||
|
rts
|
||||||
|
|
||||||
|
upload_callback:
|
||||||
|
stax copy_dest
|
||||||
|
ldax #buffer1
|
||||||
|
stax copy_src
|
||||||
|
inc block_number
|
||||||
|
lda block_number
|
||||||
|
ldx #00
|
||||||
|
@next_byte:
|
||||||
|
sta buffer1,x
|
||||||
|
sta buffer2,x
|
||||||
|
inx
|
||||||
|
bne @next_byte
|
||||||
|
cmp #7
|
||||||
|
beq @last_block
|
||||||
|
ldax #512
|
||||||
|
jmp :+
|
||||||
|
@last_block:
|
||||||
|
ldax #0
|
||||||
|
:
|
||||||
|
stax block_length
|
||||||
|
jsr copymem
|
||||||
|
ldax block_length
|
||||||
|
rts
|
||||||
|
.rodata
|
||||||
|
|
||||||
|
test_file: .byte "TESTFILE.BIN",0
|
||||||
|
sending: .byte "SENDING...",0
|
||||||
|
|
||||||
|
.bss
|
||||||
|
block_number: .res 1
|
||||||
|
block_length: .res 2
|
||||||
|
buffer1: .res 256
|
||||||
|
buffer2: .res 256
|
1
dist/make_dist.rb
vendored
1
dist/make_dist.rb
vendored
@ -16,6 +16,7 @@ end
|
|||||||
[
|
[
|
||||||
["client/nb65/utherboot.dsk","nb65/"],
|
["client/nb65/utherboot.dsk","nb65/"],
|
||||||
["client/nb65/nb65_rrnet.bin","nb65/"],
|
["client/nb65/nb65_rrnet.bin","nb65/"],
|
||||||
|
["client/nb65/nb65_c64_ram.prg","nb65/"],
|
||||||
["client/nb65/nb65_std_cart.bin","nb65/"],
|
["client/nb65/nb65_std_cart.bin","nb65/"],
|
||||||
["server/lib/tftp_server.rb","lib"],
|
["server/lib/tftp_server.rb","lib"],
|
||||||
["server/bin/tftp_only_server.rb","bin/tftp_server.rb"],
|
["server/bin/tftp_only_server.rb","bin/tftp_server.rb"],
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
require 'socket'
|
require 'socket'
|
||||||
class Netboot65TFTPServer
|
class Netboot65TFTPServer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TFTP_OPCODES={
|
TFTP_OPCODES={
|
||||||
1=>'RRQ', #read request
|
1=>'RRQ', #read request
|
||||||
2=>'WRQ', #write request
|
2=>'WRQ', #write request
|
||||||
@ -34,7 +36,7 @@ class Netboot65TFTPServer
|
|||||||
@bootfile_dir=bootfile_dir
|
@bootfile_dir=bootfile_dir
|
||||||
@port=port
|
@port=port
|
||||||
@server_thread=nil
|
@server_thread=nil
|
||||||
|
@current_connection={}
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_error(client_ip,client_port,error_code,error_msg)
|
def send_error(client_ip,client_port,error_code,error_msg)
|
||||||
@ -86,12 +88,17 @@ class Netboot65TFTPServer
|
|||||||
|
|
||||||
client_sock=UDPSocket.open
|
client_sock=UDPSocket.open
|
||||||
client_sock.connect(client_ip,client_port)
|
client_sock.connect(client_ip,client_port)
|
||||||
|
client_id="#{client_ip}:#{client_port}"
|
||||||
|
if @current_connection[client_id]==true then
|
||||||
|
log_msg("already sending to #{client_id}" )
|
||||||
|
end
|
||||||
|
@current_connection[client_id]=true
|
||||||
log_msg("receiving #{filename} from #{client_ip}:#{client_port}")
|
log_msg("receiving #{filename} from #{client_ip}:#{client_port}")
|
||||||
got_last_block=false
|
got_last_block=false
|
||||||
sent_last_ack=false
|
finished=false
|
||||||
block_number=0
|
block_number=0
|
||||||
until sent_last_ack do
|
finished
|
||||||
|
until finished do
|
||||||
packet=[4,block_number].pack("nn")
|
packet=[4,block_number].pack("nn")
|
||||||
got_block=false
|
got_block=false
|
||||||
TFTP_MAX_RESENDS.times do |attempt_number|
|
TFTP_MAX_RESENDS.times do |attempt_number|
|
||||||
@ -99,7 +106,7 @@ class Netboot65TFTPServer
|
|||||||
client_sock.send(packet,0,client_ip,client_port)
|
client_sock.send(packet,0,client_ip,client_port)
|
||||||
if got_last_block then
|
if got_last_block then
|
||||||
puts "last block received"
|
puts "last block received"
|
||||||
sent_last_ack=true
|
finished=true
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
if (IO.select([client_sock], nil, nil, 1)) then
|
if (IO.select([client_sock], nil, nil, 1)) then
|
||||||
@ -123,15 +130,17 @@ class Netboot65TFTPServer
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
break if got_block
|
break if got_block
|
||||||
if !got_block then
|
|
||||||
log_msg "TFTP: timed out waiting for DATA for block #{block_number+1} from #{client_ip}"
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if !got_block && !finished then
|
||||||
|
log_msg "TFTP: timed out waiting for DATA for block #{block_number+1} from #{client_ip}"
|
||||||
|
finished=true
|
||||||
|
break
|
||||||
|
end
|
||||||
block_number+=1
|
block_number+=1
|
||||||
end
|
end
|
||||||
file_handle.close
|
file_handle.close
|
||||||
|
@current_connection[client_id]=false
|
||||||
end
|
end
|
||||||
|
|
||||||
def start()
|
def start()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user