diff --git a/client/ip65/xmodem.s b/client/ip65/xmodem.s index fb91902..d8a6b2b 100644 --- a/client/ip65/xmodem.s +++ b/client/ip65/xmodem.s @@ -17,6 +17,7 @@ NAK = $15 CAN = $18 .export xmodem_receive +.export xmodem_send .export xmodem_iac_escape ;are IAC bytes ($FF) escaped? @@ -40,6 +41,9 @@ CAN = $18 got_byte: jmp $ffff +get_byte: + jmp $ffff + next_char: lda buffer_length bne @not_eof @@ -63,9 +67,23 @@ next_char: sbc #0 sta buffer_length+1 pla - clc - + clc rts + + +emit_a: +emit_a_ptr=*+1 + sta $ffff + inc emit_a_ptr + bne :+ + inc emit_a_ptr+1 +: + inc xmodem_block_buffer_length + bne :+ + inc xmodem_block_buffer_length+1 +: + rts + .bss original_tcp_callback: .res 2 @@ -74,16 +92,110 @@ getc_timeout_seconds: .res 1 buffer_length: .res 2 .code - -xmodem_receive: -;recieve a file via XMODEM (checksum mode only, not CRC) -;assumes that a tcp connection has already been set up, and that the other end is waiting to start sending -;inputs: AX points to routine to call once for each byte in downloaded file (e.g. save to disk, print to screen, whatever) - byte will be in A + +xmodem_send: +;send a file via XMODEM (checksum mode only, not CRC) +;assumes that a tcp connection has already been set up, and that the other end is waiting to start receiving +;inputs: AX points to routine to call once for each byte in file to send (e.g. save to disk, print to screen, whatever) - byte will be in A, carry flag set means EOF ; xmodem_iac_escape should be set to non-zero if the remote end escapes $FF bytes (i.e. if it is a real telnet server) ;outputs: none + stax get_byte+1 + jsr xmodem_transfer_setup + + +@send_block: + ldax #sending + jsr print_ascii_as_native + + ldax #block_number_msg + jsr print_ascii_as_native + lda expected_block_number + jsr print_hex + jsr print_cr + + +@wait_for_ack_or_nak: + lda #XMODEM_TIMEOUT_SECONDS + jsr getc + bcs @synch_error + cmp #ACK + beq @got_ack + cmp #NAK + beq @got_nak + +@synch_error: + pha + lda user_abort + beq @no_user_abort + jmp xmodem_transfer_exit +@no_user_abort: + + lda #'(' + jsr print_a + pla + jsr print_hex + lda #')' + jsr print_a + + inc error_number + ldax #sync_error_msg + jsr print_ascii_as_native + ldax #error_count_msg + jsr print_ascii_as_native + lda error_number + jsr print_hex + jsr print_cr + lda error_number + cmp #XMODEM_MAX_ERRORS + bcc @wait_for_ack_or_nak + lda #KPR_ERROR_TOO_MANY_ERRORS + sta ip65_error + jmp xmodem_transfer_exit + +@got_ack: + inc expected_block_number +@got_nak: + + lda #0 + sta checksum + sta xmodem_block_buffer_length + sta xmodem_block_buffer_length+1 + ldax #xmodem_block_buffer + stax emit_a_ptr + + lda #SOH + jsr emit_a + lda expected_block_number + jsr emit_a + eor #$ff + jsr emit_a + lda #$80 + sta block_ptr +@copy_one_byte: + lda #$1; FIX ME + pha + clc + adc checksum + sta checksum + pla + jsr emit_a + dec block_ptr + bne @copy_one_byte + lda checksum + jsr emit_a + + ldax xmodem_block_buffer_length + stax tcp_send_data_len + ldax #xmodem_block_buffer + jsr tcp_send + + jmp @send_block + + rts + - stax got_byte+1 +xmodem_transfer_setup: lda #0 sta buffer_length sta buffer_length+1 @@ -95,8 +207,20 @@ xmodem_receive: ldax tcp_callback stax original_tcp_callback - ldax #xmodem_receive_callback + ldax #xmodem_tcp_callback stax tcp_callback + rts + +xmodem_receive: +;recieve a file via XMODEM (checksum mode only, not CRC) +;assumes that a tcp connection has already been set up, and that the other end is waiting to start sending +;inputs: AX points to routine to call once for each byte in downloaded file (e.g. save to disk, print to screen, whatever) - byte will be in A +; xmodem_iac_escape should be set to non-zero if the remote end escapes $FF bytes (i.e. if it is a real telnet server) +;outputs: none + + + stax got_byte+1 + jsr xmodem_transfer_setup jsr send_nak @@ -119,12 +243,14 @@ xmodem_receive: bcc @got_block_start lda user_abort beq @no_user_abort - jmp @exit + jmp xmodem_transfer_exit @no_user_abort: jsr send_nak inc error_number ldax #timeout_msg jsr print_ascii_as_native + ldax #error_count_msg + jsr print_ascii_as_native lda error_number jsr print_hex jsr print_cr @@ -133,13 +259,13 @@ xmodem_receive: bcc @wait_for_block_start lda #KPR_ERROR_TOO_MANY_ERRORS sta ip65_error - jmp @exit + jmp xmodem_transfer_exit @got_block_start: cmp #EOT bne :+ jsr send_ack clc - jmp @exit + jmp xmodem_transfer_exit : cmp #SOH bne @wait_for_block_start @@ -176,7 +302,7 @@ xmodem_receive: lda #XMODEM_TIMEOUT_SECONDS jsr getc bcc :+ - jmp @exit + jmp xmodem_transfer_exit : ldx block_ptr sta xmodem_block_buffer,x @@ -189,6 +315,7 @@ xmodem_receive: ldax #checksum_msg jsr print_ascii_as_native + lda checksum jsr print_hex @@ -197,7 +324,7 @@ xmodem_receive: lda #XMODEM_TIMEOUT_SECONDS jsr getc - bcs @exit + bcs xmodem_transfer_exit sta received_checksum jsr print_hex jsr print_cr @@ -209,6 +336,8 @@ xmodem_receive: inc error_number ldax #checksum_error_msg jsr print_ascii_as_native + ldax #error_count_msg + jsr print_ascii_as_native lda error_number jsr print_hex jsr print_cr @@ -219,7 +348,7 @@ xmodem_receive: : lda #KPR_ERROR_TOO_MANY_ERRORS sta ip65_error - jmp @exit + jmp xmodem_transfer_exit jsr send_nak jmp @next_block @@ -247,13 +376,14 @@ xmodem_receive: jmp @next_block clc -@exit: + +xmodem_transfer_exit: ldax original_tcp_callback stax tcp_callback rts -xmodem_receive_callback: +xmodem_tcp_callback: lda tcp_inbound_data_length+1 cmp #$ff bne @not_eof @@ -268,8 +398,8 @@ xmodem_receive_callback: ldax tcp_inbound_data_length stax buffer_length - jmp copymem - + jsr copymem + rts send_nak: ldax #1 @@ -331,6 +461,7 @@ getc: lda $dc09 ;time of day clock: seconds cmp getc_timeout_end bne @poll_loop + lda #00 sec rts @@ -343,14 +474,18 @@ getc: block_number_msg: .byte " block $",0 expecting: .byte "expecting",0 receiving: .byte "receiving",0 +sending: .byte "sending",0 + bad_block_number: .byte "bad block number",0 checksum_msg: .byte "checksum $",0 -checksum_error_msg : .byte "checksum error - error count $",0 -timeout_msg: .byte "timeout error - error count $",0 - +checksum_error_msg : .byte "checksum",0 +timeout_msg: .byte "timeout error",0 +sync_error_msg: .byte "sync",0 +error_count_msg: .byte " error - error count $",0 .segment "APP_SCRATCH" xmodem_stream_buffer: .res 1600 -xmodem_block_buffer: .res 128 +xmodem_block_buffer: .res 300 +xmodem_block_buffer_length: .res 2 expected_block_number: .res 1 actual_block_number: .res 1 checksum: .res 1 diff --git a/client/test/test_xmodem.s b/client/test/test_xmodem.s index 9d74c93..064ad7d 100644 --- a/client/test/test_xmodem.s +++ b/client/test/test_xmodem.s @@ -16,6 +16,7 @@ .import tcp_inbound_data_ptr .import tcp_inbound_data_length + .import xmodem_send .import xmodem_receive .import xmodem_iac_escape @@ -74,8 +75,6 @@ init: jsr print_ascii_as_native jsr print_cr - lda #'1' - jsr print_a ;connect to port 1000 - xmodem server @@ -91,21 +90,56 @@ init: ldax #1000 jsr tcp_connect - bcs @error - - lda #'2' - jsr print_a + bcc :+ + jmp check_for_error +: ldax #first_message jsr tcp_send_string - : jsr ip65_process lda packet_count beq :- + + ldax #connected + jsr print_ascii_as_native + jsr download_file + jsr check_for_error + jsr upload_file + jsr check_for_error + jsr tcp_close + rts + +upload_file: + ldax #uploading + jsr print_ascii_as_native - lda #'3' - jsr print_a + ldax #start_upload + jsr tcp_send_string + bcc :+ +@error: + jsr check_for_error +: + + jsr open_upload_file + bcc :+ + jmp check_for_error +: + ldax #read_byte + jsr xmodem_send + jsr close_file + + rts + +read_byte: + .byte $92 + + + + +download_file: + ldax #downloading + jsr print_ascii_as_native ldax #start_download jsr tcp_send_string @@ -114,8 +148,7 @@ init: jsr check_for_error : - - jsr open_file + jsr open_download_file bcc :+ jmp check_for_error : @@ -123,11 +156,7 @@ init: jsr xmodem_receive jsr close_file - jsr tcp_close - lda #'4' - jsr print_a - rts @@ -160,11 +189,19 @@ check_for_error: jsr print_cr rts -open_file: - lda #fname_end-fname - ldx #fname + +open_upload_file: + lda #upload_filename_end-upload_filename + ldx #upload_filename + jmp open_file +open_download_file: + lda #download_filename_end-download_filename + ldx #download_filename + +open_file: jsr $FFBD ; call SETNAM lda #$02 ; file number 2 ldx $BA ; last used device number @@ -220,16 +257,27 @@ close_file: starting: .byte "saving to " -fname: .byte "@0:XMODEM.TMP,P,W" ; @0: means 'overwrite if existing', ',P,W' is required to make this an output file -fname_end: +download_filename: .byte "@0:XMODEM.TMP,P,W" ; @0: means 'overwrite if existing', ',P,W' is required to make this an output file +download_filename_end: .byte 0 first_message: .byte "yo!",0 +upload_filename: .byte "XMODEM.TMP" +upload_filename_end: +.byte 0 + start_download: - .byte "B",0 ;b=Binary, i.e. trigger IAC escape, R=receive text, i.e. no IAC escape + .byte "B",0 ;B=Binary, i.e. trigger IAC escape, R=receive text, i.e. no IAC escape .data +start_upload: + .byte "S",0 ;S send via normal checksum mode (not CRC) +.data + +uploading: .byte "uploading",10,0 +downloading: .byte "downloading",10,0 +connected: .byte "connected",10,0 tcp_dest_ip: .byte 10,5,1,102 ; .byte 192,168,160,1