Websites Navigation: Airbit | Shop | m-shell.net
Languages: EN | DE

Module bt: Bluetooth Communication

This module provides access to Bluetooth® wireless communication with other Bluetooth equipped devices. The supported functions are:

  • Obtaining the own bluetooth address and name, and modifying the latter.
  • Getting and setting the Bluetooth visibility flag.
  • Scanning for visible devices and obtaining the address, name and class, also interactively.
  • Creation of services (passive connections), either directly using a channel number, or by registering with an UUID for service discovery.
  • Connecting to services (active connections), either directly using a channel number, or by looking an UUID up via service discovery.

Terminology

Bluetooth is a relatively complex technology. The following is a quick crash course of the key concepts required to completely understand this module. For more information and detailed specifications, see www.bluetooth.org.

  • Device Address: Each Bluetooth device is identified by a unique 48 bit address. In this module, an address is a string of six hexadecimal bytes, separated by colons, e.g. "00:E0:03:5E:AF:CD", or "0:e0:3:5e:af:cd".
  • Device Name: Each Bluetooth device can have a freely assignable name. A well chosen name helps in distinguishing visible devices, but is of little use when trying to automatically identify or find a device.
  • Device Class: Each Bluetooth device has a class defining its type and capabilities. The device class is a 24 bit integer, encoded as follows:

    BitsValueContents
    0-1Always zero
    2-7Minor device class:
    interpretation depends on Major device class
    8-12Major device class:
    0Miscellaneous
    1Computer
    2Phone
    3LAN/Network access point
    4Audio/Video
    5Peripheral (mouse, joystick, keyboard)
    6Imaging (printer, display, scanner, camera)
    7Wearable
    31Uncategorized
    13-23Service class:
    161Positioning (GPS)
    171Networking (LAN)
    181Rendering (Video and Audio)
    191Capturing (Video and Audio)
    201Object Transfer (vCal, vCard)
    211Audio
    221Telephony
    231Information (WWW/WAP-Servers)
  • SDP (Service Discovery Protocol): A mechanism to advertise services (e.g. data synchronization, printing, scanning, or own services), and discover them. Services are identified by UUIDs.
  • UUID (Universally Unique Identifier): This is a 128 bit (16 byte) quantity. In Bluetooth, each service has one or more UUIDs assigned: when creating a service, a UUID should be assigned to it (see bt.start).

    In this module, a UUID is represented as an array of four nonnegative numbers, starting with bits 127 to 96, and ending with bits 31 to 0. See also bt.uuid.

    In Bluetooth, often only 32 bits of the UUID are specified. Such an UUID maps to a 128 bit UUID by adding fixed values for the lower 96 bits:

    u=bt.uuid(12345);
    print u
    → [12345,4096,2147483776,1604007163]
    for v in u do print hexstr(v) end
    → 3039
    1000
    80000080
    5f9b34fb

    A few of the standard 32 bit UUIDs are:

    HexDecimalService Class
    33RFCOMM
    100256L2CAP
    11014353Serial Port
    11034355Dialup Networking
    11054357Obex (Object Exchange)
    11114369Fax
    12044612Generic Telephony

  • RFCOMM (Radio Frequency Communications): Provides reliable communication between two Bluetooth devices. This corresponds to the TCP layer in the Internet world.
  • Channel: An integer identifying an RFCOMM communication stream. This corresponds to a port number in the Internet world. A service can be reached by a device address and a channel number.

Connections Are Streams

Once created, a Bluetooth connection is accessed via module io:
  • io.read, io.readln, and io.readm receive data,
  • io.write, io.writeln, io.writem, io.print, and io.println send data,
  • io.avail gets the number of bytes which can be read without blocking,
  • io.wait waits for data which can be read without blocking,
  • io.close closes the connection.
  • io.ces gets and sets the character encoding scheme. As with files, the default is io.raw.
  • io.timeout sets the timeout for send and receive operations.
  • io.flush sets the auto flush state. If auto flushing is disabled, io.flush must be called to make sure all data is sent.

Simple Example

To illustrate use of the m Bluetooth module, a trivial client-server example is presented. The server reverses each line of input it receives.

Client code:

use bt, io
// have the user select a device
dev=bt.select();
// connect to server
s=bt.conn(dev["adr"], "Reverser");
// write a line
io.writeln(s, "Hello world!");
// read the result
print io.readln(s)
→ !dlrow olleH
// and again
io.writeln(s, "Bye server");
print io.readln(s)
→ revres eyB
io.close(s)

Server code:

// a function which reverses a string
function reverse(s)
  c=code(s);
  i=0; j=len(c)-1;
  while i<j do
    h=c[i]; c[i]=c[j]; c[j]=h; i++; j--
  end;
  return char(c)
end

use bt, io
// create and advertise a service called "Reverser"
service=bt.start("Reverser");
while true do // loop forever
  // wait for a client
  io.print(io.stdout, "Waiting...");
  s=bt.accept(service);
  print bt.adr(s),"ok.";
  // read each line, writing it back reversed
  line=io.readln(s);
  while line#null do
    io.writeln(s, reverse(line));
    line=io.readln(s)
  end;
  io.close(s)
end
→ Waiting...00:0E:07:C9:EE:88 ok.
Waiting...

bt.accept

• function accept(service) → Native Object
  Permissions: FreeComm

Marks service available, then waits for a device connecting to service. When a device connects successfully, marks service as unavailable, and returns the connection stream.

See bt.start for an example.

bt.adr

• function adr(stream) → String
  Permissions: FreeComm
• function adr() → String
  Permissions: FreeComm

With one argument, returns the Bluetooth address of the device stream is connected to.

Without arguments, returns the local (own) Bluetooth address.

s=bt.accept(service);
// who connected?
print bt.adr(s)
→ 00:0E:07:C9:EE:88
// our own bluetooth address
print bt.adr()
→ 00:E0:03:5E:AF:CD

bt.chan

• function chan(service) → Array
  Permissions: FreeComm
• function chan(adr, uuid) → Array
  Permissions: FreeComm

With one argument, returns the channel number of service, in an array with the service name as key.

With two arguments, queries the service discovery database of the device with address adr for all services with the service class UUID defined by uuid, and returns their channel numbers in an array with the service names as keys. See bt.uuid for the values allowed for uuid.

// create a service on a fixed channel
s=bt.start("Sample", 18);
// obtain the channel of the service
c=bt.chan(s);
print c, keys(c)
→ [18] [Sample]
// query a device for all Obex services
c=bt.chan("00:0E:07:C9:EE:88", 4357);
print c, keys(c)
→ [9] [OBEX Object Push]
// query a device for all services using RFCOMM
c=bt.chan("00:0E:07:C9:EE:88", 3);
print c, keys(c)
→ [1,2,10,9,15,11,12,3] [Hands-Free Audio Gateway,
Headset Audio Gateway,OBEX File Transfer,OBEX Object
Push, Imaging,SyncMLClient,...<8>]

bt.conn

• function conn(adr, uuidOrChannel) → Native Object
  Permissions: FreeComm

If uuidOrChannel is an array or a string, queries the service discovery database of the device with address adr for the first service with the service class UUID defined by uuidOrChannel, then connects to the service's channel.

If uuidOrChannel is a number, connects directly to channel uuidOrChannel of the device with address adr, without querying the database.

// connect to the Obex service on a device
dev="00:0E:07:C9:EE:88";
s=bt.conn(dev, [4357]);
io.close(s)
// connect to channel 18 on the same device
s=bt.conn(dev, 18);
io.close(s)

bt.name

• function name() → String
  Permissions: FreeComm
• function name(newname) → String
  Permissions: FreeComm+WriteApp

Without an argument, returns the local (own) device name. With a single argument, set the local device name to newname and returns the old name.

// change the name, returning the old one
print bt.name("Test Device #1")
→ Nokia 6670
// get the current name
print bt.name()
→ Test Device #1

bt.scan

• function scan(limited=false) → Array
  Permissions: FreeComm
• function scan() → Array
  Permissions: FreeComm

With a single argument, scans for other visible bluetooth devices in the neighborhood, and returns the first device found, or null if there is no visible device.
If limited=false, the scan is performed with general unlimited inquiry access code (IAC), returning all devices.
If limited=true, the scan is performed with the faster limited IAC, but only returning devices which are scanning with limited IAC.

Without an argument, continues scanning, and returns the next device found, or null if there are no more devices.

Making an SDP request (bt.chan, bt.conn) ends the current scan, i.e. the next call to bt.scan will always start a new scan.

Each device found is returned as an array with the following keys:

KeyMeaningType
adrDevice addressString
nameDevice nameString
classDevice classNumber

dev=bt.scan(false);
// print each device
while dev#null do
  print dev;
  // get the next device
  dev=bt.scan()
end
→ [00:E0:03:5E:AF:CD,Test Device #1,5243404]
→ [00:0E:07:C9:EE:88,Test Device #2,5251596]

bt.select

• function select() → Array
  Permissions: FreeComm

Shows an interactive dialog scanning for Bluetooth devices and allowing the user to select one. Returns the selected device in the same format as returned by bt.scan, or null if the user cancelled the selection.

print bt.select()
→ [00:E0:03:5E:AF:CD,Test Device #1,5243404]

bt.start

• function start(name, uuidOrChannel=null, flags=0) → Native Object
  Permissions: FreeComm

Creates a service with name name and returns it. To accept an incoming connection on the service, use bt.accept.

If uuidOrChannel is an array or a string, bt.start finds an unused channel and creates a service with the UUID defined by uuidOrChannel. The service is advertised in the service discovery database of the device.

uuidOrChannel=null is equivalent to uuidOrChannel=name.

If uuidOrChannel is a number, listens directly on channel uuidOrChannel, without advertising the service.

The security imposed on incoming connections is defined by flags, which is a combination of the following values:

• const authenticate = 1 Connecting devices must be paired, or mutual password authentication is requested.

• const encrypt = 2 Data transfers are encrypted.

• const authorise = 4 The user is asked for authorisation whenever a device attempts to connect to the channel.

// create a service with the UUID of the Fax
// service class, and asking for authorisation
service1=bt.start("My Fax", [4369], bt.authorise);
// wait for a connection
conn=bt.accept(service1);
...
// create a service listening on channel 18
service2=bt.start("Sample", 18);
conn2=bt.accept(service2);
...

bt.stop

• function stop(service) → null
  Permissions: FreeComm

Stops service. If it has been advertised, it is removed from the service discovery database.

bt.timeout

• function timeout() → Number
  Permissions: FreeComm
• function timeout(ms) → Number
  Permissions: FreeComm

Gets or sets the timeout used during most functions of this module. Without arguments, returns the current timeout in milliseconds. With one argument, returns the old timeout, and sets the new timeout to ms. Setting the timeout to zero (the default) or a negative value disables timeouts, i.e. Bluetooth operations can block indefinitely, or use a timeout defined by the underlying system.

Throws ExcValueOutOfRange if ms exceeds 2147483 (35 minutes and 47.483 seconds).

The timeout is used in all following calls: whenever an operation does not complete within the given number of milliseconds, it throws ErrTimedOut.

 // allow 10 seconds to connect
bt.timeout(10000);
try
  s=bt.conn("00:E0:03:5E:AF:CD", 4)
  // connection successful...
catch e by
  if index(e, "ErrTimedOut") # 0 then throw e end;
  print "Could not connect within 10 seconds"
end

bt.uuid

• function uuid(uuid) → Array
  Permissions: FreeComm

Converts a number, string or array to a 128 bit UUID, and returns the UUID as an array of four integers.

  • If uuid is a number, uuid is considered a 32 bit Bluetooth UUID.
  • If uuid is an array with one element, its only element is considered a 32 bit Bluetooth UUID.
  • If uuid is an array with four elements, they are considered the four 32 bit values making up the entire 128 bit UUID (from highest to lowest).
  • If uuid is a string with two characters or less, the characters are considered a 16 bit Bluetooth UIID.
  • If uuid is a string with three or four characters, the characters are considered a 32 bit Bluetooth UIID.
  • If uuid is a string with more than four characters, its first 16 characters are considered the 16 bytes of the UUID (from highest to lowest). Missing bytes are assumed zero.
All other values throw ErrArgument.

print bt.uuid(12345);
→ [12345,4096,2147483776,1604007163]
print bt.uuid([12345]);
→ [12345,4096,2147483776,1604007163]
print bt.uuid("Sample")
→ [1398893936,1818558464,0,0]
print bt.uuid([1,2])
→ ErrArgument thrown

bt.visible

• function visible() → Boolean
  Permissions: FreeComm
• function visible(newvisible) → Boolean
  Permissions: FreeComm+WriteApp
  Capabilities: certified

  
Compatibility of function bt.visible
Nokia phones before Symbian 8[12]ok
Nokia phones with Symbian 8[13]ErrNotSupported
Symbian 3rd/5th Edition and Sony Ericsson phones[14]ErrNotSupported

Without an argument, returns the current visibility state of this device: true if the device is detectable by others, false if it is not visible. With an argument, sets the visibility to newvisible, and returns the old visibility state.

// make the device visible
bt.visible(true)
// is it visible?
print bt.visible()
→ true


© 2004-2010 airbit AG, CH-8008 Zürich
Document AB-M-LIB-871
mShell Home  > Documentation  > Manuals