Mono Developer Documentation

Skip all the talking and just start off with: Getting started installing the framework, and you are already half way.

What to find here?

Here on our developer site, we collect all learning resources about mono. You will find initial getting started guides, followed by tutorials on specific topics, in-depth articles and last (but not least) the API reference docs.

We prioritize to get as much text published fast, instead of keeping our cards close. We hope you like our desicion. Anyway - should you encounter anything you would like to correct - see: Contributing

Content

Getting Started

These guides will help you get started on creating your first mono app. We begin with guides that help you setup the toolchain and environment.

Lets start: Installing Mono Framework

In this guide we go through the steps of installing the Mono toolchain on your computer.

Download

First we begin with downloading the installer package, that will install the framework on your computer:

WindowsmacOSDebian/Ubuntu
Download Download Download

Download the installer package that fits your OS. Run the installer and follow the steps to install Mono’s developing tools on your system.

The installer contains all you need to install apps on mono, and to develop your own apps. The installer package contains:

  • Mono Framework code: The software library
  • GCC for embedded ARM: Compiler
  • Binutils (Windows only): The make tool
  • monoprog: Tool that uploads apps to Mono via USB
  • monomake: Tool that creates new mono application projects for you
Check installation

When the installer package has finished, you should check that have the toolchain installed. Open a terminal:

Mac & Linux

Open the Terminal application, and type this into it:

    $ monomake

If you have installed the toolchain successfully in your path, the monomake tool should respond this:

    ERR: No command argument given! You must provide a command
    Usage:
    monomake COMMAND [options]
    Commands:
      project [name]  Create a new project folder. Default name is: new_mono_project
      version         Display the current version of monomake
      path            Display the path to the Mono Environment installation dir

Congratulations, you have the tool chain running! Now, you are ready to crate your first Hello World project in the next tutorial.

Any problems?

If you do not get the excepted response, but instead something like:

-bash: monomake: command not found

It means monomake is not in your PATH. Check if you can see a mono reference in your PATH, by typing:

    $ echo $PATH

Look for references to something like /usr/local/openmono/bin. If you cannot find this, please restart the Terminal application to reload bash profile.

Windows

Open the Run command window (press Windows-key + R), type cmd and press Enter. The Command Prompt window should open. Check that the toolchain is correctly installed by typing:

    Microsoft Windows [Version 6.3.9600]
    (c) 2013 Microsoft Corporation. All rights reserved.

    C:\Users\stoffer> monomake

Like on Mac and Linux, monomake should respond with:

    ERR: No command argument given! You must provide a command
    Usage:
    monomake COMMAND [options]
    Commands:
      project [name]  Create a new project folder. Default name is: new_mono_project
      version         Display the current version of monomake
      path            Display the path to the Mono Environment installation dir

If you get this: Congratulations! You have the toolchain installed, and you can go ahead with creating your first Hello World app, in the next tutorial.

Any problems?

On the other hand, if you get:

    'monomake' is not recognized as an internal or external command,
    operable program or batch file.

It means monomake is not in the environment variable PATH. Check that you really did install the tool chain, and that your system environment variable PATH does indeed contain a path like this:

C:\Program Files\OpenMono\bin

You can see your PATH environment variable by typing:

    C:\Users\stoffer> echo %PATH%

The Hello World project

Now, let us create the obligatory Hello World project, that does not do anything else than verify your installation works.

Prerequisites

By now I expexct you have installed the Mono tool chain, as decribed in the previous tutorial. Also, it is best if you are familiar with object oriented programming. If you are not, then you might find yourself thinking “what the heck is a class and inheritance!” But read on anyways, but I will recommend to read our Object oriented guide to C++.

Create a new project

Mono comes with a tool called monomake, that does one thing - and one thing only: creating new mono projects. Let’s try it!

Open a terminal
  • Mac/Linux: Open the Terminal application
  • Window: Press Windows-key + R, and type cmd then hit Enter
Create project

In the terminal, navigate to the directory where you would like to create the project. Then:

$ monomake project hello_world

Hit Enter and monomake will create a new folder called hello_world with 3 files inside:

  • app_controller.h
  • app_controller.cpp
  • Makefile

These 3 files are required for all mono applications. I will not go into too many details here, but just tell you that app_controller.h defines the class AppController, that is the application entry point. It replaces the main() function.

Now, cd into the project folder hello_world:

    $ cd hello_world
Compile

The project already contains code that compiles, so the only thing you need to do is:

    $ make

Now the tool chain compiles the application:

    Compiling C++: app_controller.cpp
    Compiling C++: System default mono_default_main
    Linking hello_world.elf

Voila, your mono application compiled and the executable is hello_world.elf. This is the file that can be uploaded to Mono.

If you already have mono connected via USB, you can upload your new application to it by:

    $ make install

The install command will search to any connected Mono’s, reboot it and upload the application. If everything went smoothly you should see the text Hi, I’m Mono on the display.

The code

Okay, we got the code running on Mono - but what really happens in the code? In this section we sill look at the template code in AppController.

First, let just describe what the application does. It creates a text on the screen that says: “Hi, I’m Mono”. That’s it. More specific, it creates a TextLabel that gets the text content, and renders on the screen. I have includes at picture of the application below:

The Hello World application

Header file

As said, all Mono applications needs an AppController, because it is the entry point for all mono applications. Let’s take a look at the code in app_controller.h:

    #include <mono.h>           // 1

    using namespace mono;       // 2
    using namespace mono::ui;

    class AppController : public mono::IApplication {   // 3
    

        TextLabelView helloLabel;       // 4
    
    public:
    
        AppController();                // 5
    
        void monoWakeFromReset();       // 6

        void monoWillGotoSleep();       // 7

        void monoWakeFromSleep();       // 8
    
    };

I have added numbers to the interresting code lines in comments. Let’s go through each of the lines, and see what it does:

  1. We include the framework. This header file, is an umbrella that include all the classes in Mono framework. Every mono application need this include.
  2. All mono framework classes exists inside a namespace called mono. We include namespace in the context, to make the code less verbose. This allows us to write String(), instead of mono::String(). (And yes, mono has its own string class!)
  3. Here we define the AppController class itself. It inherits from the abstract interface called IApplication. This interface defines the 3 methods the AppController must have. We shall examine them shortly.
  4. Here we define the TextLabel object that will display our text on the screen. It is defined as a member of the AppController class.
  5. We overwrite the default contructor for our AppController class, to allow us to do custom initialization. You will see later why.
  6. This is a required overwrite from the IApplicationinterface. It is a method that is called when mono is reset.
  7. Also a requirement from IApplication. It defines a method that is called just before mono is put into sleep mode.
  8. As required by IApplication, this method is called when mono wake up from sleep mode.

All AppController‘s are required to implement 6,7 and 8, but you may just leave them blank.

Implementation

Now, the contents of: app_controller.cpp file:

    #include "app_controller.h"

    using namespace mono::geo;

    AppController::AppController() :
        helloLabel(Rect(0,100,176,20), "Hi, I'm Mono!")       // 1
    {
        
        helloLabel.setAlignment(TextLabelView::ALIGN_CENTER); // 2
    
        helloLabel.setTextColor(display::TurquoiseColor);     // 3
    }

    void AppController::monoWakeFromReset()
    {
        helloLabel.show();                                  // 4
    }

    void AppController::monoWillGotoSleep()
    {
    
    }

    void AppController::monoWakeFromSleep()
    {
        helloLabel.scheduleRepaint();                           // 5
    }

Again, I have numbered the most interesting code lines:

  1. This the default constructor overwrite. We overwrite the contructor to construct the TextLabel object with specific parameters. (See TextLabelView reference) We set the labels position and size on the screen (using the Rect class), and its text content.
  2. In (1) we defined the text labels width to be the entire screen (176 pixels). We want to center the text on the screen, therefore we tell the label to center align its text content.
  3. To make application look fancy, we set the text color to be an artzy turquoise color.
  4. The method monoWakeFromReset is automatically called upon reset. Inside here we tell the text label to be visible. All UI widgets are hidden by default. You must call show() to render them.
  5. monoWakeFromSleep is called when Mono wakes from sleep mode. Here we tell the label to repaint (render) itself on the screen. Sleep mode might have cleared the display memory, so we need to render the label again. scheduleRepaint will render the text, when the display signals its time to update.

That is all the code you need to draw on the screen. Notice that we left the method monoWillGotoSleep empty. We do not need any clean up code, before mono goes to sleep.

Sleep mode

But how and when will Mono go into sleep mode? Easy: By default the side-button on Mono will trigger sleep and wake. You do not have do anything! Sleep mode will turn off all peripherals and halt the CPU execution. Only a button press will wake it. Sleep mode is only way you can turn off Mono!

Further reading

Tic-tac-toe for Mono

In this tutorial I will teach you how to program Mono’s display and touch device by creating a tiny game.

Anatomy of a Mono application

Mono apps can be written inside the Arduino IDE, but if you really want be a pro, you can write Mono apps directly in C++. For that you will need to implement an AppController with at least three functions. So I will start there, with my app_controller.h header file:

#include <mono.h>

class AppController
:
    public mono::IApplication
{
public:
    AppController ();
    void monoWakeFromReset ();
    void monoWillGotoSleep ();
    void monoWakeFromSleep ();
};

My matching app_controller.cpp implementation file will start out as this:

#include "app_controller.h"

AppController::AppController ()
{
}

void AppController::monoWakeFromReset ()
{
}

void AppController::monoWakeFromSleep ()
{
}

void AppController::monoWillGotoSleep ()
{
}

Now I have a fully functional Mono application! It does not do much, but hey, there it is.

Screen and Touch

Tic Tac Toe is played on a 3-by-3 board, so let me sketch out the layout something like this:

   Tic Tac Toe
+---+ +---+ +---+
|   | |   | |   |
+---+ +---+ +---+
+---+ +---+ +---+
|   | |   | |   |
+---+ +---+ +---+
+---+ +---+ +---+
|   | |   | |   |
+---+ +---+ +---+

I will make the AppController hold the board as an array of arrays holding the tokens X and O, and also a token _ for an empty field:

class AppController
    ...
{
    ...
    enum Token { _, X, O };
    Token board[3][3];
};

For simplicity, I do not want Mono to make any moves by itself (yet); I just want two players to take turns by touching the board. So I need to show the board on the screen, and I want each field of the board to respond to touch.

This kind of input and output can in Mono be controlled by the ResponderView. It is a class that offers a lot of functionality out of the box, and in my case I only need to override two methods, repaint for generating the output and TouchBegin for receiving input:

class TouchField
:
    public mono::ui::ResponderView
{
    void TouchBegin (mono::TouchEvent &);
    void repaint ();
};

class AppController
    ...
{
    ...
    TouchField fields[3][3];
};

Above I have given AppController nine touch fields, one for each coordinate on the board. To make a TouchField able to paint itself, it needs to know how to get hold of the token it has to draw:

class TouchField
    ...
{
    ...
public:
    AppController * app;
    uint8_t boardX, boardY;
};

With the above information, I can make a TouchField draw a circle or a cross on the screen using the geometric classes Point, Rect, and the underlying functionality it inherits from ResponderView. The ResponderView is a subclass of View, and all Views have a DisplayPainter named painter that takes care of actually putting pixel on the screen:

using mono::geo::Point;
using mono::geo::Rect;

void TouchField::repaint ()
{
    // Clear background.
    painter.drawFillRect(viewRect,true);
    // Show box around touch area.
    painter.drawRect(viewRect);
    // Draw the game piece.
    switch (app->board[boardY][boardX])
    {
        case AppController::X:
        {
            painter.drawLine(Position(),Point(viewRect.X2(),viewRect.Y2()));
            painter.drawLine(Point(viewRect.X2(),viewRect.Y()),Point(viewRect.X(),viewRect.Y2()));
            break;
        }
        case AppController::O:
        {
            uint16_t radius = viewRect.Size().Width() / 2;
            painter.drawCircle(viewRect.X()+radius,viewRect.Y()+radius,radius);
            break;
        }
        default:
            // Draw nothing.
            break;
    }
}

Above, I use the View’s viewRect to figure out where to draw. The viewRect defines the View’s position and size on the screen, and its methods X(), Y(), X2(), and Y2() give me the screen coordinates of the View. The method Position() is just a shortcut to get X() and Y() as a Point.

With respect to the board, I index multidimensional arrays by row-major order to please you old-school C coders out there. So it is board[y][x], thank you very much.

Well, now that each field can draw itself, we need the AppController to setup the board and actually initialise each field when a game is started:

using mono::ui::View;

void AppController::startNewGame ()
{
    // Clear the board.
    for (uint8_t x = 0; x < 3; ++x)
        for (uint8_t y = 0; y < 3; ++y)
            board[y][x] = _;
    // Setup touch fields.
    const uint8_t width = View::DisplayWidth();
    const uint8_t height = View::DisplayHeight();
    const uint8_t fieldSize = 50;
    const uint8_t fieldSeparation = 8;
    const uint8_t screenMargin = (width-(3*fieldSize+2*fieldSeparation))/2;
    uint8_t yOffset = height-width-(fieldSeparation-screenMargin);
    for (uint8_t y = 0; y < 3; ++y)
    {
        yOffset += fieldSeparation;
        uint8_t xOffset = screenMargin;
        for (uint8_t x = 0; x < 3; ++x)
        {
            // Give each touch field enough info to paint itself.
            TouchField & field = fields[y][x];
            field.app = this;
            field.boardX = x;
            field.boardY = y;
            // Tell the view & touch system where the field is on the screen.
            field.setRect(Rect(xOffset,yOffset,fieldSize,fieldSize));
            // Next x position.
            xOffset += fieldSize + fieldSeparation;
        }
        // Next y position.
        yOffset += fieldSize;
    }
    continueGame();
}

Above I space out the fields evenly on the bottom part of the screen, using the DisplayWidth() and DisplayHeight() to get the full size of the screen, and while telling each field where it should draw itself, I also tell the field which board coordinate it represents.

Before we talk about the game control and implement the function continueGame, let us hook up each field so that it responds to touch events:

using mono::TouchEvent;

void TouchField::TouchBegin (TouchEvent & event)
{
    app->humanMoved(boardX,boardY);
}

Above the touch event is implicitly translated to a board coordinate (because each field knows its own board coordinate) and passed to the AppController that holds the board and controls the game play.

Game status display

To inform the players what is going on, I want the top of the display to show a status message. And I also want to keep track of which player is next:

class AppController
    ...
{
    ...
    mono::ui::TextLabelView topLabel;
    Token nextToMove;
};

using mono::ui::TextLabelView;

AppController::AppController ()
:
    topLabel(Rect(0,10,View::DisplayWidth(),20),"Tic Tac Toe")
{
    topLabel.setAlignment(TextLabelView::ALIGN_CENTER);
}

A TextLabelView is a View that holds a piece of text and displays this text in inside its viewRect. I can now change the label at the top of the screen depending on the state of the game after each move by using setText(), followed by a call to show() to force the TextLabelView to repaint:

void AppController::continueGame ()
{
    updateView();
    whosMove();
    if (hasWinner())
    {
        if (winner() == X) topLabel.setText("X wins!");
        else topLabel.setText("O wins!");
    }
    else if (nextToMove == _) topLabel.setText("Tie!");
    else if (nextToMove == X) topLabel.setText("X to move");
    else topLabel.setText("O to move");
    topLabel.show();
}

The updateView() function simply forces all the fields to repaint:

void AppController::updateView ()
{
    for (uint8_t y = 0; y < 3; ++y)
        for (uint8_t x = 0; x < 3; ++x)
            fields[y][x].show();
}
Game control

I now need to implement functionality that decides which player should move next and whether there is a winner. First, I can figure out who’s turn it is by counting the number of game pieces for both players, and placing the result in nextToMove. If nextToMove gets the value _, then it means that the board is full:

void AppController::whosMove ()
{
    uint8_t xPieces = 0;
    uint8_t oPieces = 0;
    for (uint8_t y = 0; y < 3; ++y)
        for (uint8_t x = 0; x < 3; ++x)
            if (board[y][x] == X) ++xPieces;
            else if (board[y][x] == O) ++oPieces;
    if (xPieces + oPieces >= 9) nextToMove = _;
    else if (xPieces <= oPieces) nextToMove = X;
    else nextToMove = O;
}

Finding out whether there is a winner is just plain grunt work, checking the board for three-in-a-row:

bool AppController::hasThreeInRow (Token token)
{
    // Check columns.
    for (uint8_t x = 0; x < 3; ++x)
        if (board[0][x] == token &&
            board[1][x] == token &&
            board[2][x] == token
        ) return true;
    // Check rows.
    for (uint8_t y = 0; y < 3; ++y)
        if (board[y][0] == token &&
            board[y][1] == token &&
            board[y][2] == token
        ) return true;
    // Check diagonal.
    if (board[0][0] == token &&
        board[1][1] == token &&
        board[2][2] == token
    ) return true;
    // Check other diagonal.
    if (board[0][2] == token &&
        board[1][1] == token &&
        board[2][0] == token
    ) return true;
    return false;
}

AppController::Token AppController::winner ()
{
    if (hasThreeInRow(X)) return X;
    if (hasThreeInRow(O)) return O;
    return _;
}

bool AppController::hasWinner ()
{
    return winner() != _;
}

Lastly, I need to figure out what to do when a player touches a field. If the game has ended, one way or the other, then I want to start a new game, no matter which field is touched; If the player touches a field that is already occupied, then I ignore the touch; Otherwise, I place the proper piece on the board:

void AppController::humanMoved (uint8_t x, uint8_t y)
{
    if (nextToMove == _ || hasWinner()) return startNewGame();
    else if (board[y][x] != _) return;
    else board[y][x] = nextToMove;
    continueGame();
}
Fallen asleep?

To wrap things up, I want Mono to start a new game whenever it comes out of a reset or sleep:

void AppController::monoWakeFromReset ()
{
    startNewGame();
}

void AppController::monoWakeFromSleep ()
{
    startNewGame();
}

Well there you have it: An astonishing, revolutionary, new game has been born! Now your job is to type it all in.

Tic-tac-toe for Mono, part II

In the first part, you saw how to get Mono to draw on the screen and how to react to touch input.

In this second part, I will show you how to use timers to turn Mono into an intelligent opponent!

Growing smart

To get Mono to play Tic Tac Toe, I will need to give it a strategy. A very simple strategy could be the following:

  1. Place a token on an empty field if it makes Mono win.
  2. Place a token on an empty field if it blocks the human opponent from winning.
  3. Place a token arbitrarily on an empty field.

Well, it is not exactly Skynet, but it will at least make Mono appear to have some brains. In code it translates to the following.

void AppController::autoMove ()
{
    timer.Stop();
    // Play to win, if possible.
    for (uint8_t x = 0; x < 3; ++x)
        for (uint8_t y = 0; y < 3; ++y)
            if (board[y][x] == _)
            {
                board[y][x] = O;
                if (hasWinner()) return continueGame();
                else board[y][x] = _;
            }
    // Play to not loose.
    for (uint8_t x = 0; x < 3; ++x)
        for (uint8_t y = 0; y < 3; ++y)
            if (board[y][x] == _)
            {
                board[y][x] = X;
                if (hasWinner())
                {
                    board[y][x] = O;
                    return continueGame();
                }
                else board[y][x] = _;
            }
    // Play where free.
    for (uint8_t x = 0; x < 3; ++x)
        for (uint8_t y = 0; y < 3; ++y)
            if (board[y][x] == _)
            {
                board[y][x] = O;
                return continueGame();
            }
    }
}

The timer is what controls when Mono should make its move; it is a Mono framework Timer that can be told to trigger repeatedly at given number of milliseconds. I will make the application fire the timer with 1.5 second intervals:

class AppController
    ...
{
    ...
private:
    mono::Timer timer;
    void autoMove ();
    void prepareNewGame ();
};

AppController::AppController ()
:
    timer(1500)
{
    ...
}

I will control the application by telling timer to call various functions when it triggers, and then stop and start the timer where appropriate. Conceptually, I can simply tell timer to call a function autoMove by

timer.setCallBack(autoMove);

but because autoMove is a C++ class member-function, I need to help out the poor old C++ compiler by giving it information about which object has the autoMove function, so the incantation will actually be

timer.setCallback<AppController>(this,&AppController::autoMove);

With that cleared up, I can place the bulk of the control in the continueGame function:

void AppController::continueGame ()
{
    updateView();
    whosMove();
    if (hasWinner())
    {
        if (winner() == X) topLabel.setText("You win!");
        else topLabel.setText("Mono wins!");
        timer.setCallback<AppController>(this,&AppController::prepareNewGame);
        timer.Start();
    }
    else if (nextToMove == _)
    {
        topLabel.setText("Tie!");
        timer.setCallback<AppController>(this,&AppController::prepareNewGame);
        timer.Start();
    }
    else if (nextToMove == X)
    {
        topLabel.setText("Your move");
        topLabel.show();
    }
    else
    {
        topLabel.setText("Thinking...");
        timer.setCallback<AppController>(this,&AppController::autoMove);
        timer.Start();
    }
}

All that is missing now is a prepareNewGame function that prompts for a new game:

void AppController::prepareNewGame ()
{
    timer.Stop();
    topLabel.setText("Play again?");
}

And that is it! Now you can let your friends try to beat Mono, and when they fail, you can tell them that you created this master mind.

Tic-tac-toe for Mono, part III

In the first part, you saw how to get Mono to draw on the screen and how to react to touch input.

In the second part, you saw how to use timers to turn Mono into an intelligent opponent.

In this third part, I will show you how to extend battery life and how to calibrate the touch system.

Getting a Good Night’s Sleep

It is important to automatically put Mono to sleep if you want to conserve your battery. The battery lasts less than a day if the screen is permanently turned on. On the other hand, if Mono only wakes up every second to make a measurement of some sort, then the battery will last a year or thereabouts. What I will do in this app, is something in between these two extremes.

In it’s simplest form, an auto-sleeper looks like this:

class AppController
    ...
{
    ...
private:
    mono::Timer sleeper;
    ...
};

AppController::AppController ()
:
    sleeper(30*1000,true),
    ...
{
    sleeper.setCallback(mono::IApplicationContext::EnterSleepMode);
    ...
}

void AppController::continueGame ()
{
    sleeper.Start();
    ...
}

The sleeper is a single-shot Timer, which means that it will only fire once. And by calling Start on sleeper every time the game proceeds in continueGame, I ensure that timer is restarted whenever something happens in the game, so that EnterSleepMode is only called after 30 seconds of inactivity.

It is Better to Fade Out than to Black Out

Abruptly putting Mono to sleep without warning, as done above, is not very considerate to the indecisive user. And there is room for everyone here in Mono world.

So how about slowly fading down the screen to warn about an imminent termination of the exiting game?

Here I only start the sleeper timer after the display has been dimmed:

class AppController
    ...
{
    ...
private:
    mono::Timer dimmer;
    void dim ();
    ...
};

using mono::display::IDisplayController;

AppController::AppController ()
:
    dimmer(30*1000,true),
    ...
{
    dimmer.setCallback<AppController>(this,&AppController::dim);
    ...
}

void AppController::dim ()
{
    dimmer.Stop();
    IDisplayController * display = IApplicationContext::Instance->DisplayController;
    for (int i = display->Brightness(); i >= 50; --i)
    {
        display->setBrightness(i);
        wait_ms(2);
    }
    sleeper.Start();
}

The dimmer timer is started whenever there is progress in the game, and when dimmer times out, the dim method turns down the brightness from the max value of 255 down to 50, one step at a time.

Oh, I almost forgot, I need to turn up the brightness again when the the dimmer resets:

void AppController::continueGame ()
{
    IApplicationContext::Instance->DisplayController->setBrightness(255);
    sleeper.Stop();
    dimmer.Start();
    ...
}

So there you have it, saving the environment and your battery at the same time!

Mono for Arduino Hackers

You can use the familiar Arduino IDE to build Mono applications. This guide will take you through the steps.

Prerequisites

First I expect you are familiar with Arduino, its coding IDE and the API’s like pinMode() etc. I also assume that you have the IDE installed, and it is version 1.6.7 or above. You do not have to follow any other of the getting started guides. Arduino IDE development for Mono is completely independed. If this is the first Mono guide you read, it is all good.

Overview

You can code Mono using 2 approaches: Native Mono or the Arduino IDE. The difference is the tools you use, and the way you structure your code. In the Arduino approach you get the familiar setup() and loop() functions, and you use the Arduino IDE editor to code, compile and upload applications to Mono.

Under the hood we still use the native Mono API’s and build system, we just encapsulate it in the Arduino IDE.

Installation

The Arduino IDE has a plugin system, where you can add support for third-party boards. We use such a plugin, that adds Mono as a target board. To install the plugin we use the Board Manager, that can install new target boards.

Note

You need Arduino IDE version 1.6 or above to utilize the Board Manager feature. You can download Arduino IDE here: arduino.cc

Add Mono as a board source

To make the Board Manager aware of Mono’s existence, you must add a source URL to the manager. You do this by opening the preferences window in Ardiono IDE. Below is a screenshot of the window:

Preferences window in Arduino IDE

In the text field called Additional Boards Manager URLs type in the URL for Mono board package:

https://github.com/getopenmono/arduino_comp/releases/download/current/package_openmono_index.json

And press OK.

Install the board package

Now, open the Board Manager by selecting the menu: Tools -> Boards -> Board Manager:

The Tools menu in Arduino IDE

The Board Manager appears, and query the source URLs for new board types. It will discover a new board type OpenMono. Select the type Contributed, in top left corner:

The OpenMono board package

Now click on the Install button to download and install all the needed tools to build mono applications. This might take a few minutes.

When the installation is done, you can close the Board Manager and return the main window. Now select Mono from the list of available target boards:

Board list with Mono as a target board

Install the USB Serial Port Driver

If you run Windows, there is an additional step. (Mac users, you can skip this section.) Windows need to detect the Mono hardware as an USB CDC device and create an ol’ fashion COM port. So download the USB device definition driver by right clicking the link and choosing Save file as:

Download Windows Serial Port Driver

Run the installer, and you are ready to use Mono.

Limitations

The standard Arduino boards are much simpler than Mono. For example: They can be turned off and they have bare pin headers. Arduino API are made to make digital and analog communication simple. You have functions like digitalWrite and analogRead. While you have these functions available, you do not have any pin headers sticking out of Mono chassis! You need the Arduino Shield Adaptor or to build your own hardware to really take advantage of the Arduino API.

Mono’s API is much more high-level, meaning that you have functions like Render text on the screen, and the software library (Mono Framework) will handle all the communication for you. Luckily you can still do this from inside the Arduino IDE.

Our additions to the default Arduino sketch

There are some key differences between Arduino and Mono, most important the power supply. You can always turn off an Arduino by pulling its power supply, but that is not true for mono. Here power is controlled by software.

By default we have added some code to the Arduino sketch template, so it will power on/off when pressing the User button. Also, we added the text Arduino to the display, such that you know your Mono is turned on.

Hello World

Let us build a Hello World application, similar to the one in the The obligatory Hello World project guide. We start out with the default Arduino project template:

    void setup() {
        // put your setup code here, to run once:
        
    }
    
    void loop() {
        // put your main code here, to run repeatedly:
        
    }

We will use the class TextLabelView to displat text on the screen. A TextLabel has a size and a position on the screen, which is defined by the class Rect that represents a rectangle.

Context issue

You might think we just create the TextLabel in the setup() function like this:

    void setup() {
        // put your setup code here, to run once:
        
        mono::ui::TextLabelView helloLbl;
    
    }

But this approach will deallocate the textlabel as soon as the setup() function returns. This means it cannot be rendered to the screen, because it have to be present in memory when screen repaints occur.

The correct approach here is to create a class (say MyClass), and let the TextLabel be a member of that class. We than create an object of the class in te global context. (Outside the setup() and loop() functions.) But all this will be out of scope with this tutorial, so we will do it the ugly way . Just know that having many global context objects, is a bad thing programmatically.

Adding the TextLabel

The complete code added to the project global context and in the setup() function:

    #include <mono.h>     // 1
    #include <app_controller.h> // 2
    
    mono::ui::TextLabelView textLbl(mono::geo::Rect(0,73,176,20),"Hi, I'm Mono"); // 3
    
    void setup() {
        // put your setup code here, to run once:
        
        //Remove the existing _Arduino_ text label
        AppController::ArduinoAppController->ard.hide();    //3
        
        textLbl.setTextColor(mono::display::WhiteColor);   // 4
        textLbl.show();   // 5
    }

I have numbered the interesting source code lines, let go through them one by one:

  1. We include the Mono Framework, to have access to Mono’s API.
  2. Include refences to the default AppController object
  3. Here we define the global TextLabel object called textLbl. Because it is global it will stick around and not be deallocated.
    • In TextLabelView‘s contructor we create a rectangle object (Rect), and give the position \((0,73)\) and dimension \((176,20)\).
    • In the constructors second parameters we set the text content on the TextLabel. This is the text that will be displayed on the screen.
  4. Get the default AppController object, and tells its ard TextLabel to be hidden.
  5. Because the screen on the Arduino template app is black, we need to tell the label to use a White text color.
  6. We tell the TextLabel to render itself on the screen. All UI widgets are hidden by default. You must call show() to render them.

Now you can press the compile button () and see the code compiles. If you have Mono connected you can upload the application by pressing the button.

Notice that we did not need to put any code inside the loop() function.

Enhancing the look and feel

To make our Hello World exactly like the The obligatory Hello World project guide, we need to add some refinements to it. We need to center the text on the screen and to color it a fancy red color. But that easy, just two calls added to the setup() function:

    textLbl.setAlignment(mono::ui::TextLabelView::ALIGN_CENTER);
    
    textLbl.setTextColor(mono::display::AlizarinColor);

Now, if you build and run the application the text will be a fancy color and centered on the screen:

Hello World Mono app

A quick note on namespaces

If find yourself wondering about what this is: mono::ui::, then read on. Everybody else - you can skip this section.

C++ uses namespaces to encapsulate class names, minimizing the risk of conflicting names. If you for example define a class called Stream, you like likely get a compiler error. This is because Arduino already have a class called Stream - the name is already taken.

To avoid this situation we defined all Mono classes inside a namespace, meaning that we exists inside a enclosed context:

    namespace mono {
        class String;
        class Stream;
        class WhatEver;
    }

You access classes inside a namespace by prepending the namespace to the class name like this: mono::String. Namespaces can be nested like this:

    namespace mono {
        namespace display {
            class Color;
        }
        
        namespace ui {
            class TextLabelView;
        }
    }
Importing into global context

You can import a namespace into the global context, to avoid prepending all mono classes with mono::, by the using keyword:

    using namespace mono;

Now, instead of accessing classe by mono::String, you just write String, the mono:: has become implcit. You can import multiple namespaces into the global context by:

    
    using namespace mono;
    using namespace mono::ui;
    using namespace mono::display;

Now you can implicit access classes from 3 different namespaces!

Note: The classes are not imported or loaded into the global context (like in Python), C++ does not work that way. It is just a short hand convenience feature, to make the code less verbose.

Further reading

Now you know how to build mono applications from the Arduino IDE. You might what dive into the native API and build system, or reading one of the in-depth articles:

Happy hacking.

Common Misconceptions & Worst Practice

To clear out, what we imagine will be common mistakes, let’s go through some senarios that you should avoid - at least!

Who should read this?

Mono API and application structure might be new to you, if you previously programmed only for Arduino or similar embedded devices. We are aware of our framework might be quite unfamiliar to bare metal developers, who expect to have full access and control, from main() to return 0.

Mono Framework is advanced and its good performance depends on you, following the best practice guide lines. Read this, and you can avoid the most basic mistakes that degrade Mono’s functionality.

No while(1)‘s

First, never ever create your own run loop! Never do this:

    void AppController::monoWakeFromReset()
    {
        // do one time setups ...
        
        // now lets do repetitive tasks, that I want to control myself
        while(1)
        {
            //check status of button
            
            // check something else
            
            // maybe update the screen
            
            // increment some counter
        }
        // we will never return here
    }

Try to do this, and you will find Mono completely unresponsive. The USB port will not work, the programmer (monoprog) will not work, along with a whole bunch of other stuff.

Like other applications in modern platforms, Mono applications uses an internal run loop. If you create your own, the internal run loop will not progress. All features that depend on the run loop will not work. Timers will not run, display system will not work, and worst monoprog cannot reset mono, to upload a new app.

If you want to do repetitive tasks, that should run always (like while(1)), you should instead utilize the run loop. You can inject jobs into the run loop by implementing an interface called IRunLoopTask. This will allow you to define a method that gets called on each run loop iteration. That’s how you do it. We shall not go into more details here, but just refer to the tutorial Using the Run Loop

No busy waits

Many API’s (including Mono’s), allows you to do busy waits like this:

    // do something
    wait_ms(500); // wait here for 0.5 secs
    
    // do something else

It is really covenient to make code like this, but it is bad for performance! For half a second you just halt the CPU - it does nothing. The application run loop is halted, so all background tasks must wait as well. The CPU runs at 66 Mhz, imagine all code it could have executed in that half second!

Instead of halting the CPU like this, you should use callbacks to allow the CPU to do other stuff, while you wait:

    // do someting
    mono::Timer::callOnce<MyClass>(500, this, &MyClass::doSomethingElse); // do something else in 0.5 secs

By using the Timer class, and encapsulating the “do something else” functionality in a method - you free the CPU to do useful stuff while you wait. To learn more about callbacks see the tutorial: Callbacks in C++.

Extensive use of new or malloc

The C++ new operator uses the stdlib function malloc to allocate memory on the heap. And it is very easy and convenient to use the heap:

    // object allocation on the heap - because Qt and Obj-C Cocoa uses this scheme!
    mono::geo::Rect *bounds = new mono::geo::Rect(0,0,100,20);
    mono::ui::TextLabelView *txtLbl = new mono::ui:TextLabelview(*bounds, "I'm on the heap!");
    
    //pass the pointer around
    return txtLbl;

What happened to the bounds pointer, that had a reference to a Rect object? Nothing happened, the object is still on the heap and we just lost the reference to it. Our application is leaking memory. And that is one issue with using the heap. We do not have a Garbage Collector , so you must be careful to always free your objects on the heap.

And it gets worse, the heap on Mono PSoC5 MCU is not big - it is just 16 Kb. You might run out of heap quicker than you expect. At that point malloc will start providing you with NULL pointers.

Use heap for Asynchronous tasks

There are some cases where you must use the heap, for example this will not work:

    void getTemp()
    {
        // say we got this variable from the temperature sensor
        int celcius = 22;
    
        char tempStr[100]; // make a local buffer variable to hold our text
    
        // format a string of max 100 chars, that shows the temperature
        snprintf(tempStr, 100, "the temperature is: %i C",celcius);
    
        renderOnDisplayAsync(tempStr);
    }

Here we have an integer and want to present its value nicely wrapped in a string. It is a pretty common thing to do in applications. The issue here is that display rendering is asynchronous. The call to renderOnDisplayAsync will just put our request in a queue, and then return. This means our buffer is removed (deallocated) as soon as the getTemp() returns, because it is on the stack.

Then, when its time to render the display there is no longer a tempStr around. We could make the string buffer object global, but that will take up memory - especially when we do not need the string.

In this case you should the heap! And luckily we made a String class that does this for you. It store its content on the heap, and keeps track of references to the content. As soon as you discard the last reference to the content, it is automatically freed - no leaks!

The code from above becomes:

    
    int celcius = 22; // from the temp. sensor
    
    // lets use mono's string class to keep track of our text
    mono:String tempStr = mono::String::Format("the temperature is: %i C",celcius);
    
    renderOnDisplayAsync(tempStr);

That’s it. Always use Mono’s String class when handling text strings. It is lightweight, uses data de-duplication and do not leak.

(The method renderOnDisplayAsync is not a Mono Framework method, it is just for demonstration.)

Avoid using the Global Context

If you write code that defines variables in the global context, you might encounter strange behaviours. Avoid code like this:

    // I really need this timer in reach of all my code
    mono::Timer importantTimer;
    
    // some object I need available from everywhere
    SomeClass myGlobalObject;
    
    class AppController : public mono::IApplication
    {
        // ...
    };

If you use Mono classes inside SomeClass or reference myGlobalTimer from it, when you will likely run into problems! The reason is Mono’s initialization scheme. A Mono application’s start procedure is quite advanced, because many things must be setup and ready. Some hardware components depend on other components, and so on.

When you define global variables (that are classes) they are put into C++’s global initializer lists. This means they are defined before monoWakeFromReset() is executed. You can not expect periphrals to work before monoWakeFromReset has been called. When it is called, the system and all its features is ready. If you interact with Mono classes in code you execute before, it is not guaranteed to work properly.

If you would like to know more about the startup procedures of mono applications and how application code actually loads on the CPU, see the Boot and Startup procedures in-depth article.

Direct H/W Interrupts

If you are an exerienced embedded developer, you know interrupts and what the requirements to their ISR’s are. If you are thinking more like: “What is ISR’s?” Or, “ISR’s they relate to IRQ’s right?” - then read on because you might make mistakes when using interrupts.

First, let’s see some code that only noobs would write:

    // H/W calls this function on pin state change, for example
    void interruptServiceRoutine()
    {
        flag = true;
        counter += 1;
        
        //debounce?
        wait_ms(200);
    }

With the wait_ms() call, this interrupt handler (or ISR) will always take 200 ms to complete. Which is bad. A rule of thumb is that ISR’s should be fast. You should avoid doing any real work inside them, least of all do busy waits.

Mono Framework is build on top of mbed, that provides classes for H/W Timer interrupts and input triggered interrupts. But because you should never do real work inside interrupt handlers, you normally just set a flag and then check that flag every run loop iteration.

We have includes classes that does all this for you. We call them Queued Interrupts, and we have an in-depth article about the topic: Queued callbacks and interrupts. There are the QueuedInterrupt class, that trigger a queued (run loop based) interrupt handler when an input pin changes state. And the Timer class, that provides a queued version of hardware timer interrupts.

Caution

We strongly encourage you to use the queued versions of timers and interrupts, since you avoid all the issues related to real H/W interrupts like: reentrancy, race-conditions, volatile variable, dead-locks and more.

Monokiosk

Using Monokiosk

If you want to install an existing app from Monokiosk, on to your Mono device - this guide is for you!

In this guide we will show you how to download and install a pre-built application on Mono. Monokiosk is the app store where you can browse and download mono applications, built by makers from around the world.

Note

We plan to add more applications to the kiosk ourselves, and hope that our community will submit their own creations to the site.

Visit monokiosk.com

First order of business, direct your favorite browser to monokiosk.com, and you will see this page like this:

Mono Kiosk landing page

Currently there are a simple Clock app and and a Tic Tac Toe app. But before you franticly click on one of these crazy mind blowing apps, you first need to install our MonoMake tool to install the application onto Mono.

MonoMake is an application that programs the application on Mono. Such a programmer transfers application files to mono, using the USB port. You need this tool to get the application from your computer to your Mono device. When you install applications from Monokiosk, the overall procedure is:

  1. Connect Mono to your computer using an USB cable
  2. Make sure Mono is on
  3. Click the Install button in MonoKiosk, for the app you wish to install.

However, first you must download MonoMake itself, so click on the button that suits your system:

WindowsmacOSDebian/Ubuntu
Download Download Download

Choose the option that fits you or your OS. The downloads are installers that will install monoprog on your system.

Note

This software you have installed is the complete toolset for developing OpenMono applications. However, you dont need to use that. Here, we are just using the tool MonoMake.

Install Tic Tac Toe

After you have download and installed the OpenMono SDK on your system, let’s continue.

Go to the frontpage and click on the Tic Tac Toe app. You will now see this page, where you will see the install button at the bottom right:

Tic Tac Toe app details page

When you click the link, the install button, the MonoMake application will launch. MonoMake will automatically download the chosen application binary and install it on to Mono.

Now the application’s binary code is loaded to Mono’s internal flash memory. If everything goes well Mono will wake up and display the Tic Tac Toe app. Next, you can find a friend to play Tic Tac Toe with, you can install the other app or you could consider creating your own!

Manual installs

If, for some reason MonoMake does not launch when you click the install button - there are other options. Scroll down and click the Download button instead. This downloads the application binary file (.elf) to your computer. When the file is downloaded, launch MonoMake yourself.

MonoMake

Make sure that Monomake can see your connected (and running) Mono device. This is indicated at the lower right corner. Now, click the blue Install button left of the center. A standard Open file dialog box will open. Navigate to the just downloaded application .elf file, and open it.

MonoMake installs the application onto Mono.

Tutorials

Essentials

Resetting Mono

Like most Wifi routers and alike, Mono has a reset switch hidden inside a cavity.

If you have gotten stuck and need to force reboot Mono, this guide will help you in resetting Mono. If you have made a coding mistake that might have caused Mono to freeze - then we shall later look at how force Mono into bootloader mode.

Hardware Reset

If you just need to trigger a hardware reset, follow these steps:

Reset Mono

  1. Find a small tool like a small pen, steel wire or paper clip
  2. Insert the tool into the reset cavity, as displayed in the picture above. Be aware not to insert it into the buzzer opening.
  3. Push down gently to the toggle the reset switch, and lift up the tool.

Mono will reset. It will load the bootloader that waits for 1 sec, before loading the application programmed in memory.

Force load Bootloader

If you need to install an app from Monokiosk or likewise, it might be nice to force Mono to stay in bootloader - and not load the programmed application. You can do this by pressing the User button, when releasing the reset switch. Then Mono will stay in Bootloader and not load any application. You will be able to upload a new app to it with monoprog.

To force Mono to stay in bootloader:

  1. Press and hold the User button
  2. Gently press and release the reset switch
  3. Release the User button

The stay in bootloader mode is only triggered by the pressed User button, then awaking from reset. There are no timeouts. To exit from bootloader, you must do an ordinary hardware reset.

Caution

Do not leave Mono in bootloader mode, since this will drain the battery. If you are in doubt, just do an extra normal reset.

Monoprog can detect the Bootloader

If you have connected Mono to your computer, you can use the Monoprog-tool to detect if Mono is in bootloader. Open a console / terminal and type:

$ monoprog -d

Monoprog will tell you if it could detect Mono. If it can, it is in bootloader!

Software Resets

You can programmaticly trigger a reset from code! What happens is the CPU will reset itself if you explicitly tell it to do so. (That it, writing to a specific register.) In Mono Framework there are 3 functions you can use to trigger a reset:

  • Ordinary Reset, where bootloader runs for 1 sec.
  • Reset To Application, where bootloader is skipped.
  • Reset To Bootloader, where Mono stays in bootloader.

The 3 functions are static (or class methods) on IApplicationContext, and can be used like this:

// Ordinary Reset
mono::IApplicationContext::SoftwareReset();

// Reset to Application
mono::IApplicationContext::SoftwareResetToApplication();

// Reset to Bootloader
mono::IApplicationContext::SoftwareResetToBootloader();

Note that these functions will never return, since they cause the CPU to reset. So any code beneath the reset functions, will get be reached, just take up memory!

Using Mono’s Serial port

Let us examine how to use Mono’s built in USB Serial port, and how to monitor it from your computer

By default when you plug in Mono’s USB cable to a computer, Mono will appear as a USB CDC device. If you run Windows you have to install a driver, please goto this section to see how.

Get a Serial Terminal

First you need a serial terminal on your computer. Back in the old Windows XP days there was Hyper Terminal, but I guess it got retired at some point. So both Mac/Linux and Windows folks need to go fetch a serial terminal application from the internet.

Windows Serial apps:

Mac / Linux Serial apps

We are very happy with minicom, since it has a feature that makes it really great with Mono. More about that later! Unfortunately minicom does not run on Windows, so we are considering making our own serial terminal client for Windows - that is similar to minicom.

If you use Linux / Mac, you should properly install minicom now. But you do not have to, you can also use any of the other choices.

Installing minicom

To install minicom on a Debian based Linux you should just use aptitude or apt-get:

$ sudo aptitude install minicom

On Mac you need the package manager called Homebrew. If you don’t have it, go get it from their homepage. When you are ready type:

$ brew install minicom
Sending data from Mono

Transferring text or binary data from Mono is really easy. In fact we have standard I/O from the standard C library available! To write some text to the serial port just do:

printf("Hello Serial port!!\t\n");

Notice that we ended the line with \t\n and not only \n. That is because the serial terminal standard is quite old, therfore many serial terminals expects both a carriage return and a line feed character.

To capture output from Mono in a terminal, we need to continuesly output text. Therefore we need to call the print function periodicly.

In app_controller.h:

class AppController : mono::IApplication
{
public:
    
    //Add a timer object to our appController
    mono::Timer timer;
    
    // just a counter variable - for fun
    int counter;
    
    // class contructor
    AppController();
    
    // add this method to print to the serial port
    void outputSomething();
    
    
    // ...

Then in app_controller.cpp:

AppController::AppController()
{
    // in the contructor we setup the timer to fire periodicly (every half second)
    timer.setInterval(500);
    
    // we tell it which function to call when it fires
    timer.setCallback<AppController>(this, &AppController::outputSomething);
    
    // set the counter to zero
    counter = 0;
    
    //start the timer
    timer.Start();
}

void AppController::outputSomething()
{
    printf("I can count to: %i",counter++);
}

Compile and upload the app to Mono.

Note

We are following best practice here. We could also have created a loop and a wait_ms() and printf() statement inside. But that would have broken serial port I/O!

Connecting to Mono

When Mono is plugged in to the USB port, you should see a serial device on your computer. In Windows a COM port should be present in Device manager. On Linux / Mac there should exist a I/O device in the folder /dev. On Mac it would be named something like /dev/cu.usbmodem1246. On Linux the name could be /dev/ttyACM0.

If you use minicom you connect to the serial port with the -D flag, like this:

$ minicom -D /dev/cu.usbmodem1246

With PuTTY on Windows you should check the COM port number in Device Manager and type the this number in the Serial line text box:

How to connect to COM1 in PuTTY

Now you should be connected to the Mono serial output:

I can count to: 3
I can count to: 4
I can count to: 5
I can count to: 6

Because Mono does not wait for you to open the serial port, you might loose some output. That is why you properly will not see I can count to 0 and I can count to 1. At some point we might change this behaviour and add a larger output buffer on Mono.

Note

You can also read from the serial port using the standard getc stdio function. Avoid using scanf since this will block until the formatted input has been read from the serial port.

Reconnects and Resets

You will soon discover that every time Mono resets, when uploading new apps or likewise, the serial port disappears. If you are not using minicom, you will have to manually connect to the port again. That is why we prefer to use minicom, because it automatically connects again when the port re-appears.

If you are not using minicom you will get pretty tired of reconnecting over and over again. At some point you might even consider helping us out with a .NET based serial tool to resolve the issue :-)

Why does the serial port disappear?

Unlike Arduino, Mono does not have a dedicated serial port to USB chip. We use the CPU’s built-in USB component to create the serial port. This means that when the CPU is reset, the USB port is reset. That efficiently ends the serial connection. There is no way around this issue, expect using a dedicated USB chip.

Reset over the USB

Like Arduino we also use the Serial connection to trigger resets. Before a new application can be uploaded to Mono, we have to put it into bootloader. This is done by a reset, just like Arduino does. We use the serial port’s DTR line to trigger a reset. Mono continuously monitors the DTR line, ready to trigger a software reset on itself.

If you do not follow the coding best practice convention and do something ugly, like this:

while(1)
{
    // I just wanna stay here for the rest of time ...
}

You have effectively cut off the possibility of resetting using the DTR, to trigger a software reset.

Serial Port Windows Driver

Windows do not support mapping USB CDC devices to Serial ports (COM devices) out of the box. It needs an .inf file to tell it to do so. You can download an installer for this INF file here, but it should have been installed automatically. The driver is included in both the Monokiosk based installer and the SDK toolchain.

Sleep Mode

In this tutorial we will quickly demonstrate how to put Mono into sleep mode.

Mono has no physical on/off switch, so you cannot cut the power from the system. This means you must always provide a way for Mono to goto to sleep. Sleep mode is the closest we come to being powered off. Mono’s power consumption in sleep mode is around 50 µA (micro amperes), which is really close to no consumption at all.

Default behaviour

Because it is crusial to be able to turn off Mono (goto sleep mode), we provide this functionality by default. When you create a new project with:

$ monomake project MyNewProject

The SDK predefines the behaviour of the User button, to toggle sleep mode. This is important because controlling on/off functionality, is not what is first on your mind when developing new mono apps. So you dont’t have to consider it too much, unless to wish to use the User button for something else.

Sleep and USB

In our v1.1 release of our SDK, we enabled sleep mode while connected to the USB. This means that triggering sleep will power-down Mono’s USB port. Therefore our computer will loose connection to Mono if it goes to sleep.

When you wake up Mono, it will be enumerated once again.

Sleep and external power

Mono has the ability to provide power for components mounted either on the Mono Shield Adaptor or attached through the 3.5mm jack connector. By default Mono provides 3.3V on this external power rail (called VAUX). To safe battery life, the VAUX power if turned off in sleep mode. This is the default behaviour, but you can change it if you need to.

In the 3.5mm jack connector the power on J_TIP in sleep mode depends on the USB state. If USB is connected the voltage on J_TIP is 1.7V, because of leakage currents from VBUS. With no USB attached, the J_TIP voltage is 0.0V in sleep mode.

Warning

We have introducted this behaviour in Release 1.4. Before this version the VAUX line was not limited to 3.3V! Especially in sleep mode, the voltage rises to the battery’s current voltage level. In Release 1.4 we fixed this issue, by turning off auxillary power in sleep mode.

You can consult the schematics to see how the power system is configured.

Triggering sleep mode

Say we have an application that utilizes the User button to do something else, than toggling sleep mode. Now we need another way of going to sleep, so lets create a button on the touch screen to toggle sleep. First in our app_controller.h we add the ButtonView object to the class:

class AppController : public mono::IApplication {

    // we add our button view here
    mono::ui::ButtonView sleepBtn;

    // ... rest of appcontroller.h ...

In the implementation file (app_controller.cpp) we initialize the button, setting its position and dimensions on the screen. We also define the text label on the button:

AppController::AppController() :
    
    //first we call the button constructor with a Rect object and a string
    sleepBtn(Rect(10,175,150,40), "Enter Sleep"),

    // here comes the project template code...
    // Call the TextLabel's constructor, with a Rect and a static text
    helloLabel(Rect(0,100,176,20), "Hi, I'm Mono!")
{

Now, we need to tie a function to the button’s click handler. That means when the button is clicked, it automatically triggers a function to be called. We can call the standard static function for going to sleep, that is defined in the global IApplicationContext object. The function is:

mono::IApplicationContext::EnterSleepMode();

Normally, we could just add this function directly to the button’s callback handler, but in this particular case it is not possible! The callback handler always expects a member function, not a static class function like EnterSleepMode. So we need to define a member function on our AppController and wrap the call inside that.

Inside app_controller.h add:

public:

    // The default constructor
    AppController();
    
    // we add our sleep method here:
    void gotoSleep();

    // Called automaticlly by Mono on device reset
    void monoWakeFromReset();

Then in the implementation file (app_controller.cpp), we define the body of the function to:

void AppController::gotoSleep()
{
    mono::IApplicationContext::EnterSleepMode();
}

Lastly, we tell the sleepBtn object to call our function, when it gets clicked - we do this from AppController‘s constructor:

// set another text color
helloLabel.setTextColor(display::TurquoiseColor);

// tell the button to call our gotoSleep function
sleepBtn.setClickCallback<AppController>(this, &AppController::gotoSleep);

// tell the button to show itself on the screen
sleepBtn.show();

Okay, go compile and install the app on Mono - and you should see this on the screen:

Example of the sleep button app

Try to press the button and you will see Mono goto sleep and turning off the display. In this example you wake Mono again just by pressing the User button.

Danger

Be aware that if you overwrite the User Button functionality, you are responsible for ensuring that Mono has a wake up source. A wake source is always a physical input pin interrupt. In most cases you should use the User button.

In another tutorial we shall see how you overwrite the User button functionality.

Complete sample code

For reference, here is the complete sample code of the tutorial:

app_controller.h:

#ifndef app_controller_h
#define app_controller_h

// Include the Mono Framework
#include <mono.h>

// Import the mono and mono::ui namespaces into the context
// to avoid writing long type names, like mono::ui::TextLabel
using namespace mono;
using namespace mono::ui;

// The App main controller object.
// This template app will show a "hello" text in the screen
class AppController : public mono::IApplication {
    
    // we add our button view here
    mono::ui::ButtonView sleepBtn;
    
    // This is the text label object that will displayed
    TextLabelView helloLabel;
    
public:

    // The default constructor
    AppController();

    // we add our sleep method here:
    void gotoSleep(); 

    // Called automaticlly by Mono on device reset
    void monoWakeFromReset();

    // Called automatically by Mono just before it enters sleep mode
    void monoWillGotoSleep();

    // Called automatically by Mono right after after it wakes from sleep
    void monoWakeFromSleep();
    
};

#endif /* app_controller_h */

app_controller.cpp:

#include "app_controller.h"

using namespace mono::geo;

// Contructor
// initializes the label object with position and text content
// You should init data here, since I/O is not setup yet.
AppController::AppController() :
    
    //first we call the button constructor with a Rect object and a string
    sleepBtn(Rect(10,175,150,40), "Enter Sleep"),
    
    // Call the TextLabel's constructor, with a Rect and a static text
    helloLabel(Rect(0,100,176,20), "Hi, I'm Mono!")
{

    // the label is the full width of screen, set it to be center aligned
    helloLabel.setAlignment(TextLabelView::ALIGN_CENTER);
    
    // set another text color
    helloLabel.setTextColor(display::TurquoiseColor);
    
    // tell the button to call our gotoSleep function
    sleepBtn.setClickCallback<AppController>(this, &AppController::gotoSleep);

    // tell the button to show itself on the screen
    sleepBtn.show();
}

void AppController::gotoSleep()
{
    mono::IApplicationContext::EnterSleepMode();
}

void AppController::monoWakeFromReset()
{
    // At this point after reset we can safely expect all peripherals and
    // I/O to be setup & ready.

    // tell the label to show itself on the screen
    helloLabel.show();
}

void AppController::monoWillGotoSleep()
{
    // Do any clean up here, before system goes to sleep and power
    // off peripherals.

}

void AppController::monoWakeFromSleep()
{
    // Due to a software bug in the wake-up routines, we need to reset here!
    // If not, Mono will go into an infinite loop!
    mono::IApplicationContext::SoftwareResetToApplication();
    // We never reach this point in the code, CPU has reset!

    // (Normally) after sleep, the screen memory has been cleared - tell the label to
    // draw itself again
    helloLabel.scheduleRepaint();
}

Coding

Using Wifi

Let us walk through the steps required to connect Mono to a Wifi access point, and download the content of a web page

Note

The network abstraction layer in Mono Framework is not implemented at this point. We will use the hardware layers directly, so this tutorial will be simpler in the future.

The Goal

We shall create a small mono application that connects to a Wifi access point and downloads a website. To achieve this, we need to accomplish the following steps:

  1. Initialize the SPI communication to te Wifi module
  2. Initialize the Wifi module
  3. Connect to an access point, using either hardcoded credentials or read the credentials from SD card.
  4. Using DHCP to get an IP address from the access point
  5. Create a HTTP Get request to a URL and display the response
Setting up the project

First order of business is to create a new mono application project. I assume you already have installed the developer tool chain.

Open a terminal (or command prompt) and fire up this command:

$ monomake project wifi_tutorial

monomake will now create an application project template for us. Open the two source files (app_controller.h and app_controller.cpp) in your favorite code editor. In the header file (.h) we need to add 2 includes, to import the wireless module definitions:

    #include <mono.h>
    #include <wireless/module_communication.h>
    #include <wireless/redpine_module.h>

    using namespace mono;
    using namespace mono::ui;

Also, in the header file we need to add member variables for the module to the AppController class definition. Two for the SPI communication and one the HTTP client class.

Note

The class HttpClient is a quick’n’dirty implementation, and is likely to be phased out to future releases of Mono Framework.

Therefore we extend the class members with:

    class AppController : public mono::IApplication {
    
        // This is the text label object that will displayed
        TextLabelView helloLabel;
        
        // The hardware SPI port
        mbed::SPI spi;
        // The spi based communication interface for the module
        redpine::ModuleSPICommunication spiComm;
        
        // The http client object variable
        network::HttpClient client; 
        
        // a console view to display html data
        mono::ui::ConsoleView<176, 110> console;
    
    public:
    
        AppController();
        
        // ...
    }
    

Now, we have imported the objects we are going to need, the next step is to initialize them properly.

Initializing the Communication channel

The wifi module is connected to Mono’s MCU by a dedicated SPI. In the initial release of Mono Framework there is no abstraction layer for the Wifi module, so we have to initialize this SPI explicitly.

First we need to add the raw mbed SPI object to the AppController‘s constructor list. Therefore we add two new lines next to the existing initialization of helloLabel object:

    
    // You should init data here, since I/O is not setup yet.
    AppController::AppController() :
        helloLabel(Rect(0,150,176,20), "Hi, I'm Mono!"),
        spi(RP_SPI_MOSI, RP_SPI_MISO, RP_SPI_CLK),
        spiComm(spi, NC, RP_nRESET, RP_INTERRUPT)
    {
    // ...
    

So what is happening here? We are setting up two objects: the basic SPI port and a SPI based communication channel to the module (spiComm). The module uses a few additional hardware signals, like the reset and interrupt signals. Now we have initialized the communication to the module, so we are ready to send commands to it!

The first thing we wanna do is tell the module to boot up and begin listening for commands. But we can not do that from the constructor, because the module might not be powered yet. We need to initialize it from the monoWakeFromReset() method:

    void AppController::monoWakeFromReset()
    {
        //initialize the wifi module
        redpine::Module::initialize(&spiComm);
        
        //show the console view
        console.show();

Now the module will boot, so next we will tell it to connect to an access point.

Connecting to an Access Point

Let us begin with a hardcoded SSID and passphrase. (Still from inside the monoWakeFromReset() method.) Add this code line:

    redpine::Module::setupWifiOnly("MY_SSID", "MY_PASSPHRASE");
    
    // print something in the console
    console.WriteLine("Connecting...");

Now the module will try to connect to the given access point, and expect to get a DHCP configured IP address. The setupWifiOnly function has a third parameter that defines the security setting. The default value is WPA/WPA2 Personal. Other supported options are: No security, WEP and Enterprise WPA/WPA2.

Caution

Almost all calls to the Wifi module are asynchronous. This means they add commands to a queue. The function call returns immediately and the commands will be processed by the applications run loop. So when the method returns, the network is not connected and ready yet.

Because the connecting process is running in the background, we would like to be notified when the network is actually ready. Therefore, we need to setup a callback method. To do that we add a new method to our AppController class. We add the method definition in the header file:

    class AppController : mono::IApplication
    {
    // ...
    
    public:
    
        void networkReadyHandler();
    
    // ...

Next, we add the method body in the implementation file:

    void AppController::networkReadyHandler()
    {
        helloLabel.setText("Network Ready");
    }

Notice that we use the existing helloLabel to display the network state on the screen.

Now, we need to tell the module to call our method, when the network is connected. We append this line to monoWakeFromReset():

    redpine::Module::setNetworkReadyCallback<AppController>(this, &AppController::networkReadyHandler);

This sets up the callback function, such that the module will call the networkReadyHandler() method, on our AppController instance.

Tip

Callback functions are an important part of using the network on Mono. If you wish to familiarize yourself with the concept, please see the in-depth article: Queued callbacks and interrupts

If you feel for it, tryout the code we have written so far. If you monitor the serial port, you should see the Wifi module emitting debug information. Hopefully you should see the Network Ready text in screen after ~20 secs. If not, consult the serial terminal for any clue to what went wrong.

Download a website

Now that we have connected to an access point with DHCP, I take the freedom to assume that Mono now has internet access! So lets go ahead and download: this webpage!

To download a website means doing a HTTP GET request from a HTTP client, and here our HttpClient class member from earlier, comes into action.

Like the process of connecting to an access point was asynchrounous, (happening in the background), the process of downloading websites is asynchrounous. That means we are going to need another callback function, so lets define another method on AppController.h:

    
    // ...
    
    public:
    
        void networkReadyHandler();
        
        void httpHandleData(const network::HttpClient::HttpResponseData &data);
        
    // ...

Notice the ampersand (&) symbol that define the data parameter as a reference. In the implementation file we add the function body:

    void AppController::httpHandleData(const network::HttpClient::HttpResponseData &data)
    {
        helloLabel.setText("loading");
        console.WriteLine(data.bodyChunk);
        
        if (data.Finished)
        {
            helloLabel.setText("Downloaded");
        }
    }

HttpClient will return the HTML content in multiple calls, and you use the Finished member to see when all data has arrived. Here we just set the label content to the HTML chunk, so it is not so pretty to look at. When the response has been downloaded, we set the text label to display Downloaded.

Now, we are ready to setup the http client and fetch the webpage. We can use HttpClient only after the network is ready. So in the implementation file, add this to networkReadyHandler():

    void AppController::networkReadyHandler()
    {
        helloLabel.setText("Network Ready");
        
        //fetch a webpage
        client = mono::network::HttpClient("http://developer.openmono.com/en/latest/");
        
        //now the client will be fetching the web page
        // let setup the data callback
        client.setDataReadyCallback<AppController>(this, &AppController::httpHandleData);
    }
Using file I/O

In this tutorial we will see how to read and write files on an SD card.

Mono has a Micro SD Card slot and currently supports communicating with an SD card using an SPI interface. We have included both SD card I/O and FAT32 file system I/O in our framework. As soon as you have setup the SD card I/O you can use the familiar stdio.h file I/O.

Get an SD Card

First order of business is for you to obtain a MicroSD Card and format in good ol’ FAT32. Then insert the card into Mono’s slot and fire up a new project:

$ monomake project fileIO --bare
Creating new bare mono project: fileIO...
 * fileIO/app_controller.h
 * fileIO/app_controller.cpp
Writing Makefile: fileIO/Makefile...
Atom Project Settings: Writing Auto complete includes...

Note

Notice that we use the switch --bare when we created the project. This option strips all comments from the template code. This way you have a less verbose starting point.

Now cd into the fileIO directory and open the code files in your favourite code editor.

Initalizing the SD Card

At this time we have yet to create a real abstraction layer for the file system initialization. Until we do, you need to initialize the SD card communication yourself. Therefore open app_controller.h and add these lines:

    #include <mono.h>
    // import the SD and FS definitions
    #include <SDFileSystem.h>
    #include <stdio.h>

    class AppController : public mono::IApplication {
    public:

        SDFileSystem fs; // create an instance of the FS I/O

        AppController();

Here we include the definitions for the both the SD card I/O and the file I/O. Next, we need to contruct the fs object in AppController‘s constructor. Go to app_controller.cpp:

    AppController::AppController() :
        fs(SD_SPI_MOSI, SD_SPI_MISO, SD_SPI_CLK, SD_SPI_CS, "sd")
    {
    }

Here we initialize the file system and provide the library with the SPI lines for communicating with the SD Card. The last parameter "sd" is the mount point. This means the SD Card is mounted at /sd.

Writing to a file

Let us write a file in the SD card. We use the standard C library functions fopen and fwrite, that you might know - if you ever coded in C.

So, to write some data to a file we insert the following code in the monoWakeFromReset method:

    void AppController::monoWakeFromReset()
    {
        FILE *file = fopen("/sd/new_file.txt", "w");

        if (file == 0) {
            printf("Could not open write file!\r\n");
            return;
        }
        else {
            const char *str = "Hello file system!\nRemember coding in C?";
            int written = fwrite(str, 1, strlen(str), file);
            printf("Wrote %d bytes\r\n",written);
            fclose(file);
        }
    }

Here we open/create a file on the SD card called new_file.txt. The fopen function returns a file descriptor (FILE*) that is 0 if an error occurs.

If file is not 0 we write some text to it and finally close (fclose) the file to flush the written data to the disk. You should always close files when you are done writing to them. If you don’t, you risk losing your written data.

Reading from a file

So we just written to a file, now let us read what we just wrote. Append the following to the monoWakeFromReset method:

    FILE *rFile = fopen("/sd/new_file.txt", "r");
    if (rFile == 0) {
        printf("Could not open read file!\r\n");
        return;
    }
    
    char buffer[100];
    memset(buffer, 0, 100);
    int read = fread(buffer, 1, 100, rFile);
    printf("Read %d bytes from file\r\n", read);
    printf("%s\r\n", buffer);
    fclose(rFile);

Here we first open the file we previously written. Then, we create a byte buffer to hold the data we read from the file. Because the initial content of buffer is nondeterministic, we zero its contents with the memset call.

Note

We do this because printf needs a string terminator. A string terminator is a 0 character. Upon accounting a 0 printf will know that the end of the string has been reached.

The fread function reads the data from the file. It reads the first 100 bytes or until EOF is reached. Then we just print the contents of buffer, which is the content of the file.

Standard C Library

As mentioned earlier, you have access to the file I/O of stdlib. This means you can use the familiar stdlib file I/O API’s.

These include:

  • fprintf
  • fscanf
  • fseek
  • ftell
  • fflush
  • fgetc
  • fputc
  • etc.

When you for example read or write from the serial port (using printf), you in fact just use the stdout and stdin global pointers. (stderr just maps to stdout.)

See the API for the stdlib file I/O here: www.cplusplus.com/reference/cstdio

SD Card and sleep

Currently the SD card file system library do not support sleep mode. When you wake from sleep the SD card have been reset, since its power source has been off while in sleep.

This means you cannot do any file I/O after waking from sleep. Until we fix this you need to reset Mono to re-enable file I/O.

Custom Views

In this tutorial we shall create our own custom view, that utilizes the drawing commands to display content on the screen.

Our software framework contains a selection of common View classes. These include TextLabels, Buttons and things like progress and state indicators. But you also have the ability to create your own views, to display custom content. Before we begin it is useful to know a little bit about views. Also, you should see the Display System Architecture article.

About Views

We have stolen the concept of a View from almost all other existing GUI frameworks. A view is a rectangular frame where you can draw primitives inside. All views define a width and height, along with a x,y position. These properties position all views on Mono’s display - with respect to the display coordinates.

The view concept

As you can see on the figure, the display coordinates have a origo at the top left corner of the screen. The positive Y direction is downward. In contrast to modern GUI frameworks Mono views cannot be nested and does not define their own internal coordinate system. All coordinates given to the drawing command are in display coordinates. It is your hassle to correct for the view’s x,y offsets.

Views can be Invisible and Dirty

All views has a visibility state. This state is used by the display system to know if it can render views to the screen. Only visible views are painted. By convention all views must be created in the invisible state. Further, views can also be dirty. This means that the view has changes that need to be rendered on the screen. Only dirty views are rendered. You can mark a view as dirty by calling the method: scheduleRepaint().

Painting views

When you create your own views, you must subclass the View class and you are required to overwrite 1 method: repaint(). This is the method that paints the view on the screen. The method is automatically called by the display system - you should never call it manually!

All views share a common DisplayPainter object that can draw primitives. You should draw primitives only from inside the repaint() method. If you draw primitives from outside the method, you might see artifacts on the screen.

The Goal

In this tutorial I will show you how to create a custom view that displays two crossing lines and a circle. To accomplish this we use the DisplayPainter routines drawLine() and drawCircle(), along with other routines to make our view robust. This means it does not make any assumptions about the screen state.

We want the cross and circle to fill the views entire view rectangle, so we use the view dimensions as parameters for the drawing functions.

Creating the project

First go ahead and create a new project:

$ monomake project customView --bare

Note

We use the –bare option to create an empty project without any example code.

It is good practice to create our custom view in separate files. Create two new files:

  • custom_view.h
  • custom_view.cpp

In the header file we define our new custom view class:

class CustomView : public mono::ui::View {
public:

    CustomView(const mono::geo::Rect &rect);

    void repaint();
};

We overwrite only the constructor and the repaint function. The default constructor for views takes a Rect that defines the views position and dimensions.

In the implementation file (custom_view.cpp) we add the implementation of the two methods:

// Constructor
CustomView::CustomView(const mono::geo::Rect &rect) : mono::ui::View(rect)
{

}

// and the repaint function
void CustomView::repaint()
{
    // enable anti-aliased line painting (slower but prettier)
    this->painter.useAntialiasedDrawing();

    // setup the view background color to pitch black
    painter.setBackgroundColor(mono::display::BlackColor);

    //draw the black background: a filled rect
    painter.drawFillRect(this->ViewRect(), true);

    // set the foreground color to a deep blue color
    painter.setForegroundColor(mono::display::MidnightBlueColor);

    // draw an outline rect around the view rectangle
    painter.drawRect(this->ViewRect());

    //set a new foreground color to red
    painter.setForegroundColor(mono::display::RedColor);

    //draw the first line in the cross
    painter.drawLine(this->ViewRect().UpperLeft(), this->ViewRect().LowerRight());

    //draw the second line in the cross
    painter.drawLine(this->ViewRect().LowerLeft(), this->ViewRect().UpperRight());

    //now we will draw the circle, with a radius that is the either width
    // or height - which ever is smallest.
    int radius;
    if (this->ViewRect().Width() < this->ViewRect().Height())
        radius = this->ViewRect().Width()/2;
    else
        radius = this->ViewRect().Height()/2;

    // create a circle object with center inside the views rectangle
    mono::geo::Circle c(this->ViewRect().Center(), radius - 1);

    //set the foreground color
    painter.setForegroundColor(mono::display::WhiteColor);

    //draw the circle
    painter.drawCircle(c);

    // disable anti-aliasing to make drawing fast for any other view
    painter.useAntialiasedDrawing(false);
}

Now, this code snippet is a mouthful. Let me break it down to pieces:

The constructor

Our constructor simply forwards the provided Rect object to the parent (View) constructor. The parent constructor will take care of initializing the our views properties. In our implementation we simply call the parent constructor and leave the methods body empty.

The repainting

This is here we actually paint the view. As mentioned earlier all views share a global DisplayPainter object. This object holds a set of properties like paint brush colors and anti-aliasing settings. Therefore, to be sure about what colors you are painting, you should always set the colors in your repaint() method.

We start by enabling anti-aliased drawing of lines. This slows down the painting process a bit, but the lines looks much smoother. Next, we set the painters background brush color to black. With the black color set, we draw a filled rectangle clearing the entire area of the view. This is important because there might be some old graphics present on the screen.

To highlight the views boundary rectangle we draw an outlined rectangle with the dimension of the views own rectangle. You can say we give the view a border.

Next, we begin to draw the crossing lines - one at the time. The drawLine routine take the begin and end points of the line. We use a set of convenience methods on the Rect class to get the positions of the view rectangle‘s corners.

The Circle class defines circles by a center and a radius. We can get the view rectangles center using another convenient method on the Rect object. But we need to do a little bit of calculations to get the radius. We use the smallest of the width and height, to keep the circle within the view boundaries. (And subtract 1 to not overwrite the border.)

Lastly, we disable the anti-aliased drawing. To leave the DisplayPainter as we found it.

The Result

Now, we must add our CustomView to our application. This means we must use it from the AppController. Therefore, include the header file in app_controller.h, and add our CustomView as a member variable:

#include "custom_view.h"

class AppController : public mono::IApplication {
public:

    CustomView cv;
    
    AppController();
    //...

Finally, we need to initialize our view correctly in AppController‘s constructor and set the views visibility state by calling the show() method.

In app_controller.cpp add:

AppController::AppController() :
    cv(mono::geo::Rect(20,30,136,70))
{
}

void AppController::monoWakeFromReset()
{
    cv.show();
}

Notice that we set the views position and dimensions in the constructor, by defining a Rect \((20, 30, 136, 70)\).

Do a make install and our custom should look like this on your Mono:

Example of the custom view

Because we use the views own dimensions to draw the primitives, the view will paint correctly for all dimensions and positions.

Humidty app
Humidity harware setup

The purpose of this tutorial is to build a humidity app.

Mono connected to humidity sensor

Sensor

To get humidity readings into my Mono, I will need a humidity sensor. For this app I will use the relatively low cost sensors DHT11 and DHT22. Their underlying hardware communication protocol is the same, but the interpretation of the readings differ slightly (DHT22 has better resolution).

DHT11 and DHT22 pinout

Connecting the sensor to Mono

The sensor uses a single wire to transmit data, and it must get power through two additional wires (3.3V and 0V).

So I need three wires in total from Mono to the sensor. Mono’s mini-jack accomodates a total of four wires, so I will use a mini-jack connector and solder a set of wires to it. For this particular application, I could use a regular three-wire mini-jack, but the mini-jack connector I have has four connections, so I will solder all four wires and reserve the fourth wire for future experiments.

Four wires soldered onto mini-jack

Here I have put a red wire on the tip, a white wire on ring 1 (the one next to the tip), a black wire on the sleeve. The green wire is connectred to ring 2, but it is not used in the app.

With that taken care of, I can connect the sensor to my Mono and start pulling out data from the sensor.

Data communication

To sanity check the connection, I will make the simplest possible app that can request a reading from the sensor, and then view the result on an oscilloscope. You do not need to do this, of course, but I will need to do that to show you what the sensor communication looks like.

An application to get the sensor talking must put 3.3V on the tip (red wire), and then alternate the data line (white wire) between 3.3V and 0V to tell the sensor that it needs a reading. The sleeve (black wire) is by default set to 0V, so nothing needs to be setup there.

More specificly, the data line must be configured to be an output pin with pullup. To request a reading from the sensor, the data line needs to be pulled down to 0V for 18ms, and then set back to 1. After that, the sensor will start talking.

The following program makes such a request every 3 seconds.

#include <mono.h>
#include <mbed.h>

class AppController
:
    public mono::IApplication
{
    mono::Timer measure;
    mbed::Ticker ticker;
    mono::io::DigitalOut out;
public:
    AppController()
    :
        measure(3*1000),
        out(J_RING1,1,PullUp),
    {
        measure.setCallback<AppController>(this,&AppController::requestSensorReading);
    }
    void monoWakeFromReset ()
    {
        put3V3onTip();
        measure.Start();
    }
    void monoWillGotoSleep ()
    {
        turnOffTip();
    }
    void monoWakeFromSleep () {}
    void put3V3onTip ()
    {
        DigitalOut(VAUX_EN,1);
        DigitalOut(VAUX_SEL,1);
        DigitalOut(JPO_nEN,0);
    }
    void turnOffTip ()
    {
        DigitalOut(JPO_nEN,1);
    }
    void requestSensorReading ()
    {
        out = 0;
        ticker.attach_us(this,&AppController::IRQ_letGoOfWire,18*1000);
    }
    void IRQ_letGoOfWire ()
    {
        out = 1;
    }
};

Side note: I use the IRQ_ prefix on functions that are invoked by interrupts to remind myself that such functions should not do any heavy lifting.

When I connect Mono to the sensor, and hook up an oscilloscope to the data and ground wires, then I get the following picture of the communication when I run the app.

Oscilloscope capture of humidity reading

To the left you can see a tiny bit of the end of the 18ms period, ending in a rising edge (the transition from 0V to 3.3V) marked by T (the trigger point). From there on, the sensor takes over and starts alternating the data line between 3.3V and 0V.

The first 3.3V period is just a handshake, and after that the length of each 3.3V period determines whether data sent from the sensor is a logical 1 or a logical 0. For the screenshot above, the visible part of data is 0000000110.

What exactly does that mean? Well, I will tell you in the next part.

Humidity app

In the first part of this Humidity app tutorial, I showed how to connect a humidity sensor to Mono. Now, I will show how to get and display humidity and temperature readings.

Displaying readings

The humidity sensor measures both humidity and temperature, and I want these readings shown in a nice big font and funky colours.

#include <mono.h>
#include <ptmono30.h>
using mono::geo::Rect;
using mono::ui::TextLabelView;

class AppController
:
    public mono::IApplication
{
    TextLabelView humidityLabel;
    TextLabelView humidityValueLabel;
    TextLabelView temperatureLabel;
    TextLabelView temperatureValueLabel;
public:
    AppController()
    :
        humidityLabel(Rect(0,10,176,20),"humidity"),
        humidityValueLabel(Rect(0,30,176,42),"--.--"),
        temperatureLabel(Rect(0,80,176,20),"temperature"),
        temperatureValueLabel(Rect(0,100,176,42),"--.--")
    {
    }
    void monoWakeFromReset ()
    {
        humidityLabel.setAlignment(TextLabelView::ALIGN_CENTER);
        humidityLabel.setTextColor(TurquoiseColor);
        humidityValueLabel.setAlignment(TextLabelView::ALIGN_CENTER);
        humidityValueLabel.setFont(PT_Mono_30);
        humidityValueLabel.setTextColor(AlizarinColor);
        temperatureLabel.setAlignment(TextLabelView::ALIGN_CENTER);
        temperatureLabel.setTextColor(TurquoiseColor);
        temperatureLabel.setAlignment(TextLabelView::ALIGN_CENTER);
        temperatureValueLabel.setAlignment(TextLabelView::ALIGN_CENTER);
        temperatureValueLabel.setFont(PT_Mono_30);
        temperatureValueLabel.setTextColor(AlizarinColor);
        humidityLabel.show();
        humidityValueLabel.show();
        temperatureLabel.show();
        temperatureValueLabel.show();
    }
    void monoWillGotoSleep () {}
    void monoWakeFromSleep () {}
};
Getting data from the sensor

From the first part of this tutorial, you know how to start a reading from the sensor, but it gets somewhat more complicated to capture and interpret the data from the sensor.

The data from the sensor is a series of bits, where each bit value is determined by the length of each wave. So I can make my app to trigger on the start of each new wave and then record the time that has passed since the the last wave started. The triggering can be done by attaching an interrupt handler to the data wire, which is done by using the InterruptIn class from the mbed library.

Compared to the first version, I now have an array bits and an index bitIndex into this array so that I can collect the bits I read from the sensor. The requestSensorReading function now resets bitIndex before requesting a new reading, and IRQ_letGoOfWireAndListen sets up the function IRQ_falling to get called every time there is a falling edge on the data line from the sensor:

#include <mono.h>
#include <mbed.h>
using mono::io::DigitalOut;

#define LEADBITS 3
#define TOTALBITS LEADBITS+5*8

class AppController
:
    public mono::IApplication
{
    mono::Timer measure;
    mbed::Ticker ticker;
    mbed::InterruptIn in;
    DigitalOut out;
    uint8_t bits [TOTALBITS];
    size_t bitIndex;
    uint32_t usLastTimeStamp;
public:
    AppController()
    :
        measure(3*1000),
        /// It is important that InterruptIn in initialised...
        in(J_RING1),
        /// ...before DigitalOut because they use the same pin, and the initialisation
        /// sets the pin mode, which must be pull-up.
        out(J_RING1,1,PullUp)
    {
        measure.setCallback<AppController>(this,&AppController::requestSensorReading);
    }
    void monoWakeFromReset ()
    {
        put3V3onTip();
        measure.Start();
    }
    void monoWillGotoSleep ()
    {
        turnOffTip();
    }
    void monoWakeFromSleep () {}
    void put3V3onTip ()
    {
        DigitalOut(VAUX_EN,1);
        DigitalOut(VAUX_SEL,1);
        DigitalOut(JPO_nEN,0);
    }
    void turnOffTip ()
    {
        DigitalOut(JPO_nEN,1);
    }
    void requestSensorReading ()
    {
        bitIndex = 0;
        out = 0;
        ticker.attach_us(this,&AppController::IRQ_letGoOfWireAndListen,18*1000);
    }
    void IRQ_letGoOfWireAndListen ()
    {
        out = 1;
        usLastTimeStamp = us_ticker_read();
        in.fall(this,&AppController::IRQ_falling);
    }
    void IRQ_falling ()
    {
        uint32_t usNow = us_ticker_read();
        uint32_t usInterval = usNow - usLastTimeStamp;
        usLastTimeStamp = usNow;
        uint8_t bit = (usInterval < 100) ? 0 : 1;
        bits[bitIndex] = bit;
        ++bitIndex;
        if (bitIndex >= TOTALBITS)
        {
            in.disable_irq();
            // TODO:
            //async(this,&AppController::collectReadings);
        }
    }
};

The IRQ_falling function calculates the time difference between the last falling edge on the data from the sensor, and if that interval is less that 100 µs, then the received bit is a 0; otherwise it is a 1. When enough bits have been received, the interrupt is turn off so that I will stop receiving calls to IRQ_falling.

I use the IRQ_ prefix on functions that are invoked by interrupts to remind myself that such functions should not do any heavy lifting. That is also why the (to be done) processing of the received bits is wrapped in an async call.

Interpreting the data from the sensor

Up until now, it has made no difference whether I was using a DHT11 or DHT22 sensor. But now I want to implement the collectReadings function to interpret the bits I get back from the sensor, and then the type of sensor matters.

I will start with the DHT11 sensor, which only gives me the integral part of the humidity and temperature value. So I need to go through the array of bits, skip the initial handshakes, dig out the humidity, dig out the temperature, and finally update the display with the new values:

    // DHT11
    void collectReadings ()
    {
        uint16_t humidity = 0;
        for (size_t i = LEADBITS; i < LEADBITS + 8; ++i)
        {
            size_t index = 7 - (i - LEADBITS);
            if (1 == bits[i])
                humidity |= (1 << index);
        }
        uint16_t temperature = 0;
        for (size_t i = LEADBITS + 16; i < LEADBITS + 24; ++i)
        {
            size_t index = 7 - (i - LEADBITS - 16);
            if (1 == bits[i])
                temperature |= (1 << index);
        }
        humidityValueLabel.setText(String::Format("%d%%",humidity)());
        humidityValueLabel.scheduleRepaint();
        temperatureValueLabel.setText(String::Format("%dC",temperature)());
        temperatureValueLabel.scheduleRepaint();
    }

For the DHT22 sensor, the values have one decimal of resolution. So I need to do a little bit more manipulation to display the reading, because the Mono framework do not support formatting of floating point:

    // DHT22
    void collectReadings ()
    {
        uint16_t humidityX10 = 0;
        for (size_t i = LEAD; i < LEAD + 16; ++i)
        {
            size_t index = 15 - (i - LEAD);
            if (1 == bits[i])
                humidityX10 |= (1 << index);
        }
        int humiWhole = humidityX10 / 10;
        int humiDecimals = humidityX10 - humiWhole*10;
        uint16_t temperatureX10 = 0;
        for (size_t i = LEAD + 16; i < LEAD + 32; ++i)
        {
            size_t index = 15 - (i - LEAD - 16);
            if (1 == bits[i])
                temperatureX10 |= (1 << index);
        }
        int tempWhole = temperatureX10 / 10;
        int tempDecimals = temperatureX10 - tempWhole*10;
        humidityValueLabel.setText(String::Format("%d.%0d%%",humiWhole,humiDecimals)());
        humidityValueLabel.scheduleRepaint();
        temperatureValueLabel.setText(String::Format("%d.%0dC",tempWhole,tempDecimals)());
        temperatureValueLabel.scheduleRepaint();
    }

What is still missing is detecting negative temperatures, unit conversion and auto sleep, but I will leave that as an excercise. Of course, you could cheat and look at the full app in MonoKiosk.

Quick Examples
Counting variable on mono’s screen.

This is a small example of how to show a counting variable on mono’s screen.

Warning

This is a draft article, that is work in progress. It still needs some work, therefore you might stumble upon missing words, typos and unclear passages.

When mono (and some Arduino’s) runs a program there is more going on than what you can see in the setup() and main() loop. Every time the main loop is starting over, mono will do some housekeeping. This includes tasks as updating the screen and servicing the serial port. This means that if you use wait functions or do long intensive tasks in the main loop, mono will never have time for updating the screen or listening to the serial port. This will also affect monos ability to receive a reset announcement, which is important every time you are uploading a new sketch.

If you are running into this you can always put mono into bootloader manually

  1. press and hold down the user button on the side.
  2. press and release the reset switch with a clips.
  3. release the user button.

To avoid doing this every time the following example uses an alternative to the wait function. To slow down the counting, we here use a variable to count loop iterations and an if() to detect when it reaches 1000 and then increment the counter and update the label on the screen.

Warning

When using this method the timing will be highly dependent on what mono is doing for housekeeping.

For the time being the housekeeping is not optimized, we will work on this in near future. This means that the timing in your program will change when we update the framework. We are working on making a tutorial that shows how to make time-critical applications.

    /***
     * 
     * This is a small example of how to show a counting variable on mono's screen.
     *
     * Instead of using a delay function to slow down the counting, I here use a variable to count loop iterations
     * and an if() to detect when it reaches 1000 and then increment the counter and update the label on the screen.
     * 
     ***/
    #include <mono.h>
    
    mono::ui::TextLabelView textLbl(mono::geo::Rect(0,20,176,20),"Hi, I'm Mono");
    
    int loopItererations;
    int counter;
    
    void setup()
    {
      textLbl.setTextColor(mono::display::WhiteColor); 
      textLbl.show();

      // to prevent the framework from dimming the light
      CY_SET_REG8( CYREG_PRT5_BYP, 0 );                             // attention: this will affect all pins in port 5
      CyPins_SetPinDriveMode( CYREG_PRT5_PC1, CY_PINS_DM_STRONG );  // set drivemode to strong for TFT LED backlight
      CyPins_SetPin( CYREG_PRT5_PC1 );                              // set pin high for TFT LED backlight

    }
        
    void loop()
    {
      loopItererations++;
    
      if( loopItererations >= 1000 )
      {
        loopItererations = 0;
        counter++;
        textLbl.setText(mono::String::Format("count: %i", counter));
      }
    }

Attention

This example uses a hack to prevent dimmer of the display. This is only a temporary solution, and is not recommended. You should replace any use of the code when we release a best-practice method.

Adding a Button to the Screen

In this quick tutorial we shall see how to add a set of push buttons to the screen.

The SDK comes this standard classes for screen drawing and listening for touch input. One of these classes are ButtonView. ButtonView display a simple push button and accepts touch input.

Reacting to clicks

Let us go create a new Mono project, fire up your terminal and:

$ monomake project buttonExample

To create a button on the screen we first add a ButtonView object to AppController. Insert this into app_controller.h:

class AppController : public mono::IApplication {
    
    // This is the text label object that will displayed
    TextLabelView helloLabel;

    // We add this: our button object
    ButtonView btn;
    
public:

    // The default constructor
    AppController();

    // We also add this callback function for button clicks
    void buttonClick();

We added a member object for the button itself and a member method for its callback. This callback is a function that is called, then the button is clicked.

Now, in the implementation file (app_controller.cpp), we add the button the contructor initializer list:

AppController::AppController() :

    // Call the TextLabel's constructor, with a Rect and a static text
    helloLabel(Rect(0,100,176,20), "Hi, I'm Mono!"),

    // Here we initialize the button
    btn(Rect(20, 175, 136, 40), "Click me!")
{

The button’s constructor takes 2 arguments: position and dimension rectangle and its text label. The first argument is a Rect object, it defines the rectangle where the Button lives. This means it will draw itself in the rectangle and listen for touch input in this rectangle:

The position and dimension of the button

The second argument is the text label that is displayed inside the button. In this example it is just the text Click me!

To trigger a response when we click the button, we need to implement the function body for the buttonClick method. In app_controller.cpp add this method:

void AppController::buttonClick()
{
    helloLabel.setText("Button clicked!");
}

This method changes the content of the project templates existing helloLabel to a new text. Lastly, we connect the button click handler to call our function. From inside the monoWakeFromReset method, we append:

// tell the label to show itself on the screen
helloLabel.show();

// set the callback for the button click handler
btn.setClickCallback<AppController>(this, &AppController::buttonClick);
// set the button to be shown
btn.show();

That’s it! Run make install and see the example run on Mono:

Before and after the button is clicked

Periodically call a Function

In this quick example we will see how to use a Timer to repetitively call a function

A big part of developing apps is do tasks at regular intervals. Mono employs a timer architecture that allows you to schedule single or recurring function calls, ahead of time. The semantics are “call this function 3 minutes from now”, or “call this method every 45 second”.

Timers

The timer system on Mono is very powerful, you can schedule as many timers as of like! (Okay, you are limited by the amount of RAM). The timers are instances of the class Timer and they are built upon the bed::Ticker class. This architecture leverages the versatility of the mbed timers and adds thread safety from Mono’s own Timer class.

You can schedule a method to be called 5 minutes from now, by a single line of code:

mono::Timer::callOnce<MyClass>(5*60*1000, this, &MyClass::MyCallbackMethod);

This will create a timer instance on the heap, and it will deallocate itself after it has fired. Because we use C++ methods, and not C functions as callbacks, you must provide the this pointer and the type definition of the context. (MyClass in the example above.) The last parameter is the pointer to the actual method on the class. This makes the call a bit more verbose, compared to C function pointers, but being able define callback methods in C++ is extremely powerful.

Note

In recent versions of C++ (C++11 and C++14), lambda functions has been added. These achieve the same goal with a cleaner syntax. However, we cannot use C++11 or 14 on Mono, the runtime is simply too large!

Call a function every second

Now, let us see how to repeatedly call a function every second. First, we create a new project from the console / terminal:

$ monomake project timerExample

Open the app_controller.h file and add a Timer as a member on the AppController class, and define the method we want to be called:

class AppController : public mono::IApplication {
    
    // This is the text label object that will displayed
    TextLabelView helloLabel;
    
    // this is our timer object
    Timer timer;
    
public:

    //this is our method we want the timer to call
    void timerFire();

Because we want to repetitively call a function, we need the timer to stick around and not get deallocated. Therefore, it is declared as a member variable on AppController. In the implementation file (app_controller.cpp) we need to initialize it, in the constructors initialization list:

AppController::AppController() :

    // Call the TextLabel's constructor, with a Rect and a static text
    helloLabel(Rect(0,100,176,20), "Hi, I'm Mono!"),
    // set our timers interval to 1000 ms
    timer(1000)
{

Let us add the body of the timerFire method to the implementation file, also:

void AppController::timerFire()
{
    printf("Timer did fire!\t\n");
}

Lastly, we tie the timer callback handler to out method. This is done from inside the monoWakeFromReset method:

void AppController::monoWakeFromReset()
{
    // tell the label to show itself on the screen
    helloLabel.show();
    
    // set the timers callback handler
    timer.setCallback<AppController>(this, &AppController::timerFire);
    // start the timer
    timer.Start();
}

All right, go to the console and run make install and our app should compile and upload to mono. Open a serial terminal and you should see:

Timer did fire!
Timer did fire!
Timer did fire!
Timer did fire!

Arriving with 1 second intervals.

Timing the UI

Now, let us step it up a bit. We want to toggle a UI element with our timer function. The SDK includes a class called StatusIndicatorView, it mimics a LED that just is on or off. Lets add it as a member on our AppController:

class AppController : public mono::IApplication {
    
    // This is the text label object that will displayed
    TextLabelView helloLabel;
    
    Timer timer;
    
    StatusIndicatorView stView;

We also need to initialize with position and dimension in the initializer list:

AppController::AppController() :

    // Call the TextLabel's constructor, with a Rect and a static text
    helloLabel(Rect(0,100,176,20), "Hi, I'm Mono!"),
    // set our timers interval to 1000 ms
    timer(1000),
    
    stView(Rect(75,55,25,25))
{

Then, in the monoWakeFromReset method we must set its *visibility state *to shown:

// tell the label to show itself on the screen
helloLabel.show();

// set the timers callback handler
timer.setCallback<AppController>(this, &AppController::timerFire);
// start the timer
timer.Start();

stView.show();

Last we insert code to toggle its state in the timerFire method:

void AppController::timerFire()
{
    printf("Timer did fire!\t\n");
    
    stView.setState(!stView.State());
}

Go compile and run the modified code. You should see this on your mono:

Timer controlling UI state example

Sample code

Here is the full source code for reference:

app_controller.h:

#ifndef app_controller_h
#define app_controller_h

// Include the Mono Framework
#include <mono.h>

// Import the mono and mono::ui namespaces into the context
// to avoid writing long type names, like mono::ui::TextLabel
using namespace mono;
using namespace mono::ui;

// The App main controller object.
// This template app will show a "hello" text in the screen
class AppController : public mono::IApplication {
    
    // This is the text label object that will displayed
    TextLabelView helloLabel;
    
    Timer timer;
    
    StatusIndicatorView stView;
    
public:
    
    //this is our method we want the timer to call
    void timerFire();

    // The default constructor
    AppController();

    // Called automaticlly by Mono on device reset
    void monoWakeFromReset();

    // Called automatically by Mono just before it enters sleep mode
    void monoWillGotoSleep();

    // Called automatically by Mono right after after it wakes from sleep
    void monoWakeFromSleep();
    
};

#endif /* app_controller_h */

app_controller.cpp:

#include "app_controller.h"

using namespace mono::geo;

// Contructor
// initializes the label object with position and text content
// You should init data here, since I/O is not setup yet.
AppController::AppController() :

    // Call the TextLabel's constructor, with a Rect and a static text
    helloLabel(Rect(0,100,176,20), "Hi, I'm Mono!"),
    // set our timers interval to 1000 ms
    timer(1000),
    
    stView(Rect(88,55,25,25))
{

    // the label is the full width of screen, set it to be center aligned
    helloLabel.setAlignment(TextLabelView::ALIGN_CENTER);
    
    // set another text color
    helloLabel.setTextColor(display::TurquoiseColor);
}

void AppController::timerFire()
{
    printf("Timer did fire!\t\n");
    
    stView.setState(!stView.State());
}

void AppController::monoWakeFromReset()
{
    // At this point after reset we can safely expect all peripherals and
    // I/O to be setup & ready.

    // tell the label to show itself on the screen
    helloLabel.show();
    
    // set the timers callback handler
    timer.setCallback<AppController>(this, &AppController::timerFire);
    // start the timer
    timer.Start();
    
    stView.show();
}

void AppController::monoWillGotoSleep()
{
    // Do any clean up here, before system goes to sleep and power
    // off peripherals.

}

void AppController::monoWakeFromSleep()
{
    // Due to a software bug in the wake-up routines, we need to reset here!
    // If not, Mono will go into an infinite loop!
    mono::IApplicationContext::SoftwareResetToApplication();
    // We never reach this point in the code, CPU has reset!

    // (Normally) after sleep, the screen memory has been cleared - tell the label to
    // draw itself again
    helloLabel.scheduleRepaint();
}
Measuring the Temperature

This quick tutorial will demonstrate how you measure the temperature, by using the standard temperature sensor API

Mono has a built-in thermometer that is situated on the PCB under the SD Card connector. We have a standard API for getting the temperature in degrees Celcius. If you wish to get convert to Fahrenheit, use this formula: \( ^{\circ}F = ^{\circ}C \cdot 1.8 + 32 \)

Example

Let us try to fetch the temperature! The Mono SDK uses a standard interface for getting the temperature, that abstracts away the hardware. The interface contains of only two functions:

  • Read() To get the temperature in celcius (as an integer)
  • ReadMilliCelcius() To get the temperature in an integer that is 1000th of a celcius. \(1 ^{\circ}C = 1000 ^{\circ}mC\)

You acquire a reference (a pointer) to the interface through the global IApplicationContext variable:

sensor::ITemperature *temp = IApplicationContext::Instance->Temperature;
int mcel = temp->ReadMilliCelcius();

Now the variable mcel hold the temperature in millicelcius. Divide by 1000 to get the value in celcius. You can easily print the temperature on the serial port by using printf:

printf("%d.%d",mcel/1000,mcel%1000);

Caution

Please observe that we cannot use the %f format specifier in the printf function! To make the application binary smaller, it is not linked with printf‘s floating point formatting. If you wish to add floating point I/O, then you should add -u _printf_float in the linker command!

That is it. You can now read the temperature! Go hack or keep reading, for a little more on temperature measurements.

Temperature measuring Caveats

Measuring the temperature seems like a simple operation, but you should know that it is actually quite difficult to get it right. First for all, unless you really invest money and time in advanced equipment and in calibrating this equipment, then you will not get a precise measurement. But then, what is a precise measurement?

First let us visit the terms: absolute and relative measurements. An absolute temperature measurement is a temperature measured againts a fixed global reference. At the summer the sea temperature at the beaches reach \(25 ^{\circ}C\) or \(77 ^{\circ}F\). This is an absolute measurement. In contrast if I say: The sea temperature has rised by \(2 ^{\circ}C\) or \(3,5 ^{\circ}F\), rise in temperature is a reltive measurement.

When measuring temperature you should know that absolute measurements are hard, and relative measurements are easy in comparison. Normal household thermometers do not achieve a precision below \(1 ^{\circ}C\) or \(1.8 ^{\circ}F\), in absolute measurements. But their relative precision can be far better - like \(0.1 ^{\circ}C\) or \(0.18 ^{\circ}F\).

Mono’s built-in thermometer share the same characteristics. However, be aware that the thermometer is mounted on the PCB which get heated by the electronics inside the device. You are measuring the temperature of the PCB - not the air temperature. To overcome this you can put mono in sleep mode for some time, and then wake up and measure the temperature. When Mono is in sleep, the PCB will (over time) get the same temperature as the air around it.

Using the Buzzer

In this quick tutorial I will demonstrate how to make Mono buzz, using the simple API in the SDK

Mono has a built-in buzz speaker. The speaker is directly connected to a GPIO on Mono’s MCU. We have configured the MCU such that the GPIO pin is used by a hardware PWM. This means the speaker is driven by a square pulse signal generated by the MCU hardware. The software only has to turn the PWM on and off.

Simple Example

Let us begin with a code snippet that beeps for 0.5 sec:

void AppController::monoWakeFromReset() {
    
    // Get a pointer to the buzzer object
    mono::sensor::IBuzzer *buzzer = mono::IApplicationContext::Instance->Buzzer;

    // make a beep for 0.5 sec
    buzzer->buzzAsync(500);
}

First we get a pointer to the current buzzer object that has been created by the global ApplicationContext object. All buzz-speaker objects must implement the IBuzzer interface, that defines methods to emit buzzing sounds.

Then we use the method buzzAsync that turns on the speaker. The important thing here is to note that the buzzing is asynchronous. The signal sent to the speaker is hardware generated, so the software does not need to do anything. When buzzAsync returns, the buzzing is still going on - and will it do so for the next 0.5 sec.

Multiple Beeps

If you what to make, say 3 beeps in a row, you need to use callbacks. This is due to the asynchonous behaviour of the IBuzzer interface. Luckily there is a similar method called: buzzAsync(void (*callback)(void)). This method takes a callback function, that gets called when the buzzing has ended. We can use this function to chain the buzzing, thereby making multiple beeps.

To do this, we use the built-in Timer class to control the delay between beeps.

Note

This is the best practice approach. The lazy ones might choose to use several wait_ms() calls. But this approach will stall the CPU, making it unresponsive.

In our AppController we declare an integer count variable. We also add a callback function for the buzz (buzzEnded()) and one for the delay (pauseEnded()).

wakeFromReset:

void AppController::monoWakeFromReset() {

    // init the count to 0
    count = 0;
    
    mono::sensor:IBuzzer *buzzer = mono::IApplicationContext::Instance->Buzzer;
    
    // begin the buzzing (for 0.5 sec)
    buzzer->buzzAsync<AppController>(500, this, &AppController::buzzEnded);
}

buzzEnded:

void AppController::buzzEnded() {

    // increment the buzz beep count
    count++;

    // If we have buzzed less the 3 times, start a delay timer
    if (count < 3)
        mono::Timer::callOnce<AppController>(500, this, &AppController::buzzEnded);
}

pauseEnded:

void AppController::buzzEnded() {

    //the delay timed out - begin buzzing again

    // get the buzzer pointer
    mono::sensor:IBuzzer *buzzer = mono::IApplicationContext::Instance->Buzzer;
    
    // begin buzzing again (for 0.5 sec)
    buzzer->buzzAsync<AppController>(500, this, &AppController::buzzEnded);
}

Now, since we use Timers and async buzzing, Mono will stay responsive during both the buzzing and the pauses in between. This means it will keep sampling the touch input, updating display and running other timers in the background.

Killing a buzz

Say you might have called buzzAsync(60000), which is a one minute long buzz tone. After some seconds you regret the decision and wish cancel the buzzing. To do that you use the buzzKill() method! Calling this method will immediate stop any buzzing started earlier.

Note

If you have installed a callback at the end of your buzz - the callback will still get called.

In-Depth Articles

In this chapter we shall take a dive into the structure and workings of Mono Framekwork. The purpose of each article is to give you an understanding of how mono internals works. You do not have to read these articles, but knowledge of the framework design and workings will definately help you. Especially if (when) you bump into problems.

Architectural Overview

In this article we take a quick tour of the complete framework, its classes and features. We will visit the most important topics and requirements for developing Mono applications.

Who should read this?

If you wish to understand the concepts and thoughts behind the frameworks structure, this article is for you. Or if you should choose to read only one in-depth article, it should definitely be this one!

Warning

This is a draft article, that is work in progress. It still needs some work, therefore you might stumble upon missing words, typos and unclear passages.

Overview

Mono Framework is a collection of C++ classes, all build on top of the mbed library created by ARM. The complete Mono software stack consists of 3 levels of abstractions, which are separate libraries:

  1. Mono layer (C++): All high-level classes
  2. mbed layer (C++/C): Hardware level I/O and functions (including most of stdlib)
  3. Cypress layer (C): Hardware dependent code, generated by PSoC Creator

In this article we focus mainly on the Mono layer. Mono is an open system, so you have access to the underlying layers from your application. However, you should use only layer 3 (and some of mbed), if you really can not avoid it. Using these layers might break compatibility with future hardware releases and the to-be-released simulator.

API Overview

Below is a diagram of the features provided by Mono Framework. These are the high-level interfaces that makes it fast and easy, for you to take advantage of all Mono’s features.

Mono Framework Feature Overview

As you can see in the diagram, the features can be grouped by their function. Some framework classes are generic, like the String class. Other serves a specific purpose, like providing the accelerometer interface (IAccelerometer).

Core Concepts

Since there is no operating system, your application will run on bare metal, meaning it interfaces the hardware directly. On a versatile platform, such as Mono, it means that your application must deal with some critical events and concepts. In the next sections we shall take a look at the key functions and requirements of all applications targeting the OpenMono platform.

Application lifecycle

The application lifecycle is the time from execution of the first instruction to the last. In conventional environments this is from main() gets called, until it returns:

    // This is a normal familiar C++ application main function:
    int main(char *argv[], int argc)
    {
        // Application lifecycle begins
        
        // do stuff
        
        // Application lifecycle ends
        return 0;
    }

This is the case when you are inside an operating system. Mono is an embedded platform, so here the lifecycle is quite different and determined by the power on and power off events.

When the CPU powers up, it will immediately start executing your application. And it will not stop before you cut the CPU’s power source - literally! There is no return 0 that stops your application.

Mono is Always on

Mono’s hardware is always powered, because there is just no power switch! You can not simply cut the power to the CPU, when you what to turn off Mono. The “turn off” feature needs to be the software that throttles down the CPU and puts all peripherals into a low power state. We call this state: sleep mode.

Mono Framework helps you with handling sleep mode. By default Mono’s side-button will toggle sleep mode. It will put Mono to sleep, and wake Mono up again if pressed during sleep. You do not need to do anything to support sleep mode, it is provided to you by the framework. Only if you need to make use of the side-button for you own purpose, you must provide a way of going to sleep. This is done by calling the IApplicationContext::EnterSleepMode method:

// put mono into sleep mode:
mono::IApplicationContext::EnterSleepMode(); // execution halts here until wake-up

// only after wake-up will EnterSleepMode return
printf("Mono has awaken!");

Because power is never cut from the CPU, it rarely resets. The application state is preserved across sleep cycles, meaning that your application lifespan will be long. Even significantly longer when compared to desktop applications. The long lifespan makes the application more vulnerable to errors, such as memory leaks, corrupting memory or stack overflows. The point is: it is a tough job to be an embedded developer .

Power On Reset

The term Power On Reset or POR means the initial reset that occurs when the CPU powers on. This is when the power supply is first asserted or the physical H/W reset line is de-asserted. On Mono a POR is the same as a hardware reset.

A POR can be triggered in a number of different ways:

  • Pressing Mono’s reset button
  • If Mono’s battery is drained, the power control software will halt the CPU’s. When Mono is charged, the system will wake the CPU and a software triggered POR happens.
  • Uploading a new application to Mono, using monoprog.
  • Your application can trigger a SoftwareReset, that results in a POR.

Every Mono application is required to handle the POR event. It is here your application must setup all needed peripherals, such as temperature sensor or SD Card file I/O. If you use any UI Widgets, you need to initialize them on POR as well.

Later in the Required virtual methods section, we shall see how you handle the POR event.

Sleep and Wake-up

When Mono goes to sleep mode it turns off all peripherals to minimize power consumption.

You have the option to handle the go to sleep and wake from sleep events, as we shall see in the section about the The AppController. We imagine you might need to do some book-keeping or I/O flushing before entering sleep. Likewise, you may need some setup after waking from sleep. If you use the display, you will need to take repaint actions when waking from sleep.

However, it you are lazy could could just trigger a SoftwareReset upon wake from sleep, but you would loose any state that is not serialized.

The run loop

Like most modern application runtimes, Mono has an internal run loop (also called an event loop). The loop handles periodic tasks, like sampling the touch system, updating the display, processing Timers and handling any other asynchronous task. You can inject your own tasks into the run loop, and there by achieve the Arduino-like loop() functionality.

The run loop is started right after your POR handler returns, and runs for the entire length of the application lifecycle.

Callback functions

Because we have a run loop we can make tasks asynchronous. This does not mean your code will run concurrently, it means that you can put tasks in the background. You do not need to think about race-conditions and other rough topics related to parallelism.

You use callback functions to handle events that arrive, and require your action. For example you can schedule a function call in the future. The Timer class can schedule a function getting called 5 secs from now:

    mono::Timer::callOnce<MyClass>(5000, this, &MyClass::futureFunction);

Notice the syntax here. We use C++ templates and function pointers. Reason is the complexity of context and function pointers in C++. In C you create function pointers with ease:


    void MyFunction() {}

    mono::Timer::callOnce(5000, &MyFunction);

C functions has no context (do not belong to a class), and can be identified by a pointer. Functions (methods to be precise) in C++ exists as attributes on object instances. When we use these as callback handlers, we need to define 3 parameters:

  1. The type of class where the method is defined
  2. Provide a pointer to an instance of the class (the object)
  3. Provide the actual function (method) pointer

Note

That we can have callback methods in old C++98 is a kind of hack. In more modern C++ version, lambda functions achieve the same - but less verbose. Unfortunately Mono do not have enough memory to contain the runtime libraries for either C++11 or C++14.

Timers
  • Timers trigger a periodic event handler callback
  • Real-Time apps might update its state/content on a regular interval
  • Timers can also be used to call a function at some point in the future (as soon as possible).
Queued interrupts
  • in embedded environment interrupts are hardware triggers, that call a C function (the ISR)
  • the ISR should be fast and return very quickly - a lot of concurrency issues arise when using ISR.
  • mono uses Queued interrupt, where the ISR is handled in the run loop.
  • no concurrency issues
  • you can longer lived ISR’s
  • they can debounce your hardware input signals, to create more robust handling of button or switches
The AppController

All application must have a app controller - this is there entry point

Required virtual methods
Application Entry Point & Startup
  1. static inits
  2. main func
  3. app ctrl POR method
  4. run loop
The Bootloader
Crashes and Exceptions
Best Pratice

some do and dont’s

Further reading

in depth articles:

  • Boot and Startup procedures
  • Queued callbacks and interrupts
  • [[Display System Architecture|display_system_architecture]]
  • Touch System Architecture
  • Wifi & networking
  • Power Management Overview
  • Memory Management: Stack vs heap objects?
  • Coding C++ for bare metal
  • The Build System

Display System Architecture

Mono display system is makes it easy and fast to create graphical user interfaces (GUIs). You can take advantage of the many high-level classes, that display controls or text in the screen.

Who should read this?

In this article we will take an in-depth look at Mono’s display system. You should read this if you wish to create your own User Interface elements or if you experience issues related to displaying graphics. Also, if you simply would like to know more about how the software works under the hood. I presume you already are familiar with other GUI system programming, like iOS or Qt.

Overview

The Mono framework implements a display stack that closely assembles the first computer GUI systems, like the first Mac OS or Atari TOS. It is a single display buffer that your application paints in. The buffer is placed in the display chip, and is therefore not a part of the MCU systems internal RAM. This means writing (and reading) to the display buffer is expensive operations, and should only be done in an efficient way.

To paint on the display the view stack has 3 distinct layers:

  1. The Display controller: An object that communicates with the hardware display chip, and can read and write to the display buffer. The display controller objects can write pixels in an file I/O like manner. It does not have any notion of text glyphs or graphical shapes.
  2. The Display Painter: The painter object can translate geometrical shapes into pixels. It utilizes the Display Controller as a pixels drawing target. The painter can also draw individual text glyphs, and works with colors too.
  3. The Views: A view is an abstract class that represents a User Interface element, like a button. It uses the Display Painter to composite a complete element from a series of shape painting routines. Some views also works with touch input.

We shall only visit the last layer (Views) in this tutorial.

The Views

All UI element classes inherit from the View class. The view class defines the properties and behaviors shared by all UI elements. The mono framework comes with a set of predefined UI views that comprises different UI elements. They all in inherit from the View class, as seen on the figure below:

The UI elements view hierarchy, with touch responders

If you need learn about the specific UI classes can their usage, please see the reference documentation or the Drawing UI Elements tutorial.

As all classes inherit from the parent View class, they all define these central properties:

  • The View Rect: A rectangle that defines the boundaries of the view. This is the views width and height, but also its X,Y position on the display.
  • Standard Colors: All views share a palette of standard/default colors for borders, text, backgrounds and highlights. Changing one of these will affect all view subclasses.
  • Dirty state: Views can be dirty, meaning that they need to be repainted on the screen. You might change the content of a TextLabelView, and the view will need to be repainted - therefore it is dirty. When the view has been repainted, the dirty state is cleared.
  • Repainting: All View subclasses must define the protected method repaint(). Dirty views are scheduled for repaint by the display system, meaning that the repaint() method is automatically called to actually draw the view. If you create your own custom views, all your shape painting must happen inside the repaint() routine.
  • Visibility state: Views can be visible or invisible. When first created, a view is always invisible. This means it will not be scheduled for repaints at all. To make a view appear on the display, you must first call the show() method. This will set its state to visible.

Since all views share a single global display buffer, you can (by mistake or on purpose) position one view overlapping another. The display system does not have any notion of a Z-axis. To the top-most view will be the one that gets its repaint() method called last. The display system keeps dirty views in a queue, so they are repainted in a FIFO style manner.

When you create your own views, it is your responsibility to respect the views boundaries. Say, a view with the dimensions 100x100, must not draw any shapes outside its 100x100 rectangle. Shape drawing inside the repaint() method is not automatically clipped to the views bounding rectangle. It is perfectly possible to create a view, that completely ignores its bounding rectangle.

In contrast to many modern GUI systems, mono views cannot contain nested views. However, this does not mean a view cannot contain another. It just has to manually manage it.
Display Coordinate System

All views and painted shapes exists in the painter’s coordinate system. This coordinate system is cartesian with origin in the top left corner. The positive Y direction is downward, while positive X is left to right. The coordinates are in pixels, meaning they are integers.

Pixel position in coordinate system, for coordinate (1,1)

An example of the used coordinate system is seen in the figure above. Notice how the pixel’s coordinate references the upper left corner of the pixel area - not the center.

Because views cannot be nested, we use only one global coordinate system. It is called the absolute coordinate system, and all shapes and views are painted relative to that. This means that if you position views with the offset coordinate \((20,20)\), you must offset all shape painting with \((20,20)\).

Rotations

Mono includes an accelerometer, that enables you to detect orientation changes. You can create an application that layout its content differently in landscape and portrait modes.

Unfortunately, at this time, I have yet to implement an automatic coordinate system rotation, that uses the accelerometer. I plan to augment the Display Painter class with the ability to rotate the coordinate system, to account for mono physical orientation. This will mean the coordinate system’s origin will always be the upper left corner relative to gravity, and independent on the physical orientation.

Pixel Blitting

The display painter class takes commands like drawRect(x,y,w,h), that paints an outlined rectangle on the display. It handles conversion from geometric shape parameters, into a series of pixels. These pixels are written to the display through the Display Controller object.

The pixel color is determined by the state of the painter. The painter has foreground and background color, that can be set before the calls to shape drawing routines. Shapes are painted using the foreground color by default, but you can explicitly tell the routines to use the background color instead.

The text glyphs drawing routine uses both the foreground and background colors, to draw the text glyphs against the background color.

Bitmaps & Colors

The display painter cannot take pixels as input. If you need to draw raw pixels or bitmaps from a file or memory, you need to interface the Display Controller directly. The display controller has a cursor that points to a location on the display. When you write a pixel, the cursor increments. The incrementation is from left to right, and downward. (Normal western reading direction.)

Basically you need only to use 2 methods: write(color) and setCursor(x,y). You can see how if you take a look at the source code for the class ImageView. It blit pixels using the display controller, from within its repaint() method.

If you plan to use bitmaps, keep in mind that Mono’s memory is very limited. Therefore I will encourage you not to use large in-memory pixel buffers. Instead use the SD Card file I/O, as done by the ImageView class.

When you write raw pixels, you must use the correct pixel color format. For mono this is 16 bit, 5-6-5 RGB colors. Note that Mono’s CPU architecture is little endian, and the display uses big endian. If you define a color like this:

uint16_t color = 0x07E0; // I think this might be a green color?

The color will be interpreted by the display as: 0xE007. For convenience you should use the Color class, that has a constructor that takes RGB components as separate values.

V-Sync and refreshes

The display hardware periodically refreshes the LCD. If you change the display buffer during a refresh, you will see weird artifacts. Especially animations are prone to such artifacts.

To counter this mono uses tearing effect interrupts. This interrupt works like the v-sync signal on RGB interfaced displays. It occurs the moment after a display refresh. After the interrupt there is a time window, where the display buffer can be changed, before the display refreshes again.

Modern systems uses a technique called double buffering, where two separate display buffers exists. This means that one can be modified while the other is shown. When all changes has been written, the buffer that is displayed are changed to the other one. This technique makes it possible is to (slowly) write a lot of changes to the display, and have them appear instantly.

Unfortunately we do not have this facility in Mono. There is only one display buffer. This means all drawing must have finished, by the time the display is refreshed again. To not exceed the time window between display refreshes, all painting routines must be very efficient and optimized. If you create your own view subclasses, keep in mind that your drawing must be highly efficient. It is best only to paint changes, and not the entire view again.

The display system automatically handle this tearing effect timing, and skips repainting, should the CPU be too busy at the moment of the interrupt.

Bare Metal C++: A Practical Guide

If you what to be an embedded coding champ, you should really read Alex Robenko’s book: Practical Guide to Bare Metal C++ (and I mean: really!)

Alex’ book goes through very interesting topics of getting C++ runnning on embedded devices. It covers important shortcomings and advantages of C++ in an embedded environment.

If you know C++ you might want to use Exceptions and RTTI features, before you do: Read the book! In contrast, if you do not know C++ you might (will) make mistakes that can take hours to recover from. Again: Read the book!

Here is a short list of most interesting chapters of the book:

  • Dynamic Memory Allocation
  • Exceptions
  • RTTI
  • Removing Standard library
  • Static objects
  • Abstract classes
  • Templates
  • Event loops

As a Mono developer you will face most of these topics.

Read the Book

  • Queued callbacks and interrupts
  • Touch System Architecture
  • Wifi & networking
  • Boot and Startup procedures
  • Power Management Overview
  • Memory Management: Stack vs heap objects?
  • The Build System

Schematics

This is the schematics for our hardware. These are meant to help you develop our own extensions to Mono, go create!

If you need more specific schematics than what is shown here, please consider posting a request on our community.

Mono (Maker + Basic)

Mono functional schematic

PDF PNG

If you have a Mono Basic, it is the same as Maker, just without the Wifi / Bluetooth component mounted.

Mono Shield Adapter

Mono Shield Adapter functional schematic

PDF PNG

MonoKiosk

Mono apps are distributed through the Kiosk, and you can get your app into the Kiosk by following the recipe below.

GitHub

If your source code is hosted on GitHub, you will need to make a GitHub release and attach three types of files to the release, namely

  • The app description.
  • A set of screenshots.
  • The binary app itself.
App description

The release must contain a file named app.json that contains the metadata about your app, for example

{ "id":"com.openmono.tictactoe"
, "name":"Tic Tac Toe"
, "author":"Jens Peter Secher"
, "authorwebsite":"http://developer.openmono.com"
, "license":"MIT"
, "headline":"The classic 3x3 board game."
, "description":
  [ "Play with a fun and exciting game with against another player."
  , "Can you beat your best friend in the most classic of board games?"
  ]
, "binary":"ttt.elf"
, "sourceurl":"https://github.com/getopenmono/ttt"
, "required":["display","touch"]
, "optional":[]
, "screenshots":
  [ "tic-tac-toe-part1.png"
  , "tic-tac-toe-part2.png"
  , "tic-tac-toe-part3.png"
  ]
, "cover": "tic-tac-toe-part2.png"
, "kioskapi": 1
}

As you can see, app.json refers to three distinct images (tic-tac-toe-part1.png, tic-tac-toe-part2.png,tic-tac-toe-part3.png) to be used on the app’s page in MonoKiosk, so these three files must also be attached to the GitHub release. The metadata also refers to the app itself (ttt.elf), the result of you building the application, so that file must also be attached to the release.

The format of the metadata needs to be very strict, because it is used to automatically create an entry for your app in MonoKiosk. The metadata must be in JSON format, and the file must be named app.json. In the following, we will describe the format in detail.

id

The id must be unique within the Kiosk, so you should use reverse domain name notation like uk.homebrewers.brewcenter.

name

The name of the app as it should appear to people browsing the Kiosk.

author

Your name or Organisation, as it should appear to people browsing the Kiosk.

authorwebsite

An optional URL to your (organisation’s) website.

license

How other people can use your app and the source code. We acknowledges the following licenses:

If you feel that you need another license supported, take it up in the community.

headline

Your headline that accompanies the app on the Kiosk.

description

A list of paragraphs that give other people a detailed desription of the app, such as why they would need it and what it does.

binary

The name of the ELF file which has been produced by your compiler, and which you have attached to the release.

sourceurl

An URL to the source code of the app.

required

A list of hardware that must be present in a particular Mono to run the app. The acknowledged hardware is as follows.

  • accelerometer
  • buzzer
  • clock
  • display
  • jack
  • temperature
  • touch
  • wifi
  • bluetooth
optional

A list of Mono hardware that the app will make use of if present. The acknowledged hardware is the same as for the required list.

screenshots

A list of images that will be presented in the Kiosk alongside the app description.

All images must be either 176x220 or 220x176 pixes, and they must be attached to the release.

cover

One of the screenshots that you want as cover for app in the Kiosk.

kioskapi

The format of the metadata. The format described here is version 1.

How to get your app included

When you have created a new (version) of your app, you can contact us at kiosk@openmono.com with the URL of your release (eg. https://api.github.com/repos/getopenmono/ttt/releases/tags/v0.1.0), and we will do a sanity check of the app and add to the official list used by the Kiosk.

For GitHub, the url for a release is https://api.github.com/repos/:owner/:repo/releases/tags/:tag

Datasheets

If you need to dive a little deeper into the inner workings of Mono, we have collected the datasheets for the components in Mono

You might need to consult specific datasheets for the components in Mono, if you are debugging or just need some advanced features not provided by the API.

Accelerometer

Mono’s accelerometer is a MMA8652FC chip by Freescale. It is connected to Mono’s I2C bus.

MMA8652FC Accelerometer datasheet thumbnail
Download PDF

The accelerometer is handled by the MonoAccelerometer class in the software framework. If you need specific features, or just wish to play with the component directly, you should consult the datasheet.

MCU

Mono’s Micro Controller Unit (MCU) is a Cypress PSoC5LP, that is an Arm Cortex-M3 CPU. You can use all its registers and functions for your application, the SDK includes headers for all pins and registers. (You must explicitly include the project.h file.)

The MCU model we use has 64 Kb SRAM, 256 Kb Flash RAM and runs at 66 Mhz.

Cypress PSoC5 Technical Reference Manual thumbnail
Download PDF

The software framework encapsulates most MCU features in the mbed layer, such as GPIO, interrupts and timers. Power modes is also controlled by the registers in the MCU and utilized by the PowerManagement class.

Display Chip

The display is driven by an ILITEK 9225G chip. On mono we have hardwired the interface to 16 bit 5-6-5 color space and the data transfer to be 9-bit dedicated SPI, where the 9th bit selects data/command registers. (This should make sense, when you study the datasheet.)

Ilitek 9225G display driver specification thumbnail
Download PDF

In the framework the display controller class ILI9225G utilizes the communication and pixel blitting to the display chip.

Wireless

Mono uses the Redpine Wifi chip to achieve wireless communication. (The same chip includes Bluetooth for the Maker model, also.) The chip is connected via a dedicated SPI interface, and has a interrupt line connected as well.

Redpine WiseConnect Software Programming Reference Manual thumbnail
Download PDF

The communication interface is quite advanced, including many data package layers. You can find our implementation of the communication in the ModuleSPICommunication class. This class utilizes the SPI communication from and to the module, it does not know anything about the semantics of the commands sent.

Temperature Sensor

The temperature sensor is an Amtel AT30TS74 chip, connected via the internal I2C bus.

Redpine WiseConnect Software Programming Reference Manual thumbnail
Download PDF

The temperature interface is used in the AT30TS74Temperature class.

API Reference

Common Utilities

DateTime
class mono::DateTime

A Date and time representation in the Gregorian calendar.

This class represents a point in time, defined in the gregorian calendar. Such a timestamp are given in year, month, day of month, hours since midnight, minutes and seconds. This class also defined if the timestamp is in UTC / GMT or a defined local time zone.

The class handles leap years and the varying length of months. You can add seconds, minutes, hours and days to a DateTime object and get the result as a new DateTime object.

When you create DateTime objects they are created in the local time zone by default. The local time zone is defined as a offset in hours relative to UTC. There is no notion of IANA Time Zone names of alike - just an offset to the UTC time.

There are two convenient method to print DateTime as readable strings. The toString method print a human readable (MySql compatible) timestamp. The other toISO8601 returns a string formatted in the ISO 8601 standard format used in JSON objects.

When printing DateTime objects, they are returned in the time zone that they are created in.

System Wall Clock

This class also has a global DateTime object reserved for use by a RTC feature. A subsystem manages the RTC and increments the global system DateTime object.

You can get the current DateTime time by using the static method now To set the system clock use the static method setSystemClock

Public Types

enum TimeTypes

DateTime timestamps can be one of three types

Values:

LOCAL_TIME_ZONE

The DateTime is specified in local time zone

UTC_TIME_ZONE

The DateTime is specified in UTC / GMT time zone

UNKNOWN_TIME_ZONE

The DateTime do not have a specified time zone

Public Functions

DateTime()

Construct an empty / invalid DateTime object.

DateTime(const time_t t, bool localTimeZone = true)

Create a DateTime from the a libc simple time.

This constructor takes a standard lic time variable and create a calendar DateTime object from that. It uses the systems timezone, and libc systems time stamp to calendar conversion.

You can set the optional argument localTimeZone to false to force the DateTime to be created in UTC time, instead of system time.

Times is converted to a date in the Gregorian calendar.

Parameters
  • t: The libc simple time stamp
  • localTimeZone: Optional: Use the systems timezone in convertion

DateTime(const tm *brokentime, bool localTimeZone = true)

Create a DateTime from the a libc broken-down time struct.

This constructor takes a standard libc broken-downtime variable and creates a calendar DateTime object from that. It uses the timezone present in libc structure.

You can set the optional argument localTimeZone to false to force the DateTime to be created in UTC time, instead of system time.

Parameters
  • brokentime: The libc simple broken-down calendar time
  • localTimeZone: Optional: Use the systems timezone in convertion

DateTime(uint16_t years, uint8_t months, uint8_t days, uint8_t hours = 0, uint8_t minutes = 0, uint8_t seconds = 0, TimeTypes zone = LOCAL_TIME_ZONE)

Construct a DateTime object with a given date and time.

Parameters
  • years: The Year component of the date, for example 2016
  • months: The month component of the date from 1 to 12, May is 5
  • days: The day component of the date, 1-indexed, from 1 to 31
  • hours: Optional: The hour component of the timestamp, range is 0 to 23
  • minutes: The minute component of the timestamp, range is 0 to 59
  • seconds: The seconds component of the timestamp, range is 0 to 59
  • zone: The timezone where this DateTime define its time, default is the local timezone

String toString() const

Return the DateTime object as a huamn readable string.

Return
A mono string on the format: yyyy-MM-dd hh:mm:ss

String toISO8601() const

Return an ISO8601 formatted timestamp as a string.

This returned string is on the format: yyyy-MM-ddTHH:mm:ss+tt:00 if not UTC or yyyy-MM-ddTHH:mm:ssZ

String toRFC1123() const

Get the DateTime as an RFC1123 compatible date/time string.

This is the standard used by the HTTP standard and therefore used in HTTP headers like Date and Last-Modified. Use this method to format a DateTime to this representation.

String toTimeString() const

Return only a time string from the DateTime.

The format is: HH:mm:ss

String toDateString() const

Return only a date string from the DateTime.

The format is: yyyy-MM-dd

uint32_t toJulianDayNumber() const

Return Julian day number of the DateTime.

uint32_t toUnixTime() const

Return Unix time of the DateTime.

struct tm toBrokenDownUnixTime() const

Return a libc broken-down time/date compnents.

This uses the default timezone of the local systems time zone

time_t toLibcUnixTime() const

Returns the libc style timestamp (simple time)

bool isValid() const

Return true if the DateTime is valid.

Invalid date object is contructed by the default constructor

DateTime toUtcTime() const

Convert this DateTime to UTC time.

uint8_t Hours() const

Get the hour component, from 0 to 23.

uint8_t Minutes() const

Get the Minute component, from 0 to 59.

uint8_t Seconds() const

Get the Seconds component, from 0 to 59.

uint8_t Days() const

Get the day of month component, first day of month is 1.

uint8_t Month() const

Get the month component, January is 1, December 12.

uint16_t Year() const

Get the year component.

DateTime addSeconds(int seconds) const

Return a new object with a number of seconds added.

This method increments the timestamp for the given second interval

Return
The new DateTime object with seconds added
Parameters
  • seconds: The seconds to add

DateTime addMinutes(int minutes) const

Return a new object with a number of minutes added.

This method increments the timestamp for the given minute interval

Return
The new DateTime object with minutes added
Parameters
  • minutes: The minutes to add

DateTime addHours(int hours) const

Return a new object with a number of hours added.

This method increments the timestamp for the given hour interval

Return
The new DateTime object with hours added
Parameters
  • hours: The hours to add

DateTime addDays(int days) const

Return a new object with a number of days added.

This method increments the timestamp for the given day interval

Return
The new DateTime object with days added
Parameters
  • days: The days to add

DateTime addTime(const time_t *t) const

Return a new object with the Unix simple time component added.

The provided pointer to a unix time is added to the existing DateTime and the result is returned as a new object.

Return
The new DateTime object with the time interval added
Parameters
  • t: The unix simple time to add

String toString(const char *format) const

Format the DateTime to a string, using libc strftime function.

Use this method to get a custom representation of the date/time as text. You control the format of the output using the string at format. It can contain two kinds of specifications: text to be copied literally into the formatted string, and time conversion specifications. Time conversion specifications are two- and three-character sequences beginning with ‘’ (use ‘%’ to include a percent sign in the output). Each defined conversion specification selects only the specified field(s) of calendar time data from *timp, and converts it to a string in one of the following ways:

a The abbreviated weekday name according to the current locale. [tm_wday]

A The full weekday name according to the current locale. In the default “C” locale, one of ‘Sunday’, ‘Monday’, ‘Tuesday’, ‘Wednesday’, ‘Thursday’, ‘Friday’, ‘Saturday’. [tm_wday]

b The abbreviated month name according to the current locale. [tm_mon]

B The full month name according to the current locale. In the default “C” locale, one of ‘January’, ‘February’, ‘March’, ‘April’, ‘May’, ‘June’, ‘July’, ‘August’, ‘September’, ‘October’, ‘November’, ‘December’. [tm_mon]

c The preferred date and time representation for the current locale. [tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday]

C The century, that is, the year divided by 100 then truncated. For 4-digit years, the result is zero-padded and exactly two characters; but for other years, there may a negative sign or more digits. In this way, ‘Cy’ is equivalent to ‘Y’. [tm_year]

d The day of the month, formatted with two digits (from ‘01’ to ‘31’). [tm_mday]

D A string representing the date, in the form ‘”%m/%d/%y”’. [tm_mday, tm_mon, tm_year]

e The day of the month, formatted with leading space if single digit (from ‘1’ to ‘31’). [tm_mday]

Ex In some locales, the E modifier selects alternative representations of certain modifiers x. In newlib, it is ignored, and treated as x.

F A string representing the ISO 8601:2000 date format, in the form ‘”%Y-%m-%d”’. [tm_mday, tm_mon, tm_year]

g The last two digits of the week-based year, see specifier G (from ‘00’ to ‘99’). [tm_year, tm_wday, tm_yday]

G The week-based year. In the ISO 8601:2000 calendar, week 1 of the year includes January 4th, and begin on Mondays. Therefore, if January 1st, 2nd, or 3rd falls on a Sunday, that day and earlier belong to the last week of the previous year; and if December 29th, 30th, or 31st falls on Monday, that day and later belong to week 1 of the next year. For consistency with Y, it always has at least four characters. Example: “%G” for Saturday 2nd January 1999 gives “1998”, and for Tuesday 30th December 1997 gives “1998”. [tm_year, tm_wday, tm_yday]

h Synonym for “%b”. [tm_mon]

H The hour (on a 24-hour clock), formatted with two digits (from ‘00’ to ‘23’). [tm_hour]

I The hour (on a 12-hour clock), formatted with two digits (from ‘01’ to ‘12’). [tm_hour]

j The count of days in the year, formatted with three digits (from ‘001’ to ‘366’). [tm_yday]

k The hour (on a 24-hour clock), formatted with leading space if single digit (from ‘0’ to ‘23’). Non-POSIX extension (c.p. I). [tm_hour]

l The hour (on a 12-hour clock), formatted with leading space if single digit (from ‘1’ to ‘12’). Non-POSIX extension (c.p. H). [tm_hour]

m The month number, formatted with two digits (from ‘01’ to ‘12’). [tm_mon]

M The minute, formatted with two digits (from ‘00’ to ‘59’). [tm_min]

n A newline character (‘ ’).

Ox In some locales, the O modifier selects alternative digit characters for certain modifiers x. In newlib, it is ignored, and treated as x.

p Either ‘AM’ or ‘PM’ as appropriate, or the corresponding strings for the current locale. [tm_hour]

P Same as ’p’, but in lowercase. This is a GNU extension. [tm_hour]

r Replaced by the time in a.m. and p.m. notation. In the “C” locale this is equivalent to “%I:%M:%S %p”. In locales which don’t define a.m./p.m. notations, the result is an empty string. [tm_sec, tm_min, tm_hour]

R The 24-hour time, to the minute. Equivalent to “%H:%M”. [tm_min, tm_hour]

S The second, formatted with two digits (from ‘00’ to ‘60’). The value 60 accounts for the occasional leap second. [tm_sec]

t A tab character (‘’).

T The 24-hour time, to the second. Equivalent to “%H:%M:%S”. [tm_sec, tm_min, tm_hour]

u The weekday as a number, 1-based from Monday (from ‘1’ to ‘7’). [tm_wday]

U The week number, where weeks start on Sunday, week 1 contains the first Sunday in a year, and earlier days are in week 0. Formatted with two digits (from ‘00’ to ‘53’). See also W. [tm_wday, tm_yday]

V The week number, where weeks start on Monday, week 1 contains January 4th, and earlier days are in the previous year. Formatted with two digits (from ‘01’ to ‘53’). See also G. [tm_year, tm_wday, tm_yday]

w The weekday as a number, 0-based from Sunday (from ‘0’ to ‘6’). [tm_wday]

W The week number, where weeks start on Monday, week 1 contains the first Monday in a year, and earlier days are in week 0. Formatted with two digits (from ‘00’ to ‘53’). [tm_wday, tm_yday]

x Replaced by the preferred date representation in the current locale. In the “C” locale this is equivalent to “%m/%d/%y”. [tm_mon, tm_mday, tm_year]

X Replaced by the preferred time representation in the current locale. In the “C” locale this is equivalent to “%H:%M:%S”. [tm_sec, tm_min, tm_hour]

y The last two digits of the year (from ‘00’ to ‘99’). tm_year

Y The full year, equivalent to Cy. It will always have at least four characters, but may have more. The year is accurate even when tm_year added to the offset of 1900 overflows an int. [tm_year]

z The offset from UTC. The format consists of a sign (negative is west of Greewich), two characters for hour, then two characters for minutes (-hhmm or +hhmm). If tm_isdst is negative, the offset is unknown and no output is generated; if it is zero, the offset is the standard offset for the current time zone; and if it is positive, the offset is the daylight savings offset for the current timezone. The offset is determined from the TZ environment variable, as if by calling tzset(). [tm_isdst]

Z The time zone name. If tm_isdst is negative, no output is generated. Otherwise, the time zone name is based on the TZ environment variable, as if by calling tzset(). [tm_isdst]

%% A single character, ‘’.

Public Static Functions

static DateTime maxValue()

Get the maximum possible DateTime value (far in the future)

static DateTime minValue()

Get the lowest possible DateTime value (the distant past)

bool isLeapYear(uint16_t year)

Check is a year is a leap year.

DateTime fromISO8601(String date)

Parse a subset of ISO 8601 compatible date time representations.

This static method takes a ISO 8601 formatted string, and creates a DateTime object from that. This method only parses a subset of the possible date representations allowed in ISO 8601. Specifically it can handle dates in these format:

  • yyyy-MM-ddTHH:mm:ssZ
  • yyyy-MM-ddTHH:mm:ss+01:00 or other time zones
  • yyyy-MM-dd HH:mm:ssZ
  • yyyy-MM-dd HH:mm:ss

Return
The parsed DateTime object, that might be valid or invalid

void setSystemDateTime(DateTime dt)

Set a new system DateTime.

DateTime now()

Get the current DateTime from the system RTC clock.

void incrementSystemClock()

Internal method used by the RTC system to increment the system DateTime. You should not call this manually.

Public Static Attributes

int LocalTimeZoneHourOffset = 0

The systems current TimeZone setting.

The timezone is just an hour-offset from the UTC / GMT time

PowerSaver
class mono::PowerSaver

Auto dim the display and sleep Mono after a given period of inactivity.

This class will automatically dim the display and enter sleep mode, after a period of user inactivity. The uses 3 states:

  1. Normal mode (full brightness on display)
  2. After a period of no user touch input (default 10 secs.), display dims to 11%
  3. After yet a period (default 10 secs.) of no touch input, sleep mode is entered.

Any touch input will reset the state to 1.

You should add this objact to your AppController class, to enable automatic power saving.

Multiple PowerSavers

If you want to use multiple instances of this class, remember to deactivate the instances that should be inactive. Having two active instances at one time, can be confusing to the users.

Catch-all Touches

TO capture all touches, any instane should be the first to respond to touch inputs. The touch system has a responder chain of objects that handles touch input. Any of these objects might choose to break the chain and allow no further processing of a given touch event.

Therefore the PowerSaver must be the first (or one of) to handle touch events. You accomplish this by initializing the PowerSaver object as the first member object of your AppController. Before any other touch related classes.

Inherits from mono::TouchResponder

Public Functions

PowerSaver(int dimTimeoutMs = 10000, int sleepTimeoutMs = 10000, int dimBrightness = 30, int fullBrightness = 255)

Construct a auto dimmer and sleep timer.

Parameters
  • dimTimeoutMs: The delay before display is dimmed (in milliseconds)
  • sleepTimeoutMs: The delay before sleep mode is entered (in milliseconds)
  • dimBrightness: The brightness level when display is dimmed (0 to 255)
  • fullBrightness: The full brightness level (normal mode) (0 to 255)

void startDimTimer()

Starts the timer that will dim the display after the chosen timeout.

This call stops any running sleep timer. After the dim timer fires, the sleep timer is automatically started.

void startSleepTimer()

Starts the sleep timer, that will sleep Mono after the chson timeout.

This will stop a running dim timer, and trigger sleep mode on timeout.

void dim()

Immidiately dim the display and then start the sleep timer.

This will (asynchronously) dim the display to the chosen brightness level. WHen the display has been dimmed, the sleep timer is started.

void undim()

Immidiately undim the display to full brightness.

This will stop the sleep timer and re-start the dim timer.

void deactivate()

Disable the PowerSaver all together.

No dimming or sleep is triggered. You must call startDimTimer to re-enabled the PowerSaver.

Queue
class mono::Queue

A pointer based FIFO style Queue.

See
GenericQueue

Subclassed by mono::GenericQueue< mono::redpine::ManagementFrame >, mono::GenericQueue< mono::ScheduledTask >, mono::GenericQueue< mono::TouchResponder >, mono::GenericQueue< mono::ui::View >, mono::GenericQueue< Item >

Public Functions

void Enqueue(IQueueItem *item)

Add a new element to the back of the queue Insert a pointer to an element on the back of the queue.

IQueueItem *Dequeue()

Returns and removes the oldest element in the queue.

IQueueItem *Peek()

Return the oldest element in the queue, without removing it.

IQueueItem *Next(IQueueItem *item)

Get the next element in the queue, after the one you provide.

NOTE: There is no check if the item belongs in the parent queue at all!

Return
The next element in the queue, after the item you provided.
Parameters
  • item: A pointer to an item in the queue

bool Exists(IQueueItem *item)

Check that an object already exists in the queue. Because of the stack based nature of this queue, all objects can only exist one replace in the queue. You cannot add the same object to two different positions in the queue.

Parameters
  • item: The element to search for in the queue

QueueInterrupt
class mono::QueueInterrupt

An queued input pin interrupt function callback handler This class represents an input pin on mono, and provides up to 3 different callback handler functions. You can installed callback function for rising, falling or both edges.

Queued interrupts

In Mono framework a queued interrupt is handled inside the normal execution context, and not the hardware interrupt routine. In embedded programming it is good practice not to do any real work, inside the hardware interrupt routine. Instead the best practice method is to set a signal flag, and handled the event in a run loop.

QueueInterrupt does this for you. The rise, fall and change callback are all executed by the default mono run loop (AppRunLoop) You can safely do heavy calculations or use slow I/O in the callback routines you assign to QueueInterrupt!

Latency

The run loop might handle the interrupt callback some time after it occur, if it is busy doing other stuff. THerefore you cannot expect to have your callback executed the instant the interrupt fires. (If you need that use DirectInterrupt) QueueInterrupt holds the latest interrupt trigger timestamp, to help you determine the latency between the actual interrupt and you callback. Also, many interrupt triggering signal edges might occur, before the run loop executes you handler. The timestamp only shows the latest one.

Inherits from InterruptIn, mono::IRunLoopTask

Public Functions

QueueInterrupt(PinName inputPinName = NC, PinMode mode = PullNone)

Assign a queued inetrrupt handler to a physical pin

Parameters
  • inputPinName: The actual pin to listen on (must be PORT0 - PORT15)
  • mode: OPTIONAL: The pin mode, default is Hi-Impedance input.

void DeactivateUntilHandled(bool deactive = true)

Set this property to true, to turn off incoming interrupts while waiting for the run loop to finish process a pending interrupt.

If you want to do heavy calculations or loading in your interrupt function, you might want to not queue up new interrupts while you process a previous one.

Parameters
  • deactive: OPTIONAL: Set this to false, to not disable interrupts while processing. Default is true

bool IsInterruptsWhilePendingActive() const

Get the state of the DeactivateUntilHandled property. If true the hardware interrupt is deactivated until the handler has run. If false (the default when constructing the object), all interrupt are intercepted, and will be handled. This means the handler can be executed two times in row.

Return
true if incomming interrupt are displaed, until previous is handled.

void setDebouncing(bool active)

Enable/Disable interrupt de-bounce.

Switches state change might cause multiple interrupts to fire, or electrostatic discharges might cause nano seconds changes to I/O lines. The debounce ensures the interrupt will only be triggered, on sane button presses.

void setDebounceTimeout(int timeUs)

Change the timeout for the debounce mechanism.

Parameters
  • timeUs: The time from interrupt to the signal is considered stable, in micro-seconds

void rise(void (*fptr)(void))

Attach a function to call when a rising edge occurs on the input

Parameters
  • fptr: A pointer to a void function, or 0 to set as none

template <typename T>
void mono::QueueInterrupt::rise(T * tptr, void(T::*)(void) mptr)

Attach a member function to call when a rising edge occurs on the input

Parameters
  • tptr: pointer to the object to call the member function on
  • mptr: pointer to the member function to be called

void fall(void (*fptr)(void))

Attach a function to call when a falling edge occurs on the input

Parameters
  • fptr: A pointer to a void function, or 0 to set as none

template <typename T>
void mono::QueueInterrupt::fall(T * tptr, void(T::*)(void) mptr)

Attach a member function to call when a falling edge occurs on the input

Parameters
  • tptr: pointer to the object to call the member function on
  • mptr: pointer to the member function to be called

uint32_t FallTimeStamp()

On fall interrupts, this is the µSec. ticker timestamp for the falling edge inetrrupt. You can use this to calculate the time passed from the interrupt occured, to the time you process it in the application run loop.

Return
The ticker time of the falling edge in micro seconds

uint32_t RiseTimeStamp()

On rise interrupts, this is the µSec. ticker timestamp for the rising edge inetrrupt. You can use this to calculate the time passed from the interrupt occured, to the time you process it in the application run loop.

Return
The ticker time of the rising edge in micro seconds

bool Snapshot()

The pin value at the moment the H/W interrupt triggered The callback might be executed some time after the actual inetrrupt occured. THis method return the pin state at the moment of the interrupt.

Return
The pin state, at the time of the interrupt

bool willInterruptSleep() const

Interrupt will abort sleep mode to run handler.

If interrupt fires during sleep mode, Mono will wake up to service the handler in the run loop

void setInterruptsSleep(bool wake)

Set if this interrupt will wake Mono from sleep.

Set to true to wake from sleep and continue the run loop upon interrupts.

Parameters
  • wake: true to enabled wake-from-sleep

template <typename T>
void mono::QueueInterrupt::change(T * tptr, void(T::*)(void) mptr)

Attach a member function to call when a rising or falling edge occurs on the input

Parameters
  • tptr: pointer to the object to call the member function on
  • mptr: pointer to the member function to be called

Protected Functions

void taskHandler()

This is the method that gets called by the run loop.

NOTE that this is not an interrupt function, you can do stuff that take some time.

Regex
class mono::Regex

This class is a C++ wrapper around the C library called SLRE (Super Lightweight Regular Expressions)

Pattern syntax

(?i) Must be at the beginning of the regex. Makes match case-insensitive ^ Match beginning of a buffer $ Match end of a buffer () Grouping and substring capturing \s Match whitespace \S Match non-whitespace \d Match decimal digit \n Match new line character \r Match line feed character \f Match form feed character \v Match vertical tab character \t Match horizontal tab character \b Match backspace character + Match one or more times (greedy) +? Match one or more times (non-greedy) * Match zero or more times (greedy) *? Match zero or more times (non-greedy) ? Match zero or once (non-greedy) x|y Match x or y (alternation operator) \meta Match one of the meta character: ^$().[]*+?|\ \xHH Match byte with hex value 0xHH, e.g. [...] Match any character from set. Ranges like [a-z] are supported [^...] Match any character but ones from set

https://github.com/cesanta/slre

Public Types

typedef slre_cap Capture

Regex Match capture object holding the first match capture

See
Regex

Public Functions

Regex(String pattern)

Create a regular expression object from a pattern string

bool IsMatch(String matchStr)

Test if a string matches the regex pattern

Return
true on match, false otherwise

bool Match(String matchStr, Capture *captureArray, uint32_t capArraySize)

Get a the first capture group match from a string

The Regex class does not allocate any capure objects, so you must supply all needed objects for captures.

Regex::Capure caps[3];
Regex reg("(..) (..) (..)");
bool success = reg.Match("test my regex", caps, 3);

Return
true on match, false otherwise
Parameters
  • matchStr: The string to match against the regex pattern
  • captureArray: A pointer to a array of Capture objects
  • capArraySize: The size of the provided capture array

String Value(Capture &cap)

Return the string value from a match capture object

String
class mono::String

High level string class, that is allocated on the HEAP or rodata

The mono framework has it own string class, that either reside on the HEAP or inside the read-only data segment (.rodata).

We use this string class to pass string data to async routines like the View ‘s scheduleRepaint method. Because views might be repainted at any point in time, we cannot have view data reside on the stack. This string class hold its data on the HEAP, but behaves as it would reside on the stack.

THis string class takes care of all alloc and dealloc of memory. It is a referenced based string class. You should not pass pointers of C++ references to this class, but instead normal assignment or pass the full class to functions. The efficient copy / assignment operator methods on the class ensure only data references are passed, behind the scenes.

For example:

String str = String::Format("Hello World, number: %i", 1);
String str2 = str;
String str3 = str2;

In the code only 1 copy of the string data is present in memory. And only references are passed to the objects str2 and str3. Only as the last object is deallocated is the data disposed from the HEAP.

These features makes the class very lightweight and safe to pass around functions and objects.

Subclassed by mono::network::Url

ScheduledTask
class mono::ScheduledTask

Schedule function a call at a point in the future using the RTC.

A SchdueldTask is a wrapper around a function call that is scheduled some time in the future. You create a task by defining a function to be called, and a DateTime on when it should be called.

A ScheduledTask differs from Timer by not being repetitive by nature. Also, the time resolution on is seconds, not milliseconds as on Timers.

An advantage of scheduled tasks is they can execute in sleep mode. They have the ability to wake Mono from sleep, either completely or just to execute simple house keeping code inside the sleep mode state!

Scheduled tasks rely on the RTC system to execute. They use the global system DateTime object to execute when they are due. A ScheduledTask executes once. If you wish to re-scedule the task at a new point in the future, use the method reschedule.

Execution in Sleep Mode

You can opt-in to allow your task to run in sleep mode. This means Mono’s CPU wake up and executes your task’s callback function. You enabled sleep mode execution by:

ScheduledTask task(DateTime::now().addMinutes(30));
task.setRunInSleep(true);
task.setTask<MyClass>(this, &MyClass::myCallback);

The function is executed without exiting the frameworks sleep state. This means the auxillary power is not enabled. (Display, Wireless chip and sensors are off.) Inside you callback function you can do small lightweight tasks, and when your function returns Mono re-enter the sleep state.

Wake-up from a task

If you want to wake Mono from sleep, you must indicate to the IPowerManager that sleep mode should be exited. This is done by setting the flag:

IApplicationContext::Instance->PowerManager->__shouldWakeUp = true;

This will trigger a full wake-up, just as toggling the user button does.

RTC must run

Scheduled tasks will not work if the RTC system is not started. This system is automatically started on reset, so the system is enabled by default.

Just like Timer you are not guaranteed to have you function executed at the exact moment defined by the DateTime provided. The guarantee is that your function will not be executed before the provided time stamp.

Inherits from mono::IQueueItem

Public Functions

ScheduledTask()

Consrtuct an empty (non-executable) Task.

You must provide a callback function and reschedule the task using the accessors in subsequent calls.

ScheduledTask(const DateTime &scheduledTime)

Construct a task that is due at a provided time stamp.

Create a ScheduledTask that is due on the given DateTime, which must be in the future. You must also provide the callback function using the setTask method.

Parameters
  • scheduledTime: The point in the future where the task should run

void reschedule(const DateTime &newTime)

Reschedules the task at a new point in the future.

Tasks only executes once. To enable re-ocurring tasks, use this method to schedule the task again.

Parameters
  • newTime: The new point in the future where the task is run again

bool willRunInSleep() const

Get is this task will execute in sleep mode.

void setRunInSleep(bool run)

Allow this task to run in sleep mode.

If you set this to true the task will execute in sleep mode. Note that it does not abort sleep (wake up), it execute inside the sleep mode.

Task that do not run in sleep are executed ASAP after wake-up.

Parameters
  • run: true if the task can run in sleep, false otherwise

template <typename Class>
void mono::ScheduledTask::setTask(Class * context, void(Class::*)(void) memptr)

Set the tasks callback function.

Here you provide the function that is called when the task is scheduled

Parameters
  • context: The this pointer or object instance
  • memptr: A pointer to a member method on a class

Public Static Functions

void processScheduledTasks(bool isSleeping = false)

System routine of run any due scheduled task.

the RTC system automatically calls this method, you should not call it yourself.

bool pendingScheduledTasks(bool inSleep = false)

Returns true if there are scheduling tasks pending for processing.

This means a running task has timed out and are ready to have its handler called. tasks with no callback handler are not regarded as pending.

Parameters
  • inSleep: If this static method is called from inside sleep mode, set to true

Protected Functions

void runTask(bool inSleep = false)

Execute the tasks callback function

bool isDue() const

Return true if the tasks time stamp has been reached

Protected Static Attributes

GenericQueue<ScheduledTask> queue

The global singleton queue of pending tasks

Timer
class mono::Timer

A queued Timer class, recurring or single shot.

A timer can call a function at regular intervals or after a defined delay. You can use the timer to do periodic tasks, like house-keeping functions or display updates.

Queued callback

The timer uses the Application Run Loop to schedule the callback handler function. This means your callback are not executed inside a hardware interrupt context. This is very convenient since your can do any kind of heavy lifting in your callback handler, and your code is not pre-empted.

Presicion

You should note that the timer are not guaranteed to be precisely accurate, it might fire later than your defined interval (or delay). The timer will not fire before your defined interval though. If you use any blocking wait statements in your code, you might contribute to loss in precision for timers.

If you want precise hardware timer interrupts consider the mbed Ticker class, but you should be aware of the hazards when using hardware interrupts.

Example

Create a reocurring timer that fires each second:

Timer timr(1000);
timr.setCallback<MyClass>(this, &MyClass::callback);
timr.Start();

The member function callback will now be called every second. If you want to use a single shot callback with a delay, Timer has a convenience static function:

Timer delay = Timer::callOnce<MyClass>(100, this, &MyClass::callback);

Now delay is a running timer that calls callback only one time. Note that the timer object (delay) should not be deallocated. Deallocating the object will cause the timer to shut down.

Time slices

Say you set an interval of 1000 ms, and your callback takes 300 ms to execute. Then timer will delay for 700 ms and not 1000 ms. It is up to you to ensure your callback do not take longer to execute, than the timer interval.

Inherits from mono::IRunLoopTask

Public Functions

Timer()

Contruct an empty (zero-timeout) re-occurring timer.

After calling this contructor, you must set the time out and callback function. Then start the timer.

Timer(uint32_t intervalOrTimeoutMs, bool snglShot = false)

Create a new timer with with an interval or timeout time.

All newly created timers are stopped as default. You must also attach callback handler to the timer, before it can start.

Parameters
  • intervalOrTimeoutMs: The timers time interval before it fires, in milliseconds
  • snglShot: Set this to true if the timer should only fire once. Default false

void start()

Start the timer and put into running state.

Note: You must set a callback handler, before starting the timer.

void Start()

void stop()

Stop the timer, any pending callback will not be executed.

void Stop()

bool SingleShot() const

See if the timer is single shot.

bool Running() const

See if the timer is currently running

void setInterval(uint32_t newIntervalMs)

Set a new timer interval.

Parameters
  • newIntervalMs: The timer interval in milliseconds

template <typename Owner>
void mono::Timer::setCallback(Owner * obj, void(Owner::*)(void) memPtr)

Sets a C++ callback member function to the timer.

Parameters
  • obj: A pointer to the callback member function context (the this pointer)
  • memPtr: A pointer to the member function, that is the callback

void setCallback(void (*cFunction)(void))

Sets a callback handler C function to the timer.

Parameters
  • cFunction: A pointer to the C function, that is the callback

Public Static Functions

template <typename Owner>
static Timer* mono::Timer::callOnce(uint32_t delayMs, Owner * obj, void(Owner::*)(void) memPtr)

Create a single shot timer with a delay and callback function.

The timer object is created on the HEAP, which allows it to exists across stack frame contexts. You can safely create a callOnce(...) timer, and return from a function. Even if you do not have a reference to the timer object, it will still run and fire. The timer deallocates itself after it has fired. It cannot be reused.

Return
A pointer to the single shot timer
Parameters
  • delayMs: Delay time before the timer fires, in milliseconds.
  • obj: A pointer to the callbacks function member context (the this pointer)
  • memPtr: A pointer to the callback member function

static Timer *callOnce(uint32_t delayMs, void (*memPtr)(void))

Create a single shot timer with a delay and callback function.

The timer object is created on the HEAP, which allows it to exists across stack frame contexts. You can safely create a callOnce(...) timer, and return from a function. Even if you do not have a reference to the timer object, it will still run and fire. The timer deallocates itself after it has fired. It cannot be reused.

Return
A pointer to the single shot timer
Parameters
  • delayMs: Delay time before the timer fires, in milliseconds.
  • memPtr: A pointer to the callback C function

Protected Functions

void taskHandler()

This is the method that gets called by the run loop.

NOTE that this is not an interrupt function, you can do stuff that take some time.

Core Classes

AppRunLoop
class mono::AppRunLoop

This is the event run-loop for all mono applications. This class is instantiated and used inside the IApplicationContext interface. You should not interact with this class directly.

The run loop handles non-critical periodicly tasks. Classes can install tasks in the run-loop. Such classes are usually repetitive timers or lazy interrupt handlers.

Some standard system tasks are handled staticly inside the loop, like the USB serial reads.

Public Functions

void exec()

Start executing the run loop.

void CheckUsbDtr()

Do a single check of the DTR on the virtual UART.

bool addDynamicTask(IRunLoopTask *task)

Add a task to the dynamic task queue. This task is repeated over and over, until it reports that its should not be scheduled.

The task is added to a linked list, runtime is n.

Return
Always true at this point

bool removeDynamicTask(IRunLoopTask *task)

Remove a task from the dynamic task queue. This will search the queue for he pointer provided, and remove it.

Return
true if the object was found and removed, false otherwise.
Parameters
  • task: A pointer to the object, that should be removed

void setResetOnUserButton(bool roub)

Sets the Reset on User Button mode.

If true the run loop will check the user button, and if pressed it will trigger a software reset.

Parameters
  • roub: true will reset on user button, false is normal functionality.

void quit()

Terminate the run loop. Application events and more will stop working

You should use this, if you use your own embedded run loops.

Public Members

bool resetOnDTR

As default behaviour the run loop will force a reset on high-to-low transition on the serial ports DTR (Data Terminal Ready) line.

This property controls this feature, setting it to true will enable software reset via the serial connection. This means the monoprog programmer can reset the device and connect to the bootloader.

Setting this to false means monoprog cannot automatically reset into the bootloader, you must press the reset button yourself.

uint32_t TouchSystemTime

The CPU time used on proccessing touch input. This includes:

  • ADC sampling (approx 16 samples)
  • Touch value evaluation, and possible convertion into events
  • Traversing the responder chain
  • Handling TouchBegin, TouchEnd & TouchMove, and any function they call

This time includes the execution of your code if you have any button handlers or touch based event callbacks.

uint32_t DynamicTaskQueueTime

The CPU time used on processing the dynamic task queue The time spend here include all queued tasks and callbacks. these could be:

  • Timer callback
  • Any QueueInterrupt you might have in use
  • All display painting routines (repainting of views subclasses)
  • Any custom active IRunLoopTask you might use

Nearly all callbacks are executed with origin inside the dynamic task queue. Expect that the majority of your code are executed here.

Protected Functions

bool runLoopActive mono::AppRunLoop::__DEPRECATED("Will be removed in future releases", "")

As long as this is true the stadard run loop will run

If set to false, the run loop will exit and main() will return, which you should absolutely not do!.

void processDynamicTaskQueue()

Execute all tasks in the dynamic task queue

void removeTaskInQueue(IRunLoopTask *task)

Internal method to sow together neightbourghs in the linked list

void process()

Process a single iteration of the run loop

void checkUsbUartState()

read the UART DTR state if possible

Protected Attributes

bool lastDtrValue

The last seen serial DTR value. Reset can only happen in transitions.

bool resetOnUserButton

Set to true if you want the run loop to call software reset when pressing the user button. Initial value is false

IRunLoopTask *taskQueueHead

A pointer to the head task of the dynamic task queue. If no task are in the queue, this is NULL

GenericQueue
template <typename Item>
class mono::GenericQueue

A templated Queue, where template defines the queue element type.

This class is identical to Queue, but it uses templating to preserve type information.

See
Queue

Inherits from mono::Queue

IApplication
class mono::IApplication

Entry point for all mono applications, abstract interface.

Every mono application must implement this interface. This is the starting point of the your application code, you must call it after the runtime initalization.

You do this from inside the main() function. Your main function should look like this:

int main()
{
     // Construct you IApplication subclass
     MyIApplicationSubclass appCtrl;
     
     // Tell the IApplicationContext of your existance
     IApplicationContext::Instance->setMonoApplication(&appCtrl);

     // Start the run loop... - and never come back! (Gollum!, Gollum!)
     return appCtrl.enterRunLoop();
}

Your mono applications entry point must be your own subclass of IApplication. And you must initalize it inside (not outside) the main() function. This is strictly nessesary, because the IApplicationContext must be ready when the IApplication is executed.

Also you must call the enterRunLoop method from main, to enter the event loop and prevent main() from returning.

Public Functions

IApplication()

Construct the global Application class.

Constructor for the global Application Controller. See IApplication for a describtion on when to call this constructor.

virtual void monoWakeFromReset() = 0

Called when mono boot after having been power off or after a reset This method is only called once, you should use it to do inital data and object setup.

When this method returns mono will enter in an event loop, so use this method to setup event listeners for your code.

Do not call this method yourself, it is intended only to be called by the mono framework runtime.

virtual void monoWillGotoSleep() = 0

The runtime library calls this function when the MCU will go into standby or sleep mode. Use this method to disconnect from networks or last-minute clean ups.

When you return from this method the system will goto sleep, and at wakeup the monoWakeFromSleep() method will be called automatically.

Do not call this method yourself, it is ontended only to be called by the mono framework runtime.

virtual void monoWakeFromSleep() = 0

Called when mono comes out of a standby or sleep state, where the MCU instruction execution has been paused.

Use this method to reestablish I/O connections and refresh data objects.

You should not call this method your self, it is intended only to be called by the mono framework runtime.

int enterRunLoop()

Start the mono application run loop.

Start the main run loop for your mono application. This method calls the global IApplicationContext run loop.

The last line in the main.cpp file must be a call to this function:

int main()
{
    MyIApplicationSubclass appCtrl;

    // Some app ctrl setup code here perhaps?
    
    return appCtrl.enterRunLoop();
}

Return
The run loop never returns, the return type is only for comformaty.

IApplicationContext
class mono::IApplicationContext

The Application context class is a singleton class that is automatically instanciated by the framework. You should not need to interact with it directly. It is allocated on the stack, with its member objects.

The application context controls the application event loop at hardware event inputs. It is essential for communicating with Serial-USB and the display.

Depending on the execution context (hardware mono device or simulator), different subclasses of this interface it used. This interface is provided to give your application code a pointer to the concrete implementation of the application context. Regardless of running on a simulator or the actual device.

Subclassed by mono::ApplicationContext

Public Functions

virtual int exec() = 0

Start the application run loop.

This method starts the global run/event loop for the mono application. The method never returns, so a call to this function should be the last line in your main() function.

The event loop automatically schedules the sub system, such as the network, inputs and the display.

virtual void setMonoApplication(mono::IApplication *app) = 0

Sets a pointer to the mono application object

Public Members

power::IPowerManagement *PowerManager

A pointer the power management system.

Pointer to the global power management object, that controls power related events and functions. Use this pointer to go into sleep mode’ or get the current battery voltage level.

AppRunLoop *RunLoop

A reference to the main run loop of the application. This pointer must be instanciated be subclasses

display::IDisplayController *DisplayController

Pointer to the display interface controller object. The object itself should be initialized differntly depending on the ApplicationContext

ITouchSystem *TouchSystem

Pointer to the touch system controller object.

The touch system handles touch input from the display or other input device. It must be initialized by an ApplicationContext implementation.

The touch system is the source of TouchEvent and delegate these to the TouchResponder classes. It is the ITouchSystem holds the current touch calibration. To re-calibrate the touch system, you can use this reference.

See
ITouchSystem

QueueInterrupt *UserButton

The User Button queued interrupt handler.

Here you add your application handler function for mono user button. To handle button presses you can set a callback function for the button push.

The callback function is handled in the AppRunLoop, see the QueueInterrupt documentation for more information.

Note that the default initialized callback handler will toggle sleep mode. This means that if you do not set your own handler, the user button will put mono into sleep mode. The default callback is set on the .fall(...) handler.

Example for replacing the user button handler, with a reset handler:

// the button callback function
void MyApp::handlerMethod()
{
    IApplicationContext::SoftwareReset();
}

// on reset install our own button handler callback
void MyApp::monoWakeFromReset()
{
    IApplicationContext::Instance->UserButton->fall<MyApp>(this, &MyApp::handlerMethod);
}

sensor::ITemperature *Temperature

A pointer to the Temperatrure sensor, if present in hardware.

This is an automatically initialized pointer to the temperature object, that is automatically created by the framework.

sensor::IAccelerometer *Accelerometer

A pointer to the Accelerometer, if present in hardware.

This is an automatically initialized pointer to the accelerometer object, that is automatically created by the framework.

sensor::IBuzzer *Buzzer

A pointer to the buzzer, if present in hardware.

This is an automatically initialized pointer to the buzzer object, that is automatically created by the framework.

IRTCSystem *RTC

A Pointer to the current RTC interface, if such exists.

Mono has a RTC clock, that can control a system date time clock, that is accessed by the DateTime class

You can start or stop the RTC using this interface. Note that this pointer might be NULL

Public Static Functions

static void EnterSleepMode()

The mono application controller should call this to give the Application Context a reference to itself.

This will ensure the Application Controllers methods gets called. Call this method to make mono goto sleep.

In sleep mode the CPU does not excute instruction and powers down into a low power state. The power system will turn off dynamically powered peripherals.

NOTE: Before you call this method make sure that you configured a way to go out of sleep.

static void ResetOnUserButton()

Enable Reset On User Button mode, where user button resets mono.

If your application encounters unmet dependencies (missing SD Card) or gracefully handles any runtime errors, you can call this method. When called, the run loop will reset mono if the user button (USER_SW) is activated.

This method allows you to reset mono using the user button, instead of the reset button.

static void SleepForMs(uint32_t ms)

Enter MCU sleep mode for a short time only. Sets a wake-up timer us the preferred interval, and calls the EnterSleepMode method.

Parameters
  • ms: The number of milli-second to sleep

static void SoftwareReset()

Trigger a software reset of Mono’s MCU.

Calls the MCU’s reset exception, which will reset the system. When reset the bootloader will run again, before entering the application.

static void SoftwareResetToApplication()

Trigger a software reset of MOno’s MCU, that does not load the bootloader.

Use this to do a fast reset of the MCU.

static void SoftwareResetToBootloader()

Trigger a software reset, and stay in bootloader.

Calls the MCU reset exception, which resets the system. This method sets bootloader parameters to stay in bootloader mode.

CAUTION: To get out of bootloader mode you must do a hard reset (by the reset button) or program mono using monoprog.

Public Static Attributes

IApplicationContext *Instance = NULL

Get a pointer to the global application context

Protected Functions

virtual void enterSleepMode() = 0

Subclasses should overirde this method to make the sysetm goto sleep

virtual void sleepForMs(uint32_t ms) = 0

Subclasses should override this to enable sleep mode for a specefic interval only.

virtual void resetOnUserButton() = 0

Subclasses must implement this to enable the “Reset On User Button” behaviour. See ResetOnUserButton

virtual void _softwareReset() = 0

Subclasses must implement this method to enable software resets. See SoftwareReset

virtual void _softwareResetToApplication() = 0

Subclasses must implement this to enable software reset to application See SoftwareResetToApplication

virtual void _softwareResetToBootloader() = 0

Subclasses must implement this method to allow reset to bootloader See SoftwareResetToBootloader

IApplicationContext(power::IPowerManagement *pwr, AppRunLoop *runLp, display::IDisplayController *dispCtrl, ITouchSystem *tchSys, QueueInterrupt *userBtn, sensor::ITemperature *temp = 0, sensor::IAccelerometer *accel = 0, sensor::IBuzzer *buzzer = 0, IRTCSystem *irtc = 0)

Protected constructor that must be called by the sub class. It sets up needed pointers for the required subsystems. This ensure the pointers are available when class members’ constructors are executed.

If this contructor did not setup the pointers, the PowerManagement constructor would see the Instance global equal null.

IRTCSystem
class mono::IRTCSystem

Abstract interface for controlling a MCU specific RTC.

This interface defines methods for setting up the RTC component, and starting and stopping the RTC interrupt.

The DateTime class contains a static DateTime object that represents the system time. It is this RTC interface’s task to maintain a valid system timestamp by incrementing the static system DateTime object.

Subclassed by mono::MonoRTC

Public Functions

virtual void setupRtcSystem() = 0

Setup the RTC system with all register setting and interrupts needed.

This shuold not start the RTC, just intialize it - making it ready for calling startRtc().

Any subclass must implement this function - it is automatically called by the IApplicationContext class.

virtual void startRtc() = 0

Start the built-in RTC, effectively starting the system date/ time clock.

virtual void stopRtc() = 0

Stop the built-in RTC, effectively pausing the system date/ time clock.

Public Static Attributes

bool __shouldProcessScheduledTasks = false

The RTC should set this when it is time to process scheduled tasks.

The run loop and the sleep loop should check this variable to know when to process all scheduled tasks. You must set this variable in your RTC interrupt function.

IRunLoopTask
class mono::IRunLoopTask

THis interface defines tasks or functions that can be inserted into the ApplicationRunLoop.

The interface defines a method that implements the actual logic. Also, the interface defines the pointers previousTask and nextTask. These define the previous and next task to be run, in the run loops task queue.

To avoid dynamic memory allocation of linked lists and queues in the run loop, the run loop handler functions, are themselves items in a linked list.

All classes that that want to use the run loop, must inherit this interface.

NOTE that tasks in the run loop do not have any contraints on how often or how rare they are executed. If you need a function called at fixes intervals, use a Ticker or timer.

Subclassed by mono::display::ILI9225G, mono::power::MonoPowerManagement, mono::QueueInterrupt, mono::Timer, mono::ui::Animator

Protected Functions

virtual void taskHandler() = 0

This is the method that gets called by the run loop.

NOTE that this is not an interrupt function, you can do stuff that take some time.

Protected Attributes

IRunLoopTask *previousTask

A pointer to the previous task in the run loop The the task is the first in queue, this is NULL

IRunLoopTask *nextTask

A pointer to the next task to be run, after this one. If this task is the last in queue, this is NULL

bool singleShot

Tasks are expected to be repetative. They are scheduled over and over again. Set this property to true and the task will not scheduled again, when handled.

ITouchSystem
class mono::ITouchSystem

Interface for the Touch sub-system

Subclassed by mono::MonoTouchSystem

Public Functions

virtual void init() = 0

Initialize the touch system controller.

NOTE: This method is called by the current IApplicationContext automatically upon reset. You should call this manually.

virtual void processTouchInput() = 0

Sample the touch inputs and dispatch events if needed.

This AppRunLoop calls this method automatically on each cycle. If you wish to limit the sample frequency, your subclass must manually abort some calls to this method.

Note: Inactive touch systems must ignores calls to this method.

virtual int ToScreenCoordsX(int touchPos, uint16_t screenWidth) = 0

Sub-classes must convert corrdinates to screen pixels (X axis)

virtual int ToScreenCoordsY(int touchPos, uint16_t screenHeight) = 0

Sub-classes must convert corrdinates to screen pixels (Y axis)

virtual TouchCalibration CurrentCalibration() = 0

Get the touch systems current calibration config.

virtual void setCalibration(TouchCalibration &cal) = 0

Set a new calibration config on the touch system.

virtual void activate()

Activate (enables) the touch system.

virtual void deactivate()

Deactivates (disables) the touch system.

virtual bool isActive() const

Retuern true if touch system is active.

Protected Functions

void runTouchBegin(geo::Point &pos)

Run the system system handlers of the begin touch event.

NOTE: You should not call this method manually. It is used by the sub- class of this interface.

Parameters
  • pos: The begin event position on the screen

void runTouchMove(geo::Point &pos)

Run the system system handlers of the move touch event.

NOTE: You should not call this method manually. It is used by the sub- class of this interface.

Parameters
  • pos: The move event position on the screen

void runTouchEnd(geo::Point &pos)

Run the system system handlers of the end touch event.

NOTE: You should not call this method manually. It is used by the sub- class of this interface.

Parameters
  • pos: The end event position on the screen

ManagedPointer
template <typename ContentClass>
class mono::ManagedPointer

Pointer to a heap object, that keeps track of memory references.

The managed pointer is an object designed to live on the stack, but point to memory cobntent that live on the heap. The ManagedPointer keeps track of memory references, such that the it can be shared across multiple objects in your code.

It maintains an internal reference count, to keep track of how many objects holds a reference to itself. If the count reaches zero, then the content is deallocated.

With ManagedPointer you can prevent memory leaks, by ensuring un-references memory gets freed.

Public Functions

ManagedPointer()

Create an empty pointer

void Surrender()

Give up this ManagedPointers refrences to the content object, by setting its pointer to NULL.

This means that if the Reference count is 1, this pointer is the only existing, and it will not dealloc the content memory upon deletion of the ManagedPointer.

We Reference count is > 1, then other ManagedPointers might dealloc the content memory.

TouchEvent
class mono::TouchEvent
TouchResponder
class mono::TouchResponder

The TouchReponder handles incoming touch events.

The TouchResponder is an interface that classes and inherit from to receive touch input events. This class also defined global static method used by Mono’s hardware dependend touch system. These static methods receives the touch events and delegates them to all objects in the responder chain.

You can make any object a receiver of touch events if you inherit from this interface. You need to override 3 methods:

  • RespondTouchBegin
  • RespondTouchMove
  • RespondTouchEnd

These methods are called on any subclass when touch input events are received. Note that your subclass will receive all incoming events not handled by other responders.

If you want to make touch enabled graphical elements, you should use the interface ResponderView. This class is the parent class for all touch enabled views.

See
ResponderView
See
ITouchSystem

Inherits from mono::IQueueItem

Subclassed by mono::PowerSaver, mono::ui::ResponderView

Public Functions

TouchResponder()

Create a new responder object that receives touch input.

Upon creation, this object is automatically inserted into the responder chain, to receive touch input events.

void Activate()

Add this responder to the responder chain

void Deactivate()

Remove this responder from the responder chain

Public Static Functions

TouchResponder *FirstResponder()

Get the top of the responder queue, the first to handle touch.

If there are no objects reponding to touch, this will return NULL

UI Widgets

AbstractButtonView
class mono::ui::AbstractButtonView

Inherits from mono::ui::ResponderView

Subclassed by mono::ui::OnOffButtonView

Public Functions

template <typename Owner>
void mono::ui::AbstractButtonView::setClickCallback(Owner * obj, void(Owner::*)(void) memPtr)

Attach a member function as the button click handler.

Provide the callback member function you ewant to be called when the button is clicked.

NOTE: THere can only be one callback function

Parameters
  • obj: A pointer to the object where the callback method exists
  • memPtr: A pointer to the callback method itself

void setClickCallback(void (*memPtr)(void))

Attach a C function pointeras the button click handler.

Provide a pointer to the callback C function, you ewant to be called when the button is clicked.

NOTE: THere can only be one callback function.

Parameters
  • memPtr: A pointer to the C function callback

Protected Functions

AbstractButtonView()

Cannot construct abstract buttons.

AbstractButtonView(geo::Rect rct)

Construct a button with a defined viewRect.

BackgroundView
class mono::ui::BackgroundView

A full screen solid colored background.

Use this view to paint the background any color you like. This view is by default the same size as Mono’s display. It can be used a solid colored background for your GUI.

To save memory you should only have one background view per app.

Painting on top of the background

To ensure that the background is behind all other UI widgets on the screen, it has to be rendered first. Then all other views will apepear on top of the background. To achieve this, it is important to keep track of your repaint order. All paint calls must begin with a scheduleRepaint to the background view.

Example

// Construct the view (should alwaus be a class member)
mono::ui::BackgroundView bg;

// set an exiting new background color
bg.setBackgroundColor(mono::display::RedColor);

//show the background
bg.show();

// show all my other views, after the call to bg.show()

Inherits from mono::ui::View

Public Functions

BackgroundView(display::Color color = StandardBackgroundColor)

Construct a Background view on the entire screen.

This contructor takes a optional color to use for the background. If no argument is provided the color default to the View::StandardBackgroundColor

Also be default the view dimension is the entire display, meaning it has a bounding rect (vireRect) that is (0,0,176,220).

Note: Remember to all show to make the view visible.

Parameters
  • color: An optional bckground color

BackgroundView(geo::Rect const &rect, display::Color color = StandardBackgroundColor)

Construct a BackgroundView with a specific position and size.

If you need at solid color (as background) in a confined space on the screen, then you can use this constructor.

Parameters
  • rect: The position and size of the view
  • color: An optional color, default is StandardBackgroundColor

void setBackgroundColor(display::Color color)

Sets a new background color on the view.

Set a new background color on the view. If the view is shared between multiple UI scenes, you can use this method to change the background color.

When changing the background color the view is not automatically repainted. You must call scheduleRepaint yourself.

mono::display::Color Color() const

Gets the current background color.

void repaint()

Repaint the view content, using the View::painter.

Re-paint the view content. This method should be called when the view content has changed. You can call this method directly, but it might cause graphics artifacts because the display is not double buffered. Instead you should schedule a repaint by calling the scheduleRepaint() method. This method will schedule the repaint, right after the next display update.

The display system will not schedule any repaints automatically. The view does not contain any state information, so you or other classes utilizing view must schedule repaints.

In subclasses of View, this method must be overwritten.

ButtonView
class mono::ui::ButtonView

A Push Button UI Widget.

This is a common state-less push button. It is basically a bordered text label. This button reacts to touch input (pushes) and can call a function when it is pushed.

You provide the button with a callback function, that gets called when the button is pushed. A valid button push is a touch that begins and ends within the button boundaries. If a touch begins inside the buttons boudaries, but ends outside - the button click callback is not triggered.

You define the button dimensions by the Rect you provide in the constructor. Note that the resistive touch panel is not that precise, you should not create buttons smaller than 40x35 pixels. Also note that buttons do not automatically scale, when you set their text content.

Example

// Create the button (should normally be defined as a class member)
mono::ui::ButtonView btn(mono::geo::Rect(10,10,100,35), "Push Here")

// Setup a click handler
btn.setClickCallback<MyClass>(this, &MyClass::MyClickHandler);

// show the button on the screen
btn.show();

Inherits from mono::ui::ResponderView

Public Functions

ButtonView()

Construct an empty button.

The button will have zero dimensions and no text.

ButtonView(geo::Rect rect, String text)

Construct a button with dimensions and text.

Creates a button with the provided dimensions and text to display. You still need to setup a callback and call show.

Parameters
  • rect: The view rect, where the button is displayed
  • text: The text that is showed on the button

ButtonView(geo::Rect rect, const char *text)

Construct a button with dimensions and text.

Creates a button with the provided dimensions and text to display. You still need to setup a callback and call show.

Parameters
  • rect: The view rect, where the button is displayed
  • text: The text that is showed on the button

void setText(String txt)

Set the text content.

Sets the text that is displayed on the button. Note that the width and height of the button is not changed. You must change the buttons viewRect if your text is larger than the buttons dimensions.

When you set new text content, the button is automatically repainted

Parameters
  • txt: The new text content

void setFont(MonoFont const &newFont)

Change the button fontface (font family and size)

You can change the buttons font to use a larger (or smaller) font.

void setFont(GFXfont const &newFont)

Change the buttons fontface (font family and size)

You can change the buttons font to use a larger (or smaller) font.

Parameters
  • newFont: The font face to render the text content with

void setBorder(Color c)

Sets the border color.

This method will not schedule repaint! You must scheduleRepaint manually.

Parameters
  • c: The new border color

void setText(Color c)

Sets the text color.

This method will not schedule repaint! You must scheduleRepaint manually.

Parameters
  • c: The new text color

void setHighlight(Color c)

Sets the highlight color (border & text)

The highlight color is the color used to represented a button that is currently being pushed. This means that a touch event has started inside its boundaries. The highlight color is applied to both border and text.

This method will not schedule repaint! You must scheduleRepaint manually.

Parameters
  • c: The new highlight color

void setBackground(Color c)

Sets the background color.

The background color of the fill color inside the button bounding rectangle.

This method will not schedule repaint! You must scheduleRepaint manually.

Parameters
  • c: The new border and text color

void setRect(geo::Rect rect)

Set the view’s position and size, by providing a rectangle object.

Note that this method does not repaint the view, you must do that explicitly.

Parameters
  • rect: The view rectangle, containing size and position

const TextLabelView &TextLabel() const

Get a reference to the internal TextLabel object.

You get a const reference to the button internal TextLabelView

template <typename Owner>
void mono::ui::ButtonView::setClickCallback(Owner * obj, void(Owner::*)(void) memPtr)

Attach a member function as the button click handler.

Provide the callback member function you ewant to be called when the button is clicked.

NOTE: THere can only be one callback function

Parameters
  • obj: A pointer to the object where the callback method exists
  • memPtr: A pointer to the callback method itself

void setClickCallback(void (*memPtr)(void))

Attach a C function pointeras the button click handler.

Provide a pointer to the callback C function, you ewant to be called when the button is clicked.

NOTE: THere can only be one callback function.

Parameters
  • memPtr: A pointer to the C function callback

void repaint()

Painters.

ConsoleView
template <uint16_t W, uint16_t H>
class mono::ui::ConsoleView

Inherits from mono::ui::View

Public Functions

ConsoleView(geo::Point pos)

Construct a new ConsoleView, for viewing console output on the screen.

void WriteLine(String txt)

Write a string to the console, and append a new line.

Parameters
  • txt: The string to write to the console

void repaint()

Repaint the view content, using the View::painter.

Re-paint the view content. This method should be called when the view content has changed. You can call this method directly, but it might cause graphics artifacts because the display is not double buffered. Instead you should schedule a repaint by calling the scheduleRepaint() method. This method will schedule the repaint, right after the next display update.

The display system will not schedule any repaints automatically. The view does not contain any state information, so you or other classes utilizing view must schedule repaints.

In subclasses of View, this method must be overwritten.

int lineLength()

Get the width of a line in characters.

<# description #>

Return
Number of characters in one line

int consoleLines()

Get the number lines in the console.

<# description #>

Return
Numeber of text lines on the console view.

Protected Attributes

TextBuffer<(W-4)/5, (H-4)/9> textBuffer

Text buffer that hold the visible text in the console. When the console scrolls, the text in the buffer is overwritten.

bool scrolls

Becomes true when the console text has reached the bottom line of its view rectangle. And all text appending from now on, causes the console to scroll.

GraphView
class mono::ui::GraphView

Visualizes a data series as a graph, based on a associated data source.

This class can visualize an array of samples on a graph. You provide the data by subclasseing the IGraphViewDataSource to deliver to data to display.

This class only display the data, it does not hold or buffer it. In this sense the GraphView contains no state.

Example

To demonstrate a simple example of using the GraphView we must also create a data source. For an associated data source, let us wrap a simple C array as a IGraphViewDataSource subclass:

// Subclass the IGraphViewDataSource interface
class DataSource : public IGraphViewDataSource
{
private:

    // Use an internal array as data store
    uint8_t data[100];

public:

    // Override the method that provide data samples
    int DataPoint(int index) { return data[index]; }

    // Override the method that return the total length of the data set
    int BufferLenght() { return 100; }

    // Override the method that return the valid value range of the data
    // samples.
    int MaxSampleValueSpan() { return 256; }
};

The class DataSource is just an array with a length of 100. Note that we only store 8-bit data samples (uint_t), therefore the valid data range is 256. The GraphView expects the data values to be signed, meaning the valid range is from -127 to +127.

We have not provided any methods for putting data into the data source, but we will skip that for this example.

Now, we can create a GraphView that displays data from the array:

// Crate the data source object
DataSource ds;

// The view rectangle, where the graph is displayed
mono::geo::Rect vRect(0,0,150,100);

// create the graph view, providing the display rect and data
mono::ui::GraphView graph(vRect, ds);

//tell the graph view to be visible
graph.show();

Update Cursor

If you IGraphViewDataSource subclass overrides the method: NewestSampleIndex(), the GraphView can show an update cursor. The cursor is a vertical line drawn next to the latest or newest sample. The cursor is hidden by default, but you can activate it by overiding the data source method and calling setCursorActive.

Note that if you time span across the x-axis is less than 100 ms, the cursor might be annoying. I would recommend only using the cursor when your graph updates slowly.

Scaling and Zooming

the graoh view will automatically scale down the data samples to be display inside its graph area. It displays the complete data set from the data source, and does not support displaying ranges of the data set.

If you wish to apply zooming (either on x or Y axis), you must do that by scaling transforming the data in the data source. You can use an intermediate data source object, that scales the data samples, before sending them to the view.

See
IGraphViewDataSource

Inherits from mono::ui::View

Public Functions

GraphView()

Construct a GraphView with no viewRect and data source.

This contructor creates a GraphView object that needs a viewRect and source to be set manually.

You cannot display view objects that have a null-viewRect

See
setDataSource
See
setRect

GraphView(geo::Rect rect)

Construct a GraphView with a defined viewRect.

This constructor takes a viewRect, that defines the space where graph is displayed.

**No data will be displayed before you set a valid source**

See
setDataSource
Parameters
  • rect: The viewRect where the graph is displayed

GraphView(geo::Rect rect, const IGraphViewDataSource &dSource)

Construct a GraphView with viewRect and a data source.

Parameters

Protected Functions

void repaint()

Repaint the view content, using the View::painter.

Re-paint the view content. This method should be called when the view content has changed. You can call this method directly, but it might cause graphics artifacts because the display is not double buffered. Instead you should schedule a repaint by calling the scheduleRepaint() method. This method will schedule the repaint, right after the next display update.

The display system will not schedule any repaints automatically. The view does not contain any state information, so you or other classes utilizing view must schedule repaints.

In subclasses of View, this method must be overwritten.

IGraphViewDataSource
class mono::ui::IGraphViewDataSource

Data provider interface for the GraphView class.

This interface defines the DataSource for GraphView objects. The graph view queries an associated data source object for the data to display. All GraphView objects must have a data source object that hold the data to be displayed. The data source interface exposes an array-like scheme for providing data to the GraphView.

This interface forces you to expose your data sample as an array, where all samples has an index. The index starts at index 0 and has variable length.

You must subclass this interface and override at least 3 virtual methods. These 3 methods are:

  • DataPoint(int) : Return individual data samples
  • BufferLength() : Return the full length of the data source
  • MaxSampleValueSpan() : Return the full range of the data sample values

By providing the methods for retreiving data, getting the total length of the data buffer and defining the valid value range of the data samples.

If your subclass is representing a casual signal buffer, where samples are continuesly written, you might override the method:

This method should return the index to the newest sample in the buffer. This enables the GraphView to display a scrolling cursor, that moves as the buffer data gets updates.

Note: You are in charge of notifying the associated GraphView‘s when the data source content changes.

See
GraphView

Public Functions

virtual int DataPoint(int index) = 0

Override this to return data point samples to the view.

Provides a sample from the data source. You must override this method to return samples at any given index.

Return
the sample value at the given index
Parameters
  • index: The 0-indexed sample position, that should be returned

virtual int BufferLenght() = 0

Override this to return the data sample buffer length to the view.

Returns the length / the total number of data samples in the data source. You must override this method to return the total number of data sample in your data source implementation.

Return
the size / length of the data source

virtual int MaxSampleValueSpan() = 0

The value span for the data samples. üsed to map the buffer samples to the screen (view height)

virtual int NewestSampleIndex()

Return the position / index of the newest sample in the buffer.

Override this method to get a scrolling pointer on the GraphView, a pointer that is drawn at this index position.

Return
Position of newest sample

ImageView
class mono::ui::ImageView

Displays a bitmap image on the display.

The ImageView can render a bitmap image on the display. It needs a image data source, that delivers the actual bitmap. (See BMPImage)

You provide the image data and a bounding rect where the ImageView is painted.

If you wish to use the class BMPImage as a image source, you must initialize the SD Card Filesystem first!

## Example

// init the SD card before accessing the file system

// Open and prepare the BMP file to display
mono::media::BMPImage img("/sd/my_pic.bmp");

// create the view and provide the image source
mono::ui::ImageView imgView(&img);

// tell the image to be showed
imgView.show();

It is your responsibility to make sure the source image data object is staying around, and do not get deallocated. Preferreably you should make both the image source and the view class members.

Cropping

The image view can crop the source image, thereby only showing a selected portion. The default crop is defined by the views bounding rect. Naturally images larger than the view’s rect will be cropped with repect to the upper left corner.

The default cropping Rect is therefore *(0, 0, imageWidth, imageHeight)*

Inherits from mono::ui::View

Public Functions

ImageView()

Construct an empty image view, where no image is displayed To display an image you need to call setImage later.

ImageView(media::Image *img)

Construct an UI image from an image file

At the moment only BMP images are supported! Remember to initialize the mbed class object before calling this consructor!

The image viewRect is set to the full screen size. Use setRect to adjust size and position.

Parameters
  • img: The image data slurce to show

void setImage(media::Image *img)

Set a new image source object Note: This method also resets the current cropping rectangle!

Parameters
  • img: A pointer to the new image to display

void setCrop(geo::Rect crp)

Set image cropping.

Define switch portion for the image should be display inside the view own bounding rectangle. By default as much as the original image as possible, will be showed.

By defining a cropping rectangle you can define an offset and size to display from thesource image.

The source image has the same coordinate system as the display. That is (0,0) is the upper left corner.

Parameters
  • crp: A cropping rectangle

const mono::geo::Rect &Crop() const

Get the current cropping rectangle Get the current used cropping rectangle for the source image.

void repaint()

Repaint the view content, using the View::painter.

Re-paint the view content. This method should be called when the view content has changed. You can call this method directly, but it might cause graphics artifacts because the display is not double buffered. Instead you should schedule a repaint by calling the scheduleRepaint() method. This method will schedule the repaint, right after the next display update.

The display system will not schedule any repaints automatically. The view does not contain any state information, so you or other classes utilizing view must schedule repaints.

In subclasses of View, this method must be overwritten.

Protected Attributes

media::Image *image

A pointer to the Image object that is to be displayed in the screen.

geo::Rect crop

Image crop rectangle. Setting this rect will crop the source image (non destructive).

OnOffButtonView
class mono::ui::OnOffButtonView

Inherits from mono::ui::AbstractButtonView

Public Functions

void repaint()

Repaint the view content, using the View::painter.

Re-paint the view content. This method should be called when the view content has changed. You can call this method directly, but it might cause graphics artifacts because the display is not double buffered. Instead you should schedule a repaint by calling the scheduleRepaint() method. This method will schedule the repaint, right after the next display update.

The display system will not schedule any repaints automatically. The view does not contain any state information, so you or other classes utilizing view must schedule repaints.

In subclasses of View, this method must be overwritten.

ProgressBarView
class mono::ui::ProgressBarView

A UI widget displaying a common progress bar.

This progressbar is simply a rectangle with a line (progress indicator) inside. The indicator value is (by default) a value between 0 and 100, but you can set your own minimum and maximum points.

The progress value’s minimum and maximum is automtically calculated into the correct pixel value, scaled to the pixel width of the progressbar.

Example

// Create the progressbar object
mono::ui::ProgressBarView prgs(mono::geo::Rect(10,10,156,100));

// set the progressbars indicator value to 50%
prgs.setValue(50);

// display it
prgs.show();

A common mistake

Be aware that the progressbar is painted asynchronously. This means you cannot increment its value inside a for-loop or alike.

This code will not work:

for (int i=0; i<100; i++) {
    prgs.setValue(i);
}

Even if the loop ran veeery slow, you will not see a moving progress indicator. The reason is that the view is only painted in the run-loop, so no screen updates can happen from inside the for-loop!

You should use a continous timer, with a callback that increments the progress indicator:

void updateProgress(){
    prgs.setValue(i++);
}

mono::Timer tim(500);
tim.setCallback(&updateProgress);

This code inject a continous task to the run loop that can increment the progressbar. This is the correct way to animate a progressbar.

Inherits from mono::ui::View

Public Functions

ProgressBarView()

Create a ProgressBar with a zero view rect (0,0,0,0)

ProgressBarView(geo::Rect rect)

Create a ProgressBarView with values from 0 to 100.

Create a new ProgressBarView, with a defined view rect and default progress value span: 0 to 100, with a current value of 0.

Parameters
  • rect: The view rect where the ProgressBar is painted

void setValue(int newValue)

Set a new progress value.

Set a new current value for the progress bar. The value is truncated to the existing value span (min and max values).

Changes to the value will trigger the value changed callback and cause the view to schedule itself for repaint.

Parameters
  • newValue: The new value

void setMaximum(int max)

Define a new minimum value for the progress indicator.

SETTERS.

void setMinimum(int min)

define a new maximum value for the progress indicator

template <typename Owner>
void mono::ui::ProgressBarView::setValueChangedCallback(Owner * cnxt, void(Owner::*)(void) memPtr)

Set a progress value change callback function.

Get notification callback everytime this progressbar changes its value

Parameters
  • cnxt: A pointer to the callback member context (the this pointer)
  • memPtr: A pointer to the callback member function

int Minimum() const

GETTERS.

int Maximum() const

GETTERS.

Protected Functions

void init()

convenience initializer

void repaint()

MISC.

ResponderView
class mono::ui::ResponderView

Inherits from mono::ui::View, mono::TouchResponder

Subclassed by mono::ui::AbstractButtonView, mono::ui::ButtonView, mono::ui::TouchCalibrateView

Public Functions

void show()

Shows (repaints) the view and insert into the responder chain.

See
View::show

void hide()

hides the view, and remove from the responder chain

See
View::hide

Protected Functions

void RespondTouchBegin(TouchEvent &event)

Internal touch handler, you should not overwrite this

void RespondTouchMove(TouchEvent &event)

Internal touch handler, you should not overwrite this

void RespondTouchEnd(TouchEvent &event)

Internal touch handler, you should not overwrite this

StatusIndicatorView
class mono::ui::StatusIndicatorView

Indicate a boolean status, true/false, on/off or red/green.

The status indicator displays a circular LED like widget, that is red and green by default. (Green is true, red is false)

You use the method setState to change the current state of the indicator. This you change the state, the view automatically repaints itself on the screen.

Example

// Initialize the view (you should make it a class member)
mono::ui::StatusIndicatorView indicate(mono::geo::Rect(10,10,20,20), false);

// Change the default off color from red to to white
indicator.setOnStateColor(mono::display::WhiteColor);

// set the state to be On
indicator.setState(true);

// make the view visible
indicator.show();

Inherits from mono::ui::View

Public Functions

StatusIndicatorView()

contruct a StatusIndicator with default parameters

this view will be initialized in an empty viewRect, that is (0,0,0,0)

StatusIndicatorView(geo::Rect vRct)

Construct a Indicator and provide a View rect.

This create a view rect the exists in the provided Rect and has the default state false

Note: You need to call show before the view can be rendered

Parameters
  • vRct: The bounding view rectangle, where the indicator is displayed

StatusIndicatorView(geo::Rect vRct, bool status)

Construct a Indicator and provide a View rect and a initial state.

This create a view rect the exists in the provided Rect

Note: You need to call show before the view can be rendered

Parameters
  • vRct: The bounding view rectangle, where the indicator is displayed
  • status: The initial state of the indicator

void setOnStateColor(display::Color col)

Sets the on state color.

If you change the color, you must call scheduleRepaint to make the change have effect.

Parameters
  • col: The color of the indicator when it is on

void setOffStateColor(display::Color col)

Sets the off state color.

MARK: SETTERS.

If you change the color, you must call scheduleRepaint to make the change have effect.

Parameters
  • col: The color of the indicator when it is off

void setState(bool newState)

Sets a new on/off state.

Note that the view repaints itself if the new state differs from the old.

Parameters
  • newState: The value of the new state (true is on)

bool State() const

Gets the state of the indicator.

MARK: GETTERS.

Return
trueif the state if on, false otherwise.

Protected Functions

void initializer()

MARK: Constructors.

void repaint()

Repaint the view content, using the View::painter.

Re-paint the view content. This method should be called when the view content has changed. You can call this method directly, but it might cause graphics artifacts because the display is not double buffered. Instead you should schedule a repaint by calling the scheduleRepaint() method. This method will schedule the repaint, right after the next display update.

The display system will not schedule any repaints automatically. The view does not contain any state information, so you or other classes utilizing view must schedule repaints.

In subclasses of View, this method must be overwritten.

TextLabelView
class mono::ui::TextLabelView

A Text Label displays text strings on the display.

Use this UI view whenever you need to display text on the screen.

A text label renders text strings on the display. As all views the label lives inside a defined rectangle (viewRect), where the text is rendered. If the rectangle is smaller than the length of the text content, the content will cropped. If the rectangle is larger, then you can align the text inside the rectangle (left, center or right).

Example

You can mix and match mono strings with standard C strings when constructing TextLabels.

Create a label using a C string:

TextLabelView lbl("This is a contant string");

Also you can use C strings allocated on the stack:

char text[4] = {'m', 'o', 'n', 'o'};
TextLabelView lbl(text);

Above the TextLabel will take a copy of the input string, to ensure it can be accessed asynchronously.

Content

The text view contains it content (a String object), and therefore has a state. You get and set the content to update the rendered text on the display.When you set new text content the label automatically re-renders itself. (By calling scheduleRepaint)

Because the view is rendered asynchronously, its text content must be allocated on the heap. Therefore it uses the String as text storage. You can provide it with C strings, but these must allocated inside the .rodata segment of your binary. (Meaning they are static const.)

Text Format

Currently there are only one font type. But the text color and font can changed. You change these for parameters:

  • Text font (including size)
  • Text color
  • Text background color (the color behind the characters)

Getting text dimensions

To help you layout your views, you can query the TextLabel of the current width and height of its contents. The methods TextPixelWidth and TextPixelHeight, will return the texts dimensions in pixels

  • regardless of view rectangle. Also, you can use these methods before the view has been rendered.

Inherits from mono::ui::View

Public Types

enum TextAlignment

Three ways of justifing text inside the TextLabel.

Values:

ALIGN_LEFT

Align text to the left

ALIGN_CENTER

Align text in the center

ALIGN_RIGHT

Align text to the right

enum VerticalTextAlignment

The Vertical justification of the text, inside the labels Rect.

Values:

ALIGN_TOP

Align the text at the top of the label

ALIGN_MIDDLE

Align the text at in the middle of the label

ALIGN_BOTTOM

Align the text at the bottom of the label

Public Functions

TextLabelView(String txt = String ())

Construct a text label with defined content, but no dimensions.

Before you can render the label you still need to set the view dimensions. This constructor take the String object as defined in the mono framework.

Parameters
  • txt: The labels text content (as a mono lightweight string)

TextLabelView(const char *txt)

Construct a text label with defined content, but no dimensions.

Before you can render the label you still need to set the view dimensions. This constructor takes a static const C string pointer that must not exist on the stack! (It must live inside the .rodata segment.

Parameters
  • txt: A pointer to the static const C string (.rodata based)

TextLabelView(geo::Rect rct, String txt)

Construct a label in a defined rectangle and with a string.

You provide the position and size of the label, along with its text content. You can call this constructor using a mono type string or a stack based C string - and it is automatically converted to a mono string:

int celcius = 22;

// char array (string) on the stack
char strArray[50];

// format the string content
sprintf(strArray,"%i celcius", celcius);

// construct the label with our stack based string
TextLabelView lbl(geo::Rect(0,0,100,100), strArray);

TextLabelView(geo::Rect rct, const char *txt)

Construct a label in a defined rectangle and with a string.

You provide the position and size of the label, along with its text content. You can call this constructor using static const C string:

// construct the label with our stack based string
TextLabelView lbl(geo::Rect(0,0,100,100), "I am a .rodata string!");

uint8_t TextSize() const

The text size will be phased out in coming releases. You control text by changing the font.

mono::display::Color TextColor() const

Get the current color of the text.

TextLabelView::TextAlignment Alignment() const

Get the current horizontal text alignment.

TextLabelView::VerticalTextAlignment VerticalAlignment() const

Get the current vertical text alignment.

uint16_t TextPixelWidth() const

Get the width of the current text dimension.

uint16_t TextPixelHeight() const

Get the height of the current text dimension.

const MonoFont *Font() const

If not NULL, then returns the current selected MonoFont.

const GFXfont *GfxFont() const

If not NULL, then returns the current selected GFXfont.

mono::geo::Rect TextDimension() const

Returns the dimensions ( Size and offset Point ) of the text.

void setTextSize(uint8_t newSize)

We will phase out this attribute in the coming releases. To change the font size you should rely on the font face.

If you set this to 1 the old font (very bulky) font will be used. Any other value will load the new default font.

void setTextColor(display::Color col)

void setBackgroundColor(display::Color col)

void setText(display::Color col)

Set the text color.

void setBackground(display::Color col)

Set the color behind the text.

void setAlignment(TextAlignment align)

Controls text justification: center, right, left.

void setAlignment(VerticalTextAlignment vAlign)

Set the texts vertical alignment: top, middle or bottom.

void setText(const char *text)

Change the text content of the Text label, and schedules repaint.

This method updates the text that is rendered by the textlabel. It automatically schedules an incremental (fast) repaint.

Parameters
  • text: The C string text to render

void setText(String text)

Change the text content of the Text label, and schedules repaint.

This method updates the text that is rendered by the textlabel. It automatically schedules an incremental (fast) repaint.

Parameters
  • text: The Mono string text to render

void setText(const char *txt, bool resizeViewWidth)

void setText(String text, bool resizeViewWidth)

void setFont(MonoFont const &newFont)

Set a new font face on the label.

You can pass any MonoFont to the label to change its appearence. Fonts are header files that you must include youself. Each header file defines a font in a specific size.

The header file defines a global const variable that you pass to to this method.

Parameters
  • newFont: The mono-spaced to use with the textlabel

void setFont(GFXfont const &font)

Set a new font face on the label.

You can pass any Adafruit GfxFont to the label to change its appearence. Fonts are header files that you must include youself. Each header file defines a font in a specific size.

The header file defines a global const variable that you pass to to this method.

mono::String Text() const

Gets the content of the text label.

void scheduleFastRepaint()

Repaints the view, using incremental repaints if possible.

This method might be faster than scheduleRepaint, since this repaint allows the text to be repainted incrementally. This means fast repaint of counters or fade animations.

If you experience rendering errors, you should use the normal scheduleRepaint method.

void scheduleRepaint()

Schedule this view for repaint at next display refresh.

This method add the view to the display systems re-paint queue. The queue is executed right after a display refresh. This helps prevent graphical artifacts, when running on a single display buffer system.

Because views have no state information, they do not know when to repaint themselves. You, or classes using views, must call this repaint method when the view is ready to be repainted.

void repaint()

Repaint the view content, using the View::painter.

Re-paint the view content. This method should be called when the view content has changed. You can call this method directly, but it might cause graphics artifacts because the display is not double buffered. Instead you should schedule a repaint by calling the scheduleRepaint() method. This method will schedule the repaint, right after the next display update.

The display system will not schedule any repaints automatically. The view does not contain any state information, so you or other classes utilizing view must schedule repaints.

In subclasses of View, this method must be overwritten.

Public Members

bool incrementalRepaint

This indicate if the next repaint should only repaint differences

void setBackground

Set the color behind the text

Public Static Functions

static const MonoFont* StandardTextFont mono::ui::TextLabelView::__DEPRECATED("use the similar variable of the GfxFontType", "StandardGfxFont")

This is the default font for all TextLabelView‘s.

This points to the default Textlabel font. You can overwrite this in your own code to change the default appearence of all TextLabels.

You can also overwrite it to use a less memory expensive (lower quality) font face.

Public Static Attributes

const GFXfont *StandardGfxFont

This is the default font for all TextLabelView‘s.

This points to the default Textlabel font. You can overwrite this in your own code to change the default appearence of all TextLabels.

You can also overwrite it to use a less memory expensive (lower quality) font face.

Protected Functions

bool isTextMultiline() const

Check if the current text has newline characters.

This runs O(n)

Return
true is newlines are found

TouchCalibrator

Warning

doxygenclass: Cannot find class “mono::ui::TouchCalibrator” in doxygen xml output for project “monoapi” from directory: xml

View
class mono::ui::View

Abstract interface for all UI Views, parent class for all views.

Abstract View class/interface. All UI view/widgets that paint to the screen must inherit from this class. Views handle repaint queues, touch input and painting to the display buffer automatically.

All views have a width and height, along with an absolute x,y coordinate that defines the upper left corner of the view rectangle.

Views must not contain any state. They only draw data to the display. Therefore views might contain or have references to objects holding the actual state information. Some simple views, like TextLabelView, are exceptions to this rule, since it is highly convenient to let them hold some state. (Like text content.)

Something on dependence of AppContext and Appctrl design pattern

See
ResponderView

Inherits from mono::ui::IViewALike, mono::IQueueItem

Subclassed by mono::ui::BackgroundView, mono::ui::ConsoleView< W, H >, mono::ui::GraphView, mono::ui::IconView, mono::ui::ImageView, mono::ui::ProgressBarView, mono::ui::ResponderView, mono::ui::StatusIndicatorView, mono::ui::TextLabelView

Public Types

enum Orientation

Define the 4 dirrerent orientations the of display. The display controller apply the orientation transformation to real display. For the UI Views the coordinate system remains the same, it just changes width and height. The origo is always the top left corner (defined relative to gravity), no matter the physical orientation of mono’s display.

Values:

PORTRAIT = 0

Expected standard orientation of mono, where the thick edge is at the bottom

PORTRAIT_BOTTOMUP =1

Upside-down of PORTRAIT, where the thick edge is at the top

LANDSCAPE_RIGHT = 2

PORTRAIT rotated 90 degrees clock-wise

LANDSCAPE_LEFT = 3

PORTRAIT rotated 90 degrees counter clock-wise

Public Functions

View()

Construct an empty view, you should not do this! You should not use View directly, subclass it instead.

View(geo::Rect rect)

Construct a view with dimensions, you should not do this! You should not use View directly, subclass it instead.

void setPosition(geo::Point pos)

Change the view’s position on the screens coordinate system.

Changes the view’s position on the screen. Note that changing the position does not implicitly redraw the view. This means you will need to update the screen the affected areas to make the change visible.

Parameters
  • pos: The new position of the view

void setSize(geo::Size siz)

Change the size (width, height) of the view.

Changes the view’s dimensions. The effect of size changes might depend on the specefic view subclass. Some views might use their size to calculate their internal layout - others might only support fixed size.

Note that changing the size here does not redraw the view. The screen needs to be redrawn to make the size change visible.

Parameters
  • siz: The new size of the view

void setRect(geo::Rect rect)

Set the view’s position and size, by providing a rectangle object.

Note that this method does not repaint the view, you must do that explicitly.

Parameters
  • rect: The view rectangle, containing size and position

mono::geo::Point &Position()

Get the current position of the view’s upper left corner.

Return
A reference to the current position

mono::geo::Size &Size()

Get the view’s current size rectangle.

Return
A reference to the view’s size rectangle

const mono::geo::Rect &ViewRect() const

Get the views view rect

This method returns a reference to the views current view rect.

void scheduleRepaint()

Schedule this view for repaint at next display refresh.

This method add the view to the display systems re-paint queue. The queue is executed right after a display refresh. This helps prevent graphical artifacts, when running on a single display buffer system.

Because views have no state information, they do not know when to repaint themselves. You, or classes using views, must call this repaint method when the view is ready to be repainted.

bool Visible() const

Returns the view’s visibility.

Get the view visible state. Non-visible view are ignored by the method scheduleRepaint. You change the visibility state by using the methods show and hide

Return
true if the view can/should be painted on the screen, false otherwise.
See
show
See
hide

void show()

Set the view to visible, and paint it.

Change the view’s visibility state to visible. This means it can be scheduled for repaint by scheduleRepaint. This method automatically schedules the view for repaint.

See
hide
See
Visible

void hide()

Set the view to be invisible.

Change the view’s state to invisible. This method will remove the view from the dirtyQueue, if it has already been scheduled for repaint.

Any calls to scheduleRepaint will be ignored, until the view is set visible again.

See
show
See
Visible

Public Static Functions

uint16_t DisplayWidth()

Returns the horizontal (X-axis) width of the display canvas, in pixels. The width is always defined as perpendicular to gravity

uint16_t DisplayHeight()

Returns the vertical (Y-axis) height of the display canvas, in pixels. The height axis is meant to be parallel to the gravitational axis.

View::Orientation DisplayOrientation()

Returns the current physical display orientation of the display The orientation is controlled by the IDisplayController

Public Static Attributes

uint32_t RepaintScheduledViewsTime = 0

The CPU time used to repaint the latest set of dirty views. This measure includes both the painting algorithms and the transfer time used to comminicate with the disdplay hardware.

Protected Functions

void callRepaintScheduledViews()

A member method to call the static method repaintScheduledViews.

See
repaintScheduledViews

virtual void repaint() = 0

Repaint the view content, using the View::painter.

Re-paint the view content. This method should be called when the view content has changed. You can call this method directly, but it might cause graphics artifacts because the display is not double buffered. Instead you should schedule a repaint by calling the scheduleRepaint() method. This method will schedule the repaint, right after the next display update.

The display system will not schedule any repaints automatically. The view does not contain any state information, so you or other classes utilizing view must schedule repaints.

In subclasses of View, this method must be overwritten.

Protected Attributes

geo::Rect viewRect

The rect defines the position and size of this view on the screen. This defines where the view rectangles upper left corner is situated, and the width and height in pixels.

bool isDirty

Indicate is this view should be repainted on next display refresh.

bool visible

Views can be visible of non-visisble (hidden). When a view is not visible scheduleRepaint will ignore requests.

You should use the methods show and hide is toggle visibility.

See
show
See
hide
See
Visible

Protected Static Functions

void repaintScheduledViews()

This class method will run through the scheduled re-paints queue and call the repaint method on all of them.

This method is called automatically be the display system, you do not need to call it yourself.

Protected Static Attributes

mono::display::DisplayPainter painter

Global View painter object. Once the first View is included in the code, this painter is initialized on the stack. Every view object uses this painter to paint itself.

The painter is initialized with the display controller of the application context. If you want views to draw themselv on another display, you must subclass or change the current display controller of the mono::ApplicationContext object.

mono::GenericQueue<View> dirtyQueue

The global re-paint queue.

When you call the scheduleRepaint method, your views is added to the re-paint queue.

Network

HttpClient
class mono::network::HttpClient

A HTTP GET Request Client.

This class implements a HTTP GET Request, and provide you with a notification, when the response arrives.

You provide an URL and one or more callback functions, for getting the response data.

Example

HttpClient client("http://www.myip.com");
client.setDataReadyCallback<MyClass>(this, &MyClass::httpData);

Now your method httpData is called when response data arrives. Note that the callback can be called multiple times. A flag in the returned data object indicates, when this was the last data to be received.

DNS resolution is done automatically. You can also change the HTTP port to something other than 80 by providing an alternative port via the URL: . Likewise, you can use raw IPv4 addresses: .

Headers

You can provide additional headers for the request by using the constructors optional second argument. Just remember to end each header line with a . Like this: Accept: text/html\r\n

Error handling

This client class handles error that arise from:

  • DNS lookup failed (no such domain name)
  • No server response (host does not respond)

This class does not handle errors based on HTTP status codes or content types.

If you wish to handle errors you should setup a callback for the setErrorCallback

Inherits from mono::network::INetworkRequest

Subclassed by mono::network::HttpPostClient

Public Functions

HttpClient()

Construct an empty invalid client object.

HttpClient(String anUrl, String headers = String ())

Construct a new HTPT request to a given URL.

To receive the response, also setup the callback setDataReadyCallback

Parameters
  • anUrl: The URL string
  • headers: Any additional headers to add

template <typename Owner>
void mono::network::HttpClient::setDataReadyCallback(Owner * cnxt, void(Owner::*)(const HttpResponseData &) memPtr)

Provide your callback function to handle response data.

Parameters
  • cnxt: A pointer to the callback member function context (the this pointer)
  • memPtr: A pointer to the member function, that is the callback

Protected Functions

void dnsResolutionError(INetworkRequest::ErrorEvent *evnt)

Error callback for dns resolver

void dnsComplete(INetworkRequest::CompletionEvent *evnt)

dns resolver completion event handler

void httpCompletion(redpine::ManagementFrame::FrameCompletionData *data)

when the HTTP GET frame completes, check for error

class HttpResponseData

Class to represent HTTP response data.

This class defines the response data chunk return by an HTTP request. It defines only public accessable properties, that indicate the response state and the raw data.

Public Members

HttpClient *Context

Pointer to the originating HttpClient object.

String bodyChunk

The raw HTTP response chunk. More chunk might arrive later.

bool Finished

true if this response chunk is the final.

HttpPostClient
class mono::network::HttpPostClient

HTTP POST Request Client.

This class can send a HTTP POST request with body data. You provide callbacks to provide the body length (in bytes) and content. This is to avoid caching the content, and save memory.

Before this class works you must setup a working wifi connection.

Example

HttpPostClient client("http://www.postrequest.org/");
client.setBodyLengthCallback<MyClass>(this, &MyClass::getDataLength);
client.setBodyDataCallback<MyClass>(this, &MyClass::getData);
client.post();

This will post the request with no default Content-Type header. You can provide your own Content-Type by using the second (optional) argument in the constructor. If you do, remember to insert a \r\n at the end of of the header string.

Trailing white space

Due to a bug in the Redpine module protocol, the post body risk getting trailing whitespace characters (spaces: 0x20). There can up to 3 trailing spaces: . The reason is the redpine frame must end on a 4-byte byte boundry. Instead of appending NULL characters, we append spaces. Most HTTP servers does not respond well to NULL character being part of a text body.

This is of course an issue when sending binary data via POST requests. In these cases you should (at this point) avoid binary formats. (Maybe use base64 encoding.)

Inherits from mono::network::HttpClient

Public Functions

HttpPostClient()

Construct an empty invalid HTTP client.

HttpPostClient(String anUrl, String headers = String ())

Construct a client with a target URL.

Headers like Host and Content-Length are created automatically. The DNS resolution of the hostname is also done automatically.

The actual POST request is not execute before you call post. However, DNS resolution is started immediately.

Parameters
  • anUrl: THe URL to call
  • headers: Optional extra headers to add to the request

template <typename Class>
void mono::network::HttpPostClient::setBodyLengthCallback(Class * context, uint16_t(Class::*)(void) method)

Callback for providing the length of the HTTP POST body.

You should provide a efficient method of getting the body length, since this callback is used multiple times under the request execution.

Parameters
  • context: pointer to the object to call the member function on
  • method: pointer to the member function to be called

template <typename Class>
void mono::network::HttpPostClient::setBodyDataCallback(Class * context, void(Class::*)(char *) method)

Callback for providing the body content of the HTTP POST.

The internals of the request will ensure the provided char* is large enough to hold the size of the HTTP body.

Parameters
  • context: pointer to the object to call the member function on
  • method: pointer to the member function to be called

void post()

Execute the POST request.

Commit the request sending it to the server.

Protected Functions

void dnsComplete(INetworkRequest::CompletionEvent *evnt)

dns resolver completion event handler

Drawing

Color
class mono::display::Color

A RGB color representation, generic for display devices.

This class implements a 16-bit RGB 5-6-5 color model. It support methods for calculating color blendings and more.

The class definition also define a set of global constant predefined colors, like white, red, green, blue and black. Further, it includes a set of the FlatUI colors that Mono uses:

  • Clouds
  • WetAsphalt
  • Concrete
  • Silver
  • Asbestos
  • BelizeHole
  • MidnightBlue
  • Alizarin
  • Turquoise
  • Emerald

Public Functions

uint8_t Red() const

Return 8-bit red color component

uint8_t Green() const

Return 8-bit green color component

uint8_t Blue() const

Return 8-bit blue color component

Color scale(uint8_t factor) const

Misc.

Multiply each RGB channel by a factor from 0-255

Return
the scaled color

Color blendMultiply(Color other) const

Return the product of two colors

Return
the multiply blended color

Color blendAdditive(Color other) const

Add this color with another

Color invert() const

Return the inverse

mono::String toString() const

Get a human readable string representatio of the color.

Returns a string of the form: (RR, GG, BB)

Return
a color string

DisplayPainter
class mono::display::DisplayPainter

The DisplayPainter draws shapes on a display, using the DisplayController interface.

You should use this class to draw shapes on the screen, and use it from inside view only. The standard view class has a reference to to an instance of this class.

The coordinate system used by the painter is the same as used by the display interface. This means all shape coords are relative to the display origo at the top left corner for the screen, when screen is in portrait mode.

A painter keeps track of an active foreground and background color. You can set new colors at any time, and the succeeding draw calls will paint in that color. The standard draw color is the active foreground color, but some draw routines might use the background color also. An example is the font drawing routines.

Like colors, the painter object keeps a active line width and textsize. When drawing shapes based on lines drawLine, drawPolygon, drawRect and drawEllipse, the line width used is the currently active line width property of the painter object.

When painting text characters the character size is dependend on the textsize property. Text painting is not affected by the current line width.

Public Functions

DisplayPainter(IDisplayController *displayController, bool assignRefreshHandler = true)

Construct a new painter object that are attached to a display. A painter object is automatically initialized by the view/UI system and shared among the view classes.

In most cases you should not have to initialize your own display painter.

Parameters
  • displayController: A pointer to the display controller of the active display
  • Take: ownership of the DisplayControllers refresh callback handler

template <typename Owner>
void mono::display::DisplayPainter::setRefreshCallback(Owner * obj, void(Owner::*)(void) memPtr)

Set/Overwrite the display tearing effect / refresh callback.

Set the Painters display refresh callback handler. The display refreshes the screen at a regular interval. To avoid graphical artifacts, you should restrict your paint calls to right after this callback gets triggered.

The default View painter already has a callback installed, that triggers the View’s re-paint queue. If you create you own painter object you can safely overwrite this callback.

Parameters
  • obj: The this pointer for the object who shoould have its member function called
  • memPtr: A pointer the the class’ member function.

void setForegroundColor(Color color)

Set the painters foreground pencil color.

Parameters
  • color: The new foreground color

void setBackgroundColor(Color color)

Sets the painters background pencil color.

Parameters
  • color: the new background color

Color ForegroundColor() const

Gets the painters current foreground pencil color.

Return
The current foreground color

Color BackgroundColor() const

Gets the painters current background pencil color.

Return
The current foreground color

void useAntialiasedDrawing(bool enable = true)

Turn on/off anti-aliased line drawing.

You can enable or disable anti-aliased drawing if you need nicer graphics or faster rendering. Anti-aliasing smoothes lines edges, that can otherwise appear jagged.

Parameters
  • enable: Optional: Switch to turn on/off anti-aliasing. Deafult is enabled.

bool IsAntialiasedDrawing()

Returns true if anti-aliased drawing is enabled.

See
useAntialiasedDrawing
Return
true if enabled, false otherwise.

uint16_t CanvasWidth() const

Get the canvas width in pixels. This is the display display width as well.

Return
The canvas/display width in pixels

uint16_t CanvasHeight() const

Get the canvas height in pixels. This is the display display height as well.

Return
The canvas/display height in pixels

IDisplayController *DisplayController() const

Get a pointer to the painters current display controller You can use this method to obtain the display controller interface if you need to blit pixels directly to the display.

Return
A pointer to an object implementing the IDisplayController interface

void drawPixel(uint16_t x, uint16_t y, bool background = false)

Draw a single pixel on a specific position on the display.

The pixel will be the active foreground color, unless you set the third parameter to true.

Parameters
  • x: The X-coordinate
  • y: The Y coordinate
  • background: Optional: Set to true to paint with active background color.

void drawPixel(uint16_t x, uint16_t y, uint8_t intensity, bool background = false)

Draw a pixel and blend it with the background/foreground color.

Use this method to draw transparent pixels. You define an intensity of the pixel, that corrosponds to its Alpha value or opacity. 0 is totally transparent and 255 is fully opaque.

Only the foreground is influenced by the alpha value, the background is always treated as fully opaque.

Parameters
  • x: The pixels x coordinate
  • y: The puxels y coordinate
  • intensity: The alpha value, 0 to 255 where 0 is transparent.
  • Optionaluse: the background color as foreground and vice versa

void drawFillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, bool background = false)

Draw a filled rectangle.

Paints a filled rectangle in the active foreground color. Coordinates a defining the point of the rectangles upper left corner and are given in screen coordinates. (Absolute coordinates)

Parameters
  • x: X coordinate of upper left corner, in screen coordinates.
  • y: Y coordinate of upper left corner, in screen coordinates.
  • width: The width of the rectangle
  • height: The height of the rectangle
  • background: Optional: Set to true to paint in active background color

void drawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, bool background = false)

Draw a straight line between two points.

Draw a line on the display. The line is defined by its two end points. End point coordinates are in absolute screen coordinates.

The line is not anti-aliased.

Based on Bresenham’s algorithm. But If the line you intend to draw is horizontal of vertical, this method will usemore efficient routines specialized for these cases.

Parameters
  • x1: The X coordinate of the lines first endpoint
  • y1: The Y coordinate of the lines first endpoint
  • x2: The X coordinate of the lines second endpoint
  • y2: The Y coordinate of the lines second endpoint
  • background: Optional: Set this to true to paint in active background color

void drawRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, bool background = false)

Draw a outlined rectangle.

Draw an outlined rectangle with the current line width and the active color.

Parameters
  • x: Top left corner X coordinate
  • x: Top left corner X coordinate
  • width: The rectangles width
  • height: The rectangles height
  • background: Optional: Set this to true to paint in active background color

void drawChar(uint16_t x, uint16_t y, char character)

Draw a single character on the display.

Paint a single ASCII character on the display. Characters are always painted in the foreground color, with the background color as background fill.

The character is painted in the currently selected text size. The text is a monospaced font, width a minimum size of (5,3) per character. The origo of a character is the upper left corner of the (5,3) rectangle.

If you want write text on the screen, you should use the TextLabel view, or the Console view.

Parameters
  • x: The X coordinate of the characters upper left corner
  • y: The Y coordinate of the characters upper left corner
  • character: The text character to draw

void drawVLine(uint16_t x, uint16_t y1, uint16_t y2, bool background = false)

Helper function to draw a vertical line very fast. This method uses much less communication with the display.

*This method is automatically called by drawLine*

Parameters
  • x: The lines X coordinate (same for both end points)
  • y1: The first end points Y coordinate
  • y2: The second end points Y coordinate
  • background: Optional: Set this to true to paint in active background color

void drawHLine(uint16_t x1, uint16_t x2, uint16_t y, bool background = false)

Helper function to draw a horizontal line very fast. This method uses much less communication with the display.

*This method is automatically called by drawLine*

Parameters
  • x1: The first end points X coordinate
  • x2: The second end points X coordinate
  • y: The lines Y coordinate (same for both end points)
  • background: Optional: Set this to true to paint in active background color

void drawCircle(uint16_t x0, uint16_t y0, uint16_t r, bool background = false)

Paint an outlined circle.

Protected Functions

void swap(uint16_t &a, uint16_t &b)

Inline swap of two numbers.

Protected Attributes

mbed::FunctionPointer displayRefreshHandler

Handler for the DisplayControllers action queue, that gets triggered when the display refreshes.

This handler is normally used by the first View that gets contructed, to enable the re-paint queue.

IDisplayController
class mono::display::IDisplayController

Abstract Interface for display controllers like ILITEK chip etc.

This interface a simple set of function that display interface must implement.

Mono dislpay system build upon this interface, and all drawing is done through these functions.

You must override all the defined methods in this interface. The interface does not define or depend on a communication protocol, like parrallel or SPI.

Author
Kristoffer Andersen

Subclassed by mono::display::HX8340, mono::display::ILI9225G

Public Functions

IDisplayController(int width, int height)

Setup the display controller object, init vaiables and the screen size. The width is the horizontal measure, when mono is held in portrait mode.

This constructor should not transfer any data or initialize the display. You must do that in the init method.

Return
The display controller instance.
Parameters
  • width: The display width (horizontal) in pixels
  • height: The display height (vertical) in pixels

virtual void init() = 0

Initializes the hardware display controller.

Initalizing the hardware display controller means setting up the power, gamma control and sync options. The display should be ready to draw graphics when this method returns.

It is not nessasary to do any draw commands from this method, other classes will take care of clearing the screen to black, etc.

virtual void setWindow(int x, int y, int width, int height) = 0

Changes the current active window to a new rectangle.

The display controller must support windowing in software or in hardware. The window is the acrtive painting area of the screen, where you can paint. Upon drawing a single pixel the dispay cursor increments inside the window. This means you can sometime skip calls to the setCursor method.

Parameters
  • x: X-coordinate of the new windows upper left corner
  • y: Y-coordinate of the new windows upper left corner
  • width: The window width
  • height: The window height

void setRefreshHandler(mbed::FunctionPointer *handler)

Set the callback for display refreshes.

Set the callback function, that is called whenever the display has just repainted itself. This means it is time to repaint any dirty views, that needs to be updated.

IMPORTANT: You should re-paint graphics from within this callback, since it might run inside a hardware interrupt. It is better to just schedule the repaint from here.

Parameters
  • obj: The owner object of the callback method (the this context)
  • memPtr: A pointer to the owner objects callback member function

virtual void setCursor(int x, int y) = 0

Set the drawing cursor to a new absolute position.

Sets the current drawing cursor to a new position (must be within the cuurently active window).

When setting the cursor you must use absolute coordinates (screen coordinates), not coordinates inside the active window.

Parameters
  • x: The new X position (screen coordinates)
  • y: The new X position (screen coordinates)

virtual void write(Color pixelColor) = 0

Draw a pixel with the given color, at cursor position.

Write a pixel color to the display, at the cursor position. This method will automatically increment the cursor position.

If the increment happens automatically in hardware, the controller implementation must keep its own cursor in sync.

Parameters
  • pixelColor: The 16-bit 5-6-5 RGB color to draw

virtual void setBrightness(uint8_t value) = 0

Set the display backlight brightness. Higher values means more brightness. The display controller implementation might use a PWM to switch backlight LED’s.

Parameters
  • value: The brightness 0: off, 255: max brightness

virtual void setBrightnessPercent(float percent)

Set the display backlight brightness. Higher values means more brightness. The display controller implementation might use a PWM to switch backlight LED’s.

Parameters
  • percent: The brightness percentage, 0.00: off, 1.00: max brightness

virtual uint8_t Brightness() const = 0

Gets the current LES backlight brightness The display controller implementation might use a PWM to dim the display, this method returns the PWM duty cycle.

Return
The current brightness level in 8-bit format: 0: off, 255: max brightness

Public Members

uint32_t LastTearningEffectTime

The last tearning effect interrupt time (us_ticker_read())

To calculate the time since the last tearning effect interrupt (display refresh), you can use this member variable. On each interrupt this value is updated.

If too much time has passed between the interrupt occured and you handle the painting, you might want to skip the painting. THis is to avoid artifacts, when drawing on a refreshing display.

Any implementation of the IDisplayController must update this value in its tearning effect interrupt handler.

TextRender
class mono::display::TextRender

Text Render class to paint Text paragraphs on a DisplayController.

This is a Text glyph and paragraph render. It uses a bitmap based fonts and typesets the text to provide.

You need to provide the text render with either a DisplayPainter or IDisplayController that serves as a target for the text rendering.

The TextRender does not include any Font definitions. When you render your text, you need to provide a pointer to wither the MonoFont structure, or a Adafruit compatible GFXfont structure. One these is used as the rendered font.

Monospaced MonoFonts

Mono has its own monospace-only font format MonoFont

This renderer has a palette like DisplayPainter, and uses it the blend the semi-transparent pixels in the font anti-aliasing. The font bitmap defines pixel intensities, that are the foreground opacity.

The MonoFont defines the text size and the anti-aliasing quality. Some fonts has 2 bit pixels, others have 4 bit pixels.

Adafruit GFXfonts

TextRender can also work with Adafruits proportionally spaced fonts, that include many different styles: Sans, serif, plain, italic, bold and combinations of these.

This format is still bitmap based, but it does not used semi-transparent pixels to achieve anti-aliasing. The bitmaps are one bit per pixel.

Because coherent glyphs might overlap each others bounding rects, this format does not draw text backgrounds. Since this will overwrite overlapping areas of text glyphs.

Line Layouts

The text rendering has two modes: line layout or not. Line layout means a text line always has a fixed height: the line separation height. This is critically when rendering multiline text layouts. But single line text will appear off-centered in a vertically centered box. The reason is the line height is much higher than the visual center of the text glyphs.

If you need to render a single line of text at the center of a box, you want to not use line layout mode. In this mode, text dimension height are the distance from the texts hightest to lowest point.

Public Types

enum HorizontalAlignment

The horizontal text alignment, when rendering inside rects.

Values:

ALIGN_LEFT

Left justify text inside containing Rect

ALIGN_CENTER

Justify at center of containing Rect

ALIGN_RIGHT

Right justify text inside containing Rect

enum VerticalAlignmentType

The horizontal text alignment, when rendering inside rects.

Values:

ALIGN_TOP

Place text at the top of containing Rect

ALIGN_MIDDLE

Place text at the vertical center of containing Rect

ALIGN_BOTTOM

Place text at the bottom of containing Rect

typedef void (*charDrawFunction)(geo::Point &position, char character, const GFXfont &font, geo::Rect const &boundRect, int lineHeight)

Function interface that for character drawing routines

Public Functions

TextRender(IDisplayController *displayCtrl = 0)

Construct a TextRender that renders to a DisplayController Text Colors default to View::Standard colors.

Parameters
  • displayCtrl: A pointer to the display controller that is the render target

TextRender(IDisplayController *displayCtrl, Color foreground, Color background)

Construct a TextRender that renders to a DisplayController You provide explicit text colors.

Parameters
  • displayCtrl: A pointer to the display controller that is the render target
  • foreground: The text color
  • background: the background color

TextRender(const DisplayPainter &painter)

Construct a TextRender that renders to the DisplayController provided by a DisplayPainter. The painter current pencil colors are used for the text color.

Parameters
  • painter: The display painter to copy DisplayController and color palette from

template <typename Context>
void mono::display::TextRender::layoutInRect(geo::Rect rect, const String text, const GFXfont & fontFace, Context * self, void(Context::*)(const geo::Point &position, const GFXfont &font, const GFXglyph *gfxGlyph, geo::Rect const &boundingRect, const int lineHeight) memptr, bool lineLayout = true)

Layout the string in a rect, using af callback to handle characters.

This method will parse a text string and trigger a callback for each character, providing the position and allowed dimension of each character.

Parameters
  • rect: The rectangle to render in
  • text: The text string to render
  • fontFace: A pointer the Adafruit GFX font to use
  • self: A pointer to the callback method context object
  • memptr: A pointer to the callback method
  • lineLayout: Default: true, Render text as a multiline layout

void drawInRect(geo::Rect rect, String text, const MonoFont &fontFace)

Renders a text string in a provided Rectangle.

THis method paints / renders the text in bounding rectangle. The text is always rendered with origin in the rectangles top left corner. If the provided Rect is not large enough, the text is clipped!

Parameters
  • rect: The rectangle to render in
  • text: The text string to render
  • fontFace: A pointer the fontface to use

geo::Size renderDimension(String text, const MonoFont &fontFace)

Return the resulting dimension / size of some rendered text.

The final width and height of a rendered text, with the defined font face.

Parameters
  • text: The text to calculate the dimensions of
  • fontFace: The font to use

void drawChar(const geo::Point &position, const GFXfont &font, const GFXglyph *gfxGlyph, geo::Rect const &boundingRect, const int lineHeight)

Render a single Adafruit GfxFont character.

Parameters
  • position: The point where the glyph is rendered
  • font: The Adafruit GfxFont to use
  • gfxGlyph: The specific glyph to render
  • boundingRect: The Rect that limits the render canvas (no paints beyond this Rect)
  • lineHeight: The glyph height offset, to align glyphs on the same baseline

void drawInRect(const geo::Rect &rect, String text, const GFXfont &fontFace, bool lineLayout = true)

Renders a text string in a provided Rectangle.

THis method paints / renders the text in bounding rectangle. The text is always rendered with origin in the rectangles top left corner. If the provided Rect is not large enough, the text is clipped!

Parameters
  • rect: The rectangle to render in
  • text: The text string to render
  • fontFace: A pointer the Adafruit GFX font to use
  • lineLayout: Default: true, Render text as a multiline layout

geo::Size renderDimension(String text, const GFXfont &fontFace, bool lineLayout = true)

Return the resulting dimension / size of some rendered text.

The final width and height of a rendered text, with the defined font face.

Parameters
  • text: The text to calculate the dimensions of
  • fontFace: The font to use
  • lineLayout: Default: true, use line layout or not

mono::geo::Rect renderInRect(const geo::Rect &rect, String text, const GFXfont &fontFace, bool lineLayout = true)

Return the calculated offset of the text in the drawing Rect.

The offset is returned in absolute coords, not the relative coords inside the drawing rect. The offset matters for text that is aligned other than left and top.

Parameters
  • rect: The drawing Rect, that the text should be rendered inside
  • text: The text
  • fontFace: The GFXfont to use
  • lineLayout: Default: true, sets if lineLayout is used

void setForeground(Color fg)

Set the text color.

void setBackground(Color bg)

Set the background color. Transparent pixels will be blended with this color.

void setAlignment(HorizontalAlignment align)

Sets the texts justification within the drawing rect.

Parameters
  • align: The alignment

void setAlignment(VerticalAlignmentType vAlign)

Set the texts vertical alignment withnin the drawing rect.

Parameters
  • vAlign: The vertical alignment

Color Foreground() const

Get the current text color.

Color Background() const

Get the current text background color.

TextRender::HorizontalAlignment Alignment() const

Get the horizontal text alignment.

TextRender::VerticalAlignmentType VerticalAlignment() const

Get the vertical text alignment.

Protected Functions

void drawChar(geo::Point position, char character, const MonoFont &font, geo::Rect const &boundingRect)

Render a single MonoFont character.

int calcUnderBaseline(String text, const GFXfont &font)

Calculated the maximum offset under the text baseline.

This method returns the maximum offset under the baseline for some text. Some characters (glyphs) has parts under the baseline, examples are lower-case g, p, q and j.

To align all glyphs in a text line, the character with the largest undershoot is found and returned here.

Return
The maximum offset below the text baseline
Parameters
  • text: The text content to process font The font face to use

void writePixel(uint8_t intensity, bool bg = false)

Blend and emit a single pixel to the DisplayController.

uint32_t remainingTextlineWidth(const GFXfont &font, const char *text)

Returns the pixel width of the text provided.

This method is used in multiline text rendering, to get the width of a stand-alone line inside a multiline text blob. Unlike renderDimensions that gets the width of the longest line, this method get the length of the current line.

Return
The pixel width of the line
Parameters
  • font: The font face to use
  • The: C string text to get the current line from (until newline or end)

Geometry

Circle
class mono::geo::Circle

Inherits from mono::geo::Point

Point
class mono::geo::Point

Representation of a point in a 2D cartisian coordinate system. The point has no width or height, only an x-coordinate and a y-coordinate.

This class defines the coordinates, as well as methods to manipulate the point. Also functions for geometrical calculus is present.

Subclassed by mono::geo::Circle, mono::geo::Rect

Rect
class mono::geo::Rect

A Rectangle in a Cartesian coordinate system, having a size and position.

This class defines a geometric rectangle. It exists in a std. cartesian coordinate system. It is defined by its upper left corner (X,Y), and a width and height.

The rectangle cannot be rotated, its sides a parallel to the coordinate system axis.

It defines helper methods to calculate different positions and properties. You can also extract interpolation information.

See
Size
See
Point

Inherits from mono::geo::Point, mono::geo::Size

Public Functions

Rect(int x, int y, int width, int height)

Construct a rectangle from position coordinates and size.

Rect(const Point &p, const Size &s)

Construct a rectangle from Point and Size objects.

Rect()

COnstruct an empty rectangle having position (0,0) and size (0,0)

Point UpperLeft() const

Reutrn the position of the upper left corner.

This method is the same as casting the Rect to a Point

Return
The point of the upper left corner

Point LowerRight() const

Reutrn the position of the lower right corner.

Return
The point of the lower right corner

Point UpperRight() const

Reutrn the position of the upper right corner.

Return
The point of the upper right corner

Point LowerLeft() const

Reutrn the position of the lower left corner.

Return
The point of the lower left corner

class Point Center() const

Return the position of the Rectangles center.

void setPoint(class Point p)

Move (translate) the rectangle by its upper left corner.

void setSize(class Size s)

Set a new size (width/height) of the rectangle.

bool contains(class Point &p) const

Check whether or not a Point is inside this rectangle.

Rect crop(Rect const &other) const

Return this Rect cropped by the baundaries of another rect

mono::String ToString() const

Return a string representation of the ractangle.

Return
A string of the form Rect( x, y, w, h )

Size
class mono::geo::Size

Class to represent a rectangular size, meaning something that has a width and a height. A size class does not have any position in space, it only defines dimensions.

Subclassed by mono::geo::Rect

Public Functions

Size()

Construct a NULL size. A size that has no width or height.

Size(int w, int h)

Construct a size with defined dimenstions

Size(const Size &s)

Construct a size based on another size

Sensors

IAccelerometer
class mono::sensor::IAccelerometer

Abstract inteface for interacting with the accelerometer.

Subclassed by mono::sensor::MMAAccelerometer

Public Functions

virtual void Start()

Start the accelerometer.

Before you can sample any acceleration, you must start the accelerometer. When the accelerometer is running its power consumption will likely increase. Remember to Stop the accelerometer, when you are done sampling the acceleration.

virtual void Stop()

Stops the accelerometer.

A stopped accelerometer can not sample acceleration. Start the accelerometer before you sample any axis.

virtual bool IsActive() = 0

Return the current Start/Stop state of the accelerometer.

Return
true only if the accelerometer is started and sampling data

virtual int16_t rawXAxis(bool monoOrientation = true) = 0

<# brief desc #>

Return
<# return desc #>

virtual int16_t rawYAxis(bool monoOrientation = true) = 0

<# brief desc #>

Return
<# return desc #>

virtual int16_t rawZAxis(bool monoOrientation = true) = 0

<# brief desc #>

Return
<# return desc #>

IBuzzer
class mono::sensor::IBuzzer

Generic Buzzer interface.

This interface defines a generic API for buzzers used in the framework. You should not construct any subclass of this interface yourself. The system automatically creates a buzzer object for you, that you can obtain through the IApplicationContext:

Example

mono::sensor::IBuzzer *buzz = mono::IApplicationContext::Instance->Buzzer;

To make a short buzz sound do:

mono::IApplicationContext::Instance->Buzzer->buzzAsync(100);

Subclassed by mono::sensor::MonoBuzzer

Public Functions

virtual void buzzAsync(uint32_t timeMs) = 0

Buzz for a given period of time, then stop.

Sets the buzzer to emit a buzz for a defined number of milliseconds. Then stop. This method is asynchronous, so it returns immediately. It relies on interrupts to mute the buzzer later in time.

You should not call it multiple times in a row, since it behaves asynchronously. Instread use Timer to schedule multiple beeps.

Parameters
  • timeMs: The time window where the buzzer buzzes, in milliseconds

virtual void buzzKill() = 0

Stop any running buzz.

Use this method to cancel a buzz immediately. This method will not have any impact on callback functions. They will still be called, when the buzz was suppose to end.

template <typename Object>
void mono::sensor::IBuzzer::buzzAsync(uint32_t timeMs, Object * self, void(Object::*)(void) member)

Buzz for some time, and when done call a C++ member function.

Sets the buzzer to emit a buzz for a defined number of milliseconds. Then stop. This method is asynchronous, so it return immediately. It relies on the run loop to mute the buzzer later in time. You also provide a callback function, that gets called when the buzz is finished.

You should not call it multiple times in a row, since it behaves asynchronously. Instead you should use the callback function to make a new beep.

Example

buzzAsync<AppController>(100, this, &AppController::buzzDone);
This will buzz for 100 ms, then call buzzDone.

Parameters
  • timeMs: The time window where the buzzer buzzes, in milliseconds
  • self: The this pointer for the member function
  • member: A pointer to the member function to call

void buzzAsync(uint32_t timeMs, void (*function)(void))

Buzz for some time, and when done call a C function.

Sets the buzzer to emit a buzz for a defined number of milliseconds. Then stop. This method is asynchronous, so it return immediately. It relies on the run loop to mute the buzzer later in time. You also provide a callback function, that gets called when the buzz is finished.

You should not call it multiple times in a row, since it behaves asynchronously. Instead you should use the callback function to make a new beep.

Example

buzzAsync(100, &buzzDone);
This will buzz for 100 ms, then call global C function buzzDone.

Parameters
  • timeMs: The time window where the buzzer buzzes, in milliseconds
  • function: A pointer to the global C function to call

Protected Attributes

mbed::FunctionPointer timeoutHandler

A Handler to call when buzzing finished.

This member is setup when you provide a callback to the buzzAsync methods. Your subclass must call this when buzzing ends.

ITemperature
class mono::sensor::ITemperature

Abstract Interface for temperature sensors.

This interface creates a hardware-independent abstraction layer for interacting with temperature sensors. Any hardware temperature sensor in Mono must subclass this interface.

In Mono Framework these is only initialized one global temperature sensor object. To obtain a reference to the temperature sensor, use the IApplicationContext object:

ITemperature *temp = mono::IApplicationContext::Instance->Temperature;

This object is automatically initialized by the IApplicationContext and the current ITemperature subclass. IT is the IApplicationContext‘s job to initialize the temperature sensor.

Subclassed by mono::sensor::AT30TS74Temperature, mono::sensor::Edu1, mono::sensor::PCT2075Temperature

Public Functions

virtual int Read() = 0

Reads the current temperature from the temperature sensor

Return
the temperature in Celcius

virtual int ReadMilliCelcius()

Reads the temperature in fixed point milli-Celcius.

To get a higher precision output, this method will return milliCelcius such that: 22,5 Celcius == 22500 mCelcius

Return
The temperature in mCelcius

Power

IPowerManagement
class mono::power::IPowerManagement

Generic abstract interface for the power management system.

A PowerManagement implementation class handles power related events and sets up the system. The ApplicationContext object initializes an instance of this class automatically. Use can find a pointer to the PowerManagement object in the static IApplicationContext class.

Depending on the system (mono device or simulator), the concrete sub-class implementation of this interface varies.

The active IApplicationContext initializes this class and calls its POR initialization functions. Implementations of this class then calls and initializes any nessasary related classes, like the power supply IC sub-system (IPowerSubSystem).

This interface defines queues of objects that implement the IPowerAware interface. This interface lets classes handle critical power events like:

  • Power-On-Reset (POR): Called when the chip powers up after a reset
  • Enter Sleep Mode: Called before system goes in to low power sleep mode
  • Awake From Sleep: Called when nornal mode is restored after sleep

Power Awareness

Classes that handle components like I2C, Display, etc can use the PowerAware interface to receive these type of events. Its the PowerManagement object task to call these IPowerAware objects.

The interface defines a protected member object powerAwarenessQueue that is a pointer to the first object in the queue. The Power Awareness Queue is a list of objects that implment the IpowerAware interface and have added themselves to the queue by calling AppendToPowerAwareQueue

Objects in the queue receive power aware notifications on event like enter sleep mode, wake from sleep and battery low. You can add your own objects to the queue to make them “power aware” or you remove the system components that gets added by default. (But why would you do that?)

Subclassed by mono::power::MonoPowerManagement

Public Functions

virtual void EnterSleep() = 0

Send Mono to sleep mode, and stop CPU execution. In sleep mode the CPU does not excute instruction and powers down into a low power state. The power system will turn off dynamically powered peripherals.

Any power aware objects (IPowerAware), that has registered itself in the powerAwarenessQueuemust have its onSystemEnterSleep method called.

NOTE: Before you call this method, make sure you have configured a way to go out of sleep.

virtual void AppendToPowerAwareQueue(IPowerAware *object)

Add a IPowerAware object to the awareness queue

By added object to the Power Awareness Queue they receive callbacks on power related events, such as reset and sleep.

Parameters
  • object: A pointer to the object that is power aware

virtual bool RemoveFromPowerAwareQueue(IPowerAware *object)

Remove an object from the Power Awareness Queue.

Searches the Power Awareness Queue for the object and removes it, if it is found. This object will no longer receive power related notifications.

Return
true if object was removed, false if the object was not in the queue
Parameters
  • object: A pointer to the object that should be removed from the queue

Public Members

IPowerSubSystem *PowerSystem

A pointer to the initialized power sub-system. This is initialize automatically and depends on compiled environment. The power system to used to control power supply to periphirals and to give interrupt on power related events.

WARNING: Use this class with extreme caution! Wrong power settings can fry the MCU and other peripherals!

Public Static Attributes

volatile bool __shouldWakeUp = false

This variable must be true before sleep mode is aborted.

EnterSleep() must set this to false, you should set it to true to abort sleep mode and re-enter the run loop execution. EnterSleep() will not return before this is set to true.

**Note: The class QueuedInterrupt will set this automatically!**

volatile bool __busySleep = false

Global flag to indicate to not halt CPU during sleep mode.

Some processes might require hardware to run async under what is normally sleep mode, where hardware peripherals are halted.

Set this flag to true to keep the the CPU awake inside the sleep mode loop. This is especially useful when handled debouncing of edge triggered interrupts.

Note: You should keep this flag false to ensure power presevation

Protected Functions

virtual void processResetAwarenessQueue()

Call all the power aware objects right after Power-On-Reset The singleton power management object must call this method on reset

Protected Attributes

IPowerAware *powerAwarenessQueue

A pointer to the top object in the Power Awareness Queue

The Power Awareness queue is realized by having the power object themselves hold references to the next and previous object in the queue. This eliminates the need for dynamic memory allocation a runtime.

The IPowerAware interface defines the next and previous pointers for the object in the linked list. This class only holds a reference to the first object in the queue.

IPowerSubSystems

Warning

doxygenclass: Cannot find class “mono::power::IPowerSubSystems” in doxygen xml output for project “monoapi” from directory: xml

mbed API

If you need to interact with the GPIO, Hardware interrupts, SPI, I2C, etc. you should use the mbed layer in the SDK. Take a look at the documentation for mbed:

mbed documentation

Direct Download

Go straight to our download page: Download SDKs

Implementation status

As with this site, the software is also being finished right now. The current status page include a list of all the planned features of the framework - and their implementation status:

Contribute

The source to this documentation is available publicly on our GitHub. Please just fork it, correct all our bad engrish - and submit a pull request. We would just loooove that!

You can contribute to this documentation through the GitHub repository. Note that everything you contribute will be free for anyone to use because it falls under the site license.

What is Mono anyway?

Haven’t you heard the word? Mono is an embedded hardware platform that brings all the goods from Arduino and mbed to a whole new level! No fiddling with voltage levels, open-drain vs pull-up configurations. We take care of all this low-level stuff for you. You just focus on building your application, taking advantage of all the build-in hardware functionalities - like:

  • Arm Cortex-M3 MCU
  • Touch display
  • Battery
  • Wifi
  • Bluetooth
  • Accelerometer
  • Temperature Sensor
  • SD Card
  • General Purpose 3.5mm jack connector

On this developer documentation site, you learn how to use all these features through our high-level API.