You are viewing an older revision! See the latest version

Writing a Library

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

What is a Library?

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

You can think of it as a building block for a program; 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 example:

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 of 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; n++) {
        pin = !pin;
        wait(0.2);
    }

    // do something else

    // flash 2 times
    for(int i=0; i<4; n++) {
        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; n++) {
        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:

  • If my flash logic had a bug or I wanted to change it, i'd only have to fix it in one place
  • My comments "flash n times" are now pretty redundant! The code speaks for itself

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; n++) {
            _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 in to 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; n++) {
        _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 more than 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 supports importing and exporting of programs to make it easy to share code. These programs can also be treated as libraries, assuming they have been prepared correctly. This basically means they don't contain a main() function (and therefore, by convention, no main.cpp).

For this example, we want to:

  • Publish a program containing only the Flasher.h and Flasher.cpp files; people can then pull this in as a library
  • Perhaps publish an example (main.cpp + Flasher lib), and write it up somewhere (Notebook or Cookbook)

Information

We will be improving the way libraries are supported in the tools, making it easier to publish and use libraries. This documents the best approach at this time, but keep an eye out for updates that will simplify the process.

To publish the library, we first need to remove the main.cpp from our Flasher program. A good way might be to make a new program FlasherExample, and just copy the main.cpp in to that.

Now Flasher only contains the Flasher.h and Flasher.cpp, we can publish in the normal way (right-click, select Publish). Flasher will now appear as a published program.

If you wanted to use that library, you can now import it as a library from the website or inside the compiler. If you choose to import it in to the "FlasherExample" program, you should now have:

  • main.cpp
  • mbed library
  • Flasher library

And it should compiles fine. Success! Now share your hard work.


All wikipages