   10 REM *************************************************************

   20 REM * File Transfer Program                                     *

   30 REM * BBC <-> Risc PC                                           *

   40 REM * By Paul Theobald                                          *

   50 REM *************************************************************

   60 

   70 REM Set up error handler

   80 ON ERROR PROCreset:REPORT:PRINT " at line ";ERL:END

   90 

  100 REM Main loop

  110 PROCinit

  120 REPEAT

  130 PRINT "(S)end, (R)eceive, (*) command, (Q)uit?";

  140 REPEAT

  150 option$ = GET$

  160 IF option$ <> "*" THEN option$=CHR$(ASC(option$) AND &DF)

  170 UNTIL option$="S" OR option$="R" OR option$="*" OR option$="Q"

  180 PRINT option$

  190 IF option$ = "S" THEN PROCsend

  200 IF option$ = "R" THEN PROCreceive

  210 IF option$ = "*" THEN INPUT "*" command$:OSCLI(command$)

  220 PROCreset

  221 UNTIL option$ = "Q"

  240 END

  250 

  260 REM *************************************************************

  270 REM * Initialise variables                                      *

  280 REM *************************************************************

  290 DEF PROCinit

  300 baud_rate%        = 7     : REM 9600 baud transfer rate

  310 file_name_length% = 7     : REM Max size of file name for BBC DFS

  320 file_size_length% = 4     : REM Max size of file is &FFFFFFFF

  330 osbyte%           = &FFF4 : REM OSBYTE call address

  340 sync_text$ = "BBC<->RPC"  : REM Text indicating start of transfer 

  350 ENDPROC

  360 

  370 REM *************************************************************

  380 REM * Receive a file                                            *

  390 REM *************************************************************

  400 DEF PROCreceive

  410 PRINT "Waiting for remote end..."

  420 REM Set receive baud rate

  430 A% = 7:X% = baud_rate%:CALL osbyte%

  440 REM Open the serial port for input

  450 *FX 2,1

  460 REM Flush the serial port input buffer

  470 *FX 21,1

  480 REM Read in the sync text to check we're receiving valid data

  490 this_text$ = FNread_string(LEN(sync_text$))

  500 IF this_text$ <> sync_text$ THEN PRINT "Invalid data received, please try again.":ENDPROC

  510 REM Read in the file name

  520 file_name$ = FNread_string(file_name_length%)

  530 REM Read in the file length

  540 file_size% = FNread_integer(file_size_length%)

  550 REM Display file details

  560 PRINT "Receiving:"

  570 PRINT "File name   = ";file_name$

  580 PRINT "File length = ";file_size%

  590 REM Create a local file of the same name

  600 file_handle% = OPENOUT(file_name$)

  610 REM Copy in the file contents

  620 PROCread_data(file_handle%, file_size%)

  630 REM Close the file

  640 CLOSE#file_handle%

  650 REM Close the serial port and reselect keyboard input

  660 *FX 2,0

  670 ENDPROC

  680 

  690 REM *************************************************************

  700 REM * Send a file                                               *

  710 REM *************************************************************

  720 DEF PROCsend

  730 REM Input a file name and truncate/lengthen to standard length

  740 INPUT"Filename: " file_name$

  750 file_name$ = LEFT$(file_name$, file_name_length%)

  760 file_name$ = file_name$+STRING$(file_name_length%-LEN(file_name$)," ")

  770 REM Open the file or report an error if we can't

  780 file_handle% = OPENIN(file_name$)

  790 IF file_handle% = 0 THEN PRINT "Can't open file """;file_name$;""", please try again.":ENDPROC

  800 REM Find the file size

  810 file_size% = EXT#file_handle%

  820 REM Display file details

  830 PRINT "Sending:"

  840 PRINT "File name   = ";file_name$

  850 PRINT "File length = ";file_size%

  860 REM Set transmit baud rate

  870 A% = 8:X% = baud_rate%:CALL osbyte%

  880 REM Select the serial port for output

  890 *FX 3,3

  900 REM Flush the serial port output buffer

  910 *FX 21,2

  920 REM Send the sync text to indicate start of transfer

  930 PROCwrite_string(sync_text$, LEN(sync_text$))

  960 REM Send the file name

  970 PROCwrite_string(file_name$, file_name_length%)

  980 REM Send the file size

  990 PROCwrite_integer(file_size%,file_size_length%)

 1000 REM Copy out the file contents

 1010 PROCwrite_data(file_handle%, file_size%)

 1020 REM Close the file

 1030 CLOSE#file_handle%

 1040 REM Reselect VDU output

 1050 *FX 3,0

 1060 ENDPROC

 1070 

 1080 REM *************************************************************

 1090 REM * Reset configuration                                       *

 1100 REM *************************************************************

 1110 DEF PROCreset

 1120 REM Close the serial port and reselect keyboard input

 1130 *FX 2,0

 1140 REM Reselect VDU output

 1150 *FX 3,0

 1160 REM Close any remaining open files

 1170 CLOSE#0

 1180 ENDPROC

 1190 

 1200 REM *************************************************************

 1210 REM * Read in a string of specified length                      *

 1220 REM *************************************************************

 1230 DEF FNread_string(length%)

 1240 LOCAL loop%, string$

 1250 string$ = ""

 1260 FOR loop% = 1 TO length%

 1270 string$ = string$ + GET$

 1280 NEXT

 1290 = string$

 1300 

 1310 REM *************************************************************

 1320 REM * Read in an integer of specified length                    *

 1330 REM *************************************************************

 1340 DEF FNread_integer(length%)

 1350 LOCAL loop%, integer%

 1360 integer% = 0

 1370 FOR loop% = 1 TO length%

 1380 integer% = integer% * 256 + GET

 1390 NEXT

 1400 = integer%

 1410 

 1420 REM *************************************************************

 1430 REM * Read in data of specified length to a file                *

 1440 REM *************************************************************

 1450 DEF PROCread_data(file_handle%,length%)

 1460 LOCAL loop%

 1470 FOR loop% = 1 TO length%

 1480 BPUT#file_handle%,GET

 1490 NEXT

 1500 ENDPROC

 1510 

 1520 REM *************************************************************

 1530 REM * Write out a string of specified length                    *

 1540 REM *************************************************************

 1550 DEF PROCwrite_string(string$,length%)

 1560 PRINT LEFT$(string$,length%);

 1570 ENDPROC

 1580 

 1590 REM *************************************************************

 1600 REM * Write out an integer of specified length                  *

 1610 REM *************************************************************

 1620 DEF PROCwrite_integer(integer%,length%)

 1630 LOCAL loop%

 1640 FOR loop% = 1 TO length%

 1650 VDU integer% DIV (256 ^ (4-loop%)) MOD 256

 1660 NEXT

 1670 ENDPROC

 1680 

 1690 REM *************************************************************

 1700 REM * Write out data of specified length from a file            *

 1710 REM *************************************************************

 1720 DEF PROCwrite_data(file_handle%,length%)

 1730 LOCAL loop%

 1740 FOR loop% = 1 TO length%

 1750 VDU BGET#file_handle%

 1760 NEXT

 1770 ENDPROC

 1780 

 