sb-ble 0.5.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.
- checksums.yaml +7 -0
- data/.rspec +1 -0
- data/.semver +5 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +130 -0
- data/LICENSE +21 -0
- data/README.org +62 -0
- data/Rakefile +51 -0
- data/bin/rble +0 -0
- data/lib/ble.rb +112 -0
- data/lib/ble/adapter.rb +162 -0
- data/lib/ble/agent.rb +46 -0
- data/lib/ble/char_desc.rb +63 -0
- data/lib/ble/char_registry.rb +142 -0
- data/lib/ble/characteristic.rb +85 -0
- data/lib/ble/db_eddystone.rb +50 -0
- data/lib/ble/db_nordic.rb +26 -0
- data/lib/ble/db_sig_characteristic.rb +142 -0
- data/lib/ble/db_sig_service.rb +59 -0
- data/lib/ble/device.rb +494 -0
- data/lib/ble/notifications.rb +44 -0
- data/lib/ble/service.rb +121 -0
- data/lib/ble/uuid.rb +25 -0
- data/lib/ble/version.rb +15 -0
- data/sb-ble.gemspec +112 -0
- data/spec/ruby-ble_spec.rb +7 -0
- data/spec/spec_helper.rb +29 -0
- metadata +296 -0
data/lib/ble/agent.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
module BLE
|
2
|
+
class Agent < DBus::Object
|
3
|
+
@log = Logger.new($stdout)
|
4
|
+
# https://kernel.googlesource.com/pub/scm/bluetooth/bluez/+/refs/heads/master/doc/agent-api.txt
|
5
|
+
dbus_interface I_AGENT do
|
6
|
+
dbus_method :Release do
|
7
|
+
@log.debug "Release()"
|
8
|
+
exit false
|
9
|
+
end
|
10
|
+
|
11
|
+
dbus_method :RequestPinCode, "in device:o, out ret:s" do |device|
|
12
|
+
@log.debug{ "RequestPinCode(#{device})" }
|
13
|
+
["0000"]
|
14
|
+
end
|
15
|
+
|
16
|
+
dbus_method :RequestPasskey, "in device:o, out ret:u" do |device|
|
17
|
+
@log.debug{ "RequestPasskey(#{device})" }
|
18
|
+
raise DBus.error("org.bluez.Error.Rejected")
|
19
|
+
end
|
20
|
+
|
21
|
+
dbus_method :DisplayPasskey, "in device:o, in passkey:u, in entered:y" do |device, passkey, entered|
|
22
|
+
@log.debug{ "DisplayPasskey(#{device}, #{passkey}, #{entered})" }
|
23
|
+
raise DBus.error("org.bluez.Error.Rejected")
|
24
|
+
end
|
25
|
+
|
26
|
+
dbus_method :RequestConfirmation, "in device:o, in passkey:u" do |device, passkey|
|
27
|
+
@log.debug{ "RequestConfirmation(#{device}, #{passkey})" }
|
28
|
+
raise DBus.error("org.bluez.Error.Rejected")
|
29
|
+
end
|
30
|
+
|
31
|
+
dbus_method :Authorize, "in device:o, in uuid:s" do |device, uuid|
|
32
|
+
@log.debug{ "Authorize(#{device}, #{uuid})" }
|
33
|
+
end
|
34
|
+
|
35
|
+
dbus_method :ConfirmModeChange, "in mode:s" do |mode|
|
36
|
+
@log.debug{ "ConfirmModeChange(#{mode})" }
|
37
|
+
raise DBus.error("org.bluez.Error.Rejected")
|
38
|
+
end
|
39
|
+
|
40
|
+
dbus_method :Cancel do
|
41
|
+
@log.debug "Cancel()"
|
42
|
+
raise DBus.error("org.bluez.Error.Rejected")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# Encapsulates Characteristic descriptors and offers easy
|
2
|
+
# access to characteristic related information.
|
3
|
+
#
|
4
|
+
module BLE
|
5
|
+
class CharDesc
|
6
|
+
attr_reader :desc
|
7
|
+
# @param desc [Hash] Descriptors.
|
8
|
+
def initialize(desc)
|
9
|
+
@desc= desc
|
10
|
+
end
|
11
|
+
def flags
|
12
|
+
@flags||= @desc[:flags]
|
13
|
+
end
|
14
|
+
def config
|
15
|
+
@config||= Characteristic[@desc[:uuid]]
|
16
|
+
end
|
17
|
+
|
18
|
+
def uuid
|
19
|
+
@desc[:uuid]
|
20
|
+
end
|
21
|
+
def flag?(flag_name)
|
22
|
+
flags.include?(flag_name)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Does outgoing values have processors configured?
|
26
|
+
# If yes, the value needs to be pre-processed before being send.
|
27
|
+
def write_processors?
|
28
|
+
verifier? or write_pre_processor?
|
29
|
+
end
|
30
|
+
# Does incoming values have processors configured?
|
31
|
+
# If yes, the value needs to be post-processed after being received.
|
32
|
+
def read_processors?
|
33
|
+
config && read_post_processor?
|
34
|
+
end
|
35
|
+
# It has been configured a verifier preprocessor to check
|
36
|
+
# outgoing data?
|
37
|
+
def verifier?
|
38
|
+
config[:vrfy]
|
39
|
+
end
|
40
|
+
def write_pre_processor?
|
41
|
+
config[:out]
|
42
|
+
end
|
43
|
+
def read_post_processor?
|
44
|
+
config[:in]
|
45
|
+
end
|
46
|
+
# Is the received value verified by the verifier?
|
47
|
+
def verifies?(val)
|
48
|
+
config[:vrfy].call(val)
|
49
|
+
end
|
50
|
+
def pre_process(val)
|
51
|
+
if verifier? && !verifies?(val)
|
52
|
+
raise ArgumentError,
|
53
|
+
"bad value for characteristic '#{uuid}'"
|
54
|
+
end
|
55
|
+
val = config[:out].call(val) if write_pre_processor?
|
56
|
+
end
|
57
|
+
|
58
|
+
def post_process(val)
|
59
|
+
val = config[:in].call(val) if read_post_processor?
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# To add a new characteristic description:
|
2
|
+
# BLE::Characteristic.add 'c4935338-4307-47cf-ae1f-feac9e2b3ae7',
|
3
|
+
# name: 'Controlled mind',
|
4
|
+
# type: 'net.cortex-minus.characteristic.controlled_mind'
|
5
|
+
# vrfy: ->(x) { x >= 0 },
|
6
|
+
# in: ->(s) { s.unpack('s<').first },
|
7
|
+
# out: ->(v) { [ v ].pack('s<') }
|
8
|
+
#
|
9
|
+
# Returned characteristic description will be a hash:
|
10
|
+
# {
|
11
|
+
# name: "Bluetooth characteristic name",
|
12
|
+
# type: "org.bluetooth.characteristic.name",
|
13
|
+
# uuid: "128bit-uuid-string",
|
14
|
+
# vrfy: ->(x) { verify_value(x) },
|
15
|
+
# in: ->(s) { s.unpack(....) ... },
|
16
|
+
# out: ->(v) { [ v ].pack(....) ... }
|
17
|
+
# }
|
18
|
+
#
|
19
|
+
module BLE
|
20
|
+
module CharRegistry
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
DB_UUID = {}
|
25
|
+
DB_TYPE = {}
|
26
|
+
DB_NICKNAME = {}
|
27
|
+
|
28
|
+
public
|
29
|
+
def self.included(klass)
|
30
|
+
class << klass
|
31
|
+
# Get characteristic description from nickname.
|
32
|
+
#
|
33
|
+
# @param id [Symbol] nickname
|
34
|
+
# @return [CharDesc] characteristic description
|
35
|
+
def by_nickname(id)
|
36
|
+
DB_NICKNAME[id]
|
37
|
+
end
|
38
|
+
|
39
|
+
# Get characteristic description from uuid.
|
40
|
+
#
|
41
|
+
# @param id [String] uuid
|
42
|
+
# @return [CharDesc] characteristic description
|
43
|
+
def by_uuid(id)
|
44
|
+
DB_UUID[id]
|
45
|
+
end
|
46
|
+
|
47
|
+
# Get characteristic description from type
|
48
|
+
#
|
49
|
+
# @param id [Strig] type
|
50
|
+
# @return [CharDesc] characteristic description
|
51
|
+
def by_type(id)
|
52
|
+
DB_TYPE[id]
|
53
|
+
end
|
54
|
+
|
55
|
+
# Get a characteristic description from it's id
|
56
|
+
# @param id [Symbol,String]
|
57
|
+
# @return [CharDesc]
|
58
|
+
def [](id)
|
59
|
+
case id
|
60
|
+
when Symbol then DB_NICKNAME[id]
|
61
|
+
when UUID::REGEX then DB_UUID[id]
|
62
|
+
when String then DB_TYPE[id]
|
63
|
+
when Integer then DB_UUID[BLE::UUID(id)]
|
64
|
+
else raise ArgumentError, "invalid type for characteristic id"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
# Add a characteristic description.
|
70
|
+
# @example Add a characteristic description with a 16-bit uuid
|
71
|
+
# module Characteristic
|
72
|
+
# add 0x2A6E,
|
73
|
+
# name: 'Temperature',
|
74
|
+
# type: 'org.bluetooth.characteristic.temperature',
|
75
|
+
# vrfy: ->(x) { (0..100).include?(x) },
|
76
|
+
# in: ->(s) { s.unpack('s<').first.to_f / 100 },
|
77
|
+
# out: ->(v) { [ v*100 ].pack('s<') }
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# @example Add a characteristic description with a 128-bit uuid
|
81
|
+
# module Characteristic
|
82
|
+
# add 'c4935338-4307-47cf-ae1f-feac9e2b3ae7',
|
83
|
+
# name: 'Controlled mind',
|
84
|
+
# type: 'net.cortex-minus.characteristic.controlled_mind',
|
85
|
+
# vrfy: ->(x) { x >= 0 },
|
86
|
+
# in: ->(s) { s.unpack('s<').first },
|
87
|
+
# out: ->(v) { [ v ].pack('s<') }
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# @param uuid [Integer, String] 16-bit, 32-bit or 128-bit uuid
|
91
|
+
# @param name [String]
|
92
|
+
# @option opts :type [String] type
|
93
|
+
# @option opts :nick [Symbol] nickname
|
94
|
+
# @option opts :in [Proc] convert to ruby
|
95
|
+
# @option opts :out [Proc] convert to bluetooth data
|
96
|
+
# @option opts :vry [Proc] verify
|
97
|
+
# @return [CharDesc] characteristic description
|
98
|
+
def add(uuid, name:, **opts)
|
99
|
+
uuid = BLE::UUID(uuid)
|
100
|
+
type = opts.delete :type
|
101
|
+
nick = opts.delete :nick
|
102
|
+
_in = opts.delete :in
|
103
|
+
_out = opts.delete :out
|
104
|
+
vrfy = opts.delete :vrfy
|
105
|
+
if opts.first
|
106
|
+
raise ArgumentError, "unknown keyword: #{opts.first[0]}"
|
107
|
+
end
|
108
|
+
|
109
|
+
char_config= DB_UUID[uuid] = {
|
110
|
+
uuid: uuid,
|
111
|
+
name: name,
|
112
|
+
in: _in,
|
113
|
+
out: _out,
|
114
|
+
vrfy: vrfy
|
115
|
+
}
|
116
|
+
|
117
|
+
# Add type if specified
|
118
|
+
if type
|
119
|
+
type = type.downcase
|
120
|
+
char_config.merge!(type: type)
|
121
|
+
DB_TYPE[type] = char_config
|
122
|
+
end
|
123
|
+
|
124
|
+
# Add nickname if specified or can be derived from type
|
125
|
+
if nick.nil? && type && type =~ /\.(?<key>[^.]+)$/
|
126
|
+
nick = $1.to_sym if type.start_with? 'org.bluetooth.characteristic'
|
127
|
+
end
|
128
|
+
if nick
|
129
|
+
if DB_NICKNAME.include?(nick)
|
130
|
+
raise ArgumentError,
|
131
|
+
"nickname '#{nick}' already registered (uuid: #{uuid})"
|
132
|
+
end
|
133
|
+
DB_NICKNAME[nick] = char_config
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
module BLE
|
3
|
+
# Build information about {https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicsHome.aspx Bluetooth Characteristics}
|
4
|
+
#
|
5
|
+
class Characteristic
|
6
|
+
include CharRegistry
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
# Notify of characteristic not found
|
10
|
+
class NotFound < BLE::NotFound
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(desc)
|
14
|
+
@dbus_obj= desc[:obj]
|
15
|
+
@desc= CharDesc.new(desc)
|
16
|
+
end
|
17
|
+
|
18
|
+
def_delegators :@desc, :flag?, :uuid
|
19
|
+
|
20
|
+
private
|
21
|
+
FLAGS = [ 'broadcast',
|
22
|
+
'read',
|
23
|
+
'write-without-response',
|
24
|
+
'write',
|
25
|
+
'notify',
|
26
|
+
'indicate',
|
27
|
+
'authenticated-signed-writes',
|
28
|
+
'reliable-write',
|
29
|
+
'writable-auxiliaries',
|
30
|
+
'encrypt-read',
|
31
|
+
'encrypt-write',
|
32
|
+
'encrypt-authenticated-read',
|
33
|
+
'encrypt-authenticated-write' ]
|
34
|
+
|
35
|
+
|
36
|
+
#++++++++++++++++++++++++++++
|
37
|
+
public
|
38
|
+
#++++++++++++++++++++++++++++
|
39
|
+
|
40
|
+
def write(val, raw: false)
|
41
|
+
val= _serialize_value(val, raw: raw)
|
42
|
+
@dbus_obj[I_GATT_CHARACTERISTIC].WriteValue(val)
|
43
|
+
end
|
44
|
+
|
45
|
+
def read(raw: false)
|
46
|
+
val= @dbus_obj[I_GATT_CHARACTERISTIC].ReadValue().first
|
47
|
+
val= _deserialize_value(val, raw: raw)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Register to this characteristic for notifications when
|
51
|
+
# its value changes.
|
52
|
+
def notify!
|
53
|
+
@dbus_obj[I_GATT_CHARACTERISTIC].StartNotify
|
54
|
+
end
|
55
|
+
|
56
|
+
def on_change(raw: false, &callback)
|
57
|
+
@dbus_obj[I_PROPERTIES].on_signal('PropertiesChanged') do |intf, props|
|
58
|
+
case intf
|
59
|
+
when I_GATT_CHARACTERISTIC
|
60
|
+
val= _deserialize_value(props['Value'], raw: raw)
|
61
|
+
callback.call(val)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
#----------------------------
|
66
|
+
private
|
67
|
+
#----------------------------
|
68
|
+
|
69
|
+
# Convert Arrays of bytes returned by DBus to Strings of bytes.
|
70
|
+
def _serialize_value(val, raw: false)
|
71
|
+
if !raw && @desc.write_processors?
|
72
|
+
val= @desc.pre_process(val)
|
73
|
+
end
|
74
|
+
val.unpack('C*')
|
75
|
+
end
|
76
|
+
|
77
|
+
# Convert Arrays of bytes returned by DBus to Strings of bytes.
|
78
|
+
def _deserialize_value(val, raw: false)
|
79
|
+
val = val.pack('C*')
|
80
|
+
val = @desc.post_process(val) if !raw && @desc.read_processors?
|
81
|
+
val
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module BLE
|
2
|
+
module Service
|
3
|
+
add 'ee0c2080-8786-40ba-ab96-99b91ac981d8',
|
4
|
+
name: 'Eddystone-URL Beacon Configuration'
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
module BLE
|
9
|
+
class Characteristic
|
10
|
+
add 'ee0c2081-8786-40ba-ab96-99b91ac981d8',
|
11
|
+
name: 'Eddystone Lock State',
|
12
|
+
nick: :esurl_lockstate
|
13
|
+
|
14
|
+
add 'ee0c2082-8786-40ba-ab96-99b91ac981d8',
|
15
|
+
name: 'Eddystone Lock',
|
16
|
+
nick: :esurl_lock
|
17
|
+
|
18
|
+
add 'ee0c2083-8786-40ba-ab96-99b91ac981d8',
|
19
|
+
name: 'Eddystone Unlock',
|
20
|
+
nick: :esurl_unlock
|
21
|
+
|
22
|
+
add 'ee0c2084-8786-40ba-ab96-99b91ac981d8',
|
23
|
+
name: 'Eddystone URL Data',
|
24
|
+
nick: :esurl_data
|
25
|
+
|
26
|
+
add 'ee0c2085-8786-40ba-ab96-99b91ac981d8',
|
27
|
+
name: 'Eddystone Flags',
|
28
|
+
nick: :esurl_flags
|
29
|
+
|
30
|
+
add 'ee0c2086-8786-40ba-ab96-99b91ac981d8',
|
31
|
+
name: 'Eddystone Adv Tx Power Levels',
|
32
|
+
nick: :esurl_adv_txpower_levels
|
33
|
+
|
34
|
+
add 'ee0c2087-8786-40ba-ab96-99b91ac981d8',
|
35
|
+
name: 'Eddystone TX power mode',
|
36
|
+
nick: :esurl_txpower_mode
|
37
|
+
|
38
|
+
add 'ee0c2088-8786-40ba-ab96-99b91ac981d8',
|
39
|
+
name: 'Eddystone Beacon period',
|
40
|
+
nick: :esurl_beacon_period
|
41
|
+
|
42
|
+
add 'ee0c2089-8786-40ba-ab96-99b91ac981d8',
|
43
|
+
name: 'Eddystone Reset',
|
44
|
+
nick: :esurl_reset
|
45
|
+
|
46
|
+
add 'ee0c208a-8786-40ba-ab96-99b91ac981d8',
|
47
|
+
name: 'Eddystone Radio Tx Power Levels',
|
48
|
+
nick: :esurl_radio_txpower_levels
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module BLE
|
2
|
+
module Service
|
3
|
+
add '00001530-1212-efde-1523-785feabcd123',
|
4
|
+
name: 'Nordic Device Firmware Update Service'
|
5
|
+
|
6
|
+
add '6e400001-b5a3-f393-e0a9-e50e24dcca9e',
|
7
|
+
name: 'Nordic UART Service'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
module BLE
|
13
|
+
class Characteristic
|
14
|
+
add '00001531-1212-efde-1523-785feabcd123', # WriteWithoutResponse
|
15
|
+
name: 'DFU Packet'
|
16
|
+
|
17
|
+
add '00001532-1212-efde-1523-785feabcd123', # Write,Notify
|
18
|
+
name: 'DFU Control Point'
|
19
|
+
|
20
|
+
add '6e400002-b5a3-f393-e0a9-e50e24dcca9e',
|
21
|
+
name: 'UART TX'
|
22
|
+
|
23
|
+
add '6e400003-b5a3-f393-e0a9-e50e24dcca9e',
|
24
|
+
name: 'UART RX'
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module BLE
|
2
|
+
class Characteristic
|
3
|
+
# C | Integer | 8-bit unsigned (unsigned char)
|
4
|
+
# S | Integer | 16-bit unsigned, native endian (uint16_t)
|
5
|
+
# L | Integer | 32-bit unsigned, native endian (uint32_t)
|
6
|
+
# Q | Integer | 64-bit unsigned, native endian (uint64_t)
|
7
|
+
# | |
|
8
|
+
# c | Integer | 8-bit signed (signed char)
|
9
|
+
# s | Integer | 16-bit signed, native endian (int16_t)
|
10
|
+
# l | Integer | 32-bit signed, native endian (int32_t)
|
11
|
+
# q | Integer | 64-bit signed, native endian (int64_t)
|
12
|
+
#
|
13
|
+
# < | Little endian
|
14
|
+
# > | Big endian
|
15
|
+
|
16
|
+
add 0x2A07,
|
17
|
+
name: 'Tx Power Level',
|
18
|
+
type: 'org.bluetooth.characteristic.tx_power_level',
|
19
|
+
vrfy: ->(x) { (-100..20).include?(c) },
|
20
|
+
in: ->(s) { s.unpack('c').first },
|
21
|
+
out: ->(v) { [ v ].pack('c') }
|
22
|
+
|
23
|
+
add 0x2A23,
|
24
|
+
name: 'System ID',
|
25
|
+
type: 'org.bluetooth.characteristic.system_id',
|
26
|
+
vrfy: ->(x) { (0..1099511627775).include?(x[0]) &&
|
27
|
+
(0..16777215 ).include?(x[1])},
|
28
|
+
in: ->(s) { raise NotYetImplemented },
|
29
|
+
out: ->(v) { raise NotYetImplemented }
|
30
|
+
|
31
|
+
add 0x2A24,
|
32
|
+
name: 'Model Number String',
|
33
|
+
type: 'org.bluetooth.characteristic.model_number_string',
|
34
|
+
in: ->(s) { s.force_encoding('UTF-8') },
|
35
|
+
out: ->(v) { v.encode('UTF-8') }
|
36
|
+
|
37
|
+
add 0x2A25,
|
38
|
+
name: 'Serial Number String',
|
39
|
+
type: 'org.bluetooth.characteristic.serial_number_string',
|
40
|
+
in: ->(s) { s.force_encoding('UTF-8') },
|
41
|
+
out: ->(v) { v.encode('UTF-8') }
|
42
|
+
|
43
|
+
add 0x2A26,
|
44
|
+
name: 'Firmware Revision String',
|
45
|
+
type: 'org.bluetooth.characteristic.firmware_revision_string',
|
46
|
+
in: ->(s) { s.force_encoding('UTF-8') },
|
47
|
+
out: ->(v) { v.encode('UTF-8') }
|
48
|
+
|
49
|
+
add 0x2A27,
|
50
|
+
name: 'Hardware Revision String',
|
51
|
+
type: 'org.bluetooth.characteristic.hardware_revision_string',
|
52
|
+
in: ->(s) { s.force_encoding('UTF-8') },
|
53
|
+
out: ->(v) { v.encode('UTF-8') }
|
54
|
+
|
55
|
+
add 0x2A28,
|
56
|
+
name: 'Software Revision String',
|
57
|
+
type: 'org.bluetooth.characteristic.software_revision_string',
|
58
|
+
in: ->(s) { s.force_encoding('UTF-8') },
|
59
|
+
out: ->(v) { v.encode('UTF-8') }
|
60
|
+
|
61
|
+
add 0x2A29,
|
62
|
+
name: 'Manufacturer Name String',
|
63
|
+
type: 'org.bluetooth.characteristic.manufacturer_name_string',
|
64
|
+
in: ->(s) { s.force_encoding('UTF-8') },
|
65
|
+
out: ->(v) { v.encode('UTF-8') }
|
66
|
+
|
67
|
+
add 0x2A2A,
|
68
|
+
name: 'IEEE 11073-20601 Regulatory Certification Data List',
|
69
|
+
type: 'org.bluetooth.characteristic.ieee_11073-20601_regulatory_certification_data_list',
|
70
|
+
in: ->(s) { raise NotYetImplemented },
|
71
|
+
out: ->(v) { raise NotYetImplemented }
|
72
|
+
|
73
|
+
add 0x2A50,
|
74
|
+
name: 'PnP ID',
|
75
|
+
type: 'org.bluetooth.characteristic.pnp_id',
|
76
|
+
in: ->(s) { vendor_src, vendor_id,
|
77
|
+
product_id, product_version = s.unpack('CS<S<S<')
|
78
|
+
vendor_src = case vendor_src
|
79
|
+
when 1 then :bluetooth_sig
|
80
|
+
when 2 then :usb_forum
|
81
|
+
else :reserved
|
82
|
+
end
|
83
|
+
[ vendor_src, vendor_id,
|
84
|
+
product_id, product_version ] },
|
85
|
+
out: ->(v) { raise NotYetImplemented }
|
86
|
+
|
87
|
+
|
88
|
+
add 0x2A6E,
|
89
|
+
name: 'Temperature',
|
90
|
+
type: 'org.bluetooth.characteristic.temperature',
|
91
|
+
vrfy: ->(x) { (0..100).include?(x) },
|
92
|
+
in: ->(s) { s.unpack('s<').first.to_f / 100 },
|
93
|
+
out: ->(v) { [ v*100 ].pack('s<') }
|
94
|
+
|
95
|
+
add 0x2A76,
|
96
|
+
name: 'UV Index',
|
97
|
+
type: 'org.bluetooth.characteristic.uv_index',
|
98
|
+
in: ->(s) { s.unpack('C').first },
|
99
|
+
out: ->(v) { [ v ].pack('C') }
|
100
|
+
|
101
|
+
add 0x2A77,
|
102
|
+
name: 'Irradiance',
|
103
|
+
type: 'org.bluetooth.characteristic.irradiance',
|
104
|
+
in: ->(s) { s.unpack('S<').first.to_f / 10 },
|
105
|
+
out: ->(v) { [ v*10 ].pack('S<') }
|
106
|
+
|
107
|
+
add 0x2A7A,
|
108
|
+
name: 'Heat Index',
|
109
|
+
type: 'org.bluetooth.characteristic.heat_index',
|
110
|
+
in: ->(s) { s.unpack('c').first },
|
111
|
+
out: ->(v) { [ v ].pack('c') }
|
112
|
+
|
113
|
+
add 0x2A19,
|
114
|
+
name: 'Battery Level',
|
115
|
+
type: 'org.bluetooth.characteristic.battery_level',
|
116
|
+
vrfy: ->(x) { (0..100).include?(x) },
|
117
|
+
in: ->(s) { s.unpack('C').first },
|
118
|
+
out: ->(v) { [ v ].pack('C') }
|
119
|
+
|
120
|
+
add 0x2A6F,
|
121
|
+
name: 'Humidity',
|
122
|
+
type: 'org.bluetooth.characteristic.humidity',
|
123
|
+
vrfy: ->(x) { (0..100).include?(x) },
|
124
|
+
in: ->(s) { s.unpack('S<').first.to_f / 100 },
|
125
|
+
out: ->(v) { [ v*100 ].pack('S<') }
|
126
|
+
|
127
|
+
add 0x2A6D,
|
128
|
+
name: 'Pressure',
|
129
|
+
type: 'org.bluetooth.characteristic.pressure',
|
130
|
+
vrfy: ->(x) { x >= 0 },
|
131
|
+
in: ->(s) { s.unpack('L<').first.to_f / 10 },
|
132
|
+
out: ->(v) { [ v*10 ].pack('L<') }
|
133
|
+
|
134
|
+
add 0x2AB3,
|
135
|
+
name: 'Altitude',
|
136
|
+
type: 'org.bluetooth.characteristic.altitude',
|
137
|
+
vrfy: ->(x) { x >= 0 },
|
138
|
+
in: ->(s) { s.unpack('S<').first },
|
139
|
+
out: ->(v) { [ v ].pack('S<') }
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|