flic 0.0.1 → 0.0.2

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.
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