flic 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/flic.rb +2 -1
  3. data/lib/flic/callbacks.rb +36 -0
  4. data/lib/flic/client.rb +52 -203
  5. data/lib/flic/client/connection_channel.rb +21 -0
  6. data/lib/flic/client/features.rb +15 -0
  7. data/lib/flic/client/features/connection_channel.rb +175 -0
  8. data/lib/flic/client/features/force_disconnect.rb +13 -0
  9. data/lib/flic/client/features/get_button_uuid.rb +43 -0
  10. data/lib/flic/client/features/get_info.rb +52 -0
  11. data/lib/flic/client/features/ping.rb +55 -0
  12. data/lib/flic/client/features/scan.rb +112 -0
  13. data/lib/flic/client/features/scan_wizard.rb +131 -0
  14. data/lib/flic/client/scan_wizard.rb +14 -0
  15. data/lib/flic/client/scanner.rb +12 -0
  16. data/lib/flic/client/server_info.rb +16 -0
  17. data/lib/flic/protocol.rb +1 -0
  18. data/lib/flic/protocol/commands/change_mode_parameters.rb +3 -2
  19. data/lib/flic/protocol/commands/create_connection_channel.rb +3 -2
  20. data/lib/flic/protocol/commands/remove_connection_channel.rb +1 -1
  21. data/lib/flic/{client → protocol}/connection.rb +20 -26
  22. data/lib/flic/protocol/events/button_click_or_hold.rb +1 -1
  23. data/lib/flic/protocol/events/button_single_or_double_click.rb +1 -1
  24. data/lib/flic/protocol/events/button_single_or_double_click_or_hold.rb +1 -1
  25. data/lib/flic/protocol/events/button_up_or_down.rb +1 -1
  26. data/lib/flic/protocol/events/connection_channel_removed.rb +2 -2
  27. data/lib/flic/protocol/events/connection_status_changed.rb +1 -1
  28. data/lib/flic/protocol/events/create_connection_channel_response.rb +1 -1
  29. data/lib/flic/protocol/events/get_info_response.rb +3 -2
  30. data/lib/flic/protocol/primitives.rb +1 -0
  31. data/lib/flic/protocol/primitives/disconnect_time.rb +29 -0
  32. data/lib/flic/simple_client.rb +116 -0
  33. data/lib/flic/version.rb +1 -1
  34. metadata +18 -6
  35. data/lib/flic/event_bus.rb +0 -81
  36. data/lib/flic/event_bus/driver.rb +0 -23
  37. data/lib/flic/event_bus/subscription.rb +0 -66
@@ -5,6 +5,7 @@ module Flic
5
5
  class Error < StandardError; end
6
6
 
7
7
  autoload :Commands, 'flic/protocol/commands'
8
+ autoload :Connection, 'flic/protocol/connection'
8
9
  autoload :Events, 'flic/protocol/events'
9
10
  autoload :PacketHeader, 'flic/protocol/packet_header'
10
11
  autoload :Primitives, 'flic/protocol/primitives'
@@ -1,6 +1,7 @@
1
1
  require 'flic/protocol/commands'
2
2
  require 'flic/protocol/commands/command'
3
3
  require 'flic/protocol/primitives/latency_mode'
4
+ require 'flic/protocol/primitives/disconnect_time'
4
5
 
5
6
  module Flic
6
7
  module Protocol
@@ -8,9 +9,9 @@ module Flic
8
9
  class ChangeModeParameters < Command
9
10
  endian :little
10
11
 
11
- uint32 :connection_id
12
+ uint32 :connection_channel_id
12
13
  latency_mode :latency_mode
13
- uint16 :auto_disconnect_time
14
+ disconnect_time :auto_disconnect_time
14
15
  end
15
16
  end
16
17
  end
@@ -2,6 +2,7 @@ require 'flic/protocol/commands'
2
2
  require 'flic/protocol/commands/command'
3
3
  require 'flic/protocol/primitives/bluetooth_address'
4
4
  require 'flic/protocol/primitives/latency_mode'
5
+ require 'flic/protocol/primitives/disconnect_time'
5
6
 
6
7
  module Flic
7
8
  module Protocol
@@ -9,11 +10,11 @@ module Flic
9
10
  class CreateConnectionChannel < Command
10
11
  endian :little
11
12
 
12
- uint32 :connection_id
13
+ uint32 :connection_channel_id
13
14
  bluetooth_address :bluetooth_address
14
15
 
15
16
  latency_mode :latency_mode
16
- uint16 :auto_disconnect_time, initial_value: 512 # 512 means disabled
17
+ disconnect_time :auto_disconnect_time
17
18
  end
18
19
  end
19
20
  end
@@ -7,7 +7,7 @@ module Flic
7
7
  class RemoveConnectionChannel < Command
8
8
  endian :little
9
9
 
10
- uint32 :connection_id
10
+ uint32 :connection_channel_id
11
11
  end
12
12
  end
13
13
  end
@@ -1,32 +1,15 @@
1
- require 'flic'
2
- require 'flic/client'
3
1
  require 'flic/protocol'
4
2
 
5
- require 'socket'
6
-
7
3
  module Flic
8
- class Client
4
+ module Protocol
9
5
  class Connection
10
- class Error < StandardError; end
11
6
  class ConnectionClosedError < Error; end
7
+ class NilResponse < Error; end
12
8
 
13
- class << self
14
- def open(*args)
15
- client = new(*args)
16
-
17
- begin
18
- yield client
19
- ensure
20
- client.close
21
- end
22
- end
23
- end
24
-
25
- attr_reader :hostname, :port
9
+ attr_reader :socket
26
10
 
27
- def initialize(hostname = 'localhost', port = 5551, *additional_socket_args)
28
- @hostname, @port = hostname, port
29
- @socket = TCPSocket.new(hostname, port, *additional_socket_args)
11
+ def initialize(socket)
12
+ @socket = socket
30
13
  @read_semaphore = Mutex.new
31
14
  @write_semaphore = Mutex.new
32
15
  end
@@ -35,12 +18,16 @@ module Flic
35
18
  send_packet Protocol.serialize_command(command)
36
19
  end
37
20
 
38
- def recv_event
39
- Protocol.parse_event(recv_packet)
21
+ def recv_command
22
+ Protocol.parse_event(recv_command)
40
23
  end
41
24
 
42
- def listen
43
- loop { yield recv_event }
25
+ def send_event(event)
26
+ send_packet Protocol.serialize_event(event)
27
+ end
28
+
29
+ def recv_event
30
+ Protocol.parse_event(recv_packet)
44
31
  end
45
32
 
46
33
  def closed?
@@ -71,10 +58,17 @@ module Flic
71
58
  @read_semaphore.synchronize do
72
59
  packet_header = Protocol::PacketHeader.new
73
60
  packet_header_bytes = @socket.read packet_header.num_bytes
61
+
62
+ raise NilResponse unless packet_header_bytes
63
+
74
64
  packet_header.read(packet_header_bytes)
75
65
 
76
66
  @socket.read(packet_header.byte_length)
77
67
  end
68
+ rescue NilResponse
69
+ @socket.close
70
+
71
+ retry
78
72
  rescue IOError
79
73
  if closed?
80
74
  raise ConnectionClosedError
@@ -9,7 +9,7 @@ module Flic
9
9
  class ButtonClickOrHold < Event
10
10
  endian :little
11
11
 
12
- uint32 :connection_id
12
+ uint32 :connection_channel_id
13
13
  click_type :click_type
14
14
  boolean :was_queued
15
15
  uint32 :time_difference
@@ -9,7 +9,7 @@ module Flic
9
9
  class ButtonSingleOrDoubleClick < Event
10
10
  endian :little
11
11
 
12
- uint32 :connection_id
12
+ uint32 :connection_channel_id
13
13
  click_type :click_type
14
14
  boolean :was_queued
15
15
  uint32 :time_difference
@@ -9,7 +9,7 @@ module Flic
9
9
  class ButtonSingleOrDoubleClickOrHold < Event
10
10
  endian :little
11
11
 
12
- uint32 :connection_id
12
+ uint32 :connection_channel_id
13
13
  click_type :click_type
14
14
  boolean :was_queued
15
15
  uint32 :time_difference
@@ -9,7 +9,7 @@ module Flic
9
9
  class ButtonUpOrDown < Event
10
10
  endian :little
11
11
 
12
- uint32 :connection_id
12
+ uint32 :connection_channel_id
13
13
  click_type :click_type
14
14
  boolean :was_queued
15
15
  uint32 :time_difference
@@ -8,8 +8,8 @@ module Flic
8
8
  class ConnectionChannelRemoved < Event
9
9
  endian :little
10
10
 
11
- uint32 :connection_id
12
- removed_reason :removed_reason
11
+ uint32 :connection_channel_id
12
+ removed_reason :reason
13
13
  end
14
14
  end
15
15
  end
@@ -9,7 +9,7 @@ module Flic
9
9
  class ConnectionStatusChanged < Event
10
10
  endian :little
11
11
 
12
- uint32 :connection_id
12
+ uint32 :connection_channel_id
13
13
  connection_status :connection_status
14
14
 
15
15
  disconnect_reason :disconnect_reason # only relevant when connection_status is :disconnected
@@ -9,7 +9,7 @@ module Flic
9
9
  class CreateConnectionChannelResponse < Event
10
10
  endian :little
11
11
 
12
- uint32 :connection_id
12
+ uint32 :connection_channel_id
13
13
  create_connection_channel_error :error
14
14
  connection_status :connection_status
15
15
  end
@@ -19,9 +19,10 @@ module Flic
19
19
  uint8 :current_pending_connections
20
20
  boolean :currently_no_space_for_new_connection
21
21
 
22
- uint16 :verified_buttons_length
23
- array :verified_buttons, type: :bluetooth_address, initial_length: :verified_buttons_length
22
+ uint16 :verified_buttons_bluetooth_addresses_length
23
+ array :verified_buttons_bluetooth_addresses, type: :bluetooth_address, initial_length: :verified_buttons_bluetooth_addresses_length
24
24
  end
25
25
  end
26
26
  end
27
27
  end
28
+
@@ -12,6 +12,7 @@ module Flic
12
12
  autoload :CreateConnectionChannelError, 'flic/protocol/primitives/create_connection_channel_error'
13
13
  autoload :DeviceName, 'flic/protocol/primitives/device_name'
14
14
  autoload :DisconnectReason, 'flic/protocol/primitives/disconnect_reason'
15
+ autoload :DisconnectTime, 'flic/protocol/primitives/disconnect_time'
15
16
  autoload :Enum, 'flic/protocol/primitives/enum'
16
17
  autoload :LatencyMode, 'flic/protocol/primitives/latency_mode'
17
18
  autoload :RemovedReason, 'flic/protocol/primitives/removed_reason'
@@ -0,0 +1,29 @@
1
+ require 'flic/protocol/primitives'
2
+
3
+ module Flic
4
+ module Primitives
5
+ class DisconnectTime < BinData::Primitive
6
+ endian :little
7
+
8
+ uint16 :time, initial_value: 512
9
+
10
+ def get
11
+ if time == 512
12
+ nil
13
+ else
14
+ time
15
+ end
16
+ end
17
+
18
+ def set(value)
19
+ if value == 512
20
+ raise RangeError, '512 is a special value that cannot be used for disconnect_time'
21
+ elsif value
22
+ self.time = value
23
+ else
24
+ self.time = 512
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,116 @@
1
+ require 'flic'
2
+
3
+ require 'thread'
4
+
5
+ module Flic
6
+ class SimpleClient
7
+ class Error < StandardError; end
8
+ class ConnectionChannelRemoved; end
9
+
10
+ attr_reader :client
11
+
12
+ def initialize(*client_args)
13
+ @client = Client.new(*client_args)
14
+ end
15
+
16
+ def shutdown
17
+ client.shutdown
18
+ event_dispatch_thread.join
19
+ end
20
+
21
+ def buttons
22
+ server_info = process_events_until do |callback|
23
+ client.get_info(&callback)
24
+ end
25
+
26
+ server_info.verified_buttons_bluetooth_addresses
27
+ end
28
+
29
+ def connect_button
30
+ begin
31
+ scan_wizard = Client::ScanWizard.new
32
+
33
+ process_events_until do |callback|
34
+ scan_wizard.removed do |result, bluetooth_address, *|
35
+ if result == :success
36
+ callback.call(bluetooth_address)
37
+ else
38
+ callback.call(nil)
39
+ end
40
+ end
41
+
42
+ client.add_scan_wizard(scan_wizard)
43
+ end
44
+ ensure
45
+ client.remove_scan_wizard(scan_wizard)
46
+ end
47
+ end
48
+
49
+ def disconnect_button(button_bluetooth_address)
50
+ client.force_disconnect(button_bluetooth_address)
51
+ end
52
+
53
+ def listen(latency_mode, *button_bluetooth_addresses)
54
+ connection_channels = []
55
+ button_events = []
56
+ broken = false
57
+
58
+ begin
59
+ button_bluetooth_addresses.each do |button_bluetooth_addresses|
60
+ connection_channel = Client::ConnectionChannel.new(button_bluetooth_addresses, latency_mode)
61
+
62
+ connection_channel.button_up_or_down do |click_type, latency|
63
+ button_events << [button_bluetooth_addresses, click_type, latency]
64
+ end
65
+
66
+ connection_channel.button_single_click_or_double_click_or_hold do |click_type, latency|
67
+ button_events << [button_bluetooth_addresses, click_type, latency]
68
+ end
69
+
70
+ connection_channel.removed do
71
+ broken = true
72
+ end
73
+
74
+ connection_channels << connection_channel
75
+
76
+ client.add_connection_channel connection_channel
77
+ end
78
+
79
+
80
+ loop do
81
+ client.handle_next_event while !broken && button_events.empty?
82
+
83
+ button_events.each do |button_event|
84
+ yield *button_event
85
+ end
86
+
87
+ button_events.clear
88
+
89
+ raise ConnectionChannelRemoved, 'A connection channel was removed' if broken
90
+ end
91
+ ensure
92
+ connection_channels.each do |connection_channel|
93
+ client.remove_connection_channel connection_channel
94
+ end
95
+ end
96
+ end
97
+
98
+ private
99
+
100
+ def process_events_until
101
+ done = false
102
+ result = nil
103
+
104
+ callback = proc do |_result|
105
+ done = true
106
+ result = _result
107
+ end
108
+
109
+ yield callback
110
+
111
+ client.handle_next_event until done
112
+
113
+ result
114
+ end
115
+ end
116
+ end
@@ -1,3 +1,3 @@
1
1
  module Flic
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alec Larsen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-11 00:00:00.000000000 Z
11
+ date: 2016-08-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bindata
@@ -96,11 +96,20 @@ files:
96
96
  - Rakefile
97
97
  - flic.gemspec
98
98
  - lib/flic.rb
99
+ - lib/flic/callbacks.rb
99
100
  - lib/flic/client.rb
100
- - lib/flic/client/connection.rb
101
- - lib/flic/event_bus.rb
102
- - lib/flic/event_bus/driver.rb
103
- - lib/flic/event_bus/subscription.rb
101
+ - lib/flic/client/connection_channel.rb
102
+ - lib/flic/client/features.rb
103
+ - lib/flic/client/features/connection_channel.rb
104
+ - lib/flic/client/features/force_disconnect.rb
105
+ - lib/flic/client/features/get_button_uuid.rb
106
+ - lib/flic/client/features/get_info.rb
107
+ - lib/flic/client/features/ping.rb
108
+ - lib/flic/client/features/scan.rb
109
+ - lib/flic/client/features/scan_wizard.rb
110
+ - lib/flic/client/scan_wizard.rb
111
+ - lib/flic/client/scanner.rb
112
+ - lib/flic/client/server_info.rb
104
113
  - lib/flic/protocol.rb
105
114
  - lib/flic/protocol/commands.rb
106
115
  - lib/flic/protocol/commands/cancel_scan_wizard.rb
@@ -115,6 +124,7 @@ files:
115
124
  - lib/flic/protocol/commands/ping.rb
116
125
  - lib/flic/protocol/commands/remove_connection_channel.rb
117
126
  - lib/flic/protocol/commands/remove_scanner.rb
127
+ - lib/flic/protocol/connection.rb
118
128
  - lib/flic/protocol/events.rb
119
129
  - lib/flic/protocol/events/advertisement_packet.rb
120
130
  - lib/flic/protocol/events/bluetooth_controller_state_change.rb
@@ -147,11 +157,13 @@ files:
147
157
  - lib/flic/protocol/primitives/create_connection_channel_error.rb
148
158
  - lib/flic/protocol/primitives/device_name.rb
149
159
  - lib/flic/protocol/primitives/disconnect_reason.rb
160
+ - lib/flic/protocol/primitives/disconnect_time.rb
150
161
  - lib/flic/protocol/primitives/enum.rb
151
162
  - lib/flic/protocol/primitives/latency_mode.rb
152
163
  - lib/flic/protocol/primitives/removed_reason.rb
153
164
  - lib/flic/protocol/primitives/scan_wizard_result.rb
154
165
  - lib/flic/protocol/primitives/uuid.rb
166
+ - lib/flic/simple_client.rb
155
167
  - lib/flic/version.rb
156
168
  homepage: https://github.com/anarchocurious/flic
157
169
  licenses:
@@ -1,81 +0,0 @@
1
- require 'flic'
2
-
3
- require 'thread'
4
-
5
- module Flic
6
- class EventBus
7
- class Error < StandardError; end
8
- class EventBusShutdown < Error; end
9
-
10
- autoload :Driver, 'flic/event_bus/driver'
11
- autoload :Subscription, 'flic/event_bus/subscription'
12
-
13
- def initialize
14
- @semaphore = Mutex.new
15
- @subscriptions = []
16
- @is_shutdown = false
17
- end
18
-
19
- def subscribe(subscription = Subscription.new)
20
- @semaphore.synchronize do
21
- raise EventBusShutdown if shutdown?
22
-
23
- @subscriptions << subscription
24
- end
25
-
26
- if block_given?
27
- begin
28
- yield subscription
29
- ensure
30
- unsubscribe subscription
31
- end
32
- end
33
- end
34
-
35
- def unsubscribe(subscription)
36
- @semaphore.synchronize do
37
- raise EventBusShutdown if shutdown?
38
-
39
- @subscriptions.delete subscription
40
- end
41
-
42
- subscription.destroy
43
- end
44
-
45
- def listen
46
- subscribe do |subscription|
47
- subscription.listen do
48
- yield
49
- end
50
- end
51
- end
52
-
53
- def broadcast(*args)
54
- @semaphore.synchronize do
55
- raise EventBusShutdown if shutdown?
56
-
57
- @subscriptions.each do |subscription|
58
- subscription.publish(*args)
59
- end
60
- end
61
- end
62
-
63
- def shutdown?
64
- @is_shutdown
65
- end
66
-
67
- def shutdown
68
- @semaphore.synchronize do
69
- unless shutdown?
70
- @is_shutdown = true
71
-
72
- @subscriptions.each do |subscription|
73
- subscription.destroy
74
- end
75
-
76
- @subscriptions.clear
77
- end
78
- end
79
- end
80
- end
81
- end