Supporting a phone in BitPim

This document describes how to support a phone in BitPim. The intention of the implementation behind BitPim is to allow both a GUI driven user interface as well as a command line driven one (although the latter has not been implemented). It is also good abstraction to keep phone communication details and the actual UI etc seperate.

In the GUI version of BitPim, the UI operates in the main thread, and the phone communication code operates in a background thread. This keeps the UI responsive and means the phone thread doesn't have to remember state and be event driven. It also means that the phone thread cannot make any gui requests. In the command line version, everything will run in the main (and only) thread.

You should browse through the source and become familiar with the layout and purpose of each module. The developer page has links to the apidoc and cross-referenced source. If there is a function with no or inadequate documentation, please point it out on the bitpim-devel list. I consider that a bug and will fix it immediately.

Example

The best example to look at is the LG VX4400. This was the first phone implemented, and is the most feature complete.

Your code

You should put the code that implements your phone into a file with the prefix com_ (for example com_lgvx4400.py). The code executed in the communications thread should be a class named Phone. You will want to multiply inherit from the base phone class (com_phone.Phone) as well as from other phone classes (eg com_brew.BrewProtocol). There may also be a base class for the manufacturer of your phone since there is normally a lot in common for all models (for example com_lg is common for all LG phones).

The phone is always in a mode (starting with MODE_NONE). You may add extra modes or more typically your base classes will. For example com_brew adds MODE_BREW. The modes are used to switch the phone into different modes (for example brew, phonebook, modem). com_phone.Phone defines the setmode function which changes to a new mode and documents how the mode transition happens.

You need to add a config value for your phone together with the basename of the module at the start of ConfigDialog in guiwidgets.py.

You will also likely need to describe the protocol used by your phone. The protocol descriptions go in p_*.p files. Run protogen.py to compile the .p files into .py

The file packetdescription.txt describes the format and functionality of the descriptions. It is also highly recommended that you run analyser.py supplying various files in the examples directory. This will give you and idea as to how the other phones work. You can also use this to work on your description.

While running BitPim, you can turn on the protocol log view. If you press ctrl-alt-p the protocol analyser will appear. If will import whatever text you had selected, or all of it if there was no selection. You can also copy and paste the text to save for a file to put in examples.

It is a good idea to contribute some files to examples. It lets other developers see what the protocol and record formats look like on your phone. You should try to make the examples interesting and featureful. For example for a phonebook record you may want to fill out every number to the maximum number of digits. Since the files are public you should not use private data.

You also need a second class, named Profile. All the methods in this class are called from the gui thread and are to do with gui interaction between the gui and your phone. For example it munges phonebook data into a format suitable for the phone and can generate warnings. It also returns what the size and format constraints are for images.

Many of the methods take a dictionary as a parameter. Your methods are expected to return information by adding new keys and can consult other keys to get more information.

Calling convention

- mention results/data dict parameter

Phone requirements

serials source and unique id stuff

Methods in your Phone class

getfundamentals
This method should get any data off the phone that may be necessary for other methods in the Phone or Profile classes to use when processing data.

In the LGVX4400 code, this method retrieves the wallpaper and ringtone indices (needed to convert the wallpaper and ringtone names into numbers as used in the phonebook and calendar). It also gets hash of the ESN of the phone.

getphonebook
This method retrieves the phonebook. It should update the 'phonebook' key with the phonebook. Each entry in the dict should have a value in the same format as specified in the top of phonebook.py. The user interface will then deal with merging or replacing of the results.
savephonebook
This method saves the phonebook to the phone. By convention the convertphonebooktophone method in Profile will munge the phonebook into something suitable for this method and save it back into the phonebook key.

You will probably also want to update the serials for each entry (especially for new entries). You can add a key named serialupdates. It is a list of tuple. Each tuple consists of the bitpim serial for an entry (sourcetype="bitpim") and your serial update. See the updateserials() function in phonebook.py for more information.

getcalendar
savecalendar
getringtones
saveringtones
getwallpapers
savewallpapers

Methods in your Profile class

convertphonebooktophone - don't conv wallpaper and ringtone names since they
    may be updated after call to this fun

Constants in your Profile class

usbids

This is a list of tuples (vendorid, productid, interfacenumber) that correspond to the device. You should include USB to serial converters. You must have an interface number for the device to accessible via libusb. If you only work through OS device drivers then interfacenumber can be none.

The list should be in most preferred first. Typically you would list direct USB connections before USB to serial converters.

deviceclasses

A tuple containing one or both of "serial" and "modem". This is used to filter out interfaces for composite devices in the detection code. For example the LG VX4400 presents both a modem interface and a serial interface. BitPim can only talk to the serial interface as the modem interface only does modem stuff. The Sanyo phones only present a modem interface.

WALLPAPER_WIDTH WALLPAPER_HEIGHT

The normal width and height of wallpapers for use on the device. These values are used for auto resizing when the user adds a new wallpaper (eg via drag and drop). Wallpapers and images from the phone are not resized unless the user explicitly asks for it (ie you don't have to worry about camera images being resized to this size).

MAX_WALLPAPER_BASENAME_LENGTH

The maximum length of a wallpaper filename extension. Files added via BitPim will be truncated if necessary.

WALLPAPER_FILENAME_CHARS

A list of acceptable characters in wallpaper filenames. Any characters not in the list will be removed when files are added via BitPim. If there are no upper case letters then names are converted to lowercase, and if there are no lowercase letters then names are converted to uppercase.

WALLPAPER_CONVERT_FORMAT

The file extension that wallpapers are automatically converted to (without the dot). Examples are 'bmp', 'jpg' and 'png'.

Calling sequence

Remember that all methods in Phone are called in comms thread and all methods in Profile are called in gui thread. If the user has selected multiple actions (eg write phonebook and ringtones) then Phone.getfundamentals is called only once first, all Profile methods are called, and then Phone methods are called.

Reading phonebook

Writing phonebook

Monolog on adding phone support...

Each phone supported by bitpim has two source files and one protocol file. The protocol file is used to generate one of the protocol files. Say you wanted to add support for a new phone "newphone". The filenames would be

com_newphone.py
p_newphone.p
p_newphone.py (this one is generated when you run protogen.py, you do not edit it)

To make things easy for yourself you should copy one of the existing phones in bitpim. Try to choose a phone which is similar, i.e. the same manufacturer and the same basic feature set. Do a search and replace on the model name to create your new files. Remember to run protogen.py to generate the protocol source file. Make sure you change the import directive in the com_newphone to use the new p_newphone file.

To make your phone appear in the list of supported phones edit guiwidgets.py. Find the ConfigDialog class (~ln 340) and add your new phone to the list, the second field in the list is the filename of the new file you just created without the extension.

In the p_newphone.py are a bunch of PACKET defnintions, these tell bitpim how to communicate with your phone. You have to create a PACKET definition for the files and messages you are decoding. Most of the time if you are copying a similar phone these PACKET definition will not need to be changed, or if they do the change will be slight, often the size of a field will change from one model to another. The SMS PACKET definitions on the LG phones are a really good example of how the manufacturers constantly change things.

Figuring out the correct PACKET definitions is probably the hardest thing to do. There are 2 ways to get data from the phone, Sending messages over the serial port and reading/writing the phone's filesystem directly. In general using the serial port to send messages is better than directly accessing the filesystem as the serial protocols change less from one phone to another. Also writing the filesystem directly can require a phone reboot for the changes to take effect.

These packet definitions get used by get and save functions in the com_newphone.py class.

The com_newphone class contains 2 classes that your phone inherits from and overrides.

Phone -

This class is where you will write most of the code to convert from the phone's proprietary format into the standard bitpim format. The get and save functions are called by bitpim to read and write things like the phonebook, calendar and ringtones.

Profile -

This class contains static information about your phone that bitpim needs. This includes things likde the usbIDs, the size of the wallpaper files, valid characters for filenames and other infomation. It can also contain helper functions that bitpim uses to convert data from the bitpim format into a format that is more convenient for your Phone class to manipulate.

Really important info...

The get and save functions (in the Phone class). There is one pair for each feature supported by bitpim, these functions are what bitpim uses to talk to your phone:

getmemo, savememo
getsms, savesms
gettodo, savetodo
getcalendar, savecalendar
getwallpapers, savewallpapers
getringtones, saveringtones
getcallhistory, (no save function for call history)

If you are copying an existing phone then it is very likely that some or all of the code you need to make the phone work is already written and all you have to do is tweek the PACKET definitions in the p_newphone.p file. It is better to reuse existing code than duplicate it.

If you want to add support for a new feature that is not supported like say SMS or memo the following will help...

You need to add code to your phone class to allow bitpim to access the SMS (or memo etc) messages on your phone.

As mentioned before, for each type of data bitpim retrieves there is a get and a save function defined, so to add SMS support you have to implement getsms() and savesms(). You need to implement these functions in the Phone class in the com_newphone.py file.

In the Profile class you define the features supported by the phone, look for the _supportedsyncs list, you need to add SMS (or whatever new feature you are adding) to this, note that SMS write only allows the user to change the prewritten presponses at the moment.

For example, this is the _supportedsync from the lgvx4400, it supports everything except the todo feature (limitation of the phone not bitpim).

This list determines what options are greyed out in the get/send data dialog boxes in bitpim.

    _supportedsyncs=(
        ('phonebook', 'read', None),  # all phonebook reading
        ('calendar', 'read', None),   # all calendar reading
        ('wallpaper', 'read', None),  # all wallpaper reading
        ('ringtone', 'read', None),   # all ringtone reading
        ('call_history', 'read', None),# all call history list reading
        ('sms', 'read', None),         # all SMS list reading
        ('phonebook', 'write', 'OVERWRITE'),  # only overwriting phonebook
        ('calendar', 'write', 'OVERWRITE'),   # only overwriting calendar
        ('wallpaper', 'write', 'MERGE'),      # merge and overwrite wallpaper
        ('wallpaper', 'write', 'OVERWRITE'),
        ('ringtone', 'write', 'MERGE'),      # merge and overwrite ringtone
        ('ringtone', 'write', 'OVERWRITE'),
        ('sms', 'write', 'OVERWRITE'),        # all SMS list writing
        )

The contents of the getsms() function in your phone will decode the proprietary contents of files on your phone and convert them into a standard format understood by bitpim. Bitpim expects the data to be stored in records in a python dictionary data type. The easiest way to do this is to copy code from another phone. I would recommend the com_lgvx4400. Many other phones also implement this, most of the LG family uses the code in the 4400, but the other models contain other implmentations you can copy. Just search for getsms() or whatever function you are trying to add to find them.

As a rule try not to duplicate code from other phones, it is much better to add code to a base class and allow the code to be shared. This makes maintaining the code easier.


Last modified: Sat Feb 19 22:57:24 Pacific Standard Time 2005