×
Namespaces

Variants
Actions

Archived:Python on Symbian/ZZ. Bluetooth

From Nokia Developer Wiki
Jump to: navigation, search

Archived.pngAquivado: Este artigo foi arquivado, pois o conteúdo não é mais considerado relevante para se criar soluções comerciais atuais. Se você achar que este artigo ainda é importante, inclua o template {{ForArchiveReview|escreva a sua justificativa}}.

All PySymbian articles have been archived. PySymbian is no longer maintained by Nokia and is not guaranteed to work on more recent Symbian devices. It is not possible to submit apps to Nokia Store.

Article Metadata
Article
Created: hamishwillee (30 Nov 2010)
Last edited: hamishwillee (08 May 2013)

Original Author: User:Alex.Susu

Contents

What is Bluetooth?

Bluetooth is a short range communication standard developed originally by Ericsson, from 1994, as a wireless alternative to serial data cable. The technology keeps evolving even today through the gathered efforts of a Special Interest Group (SIG) composed by Ericsson, IBM, Intel, Nokia, Toshiba (the last four adhered from 1998), 3Com, Microsoft, Motorola, Lucent and many other companies that adhere to the standard. Besides the SIG, Bluetooth is also standardized by IEEE under the reference IEEE 802.15.1. [Springer2007]

From the beginning the main idea of the Bluetooth standard was to specify a low power, low cost radio technology, which could be deployed on a very large scale.

Bluetooth uses the 2.4Ghz ISM (Industrial, Scientific and Medical) frequency range. The technology is normally intended for communication between mobile devices at distances of up to 10 meters apart. This allows the formation of Personal Area Networks (PAN) from devices that can be transported by a person - remember that very common are also Local Area Networks formed by WiFi enabled devices at distances of up to 100 meters apart. An important feature of Bluetooth is that it is low power when compared with other technologies like WiFi which has much higher connection maintenance power consumption.

An important reason to give attention to Bluetooth is that most mobile phones, either smartphones or not, are equipped these days with Bluetooth transceivers. Bluetooth is the only alternative for direct communication between non-smart phones (and other devices), since many are not equipped with WiFi interfaces, nor other short range radios.

The most widespread Bluetooth standard, class 2, version 1.2, allows communication at ranges of up to 10 meters with no obstacles in-between, with a bandwidth of 1 Mbps.

Terminology

Bluetooth is a well developed standard. Its complete specification can be accessed by registered companies from the Bluetooth SIG website (www.bluetooth.org). Obsolete Bluetooth specifications are publicly available. We present in the following paragraphs the fundamental concepts of the technology.

To distinguish between the various radio interfaces that can coexist in close vicinity, Bluetooth uses device addresses with 48 bits long which are usually represented as a 12 hexadecimal digits number - for example, 00:22:65:91:fc:bc. A Bluetooth device can accept various connections from other devices, even simultaneously. In fact, a client can have one or more connections via Bluetooth to the server applications running on a particular remote device. These connections are implemented in Bluetooth using the concept of services, a similar notion to the TCP/IP ports. A Bluetooth service is uniquely described by a name, an UUID or a port number. Symbian uses the term channel to denote a Bluetooth port in its C++ and PySymbian APIs.

At runtime, different port (or channel) values can be assigned to the same Bluetooth service at various instances. For a client application on a different device to be able to connect to this service, Bluetooth uses the Service Discovery Protocol (SDP). The SDP of a device uses a dictionary called the Service Discovery Database, where the server applications are registered to be advertised by the Bluetooth stack to other devices. The client applications perform a lookup after the service name (or UUID) in the database of the neighboring devices of interest and obtain the port (channel) number of the target service.

Bluetooth Profiles

Some of the Bluetooth services are considered universal. They are specified in the standard and are called profiles. Two general profiles are especially useful when programming: Serial Port Profile (SPP) and the Object Exchange (OBEX) Profile.

SPP is built around the RFCOMM protocol (Radio Frequency COMMunication, also called serial port emulation). RFCOMM is a connection oriented transport protocol and it uses socket objects to manage the connection.

The OBEX profile is designed to exchange data such as files, contact and scheduling information. It uses RFCOMM as a transport protocol, but can work over TCP/IP or IrDA as well.

There are other more specialized profiles like Dial-up Networking, Fax, Headset, LAN Access, all using SPP, and File Transfer, Object Push Profile (OPP) and Synchronization, which rely on OBEX.

Communicating via the OBEX Push Profile

A very robust and simple way to communicate via Bluetooth is to send the data via the OBEX Push Profile (OPP) and then read the received Bluetooth Messages. The second step can be achieved by using, for example, the pyinbox module, which can access the Bluetooth messages received by the phone.

The advantages are the following:

  • the programmer does not have to create the listening server socket, since the Symbian OS creates itself the OPP service.
  • OPP uses the Bluetooth only as long as data is transferred and automatically disconnects immediately after transmission, which results also in good power management.
  • sending a file via OPP is a very standard routine - many tools support it and also it requires calling very robust and simple routines.
  • the receiver application can treat asynchronously the Bluetooth messages. In fact the receiver application does not even have to be running when the sender application transfers data - the only requirement is that the standard Symbian OBEX Push Profile has to be started which is the case when the Bluetooth is turned on.
  • it is easier to debug the Bluetooth communication since you can use the Messaging application to see the Bluetooth messages received.

Below, we present an example where two applications are created: one for sending messages (based on OBEX protocol) and other for receiving messages (using the pyinbox module).

Normally the Bluetooth messages (received via the OBEX Push Protocol) are stored on the C drive. In case we want to avoid filling up the internal memory, we can configure Symbian to use a different drive. To do this on S60 3rd edition phones you have to open the Messaging application, go to Options, Settings, choose Other and then at "Memory in use" specify the drive to store the messages. If you choose the label of the E drive, the Bluetooth messages are stored in the E:\private folder - for example, E:\private\1000484b\Mail2\. On S60 2nd edition you can use, for example, the third party application MsvDriveE to move the Messaging folders to the E drive.

Also, to avoid being asked each time "Receive message from [name]?" when a Bluetooth message is being transferred, you have to pair the two communicating devices and authorize the connection on this device. More exactly you have to open the Bluetooth application, choose the right tab ("Paired devices"), go to Options, select “New paired device”, discover the other device and enter a passkey, which has to be confirmed at the other end. When the pairing is completed, go to Options and choose "Set as Authorized".

The simplest way to add the pyinbox extension, as described in the Extending Python on Symbian chapter, is to copy the kf_pyinbox.pyd and module_config.cfg files found in the pyinbox distribution in the "module-repo\dev-modules\pyinbox" folder of the PySymbian SDK installation. These files will be copied by the PySymbian application packager when creating the SIS.

#Sender application
import e32
 
#PySymbian 1.4.5 has the Bluetooth specific functions in the module socket, while PySymbian 1.9+ has them in btsocket.
pys60_version_number = e32.pys60_version_info[0] * 10 + e32.pys60_version_info[1]
if pys60_version_number <= 14:
import socket as btsocket
elif pys60_version_number >= 19:
import btsocket
 
pathFileName = "E:\\file_2send"
 
blueToothServerAddress, services = btsocket.bt_obex_discover()
 
"""
The name of the OBEX Push Profile is different among the manufacturers:
Nokia uses u"OBEX Object Push",
some WindowsCE devices use u"(OPP) Object Push\x00".
Therefore, we use the common substring of these two to search for.
"""

SERVICE_NAME_SUBSTR = "Object Push"
for serviceName in services:
if serviceName.find(SERVICE_NAME_SUBSTR) >= 0:
#The port number is usually 9 on Nokia Symbian phones. But we cannot take this for granted.
port = services[serviceName]
btsocket.bt_obex_send_file(blueToothServerAddress, port, unicode(pathFileName))

The other phone can retrieve the Bluetooth message invoking the code below. Note that pyinbox has a very similar API to the inbox module for SMSes. Besides the functions used in the code we can also bind a callable to be notified of the reception of Bluetooth messages (note that invoking pyinbox.description() in the callable returns an exception or an empty string). Also we can use pyinbox.address(), pyinbox.message_type(), pyinbox.time(), pyinbox.unread().

#Receiver application
import e32
import pyinbox
 
 
def ProcessBluetoothMessage(btMsgId):
global bluetoothInbox
 
fileNameBTMessage = None
if e32.s60_version_info[0] >= 3:
#For S60 3rd+ edition.
btMsgData = bluetoothInbox.data(btMsgId, 0, bluetoothInbox.size(btMsgId))
#bluetoothInbox.attachment_path() gives exception on S60 3rd+ edition, most
# likely because the messages are stored in the OS protected \private folder.
else:
#For S60 2nd edition.
pathFileNameBTMessage = bluetoothInbox.attachment_path(btMsgId)
if not pathFileNameBTMessage: #Should not happen.
return -1
 
fInput = open(pathFileNameBTMessage, "r")
try:
# read() without parameter will read all bytes from the file, take care when dealing with large files
btMsgData = fInput.read()
finally:
fInput.close()
 
print "The name of the file within the Bluetooth message is %s." % bluetoothInbox.description(btMsgId)
#The data of the file within the Bluetooth message is available in btMsgData.
bluetoothInbox.delete(btMsgId) #We delete after processing the file.
 
 
bluetoothInbox = None
def BluetoothServer():
global bluetoothInbox
 
"""
0x10009ED5 is a value that must not be changed, which specifies to the Inbox adapter to read only
the Bluetooth messages from Inbox.
"""

bluetoothInbox = pyinbox.Inbox(0x10009ED5)
#bluetoothInbox.bind(BluetoothMessageCallback)
 
def BluetoothServerReceiver():
global bluetoothInbox
 
"""
Enumerate all Bluetooth messages from Inbox, read their data and then delete them.
0x10009ED5 must not be changed - specifies to read only Bluetooth messages from Inbox.
"""
btMsgList = bluetoothInbox.list_messages(0x10009ED5)
for msg in btMsgList:
ProcessBluetoothMessage(msg)
 
 
#Main
BluetoothServer() #Invoke once the BluetoothServer() to create the BT Inbox adapter.
while (True):
#Check periodically for the BT messages in the Inbox. After we process a new BT message we delete it.
BluetoothServerReceiver()
e32.ao_sleep(10)

A Bluetooth Client-Server Application Using RFCOMM

In this section we present a simple FTP-like application, which uses the RFCOMM protocol (Serial Port Profile) for communication. The client application asks the server to send a specific file from its file system. This happens forever in a loop, which gives also the opportunity to test the maximum communication range between the devices.

A number of other publicly available client-server applications exist – see for example the chat example from [Scheible2007].

This application uses the btsocket module to advertise the service, connect and accept connections. As described below using Bluetooth sockets is very similar to TCP/IP programming, which is treated in detail in the Basic Network Programming chapter:

  • use the btsocket.AF_BT constant to specify the Bluetooth address family instead of AF_INET, as in IPv4,
  • set the desired security of the Bluetooth connections and
  • advertise the Bluetooth service.

Note that in TCP/IP the service is registered at a numeric port value agreed upon at the design of the protocol, which is hard-coded in the server and the client applications and, therefore, no advertising is needed for the connection to be established.

To advertise a Bluetooth service, we use:

    bluetooth.bt_advertise_service(name = u"My_BT", socket, flag = True, class_ = btsocket.RFCOMM)

where:

  • 'name is a Unicode string representing the service name;
  • socket is the server socket;
  • flag, when True, tells to start advertising;
  • class_ specifies the type of communication protocol to use - either btsocket.OBEX or btsocket.RFCOMM.

To stop advertising the service we can invoke the previous function with the flag parameter set to False.

Similar to the Basic Network Programming chapter, we use file-like sockets, to abstract away the buffering details of the data from the sockets.

We must warn that calling btsocket.connect() can lead in few cases to program instability - see, for example, the following discussion: http://www.developer.nokia.com/Community/Discussion/showthread.php?207039-BlueTooth-RFCOMM-crashes-when-used-between-2-Nokia-N95s. This problem should be addressed and solved in the near future.

The code of the client-server application can be found below.

import appuifw
import e32
import os
import struct
import sys
 
try:
import btsocket #For PySymbian from 1.9.x onwards.
except ImportError:
import socket as btsocket #For PySymbian up to 1.4.x.
pass
 
BT_RFCOMM_SERVICE_NAME = "My_BT"
 
LOCAL_FOLDER = "E:\\BlueTooth"
if not os.path.exists(LOCAL_FOLDER):
os.makedirs(LOCAL_FOLDER)
 
stderrFileName = LOCAL_FOLDER + "\\stderr.txt"
stderrFile = open(stderrFileName, "a")
sys.stderr = stderrFile
 
stdoutFileName = LOCAL_FOLDER + "\\stdout.txt"
stdoutFile = open(stdoutFileName, "a")
sys.stdout = stdoutFile
 
 
def SendFile(fdBlueTooth, pathFileName):
#appuifw.note(u"Entered SendFile().", "info")
fileSize = os.path.getsize(pathFileName)
fileSizeStr = struct.pack("<i", fileSize)
fdBlueTooth.write(fileSizeStr)
 
try:
#Read the binary file from disk.
fInput = open(pathFileName, "rb")
fileData = fInput.read()
fInput.close()
except:
fileData = "[NO_FILE]"
 
fdBlueTooth.write(fileData)
#appuifw.note(u"Exiting SendFile().", "info")
 
 
def FileTransferServer():
serverSocket = btsocket.socket(btsocket.AF_BT, btsocket.SOCK_STREAM) #One can use SOCK_DGRAM as well.
channel = btsocket.bt_rfcomm_get_available_server_channel(serverSocket)
 
serverSocket.bind(("", channel))
serverSocket.listen(1)
btsocket.bt_advertise_service(unicode(BT_RFCOMM_SERVICE_NAME), serverSocket, True, btsocket.RFCOMM)
 
"""
For btsocket.set_security(), we can use a combination of one or more of the following flags:
- btsocket.AUTH - it means that the Bluetooth connection needs to be authenticated with a passcode;
- btsocket.AUTHOR - the user is asked to authorize the incoming connection;
- btsocket.ENCRYPT - encrypt the communication.
If we comment btsocket.set_security() then the connection is performed
automatically without any authorization, authenticatio, nor encryption.
"""

#btsocket.set_security(serverSocket, btsocket.AUTH | btsocket.AUTHOR)
 
connectionSocket, client_addr = serverSocket.accept()
fdBlueTooth = connectionSocket.makefile("rw", 0)
appuifw.note(u"Server created pipe.", "info")
try:
while True:
command = fdBlueTooth.readline()
appuifw.note(u"Received command %s." % command, "info")
tokens = command.split(" ")
if tokens[0] == "get-file":
SendFile(fdBlueTooth, LOCAL_FOLDER + "\\" + tokens[1])
except:
appuifw.note(u"Connection lost", "info")
if connectionSocket:
connectionSocket.close()
 
 
def FileTransferClient():
connectionSocket = btsocket.socket(btsocket.AF_BT, btsocket.SOCK_STREAM)
 
address, services = btsocket.bt_discover()
"""
address contains the Bluetooth device addresses selected in the Discover menu (ex: 00:13:fd:fb:66:16) and
services contains a map with keys service names and values channel (or port) number
(for example: {u'My_BT': 2, u'OBEX Object Push': 9}).
"""

 
if BT_RFCOMM_SERVICE_NAME in services:
channel = services[unicode(BT_RFCOMM_SERVICE_NAME)]
connectionSocket.connect((address, channel))
fdBlueTooth = connectionSocket.makefile("rw", 0)
appuifw.note(u"Client created pipe.", "info")
try:
fileName = "file_2send"
while True:
fdBlueTooth.write("get-file %s\n" % fileName) #Note the \n required by the readline() in FileTransferServer().
global LOCAL_FOLDER
fileSizeStr = fdBlueTooth.read(4)
fileSizeTuple = struct.unpack("<i", fileSizeStr)
fileSize = fileSizeTuple[0]
#print "Received 4-bytes data: %s" % txtData
data = fdBlueTooth.read(fileSize) #We can use also fdBlueTooth.readline().
 
#We can write data in "E:\\" + fileName.
appuifw.note(u"Received fileSize = %d, data = %s." % (fileSize, data), "info")
except:
appuifw.note(u"Connection lost", "info")
if connectionSocket:
connectionSocket.close()
else:
appuifw.note(u"Target is not running a file transfer server", "error")
 
 
def Main():
index = appuifw.popup_menu([u"Server", u"Client"], u"Choose Device Type")
 
if (index != None):
if (index == 0):
FileTransferServer()
elif (index == 1):
FileTransferClient()
 
if __name__ == "__main__":
Main()

Other PySymbian Bluetooth Modules

A useful module is miso. Besides the API for process handling, phone rebooting and so on, miso implements two Bluetooth related functions:

  • miso.local_bt_address(), which returns the Bluetooth device address and
  • miso.local_bt_name(), which returns the name of the Bluetooth interface.

Additionally, the UtilBluetoothPyExt module programmatically allows to turn on and off the Bluetooth interface and get the name of the Bluetooth interface.

References


Licence icon cc-by-sa 3.0-88x31.png© 2010 Symbian Foundation Limited. Portions copyright Alex Susu and others in wiki document history list. This document is licensed under the Creative Commons Attribution-Share Alike 2.0 license. See http://creativecommons.org/licenses/by-sa/2.0/legalcode for the full terms of the license.
Note that this content was originally hosted on the Symbian Foundation developer wiki.

This page was last modified on 8 May 2013, at 09:04.
86 page views in the last 30 days.
×