-- UserTeminalHeadDLion.mesa
-- Last Edited by: Taft, February 27, 1983 3:27 pm

DIRECTORY
  BitBlt USING [BBTable],
  DeviceCleanup USING [Await, Item, Reason],
  DisplayFace,
  DisplayFaceExtras USING [FieldRate, MonitorType],
  DLionInputOutput USING [firstReservedPage, IOPage, SetReservedMemoryUse],
  Environment USING [bitsPerWord, PageCount, PageNumber, wordsPerPage],
  HeadStartChain,
  Inline USING [BITOR, LongCOPY, LongDiv, LowHalf],
  KeyboardFace,
  KeyStations USING [KeyBits],
  MouseFace,
  PageMap USING [Assoc, flagsClean, RealPageNumber, Value, valueVacant],
  Process USING [GetPriority, MsecToTicks, Pause,
    Priority, priorityInterrupt, SetPriority],
  SoundGenerator USING [],
  Utilities USING [LongPointerFromPage, PageFromLongPointer];
  
UserTerminalHeadDLion: MONITOR
  IMPORTS
    DeviceCleanup, DLionInputOutput, Inline, RemainingHeads: HeadStartChain,
    PageMap, Process, Utilities
  EXPORTS DisplayFace, DisplayFaceExtras, HeadStartChain, KeyboardFace, MouseFace,
    SoundGenerator
  SHARES PageMap =
BEGIN OPEN Environment;

CSB: TYPE = MACHINE DEPENDENT RECORD [
  wakeups: WORD,	--vertical field wake up bits--
  off: BOOLEAN,
  unused: [0..7],
  invert, disconnect: BOOLEAN,
  line: CARDINAL [0..1024),
  border: RECORD [oddPairs, evenPairs: [0..400B)],
  cursor: DisplayFace.Point,                             --cursor location--
  map: DisplayFace.Cursor                                --cursor bit map--
  ];
csb: LONG POINTER TO CSB = LOOPHOLE[DLionInputOutput.IOPage + 353B];          --FFEB--

hasBuffer:      PUBLIC BOOLEAN ← TRUE;
width:          PUBLIC CARDINAL [0..32767] ← 1024;
height:         PUBLIC CARDINAL [0..32767] ← 808;
pagesForBitmap: PUBLIC Environment.PageCount ←
  (height*(width/bitsPerWord) + wordsPerPage - 1)/wordsPerPage;
  
-- DisplayFace Implementation

bitmapAddress: LONG POINTER ← NIL;

-- it should it be an ERROR to this if already connected
-- or to turn on/off a disconnected display
Connect: PUBLIC PROC [bitMap: PageNumber] =
  BEGIN
  rp: PageMap.RealPageNumber ← DLionInputOutput.firstReservedPage;
  DLionInputOutput.SetReservedMemoryUse[Display];
  csb.off ← TRUE;
  csb.disconnect ← FALSE;
  FOR vp: PageNumber IN [bitMap..bitMap + pagesForBitmap) DO
    PageMap.Assoc[vp, [FALSE, PageMap.flagsClean, rp]]; rp ← rp + 1 ENDLOOP;
  bitmapAddress ← Utilities.LongPointerFromPage[bitMap];
  bitmapAddress↑ ← 0;
  Inline.LongCOPY[
    from: bitmapAddress, nwords: pagesForBitmap*wordsPerPage - 1,
    to: bitmapAddress + 1];
  END;
  
Disconnect: PUBLIC PROC =
  BEGIN
  p: CARDINAL = Utilities.PageFromLongPointer[bitmapAddress];
  csb.off ← TRUE;
  csb.disconnect ← TRUE;
  IF bitmapAddress # NIL THEN
    FOR vp: PageNumber IN [p..p + pagesForBitmap) DO
	PageMap.Assoc[vp, PageMap.valueVacant] ENDLOOP;
  bitmapAddress ← NIL;
  DLionInputOutput.SetReservedMemoryUse[notBusy];
  END;
  
TurnOn:  PUBLIC PROC = {csb.off ← FALSE};

TurnOff: PUBLIC PROC = {csb.off ← TRUE};

GetBitBltTable: PUBLIC PROC RETURNS [BitBlt.BBTable] =
  BEGIN
  RETURN[
    [dst: [word: bitmapAddress, bit: 0], dstBpl: width,
     src: [word: bitmapAddress, bit: 0], srcDesc: [srcBpl[width]],
     width: width, height: height, flags: []]]
  END;
  
pixelsPerInch: PUBLIC CARDINAL ← 75;
refreshRate:   PUBLIC CARDINAL ← 39;
interlaced:    PUBLIC BOOLEAN ← TRUE;

SetBackground: PUBLIC PROC [b: DisplayFace.Background] =
  {csb.invert ← (b = black)};
  
hasBorder:     PUBLIC BOOLEAN ← TRUE;

SetBorderPattern: PUBLIC PROC [oddPairs, evenPairs: [0..377B]] =
  {csb.border ← [oddPairs, evenPairs]};
  
SetCursorPattern: PUBLIC PROC [p: DisplayFace.CursorPtr] = {csb.map ← p↑};

cursorPosition:  PUBLIC LONG POINTER TO DisplayFace.Point ← @csb.cursor;

globalStateSize: PUBLIC CARDINAL ← 0;

Initialize: PUBLIC PROC
  [globalState: DisplayFace.GlobalStatePtr, wakeVF: WORD] =
  BEGIN
  csb↑ ← CSB[
    wakeups: Inline.BITOR[wakeVF, csb.wakeups],
    off: NULL,
    unused: 0,
    invert: FALSE,
    disconnect: TRUE,
    line: 0,
    border: [210B, 42B],
    cursor: [0,0],
    map: ALL[0]];
  pSGCSB↑ ← SoundGeneratorCSB[
    busy: FALSE,
    command: NULL,
    period: 0];
  END;


  --  DisplayFaceExtras.

  monitorType: PUBLIC DisplayFaceExtras.MonitorType ← lf;

  SetFieldRate: PUBLIC PROCEDURE [rate: DisplayFaceExtras.FieldRate]
    RETURNS [ok: BOOLEAN] =
    {RETURN [rate=normalLF]};

  SetVerticalWaveforms: PUBLIC PROCEDURE [sync, visible, topBorder: CARDINAL]
    RETURNS [ok: BOOLEAN] =
    {RETURN [FALSE]};
  
-- KeyboardFace

keyboard: PUBLIC LONG POINTER TO READONLY KeyStations.KeyBits ←
  LOOPHOLE[DLionInputOutput.IOPage + 72B]; --FF3A
  
-- MouseFace

position: PUBLIC LONG POINTER TO READONLY MouseFace.Point ←
  LOOPHOLE[DLionInputOutput.IOPage + 70B]; --FF38
buttons:  PUBLIC LONG POINTER TO READONLY MouseFace.Buttons ←
  LOOPHOLE[keyboard]; --FF3A

setPosition: LONG POINTER TO MACHINE DEPENDENT RECORD [
  point(0:0..31): MouseFace.Point,
  busy(2:0..0): BOOLEAN,
  fill(2:1..15): [0..32767]] = LOOPHOLE[DLionInputOutput.IOPage + 133B];
    --FF5B
  
SetPosition: PUBLIC PROC [p: MouseFace.Point] =
  BEGIN
  DO
    LOOPHOLE[position, LONG POINTER TO MouseFace.Point]↑ ← p;
    IF ~setPosition.busy THEN EXIT
    ENDLOOP;
  setPosition.point ← p; setPosition.busy ← TRUE;
  END;


-- Sound Generator implementation

SoundGeneratorCSBOffset: CARDINAL = 136B; -- = 0101 1110 = 5EX

SoundGeneratorCSB: TYPE = MACHINE DEPENDENT RECORD [
  busy (0:0..0): BOOLEAN,
  command (0:1..15): MACHINE DEPENDENT {start (0), stop (1)},
  period (1:0..15): CARDINAL]; -- = 1843200/f, where f is frequency in Hz

pSGCSB: LONG POINTER TO SoundGeneratorCSB =
    DLionInputOutput.IOPage + SoundGeneratorCSBOffset;

-- Beep wants to run at interrupt priority, so it can accurately time
-- the duration of the beep.  Either interrupt priority should have an extra
-- state vector, or Beep's code (and local and global frame) must be pinned.

Beep: PUBLIC ENTRY PROC [frequency: CARDINAL, duration: CARDINAL] =
  BEGIN OPEN Inline;
  priority: Process.Priority = Process.GetPriority[];
  aborted: BOOLEAN ← FALSE;
  WHILE pSGCSB.busy DO ENDLOOP;
  Process.SetPriority[MAX[Process.priorityInterrupt, priority]];

  -- The MAX in the next statement prevents the LowHalf from overflowing.
  -- The period (in usec*1.8432) will be in the range [~29..63535].
  pSGCSB.period ← LowHalf[LongDiv[1843200, MAX[frequency, 29]]];
  pSGCSB.command ← start;
  pSGCSB.busy ← TRUE;
  WHILE pSGCSB.busy DO ENDLOOP;

  Process.Pause[Process.MsecToTicks[duration] !
    ABORTED => {aborted ← TRUE; CONTINUE}];

  pSGCSB.command ← stop;
  pSGCSB.busy ← TRUE;
  WHILE pSGCSB.busy DO ENDLOOP;

  Process.SetPriority[priority];
  IF aborted THEN RETURN WITH ERROR ABORTED;
  END;

  
-- Display/Raven/Sound Generator cleanup Proc

InitializeCleanup: PUBLIC PROC =
BEGIN OPEN DeviceCleanup;
csbState: CSB;
sgcsbState: SoundGeneratorCSB;
item: Item;
mousePos: MouseFace.Point;
DO
  reason: Reason = Await[@item];
  SELECT reason FROM
    turnOff, kill =>
      BEGIN
      csbState ← csb↑;
      csb.off ← TRUE;
      mousePos ← position↑;
      THROUGH [0..8000] DO --wait for field-- ENDLOOP;
      THROUGH [0..30000] DO IF ~pSGCSB.busy THEN EXIT ENDLOOP;
        -- stop sound generator
      sgcsbState ← pSGCSB↑;
      pSGCSB.command ← stop;
      pSGCSB.busy ← TRUE;
      THROUGH [0..30000] DO IF ~pSGCSB.busy THEN EXIT ENDLOOP;
      END;
    turnOn =>
       BEGIN
       setPosition.point ← mousePos; setPosition.busy ← TRUE;
       LOOPHOLE[position, LONG POINTER TO MouseFace.Point]↑ ← mousePos;
       pSGCSB↑ ← sgcsbState;
       csb↑ ← csbState;
       END;
    disconnect =>
      IF bitmapAddress # NIL THEN
        BEGIN
        p: CARDINAL = Utilities.PageFromLongPointer[bitmapAddress];
        FOR vp: PageNumber IN [p..p + pagesForBitmap) DO
          PageMap.Assoc[vp, PageMap.valueVacant] ENDLOOP;
        END;
    ENDCASE;
  ENDLOOP;
END;

-- Start Chain

Start: PUBLIC PROC = {setPosition.fill ← 0; RemainingHeads.Start[]};

END....

February 27, 1983 2:12 pm  Taft  DisplayFaceExtras