-- 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

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];
g ← g*2;
THROUGH[1..GasScaledFactor] DO
g ← g/10;
ENDLOOP;
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.