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
data.tar.gz.sig
ADDED
Binary file
|
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
ext/bluetooth/extconf.rb
|
6
|
+
ext/bluetooth/linux/ruby_bluetooth.c
|
7
|
+
ext/bluetooth/linux/ruby_bluetooth.h
|
8
|
+
ext/bluetooth/macosx/device.m
|
9
|
+
ext/bluetooth/macosx/error.m
|
10
|
+
ext/bluetooth/macosx/host_controller.m
|
11
|
+
ext/bluetooth/macosx/ruby_bluetooth.h
|
12
|
+
ext/bluetooth/macosx/ruby_bluetooth.m
|
13
|
+
ext/bluetooth/macosx/scan.m
|
14
|
+
ext/bluetooth/win32/ruby_bluetooth.cpp
|
15
|
+
ext/bluetooth/win32/ruby_bluetooth.h
|
16
|
+
lib/bluetooth.rb
|
17
|
+
lib/bluetooth/device.rb
|
18
|
+
sample/name.rb
|
19
|
+
sample/pair.rb
|
20
|
+
sample/quality.rb
|
21
|
+
sample/scan.rb
|
data/README.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
= ruby-bluetooth
|
2
|
+
|
3
|
+
* http://github.com/yaksnrainbows/ruby-bluetooth
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
A bluetooth library for ruby
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* Only known to work on OS X
|
12
|
+
|
13
|
+
== INSTALL:
|
14
|
+
|
15
|
+
gem install ruby-bluetooth
|
16
|
+
|
17
|
+
== LICENSE:
|
18
|
+
|
19
|
+
Unknown
|
20
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'hoe'
|
3
|
+
#require 'rake/extensiontask'
|
4
|
+
|
5
|
+
hoe = Hoe.spec 'bluetooth' do
|
6
|
+
developer 'Eric Hodel', 'drbrain@segment7.net'
|
7
|
+
developer 'Jeremie Castagna', ''
|
8
|
+
developer 'Esteve Fernandez', ''
|
9
|
+
|
10
|
+
extra_dev_deps << ['rake-compiler', '~> 0.6']
|
11
|
+
|
12
|
+
self.clean_globs = %w[
|
13
|
+
ext/bluetooth/Makefile
|
14
|
+
ext/bluetooth/mkmf.log
|
15
|
+
ext/bluetooth/bluetooth.bundle
|
16
|
+
ext/bluetooth/*.o
|
17
|
+
]
|
18
|
+
|
19
|
+
self.spec_extras[:extensions] = 'ext/bluetooth/extconf.rb'
|
20
|
+
end
|
21
|
+
|
22
|
+
#Rake::ExtensionTask.new 'bluetooth' do |ext|
|
23
|
+
# ext.source_pattern = '*/*.{c,cpp,h,m}'
|
24
|
+
# ext.gem_spec = hoe.spec
|
25
|
+
#end
|
26
|
+
#
|
27
|
+
#task :test => :compile
|
28
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
dir_config 'bluetooth'
|
4
|
+
|
5
|
+
name = case RUBY_PLATFORM
|
6
|
+
when /linux/ then
|
7
|
+
abort 'could not find bluetooth library' unless
|
8
|
+
have_library 'bluetooth'
|
9
|
+
|
10
|
+
'linux'
|
11
|
+
when /(win32|mingw32)/
|
12
|
+
abort 'could not find Ws2bth.h' unless
|
13
|
+
find_header('Ws2bth.h', 'c:\archiv~1\micros~2\include')
|
14
|
+
|
15
|
+
'win32'
|
16
|
+
when /darwin/ then
|
17
|
+
$LDFLAGS << ' -framework IOBluetooth'
|
18
|
+
'macosx'
|
19
|
+
else
|
20
|
+
abort "unknown platform #{RUBY_PLATFORM}"
|
21
|
+
end
|
22
|
+
|
23
|
+
create_makefile 'bluetooth', name
|
24
|
+
|
25
|
+
if RUBY_PLATFORM =~ /darwin/ then
|
26
|
+
open 'Makefile', 'a' do |io|
|
27
|
+
io.write "\n.m.o:\n\t#{COMPILE_C}\n\n"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,539 @@
|
|
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 "ruby_bluetooth.h"
|
7
|
+
#include <arpa/inet.h>
|
8
|
+
|
9
|
+
VALUE bt_module;
|
10
|
+
VALUE bt_devices_class;
|
11
|
+
VALUE bt_socket_class;
|
12
|
+
VALUE bt_rfcomm_socket_class;
|
13
|
+
VALUE bt_l2cap_socket_class;
|
14
|
+
VALUE bt_service_class;
|
15
|
+
VALUE bt_services_class;
|
16
|
+
VALUE bt_cBluetoothDevice;
|
17
|
+
|
18
|
+
// The initialization method for this module
|
19
|
+
void Init_bluetooth()
|
20
|
+
{
|
21
|
+
bt_module = rb_define_module("Bluetooth");
|
22
|
+
|
23
|
+
rb_define_singleton_method(bt_devices_class, "scan", bt_devices_scan, 0);
|
24
|
+
rb_undef_method(bt_devices_class, "initialize");
|
25
|
+
|
26
|
+
bt_socket_class = rb_define_class_under(bt_module, "BluetoothSocket", rb_cIO);
|
27
|
+
rb_define_method(bt_socket_class, "inspect", bt_socket_inspect, 0);
|
28
|
+
rb_define_method(bt_socket_class, "for_fd", bt_socket_s_for_fd, 1);
|
29
|
+
rb_define_method(bt_socket_class, "listen", bt_socket_listen, 1);
|
30
|
+
rb_define_method(bt_socket_class, "accept", bt_socket_accept, 0);
|
31
|
+
rb_undef_method(bt_socket_class, "initialize");
|
32
|
+
|
33
|
+
bt_rfcomm_socket_class = rb_define_class_under(bt_module, "RFCOMMSocket", bt_socket_class);
|
34
|
+
rb_define_method(bt_rfcomm_socket_class, "initialize", bt_rfcomm_socket_init, -1);
|
35
|
+
rb_define_method(bt_rfcomm_socket_class, "connect", bt_rfcomm_socket_connect, 2);
|
36
|
+
rb_define_method(bt_rfcomm_socket_class, "bind", bt_rfcomm_socket_bind, 1);
|
37
|
+
|
38
|
+
bt_l2cap_socket_class = rb_define_class_under(bt_module, "L2CAPSocket", bt_socket_class);
|
39
|
+
rb_define_method(bt_l2cap_socket_class, "initialize", bt_l2cap_socket_init, -1);
|
40
|
+
rb_define_method(bt_l2cap_socket_class, "connect", bt_l2cap_socket_connect, 2);
|
41
|
+
rb_define_method(bt_l2cap_socket_class, "bind", bt_l2cap_socket_bind, 1);
|
42
|
+
|
43
|
+
bt_services_class = rb_define_class_under(bt_module, "Services", rb_cObject);
|
44
|
+
//rb_define_singleton_method(bt_services_class, "scan", bt_services_scan, 3);
|
45
|
+
rb_undef_method(bt_services_class, "initialize");
|
46
|
+
|
47
|
+
bt_service_class = rb_define_class_under(bt_module, "Service", rb_cObject);
|
48
|
+
rb_define_singleton_method(bt_service_class, "new", bt_service_new, 4);
|
49
|
+
rb_define_method(bt_service_class, "register", bt_service_register, 1);
|
50
|
+
rb_define_method(bt_service_class, "unregister", bt_service_unregister, 0);
|
51
|
+
rb_define_attr(bt_service_class, "uuid", Qtrue, Qfalse);
|
52
|
+
rb_define_attr(bt_service_class, "name", Qtrue, Qfalse);
|
53
|
+
rb_define_attr(bt_service_class, "description", Qtrue, Qfalse);
|
54
|
+
rb_define_attr(bt_service_class, "provider", Qtrue, Qfalse);
|
55
|
+
|
56
|
+
rb_define_method(bt_service_class, "registered?", bt_service_registered, 0);
|
57
|
+
|
58
|
+
bt_cBluetoothDevice = rb_const_get(mBluetooth, rb_intern("Device"));
|
59
|
+
}
|
60
|
+
|
61
|
+
static VALUE bt_socket_accept(VALUE self) {
|
62
|
+
OpenFile *fptr;
|
63
|
+
VALUE sock2;
|
64
|
+
char buf[1024];
|
65
|
+
socklen_t len = sizeof(buf);
|
66
|
+
|
67
|
+
// struct sockaddr_rc rcaddr;
|
68
|
+
// addr_len = sizeof(rcaddr);
|
69
|
+
|
70
|
+
GetOpenFile(self, fptr);
|
71
|
+
//sock2 = s_accept(bt_socket_class, fileno(fptr->f), (struct sockaddr *)&rcaddr, &addr_len);
|
72
|
+
sock2 = s_accept(bt_socket_class, fileno(fptr->f), (struct sockaddr *)buf, &len);
|
73
|
+
return rb_assoc_new(sock2, rb_str_new(buf, len));
|
74
|
+
}
|
75
|
+
|
76
|
+
|
77
|
+
static VALUE
|
78
|
+
bt_socket_listen(sock, log)
|
79
|
+
VALUE sock, log;
|
80
|
+
{
|
81
|
+
OpenFile *fptr;
|
82
|
+
int backlog;
|
83
|
+
|
84
|
+
rb_secure(4);
|
85
|
+
backlog = NUM2INT(log);
|
86
|
+
GetOpenFile(sock, fptr);
|
87
|
+
if (listen(fileno(fptr->f), backlog) < 0)
|
88
|
+
rb_sys_fail("listen(2)");
|
89
|
+
|
90
|
+
return INT2FIX(0);
|
91
|
+
}
|
92
|
+
|
93
|
+
|
94
|
+
static VALUE bt_service_register(VALUE self, VALUE socket) {
|
95
|
+
VALUE registered = rb_iv_get(self, "@registered");
|
96
|
+
if (registered == Qfalse) {
|
97
|
+
VALUE port_v = rb_iv_get(socket, "@port");
|
98
|
+
if(Qnil == port_v) {
|
99
|
+
rb_raise (rb_eIOError, "a bound socket must be passed");
|
100
|
+
}
|
101
|
+
|
102
|
+
// uint32_t service_uuid_int[] = { 0, 0, 0, 0xABCD };
|
103
|
+
const char *service_name = STR2CSTR(rb_iv_get(self, "@name"));
|
104
|
+
const char *service_dsc = STR2CSTR(rb_iv_get(self, "@description"));
|
105
|
+
const char *service_prov = STR2CSTR(rb_iv_get(self, "@provider"));
|
106
|
+
|
107
|
+
uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid;
|
108
|
+
sdp_list_t *l2cap_list = 0,
|
109
|
+
*rfcomm_list = 0,
|
110
|
+
*root_list = 0,
|
111
|
+
*proto_list = 0,
|
112
|
+
*access_proto_list = 0;
|
113
|
+
sdp_data_t *channel = 0, *psm = 0;
|
114
|
+
|
115
|
+
sdp_record_t *record = sdp_record_alloc();
|
116
|
+
|
117
|
+
// set the general service ID
|
118
|
+
// sdp_uuid128_create( &svc_uuid, &service_uuid_int );
|
119
|
+
char *service_id = STR2CSTR(rb_iv_get(self, "@uuid"));
|
120
|
+
if(str2uuid(service_id, &svc_uuid) != 0) {
|
121
|
+
rb_raise (rb_eIOError, "a valid uuid must be passed");
|
122
|
+
}
|
123
|
+
sdp_set_service_id( record, svc_uuid );
|
124
|
+
|
125
|
+
// make the service record publicly browsable
|
126
|
+
sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
|
127
|
+
root_list = sdp_list_append(0, &root_uuid);
|
128
|
+
sdp_set_browse_groups( record, root_list );
|
129
|
+
|
130
|
+
// set l2cap information
|
131
|
+
sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
|
132
|
+
l2cap_list = sdp_list_append( 0, &l2cap_uuid );
|
133
|
+
if (bt_l2cap_socket_class == CLASS_OF(socket)) {
|
134
|
+
uint16_t l2cap_port = FIX2UINT(port_v);
|
135
|
+
psm = sdp_data_alloc(SDP_UINT16, &l2cap_port);
|
136
|
+
sdp_list_append(l2cap_list, psm);
|
137
|
+
}
|
138
|
+
proto_list = sdp_list_append( 0, l2cap_list );
|
139
|
+
|
140
|
+
// set rfcomm information
|
141
|
+
sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
|
142
|
+
rfcomm_list = sdp_list_append( 0, &rfcomm_uuid );
|
143
|
+
if (bt_rfcomm_socket_class == CLASS_OF(socket)) {
|
144
|
+
uint16_t rfcomm_channel = FIX2UINT(port_v);
|
145
|
+
channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel);
|
146
|
+
sdp_list_append(rfcomm_list, channel);
|
147
|
+
}
|
148
|
+
sdp_list_append( proto_list, rfcomm_list );
|
149
|
+
|
150
|
+
// attach protocol information to service record
|
151
|
+
access_proto_list = sdp_list_append( 0, proto_list );
|
152
|
+
sdp_set_access_protos( record, access_proto_list );
|
153
|
+
|
154
|
+
// set the name, provider, and description
|
155
|
+
sdp_set_info_attr(record, service_name, service_prov, service_dsc);
|
156
|
+
int err = 0;
|
157
|
+
sdp_session_t *session = 0;
|
158
|
+
|
159
|
+
// connect to the local SDP server, register the service record, and
|
160
|
+
// disconnect
|
161
|
+
session = sdp_connect( BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY );
|
162
|
+
err = sdp_record_register(session, record, 0);
|
163
|
+
|
164
|
+
// cleanup
|
165
|
+
if (channel != 0) {
|
166
|
+
sdp_data_free( channel );
|
167
|
+
}
|
168
|
+
sdp_list_free( l2cap_list, 0 );
|
169
|
+
sdp_list_free( rfcomm_list, 0 );
|
170
|
+
sdp_list_free( root_list, 0 );
|
171
|
+
sdp_list_free( access_proto_list, 0 );
|
172
|
+
|
173
|
+
struct bluetooth_service_struct *bss;
|
174
|
+
Data_Get_Struct(self, struct bluetooth_service_struct, bss);
|
175
|
+
bss->session = session;
|
176
|
+
// Do something
|
177
|
+
rb_iv_set(self, "@registered", Qtrue);
|
178
|
+
}
|
179
|
+
return Qnil;
|
180
|
+
}
|
181
|
+
|
182
|
+
static VALUE bt_service_unregister(VALUE self) {
|
183
|
+
VALUE registered = rb_iv_get(self, "@registered");
|
184
|
+
if (registered == Qtrue) {
|
185
|
+
struct bluetooth_service_struct *bss;
|
186
|
+
Data_Get_Struct(self, struct bluetooth_service_struct, bss);
|
187
|
+
sdp_close(bss->session);
|
188
|
+
bss->session = NULL;
|
189
|
+
// Do something
|
190
|
+
rb_iv_set(self, "@registered", Qfalse);
|
191
|
+
}
|
192
|
+
return registered;
|
193
|
+
}
|
194
|
+
|
195
|
+
static VALUE bt_service_registered(VALUE self) {
|
196
|
+
VALUE registered = rb_iv_get(self, "@registered");
|
197
|
+
if (registered == Qtrue) {
|
198
|
+
// Do something
|
199
|
+
}
|
200
|
+
return registered;
|
201
|
+
}
|
202
|
+
|
203
|
+
static VALUE bt_service_new(VALUE self, VALUE uuid, VALUE name, VALUE description, VALUE provider) {
|
204
|
+
struct bluetooth_service_struct *bss;
|
205
|
+
|
206
|
+
VALUE obj = Data_Make_Struct(self,
|
207
|
+
struct bluetooth_service_struct, NULL,
|
208
|
+
free, bss);
|
209
|
+
|
210
|
+
rb_iv_set(obj, "@uuid", uuid);
|
211
|
+
rb_iv_set(obj, "@name", name);
|
212
|
+
rb_iv_set(obj, "@description", description);
|
213
|
+
rb_iv_set(obj, "@provider", provider);
|
214
|
+
rb_iv_set(obj, "@registered", Qfalse);
|
215
|
+
|
216
|
+
return obj;
|
217
|
+
}
|
218
|
+
|
219
|
+
static VALUE
|
220
|
+
bt_l2cap_socket_connect(VALUE self, VALUE host, VALUE port)
|
221
|
+
{
|
222
|
+
OpenFile *fptr;
|
223
|
+
int fd;
|
224
|
+
|
225
|
+
GetOpenFile(self, fptr);
|
226
|
+
fd = fileno(fptr->f);
|
227
|
+
|
228
|
+
struct sockaddr_l2 addr = { 0 };
|
229
|
+
char *dest = STR2CSTR(host);
|
230
|
+
|
231
|
+
// set the connection parameters (who to connect to)
|
232
|
+
addr.l2_family = AF_BLUETOOTH;
|
233
|
+
addr.l2_psm = (uint8_t) FIX2UINT(port);
|
234
|
+
str2ba( dest, &addr.l2_bdaddr );
|
235
|
+
|
236
|
+
// connect to server
|
237
|
+
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
238
|
+
rb_sys_fail("connect(2)");
|
239
|
+
}
|
240
|
+
|
241
|
+
return INT2FIX(0);
|
242
|
+
}
|
243
|
+
|
244
|
+
static VALUE
|
245
|
+
bt_rfcomm_socket_connect(VALUE self, VALUE host, VALUE port)
|
246
|
+
{
|
247
|
+
OpenFile *fptr;
|
248
|
+
int fd;
|
249
|
+
|
250
|
+
GetOpenFile(self, fptr);
|
251
|
+
fd = fileno(fptr->f);
|
252
|
+
|
253
|
+
struct sockaddr_rc addr = { 0 };
|
254
|
+
char *dest = STR2CSTR(host);
|
255
|
+
|
256
|
+
// set the connection parameters (who to connect to)
|
257
|
+
addr.rc_family = AF_BLUETOOTH;
|
258
|
+
addr.rc_channel = (uint8_t) FIX2UINT(port);
|
259
|
+
str2ba( dest, &addr.rc_bdaddr );
|
260
|
+
|
261
|
+
// connect to server
|
262
|
+
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
263
|
+
rb_sys_fail("connect(2)");
|
264
|
+
}
|
265
|
+
|
266
|
+
return INT2FIX(0);
|
267
|
+
}
|
268
|
+
|
269
|
+
static VALUE
|
270
|
+
bt_socket_s_for_fd(VALUE klass, VALUE fd)
|
271
|
+
{
|
272
|
+
OpenFile *fptr;
|
273
|
+
VALUE sock = bt_init_sock(rb_obj_alloc(klass), NUM2INT(fd));
|
274
|
+
|
275
|
+
GetOpenFile(sock, fptr);
|
276
|
+
return sock;
|
277
|
+
}
|
278
|
+
|
279
|
+
static VALUE
|
280
|
+
bt_rfcomm_socket_bind(VALUE self, VALUE port)
|
281
|
+
{
|
282
|
+
OpenFile *fptr;
|
283
|
+
int fd;
|
284
|
+
|
285
|
+
GetOpenFile(self, fptr);
|
286
|
+
fd = fileno(fptr->f);
|
287
|
+
|
288
|
+
struct sockaddr_rc loc_addr = { 0 };
|
289
|
+
loc_addr.rc_family = AF_BLUETOOTH;
|
290
|
+
loc_addr.rc_bdaddr = *BDADDR_ANY;
|
291
|
+
loc_addr.rc_channel = (uint8_t) FIX2UINT(port);
|
292
|
+
|
293
|
+
if (bind(fd, (struct sockaddr *)&loc_addr, sizeof(loc_addr)) >= 0)
|
294
|
+
rb_iv_set(self, "@port", port);
|
295
|
+
return INT2FIX(0);
|
296
|
+
}
|
297
|
+
|
298
|
+
static VALUE
|
299
|
+
bt_l2cap_socket_bind(VALUE self, VALUE port)
|
300
|
+
{
|
301
|
+
OpenFile *fptr;
|
302
|
+
int fd;
|
303
|
+
|
304
|
+
GetOpenFile(self, fptr);
|
305
|
+
fd = fileno(fptr->f);
|
306
|
+
|
307
|
+
struct sockaddr_l2 loc_addr = { 0 };
|
308
|
+
loc_addr.l2_family = AF_BLUETOOTH;
|
309
|
+
loc_addr.l2_bdaddr = *BDADDR_ANY;
|
310
|
+
loc_addr.l2_psm = (uint8_t) FIX2UINT(port);
|
311
|
+
|
312
|
+
if (bind(fd, (struct sockaddr *)&loc_addr, sizeof(loc_addr)) >= 0)
|
313
|
+
rb_iv_set(self, "@port", port);
|
314
|
+
return INT2FIX(0);
|
315
|
+
}
|
316
|
+
|
317
|
+
static VALUE bt_socket_inspect(VALUE self)
|
318
|
+
{
|
319
|
+
return self;
|
320
|
+
}
|
321
|
+
|
322
|
+
static int
|
323
|
+
bt_ruby_socket(int domain, int type, int proto)
|
324
|
+
{
|
325
|
+
int fd;
|
326
|
+
|
327
|
+
fd = socket(domain, type, proto);
|
328
|
+
if (fd < 0) {
|
329
|
+
if (errno == EMFILE || errno == ENFILE) {
|
330
|
+
rb_gc();
|
331
|
+
fd = socket(domain, type, proto);
|
332
|
+
}
|
333
|
+
}
|
334
|
+
return fd;
|
335
|
+
}
|
336
|
+
|
337
|
+
static VALUE
|
338
|
+
bt_init_sock(VALUE sock, int fd)
|
339
|
+
{
|
340
|
+
OpenFile *fp = NULL;
|
341
|
+
|
342
|
+
MakeOpenFile(sock, fp);
|
343
|
+
|
344
|
+
fp->f = rb_fdopen(fd, "r");
|
345
|
+
fp->f2 = rb_fdopen(fd, "w");
|
346
|
+
fp->mode = FMODE_READWRITE;
|
347
|
+
|
348
|
+
rb_io_synchronized(fp);
|
349
|
+
|
350
|
+
return sock;
|
351
|
+
}
|
352
|
+
|
353
|
+
// Initialization of a RFCOMM socket
|
354
|
+
static VALUE bt_rfcomm_socket_init(int argc, VALUE *argv, VALUE sock)
|
355
|
+
{
|
356
|
+
int fd = bt_ruby_socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
|
357
|
+
if (fd < 0) {
|
358
|
+
rb_sys_fail("socket(2) - bt");
|
359
|
+
}
|
360
|
+
VALUE ret = bt_init_sock(sock, fd);
|
361
|
+
return ret;
|
362
|
+
}
|
363
|
+
|
364
|
+
// Initialization of a L2CAP socket
|
365
|
+
static VALUE bt_l2cap_socket_init(int argc, VALUE *argv, VALUE sock)
|
366
|
+
{
|
367
|
+
int fd = bt_ruby_socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
|
368
|
+
if (fd < 0) {
|
369
|
+
rb_sys_fail("socket(2) - bt");
|
370
|
+
}
|
371
|
+
VALUE ret = bt_init_sock(sock, fd);
|
372
|
+
return ret;
|
373
|
+
}
|
374
|
+
|
375
|
+
// Scan local network for visible remote devices
|
376
|
+
static VALUE bt_devices_scan(VALUE self)
|
377
|
+
{
|
378
|
+
inquiry_info *ii = NULL;
|
379
|
+
int max_rsp, num_rsp;
|
380
|
+
int dev_id, sock, len, flags;
|
381
|
+
int i;
|
382
|
+
|
383
|
+
dev_id = hci_get_route(NULL);
|
384
|
+
sock = hci_open_dev( dev_id );
|
385
|
+
if (dev_id < 0 || sock < 0)
|
386
|
+
{
|
387
|
+
rb_raise (rb_eIOError, "error opening socket");
|
388
|
+
}
|
389
|
+
|
390
|
+
len = 8;
|
391
|
+
max_rsp = 255;
|
392
|
+
flags = IREQ_CACHE_FLUSH;
|
393
|
+
ii = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info));
|
394
|
+
|
395
|
+
num_rsp = hci_inquiry(dev_id, len, max_rsp, NULL, &ii, flags);
|
396
|
+
if( num_rsp < 0 )
|
397
|
+
rb_raise(rb_eIOError, "hci_inquiry");
|
398
|
+
|
399
|
+
VALUE devices_array = rb_ary_new();
|
400
|
+
|
401
|
+
// Iterate over every device found and add it to result array
|
402
|
+
for (i = 0; i < num_rsp; i++)
|
403
|
+
{
|
404
|
+
char addr[19] = { 0 };
|
405
|
+
char name[248] = { 0 };
|
406
|
+
|
407
|
+
ba2str(&(ii+i)->bdaddr, addr);
|
408
|
+
memset(name, 0, sizeof(name));
|
409
|
+
if (hci_read_remote_name(sock, &(ii+i)->bdaddr, sizeof(name),
|
410
|
+
name, 0) < 0)
|
411
|
+
strcpy(name, "(unknown)");
|
412
|
+
|
413
|
+
VALUE bt_dev = rb_funcall(bt_cBluetoothDevice, rb_intern("new"), 2,
|
414
|
+
rb_str_new(name), rb_str_new2(addr));
|
415
|
+
|
416
|
+
rb_ary_push(devices_array, bt_dev);
|
417
|
+
}
|
418
|
+
|
419
|
+
free( ii );
|
420
|
+
close( sock );
|
421
|
+
return devices_array;
|
422
|
+
}
|
423
|
+
|
424
|
+
static VALUE
|
425
|
+
s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len) {
|
426
|
+
int fd2;
|
427
|
+
int retry = 0;
|
428
|
+
|
429
|
+
rb_secure(3);
|
430
|
+
retry:
|
431
|
+
rb_thread_wait_fd(fd);
|
432
|
+
#if defined(_nec_ews)
|
433
|
+
fd2 = accept(fd, sockaddr, len);
|
434
|
+
#else
|
435
|
+
TRAP_BEG;
|
436
|
+
fd2 = accept(fd, sockaddr, len);
|
437
|
+
TRAP_END;
|
438
|
+
#endif
|
439
|
+
if (fd2 < 0) {
|
440
|
+
switch (errno) {
|
441
|
+
case EMFILE:
|
442
|
+
case ENFILE:
|
443
|
+
if (retry) break;
|
444
|
+
rb_gc();
|
445
|
+
retry = 1;
|
446
|
+
goto retry;
|
447
|
+
case EWOULDBLOCK:
|
448
|
+
break;
|
449
|
+
default:
|
450
|
+
if (!rb_io_wait_readable(fd)) break;
|
451
|
+
retry = 0;
|
452
|
+
goto retry;
|
453
|
+
}
|
454
|
+
rb_sys_fail(0);
|
455
|
+
}
|
456
|
+
if (!klass) return INT2NUM(fd2);
|
457
|
+
return bt_init_sock(rb_obj_alloc(klass), fd2);
|
458
|
+
}
|
459
|
+
// Code from PyBlueZ
|
460
|
+
int
|
461
|
+
str2uuid(char *uuid_str, uuid_t *uuid)
|
462
|
+
{
|
463
|
+
uint32_t uuid_int[4];
|
464
|
+
char *endptr;
|
465
|
+
|
466
|
+
if(strlen(uuid_str) == 36) {
|
467
|
+
// Parse uuid128 standard format: 12345678-9012-3456-7890-123456789012
|
468
|
+
char buf[9] = { 0 };
|
469
|
+
|
470
|
+
if(uuid_str[8] != '-' && uuid_str[13] != '-' &&
|
471
|
+
uuid_str[18] != '-' && uuid_str[23] != '-') {
|
472
|
+
return -1;
|
473
|
+
}
|
474
|
+
// first 8-bytes
|
475
|
+
strncpy(buf, uuid_str, 8);
|
476
|
+
uuid_int[0] = htonl(strtoul(buf, &endptr, 16));
|
477
|
+
if(endptr != buf + 8) return -1;
|
478
|
+
|
479
|
+
// second 8-bytes
|
480
|
+
strncpy(buf, uuid_str+9, 4);
|
481
|
+
strncpy(buf+4, uuid_str+14, 4);
|
482
|
+
uuid_int[1] = htonl(strtoul( buf, &endptr, 16));
|
483
|
+
if(endptr != buf + 8) return -1;
|
484
|
+
|
485
|
+
// third 8-bytes
|
486
|
+
strncpy(buf, uuid_str+19, 4);
|
487
|
+
strncpy(buf+4, uuid_str+24, 4);
|
488
|
+
uuid_int[2] = htonl(strtoul(buf, &endptr, 16));
|
489
|
+
if(endptr != buf + 8) return -1;
|
490
|
+
|
491
|
+
// fourth 8-bytes
|
492
|
+
strncpy(buf, uuid_str+28, 8);
|
493
|
+
uuid_int[3] = htonl(strtoul(buf, &endptr, 16));
|
494
|
+
if(endptr != buf + 8) return -1;
|
495
|
+
|
496
|
+
if(uuid != NULL) sdp_uuid128_create(uuid, uuid_int);
|
497
|
+
}
|
498
|
+
|
499
|
+
else if(strlen(uuid_str) == 8) {
|
500
|
+
// 32-bit reserved UUID
|
501
|
+
uint32_t i = strtoul(uuid_str, &endptr, 16);
|
502
|
+
if(endptr != uuid_str + 8) return -1;
|
503
|
+
if(uuid != NULL) sdp_uuid32_create(uuid, i);
|
504
|
+
}
|
505
|
+
|
506
|
+
else if(strlen(uuid_str) == 6) {
|
507
|
+
// 16-bit reserved UUID with 0x on front
|
508
|
+
if(uuid_str[0] == '0' && (uuid_str[1] == 'x' || uuid_str[1] == 'X')) {
|
509
|
+
// move chars up
|
510
|
+
uuid_str[0] = uuid_str[2];
|
511
|
+
uuid_str[1] = uuid_str[3];
|
512
|
+
uuid_str[2] = uuid_str[4];
|
513
|
+
uuid_str[3] = uuid_str[5];
|
514
|
+
uuid_str[4] = '\0';
|
515
|
+
int i = strtol(uuid_str, &endptr, 16);
|
516
|
+
if(endptr != uuid_str + 4) return -1;
|
517
|
+
if(uuid != NULL) sdp_uuid16_create(uuid, i);
|
518
|
+
}
|
519
|
+
|
520
|
+
else return(-1);
|
521
|
+
}
|
522
|
+
|
523
|
+
else if(strlen(uuid_str) == 4) {
|
524
|
+
// 16-bit reserved UUID
|
525
|
+
int i = strtol(uuid_str, &endptr, 16);
|
526
|
+
if(endptr != uuid_str + 4) return -1;
|
527
|
+
if(uuid != NULL) sdp_uuid16_create(uuid, i);
|
528
|
+
}
|
529
|
+
|
530
|
+
else {
|
531
|
+
return -1;
|
532
|
+
}
|
533
|
+
|
534
|
+
return 0;
|
535
|
+
}
|
536
|
+
|
537
|
+
|
538
|
+
|
539
|
+
|