blob: 8bf48364160b7ed30cf3b49044f9ae40f6a012e8 [file] [log] [blame]
Eric Wild1e17c4f2020-03-24 17:19:27 +01001/*
2* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
3* Author: Pau Espin Pedrol <pespin@sysmocom.de>
4*
5* SPDX-License-Identifier: AGPL-3.0+
6*
7* This program is free software: you can redistribute it and/or modify
8* it under the terms of the GNU Affero General Public License as published by
9* the Free Software Foundation, either version 3 of the License, or
10* (at your option) any later version.
11*
12* This program is distributed in the hope that it will be useful,
13* but WITHOUT ANY WARRANTY; without even the implied warranty of
14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15* GNU Affero General Public License for more details.
16*
17* You should have received a copy of the GNU Affero General Public License
18* along with this program. If not, see <http://www.gnu.org/licenses/>.
19* See the COPYING file in the main directory for details.
20*/
21
22#include <cstdint>
23#include <cstring>
24#include <cstdlib>
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif
29
30#include "Logger.h"
31#include "Threads.h"
32#include "IPCDevice.h"
33#include "smpl_buf.h"
34
35extern "C" {
36#include <sys/mman.h>
37#include <sys/stat.h> /* For mode constants */
38#include <fcntl.h> /* For O_* constants */
39
40#include "osmo_signal.h"
41#include <osmocom/core/talloc.h>
42#include <osmocom/core/select.h>
43#include <osmocom/core/socket.h>
44#include <osmocom/core/logging.h>
45#include <osmocom/core/utils.h>
46#include <osmocom/core/msgb.h>
47#include <osmocom/core/select.h>
48#include <osmocom/core/timer.h>
49
50#include "ipc_shm.h"
51}
52
53#define SAMPLE_BUF_SZ (1 << 20)
54
55using namespace std;
56
57static int ipc_chan_sock_cb(struct osmo_fd *bfd, unsigned int flags);
58
59IPCDevice::IPCDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chan_num, double lo_offset,
60 const std::vector<std::string> &tx_paths, const std::vector<std::string> &rx_paths)
Eric5561f112022-07-19 21:18:21 +020061 : RadioDevice(tx_sps, rx_sps, iface, chan_num, lo_offset, tx_paths, rx_paths), sk_chan_state(chans, ipc_per_trx_sock_state()),
62 tx_attenuation(), tmp_state(IPC_IF_MSG_GREETING_REQ), shm(NULL), shm_dec(0),
63 rx_buffers(chans), started(false), tx_gains(chans), rx_gains(chans)
Eric Wild1e17c4f2020-03-24 17:19:27 +010064{
65 LOGC(DDEV, INFO) << "creating IPC device...";
66
Eric Wild1e17c4f2020-03-24 17:19:27 +010067 /* Set up per-channel Rx timestamp based Ring buffers */
68 for (size_t i = 0; i < rx_buffers.size(); i++)
69 rx_buffers[i] = new smpl_buf(SAMPLE_BUF_SZ / sizeof(uint32_t));
70}
71
72IPCDevice::~IPCDevice()
73{
74 LOGC(DDEV, INFO) << "Closing IPC device";
75 /* disable all channels */
76
77 for (size_t i = 0; i < rx_buffers.size(); i++)
78 delete rx_buffers[i];
79
80 ipc_sock_close(&master_sk_state);
81
82 for (unsigned int i = 0; i < sk_chan_state.size(); i++)
83 ipc_sock_close(&sk_chan_state[i]);
84
85 for (auto i : shm_io_rx_streams)
86 ipc_shm_close(i);
87 for (auto i : shm_io_tx_streams)
88 ipc_shm_close(i);
89
90 if (shm_dec)
91 talloc_free(shm_dec);
92}
93
94int IPCDevice::ipc_shm_connect(const char *shm_name)
95{
96 int fd;
Vadim Yanitskiy683f1402021-10-25 12:41:20 +030097 char err_buf[256];
Eric Wild1e17c4f2020-03-24 17:19:27 +010098 size_t shm_len;
99 int rc;
100
101 LOGP(DDEV, LOGL_NOTICE, "Opening shm path %s\n", shm_name);
102 if ((fd = shm_open(shm_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) {
Vadim Yanitskiy683f1402021-10-25 12:41:20 +0300103 LOGP(DDEV, LOGL_ERROR, "shm_open %d: %s\n", errno,
104 strerror_r(errno, err_buf, sizeof(err_buf)));
Eric Wild1e17c4f2020-03-24 17:19:27 +0100105 rc = -errno;
106 goto err_shm_open;
107 }
108
109 // Get size of the allocated memory
110 struct stat shm_stat;
111 if (fstat(fd, &shm_stat) < 0) {
Vadim Yanitskiy683f1402021-10-25 12:41:20 +0300112 LOGP(DDEV, LOGL_ERROR, "fstat %d: %s\n", errno,
113 strerror_r(errno, err_buf, sizeof(err_buf)));
Eric Wild1e17c4f2020-03-24 17:19:27 +0100114 rc = -errno;
115 goto err_mmap;
116 }
117
118 shm_len = shm_stat.st_size;
119
120 LOGP(DDEV, LOGL_NOTICE, "mmaping shared memory fd %d (size=%zu)\n", fd, shm_len);
121 if ((shm = mmap(NULL, shm_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
Vadim Yanitskiy683f1402021-10-25 12:41:20 +0300122 LOGP(DDEV, LOGL_ERROR, "mmap %d: %s\n", errno,
123 strerror_r(errno, err_buf, sizeof(err_buf)));
Eric Wild1e17c4f2020-03-24 17:19:27 +0100124 rc = -errno;
125 goto err_mmap;
126 }
127 LOGP(DDEV, LOGL_NOTICE, "mmap'ed shared memory at addr %p\n", shm);
128 // LOGP(DDEV, LOGL_NOTICE, "%s\n", osmo_hexdump((const unsigned char *)shm, 80));
129 /* After a call to mmap(2) the file descriptor may be closed without affecting the memory mapping. */
130 close(fd);
131 return 0;
132err_mmap:
133 shm_unlink(shm_name);
134 close(fd);
135err_shm_open:
136 return rc;
137}
138
139static int ipc_sock_send(struct ipc_per_trx_sock_state *state, struct msgb *msg);
140
141static struct msgb *ipc_msgb_alloc(uint8_t msg_type)
142{
143 struct msgb *msg;
144 struct ipc_sk_if *ipc_prim;
145
146 msg = msgb_alloc(sizeof(struct ipc_sk_if) + 1000, "ipc_sock_tx");
147 if (!msg)
148 return NULL;
149 msgb_put(msg, sizeof(struct ipc_sk_if) + 1000);
150 ipc_prim = (struct ipc_sk_if *)msg->data;
151 ipc_prim->msg_type = msg_type;
152
153 return msg;
154}
155
156static int ipc_tx_greeting_req(struct ipc_per_trx_sock_state *state, uint8_t req_version)
157{
158 struct msgb *msg;
159 struct ipc_sk_if *ipc_prim;
160
161 LOGC(DDEV, NOTICE) << "Tx Greeting Req (" << IPC_IF_MSG_GREETING_REQ << ")\n";
162
163 msg = ipc_msgb_alloc(IPC_IF_MSG_GREETING_REQ);
164 if (!msg) {
165 LOGC(DDEV, INFO) << "ipc_msgb_alloc() returns NULL!";
166 return -ENOMEM;
167 }
168 ipc_prim = (struct ipc_sk_if *)msg->data;
169 ipc_prim->u.greeting_req.req_version = req_version;
170
171 return ipc_sock_send(state, msg);
172}
173
174static int ipc_tx_info_req(struct ipc_per_trx_sock_state *state)
175{
176 struct msgb *msg;
177 //struct ipc_sk_if *ipc_prim;
178
179 LOGC(DDEV, NOTICE) << "Tx INFO Req\n";
180
181 msg = ipc_msgb_alloc(IPC_IF_MSG_INFO_REQ);
182 if (!msg)
183 return -ENOMEM;
184
185 //ipc_prim = (struct ipc_sk_if *) msg->data;
186
187 return ipc_sock_send(state, msg);
188}
189
190int IPCDevice::ipc_tx_open_req(struct ipc_per_trx_sock_state *state, uint32_t num_chans, uint32_t ref)
191{
192 struct msgb *msg;
193 struct ipc_sk_if *ipc_prim;
194 struct ipc_sk_if_open_req_chan *chan_info;
195
196 LOGC(DDEV, NOTICE) << "Tx Open Req\n";
197
198 msg = ipc_msgb_alloc(IPC_IF_MSG_OPEN_REQ);
199 if (!msg) {
200 return -ENOMEM;
201 }
202 ipc_prim = (struct ipc_sk_if *)msg->data;
203 ipc_prim->u.open_req.num_chans = num_chans;
204
205 /* FIXME: this is actually the sps value, not the sample rate!
206 * sample rate is looked up according to the sps rate by uhd backend */
207 ipc_prim->u.open_req.rx_sample_freq_num = rx_sps;
208 ipc_prim->u.open_req.rx_sample_freq_den = 1;
209 ipc_prim->u.open_req.tx_sample_freq_num = tx_sps;
210 ipc_prim->u.open_req.tx_sample_freq_den = 1;
211
212 switch (ref) {
213 case ReferenceType::REF_EXTERNAL:
214 ipc_prim->u.open_req.clockref = FEATURE_MASK_CLOCKREF_EXTERNAL;
215 break;
216 case ReferenceType::REF_INTERNAL:
217 case ReferenceType::REF_GPS:
218 ipc_prim->u.open_req.clockref = FEATURE_MASK_CLOCKREF_INTERNAL;
219 break;
220 }
221
222 /* FIXME: clock ref part of config, not open */
223 ipc_prim->u.open_req.clockref = FEATURE_MASK_CLOCKREF_EXTERNAL;
224
225 for (unsigned int i = 0; i < num_chans; i++) {
226 chan_info = &ipc_prim->u.open_req.chan_info[i];
227 OSMO_STRLCPY_ARRAY(chan_info->rx_path, rx_paths[i].c_str());
228 OSMO_STRLCPY_ARRAY(chan_info->tx_path, tx_paths[i].c_str());
229 }
230
231 return ipc_sock_send(state, msg);
232}
233
234static void ipc_sock_timeout(void *_priv)
235{
236 LOGC(DDEV, INFO) << "UNIX SOCKET TIMEOUT!";
237 exit(1);
238}
239
240int IPCDevice::ipc_rx_greeting_cnf(const struct ipc_sk_if_greeting *greeting_cnf)
241{
242 if (greeting_cnf->req_version == IPC_SOCK_API_VERSION) {
243 LOGC(DDEV, NOTICE) << "Rx Greeting CNF: correct sock API version" << greeting_cnf->req_version;
244 tmp_state = IPC_IF_MSG_GREETING_CNF;
245 } else {
246 LOGC(DDEV, ERROR) << "Wrong IPC SOCK API VERSION RECEIVED!" << greeting_cnf->req_version;
247 exit(1);
248 }
249 return 0;
250}
251
252int IPCDevice::ipc_rx_info_cnf(const struct ipc_sk_if_info_cnf *info_cnf)
253{
254 current_info_cnf = *info_cnf;
255 unsigned int i;
256
257 if (info_cnf->max_num_chans < chans) {
258 LOGC(DDEV, ERROR) << "chan num mismatch:" << info_cnf->max_num_chans << " vs " << chans;
259 return -1;
260 }
261
262 /* Here:
263 * verify info_cnf->max_num_chans >= requested chans
264 * verify supports setting reflock as asked by user looking in info_cnf->feature_mask
265 * cache locally min/max tx/rxGain values from info_cnf
266 * do whatever validations or print info_cnf->dev_desc
267 * cache rx/tx paths per channel, and make sure it matches the one the user wants to set
268 */
269
270 LOGC(DDEV, NOTICE)
271 << "Rx Info CNF:"
272 << " name=" << info_cnf->dev_desc << std::endl
273 << " max_num_chans=" << info_cnf->max_num_chans << " feature_mask=" << info_cnf->feature_mask;
274 for (i = 0; i < info_cnf->max_num_chans; i++) {
275 int j = 0;
276 bool rx_found = false, tx_found = false;
277 while (strcmp(info_cnf->chan_info[i].rx_path[j], "") != 0) {
278 LOGC(DDEV, NOTICE)
279 << "chan " << i << ": RxPath[" << j << "]: " << info_cnf->chan_info[i].rx_path[j]
280 << " min_rx_gain=" << info_cnf->chan_info[i].min_rx_gain
281 << " max_rx_gain=" << info_cnf->chan_info[i].max_rx_gain
282 << " min_tx_gain=" << info_cnf->chan_info[i].min_tx_gain
283 << " max_tx_gain=" << info_cnf->chan_info[i].max_tx_gain;
284
285 if (rx_paths.size() < (i + 1) ||
286 strcmp(rx_paths[i].c_str(), info_cnf->chan_info[i].rx_path[j]) == 0) {
287 rx_found = true;
288 break;
289 }
290 j++;
291 }
292 j = 0;
293 while (strcmp(info_cnf->chan_info[i].tx_path[j], "") != 0) {
294 LOGC(DDEV, NOTICE)
295 << "chan " << i << ": TxPath[" << j << "]: " << info_cnf->chan_info[i].tx_path[j];
296 if (tx_paths.size() < (i + 1) ||
297 strcmp(tx_paths[i].c_str(), info_cnf->chan_info[i].tx_path[j]) == 0) {
298 tx_found = true;
299 break;
300 }
301 j++;
302 }
303
304 if (!rx_found) {
305 LOGC(DDEV, ERROR) << "rx antenna not found: " << rx_paths[i];
306 exit(0);
307 }
308 if (!tx_found) {
309 LOGC(DDEV, ERROR) << "tx antenna not found: " << rx_paths[i];
310 exit(0);
311 }
312 }
313 tmp_state = IPC_IF_MSG_INFO_CNF;
314 return 0;
315}
316
317int IPCDevice::ipc_rx_open_cnf(const struct ipc_sk_if_open_cnf *open_cnf)
318{
319 unsigned int i;
320 current_open_cnf = *open_cnf;
321
322 LOGC(DDEV, NOTICE)
323 << "Rx Open CNF:"
324 << " return_code=" << (unsigned int)open_cnf->return_code << " shm_name=" << open_cnf->shm_name;
325 LOGC(DDEV, NOTICE) << "Rx Open CNF:"
326 << " ipc device path delay: " << (unsigned int)open_cnf->path_delay;
327 for (i = 0; i < chans; i++) {
328 int rc;
329 LOGC(DDEV, NOTICE) << "chan " << i << ": sk_path=" << open_cnf->chan_info[i].chan_ipc_sk_path;
330
331 /* FIXME: current limit IPC_MAX_NUM_TRX chans, make dynamic */
332 if (i < IPC_MAX_NUM_TRX) {
333 struct ipc_per_trx_sock_state *state = &sk_chan_state[i];
334
335 INIT_LLIST_HEAD(&state->upqueue);
336 rc = osmo_sock_unix_init_ofd(&state->conn_bfd, SOCK_SEQPACKET, 0,
337 open_cnf->chan_info[i].chan_ipc_sk_path, OSMO_SOCK_F_CONNECT);
338 if (rc < 0) {
339 LOGC(DDEV, ERROR) << "Failed to connect to the BTS ("
340 << open_cnf->chan_info[i].chan_ipc_sk_path << "). "
341 << "Retrying...\n";
342 osmo_timer_setup(&state->timer, ipc_sock_timeout, NULL);
343 osmo_timer_schedule(&state->timer, 5, 0);
344 return -1;
345 }
346 state->conn_bfd.cb = ipc_chan_sock_cb;
347 state->conn_bfd.data = this;
348 state->conn_bfd.priv_nr = i;
349 }
350 }
351
352 OSMO_STRLCPY_ARRAY(shm_name, open_cnf->shm_name);
353 if (ipc_shm_connect(shm_name) < 0)
354 return -1;
355 shm_dec = ipc_shm_decode_region(NULL, (ipc_shm_raw_region *)shm);
356 LOGC(DDEV, NOTICE) << "shm: num_chans=" << shm_dec->num_chans;
357
358 /* server inits both producers */
359 for (unsigned int i = 0; i < shm_dec->num_chans; i++) {
360 LOGC(DDEV, NOTICE)
361 << "shm: chan" << i << "/dl: num_buffers=" << shm_dec->channels[i]->dl_stream->num_buffers;
362 LOGC(DDEV, NOTICE)
363 << "shm: chan" << i << "/dl: buffer_size=" << shm_dec->channels[i]->dl_stream->buffer_size;
364 LOGC(DDEV, NOTICE)
365 << "shm: chan" << i << "/ul: num_buffers=" << shm_dec->channels[i]->ul_stream->num_buffers;
366 LOGC(DDEV, NOTICE)
367 << "shm: chan" << i << "/ul: buffer_size=" << shm_dec->channels[i]->ul_stream->buffer_size;
368 shm_io_rx_streams.push_back(ipc_shm_init_consumer(shm_dec->channels[i]->ul_stream));
369 shm_io_tx_streams.push_back(ipc_shm_init_consumer(shm_dec->channels[i]->dl_stream));
370 // we should init a producer here, but delegating all producers and therefore lock management
371 // to the other side is the reasonable approach to circumvent shutdown issues
372 }
373
374 tmp_state = IPC_IF_MSG_OPEN_CNF;
375 return 0;
376}
377
378int IPCDevice::ipc_rx(uint8_t msg_type, struct ipc_sk_if *ipc_prim)
379{
380 int rc = 0;
381
382 switch (msg_type) {
383 case IPC_IF_MSG_GREETING_CNF:
384 rc = ipc_rx_greeting_cnf(&ipc_prim->u.greeting_cnf);
385 break;
386 case IPC_IF_MSG_INFO_CNF:
387 rc = ipc_rx_info_cnf(&ipc_prim->u.info_cnf);
388 break;
389 case IPC_IF_MSG_OPEN_CNF:
390 rc = ipc_rx_open_cnf(&ipc_prim->u.open_cnf);
391 break;
392 default:
393 LOGP(DDEV, LOGL_ERROR, "Received unknown IPC msg type %d\n", msg_type);
394 rc = -EINVAL;
395 }
396
397 return rc;
398}
399
400int IPCDevice::ipc_rx_chan_start_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr)
401{
402 if (chan_nr >= chans) {
403 LOGC(DDEV, NOTICE) << "shm: illegal start response for chan #" << chan_nr << " ?!?";
404 return 0;
405 }
406 return 0;
407}
408int IPCDevice::ipc_rx_chan_stop_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr)
409{
410 if (chan_nr >= chans) {
411 LOGC(DDEV, NOTICE) << "shm: illegal stop response for chan #" << chan_nr << " ?!?";
412 return 0;
413 }
414 return 0;
415}
416int IPCDevice::ipc_rx_chan_setgain_cnf(ipc_sk_chan_if_gain *ret, uint8_t chan_nr)
417{
418 if (chan_nr >= chans) {
419 LOGC(DDEV, NOTICE) << "shm: illegal setgain response for chan #" << chan_nr << " ?!?";
420 return 0;
421 }
422
423 ret->is_tx ? tx_gains[chan_nr] = ret->gain : rx_gains[chan_nr] = ret->gain;
424 return 0;
425}
426int IPCDevice::ipc_rx_chan_settxattn_cnf(ipc_sk_chan_if_tx_attenuation *ret, uint8_t chan_nr)
427{
428 if (chan_nr >= chans) {
429 LOGC(DDEV, NOTICE) << "shm: illegal tx attn response for chan #" << chan_nr << " ?!?";
430 return 0;
431 }
432
433 tx_attenuation[chan_nr] = ret->attenuation;
434 return 0;
435}
436int IPCDevice::ipc_rx_chan_setfreq_cnf(ipc_sk_chan_if_freq_cnf *ret, uint8_t chan_nr)
437{
438 if (chan_nr >= chans) {
439 LOGC(DDEV, NOTICE) << "shm: illegal setfreq response for chan #" << chan_nr << " ?!?";
440 return 0;
441 }
442
443 return 0;
444}
445int IPCDevice::ipc_rx_chan_notify_underflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr)
446{
447 if (chan_nr >= chans) {
448 LOGC(DDEV, NOTICE) << "shm: illegal underfloww notification for chan #" << chan_nr << " ?!?";
449 return 0;
450 }
451
452 m_ctr[chan_nr].tx_underruns += 1;
453 osmo_signal_dispatch(SS_DEVICE, S_DEVICE_COUNTER_CHANGE, &m_ctr[chan_nr]);
454
455 return 0;
456}
457int IPCDevice::ipc_rx_chan_notify_overflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr)
458{
459 if (chan_nr >= chans) {
460 LOGC(DDEV, NOTICE) << "shm: illegal overflow notification for chan #" << chan_nr << " ?!?";
461 return 0;
462 }
463
464 m_ctr[chan_nr].rx_overruns += 1;
465 osmo_signal_dispatch(SS_DEVICE, S_DEVICE_COUNTER_CHANGE, &m_ctr[chan_nr]);
466 return 0;
467}
468
469int IPCDevice::ipc_chan_rx(uint8_t msg_type, struct ipc_sk_chan_if *ipc_prim, uint8_t chan_nr)
470{
471 int rc = 0;
472
473 switch (msg_type) {
474 case IPC_IF_MSG_START_CNF:
475 rc = ipc_rx_chan_start_cnf(&ipc_prim->u.start_cnf, chan_nr);
476 break;
477 case IPC_IF_MSG_STOP_CNF:
478 rc = ipc_rx_chan_stop_cnf(&ipc_prim->u.stop_cnf, chan_nr);
479 break;
480 case IPC_IF_MSG_SETGAIN_CNF:
481 rc = ipc_rx_chan_setgain_cnf(&ipc_prim->u.set_gain_cnf, chan_nr);
482 break;
483 case IPC_IF_MSG_SETFREQ_CNF:
484 rc = ipc_rx_chan_setfreq_cnf(&ipc_prim->u.set_freq_cnf, chan_nr);
485 break;
486 case IPC_IF_NOTIFY_UNDERFLOW:
487 rc = ipc_rx_chan_notify_underflow(&ipc_prim->u.notify, chan_nr);
488 break;
489 case IPC_IF_NOTIFY_OVERFLOW:
490 rc = ipc_rx_chan_notify_overflow(&ipc_prim->u.notify, chan_nr);
491 break;
492 case IPC_IF_MSG_SETTXATTN_CNF:
493 rc = ipc_rx_chan_settxattn_cnf(&ipc_prim->u.txatten_cnf, chan_nr);
494 break;
495 default:
496 LOGP(DMAIN, LOGL_ERROR, "Received unknown IPC msg type %d\n", msg_type);
497 rc = -EINVAL;
498 }
499
500 return rc;
501}
502
503static int ipc_sock_send(struct ipc_per_trx_sock_state *state, struct msgb *msg)
504{
505 struct osmo_fd *conn_bfd;
506
507 if (!state) {
508 LOGP(DMAIN, LOGL_INFO,
509 "IPC socket not created, "
510 "dropping message\n");
511 msgb_free(msg);
512 return -EINVAL;
513 }
514 conn_bfd = &state->conn_bfd;
515 if (conn_bfd->fd <= 0) {
516 LOGP(DMAIN, LOGL_NOTICE,
517 "IPC socket not connected, "
518 "dropping message\n");
519 msgb_free(msg);
520 return -EIO;
521 }
522 msgb_enqueue(&state->upqueue, msg);
Harald Welte94def472020-10-19 12:28:26 +0200523 osmo_fd_write_enable(conn_bfd);
Eric Wild1e17c4f2020-03-24 17:19:27 +0100524
525 return 0;
526}
527
528void IPCDevice::ipc_sock_close(struct ipc_per_trx_sock_state *state)
529{
530 if (state == 0)
531 return;
532
533 struct osmo_fd *bfd = &state->conn_bfd;
534
535 if (bfd->fd <= 0)
536 return;
537
538 LOGP(DDEV, LOGL_NOTICE, "IPC socket has LOST connection\n");
539
540 close(bfd->fd);
541 bfd->fd = -1;
542 osmo_fd_unregister(bfd);
543
544 /* flush the queue */
545 while (!llist_empty(&state->upqueue)) {
546 struct msgb *msg = msgb_dequeue(&state->upqueue);
547 msgb_free(msg);
548 }
549}
550
551int IPCDevice::ipc_sock_read(struct osmo_fd *bfd)
552{
553 struct ipc_sk_if *ipc_prim;
554 struct msgb *msg;
555 int rc;
556
557 msg = msgb_alloc(sizeof(*ipc_prim) + 1000, "ipc_sock_rx");
558 if (!msg)
559 return -ENOMEM;
560
561 ipc_prim = (struct ipc_sk_if *)msg->tail;
562
563 rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0);
564 if (rc == 0)
565 goto close;
566
567 if (rc < 0) {
568 if (errno == EAGAIN) {
569 msgb_free(msg);
570 return 0;
571 }
572 goto close;
573 }
574
575 if ((size_t)rc < sizeof(*ipc_prim)) {
576 LOGP(DDEV, LOGL_ERROR,
577 "Received %d bytes on Unix Socket, but primitive size "
578 "is %zu, discarding\n",
579 rc, sizeof(*ipc_prim));
580 msgb_free(msg);
581 return 0;
582 }
583
584 rc = ipc_rx(ipc_prim->msg_type, ipc_prim);
585
586 /* as we always synchronously process the message in IPC_rx() and
587 * its callbacks, we can free the message here. */
588 msgb_free(msg);
589
590 return rc;
591
592close:
593 msgb_free(msg);
594 ipc_sock_close(&master_sk_state);
595 return -1;
596}
597
598int IPCDevice::ipc_chan_sock_read(struct osmo_fd *bfd)
599{
600 struct ipc_sk_chan_if *ipc_prim;
601 struct msgb *msg;
602 int rc;
603
604 msg = msgb_alloc(sizeof(*ipc_prim) + 1000, "ipc_chan_sock_rx");
605 if (!msg)
606 return -ENOMEM;
607
608 ipc_prim = (struct ipc_sk_chan_if *)msg->tail;
609
610 rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0);
611 if (rc == 0)
612 goto close;
613
614 if (rc < 0) {
615 if (errno == EAGAIN) {
616 msgb_free(msg);
617 return 0;
618 }
619 goto close;
620 }
621
622 if ((size_t)rc < sizeof(*ipc_prim)) {
623 LOGP(DDEV, LOGL_ERROR,
624 "Received %d bytes on Unix Socket, but primitive size "
625 "is %zu, discarding\n",
626 rc, sizeof(*ipc_prim));
627 msgb_free(msg);
628 return 0;
629 }
630
631 /* store mask of last received messages so we can check later */
632 sk_chan_state[bfd->priv_nr].messages_processed_mask |= (1 << (ipc_prim->msg_type - IPC_IF_CHAN_MSG_OFFSET));
633
634 rc = ipc_chan_rx(ipc_prim->msg_type, ipc_prim, bfd->priv_nr);
635
636 /* as we always synchronously process the message in IPC_rx() and
637 * its callbacks, we can free the message here. */
638 msgb_free(msg);
639
640 return rc;
641
642close:
643 msgb_free(msg);
644 ipc_sock_close(&sk_chan_state[bfd->priv_nr]);
645 return -1;
646}
647
648int IPCDevice::ipc_sock_write(struct osmo_fd *bfd)
649{
650 int rc;
651
652 while (!llist_empty(&master_sk_state.upqueue)) {
653 struct msgb *msg, *msg2;
654 struct ipc_sk_if *ipc_prim;
655
656 /* peek at the beginning of the queue */
657 msg = llist_entry(master_sk_state.upqueue.next, struct msgb, list);
658 ipc_prim = (struct ipc_sk_if *)msg->data;
659
Harald Welte94def472020-10-19 12:28:26 +0200660 osmo_fd_write_disable(bfd);
Eric Wild1e17c4f2020-03-24 17:19:27 +0100661
662 /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
663 if (!msgb_length(msg)) {
664 LOGP(DDEV, LOGL_ERROR,
665 "message type (%d) with ZERO "
666 "bytes!\n",
667 ipc_prim->msg_type);
668 goto dontsend;
669 }
670
671 /* try to send it over the socket */
672 rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
673 if (rc == 0)
674 goto close;
675 if (rc < 0) {
676 if (errno == EAGAIN) {
Harald Welte94def472020-10-19 12:28:26 +0200677 osmo_fd_write_enable(bfd);
Eric Wild1e17c4f2020-03-24 17:19:27 +0100678 break;
679 }
680 goto close;
681 }
682
683 dontsend:
684 /* _after_ we send it, we can deueue */
685 msg2 = msgb_dequeue(&master_sk_state.upqueue);
686 assert(msg == msg2);
687 msgb_free(msg);
688 }
689 return 0;
690
691close:
692 ipc_sock_close(&master_sk_state);
693 return -1;
694}
695
696int IPCDevice::ipc_chan_sock_write(struct osmo_fd *bfd)
697{
698 int rc;
699
700 while (!llist_empty(&sk_chan_state[bfd->priv_nr].upqueue)) {
701 struct msgb *msg, *msg2;
702 struct ipc_sk_chan_if *ipc_prim;
703
704 /* peek at the beginning of the queue */
705 msg = llist_entry(sk_chan_state[bfd->priv_nr].upqueue.next, struct msgb, list);
706 ipc_prim = (struct ipc_sk_chan_if *)msg->data;
Harald Welte94def472020-10-19 12:28:26 +0200707 osmo_fd_write_disable(bfd);
Eric Wild1e17c4f2020-03-24 17:19:27 +0100708 /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
709 if (!msgb_length(msg)) {
710 LOGP(DDEV, LOGL_ERROR,
711 "message type (%d) with ZERO "
712 "bytes!\n",
713 ipc_prim->msg_type);
714 goto dontsend;
715 }
716
717 /* try to send it over the socket */
718 rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
719 if (rc == 0)
720 goto close;
721 if (rc < 0) {
722 if (errno == EAGAIN) {
Harald Welte94def472020-10-19 12:28:26 +0200723 osmo_fd_write_enable(bfd);
Eric Wild1e17c4f2020-03-24 17:19:27 +0100724 break;
725 }
726 goto close;
727 }
728
729 dontsend:
730 /* _after_ we send it, we can dequeue */
731 msg2 = msgb_dequeue(&sk_chan_state[bfd->priv_nr].upqueue);
732 assert(msg == msg2);
733 msgb_free(msg);
734 }
735 return 0;
736
737close:
738 ipc_sock_close(&sk_chan_state[bfd->priv_nr]);
739 return -1;
740}
741
742static int ipc_sock_cb(struct osmo_fd *bfd, unsigned int flags)
743{
744 IPCDevice *device = static_cast<IPCDevice *>(bfd->data);
745 int rc = 0;
746
Harald Welte08970c52020-10-18 22:41:40 +0200747 if (flags & OSMO_FD_READ)
Eric Wild1e17c4f2020-03-24 17:19:27 +0100748 rc = device->ipc_sock_read(bfd);
749 if (rc < 0)
750 return rc;
751
Harald Welte08970c52020-10-18 22:41:40 +0200752 if (flags & OSMO_FD_WRITE)
Eric Wild1e17c4f2020-03-24 17:19:27 +0100753 rc = device->ipc_sock_write(bfd);
754
755 return rc;
756}
757
758static int ipc_chan_sock_cb(struct osmo_fd *bfd, unsigned int flags)
759{
760 IPCDevice *device = static_cast<IPCDevice *>(bfd->data);
761 int rc = 0;
762
Harald Welte08970c52020-10-18 22:41:40 +0200763 if (flags & OSMO_FD_READ)
Eric Wild1e17c4f2020-03-24 17:19:27 +0100764 rc = device->ipc_chan_sock_read(bfd);
765 if (rc < 0)
766 return rc;
767
Harald Welte08970c52020-10-18 22:41:40 +0200768 if (flags & OSMO_FD_WRITE)
Eric Wild1e17c4f2020-03-24 17:19:27 +0100769 rc = device->ipc_chan_sock_write(bfd);
770
771 return rc;
772}
773
774int IPCDevice::open(const std::string &args, int ref, bool swap_channels)
775{
776 std::string k, v;
777 std::string::size_type keyend;
778 int rc;
779
780 if ((keyend = args.find('=')) != std::string::npos) {
781 k = args.substr(0, keyend++);
782 v = args.substr(keyend);
783 }
784 if (k != "ipc_msock" || !v.length()) {
785 LOGC(DDEV, ERROR) << "Invalid device args provided, expected \"dev-args ipc_msock=/path/to/socket\"\n";
786 return -1;
787 }
788
789 LOGC(DDEV, INFO) << "Opening IPC device" << v << "..";
790
791 INIT_LLIST_HEAD(&master_sk_state.upqueue);
792 rc = osmo_sock_unix_init_ofd(&master_sk_state.conn_bfd, SOCK_SEQPACKET, 0, v.c_str(), OSMO_SOCK_F_CONNECT);
793 if (rc < 0) {
Pau Espin Pedrol7e83f182020-12-07 19:28:44 +0100794 LOGC(DDEV, ERROR) << "Failed to connect to the IPC device (" << v << "). "
Eric Wild1e17c4f2020-03-24 17:19:27 +0100795 << "Retrying...\n";
796 osmo_timer_setup(&master_sk_state.timer, ipc_sock_timeout, NULL);
797 osmo_timer_schedule(&master_sk_state.timer, 5, 0);
798 return -1;
799 }
800 master_sk_state.conn_bfd.cb = ipc_sock_cb;
801 master_sk_state.conn_bfd.data = this;
802
803 ipc_tx_greeting_req(&master_sk_state, IPC_SOCK_API_VERSION);
804 /* Wait until confirmation is recieved */
805 while (tmp_state != IPC_IF_MSG_GREETING_CNF)
806 osmo_select_main(0);
807
808 ipc_tx_info_req(&master_sk_state);
809 /* Wait until confirmation is recieved */
810 while (tmp_state != IPC_IF_MSG_INFO_CNF)
811 osmo_select_main(0);
812
813 ipc_tx_open_req(&master_sk_state, chans, ref);
814 /* Wait until confirmation is recieved */
815 while (tmp_state != IPC_IF_MSG_OPEN_CNF)
816 osmo_select_main(0);
817 LOGC(DDEV, NOTICE) << "Device driver opened successfuly!";
818
819 /* configure antennas */
820 if (!set_antennas()) {
821 LOGC(DDEV, FATAL) << "IPC antenna setting failed";
822 goto out_close;
823 }
824
825 return iface == MULTI_ARFCN ? MULTI_ARFCN : NORMAL;
826
827out_close:
828 LOGC(DDEV, FATAL) << "Error in IPC open, closing";
829 return -1;
830}
831
832void IPCDevice::manually_poll_sock_fds()
833{
834 struct timeval wait = { 0, 100000 };
835 fd_set crfds, cwfds;
Vadim Yanitskiya6862772021-10-24 22:47:50 +0300836 char err_buf[256];
Eric Wild1e17c4f2020-03-24 17:19:27 +0100837 int max_fd = 0;
838
839 FD_ZERO(&crfds);
840 FD_ZERO(&cwfds);
841 for (unsigned int i = 0; i < chans; i++) {
842 struct osmo_fd *curr_fd = &sk_chan_state[i].conn_bfd;
843 max_fd = curr_fd->fd > max_fd ? curr_fd->fd : max_fd;
844
845 if (curr_fd->when & OSMO_FD_READ)
846 FD_SET(curr_fd->fd, &crfds);
847 if (curr_fd->when & OSMO_FD_WRITE)
848 FD_SET(curr_fd->fd, &cwfds);
849 }
850
Vadim Yanitskiya6862772021-10-24 22:47:50 +0300851 if (select(max_fd + 1, &crfds, &cwfds, 0, &wait) < 0) {
852 LOGP(DDEV, LOGL_ERROR, "select() failed: %s\n",
853 strerror_r(errno, err_buf, sizeof(err_buf)));
854 return;
855 }
Eric Wild1e17c4f2020-03-24 17:19:27 +0100856
857 for (unsigned int i = 0; i < chans; i++) {
858 int flags = 0;
859 struct osmo_fd *ofd = &sk_chan_state[i].conn_bfd;
860
861 if (FD_ISSET(ofd->fd, &crfds)) {
862 flags |= OSMO_FD_READ;
863 FD_CLR(ofd->fd, &crfds);
864 }
865
866 if (FD_ISSET(ofd->fd, &cwfds)) {
867 flags |= OSMO_FD_WRITE;
868 FD_CLR(ofd->fd, &cwfds);
869 }
870 if (flags)
871 ipc_chan_sock_cb(ofd, flags);
872 }
873}
874
875bool IPCDevice::send_chan_wait_rsp(uint32_t chan, struct msgb *msg_to_send, uint32_t expected_rsp_msg_id)
876{
877 struct timeval timer_now, timeout;
878
879 sk_chan_state[chan].messages_processed_mask = 0;
880 ipc_sock_send(&sk_chan_state[chan], msg_to_send);
881
882 gettimeofday(&timeout, 0);
883 timeout.tv_sec += 2;
884
885 while (!(sk_chan_state[chan].messages_processed_mask & (1 << (expected_rsp_msg_id - IPC_IF_CHAN_MSG_OFFSET)))) {
886 /* just poll here, we're already in select, so there is no other way to drive
887 * the fds and "wait" for a response or retry */
888 manually_poll_sock_fds();
889
890 gettimeofday(&timer_now, 0);
891 if (timercmp(&timer_now, &timeout, >))
892 return false;
893 }
894 return true;
895}
896
897bool IPCDevice::send_all_chan_wait_rsp(uint32_t msgid_to_send, uint32_t msgid_to_expect)
898{
899 struct msgb *msg;
900 struct ipc_sk_chan_if *ipc_prim;
901 struct timeval timer_now, timeout;
902
903 for (unsigned int i = 0; i < chans; i++) {
904 msg = ipc_msgb_alloc(msgid_to_send);
905 if (!msg)
906 return -ENOMEM;
907 ipc_prim = (struct ipc_sk_chan_if *)msg->data;
908 ipc_prim->u.start_req.dummy = 0;
909
910 sk_chan_state[i].messages_processed_mask = 0;
911 ipc_sock_send(&sk_chan_state[i], msg);
912 }
913
914 gettimeofday(&timeout, 0);
915 timeout.tv_sec += 2;
916
917 unsigned int msg_received_count = 0;
918 while (msg_received_count != chans) {
919 msg_received_count = 0;
920
921 /* just poll here, we're already in select, so there is no other way to drive
922 * the fds and "wait" for a response or retry */
923 manually_poll_sock_fds();
924
925 for (unsigned int i = 0; i < sk_chan_state.size(); i++)
926 if (sk_chan_state[i].messages_processed_mask &
927 (1 << (msgid_to_expect - IPC_IF_CHAN_MSG_OFFSET)))
928 msg_received_count++;
929
930 gettimeofday(&timer_now, 0);
931 if (timercmp(&timer_now, &timeout, >))
932 return false;
933 }
934
935 return true;
936}
937
938/* the call stack is rather difficult here, we're already in select:
939>~"#0 IPCDevice::start (this=<optimized out>) at IPCDevice.cpp:789\n"
940>~"#1 in RadioInterface::start (this=0x614000001640) at radioInterface.cpp:187\n"
941>~"#2 in Transceiver::start (this=<optimized out>) at Transceiver.cpp:293\n"
942>~"#3 in Transceiver::ctrl_sock_handle_rx (this=0x61600000b180, chan=0) at Transceiver.cpp:838\n"
943>~"#4 in Transceiver::ctrl_sock_cb (bfd=<optimized out>, flags=1) at Transceiver.cpp:168\n"
944>~"#5 in osmo_fd_disp_fds (_rset=<optimized out>, _wset=<optimized out>, _eset=<optimized out>) at select.c:227\n"
945>~"#6 _osmo_select_main (polling=<optimized out>) at select.c:265\n"
946>~"#7 in osmo_select_main (polling=128) at select.c:274\n"
947>~"#8 in main (argc=<optimized out>, argv=<optimized out>) at osmo-trx.cpp:649\n"
948 * */
949bool IPCDevice::start()
950{
951 LOGC(DDEV, INFO) << "starting IPC...";
952
953 if (started) {
954 LOGC(DDEV, ERR) << "Device already started";
955 return true;
956 }
957
958 if (!(send_all_chan_wait_rsp(IPC_IF_MSG_START_REQ, IPC_IF_MSG_START_CNF))) {
959 LOGC(DDEV, ERR) << "start timeout!";
960 return false;
961 }
962
963 int max_bufs_to_flush = 0;
964 for (unsigned int i = 0; i < shm_dec->num_chans; i++) {
965 int buf_per_chan = shm_dec->channels[i]->ul_stream->num_buffers;
966 max_bufs_to_flush = max_bufs_to_flush < buf_per_chan ? buf_per_chan : max_bufs_to_flush;
967 }
968 flush_recv(max_bufs_to_flush);
969
970 started = true;
971 return true;
972}
973
974bool IPCDevice::stop()
975{
976 if (!started)
977 return true;
978
979 if (!(send_all_chan_wait_rsp(IPC_IF_MSG_STOP_REQ, IPC_IF_MSG_STOP_CNF))) {
980 LOGC(DDEV, ERR) << "stop timeout!";
981 return false;
982 }
983
984 LOGC(DDEV, NOTICE) << "All channels stopped, terminating...";
985
Eric4080eb72020-07-16 18:08:30 +0200986 /* reset internal buffer timestamps */
987 for (size_t i = 0; i < rx_buffers.size(); i++)
988 rx_buffers[i]->reset();
989
Eric Wild1e17c4f2020-03-24 17:19:27 +0100990 started = false;
991 return true;
992}
993
994double IPCDevice::maxRxGain()
995{
996 return current_info_cnf.chan_info[0].max_rx_gain;
997}
998
999double IPCDevice::minRxGain()
1000{
1001 return current_info_cnf.chan_info[0].min_rx_gain;
1002}
1003
1004int IPCDevice::getNominalTxPower(size_t chan)
1005{
1006 return current_info_cnf.chan_info[chan].nominal_tx_power;
1007}
1008
1009double IPCDevice::setPowerAttenuation(int atten, size_t chan)
1010{
1011 struct msgb *msg;
1012 struct ipc_sk_chan_if *ipc_prim;
1013
1014 if (chan >= chans)
1015 return 0;
1016
1017 LOGCHAN(chan, DDEV, NOTICE) << "Setting TX attenuation to " << atten << " dB"
1018 << " chan " << chan;
1019
1020 msg = ipc_msgb_alloc(IPC_IF_MSG_SETTXATTN_REQ);
1021 if (!msg)
1022 return -ENOMEM;
1023 ipc_prim = (struct ipc_sk_chan_if *)msg->data;
1024 ipc_prim->u.txatten_req.attenuation = atten;
1025
1026 if (!send_chan_wait_rsp(chan, msg, IPC_IF_MSG_SETTXATTN_CNF))
1027 LOGCHAN(chan, DDEV, ERROR) << "Setting TX attenuation timeout! ";
1028
1029 return atten;
1030}
1031
1032double IPCDevice::getPowerAttenuation(size_t chan)
1033{
1034 if (chan >= chans)
1035 return 0;
1036
1037 return tx_attenuation[chan];
1038}
1039
1040double IPCDevice::setRxGain(double dB, size_t chan)
1041{
1042 struct msgb *msg;
1043 struct ipc_sk_chan_if *ipc_prim;
1044
1045 if (dB > maxRxGain())
1046 dB = maxRxGain();
1047 if (dB < minRxGain())
1048 dB = minRxGain();
1049
1050 LOGCHAN(chan, DDEV, NOTICE) << "Setting RX gain to " << dB << " dB";
1051
1052 msg = ipc_msgb_alloc(IPC_IF_MSG_SETGAIN_REQ);
1053 if (!msg)
1054 return -ENOMEM;
1055 ipc_prim = (struct ipc_sk_chan_if *)msg->data;
1056 ipc_prim->u.set_gain_req.is_tx = 0;
1057 ipc_prim->u.set_gain_req.gain = dB;
1058
1059 if (!send_chan_wait_rsp(chan, msg, IPC_IF_MSG_SETGAIN_CNF))
1060 LOGCHAN(chan, DDEV, ERROR) << "Setting RX gain timeout! ";
1061
1062 return rx_gains[chan];
1063}
1064
1065bool IPCDevice::flush_recv(size_t num_pkts)
1066{
1067 std::vector<uint16_t> tmp(4096);
1068 uint64_t tmps;
1069 uint32_t read = 0;
1070
1071 for (uint32_t j = 0; j < num_pkts; j++) {
1072 for (unsigned int i = 0; i < chans; i++)
1073 read = ipc_shm_read(shm_io_rx_streams[i], (uint16_t *)&tmp.front(), 4096 / 2, &tmps, 3);
1074 }
1075 ts_initial = tmps + read;
1076
1077 LOGC(DDEV, INFO) << "Initial timestamp " << ts_initial << std::endl;
1078 return true;
1079}
1080
1081bool IPCDevice::setRxAntenna(const std::string &ant, size_t chan)
1082{
1083 return true;
1084}
1085
1086std::string IPCDevice::getRxAntenna(size_t chan)
1087{
1088 return "";
1089}
1090
1091bool IPCDevice::setTxAntenna(const std::string &ant, size_t chan)
1092{
1093 return true;
1094}
1095
1096std::string IPCDevice::getTxAntenna(size_t chan)
1097{
1098 return "";
1099}
1100
1101bool IPCDevice::requiresRadioAlign()
1102{
1103 return false;
1104}
1105
1106GSM::Time IPCDevice::minLatency()
1107{
1108 /* UNUSED */
1109 return GSM::Time(0, 0);
1110}
1111
1112/** Returns the starting write Timestamp*/
1113TIMESTAMP IPCDevice::initialWriteTimestamp(void)
1114{
1115 return ts_initial;
1116}
1117
1118/** Returns the starting read Timestamp*/
1119TIMESTAMP IPCDevice::initialReadTimestamp(void)
1120{
1121 return ts_initial;
1122}
1123
1124// NOTE: Assumes sequential reads
1125int IPCDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun, TIMESTAMP timestamp, bool *underrun)
1126{
1127 int rc, num_smpls; //, expect_smpls;
1128 ssize_t avail_smpls;
1129 TIMESTAMP expect_timestamp;
1130 unsigned int i;
1131
1132 if (bufs.size() != chans) {
1133 LOGC(DDEV, ERROR) << "Invalid channel combination " << bufs.size();
1134 return -1;
1135 }
1136
1137 *overrun = false;
1138 *underrun = false;
1139
1140 timestamp += current_open_cnf.path_delay;
1141
1142 /* Check that timestamp is valid */
1143 rc = rx_buffers[0]->avail_smpls(timestamp);
1144 if (rc < 0) {
1145 LOGC(DDEV, ERROR) << rx_buffers[0]->str_code(rc);
1146 LOGC(DDEV, ERROR) << rx_buffers[0]->str_status(timestamp);
1147 return 0;
1148 }
1149
1150 for (i = 0; i < chans; i++) {
1151 /* Receive samples from HW until we have enough */
1152 while ((avail_smpls = rx_buffers[i]->avail_smpls(timestamp)) < len) {
1153 uint64_t recv_timestamp = 0;
1154
1155 thread_enable_cancel(false);
1156 num_smpls = ipc_shm_read(shm_io_rx_streams[i], (uint16_t *)bufs[i], len - avail_smpls,
1157 &recv_timestamp, 1);
1158 expect_timestamp = timestamp + avail_smpls;
1159 thread_enable_cancel(true);
1160
1161 if (num_smpls == -ETIMEDOUT)
1162 continue;
1163
1164 LOGCHAN(i, DDEV, DEBUG)
1165 "Received timestamp = " << (TIMESTAMP)recv_timestamp << " (" << num_smpls << ")";
1166
1167 if (expect_timestamp != (TIMESTAMP)recv_timestamp)
1168 LOGCHAN(i, DDEV, ERROR) << "Unexpected recv buffer timestamp: expect "
1169 << expect_timestamp << " got " << recv_timestamp << ", diff="
1170 << ((uint64_t)recv_timestamp > expect_timestamp ?
1171 (uint64_t)recv_timestamp - expect_timestamp :
1172 expect_timestamp - recv_timestamp);
1173
1174 rc = rx_buffers[i]->write(bufs[i], num_smpls, (TIMESTAMP)recv_timestamp);
1175 if (rc < 0) {
1176 LOGCHAN(i, DDEV, ERROR)
1177 << rx_buffers[i]->str_code(rc) << " num smpls: " << num_smpls << " chan: " << i;
1178 LOGCHAN(i, DDEV, ERROR) << rx_buffers[i]->str_status(timestamp);
1179 if (rc != smpl_buf::ERROR_OVERFLOW)
1180 return 0;
1181 }
1182 }
1183 }
1184
1185 /* We have enough samples */
1186 for (size_t i = 0; i < rx_buffers.size(); i++) {
1187 rc = rx_buffers[i]->read(bufs[i], len, timestamp);
1188 if ((rc < 0) || (rc != len)) {
1189 LOGCHAN(i, DDEV, ERROR) << rx_buffers[i]->str_code(rc) << ". "
1190 << rx_buffers[i]->str_status(timestamp) << ", (len=" << len << ")";
1191 return 0;
1192 }
1193 }
1194
1195 return len;
1196}
1197
1198int IPCDevice::writeSamples(std::vector<short *> &bufs, int len, bool *underrun, unsigned long long timestamp)
1199{
1200 int rc = 0;
1201 unsigned int i;
1202
1203 if (bufs.size() != chans) {
1204 LOGC(DDEV, ERROR) << "Invalid channel combination " << bufs.size();
1205 return -1;
1206 }
1207
1208 *underrun = false;
1209
1210 for (i = 0; i < chans; i++) {
1211 LOGCHAN(i, DDEV, DEBUG) << "send buffer of len " << len << " timestamp " << std::hex << timestamp;
1212 thread_enable_cancel(false);
1213 rc = ipc_shm_enqueue(shm_io_tx_streams[i], timestamp, len, (uint16_t *)bufs[i]);
1214 thread_enable_cancel(true);
1215
1216 if (rc != len) {
1217 LOGCHAN(i, DDEV, ERROR) << "LMS: Device Tx timed out (" << rc << " vs exp " << len << ").";
1218 return -1;
1219 }
1220 }
1221
1222 return rc;
1223}
1224
1225bool IPCDevice::updateAlignment(TIMESTAMP timestamp)
1226{
1227 return true;
1228}
1229
1230bool IPCDevice::setTxFreq(double wFreq, size_t chan)
1231{
1232 struct msgb *msg;
1233 struct ipc_sk_chan_if *ipc_prim;
1234 LOGCHAN(chan, DDEV, NOTICE) << "Setting Tx Freq to " << wFreq << " Hz";
1235
1236 msg = ipc_msgb_alloc(IPC_IF_MSG_SETFREQ_REQ);
1237 if (!msg)
1238 return -ENOMEM;
1239 ipc_prim = (struct ipc_sk_chan_if *)msg->data;
1240 ipc_prim->u.set_freq_req.is_tx = 1;
1241 ipc_prim->u.set_freq_req.freq = wFreq;
1242
1243 return send_chan_wait_rsp(chan, msg, IPC_IF_MSG_SETFREQ_CNF);
1244}
1245
1246bool IPCDevice::setRxFreq(double wFreq, size_t chan)
1247{
1248 struct msgb *msg;
1249 struct ipc_sk_chan_if *ipc_prim;
1250 LOGCHAN(chan, DDEV, NOTICE) << "Setting Rx Freq to " << wFreq << " Hz";
1251
1252 msg = ipc_msgb_alloc(IPC_IF_MSG_SETFREQ_REQ);
1253 if (!msg)
1254 return -ENOMEM;
1255 ipc_prim = (struct ipc_sk_chan_if *)msg->data;
1256 ipc_prim->u.set_freq_req.is_tx = 0;
1257 ipc_prim->u.set_freq_req.freq = wFreq;
1258
1259 return send_chan_wait_rsp(chan, msg, IPC_IF_MSG_SETFREQ_CNF);
1260}
1261
1262RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chans, double lo_offset,
1263 const std::vector<std::string> &tx_paths, const std::vector<std::string> &rx_paths)
1264{
1265 if (tx_sps != rx_sps) {
1266 LOGC(DDEV, ERROR) << "IPC Requires tx_sps == rx_sps";
1267 return NULL;
1268 }
1269 if (lo_offset != 0.0) {
1270 LOGC(DDEV, ERROR) << "IPC doesn't support lo_offset";
1271 return NULL;
1272 }
1273 return new IPCDevice(tx_sps, rx_sps, iface, chans, lo_offset, tx_paths, rx_paths);
1274}