Event Logger - Old Versions

From OpenTom

Jump to: navigation, search

These outdated versions have been put here only to keep an history.

Contents

Version 5.2beta

October 8, 2005 - NOTE

NOTE: New code added below (v5.2 which is still an untuned beta and only partially documented). Take care to TIMEZONE, TIMEZONEI, AddIntervals, OldItnToKeepOnline, AllowDateTranslation, GPX variables.

What’s new

The following features are available in release 5.2beta:

  • GPX Tracking system (GPX files automatically archived with gzip compression)
  • Automatic track segmentation inside GPX files based on stop periods.
  • Geodecoding
  • POI creation
  • Integration with TTGO via file SDK (display message; more accurate positioning in case of poor radio coverage)
  • Management of short intervals, with the introduction of the aggregate items.
  • Computation of the duration of aggregated periods, including total journey time, total run time, time of small stops.
  • Archiving of past itinerary files into a single TGZ file (tar archive compressed with gzip).

This release also includes a bug correction in the GPX speed format (m/sec instead of km/h).

The following description still mainly refers to Event_Logger version 3. Will be updated as soon as there is time avilable.

WARNING: menu button only compatible with 5.202; version 5.0beta only tested with this version (go to ScaredyCat's site http://www.automated.it/ttg-apps.html; check file ttgoapp-5.202.zip included in http://www.automated.it/ttgapps.zip).

Introduction

The following script will log TTGO events to an Itinerary file called "/itn/_Logger.itn", which can be browsed within TTGO 5.x like any other Itinerary file; logged records include boot, resume, suspend and optionally other “log” events.

“Log” events refer to a specific menu button, which can be optionally installed; it allows to add a record in the Itinerary file each time this button is manually selected (by browsing the TTGO menu) and pressed.

All records will register the current position, altitude and speed.

Together with the connection of the TTGO with the car ignition, the Event Logger will help answering the following questions:

  • What itinerary did I do yesterday?
  • When did I start driving today?
  • How long did I take to go there?
  • Where did I park my car?
  • Which is the current altitude and speed?
  • How can I remind precise positions, when exactly I arrived there, which was the altitude and whether I was moving in that moment?

Compatibility

This version has been currently tested with TTGO 5.00, 5.10, 5.20, 5.201, 5.202.

Utility expr required (standard UNIX expr command, ARM Linux).

Installation

  • Paste the TTN script into an editor able to manage UNIX newlines and save the file in the root directory of the TTGO SD Card with name ttn (three letters, all lowercase; e.g., if exploiting Windows for this, do not use notepad, which cannot manage the UNIX carriage return format; UltraEdit is OK, provided that, before saving the file, you select File -> Conversions -> DOS to UNIX). Pay attention that the file name should not have any extension (e.g., the following file names will not work: ttn.txt, Ttn.txt, Ttn, TTN; the only working file name is ttn).
  • The directory “Tracer” must be created under the root directory of the SD card (with only the first letter uppercase; e.g., tracer with all letters lowercase will not work).
  • Verify that the itn directory exists in the SD card; alternatively, create it (under the root; three letters, all lowercase).
  • Inside the directory “Tracer”, the “expr” command (required) must be installed. The free package http://rpmfind.net/linux/RPM/netwinder/netwinder/RPMS/base/3.1-15/sh-utils-2.0-1.armv4l.html can be used for this: download the filename “sh-utils-2.0-1.armv4l.rpm” and open it with an archiver managing RPM, GZIP and CPIO packages (e.g., the freeware 7-Zip is OK and can be downloaded from http://www.7-zip.org); inside the package there is a file named “sh-utils-2.0-1.armv4l.cpio.gz”, including “sh-utils-2.0-1.armv4l.cpio”, which in turn incorporates the file “expr” under the directory “/usr/bin”. Extract expr and move it to the “Tracer” directory of the SD card. (Notice also that there is a file named sh-utils.info.gz under usr/info: it is a primer also covering the TIMEZONE date formats, that you can use in order to set the subsequently mentioned $TIMEZONE variable.)
  • As mentioned before, an optional menu button can be added. See the Menu Button chapter below for the related installation.

Note: the old script named “GpsLogger” (inside the “Tracer” directory) is no more needed in this version and, if available in the SD card as part of a previous installation, can be safely removed.


Edit (roussillat) 26/11/2006 : the link for armv41.html is broken : I found it here : ftp://mirrors.blueyonder.co.uk/sites/ftp.netwinder.org/pub/netwinder/RPMS/dm/3.1-15/sh-utils-2.0-1.armv4l.rpm

Configuration

No specific configuration should be required apart from changing the $TIMEZONE variable at the beginning of the script with the target time zone number (e.g., negative or positive number from GMT). The variable $SyncTime can be set to no in order to disable time synchronization. If this variable is set to yes (default), time synchronization is active: this means that each time the TTGO is being suspended (not booted or resumed) with good enough coverage, the date is automatically set to the satellite time. Also the selection of the related menu button (generating “log” events) will try performing a time synchronization.

The configuration section of the script includes a set of additional variables (e.g., labels and file names) which can be used by experienced shell programmers to customize execution. Pay attention to change the date formats, as only a subset of strings is allowed. Exchanging the position of month and day can anyway be done. Changing SpeedUnit and AltitudeUnit can be done, provided that the appropriate conversion code is enabled (e.g., using expr, by uncommenting the related lines in the script; note that these conversions are untested). By customizing and enabling the date translation subroutine named ConvertDate(), the date string can be localized; this refers to the extended date reported to the itinerary file during the first event of each day.

Usage

After this installation, use TTGO normally. The Event Logger automatically generates Itinerary files under the itn directory of the TTGO SD card. These files can be opened and edited through TTGO. The most recent file is called _Logger.itn (its name can be changed through the variable $ITNName). Each time _Logger.itn is opened inside TTGO, it reports the updated list of events occurred during the current day.

Events include:

  • Boot, marked as appropriate barred lines, registered when powering on the TTGO after a physical reset or after an external modification of the SD card.
  • Suspend event, registered when powering off the TTGO through the power button; if the TTGO is appropriately connected to the car ignition, this event automatically occurs, driven by the car. The Suspend events can be distinguished by the Resume ones because they are marked with appropriate icon and separator line by TTGO.
  • Resume event, registered when powering on the TTGO after a suspend event; if the TTGO is appropriately connected to the car ignition, this event automatically occurs, driven by the car. Resume events can be distinguished by Log ones because occurring after a Suspend or boot.
  • Log event (optional), registered when pressing the appropriate menu button of TTGO, provided that the menu add-on have been installed and configured. These events are marked similarly to Resume ones, but can be distinguished from them because occurring after a Resume (or Log) and before a Suspend.
  • Date change: if a date is automatically changed, two lines are reported in the Itinerary file: previous date and new date.
  • Log rolling: all log renaming operations are logged. Logs are automatically rolled each day and if the number of lines exceeds $MaxItnLines (set to 45 by default). Notice that currently TTGO cannot coop with Itinerary files including more than 48 lines.

For each event, the following information is logged:

  • event type (start, stop, boot, log events, appropriately shown by TTGO)
  • date and time of the event
  • position (in case this information is provided by the GPS; otherwise, the latest valid positioning stored data are reused)
  • altitude (in case this information is not provided by the GPS, the latest valid positioning stored data are reused)
  • speed (in case this information is not provided by the GPS, the latest valid positioning stored data are reused)

Date and time are always present and correspond to the current TTGO clock (possibly but not always synchronized with the satellite: as mentioned, synchronization happens during the LOG or SUSPEND events, provided that there is good enough satellite coverage when these events occur).

In case there is no radio coverage, the latest valid positioning information is reused and the symbol “^” highlights that the related logged position is not up to date. This symbol can be changed by editing the script. Unfortunately, this version cannot retrieve the latest information processed by the real ttn application, which is always much more updated than the latest registered valid event. Besides, boot events always refer to outdated information, as currently the script is not able to activate the GPS device and can only exploit the activation performed by the real ttn application (not applicable for boot events). Notice also that RESUME events may not report an updated position even if the symbol “^” is not shown; this is because the process to get the position retrieves information directly from the GPS device, which for some instants just after a power-on might provide outdated information (even if marked as valid). The ideal method to retrieve GPS data is to fetch them from the temporary area where the real ttn application (TTGO) stores them during the suspend operation; how to perform this is currently unknown (hoping in some contribution from anyone who is willing to help…).

The itn directory includes “_Logger.itn”, as well as all the past logging files, named “Log-yy-mm-dd_hh.mm[.n].itn”. This is because events related to the previous days are moved to historical itinerary files, named with the date of the latest relative event included in the file.

The Tracer directory includes the following files:

  • GpsLog.txt (temporary file including last data returned by the GPS device during last processed event; always recreated, can be safely deleted).
  • LastLog.itn (temporary file including information related to the last valid GPS data processed by the Event Logger; this is used instead of the GPS data when there is no radio coverage as soon as an event happens; if this file is not available, a null positioning record will be generated).
  • TtnLog.txt (optional log file, usually generated if the $Debug variable is greater than 0; it can be safely deleted and, if generated, it is not automatically rolled).

Logging level can be set through the $Debug variable. As all write operations on the SD card are slow, logging will slow down execution. For best performance, set logging to 0. (In any case, this shell script takes long time to execute and consequently slows down all the event operations: this is a current drawback).

Optional installation of the Menu Button

  • Create the SdkRegistry directory under the root of the SD card.
  • Create a file named logpos.cap inside the SdkRegistry directory, including the following information:
Version|100|
AppName|ttn GpsLogger LOG 1|
AppPath|/mnt/sdcard/|
AppIconFile|logpos.bmp|
AppMainTitle|Log Position|
AppPort|2001|
COMMAND|CMD|ttn GpsLogger LOG 1|logpos.bmp|Log Position|
  • Create your own icon file related to the push button with a BMP file editor; select a bitmap of 62x43 pixels, 24 bit color depth, named “logpos.bmp”.
  • Create or update the “tomtom.mnu” file, by adding the line
MENUITEM|TASK_SDKn|

where n is the first unused SDK number starting from 1. Possibly, an additional menu page is needed.

Example:

the standard menu, which is not available by default, is as follows:

MENUBLOCK|BLOCK_MAIN|BTM_GPS_POSITION|
MENUPAGE|TASK_PAGE1|Main Menu 1 of 3|
MENUITEM|TASK_NAVIGATE_TO|
MENUITEM|TASK_MENU_FIND_ALTERNATIVES|
MENUITEM|TASK_SHOW_MAP|
MENUITEM|TASK_ADD_FAVORITE|
MENUITEM|TASK_MENU_PREFERENCES|
MENUITEM|TASK_PAGE2|
MENUPAGE|TASK_PAGE2|Main Menu 2 of 3|
MENUITEM|TASK_MENU_PLAN_ATOB|
MENUITEM|TASK_MENU_ROUTE_INSTRUCTIONS|
MENUITEM|TASK_DELETE_ROUTE|
MENUITEM|TASK_MENU_PHONE|
MENUITEM|TASK_ITINERARY|
MENUITEM|TASK_PAGE3|
MENUPAGE|TASK_PAGE3|Main Menu 3 of 3|
MENUITEM|TASK_SHOW_WEATHER|
MENUITEM|TASK_MENU_DOWNLOAD|
MENUITEM|TASK_MENU_TRAFFIC|
MENUITEM|TASK_TUTORIAL|
MENUITEM|TASK_SHOW_GPS_STATUS|
MENUITEM|TASK_PAGE1|

A modified menu supporting the "Log Position to Itinerary" function is as follows (notice the last four lines):

MENUBLOCK|BLOCK_MAIN|BTM_GPS_POSITION|
MENUPAGE|TASK_PAGE1|Main Menu 1 of 4|
MENUITEM|TASK_NAVIGATE_TO|
MENUITEM|TASK_MENU_FIND_ALTERNATIVES|
MENUITEM|TASK_SHOW_MAP|
MENUITEM|TASK_ADD_FAVORITE|
MENUITEM|TASK_MENU_PREFERENCES|
MENUITEM|TASK_PAGE2|
MENUPAGE|TASK_PAGE2|Main Menu 2 of 4|
MENUITEM|TASK_MENU_PLAN_ATOB|
MENUITEM|TASK_MENU_ROUTE_INSTRUCTIONS|
MENUITEM|TASK_DELETE_ROUTE|
MENUITEM|TASK_MENU_PHONE|
MENUITEM|TASK_ITINERARY|
MENUITEM|TASK_PAGE3|
MENUPAGE|TASK_PAGE3|Main Menu 3 of 4|
MENUITEM|TASK_SHOW_WEATHER|
MENUITEM|TASK_MENU_DOWNLOAD|
MENUITEM|TASK_MENU_TRAFFIC|
MENUITEM|TASK_TUTORIAL|
MENUITEM|TASK_SHOW_GPS_STATUS|
MENUITEM|TASK_PAGE4|
MENUPAGE|TASK_PAGE4|Main Menu 4 of 4|
MENUITEM|TASK_SDK1|
MENUITEM|TASK_PAGE1|

Testing the TTN script with cgywin

  • Download and install cgywin from http://www.cygwin.com
  • Select a Windows directory for the TTN script environment and perform there the installation described in the previous paragraphs. The expr command inside the Tracer directory should include this script:
#/bin/sh
expr $*
  • Some examples of GPS dumps should be fetched and saved in some backup files. In order to accomplish this, install the script to TTGO, execute it and get some examples of /Tracer/GpsLog.txt saving them e.g. as gps1, gps2, etc under the previously created directory. This can be also achieved by enabling Debug=2 in the script and then extracting the samples from /Tracer/TtnLog.txt.
  • Run the cgywin bash, position to the script installation directory and execute the following commands:
export LoggerRootDir=/cygdrive/<drive letter>/<path>
export LoggerDoNotChangeDate=yes

The first command will refer to the Windows directory where the TTN script is installed. The second command will avoid that the PC date is changed after the execution of some test exploiting valid GPS data.

  • BOOT event:
./ttn
  • RESUME event:
LoggerGpsData=./gps1 ./ttn GpsLogger RESUME 1
  • SUSPEND event:
LoggerGpsData=./gps2 ./ttn GpsLogger SUSPEND 3
  • LOG event:
LoggerGpsData=./gps3 ./ttn GpsLogger LOG 1

Itinerary File Formats

Event_Logger creates Itinerary files which should be compliant with the TomTom file format.

The management of Itinerary files is included in any updated TomTom version, regardless of the used processor or embedded system (TomTom Mobile for Symbian mobile phones, TomTom Navigator for PDA, all the TomTom GO models, which exploits the ARM Linux O. S., etc.).

A TomTom user can manually create, edit and use Itinerary files as an alternative method to the single destination and optional single 'via' location allowed by the standard “Navigate to…” function of TomTom: exploiting itineraries allows managing journeys which consist of a list of 'waypoints' and 'destinations'; other than planning compound journeys, itineraries can be saved and, as they are ascii files, they can be easily exported. The general syntax for Itinerary records managed by TTGO (e.g., format of each line of an Itinerary file) is:

< longitude >|< latitude >|< comment >|<  flag >|

where:

< longitude > is the longitude in millionths of degrees (WGS84 datum);

< latitude> is the latitude in millionths of degrees (WGS84 datum)

Note: when < longitude >|< latitude >| is valued to 0|0| it means no positioning available and TomTom shows the related line barred.

< comment > might include any string (e.g., in general there should be the point name in the itinerary); see below for the actual syntax used by the Event_Logger inside this field.

< flag > is a number (tipically 0, 1, 2, 3 and 4) The following component values are admitted to generate the flag and all components have to be ORed together in order to produce the flag value.

  • 0x00 None
  • 0x01 Itinerary location is enabled
  • 0x02 Itinerary location is a stop-over (as opposed to a pass-by location)
  • 0x04 Itinerary location is departure point (Should only be set for the first item in the itinerary file)

Considering how the Event_Logger manages this flag, 4 is never used, while 3 is used to mark the last record of a journey, separating the closed journey from the next one. 0, 1 and 2 are used for lines within the same journey (e.g., 0 and 2 make TomTom GO show the previous records in grey instead of black; this is used by the Event_Logger in order to differentiate the representation of heading comments).

Syntax used by the Event_Logger in the Itinerary comment field:

Comment:= <hour>:<minute><first set of symbols><short stopover interval> <altitude>m <speed>km/h<second set of symbols> [<total journey duration>,<real journey duration>] <Address>

Alternate duration syntax:

{<total stop duration>,<real journey duration following the stop>}

Note: all symbols are configurable, including altitude and speed symbols.

Detailed description of each field in the comment string:

<hour>:<minute>: two digits for hour (00-24 format), column symbol, two digits for minutes.

<first set of symbols> the following symbol might optionally be shown:

  • ^: meaning outdated positioning; in this case the positioning is referred to the previous registered event (both TomTom GO and the GPS device were not able to provide positioning data).

<short stopover interval>: it reports short stops within a journey, representing the total minutes resulting from the calculation of the sum of any contiguous short stop period; more precisely, the reported value consists of the overall period of a sequence of one or more “stop-and-go” taking in total up to four minutes (configurable timeout); these short breaks are aggregated into one line and made part of the current journey in order to improve readability of itinerary records by differentiating the representation of short stopovers from long stops, where the latter case of stops (e.g., longer than four minutes) conclude a journey and produce the separation of the performed journey from the next one (e.g., set the < flag > field of the last record of the journey to 3 instead of 1). The syntax is <-><minutes> (e.g., minutes preceded by the dash symbol) and in case the period at a waypoint takes less than one minute, the additional <’> apostrophe character is added at the end. The related date is referred to the last aggregated event (by subtracting the reported minutes, the date of the occurrence of the first aggregated event can be easily calculated).

<altitude>: parameter optionally returned by the GPS device, followed by the “m” symbol (the metric unit is currently used but the script can be modified to produce feet).

<speed> parameter optionally returned by the GPS device or by TomTom GO, followed by the “km/h” symbol (the script can be modified to produce miles-per-hour).

< second set of symbols > the following symbols are used:

  • *: the line is generated by the manual selection of the appropriate menu button (Note: the asterisk (*) was formerly represented as degree symbol (°).) If this symbol is not available, the line was produced by a TomTom event.
  •  !: the positioning information might be slightly outdated (not produced by the GPS device, simply fetched from the TomTom cache; in this case, altitude is missing as TomTom does not currently manages this dimension)

<total journey duration>: period covering the time difference between the last registered event of a journey (e.g., last stop) and the first one (e.g., first start).

<total stop duration>: duration of a long stop (more than 4 minutes), reporting the time separating two different and consecutive journeys. It is enclosed within curly brackets to differentiate it from the total journey duration, which is enclosed in square brackets. The first line (event) of a journey should include this data, optionally followed by the real journey duration, which is separated by a comma inside the braces.

<real journey duration>: sum of all the real trip durations composing a single journey (different from the “total journey duration”, which also computes the small stop timings between two trips). To improve readability, the < real journey duration > field is only reported if the related value is different from the <total journey duration> field (e.g., in general the real duration is slightly shorter than the total duration; anyway the values can be the same if a journey does not include short stopover intervals).

Time formats used in fields <total journey duration>, <total stop duration> and <real journey duration> are:

  • For intervals up to 59 minutes: <minutes>’ (number of minutes followed by the apostrophe symbol)
  • For intervals between 1 hour and 23:59 hours: <hour>:<minute> (one or two digits for hour in 0-24 format, column symbol and two digits for minutes).
  • For longer intervals: <number of days>-<hour>:<minute>
Address:= <street name> <adjacent number1>-<adjacent number2>, <city>

The optional geodecoded information has currently a fixed syntax representing house number or numbers (when available) after the street name. If there are two house numbers, they are separated by a dash symbol. Street (when available) and city names are separated by the comma symbol.

For each event, the date when the event occurred and the related interval computations are basic information always available. As a matter of fact, these data can be directly managed by the Event_logger script and do not depend from TTGO and from the GPS device.

Through the interaction with TTGO via SDK, the Event_logger enhances the data by adding the following values:

  • Positioning, speed and altitude, when the GPS provides this data;
  • Cached positioning, important when the GPS device cannot provide information (the altitude field is anyway unmanaged by TTGO and so not cached);
  • Geodecoding: street, street numbers and city name

There are cases in which the SDK interaction fails and does not produce enhancements to the basic information produced by the Event_Logger; for example, after a reset the SDK management is temporarily frozen until TTGO retrieves the first valid information from the GPS device; as soon as this information is retrieved, the SDK management starts and correctly provides updated information received from the GPS device or cached information in case the GPS data are not available. Consider also that when a route calculation freezes waiting for a valid GPS data, also the SDK management is inhibited. Notice that even if the GPS data are available, TTGO might give precedence to its internal routing calculation than managing SDK requests; for this reason, the Event_Logger treats asynchronously all external requests managing internal timeouts; so, during a route recalculation or other TomTom internal processing the data enhancement might not be fulfilled in time. In all these cases the enhancements are lost (e.g., not used by the Event_logger).

When browsing or managing an Itinerary file within TomTom, while TomTom controls the longitude, altitude, and flag fields in each Itinerary line, it completely ignores all the previously described syntax internally used by the Event_Logger and simply shows the whole comment field as a multiline string (e.g., one or two lines per record, depending on the field length).

Example:

934137|4556701|17:49 197.6m 97.2km/h* [50',46'] A4/E64 Autostrada Milano Brescia, Agrate Brianza|1|

Meaning: during a journey, on hour 17:49, the driver pressed the custom menu icon when travelling at about 100 km/h over a position with longitude 934137, latitude 4556701 (WGS84 datum in millionths of degrees) and elevation of 198 meters, which corresponds to the highway “A4/E64 Autostrada Milano Brescia” within the town “Agrate Brianza”; in that moment, his journey duration was 50 minutes but the actual driving duration was 46 minutes (that is, there was a short stop of 4 minutes before). When openinf an Itinerary file with this line, the following is shown:

17:49 197.6m 97.2km/h* [50',46'] A4/E64 Autostrada Milano Brescia, Agrate Brianza

As this comment is long and by default only the first characters are shown, press the line and keep it pressed in order to make TTGO change the character format and show the full multiline comment. (Besides, when tapping on the line, the related menu appears and in its heading note the first part of the comment is shown.)

GPX Tracking System

GPX (the GPS Exchange Format) is a light-weight XML data format for the interchange of GPS data (waypoints, routes, and tracks) between applications and Web services on the Internet. Find more information at http://www.topografix.com/gpx.asp

Other than including waypoints in a GPX file basing on the information logged to the Itinerary file, the Event_Logger can optionally log tracks through a specific process periodically polling TTGO in background.

GPX files produced by Event_Logger should pass the validation described at http://www.topografix.com/gpx_validation.asp

GPX files are created if at least one of the two variables DoSdkTracking and DoGpxWpt is set to yes.

When DoGpxWpt is set to yes, <wpt> elements are created upon each waypoint (suspend, resume and log menu buttons events).

When DoGpxWpt is set to yes, DoTrackWpt allows adding <trkseg> elements upon each waypoint, including elevation information in case this is retrieved from the GPS device (this option is not invasive and should always be set to yes).

If DoSdkTracking is set to yes, a daemon is started in low priority execution, repeatedly fetching positioning data from TTGO via SDK, each TrackingGranularity seconds. Even if the process takes minimum resources, in case tracking information is unneeded, avoid starting it (unset DoSdkTracking). In order to reduce the impact to the minimum, the daemon only interacts with TomTomGO via SDK file interface, without performing direct collection from the GPS device; by consequence of this, elevation data is not retrieved inside these <trkseg> elements (not provided by TomTomGO).

A GPX file can include zero or more <wpt> (waypoints) and/or zero or more <trk> sections with optional <trkseg> (track points). Null GPX files are anyway discarded. Track points and waypoints are distributed into more files basing on rules controlled by variables NewGpxWhenDateChanges, NewGpxWhenDayChanges, NewGpxWhenNewItinerary, NewGpxWhenBooting and NewGpxWhenNewTravel.

If NewGpxWhenDateChanges is set to yes, a new GPX file is created as soon as the date changes. If NewGpxWhenDayChanges is set to yes, a new GPX file is created as soon as the day changes. If NewGpxWhenNewItinerary is set to yes, a new GPX file is created if the itinerary file is missing, renamed or deleted. If NewGpxWhenBooting is set to yes, a new GPX file is created upon each boot. If NewGpxWhenNewTravel is set to yes, a new GPX file is created as soon as a new travel is identified (e.g., suspend interval taking more than ShortInterval minutes).

Appropriate variables control tracks segmentation, which produces more <trk> sections basing on a timeout expiration. GPX tracks are segmented if DoBreakTracks is set to yes and when the same 2d fix (latitude, longitude) does not change for more than (TrackingGranularity + DelayToBreakTracks) seconds. The configuration variable AllowDuplicatedCoords controls the process used to segment tracks; if not set, no information is collected when TTGO stands in a fixed position for enough time (typically when the vehicle stops for enough time, e.g., waiting in queue with ignition on) and a new track segment is produced when the position returns to change; besides, a new track segment is generated each time the vehicle ignition is restarted (e.g., TTGO stays suspended for enough time). If AllowDuplicatedCoords is set to yes, only when TTGO stays suspended for enough time a new track segment is generated.

Generated GPX files are compressed through gzip to save space and archived under the directory /Tracer/Tracks inside the SD card (check TrkPath variable). Dates (name of each GPX file, archive and internal dates in the trk sections) refer to the archiving instant using local time (e.g., do not support the GPX directive to use the UTC time).

Currently collected GPX information are stored in files /Tracer/Wpt.gpx and /Tracer/Trk.gpx. In order to allow the creation of the last GPX file including the recently fetched data, one of the event controlled by the NewGpxWhen… variables must be manually generated before analyzing the /Tracer/Tracks directory in the SD Card (e.g. if NewGpxWhenBooting is set to yes, extract the SD card, insert it again, perform a boot, wait a while in order to allow the creation and compression of the GPX file; then extract the SD card and inspect the /Tracer/Tracks directory).

GPX file size depends on the selected information and on the travelling period. In general, each travelling hour might produce up to about 5 KB of compressed GPX data. Files in /Tracer/Tracks should be periodically deleted or moved out of the SD card in order to preserve space.

TTN Version 5.2beta (to be placed in the root filesystem of the SD card)

#!/bin/sh
################################################################################
# <<ttn>> to be installed in the root directory of the TomTom GO (TTGO) SD card.
# Event_Logger (/mnt/sdcard/ttn) - Version 5.3beta - amacri(at)tiscali.it
# <<REMARK: PRELIMINARY TO VERSION 6.0; INCLUDES BUGS AND PERFORMANCE ISSUES>>
# http://wiki.opentom.org/index.php/Event_Logger (Note: use UNIX newline format)
# Requires: (1) /Tracer directory (/mnt/sdcard/Tracer) and (2) /Tracer/expr
# Create (1) on the SD card. As (2) is not not available in the current TTGO
# busybox set, it can be downloaded from: http://rpmfind.net/linux/RPM/
# netwinder/netwinder/RPMS/base/3.1-15/sh-utils-2.0-1.armv4l.html
################################################################################

test "$LoggerGpsData" || LoggerGpsData=/dev/gpsdata
test "$LoggerRootDir" || LoggerRootDir=/mnt/sdcard
# Uncomment to trace (e.g., debug why TTGO hangs while booting, if just keeps
# displaying 2 hands). Typical issue: always use the UNIX line separator format!
#exec 1>>$LoggerRootDir/BootLog.txt 2>&1;set -x;echo -e "\n\n`date` - ttn START\n\n"
#exec 1>>/var/run/TtnLog.txt 2>&1;echo -e "\n\n`date` - ttn START\n\n" # option B

############## START OF CONFIGURATION VARIALBES ################################
# Time synchronization:
TIMEZONE=UTC+2  # IMPORTANT: set this to your current time zone (TZ, std UNIX format)
                # E.g.: UTC0 for Greenwich, UTC+2, UTC-1, etc.
TIMEZONEI=UTC-2 # IMPORTANT: set this to the INVERSE of your current time zone
                # E.g.: UTC0 for Greenwich, UTC-2 if your TZ is UTC+2, UTC+1
                # if your TZ=UTC-1. GMT can also be used in place of UTC.
SyncTime=yes # Set to yes if you want to keep Linux time always in sync with GPS
             # time. Default is yes (TIMEZONE/I needed only if this flag is yes)

AllowDateTranslation=yes # Unset this to disable localization of date strings.
    # See ConvertDate() to set the translation strings to the target language.

# String to discard in address geodecoding (sensible to the TTGO used locale)
# UnnamedRoadString1='Unnamed road' # English
UnnamedRoadString1='(Senza nome posizione)' # Italian
UnnamedRoadString2='Strada senza nome' # Italian
AddIntervals=yes # (yes|no/unset) calculate and report the duration of each journey

# Logging
DebugLog=NoLog # set this to "DoLog" (perform logging) or to "NoLog" (disable logging)
Debug=0 # Default setting (Debug variable not relevant if DebugLog=NoLog)
# -1: no error logging, no stdout and stderr redirection
# 0: no debug, no stdout and stderr redirection (only error logging)
# 1: minimal debug
# 2: standard debug
# 3: trace also part of the code

# Log timings:
DumpDate=1 # 0: Do not log date changes inside the Itinerary file, default=1: log
MaxSilentDateInterval=300 # seconds needed for a date change to be logged.
MaxItnLines=45 # max number of lines in an itinerary file.
# Note: TTGO truncates Itinerary files with more than 48 lines.
ShortInterval=6 # Minutes. More events are aggregated into one if happening within this
# timeframe. Default=6 minutes. Set ShortInterval=-1 to disable this feature.
GpsLines=10 # Number of consecutive lines to read (and wait for) from the GPS device before processing GPS data
Rounding=31 # Rounding of seconds to the nearest minute in date calculations (including computation delays)

# Symbols and labels:
AggregSeparatorSymbol='-' # used in aggregated records as header of the aggregation interval (in minutes)
LessThanOneMinuteSymbol="'" # used to identify aggregate records less than one minute; they should be
# reported as "-0", but this is forced to "-1" + LessThanOneMinuteSymbol (can be also set to null)
LogSymbol='*' # used to identify intermediate marks (shown as asterisk by TTGO; can be set to null)
DaySeparatorSymbol='-' # used for the duration strings covering more days
LogRotationSymbol='<' # header of Today date string for Itineray files rotated because > than MaxItnLines
PreviousRecordSymbol='^' # Used in the DateFormatO to identify records with outdated fix
OutdatedRecordSymbol='!' # Used in the DateFormatO to identify records with outdated fix
ResetString="RST"
IntOS='{'
IntCS='}'
IntOR='['
IntCR=']'

SpeedUnit="km/h"
ElevationUnit="m"
# See commented & untested code inside the script in order to enable unit conversion

DateFormatO="+%H:%M$PreviousRecordSymbol" # Date for records with old position (no satellite coverage)
DateFormat="+%H:%M" # Date for records with current, valid fix
LongDateFormat="+%d/%m %H:%M" # Date included in description records
Today="+%A %e %B %Y" # Date included in the new day notifications

# Usage of the SDK
DoSdkShowMessage=yes
FlashMessageDuration=20 # seconds
DoSdkGeodecode=yes
DoSdkPosition=yes
DoSdkAddPoi=yes # Se to yes in order to add POIs to file $PoiFileName upon events described in PoiEventFilter (otherwise unset)
PoiEventFilter='POI' # Quoted list of events separated by '|' generating a Poi if DoSdkAddPoi=yes (e.g.: 'RESUME|LOG' or '*')
PoiFileName=Tracker # Filename without the ".ov2" extension, to be created in the current "Map" directory, hosting the
# POIs added through $DoSdkAddPoi and $PoiEventFilter. (An icon file $PoiFileName.bmp can be manually saved there if needed.)
SdkDisableAutoZoom=

# GPX Tracking System control variables:
DoSdkTracking=yes # if set to yes, a specific daemon starts in background, tracking samples periodically fetched from TTGO.
DoBreakTracks=yes # GPX tracks are broken if DoBreakTracks is set to yes and when the same fix (latitude,longitude)...
TrackingGranularity=20 # Polling period in seconds to fetch positioning data from TTGO via SDK.
DelayToBreakTracks=10 # [Seconds]. ...does not change for more than $((TrackingGranularity+DelayToBreakTracks)) seconds
AllowDuplicatedCoords= # this controls the process used to break tracks; if set to yes, only TTGO suspend delays are used.
TrackingReadLoops="1" # (do not change it)
GpxAuthor='amacri' # Any string (XML escapes are needed if special characters are used)
GpxEmail= # Any valid e-mail (XML escapes are needed if special characters like "<" and ">" are used)
GpxUrl='http://wiki.opentom.org/index.php/Event_Logger' # Any valid URL (XML escapes are needed if special characters are used)
GpxUrlName='Event_Logger 6.0' # Any string (XML escapes are needed if special characters are used)
DoGpxWpt=yes # Add waypoints to GPX (ref. to events logging: poweroff, poweron, boot and menu buttons)
DoTrackWpt=yes # track waypoints (duplicate <wpt> data to <trkpt> in GPX files)
NewGpxWhenDateChanges= # Start a new Gpx file as soon as the date changes
NewGpxWhenDayChanges= # New Gpx file as soon as the day changes
NewGpxWhenNewItinerary=yes # New Gpx file if the itinerary file is missing, renamed or deleted.
NewGpxWhenBooting=yes # New Gpx file upon each boot
NewGpxWhenNewTravel=yes # New Gpx file as soon as a new travel is identified (long interval)

# Itinerary file name for TTGO:
ITNPath=$LoggerRootDir/itn
ITNName=_Logger.itn # Initial underscore ensures to stay first in the TTGO file list
ITNOHeader=Log
OldLogFileFormat="+%y-%m-%d_%H.%M"
ITNExtension=itn
ITN="$ITNPath/$ITNName" # Actual Itinerary pathname

HourToStartItnRotation="03:30:00" # Hour:minute:second of the current day
# Set this to the less probable driving hour: if the Itinerary file is found older
# than this hour and a new record is being added, a rotation is performed first.

# Tarball archiving of old Itinerary files (gzip compression)
OldItnToKeepOnline=10 # set to 0 to disable this feature
TarExtension=tgz
Tarball="$ITNPath/EventLogger.$TarExtension"
OldTarball="$ITNPath/EventLogger-old.$TarExtension"
AllowRestoreFromTarball=yes

#Log file:
TmpDir="/var/run"
MAINDIR="$LoggerRootDir/Tracer"
LOGFILE="$TmpDir/elg_TtnLog.txt"
LogfileSD="$MAINDIR/TtnLog.txt"
TrkPath="$MAINDIR/Tracks"

# Temporary files:
ITNOK="$MAINDIR/LastLog.itn" # This is the only one which goes to the SD card (other than ITNs and logs)
MountLog="$TmpDir/elg_MntLog" # mount logging and flag
ShortIntervalSkipFlag="$TmpDir/elg_EvLogSkipFlag.txt" # If existing, next ShortInterval is ignored
#   dates to be shared among subsequent script instances are stored
#   as temporary files and read with date -r<temp file> "+%s"
LastGpsDate="$TmpDir/elg_LastGpsDate" # Event and date of the last (current) GPS retrieval
ShortIntervalPermanentDate="$TmpDir/elg_EvLogIntDate" # First aggregated record (last master record before aggregation)
MasterEventDate="$TmpDir/elg_MasterEventDate" # Date and event of the valid master record
PrevMasterEventDate="$TmpDir/elg_PrevMstrEvtDate" # Date and event of the previous valid master record
TripSeconds="$TmpDir/elg_TripSeconds" # Last track start date and duration of the previous tracks of a route
TextForNextItem="$TmpDir/elg_TextNextItem" # Includes a string to be added to each next item (ref. next scripts)
WptFile="$MAINDIR/Wpt.gpx" # Used by the GPX Tracking System to store Wpt records
TrkptFile="$MAINDIR/Trk.gpx" # Used by the GPX Tracking System to store Trkpt records
TrkptFileTemp="$MAINDIR/Trk-tmp.gpx" # Used by the GPX Tracking System.

# Commands:
oexpr="$MAINDIR/expr" # Original UNIX "expr" utility (to be installed; not available within busybox)
expr="/bin/expr" # expr command is then moved to bin (RAM) in order to speed-up activation
OEXEC="$LoggerRootDir/ttn" # Original "ttn" wrapper" (to be installed in the root of the SD)
EXEC="/bin/GpsLogger" # "ttn" wrapper is then moved to $EXEC (RAM) to speed-up activation
RealTtn="/bin/ttn" # this is the real TTGO application (that one wrapped by this script)
SH="/bin/ash" # $SH will be the interpreter executing this script (default "/bin/ash")
#OSH="$MAINDIR/zsh" # if this variable is set, $SH will be replaced by $OSH; deault is unset
############### END OF CONFIGURATION VARIALBES #################################

NoLog() # Hoping that this speeds up performance if logs are deactivated...
{
return 1
}

DoLog()
{
# ...notice that each test in ash is a call to an external program
if test "$Debug" -ge $1
   then shift
        test $# -gt 0 && echo -e "`date`-$Application-$Event-$$: $*"
        return 0
fi
return 1
} # of DoLog


ConvertDate()
{
# Translation of date strings.
# Okay, using locale should be a better alternative, but provided that it is
# first set up in the Linux environment of TTGO. Who is willing to perform this?

if test "$AllowDateTranslation" = yes
   then
# Find below an example of Italian translation; strings can be changed as needed.
sed 's/January/gennaio/
s/February/febbraio/
s/March/marzo/
s/April/aprile/
s/May/maggio/
s/June/giugno/
s/July/luglio/
s/August/agosto/
s/September/settembre/
s/October/ottobre/
s/November/novembre/
s/December/dicembre/
s/Monday/Lunedì/
s/Tuesday/Martedì/
s/Wednesday/Mercoledì/
s/Thursday/Giovedì/
s/Friday/Venerdì/
s/Saturday/Sabato/
s/Sunday/Domenica/
s/  / /' # this is needed because the %- modifier of date strings should be unsupported
else sed 's/  / /'
fi
} # of ConvertDate

######################
trkptDaemon()
{
$DebugLog 3 && set -x && exec 1>>$LoggerRootDir/TrxLog.txt 2>&1

export ProcessId=$$
sleep 30
OldLatitude=
OldLongitude=
OldLatitudeF=
LatitudeU=
LatitudeD=
OldLongitudeF=
LongitudeU=
LongitudeD=
OldStrings=
GpxCourse=
GpxSpeed=
GpxFix=
PrevTime=`date "+%s"`
SameCoords=

#infinite loop
while true
do

#query
echo -e "GetCurrentPosition|\0\c">"/var/run/SDK.TomTomNavigationServer.$ProcessId.9.message"
echo finish>"/var/run/SDK.TomTomNavigationServer.$$.9.finished"

#wait
sleep $TrackingGranularity

#fetch
SdkRetCode= SdkGCPUpdate= SdkGCPLongitude= SdkGCPLatitude= SdkGCPSpeed= SdkGCPDirection= SdkGCPOther=
for i in $TrackingReadLoops
do
if test -s "/var/run/TomTomNavigationServer.SDK.$ProcessId.9.finished"
   then { # Fetch data from the SDK response
        GpxDate=`date -r "/var/run/TomTomNavigationServer.SDK.$ProcessId.9.finished" "+%Y-%m-%dT%H:%M:%S" 2>/dev/null`
        test "$GpxDate" || continue
        OIFS="$IFS" IFS='|'
        read SdkRetCode SdkGCPUpdate Longitude Latitude SdkGCPSpeed SdkGCPDirection SdkGCPOther
        IFS="$OIFS"
        } >/dev/null 2>&1 <"/var/run/TomTomNavigationServer.SDK.$ProcessId.9.message"
        break
fi
sleep $i 2>/dev/null
done

if ! $DebugLog 1
   then rm -f "/var/run/TomTomNavigationServer.SDK.$ProcessId.9."* "/var/run/SDK.TomTomNavigationServer.$ProcessId.9."* >/dev/null 2>&1
fi

#skip invalid records
if ! test "$SdkRetCode" -ge 0 2>/dev/null 2>&1
   then test "$SameCoords" = yes || PrevTime=`date "+%s"`
        continue
fi
if test ! "AllowDuplicatedCoords" = yes -a "$Longitude" = "$OldLongitude" -a "$Latitude" = "$OldLatitude"
   then SameCoords=yes
        continue
fi
SameCoords=

#prepare
OldLatitude="$Latitude"
OldLongitude="$Longitude"
OldLatitudeF="${LatitudeU}.${LatitudeD}"
OldLongitudeF="${LongitudeU}.${LongitudeD}"
OldStrings="$GpxCourse$GpxSpeed$GpxFix"
LatitudeU="${Latitude%?????}"
LatitudeD="${Latitude#$LatitudeU}"
LongitudeU="${Longitude%?????}"
LongitudeD="${Longitude#$LongitudeU}"
test "$SdkGCPDirection" && GpxCourse="<course>${SdkGCPDirection}.0</course>"
Speed="$SdkGCPSpeed${SdkGCPSpeed:+.0}"
#test "$Speed" && GpxSpeed="<speed>$Speed.0</speed>" # This is not correct as uses km/h instead of m/sec
if [ "$Speed" ]
   then # Convert km/h to m/sec
        SpeedMs=`$expr \( ${Speed%.*}${Speed#*.}000 / 36 + 5 \) / 10`
        SpeedMsU="${SpeedMs%??}"
        SpeedMsD="${SpeedMs#$SpeedMsU}"
        SpeedMsU="${SpeedMsU:-0}"
        SpeedMsD="${SpeedMsD:-0}"
        GpxSpeed="<speed>$SpeedMsU.$SpeedMsD</speed>"
fi
GpxFix='<fix>none</fix>'
test "$SdkGCPUpdate" -gt 0 && GpxFix='<fix>2d</fix>'
#write
Time=`date "+%s"`
test -f "$TrkptFile" || echo '<trk><name>'"`date \"$Today %H:%M:%S\"|ConvertDate`"'</name><trkseg>' >> "$TrkptFile"
test "$DoBreakTracks" = yes -a ! "$OldLatitudeF" = "." -a ! "$OldLongitudeF" = "." -a `$expr $Time - $PrevTime - $TrackingGranularity` -gt $DelayToBreakTracks && \
   echo '</trkseg></trk><trk><name>'"`date \"$Today %H:%M:%S\"|ConvertDate`"'</name><trkseg>'\
'<trkpt lat="'"${OldLatitudeF}"'" lon="'"${OldLongitudeF}"'"><time>'"$GpxDate"'Z</time>'"$OldStrings"'</trkpt>' >> "$TrkptFile"
echo '<trkpt lat="'"${LatitudeU}.${LatitudeD}"'" lon="'"${LongitudeU}.${LongitudeD}"'"><time>'"$GpxDate"'Z</time>'"$GpxCourse$GpxSpeed$GpxFix"'</trkpt>' >> "$TrkptFile"
PrevTime="$Time"

done
} # of trkptDaemon
######################

WptTrkPoi()
{
SymType="<sym>Dot</sym><type>$1</type>"
case "$1" in RESUME|SUSPEND|BOOT)SymType="<sym>Waypoint</sym><type>$1</type>";;esac
if test "$DoGpxWpt" = yes
   then test -f "$WptFile" || echo '<desc>FIRST '"`date \"$Today %H:%M:%S\"|ConvertDate`"'</desc>
 '"${GpxAuthor:+<author>}$GpxAuthor${GpxAuthor:+</author>}${GpxEmail:+<email>}$GpxEmail${GpxEmail:+</email>}
 ${GpxUrl:+<url>}$GpxUrl${GpxUrl:+</url>}${GpxUrlName:+<urlname>}$GpxUrlName${GpxUrlName:+</urlname>}" >> "$WptFile"
        echo "<wpt $3$5$SymType</wpt>" >> "$WptFile"
fi
if test "$DoTrackWpt" = yes
   then test -f "$TrkptFile" || echo '<trk><name>'"`date \"$Today %H:%M:%S\"|ConvertDate`"'</name><trkseg>' >> "$TrkptFile"
        echo "<trkpt $3$4</trkpt>" >> "$TrkptFile"
fi
if [ "$DoSdkAddPoi" = yes ]
   then eval case "$1" in $PoiEventFilter\)\;\;*\) return\;\;esac
        echo -e "AddPoi|$PoiFileName|$2|\0\c">"/var/run/SDK.TomTomNavigationServer.$$.8.message"
        echo finish>"/var/run/SDK.TomTomNavigationServer.$$.8.finished"
fi
}

GpxEnveloper()
{
DateFile="$WptFile"
test -f "$DateFile" || DateFile="$TrkptFile"
test -f "$DateFile" || return
GpxFile="$TrkPath/Trk_`date -r "$DateFile" \"+%y-%m-%d_%H.%M.%S\"`.gpx"

# GPX Header
echo '<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<gpx
 version="1.0" creator="Event_Logger 6.0 - http://wiki.opentom.org/index.php/Event_Logger"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/0"
 xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
<name>LAST '"`date -r "$DateFile" \"$Today %H:%M:%S\" 2>/dev/null |ConvertDate`"'</name>' > "$GpxFile"
cat "$WptFile" >> "$GpxFile"  2>/dev/null
#if [ $? -ne 0 ]
#   then rm -f "$GpxFile"
#        return
#fi

if mv "$TrkptFile" "$TrkptFileTemp" 2>/dev/null
   then
        cat "$TrkptFileTemp" >> "$GpxFile" 2>/dev/null
        echo '</trkseg></trk>' >> "$GpxFile" # Track footer
fi
# GPX Footer
echo '</gpx>' >> "$GpxFile"
rm -f "$WptFile" "$TrkptFileTemp"
gzip "$GpxFile" & # unfortunately bzip2 is not currently available within busybox
} # of GpxEnveloper

GetGeodecode()
{
SdkRetCode= SdkGCPUpdate= SdkGCPLongitude= SdkGCPLatitude= SdkGCPSpeed= SdkGCPDirection= SdkGCPOther=
for i in 0 0 0 1 1 1
do
if test -s "/var/run/TomTomNavigationServer.SDK.$ProcessId.1.finished"
   then { # Fetch data from the SDK response
        OIFS="$IFS" IFS='|'
        read SdkRetCode SdkGCPUpdate SdkGCPLongitude SdkGCPLatitude SdkGCPSpeed SdkGCPDirection SdkGCPOther
        IFS="$OIFS"
        } >/dev/null 2>&1 <"/var/run/TomTomNavigationServer.SDK.$ProcessId.1.message"
        if test "$SdkRetCode" -ge 0 -a "$SdkGCPLongitude" -a "$SdkGCPLatitude" 2>/dev/null
           then echo -e "GetLocationInfoEx|$SdkGCPLongitude|$SdkGCPLatitude|\0\c">"/var/run/SDK.TomTomNavigationServer.$ProcessId.3.message"
                echo finish>"/var/run/SDK.TomTomNavigationServer.$ProcessId.3.finished"
        fi
        return
fi
sleep $i 2>/dev/null
done
} # of GetGeodecode

MakeOldItnTarball()
{
# Move old Itinerary files to a "$Tarball" tgz archive (gzip compressed tar),
# always leaving "$OldItnToKeepOnline" files online (e.g., not archived);
# if $AllowRestoreFromTarball is set to yes, also restore from archive if the
# files online are not enough to reach the number of "$OldItnToKeepOnline".
# By checking existence of "$OldTarball", this function should allow rollback
# in any moment without loss of files, if e.g. it is broken while resetting
# or suspending. Return codes: 0=ok, 1=failed, 2=major error.
test "$OldItnToKeepOnline" -lt 1 && return
$DebugLog 1 "archiving started"
TmpItnDir="$TmpDir/elg_tar-$$"
test -f "$OldTarball" && return 2
mkdir "$TmpItnDir" 2>/dev/null || return 2
$DebugLog 3 && set -x
PWD=`pwd`
if ! cd "$TmpItnDir"
   then rm -rf "$TmpItnDir"
        $DebugLog 3 && set +x
        return 1
fi
if test -s "$Tarball"
   then tar -xzf "$Tarball" && mv "$Tarball" "$OldTarball"
        if [ $? -ne 0 ]   
           then mv "$Tarball" "$ITNPath/bad-`basename "$Tarball" .$TarExtension`-`date \"+%y-%m-%d_%H.%M.%S\"`.$TarExtension"
                rm -rf "$TmpItnDir"
                cd "$PWD"
                $DebugLog 3 && set +x
                return 1
        fi
   else >"$OldTarball"
fi
FileList=`ls -t "$LoggerRootDir/itn/"Log-*.itn 2>/dev/null|sed "1,${OldItnToKeepOnline} d
s;.*;\'&\';"`
Cmd=
if test "$FileList"
   then Cmd=`echo "$FileList"|sed "s;.*;cp -p & \"$TmpItnDir\";"`
   else test "$AllowRestoreFromTarball" = yes && Cmd=`{ set -- "$LoggerRootDir/itn/"Log-*.itn
   shift;test $# -gt 0 && ls -t $*;ls -t;}|sed "${OldItnToKeepOnline},\\$ d
s;^$LoggerRootDir/itn/.*;;
/^$/ d
s;.*;mv \"&\" \"$LoggerRootDir/itn\";"`
fi
test "$Cmd" && eval "$Cmd" && if [ `set -- *;echo "$1"` = '*' ]
   then eval rm -f $FileList "$OldTarball" "$Tarball"
   else tar -czf "$Tarball" * && eval rm -f $FileList && rm -f "$OldTarball"
fi
if test -f "$OldTarball" # if archiving failed, then rollback
   then if $DebugLog 1 && test "$Cmd"
           then $DebugLog 1 "failed generation of $Tarball"
           else $DebugLog 1 "nothing to archive in $Tarball"
        fi
        cd "$PWD"
        rm -f "$Tarball"
        test -s "$OldTarball" && mv "$OldTarball" "$Tarball"
        rm -rf "$TmpItnDir"
        rm -f "$OldTarball"
        $DebugLog 3 && set +x
        test "$Cmd" && return 1
        return 0
fi
cd "$PWD"
rm -rf "$TmpItnDir" || return 2
$DebugLog 1 "generation of $Tarball successfully completed"
$DebugLog 3 && set +x
return 0
} # of MakeOldItnTarball

GetGpsData() # Notice this function must not use the SD card
{
# $1: Event: RESUME|SUSPEND|BOOT
case "$1" in RESUME|SUSPEND|BOOT);;*)LoggerGpsData=/var/run/gpsfeed;;esac # set the variable only for LOG type events
Command=
Command="`head -n $GpsLines $LoggerGpsData`"
if test ! "$Command"
then sleep 3
     Command="`head -n $GpsLines $LoggerGpsData`"
fi
if test ! "$Command"
   then $DebugLog 1 "Fetch of GPS data failed."
        return 1
fi

case "$1" in RESUME|SUSPEND|BOOT)echo "$1">"$LastGpsDate";;esac
test "$1" = "RESUME" && touch "$TripSeconds"

$DebugLog 1 "Dump of GPS data:\n$Command"

# Date management (if env. $LoggerDoNotChangeDate is set to yes, it allows to test without changing the date)
$DebugLog 3 && set -x
if test "$SyncTime" = yes -a ! "$1" = BOOT -a ! "$1" = RESUME
   then NewDate=`echo "$Command" | sed '1h;/^\$GPRMC/h;g;/^\$GPRMC/! d;$! d
s/^\$GPRMC,\([0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\)\.[^,]*,A,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,\
\([0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\),.*/\
20\6.\5.\4-\1:\2:\3/
s/^\$GPRMC.*//'`
# Notice that the busybox date -d/-s requires the non standard format "+%Y.%m.%d-%H:%M:%S"
        test ! `TZ=$TIMEZONE date "$LongDateFormat"` = "`date -d \"$NewDate\" \"$LongDateFormat\"\
         2>/dev/null`" 2>/dev/null && case "$NewDate$LoggerDoNotChangeDate" in
        20[0-9][0-9].[0-1][0-9].[0-3][0-9]-[0-2][0-9]:[0-5][0-9]:[0-5][0-9])
            if date -u -s "$NewDate" && date `TZ=$TIMEZONEI date "+%m%d%H%M%Y.%S"`
               then Ndate=`date "$LongDateFormat"`
                    $DebugLog 1 "date changed to $Ndate = $NewDate + $TIMEZONE."
               else $DebugLog 1 "failed to change date to $NewDate."
            fi
            ;;
        "") $DebugLog 2 "Null date string; date not changed."
            ;;
        *)  $DebugLog 2 "string \"$NewDate$LoggerDoNotChangeDate\" not valid to change the date."
            ;;
        esac 
fi
$DebugLog 3 && set +x
return 0
} # of GetGpsData

WaitForBackgroundPids()
{
List=
# if $1=command, $2=60 and $3=pid, time limit to wait for is 60x1=60 seconds
case "$2" in
60) List="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 \
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60";;
esac
for j in $List END
do
    FoundPid=
    if test -f /bin/ttn
       then Cmd=`ps -ef |grep -v $3`
       else Cmd=`top -bc -n1 |grep -v $3`
    fi
    $DebugLog 2 "doing probe $j\n$Cmd"
    case "$Cmd" in
     *sh*GpsLogger*) FoundPid=yes;;
     *) break;;
    esac
    if test $j = END
       then $DebugLog 1 "probes finished."
            return 1
       else sleep 1
    fi
done
$DebugLog 1 "WAIT probes=$j"
return 0
}

PsTop()
{
echo _______________________________________________________ >> /mnt/sdcard/top.txt 2>&1
echo $$ >> /mnt/sdcard/top.txt 2>&1
echo _______________________________________________________ >> /mnt/sdcard/top.txt 2>&1
while true
do
top -d 20 >> /mnt/sdcard/top.txt 2>&1 &
ps -ef >> /mnt/sdcard/top.txt 2>&1
sleep 20
done
}


################################################################################
GpsLogger()
{
# $1: Event: RESUME|SUSPEND|BOOT
# $2: Flag: 0=grey start, 1=start, 2=grey stop, 3=stop, 4=first
Flag="$2"

#####
## STEP H1: report date change
if [ ! "$Odate" = "$Ndate" ]
   then $DebugLog 1 "date was changed (old one: $Odate; new one: $Ndate)"
        if test "$DumpDate" -eq 1
            then echo -e "0|0|Old date $Odate|0|\n0|1|New date $Ndate|1|" >>"$ITN"
                 DenyAggregation=yes
                 test "$NewGpxWhenDateChanges" = yes && GpxEnveloper
        fi
fi

## STEP H2: while resuming, leave background processes terminate first
test "$1" = "RESUME" -a "$3" && WaitForBackgroundPids $1 60 $3

## STEP H3: Manage log rotation
DoArchive=
SecondsItn=
if test -f "$ITN"
  then SecondsItn=`date -r"$ITN" "+%s"`
       DateToStartItnRotation=`date -d"$HourToStartItnRotation" "+%s"`
       test $DateToStartItnRotation -gt $SecondsNow 2>/dev/null && DateToStartItnRotation=`$expr $DateToStartItnRotation - 86400` # go back one day
# do not break logging if a change of day occurs before a LOG type or SUSPEND event
# anyway, always break when exceeding $MaxItnLines
       if [ \( \( "$1" = "RESUME" -o "$1" = "BOOT" \) -a $DateToStartItnRotation -gt $SecondsItn \) -o `set -- \`wc -l "$ITN"\`;echo $1` -ge $MaxItnLines ]
          then OldItn="$ITNOHeader-`date -r"$ITN" \"$OldLogFileFormat\"`.$ITNExtension" # log name corresponds to the date of the last event
               while test -f "$ITNPath/$OldItn"
                  do test "$Counter" || Counter=1
                     OldItn="$ITNOHeader-`date -r"$ITN" \"$OldLogFileFormat\"`-$Counter.$ITNExtension"
                     Counter=`$expr $Counter + 1`
                  done
               test "$NewGpxWhenDayChanges" = yes -a $DateToStartItnRotation -gt $SecondsItn && GpxEnveloper
               echo "0|0|Rotated on $Ndate|2|" >>"$ITN"
               mv "$ITN" "$ITNPath/$OldItn"
               LogRotationSym="$LogRotationSymbol" && test $DateToStartItnRotation -gt $SecondsItn && LogRotationSym=
               # Here rotate ITN because of new day (no LogRotationSymbol mark) or exceeding items (mark with LogRotationSymbol)
               echo "0|0|${LogRotationSym}From $OldItn|1|" >>"$ITN"
               echo "0|0|`date \"$Today\"|ConvertDate`|1|" >>"$ITN"
               test $Flag -gt 0 && Flag=`$expr $Flag - 1` # show comments in grey
               DenyAggregation=yes
               DoArchive=yes
       fi
  else # Here initialize a new $ITN
       echo "0|0|`date \"$Today\"|ConvertDate`|1|" >>"$ITN"
       test $Flag -gt 0 && Flag=`$expr $Flag - 1` # show comments in grey
       DenyAggregation=yes
       test "$NewGpxWhenNewItinerary" = yes && GpxEnveloper
fi

#####
# Now try extracting information from $Command, by parsing relevant strings
Latitude=
Longitude=
Elevation=
Knots=
Speed=

$DebugLog 1 "managing GPGGA"
## STEP A1: extract Latitude
LatitudeSignedDeg=`echo "$Command" | sed '1h;/^\$GPGGA/h;g;/^\$GPGGA/! d;$! d
s/\(^$GPGGA,[^,]*,\)\(..[^,]*,\)\(.\)\(.*\)/\1\3\2\3\4/
s/^\$GPGGA,[^,]*,\(...\)[^,]*,.,[^,]*,.,[123],.*/\1/
s/^[^N]/-/
s/N//
s/^-*\$*GPGGA.*//'`
$DebugLog 2 "LatitudeSignedDeg: $LatitudeSignedDeg"
case "$LatitudeSignedDeg" in
[0-9]*|-[0-9]*)
LatitudeMinutes=`echo "$Command" | sed '1h;/^\$GPGGA/h;g;/^\$GPGGA/! d;$! d
s/^\$GPGGA,[^,]*,..\([^,.]*\)\.\([^,]*\),.*/\1\20000000/
s/^\(........\).*/\1/
s/^-*\$*GPGGA.*//'`
$DebugLog 2 "LatitudeMinutes: $LatitudeMinutes"
LatitudeMinToDeg=`$expr \( $LatitudeMinutes / 60 + 5 \) / 10`
$DebugLog 2 "LatitudeMinToDeg: $LatitudeMinToDeg"
Latitude=`echo "00000$LatitudeMinToDeg" | sed "s/.*\(.....\)\$/$LatitudeSignedDeg\1/
"'s/^\(-*\)0*\(.*\)$/\1\2/'`
$DebugLog 2 "Target Latitude: $Latitude"

## STEP A2: extract Longitude
LongitudeSignedDeg=`echo "$Command" | sed '1h;/^\$GPGGA/h;g;/^\$GPGGA/! d;$! d
s/^\($GPGGA,[^,]*,[^,]*,.,\)\(...[^,]*,\)\(.\)\(,[0-9]*,.*\)/\1\3\2\3\4/
s/^\$GPGGA,[^,]*,[^,]*,.,\(....\)[^,]*,.,[0-9]*,.*/\1/
s/^[^E]/-/
s/E//
s/^-*\$*GPGGA.*//'`
$DebugLog 2 "LongitudeSignedDeg: $LongitudeSignedDeg"
LongitudeMinutes=`echo "$Command" | sed '1h;/^\$GPGGA/h;g;/^\$GPGGA/! d;$! d
s/^\$GPGGA,[^,]*,[^,]*,.,...\([^,.]*\)\.\([^,.]*\),.,[0-9]*,.*/\1\20000000/
s/^\(........\).*/\1/
s/^-*\$*GPGGA.*//'`
$DebugLog 2 "LongitudeMinutes: $LongitudeMinutes"
LongitudeMinToDeg=`$expr \( $LongitudeMinutes / 60 + 5 \) / 10`
$DebugLog 2 "LongitudeMinToDeg: $LongitudeMinToDeg"
Longitude=`echo "00000$LongitudeMinToDeg" | sed "s/.*\(.....\)\$/$LongitudeSignedDeg\1/
"'s/^\(-*\)0*\(.*\)$/\1\2/'`
$DebugLog 2 "Target Longitude: $Longitude"

# STEP A3: extract Elevation
Elevation=`echo "$Command"|sed '1h;/^\$GPGGA/h;g;/^\$GPGGA/! d;$! d
s/^\$GPGGA,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[123],[^,]*,[^,]*,\([^,]*\),M,.*/\1/
s/^-*\$*GPGGA.*//'`
# HINT: Convert here if the elevation unit needs to be changed (e.g., through expr).
# Example of conversion from meters to feet:
#Elevation=`expr \`echo "$Elevation" | sed 's/\.//'\` \* 1000 / 304 | sed 's/.$/.&/'`
$DebugLog 2 "Elevation: $Elevation"
;;

*) $DebugLog 2 "No valid data from GPS";;
esac # Latitude

# STEP A4: extract speed (km/h)
$DebugLog 1 "managing GPVTG"

Speed=`echo "$Command"|sed '1h;/^\$GPVTG/h;g;/^\$GPVTG/! d;$! d
s/^\$GPVTG,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,\([^,]*\),K,.*/\1/
s/^\$GPVTG.*//'`
# HINT: Convert this in miles-per-hour here if needed (e.g., through expr).
# Example of conversion from km/h to miles/h:
#Speed=`expr \`echo "$Speed" | sed 's/\.//'\` \* 10 / 16 | sed 's/.$/.&/'`

$DebugLog 2 "Speed: $Speed"
########## Note: parsing of GPS data finishes here ############

# STEP B1: manage a boot record and Flag field
if [ "$1" = "BOOT" ]
   then Flag=0
        $DebugLog 1 "Boot record is: 0|0|Boot $Ndate|3|"
        echo "0|0|Boot $Ndate|2|" >>"$ITN"
        DenyAggregation=yes
        test "$NewGpxWhenBooting" = yes && GpxEnveloper
fi
test -f "$ITN" || Flag=4
$DebugLog 2 "Flag=$Flag"

$DebugLog 3 && set -x
# STEP B2: manage aggregate records

# Use DenyAggregation to avoid aggregation within this script (e.g. when last $ITN record includes a
# comment which must not be deleted); use ShortIntervalSkipFlag to signal next script to avoid
# aggregation (e.g., next event is a LOG type or there are comments in $ITN made by a previous script)

# Master records are RESUME or SUSPEND event logs not replacing a previous event (so, not involved by aggregation).
# Aggregate records are non LOG type events which occur within ShortInterval from a previous non LOG type event.
# Delta are calculated as time differences from the first deleted record of repeated adiacent removals.
# Intervals are calculated as time differences from the master record occurrence.

# each BOOT event will update both PrevMasterEventDate and MasterEventDate
if [ "$1" = "BOOT" ]
   then cp -p "$LastGpsDate" "$PrevMasterEventDate" 2>/dev/null || echo "$1" > "$PrevMasterEventDate"
        cp -p "$LastGpsDate" "$MasterEventDate" 2>/dev/null || echo "$1" > "$MasterEventDate"
        $DebugLog 1 "BOOT event: new MasterEventDate=`date -r\"$MasterEventDate\"`; new PrevMasterEventDate=`date -r\"$PrevMasterEventDate\"`"
        cp -p "$LastGpsDate" "$TripSeconds"
fi

Delta=
rm "$ShortIntervalSkipFlag" 2>/dev/null && DenyAggregation=yes # If ShortIntervalSkipFlag exists, reset to avoid aggregation
# Comment out the following line if LOG type events shall also be part of aggregations
case "$1" in RESUME|SUSPEND|BOOT);;*)echo "$SecondsPreviousEvent" > "$ShortIntervalSkipFlag";;esac # Do not aggregate after a LOG type event
MasterEvent=

test "$1" = "SUSPEND" -o "$1" = "RESUME" && MasterEvent=yes
DiffDate=`$expr \( $Rounding + $SecondsNow - $SecondsPreviousEvent \) / 60 2>/dev/null`
$DebugLog 2 "DiffDate=$DiffDate ShortInterval=$ShortInterval"
if test ! "$DenyAggregation" = yes -a \( "$1" = "SUSPEND" -o "$1" = "RESUME" \) -a $DiffDate -lt $ShortInterval 2>/dev/null
   then if test -f "$ShortIntervalPermanentDate"
           then DiffDate=`$expr \( $Rounding + $SecondsNow - \`date -r"$ShortIntervalPermanentDate" "+%s"\` \) / 60`
           else cp -p "$MasterEventDate" "$ShortIntervalPermanentDate" || cp -p "$LastGpsDate" "$ShortIntervalPermanentDate" || >"$ShortIntervalPermanentDate"
        fi
        Delta=$AggregSeparatorSymbol$DiffDate
        test "$Delta" = '-0' && Delta="-1$LessThanOneMinuteSymbol"
        if $DebugLog 2
           then echo -e "0|0|^^ Delete!! ^^|1|" >>"$ITN"
           else sed -i -e '$ d' "$ITN" # Delete the last record of the itinerary file
        fi
        grep -v '^0|0|' "$ITN" >/dev/null 2>&1 # returns 1 if $ITN only includes comments
        test $? -ne 0 -a $Flag -gt 0 -a $Flag -lt 4 && Flag=`$expr $Flag - 1` # show comments in grey
        MasterEvent= # this is an aggregate record, not a master event

        # If a SUSPEND event has been removed, also the related MasterEventDate shall be deleted, by restoring the previous value.
        if [ "$TypePreviousEvent" = SUSPEND ]
           then cp -p "$PrevMasterEventDate" "$MasterEventDate" 2>/dev/null # restore the previous master date if any
                $DebugLog 1 "SUSPEND event removed: MasterEventDate restored to `date -r\"$MasterEventDate\"` (aggregate record)"
        fi

   else rm -f "$ShortIntervalPermanentDate" "$TextForNextItem"
        $DebugLog 2 "ShortInterval exceeded: no Delta, $ShortIntervalPermanentDate removed"
fi

# STEP B3: if AddIntervals=yes, calculate Interval (including RealInterval)
TripTime=0"`$expr $SecondsNow - \`date -r\"$TripSeconds\"  \"+%s\" 2>/dev/null\` + \
\`sed 's/^[^0-9]*\$/0/;s/^\$/0/;\$! d'<\"$TripSeconds\" 2>/dev/null\` 2>/dev/null`"
TripHours=`$expr \( $TripTime + $Rounding \) / 3600 2>/dev/null`
TripMinutes=`$expr \( $TripTime - ${TripHours:-0} \* 3600 + $Rounding \) / 60 2>/dev/null`

Interval=
if test -f "$MasterEventDate" -a "$AddIntervals" = yes
   then SecondsMasterEvent=`date -r"$MasterEventDate" "+%s"`
        days=`$expr \( $SecondsNow - $SecondsMasterEvent + $Rounding \) / 86400`
        hours=`$expr \( $SecondsNow - $SecondsMasterEvent - $days \* 86400 + $Rounding \) / 3600`
        minutes=`$expr \( $SecondsNow - $SecondsMasterEvent - $days \* 86400 - $hours \* 3600 + $Rounding \) / 60`
        #minutesNotRounded=`$expr \( $SecondsNow - $SecondsMasterEvent - $days \* 86400 - $hours \* 3600 \) / 60`
        #secs=`$expr $SecondsNow - $SecondsMasterEvent - $days \* 86400 - $hours \* 3600 - $minutesA \* 60`
        case "$days" in
        0) ;;
        -*|$ResetString) Interval="$ResetString";;
        *) test "$minutes" -ge 0 -a "$minutes" -lt 10 && minutes="0$minutes"
           Interval="${days}${DaySeparatorSymbol}${hours}:${minutes}";;
        esac
        case "$hours$Interval" in
        -*|$ResetString) Interval= "$ResetString";;
        0) ;;
        [0-9]|[0-9][0-9])
           test "$minutes" -ge 0 -a "$minutes" -lt 10 && minutes="0$minutes"
           Interval="$hours:$minutes";;
        esac
        case "$minutes$Interval" in
        -*|$ResetString) Interval="$ResetString";;
        0) ;;
        [0-9]|[0-9][0-9]) Interval="$minutes'";;
        esac
fi

# A non (or not yet) aggregated RESUME following a SUSPEND sets the Interval symbol to stop and updates PrevMasterEventDate and MasterEventDate
if [ "$MasterEvent" -a "$TypePreviousEvent" = "SUSPEND" -a "$1" = "RESUME" ]
   then cp -p "$LastGpsDate" "$MasterEventDate" 2>/dev/null || echo "$1" > "$MasterEventDate"
        cp -p "$MasterEventDate" "$PrevMasterEventDate"
        $DebugLog 1 "NEW TRIP; new MasterEventDate=`date -r\"$MasterEventDate\"`; new PrevMasterEventDate=`date -r\"$PrevMasterEventDate\"`"
        echo "$Interval" > "$TextForNextItem"
        test "$AddIntervals" = yes && Interval=" ${IntOS}$Interval${IntCS}"
        cp -p "$LastGpsDate" "$TripSeconds"
        test "$NewGpxWhenNewTravel" = yes && GpxEnveloper
   else RealInterval=
        if [ ${TripHours:-0} -gt 0 ]
           then test "$TripMinutes" -ge 0 -a "$TripMinutes" -lt 10 && TripMinutes="0$TripMinutes"
                RealInterval="${TripHours}:${TripMinutes}"
           else RealInterval="${TripMinutes}'"
        fi
        test "$RealInterval" = "$Interval" && RealInterval=
        IntO="${IntOR}" IntC="${IntCR}" PrevInterval=`cat "$TextForNextItem" 2>/dev/null` && Interval="$PrevInterval" IntO="${IntOS}" IntC="${IntCS}"
        test "$AddIntervals" = yes && if [ $TripTime -gt 30 -a "$RealInterval" ]
           then Interval=" ${IntO}$Interval,$RealInterval${IntC}"
           else test "$Interval" && Interval=" ${IntO}$Interval${IntC}"
        fi
fi

# All SUSPEND events will update MasterEventDate (but not PrevMasterEventDate)
if [ "$1" = "SUSPEND" ]
   then cp -p "$LastGpsDate" "$MasterEventDate" 2>/dev/null || echo "$1" > "$MasterEventDate"
        $DebugLog 1 "SUSPEND Event: New MasterEventDate=`date -r\"$MasterEventDate\"`"
        # Now MasterEventDate (e.g., PrevMasterEventDate of the next event) also includes the SUSPEND event

        echo "$TripTime" >> "$TripSeconds"
        $DebugLog 2 "TripSeconds=\n`cat \"$TripSeconds\"`"
fi

case "$1" in RESUME|SUSPEND|BOOT);;*)Interval="$LogSymbol$Interval";;esac # set Interval only for LOG type events
$DebugLog 3 && set +x

# STEP B4: create the final records
GpxFix='<fix>3d</fix>'
SdkRetCode= SdkGCPUpdate= SdkGCPLongitude= SdkGCPLatitude= SdkGCPSpeed= SdkGCPDirection= SdkGCPOther=
if test \( ! "$Longitude" -o ! "$Latitude" -o ! "$Speed" \) -a -s "/var/run/TomTomNavigationServer.SDK.$ProcessId.1.finished" -a "$DoSdkPosition"
   then { # Fetch data from the SDK response
        OIFS="$IFS"
        IFS='|'
        read SdkRetCode SdkGCPUpdate SdkGCPLongitude SdkGCPLatitude SdkGCPSpeed SdkGCPDirection SdkGCPOther
        IFS="$OIFS"
        } >/dev/null 2>&1 <"/var/run/TomTomNavigationServer.SDK.$ProcessId.1.message"
        $DebugLog 1 "SdkRetCode=$SdkRetCode SdkGCPUpdate=$SdkGCPUpdate SdkGCPLongitude=$SdkGCPLongitude SdkGCPLatitude=$SdkGCPLatitude SdkGCPSpeed=$SdkGCPSpeed SdkGCPDirection=$SdkGCPDirection SdkGCPOther=$SdkGCPOther"
        if test "$SdkRetCode" -ge 0 -a "$SdkGCPLongitude" -a "$SdkGCPLatitude" 2>/dev/null
           then Longitude="$SdkGCPLongitude" Latitude="$SdkGCPLatitude" Speed="$SdkGCPSpeed${SdkGCPSpeed:+.0}" GpxFix='<fix>2d</fix>'
        fi
fi
GeoDecode= SdkRGRetCode= SdkRGLongitude= SdkRGLatitude= SdkRGType= SdkRGStreet= SdkRGHouseNumber1= SdkRGHouseNumber2= SdkRGCity= SdkRGOther=
if test -s "/var/run/TomTomNavigationServer.SDK.$ProcessId.3.finished" -a "$DoSdkGeodecode"
   then { # Fetch data from the SDK response
        OIFS="$IFS"
        IFS='|'
        read SdkRGRetCode SdkRGLongitude SdkRGLatitude SdkRGType SdkRGStreet SdkRGHouseNumber1 SdkRGHouseNumber2 SdkRGCity SdkRGOther
        IFS="$OIFS"
        } >/dev/null 2>&1 <"/var/run/TomTomNavigationServer.SDK.$ProcessId.3.message"
        $DebugLog 1 "SdkRGRetCode=$SdkRetCode SdkRGLongitude=$SdkRGLongitude SdkRGLatitude=$SdkRGLatitude SdkRGType=$SdkRGType SdkRGStreet=$SdkRGStreet  SdkRGHouseNumber1=$SdkRGHouseNumber1 SdkRGHouseNumber2=$SdkRGHouseNumber2 SdkRGCity=$SdkRGCity SdkRGOther=$SdkRGOther"
        if test "$SdkRGRetCode" -ge 0 2>/dev/null
           then GeoDecode=
                Sep=" " SepC=""
                test "$SdkRGStreet" -a ! "$SdkRGStreet" = "$UnnamedRoadString1" -a ! "$SdkRGStreet" = "$UnnamedRoadString2" && GeoDecode=" $SdkRGStreet" SepC=','
                test "$SdkRGHouseNumber1" -a ! "$SdkRGHouseNumber1" = 0 && GeoDecode="$GeoDecode $SdkRGHouseNumber1" Sep='-' SepC=','
                test "$SdkRGHouseNumber2" -a ! "$SdkRGHouseNumber2" = 0 && GeoDecode="$GeoDecode$Sep$SdkRGHouseNumber2" SepC=','
                test "$SdkRGCity" && GeoDecode="$GeoDecode$SepC $SdkRGCity"
        fi
fi

# STEP B5: prepare data
# Generate null positioning fields if the retrieved data are invalid.
test "$Longitude" || Longitude="0" GpxFix='<fix>none</fix>'
test "$Latitude" || Latitude="0" GpxFix='<fix>none</fix>'
EleGpx=
if test "$Elevation"
   then EleGpx='<ele>'${Elevation}'</ele>'
        Elevation=" ${Elevation}${ElevationUnit}"
   else test ! "$GpxFix" = '<fix>none</fix>' && GpxFix='<fix>2d</fix>'
fi
GpxCourse=
if test "$SdkGCPDirection"
   then GpxCourse="<course>${SdkGCPDirection}.0</course>"
fi
GpxSpeed=
if test "$Speed"
   then # GpxSpeed="<speed>$Speed</speed>" # This is not correct as uses km/h instead of m/sec
        SpeedMs=`$expr \( ${Speed%.*}${Speed#*.}000 / 36 + 5 \) / 10`
        SpeedMsU="${SpeedMs%??}"
        SpeedMsD="${SpeedMs#$SpeedMsU}"
        SpeedMsU="${SpeedMsU:-0}"
        SpeedMsD="${SpeedMsD:-0}"
        GpxSpeed="<speed>$SpeedMsU.$SpeedMsD</speed>"
        if [ "$Speed" = "0.0" -o "$Speed" = "0" ]
           then Speed= # Log speed only if > 0
           else Speed=" ${Speed}${SpeedUnit}"
        fi
fi
if test "$SdkRetCode" -ge 0 -a "$SdkGCPUpdate" = 0 2>/dev/null
   then Delta="${OutdatedRecordSymbol}${Delta}"
        GpxFix='<fix>none</fix>'
fi
RecordOk="$Longitude|$Latitude|_REPLACE_$Elevation$Speed"
LatitudeU="${Latitude%?????}"
LatitudeD="${Latitude#$LatitudeU}"
LongitudeU="${Longitude%?????}"
LongitudeD="${Longitude#$LongitudeU}"

# STEP B6: save the final records to the SD card
if [ "$Longitude" -gt 0 -a "$Latitude" -gt 0 ]
   then echo "$RecordOk" >"$ITNOK"
        echo "$Longitude|$Latitude|${CurrentDate}$Delta${Elevation}${Speed}${Interval}${GeoDecode}|$Flag|" >>"$ITN"
        test "$Longitude" -gt 0 -a "$Latitude" -gt 0 >/dev/null 2>&1 && WptTrkPoi "$1"\
         "$Longitude|$Latitude|${CurrentDate}$Delta${Elevation}${Speed}${Interval}${GeoDecode}|"\
 'lat="'"${LatitudeU}.${LatitudeD}"'" lon="'"${LongitudeU}.${LongitudeD}"'">'"${EleGpx}"'<time>'"$GpxDate"'Z</time>' \
 "$GpxCourse$GpxSpeed$GpxFix" \
 '<name>'"${CurrentDate}:${SecondsNow#????????}"'</name><desc>'"$Delta${Interval}${GeoDecode}"'</desc>'
   else if test -f "$ITNOK"
     then sed "s;_REPLACE_\(.*\)$;${CurrentDateO}${Delta}\1${Interval}|$Flag|;" < "$ITNOK" >>"$ITN"
     else echo "$Longitude|$Latitude|${CurrentDate}$Delta${Elevation}${Speed}${Interval}${GeoDecode}|$Flag|" >>"$ITN"
          test "$Longitude" -gt 0 -a "$Latitude" -gt 0 >/dev/null 2>&1 && WptTrkPoi "$1"\
"$Longitude|$Latitude|${CurrentDate}$Delta${Elevation}${Speed}${Interval}${GeoDecode}|" \
 'lat="'"${LatitudeU}.${LatitudeD}"'" lon="'"${LongitudeU}.${LongitudeD}"'">'"${EleGpx}"'<time>'"$GpxDate"'Z</time>' \
 "$GpxCourse$GpxSpeed$GpxFix" \
 '<name>'"${CurrentDate}:${SecondsNow#????????}"'</name><desc>'"$Delta${Interval}${GeoDecode}"'</desc>'
  fi
fi
$DebugLog 1 "last two stored records are:\n`tail -2 \"$ITN\"`"

if [ "$DoArchive" = yes -a \( "$1" = "BOOT" -o "$1" = "RESUME" \) ]
   then if $DebugLog 2
           then test "$1" = "SUSPEND" || MakeOldItnTarball $1
           else test "$1" = "SUSPEND" || MakeOldItnTarball $1 >/dev/null 2>&1
        fi
        test $? -ne 0 && $DebugLog 1 "archiving failed"
fi
$DebugLog 1 || { rm -f "/var/run/TomTomNavigationServer.SDK.$ProcessId."* ;} >/dev/null 2>&1

if test ! "$1" = "SUSPEND" -a "${Delta}${Elevation}${Speed}${Interval}" -a "$DoSdkShowMessage"
   then echo -e "FlashMessageV01| ${Delta}${Elevation}${Speed}${Interval}${GeoDecode} |${FlashMessageDuration}000|\0\c" > "/var/run/SDK.TomTomNavigationServer.$$.2.message"
        echo finish > "/var/run/SDK.TomTomNavigationServer.$$.2.finished"
fi

$DebugLog 2 "SDK Dump:
`exec 2>&1
echo \"<<<START>>>\"
for i in /var/run/TomTomNavigationServer.*
do
echo \"<<<$i>>>\"
echo
cat \"$i\"
echo
done
echo \"<<<FINISH>>>\"`"
} # of GpsLogger

## MAIN ########################################################################
if test "$SdkDisableAutoZoom" = yes; then
echo -e "SendDirectCommand|AutoZoomOff|\0\c" > "/var/run/SDK.TomTomNavigationServer.$$.6.message"
echo finish > "/var/run/SDK.TomTomNavigationServer.$$.6.finished"
fi

Event=BOOTSTRAP # for $DebugLog
Application=Default # for $DebugLog
if test "$1" = GpsLogger
   then Event=$2 # for $DebugLog
        Application=$1 # for $DebugLog
        shift

# Mount the SD card
        if test -f "$MountLog"
           then echo "0|0|Last mount failed: `date -r\"$MountLog\" \"$LongDateFormat\"`|1|" >>"$ITN" 
                echo "Last mount failed: `date -r\"$MountLog\" \"$LongDateFormat\"`:"
                cat "$MountLog"
                rm -f "$MountLog"
        fi
        MountSd=
        # Mounting the SD card is needed for SUSPEND events, while already done for the other event types.
#DEBUG!!
#        test ! -f ${OEXEC} -a -f "$RealTtn" && if mount -n -t vfat -orw,sync,noatime,nodiratime,nosuid,nodev /dev/sdcard0 "$LoggerRootDir" >"$MountLog" 2>&1
         test ! -f ${OEXEC} -a -f "$RealTtn" && if mount -n -t vfat -orw,noatime,nodiratime,nosuid,nodev /dev/sdcard0 "$LoggerRootDir" >"$MountLog" 2>&1
            then MountSd=yes
                 rm -f "$MountLog"
            else exit 1
        fi
        for i in 1 2 3 4 5 # locks the SD (check until the SD is available)
          do
            exec 6<"$MAINDIR" && break
            sleep 1
          done
        $DebugLog 1 && exec 1>>"$LOGFILE" 2>&1
        $DebugLog 1 "started"
        if test ! -f "$expr"
          then  echo "0|0|expr missing! `date \"$LongDateFormat\"`|1|" >>"$ITN"
                $DebugLog 0 "ending because expr command is missing."
                exit 1
        fi
        if test -s "$OldTarball" -a \( "$1" = "BOOT" -o "$1" = "RESUME" \)
           then mv "$OldTarball" "$Tarball"
                echo "0|0|Previous archive failed!|1|" >>"$ITN" && echo > "$ShortIntervalSkipFlag"
                echo -e "Warning: previous archiving operation failed."
        fi
        rm -f "$OldTarball"

# Start of the actual process
        test "$Debug" -le 0 -a "$1" = "RESUME" && { rm -f "/var/run/SDK.TomTomNavigationServer."* "/var/run/TomTomNavigationServer.SDK."* ;} >/dev/null 2>&1
        export ProcessId=$$
        if [ "$DoSdkPosition" ]
           then echo -e "GetCurrentPosition|\0\c">"/var/run/SDK.TomTomNavigationServer.$ProcessId.1.message"
                echo finish>"/var/run/SDK.TomTomNavigationServer.$$.1.finished"
        fi

        test "$DoSdkGeodecode" = yes && GetGeodecode &

        DenyAggregation=
        SecondsPreviousEvent=`date -r"$LastGpsDate" "+%s" 2>/dev/null`
        TypePreviousEvent=`cat "$LastGpsDate" 2>/dev/null`
        $DebugLog 2 "SecondsPreviousEvent=$SecondsPreviousEvent\n`ls -l \"$LastGpsDate\"`"

   # start of commands updating time flags (must be in foreground to avoid being suspended)
        Odate=`date "$LongDateFormat"`
        Ndate="$Odate"
        if test "$1" = "BOOT"
           then echo "$1" > "$LastGpsDate"
                # In case of reset, the date is set to default; in this case,
                # try at least to sync the date with the modification time of this script
                test `date -u "+%s"` -lt `date -r"$OEXEC" "+%s" 2>/dev/null` 2>/dev/null && \
                   date -s `date -r"$OEXEC" "+%Y.%m.%d-%H:%M:%S"` "+%c: date changed following $OEXEC modification time"
           else GetGpsData $*
        fi
        CurrentDateO=`date "$DateFormatO"`
        CurrentDate=`date "$DateFormat"`
        GpxDate=`date "+%Y-%m-%dT%H:%M:%S"`
        SecondsNow=`date "+%s"`
   # end of commands updating time flags

        case "$1" in
        SUSPEND) GpsLogger $*;;
   # Fast suspend and fast boot are not so important (while a supend is running, TTGO can be actually considered switched off)
        BOOT) GpsLogger $*;;
        *) GpsLogger $* &
           Pid=$!
           test $? -eq 0 -a $Pid -gt 1 && renice 5 $Pid
   # Notice that the background part will not produce any date mark (so that it can be possibly suspended and resumed after some time)
           ;;
        esac
        $DebugLog 1 && if [ "$1" = "SUSPEND" -a "$3" ] # Note: unfinished processes will go on after resuming, so just notify them
                   then if ! WaitForBackgroundPids $1 1 $3
                           then echo -e "some background process still running:\n$Cmd"
                                echo "0|0|Process still running!|1|" >>"$ITN"
                                echo > "$ShortIntervalSkipFlag" # This is because now TTN lasts with a comment
                        fi
        fi
        $DebugLog 1 "ended"
# End of the actual process

        test -f "$LOGFILE" && cp "$LOGFILE" "$LogfileSD" # Log option A
        #test -f "$LOGFILE" && cp "$LOGFILE" "$MAINDIR/TtnLog-$1-`date \"$OldLogFileFormat\"`.txt" # Log option B

        sync
        exec 6<&- # Free the SD lock
        exec 1>/dev/null 2>&1
        sync
        test "$MountSd" = yes && umount "$LoggerRootDir"
        exit 0
   else if [ $# -gt 0 ]
           then eval $* # test a specific command or function
                exit
        fi
fi # of GpsLogger

## Falls here if booting

mkdir "$MAINDIR" 2>/dev/null
mkdir "$TrkPath" 2>/dev/null

mv "$LogfileSD" "$MAINDIR/ttnlog-`date \"$OldLogFileFormat\".%S`.txt" 2>/dev/null # Rotate old logs (needed for log option A)
$DebugLog 1 && exec 1>>"$LOGFILE" 2>&1

#### Here insert appropriate hooks in the suspend and resume procedures of TTGO:
File=`echo -e '#!'"$SH\n$EXEC GpsLogger SUSPEND 3 _\$\$_";cat /etc/rc.suspend`
echo "$File" > /etc/rc.suspend
################################################################################
File=`echo -e '#!'"$SH\n$EXEC GpsLogger RESUME 1 _\$\$_";cat /etc/rc.resume`
echo "$File" > /etc/rc.resume
################################################################################

RealTtn="/bin/ttn" # this is the real TTGO application (that one wrapped by this script)
test -f "$RealTtn" && test -f "$oexpr" && cp "$oexpr" "$expr"
test -f "$OEXEC" && sed '1s-^#!/bin/sh$-#!'"$SH-" "$OEXEC" > "$EXEC"
test -f "$RealTtn" && test -f "$OSH" && cp "$OSH" "$SH"
chmod a+x "$EXEC" /etc/rc.suspend /etc/rc.resume

## Here process boot events:
$EXEC GpsLogger BOOT 0 _$$_

if test "$DoSdkTracking" -a "$DoSdkPosition"
   then trkptDaemon &
        Pid=$!
        test $? -eq 0 -a $Pid -gt 1 && renice 13 $Pid
fi

#PsTop &

echo "`date`-TTN - Starting TTN"
test -f "$RealTtn" && exec "$RealTtn"

Version 3.0beta

=TTN Version 3.0beta (to be placed in the root filesystem of the SD card)

#!/bin/sh
################################################################################
# >>ttn<< (to be installed in the root directory of the TomTom GO SD card)
# Event Logger (/mnt/sdcard/ttn) - Version 3.0beta - amacri(at)tiscali.it
# http://wiki.opentom.org/index.php/Event_Logger (Note: use UNIX newline format)
# Requires: (1) /Tracer directory (/mnt/sdcard/Tracer) and (2) /Tracer/expr
# Create (1) on the SD card. As (2) is not not available in the current TTGO
# busybox set, it can be downloaded from: http://rpmfind.net/linux/RPM/
# netwinder/netwinder/RPMS/base/3.1-15/sh-utils-2.0-1.armv4l.html
################################################################################

test "$LoggerGpsData" || LoggerGpsData=/dev/gpsdata
test "$LoggerRootDir" || LoggerRootDir=/mnt/sdcard
# Uncomment to trace (e.g.,TTGO hangs while booting, e.g. just sits there
# displaying 2 hands): Remember to use the UNIX line separator format.
#exec 1>>$LoggerRootDir/BootLog.txt 2>&1;set -x;echo -e "\n\n`date` - ttn START\n\n"

############## START OF CONFIGURATION VARIALBES ################################
# Time synchronization:
TIMEZONE=GMT-2 # IMPORTANT: set this to your current time zone (std UNIX format)
               # E.g.: GMT-2, GMT, GMT+1
SyncTime=yes # Set to yes if you want to keep Linux time always in sync with GPS
             # time. Default is yes (TIMEZONE needed only if this flag is yes)
DumpDate=1 # 0: Do not add date changes in Itineray, default (1: add)

# Logging:
Debug=0 # Default setting
# -1: no error logging
# 0: no debug (only error logging)
# 1: minimal debug
# 2: standard debug

# Log timings:
MaxSilentDateInterval=300 # seconds needed for a date change to be notified
MaxItnLines=45 # max number of lines in an itinerary file
# Note: TTGO truncates Itinerary files with more than 48 lines

# Labels:
SpeedUnit="km/h"
AltitudeUnit="m"
DateFormatO="+%H:%M^" # Date for records with old position (no satellite coverage)
DateFormat="+%H:%M" # Date for records with current, valid position
LongDateFormat="+%d/%m %H:%M" # Date included in description records
Today="+%A%e %B %Y" # Date included in the new day notifications

# Itinerary file name for TTGO:
ITNPath=$LoggerRootDir/itn

ITNName=_Logger.itn

ITNOHeader=Log
OldLogFileFormat="+%y-%m-%d_%H.%M"
ITNExtension=itn
ITN="$ITNPath/$ITNName"

HourToStartItnRotation="03:30:00" # Hour:minute:second of the current day
# Set this to the less probable driving hour: if the Itinerary file is found older
# than this hour and a new record is being added, a rotation is performed first.

#Log file:
MAINDIR=$LoggerRootDir/Tracer
LOGFILE=/dev/null # Default setting
LOGFILE="$MAINDIR/TtnLog.txt"

# Temporary files:
GPSLOG="$MAINDIR/GpsLog.txt"
ITNOK=$MAINDIR/LastLog.itn

# Commands:
expr=$MAINDIR/expr
EXEC=$LoggerRootDir/ttn
############### END OF CONFIGURATION VARIALBES #################################

ConvertDate()
{
# Comment out the following line to enable the translation of date strings.
cat;return
# Okay, using locale should be a better alternative, but provided that it is
# first set up in the Linux environment of TTGO. Who is willing to perform this?

# Find below an example of Italian translation; strings can be changed as needed.
sed 's/January/gennaio/
s/February/febbraio/
s/March/marzo/
s/April/aprile/
s/May/maggio/
s/June/giugno/
s/July/luglio/
s/August/agosto/
s/September/settembre/
s/October/ottobre/
s/November/novembre/
s/December/dicembre/
s/Monday/Lunedì/
s/Tuesday/Martedì/
s/Wednesday/Mercoledì/
s/Thursday/Giovedì/
s/Friday/Venerdì/
s/Saturday/Sabato/
s/Sunday/Domenica/'
} # of ConvertDate

################################################################################
GpsLogger()
{
# $1: Event: RESUME|SUSPEND|BOOT
# $2: Flag: 0-9

test "$Debug" -ge 1 && echo "`date`-GPSLOGGER-$1: started"
test "$1" = "LOG" && LoggerGpsData=/var/run/gpsfeed

if test ! -f "$expr"
  then
        echo "0|0|expr missing! `date \"$LongDateFormat\"`|1|" >>"$ITN"
        test "$Debug" -ge 0 && echo "`date`-GPSLOGGER-$1: ending because expr command is missing."
        return
fi

Lines=10
if [ ! "$1" = "BOOT" ]
   then
       test "$Debug" -ge 2 -a -f "$GPSLOG" && echo -e "`date`-GPSLOGGER-$1: Dump of $GPSLOG before:\n`ls -l \"$GPSLOG\";cat \"$GPSLOG\"`"
       head -n $Lines $LoggerGpsData >"$GPSLOG" 2>&1
       test "$Debug" -ge 1 -a -f "$GPSLOG" && echo -e "`date`-GPSLOGGER-$1: Dump of $GPSLOG after:\n`ls -l \"$GPSLOG\";cat \"$GPSLOG\"`"
fi

Flag="$2"

#####
#Manage log rotation
DateToStartItnRotation=`date -d"$HourToStartItnRotation" "+%s"`
if test -f "$ITN"
  then DateItn=`date -r"$ITN" "+%s"`
# do not break logging if a change of day occurs before a LOG or SUSPEND event
# anyway, always break when exceeding $MaxItnLines
       if [ \( \( "$1" = "RESUME" -o "$1" = "BOOT" \) -a $DateToStartItnRotation -gt $DateItn \) -o `set -- \`wc -l "$ITN"\`;echo $1` -ge $MaxItnLines ]
          then OldItn="$ITNOHeader-`date -r"$ITN" \"$OldLogFileFormat\"`.$ITNExtension" # log name corresponds to the date of the last event
               while test -f "$ITNPath/$OldItn"
                  do test "$Counter" || Counter=1
                     OldItn="$ITNOHeader-`date -r"$ITN" \"$OldLogFileFormat\"`-$Counter.$ITNExtension"
                     Counter=`$expr $Counter + 1`
                  done
               echo "0|0|Rotated on `date \"$LongDateFormat\"`|2|" >>"$ITN"
               mv "$ITN" "$ITNPath/$OldItn"
               echo "0|0|From $OldItn|1|" >>"$ITN"
               if [ $DateToStartItnRotation -gt $DateItn ]
                 then echo "0|0|`date \"$Today\"|ConvertDate`|1|" >>"$ITN"
               fi
               test $Flag -gt 0 && Flag=`$expr $Flag - 1`
       fi
  else echo "0|0|`date \"$Today\"|ConvertDate`|1|" >>"$ITN"
       test $Flag -gt 0 && Flag=`$expr $Flag - 1`
fi

#####
# Now try extracting information from $GPSLOG, by parsing relevant strings
Latitude=
Longitude=
Altitude=
Knots=
Speed=

Command=
test -f "$GPSLOG" && Command="`cat \"$GPSLOG\"`"

## STEP A1: extract Latitude and Longitude
test "$Debug" -ge 1 && echo "`date`-GPSLOGGER-$1: managing GPGGA"
CMD=`echo "$Command"|grep '^$GPGGA,'|tail -1`

Latitude1=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,\(..\)[^,]*,.,[^,]*,.,[123],.*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - Latitude: $Latitude1"

if [ ! "$Latitude1" = "$CMD" ]
   then
LatitudeM=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,..\([^,]*\),.*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - LatitudeM: $LatitudeM"
LatitudeSign=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,..[^,]*,\(.\).*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - LatitudeSign: $LatitudeSign"
if test "$LatitudeSign" = N
   then LatitudeSign=
   else LatitudeSign=-
fi
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - LatitudeSign: $LatitudeSign"
LatitudeMa=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,..\([^,.]*\)\..*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - LatitudeMa: $LatitudeMa"
LatitudeMb=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,..[^,.]*\.\([^,]*\),.*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - LatitudeMb: $LatitudeMb"
LatitudeMc=`echo "${LatitudeMa}${LatitudeMb}0000000" | sed 's/^\(........\).*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - LatitudeMc: $LatitudeMc"
LatitudeMd=`$expr \( $LatitudeMc / 60 + 5 \) / 10`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - LatitudeMd: $LatitudeMd"
LatitudeMe=`echo 00000$LatitudeMd | sed 's/.*\(.....\)$/\1/'`

Latitude="$LatitudeSign`echo \"$Latitude1$LatitudeMe\" | sed 's/^0*\(.*\)$/\1/'`"
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - Target Latitude: $Latitude"

Longitude1=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,[^,]*,.,\(...\)[^,]*,.,[0-9]*,.*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - Longitude1: $Longitude1"

LongitudeM=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,[^,]*,.,...\([^,]*\),.,[0-9]*,.*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - LongitudeM: $LongitudeM"
LongitudeSign=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,[^,]*,.,...[^,]*,\(.\),[0-9]*,.*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - LongitudeSign: $LongitudeSign"
if test "$LongitudeSign" = E
   then LongitudeSign=
   else LongitudeSign=-
fi
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - LongitudeSign: $LongitudeSign"
LongitudeMa=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,[^,]*,.,...\([^,.]*\)\.[^,.]*,.,[0-9]*,.*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - LongitudeMa: $LongitudeMa"
LongitudeMb=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,[^,]*,.,...[^,.]*\.\([^,]*\),.,[0-9]*,.*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - LongitudeMb: $LongitudeMb"
LongitudeMc=`echo "${LongitudeMa}${LongitudeMb}0000000" | sed 's/^\(........\).*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - LongitudeMc: $LongitudeMc"
LongitudeMd=`$expr \( $LongitudeMc / 60 + 5 \) / 10`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - LongitudeMd: $LongitudeMd"
LongitudeMe=`echo 00000$LongitudeMd | sed 's/.*\(.....\)$/\1/'`

Longitude="$LongitudeSign`echo \"$Longitude1$LongitudeMe\" | sed 's/^0*\(.*\)$/\1/'`"
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - Target Longitude: $Longitude"

# STEP A2: extract Altitude and date
Altitude=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[123],[^,]*,[^,]*,\([^,]*\),M,.*/\1/'`
# HINT: Convert here if the altitude unit needs to be changed (e.g., through expr).
# Example of conversion from meters to feet:
#Altitude=`expr \`echo "$Altitude" | sed 's/\.//'\` \* 1000 / 304 | sed 's/.$/.&/'`

test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - Altitude: $Altitude"

fi # Latitude

test "$Debug" -ge 1 && echo "`date`-GPSLOGGER-$1: managing GPRMC"
CMD=`echo "$Command"|grep '^$GPRMC,'|tail -1`

Knots=`echo "$CMD"|sed 's/^$GPRMC,[^,]*,A,[^,]*,[^,]*,[^,]*,[^,]*,\([^,]*\),.*/\1/'`

if [ ! "$Knots" = "$CMD" ]
   then
Hours=`echo "$CMD"|sed 's/^$GPRMC,\(..\).*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - Hours: $Hours"
Mins=`echo "$CMD"|sed 's/^$GPRMC,..\(..\).*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - Minutes: $Mins"
Secs=`echo "$CMD"|sed 's/^$GPRMC,....\(..\).*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - Seconds: $Secs"
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - Knots: $Knots"
Day=`echo "$CMD"|sed 's/^$GPRMC,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,\(..\)....,.*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - Day: $Day"
Month=`echo "$CMD"|sed 's/^$GPRMC,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,..\(..\)..,.*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - Month: $Month"
Year=`echo "$CMD"|sed 's/^$GPRMC,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,....\(..\),.*/\1/'`
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - Year: $Year"

# STEP A3: sync Linux time with GPS time if required and if the related extracted strings are valid.
if [ "$Year" -a "$Month" -a "$Day" -a "$Hours" -a "$Mins"  -a "$SyncTime" = yes -a ! "$1" = BOOT -a ! "$1" = RESUME ]
   then Date="$Day/$Month $Hours:$Mins"
        Odate=`date "$LongDateFormat"`
        test "$Debug" -ge 1 && echo "`date`-GPSLOGGER-$1: GPS date is $Date"
        SecBefore=`date "+%s"`
        test "$LoggerDoNotChangeDate" || date -u "$Month$Day$Hours${Mins}20${Year}.$Secs"
        test "$LoggerDoNotChangeDate" || date `TZ=$TIMEZONE date "+%m%d%H%M%Y.%S"`
        SecAfter=`date "+%s"`
        if test `$expr $SecAfter - $SecBefore` -gt $MaxSilentDateInterval -o `$expr $SecBefore - $SecAfter` -gt $MaxSilentDateInterval
           then if test "$DumpDate" -eq 1
                    then echo -e "0|0|Old date $Odate|0|\n0|1|New date `date \"$LongDateFormat\"`|1|" >>"$ITN"
                fi
        fi
        test "$Debug" -ge 1 && echo "`date`-GPSLOGGER-$1: date changed."
fi

fi # Knots

# STEP A4: extract speed (km/h)
test "$Debug" -ge 1 && echo "`date`-GPSLOGGER-$1: managing GPVTG"
CMD=`echo "$Command"|grep '^$GPVTG,'|tail -1`

Speed=`echo "$CMD"|sed 's/^$GPVTG,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,\([^,]*\),K,.*/\1/'`
# HINT: Convert this in miles per hour here if needed (e.g., through expr).
# Example of conversion from km/h to miles/h:
#Speed=`expr \`echo "$Speed" | sed 's/\.//'\` \* 10 / 16 | sed 's/.$/.&/'`

test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - Speed: $Speed"
########## Note: parsing of GPS data finishes here ############

# STEP B1: manage a boot record and Flag field
if [ "$1" = "BOOT" ]
   then Flag=0
        test "$Debug" -ge 1 && echo "`date`-GPSLOGGER-$1: Boot record is: 0|0|Boot `date \"+%d/%m %H:%M\"`|3|"
        echo "0|0|Boot `date \"$LongDateFormat\"`|2|" >>"$ITN"
fi
test -f "$ITN" || Flag=4
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1 - Flag=$Flag"

# STEP B2: prepare data
Valid=0
test "$Longitude" -a "$Latitude" -a "$Altitude" -a "$Speed" && Valid=1

# Generate a null positioning record if the retrieved data are not valid.
test "$Longitude" || Longitude="0"
test "$Latitude" || Latitude="0"
test "$Altitude" && Altitude=" ${Altitude}${AltitudeUnit}"
test "$Speed" && if [ "$Speed" = "0.0" ]
   then Speed= # Log speed only if > 0
   else Speed=" ${Speed}${SpeedUnit}"
fi

Record="$Longitude|$Latitude|`date \"$DateFormat\"`$Altitude$Speed|$Flag|"
RecordOk="$Longitude|$Latitude|_REPLACE_$Altitude$Speed|"
test "$Debug" -ge 2 && echo "`date`-GPSLOGGER-$1-OM: record is: $Record"

if test $Valid -eq 1
   then echo "$RecordOk" >"$ITNOK"
        echo "$Record" >>"$ITN"
   else if test -f "$ITNOK"
     then sed "s|_REPLACE_|`date \"$DateFormatO\"`|" < "$ITNOK" | sed "s/\$/$Flag|/" >>"$ITN"
     else echo "$Record" >>"$ITN"
  fi
fi
test "$Debug" -ge 1 && echo -e "`date`-GPSLOGGER-$1-OM: last two stored records are:\n`tail -2 \"$ITN\"`"
test "$Debug" -ge 1 && echo "`date`-GPSLOGGER-$1-OM: ended"
} # of GpsLogger

################################################################################

test -d "$MAINDIR" || mkdir "$MAINDIR" # okay, but expr must be there too...
test "$Debug" -ge 1 && exec 1>>"$LOGFILE" 2>&1

if test "$1" = GpsLogger
   then shift
        GpsLogger $*
        exit
fi

################################################################################
File=`echo -e "#!/bin/sh\n$EXEC GpsLogger SUSPEND 3";cat /etc/rc.suspend`
echo "$File" > /etc/rc.suspend
################################################################################
File=`echo -e "#!/bin/sh\n$EXEC GpsLogger RESUME 1";cat /etc/rc.resume`
echo "$File" > /etc/rc.resume
################################################################################

GpsLogger BOOT 0
test -f /bin/ttn || exit

echo "`date`-TTN - Starting TTN"
/bin/ttn
#NOTE:"/bin/ttn&" or "exec /bin/ttn" will not correctly flush the script output.


Version 2

TTN Version 2 (to be placed in the root filesystem of the SD card)

 #!/bin/sh
 
 ################################################################################
 echo '#!/bin/sh
 
 echo "* Running suspend tasks"
 
 head -n 10 /dev/gpsdata > /mnt/sdcard/Tracer/GpsLog.txt 2>&1
 echo "SUSPEND: Dump of /mnt/sdcard/Tracer/GpsLog.txt"  >> /mnt/sdcard/Tracer/TtnLog.txt 2>&1
 cat /mnt/sdcard/Tracer/GpsLog.txt >> /mnt/sdcard/Tracer/TtnLog.txt 2>&1
 /mnt/sdcard/Tracer/GpsLogger 3  >> /mnt/sdcard/Tracer/TtnLog.txt 2>&1
 
 hciconfig hci0 down
 killall hciattach
 
 # EOF' > /etc/rc.suspend
 LOGFILE=/mnt/sdcard/Tracer/TtnLog.txt
 chmod +x /etc/rc.suspend  >> $LOGFILE 2>&1
 ################################################################################
 echo '#!/bin/sh
 
 echo "* Running resume tasks"
 
 head -n 10 /dev/gpsdata > /mnt/sdcard/Tracer/GpsLog.txt 2>&1
 echo "RESUME: Dump of /mnt/sdcard/Tracer/GpsLog.txt"  >> /mnt/sdcard/Tracer/TtnLog.txt 2>&1
 cat /mnt/sdcard/Tracer/GpsLog.txt >> /mnt/sdcard/Tracer/TtnLog.txt 2>&1
 /mnt/sdcard/Tracer/GpsLogger 1  >> /mnt/sdcard/Tracer/TtnLog.txt 2>&1
 
 . /etc/rc.bluetooth resume
 
 # EOF' > /etc/rc.resume
 LOGFILE=/mnt/sdcard/Tracer/TtnLog.txt
 chmod +x /etc/rc.resume  >> $LOGFILE 2>&1
 ################################################################################
 
 /mnt/sdcard/Tracer/GpsLogger B  >> /mnt/sdcard/Tracer/TtnLog.txt 2>&1
 
 date >> $LOGFILE 2>&1
 echo "Starting TTN" >> $LOGFILE 2>&1
 while true
 do
 /bin/ttn 1>>$LOGFILE  2>&1
 echo "Rebooting TTN" >> $LOGFILE 2>&1
 done

GpsLogger Version 2 (to be placed in the directory "Tracer" of the SD card; this directory must first be created)

 #!/bin/sh
 
 TIMEZONE=GMT-2
 SyncTime=yes
 
 ITN=/mnt/sdcard/itn/Logger.itn
 ITNOK=/mnt/sdcard/Tracer/LastLog.itn
 GPSLOG=/mnt/sdcard/Tracer/GpsLog.txt
 #GPSLOG=/mnt/sdcard/Tracer/p2.txt
 
 expr=/mnt/sdcard/Tracer/expr
 
 Debug=0
 Latitude=
 Longitude=
 Altitude=
 Knots=
 Kmh=
 
 Command=
 test -f "$GPSLOG" && Command="`cat \"$GPSLOG\"`"
 
 CMD=`echo "$Command"|grep '^$GPGGA,'|tail -1`
 #test "$CMD" || exit 1
 
 Latitude1=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,\(..\)[^,]*,N,[^,]*,E,[123],.*/\1/'`
 test "$Debug" -eq 1 && echo "Latitude: $Latitude1"
 
 if [ ! "$Latitude1" = "$CMD" ]
    then
 LatitudeM=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,..\([^,]*\),.*/\1/'`
 test "$Debug" -eq 1 && echo "LatitudeM: $LatitudeM"
 LatitudeMa=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,..\([^,.]*\)\..*/\1/'`
 test "$Debug" -eq 1 && echo "LatitudeMa: $LatitudeMa"
 LatitudeMb=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,..[^,.]*\.\([^,]*\),.*/\1/'`
 test "$Debug" -eq 1 && echo "LatitudeMb: $LatitudeMb"
 LatitudeMc=`echo "${LatitudeMa}${LatitudeMb}0000000" | sed 's/^\(........\).*/\1/'`
 test "$Debug" -eq 1 && echo "LatitudeMc: $LatitudeMc"
 LatitudeMd=`$expr \( $LatitudeMc / 60 + 5 \) / 10`
 test "$Debug" -eq 1 && echo "LatitudeMd: $LatitudeMd"
 LatitudeMe=`echo 00000$LatitudeMd | sed 's/.*\(.....\)$/\1/'`
 
 Latitude=`echo "$Latitude1$LatitudeMe" | sed 's/^0*\(.*\)$/\1/'`
 test "$Debug" -eq 1 && echo "Target Latitude: $Latitude"
 
 #let Latitude=\($Latitude+$LatitudeM/60\)*100000
 #echo $Latitude
 
 Longitude1=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,[^,]*,N,\(...\)[^,]*,E,1,.*/\1/'`
 test "$Debug" -eq 1 && echo "Longitude1: $Longitude1"
 
 LongitudeM=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,[^,]*,N,...\([^,]*\),E,1,.*/\1/'`
 test "$Debug" -eq 1 && echo "LongitudeM: $LongitudeM"
 LongitudeMa=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,[^,]*,N,...\([^,.]*\)\.[^,.]*,E,1,.*/\1/'`
 test "$Debug" -eq 1 && echo "LongitudeMa: $LongitudeMa"
 LongitudeMb=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,[^,]*,N,...[^,.]*\.\([^,]*\),E,1,.*/\1/'`
 test "$Debug" -eq 1 && echo "LongitudeMb: $LongitudeMb"
 LongitudeMc=`echo "${LongitudeMa}${LongitudeMb}0000000" | sed 's/^\(........\).*/\1/'`
 test "$Debug" -eq 1 && echo "LongitudeMc: $LongitudeMc"
 LongitudeMd=`$expr \( $LongitudeMc / 60 + 5 \) / 10`
 test "$Debug" -eq 1 && echo "LongitudeMd: $LongitudeMd"
 LongitudeMe=`echo 00000$LongitudeMd | sed 's/.*\(.....\)$/\1/'`
 
 Longitude=`echo "$Longitude1$LongitudeMe" | sed 's/^0*\(.*\)$/\1/'`
 test "$Debug" -eq 1 && echo "Target Longitude: $Longitude"
 
 #let Longitude=\($Longitude+$LongitudeM/60\)*100000
 #echo $Longitude
 
 Altitude=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[123],[^,]*,[^,]*,\([^,]*\),M,.*/\1/'`
 test "$Debug" -eq 1 && echo "Altitude: $Altitude"
 
 fi
 
 CMD=`echo "$Command"|grep '^$GPRMC,'|tail -1`
 #test "$CMD" || exit 1
 
 Knots=`echo "$CMD"|sed 's/^$GPRMC,[^,]*,A,[^,]*,[^,]*,[^,]*,[^,]*,\([^,]*\),.*/\1/'`
 
 if [ ! "$Knots" = "$CMD" ]
    then
 Hours=`echo "$CMD"|sed 's/^$GPRMC,\(..\).*/\1/'`
 test "$Debug" -eq 1 && echo "Hours: $Hours"
 Mins=`echo "$CMD"|sed 's/^$GPRMC,..\(..\).*/\1/'`
 test "$Debug" -eq 1 && echo "Minutes: $Mins"
 Secs=`echo "$CMD"|sed 's/^$GPRMC,....\(..\).*/\1/'`
 test "$Debug" -eq 1 && echo "Seconds: $Secs"
 test "$Debug" -eq 1 && echo "Knots: $Knots"
 Day=`echo "$CMD"|sed 's/^$GPRMC,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,\(..\)....,.*/\1/'`
 test "$Debug" -eq 1 && echo "Day: $Day"
 Month=`echo "$CMD"|sed 's/^$GPRMC,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,..\(..\)..,.*/\1/'`
 test "$Debug" -eq 1 && echo "Month: $Month"
 Year=`echo "$CMD"|sed 's/^$GPRMC,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,....\(..\),.*/\1/'`
 test "$Debug" -eq 1 && echo "Year: $Year"
 
 if [ "$Year" -a "$Month" -a "$Day" -a "$Hours" -a "$Mins"  -a "$SyncTime" = yes ]
    then Date="$Day/$Month $Hours:$Mins"
   test "$Debug" -eq 1 && echo "$Date"
   test "$Debug" -eq 1 && date
   date -u "$Month$Day$Hours${Mins}20${Year}.$Secs"
   date `TZ=$TIMEZONE date "+%m%d%H%M%Y.%S"`
   test "$Debug" -eq 1 && date
 fi
 
 fi
 
 CMD=`echo "$Command"|grep '^$GPVTG,'|tail -1`
 #test "$CMD" || exit 1
 
 Kmh=`echo "$CMD"|sed 's/^$GPVTG,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,\([^,]*\),K,.*/\1/'`
 test "$Debug" -eq 1 && echo "kmh: $Kmh"
 
 Flag="$1"
 if [ "$Flag" = B ]
    then Flag=0
         echo "0|0|Boot `date "+%d/%m %H:%M"`|3|" >>"$ITN"
 fi
 test -f "$ITN" || Flag=4
 test "$Debug" -eq 1 && echo "Flag=$Flag"
 
 Valid=0
 test "$Longitude" -a "$Latitude" -a "$Altitude" -a "$Kmh" && Valid=1
 
 test "$Longitude" || Longitude="0"
 test "$Latitude" || Latitude="0"
 test "$Altitude" && Altitude=" ${Altitude}m"
 test "$Kmh" && if [ "$Kmh" = "0.0" ]
    then Kmh=
    else Kmh=" ${Kmh}Km/h"
 fi
 Record="$Longitude|$Latitude|`date "+%d/%m %H:%M"`$Altitude$Kmh|$Flag|"
 RecordOk="$Longitude|$Latitude|_REPLACE_$Altitude$Kmh|"
 test "$Debug" -gt 0 && echo "$Record"
 
 if test $Valid -eq 1
    then echo "$RecordOk" >"$ITNOK"
         echo "$Record" >>"$ITN"
    else if test -f "$ITNOK"
      then sed "s|_REPLACE_|`date \"+%d/%m_%H:%M\"`|" < "$ITNOK" | sed "s/\$/$Flag|/" >>"$ITN"
      else echo "$Record" >>"$ITN"
   fi
 fi


Version 1

TTN (to be placed in the root filesystem of the SD card)

 #!/bin/sh
 
 ################################################################################
 echo '#!/bin/sh
 
 echo "* Running suspend tasks"
 
 head -n 10 /dev/gpsdata > /mnt/sdcard/Tracer/GpsLog.txt 2>&1 &
 Listener=$!
 sleep 1
 echo "SUSPEND: Dump of /mnt/sdcard/Tracer/GpsLog.txt"  >> /mnt/sdcard/Tracer/TtnLog.txt 2>&1
 cat /mnt/sdcard/Tracer/GpsLog.txt >> /mnt/sdcard/Tracer/TtnLog.txt 2>&1
 /mnt/sdcard/Tracer/GpsLogger 3  >> /mnt/sdcard/Tracer/TtnLog.txt 2>&1
 kill $Listener  >> /mnt/sdcard/Tracer/TtnLog.txt 2>&1
 
 hciconfig hci0 down
 killall hciattach
 
 # EOF' > /etc/rc.suspend
 LOGFILE=/mnt/sdcard/Tracer/TtnLog.txt
 chmod +x /etc/rc.suspend  >> $LOGFILE 2>&1
 ################################################################################
 echo '#!/bin/sh
 
 echo "* Running resume tasks"
 
 head -n 10 /dev/gpsdata > /mnt/sdcard/Tracer/GpsLog.txt 2>&1 &
 Listener=$!
 sleep 1
 echo "RESUME: Dump of /mnt/sdcard/Tracer/GpsLog.txt"  >> /mnt/sdcard/Tracer/TtnLog.txt 2>&1
 cat /mnt/sdcard/Tracer/GpsLog.txt >> /mnt/sdcard/Tracer/TtnLog.txt 2>&1
 /mnt/sdcard/Tracer/GpsLogger 1  >> /mnt/sdcard/Tracer/TtnLog.txt 2>&1
 kill $Listener  >> /mnt/sdcard/Tracer/TtnLog.txt 2>&1
 
 . /etc/rc.bluetooth resume
 
 # EOF' > /etc/rc.resume
 LOGFILE=/mnt/sdcard/Tracer/TtnLog.txt
 chmod +x /etc/rc.resume  >> $LOGFILE 2>&1
 ################################################################################
 
 /mnt/sdcard/Tracer/GpsLogger B  >> /mnt/sdcard/Tracer/TtnLog.txt 2>&1
 
 date >> $LOGFILE 2>&1
 echo "Starting TTN" >> $LOGFILE 2>&1
 while true
 do
 /bin/ttn 1>>$LOGFILE  2>&1
 echo "Rebooting TTN" >> $LOGFILE 2>&1
 done

GpsLogger (to be placed in the directory "Tracer" of the SD card; this directory must first be created)

 #!/bin/sh
 
 TIMEZONE=GMT-2
 SyncTime=yes
 
 ITN=/mnt/sdcard/itn/Logger.itn
 ITNOK=/mnt/sdcard/Tracer/LastLog.itn
 GPSLOG=/mnt/sdcard/Tracer/GpsLog.txt
 #GPSLOG=/mnt/sdcard/Tracer/p2.txt
 
 expr=/mnt/sdcard/Tracer/expr
 
 Debug=0
 Latitude=
 Longitude=
 Altitude=
 Knots=
 Kmh=
 
 Command=
 test -f "$GPSLOG" && Command="`cat \"$GPSLOG\"`"
 
 CMD=`echo "$Command"|grep '^$GPGGA,'|tail -1`
 #test "$CMD" || exit 1
 
 Latitude1=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,\(..\)[^,]*,N,[^,]*,E,[123],.*/\1/'`
 test "$Debug" -eq 1 && echo "Latitude: $Latitude1"
 
 if [ ! "$Latitude1" = "$CMD" ]
    then
 LatitudeM=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,..\([^,]*\),.*/\1/'`
 test "$Debug" -eq 1 && echo "LatitudeM: $LatitudeM"
 LatitudeMa=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,..\([^,.]*\)\..*/\1/'`
 test "$Debug" -eq 1 && echo "LatitudeMa: $LatitudeMa"
 LatitudeMb=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,..[^,.]*\.\([^,]*\),.*/\1/'`
 test "$Debug" -eq 1 && echo "LatitudeMb: $LatitudeMb"
 LatitudeMc=`echo "${LatitudeMa}${LatitudeMb}0000000" | sed 's/^\(........\).*/\1/'`
 test "$Debug" -eq 1 && echo "LatitudeMc: $LatitudeMc"
 LatitudeMd=`$expr \( $LatitudeMc / 60 + 5 \) / 10`
 test "$Debug" -eq 1 && echo "LatitudeMd: $LatitudeMd"
 LatitudeMe=`echo 00000$LatitudeMd | sed 's/.*\(.....\)$/\1/'`
 
 Latitude=`echo "$Latitude1$LatitudeMe" | sed 's/^0*\(.*\)$/\1/'`
 test "$Debug" -eq 1 && echo "Target Latitude: $Latitude"
 
 #let Latitude=\($Latitude+$LatitudeM/60\)*100000
 #echo $Latitude
 
 Longitude1=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,[^,]*,N,\(...\)[^,]*,E,1,.*/\1/'`
 test "$Debug" -eq 1 && echo "Longitude1: $Longitude1"
 
 LongitudeM=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,[^,]*,N,...\([^,]*\),E,1,.*/\1/'`
 test "$Debug" -eq 1 && echo "LongitudeM: $LongitudeM"
 LongitudeMa=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,[^,]*,N,...\([^,.]*\)\.[^,.]*,E,1,.*/\1/'`
 test "$Debug" -eq 1 && echo "LongitudeMa: $LongitudeMa"
 LongitudeMb=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,[^,]*,N,...[^,.]*\.\([^,]*\),E,1,.*/\1/'`
 test "$Debug" -eq 1 && echo "LongitudeMb: $LongitudeMb"
 LongitudeMc=`echo "${LongitudeMa}${LongitudeMb}0000000" | sed 's/^\(........\).*/\1/'`
 test "$Debug" -eq 1 && echo "LongitudeMc: $LongitudeMc"
 LongitudeMd=`$expr \( $LongitudeMc / 60 + 5 \) / 10`
 test "$Debug" -eq 1 && echo "LongitudeMd: $LongitudeMd"
 LongitudeMe=`echo 00000$LongitudeMd | sed 's/.*\(.....\)$/\1/'`
 
 Longitude=`echo "$Longitude1$LongitudeMe" | sed 's/^0*\(.*\)$/\1/'`
 test "$Debug" -eq 1 && echo "Target Longitude: $Longitude"
 
 #let Longitude=\($Longitude+$LongitudeM/60\)*100000
 #echo $Longitude
 
 Altitude=`echo "$CMD"|sed 's/^$GPGGA,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[123],[^,]*,[^,]*,\([^,]*\),M,.*/\1/'`
 test "$Debug" -eq 1 && echo "Altitude: $Altitude"
 
 fi
 
 CMD=`echo "$Command"|grep '^$GPRMC,'|tail -1`
 #test "$CMD" || exit 1
 
 Knots=`echo "$CMD"|sed 's/^$GPRMC,[^,]*,A,[^,]*,[^,]*,[^,]*,[^,]*,\([^,]*\),.*/\1/'`
 
 if [ ! "$Knots" = "$CMD" ]
    then
 Hours=`echo "$CMD"|sed 's/^$GPRMC,\(..\).*/\1/'`
 test "$Debug" -eq 1 && echo "Hours: $Hours"
 Mins=`echo "$CMD"|sed 's/^$GPRMC,..\(..\).*/\1/'`
 test "$Debug" -eq 1 && echo "Minutes: $Mins"
 Secs=`echo "$CMD"|sed 's/^$GPRMC,....\(..\).*/\1/'`
 test "$Debug" -eq 1 && echo "Seconds: $Secs"
 test "$Debug" -eq 1 && echo "Knots: $Knots"
 Day=`echo "$CMD"|sed 's/^$GPRMC,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,\(..\)....,.*/\1/'`
 test "$Debug" -eq 1 && echo "Day: $Day"
 Month=`echo "$CMD"|sed 's/^$GPRMC,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,..\(..\)..,.*/\1/'`
 test "$Debug" -eq 1 && echo "Month: $Month"
 Year=`echo "$CMD"|sed 's/^$GPRMC,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,....\(..\),.*/\1/'`
 test "$Debug" -eq 1 && echo "Year: $Year"
 
 if [ "$Year" -a "$Month" -a "$Day" -a "$Hours" -a "$Mins"  -a "$SyncTime" = yes ]
    then Date="$Day/$Month $Hours:$Mins"
   test "$Debug" -eq 1 && echo "$Date"
   test "$Debug" -eq 1 && date
   date -u "$Month$Day$Hours${Mins}20${Year}.$Secs"
   date `TZ=$TIMEZONE date "+%m%d%H%M%Y.%S"`
   test "$Debug" -eq 1 && date
 fi
 
 fi
 
 CMD=`echo "$Command"|grep '^$GPVTG,'|tail -1`
 #test "$CMD" || exit 1
 
 Kmh=`echo "$CMD"|sed 's/^$GPVTG,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,\([^,]*\),K,.*/\1/'`
 test "$Debug" -eq 1 && echo "kmh: $Kmh"
 
 Flag="$1"
 if [ "$Flag" = B ]
    then Flag=0
         echo "0|0|Boot `date "+%d/%m %H:%M"`|3|" >>"$ITN"
 fi
 test -f "$ITN" || Flag=4
 test "$Debug" -eq 1 && echo "Flag=$Flag"
 
 Valid=0
 test "$Longitude" -a "$Latitude" -a "$Altitude" -a "$Kmh" && Valid=1
 
 test "$Longitude" || Longitude="0"
 test "$Latitude" || Latitude="0"
 test "$Altitude" && Altitude=" ${Altitude}m"
 test "$Kmh" && if [ "$Kmh" = "0.0" ]
    then Kmh=
    else Kmh=" ${Kmh}Km/h"
 fi
 Record="$Longitude|$Latitude|`date "+%d/%m %H:%M"`$Altitude$Kmh|$Flag|"
 RecordOk="$Longitude|$Latitude|_REPLACE_$Altitude$Kmh|"
 test "$Debug" -gt 0 && echo "$Record"
 
 if test $Valid -eq 1
    then echo "$RecordOk" >"$ITNOK"
         echo "$Record" >>"$ITN"
    else if test -f "$ITNOK"
      then sed "s|_REPLACE_|`date \"+%d/%m_%H:%M\"`|" < "$ITNOK" | sed "s/\$/$Flag|/" >>"$ITN"
      else echo "$Record" >>"$ITN"
   fi
 fi


Version 0

Old package called Event POI Category Manager

This initial script used POI instead of Iinerary files; the drawback of using POI is that each POI update can only be browsed after a reboot TTGO; besides, redundant automatic boots could happen after resuming (a reboot happens each time the TTN application find some relevant file modified, like POI).

The following (trivial) script (to be named ttn and to be placed in the root filesystem of the SD card) can:

  • create Events POI category items including all suspend, resume and boot events
  • log information to TtnLog.txt (verbose) and to SuspendLog.txt (only suspend, resume and boot events)
  • allow updating the TTGO system date in case the file date.txt is available (date(1) format MMDDhhmm[[CC]YY][.ss], e.g. to set the date to Apr 12 18:52:41 2005 the file date.txt should include 041218522005.41) [notice that TTN date that can also be updated through the GPS device does not set the sytem date.]

All files are in the root filesystem of the SD card.

Strings <country> and <org> have to be customized.

#!/bin/sh

uptime >> /mnt/sdcard/TtnLog.txt 2>&1

if test -f /mnt/sdcard/date.txt
  then echo "Date before setting:" >> /mnt/sdcard/TtnLog.txt 2>&1
       date `cat /mnt/sdcard/date.txt` >> /mnt/sdcard/TtnLog.txt 2>&1
       echo "Date after setting:" >> /mnt/sdcard/TtnLog.txt 2>&1
       rm -f /mnt/sdcard/date.old
       mv /mnt/sdcard/date.txt /mnt/sdcard/date.old
fi
echo '#!/bin/sh

echo "* Running suspend tasks"
echo "Stop `date`" >> /mnt/sdcard/TtnLog.txt 2>&1
echo "Stop  `date`" >> /mnt/sdcard/SuspendLog.txt 2>&1
uptime >> /mnt/sdcard/SuspendLog.txt 2>&1
echo -e "\002\037\000\000\000\000\000\000\000\000\000\000\000Stop  `date "+%d/%m %H:%M"`\000\c" >> /mnt/sdcard/<country>-Map/Events.ov2

hciconfig hci0 dow