/// <summary> /// Creates a new <see cref="LogixTag"/> with the specified TagAddress and adds it to the <see cref="T:LogixProcessor"/>. /// </summary> /// <param name="tagAddress">Address (Tag Name) of the item on the Processor.</param> /// <param name="processor">Processor to add this <c>LogixTag</c> to.</param> internal LogixTag(string tagAddress, LogixProcessor processor) : this(tagAddress) { _parent = processor; //Processor.AddTag(this); //Everything else is automatically set by the processor }
static void processor_KeySwitchChanged(LogixProcessor sender, LogixKeyChangedEventArgs e) { //This function will be called when the key switch changes position. The key switch is on the front of //the processor and can either be in Run, Program or Remote mode. There is an additional member of the //ProcessorKeySwitch enumeration called "Unknown" which is used when the value hasn't been read yet or //can't be obtained. Console.WriteLine("Processor Key Position Changed from " + e.OldPosition.ToString() + " to " + e.NewPosition.ToString()); }
/// <summary> /// Creates a new LogixTagGroup on the specified processor. It is /// recommended that you use <see cref="LogixProcessor.CreateTagGroup"/> /// to create tag groups instead of this constructor so the processor /// can manage the group. /// </summary> /// <param name="processor">Processor that the group belongs to</param> /// <param name="groupName">Name of the group, must be unique on the processor</param> public LogixTagGroup(LogixProcessor processor, string groupName) { //ToDo _logger = processor.LoggerFactory.CreateLogger <LogixTagGroup>(); _parent = processor; _groupName = groupName; _enabled = true; _tags = new List <LogixTag>(); _readPackets = new List <PacketMap>(); _msrPackets = new List <MultiServiceRequest>(); }
/* * HOW TO USE THIS SAMPLE * * 1. First change the hostNameOrIp to the IP address or host name of your PLC * 2. Then change the path to be the path to your PLC, see comments below * 3. Create a new User Defined Type on the processor called CustomUDT * 4. Add the following members to the type: * 1. Enabled : BOOL * 2. UpperLimit : DINT * 3. LowerLimit : DINT * 4. RunningValue : REAL * 5. Over : BOOL * 6. Under : BOOL * 5. Create a new tag of type CustomUDT called myCustomUDT * 6. Run * */ static void Main(string[] args) { //First we create the processor object. Typically the path is the slot //number of the processor module in the backplane, but if your communications //card is not in the same chassis as your processor, this is the path through //the chassis to get to your processor. You will have to add a 1 for every //chassis you go through, for example: //Chassis 1: ENBT card in Slot 1 (slot is irrelavent), ControlNet Card in Slot 2 //Chassis 2: L61 in Slot 4 //Path would be: { 2, 1, 4 } //Basically it's the target slot, 1 for backplane, target slot, 1 for backplane... //until you get to the processor. string hostNameOrIp = "192.168.1.10"; byte[] path = new byte[] { 1 }; LogixProcessor processor = new LogixProcessor(hostNameOrIp, path); //The processor has to be connected before you add any tags or tag groups. if (!processor.Connect()) { Console.WriteLine("Could not connect to the processor"); Console.ReadKey(false); return; } Console.WriteLine("6D Systems LLC\n\n"); //First create a group. Groups are much more efficient at reading and writing //large numbers of tags or complex tags like UDTs. LogixTagGroup myGroup = processor.CreateTagGroup("MyGroup"); CustomUDT myCustomUDT = new CustomUDT("myCustomUDT", processor); myCustomUDT.TagValueUpdated += new ICommon.TagValueUpdateEventHandler(TagValueUpdated); //Add the tag to the group... myGroup.AddTag(myCustomUDT); //Set the group to auto update processor.EnableAutoUpdate(500); //Print out some structure information: PrintStructure(myCustomUDT); //Now wait for updates... Console.WriteLine("Change some data in the custom type, then hit Enter to quit"); Console.ReadLine(); processor.Disconnect(); }
static void WriteTag(LogixProcessor processor) { //Writing a tag is also very easy. First, create a tag... string address = GetTagAddress(); if (string.IsNullOrEmpty(address)) { return; } //Now we have to create the tag on the processor. The easiest way to //do this without knowing the underlying type is to use the //LogixTagFactory class. LogixTag userTag = LogixTagFactory.CreateTag(address, processor); if (userTag == null) { Console.WriteLine("Could not create the tag " + address + " on the processor"); return; } switch (userTag.LogixType) { case LogixTypes.Bool: WriteBool(userTag, processor); break; case LogixTypes.DInt: case LogixTypes.LInt: case LogixTypes.Real: case LogixTypes.SInt: WriteOther(userTag, processor); break; case LogixTypes.Control: case LogixTypes.Counter: case LogixTypes.Timer: case LogixTypes.User_Defined: WriteStructure(userTag, processor); break; default: Console.WriteLine("The LogixType of " + userTag.LogixType.ToString() + " is not supported in this sample"); return; } PrintTagValue(userTag); //And go back to the menu }
/// <summary> /// Creates a new <see cref="LogixTag"/> with the specified TagAddress and adds it to the <see cref="T:LogixProcessor"/>. /// </summary> /// <param name="tagAddress">Address (Tag Name) of the item on the Processor.</param> /// <param name="processor">Processor to add this <c>LogixTag</c> to.</param> /// <param name="elementCount"></param> /// <param name="initData"></param> internal LogixTag(string tagAddress, LogixProcessor processor, ushort elementCount, object initData = null) #endif { _enabled = true; _parent = processor; _dataType = 0x00; _address = tagAddress; _lastError = string.Empty; _lastErrorNumber = 0; _tagQuality = TagQuality.Unknown; _timeStamp = DateTime.MinValue; _elements = elementCount; Initialize(initData); //Processor.AddTag(this); }
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 ReadTag(LogixProcessor processor) { //Reading a tag is very easy. First, create a tag... string address = GetTagAddress(); if (string.IsNullOrEmpty(address)) { return; } //Now we have to create the tag on the processor. The easiest way to //do this without knowing the underlying type is to use the //LogixTagFactory class. LogixTag userTag = LogixTagFactory.CreateTag(address, processor); if (userTag == null) { Console.WriteLine("Could not create the tag " + address + " on the processor"); return; } //The tag is automatically read when it is created. The LogixProcessor does this //to verify the tag exists and to get type information about the tag. From this //point on you can read/write the tag all you want, either by using tag groups //or by directly writing it with the LogixProcessor.WriteTag() function. //We'll demonstrate a read anyway... if (!processor.ReadTag(userTag)) { Console.WriteLine("Could not read the tag: " + userTag.LastError); } //Print the value out with our handy helper function PrintTagValue(userTag); //And go back to the main menu }
static void TagInformation(LogixProcessor processor) { //Getting detailed tag information is actually an expensive process. Currently //there is no way to get detailed information about a tag except to request all //the tag information in the PLC. The GetTagInformation will read all the tags //in the PLC, then return the one you are looking for. string address = GetTagAddress(); if (string.IsNullOrEmpty(address)) { return; } LogixTagInfo tagInfo = processor.GetTagInformation(address); if (tagInfo == null) { Console.WriteLine("The tag '" + address + "' could not be found on the processor"); Console.ReadKey(false); return; } Console.WriteLine(tagInfo.ToString()); }
/* * HOW TO USE THIS SAMPLE * * 1. First change the hostNameOrIp to the IP address or host name of your PLC * 2. Then change the path to be the path to your PLC, see comments below * 3. Create a user defined type tag in your processor called myUDT1 * 4. Create an ALARM tag in your processor called myAlarm1 * 5. Run * */ static void Main(string[] args) { //First we create the processor object. Typically the path is the slot //number of the processor module in the backplane, but if your communications //card is not in the same chassis as your processor, this is the path through //the chassis to get to your processor. You will have to add a 1 for every //chassis you go through, for example: //Chassis 1: ENBT card in Slot 1 (slot is irrelavent), ControlNet Card in Slot 2 //Chassis 2: L61 in Slot 4 //Path would be: { 2, 1, 4 } //Basically it's the target slot, 1 for backplane, target slot, 1 for backplane... //until you get to the processor. string hostNameOrIp = "192.168.1.10"; byte[] path = new byte[] { 1 }; LogixProcessor processor = new LogixProcessor(hostNameOrIp, path); //The processor has to be connected before you add any tags or tag groups. if (!processor.Connect()) { Console.WriteLine("Could not connect to the processor"); Console.ReadKey(false); return; } Console.WriteLine("6D Systems LLC\n\n"); //First create a group. Groups are much more efficient at reading and writing //large numbers of tags or complex tags like UDTs. LogixTagGroup myGroup = processor.CreateTagGroup("MyGroup"); //Ok, let's create the first tag which is some random user defined type LogixTag genericTag = LogixTagFactory.CreateTag("myUDT1", processor); LogixUDT udtTag = genericTag as LogixUDT; if (udtTag == null) { Console.WriteLine("The tag 'myUDT1' on the processor is not a structure tag"); Console.WriteLine("Press any key to quit"); Console.ReadKey(false); processor.Disconnect(); return; } //Let's print out some information about the UDT PrintStructure(udtTag); //The value of any member can also be set with the tagName[memberName] = value syntax //Now let's get information about the alarm tag that was created... LogixTag genericAlarm = LogixTagFactory.CreateTag("myAlarm1", processor); LogixUDT alarmTag = genericAlarm as LogixUDT; if (alarmTag == null) { Console.WriteLine("The tag 'myAlarm1' is not a structure tag"); Console.WriteLine("Press any key to quit"); Console.ReadKey(false); processor.Disconnect(); return; } //Print out information about it... PrintStructure(alarmTag); //Now, let's set up the tags in the group, set the group to auto update, and watch //for tag update events... myGroup.AddTag(udtTag); myGroup.AddTag(alarmTag); udtTag.TagValueUpdated += new ICommon.TagValueUpdateEventHandler(TagValueUpdated); alarmTag.TagValueUpdated += new ICommon.TagValueUpdateEventHandler(TagValueUpdated); processor.EnableAutoUpdate(500); Console.WriteLine("Press Enter to quit"); Console.ReadLine(); processor.Disconnect(); }
static void processor_FaultStateChanged(LogixProcessor sender, LogixFaultStateChangedEventArgs e) { //This function is called when the processor fault state changes. The fault states are None, Minor //Recoverable, Minor Unrecoverable, Major Recoverable, and Major Unrecoverable. Console.WriteLine("Processor Fault Mode Changed from " + e.OldState.ToString() + " to " + e.NewState.ToString()); }
/// <summary> /// Creates a new <see cref="LogixTag"/> with the specified TagAddress and adds it to the <see cref="T:LogixProcessor"/>. /// </summary> /// <param name="TagAddress">Address (Tag Name) of the item on the Processor.</param> /// <param name="Processor">Processor to add this <c>LogixTag</c> to.</param> /// <param name="ElementCount"></param> internal LogixTag(string TagAddress, LogixProcessor Processor, ushort ElementCount, object InitData = null) #endif { _enabled = true; _parent = Processor; _dataType = 0x00; _address = TagAddress; _lastError = string.Empty; _lastErrorNumber = 0; _tagQuality = TagQuality.Unknown; _timeStamp = DateTime.MinValue; _elements = ElementCount; Initialize(InitData); //Processor.AddTag(this); }
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); } }
private static LogixTag CreateStructTag(string Address, LogixProcessor Processor, ushort Elements, TemplateInfo Template) { if (Template.TemplateName == "COUNTER") { return new LogixCOUNTER(Address, Template, Processor, Elements); } else if (Template.TemplateName == "CONTROL") { return new LogixCONTROL(Address, Template, Processor, Elements); } else if (Template.TemplateName == "TIMER") { return new LogixTIMER(Address, Template, Processor, Elements); } else if (Template.TemplateName == "ASCIISTRING82") { return new LogixSTRING(Address, Template, Processor, Elements); } else { //Return as a UDT... return new LogixUDT(Address, Template, Processor, Elements); } }
/// <summary> /// Creates a new BOOL Logix Tag on the specified Processor with the number of Elements /// </summary> /// <param name="TagAddress">Address (Tag Name) in the processor</param> /// <param name="Processor">Processor where the tag resides</param> /// <param name="ElementCount">Number of elements to read</param> public LogixBOOL(string TagAddress, LogixProcessor Processor, ushort ElementCount) : base(TagAddress, Processor, ElementCount) { }
/// <summary> /// Creates a new User-Defined Type Logix Tag on the specified Processor /// </summary> /// <param name="TagAddress">Address (Tag Name) in the processor</param> /// <param name="TemplateInfo">Template information about the type</param> /// <param name="Processor">Processor where the tag resides</param> internal LogixUDT(string TagAddress, TemplateInfo TemplateInfo, LogixProcessor Processor) : base(TagAddress, Processor, 1, TemplateInfo) { _templateInfo = TemplateInfo; }
internal static TemplateInfo GetTemplateInfo(string Address, LogixProcessor Processor, ushort Elements) { //lock (Processor.SyncRoot) { ReadDataServiceReply lgxRead = LogixServices.ReadLogixData( Processor.SessionInfo, Address, Elements); if (lgxRead == null) return null; if (lgxRead.Data == null) return null; if (lgxRead.Status != 0x00 && lgxRead.Status != 0x06) { return null; } //The first two bytes are the type... CIPType tagType = (CIPType)lgxRead.DataType; if (tagType == CIPType.STRUCT) { //We need to build an information object about this type //The first two bytes are a handle to the structure... ushort structureId = Processor.GetStructureHandle(Address); //Now we can send a request to get the attributes... TemplateInfo ti = ReadStructAttributes(structureId, Processor); return ti; } } return null; }
/* * HOW TO USE THIS SAMPLE * * 1. First change the hostNameOrIp to the IP address or host name of your PLC * 2. Then change the path to be the path to your PLC, see comments below * 3. Run * */ static void Main(string[] args) { //First we create the processor object. Typically the path is the slot //number of the processor module in the backplane, but if your communications //card is not in the same chassis as your processor, this is the path through //the chassis to get to your processor. You will have to add a 1 for every //chassis you go through, for example: //Chassis 1: ENBT card in Slot 1 (slot is irrelavent), ControlNet Card in Slot 2 //Chassis 2: L61 in Slot 4 //Path would be: { 2, 1, 4 } //Basically it's the target slot, 1 for backplane, target slot, 1 for backplane... //until you get to the processor. string hostNameOrIp = "192.168.1.10"; byte[] path = new byte[] { 0 }; LogixProcessor processor = new LogixProcessor(hostNameOrIp, path); //Connect to the PLC, you can create the events before or after the connect function if (!processor.Connect()) { Console.WriteLine("Could not connect to the processor"); Console.ReadKey(false); return; } //Create the events, the processor state is updated every second, and if there is //a change in either the fault state, key switch position, or processor state (RUN, PROGRAM, TEST), //then one of these events will be fired. processor.FaultStateChanged += new LogixFaultStateChangedEvent(processor_FaultStateChanged); processor.KeySwitchChanged += new LogixKeyPositionChangedEvent(processor_KeySwitchChanged); processor.ProcessorStateChanged += new LogixProcessorStateChangedEvent(processor_ProcessorStateChanged); Console.WriteLine("6D Systems LLC"); Console.WriteLine("Processor State Example: Change the key switch, fault state, or processor\nmode to see a message displayed"); Console.WriteLine("\nProcessor Information:\n" + processor); Console.WriteLine("\n\n"); //The processor can, through source code, be put in Program mode or Run mode. This is useful //if you are developing a critical process where you want to be able to shut all the outputs //off on the PLC at one time. Mode changes only work if the processor key is in Remote //The .UserData field can be used to store any data you desire, and it will be persisted //with the processor object. This is useful, for example, for storing information about //a processor when it's in a dictionary... processor.UserData = "MainPLC_1"; bool quitFlag = false; while (!quitFlag) { Console.WriteLine("\n\n=============================MENU============================="); Console.WriteLine("Press the 'P' key to put the processor in Program mode"); Console.WriteLine("Press the 'R' key to put the processor in Run mode"); Console.WriteLine("Press the 'U' key to display the processor UserData"); Console.WriteLine("Press the 'T' key to display all the tags on the processor"); Console.WriteLine("Press the 'Q' key to quit"); Console.WriteLine("=============================================================="); char key = Console.ReadKey(true).KeyChar; switch (key) { case 'p': case 'P': Console.WriteLine("Setting processor to Program mode..."); processor.SetProgramMode(); break; case 'r': case 'R': Console.WriteLine("Setting processor to Run mode..."); processor.SetRunMode(); break; case 'u': case 'U': Console.WriteLine("UserData: " + (string)processor.UserData); break; case 't': case 'T': List <LogixTagInfo> tagInfo = processor.EnumerateTags(); if (tagInfo == null) { Console.WriteLine("No tags found"); break; } Console.WriteLine("There are " + tagInfo.Count + " tags..."); foreach (LogixTagInfo info in tagInfo) { string name = info.TagName; if (info.Dimensions > 0) { name += "[" + info.Dimension1Size.ToString(); } if (info.Dimensions > 1) { name += ", " + info.Dimension2Size.ToString(); } if (info.Dimensions > 2) { name += ", " + info.Dimension3Size.ToString(); } if (info.Dimensions > 0) { name += "]"; } Console.WriteLine("\t" + name); } break; case 'q': case 'Q': quitFlag = true; break; default: break; } } //Always remember to disconnect the PLC. If you forget, the PLC won't allow you to reconnect //until the session times out. This is typically about 45-60 seconds. processor.Disconnect(); }
/// <summary> /// Creates a new LogixUDT /// </summary> /// <param name="TagAddress">Address (Tag Name) of the tag on the processor</param> /// <param name="Processor">Processor that the tag belongs to</param> public LogixUDT(string TagAddress, LogixProcessor Processor) : base (TagAddress, Processor, 1, null) { }
static void processor_ProcessorStateChanged(LogixProcessor sender, LogixProcessorStateChangedEventArgs e) { //This function will be called whenever the processor changes state. The processor state is information //like what mode it's in, if it has a communications fault, if it's in firmware update mode, etc. Console.WriteLine("Processor State Changed from " + e.OldState.ToString() + " to " + e.NewState.ToString()); }
internal LogixTag(string TagAddress, LogixProcessor Processor, ushort ElementCount, object InitData)
internal static LogixTag CreateQuickTag(string Address, LogixProcessor Processor, ushort Elements) { if (Address.Contains(".") || Address.Contains("[")) { return CreateLongTag(Address, Processor, Elements); } LogixTagInfo ti = Processor.GetInfoForTag(Address); if (ti == null) return null; if (ti.IsStructure) { //We need to build an information object about this type //The first two bytes are a handle to the structure... ushort structureId = Processor.GetStructureHandle(Address); //Now we can send a request to get the attributes... TemplateInfo tempInfo = ReadStructAttributes(structureId, Processor); LogixTag st = CreateStructTag(Address, Processor, Elements, tempInfo); st.TagInfo = ti; } else { LogixTag at = null; switch ((CIPType)ti.DataType) { case CIPType.BITS: case CIPType.BOOL: at = new LogixBOOL(Address, Processor, Elements); break; case CIPType.SINT: at = new LogixSINT(Address, Processor, Elements); break; case CIPType.INT: at = new LogixINT(Address, Processor, Elements); break; case CIPType.DINT: at = new LogixDINT(Address, Processor, Elements); break; case CIPType.LINT: at = new LogixLINT(Address, Processor, Elements); break; case CIPType.REAL: at = new LogixREAL(Address, Processor, Elements); break; default: break; //Unknown type... } if (at != null) { at.TagInfo = ti; return at; } } return null; }
static void ReadTag(LogixProcessor processor) { //Reading a tag is very easy. First, create a tag... string address = GetTagAddress(); if (string.IsNullOrEmpty(address)) return; //Now we have to create the tag on the processor. The easiest way to //do this without knowing the underlying type is to use the //LogixTagFactory class. LogixTag userTag = LogixTagFactory.CreateTag(address, processor); if (userTag == null) { Console.WriteLine("Could not create the tag " + address + " on the processor"); return; } //The tag is automatically read when it is created. The LogixProcessor does this //to verify the tag exists and to get type information about the tag. From this //point on you can read/write the tag all you want, either by using tag groups //or by directly writing it with the LogixProcessor.WriteTag() function. //We'll demonstrate a read anyway... if (!processor.ReadTag(userTag)) Console.WriteLine("Could not read the tag: " + userTag.LastError); //Print the value out with our handy helper function PrintTagValue(userTag); //And go back to the main menu }
private static TemplateInfo ReadStructAttributes(ushort structureId, LogixProcessor processor) { //First we have to get the template info... GetStructAttribsRequest attribsReq = new GetStructAttribsRequest(structureId); CommonPacketItem addressItem = CommonPacketItem.GetNullAddressItem(); UnconnectedSend ucmm = new UnconnectedSend(); ucmm.Priority_TimeTick = 0x07; ucmm.Timeout_Ticks = 0x9B; ucmm.RoutePath = processor.Path; ucmm.MessageRequest = new MR_Request(); ucmm.MessageRequest.Request_Path = new byte[] { 0x20, 0x6C, 0x25, 0x00, (byte)((structureId & 0x00FF)), (byte)((structureId & 0xFF00) >> 8) }; ucmm.MessageRequest.Service = 0x03; ucmm.MessageRequest.Request_Data = new byte[] { 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, 0x01, 0x00 }; ucmm.RequestPath = CommonPaths.ConnectionManager; CommonPacketItem dataItem = CommonPacketItem.GetUnconnectedDataItem(ucmm.Pack()); EncapsReply reply = processor.SessionInfo.SendRRData(addressItem, dataItem); if (reply.Status != 0x00) return null; //We have to get the data out... EncapsRRData rrData = new EncapsRRData(); CommonPacket cpf = new CommonPacket(); int temp = 0; rrData.Expand(reply.EncapsData, 0, out temp); cpf = rrData.CPF; byte[] replyData = new byte[28]; Buffer.BlockCopy(cpf.DataItem.Data, 4, replyData, 0, 28); GetStructAttribsReply structAttribs = new GetStructAttribsReply(replyData); //Great... now we can request the structure template and be able to read it! ucmm.MessageRequest.Service = 0x4C; //We can only read about 480 bytes at a time, so we may have to break it up... uint bytesRemaining = (structAttribs.TemplateSize - 5) * 4; uint offset = 0; List<byte> structInfoBytes = new List<byte>(); while (bytesRemaining > 0) { ushort bytesToRead; if (bytesRemaining < 480) { bytesToRead = (ushort)bytesRemaining; bytesRemaining = 0; } else { bytesToRead = 480; bytesRemaining -= 480; } byte[] tempB = new byte[6]; Buffer.BlockCopy(BitConverter.GetBytes(offset), 0, tempB, 0, 4); Buffer.BlockCopy(BitConverter.GetBytes(bytesToRead), 0, tempB, 4, 2); ucmm.MessageRequest.Request_Data = tempB; dataItem = CommonPacketItem.GetUnconnectedDataItem(ucmm.Pack()); reply = processor.SessionInfo.SendRRData(addressItem, dataItem); if (reply.Status != 0x00) continue; rrData.Expand(reply.EncapsData, 0, out temp); cpf = rrData.CPF; //get the data out... tempB = new byte[cpf.DataItem.Data.Length - 4]; Buffer.BlockCopy(cpf.DataItem.Data, 4, tempB, 0, cpf.DataItem.Data.Length - 4); structInfoBytes.AddRange(tempB); offset += bytesToRead; } //Now we have all the data!!!! return new TemplateInfo(structInfoBytes.ToArray(), structAttribs); }
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); }
/// <summary> /// Creates a new BOOL Logix Tag on the specified Processor /// </summary> /// <param name="TagAddress">Address (Tag Name) in the processor</param> /// <param name="Processor">Processor where the tag resides</param> public LogixBOOL(string TagAddress, LogixProcessor Processor) : base(TagAddress, Processor) { }
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); } }
internal LogixTag(string TagAddress, LogixProcessor Processor, ushort ElementCount) : this(TagAddress, Processor, ElementCount, null) { }
/* * HOW TO USE THIS SAMPLE * * 1. First change the hostNameOrIp to the IP address or host name of your PLC * 2. Then change the path to be the path to your PLC, see comments below * 3. Run * */ static void Main(string[] args) { //First we create the processor object. Typically the path is the slot //number of the processor module in the backplane, but if your communications //card is not in the same chassis as your processor, this is the path through //the chassis to get to your processor. You will have to add a 1 for every //chassis you go through, for example: //Chassis 1: ENBT card in Slot 1 (slot is irrelavent), ControlNet Card in Slot 2 //Chassis 2: L61 in Slot 4 //Path would be: { 2, 1, 4 } //Basically it's the target slot, 1 for backplane, target slot, 1 for backplane... //until you get to the processor. string hostNameOrIp = "192.168.1.10"; byte[] path = new byte[] { 0 }; LogixProcessor processor = new LogixProcessor(hostNameOrIp, path); //The processor has to be connected before you add any tags or tag groups. if (!processor.Connect()) { Console.WriteLine("Could not connect to the processor"); Console.ReadKey(false); return; } string menu = "6D Systems LLC\n" + "-----------------------------------------\n" + "(1) - Get Information About A Tag\n" + "(2) - Read a tag\n" + "(3) - Write a tag\n" + "(Q) - Quit\n" + "-----------------------------------------\n" + "Enter your choice:"; bool quitFlag = false; while (!quitFlag) { Console.Clear(); Console.Write(menu); string key = Console.ReadLine(); switch (key) { case "1": TagInformation(processor); break; case "2": ReadTag(processor); break; case "3": WriteTag(processor); break; case "q": case "Q": quitFlag = true; continue; default: Console.WriteLine("Invalid entry"); break; } Console.WriteLine("Hit any key to go back to the menu"); Console.ReadKey(false); } //Remember to disconnect from the processor. If you forget, the processor won't allow you //to reconnect until the session times out, which is typically 60 seconds. processor.Disconnect(); }
static void Main(string[] args) { //First we create the processor object. Typically the path is the slot //number of the processor module in the backplane, but if your communications //card is not in the same chassis as your processor, this is the path through //the chassis to get to your processor. You will have to add a 1 for every //chassis you go through, for example: //Chassis 1: ENBT card in Slot 1 (slot is irrelavent), ControlNet Card in Slot 2 //Chassis 2: L61 in Slot 4 //Path would be: { 2, 1, 4 } //Basically it's the target slot, 1 for backplane, target slot, 1 for backplane... //until you get to the processor. string hostNameOrIp = "192.168.1.10"; byte[] path = new byte[] { 1 }; LogixProcessor processor = new LogixProcessor(hostNameOrIp, path); //Connect to the PLC, you can create the events before or after the connect function if (!processor.Connect()) { Console.WriteLine("Could not connect to the processor"); Console.ReadKey(false); return; } //Tag groups allow you to group tags in a useful manner. For example in an HMI you //could create tag groups for each page. Disabling a tag group that is not in use //frees up resources on the processor and the network. //You also have to be careful about the two different kinds of Enabled properties. //There is an enabled property for the tag group, and there is an Enabled property //for the tag itself. Disabling the tag group stops it from being updated, so no //tags belonging to that group will be updated (unless they also belong to another //active tag group). Disabling the tag by setting the LogixTag.Enabled property //to false means that the tag won't accept new data or pending values, and that //any tag group that it belongs to won't update it. //First, we need to create a LogixTagGroup on the processor. The easiest way to do //this is to use the LogixProcessor.CreateTagGroup() method. This allows the //processor to create the tag group, verify it doesn't conflict with another tag //group, and manage the group. LogixTagGroup tg = processor.CreateTagGroup("MyGroup"); //Now that we've created a tag group, we can add some tags to it. Adding and removing //tags from a tag group is an expensive process. The tag group will automatically //re-optimize all the tags it's responsible for when you add or remove a tag. It's //recommended that you don't add or remove tags very often, if you don't need a tag //to be updated anymore just set the LogixTag.Enabled property to false. //Here we are going to ask the user (probably you) for some tags. The easiest way to //create tags without knowing the underlying data type in the processor is to use //the LogixTagFactory. bool quitFlag = false; LogixDINT dTag = new LogixDINT("tst_Dint", processor); dTag.TagValueUpdated += new ICommon.TagValueUpdateEventHandler(TagValueUpdated); tg.AddTag(dTag); while (!quitFlag) { Console.Write("Please enter a tag name to monitor, enter 'done' when finished: "); string tagName = Console.ReadLine(); if (tagName.ToLower() == "done") { quitFlag = true; continue; } LogixTag userTag = LogixTagFactory.CreateTag(tagName, processor); if (userTag == null) { //When the tag factory returns null, the tag was not found or some other //catastrophic error occurred trying to reference it on the processor. Console.WriteLine("The tag " + tagName + " could not be created"); continue; } //If we got here, we were able to successfully create the tag. Let's print //some information about it... Console.WriteLine("Created " + tagName + " as a(n) " + userTag.LogixType.ToString()); //Let's reference the update functions... userTag.TagValueUpdated += new ICommon.TagValueUpdateEventHandler(TagValueUpdated); //Now let's add it to the tag group... tg.AddTag(userTag); } //The processor has a feature that allows them to automatically update the tag group. This //helps to free up your logic and not worry about having to update tag groups that are //enabled or disabled. The argument for this function is the time between updates in //milliseconds. The actual time from the start of one update to the start of another is //dependant on how many tags there are and how much data needs to be transferred. processor.EnableAutoUpdate(500); Console.WriteLine("Press Enter to quit"); Console.ReadLine(); processor.Disconnect(); }
/// <summary> /// Creates a new User-Defined Type Tag on the specified Processor with the number of Elements /// </summary> /// <param name="TagAddress">Address (Tag Name) in the processor</param> /// <param name="TemplateInfo">Template information about the type</param> /// <param name="Processor">Processor where the tag resides</param> /// <param name="ElementCount">Number of elements to read</param> internal LogixUDT(string TagAddress, TemplateInfo TemplateInfo, LogixProcessor Processor, ushort ElementCount) : base(TagAddress, Processor, ElementCount, TemplateInfo) { _templateInfo = TemplateInfo; }
/* * HOW TO USE THIS SAMPLE * * 1. First change the hostNameOrIp to the IP address or host name of your PLC * 2. Then change the path to be the path to your PLC, see comments below * 3. Run * */ static void Main(string[] args) { //First we create the processor object. Typically the path is the slot //number of the processor module in the backplane, but if your communications //card is not in the same chassis as your processor, this is the path through //the chassis to get to your processor. You will have to add a 1 for every //chassis you go through, for example: //Chassis 1: ENBT card in Slot 1 (slot is irrelavent), ControlNet Card in Slot 2 //Chassis 2: L61 in Slot 4 //Path would be: { 2, 1, 4 } //Basically it's the target slot, 1 for backplane, target slot, 1 for backplane... //until you get to the processor. string hostNameOrIp = "192.168.1.10"; byte[] path = new byte[] { 0 }; LogixProcessor processor = new LogixProcessor(hostNameOrIp, path); //Connect to the PLC, you can create the events before or after the connect function if (!processor.Connect()) { Console.WriteLine("Could not connect to the processor"); Console.ReadKey(false); return; } //Create the events, the processor state is updated every second, and if there is //a change in either the fault state, key switch position, or processor state (RUN, PROGRAM, TEST), //then one of these events will be fired. processor.FaultStateChanged += new LogixFaultStateChangedEvent(processor_FaultStateChanged); processor.KeySwitchChanged += new LogixKeyPositionChangedEvent(processor_KeySwitchChanged); processor.ProcessorStateChanged += new LogixProcessorStateChangedEvent(processor_ProcessorStateChanged); Console.WriteLine("6D Systems LLC"); Console.WriteLine("Processor State Example: Change the key switch, fault state, or processor\nmode to see a message displayed"); Console.WriteLine("\nProcessor Information:\n" + processor); Console.WriteLine("\n\n"); //The processor can, through source code, be put in Program mode or Run mode. This is useful //if you are developing a critical process where you want to be able to shut all the outputs //off on the PLC at one time. Mode changes only work if the processor key is in Remote //The .UserData field can be used to store any data you desire, and it will be persisted //with the processor object. This is useful, for example, for storing information about //a processor when it's in a dictionary... processor.UserData = "MainPLC_1"; bool quitFlag = false; while (!quitFlag) { Console.WriteLine("\n\n=============================MENU============================="); Console.WriteLine("Press the 'P' key to put the processor in Program mode"); Console.WriteLine("Press the 'R' key to put the processor in Run mode"); Console.WriteLine("Press the 'U' key to display the processor UserData"); Console.WriteLine("Press the 'T' key to display all the tags on the processor"); Console.WriteLine("Press the 'Q' key to quit"); Console.WriteLine("=============================================================="); char key = Console.ReadKey(true).KeyChar; switch (key) { case 'p': case 'P': Console.WriteLine("Setting processor to Program mode..."); processor.SetProgramMode(); break; case 'r': case 'R': Console.WriteLine("Setting processor to Run mode..."); processor.SetRunMode(); break; case 'u': case 'U': Console.WriteLine("UserData: " + (string)processor.UserData); break; case 't': case 'T': List<LogixTagInfo> tagInfo = processor.EnumerateTags(); if (tagInfo == null) { Console.WriteLine("No tags found"); break; } Console.WriteLine("There are " + tagInfo.Count + " tags..."); foreach (LogixTagInfo info in tagInfo) { string name = info.TagName; if (info.Dimensions > 0) name += "[" + info.Dimension1Size.ToString(); if (info.Dimensions > 1) name += ", " + info.Dimension2Size.ToString(); if (info.Dimensions > 2) name += ", " + info.Dimension3Size.ToString(); if (info.Dimensions > 0) name += "]"; Console.WriteLine("\t" + name); } break; case 'q': case 'Q': quitFlag = true; break; default: break; } } //Always remember to disconnect the PLC. If you forget, the PLC won't allow you to reconnect //until the session times out. This is typically about 45-60 seconds. processor.Disconnect(); }
/// <summary> /// Creates a new COUNTER Logix Tag on the specified Processor /// </summary> /// <param name="TagAddress">Address (Tag Name) in the processor</param> /// <param name="TemplateInfo">Template information about the type</param> /// <param name="Processor">Processor where the tag resides</param> internal LogixCOUNTER(string TagAddress, TemplateInfo TemplateInfo, LogixProcessor Processor) : base(TagAddress, TemplateInfo, Processor) { }
/// <summary> /// Creates a new STRING Logix Tag on the specified Processor /// </summary> /// <param name="TagAddress">Address (Tag Name) in the processor</param> /// <param name="TemplateInfo">Template information about the type</param> /// <param name="Processor">Processor where the tag resides</param> internal LogixSTRING(string TagAddress, TemplateInfo TemplateInfo, LogixProcessor Processor) : base(TagAddress, TemplateInfo, Processor) { }
static void TagInformation(LogixProcessor processor) { //Getting detailed tag information is actually an expensive process. Currently //there is no way to get detailed information about a tag except to request all //the tag information in the PLC. The GetTagInformation will read all the tags //in the PLC, then return the one you are looking for. string address = GetTagAddress(); if (string.IsNullOrEmpty(address)) return; LogixTagInfo tagInfo = processor.GetTagInformation(address); if (tagInfo == null) { Console.WriteLine("The tag '" + address + "' could not be found on the processor"); Console.ReadKey(false); return; } Console.WriteLine(tagInfo.ToString()); }
/// <summary> /// Creates a new STRING Tag on the specified Processor with the number of Elements /// </summary> /// <param name="TagAddress">Address (Tag Name) in the processor</param> /// <param name="TemplateInfo">Template information about the type</param> /// <param name="Processor">Processor where the tag resides</param> /// <param name="ElementCount">Number of elements to read</param> internal LogixSTRING(string TagAddress, TemplateInfo TemplateInfo, LogixProcessor Processor, ushort ElementCount) : base(TagAddress, TemplateInfo, Processor, ElementCount) { }
public static LogixTag CreateTag(string Address, LogixProcessor Processor) { return CreateTag(Address, Processor, 1); }
static void WriteTag(LogixProcessor processor) { //Writing a tag is also very easy. First, create a tag... string address = GetTagAddress(); if (string.IsNullOrEmpty(address)) return; //Now we have to create the tag on the processor. The easiest way to //do this without knowing the underlying type is to use the //LogixTagFactory class. LogixTag userTag = LogixTagFactory.CreateTag(address, processor); if (userTag == null) { Console.WriteLine("Could not create the tag " + address + " on the processor"); return; } switch (userTag.LogixType) { case LogixTypes.Bool: WriteBool(userTag, processor); break; case LogixTypes.DInt: case LogixTypes.LInt: case LogixTypes.Real: case LogixTypes.SInt: WriteOther(userTag, processor); break; case LogixTypes.Control: case LogixTypes.Counter: case LogixTypes.Timer: case LogixTypes.User_Defined: WriteStructure(userTag, processor); break; default: Console.WriteLine("The LogixType of " + userTag.LogixType.ToString() + " is not supported in this sample"); return; } PrintTagValue(userTag); //And go back to the menu }
public static LogixTag CreateTag(string Address, LogixProcessor Processor, ushort Elements)
/// <summary> /// Creates a LogixTag with the correct type /// </summary> /// <param name="Address">Address (Tag Name)</param> /// <param name="Processor">Processor the tag belongs to</param> /// <param name="Elements">Number of elements to read</param> /// <returns>LogixTag of the correct underlying type</returns> public static LogixTag CreateTag(string Address, LogixProcessor Processor, ushort Elements = 1) #endif { //We'll do this by creating the tag first, then seeing what type it is //and returning it to the user... return CreateQuickTag(Address, Processor, Elements); }
/* * HOW TO USE THIS SAMPLE * * 1. First change the hostNameOrIp to the IP address or host name of your PLC * 2. Then change the path to be the path to your PLC, see comments below * 3. Create a 1 dimensional DINT array on the processor called dintArray1[10] * 4. Create a 2 dimensional DINT array on the processor called dintArray2[10,10] * 5. Create a 3 dimensional DINT array on the processor called dintArray3[10,10,10] * 6. Run * */ static void Main(string[] args) { //First we create the processor object. Typically the path is the slot //number of the processor module in the backplane, but if your communications //card is not in the same chassis as your processor, this is the path through //the chassis to get to your processor. You will have to add a 1 for every //chassis you go through, for example: //Chassis 1: ENBT card in Slot 1 (slot is irrelavent), ControlNet Card in Slot 2 //Chassis 2: L61 in Slot 4 //Path would be: { 2, 1, 4 } //Basically it's the target slot, 1 for backplane, target slot, 1 for backplane... //until you get to the processor. string hostNameOrIp = "192.168.1.10"; byte[] path = new byte[] { 1 }; LogixProcessor processor = new LogixProcessor(hostNameOrIp, path); //The processor has to be connected before you add any tags or tag groups. if (!processor.Connect()) { Console.WriteLine("Could not connect to the processor"); Console.ReadKey(false); return; } //First create a group. Groups are much more efficient at reading and writing //large numbers of tags. LogixTagGroup myGroup = processor.CreateTagGroup("MyGroup"); //Now let's create our first array. The number of elements is the TOTAL number //of elements to read, in all dimensions. LogixDINT dintArray1 = new LogixDINT("dintArray1", processor, 10); //We don't need to set the number of dimensions on the tag here because it //assumes that it's a single dimension tag. All tags are set up to be arrays //by default, the .Value or similar member always returns the 0th element //of the array. With a tag that is not an array, that is where the value is. //Let's create the 2 dimensional array LogixDINT dintArray2 = new LogixDINT("dintArray2", processor, 100); //The number of elements are the subscripts multiplied by each other. In this //case, 10*10 = 100. If you put a lower value here you will only read that //much of the array. ControlLogix packs it's arrays in row major format, so //just keep that in mind if reading partial arrays. //If you want to set it up to read with a multidimensional accessor, we need //to tell the tag what the size of the dimensions are. dintArray2.SetMultipleDimensions(10, 10); //We can now access the tag by the tagName[row,column] format. If you didn't //set the size, you would get an exception when trying to access the tag //using that format. //Let's create the last tag LogixDINT dintArray3 = new LogixDINT("dintArray3", processor, 1000); //Set the dimensions dintArray3.SetMultipleDimensions(10, 10, 10); //Now let's add our tags to the tag group... myGroup.AddTag(dintArray1); myGroup.AddTag(dintArray2); myGroup.AddTag(dintArray3); Console.WriteLine("6D Systems LLC\n\n"); Console.WriteLine("Tags created..."); //Now let's pick out some random members and display them... Console.WriteLine("dintArray1[4] = " + dintArray1[4].ToString()); Console.WriteLine("dintArray2[5,2] = " + dintArray2[5, 2].ToString()); Console.WriteLine("dintArray3[4,7,3] = " + dintArray3[4, 7, 3].ToString()); Console.WriteLine("\nPress any key to write a new value to each of the above tags"); Console.ReadKey(false); //Now let's write some data to those tags... Random rnd = new Random(); dintArray1[4] = rnd.Next(int.MinValue, int.MaxValue); dintArray2[5, 2] = rnd.Next(int.MinValue, int.MaxValue); dintArray3[4, 7, 3] = rnd.Next(int.MinValue, int.MaxValue); //Let's update the tag group processor.UpdateGroups(); //Now print them back out for the user... Console.WriteLine("\nNew tag values..."); Console.WriteLine("dintArray1[4] = " + dintArray1[4].ToString()); Console.WriteLine("dintArray2[5,2] = " + dintArray2[5, 2].ToString()); Console.WriteLine("dintArray3[4,7,3] = " + dintArray3[4, 7, 3].ToString()); Console.WriteLine("\nPress any key to quit"); Console.ReadKey(false); //Remember to disconnect from the processor processor.Disconnect(); }
internal static LogixTag CreateLongTag(string Address, LogixProcessor Processor, ushort Elements) { //It doesn't exist in the list, maybe it was added later? //lock (Processor.SyncRoot) { ReadDataServiceReply lgxRead = LogixServices.ReadLogixData( Processor.SessionInfo, Address, Elements); if (lgxRead == null) return null; if (lgxRead.Data == null) return null; if (lgxRead.Status != 0x00 && lgxRead.Status != 0x06) { return null; } //The first two bytes are the type... CIPType tagType = (CIPType)lgxRead.DataType; if (tagType == CIPType.STRUCT) { //We need to build an information object about this type //The first two bytes are a handle to the structure... ushort structureId = Processor.GetStructureHandle(Address); //Now we can send a request to get the attributes... TemplateInfo ti = ReadStructAttributes(structureId, Processor); return CreateStructTag(Address, Processor, Elements, ti); } else { switch (tagType) { case CIPType.BITS: case CIPType.BOOL: return new LogixBOOL(Address, Processor, Elements); case CIPType.SINT: return new LogixSINT(Address, Processor, Elements); case CIPType.INT: return new LogixINT(Address, Processor, Elements); case CIPType.DINT: return new LogixDINT(Address, Processor, Elements); case CIPType.LINT: return new LogixLINT(Address, Processor, Elements); case CIPType.REAL: return new LogixREAL(Address, Processor, Elements); default: break; //Unknown type... } } return null; } }
public CustomUDT(string TagAddress, LogixProcessor Processor) : base(TagAddress, Processor) { }