GPSProvider wrapper library for STMicroelectronics' X-NUCLEO-GNSS1A1 Expansion Board.

Dependents:   TeseoLocation

X_NUCLEO_GNSS1A1 Library

GPS_Provider wrapper library for STMicroelectronics' X-NUCLEO-GNSS1A1 component.

Overview

This library includes drivers for ST’s Teseo-LIV3F Global Navigation Satellite System (GNSS) device and middleware for the NMEA protocol support. This firmware package implements the port of the GPS_Provider to STMicroelectronics' X-NUCLEO-GNSS1A1 GNSS Expansion Board.

The key features of the library are:

  • Complete software to build applications using Teseo-LIV3F GNSS device
  • Middleware for the NMEA protocol support

Furthermore the library provides the following advanced features:

  • Geofencing - allows the Teseo-LIV3F receiver to raise a NMEA message when the resolved GNSS position is close to or entering or exiting from a specific circle
  • Odometer - provides information on the traveled distance using only the resolved GNSS position
  • Data Logging - allows the Teseo-LIV3F receiver to save locally on the flash the resolved GNSS position to be retrieved on demand from the Host

Hardware description

The X-NUCLEO-GNSS1A1 is a Global Navigation Satellite System Expansion Board usable with the STM32 Nucleo system and other Arduino compatible platforms. It is designed around the STMicroelectronics Teseo-LIV3F GNSS receiver IC working on multiple constellations (GPS/Galileo/Glonass/BeiDou/QZSS).

The Teseo-LIV3F module is designed for top performance in a minimal space. Within its 10x10mm compact size, Teseo-LIV3F offers superior accuracy thanks to the on board 26MHz Temperature Compensated Crystal Oscillator (TCXO) and a reduced Time To First Fix (TTFF) relying to its dedicated 32KHz Real Time Clock (RTC) oscillator.

The X-NUCLEO-GNSS1A1, hosting the Teseo-LIV3F, is compatible with Arduino UNO R3 connector layout and interfaces with the MCU via the UART channel. To connect by serial port the GNSS receiver and the host the following parameters must be used:

  • 8 data bits
  • No parity
  • 1 stop bit
  • 9600 bauds

A GPS/GLONASS/Beidou antenna, distributed along with the X-NUCLEO-GNSS1A1 Expansion Board, must be connected to the antenna connector present on the Expansion Board. For the X-NUCLEO-GNSS1A1 proper operations, the following jumper settings must be used:

  • J2 open
  • J3 closed
  • J4 closed
  • J5 open
  • J6 closed
  • J7 closed
  • J8 open
  • J9 closed
  • J10 open
  • J11 closed
  • J12 closed
  • J13 closed
  • J14 closed
  • J15 closed

Tested platforms

This firmware has been tested on STM32 NUCLEO-F401RE

Example Application

To run GNSS example applications using X-NUCLEO-GNSS1A1 Expansion Board based on mbed OS, please refer to TeseoLocation page.

Revision:
0:a77f1f1f8318
Child:
5:1fe1ba1f0013
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/createTeseoGNSS.cpp	Fri Nov 09 17:06:11 2018 +0000
@@ -0,0 +1,713 @@
+/**
+ ******************************************************************************
+ * @file    createTeseoGNSS.cpp
+ * @author  AST/CL
+ * @version V1.1.0
+ * @date    May, 2017
+ * @brief   .
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *   1. Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright notice,
+ *      this list of conditions and the following disclaimer in the documentation
+ *      and/or other materials provided with the distribution.
+ *   3. Neither the name of STMicroelectronics nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+#include "mbed.h"
+#include "Teseo.h"
+#include "GPSProviderImplBase.h"
+
+#include "TeseoConfig.h"
+
+static void _AppOutputCallback(uint32_t msgId, uint32_t msgType, tTeseoData *pData);
+static void _AppEventCallback(eTeseoLocEventType event, uint32_t data);
+static char msg[256];
+
+static char *geofenceCirclePosition[] = {
+  "Unknown",
+  "Outside",
+  "Boundary",
+  "Inside"
+};
+
+extern Serial serialDebug;
+#define TESEO_APP_LOG_INFO(...) serialDebug.printf(__VA_ARGS__)
+
+GPSProviderImplBase *
+createGPSProviderInstance(void)
+{
+    static Teseo gnss(TESEO_PIN_RESET,
+                      TESEO_PIN_WAKEUP,
+                      TESEO_PIN_PPS,
+                      TESEO_PIN_TX,
+                      TESEO_PIN_RX,
+                      &serialDebug);
+
+    /* Register output callback and event callback functions */
+    gnss.TeseoLocRegOutput(_AppOutputCallback, _AppEventCallback);
+
+    return &gnss;
+}
+
+/** 
+ * @brief  This function prints on the console the info about Fix data for single or combined satellite navigation system
+ * @param  pData
+ * @retval None
+ */
+static void
+GetGNSMsgInfos(tTeseoData *pData)
+{
+//  char msg[256];
+  
+  TESEO_APP_LOG_INFO("\r\n");
+  
+  sprintf(msg, "Constellation:\t\t[ %s ]\t",
+          pData->gns_data.constellation);
+  TESEO_APP_LOG_INFO(msg);
+  
+  if (strcmp(pData->gns_data.constellation, "$GPGSV") == 0) {
+    TESEO_APP_LOG_INFO("-- only GPS constellation is enabled\n\r");  
+  }
+  else if (strcmp(pData->gns_data.constellation, "$GLGSV") == 0) {
+    TESEO_APP_LOG_INFO("-- only GLONASS constellation is enabled\n\r");
+  }
+  else if (strcmp(pData->gns_data.constellation, "$GAGSV") == 0) {
+    TESEO_APP_LOG_INFO("-- only GALILEO constellation is enabled\n\r");
+  }
+  else if (strcmp(pData->gns_data.constellation, "$BDGSV") == 0) {
+    TESEO_APP_LOG_INFO("-- only BEIDOU constellation is enabled\n\r");    
+  }
+  else if (strcmp(pData->gns_data.constellation, "$QZGSV") == 0) {
+    TESEO_APP_LOG_INFO("-- only QZSS constellation is enabled\n\r");
+  }
+  else if (strcmp(pData->gns_data.constellation, "$GNGSV") == 0) {
+    TESEO_APP_LOG_INFO("-- message to report all satellites for all enabled constellations\n\r");   
+  }
+  
+  sprintf(msg, "UTC:\t\t\t[ %02d:%02d:%02d ]\n\r",
+          pData->gns_data.utc.hh, 
+          pData->gns_data.utc.mm, 
+          pData->gns_data.utc.ss);
+  TESEO_APP_LOG_INFO(msg);
+  
+  sprintf(msg,"Latitude:\t\t[ %.0f' %d'' %c ]\n\r",
+          (pData->gns_data.xyz.lat - ((int)pData->gns_data.xyz.lat % 100)) / 100, 
+          ((int)pData->gns_data.xyz.lat % 100), 
+          pData->gns_data.xyz.ns);          
+  TESEO_APP_LOG_INFO(msg);
+  
+  sprintf(msg,"Longitude:\t\t[ %.0f' %d'' %c ]\n\r",
+          (pData->gns_data.xyz.lon - ((int)pData->gns_data.xyz.lon % 100)) / 100, 
+          ((int)pData->gns_data.xyz.lon % 100),
+          pData->gns_data.xyz.ew);
+  TESEO_APP_LOG_INFO(msg);
+  
+  sprintf(msg,"Satellites locked:\t[ %d ]\n\r",
+          pData->gns_data.sats);
+  TESEO_APP_LOG_INFO(msg);
+  
+  sprintf(msg,"HDOP:\t\t\t[ %.01f ]\n\r",
+          pData->gns_data.hdop);
+  TESEO_APP_LOG_INFO(msg);
+  
+  sprintf(msg,"Altitude:\t\t[ %.01f ]\n\r",
+          pData->gns_data.xyz.alt);
+  TESEO_APP_LOG_INFO(msg);
+  
+  sprintf(msg,"Geoid infos:\t\t[ %.01f ]\n\r",
+          pData->gns_data.geo_sep);
+  TESEO_APP_LOG_INFO(msg);
+  
+  //  sprintf(msg,"ID - Checksum:\t\t[ *%x ]\n\r",
+  //          (pData->gns_data.checksum);
+  //  TESEO_APP_LOG_INFO(msg);
+  
+  TESEO_APP_LOG_INFO("\n\n\r");
+  
+  return;
+}
+
+/** 
+ * @brief  This function prints on the console the info about GPS Pseudorange Noise Statistics
+ * @param  pData
+ * @retval None
+ */
+static void
+GetGPGSTInfos(tTeseoData *pData)
+{
+//  char msg[256];
+  
+  TESEO_APP_LOG_INFO("\r\n");
+    
+  sprintf(msg, "UTC:\t\t\t[ %02d:%02d:%02d ]\n\r",
+          pData->gpgst_data.utc.hh, 
+          pData->gpgst_data.utc.mm, 
+          pData->gpgst_data.utc.ss);
+  TESEO_APP_LOG_INFO(msg);
+    
+  sprintf(msg,"EHPE:\t\t[ %.01f ]\n\r",
+          pData->gpgst_data.EHPE);
+  TESEO_APP_LOG_INFO(msg);
+    
+  sprintf(msg,"Semi-major Dev:\t\t[ %.01f ]\n\r",
+          pData->gpgst_data.semi_major_dev);
+  TESEO_APP_LOG_INFO(msg);
+    
+  sprintf(msg,"Semi-minor Dev:\t\t[ %.01f ]\n\r",
+          pData->gpgst_data.semi_minor_dev);
+  TESEO_APP_LOG_INFO(msg);
+  
+  sprintf(msg,"Semi-maior Angle:\t\t[ %.01f ]\n\r",
+          pData->gpgst_data.semi_major_angle);
+  TESEO_APP_LOG_INFO(msg);
+      
+  sprintf(msg,"Lat Err Dev:\t\t[ %.01f ]\n\r",
+          pData->gpgst_data.lat_err_dev);
+  TESEO_APP_LOG_INFO(msg);
+  
+  sprintf(msg,"Lon Err Dev:\t\t[ %.01f ]\n\r",
+          pData->gpgst_data.lon_err_dev);
+  TESEO_APP_LOG_INFO(msg);
+  
+  sprintf(msg,"Alt Err Dev:\t\t[ %.01f ]\n\r",
+          pData->gpgst_data.alt_err_dev);
+  TESEO_APP_LOG_INFO(msg);
+    
+//  sprintf(msg,"ID - Checksum:\t\t[ *%x ]\n\r",
+//          pData->gpgst_data.checksum);
+//  TESEO_APP_LOG_INFO(msg);
+    
+  TESEO_APP_LOG_INFO("\n\n\r");
+
+  return;
+}
+
+/** 
+ * @brief  This function prints on the console the info about Recommended Minimum Specific GPS/Transit data got by the most recent reception process
+ * @param  pData
+ * @retval None
+ */
+static void
+GetGPRMCInfos(tTeseoData *pData)
+{
+//  char msg[256];
+  
+  TESEO_APP_LOG_INFO("\r\n");
+    
+  sprintf(msg, "UTC:\t\t\t\t[ %02d:%02d:%02d ]\n\r",
+          pData->gprmc_data.utc.hh, 
+          pData->gprmc_data.utc.mm, 
+          pData->gprmc_data.utc.ss);
+  TESEO_APP_LOG_INFO(msg);
+    
+  sprintf(msg,"Status:\t\t\t\t[ %c ]\t\t",
+          pData->gprmc_data.status);
+  TESEO_APP_LOG_INFO(msg);
+  if (pData->gprmc_data.status == 'A') {
+    TESEO_APP_LOG_INFO("-- Valid (reported in 2D and 3D fix conditions)\n\r");
+  }
+  else if (pData->gprmc_data.status == 'V') {
+    TESEO_APP_LOG_INFO("-- Warning (reported in NO FIX conditions)\n\r");
+  }
+  else {
+    TESEO_APP_LOG_INFO("-- Unknown status\n\r");
+  }
+    
+  sprintf(msg,"Latitude:\t\t\t[ %.0f' %02d'' %c ]\n\r",
+          ((pData->gprmc_data.xyz.lat - ((int)pData->gprmc_data.xyz.lat % 100))) / 100, 
+          ((int)pData->gprmc_data.xyz.lat % 100), 
+          pData->gprmc_data.xyz.ns);          
+  TESEO_APP_LOG_INFO(msg);
+  
+  sprintf(msg,"Longitude:\t\t\t[ %.0f' %02d'' %c ]\n\r",
+          ((pData->gprmc_data.xyz.lon - ((int)pData->gprmc_data.xyz.lon % 100))) / 100, 
+          ((int)pData->gprmc_data.xyz.lon % 100),
+          pData->gprmc_data.xyz.ew);
+  TESEO_APP_LOG_INFO(msg);
+    
+  sprintf(msg,"Speed over ground (knots):\t[ %.01f ]\n\r",
+          pData->gprmc_data.speed);
+  TESEO_APP_LOG_INFO(msg);
+  
+  sprintf(msg,"Trackgood:\t\t\t[ %.01f ]\n\r",
+          pData->gprmc_data.trackgood);
+  TESEO_APP_LOG_INFO(msg);
+  
+  sprintf(msg,"Date (ddmmyy):\t\t\t[ %d ]\n\r",
+          pData->gprmc_data.date);
+  TESEO_APP_LOG_INFO(msg);
+    
+  sprintf(msg,"Magnetic Variation:\t\t[ %.01f ]\n\r",
+          pData->gprmc_data.mag_var);
+  TESEO_APP_LOG_INFO(msg);
+  
+  if (pData->gprmc_data.mag_var_dir != 'E' &&
+      pData->gprmc_data.mag_var_dir != 'W') {
+    sprintf(msg,"Magnetic Var. Direction:\t[ - ]\n\r");
+  }
+  else {
+    sprintf(msg,"Magnetic Var. Direction:\t[ %c ]\n\r",
+          pData->gprmc_data.mag_var_dir);
+  }
+  TESEO_APP_LOG_INFO(msg);
+  
+//  sprintf(msg,"Checksum:\t\t[ *%x ]\n\r",
+//          pData->gprmc_data.checksum);
+//  TESEO_APP_LOG_INFO(msg);
+    
+  TESEO_APP_LOG_INFO("\n\n\r");
+
+  return;
+}
+
+/** 
+ * @brief  This function prints on the console the info about GNSS satellites got by the most recent reception process
+ * @param  pData
+ * @retval None
+ */
+static void
+GetGSAMsgInfos(tTeseoData *pData)
+{
+//  char msg[256];
+  
+  TESEO_APP_LOG_INFO("\r\n");
+  
+  sprintf(msg, "Constellation:\t\t[ %s ]\t",
+          pData->gsa_data.constellation);
+  TESEO_APP_LOG_INFO(msg);
+  
+  if (strcmp(pData->gsa_data.constellation, "$GPGSA") == 0) {
+    TESEO_APP_LOG_INFO("-- only GPS constellation is enabled\n\r");    
+  }
+  else if (strcmp(pData->gsa_data.constellation, "$GLGSA") == 0) {
+    TESEO_APP_LOG_INFO("-- only GLONASS constellation is enabled\n\r");
+  }
+  else if (strcmp(pData->gsa_data.constellation, "$GAGSA") == 0) {
+    TESEO_APP_LOG_INFO("-- only GALILEO constellation is enabled\n\r");
+  }
+  else if (strcmp(pData->gsa_data.constellation, "$BDGSA") == 0) {
+    TESEO_APP_LOG_INFO("-- only BEIDOU constellation is enabled\n\r");
+  }
+  else if (strcmp(pData->gsa_data.constellation, "$GNGSA") == 0) {
+    TESEO_APP_LOG_INFO("-- more than one constellation is enabled\n\r");   
+  }
+  
+  sprintf(msg, "Operating Mode:\t\t[ %c ]\t\t",
+          pData->gsa_data.operating_mode);
+  TESEO_APP_LOG_INFO(msg);
+  if (pData->gsa_data.operating_mode == 'A') {
+    TESEO_APP_LOG_INFO("-- Auto (2D/3D)\n\r");
+  }
+  else if (pData->gsa_data.operating_mode == 'M') {
+    TESEO_APP_LOG_INFO("-- Manual\n\r");
+  }
+  
+  sprintf(msg,"Current Mode:\t\t[ %d ]\t\t",
+          pData->gsa_data.current_mode);          
+  TESEO_APP_LOG_INFO(msg);
+  if (pData->gsa_data.current_mode == 1) {
+    TESEO_APP_LOG_INFO("-- no fix available\n\r");
+  }
+  else if (pData->gsa_data.current_mode == 2) {
+    TESEO_APP_LOG_INFO("-- 2D\n\r");
+  }
+  else if (pData->gsa_data.current_mode == 3) {
+    TESEO_APP_LOG_INFO("-- 3D\n\r");
+  }
+  
+  for (uint8_t i=0; i<12; i++) {  
+    sprintf(msg,"SatPRN%02d:\t\t[ %d ]\n\r", i+1,
+            pData->gsa_data.sat_prn[i]);
+    TESEO_APP_LOG_INFO(msg);
+  }
+  
+  sprintf(msg,"PDOP:\t\t\t[ %.01f ]\n\r",
+          pData->gsa_data.pdop);
+  TESEO_APP_LOG_INFO(msg);
+  
+  sprintf(msg,"HDOP:\t\t\t[ %.01f ]\n\r",
+          pData->gsa_data.hdop);
+  TESEO_APP_LOG_INFO(msg);
+  
+  sprintf(msg,"VDOP:\t\t\t[ %.01f ]\n\r",
+          pData->gsa_data.vdop);
+  TESEO_APP_LOG_INFO(msg);
+  
+//  sprintf(msg,"ID - Checksum:\t\t[ *%x ]\n\r",
+//          pData->gsa_data.checksum);
+//  TESEO_APP_LOG_INFO(msg);
+  
+  TESEO_APP_LOG_INFO("\n\n\r");
+  
+}
+            
+/** 
+ * @brief  This function prints on the console the info about GNSS satellites got by the most recent reception process
+ * @param  pData
+ * @retval None
+ */
+static void
+GetGSVMsgInfos(tTeseoData *pData)
+{
+  uint8_t i;
+  uint8_t tot_sats = pData->gsv_data.tot_sats;
+//  char msg[256];
+  
+  char degree_sym = 248;
+  
+  TESEO_APP_LOG_INFO("\r\n");
+  
+  sprintf(msg, "Constellation:\t\t[ %s ]\t",
+          pData->gsv_data.constellation);
+  TESEO_APP_LOG_INFO(msg);
+  
+  if (strcmp(pData->gsv_data.constellation, "$GPGSV") == 0) {
+    TESEO_APP_LOG_INFO("-- message to report all GPS satellites\n\r");    
+  }
+  else if (strcmp(pData->gsv_data.constellation, "$GLGSV") == 0) {
+    TESEO_APP_LOG_INFO("-- message to report all GLONASS satellites\n\r");
+  }
+  else if (strcmp(pData->gsv_data.constellation, "$GAGSV") == 0) {
+    TESEO_APP_LOG_INFO("-- message to report all GALILEO satellites\n\r");
+  }
+  else if (strcmp(pData->gsv_data.constellation, "$BDGSV") == 0) {
+    TESEO_APP_LOG_INFO("-- message to report all BEIDOU satellites\n\r");
+  }
+  else if (strcmp(pData->gsv_data.constellation, "$QZGSV") == 0) {
+    TESEO_APP_LOG_INFO("-- message to report all QZSS satellites\n\r");
+  }
+  else if (strcmp(pData->gsv_data.constellation, "$GNGSV") == 0) {
+    TESEO_APP_LOG_INFO("-- message to report all satellites for all enabled constellations\n\r");   
+  }
+  
+  /* debug */
+//  sprintf(msg,"Tot Messages:\t\t[ %d ]\n\r",
+//          ((tTeseoData *)(handle->pData))->gsv_data.amount);
+//  TESEO_APP_LOG_INFO(msg);
+//  
+//  sprintf(msg,"Message Num:\t\t[ %d ]\n\r",
+//          ((tTeseoData *)(handle->pData))->gsv_data.number);
+//  TESEO_APP_LOG_INFO(msg);
+  
+  sprintf(msg,"Num of Satellites:\t[ %d ]\n\r", tot_sats);
+  TESEO_APP_LOG_INFO(msg);
+  
+  TESEO_APP_LOG_INFO("\n\r");
+  
+  for (i=0; i<tot_sats; i++) {
+    sprintf(msg,"Sat%02dPRN:\t\t[ %03d ]\n\r", i+1, 
+            pData->gsv_data.gsv_sat_i[i].prn);
+    TESEO_APP_LOG_INFO(msg);
+    
+    sprintf(msg,"Sat%02dElev (%c):\t\t[ %03d ]\n\r", i+1, degree_sym,
+            pData->gsv_data.gsv_sat_i[i].elev);
+    TESEO_APP_LOG_INFO(msg);
+    
+    sprintf(msg,"Sat%02dAzim (%c):\t\t[ %03d ]\n\r", i+1, degree_sym,
+            pData->gsv_data.gsv_sat_i[i].azim);
+    TESEO_APP_LOG_INFO(msg);
+    
+    sprintf(msg,"Sat%02dCN0 (dB):\t\t[ %03d ]\n\r", i+1, 
+            pData->gsv_data.gsv_sat_i[i].cn0);
+    TESEO_APP_LOG_INFO(msg);  
+    
+    TESEO_APP_LOG_INFO("\n\r");
+  }
+  
+  TESEO_APP_LOG_INFO("\r\n");
+  
+}
+
+/** 
+ * @brief  This function prints on the console the info Geofence
+ * @param  pData
+ * @retval None
+ */
+static void
+GetGeofenceInfos(tTeseoData *pData)
+{
+//  char msg[256];
+  
+  TESEO_APP_LOG_INFO("\r\n");
+
+  if(pData->geofence_data.op == GNSS_FEATURE_EN_MSG) {
+    sprintf(msg, "Geofence Enabling:\t\t[ %s ]\t",
+            pData->geofence_data.result ? "ERROR" : "OK");
+    TESEO_APP_LOG_INFO(msg);
+  }
+  if(pData->geofence_data.op == GNSS_GEOFENCE_CFG_MSG) {
+    sprintf(msg, "Geofence Configuration:\t\t[ %s ]\t",
+          pData->geofence_data.result ? "ERROR" : "OK");
+    TESEO_APP_LOG_INFO(msg);
+  }
+  if(pData->geofence_data.op == GNSS_GEOFENCE_STATUS_MSG) {
+    sprintf(msg, "Geofence Status:\t\t[ %s ]\t",
+          pData->geofence_data.result ? "ERROR" : "OK");
+    TESEO_APP_LOG_INFO(msg);
+    if(pData->geofence_data.result == 0) {
+      TESEO_APP_LOG_INFO("\r\n");
+      sprintf(msg, "Time/Date:\t\t%02d:%02d:%02d %02d/%02d/%04d\n",
+          pData->geofence_data.timestamp.hh,
+          pData->geofence_data.timestamp.mm,
+          pData->geofence_data.timestamp.ss,
+          pData->geofence_data.timestamp.day,
+          pData->geofence_data.timestamp.month,
+          pData->geofence_data.timestamp.year);
+      TESEO_APP_LOG_INFO(msg);
+      
+      for(uint8_t i = 0; i<MAX_GEOFENCES_NUM; i++) {
+        sprintf(msg, "Position circle[%d]:\t%s\n",
+          i, geofenceCirclePosition[pData->geofence_data.status[i]]);
+        TESEO_APP_LOG_INFO(msg);
+      }
+    }
+  }
+  if(pData->geofence_data.op == GNSS_GEOFENCE_ALARM_MSG) {
+    sprintf(msg, "Geofence Alarm:\t\t[ %s ]\t",
+          pData->geofence_data.result ? "ERROR" : "OK");
+    TESEO_APP_LOG_INFO(msg);
+    if(pData->geofence_data.result == 0) {
+      TESEO_APP_LOG_INFO("\r\n");
+      sprintf(msg, "Time:\t\t%02d:%02d:%02d\n",
+          pData->geofence_data.timestamp.hh,
+          pData->geofence_data.timestamp.mm,
+          pData->geofence_data.timestamp.ss);
+      TESEO_APP_LOG_INFO(msg);
+      int i = pData->geofence_data.idAlarm;
+      sprintf(msg, "Position circle[%d]:\t%s\n",
+              i, geofenceCirclePosition[pData->geofence_data.status[i]]);
+      TESEO_APP_LOG_INFO(msg);
+    }
+  }  
+  TESEO_APP_LOG_INFO("\r\n");
+  
+}
+
+/** 
+ * @brief  This function prints on the console the info about Odometer
+ * @param  pData
+ * @retval None
+ */
+static void
+GetOdometerInfos(tTeseoData *pData)
+{
+//  char msg[256];
+  
+  TESEO_APP_LOG_INFO("\r\n");
+  
+  if(pData->odo_data.op == GNSS_FEATURE_EN_MSG) {
+    sprintf(msg, "Odometer Enabling:\t\t[ %s ]\t",
+            pData->odo_data.result ? "ERROR" : "OK");
+    TESEO_APP_LOG_INFO(msg);
+  }
+  if((pData->odo_data.op == GNSS_ODO_START_MSG) ||
+     (pData->odo_data.op == GNSS_ODO_STOP_MSG)) {
+    sprintf(msg, "Odometer Operation:\t\t[ %s ]\t",
+          pData->odo_data.result ? "ERROR" : "OK");
+    TESEO_APP_LOG_INFO(msg);
+  }  
+  TESEO_APP_LOG_INFO("\r\n");
+  
+}
+
+/** 
+ * @brief  This function prints on the console the info about Datalog
+ * @param  pData
+ * @retval None
+ */
+static void
+GetDatalogInfos(tTeseoData *pData)
+{
+//  char msg[256];
+  
+  TESEO_APP_LOG_INFO("\r\n");
+  
+  if(pData->datalog_data.op == GNSS_FEATURE_EN_MSG) {
+    sprintf(msg, "Datalog Enabling:\t\t[ %s ]\t",
+            pData->datalog_data.result ? "ERROR" : "OK");
+    TESEO_APP_LOG_INFO(msg);
+  }
+  if(pData->datalog_data.op == GNSS_DATALOG_CFG_MSG) {
+    sprintf(msg, "Datalog Configuring:\t\t[ %s ]\t",
+            pData->datalog_data.result ? "ERROR" : "OK");
+    TESEO_APP_LOG_INFO(msg);
+  }
+  if(pData->datalog_data.op == GNSS_DATALOG_START_MSG) {
+    sprintf(msg, "Datalog Start:\t\t[ %s ]\t",
+            pData->datalog_data.result ? "ERROR" : "OK");
+    TESEO_APP_LOG_INFO(msg);
+  }
+  if(pData->datalog_data.op == GNSS_DATALOG_STOP_MSG) {
+    sprintf(msg, "Datalog Stop:\t\t[ %s ]\t",
+            pData->datalog_data.result ? "ERROR" : "OK");
+    TESEO_APP_LOG_INFO(msg);
+  }
+  if(pData->datalog_data.op == GNSS_DATALOG_ERASE_MSG) {
+    sprintf(msg, "Datalog Erase:\t\t[ %s ]\t",
+            pData->datalog_data.result ? "ERROR" : "OK");
+    TESEO_APP_LOG_INFO(msg);
+  }
+  TESEO_APP_LOG_INFO("\r\n");
+  
+}
+
+/** 
+ * @brief  This function prints on the console the ack about Message List cfg
+ * @param  pData
+ * @retval None
+ */
+static void
+GetMsgListAck(tTeseoData *pData)
+{
+//  char msg[256];
+  
+  TESEO_APP_LOG_INFO("\r\n");
+  
+  sprintf(msg, "Msg List config:\t\t[ %s ]\t",
+          pData->ack ? "ERROR" : "OK");
+  TESEO_APP_LOG_INFO(msg);
+    
+  TESEO_APP_LOG_INFO("\r\n");
+}
+
+/** 
+ * @brief  This function prints on the console the ack about Message List cfg
+ * @param  pData
+ * @retval None
+ */
+static void
+GetAck(tTeseoData *pData)
+{
+//  char msg[256];
+  
+  TESEO_APP_LOG_INFO("\r\n");
+  
+  sprintf(msg, "Params configuration:\t\t[ %s ]\t",
+          pData->ack ? "ERROR" : "OK");
+  TESEO_APP_LOG_INFO(msg);
+    
+  TESEO_APP_LOG_INFO("\r\n");
+}
+
+void
+_AppOutputCallback(uint32_t msgId, uint32_t msgType, tTeseoData *pData)
+{
+  switch (msgId) {
+  case LOC_OUTPUT_LOCATION: {
+    // Output last location
+    TESEO_APP_LOG_INFO("Loc: lat=%lf, lon=%lf, alt=%f\r\n", pData->gpgga_data.xyz.lat, pData->gpgga_data.xyz.lon, pData->gpgga_data.xyz.alt);
+    break;
+  }
+  case LOC_OUTPUT_NMEA: {
+    //return;
+    Teseo::eMsg msg = (Teseo::eMsg)msgType;
+    switch(msg) {
+    case Teseo::GNS:
+      // GET Fix data for single or combined Satellite navigation system
+      GetGNSMsgInfos(pData);
+      break;
+      
+    case Teseo::GPGST:
+      // GET GPS Pseudorange Noise Statistics
+      GetGPGSTInfos(pData);
+      break;
+      
+    case Teseo::GPRMC:
+      // GET Recommended Minimum Specific GPS/Transit data
+      GetGPRMCInfos(pData);
+      break;
+      
+    case Teseo::GSA:
+      // GET GPS DOP and Active Satellites
+      GetGSAMsgInfos(pData);
+      break;
+      
+    case Teseo::GSV:
+      // GET GPS Satellites in View
+      GetGSVMsgInfos(pData);
+      break;
+      
+    default:
+      break;
+    }
+    break;
+  }
+  case LOC_OUTPUT_PSTM: {
+    Teseo::ePSTMsg msg = (Teseo::ePSTMsg)msgType;
+    switch(msg) {
+    case Teseo::PSTMGEOFENCE:
+      // GET Geofence info
+      GetGeofenceInfos(pData);
+      break;
+    case Teseo::PSTMODO:
+      // GET Geofence info
+      GetOdometerInfos(pData);
+      break;
+    case Teseo::PSTMDATALOG:
+      // GET Datalog info
+      GetDatalogInfos(pData);
+      break;
+    case Teseo::PSTMSGL:
+      // GET Message List ack
+      GetMsgListAck(pData);
+      break;
+    case Teseo::PSTMSAVEPAR:
+      // GET SAVE PAR ack
+      GetAck(pData);
+      break;
+    default:
+      break;
+    }
+    break;
+  }
+  
+  default:
+    break;
+  }
+}
+
+
+void
+_AppEventCallback(eTeseoLocEventType event, uint32_t data)
+{
+    switch (event) {
+        case TESEO_LOC_EVENT_START_RESULT:
+            if (data != 0) {
+                TESEO_APP_LOG_INFO("start failed.\r\n");
+            } else {
+                TESEO_APP_LOG_INFO("start OK.\r\n");
+            }
+            break;
+        case TESEO_LOC_EVENT_STOP_RESULT:
+            if (data != 0) {
+                TESEO_APP_LOG_INFO("stop failed.\r\n");
+            } else {
+                TESEO_APP_LOG_INFO("stop OK.\r\n");
+            }
+            break;
+        default:
+            break;
+    }
+}