Statistics
| Branch: | Tag: | Revision:

root / host / lib / usrp / usrp_e100 / usrp_e100_iface.cpp @ 1b63cd25

History | View | Annotate | Download (8.59 KB)

1
//
2
// Copyright 2010-2011 Ettus Research LLC
3
//
4
// This program is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
//
17

    
18
#include "usrp_e100_iface.hpp"
19
#include "usrp_e100_regs.hpp"
20
#include <uhd/exception.hpp>
21
#include <sys/ioctl.h> //ioctl
22
#include <fcntl.h> //open, close
23
#include <linux/usrp_e.h> //ioctl structures and constants
24
#include <boost/format.hpp>
25
#include <boost/thread.hpp> //mutex
26
#include <linux/i2c-dev.h>
27
#include <linux/i2c.h>
28
#include <stdexcept>
29

    
30
using namespace uhd;
31
using namespace uhd::usrp;
32

    
33
/***********************************************************************
34
 * I2C device node implementation wrapper
35
 **********************************************************************/
36
class i2c_dev_iface : public i2c_iface{
37
public:
38
    i2c_dev_iface(const std::string &node){
39
        if ((_node_fd = ::open(node.c_str(), O_RDWR)) < 0){
40
            throw uhd::io_error("Failed to open " + node);
41
        }
42
    }
43

    
44
    ~i2c_dev_iface(void){
45
        ::close(_node_fd);
46
    }
47

    
48
    void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){
49
        byte_vector_t rw_bytes(bytes);
50

    
51
        //setup the message
52
        i2c_msg msg;
53
        msg.addr = addr;
54
        msg.flags = 0;
55
        msg.len = bytes.size();
56
        msg.buf = &rw_bytes.front();
57

    
58
        //setup the data
59
        i2c_rdwr_ioctl_data data;
60
        data.msgs = &msg;
61
        data.nmsgs = 1;
62

    
63
        //call the ioctl
64
        UHD_ASSERT_THROW(::ioctl(_node_fd, I2C_RDWR, &data) >= 0);
65
    }
66

    
67
    byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){
68
        byte_vector_t bytes(num_bytes);
69

    
70
        //setup the message
71
        i2c_msg msg;
72
        msg.addr = addr;
73
        msg.flags = I2C_M_RD;
74
        msg.len = bytes.size();
75
        msg.buf = &bytes.front();
76

    
77
        //setup the data
78
        i2c_rdwr_ioctl_data data;
79
        data.msgs = &msg;
80
        data.nmsgs = 1;
81

    
82
        //call the ioctl
83
        UHD_ASSERT_THROW(::ioctl(_node_fd, I2C_RDWR, &data) >= 0);
84

    
85
        return bytes;
86
    }
87

    
88
private: int _node_fd;
89
};
90

    
91
/***********************************************************************
92
 * USRP-E100 interface implementation
93
 **********************************************************************/
94
class usrp_e100_iface_impl : public usrp_e100_iface{
95
public:
96

    
97
    int get_file_descriptor(void){
98
        return _node_fd;
99
    }
100

    
101
    /*******************************************************************
102
     * Structors
103
     ******************************************************************/
104
    usrp_e100_iface_impl(const std::string &node):
105
        _i2c_dev_iface(i2c_dev_iface("/dev/i2c-3"))
106
    {
107
        //open the device node and check file descriptor
108
        if ((_node_fd = ::open(node.c_str(), O_RDWR)) < 0){
109
            throw uhd::io_error("Failed to open " + node);
110
        }
111

    
112
        //very first thing, reset all the wishbone, always do first!
113
        //disabled for now: this->poke32(UE_REG_CLEAR_GLOBAL, 0);
114

    
115
        mb_eeprom = mboard_eeprom_t(get_i2c_dev_iface(), mboard_eeprom_t::MAP_E100);
116
    }
117

    
118
    ~usrp_e100_iface_impl(void){
119
        //close the device node file descriptor
120
        ::close(_node_fd);
121
    }
122

    
123
    /*******************************************************************
124
     * IOCTL: provides the communication base for all other calls
125
     ******************************************************************/
126
    void ioctl(int request, void *mem){
127
        boost::mutex::scoped_lock lock(_ctrl_mutex);
128

    
129
        if (::ioctl(_node_fd, request, mem) < 0){
130
            throw uhd::os_error(str(
131
                boost::format("ioctl failed with request %d") % request
132
            ));
133
        }
134
    }
135

    
136
    /*******************************************************************
137
     * I2C device node interface
138
     ******************************************************************/
139
    i2c_iface &get_i2c_dev_iface(void){
140
        return _i2c_dev_iface;
141
    }
142

    
143
    /*******************************************************************
144
     * Peek and Poke
145
     ******************************************************************/
146
    void poke32(boost::uint32_t addr, boost::uint32_t value){
147
        //load the data struct
148
        usrp_e_ctl32 data;
149
        data.offset = addr;
150
        data.count = 1;
151
        data.buf[0] = value;
152

    
153
        //call the ioctl
154
        this->ioctl(USRP_E_WRITE_CTL32, &data);
155
    }
156

    
157
    void poke16(boost::uint32_t addr, boost::uint16_t value){
158
        //load the data struct
159
        usrp_e_ctl16 data;
160
        data.offset = addr;
161
        data.count = 1;
162
        data.buf[0] = value;
163

    
164
        //call the ioctl
165
        this->ioctl(USRP_E_WRITE_CTL16, &data);
166
    }
167

    
168
    boost::uint32_t peek32(boost::uint32_t addr){
169
        //load the data struct
170
        usrp_e_ctl32 data;
171
        data.offset = addr;
172
        data.count = 1;
173

    
174
        //call the ioctl
175
        this->ioctl(USRP_E_READ_CTL32, &data);
176

    
177
        return data.buf[0];
178
    }
179

    
180
    boost::uint16_t peek16(boost::uint32_t addr){
181
        //load the data struct
182
        usrp_e_ctl16 data;
183
        data.offset = addr;
184
        data.count = 1;
185

    
186
        //call the ioctl
187
        this->ioctl(USRP_E_READ_CTL16, &data);
188

    
189
        return data.buf[0];
190
    }
191

    
192
    /*******************************************************************
193
     * I2C
194
     ******************************************************************/
195
    static const size_t max_i2c_data_bytes = 10;
196

    
197
    void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){
198
        //allocate some memory for this transaction
199
        UHD_ASSERT_THROW(bytes.size() <= max_i2c_data_bytes);
200
        boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes];
201

    
202
        //load the data struct
203
        usrp_e_i2c *data = reinterpret_cast<usrp_e_i2c*>(mem);
204
        data->addr = addr;
205
        data->len = bytes.size();
206
        std::copy(bytes.begin(), bytes.end(), data->data);
207

    
208
        //call the spi ioctl
209
        this->ioctl(USRP_E_I2C_WRITE, data);
210
    }
211

    
212
    byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){
213
        //allocate some memory for this transaction
214
        UHD_ASSERT_THROW(num_bytes <= max_i2c_data_bytes);
215
        boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes];
216

    
217
        //load the data struct
218
        usrp_e_i2c *data = reinterpret_cast<usrp_e_i2c*>(mem);
219
        data->addr = addr;
220
        data->len = num_bytes;
221

    
222
        //call the spi ioctl
223
        this->ioctl(USRP_E_I2C_READ, data);
224

    
225
        //unload the data
226
        byte_vector_t bytes(data->len);
227
        UHD_ASSERT_THROW(bytes.size() == num_bytes);
228
        std::copy(data->data, data->data+bytes.size(), bytes.begin());
229
        return bytes;
230
    }
231

    
232
    /*******************************************************************
233
     * SPI
234
     ******************************************************************/
235
    boost::uint32_t transact_spi(
236
        int which_slave,
237
        const spi_config_t &config,
238
        boost::uint32_t bits,
239
        size_t num_bits,
240
        bool readback
241
    ){
242
        //load data struct
243
        usrp_e_spi data;
244
        data.readback = (readback)? UE_SPI_TXRX : UE_SPI_TXONLY;
245
        data.slave = which_slave;
246
        data.length = num_bits;
247
        data.data = bits;
248

    
249
        //load the flags
250
        data.flags = 0;
251
        data.flags |= (config.miso_edge == spi_config_t::EDGE_RISE)? UE_SPI_LATCH_RISE : UE_SPI_LATCH_FALL;
252
        data.flags |= (config.mosi_edge == spi_config_t::EDGE_RISE)? UE_SPI_PUSH_FALL  : UE_SPI_PUSH_RISE;
253

    
254
        //call the spi ioctl
255
        this->ioctl(USRP_E_SPI, &data);
256

    
257
        //unload the data
258
        return data.data;
259
    }
260
    
261
    void write_uart(boost::uint8_t dev, const std::string &buf) {
262
        throw uhd::not_implemented_error("Unhandled command write_uart()");
263
    }
264
    
265
    std::string read_uart(boost::uint8_t dev) {
266
        throw uhd::not_implemented_error("Unhandled command read_uart()");
267
    }
268

    
269
private:
270
    int _node_fd;
271
    i2c_dev_iface _i2c_dev_iface;
272
    boost::mutex _ctrl_mutex;
273
};
274

    
275
/***********************************************************************
276
 * Public Make Function
277
 **********************************************************************/
278
usrp_e100_iface::sptr usrp_e100_iface::make(const std::string &node){
279
    return sptr(new usrp_e100_iface_impl(node));
280
}