Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add debug broadcast enable/disable option and debug broadcast port option to config file #309

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
32 changes: 32 additions & 0 deletions config/motoros2_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,35 @@ publisher_qos:
#
# DEFAULT: false
#ignore_missing_calib_data: false

#-----------------------------------------------------------------------------
# Should MotoROS2 broadcast debug messages?
#
# If enabled, this will broadcast log messages on the network on port UDP 21789.
# the user can use the debug script provided in the distribution of MotoROS2 to
jimmy-mcelwain marked this conversation as resolved.
Show resolved Hide resolved
# monitor the state of the robot, identify problems, and debug their code.
#
# The debug script is available under the Yaskawa-Global/motoros2 repository in
# the tools directory
# https://github.com/Yaskawa-Global/motoros2/tree/main/tools
#
# DEFAULT: true
#userlan_debug_broadcast_enabled: true
jimmy-mcelwain marked this conversation as resolved.
Show resolved Hide resolved

#-----------------------------------------------------------------------------
# Which network port should MotoROS2 broadcast the debug messages to, if
jimmy-mcelwain marked this conversation as resolved.
Show resolved Hide resolved
# 'userlan_debug_broadcast_enabled' is 'true'?
#
# If not specified and 'userlan_debug_broadcast_enabled' is true, MotoROS2 will
# send the broadcast to all network ports which are enabled on the controller.
jimmy-mcelwain marked this conversation as resolved.
Show resolved Hide resolved
#
# To choose a specific port to broadcast debug messages, uncomment
# 'userlan_debug_broadcast_port' below and set it to the desired port.
#
# NOTE 1: this setting only applies to YRC1000 and YRC1000u controllers.
jimmy-mcelwain marked this conversation as resolved.
Show resolved Hide resolved
# DX200 and FS100 controllers only have a single ethernet port, and will
# always default to USER_LAN1
#
# OPTIONS: USER_LAN1, USER_LAN2
# DEFAULT: (all available network ports)
#userlan_debug_broadcast_port: USER_LAN1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what would be the value (ie: string) for 'all available network ports'? Because the documentation states that's the default, but I can't set this to 'all available network ports' I believe.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So there is not a dedicated string for 'all available ports'. I was planning on having that, but part of the weirdness with it having the same type as userlan_monitor_port (Ros_UserLan_Port_Setting) is that even if they have different options with different behavior (e.g. userlan_monitor_port has 'auto detection' and userlan_debug_broadcast_port has 'all available ports'), they are parsed the same. So I had the behavior match that of userlan_monitor_port, which doesn't have a specific string for 'auto detection'. That being said, unlike userlan_monitor_port, if the user types in an invalid string, it will default to 'all available ports' rather than 'disabled'

37 changes: 37 additions & 0 deletions doc/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,21 @@ Save a copy of the output of the [debug-listener script](#debug-log-client) and
Open a new issue on the [Issue tracker](https://github.com/yaskawa-global/motoros2/issues), describe the problem and attach `PANELBOX.LOG` and the debug log to the issue.
Include a verbatim copy of the alarm text as seen on the teach pendant (alarm number and `[subcode]`).

### Alarm: 8011[64]

*Example:*

```text
ALARM 8011
Enable LAN port 1 for debug
[64]
```

*Solution:*
The ETHERNET function must be enabled for the LAN interface that was specified in the config file.
Either change the interface specified in the config file to a LAN interface that is enabled, or enable the corresponding LAN interface on the controller.
Please contact your local Yaskawa representative to request the ETHERNET function if it is not enabled.

### Alarm: 8012[xx]

*Example:*
Expand Down Expand Up @@ -1024,6 +1039,28 @@ In case the alarm is still raised after calibration was performed, TF broadcasti
Open a new issue on the [Issue tracker](https://github.com/yaskawa-global/motoros2/issues), describe the problem and attach `PANELBOX.LOG`, `RBCALIB.DAT` and the debug log to the issue.
Include a verbatim copy of the alarm text as seen on the teach pendant (alarm number and `[subcode]`).

### Alarm: 8013[17]

*Example:*

```text
ALARM 8013
Bad UserLan debug port in cfg
[17]
```

*Solution:*
The `userlan_debug_broadcast_port` key in the `motoros2_config.yaml` configuration file is set to an invalid value.
Debug broadcasting will be disabled for this session.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug broadcasting will be disabled for this session

I don't like this behavior. I definitely think broadcasting should be enabled if there's an error in the configuration.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can change that. So userlan_monitoring_enabled should be set to disabled if there is an error in the config, but broadcasting should still be enabled? I only ask because they're in the same case for the config switch case.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have an opinion on the behavior of userlan_monitoring_enabled in this case

Copy link
Collaborator

@gavanderhoorn gavanderhoorn Sep 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UserLan monitoring is extra functionality: it makes detecting disconnections faster, but isn't absolutely necessary (other places will also detect disconnects, they'll just take longer).

There's no harm in disabling it if the configuration is incorrect. And, we really can't do anything if configuration is incorrect: monitoring only a single port (when two are present) would be incorrect (which one to monitor in that case?) and monitoring all of them would also be incorrect -- it would likely result in MotoROS2 detecting disconnects 'all the time'. So disabling is really the only thing we can do.

But debug broadcasts should indeed not be disabled in cases of incorrect configuration. Especially since we often use debug logs to diagnose misconfiguration.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the behavior and this documentation so that it broadcasts to all ports if the specific port isn't active.


On YRC1000 and YRC1000u, this must be set to either `USER_LAN1` or `USER_LAN2`.

No other values are supported.

Example: `userlan_debug_broadcast_port: USER_LAN1`.

After correcting the configuration, the [changes will need to be propagated to the Yaskawa controller](../README.md#updating-the-configuration).

### Alarm: 8014[0]

*Example:*
Expand Down
60 changes: 47 additions & 13 deletions src/ConfigFile.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ Configuration_Item Ros_ConfigFile_Items[] =
{ "userlan_monitor_enabled", &g_nodeConfigSettings.userlan_monitor_enabled, Value_Bool },
{ "userlan_monitor_port", &g_nodeConfigSettings.userlan_monitor_port, Value_UserLanPort },
{ "ignore_missing_calib_data", &g_nodeConfigSettings.ignore_missing_calib_data, Value_Bool },
{ "userlan_debug_broadcast_enabled", &g_nodeConfigSettings.userlan_debug_broadcast_enabled, Value_Bool },
{ "userlan_debug_broadcast_port", &g_nodeConfigSettings.userlan_debug_broadcast_port, Value_UserLanPort },
};

void Ros_ConfigFile_SetAllDefaultValues()
Expand Down Expand Up @@ -241,6 +243,10 @@ void Ros_ConfigFile_SetAllDefaultValues()

//ignore_missing_calib_data
g_nodeConfigSettings.ignore_missing_calib_data = DEFAULT_IGNORE_MISSING_CALIB;

//userlan debug broadcast
g_nodeConfigSettings.userlan_debug_broadcast_enabled = DEFAULT_ULAN_DEBUG_BROADCAST_ENABLED;
g_nodeConfigSettings.userlan_debug_broadcast_port = DEFAULT_ULAN_DEBUG_BROADCAST_PORT;
}

void Ros_ConfigFile_CheckYamlEvent(yaml_event_t* event)
Expand Down Expand Up @@ -327,7 +333,7 @@ void Ros_ConfigFile_CheckYamlEvent(yaml_event_t* event)
case Value_UserLanPort:
#if defined (FS100) || defined (DX200)
// single port, override whatever was configured
*(Ros_UserLan_Port_Setting*)activeItem->valueToSet = CFG_ROS_USER_LAN1;
* (Ros_UserLan_Port_Setting*)activeItem->valueToSet = CFG_ROS_USER_LAN1;
Ros_Debug_BroadcastMsg("DX200 or FS100: override to 'USER_LAN1'");

#elif defined (YRC1000) || defined (YRC1000u)
jimmy-mcelwain marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -337,20 +343,20 @@ void Ros_ConfigFile_CheckYamlEvent(yaml_event_t* event)
*(Ros_UserLan_Port_Setting*)activeItem->valueToSet = CFG_ROS_USER_LAN2;
else
{
//Note: ideally, we'd disable user lan monitoring here. However, we can't
//guarantee the 'userlan_monitor_enabled' setting won't be parsed after
//this one. If it were to be parsed after 'userlan_monitor_port', we'd
//be disabling it here, only to have it re-enabled later.
//Set the config value to the 'disabled' sentinel value and let the
//validation code below handle the fallout.
// Note: ideally, we'd disable user lan monitoring or set user lan debug
// broadcast to all here. However, we can't guarantee that the 'userlan_monitor_enabled'
// or the 'userlan_debug_broadcast_enabled' setting won't be parsed after
// this one. If it were to be parsed after the corresponding port setting, we'd
// be setting it here, only to have it re-set later. Set the config value to the
// 'malformed' sentinel value and let the validation code below handle the fallout.
Ros_Debug_BroadcastMsg(
"Unrecognised value for '%s': '%s'. Port monitoring will be disabled",
(char*)event->data.scalar.value,
(char*)activeItem->yamlKey);
*(Ros_UserLan_Port_Setting*)activeItem->valueToSet = CFG_ROS_USER_LAN_DISABLED;
"Unrecognised value for '%s': '%s'.",
(char*)activeItem->yamlKey,
(char*)event->data.scalar.value);
*(Ros_UserLan_Port_Setting*)activeItem->valueToSet = CFG_ROS_USER_LAN_MALFORMED;
}
#else
#error Unsupported platform
#error Unsupported platform
#endif
//Note: this logs whatever was in the .yaml, NOT the verified/parsed value above
Ros_Debug_BroadcastMsg("Config: %s = %s", (char*)activeItem->yamlKey,
Expand Down Expand Up @@ -690,7 +696,7 @@ void Ros_ConfigFile_ValidateNonCriticalSettings()
if (g_nodeConfigSettings.userlan_monitor_port != CFG_ROS_USER_LAN1)
#endif
{
mpSetAlarm(ALARM_CONFIGURATION_FAIL, "Invalid UserLan port in cfg",
mpSetAlarm(ALARM_CONFIGURATION_FAIL, "Bad UserLan monitor port in cfg",
Copy link
Collaborator

@gavanderhoorn gavanderhoorn Sep 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you have a particular reason changing the phrasing here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are now 2 different UserLan ports that the user can specify (monitor and debug broadcast), so I added the word "monitor" to clarify which one this condition checked. But then that put it above 32 characters (the alarm message limit), so I chose to shorten "Invalid" to "Bad" to fit in the character limit. I think that "invalid" is a better word for that, but it's more important to be specific about which config setting needs to be changed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So should we instead separate parsing and error reporting for monitoring and debug log port?

Would lead to some mild code duplication, but would also make parsing clearer and avoids this situation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe that this specific message is affected by combined parsing/error reporting for the two port config options. My preference would be to keep the parsing as combined, but I would be fine with changing it.

SUBCODE_CONFIGURATION_INVALID_USERLAN_MONITOR_PORT);
g_nodeConfigSettings.userlan_monitor_enabled = FALSE;
Ros_Debug_BroadcastMsg(
Expand All @@ -699,6 +705,28 @@ void Ros_ConfigFile_ValidateNonCriticalSettings()
}
}
}

if (g_nodeConfigSettings.userlan_debug_broadcast_enabled)
{
Ros_Debug_BroadcastMsg("UserLan debug broadcast enabled, checking port setting...");

#if defined (YRC1000) || defined (YRC1000u)
if (g_nodeConfigSettings.userlan_debug_broadcast_port != CFG_ROS_USER_LAN1 &&
g_nodeConfigSettings.userlan_debug_broadcast_port != CFG_ROS_USER_LAN2 &&
g_nodeConfigSettings.userlan_debug_broadcast_port != CFG_ROS_USER_LAN_ALL)
#elif defined (FS100) || defined (DX200)
if (g_nodeConfigSettings.userlan_debug_broadcast_port != CFG_ROS_USER_LAN1)
#endif
{
mpSetAlarm(ALARM_CONFIGURATION_FAIL, "Bad UserLan debug port in cfg",
SUBCODE_CONFIGURATION_INVALID_USERLAN_DEBUG_BROADCAST_PORT);
Ros_Debug_BroadcastMsg(
"userlan_debug_broadcast_port value %d is invalid, broadcasting to all enabled ports instead",
g_nodeConfigSettings.userlan_debug_broadcast_port);
}
}


}

const char* const Ros_ConfigFile_Rmw_Qos_ProfileSetting_ToString(Ros_QoS_Profile_Setting val)
Expand Down Expand Up @@ -862,6 +890,12 @@ void Ros_ConfigFile_Parse()

Ros_ConfigFile_ValidateCriticalSettings();
Ros_ConfigFile_ValidateNonCriticalSettings();
#if defined(YRC1000) || defined(YRC1000u)
if(g_nodeConfigSettings.userlan_debug_broadcast_enabled &&
(g_nodeConfigSettings.userlan_debug_broadcast_port == CFG_ROS_USER_LAN1 ||
g_nodeConfigSettings.userlan_debug_broadcast_port == CFG_ROS_USER_LAN2))
Ros_Debug_SetFromConfig();
jimmy-mcelwain marked this conversation as resolved.
Show resolved Hide resolved
#endif
Ros_ConfigFile_PrintActiveConfiguration(&g_nodeConfigSettings);
}

Expand Down
14 changes: 10 additions & 4 deletions src/ConfigFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,17 +88,20 @@ typedef enum

typedef enum
{
CFG_ROS_USER_LAN_DISABLED = -2, //sentinel
CFG_ROS_USER_LAN_MALFORMED = -3, //sentinel
CFG_ROS_USER_LAN_ALL = -2, //sentinel
CFG_ROS_USER_LAN_AUTO = -1, //sentinel
CFG_ROS_USER_LAN1 = ROS_USER_LAN1,
CFG_ROS_USER_LAN2 = ROS_USER_LAN2,
} Ros_UserLan_Port_Setting;
Comment on lines -91 to 96
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand why you opted to reuse the Ros_UserLan_Port_Setting type, but it does make the parsing code a little harder to read.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I tried doing it both ways, and this had much less duplicated code and was overall cleaner in my opinion. I don't especially like it either though.


#define DEFAULT_ULAN_MON_ENABLED TRUE
#define DEFAULT_ULAN_MON_LINK CFG_ROS_USER_LAN_AUTO
#define DEFAULT_ULAN_MON_ENABLED TRUE
#define DEFAULT_ULAN_MON_LINK CFG_ROS_USER_LAN_AUTO

#define DEFAULT_IGNORE_MISSING_CALIB FALSE
#define DEFAULT_IGNORE_MISSING_CALIB FALSE

#define DEFAULT_ULAN_DEBUG_BROADCAST_ENABLED TRUE
#define DEFAULT_ULAN_DEBUG_BROADCAST_PORT CFG_ROS_USER_LAN_ALL
typedef struct
{
//TODO(gavanderhoorn): add support for unsigned types
Expand Down Expand Up @@ -141,6 +144,9 @@ typedef struct
Ros_UserLan_Port_Setting userlan_monitor_port;

BOOL ignore_missing_calib_data;

BOOL userlan_debug_broadcast_enabled;
Ros_UserLan_Port_Setting userlan_debug_broadcast_port;
} Ros_Configuration_Settings;

extern Ros_Configuration_Settings g_nodeConfigSettings;
Expand Down
85 changes: 73 additions & 12 deletions src/Debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@

#define FORMATTED_TIME_SIZE 1024

int ros_DebugSocket = -1;
struct sockaddr_in ros_debug_destAddr1;
typedef struct
{
UINT8 enabledPortCount;
int debugSocket[MAX_NETWORK_PORTS];
struct sockaddr_in destAddr[MAX_NETWORK_PORTS];
} userLanInfo;

userLanInfo ros_debugPorts = {0};

void Ros_Debug_Init()
{
Expand All @@ -24,31 +30,84 @@ void Ros_Debug_Init()
ULONG gateway_be;
int broadcastVal = 1;
UCHAR mac[6];
STATUS status;
int count = 0;
int* socket = ros_debugPorts.debugSocket;
struct sockaddr_in* sin = ros_debugPorts.destAddr;

bzero(&ros_debugPorts, sizeof(ros_debugPorts));

for (int i = 1; i <= MAX_NETWORK_PORTS; i++)
{

status = Ros_mpNICData(i, &ip_be, &subnetmask_be, mac, &gateway_be);

if (status == OK)
{
socket[count] = mpSocket(AF_INET, SOCK_DGRAM, 0);
Ros_setsockopt(socket[count], SOL_SOCKET, SO_BROADCAST, (char*)&broadcastVal, sizeof(broadcastVal));
sin[count].sin_addr.s_addr = ip_be | (~subnetmask_be);
sin[count].sin_family = AF_INET;
sin[count].sin_port = mpHtons(DEBUG_UDP_PORT_NUMBER);
count++;
}
}
ros_debugPorts.enabledPortCount = count;
}

void Ros_Debug_SetFromConfig()
{
ULONG ip_be;
ULONG subnetmask_be;
ULONG gateway_be;
int broadcastVal = 1;
UCHAR mac[6];
STATUS status;
char message[ERROR_MSG_MAX_SIZE];
int* socket = ros_debugPorts.debugSocket;
struct sockaddr_in* sin = ros_debugPorts.destAddr;

ros_DebugSocket = mpSocket(AF_INET, SOCK_DGRAM, 0);
Ros_setsockopt(ros_DebugSocket, SOL_SOCKET, SO_BROADCAST, (char*)&broadcastVal, sizeof(broadcastVal));
bzero(&ros_debugPorts, sizeof(ros_debugPorts));

Ros_mpNICData(ROS_USER_LAN1, &ip_be, &subnetmask_be, mac, &gateway_be);
status = Ros_mpNICData(g_nodeConfigSettings.userlan_debug_broadcast_port, &ip_be, &subnetmask_be, mac, &gateway_be);

ros_debug_destAddr1.sin_addr.s_addr = ip_be | (~subnetmask_be);
ros_debug_destAddr1.sin_family = AF_INET;
ros_debug_destAddr1.sin_port = mpHtons(DEBUG_UDP_PORT_NUMBER);
if (status == OK)
{
socket[0] = mpSocket(AF_INET, SOCK_DGRAM, 0);
Ros_setsockopt(socket[0], SOL_SOCKET, SO_BROADCAST, (char*)&broadcastVal, sizeof(broadcastVal));
sin[0].sin_addr.s_addr = ip_be | (~subnetmask_be);
sin[0].sin_family = AF_INET;
sin[0].sin_port = mpHtons(DEBUG_UDP_PORT_NUMBER);
ros_debugPorts.enabledPortCount = 1;
}
else
{
int ret = snprintf(message, ERROR_MSG_MAX_SIZE, "Enable LAN port %d for debug", g_nodeConfigSettings.userlan_debug_broadcast_port);
if (0 < ret && ret <= 32)
mpSetAlarm(ALARM_ASSERTION_FAIL, message, SUBCODE_DEBUG_INIT_FAIL_MP_NICDATA_SPECIFIC);
else
mpSetAlarm(ALARM_ASSERTION_FAIL, "Enable debug LAN port from cfg", SUBCODE_DEBUG_INIT_FAIL_MP_NICDATA_SPECIFIC);
g_nodeConfigSettings.userlan_debug_broadcast_enabled = FALSE;
}
}

void Ros_Debug_BroadcastMsg(char* fmt, ...)
{
char str[MAX_DEBUG_MESSAGE_SIZE];
va_list va;

if (g_nodeConfigSettings.userlan_debug_broadcast_enabled && ros_debugPorts.enabledPortCount == 0)
Ros_Debug_Init();

if (!g_nodeConfigSettings.userlan_debug_broadcast_enabled && !g_nodeConfigSettings.log_to_stdout)
return;

bzero(str, MAX_DEBUG_MESSAGE_SIZE);

va_start(va, fmt);
vsnprintf(str, MAX_DEBUG_MESSAGE_SIZE, fmt, va);
va_end(va);

if (ros_DebugSocket == -1)
Ros_Debug_Init();

// Timestamp
//The timestamp for the message "Found Micro-Ros PC Agent" will be the epoch time (THU 1970-01-01 00:00:00.000) as the global flags
//are set to indicate that the Micro-Ros PC Agent is connected but the first sync of the host time using the micro-ROS agent is yet to occur
Expand Down Expand Up @@ -82,7 +141,9 @@ void Ros_Debug_BroadcastMsg(char* fmt, ...)
memcpy(str, timestamp, timestamp_length);
}

mpSendTo(ros_DebugSocket, str, strlen(str), 0, (struct sockaddr*) &ros_debug_destAddr1, sizeof(struct sockaddr_in));
for (int i = 0; i < ros_debugPorts.enabledPortCount; i++)
mpSendTo(ros_debugPorts.debugSocket[i], str, strlen(str), 0, (struct sockaddr*)&(ros_debugPorts.destAddr[i]), sizeof(struct sockaddr_in));
jimmy-mcelwain marked this conversation as resolved.
Show resolved Hide resolved


if (g_nodeConfigSettings.log_to_stdout)
puts(str);
Expand Down
6 changes: 6 additions & 0 deletions src/Debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@

#ifndef MOTOROS2_DEBUG_H
#define MOTOROS2_DEBUG_H
#if defined (YRC1000) || defined (YRC1000u)
#define MAX_NETWORK_PORTS 2
#else
#define MAX_NETWORK_PORTS 1
#endif

extern void Ros_Debug_SetFromConfig();
extern void Ros_Debug_BroadcastMsg(char* fmt, ...);
extern void Ros_Debug_LogToConsole(char* fmt, ...);

Expand Down
2 changes: 2 additions & 0 deletions src/ErrorHandling.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ typedef enum
SUBCODE_CONFIGURATION_FAIL_MP_NICDATA1,
SUBCODE_FAIL_MP_NICDATA_INIT1,
SUBCODE_FAIL_INVALID_BASE_TRACK_MOTION_TYPE,
SUBCODE_DEBUG_INIT_FAIL_MP_NICDATA_SPECIFIC,
jimmy-mcelwain marked this conversation as resolved.
Show resolved Hide resolved

} ALARM_ASSERTION_FAIL_SUBCODE; //8011

Expand Down Expand Up @@ -200,6 +201,7 @@ typedef enum
SUBCODE_CONFIGURATION_USERLAN_MONITOR_AUTO_DETECT_FAILED,
SUBCODE_CONFIGURATION_RUNTIME_USERLAN_LINKUP_ERR,
SUBCODE_CONFIGURATION_NO_CALIB_FILES_LOADED,
SUBCODE_CONFIGURATION_INVALID_USERLAN_DEBUG_BROADCAST_PORT,
} ALARM_CONFIGURATION_FAIL_SUBCODE; //8013

typedef enum
Expand Down
Loading