diff --git a/Changelog.md b/Changelog.md index 3c8e362..4ffcc3f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,12 +2,16 @@ ## [Unreleased] +## [2.1.3] - 2024-01-03 + ### Changed - [apple2] sp_init looks from slot 7 down to 1 instead of up from 1 to 7 - [apple2] sp_init now additionally looks for an SP card WITH the network adapter on it, which should skip other installed SP devices - [apple2] sp_init only runs once and stores network id, close no longer resets it. - lots of tests fixed (cycle count errors mostly) +- add network_init to detect network errors early. Implemented on APPLE2, nop on atari. + Note: network_open still checks if appropriate init has happened on apple, but network_init will do same thing first, and then open will use the results from init. ## [2.1.2] - 2024-01-03 diff --git a/apple2/src/fn_fuji/sp_init.s b/apple2/src/fn_fuji/sp_init.s index 715056a..ce39f77 100644 --- a/apple2/src/fn_fuji/sp_init.s +++ b/apple2/src/fn_fuji/sp_init.s @@ -14,16 +14,17 @@ .include "macros.inc" .include "zp.inc" -; uint8_t sp_init(); +; int8_t sp_init(); ; ; returns network slot if Smart Port initialised and has a NETWORK adapter -; otherwise 0. +; otherwise 0 if there were no errors but no SP device, else the -ve value of the device error from SP, as returned by sp_find_device. .proc _sp_init - mva #$01, _sp_is_init + mva #$01, _sp_is_init ; we assume you can only call init once. No devices are mounted after powerup mva #$00, _sp_network + sta last_sp_error ; find a device slot that has Smart Port with a NETWORK adapter -; going from 7 down to 1, which is more likely to hit a FN device before some other RAM Card etc. +; going from 7 down to 1, which is more likely to hit a FN device before some other RAM Card etc (thanks @ShunKita) mwa #$c700, ptr1 ldx #$01 @@ -52,12 +53,12 @@ cpx #$08 bne @all_slots - ; not found, return 0 in A/X + ; not found, return value of last_sp_error, which will be -ve or 0 for the caller to know there was a device error or not ; first, clear the dispatch function in case it was set when testing for a network device ldx #$00 stx _sp_dispatch_fn stx _sp_dispatch_fn+1 - txa + lda last_sp_error rts @found_sp: @@ -79,10 +80,15 @@ jsr _sp_find_network bpl @found_network + beq :+ + + ; we had a -ve value, which indicates a real SP error of some kind, capture it + ; so we can indicate the issue at the end if we didn't find a SP with network + sta last_sp_error - ; didn't find network, keep trying more slots + ; as we didn't find network, keep trying more slots ; restore ptr1 - popax ptr1 +: popax ptr1 ; restore the id we last tried into X pla tax @@ -94,6 +100,9 @@ ; a contains the found slot id of the network device sta _sp_network ; save the value for other functions to use + ; if one of the potentially other SP devices was in error, we will ignore it, as we found the right one with network. + mva #$00, last_sp_error + ; fix the stack jsr incsp2 ; remove the ptr1 we saved for looping pla ; remove the old X index we saved for looping @@ -102,4 +111,9 @@ ldx #$00 ; high byte of return lda _sp_network ; low byte of return (and sets Z) rts -.endproc \ No newline at end of file +.endproc + +.data +; store the last SP error we got. +; we want to ensure any error from the last SP device detected that we discard is captured. +last_sp_error: .byte 0 diff --git a/apple2/src/fn_network/network_json_query.s b/apple2/src/fn_network/network_json_query.s index 5cfcf9c..b1386ff 100644 --- a/apple2/src/fn_network/network_json_query.s +++ b/apple2/src/fn_network/network_json_query.s @@ -126,6 +126,7 @@ not_empty: ; nul terminate the string adw tmp5, ptr4 ; set tmp5 to end of string + sbw1 tmp5, #$01 ; remove 1 for the 0x9b char at the end of the result ldy #$00 tya sta (tmp5), y diff --git a/apple2/src/fn_network/network_status.s b/apple2/src/fn_network/network_status.s index e38fd54..9387f6c 100644 --- a/apple2/src/fn_network/network_status.s +++ b/apple2/src/fn_network/network_status.s @@ -23,13 +23,15 @@ ; _network_status: ; save A/X so we can restore them after clearing payload - pha - txa - pha - jsr _sp_clr_payload ; calls bzero, so trashes p1/2/3 - pla - tax - pla + + ; pha + ; txa + ; pha + ; jsr _sp_clr_payload ; calls bzero, so trashes p1/2/3 + ; pla + ; tax + ; pla + ; drop into no_clr version _network_status_no_clr: diff --git a/atari/src/fn_network/network_json_query.s b/atari/src/fn_network/network_json_query.s index 1f080a4..9db67a4 100644 --- a/atari/src/fn_network/network_json_query.s +++ b/atari/src/fn_network/network_json_query.s @@ -23,6 +23,9 @@ ; uint8_t network_json_query(char *devicespec, char *query, char *s); ; +; TODO: how do we deal with very large json results? Maybe interface with network_read, which can handle them. +; Or does sio_read work with any max size? + .proc _network_json_query axinto tmp6 ; save target string location @@ -65,9 +68,9 @@ beq no_data ; read data, this sets _fn_bytes_read - pusha tmp5 - pushax tmp6 - setax DVSTAT + pusha tmp5 ; unit + pushax tmp6 ; buffer + setax DVSTAT ; length jsr _sio_read bne error diff --git a/atari/src/fn_network/sio_read.s b/atari/src/fn_network/sio_read.s index b2c1bef..818fa46 100644 --- a/atari/src/fn_network/sio_read.s +++ b/atari/src/fn_network/sio_read.s @@ -16,8 +16,7 @@ _sio_read: axinto ptr1 ; length - ; this is wrong, we must set this in the network_read code, not here, as we could do more than 1 read for any connection, and need to accumulate - ; axinto _fn_bytes_read + axinto _fn_bytes_read setax #t_network_read jsr copy_nw_cmd_data ; setup DCB diff --git a/common/src/network_init.c b/common/src/network_init.c new file mode 100644 index 0000000..3f5dca0 --- /dev/null +++ b/common/src/network_init.c @@ -0,0 +1,29 @@ +#include +#include + +#include "../../fujinet-network.h" + +#ifdef BUILD_APPLE2 +#include "../../fujinet-network-apple2.h" +#include "../../apple2/src/fn_fuji/inc/sp.h" +#endif + +uint8_t network_init() +{ + int8_t err = 0; + +#ifdef BUILD_APPLE2 + err = sp_init(); + if (err == 0) { + return FN_ERR_NO_DEVICE; + } else if (err > 0) { + // The device was initialised correctly, and we found a network device + return FN_ERR_OK; + } else { + // -ve value is the inverse of the SP error from sp_find_device + return fn_error(-err); + } +#endif + + return err; +} \ No newline at end of file diff --git a/common/src/network_read.c b/common/src/network_read.c index 315fab4..49c5b76 100644 --- a/common/src/network_read.c +++ b/common/src/network_read.c @@ -25,6 +25,7 @@ uint8_t network_read(char *devicespec, uint8_t *buf, uint16_t len) uint8_t r = 0; uint16_t fetch_size = 0; uint16_t amount_left = len; + uint16_t total_read = 0; #ifdef BUILD_ATARI uint8_t unit = 0; #endif @@ -75,7 +76,11 @@ uint8_t network_read(char *devicespec, uint8_t *buf, uint16_t len) } fetch_size = MIN(amount_left, fn_network_bw); - fetch_size = MIN(fetch_size, MAX_READ_SIZE); // should we always limit to MAX_READ_SIZE on all devices? + +#ifdef BUILD_APPLE2 + // need to validate this is only required for apple + fetch_size = MIN(fetch_size, MAX_READ_SIZE); +#endif #ifdef BUILD_ATARI sio_read(unit, buf, fetch_size); @@ -88,8 +93,10 @@ uint8_t network_read(char *devicespec, uint8_t *buf, uint16_t len) buf += fetch_size; amount_left -= fetch_size; - fn_bytes_read += fetch_size; + total_read += fetch_size; } + // do this here at the end, not in the loop so sio_read for atari can continue to set fn_bytes_read for short reads. + fn_bytes_read = total_read; return 0; } \ No newline at end of file diff --git a/fujinet-network-apple2.h b/fujinet-network-apple2.h index 06293a7..3789668 100644 --- a/fujinet-network-apple2.h +++ b/fujinet-network-apple2.h @@ -24,8 +24,10 @@ void sp_clr_payload(); int8_t sp_status(uint8_t dest, uint8_t statcode); int8_t sp_control(uint8_t dest, uint8_t ctrlcode); int8_t sp_read(uint8_t dest, uint16_t len); +uint8_t sp_init(); uint8_t network_status_no_clr(char *devicespec, uint16_t *bw, uint8_t *c, uint8_t *err); uint8_t network_unit(char *devicespec); + #endif diff --git a/fujinet-network.h b/fujinet-network.h index e976f3f..688eb7c 100644 --- a/fujinet-network.h +++ b/fujinet-network.h @@ -23,7 +23,6 @@ extern uint16_t fn_bytes_read; extern uint8_t fn_device_error; uint8_t fn_error(uint8_t code); - /* * Network status values. These are set during network_read. You can capture your own using network_status. * bw : bytes waiting @@ -35,7 +34,15 @@ extern uint8_t fn_network_conn; extern uint8_t fn_network_error; /** - * @brief Get Network Device Status byte + * @brief Initialise network device + * Allows initialisation of network to perform any platform dependent checks, and allow applications to + * exit early if there is a network issue. + * @return fujinet-network status/error code (See FN_ERR_* values) and set device specific error if there is any + */ +uint8_t network_init(); + +/** + * @brief Get Network Device Status byte * @param devicespec pointer to device specification of form: N:PROTO://[HOSTNAME]:PORT/PATH/.../ * @param bw pointer to where to put bytes waiting * @param c pointer to where to put connection status @@ -184,6 +191,7 @@ uint8_t network_http_delete(char *devicespec, uint8_t trans); #define FN_ERR_BAD_CMD (0x02) /* Function called with bad arguments */ #define FN_ERR_OFFLINE (0x03) /* The device is offline */ #define FN_ERR_WARNING (0x04) /* Device specific non-fatal warning issued */ +#define FN_ERR_NO_DEVICE (0x05) /* There is no network device */ #define FN_ERR_UNKNOWN (0xff) /* Device specific error we didn't handle */