-- DialupImpl.mesa (last edited by Danielson:  January 20, 1981  3:50 PM) --

DIRECTORY
  Dialup: FROM "Dialup" USING [Outcome, RetryCount],
  Process: FROM "Process" USING [MsecToTicks, SetTimeout],
  RS366Face: FROM "RS366Face" USING [
    GetDialerCount, GetStatus, SetStatus, GetStatusBits, SetStatusBits];

DialupImpl: MONITOR IMPORTS Process, RS366Face EXPORTS Dialup =
  BEGIN
  -- various definitions
  timer, oneTick: CONDITION;
  abortRequested: PACKED ARRAY [0..15] OF BOOLEAN ← ALL[FALSE];
  -- procedures (listed alphabetically)
  AbortCall: PUBLIC ENTRY PROCEDURE [dialerNumber: CARDINAL] =
    BEGIN abortRequested[dialerNumber] ← TRUE; END;

  Dial: PUBLIC ENTRY PROCEDURE [
    dialerNumber: CARDINAL, number: LONG STRING, retries: Dialup.RetryCount]
    RETURNS [outcome: Dialup.Outcome] =
    BEGIN
    stringIndex: CARDINAL;
    setStatusBits: RS366Face.SetStatusBits;
    getStatusBits: RS366Face.GetStatusBits;
    abortRequested[dialerNumber] ← FALSE;
    -- Validate parameters --
    IF RS366Face.GetDialerCount[] <= dialerNumber THEN RETURN[dialerNotPresent];
    IF number.length > 31 THEN RETURN[formatError];
    -- Make certain that the dialer has power --
    IF ~RS366Face.GetStatus[dialerNumber].powerIndication THEN
      RETURN[dialerNotPresent];
    BEGIN
    THROUGH [0..retries] DO
      -- Dial the phone number retries-1 times
      setStatusBits ← ResetDialer[dialerNumber];
      IF (RS366Face.GetStatus[dialerNumber]).dataLineOccupied THEN
        RETURN[dataLineOccupied];
      setStatusBits.callRequest ← TRUE;
      RS366Face.SetStatus[dialerNumber, setStatusBits];
      BEGIN
      FOR stringIndex IN [0..number.length) DO
        THROUGH [0..200) DO
          -- 10 second timeout
          getStatusBits ← RS366Face.GetStatus[dialerNumber];
          IF getStatusBits.presentNextDigit THEN EXIT;
          IF getStatusBits.abandonCallAndRetry THEN GO TO retry;
          IF abortRequested[dialerNumber] THEN GO TO abortDialing;
          WAIT oneTick;
          REPEAT FINISHED => GOTO dialingTimeout;
          ENDLOOP;
        SELECT number[stringIndex] FROM
          IN ['0..'9] =>
            setStatusBits.digit ← LOOPHOLE[number[stringIndex] - '0];
          '* => setStatusBits.digit ← 10;
          '# => setStatusBits.digit ← 11;
          '= => setStatusBits.digit ← 12;  -- EON --
          '< => setStatusBits.digit ← 13;  -- SEP..await dial tone --
          '> =>  -- timeout..pause before next digit --
            BEGIN WaitFor[6000]; LOOP; END;
          ENDCASE => GOTO formatError;
        RS366Face.SetStatus[dialerNumber, setStatusBits];
        setStatusBits.digitPresent ← TRUE;
        RS366Face.SetStatus[dialerNumber, setStatusBits];
        THROUGH [0..200) DO
          -- 10 second timeout
          getStatusBits ← RS366Face.GetStatus[dialerNumber];
          IF ~getStatusBits.presentNextDigit THEN EXIT;
          IF getStatusBits.abandonCallAndRetry THEN GO TO retry;
          IF abortRequested[dialerNumber] THEN GO TO abortDialing;
          WAIT oneTick;
          REPEAT FINISHED => GOTO dialingTimeout;
          ENDLOOP;
        setStatusBits.digitPresent ← FALSE;
        RS366Face.SetStatus[dialerNumber, setStatusBits];
        ENDLOOP;  -- go on to next digit
      -- Wait until dialer has transferred control of communication line to the data set.
      THROUGH [0..2000) DO
        --100 second timeout
        getStatusBits ← RS366Face.GetStatus[dialerNumber];
        IF getStatusBits.callOriginationStatus THEN EXIT;
        IF getStatusBits.abandonCallAndRetry THEN GO TO retry;
        IF abortRequested[dialerNumber] THEN GOTO abortDialing;
        WAIT oneTick;
        REPEAT FINISHED => GOTO transferTimeout;
        ENDLOOP;
      -- Modem now in control...idle dialer --
      setStatusBits ← [FALSE, FALSE, 0];
      RS366Face.SetStatus[dialerNumber, setStatusBits];
      RETURN[success];
      EXITS retry => NULL;
      END;
      ENDLOOP;
    outcome ← failure;
    EXITS
      abortDialing => outcome ← aborted;
      dialingTimeout => outcome ← dialingTimeout;
      formatError => outcome ← formatError;
      transferTimeout => outcome ← transferTimeout;
    END;
    [] ← ResetDialer[dialerNumber];
    RETURN;
    END;

  GetDialerCount: PUBLIC PROCEDURE RETURNS [numberOfDialers: CARDINAL] =
    BEGIN RETURN[RS366Face.GetDialerCount[]]; END;

  ResetDialer: PRIVATE INTERNAL PROCEDURE [dialerNumber: CARDINAL]
    RETURNS [setStatusBits: RS366Face.SetStatusBits] =
    BEGIN  -- Resets setStatusBits and hangs up phone --
    setStatusBits ← [callRequest: FALSE, digitPresent: FALSE, digit: 0];
    RS366Face.SetStatus[dialerNumber, setStatusBits];
    THROUGH [0..200) DO
      -- 10 second timeout for phone to be hung up --
      IF ~(RS366Face.GetStatus[dialerNumber]).dataLineOccupied THEN RETURN;
      WAIT oneTick;
      ENDLOOP;
    END;

  WaitFor: PRIVATE INTERNAL PROCEDURE [milliseconds: CARDINAL] =
    BEGIN
    Process.SetTimeout[@timer, Process.MsecToTicks[milliseconds]];
    WAIT timer;
    END;

  Process.SetTimeout[@oneTick, 1];
  END.
LOG
Time: October 18, 1978  8:47 AM	By: Schwartz	Action: Created file
Time: May 30, 1980  3:00 PM	By: Schwartz	Action: Remove all pre-Amargosa log entries, and change abortRequested to an array to allow support of multiple dialers.
Time: July 10, 1980  10:55 AM	By: Danielson	Action: Modified to support use RS366Face interface.
Time: January 20, 1981  3:51 PM	By: Danielson	Action: Added GetDialerCount procedure to allow client to determine number of dialers.