| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef GARNET_DRIVERS_BLUETOOTH_LIB_COMMON_STATUS_H_ |
| #define GARNET_DRIVERS_BLUETOOTH_LIB_COMMON_STATUS_H_ |
| |
| #include <stdarg.h> |
| |
| #include <cstdint> |
| #include <string> |
| |
| #include <zircon/assert.h> |
| |
| #include "lib/fxl/strings/string_printf.h" |
| |
| #include "garnet/drivers/bluetooth/lib/common/log.h" |
| |
| namespace btlib { |
| namespace common { |
| |
| // Status types used for internal errors generated by the host |
| enum class HostError : uint8_t { |
| kNoError = 0u, |
| |
| // Not found. |
| kNotFound, |
| |
| // Not ready. |
| kNotReady, |
| |
| // The time limit for the operation has expired. |
| kTimedOut, |
| |
| // The operation was initiated with invalid parameters. |
| kInvalidParameters, |
| |
| // The operation was canceled. |
| kCanceled, |
| |
| // Operation is already in progress. |
| kInProgress, |
| |
| // Operation is not supported by the host. |
| kNotSupported, |
| |
| // Received an invalid packet from the controller. |
| kPacketMalformed, |
| |
| // Link was disconnected during operation. |
| kLinkDisconnected, |
| |
| // Ran out of resources. |
| kOutOfMemory, |
| |
| // Error code for protocol errors. The actual error code is specified by a |
| // protocol error code type. |
| kProtocolError, |
| |
| // Generic error code. Use this only if another error code does not accurately |
| // capture the failure condition. |
| kFailed, |
| }; |
| |
| // Returns a string representation of HostError. |
| std::string HostErrorToString(HostError error); |
| |
| // Required trait for ProtocolErrorCode types. |
| template <typename ProtocolErrorCode> |
| struct ProtocolErrorTraits { |
| // Returns a string representation of the given ProtocolErrorCode value. |
| static std::string ToString(ProtocolErrorCode); |
| }; |
| |
| template <typename ProtocolErrorCode> |
| class Status { |
| using ProtoTraits = ProtocolErrorTraits<ProtocolErrorCode>; |
| |
| public: |
| // The result will carry a protocol error code. |
| constexpr explicit Status(ProtocolErrorCode proto_code) |
| : error_(HostError::kProtocolError), protocol_error_(proto_code) {} |
| |
| // The result will carry a host error. Constructs a success result by default. |
| constexpr explicit Status(HostError ecode = HostError::kNoError) |
| : error_(ecode) { |
| ZX_DEBUG_ASSERT_MSG( |
| ecode != HostError::kProtocolError, |
| "HostError::kProtocolError not allowed in HostError constructor"); |
| } |
| |
| // Returns true if this is a success result. |
| bool is_success() const { return error_ == HostError::kNoError; } |
| |
| // Returns the host error code. |
| HostError error() const { return error_; } |
| |
| // Returns true if this result is a protocol error. |
| bool is_protocol_error() const { return error_ == HostError::kProtocolError; } |
| |
| // Returns the protocol error code. This value is undefined if error() is |
| // not equal to HostError::kProtocolError. |
| ProtocolErrorCode protocol_error() const { return protocol_error_; } |
| |
| // Returns true if this is a success result. |
| operator bool() const { return is_success(); } |
| |
| // Returns a string representation. |
| inline std::string ToString() const { |
| return fxl::StringPrintf( |
| "[status: %s]", |
| (is_protocol_error() ? ProtoTraits::ToString(protocol_error()) |
| : HostErrorToString(error())) |
| .c_str()); |
| } |
| |
| // Helper that returns true if this status represents an error and prints a |
| // message containing a string representation of the status. |
| bool TestForErrorAndLog(LogSeverity severity, const char* tag, |
| const char* file, int line, |
| const std::string& msg) const { |
| bool is_error = !is_success(); |
| if (is_error && IsLogLevelEnabled(severity)) { |
| LogMessage(file, line, severity, tag, "%s: %s", msg.c_str(), |
| ToString().c_str()); |
| } |
| return is_error; |
| } |
| |
| bool TestForErrorAndLogF(LogSeverity severity, const char* tag, |
| const char* file, int line, const char* fmt, |
| ...) const { |
| va_list args; |
| va_start(args, fmt); |
| std::string msg = fxl::StringVPrintf(fmt, args); |
| va_end(args); |
| return TestForErrorAndLog(severity, tag, file, line, msg); |
| } |
| |
| private: |
| HostError error_; |
| ProtocolErrorCode protocol_error_; |
| }; |
| |
| } // namespace common |
| } // namespace btlib |
| |
| // Macro to check and log any non-Success status of an event. |
| // Use these like: |
| // if (bt_is_error(status, WARN, "gap", "failed to set event mask")) { |
| // ... |
| // return; |
| // } |
| // |
| // It will log with the string prepended to the stringified status if status is |
| // a failure. Evaluates to true if the status indicates failure. |
| |
| #define bt_is_error(status, flag, tag, fmt...) \ |
| (status.TestForErrorAndLogF(::btlib::common::LogSeverity::flag, tag, \ |
| __FILE__, __LINE__, fmt)) |
| |
| #endif // GARNET_DRIVERS_BLUETOOTH_LIB_COMMON_STATUS_H_ |