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
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
|
+
|