Class pn532::comm_operation

Class Documentation

class comm_operation

Class managing the correct firing of the events in channel.

This class is a RAII wrapper that fires the correct events at construction and destruction. It holds the transmission result obtained so far (or the corresponding error), in such a way that it can pass it to channel::on_receive_complete or channel::on_send_complete. Use the passthrough methods comm_operation::update to record results or errors, as in the example below. Use the comm_operation::ok accessor to check whether the channel::on_receive_prepare or channel::on_send_prepare events were successful before calling any lower level function.

using namespace std::chrono_literals;

// In a subclass of channel
result<any_frame> chn_subclass::custom_receive_frame() {
    // Create a comm_operation alive within the scope of the if.
    // This fires on_receive_prepare, and test with ::ok() whether it succeeded.
    if (comm_operation op{*this, comm_dir::receive, 10ms}; op.ok()) {
        // Able to receive, prepare buffer
        mlab::bin_data buffer{mlab::prealloc(100)};
        // Make sure to test whether the communication succeeded
        if (const auto result_comm = raw_receive(buffer.view(), 10ms); result_comm) {
            // Success, attempt parsing
            mlab::bin_stream s{buffer};
            frame_id fid{};
            s >> fid;
            if (s.bad()) {
                // Could not parse the frame, update the comm_operation and return
                return op.update(error::malformed);
            }
            // Extract the frame
            any_frame f{};
            std::tie(s, fid) >> f;
            if (s.bad()) {
                // Could not parse the frame, update the comm_operation and return
                return op.update(error::malformed);
            }
            // Nice! Parsed. Update the operation and return the frame
            return op.update(std::move(f));
        } else {
            // Failure, update the comm_opeation and return the error from raw_receive
            return op.update(result_comm.error());
        }
    } else {
        // Receive preparation failed, return the error collected into comm_operation
        return op.error();
    }
}

using namespace std::chrono_literals;

// In some subclass of channel that requires sending data to wake
bool chn_subclass::wake() {
    // Create a comm_operation alive within the scope of the if.
    // This fires on_send_prepare, and test with ::ok() whether it succeeded.
    if (comm_operation op{*this, comm_dir::send, 10ms}; op.ok()) {
        // Attempt sending data; use the result to update the comm operation
        //  and passthrough. An explicit cast to bool is required here.
        return bool(op.update(raw_send({0x55, 0x55, 0x55}, 10ms)));
    } else {
        return false;
    }
}

Note

Subclasses should never directly call any of channel::on_receive_prepare, channel::on_receive_complete, channel::on_send_prepare, channel::on_send_complete. These are managed by this class.

Warning

Always call channel::raw_send and channel::raw_receive with one such class in scope (otherwise the events will not be fired and the class may not be in the correct state).

Collect and update methods

These methods collect a result, an error, or a boolean representing success and store it inside the class. Moreover, they return whatever was passed to them (in the form of result or in form of channel_error), in such a way that the user can directly pass it through in a return statement. The updated result is used in the call to channel::on_receive_complete and channel::on_send_complete.

comm_operation op{...};
// ...
return op.update(raw_send(...));

inline channel_error update(channel_error e)

Stores an error state from an explicit error code.

Parameters:

e – Error code.

Returns:

The same error code e.

inline result update(bool operation_result)

Stores a success or timeout state from a boolean.

Parameters:

operation_result – True if the operation succeded, false if it timed out.

Returns:

mlab::result_success or channel_error::timeout, depending on operation_result.

template<class ...Tn, class ...Args>
inline result<Tn...> update(Args&&... args)

Stores an existing result into the internal result

Template Parameters:
  • Tn – Any result type for result.

  • Args – Anything that can be assigned to result.

Parameters:

args – Anything that can be assigned to result.

Returns:

The same result as the one constructed.

Public Functions

comm_operation(channel &owner, comm_dir event, ms timeout)

Calls channel::on_receive_prepare or channel::on_send_prepare and stores the outcome.

See also

ok

Parameters:
~comm_operation()

Calls channel::on_receive_complete or channel::on_send_complete with the internally stored result.

inline bool ok() const

Tests whether the operation contains an error or not. The main usage of this is to test whether the channel::on_receive_prepare and channel::on_send_prepare events have succeeded; however it will also return false if e.g. update has been called with a failed result.

// Fire the on_receive_prepare event.
if (comm_operation op{*this, comm_operation::receive, 10ms}; op.ok()) {
    // Do stuff
} else {
    // Preparation failed
}

Returns:

True if an only if so far all the operations succeeded.

inline channel_error error() const

Error currently stored in this operation.

Note

This calls mlab::result::error; if the result is not an error, it is not possible to call this method, therefore test first with ok that this comm_operation contains in fact an error code.

Returns:

The error code of the currently stored result.