bluetooth 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +0 -0
- data/History.txt +4 -0
- data/Manifest.txt +21 -0
- data/README.txt +20 -0
- data/Rakefile +28 -0
- data/ext/bluetooth/extconf.rb +30 -0
- data/ext/bluetooth/linux/ruby_bluetooth.c +539 -0
- data/ext/bluetooth/linux/ruby_bluetooth.h +68 -0
- data/ext/bluetooth/macosx/device.m +230 -0
- data/ext/bluetooth/macosx/error.m +269 -0
- data/ext/bluetooth/macosx/host_controller.m +39 -0
- data/ext/bluetooth/macosx/ruby_bluetooth.h +69 -0
- data/ext/bluetooth/macosx/ruby_bluetooth.m +29 -0
- data/ext/bluetooth/macosx/scan.m +87 -0
- data/ext/bluetooth/win32/ruby_bluetooth.cpp +112 -0
- data/ext/bluetooth/win32/ruby_bluetooth.h +24 -0
- data/lib/bluetooth.rb +21 -0
- data/lib/bluetooth/device.rb +79 -0
- data/sample/name.rb +8 -0
- data/sample/pair.rb +15 -0
- data/sample/quality.rb +25 -0
- data/sample/scan.rb +8 -0
- metadata +178 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
#import "ruby_bluetooth.h"
|
2
|
+
|
3
|
+
@implementation HCIDelegate
|
4
|
+
|
5
|
+
- (VALUE) device {
|
6
|
+
return device;
|
7
|
+
}
|
8
|
+
|
9
|
+
- (void) setDevice: (VALUE)input {
|
10
|
+
device = input;
|
11
|
+
}
|
12
|
+
|
13
|
+
|
14
|
+
- (void) controllerClassOfDeviceReverted: (id)sender {
|
15
|
+
printf("class of device reverted!\n");
|
16
|
+
}
|
17
|
+
|
18
|
+
- (void) readLinkQualityForDeviceComplete: (id)controller
|
19
|
+
device: (IOBluetoothDevice*)bt_device
|
20
|
+
info: (BluetoothHCILinkQualityInfo*)info
|
21
|
+
error: (IOReturn)error {
|
22
|
+
CFRunLoopStop(CFRunLoopGetCurrent());
|
23
|
+
|
24
|
+
rb_iv_set(device, "@link_quality_error", INT2NUM(error));
|
25
|
+
rb_iv_set(device, "@link_quality", UINT2NUM(info->qualityValue));
|
26
|
+
}
|
27
|
+
|
28
|
+
- (void) readRSSIForDeviceComplete: (id)controller
|
29
|
+
device: (IOBluetoothDevice*)bt_device
|
30
|
+
info: (BluetoothHCIRSSIInfo*)info
|
31
|
+
error: (IOReturn)error {
|
32
|
+
CFRunLoopStop(CFRunLoopGetCurrent());
|
33
|
+
|
34
|
+
rb_iv_set(device, "@rssi_error", INT2NUM(error));
|
35
|
+
rb_iv_set(device, "@rssi", INT2NUM(info->RSSIValue));
|
36
|
+
}
|
37
|
+
|
38
|
+
@end
|
39
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#import <Cocoa/Cocoa.h>
|
2
|
+
|
3
|
+
#import <IOBluetooth/IOBluetoothUserLib.h>
|
4
|
+
#import <IOBluetooth/objc/IOBluetoothDevice.h>
|
5
|
+
#import <IOBluetooth/objc/IOBluetoothDeviceInquiry.h>
|
6
|
+
#import <IOBluetooth/objc/IOBluetoothHostController.h>
|
7
|
+
|
8
|
+
#import <ruby.h>
|
9
|
+
|
10
|
+
void init_rbt_error();
|
11
|
+
|
12
|
+
void rbt_check_status(IOReturn status, NSAutoreleasePool *pool);
|
13
|
+
|
14
|
+
VALUE rbt_scan(VALUE);
|
15
|
+
|
16
|
+
VALUE rbt_device_link_quality(VALUE);
|
17
|
+
VALUE rbt_device_open_connection(VALUE);
|
18
|
+
VALUE rbt_device_pair(VALUE);
|
19
|
+
VALUE rbt_device_request_name(VALUE);
|
20
|
+
VALUE rbt_device_rssi(VALUE);
|
21
|
+
|
22
|
+
@interface BluetoothDeviceScanner : NSObject {
|
23
|
+
IOBluetoothDeviceInquiry * _inquiry;
|
24
|
+
BOOL _busy;
|
25
|
+
VALUE _devices;
|
26
|
+
}
|
27
|
+
|
28
|
+
- (void) stopSearch;
|
29
|
+
- (IOReturn) startSearch;
|
30
|
+
- (VALUE) devices;
|
31
|
+
@end
|
32
|
+
|
33
|
+
@interface PairingDelegate : NSObject {
|
34
|
+
VALUE device;
|
35
|
+
}
|
36
|
+
|
37
|
+
- (VALUE) device;
|
38
|
+
- (void) setDevice: (VALUE)input;
|
39
|
+
|
40
|
+
- (void) devicePairingConnecting: (id)sender;
|
41
|
+
- (void) devicePairingStarted: (id)sender;
|
42
|
+
- (void) devicePairingFinished: (id)sender
|
43
|
+
error: (IOReturn)error;
|
44
|
+
|
45
|
+
- (void) devicePairingPasskeyNotification: (id)sender
|
46
|
+
passkey: (BluetoothPasskey)passkey;
|
47
|
+
- (void) devicePairingPINCodeRequest: (id)sender;
|
48
|
+
- (void) devicePairingUserConfirmationRequest: (id)sender
|
49
|
+
numericValue: (BluetoothNumericValue)numericValue;
|
50
|
+
@end
|
51
|
+
|
52
|
+
@interface HCIDelegate : NSObject {
|
53
|
+
VALUE device;
|
54
|
+
}
|
55
|
+
|
56
|
+
- (VALUE) device;
|
57
|
+
- (void) setDevice: (VALUE)input;
|
58
|
+
|
59
|
+
- (void) controllerClassOfDeviceReverted: (id)sender;
|
60
|
+
- (void) readLinkQualityForDeviceComplete: (id)controller
|
61
|
+
device: (IOBluetoothDevice*)bt_device
|
62
|
+
info: (BluetoothHCILinkQualityInfo*)info
|
63
|
+
error: (IOReturn)error;
|
64
|
+
- (void) readRSSIForDeviceComplete: (id)controller
|
65
|
+
device: (IOBluetoothDevice*)bt_device
|
66
|
+
info: (BluetoothHCIRSSIInfo*)info
|
67
|
+
error: (IOReturn)error;
|
68
|
+
@end
|
69
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#import "ruby_bluetooth.h"
|
2
|
+
|
3
|
+
VALUE rbt_mBluetooth = Qnil;
|
4
|
+
|
5
|
+
VALUE rbt_cBluetoothDevice = Qnil;
|
6
|
+
VALUE rbt_cBluetoothERRORS = Qnil;
|
7
|
+
VALUE rbt_cBluetoothError = Qnil;
|
8
|
+
|
9
|
+
void Init_bluetooth() {
|
10
|
+
rbt_mBluetooth = rb_define_module("Bluetooth");
|
11
|
+
|
12
|
+
rbt_cBluetoothError = rb_const_get(rbt_mBluetooth, rb_intern("Error"));
|
13
|
+
|
14
|
+
rb_define_singleton_method(rbt_mBluetooth, "scan", rbt_scan, 0);
|
15
|
+
|
16
|
+
rbt_cBluetoothDevice = rb_const_get(rbt_mBluetooth, rb_intern("Device"));
|
17
|
+
|
18
|
+
rb_define_method(rbt_cBluetoothDevice, "connect",
|
19
|
+
rbt_device_open_connection, 0);
|
20
|
+
rb_define_method(rbt_cBluetoothDevice, "_link_quality",
|
21
|
+
rbt_device_link_quality, 0);
|
22
|
+
rb_define_method(rbt_cBluetoothDevice, "pair", rbt_device_pair, 0);
|
23
|
+
rb_define_method(rbt_cBluetoothDevice, "request_name",
|
24
|
+
rbt_device_request_name, 0);
|
25
|
+
rb_define_method(rbt_cBluetoothDevice, "_rssi", rbt_device_rssi, 0);
|
26
|
+
|
27
|
+
init_rbt_error();
|
28
|
+
}
|
29
|
+
|
@@ -0,0 +1,87 @@
|
|
1
|
+
#import "ruby_bluetooth.h"
|
2
|
+
|
3
|
+
extern VALUE rbt_cBluetoothDevice;
|
4
|
+
|
5
|
+
VALUE rbt_scan(VALUE self) {
|
6
|
+
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
7
|
+
BluetoothDeviceScanner *bds = [BluetoothDeviceScanner new];
|
8
|
+
|
9
|
+
[bds startSearch];
|
10
|
+
|
11
|
+
CFRunLoopRun();
|
12
|
+
|
13
|
+
[pool release];
|
14
|
+
|
15
|
+
return [bds devices];
|
16
|
+
}
|
17
|
+
|
18
|
+
@implementation BluetoothDeviceScanner
|
19
|
+
|
20
|
+
- (void) deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender
|
21
|
+
error:(IOReturn)error aborted:(BOOL)aborted {
|
22
|
+
CFRunLoopStop(CFRunLoopGetCurrent());
|
23
|
+
}
|
24
|
+
|
25
|
+
- (void) deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
|
26
|
+
device:(IOBluetoothDevice*)device {
|
27
|
+
VALUE address;
|
28
|
+
VALUE name = Qnil;
|
29
|
+
const char * device_name = [[device name] UTF8String];
|
30
|
+
|
31
|
+
address = rb_str_new2([[device getAddressString] UTF8String]);
|
32
|
+
|
33
|
+
if (device_name)
|
34
|
+
name = rb_str_new2(device_name);
|
35
|
+
|
36
|
+
VALUE dev = rb_funcall(rbt_cBluetoothDevice, rb_intern("new"), 2,
|
37
|
+
address, name);
|
38
|
+
|
39
|
+
rb_ary_push(_devices, dev);
|
40
|
+
}
|
41
|
+
|
42
|
+
- (void) deviceInquiryDeviceNameUpdated:(IOBluetoothDeviceInquiry*)sender
|
43
|
+
device:(IOBluetoothDevice*)device
|
44
|
+
devicesRemaining:(uint32_t)devicesRemaining {
|
45
|
+
// do something
|
46
|
+
}
|
47
|
+
|
48
|
+
- (void) deviceInquiryUpdatingDeviceNamesStarted:(IOBluetoothDeviceInquiry*)sender
|
49
|
+
devicesRemaining:(uint32_t)devicesRemaining {
|
50
|
+
// do something
|
51
|
+
}
|
52
|
+
|
53
|
+
- (IOReturn) startSearch {
|
54
|
+
IOReturn status;
|
55
|
+
|
56
|
+
[self stopSearch];
|
57
|
+
|
58
|
+
_inquiry = [IOBluetoothDeviceInquiry inquiryWithDelegate:self];
|
59
|
+
_devices = rb_ary_new();
|
60
|
+
|
61
|
+
[_inquiry setUpdateNewDeviceNames: TRUE];
|
62
|
+
|
63
|
+
status = [_inquiry start];
|
64
|
+
|
65
|
+
if (status == kIOReturnSuccess) {
|
66
|
+
[_inquiry retain];
|
67
|
+
|
68
|
+
_busy = TRUE;
|
69
|
+
}
|
70
|
+
|
71
|
+
return status;
|
72
|
+
}
|
73
|
+
|
74
|
+
- (void) stopSearch {
|
75
|
+
if (_inquiry) {
|
76
|
+
[_inquiry stop];
|
77
|
+
|
78
|
+
[_inquiry release];
|
79
|
+
_inquiry = nil;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
- (VALUE) devices {
|
84
|
+
return _devices;
|
85
|
+
}
|
86
|
+
@end
|
87
|
+
|
@@ -0,0 +1,112 @@
|
|
1
|
+
// Include the Ruby headers and goodies
|
2
|
+
#include <ruby.h>
|
3
|
+
#include <rubyio.h>
|
4
|
+
#include <rubysig.h>
|
5
|
+
#include <util.h>
|
6
|
+
//#include <unistd.h>
|
7
|
+
//#include <winsock2.h>
|
8
|
+
#include <Ws2bth.h>
|
9
|
+
#include <BluetoothAPIs.h>
|
10
|
+
|
11
|
+
#include <stdio.h>
|
12
|
+
|
13
|
+
#include "ruby_bluetooth.h"
|
14
|
+
|
15
|
+
#pragma comment(lib, "irprops.lib")
|
16
|
+
|
17
|
+
#pragma comment(lib, "ws2_32.lib")
|
18
|
+
|
19
|
+
|
20
|
+
VALUE bt_module;
|
21
|
+
VALUE bt_devices_class;
|
22
|
+
VALUE bt_cBluetoothDevice;
|
23
|
+
|
24
|
+
// The initialization method for this module
|
25
|
+
void Init_bluetooth()
|
26
|
+
{
|
27
|
+
bt_module = rb_define_module("Bluetooth");
|
28
|
+
bt_devices_class = rb_define_class_under(bt_module, "Devices", rb_cObject);
|
29
|
+
rb_define_singleton_method(bt_devices_class, "scan", RUBY_METHOD_FUNC(bt_devices_scan), 0);
|
30
|
+
rb_undef_method(bt_devices_class, "initialize");
|
31
|
+
|
32
|
+
bt_cBluetoothDevice = rb_const_get(mBluetooth, rb_intern("Device"));
|
33
|
+
}
|
34
|
+
|
35
|
+
// Scan local network for visible remote devices
|
36
|
+
static VALUE bt_devices_scan(VALUE self)
|
37
|
+
{
|
38
|
+
WORD wVersionRequested = 0x202;
|
39
|
+
HANDLE hRadio;
|
40
|
+
BLUETOOTH_FIND_RADIO_PARAMS btfrp = { sizeof(btfrp) };
|
41
|
+
|
42
|
+
HBLUETOOTH_RADIO_FIND hFind = BluetoothFindFirstRadio( &btfrp, &hRadio );
|
43
|
+
|
44
|
+
VALUE devices_array = rb_ary_new();
|
45
|
+
if ( NULL != hFind )
|
46
|
+
{
|
47
|
+
do
|
48
|
+
{
|
49
|
+
BLUETOOTH_DEVICE_INFO_STRUCT deviceInfo;
|
50
|
+
|
51
|
+
deviceInfo.dwSize = sizeof(deviceInfo);
|
52
|
+
|
53
|
+
BLUETOOTH_DEVICE_SEARCH_PARAMS deviceSearchParams;
|
54
|
+
|
55
|
+
memset(&deviceSearchParams, 0, sizeof(deviceSearchParams));
|
56
|
+
|
57
|
+
deviceSearchParams.dwSize = sizeof(deviceSearchParams);
|
58
|
+
|
59
|
+
deviceSearchParams.fReturnAuthenticated = true;
|
60
|
+
deviceSearchParams.fReturnRemembered = false;
|
61
|
+
deviceSearchParams.fReturnUnknown = true;
|
62
|
+
deviceSearchParams.fReturnConnected = true;
|
63
|
+
deviceSearchParams.fIssueInquiry = true;
|
64
|
+
deviceSearchParams.cTimeoutMultiplier = 1;
|
65
|
+
|
66
|
+
deviceSearchParams.hRadio = hRadio;
|
67
|
+
|
68
|
+
HANDLE hDeviceFind = BluetoothFindFirstDevice(&deviceSearchParams, &deviceInfo);
|
69
|
+
|
70
|
+
if (NULL != hDeviceFind)
|
71
|
+
{
|
72
|
+
do
|
73
|
+
{
|
74
|
+
BYTE *rgBytes = deviceInfo.Address.rgBytes;
|
75
|
+
//BluetoothDisplayDeviceProperties(0, &deviceInfo);
|
76
|
+
char addr[19] = { 0 };
|
77
|
+
char name[248] = { 0 };
|
78
|
+
wcstombs(name, deviceInfo.szName, sizeof(name));
|
79
|
+
|
80
|
+
snprintf(addr, sizeof(addr), "%02x:%02x:%02x:%02x:%02x:%02x",
|
81
|
+
rgBytes[5],
|
82
|
+
rgBytes[4],
|
83
|
+
rgBytes[3],
|
84
|
+
rgBytes[2],
|
85
|
+
rgBytes[1],
|
86
|
+
rgBytes[0]);
|
87
|
+
|
88
|
+
VALUE bt_dev = rb_funcall(bt_cBluetoothDevice,
|
89
|
+
rb_intern("new"), 2,
|
90
|
+
rb_str_new2(name), rb_str_new2(addr));
|
91
|
+
rb_ary_push(devices_array, bt_dev);
|
92
|
+
}
|
93
|
+
while(BluetoothFindNextDevice(hDeviceFind, &deviceInfo));
|
94
|
+
|
95
|
+
BluetoothFindDeviceClose(hDeviceFind);
|
96
|
+
}
|
97
|
+
|
98
|
+
GUID guidServices[10];
|
99
|
+
|
100
|
+
DWORD numServices = sizeof(guidServices);
|
101
|
+
|
102
|
+
DWORD result = BluetoothEnumerateInstalledServices(hRadio, &deviceInfo, &numServices, guidServices);
|
103
|
+
|
104
|
+
CloseHandle( hRadio );
|
105
|
+
} while( BluetoothFindNextRadio( hFind, &hRadio ) );
|
106
|
+
|
107
|
+
BluetoothFindRadioClose( hFind );
|
108
|
+
}
|
109
|
+
|
110
|
+
return devices_array;
|
111
|
+
|
112
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
// Prototype for the initialization method - Ruby calls this, not you
|
2
|
+
void Init_ruby_bluetooth();
|
3
|
+
|
4
|
+
struct bluetooth_device_struct
|
5
|
+
{
|
6
|
+
VALUE addr;
|
7
|
+
VALUE name;
|
8
|
+
};
|
9
|
+
|
10
|
+
static VALUE bt_device_new(VALUE self, VALUE name, VALUE addr);
|
11
|
+
|
12
|
+
static VALUE bt_devices_scan(VALUE self);
|
13
|
+
|
14
|
+
static VALUE bt_socket_s_for_fd(VALUE klass, VALUE fd);
|
15
|
+
|
16
|
+
static VALUE bt_socket_inspect(VALUE self);
|
17
|
+
|
18
|
+
static VALUE bt_init_sock(VALUE sock, int fd);
|
19
|
+
|
20
|
+
static int bt_ruby_socket(int domain, int type, int proto);
|
21
|
+
|
22
|
+
static VALUE bt_rfcomm_socket_init(int argc, VALUE *argv, VALUE sock);
|
23
|
+
|
24
|
+
static VALUE bt_rfcomm_socket_connect(VALUE self, VALUE host, VALUE port);
|
data/lib/bluetooth.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Bluetooth
|
2
|
+
|
3
|
+
VERSION = '1.0'
|
4
|
+
|
5
|
+
ERRORS = {}
|
6
|
+
|
7
|
+
class Error < RuntimeError
|
8
|
+
def self.raise status
|
9
|
+
err = Bluetooth::ERRORS[status]
|
10
|
+
super(*err) if err
|
11
|
+
|
12
|
+
super self, "unknown error (#{status})"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
autoload :Device, 'bluetooth/device'
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'bluetooth/bluetooth'
|
21
|
+
|
@@ -0,0 +1,79 @@
|
|
1
|
+
##
|
2
|
+
# A bluetooth device
|
3
|
+
|
4
|
+
class Bluetooth::Device
|
5
|
+
|
6
|
+
##
|
7
|
+
# The address of this device in XX-XX-XX-XX-XX-XX format
|
8
|
+
|
9
|
+
attr_accessor :address
|
10
|
+
|
11
|
+
##
|
12
|
+
# Sets the name of this device
|
13
|
+
|
14
|
+
attr_writer :name
|
15
|
+
|
16
|
+
##
|
17
|
+
# Creates a new Device with an +address+ and an optional +name+
|
18
|
+
|
19
|
+
def initialize address, name = nil
|
20
|
+
@address = address
|
21
|
+
@name = name
|
22
|
+
|
23
|
+
@pair_error = nil
|
24
|
+
@pair_confirmation_callback = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# The bytes of this address
|
29
|
+
|
30
|
+
def address_bytes
|
31
|
+
@address.split('-').map { |c| c.to_i(16) }.pack 'C*'
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Returns the link quality for the device.
|
36
|
+
|
37
|
+
def link_quality
|
38
|
+
connect do
|
39
|
+
_link_quality
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# The name of this Device. It will be automatically looked up if not
|
45
|
+
# already known.
|
46
|
+
|
47
|
+
def name
|
48
|
+
return @name if @name
|
49
|
+
|
50
|
+
@name = request_name
|
51
|
+
|
52
|
+
return '(unknown)' unless @name
|
53
|
+
|
54
|
+
@name
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Called during pairing if user confirmation is required with a number
|
59
|
+
# to match with the device. Return true if the number matches.
|
60
|
+
|
61
|
+
def pair_confirmation &block
|
62
|
+
@pair_confirmation_callback = block
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Returns the RSSI for the device
|
67
|
+
|
68
|
+
def rssi
|
69
|
+
connect do
|
70
|
+
_rssi
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_s # :nodoc:
|
75
|
+
"#{name} at #{address}"
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|