private static int TestStringEscapeOne(string str) { int nerror = 0; var escape = ValueCalculate.EscapeString(str); if (escape.Contains('\0')) { nerror++; System.Diagnostics.Debug.WriteLine($"ERROR in TestStringEscape({str}) escape {escape} contains NULL"); } if (escape.Contains(' ')) { nerror++; System.Diagnostics.Debug.WriteLine($"ERROR in TestStringEscape({str}) escape {escape} contains SPACE"); } if (escape.Contains('|')) { nerror++; System.Diagnostics.Debug.WriteLine($"ERROR in TestStringEscape({str}) escape {escape} contains BAR"); } if (escape.Contains('^')) { nerror++; System.Diagnostics.Debug.WriteLine($"ERROR in TestStringEscape({str}) escape {escape} contains CARET"); } if (escape.Contains('\r')) { nerror++; System.Diagnostics.Debug.WriteLine($"ERROR in TestStringEscape({str}) escape {escape} contains CR"); } if (escape.Contains('\n')) { nerror++; System.Diagnostics.Debug.WriteLine($"ERROR in TestStringEscape({str}) escape {escape} contains LF"); } var reverse = ValueCalculate.UnescapeString(escape); if (reverse != str) { nerror++; System.Diagnostics.Debug.WriteLine($"ERROR in TestStringEscape({str}) escape {escape} reverse {reverse} isn't the same!"); } return(nerror); }
private static ValueParserResult ConvertHelper(DataReader dr, string decodeCommands) { var str = ""; var vps = ValueParserSplit.ParseLine(decodeCommands); var valueList = new BCBasic.BCValueList(); bool isOptional = false; for (int i = 0; i < vps.Count; i++) { var stritem = ""; var command = vps[i]; var readcmd = command.ByteFormatPrimary; var readindicator = readcmd[0]; var displayFormat = command.DisplayFormatPrimary; var displayFormatSecondary = command.Get(1, 1); var name = command.NamePrimary; if (string.IsNullOrEmpty(name)) { name = $"param{i}"; } var units = command.UnitsPrimary; var resultState = ResultState.IsDouble; // the most common result double dvalue = double.NaN; try { switch (readindicator) { case 'F': // FLOAT if (dr.UnconsumedBufferLength == 0) { if (isOptional) { dvalue = double.NaN; stritem = ""; break; } else { return(ValueParserResult.CreateError(decodeCommands, $"Missing data with {readcmd} field {i+1}")); } } switch (readcmd) { case "F32": { dvalue = dr.ReadSingle(); switch (displayFormat) { case "": case "FIXED": displayFormat = (displayFormatSecondary == "") ? "N3" : displayFormatSecondary; break; case "DEC": displayFormat = (displayFormatSecondary == "") ? "N0" : displayFormatSecondary; break; case "HEX": return(ValueParserResult.CreateError(decodeCommands, $"Float displayFormat unrecognized; should be FIXED {displayFormat}")); } stritem = dvalue.ToString(displayFormat); // e.g. N3 for 3 digits } break; case "F64": { dvalue = dr.ReadDouble(); switch (displayFormat) { case "": case "FIXED": displayFormat = (displayFormatSecondary == "") ? "N3" : displayFormatSecondary; break; case "DEC": displayFormat = (displayFormatSecondary == "") ? "N0" : displayFormatSecondary; break; case "HEX": return(ValueParserResult.CreateError(decodeCommands, $"Float displayFormat unrecognized; should be FIXED {displayFormat}")); } stritem = dvalue.ToString(displayFormat); // e.g. N3 for 3 digits } break; default: return(ValueParserResult.CreateError(decodeCommands, $"Float command unrecognized; should be F32 or F64 not {readcmd}")); } break; case 'I': if (dr.UnconsumedBufferLength == 0) { if (isOptional) { dvalue = double.NaN; stritem = ""; break; } else { return(ValueParserResult.CreateError(decodeCommands, $"Missing data with {readcmd} field {i + 1}")); } } switch (readcmd) { case "I8": case "I16": case "I24": case "I32": { string floatFormat = "F2"; string intFormat = "X6"; switch (readcmd) { case "I8": { var value = (sbyte)dr.ReadByte(); dvalue = (double)value; } break; case "I16": { var value = dr.ReadInt16(); dvalue = (double)value; } break; case "I24": { var b0 = dr.ReadByte(); var b1 = dr.ReadByte(); var b2 = dr.ReadByte(); var msb = (sbyte)(dr.ByteOrder == ByteOrder.BigEndian ? b0 : b2); var lsb = dr.ByteOrder == ByteOrder.BigEndian ? b2 : b0; int value = (int)(msb << 16) + (b1 << 8) + (lsb); dvalue = (double)value; } break; case "I32": { var value = dr.ReadInt32(); dvalue = (double)value; intFormat = "X8"; } break; } string calculateCommand = command.Get(0, 1); // e.g. for I24^100_/ for TI 1350 barometer values if (!string.IsNullOrEmpty(calculateCommand)) { dvalue = ValueCalculate.Calculate(calculateCommand, dvalue).D; if (double.IsNaN(dvalue)) { return(ValueParserResult.CreateError(decodeCommands, $"Calculation failed for {calculateCommand} in {readcmd}")); } else { // Everything worked and got a value stritem = DoubleToString(dvalue, displayFormat, displayFormatSecondary); if (stritem == null) { return(ValueParserResult.CreateError(decodeCommands, $"Integer display format command unrecognized; should be FIXED or HEX or DEC not {displayFormat} in {readcmd}")); } } } else { if (displayFormat == "") { displayFormat = "HEX"; } stritem = DoubleToString(dvalue, displayFormat, displayFormatSecondary, floatFormat, intFormat); if (stritem == null) { return(ValueParserResult.CreateError(decodeCommands, $"Integer display format command unrecognized; should be FIXED or HEX or DEC not {displayFormat} in {readcmd}")); } } } break; default: return(ValueParserResult.CreateError(decodeCommands, $"Integer command unrecognized; should be I8/16/24/32 not {readcmd}")); } break; case 'O': switch (readcmd) { case "OEB": resultState = ResultState.NoResult; dr.ByteOrder = ByteOrder.LittleEndian; break; case "OEL": resultState = ResultState.NoResult; dr.ByteOrder = ByteOrder.LittleEndian; break; case "OOPT": isOptional = true; break; default: return(ValueParserResult.CreateError(decodeCommands, $"Optional command unrecognized; should be OEL or OEB not {readcmd}")); } break; case 'Q': if (dr.UnconsumedBufferLength == 0) { if (isOptional) { dvalue = double.NaN; stritem = ""; break; } else { return(ValueParserResult.CreateError(decodeCommands, $"Missing data with {readcmd} field {i + 1}")); } } // e.g. Q12Q4.Fixed { var subtypes = readcmd.Split(new char[] { 'Q' }); if (subtypes.Length != 3) // Actually 2, but first is blank { return(ValueParserResult.CreateError(decodeCommands, $"Q command unrecognized; wrong number of Qs {readcmd}")); } stritem = FixedQuotientHelper(dr, subtypes[1], subtypes[2], displayFormat, out dvalue); //NOTE: fail on failure } break; case 'U': if (dr.UnconsumedBufferLength == 0) { if (isOptional) { dvalue = double.NaN; stritem = ""; break; } else { return(ValueParserResult.CreateError(decodeCommands, $"Missing data with {readcmd} field {i + 1}")); } } switch (readcmd) { case "U8": case "U16": case "U24": case "U32": string xfmt = "X2"; switch (readcmd) { case "U8": { var value = dr.ReadByte(); dvalue = (double)value; xfmt = "X2"; } break; case "U16": { var value = dr.ReadUInt16(); dvalue = (double)value; xfmt = "X4"; } break; case "U24": { var b0 = dr.ReadByte(); var b1 = dr.ReadByte(); var b2 = dr.ReadByte(); var msb = (byte)(dr.ByteOrder == ByteOrder.BigEndian ? b0 : b2); var lsb = dr.ByteOrder == ByteOrder.BigEndian ? b2 : b0; int value = (int)(msb << 16) + (b1 << 8) + (lsb); dvalue = (double)value; } break; case "U32": { var value = dr.ReadUInt32(); dvalue = (double)value; xfmt = "X8"; } break; } string calculateCommand = command.Get(0, 1); // e.g. for I24^100_/ for TI 1350 barometer values if (!string.IsNullOrEmpty(calculateCommand)) { dvalue = ValueCalculate.Calculate(calculateCommand, dvalue).D; if (double.IsNaN(dvalue)) { return(ValueParserResult.CreateError(decodeCommands, $"Calculation failed for {calculateCommand} in {readcmd}")); } else { stritem = DoubleToString(dvalue, displayFormat, displayFormatSecondary); if (stritem == null) { return(ValueParserResult.CreateError(decodeCommands, $"Integer display format command unrecognized; should be FIXED or HEX or DEC not {displayFormat} in {readcmd}")); } } } else { if (displayFormat == "") { displayFormat = "HEX"; } stritem = DoubleToString(dvalue, displayFormat, displayFormatSecondary, "F2", xfmt); if (stritem == null) { return(ValueParserResult.CreateError(decodeCommands, $"Integer display format command unrecognized;\nshould be FIXED or HEX or DEC not {displayFormat} in {readcmd}")); } } break; default: return(ValueParserResult.CreateError(decodeCommands, $"UInteger command unrecognized;\nshould be U8/U16/U24/U32 not {readcmd}")); } break; case '/': // e.g. /U8/I16|Fixed if (dr.UnconsumedBufferLength == 0) { if (isOptional) { dvalue = double.NaN; stritem = ""; break; } else { return(ValueParserResult.CreateError(decodeCommands, $"Missing data with {readcmd} field {i + 1}")); } } { var subtypes = readcmd.Split(new char[] { '/' }); if (subtypes.Length != 3) // Actually 2, but first is blank { return(ValueParserResult.CreateError(decodeCommands, $"/ command unrecognized; wrong number of slashes {readcmd}")); } stritem = FixedFractionHelper(dr, subtypes[1], subtypes[2], displayFormat, out dvalue); // NOTE: fail on failure } break; default: if (readcmd != readcmd.ToUpper()) { System.Diagnostics.Debug.WriteLine("ERROR: readcmd {readcmd} but should be uppercase"); } switch (readcmd.ToUpper()) //NOTE: should be all-uppercase; any lowercase is wrong { case "STRING": { try { stritem = dr.ReadString(dr.UnconsumedBufferLength); switch (displayFormat) { case "": case "ASCII": stritem = EscapeString(stritem, displayFormatSecondary); break; case "Eddystone": stritem = BluetoothDefinitionLanguage.Eddystone.EddystoneUrlToString(stritem); break; default: return(ValueParserResult.CreateError(decodeCommands, $"Unknown string format type {displayFormat}")); } } catch (Exception) { // The string can't be read. Let's try reading as a buffer instead. IBuffer buffer = dr.ReadBuffer(dr.UnconsumedBufferLength); for (uint ii = 0; ii < buffer.Length; ii++) { if (ii != 0) { stritem += " "; } stritem += buffer.GetByte(ii).ToString("X2"); } } resultState = ResultState.IsString; } break; case "BYTES": { IBuffer buffer = dr.ReadBuffer(dr.UnconsumedBufferLength); for (uint ii = 0; ii < buffer.Length; ii++) { if (ii != 0) { stritem += " "; } stritem += buffer.GetByte(ii).ToString("X2"); } resultState = ResultState.IsString; } break; default: return(ValueParserResult.CreateError(decodeCommands, $"Other command unrecognized; should be String or Bytes {readcmd}")); } break; } } catch (Exception e) { stritem = $"EXCEPTION reading data {e} index {i} command {command} len {dr.UnconsumedBufferLength}"; return(ValueParserResult.CreateError(str + stritem, stritem)); } switch (resultState) { case ResultState.IsDouble: valueList.SetProperty(name, new BCBasic.BCValue(dvalue)); break; case ResultState.IsString: valueList.SetProperty(name, new BCBasic.BCValue(stritem)); break; } if (str != "") { str += " "; } str += stritem; if (dr.UnconsumedBufferLength <= 0) { break; } } return(ValueParserResult.CreateOk(str, valueList)); }