Revision 40217798 host/lib/usrp/usrp1/io_impl.cpp

b/host/lib/usrp/usrp1/io_impl.cpp
35 35

  
36 36
static const float poll_interval = 0.1;  //100ms
37 37

  
38
/*
39
 * The FX2 firmware bursts data to the FPGA in 512 byte chunks so
40
 * maintain send state to make sure that happens.
41
 */
42 38
struct usrp1_send_state {
43 39
    uhd::transport::managed_send_buffer::sptr send_buff;
44
    size_t bytes_used;
40
    size_t bytes_written;
45 41
    size_t bytes_free;
42
    size_t underrun_poll_samp_count;
43
};
44

  
45
struct usrp1_recv_state {
46
    uhd::transport::managed_recv_buffer::sptr recv_buff;
47
    size_t bytes_read;
48
    size_t bytes_avail;
49
    size_t overrun_poll_samp_count;
46 50
};
47 51

  
48 52
/***********************************************************************
49 53
 * IO Implementation Details
50 54
 **********************************************************************/
51 55
struct usrp1_impl::io_impl {
52
    io_impl(zero_copy_if::sptr zc_if);
56
    io_impl();
53 57
    ~io_impl(void);
54 58

  
55
    bool get_recv_buff(managed_recv_buffer::sptr buff); 
56

  
57
    //state management for the vrt packet handler code
58
    vrt_packet_handler::recv_state packet_handler_recv_state;
59
    //state handling for buffer management 
60
    usrp1_recv_state recv_state;
59 61
    usrp1_send_state send_state;
60 62

  
61
    zero_copy_if::sptr data_transport;
62

  
63
    //overun-underrun values
64
    unsigned int tx_underrun_count;
65
    unsigned int rx_overrun_count;
63
    //send transport management 
64
    bool get_send_buffer(zero_copy_if::sptr zc_if);
65
    size_t copy_convert_send_samps(const void *buff, size_t num_samps,
66
                              size_t sample_offset, const io_type_t io_type,
67
                              otw_type_t otw_type);
68
    bool conditional_buff_commit(bool force);
69
    bool check_underrun(usrp_ctrl::sptr ctrl_if,
70
                        size_t poll_interval, bool force);
71

  
72
    //recv transport management 
73
    bool get_recv_buffer(zero_copy_if::sptr zc_if);
74
    size_t copy_convert_recv_samps(void *buff, size_t num_samps,
75
                              size_t sample_offset, const io_type_t io_type,
76
                              otw_type_t otw_type);
77
    bool check_overrun(usrp_ctrl::sptr ctrl_if,
78
                        size_t poll_interval, bool force);
66 79
};
67 80

  
68
usrp1_impl::io_impl::io_impl(zero_copy_if::sptr zc_if)
69
 : packet_handler_recv_state(1), data_transport(zc_if),
70
   tx_underrun_count(0), rx_overrun_count(0)
81
usrp1_impl::io_impl::io_impl()
71 82
{
72
    /* NOP */
83
    send_state.send_buff = uhd::transport::managed_send_buffer::sptr();
84
    recv_state.recv_buff = uhd::transport::managed_recv_buffer::sptr();
73 85
}
74 86

  
75 87
usrp1_impl::io_impl::~io_impl(void)
......
87 99
    _tx_otw_type.shift = 0;
88 100
    _tx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
89 101

  
90
    _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport));
102
    _io_impl = UHD_PIMPL_MAKE(io_impl, ());
91 103
}
92 104

  
93 105
/***********************************************************************
94 106
 * Data Send
95 107
 **********************************************************************/
108
bool usrp1_impl::io_impl::get_send_buffer(zero_copy_if::sptr zc_if)
109
{
110
    if (send_state.send_buff == NULL) {
111

  
112
        send_state.send_buff = zc_if->get_send_buff();
113
        if (send_state.send_buff == NULL)
114
            return false;
115

  
116
        send_state.bytes_free = send_state.send_buff->size();
117
        send_state.bytes_written = 0;
118
    }
119

  
120
    return true;
121
}
122

  
123
size_t usrp1_impl::io_impl::copy_convert_send_samps(const void *buff,
124
                                                    size_t num_samps,
125
                                                    size_t sample_offset,
126
                                                    const io_type_t io_type,
127
                                                    otw_type_t otw_type)
128
{
129
    UHD_ASSERT_THROW(send_state.bytes_free % otw_type.get_sample_size() == 0);
130

  
131
    size_t samps_free = send_state.bytes_free / otw_type.get_sample_size();
132
    size_t copy_samps = std::min(num_samps - sample_offset, samps_free); 
133

  
134
    const boost::uint8_t *io_mem =
135
        reinterpret_cast<const boost::uint8_t *>(buff);
136

  
137
    boost::uint8_t *otw_mem = send_state.send_buff->cast<boost::uint8_t *>();
138

  
139
    convert_io_type_to_otw_type(io_mem + sample_offset * io_type.size,
140
                                io_type,
141
                                otw_mem + send_state.bytes_written,
142
                                otw_type,
143
                                copy_samps);
144

  
145
    send_state.bytes_written += copy_samps * otw_type.get_sample_size();
146
    send_state.bytes_free -= copy_samps * otw_type.get_sample_size();
147
    send_state.underrun_poll_samp_count += copy_samps;
148

  
149
    return copy_samps;
150
}
151

  
152
bool usrp1_impl::io_impl::conditional_buff_commit(bool force)
153
{
154
    if (send_state.bytes_written % 512)
155
        return false;
156

  
157
    if (force || send_state.bytes_free == 0) {
158
        send_state.send_buff->commit(send_state.bytes_written);
159
        send_state.send_buff = uhd::transport::managed_send_buffer::sptr();
160
        return true;
161
    }
162
    
163
    return false;
164
}
165

  
166
bool usrp1_impl::io_impl::check_underrun(usrp_ctrl::sptr ctrl_if,
167
                                         size_t poll_interval,
168
                                         bool force)
169
{
170
    unsigned char underrun = 0;
171

  
172
    bool ready_to_poll = send_state.underrun_poll_samp_count > poll_interval;
173

  
174
    if (force || ready_to_poll) {
175
        int ret = ctrl_if->usrp_control_read(VRQ_GET_STATUS,
176
                                             0,
177
                                             GS_TX_UNDERRUN,
178
                                             &underrun, sizeof(char));
179
        if (ret < 0)
180
            std::cerr << "USRP: underrun check failed" << std::endl;
181
        if (underrun)
182
            std::cerr << "U" << std::endl;
183

  
184
        send_state.underrun_poll_samp_count = 0;
185
    }
186

  
187
    return (bool) underrun;
188
}
189

  
96 190
size_t usrp1_impl::send(const std::vector<const void *> &buffs,
97 191
                        size_t num_samps,
98 192
                        const tx_metadata_t &,
......
104 198
    size_t total_samps_sent = 0;
105 199

  
106 200
    while (total_samps_sent < num_samps) {
107

  
108
        if (_io_impl->send_state.send_buff == NULL) {
109
            _io_impl->send_state.send_buff = _data_transport->get_send_buff();
110
            if (_io_impl->send_state.send_buff == NULL) {
111
                return 0;
112
            }
113
            _io_impl->send_state.bytes_used = 0;
114
            _io_impl->send_state.bytes_free = _io_impl->send_state.send_buff->size();
115
        }
116

  
117
        size_t copy_samps =
118
               std::min(num_samps - total_samps_sent, _io_impl->send_state.bytes_free / _tx_otw_type.get_sample_size());
119

  
120
        const boost::uint8_t *io_mem =
121
                             reinterpret_cast<const boost::uint8_t *>(buffs[0]);
122

  
123
        boost::uint8_t *otw_mem = _io_impl->send_state.send_buff->cast<boost::uint8_t *>();
124

  
125
        // Type conversion and copy 
126
        convert_io_type_to_otw_type(
127
                     io_mem + total_samps_sent * io_type.size,
128
                     io_type,
129
                     otw_mem + _io_impl->send_state.bytes_used,
130
                     _tx_otw_type,
131
                     copy_samps);
132
 
133
        _io_impl->send_state.bytes_used += copy_samps * _tx_otw_type.get_sample_size();
134
        _io_impl->send_state.bytes_free -= copy_samps * _tx_otw_type.get_sample_size();
135

  
136
        if (_io_impl->send_state.bytes_free == 0) {
137
            _io_impl->send_state.send_buff->commit(_io_impl->send_state.bytes_used);
138
            _io_impl->send_state.send_buff = uhd::transport::managed_send_buffer::sptr();
139
        }
140

  
141
        total_samps_sent += copy_samps; 
142
        _io_impl->tx_underrun_count += copy_samps * _tx_otw_type.get_sample_size();
143
 
144
        //check for underruns
145
        if (!(_io_impl->tx_underrun_count > _tx_dsp_freq * poll_interval * _tx_otw_type.get_sample_size())) {
146
            unsigned char underrun;
147
            int ret = _ctrl_transport->usrp_control_read(VRQ_GET_STATUS,
148
                                                         0,
149
                                                         GS_TX_UNDERRUN,
150
                                                         &underrun, sizeof(char));
151
            if (ret < 0)
152
                std::cerr << "error: underrun check failed" << std::endl;
153
            if (underrun)
154
                std::cerr << "U" << std::endl;
155

  
156
            _io_impl->tx_underrun_count = 0;
157
        }
201
        if (!_io_impl->get_send_buffer(_data_transport))
202
            return 0;
203

  
204
        total_samps_sent += _io_impl->copy_convert_send_samps(buffs[0],
205
                                                              num_samps,
206
                                                              total_samps_sent,
207
                                                              io_type,
208
                                                              _tx_otw_type);
209
        if (total_samps_sent == num_samps)
210
            _io_impl->conditional_buff_commit(true);
211
        else
212
            _io_impl->conditional_buff_commit(false);
213

  
214
        _io_impl->check_underrun(_ctrl_transport,
215
                                 _tx_samps_per_poll_interval, false);
158 216
    }
159 217

  
160 218
    return total_samps_sent;
......
163 221
/***********************************************************************
164 222
 * Data Recv
165 223
 **********************************************************************/
166
void _recv_helper(vrt_packet_handler::recv_state &state)
224
bool usrp1_impl::io_impl::get_recv_buffer(zero_copy_if::sptr zc_if)
225
{
226
    if ((recv_state.recv_buff == NULL) || (recv_state.bytes_avail == 0)) {
227

  
228
        recv_state.recv_buff = zc_if->get_recv_buff();
229
        if (recv_state.recv_buff == NULL)
230
            return false;
231

  
232
        recv_state.bytes_read = 0;
233
        recv_state.bytes_avail = recv_state.recv_buff->size();
234
    }
235

  
236
    return true;
237
}
238

  
239
size_t usrp1_impl::io_impl::copy_convert_recv_samps(void *buff,
240
                                                    size_t num_samps,
241
                                                    size_t sample_offset,
242
                                                    const io_type_t io_type,
243
                                                    otw_type_t otw_type)
244
{
245
    UHD_ASSERT_THROW(recv_state.bytes_avail % otw_type.get_sample_size() == 0);
246

  
247
    size_t samps_avail = recv_state.bytes_avail / otw_type.get_sample_size();
248
    size_t copy_samps = std::min(num_samps - sample_offset, samps_avail); 
249

  
250
    const boost::uint8_t *otw_mem =
251
        recv_state.recv_buff->cast<const boost::uint8_t *>();
252

  
253
    boost::uint8_t *io_mem = reinterpret_cast<boost::uint8_t *>(buff);
254

  
255
    convert_otw_type_to_io_type(otw_mem + recv_state.bytes_read,
256
                                otw_type,
257
                                io_mem + sample_offset * io_type.size,
258
                                io_type,
259
                                copy_samps);
260

  
261
    recv_state.bytes_read += copy_samps * otw_type.get_sample_size();
262
    recv_state.bytes_avail -= copy_samps * otw_type.get_sample_size();
263
    recv_state.overrun_poll_samp_count += copy_samps;
264

  
265
    return copy_samps;
266
}
267

  
268
bool usrp1_impl::io_impl::check_overrun(usrp_ctrl::sptr ctrl_if,
269
                                        size_t poll_interval,
270
                                        bool force)
167 271
{
168
    size_t num_packet_words32 =
169
                       state.managed_buffs[0]->size() / sizeof(boost::uint32_t);
272
    unsigned char overrun = 0;
273

  
274
    bool ready_to_poll = recv_state.overrun_poll_samp_count > poll_interval;
170 275

  
171
    const boost::uint32_t *data =
172
                        state.managed_buffs[0]->cast<const boost::uint32_t *>();
276
    if (force || ready_to_poll) {
277
        int ret = ctrl_if->usrp_control_read(VRQ_GET_STATUS,
278
                                             0,
279
                                             GS_RX_OVERRUN,
280
                                             &overrun, sizeof(char));
281
        if (ret < 0)
282
            std::cerr << "USRP: overrrun check failed" << std::endl;
283
        if (overrun)
284
            std::cerr << "O" << std::endl;
285

  
286
        recv_state.overrun_poll_samp_count = 0;
287
    }
173 288

  
174
    state.copy_buffs[0] = reinterpret_cast<const boost::uint8_t *>(data);
175
    size_t num_payload_bytes = num_packet_words32 * sizeof(boost::uint32_t);
176
    state.size_of_copy_buffs = num_payload_bytes;
289
    return (bool) overrun;
177 290
}
178 291

  
179 292
size_t usrp1_impl::recv(const std::vector<void *> &buffs,
......
183 296
                        recv_mode_t,
184 297
                        size_t)
185 298
{
186
    UHD_ASSERT_THROW(_io_impl->packet_handler_recv_state.width == 1);
187 299
    UHD_ASSERT_THROW(buffs.size() == 1);
188 300

  
189
    size_t sent_samps = 0;
190
    size_t nsamps_to_copy = 0;; 
191

  
192
    while (sent_samps < num_samps) {
193
        if (_io_impl->packet_handler_recv_state.size_of_copy_buffs == 0) {
194
            _io_impl->packet_handler_recv_state.fragment_offset_in_samps = 0;
195
            _io_impl->packet_handler_recv_state.managed_buffs[0] =
196
                                          _io_impl->data_transport->get_recv_buff();
197
 
198
            //timeout or something bad returns zero
199
            if (!_io_impl->packet_handler_recv_state.managed_buffs[0].get())
200
                return 0;
201
 
202
            _recv_helper(_io_impl->packet_handler_recv_state);
203
        }
204

  
205
        size_t bytes_per_item = _rx_otw_type.get_sample_size();
206
        size_t nsamps_available =
207
            _io_impl->packet_handler_recv_state.size_of_copy_buffs / bytes_per_item;
208
        nsamps_to_copy = std::min(num_samps, nsamps_available);
209
        size_t bytes_to_copy = nsamps_to_copy * bytes_per_item;
210

  
211
        convert_otw_type_to_io_type(
212
              _io_impl->packet_handler_recv_state.copy_buffs[0],
213
              _rx_otw_type,
214
              reinterpret_cast<boost::uint8_t *>(buffs[0]) + sent_samps * io_type.size,
215
              io_type,
216
              nsamps_to_copy);
217
 
218
        _io_impl->packet_handler_recv_state.copy_buffs[0] += bytes_to_copy; 
219
        _io_impl->packet_handler_recv_state.size_of_copy_buffs -= bytes_to_copy;
220
        _io_impl->rx_overrun_count += nsamps_to_copy;
221

  
222
        sent_samps += nsamps_to_copy;
223

  
224
        //check for overruns 
225
        if (_io_impl->rx_overrun_count > (8e6 * poll_interval)) {
226
            unsigned char overrun;
227
            int ret = _ctrl_transport->usrp_control_read(VRQ_GET_STATUS,
228
                                                         0,
229
                                                         GS_RX_OVERRUN,
230
                                                         &overrun, sizeof(char));
231
            if (ret < 0)
232
                std::cerr << "error: overrun check failed" << std::endl;
233
            if (overrun)
234
                std::cerr << "O" << std::endl;
235

  
236
            _io_impl->rx_overrun_count = 0;
237
        }
301
    size_t total_samps_recv = 0;
302

  
303
    while (total_samps_recv < num_samps) {
304

  
305
        if (!_io_impl->get_recv_buffer(_data_transport))
306
            return 0;
307

  
308
        total_samps_recv += _io_impl->copy_convert_recv_samps(buffs[0],
309
                                                              num_samps,
310
                                                              total_samps_recv,
311
                                                              io_type,
312
                                                              _rx_otw_type);
313
        _io_impl->check_overrun(_ctrl_transport,
314
                                _rx_samps_per_poll_interval, false);
238 315
    }
239 316

  
240
    return sent_samps; 
317
    return total_samps_recv; 
241 318
}

Also available in: Unified diff