C/C++ coding tutorial - bitty audio prank

micro:bit code

Your micro:bit needs the right code on it for you to be able to control the sounds made by the bitty audio prank app. As with all our apps you can simply download and install a hex file which we've prepared for you or you can code it yourself, following the Bitty Software coding tutorial below. We recommend you code it yourself!


goals

Our micro:bit code needs to:

  1. Keep track of whether or not something is connected to the micro:bit over Bluetooth
  2. Keep track of whether the micro:bit is being held with the LED display facing up or facing down
  3. Detect and respond to button A or button B being pressed or both buttons A and B being pressed at the same time
  4. Send events with event ID 9005 and a distinct value of 1 - 6 over Bluetooth according to the button(s) pressed and whether the micro:bit is face up or face down

before you start

To program your micro:bit using C/C++ you need the Yotta tools and the micro:bit 'DAL' source code on a PC or Mac. If you haven't yet set this environment up, read the information on our tools page and make sure you can build and install the Hello World sample code onto your micro:bit before going any further. If you've accomplished this then you have a working C/C++ environment for micro:bit development and can move on.

You should also install the bitty audio prank application on your phone so you can use it for testing whilst you develop the micro:bit code. Check the bitty audio prank page for details of where to find the app for your type of phone or tablet.


step 1 - set up initial source code files

Download our project starter source code file to your microbit-samples\source folder. Delete any ".cpp" files you already had there. Rename the file AudioPrank.cpp so it has a name that reflects what it does.

During the course of the tutorial, you'll create a micro:bit hex file which does not require Bluetooth pairing. At the end of the tutorial, when everything is working, we'll do one final build that does need your phone or tablet to pair with your micro:bit so that nobody else can connect to your micro:bit and interfere with the fun!

Download this config.json file and save it in your microbit-samples folder. Rename it to config.json.

Your microbit-samples folder should now look like this:

And your microbit-samples source folder should look like this:

config.json includes various build properties that affects certain aspects of your micro:bit hex file once you have created it:

The property "open" which has a value of "1" means that your micro:bit will not need to be paired with your phone to be usable. This makes life easier during development but before you finish your project, remember to review this and if you decide you do want security then change the property to "0" and build again. You'll now need to pair your micro:bit with your phone.

Open AudioPrank.cpp in a text editor. It should look like this:

The lines which start with "//" are comments which are there to help you understand the code. Review them now. Don't worry if the final comment block about fibers makes no sense to you at this stage. The key point here is that when programming a micro:bit, finishing with a call to the release_fiber() function is good practice.


step 2 - change the start-up message

To get things started let's just change the start-up message which is displayed on the micro:bit to something more fitting. Change it to "AUDIO PRANK" now and save your text file.

// Display a start-up message
uBit.display.scroll("AUDIO PRANK");

step 3 - build and test

If you haven't already done so, find and launch the "Run Yotta" shortcut that should have been created for you when you installed Yotta. This will result in a window you can type commands into appearing. Use 'cd' to navigate to your microbit-samples folder.

Your micro:bit does not process C/C++ code directly. We have to translate it into a binary format which the micro:bit understands using a process called "building". Before we go any further, let's build and install your application now to make sure everything is working as expected. Follow the steps for building and installing your code and then return here and continue.

Tip: It's a good idea to progress by making small changes, building and testing at each step rather than typing huge amounts of code and then trying to build and test all in one go. It's much easier to solve problems when we're only making small changes each time.

Press the reset button on the back of your micro:bit. Your code will execute and you should see the text "AUDIO PRANK" scroll across the LED display.


step 4 - micro:bit events

We're going to make extensive use of 'events' in this application so if you don't know what that means, read all about micro:bit events now and then come back here to resume the tutorial.


step 5 - keeping track of the bluetooth connection state

bitty audio prank uses Bluetooth for communication between the micro:bit and the mobile app. Before any communication can take place, the mobile device must connect to the micro:bit. Our micro:bit code needs to keep track of whether or not something is connected by Bluetooth to it and use this information in some of the logic we need to program. Read all about keeping track of Bluetooth connections now and then come back here to resume the tutorial.

Apply what you learned about Bluetooth connection tracking to your code now. Listen for connect and disconnect events and use functions to display "C" or "D" for each of the two connection states. And use an int variable to record the current state too. In other words use *exactly* the code you just reviewed right here in your audio prank code.


step 6 - checkpoint

Let's check that what we have at this point is working. Build your code and copy the hex file it created onto your micro:bit.

On your phone or tablet, launch the bitty audio prank app. Press the Scan button. You should see your micro:bit appear, listed on the screen. Tap it and this will cause your phone to connect to it. The micro:bit should now display a letter 'C'. Press the Back button on the app and your phone will disconnect and the micro:bit show a letter 'D'.


step 7 - respond to the buttons

We want to be able to trigger one of six different sounds on a Bluetooth connected phone or tablet. The user.... that's probably you.... will choose between the six sounds by either holding the micro:bit face up with the LED display showing or face down and will press either button A, button B or both A and B together. So that's six possibilities in total. According to the button(s) pressed and the micro:bit orientation, we'll send something over Bluetooth to the phone so it knows what we did and therefore what sound to make. Simples.

So next, let's add some code that will let us respond to buttons being pressed. We'll deal with the question of which way up the micro:bit is being held after that.

Once again, we'll be using events. The micro:bit generates events whenever buttons are pressed or released. If we know the event ID and event code then we can program our micro:bit code to listen for and respond to these events.

Add the following code after the lines where you listen for Bluetooth connection events:

uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, onButton);
uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButton);
uBit.messageBus.listen(MICROBIT_ID_BUTTON_AB, MICROBIT_BUTTON_EVT_CLICK, onButton);  

We've said we're interested in 'click events' relating to buttons A, B and A+B and that in all three cases, the function onButton must be called if any one of these events occurs. Let's make a start on the onButton function.

Add the following code somewhere outside of the main() function:

void onButton(MicroBitEvent e)
{
    if (e.source == MICROBIT_ID_BUTTON_A) {
        uBit.display.scroll("BTN A");
    }

    if (e.source == MICROBIT_ID_BUTTON_B) {
        uBit.display.scroll("BTN B");
    }

    if (e.source == MICROBIT_ID_BUTTON_AB) {
        uBit.display.scroll("BTN AB");
    }
}

To begin with, we're just concerned with making sure those buttons are working for us. As you can see, at this stage, all we do is check the type of button event which has occurred and use this to show a simple message on the LED display. Once you've added this code, build, install and test by pressing button A, then button B, then pressing buttons A and B at the same time. You should see the expected messages scroll across the display.


step 8 - determine which way up the micro:bit is being held

Let's now add code which will tell us which way up the micro:bit is. We'll need to check the 'orientation' to decide what to send over Bluetooth to the connected phone.

micro:bit has the idea of 'gestures' built in. We'll write a function now which tells us, in terms of micro:bit gestures, which way up the micro:bit is. Add the following function underneath the onButton function you just added:

int getGesture() {
    int x = uBit.accelerometer.getX();
    int y = uBit.accelerometer.getY();
    return uBit.accelerometer.getGesture();
}

Gestures are derived from accelerometer data. The accelerometer is the motion detector inside your micro:bit. We read the most recent x and y values from the micro:bit accelerometer as this 'primes' the gesture system and then use one of the micro:bit's built-in functions to obtain and return the most recent gesture. Now let's make use of this in our onButton function. Replace your onButton function with the following, new version and review the code we now have:

void onButton(MicroBitEvent e)
{
    if (getGesture() == MICROBIT_ACCELEROMETER_EVT_FACE_UP || getGesture() == MICROBIT_ACCELEROMETER_EVT_NONE) {
        if (e.source == MICROBIT_ID_BUTTON_A) {
            uBit.display.scroll("BTN A UP");
        }

        if (e.source == MICROBIT_ID_BUTTON_B) {
            uBit.display.scroll("BTN B UP");
        }

        if (e.source == MICROBIT_ID_BUTTON_AB) {
            uBit.display.scroll("BTN AB UP");
        }
        
    } else {
        
        if (e.source == MICROBIT_ID_BUTTON_A) {
            uBit.display.scroll("BTN A DOWN");
        }

        if (e.source == MICROBIT_ID_BUTTON_B) {
            uBit.display.scroll("BTN B DOWN");
        }

        if (e.source == MICROBIT_ID_BUTTON_AB) {
            uBit.display.scroll("BTN AB DOWN");
        }
    }
}

There are various constants available to us for the different types of gesture which the micro:bit runtime can recognise. We check for 'face up' or 'none' and take either of these to mean that the micro:bit has the display facing upwards, otherwise we conclude it's facing down. We've adjusted the messages we display to include the orientation as well as the button(s) pressed.

Build, install and test again.


step 9 - send events over Bluetooth

Our code can now detect button presses and knows which way up the micro:bit is being held. We're nearly there! All we have left to do is to send messages over Bluetooth to tell the bitty audio prank application which sound to make and add some code to ensure we only do this if there is something connected to the micro:bit over Bluetooth.

Rather than tell the bitty audio prank application which sound to play, we'll send an event over Bluetooth and the app can use this to decide which sound to make. Events have two parts; an ID and a value. We'll define and use our own ID and values for this purpose.

All our events will use the same ID value of 9005. Add the following code underneath the line which reads '#include "MicroBit.h""'

#define MES_AUDIO_CONTROL  9005

Now change the onButton function so it creates different MicroBitEvent objects according to the button pressed and orientation of the micro:bit. We can get rid of the display messages at the same time. We only included them for interim testing purposes.

At the same time, let's ensure this code is only executed if we have a Bluetooth connection. There's no point responding to buttons unless we do, so this is where we get to use the 'connected' variable we created in the Bluetooth connection event handlers.

void onButton(MicroBitEvent e)
{
    if (connected == 0) {
        uBit.display.scroll("NC");
        return;
    }

    if (getGesture() == MICROBIT_ACCELEROMETER_EVT_FACE_UP || getGesture() == MICROBIT_ACCELEROMETER_EVT_NONE) {
        if (e.source == MICROBIT_ID_BUTTON_A) {
            MicroBitEvent evt(MES_AUDIO_CONTROL, 1);
        }

        if (e.source == MICROBIT_ID_BUTTON_B) {
            MicroBitEvent evt(MES_AUDIO_CONTROL, 2);
        }

        if (e.source == MICROBIT_ID_BUTTON_AB) {
            MicroBitEvent evt(MES_AUDIO_CONTROL, 3);
        }
        
    } else {
        
        if (e.source == MICROBIT_ID_BUTTON_A) {
            MicroBitEvent evt(MES_AUDIO_CONTROL, 4);
        }

        if (e.source == MICROBIT_ID_BUTTON_B) {
            MicroBitEvent evt(MES_AUDIO_CONTROL, 5);
        }

        if (e.source == MICROBIT_ID_BUTTON_AB) {
            MicroBitEvent evt(MES_AUDIO_CONTROL, 6);
        }        
    }
}

To send an event over Bluetooth all we have to do is create a MicroBitEvent object with the right values. Just as we can indicate events our code wants to know about, the remote application on the phone or tablet can tell the micro:bit what events it's interested in. How? By sending details over Bluetooth to the micro:bit of course! You don't need to do anything for this to work, the mobile application and micro:bit runtime code take care of this for you.

So this code, for example:

MicroBitEvent evt(MES_AUDIO_CONTROL, 5);

creates an event with ID 9005 and value 5 and it automatically gets communicated to the connected phone where the bitty audio prank application will play whatever sound has been selected to be used with this event value.


step 10 - final test

If all has gone to plan, we should now have a completed micro:bit application for use with the bitty audio prank application. Build, install and test to make sure everything is working.


step 11 - make Bluetooth pairing required

For this application it makes sense to use Bluetooth pairing. If you pair your micro:bit with your phone then nobody else will be able to connect to your micro:bit and take control of it!

Edit the config.json file in your microbit-samples folder and change it so that the 'open' property is set to 0 and the 'pairing_mode' property is set to 1, as shown here:

{
    "microbit-dal": {
        "bluetooth": {
            "enabled": 1,
            "pairing_mode": 1,
            "private_addressing": 0,
            "open": 0,
            "whitelist": 1,
            "advertising_timeout": 0,
            "tx_power": 6,
            "dfu_service": 0,
            "event_service": 1,
            "device_info_service": 1
        },
        "gatt_table_size": "0x600"
    }
}

Run 'yt clean' and then 'yt build' to rebuild your application in full and install the hex file on your micro:bit.

you've finished!

That's it! You've finished and are all set to have fun with the bitty audio prank application. You've also learned about handling buttons, about micro:bit events and about Bluetooth connection tracking. Nice work!

if you get stuck

Check the steps above carefully and see if you can spot where things have gone wrong. If necessary, start again and proceed very slowly. building and testing at each step. Take a look at the solution and compare the code with yours.

If you did not install the correct config.json file in the microbit-samples directory or put it in the wrong place (e.g. in microbit-samples/source) then the app will not work because the phone must be paired with the micro:bit before they can work together. Check the location and content of config.json. Try pairing your phone with your micro:bit. See our list of common issues for more information on this.