-- BruceToBinary.mesa
-- Created by Barth
-- Last edited by Barth, December 6, 1981  5:48 PM
-- Last edited by Chi Yung, January 5, 1982  2:11 PM
-- Last edited by Chi Yung Fu, January 28, 1982  10:27 AM
-- Last edited by Chi Yung Fu, March 26, 1982  3:02 PM
-- Last edited by Chi Yung Fu, April 30, 1982  2:39 PM
-- Last edited by Chi Yung Fu, August 9, 1983  11:21 AM
-- Last edited by Chi Yung Fu, September 1, 1983  11:20 AM
-- Last edited by J.White, 24-Apr-85 17:58:32

DIRECTORY
  Ascii,
  BruceDefs,
  MachineParseDefs,
  vmD: FROM "VirtualMgrDefs";

BruceToBinary: PROGRAM
  IMPORTS MachineParseDefs
  EXPORTS BruceDefs =
BEGIN

OPEN MachineParseDefs;

MinProfiledTemp:CARDINAL ← 0; 
MaxProfiledTemp:CARDINAL ← 12000;
MaxTempRangeScale:CARDINAL ← 15000;
--This change is implemented on July 31, 1982
--This MaxTempRangeScale is for the last column in the coefficient table.
--The Max entry there is 14990.

MinGasFlowConversion: CARDINAL ← 0;
MaxGasFlowConversion: CARDINAL ← 9999;

TempScaledFactor: CARDINAL ← 1;
GasScaledFactor: CARDINAL ← 2;

AsciiToBinary: PUBLIC PROCEDURE [vmp:vmD.VirtualMessagePtr,
  brp:BruceDefs.RecipePtr]=
BEGIN
  ph:ParseHandle ← @pd;
  pd:ParseData;
  fields: ARRAY [0 .. 6) OF FieldRec ←
    [["Interval"L, ParseInterval], ["AlarmMask/AbortDestination"L,
    ParseAlarm], ["TemperatureSetpoint"L, ParseTempTable], ["GasSetpoint"L,
    ParseGasTable], ["BoatSpeed"L, ParseBoatControl], ["Coefficient"L,
    ParseCoefficient]];
  pd.breakSet ← ":."L;
  pd.blankSet ← " 	
"L;
  ph.message ← vmp;
  pd.userData ← brp;
  ParseMessage[ph, DESCRIPTOR[fields]];
END; -- of AsciiToBinary

ParseMult: PROCEDURE[ph:ParseHandle] RETURNS[m:CARDINAL]=
BEGIN
  m ← ParseDecimal[ph]*10;
  CheckChar[ph, '.];
  m ← m + ParseDecimal[ph];
END; -- of ParseMult


ParseTemp: PUBLIC PROCEDURE[ph:ParseHandle, MinProfiledTemp:CARDINAL, MaxProfiledTemp:CARDINAL] RETURNS[t,tNumberOfDigits:CARDINAL]=
BEGIN
  [t,tNumberOfDigits] 
  ← ParseScaledNumber[ph, TempScaledFactor, MinProfiledTemp, 
  MaxProfiledTemp];
  ParseToNonWhite[ph];
  CheckChar[ph, Ascii.ControlD];
  ParseToNonWhite[ph];
  CheckChar[ph, 'C];
END; -- of ParseTemp

ParseGas: PUBLIC PROCEDURE[ph:ParseHandle, MinGasFlowConversion: CARDINAL,
MaxGasFlowConversion: CARDINAL] RETURNS[g,gNumberOfDigits:CARDINAL]=
BEGIN
  curPos: vmD.CharIndex;
  curPos ← ph.currentChar;
  [g,gNumberOfDigits] ← ParseScaledNumber[ph, GasScaledFactor, 
  MinGasFlowConversion, MaxGasFlowConversion*50];
  ParseToNonWhite[ph];
  IF ParseCharIfCharIs[ph, 'L] = FALSE THEN BEGIN
    IF ParseCharIfCharIs[ph, 'C] = FALSE THEN ERROR ParseFault
    ["The character here should be either l or cc.",
    ph.currentChar, ph.currentChar+1] ELSE
    CheckChar[ph,'C];
    THROUGH[1..GasScaledFactor] DO
     g ← g/10;
     ENDLOOP;
    g ← g*2;  -- because of the way the Gas flow calibration table is set up
  END ELSE BEGIN
    ph.currentChar ← curPos;
    [g,gNumberOfDigits] ← ParseScaledNumber[ph, GasScaledFactor,
     MinGasFlowConversion,MaxGasFlowConversion];
    ParseToNonWhite[ph];
    CheckChar[ph,'L];
  END;
  ParseToNonWhite[ph];
  CheckChar[ph, '/];
  ParseToNonWhite[ph];
  CheckChar[ph, 'M];
END; -- of ParseGas

ParseInterval: FieldParseProc=
BEGIN
i:BruceDefs.IntervalIndex;
rp:BruceDefs.RecipePtr ← ph.userData;
WHILE ParseToLeadingChar[ph] DO
  i ← ParseDecimal[ph,0,30];
  [rp.interval[i].hours, rp.interval[i].minutes, rp.interval[i].seconds]
    ← ParseTime[ph];
  rp.interval[i].controlAlg ← ParseNibble[ph,0,10];
  -- the upper bound value,10, allow us to enter the code a beside 0, 4 and 8.
  rp.interval[i].tempAlarm ← ParseNibble[ph,10,13];
  rp.interval[i].gasTempControl ← rp.interval[i].gasTempControl MOD 10 +
    10*ParseDecimal[ph,0,8];
  rp.interval[i].gasAlarm ← ParseNibble[ph,10,13];
  rp.interval[i].gasTempControl ← (rp.interval[i].gasTempControl/10)*10
    + ParseDecimal[ph,0,8];
  rp.interval[i].controlCoeff ← ParseNibble[ph,10,13];
  rp.interval[i].abortGroup ← ParseNibble[ph,10,13];
  FOR j: CARDINAL DECREASING IN [1..8] DO
    rp.interval[i].function1[j] ← ParseBinary[ph];
  ENDLOOP;
  FOR j: CARDINAL DECREASING IN [1..4] DO
    rp.interval[i].function2[j] ← ParseBinary[ph];
  ENDLOOP;
  FOR j: CARDINAL DECREASING IN [1..6] DO
    rp.interval[i].function3[j] ← ParseBinary[ph];
  ENDLOOP;
ENDLOOP;
END; -- of ParseInterval

ParseAlarm: FieldParseProc=
BEGIN
i:BruceDefs.AlarmIndex;
rp:BruceDefs.RecipePtr ← ph.userData;
WHILE ParseToLeadingChar[ph] DO
  i ← ParseNibble[ph,10,13,FALSE] - 9;
  FOR j:CARDINAL DECREASING IN [7..16] DO
    rp.alarm[i].binaryMask[j] ← ParseBinary[ph];
  ENDLOOP;
  FOR j: CARDINAL DECREASING IN [3..8] DO
    rp.alarm[i].tempMask[j] ← ParseBinary[ph];
  ENDLOOP;
  FOR j: CARDINAL DECREASING IN [2..8] DO
    rp.alarm[i].gasMask[j] ← ParseBinary[ph];
  ENDLOOP;
  FOR j: CARDINAL DECREASING IN [6..8] DO
    rp.alarm[i].softMask[j] ← ParseBinary[ph];
  ENDLOOP;
  rp.alarm[i].destInterval ← ParseDecimal[ph,0,30];
ENDLOOP;
END; -- of ParseAlarm

ParseTempTable: FieldParseProc=
BEGIN
i:BruceDefs.TempRowIndex;
rp:BruceDefs.RecipePtr ← ph.userData;
WHILE ParseToLeadingChar[ph] DO
  i ← ParseNibble[ph,1,12,FALSE];
  IF i>8 THEN BEGIN
    IF i<10 THEN ParseFault["Illegal temperature row",ph.currentChar-1,
    ph.currentChar];
    rp.abortMultipliers.temp[i - 9] ← ParseScaledNumber[ph, 1, 0, 99].n;
    -- The scale factor is 1. The lower bound is 0 and upper bound is 9.9.
    -- [i - 9] because a=10. So when  i = a we actually have i = 10 but the 
    -- j in the rp.abortMultipliers.temp[j] can only take on the value 1,2 or 
    -- 3 because of the constraint of the BruceDefs.mesa. Therefore we 
    -- substract 9 to get back to 1, 2, or 3.
    -- TO DEACTIVATE THE ABORT.MULTIPLIERS, DELETE THE -9 FROM [i - 9 ], THIS
    -- WILL READ THE NUMBER FROM THE TEMP TABLE BUT DUMP IT AWAY.
  END;
  IF i=10 THEN FOR j:BruceDefs.TempColIndex IN BruceDefs.TempColIndex DO
    rp.alert.temp[j] ← ParseScaledNumber[ph, TempScaledFactor,0, 500].n;
  -- The lower bound is 0C and upper bound is 50C.
  -- TO DEACTIVATE THE ALERT ROW ( ROW A ), JUST CHANGE THE FOLLOWING 
  -- STATEMENT FROM i<10 TO i<11 , THIS WILL DUMP THE A ROW AWAY SINCE THE 
  -- rp.temp IS DEFINED FOR ONLY 8 ROWS.
  ENDLOOP;
  IF i<10 THEN FOR j:BruceDefs.TempColIndex IN BruceDefs.TempColIndex DO
    rp.temp[i][j] ← ParseScaledNumber[ph, TempScaledFactor,MinProfiledTemp,   MaxProfiledTemp].n;
  ENDLOOP;
ENDLOOP;
END; -- of ParseTempTable

ParseGasTable: FieldParseProc=
BEGIN
i:BruceDefs.GasRowIndex;
rp:BruceDefs.RecipePtr ← ph.userData;
WHILE ParseToLeadingChar[ph] DO
  i ← ParseNibble[ph,1,12,FALSE];
  IF i>8 THEN BEGIN
    IF i<10 THEN ParseFault["Illegal gas row",ph.currentChar-1,
    ph.currentChar];
    rp.abortMultipliers.gas[i - 9] ← ParseScaledNumber[ph, 1, 0, 99].n;
    -- The scale factor is 1. The lower bound is 0 and upper bound is 9.9.
    -- [i - 9] because a=10. So when  i = a we actually have i = 10 but the 
    -- j in the rp.abortMultipliers.temp[j] can only take on the value 1,2 or 
    -- 3 because of the constraint of the BruceDefs.mesa. Therefore we 
    -- substract 9 to get back to 1, 2, or 3.
  END;
  IF i=10 THEN FOR j:BruceDefs.GasColIndex IN BruceDefs.GasColIndex DO
    rp.alert.gas[j] ← ParseScaledNumber[ph, GasScaledFactor,0, 500].n;
  -- The lower bound is 0% and upper bound is 5%.
  ENDLOOP;
  IF i<10 THEN FOR j:BruceDefs.GasColIndex IN BruceDefs.GasColIndex DO
    rp.gas[i][j] 
    ← ParseScaledNumber[ph, GasScaledFactor,MinGasFlowConversion, 
  MaxGasFlowConversion].n;
  ENDLOOP;
ENDLOOP;
END; -- of ParseGasTable

ParseBoatControl: FieldParseProc=
BEGIN
ParseSubTable:PROCEDURE[ph:ParseHandle, br: POINTER TO BruceDefs.BoatRows]=
BEGIN
  s:STRING ← [6];
  FOR i:BruceDefs.BoatRowIndex IN BruceDefs.BoatRowIndex DO
    IF ~ParseToLeadingChar[ph] THEN
    ERROR ParseFault["Data for Boat Speed Missing", ph.currentChar-1,
    ph.currentChar];
    THROUGH [1..IF i=1 THEN 3 ELSE 1] DO ParseWord[ph,s] ENDLOOP;
    FOR j:BruceDefs.BoatSegmentIndex IN BruceDefs.BoatSegmentIndex DO
      br[i][j].speed ← ParseDecimal[ph,0,99];
      br[i][j].distance ← ParseDecimal[ph,0,99];
    ENDLOOP;
  ENDLOOP;
END; -- of ParseSubTable
rp:BruceDefs.RecipePtr ← ph.userData;
ParseSubTable[ph, @rp.boat.in];
ParseSubTable[ph, @rp.boat.out];
ParseToEndOfField[ph];
END; -- of ParseBoatControl

ParseCoefficient: FieldParseProc=
BEGIN
b,c:CHARACTER;
rp:BruceDefs.RecipePtr ← ph.userData;
FOR i:BruceDefs.FactorIndex IN BruceDefs.FactorIndex DO
  IF ~ParseToLeadingChar[ph] THEN
  ERROR ParseFault["Data for Coefficient Missing", ph.currentChar-1,
  ph.currentChar];
  b ← ParseChar[ph];
  IF i # b - '@ THEN
  SELECT i FROM
    = 1 => ERROR ParseFault["Row A of Coefficient Table is missing",
                               ph.currentChar - 2, ph.currentChar];
    = 2 => ERROR ParseFault["Row B of Coefficient Table is missing",
                               ph.currentChar - 2, ph.currentChar];
    = 3 => ERROR ParseFault["Row C of Coefficient Table is missing",
                               ph.currentChar - 2, ph.currentChar]; 
    = 4 => ERROR ParseFault["Row D of Coefficient Table is missing",
                               ph.currentChar - 2, ph.currentChar]; 
  ENDCASE; 
  FOR j:BruceDefs.ZoneIndex IN BruceDefs.ZoneIndex DO
    IF ~ParseToLeadingChar[ph] THEN
    ERROR ParseFault
    ["Part of the Data for the Coefficient Table is missing",
    ph.currentChar-1, ph.currentChar];
    c ← ParseChar[ph];
    IF j # c - '0 THEN
    SELECT j FROM
      = 1 => ERROR ParseFault["Zone 1 of Coefficient Table is missing",
                               ph.currentChar - 1, ph.currentChar];
      = 2 => ERROR ParseFault["Zone 2 of Coefficient Table is missing",
                               ph.currentChar - 1, ph.currentChar];
      = 3 => ERROR ParseFault["Zone 3 of Coefficient Table is missing",
                               ph.currentChar - 1, ph.currentChar]; 
    ENDCASE; 
    rp.control.factorArray[i].calibration[j] ← ParseDecimal[ph];
    rp.control.factorArray[i].latency[j] ← ParseDecimal[ph];
    rp.control.factorArray[i].outerLoopRate[j] ← ParseDecimal[ph];
    rp.control.factorArray[i].rate[j] ← ParseDecimal[ph];
    rp.control.factorArray[i].reset[j] ← ParseDecimal[ph];
    rp.control.factorArray[i].proportionalBand[j] ← ParseDecimal[ph];
    IF j=FIRST[BruceDefs.ZoneIndex] THEN 
    rp.tempRange[i] ← ParseScaledNumber[ph, TempScaledFactor,
    MinProfiledTemp, MaxTempRangeScale].n;
  ENDLOOP;
ENDLOOP;
IF ~ParseToLeadingChar[ph] THEN
ERROR ParseFault["WierdIndex is missing from the Coefficient Table", 
ph.currentChar-5, ph.currentChar];
FOR i:BruceDefs.WierdIndex IN BruceDefs.WierdIndex DO
  rp.control.wierdStuff[i] ← ParseDecimal[ph];
ENDLOOP;
ParseToEndOfField[ph];
END; -- of ParseCoefficient

END.