aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/usrp2/gps_ctrl.cpp
blob: 20d670f81488c1ab595b9ae783c7ab3dc2dad566 (plain)
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//
// Copyright 2010 Ettus Research LLC
//
// 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 3 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.  If not, see <http://www.gnu.org/licenses/>.
//

#include "gps_ctrl.hpp"
#include <uhd/utils/assert.hpp>
#include <boost/cstdint.hpp>
#include <string>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/tokenizer.hpp>

using namespace uhd;
using namespace boost::gregorian;
using namespace boost::posix_time;
using namespace boost::algorithm;

/*!
 * A usrp2 GPS control for Jackson Labs devices
 */

//TODO: multiple baud rate support (requires mboard_impl changes for poking UART registers), NMEA support, better autodetection
class usrp2_gps_ctrl_impl : public usrp2_gps_ctrl{
public:
  usrp2_gps_ctrl_impl(usrp2_iface::sptr iface){
    _iface = iface;
    //do init here
    //so the Jackson Labs Firefly (and Fury) don't acknowledge successful commands -- only invalid ones.
    //first we test to see if there's a Firefly/Fury connected by sending an invalid packet and listening for the response

    std::string reply;

    //TODO: try multiple baud rates (many GPS's are set up for 4800bps, you're fixed at 115200bps 8N1 right now)
    //you have to poke registers in order to set baud rate, there's no dude/bro interface for it
    _iface->read_uart(GPS_UART); //flush it out
    _iface->write_uart(GPS_UART, "HAAAY GUYYYYS\n");
    try {
      reply = _iface->read_uart(GPS_UART);
	//std::cerr << "Got reply from GPS: " << reply.c_str() << " with length = " << reply.length() << std::endl;
    } catch (std::runtime_error err) {
      if(err.what() != std::string("usrp2 no control response")) throw; //sorry can't cope with that
      else { //we don't actually have a GPS installed
        gps_type = GPS_TYPE_NONE;
      }
    }

    if(trim_right_copy(reply) == "Command Error") gps_type = GPS_TYPE_JACKSON_LABS;
    else gps_type = GPS_TYPE_NONE; //we'll add NMEA support later

    switch(gps_type) {
    case GPS_TYPE_JACKSON_LABS:
      std::cerr << "Found a Jackson Labs GPS" << std::endl;
      //issue some setup stuff so it quits spewing data out when not asked to
      //none of these should issue replies so we don't bother looking for it
      //we have to sleep between commands because the JL device, despite not acking, takes considerable time to process each command.
       boost::this_thread::sleep(boost::posix_time::milliseconds(200));
      _iface->write_uart(GPS_UART, "SYST:COMM:SER:ECHO OFF\n");
       boost::this_thread::sleep(boost::posix_time::milliseconds(200));
      _iface->write_uart(GPS_UART, "SYST:COMM:SER:PRO OFF\n");
       boost::this_thread::sleep(boost::posix_time::milliseconds(200));
      _iface->write_uart(GPS_UART, "GPS:GPGGA 0\n");
       boost::this_thread::sleep(boost::posix_time::milliseconds(200));
      _iface->write_uart(GPS_UART, "GPS:GGAST 0\n");
       boost::this_thread::sleep(boost::posix_time::milliseconds(200));
      _iface->write_uart(GPS_UART, "GPS:GPRMC 1\n");
       boost::this_thread::sleep(boost::posix_time::milliseconds(200));
      break;

    case GPS_TYPE_GENERIC_NMEA:
    case GPS_TYPE_NONE:
    default:

      break;
    }
  }

  ~usrp2_gps_ctrl_impl(void){

  }

  ptime get_time(void) {
    std::string reply;
    ptime now;
    boost::tokenizer<boost::escaped_list_separator<char> > tok(reply);
    std::vector<std::string> toked;
    switch(gps_type) {
    case GPS_TYPE_JACKSON_LABS: //deprecated in favor of a single NMEA parser
    case GPS_TYPE_GENERIC_NMEA:
      while(reply.length() == 0) reply = _iface->read_uart(GPS_UART); //loop until we hear something
      tok.assign(reply);
      toked.assign(tok.begin(), tok.end());

      UHD_ASSERT_THROW(toked.size() == 11); //if it's not we got something weird in there

      now = ptime( date( 
                         greg_year(boost::lexical_cast<int>(toked[8].substr(4, 2)) + 2000), //just trust me on this one
                         greg_month(boost::lexical_cast<int>(toked[8].substr(2, 2))), 
                         greg_day(boost::lexical_cast<int>(toked[8].substr(0, 2))) 
                       ),
                   hours(  boost::lexical_cast<int>(toked[1].substr(0, 2)))
                 + minutes(boost::lexical_cast<int>(toked[1].substr(2, 2)))
                 + seconds(boost::lexical_cast<int>(toked[1].substr(4, 2)))
                 );
      break;
    case GPS_TYPE_NONE:
    default:
      throw std::runtime_error("get_time(): Unsupported GPS or no GPS detected\n");
      break;
    }
    return now;
  }

  bool gps_detected(void) {
    return (gps_type != GPS_TYPE_NONE);
  }

private:
  usrp2_iface::sptr _iface;

  enum {
    GPS_TYPE_JACKSON_LABS,
    GPS_TYPE_GENERIC_NMEA,
    GPS_TYPE_NONE
  } gps_type;

  static const int GPS_UART = 2; //TODO: this should be plucked from fw_common.h or memory_map.h or somewhere in common with the firmware

};

/***********************************************************************
 * Public make function for the GPS control
 **********************************************************************/
usrp2_gps_ctrl::sptr usrp2_gps_ctrl::make(usrp2_iface::sptr iface){
    return sptr(new usrp2_gps_ctrl_impl(iface));
}