1+ #include < utils/flog.h>
2+ #include < module.h>
3+ #include < gui/gui.h>
4+ #include < signal_path/signal_path.h>
5+ #include < core.h>
6+ #include < gui/style.h>
7+ #include < config.h>
8+ #include < gui/smgui.h>
9+ #include < gui/widgets/stepped_slider.h>
10+ #include < utils/optionlist.h>
11+ #include < utils/net.h>
12+
13+ #define CONCAT (a, b ) ((std::string(a) + b).c_str())
14+
15+ SDRPP_MOD_INFO{
16+ /* Name: */ " network_source" ,
17+ /* Description: */ " UDP/TCP Source Module" ,
18+ /* Author: */ " Ryzerth" ,
19+ /* Version: */ 0 , 1 , 0 ,
20+ /* Max instances */ 1
21+ };
22+
23+ ConfigManager config;
24+
25+ enum Protocol {
26+ PROTOCOL_TCP_SERVER,
27+ PROTOCOL_TCP_CLIENT,
28+ PROTOCOL_UDP
29+ };
30+
31+ enum SampleType {
32+ SAMPLE_TYPE_INT8,
33+ SAMPLE_TYPE_INT16,
34+ SAMPLE_TYPE_INT32,
35+ SAMPLE_TYPE_FLOAT32
36+ };
37+
38+ class NetworkSourceModule : public ModuleManager ::Instance {
39+ public:
40+ NetworkSourceModule (std::string name) {
41+ this ->name = name;
42+
43+ samplerate = 1000000.0 ;
44+
45+ handler.ctx = this ;
46+ handler.selectHandler = menuSelected;
47+ handler.deselectHandler = menuDeselected;
48+ handler.menuHandler = menuHandler;
49+ handler.startHandler = start;
50+ handler.stopHandler = stop;
51+ handler.tuneHandler = tune;
52+ handler.stream = &stream;
53+
54+ // Define samplerates
55+ for (int i = 3000 ; i <= 192000 ; i <<= 1 ) {
56+ samplerates.define (i, getSrScaled (i), i);
57+ }
58+ for (int i = 250000 ; i < 1000000 ; i += 250000 ) {
59+ samplerates.define (i, getSrScaled (i), i);
60+ }
61+ for (int i = 1000000 ; i < 10000000 ; i += 500000 ) {
62+ samplerates.define (i, getSrScaled (i), i);
63+ }
64+ for (int i = 10000000 ; i <= 100000000 ; i += 5000000 ) {
65+ samplerates.define (i, getSrScaled (i), i);
66+ }
67+
68+ // Define protocols
69+ protocols.define (" TCP (Server)" , PROTOCOL_TCP_SERVER);
70+ protocols.define (" TCP (Client)" , PROTOCOL_TCP_CLIENT);
71+ protocols.define (" UDP" , PROTOCOL_UDP);
72+
73+ // Define sample types
74+ sampleTypes.define (" Int8" , SAMPLE_TYPE_INT8);
75+ sampleTypes.define (" Int16" , SAMPLE_TYPE_INT16);
76+ sampleTypes.define (" Int32" , SAMPLE_TYPE_INT32);
77+ sampleTypes.define (" Float32" , SAMPLE_TYPE_FLOAT32);
78+
79+ // Load config
80+ config.acquire ();
81+ if (config.conf [name].contains (" samplerate" )) {
82+ int sr = config.conf [name][" samplerate" ];
83+ if (samplerates.keyExists (sr)) { samplerate = samplerates.value (samplerates.keyId (sr)); }
84+ }
85+ if (config.conf [name].contains (" protocol" )) {
86+ std::string protoStr = config.conf [name][" protocol" ];
87+ if (protocols.keyExists (protoStr)) { proto = protocols.value (protocols.keyId (protoStr)); }
88+ }
89+ if (config.conf [name].contains (" sampleType" )) {
90+ std::string sampTypeStr = config.conf [name][" sampleType" ];
91+ if (sampleTypes.keyExists (sampTypeStr)) { sampType = sampleTypes.value (sampleTypes.keyId (sampTypeStr)); }
92+ }
93+ if (config.conf [name].contains (" host" )) {
94+ std::string hostStr = config.conf [name][" host" ];
95+ strcpy (hostname, hostStr.c_str ());
96+ }
97+ if (config.conf [name].contains (" port" )) {
98+ port = config.conf [name][" port" ];
99+ port = std::clamp<int >(port, 1 , 65535 );
100+ }
101+ config.release ();
102+
103+ // Set menu IDs
104+ srId = samplerates.valueId (samplerate);
105+ protoId = protocols.valueId (proto);
106+ sampTypeId = sampleTypes.valueId (sampType);
107+
108+ sigpath::sourceManager.registerSource (" Network" , &handler);
109+ }
110+
111+ ~NetworkSourceModule () {
112+ stop (this );
113+ sigpath::sourceManager.unregisterSource (" Network" );
114+ }
115+
116+ void postInit () {}
117+
118+ void enable () {
119+ enabled = true ;
120+ }
121+
122+ void disable () {
123+ enabled = false ;
124+ }
125+
126+ bool isEnabled () {
127+ return enabled;
128+ }
129+
130+ private:
131+ std::string getSrScaled (double sr) {
132+ char buf[1024 ];
133+ if (sr >= 1000000.0 ) {
134+ sprintf (buf, " %.1lf MS/s" , sr / 1000000.0 );
135+ }
136+ else if (sr >= 1000.0 ) {
137+ sprintf (buf, " %.1lf KS/s" , sr / 1000.0 );
138+ }
139+ else {
140+ sprintf (buf, " %.1lf S/s" , sr);
141+ }
142+ return std::string (buf);
143+ }
144+
145+ static void menuSelected (void * ctx) {
146+ NetworkSourceModule* _this = (NetworkSourceModule*)ctx;
147+ core::setInputSampleRate (_this->samplerate );
148+ flog::info (" NetworkSourceModule '{0}': Menu Select!" , _this->name );
149+ }
150+
151+ static void menuDeselected (void * ctx) {
152+ NetworkSourceModule* _this = (NetworkSourceModule*)ctx;
153+ flog::info (" NetworkSourceModule '{0}': Menu Deselect!" , _this->name );
154+ }
155+
156+ static void start (void * ctx) {
157+ NetworkSourceModule* _this = (NetworkSourceModule*)ctx;
158+ if (_this->running ) { return ; }
159+
160+ // TODO
161+
162+ _this->running = true ;
163+ flog::info (" NetworkSourceModule '{0}': Start!" , _this->name );
164+ }
165+
166+ static void stop (void * ctx) {
167+ NetworkSourceModule* _this = (NetworkSourceModule*)ctx;
168+ if (!_this->running ) { return ; }
169+
170+ // TODO
171+
172+ _this->running = false ;
173+ flog::info (" NetworkSourceModule '{0}': Stop!" , _this->name );
174+ }
175+
176+ static void tune (double freq, void * ctx) {
177+ NetworkSourceModule* _this = (NetworkSourceModule*)ctx;
178+ if (_this->running ) {
179+ // Nothing for now
180+ }
181+ _this->freq = freq;
182+ flog::info (" NetworkSourceModule '{0}': Tune: {1}!" , _this->name , freq);
183+ }
184+
185+ static void menuHandler (void * ctx) {
186+ NetworkSourceModule* _this = (NetworkSourceModule*)ctx;
187+
188+ if (_this->running ) { SmGui::BeginDisabled (); }
189+
190+ // Hostname and port field
191+ if (ImGui::InputText ((" ##iq_exporter_host_" + _this->name ).c_str (), _this->hostname , sizeof (_this->hostname ))) {
192+ config.acquire ();
193+ config.conf [_this->name ][" host" ] = _this->hostname ;
194+ config.release (true );
195+ }
196+ ImGui::SameLine ();
197+ ImGui::FillWidth ();
198+ if (ImGui::InputInt ((" ##iq_exporter_port_" + _this->name ).c_str (), &_this->port , 0 , 0 )) {
199+ _this->port = std::clamp<int >(_this->port , 1 , 65535 );
200+ config.acquire ();
201+ config.conf [_this->name ][" port" ] = _this->port ;
202+ config.release (true );
203+ }
204+
205+ // Samplerate selector
206+ ImGui::LeftLabel (" Samplerate" );
207+ ImGui::FillWidth ();
208+ if (ImGui::Combo ((" ##iq_exporter_sr_" + _this->name ).c_str (), &_this->srId , _this->samplerates .txt )) {
209+ _this->samplerate = _this->samplerates .value (_this->srId );
210+ core::setInputSampleRate (_this->samplerate );
211+ config.acquire ();
212+ config.conf [_this->name ][" samplerate" ] = _this->samplerates .key (_this->srId );
213+ config.release (true );
214+ }
215+
216+ // Mode protocol selector
217+ ImGui::LeftLabel (" Protocol" );
218+ ImGui::FillWidth ();
219+ if (ImGui::Combo ((" ##iq_exporter_proto_" + _this->name ).c_str (), &_this->protoId , _this->protocols .txt )) {
220+ _this->proto = _this->protocols .value (_this->protoId );
221+ config.acquire ();
222+ config.conf [_this->name ][" protocol" ] = _this->protocols .key (_this->protoId );
223+ config.release (true );
224+ }
225+
226+ // Sample type selector
227+ ImGui::LeftLabel (" Sample type" );
228+ ImGui::FillWidth ();
229+ if (ImGui::Combo ((" ##iq_exporter_samp_" + _this->name ).c_str (), &_this->sampTypeId , _this->sampleTypes .txt )) {
230+ _this->sampType = _this->sampleTypes .value (_this->sampTypeId );
231+ config.acquire ();
232+ config.conf [_this->name ][" sampleType" ] = _this->sampleTypes .key (_this->sampTypeId );
233+ config.release (true );
234+ }
235+
236+ if (_this->running ) { SmGui::EndDisabled (); }
237+ }
238+
239+ void worker () {
240+ int frameSize = samplerate / 200 ;
241+ switch (sampType) {
242+ case SAMPLE_TYPE_INT8:
243+ frameSize *= 2 *sizeof (int8_t );;
244+ break ;
245+ case SAMPLE_TYPE_INT16:
246+ frameSize *= 2 *sizeof (int16_t );
247+ break ;
248+ case SAMPLE_TYPE_INT32:
249+ frameSize *= 2 *sizeof (int32_t );
250+ break ;
251+ case SAMPLE_TYPE_FLOAT32:
252+ frameSize *= sizeof (dsp::complex_t );
253+ break ;
254+ default :
255+ return ;
256+ }
257+ uint8_t * buffer = dsp::buffer::alloc<uint8_t >(STREAM_BUFFER_SIZE*sizeof (uint32_t ));
258+
259+ while (true ) {
260+ // Read samples from socket
261+ int bytes = sock->recv (buffer, frameSize, true );
262+
263+ // Convert to CF32
264+ int count;
265+ switch (sampType) {
266+ case SAMPLE_TYPE_INT8:
267+ frameSize *= 2 *sizeof (int8_t );;
268+ break ;
269+ case SAMPLE_TYPE_INT16:
270+ frameSize *= 2 *sizeof (int16_t );
271+ break ;
272+ case SAMPLE_TYPE_INT32:
273+ frameSize *= 2 *sizeof (int32_t );
274+ break ;
275+ case SAMPLE_TYPE_FLOAT32:
276+ // memcpy(stream.writeBuf, buffer, )
277+ break ;
278+ default :
279+ break ;
280+ }
281+
282+ // Send out converted samples
283+ // if (!stream.swap(bufferSize))
284+ }
285+
286+ dsp::buffer::free (buffer);
287+ }
288+
289+ std::string name;
290+ bool enabled = true ;
291+ dsp::stream<dsp::complex_t > stream;
292+ SourceManager::SourceHandler handler;
293+ bool running = false ;
294+ double freq;
295+
296+ int samplerate = 1000000 ;
297+ int srId;
298+ Protocol proto = PROTOCOL_TCP_SERVER;
299+ int protoId;
300+ SampleType sampType = SAMPLE_TYPE_INT16;
301+ int sampTypeId;
302+ char hostname[1024 ] = " localhost" ;
303+ int port = 1234 ;
304+
305+ OptionList<int , int > samplerates;
306+ OptionList<std::string, Protocol> protocols;
307+ OptionList<std::string, SampleType> sampleTypes;
308+
309+ std::thread listenWorkerThread;
310+
311+ std::mutex sockMtx;
312+ std::shared_ptr<net::Socket> sock;
313+ std::shared_ptr<net::Listener> listener;
314+ };
315+
316+ MOD_EXPORT void _INIT_ () {
317+ json def = json ({});
318+ config.setPath (core::args[" root" ].s () + " /network_source_config.json" );
319+ config.load (def);
320+ config.enableAutoSave ();
321+ }
322+
323+ MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_ (std::string name) {
324+ return new NetworkSourceModule (name);
325+ }
326+
327+ MOD_EXPORT void _DELETE_INSTANCE_ (ModuleManager::Instance* instance) {
328+ delete (NetworkSourceModule*)instance;
329+ }
330+
331+ MOD_EXPORT void _END_ () {
332+ config.disableAutoSave ();
333+ config.save ();
334+ }
0 commit comments