aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/cores/time64_core_200.cpp
blob: b0138400d85a911fbd3f670f44ad59a1f90de78d (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
//
// Copyright 2011,2014 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 "time64_core_200.hpp"
#include <uhd/exception.hpp>
#include <uhd/utils/assert_has.hpp>
#include <boost/math/special_functions/round.hpp>

#define REG_TIME64_TICKS_HI    _base + 0
#define REG_TIME64_TICKS_LO    _base + 4
#define REG_TIME64_FLAGS       _base + 8
#define REG_TIME64_IMM         _base + 12
#define REG_TIME64_MIMO_SYNC   _base + 20 //lower byte is delay cycles

//pps flags (see above)
#define FLAG_TIME64_PPS_NEGEDGE (0 << 0)
#define FLAG_TIME64_PPS_POSEDGE (1 << 0)
#define FLAG_TIME64_PPS_SMA     (0 << 1)
#define FLAG_TIME64_PPS_MIMO    (1 << 1) //apparently not used

#define FLAG_TIME64_LATCH_NOW 1
#define FLAG_TIME64_LATCH_NEXT_PPS 0

#define FLAG_TIME64_MIMO_SYNC (1 << 8)

using namespace uhd;

time64_core_200::~time64_core_200(void){
    /* NOP */
}

class time64_core_200_impl : public time64_core_200{
public:
    time64_core_200_impl(
        wb_iface::sptr iface, const size_t base,
        const readback_bases_type &readback_bases,
        const size_t mimo_delay_cycles
    ):
        _iface(iface), _base(base),
        _readback_bases(readback_bases),
        _tick_rate(0.0),
        _mimo_delay_cycles(mimo_delay_cycles)
    {
        _sources.push_back("none");
        _sources.push_back("external");
        _sources.push_back("_external_");
        if (_mimo_delay_cycles != 0) _sources.push_back("mimo");
    }

    void enable_gpsdo(void){
        _sources.push_back("gpsdo");
    }

    void set_tick_rate(const double rate){
        _tick_rate = rate;
    }

    uhd::time_spec_t get_time_now(void){
        for (size_t i = 0; i < 3; i++){ //special algorithm because we cant read 64 bits synchronously
            const uint32_t ticks_hi = _iface->peek32(_readback_bases.rb_hi_now);
            const uint32_t ticks_lo = _iface->peek32(_readback_bases.rb_lo_now);
            if (ticks_hi != _iface->peek32(_readback_bases.rb_hi_now)) continue;
            const uint64_t ticks = (uint64_t(ticks_hi) << 32) | ticks_lo;
            return time_spec_t::from_ticks(ticks, _tick_rate);
        }
        throw uhd::runtime_error("time64_core_200: get time now timeout");
    }

    uhd::time_spec_t get_time_last_pps(void){
        for (size_t i = 0; i < 3; i++){ //special algorithm because we cant read 64 bits synchronously
            const uint32_t ticks_hi = _iface->peek32(_readback_bases.rb_hi_pps);
            const uint32_t ticks_lo = _iface->peek32(_readback_bases.rb_lo_pps);
            if (ticks_hi != _iface->peek32(_readback_bases.rb_hi_pps)) continue;
            const uint64_t ticks = (uint64_t(ticks_hi) << 32) | ticks_lo;
            return time_spec_t::from_ticks(ticks, _tick_rate);
        }
        throw uhd::runtime_error("time64_core_200: get time last pps timeout");
    }

    void set_time_now(const uhd::time_spec_t &time){
        const uint64_t ticks = time.to_ticks(_tick_rate);
        _iface->poke32(REG_TIME64_TICKS_LO, uint32_t(ticks >> 0));
        _iface->poke32(REG_TIME64_IMM, FLAG_TIME64_LATCH_NOW);
        _iface->poke32(REG_TIME64_TICKS_HI, uint32_t(ticks >> 32)); //latches all 3
    }

    void set_time_next_pps(const uhd::time_spec_t &time){
        const uint64_t ticks = time.to_ticks(_tick_rate);
        _iface->poke32(REG_TIME64_TICKS_LO, uint32_t(ticks >> 0));
        _iface->poke32(REG_TIME64_IMM, FLAG_TIME64_LATCH_NEXT_PPS);
        _iface->poke32(REG_TIME64_TICKS_HI, uint32_t(ticks >> 32)); //latches all 3
    }

    void set_time_source(const std::string &source){
        assert_has(_sources, source, "time source");

        //setup pps flags
        if (source == "external" or source == "gpsdo"){
            _iface->poke32(REG_TIME64_FLAGS, FLAG_TIME64_PPS_SMA | FLAG_TIME64_PPS_POSEDGE);
        }
        else if (source == "_external_"){
            _iface->poke32(REG_TIME64_FLAGS, FLAG_TIME64_PPS_SMA | FLAG_TIME64_PPS_NEGEDGE);
        }

        //setup mimo flags
        if (source == "mimo"){
            _iface->poke32(REG_TIME64_MIMO_SYNC, FLAG_TIME64_MIMO_SYNC | (_mimo_delay_cycles & 0xff));
        }
        else{
            _iface->poke32(REG_TIME64_MIMO_SYNC, 0);
        }
    }

    std::vector<std::string> get_time_sources(void){
        return _sources;
    }

private:
    wb_iface::sptr _iface;
    const size_t _base;
    const readback_bases_type _readback_bases;
    double _tick_rate;
    const size_t _mimo_delay_cycles;
    std::vector<std::string> _sources;
};

time64_core_200::sptr time64_core_200::make(wb_iface::sptr iface, const size_t base, const readback_bases_type &readback_bases, const size_t mimo_delay_cycles){
    return sptr(new time64_core_200_impl(iface, base, readback_bases, mimo_delay_cycles));
}