iocp package reference (V1.1.0)

# ::iocp::btTop, Main, Index

The `iocp_bt` package implements Bluetooth support and is loaded as

    package require iocp_bt

The commands are broken into the following namespaces:

::iocp::bt | Core commands for Bluetooth communication.
::iocp::bt::sdr | Commands for handling Bluetooth service discovery records.
::iocp::bt::names | Commands for mapping Bluetooth UUIDs and names.

Note the current limitations:

- Only client-side communication is implemented in this release. Server-side functionality will be added in some future release based on demand.
- Only RFCOMM channels are supported. There is no support for L2CAP or other protocols as these are not exposed at the Win32 API level.
- Bluetooth LE is not currently supported.

This documentation is a reference for the package. For an introductory guide, see the tutorials.

## Device discoverybt, Top, Main, Index

Remote Bluetooth devices are discovered through devices command. It is generally recommended that a new device inquiry be initiated with the `-inquire` option when using this command as otherwise newly reachable devices will not be discovered. The device printn command will print the information related to each device in human-readable form.

Bluetooth radios on the local system can be enumerated with the radios command. There is however rarely a need to do this as it is not required for a establishing a Bluetooth connection.

## Service discoverybt, Top, Main, Index

A device will generally host multiple services. The device services commands will retrieve information about the services advertised by the device. This information is in the form of service discovery records. Commands for parsing these records are contained in the sdr namespace.

Services and service classes are identified with UUID's. Most commands will however accept mnemonics for services defined in the standard as they are easier to remember than the UUID's. The names::print command will print the list of mnemonics and the corresponding UUID's.

## Connection establishmentbt, Top, Main, Index

Establishing a Bluetooth connection involves the following steps.

First, the device name has to be mapped to its physical address. Unlike the TCP sockets in Tcl, Bluetooth sockets require physical addresses to be specified as device names are ambiguous. The device addresses command can be used to obtain the physical addresses corresponding to a name. Note that there can be multiple devices with the same name so the command returns a list of addresses, one per device. When the list contains more than one address, generally the user needs to be prompted to pick one though below we just assume there is a single address in the list.

    set addrs [iocp::bt::device addresses "APN Phone"]
    set addr  [lindex $addrs 0]

Next, the port the service is listening on needs to be resolved with the device port command. In the example below, `OBEXObjectPush` is the service of interest.

    set port [iocp::bt::service port $addr OBEXObjectPush]

Finally, a connection is established to the service using the socket command.

    set so [iocp::bt::socket $addr $port]

Other commands in the namespace provide supporting functions such as device and service discovery.

## Commandsbt, Top, Main, Index

#### device address [::iocp::bt]bt, Top, Main, Index

Returns a Bluetooth address for a given name.

device address name ?args?

##### Parameters

`name` | Name of device of interest.
`args` | Options to control device enquiry. See devices.

##### Description

If a device has multiple addresses, the command may return any one them. If no addresses are found for the device, an error is raised.

##### Return value

Returns a Bluetooth address for a given name.

Show source

    proc ::iocp::bt::device::address {name args} {

        # Returns a Bluetooth address for a given name.
        #  name - name of device of interest
        #  args - Options to control device enquiry. See [devices].
        # If a device has multiple addresses, the command may return any one
        # them. If no addresses are found for the device, an error is raised.
        set addrs [addresses $name {*}$args]
        if {[llength $addrs]} {
            return [lindex $addrs 0]
        }
        error "Could not find address for device \"$name\"."
    }
    # NOTE: showing source of procedure implementing ensemble subcommand.

#### device addresses [::iocp::bt]bt, Top, Main, Index

Returns a list of Bluetooth addresses for a given name.

device addresses name ?args?

##### Parameters

`name` | Name of device of interest.
`args` | Options to control device enquiry. See devices.

##### Return value

Returns a list of Bluetooth addresses for a given name.

Show source

    proc ::iocp::bt::device::addresses {name args} {

        # Returns a list of Bluetooth addresses for a given name.
        # name - name of device of interest
        # args - Options to control device enquiry. See [devices].

        set addresses [lmap device [devices {*}$args] {
            if {[string compare -nocase $name [dict get $device Name]]} {
                continue
            }
            dict get $device Address
        }]
        # Also resolve local system radios
        foreach radio [radios 1] {
            if {[string equal -nocase $name [dict get $radio Name]]} {
                lappend addresses [dict get $radio Address]
            }
        }
        return $addresses
    }
    # NOTE: showing source of procedure implementing ensemble subcommand.

#### device port [::iocp::bt]bt, Top, Main, Index

Resolve the port for a Bluetooth service running over RFCOMM.

device port device service_class

##### Parameters

`device` | Bluetooth address or name of a device. If specified as a name, it must resolve to a single address.
`service_class` | UUID or name of service class of interest. Note the service name cannot be used for lookup.

##### Description

In case multiple services of the same service class are available on the device, the port for the first one discovered is returned.

##### Return value

Returns the port number for the service or raises an error if it cannot be resolved.

Show source

    proc ::iocp::bt::device::port {device service_class} {

        # Resolve the port for a Bluetooth service running over RFCOMM.
        #  device - Bluetooth address or name of a device. If specified as a name,
        #           it must resolve to a single address.
        #  service_class - UUID or name of service class of interest. Note the
        #           service **name** cannot be used for lookup.
        #
        # In case multiple services of the same service class are available on the
        # device, the port for the first one discovered is returned.
        #
        # Returns the port number for the service or raises an error if it
        # cannot be resolved.

        #TBD - maybe use device::services and loop through so we can match service_class
        #against service name as well

        set h [LookupServiceBegin  [ResolveDeviceUnique $device]  [names::service_class_uuid $service_class]]
        try {
            while {1} {
                # 0x100 -> LUP_RETURN_ADDR
                set rec [LookupServiceNext $h 0x100]
                if {[dict exists $rec RemoteAddress] &&
                    [dict get $rec RemoteAddress AddressFamily] == 32} {
                    # 32 -> AF_BTH (Bluetooth)
                    # Further we are looking for RFCOMM (protocol 3)
                    if {[dict exists $rec Protocol] &&
                        [dict get $rec Protocol] == 3} {
                        return [dict get $rec RemoteAddress Port]
                    }
                }
            }
        } finally {
            LookupServiceEnd $h
        }
        error "Could not resolve service \"$service_class\" to a port on device \"$device\"."
    }
    # NOTE: showing source of procedure implementing ensemble subcommand.

#### device print [::iocp::bt]bt, Top, Main, Index

Prints device information in human-readable form to stdout.

device print devinfo

##### Parameters

`devinfo` | A device information record as returned by the devices command.

Show source

    proc ::iocp::bt::device::print {devinfo} {

        # Prints device information in human-readable form to stdout.
        #  devinfo - A device information record as returned by
        #            the [devices] command.
        dict with devinfo {
            puts "Device $Name"
            puts "Address: $Address"
            puts "Class: $Class ($MajorClassName:$MinorClassName)"
            puts "Device categories: ([join $DeviceClasses {, }])"
            puts "Authenticated: $Authenticated"
            puts "Remembered: $Remembered"
            puts "Connected: $Connected"
            puts "Last seen: $LastSeen"
            puts "Last used: $LastUsed"
        }
    }
    # NOTE: showing source of procedure implementing ensemble subcommand.

#### device printn [::iocp::bt]bt, Top, Main, Index

Prints device information in human-readable form to stdout.

device printn dinfolist ?detailed?

##### Parameters

`dinfolist` | A list of device information records as returned by the devices command.
`detailed` | If a true value, detailed information about the device is printed. If false (default), only the address and name are printed in compact form. Optional, default `false`.

Show source

    proc ::iocp::bt::device::printn {dinfolist {detailed false}} {

        # Prints device information in human-readable form to stdout.
        #  dinfolist - A list of device information records as returned by
        #            the [devices] command.
        #  detailed - If a true value, detailed information about the device
        #             is printed. If false (default), only the address and
        #             name are printed in compact form.
        set sep ""
        foreach dinfo $dinfolist {
            if {$detailed} {
                puts -nonewline $sep
                set sep "----------------------------------------------\n"
                print $dinfo
            } else {
                dict with dinfo {
                    puts "$Address $Name"
                }
            }
        }
    }
    # NOTE: showing source of procedure implementing ensemble subcommand.

#### device remove [::iocp::bt]bt, Top, Main, Index

Removes cached authentication information for a device from the system cache.

device remove device

##### Parameters

`device` | Bluetooth address or name of a device. if specified as a name, it must resolve to a single address.

##### Description

The command will raise an error if `$device` is a name that cannot be resolved.

Show source

    proc ::iocp::bt::device::remove {device} {

        # Removes cached authentication information for a device from the system cache.
        #  device - bluetooth address or name of a device. if specified as a name,
        #           it must resolve to a single address.
        # The command will raise an error if $device is a name that cannot be
        # resolved.

        RemoveDevice [ResolveDeviceUnique $device]
    }
    # NOTE: showing source of procedure implementing ensemble subcommand.

#### device service_references [::iocp::bt]bt, Top, Main, Index

Retrieve service discovery records that refer to a specified service.

device service_references device service

##### Parameters

`device` | Bluetooth address or name of a device. If specified as a name, it must resolve to a single address.
`service` | The UUID of a service or service class or its mnemonic.

##### Description

The command will return all service discovery records that contain an attribute referring to the specified service. The returned service discovery records should be treated as opaque and accessed through the service record decoding commands.

##### Return value

Returns a list of service discovery records.

Show source

    proc ::iocp::bt::device::service_references {device service} {

        # Retrieve service discovery records that refer to a specified service.
        #  device - Bluetooth address or name of a device. If specified as a name,
        #           it must resolve to a single address.
        #  service - the UUID of a service or service class or its mnemonic.
        # The command will return all service discovery records that contain
        # an attribute referring to the specified service.
        # The returned service discovery records should be treated as
        # opaque and accessed through the service record decoding commands.
        #
        # Returns a list of service discovery records.

        set h [LookupServiceBegin  [ResolveDeviceUnique $device]  [names::to_uuid $service]]
        set recs {}
        try {
            while {1} {
                # 0x0200 -> LUP_RETURN_BLOB. Returns {Blob BINDATA}
                lappend recs [lindex [LookupServiceNext $h 0x200] 1]
            }
        } finally {
            LookupServiceEnd $h
        }
        return $recs
    }
    # NOTE: showing source of procedure implementing ensemble subcommand.

#### device services [::iocp::bt]bt, Top, Main, Index

Retrieve the service discovery records for top level services advertised by a device.

device services device

##### Parameters

`device` | Bluetooth address or name of a device. If specified as a name, it must resolve to a single address.

##### Description

The command will return all service discovery records that reference the `PublicBrowseRoot` service class. This is not necessarily all the services on the device, only those the device advertises as the top-level services.

The returned service discovery records should be treated as opaque and accessed through the service record decoding commands.

##### Return value

Returns a list of service dscovery records.

Show source

    proc ::iocp::bt::device::services {device} {

        # Retrieve the service discovery records for top level services
        # advertised by a device.
        #  device - Bluetooth address or name of a device. If specified as a name,
        #           it must resolve to a single address.
        #
        # The command will return all service discovery records that reference
        # the `PublicBrowseRoot` service class. This is not necessarily all the
        # services on the device, only those the device advertises as the
        # top-level services.
        #
        # The returned service discovery records should be treated as
        # opaque and accessed through the service record decoding commands.
        #
        # Returns a list of service dscovery records.

        # TBD - add a browse group parameter
        # TBD - perhaps check that the sdr acually refernces browse group in
        # the appropriate attribute
        return [service_references $device 00001002-0000-1000-8000-00805f9b34fb]
    }
    # NOTE: showing source of procedure implementing ensemble subcommand.

#### devices [::iocp::bt]bt, Top, Main, Index

Discover Bluetooth devices.

devices ?args?

##### Parameters

`args` | Optional arguments.
`-authenticated` | Filter for authenticated devices.
`-connected` | Filter for connected devices.
`-inquire` | Issue a new inquiry. Without this option, devices that are not already known to the system will not be discovered.
`-remembered` | Filter for remembered devices.
`-timeout MS` | Timeout for the inquiry in milliseconds. Defaults to 10240ms. Ignored if `-inquire` is not specified.
`-unknown` | Filter for unknown devices.

##### Description

Each device information element is returned as a dictionary with the following keys:

Authenticated | Boolean value indicating whether the device has been authenticated.
Address | Bluetooth address of the devicec.
Class | Device class as a numeric value.
Connected | Boolean value indicating whether the device is connected.
DeviceClasses | Human readable list of general device class categories.
LastSeen | Time when device was last seen. The format is a list of year, month, day, hour, minutes, seconds and milliseconds.
LastUsed | Time when device was last used. The format is a list of year, month, day, hour, minutes, seconds and milliseconds.
MajorClassName | Human readable major device class name.
MinorClassName | Human readable minor device class name.
Name | Human readable name of the device.
Remembered | Boolean value indicating whether the device is connected.

The filtering options may be specified to limit the devices returned. If none are specified, all devices are returned.

##### Return value

Returns a list of device information dictionaries.

Show source

    proc ::iocp::bt::devices {args} {

        # Discover Bluetooth devices.
        # -authenticated - filter for authenticated devices
        # -connected     - filter for connected devices
        # -inquire       - issue a new inquiry. Without this option, devices that are
        #                  not already known to the system will not be discovered.
        # -remembered    - filter for remembered devices
        # -timeout MS    - timeout for the inquiry in milliseconds. Defaults to 10240ms.
        #                  Ignored if `-inquire` is not specified.
        # -unknown       - filter for unknown devices
        #
        # Each device information element is returned as a dictionary with
        # the following keys:
        # Authenticated - Boolean value indicating whether the device has
        #                 been authenticated
        # Address - Bluetooth address of the devicec
        # Class - Device class as a numeric value
        # Connected - Boolean value indicating whether the device is connected
        # DeviceClasses - Human readable list of general device class categories
        # LastSeen - Time when device was last seen. The format is a list of
        #            year, month, day, hour, minutes, seconds and milliseconds.
        # LastUsed - Time when device was last used. The format is a list of
        #            year, month, day, hour, minutes, seconds and milliseconds.
        # MajorClassName - Human readable major device class name.
        # MinorClassName - Human readable minor device class name.
        # Name - Human readable name of the device
        # Remembered - Boolean value indicating whether the device is connected
        #
        # The filtering options may be specified to limit the devices
        # returned. If none are specified, all devices are returned.
        #
        # Returns a list of device information dictionaries.

        set pair [FindFirstDevice {*}$args]
        if {[llength $pair] == 0} {
            # No devices found
            return {}
        }
        lassign $pair finder device
        set device [dict merge $device [DeviceClass [dict get $device Class]]]
        set devices [list $device]
        try {
            while {1} {
                set device [FindNextDevice $finder]
                set device [dict merge $device [DeviceClass [dict get $device Class]]]
                lappend devices $device
            }
        } finally {
            FindFirstDeviceClose $finder
        }
        return $devices
    }

#### radio configure [::iocp::bt]bt, Top, Main, Index

Gets or modifies a radio configuration.

radio configure radio ?args?

##### Parameters

`radio` | The address or name associated with a radio on the system.
`args` | See below.

##### Description

If no arguments are given to the command, it returns the current values of all options in the form of a dictionary.

If exactly one argument is given, it must be the name of an option and the command returns the value of the option.

Otherwise, the arguments must be a list of option name and values. The radio's options are set accordingly. The command returns an empty string for this case. Note that in case of raised exceptions the state of the radio options is indeterminate.

##### Return value

Returns an option value, a dictionary of options and values, or an empty string.

Show source

    proc ::iocp::bt::radio::configure {radio args} {

        # Gets or modifies a radio configuration.
        #  radio - The address or name associated with a radio on the system.
        #  args - See below.
        #
        # Returns an option value, a dictionary of options and values, or an empty
        # string.
        #
        # If no arguments are given to the command, it returns the current
        # values of all options in the form of a dictionary.
        #
        # If exactly one argument is given, it must be the name of an option
        # and the command returns the value of the option.
        #
        # Otherwise, the arguments must be a list of option name and
        # values. The radio's options are set accordingly. The command returns
        # an empty string for this case. Note that in case of raised exceptions
        # the state of the radio options is indeterminate.

        set hradio [Open $radio]
        try {
            if {[llength $args] == 0} {
                return [list  -discoverable [IsDiscoverable $hradio]  -connectable  [IsConnectable $hradio]]
            } elseif {[llength $args] == 1} {
                return [switch -exact -- [lindex $args 0] {
                    -discoverable {IsDiscoverable $hradio}
                    -connectable  {IsConnectable $hradio}
                    default { error "Unknown option \"[lindex $args 0]\"."}
                }]
            } else {
                set unchanged {}
                foreach {opt val} $args {
                    switch -exact -- $opt {
                        -discoverable {
                            set changed [EnableDiscovery $val]
                        }
                        -connectable  {
                            set changed [EnableIncoming $val]
                        }
                        default { error "Unknown option \"$opt\"."}
                    }
                    if {! $changed} {
                        lappend unchanged $opt
                    }
                }
                if {[llength $unchanged]} {
                    error "Options [join $unchanged {, }] could not be modified."
                }
            }
        } finally {
            Close $hradio
        }
    }
    # NOTE: showing source of procedure implementing ensemble subcommand.

#### radio devices [::iocp::bt]bt, Top, Main, Index

Discover devices accessible through the specified radio.

radio devices radio ?args?

##### Parameters

`radio` | Name or address of Bluetooth radio.
`args` | Passed on to devices

##### Description

This command has the same functionality as the devices command except that it restricts discovery only to those devices accessible through the specified radio.

##### Return value

Returns a list of device information dictionaries. See devices for the dictionary format.

Show source

    proc ::iocp::bt::radio::devices {radio args} {

        # Discover devices accessible through the specified radio.
        #  radio - Name or address of Bluetooth radio
        #  args  - Passed on to [::iocp::bt::devices]
        # This command has the same functionality as the [::iocp::bt::devices]
        # command except that it restricts discovery only to those devices
        # accessible through the specified radio.
        #
        # Returns a list of device information dictionaries. See
        # [::iocp::bt::devices] for the dictionary format.

        set hradio [Open $radio]
        try {
            return [::iocp::bt::devices {*}$args -hradio $hradio]
        } finally {
            Close $hradio
        }
    }
    # NOTE: showing source of procedure implementing ensemble subcommand.

#### radio info [::iocp::bt]bt, Top, Main, Index

Get detailed information about a radio on the system

radio info ?radio?

##### Parameters

`radio` | The address or name associated with a radio on the system. If unspecified or the empty string, information about the first radio found is returned. Optional, default `""`.

##### Description

The returned dictionary has the following keys:

Address | The Bluetooth address of the radio.
Name | Name assigned to the local system as advertised by the radio.
Class | Device class as a numeric value.
DeviceClasses | Human readable list of general device class categories.
Subversion | Integer value whose interpretation is manufacturer-specific.
Manufacturer | Integer identifier assigned to the manufacturer.
MajorClassName | Human readable major device class name.
MinorClassName | Human readable minor device class name.

##### Return value

Returns a dictionary containing information about the radio.

Show source

    proc ::iocp::bt::radio::info {{radio {}}} {

        # Get detailed information about a radio on the system
        #  radio - The address or name associated with a radio on the system.
        #          If unspecified or the empty string, information about
        #          the first radio found is returned.
        #
        # The returned dictionary has the following keys:
        #
        # Address - The Bluetooth address of the radio.
        # Name - Name assigned to the local system as advertised by the radio.
        # Class - Device class as a numeric value.
        # DeviceClasses - Human readable list of general device class categories
        # Subversion - Integer value whose interpretation is manufacturer-specific.
        # Manufacturer - Integer identifier assigned to the manufacturer.
        # MajorClassName - Human readable major device class name.
        # MinorClassName - Human readable minor device class name.
        #
        # Returns a dictionary containing information about the radio.

        set hradio [Open $radio]
        try {
            set radio [GetRadioInfo $hradio]
            set radio [dict merge $radio [DeviceClass [dict get $radio Class]]]
        } finally {
            Close $hradio
        }
    }
    # NOTE: showing source of procedure implementing ensemble subcommand.

#### radios [::iocp::bt]bt, Top, Main, Index

Enumerate Bluetooth radios on the local system.

radios ?detailed?

##### Parameters

`detailed` | If true, detailed information about each radio is returned. If false (default), only the radio addresses are returned. Optional, default `false`.

##### Description

When `$detailed` is passed as a boolean false value, a list of radio addresses is returned.

When `$detailed` is passed as a boolean true value, each element of the returned list contains the following keys:

Address | The Bluetooth address of the radio.
Name | Name assigned to the local system as advertised by the radio.
Class | Device class as a numeric value.
DeviceClasses | Human readable list of general device class categories.
Subversion | Integer value whose interpretation is manufacturer-specific.
Manufacturer | Integer identifier assigned to the manufacturer.
MajorClassName | Human readable major device class name.
MinorClassName | Human readable minor device class name.

##### Return value

Returns a list of radio addresses or radio information elements.

Show source

    proc ::iocp::bt::radios {{detailed false}} {

        # Enumerate Bluetooth radios on the local system.
        #  detailed - If true, detailed information about each radio is returned.
        #             If false (default), only the radio addresses are returned.
        #
        # When $detailed is passed as a boolean false value, a list of radio
        # addresses is returned.
        #
        # When $detailed is passed as a boolean true value,
        # each element of the returned list contains the following keys:
        # Address - The Bluetooth address of the radio.
        # Name - Name assigned to the local system as advertised by the radio.
        # Class - Device class as a numeric value.
        # DeviceClasses - Human readable list of general device class categories
        # Subversion - Integer value whose interpretation is manufacturer-specific.
        # Manufacturer - Integer identifier assigned to the manufacturer.
        # MajorClassName - Human readable major device class name.
        # MinorClassName - Human readable minor device class name.
        #
        # Returns a list of radio addresses or radio information elements.

        set pair [FindFirstRadio]
        if {[llength $pair] == 0} {
            return {}
        }
        lassign $pair finder hradio
        set radios {}
        try {
            while {1} {
                set radio [GetRadioInfo $hradio]
                if {$detailed} {
                    lappend radios [dict merge $radio [DeviceClass [dict get $radio Class]]]
                } else {
                    lappend radios [dict get $radio Address]
                }
                CloseHandle $hradio
                set hradio [FindNextRadio $finder]
            }
        } finally {
            FindFirstRadioClose $finder
        }
        return $radios
    }

#### socket [::iocp::bt]bt, Top, Main, Index

Returns a client Bluetooth RFCOMM channel.

socket ?args?

##### Parameters

`args` | See below.

##### Description

The command takes the form

    socket ?-async? device port

where `device` is the Bluetooth hardware address of the remote device and `port` is the RFCOMM port (channel). The `-async` option has the same effect as in the Tcl socket command. It returns immediately without waiting for the connection to complete.

Once the connection is established, Bluetooth channel operation is identical to that of Tcl sockets except that half closes are not supported.

The returned channel must be closed with the Tcl `close` or `chan close` command.

##### Return value

Returns a client Bluetooth RFCOMM channel.

Show source

    proc ::iocp::bt::socket {args} {

        # Returns a client Bluetooth RFCOMM channel.
        #   args - see below.
        # The command takes the form
        #
        #     socket ?-async? device port
        #
        # where `device` is the Bluetooth hardware address of the
        # remote device and `port` is the RFCOMM port (channel).
        # The `-async` option has the same effect as in the Tcl
        # [socket](http://www.tcl-lang.org/man/tcl8.6/TclCmd/socket.htm)
        # command. It returns immediately without waiting for the
        # connection to complete.
        #
        # Once the connection is established, Bluetooth channel operation
        # is identical to that of Tcl sockets except that half closes
        # are not supported.
        #
        # The returned channel must be closed with the Tcl `close`
        # or `chan close` command.
    }

# Start page

# Index

# iocp::bt

# iocp::bt::names

# iocp::bt::sdr

# iocp::inet

# iocp::bt

## Device discovery

## Service discovery

## Connection establishment

## Commands

#### device address Returns a Bluetooth address for a given name.

#### device addresses Returns a list of Bluetooth addresses for a given name.

#### device port Resolve the port for a Bluetooth service running over RFCOMM.

#### device print Prints device information in human-readable form to stdout.

#### device printn Prints device information in human-readable form to stdout.

#### device remove Removes cached authentication information for a device from the system cache.

#### device service_references Retrieve service discovery records that refer to a specified service.

#### device services Retrieve the service discovery records for top level services advertised by a device.

#### devices Discover Bluetooth devices.

#### radio configure Gets or modifies a radio configuration.

#### radio devices Discover devices accessible through the specified radio.

#### radio info Get detailed information about a radio on the system

#### radios Enumerate Bluetooth radios on the local system.

#### socket Returns a client Bluetooth RFCOMM channel.

Document generated by Ruff!