User Limits in Firmware Memory

[RMP 10.4.3]

I’m investigating an issue that may be the result of a user limit action. I’d like to be able to prove that it’s the user limit triggering that’s the ultimate cause of the behavior. It occurred to me that I might be able to inspect user limit data in the scope.

There’s an address type, RSIControllerAddressTypeUSERLIMIT_STATUS that sounds promising. Assuming I resolve this with MotionController::AddressGet(...,<user_limit_index>), what is stored at that location?

It seems like I might want to be able to inspect the data structure, but at the very least, I’d like to be able to discern

  • Whether the user limit fired (UserLimitStateGet ?)
  • Whether the user limit is enabled, and, presumably configured, (UserLimitEnableGet)

If I could get the input logic, comparison values, etc. that would be cool. I realize that this kind of detail is likely to change between versions of RMP, but unless it commonly changes (which I doubt, 1.4 → 1.5, excepted), it would at least be somewhat reliable to use the same memory layout scheme to troubleshoot issues.

How can I “monitor” a user limit in the scope?

Hi Todd,

Yes, you are correct that you can use RSIControllerAddressType.RSIControllerAddressTypeUSERLIMIT_STATUS with MotionController::AddressGet(<address_type>, <user_limit_index>) to retrieve the memory address where the UserLimit status is stored. Reading from that address will return a 32bit integer that is 1 if the UserLimit is triggered and 0 otherwise. You can use MotionController::MemoryGet(<userlimit_status_address>) to read this memory directly or use MotionController::UserLimitStateGet(<user_limit_index>) which returns a bool.

There is no address type for if the user limit is enabled, but you can use MotionController::UserLimitEnableGet(<user_limit_index>) as you mentioned. If you need the enabled address, then we can look into adding that to the AddressType enum in the future.

What is the issue that you are investigating?

The basic issue I have is that I’m trying to prove that a user limit is “firing.” The thing about this that makes it difficult is that I’m using the user limit as a dead man switch, so every few hundred milliseconds, I reconfigure it (condition <sample_counter_addr> >= <value_5_seconds_in_the_future>), so that if it fires, I won’t be able to tell by halting things and examining the user limit in RapidSetup. If I could capture some internals of the user limit in a MotionScope capture, I could at least tell that it fired, and precisely (to the sample rate) when.

So, if there were a way to lookup addresses for at least some attributes of a user limit, that would be helpful (in the future).

For the present, it would be most helpful if I could deduce the address of at least whether the user limit is enabled. I presume that there’s a fixed (for v 1.4.3, at least) offset in firmware memory from the location of status. Also, if I could know the location of the conditions, that would be helpful (since my condition is constantly changing—it might help me understand the particulars of why the user limit is firing when I don’t expect it to).

What’s crucial here is that I be able to get the data into a firmware data capture (e.g. MotionScope) rather than query it via the API.

This particular user limit is designed to safely disable things by setting an output if my application stops responding (or crashes), so the effects are handled inside RMP, and are not driven (directly) by my application. I can’t really put breakpoints in the firmware, so the best I can do is verify that the logic is behaving as I expect by examining the data every cycle.

Hi Todd,

Since there is currently no address type for UserLimit.Enabled, here is a workaround that might help:

  1. Start by retrieving the address for RSIControllerAddressTypeUSERLIMIT_STATUS. This serves as our base point.

  2. Calculate the address of the Enabled data by adding an offset. For the current structure, you can find the Enabled data at an offset of 0x90 from the USERLIMIT_STATUS address. For example:
    UserLimit_0_Enabled_addr = UserLimit_0_Status_addr + 0x90

  3. Ensure compatibility for future updates. Given the possibility of changes in the UserLimits structure, it’s wise to check if the structure has changed before proceeding. You can do this by comparing the addresses of two adjacent UserLimits (AddressGet function) and expecting a difference of 0x1C0. This step will warn you if the structure of UserLimits has changed. For example:
    assert(UserLimit_1_Status_addr - UserLimit_0_Status_addr == 0x1C0)

Here’s a quick breakdown of the current structure for clarity:

UserLimit_0_Status_addr = MotionController::AddressGet(
    RSIControllerAddressType.RSIControllerAddressTypeUSERLIMIT_STATUS,
    0
);
UserLimit_0_Enabled_addr = UserLimit_0_Status_addr + 0x90;

UserLimit_1_Status_addr = UserLimit_0_Status_addr + 0x1C0;
UserLimit_1_Enabled_addr = UserLimit_1_Status_addr + 0x90;
...
  1. Use the calculated addresses to record the data in either MotionScope or a RapidCode Recorder.

Future Updates: I have added a story for a USERLIMIT_ENABLED address type in future releases. If there are other UserLimit attributes you’re interested in, please let me know! I’d be more than happy to assist in finding the offsets for those and adding them as address types.

Note: If you are interested in diving deeper, you can explore the UserLimit memory structure through VM3 by looking for the MFWLimit object.

Feel free to reach out if you have any questions or need further clarification.

1 Like

Additionally, to address your question about examining the conditions. You can check the limitValue by subtracting an offset of 0x60 from the status. For example:
UserLimit_0_limitValue0_addr = UserLimit_0_Status_addr - 0x60

If you have two conditions, then the second limit value can be found by either subtracting 0x40 from the status address or adding 0x20 to the first limit value address. For example:
UserLimit_0_limitValue1_addr = UserLimit_0_Status_addr - 0x40
OR
UserLimit_0_limitValue1_addr = UserLimit_0_limitValue0_addr + 0x20

The limits values are stored as doubles, so make sure set the data type if you are using the MotionScope or use MotionController::RecorderRecordDataDoubleGet if you are using RapidCode Recorders.

Relevant Doc Pages:
User Limits - Concepts, C# Samples, C++ Samples
MotionScope - Software - Tools
RapidCode Recorder - Concepts, C# Samples

1 Like