#
#  gpsman --- GPS Manager: a manager for GPS receiver data
#
#  Copyright (c) 2001 Miguel Filgueiras (mig@ncc.up.pt) / Universidade do Porto
#
#    This program is free software; you can redistribute it and/or modify
#      it under the terms of the GNU General Public License as published by
#      the Free Software Foundation; either version 2 of the License, or
#      (at your option) any later version.
#
#      This program is distributed in the hope that it will be useful,
#      but WITHOUT ANY WARRANTY; without even the implied warranty of
#      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#      GNU General Public License for more details.
#
#      You should have received a copy of the GNU General Public License
#      along with this program.
#
#  File: garmin_protocols.tcl
#  Last change:  26 October 2001
#

# description of Garmin protocols based on Garmin GPS Interface
#  Specification Version 1 Rev. 2
# updated for Garmin GPS Interface Specification Version 1 Rev. 3

   # ASCII codes (decimal)
set DLE 16
set ETX 3
set ACK 6
set NAK 21

   # DLE char 
set DLECHR [binary format "c" $DLE]

   # protocol tags
array set PROTTAG {
    P Physical  L Link  A Application  D Data
}

   # application protocol categories
array set PROTCAT {
    A010  DevCmd
    A011  DevCmd
    A100  WP
    A200  RT
    A201  RT
    A300  TR
    A301  TR
    A400  Prx
    A500  AL
    A600  DtTm
    A700  Posn
    A800  PVT
    A900  undef
}

   # protocol requirements
array set PROTREQ {
    N/A   ""
    P000  ""
    L000  ""
    L001  ""
    L002  ""
    A010  ""
    A011  ""
    A100  WPData
    A200  {RTHeader RTWPData}
    A201  {RTHeader RTWPData RTLinkData}
    A300  TRData
    A301  {TRHeader TRData}
    A400  PrxWPData
    A500  ALData
    A600  DtTmData
    A700  PosnData
    A800  PVTData
}

   # Basic Link Protocol
set PID(ACK) 6  ; set RPID(6) ACK
set PID(NAK) 21 ; set RPID(21) NAK
set PID(PArray) 253 ; set RPID(253) PArray
set PID(PrdReq) 254 ; set RPID(254) PrdReq
set PID(PrdData) 255 ; set RPID(255) PrdData

   # names of product specific protocols
set PSPROTOCOLS {Link DevCmd WP RT TR Prx AL DtTm Posn PVT}

   # definitions of Link product specific protocols
set PSPDEF(L001) {{CmdData 10} {XfrCmpl 12} {DtTmData 14} {PosnData 17}
                  {PrxWPData 19} {Records 27} {RTHeader 29} {RTWPData 30}
                  {ALData 31} {TRData 34} {WPData 35} {PVTData 51}
	          {RTLinkData 98} {TRHeader 99}}
set PSPDEF(L002) {{ALData 4} {CmdData 11} {XfrCmpl 12} {DtTmData 20}
                  {PosnData 24} {Records 35} {RTHeader 37} {RTWPData 39}
                  {WPData 43}}

    # definition of product specific device commands
set PSCMDDEF(A010) {{Abort 0} {XfrAL 1} {XfrPosnData 2} {XfrPrx 3} {XfrRT 4}
                  {XfrDtTmData 5} {XfrTR 6} {XfrWP 7} {TurnOff 8} {StartPVT 49}
                  {StopPVT 50}}
set PSCMDDEF(A011) {{Abort 0} {XfrAL 1} {XfrRT 8} {XfrDtTmData 20} {XfrWP 21}
                  {TurnOff 26}}

    # size in bytes of data types used in unions
    # unions are only used if there is a single data item and sizes of
    #  types in the union must be all different
array set PDTSIZE {
    byte 1
    int  2
}

    # protocol data types
array set PDTYPE {
    ACK  union=byte,int
    NAK  union=byte,int
    PArray  starray=char,word
    PrdReq  ignored
    PrdData  {int int string ignored}
    Records  int
    D100  {charray=6 semicircle unused=4 charray=40}
    D101  {charray=6 semicircle unused=4 charray=40 float byte}
    D102  {charray=6 semicircle unused=4 charray=40 float int}
    D103  {charray=6 semicircle unused=4 charray=40 byte byte}
    D104  {charray=6 semicircle unused=4 charray=40 float int byte}
    D105  {semicircle int string}
    D106  {byte bytes=13 semicircle int string string}
    D107  {charray=6 semicircle unused=4 charray=40 byte byte float byte}
    D108  {byte byte byte byte int bytes=18 semicircle float float float
           charray=2 charray=2 string string string string string string}
    D150  {charray=6 charray=2 byte semicircle int charray=24 charray=2
	   charray=30 charray=40}
    D151  {charray=6 semicircle unused=4 charray=40 float charray=30
           charray=24 charray=2 int charray=2 unused=1 byte}
    D152  {charray=6 semicircle unused=4 charray=40 float charray=30
           charray=24 charray=2 int charray=2 unused=1 byte}
    D154  {charray=6 semicircle unused=4 charray=40 float charray=30
           charray=24 charray=2 int charray=2 unused=1 byte int}
    D155  {charray=6 semicircle unused=4 charray=40 float charray=30
           charray=24 charray=2 int charray=2 unused=1 byte int byte}
    D200  byte
    D201  {byte charray=20}
    D202  string
    D210  {word bytes=18 string}
    D300  {semicircle longword boolean}
    D301  {semicircle longword float float boolean}
    D310  {boolean byte string}
    D400  {charray=6 semicircle unused=4 charray=40 float}
    D403  {charray=6 semicircle unused=4 charray=40 byte byte float}
    D500  {int float float float float float float float float float float}
    D501  {int float float float float float float float float float float
           byte}
    D600  {byte byte word int byte byte}
    D700  radian
    D800  {float float float float int double radian float float float float
           int long}
}

    # product identifiers; new entries should also be added to recmodels.tcl
    #  numbers followed by a letter are defined here to support older
    #  software versions; not following Garmin specs in this
array set PRODID {
    "GPS 75" {13 23 42}
    "GPS 55" 14
    "GPS 55 AVD" 15
    "GPS 65" 18
    "GPS 95 AVD" 22
    "GPS 95" {24 35}
    "GPSMAP 205" {29 44}
    "GPSMAP 210" 29
    "GPSMAP 220" 29
    "GPS 40" {31 41}
    "GPS 45" {31 41}
    "GPS 95 XL" {36 22}
    "GPS 89" 39
    "GPS 38" 41
    "GPS 45 XL" 41
    "GPS 90" 45
    "GPS 120" 47
    "GPSMAP 195" 48
    "GPSMAP 130" 49
    "GPSMAP 135 Sounder" 49
    "GPSMAP 175" 49
    "GPSMAP 230" 49
    "GPSMAP 235 Sounder" 49
    "GPSCOM 170" 50
    "GPSCOM 190" 53
    "GPS 120 Chinese" 55
    "GPS 38 Chinese" 56
    "GPS 40 Chinese" 56
    "GPS 45 Chinese" 56
    "GPS II" 59
    "GPS 125 Sounder" 61
    "GPS 38 Japanese" 62
    "GPS 40 Japanese" 62
    "GPS III Pilot" 71
    "GPS III" 72
    "GPS II Plus" {73 97}
    "GPS 120 XL" 74
    "GPSMAP 130 Chinese" 76
    "GPSMAP 230 Chinese" 76
    "GPS 12" {77 87 96}
    "GPS 12 XL" 77
    "GPS 12 XL - software < 3.01" 77a
    "GPSMAP 180" 89
    "GPS 126" {95 100}
    "GPS 128" {95 100}
    "GPS 48" 96
    "GPS 12 XL Japanese" 105
    "GPS 12 XL Chinese" 106
    eMap   111
    "GPS 12CX" 116
    "GPS III Plus" 119
    "GPSMAP 295" 128
    eTrex  130
    "eTrex Summit"  141
    "eTrex Venture/Mariner"  154
    "eTrex Euro"  156
    "eTrek Vista" 169
    "eTrek Legend" 179
}

    # product names and how to obain its product specific protocols
    #  valid values for $PRTCLDEF($product_id) are
    #   array   set PSPID($product_id,$name_prod_spec_prot) to protocol
    #            to use, for each $name_prod_spec_prot
    #   see=$ID use the same protocols as product $ID
    #   diff    set PSDIFF($product_id) to list whose head is a product id
    #            and whose tail contains pairs of $name_prod_spec_prot and
    #            protocol to use; these pairs describe the differences to
    #            the other product and must not contain Link or DevCmd

array set PNAME {
    13  "GPS 75"
    14  "GPS 55"
    15  "GPS 55 AVD"
    18  "GPS 65"
    22  "GPS 95 AVD"
    23  "GPS 75"
    24  "GPS 95"
    29  "GPSMAP 205/210/220"
    31  "GPS 40/45"
    35  "GPS 95"
    36  "GPS 95 XL"
    39  "GPS 89"
    41  "GPS 38/40/45/45 XL"
    42  "GPS 75"
    44  "GPSMAP 205"
    45  "GPS 90"
    47  "GPS 120"
    48  "GPSMAP 195"
    49  "GPSMAP 130/135 Sounder/175/230/235 Sounder"
    50  "GPSCOM 170"
    53  "GPSCOM 190"
    55  "GPS 120 Chinese"
    56  "GPS 38/40/45 Chinese"
    59  "GPS II"
    61  "GPS 125 Sounder"
    62  "GPS 38 Japanese/40 Japanese"
    71  "GPS III Pilot"
    72  "GPS III"
    73  "GPS II Plus"
    74  "GPS 120 XL"
    76  "GPSMAP 130 Chinese/230 Chinese"
    77a "GPS 12 XL - software < 3.01"
    77  "GPS 12/12 XL"
    87  "GPS 12"
    89  "GPSMAP 180"
    95  "GPS 126/128"
    96  "GPS 12/48"
    97  "GPS II Plus"
    100  "GPS 126 Chinese/128 Chinese"
    105  "GPS 12 XL Japanese"
    106  "GPS 12 XL Chinese"
    119  "GPS III Plus"
    111  eMap
    116  "GPS 12CX"
    128  "GPSMAP 295"
    130  eTrex
    141  "eTrex Summit"
    154  "eTrex Venture/Mariner"
    156  "eTrex Euro"
    169  "eTrex Vista"
    179  "eTrex Legend"
}

# the descriptions below are valid for all versions except:
#  29 version >= 4.0
#  36 version >= 3.0; for older versions see=22
#  77 version >= 3.61; may work for some older versions
#  77a defined for 77 version < 3.01

array set PRTCLDEF {
    13  diff
    14  diff
    15  diff
    18  see=13
    22  diff
    23  see=13
    24  see=13
    29  diff
    31  see=59
    35  see=13
    36  see=45
    39  diff
    41  see=59
    42  see=13
    44  diff
    45  diff
    47  see=59
    48  diff
    49  diff
    50  diff
    53  see=50
    55  see=59
    56  see=59
    59  array
    61  see=59
    62  see=59
    71  diff
    72  diff
    73  diff
    74  see=59
    76  see=49
    77  diff
    77a diff
    87  see=77
    89  see=29
    95  see=77
    96  see=77
    97  see=73
    100  see=77
    105  see=77
    106  see=77
    111  array
    116  array
    119  array
    128  see=111
    130  diff
    141  see=130
    154  see=130
    156  see=130
    169  see=130
    179  see=130
}

### there is no information on which receivers use the PVT protocol
# and therefore it is assumed all can use it

array set PSPID {
    59,Link  L001
    59,DevCmd  A010
    59,WP  A100
    59,WPData  D100
    59,RT  A200
    59,RTHeader  D201
    59,RTWPData  D100
    59,TR  A300
    59,TRData  D300
    59,Prx  N/A
    59,AL  A500
    59,ALData  D500
    59,DtTm  A600
    59,DtTmData  D600
    59,Posn  A700
    59,PosnData  D700
    59,PVT   A800
    59,PVTData   D800

    111,Link  L001
    111,DevCmd  A010
    111,WP  A100
    111,WPData  D108
    111,RT  A201
    111,RTHeader  D201
    111,RTWPData  D108
    111,RTLinkData  D210
    111,TR  A301
    111,TRHeader  D310
    111,TRData  D301
    111,Prx  A400
    111,PrxWPData D108
    111,AL  A500
    111,ALData  D500
    111,DtTm  A600
    111,DtTmData  D600
    111,Posn  A700
    111,PosnData  D700
    111,PVT  A800
    111,PVTData D800

    116,Link L001
    116,DevCmd  A010
    116,WP  A100
    116,WPData  D107
    116,RT  A200
    116,RTHeader  D201
    116,RTWPData  D107
    116,TR  A300
    116,TRData  D300
    116,Prx  A400
    116,PrxWPData D107
    116,AL  A500
    116,ALData  D501
    116,DtTm  A600
    116,DtTmData  D600
    116,Posn  A700
    116,PosnData  D700
    116,PVT  A800
    116,PVTData D800

    119,Link  L001
    119,DevCmd  A010
    119,WP  A100
    119,WPData  D104
    119,RT  A200
    119,RTHeader  D201
    119,RTWPData  D104
    119,TR  A300
    119,TRData  D300
    119,Prx  N/A
    119,AL  A500
    119,ALData  D501
    119,DtTm  A600
    119,DtTmData  D600
    119,Posn  A700
    119,PosnData  D700
    119,PVT  A800
    119,PVTData D800
}

          # must not differ on the Link and DevCmd protocols
array set PSDIFF {
    13  {59 {Prx A400} {PrxData D400}}
    14  {13 {RTHeader D200}}
    15  {14 {WPData D151} {RTWPData D151} {PrxData D151}}
    22  {45 {Prx A400} {PrxData D152}}
    29  {59 {WPData D102} {RTWPData D102} {Prx A400} {PrxData D102}}
    39  {59 {WPData D151} {RTWPData D151}}
    44  {59 {WPData D101} {RTWPData D101} {Prx A400} {PrxData D101}}
    45  {59 {WPData D152} {RTWPData D152}}
    48  {59 {WPData D154} {RTWPData D154} {ALData D501}}
    49  {29 {ALData D501}}
    50  {45 {ALData D501}}
    71  {59 {WPData D155} {RTWPData D155} {ALData D501}}
    72  {59 {WPData D104} {RTWPData D104} {ALData D501}}
    73  {59 {WPData D103} {RTWPData D103} {ALData D501}}
    77  {73 {Prx A400} {PrxData D403}}
    77a {59 {ALData D501}}
    130 {111 {RTHeader D202}}
}

## descriptions, positions in Garmin structures of GPSMan data

array set DATAFOR {
    D100,ns {Name Posn Commt}
    D100,ps {0 1 3}

    D101,ns {Name Posn Commt Symbol}
    D101,ps {0 1 3 5}

    D102,ns {Name Posn Commt Symbol}
    D102,ps {0 1 3 5}

    D103,ns {Name Posn Commt Symbol DispOpt}
    D103,ps {0 1 3 4 5}

    D104,ns {Name Posn Commt Symbol DispOpt}
    D104,ps {0 1 3 5 6}

    D105,ns {Posn Symbol Name}
    D105,ps {0 1 2}

    D106,ns {Posn Symbol Name}
    D106,ps {2 3 4}

    D107,ns {Name Posn Commt Symbol DispOpt}
    D107,ps {0 1 3 4 5}

    D108,ns {DispOpt Symbol Posn Alt Name Commt}
    D108,ps {2 4 6 7 12 13}

    D150,ns {Name Posn Alt Commt}
    D150,ps {0 3 4 8}

    D151,ns {Name Posn Commt Alt}
    D151,ps {0 1 3 8}

    D152,ns {Name Posn Commt Alt}
    D152,ps {0 1 3 8}

    D154,ns {Name Posn Commt Alt Symbol}
    D154,ps {0 1 3 8 12}

    D155,ns {Name Posn Commt Alt Symbol DispOpt}
    D155,ps {0 1 3 8 12 13}
}

## descriptions, types, default values, positions in Garmin structures, and
#   constraints of hidden attributes

 # positions must be in increasing order!
 # constraints assume that all attributes have been assigned to variables
 #  with the same name

array set HIDDENFOR {
    D106,ns {class subclass lnk_ident}
    D106,ts {byte bytes=13 string}
    D106,vs {0 0 ""}
    D106,ps {0 1 5}
    D106,cs { { if { $class==0 } { lappend undef subclass } } }

    D107,ns {colour}
    D107,ts {byte}
    D107,vs {0}
    D107,ps {7}
    D107,cs {}

    D108,ns {class colour attrs subclass depth state country facility
    city addr int_road}
    D108,ts {byte byte byte bytes=18 float charray=2 charray=2
    string string string string}
    D108,vs {0 255 96
    "0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255"
    1.0e25 "" "" "" "" "" ""}
    D108,ps {0 1 3 5 8 10 11 14 15 16 17}
    D108,cs {
	{ if { $class==0 || $class>0x46 } { lappend undef city facility } }
	{ if { $class<0x80 } { lappend undef subclass } }
	{ if { $class!=0x83 } { lappend undef addr } }
	{ if { $class!=0x82 } { lappend undef int_road } }
    }

    D150,ns {country class city state facility}
    D150,ts {charray=2 byte charray=24 charray=2 charray=30}
    D150,vs {"" 4 "" "" ""}
    D150,ps {1 2 5 6 7}
    D150,cs {
	{ if { $class==4 } { lappend undef city state country facility } }
    }

    D151,ns {facility city state country class}
    D151,ts {charray=30 charray=24 charray=2 charray=2 byte}
    D151,vs {"" "" "" "" 2}
    D151,ps {5 6 7 9 11}
    D151,cs {
	{ if { $class==2 } { lappend undef city state country facility } }
    }

    D152,ns {facility city state country class}
    D152,ts {charray=30 charray=24 charray=2 charray=2 byte}
    D152,vs {"" "" "" "" 4}
    D152,ps {5 6 7 9 11}
    D152,cs {
	{ if { $class==4 } { lappend undef city state country facility } }
    }

    D154,ns {facility city state country class}
    D154,ts {charray=30 charray=24 charray=2 charray=2 byte}
    D154,vs {"" "" "" "" 4}
    D154,ps {5 6 7 9 11}
    D154,cs {
	{ if { $class==4 } { lappend undef city state country facility } }
    }

    D155,ns {facility city state country class}
    D155,ts {charray=30 charray=24 charray=2 charray=2 byte}
    D155,vs {"" "" "" "" 4}
    D155,ps {5 6 7 9 11}
    D155,cs {
	{ if { $class==4 } { lappend undef city state country facility } }
    }

    D210,ns {class subclass}
    D210,ts {word bytes=18}
    D210,vs {0 "0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255"}
    D210,ps {0 1}
    D210,cs {
	{ if { $class==3 || $class==0xff } { lappend undef subclass } }
    }

    D310,ns {colour display}
    D310,ts {byte boolean}
    D310,vs {255 0}
    D310,ps {0 1}
    D310,cs {}
}

### PVT status for D800

array set GarminPVTStatus {
    0     error
    1     _
    2     2D
    3     3D
    4     2D-diff
    5     3D-diff
}

### Simple Text Output Protocol

set SimpleTextBegs "1 3 5 7 9 11 13 14 16 21 22 25 30 31 34 35 40 \
	41 45 46 50 51"
set SimpleTextEnds "2 4 6 8 10 12 13 15 20 21 24 29 30 33 34 39 40 \
	44 45 49 50 54"

array set SimpleTextPStatus {
    _  _
    d  2D-diff
    D  3D-diff
    g  2D
    G  3D
    S  simul
}

