Recent changes
FIR Filter
Homepage
MPL115A2
Compiler Error 42
From the mbed microcontroller Cookbook.  

Writing a Library

This page discusses the steps in writing and publishing an mbed Library. It covers:

What is a Library?

A library is a collection of code, usually focused on enabling a specific component, peripheral or functionality.

The main point of a library is to package something useful up so you and others don't need to keep re-inventing the wheel when you want to use some device or functionality. You can think of it as a building block for a program. Importantly, it is not a program in itself. i.e. it doesn't have a main() function, but will be a useful and reusable component in a program.

For reference, here are some existing examples:

You'll see the Servo library is a reusable component including the API documentation to make it easy to use, and the Servo Hello World pulls in this library, only having to worry about what it is going to do with the servo.

How to code a library

A good library has a clear purpose, nice clean interface, and doesn't include the code doing other things - that is what the users program is for.

Most libraries actually start as some code that turns out to be useful, is then re-factored in to a useful class or set of functions that can be reused in multiple places in a program, and then finally separated out so any program can include and use it. Lets work through an example to see how this might work...

Step 1 - Refactoring

To start with, here is some code I might have ended up with after some programming:

main.cpp

#include "mbed.h"

DigitalOut pin(LED2);

int main() {
    // do something...

    // flash 5 times
    for(int i=0; i<10; i++) {
        pin = !pin;
        wait(0.2);
    }

    // do something else

    // flash 2 times
    for(int i=0; i<4; i++) {
        pin = !pin;
        wait(0.2);
    }

    // do another thing
}

The program might do what I want, but it is obvious that some of the code is doing very similar things, perhaps as the result of copy-paste of bits I found useful. In this case, it is good practice to re-factor the code so we create a function that can do the flashing for us; define the code in one place, use it in many places.

So our code might become:

main.cpp

#include "mbed.h"

DigitalOut pin(LED2);

void flash(int n) {
    for(int i=0; i<n*2; i++) {
        pin = !pin;
        wait(0.2);
    }
}

int main() {
    // do something...

    // flash 5 times
    flash(5);

    // do something else

    // flash 2 times
    flash(2);

    // do another thing
}

So we haven't changed the functionality, but the code is now more structured. A quick look at some of the advantages:

Step 2 - Making it a Class

In the example we're using, although we have factored the flashing logic in to a function, what it is flashing is fixed (a global pin). We might decide that this is so useful, we want to create something that we can use on any output.

There are a number of ways we can do this:

  1. Create a class for the functionality that contains it's own DigitalOut object, so we can create multiple versions on different pins
  2. Make a function that we also pass what pin object to flash
  3. Create a new class inherited from DigitalOut that adds the flash functionality

I'm going to choose 1. It may not actually be the most appropriate for this example, but is by far the most common approach so we'll ignore that :)

So we are going to create a class called Flasher that when created sets up a DigitalOut pin, and provides the method to flash it:

main.cpp

#include "mbed.h"

class Flasher {
public:
    Flasher(PinName pin) : _pin(pin) {  // _pin(pin) means pass pin to the DigitalOut constructor
        _pin = 0;                                        // default the output to 0
    }

    void flash(int n) {
        for(int i=0; i<n*2; i++) {
            _pin = !_pin;
            wait(0.2);
        }
    }

private:
    DigitalOut _pin;
};

Flasher led(LED2);
Flasher out(p6);

int main() {
    led.flash(5);
    led.flash(2);
    out.flash(10);
}

In this code, we can now create a Flasher tied to a particular pin, and tell it to flash. But of course now, we can easily create different flashers on different pins too.

This is obviously quite a bit more complex, but the important thing is that the extra effort put in to turning this useful code in to a class results in the simplicity of how you can use it.

Step 3 - Separating the code into files

With the effort put in to making this code reusable, we may want to make it easier to include in to other programs. To do this, we can put the code in its own files which can simply be included by other programs.

In C, we do this by creating header files which can be included by other code so we know what is available (the declaration), and source files that contain the implementation that generates the code (the definition).

As a convention, if we had a class Flasher, we'd create the header and source files of the same name to contain it; Flasher.h and Flasher.cpp:

Flasher.h

#ifndef MBED_FLASHER_H
#define MBED_FLASHER_H

#include "mbed.h"

class Flasher {
public:
    Flasher(PinName pin);
    void flash(int n);
  
private:  
    DigitalOut _pin;
};

#endif

Flasher.cpp

#include "Flasher.h"
#include "mbed.h"

Flasher::Flasher(PinName pin) : _pin(pin) {
    _pin = 0;
}

void Flasher::flash(int n) {
    for(int i=0; i<n*2; i++) {
        _pin = !_pin;
        wait(0.2);
    }
}

Again, you'll need to know a little about C/C++ and the pre-processor to know what is going on; important things are the #define guards around the header (so if it gets included more than once, it only appears once), and the split between the .h and .cpp and the resulting syntax of how to define the methods.

So now we have that, our main.cpp file looks like:

main.cpp

#include "mbed.h"
#include "Flasher.h"

Flasher led(LED2);

int main() {
    led.flash(5);
    led.flash(2);
}

The program is now using the functionality, without getting caught up on how it is implemented. Simple!

How to publish your library

So, now you have some great code, how do you let others use it?! Well, the mbed Compiler has built in support for libraries, and lets you package up your own and publish them for anyone to use. Here is how you do it.

From the previous sections, we've now got a program that looks something like:

/media/uploads/simon/library-tutorial-01.png

Using the same convention that a class called Flasher should have a header file Flasher.h, we suggest you make your library have the same name i.e. "Flasher".

To create a library, right-click on your program, select "New Library..." and enter "Flasher"; it'll add a folder to your program, but you'll notice a little cog on it indicating it is actually a library in edit mode. You can now drag your files that will be part of the library in to it, and you'll end up with:

/media/uploads/simon/library-tutorial-02.png

Your program should still build fine, but now there is a little bit more structure.

The next step is to publish it. To do this, just right-click the library and choose "Publish Library...". You'll be asked to enter a description, some tags and any message specific to that particular version (e.g. first revision, bug fixes). Once done, hit OK and you'll get a message:

/media/uploads/simon/library-tutorial-03.png

Your library is now live! You can go to the URL and see it on the mbed.org website, and tell all your friends! You'll also see your project has been updated:

/media/uploads/simon/library-tutorial-04.png

It now just contains a reference to the published library, just like anyone else will get when they choose to import your library.

How to make updates to a library (or edit someone else's library)

So, now lets say you wanted to edit the library some more. Perhaps you wanted to add some Doxygen documentation so users of your library get nice documentation of your library so they know how to use it. We'll that's nice and easy. Just right-click the library and choose "Edit Library...". You'll be back to a editable library folder:

/media/uploads/simon/library-tutorial-02.png

Make your changes, then re-publish it as before, and your updates are pushed live! Go to the URL and you'll be able to look through the history. Anyone using your library will be able to see a newer version exists, and choose to update in a single click. Magic :)

Note that you can also edit a library that someone else wrote. Just import it, click edit library and go nuts. The only difference is when you come to publish it, it'll publish under your libraries area rather than theirs.

Documenting your library

The mbed site will also automatically generate API documentation for your library if you mark it up. See:




calendar Page history
Last modified 10 Feb 2012, by   user Dieter Brueggemann   tag library, tutorial | 18 comments  

18 comments on Writing a Library:

23 May 2010

Hi:

I hope you don't mind me going after typos and grammar. I feel it is a way I can help contribute. If you don't approve, please say so. "here is some code i might" capital I "(so if it gets included more than once, it only appears more than once)," it only appears once "So now we have that, our main.cpp " now that we or now we have our main.cpp "Now Flasher only contains " Now that Flasher "If you wanted to use " want to use "should compiles fine" should compile fine Tim

23 May 2010

I have only attempted to import one library (Igor's Driver Library), but one thing I found a little annoying was that when you import as a library, you can't see the header files in your project. So I had to create another project to import the library files separately so I could see them. Perhaps you could consider improving the online compiler so it displays the header files for a library you import - otherwise how do you know what functions/classes are exported? Also, how do you add documentation to a library, such as you have included with the mbed library?

29 May 2010

Tim - Please feel free to correct typos, grammar, or anything else. Thanks!

29 May 2010

I actually didn't notice these comments, which reminds me to add the option of email subscription to wiki pages (or entire wikis) before we go live with this wiki.

Andrew - Creating a library right now is definitely non-obvious and deficient in several ways.

Right now we are working on improving the whole process to make it a lot easier, including:

  • Auto-generation of documentation
  • You should be able to see the header files in an imported lib (part of documentation)
  • Making it lot easier to fork other people's libraries
  • Making the process of turning a program into a library a lot more obvious and straightforward

Watch this space - the above is one of our top priorities at the moment.

Thanks!

28 Sep 2010

Love how easy it is to create. Just made a new library for handling an analogue joystick:

ยป Import this library into a program

Public Member Functions

Joystick (PinName b, PinName h, PinName v)
Constructor: Joystick .
joyhv read ()
Function: read Read the joystick position, represented as a joyhv value - h and v are doubles in the range [0.0, 1.0].
double getV ()
Function: getV Read the joystick's vertical position, represented as a double value in the range [0.0, 1.0].
double getH ()
Function: getH Read the joystick's horizontal position, represented as a double value in the range [0.0, 1.0].
void rise (void(*fptr)(void))
Function: rise Attach a function to call when a rising edge occurs on the button input.
void fall (void(*fptr)(void))
Function: fall Attach a function to call when a falling edge occurs on the button input.
operator joyhv ()
Function: operator joyhv An operator shorthand for < read() >.
18 Oct 2010

I also have been trying to import a library - with no success. The library source code appears to import as a separate project or build under 'My Programs'. I just clicked the web link to import the library and I added the #include "*.h" file to my source and it did find the new library source - it sounds similar to Andrew's experience. Guess I could manually move the library source over to my project - but this seems brute-force. I realize that Dan has indicated that more changes are in process concerning libraries, but I'm wondering if anyone has any advice on what is the easiest/best approach to use today?

Dave

18 Oct 2010

Hi Dave,

We've only just implemented "libraries" fully, so most published things are classified as "programs" at the moment. In effect, they are all just collections of code which you can import either:

  • As a program (i.e. the code is imported an appears as a new program in your workspace)
  • As a library (i.e the code is imported in to a library directory of an existing program, alongside existing code within a project) So when you go to import something, you can decide to import (what is basically just a collection of code files) as a new project, or in to an existing project as a new library using the radio buttons.

Now we have distinctions of what is a program or library (i.e. the database knows whether to consider something a program or library), so that helps default based on the publishers intended us case, but it basically comes down to intent, where the collection of code is considered a program if it includes a main() function, and a library if it is a collection of useful code but not with a main() function.

We'll be working to improve it further, but it should be working. Please tell us if you are having problems...

28 Oct 2010

Shouldn't it be "i++" instead of "n++" in the examples above?

15 Nov 2010

I was a bit puzzled about the n++ as well. Great explanation though apart from that. Thanks for the good documentation.

15 Dec 2010

Is it possible to import a library into another library? On several occasions I want to reuse code (either my own one or from someone else) in one of my libraries, but cannot find a way to do this. The only way right now seems to duplicate the needed header files, and state in the documentation that the using programs also need to import other libraries. Is it possible to add such support to the compiler?

16 Dec 2010

Hi Hendrik,

Yes, it is. The procedure is:

  • Create a library as normal, in a subdirectory of a program.
  • Import a library into this directory.
  • Convert the directory to a library
  • Publish library

Example: http://mbed.org/users/dan/libraries/TestLib/ljh9as

16 Dec 2010

Thanks, that did the trick. It's a little bit non-intuitive, but works. Interestingly, I could not properly convert my library to a folder - the compiler always converted it back to a library. But you can see the result here: http://mbed.org/users/hlipka/libraries/LcdWindow/ljk1c7

17 Dec 2010

Glad that sorted things out for you. Out of interest, in which ways do you think the process might be made more intuitive?

17 Dec 2010

The first obstacle was that one needs to revert the library back to a directory to add a dependency (which, btw., is not kept when the library is added to another project - the dependent library goes to the top level directory). In the end I would like to see a recursive process - something like the Debian package management. In the Java world, Ivy and Maven do something similar. A library can specify on which other libraries it depends, so after importing it I might get a whole tree of libraries pulled to my project. I know that this opens up a whole can of worms regarding versioning, I have been here too :)

17 Dec 2010

user Hendrik Lipka wrote:

(which, btw., is not kept when the library is added to another project - the dependent library goes to the top level directory). In

That's interesting, and perhaps a bug.

user Hendrik Lipka wrote:

In the end I would like to see a recursive process - something like the Debian package management. In the Java world, Ivy and Maven do something similar. A library can specify on which other libraries it depends, so after importing it I might get a whole tree of libraries pulled to my project. I

That's kind of how it should work now. If program A depends on libraries B and C, and C depends on library D, when you import program A, it should import B, C and D.

Will look at these issues.

Thanks!

Dan

21 Mar 2011

After reading the above I am still confused as to how to create a library. When I right click "Create Library" I get a folder. However, Dragging files into it does not work. Also, if a library is new one and untested I would not want to publish. Is that necessary to be able to use it? (Using MAc OS/X Snow Leopard ans Safari) Thx. Paul

21 Mar 2011
  • you should be able to drag file into the library, as long as they are already in the cloud IDE (but this is a move, not a copy)
  • if you want to import files from your disk, use the "import" functionality
  • you only need to publish the library if you want to re-use it in another project. As long as you create the library in the project where you use it you don't need to publish it
  • you can publish a library without making it public (it won't show up in search and in your profile)
13 Nov 2011

It is now 13 November 2011. Has "Writing a Library" been updated? It seems almost all of the comments were posted in 2010. I just purchased the mbed, and 3pi expansion board, to make it a m3pi. I've gotten a few example programs to work and modified a few.

I would like to try my hand at writing a library to utilize some more of the features of the original 3pi. But, it seems not very many input blogs after March 2011.

Please login to post comments.