/* Copyright (c) 2023-forever Douglas Malnati. All rights reserved. See the /faq/tos page for details. (If this generated header is stamped on a file which is a 3rd party file or under a different license or copyright, then ignore this copyright statement and use that file's terms.) */ import { WSPREncoded } from '/js/WSPREncoded.js'; import { StrAccumulator } from '/js/Utl.js'; export class WsprCodecMaker { constructor() { this.debug = false; this.codec = ""; this.json = {}; this.errList = []; this.CodecClass = null; this.SetCodecDefFragment("MyMessageType", ""); } SetDebug(debug) { this.debug = debug; } GetFieldBitsAvailable() { const BITS_AVAILABLE = 29.180; return BITS_AVAILABLE; } // allow setting just name and fields, don't worry about object structure SetCodecDefFragment(msgName, codecFragment) { // support comments in input by eliminating lines with comment char before them let codecDefLineList = []; for (let line of codecFragment.split("\n")) { line = line.trim(); if (line.substring(0, 2) != "//") { codecDefLineList.push(line); } } let codecFragmentUse = codecDefLineList.join("\n"); // attempt to parse the fragment as valid json so that decent error messages // can be returned to users if it's busted this.ResetErrList(); let ok = true; try { // expected to have a trailing comma let fakeCodec = `{ "fieldList": [ ${codecFragmentUse}\n\n {}] }`; let json = JSON.parse(fakeCodec); } catch (e) { ok = false; this.AddErr(e); } if (ok) { let finalFieldFragment = ` { "name": "HdrSlot", "unit": "Enum", "lowValue": 0, "highValue": 4, "stepSize": 1 }, { "name": "HdrType", "unit": "Enum", "lowValue": 0, "highValue": 15, "stepSize": 1 }, { "name": "HdrRESERVED", "unit": "Enum", "lowValue": 0, "highValue": 3, "stepSize": 1 }, { "name": "HdrTelemetryType", "unit": "Enum", "lowValue": 0, "highValue": 1, "stepSize": 1 } `; // assumes the input's codeFragment ends with a comma if there are fields let codec = ` { "name": "${msgName}", "fieldList": [ ${codecFragmentUse} ${finalFieldFragment}] }`; ok = this.SetCodecDef(codec); } return ok; } SetCodecDef(codec) { this.codec = codec; let ok = this.ParseCodecDef(this.codec); if (ok) { this.Calculate(); this.#MakeCodecClass(); } return ok; } GetErrList() { return this.errList; } ResetErrList() { this.errList = []; } AddErr(err) { this.errList.push(err); if (this.debug) { console.log(err); } } #IsValueSegmentList(field) { return Array.isArray(field.valueSegmentList); } #IsSegmentedField(field) { return this.#IsValueSegmentList(field); } #IsPositiveNumber(value) { return typeof value == "number" && Number.isFinite(value) && value > 0; } #IsWholeNumberClose(value, epsilon = 1e-9) { return Math.abs(value - Math.round(value)) < epsilon; } #ValidateScalarField(field) { let ok = true; let stepCount = (field.highValue - field.lowValue) / field.stepSize; if (this.#IsWholeNumberClose(stepCount) == false) { ok = false; let err = `Field(${field.name}) stepSize(${field.stepSize}) does not evenly divide the low(${field.lowValue})-to-high(${field.highValue}) range.`; let factorList = []; if (Number.isInteger(field.lowValue) && Number.isInteger(field.highValue)) { for (let stepSize = 1; stepSize < ((field.highValue - field.lowValue) / 2); ++stepSize) { let stepCountNew = (field.highValue - field.lowValue) / stepSize; if (Number.isInteger(stepCountNew)) { factorList.push(stepSize); } } if (factorList.length) { err += `\n`; err += ` Whole integer steps are: ${factorList.join(", ")}.`; } } this.AddErr(err); } return ok; } #ValidateValueSegmentListField(field) { let ok = true; if (this.#IsValueSegmentList(field) == false || field.valueSegmentList.length == 0) { this.AddErr(`Field(${field.name}) valueSegmentList must be a non-empty array.`); return false; } let prevHigh = null; for (let i = 0; i < field.valueSegmentList.length; ++i) { const segment = field.valueSegmentList[i]; if (Array.isArray(segment) == false || segment.length != 3) { ok = false; this.AddErr(`Field(${field.name}) valueSegmentList[${i}] must be [low, step, high].`); continue; } const [low, step, high] = segment; if ([low, step, high].every((value) => typeof value == "number" && Number.isFinite(value))) { if (low >= high) { ok = false; this.AddErr(`Field(${field.name}) segment ${i + 1} low(${low}) must be less than high(${high}).`); } if (step <= 0) { ok = false; this.AddErr(`Field(${field.name}) segment ${i + 1} step(${step}) must be greater than zero.`); } const stepCount = (high - low) / step; if (this.#IsWholeNumberClose(stepCount) == false) { ok = false; this.AddErr(`Field(${field.name}) segment ${i + 1} step(${step}) does not evenly divide the low(${low})-to-high(${high}) range.`); } if (prevHigh != null && Math.abs(prevHigh - low) > 1e-9) { ok = false; this.AddErr(`Field(${field.name}) segment ${i + 1} low(${low}) must equal prior segment high(${prevHigh}).`); } prevHigh = high; } else { ok = false; this.AddErr(`Field(${field.name}) valueSegmentList[${i}] values must all be finite numbers.`); } } return ok; } #MakeSegmentListFromValueSegmentList(field) { let segmentList = []; for (let i = 0; i < field.valueSegmentList.length; ++i) { const [low, step, high] = field.valueSegmentList[i]; const isLast = i == field.valueSegmentList.length - 1; const rawCount = Math.round((high - low) / step); const count = isLast ? rawCount + 1 : rawCount; segmentList.push({ low, high, step, isLast, count, }); } return segmentList; } #ValidateField(field) { let ok = true; const isValueSegmented = this.#IsValueSegmentList(field); const propList = [ "unit", ...(isValueSegmented ? ["valueSegmentList"] : ["lowValue", "highValue", "stepSize"]), ]; let IsInvalidString = (str) => { return str.trim() == "" || str.trim() != str || str.indexOf(' ') !== -1; }; let HasInvalidChar = (str) => { return /[^a-zA-Z0-9_]/.test(str); }; for (const prop of propList) { if (prop in field == false) { ok = false; this.AddErr(`No "${prop}" property in field(${field.name})`); } else if (prop == "unit") { if (IsInvalidString(field[prop].toString())) { ok = false; this.AddErr(`Field name "${prop}" cannot be blank or have whitespace`); } else if (HasInvalidChar(field[prop].substring(1))) { ok = false; this.AddErr(`Field name "${field.name}" must only have alphanumeric characters or underscore (_) after first character`); } } else if (prop == "valueSegmentList") { if (this.#ValidateValueSegmentListField(field) == false) { ok = false; } } else if (prop == "stepSize") { let validStepSize = false; if (typeof field.stepSize == "number") { validStepSize = this.#IsPositiveNumber(field.stepSize); } else if (Array.isArray(field.stepSize)) { ok = false; this.AddErr(`Field(${field.name}) stepSize must be a positive number.`); continue; } if (validStepSize == false) { ok = false; this.AddErr(`Field(${field.name}) stepSize(${JSON.stringify(field.stepSize)}) must be a positive number`); } } else if (typeof field[prop] != "number" || Number.isFinite(field[prop]) == false) { ok = false; this.AddErr(`Field value "${prop}" = ${field[prop]} must be a number`); } } if (ok && this.#IsValueSegmentList(field) == false && field.lowValue >= field.highValue) { ok = false; this.AddErr(`Field(${field.name}) lowValue(${field.lowValue}) must be less than highValue(${field.highValue})`); } if (ok) { if (this.#IsValueSegmentList(field)) { ok = this.#ValidateValueSegmentListField(field); } else { ok = this.#ValidateScalarField(field); } } return ok; } #PrepareField(field) { let bits = 0; let numValues = 0; let indexCount = 0; let enumCount = this.#IsSegmentedField(field) ? field.valueSegmentList.length : 1; let segmentList = []; if (this.#IsValueSegmentList(field)) { segmentList = this.#MakeSegmentListFromValueSegmentList(field); numValues = segmentList.reduce((acc, segment) => acc + segment.count, 0); indexCount = 0; field.lowValue = segmentList[0].low; field.highValue = segmentList[segmentList.length - 1].high; field.stepSize = segmentList.map((segment) => segment.step); } else { let stepCount = Math.round((field.highValue - field.lowValue) / field.stepSize); indexCount = stepCount + 1; numValues = indexCount; } if (segmentList.length) { let base = 0; for (const segment of segmentList) { segment.base = base; base += segment.count; } } bits = Math.log2(numValues); field.EnumCount = enumCount; field.IndexCount = indexCount; field.NumValues = numValues; field.Bits = bits; field.IsSegmented = this.#IsSegmentedField(field); if (field.IsSegmented) { field.SegmentList = segmentList; } else { delete field.SegmentList; } } ParseCodecDef(codec) { let ok = true; if (this.debug) { console.log(codec); } this.ResetErrList(); try { let json = JSON.parse(codec); // validate basic structure if ("name" in json == false) { ok = false; this.AddErr(`No "name" property for codec`); } else if ("fieldList" in json == false) { ok = false; this.AddErr(`No "fieldList" property for codec`); } else { let fieldNameSet = new Set(); let IsInvalidString = (str) => { return str.trim() == "" || str.trim() != str || str.indexOf(' ') !== -1; }; let HasInvalidChar = (str) => { return /[^a-zA-Z0-9_]/.test(str); }; for (const field of json.fieldList) { if ("name" in field == false) { ok = false; this.AddErr(`No "name" property in field`); } else if (fieldNameSet.has(field.name)) { ok = false; this.AddErr(`Field name "${field.name}" already defined`); } else if (IsInvalidString(field.name)) { ok = false; this.AddErr(`Field name "${field.name}" cannot be blank or have whitespace`); } else if (/^[a-zA-Z]/.test(field.name) == false) { ok = false; this.AddErr(`Field name "${field.name}" must start with a letter`); } else if (HasInvalidChar(field.name.substring(1))) { ok = false; this.AddErr(`Field name "${field.name}" must only have alphanumeric characters or underscore (_) after first character`); } else { fieldNameSet.add(field.name); if (this.#ValidateField(field) == false) { ok = false; } } } if (ok) { this.json = json; } } } catch (e) { ok = false; this.AddErr(e); } return ok; } GetLastErr() { return this.lastErr; } Calculate() { let bitsSum = 0; for (let field of this.json.fieldList) { this.#PrepareField(field); field.BitsSum = field.Bits + bitsSum; bitsSum += field.Bits; } if (this.debug) { console.table(this.json.fieldList); } } GetField(fieldName) { let retVal = null; for (let field of this.json.fieldList) { if (field.name == fieldName) { retVal = field; break; } } return retVal; } #MakeCodecClass() { let c = this.GenerateCodecClassDef(); if (this.debug) { console.log(c); } const MyClassDef = new Function('', `return ${c};`); const MyClass = MyClassDef(); this.CodecClass = MyClass; } GetCodecInstance() { let codec = new this.CodecClass(); codec.SetWsprEncoded(WSPREncoded); return codec; } GenerateCodecClassDef() { let a = new StrAccumulator(); a.A(`class ${this.json.name}Codec`); a.A(`{`); // Constructor a.IncrIndent(); a.A(`constructor()`); a.A(`{`); a.IncrIndent(); a.A(`this.Reset();`); a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(``); // Application field list a.IncrIndent(); a.A(`GetFieldList()`); a.A(`{`); a.IncrIndent(); a.A(`return [`); a.IncrIndent(); let sep = ""; for (let field of this.json.fieldList) { if (field.name.substr(0, 3) != "Hdr") { a.A(`${sep}${JSON.stringify(field)}`); sep = ","; } } a.DecrIndent(); a.A(`];`); a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(``); // Reset a.IncrIndent(); a.A(`Reset()`); a.A(`{`); a.IncrIndent(); a.A(`this.call = "0A0AAA";`); a.A(`this.grid = "AA00";`); a.A(`this.powerDbm = 0;`); a.A(``); a.A(`this.id13 = "00";`); a.A(``); a.A(`if (this.wsprEncoded == undefined) { this.wsprEncoded = null; }`); a.A(``); for (let field of this.json.fieldList) { a.A(`this.${field.name} = ${field.lowValue};`); } a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(` `); // Hack to get WSPREncoded into this object a.IncrIndent(); a.A(`SetWsprEncoded(wsprEncoded)`); a.A(`{`); a.IncrIndent(); a.A(`this.wsprEncoded = wsprEncoded;`); a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(` `); // Set id13 a.IncrIndent(); a.A(`SetId13(id13)`); a.A(`{`); a.IncrIndent(); a.A(`this.id13 = id13;`); a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(` `); // Get id13 a.IncrIndent(); a.A(`GetId13(id13)`); a.A(`{`); a.IncrIndent(); a.A(`return this.id13;`); a.DecrIndent(); a.A(`}`); a.DecrIndent(); // Setters / Getters for (let field of this.json.fieldList) { a.A(` `); // Setter a.IncrIndent(); a.A(`Set${field.name}${field.unit}(inputVal)`); a.A(`{`); a.IncrIndent(); a.A(`let val = inputVal ?? ${field.lowValue};`); a.A(``); a.A(`if (val < ${field.lowValue}) { val = ${field.lowValue}; }`); a.A(`else if (val > ${field.highValue}) { val = ${field.highValue}; }`); a.A(``); a.A(`this.${field.name} = this.Get${field.name}${field.unit}ValueFromNumber(this.Get${field.name}${field.unit}NumberFromValue(val));`); a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(` `); // Getter a.IncrIndent(); a.A(`Get${field.name}${field.unit}()`); a.A(`{`); a.IncrIndent(); a.A(`return this.${field.name};`); a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(` `); // field metadata - low value a.IncrIndent(); a.A(`Get${field.name}${field.unit}LowValue()`); a.A(`{`); a.IncrIndent(); a.A(`return ${field.lowValue};`); a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(` `); // field metadata - high value a.IncrIndent(); a.A(`Get${field.name}${field.unit}HighValue()`); a.A(`{`); a.IncrIndent(); a.A(`return ${field.highValue};`); a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(` `); // field metadata - step size a.IncrIndent(); a.A(`Get${field.name}${field.unit}StepSize()`); a.A(`{`); a.IncrIndent(); a.A(`return ${JSON.stringify(field.stepSize)};`); a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(` `); // Encoded Number Getter a.IncrIndent(); a.A(`Get${field.name}${field.unit}NumberFromValue(inputVal)`); a.A(`{`); a.IncrIndent(); a.A(`let val = inputVal ?? ${field.lowValue};`); a.A(`if (val < ${field.lowValue}) { val = ${field.lowValue}; }`); a.A(`else if (val > ${field.highValue}) { val = ${field.highValue}; }`); a.A(``); if (field.IsSegmented) { a.A(`let segmentList = ${JSON.stringify(field.SegmentList)};`); a.A(`let bestNumber = 0;`); a.A(`let bestValue = segmentList[0].low;`); a.A(`let bestDiff = Math.abs(val - bestValue);`); a.A(``); a.A(`for (let i = 0; i < segmentList.length; ++i)`); a.A(`{`); a.IncrIndent(); a.A(`let segment = segmentList[i];`); a.A(`let rawIndex = (val - segment.low) / segment.step;`); a.A(`let candidateIdxList = [Math.floor(rawIndex), Math.ceil(rawIndex)];`); a.A(`for (let candidateIdx of candidateIdxList)`); a.A(`{`); a.IncrIndent(); a.A(`if (candidateIdx < 0) { candidateIdx = 0; }`); a.A(`else if (candidateIdx >= segment.count) { candidateIdx = segment.count - 1; }`); a.A(`let candidateValue = segment.low + (candidateIdx * segment.step);`); a.A(`let candidateNumber = segment.base + candidateIdx;`); a.A(`let candidateDiff = Math.abs(val - candidateValue);`); a.A(`if (candidateDiff < bestDiff || (Math.abs(candidateDiff - bestDiff) < 1e-9 && candidateValue > bestValue))`); a.A(`{`); a.IncrIndent(); a.A(`bestDiff = candidateDiff;`); a.A(`bestValue = candidateValue;`); a.A(`bestNumber = candidateNumber;`); a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(`}`); a.A(``); a.A(`return bestNumber;`); } else { a.A(`let retVal = ((val - ${field.lowValue}) / ${field.stepSize});`); a.A(`retVal = Math.round(retVal);`); a.A(`return retVal;`); } a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(` `); // Encoded Number Getter a.IncrIndent(); a.A(`Get${field.name}${field.unit}Number()`); a.A(`{`); a.IncrIndent(); a.A(`return this.Get${field.name}${field.unit}NumberFromValue(this.Get${field.name}${field.unit}());`); a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(` `); a.IncrIndent(); a.A(`Get${field.name}${field.unit}ValueFromNumber(inputVal)`); a.A(`{`); a.IncrIndent(); a.A(`let val = inputVal ?? 0;`); a.A(`if (val < 0) { val = 0; }`); a.A(`else if (val >= ${field.NumValues}) { val = ${field.NumValues - 1}; }`); a.A(``); if (field.IsSegmented) { a.A(`let segmentList = ${JSON.stringify(field.SegmentList)};`); a.A(`for (let i = 0; i < segmentList.length; ++i)`); a.A(`{`); a.IncrIndent(); a.A(`let segment = segmentList[i];`); a.A(`if (val >= segment.base && val < segment.base + segment.count)`); a.A(`{`); a.IncrIndent(); a.A(`let localIndex = val - segment.base;`); a.A(`return segment.low + (localIndex * segment.step);`); a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(`}`); a.A(`let segment = segmentList[segmentList.length - 1];`); a.A(`return segment.low + ((segment.count - 1) * segment.step);`); } else { a.A(`return ${field.lowValue} + (val * ${field.stepSize});`); } a.DecrIndent(); a.A(`}`); a.DecrIndent(); } a.A(` `); // Encode // arrange application fields in reverse order // but ensure the original order of header fields. // this allows decode to pull out the "first" application field // consistently, even if the fields after it // change, are added, or revmoed. // this isn't an expected feature, but a good feature as it protects // legacy data in the event of future change as much as possible. let fieldEncodeList = this.json.fieldList.slice(); let fieldListApp = []; let fieldListHdr = []; for (const field of fieldEncodeList) { if (field.name.substr(0, 3) == "Hdr") { fieldListHdr.push(field); } else { fieldListApp.push(field); } } // reverse the application fields in-place fieldListApp.reverse(); // re-make the field list fieldEncodeList = []; for (const field of fieldListApp) { fieldEncodeList.push(field); } for (const field of fieldListHdr) { fieldEncodeList.push(field); } a.IncrIndent(); a.A(`Encode()`); a.A(`{`); a.IncrIndent(); a.A(`let val = 0;`); a.A(``); a.A(`// combine field values`); for (let field of fieldEncodeList) { a.A(`val *= ${field.NumValues}; val += this.Get${field.name}${field.unit}Number();`); } a.A(``); a.A(`// encode into power`); a.A(`let powerVal = val % 19; val = Math.floor(val / 19);`); a.A(`let powerDbm = this.wsprEncoded.EncodeNumToPower(powerVal);`); a.A(``); a.A(`// encode into grid`); a.A(`let g4Val = val % 10; val = Math.floor(val / 10);`); a.A(`let g3Val = val % 10; val = Math.floor(val / 10);`); a.A(`let g2Val = val % 18; val = Math.floor(val / 18);`); a.A(`let g1Val = val % 18; val = Math.floor(val / 18);`); a.A(``); a.A(`let g1 = String.fromCharCode("A".charCodeAt(0) + g1Val);`); a.A(`let g2 = String.fromCharCode("A".charCodeAt(0) + g2Val);`); a.A(`let g3 = String.fromCharCode("0".charCodeAt(0) + g3Val);`); a.A(`let g4 = String.fromCharCode("0".charCodeAt(0) + g4Val);`); a.A(`let grid = g1 + g2 + g3 + g4;`); a.A(``); a.A(`// encode into callsign`); a.A(`let id6Val = val % 26; val = Math.floor(val / 26);`); a.A(`let id5Val = val % 26; val = Math.floor(val / 26);`); a.A(`let id4Val = val % 26; val = Math.floor(val / 26);`); a.A(`let id2Val = val % 36; val = Math.floor(val / 36);`); a.A(``); a.A(`let id2 = this.wsprEncoded.EncodeBase36(id2Val);`); a.A(`let id4 = String.fromCharCode("A".charCodeAt(0) + id4Val);`); a.A(`let id5 = String.fromCharCode("A".charCodeAt(0) + id5Val);`); a.A(`let id6 = String.fromCharCode("A".charCodeAt(0) + id6Val);`); a.A(`let call = this.id13.at(0) + id2 + this.id13.at(1) + id4 + id5 + id6;`); a.A(``); a.A(`// capture results`); a.A(`this.call = call;`); a.A(`this.grid = grid;`); a.A(`this.powerDbm = powerDbm;`); a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(``); // Decode // get an entire-list reversed copy of the encoded field order let fieldDecodeList = fieldEncodeList.slice().reverse(); a.IncrIndent(); a.A(`Decode()`); a.A(`{`); a.IncrIndent(); a.A(`// pull in inputs`); a.A(`let call = this.GetCall();`); a.A(`let grid = this.GetGrid();`); a.A(`let powerDbm = this.GetPowerDbm();`); a.A(``); a.A(`// break call down`); a.A(`let id2Val = this.wsprEncoded.DecodeBase36(call.charAt(1));`); a.A(`let id4Val = call.charAt(3).charCodeAt(0) - "A".charCodeAt(0);`); a.A(`let id5Val = call.charAt(4).charCodeAt(0) - "A".charCodeAt(0);`); a.A(`let id6Val = call.charAt(5).charCodeAt(0) - "A".charCodeAt(0);`); a.A(``); a.A(`// break grid down`); a.A(`let g1Val = grid.charAt(0).charCodeAt(0) - "A".charCodeAt(0);`); a.A(`let g2Val = grid.charAt(1).charCodeAt(0) - "A".charCodeAt(0);`); a.A(`let g3Val = grid.charAt(2).charCodeAt(0) - "0".charCodeAt(0);`); a.A(`let g4Val = grid.charAt(3).charCodeAt(0) - "0".charCodeAt(0);`); a.A(``); a.A(`// break power down`); a.A(`let powerVal = this.wsprEncoded.DecodePowerToNum(powerDbm);`); a.A(``); a.A(`// combine values into single integer`); a.A(`let val = 0;`); a.A(`val *= 36; val += id2Val;`); a.A(`val *= 26; val += id4Val; // spaces aren't used, so 26 not 27`); a.A(`val *= 26; val += id5Val; // spaces aren't used, so 26 not 27`); a.A(`val *= 26; val += id6Val; // spaces aren't used, so 26 not 27`); a.A(`val *= 18; val += g1Val;`); a.A(`val *= 18; val += g2Val;`); a.A(`val *= 10; val += g3Val;`); a.A(`val *= 10; val += g4Val;`); a.A(`val *= 19; val += powerVal;`); a.A(``); a.A(`// extract field values`); for (let field of fieldDecodeList) { a.A(`this.Set${field.name}${field.unit}(this.Get${field.name}${field.unit}ValueFromNumber(val % ${field.NumValues})); val = Math.floor(val / ${field.NumValues});`); } a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(``); // SetCall a.IncrIndent(); a.A(`SetCall(inputVal)`); a.A(`{`); a.IncrIndent(); a.A(`this.call = inputVal;`) a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(``); // GetCall a.IncrIndent(); a.A(`GetCall()`); a.A(`{`); a.IncrIndent(); a.A(`return this.call;`) a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(``); // SetGrid a.IncrIndent(); a.A(`SetGrid(inputVal)`); a.A(`{`); a.IncrIndent(); a.A(`this.grid = inputVal;`) a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(``); // GetGrid a.IncrIndent(); a.A(`GetGrid()`); a.A(`{`); a.IncrIndent(); a.A(`return this.grid;`) a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(``); // SetPowerDbm a.IncrIndent(); a.A(`SetPowerDbm(inputVal)`); a.A(`{`); a.IncrIndent(); a.A(`this.powerDbm = inputVal;`) a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(``); // GetPowerDbm a.IncrIndent(); a.A(`GetPowerDbm()`); a.A(`{`); a.IncrIndent(); a.A(`return parseInt(this.powerDbm);`) a.DecrIndent(); a.A(`}`); a.DecrIndent(); a.A(`}`); let c = a.Get(); return c; } }