Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ce0cf7c authored by Jakub Pawłowski's avatar Jakub Pawłowski Committed by Gerrit Code Review
Browse files

Merge changes I9bd7854e,I7ea9f07c

* changes:
  has_client: Adjust to latest HAS specification
  has_client: Update characteristic values
parents 19313ddb d8c745d6
Loading
Loading
Loading
Loading
+8 −7
Original line number Diff line number Diff line
@@ -395,7 +395,7 @@ class HasClientImpl : public HasClient {
    }

    auto op = op_opt.value();
    if (op.opcode == PresetCtpOpcode::READ_PRESET_BY_INDEX) {
    if (op.opcode == PresetCtpOpcode::READ_PRESETS) {
      callbacks_->OnPresetInfoError(device->addr, op.index,
                                    GattStatus2SvcErrorCode(status));

@@ -588,7 +588,7 @@ class HasClientImpl : public HasClient {

    if (status != ErrorCode::NO_ERROR) {
      switch (operation.opcode) {
        case PresetCtpOpcode::READ_PRESET_BY_INDEX:
        case PresetCtpOpcode::READ_PRESETS:
          LOG_ASSERT(
              std::holds_alternative<RawAddress>(operation.addr_or_group))
              << " Unsupported group operation!";
@@ -837,8 +837,8 @@ class HasClientImpl : public HasClient {
                                 .available = preset->IsAvailable(),
                                 .preset_name = preset->GetName()}});
    } else {
      CpPresetIndexOperation(HasCtpOp(
          address, PresetCtpOpcode::READ_PRESET_BY_INDEX, preset_index));
      CpPresetIndexOperation(
          HasCtpOp(address, PresetCtpOpcode::READ_PRESETS, preset_index));
    }
  }

@@ -849,7 +849,7 @@ class HasClientImpl : public HasClient {

    CpWritePresetNameOperation(HasCtpOp(addr_or_group_id,
                                        PresetCtpOpcode::WRITE_PRESET_NAME,
                                        preset_index, name));
                                        preset_index, 1 /* Don't care */, name));
  }

  void CleanUp() {
@@ -1662,8 +1662,9 @@ class HasClientImpl : public HasClient {
                                ccc_val);

      /* Get all the presets */
      CpReadAllPresetsOperation(
          HasCtpOp(device->addr, PresetCtpOpcode::READ_ALL_PRESETS));
      CpReadAllPresetsOperation(HasCtpOp(
          device->addr, PresetCtpOpcode::READ_PRESETS,
          le_audio::has::kStartPresetIndex, le_audio::has::kMaxNumOfPresets));

      /* Read the current active preset index */
      BtaGattQueue::ReadCharacteristic(
+45 −49
Original line number Diff line number Diff line
@@ -319,7 +319,7 @@ class HasClientTestBase : public ::testing::Test {
                                              void* cb_data) {
          auto pp = value.data();
          auto len = value.size();
          uint8_t op, index;
          uint8_t op, index, num_of_indices;

          const bool indicate = false;

@@ -344,25 +344,21 @@ class HasClientTestBase : public ::testing::Test {
          }

          switch (static_cast<::le_audio::has::PresetCtpOpcode>(op)) {
            case ::le_audio::has::PresetCtpOpcode::READ_ALL_PRESETS:
              ASSERT_EQ(0u, len);
              InjectNotifyReadPresetsResponse(conn_id, address, handle, value,
                                              indicate, -1, cb, cb_data);
              break;

            case ::le_audio::has::PresetCtpOpcode::READ_PRESET_BY_INDEX:
              if (len < 1) {
            case ::le_audio::has::PresetCtpOpcode::READ_PRESETS:
              if (len < 2) {
                if (cb)
                  cb(conn_id, GATT_INVALID_ATTR_LEN, handle, value.size(),
                     value.data(), cb_data);

              } else {
                STREAM_TO_UINT8(index, pp);
                --len;
                STREAM_TO_UINT8(num_of_indices, pp);
                len -= 2;
                ASSERT_EQ(0u, len);

                InjectNotifyReadPresetsResponse(conn_id, address, handle, value,
                                                indicate, index, cb, cb_data);
                                                indicate, index, num_of_indices,
                                                cb, cb_data);
              }
              break;

@@ -949,38 +945,43 @@ class HasClientTestBase : public ::testing::Test {
                            value, indicate);
  }

  void InjectNotifyReadPresetsResponse(uint16_t conn_id,
                                       RawAddress const& address,
                                       uint16_t handle,
                                       std::vector<uint8_t> value,
                                       bool indicate, int index,
  void InjectNotifyReadPresetsResponse(
      uint16_t conn_id, RawAddress const& address, uint16_t handle,
      std::vector<uint8_t> value, bool indicate, int index, int num_of_indices,
      GATT_WRITE_OP_CB cb, void* cb_data) {
    auto presets = current_peer_presets_.at(conn_id);
    LOG_ASSERT(!presets.empty()) << __func__ << " Mocking error!";

    if (index == -1) {
      if (cb)
        cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(), cb_data);
      /* Notify all presets */
      for (auto preset = presets.begin(); preset != presets.end(); preset++) {
        InjectNotifyReadPresetResponse(conn_id, address, handle, *preset,
                                       indicate,
                                       (preset == std::prev(presets.end())));
      }
    } else {
    /* Index is a start index, not necessary is a valid index for the
     * peer device */
    auto preset = presets.find(index);
      if (preset != presets.end()) {
        if (cb)
          cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(),
             cb_data);
        InjectNotifyReadPresetResponse(conn_id, address, handle, *preset,
                                       indicate, true);
      } else {
    while (preset == presets.end() &&
           index++ <= ::le_audio::has::kMaxNumOfPresets) {
      preset = presets.find(index);
    }

    if (preset == presets.end()) {
      /* operation not possible */
      if (cb)
        cb(conn_id, (tGATT_STATUS)0x83, handle, value.size(), value.data(),
           cb_data);

      return;
    }

    if (cb)
      cb(conn_id, GATT_SUCCESS, handle, value.size(), value.data(), cb_data);
    /* Notify presets */
    int num_of_notif = 1;
    while (1) {
      bool last =
          preset == std::prev(presets.end()) || num_of_notif == num_of_indices;
      InjectNotifyReadPresetResponse(conn_id, address, handle, *preset,
                                     indicate, (last));
      if (last) return;

      num_of_notif++;
      preset++;
    }
  }

@@ -3023,8 +3024,7 @@ TEST_F(HasTypesTest, test_group_op_coordinator_init) {
  EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1);
  HasCtpGroupOpCoordinator wrapper(
      {address1, address2},
      HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESET_BY_INDEX,
               6));
      HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESETS, 6));
  ASSERT_EQ(2u, wrapper.ref_cnt);

  EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(1);
@@ -3043,12 +3043,10 @@ TEST_F(HasTypesTest, test_group_op_coordinator_copy) {
  EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1);
  HasCtpGroupOpCoordinator wrapper(
      {address1, address2},
      HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESET_BY_INDEX,
               6));
      HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESETS, 6));
  HasCtpGroupOpCoordinator wrapper2(
      {address1},
      HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESET_BY_INDEX,
               6));
      HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESETS, 6));
  ASSERT_EQ(3u, wrapper.ref_cnt);
  HasCtpGroupOpCoordinator wrapper3 = wrapper2;
  auto* wrapper4 =
@@ -3076,12 +3074,10 @@ TEST_F(HasTypesTest, test_group_op_coordinator_completion) {
  EXPECT_CALL(*AlarmMock::Get(), AlarmNew(_)).Times(1);
  HasCtpGroupOpCoordinator wrapper(
      {address1, address3},
      HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESET_BY_INDEX,
               6));
      HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESETS, 6));
  HasCtpGroupOpCoordinator wrapper2(
      {address2},
      HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESET_BY_INDEX,
               6));
      HasCtpOp(0x01, ::le_audio::has::PresetCtpOpcode::READ_PRESETS, 6));
  ASSERT_EQ(3u, wrapper.ref_cnt);

  EXPECT_CALL(*AlarmMock::Get(), AlarmFree(_)).Times(0);
+5 −6
Original line number Diff line number Diff line
@@ -138,14 +138,14 @@ std::vector<uint8_t> HasCtpOp::ToCharacteristicValue() const {
  auto* pp = value.data();

  switch (opcode) {
    case PresetCtpOpcode::READ_ALL_PRESETS:
      value.resize(1);
    case PresetCtpOpcode::READ_PRESETS:
      value.resize(3);
      pp = value.data();
      UINT8_TO_STREAM(
          pp, static_cast<std::underlying_type_t<PresetCtpOpcode>>(opcode));
      UINT8_TO_STREAM(pp, index);
      UINT8_TO_STREAM(pp, num_of_indices);
      break;

    case PresetCtpOpcode::READ_PRESET_BY_INDEX:
    case PresetCtpOpcode::SET_ACTIVE_PRESET:
    case PresetCtpOpcode::SET_ACTIVE_PRESET_SYNC:
      value.resize(2);
@@ -206,8 +206,7 @@ std::ostream& operator<<(std::ostream& out, const PresetCtpChangeId value) {
std::ostream& operator<<(std::ostream& out, const PresetCtpOpcode value) {
  const char* ch = 0;
  switch (value) {
    CASE_SET_PTR_TO_TOKEN_STR(PresetCtpOpcode::READ_ALL_PRESETS);
    CASE_SET_PTR_TO_TOKEN_STR(PresetCtpOpcode::READ_PRESET_BY_INDEX);
    CASE_SET_PTR_TO_TOKEN_STR(PresetCtpOpcode::READ_PRESETS);
    CASE_SET_PTR_TO_TOKEN_STR(PresetCtpOpcode::READ_PRESET_RESPONSE);
    CASE_SET_PTR_TO_TOKEN_STR(PresetCtpOpcode::PRESET_CHANGED);
    CASE_SET_PTR_TO_TOKEN_STR(PresetCtpOpcode::WRITE_PRESET_NAME);
+9 −5
Original line number Diff line number Diff line
@@ -41,8 +41,7 @@ std::ostream& operator<<(std::ostream& out, const PresetCtpChangeId value);

/* HAS control point Opcodes */
enum class PresetCtpOpcode : uint8_t {
  READ_ALL_PRESETS = 0,
  READ_PRESET_BY_INDEX,
  READ_PRESETS = 1,
  READ_PRESET_RESPONSE,
  PRESET_CHANGED,
  WRITE_PRESET_NAME,
@@ -67,8 +66,7 @@ static constexpr uint16_t PresetCtpOpcode2Bitmask(PresetCtpOpcode op) {

/* Mandatory opcodes if control point characteristic exists */
static constexpr uint16_t kControlPointMandatoryOpcodesBitmask =
    PresetCtpOpcode2Bitmask(PresetCtpOpcode::READ_ALL_PRESETS) |
    PresetCtpOpcode2Bitmask(PresetCtpOpcode::READ_PRESET_BY_INDEX) |
    PresetCtpOpcode2Bitmask(PresetCtpOpcode::READ_PRESETS) |
    PresetCtpOpcode2Bitmask(PresetCtpOpcode::SET_ACTIVE_PRESET) |
    PresetCtpOpcode2Bitmask(PresetCtpOpcode::SET_NEXT_PRESET) |
    PresetCtpOpcode2Bitmask(PresetCtpOpcode::SET_PREV_PRESET);
@@ -100,13 +98,19 @@ struct HasCtpOp {
  std::variant<RawAddress, int> addr_or_group;
  PresetCtpOpcode opcode;
  uint8_t index;
  uint8_t num_of_indices;
  std::optional<std::string> name;
  uint16_t op_id;

  HasCtpOp(std::variant<RawAddress, int> addr_or_group_id, PresetCtpOpcode op,
           uint8_t index = bluetooth::has::kHasPresetIndexInvalid,
           uint8_t num_of_indices = 1,
           std::optional<std::string> name = std::nullopt)
      : addr_or_group(addr_or_group_id), opcode(op), index(index), name(name) {
      : addr_or_group(addr_or_group_id),
        opcode(op),
        index(index),
        num_of_indices(num_of_indices),
        name(name) {
    /* Skip 0 on roll-over */
    last_op_id_ += 1;
    if (last_op_id_ == 0) last_op_id_ = 1;
+6 −4
Original line number Diff line number Diff line
@@ -70,15 +70,17 @@ union HasGattOpContext {
static_assert(sizeof(HasGattOpContext) <= sizeof(void*));

/* Service UUIDs */
/* FIXME: actually these were not yet assigned - using placeholders for now. */
static const bluetooth::Uuid kUuidHearingAccessService =
    bluetooth::Uuid::From16Bit(0x1854);
static const bluetooth::Uuid kUuidHearingAidFeatures =
    bluetooth::Uuid::From16Bit(0xEEED);
    bluetooth::Uuid::From16Bit(0x2BDA);
static const bluetooth::Uuid kUuidHearingAidPresetControlPoint =
    bluetooth::Uuid::From16Bit(0xEEEC);
    bluetooth::Uuid::From16Bit(0x2BDB);
static const bluetooth::Uuid kUuidActivePresetIndex =
    bluetooth::Uuid::From16Bit(0xEEEB);
    bluetooth::Uuid::From16Bit(0x2BDC);

static const uint8_t kStartPresetIndex = 1;
static const uint8_t kMaxNumOfPresets = 255;

/* Base device class for the GATT-based service clients */
class GattServiceDevice {