// Get the length of the area in words (2 bytes per word) public static int GetSpan(Modbus MB, T start, T end) { AttrData startAttr = MB.GetAttrData(start); // Starting memory address (Words) AttrData endAttr = MB.GetAttrData(end); // Ending memory address Debug.Assert(startAttr.Val <= endAttr.Val); // Make sure they are in the correct order return(endAttr.Val - startAttr.Val + endAttr.Data.Len); // Be sure to include the last element }
private void GetMessages(ModbusPkt pkt) { StringBuilder sb = new StringBuilder(); List <string> msgs = new List <string>(); string[] s = new string[3]; // For now, look at the first 48 only. Need to implement block read AttrData attrCount = MB.GetAttrData(ccMM.Registration); for (int i = 0; i < Math.Min(3, attrCount.Count); i++) { int reg = MB.GetDecAttribute(ccMM.Registration, i); if (reg == 0) { continue; } for (int j = 15; j >= 0; j--) { if ((reg & (1 << j)) > 0) { int n = i * 16 - j + 15; // 1-origin MB.SetAttribute(ccIDX.Start_Stop_Management_Flag, 1); MB.SetAttribute(ccIDX.Message_Number, n + 1); // Load the message into input registers MB.SetAttribute(ccIDX.Start_Stop_Management_Flag, 2); s[0] = MB.GetHRAttribute(ccMM.Group_Number); s[1] = MB.GetHRAttribute(ccMM.Message_Number); s[2] = MB.GetHRAttribute(ccMM.Message_Name); msgs.Add(string.Join(",", s)); } } } AsyncComplete ac = new AsyncComplete(MB, pkt) { MultiLine = msgs.ToArray() }; parent.BeginInvoke(new EventHandler(delegate { Complete(this, ac); })); }
// Attribute selection changed private void cbAttribute_SelectedIndexChanged(object sender, EventArgs e) { cbInstance.Items.Clear(); if (cbAttribute.SelectedIndex >= 0) { int n1 = Array.FindIndex(ccNames, x => x == cbClass.Text); attValues = (int[])Enum.GetValues(MB.ClassCodeAttributes[n1]); int n2 = Array.FindIndex(attrNames, x => x == cbAttribute.Text); attr = MB.GetAttrData(MB.ClassCodes[n1], attValues[n2]); if (attr.HoldingReg) { optHoldingRegister.Checked = true; } else { optInputRegister.Checked = true; } switch (attr.Nozzle) { case Noz.None: cbNozzle.SelectedIndex = 0; break; case Noz.Current: cbNozzle.SelectedIndex = MB.Nozzle + 1; break; case Noz.Both: cbNozzle.SelectedIndex = 3; break; default: break; } int n = attr.Count; for (int i = 0; i < n; i++) { cbInstance.Items.Add(i); } cbInstance.SelectedIndex = 0; } }
// Get an attribute and convert it to a string for SOP output public string Get(T item, int index, int resultLen) { string result = string.Empty; AttrData getAttr = MB.GetAttrData(item); // Get attributes of desired item int n = (getAttr.Val - BaseAttr.Val) * 2 + // Get offset in byte array (2 bytes per word) (index - this.Index) * BaseAttr.Stride * 2; // Relative to the Index that was loaded int len = getAttr.Data.Len; // Get length switch (getAttr.Data.Fmt) // Format the data as needed { case DataFormats.None: break; case DataFormats.SDecimal: case DataFormats.Decimal: len += len; // Length is in words so double it int res = 0; for (int i = 0; i < len; i++) { res = (res << 8) + b[n + i]; // Words are stored in Big Endial format } result = res.ToString($"D{resultLen}"); // To string with leading zeros break; case DataFormats.UTF8: char[] c = new char[len]; Buffer.BlockCopy(b, n + 1, c, 0, len * 2 - 1); // Characters are stored as little endian. result = new string(c); break; case DataFormats.Date: // Probably on a TODO list case DataFormats.Bytes: case DataFormats.AttrText: default: break; } MB.LogIt($"BGet[{MB.GetNozzle(getAttr)}{getAttr.Val:X4}+{n / 2:X4}] {MB.GetAttributeName(getAttr.Class, getAttr.Val)} = " + $"{result}"); return(result); }
// Let Section find the attrData public Section(Modbus MB, T attr, int index, int Len, bool load) : this(MB, MB.GetAttrData(attr), index, Len, load) { }
bool Load; // Save to cut down on trace I/O #endregion #region Constructor, Destructor, and Service Routines // Let Section find the attrData and calculate the span public Section(Modbus MB, T startAttr, T endAttr, int index, bool load) : this(MB, MB.GetAttrData(startAttr), index, GetSpan(MB, startAttr, endAttr), load) { }