SoDaRadio-5.0.3-master:8901fb5
USRPRX.cxx
Go to the documentation of this file.
1 /*
2  Copyright (c) 2012, Matthew H. Reilly (kb1vc)
3  All rights reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are
7  met:
8 
9  Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11  Redistributions in binary form must reproduce the above copyright
12  notice, this list of conditions and the following disclaimer in
13  the documentation and/or other materials provided with the
14  distribution.
15 
16  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include "USRPRX.hxx"
30 #include "QuadratureOscillator.hxx"
31 
32 #include <uhd/utils/safe_main.hpp>
33 #include <uhd/utils/thread_priority.hpp>
34 #include <uhd/usrp/multi_usrp.hpp>
35 #include <fftw3.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 
40 #include <fstream>
41 
42 SoDa::USRPRX::USRPRX(Params * params, uhd::usrp::multi_usrp::sptr _usrp,
43  DatMBox * _rx_stream, DatMBox * _if_stream,
44  CmdMBox * _cmd_stream) : SoDa::SoDaThread("USRPRX")
45 {
46  cmd_stream = _cmd_stream;
47  rx_stream = _rx_stream;
48  if_stream = _if_stream;
49 
50  usrp = _usrp;
51 
52  // subscribe to the command stream.
54 
55  // create the rx buffer streamers.
56  uhd::stream_args_t stream_args("fc32", "sc16");
57  std::vector<size_t> channel_nums;
58  channel_nums.push_back(0);
59  stream_args.channels = channel_nums;
60  rx_bits = usrp->get_rx_stream(stream_args);
61 
62  usrp->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
63 
64  // no UI listening for spectrum dumps yet.
65  ui = NULL;
66 
67  rx_sample_rate = params->getRXRate();
68  rx_buffer_size = params->getRFBufferSize();
69 
70  // we aren't receiving yet.
72 
73  // wake up in USB mode
75 
76  // setup debug hooks
77  // outf[0] = creat("RF_premix.dat", 0666);
78  // outf[1] = creat("RF_postmix.dat", 0666);
79  scount = 0;
80 
81  // enable spectrum reporting at startup
82  enable_spectrum_report = true;
83 
84 #if 0
85  rf_dumpfile.open("RFDump.dat", std::ios::out | std::ios::binary);
86  if_dumpfile.open("IFDump.dat", std::ios::out | std::ios::binary);
87 #endif
88 }
89 
90 static void doFFTandDump(int fd, std::complex<float> * in, int len) __attribute__ ((unused));
91 
92 static void doFFTandDump(int fd, std::complex<float> * in, int len)
93 {
94  std::complex<float> out[len];
95  // create plan
96  fftwf_plan tplan = fftwf_plan_dft_1d(len, (fftwf_complex*) in, (fftwf_complex*) out,
97  FFTW_FORWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
98 
99  fftwf_execute(tplan);
100  write(fd, out, sizeof(std::complex<float>) * len);
101  fftwf_destroy_plan(tplan);
102 }
103 
105 {
106  uhd::set_thread_priority_safe();
107  // now do the event loop. we watch
108  // for commands and responses on the command stream.
109  // and we watch for data in the input buffer.
110 
111  bool exitflag = false;
112 
113  while(!exitflag) {
114  Command * cmd = cmd_stream->get(cmd_subs);
115  if(cmd != NULL) {
116  // std::cerr << "\n\nIn RX loop got command\n\n" << std::endl;
117  // process the command.
118  execCommand(cmd);
119  exitflag |= (cmd->target == Command::STOP);
120  cmd_stream->free(cmd);
121  }
122  else if(audio_rx_stream_enabled) {
123  // go get some data
124  // get a free buffer.
125  SoDaBuf * buf = rx_stream->alloc();
126  if(buf == NULL) {
127  buf = new SoDaBuf(rx_buffer_size);
128  }
129 
130  if(buf == NULL) throw(new SoDa::SoDaException("USRPRX couldn't allocate SoDaBuf object", this));
131  if(buf->getComplexBuf() == NULL) throw(new SoDa::SoDaException("USRPRX allocated empty SoDaBuf object", this));
132 
133  unsigned int left = rx_buffer_size;
134  unsigned int coll_so_far = 0;
135  uhd::rx_metadata_t md;
136  std::complex<float> *dbuf = buf->getComplexBuf();
137  while(left != 0) {
138  unsigned int got = rx_bits->recv(&(dbuf[coll_so_far]), left, md);
139  if(got == 0) {
140  debugMsg("****************************************");
141  debugMsg(boost::format("RECV got error -- md = [%s]\n") % md.to_pp_string());
142  debugMsg("****************************************");
143  }
144  coll_so_far += got;
145  left -= got;
146  }
147 
148  // If the anybody cares, send the IF buffer out.
149  // If the UI is listening, it will do an FFT on the buffer
150  // and send the positive spectrum via the UI to any listener.
151  // the UI does the FFT then puts it on its own ring.
153  // clone a buffer, cause we're going to modify
154  // it before the send is complete.
155  SoDaBuf * if_buf = if_stream->alloc();
156  if(if_buf == NULL) {
157  if_buf = new SoDaBuf(rx_buffer_size);
158  }
159 
160  if(if_buf->copy(buf)) {
161  if_stream->put(if_buf);
162  }
163  else {
164  throw new SoDaException("SoDaBuf Copy for IF stream failed", this);
165  }
166  }
167 
168 
169  // support debug...
170  scount++;
171 
172  // tune it down with the IF oscillator
173  doMixer(buf);
174  // now put the baseband signal on the ring.
175  rx_stream->put(buf);
176 
177  // write the buffer output
178  }
179  else {
180  usleep(1000);
181  }
182  }
183 
184  stopStream();
185 }
186 
188 {
189  unsigned int i;
190  std::complex<float> o;
191  std::complex<float> * ioa = inout->getComplexBuf();
192  for(i = 0; i < inout->getComplexMaxLen(); i++) {
193  o = IF_osc.stepOscCF();
194  ioa[i] = ioa[i] * o;
195  }
196 }
197 
198 void SoDa::USRPRX::set3rdLOFreq(double IF_tuning)
199 {
200  // calculate the advance of phase for the IF
201  // oscilator in terms of radians per sample
202  IF_osc.setPhaseIncr(IF_tuning * 2.0 * M_PI / rx_sample_rate);
203  debugMsg(boost::format("Changed 3rdLO to freq = %g\n") % IF_tuning);
204 }
205 
207 {
208  // std::cerr << "In USRPRX execCommand" << std::endl;
209  switch (cmd->cmd) {
210  case Command::GET:
211  execGetCommand(cmd);
212  break;
213  case Command::SET:
214  execSetCommand(cmd);
215  break;
216  case Command::REP:
217  execRepCommand(cmd);
218  break;
219  default:
220  break;
221  }
222 }
223 
225 {
227  // std::cerr << "Starting RX Stream from USRP" << std::endl;
228  usrp->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS, 0);
229  audio_rx_stream_enabled = true;
230  }
231 }
232 
234 {
235  // std::cerr << "Stoping RX Stream from USRP" << std::endl;
236  usrp->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, 0);
237  audio_rx_stream_enabled = false;
238 }
239 
241 {
242  // std::cerr << "In USRPRX execSetCommand" << std::endl;
243  switch(cmd->target) {
246  break;
248  current_IF_tuning = cmd->dparms[0];
249  set3rdLOFreq(cmd->dparms[0]);
250  break;
251  case SoDa::Command::TX_STATE: // SET TX_ON
252  if(cmd->iparms[0] == 3) {
254  // If we're in a CW mode, set the RF gain to zip.
255  // this is already done in the USRPCtrl thread.
256  // and adjust the AF gain.
257  debugMsg("In TX ON -- stream continues");
258  }
259  else {
260  // Otherwise
261  // stop the RX stream
262  debugMsg("In TX ON -- stopped stream");
263  stopStream();
264  }
265  enable_spectrum_report = false;
266  }
267  if(cmd->iparms[0] == 2) {
268  // start the RX stream.
269  //usleep(750000);
270  debugMsg("In TX OFF -- restart stream");
271  startStream();
272  enable_spectrum_report = true;
273  }
274  break;
275  default:
276  break;
277  }
278 }
279 
281 {
282  (void) cmd;
283 }
284 
286 {
287  (void) cmd;
288 }
289 
void execCommand(Command *cmd)
Definition: USRPRX.cxx:206
void setPhaseIncr(double _pi)
set the phase increment per step for the oscillator (1/freq)
The Thread baseclass for all SoDa thread objects.
Definition: SoDaBase.hxx:284
void doMixer(SoDaBuf *inout)
implement a complex down converter with complex multiplication
Definition: USRPRX.cxx:187
void debugMsg(const std::string &msg, unsigned int threshold=1)
Definition: Debug.hxx:64
USRPRX(Params *params, uhd::usrp::multi_usrp::sptr usrp, DatMBox *_rx_stream, DatMBox *_if_stream, CmdMBox *_cmd_stream)
The constructor.
Definition: USRPRX.cxx:42
turn transmitter on and off.
Definition: Command.hxx:197
T * get(unsigned int subscriber_id)
Definition: MultiMBox.hxx:110
QuadratureOscillator IF_osc
Definition: USRPRX.hxx:107
Set the modulation mode for the receive chain.
Definition: Command.hxx:251
unsigned int cmd_subs
Definition: USRPRX.hxx:90
int iparms[4]
integer parameters
Definition: Command.hxx:668
std::ofstream if_dumpfile
Definition: USRPRX.hxx:119
This class handles command line parameters and built-ins.
Definition: Params.hxx:42
The SoDa Exception class.
Definition: SoDaBase.hxx:217
void execGetCommand(Command *cmd)
optional method to handle "GET" commands – commands that request a response
Definition: USRPRX.cxx:280
uhd::rx_streamer::sptr rx_bits
Definition: USRPRX.hxx:93
unsigned int rx_buffer_size
Definition: USRPRX.hxx:96
CmdTarget target
the thing we&#39;re touching
Definition: Command.hxx:673
SoDa::Command::ModulationType rx_modulation
Definition: USRPRX.hxx:101
std::complex< float > stepOscCF()
step the oscillator and produce a complex float result
CmdMBox * cmd_stream
Definition: USRPRX.hxx:89
bool audio_rx_stream_enabled
Definition: USRPRX.hxx:99
unsigned int getComplexMaxLen()
Return the maximum number of complex float values that this buffer can hold.
Definition: SoDaBase.hxx:103
double getRXRate() const
Sample rates and all that other stuff are fixed.
Definition: Params.hxx:98
The Buffer Class.
Definition: SoDaBase.hxx:72
void run()
USRPRX is a thread – this is its run loop.
Definition: USRPRX.cxx:104
uhd::usrp::multi_usrp::sptr usrp
Definition: USRPRX.hxx:94
unsigned int getRFBufferSize() const
Definition: Params.hxx:105
On receipt of a STOP command, all threads should exit their run loop.
Definition: Command.hxx:371
std::complex< float > * getComplexBuf()
Return a pointer to the storage buffer of complex floats.
Definition: SoDaBase.hxx:133
This is a list of all the commands that can "do something" to one or more components in the SoDa radi...
Definition: Command.hxx:47
bool enable_spectrum_report
Definition: USRPRX.hxx:112
DatMBox * if_stream
Definition: USRPRX.hxx:88
ModulationType
modulation selector targets take one of these values
Definition: Command.hxx:478
void startStream()
Definition: USRPRX.cxx:224
int getSubscriberCount()
Definition: MultiMBox.hxx:95
void execRepCommand(Command *cmd)
optional method that reports status or the result of some action.
Definition: USRPRX.cxx:285
std::ofstream rf_dumpfile
Definition: USRPRX.hxx:118
void free(T *m)
Definition: MultiMBox.hxx:118
double rx_sample_rate
Definition: USRPRX.hxx:109
CmdType cmd
the command type (SET, GET, REP)
Definition: Command.hxx:672
double dparms[4]
double float parameters
Definition: Command.hxx:669
double current_IF_tuning
Definition: USRPRX.hxx:108
void stopStream()
Definition: USRPRX.cxx:233
Tune the 3rd LO (in SoDa::USRPRX).
Definition: Command.hxx:96
DatMBox * rx_stream
Definition: USRPRX.hxx:87
void put(T *m)
Definition: MultiMBox.hxx:97
void set3rdLOFreq(double IF_tuning)
Definition: USRPRX.cxx:198
void execSetCommand(Command *cmd)
optional method to handle "SET" commands – commands that set internal state in the object...
Definition: USRPRX.cxx:240
bool copy(SoDaBuf *src)
Definition: SoDaBase.hxx:89
static void doFFTandDump(int fd, std::complex< float > *in, int len) __attribute__((unused))
Definition: USRPRX.cxx:92