예제 #1
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());
  }
}
예제 #2
0
/*
 * Start the discovery process
 * @param on_complete the callback to run when discovery completes
 * @param incremental true if this is incremental, false otherwise
 */
void DiscoveryAgent::InitDiscovery(
    DiscoveryCompleteCallback *on_complete,
    bool incremental) {
  if (m_on_complete) {
    OLA_WARN << "Discovery procedure already running";
    UIDSet uids;
    on_complete->Run(false, uids);
    return;
  }
  m_on_complete = on_complete;

  // this should be empty, but clear it out anyway
  while (!m_uids_to_mute.empty()) {
    m_uids_to_mute.pop();
  }

  // this should also be empty
  while (!m_uid_ranges.empty()) {
    FreeCurrentRange();
  }

  if (incremental) {
    UIDSet::Iterator iter = m_uids.Begin();
    for (; iter != m_uids.End(); ++iter) {
      m_uids_to_mute.push(*iter);
    }
  } else {
    m_uids.Clear();
  }

  m_bad_uids.Clear();
  m_tree_corrupt = false;

  // push the first range on to the branch stack
  UID lower(0, 0);
  m_uid_ranges.push(new UIDRange(lower, UID::AllDevices(), NULL));

  m_unmute_count = 0;
  m_target->UnMuteAll(m_unmute_callback.get());
}
예제 #3
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());
  }
}
예제 #4
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);
  }
}