API and Command Error Handling

API and Command Errors

When using NxLib you can encounter two different types of errors:

  • API errors: these happen when a read or write operation to a tree item fails. This might happen when you try to modify a read-only item (like the camera’s serial number of status node ), or you try to read a value from an inexistent item (i.e. the path specified in the read operation does not correspond to a node in the tree). API errors are reported directly via return codes or exceptions, depending on which of the overloaded read/write functions you use.

  • Command execution errors: the execution of commands via the Execute node at the tree root level is a concept that is built on top the tree read/write functionality. A command is executed after writing its name into the Command node. A separate thread takes care of the command execution and clears the Command node (sets it to the JSON value Null ) after the command has finished executing. If the command execution thread encounters problems during the command it will create a node /Execute/Result/ErrorSymbol and /Execute/Result/ErrorText. ErorrSymbol serves as a unique, constant identifier for the error type and ErrorText contains an English human readable explanation of what happened. The user should therefore check for the existence of the ErrorSymbol node after each command execution to determine if the command suceeded. When using the NxLibCommand classes to execute commands the existence of ErrorSymbol is checked automatically and an exception with the error code NxLibExecutionFailed is generated.

Error Handling with Exceptions

Using our C++ or C# classes error handling can conveniently done with exceptions by encapsulating code blocks like this:

try {
	// Code block using NxLib's C++ classes NxLibItem and NxLibCommand. These might throw and
	// exception of type NxLibException.
	// An example of a failing Open command is shown below:

	NxLibCommand open(cmdOpen);
	open.parameters()[itmCameras] = ""; // This fails, as the serial number is mandatory for opening.
	open.execute();                     // and throws an NxLibException here.
} catch (NxLibException& e) {
	// Errors related to accessing the parameter tree are directly contained as return codes.

	// NxLibCommand can return the special return code 'NxLibExecutionFailed' to indicate that
	// the executed command returned more error information in the ErrorSymbol and ErrorText nodes.

	if (e.getErrorCode() == NxLibExecutionFailed) {
		// The command above has failed to execute successfully. Print all information to identify what happened.
		// The NxLibException stores the NxLibItem (within a NxLibToken), in which the NxLibCommand parameters and
		// results are stored.

		std::string errorSymbol = e.getToken()->item[itmResult][itmErrorSymbol].asString();
		std::string completeParametersAndResults = e.getToken()->item.asJson(true);

		std::cerr << "The execution of a command failed with error: " << errorSymbol << std::endl;
		std::cerr << "The full command and all parameters in JSON format of the failed command were:" << std::endl
		          << completeParametersAndResults << std::endl;
	} else {
		// Access to some tree node failed. Print the error code and corresponding text.

		std::cerr << "An NxLib API error " << e.getErrorCode() << " occurred when accessing the item "
		          << e.getItemPath() << ". Message: " << e.getErrorText() << std::endl;
	}
}
open_framegrabber ('Ensenso-NxLib', 0, 0, 0, 0, 0, 0, 'default', 0, 'Raw', -1, 'false', 'Item', '/', 0, 0, RootHandle)

try
   * Code block using Ensenso-NxLib framegrabber functions
catch (Exception)
   * Errors related to accessing the parameter tree are directly contained as return codes.
   * NxLibCommand can return the special return code 'NxLibExecutionFailed' to indicate that
   * the executed command returned more error information in the ErrorSymbol and ErrorText nodes.

   get_framegrabber_param (RootHandle, 'error_code', ErrorCode)
   if (ErrorCode == 17)
      * A command has failed to execute successfully. Print all information to identify what happened.
      get_framegrabber_param (RootHandle, 'exec:Result/ErrorSymbol', ErrorSymbol)
      get_framegrabber_param (RootHandle, 'exec:Result/ErrorText', ErrorText)
      throw ('The execution of a command failed with error ' + ErrorSymbol + '. Message: ' + ErrorText)
   else
      * Access to some tree node failed. Print the error code and corresponding text.
      get_framegrabber_param (RootHandle, 'error_item', ErrorItem)
      get_framegrabber_param (RootHandle, 'error_text', ErrorText)
      throw ('An NxLib API error ' + ErrorCode + ' occurred when accessing the item ' + ErrorItem + '. Message: ' + ErrorText)
   endif
endtry

Error Handling with Return Codes

It is also possible to handle errors by checking return codes of each NxLib function call. A list of return codes of the read/write functions can be found in the API Return Codes topic.

Reading/Writing Tree Nodes

For the case of reading or writing a tree error handling could look like this:

// Read a parameter on a camera with serial number "1234"

int result;
bool available = nxLibGetBool(&result, "/Cameras/1234/Status/Available");

if (result == NxLibOperationSucceeded) {
	printf("The camera is currently available%s\n.", available ? "true" : "false");
} else {
	char const* errorText = nxLibTranslateReturnCode(result);
	printf("Could not read status node due to error %d. Message %s\n.", result, errorText);
}

Command Execution

// Execute the Capture command on the camera with serial number "1234" and check for errors

int result;
nxLibSetString(&result, "/Execute/Parameters/Cameras", "1234");
// Check 'result' of write operation as under 'Reading/Writing Tree Nodes' above
// ...

nxLibSetString(&result, "/Execute/Command", "Capture");
// Check 'result' of write operation as under 'Reading/Writing Tree Nodes' above
// ...

// The command "Capture" is now executing. When it's finished the /Execute/Command node will be cleared and set to
// 'null'.

// Wait for the command to finish (i.e. wait for the Command node to become 'null' again
nxLibWaitForType(&result, "/Execute/Command", NxLibItemTypeNull, true);
// Check 'result' of wait operation as under 'Reading/Writing Tree Nodes' above
// ...

// Now we must check if the command returned an error by looking at the /Execute/Result/ErrorSymbol node:
// if it exists, we can use the ErrorSymbol and ErrorText nodes to identify what happended,
// otherwise the command execution was successful

int type = nxLibGetType(&result, "/Execute/Result/ErrorSymbol");
// If the command execution succeeded the ErrorSymbol node should not exist and nxLibGetType should return the api
// error 'NxLibItemInexistent' and type should be NxLibItemTypeInvalid. When the ErrorSymbol exists the type should
// be NxLibItemTypeString.
if (result == NxLibItemInexistent && type == NxLibItemTypeInvalid) {
	printf("The capture command succeeded\n.");
} else {
	NXLIBSTR errorSymbol = nxLibGetString(&result, "/Execute/Result/ErrorSymbol");
	NXLIBSTR errorText = nxLibGetString(&result, "/Execute/Result/ErrorText");
	NXLIBSTR failedCommandInfo = nxLibGetJson(&result, "/Execute/Result/Execute", true, 6, false);
	if (errorSymbol && errorText && failedCommandInfo) {
		printf(
		    "Image capture failed with error %s. Message %s\n. Failed command with parameters:\n%s\n", errorSymbol,
		    errorText, failedCommandInfo);
	} else {
		printf(
		    "Something went wrong. We could not read out ErrorSymbol, ErrorText or the failing command info from "
		    "/Execute/Result.\n");
	}
}