# ip65 technical reference

# File : ip65/function_dispatcher.s

    this is some very quick and dirty glue to make the most useful IP65 functions available via a single entry point.
    this allows user applications to be developed that don't link ip65 in directly, rather they use an instance of ip65 that is preloaded (or in a cartridge/ROM)
    this whole file could (and should) be greatly optimised by making it all table driven, but since this file is probably only going to be used in a bankswitched ROM where
    space is not at such a premium, I'll go with the gross hack for now.

## functions

function | description
--- | ---
kipper_dispatcher |

## implementation

    ;this is some very quick and dirty glue to make the most useful IP65 functions available via a single entry point.
    ;this allows user applications to be developed that don't link ip65 in directly, rather they use an instance of ip65 that is preloaded (or in a cartridge/ROM)
    ;this whole file could (and should) be greatly optimised by making it all table driven, but since this file is probably only going to be used in a bankswitched ROM where
    ;space is not at such a premium, I'll go with the gross hack for now.

    .ifndef KPR_API_VERSION_NUMBER
      .define EQU     =
      .include "../inc/kipper_constants.i"
    .endif
    .include "../inc/common.i"
    .include "../inc/commonprint.i"
    .export kipper_dispatcher

    .import ip65_init
    .import dhcp_init
    .import cfg_get_configuration_ptr
    .import tftp_load_address
    .importzp tftp_filename
    .import tftp_ip
    .import ip65_error
    .import tftp_clear_callbacks
    .import tftp_download
    .import tftp_upload
    .import tftp_set_callback_vector
    .import tftp_filesize
    .import dns_ip
    .import dns_resolve
    .import dns_set_hostname
    .import udp_callback
    .import udp_add_listener
    .import udp_remove_listener
    .import ip_inp
    .import udp_inp
    .import udp_send
    .import udp_send_src
    .import udp_send_src_port
    .import udp_send_dest
    .import udp_send_dest_port
    .import udp_send_len

    .import copymem
    .import cfg_mac
    .import cfg_tftp_server
    .importzp copy_src
    .importzp copy_dest

    ;reuse the copy_src zero page location
    kipper_params = copy_src
    buffer_ptr= copy_dest
    .data

    ip_configured_flag:
      .byte 0

    .code

    set_tftp_params:
        ldx #$03
    :
      lda cfg_tftp_server,x
      sta tftp_ip,x
      dex
      bpl :-

      ldy #KPR_TFTP_FILENAME
      lda (kipper_params),y
      sta tftp_filename
      iny
      lda (kipper_params),y
      sta tftp_filename+1

      ldy #KPR_TFTP_POINTER
      lda (kipper_params),y
      sta tftp_load_address
      iny
      lda (kipper_params),y
      sta tftp_load_address+1

      jsr tftp_clear_callbacks

      rts

    set_tftp_callback_vector:
      ldy #KPR_TFTP_POINTER+1
      lda (kipper_params),y
      tax
      dey
      lda (kipper_params),y
      jmp tftp_set_callback_vector

    kipper_dispatcher:
      stax kipper_params

      cpy #KPR_INITIALIZE
      bne :+
      lda ip_configured_flag
      bne ip_configured
      jsr ip65_init
      bcs init_failed
      jsr dhcp_init
      bcc dhcp_ok
      jsr ip65_init   ;if DHCP failed, then reinit the IP stack (which will reset IP address etc that DHCP messed with to cartridge default values)
    dhcp_ok:
      lda #1
      sta ip_configured_flag
      clc
    init_failed:
      rts

    ip_configured:
      clc
      rts
    :

      cpy #KPR_GET_IP_CONFIG
      bne :+
      ldax  #cfg_mac
      clc
      rts
    :

      cpy #KPR_DNS_RESOLVE
      bne :+
      phax
      ldy #KPR_DNS_HOSTNAME+1
      lda (kipper_params),y
      tax
      dey
      lda (kipper_params),y
      jsr dns_set_hostname
      bcs @dns_error
      jsr dns_resolve
      bcs @dns_error

      ldy #KPR_DNS_HOSTNAME_IP
      plax
      stax kipper_params
      ldx #4
    @copy_dns_ip:
      lda dns_ip,y
      sta (kipper_params),y
      iny
      dex
      bne @copy_dns_ip
      rts
    @dns_error:
      plax
      rts

    :

      cpy #KPR_UDP_ADD_LISTENER
      bne :+
      ldy #KPR_UDP_LISTENER_CALLBACK
      lda (kipper_params),y
      sta udp_callback
      iny
      lda (kipper_params),y
      sta udp_callback+1
      ldy #KPR_UDP_LISTENER_PORT+1
      lda (kipper_params),y
      tax
      dey
      lda (kipper_params),y

      jmp udp_add_listener
    :

      cpy #KPR_GET_INPUT_PACKET_INFO
      bne :+
      ldy #3
    @copy_src_ip:
      lda ip_inp+12,y  ;src IP
      sta (kipper_params),y
      dey
      bpl @copy_src_ip

      ldy #KPR_REMOTE_PORT
      lda udp_inp+1 ;src port (lo byte)
      sta (kipper_params),y
      iny
      lda udp_inp+0 ;src port (high byte)
      sta (kipper_params),y
      iny
      lda udp_inp+3 ;dest port (lo byte)
      sta (kipper_params),y
      iny
      lda udp_inp+2 ;dest port (high byte)
      sta (kipper_params),y

      iny
      sec
      lda udp_inp+5 ;payload length (lo byte)
      sbc #8  ;to remove length of header
      sta (kipper_params),y

      iny
      lda udp_inp+4 ;payload length (hi byte)
      sbc #0  ;in case there was a carry from the lo byte
      sta (kipper_params),y

      iny
      lda #<(udp_inp+8) ;payload ptr (lo byte)
      sta (kipper_params),y

      iny
      lda #>(udp_inp+8) ;payload ptr (hi byte)
      sta (kipper_params),y

    .import tcp_inbound_data_ptr
    .import tcp_inbound_data_length

      lda ip_inp+9 ;proto number
      cmp #6  ;TCP
      bne @not_tcp
      ldy #KPR_PAYLOAD_LENGTH
      lda tcp_inbound_data_length
      sta (kipper_params),y
      iny
      lda tcp_inbound_data_length+1
      sta (kipper_params),y

      ldy #KPR_PAYLOAD_POINTER
      lda tcp_inbound_data_ptr
      sta (kipper_params),y
      iny
      lda tcp_inbound_data_ptr+1
      sta (kipper_params),y
    @not_tcp:

      clc
      rts
    :

      cpy #KPR_SEND_UDP_PACKET
      bne :+
      ldy #3
    @copy_dest_ip:
      lda (kipper_params),y
      sta udp_send_dest,y
      dey
      bpl @copy_dest_ip

      ldy #KPR_REMOTE_PORT
      lda (kipper_params),y
      sta udp_send_dest_port
      iny
      lda (kipper_params),y
      sta udp_send_dest_port+1
      iny

      lda (kipper_params),y
      sta udp_send_src_port
      iny
      lda (kipper_params),y
      sta udp_send_src_port+1
      iny

      lda (kipper_params),y
      sta udp_send_len
      iny
      lda (kipper_params),y
      sta udp_send_len+1
      iny

      ;AX should point at data to send
      lda (kipper_params),y
      pha
      iny
      lda (kipper_params),y
      tax
      pla
      jmp udp_send
    :

      cpy #KPR_UDP_REMOVE_LISTENER
      bne :+
      jmp udp_remove_listener
    :

      cpy #KPR_DEACTIVATE
      ;nothing to do now we don't use IRQ
      bne :+
      clc
      rts
    :

      cpy #KPR_TFTP_SET_SERVER
      bne :+
      ldy #3
    @copy_tftp_server_ip:
      lda (kipper_params),y
      sta cfg_tftp_server,y
      dey
      bpl @copy_tftp_server_ip
      clc
      rts

    :
      cpy #KPR_TFTP_DOWNLOAD
      bne :+
      phax
      jsr set_tftp_params
      jsr tftp_download

    @after_tftp_call:  ;write the current load address back to the param buffer (so if $0000 was passed in, the caller can find out the actual value used)
      plax
      bcs @tftp_error
      stax kipper_params

      ldy #KPR_TFTP_POINTER
      lda tftp_load_address
      sta (kipper_params),y
      iny
      lda tftp_load_address+1
      sta (kipper_params),y

      ldy #KPR_TFTP_FILESIZE
      lda tftp_filesize
      sta (kipper_params),y
      iny
      lda tftp_filesize+1
      sta (kipper_params),y
      clc
    @tftp_error:
      rts
    :

      cpy #KPR_TFTP_CALLBACK_DOWNLOAD
      bne :+
      phax
      jsr set_tftp_params
      jsr set_tftp_callback_vector
      jsr tftp_download
      jmp @after_tftp_call
    :

      cpy #KPR_TFTP_UPLOAD
      bne :+
      phax
      jsr set_tftp_params
      ldy #KPR_TFTP_POINTER
      lda (kipper_params),y
      sta tftp_filesize
      iny
      lda (kipper_params),y
      sta tftp_filesize+1

      jsr tftp_download
      jmp @after_tftp_call
    :

      cpy #KPR_TFTP_CALLBACK_UPLOAD
      bne :+
      jsr set_tftp_params
      jsr set_tftp_callback_vector
      jmp tftp_upload
    :

      cpy #KPR_PRINT_ASCIIZ
      bne :+
      jsr print
      clc
      rts
    :

      cpy #KPR_PRINT_HEX
      bne :+
      jsr print_hex
      clc
      rts
    :

      cpy #KPR_PRINT_DOTTED_QUAD
      bne :+
      jsr print_dotted_quad
      clc
      rts
    :

      cpy #KPR_PRINT_IP_CONFIG
      bne :+
      jsr print_ip_config
      clc
      rts
    :

      cpy #KPR_PRINT_INTEGER
      bne :+
      jsr print_integer
      clc
      rts
    :

      .segment "TCP_VARS"
        port_number: .res 2
        nonzero_octets: .res 1
      .code

      cpy #KPR_DOWNLOAD_RESOURCE
      bne :+
    .import url_download
    .import url_download_buffer
    .import url_download_buffer_length

      ldy #KPR_URL_DOWNLOAD_BUFFER
      lda (kipper_params),y
      sta url_download_buffer
      iny
      lda (kipper_params),y
      sta url_download_buffer+1

      ldy #KPR_URL_DOWNLOAD_BUFFER_LENGTH
      lda (kipper_params),y
      sta url_download_buffer_length
      iny
      lda (kipper_params),y
      sta url_download_buffer_length+1

      ldy #KPR_URL+1
      lda (kipper_params),y
      tax
      dey
      lda (kipper_params),y
      jmp url_download
    :

      cpy #KPR_FILE_LOAD
    bne :+
    .import  io_device_no
    .import io_read_file
    .import io_filename
    .import io_filesize
    .import io_load_address
      phax
      ldy #KPR_FILE_ACCESS_FILENAME
      lda (kipper_params),y
      sta io_filename
      iny
      lda (kipper_params),y
      sta io_filename+1

      ldy #KPR_FILE_ACCESS_DEVICE
      lda (kipper_params),y
      sta io_device_no

      ldy #KPR_FILE_ACCESS_POINTER+1
      lda (kipper_params),y
      tax
      dey
      lda (kipper_params),y
      jsr io_read_file
      plax
      bcc @read_file_ok
      rts

    @read_file_ok:
      stax kipper_params

      ldy #KPR_FILE_ACCESS_POINTER
      lda io_load_address
      sta (kipper_params),y
      iny
      lda io_load_address+1
      sta (kipper_params),y

      ldy #KPR_FILE_ACCESS_FILESIZE
      lda io_filesize
      sta (kipper_params),y
      iny
      lda io_filesize+1
      sta (kipper_params),y
      rts
    :

      cpy #KPR_HTTPD_START
      bne :+
      .import httpd_start
      jmp httpd_start
    :

    cpy #KPR_HTTPD_GET_VAR_VALUE
      bne :+
      .import http_get_value
      jmp http_get_value
    :

      cpy #KPR_PING_HOST
      .import icmp_echo_ip
      .import icmp_ping
      bne :+
      ldy #3
    @copy_ping_ip_loop:
      lda (kipper_params),y
      sta icmp_echo_ip,y
      dey
      bpl @copy_ping_ip_loop
      jmp icmp_ping

    :
      cpy #KPR_TCP_CONNECT
      bne :+
      .import tcp_connect
      .import tcp_callback
      .import tcp_connect_ip
      .import tcp_listen
      ldy #3
      lda #0
      sta nonzero_octets
    @copy_dest_ip:
      lda (kipper_params),y
      beq @octet_was_zero
      inc nonzero_octets
    @octet_was_zero:
      sta tcp_connect_ip,y
      dey
      bpl @copy_dest_ip

      ldy #KPR_TCP_CALLBACK
      lda (kipper_params),y
      sta tcp_callback
      iny
      lda (kipper_params),y
      sta tcp_callback+1

      ldy #KPR_TCP_PORT+1
      lda (kipper_params),y
      tax
      dey
      lda (kipper_params),y
      ldy nonzero_octets
      bne @outbound_tcp_connection
      jmp tcp_listen

    @outbound_tcp_connection:
      jmp tcp_connect

    :

      .import tcp_send
      .import tcp_send_data_len
      cpy #KPR_SEND_TCP_PACKET
      bne :+
      ldy #KPR_TCP_PAYLOAD_LENGTH
      lda (kipper_params),y
      sta tcp_send_data_len
      iny
      lda (kipper_params),y
      sta tcp_send_data_len+1
      ldy #KPR_TCP_PAYLOAD_POINTER+1
      lda (kipper_params),y
      tax
      dey
      lda (kipper_params),y
      jmp tcp_send

    :

    .import tcp_close
      cpy #KPR_TCP_CLOSE_CONNECTION
      bne :+
      jmp tcp_close
    :

    .import filter_dns
    .import get_filtered_input
    .import filter_number

      cpy #KPR_INPUT_STRING
      bne :+
      ldy #40 ;max chars
      ldax #$0000
      jmp get_filtered_input
    :

      cpy #KPR_INPUT_HOSTNAME
      bne :+
      ldy #40 ;max chars
      ldax #filter_dns
      jmp get_filtered_input
    :

    cpy #KPR_INPUT_PORT_NUMBER
      bne :+
      ldy #5 ;max chars
      ldax #filter_number
      jsr get_filtered_input
      bcs @no_port_entered

      ;AX now points a string containing port number
      .import parse_integer
      jmp parse_integer

    @no_port_entered:
      rts
    :

    cpy #KPR_BLOCK_COPY
      bne :+
      ;this is where we pay the price for trying to save a few 'zero page' pointers
      ;by reusing the 'copy_src' and 'copy_dest' addresses!
    .segment "TCP_VARS"
      tmp_copy_src: .res 2
      tmp_copy_dest: .res 2
      tmp_copy_length: .res 2
    .code

      ldy #KPR_BLOCK_SRC
      lda (kipper_params),y
      sta tmp_copy_src
      iny
      lda (kipper_params),y
      sta tmp_copy_src+1

      ldy #KPR_BLOCK_DEST
      lda (kipper_params),y
      sta tmp_copy_dest
      iny
      lda (kipper_params),y
      sta tmp_copy_dest+1

      ldy #KPR_BLOCK_SIZE
      lda (kipper_params),y
      sta tmp_copy_length
      iny
      lda (kipper_params),y
      sta tmp_copy_length+1

      ldax tmp_copy_src
      stax  copy_src
      ldax tmp_copy_dest
      stax  copy_dest
      ldax tmp_copy_length
      jmp copymem
    :

      cpy #KPR_PARSER_INIT
      bne :+
      .import parser_init
      jmp parser_init
    :

      cpy #KPR_PARSER_SKIP_NEXT
      bne :+
      .import parser_skip_next
      jmp parser_skip_next
    :

      cpy #KPR_GET_LAST_ERROR
      bne :+
      lda ip65_error
      clc
      rts
    :

    ;default function handler
      lda #KPR_ERROR_FUNCTION_NOT_SUPPORTED
      sta ip65_error
      sec        ;carry flag set = error
      rts

    ;-- LICENSE FOR function_dispatcher.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 --