bluez 에서는 bluetooth 4.0의 core(?)를 지원한다고 나와있으나 bluez에서 제공하는 util을 사용해보면
4.0을 스캔하기 위해서는 별도의 스캔 옵션을 주어야 한다.
이말은 4,0 이전 버전과 4.0 버전의 인터페이스가 다르다는 뜻이다.
bluetooth 4.0 디바이스를 검색하기 위해서는
hcitool lescan
을 사용해야한다.
사용해보면 알겠지만 이 방법은 사용자가 종료하기 전까지 무한대기한다.
내부 함수를 살펴보면 read 함수를 호출하는데 블루투스 소켓이기 때문에 서비스가 내려가기 전까지 대기할 수 밖에 없는 구조이다. 이 부분은 차후에 수정할 예정이며 아래는 일단 스캔에 설공한 소스예제이다.
이 역시 hcitool 소스에서 필요한 부분만은 편집한 소스이다.
- #include <stdio.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <fcntl.h>
- #include <sys/param.h>
- #include <sys/ioctl.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <signal.h>
- #include <bluetooth/bluetooth.h>
- #include <bluetooth/hci.h>
- #include <bluetooth/hci_lib.h>
- #include <errno.h>
- #include "textfile.h"
- #include "oui.h"
- #define FLAGS_AD_TYPE 0x01
- #define FLAGS_LIMITED_MODE_BIT 0x01
- #define FLAGS_GENERAL_MODE_BIT 0x02
- #define EIR_FLAGS 0x01
- #define EIR_UUID16_SOME 0x02
- #define EIR_UUID16_ALL 0x03
- #define EIR_UUID32_SOME 0x04
- #define EIR_UUID32_ALL 0x05
- #define EIR_UUID128_SOME 0x06
- #define EIR_UUID128_ALL 0x07
- #define EIR_NAME_SHORT 0x08
- #define EIR_NAME_COMPLETE 0x09
- #define EIR_TX_POWER 0x0A
- #define EIR_DEVICE_ID 0x10
- static volatile int signal_received = 0;
- static int print_advertising_devices(int dd, uint8_t filter_type);
- static void sigint_handler(int sig);
- static int check_report_filter(uint8_t procedure, le_advertising_info *info);
- static int read_flags(uint8_t *flags, const uint8_t *data, size_t size);
- static void eir_parse_name(uint8_t *eir, size_t eir_len, char *buf, size_t buf_len);
- static void eir_parse_name(uint8_t *eir, size_t eir_len, char *buf, size_t buf_len)
- {
- size_t offset;
- offset = 0;
- while(offset < eir_len)
- {
- uint8_t field_len = eir[0];
- size_t name_len;
- if(field_len == 0)
- break;
- if(offset + field_len > eir_len)
- goto failed;
- switch(eir[1])
- {
- case EIR_NAME_SHORT:
- case EIR_NAME_COMPLETE:
- name_len = field_len -1;
- if(name_len > buf_len)
- goto failed;
- memcpy(buf, &eir[2], name_len);
- return ;
- }
- offset += field_len + 1;
- eir += field_len + 1;
- }
- failed:
- snprintf(buf, buf_len,"(unknow)");
- }
- static int read_flags(uint8_t *flags, const uint8_t *data, size_t size)
- {
- size_t offset;
- if(!flags || !data)
- return -EINVAL;
- offset = 0;
- while(offset < size)
- {
- uint8_t len = data[offset];
- uint8_t type;
- if(len == 0)
- break;
- if(len + offset > size)
- break;
- type = data[offset +1];
- if(type == FLAGS_AD_TYPE)
- {
- *flags = data[offset +2];
- return 0;
- }
- offset += 1 + len;
- }
- return -ENOENT;
- }
- static int check_report_filter(uint8_t procedure, le_advertising_info *info)
- {
- printf("report filter..\n");
- uint8_t flags;
- if(procedure == 0)
- return 1;
- printf("read flags...\n");
- if(read_flags(&flags, info->data, info->length))
- return 0;
- switch(procedure)
- {
- case 1:
- if(flags & FLAGS_LIMITED_MODE_BIT)
- return 1;
- break;
- case 'g':
- if(flags & (FLAGS_LIMITED_MODE_BIT | FLAGS_GENERAL_MODE_BIT))
- return 1;
- break;
- default:
- fprintf(stderr, "Unknow discovery procedure\n");
- break;
- }
- return 0;
- }
- static void sigint_handler(int sig)
- {
- signal_received = sig;
- }
- static int print_advertising_devices(int dd, uint8_t filter_type)
- {
- unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr;
- struct hci_filter nf, of;
- struct sigaction sa;
- socklen_t olen;
- int len;
- olen = sizeof(of);
- if(getsockopt(dd, SOL_HCI, HCI_FILTER, &of, &olen) < 0)
- {
- printf("Could not get socket option\n");
- return -1;
- }
- hci_filter_clear(&nf);
- hci_filter_set_ptype(HCI_EVENT_PKT, &nf);
- hci_filter_set_event(EVT_LE_META_EVENT, &nf);
- if(setsockopt(dd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0)
- {
- printf("Could not set socket option\n");
- return -1;
- }
- memset(&sa, 0x00, sizeof(sa));
- sa.sa_flags = SA_NOCLDSTOP;
- sa.sa_handler = sigint_handler;
- sigaction(SIGINT, &sa, NULL);
- while(1)
- {
- evt_le_meta_event *meta;
- le_advertising_info *info;
- char addr[18];
- while( (len = read(dd, buf, sizeof(buf))) < 0 )
- {
- printf("while...\n");
- if(errno == EINTR && signal_received == SIGINT )
- {
- len = 0;
- goto done;
- }
- if( errno == EAGAIN || errno == EINTR )
- continue;
- goto done;
- }
- ptr = buf + (1 + HCI_EVENT_HDR_SIZE);
- len -= (1 + HCI_EVENT_HDR_SIZE);
- meta = (void*) ptr;
- if(meta->subevent != 0x02)
- goto done;
- /* ignoring multiple reports */
- info = (le_advertising_info*) (meta->data + 1);
- if(check_report_filter(filter_type, info))
- {
- char name[30];
- memset(name, 0x00, sizeof(name));
- ba2str(&info->bdaddr, addr);
- eir_parse_name(info->data, info->length, name, sizeof(name)-1);
- printf("%s %s\n",addr, name);
- }
- }
- done:
- setsockopt(dd, SOL_HCI, HCI_FILTER, &of, sizeof(of));
- if(len < 0)
- return -1;
- return 0;
- }
- int main(int argc, char **argv)
- {
- int dev_id,dd;
- int err;
- uint8_t own_type = 0x00;
- uint8_t scan_type = 0x01; // 0x00 passive sacan 0x01 random scan
- uint8_t filter_type = 0;
- uint8_t filter_dup = 1;
- uint16_t interval = htobs(0x0010); // 0x12 none filtering duplicates
- uint16_t window = htobs(0x0010); // same upper
- dev_id = hci_get_route(NULL);
- if(dev_id < 0)
- {
- perror("Could not open device");
- exit(1);
- }
- dd = hci_open_dev(dev_id);
- if(dd < 0)
- {
- perror("Could not open device");
- exit(1);
- }
- interval = htobs(0x0012);
- window = htobs(0x0012);
- err = hci_le_set_scan_parameters(dd, scan_type, interval, window, own_type, 0x00, 1000);
- if(err < 0)
- {
- perror("set scan parameters failed");
- exit(1);
- }
- 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 reveive adverising 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;
- }