Recognize Contiguous Address Ranges In Allen-Bradley Drivers


Recommended Posts

Enhance the Allen-Bradley driver(s) to recognize blocks of contiguous addresses in channel table.

 

As it is now, the channel table can read (or write) individual addresses from an AB controller, but can’t automatically recognize ranges of contiguous addresses and retrieve them all at once as it can do with Modbus for instance.  This is due to the unique addressing structure in classic AB controllers and newer tag-based controllers using classic-mode emulation (very common).  The only way to do it is to do the comms in sequence, and then, if the results are to populate channels, to do MyChannel.AddValue() as many times as there are channels.  This is reasonably manageable  with INT’s, since you’re probably only reading 100 at a time or whatever, but imagine using that process with 500 consecutive coils, and it would be nice to get rid of it with analog values as well.  Writes tend to be event-driven and therefore occur far more often one register at a time anyway.

 

There would be at least a couple ways to go about this.  You could add an instruction similar to ReadGroup(), where you can do a mass AddValue from the return array to all the channels in a group simultaneously (or maybe enhance ReadGroup() itself to where the user can specify a read, and the returned array is automatically AddValue’d to the specified group.

 

Or, you could somehow make the channel table capable of recognizing contiguous blocks, whether automatically or give the user some way to define it within the channel table.  It wouldn’t bother me if this ended up being a hierarchy in the channel table where the user would have to manually indicate contiguous ranges.  So each channel would still have an entry in the channel table, but there would be some way of indicating that these 100 registers  or these 500 coils form a contiguous block and can be retrieved with a single read.

Link to comment
Share on other sites

I concur with this line of thinking not only for AB controllers, but for most types of interfacing equipment. It would be much better to be able to read inputs of any kind in blocks as opposed to one at a time especially for  any equipment on a serial link like RS422. But would also be beneficially for Ethernet connected equipment. For some our controls we are turning several pieces of equipment on and off at the same time as the process changes modes. So if possible it would also be nice to have block writes were applicable.

 

For now we are solving this problem by doing all I/O through variables created with OOP and writing our own drivers, but this isn't the ideal solution. This has proven to be quite a bit of extra work.

 

If enhancements are made to the I/O system, I would like to see the ability to have persistent variables for calibration factors and set points as well.

Link to comment
Share on other sites

Was just reading the Serial Guide (is this not installed by default in new versions?) because I'm working on an AB PCCC / CSPv4 Ethernet protocol (IOW classic AB Ethernet vs. Ethernet/IP) and I ran across the generic Channel.Addvalue() for channels with unknown names.

 

Will Channel.Addvalue() also work in generic non DDP sequences?  If so, that would pretty much supply one of the alternatives I mentioned, mass assignment to channels without a million lines of code.  Given an array of returned data, you could loop through it with an array index and the differential channel offset.  I had already thought of that approach, but I would have had to use formulaic channel names, which would defy your advice about using relevant function-based rather than address-based channel names.

Link to comment
Share on other sites

Yes, channel.addvalue() will work outside DDP sequences.

 

The serial guide isn't in the new release because it really needs to be updated.  Using DDP's really needs to be in an advanced section rather than the normal way to do communications to non-standard protocols.  Its just much easier if you are creating a single application (as many DAQFactory user's are) to simply do the protocol in a regular sequence.  DDP is really only useful if you are going to reuse the protocol across multiple applications, and even then, its easier to debug the script using a sequence, then move it into a DDP file (with some minor edits).

Link to comment
Share on other sites

Thanks - that's exactly what I'm doing, writing it in sequence, and will eventually move it to a DDP (or maybe not).

 

If you rewrite the comms manual, I'd like to request a more formal description of details like variable scoping, etc.  Is there a global DDP scope for instance, that the CTL can't see?, for instance.  What are the exact names of the fields that get passed implicitly from the channel table?, etc.

 

It's probably all in there, but the doc seems more narrative in nature, walking the reader in a natural sequence through the various tasks of increasing complexity he might want to do, but it's hard to use as a random-access reference to writing DDP's.

Link to comment
Share on other sites

Did From.Word() ever return a 1-dimenisonal array?  I have what I think is the final version of my old DF1 driver, and all it does to prep the array of 16-bit values is run From.Word() on them, and what gets done with them won't work with a 2D array.  I definitely remember that this driver worked, but maybe the version I have isn't the final one or something.

 

Anyway, what I want to do is, given an array of 16-bit values, to convert it to a 1D array of bytes.  What's the fastest, cleanest way to do that?  (I'll also need to do this with arrays of floats)

 

Thanks!

Link to comment
Share on other sites

No, I don't think it ever did.  The easiest way to flatten a 2D array of byte values into a 1D is to use chra() and asca().  For example:

 

? asca(chra(from.word({256,65535})))

 

{0,1,255,255}

 

vs:

 

? from.word({256,65535})

 

{{0,1}, {255,255}}

 

chra() ignores the dimensionality and just burns through all the values, converting each to a character.  Asca() converts that string back to an array.  Note this only works with byte values since chra() will only convert values between 0 and 255.  

 

FYI: internally we store arrays as a single 1D array and then just track the # of rows, columns, and depth.  Its stored basically in the order it prints out, that's why chra() works.  Chra() ignores the row / column / depth settings and just uses the internal 1D array as a 1D array.  I believe there are other functions that will do the same sort of thing, but can't think of them right off hand.

Link to comment
Share on other sites

  • 1 month later...

So when building a protocol, if you want the functions to be accessible from script as well as the channel table, similar to say the Modbus driver, you should replicate the code from the I/O Type in a function in the DDP?  Or  maybe better, have the I/O type be a shell that does no more than call the function, which function is then also accessible from script?

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.