1 /////////////////////////////////////////////////////////////////////////////
2 //
3 // Linrad driver code for the Funcube Dongle Pro Plus
4 //
5 // Copyright (c) <2013> <Mike. J. Keehan>
6 //
7 // Permission is hereby granted, free of charge, to any person
8 // obtaining a copy of this software and associated documentation
9 // files (the "Software"), to deal in the Software without restriction,
10 // including without limitation the rights to use, copy, modify,
11 // merge, publish, distribute, sublicense, and/or sell copies of
12 // the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
14 //
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
17 //
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
25 // OR OTHER DEALINGS IN THE SOFTWARE.
26 //
27 //
28 //
29 //
30 //
31 // This code uses HIDAPI from http://www.signal11.us/oss/hidapi/
32 // and the Linux kernel hidraw interface.
33 //
34 // M. J. Keehan, 25th Feb 2013 (mike@keehan.net)
35 //
36 //
37 // NOTES:-
38 //
39 // Frequency setting
40 // The user graphic window shows the FCD's current frequency setting. It
41 // is not an input field.
42 //
43 // Linrad's frequency control box is configured for input in MHz, and
44 // allows for 7 digits of input plus a decimal point, and uses a
45 // floating point value to hold this input (floats are limited to approx
46 // 7 digits of precision).
47 // The FCD supports setting input by individual Hz upto the 240MHz point,
48 // and 7 digit precision above that.
49 // Hence, it is possible to enter 1.234567MHz (or 12.34567, or 123.4567)
50 // in Linrad and all digits will be used to set the FCD. But above 240MHz
51 // only 6 digits of frequency input are used (the code actually checks at
52 // 300MHz as the FCD has a break in coverage between approx 240MHz and 420MHz)
53 //
54 // Frequency increment
55 // The value to be used in Linrad's frequency control box when up/down
56 // buttons are used. Defaults to 100kHz, range 1kHz-100MHz.
57 //
58 // Rx Gain control
59 // The lower control in Linrad's Frequency control box has been configured
60 // to adjust the FCD Pro Plus's IF Gain settings.
61 //
62 // PPM Correction
63 // A ppm correction value can be set in the lowest line of the graphic box.
64 // Either enter a value by clicking on the current value and using the
65 // keyboard, or use the up/down arrow keys to increment/decrement the
66 // current value.
67 //
68 //
69 //
70 // Note: The usergraphic position, the ppm setting, frequency increment
71 // and other values are saved in a parameterfile which is read
72 // when Linrad is started.
73 // The file name is "par_xxx_hwd_fcdgr" (with xxx = rx_mode) and its
74 // content can be displayed (and changed - carefully) with an editor.
75 //
76 //
77 //////////////////////////////////////////////////////////////////////////////
78
79 #if LIBUDEV_PRESENT==1
80
81 #include <string.h>
82
83 #include "fcdpp.h"
84 #include "hidapi.h"
85
86 #include "globdef.h"
87 #include "uidef.h"
88 #include "screendef.h"
89 #include "fft1def.h"
90 #include "rusage.h"
91 #include "thrdef.h"
92
93
94 // UserGraphic Button defs.
95 #define UG_TOP 0
96 #define UG_BOTTOM 1
97 #define UG_LEFT 2
98 #define UG_RIGHT 3
99 #define UG_INCREASE_PPM_CORR 4
100 #define UG_DECREASE_PPM_CORR 5
101 #define UG_LNA_ON_OFF 6
102 #define UG_MIXER_GAIN_ON_OFF 7
103 #define UG_BIAS_T_ON_OFF 8
104 #define MAX_FCDGRBUTT 9
105
106 //Size of messages in user graphic box
107 #define MAX_MSGSIZE 30
108
109
110 // FCDPro+ Global variables.
111 // =========================
112 int FCDstate;
113 #define FCD_NOTFOUND 0
114 #define FCD_RUNNING 2
115 #define FCD_BOOTLOAD 1
116
117 #define MAX_HWAREDRIVER_PARM 12
118 char *fcdprodriver_parm_text[MAX_HWAREDRIVER_PARM]={
119 "fcdgr_xleft ",
120 "fcdgr_ytop ",
121 "center_freq ",
122 "freq_increment ",
123 "lna_on_off ",
124 "mixer_gain_on_off ",
125 "rf_filter_val ",
126 "if_filter_val ",
127 "ppm_correction ",
128 "if_gain ",
129 "bias_t_on_off ",
130 "dummy_entry_to_end "
131 };
132
133 typedef struct {
134 int fcdgr_xleft;
135 int fcdgr_ytop;
136 unsigned int center_freq;
137 int freq_incr;
138 int lna_on_off;
139 int mixer_gain_on_off;
140 int rf_filter_val;
141 int if_filter_val;
142 int ppm_correction;
143 int if_gain;
144 int biasT_on_off;
145 int dummy;
146 } HWAREDRIVER_PARMS;
147 HWAREDRIVER_PARMS fcdprodriver;
148
149 typedef struct {
150 int ytop;
151 int ybottom;
152 int xleft;
153 int xright;
154 int yborder;
155 } UG_PARMS;
156 UG_PARMS fcdgr;
157
158 BUTTONS fcdgrbutt[MAX_FCDGRBUTT];
159
160 int fcdgr_old_y1;
161 int fcdgr_old_y2;
162 int fcdgr_old_x1;
163 int fcdgr_old_x2;
164 int fcdproplus_graph_scro;
165
166 int fcdgr_oldx;
167 int fcdgr_oldy;
168 int fcdgr_yborder;
169 int fcdgr_hsiz;
170 int fcdgr_vsiz;
171
172 int fcdgr_msg_color; // switch for message-color in usergraph
173 int LinFreqColor = 7;
174 char fcdgr_msg0[MAX_MSGSIZE]; // messages in usergraph
175 char fcdgr_msg1[MAX_MSGSIZE];
176 char fcdgr_msg2[MAX_MSGSIZE];
177
178 // Prototypes
179 int fcdppGetBiasT(unsigned char *);
180 int fcdppGetIFGain(unsigned char *);
181 int fcdppGetLNA(unsigned char *);
182 int fcdppGetMixerGain(unsigned char *);
183 int fcdppSetBiasT(unsigned char);
184 int fcdppSetFreq(unsigned int, unsigned int *);
185 int fcdppSetIFGain(unsigned char);
186 int fcdppSetLNA(unsigned char);
187 int fcdppSetMixerGain(unsigned char);
188 void fcd_append_freq(char *, double);
189 void init_fcdproplus_control_window(void);
190 void readDevice(int);
191 int read_value_from_fcd(unsigned char, unsigned char *);
192 void show_fcdpp_parms(void);
193 int write_value_to_fcd(unsigned char, unsigned int, unsigned int *);
194
195 //////////////
196 // Code
197 //////////////
198
fcdproplus_setup(void)199 void fcdproplus_setup(void)
200 {
201 // Routine to set up FCDProPlus from the soundcard setup menu.
202 clear_screen();
203 lir_text(3,3,"FCDProPlus selected. (Nothing to do)");
204 lir_text(3,6,press_any_key);
205 await_processed_keyboard();
206 }
207
208 // This is the data entered in the rx gain control box.
209 // int fg.gain_increment = The increment in dB for clicking
210 // the arrows in the gain control box.
211 // The global fg_new_band can be used to allow for different
212 // settings on different bands.
213 //
214 // Uses global data:
215 // int fg.gain
216 //************************************************************
fcdproplus_rx_amp_control(void)217 void fcdproplus_rx_amp_control(void)
218 {
219 fg.gain_increment = 1; // FCD's IF GAIN, step by 1dB.
220
221 // Limit gain to 0-59dB. Be aware that values
222 // above about 30dB are likely to overload.
223 if ( fg.gain < 0 )
224 fg.gain = 0;
225 if ( fg.gain > 59 )
226 fg.gain = 59;
227
228 FCDstate = fcdppSetIFGain(fg.gain);
229 FCDstate = fcdppGetIFGain((unsigned char *)&fcdprodriver.if_gain);
230 fg.gain = fcdprodriver.if_gain;
231 }
232
fcdproplus_rx_freq_control(void)233 void fcdproplus_rx_freq_control(void)
234 { unsigned int fcdFreq, askFreq, centerfreq;
235 int correction;
236
237 fg.passband_direction = 1;
238 fft1_direction = fg.passband_direction;
239 if ( fcdprodriver.dummy == 0 ) // not yet loaded user parameters
240 return;
241
242 fg.passband_increment = ((double)fcdprodriver.freq_incr) / 1000.0;
243
244 // Limit the requested frequency to what is possible on FCDproplus.
245 LinFreqColor = 10; // normal GREEN
246 if ( fg.passband_center < .15 ) // set min freq to 150kHz.
247 { fg.passband_center = .15;
248 LinFreqColor = 12; // show frequency in RED
249 }
250 if ( fg.passband_center > 2050 ) // set max freq to 2.05GHz.
251 { fg.passband_center = 2050;
252 LinFreqColor = 12; // show frequency in RED
253 }
254
255 // Following horrible expression uses floating point to maintain precision till result.
256 correction = (int)(((fg.passband_center*1000000.0*fcdprodriver.ppm_correction)+0.5)/1000000);
257
258 // Round() request frequency to 7 digits of precision
259 centerfreq = (unsigned int)rint(fg.passband_center*1000000);
260 if ( centerfreq > 300000000 )
261 centerfreq = ((centerfreq)/1000)*1000;
262 if ( centerfreq > 99999999 )
263 centerfreq = ((centerfreq+4)/100)*100;
264 if ( centerfreq > 9999999 )
265 centerfreq = ((centerfreq+4)/10)*10;
266 fcdprodriver.center_freq = centerfreq;
267
268 askFreq = centerfreq + correction;
269 if ( askFreq > 300000000 )
270 askFreq = ((askFreq)/1000)*1000;
271
272 FCDstate = fcdppSetFreq(askFreq, &fcdFreq);
273
274 if ( fcdFreq != askFreq )
275 { if ( FCDstate != FCD_RUNNING )
276 fprintf( stderr,"fcdpp: FAILED TO SET FCD FREQ! mode: %s, ask:%d, got:%d\n",
277 (FCDstate==FCD_RUNNING) ? "Running" :
278 (FCDstate==FCD_BOOTLOAD) ? "BootLoad" : "Not Found", askFreq, fcdFreq);
279
280 LinFreqColor = 12; // show frequency in RED text!
281 fg.passband_center = (double) (fcdFreq - correction)/1000000.0;
282 fcdprodriver.center_freq = fcdFreq;
283 }
284
285 show_fcdpp_parms();
286 //fprintf( stderr,"fcdpp_rx_freq: fg.pass %f, center %d, corr %d, askFreq %d, fcdFreq %d\n",
287 // fg.passband_center, centerfreq, correction, askFreq, fcdFreq);
288 }
289
290 // Append frequency formatted in Hz or kHz to the end of
291 // the already present text in the MAX_MSGSIZE buffer.
fcd_append_freq(char * buffer,double fq)292 void fcd_append_freq(char *buffer, double fq)
293 { int j, freq;
294 char *src, *dst, *tail = " Hz", stmp[MAX_MSGSIZE];
295 unsigned u,spaceleft;
296
297 freq = (int)fq; // need Hertz, and not fractions of
298 sprintf(stmp, "%d", freq);
299
300 // Find out how much space is left in given buffer.
301 spaceleft = MAX_MSGSIZE - strlen(buffer) - 1;
302
303 // Change freq to kHz if too many digits present as Hz
304 if ( (strlen(stmp) + strlen(" Hz")) > spaceleft )
305 {
306 freq = freq / 1000; // kHz
307 sprintf(stmp, "%d", freq);
308 tail = " kHz";
309 }
310
311 // space pad the rest of the buffer, and terminate with the tail.
312 for ( u=strlen(buffer) ; u<(MAX_MSGSIZE - strlen(tail) -1) ; ++u )
313 buffer[u] = ' ';
314 strcpy(&buffer[MAX_MSGSIZE - strlen(tail) -1], tail);
315
316 // copy frequency tail first, adding separators every 3rd digit
317 src = &stmp[strlen(stmp)];
318 dst = &buffer[MAX_MSGSIZE - strlen(tail) -1];
319 for ( u=strlen(stmp), j=0 ; u ; --u )
320 {
321 *--dst = *--src;
322 if ( (++j % 3) == 0 && u > 1 ) // but no sep. at front of digits
323 *--dst = ',';
324 }
325 }
326
check_fcdgr_borders(void)327 void check_fcdgr_borders(void) // required for move graph
328 {
329 current_graph_minh=fcdgr_vsiz;
330 current_graph_minw=fcdgr_hsiz;
331 check_graph_placement((void*)(&fcdgr));
332 set_graph_minwidth((void*)(&fcdgr));
333 }
334
make_fcdproplus_control_graph(void)335 void make_fcdproplus_control_graph(void)
336 {
337 pause_thread(THREAD_SCREEN);
338
339 check_fcdgr_borders(); // required for move graph
340 scro[fcdproplus_graph_scro].no=FCDPROPLUS_GRAPH;
341
342 // These are the coordinates of the border lines.
343 scro[fcdproplus_graph_scro].x1=fcdgr.xleft;
344 scro[fcdproplus_graph_scro].x2=fcdgr.xright;
345 scro[fcdproplus_graph_scro].y1=fcdgr.ytop;
346 scro[fcdproplus_graph_scro].y2=fcdgr.ybottom;
347
348 // Each border line is treated as a button.
349 // That is for the mouse to get hold of them so the window can be moved.
350 fcdgrbutt[UG_LEFT].x1=fcdgr.xleft;
351 fcdgrbutt[UG_LEFT].x2=fcdgr.xleft+2;
352 fcdgrbutt[UG_LEFT].y1=fcdgr.ytop;
353 fcdgrbutt[UG_LEFT].y2=fcdgr.ybottom;
354 fcdgrbutt[UG_RIGHT].x1=fcdgr.xright;
355 fcdgrbutt[UG_RIGHT].x2=fcdgr.xright-2;
356 fcdgrbutt[UG_RIGHT].y1=fcdgr.ytop;
357 fcdgrbutt[UG_RIGHT].y2=fcdgr.ybottom;
358 fcdgrbutt[UG_TOP].x1=fcdgr.xleft;
359 fcdgrbutt[UG_TOP].x2=fcdgr.xright;
360 fcdgrbutt[UG_TOP].y1=fcdgr.ytop;
361 fcdgrbutt[UG_TOP].y2=fcdgr.ytop+2;
362 fcdgrbutt[UG_BOTTOM].x1=fcdgr.xleft;
363 fcdgrbutt[UG_BOTTOM].x2=fcdgr.xright;
364 fcdgrbutt[UG_BOTTOM].y1=fcdgr.ybottom;
365 fcdgrbutt[UG_BOTTOM].y2=fcdgr.ybottom-2;
366
367 // Draw the border lines
368 graph_borders((void*)&fcdgr,7);
369 fcdgr_oldx=-10000; // from freq_control
370 settextcolor(7);
371 make_button(fcdgr.xleft+57.2*text_width+2,-2+fcdgr.ybottom-1*text_height/2-1,
372 fcdgrbutt,UG_DECREASE_PPM_CORR,25);
373 make_button(fcdgr.xleft+58.7*text_width+2,-2+fcdgr.ybottom-1*text_height/2-1,
374 fcdgrbutt,UG_INCREASE_PPM_CORR,24);
375
376 // Draw separator lines in usergraph
377 // vertical
378 lir_line(fcdgr.xleft+30.5*text_width,fcdgr.ytop+1.3*text_height,
379 fcdgr.xleft+30.5*text_width,fcdgr.ybottom,7);
380 // horizontal
381 lir_line(fcdgr.xleft,fcdgr.ytop+1.3*text_height,fcdgr.xright,fcdgr.ytop+1.3*text_height,7);
382
383 // Make button for LNA
384 fcdgrbutt[UG_LNA_ON_OFF].x1=fcdgr.xleft+16*text_width;
385 fcdgrbutt[UG_LNA_ON_OFF].x2=fcdgr.xleft+20*text_width;
386 fcdgrbutt[UG_LNA_ON_OFF].y1=fcdgr.ytop+1.5*text_height;
387 fcdgrbutt[UG_LNA_ON_OFF].y2=fcdgr.ytop+2.4*text_height;
388
389 // Make button for Mixer Gain
390 fcdgrbutt[UG_MIXER_GAIN_ON_OFF].x1=fcdgr.xleft+16*text_width;
391 fcdgrbutt[UG_MIXER_GAIN_ON_OFF].x2=fcdgr.xleft+20*text_width;
392 fcdgrbutt[UG_MIXER_GAIN_ON_OFF].y1=fcdgr.ytop+2.5*text_height;
393 fcdgrbutt[UG_MIXER_GAIN_ON_OFF].y2=fcdgr.ytop+3.4*text_height;
394
395 // Make button for BiasT
396 fcdgrbutt[UG_BIAS_T_ON_OFF].x1=fcdgr.xleft+16*text_width;
397 fcdgrbutt[UG_BIAS_T_ON_OFF].x2=fcdgr.xleft+20*text_width;
398 fcdgrbutt[UG_BIAS_T_ON_OFF].y1=fcdgr.ytop+3.5*text_height;
399 fcdgrbutt[UG_BIAS_T_ON_OFF].y2=fcdgr.ytop+4.4*text_height;
400
401 fcdproplus_rx_freq_control();
402 show_fcdpp_parms();
403 resume_thread(THREAD_SCREEN);
404 }
405
append_blanks_fcdgrmsg(char * msg)406 void append_blanks_fcdgrmsg(char *msg)
407 { int i;
408
409 i=strlen(msg);
410 if(i>=MAX_MSGSIZE)
411 lirerr(3413400);
412 while(i<MAX_MSGSIZE-1)
413 {
414 msg[i]=' ';
415 i++;
416 }
417 msg[MAX_MSGSIZE-1]=0;
418 }
419
420 // Show the user parameters on screen
show_fcdpp_parms(void)421 void show_fcdpp_parms(void)
422 { int i;
423 int *sdr_pi;
424 char s[80];
425 char *mode = "";
426 char fcdprodriver_parfil_name[20];
427 FILE *fcdprodriver_file;
428
429 switch(rx_mode)
430 {
431 case MODE_WCW: mode = "WCW"; break;
432 case MODE_HSMS: mode = "HSMS"; break;
433 case MODE_QRSS: mode = "QRSS"; break;
434 case MODE_NCW: mode = "NCW"; break;
435 case MODE_SSB: mode = "SSB"; break;
436 case MODE_FM: mode = "FM "; break;
437 case MODE_AM: mode = "AM "; break;
438 }
439
440 if ( fcdprodriver.dummy == 0 ) // if control window does not yet exist, exit.
441 return;
442
443 hide_mouse(fcdgr.xleft, fcdgr.xright,fcdgr.ytop,fcdgr.ybottom);
444 sprintf(s,"FunCubeDongle Pro+ %4s LINRAD %s mode",
445 (FCDstate==FCD_RUNNING) ? "Running" : \
446 (FCDstate==FCD_BOOTLOAD) ? "BootLoad" : "Not Found", mode);
447 settextcolor(14); // yellow
448 lir_pixwrite(fcdgr.xleft+1.5*text_width,fcdgr.ytop+0.35*text_height,s);
449 settextcolor(15); // white
450 settextcolor(7); // grey
451
452 sprintf(s,"PPM correction : %d ", fcdprodriver.ppm_correction);
453 s[26]=0;
454 lir_pixwrite(fcdgr.xleft+31*text_width,fcdgr.ytop+1+3.5*text_height,s);
455 sprintf(s,"VFO incr (Khz) : %d ", fcdprodriver.freq_incr);
456 s[25]=0;
457 lir_pixwrite(fcdgr.xleft+31*text_width,fcdgr.ytop+2.5*text_height,s);
458
459 //Display messages in message-area of usergraph
460 settextcolor(11); // light blue
461 sprintf(s,"Low Noise Amp: %3s", fcdprodriver.lna_on_off ? "On" : "Off");
462 append_blanks_fcdgrmsg(s);
463 lir_pixwrite(fcdgr.xleft+1.5*text_width,fcdgr.ytop+1.5*text_height,s);
464 sprintf(s,"Mixer Gain : %3s", fcdprodriver.mixer_gain_on_off? "On":"Off");
465 append_blanks_fcdgrmsg(s);
466 lir_pixwrite(fcdgr.xleft+1.5*text_width,fcdgr.ytop+2.5*text_height,s);
467 sprintf(s,"Bias T : %3s", fcdprodriver.biasT_on_off ? "On" : "Off");
468 append_blanks_fcdgrmsg(s);
469 lir_pixwrite(fcdgr.xleft+1.5*text_width,fcdgr.ytop+3.5*text_height,s);
470
471 sprintf(fcdgr_msg0,"FCDPP Freq: ");
472 fcd_append_freq(fcdgr_msg0,fcdprodriver.center_freq);
473 append_blanks_fcdgrmsg(fcdgr_msg0);
474 settextcolor(LinFreqColor);
475 lir_pixwrite(fcdgr.xleft+31*text_width,fcdgr.ytop+1.5*text_height,fcdgr_msg0);
476
477 // Save screenposition, and FCD settings to the parameterfile on disk
478 sprintf(fcdprodriver_parfil_name,"%s_hwd_fcdgr",rxpar_filenames[rx_mode]);
479 fcdprodriver_file=fopen(fcdprodriver_parfil_name,"w");
480 fcdprodriver.fcdgr_xleft=fcdgr.xleft;
481 fcdprodriver.fcdgr_ytop=fcdgr.ytop;
482 sdr_pi=(int*)(&fcdprodriver);
483 for(i=0; i<MAX_HWAREDRIVER_PARM; i++)
484 fprintf(fcdprodriver_file,"%s [%d]\n",fcdprodriver_parm_text[i],sdr_pi[i]);
485 parfile_end(fcdprodriver_file);
486
487 settextcolor(7);
488 }
489
new_fcd_lna_on_off(void)490 void new_fcd_lna_on_off(void)
491 { int fme;
492
493 fcdprodriver.lna_on_off ^= 1;
494 fme = fcdppSetLNA(fcdprodriver.lna_on_off);
495 if ( fme == 0 )
496 fprintf( stderr,"new_fcd_lna_on_off: Failed to change LNA setting\n");
497 }
498
new_fcd_biasT(void)499 void new_fcd_biasT(void)
500 { int fme;
501
502 fcdprodriver.biasT_on_off ^= 1;
503 fme = fcdppSetBiasT(fcdprodriver.biasT_on_off);
504 if ( fme == 0 )
505 fprintf( stderr,"new_fcd_biasT: Failed to change BIAS T setting\n");
506 }
507
new_fcd_mixer_gain(void)508 void new_fcd_mixer_gain(void)
509 { int fme;
510
511 fcdprodriver.mixer_gain_on_off ^= 1;
512 fme = fcdppSetMixerGain(fcdprodriver.mixer_gain_on_off);
513 if ( fme == 0 )
514 fprintf( stderr,"new_fcd_mixer_gain: Failed to change MixerGain setting\n");
515 }
516
mouse_continue_fcdproplus_graph(void)517 void mouse_continue_fcdproplus_graph(void)
518 { int i, j; // required for move graph
519
520 // Move border lines immediately.
521 // Other functions must wait until button is released.
522 // Move fixed size window based on coding in freq_control.c
523 switch (mouse_active_flag-1)
524 {
525 case UG_TOP:
526 if (fcdgr.ytop!=mouse_y)
527 break;
528
529 case UG_BOTTOM:
530 if (fcdgr.ybottom!=mouse_y)
531 break;
532
533 case UG_LEFT:
534 if (fcdgr.xleft!=mouse_x)
535 break;
536
537 case UG_RIGHT:
538 if (fcdgr.xright==mouse_x)
539 break;
540 break;
541
542 default:
543 goto await_release;
544 }
545
546 pause_screen_and_hide_mouse();
547 graph_borders((void*)&fcdgr,0);
548 if (fcdgr_oldx==-10000)
549 {
550 fcdgr_oldx=mouse_x;
551 fcdgr_oldy=mouse_y;
552 }
553 else
554 {
555 i=mouse_x-fcdgr_oldx;
556 j=mouse_y-fcdgr_oldy;
557 fcdgr_oldx=mouse_x;
558 fcdgr_oldy=mouse_y;
559 fcdgr.ytop+=j;
560 fcdgr.ybottom+=j;
561 fcdgr.xleft+=i;
562 fcdgr.xright+=i;
563 check_fcdgr_borders();
564 fcdgr.yborder=(fcdgr.ytop+fcdgr.ybottom)>>1;
565 }
566 graph_borders((void*)&fcdgr,15);
567 resume_thread(THREAD_SCREEN);
568
569 if (leftpressed == BUTTON_RELEASED)
570 goto finish;
571 return;
572
573 await_release:;
574 if (leftpressed != BUTTON_RELEASED)
575 return;
576
577 // Assuming the user wants to control hardware, allow
578 // commands only when data is not over the network.
579 if((ui.network_flag&NET_RX_INPUT) == 0) //for linrad02.23
580 {
581 switch (mouse_active_flag-1)
582 {
583 case UG_INCREASE_PPM_CORR:
584 if ( fcdprodriver.ppm_correction < 255 )
585 {
586 fcdprodriver.ppm_correction++;
587 fcdproplus_rx_freq_control();
588 }
589 break;
590
591 case UG_DECREASE_PPM_CORR:
592 if ( fcdprodriver.ppm_correction > -255 )
593 {
594 fcdprodriver.ppm_correction--;
595 fcdproplus_rx_freq_control();
596 }
597 break;
598
599 case UG_LNA_ON_OFF:
600 new_fcd_lna_on_off();
601 break;
602
603 case UG_MIXER_GAIN_ON_OFF:
604 new_fcd_mixer_gain();
605 break;
606
607 case UG_BIAS_T_ON_OFF:
608 new_fcd_biasT();
609 break;
610
611 default: // This should never happen.
612 lirerr(211053);
613 break;
614 }
615 }
616
617 finish:;
618 hide_mouse(fcdgr_old_x1,fcdgr_old_x2,fcdgr_old_y1,fcdgr_old_y2);
619 leftpressed=BUTTON_IDLE;
620 mouse_active_flag=0;
621 graph_borders((void*)&fcdgr,0);
622 lir_fillbox(fcdgr_old_x1,fcdgr_old_y1,fcdgr_old_x2-fcdgr_old_x1,fcdgr_old_y2-fcdgr_old_y1,0);
623 make_fcdproplus_control_graph();
624 fcdgr_oldx=-10000;
625 }
626
new_fcd_ppm_correction(void)627 void new_fcd_ppm_correction(void)
628 {
629 if ( numinput_int_data >= -255 && numinput_int_data <= 255 )
630 {
631 fcdprodriver.ppm_correction=numinput_int_data;
632 pause_thread(THREAD_SCREEN);
633 show_fcdpp_parms();
634 resume_thread(THREAD_SCREEN);
635 fcdproplus_rx_freq_control();
636 }
637 }
638
new_fcd_vfo_incr(void)639 void new_fcd_vfo_incr(void)
640 {
641 if ( numinput_int_data < 1 )
642 numinput_int_data = 1;
643 if ( numinput_int_data > 100000 )
644 numinput_int_data = 100000;
645
646 fcdprodriver.freq_incr=numinput_int_data;
647 fg.passband_increment = ((double)fcdprodriver.freq_incr) / 1000.0;
648 pause_thread(THREAD_SCREEN);
649 show_fcdpp_parms();
650 resume_thread(THREAD_SCREEN);
651 }
652
mouse_on_fcdproplus_graph(void)653 void mouse_on_fcdproplus_graph(void)
654 { int event_no;
655 // First find out if we are on a button or border line.
656 for(event_no=0; event_no<MAX_FCDGRBUTT; event_no++)
657 {
658 if( fcdgrbutt[event_no].x1 <= mouse_x &&
659 fcdgrbutt[event_no].x2 >= mouse_x &&
660 fcdgrbutt[event_no].y1 <= mouse_y &&
661 fcdgrbutt[event_no].y2 >= mouse_y)
662 {
663 fcdgr_old_y1=fcdgr.ytop;
664 fcdgr_old_y2=fcdgr.ybottom;
665 fcdgr_old_x1=fcdgr.xleft;
666 fcdgr_old_x2=fcdgr.xright;
667 mouse_active_flag=1+event_no;
668 current_mouse_activity=mouse_continue_fcdproplus_graph;
669 return;
670 }
671 }
672
673 mouse_active_flag=1;
674
675 if(mouse_x > fcdgr.xleft+48*text_width && mouse_x < fcdgr.xleft+53*text_width)
676 {
677 numinput_xpix=fcdgr.xleft+48*text_width;
678 if(mouse_y > (fcdgr.ytop+3.5*text_height))
679 {
680 numinput_ypix=fcdgr.ytop+3.6*text_height;
681 numinput_chars=4;
682 erase_numinput_txt();
683 numinput_flag=FIXED_INT_PARM;
684 par_from_keyboard_routine=new_fcd_ppm_correction; // PPM value
685 }
686 else if(mouse_y > (fcdgr.ytop+2.5*text_height))
687 {
688 numinput_ypix=fcdgr.ytop+(2.4*text_height)+2;
689 numinput_chars=6;
690 erase_numinput_txt();
691 numinput_flag=FIXED_INT_PARM;
692 par_from_keyboard_routine=new_fcd_vfo_incr; // VFO incr value
693 }
694 }
695 else
696 { // If we did not select a numeric input by setting numinput_flag
697 // we have to set mouse_active flag.
698 // Set the routine to mouse_nothing, we just want to
699 // set flags when the mouse button is released.
700 current_mouse_activity=mouse_nothing;
701 mouse_active_flag=1;
702 }
703 }
704
init_fcdproplus_control_window(void)705 void init_fcdproplus_control_window(void)
706 { int i;
707 int errcod;
708 int *sdr_pi;
709 char fcdprodriver_parfil_name[20];
710 FILE *fcdprodriver_file;
711
712 // Get values from parameterfile
713 sprintf(fcdprodriver_parfil_name,"%s_hwd_fcdgr",rxpar_filenames[rx_mode]);
714 errcod = read_sdrpar(fcdprodriver_parfil_name, MAX_HWAREDRIVER_PARM,
715 fcdprodriver_parm_text, (int*)((void*)&fcdprodriver));
716 if (errcod != 0)
717 {
718 fcdprodriver_file = fopen(fcdprodriver_parfil_name,"w");
719 //set_default_parameter values
720 fcdprodriver.fcdgr_xleft = 60*text_width;
721 fcdprodriver.fcdgr_ytop = (screen_last_line-4)*text_height;
722 fcdprodriver.center_freq = 1000000;
723 fcdprodriver.freq_incr = 100; // khz
724 fcdprodriver.lna_on_off = 1; // on
725 fcdprodriver.mixer_gain_on_off = 1; // on
726 fcdprodriver.if_filter_val = 0;
727 fcdprodriver.if_gain = 0; // dB
728 fcdprodriver.ppm_correction = 0;
729 fcdprodriver.biasT_on_off = 0; // off
730 sdr_pi = (int*)(&fcdprodriver);
731 for( i=0; i<MAX_HWAREDRIVER_PARM; i++ )
732 {
733 fprintf(fcdprodriver_file,"%s [%d]\n",fcdprodriver_parm_text[i],sdr_pi[i]);
734 }
735 parfile_end(fcdprodriver_file);
736 }
737
738 fcdgr.xleft = fcdprodriver.fcdgr_xleft;
739 fcdgr.ytop = fcdprodriver.fcdgr_ytop;
740 // Read state of FCD itself
741 FCDstate = fcdppGetLNA((unsigned char *)&fcdprodriver.lna_on_off);
742 FCDstate = fcdppGetMixerGain((unsigned char *)&fcdprodriver.mixer_gain_on_off);
743 FCDstate = fcdppGetBiasT((unsigned char *)&fcdprodriver.biasT_on_off);
744 FCDstate = fcdppGetIFGain((unsigned char *)&fcdprodriver.if_gain);
745 fg.gain = fcdprodriver.if_gain;
746 fg.passband_center = ((double)fcdprodriver.center_freq) / 1000000.0;
747 fg.passband_increment = ((double)fcdprodriver.freq_incr) / 1000.0;
748
749 fcdgr_msg_color = 10;
750 fcdgr_msg1[0] = 0;
751 fcdgr_hsiz = (30+MAX_MSGSIZE)*text_width; // WIDTH OF USERGRAPH
752 fcdgr_vsiz = (4.8*text_height); // HEIGHT OF USERGRAPH
753 fcdgr.xright = fcdgr.xleft+fcdgr_hsiz;
754 fcdgr.ybottom = fcdgr.ytop+fcdgr_vsiz;
755 if(rx_mode < MODE_TXTEST)
756 {
757 fcdproplus_graph_scro = no_of_scro;
758 make_fcdproplus_control_graph();
759 no_of_scro++;
760 if(no_of_scro >= MAX_SCRO)
761 lirerr(89);
762 }
763 fcdprodriver.dummy = 1; // indicates control window is setup OK.
764 }
765
766 /////////////////////
767 // FCDPP I/O routines
768 /////////////////////
769
fcdppGetBiasT(unsigned char * state)770 int fcdppGetBiasT(unsigned char *state)
771 { return read_value_from_fcd(FCD_HID_CMD_GET_BIAS_TEE, state);
772 }
773
fcdppGetIFGain(unsigned char * value)774 int fcdppGetIFGain(unsigned char *value)
775 { return read_value_from_fcd(FCD_HID_CMD_GET_IF_GAIN, value);
776 }
777
fcdppGetLNA(unsigned char * state)778 int fcdppGetLNA(unsigned char *state)
779 { return read_value_from_fcd(FCD_HID_CMD_GET_LNA_GAIN, state);
780 }
781
fcdppGetMixerGain(unsigned char * state)782 int fcdppGetMixerGain(unsigned char *state)
783 { return read_value_from_fcd(FCD_HID_CMD_GET_MIXER_GAIN, state);
784 }
785
fcdppSetBiasT(unsigned char state)786 int fcdppSetBiasT(unsigned char state)
787 { return write_value_to_fcd(FCD_HID_CMD_SET_BIAS_TEE, state, NULL);
788 }
789
fcdppSetFreq(unsigned int nufreq,unsigned int * fcdfreq)790 int fcdppSetFreq(unsigned int nufreq, unsigned int *fcdfreq)
791 { return write_value_to_fcd(FCD_HID_CMD_SET_FREQUENCY_HZ, nufreq, fcdfreq);
792 }
793
fcdppSetIFGain(unsigned char value)794 int fcdppSetIFGain(unsigned char value)
795 { return write_value_to_fcd(FCD_HID_CMD_SET_IF_GAIN, value, NULL);
796 }
797
fcdppSetLNA(unsigned char state)798 int fcdppSetLNA(unsigned char state)
799 { return write_value_to_fcd(FCD_HID_CMD_SET_LNA_GAIN, state, NULL);
800 }
801
fcdppSetMixerGain(unsigned char state)802 int fcdppSetMixerGain(unsigned char state)
803 { return write_value_to_fcd(FCD_HID_CMD_SET_MIXER_GAIN, state, NULL);
804 }
805
806 //////////////////////////////////////////////////////////////////
807 //
808 // I/O routines using HID for the FCDProPlus
809 //
810 //////////////////////////////////////////////////////////////////
811 // identifiers for the FCDPP USB interface
812 #define USB_VEND 0x04d8 // USB vendor ID (Microchip Technology Inc.)
813 #define USB_PROD 0xfb31 // USB product ID
814 #define FCD_BUFF 65
815
read_value_from_fcd(unsigned char cmd,unsigned char * fcdbyte)816 int read_value_from_fcd(unsigned char cmd, unsigned char *fcdbyte)
817 { hid_device *fcd_hid;
818 unsigned char buff[FCD_BUFF];
819 int result;
820
821 fcd_hid = hid_open(USB_VEND, USB_PROD, NULL);
822 if ( fcd_hid == NULL )
823 return FCD_NOTFOUND;
824
825 memset(buff, 0, FCD_BUFF);
826 buff[0] = 0; // Report ID. Ignored by FCDPP
827 buff[1] = cmd;
828 result = hid_write(fcd_hid, buff, FCD_BUFF);
829 if ( result < 0 )
830 fprintf( stderr,"read_value_from_fcd: hid_write=%d\n", result);
831
832 memset(buff, 0, FCD_BUFF);
833 result = hid_read(fcd_hid, buff, FCD_BUFF);
834 if ( result < 0 )
835 fprintf( stderr,"read_value_from_fcd: hid_read=%d\n", result);
836
837 hid_close(fcd_hid);
838
839 if ( (buff[0] == cmd) && (buff[1] == 1) )
840 { *fcdbyte = buff[2];
841 return FCD_RUNNING;
842 }
843 return FCD_BOOTLOAD;
844 }
845
write_value_to_fcd(unsigned char cmd,unsigned int fcdvalue,unsigned int * fcdfreq)846 int write_value_to_fcd(unsigned char cmd, unsigned int fcdvalue, unsigned int *fcdfreq)
847 { hid_device *fcd_hid;
848 unsigned char buff[FCD_BUFF]; // buffer to be written to and read from FCDPP
849 int result;
850
851 fcd_hid = hid_open(USB_VEND, USB_PROD, NULL);
852 if ( fcd_hid == NULL )
853 return FCD_NOTFOUND;
854
855 memset(buff, 0, FCD_BUFF);
856 buff[0] = 0; // Report ID. Ignored by FCDPP
857 buff[1] = cmd;
858 buff[2] = (unsigned char) fcdvalue & 0xFF; // most values are single char only
859 buff[3] = (unsigned char) (fcdvalue >> 8) & 0xFF; // Freq needs these extra 3 bytes.
860 buff[4] = (unsigned char) (fcdvalue >> 16) & 0xFF;
861 buff[5] = (unsigned char) (fcdvalue >> 24) & 0xFF;
862 result = hid_write(fcd_hid, buff, FCD_BUFF);
863 if ( result < 0 )
864 fprintf( stderr,"write_value_to_fcd: hid_write=%d\n", result);
865
866 memset(buff, 0, FCD_BUFF);
867 result = hid_read(fcd_hid, buff, FCD_BUFF);
868 if ( result < 0 )
869 fprintf( stderr,"write_value_to_fcd: hid_read=%d\n", result);
870
871 hid_close(fcd_hid);
872
873 if ( buff[0]==FCD_HID_CMD_SET_FREQUENCY_HZ && buff[1]==1 )
874 { if (fcdfreq != NULL)
875 { *fcdfreq = (unsigned int) buff[2];
876 *fcdfreq += (unsigned int) (buff[3] << 8);
877 *fcdfreq += (unsigned int) (buff[4] << 16);
878 *fcdfreq += (unsigned int) (buff[5] << 24);
879 }
880 }
881
882 if ( buff[0] == cmd )
883 return FCD_RUNNING;
884
885 return FCD_BOOTLOAD;
886 }
887
888 #endif
889