Logging, Exceptions, and Errors: Difference between revisions

From Phidgets Support
(Changed redirect target from Handling Errors and Logging to Phidget Logging)
Tag: Redirect target changed
 
(14 intermediate revisions by 5 users not shown)
Line 1: Line 1:
[[Category:Programming]]
#REDIRECT [[Phidget Logging]]
You've written your code, fixed the compiler errors, and yet, the program still isn't behaving as intended. The tools described on this page will help you further debug your program and figure out where in the code things are going wrong.
 
 
==Logging==
 
You can enable logging to get more debugging information. This would happen at the very start of your program, before even initializing your software object or opening it.  Logging lets you get feedback from the Phidget libraries about every Phidget API call you make.
 
Logging is controlled through the Logging API. You can see the full list of functions and properties by going to the {{Phidget22API}} and selecting '''Logging API''' from the drop-down menu.
 
In C, turning on logging to the command line would look like:
 
<syntaxhighlight lang=cpp>
 
PhidgetLog_enable(PHIDGET_LOG_DEBUG, NULL);
 
</syntaxhighlight>
 
Or in Java:
 
<syntaxhighlight lang=java>
 
Log.enable(LogLevel.DEBUG, null);
 
</syntaxhighlight>
 
The use of null is to indicate that the output is not to a file (and hence to the command line).  Otherwise, the second argument would be a string filename.
 
There are six different logging levels, ranging from "Give me Everything!" to "Tell me only about critical problems".  The level in the examples above - <code>PHIDGET_LOG_DEBUG</code> - is a medium output level.
 
'''CRITICAL = 0x1'''
:Critical error messages.
:This is the lowest logging level. Errors at this level are generally non-recoverable and indicate either hardware problems, library bugs, or other serious issues.
 
'''ERROR = 0x2'''
:Non-critical error messages.
:Errors at this level are generally automatically recoverable, but may help to track down issues.
 
'''WARNING = 0x3'''
:Warning messages.
:Warnings are used to log behavior that is not necessarily in error, but is nevertheless odd or unexpected.
 
'''DEBUG = 0x4'''
:Debug messages.
:Debug messages are generally used for debugging at Phidgets Inc.
:'''Note:''' PHIDGET_LOG_DEBUG messages are only logged in the debug version of the library, regardless of logging level. Thus, these logs should never be seen outside of Phidgets Inc.
 
'''INFO = 0x5'''
:Informational messages.
:Informational messages track key happenings within phidget21 - mostly to do with threads starting and shutting down, and the internal USB code.
 
'''VERBOSE = 0x6'''
:Verbose messages.
:This is the highest logging level. Verbose messages are informational messages that are expected to happen so frequently that they tend to drown out other log messages.
 
You can also find this list of log levels in the '''Enumerations''' section of Logging API in the {{Phidget22API}} documentation.
 
=== Making Use of Logging in Your Program ===
 
In addition to error logging from within the Phidget libraries, the Logging API also has support for adding logging to your own programs. The {{Code|log()}} function can be called to print a line into the log file.
 
For example, in C:
 
<syntaxhighlight lang=cpp>
 
PhidgetLog_log(PHIDGET_LOG_DEBUG, "Something happened in loop iteration %d!",i);
 
</syntaxhighlight>
 
Or in Java:
 
<syntaxhighlight lang=java>
 
Log.log(LogLevel.DEBUG, "Something happened in loop iteration" + i + "!");
 
</syntaxhighlight>
 
This example shows how you can add variables to the information in your log. In C, it behaves similarly to the {{Code|printf()}} function, and in Java you can concatenate the string with variables using the plus operator.
 
If you have a complex program with many different places where similar messages might be logged from, you can organize them by setting a log source name and then using the extended log function to specify that the message is coming from that source. The log level for that source can be set separately from other sources. This feature is only available in C, since it's the only one with special macros like {{Code|__LINE__}} or {{Code|__func__}} to get the line number and function, respectively.
 
For example:
 
<syntaxhighlight lang=cpp>
 
PhidgetLog_addSource("my_program_init",PHIDGET_LOG_DEBUG);
PhidgetLog_loge(__FILE__, __LINE__, __func__, "my_program_init", PHIDGET_LOG_DEBUG, "Something happened in loop iteration %d!",i);
 
</syntaxhighlight>
 
This extended log function will log the file that the message came from, the line number, the function, the log source, and the message you provided. You can also change the log level of a specific source by calling {{Code|setSourceLevel()}}.
 
==Exceptions and Errors==
 
There are two different types of errors that you can use to determine where a problem exists in your program.
 
===Error Generated By A Function===
 
When you call a function in the Phidgets library, it tells you whether that function succeeded or failed, and if it failed, what went wrong.  For example, you might try to read analog sensor port #9 on a board that only has eight.  The {{Code|getVoltage()}} function you used to read port 9 would return error code {{Code|EPHIDGET_INVALIDARG}} (in C/C++) or throw an error event (in languages that support exceptions like Java, .NET, or Python). 
 
These errors happen ''synchronously'' to the function, that is, they are returned or thrown right after a function returns.  You can handle these by checking the return values on your functions (in C/C++) or using an error catching function like <code>try...catch</code> in languages that support exceptions (e.g., Java, .NET, Python).
 
For example, in C, you might write a LocalErrorCatcher function that you can then use on every Phidget function you call in order to detect and deal with errors:
 
<syntaxhighlight lang=cpp>
  int LocalErrorCatcher (int errorCode) {
 
      if (errorCode != 0) {  // Everything is okay if errorCode = 0
   
          switch (errorCode) {
 
            case EPHIDGET_INVALIDARG: // example error handler
            printf("Invalid arguments sent to function.");
            // do other things specific to this error
            break;
 
            default:
              const char *errorDescription;
              LocalErrorCatcher(
                  Phidget_getErrorDescription (errorCode, &errorDescription));
              printf("The description for error %d is: %s\n", errorCode, errorDescription);
              break;
          }
      }
      return 0;
  }
 
  // ... Then, later, you would use it on any Phidget function:
  LocalErrorCatcher(
      Phidget_open((CPhidgetHandle) device, -1));
 
</syntaxhighlight>
 
 
Note that:
# The function {{Code|LocalErrorCatcher}} uses itself to check for errors on getting an error description. 
# You can handle individual error codes as they are listed in the API (like the INVALIDARG example), and you can write customized code to do special things reacting to that specific error. This is useful for applications where errors are an inevitability due to (potentially incorrect) user input, and you want to be able to handle and correct them in real-time.  The default case only prints a general message, and is more useful for general debugging.
 
Or in Java, you would try a Phidget method, and catch any resulting exception that occurs:
 
<syntaxhighlight lang=java>
  try {
      device.open();
  } catch (PhidgetException exception) {
      system.out.println("The description for error " + Integer.toString(exception.getErrorCode()) + " is: ", exception.getDescription());
  }
 
</syntaxhighlight>
 
As with the previous example, you could also use a <code>try...catch</code> statement around the exception.getErrorNumber() and exception.getDescription()  to catch any errors from those calls.
 
The consequences of not catching this type of error (on ''every'' function) differ by programming language.
In C/C++ these errors must be ''explicitly'' checked for after each function call, otherwise the program will simply continue on in an incorrect state.  In languages that support exceptions (e.g., Java, .NET, Python), errors are returned using exceptions which will leave you no choice but to catch them, or have your program terminate when the exception occurs.
 
Be careful when trying to determine what is causing the exception.  Depending on how your code is structured, you can have exceptions that claim to be a particular Phidget exception but in fact have originated from non-Phidgets code(for example, a non-Phidgets function called from inside a Phidgets event handler).
 
====Error Codes====
 
You can find a complete list of possible error codes in the {{Phidget22API}} under the Phidget API section. Scroll down to the bottom and open up the {{Code|PhidgetReturnCode}} enumeration. In some languages, they won't be listed because they're thrown as exceptions instead of returned by functions.
 
===Error Generated From The Device===
 
These errors are generated by the Phidget library during runtime.  For example, the Phidget device might be experiencing too high a temperature, and trigger an error.  This would not necessarily be due to any one function your program called; rather, the error would appear when the problem appears and would trigger an event.
 
So, these errors happen ''asynchronously'', that is, something happens apart from any function calls and an error event is triggered. You can handle these by setting up an Error Event Handler.
 
In C, this would look like:
 
<syntaxhighlight lang=cpp>
  int ErrorEventHandler (PhidgetHandle device, void *usrptr, Phidget_ErrorEventCode errorCode, const char *errorDescription) {
    printf("The description for error %d is: %s\n", errorCode, errorDescription);
    // Do something useful based on the error code
    return 0;
  }
 
  // At the beginning of your program, hook the Error Event Handler in to receive events
  LocalErrorCatcher(
      Phidget_setOnErrorHandler((PhidgetHandle) device, ErrorEventHandler, NULL));
</syntaxhighlight>
 
You'll note that the '''ErrorEventHandler''' function is what gets called when an error event occurs, and it gives you an opportunity to handle the error. 
 
You'll also note that there is a second function called '''LocalErrorCatcher'''.  This second function handles the return value from setting the  error handler.  We included it here because, as these are examples on how to handle errors, the example would leave a possibly unhandled error without it. This second type of error handling  and the '''LocalErrorCatcher''' function are [[#Phidget Return Codes|described above]].
 
In Java, it would look like this:
 
<syntaxhighlight lang=java>
  try {
    device.addErrorListener((ErrorEvent ee) -> {
            System.out.println("Error: " + ee.getDescription());
        });
    });
  } catch (PhidgetException exception) {
      system.out.println("The description for error " + Integer.toString(exception.getErrorCode()) + " is: ", exception.getDescription());
  }
 
</syntaxhighlight>
 
Like C above, the act of hooking an error listener in to the device can itself generate an error, which should be caught. 
 
These event-type errors are also how a Phidget being run over a network announces bad passwords, lost packets, and other network problems.  Locally, the errors can announce incorrect temperatures, current, and power. So, it is in your best interest to set up an error event handler and take action based on the codes and error types in the {{Phidget22API}}.
 
====Error Codes====
 
These codes are used within the Error Event. See the {{Phidget22API}} documentation for your device to see which codes can be returned by which functions. These codes can be very generalized so it’s important to look at the accompanying description. These codes are broken down into errors that stem from within the library, errors which are directly reported by Phidget hardware, and errors that occur in your software.
 
'''BADVERSION'''
:Version Mismatch Error. Usually means client and host side of a network connection are out of sync. Update the latest versions of the Phidget drivers on both the client and the host.
 
 
'''BUSY'''
:The Phidget channel has already been opened locally by another process, so it can't be opened. You can have multiple processes open the same channel if they all open it remotely (with the exception of some Phidgets like motor controllers, which only allow a single connection regardless of whether it's local or remote).
 
 
'''NETWORK'''
:???
 
 
'''DISPATCH'''
:???
 
 
'''OK'''
: An error state has ended. You can use the <code>getDescription</code> method of the error event to get more information. For example, if there is an over-voltage condition occurring, this error code will be thrown when the voltage returns to acceptable levels.
 
 
'''OVERRUN'''
:Sampling overrun. Some samples were lost in firmware because the queue filled up. This error is exclusive to Phidget InterfaceKits.
 
 
'''PACKETLOST'''
:Packet(s) were lost. This error is often an indication that your event handlers are not executing fast enough. Try to remove slow processes like GUI updates or user input from your handlers.
 
 
'''WRAP'''
:A variable has wrapped. For example, the encoder position can wrap from 2,147,483,647 to -2,147,483,648 because of an integer overflow.
 
 
'''OVERTEMP'''
:Over-Temperature condition detected. See error description for more details.
 
 
'''OVERCURRENT'''
:Over-Current condition detected. See error description for more details.
 
 
'''OUTOFRANGE'''
:Out of range condition detected. Usually an input on the board is reporting a value that is outside of the allowed range.
 
 
'''BADPOWER'''
:Power supply problem detected. Either the power supply is being overloaded, or it is under-powered (possibly not plugged in).
 
 
'''SATURATION'''
:A sensor's value has reached the maximum or minimum of its sensing range. For example, a 1000 lux light sensor will throw this error event when a value greater than 1000 lux is detected. The sensor will still be reporting 1000 lux, but this error tells you that you don't know for certain how much higher than 1000 the real reading is.
 
 
'''OVERVOLTAGE'''
:Over-Voltage condition detected.
 
 
'''FAILSAFE'''
:???
 
 
'''VOLTAGEERROR'''
:???
 
 
'''ENERGYDUMP'''
:???
 
== Other Problems ==
 
If your Phidget is still not behaving as expected after handling errors and exceptions, have a look at our [[General Troubleshooting]] guide to track down the problem.
 
== Further Reading ==
 
[[Phidget Programming Basics]] - Here you can find the basic concepts to help you get started with making your own programs that use Phidgets.
 
[[Data Interval/Change Trigger]] - Learn about these two properties that control how much data comes in from your sensors.
 
[[Using Multiple Phidgets]] - It can be difficult to figure out how to use more than one Phidget in your program. This page will guide you through the steps.
 
[[Polling vs. Events]] - Your program can gather data in either a polling-driven or event-driven manner. Learn the difference to determine which is best for your application.
 
[[Phidget Network Server]] - Phidgets can be controlled and communicated with over your network- either wirelessly or over ethernet.
 
[[Best Phidgets Practices]] - Good programming habits that will save you from common problems when writing code for your Phidgets.

Latest revision as of 20:30, 3 August 2023

Redirect to: