-- DiagnosticsImplH.mesa  -  edited by:
-- Paul 	10-Jan-84 14:11:13

-- RS232C Loopback Diagnostic module 

DIRECTORY
  Address USING [AddressTrouble, NetworkAddressToString, StringsToNetworkAddress],
  CommOnlineDiagnostics USING [
    CountType, GetRS232CResults, ModemChange, RS232CLoopback, RS232CDiagError, 
    PatternType, WriteMsg],
  DiagnosticsOps USING [
    CheckForAbort, RS232LineType, PutCR, PutChar, PutLine, PutLongNumber,
    PutNumber, PutText],
  Format USING [StringProc],
  Heap USING [systemZone],
  NetworkStream USING [AssignNetworkAddress],
  NSConstants USING [echoerSocket],
  Process USING [Detach, SecondsToTicks, SetTimeout, Pause],
  RS232C USING [Correspondent, LineSpeed, LineType],
  RS232CCorrespondents USING [nsSystemElement, xerox800],
  String USING [Replace],
  System USING [NetworkAddress, nullNetworkAddress];

DiagnosticsImplH: MONITOR
  IMPORTS
    Address, CommOnlineDiagnostics, DiagnosticsOps, Heap, NetworkStream, Process,
    String
  EXPORTS DiagnosticsOps =
  BEGIN

  doneWithSession: BOOLEAN ← FALSE;
  results: CommOnlineDiagnostics.CountType;
  hostAddr: System.NetworkAddress ← System.nullNetworkAddress;
  showEchoes: BOOLEAN ← TRUE;
  realLineType: RS232C.LineType;

  RS232CLoopBackTest: PUBLIC PROCEDURE [
    host: LONG STRING, hostNet: LONG STRING, 
    lineType: DiagnosticsOps.RS232LineType, 
    lineSpeed: RS232C.LineSpeed, pattern: CommOnlineDiagnostics.PatternType, 
    constant, minPacketSize, maxPacketSize: CARDINAL] =
    BEGIN
    CopyMyAddress: Format.StringProc = {
      String.Replace[@myAddress, s, Heap.systemZone]};

    myAddr: System.NetworkAddress = NetworkStream.AssignNetworkAddress[];
    myAddress: LONG STRING ← NIL;
    errFlag: BOOLEAN ← FALSE;
    correspondentType: RS232C.Correspondent ← 
      IF lineType = bitSynchronous 
        THEN RS232CCorrespondents.nsSystemElement 
	ELSE RS232CCorrespondents.xerox800; 

    realLineType ← 
      IF lineType = bitSynchronous THEN bitSynchronous ELSE asynchronous;
      
    hostAddr ← Address.StringsToNetworkAddress[
      host, NSConstants.echoerSocket, hostNet !
      Address.AddressTrouble =>
        BEGIN
        DiagnosticsOps.PutText["Host address translation troubles: "L];
        DiagnosticsOps.PutLine[reason];
        errFlag ← TRUE;
        CONTINUE;
        END];

    IF hostAddr.net # myAddr.net OR hostAddr.host # myAddr.host THEN
      showEchoes ← FALSE;  -- can't show remotes

    Address.NetworkAddressToString[
      myAddr, CopyMyAddress !
      Address.AddressTrouble =>
        BEGIN
        DiagnosticsOps.PutText["Local Network Address translation troubles: "L];
        DiagnosticsOps.PutLine[reason];
        errFlag ← TRUE;
        CONTINUE;
        END];

    IF errFlag THEN RETURN;
    DiagnosticsOps.PutCR[];
    DiagnosticsOps.PutLine["      RS232C Loopback Test Parameters:"L];
    DiagnosticsOps.PutCR[];
    
    DiagnosticsOps.PutText["Local Network Address = "L];
    DiagnosticsOps.PutText[myAddress];
    DiagnosticsOps.PutCR[];

    DiagnosticsOps.PutText["LoopBack Host = "L];
    DiagnosticsOps.PutText[host];
    DiagnosticsOps.PutCR[];

    DiagnosticsOps.PutText["Data Pattern: "L];
    DiagnosticsOps.PutText[
      SELECT pattern FROM
        zero => "All 0's"L,
        ones => "All 1's"L,
        byteIncr => "Incrementing"L,
        constant => "Constant"L,
        ENDCASE => "Unknown"L];
    DiagnosticsOps.PutCR[];
    
    IF pattern = constant THEN {
      DiagnosticsOps.PutText["Pattern: "L];
      DiagnosticsOps.PutNumber[constant, 10];
      DiagnosticsOps.PutCR[];
      };
    

    DiagnosticsOps.PutText["Minimum Packet Size: "L];
    DiagnosticsOps.PutNumber[minPacketSize, 10];
    DiagnosticsOps.PutCR[];

    DiagnosticsOps.PutText["Maximum Packet Size: "L];
    DiagnosticsOps.PutNumber[maxPacketSize, 10];
    DiagnosticsOps.PutCR[];


    DiagnosticsOps.PutText["Please install loopback plug on RS232 port, or set modem to Loopback before running this test."L];
    DiagnosticsOps.PutCR[];
    DiagnosticsOps.PutCR[];

    DiagnosticsOps.PutLine["Feedback key:"L];
    DiagnosticsOps.PutLine["Each '!' represents a successful receive operation."L];
    DiagnosticsOps.PutLine["Each '?' represents device error."L];
    DiagnosticsOps.PutLine["Each '#' represents a receive error."L];
    DiagnosticsOps.PutLine[
      "Each '~' represents a packet which had data lost."L];
    DiagnosticsOps.PutLine[
      "Each ':' marks XMit error."L];
    DiagnosticsOps.PutLine["Each '*' represents a bad seq # or missing data."L];
    DiagnosticsOps.PutLine["Each '|' represents a good send operation."L];
    DiagnosticsOps.PutLine["Each 'E' represents a send error."L];
    DiagnosticsOps.PutCR[];
    
    CommOnlineDiagnostics.RS232CLoopback[
      rs232cParams: [
        testCount: LAST[CARDINAL], lineSpeed: lineSpeed,
        correspondent: correspondentType, lineType: realLineType,
        lineNumber: 0, parity: even, charLength: 8, pattern: pattern, 
	constant: constant, 
	dataLengths: [low: minPacketSize, high: maxPacketSize]], 
      setDiagnosticLine: NIL, 
      writeMsg: RS232CFeedback, modemChange: ModemFeedback, host: hostAddr !
      CommOnlineDiagnostics.RS232CDiagError =>
        BEGIN
        DiagnosticsOps.PutText["RS232C Error: "L];
        DiagnosticsOps.PutLine[
          SELECT reason FROM
            aborted => "Aborted"L,
            noHardware => "No RS232C Hardware"L,
            noSuchLine => "No Such Line"L,
            channelInUse => "Channel In Use"L,
            unimplementedFeature => "Unimplemented Feature"L,
            invalidParameter => "Invalid Parameter"L,
            ENDCASE => "Unknown Error"L];
        CONTINUE;
        END];  --remote needs ServerOn!!!!!

    DiagnosticsOps.PutLine["Rs232C Loopback Test Started"L];

    doneWithSession ← FALSE;
    Process.Detach[FORK Echoer[]];
    DO
      DiagnosticsOps.CheckForAbort[ ! ABORTED => EXIT];
      Process.Pause[Process.SecondsToTicks[1]];
      ENDLOOP;
    doneWithSession ← TRUE;

    [results] ← CommOnlineDiagnostics.GetRS232CResults[
      stopIt: TRUE, host: hostAddr !
      CommOnlineDiagnostics.RS232CDiagError =>
        BEGIN
        DiagnosticsOps.PutText["RS232C Error: "L];
        DiagnosticsOps.PutLine[
          SELECT reason FROM
            aborted => "Aborted"L,
            noHardware => "No RS232C Hardware"L,
            noSuchLine => "No Such Line"L,
            channelInUse => "Channel In Use"L,
            unimplementedFeature => "Unimplemented Feature"L,
            invalidParameter => "Invalid Parameter"L,
            ENDCASE => "Unknown Error"L];
	  CONTINUE;
        END];
    DiagnosticsOps.PutCR[];
    DiagnosticsOps.PutCR[];
    DiagnosticsOps.PutLine["Final results: "L];
    PrintResults[];
    DiagnosticsOps.PutLine["Done"L];
    END;  -- EchoUserTest --

  Echoer: ENTRY PROC = {
    cv: CONDITION;
    Process.SetTimeout[@cv, Process.SecondsToTicks[10]];
    UNTIL doneWithSession DO
      WAIT cv;
      IF doneWithSession THEN EXIT;
      [results] ← CommOnlineDiagnostics.GetRS232CResults[
        stopIt: FALSE, host: hostAddr !
        CommOnlineDiagnostics.RS232CDiagError =>
          BEGIN
          DiagnosticsOps.PutText["RS232C Error: "L];
          DiagnosticsOps.PutLine[
          SELECT reason FROM
            aborted => "Aborted"L,
            noHardware => "No RS232C Hardware"L,
            noSuchLine => "No Such Line"L,
            channelInUse => "Channel In Use"L,
            unimplementedFeature => "Unimplemented Feature"L,
            invalidParameter => "Invalid Parameter"L,
            ENDCASE => "Unknown Error"L];
	    EXIT;
          END];
      DiagnosticsOps.PutCR[];
      DiagnosticsOps.PutCR[];
      DiagnosticsOps.PutText["Intermediate results: "L];
      PrintResults[];
      ENDLOOP};

  PrintResults: PROCEDURE [] = {
    DiagnosticsOps.PutCR[];
    DiagnosticsOps.PutText["Number of packets sent OK: "L];
    DiagnosticsOps.PutLongNumber[results.sendOk, 10];
    DiagnosticsOps.PutCR[];
    IF realLineType = bitSynchronous THEN {
      DiagnosticsOps.PutText["Number of good packets received: "L];
      DiagnosticsOps.PutLongNumber[results.recOk, 10];
      DiagnosticsOps.PutCR[];
      DiagnosticsOps.PutText["Number of packets not sent: "L];
      DiagnosticsOps.PutLongNumber[results.sendErrors, 10];
      DiagnosticsOps.PutCR[]};
    DiagnosticsOps.PutText["Number of bytes sent: "L];
    DiagnosticsOps.PutLongNumber[results.bytesSent, 10];
    DiagnosticsOps.PutCR[];
    DiagnosticsOps.PutText["Number of bytes received: "L];
    DiagnosticsOps.PutLongNumber[results.bytesRec, 10];
    DiagnosticsOps.PutCR[];
    IF results.deviceError # 0 THEN {
      DiagnosticsOps.PutText["Device errors: "L];
      DiagnosticsOps.PutLongNumber[results.deviceError, 10];
      DiagnosticsOps.PutCR[]};
    IF results.checkSum # 0 THEN {
      DiagnosticsOps.PutText["Transmit errors: "L];
      DiagnosticsOps.PutLongNumber[results.checkSum, 10];
      DiagnosticsOps.PutCR[]};
    IF results.badSeq # 0 THEN {
      DiagnosticsOps.PutText["Bad data: "L];
      DiagnosticsOps.PutLongNumber[results.badSeq, 10];
      DiagnosticsOps.PutCR[]};
    IF results.missing # 0 THEN {
      DiagnosticsOps.PutText["Missing data: "L];
      DiagnosticsOps.PutLongNumber[results.missing, 10];
      DiagnosticsOps.PutCR[]};
    IF results.dataLost # 0 THEN {
      DiagnosticsOps.PutText["Data Lost: "L];
      DiagnosticsOps.PutLongNumber[results.dataLost, 10];
      DiagnosticsOps.PutCR[]};
    IF results.parity # 0 THEN {
      DiagnosticsOps.PutText["Parity Errors: "L];
      DiagnosticsOps.PutLongNumber[results.parity, 10];
      DiagnosticsOps.PutCR[]};
    DiagnosticsOps.PutCR[]};

  RS232CFeedback: CommOnlineDiagnostics.WriteMsg =
    BEGIN
    -- If NOT showEchoes Then just Return
    IF showEchoes THEN
      DiagnosticsOps.PutChar[
        SELECT msg FROM
          recvOk => '!,
          recvErrors => '#,
          deviceError => '?,
          dataLost => '~,
          xmitErrors => ':,
          badSeq => '*,
	  missing => '*,
	  sendOk => '|,
	  sendErrors => 'E,
          ENDCASE => '@];
    END;
    
  ModemFeedback: CommOnlineDiagnostics.ModemChange =
    BEGIN
    -- If NOT showEchoes Then just Return
    IF showEchoes THEN
      DiagnosticsOps.PutText[
        SELECT modemSignal FROM
          dataSetReady => "Data Set Ready"L,
          clearToSend => "Clear To Send"L,
          carrierDetect => "Carrier Detect"L,
          ringIndicator => "Ring Indicator"L,
          ringHeard => "Ring Heard"L,
          ENDCASE => "Unknown Modem Change"L];
     DiagnosticsOps.PutLine[IF state THEN " TRUE"L ELSE " FALSE"L];
    END;

  END.