Article # 149, added by Geoworks, historical record
| first | previous | index | next | last |

PCCom protocol (for OmniGo)




This info is specific to the PCCom protocol used by the OmniGo 100
Transfer application.  It is current as of Februrary 1996.
The following commands should work on future versions of the PCCom
library.  However future versions may contain extra commands not
listed below.

The PCCom Library utilizes a simple file transfer protocol.
Basically, send  to signal the beginning of a command.  Then send
the two character command plus any parameters.  Terminate the command with
'!'.

Here is a list of the current PCCom commands:

AD! 
	Available drives.  Displays all the drives known to the system with
	their disk labels.

AK(On|Off)!
	Turns acknowledgement on or off.  If ack is on, whenever a 
	transaction is successfully complete, the host will receive
	ACK and display "Ack Received."; if a transaction is
	unsuccessful, the host will receive NAK and display
	"Nak Recieved."
	
	By omitting On|Off arg, you can get the current status of 
	acknowledgement.  This can be used to "ping" the remote unit.

CD!
	change to the specified drive or directory

CP!!
	Make a copy of the file named  and name the copy 

EB(On|Off)!
	Turns echo back on or off.  If echo back is on, all the output to the
	server side is echoed back to client.  If argument is omitted, displays
	the current status of echo back.  On/off string is case insensitive.

EX
	Exit.  Tells the remove PCCom to close the serial connection.

FS:!
	Displays the amount of free space in the specified driver.  If path is
	omitted, displays free space on current driver.

LL!	
	Long listing of files. LL command displays the following in addition to
	normal LS command:
	  DOS attributes, a: archive
			  d: sub directory
			  v: volume file
			  s: system
			  h: hidden
			  r: read only
	  GEOS name, 	  32 char file name
	  release number,  
	  creator,
	  token,
	  protocol number,

	Creator and other geode token are displayed in the following format:
		"4-letter token"[Manufacturer's ID number]

LM!
	Medium listing of files. This is LL without creator, geode token, and
	protocol number.  As you will notice, LL will display 2 lines of info
	per file.  LM displays one line per file.

LS!
	List the directory contents.

MD!
	Create a directory with the given name.

MV!!
	rename the file from  to 

RD!
	Remove the directory with the given name.

RF!
	Delete the file of the given name.

XF
	Transfer a file.  This is fairly involved.  The following
	describes the transfer protocol.

  These constants will be used in the explanation below.

  ACK		equ	0		; everything OK
  NAK		equ	1		; not OK, try again
  NAK_QUIT	equ	2		; not OK, give up
  SYNC		equ	0ffh

  BLOCK_START		equ	01h
  BLOCK_END		equ	02h
  BLOCK_QUOTE		equ	03h

  There can be at most 1K of data per block, and since BLOCK_START,
  BLOCK_END, and BLOCK_QUOTE are reserved values, any data with one of 
  these values must be "quoted".  

  The CRC value for a block of data is a word calculated using the
  algorithm described below, in CalcCRC().

  ------------------------------------------------------------------------
  SENDING A FILE
  ------------------------------------------------------------------------

  Sending a file to the remote machine involves the steps below. A file 
  may be sent by any program that can access the serial port.

  Note that if the block is not received correctly the first time,
  the receiver will give up after 3 more attempts to receive it.

  If you want to make the sending of the filename more robust, you can
  send it in the first data block, which contains this data:

  	!PCCom File Transfer Filename Block! 
	

  Calculate the CRC for this block in the usual manner, but send CRC+1.
  This special block should only be re-sent 1 time if it is not successfully
  received, instead of the normal 3 times.
  

send XF<0x1>				(alert PCCom a file is coming )
send      	    	(destination file name)
read byte
wait for SYNC
send 
while (not EOF) {
  resend:
    if (first block) {	    	    	    	(this part is optional)
    	send BLOCK_START
	send the special block 
    	send BLOCK_END
	send CRC + 1
    } else {
    	send BLOCK_START 
	while (more bytes in block) {
    	    get next byte in block
	    if (byte == BLOCK_START, BLOCK_END, or BLOCK_QUOTE) {
	    	send BLOCK_QUOTE
		send (byte + BLOCK_QUOTE)
	    }
	    else
	    	send byte
	    endif
	}
	send BLOCK_END 
	send CRC (word value, send low byte first)
	read byte
	if (byte == NAK) 
	    goto resend
	elif (byte != SYNC) 
	    quit
	endif
	read next block from file
    }	
send byte 0
send byte 0
wait for ACK

  ------------------------------------------------------------------------
  RETRIEVING A FILE
  ------------------------------------------------------------------------

  Retrieving a file from a machine running PCCom is straightforward
  and uses the same file transfer protocol shown above for sending a
  file. The sequence of commands is different, however, and is listed
  below.  There is no special first block for file retrieval analagous
  to that for file send.

  Note that if the PCCom library does not get a SYNC after sending a
  block of data, it will resend it 3 more times before giving up.

send XF<0x4>			    (alert PCCom you want a file)
send      	    (source file name, can contain
                                                  wildcard characters)
wait for SYNC 	    	    	    	    (PCCom must acknowledge receipt
                                                  of the file name)
while (read byte == SYNC)    	    	    (wait for PCCom to find next file)
  read 	    (the destination file name)
  send SYNC
  read filesize (dword)
  while (filesize > 0) {
    read byte
    if (byte = BLOCK_START) {
    	while (read byte != BLOCK_END) {
	    if (byte == BLOCK_QUOTE) {
	    	read byte
	    	byte = byte - BLOCK_QUOTE
	    }
	    write byte to output buffer
	    filesize = filesize - 1
	}
	read CRC
	if (CRC = CalcCRC(buffer))
	    send SYNC
	    write buffer to destination file
	else
	    send NAK
	endif
    else 
        send NAK
    endif
    }
  read checksum (word)
  if (checksum == 0) 
    send ACK
  else
    send NAK
  }



 *---------------------------------------------------------------------*
 		CalcCRC						
 *---------------------------------------------------------------------*
  SUMMARY:	Calculate the CRC on a block of data.
  PASS:		char *buf		Pointer to the data buffer
 		short size		Size of the data buffer
 		short checksum		Previous checksum (0 at first)
  RETURN:	CRC value (2 bytes)
 *---------------------------------------------------------------------*

short	crcTable[] = { 
    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
    0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
    0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
    0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
    0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
    0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
    0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
    0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
    0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
    0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
    0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
    0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
    0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
    0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
    0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
    0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
    0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
    0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
    0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
    0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
    0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
    0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
    0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
    0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
    0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
    0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
    0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
    0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
    0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
    0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
    0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
    0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};

unsigned short		IncCRC(unsigned short crc, char c){
    return ((crc << 8) ^ crcTable[((crc >> 8) ^ c) & 0xff]);
}

short		CalcCRC(char *buf, short size, short checksum){
    for (;size >= 0; size--){
 	checksum = IncCRC(checksum, *buf++);
    }
    return checksum;
}