🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

bare-bluetooth-android

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bare-bluetooth-android - npm Package Compare versions

Comparing version
0.0.0
to
0.1.0
binding.cc

Sorry, the diff of this file is too big to display

+1
module.exports = require.addon()
cmake_minimum_required(VERSION 4.0)
find_package(cmake-bare REQUIRED PATHS node_modules/cmake-bare)
find_package(cmake-fetch REQUIRED PATHS node_modules/cmake-fetch)
find_package(cmake-android REQUIRED PATHS node_modules/cmake-android)
project(bare_bluetooth_android C CXX)
use_java()
fetch_package("github:holepunchto/libjstl")
fetch_package("github:holepunchto/libjnitl")
add_bare_module(bare_bluetooth_android)
target_sources(
${bare_bluetooth_android}
PRIVATE
binding.cc
)
target_link_libraries(
${bare_bluetooth_android}
PUBLIC
jstl
jnitl
)
set_target_properties(
${bare_bluetooth_android}
PROPERTIES
C_STANDARD 11
CXX_STANDARD 20
CXX_SCAN_FOR_MODULES OFF
POSITION_INDEPENDENT_CODE ON
)
find_android_jar(android_jar)
set(CMAKE_JAVA_COMPILE_FLAGS --release 17)
add_dex(
bare_bluetooth_classes
SOURCES
lib/ScanCallback.java
lib/GattCallback.java
lib/GattServerCallback.java
lib/AdvertiseCallback.java
INCLUDE_JARS
${android_jar}
)
bare_target(target)
bare_module_target("." _module NAME _name)
install(
FILES
$<TARGET_PROPERTY:bare_bluetooth_classes,DEX_FILE>
DESTINATION ${target}/${_name}
)
export { default as L2CAPChannel } from './lib/channel'
export { default as Service, ServiceOptions } from './lib/service'
export { default as Characteristic, CharacteristicOptions } from './lib/characteristic'
export {
default as Server,
BluetoothState,
AdvertisingOptions,
ChannelOptions,
ReadRequest,
WriteRequest
} from './lib/server'
export { default as Central } from './lib/central'
export { default as Peripheral, PeripheralOptions } from './lib/peripheral'
exports.Central = require('./lib/central')
exports.Peripheral = require('./lib/peripheral')
exports.Server = require('./lib/server')
exports.L2CAPChannel = require('./lib/channel')
exports.Service = require('./lib/service')
exports.Characteristic = require('./lib/characteristic')
package to.holepunch.bare.bluetooth;
import android.bluetooth.le.AdvertiseSettings;
public final class AdvertiseCallback extends android.bluetooth.le.AdvertiseCallback {
private final long nativePointer;
public AdvertiseCallback(long nativePointer) {
this.nativePointer = nativePointer;
}
@Override
public void
onStartSuccess(AdvertiseSettings settingsInEffect) {
nativeOnStartSuccess(nativePointer, settingsInEffect);
}
@Override
public void
onStartFailure(int errorCode) {
nativeOnStartFailure(nativePointer, errorCode);
}
private static native void
nativeOnStartSuccess(long nativePointer, AdvertiseSettings settingsInEffect);
private static native void
nativeOnStartFailure(long nativePointer, int errorCode);
}
import { EventEmitter, EventMap } from 'bare-events'
import Peripheral from './peripheral'
export type BluetoothState = 'off' | 'turningOn' | 'on' | 'turningOff'
export interface CentralEventMap extends EventMap {
stateChange: [state: BluetoothState]
discover: [peripheral: Peripheral]
connect: [peripheral: Peripheral, error?: string]
disconnect: [peripheral: Peripheral | null, error?: string]
connectFail: [id: string, error: string]
scanFail: [errorCode: number]
}
export default class Central extends EventEmitter<CentralEventMap> {
constructor()
readonly state: BluetoothState
startScan(serviceUUIDs?: string[]): void
stopScan(): void
connect(peripheral: Peripheral): void
disconnect(peripheral: Peripheral): void
destroy(): void
static readonly STATE_OFF: number
static readonly STATE_TURNING_ON: number
static readonly STATE_ON: number
static readonly STATE_TURNING_OFF: number
}
const EventEmitter = require('bare-events')
const binding = require('../binding')
const Peripheral = require('./peripheral')
const STATES = {
[binding.STATE_OFF]: 'off',
[binding.STATE_TURNING_ON]: 'turningOn',
[binding.STATE_ON]: 'on',
[binding.STATE_TURNING_OFF]: 'turningOff'
}
module.exports = exports = class Central extends EventEmitter {
constructor() {
super()
this._handle = binding.centralInit(
this,
this._onstatechange,
this._ondiscover,
this._onconnect,
this._ondisconnect,
this._onconnectfail,
this._onscanfail
)
this._peripherals = new Map()
this._connected = new Map()
this._state = 'off'
}
get state() {
return this._state
}
startScan(serviceUUIDs, opts = {}) {
const uuids = serviceUUIDs ? serviceUUIDs.map((s) => binding.createUUID(s)) : null
const scanMode = opts.scanMode === undefined ? null : opts.scanMode
binding.centralStartScan(this._handle, uuids, scanMode)
}
stopScan() {
binding.centralStopScan(this._handle)
this._peripherals.clear()
}
connect(peripheral) {
binding.centralConnect(this._handle, peripheral.handle)
}
disconnect(peripheral) {
binding.centralDisconnect(this._handle, peripheral._connectHandle)
}
destroy() {
for (const peripheral of this._connected.values()) {
peripheral.destroy()
}
this._connected.clear()
binding.centralDestroy(this._handle)
}
[Symbol.for('bare.inspect')]() {
return {
__proto__: { constructor: Central },
state: this._state
}
}
_onstatechange(state) {
this._state = STATES[state] || 'off'
this.emit('stateChange', this._state)
}
_ondiscover(handle, id, name, rssi) {
let peripheral = this._peripherals.get(id)
if (peripheral) {
peripheral.handle = handle
peripheral.rssi = rssi
if (name) peripheral.name = name
} else {
peripheral = { handle, id, name, rssi }
this._peripherals.set(id, peripheral)
}
this.emit('discover', peripheral)
}
_onconnect(handle, id) {
const discovered = this._peripherals.get(id) || null
const peripheral = new Peripheral(handle, {
id,
name: discovered ? discovered.name : null,
connectHandle: handle
})
this._connected.set(id, peripheral)
this.emit('connect', peripheral)
}
_ondisconnect(id, error) {
const peripheral = this._connected.get(id) || null
if (peripheral) {
peripheral._ondisconnect(error || null)
peripheral.destroy()
}
this._connected.delete(id)
this.emit('disconnect', peripheral, error || null)
}
_onconnectfail(id, error) {
this.emit('connectFail', id, error)
}
_onscanfail(errorCode) {
this.emit('scanFail', errorCode)
}
}
exports.STATE_OFF = binding.STATE_OFF
exports.STATE_TURNING_ON = binding.STATE_TURNING_ON
exports.STATE_ON = binding.STATE_ON
exports.STATE_TURNING_OFF = binding.STATE_TURNING_OFF
exports.SCAN_MODE_OPPORTUNISTIC = binding.SCAN_MODE_OPPORTUNISTIC
exports.SCAN_MODE_LOW_POWER = binding.SCAN_MODE_LOW_POWER
exports.SCAN_MODE_BALANCED = binding.SCAN_MODE_BALANCED
exports.SCAN_MODE_LOW_LATENCY = binding.SCAN_MODE_LOW_LATENCY
import { Duplex } from 'bare-stream'
export default class L2CAPChannel extends Duplex {
constructor(channelHandle: ArrayBuffer)
readonly psm: number
readonly peer: string | null
}
const { Duplex } = require('bare-stream')
const binding = require('../binding')
module.exports = exports = class L2CAPChannel extends Duplex {
constructor(channelHandle) {
super({
allowHalfOpen: false
})
this._channelHandle = channelHandle
this._handle = binding.l2capInit(
channelHandle,
this,
this._ondata,
this._ondrain,
this._onend,
this._onerror,
this._onclose,
this._onopen
)
}
get psm() {
return binding.l2capPsm(this._handle)
}
get peer() {
return binding.l2capPeer(this._handle)
}
_open(cb) {
binding.l2capOpen(this._handle)
cb()
}
_write(chunk, _encoding, cb) {
const bytesWritten = binding.l2capWrite(this._handle, chunk)
if (bytesWritten === 0) {
cb(new Error('Channel not ready or destroyed'))
} else {
cb(null)
}
}
_destroy(err, cb) {
binding.l2capEnd(this._handle)
cb(err)
}
[Symbol.for('bare.inspect')]() {
return {
__proto__: { constructor: L2CAPChannel },
destroyed: this.destroyed
}
}
_ondata(data) {
this.push(data)
}
_ondrain() {
this.emit('drain')
}
_onend() {
this.push(null)
}
_onerror(message) {
this.emit('error', new Error(message))
}
_onclose() {
this.emit('close')
}
_onopen() {
this.emit('open')
}
}
export default class Characteristic {
constructor(uuid: string, opts?: CharacteristicOptions)
readonly uuid: string
readonly properties: number
readonly permissions: number | null
value: Uint8Array | null
static readonly PROPERTY_READ: number
static readonly PROPERTY_WRITE_WITHOUT_RESPONSE: number
static readonly PROPERTY_WRITE: number
static readonly PROPERTY_NOTIFY: number
static readonly PROPERTY_INDICATE: number
}
export interface CharacteristicOptions {
read?: boolean
write?: boolean
writeWithoutResponse?: boolean
notify?: boolean
indicate?: boolean
permissions?: number
value?: Uint8Array | null
}
module.exports = exports = class Characteristic {
constructor(uuid, opts = {}) {
this._uuid = uuid
this._properties = 0
this._permissions = opts.permissions === undefined ? null : opts.permissions
this._handle = null
this._value = opts.value || null
if (opts.read) this._properties |= Characteristic.PROPERTY_READ
if (opts.write) this._properties |= Characteristic.PROPERTY_WRITE
if (opts.writeWithoutResponse) {
this._properties |= Characteristic.PROPERTY_WRITE_WITHOUT_RESPONSE
}
if (opts.notify) this._properties |= Characteristic.PROPERTY_NOTIFY
if (opts.indicate) this._properties |= Characteristic.PROPERTY_INDICATE
}
get uuid() {
return this._uuid
}
get properties() {
return this._properties
}
get permissions() {
return this._permissions
}
get value() {
return this._value
}
set value(val) {
this._value = val
}
[Symbol.for('bare.inspect')]() {
return {
__proto__: { constructor: Characteristic },
uuid: this._uuid
}
}
}
exports.PROPERTY_READ = 0x02
exports.PROPERTY_WRITE_WITHOUT_RESPONSE = 0x04
exports.PROPERTY_WRITE = 0x08
exports.PROPERTY_NOTIFY = 0x10
exports.PROPERTY_INDICATE = 0x20
package to.holepunch.bare.bluetooth;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
public final class GattCallback extends android.bluetooth.BluetoothGattCallback {
private final long nativePointer;
public GattCallback(long nativePointer) {
this.nativePointer = nativePointer;
}
@Override
public void
onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
nativeOnConnectionStateChange(nativePointer, gatt, status, newState);
}
@Override
public void
onServicesDiscovered(BluetoothGatt gatt, int status) {
nativeOnServicesDiscovered(nativePointer, gatt, status);
}
@Override
public void
onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, byte[] value, int status) {
nativeOnCharacteristicRead(nativePointer, gatt, characteristic, value, status);
}
@Override
public void
onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
nativeOnCharacteristicWrite(nativePointer, gatt, characteristic, status);
}
@Override
public void
onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, byte[] value) {
nativeOnCharacteristicChanged(nativePointer, gatt, characteristic, value);
}
@Override
public void
onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
nativeOnDescriptorWrite(nativePointer, gatt, descriptor, status);
}
@Override
public void
onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
nativeOnMtuChanged(nativePointer, gatt, mtu, status);
}
private static native void
nativeOnConnectionStateChange(long nativePointer, BluetoothGatt gatt, int status, int newState);
private static native void
nativeOnServicesDiscovered(long nativePointer, BluetoothGatt gatt, int status);
private static native void
nativeOnCharacteristicRead(long nativePointer, BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, byte[] value, int status);
private static native void
nativeOnCharacteristicWrite(long nativePointer, BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status);
private static native void
nativeOnCharacteristicChanged(long nativePointer, BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, byte[] value);
private static native void
nativeOnDescriptorWrite(long nativePointer, BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status);
private static native void
nativeOnMtuChanged(long nativePointer, BluetoothGatt gatt, int mtu, int status);
}
package to.holepunch.bare.bluetooth;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattService;
public final class GattServerCallback extends android.bluetooth.BluetoothGattServerCallback {
private final long nativePointer;
public GattServerCallback(long nativePointer) {
this.nativePointer = nativePointer;
}
@Override
public void
onConnectionStateChange(BluetoothDevice device, int status, int newState) {
nativeOnConnectionStateChange(nativePointer, device, status, newState);
}
@Override
public void
onServiceAdded(int status, BluetoothGattService service) {
nativeOnServiceAdded(nativePointer, status, service);
}
@Override
public void
onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
nativeOnCharacteristicReadRequest(nativePointer, device, requestId, offset, characteristic);
}
@Override
public void
onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
nativeOnCharacteristicWriteRequest(nativePointer, device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
}
@Override
public void
onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
nativeOnDescriptorWriteRequest(nativePointer, device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
}
@Override
public void
onNotificationSent(BluetoothDevice device, int status) {
nativeOnNotificationSent(nativePointer, device, status);
}
private static native void
nativeOnConnectionStateChange(long nativePointer, BluetoothDevice device, int status, int newState);
private static native void
nativeOnServiceAdded(long nativePointer, int status, BluetoothGattService service);
private static native void
nativeOnCharacteristicReadRequest(long nativePointer, BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic);
private static native void
nativeOnCharacteristicWriteRequest(long nativePointer, BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value);
private static native void
nativeOnDescriptorWriteRequest(long nativePointer, BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value);
private static native void
nativeOnNotificationSent(long nativePointer, BluetoothDevice device, int status);
}
import { EventEmitter, EventMap } from 'bare-events'
import Service from './service'
import Characteristic from './characteristic'
import L2CAPChannel from './channel'
export interface PeripheralOptions {
connectHandle?: ArrayBuffer
id?: string
name?: string
}
export interface PeripheralEventMap extends EventMap {
servicesDiscover: [services: Service[] | null, error?: string]
characteristicsDiscover: [
service: string,
characteristics: Characteristic[] | null,
error?: string
]
read: [characteristic: string, data: Uint8Array, error?: string]
write: [characteristic: string, error?: string]
notify: [characteristic: string, data: Uint8Array, error?: string]
notifyState: [characteristic: string, isNotifying: boolean, error?: string]
channelOpen: [channel: L2CAPChannel | null, error?: string]
mtuChanged: [mtu: number, error?: string]
}
export default class Peripheral extends EventEmitter<PeripheralEventMap> {
constructor(peripheralHandle: ArrayBuffer, opts?: PeripheralOptions)
readonly id: string
readonly name: string | null
discoverServices(): void
discoverCharacteristics(service: string): void
read(characteristic: string): void
write(characteristic: string, data: Uint8Array, withResponse?: boolean): void
subscribe(characteristic: string): void
unsubscribe(characteristic: string): void
openL2CAPChannel(psm: number): void
requestMtu(mtu: number): void
destroy(): void
static readonly PROPERTY_READ: number
static readonly PROPERTY_WRITE_WITHOUT_RESPONSE: number
static readonly PROPERTY_WRITE: number
static readonly PROPERTY_NOTIFY: number
static readonly PROPERTY_INDICATE: number
}
const EventEmitter = require('bare-events')
const binding = require('../binding')
const Service = require('./service')
const Characteristic = require('./characteristic')
const L2CAPChannel = require('./channel')
module.exports = exports = class Peripheral extends EventEmitter {
constructor(peripheralHandle, opts = {}) {
super()
this._peripheralHandle = peripheralHandle
this._connectHandle = opts.connectHandle || null
this._id = opts.id || null
this._name = opts.name === undefined ? null : opts.name
this._destroyed = false
this._services = new Map()
this._characteristics = new Map()
this._characteristicsByHandle = new Map()
this._handle = binding.peripheralInit(
peripheralHandle,
this,
this._onservicesdiscover,
this._oncharacteristicsdiscover,
this._onread,
this._onwrite,
this._onnotify,
this._onnotifystate,
this._onchannelopen,
this._onmtuchanged
)
if (this._id === null) this._id = binding.peripheralId(this._handle)
if (opts.name === undefined) this._name = binding.peripheralName(this._handle)
}
get id() {
return this._id
}
get name() {
return this._name
}
discoverServices() {
return binding.peripheralDiscoverServices(this._handle)
}
discoverCharacteristics(service) {
binding.peripheralDiscoverCharacteristics(this._handle, service._handle)
}
read(characteristic) {
return binding.peripheralRead(this._handle, characteristic._handle)
}
write(characteristic, data, withResponse) {
if (withResponse === undefined) withResponse = true
return binding.peripheralWrite(this._handle, characteristic._handle, data, withResponse)
}
subscribe(characteristic) {
return binding.peripheralSubscribe(this._handle, characteristic._handle)
}
unsubscribe(characteristic) {
return binding.peripheralUnsubscribe(this._handle, characteristic._handle)
}
openL2CAPChannel(psm) {
binding.peripheralOpenL2CAPChannel(this._handle, psm)
}
requestMtu(mtu) {
return binding.peripheralRequestMtu(this._handle, mtu)
}
destroy() {
if (this._destroyed) return
this._destroyed = true
this._connectHandle = null
binding.peripheralDestroy(this._handle)
}
[Symbol.for('bare.inspect')]() {
return {
__proto__: { constructor: Peripheral },
id: this.id,
name: this.name
}
}
_onservicesdiscover(count, error) {
if (error) {
this.emit('servicesDiscover', null, error)
return
}
const services = []
for (let i = 0; i < count; i++) {
const handle = binding.peripheralServiceAtIndex(this._handle, i)
const serviceKey = binding.serviceKey(handle)
const uuid = binding.serviceUuid(handle)
let service = this._services.get(serviceKey)
if (!service) {
service = new Service(uuid)
service._handle = handle
service._key = serviceKey
this._services.set(serviceKey, service)
} else {
service._handle = handle
}
services.push(service)
}
this.emit('servicesDiscover', services, null)
}
_oncharacteristicsdiscover(serviceHandle, count, error) {
const serviceKey = binding.serviceKey(serviceHandle)
const service = this._services.get(serviceKey) || null
if (error) {
this.emit('characteristicsDiscover', service, null, error)
return
}
const characteristics = []
for (let i = 0; i < count; i++) {
const handle = binding.serviceCharacteristicAtIndex(serviceHandle, i)
const handleKey = binding.characteristicKey(handle)
const characteristicKey = serviceKey + ':' + handleKey
const uuid = binding.characteristicUuid(handle)
const properties = binding.characteristicProperties(handle)
let characteristic = this._characteristics.get(characteristicKey)
if (!characteristic) {
characteristic = new Characteristic(uuid)
characteristic._handle = handle
characteristic._properties = properties
characteristic._key = characteristicKey
characteristic._serviceKey = serviceKey
characteristic._handleKey = handleKey
this._characteristics.set(characteristicKey, characteristic)
} else {
characteristic._handle = handle
characteristic._properties = properties
}
this._characteristicsByHandle.set(handleKey, characteristic)
characteristics.push(characteristic)
}
if (service) {
service._characteristics = characteristics
}
this.emit('characteristicsDiscover', service, characteristics, null)
}
_onread(charHandle, uuid, data, error) {
const characteristic =
this._characteristicsByHandle.get(binding.characteristicKey(charHandle)) || null
this.emit('read', characteristic, data, error)
}
_onwrite(charHandle, uuid, error) {
const characteristic =
this._characteristicsByHandle.get(binding.characteristicKey(charHandle)) || null
this.emit('write', characteristic, error)
}
_onnotify(uuid, data, error) {
const characteristic = this._characteristicsByHandle.get(uuid) || null
this.emit('notify', characteristic, data, error)
}
_onnotifystate(charHandle, uuid, isNotifying, error) {
const characteristic =
this._characteristicsByHandle.get(binding.characteristicKey(charHandle)) || null
this.emit('notifyState', characteristic, isNotifying, error)
}
_ondisconnect() {
this._connectHandle = null
}
_onchannelopen(channelHandle, error) {
if (error || !channelHandle) {
this.emit('channelOpen', null, error)
return
}
const channel = new L2CAPChannel(channelHandle)
this.emit('channelOpen', channel, null)
}
_onmtuchanged(mtu, error) {
this.emit('mtuChanged', mtu, error)
}
}
exports.PROPERTY_READ = binding.PROPERTY_READ
exports.PROPERTY_WRITE_WITHOUT_RESPONSE = binding.PROPERTY_WRITE_WITHOUT_RESPONSE
exports.PROPERTY_WRITE = binding.PROPERTY_WRITE
exports.PROPERTY_NOTIFY = binding.PROPERTY_NOTIFY
exports.PROPERTY_INDICATE = binding.PROPERTY_INDICATE
package to.holepunch.bare.bluetooth;
import android.bluetooth.le.ScanResult;
public final class ScanCallback extends android.bluetooth.le.ScanCallback {
private final long nativePointer;
public ScanCallback(long nativePointer) {
this.nativePointer = nativePointer;
}
@Override
public void
onScanResult(int callbackType, ScanResult result) {
nativeOnScanResult(nativePointer, callbackType, result);
}
@Override
public void
onScanFailed(int errorCode) {
nativeOnScanFailed(nativePointer, errorCode);
}
private static native void
nativeOnScanResult(long nativePointer, int callbackType, ScanResult result);
private static native void
nativeOnScanFailed(long nativePointer, int errorCode);
}
import { EventEmitter, EventMap } from 'bare-events'
import Service from './service'
import Characteristic from './characteristic'
import L2CAPChannel from './channel'
export type BluetoothState = 'off' | 'turningOn' | 'on' | 'turningOff'
export interface AdvertisingOptions {
name?: string
serviceUUIDs?: string[]
}
export interface ChannelOptions {
encrypted?: boolean
}
export interface ReadRequest {
characteristicUuid: string
offset: number
}
export interface WriteRequest {
characteristicUuid: string
data: Uint8Array
}
export interface ServerEventMap extends EventMap {
stateChange: [state: BluetoothState]
addService: [uuid: string, error?: string]
channelPublish: [psm: number, error?: string]
channelOpen: [channel: L2CAPChannel | null, error?: string]
readRequest: [request: ReadRequest]
writeRequests: [requests: WriteRequest[]]
subscribe: [deviceAddress: string, characteristicUuid: string]
unsubscribe: [deviceAddress: string, characteristicUuid: string]
advertiseError: [errorCode: number, error: string]
}
declare class Server extends EventEmitter<ServerEventMap> {
constructor()
readonly state: BluetoothState
addService(service: Service): void
startAdvertising(opts?: AdvertisingOptions): void
stopAdvertising(): void
respondToRequest(request: ReadRequest, result: number, data?: Uint8Array | null): void
updateValue(characteristic: Characteristic, data: Uint8Array): boolean
publishChannel(opts?: ChannelOptions): void
unpublishChannel(psm: number): void
destroy(): void
static readonly STATE_OFF: number
static readonly STATE_TURNING_ON: number
static readonly STATE_ON: number
static readonly STATE_TURNING_OFF: number
static readonly PROPERTY_READ: number
static readonly PROPERTY_WRITE_WITHOUT_RESPONSE: number
static readonly PROPERTY_WRITE: number
static readonly PROPERTY_NOTIFY: number
static readonly PROPERTY_INDICATE: number
static readonly PERMISSION_READABLE: number
static readonly PERMISSION_WRITEABLE: number
static readonly PERMISSION_READ_ENCRYPTED: number
static readonly PERMISSION_WRITE_ENCRYPTED: number
static readonly ATT_SUCCESS: number
static readonly ATT_INVALID_HANDLE: number
static readonly ATT_READ_NOT_PERMITTED: number
static readonly ATT_WRITE_NOT_PERMITTED: number
static readonly ATT_INSUFFICIENT_RESOURCES: number
static readonly ATT_UNLIKELY_ERROR: number
}
export default Server
const EventEmitter = require('bare-events')
const binding = require('../binding')
const L2CAPChannel = require('./channel')
const STATES = {
[binding.STATE_OFF]: 'off',
[binding.STATE_TURNING_ON]: 'turningOn',
[binding.STATE_ON]: 'on',
[binding.STATE_TURNING_OFF]: 'turningOff'
}
module.exports = exports = class Server extends EventEmitter {
constructor() {
super()
this._state = 'off'
this._handle = binding.serverInit(
this,
this._onstatechange,
this._onaddservice,
this._onreadrequest,
this._onwriterequest,
this._onsubscribe,
this._onunsubscribe,
this._onadvertiseerror,
this._onchannelpublish,
this._onchannelopen,
this._onnotifysent
)
}
get state() {
return this._state
}
addService(service) {
const charHandles = []
for (const char of service.characteristics) {
let permissions = char.permissions
if (permissions === null) {
permissions = 0
if (char.properties & exports.PROPERTY_READ) {
permissions |= exports.PERMISSION_READABLE
}
if (char.properties & (exports.PROPERTY_WRITE | exports.PROPERTY_WRITE_WITHOUT_RESPONSE)) {
permissions |= exports.PERMISSION_WRITEABLE
}
}
const uuid = binding.createUUID(char.uuid)
char._handle = binding.createMutableCharacteristic(
uuid,
char.properties,
permissions,
char.value || null
)
charHandles.push(char._handle)
}
const serviceUuid = binding.createUUID(service.uuid)
const serviceHandle = binding.createMutableService(serviceUuid, service.primary)
binding.serviceSetCharacteristics(serviceHandle, charHandles)
binding.serverAddService(this._handle, serviceHandle)
}
startAdvertising(opts = {}) {
const uuids = opts.serviceUUIDs ? opts.serviceUUIDs.map((s) => binding.createUUID(s)) : null
binding.serverStartAdvertising(this._handle, opts.name || null, uuids)
}
stopAdvertising() {
binding.serverStopAdvertising(this._handle)
}
respondToRequest(request, result, data) {
binding.serverRespondToRequest(
this._handle,
request.handle,
request.requestId,
result,
request.offset,
data || null
)
}
updateValue(characteristic, data) {
return binding.serverUpdateValue(this._handle, characteristic._handle, data)
}
publishChannel(opts = {}) {
binding.serverPublishChannel(this._handle, opts.encrypted || false)
}
unpublishChannel(psm) {
binding.serverUnpublishChannel(this._handle, psm)
}
destroy() {
binding.serverDestroy(this._handle)
}
[Symbol.for('bare.inspect')]() {
return {
__proto__: { constructor: Server },
state: this._state
}
}
_onstatechange(state) {
this._state = STATES[state] || 'off'
this.emit('stateChange', this._state)
}
_onaddservice(uuid, error) {
this.emit('serviceAdd', uuid, error)
}
_onreadrequest(requestHandle, requestId, characteristicUuid, offset) {
this.emit('readRequest', {
handle: requestHandle,
requestId,
characteristicUuid,
offset
})
}
_onwriterequest(requestHandle, requestId, characteristicUuid, offset, data, responseNeeded) {
this.emit('writeRequest', [
{
handle: requestHandle,
requestId,
characteristicUuid,
data,
offset,
responseNeeded
}
])
}
_onsubscribe(deviceAddress, characteristicUuid) {
this.emit('subscribe', deviceAddress, characteristicUuid)
}
_onunsubscribe(deviceAddress, characteristicUuid) {
this.emit('unsubscribe', deviceAddress, characteristicUuid)
}
_onadvertiseerror(errorCode, error) {
this.emit('advertiseError', errorCode, error)
}
_onchannelpublish(psm, error) {
this.emit('channelPublish', psm, error)
}
_onchannelopen(channelHandle, error) {
if (error || !channelHandle) {
this.emit('channelOpen', null, error)
return
}
const channel = new L2CAPChannel(channelHandle)
this.emit('channelOpen', channel, null)
}
_onnotifysent(deviceAddress, status) {
this.emit('notifySent', deviceAddress, status)
}
}
exports.STATE_OFF = binding.STATE_OFF
exports.STATE_TURNING_ON = binding.STATE_TURNING_ON
exports.STATE_ON = binding.STATE_ON
exports.STATE_TURNING_OFF = binding.STATE_TURNING_OFF
exports.PROPERTY_READ = binding.PROPERTY_READ
exports.PROPERTY_WRITE_WITHOUT_RESPONSE = binding.PROPERTY_WRITE_WITHOUT_RESPONSE
exports.PROPERTY_WRITE = binding.PROPERTY_WRITE
exports.PROPERTY_NOTIFY = binding.PROPERTY_NOTIFY
exports.PROPERTY_INDICATE = binding.PROPERTY_INDICATE
exports.PERMISSION_READABLE = binding.PERMISSION_READABLE
exports.PERMISSION_WRITEABLE = binding.PERMISSION_WRITEABLE
exports.PERMISSION_READ_ENCRYPTED = binding.PERMISSION_READ_ENCRYPTED
exports.PERMISSION_WRITE_ENCRYPTED = binding.PERMISSION_WRITE_ENCRYPTED
exports.ATT_SUCCESS = binding.ATT_SUCCESS
exports.ATT_INVALID_HANDLE = binding.ATT_INVALID_HANDLE
exports.ATT_READ_NOT_PERMITTED = binding.ATT_READ_NOT_PERMITTED
exports.ATT_WRITE_NOT_PERMITTED = binding.ATT_WRITE_NOT_PERMITTED
exports.ATT_INSUFFICIENT_RESOURCES = binding.ATT_INSUFFICIENT_RESOURCES
exports.ATT_UNLIKELY_ERROR = binding.ATT_UNLIKELY_ERROR
import Characteristic from './characteristic'
export default class Service {
constructor(uuid: string, characteristics?: Characteristic[], opts?: ServiceOptions)
readonly uuid: string
readonly characteristics: Characteristic[]
readonly primary: boolean
}
export interface ServiceOptions {
primary?: boolean
}
module.exports = class Service {
constructor(uuid, characteristics, opts = {}) {
this._uuid = uuid
this._characteristics = characteristics || []
this._primary = opts.primary !== false
this._handle = null
}
get uuid() {
return this._uuid
}
get characteristics() {
return this._characteristics
}
get primary() {
return this._primary
}
[Symbol.for('bare.inspect')]() {
return {
__proto__: { constructor: Service },
uuid: this._uuid
}
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

# bare-bluetooth-android
Android Bluetooth Low Energy (BLE) bindings for Bare, providing both central and peripheral roles. Built on the Android Bluetooth API.
```
npm i bare-bluetooth-android
```
## Usage
```js
const { Central } = require('bare-bluetooth-android')
const central = new Central()
central.on('stateChange', (state) => {
if (state === 'on') {
central.startScan(['180D']) // Heart Rate service UUID
}
})
central.on('discover', (peripheral) => {
console.log('Found:', peripheral.name, peripheral.id)
central.stopScan()
central.connect(peripheral)
})
central.on('connect', (peripheral) => {
peripheral.discoverServices()
peripheral.on('servicesDiscover', (services) => {
// Discover characteristics for each service
})
})
```
## API
#### `const central = new Central()`
Create a new BLE central manager for scanning and connecting to peripherals.
#### `central.state`
The current Bluetooth adapter state. One of `'off'`, `'turningOn'`, `'on'`, or `'turningOff'`.
#### `central.startScan(serviceUUIDs[, opts])`
Start scanning for peripherals advertising the given `serviceUUIDs`. Pass `null` to scan for all peripherals.
Options include:
```js
opts = {
scanMode: null
}
```
Set `scanMode` to one of `Central.SCAN_MODE_OPPORTUNISTIC`, `Central.SCAN_MODE_LOW_POWER`, `Central.SCAN_MODE_BALANCED`, or `Central.SCAN_MODE_LOW_LATENCY`.
#### `central.stopScan()`
Stop scanning for peripherals.
#### `central.connect(peripheral)`
Connect to a discovered `peripheral`.
#### `central.disconnect(peripheral)`
Disconnect from a connected `peripheral`.
#### `central.destroy()`
Destroy the central manager, disconnecting all connected peripherals.
#### `event: 'stateChange'`
Emitted when the Bluetooth adapter state changes. The listener receives the new `state` string.
#### `event: 'discover'`
Emitted when a peripheral is discovered during scanning. The listener receives a `peripheral` object with `handle`, `id`, `name`, and `rssi` properties.
#### `event: 'connect'`
Emitted when a connection to a peripheral is established. The listener receives a `Peripheral` instance.
#### `event: 'disconnect'`
Emitted when a peripheral disconnects. The listener receives the `peripheral` and an optional `error`.
#### `event: 'connectFail'`
Emitted when a connection attempt fails. The listener receives the peripheral `id` and an `error`.
#### `event: 'scanFail'`
Emitted when scanning fails. The listener receives the `errorCode`.
#### `Central.SCAN_MODE_OPPORTUNISTIC`
#### `Central.SCAN_MODE_LOW_POWER`
#### `Central.SCAN_MODE_BALANCED`
#### `Central.SCAN_MODE_LOW_LATENCY`
Scan mode constants for use with `central.startScan()`.
#### `const peripheral = new Peripheral(peripheralHandle[, opts])`
Create a new peripheral instance. Typically obtained via the `'connect'` event on `Central` rather than constructed directly.
Options include:
```js
opts = {
connectHandle: null,
id: null,
name: null
}
```
#### `peripheral.id`
The unique identifier of the peripheral.
#### `peripheral.name`
The advertised name of the peripheral, or `null` if unavailable.
#### `peripheral.discoverServices()`
Discover services offered by the peripheral. Results are emitted via the `'servicesDiscover'` event.
#### `peripheral.discoverCharacteristics(service)`
Discover characteristics for the given `service`. Results are emitted via the `'characteristicsDiscover'` event.
#### `peripheral.read(characteristic)`
Read the value of `characteristic`. The result is emitted via the `'read'` event.
#### `peripheral.write(characteristic, data[, withResponse])`
Write `data` to `characteristic`. If `withResponse` is `true` (the default), a write confirmation is requested.
#### `peripheral.subscribe(characteristic)`
Subscribe to notifications for `characteristic`.
#### `peripheral.unsubscribe(characteristic)`
Unsubscribe from notifications for `characteristic`.
#### `peripheral.openL2CAPChannel(psm)`
Open an L2CAP channel to the peripheral using the given `psm`. The result is emitted via the `'channelOpen'` event.
#### `peripheral.requestMtu(mtu)`
Request a new MTU size. The result is emitted via the `'mtuChanged'` event.
#### `peripheral.destroy()`
Destroy the peripheral instance.
#### `event: 'servicesDiscover'`
Emitted when services are discovered. The listener receives an array of `Service` instances and an optional `error`.
#### `event: 'characteristicsDiscover'`
Emitted when characteristics are discovered. The listener receives the `service`, an array of `Characteristic` instances, and an optional `error`.
#### `event: 'read'`
Emitted when a characteristic read completes. The listener receives the `characteristic`, `data`, and an optional `error`.
#### `event: 'write'`
Emitted when a characteristic write completes. The listener receives the `characteristic` and an optional `error`.
#### `event: 'notify'`
Emitted when a characteristic notification is received. The listener receives the `characteristic`, `data`, and an optional `error`.
#### `event: 'notifyState'`
Emitted when the notification state changes. The listener receives the `characteristic`, `isNotifying`, and an optional `error`.
#### `event: 'channelOpen'`
Emitted when an L2CAP channel is opened. The listener receives an `L2CAPChannel` instance or `null`, and an optional `error`.
#### `event: 'mtuChanged'`
Emitted when the MTU is changed. The listener receives the new `mtu` and an optional `error`.
#### `Peripheral.PROPERTY_READ`
#### `Peripheral.PROPERTY_WRITE_WITHOUT_RESPONSE`
#### `Peripheral.PROPERTY_WRITE`
#### `Peripheral.PROPERTY_NOTIFY`
#### `Peripheral.PROPERTY_INDICATE`
Characteristic property constants.
#### `const server = new Server()`
Create a new BLE peripheral server for advertising services and handling client requests.
#### `server.state`
The current Bluetooth adapter state. One of `'off'`, `'turningOn'`, `'on'`, or `'turningOff'`.
#### `server.addService(service)`
Add a `service` to the GATT server. The `'serviceAdd'` event is emitted when the service has been registered.
#### `server.startAdvertising([opts])`
Start advertising the server.
Options include:
```js
opts = {
name: null,
serviceUUIDs: null
}
```
#### `server.stopAdvertising()`
Stop advertising.
#### `server.respondToRequest(request, result[, data])`
Respond to a read or write `request` with a `result` code and optional `data`. Use the `Server.ATT_*` constants for the result.
#### `server.updateValue(characteristic, data)`
Update the value of `characteristic` with `data` and notify subscribed clients. Returns `true` if the notification was sent successfully.
#### `server.publishChannel([opts])`
Publish an L2CAP channel. The `'channelPublish'` event is emitted with the assigned PSM.
Options include:
```js
opts = {
encrypted: false
}
```
#### `server.unpublishChannel(psm)`
Unpublish an L2CAP channel with the given `psm`.
#### `server.destroy()`
Destroy the server.
#### `event: 'stateChange'`
Emitted when the Bluetooth adapter state changes. The listener receives the new `state` string.
#### `event: 'serviceAdd'`
Emitted when a service is added. The listener receives the `uuid` and an optional `error`.
#### `event: 'readRequest'`
Emitted when a client reads a characteristic. The listener receives a `request` object with `handle`, `requestId`, `characteristicUuid`, and `offset` properties.
#### `event: 'writeRequest'`
Emitted when a client writes to a characteristic. The listener receives an array of request objects, each with `handle`, `requestId`, `characteristicUuid`, `data`, `offset`, and `responseNeeded` properties.
#### `event: 'subscribe'`
Emitted when a client subscribes to notifications. The listener receives `deviceAddress` and `characteristicUuid`.
#### `event: 'unsubscribe'`
Emitted when a client unsubscribes from notifications. The listener receives `deviceAddress` and `characteristicUuid`.
#### `event: 'advertiseError'`
Emitted when advertising fails. The listener receives `errorCode` and `error`.
#### `event: 'channelPublish'`
Emitted when an L2CAP channel is published. The listener receives the `psm` and an optional `error`.
#### `event: 'channelOpen'`
Emitted when an L2CAP channel is opened by a client. The listener receives an `L2CAPChannel` instance or `null`, and an optional `error`.
#### `event: 'notifySent'`
Emitted when a notification is delivered. The listener receives `deviceAddress` and `status`.
#### `Server.PROPERTY_READ`
#### `Server.PROPERTY_WRITE_WITHOUT_RESPONSE`
#### `Server.PROPERTY_WRITE`
#### `Server.PROPERTY_NOTIFY`
#### `Server.PROPERTY_INDICATE`
Characteristic property constants.
#### `Server.PERMISSION_READABLE`
#### `Server.PERMISSION_WRITEABLE`
#### `Server.PERMISSION_READ_ENCRYPTED`
#### `Server.PERMISSION_WRITE_ENCRYPTED`
Characteristic permission constants.
#### `Server.ATT_SUCCESS`
#### `Server.ATT_INVALID_HANDLE`
#### `Server.ATT_READ_NOT_PERMITTED`
#### `Server.ATT_WRITE_NOT_PERMITTED`
#### `Server.ATT_INSUFFICIENT_RESOURCES`
#### `Server.ATT_UNLIKELY_ERROR`
ATT result codes for use with `server.respondToRequest()`.
#### `const channel = new L2CAPChannel(channelHandle)`
A duplex stream representing an L2CAP connection-oriented channel. Extends `Duplex` from <https://github.com/holepunchto/bare-stream>. Typically obtained via the `'channelOpen'` event rather than constructed directly.
#### `channel.psm`
The Protocol/Service Multiplexer number of the channel.
#### `channel.peer`
The address of the remote peer, or `null`.
#### `const service = new Service(uuid[, characteristics][, opts])`
Create a new GATT service definition.
Options include:
```js
opts = {
primary: true
}
```
#### `service.uuid`
The UUID of the service.
#### `service.characteristics`
The array of characteristics belonging to the service.
#### `service.primary`
Whether the service is a primary service.
#### `const characteristic = new Characteristic(uuid[, opts])`
Create a new GATT characteristic definition.
Options include:
```js
opts = {
read: false,
write: false,
writeWithoutResponse: false,
notify: false,
indicate: false,
permissions: null,
value: null
}
```
Set `read`, `write`, `writeWithoutResponse`, `notify`, and `indicate` to configure the characteristic properties. If `permissions` is `null`, permissions are inferred from the properties.
#### `characteristic.uuid`
The UUID of the characteristic.
#### `characteristic.properties`
The property flags of the characteristic.
#### `characteristic.permissions`
The permission flags of the characteristic, or `null` if inferred.
#### `characteristic.value`
The current value of the characteristic, or `null`.
#### `Characteristic.PROPERTY_READ`
#### `Characteristic.PROPERTY_WRITE_WITHOUT_RESPONSE`
#### `Characteristic.PROPERTY_WRITE`
#### `Characteristic.PROPERTY_NOTIFY`
#### `Characteristic.PROPERTY_INDICATE`
Characteristic property constants.
## License
Apache-2.0
+51
-1

@@ -1,1 +0,51 @@

{"name":"bare-bluetooth-android","version":"0.0.0"}
{
"name": "bare-bluetooth-android",
"version": "0.1.0",
"description": "Android Bluetooth bindings for Bare",
"addon": true,
"scripts": {
"format": "prettier --write . && lunte --fix",
"lint": "prettier --check . && lunte",
"test": "brittle-bare --coverage test.js"
},
"exports": {
"./package": "./package.json",
".": {
"types": "./index.d.ts",
"default": "./index.js"
}
},
"files": [
"index.js",
"index.d.ts",
"binding.cc",
"binding.js",
"CMakeLists.txt",
"lib",
"prebuilds"
],
"repository": {
"type": "git",
"url": "git+https://github.com/holepunchto/bare-bluetooth-android.git"
},
"author": "Holepunch",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/holepunchto/bare-bluetooth-android/issues"
},
"homepage": "https://github.com/holepunchto/bare-bluetooth-android#readme",
"dependencies": {
"bare-events": "^2.8.2",
"bare-stream": "^2.11.0"
},
"devDependencies": {
"bare-os": "^3.8.0",
"brittle": "^3.19.1",
"cmake-android": "^0.1.2",
"cmake-bare": "^1.6.5",
"cmake-fetch": "^1.4.0",
"lunte": "^1.6.0",
"prettier": "^3.8.1",
"prettier-config-holepunch": "^2.0.0"
}
}