internal void RaiseTagQualityChanged(LogixTag sender) { if (TagQualityChanged != null) { TagQualityChanged(sender, new TagQualityChangedEventArgs(sender)); } }
public static ReadDataServiceRequest BuildLogixReadDataRequest(LogixTag tag, ushort number, out int requestSize) { if (tag.TagInfo != null && tag.TagInfo.IsStructure == false && tag.TagInfo.Dimensions == 0) { //Short version ushort size = 0; switch ((CIPType)tag.TagInfo.DataType) { case CIPType.BITS: case CIPType.BOOL: size = 1; break; case CIPType.DINT: size = 4; break; case CIPType.INT: size = 2; break; case CIPType.LINT: size = 8; break; case CIPType.REAL: size = 4; break; case CIPType.SINT: size = 1; break; default: return BuildLogixReadDataRequest(tag.Address, number, out requestSize); } return BuildShortReadDataRequest(tag.TagInfo.MemoryAddress, number, size, out requestSize); } else { //Long version return BuildLogixReadDataRequest(tag.Address, number, out requestSize); } }
/// <summary> /// Writes a single tag /// </summary> /// <param name="tag">Tag to write</param> /// <returns>True if the write was successful</returns> /// <remarks>This is not the preferred method of updating tag information. If you have /// multiple tags that you want to update, use the <see cref="UpdateGroups"/> method.</remarks> public bool WriteTag(ITag tag) { lock (_lockObject) { LogixTag lgxTag = tag as LogixTag; if (lgxTag == null) { throw new ArgumentException(Resources.ErrorStrings.IncorrectArgTagType, "tag"); } WriteDataServiceReply lgxWrite = LogixServices.WriteLogixData(_session, lgxTag.Address, lgxTag.DataType, (ushort)lgxTag.Elements, lgxTag.GetWriteData(), lgxTag.StructHandle); if (lgxWrite == null) { return(false); } if (lgxWrite.Status == 0x00) { lgxTag.ClearPendingWrite(); return(true); } } return(false); }
internal void RaiseTagDataChanged(LogixTag sender) { if (TagValueUpdated != null) { TagValueUpdated(sender, new TagValueUpdateEventArgs(sender)); } }
/// <summary> /// Removes a tag from this tag group /// </summary> /// <param name="tag">Tag to be removed</param> /// <remarks> /// <para>Removing a tag triggers the tag group to re-optimize all /// of the tag read requests. This can be a long process for groups /// with large numbers of tags or tags that require a lot of data to /// be transferred.</para> /// <para>It is recommended that if you only need to remove a couple /// tags from a group that you disable them instead. Disabled tags /// will no longer update the value or send out update events.</para> /// </remarks> public void RemoveTag(LogixTag tag) { //lock (_lockObject) { _tags.Remove(tag); RebuildReadRequests(); } }
/// <summary> /// Reads a single tag /// </summary> /// <param name="tag">Tag to read</param> /// <returns>True if the read was successful</returns> /// <remarks>This is not the preferred method of updating tag information. If you have /// multiple tags that you want to update, use the <see cref="UpdateGroup"/> method.</remarks> public bool ReadTag(ITag tag) { lock (_lockObject) { LogixTag lgxTag = tag as LogixTag; if (lgxTag == null) { throw new ArgumentException(Resources.ErrorStrings.IncorrectArgTagType, "tag"); } ReadDataServiceReply lgxRead = LogixServices.ReadLogixData(_session, lgxTag.Address, (ushort)lgxTag.Elements); if (lgxRead == null || lgxRead.Data == null) { if (lgxRead != null) { lgxTag.SetTagError(lgxRead.ByteStatus); } lgxTag.LastError = Resources.ErrorStrings.TagNotFound + _ipAddress; lgxTag.LastErrorNumber = (int)LogixErrors.TagNotFound; return(false); } lgxTag.SetTagError(lgxRead.ByteStatus); CIPType tagType = (CIPType)lgxRead.DataType; byte[] temp = new byte[lgxRead.Data.Length + 2]; Buffer.BlockCopy(BitConverter.GetBytes(lgxRead.DataType), 0, temp, 0, 2); Buffer.BlockCopy(lgxRead.Data, 0, temp, 2, lgxRead.Data.Length); lgxTag.UpdateValue(temp); uint offset = (uint)lgxRead.Data.Length; if (lgxRead.Status == 0x06) { //We are going to have to request more data... while (lgxRead.Status == 0x06) { lgxRead = LogixServices.ReadLogixDataFragmented(_session, lgxTag.Address, (ushort)lgxTag.Elements, offset); lgxTag.SetTagError(lgxRead.ByteStatus); tagType = (CIPType)lgxRead.DataType; temp = new byte[lgxRead.Data.Length + 2]; Buffer.BlockCopy(BitConverter.GetBytes(lgxRead.DataType), 0, temp, 0, 2); Buffer.BlockCopy(lgxRead.Data, 0, temp, 2, lgxRead.Data.Length); lgxTag.UpdateValue(temp, offset); offset += (uint)lgxRead.Data.Length; } } } //End Lock return(true); }
/// <summary> /// Adds a tag to this tag group /// </summary> /// <param name="tag">Tag to be added</param> /// <remarks> /// <para>It is recommended that you create your groups once, then /// enable or disable them as you need them. Don't <see cref="RemoveTag"/> /// frequently, as this may degrade the performance of your application.</para> /// </remarks> public void AddTag(LogixTag tag) { //lock (_lockObject) { int idx = _tags.Count; _tags.Add(tag); AddOrCreateReadPacket(_tags[idx], idx); } }
/// <summary> /// Adds a tag to the processor /// </summary> /// <param name="tag">Tag to add (must be a LogixTag)</param> /// <returns>True if the tag was successfully added</returns> /// <remarks>This is used by the tag service to verify the /// tag actually exists.</remarks> internal bool AddTag(LogixTag tag) { //Here is the procedure for adding a tag: //1. Run some verification tests on the tag first //2. First create a read request for a single tag //3. Send the request to the PLC //4. Verify the response and data type //5. Store it in the tag LogixTag lgxTag = tag as LogixTag; if (lgxTag == null) { throw new ArgumentException(Resources.ErrorStrings.IncorrectArgTagType, "tag"); } if (!ReadTag(lgxTag)) { return(false); } return(true); }
static void WriteStructure(LogixTag tag, LogixProcessor processor) { Console.Write("The tag is a structure called " + ((LogixUDT)tag).TypeName + ", please enter a member name: "); string memberName = Console.ReadLine(); //First we have to find out if the member exists, if it doesn't we can't write to it... List<string> memberNames = ((LogixUDT)tag).MemberNames; bool hasMember = false; for (int i = 0; i < memberNames.Count; i++) { if (string.Compare(memberNames[i], memberName) == 0) { hasMember = true; break; } } if (!hasMember) { Console.WriteLine("The specified member could not be found in the structure"); return; } Console.Write("Enter a value: "); string sValue = Console.ReadLine(); //Now we have to convert it to the right type... try { switch (tag.LogixType) { case LogixTypes.Bool: if (sValue == "1") ((LogixUDT)tag)[memberName] = true; else ((LogixUDT)tag)[memberName] = false; break; case LogixTypes.DInt: ((LogixUDT)tag)[memberName] = Convert.ToInt32(sValue); break; case LogixTypes.Int: ((LogixUDT)tag)[memberName] = Convert.ToInt16(sValue); break; case LogixTypes.LInt: ((LogixUDT)tag)[memberName] = Convert.ToInt64(sValue); break; case LogixTypes.Real: ((LogixUDT)tag)[memberName] = Convert.ToSingle(sValue); break; case LogixTypes.SInt: ((LogixUDT)tag)[memberName] = Convert.ToSByte(sValue); break; case LogixTypes.User_Defined: default: Console.WriteLine("This demo does not support writing to nested structure tags"); return; } //At this point the tag has not been committed to the processor. The //tag must be written, then read back for the value to change. The //easiest way to do this with a single tag is to use the processor //LogixProcessor.WriteRead() which performs the write, then the //subsequent read on the tag. processor.WriteRead(tag); } catch (Exception e) { Console.WriteLine("Could not convert " + sValue + " to the correct type for " + tag.Address); } }
static void WriteOther(LogixTag tag, LogixProcessor processor) { Console.Write("Enter a value: "); string sValue = Console.ReadLine(); //Now we have to convert it to the right type... try { switch (tag.LogixType) { case LogixTypes.DInt: ((LogixDINT)tag).Value = Convert.ToInt32(sValue); break; case LogixTypes.Int: ((LogixINT)tag).Value = Convert.ToInt16(sValue); break; case LogixTypes.LInt: ((LogixLINT)tag).Value = Convert.ToInt64(sValue); break; case LogixTypes.Real: ((LogixREAL)tag).Value = Convert.ToSingle(sValue); break; case LogixTypes.SInt: ((LogixSINT)tag).Value = Convert.ToSByte(sValue); break; default: return; } //At this point the tag has not been committed to the processor. The //tag must be written, then read back for the value to change. The //easiest way to do this with a single tag is to use the processor //LogixProcessor.WriteRead() which performs the write, then the //subsequent read on the tag. processor.WriteRead(tag); } catch (Exception e) { Console.WriteLine("Could not convert " + sValue + " to the correct type for " + tag.Address); } }
static void WriteBool(LogixTag tag, LogixProcessor processor) { Console.WriteLine("Enter 1 for True, 0 for False: "); char key = Console.ReadKey().KeyChar; if (key == '1') ((LogixBOOL)tag).Value = true; else ((LogixBOOL)tag).Value = false; //At this point the tag has not been committed to the processor. The //tag must be written, then read back for the value to change. The //easiest way to do this with a single tag is to use the processor //LogixProcessor.WriteRead() which performs the write, then the //subsequent read on the tag. processor.WriteRead(tag); }
static void PrintTagValue(LogixTag tag) { //Now we'll determine the value of the tag... switch (tag.LogixType) { case LogixTypes.Bool: Console.WriteLine("BOOL value is: " + ((LogixBOOL)tag).Value.ToString()); break; case LogixTypes.Control: //The control tag is a lot more complicated, there is no way currently to know //which member was updated, so all you can do is say it was updated, we'll print //out one of the members though. Console.WriteLine("Control.POS is: " + ((LogixCONTROL)tag).POS.ToString()); break; case LogixTypes.Counter: //Same as the counter above, we'll just print out the ACC value Console.WriteLine("Counter.ACC value is: " + ((LogixCOUNTER)tag).ACC.ToString()); break; case LogixTypes.DInt: //Print out the value. DINT's are equivalent to int in .NET Console.WriteLine("DINT value is: " + ((LogixDINT)tag).Value.ToString()); break; case LogixTypes.Int: //An INT in a logix processor is more like a short in .NET Console.WriteLine("INT value is: " + ((LogixINT)tag).Value.ToString()); break; case LogixTypes.LInt: //LINT's are equivalent to long in .NET Console.WriteLine("LINT value is: " + ((LogixLINT)tag).Value.ToString()); break; case LogixTypes.Real: //REALs are single precision floats Console.WriteLine("REAL value is: " + ((LogixREAL)tag).Value.ToString()); break; case LogixTypes.SInt: //SINTs are signed bytes Console.WriteLine("SINT value is: " + ((LogixSINT)tag).Value.ToString()); break; case LogixTypes.String: //Strings are just like .NET strings, so notice how we can skip the .StringValue //member, since the .ToString() will automatically be called, which returns the //same value as .StringValue Console.WriteLine("STRING value is: " + ((LogixSTRING)tag)); break; case LogixTypes.Timer: //Timers again are like the CONTROL and COUNTER types Console.WriteLine("Timer.ACC value is: " + ((LogixTIMER)tag).ACC.ToString()); break; case LogixTypes.User_Defined: //The only way to get the value out of a UDT, PDT, or MDT is to define the //structure or know the member name you wish to read. We'll just print that //we know its a UDT, MDT, or PDT that changed. Console.WriteLine("User defined type"); break; default: break; } }
private void AddOrCreateReadPacket(LogixTag tag, int idx) { //First we create the request... int temp = 0; ReadDataServiceRequest request = LogixServices.BuildLogixReadDataRequest( tag.Address, tag.Elements, out temp); //Now we read it from the PLC to find out if it's fragmented... CommonPacketItem addressItem = CommonPacketItem.GetConnectedAddressItem(_parent.SessionInfo.ConnectionParameters.O2T_CID); CommonPacketItem dataItem = CommonPacketItem.GetConnectedDataItem(request.Pack(), SequenceNumberGenerator.SequenceNumber); EncapsReply reply = _parent.SessionInfo.SendUnitData(addressItem, dataItem); if (reply != null) { //It's a good tag, let's figure out if it's fragmented... ReadDataServiceReply rdReply = new ReadDataServiceReply(reply); PacketMap pm = new PacketMap() { TagIndex = idx }; pm.PacketIndex = new List <int>(); pm.ServiceIndex = new List <int>(); pm.Offsets = new List <uint>(); pm.NumReplies = 1; if (rdReply.Status == 0x06) { //Partial read... We'll have to request more data, but first let's make this packet request = LogixServices.BuildFragmentedReadDataRequest(tag.Address, tag.Elements, 0, out temp); int[] status = FindPacketOrCreate(request.Pack(), (ushort)(rdReply.Data.Length + 2)); uint offset = (uint)rdReply.Data.Length; pm.PacketIndex.Add(status[0]); pm.ServiceIndex.Add(status[1]); pm.Offsets.Add(0); while (rdReply.Status == 0x06) { rdReply = LogixServices.ReadLogixDataFragmented(_parent.SessionInfo, tag.Address, tag.Elements, offset); request = LogixServices.BuildFragmentedReadDataRequest(tag.Address, tag.Elements, offset, out temp); status = FindPacketOrCreate(request.Pack(), (ushort)(rdReply.Data.Length + 2)); pm.PacketIndex.Add(status[0]); pm.ServiceIndex.Add(status[1]); offset += (uint)rdReply.Data.Length; pm.Offsets.Add(offset); pm.NumReplies++; } } else if (rdReply.Status == 0x00 && rdReply.Data != null) { //Full read, create the packet... int[] status = FindPacketOrCreate(request.Pack(), (ushort)(rdReply.Data.Length + 2)); pm.PacketIndex.Add(status[0]); pm.ServiceIndex.Add(status[1]); pm.Offsets.Add(0); } _readPackets.Add(pm); } }
internal void RaiseTagQualityChanged(LogixTag sender) { if (TagQualityChanged != null) TagQualityChanged(sender, new TagQualityChangedEventArgs(sender)); }
internal void RaiseTagDataChanged(LogixTag sender) { if (TagValueUpdated != null) TagValueUpdated(sender, new TagValueUpdateEventArgs(sender)); }