REBOL [
title: "PhotoTrackr DPL converter"
purpose: "Converts memory dumps of the PhotoTrackr GPS (DPL) logger to OziExplorer/GPX formats"
author: "pijoter"
date: 2009-07-15/14:05:52+2:00
file: %phototrackr-converter.r
License: "GNU General Public License (Version II)"
Library: [
replaced-by: %dpl700-converter.r
level: 'intermediate
platform: 'all
type: [tool]
domain: [file-handling]
tested-under: [
view 1.3.1 on [Linux]
view 2.7.6 on [Linux WinXP]
]
support: none
license: 'GPL
]
]
sr: context [
d: make hash! 60
unpack: func [record [binary!] /local blk b] [
blk: make block! 6
; MTK CHIPSET: lon lat datetime alt spd tag
foreach b [4 4 4 2 1 1] [
append blk reverse copy/part record b
record: skip record b
]
return blk
]
datetime: func [dtime [binary! integer!] /local d t] [
if binary? dtime [dtime: to-integer dtime]
if (dtime = -1) [return now]
d: to-date reduce [
((shift dtime 26) and 63) + 2000 ;; Y
((shift dtime 22) and 15) ;; M
((shift dtime 17) and 31) ;; D
]
t: to-time reduce [
((shift dtime 12) and 31) ;; H
((shift dtime 6) and 63) ;; Mi
dtime and 63 ;; S
]
to-date rejoin [d "/" t]
]
location: func [lat [binary! integer!] lon [binary! integer!]] [
if binary? lat [lat: to-integer lat]
if binary? lon [lon: to-integer lon]
if (lat < 0) [lat: (lat - (to-integer #{80000000})) * -1]
if (lon < 0) [lon: (lon - (to-integer #{80000000})) * -1]
return reduce [
(to-integer (lat / 1000000)) + (((lat / 1000000) - (to-integer (lat / 1000000))) * 100 / 60)
(to-integer (lon / 1000000)) + (((lon / 1000000) - (to-integer (lon / 1000000))) * 100 / 60)
]
]
filter: func [b [block!] tag [block! integer!]] [
tag: to-block tag
remove-each point (copy b) [not found? find tag point/tag]
]
waypoints: func [b [block!]] [self/filter b 254]
tracklogs: func [b [block!] /local t blk segments] [
blk: make block! 500
segments: make block! 10
t: self/filter b [99 255]
foreach point t [
if all [(not empty? blk) (point/tag = 99)] [
append/only segments blk
blk: copy []
]
append/only blk point
]
if not empty? blk [append/only segments blk]
return segments
]
decode: func [sr [binary!] config [object!]
/local lat lon dtm alt spd tag date stamp points i] [
i: 0
forskip sr 16 [
set [lon lat dtm alt spd tag] (self/unpack sr)
if (lon = #{FFFFFFFF}) [
print [i "/" (any [attempt [((index? sr) - 1) / 16] "??"]) "records"]
print ["from" (first self/d) "to" pick self/d ((length? self/d) - 1)]
break
]
date: self/datetime dtm
if all [
any [(none? config/start) (date >= config/start)]
any [(none? config/stop) (date <= config/stop) ]
][
i: i + 1
stamp: dt/to-stamp/date date
points: any [
select self/d stamp
make block! 10000
]
set [lat lon] (self/location lat lon)
repend/only points [
'lat lat
'lon lon
'alt (to-integer alt)
'spd (to-integer spd) * 1.852
'tag (to-integer tag)
'created date
]
if ((length? points) = 1) [repend self/d [stamp points]]
]
]
]
save: func [dump [object!] /local w t f stamp log] [
;; zapis do plikow
f: get in dump 'save
foreach [stamp log] self/d [
w: waypoints log
t: tracklogs log
if function? :f [attempt [f stamp w t]]
]
unset [d w t f]
recycle
]
]
dt: context [
to-epoch: func [date [date!] /local res] [
either res: attempt [to integer! difference date 1970-01-01/00:00:00]
[res]
[date - 1970-01-01/00:00:00 * 86400.0]
]
from-epoch: func [val [integer!] /zone tz /local date time] [
val: to-time val
date: 1970-01-01 + round/down val / 24:00:00
time: val // 24:00:00
(to-date rejoin [date "/" time]) + (any [(if value? zone [tz]) (00:00)])
]
to-human: func [dt [date!] /date /time /local pad d t s] [
pad: func [val n] [head insert/dup val: form val #"0" (n - length? val)]
dt: rejoin [
(pad dt/year 4) #"-" (pad dt/month 2) #"-" (pad dt/day 2)
#"/" to-itime any [dt/time 0:00]
]
any [
if date [copy/part dt 10]
if time [copy/part (skip dt 11) 8]
dt
]
]
to-stamp: func [dtm [date!] /date] [
dtm: any [
if date [self/to-human/date dtm]
self/to-human dtm
]
remove-each ch dtm [found? find "-/:" ch]
]
to-gpx-date: func [date [date!]] [
append replace (self/to-human date) "/" "T" "Z"
]
]
sr-gpx: context [
WPT-SUFFIX: {.gpx}
TRK-SUFFIX: {.gpx}
out: none
save: func [name [string!] w [block!] t [block!] /local created gpx] [
self/out: make block! 1000
created: any [
attempt [t/1/1/created] ;; pierwszy punkt, pierwszy segment
attempt [w/1/created] ;; pierwszy waypoint
now
]
attempt [
if not empty? w [waypoints name w]
if not empty? t [tracklogs name t]
]
if not empty? out [
insert head out rejoin [
{} LF
{} LF
{ } LF
]
repend out [{} LF]
gpx: to-file join name TRK-SUFFIX
print gpx
write/direct/binary gpx form self/out
]
]
waypoints: func [name [string!] w [block!] /local i point] [
i: 0
foreach point w [
i: i + 1
append out rejoin [
{ } LF
{ } (round/to point/alt 0.01) {} LF
{ } (dt/to-stamp point/created) {} LF
{ Flag, Blue} LF
{ speed } (round/to point/spd 0.01) { km/h} LF
{ } LF
{ } LF
]
]
]
tracklogs: func [name [string!] t [block!] /local i point created track-segment] [
created: any [(attempt [t/1/1/created]) now]
append out rejoin [
{ } LF
{ } dt/to-stamp/date created {} LF
{ } 1 {} LF
]
i: 0
foreach segment t [
i: i + 1
append out rejoin [{ } LF]
foreach point segment [
append out rejoin [
{ } LF
{ } (round/to point/alt 0.01) {} LF
{ } LF
{ } (round/to point/spd 0.01) {} LF
{ } LF
]
]
append out rejoin [ { } LF ]
]
append out rejoin [{ } LF]
]
]
sr-ozi: context [
WPT-SUFFIX: {.wpt}
TRK-SUFFIX: {.plt}
save: func [name [string!] w [block!] t [block!]] [
if error? try [
if not empty? w [waypoints name w]
if not empty? t [tracklogs name t]
][
print ["error!" name "format" WPT-SUFFIX TRK-SUFFIX]
]
]
to-ozi-alt: func [alt [number!]] [alt * 3.28083931316019]
to-ozi-date: func [date [date!]] [
date: dt/to-epoch date
(date / 86400) + 25569.0
]
waypoints: func [name [string!] w [block!] /local wpt i out point] [
out: make block! 100
i: 0
append out rejoin [
"OziExplorer Waypoint File Version 1.1" CRLF
"WGS 84" CRLF
"Reserved 2" CRLF
"Reserved 3" CRLF
]
foreach point w [
i: i + 1
append out rejoin [
i ","
dt/to-stamp point/created ","
(round/to point/lat 0.000001) ","
(round/to point/lon 0.000001) ","
(to-ozi-date point/created) ","
"0,0,3,0,65535,"
reform [(dt/to-stamp point/created) "speed" (round/to point/spd 0.01) "km/h"] ","
"0,0,0,"
to-ozi-alt (round/to point/alt 0.01) ","
"8.25,0,17"
CRLF
]
]
wpt: to-file join name WPT-SUFFIX
print wpt
write/direct/binary wpt form out
]
tracklogs: func [name [string!] t [block!] /local plt i out track-segment] [
out: make block! 1000
i: 0
foreach segment t [
foreach point segment [
i: i + 1
track-segment: pick [1 0] (point = first segment)
append out rejoin [
(round/to point/lat 0.000001) ","
(round/to point/lon 0.000001) ","
track-segment ","
to-ozi-alt (round/to point/alt 0.01) ","
to-ozi-date (point/created) ","
dt/to-human/date (point/created) ","
dt/to-human/time (point/created) CRLF
;; (round/to point/spd 0.01) CRLF
]
]
]
insert (head out) rejoin [
"OziExplorer Track Point File Version 2.1" CRLF
"WGS 84" CRLF
"Altitude is in Feet" CRLF
"Reserved 3" CRLF
"0,2,255," name ",0,0,2,8421376" CRLF
i CRLF
]
plt: to-file join name TRK-SUFFIX
print plt
write/direct/binary plt form out
]
]
use [data config] [
data: read/binary to-file first any [request-file halt]
config: make object! [
start: none ;; date from
stop: none ;; date to
]
sr/decode data config
sr/save sr-gpx ;; -> gpx 1.0
;; sr/save sr-ozi ;; -> oziexplorer
]
halt