Esempio n. 1
0
/*
 * Handle a DUB collision.
 */
void DiscoveryAgent::HandleCollision() {
  UIDRange *range = m_uid_ranges.top();
  UID lower_uid = range->lower;
  UID upper_uid = range->upper;

  if (lower_uid == upper_uid) {
    range->failures++;
    OLA_WARN << "End of tree reached!!!";
    SendDiscovery();
    return;
  }

  // work out the mid point
  uint64_t lower = ((static_cast<uint64_t>(lower_uid.ManufacturerId()) << 32) +
                    lower_uid.DeviceId());
  uint64_t upper = ((static_cast<uint64_t>(upper_uid.ManufacturerId()) << 32) +
                    upper_uid.DeviceId());
  uint64_t mid = (lower + upper) / 2;
  UID mid_uid(mid >> 32, mid);
  mid++;
  UID mid_plus_one_uid(mid >> 32, mid);
  OLA_INFO << "Collision, splitting into: " << lower_uid << " - " << mid_uid
           << " , " << mid_plus_one_uid << " - " << upper_uid;

  range->uids_discovered = 0;
  // add both ranges to the stack
  m_uid_ranges.push(new UIDRange(lower_uid, mid_uid, range));
  m_uid_ranges.push(new UIDRange(mid_plus_one_uid, upper_uid, range));
  SendDiscovery();
}
Esempio n. 2
0
/*
 * Send a Discovery Unique Branch request.
 */
void DiscoveryAgent::SendDiscovery() {
  if (m_uid_ranges.empty()) {
    // we're hit the end of the stack, now we're done
    if (m_on_complete) {
      m_on_complete->Run(!m_tree_corrupt, m_uids);
      m_on_complete = NULL;
    } else {
      OLA_WARN << "Discovery complete but no callback";
    }
    return;
  }
  UIDRange *range = m_uid_ranges.top();
  if (range->uids_discovered == 0) {
    range->attempt++;
  }

  if (range->failures == MAX_BRANCH_FAILURES ||
      range->attempt == MAX_EMPTY_BRANCH_ATTEMPTS ||
      range->branch_corrupt) {
    // limit reached, move on to the next branch
    OLA_DEBUG << "Hit failure limit for (" << range->lower << ", "
              << range->upper << ")";
    if (range->parent)
      range->parent->branch_corrupt = true;
    FreeCurrentRange();
    SendDiscovery();
  } else {
    OLA_DEBUG << "DUB " << range->lower << " - " << range->upper
              << ", attempt " << range->attempt << ", uids found: "
              << range->uids_discovered << ", failures " << range->failures
              << ", corrupted " << range->branch_corrupt;
    m_target->Branch(range->lower, range->upper, m_branch_callback.get());
  }
}
Esempio n. 3
0
/*
 * If we're in incremental mode, mute previously discovered devices. Otherwise
 * proceed to the branch stage.
 */
void DiscoveryAgent::MaybeMuteNextDevice() {
  if (m_uids_to_mute.empty()) {
    SendDiscovery();
  } else {
    m_muting_uid = m_uids_to_mute.front();
    m_uids_to_mute.pop();
    OLA_DEBUG << "Muting previously discovered responder: " << m_muting_uid;
    m_target->MuteDevice(m_muting_uid, m_incremental_mute_callback.get());
  }
}
Esempio n. 4
0
/*
 * Called when we successful mute a device during the branch stage.
 */
void DiscoveryAgent::BranchMuteComplete(bool status) {
  m_mute_attempts++;
  if (status) {
    m_uids.AddUID(m_muting_uid);
    m_uid_ranges.top()->uids_discovered++;
  } else {
    // failed to mute, if we haven't reached the limit try it again
    if (m_mute_attempts < MAX_MUTE_ATTEMPTS) {
      OLA_INFO << "Muting " << m_muting_uid;
      m_target->MuteDevice(m_muting_uid, m_branch_mute_callback.get());
      return;
    } else {
      // this UID is bad, either it was a phantom or it doesn't response to
      // mute commands
      OLA_INFO << m_muting_uid << " didn't respond to MUTE, marking as bad";
      m_bad_uids.AddUID(m_muting_uid);
    }
  }
  SendDiscovery();
}
Esempio n. 5
0
/*
 * Handle a DUB response (inc. timeouts).
 * @param data the raw response, excluding the start code
 * @param length the length of the response, 0 if no response was received.
 */
void DiscoveryAgent::BranchComplete(const uint8_t *data, unsigned int length) {
  OLA_INFO << "BranchComplete, got " << length;
  if (length == 0) {
    // timeout
    if (!m_uid_ranges.empty()) {
      FreeCurrentRange();
    }
    SendDiscovery();
    return;
  }

  // Must at least have the separator, the EUID and the checksum
  if (length < 1 + EUID_SIZE + CHECKSUM_SIZE) {
    HandleCollision();
    return;
  }

  unsigned int offset = 0;
  while (data[offset] != PREAMBLE_SEPARATOR && offset < PREAMBLE_SIZE - 1) {
    if (data[offset] != PREAMBLE) {
      OLA_INFO << "Preamble " << offset << " " << strings::ToHex(data[offset]);
      HandleCollision();
      return;
    }
    offset++;
  }

  if (data[offset] != PREAMBLE_SEPARATOR) {
    OLA_INFO << "Preamble separator" << offset << " "
             << strings::ToHex(data[offset]);
    HandleCollision();
    return;
  }

  offset++;
  unsigned int remaining = length - offset;
  if (remaining < EUID_SIZE + CHECKSUM_SIZE) {
    OLA_INFO << "Insufficient data remaining, was " << remaining;
    HandleCollision();
    return;
  }

  typedef struct {
    uint8_t euid11;
    uint8_t euid10;
    uint8_t euid9;
    uint8_t euid8;
    uint8_t euid7;
    uint8_t euid6;
    uint8_t euid5;
    uint8_t euid4;
    uint8_t euid3;
    uint8_t euid2;
    uint8_t euid1;
    uint8_t euid0;
    uint8_t ecs3;
    uint8_t ecs2;
    uint8_t ecs1;
    uint8_t ecs0;
  } dub_response_structure;

  const dub_response_structure *response =
      reinterpret_cast<const dub_response_structure*>(data + offset);

  uint16_t calculated_checksum = 0;
  for (unsigned int i = offset; i < offset + EUID_SIZE; i++) {
    calculated_checksum += data[i];
  }

  uint16_t recovered_checksum = JoinUInt8((response->ecs3 & response->ecs2),
                                          (response->ecs1 & response->ecs0));

  if (recovered_checksum != calculated_checksum) {
    OLA_INFO << "Recovered checksum: " << recovered_checksum << " != "
             << "calculated checksum: " << calculated_checksum;
    HandleCollision();
    return;
  }

  // ok this is a valid response
  uint16_t manufacturer_id = JoinUInt8((response->euid11 & response->euid10),
                                       (response->euid9 & response->euid8));
  uint32_t device_id = JoinUInt8((response->euid7 & response->euid6),
                                 (response->euid5 & response->euid4),
                                 (response->euid3 & response->euid2),
                                 (response->euid1 & response->euid0));

  UIDRange *range = m_uid_ranges.top();

  // we store this as an instance variable so we don't have to create a new
  // callback each time.
  UID located_uid = UID(manufacturer_id, device_id);
  if (m_uids.Contains(located_uid)) {
    OLA_WARN << "Previous muted responder " << located_uid
             << " continues to respond";
    range->failures++;
    // ignore this and continue on to the next branch.
    SendDiscovery();
  } else if (m_bad_uids.Contains(located_uid)) {
    // we've already tried this one
    range->failures++;
    SendDiscovery();
  } else {
    m_muting_uid = located_uid;
    m_mute_attempts = 0;
    OLA_INFO << "Muting " << m_muting_uid;
    m_target->MuteDevice(m_muting_uid, m_branch_mute_callback.get());
  }
}
Esempio n. 6
0
/**
 * Called when we get a response (or timeout) to a branch request.
 * @param data the raw response, excluding the start code
 * @param length the length of the response, 0 if no response was received.
 */
void DiscoveryAgent::BranchComplete(const uint8_t *data, unsigned int length) {
  if (length == 0) {
    // timeout
    FreeCurrentRange();
    SendDiscovery();
    return;
  }

  if (length < MIN_DUB_RESPONSE_SIZE || length > MAX_DUB_RESPONSE_SIZE) {
    HandleCollision();
    return;
  }

  unsigned int preamble_size = length - MIN_DUB_RESPONSE_SIZE;
  for (unsigned int i = 0; i < preamble_size; i++) {
    if (data[i] != 0xfe) {
      OLA_INFO << "preamble " << i << " " << std::hex <<
        static_cast<int>(data[i]);
      HandleCollision();
      return;
    }
  }

  unsigned int offset = preamble_size;
  if (data[offset++] != 0xaa) {
    OLA_INFO << "preamble separator is " << std::hex <<
      static_cast<int>(data[offset]);
    HandleCollision();
    return;
  }

  typedef struct {
    uint8_t euid11;
    uint8_t euid10;
    uint8_t euid9;
    uint8_t euid8;
    uint8_t euid7;
    uint8_t euid6;
    uint8_t euid5;
    uint8_t euid4;
    uint8_t euid3;
    uint8_t euid2;
    uint8_t euid1;
    uint8_t euid0;
    uint8_t ecs3;
    uint8_t ecs2;
    uint8_t ecs1;
    uint8_t ecs0;
  } dub_response_structure;

  const dub_response_structure *response =
      reinterpret_cast<const dub_response_structure*>(data + offset);

  uint16_t calculated_checksum = 0;
  for (unsigned int i = offset; i < offset + 12; i++)
    calculated_checksum += data[i];

  uint16_t recovered_checksum =
    ((response->ecs3 & response->ecs2) << 8) +
    (response->ecs1 & response->ecs0);

  if (recovered_checksum != calculated_checksum) {
    OLA_INFO << "recovered checksum: " << recovered_checksum << " != " <<
      "calculated checksum: " << calculated_checksum;
    HandleCollision();
    return;
  }

  // ok this is a valid response
  uint16_t manufacturer_id =
    ((response->euid11 & response->euid10) << 8) +
    (response->euid9 & response->euid8);
  uint32_t device_id =
    ((response->euid7 & response->euid6) << 24) +
    ((response->euid5 & response->euid4) << 16) +
    ((response->euid3 & response->euid2) << 8) +
    (response->euid1 & response->euid0);

  UIDRange *range = m_uid_ranges.top();

  // we store this as an instance variable so we don't have to create a new
  // callback each time.
  UID located_uid = UID(manufacturer_id, device_id);
  if (m_uids.Contains(located_uid)) {
    OLA_WARN << "Previous muted responder " << located_uid <<
      " continues to respond";
    range->failures++;
    // ignore this and continue on to the next branch.
    SendDiscovery();
  } else if (m_bad_uids.Contains(located_uid)) {
    // we've already tried this one
    range->failures++;
    SendDiscovery();
  } else {
    m_muting_uid = located_uid;
    m_mute_attempts = 0;
    OLA_INFO << "muting " << m_muting_uid;
    m_target->MuteDevice(m_muting_uid, m_branch_mute_callback);
  }
}