Skip to content

Issuing SmartPort Commands

Norman Davie edited this page Mar 16, 2023 · 7 revisions

Once the SmartPort dispatcher is found, commands can be issued. The FujiNet can respond to STATUS, CONTROL, READ, and WRITE commands.

STATUS

Status commands are used to ask for information from the FujiNet.

C implementation (CC65)

int8_t sp_status(uint8_t dest, uint8_t statcode)
{
  sp_error = 0;
  // build the command list
  sp_cmdlist[0] = SP_STATUS_PARAM_COUNT;
  sp_cmdlist[1] = dest; // set before calling sp_status();
  sp_cmdlist[2] = (uint8_t)((uint16_t)&sp_payload & 0x00FF);
  sp_cmdlist[3] = (uint8_t)((uint16_t)&sp_payload >> 8) & 0xFF;
  sp_cmdlist[4] = statcode;

  sp_cmdlist_low = (uint8_t)((uint16_t)&sp_cmdlist & 0x00FF);
  sp_cmdlist_high = (uint8_t)((uint16_t)&sp_cmdlist >> 8) & 0xFF;


  // store cmd list
  __asm__ volatile ("lda #%b", SP_CMD_STATUS);
  __asm__ volatile ("sta %g", spCmd); // store status command # 
  __asm__ volatile ("lda %v", sp_cmdlist_low);
  __asm__ volatile ("sta %g", spCmdListLow); // store status command #
  __asm__ volatile ("lda %v", sp_cmdlist_high);
  __asm__ volatile ("sta %g", spCmdListHigh); // store status command #

  __asm__ volatile ("jsr $C50D"); // to do - find SP entry point using algorithm from firmware reference
spCmd:
  __asm__ volatile ("nop");
spCmdListLow:
  __asm__ volatile ("nop");
spCmdListHigh:
  __asm__ volatile ("nop");
  __asm__ volatile ("stx %v", sp_rtn_low);
  __asm__ volatile ("sty %v", sp_rtn_high);
  __asm__ volatile ("sta %v", sp_err);

  sp_count = ((uint16_t)sp_rtn_high << 8) | (uint16_t)sp_rtn_low;
  sp_error = sp_err;
  return sp_err;
}

Asm implementation

STATUSCODE = $00

	jsr DISPATCH
	DFB #STATUSCODE
	DW  CMLIST
	BCS ERROR

	; Everything ok
	CLC
	RTS
	
ERROR	; not okay
	RTS
	
CMLIST: DFB	#$03		; status has 3 params	
	DFB	#DEST           ; Destination device #
	DW	BUFFER          ; lo and hi bytes for buffer address
	DFB	STATUSCODE      ; The status code

CONTROL

CONTROL commands are typically imperative in nature, asking the FujiNet to perform an operation.

Asm Implementation

CTRLCODE = $04

	jsr DISPATCH
	DFB #CTRLCODE
	DW  CMLIST
	BCS ERROR

	; Everything ok
	CLC
	RTS
	
ERROR	; not okay
	RTS
	
CMLIST: DFB	#$03		; status has length of 3	
	DFB	#DEST           ; Destination device #
	DW	BUFFER          ; lo and hi bytes for buffer address
	DFB	CTRLCODE        ; The status code

C (CC65) implementation

int8_t sp_control(uint8_t dest, uint8_t ctrlcode)
{
  sp_error = 0;
  // sp_dest = 5; // need to search
  // build the command list
  sp_cmdlist[0] = SP_CONTROL_PARAM_COUNT;
  sp_cmdlist[1] = dest; // set before calling sp_status();
  sp_cmdlist[2] = (uint8_t)((uint16_t)&sp_payload & 0x00FF);
  sp_cmdlist[3] = (uint8_t)((uint16_t)&sp_payload >> 8) & 0xFF;
  sp_cmdlist[4] = ctrlcode;

  sp_cmdlist_low = (uint8_t)((uint16_t)&sp_cmdlist & 0x00FF);
  sp_cmdlist_high = (uint8_t)((uint16_t)&sp_cmdlist >> 8) & 0xFF;

  // store cmd list
  __asm__ volatile ("lda #%b", SP_CMD_CONTROL);
  __asm__ volatile ("sta %g", spCmd); // store status command #
  __asm__ volatile ("lda %v", sp_cmdlist_low);
  __asm__ volatile ("sta %g", spCmdListLow); // store status command #
  __asm__ volatile ("lda %v", sp_cmdlist_high);
  __asm__ volatile ("sta %g", spCmdListHigh); // store status command #

  __asm__ volatile ("jsr $C50D"); // to do - find entry point and used it instead of hardcoded address
spCmd:
  __asm__ volatile ("nop");
spCmdListLow:
  __asm__ volatile ("nop");
spCmdListHigh:
  __asm__ volatile ("nop");
  __asm__ volatile ("sta %v", sp_err);
  sp_error = sp_err;
  return sp_err;
}

READ

The READ command can be used, for example, with the Network Device, to read a number of bytes that are waiting in the receive buffer, and send them to the computer.

The main difference between this command (as well as the proceeding WRITE command) and the STATUS/CONTROL commands is that a buffer length is passed as part of the command list.

Asm Implementation

READCODE = $08

	jsr DISPATCH
	DFB #READCODE
	DW  CMLIST
	BCS ERROR

	; Everything ok
	CLC
	RTS
	
ERROR	; not okay
	RTS
	
CMLIST: DFB	#$04		; status has 4 params	
	DFB	#DEST           ; Destination device #
	DW	BUFFER          ; lo and hi bytes for buffer address
        DW      LEN             ; # of bytes to read into buffer

C Implementation

int8_t sp_read(uint8_t dest, uint16_t len)
{
  sp_error = 0;
  // sp_dest = 5; // need to search
  // build the command list
  sp_cmdlist[0] = SP_READ_PARAM_COUNT;
  sp_cmdlist[1] = dest; // set before calling sp_status();
  sp_cmdlist[2] = (uint8_t)((uint16_t)&sp_payload & 0x00FF);
  sp_cmdlist[3] = (uint8_t)((uint16_t)&sp_payload >> 8) & 0xFF;
  sp_cmdlist[4] = len & 0xFF;
  sp_cmdlist[5] = len >> 8;

  sp_cmdlist_low = (uint8_t)((uint16_t)&sp_cmdlist & 0x00FF);
  sp_cmdlist_high = (uint8_t)((uint16_t)&sp_cmdlist >> 8) & 0xFF;

  // store cmd list
  __asm__ volatile ("lda #%b", SP_CMD_READ);
  __asm__ volatile ("sta %g", spCmd); // store status command #
  __asm__ volatile ("lda %v", sp_cmdlist_low);
  __asm__ volatile ("sta %g", spCmdListLow); // store status command #
  __asm__ volatile ("lda %v", sp_cmdlist_high);
  __asm__ volatile ("sta %g", spCmdListHigh); // store status command #

  __asm__ volatile ("jsr $C50D"); // to do - find entry point and used it instead of hardcoded address
spCmd:
  __asm__ volatile ("nop");
spCmdListLow:
  __asm__ volatile ("nop");
spCmdListHigh:
  __asm__ volatile ("nop");
  __asm__ volatile ("sta %v", sp_err);
  sp_error = sp_err;
  return sp_err;
}

WRITE

The WRITE command can be used, for example, with the Network Device, to write a number of bytes to a remote network host (by placing them in the transmit buffer)

The main difference between this command (as well as the preceeding READ command) and the STATUS/CONTROL commands is that a buffer length is passed as part of the command list.

Asm Implementation

WRITECODE = $09

	jsr DISPATCH
	DFB #WRITECODE
	DW  CMLIST
	BCS ERROR

	; Everything ok
	CLC
	RTS
	
ERROR	; not okay
	RTS
	
CMLIST: DFB	#$04		; write has 4 params	
	DFB	#DEST           ; Destination device #
	DW	BUFFER          ; lo and hi bytes for buffer address
        DW      LEN             ; # of bytes to read into buffer

C Implementation

int8_t sp_write(uint8_t dest, uint16_t len)
{
  sp_error = 0;
  // sp_dest = 5; // need to search
  // build the command list
  sp_cmdlist[0] = SP_WRITE_PARAM_COUNT;
  sp_cmdlist[1] = dest; // set before calling sp_status();
  sp_cmdlist[2] = (uint8_t)((uint16_t)&sp_payload & 0x00FF);
  sp_cmdlist[3] = (uint8_t)((uint16_t)&sp_payload >> 8) & 0xFF;
  sp_cmdlist[4] = len & 0xFF;
  sp_cmdlist[5] = len >> 8;

  sp_cmdlist_low = (uint8_t)((uint16_t)&sp_cmdlist & 0x00FF);
  sp_cmdlist_high = (uint8_t)((uint16_t)&sp_cmdlist >> 8) & 0xFF;

  // store cmd list
  __asm__ volatile ("lda #%b", SP_CMD_WRITE);
  __asm__ volatile ("sta %g", spCmd); // store status command #
  __asm__ volatile ("lda %v", sp_cmdlist_low);
  __asm__ volatile ("sta %g", spCmdListLow); // store status command #
  __asm__ volatile ("lda %v", sp_cmdlist_high);
  __asm__ volatile ("sta %g", spCmdListHigh); // store status command #

  __asm__ volatile ("jsr $C50D"); // to do - find entry point and used it instead of hardcoded address
spCmd:
  __asm__ volatile ("nop");
spCmdListLow:
  __asm__ volatile ("nop");
spCmdListHigh:
  __asm__ volatile ("nop");
  __asm__ volatile ("sta %v", sp_err);
  sp_error = sp_err;
  return sp_err;
}

SmartPort functions In a C context

You can see all of these functions as part of the 'netcat' program: https://github.com/FujiNetWIFI/fujinet-apps/tree/master/netcat/apple2

SmartPort functions In an Assembly context

You can see all of these functions as part of the 'apple ampersand' program: https://github.com/FujiNetWIFI/fujinet-nhandler/tree/master/apple2

What commands?

Now that you've seen how to issue various SmartPort commands, the following sections will show a table reference of commands:

Clone this wiki locally