Skip to main content

bluetooth.startscan(callback)

Causes the imp004m to begin scanning for GAP advertisements

Availability

Device (from impOS™ 38)

Parameters

Name Type Description
callback Function A function to process any detected advertising data

Returns

Nothing

Description

This method initiates scanning and registers a function that will be called when the imp004m detects an advertisement signal.

The callback function has a single parameter of its own, adverts, into which an array of detected advertisements is passed. Each advert is a table with the following keys:

Key Type Description
type Integer The type of advertisement detected (see below)
rssi Integer The signal strength (-127 to 20) of the received data in dBm
address String The peer’s address as a 12-character hexadecimal string
addresstype Integer 0 if the address is public, 1 if the address is random
data Blob The raw data received. Up to 31 bytes in length
time Integer The time of receipt by impOS, as an integer millisecond time against the same clock as hardware.millis()
rule Integer The index (integer, zero-based) of the filter that allowed this advert. This is intended to both assist debugging of rules, and to allow Squirrel to fast-path adverts which match a certain rule (see bluetooth.setscanfilter() examples). This will be zero if the default accept-all filter is in use.

impOS™ will add as many advertisements to the adverts array as it can but will not add latency to achieve this.

impOS doesn’t interpret or validate the raw advertisement data (provided as data in the advert table) in any way other than to cap the length at the specified 31 bytes. Specifically, data is not guaranteed to contain syntactically valid advertising or scan data. Your application code should therefore take great care when parsing data.

Typically, a user will want to process advertising and scan response packets together; your application is responsible for mapping advertisement to scan response.

Advertisement Type Constants

Bluetooth Constant Value Description
ADV_IND 0 Connectable undirected advertisement
ADV_DIRECT_IND 1 Connectable directed advertisement
ADV_SCAN_IND 2 Scannable undirected advertisement
ADV_NONCONN_IND 3 Non-connectable undirected advertisement
SCAN_RSP 4 Scan response

Note These constants are not defined in Squirrel — please use the integer value in comparisons.

Example Code

Scan for iBeacons and save each in a table as they are found.

// Beacons
beacons <- [];

function hti(hs) {
  if (hs.slice(0, 2) == "0x") hs = hs.slice(2);
  local i = 0;
  foreach (c in hs) {
    local n = c - '0';
    if (n > 9) n = ((n & 0x1F) - 7);
    i = (i << 4) + n;
  }
  return i;
}

function addBeacon(beacon) {
  beacons.append(beacon);
  local uuid = beacon.uuid.slice(0,8) + "-" + beacon.uuid.slice(8,12) + "-" + 
    beacon.uuid.slice(12,16) + "-" + beacon.uuid.slice(16,20) + "-" + beacon.uuid.slice(20);
  server.log("Beacon found: " + uuid + " (Major: " + beacon.majorValue + " Minor: " + beacon.minorValue + ")");
}

server.log("Scanning...");
bt.setscanparams(false, 100, 100);
bt.setscanfilter([{ "type" : 3,
                    "data" : "\x02\x01\x1A\x1A\xFF\x4C\x00\x02\x15" }]);
bt.startscan(function(adverts) {
  foreach (advert in adverts) {
    // Convert payload to hex string
    local payload = "";

    for (local i = 0 ; i < advert.data.len() ; i++) {
      payload = payload + format("%02x", advert.data[i]);
    }

    // We're filtering out non-iBeacons using setscanfilter()
    // So just record this one
    local beacon = {};
    beacon.uuid <- payload.slice(18, 50);
    beacon.majorString <- payload.slice(50, 54);
    beacon.majorValue <- (hti(beacon.majorString.slice(0, 2)) * 256 + hti(beacon.majorString.slice(2)));
    beacon.minorString <- payload.slice(54, 58);
    beacon.minorValue <- (hti(beacon.minorString.slice(0, 2)) * 256 + hti(beacon.minorString.slice(2)));

    if (beacons.len() > 0) {
      local got = false;

      foreach (aBeacon in beacons) {
        if (aBeacon.uuid == beacon.uuid && aBeacon.majorValue == beacon.majorValue 
            && aBeacon.minorValue == beacon.minorValue) {
          got = true;
          break;
        }
      }

      if (!got) addBeacon(beacon);
    } else {
      addBeacon(beacon);
    }
  }
});