class Radbeacon::Usb
Constants
- ADVERTISING_RATE_VALUES
- BEACON_TYPES
- C_APPEARANCE
- C_DEVICE_NAME
Define GATT characteristic constants
Generic Access Profile
- C_FIRMWARE_STRING
- C_MANUFACTURER_NAME
Device Information
- C_MODEL_NUMBER
- C_SERIAL_STRING
- DEFAULT_MEASURED_POWER_VALUES
- GATT_ACTION
- GATT_ACTION_CONNECTABLE_TIME
- GATT_ACTION_DFU
- GATT_ACTION_DONOTHING
Define GATT action/result constants
Actions
- GATT_ACTION_FACTORY_RESET
- GATT_ACTION_LOCK
- GATT_ACTION_UPDATE_ADV
- GATT_ACTION_UPDATE_PIN
- GATT_BCTYPE
- GATT_BEACON_SWITCH
- GATT_CONN_TIMEOUT
- GATT_DEV_ID
- GATT_DEV_MODEL
Configuration
- GATT_DEV_NAME
- GATT_ERROR
- GATT_FWVERSION
- GATT_INTERVAL
- GATT_INVALID_PIN
- GATT_MAJOR
- GATT_MINOR
- GATT_NEW_PIN
- GATT_PIN
- GATT_POWER
- GATT_RESULT
- GATT_SUCCES
Results
- GATT_TXPOWER
- GATT_UUID
- TIMEOUT
Timeout length for GATT commands
- TRANSMIT_POWER_VALUES
Transmit power and advertisement frequency values
- VALID_UUID
Valid UUID pattern
Attributes
adv_rate[RW]
beacon_type[RW]
dev_id[RW]
dev_model[RW]
dev_name[RW]
dev_version[RW]
errors[RW]
mac_address[RW]
major[RW]
minor[RW]
power[RW]
tx_power[RW]
uuid[RW]
Public Class Methods
create_if_valid(device)
click to toggle source
# File lib/radbeacon/usb.rb, line 64 def self.create_if_valid(device) # Check everything required_attrs = [GATT_DEV_MODEL, GATT_DEV_ID, GATT_FWVERSION, GATT_DEV_NAME, GATT_UUID, GATT_MAJOR, GATT_MINOR, GATT_POWER, GATT_TXPOWER, GATT_INTERVAL, GATT_BCTYPE] if required_attrs.all? { |key| device.values[key] } self.new(device) end end
new(device)
click to toggle source
# File lib/radbeacon/usb.rb, line 73 def initialize(device) @errors = [] @mac_address = device.mac_address @dev_model = bytes_to_text(device.values[GATT_DEV_MODEL]) @dev_id = bytes_to_text(device.values[GATT_DEV_ID]) @dev_version = bytes_to_text(device.values[GATT_FWVERSION]) @dev_name = bytes_to_text(device.values[GATT_DEV_NAME]) @uuid = bytes_to_uuid(device.values[GATT_UUID]) @major = bytes_to_major_minor(device.values[GATT_MAJOR]) @minor = bytes_to_major_minor(device.values[GATT_MINOR]) @power = bytes_to_power(device.values[GATT_POWER]) @tx_power = TRANSMIT_POWER_VALUES.key(device.values[GATT_TXPOWER]) @adv_rate = ADVERTISING_RATE_VALUES.key(device.values[GATT_INTERVAL].delete(' ')) @beacon_type = BEACON_TYPES.key(device.values[GATT_BCTYPE]) end
Public Instance Methods
boot_to_dfu(pin)
click to toggle source
# File lib/radbeacon/usb.rb, line 130 def boot_to_dfu(pin) dfu_commands = ["#{GATT_ACTION} #{GATT_ACTION_DFU}", "#{GATT_PIN} #{pin_to_bytes(pin)}"] con(dfu_commands) end
change_pin(new_pin, old_pin)
click to toggle source
# File lib/radbeacon/usb.rb, line 119 def change_pin(new_pin, old_pin) update_pin_commands = ["#{GATT_NEW_PIN} #{pin_to_bytes(new_pin)}", "#{GATT_ACTION} #{GATT_ACTION_UPDATE_PIN}", "#{GATT_PIN} #{pin_to_bytes(old_pin)}"] con(update_pin_commands) end
factory_reset(pin)
click to toggle source
# File lib/radbeacon/usb.rb, line 125 def factory_reset(pin) reset_commands = ["#{GATT_ACTION} #{GATT_ACTION_FACTORY_RESET}", "#{GATT_PIN} #{pin_to_bytes(pin)}"] con(reset_commands) && defaults end
lock(pin)
click to toggle source
# File lib/radbeacon/usb.rb, line 135 def lock(pin) lock_commands = ["#{GATT_ACTION} #{GATT_ACTION_LOCK}", "#{GATT_PIN} #{pin_to_bytes(pin)}"] con(lock_commands) end
save(pin)
click to toggle source
# File lib/radbeacon/usb.rb, line 106 def save(pin) if self.valid? update_params_commands = ["#{GATT_DEV_NAME} #{text_to_bytes(@dev_name)}", "#{GATT_UUID} #{uuid_to_bytes(@uuid)}", "#{GATT_MAJOR} #{major_minor_to_bytes(@major)}", "#{GATT_MINOR} #{major_minor_to_bytes(@minor)}", "#{GATT_POWER} #{power_to_bytes(@power)}", "#{GATT_TXPOWER} #{TRANSMIT_POWER_VALUES[@tx_power]}", "#{GATT_INTERVAL} #{ADVERTISING_RATE_VALUES[@adv_rate]}", "#{GATT_BCTYPE} #{BEACON_TYPES[@beacon_type]}", "#{GATT_ACTION} #{GATT_ACTION_UPDATE_ADV}", "#{GATT_PIN} #{pin_to_bytes(pin)}"] con(update_params_commands) else false end end
valid?()
click to toggle source
# File lib/radbeacon/usb.rb, line 89 def valid? @errors = [] @errors << "Invalid device name" unless @dev_name.length <= 20 @errors << "Invalid UUID" unless @uuid.match(VALID_UUID) @errors << "Invalid major value" unless @major.to_i.between?(0, 65535) @errors << "Invalid minor value" unless @minor.to_i.between?(0, 65535) @errors << "Invalid measured power value" unless @power.to_i.between?(-127, -1) @errors << "Invalid transmit power" unless TRANSMIT_POWER_VALUES.has_key?(@tx_power) @errors << "Invalid advertising rate" unless ADVERTISING_RATE_VALUES.has_key?(@adv_rate) @errors << "Invalid beacon type" unless BEACON_TYPES.has_key?(@beacon_type) if @errors.empty? true else false end end
Private Instance Methods
con(commands)
click to toggle source
# File lib/radbeacon/usb.rb, line 157 def con(commands) @errors = [] result = false cmd_line = "gatttool -b #{@mac_address} --interactive" PTY.spawn(cmd_line) do |output, input, pid| output.expect(/\[LE\]>/) input.puts "connect" if output.expect(/Connection successful/, TIMEOUT) commands.each do |cmd| cmd = "char-write-req #{cmd}" input.puts cmd if output.expect(/Characteristic value was written successfully/, TIMEOUT) result = true else @errors << "Action failed: #{cmd}" result = false break end end if result input.puts "char-read-hnd #{GATT_RESULT}" if output.expect(/Characteristic value\/descriptor: 00 00 00 00/, TIMEOUT) result = true else @errors << "Invalid PIN" result = false end end else @errors << "Connection failed" end input.puts "quit" _, status = Process.waitpid2(pid) if !status.success? result = false @errors << "Process failed to exit properly" end end result end
defaults()
click to toggle source
# File lib/radbeacon/usb.rb, line 146 def defaults @dev_name = "RadBeacon USB" @uuid = "2F234454-CF6D-4A0F-ADF2-F4911BA9FFA6" @major = 1 @minor = 1 @power = -66 @tx_power = 3 @adv_rate = 10 @beacon_type = "dual" end