Introduction: Sigfox GPS Tracker

You may have wondered how GPS trackers work. At the end of this tutorial, you will be able to have a fully functional GPS tracker that sends data to your server. The use cases are endless, from tracking your pets or your shipments to tracking your motorbike, your boat or your drone. Feel free to share what you are tracking, it might give others great ideas!

What will be covered by this tutorial?

We will be using the TD1205P device (it should work also with TD1204 but I haven't tested and it has a different shape) from Telecom Design using Sigfox network.

Note that at the time I wrote the tutorial, the TD1205P was not officially released. We had the chance to test it before its official release.

Thus, we will see how to get started with Telecom Design SDK, how to download the sources, configure your laptop. We will also see how GPS works and how to request a GPS fix, how Sigfox works, how to encode the GPS fix into a Sigfox message (12 bytes) and send it, how to use the Sigfox bidirectional functionality to configure your device, how to set a callback in Sigfox's backend to send the data to your server.

What is Sigfox?

Sigfox is a connectivity solution dedicated to the Internet of Things. The operated network is currently operating in +22 countries, on every continent. Focused on tiny messages (up to 12 bytes) & low energy consumption, it currently powers 7 million devices. Various Sigfox-compatible technical solutions are available, from different silicon vendors.

Subscriptions to the Sigfox service are free for developers ( development kits & evaluation boards). Otherwise, they range between 1€/month & 1€/year depending on the volume commitment.

This project uses a TD1205 device from Telecom Design.

Ready to get started? Let's go!

Any skills required?

In my point of view, if you follow this tutorial, you should be able to reproduce it. However, knowing some basics of C programming will be a real plus. We will see in details what the code does and I commented the code to understand every step. Do not hesitate to leave a comment for the parts you don't understand if I haven't been clear enough.

This tutorial is quite long but will cover every step.

Who am I?

My name is Louis Moreau, I'm an intern at Sigfox. My role is to create prototypes and PoC using Sigfox network. I want these projects to be fun and instructive. I want to show you that it is easy to develop the first steps of your ideas. I will try to make this tutorial as complete as I can. Do not hesitate to ask me for more details if needed.

Contribution

I would like to thank Telecom Design (manufacturer of the device) and especially Jérôme Guerin, his precious time helped me to resolve many issues.

Step 1: Hardware

The easiest way to get the hardware is to buy a Telecom Design EVB:

Make sure to order one with a TD1204 or TD1205P, these two models include a GPS chip. The EVB include:

In order to have a fully functional device, you will also need a battery. You can use a LiPo or a small battery (no more than 3.7V).

Step 2: Get Started With Telecom Design SDK

These next parts are surely the hardest parts. I had many troubles to get started with the TD SDK. Not to mention that it is only for Windows OS... However, as I encountered many of the issues related on the td-next community forum, I will try to be as clear and illustrative as possible.

Get access to the Github repository

The first thing you need to do is to have access to the Github repository. To do so, you can follow the few steps on http://rfmodules.td-next.com/sdk/

I will still explain the steps with some screenshots:

Now you should have access to the private Github repository. When you have a look at the README.md documentation, here is what it is said.

The first parts are pretty simple, I did not get any trouble. However, when it came to the compiling part I found it way harder. I'll do a dedicated step for the compilation where I will try to add many screenshots.

Download the toolkits

You can get it on: https://s3-eu-west-1.amazonaws.com/assetstdnext/d...

Note that you have to unzip in C:/ (Windows root) otherwise it won't work.

Get the sources

The following steps detail how to download the source code and import all projects into the Eclipse environment.

  1. Navigate to the "C:\TD\TD_RF_Module_SDK-v6.0.0\eclipse" folder and double-click on the "eclipse.exe" icon
  2. Open the "File" menu and select the "Import..." item.
  3. In the "Import" dialog, unfold the "Git" folder by clicking on the "+" sign left to it, select the "Projects from Git" item and click on the "Next >" button
  4. In the "Import Projects from Git", select the "URI" icon ad click on the "Next >" button
  5. Enter The Github repository URL "https://github.com/Telecom-Design/TD_RF_Module_SDK.git" in the "URI" field
  6. Enter your Github username and password in the "User:" and "Password:" fields, respectively and click on the "Next >" button
  7. Check the "Master" branch box and click on the "Next >" button
  8. Enter "C:\TD\TD_RF_Module_SDK-v6.0.0\Github\TD_RF_Module_SDK" in the "Directory:" field and click on the "Next >" button
  9. Check the "Import existing projects" radio button and click on the "Next >" button
  10. Click on the "Finish" button. The Git import will take place, this may take a while

All the available libraries and examples should now be available in the Project Explorer panel.

Organise the sources

By default, all projects are presented in Eclipse at the same level without particular organisation except that they are sorted alphabetically.

In order to have a more logical organisation, we must import an Eclipse "Working Set" that will provide a grouping of projects by categories.

To do so, launch Eclipse by navigating to the "C:\TD\TD_RF_Module_SDK-v6.0.0\eclipse" folder and double-click on the "eclipse.exe" icon (if not already done) and:

  1. Open the "File" menu and select the "Import..." item.
  2. In the "Import" dialog, unfold the "General" folder by clicking on the "+" sign left to it, select the "Working Sets" item and click on the "Next >" button
  3. Enter "C:\TD\TD_RF_Module_SDK-v6.0.0\Github\TD_RF_Module_SDK\TD_RF_Module_SDK.wst" in the "Browse..." field, check all working sets and click on the "Finish" button
  4. Click on the small downwards arrow in the top-right corner of the "Project Explorer" panel and select the "Select Working Sets..." item
  5. In the "Select Working Sets" dialog, click on the "Select All", then on the "OK" button
  6. Click on the small downwards arrow in the top-right corner of the "Project Explorer" panel again and select the "Top Level Elements > Working Sets" item

All the available libraries and examples should now be better organised in the Project Explorer panel.

Step 3: (Re)set the Device With the Original Firmware

In the unfortunate event where anything works, you may need to reset the device to its original state (yes, I had to do it a few times :p).

Here is the procedure:

Easiest way:

  • Download the TDLoader.exe program:
    https://developers.insgroup.fr/downloads/TDLoaderV...
  • Select the original firmware and click on acquire
    In my case, this method did not work... I had some different errors such as "could not initialize COM port" or "SRAM error". Don't worry there are other ways :)

Another way:

  • Open the program under:C:\TD\TD_RF_Module_SDK-v6.0.0\energymicro\energyAware Commander\eACommander.exe
  • Click on connect
  • Go to "Kit" tab and set the parameters as in the screenshots (Out)
  • Go to "Flash" tab and select the original firmware
  • Click on Flash EFM32

I had an issue where even this step did not work. To solve this problem, I had to do a small trick on the evaluation board as it is said in this document page 5: https://github.com/Telecom-Design/Documentation_TD...

You have to solder the evaluation board as it is described (see the pictures for a visual -> don't judge me about my soldering skills please)

Right now you should have a fully functional TD1205P. Now we will access it using AT commands and send our first Sigfox message. Ready?

Step 4: Send Your First Sigfox Message

Before we try to compile anything, we will do one first test to check if everything works fine.

Note that if you already have uploaded a custom firmware it won't work, but you still can upload again the official firmware to make these tests (see the previous step). The names of these firmware are "like td120X_modem_SOFTXXXX.bin"

We will try to send a simple Sigfox message saying 01CAFE (in hex). We will try to do so using the AT commands:

  • Plug the FTDI cable to your laptop
  • Check on which COM port the FTDI cable is: Go to "Windows" and search "device manager"
  • Open the C:\TD\TD_RF_Module_SDK-v6.0.0\putty\putty.exe program
  • Click on serial radio button
  • Go to the serial tab
  • Set the parameters as they are in the screenshot (Baud rate: 9600, parity: none and flow control: none)
  • Click on "Open"

Now, plug the TD1205P to your EVB.

On the Putty terminal:

Hit AT&V, you should see the result with some information (as you may see on the screenshot).

Now hit AT$SF=01CAFE the result should be "OK".

Let's see what your message look like in Sigfox backend.

Step 5: View Your Message in Sigfox Backend

If you don't have an account yet, please contact subscribe@sigfox.com

It has not been automatized yet but hopefully, it should become easier in the near future...

Once you have access to your devices, go to "device" and select your device by clicking on its id.
Then, you will see its information, on the left-hand menu, click on "message". Here you go you should see the message sent by the device.

Now I would suggest that you stop for a coffee, next parts are going to be tricky... But please come back!

Step 6: Import Project

All the sources are available on https://github.com/luisomoreau/sigfox_gps_tracker

Import the "Sigfox GPS Tracker" project

Open the "File" menu and select the "Import..." item.

  1. In the "Import" dialogue, unfold the "Git" folder by clicking on the "+" sign left to it, select the "Projects from Git" item and click on the "Next >" button
  2. In the "Import Projects from Git", select the "URI" icon ad click on the "Next >" button
  3. Enter The Github repository URL "https://github.com/luisomoreau/sigfox_gps_tracker.git" in the "URI" field
  4. Enter your Github username and password in the "User:" and "Password:" fields, respectively and click on the "Next >" button
  5. Check the "Master" branch box and click on the "Next >" button
  6. Enter "C:\TD\TD_RF_Module_SDK-v6.0.0\workspace" in the "Directory:" field and click on the "Next >" button
  7. Check the "Import existing projects" radio button and click on the "Next >" button
  8. Click on the "Finish" button.
  9. You can also create a workspace called "Tutorial"and add the project to this workspace.

Step 7: Compile the Sources

Ok right now comes the hard part. I had many troubles while compiling. I will try to overcome most of the issues and how to solve it.

Add the environment variables

With the exception of the binary-only static libraries in the "libtddrivers" and "libtdrf" projects, all deliverables are presented in source form only, and must be compiled to obtain an executable firmware. To compile properly you must add the GCC path into your Eclipse environment variables by opening:

Window -> Preferences -> C/C++ -> Build -> Environment -> Add...

Please add the PATH variable with the following value:

"C:\TD\TD_RF_Module_SDK-v6.0.0\gnu\bin;"

and "C:\TD\TD_RF_Module_SDK-v6.0.0\gnu\arm-none-eabi\bin"

At first, I had imported only the first path "C:\TD\TD_RF_Module_SDK-v6.0.0\gnu\bin" as it was suggested in the Telecom-Design' s Github repository but I had some troubles when compiling. Thus I strongly advise to add both paths. (See screenshot for the error logs)

Edit 10th October 2016: It appears that eclipse stores some cached data, try to clean the projects first and you should be able to compile it without adding any environment variables...

Compiling for TD1204 and TD1205

I haven't tested these devices but you should be able to make it work if you follow the official procedure:

  1. In order to avoid unnecessary rebuilds of the common libraries, it is best to set the right build configuration for all these libraries: unfold the "Common_Libraries" working set in the Project Explorer panel on the left side, then select all the projects by clicking on the first one in the list, pressing the "SHIFT"key, then clicking on the last one in the list
  2. Click on the small downwards arrow right next to the "Hammer" icon in the top menu bar and select the right build configuration corresponding to your board: "TD1204 or TD1205""GCC Release (EFM32G210F128)" for a stripped down firmware
  3. Open the file "sigfox_gps_tracker.c"
  4. Click again on the small downwards arrow right next to the "Hammer" icon in the top menu bar and select the same build configuration as for the libraries above ("TD1205P")
  5. Compilation of the "sigfox_gps_tracker"project and all the required dependencies will take place, which can be monitored in the "Console" tab of the bottom panel.

Compiling for TD1205P

The TD1205P was not officially released when I wrote the tutorial, you should be able to compile the project for the TD1205P with this project (configuration is included in this repository). However, if you wish to go back from scratch, few tricks will be needed.

Then if we take this project as an example, here are the steps required to compile it:

  1. In order to avoid unnecessary rebuilds of the common libraries, it is best to set the right build configuration for all these libraries: unfold the "Common_Libraries" working set in the Project Explorer panel on the left side, then select all the projects by clicking on the first one in the list, pressing the "SHIFT"key, then clicking on the last one in the list.
  2. Click on the small downwards arrow right next to the "Hammer" icon in the top menu bar and select the right build configuration corresponding to your board: "TD1205P""GCC Release EZR" for a stripped down firmware.
  3. Unfold the "Tutorial" working set in the Project Explorer panel on the left side, then select the "sigfox_gps_tracker" project
  4. Click right on the project and select "Properties".
  5. Go to C/C++ build -> Build variable. Make sure that the TD1205P appear. If not you can create it by clicking on "Manage Configuration" -> "New" -> add "TD1205P Release" and copy the "TD1508" configuration. Then go to "Settings"->"Preprocessor" and replace the revision with "MODULE_REVISION=REVISION_TD1205P". Make sure you do it for both preprocessors tab (under assembler and compiler).
  6. Click on OK
  7. Open the file "sigfox_gps_tracker.c"
  8. Click again on the small downwards arrow right next to the "Hammer" icon in the top menu bar and select the same build configuration as for the libraries above ("TD1205P")
  9. Compilation of the "sigfox_gps_tracker"project and all the required dependencies will take place, which can be monitored in the "Console" tab of the bottom panel.

The same procedure can be used for all the example projects when required.

Other encountered issue

Note that this may occur only with the TD1205P version.

I had an error with the _cs3_interrupt_vector_em (see screenshots) and it took me a pretty long time to solve. I proposed a pull request on Github official repository to solve this. I don't know neither if it will be accepted nor when. Thus, to solve it you can follow the very simple procedure:

Change the name of this file :

C:\TD\TD_RF_Module_SDK-v6.0.0\Github\TD_RF_Module_SDK\lib\Device\EnergyMicro\EFM32LG\Source\G++\startup_efm32lg.s

By:

C:\TD\TD_RF_Module_SDK-v6.0.0\Github\TD_RF_Module_SDK\lib\Device\EnergyMicro\EFM32LG\Source\G++\startup_efm32lg.S

Yes, just change the extension with an upper S... :/

Step 8: Code Explanation

What is the code doing?

Basically, we wanted a GPS tracker that sends the GPS coordinates every hour. However, we were not certain about the battery consumption, thus we wanted to be able to configure the device to send the coordinates every 2, 3, 6, 24 hours if needed (after our tests).

We did not want either to let the GPS switch on for a too long time if no GPS fix was available. Thus we wanted to be able to configure the GPS timeout.

We wanted to know the battery level, the speed and the precision hdop and the number of satellites received) .

We also wanted to be able to encrypt the Sigfox payload if needed.

Payload encoding

Here is how the payload is encoded:

  • Byte 0: Lat
  • Byte 1: Lat
  • Byte 2: Lat
  • Byte 3: Lat
  • Byte 4: Long
  • Byte 5: Long
  • Byte 6: Long
  • Byte 7: Long
  • Byte 8:
    Voltage between 0 and 3825 with a 15mV step

  • Byte 9:
    Hdop on the first 2 bits (0 if <1; 1 if < 2; 2 if <5; 3 if >5)
    Number of satellites received on the 2 next bits (0 if <3, 1 if <6; 2 if <8; 3 if >8)

  • Byte 10:
    Acquisition time between 0 and 75s with a 5s step on the 4 first bits
    Speed in km/h between 0 and 155km/h with a 5km/h step on the 4 last bits
  • Byte 11: Empty

Code

Now let's have a deeper look into the code in sigfox_gps_tracker.c, especially at the comments for a better understanding:

/******************************************************************************
 * @file
 * @brief Simple GPS periodic fix application for the TDxxxx RF modules.
 * @author Telecom Design S.A.
 * @version 1.1.0
 ******************************************************************************
 * @section License
 * <b>(C) Copyright 2014-2015 Telecom Design S.A., <a> http://www.telecomdesign.fr
</a>>
 ******************************************************************************
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 *
 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Telecom Design SA has no
 * obligation to support this Software. Telecom Design SA is providing the
 * Software "AS IS", with no express or implied warranties of any kind,
 * including, but not limited to, any implied warranties of merchantability
 * or fitness for any particular purpose or warranties against infringement
 * of any proprietary rights of a third party.
 *
 * Telecom Design SA will not be liable for any consequential, incidental, or
 * special damages, or any other relief, or for any claim by any third party,
 * arising from your use of this Software.
 *
  ******************************************************************************/

#include "config.h"

#include <stdint.h>
#include <stdbool.h>

#include <efm32.h>

#include <td_core.h>
#include <td_uart.h>
#include <td_printf.h>
#include <td_stream.h>
#include <td_flash.h>
#include <td_scheduler.h>
#include <td_watchdog.h>
#include <td_gpio.h>
#include <td_utils.h>
#include <td_measure.h>

#include <td_sensor.h>
#include <sensor_data_geoloc.h>

#include <td_accelero.h>
#include <td_geoloc.h>
#include <td_sigfox.h>

#include <td_config.h>

/*******************************************************************************
 ******************************  DEFINES ****************************
 ******************************************************************************/

/** Flash variable version ID */
#define VARIABLES_VERSION 0

// Interval at which position is reported (in seconds)
#define FIX_INTERVAL 1*3600 // Send a Sigfox message every 1 hour

/** Boot monitoring, 1 to enable */
#define BOOT_MONITORING 0

/** Keepalive monitoring interval in hours, 0 to disable
 * If you wish to send a keepalive frame remember to add a scheduler as well in the setup function */
#define KEEPALIVE_INTERVAL 0

#define DEBUG_USE_PRINTF 0 //trace on serial
#if DEBUG_USE_PRINTF
	#define DEBUG_PRINTF(...) tfp_printf(__VA_ARGS__);
#else
	#define DEBUG_PRINTF(...)
#endif

TD_GEOLOC_Fix_t CurrentGPSPosition;
int timeout;
uint8_t fixIntervalSchedulerId;

//Configure the downlink request every maxCounter sigfox message
int downlinkCounter;
int downlinkMaxCounter;
bool encrypt = false;
int gpsSleepMode = TD_GEOLOC_OFF;
int precision = TD_GEOLOC_2D_FIX;

/*******************************************************************************
 ******************************  GLOBAL FUNCTIONS  ****************************
 ******************************************************************************/

void encryption(uint8_t * bytes, uint8_t * cryptMessage, int size){

	//Here you can insert your own encryption method - This function does nothing

	int i=0;

	for(i=0;i<size;i++){
		cryptMessage[i] = bytes[i];
	}
}

/***************************************************************************//**
 * @brief
 *  GPS fix callback
 *
 * @param[in] fix
 *   The GPS fix data structure.
 *
 * @param[in] timeout
 *   Flag that indicates whether a timeout occurred if set to true.
 ******************************************************************************/
static void GPSFix(TD_GEOLOC_Fix_t * fix, bool timeout)
{
	int i;
	uint8_t bytes[12];
	uint8_t cryptMessage[12];
	uint8_t timeoutMessage[1];

	unsigned long latitude, longitude;
	char latitude_direction, longitude_direction;
	int hdop, nbSat, acqTime, speed, size;

	//Message init - Set to zero not to get random unwanted values
	for(i=0;i<12;i++){
		bytes[i] = 0x00;
	}

	//
	if (fix->type >= precision && fix->hard.rtc_calibrated) {
		uint32_t mv = TD_MEASURE_VoltageTemperatureExtended(false);

		DEBUG_PRINTF("Voltage: %d\r\n", mv);
		DEBUG_PRINTF("Lat: %d - %08lX\r\n", fix->position.latitude,  fix->position.latitude);
		DEBUG_PRINTF("Long: %d - %08lX\r\n", fix->position.longitude, fix->position.longitude);
		DEBUG_PRINTF("Hdop: %d \r\n", fix->quality.hdop);
		DEBUG_PRINTF("nb sat: %d \r\n", fix->quality.sat);
		DEBUG_PRINTF("acquisition time: %d \r\n", fix->duration);
		DEBUG_PRINTF("speed: %d \r\n", fix->speed.speed_kmh);

		//Stop GPS
		TD_GEOLOC_StopFix(gpsSleepMode);

		//Now we add the received data in the bytes array:

		//Latitude
		//Hint: divid the return value by 10 will make it understandable by Sigfox backend
		if (fix->position.latitude < 0) {
			  latitude = (int32_t)(-1)* ((int32_t)fix->position.latitude / 10) ;
			  latitude_direction = 'S';
			  latitude = latitude| 0x80000000;
		} else {
			  latitude = fix->position.latitude / 10;
			  latitude_direction = 'N';
		}
		bytes[0] = (latitude >> 24) & 0xFF;
		bytes[1] = (latitude >> 16) & 0xFF;
		bytes[2] = (latitude >> 8) & 0xFF;
		bytes[3] = latitude & 0xFF;

		//Longitude
		if (fix->position.longitude < 0) {
			  longitude = (int32_t)(-1)* ((int32_t)fix->position.longitude / 10) ;
			  longitude_direction = 'W';
			  longitude = longitude| 0x80000000;
		} else {
			  longitude = fix->position.longitude / 10;
			  longitude_direction = 'E';
		}
		bytes[4] = (longitude >> 24) & 0xFF;
		bytes[5] = (longitude >> 16) & 0xFF;
		bytes[6] = (longitude >> 8) & 0xFF;
		bytes[7] = longitude & 0xFF;

		//Battery
		for(i=0; i<255; i++){
			if(mv>=i*15 && mv<=(i+1)*15){
				bytes[8] = bytes[8] |  i;
			}else if(mv>3825){
				bytes[8] = bytes[8] | 0xFF;
			}
		}
		
		//Hdop
		/*
		 * On the byte 9, we will encode both quality (hdop) and number of satellites
		 * 		  h h s s           (h for hdop and s for the number of satellites)
		 * Byte : _ _ _ _   _ _ _ _
		 */
		hdop = fix->quality.hdop / 100;
		if(hdop > 5){
			//Set the 2 first bits to 3
			bytes[9] = 0xC0;
		} else if(hdop >= 2 && hdop <=5){
			//Set the 2 first bits to 2
			bytes[9] = 0x80;
		} else if(hdop >= 1 && hdop <2){
			//Set the 2 first bits to 1
			bytes[9] = 0x04;
		}

		//Satellites number
		nbSat = fix->quality.sat;
		if(nbSat >=8){
			bytes[9] = bytes[9] | 0x30;
		}else if(nbSat >=6 && nbSat <= 8){
			bytes[9] = bytes[9] | 0x20;
		}else if(nbSat >=4 && nbSat <= 6){
			bytes[9] = bytes[9] | 0x10;
		}

		//Acquisition time
		/*
		 * On the byte 10, we will encode both acquisition (a) time and the speed (s)
		 * 		  a a a a   s s s s
		 * Byte : _ _ _ _   _ _ _ _
		 */
		uint8_t mask;
		acqTime = fix->duration;
		for(i=0; i<15; i++){
			if(acqTime>=i*5 && acqTime<=(i+1)*5){
				mask = i << 4 ;
				bytes[10] = bytes[10] | mask;
			}else if(acqTime>75){
				bytes[10] = bytes[10] | 0xF0;
			}
		}

		//Speed
		speed = fix->speed.speed_kmh;
		for(i=0; i<15; i++){
			if(speed>=i*5 && speed<=(i+1)*5){
				bytes[10] = bytes[10] |  i;
			}else if(speed>75){
				bytes[10] = bytes[10] | 0x0F;
			}
		}

		//DEBUG
		size = sizeof(bytes)/sizeof(bytes[0]);
		for(i=0;i<size;i++){
			DEBUG_PRINTF("bytes[%d]: %x\r\n", i, bytes[i]);
		}
		//TD_GEOLOC_PrintfFix(fix);
		encryption(&bytes, &cryptMessage, size);
		for(i=0;i<size;i++){
			DEBUG_PRINTF("crypt[%d]: %x\r\n", i, cryptMessage[i]);
		}

		//Send data
		/*
		 * If downlinkMaxCounter is reached, send a downlink request with the sigfox message
		 */
		//DEBUG_PRINTF("Downlink counter: %d / %d\r\n", downlinkCounter, downlinkMaxCounter);
		if(downlinkCounter >= downlinkMaxCounter){
			TD_SIGFOX_SendV1(MODE_FRAME, false,encrypt?cryptMessage:bytes, size, 2, true, false);
			downlinkCounter = 0;
		}else{
			TD_SIGFOX_Send(encrypt?cryptMessage:bytes, size, 2);
			downlinkCounter++;
		}

	} else if (timeout) {
		//If no GPS fix has been found, we still send the voltage
		uint32_t mv = TD_MEASURE_VoltageTemperatureExtended(false);
		DEBUG_PRINTF("Voltage: %d\r\n", mv);
		for(i=0; i<255; i++){
			if(mv>=i*15 && mv<=(i+1)*15){
				timeoutMessage[0] = timeoutMessage[0] |  i;
			}else if(mv>3825){
				timeoutMessage[0] = timeoutMessage[0] | 0xFF;
			}
		}
		//Set the device in its sleep mode
		TD_GEOLOC_StopFix(gpsSleepMode);
		DEBUG_PRINTF("Fix Timeout\r\n");
		DEBUG_PRINTF("Time: %d \r\n", fix->duration);
		TD_GEOLOC_PrintfFix(fix);
		DEBUG_PRINTF("Downlink counter: %d / %d\r\n", downlinkCounter, downlinkMaxCounter);
		if(downlinkCounter >= downlinkMaxCounter){
			TD_SIGFOX_SendV1(MODE_FRAME, false, timeoutMessage, 1, 2, true, false);
			downlinkCounter = 0;
		}else{
			TD_SIGFOX_Send((uint8_t *) timeoutMessage, 1, 2);
			downlinkCounter++;
		}



	}
}

/***************************************************************************//**
 * @brief
 *   Call-back function for SIGFOX downlink.
 *
 * @param[in] rx_frame
 *   Pointer to the received frame or null if timeout occurred.
 *
 * @param[in] length
 *   Length in bytes of the received frame.
 *
 * @return
 *   Returns the buffer length if OK, -1 if an error occurred.
 ******************************************************************************/
static int DownlinkCallback(uint8_t *rx_frame, uint8_t length)
{
	int i;
	int fixInterval;
	DEBUG_PRINTF("Downlink...\r\n");
	if (rx_frame == 0) {
		// Finished receiving
		//TD_SIGFOX_DOWNLINK_SetUserCallback(0);
		DEBUG_PRINTF("RX END\r\n");
		// Done
		return 1;
	} else {
		if (length == 0) {
			// Start receiving
			DEBUG_PRINTF("RX BEGIN\r\n");
			// Done
			return 1;
		}
		// Received one good frame
		tfp_dump("RX=", rx_frame, length);
		DEBUG_PRINTF("rx_frame: %d - %x - %s\r\n", rx_frame, rx_frame, rx_frame);
		for(i=0;i<8;i++){
			DEBUG_PRINTF("rx_frame[%d]: %x - %d\r\n", i, rx_frame[i], rx_frame[i]);

		}

		//Here is the GPS timeout value meaning the maximum time you will try to get a GPS fix
		timeout = rx_frame[0];
		DEBUG_PRINTF("timeout: %d (in seconds)\r\n", timeout);

		//The fixInterval (in hours) is the time interval to send a message
		fixInterval = rx_frame[1];
		if(fixInterval>3 && fixInterval<48){
			DEBUG_PRINTF("fixInterval: %d (in hours)\r\n", fixInterval);
			TD_SCHEDULER_SetInterval(fixIntervalSchedulerId, fixInterval * 3600,0,0);
			gpsSleepMode = TD_GEOLOC_OFF;
		}
		if(fixInterval>0 && fixInterval<=3){
			DEBUG_PRINTF("fixInterval: %d (in hours)\r\n", fixInterval);
			TD_SCHEDULER_SetInterval(fixIntervalSchedulerId, fixInterval * 3600,0,0);
			gpsSleepMode = TD_GEOLOC_HW_BCKP;
		}

		//you can add restriction for the max number of uplink to occur before requesting a downlink here
		//When 255, it will always be true
		//You can easily calculate the interval time for downlinks doing '(fixInterval * downlinkMaxCounter) + 1'
		if(rx_frame[2]<48){
			downlinkMaxCounter = rx_frame[2];
			DEBUG_PRINTF("downlinkMaxCounter: %d (in hours)\r\n", downlinkMaxCounter);
		}

		// Done
		return 1;

	}
}

/***************************************************************************//**
 * @brief
 *  Start fixing periodically.
 *
 * @param[in] arg
 *  Generic argument set by the user that is passed along to the callback
 *  function.
 *
 * @param[in] repeat_count
 *  Updated repeat count, decremented at each timer trigger, unless it is an
 *  infinite timer.
 ******************************************************************************/
static void StartFixing(uint32_t arg, uint8_t repeat_count)
{
	DEBUG_PRINTF("Start fixing\r\n");
	TD_GEOLOC_TryToFix(TD_GEOLOC_NAVIGATION, timeout, GPSFix);
}

/***************************************************************************//**
 * @brief
 *  User Setup function.
 ******************************************************************************/
void TD_USER_Setup(void)
{
	TD_UART_Options_t options = {LEUART_DEVICE, LEUART_LOCATION, 9600, 8, 'N',
		1, false};

	// Open an I/O stream using LEUART0
	TD_UART_Open(&options, TD_STREAM_RDWR);

	// Use a 64 s automatic watchdog
	TD_WATCHDOG_Init(64);
	TD_WATCHDOG_Enable(true, true);
	TD_SENSOR_Init(SENSOR_TRANSMITTER, 0, 0);

	// Geoloc and accelerometer initialization
	TD_GEOLOC_Init();
	TD_ACCELERO_Init();

	//Fix timeout
	timeout = 60;

	//Init downlink counter
	downlinkCounter = 0;
	//Once every x uplink
	downlinkMaxCounter = 23; //One downlink every day

#if BOOT_MONITORING

	// Will only send a boot monitor frame on NEXT reboot
	TD_SENSOR_MonitorBoot(true, 0);
#endif

#if KEEPALIVE_INTERVAL > 0

	// Send a keep-alive frame immediately, then at given interval
	TD_SENSOR_MonitorKeepAlive(true, KEEPALIVE_INTERVAL);
#endif

	// Start fixing right now
	StartFixing(0, 0);

	// Start the fix infinite timer
	fixIntervalSchedulerId = TD_SCHEDULER_Append(FIX_INTERVAL, 0, 0, TD_SCHEDULER_INFINITE, StartFixing, 0);

	TD_SIGFOX_DOWNLINK_SetUserCallback(DownlinkCallback);
}

/***************************************************************************//**
 * @brief
 *   User loop function.
 ******************************************************************************/
void TD_USER_Loop(void)
{
	// Process Sensor events
	TD_SENSOR_Process();

	// Process geoloc events
	TD_GEOLOC_Process();

	// Process downlink events
	TD_SIGFOX_DOWNLINK_Process();
}

Step 9: Flash Project to the Device

Debug

You can debug the project using Putty (same method as in the reset the device step) and enable DEBUG variables in the project (Set the variable to 1 - ligne 78).

Software

If it does not work, please try to reset your device.

Unlike some dedicated embedded Interactive Development Environments (IDEs), Eclipse does not come with fixed Flash/Debug commands or menu buttons: they need to be added explicitly on a project by project basis.

Fortunately, these Flash/Debug "Launchers" can be imported or duplicated to other projects easily:

  1. Open the "File" menu and select the "Import..." item.
  2. In the "Import" dialogue, unfold the "Run/Debug" folder by clicking on the "+" sign left to it, select the "Launch Configurations" item and click on the "Next >" button
  3. Enter "C:/TD/TD_RF_Module_SDK-v6.0.0/Github/TD_RF_Module_SDK/Eclipse Launchers" in the "Browse..." field, check the box in front of the "Eclipse Launchers" item and click on the "Finish" button
  4. All the default Flash/Debug "Launchers" will be added to the top menu "Bug" and "Green Circle with With Right Arrow and Briefcase" icons
  5. If required, you can edit these "Launchers" by choosing the "Debug Configurations..."or "External Tools Configurations..." entries in the menu obtained by the small downwards arrow right next to the corresponding "Bug" or "Green Circle with With Right Arrow and Briefcase" icon
  6. In the dialogue windows that opens, you can edit a given configuration directly and click on the "Apply" and "Close" buttons, or you can duplicate it by right-clicking on it and selecting the "Duplicate" entry in the contextual menu that pops up

Then, to flash a firmware to the TD12xx/TD15xx board:

  1. Select the desired project in the Project Explorer panel on the left side
  2. Right-click on the project and select the "Build Configurations > Set Active >" and the desired build configuration as explained above
  3. Optionally click on the "Hammer" icon in the top menu bar to build the project
  4. Click on the small downwards arrow right next to the "Green Circle with With Right Arrow and Briefcase" icon and select "Flash Selected Project" in the contextual menu.

Hardware

Depending on how you want to supply power to the device, use the switch on the EVB (see screenshot of the documentation):

  • The upper position will supply power from the FTDI cable
  • The lower position will supply power from the EFM32 board
  • No jumper will use the power from the device (Battery, Lipo, etc...)

Be careful not to put the jumper when the device is powered by an external source otherwise, it may damage your device!!

Step 10: View the Geolocalisation

Now that our device can send data, let see how to see the geolocalisation on Sigfox Backend:

  • Go to "Device Type"
  • Click on your device type
  • You should arrive on the information tab. Click on "edit" upper right corner
  • Change the display type to "Geolocalisation" "Default (root)"
  • Save
  • Go to "Device"
  • Select your device
  • Scroll down on the information tab until you see "See the device track on map"
  • Click on it, you will see your device last positions on a map
  • You can also go to message and see the latitude and longitude

Step 11: Bravo

Let your imagination guide you.

Now you can connect and track your dog, your bike, your car or whatever you want.

You just need to solder a small battery (be careful not to overstep 3.7V) and let your device live its life!

Do not hesitate to share what you made. I'll be glad to answer your question. Feel free to contact me!

We haven't discussed the part where you send a callback to your own server. I wrote a small part on this on my first tutorial "Sigfox Talking Plant" (step 7). Go and have a look if you are interested ;)

Thank you for your attention. I know this tutorial is not the easiest I made. Bravo if you've reached the end!!!

Maker Olympics Contest 2016

Participated in the
Maker Olympics Contest 2016