bluetooth 1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|