public Parser(MainWindow mainWindow, string dbcPath = null) { this.mainWindow = mainWindow; items = new Dictionary <string, ListElement>(); packets = new SortedList <uint, Packet>(); // time = SystemClock.ElapsedRealtime() + 1000; Packet p; if (dbcPath != null) { Reader reader = new DBCLib.Reader(); reader.AllowErrors = true; List <object> entries = reader.Read(dbcPath); foreach (object entry in entries) { if (entry is Message) { Message message = (Message)entry; packets.Add(message.Id, p = new Packet(message.Id, this)); foreach (Message.Signal signal in message.Signals) { var valueLookup = (DBCLib.Value) entries.Where(x => x is DBCLib.Value && ((DBCLib.Value)x).ContextSignalName == signal.Name).FirstOrDefault(); p.AddValue( signal.Name,//.Replace("_", " "), signal.Unit, signal.Name, (bytes) => { double result; if (signal.StartBit + signal.BitSize > bytes.Length * 8) // check data length { return(null); } if (signal.Multiplexer) // if this is our multiplex / page selector { return (p.currentMultiplexer = // store it ExtractSignalFromBytes(bytes, signal)); // and return it } else if (signal.MultiplexerIdentifier != null) // else if this is a sub-item { if (signal.MultiplexerIdentifier == p.currentMultiplexer) // check if we're on the same page { result = ExtractSignalFromBytes(bytes, signal); // then return it } else { return(null); } } else { result = ExtractSignalFromBytes(bytes, signal); } if (valueLookup != null) { string s = valueLookup.Mapping.Where(x => x.Key == result).FirstOrDefault().Value; //TryGetValue((long)result, out s); if (s != null) { return(s); } } return(result); }, null ); } } } } packets.Add(0xFFF1, p = new Packet(0x1, this)); p.AddValue("Byte 0", "b", "br", (bytes) => (bytes[0])); p.AddValue("Byte 1", "b", "br", (bytes) => (bytes[1])); p.AddValue("Byte 2", "b", "br", (bytes) => (bytes[2])); p.AddValue("Byte 3", "b", "br", (bytes) => (bytes[3])); p.AddValue("Byte 4", "b", "br", (bytes) => (bytes[4])); p.AddValue("Byte 5", "b", "br", (bytes) => (bytes[5])); p.AddValue("Byte 6", "b", "br", (bytes) => (bytes[6])); p.AddValue("Byte 7", "b", "br", (bytes) => (bytes[7])); packets.Add(0xFFF2, p = new Packet(0x2, this)); p.AddValue("Word 0", "b", "br", (bytes) => (bytes[0] + (bytes[1] << 8))); p.AddValue("Word 1", "b", "br", (bytes) => (bytes[2] + (bytes[3] << 8))); p.AddValue("Word 2", "b", "br", (bytes) => (bytes[4] + (bytes[5] << 8))); p.AddValue("Word 3", "b", "br", (bytes) => (bytes[6] + (bytes[7] << 8))); packets.Add(0xFFF3, p = new Packet(0x3, this)); p.AddValue("Int 0", "b", "br", (bytes) => (bytes[0] + (bytes[1] << 8)) - (512 * (bytes[1] & 0x80))); p.AddValue("Int 1", "b", "br", (bytes) => (bytes[2] + (bytes[3] << 8)) - (512 * (bytes[3] & 0x80))); p.AddValue("Int 2", "b", "br", (bytes) => (bytes[4] + (bytes[5] << 8)) - (512 * (bytes[5] & 0x80))); p.AddValue("Int 3", "b", "br", (bytes) => (bytes[6] + (bytes[7] << 8)) - (512 * (bytes[7] & 0x80))); packets.Add(0xFFF5, p = new Packet(0x5, this)); p.AddValue("12 bit 0", "b", "br", (bytes) => (bytes[0] + ((bytes[1] & 0x0F) << 4))); p.AddValue("12 bit 1", "b", "br", (bytes) => (((bytes[1] & 0xF0) >> 4) + ((bytes[2]) << 8))); p.AddValue("12 bit 3", "b", "br", (bytes) => (bytes[3] + ((bytes[4] & 0x0F) << 4))); p.AddValue("12 bit 4", "b", "br", (bytes) => (((bytes[4] & 0xF0) >> 4) + ((bytes[5]) << 8))); p.AddValue("12 bit 5", "b", "br", (bytes) => (bytes[6] + ((bytes[7] & 0x0F) << 4))); packets.Add(0xFFF6, p = new Packet(0x6, this)); p.AddValue("Temp 1", " C", "h", (bytes) => (bytes[1] - 40)); p.AddValue("Temp 2", " C", "h", (bytes) => (bytes[0] - 40)); p.AddValue("Temp 3", " C", "h", (bytes) => (bytes[2] - 40)); p.AddValue("Temp 4", " C", "h", (bytes) => (bytes[3] - 40)); p.AddValue("Temp 5", " C", "h", (bytes) => (bytes[4] - 40)); p.AddValue("Temp 6", " C", "h", (bytes) => (bytes[5] - 40)); p.AddValue("Temp 7", " C", "h", (bytes) => (bytes[6] - 40)); p.AddValue("Temp 8", " C", "h", (bytes) => (bytes[7] - 40)); }
public Parser(MainWindow mainWindow, ObservableCollection <DBCwAssociatedBus> dbcList = null) { this.mainWindow = mainWindow; items = new Dictionary <string, ListElement>(); packets = new SortedList <Tuple <uint, int>, Packet>(); Packet p; if (dbcList != null) { foreach (DBCwAssociatedBus dbcFile in dbcList) //parse each file { //if (dbcFile != null) //{ Reader reader = new DBCLib.Reader(); reader.AllowErrors = true; List <object> entries = reader.Read(dbcFile.Path); foreach (object entry in entries) { if (entry is Message) { Message message = (Message)entry; try { packets.Add(Tuple.Create(message.Id, int.Parse(dbcFile.Bus)), p = new Packet(message.Id, dbcFile, this)); foreach (Message.Signal signal in message.Signals) { string nameWoPrefix = Regex.Replace(signal.Name, @"^_(_|\d)*_", ""); var valueLookup = (DBCLib.Value) entries.Where(x => x is DBCLib.Value && ((DBCLib.Value)x).ContextSignalName == signal.Name).FirstOrDefault(); List <KeyValuePair <long, string> > VT_List = new List <KeyValuePair <long, string> >(); if (valueLookup != null) { VT_List = valueLookup.Mapping.ToList(); } p.AddValue( dbcFile.Bus + "_" + (message.Id).ToString("X") + "_" + nameWoPrefix, message.Name, dbcFile.Bus, signal.Unit, nameWoPrefix, (bytes) => { double result; if (signal.StartBit + signal.BitSize > bytes.Length * 8) // check data length { return(null); } if (signal.Multiplexer) // if this is our multiplex / page selector { return (p.currentMultiplexer = // store it ExtractSignalFromBytes(bytes, signal)); // and return it } else if (signal.MultiplexerIdentifier != null) { // else if this is a sub-item if (signal.MultiplexerIdentifier == p.currentMultiplexer) // check if we're on the same page { result = ExtractSignalFromBytes(bytes, signal); // then return it } else { return(null); } } else { result = ExtractSignalFromBytes(bytes, signal); } //if (valueLookup != null) //{ // string s = // valueLookup.Mapping.Where(x => x.Key == result).FirstOrDefault().Value; //TryGetValue((long)result, out s); // if (s != null) // return s; //} return(result); }, VT_List , null ); } } catch { } } } //} } } }
public Parser() { items = new Dictionary <string, ListElement>(); packets = new SortedList <uint, Packet>(); // time = SystemClock.ElapsedRealtime() + 1000; Packet p; if (use_DBC != KnownDBC.None) { Reader reader = new DBCLib.Reader(); string dbcPath = @"C:\git\CANBUS-Analyzer\DBCTools\Samples"; switch (use_DBC) { case KnownDBC.Model3: dbcPath += @"\tesla_model3.dbc"; break; case KnownDBC.ModelSAWD: dbcPath += @"\tesla_models_awd.dbc"; break; case KnownDBC.ModelSRWD: dbcPath += @"\tesla_models_rwd.dbc"; break; } List <object> entries = reader.Read(dbcPath); foreach (object entry in entries) { if (entry is Message) { Message message = (Message)entry; packets.Add(message.Id, p = new Packet(message.Id, this)); foreach (Message.Signal signal in message.Signals) { p.AddValue( signal.Name.Replace("_", " "), signal.Unit, signal.Name, (bytes) => ExtractSignalFromBytes(bytes, signal), null ); } } } } packets.Add(0x1, p = new Packet(0x1, this)); p.AddValue("Byte 0", "b", "br", (bytes) => (bytes[0])); p.AddValue("Byte 1", "b", "br", (bytes) => (bytes[1])); p.AddValue("Byte 2", "b", "br", (bytes) => (bytes[2])); p.AddValue("Byte 3", "b", "br", (bytes) => (bytes[3])); p.AddValue("Byte 4", "b", "br", (bytes) => (bytes[4])); p.AddValue("Byte 5", "b", "br", (bytes) => (bytes[5])); p.AddValue("Byte 6", "b", "br", (bytes) => (bytes[6])); p.AddValue("Byte 7", "b", "br", (bytes) => (bytes[7])); packets.Add(0x2, p = new Packet(0x2, this)); p.AddValue("Word 0", "b", "br", (bytes) => (bytes[0] + (bytes[1] << 8))); p.AddValue("Word 1", "b", "br", (bytes) => (bytes[2] + (bytes[3] << 8))); p.AddValue("Word 2", "b", "br", (bytes) => (bytes[4] + (bytes[5] << 8))); p.AddValue("Word 3", "b", "br", (bytes) => (bytes[6] + (bytes[7] << 8))); packets.Add(0x3, p = new Packet(0x3, this)); p.AddValue("Int 0", "b", "br", (bytes) => (bytes[0] + (bytes[1] << 8)) - (512 * (bytes[1] & 0x80))); p.AddValue("Int 1", "b", "br", (bytes) => (bytes[2] + (bytes[3] << 8)) - (512 * (bytes[3] & 0x80))); p.AddValue("Int 2", "b", "br", (bytes) => (bytes[4] + (bytes[5] << 8)) - (512 * (bytes[5] & 0x80))); p.AddValue("Int 3", "b", "br", (bytes) => (bytes[6] + (bytes[7] << 8)) - (512 * (bytes[7] & 0x80))); packets.Add(0x5, p = new Packet(0x5, this)); p.AddValue("12 bit 0", "b", "br", (bytes) => (bytes[0] + ((bytes[1] & 0x0F) << 4))); p.AddValue("12 bit 1", "b", "br", (bytes) => (((bytes[1] & 0xF0) >> 4) + ((bytes[2]) << 8))); p.AddValue("12 bit 3", "b", "br", (bytes) => (bytes[3] + ((bytes[4] & 0x0F) << 4))); p.AddValue("12 bit 4", "b", "br", (bytes) => (((bytes[4] & 0xF0) >> 4) + ((bytes[5]) << 8))); p.AddValue("12 bit 5", "b", "br", (bytes) => (bytes[6] + ((bytes[7] & 0x0F) << 4))); packets.Add(0x6, p = new Packet(0x6, this)); p.AddValue("Temp 1", " C", "h", (bytes) => (bytes[1] - 40)); p.AddValue("Temp 2", " C", "h", (bytes) => (bytes[0] - 40)); p.AddValue("Temp 3", " C", "h", (bytes) => (bytes[2] - 40)); p.AddValue("Temp 4", " C", "h", (bytes) => (bytes[3] - 40)); p.AddValue("Temp 5", " C", "h", (bytes) => (bytes[4] - 40)); p.AddValue("Temp 6", " C", "h", (bytes) => (bytes[5] - 40)); p.AddValue("Temp 7", " C", "h", (bytes) => (bytes[6] - 40)); p.AddValue("Temp 8", " C", "h", (bytes) => (bytes[7] - 40)); }
public Parser(MainActivity mainActivity, CustomAdapter adapter) { this.adapter = adapter; this.mainActivity = mainActivity; items = new ConcurrentDictionary <string, ListElement>(); packets = new SortedList <int, Packet>(); time = SystemClock.ElapsedRealtime() + 1000; /* tags: * p: performance * t: trip * b: battery * c: temperature * f: front drive unit * s: startup (app will wait until these packets are found before starting 'normal' mode) * i: imperial * m: metric * i: ignore (in trip tabs, with slow/ELM adapters) * z: BMS * x: Cells * e: efficiency */ Packet p; #if USEDCB //String dbcPath = "Model3CAN.dbc"; //string path = Directory.GetCurrentDirectory(); //var pathFile = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads); ////IEnumerable<string> files2 = Directory.EnumerateFiles((String)pathFile, "*.dbc"); //dbcPath = (string)pathFile + "/" + dbcPath; //inputStream = mainActivity.Assets.Open("CAN_BUS_LOG_Feb_10.txt"); //LINES 185 to 239 are taken from CANBUS-Analyzer https://github.com/amund7/CANBUS-Analyzer //if (dbcPath != null) if (true) { Reader reader = new DBCLib.Reader(); reader.AllowErrors = true; //List<object> entries = reader.Read(dbcPath); //AssetManager assets = this.Assets; List <KeyValuePair <uint, string> > errors = null; List <KeyValuePair <uint, string> > warnings = null; using (StreamReader streamReader = new StreamReader(mainActivity.Assets.Open("Model3CAN.dbc"), Encoding.Default, false)) { List <object> entries = reader.Read(streamReader, "Model3CAN.dbc", errors, warnings); //List<object> entries = reader.Read(mainActivity.Assets.Open("Model3CAN.dbc")); foreach (object entry in entries) { if (entry is DBCLib.Message) { DBCLib.Message message = (DBCLib.Message)entry; packets.Add((int)message.Id, p = new Packet((int)message.Id, this)); foreach (DBCLib.Message.Signal signal in message.Signals) { var valueLookup = (DBCLib.Value) entries.Where(x => x is DBCLib.Value && ((DBCLib.Value)x).ContextSignalName == signal.Name).FirstOrDefault(); p.AddValue( signal.Name.Replace("_", " ").Remove(signal.Name.Length - 3), //.Replace("_", " "), signal.Unit, NameToTag(message.Id), //NameToTag(signal.Name), (bytes) => { double result; if (signal.StartBit + signal.BitSize > bytes.Length * 8) // check data length { return(0); } if (signal.Multiplexer) // if this is our multiplex / page selector { return (p.currentMultiplexer = // store it ExtractSignalFromBytes(bytes, signal)); // and return it } else if (signal.MultiplexerIdentifier != null) { // else if this is a sub-item if (signal.MultiplexerIdentifier == p.currentMultiplexer) // check if we're on the same page { result = ExtractSignalFromBytes(bytes, signal); // then return it } else { return(0); } } else { result = ExtractSignalFromBytes(bytes, signal); } if (valueLookup != null) { string s = valueLookup.Mapping.Where(x => x.Key == result).FirstOrDefault().Value; //TryGetValue((long)result, out s); if (s != null) { return(0); } //return s; } return(result); }, null ); } } } } } #else /*packets.Add(0x256, p = new Packet(0x256, this)); * p.AddValue("Metric", "bool", "s", (bytes) => { * metric = Convert.ToBoolean(bytes[3] & 0x80); * if (metric) { * foreach (var packet in packets) * foreach (var v in packet.Value.values) * if (v.tag.Contains("i")) * packet.Value.values.Remove(v); * } else { * foreach (var packet in packets) * foreach (var v in packet.Value.values) * if (v.tag.Contains("m")) * packet.Value.values.Remove(v); * } * return metric ? 1 : 0; * });*/ packets.Add(0x528, p = new Packet(0x528, this)); p.AddValue("UNIX Time", "Sec", "br", (bytes) => (bytes[0] << 8 * 3) + (bytes[1] << 8 * 2) + (bytes[2] << 8) + bytes[3]); packets.Add(0x266, p = new Packet(0x266, this)); p.AddValue("Rr inverter 12V", "V12", "", (bytes) => bytes[0] / 10.0); p.AddValue("Rr power", " kW", "e", (bytes) => mechPower = ((bytes[2] + ((bytes[3] & 0x7) << 8)) - (512 * (bytes[3] & 0x4))) / 2.0); //p.AddValue("Rr mech power HP", "HP", "pf", (bytes) => mechPower * kw_to_hp); p.AddValue("Rr dissipation", " kW", "", (bytes) => { rDissipation = bytes[1] * 125.0 / 1000.0; /*dissipationUpdated = true; * dissipationTimeStamp = DateTime.Now.Millisecond;*/ return(rDissipation); }); p.AddValue("Rr stator current", "A", "", (bytes) => bytes[4] + ((bytes[5] & 0x7) << 8)); p.AddValue("Rr regen power max", "KW", "b", (bytes) => (bytes[7] * 4) - 200); p.AddValue("Rr drive power max", "KW", "b", (bytes) => drivePowerMax = (((bytes[6] & 0x3F) << 5) + ((bytes[5] & 0xF0) >> 3)) + 1); packets.Add(0x132, p = new Packet(0x132, this)); p.AddValue("Battery voltage", " V", "bpr", (bytes) => volt = (bytes[0] + (bytes[1] << 8)) / 100.0); p.AddValue("Battery current", " A", "b", (bytes) => amp = 1000 - ((Int16)((((bytes[3]) << 8) + bytes[2]))) / 10.0); p.AddValue("Battery power", " kW", "bpe", (bytes) => power = amp * volt / 1000.0); packets.Add(0x3B6, p = new Packet(0x3B6, this)); p.AddValue("Odometer", "Km", "b", (bytes) => odometer = (bytes[0] + (bytes[1] << 8) + (bytes[2] << 16) + (bytes[3] << 24)) / 1000.0); packets.Add(0x154, p = new Packet(0x154, this)); p.AddValue("Rr torque measured", "Nm", "p", (bytes) => torque = (bytes[5] + ((bytes[6] & 0x1F) << 8) - (512 * (bytes[6] & 0x10))) * 0.25); packets.Add(0x108, p = new Packet(0x108, this)); p.AddValue("Rr motor RPM", "RPM", "", (bytes) => rrpm = (bytes[5] + (bytes[6] << 8)) - (512 * (bytes[6] & 0x80))); packets.Add(0x376, p = new Packet(0x376, this)); p.AddValue("Inverter temp 1", " C", "e", (bytes) => (bytes[0] - 40)); p.AddValue("Inverter temp 2", " C", "e", (bytes) => (bytes[1] - 40)); p.AddValue("Inverter temp 3", " C", "e", (bytes) => (bytes[2] - 40)); p.AddValue("Inverter temp 4", " C", "e", (bytes) => (bytes[4] - 40)); packets.Add(0x292, p = new Packet(0x292, this)); p.AddValue("SOC UI", "%", "br", (bytes) => (bytes[0] + ((bytes[1] & 0x3) << 8)) / 10.0); p.AddValue("SOC Min", "%", "br", (bytes) => ((bytes[1] >> 2) + ((bytes[2] & 0xF) << 6)) / 10.0); p.AddValue("SOC Max", "%", "br", (bytes) => ((bytes[2] >> 4) + ((bytes[3] & 0x3F) << 4)) / 10.0); p.AddValue("SOC Avg", "%", "br", (bytes) => ((bytes[3] >> 6) + ((bytes[4]) << 2)) / 10.0); packets.Add(0x252, p = new Packet(0x252, this)); p.AddValue("Max discharge power", "kW", "b", (bytes) => (bytes[2] + (bytes[3] << 8)) / 100.0); p.AddValue("Max regen power", "kW", "b", (bytes) => (bytes[0] + (bytes[1] << 8)) / 100.0); packets.Add(0x2A4, p = new Packet(0x2A4, this)); p.AddValue("7 bit 0", "b", "br", (bytes) => (bytes[0] & 0x7F)); p.AddValue("5 bit 1", "b", "br", (bytes) => (bytes[1] & 0xF8) >> 3); p.AddValue("5 bit 2", "b", "br", (bytes) => ((bytes[1] & 0x7) << 2) + ((bytes[2] & 0xC0) >> 6)); p.AddValue("7 bit 3", "b", "br", (bytes) => (bytes[3] & 0x7F)); p.AddValue("7 bit 4", "b", "br", (bytes) => (bytes[4] & 0xFE) >> 1); /*p.AddValue("33A 12 bit 3", "b", "br", * (bytes) => (bytes[3] + ((bytes[4] & 0x0F) << 8))); * p.AddValue("33A 12 bit 4", "b", "br", * (bytes) => (((bytes[4] & 0xF0) >> 4) + ((bytes[5]) << 4))); * p.AddValue("33A 12 bit 5", "b", "br", * (bytes) => (bytes[6] + ((bytes[7] & 0x0F) << 8)));*/ packets.Add(0x352, p = new Packet(0x352, this)); p.AddValue("Nominal full pack", "kWh", "br", (bytes) => nominalFullPackEnergy = (bytes[0] + ((bytes[1] & 0x03) << 8)) * 0.1); p.AddValue("Nominal remaining", "kWh", "br", (bytes) => nominalRemaining = ((bytes[1] >> 2) + ((bytes[2] & 0x0F) * 64)) * 0.1); p.AddValue("Expected remaining", "kWh", "r", (bytes) => ((bytes[2] >> 4) + ((bytes[3] & 0x3F) * 16)) * 0.1); p.AddValue("Ideal remaining", "kWh", "r", (bytes) => ((bytes[3] >> 6) + ((bytes[4] & 0xFF) * 4)) * 0.1); p.AddValue("To charge complete", "kWh", "", (bytes) => (bytes[5] + ((bytes[6] & 0x03) << 8)) * 0.1); p.AddValue("Energy buffer", "kWh", "br", (bytes) => buffer = ((bytes[6] >> 2) + ((bytes[7] & 0x03) * 64)) * 0.1); /*p.AddValue("SOC", "%", "br", (bytes) => soc = (nominalRemaining - buffer) / (nominalFullPackEnergy - buffer) * 100.0); * This one seems to be confirmed to be far off the UI displayed SOC */ packets.Add(0x212, p = new Packet(0x212, this)); p.AddValue("Battery temp", "C", "i", (bytes) => ((bytes[7]) / 2.0) - 40.0); packets.Add(0x321, p = new Packet(0x321, this)); p.AddValue("CoolantTempBatteryInlet", "C", "e", (bytes) => ((bytes[0] + ((bytes[1] & 0x3) << 8)) * 0.125) - 40); p.AddValue("CoolantTempPowertrainInlet", "C", "e", (bytes) => (((((bytes[2] & 0xF) << 8) + bytes[1]) >> 2) * 0.125) - 40); p.AddValue("Ambient Temp raw", "C", "e", (bytes) => ((bytes[3] * 0.5) - 40)); p.AddValue("Ambient Temp filtered", "C", "e", (bytes) => ((bytes[5] * 0.5) - 40)); packets.Add(0x3D2, p = new Packet(0x3D2, this)); p.AddValue("Charge total", "kWH", "bs", (bytes) => { chargeTotal = (bytes[0] + (bytes[1] << 8) + (bytes[2] << 16) + (bytes[3] << 24)) / 1000.0; /*if (mainActivity.currentTab.trip.chargeStart == 0) * mainActivity.currentTab.trip.chargeStart = chargeTotal; * charge = chargeTotal - mainActivity.currentTab.trip.chargeStart;*/ return(chargeTotal); }); p.AddValue("Discharge total", "kWH", "b", (bytes) => { dischargeTotal = (bytes[4] + (bytes[5] << 8) + (bytes[6] << 16) + (bytes[7] << 24)) / 1000.0; /*if (mainActivity.currentTab.trip.dischargeStart == 0) * mainActivity.currentTab.trip.dischargeStart = dischargeTotal; * discharge = dischargeTotal - mainActivity.currentTab.trip.dischargeStart;*/ return(dischargeTotal); }); /*packets.Add(0x712, p = new Packet(0x712, this)); * p.AddValue("Last cell block updated", "xb", "", (bytes) => { * int cell = 0; * double voltage = 0.0; * for (int i = 0; i < 3; i++) { * voltage = (((bytes[i * 2 + 3] << 8) + bytes[i * 2 + 2]) /100.0); * if (voltage > 0) * UpdateItem("Cell " + (cell = ((bytes[0]) * 3 + i + 1)).ToString().PadLeft(2) + " temp" * , "zVC" * , "z" * , bytes[0] * , voltage * , 0x712); * } * return bytes[0]; * }); */ // these are placeholders for the filters to be generated correctly. p.AddValue("Cell temp min", "C", "b", null); p.AddValue("Cell temp avg", "C", "bcp", null); p.AddValue("Cell temp max", "C", "b", null); p.AddValue("Cell temp diff", "Cd", "bc", null); p.AddValue("Cell min", "Vc", "b", null); p.AddValue("Cell avg", "Vc", "bpzr", null); p.AddValue("Cell max", "Vc", "b", null); p.AddValue("Cell diff", "Vcd", "bz", null); for (int i = 1; i <= 96; i++) { p.AddValue("Cell " + i.ToString().PadLeft(2) + " voltage" , "zVC" , "z", null); } for (int i = 1; i <= 32; i++) { p.AddValue("Cell " + i.ToString().PadLeft(2) + " temp" , "zCC" , "c" , null); } #endif }