-- PDDeviceDriverImpl.mesa
-- Copyright (C) 1984, Xerox Corporation.  All rights reserved.
-- Jim Gasbarro  2-Apr-84 19:12:54
-- Michael Plass, September 27, 1984 8:34:22 am PDT
-- Jim Gasbarro  10-Dec-84 14:02:07

DIRECTORY
    ColorVersatecDriver,
    ColorVersatecUtils,
    DicentraDiskDriver,
    PDDeviceDriver,
    PDQueue,
    Process;
    
PDDeviceDriverImpl: MONITOR 
    IMPORTS ColorVersatecDriver, ColorVersatecUtils, DicentraDiskDriver, PDQueue, Process
    EXPORTS PDDeviceDriver
    = BEGIN
    
OPEN PDDeviceDriver;

diskCmdOffset: CARDINAL = 32;
versatecCmdOffset: CARDINAL = 0;
bandOffset: LONG CARDINAL = 64;

cylindersPerPartition: CARDINAL = 200;
queueStateCylinder: CARDINAL = (ORD[Color.LAST] + 1) * cylindersPerPartition;
bpi: CARDINAL = ColorVersatecDriver.bpi;
wordsPerScan: CARDINAL = ColorVersatecDriver.wordsPerScan;
scansPerBand: CARDINAL = ColorVersatecDriver.scansPerBand;
wordsPerBand: LONG CARDINAL = ColorVersatecDriver.wordsPerBand;
sectorsPerBand: CARDINAL = ColorVersatecDriver.sectorsPerBand;
tracksPerCylinder: CARDINAL = DicentraDiskDriver.tracksPerCylinder;
sectorsPerTrack: CARDINAL = DicentraDiskDriver.sectorsPerTrack;
cylindersPerSpindle: CARDINAL = DicentraDiskDriver.cylindersPerSpindle;
wordsPerSector: LONG CARDINAL = DicentraDiskDriver.wordsPerSector;
separatorBandOffset: LONG CARDINAL ← 0;
separatorBandColor: Color ← Black;

StoreBand: PUBLIC ENTRY PROC [sourcePtr: LONG POINTER TO WORD, destOffset: LONG CARDINAL, wordCount: LONG CARDINAL, color: Color ← Black, isSeparatorBand: BOOLEAN ← FALSE] =
    BEGIN
    c, h, s: CARDINAL;
    x, cylOffset, sectorOffset: LONG CARDINAL;
    ColorVersatecUtils.HyperStore[sourcePtr: sourcePtr, destOffset: bandOffset, wordCount: wordCount];
    cylOffset ← LOOPHOLE[color] * cylindersPerPartition;
    sectorOffset ← (destOffset / wordsPerSector);
    c ← CARDINAL[sectorOffset / (sectorsPerTrack * tracksPerCylinder) + cylOffset];
    h ← CARDINAL[(x ← (sectorOffset MOD (sectorsPerTrack * tracksPerCylinder))) / sectorsPerTrack];
    s ← CARDINAL[x MOD sectorsPerTrack];
    [] ← DicentraDiskDriver.Write[cylinder: c, head: h, sector: s, sectorCount: CARDINAL[wordCount / wordsPerSector], cmdOffset: diskCmdOffset, dataOffset: bandOffset];
    IF isSeparatorBand AND color=Black THEN {separatorBandOffset ← destOffset; separatorBandColor ← color};
    END;
    
PrintPage: PUBLIC PROC [passBands: ARRAY Color OF NAT, nBands: ARRAY Color OF NAT, fourColor: BOOLEAN ← FALSE, color: Color ← Black] RETURNS [SuccessCode] =
    BEGIN
    LongestColor: PROC [] RETURNS [CARDINAL] =
        BEGIN
        inches: CARDINAL ← 0;
        FOR c: Color IN Color DO
            inches ← MAX[inches, ((passBands[c] + nBands[c]) * scansPerBand) / bpi];
            ENDLOOP;
        RETURN[inches];
        END;

    IF NOT ColorVersatecDriver.VersatecIsOK[] THEN 
        BEGIN
        PDQueue.LogMessage["Versatec is Offline or out of paper.  Waiting..."];
        WHILE NOT ColorVersatecDriver.VersatecIsOK[] DO 
            Process.Pause[Process.SecondsToTicks[2]];
	    ENDLOOP;
        PDQueue.LogMessage["Versatec is Online"];
        END;
    
    IF fourColor THEN BEGIN
        ColorVersatecDriver.SetColorMode[inches: LongestColor[], mode: FirstPassOfColor, color: Black, cmdOffset: versatecCmdOffset];
        PrintLeadingTitleBlock[];
	SkipWS[bands: passBands[Black]-1];
        PrintColor[color: Black, bands: nBands[Black]];
        ColorVersatecDriver.Rewind[cmdOffset: versatecCmdOffset];
        
        ColorVersatecDriver.SetColorMode[inches: 0, mode: IntermediatePassOfColor, color: Cyan, cmdOffset: versatecCmdOffset];
        SkipWS[bands: passBands[Cyan]];
        PrintColor[color: Cyan, bands: nBands[Cyan]];
        ColorVersatecDriver.Rewind[cmdOffset: versatecCmdOffset];
        
        ColorVersatecDriver.SetColorMode[inches: 0, mode: IntermediatePassOfColor, color: Magenta, cmdOffset: versatecCmdOffset];
        SkipWS[bands: passBands[Magenta]];
        PrintColor[color: Magenta, bands: nBands[Magenta]];
        ColorVersatecDriver.Rewind[cmdOffset: versatecCmdOffset];
        
        ColorVersatecDriver.SetColorMode[inches: 0, mode: IntermediatePassOfColor, color: Yellow, cmdOffset: versatecCmdOffset];
        SkipWS[bands: passBands[Yellow]];
        PrintColor[color: Yellow, bands: nBands[Yellow]];
        ColorVersatecDriver.SendEOT[];
        END 
    ELSE BEGIN
        ColorVersatecDriver.SetColorMode[inches: 0, mode: SinglePassOfColor, color: color, cmdOffset: versatecCmdOffset];
        PrintLeadingTitleBlock[];
	SkipWS[bands: passBands[color]-1];
        PrintColor[color: color, bands: nBands[color]];
        ColorVersatecDriver.SendEOT[];
        END; 
    RETURN[ok];
    END;
    
PrintLeadingTitleBlock: PROC =
    BEGIN
    cylOffset: LONG CARDINAL ← LOOPHOLE[separatorBandColor] * cylindersPerPartition;
    sectorOffset: LONG CARDINAL ← separatorBandOffset/wordsPerSector;
    PrintColorBand[cylOffset, sectorOffset];
    END;
    
SkipWS: PROC[bands: CARDINAL] =
    BEGIN
    buffer: ARRAY [0..wordsPerScan) OF CARDINAL;
    p: POINTER ← @buffer;
    FOR i: CARDINAL IN [0..wordsPerScan) DO
        buffer[i] ← 0;
        ENDLOOP;
    FOR i: LONG CARDINAL IN [0..scansPerBand) DO
        ColorVersatecUtils.HyperStore[sourcePtr: p, destOffset: bandOffset + (i * LENGTH[buffer]), wordCount: LENGTH[buffer]];
        ENDLOOP;
    FOR i: CARDINAL IN [0..bands) DO
        ColorVersatecDriver.PlotBuffer[wordCount: wordsPerBand, hyperOffset: bandOffset];
        ENDLOOP;
    END;
    
PrintColorBand: ENTRY PROC [cylOffset: LONG CARDINAL, sectorOffset: LONG CARDINAL] =
    BEGIN
    c: CARDINAL ← CARDINAL[sectorOffset / (sectorsPerTrack * tracksPerCylinder) + cylOffset];
    x: LONG CARDINAL ← (sectorOffset MOD (sectorsPerTrack * tracksPerCylinder));
    h: CARDINAL ← CARDINAL[x / sectorsPerTrack];
    s: CARDINAL ← CARDINAL[x MOD sectorsPerTrack];
    [] ← DicentraDiskDriver.Read[cylinder: c, head: h, sector: s, sectorCount: sectorsPerBand, cmdOffset: diskCmdOffset, dataOffset: bandOffset];
    ColorVersatecDriver.PlotBuffer[wordCount: wordsPerBand, hyperOffset: bandOffset];
    END;
    
PrintColor: PROC [color: Color, bands: CARDINAL] =
    BEGIN
    cylOffset, sectorOffset: LONG CARDINAL;
    cylOffset ← LOOPHOLE[color] * cylindersPerPartition;
    FOR i: CARDINAL IN [0..bands) DO
        sectorOffset ← i * sectorsPerBand;
        PrintColorBand[cylOffset, sectorOffset];
        ENDLOOP;
    END;
    
ReadQueueState: ENTRY PROC [address: LONG POINTER, nwords: CARDINAL] =
    BEGIN
    [] ← DicentraDiskDriver.Read[cylinder: queueStateCylinder, head: 0, sector: 0, sectorCount: CARDINAL[(nwords+wordsPerSector-1)/wordsPerSector], cmdOffset: diskCmdOffset, dataOffset: bandOffset];
    ColorVersatecUtils.HyperRead[destPtr: address, sourceOffset: bandOffset, wordCount: nwords]
    END;
    
WriteQueueState: ENTRY PROC [address: LONG POINTER, nwords: CARDINAL] =
    BEGIN
    ColorVersatecUtils.HyperStore[sourcePtr: address, destOffset: bandOffset, wordCount: nwords];
    [] ← DicentraDiskDriver.Write[cylinder: queueStateCylinder, head: 0, sector: 0, sectorCount: CARDINAL[(nwords+wordsPerSector-1)/wordsPerSector], cmdOffset: diskCmdOffset, dataOffset: bandOffset];
    END;
    
DisplayBadStatusInMP: PUBLIC PROC [s: PrinterStatus] =
    BEGIN
    END;
    
GetStatus: PUBLIC PROC RETURNS [PrinterStatus] =
    BEGIN
    RETURN[noStatus];
    END;
    
Display: PUBLIC PROC [c0, c1: CHAR] =
    BEGIN
    END;
    
maxStateWords: CARDINAL ← 16*1024;
PDQueue.RegisterDisk[read: ReadQueueState, write: WriteQueueState, maxWords: maxStateWords];
    
END.