Statistics
| Branch: | Tag: | Revision:

root / host / lib / usrp / usrp_e100 / usrp_e100_iface.cpp @ f2d5f0b1

History | View | Annotate | Download (8.14 KB)

1
//
2
// Copyright 2010 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 <uhd/utils/assert.hpp>
20
#include <sys/ioctl.h> //ioctl
21
#include <fcntl.h> //open, close
22
#include <linux/usrp_e.h> //ioctl structures and constants
23
#include <boost/format.hpp>
24
#include <boost/thread.hpp> //mutex
25
#include <linux/i2c-dev.h>
26
#include <stdexcept>
27

    
28
using namespace uhd;
29
using namespace uhd::usrp;
30

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

    
42
    ~i2c_dev_iface(void){
43
        ::close(_node_fd);
44
    }
45

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

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

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

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

    
65
    byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){
66
        byte_vector_t bytes(num_bytes);
67

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

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

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

    
83
        return bytes;
84
    }
85

    
86
private: int _node_fd;
87
};
88

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

    
95
    int get_file_descriptor(void){
96
        return _node_fd;
97
    }
98

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

    
110
        mb_eeprom = mboard_eeprom_t(get_i2c_dev_iface(), mboard_eeprom_t::MAP_E100);
111
    }
112

    
113
    ~usrp_e100_iface_impl(void){
114
        //close the device node file descriptor
115
        ::close(_node_fd);
116
    }
117

    
118
    /*******************************************************************
119
     * IOCTL: provides the communication base for all other calls
120
     ******************************************************************/
121
    void ioctl(int request, void *mem){
122
        boost::mutex::scoped_lock lock(_ctrl_mutex);
123

    
124
        if (::ioctl(_node_fd, request, mem) < 0){
125
            throw std::runtime_error(str(
126
                boost::format("ioctl failed with request %d") % request
127
            ));
128
        }
129
    }
130

    
131
    /*******************************************************************
132
     * I2C device node interface
133
     ******************************************************************/
134
    i2c_iface &get_i2c_dev_iface(void){
135
        return _i2c_dev_iface;
136
    }
137

    
138
    /*******************************************************************
139
     * Peek and Poke
140
     ******************************************************************/
141
    void poke32(boost::uint32_t addr, boost::uint32_t value){
142
        //load the data struct
143
        usrp_e_ctl32 data;
144
        data.offset = addr;
145
        data.count = 1;
146
        data.buf[0] = value;
147

    
148
        //call the ioctl
149
        this->ioctl(USRP_E_WRITE_CTL32, &data);
150
    }
151

    
152
    void poke16(boost::uint32_t addr, boost::uint16_t value){
153
        //load the data struct
154
        usrp_e_ctl16 data;
155
        data.offset = addr;
156
        data.count = 1;
157
        data.buf[0] = value;
158

    
159
        //call the ioctl
160
        this->ioctl(USRP_E_WRITE_CTL16, &data);
161
    }
162

    
163
    boost::uint32_t peek32(boost::uint32_t addr){
164
        //load the data struct
165
        usrp_e_ctl32 data;
166
        data.offset = addr;
167
        data.count = 1;
168

    
169
        //call the ioctl
170
        this->ioctl(USRP_E_READ_CTL32, &data);
171

    
172
        return data.buf[0];
173
    }
174

    
175
    boost::uint16_t peek16(boost::uint32_t addr){
176
        //load the data struct
177
        usrp_e_ctl16 data;
178
        data.offset = addr;
179
        data.count = 1;
180

    
181
        //call the ioctl
182
        this->ioctl(USRP_E_READ_CTL16, &data);
183

    
184
        return data.buf[0];
185
    }
186

    
187
    /*******************************************************************
188
     * I2C
189
     ******************************************************************/
190
    static const size_t max_i2c_data_bytes = 10;
191

    
192
    void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){
193
        //allocate some memory for this transaction
194
        UHD_ASSERT_THROW(bytes.size() <= max_i2c_data_bytes);
195
        boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes];
196

    
197
        //load the data struct
198
        usrp_e_i2c *data = reinterpret_cast<usrp_e_i2c*>(mem);
199
        data->addr = addr;
200
        data->len = bytes.size();
201
        std::copy(bytes.begin(), bytes.end(), data->data);
202

    
203
        //call the spi ioctl
204
        this->ioctl(USRP_E_I2C_WRITE, data);
205
    }
206

    
207
    byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){
208
        //allocate some memory for this transaction
209
        UHD_ASSERT_THROW(num_bytes <= max_i2c_data_bytes);
210
        boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes];
211

    
212
        //load the data struct
213
        usrp_e_i2c *data = reinterpret_cast<usrp_e_i2c*>(mem);
214
        data->addr = addr;
215
        data->len = num_bytes;
216

    
217
        //call the spi ioctl
218
        this->ioctl(USRP_E_I2C_READ, data);
219

    
220
        //unload the data
221
        byte_vector_t bytes(data->len);
222
        UHD_ASSERT_THROW(bytes.size() == num_bytes);
223
        std::copy(data->data, data->data+bytes.size(), bytes.begin());
224
        return bytes;
225
    }
226

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

    
244
        //load the flags
245
        data.flags = 0;
246
        data.flags |= (config.miso_edge == spi_config_t::EDGE_RISE)? UE_SPI_LATCH_RISE : UE_SPI_LATCH_FALL;
247
        data.flags |= (config.mosi_edge == spi_config_t::EDGE_RISE)? UE_SPI_PUSH_FALL  : UE_SPI_PUSH_RISE;
248

    
249
        //call the spi ioctl
250
        this->ioctl(USRP_E_SPI, &data);
251

    
252
        //unload the data
253
        return data.data;
254
    }
255

    
256
private:
257
    int _node_fd;
258
    i2c_dev_iface _i2c_dev_iface;
259
    boost::mutex _ctrl_mutex;
260
};
261

    
262
/***********************************************************************
263
 * Public Make Function
264
 **********************************************************************/
265
usrp_e100_iface::sptr usrp_e100_iface::make(const std::string &node){
266
    return sptr(new usrp_e100_iface_impl(node));
267
}