Category: Python


“Code less ..Achieve more” is the prime philosophy behind the development of all the Very High Level Languages (or VHLL in short). But less no. of lines should not mean reduced flexibility in terms of choosing an approach in solving a problem. Though many of the VHLL or Scripting Languages as they are popularly known, does not keep in mind the flexibility, yet there area few that have the logic of flexibility and choice as their core. Python is one of them. This fact is evident if one tries to do network programming in Python. The choices are aplenty for the programmer. The choices range from low-level sockets or raw-sockets to a completely extensible and functional web-server. In this tutorial I will be discussing how to use raw sockets to create network oriented applications in Python. The first section will cover the basics of the socket module and by the end of the section a simple echo server will be coded. In the second section the echo server would be enhanced by making it capable of serving multiple clients using the concepts introduced in the first section.

 

Sockets and Ports- Doing it the Python way:

Sockets and ports form the core of any network oriented application. According to the formal definition a socket is “An endpoint of communication to which a name may be bound”. The concept (as well as implementation) comes from the BSD community. The 4.3BSD implementation defines three domains for the sockets:

  1. Unix Domain/ File-system Domain:

The sockets under this domain are used when two or more processes within a system have to communicate with each other. In this domain, the sockets are created within the file system. They are represented as strings that contains local path such as /var/lock/sock or /tmp/sock.

 

  1. Internet Domain:

This domain represents the processes that communicate over the TCP/IP. The sockets created for this domain are represented using a (host, port) tuple. Here host is a fully qualified Internet host name that can be represented using a string or in the dotted decimal format (or IP address).

  1. NS Domain:

This domain is the one used by the processes communicating over Xerox protocol which is now obsolete.

 

Of these only the first two are the most commonly used. Python supports all of these. My discussion would be limited to the Internet Domain. To create an application that uses TCP/IP sockets following are the steps:

 

  1. Creating a socket
  2. Connecting the socket
  3. Binding the socket to an address
  4. Listening and accepting connections
  5. Transferring data/receiving data.

 

But before creating a socket libraries have to be imported. The socket module contains all that is needed to work with sockets. The imports can be done in two ways:

import socket or from socket import *. If the first form is used then to access the methods of socket module, socket.methodname() would have to be used. If the later format is used, then the methods could be called without the fully qualified name. I will be using the second format for clarity of the code and ease. Now lets see the various provisions within socket module for the programmers.

 

  1. Creating a socket:

A socket can be created by making call to the socket() function. The socket() function returns a socket in the domain specified. The parameters to the function are:

 

a. family:

The family parameter specifies in which domain the socket has to be created.  The valid values are AF_UNIX for UNIX domain and AF_INET for internet domain.

b. type:

Type defines the type of the protocol to be used. The type can be                   connection oriented like TCP or connection less like UDP. These are defined by the constants SOCK_STREAM for TCP, SOCK_DGRAM for UDP. Other valid parameters are SOCK RAW, SOCK SEQPACKET and SOCK RDM.

c. protocol:

This generally left for default value. The default is 0.

 

So a socket for Internet domain is created thus:

testsocket=socket(AF_INET,SOCK_STREAM)

 

  1. Connecting the Socket:

Sockets thus created can be used on the server-side or client-side. To use the socket as client-socket it needs to be connected to a host. That can be done using the connect() method of the socket object. The connect() method accepts either the host name as the parameter or a tuple containing host name/address and port number as parameter. For example to connect to a host whose address is 192.168.51.100 and the port number 8080 the statement would be:

 

testsocket.connect((‘192.168.51.100’,8080))

 

  1. Binding the socket to an address:

If the socket has to be used on the server side, then the socket has to be bound to an address and a port, thus naming it. To bind a socket to an address, the bind() method of the socket object has to be used. The valid parameter is a tuple containing the address to which the socket has to be bound and the port at which it has to listen for incoming requests. To use the same socket i.e. testsocket on the server side the statement would be:

 

testsocket.bind((‘192.168.51.100’,8080))

  1. Listening and accepting connections:

Once a socket has been named, then it has to be instructed to listen at the given port for incoming requests. This can be done using the listen() method. The listen accepts a no. representing the maximum queued connection. The argument should be atleast 1. for example the following code sets the max queued connection to 2:

 

testsocket.listen(2)

The next thing to be done is to accept the incoming connection requests. This can be done by the accept() function. This function returns a tuple containing a new socket object representing the client and the address of the client. For example:

clientsock,address= testsocket.accept()

in the above statement clientsock would contains a new socket object and address would contain the address of the client.

 

  1. Transferring data/receiving data:

Data can be transferred using recv() and send() methods of socket object. Socket’s recv() method is used to receive the data send from the server or from the client. The parameters are a buffer size for the data , and flags. The flags parameter is optional. So to receive data the code would be:

buff=1024

testsocket.recv(buff)

 

To send the data, a call to the send method is in order. The parameters are the data to be send and the flags. To elucidate  further:

data=raw_input(‘>>’)

testsocket.send(data)

Now that the steps are clear, lets create a simple echo server. First the imports

from socket import *

Then the constants that defines the host, port, buffer size and the address tuple to be used with bind().

 

from socket import *

HOST = ‘localhost’

PORT = 21567

BUFSIZ = 1024

ADDR = (HOST, PORT)

 

Then create the server side socket and bind it to the host and the port. Then comes the max queue size to 2:

 

from socket import *

HOST = ‘localhost’

PORT = 21567

BUFSIZ = 1024

ADDR = (HOST, PORT)

serversock = socket(AF_INET, SOCK_STREAM)

serversock.bind(ADDR)

serversock.listen(2)

 

Now to make it listen for incoming requests continuously place the accept() method in a while loop. This is not the most preferable mode. The preferable way will be discussed in next section:

 

from socket import *

HOST = ‘localhost’

PORT = 21567

BUFSIZ = 1024

ADDR = (HOST, PORT)

serversock = socket(AF_INET, SOCK_STREAM)

serversock.bind(ADDR)

serversock.listen(2)

 

while 1:

print ‘waiting for connection…’

clientsock, addr = serversock.accept()

print ‘…connected from:’, addr

:

:

Next  receive the data from the client and echo it back. This has to continue till the client doesn’t send the null data or ctrl+c. to achieve this again use a while loop and then close the connection when done.

 

from socket import *

HOST = ‘localhost’

PORT = 21567

BUFSIZ = 1024

ADDR = (HOST, PORT)

serversock = socket(AF_INET, SOCK_STREAM)

serversock.bind(ADDR)

serversock.listen(2)

 

while 1:

print ‘waiting for connection…’

clientsock, addr = serversock.accept()

print ‘…connected from:’, addr

 

while 1:

data = clientsock.recv(BUFSIZ)

if not data: break

clientsock.send(‘echoed’, data)

 

clientsock.close()

serversock.close()

 

That’s all for the server. Now for the client. The only exception is that there is no bind(), accept() and listen().

 

from socket import *

HOST = ‘localhost’

PORT = 21567

BUFSIZ = 1024

ADDR = (HOST, PORT)

tcpCliSock = socket(AF_INET, SOCK_STREAM)

tcpCliSock.connect(ADDR)

while 1:

data = raw_input(‘> ‘)

if not data: break

tcpCliSock.send(data)

data = tcpCliSock.recv(1024)

if not data: break

print data

tcpCliSock.close()

Multi-Threaded Echo Server- Other Approach in Creating a Server:

 

In the above example the uses while loop to service different clients. For elucidations it is ok. But in the real world, it won’t work well. The reason is that more than one client cannot be served simultaneously by just while constructs. To overcome the limitations there are several strategies. One of them is making the server multi-threaded. There are two parts in the creation of a multi threaded server:

 

  1. Create threads for each accepted  connections:

This is the core of the multi-threaded server. For each accepted connection request, a different thread is created and the serving that particular client is carried out by an independent thread. Thus quick response time can be achieved.

 

  1. Create a handler:

It is the handler where the whole processing goes on. In our case transferring a file.

 

To make the echo server some changes have to be made. It starts with the accept part as shown below:

 

from socket import *

from threading import *

HOST = ‘localhost’

PORT = 21567

BUFSIZ = 1024

ADDR = (HOST, PORT)

serversock = socket(AF_INET, SOCK_STREAM)

serversock.bind(ADDR)

serversock.listen(2)

while 1:

print ‘waiting for connection…’

clientsock, addr = serversock.accept()

print ‘…connected from:’, addr

thread.start_new_thread(handler, (clientsock, addr))

 

 

 

serversock.close()

 

After accepting the request a new thread is created for the client. This is done for each connection request. The logic of handling the client is defined within the handler which goes thus:

 

from socket import *

from threading import *

def handler(clientsock,addr):

while 1:

data = clientsock.recv(BUFSIZ)

if not data: break

clientsock.send(‘echoed:..’, data)

 

clientsock.close()

if __name__==’__main__’:

HOST = ‘localhost’

PORT = 21567

BUFSIZ = 1024

ADDR = (HOST, PORT)

serversock = socket(AF_INET, SOCK_STREAM)

serversock.bind(ADDR)

serversock.listen(2)

 

while 1:

print ‘waiting for connection…’

clientsock, addr = serversock.accept()

print ‘…connected from:’, addr

thread.start_new_thread(handler, (clientsock, addr))

#some other cleanup code if necessary

 

The handler has to be defined before calling it. The handler contains the same code that was contained in the inner while loop previously. This example is not optimized. But it serves the purpose of providing a different approach for serving multiple clients. This brings us to the end of this section.

 

Parting Thoughts:

  1. The low level sockets can be mixed and matched with other modules such as threads and forks to create a server capable of serving multiple clients simultaneously.
  2. While using threading approach the locking and synchronization issues must be kept in mind.
  3. The security measures must be taken care of when creating FTP kind of servers.

 

This brings us to the end of this discussion. In the introductory section I mentioned flexibility as one of the core aspects of Python. Ability to work with low-level sockets is one of them. But at the other end of the spectrum are the pre-built yet extensible web-servers. These will be discussed in the near future. Till then…

The arrangement of data within the memory forms the basis of computing. The arrangement of data is known as data-structure. Every language provides variety of built-in data-structures. Languages such as C provide basic data-structure mechanisms using which complex structures can be built whereas languages such as Java use full-blown object-oriented approach for almost all types of data-structures. Then there are languages like Python which takes a middle approach. In this article I would be discussing the middle path used by Python using two of its built-in data-structures – Lists and Tuples. The first section would focus on functionalities of Lists and Tuples. In the second section I would develop a real world application which makes use of Lists and/or Tuples. That’s the agenda for this discussion.

 

List and Tuple – More About Them:

List and Tuple are two of the basic built-in data-structures. As with all other features of Python, these in-built data-structures provide both flexibility and power. The answer to how flexible and powerful they are is what I am going to discuss now. First lets look at List data-structure.

 

1. List:

By definition a List is “An instance of an abstract data type (ADT), formalizing the concept of an ordered collection of entities”. In other words, a List is a collection of objects. In contrast with Array, List contains different objects. That’s how Python also views Lists. Data types (that’s what Python calls built-in data-structures too) such as List is known as compound data type in Python. The operations that can be performed on a List are:

 

a. Creation

b. Addition of elements

c. Accessing and Searching

d. Deletion

 

Many of the library functions essentially create Lists. These functions may be working on Lists themselves such as during accessing and searching. Here are the details:

 

a. Creation:

A List is defined as list of coma separated values between square brackets thus:

 

a = ['spam', 'eggs', 100, 1234]

 

where the items of the List a are of different data types.  This is the most common method of creating a list. The other technique is to use the range() function. The range() function provides a List of consecutive integers. The range() function takes two arguments. The List returned contains all the integers from the first to the second, including the first but not including the second. For example,

>>range(1, 5)

Gives

[1,2,3,4]

Since List itself is a data type, so a List can contain another List. For example,

 

[1,”a”,[2,3]]

 

is perfectly valid List.

 

b. Addition of elements:

There are three ways to add elements to an existing List using member functions of the List which are:

 

i. append adds a single element to the end of the List. For example, let li be

a List, then

>>> li

['a', 'b', 'mpilgrim', 'z', 'example']

>>> li.append(“new”)

>>> li

['a', 'b', 'mpilgrim', 'z', 'example', 'new']

 

ii. insert method inserts a single element into the List. The numeric argument

is the index of the first element that gets shifted out of position. Also there can be two elements of same value at two different positions.

 

>>> li.insert(2, “new”)

>>> li

['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new']

iii. extends concatenates the List passed as argument with the existing List.

For example,

>>> li.extend(["two", "elements"])

>>> li

['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']

 

c. Accessing and Searching:

For accessing and searching, one of the following techniques can be used:

 

i. Slicing:

Slice is a sub-list of a List. Slicing is done using the [n : m] which

returns the part of the List from the n-eth character to the m-eth

character, including the first but excluding the last. For example if a_list is

a List of alphabets from a to f, then

 

>>> a_list = ['a', 'b', 'c', 'd', 'e', 'f']

>>> a_list[1:3]

['b', 'c']

>>> a_list[:4]

['a', 'b', 'c', 'd']

>>> a_list[3:]

['d', 'e', 'f']

>>> a_list[:]

['a', 'b', 'c', 'd', 'e', 'f']

 

ii. Indexing:

Index of a given element can be found using the index() function of List. It returns the first occurrence of the element supplied as argument. That means even if the element occurs twice, only the position of the first element would be returned. If  the element is not found an exception is raised. For example

>>>li=['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']

>>> li

['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']

>>> li.index(“example”)

5

>>> li.index(“new”)

2

>>> li.index(“c”)

Traceback (innermost last):

File “<interactive input>”, line 1, in ?

ValueError: list.index(x): x not in list

 

Apart from these, a List can be accessed as one access an array by specifying index thus:

>>>li=['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']

>>>li[0]

‘a’

d. Deletion:

To delete an element from a List, one can us del. It removes an element from the specified List. For example:

>>> a = ['one', 'two', 'three']

>>> del a[1]

>>> a

['one', 'three']

 

del also can have slice thus:

>>> a_list = ['a', 'b', 'c', 'd', 'e', 'f']

>>> del a_list[1:5]

>>> print a_list

['a', 'f']

That’s all about the operations on Lists. The way the operations are implemented shows the flexibility of Python’s middle path approach. The flexibility doesn’t just stop here. Though strings are immutable and Lists are mutable yet they are inter-convertible. Two of the most useful functions in the string module involve Lists of strings – split and join. The former returns a List composed of individual elements of string separated by the delimiter passed as argument. While the latter creates a string out of supplied List. Following are the examples:

 

>>> import string

>>> song = “The rain in Spain…”

>>> string.split(song)

['The', 'rain', 'in', 'Spain...']

 

Here the string is split on the basis of space as delimiter which is the default delimiter. Next example shows the reverse of the above functionality – string from a List:

 

>>> lst = ['The', 'rain', 'in', 'Spain...']

>>> string.join(lst)

‘The rain in Spain…’

where the joining is done on the basis of space delimiter which again is default delimiter. That’s all about Lists at present. Next lets look at the other compound data-type – Tuple.

 

2. Tuple:

According to definition, “A tuple is a finite sequence (also known as an “ordered list”) of objects, each of a specified type”. In other words, a Tuple is an ordered collection of  objects of different types. In Python, a Tuple is a list of comma separated values but immutable unlike List. So the operations on a Tuple are restricted to the ones that don’t affect its immutability. Accordingly following are the operations that can be performed on a Tuple are:

 

a. Creation

b. Accessing

 

Due to immutability, deletion and addition of new elements are not possible.

 

a. Creation:

Creating or defining a Tuple is as simple as giving a list of values within parenthesis. For example

 

>>> tup = (2, 4, 6, 8, 10)

 

is a Tuple. If a Tuple is having only one element, then, it would be defined as follows:

>>> tup = (5,)

 

b. Accessing:

Since Lists and Tuples are almost same, so the accessing mechanisms also works in similar fashion. Elements of a Tuple can be accessed in two ways:

 

i. Index based:

The elements of a  Tuple can be accessed using their indices. The

index starts at 0. For example to access an element at index 0 of a Tuple

tup, the statement would be:

 

>>> tup = (‘a’, ‘b’, ‘c’, ‘d’, ‘e’)

>>> tup[0]

‘a’

 

ii. Slicing:

As in List, slice operator can be used to access elements of a Tuple. It selects a range of elements. For example the following statement selects elements between 1 and 3 (excluding 3):

>>> tup[1:3]

(‘b’, ‘c’)

That’s about operations on a Tuple. So the question arises, when to use List and when to use Tuple. List can be used almost in all the cases. However, there are certain contexts where Tuple is more useful which are:

 

  • Tuples are faster than lists. If you’re defining a constant set of values and all you’re ever going to do with it is iterate through it, use a tuple instead of a list.
  • It makes your code safer if you “write-protect” data that does not need to be changed. Using a Tuple instead of a list is like having an implied assert statement that this data is constant, and that special thought (and a specific function) is required to override that.

 

In all other contexts, Lists can be used. That brings us to the next section – a real world example using List.

 

Lists And Tuples – In Real World:

The example application would implement a ring buffer or a bounded buffer using List. In a bounded buffer, once the capacity is full, then the first element i.e. the oldest element is replaced with newest element. The implementation uses class switch pattern. Here is the code:

 

class RingBuffer(object):

“”" class that implements a not-yet-full buffer “”"

def __init__(self, size_max):

self.max = size_max

self.data = [  ]

class __Full(object):

“”" class that implements a full buffer “”"

def append(self, x):

“”" Append an element overwriting the oldest one. “”"

self.data[self.cur] = x

self.cur = (self.cur+1) % self.max

def tolist(self):

“”" return list of elements in correct order. “”"

return self.data[self.cur:] + self.data[:self.cur]

def append(self, x):

“”" append an element at the end of the buffer. “”"

self.data.append(x)

if len(self.data) == self.max:

self.cur = 0

# Permanently change self’s class from non-full to full

self.__class__ = __Full

def tolist(self):

“”" Return a list of elements from the oldest to the newest. “”"

return self.data

The class defines an empty List as a buffer. The nested class __Full implements the logic to overwrite the oldest element if the buffer is full. The tolist method returns the List in correct order. Next the append method of the outer class i.e. RingBuffer appends a new item to the end of the List. It also checks whether the length of the buffer is equal to  the max size. If it is equal, then buffer’s state is changed to full. The tolist method returns the buffer. Following is sample implementation that shows how to use the RingBuffer class:

 

if __name__ == ‘__main__’:

x = RingBuffer(5)

x.append(1); x.append(2); x.append(3); x.append(4)

print x.__class__, x.tolist( )

x.append(5)

print x.__class__, x.tolist( )

x.append(6)

print x.data, x.tolist( )

x.append(7); x.append(8); x.append(9); x.append(10)

print x.data, x.tolist( )

That brings us to the end of this discussion. List and Tuple are the basic data-structures found in Python. On the basis of these more complex structures such as trees can be developed. How to implement them would be the topic for discussion in the future. Till then…

In the last article I discussed about various Bluetooth profiles. If one wants to create a client-server based application using Bluetooth, then one should program for the RFCOMM profile. RFCOMM provides socket based client-server paradigm for providing services. In this article, I will focus on creating networked based application using RFCOMM. The first section will be about the whys and wherefores of RFCOMM. In the second section, I will enumerate the steps to create client-server based application using RFCOMM. In the last section, a single-threaded server will be developed that would use RFCOMM to provide a file transfer service. That’s the outline for this discussion.

RFCOMM – The Whys and Wherefores:

The term or abbreviation RFCOMM comes from the terms Radio Frequency or RF. The main aspect of RFCOMM is emulation of serial port communication using Radio Frequency, so the name RFCOMM. The serial port emulated by RFCOMM is RS-232 which has 9-circuits. RFCOMM uses the baseband of Bluetooth to provide reliable and in-sequence delivery of data stream. The main attributes of RFCOMM are:

1. It provides multiple concurrent connections. It does this by relying on L2CAP.

L2CAP can handle multiplexing over a single connection.

2. It supports flow control on separate and individual channels.

3. It does not provide error-control. The assumption that RFCOMM makes is L2CAP

will be providing error-free channel.

4. How devices should communicate using RFCOMM is decided by Serial Port Profile

(SPP), which is one of the Bluetooth profiles.

RFCOMM divides devices into two major classes. They are:

1. Type I

2. Type II

The division is based on whether the port is physically present or it is emulated. Here are the details

1. Type I:

The devices of this type have emulated serial ports. Emulated ports are entities used to map system specific services and their API to the RFCOMM services. Therefore, whenever applications are built for RFCOMM, then Type I devices are used. In other words, Type I Devices enable programmer to use serial port even if there is no physical serial port.

2. Type II:

These devices have physical serial ports. They act as intermediate devices. In other words, they are proxy for relaying transmissions from RFCOMM to an external RS-232 interfaces that may be linked with other devices.

As I have said before, RFCOMM provides a client-server based paradigm. In case of PyBluez, the client-server is based on sockets. And the steps to create them are similar to the steps that one would follow in creating TCP/IP or UDP based sockets. The next section is about those steps. Lets get started with the steps.

Developing Applications for RFCOMM – Step by Step:

The steps to develop RFCOMM based applications can be divided into two main set of steps. They are:

1. Creating the Server

2. Creating the Client

Each of the steps can be again divided into sub-steps. Let us take each step one at a time.

1. Creating the Server:

The server of RFCOMM applications, are essentially, Bluetooth based services. This has to be kept in mind when developing the server. The importance of this point will become clear in the steps regarding the client. Creating the server can be further divided into following steps

a. Creating the Server Socket

b. Binding to a port

c. Listening for requests

d. Accepting the requests

e. Sending data

The steps are same as that for creating TCP/IP-based server. However, the first and last step differs in the case of RFCOMM. The details are as follows

a. Creating the Server Socket:

First step is to create the socket that would listen for and accepts incoming requests and creates the connection. The sockets one would use, when working with RFCOMM, are Bluetooth sockets. To create a Bluetooth socket, BluetoothSocket needs to be called with the protocol to be used. In this case it is RFCOMM. So, in order to create a socket named server_socket the statement will be:

server_socket= Bluetooth.BluetoothSocket(Bluetooth.RFCOMM)

This statement only creates a simple Bluetooth based socket that uses RFCOMM for communication. The next three steps make it a server socket.

b. Binding to a Port:

This is the second step to make a simple socket work as server socket. The socket object needs to be bound to an address and a port so that it can start listening for requests. However, since the socket will be communicating over Bluetooth, IP address is not required. PyBluez will use the address of the device on which it is running. If the device is a Desktop PC, then the address will correspond to the address provided by the Bluetooth adapter or dongle. To bind a socket object to a port, bind() method needs to b called on the socket object. The argument passed is a tuple containing the address and the port no. with which the socket has to be bound. For example, to bind a socket to a port, say 11, the statement will be

server_socket.bind((“”,11))

One point to keep in mind while working with RFCOMM is that RFCOMM uses ports between 1-30 only.

c. Listening for requests:

Once a socket has been bound to a port, next step is to make it listen for

incoming requests. To do this, listen() method needs to be called on the socket object. The listen() method accepts no. of requests to be kept in queue as the argument. For example, to make a socket start listening with a queue of size 3, the statement will be

server_socket.listen(3)

d. Accepting the requests:

Once a request is received, it has to be accepted so that communication can start. To do so, one has to call accept() method on the socket object. The accept() method doesn’t have any arguments. It returns a tuple containing the address of the client and socket object through which further communication can be done. So the statement to accept connection is

client_socket,address=server_socket.accept()

e. Sending/receiving data:

The last step is sending and/or receiving data. If the server is on the desktop pc or normal pc, then sending and receiving can be done using Python library. However, if the server is on say, a smart phone, then the library required will be based on the OS of the smart phone. For a normal PC, one would have to call send() and recv() methods on the socket object returned by the accept() method. Both accept string as arguments. For example, if server wants to send a message say, “hello”, the code will be

client_socket.send(“Hello from server”)

That completes server part. Next comes the client.

2. Developing the Client

The steps to develop the client are almost common to that of developing the server. The steps are

a. Create a socket

b. Connect to a device

c. Sending/receiving data

The first and third steps are same as that of creating the server. So only second step needs scrutinizing. Here are the details

a. Create a socket

Just as with server socket, to create a client socket BluetoothSocket() needs to be called with RFCOMM as the protocol. So, to create a socket that would connect to a server, the statement will be

client_socket= Bluetooth.BluetoothSocket(Bluetooth.RFCOMM)

b. Connect to a device:

To connect to a server, client needs to know the address of the server. In case of Bluetooth, the address will be the address of the device, which is of the form “XX:XX:XX:XX:XX”. So, to connect to a server running on a device with an address of “01:23:45:67:89:AB”, connect() method needs to be called on socket object with the port no and address of the server. For example, if the server port no is 4000 and address is “01:23:45:67:89:AB”, then the statement to connect to it is

address=“01:23:45:67:89:AB”

port=4000

client_sock.connect((address, port))

c. Sending/receiving data:

At the client side too, the way to send and /or receive data is same as that at the server-side. So, to receive any data from the server, the statement will be

data = client_sockect.recv(1024)

print “received [%s]” % data

That completes the steps to create a client and a server. Next, let us see how to develop a server that transfers a file using Bluetooth and RFCOMM.

RFCOMM in Real World:

The server will service only one client at a time. So, it is neither multithreaded nor multi-process based. Let us start. First comes the imports

from bluetooth import *

Then comes the class that will contain the server functionalities. Its constructor will take port no on which the server has to listen. It will also call the create_server function.

from bluetooth import *

class rfcomm_server:

def __init__(self,port):

self.port=port

self.create_server()

Next is the create_server method that will create a RFCOMM based socket and make it listen on the passed port. It then calls the start_server method.

from bluetooth import *

class rfcomm_server:

def __init__(self,port):

self.port=port

self.create_server()

def create_server(self):

self.server_socket=\

Bluetooth.BluetoothSocket(Bluetooth.RFCOMM)

self.server_socket.bind((“”,self.port))

self.start_server()

Next is the start_server method. This method makes the server listen on the port and then starts the connection. After that it asks the user for the file and then transfers it.

from bluetooth import *

class rfcomm_server:

def __init__(self,port):

self.port=port

self.create_server()

def create_server(self):

self.server_socket=\

Bluetooth.BluetoothSocket(Bluetooth.RFCOMM)

self.server_socket.bind((“”,self.port))

self.start_server()

def start_server(self):

while true:

self.server_socket.listen(3)

self.client_socket,address=server_socket.accept()

self.client_socket.send(“Enter the file name”)

file_name= self.client_socket.recv(2048)

if file_name is not None:

transfer_data=open(file_name,’r’).readlines()

for data in transfer_data:

self.client_socket.send(data)

self.client_socket.send(“Transfer complete”)

Next, let us start the server. To do that first we need to check whether main function is being executed. If it is being executed, then create the instance of server.

from bluetooth import *

class rfcomm_server:

def __init__(self,port):

self.port=port

self.create_server()

def create_server(self):

self.server_socket=\

Bluetooth.BluetoothSocket(Bluetooth.RFCOMM)

self.server_socket.bind((“”,self.port))

self.start_server()

def start_server(self):

while true:

self.server_socket.listen(3)

self.client_socket,address=server_socket.accept()

self.client_socket.send(“Enter the file name”)

file_name= self.client_socket.recv(2048)

if file_name is not None:

transfer_data=open(file_name,’r’).readlines()

for data in transfer_data:

self.client_socket.send(data)

self.client_socket.send(“Transfer complete”)

if ‘__name__’==’__main__’:

server=rfcomm_server(20)

That completes the application. It also brings us to the end of this discussion. The discussion until now has not touched upon the topic of service discovery. The next part of discussion will be about service discovery. Till then…

Bluetooth Programming using Python

In today world ad-hoc networks have become common. The main aspect of an ad-hoc network is that the participants of the network communicate more or less in wireless way. Bluetooth has emerged as the prominent mode of wireless communication among devices forming an ad-hoc network. Hence, any software targeted at such devices needs to be Bluetooth enabled. In other words, the language with which such software is developed need to provide API that facilitates Bluetooth enabling. However, most of the time the APIs provided by the languages introduce a steep learning curve due to the lack of flexibility of the language itself. It is here that scripting languages especially a language such as Python provides an easier way. In this discussion, I will focus on the use of Python API for programming Bluetooth devices. The first section will be about the whys and wherefores of Bluetooth and how Python fits into the picture. The second section will enumerate the steps in using Python API in accessing the Bluetooth devices and their services. The third section will put the theory into practice by developing a real world application. That’s the outline for the discussion.

Bluetooth and Python – the Whys and Wherefores:

According to definition Bluetooth is “A radio standard and communications protocol primarily designed for low power consumption, with a short-range (power-class-dependent: 1 metre, 10 metres, 100 m) based on low-cost transceiver microchips in each device”. In other words, Bluetooth is a standard and protocol that uses short-range frequencies to create a wireless connection between two compatible (Bluetooth enabled) devices. Since radio communication system is used, so there is no ‘Line of Sight’ problem that is common with Infra Red based devices. As long as the devices are in range, they can communicate with each other even if one device is in one room and the other device is in a separate room. Bluetooth enabled devices are categorized into three classes which are:

1. Class 1

2. Class 2

3. Class 3

The classification is based on the range in which the devices can communicate. The ordering is from the longest range to the shortest one.

1. Class 1:

The devices under this category have the longest range. The range is approximately up to 100 metres. Devices of this class consume highest amount of power among all the three classes. It consumes 100 mW of power.

2. Class 2:

The devices under this category can be called as medium range devices. The range in which they can communicate is upto 10 metres. With respect to power consumption, they require 2.5 mW.

3. Class 3:

The devices that cannot communicate beyond 1 metre come under this class. The power requirement also is the least for the devices of this class. They require only 1 mW.

If you observe closely the power requirement decreases with the decrease in range. That was a bird’s eye view of Bluetooth. Next let us look at how a device provides services to other device using Bluetooth. Each device provides certain based on a specification known as Wireless Interface Specification. A set of such services forms a profile. Sometimes the profile contains only one service such as streaming of sound from an audio file or it can contain a set of different services such as capturing a live video and streaming it. There are 27 standard profiles that are currently used by different devices. Some of the common profiles are

1. Basic Imaging Profile – Profile for sending, receiving and resizing images.

2. Basic Printing Profile – Profile using which vCards, text, e-mail etc. to the printer

from the device.

3. File Transfer Profile – Profile to access the file system of another device.

4. Headset Profile – One of the most common profiles that provides support for

Bluetooth headsets to work with Bluetooth enabled mobile phones for wireless audio.

5. Serial Port Profile – It emulates the serial cable connectivity and communication.

It uses RFCOMM protocol.

Writing a program for a Bluetooth device, in reality, means programming for the profiles or accessing the functionalities of the profile. For programming, BlueZ library is used commonly that provides access to Bluetooth stack in an object-oriented and modular manner. The Python wrapper for the BlueZ is PyBluez.

The wrapper targets Microsoft Bluetooth stack on Windows and BlueZ stack on GNU/Linux. Using PyBlueZ, one can easily create connection between traditional systems such as laptop, desktop and mobile devices and program the basic profiles such as File Transfer, network communication etc. Now that the library that supports programming for the Bluetooth has been introduced, we can look at the steps required to program the Bluetooth devices using Python.

Bluetooth Programming – Step by Step:

For whatever profile the programming is being done, there are two main steps that one has to follow. They are:

1. Discovering Devices in Range

2. Looking up the Human Readable name

One point to keep in mind is that both of these are probabilistic i.e. sometimes these steps may fail at first attempt. Hence, it is a good idea to repeat these steps twice or thrice before deciding that there are no devices nearby.

1. Discovering Devices in Range:

The first step is to find the devices that are in range so that a connection can be established with them. This is known as discovery of devices. To discover devices in range, one needs to call discover_devices() method. It returns a list of addresses of devices discovered. For example, the following statement discovers devices in range and returns a list of such devices:

discovered_devices = discover_devices()

2. Looking up the Human Readable name:

The address of the discovered devices are of the form “XX:XX:XX:XX:XX” where each X is a hexadecimal character representing “one octet of the 48-bit address”. However, to actually access the device with which one needs to communicate, he/she should know the ‘human readable format’ of the address. One of the main reason is a person gives a name that he or she can remember for a particular device and its easier to match with that name rather than a 48-bit address for the same. To get the human readable format one can use lookup_name() method. It accepts the address of a device and returns its user-friendly or human readable format. For example, to find a device named ‘Raj’ from the list of the of return addresses the code will be:

target_device  = “Raj”

target_device_address = None

for address in discovered_devices:

if target_device==lookup_name(address):

target_device_address=address

break

if target_device_address is not None:

print “The address of the target device is :”, target_device_address

else:

print “Could not find address of target device”

The code iterate over the list of addresses and passes one address at a time to the lookup_name method. Then it compares the returned name with the desired device name. if it matches, then a message is printed and breaks out of the loop.

That completes the basic steps required to connect to any device. Once the discovery is done, then based on type of service, the communication can begin. Now that the steps are clear, let us look at a real world example that uses the steps just detailed to access a Bluetooth device.

Bluetooth Programming – In Real World:

The first rule of any program that one to target the real world is to provide modularity. In our case, we can provide modularity by wrapping up the device discovery code in a class. The name of the class will be Devices. Lets start with the imports

from bluetooth import *

Next comes the class with the constructor. The constructor takes the name of the device whose address has to be found.

from bluetooth import *

class Devices:

def __init__( self, target_device_name):

self.target_device=target_device_name

self.target_device_address= None

Next let us define the method that will perform the method lookup. If the target device is found, it will set the address to the variable self.target_device_address. To find the address, it iterate over the list of addresses returned by discover_devices() method and pass each address to the lookup_name method.

from bluetooth import *

class Devices:

def __init__( self, target_device_name):

self.target_device=target_device_name

self.target_device_address= None

def check_devices(self):

discovered_devices=discover_devices()

for address in discovered_devices:

if self.target_device==lookup_name(address):

self.target_device_address=address

break

Next comes the method that checks whether the address of the target device is found or not. If found it will return the address otherwise it will return None.

from bluetooth import *

class Devices:

def __init__( self, target_device_name):

self.target_device=target_device_name

self.target_device_address= None

def check_devices(self):

discovered_devices=discover_devices()

for address in discovered_devices:

if self.target_device==lookup_name(address):

self.target_device_address=address

break

def device_found(self):

self.check_devices()

if self.target_device_address is not None:

return self.target_device_address

else:

return None

That completes our class. Now let us test it by calling it from another module. The module will first ask the user to enter the name of the device to be discovered. Then it will create an object of the Device class and call the check_device method. The returned result will be displayed to the user. Following is the code

user_device= raw_input(“Enter the device to be discovered:”)

device = Devices(user_device)

addr = device.device_found()

if addr is not None:

print “The address for the device is :”. Adder

else:

print “The device could not be discovered”

That completes our discussion on the basics of Bluetooth programming using Python. The next step is to create and discover services. That will be the topic of next discussion. Till then….

In the last post, the topic of discussion was about basic UI controls that PyS60 provides. These controls are useful when the solution to be developed is simple in terms of interaction. However, if a scenario presents itself where interaction becomes complex, then the basic controls would not suffice. For such situations, advanced controls need to be used that can abstract out the complexities of the interaction to the user as well as provide simple and consistent interface for the developer to work with. PyS60 has many such controls that a developer can use. In this discussion, the focus will be on three of the most commonly used controls – selection list, multi-selection list and text. The first section would focus on the whys and wherefores of these controls. In the last section, the application developed in the previous part will be enhanced using the controls being discussed in this section. That is the agenda for this discussion.

Lists and Text Controls – Whys and Wherefores

There are times when providing a list of choices is a better option than asking the user to enter data in an entry box. In such circumstances, providing a list of choices is a better option. To provide lists, PyS60 has two UI controls

1. Selection List

2. Multi-selection List

The former is a good choice when only one item needs to be chosen whereas when several items need to be chosen then the later is the control of choice. Here are the details.

1. Selection List:

As the name suggests, it displays a list to the user from which he or she can choose. The selection list provided by PyS60 also contains a search field that helps the user to narrow down the choices. It is displayed to the user using a function called selection_list(). It comes under the category of dialogs wrapped in functions. It takes two arguments:

a. choices

b. search_field

The latter is an optional argument.

a. choices:

It is a list of Unicode strings containing the options to be displayed to the user.

b. search_field:

It accepts a ‘0’ or ‘1’ as the value. The value decides whether the search field will be  shown or not. If the value is ‘1’, the search field is shown. The default value is ‘0’ i.e. the search field is off by default. If enabled, the search field is shown after the first key press occurs.

The value returned by the selection_list() function is the index of the selected item. For example, to show a list with ‘egg’, ‘spam’ and ‘butter’ to choose from without any search field, the statements will be

list = [u”egg”, u”spam”, u”butter”]

selection_list(list)

2. Multi-selection List:

There are cases where a single selection is not a solution. This is where multi-selection list comes handy. Like selection list, multi-selection list is also a function that wraps up a dialog and displays the dialog when it is executed. The function that brings up a Multi-selection List is multi_selection_list(). It accepts the following arguments

a. choices

b. style

c. search_field

The first and third are similar to the selection_list() arguments. The second argument is unique to multi_selection_list(). Here are the details

a. choices:

Just as in the case of selection_list, the value accepted by this argument is a list of Unicode strings.

b. style:

This is optional. The value of this parameter decides how the list will be displayed. There are two valid values for the style parameter:

i. checkbox – It is the default value. If ‘checkbox’ is given as the value of the
style, the list presented to the user will be a list containing a
checkbox against each list item. Empty checkboxes indicate
selectable item.

ii. checkmark – It is the other acceptable value for the style argument. If
‘checkmark’ is used as the value, then the list presented to
the user doesn’t have a visual clue as to which item to be
selected. However, once selected, a checkmark will appear
against that item.

c. search_field:

This argument does the same thing that search_field does for selection_list()
function. If value of 1 is passed, the search field is displayed and if value of 0 is
given, the search field is not displayed.

The value returned by the function is tuple containing selected values. If no values are selected, then an empty tuple is returned. For example, the following statements display a list from which multiple items can be selected having the checkmark style, having a search field and the returned values are displayed.

list = [u”egg”, u”spam”, u”butter”]

result = multi_selection_list(list, ‘checkmark’, 1)

print result

Next, let us move onto the control that provides the text editor functionalities.

Text:

It provides text editor with almost all the text formatting functionalities. The control is provided by Text type. Unlike selection or multi-selection list, text is a type. The functionalities provided by text type are categorized under the following:

a. Attributes

b. Methods

Since the text is a type the functionalities are exposed either as a attribute or a method. Here are the details

a. Attributes

Following are the most commonly used attributes of Text:

i. color:

It defines the color of the text. The valid values are all the colors supported by
graphic models in graphics module.

ii. font:

This attribute determines the font family of the text. It can be set using the
supported Unicode name.

iii. style:

It affects the style of the text. The valid values for this attribute are defined as
flags. The valid flags are provided by appuifw module. Some of the commonly
used flags are

  • STYLE_BOLD – Makes the text bold
  • STYLE_UNDERLINE – Underlines a displayed text
  • STYLE_ITALIC – Makes the text italic

For example, to use a Text type with LatinPlain12  as font’ value with bold text, the statements will be

t = appuifw.Text()

t.font = u”LatinPlain12″ # sets font to Latin Plain 12

t.style = appuifw.STYLE_BOLD

b. Methods

Text type provides various methods to perform common operations on the text
held by the editor. The most common methods are:

i. add() : It accepts Unicode string as argument. This method appends a text to
the existing text. It can also be used to insert the
passed argument at current cursor position.

ii. set() : Just like add() method, tt accepts Unicode string as argument. It sets
the passed Unicode string as argument. It replaces any text that
may be present in the editor.

iii. delete() : It accepts two arguments – position and length and deletes length of
characters in the editor starting from the position passed as
argument.

For example, to set a string having value as “This is a text” as the text in the editor, the statement is

t.set(u”This is a text”)

This brings us to the end of this section. In the next section, the guessing game application that was developed in last part will be enhanced using single selection list.

PyS60 in Real World:

In the last discussion, a guessing game was developed. The code was as follows

from appuifw import *

continue_guess=true

while continue_guess:

guess_no=random()

user_guess=query(u”Enter your guess”, ‘number’)

if user_guess is Null:

note(u”You have opted out”)

continue_guess=false

elif user_guess<guess_no:

note(u”Your guess is lesser than the goal”)

elif user_guess>guess_no:

note(u”Your guess is higher than the goal”)

else:

note(u”Congrats for excellent guess”)

user_choice=query(u”Enter Y to continue or N to quit”)

if user_choice is Null or user_choice==’N’:

continue_guess=false

else:

continue_guess=true

Now, let us change the display part for displaying the choices. Instead of taking user’s input using a query dialog, let us show a selection list from which the user can select a value. The following code

user_guess=query(u”Enter your guess”, ‘number’)

needs to be changed to

list = [guess-100, guess, guess*200, u”Quit”]

user_guess = selection_list(list)

first, a list is created using the guess no. and its combination. Then the list is given as an argument to selection_list() method. The returned index, which is the value selected by the user, is then stored in the user_guess variable.

Next, let us change how the result is processed. To do so, the following code

if user_guess is Null:

note(u”You have opted out”)

continue_guess=false

elif user_guess<guess_no:

note(u”Your guess is lesser than the goal”)

elif user_guess>guess_no:

note(u”Your guess is higher than the goal”)

else:

note(u”Congrats for excellent guess”)

to the following

if  guess_no < list [user_guess]:

note(u”Your guess is lesser than the goal”)

elif guess_no < list [user_guess]:

note(u”Your guess is higher than the goal”)

elif guess_no == list [user_guess]:

note(u”Congrats for excellent guess”)

else:

note(“Bye”)

continue_guess = false

The index returned by the selection_list() is used by the if condition to get the value selected by the user, from the list. If the index corresponds to the value lesser or greater than the goal value, then a note is displayed telling the user that he/she is either short of the goal or overshot the goal. Otherwise, user is congratulated. If user selected the option to quit, the continue_guess is set to false, thus ending ‘the game’. The complete code is as follows

from appuifw import *

continue_guess=true

while continue_guess:

guess_no=random()

list = [guess-100, guess, guess*200, u”Quit”]

user_guess = selection_list(list)

if  guess_no < list [user_guess]:

note(u”Your guess is lesser than the goal”)

elif guess_no < list [user_guess]:

note(u”Your guess is higher than the goal”)

elif guess_no == list [user_guess]:

note(u”Congrats for excellent guess”)

else:

note(“Bye”)

continue_guess = false

That completes our application. This discussion focused on the UI controls. From the next discussion, the focus will be moving towards the third party libraries in PyS60. However, the next discussion will focus primarily on graphics module. Till then…

GUI changed the way a program communicates with the user. It made applications interactive. Interactivity is the norm of the day. Mobiles are no exceptions. PyS60 makes creating GUI based applications easy. It can be termed as on of the RAD environment for Symbian OS. In this discussion I will focus on the basics of using UI library provided by PyS60. The first section will focus on the types of the controls. The second section will be about three basic controls – note and query. In the third section, a simple application will be developed that uses the controls discussed in second section. That’s the agenda for this discussion.

Types of Controls:

PyS60 provides controls or widgets (including dialogs) in two forms. They are:

1. Functions

2. Python types

Controls or widgets under the former mostly are methods where as those in latter category are Python objects implemented in C. Here are the details.

1. Functions:

Many of the dialogs are implemented as functions. In PyS60, dialogs take precedence over the other controls such as textboxes, list-boxes etc. This means if a control and a dialog needs to be shown, then dialog will be shown on top of the control, thus hiding the control. The examples of dialogs implemented as functions are note, query, multi_query etc.

2. Python types

The controls such as textboxes are implemented in C and directly accessed in PyS60. Their precedence is lower than UI implemented as Functions. Text, Listbox and Canvas are examples of Python types. These controls are displayed the instant they are set as the part of the application’s body. In other words, these controls are not displayed until they have been registered as the part of the application.

One of the controls is a dialog that has been implemented as a Python type. It is the Form control. That completes the discussion about the types of UI controls lets move onto next section.

UI Controls – Entry and Notes:

Query and Notes controls are the most commonly used of all the controls. They are used to take input and display messages. Here are the details:

1. Query:

Query is a dialog type. It is used to gather input from the user. It presents a single line text box with a label to the user. Since query is a dialog, so it is implemented as a function. There are three parameters to the function. They are:

i. label

ii. type

iii. initial value

The first two are mandatory parameters whereas the third is optional. Here are the details

i. label

It is the question or prompt that is shown to the user when the dialog box is displayed. The value for this argument is an Unicode string. For example, to show the “Enter name” as the prompt, one will use the following as the value of the argument:

U”Enter name”

ii. type

One can compare it with standard input dialog box that is common on PC. Since it is a dialog, it can be of different dialog types. The type is decided by the type parameter of the query function. The different types are:

a. text – it is a simple text. The text is of Unicode type.

b. code -

c. number – in this case, the input box will accept only numbers and not

decimals

d. date – the input is just date

e. time – to take time as input type needs to be set to time.

f. float – to accept only decimals, this type can be used

All these values are string type. For example to set the type to number, the value passed will be

‘number’

iii. initial value

This is an optional parameter. It sets the initial value shown to the user. However, for the type float, setting this value does not have any effect. For text fields i.e. type having value either ‘text’ or ‘code’, the value for this argument is Unicode. If the type is ‘number’, the value that can be passes is numeric values only. If the type is date, then initial value will be seconds since epoch rounded to the nearest local midnight. For example, to set the initial value to 3, the value passed will be

3

The return value of query is the value provided by the user and the type of the input box. Therefore, to display a query with “Enter any number between 1 and 9” as message, with number as the only acceptable data and 0 as initial value, the statement will be

guess=query(u“Enter any number between 1 and 9”, ‘number’,0)

2. note

note is another control implemented as a dialog. It is used to display messages to the user. This is, again, one of the most common controls in the toolkit of PyS60 as it can be used to display different messages. These messages can be anything from simple message such as information about the size of current file or critical messages such as low battery. The note function takes three arguments. They are

a. text

b. type

c. global

Of these, only text is mandatory argument. The other two are optional. Here are the details.

a. text

It is the message to be shown. It is a Unicode string. For example, to show a message stating that the memory is full, the text argument will be of following format

u”Memory is full”

The u at the starting indicates that it is a Unicode text.

b. type

As stated earlier, the note function can be used to display different kinds of messages. The kind of the message is determined by the value passed for ‘type’ parameter. This parameter can accept the following string values:

i. info – it is the default value, if no value is passed. When type is set to info,

the message shown will be of simple kind. Hence, the icon will have

‘i’ as symbol.

ii. error – to show error messages, one can use this string as the value. If the

type is set to ‘error’, the icon will have ‘e’ as the symbol.

iii. conf – set the type to ‘conf’ when the message to be shown is related to

configuration. An example of configuration is selecting and setting

the fonts. Once a font has been set, a message whose type conf can

be shown to the user informing him/her the name of the new font.

c. global

The value of global argument decides whether, the note displayed is global or not. Global note is a note that will be displayed even if the application calling the note function is not in foreground. The global argument takes an integer value. Any value other than zero is used to make a note or the displayed message global. The default value for this argument is zero. For example, to show a non-global message to the user, the value passed to the global argument will be

0

For example to display a global error message stating that memory is full, the statement will be

note(u”Memory is full”, error, 1)

That brings us to the end of second section. Next section will be about an application using whatever has been discussed until now.

PyS60 in Real World

Lets now see how these controls can be used within an application. The application going to be developed is a simple guessing game. It will perform following tasks

1. Choose a random number

2. Ask the user to enter his or her guess

3. Compare and show the result

4. Ask if he or she will like to continue

So lets start. First the imports

from appuifw import *

As you already know the above statement imports all the classess within appuifw module. Next the application has to choose a random number. However, since this will be a repeating process until the user chooses to stop, choosing the random number will be within a loop. The loop will terminate only when user says he or she will like to stop. The code is as follows

from appuifw import *

continue_guess=true

while continue_guess:

guess_no=random()

The loop will continue till continue_guess becomes false. Next, the application needs to accept user’s guess. To accept the value, query function will be used. The message will be “Enter your guess”, the type will be number (since decimals will not be allowed) and no initial value will be displayed. The value will be saved in user_guess variable. Here is the code

from appuifw import *

continue_guess=true

while continue_guess:

guess_no=random()

user_guess=query(u”Enter your guess”, ‘number’)

Next comes the comparison and displaying the result functionality. First, the user_guess will be checked for validity i.e. if user clicked cancel, it will be null. If it is not null, then it will be compare with the guess_no and appropriate no. will be displayed. If user pressed cancel, a “You opted out” will be shown and the continue_guess will be set to false. Here is the code

from appuifw import *

continue_guess=true

while continue_guess:

guess_no=random()

user_guess=query(u”Enter your guess”, ‘number’)

if user_guess is Null:

note(u”You have opted out”)

continue_guess=false

elif user_guess<guess_no:

note(u”Your guess is lesser than the goal”)

elif user_guess>guess_no:

note(u”Your guess is higher than the goal”)

else:

note(u”Congrats for excellent guess”)

Next comes the code that asks user whether to continue or not. The query box is shown to the user with “Enter Y to continue and N quit”. If Y is entered, the loop is continued else the application is exited.

from appuifw import *

continue_guess=true

while continue_guess:

guess_no=random()

user_guess=query(u”Enter your guess”, ‘number’)

if user_guess is Null:

note(u”You have opted out”)

continue_guess=false

elif user_guess<guess_no:

note(u”Your guess is lesser than the goal”)

elif user_guess>guess_no:

note(u”Your guess is higher than the goal”)

else:

note(u”Congrats for excellent guess”)

user_choice=query(u”Enter Y to continue or N to quit”)

if user_choice is Null or user_choice==’N’:

continue_guess=false

else:

continue_guess=true

That completes the application. In this discussion, the focus was on simple UI controls. From the next part, complex UI controls such as forms. Till then…

Soya3D: First Look

I am back with more news from Soya3D. Having developed a ‘Hello World’ kinda application, I am both happy as well as a bit disappointed with the library. Before going into my impressions about the library have a look at the ‘Hello World’ kinda app’s code:

import sys,os, os.path, soya

#initialize soya
soya.init(title = “First”, width = 640, height =480)

#set the data path
soya.path.append(os.path.join(os.path.dirname(sys.argv[0]), “data”))

#create the root of the scene graph

scene = soya.World()

#load model
sun_model = soya.Model.get(“sun”)

#class that rotates the model. The class has been inherited from soya.Body. And it overrides advance_time for adding #rotation

class rotating_sun(soya.Body):
def advance_time(self, proportion):
soya.Body.advance_time(self, proportion)
self.rotate_y(proportion*15.0)
self.rotate_x(10)
#create and attach the model to the scene graph a.k.a world
sun = rotating_sun(scene, sun_model)

#create a light source
light = soya.Light(scene)
light.set_xyz(0.5, 0.0, 2.0)

#set the camera
camera = soya.Camera(scene)
camera.z = 2.0

soya.set_root_widget(camera)

soya.MainLoop(scene).main_loop()

The app loads a model and then rotates it. If you have programmed using TKinter library, you can notice the similarity. Now the good bits about Soya3D:

  • Ease of use in terms of library
  • Simple API model
  • Good amount of example codes
  • Step-by-step explanation
  • Rendering time is good

Now what disappoints me are:

  • The loading time for this simple app ~ 10  secs on my centrino core duo laptop. Thats a bit high. The load time can be discounted due to the interpreted nature of Python
  • Whenever I move the window of the app, the app freezes. Why does this happen – no idea. Couldnt get anything from the docs as well.

Apart from these two I did not encounter any dissapointments. If anyone has any work arounds for this do post. Till next time

Setting up Soya3D

What you need

1. Python 2.4.x :

This is the major requirement. Soya3D and its dependencies require Python 2.4.x otherwise they wont install. I was a bit put off by this

2.  pyOgg 1.3 for Python 2.4

This is for enabling music.  It is Ogg part of Ogg-Vorbis.

3.  pyVorbis 1.4 for Python 2.4

Also for music enabling. Vorbis part of Ogg-Vorbis.

4. Cerealizer 0.4 for Python 2.4

For saving objects in files. Better than pickle as this one is safer. Dont use exe file with is download. Use the following

http://download.gna.org/soya/Cerealizer-0.5.tar.bz2

Untar it using 7-zip.  Fire up the command prompt. Move into the folder created. Run setup.py with build as option. Then run setup.py with install as option. Thats it.

5.  Tofu 0.4 for Python 2.4

Testing framework. Need to read more about this one.

6.  Py2Play0.1.7 for Python 2.4

Peer-to-peer gaming framewor for Python. Soya3dD uses this for networking aspect of gaming.

7.  pysdl_mixer-0.0.3 for Python 2.4

Sound mixer is provided by PySDL Mixer – a port of SDL Mixer.

8.  SDL_Mixer dlls

Thats a lot of softwares to download. But thanks to the following site, I got everything under one roof (so as to say)

http://thomas.paviot.free.fr/soya/

Thats it for now. Next I am going to try out some of the examples.

Blog As Notepad

Ya …blog as a notepad. Thats what I am going to do. I have started experimenting on Soya3D and Visual Python. So whatever I am doing I will be putting it up here. So for today, setting up of Soya3D was complete. I will be start looking at the examples.

Smart phones are becoming a common sight nowadays. Above all, the ‘smartness’ of the smart phones come from the fact that they can be programmed. In other words, one can develop custom applications for these mobiles and use them in the mobiles. Almost all the languages, from C to Java and Perl to Ruby, provide API to access and create services for the smart phones. Among them, nothing, at present, can beat the flexibility and ease-of-development that Python provides. Symbian is the most common OS used by smart phones. Symbian port of Python is known as pyS60. in this discussion I will be focusing on the basics of pyS60. The first section will focus on the topic ‘what is pyS60’. In the second section, I will detail the steps in developing and deploying a pyS60 application. In the last section, a real world application will be developed. That sets the outline for this discussion.

What is PyS60:

PyS60, also known as Python for S60 version, is a port of Python, released by Nokia for Symbian OS and targeted at N60 series of mobiles. The libraries provided by PyS60 can be divided into broad categories:

1. Built-in libraries

2. Dynamically loadable libraries

Since PyS60 essentially, is an extension to the standard Python, so, it is known as Python for S60 extension. Hence the categories can also be called as Built-in extensions and Dynamically loadable extensions. Here are the details

1. Built-in libraries or extensions:

It is one of the two native C++ extensions available in PyS60. These provide non-proprietary API to Symbian 60’s (S60) platform. The built-in extensions again divided into two modules:

i. e32:

This module provides access to those services that are not available in standard Python libraries. Essentially, this module is built into the Python interpreter to provide access to the Platform services of S60. These services include timer service (Ao_timer class), system information (sysinfo module and its classes), listing of the drives (drive_list method) etc.

ii. appuifw:

Using this module developer can access the API related to UI elements of S60 platform. The main UI elements include Text, Listbox, Canvas etc. Using the elements GUI can be constructed either as part of a window or as the part of screen itself. If the elements or controls are the part of the window then window becomes the container.

2. Dynamically loadable libraries or extension:

These extensions, as the name suggests, are loaded dynamically i.e. only when

needed as opposed to the Built-in extensions which are loaded when import statement is encountered. The reason for such a behavior is that the Dynamically Loadable extensions provide access to proprietary S60 API. There are 16 dynamically loadable extensions. Most commonly used among them are

i. graphics:

It provides access to the graphics manipulation capabilities of S60 platform including loading, saving, resizing of images.

ii. messaging:

This module provides access to the messaging capabilities of the S60. It

includes SMS and MMS services.

iii. inbox:

Using the inbox module one can access the inbox of the mobile on which

application is being executed. The information one can access includes the

message, time of message, the address of the sender etc.

iv. camera:

When one wants to access the camera, one can use this module. It grants access to all the functionalities of the camera that include image modes, flash modes, maximum zoom available etc.

v. audio:

It provides access to the audio capabilities of the device. The functionalities

include playback of different formats of audio files, recording of voice, text to

speech etc.

vi. calendar:

To use the calendar functionalities of the device, one can make use of this

module.

vii. contacts:

Using contacts module, one can access the contact list in a device. The

contacts are provided in the form of dictionary.

That completes the services provide by PyS60. Next, let us see the steps in

accessing the different services of the mobile using Python.

Accessing Services – Step By Step:

The ease of programming using Python reduces the steps required to access the different services. However, there are two steps that is always required. They are:

1. Instantiating the object of the Service

2. Setting the required properties

3. Calling the methods to access required functionality

These steps are generic to not only S60 platform but also to any mobile platform, including embedded Linux, which is another mobile platform. I will use sound module as an example for all the steps.

1. Instantiating the object of Service:

Most of the time this is the first step in accessing the service. This step is essential when working with built-in extensions. However, for most of the dynamically loadable extensions, objects are not required as their functionalities can be directly accessed. The reason is that the methods of the dynamically loadable modules are static. For example, to create a text field (the name of text field component is query) the statements will be

input= query(u”Enter Text”,”Text”)

On the other hand, to use sound module to load a file, one has to just call the open method of Sound class. The open method is a static, so object of Sound class is not required. Following statement opens a .wav file named test.wav.

Sound.open(“test.wav”)

2. Setting the required attributes:

Next step is to set up the attributes of the object instantiated. If the service can be accessed through static methods, then attributes can also be set or accessed through static mutators (setters) or accessors (getters). As with all the classes of Python, the attributes can be set at the time of instantiating the object. For example, selection_list can be used to show a list of items to the user, from which he or she can tell his or her choice. The option to show a search field can be set at instantiation. The following statements display a list of fonts available on the device and let the user select one of the available fonts.

li =available_fonts()

sl=selection_list(li,1)

However, to set the volume of Sound object one has to just call the set_volume() method, which is again a static method. The following statement sets the volume to 10.

Sound.set_volume(10)

3. Calling the methods to access required functionality:

The last step is to call the required methods on the objects to access the services. If the object is a UI component then the ‘service’ will either be displaying some value to the user or get some value from the user. If it were a device-based service such as Sound, then accessing the functionality would mean requesting the platform to either play or stop the audio file. For example, the query component returns the value entered by the user after initialization. Therefore, the instantiation returns the value entered by the user. The returned value can be displayed using note object. The following statements accepts a string from the user and display it to the user

data=entry(u”Enter your message:”, “text”)

note(u”Your message was: “+data, “info”)

If one needs to access the play service provided by Sound module, he or she has to just call the play() method of Sound class. The following statement just does that

Sound.play()

That completes the steps to work with PyS60. One point to keep in mind is that the string being passed to the methods and constructors need to be Unicode i.e. the string should be prefixed with “u” otherwise the string may not be displayed correctly. Next, I am going to develop a small application that would accept path to a .wav file and then play it.

PyS60 Programming – In Real World:

The application to be developed will have the following functionalities

1. Input box – To accept the path for file to be played

2. Playing the selected File – To play the file entered by the user

Here we go. First comes the imports. Since both UI and Sound are required, so appuifw and audio modules need to be imported

from appuifw import *

import audio

Next we need to show the entry box to the user and get the path entered by him or her. To display the text box, we can use query component. The first argument is the prompt to be shown and the second argument is the type of query. The type can be ‘text’, ’date’, ’time’, ’float’ etc. Here the type will be text as we need textual data i.e. string. The value returned by query component will be stored in a variable named data. Since, the value returned by

from appuifw import *

import audio

data=query(u’Enter the path of the file to be played’, ‘text’)

Now we need to load the file. For that we need to call the load method of sound. As discussed in the previous section every method in sound module is static. We will also check whether user clicked cancel. If cancel has been clicked, then data will contain null.

from appuifw import *

import audio

data=query(u’Enter the path of the file to be played’, ‘text’)

if data is not Null:

Sound.load(data)

else:

note(u’Give the path name’, ‘info’)

Next let us tell Symbian to play it.

from appuifw import *

import audio

data=query(u’Enter the path of the file to be played’, ‘text’)

if data is not Null:

Sound.load(data)

Sound.play()

else:

note(u’Give the path name’, ‘info’)

That completes our application. Though it is small, yet it introduces several important concepts of PyS60. In the coming discussions, I will go into the depth of each module. Till then…

Follow

Get every new post delivered to your Inbox.