10 REM > USBtoDsk45 v0.45 28-Dec-2018 J.G.Harston
   20 REM v0.20 - Manually sends data 256*max% bytes at a time
   30 REM v0.30 - Uses machine code USB transfer, dynamically skips disk errors
   40 REM v0.40 - Copies DFS/ADFS/LVFS, allows size to be overridden
   50 REM v0.41 - Selects source FS by command, keeps FS selected for transfer
   60 REM v0.42 05-Nov-2017 Faster step back from errors, steps up from success
   70 REM v0.43 31-May-2018 SEK for each USB access
   80 REM v0.44 04-Jun-2018 Rewrote from DiskToUSB
   81 REM v0.45 28-Dec-2018 Corrected parameters to FNdisk
   90 :
  100 IFFNfx(0,1)<6:IFFNfx(130,0)=&FFFF ELSE PRINT"Must run on BBC I/O processor":END
  110 PRINT "Copy USB disk image to whole disk"
  120 PRINT "Equivalent to: *IMPORT -X<drv> usbfile"
  130 PRINT "***WARNING*** THIS WILL COMPLETELY OVERWRITE YOUR DISK"'
  140 max%=(HIMEM-LOMEM-2048)DIV256:oldfs%=FNfs:IF max%<2:MODE &87:RUN
  150 DIM ctrl% 31,data% 256*max%-1:X%=ctrl%:Y%=X%DIV256
  160 PROCusb_Init:ON ERROR REPORT:PROCend:END
  170 :
  180 INPUTLINE"Source USB image file: "in$
  190 INPUTLINE"Dest. filing system:   "type$
  200 INPUTLINE"Dest. drive:           "drv%
  210 OSCLI type$:thisfs%=FNfs
  220 REPEAT:READ fs$,fn$,A$,retry%
  230 UNTIL fs$="*" OR fs$=STR$thisfs%
  240 IF fs$="*":PRINT "Unsupported filing system":PROColdfs:END
  250 DATA 4,disk,7F,3, 8,adfs,72,1, 10,adfs,62,1, 16,hadfs,5A,1, 29,disk,77,1
  260 REM     DISK         ADFS         LVFS          HADFS           RAM
  270 DATA *,*,*,*
  280 :
  290 osw%=EVAL("&"+A$):dsize%=FNsize
  300 PRINT"Total disk sectors (&";~dsize%;"): &";:INPUT""A$:IFA$<>"":dsize%=EVAL("&"+A$)
  310 IFdsize%>&FFF:INPUT"This is a hard drive - continue? "A$:A$=CHR$(ASCA$AND&DF):IF A$<>"Y":PROCend:END
  320 ON ERROR REPORT:IF INKEY-1:PROCend:END ELSE PROCabort:END
  330 PROCusb_Sync:PROCusb_Flush
  340 A%=FNusb_Cmd("IPA"):PROCusb_Flush:VDU13
  350 IF FNusb_Cmd("IPA"):PROCabort:END
  360 IF FNusb_Cmd("OPR "+in$):PROCabort:END
  370 PROCusb_Sync
  380 :
  390 sect%=0:thisnum%=max%
  400 REPEAT
  410   num%=max%:IF sect%+num%>dsize%:num%=dsize%-sect%
  420   IF thisnum%<num%:num%=thisnum%
  430   VDU13:PRINT"Reading   ";FNh0(sect%,6);"+";FNh0(thisnum%,2);
  440   IF FNusb_Cmd("SEK "+STR$(sect%*256)):PROCabort:END
  450   PROCusb_WrStr("RDF "+STR$(thisnum%*256)+CHR$13)
  460   A%=thisnum%:CALL usb_RdData
  470   thisnum%=FNwrite(sect%,thisnum%)
  480   sect%=sect%+thisnum%
  490   IF num%=thisnum%:thisnum%=thisnum%*2:IF thisnum%>max%:thisnum%=max%
  500 UNTILsect%>=dsize%
  510 :
  520 VDU13:PRINT"Closing";SPC14;
  530 PROCusb_Sync:PROCusb_Flush
  540 IF FNusb_Cmd("CLF "+in$):PROCabort
  550 PROCusb_Cmd("SUD")
  560 PROCusb_Sync
  570 PROColdfs
  580 VDU13:PRINT"Done";SPC17
  590 END
  600 :
  610 DEFPROColdfs
  620 IFoldfs%:OSCLI"FX143,18,"+STR$oldfs%:oldfs%=0
  630 ENDPROC
  640 :
  650 DEFPROCabort
  660 PROCusb_Flush:PROCusb_Cmd("CLF "+in$)
  670 PROCusb_Cmd("SUD"):PROCusb_Flush
  680 PROCend:ENDPROC
  690 :
  700 DEFPROCend
  710 PROColdfs:PRINT
  720 ENDPROC
  730 :
  740 DEFFNwrite(sect%,num%)
  750 REPEAT
  760   try%=retry%
  770   REPEAT
  780     VDU13:PRINT"Writing ";FNh0(drv%,1);":";FNh0(sect%,6);"+";FNh0(num%,2);
  790     err%=FNattempt(num%):try%=try%-1
  800   UNTIL try%<1 OR err%=0
  810   IF err%:num%=(num%+2)DIV4
  820 UNTIL err%=0 OR num%<1
  830 =num%-(num%<1)
  840 :
  850 DEFFNattempt(num%)
  860 IFfn$="disk":err%=FNdisk(data%,&4B,drv%,sect%DIV10,sect%MOD10,num%,osw%,1)
  870 IFfn$="adfs":err%=FNadfs(data%,10,drv%,sect%,num%,osw%)
  880 IFfn$="hadfs":err%=FNhadfs(data%,&81,drv%,sect%,num%,osw%)
  890 VDU13:A%=FNdisk_err(err%,drv%,sect%,num%)
  900 =err%
  910 :
  920 DEFFNsize
  930 LOCAL size%
  940 IFfn$="disk":sect%=1:err%=FNdisk(data%,&53,drv%,0,1,1,osw%,1):size%=data%?7+256*(data%?6 AND 3)
  950 IFfn$="adfs":sect%=0:err%=FNadfs(data%,8,drv%,0,1,osw%):size%=data%!&FC AND &FFFFFF
  960 IFfn$="hadfs":sect%=&46:err%=FNhadfs(data%,&80,drv%,&46,1,osw%):size%=data%!28 AND &FFFFFF
  970 VDU13:A%=FNdisk_err(err%,drv%,sect%,1)
  980 =size%
  990 :
 1000 REM Disk access routines
 1010 REM ====================
 1020 DEFFNfs:LOCALA%,E%,Y%:=(USR&FFDA)AND&FF
 1030 DEFFNdisk(addr%,cmd%,drv%,trk%,sec%,num%,osw%,den%):LOCALn%
 1040 REPEAT:n%=num%:IFsec%+n%>10:n%=10-sec%
 1050   REPEAT:X%?0=drv%+den%*24+8+2*(trk%DIV80):X%!1=addr%:X%?5=3-7*(cmd%>127)
 1060     X%?6=cmd%:X%?7=trk%MOD80:X%?8=sec%:X%!9=n%OR&1E20:A%=osw%:CALL&FFF1
 1070   A%=X%?(7+X%?5):UNTILA%<>&10:addr%=addr%+n%*256:num%=num%-n%:sec%=(sec%+n%)MOD10:trk%=trk%+1
 1080 UNTILA%<>0ORnum%<1:=A%
 1090 DEFFNadfs(addr%,cmd%,drv%,sect%,num%,osw%)
 1100 X%?0=1:X%!1=addr%:X%?5=cmd%:X%?6=drv%*32+((sect%AND&1F0000)DIV65536)
 1110 X%?7=((sect%AND&FF00)DIV256):X%?8=sect%:X%!9=num%:X%!11=0
 1120 A%=osw%:CALL&FFF1:=?X%
 1130 DEFFNhadfs(addr%,cmd%,drv%,sect%,num%,osw%)
 1140 !X%=&600:X%!2=addr%:X%!6=sect%:X%?9=drv%:X%?10=num%:X%?11=cmd%
 1150 A%=osw%:CALL&FFF1:=X%?12
 1160 DEFFNdisk_err(A%,D%,S%,N%)
 1170 IFA%:PRINT"Disk error ";FNh0(A%,2);" at ";FNh0(D%,1);":";FNh0(S%,6);"+";FNh0(N%,2)
 1180 =A%
 1190 :
 1200 REM I/O routines
 1210 REM ============
 1220 DEFFNh0(A%,N%):=RIGHT$("00000000"+STR$~A%,N%)
 1230 DEFFNfx(A%,X%):LOCAL Y%:Y%=X%DIV256:=((USR&FFF4)AND&FFFF00)DIV256
 1240 :
 1250 REM USB access routines
 1260 REM ===================
 1270 DEFPROCusb_Sync:REPEATA%=?usb_D:UNTIL(?usb_S AND 128):ENDPROC
 1280 DEFPROCusb_Flush:IF(?usb_S AND 128):ENDPROC
 1290 PRINT'"Flushing USB";:REPEAT:REPEATA%=?usb_D:UNTIL(?usb_S AND 128)
 1300 A%=TIME+20:REPEATUNTILTIME>A%:UNTIL(?usb_S AND 128):ENDPROC
 1310 DEFFNusb_Err:IF?usb_result%=13 OR usb_result%?1=ASC":":=0 ELSE PRINT"USB Error: "$usb_result%:=TRUE
 1320 DEFPROCusb_Cmd(A$):PROCusb_Sync:PROCusb_WrStr(A$+CHR$13):PROCusb_RdStr:ENDPROC
 1330 DEFFNusb_Cmd(A$):PROCusb_Cmd(A$):=FNusb_Err
 1340 DEFPROCusb_WrStr(A$):FOR A%=1 TO LEN A$:REPEATUNTIL(?usb_S AND 64)=0
 1350 ?usb_D=ASCMID$(A$,A%,1):NEXT:ENDPROC
 1360 DEFPROCusb_RdStr:A%=usb_result%-1:REPEATA%=A%+1:?A%=FNusb_Rd:UNTIL?A%=13:ENDPROC
 1370 DEFPROCusb_Wr(A%):REPEATUNTIL(?usb_S AND 64)=0:?usb_D=A%:ENDPROC
 1380 DEFFNusb_Rd:REPEATUNTIL(?usb_S AND 128)=0:=?usb_D
 1390 DEFPROCusb_Init
 1400 usb_D=&FCF8:usb_S=&FCF9
 1410 usb_result%=usb_result%:IF usb_result%:ENDPROC
 1420 DIM usb_result% 63,mc% 99
 1430 FOR P=0 TO 1:P%=mc%:[OPT P*2
 1440   .usb_RdData
 1450   TAY:LDA #data% AND 255:STA usb_RdLp+4
 1460   LDA #data% DIV 256:STA usb_RdLp+5:LDX #0
 1470   .usb_RdLp:JSR usb_Rd:STA data%,X:INX:BNE usb_RdLp
 1480   INC usb_RdLp+5:DEY:BNE usb_RdLp:RTS
 1490   .usb_Rd:BIT usb_S:BPL usb_Rd2:BIT &FF:BPL usb_Rd
 1500   .usb_Rd2:LDA usb_D:RTS
 1510   .usb_WrData
 1520   TAY:LDA #data% AND 255:STA usb_WrLp+1
 1530   LDA #data% DIV 256:STA usb_WrLp+2:LDX #0
 1540   .usb_WrLp:LDA data%,X:JSR usb_Wr
 1550   .usb_WrLp2:LDA usb_D:BIT usb_S:BPL usb_WrLp2
 1560   INX:BNE usb_WrLp
 1570   INC usb_WrLp+2:DEY:BNE usb_WrLp:RTS
 1580   .usb_Wr:BIT usb_S:BVC usb_Wr2:BIT &FF:BPL usb_Wr
 1590   .usb_Wr2:STA usb_D:RTS
 1600 ]NEXT:ENDPROC
 1610 :