Skip to content

Latest commit

 

History

History
221 lines (171 loc) · 7.69 KB

cpp_error_management.md

File metadata and controls

221 lines (171 loc) · 7.69 KB

Error management

Table of Contents

Overview

There are three mechanisms available to manage errors triggered by the C++ Kortex API:

  • standard Exception
  • accessing the Error object returned by the callback function, and
  • catching the exception thrown by a std::future.

When you use the Kortex API, the mechanism to be used depends on the type of called method:

  • With the blocking method, use standard Exception.
  • With the callback version of a method, use the Error object provided in the callback header.
  • With the async version of a method, use the Exception thrown by the future.

Note that there is a special case explained at the end of this section.

Blocking method

Exceptions are only used if a blocking or async function is used. The code is surrounded with a try/catch statement pair and to catch any exceptions. The Kortex API offers its own exception object: Kinova::Api::KDetailedException.

Example

try
{
    // Your code...
}
catch(k_api::KDetailedException& ex)
{
    // You can print the error informations and error codes
    auto error_info = ex.getErrorInfo().getError();
    std::cout << "KDetailedoption detected what:  " << ex.what() << std::endl;
    
    std::cout << "KError error_code: " << error_info.error_code() << std::endl;
    std::cout << "KError sub_code: " << error_info.error_sub_code() << std::endl;
    std::cout << "KError sub_string: " << error_info.error_sub_string() << std::endl;

    // Error codes by themselves are not very verbose if you don't see their corresponding enum value
    // You can use google::protobuf helpers to get the string enum element for every error code and sub-code 
    std::cout << "Error code string equivalent: " << k_api::ErrorCodes_Name(k_api::ErrorCodes(error_info.error_code())) << std::endl;
    std::cout << "Error sub-code string equivalent: " << k_api::SubErrorCodes_Name(k_api::SubErrorCodes     (error_info.error_sub_code())) << std::endl;
}

Here are the details of the object Kinova::Api::KDetailedException thrown by the Kortex API.

KDetailedException

class KDetailedException : public KBasicException
{
    public:
        KDetailedException(const KError& error);
        KDetailedException(const KDetailedException &other);

        virtual const char* what() const throw() override;
        virtual std::string toString() override;

        KError&      getErrorInfo() { return m_error; }

    private:
        void init(const HeaderInfo& header, const Error& error);
    
        KError       m_error;
        std::string  m_errorStr;
};

Here are the details of the object KError nested in the exception.

KError

class KError
{
    public:
        KError(Kinova::Api::ErrorCodes errorCode, Kinova::Api::SubErrorCodes errorSubCode, std::string errorDescription);
        KError(const HeaderInfo& header, Kinova::Api::ErrorCodes errorCode, Kinova::Api::SubErrorCodes errorSubCode, std::string errorDescription);
        KError(const Error& error);
        KError(const HeaderInfo& header, const Error& error);

        static Error fillError(Kinova::Api::ErrorCodes errorCode, Kinova::Api::SubErrorCodes errorSubCode, std::string errorDescription);

        std::string toString() const;

        bool            isThereHeaderInfo();
        HeaderInfo      getHeader();
        Error           getError();

        KError& operator =(const KError& other) = default;

    private:
        bool            m_isThereHeaderInfo;
        HeaderInfo      m_header;
        Error           m_error;
};

The KError object holds an error code and a sub error code to identify the fault.

Here is a link to documentation explaining all of the error and sub error codes:

Callback

If the callback version is used, a std::function is given as a parameter to act as a callback. The header of this std::function includes an Error object containing the error returned by the execution. Since it is a std::function, you can either use a lambda expression or a standard C callback.

Example using lambda

// callback function used in Refresh_callback
auto lambda_fct_callback = [](const Kinova::Api::Error &err, const k_api::BaseCyclic::Feedback data)
{
    // We are printing the data for example purposes
    // avoid this for a real-time loop 

    std::string serialized_data;
    google::protobuf::util::MessageToJsonString(data, &serialized_data);
    std::cout << serialized_data << std::endl;
};

base_cyclic->Refresh_callback(BaseCommand, lambda_fct_callback, 0);

Example using C callback

// callback function used in Refresh_callback
void fct_callback(const k_api::Error &err, const k_api::BaseCyclic::Feedback data)
{
    std::cout << "Callback function results: " << std::endl;
    //react to the fault...
}

void example_function_call()
{
	base_cyclic->Refresh_callback(BaseCommand, fct_callback, 0);
}

Async method

If an async function is used, exceptions must be used to catch any error triggered by the Kortex API. The exception is thrown during the execution of the get() function.

Async example

// The function returns a future object, and not a workable object.
std::future<k_api::Base::JointsLimitationsList> limitations_future_async = base->GetAllJointsSpeedHardLimitation_async();

// Waiting for the promise to be completed by the API.
auto timeout_ms = std::chrono::milliseconds(10000);
std::future_status status = limitations_future_async.wait_for(timeout_ms);

if(status != std::future_status::ready)
{
    throw std::runtime_error("Timeout detected while waiting for function\n");
}

// Retrieve the workable object from the future object.
try
{
    auto limitations_async = limitations_future_async.get();
}
catch(k_api::KDetailedException& ex)
{
    // Respond to the fault
}

Special case

This section describes a case that doesn't follow the standard error management rules documented earlier in this document.

RouterClient

When a RouterClient object is instantiated a callback can be specified for execution when an error occurs.

RouterClient* router = new RouterClient(pTransport, [](KError err){ cout << "callback error" << err.toString(); });