ble 0.0.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d0d63de7a39417e54dd34e2fc70a326061d36cc6
4
- data.tar.gz: ac360bfb08b81186e16840c3c7dac76f09788d6f
3
+ metadata.gz: 7cc1b7511a25f6f47653f9b5430a1a15c4361574
4
+ data.tar.gz: 776bcbf870dd96a1fb0575a8f9aefe7bcdb1199e
5
5
  SHA512:
6
- metadata.gz: d4a84b8634507629242d89e81542d03e5036ca73faba52e1a4db5d128ea8140e8ac46925de9b45948e12fa6de894865a9e2835500b5ef28265aa2c597bae989a
7
- data.tar.gz: ff96bdeadd3582a120bcd68b8b48864a736d611653c8754508daf08fe68f7fa5808cc7395397277c64be0c434a3a14f642f4bb2d445968f98927007e997caf4b
6
+ metadata.gz: 35ef023571bfd637245b82c814eaed2d08f265a14d207f29b17ad3633a9e62e30b072f4041e9b1ef4a3b6025e5607a0ed958c9cc187c98ab73eecc7534ae6cef
7
+ data.tar.gz: 118372609995212452776777eb03682579e5d87d57b19758cfa3e476415a10dccc2921d53e0f3ee64463876ed56edf3823f6304bece3da712f6e36d0d883afb3
data/lib/ble.rb CHANGED
@@ -96,8 +96,11 @@ end
96
96
  require_relative 'ble/version'
97
97
  require_relative 'ble/uuid'
98
98
  require_relative 'ble/adapter'
99
+ require_relative 'ble/char_desc'
100
+ require_relative 'ble/notifications'
99
101
  require_relative 'ble/device'
100
102
  require_relative 'ble/service'
103
+ require_relative 'ble/char_registry'
101
104
  require_relative 'ble/characteristic'
102
105
  require_relative 'ble/agent'
103
106
 
@@ -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
@@ -1,154 +1,85 @@
1
+ require 'forwardable'
1
2
  module BLE
2
- # Build information about {https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicsHome.aspx Bluetooth Characteristics}
3
- #
4
- # To add a new characteristic description:
5
- # BLE::Characteristic.add 'c4935338-4307-47cf-ae1f-feac9e2b3ae7',
6
- # name: 'Controlled mind',
7
- # type: 'net.cortex-minus.characteristic.controlled_mind'
8
- # vrfy: ->(x) { x >= 0 },
9
- # in: ->(s) { s.unpack('s<').first },
10
- # out: ->(v) { [ v ].pack('s<') }
11
- #
12
- # Returned characteristic description will be a hash:
13
- # {
14
- # name: "Bluetooth characteristic name",
15
- # type: "org.bluetooth.characteristic.name",
16
- # uuid: "128bit-uuid-string",
17
- # vrfy: ->(x) { verify_value(x) },
18
- # in: ->(s) { s.unpack(....) ... },
19
- # out: ->(v) { [ v ].pack(....) ... }
20
- # }
21
- #
22
- module Characteristic
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
+
23
9
  # Notify of characteristic not found
24
- class NotFound < BLE::NotFound
10
+ class NotFound < BLE::NotFound
11
+ end
12
+
13
+ def initialize(desc)
14
+ @dbus_obj= desc[:obj]
15
+ @desc= CharDesc.new(desc)
25
16
  end
26
17
 
18
+ def_delegators :@desc, :flag?, :uuid
19
+
27
20
  private
28
21
  FLAGS = [ 'broadcast',
29
- 'read',
30
- 'write-without-response',
31
- 'write',
32
- 'notify',
33
- 'indicate',
34
- 'authenticated-signed-writes',
35
- 'reliable-write',
36
- 'writable-auxiliaries',
37
- 'encrypt-read',
38
- 'encrypt-write',
39
- 'encrypt-authenticated-read',
40
- 'encrypt-authenticated-write' ]
41
-
42
- DB_UUID = {}
43
- DB_TYPE = {}
44
- DB_NICKNAME = {}
45
-
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
+ #++++++++++++++++++++++++++++
46
37
  public
47
- # Get characteristic description from nickname.
48
- #
49
- # @param id [Symbol] nickname
50
- # @return [Hash] characteristic description
51
- def self.by_nickname(id)
52
- DB_NICKNAME[id]
38
+ #++++++++++++++++++++++++++++
39
+
40
+ def write(val, raw: false)
41
+ val= _serialize_value(val, raw: raw)
42
+ @dbus_obj[I_GATT_CHARACTERISTIC].WriteValue(val)
53
43
  end
54
44
 
55
- # Get characteristic description from uuid.
56
- #
57
- # @param id [String] uuid
58
- # @return [Hash] characteristic description
59
- def self.by_uuid(id)
60
- DB_UUID[id]
45
+ def read(raw: false)
46
+ val= @dbus_obj[I_GATT_CHARACTERISTIC].ReadValue().first
47
+ val= _deserialize_value(val, raw: raw)
61
48
  end
62
49
 
63
- # Get characteristic description from type
64
- #
65
- # @param id [Strig] type
66
- # @return [Hash] characteristic description
67
- def self.by_type(id)
68
- DB_TYPE[id]
50
+ # Register to this characteristic for notifications when
51
+ # its value changes.
52
+ def notify!
53
+ @dbus_obj[I_GATT_CHARACTERISTIC].StartNotify
69
54
  end
70
-
71
- # Get a characteristic description from it's id
72
- # @param id [Symbol,String]
73
- # @return [Hash]
74
- def self.[](id)
75
- case id
76
- when Symbol then DB_NICKNAME[id]
77
- when UUID::REGEX then DB_UUID[id]
78
- when String then DB_TYPE[id]
79
- when Integer then DB_UUID[BLE::UUID(id)]
80
- else raise ArgumentError, "invalid type for characteristic id"
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)
81
62
  end
63
+ end
82
64
  end
83
-
65
+ #----------------------------
66
+ private
67
+ #----------------------------
84
68
 
85
- # Add a characteristic description.
86
- # @example Add a characteristic description with a 16-bit uuid
87
- # module Characteristic
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
- # end
95
- #
96
- # @example Add a characteristic description with a 128-bit uuid
97
- # module Characteristic
98
- # add 'c4935338-4307-47cf-ae1f-feac9e2b3ae7',
99
- # name: 'Controlled mind',
100
- # type: 'net.cortex-minus.characteristic.controlled_mind',
101
- # vrfy: ->(x) { x >= 0 },
102
- # in: ->(s) { s.unpack('s<').first },
103
- # out: ->(v) { [ v ].pack('s<') }
104
- # end
105
- #
106
- # @param uuid [Integer, String] 16-bit, 32-bit or 128-bit uuid
107
- # @param name [String]
108
- # @option opts :type [String] type
109
- # @option opts :nick [Symbol] nickname
110
- # @option opts :in [Proc] convert to ruby
111
- # @option opts :out [Proc] convert to bluetooth data
112
- # @option opts :vry [Proc] verify
113
- # @return [Hash] characteristic description
114
- def self.add(uuid, name:, **opts)
115
- uuid = BLE::UUID(uuid)
116
- type = opts.delete :type
117
- nick = opts.delete :nick
118
- _in = opts.delete :in
119
- _out = opts.delete :out
120
- vrfy = opts.delete :vrfy
121
- if opts.first
122
- raise ArgumentError, "unknown keyword: #{opts.first[0]}"
123
- end
124
-
125
-
126
- desc = DB_UUID[uuid] = {
127
- uuid: uuid,
128
- name: name,
129
- in: _in,
130
- out: _out,
131
- vrfy: vrfy
132
- }
133
-
134
- # Add type if specified
135
- if type
136
- type = type.downcase
137
- desc.merge!(type: type)
138
- DB_TYPE[type] = desc
139
- end
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
140
76
 
141
- # Add nickname if specified or can be derived from type
142
- if nick.nil? && type && type =~ /\.(?<key>[^.]+)$/
143
- nick = $1.to_sym if type.start_with? 'org.bluetooth.characteristic'
144
- end
145
- if nick
146
- if DB_NICKNAME.include?(nick)
147
- raise ArgumentError,
148
- "nickname '#{nick}' already registered (uuid: #{uuid})"
149
- end
150
- DB_NICKNAME[nick] = desc
151
- end
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
152
82
  end
153
- end
83
+
84
+ end
154
85
  end