! EDWIN driver for the HP 7221 plotter

%external %routine %spec PROMPT (%string (15) S)
%external %routine %spec TTMODE (%integer MODE)
%external %routine %spec TTPUT (%integer CH)
%external %routine %spec FLUSH OUTPUT
%external %integer %fn %spec TTREAD
%external %integer %fn %spec INSTREAM
%external %integer %fn %spec OUT STREAM
%external %integer %spec DEVICE
!%external %long %real %fn %spec SIN (%long %real A)
!%external %long %real %fn %spec COS (%long %real A)
%const %real D TO R = 57.2958; ! Magic number converts degrees to rads.

! Control characters
%const %integer TRUE = 0,   FALSE = 1
%const %integer ETX = 3
%const %integer ESC =27
%const %integer DEL = 127
%const %integer BUFF SIZE = 251

! Screen information
%own %integer CMODE = 0;    ! 0=>display, 1=> Console active
%own %integer MODE = 0;    !0 if alphamode
%own %integer SX = 0;      !Current device position
%own %integer SY = 0
%own %integer XL=0, YB=0; ! Lower window bounds.
%own %integer YT = 14000; ! Upper device window bound.
%own %integer XR = 16000; ! Right hand side of device window
%own %integer VIS = TRUE; ! if CVP inside VW
%own %integer TCS = 120; ! True char size.
%own %byte %integer CCOL = 1;  ! Current colour.
%own %byte %integer PM = FALSE;  ! Pending move.
%own %byte %integer PC = FALSE;  ! Pending colour change.
%own %byte %integer NEWFRAMED = FALSE; ! TRUE => NEW FRAME done
%own %integer INBUFF = 32; ! This is the initialisation code


%routine SBN (%integer N)
   ! This sends a single byte number to the plotter
   N = N+64 %if N&32 = 0
   TTPUT (N)
%end

%routine MBN (%integer N)
   ! A three byte number is sent to the plotter
   %integer NN


   TTPUT (96+N//4096)
   
   NN = (N//64)&63
   NN = NN + 64 %unless NN>31
   TTPUT (NN)

   NN = N&63
   NN = NN + 64 %unless NN>31
   TTPUT (NN)
%end

%routine MBP (%integer X, Y)
   ! Multiple byte pair of numbers (5 bytes)
   %integer N


   TTPUT (96+X//1024)
   
   N = (X//16)&63
   N = N + 64 %unless N>31
   TTPUT (N)

   N = (X&15)*4 + (Y//4096)
   N = N + 64 %unless N>31
   TTPUT (N)
   
   N = (Y//64)&63
   N = N + 64 %unless N>31
   TTPUT (N)

   N = Y&63
   N = N + 64 %unless N>31
   TTPUT (N)
%end

%routine MBA (%integer A)
   ! Gives a multi byte angle
   MBN (INT(2\15*(A/180)))
%end

%routine HP INSTRUCTION (%integer WHICH)
   TTPUT (ESC);   TTPUT ('.');   TTPUT (WHICH)
%end

%routine PON 
   HP INSTRUCTION ('(')
   CMODE=0
%end

%routine %spec RESERVE (%integer N)

%routine POF
   RESERVE (BUFF SIZE); ! force out anything which is present.
   HP INSTRUCTION (')')
   TTPUT (13)
   FLUSH OUTPUT
   CMODE=1
%end

%routine RESERVE (%integer N)
   ! Test to see if N chars. will fit in the buffer
   %integer S
   IN BUFF = IN BUFF + N
   %if IN BUFF>250 %start
       HP INSTRUCTION ('L')
       FLUSH OUTPUT
       S = IN STREAM
       SELECT INPUT (0)
       PROMPT (TO STRING (DEL))
       N = TTREAD %until N > ' '
       N = TTREAD %until N = NL; ! Ignore the response
       SELECT INPUT (S)
       IN BUFF = 0
       PROMPT ("Data: ")
   %finish
%end

%ROUTINE CHECK FOR PENDING COLOURS AND MOVES
   TTPUT ('v') %and SBN(5-CCOL) %if PC=TRUE
   TTPUT ('p') %and MBP (SX-XL, SY-YB) %if PM=TRUE
   PC = FALSE
   PM = FALSE
%end

%routine UPDATE
   %if CMODE=0 %start
       TTPUT (ETX) %if MODE=0
       RESERVE (10)
       PM = TRUE
       CHECK FOR PENDING COLOURS AND MOVES
       TTPUT ('v')
       SBN (5-CCOL)
       POF
   %finish
   MODE = -1
%end

%routine CHECK PLOTTING AND NO TEXT
   PON %if CMODE=1
   TTPUT (ETX) %and MODE=-1 %if MODE=0
%end

%external %routine HP SPEED (%integer VAL)
   %return %if DEVICE#3
   PON %if CMODE=1
   TTPUT (ETX) %if MODE=0
   VAL = 36 %unless 1<=VAL<=36
   TTPUT ('~');   TTPUT ('V')
   SBN (VAL)
%end

%dynamic %routine P7221 (%integer COM,X,Y)
   %switch SW(0:15)

   %routine NEW FRAME
      %integer IN ST, OUT ST

      CHECK PLOTTING AND NO TEXT
      SX=XR;   SY = YT;   PM = TRUE;! Goto the edge.
      VIS = CCOL;                   ! VIS used to remember current colour.
      PC = TRUE;  CCOL = 5;         ! Drop pen
      UPDATE
      IN ST = INSTREAM
      OUT ST = OUT STREAM
      SELECT OUTPUT (0)
      SELECT INPUT (0)
      PRINT STRING ("Enter new sheet of ")
      %if XR<=20*400 %and 20*400<=YT<=28*400 %then PRINT STRING ("rotated A4") %else %start
          PRINT SYMBOL ('A')
          %if XR<=28*400 %and YT<=20*400 %then PRINT SYMBOL ('4') %else PRINT SYMBOL ('3')
      %finish
      PRINT STRING (" paper, type YES to continue")
      NEWLINE
      Prompt ("Ready?")
      SKIP SYMBOL %while NEXT SYMBOL#'Y' %and NEXT SYMBOL#'y'
      SKIP SYMBOL %until NEXT SYMBOL=NL
      SKIP SYMBOL
      SELECT OUTPUT (OUT ST)
      SELECT INPUT (INST)
      Prompt ("Data:")
      NEW FRAMED = TRUE
      ! Restore default state after newframe.
      CCOL = VIS;   SX = 0;   SY = 0;   VIS = TRUE;   PM = TRUE;   PC = TRUE
   %end

   %routine PUT CHAR
      ! Put out a text character properly.
   
      PON %if CMODE=1
      %if MODE#0 %start
          CHECK FOR PENDING COLOURS AND MOVES
          TTPUT ('~'); TTPUT ('''')
          MODE=0
      %finish
      TTPUT (X)
      SX = SX + TCS
      VIS = FALSE %if SX>XR
   %end

   %routine CHANGE ATTRIBUTE
      %switch SW(0:8)
      %const %integer DASH = 32

      %return %if X>8
      CHECK PLOTTING AND NO TEXT
      MODE = -1
      RESERVE (10)
      -> SW(X)
   
SW(0): Y=1 %unless 0<=Y<=4
       Y = 5 %if Y = 0;   ! As plotter colours are 5 - the edwin colour
       PC = TRUE
       CCOL = Y
       %return

SW(1): TTPUT('~');  TTPUT ('Q')
       %if Y=1 %start
           SBN(DASH + 2); SBN(4); MBN(60)
       %finish
       %if Y=2 %start
           SBN(DASH + 14);  SBN(4);  SBN(DASH + 2); SBN(4); MBN(240)
       %finish
       %if Y=3 %start
           SBN(DASH + 8);  SBN(4);  MBN(120)
       %finish
       %if Y=4 %start
           SBN(DASH + 16);  SBN(4);  MBN(200)
       %finish
       %return

SW(2): TTPUT('~');  TTPUT('%');  TCS=Y*100//98;   MBP(TCS, TCS+TCS)
       ! Note that the 100//98 scales the H/W chars to same scale as S/W ones.
       %return

SW(3): TTPUT ('w');   TTPUT ('w');   MBA (Y);     %return;   ! Char rot

SW(4): %return;   ! Ignore attempts to change quality

SW(5): TTPUT ('~');   TTPUT ('P');   MBP (Y,Y);   %return;   ! Char font

SW(6): TTPUT ('~');   TTPUT ('/');   MBA (Y);     %return;   ! Char slant

SW(7): %return;   ! Ignore any attempts to change intensity.

SW(8): HP SPEED (Y)
   %end

   %return %if DEVICE#3 %or COM>15
   -> SW(COM)

SW(0): ! Initialise
       TTMODE (1)
       PON
       TTPUT ('~');   TTPUT('_');     ! Initilalise
       TTPUT ('~');   TTPUT('W');     ! Set graph limits to full size
       MBP (0,0);     MBP(16000,11400);   TTPUT ('}')
       TTPUT ('~');   TTPUT('S');     ! Set Grid default
       MBP(16000,11400);   TTPUT ('}')
       HP INSTRUCTION ('M');          ! Set output mode
       TTPUT (';');   TTPUT (';');   TTPUT ('1');   TTPUT ('0');   TTPUT (';')
       TTPUT (':')
       X=0; Y=1
       CHANGE ATTRIBUTE; ! Colour to 1
       X=2; Y=120
       CHANGE ATTRIBUTE; ! Char size to small ones
       NEW FRAMED = FALSE
       %return

SW(1): !Terminate
       PON %if CMODE=1
       SX = XR;   SY = YT;   PM=TRUE;   ! Go to edge of paper.
       PC = TRUE;   CCOL = 5;           ! Drop pen.

SW(2): ! Update
       UPDATE
       TTMODE (0) %if COM = 1
       %return

SW(3): ! New frame
       NEW FRAME
       %return

SW(4): ! Move Abs
       NEW FRAME %if NEWFRAMED # TRUE
       CHECK PLOTTING AND NO TEXT
       SX = X;   SY = Y
       VIS = TRUE
       PM = TRUE
       MODE = 1
       %return

SW(5): ! Line Abs
       NEW FRAME %if NEW FRAMED # TRUE
       CHECK PLOTTING AND NO TEXT
       RESERVE (20)
       CHECK FOR PENDING COLOURS AND MOVES
       TTPUT ('q'); MBP(X-XL, Y-YB)
       SX = X;   SY = Y
       VIS = TRUE
       MODE = 1
       %return

SW(6): ! Character
       NEW FRAME %if NEWFRAMED # TRUE
       PUT CHAR %if VIS = TRUE
       %return

SW(7): ! Attribute  Change
       CHANGE ATTRIBUTE
       %return

SW(8): ! Set lower  device window bounds
       XL = X
       YB = Y
       %return

SW(9): ! Set upper device window bounds
       XR = X
       YT = Y
       RESERVE (15)
       PON
       TTPUT ('~');   TTPUT ('W');   MBP (XL, YB);   MBP (XR, YT)
       TTPUT ('~');   TTPUT ('S');   MBP (XR-XL, YT-YB); TTPUT ('}')
       %return

SW(*):
%end

%external %routine HP C ARC (%integer RAD, %integer IA, FA)
   %integer OX, OY
   %return %if DEVICE#3
   RESERVE (20)
   OX = SX;   OY = SY
   P7221 (4, SX + INT (RAD * COS (IA * DtoR)), SY + INT (RAD * SIN (IA * DtoR)))
   CHECK PLOTTING AND NO TEXT
   CHECK FOR PENDING COLOURS AND MOVES
   TTPUT ('t')
   MBN (RAD)
   MBA (IA)
   MBA (FA)
   P7221 (4, OX, OY)
%end

%external %routine HP AC ARC (%integer RAD, %integer IA, FA)
   %integer OX, OY
   %return %if DEVICE#3
   RESERVE (20)
   OX = SX;   OY = SY
   P7221 (4, SX + INT (RAD * COS (IA / DtoR)), SY + INT ( RAD * SIN (IA / DtoR)))
   CHECK PLOTTING AND NO TEXT
   CHECK FOR PENDING COLOURS AND MOVES
   TTPUT ('u')
   MBN (RAD)
   MBA (IA)
   MBA (FA)
   P7221 (4, OX, OY)
%end

%external %routine HP CIRCLE (%integer RAD)
   %integer OX
   %return %if DEVICE#3
   RESERVE (20)
   OX = SX
   P7221 (4, SX+RAD, SY)
   CHECK FOR PENDING COLOURS AND MOVES
   TTPUT ('t')
   MBN (RAD)
   P7221 (4, OX, SY)
%end

%dynamic %routine P CURSOR (%integer %name STATE, X, Y)
   %integer I, S

   %integer %fn GET NUM
      %integer V,I
      V = 0
      I = TTREAD
      %cycle
         V = V*10+(I-'0')
         I = TTREAD
         %exit %unless '0'<=I<='9'
      %repeat
      %result = V
   %end

   PON %if CMODE=1
   TTPUT (ETX) %if MODE=0
   HP INSTRUCTION ('D')
   FLUSH OUTPUT
   S = IN STREAM
   SELECT INPUT (0)
   PROMPT (TO STRING (DEL))
   X = GET NUM
   Y = GET NUM
   I = GET NUM
   STATE = I<<4!GET NUM
   ! State is 'pen tp/down flag'<<4! Ctrrent pen.
   POF
   FLUSH OUTPUT
   PROMPT ("Data: ")
   SELECT INPUT (S)
%end

%end %of %file
