1 /*
2  *    Copyright (C) 2018
3  *    Matthias P. Braendli (matthias.braendli@mpb.li)
4  *
5  *    Copyright (C) 2017
6  *    Albrecht Lohofener (albrechtloh@gmx.de)
7  *
8  *    This file is based on SDR-J
9  *    Copyright (C) 2010, 2011, 2012, 2013
10  *    Jan van Katwijk (J.vanKatwijk@gmail.com)
11  *
12  *    This file is part of the welle.io.
13  *    Many of the ideas as implemented in welle.io are derived from
14  *    other work, made available through the GNU general Public License.
15  *    All copyrights of the original authors are recognized.
16  *
17  *    welle.io is free software; you can redistribute it and/or modify
18  *    it under the terms of the GNU General Public License as published by
19  *    the Free Software Foundation; either version 2 of the License, or
20  *    (at your option) any later version.
21  *
22  *    welle.io is distributed in the hope that it will be useful,
23  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
24  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  *    GNU General Public License for more details.
26  *
27  *    You should have received a copy of the GNU General Public License
28  *    along with welle.io; if not, write to the Free Software
29  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30  *
31  */
32 
33 #include <iostream>
34 #include <sys/time.h>
35 
36 #include "rtl_tcp.h"
37 
38 // For Qt translation if Qt is exisiting
39 #ifdef QT_CORE_LIB
40     #include <QtGlobal>
41 #else
42     #define QT_TRANSLATE_NOOP(x,y) (y)
43 #endif
44 
45 // commands are packed in 5 bytes, one "command byte"
46 // and an integer parameter
47 struct command
48 {
49     unsigned char cmd;
50     unsigned int param;
51 }__attribute__((packed));
52 
53 enum rtlsdr_tuner {
54     RTLSDR_TUNER_UNKNOWN = 0,
55     RTLSDR_TUNER_E4000,
56     RTLSDR_TUNER_FC0012,
57     RTLSDR_TUNER_FC0013,
58     RTLSDR_TUNER_FC2580,
59     RTLSDR_TUNER_R820T,
60     RTLSDR_TUNER_R828D
61 };
62 
63 #define ONE_BYTE 8
64 
getMyTime(void)65 static inline int64_t getMyTime(void)
66 {
67     struct timeval tv;
68 
69     gettimeofday(&tv, NULL);
70     return ((int64_t)tv.tv_sec * 1000000 + (int64_t)tv.tv_usec);
71 }
72 
CRTL_TCP_Client(RadioControllerInterface & radioController)73 CRTL_TCP_Client::CRTL_TCP_Client(RadioControllerInterface& radioController) :
74     radioController(radioController),
75     sampleBuffer(32 * 32768),
76     sampleNetworkBuffer(256 * 32768),
77     spectrumSampleBuffer(8192)
78 {
79     memset(&dongleInfo, 0, sizeof(dongle_info_t));
80     dongleInfo.tuner_type = RTLSDR_TUNER_UNKNOWN;
81 }
82 
~CRTL_TCP_Client(void)83 CRTL_TCP_Client::~CRTL_TCP_Client(void)
84 {
85     std::clog << "RTL_TCP_CLIENT: deleting ..." << std::endl;
86     stop();
87 }
88 
setFrequency(int newFrequency)89 void CRTL_TCP_Client::setFrequency(int newFrequency)
90 {
91     frequency = newFrequency;
92     sendVFO(newFrequency);
93 }
94 
getFrequency() const95 int CRTL_TCP_Client::getFrequency() const
96 {
97     return frequency;
98 }
99 
restart(void)100 bool CRTL_TCP_Client::restart(void)
101 {
102     if (rtlsdrRunning) {
103         return true;
104     }
105 
106     rtlsdrRunning = true;
107 
108     networkBufferThread = std::thread(&CRTL_TCP_Client::networkBufferCopy, this);
109     networkBufferThread.detach();
110 
111     receiveThread = std::thread(&CRTL_TCP_Client::receiveAndReconnect, this);
112     receiveThread.detach();
113 
114     // Wait so that the other thread has a chance to establish the connection
115     std::this_thread::sleep_for(std::chrono::milliseconds(500));
116 
117     std::unique_lock<std::mutex> lock(mutex);
118     return connected;
119 }
120 
is_ok()121 bool CRTL_TCP_Client::is_ok()
122 {
123     return rtlsdrRunning;
124 }
125 
stop(void)126 void CRTL_TCP_Client::stop(void)
127 {
128 #ifdef __ANDROID__
129     // Send TCP_ANDROID_EXIT cmd to explicitly cause the driver to turn off itself
130     sendCommand(0x7e, 0);
131 #endif
132 
133     std::unique_lock<std::mutex> lock(mutex);
134 
135     // Close connection
136     sock.close();
137 
138     agcRunning = false;
139     rtlsdrRunning = false;
140 
141     lock.unlock();
142 
143     if (agcThread.joinable()) {
144         agcThread.join();
145     }
146 
147     if (receiveThread.joinable()) {
148         receiveThread.join();
149     }
150 
151     if (networkBufferThread.joinable()) {
152         networkBufferThread.join();
153     }
154 
155     connected = false;
156 }
157 
read_convert_from_buffer(RingBuffer<uint8_t> & buffer,DSPCOMPLEX * v,int32_t size)158 static int32_t read_convert_from_buffer(
159         RingBuffer<uint8_t>& buffer,
160         DSPCOMPLEX *v, int32_t size)
161 {
162     int32_t amount, i;
163     std::vector<uint8_t> tempBuffer(2 * size);
164 
165     // Get data from the ring buffer
166     amount = buffer.getDataFromBuffer(tempBuffer.data(), 2 * size);
167     for (i = 0; i < amount / 2; i ++)
168         v[i] = DSPCOMPLEX(((float)tempBuffer[2 * i] - 128.0f) / 128.0f,
169                           ((float)tempBuffer[2 * i + 1] - 128.0f) / 128.0f);
170     return amount / 2;
171 }
172 
getSamples(DSPCOMPLEX * v,int32_t size)173 int32_t CRTL_TCP_Client::getSamples(DSPCOMPLEX *v, int32_t size)
174 {
175     return read_convert_from_buffer(sampleBuffer, v, size);
176 }
177 
getSpectrumSamples(int size)178 std::vector<DSPCOMPLEX> CRTL_TCP_Client::getSpectrumSamples(int size)
179 {
180     std::vector<DSPCOMPLEX> buffer(size);
181     int sizeRead = read_convert_from_buffer(spectrumSampleBuffer, buffer.data(), size);
182     if (sizeRead < size) {
183         buffer.resize(sizeRead);
184     }
185     return buffer;
186 }
187 
getSamplesToRead(void)188 int32_t CRTL_TCP_Client::getSamplesToRead(void)
189 {
190     return sampleBuffer.GetRingBufferReadAvailable() / 2;
191 }
192 
reset(void)193 void CRTL_TCP_Client::reset(void)
194 {
195     sampleBuffer.FlushRingBuffer();
196     sampleNetworkBuffer.FlushRingBuffer();
197     spectrumSampleBuffer.FlushRingBuffer();
198     firstFilledNetworkBuffer = false;
199 }
200 
receiveData(void)201 void CRTL_TCP_Client::receiveData(void)
202 {
203     std::vector<uint8_t> buffer(8192);
204 
205     size_t read = 0;
206 
207     while (sock.valid() && read < buffer.size()) {
208         const size_t remain = buffer.size() - read;
209 
210         ssize_t ret = sock.recv(buffer.data() + read, remain, 0);
211 
212         if (ret == 0) {
213             handleDisconnect();
214         }
215         else if (ret == -1) {
216             if (errno == EAGAIN) {
217                 continue;
218             }
219             else if (errno == EINTR) {
220                 continue;
221             }
222             else if (errno == ECONNRESET || errno == EBADF) {
223                 handleDisconnect();
224             }
225             else {
226                 std::string errstr = strerror(errno);
227                 throw std::runtime_error("recv: " + errstr);
228             }
229         }
230         else {
231             read += ret;
232         }
233 
234         if (not rtlsdrRunning) {
235             break;
236         }
237     }
238 
239     if (firstData) {
240         firstData = false;
241 
242         // Get dongle information
243         ::memcpy(&dongleInfo, buffer.data(), sizeof(dongle_info_t));
244 
245         // Convert the byte order
246         dongleInfo.tuner_type = ntohl(dongleInfo.tuner_type);
247         dongleInfo.tuner_gain_count = ntohl(dongleInfo.tuner_gain_count);
248 
249         if(dongleInfo.magic[0] == 'R' &&
250                 dongleInfo.magic[1] == 'T' &&
251                 dongleInfo.magic[2] == 'L' &&
252                 dongleInfo.magic[3] == '0') {
253             std::string TunerType;
254             switch(dongleInfo.tuner_type)
255             {
256                 case RTLSDR_TUNER_UNKNOWN: TunerType = "Unknown"; break;
257                 case RTLSDR_TUNER_E4000: TunerType = "E4000"; break;
258                 case RTLSDR_TUNER_FC0012: TunerType = "FC0012"; break;
259                 case RTLSDR_TUNER_FC0013: TunerType = "FC0013"; break;
260                 case RTLSDR_TUNER_FC2580: TunerType = "FC2580"; break;
261                 case RTLSDR_TUNER_R820T: TunerType = "R820T"; break;
262                 case RTLSDR_TUNER_R828D: TunerType = "R828D"; break;
263                 default: TunerType = "Unknown";
264             }
265             std::clog << "RTL_TCP_CLIENT: Tuner type: " <<
266                 dongleInfo.tuner_type << " " << TunerType << std::endl;
267             std::clog << "RTL_TCP_CLIENT: Tuner gain count: " <<
268                 dongleInfo.tuner_gain_count << std::endl;
269         }
270         else {
271             std::clog << "RTL_TCP_CLIENT: Didn't find the \"RTL0\" magic key." <<
272                 std::endl;
273         }
274     }
275 
276     sampleNetworkBuffer.putDataIntoBuffer(buffer.data(), buffer.size());
277 
278     // First fill the complete buffer to avoid sound outtages if the stream data rate is not stable e.g. over WIFI
279     if(!firstFilledNetworkBuffer) {
280         float bufferFill = (float) sampleNetworkBuffer.GetRingBufferReadAvailable() / sampleNetworkBuffer.GetBufferSize() * 100;
281 
282         // Wait for 50% filled buffer
283         if(bufferFill >= 50)
284             firstFilledNetworkBuffer = true;
285 
286         if((getMyTime() - oldTime_us > 100e3) || firstFilledNetworkBuffer) {
287             //std::clog << "RTL_TCP_CLIENT: Fill network buffer " << bufferFill << "%" << std::endl;
288             oldTime_us = getMyTime();
289         }
290     }
291 
292 
293     // Check if device is overloaded
294     minAmplitude = 255;
295     maxAmplitude = 0;
296 
297     for (const auto b : buffer) {
298         if (minAmplitude > b)
299             minAmplitude = b;
300         if (maxAmplitude < b)
301             maxAmplitude = b;
302     }
303 }
304 
handleDisconnect()305 void CRTL_TCP_Client::handleDisconnect()
306 {
307     connected = false;
308     firstData = true;
309     radioController.onMessage(message_level_t::Error,
310             QT_TRANSLATE_NOOP("CRadioController", "RTL-TCP connection closed."));
311     sock.close();
312 }
313 
sendCommand(uint8_t cmd,int32_t param)314 void CRTL_TCP_Client::sendCommand(uint8_t cmd, int32_t param)
315 {
316     if (!connected || !sock.valid()) {
317         return;
318     }
319 
320     std::vector<uint8_t> datagram;
321 
322     datagram.resize(5);
323     datagram[0] = cmd; // command to set rate
324     datagram[4] = param & 0xFF;  //lsb last
325     datagram[3] = (param >> ONE_BYTE) & 0xFF;
326     datagram[2] = (param >> (2 * ONE_BYTE)) & 0xFF;
327     datagram[1] = (param >> (3 * ONE_BYTE)) & 0xFF;
328     sock.send(datagram.data(), datagram.size(), 0);
329 }
330 
sendVFO(int32_t frequency)331 void CRTL_TCP_Client::sendVFO(int32_t frequency)
332 {
333     sendCommand(0x01, frequency);
334 }
335 
sendRate(int32_t theRate)336 void CRTL_TCP_Client::sendRate(int32_t theRate)
337 {
338     sendCommand(0x02, theRate);
339 }
340 
setGainMode(int32_t gainMode)341 void CRTL_TCP_Client::setGainMode(int32_t gainMode)
342 {
343     sendCommand (0x03, gainMode);
344 }
345 
getGain() const346 float CRTL_TCP_Client::getGain() const
347 {
348     return currentGain;
349 }
350 
setGain(int32_t gain)351 float CRTL_TCP_Client::setGain(int32_t gain)
352 {
353     currentGainCount = gain;
354     float gainValue = getGainValue(gain);
355 
356     sendCommand(0x04, (int)10 * gainValue);
357 
358     currentGain = gainValue;
359     return gainValue;
360 }
361 
getGainCount()362 int32_t CRTL_TCP_Client::getGainCount()
363 {
364     int32_t MaxGainCount = 0;
365     switch (dongleInfo.tuner_type) {
366         case RTLSDR_TUNER_E4000: MaxGainCount = e4k_gains.size(); break;
367         case RTLSDR_TUNER_FC0012: MaxGainCount = fc0012_gains.size(); break;
368         case RTLSDR_TUNER_FC0013: MaxGainCount = fc0013_gains.size(); break;
369         case RTLSDR_TUNER_FC2580: MaxGainCount = fc2580_gains.size(); break;
370         case RTLSDR_TUNER_R820T: MaxGainCount = r82xx_gains.size(); break;
371         case RTLSDR_TUNER_R828D: MaxGainCount = r82xx_gains.size(); break;
372         default: MaxGainCount = 29; // Most likely it is the R820T tuner
373     }
374 
375     return MaxGainCount;
376 }
377 
setAgc(bool AGC)378 void CRTL_TCP_Client::setAgc(bool AGC)
379 {
380     isAGC = AGC;
381 }
382 
383 //void CRTL_TCP_Client::setHwAgc(bool hwAGC)
384 //{
385 //    isHwAGC = hwAGC;
386 //    sendCommand(0x08, hwAGC ? 1 : 0);
387 //}
388 
getDescription()389 std::string CRTL_TCP_Client::getDescription()
390 {
391     return "rtl_tcp_client (server: " +
392         serverAddress + ":" +
393         std::to_string(serverPort) + ")";
394 }
395 
getID()396 CDeviceID CRTL_TCP_Client::getID()
397 {
398     return CDeviceID::RTL_TCP;
399 }
400 
setServerAddress(const std::string & serverAddress)401 void CRTL_TCP_Client::setServerAddress(const std::string& serverAddress)
402 {
403     this->serverAddress = serverAddress;
404 }
405 
setPort(uint16_t Port)406 void CRTL_TCP_Client::setPort(uint16_t Port)
407 {
408     serverPort = Port;
409 }
410 
receiveAndReconnect()411 void CRTL_TCP_Client::receiveAndReconnect()
412 {
413     while (rtlsdrRunning) {
414         std::unique_lock<std::mutex> lock(mutex);
415 
416         if (!connected) {
417             std::clog << "RTL_TCP_CLIENT: Try to connect to server " <<
418                 serverAddress << ":" << serverPort << std::endl;
419 
420             try {
421                 connected = sock.connect(serverAddress, serverPort, 2);
422             }
423             catch(const std::runtime_error& e) {
424                 std::clog << "RTL_TCP_CLIENT: " << e.what() << std::endl;
425             }
426 
427             if (connected) {
428                 std::clog << "RTL_TCP_CLIENT: Successful connected to server " <<
429                     std::endl;
430 
431                 // Always use manual gain, the AGC is implemented in software
432                 setGainMode(1);
433                 setGain(currentGainCount);
434                 sendRate(INPUT_RATE);
435                 sendVFO(frequency);
436 
437                 if (!agcRunning) {
438                     agcRunning = true;
439                     agcThread = std::thread(&CRTL_TCP_Client::agcTimer, this);
440                 }
441                 firstData = true;
442                 reset(); // Clear buffers
443             }
444             else {
445                 std::clog << "RTL_TCP_CLIENT: Could not connect to server" <<
446                     std::endl;
447 
448                 agcRunning = false;
449                 rtlsdrRunning = false;
450                 lock.unlock();
451 
452                 radioController.onMessage(message_level_t::Error,
453                         QT_TRANSLATE_NOOP("CRadioController", "Connection failed to server "),
454                         serverAddress + ":" + std::to_string(serverPort));
455             }
456         }
457 
458         if (connected) {
459             if (lock.owns_lock()) {
460                 lock.unlock();
461             }
462 
463             receiveData();
464         }
465     }
466 }
467 
468 #define NETWORK_BUFFER_READ_SAMPLES 32768
networkBufferCopy()469 void CRTL_TCP_Client::networkBufferCopy()
470 {
471     std::vector<uint8_t> tempBuffer(NETWORK_BUFFER_READ_SAMPLES * 2);
472 
473     while (rtlsdrRunning) {
474         if(!firstFilledNetworkBuffer) {
475             std::this_thread::sleep_for(std::chrono::milliseconds(100));
476             nextStop_us = getMyTime();
477             continue;
478         }
479 
480         int32_t samples = NETWORK_BUFFER_READ_SAMPLES;
481 
482         // Figure out the max samples to read from network buffer
483         int32_t samplesInBuffer = sampleNetworkBuffer.GetRingBufferReadAvailable() / 2;
484         if(samplesInBuffer < samples)
485             samples = samplesInBuffer;
486 
487         if(samples == 0) {
488             std::this_thread::sleep_for(std::chrono::milliseconds(100));
489             nextStop_us = getMyTime();
490             continue;
491         }
492 
493         // Read data
494         int32_t amount = sampleNetworkBuffer.getDataFromBuffer(tempBuffer.data(), 2 * samples);
495 
496         // Write data to standard buffers
497         sampleBuffer.putDataIntoBuffer(tempBuffer.data(), amount);
498         spectrumSampleBuffer.putDataIntoBuffer(tempBuffer.data(), amount);
499 
500         if(getMyTime() - oldTime_us > 500e3) { // 500 ms
501 
502             float bufferFill = (float) sampleNetworkBuffer.GetRingBufferReadAvailable() / sampleNetworkBuffer.GetBufferSize() * 100;
503             //std::clog << "RTL_TCP_CLIENT: Network buffer fill level " << bufferFill << "%" << std::endl;
504 
505             oldTime_us = getMyTime();
506         }
507 
508 
509         uint32_t period_us = samples / ((float) INPUT_RATE / 1e6);
510         nextStop_us += period_us;
511         int64_t timeToWait_us = nextStop_us - getMyTime();
512 
513         // Send thread to sleep
514         std::this_thread::sleep_for(std::chrono::microseconds(timeToWait_us));
515     }
516 }
517 
agcTimer(void)518 void CRTL_TCP_Client::agcTimer(void)
519 {
520     while (agcRunning) {
521         std::this_thread::sleep_for(std::chrono::milliseconds(50));
522 
523         if (isAGC && (dongleInfo.tuner_type != RTLSDR_TUNER_UNKNOWN)) {
524             // Check for overloading
525             if (minAmplitude == 0 || maxAmplitude == 255) {
526                 // We have to decrease the gain
527                 if(currentGainCount > 0) {
528                     setGain(currentGainCount - 1);
529                     //std::clog << "RTL_TCP_CLIENT: Decrease gain to " << (float)currentGain << std::endl;
530                 }
531             }
532             else {
533                 if (currentGainCount < (getGainCount() - 1)) {
534                     // Calc if a gain increase overloads the device. Calc it
535                     // from the gain values
536                     const float newGain = getGainValue(currentGainCount + 1);
537                     const float deltaGain = newGain - currentGain;
538                     const float linGain = pow(10, deltaGain / 20);
539                     const int newMaxValue = (float)maxAmplitude * linGain;
540                     const int newMinValue = (float)minAmplitude / linGain;
541 
542                     // We have to increase the gain
543                     if (newMinValue >=0 && newMaxValue <= 255) {
544                         setGain(currentGainCount + 1);
545                         //std::clog << "RTL_TCP_CLIENT: Increase gain to " << currentGain << std::endl;
546                     }
547                 }
548             }
549         }
550         else { // AGC is off or unknown tuner
551             if (minAmplitude == 0 || maxAmplitude == 255) {
552                 std::string text = QT_TRANSLATE_NOOP("CRadioController", "ADC overload."
553                     " Maybe you are using a too high gain.");
554                 std::clog << "RTL_TCP_CLIENT:" << text << std::endl;
555                 radioController.onMessage(message_level_t::Information, text);
556             }
557         }
558     }
559 }
560 
getGainValue(uint16_t gainCount)561 float CRTL_TCP_Client::getGainValue(uint16_t gainCount)
562 {
563     float gainValue = 0;
564 
565     if (dongleInfo.tuner_type == RTLSDR_TUNER_UNKNOWN)
566         return 0;
567 
568     // Get max gain count
569     uint32_t maxGainCount = getGainCount();
570     if (maxGainCount == 0)
571         return 0;
572 
573     // Check if gainCount is valid
574     if (gainCount < maxGainCount) {
575         // Get gain
576         switch(dongleInfo.tuner_type) {
577             case RTLSDR_TUNER_E4000: gainValue = e4k_gains[gainCount]; break;
578             case RTLSDR_TUNER_FC0012: gainValue = fc0012_gains[gainCount]; break;
579             case RTLSDR_TUNER_FC0013: gainValue = fc0013_gains[gainCount]; break;
580             case RTLSDR_TUNER_FC2580: gainValue = fc2580_gains[gainCount]; break;
581             case RTLSDR_TUNER_R820T: gainValue = r82xx_gains[gainCount]; break;
582             case RTLSDR_TUNER_R828D: gainValue = r82xx_gains[gainCount]; break;
583             default: gainValue = 0;
584         }
585     }
586     else {
587         gainValue = 999.0; // Max gain
588     }
589 
590     return gainValue;
591 }
592 
593