-- File: DiagnosticsImplI.mesa - last edit by: 
-- Paul		13-Jul-84 11:06:54

DIRECTORY
  DiagnosticsOps USING [PlotterType],
  GreenFace USING [
    Command, ForceWakeups, GetAndResetStatus, GetStatus, LogCommand, LogStatus,
    PutCommand, SendPage, Status],
  Inline USING [LongCOPY],
  Msg USING [FeedBack],
  Process USING [Detach, Pause, MsecToTicks, SetTimeout],
  Space USING [PageFromLongPointer, ScratchMap],
  UserTerminal USING [GetBitBltTable],
  VM USING [Interval, MakeResident, MakeSwappable];

DiagnosticsImplI: MONITOR
  IMPORTS GreenFace, Inline, Msg, Process, Space, UserTerminal, VM
  EXPORTS DiagnosticsOps =
  BEGIN
  DataType: TYPE = {nthBit, count, ff00, ascii};
  Enumerated: TYPE = RECORD [string: LONG STRING, value: UNSPECIFIED];

  -- Variable declarations
  cmd: GreenFace.Command ← reset;
  bitStep: CARDINAL ← 1;
  dataType: DataType ← ff00;

  bufferPages: CARDINAL = 2;
  buffer: LONG POINTER = Space.ScratchMap[bufferPages];
  vi: VM.Interval = [page: Space.PageFromLongPointer[buffer], count: bufferPages];
  greenStarStatus: GreenFace.Status;

  GetStatus: PUBLIC PROCEDURE [plotter: DiagnosticsOps.PlotterType]
    RETURNS [GreenFace.Status] = {RETURN[greenStarStatus]};

  SendCommand: PUBLIC PROCEDURE [
    plotter: DiagnosticsOps.PlotterType, cmd: GreenFace.Command] = {SendCmd[cmd]};

  PrintPattern: PUBLIC PROCEDURE [plotter: DiagnosticsOps.PlotterType] = {
    dataType ← ascii;
    SendVideo[];};
    
  PlotPattern: PUBLIC PROCEDURE [plotter: DiagnosticsOps.PlotterType] = {
    dataType ← count;
    SendVideo[];};

  PlotScreen: PUBLIC PROCEDURE [plotter: DiagnosticsOps.PlotterType] = {
    pID: PROCESS;
    Msg.FeedBack[s: "Plot invoked"L, severity: info, endWithCR: TRUE];
    VM.MakeResident[vi, wait];
    pID ← FORK PlotPage[plotter];
    JOIN pID;
    VM.MakeSwappable[vi]};

  PlotPage: PROCEDURE [plotter: DiagnosticsOps.PlotterType] = {
    screenData: LONG POINTER TO PACKED ARRAY [0..1024) OF BOOLEAN ←
      UserTerminal.GetBitBltTable[].src.word;
    Pixel: TYPE = MACHINE DEPENDENT{white(0), black(3)};
    printData: LONG POINTER TO PACKED ARRAY OF Pixel = buffer;
    word: CARDINAL ← 0;

    SendCmd[reset];
    Pause[1000];
    AssertStatus[plotterready];
    SendCmd[plot];

    Zero[buffer, 512];

    SendCmd[rlter];
    AssertStatus[plotterready];

    Msg.FeedBack[s: "screen contents..."L, severity: info, endWithCR: TRUE];
    Pause[1000];

    FOR k: CARDINAL IN [0..808) DO  --808 visible display lines
      offset: CARDINAL = word * 8;
      FOR i: CARDINAL IN [0..1024) DO
        dataOffset: CARDINAL = offset + i;
        IF screenData[i] THEN
          printData[dataOffset] ← printData[dataOffset + 1056] ← black
        ELSE printData[dataOffset] ← printData[dataOffset + 1056] ← white;
        ENDLOOP;
      word ← word + 8;
      --if word = 256 then send both pages and reset word to 0
      -- send a buffer
      GreenFace.SendPage[buffer];
      IF word = 256 THEN {GreenFace.SendPage[buffer + 256]; word ← 0};
      Inline.LongCOPY[from: buffer + 256, nwords: word, to: buffer];
      Zero[buffer + word + 128, 4];
      Zero[buffer + word + 260, 4];
      screenData ← screenData + 64;
      ENDLOOP;

    SendCmd[rffed];
    AssertStatus[plotterready]};

  Pause: PROCEDURE [msec: CARDINAL] = {Process.Pause[Process.MsecToTicks[msec]]};
  
  AssertStatus: PROCEDURE [expectedStatus: GreenFace.Status] = {
    Pause[1000];
    SendCmd[sensestatus];
    Pause[1000];
    [] ← GreenFace.GetAndResetStatus[];
    IF expectedStatus = greenStarStatus THEN RETURN;  -- ok
    Text["Bad status -- expected "L];
    GreenFace.LogStatus[expectedStatus, Text];
    Text[", got "L];
    GreenFace.LogStatus[greenStarStatus, Line]};

  Statusproc: ENTRY PROCEDURE = {
    cv: CONDITION;
    Process.SetTimeout[@cv, 1];
    Text["Status = "L]; 
    GreenFace.LogStatus[greenStarStatus, Line];
    DO
      status: GreenFace.Status = GreenFace.GetStatus[];
      IF status = null OR status = greenStarStatus THEN {WAIT cv; LOOP};
      Text["Status = "L];
      GreenFace.LogStatus[greenStarStatus ← status, Line];
      ENDLOOP};

  DoWakeup: PROCEDURE = {GreenFace.ForceWakeups[]};

  SendVideo: PROCEDURE = {
    bitArray: LONG POINTER TO PACKED ARRAY [0..4096) OF BOOLEAN = buffer;
    byteArray: LONG POINTER TO PACKED ARRAY [0..512) OF [0..256) = buffer;
    VM.MakeResident[vi, wait];
    Text["Sending... "L];
    SELECT dataType FROM
      count => {
        FOR j: CARDINAL IN [0..512) DO byteArray[j] ← (j + 1) MOD 256 ENDLOOP;
        Line["1, 2, ... FF, 0, 1, 2, ... FF, 0"L]};
      ascii => {
        FOR j: CARDINAL IN [0..512) DO
          i: CARDINAL = j MOD 28;
          byteArray[j] ←
            SELECT i FROM
              26 => 13,  -- CR
              27 => 10,  -- LF
              ENDCASE => LOOPHOLE['A, CARDINAL] + i;  -- A ... Z
          ENDLOOP;
        Line["A, B, C, ... Z, CR, LF, A, B, ..."L]};
      ff00 => {
        FOR j: CARDINAL IN [0..512) DO
          byteArray[j] ← IF j MOD 2 = 0 THEN 255 ELSE 0 ENDLOOP;
        Line["FF, 00, FF, 00, ..."L]};
      nthBit => {FOR j: CARDINAL IN [0..512) DO byteArray[j] ← 142b ENDLOOP};
      ENDCASE => Line["BAD ENUMERATED VALUE!!!"L];
    GreenFace.SendPage[buffer];
    VM.MakeSwappable[vi]};

  SendCmd: PROCEDURE [cmd: GreenFace.Command] = {
    Text["Command = "L];
    IF cmd = null THEN {Line["0; not sent!"L]; RETURN};
    GreenFace.PutCommand[cmd];
    GreenFace.LogCommand[cmd, Line] --effective 500 milli pause-- };

  Zero: PROC [lp: LONG POINTER, count: CARDINAL] = {
    lp↑ ← 0; Inline.LongCOPY[from: lp, nwords: count - 1, to: lp + 1]};

  Text: PROC [s: LONG STRING] = {
    Msg.FeedBack[s: s, severity: info, endWithCR: FALSE]};

  Line: PROC [s: LONG STRING] = {
    Msg.FeedBack[s: s, severity: info, endWithCR: TRUE]};

  -- Tool routines
  PrintInit: PROCEDURE = {
    pID: PROCESS;
    pID ← FORK WakeUpGreenStar[];
    JOIN pID;};
    
  WakeUpGreenStar: PROCEDURE = {
    SendCmd[reset];
    Pause[4000];
    greenStarStatus ← GreenFace.GetAndResetStatus[];
    Pause[1000];
    SendCmd[rffed]};
  

  Init: PROCEDURE = {
    PrintInit[];
    Process.Detach[FORK Statusproc[]]};

  END.