ble 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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