/* * Copyright 2020 sysmocom - s.f.m.c. GmbH * Author: Pau Espin Pedrol * * SPDX-License-Identifier: AGPL-3.0+ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * See the COPYING file in the main directory for details. */ #ifndef _IPC_DEVICE_H_ #define _IPC_DEVICE_H_ #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif extern "C" { #include #include #include "shm.h" } #include "radioDevice.h" class smpl_buf; #define IPC_MAX_NUM_TRX 8 struct ipc_per_trx_sock_state { struct osmo_fd conn_bfd; /* fd for connection to the BTS */ struct osmo_timer_list timer; /* socket connect retry timer */ struct llist_head upqueue; /* queue for sending messages */ uint32_t messages_processed_mask; // (=| IPC_IF_MSG_xxx-IPC_IF_CHAN_MSG_OFFSET) bitmask ipc_per_trx_sock_state() : conn_bfd(), timer(), upqueue(), messages_processed_mask() { conn_bfd.fd = -1; } }; class IPCDevice : public RadioDevice { protected: struct ipc_per_trx_sock_state master_sk_state; std::vector sk_chan_state; uint32_t tx_attenuation[IPC_MAX_NUM_TRX]; uint8_t tmp_state; char shm_name[SHM_NAME_MAX]; int ipc_shm_connect(const char *shm_name); void *shm; struct ipc_shm_region *shm_dec; std::vector rx_buffers; double actualSampleRate; bool started; TIMESTAMP ts_initial, ts_offset; std::vector tx_gains, rx_gains; struct ipc_sk_if_info_req current_info_req; struct ipc_sk_if_info_cnf current_info_cnf; struct ipc_sk_if_open_cnf current_open_cnf; std::vector shm_io_rx_streams; std::vector shm_io_tx_streams; bool flush_recv(size_t num_pkts); void update_stream_stats_rx(size_t chan, bool *overrun); void update_stream_stats_tx(size_t chan, bool *underrun); void manually_poll_sock_fds(); void ipc_sock_close(ipc_per_trx_sock_state *state); int ipc_rx(uint8_t msg_type, struct ipc_sk_if *ipc_prim); int ipc_rx_greeting_cnf(const struct ipc_sk_if_greeting *greeting_cnf); int ipc_rx_info_cnf(const struct ipc_sk_if_info_cnf *info_cnf); int ipc_rx_open_cnf(const struct ipc_sk_if_open_cnf *open_cnf); int ipc_tx_open_req(struct ipc_per_trx_sock_state *state, uint32_t num_chans, uint32_t ref); int ipc_chan_rx(uint8_t msg_type, ipc_sk_chan_if *ipc_prim, uint8_t chan_nr); int ipc_rx_chan_start_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr); int ipc_rx_chan_stop_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr); int ipc_rx_chan_setgain_cnf(ipc_sk_chan_if_gain *ret, uint8_t chan_nr); int ipc_rx_chan_setfreq_cnf(ipc_sk_chan_if_freq_cnf *ret, uint8_t chan_nr); int ipc_rx_chan_notify_underflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr); int ipc_rx_chan_notify_overflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr); int ipc_rx_chan_settxattn_cnf(ipc_sk_chan_if_tx_attenuation *ret, uint8_t chan_nr); bool send_chan_wait_rsp(uint32_t chan, struct msgb *msg_to_send, uint32_t expected_rsp_msg_id); bool send_all_chan_wait_rsp(uint32_t msgid_to_send, uint32_t msgid_to_expect); public: int ipc_sock_read(struct osmo_fd *bfd); int ipc_sock_write(struct osmo_fd *bfd); int ipc_chan_sock_read(osmo_fd *bfd); int ipc_chan_sock_write(osmo_fd *bfd); /** Object constructor */ IPCDevice(InterfaceType iface, const struct trx_cfg *cfg); virtual ~IPCDevice() override; /** Instantiate the IPC */ virtual int open() override; /** Start the IPC */ virtual bool start() override; /** Stop the IPC */ virtual bool stop() override; /* FIXME: any != USRP1 will do for now... */ enum TxWindowType getWindowType() override { return TX_WINDOW_LMS1; } /** Read samples from the IPC. @param buf preallocated buf to contain read result @param len number of samples desired @param overrun Set if read buffer has been overrun, e.g. data not being read fast enough @param timestamp The timestamp of the first samples to be read @param underrun Set if IPC does not have data to transmit, e.g. data not being sent fast enough @return The number of samples actually read */ virtual int readSamples(std::vector &buf, int len, bool *overrun, TIMESTAMP timestamp = 0xffffffff, bool *underrun = NULL) override; /** Write samples to the IPC. @param buf Contains the data to be written. @param len number of samples to write. @param underrun Set if IPC does not have data to transmit, e.g. data not being sent fast enough @param timestamp The timestamp of the first sample of the data buffer. @return The number of samples actually written */ virtual int writeSamples(std::vector &bufs, int len, bool *underrun, TIMESTAMP timestamp = 0xffffffff) override; /** Update the alignment between the read and write timestamps */ virtual bool updateAlignment(TIMESTAMP timestamp) override; /** Set the transmitter frequency */ virtual bool setTxFreq(double wFreq, size_t chan = 0) override; /** Set the receiver frequency */ virtual bool setRxFreq(double wFreq, size_t chan = 0) override; /** Returns the starting write Timestamp*/ virtual TIMESTAMP initialWriteTimestamp(void) override; /** Returns the starting read Timestamp*/ virtual TIMESTAMP initialReadTimestamp(void) override; /** returns the full-scale transmit amplitude **/ virtual double fullScaleInputValue() override { return (double)SHRT_MAX * current_info_cnf.iq_scaling_val_rx; } /** returns the full-scale receive amplitude **/ virtual double fullScaleOutputValue() override { return (double)SHRT_MAX * current_info_cnf.iq_scaling_val_tx; } /** sets the receive chan gain, returns the gain setting **/ virtual double setRxGain(double dB, size_t chan = 0) override; /** get the current receive gain */ virtual double getRxGain(size_t chan = 0) override { return rx_gains[chan]; } /** return maximum Rx Gain **/ virtual double maxRxGain(void) override; /** return minimum Rx Gain **/ virtual double minRxGain(void) override; /* FIXME: return rx_gains[chan] ? receive factor from IPC Driver? */ double rssiOffset(size_t chan) override { return 0.0f; }; double setPowerAttenuation(int atten, size_t chan) override; double getPowerAttenuation(size_t chan = 0) override; virtual int getNominalTxPower(size_t chan = 0) override; /** sets the RX path to use, returns true if successful and false otherwise */ virtual bool setRxAntenna(const std::string &ant, size_t chan = 0) override; /* return the used RX path */ virtual std::string getRxAntenna(size_t chan = 0) override; /** sets the RX path to use, returns true if successful and false otherwise */ virtual bool setTxAntenna(const std::string &ant, size_t chan = 0) override; /* return the used RX path */ virtual std::string getTxAntenna(size_t chan = 0) override; /** return whether user drives synchronization of Tx/Rx of USRP */ virtual bool requiresRadioAlign() override; /** return whether user drives synchronization of Tx/Rx of USRP */ virtual GSM::Time minLatency() override; /** Return internal status values */ virtual inline double getTxFreq(size_t chan = 0) override { return 0; } virtual inline double getRxFreq(size_t chan = 0) override { return 0; } virtual inline double getSampleRate() override { return actualSampleRate; } }; #endif // _IPC_DEVICE_H_