aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/cores/time_core_3000.cpp
blob: 29692375694297532544f453ab22581868ca78af (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
//
// Copyright 2013-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 "time_core_3000.hpp"
#include <uhd/utils/safe_call.hpp>
#include <uhd/utils/log.hpp>
#include <boost/thread/thread.hpp>

#define REG_TIME_HI       _base + 0
#define REG_TIME_LO       _base + 4
#define REG_TIME_CTRL     _base + 8

#define CTRL_LATCH_TIME_NOW     (1 << 0)
#define CTRL_LATCH_TIME_PPS     (1 << 1)
#define CTRL_LATCH_TIME_SYNC    (1 << 2)

using namespace uhd;

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

struct time_core_3000_impl : time_core_3000
{
    time_core_3000_impl(
        wb_iface::sptr iface, const size_t base,
        const readback_bases_type &readback_bases
    ):
        _iface(iface),
        _base(base),
        _readback_bases(readback_bases)
    {
        this->set_tick_rate(1); //init to non zero
    }

    ~time_core_3000_impl(void)
    {
        UHD_SAFE_CALL
        (
            ;//NOP
        )
    }

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

    void self_test(void)
    {
        const size_t sleep_millis = 100;
        UHD_LOGGER_INFO("CORES") << "Performing timer loopback test... ";
        const time_spec_t time0 = this->get_time_now();
        boost::this_thread::sleep(boost::posix_time::milliseconds(sleep_millis));
        const time_spec_t time1 = this->get_time_now();
        const double approx_secs = (time1 - time0).get_real_secs();
        const bool test_fail = (approx_secs > 0.15) or (approx_secs < 0.05);
        UHD_LOGGER_INFO("CORES") << "Timer loopback test " << ((test_fail)? "failed" : "passed");

        //useful warning for debugging actual rate
        const size_t ticks_elapsed = size_t(_tick_rate*approx_secs);
        const size_t approx_rate = size_t(ticks_elapsed/(sleep_millis/1e3));
        if (test_fail) UHD_LOGGER_WARNING("CORES")
            << "Expecting clock rate: " << (_tick_rate/1e6) << " MHz\n"
            << "Approximate clock rate: " << (approx_rate/1e6) << " MHz\n"
        ;
    }

    uhd::time_spec_t get_time_now(void)
    {
        const uint64_t ticks = _iface->peek64(_readback_bases.rb_now);
        return time_spec_t::from_ticks(ticks, _tick_rate);
    }

    uhd::time_spec_t get_time_last_pps(void)
    {
        const uint64_t ticks = _iface->peek64(_readback_bases.rb_pps);
        return time_spec_t::from_ticks(ticks, _tick_rate);
    }

    void set_time_now(const uhd::time_spec_t &time)
    {
        const uint64_t ticks = time.to_ticks(_tick_rate);
        _iface->poke32(REG_TIME_HI, uint32_t(ticks >> 32));
        _iface->poke32(REG_TIME_LO, uint32_t(ticks >> 0));
        _iface->poke32(REG_TIME_CTRL, CTRL_LATCH_TIME_NOW);
    }

    void set_time_sync(const uhd::time_spec_t &time)
    {
        const uint64_t ticks = time.to_ticks(_tick_rate);
        _iface->poke32(REG_TIME_HI, uint32_t(ticks >> 32));
        _iface->poke32(REG_TIME_LO, uint32_t(ticks >> 0));
        _iface->poke32(REG_TIME_CTRL, CTRL_LATCH_TIME_SYNC);
    }

    void set_time_next_pps(const uhd::time_spec_t &time)
    {
        const uint64_t ticks = time.to_ticks(_tick_rate);
        _iface->poke32(REG_TIME_HI, uint32_t(ticks >> 32));
        _iface->poke32(REG_TIME_LO, uint32_t(ticks >> 0));
        _iface->poke32(REG_TIME_CTRL, CTRL_LATCH_TIME_PPS);
    }

    wb_iface::sptr _iface;
    const size_t _base;
    const readback_bases_type _readback_bases;
    double _tick_rate;
};

time_core_3000::sptr time_core_3000::make(
    wb_iface::sptr iface, const size_t base,
    const readback_bases_type &readback_bases
)
{
    return time_core_3000::sptr(new time_core_3000_impl(iface, base, readback_bases));
}