Esempio n. 1
0
        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));
        }