-- DiagnosticsImplD.mesa - edited by: -- Poskanzer 28-Mar-83 11:42:06 DIRECTORY Ascii USING [ControlG], DiagnosticsOps USING [ CheckForAbort, GetConfirmation, GetFloppyChoice, GetYesOrNo, PutChar, PutCR, PutLine, PutMessage, PutText, PutTextCentered, running], Format USING [Blanks, Char, LongString, Number, NumberFormat, StringProc], Heap USING [systemZone], OnlineDiagnostics USING [ DisplayFieldsProc, DisplayNumberedTableProc, DisplayTableProc, ErrorHandling, FieldDataType, FloppyCleanReadWriteHeads, FloppyCommandFileTest, FloppyDisplayErrorLog, FloppyExerciser, FloppyFormatDiskette, FloppyMessage, FloppyReturn, FloppyStandardTest, PutMessageProc, SectorLength, SingleDouble], String USING [ AppendNumber, AppendString, AppendStringAndGrow, CopyToNewString]; DiagnosticsImplD: PROGRAM IMPORTS DiagnosticsOps, Format, Heap, OnlineDiagnostics, String EXPORTS DiagnosticsOps = BEGIN z: UNCOUNTED ZONE = Heap.systemZone; FloppyStandardTest: PUBLIC PROCEDURE = BEGIN errFlag: BOOLEAN ← FALSE; floppyReturn: OnlineDiagnostics.FloppyReturn; floppyReturn ← OnlineDiagnostics.FloppyStandardTest[ DisplayFields, DisplayTable, DisplayNumberedTable, DiagnosticsOps.PutMessage, DiagnosticsOps.GetConfirmation, DiagnosticsOps.GetYesOrNo, DiagnosticsOps.GetFloppyChoice ! ABORTED => BEGIN errFlag ← TRUE; CONTINUE; END]; IF NOT errFlag THEN FloppyReturnMessage[floppyReturn]; FloppyFinished[errFlag]; END; FloppyCleanReadWriteHeads: PUBLIC PROCEDURE = BEGIN errFlag: BOOLEAN ← FALSE; floppyReturn: OnlineDiagnostics.FloppyReturn; floppyReturn ← OnlineDiagnostics.FloppyCleanReadWriteHeads[ DisplayFields, DisplayTable, DisplayNumberedTable, DiagnosticsOps.PutMessage, DiagnosticsOps.GetConfirmation, DiagnosticsOps.GetYesOrNo, DiagnosticsOps.GetFloppyChoice ! ABORTED => BEGIN errFlag ← TRUE; CONTINUE; END]; IF NOT errFlag THEN FloppyReturnMessage[floppyReturn]; FloppyFinished[errFlag]; END; FloppyCommandFileTest: PUBLIC PROCEDURE [ doubleDensity: BOOLEAN, doubleSided: BOOLEAN, sectorsPerTrack: CARDINAL [8..26], sectorLength: OnlineDiagnostics.SectorLength, errorHandling: OnlineDiagnostics.ErrorHandling, cmdFile: LONG STRING] = BEGIN errFlag: BOOLEAN ← FALSE; density, sides: OnlineDiagnostics.SingleDouble; temp: LONG STRING; density ← IF doubleDensity THEN double ELSE single; sides ← IF doubleSided THEN double ELSE single; temp ← String.CopyToNewString[cmdFile, z]; String.AppendStringAndGrow[@temp, "X,"L, z]; OnlineDiagnostics.FloppyCommandFileTest[ density, sides, sectorsPerTrack, sectorLength, errorHandling, temp, DisplayFields, DisplayTable, DisplayNumberedTable, DiagnosticsOps.PutMessage, DiagnosticsOps.GetConfirmation, DiagnosticsOps.GetYesOrNo, DiagnosticsOps.GetFloppyChoice ! ABORTED => BEGIN errFlag ← TRUE; CONTINUE; END]; z.FREE[@temp]; FloppyFinished[errFlag]; END; FloppyDisplayErrorLog: PUBLIC PROCEDURE = BEGIN errFlag: BOOLEAN ← FALSE; OnlineDiagnostics.FloppyDisplayErrorLog[ DisplayFields, DisplayTable, DisplayNumberedTable, DiagnosticsOps.PutMessage, DiagnosticsOps.GetConfirmation, DiagnosticsOps.GetYesOrNo, DiagnosticsOps.GetFloppyChoice ! ABORTED => BEGIN errFlag ← TRUE; CONTINUE; END]; FloppyFinished[errFlag]; END; FloppyExerciser: PUBLIC PROCEDURE = BEGIN errFlag: BOOLEAN ← FALSE; OnlineDiagnostics.FloppyExerciser[ DisplayFields, DisplayTable, DisplayNumberedTable, DiagnosticsOps.PutMessage, DiagnosticsOps.GetConfirmation, DiagnosticsOps.GetYesOrNo, DiagnosticsOps.GetFloppyChoice ! ABORTED => BEGIN errFlag ← TRUE; CONTINUE; END]; FloppyFinished[errFlag]; END; FloppyFormatDiskette: PUBLIC PROCEDURE = BEGIN errFlag: BOOLEAN ← FALSE; OnlineDiagnostics.FloppyFormatDiskette[ DisplayFields, DisplayTable, DisplayNumberedTable, DiagnosticsOps.PutMessage, DiagnosticsOps.GetConfirmation, DiagnosticsOps.GetYesOrNo, DiagnosticsOps.GetFloppyChoice ! ABORTED => BEGIN errFlag ← TRUE; CONTINUE; END]; FloppyFinished[errFlag]; END; FloppyReturnMessage: PROCEDURE [ floppyReturn: OnlineDiagnostics.FloppyReturn] = BEGIN DiagnosticsOps.PutLine[ SELECT floppyReturn FROM deviceNotReady => "The floppy disk unit isn't ready."L, notDiagDiskette => "The floppy diskette isn't the Diagnostic Diskette."L, floppyFailure => "An error was found."L, ENDCASE => "No error was found."L]; END; FloppyFinished: PROCEDURE [errFlag: BOOLEAN ← FALSE ] = BEGIN DiagnosticsOps.running ← FALSE; DiagnosticsOps.PutLine[IF errFlag THEN "Aborted..."L ELSE "Floppy diagnostic finished."L]; DiagnosticsOps.PutCR[]; END; -- These routines are for displaying either a number of fields of data or an entire table of fields of data. The title parameter is displayed prior to display of the data. If no title is wished, the client may omit this parameter. The fieldType parameter is used to determine how to interpret the data to be displayed, whether as boolean, character, cardinal, etc. DisplayFields: OnlineDiagnostics.DisplayFieldsProc = BEGIN --"fields" contains the data to be displayed: the name of the field is paired with its value. "numberOfColumns" is the number of columns that the client wishes the fields to be displayed in; if this parameter is omitted, the default number of columns is three. screenWidth: CARDINAL = 80; columnWidth, fieldNameWidth, thisColumnNumber: CARDINAL; str: LONG STRING = [screenWidth]; IF numberOfColumns = 0 THEN RETURN; columnWidth ← screenWidth/numberOfColumns; fieldNameWidth ← 0; FOR a: CARDINAL IN [0..LENGTH[fields]) DO str.length ← 0; AppendMessageText[str, fields[a].fieldName]; fieldNameWidth ← MAX[fieldNameWidth, str.length + 1]; ENDLOOP; fieldNameWidth ← MIN[ fieldNameWidth, columnWidth - ((SELECT fieldType FROM boolean, character => 1, cardinal => 5, hexadecimal => 4, hexbyte => 2, integer => 6, octal => 7, ENDCASE => 10) + 2)]; IF title # tFirst THEN DiagnosticsOps.PutMessage[title]; thisColumnNumber ← 0; FOR a: CARDINAL IN [0..LENGTH[fields]) DO str.length ← 0; AppendMessageText[str, fields[a].fieldName]; IF str.length > fieldNameWidth THEN str.length ← fieldNameWidth; DiagnosticsOps.PutText[str, fieldNameWidth]; str.length ← 0; AppendFieldData[str, fields[a].fieldValue, fieldType]; DiagnosticsOps.PutText[str]; IF thisColumnNumber >= numberOfColumns THEN BEGIN thisColumnNumber ← 0; DiagnosticsOps.PutCR[]; END ELSE BEGIN thisColumnNumber ← thisColumnNumber + 1; DiagnosticsOps.PutText[" "L]; END; DiagnosticsOps.CheckForAbort[]; ENDLOOP; DiagnosticsOps.PutCR[]; END; DisplayTable: OnlineDiagnostics.DisplayTableProc = BEGIN --"headers" are the strings displayed at the tops of the columns of data. "rowNames" are the strings displayed at the beginning of each row of data. "values" are the values of the data which is to be displayed; value[c][r] is displayed in row r of column c. screenWidth: CARDINAL = 80; fieldWidth, rowNameWidth: CARDINAL; str: LONG STRING = [screenWidth]; rowNameWidth ← 0; FOR r: CARDINAL IN [0..LENGTH[rowNames]) DO str.length ← 0; AppendMessageText[str, rowNames[r]]; rowNameWidth ← MAX[rowNameWidth, str.length + 2]; ENDLOOP; fieldWidth ← (SELECT fieldType FROM boolean, character => 1, cardinal => 5, hexadecimal => 4, hexbyte => 2, integer => 6, octal => 8, ENDCASE => 10) + 2; FOR c: CARDINAL IN [0..LENGTH[headers]) DO str.length ← 0; AppendMessageText[str, headers[c]]; fieldWidth ← MAX[fieldWidth, str.length + 2]; ENDLOOP; fieldWidth ← MAX[ fieldWidth, ((screenWidth - rowNameWidth)/LENGTH[headers])]; IF title # tFirst THEN DiagnosticsOps.PutMessage[title]; THROUGH [0..rowNameWidth) DO DiagnosticsOps.PutChar[' ]; ENDLOOP; FOR c: CARDINAL IN [0..LENGTH[headers]) DO str.length ← 0; AppendMessageText[str, headers[c]]; DiagnosticsOps.PutTextCentered[str, fieldWidth]; ENDLOOP; DiagnosticsOps.PutCR[]; FOR r: CARDINAL IN [0..LENGTH[rowNames]) DO str.length ← 0; AppendMessageText[str, rowNames[r]]; DiagnosticsOps.PutText[str, rowNameWidth]; FOR c: CARDINAL IN [0..LENGTH[headers]) DO str.length ← 0; AppendFieldData[str, values[c][r], fieldType]; DiagnosticsOps.PutTextCentered[str, fieldWidth]; ENDLOOP; DiagnosticsOps.PutCR[]; DiagnosticsOps.CheckForAbort[]; ENDLOOP; END; DisplayNumberedTable: OnlineDiagnostics.DisplayNumberedTableProc = BEGIN -- Numbers are displayed at the beginning of each row of data, beginning with "startNum." The "rowNameHeader," if any, is displayed at the top of the numbers at the beginning of the rows. "values" are the values of the data which is to be displayed; values[r*numOfColumns + c] is displayed in row r of column c (rows and columns are numbered starting with 0). screenWidth: CARDINAL = 80; fieldWidth, rowNameWidth: CARDINAL; str: LONG STRING = [screenWidth]; index: CARDINAL ← 0; str.length ← 0; AppendMessageText[str, rowNameHeader]; rowNameWidth ← MAX[5, str.length + 2]; fieldWidth ← (SELECT fieldType FROM boolean, character => 1, cardinal => 5, hexadecimal => 4, hexbyte => 2, integer => 6, octal => 8, ENDCASE => 10) + 2; fieldWidth ← MAX[fieldWidth, ((screenWidth - rowNameWidth)/numOfColumns)]; IF title # tFirst THEN DiagnosticsOps.PutMessage[title]; DiagnosticsOps.PutText[str, rowNameWidth]; FOR c: CARDINAL IN [0..numOfColumns) DO str.length ← 0; String.AppendNumber[ str, c, SELECT numOfColumns FROM 8 => 8, 16 => 16, ENDCASE => 10]; DiagnosticsOps.PutTextCentered[str, fieldWidth]; ENDLOOP; DiagnosticsOps.PutCR[]; index ← 0; UNTIL index > LENGTH[values] DO str.length ← 0; String.AppendNumber[ str, startNum + index, SELECT numOfColumns FROM 8 => 8, 16 => 16, ENDCASE => 10]; DiagnosticsOps.PutText[str, rowNameWidth]; THROUGH [0..numOfColumns) UNTIL index > LENGTH[values] DO str.length ← 0; AppendFieldData[str, values[index], fieldType]; DiagnosticsOps.PutTextCentered[str, fieldWidth]; index ← index + 1; ENDLOOP; DiagnosticsOps.PutCR[]; DiagnosticsOps.CheckForAbort[]; ENDLOOP; END; AppendFieldData: PROCEDURE [ str: LONG STRING, value: UNSPECIFIED, fieldType: OnlineDiagnostics.FieldDataType] = BEGIN StrProc: Format.StringProc = BEGIN String.AppendString[str, s]; END; SELECT fieldType FROM boolean => Format.Char[StrProc, IF LOOPHOLE[value, BOOLEAN] THEN 'T ELSE 'F]; cardinal => Format.Number[ StrProc, LOOPHOLE[value, CARDINAL], Format.NumberFormat[ 10, FALSE, TRUE, 5]]; character => Format.Char[ StrProc, SELECT LOOPHOLE[value, CHARACTER] FROM IN [' ..'↑], IN [140C..'~] => LOOPHOLE[value, CHARACTER], ENDCASE => Ascii.ControlG]; hexadecimal => Format.Number[ StrProc, LOOPHOLE[value, CARDINAL], Format.NumberFormat[ 16, TRUE, TRUE, 4]]; hexbyte => Format.Number[ StrProc, LOOPHOLE[value, CARDINAL] MOD 256, Format.NumberFormat[ 16, TRUE, TRUE, 2]]; integer => Format.Number[ StrProc, LOOPHOLE[value, INTEGER], Format.NumberFormat[ 10, FALSE, FALSE, 6]]; octal => BEGIN Format.Number[ StrProc, LOOPHOLE[value, CARDINAL], Format.NumberFormat[ 8, FALSE, TRUE, 6]]; Format.Char[StrProc, 'B]; END; ENDCASE => BEGIN temp: LONG STRING = [30]; temp.length ← 0; --AppendMessageText[temp, LOOPHOLE[value, OnlineDiagnostics.FloppyMessage]]; String.AppendString[temp, LOOPHOLE[value, STRING]]; Format.LongString[StrProc, temp]; Format.Blanks[StrProc, 10 - temp.length]; END; END; PutMessage: PUBLIC OnlineDiagnostics.PutMessageProc = BEGIN text: LONG STRING = [100]; text.length ← 0; AppendMessageText[text, msg]; DiagnosticsOps.PutLine[text]; DiagnosticsOps.CheckForAbort[]; END; AppendMessageText: PROCEDURE [ text: LONG STRING, msg: OnlineDiagnostics.FloppyMessage] = BEGIN String.AppendString[ text, SELECT msg FROM cFirst => "cFirst"L, cCallCSC => "Please call the CSC; tell them the maintenance-panel code."L, cCloseWn => "cCloseWn"L, cEnsureReady => "Ensure that the floppy disk unit is ready and the door closed."L, cExit => "That's all, folks!"L, cInsDiffCleanDisk => "Please insert a different head-cleaning diskette."L, cInsertCleanDisk => "Please insert a head-cleaning diskette."L, cInsertDiagDisk => "Please insert the diagnostic floppy disk. (1)"L, cInsertWriteable => "Please insert a diskette that is not write-protected."L, cNBNotReady => "Note that the floppy disk unit is not ready."L, cOtherDiskErr => "Note: Any other diskette will cause erroneous results."L, cRemoveCleanDisk => "Please remove the head-cleaning diskette from the unit."L, cRemoveDiskette => "Please remove the diskette from the unit and leave door open."L, cLast => "cLast"L, hFirst => "hFirst"L, hBusy => " Busy"L, hExpec1 => " Expected = "L, hExpec2 => "EXPECTED"L, hCRC1 => "CRC Byte 1"L, hCRC2 => "CRC Byte 2"L, hCRCErr => " CRC Error"L, hDelSector => " Deleted Sector"L, hDiskChng => " Disk Changed"L, hErrDetc => " Error Detected"L, hGoodComp => " Good Completion"L, hHead => " Head"L, hHeadAddr => "Head Address"L, hIllglStat => " Illegal Status"L, hIncrtLngth => " Incorrect Length"L, hObser1 => " Observed = "L, hObser2 => "OBSERVED"L, hReadHead => "Read Header"L, hReadSector => "Read Sector"L, hReadStat => "Read Status"L, hReady => " Ready"L, hRecal => "Recalibrate"L, hRecalErr => " Recalibrate Error"L, hSector => " Sector"L, hSectorAddr => "Sector Address"L, hSectorCntErr => " Sector Count Error"L, hSectorLgth => "Sector Length"L, hSeekErr => " Seek Error"L, hTimeExc => "TIMES EXECUTED"L, hTrack => " Track"L, hTrack0 => " Track 00"L, hTrackAddr => "Track Address"L, hTwoSide => " Double Sided"L, hWriteDelSector => "Write Deleted Sectors"L, hWritePro => " Write Protected"L, hWriteSector => "Write Sectors"L, hLast => "hLast"L, iFirst => "iFirst"L, iBadContext => "Can't set context."L, iBadLabel => "Bad label area."L, iBadSector => "Bad sector found."L, iBadTrack0 => "Bad track 0."L, iCheckPanel => "Check the MP code and possibly the Summary Error Log."L, iCIERec => "Command in error: Recalibrate"L, iCleanDone => "Head cleaning completed"L, iCleanProgress => "Head cleaning in progress."L, iErrDet => " Error Detected"L, iErrNoCRCErr => "A data error without a CRC error has occured."L, iExerWarning => "Warning: This test will destroy the contents of the diskette."L, iFormDone => "Formatting successfully completed."L, iFormProgress => "Formatting in progress."L, iFormWarning => "Warning: Formatting will destroy the contents of the diskette."L, iHardErr => "A hard error has occured."L, iHeadDataErr => " A HEADER DATA ERROR HAS OCCURED."L, iInsertDiagDisk => "Please insert the diagnostic floppy disk. (2)"L, iInsertFormDisk => "Please insert a formatted diskette."L, iOneSided => "This is a single-sided diskette."L, iRunStdTest => "Please run the standard test of the floppy disk unit."L, iSoftErr => "Too many soft errors have occured."L, iTnx => "Thank you"L, iTwoSided => "This is a double-sided diskette."L, iUnitNotReady => "The floppy disk unit is still not ready."L, iVerDataErr => " A VERIFY DATA ERROR HAS OCCURED."L, iLast => "iLast"L, tFirst => "tFirst"L, tByteCnt => "Byte Count"L, tCIERH => "Command in error: Read Header"L, tCIERS => "Command in error: Read Sectors"L, tCIEVer => "Command in error: Verify"L, tCIEWDS => "Command in error: Write Deleted Sectors"L, tCIEWS => "Command in error: Write Sectors"L, tHeadDataErr => " A HEADER DATA ERROR HAS OCCURED."L, tHeadDisp => "FLOPPY DISK HEADER DISPLAY IN HEXADECIMAL"L, tHeadErrDisp => "FLOPPY DISK HEADER ERROR DISPLAY IN HEXADECIMAL"L, tSectorDisp => "FLOPPY SECTOR DISPLAY"L, tStatDisp => "FLOPPY STATUS DISPLAY"L, tSummErrLog => "SUMMARY ERROR LOG"L, tVerDataErr => " A VERIFY DATA ERROR HAS OCCURED."L, tLast => "tLast"L, yFirst => "yFirst"L, yDispSects => "Display the sectors with the last data error?"L, yDispExpObsData => "Display the header-error expected and observed data?"L, yDoorJustOpened => "Was the floppy disk unit door just opened?"L, yDoorOpenNow => "Is the floppy disk unit door open now?"L, yDoorOpenShut => "Was the floppy disk unit door just opened and closed again?"L, yIsItDiagDisk => "Is the diskette the diagnostic floppy disk?"L, yIsItWrProt => "Is the diskette write-protected?"L, yStillContinue => "Do you still wish to continue?"L, yStillSure => "Are you still sure?"L, yLast => "yLast"L, ENDCASE => "Unknown floppy message?!?"L]; END; END.