Determine i/o range programmatically

I would like to be able to determine the set range of an I/O point programmatically so I can compare the reading and make sure we are not maxing out an I/O. So for example if I have a 4-20 mA input and it is scaled 0 - 100 psi, I want to be able to know if the I/O is getting close to the max scale (100) to set a flag that it is getting close to over range. For that matter I could also look at the raw mA input and just do the same comparison with 20 mA, however I don’t know if there is a way to get either of those values programmatically.

I know this could be done manually, however if we ever change the scaled range of the I/O then we would have to go manually change a value somewhere so on and so forth.

Is there some way to do this that I’m just not seeing at this point?


I’m not aware of any built in commands to do what you want, but this can still be done programmatically.

First thing is to download document 1465, which is the OptoMMP Protocol Guide which will give you all the memory map addresses for the I/O units. This is a great reference when venturing outside the built-in commands.

You will want to use the I/O Unit Memory Map Commands to read the addresses for the analog unit “counts”. You can get the counts for all analog modules with something like this command:

ReadNumTableFromIoUnitMemMap(64, 0, ioYourIOUnit, 0xF0600100, ftResults) //Edit: Using Bank read

I got this address from the Analog Bank Read section of the protocol guide. You will need to know where you point is located on your board (or you can figure this out programmatically by looping through the point names in the configuration section - this will take some more advanced programming).

ftResults will contain 4 values for each module on your board. The values are in “counts”. 25,000 is the max value for input counts - so if you want to see when you are withing 90% of max value, then you would look for anything above 22,500. (Details in the protocol guide, Overview of Programming, Using I/O point features, Scaling).

Edited to fix some errors in how the analog bank works.

@erfigge Your question is a little out of box… I am going to answer it along the lines of Philip, but would love to hear some more about what you are trying to do and why.

One of the most powerful tools at your disposable is PAC Manager… It dovetails beautifully with doc 1465. You need both in hand for your sort of question.
Philip has already done a fantastic job of guiding you on the doc side, so lets take a quick look at the PAC Man side.

First up, do an Inspect and put in your IP address.
Once connected, hit up the Point Config menu on the left, then select your module, then your point on that module.
I have selected a voltage module here (because I did not have a ma module).

Here is the quick way to find those addresses Philip was talking about.
So in this config we see the scaled units you first mention.
Here is how you would programmatically get what ever the point was configured for.
In your case 100 psi, in this case, 10000 Gallons (but being Aussie, I always think Liters).

The other part of your question is for the actual value.
You get that by clicking on the point details menu option.

The important thing here is that you can see every part of every point has a memory address.
Use Philips post to read those addresses and do whatever logic you want or need to.

All that said, I would just do a condition block with the command ‘Is within limits’ in a chart and call it done…

Data integrity is the reason why. We run a turbocharger testing facility and monitor and record hundreds of data points across all of our test cells. If one instrument, lets say a pressure sensor gets close to exceeding the range of the output I want the operators to know. So if a 1 - 100 psi pressure sensor gets to 90 psi, we only have 10 psi of measurable range left. Currently the actual pressure the sensor is reading could go to 110 psi, but we would only measure about 102 psi and the operator would not know something is amiss.

However, if I could programmatically push IO points into a subroutine once in a while and check for that, the operator could be notified. There is a multitude of ways to do it, none very easy. Probably easier to manual have a routine with programmed numbers in it than mess with all the MM addresses. I just like subroutines so I can maximize the code and can transport between all of our controllers and minimize as much “one off” programming as possible. :slight_smile:

For your requirements, I don’t think looking at the counts will be good, since, for instance, you could have a 1-5V sensor on a 10V module. Looking at counts will only tell you if you are reaching the modules measuring limit, not the limit of your sensor.

Unless you know that all of your sensors are using the max scale of your modules, it would be easiest to just set limits in your strategy in engineering units like Ben suggested. Just make sure if you ever change the scale on the IO point to adjust the limits as well. AFAIK, there isn’t a way to get the max scale value that you type into the configuration programmatically from the IO unit since the scaled units in the IO unit are always the full scale values.

Thanks for the explanation. Very helpful to get some more context around your initial question.

Hopefully @mstjohn can pop in here, because I can only speak from a high level…
We needed to do something a little bit similar at the hospital. We needed to know if any sensors were out of range, data integrity as you say. So we loaded up the I/O unit point configurations into a table and then looped through those tables every 15 seconds and compared each analog input to a range limit.
Here is a screen shot of the section of code.

You still end up using the IsWithinLimits command, but looping through the table is quicker and cleaner (to go back to your subroutine comment - I don’t have a lot of experience with them, so work it as you feel comfortable).

Sorry I cant share the code, but hopefully you can glean a few ideas out of it.

Yeah, I kind of figured it was going to be a manual entry type of thing. Maybe that is a good feature request, a command that returns the setup range of a particular io point. Would make this sort of thing much easier. :slight_smile: