Create your own mobile application for the MediaTek Linkit ONE

Andreas LundquistBlogs, Tutorials

Tweet about this on TwitterShare on FacebookShare on LinkedInShare on Google+

mediatek-linkit-one
The Internet of Things is a reality. Right now there are an estimate of 19 million developers in the software development industry, of which 19% are involved in IoT and the numbers are growing rapidly. Within a couple of years we will be surrounded by products connected to the Internet. The LinkIt ONE has been developed by MediaTek, a fabless semiconductor company providing Systems on Chip (SOC) for wireless communications and connectivity. In this tutorial we will get a chance to explore what the MediaTek LinkIt ONE brings to this space. You will learn how to use the built-in WiFi and GPS chipset to deliver the position of the board to a mobile application using a small HTTP server.

Overview

The LinkIt ONE development board is equipped with MediaTek Aster (MT2502) SOC which, according to MediaTek, is the worlds smallest system-on-chip for wearables. It supports GSM, GPRS and Bluetooth LE wireless communication capabilities. The board is also equipped with two companion chipsets; MT5931 (WiFi) and MT3332 (GPS). It is also capable of sending and receiving SMS, play audio files, transfer data over bluetooth and read and write data on a SD card. An interesting feature is that the board is prepared to be powered using a battery. The development kit even comes with a 1000 mAh battery and there are APIs available to get the battery level and charging state.

Compared to other development kits aimed at the maker community the LinkIt ONE is powerful. The microprocessor is a ARM7 EJ-S which runs at 260 MHz. That is roughly fifteen times faster than an ordinary Arduino Uno. It also has 4MB of RAM and 4MB of flash memory so there is no need to worry about code size.

If you are curious to learn more about the LinkIt One MediaTek has an excellent developers guide that covers almost everything you need to know in order to start working with their hardware. You can find the guide here.

Source Code

You can browse the source code for this tutorial in the Evothings GitHub repository.

What you need

  • MediaTek LinkIt ONE with GPS antenna & WiFi antenna connected.
  • An iOS or Android smartphone.
  • A computer running Microsoft Windows.

Step 1 – Hardware

This tutorial does not require you to build any external circuits at all. However you need to ensure that you connect the GPS and WIFI antenna to the development board according to the picture below. Only the GPS and Wi-Fi antenna is needed in this tutorial.

mediatek-linkit-one-antenna

Step 2 – Embedded software

Preparation

If you already have installed the LinkIt SDK you can skip this step.

Before you can start compiling and downloading your software to the board you need to setup the development environment. MediaTek provides an executable that installs all libraries and drivers needed. There is also a detailed step-by-step guide to walk you through the process.

As for now only Windows is supported. MediaTek has announced future support for Mac OS X and Linux.

Source code

This application is a small web server that responds with a JSON object containing the current position regardless of what request it receives. The application is based on two examples (WifiWebServer.ino, GPS.ino) provided by MediaTek that has been merged and modified minimalistically to suit our needs.

In order to run the application you need to change the WIFI_AP to the name of your access point and the WIFI_PASSWORD to the password of your access point. You also have to provide the encryption of your network in the WIFI_AUTH define.

In the setup() function the wifi, gps and serial functionality are enabled. You can see the setup function below.

void setup()
{
  LTask.begin();
  LWiFi.begin();
  Serial.begin(115200);
  LGPS.powerOn(GPS_GLONASS);
  delay(2000);
}

In the loop() function the logic of the application is defined. It consists mainly of three parts, one part to ensure that the board is connected to the provided wifi, one part that fetches the position from the GPS chip and the last part that handles any request.

First let us look more in detail on the part that ensures that the board is connected to the wifi. The logic behind this functionality is defined in the function connectToAccessPoint(). The function first checks to see if it is connect to the access point, if not it will try to connect to it until it succeeds. Once connected to the wifi it will start the server that listens for TCP connections on port 80 and print information about the connection. You can see the implementation below:

void connectToAccessPoint()
{
  while (LWiFi.status() != LWIFI_STATUS_CONNECTED)
  {
    if (LWiFi.connect(WIFI_AP, LWiFiLoginInfo(WIFI_AUTH, WIFI_PASSWORD)))
    {
      server.begin();
      printWifiStatus();
    }
    else
    {
      Serial.println("Error - failed to connect to WiFi");
    }
  }
}

The second part of the code fetches the position, parses the result and stores the positions to the global variables latitude and longitude. We added a scheduling that fetches the position once every 5 seconds. Fetching the position requires three steps, fetch data from GPS chip (LGPS.getData()), parse the result (parseGPGGA()) and finally convert the position to decimal form (convertPostionToDecimalForm()). The parseGPGGA() function has been modified to write the results to global variables instead of local ones. The result from the parseGPGGA() function has to converted from GPGGA format to decimal format. You can read more about that conversion here. The implementation is provided below.

if (millis() - lastGPSReadTimestamp > gpsReadInterval)
{
  LGPS.getData(&gpsData);
  parseGPGGA((const char*)gpsData.GPGGA);
  convertPositionToDecimalForm();
  lastGPSReadTimestamp = millis();
}

The final part of the application sends a JSON-object as response to TCP requests made on port 80. In essence the application awaits a connection and when there is one present it reads every byte in the request until it has received an empty line followed by an ‘\n’. Then the application responds with a JSON object containing the position from the GPS chip.

Compared to the WifiWebServer tutorial mentioned previously we have modified two parts. First we modified the response. The “Content-Type” header was changed to “application/json” and the “Refresh” header was removed. Also the header “Access-Control-Allow-Origin: *” was added to the response. This is to enable cross domain requests using jQuery which is not usually allowed.

The other change is that we added a timeout that disconnects the client if there is a delay greater than 1 seconds between bytes received in the request. The implementation can be seen below.

LWiFiClient client = server.available();

if (client)
{
  Serial.println("new client");

  // an http request ends with a blank line
  boolean currentLineIsBlank = true;
  uint32_t lastReceptionTime = millis();
  while (client.connected())
  {
    if (client.available())
    {
      // we basically ignores client request, but wait for HTTP request end
      int c = client.read();
      lastReceptionTime = millis();

      Serial.print((char)c);

      if (c == '\n' && currentLineIsBlank)
      {
        Serial.println("send response");

        // send a standard http response header
        client.println("HTTP/1.1 200 OK");
        client.println("Content-Type: application/json");
        client.println("Connection: close");  // close connection after completion 
        client.println("Access-Control-Allow-Origin: *");
        client.println();
        client.print("{\"long\":\"");
        client.print(longitude, 8);
        client.print("\", \"lat\":\"");
        client.print(latitude, 8);
        client.print("\"}");
        client.println();
        break;
      }
      if (c == '\n')
      {
        // you're starting a new line
        currentLineIsBlank = true;
      }
      else if (c != '\r')
      {
        // you've gotten a character on the current line
        currentLineIsBlank = false;
      }
    }
    else
    {
      if (millis() - lastReceptionTime > requestTimeout)
      {
        Serial.println("Error - client timeout, dropping connection...");
        break;
      }
    }
  }

  // give the web browser time to receive the data
  delay(500);

  // close the connection:
  Serial.println("close connection");
  client.stop();
  Serial.println("client disconnected");
}

There is also a couple of helper functions which is not covered here since they are not essential.

Step 3 – Mobile application

Preparation

If you already have a fully working copy of Evothings Studio you can skip this step.

First you have to install the Evothings Studio on your computer. The Evothings Studio consists of two softwares that interacts with each other. You have to install Evothings Workbench on you computer. The software provides you with the interface in which you will perform your development. You also have to install the Evothings Client (iOS, Android) on your smartphone. The client will connect to the workbench and execute the mobile application.

In order to utilize the Google Maps JavaScript API v3 you need to create an API key. Google describes how to do that here. The API is used to display the position of the LinkIt ONE.

Source code

The application fetches the position of the LinkIt ONE from the web server and displays the position on a map.

The application consists of three files, index.html which contains all the code connected to the user interface, app.css which contains the style sheets of the application and last, app.js which contains all the logic of the application.

mediatek-linkit-one-startView

The user interface consists of three views, startView, connectingView and mapView. The startView, see above contains the initial view that is displayed to the user when the application is launched. It makes it possible to connect to the LinkIt ONE board using the IP address. The connectingView is displayed when the user tries to connect to the board. And finally the mapView, which is displayed once the application retrieved a response from the LinkIt ONE board. It contains the map view from the Google Maps API and a disconnect button.

The app.initializeMap() method is executed when the application and all of its resources has been fully loaded. The method initializes the map provided by the Google Maps JavaScript API. The code that ensures that this happens is placed within the in the index.html and provided below.

When you press the connect button in the connectingView the method app.connect() is executed. The method hides the connectingView and shows the connectingStatus view. It also defines a recurring timer of 10 seconds, which executes the app.fetchData() method when expiring. And finally the method executes the app.fetchData(). The implementation is provided below.

app.connect = function() 
{
  app.IPAdress = $('#IPAdress').val()

  $('#startView').hide()
  $('#connectingStatus').text('Connecting to ' + app.IPAdress)
  $('#connectingView').show()

  console.log('Trying to connect to ' + app.IPAdress)

  app.fetchTimer = 
    setInterval(function() { app.fetchData() }, app.TIME_BETWEEN_REQUESTS)

  app.fetchData()
}

The method app.fetchData() is simply a wrapper that calls the getJSON() method using the app.dataRecived() method as the callback. See the following code:

app.fetchData = function()
{ 
  console.log('Trying to fetch data...')

  $.getJSON('http://' + app.IPAdress, app.dataReceived) 
}

mediatek-linkit-one-mapView

When a response is received it is handled by the method app.dataReceived(). First the method shows the view connectingView, see above, if it is visible. It also triggers the event “resize” in the Google Maps API which ensures that the map is redrawn to fit the div. Then the actual data is extracted from the JSON-object which looks like this:

{"long":18.0374, "lat":59.2030}

The getJSON() method parses and turns the response into a JavaScript object automatically. The extracted longitude and latitude is then used to create a new marker that is added to the Google map view which is centered around the marker. The implementation looks like this:

app.dataReceived = function(data, textStatus, xhr)
{
  if ($('#mapView').css('display') == 'none') 
  {
    $('#connectingView').hide()
    $('#mapView').show()

    google.maps.event.trigger(app.map, "resize")
    console.log('Showing off')
  }

  // Read response
  var longitude = data['long']
  var latitude = data['lat'] 

  console.log('Received data - Latitude: ' + latitude + ', Longitude: ' + longitude)

  // Remove current marker if available.  
  if (app.marker) 
  {
    app.marker.setMap(null)
  }

  // Create a new parker and add it too map.
  var markerPosition = new google.maps.LatLng(latitude, longitude)
  app.marker = new google.maps.Marker({ position: markerPosition })
  app.marker.setMap(app.map)

  // Center map around the marker.
  app.map.panTo(app.marker.getPosition())
}

If you press the disconnect button the <code<app.disconnect() method is executed. It cancels the running timer and hides the mapViewstartView. See the code below.

app.disconnect = function()
{
  clearInterval(app.fetchTimer)

  $('#mapView').hide()
  $('#startView').show()
}

The application logic is based around a timer that executes the method app.fetchData() once every 10 seconds. The method simply makes a request to the development board using the jQuery method getJSON(). See the following code.

Summary

This tutorial shows how you easily can build your own mobile application that fetches data from your LinkIt ONE using the WiFi interface. There is no time to spare, get a LinkIt ONE and download the source code and Evothings Studio and start to explore the endless possibilities. The tutorial should provide a great starting point for any connected LinkIt ONE project.

We can not wait to see what you create, please share your creations with either @evothings or our forum.

Happy tinkering!