bluetooth-serial-port 3.0.4 → 3.0.6
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.
- package/README.md +8 -2
- package/binding.gyp +8 -1
- package/lib/bluetooth-serial-port.js +8 -0
- package/package.json +3 -1
- package/prebuilds/darwin-arm64/BluetoothSerialPort.abi108.node +0 -0
- package/prebuilds/darwin-arm64/BluetoothSerialPort.abi115.node +0 -0
- package/prebuilds/darwin-arm64/BluetoothSerialPort.abi127.node +0 -0
- package/prebuilds/darwin-arm64/BluetoothSerialPort.abi137.node +0 -0
- package/prebuilds/linux-arm64/BluetoothSerialPort.abi108.node +0 -0
- package/prebuilds/linux-arm64/BluetoothSerialPort.abi115.node +0 -0
- package/prebuilds/linux-arm64/BluetoothSerialPort.abi127.node +0 -0
- package/prebuilds/linux-arm64/BluetoothSerialPort.abi137.node +0 -0
- package/prebuilds/linux-arm64/BluetoothSerialPortServer.abi108.node +0 -0
- package/prebuilds/linux-arm64/BluetoothSerialPortServer.abi115.node +0 -0
- package/prebuilds/linux-arm64/BluetoothSerialPortServer.abi127.node +0 -0
- package/prebuilds/linux-arm64/BluetoothSerialPortServer.abi137.node +0 -0
- package/prebuilds/win32-x64/BluetoothSerialPort.abi108.node +0 -0
- package/prebuilds/win32-x64/BluetoothSerialPort.abi115.node +0 -0
- package/prebuilds/win32-x64/BluetoothSerialPort.abi127.node +0 -0
- package/prebuilds/win32-x64/BluetoothSerialPort.abi137.node +0 -0
- package/src/macos/BTSerialPortBinding.mm +1 -1
- package/src/macos/BluetoothWorker.mm +120 -20
- package/src/macos/DeviceINQ.mm +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
This piece of open source software is free (as in speech) to [use, modify and distribute](LICENSE.md), no strings attached. If this software saves you some cash and you want to do something for the good please consider making a donation to a [charity](https://www.doctorswithoutborders.org). Any charity will do. 🙏
|
|
6
6
|
|
|
7
|
-
>
|
|
7
|
+
> experimental macOS support is available again. Feedback (also when it is working as expected) would be highly apreciated.
|
|
8
8
|
|
|
9
9
|
> _DEPRECATED_ I am no longer actively maintaining this project. If you want to help out by adding support please contact me. It was a great experience maintaining this project for almost 8 years. It was great to see people step in to improve this project. Thank you all!
|
|
10
10
|
|
|
@@ -18,6 +18,7 @@ If you have any problems make sure to [checkout the FAQ](https://github.com/eelc
|
|
|
18
18
|
## New in the last releases
|
|
19
19
|
|
|
20
20
|
* Installs precompiled native artifacts
|
|
21
|
+
* Re-enables MacOS support
|
|
21
22
|
* Bumps dependencies
|
|
22
23
|
* Fixes memory leaks.
|
|
23
24
|
* Adds support for node 20, 22 and 24
|
|
@@ -60,11 +61,16 @@ sudo systemctl restart bluetooth
|
|
|
60
61
|
- Needs Visual Studio (Visual C++) and its command line tools for source builds.
|
|
61
62
|
- Needs Python installed and accessible from the command line path.
|
|
62
63
|
|
|
64
|
+
## Prerequisites on macOS
|
|
65
|
+
|
|
66
|
+
- Build prerequisites are only needed when no matching prebuilt binary is available.
|
|
67
|
+
- Install Xcode and Command Line Tools.
|
|
68
|
+
|
|
63
69
|
## Install
|
|
64
70
|
|
|
65
71
|
`npm install bluetooth-serial-port`
|
|
66
72
|
|
|
67
|
-
For Linux x64 and
|
|
73
|
+
For Linux x64/arm64, Windows x64, and macOS x64/arm64 on Node 18, 20, 22 and 24, installation first downloads a prebuilt native binary from GitHub Releases.
|
|
68
74
|
If a matching prebuild is unavailable, install falls back to a local `node-gyp` build.
|
|
69
75
|
|
|
70
76
|
## Test build Linux using docker
|
package/binding.gyp
CHANGED
|
@@ -11,6 +11,14 @@
|
|
|
11
11
|
'libraries': ['-lbluetooth'],
|
|
12
12
|
'cflags':['-std=c++11']
|
|
13
13
|
}],
|
|
14
|
+
[ 'OS=="mac"', {
|
|
15
|
+
'sources': ['src/macos/DeviceINQ.mm', 'src/macos/BluetoothWorker.mm', 'src/macos/pipe.c', 'src/macos/BluetoothDeviceResources.mm', 'src/macos/BluetoothSerialPort.mm', 'src/macos/BTSerialPortBinding.mm'],
|
|
16
|
+
'include_dirs' : [ "<!(node -e \"require('nan')\")", 'src', 'src/macos' ],
|
|
17
|
+
'libraries':['-framework Foundation', '-framework IOBluetooth', '-fobjc-arc'],
|
|
18
|
+
'cflags!': [ '-fno-exceptions' ],
|
|
19
|
+
'cflags_cc!': [ '-fno-exceptions' ],
|
|
20
|
+
'xcode_settings': { 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES', 'OTHER_CFLAGS': [ '-Wno-unused-function' ] }
|
|
21
|
+
}],
|
|
14
22
|
[ 'OS=="win"', {
|
|
15
23
|
'sources': [ 'src/windows/BluetoothSerialPort.cc', 'src/windows/DeviceINQ.cc', 'src/windows/BTSerialPortBinding.cc', 'src/windows/BluetoothHelpers.cc' ],
|
|
16
24
|
'include_dirs' : [ "<!(node -e \"require('nan')\")", 'src', 'src/windows' ],
|
|
@@ -32,4 +40,3 @@
|
|
|
32
40
|
}
|
|
33
41
|
] # end targets
|
|
34
42
|
}
|
|
35
|
-
|
|
@@ -51,6 +51,14 @@
|
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
BluetoothSerialPort.prototype.inquire = function () {
|
|
54
|
+
if (process.platform === 'darwin') {
|
|
55
|
+
var self = this;
|
|
56
|
+
setImmediate(function () {
|
|
57
|
+
self.inq.inquireSync(self.found, self.finish);
|
|
58
|
+
});
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
54
62
|
this.inq.inquire(this.found, this.finish);
|
|
55
63
|
};
|
|
56
64
|
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bluetooth-serial-port",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.6",
|
|
4
4
|
"description": "Bluetooth serial port communication for Node.js",
|
|
5
5
|
"author": "Eelco Cramer <eelco@hailendal.org>",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"bluetooth",
|
|
8
8
|
"serial port",
|
|
9
9
|
"rfcomm",
|
|
10
|
+
"darwin",
|
|
10
11
|
"linux",
|
|
11
12
|
"windows"
|
|
12
13
|
],
|
|
@@ -29,6 +30,7 @@
|
|
|
29
30
|
"prebuilds/"
|
|
30
31
|
],
|
|
31
32
|
"os": [
|
|
33
|
+
"darwin",
|
|
32
34
|
"linux",
|
|
33
35
|
"win32"
|
|
34
36
|
],
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -216,7 +216,7 @@ void BTSerialPortBinding::Init(Local<Object> target) {
|
|
|
216
216
|
t->InstanceTemplate()->SetInternalFieldCount(1);
|
|
217
217
|
t->SetClassName(Nan::New("BTSerialPortBinding").ToLocalChecked());
|
|
218
218
|
|
|
219
|
-
Isolate *isolate =
|
|
219
|
+
Isolate *isolate = Isolate::GetCurrent();
|
|
220
220
|
Local<Context> ctx = isolate->GetCurrentContext();
|
|
221
221
|
|
|
222
222
|
Nan::SetPrototypeMethod(t, "write", Write);
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
#include <v8.h>
|
|
21
21
|
#include <node.h>
|
|
22
|
+
#include <stdio.h>
|
|
22
23
|
#include <string.h>
|
|
23
24
|
#include <stdlib.h>
|
|
24
25
|
#include <unistd.h>
|
|
@@ -33,6 +34,8 @@
|
|
|
33
34
|
using namespace node;
|
|
34
35
|
using namespace v8;
|
|
35
36
|
|
|
37
|
+
static const CFTimeInterval INQUIRY_TIMEOUT_SECONDS = 20.0;
|
|
38
|
+
|
|
36
39
|
/** Private class for wrapping a pipe */
|
|
37
40
|
@interface Pipe : NSObject {
|
|
38
41
|
pipe_t *pipe;
|
|
@@ -60,6 +63,49 @@ using namespace v8;
|
|
|
60
63
|
@synthesize address;
|
|
61
64
|
@end
|
|
62
65
|
|
|
66
|
+
/** Stops the current run loop when inquiry completes. */
|
|
67
|
+
@interface DeviceInquiryRunLoopStopper : NSObject <IOBluetoothDeviceInquiryDelegate> {
|
|
68
|
+
@private
|
|
69
|
+
BOOL completed;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
- (BOOL)isCompleted;
|
|
73
|
+
|
|
74
|
+
@end
|
|
75
|
+
|
|
76
|
+
@implementation DeviceInquiryRunLoopStopper
|
|
77
|
+
|
|
78
|
+
- (id)init
|
|
79
|
+
{
|
|
80
|
+
self = [super init];
|
|
81
|
+
if (self != nil) {
|
|
82
|
+
completed = NO;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return self;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
- (BOOL)isCompleted
|
|
89
|
+
{
|
|
90
|
+
return completed;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
- (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry *)sender device:(IOBluetoothDevice *)device
|
|
94
|
+
{
|
|
95
|
+
(void)sender;
|
|
96
|
+
(void)device;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
- (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry *)sender error:(IOReturn)error aborted:(BOOL)aborted
|
|
100
|
+
{
|
|
101
|
+
(void)sender;
|
|
102
|
+
(void)error;
|
|
103
|
+
(void)aborted;
|
|
104
|
+
completed = YES;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@end
|
|
108
|
+
|
|
63
109
|
static NSMutableDictionary *instanceWorkers = nil;
|
|
64
110
|
static NSLock *globalConnectLock = nil;
|
|
65
111
|
|
|
@@ -260,21 +306,57 @@ static NSLock *globalConnectLock = nil;
|
|
|
260
306
|
- (void) inquireWithPipe: (pipe_t *)pipe
|
|
261
307
|
{
|
|
262
308
|
@synchronized(self) {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
309
|
+
if (inquiryProducer != NULL) {
|
|
310
|
+
pipe_producer_free(inquiryProducer);
|
|
311
|
+
inquiryProducer = NULL;
|
|
312
|
+
}
|
|
313
|
+
inquiryProducer = pipe_producer_new(pipe);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if ([NSThread isMainThread]) {
|
|
317
|
+
[self inquiryTask];
|
|
318
|
+
} else {
|
|
319
|
+
dispatch_sync(worker_queue, ^{
|
|
320
|
+
[self inquiryTask];
|
|
321
|
+
});
|
|
267
322
|
}
|
|
268
323
|
}
|
|
269
324
|
|
|
270
325
|
/** Worker task to the the inquiry */
|
|
271
326
|
- (void) inquiryTask
|
|
272
327
|
{
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
328
|
+
@autoreleasepool {
|
|
329
|
+
DeviceInquiryRunLoopStopper *stopper = [[DeviceInquiryRunLoopStopper alloc] init];
|
|
330
|
+
IOBluetoothDeviceInquiry *inquiry = [[IOBluetoothDeviceInquiry alloc] initWithDelegate:stopper];
|
|
331
|
+
|
|
332
|
+
if (inquiry == nil) {
|
|
333
|
+
[self completeInquiry];
|
|
334
|
+
[stopper release];
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
[inquiry setInquiryLength:10];
|
|
339
|
+
IOReturn startStatus = [inquiry start];
|
|
340
|
+
|
|
341
|
+
if (startStatus == kIOReturnSuccess) {
|
|
342
|
+
NSDate *deadline = [NSDate dateWithTimeIntervalSinceNow:INQUIRY_TIMEOUT_SECONDS];
|
|
343
|
+
while (![stopper isCompleted] && [deadline timeIntervalSinceNow] > 0) {
|
|
344
|
+
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:deadline];
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
[inquiry stop];
|
|
349
|
+
[inquiry setDelegate:nil];
|
|
350
|
+
|
|
351
|
+
NSArray *foundDevices = [inquiry foundDevices];
|
|
352
|
+
for (IOBluetoothDevice *device in foundDevices) {
|
|
353
|
+
[self emitInquiryDevice:device];
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
[self completeInquiry];
|
|
357
|
+
[inquiry release];
|
|
358
|
+
[stopper release];
|
|
359
|
+
}
|
|
278
360
|
}
|
|
279
361
|
|
|
280
362
|
/** Get the RFCOMM channel for a given device */
|
|
@@ -360,30 +442,48 @@ static NSLock *globalConnectLock = nil;
|
|
|
360
442
|
|
|
361
443
|
/** Called when the device inquiry completes */
|
|
362
444
|
- (void) deviceInquiryComplete: (IOBluetoothDeviceInquiry *) sender error: (IOReturn) error aborted: (BOOL) aborted
|
|
445
|
+
{
|
|
446
|
+
(void)sender;
|
|
447
|
+
(void)error;
|
|
448
|
+
(void)aborted;
|
|
449
|
+
[self completeInquiry];
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/** Called when a device has been found */
|
|
453
|
+
- (void) deviceInquiryDeviceFound: (IOBluetoothDeviceInquiry*) sender device: (IOBluetoothDevice*) device
|
|
454
|
+
{
|
|
455
|
+
(void)sender;
|
|
456
|
+
[self emitInquiryDevice:device];
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
- (void)completeInquiry
|
|
363
460
|
{
|
|
364
461
|
@synchronized(self) {
|
|
365
462
|
if (inquiryProducer != NULL) {
|
|
366
|
-
// free the producer so the main thread is signaled that the inquiry has been completed.
|
|
367
463
|
pipe_producer_free(inquiryProducer);
|
|
368
464
|
inquiryProducer = NULL;
|
|
369
465
|
}
|
|
370
466
|
}
|
|
371
467
|
}
|
|
372
468
|
|
|
373
|
-
|
|
374
|
-
- (void) deviceInquiryDeviceFound: (IOBluetoothDeviceInquiry*) sender device: (IOBluetoothDevice*) device
|
|
469
|
+
- (void)emitInquiryDevice:(IOBluetoothDevice *)device
|
|
375
470
|
{
|
|
376
471
|
@synchronized(self) {
|
|
377
|
-
if (inquiryProducer
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
strcpy(info->name, [[device addressString] UTF8String]);
|
|
472
|
+
if (inquiryProducer == NULL || device == nil) {
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
381
475
|
|
|
382
|
-
|
|
383
|
-
|
|
476
|
+
device_info_t info;
|
|
477
|
+
memset(&info, 0, sizeof(device_info_t));
|
|
384
478
|
|
|
385
|
-
|
|
386
|
-
|
|
479
|
+
const char *address = [[device addressString] UTF8String];
|
|
480
|
+
const char *name = [[device nameOrAddress] UTF8String];
|
|
481
|
+
|
|
482
|
+
snprintf(info.address, sizeof(info.address), "%s", address != NULL ? address : "");
|
|
483
|
+
snprintf(info.name, sizeof(info.name), "%s", name != NULL ? name : info.address);
|
|
484
|
+
|
|
485
|
+
// push the device data into the pipe to notify the main thread
|
|
486
|
+
pipe_push(inquiryProducer, &info, 1);
|
|
387
487
|
}
|
|
388
488
|
}
|
|
389
489
|
|
package/src/macos/DeviceINQ.mm
CHANGED
|
@@ -126,7 +126,7 @@ void DeviceINQ::Init(Local<Object> target) {
|
|
|
126
126
|
t->InstanceTemplate()->SetInternalFieldCount(1);
|
|
127
127
|
t->SetClassName(Nan::New("DeviceINQ").ToLocalChecked());
|
|
128
128
|
|
|
129
|
-
Isolate *isolate =
|
|
129
|
+
Isolate *isolate = Isolate::GetCurrent();
|
|
130
130
|
Local<Context> ctx = isolate->GetCurrentContext();
|
|
131
131
|
|
|
132
132
|
Nan::SetPrototypeMethod(t, "inquireSync", InquireSync);
|