Type=Service
Version=2.02
StartAtBoot=True
@EndOfDesignText@
'
' ***************************************************************************************************************
' Service module for GPS Stats (can be used by other modules) and GPS file recording ( Happens from within this service automatically)
' ***************************************************************************************************************
'
' This is like an automatic Accident Recording Buffer (file).
'
' Proposed Usage:
' If you are driving (or stopped), GPS data is being constantly recorded. Why????
' Say you are sitting at a Stop Light and somebody rear ends you. What is your defence?
' Say you are driving at the posted speed limit (or below) AND suddenly you are involved in an incident. What Is your defence?
' Say either of the above happened to you. How do you (currently) preserve this valuable data? SHUT THE DEVICE OFF!!!!! (it stops recording any further data)
' From Experince, relying on the user to preserve this valuable info (in this time of distress) can not be relied upon. An automatic process must be found.
' (ie longer accident buffer - 24 hours? - Decel or Acel > or < than x value?)
'
' Credits:
' STOLEN from various contributors of B4A. Without the combined knowledge and experience, I would have (almost - OK never)) never figured this out..
' Thanks all.... you are truely brilliant
' It's never perfect - HELP!!!!! where you can...
'
' Current defaults are meteric (SI) - convert where required.
'
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
Dim GPSservice1 As GPS ' delcare a GPS
Dim count As Int ' a counter for various purposes
Dim GPSStarted As Boolean ' is this service running?
Type TypeLoc (fDate As Long, fAccuracy As Float, fAccuracyValid As Boolean, fAltitude As Double, fAltitudeValid As Boolean, fBearing As Float, fBearingValid As Boolean, fLatitude As Double, fLongitude As Double, fSpeed As Float, fSpeedValid As Boolean, fTime As Long, fValidSats As Int,fDistance As Double)
' This structure captures all GPS that is published from the Location object (GPS_LocationChanged) - other than a few
Dim gLoc As TypeLoc ' DIM - create a NEW TypeLoc
Dim fSats As String ' used and all GPS sats in view
Dim fvSats As Int ' sats that are "vaild"
Dim fWriter As TextWriter ' declare a file object
Dim fGPSstr As String ' declare a string to be written to the file
Dim fGPSFileName As String ' what file shall we write to? (there are 2 - GPSrecords and GPSrecords1)
Dim GPSTick As String ' this shows on any form that the service is running (by blinking the * )
Dim latstart,latstop,lonstart,lonstop As Double ' used to determine distance travelled
Dim GPSFileSize As Long ' what is the max file size before we write to the next file?
Dim DEGREES_TO_RADIANS As Double : DEGREES_TO_RADIANS = (cPI / 180.0)
Dim EARTH_RADIUS As Double
' EARTH_RADIUS = 3959 ' miles
EARTH_RADIUS = 6371 ' km ' used as default - convert where required for NON SI reporting (ie. USA)
Dim Distance, SpdMoreThan, M_K As Double
Dim MyDir As String
Dim GPS_Rec As Boolean
' Dim Bootup As Boolean : Bootup = True
Dim fCurSpd As Float
M_K = 3.6 ' kmh
' M_K = 2.23693629 ' mph
End Sub
Sub Service_Create
' this section is "only" called when THIS service is not running (has never been started or has been killed by OS)
' repeated calls to "StartServiceAt" will NOT invoke (Service_Create) this method if service is currently running - (a good thing)
DefCM.Bootup = True
GPS_Rec = True
GPSservice1.Initialize("GPS")
gLoc.Initialize ' init structure
fvSats = 0 ' valid sats = 0 when starting
SpdMoreThan = 2.0 ' the speed at which distance shall accumulate (reduces wandering GPS from acruring distance) - set higher or lower as needed for your situation
GPSFileSize = 500000 ' byte size of file until it is saved and the rotating file begins (GPSrecord and GPSrecord1.txt)
GPSStarted = False ' GPS system has not been started at this point - we are just now starting it
Distance = 0.0 'CodeMod.Odom ' Init distance from last saved value
MyDir = File.DirDefaultExternal '&"/aMHW/"
' Note - start at boot is set ON. If your device is ON, GPS data is being recorded. PLUG YOUR DEVICE INTO A CAR CHARGER!!!
If GPSservice1.GPSEnabled = False Then
ToastMessageShow("Please enable the GPS device.", True)
StartActivity(GPSservice1.LocationSettingsIntent) 'Will open the relevant settings screen.
End If
'ToastMessageShow(" Creating GPS Service - Setting up records and files... ", True)
' Shows that service has started - caveat - if you can unlock your device early enough after booting.
' Otherwise - If you try - "Settings - Applications - Running Services" shows one process and one service for the app you included this module
End Sub
Sub Service_Start (StartingIntent As Intent)
'Return ' remove after testing
StartServiceAt( "", DateTime.Now + 60 * 1000, True) ' make sure service is always running (even when sleeping) - every 60 seconds
' device must be always be charging or battery will die soon (set last param to false to preserve battery)
If GPSStarted = False Then
' GPSservice1.Start(30000,0) ' used when stopped
DefCM.LoadGeoDB
GPSservice1.Start(0,0) ' use when driving
'Listen to GPS with no filters.
count = 0
GPSStarted = True
fCurSpd = 0.0
ToastMessageShow("Starting GPS Service - Connect Device to a Charger", True) ' always show that service has started
InitGPSFileName ' determine which file to start with (1 or 2)
' CodeMod.ReadDef
If DefCM.Bootup = True Then
'ToastMessageShow("Launching Application at Bootup", True) ' always show that service has started
StartActivity(Main)
Else
'ToastMessageShow("Start Application at Bootup Disabled", True) ' always show that service has started
End If
Else
Log(" GPS Service was already running - no need to init again ")
'If count = 100 Then
DefCM.FindNearest ' find nearest location from service mod
'DefCM.TM(" Nearest Location: "&DefCM.CurrLoc)
'End If
End If
' MIDNITE TIME STAMP
' determine if a midnight record needs to be recorded - need a time stamp when over midnite - checks every minute...
' if midnite has elapsed, what was the last status we were in
' record new stat once based on last stat - stamped at midnite and carry on
' check if last stat date is one day older - if so - write new record based on last stat date -
'
DefCM.CheckForMidnite
End Sub
Sub GPS_LocationChanged (Location1 As Location)
Dim dist As Double
Dim d As String
dist = 0.0
count = count + 1
gLoc.fDate = DateTime.Now ' populate the structure for file writing and other modules that may require it
gLoc.fAccuracy = Location1.Accuracy
gLoc.fAccuracyValid = Location1.AccuracyValid
gLoc.fAltitude = Location1.Altitude
gLoc.fBearing = Location1.Bearing
gLoc.fBearingValid = Location1.BearingValid ' note that "BearingTo" and others are not included here since they need params we do not have at this point
gLoc.fLatitude = Location1.Latitude
gLoc.fLongitude = Location1.Longitude
gLoc.fSpeed = Location1.Speed
gLoc.fSpeedValid = Location1.SpeedValid
gLoc.fTime = Location1.Time
gLoc.fValidSats = fvSats
If count = 101 Then
count = 1 ' this can be used for a progress bar to show service is running (what the hell...)
End If
'************************** Distance Recording Section Below *********************************************
' *** distance is NOT stored in the file. It's purpose is to keep a running odometer of distance travelled.
' *** use as you see fit in your application
' *** store the last value recorded and start from there when your app restarts (Distance = mylastvalue)
' ***********************************************************************************************************
latstop = gLoc.fLatitude
lonstop = gLoc.fLongitude
' Log(" GPS Service Lat - Lon: " &latstop&" "&lonstop)
' Log(" GPS Service Fix Time: " &DateTime.Date(gLoc.fTime)&" "&DateTime.Time(gLoc.fTime))
If latstart = 0 AND lonstart = 0 Then
latstart = latstop
lonstart = lonstop
End If
If gLoc.fAccuracyValid = True Then
If (gLoc.fSpeed * M_K) > SpdMoreThan Then ' when speed is valid and more than specified value (SpdMoreThan) - accumulate distance
dist = GetDistance(latstart,lonstart,latstop,lonstop)
d = dist
If (IsNumber(d) = False) Then
'ToastMessageShow(" Dist is NAN",True)
Distance = Distance + 0
Else
'Distance = Distance + dist
Distance = dist ' used when odom is setup by user - add to that
DefCM.CurrOdom = DefCM.CurrOdom + Distance
End If
Else
Distance = 0.0
End If
fCurSpd = gLoc.fSpeed * 3.6 ' speed in kph
End If
latstart = latstop ' set last known location for next distance (how far did we travel from last point until this point? (usually 1 second ago) )
lonstart = lonstop
gLoc.fDistance = Distance
fGPSstr = DateTime.Date(gLoc.fDate)&" "&DateTime.Time(gLoc.fDate)&","&gLoc.fDate&","&gLoc.fAccuracy&","&gLoc.fAccuracyValid&","&gLoc.fAltitude&","&NumberFormat2(gLoc.fBearing,1,1,1,False)&","&gLoc.fBearingValid&","&NumberFormat2(gLoc.fLatitude,1,6,1,False)&","&NumberFormat2(gLoc.fLongitude,1,6,1,False)&","&NumberFormat2(gLoc.fSpeed * 3.6,1,1,1,False)&","&gLoc.fSpeedValid&","&gLoc.fTime&","&gLoc.fValidSats&","&NumberFormat2(gLoc.fDistance,1,4,1,False)
' a comma deliminated string (cvs) that is stored in a file - parse later to reconstruct what happened during the record session
' set the max file size (GPSFileSize) to a value based on how much data you need to retain.
If GPS_Rec = True Then
If (gLoc.fSpeed * M_K) > SpdMoreThan Then ' when speed is valid and more than specified value (SpdMoreThan) - record data
RecordGPSFile ' store fGPSstr to the file
Else
If count = 2 Then ' if speed is less than x - record a sample every 100 seconds
RecordGPSFile
End If
End If
End If
If count Mod 2 = 0 Then
GPSTick = "*" ' used in any form to show service is actively polling for GPS based on a changing location (is service running?)
End If ' use a timer in other modules to retrieve this data ( GPS_LocationChanged works in other modules (sometimes) but I don't know how????)
If count Mod 5 = 0 Then
GPSTick = "" ' Make GPStick flash on any form that uses it.
End If
If count Mod 10 = 0 Then ' determine if it is time to switch files AND flush buffered data to disk (Writer does buffer data - so commit it often - or lose it)
fWriter.Flush
'CodeMod.Odom = Distance
'CodeMod.SaveDef
If File.Size(MyDir,fGPSFileName) > GPSFileSize Then
If GPSStarted = False Then ' show when service has not inited (possibly redundant since service must be running to get here)
ToastMessageShow("GPSRecords File Size: "&File.Size(MyDir,fGPSFileName), False)
End If
fWriter.Close ' instead of using a circular file buffer (hard to control) use two files to save GPS data
SetGPSFileName ' when the file in use gets to max file size, delete the other file and start using it....
End If ' the goal is to have the last x (hour) saved for reconstruction in case needed (ie. accident)
End If
If count Mod 50 = 0 Then ' more debug stuff....
If GPSStarted = False Then
ToastMessageShow(fGPSFileName&" - Current File Size: "&File.Size(File.DirRootExternal,fGPSFileName), True)
End If
End If
End Sub
Sub SetGPSFileName ' determine which file to use when recording new data - not perfect but gets us by
If fGPSFileName = "GPSRecords.txt" Then
fGPSFileName = "GPSRecords1.txt"
Else
fGPSFileName = "GPSRecords.txt"
End If
If File.Exists(MyDir,fGPSFileName) Then
File.Copy(MyDir,fGPSFileName,MyDir,fGPSFileName&".BAK")
File.Delete(MyDir,fGPSFileName)
End If
' ************** NOTE ******************
' "DirRootExternal" - "This is currently NOT my SD external card - WTF?"
' Any file explorer I use shows 2 dirs - "external_sd" and "sdcard"
' Using "DirRootExternal" stores data to internal RAM (sdcard)- NOT the external sd card (as I expected) WTF?
' Android is Truely wonderful - when you understand it....
fWriter.Initialize(File.OpenOutput(MyDir,fGPSFileName,True)) ' we closed the file handle earlier - restart (init) it...
If GPSStarted = False Then ' if not already running - this message will toast.. (more visual debug)
ToastMessageShow("Deleted Old File and Record to New GPSRecords File Name: "&fGPSFileName, True)
End If
End Sub
Sub InitGPSFileName
Dim a, b As Long
a = File.LastModified(MyDir,"GPSRecords.txt")
b = File.LastModified(MyDir,"GPSRecords1.txt")
If a > b Then ' which file was written to last? Use the "other" file when we start up (if older).
fGPSFileName = "GPSRecords1.txt"
Else
fGPSFileName = "GPSRecords.txt" ' set the filename we shall use to record data to...
End If
fWriter.Initialize(File.OpenOutput(MyDir,fGPSFileName,True))
If GPSStarted = False Then ' Don't show toasts unless this service has stopped
ToastMessageShow("GPSRecords File Name: "&fGPSFileName, True) ' show message if GPS record system has not started
End If
End Sub
Sub RecordGPSFile
fWriter.WriteLine(fGPSstr) ' record data to a file - set by function "InitGPSFileName"
End Sub
Sub GPS_GpsStatus (Satellites As List) ' get valid and number of sats in view.
Dim SatCount As Int
SatCount = 0
For i = 0 To Satellites.Size - 1
Dim Satellite As GPSSatellite
Satellite = Satellites.Get(i)
If Satellite.UsedInFix = True Then SatCount = SatCount + 1
Next
fSats = SatCount &" out of "&Satellites.Size&" in view" ' the entire string of valid sats and the total number of sats
fvSats = SatCount ' just valid sats int
End Sub
Sub GetDistance(lat1 As Double, long1 As Double, lat2 As Double, long2 As Double) As Double
Dim rlat1, rlong1, rlat2, rlong2, p1, p2, p3, ret As Double
rlat1 = DEGREES_TO_RADIANS * lat1
rlong1 = DEGREES_TO_RADIANS * long1
rlat2 = DEGREES_TO_RADIANS * lat2
rlong2 = DEGREES_TO_RADIANS * long2
p1 = Cos(rlat1) * Cos(rlong1) * Cos(rlat2) * Cos(rlong2) ' funcky code to measure distance - works very well so far
p2 = Cos(rlat1) * Sin(rlong1) * Cos(rlat2) * Sin(rlong2) ' dont ask me how it works - but it does!!!
p3 = Sin(rlat1) * Sin(rlat2)
ret = p1 + p2 + p3
If ret >= 1 Then ' greater than or equal to - otherwise NAN (not a number ) error
Return 0
Else
ret = ACos(ret)
ret = (ret * EARTH_RADIUS)
'ToastMessageShow(" PVals: "&p1&" - "&p2&" - "&p3&CRLF&" Ret1: "&ret1&" Ret2: "&ret2&" Retp: "&retp&" Res: "&ret ,True)
Return ret
End If
End Sub
Sub Service_Destroy
ToastMessageShow(" GPS Service Has Stopped Running", True)
GPSStarted = False
StartServiceAt( "", DateTime.Now + 3000000000000 * 1000, False) ' Stop service - set way into the future
fWriter.Close ' stop writing if service gets destroyed - close the file properly
End Sub