Class: Tinkerforge::IPConnection

Inherits:
Object
  • Object
show all
Defined in:
lib/tinkerforge/ip_connection.rb

Constant Summary collapse

CALLBACK_ENUMERATE =
253
CALLBACK_CONNECTED =
0
CALLBACK_DISCONNECTED =
1
ENUMERATION_TYPE_AVAILABLE =

enumeration_type parameter for CALLBACK_ENUMERATE

0
ENUMERATION_TYPE_CONNECTED =
1
ENUMERATION_TYPE_DISCONNECTED =
2
CONNECT_REASON_REQUEST =

connect_reason parameter for CALLBACK_CONNECTED

0
CONNECT_REASON_AUTO_RECONNECT =
1
DISCONNECT_REASON_REQUEST =

disconnect_reason parameter for CALLBACK_DISCONNECTED

0
DISCONNECT_REASON_ERROR =
1
DISCONNECT_REASON_SHUTDOWN =
2
CONNECTION_STATE_DISCONNECTED =

returned by get_connection_state

0
CONNECTION_STATE_CONNECTED =
1
CONNECTION_STATE_PENDING =

auto-reconnect in progress

2

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeIPConnection

Creates an IP Connection object that can be used to enumerate the available devices. It is also required for the constructor of Bricks and Bricklets.



490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
# File 'lib/tinkerforge/ip_connection.rb', line 490

def initialize
  @host = nil
  @port = 0

  @timeout = 2.5

  @auto_reconnect = true
  @auto_reconnect_allowed = false
  @auto_reconnect_pending = false

  @next_sequence_number = 0 # protected by sequence_number_mutex
  @sequence_number_mutex = Mutex.new

  @next_authentication_nonce = 0 # protected by authentication_mutex
  @authentication_mutex = Mutex.new # protects authentication handshake

  @devices = {}

  @registered_callbacks = {}

  @socket_mutex = Mutex.new
  @socket_send_mutex = Mutex.new
  @socket = nil # protected by socket_mutex
  @socket_id = 0 # protected by socket_mutex

  @receive_flag = false
  @receive_thread = nil

  @callback = nil

  @disconnect_probe_flag = false
  @disconnect_probe_queue = nil
  @disconnect_probe_thread = nil # protected by socket_mutex

  @waiter_queue = Queue.new

  @brickd = BrickDaemon.new '2', self
end

Instance Attribute Details

#devicesObject

Returns the value of attribute devices.



461
462
463
# File 'lib/tinkerforge/ip_connection.rb', line 461

def devices
  @devices
end

#timeoutObject

Returns the value of attribute timeout.



462
463
464
# File 'lib/tinkerforge/ip_connection.rb', line 462

def timeout
  @timeout
end

Instance Method Details

#authenticate(secret) ⇒ Object

Performs an authentication handshake with the connected Brick Daemon or WIFI/Ethernet Extension. If the handshake succeeds the connection switches from non-authenticated to authenticated state and communication can continue as normal. If the handshake fails then the connection gets closed. Authentication can fail if the wrong secret was used or if authentication is not enabled at all on the Brick Daemon or the WIFI/Ethernet Extension.

For more information about authentication see www.tinkerforge.com/en/doc/Tutorials/Tutorial_Authentication/Tutorial.html



596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
# File 'lib/tinkerforge/ip_connection.rb', line 596

def authenticate(secret)
  @authentication_mutex.synchronize {
    if @next_authentication_nonce == 0
      @next_authentication_nonce = SecureRandom.random_number(1 << 32)
    end

    server_nonce = @brickd.get_authentication_nonce
    client_nonce = unpack(pack([@next_authentication_nonce], 'L'), 'C4')[0]
    @next_authentication_nonce += 1
    nonce_bytes = pack [server_nonce, client_nonce], 'C4 C4'
    digest_bytes = OpenSSL::HMAC.digest 'sha1', secret, nonce_bytes
    digest = unpack(digest_bytes, 'C20')[0]

    @brickd.authenticate client_nonce, digest
  }
end

#connect(host, port) ⇒ Object

Creates a TCP/IP connection to the given host and port. The host and port can point to a Brick Daemon or to a WIFI/Ethernet Extension.

Devices can only be controlled when the connection was established successfully.

Blocks until the connection is established and throws an exception if there is no Brick Daemon or WIFI/Ethernet Extension listening at the given host and port.



539
540
541
542
543
544
545
546
547
548
549
550
# File 'lib/tinkerforge/ip_connection.rb', line 539

def connect(host, port)
  @socket_mutex.synchronize {
    if @socket != nil
      raise AlreadyConnectedException, "Already connected to #{@host}:#{@port}"
    end

    @host = host
    @port = port

    connect_unlocked false
  }
end

#create_packet_header(device, length, function_id) ⇒ Object

internal



707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
# File 'lib/tinkerforge/ip_connection.rb', line 707

def create_packet_header(device, length, function_id)
  uid = 0
  sequence_number = get_next_sequence_number
  response_expected = false
  r_bit = 0

  if device != nil
    uid = device.uid
    response_expected = device.get_response_expected function_id
  end

  if response_expected
    r_bit = 1
  end

  sequence_number_and_options = (sequence_number << 4) | (r_bit << 3)
  header = pack [uid, length, function_id, sequence_number_and_options, 0], 'L C C C C'

  [header, response_expected, sequence_number]
end

#disconnectObject

Disconnects the TCP/IP connection from the Brick Daemon or the WIFI/Ethernet Extension.



554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
# File 'lib/tinkerforge/ip_connection.rb', line 554

def disconnect
  callback = nil

  @socket_mutex.synchronize {
    @auto_reconnect_allowed = false

    if @auto_reconnect_pending
      # Abort pending auto reconnect
      @auto_reconnect_pending = false
    else
      if @socket == nil
        raise NotConnectedException, 'Not connected'
      end

      disconnect_unlocked
    end

    # Destroy callback thread
    callback = @callback
    @callback = nil
  }

  # Do this outside of socket_mutex to allow calling (dis-)connect from
  # the callbacks while blocking on the join call here
  callback.queue.push [QUEUE_KIND_META, [CALLBACK_DISCONNECTED,
                                         DISCONNECT_REASON_REQUEST, nil]]
  callback.queue.push [QUEUE_KIND_EXIT, nil]

  if Thread.current != callback.thread
    callback.thread.join
  end
end

#enumerateObject

Broadcasts an enumerate request. All devices will respond with an enumerate callback.



665
666
667
668
669
# File 'lib/tinkerforge/ip_connection.rb', line 665

def enumerate
  request, _, _ = create_packet_header nil, 8, FUNCTION_ENUMERATE

  send_request request
end

#get_auto_reconnectObject

Returns true if auto-reconnect is enabled, false otherwise.



646
647
648
# File 'lib/tinkerforge/ip_connection.rb', line 646

def get_auto_reconnect
  @auto_reconnect
end

#get_connection_stateObject

Can return the following states:

  • CONNECTION_STATE_DISCONNECTED: No connection is established.

  • CONNECTION_STATE_CONNECTED: A connection to the Brick Daemon or the WIFI/Ethernet Extension is established.

  • CONNECTION_STATE_PENDING: IP Connection is currently trying to connect.



620
621
622
623
624
625
626
627
628
# File 'lib/tinkerforge/ip_connection.rb', line 620

def get_connection_state
  if @socket != nil
    CONNECTION_STATE_CONNECTED
  elsif @auto_reconnect_pending
    CONNECTION_STATE_PENDING
  else
    CONNECTION_STATE_DISCONNECTED
  end
end

#get_next_sequence_numberObject

internal



698
699
700
701
702
703
704
# File 'lib/tinkerforge/ip_connection.rb', line 698

def get_next_sequence_number
  @sequence_number_mutex.synchronize {
    sequence_number = @next_sequence_number + 1
    @next_sequence_number = sequence_number % 15
    sequence_number
  }
end

#get_timeoutObject

Returns the timeout as set by set_timeout.



659
660
661
# File 'lib/tinkerforge/ip_connection.rb', line 659

def get_timeout
  @timeout
end

#register_callback(id, &block) ⇒ Object

Registers a callback with ID id to the block block.



692
693
694
695
# File 'lib/tinkerforge/ip_connection.rb', line 692

def register_callback(id, &block)
  callback = block
  @registered_callbacks[id] = callback
end

#send_request(request) ⇒ Object

internal



729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
# File 'lib/tinkerforge/ip_connection.rb', line 729

def send_request(request)
  @socket_mutex.synchronize {
    if @socket == nil
      raise NotConnectedException, 'Not connected'
    end

    begin
      @socket_send_mutex.synchronize {
        @socket.send request, 0
      }
    rescue IOError
      handle_disconnect_by_peer DISCONNECT_REASON_ERROR, @socket_id, true
      raise NotConnectedException, 'Not connected'
    rescue Errno::ECONNRESET
      handle_disconnect_by_peer DISCONNECT_REASON_SHUTDOWN, @socket_id, true
      raise NotConnectedException, 'Not connected'
    end

    @disconnect_probe_flag = false
  }
end

#set_auto_reconnect(auto_reconnect) ⇒ Object

Enables or disables auto-reconnect. If auto-reconnect is enabled, the IP Connection will try to reconnect to the previously given host and port, if the connection is lost.

Default value is true.



635
636
637
638
639
640
641
642
# File 'lib/tinkerforge/ip_connection.rb', line 635

def set_auto_reconnect(auto_reconnect)
  @auto_reconnect = auto_reconnect

  if not @auto_reconnect
    # Abort potentially pending auto reconnect
    @auto_reconnect_allowed = false
  end
end

#set_timeout(timeout) ⇒ Object

Sets the timeout in seconds for getters and for setters for which the response expected flag is activated.

Default timeout is 2.5.



654
655
656
# File 'lib/tinkerforge/ip_connection.rb', line 654

def set_timeout(timeout)
  @timeout = timeout
end

#unwaitObject

Unwaits the thread previously stopped by wait.

Wait and unwait act in the same way as “acquire” and “release” of a semaphore.



687
688
689
# File 'lib/tinkerforge/ip_connection.rb', line 687

def unwait
  @waiter_queue.push nil
end

#waitObject

Stops the current thread until unwait is called.

This is useful if you rely solely on callbacks for events, if you want to wait for a specific callback or if the IP Connection was created in a thread.

Wait and unwait act in the same way as “acquire” and “release” of a semaphore.



679
680
681
# File 'lib/tinkerforge/ip_connection.rb', line 679

def wait
  @waiter_queue.pop
end