// PrintSlot.bcpl - SLOT printing code

// errors 3100

get "PDInternals.d"

//outgoing procedures
external
[
PSlot
SLOTInit
]

//incoming procedures
external
[
//OS
Zero;MoveBlock;StartIO
//PRINT
PrintError
//PRINTDISK
PrintDiskInit
PrintDiskRead
PrintDiskCheck
PrintDiskStop
]

//incoming statics
external
[
invertMode
ScanMarginAdjust//Adjustments to add to user input
BitMarginAdjust
SLOTScanLength//To give to 3100 interface
SLOTDouble
SLOTTimeOut
]

// S L O T Definitions:

structure RS [
blankbyte
Spare2bit
Waitbit//complement signal
PaperJambit//complement signal
AddPaperbit//complement signal
SelectBbit
Readybit
LineSyncbit
PageSync bit//complement signal
]
manifest
[
NormalizeStatus = #161 //use to uncomplement above signals
readyMask = #164
readyValue = #4
]

structure SCB [
blankbit14
COMbit2//Command Beam On#0
//Command Status#1
//Command Reset#2
//Command Print#3
BlowUpbit// Make-one-bit-into-four; true select option
LastPagebit// Marks this command as the last page if true
invertbit// inverts the page
bitsPerLinebit13// Servo Count for number of bits per line
bitMarginword// Bottom Margin (bits)
scanLineWcword// Double Word Count
scanMarginword// Left Margin (bits before print in portrait)
scansPerPageword// Total number of Scan Lines per page
bufferPtrword// Print Buffer Base Address (first loc.)
scanLineWcIncword// Print Buffer Scan Line Increment
scansPerBuffword// Print-mode Buffer Length
currentBuffword// Current Buffer Address
currentLineword// Current Scan Address
SWword = @RS// Return Status Word
]


manifest
[
lSCB = size SCB/16
SCBloc=#720
slotSIObit=4

BeamOnCommand=0
StatusCommand=1
ResetCommand=2
PrintCommand=3
]

manifest
[
RTC=#430
Active=#453
parityInterruptBit=1
WakeupsWaiting=#452
]

let SLOTInit() be
[
SLOTCommand(ResetCommand)
SLOTCommand(BeamOnCommand)
let FailCode=SLOTStatus()
if FailCode eq 0 then return
PrintError(FailCode)
] repeat

and PSlot(pg, last, firstAdr, lastAdr) be
[
//Disable parity interrupts
let oldActive=@Active
@Active=oldActive&(not parityInterruptBit)

[Retry
let bandWidth=pg>>PageG.BandWidth
let numBands=pg>>PageG.LastBand-pg>>PageG.FirstBand+1
let scanLength=pg>>PageG.BitWc*16

//Initialize band buffers and fill them
let FirstBuf=nil
let nBuffers=PrintDiskInit(pg, firstAdr, lastAdr, lv FirstBuf)
let nR,nC=nil,nil
for i=1 to nBuffers do nR=PrintDiskRead()
nC=PrintDiskCheck() repeatuntil nC eq nR

let scb=vec lSCB
scb=SetSCB(scb)
scb>>SCB.COM = PrintCommand
scb>>SCB.LastPage = last
scb>>SCB.bitMargin = pg>>PageG.BitMargin + BitMarginAdjust
scb>>SCB.scanLineWc = pg>>PageG.BitWc/2
scb>>SCB.scanMargin = pg>>PageG.FirstBand*bandWidth + ScanMarginAdjust
scb>>SCB.scansPerPage = numBands*bandWidth
let currentBuff = FirstBuf
scb>>SCB.bufferPtr = currentBuff
scb>>SCB.currentBuff = currentBuff
scb>>SCB.scanLineWcInc = pg>>PageG.BitWc
scb>>SCB.scansPerBuff = bandWidth
@SCBloc = scb

SlotStart:
let startTime=@RTC
let PrintFail=0
StartIO(slotSIObit)
[
if scb>>SCB.currentBuff ne currentBuff then //started next buff
[
let onR=nR
nR=PrintDiskRead()
if onR ne nR then currentBuff=currentBuff!-1
]
nC=PrintDiskCheck()
if nC-nR ge nBuffers-1 then PrintFail=3105//disk behind
if scb>>SCB.SW then break
if @RTC-startTime ge SLOTTimeOut*27 then [ PrintFail=3106; break ]
] repeat

PrintDiskStop()

let FailCode=SLOTStatus()
if last then [ MsWait(6000); SLOTCommand(ResetCommand) ]
if (PrintFail%FailCode) eq 0 then break//Successful printing

// Error while printing this page. Reset and try again
SLOTCommand(ResetCommand)
PrintError((FailCode? FailCode,PrintFail))
SLOTInit()//Fuss until printer is ready
]Retry repeat

@WakeupsWaiting=@WakeupsWaiting&(not parityInterruptBit)
@Active=oldActive
]


// SLOT Procedures

// Test status of SLOT card and return a failure code (0= ready)

and SLOTStatus() = valof
[
let scb=vec lSCB
scb=SetSCB(scb)
scb>>SCB.COM = StatusCommand
scb>>SCB.SW = NormalizeStatus
@SCBloc = scb
StartIO(slotSIObit)
MsWait(20)//give microcode long enough to see the new command
if scb>>SCB.SW eq NormalizeStatus then PrintError(3100)
scb>>SCB.SW = scb>>SCB.SW xor NormalizeStatus
if (scb>>SCB.SW & readyMask) eq readyValue then resultis 0
if scb>>SCB.Wait then resultis 3101
if scb>>SCB.PaperJam then resultis 3102
if scb>>SCB.AddPaper then resultis 3103
resultis 3104
]

// Issue a command to the SLOT

and SLOTCommand(comm) be
[
let scb=vec lSCB
scb=SetSCB(scb)
scb>>SCB.COM=comm
@ SCBloc = scb
StartIO(slotSIObit)
for i = 0 to 30000 do if scb>>SCB.SW then break
if scb>>SCB.SW eq 0 then PrintError(3100)//No response
if comm eq BeamOnCommand then MsWait(1000)
]

and SetSCB(scb) = valof
[
scb=(scb+1)&(-2)
Zero(scb, lSCB)
scb>>SCB.invert = invertMode
scb>>SCB.bitsPerLine=SLOTScanLength
scb>>SCB.BlowUp=SLOTDouble
resultis scb
]

and MsWait(ms) be
[
let startTime = @RTC
until @RTC-startTime ge ms/37 do [ ]
]