/** * @brief Start low energy scan * * @param device_id * * @return */ static int start_lescan(int device_id) { int device_handle = 0; if((device_handle = hci_open_dev(device_id)) < 0) { perror("Could not open device"); return -1; } uint8_t filter_policy = 0x00; uint16_t interval = htobs(0x0010); uint16_t window = htobs(0x0010); int err = hci_le_set_scan_parameters(device_handle, 0x01, interval, window, 0x00, filter_policy, 1000); if (err < 0) { perror("Set scan parameters failed"); return -1; } err = hci_le_set_scan_enable(device_handle, 0x01, 0, 1000); if (err < 0) { perror("Enable scan failed"); return -1; } return device_handle; }
int main(int argc, char **argv) { int dev_id; int err, opt, dd; uint8_t own_type = 0x00; uint8_t scan_type = 0x01; uint8_t filter_type = 0; uint8_t filter_policy = 0x00; uint16_t interval = htobs(0x0010); uint16_t window = htobs(0x0010); // uint8_t filter_dup = 1; uint8_t filter_dup = 0; // don't filter duplicate dev_id = hci_get_route(NULL); dd = hci_open_dev( dev_id ); if (dev_id < 0 || dd < 0) { perror("opening socket"); exit(1); } err = hci_le_set_scan_parameters(dd, scan_type, interval, window, own_type, filter_policy, 1000); if (err < 0) { perror("Set scan parameters failed"); } err = hci_le_set_scan_enable(dd, 0x01, filter_dup, 1000); if (err < 0) { perror("Enable scan failed"); exit(1); } printf("LE Scan ... \n"); err = print_advertising_devices(dd, filter_type); if (err < 0) { perror("Could not receive advertising events"); exit(1); } err = hci_le_set_scan_enable(dd, 0x00, filter_dup, 1000); if (err < 0) { perror("Disable scan failed"); exit(1); } hci_close_dev(dd); return 0; }
VALUE method_scan(int argc, VALUE *argv, VALUE klass) { VALUE rb_device_id; int device_id; int device_handle; uint8_t scan_type = 0x01; //passive uint8_t own_type = 0x00; // I think this specifies not to use a random MAC uint8_t filter_dups = 0x00; uint8_t filter_policy = 0x00; // ? uint16_t interval = htobs(0x0005); uint16_t window = htobs(0x0005); struct hci_filter new_filter; socklen_t filter_size; // which device was specified? rb_scan_args(argc, argv, "01", &rb_device_id); if (rb_device_id == Qnil) { device_id = hci_get_route(NULL); } else { device_id = NUM2INT(rb_device_id); } // open the device if ( (device_handle = hci_open_dev(device_id)) < 0) { rb_raise(rb_eException, "Could not open device"); } device_handles[device_id] = device_handle; // save the old filter so we can restore it later filter_size = sizeof(stored_filters[0]); if (getsockopt(device_handle, SOL_HCI, HCI_FILTER, &stored_filters[device_id], &filter_size) < 0) { rb_raise(rb_eException, "Could not get socket options"); } // new filter to only look for event packets hci_filter_clear(&new_filter); hci_filter_set_ptype(HCI_EVENT_PKT, &new_filter); hci_filter_set_event(EVT_LE_META_EVENT, &new_filter); if (setsockopt(device_handle, SOL_HCI, HCI_FILTER, &new_filter, sizeof(new_filter)) < 0) { rb_raise(rb_eException, "Could not set socket options"); } // set the params hci_le_set_scan_parameters(device_handle, scan_type, interval, window, own_type, filter_policy, 1000); hci_le_set_scan_enable(device_handle, 0x01, filter_dups, 1000); // perform the scan and make sure device gets put back into a proper state // even in the case of being interrupted by a ruby exception rb_ensure(perform_scan, INT2FIX(device_id), stop_scan, INT2FIX(device_id)); return Qnil; }
void Bluetooth::scanStart() { int stat; const int TIMEOUT = 1000; stat = hci_le_set_scan_parameters(_sock, 0x01, htobs(0x0010), htobs(0x0010), 0x00, 0x00, TIMEOUT); if (stat < 0) { printf("ERROR hci_le_set_scan_parameters\n"); return; } stat = hci_le_set_scan_enable(_sock, 1, 1, TIMEOUT); if (stat < 0) { printf("ERROR hci_le_set_scan_enable\n"); return; } }
void start_hci_scan(struct hci_state current_hci_state) { if(hci_le_set_scan_parameters(current_hci_state.device_handle, 0x01, htobs(0x0010), htobs(0x0010), 0x00, 0x00, 1000) < 0) { current_hci_state.has_error = TRUE; snprintf(current_hci_state.error_message, sizeof(current_hci_state.error_message), "Failed to set scan parameters: %s", strerror(errno)); return; } if(hci_le_set_scan_enable(current_hci_state.device_handle, 0x01, 1, 1000) < 0) { current_hci_state.has_error = TRUE; snprintf(current_hci_state.error_message, sizeof(current_hci_state.error_message), "Failed to enable scan: %s", strerror(errno)); return; } current_hci_state.state = HCI_STATE_SCANNING; // Save the current HCI filter socklen_t olen = sizeof(current_hci_state.original_filter); if(getsockopt(current_hci_state.device_handle, SOL_HCI, HCI_FILTER, ¤t_hci_state.original_filter, &olen) < 0) { current_hci_state.has_error = TRUE; snprintf(current_hci_state.error_message, sizeof(current_hci_state.error_message), "Could not get socket options: %s", strerror(errno)); return; } // Create and set the new filter struct hci_filter new_filter; hci_filter_clear(&new_filter); hci_filter_set_ptype(HCI_EVENT_PKT, &new_filter); hci_filter_set_event(EVT_LE_META_EVENT, &new_filter); if(setsockopt(current_hci_state.device_handle, SOL_HCI, HCI_FILTER, &new_filter, sizeof(new_filter)) < 0) { current_hci_state.has_error = TRUE; snprintf(current_hci_state.error_message, sizeof(current_hci_state.error_message), "Could not set socket options: %s", strerror(errno)); return; } current_hci_state.state = HCI_STATE_FILTERING; }
static int ble_scan_enable(int device_desc) { uint16_t interval = htobs(DISCOV_LE_SCAN_INT); uint16_t window = htobs(DISCOV_LE_SCAN_WIN); uint8_t own_address_type = 0x00; uint8_t filter_policy = 0x00; int ret = hci_le_set_scan_parameters(device_desc, LE_SCAN_ACTIVE, interval, window, own_address_type, filter_policy, 10000); if (ret < 0) { fprintf(stderr, "ERROR: Set scan parameters failed (are you root?).\n"); return 1; } ret = hci_le_set_scan_enable(device_desc, 0x01, 1, 10000); if (ret < 0) { fprintf(stderr, "ERROR: Enable scan failed.\n"); return 1; } return 0; }
int do_lescan() { int dev_id, sock; int ret; if (!strncmp(g_src, "hci", 3)) dev_id = atoi(g_src + 3); else dev_id = hci_get_route(NULL); sock = hci_open_dev(dev_id); if (dev_id < 0 || sock < 0) { perror("opening socket"); exit(1); } uint8_t own_type = 0x00; uint16_t interval = htobs(0x0012); uint16_t window = htobs(0x0012); uint8_t scan_type = 0x01; uint8_t filter_dup = 1; uint8_t filter_type = 0; ret = hci_le_set_scan_parameters(sock, scan_type, interval, window, own_type, 0x00, 1000); if (ret) { perror("hci_le_set_scan_parameters"); exit(1); } ret = hci_le_set_scan_enable(sock, 0x01, filter_dup, 1000); if (ret) { perror("hci_le_set_scan_enable"); exit(1); } print_advertising_devices(sock, filter_type); ret = hci_le_set_scan_enable(sock, 0x00, filter_dup, 1000); close(sock); return 0; }
char *hci_LE_get_RSSI(hci_socket_t *hci_socket, hci_controller_t *hci_controller, int8_t *file_descriptor, bt_address_t *mac, uint16_t max_rsp, uint8_t scan_type, uint16_t scan_interval, uint16_t scan_window, uint8_t own_add_type, uint8_t scan_filter_policy) { if (!hci_controller) { print_trace(TRACE_ERROR, "hci_LE_get_RSSI : invalid controller reference.\n"); return NULL; } if (hci_controller->interrupted) { hci_resolve_interruption(hci_socket, hci_controller); } if (hci_controller->state != HCI_STATE_OPEN) { print_trace(TRACE_ERROR, "hci_LE_get_RSSI : busy or closed controller.\n"); return NULL; } // Resulting string : char *res = NULL; FILE *file = NULL; print_trace(TRACE_INFO, "1. Opening socket..."); char new_socket = 0; char socket_err = 0; check_hci_socket_ptr(&hci_socket, hci_controller, &new_socket, &socket_err); if (socket_err) { return NULL; } print_trace(TRACE_INFO, " [DONE]\n"); struct pollfd p; // Initializing the connection poll on our HCI socket : p.fd = hci_socket->sock; p.events = POLLIN; unsigned char buf[HCI_MAX_EVENT_SIZE]; hci_event_hdr event_header; unsigned char *event_parameter; struct hci_filter flt; struct hci_filter old_flt; // Creating our filter : hci_compute_filter(&flt, EVT_CMD_COMPLETE, EVT_LE_META_EVENT, EVT_LE_ADVERTISING_REPORT, 0); //hci_filter_all_events(&flt); /* Saving the old filter. This can be helpful in a case where we want to use a same socket for different purposes (even with multiple threads), we can replace the old filter and re-use it later. */ print_trace(TRACE_INFO, "2. Saving old filter..."); char saved_flt = 1; if (!new_socket) { if (get_hci_socket_filter(*hci_socket, &old_flt) < 0) { saved_flt = 0; } } print_trace(TRACE_INFO, " [DONE]\n"); // Applying the new filter : print_trace(TRACE_INFO, "3. Applying new filter..."); if (set_hci_socket_filter(*hci_socket, &flt) < 0) { goto end; } print_trace(TRACE_INFO, " [DONE]\n"); print_trace(TRACE_INFO, "4. Setting scan parameters..."); hci_change_state(hci_controller, HCI_STATE_WRITING); pthread_mutex_lock(&hci_controller_mutex); if (hci_le_set_scan_parameters(hci_socket->sock, scan_type, scan_interval, // cf p 1066 spec scan_window, own_add_type, scan_filter_policy, 2*HCI_CONTROLLER_DEFAULT_TIMEOUT) < 0) { // last parameter is timeout (for reaching the controler) 0 = infinity. print_trace(TRACE_ERROR, " [ERROR] \n"); perror("set_scan_parameters"); goto end; } print_trace(TRACE_INFO, " [DONE]\n"); hci_change_state(hci_controller, HCI_STATE_OPEN); pthread_mutex_unlock(&hci_controller_mutex); print_trace(TRACE_INFO, "5. Enabling scan..."); pthread_mutex_lock(&hci_controller_mutex); hci_change_state(hci_controller, HCI_STATE_SCANNING); if (hci_le_set_scan_enable(hci_socket->sock, htobs(0x01), htobs(0x00), 2*HCI_CONTROLLER_DEFAULT_TIMEOUT) < 0) { // Duplicate filtering ? (cf p1069) print_trace(TRACE_ERROR, " [ERROR] \n"); perror("set_scan_enable"); goto end; } print_trace(TRACE_INFO, " [DONE]\n"); pthread_mutex_unlock(&hci_controller_mutex); char canceled = 0; int k = 0; print_trace(TRACE_INFO, "6. Checking response events...\n"); int8_t n = 0; int16_t len = 0; res = calloc(6*max_rsp, sizeof(char)); res[0] = '\0'; while(!canceled && (!(max_rsp > 0) || (k < max_rsp))) { p.revents = 0; n = 0; len = 0; // Polling the BT device for an event : while ((n = poll(&p, 1, 5000)) < 0) { if (errno == EAGAIN || EINTR) { continue; } perror("hci_LE_get_RSSI : error while polling the socket"); canceled = 1; } if (canceled) { break; } if (!n) { errno = ETIMEDOUT; perror("hci_LE_get_RSSI : error while polling the socket"); break; } while ((len = read(hci_socket->sock, buf, sizeof(buf))) < 0) { if (errno == EAGAIN || errno == EINTR) continue; perror("hci_LE_get_RSSI : error while reading the socket"); canceled = 1; } if (canceled) { break; } if (len == 0) { print_trace(TRACE_WARNING, "hci_LE_get_RSSI : nothing to read on the socket.\n"); break; } // WHAT IS buf[0] ? Maybe a parameter added by "read()" ??? event_header.evt = buf[1]; event_header.plen = buf[2]; event_parameter = (void *)(buf + HCI_EVENT_HDR_SIZE + 1); uint8_t subevent_code = *(event_parameter); event_parameter = (void *)(event_parameter + 1); int num_reports = *event_parameter; event_parameter = (void *)(event_parameter + 1); switch (event_header.evt) { case EVT_LE_META_EVENT: // Code 0x3E switch (subevent_code) { case EVT_LE_ADVERTISING_REPORT: for (uint16_t i = 0; i < num_reports; i++) { bt_device_t bt_device; // Address field : bt_address_t *rsp_mac = (bt_address_t *)(event_parameter + num_reports*(1+1) + 6*i); // @ on 6 bytes. if (!bt_already_registered_device(*rsp_mac)) { uint8_t *address_type; // Address type field : address_type = (uint8_t *)(event_parameter + 1*num_reports + i); bt_device.mac = *rsp_mac; bt_device.add_type = *address_type; strcpy(bt_device.custom_name, "UNKNOWN"); bt_register_device(bt_device); } else { bt_device = bt_get_device(*rsp_mac); } if (mac != NULL && !(bt_compare_addresses(mac, rsp_mac))) { continue; } // Length_data field : uint8_t *length_data = (uint8_t *)(event_parameter + num_reports*(1+1+6) + i); // RSSI field : int8_t *rssi = (int8_t *)(event_parameter + (1+1+6+1+(*length_data))*num_reports + i); // rssi on 1byte if (*rssi == 127) { print_trace(TRACE_WARNING, "hci_LE_get_rssi : RSSI measure unavailable.\n"); } else if (*rssi >= 21) { print_trace(TRACE_ERROR, "hci_LE_get_rssi : error while reading RSSI measure.\n"); } // Display info : bt_device_display(bt_device); if (file_descriptor && *file_descriptor >= 0) { char rssi_string[RSSI_STRING_LENGTH] = {0}; snprintf(rssi_string, RSSI_STRING_LENGTH, "%i \n", *rssi); if (write(*file_descriptor, rssi_string, RSSI_STRING_LENGTH) < RSSI_STRING_LENGTH) { print_trace(TRACE_WARNING, "Unable to write rssi value into given fd\n"); } } if (file) { fprintf(file, "%i\n", *rssi); } char rssi_string_val[5] = {0}; snprintf(rssi_string_val, 5, "%i ;", *rssi); strcat(res, rssi_string_val); k++; } break; default: print_trace(TRACE_WARNING, "hci_LE_get_rssi : an unknown LE sub-event occured : 0x%X \n", subevent_code); break; } break; default: print_trace(TRACE_WARNING, "hci_LE_get_rssi : an unknown LE sub-event occured : 0x%X \n", subevent_code); break; } } print_trace(TRACE_INFO, "Scan complete !\n"); print_trace(TRACE_INFO, "7. Disabling scan..."); pthread_mutex_lock(&hci_controller_mutex); if (hci_le_set_scan_enable(hci_socket->sock, htobs(0x00), htobs(0x00), 2*HCI_CONTROLLER_DEFAULT_TIMEOUT) < 0) { print_trace(TRACE_ERROR, " [ERROR] \n"); perror("set_scan_disable"); hci_controller->interrupted = 1; goto end; } print_trace(TRACE_INFO, " [DONE]\n"); hci_change_state(hci_controller, HCI_STATE_OPEN); pthread_mutex_unlock(&hci_controller_mutex); end : if (!hci_controller->interrupted) { hci_change_state(hci_controller, HCI_STATE_OPEN); } pthread_mutex_trylock(&hci_controller_mutex); pthread_mutex_unlock(&hci_controller_mutex); if (new_socket) { close_hci_socket(hci_socket); free(hci_socket); } else { // Restoring the old filter : if (saved_flt) { set_hci_socket_filter(*hci_socket, &old_flt); } } if (file) { fclose(file); } return res; }
int main(int argc, const char* argv[]) { char *hciDeviceIdOverride = NULL; int hciDeviceId = 0; int hciSocket; struct hci_dev_info hciDevInfo; struct hci_filter oldHciFilter; struct hci_filter newHciFilter; socklen_t oldHciFilterLen; int previousAdapterState = -1; int currentAdapterState; const char* adapterState = NULL; fd_set rfds; struct timeval tv; int selectRetval; unsigned char hciEventBuf[HCI_MAX_EVENT_SIZE]; int hciEventLen; evt_le_meta_event *leMetaEvent; le_advertising_info *leAdvertisingInfo; char btAddress[18]; int i; int scanning = 0; int8_t rssi; memset(&hciDevInfo, 0x00, sizeof(hciDevInfo)); // setup signal handlers signal(SIGINT, signalHandler); signal(SIGKILL, signalHandler); signal(SIGUSR1, signalHandler); signal(SIGUSR2, signalHandler); signal(SIGHUP, signalHandler); prctl(PR_SET_PDEATHSIG, SIGKILL); // remove buffering setbuf(stdin, NULL); setbuf(stdout, NULL); setbuf(stderr, NULL); hciDeviceIdOverride = getenv("NOBLE_HCI_DEVICE_ID"); if (hciDeviceIdOverride != NULL) { hciDeviceId = atoi(hciDeviceIdOverride); } else { // if no env variable given, use the first available device hciDeviceId = hci_get_route(NULL); } if (hciDeviceId < 0) { hciDeviceId = 0; // use device 0, if device id is invalid } // setup HCI socket hciSocket = hci_open_dev(hciDeviceId); if (hciSocket == -1) { printf("adapterState unsupported\n"); return -1; } hciDevInfo.dev_id = hciDeviceId; // get old HCI filter oldHciFilterLen = sizeof(oldHciFilter); getsockopt(hciSocket, SOL_HCI, HCI_FILTER, &oldHciFilter, &oldHciFilterLen); // setup new HCI filter hci_filter_clear(&newHciFilter); hci_filter_set_ptype(HCI_EVENT_PKT, &newHciFilter); hci_filter_set_event(EVT_LE_META_EVENT, &newHciFilter); setsockopt(hciSocket, SOL_HCI, HCI_FILTER, &newHciFilter, sizeof(newHciFilter)); while(1) { FD_ZERO(&rfds); FD_SET(hciSocket, &rfds); tv.tv_sec = 1; tv.tv_usec = 0; // get HCI dev info for adapter state ioctl(hciSocket, HCIGETDEVINFO, (void *)&hciDevInfo); currentAdapterState = hci_test_bit(HCI_UP, &hciDevInfo.flags); if (previousAdapterState != currentAdapterState) { previousAdapterState = currentAdapterState; if (!currentAdapterState) { adapterState = "poweredOff"; } else if (hci_le_set_scan_parameters(hciSocket, 0x01, htobs(0x0010), htobs(0x0010), 0x00, 0, 1000) < 0) { if (EPERM == errno) { adapterState = "unauthorized"; } else if (EIO == errno) { adapterState = "unsupported"; } else { adapterState = "unknown"; } } else { adapterState = "poweredOn"; } printf("adapterState %s\n", adapterState); } selectRetval = select(hciSocket + 1, &rfds, NULL, NULL, &tv); if (-1 == selectRetval) { if (SIGINT == lastSignal || SIGKILL == lastSignal) { // done break; } else if (SIGUSR1 == lastSignal) { // start scan, filter scanning = 1; hci_le_set_scan_enable(hciSocket, 0x00, 1, 1000); hci_le_set_scan_enable(hciSocket, 0x01, 1, 1000); } else if (SIGUSR2 == lastSignal) { // start scan, no filter scanning = 1; hci_le_set_scan_enable(hciSocket, 0x00, 0, 1000); hci_le_set_scan_enable(hciSocket, 0x01, 0, 1000); } else if (SIGHUP == lastSignal) { // stop scan scanning = 0; hci_le_set_scan_enable(hciSocket, 0x00, 0, 1000); } } else if (selectRetval) { // read event hciEventLen = read(hciSocket, hciEventBuf, sizeof(hciEventBuf)); leMetaEvent = (evt_le_meta_event *)(hciEventBuf + (1 + HCI_EVENT_HDR_SIZE)); hciEventLen -= (1 + HCI_EVENT_HDR_SIZE); if (!scanning) { // ignore, not scanning continue; } if (leMetaEvent->subevent != 0x02) { continue; } leAdvertisingInfo = (le_advertising_info *)(leMetaEvent->data + 1); ba2str(&leAdvertisingInfo->bdaddr, btAddress); printf("event %s,%s,", btAddress, (leAdvertisingInfo->bdaddr_type == LE_PUBLIC_ADDRESS) ? "public" : "random"); for (i = 0; i < leAdvertisingInfo->length; i++) { printf("%02x", leAdvertisingInfo->data[i]); } rssi = *(leAdvertisingInfo->data + leAdvertisingInfo->length); printf(",%d\n", rssi); } } // restore original filter setsockopt(hciSocket, SOL_HCI, HCI_FILTER, &oldHciFilter, sizeof(oldHciFilter)); // disable LE scan hci_le_set_scan_enable(hciSocket, 0x00, 0, 1000); close(hciSocket); return 0; }
static int cmd_lescan(int dev_id) { int hci_dev = 0; int err = 0, opt = 0, dd = 0; uint8_t own_type = 0x00; uint8_t scan_type = 0x01; uint8_t filter_type = 0; uint8_t filter_policy = 0x00; uint8_t filter_dup = 1; uint16_t interval = htobs(0x0010); uint16_t window = htobs(0x0010); if (dev_id < 0) { dev_id = hci_get_route(NULL); } if (dev_id < 0) { return -1; } if((hci_dev = hci_open_dev(dev_id)) < 0) { printf("Opening hci device failed\n"); return -2; } err = hci_le_set_scan_parameters(hci_dev, scan_type, interval, window, own_type, filter_policy, 2000); if (err < 0) { printf("Setting scan parameters failed %d\n", err); return -3; } err = hci_le_set_scan_enable(hci_dev, 0x01, filter_dup, 1000); if (err < 0) { printf("Enabling the scan failed\n"); return -4; } struct sigaction sa; sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = signal_handler; sigaction(SIGINT, &sa, NULL); unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr; int len, sl_no = 0; socklen_t olen = sizeof(old_filter); if (getsockopt(hci_dev, SOL_HCI, HCI_FILTER, &old_filter, &olen) < 0) { printf("getsockopt failed\n"); btcmd_stop_scanning(hci_dev); return -5; } struct hci_filter filter; hci_filter_clear(&filter); hci_filter_set_ptype(HCI_EVENT_PKT, &filter); hci_filter_set_event(EVT_LE_META_EVENT, &filter); if (setsockopt(hci_dev, SOL_HCI, HCI_FILTER, &filter, sizeof(filter)) < 0) { printf("setsockopt failed\n"); btcmd_stop_scanning(hci_dev); return -6; } finish_scanning = 0; while(1) { le_advertising_info *info; evt_le_meta_event *meta; char addr[20]; while ((len = read(hci_dev, buf, sizeof(buf))) < 0) { set_state(STATE_SCANNING); if (errno == EINTR && finish_scanning) { len = 0; goto done; } if (errno == EAGAIN) { continue; } /* anything else, just end the loop */ goto done; } ptr = buf + (1 + HCI_EVENT_HDR_SIZE); len -= (1 + HCI_EVENT_HDR_SIZE); meta = (void *) ptr; if (meta->subevent != 0x02) { goto done; } info = (le_advertising_info *) (meta->data + 1); memset(addr, 0, sizeof(addr)); address2string(&info->bdaddr, addr); /* Socket gives same BT address twice, and we need to eliminate * duplicate entries */ static int duplicate = 0; if (duplicate == 0) { printf("%s\n", addr); duplicate = 1; } else if (duplicate) { duplicate = 0; } } /* while (1) */ done: btcmd_stop_scanning(hci_dev); set_state(STATE_DISCONNECTED); return 0; }