1 //
2 // Code for the Elektor USB SDR
3 //
4 // Driver for the USB SDR as described in the May 2007 Elektor magazine.
5 //
6 // Based on users_tr.c from Linrad, and on SDRelektor.pas from
7 // Burkhard Kainka, and ElektorSDR4Linux.c by Markus Goppelt,
8 // which are available at web-site :- http://www.b-kainka.de
9 //
10 // This driver requires the USB FTDI Driver library, libftdi.
11 //
12 //
13 //
14 // M. J. Keehan, 12th Feb 2013 (mike@keehan.net)
15 //
16 //
17 //
18 // USERGUIDE
19 //
20 // Moving the usergraphic:
21 // Move the usergraphic on the screen by hitting the left side of the box
22 // with the mousepointer, holding the left mouse button down, and dragging
23 // it to the desired position. Also works with the upper side.
24 //
25 // Setting the VFO frequency:
26 // Enter a value in Mhz into the upper field in the small Frequency/Gain box.
27 // Or click on the adjacent up/down arrows to shift the frequency by the
28 // increment value (default 20kHz).
29 // Elektor's frequency band is calculated from the frequency entered.
30 //
31 // Frequency increment
32 // The value used in the frequency up/down arrows, default 20kHz, range 1kHz-1MHz.
33 //
34 // Aerial Multiplexor (Mux)
35 // The eight mux settings can be chosen manually by either entering the number
36 // (0-7) into the Mux box, or by incrementing/decrementing using the associated
37 // buttons. Choosing the value 8 puts the software into Automatic mode, where
38 // the Mux is chosen according to the frequency in use.
39 //
40 // Pre-Selector
41 // Elektor's PreSelector option board is catered for. The preselector
42 // settings are loaded from a file - with the name stored in the variable
43 // 'preselector_parfile_name' - when Linrad starts.
44 // The values will be sent to the board when Mux is set to 3,4,5 or 6, or if
45 // Mux is set to 8 (auto), then the Aerial Mux to use is chosen from the
46 // available preselector channels if one covers the current tuning frequency.
47 // The Pre-Selector has a range of 8 bits for its settings, i.e. values 0 - 255.
48 // This canbe entered manually, or by use of coarse buttons which increment/decrement
49 // by 10, or by fine buttons which increment/decrement by 1.
50 // If no file exists at startup, then all preselector values are set to 0, and
51 // manual input is required for each specific presel channel to tune it.
52 //
53 // Pre-Selector tuning
54 // The preselector can be tuned when Mux=3,4,5,6 or 8.
55 // When Aerial Mux=8 is selected, preselector tuning points are not saved to file.
56 // When specific preselector channels are chosen, i.e. Mux=3,4,5 or 6, then when
57 // preselector tuning is performed, the settings are saved to the parameter file.
58 // An array of ten values are kept in memory to cover the preselector range.
59 // The software maintains a guard value at each end of the array, both to
60 // ensure that the limit values are present (0 & 255), and to make
61 // interpolation between settings easier to determine when near band edges.
62 // The software interpolates linearly between the
63 // array values as the frequency is changed.
64 // The software tries to keep entries spaced more than ~5% apart by frequency.
65 // The contents of the preselector parfile can be edited by hand if values
66 // closer than 5% are required, or change the divisor used in function
67 // withinXpercent() below.
68 // To clear all settings and setup anew, edit the file and delete all values
69 // for the required preselector channel(s), or delete the whole file. Restart
70 // Linrad and tune the preselector at up to ten signals spread across the
71 // preselector's tuning range. It is not necessary to find signals which make
72 // the values 0 and 255 as the software will extrapolate these from whatever
73 // values are in the array. Neither is it necessary to go through all ten
74 // tunings, just as many as you need accurate settings for.
75 // The file format is described in the comments to the function
76 // "Load_PreSelectFile" at the end of this source.
77 //
78 // Fine tune the Crystal
79 // The Elektor's 10MHz crystal can be fine tuned over the range 0-255 in the
80 // lowest line of the usergraphic box. Either enter a value by clicking on
81 // the current value and using the keyboard, or use the up/down arrow keys
82 // to increment/decrement the current value. The actual frequency change
83 // represented by this range (0-255) depends upon the crystal itself. I get
84 // approx +-1.1kHz at 10MHz.
85 //
86 // Test signal
87 // The Elektor provides a test signal at 5MHz on aerial Mux 7, at a strength
88 // of S9 +40dB.
89 //
90 // Note: The usergraphic position, the Xtal fine tune, and frequency increment
91 // values for each frequency band are saved in a parameterfile and are
92 // retrieved when Linrad is started.
93 // The file name is "par_xxx_elektor" (with xxx = rx_mode) and its
94 // content can be displayed (and changed - carefully) with an editor.
95 //
96 //
97
98
99
100 #include <string.h>
101 #include <sys/types.h>
102 #include <sys/stat.h>
103 #include <unistd.h>
104 #include <fcntl.h>
105 #include "loadusb.h"
106 #include "uidef.h"
107 #include "fft1def.h"
108 #include "screendef.h"
109 #include "seldef.h"
110 #include "rusage.h"
111 #include "thrdef.h"
112
113
114
115 #define IIC_EEPROM 208 // Elektor's hardware interface
116 #define IIC_RAM 210 // Elektor's hardware interface
117 #define PCF8951_ADDRESS 0x90 // Elektor's preselector interface
118 #define DAC_ENABLE 0x40 // Elektor's preselector interface
119
120
121 // UserGraphic Button defs.
122 #define UG_TOP 0
123 #define UG_BOTTOM 1
124 #define UG_LEFT 2
125 #define UG_RIGHT 3
126 #define UG_INCREASE_OFFS_XTAL 4
127 #define UG_DECREASE_OFFS_XTAL 5
128 #define UG_INCREASE_OFFS_KHZ 6
129 #define UG_DECREASE_OFFS_KHZ 7
130 #define UG_INCREASE_MUX_NMBR 8
131 #define UG_DECREASE_MUX_NMBR 9
132 #define UG_INCREASE_PRESEL 10
133 #define UG_DECREASE_PRESEL 11
134 #define UG_INCREASE_PRESELFINE 12
135 #define UG_DECREASE_PRESELFINE 13
136 #define MAX_EGRBUTT 14
137
138 //Size of messages in user graphic box
139 #define MAX_MSGSIZE 30
140
141
142 // Elektor Global variables.
143 // =========================
144 int FreqWanted;
145 int Fdti_Data_Count=0;
146 int Mux = 8; // Automatic mode
147 int ActiveMux = -1;
148 int VFOhigh;
149 int Write_Pins=0;
150 int PreselUpdated = 0;
151 unsigned char Div1N;
152 unsigned char FT_port;
153 unsigned char FtdiData[65536];
154
155 char* preselector_parfile_name={"par_elektor_preselector"};
156
157 struct bands
158 { int Min[6];
159 int Max[6];
160 int VFOhigh[6];
161 unsigned char Div1N[6];
162 float High[6];
163 } bands_struct;
164
165 #define NUM_SETTINGS 10 // Allow for 10 PreSelector calibration values
166 struct preselval {
167 int freq[NUM_SETTINGS+2]; // adds a guard entry at each end.
168 int val[NUM_SETTINGS+2]; // ditto.
169 } PreSelData[4]; // Four pre-selector front-ends.
170 int PreSelValue = 0;
171
172 struct ftdi_context ftdic;
173
174
175 #define MAX_HWAREDRIVER_PARM 16
176 char *elektordriver_parm_text[MAX_HWAREDRIVER_PARM]={
177 "egr_xleft ",
178 "egr_ytop ",
179 "mux_number ",
180 "xtal_fine_0.1-0.8 ",
181 "xtal_fine_0.4-1.6 ",
182 "xtal_fine_0.8-3.2 ",
183 "xtal_fine_2-8 ",
184 "xtal_fine_4-16 ",
185 "xtal_fine_10-30 ",
186 "freq_incr_0.1-0.8 ",
187 "freq_incr_0.4-1.6 ",
188 "freq_incr_0.8-3.2 ",
189 "freq_incr_2-8 ",
190 "freq_incr_4-16 ",
191 "freq_incr_10-30 ",
192 "offs_khz_band_BIG ",
193 };
194
195 #define NO_OF_BANDS 6
196 typedef struct {
197 int egr_xleft;
198 int egr_ytop;
199 int aerial;
200 int offs_hz[NO_OF_BANDS];
201 int offs_khz[NO_OF_BANDS];
202 int offs_khz_band_BIG;
203 } HWAREDRIVER_PARMS;
204 HWAREDRIVER_PARMS elektordriver;
205
206 typedef struct {
207 int ytop;
208 int ybottom;
209 int xleft;
210 int xright;
211 int yborder; // required for move graph
212 } UG_PARMS;
213 UG_PARMS egr;
214
215 BUTTONS egrbutt[MAX_EGRBUTT];
216
217 int egr_old_y1;
218 int egr_old_y2;
219 int egr_old_x1;
220 int egr_old_x2;
221 int egr_oldx; // required for move graph
222 int egr_oldy; // required for move graph
223 int egr_yborder; // required for move graph
224 int egr_hsiz; // required for move graph
225 int egr_vsiz; // required for move graph
226 int egr_band_no;
227 int elektor_graph_scro;
228
229 char egr_msg0[MAX_MSGSIZE]; //messages in usergraph
230 char egr_msg1[MAX_MSGSIZE];
231 char egr_msg2[MAX_MSGSIZE];
232 int egr_msg_color; //switch for message-color in usergraph
233
234
235 // Prototypes
236 void append_freq(char *, double);
237 void add_guard_values(int);
238 void calc_Band(double);
239 int calc_Mux(double);
240 void calc_PreselVal(int);
241 void ChangeElektorFreq(int);
242 double EFreq(int);
243 void ftdi_I2C_Init(void);
244 void ftdi_I2C_Start(void);
245 void ftdi_I2C_Stop(void);
246 void ftdi_I2C_Write_Byte(int);
247 void I2C_Init(void);
248 void i2c_write_reg(int, int, int);
249 void init_bands(void);
250 int init_Elektor(void);
251 void Load_PreSelectFile(void);
252 void print_array(void);
253 void save_presel_to_file(void);
254 void SCL(int);
255 void SDA(int);
256 int Set_Elektor_Atten(int);
257 int Set_Elektor_Freq(double);
258 int Set_Elektor_Mux(int);
259 int Set_Elektor_PreSelect(void);
260 void SetupBytes(unsigned char);
261 void Setup_Preselector(void);
262 void show_elektor_parms(void);
263 void Start(void);
264 void Stop(void);
265 void update_presel_settings(int, int);
266 int valid_Presel(int);
267 int withinXpercent(int, int, int);
268 void WriteData(void *, int);
269
270
elektor_setup(void)271 void elektor_setup(void)
272 {
273 int retval;
274 retval=load_ftdi_library();
275 if(retval != 0)return;
276 // Routine to set up elektor from the soundcard setup menu.
277 clear_screen();
278 lir_text(3,3,"Elektor selected. (Nothing to do)");
279 lir_text(3,6,press_any_key);
280 await_processed_keyboard();
281 }
282
283
284 // ***************************************************************************
285 // ROUTINES FOR THE PROCESSING OF A 'MOVABLE' FIXED SIZE USERGRAPH
286 // The screenposition of the usergraph and its variables are saved
287 // in the parameterfile "par_xxx_elektor" ( with xxx = rx_mode)
288 // in the linrad directory
289 // ***************************************************************************
check_egr_borders(void)290 void check_egr_borders(void) // required for move graph
291 {
292 current_graph_minh=egr_vsiz;
293 current_graph_minw=egr_hsiz;
294 check_graph_placement((void*)(&egr));
295 set_graph_minwidth((void*)(&egr));
296 }
297
make_elektor_control_graph(void)298 void make_elektor_control_graph(void)
299 {
300 pause_thread(THREAD_SCREEN);
301
302 check_egr_borders(); // required for move graph
303 scro[elektor_graph_scro].no=ELEKTOR_GRAPH;
304
305 // These are the coordinates of the border lines.
306 scro[elektor_graph_scro].x1=egr.xleft;
307 scro[elektor_graph_scro].x2=egr.xright;
308 scro[elektor_graph_scro].y1=egr.ytop;
309 scro[elektor_graph_scro].y2=egr.ybottom;
310
311 // Each border line is treated as a button.
312 // That is for the mouse to get hold of them so the window can be moved.
313 egrbutt[UG_LEFT].x1=egr.xleft;
314 egrbutt[UG_LEFT].x2=egr.xleft+2;
315 egrbutt[UG_LEFT].y1=egr.ytop;
316 egrbutt[UG_LEFT].y2=egr.ybottom;
317 egrbutt[UG_RIGHT].x1=egr.xright;
318 egrbutt[UG_RIGHT].x2=egr.xright-2;
319 egrbutt[UG_RIGHT].y1=egr.ytop;
320 egrbutt[UG_RIGHT].y2=egr.ybottom;
321 egrbutt[UG_TOP].x1=egr.xleft;
322 egrbutt[UG_TOP].x2=egr.xright;
323 egrbutt[UG_TOP].y1=egr.ytop;
324 egrbutt[UG_TOP].y2=egr.ytop+2;
325 egrbutt[UG_BOTTOM].x1=egr.xleft;
326 egrbutt[UG_BOTTOM].x2=egr.xright;
327 egrbutt[UG_BOTTOM].y1=egr.ybottom;
328 egrbutt[UG_BOTTOM].y2=egr.ybottom-2;
329
330 // Draw the border lines
331 graph_borders((void*)&egr,7);
332 egr_oldx=-10000; // from freq_control
333 settextcolor(7);
334 make_button(egr.xleft+27.5*text_width+2,-2+egr.ybottom-1*text_height/2-1,
335 egrbutt,UG_DECREASE_OFFS_XTAL,25);
336 make_button(egr.xleft+29*text_width+2,-2+egr.ybottom-1*text_height/2-1,
337 egrbutt,UG_INCREASE_OFFS_XTAL,24);
338
339 make_button(egr.xleft+27.5*text_width+2,-2+egr.ybottom-3*text_height/2-1,
340 egrbutt,UG_DECREASE_OFFS_KHZ,25);
341 make_button(egr.xleft+29*text_width+2,-2+egr.ybottom-3*text_height/2-1,
342 egrbutt,UG_INCREASE_OFFS_KHZ,24);
343
344 make_button(egr.xleft+27.5*text_width+2,-2+egr.ybottom-5*text_height/2-1,
345 egrbutt,UG_DECREASE_MUX_NMBR,25);
346 make_button(egr.xleft+29*text_width+2,-2+egr.ybottom-5*text_height/2-1,
347 egrbutt,UG_INCREASE_MUX_NMBR,24);
348 // presel buttons
349 make_button(egr.xleft+54*text_width+2,-3+egr.ybottom-1*text_height/2-1,
350 egrbutt,UG_DECREASE_PRESEL,25);
351 make_button(egr.xleft+55.5*text_width+2,-3+egr.ybottom-1*text_height/2-1,
352 egrbutt,UG_DECREASE_PRESELFINE,25);
353 make_button(egr.xleft+57*text_width+2,-3+egr.ybottom-1*text_height/2-1,
354 egrbutt,UG_INCREASE_PRESELFINE,24);
355 make_button(egr.xleft+58.5*text_width+2,-3+egr.ybottom-1*text_height/2-1,
356 egrbutt,UG_INCREASE_PRESEL,24);
357
358 // Draw separator lines in usergraph
359 // vertical
360 lir_line(egr.xleft+30.5*text_width,egr.ytop+1.3*text_height,
361 egr.xleft+30.5*text_width,egr.ybottom,7);
362 // horizontal
363 lir_line(egr.xleft,egr.ytop+1.3*text_height,egr.xright,egr.ytop+1.3*text_height,7);
364
365 elektor_rx_freq_control();
366 show_elektor_parms();
367 resume_thread(THREAD_SCREEN);
368 }
369
blankfill_egrmsg(char * msg)370 void blankfill_egrmsg(char *msg)
371 { int i;
372
373 i=strlen(msg);
374 if(i>=MAX_MSGSIZE)
375 lirerr(3413400);
376 while(i<MAX_MSGSIZE-1)
377 {
378 msg[i]=' ';
379 i++;
380 }
381 msg[MAX_MSGSIZE-1]=0;
382 }
383
384 // Show the user parameters on screen
show_elektor_parms(void)385 void show_elektor_parms(void)
386 { char s[80];
387 char *mode = "";
388
389 if ( elektordriver.offs_khz_band_BIG == 0 ) // if control window does not yet exist, exit.
390 return;
391
392 switch(rx_mode)
393 {
394 case MODE_WCW: mode = "WCW"; break;
395 case MODE_HSMS: mode = "HSMS"; break;
396 case MODE_QRSS: mode = "QRSS"; break;
397 case MODE_NCW: mode = "NCW"; break;
398 case MODE_SSB: mode = "SSB"; break;
399 case MODE_FM: mode = "FM "; break;
400 case MODE_AM: mode = "AM "; break;
401 }
402
403 // Note that mouse control is done in the narrowband processing thread
404 // and that you can not use lir_sleep to wait for hardware response here.
405 hide_mouse(egr.xleft, egr.xright,egr.ytop,egr.ybottom);
406 settextcolor(11);
407 sprintf(s," LINRAD SDR (Elektor USB) %s", mode);
408 settextcolor(14);
409 lir_pixwrite(egr.xleft+17.5*text_width,egr.ytop+0.35*text_height,s);
410 settextcolor(15);
411 sprintf(s," Aerial Mux: %d ", Mux);
412 lir_pixwrite(egr.xleft+.5*text_width,egr.ytop+1.5*text_height,s);
413
414 egr_msg_color=10;
415 settextcolor(15);
416 sprintf(s,"Fine tune Xtal : %d ", elektordriver.offs_hz[egr_band_no]);
417 s[25]=0;
418 lir_pixwrite(egr.xleft+1.5*text_width,egr.ytop+1+3.5*text_height,s);
419 sprintf(s,"Freq incr (Khz): %d ", elektordriver.offs_khz[egr_band_no]);
420 s[25]=0;
421 lir_pixwrite(egr.xleft+1.5*text_width,egr.ytop+2.5*text_height,s);
422
423 sprintf(egr_msg0,"Elektor Freq: ");
424 append_freq(egr_msg0,EFreq(FreqWanted)*1000);
425 //sprintf(egr_msg1,"Linrad Freq: ");
426 //append_freq(egr_msg1,floor(hwfreq+0.5)*1000);
427 if ( ActiveMux >= 3 && ActiveMux <= 6 )
428 sprintf(egr_msg2,"Preselect: %d %5d", ActiveMux-2, PreSelValue);
429 else
430 sprintf(egr_msg2,"Preselect: none ");
431 blankfill_egrmsg(egr_msg0);
432 //blankfill_egrmsg(egr_msg1);
433 blankfill_egrmsg(egr_msg2);
434 egr_msg2[MAX_MSGSIZE-8]=0;
435 settextcolor(egr_msg_color);
436 lir_pixwrite(egr.xleft+31*text_width,egr.ytop+1.5*text_height,egr_msg0);
437 //lir_pixwrite(egr.xleft+31*text_width,egr.ytop+2.5*text_height,egr_msg1);
438 lir_pixwrite(egr.xleft+31*text_width,egr.ytop+3.5*text_height,egr_msg2);
439 settextcolor(7);
440 }
441
save_elektor_parms(void)442 void save_elektor_parms(void)
443 { int i;
444 int *sdr_pi;
445 char elektordriver_parfil_name[20];
446 FILE *elektordriver_file;
447
448 // Save screenposition, mux-number, and other values
449 // to the parameterfile on disk
450 sprintf(elektordriver_parfil_name,"%s_hwd_egr",rxpar_filenames[rx_mode]);
451 elektordriver_file = fopen(elektordriver_parfil_name,"w");
452 elektordriver.egr_xleft = egr.xleft;
453 elektordriver.egr_ytop = egr.ytop;
454 elektordriver.aerial = Mux;
455 sdr_pi = (int*)(&elektordriver);
456
457 for(i=0; i<MAX_HWAREDRIVER_PARM; i++)
458 fprintf(elektordriver_file,"%s [%d]\n",elektordriver_parm_text[i],sdr_pi[i]);
459
460 parfile_end(elektordriver_file);
461 save_presel_to_file();
462 }
463
mouse_continue_elektor_graph(void)464 void mouse_continue_elektor_graph(void)
465 { int i, j; // required for move graph
466
467 // Move border lines immediately.
468 // Other functions must wait until button is released.
469 // Move fixed size window based on coding in freq_control.c
470 switch (mouse_active_flag-1)
471 {
472 case UG_TOP:
473 if (egr.ytop!=mouse_y)
474 break;
475
476 case UG_BOTTOM:
477 if (egr.ybottom!=mouse_y)
478 break;
479
480 case UG_LEFT:
481 if (egr.xleft!=mouse_x)
482 break;
483
484 case UG_RIGHT:
485 if (egr.xright==mouse_x)
486 break;
487 break;
488
489 default:
490 goto await_release;
491 }
492
493 pause_screen_and_hide_mouse();
494 graph_borders((void*)&egr,0);
495 if (egr_oldx==-10000)
496 {
497 egr_oldx=mouse_x;
498 egr_oldy=mouse_y;
499 }
500 else
501 {
502 i=mouse_x-egr_oldx;
503 j=mouse_y-egr_oldy;
504 egr_oldx=mouse_x;
505 egr_oldy=mouse_y;
506 egr.ytop+=j;
507 egr.ybottom+=j;
508 egr.xleft+=i;
509 egr.xright+=i;
510 check_egr_borders();
511 egr.yborder=(egr.ytop+egr.ybottom)>>1;
512 }
513 graph_borders((void*)&egr,15);
514 resume_thread(THREAD_SCREEN);
515
516 if (leftpressed == BUTTON_RELEASED)
517 goto finish;
518 return;
519
520 await_release:;
521 if (leftpressed != BUTTON_RELEASED)
522 return;
523
524 // Assuming the user wants to control hardware, allow
525 // commands only when data is not over the network.
526 if((ui.network_flag&NET_RX_INPUT) == 0) //for linrad02.23
527 {
528 switch (mouse_active_flag-1)
529 {
530 case UG_INCREASE_OFFS_XTAL:
531 if ( elektordriver.offs_hz[egr_band_no] < 255 )
532 { elektordriver.offs_hz[egr_band_no]++;
533 elektor_rx_freq_control();
534 }
535 break;
536
537 case UG_DECREASE_OFFS_XTAL:
538 if ( elektordriver.offs_hz[egr_band_no] > 0 )
539 { elektordriver.offs_hz[egr_band_no]--;
540 elektor_rx_freq_control();
541 }
542 break;
543
544 case UG_INCREASE_OFFS_KHZ:
545 if ( elektordriver.offs_khz[egr_band_no] < 1000 )
546 { elektordriver.offs_khz[egr_band_no]++;
547 fg.passband_increment = (double) elektordriver.offs_khz[egr_band_no]/1000;
548 }
549 break;
550
551 case UG_DECREASE_OFFS_KHZ:
552 if ( elektordriver.offs_khz[egr_band_no] > 0 )
553 { elektordriver.offs_khz[egr_band_no]--;
554 fg.passband_increment = (double) elektordriver.offs_khz[egr_band_no]/1000;
555 }
556 break;
557
558 case UG_INCREASE_MUX_NMBR:
559 if (Mux <= 7)
560 ++Mux;
561 if ( Mux == 8 ) // have to call set-elektor-freq to do the auto mux
562 Set_Elektor_Freq(fg.passband_center);
563 else
564 Set_Elektor_Mux(Mux);
565 Setup_Preselector();
566 break;
567
568 case UG_DECREASE_MUX_NMBR:
569 if (Mux > 0)
570 --Mux;
571 Set_Elektor_Mux(Mux);
572 Setup_Preselector();
573 break;
574
575 case UG_INCREASE_PRESELFINE:
576 if ( ActiveMux >=3 && ActiveMux <= 6 )
577 if ( PreSelValue < 255 )
578 { PreSelValue++;
579 update_presel_settings(ActiveMux-3, PreSelValue);
580 Set_Elektor_PreSelect();
581 }
582 break;
583
584 case UG_DECREASE_PRESELFINE:
585 if ( ActiveMux >=3 && ActiveMux <= 6 )
586 if ( PreSelValue > 0 )
587 { PreSelValue--;
588 update_presel_settings(ActiveMux-3, PreSelValue);
589 Set_Elektor_PreSelect();
590 }
591 break;
592
593 case UG_INCREASE_PRESEL:
594 if (ActiveMux >=3 && ActiveMux <= 6 )
595 { if ( PreSelValue <= 245 )
596 PreSelValue+=10;
597 else
598 PreSelValue = 255;
599 update_presel_settings(ActiveMux-3, PreSelValue);
600 Set_Elektor_PreSelect();
601 }
602 break;
603
604 case UG_DECREASE_PRESEL:
605 if ( ActiveMux >=3 && ActiveMux <= 6 )
606 { if ( PreSelValue >= 10 )
607 PreSelValue-=10;
608 else
609 PreSelValue = 0;
610 update_presel_settings(ActiveMux-3, PreSelValue);
611 Set_Elektor_PreSelect();
612 }
613 break;
614
615 default: // This should never happen.
616 lirerr(211053);
617 break;
618 }
619 }
620
621 finish:;
622 hide_mouse(egr_old_x1,egr_old_x2,egr_old_y1,egr_old_y2);
623 leftpressed=BUTTON_IDLE;
624 mouse_active_flag=0;
625 graph_borders((void*)&egr,0);
626 lir_fillbox(egr_old_x1,egr_old_y1,egr_old_x2-egr_old_x1,egr_old_y2-egr_old_y1,0);
627 make_elektor_control_graph();
628 egr_oldx=-10000;
629 }
630
new_elektor_presel(void)631 void new_elektor_presel(void)
632 {
633 if ( numinput_int_data >= 0 && numinput_int_data <= 255 )
634 {
635 PreSelValue = numinput_int_data;
636 Set_Elektor_PreSelect();
637 pause_thread(THREAD_SCREEN);
638 show_elektor_parms();
639 resume_thread(THREAD_SCREEN);
640 }
641 }
642
new_elektor_mux(void)643 void new_elektor_mux(void)
644 {
645 if ( numinput_int_data >= 0 && numinput_int_data <= 7 )
646 {
647 Mux = numinput_int_data;
648 Set_Elektor_Mux(Mux);
649 pause_thread(THREAD_SCREEN);
650 show_elektor_parms();
651 resume_thread(THREAD_SCREEN);
652 }
653 else if ( numinput_int_data == 8 )
654 {
655 Mux = numinput_int_data;
656 Set_Elektor_Freq(fg.passband_center);
657 }
658 Setup_Preselector();
659 }
660
new_elektor_offs_xtal(void)661 void new_elektor_offs_xtal(void)
662 {
663 if ( numinput_int_data >= 0 && numinput_int_data <= 255 )
664 {
665 elektordriver.offs_hz[egr_band_no]=numinput_int_data;
666 pause_thread(THREAD_SCREEN);
667 show_elektor_parms();
668 resume_thread(THREAD_SCREEN);
669 elektor_rx_freq_control();
670 }
671 }
672
new_elektor_offs_khz(void)673 void new_elektor_offs_khz(void)
674 {
675 if ( numinput_int_data < 1 )
676 numinput_int_data = 1;
677 if ( numinput_int_data > 1000 )
678 numinput_int_data = 1000;
679
680 elektordriver.offs_khz[egr_band_no]=numinput_int_data;
681 fg.passband_increment = (double) elektordriver.offs_khz[egr_band_no]/1000;
682 pause_thread(THREAD_SCREEN);
683 show_elektor_parms();
684 resume_thread(THREAD_SCREEN);
685 }
686
mouse_on_elektor_graph(void)687 void mouse_on_elektor_graph(void)
688 { int event_no;
689
690 // First find out if we are on a button or border line.
691 for(event_no=0; event_no<MAX_EGRBUTT; event_no++)
692 {
693 if( egrbutt[event_no].x1 <= mouse_x &&
694 egrbutt[event_no].x2 >= mouse_x &&
695 egrbutt[event_no].y1 <= mouse_y &&
696 egrbutt[event_no].y2 >= mouse_y)
697 {
698 egr_old_y1=egr.ytop;
699 egr_old_y2=egr.ybottom;
700 egr_old_x1=egr.xleft;
701 egr_old_x2=egr.xright;
702 mouse_active_flag=1+event_no;
703 current_mouse_activity=mouse_continue_elektor_graph;
704 return;
705 }
706 }
707
708 mouse_active_flag=1;
709
710 if(mouse_x > (egr.xleft+50*text_width) && mouse_x < (egr.xleft+54*text_width))
711 {
712 numinput_xpix=egr.xleft+50*text_width;
713 if( (mouse_y > (egr.ytop+3.8*text_height)) && Mux >=3 && Mux <= 6 )
714 {
715 numinput_ypix=egr.ytop+3.6*text_height;
716 numinput_chars=3;
717 erase_numinput_txt();
718 numinput_flag=FIXED_INT_PARM;
719 par_from_keyboard_routine=new_elektor_presel; // PreSelector tune
720 }
721 }
722 if(mouse_x > egr.xleft+18*text_width && mouse_x < egr.xleft+25*text_width)
723 {
724 numinput_xpix=egr.xleft+18.5*text_width;
725 if(mouse_y > (egr.ytop+3.5*text_height))
726 {
727 numinput_ypix=egr.ytop+3.6*text_height;
728 numinput_chars=4;
729 erase_numinput_txt();
730 numinput_flag=FIXED_INT_PARM;
731 par_from_keyboard_routine=new_elektor_offs_xtal; // Xtal fine tune
732 }
733 else if(mouse_y > (egr.ytop+2.5*text_height))
734 {
735 numinput_ypix=egr.ytop+(2.4*text_height)+2;
736 numinput_chars=5;
737 erase_numinput_txt();
738 numinput_flag=FIXED_INT_PARM;
739 par_from_keyboard_routine=new_elektor_offs_khz; // vfo increment
740 }
741 else if(mouse_y > (egr.ytop+1.5*text_height))
742 {
743 numinput_ypix=egr.ytop+(1.4*text_height)+2;
744 numinput_chars=1;
745 erase_numinput_txt();
746 numinput_flag=FIXED_INT_PARM;
747 par_from_keyboard_routine=new_elektor_mux; // aerial multiplexor
748 }
749 }
750 else
751 {
752 // If we did not select a numeric input by setting numinput_flag
753 // we have to set mouse_active flag.
754 // Set the routine to mouse_nothing, we just want to
755 // set flags when the mouse button is released.
756 current_mouse_activity=mouse_nothing;
757 mouse_active_flag=1;
758 }
759 }
760
init_elektor_control_window(void)761 int init_elektor_control_window(void)
762 { int i;
763 int errcod;
764 int *sdr_pi;
765 char elektordriver_parfil_name[20];
766 FILE *elektordriver_file;
767
768 // Get values from parameterfile
769 sprintf(elektordriver_parfil_name,"%s_hwd_egr",rxpar_filenames[rx_mode]);
770 errcod = read_sdrpar(elektordriver_parfil_name, MAX_HWAREDRIVER_PARM,
771 elektordriver_parm_text, (int*)((void*)&elektordriver));
772 if (errcod != 0)
773 {
774 elektordriver_file = fopen(elektordriver_parfil_name,"w");
775 //set_default_parameter values
776 elektordriver.egr_xleft = 60*text_width;
777 elektordriver.egr_ytop = (screen_last_line-4)*text_height;
778 elektordriver.aerial = 1;
779 for(i=0; i<NO_OF_BANDS; i++)
780 {
781 elektordriver.offs_hz[i] = 127; // middle ~ of range 0-255
782 elektordriver.offs_khz[i] = 20; // default of 20kHz increments
783 }
784 sdr_pi = (int*)(&elektordriver);
785 for( i=0; i<MAX_HWAREDRIVER_PARM; i++ )
786 {
787 fprintf(elektordriver_file,"%s [%d]\n",elektordriver_parm_text[i],sdr_pi[i]);
788 }
789 parfile_end(elektordriver_file);
790 }
791
792 Load_PreSelectFile();
793 Mux = elektordriver.aerial;
794
795 // Need to setup some stuff for Elektor before usergraphic is drawn
796 if(Set_Elektor_Freq(fg.passband_center) != EXIT_SUCCESS)return EXIT_FAILURE;
797 if(Set_Elektor_Atten(fg.gain) != EXIT_SUCCESS)return EXIT_FAILURE;
798 egr.xleft = elektordriver.egr_xleft;
799 egr.ytop = elektordriver.egr_ytop;
800 egr_msg_color = 10;
801 egr_msg1[0] = 0;
802 egr_hsiz = (30+MAX_MSGSIZE)*text_width; // WIDTH OF USERGRAPH
803 egr_vsiz = (4.8*text_height); // HEIGHT OF USERGRAPH
804 egr.xright = egr.xleft+egr_hsiz;
805 egr.ybottom = egr.ytop+egr_vsiz;
806 if(rx_mode < MODE_TXTEST)
807 {
808 elektor_graph_scro = no_of_scro;
809 make_elektor_control_graph();
810 no_of_scro++;
811 if(no_of_scro >= MAX_SCRO)
812 lirerr(89);
813 }
814 elektordriver.offs_khz_band_BIG = 1; // params setup OK now.
815 return EXIT_SUCCESS;
816 }
817
818 // ***************************************************************************
819 // END ROUTINES FOR THE PROCESSING OF A 'MOVABLE' FIXED SIZE USERGRAPH
820 // ***************************************************************************
821
822
823 // Append frequency formatted in Hz or kHz to the end of
824 // the already present text in the MAX_MSGSIZE buffer.
append_freq(char * buffer,double fq)825 void append_freq(char *buffer, double fq)
826 { int j, freq;
827 char *src, *dst, *tail = " Hz", stmp[MAX_MSGSIZE];
828 unsigned u,spaceleft;
829
830 freq = (int)fq; // need Hertz, and not fractions of
831 sprintf(stmp, "%d", freq);
832
833 // Find out how much space is left in given buffer.
834 spaceleft = MAX_MSGSIZE - strlen(buffer) - 1;
835
836 // Change freq to kHz if too many digits present as Hz
837 if ( (strlen(stmp) + strlen(" Hz")) > spaceleft )
838 {
839 freq = freq / 1000; // kHz
840 sprintf(stmp, "%d", freq);
841 tail = " kHz";
842 }
843
844 // space pad the rest of the buffer, and terminate with the tail.
845 for ( u=strlen(buffer) ; u<(MAX_MSGSIZE - strlen(tail) -1) ; ++u )
846 buffer[u] = ' ';
847 strcpy(&buffer[MAX_MSGSIZE - strlen(tail) -1], tail);
848
849 // copy frequency tail first, adding separators every 3rd digit
850 src = &stmp[strlen(stmp)];
851 dst = &buffer[MAX_MSGSIZE - strlen(tail) -1];
852 for ( u=strlen(stmp), j=0 ; u ; --u )
853 {
854 *--dst = *--src;
855 if ( (++j % 3) == 0 && u > 1 ) // but no sep. at front of digits
856 *--dst = ',';
857 }
858 }
859
860 // Is the given entry within X% of the current frequency or Preselect value?
861 // Use simple division - /20 for 5%, /10 for 10%, /32 for 3%...
withinXpercent(int p,int i,int freq)862 int withinXpercent(int p, int i, int freq)
863 { int ret;
864
865 ret = ( abs(PreSelData[p].freq[i]-freq) < (freq/(NUM_SETTINGS+6)) );
866 // fprintf( stderr,"within(%d,%d)=%d\n",pos,freq,ret);
867 return ret;
868 }
869
870 // Update preselector tuning value in memory array
update_presel_settings(int p,int val)871 void update_presel_settings(int p,int val)
872 { int i, j, freq;
873
874 freq = floor(hwfreq);
875 //fprintf( stderr,"up-presel(%d,%d) ",p, val);
876 // If value is close to zero and array is full, replace first position
877 if ( val <= (256 / (NUM_SETTINGS + 6)) && PreSelData[p].freq[NUM_SETTINGS] != 0 )
878 { PreSelData[p].val[1] = val;
879 PreSelData[p].freq[1] = freq;
880 for ( j=2; j<=NUM_SETTINGS; ++j )
881 if ( PreSelData[p].freq[j] <= freq )
882 { PreSelData[p].freq[j] = 0;
883 PreSelData[p].val[j] = 0;
884 }
885 //fprintf( stderr,"PreSelect: 1st replaced\n");
886 add_guard_values(p);
887 PreselUpdated = 1;
888 return;
889 }
890 else // else if value is close to limit and array is full, replace last
891 if ( (val >= 256 - (256 / (NUM_SETTINGS + 6))) && PreSelData[p].freq[NUM_SETTINGS] != 0 )
892 { PreSelData[p].val[NUM_SETTINGS] = val;
893 PreSelData[p].freq[NUM_SETTINGS] = freq;
894 for ( j=NUM_SETTINGS-1; j>=1; --j )
895 if ( PreSelData[p].freq[j] >= freq )
896 { PreSelData[p].freq[j] = 0;
897 PreSelData[p].val[j] = 0;
898 }
899 //fprintf( stderr,"PreSelect: last replaced\n");
900 add_guard_values(p);
901 PreselUpdated = 1;
902 return;
903 }
904
905 for ( i=1; i<=NUM_SETTINGS; ++i )
906 {
907 if ( withinXpercent(p,i,freq) )
908 {
909 PreSelData[p].freq[i] = freq;
910 PreSelData[p].val[i] = val;
911 //fprintf( stderr,"PreSelect: replaced %d\n",i);
912 add_guard_values(p);
913 PreselUpdated = 1;
914 return;
915 }
916
917 if ( PreSelData[p].freq[i] == 0 ) // no entry yet?
918 {
919 PreSelData[p].freq[i] = freq;
920 PreSelData[p].val[i] = val;
921 //fprintf( stderr,"PreSelect: new entry %d\n",i);
922 add_guard_values(p);
923 PreselUpdated = 1;
924 return;
925 }
926
927 if ( PreSelData[p].freq[i] > freq ) // Need to insert?
928 {
929 for ( j=NUM_SETTINGS; j>i; --j )
930 { PreSelData[p].val[j] = PreSelData[p].val[j-1];
931 PreSelData[p].freq[j] = PreSelData[p].freq[j-1];
932 }
933 PreSelData[p].val[i] = val;
934 PreSelData[p].freq[i] = freq;
935 //fprintf( stderr,"PreSelect: inserted %d\n",i);
936 add_guard_values(p);
937 PreselUpdated = 1;
938 return;
939 }
940 }
941
942 // Not found anywhere to put it, force it
943 if ( freq < PreSelData[p].freq[1] )
944 {
945 PreSelData[p].val[1] = val;
946 PreSelData[p].freq[1] = freq;
947 //fprintf( stderr,"PreSelect: forced 1\n");
948 add_guard_values(p);
949 PreselUpdated = 1;
950 }
951 else if ( freq > PreSelData[p].freq[NUM_SETTINGS] )
952 {
953 PreSelData[p].val[NUM_SETTINGS] = val;
954 PreSelData[p].freq[NUM_SETTINGS] = freq;
955 //fprintf( stderr,"PreSelect: force ten\n");
956 add_guard_values(p);
957 PreselUpdated = 1;
958 }
959 }
960
961 // Save current preselector settings to a file.
save_presel_to_file(void)962 void save_presel_to_file(void)
963 { int j, p;
964 FILE *filep;
965
966 if ( PreselUpdated && Mux != 8 ) // Only save changes in manual mode
967 {
968 if ( (filep=fopen(preselector_parfile_name,"w")) != NULL )
969 {
970 // could write out a header for the file, e.g. file documentation?
971 for ( p=0; p<4; ++p )
972 {
973 fprintf(filep, "In%d\n",p+4);
974 for ( j=1; j<=NUM_SETTINGS; ++j )
975 if ( PreSelData[p].freq[j] && (PreSelData[p].freq[j] != PreSelData[p].freq[j-1]) )
976 fprintf(filep, "%d %d\n",PreSelData[p].freq[j], PreSelData[p].val[j]);
977 }
978 // could write out a trailer?
979 fclose(filep);
980 }
981 else
982 fprintf( stderr,"Writing to %s failed: errno=%d\n", preselector_parfile_name, errno);
983 }
984 PreselUpdated = 0;
985 }
986
987 //************************************************************
988 // This is the data entered in the rx gain control box.
989 // int fg.gain_increment = The increment in dB for clicking
990 // the arrows in the gain control box.
991 // The global fg_new_band can be used to allow for different
992 // settings on different bands.
993 //
994 // Uses global data:
995 // int fg.gain
996 //************************************************************
elektor_rx_amp_control(void)997 void elektor_rx_amp_control(void)
998 {
999 fg.gain_increment = 10;
1000
1001 // Elektor has an IF attenuator with 3 settings, 0, -10, -20dB.
1002 if ( fg.gain > -5 )
1003 { fg.gain = 0;
1004 Set_Elektor_Atten(0);
1005 }
1006 else if (fg.gain > -15)
1007 { fg.gain = -10;
1008 Set_Elektor_Atten(-10);
1009 }
1010 else
1011 { fg.gain = -20;
1012 Set_Elektor_Atten(-20);
1013 }
1014 }
1015
update_elektor_rx_frequency()1016 void update_elektor_rx_frequency()
1017 { static double old_hwfreq=0.0;
1018
1019 //fprintf( stderr,"update-freq() cntrfreq=%f, hwfreq=%f\n",fg.passband_center,hwfreq);
1020 // This routine is called from the screen thread.
1021 if ( fabs(old_hwfreq-hwfreq) > 0.001 )
1022 { Setup_Preselector();
1023 old_hwfreq = hwfreq;
1024 show_elektor_parms();
1025 }
1026 }
1027
elektor_rx_freq_control(void)1028 void elektor_rx_freq_control(void)
1029 { static double old_passband = 0;
1030 static int Xtal=-1;
1031 //fprintf( stderr,"freq-control: passbnd=%f, hwfreq=%f\n",fg.passband_center,hwfreq);
1032
1033 fg.passband_direction = 1;
1034 fft1_direction = fg.passband_direction;
1035 if ( elektordriver.offs_khz_band_BIG == 0 ) // not yet read in params.
1036 return;
1037
1038 fg.passband_increment = (double) elektordriver.offs_khz[egr_band_no]/1000;
1039 if ( fg.passband_center < 0.13 )
1040 fg.passband_center = 0.13;
1041 if ( fg.passband_center > 30.0 )
1042 fg.passband_center = 30.0;
1043
1044 if ( (fabs(fg.passband_center-old_passband) >= 0.001) || (Xtal != elektordriver.offs_hz[egr_band_no]) )
1045 {
1046 Set_Elektor_Freq(fg.passband_center);
1047 old_passband = hwfreq;
1048 Xtal = elektordriver.offs_hz[egr_band_no];
1049 }
1050 save_elektor_parms();
1051 }
1052
1053 // ******************************************************************
1054 // ******************************************************************
1055 // ******************************************************************
1056 // Following based on ElektorSDR4Linux.c
1057 // ******************************************************************
1058 // ******************************************************************
1059 // ******************************************************************
1060
init_Elektor(void)1061 int init_Elektor(void)
1062 {
1063 int f;
1064 Fdti_Data_Count = 0;
1065 Write_Pins = 0;
1066 f = ftdi_init(&ftdic);
1067 if (f<0)
1068 {
1069 fprintf( stderr, "ftdi_init failed: %d (%s)\n",
1070 f, ftdi_get_error_string(&ftdic));
1071 return EXIT_FAILURE;
1072 }
1073 f = ftdi_usb_open(&ftdic, 0x0403, 0x6001);
1074 if(f<0)
1075 {
1076 fprintf( stderr, "ftdi_usb_open failed: %d (%s)\n",
1077 f, ftdi_get_error_string(&ftdic));
1078 return EXIT_FAILURE;
1079 }
1080
1081 f = ftdi_set_bitmode(&ftdic, 0xFF, BITMODE_BITBANG);
1082 if (f<0)
1083 {
1084 fprintf( stderr, "ftdi_set_bitmode failed: %d (%s)\n", f,
1085 ftdi_get_error_string(&ftdic));
1086 return EXIT_FAILURE;
1087 }
1088 f = ftdi_set_baudrate(&ftdic, 38400/2); // 38400 is too fast for preselector
1089 if (f<0)
1090 {
1091 fprintf( stderr, "ftdi_set_baudrate failed: %d (%s)\n",
1092 f, ftdi_get_error_string(&ftdic));
1093 return EXIT_FAILURE;
1094 }
1095 f = ftdi_read_pins(&ftdic, &FT_port);
1096 if (f<0)
1097 {
1098 fprintf( stderr, "ftdi_read_pins failed: %d (%s)\n",
1099 f, ftdi_get_error_string(&ftdic));
1100 return EXIT_FAILURE;
1101 }
1102 return EXIT_SUCCESS;
1103 }
1104
Send_To_FTDI(void)1105 int Send_To_FTDI(void)
1106 {
1107 int f;
1108 if (!(Fdti_Data_Count>0) && Write_Pins)
1109 {
1110 FtdiData[Fdti_Data_Count] = FT_port;
1111 Fdti_Data_Count++;
1112 }
1113 f = ftdi_write_data_set_chunksize(&ftdic, 16384);
1114 if (f<0)
1115 {
1116 fprintf( stderr, "ftdi_write_data_set_chunksize: %d (%s)\n",
1117 f, ftdi_get_error_string(&ftdic));
1118 Write_Pins = 0;
1119 return EXIT_FAILURE;
1120 }
1121
1122 f = ftdi_write_data(&ftdic, FtdiData, Fdti_Data_Count);
1123 if (f<0)
1124 {
1125 fprintf( stderr,"ftdi_write failed: %d (%s)\n",
1126 f, ftdi_get_error_string(&ftdic));
1127 }
1128 // fprintf( stderr,"Number of bytes written: %d\n", f);
1129
1130 ftdi_usb_close(&ftdic);
1131 ftdi_deinit(&ftdic);
1132
1133 Fdti_Data_Count = 0;
1134 Write_Pins = 0;
1135
1136 return EXIT_SUCCESS;
1137 }
1138
ChangeElektorFreq(int IICadr)1139 void ChangeElektorFreq(int IICadr)
1140 { int Pump = 1;
1141 unsigned char R40, R41, R42;
1142
1143 if (FreqWanted>479)
1144 {
1145 Pump = 2;
1146 }
1147 if (FreqWanted>639)
1148 {
1149 Pump = 3;
1150 }
1151 if (FreqWanted>799)
1152 {
1153 Pump = 4;
1154 }
1155
1156 R40 = (FreqWanted/2-4)/256+4*Pump+192;
1157 R41 = (FreqWanted/2-4)&255;
1158 if (VFOhigh)
1159 {
1160 R42 = 23 + 128*(FreqWanted%2);
1161 }
1162 else
1163 {
1164 R42 = 48 + 128*(FreqWanted%2);
1165 }
1166
1167 I2C_Init();
1168
1169 Start();
1170 SetupBytes(IICadr);
1171 SetupBytes(64);
1172 SetupBytes(R40);
1173 SetupBytes(R41);
1174 SetupBytes(R42);
1175 Stop();
1176
1177 Start();
1178 SetupBytes(IICadr);
1179 SetupBytes(12);
1180 SetupBytes(Div1N);
1181 Stop();
1182
1183 Start();
1184 SetupBytes(IICadr);
1185 SetupBytes(19);
1186 SetupBytes(elektordriver.offs_hz[egr_band_no]);
1187 Stop();
1188 }
1189
I2C_Init(void)1190 void I2C_Init(void)
1191 {
1192 SCL(1);
1193 SDA(1);
1194 }
1195
Start(void)1196 void Start(void)
1197 {
1198 SDA(0);
1199 SCL(0);
1200 }
1201
Stop(void)1202 void Stop(void)
1203 {
1204 SCL(0);
1205 SDA(0);
1206 SCL(1);
1207 SDA(1);
1208 }
1209
SDA(int TXD)1210 void SDA(int TXD)
1211 {
1212 if (TXD)
1213 {
1214 FT_port = FT_port|1;
1215 }
1216 else
1217 {
1218 FT_port = FT_port&(255-1);
1219 }
1220 FtdiData[Fdti_Data_Count] = FT_port;
1221 Fdti_Data_Count++;
1222 }
1223
SCL(int RXD)1224 void SCL(int RXD)
1225 {
1226 if (RXD)
1227 {
1228 FT_port = FT_port|2;
1229 }
1230 else
1231 {
1232 FT_port = FT_port&(255-2);
1233 }
1234 FtdiData[Fdti_Data_Count] = FT_port;
1235 Fdti_Data_Count++;
1236 }
1237
SetupBytes(unsigned char Value)1238 void SetupBytes(unsigned char Value)
1239 { int i = 128;
1240
1241 while (i>0)
1242 {
1243 if (Value&i)
1244 {
1245 SDA(1);
1246 }
1247 else
1248 {
1249 SDA(0);
1250 }
1251 SCL(1);
1252 SCL(0);
1253 i = i/2;
1254 }
1255 SDA(1);
1256 SCL(1);
1257 SCL(0);
1258 }
1259
init_bands(void)1260 void init_bands(void)
1261 {
1262 bands_struct.VFOhigh[0] = 1;
1263 bands_struct.VFOhigh[1] = 0;
1264 bands_struct.VFOhigh[2] = 0;
1265 bands_struct.VFOhigh[3] = 0;
1266 bands_struct.VFOhigh[4] = 0;
1267 bands_struct.VFOhigh[5] = 0;
1268
1269 bands_struct.Min[0] = 400;
1270 bands_struct.Min[1] = 400;
1271 bands_struct.Min[2] = 400;
1272 bands_struct.Min[3] = 400;
1273 bands_struct.Min[4] = 400;
1274 bands_struct.Min[5] = 260;
1275
1276 bands_struct.Max[0] = 1200;
1277 bands_struct.Max[1] = 1600;
1278 bands_struct.Max[2] = 1600;
1279 bands_struct.Max[3] = 1600;
1280 bands_struct.Max[4] = 1600;
1281 bands_struct.Max[5] = 1600;
1282
1283 bands_struct.Div1N[0] = 4;
1284 bands_struct.Div1N[1] = 5;
1285 bands_struct.Div1N[2] = 10;
1286 bands_struct.Div1N[3] = 25;
1287 bands_struct.Div1N[4] = 50;
1288 bands_struct.Div1N[5] = 100;
1289
1290 bands_struct.High[0] = 30.0;
1291 bands_struct.High[1] = 16.0;
1292 bands_struct.High[2] = 8.0;
1293 bands_struct.High[3] = 3.2;
1294 bands_struct.High[4] = 1.6;
1295 bands_struct.High[5] = 0.8;
1296 }
1297
Set_Elektor_Atten(int atten)1298 int Set_Elektor_Atten(int atten) // 0, 10, 20.
1299 {
1300 static int old_Atten=-1;
1301 if ( atten == old_Atten )
1302 return EXIT_SUCCESS;
1303 if(init_Elektor() != EXIT_SUCCESS)return EXIT_FAILURE;
1304 FT_port = FT_port&0x1F;
1305 switch(atten)
1306 {
1307 case 0: FT_port = FT_port+32*0; break;
1308 case -10: FT_port = FT_port+32*1; break;
1309 case -20: FT_port = FT_port+32*2; break;
1310 default: return EXIT_SUCCESS;
1311 }
1312 Write_Pins = 1;
1313 if(Send_To_FTDI() != EXIT_SUCCESS)return EXIT_FAILURE;
1314 old_Atten = atten;
1315 return EXIT_SUCCESS;
1316 }
1317
Set_Elektor_Mux(int new)1318 int Set_Elektor_Mux(int new) // 0-8, where 8=automatic.
1319 { static int old_Mux = -1;
1320 //fprintf( stderr,"SetMux %d, Active=%d\n",new,ActiveMux);
1321
1322 if ( (new != old_Mux) && (new != 8) )
1323 {
1324 if(init_Elektor() != EXIT_SUCCESS)return EXIT_FAILURE;
1325
1326 FT_port = FT_port&0x63;
1327 FT_port = FT_port+4*new;
1328 Write_Pins=1;
1329 if(Send_To_FTDI() != EXIT_SUCCESS)return EXIT_FAILURE;
1330 old_Mux = ActiveMux = new;
1331 }
1332 return EXIT_SUCCESS;
1333 }
1334
Set_Elektor_Freq(double CenterFreq)1335 int Set_Elektor_Freq(double CenterFreq) // CenterFreq in MHz
1336 {
1337 //fprintf( stderr,"CenterFreq=%f, hwfreq=%f\n",CenterFreq,hwfreq);
1338
1339 // Limit the requested frequency to what is possible on Elektor.
1340 if ( CenterFreq < 0.13 ) // min freq is 130kHz.
1341 CenterFreq = 0.13;
1342 if ( CenterFreq > 30.0 ) // max freq is 30MHz.
1343 CenterFreq = 30.0;
1344
1345 calc_Band(CenterFreq);
1346 Set_Elektor_Mux(calc_Mux(CenterFreq));
1347 Setup_Preselector();
1348 if ( VFOhigh )
1349 FreqWanted = (int)((CenterFreq)*4000/(400/Div1N)+0.5);
1350 else
1351 FreqWanted = (int)((CenterFreq)*4000/(200/Div1N)+0.5);
1352
1353 //fprintf( stderr,"FreqWanted:%fkHz, Band:%d, VFOhigh:%d, Div1N:%d\n",EFreq(FreqWanted),egr_band_no,VFOhigh,Div1N);
1354 if(init_Elektor() != EXIT_SUCCESS)return EXIT_FAILURE;
1355 ChangeElektorFreq(IIC_RAM);
1356 if(Send_To_FTDI() != EXIT_SUCCESS)return EXIT_FAILURE;
1357 return EXIT_SUCCESS;
1358 }
1359
Set_Elektor_PreSelect(void)1360 int Set_Elektor_PreSelect(void)
1361 {
1362 static int old_value = 0;
1363
1364 //fprintf( stderr,"SetPreSel %d,old_sel %d\n",PreSelValue, old_value);
1365 if ( old_value != PreSelValue )
1366 {
1367 if(init_Elektor() != EXIT_SUCCESS)return EXIT_FAILURE;
1368 I2C_Init();
1369 Start();
1370 SetupBytes(144);
1371 SetupBytes(64);
1372 SetupBytes(PreSelValue); // value from 0 to 255
1373 Stop();
1374 if(Send_To_FTDI() != EXIT_SUCCESS)return EXIT_FAILURE;
1375 old_value = PreSelValue;
1376 }
1377 return EXIT_SUCCESS;
1378 }
1379
EFreq(int F)1380 double EFreq(int F)
1381 {
1382 if (VFOhigh)
1383 return (double)(F*400/Div1N)/4;
1384
1385 return (double)(F*200/Div1N)/4;
1386 }
1387
calc_Band(double freq)1388 void calc_Band(double freq)
1389 { static int init_done=0;
1390 int old_band_no;
1391
1392 if ( init_done == 0 )
1393 {
1394 init_bands();
1395 init_done = 1;
1396 }
1397
1398 old_band_no = egr_band_no;
1399
1400 if ( freq <= bands_struct.High[5] ) egr_band_no = 5; // 800kHz
1401 else if ( freq <= bands_struct.High[4] ) egr_band_no = 4; // 1.6MHz
1402 else if ( freq <= bands_struct.High[3] ) egr_band_no = 3;
1403 else if ( freq <= bands_struct.High[2] ) egr_band_no = 2;
1404 else if ( freq <= bands_struct.High[1] ) egr_band_no = 1;
1405 else egr_band_no = 0;
1406
1407 if ( old_band_no != egr_band_no )
1408 fg.passband_increment = (double) elektordriver.offs_khz[egr_band_no]/1000;
1409
1410 Div1N = bands_struct.Div1N[egr_band_no];
1411 VFOhigh = bands_struct.VFOhigh[egr_band_no];
1412 }
1413
1414 // Mux settings: 0 - wideband with a simple audio shunt choke
1415 // 1 - Medium Wave, low pass filter at 1.6Mhz
1416 // 2 - Short Wave, via R-C high pass at 1.6MHz
1417 // 3 - PC1 on the Elektor pcb - or PreSel 1 if connected
1418 // 4 - unconnected - or PreSel 2
1419 // 5 - unconnected - or PreSel 3
1420 // 6 - unconnected - or PreSel 4
1421 // 7 - 5MHz calibration signal at S9 +40dB.
1422 // 8 - Automatic. Mux settings are chosen according to
1423 // a suitable pre-selector front-end, or
1424 // to mux1 for < 1.6MHz, or mux2 for >1.6MHz.
calc_Mux(double freq)1425 int calc_Mux(double freq)
1426 {
1427 int i;
1428
1429 //fprintf( stderr,"calc_Mux(%f): oldMux=%d\n",freq,Mux);
1430 if ( Mux != 8 ) // if manual mode selected,
1431 return Mux; // just return the current setting.
1432
1433 // Look through the PreSelector settings for a close match
1434 for ( i=0; i<4; ++i )
1435 if ( valid_Presel(i) )
1436 return i + 3; // found mux positon 3,4,5 or 6
1437
1438 if ( freq < 1.6 ) // Use the MW setting for < 1.6MHz
1439 return 1;
1440
1441 return 2; // Use the SW setting for all others.
1442 }
1443
Setup_Preselector()1444 void Setup_Preselector()
1445 {
1446 //fprintf( stderr,"Setup_Preselector: ActMux=%d\n",ActiveMux);
1447 if ( ActiveMux >= 3 && ActiveMux <= 6 )
1448 {
1449 calc_PreselVal(ActiveMux-3);
1450 Set_Elektor_PreSelect();
1451 }
1452 }
1453
1454 // Does this preselector channel include the current hardware frequency
valid_Presel(int presel)1455 int valid_Presel(int presel)
1456 { int ifreq;
1457
1458 ifreq = (int) floor(hwfreq);
1459 if ( ifreq == 0 ) // initialy, there is no hardware freq value.
1460 ifreq = floor(fg.passband_center)*1000;
1461
1462 if ( PreSelData[presel].freq[0] != 0 // if there is data in this array
1463 && PreSelData[presel].freq[0] <= ifreq // and it brackets the wanted
1464 && PreSelData[presel].freq[NUM_SETTINGS+1] >= ifreq ) // frequency, say yes.
1465 return 1;
1466
1467 return 0;
1468 }
1469
1470 // Look through PreSelector data array for a pair of frequencies that
1471 // bracket the current hardware freq, and interpolate between them.
calc_PreselVal(int presel)1472 void calc_PreselVal(int presel)
1473 { int ifreq,j;
1474 int fspan, vspan, fdiff;
1475
1476 ifreq = (int) floor(hwfreq);
1477 if ( ifreq == 0 )
1478 ifreq = floor(fg.passband_center)*1000;
1479
1480 //fprintf( stderr,"calcPSel(%d), ifreq=%d ",presel,ifreq);
1481 if ( ifreq == 0 )
1482 return;
1483
1484 // only do calculations if necessary.
1485 if ( ifreq <= PreSelData[presel].freq[0] )
1486 PreSelValue = 0;
1487 else if ( ifreq >= PreSelData[presel].freq[NUM_SETTINGS+1] )
1488 PreSelValue = 255;
1489 else
1490 {
1491 for ( j=1; j<=NUM_SETTINGS+1; ++j )
1492 if ( PreSelData[presel].freq[j] >= ifreq || PreSelData[presel].freq[j] == 0 )
1493 break;
1494
1495 fspan = PreSelData[presel].freq[j] - PreSelData[presel].freq[j-1];
1496 vspan = PreSelData[presel].val[j] - PreSelData[presel].val[j-1];
1497 if ( PreSelData[presel].freq[j] == 0 )
1498 { fspan = PreSelData[presel].freq[NUM_SETTINGS+1] - PreSelData[presel].freq[j-1];
1499 vspan = PreSelData[presel].val[NUM_SETTINGS+1] - PreSelData[presel].val[j-1];
1500 }
1501 fdiff = ifreq - PreSelData[presel].freq[j-1];
1502
1503 // Simple linear interpolation between low and high freqs
1504 if ( fspan > 0 )
1505 PreSelValue = PreSelData[presel].val[j-1] + ((vspan * fdiff)/fspan);
1506 else
1507 PreSelValue = PreSelData[presel].val[j-1];
1508 //fprintf( stderr," vspan=%d fdiff=%d fspan=%d ",vspan,fdiff,fspan);
1509 }
1510 //fprintf( stderr," val=%d\n",PreSelValue);
1511 }
1512
1513
1514 // ******************************************************************
1515 // ******************************************************************
1516 // Load the Pre-Selector calibrations
1517 // ******************************************************************
1518 // ******************************************************************
1519 //
1520 // A file of Pre-Selector settings is maintained, one section for
1521 // each of the four possible selector channels.
1522 // Each section can contain upto ten pairs of integers -
1523 // frequency in kiloHertz, and a number between 0 and 255 as the
1524 // pre-selector setting.
1525 // The file format is fairly tolerant of whitespace, and can
1526 // look like this:-
1527 //
1528 // In4
1529 // 1234
1530 // 0
1531 // 1456
1532 // 13
1533 // 1689
1534 // 59
1535 // 2345
1536 // 250
1537 //
1538 // In5
1539 // 2200
1540 // 11
1541 // 3000
1542 // 56
1543 // ... etc.
1544 //
1545 // or this:-
1546 // In4
1547 // 1234 0
1548 // 1456 13
1549 // 1689 59
1550 // ...
1551 // 2345 250
1552 //
1553 // or this:-
1554 // In5 2200 11 3000 56 4000 88 ...
1555 //
1556
1557 // Add a limit entry at each end of the given array (simplifies later processing)
add_guard_values(int p)1558 void add_guard_values(int p)
1559 { int i, j=NUM_SETTINGS+1, hival=0, valdiff, hifreq=0, freqdiff;
1560
1561 // Find highest freq in array
1562 for ( i=1; i<=NUM_SETTINGS; ++i )
1563 if ( PreSelData[p].freq[i] > hifreq )
1564 { hifreq = PreSelData[p].freq[i];
1565 hival = PreSelData[p].val[i];
1566 }
1567
1568 // Calculate the frequencies for the presel values 0 and 255.
1569 valdiff = hival - PreSelData[p].val[1];
1570 freqdiff = hifreq - PreSelData[p].freq[1];
1571
1572 if ( valdiff > 0 && freqdiff > 0 )
1573 { // The order of execution is important for accuracy in following lines
1574 PreSelData[p].freq[0] = PreSelData[p].freq[1] - ((PreSelData[p].val[1]*freqdiff)/valdiff);
1575 if ( PreSelData[p].freq[0] < 0 )
1576 PreSelData[p].freq[0] = 0;
1577 PreSelData[p].val[0] = 0;
1578 PreSelData[p].freq[j] = PreSelData[p].freq[1] + ((255-PreSelData[p].val[1])*freqdiff/valdiff);
1579 PreSelData[p].val[j] = 255;
1580 }
1581 else // No range of values present - so make some arbitrary ones.
1582 {
1583 PreSelData[p].freq[0] = PreSelData[p].freq[1]/2;
1584 PreSelData[p].val[0] = 0;
1585 PreSelData[p].freq[j] = PreSelData[p].freq[1]*2;
1586 PreSelData[p].val[j] = 255;
1587 }
1588 }
1589
Load_PreSelectFile(void)1590 void Load_PreSelectFile(void)
1591 { struct stat statbuf;
1592 int fd, i=-1, size;
1593 char *data, *ptr;
1594
1595 if ( stat(preselector_parfile_name, &statbuf) != 0 )
1596 { fprintf( stderr,"Cannot find %s\n",preselector_parfile_name);
1597 return;
1598 }
1599
1600 size = statbuf.st_size;
1601 data = malloc(size+1);
1602 if ( data == NULL )
1603 { fprintf( stderr,"Not enough memory for %s\n",preselector_parfile_name);
1604 return;
1605 }
1606
1607 fd = open(preselector_parfile_name, O_RDONLY);
1608 if ( fd == -1 )
1609 { fprintf( stderr,"Cannot open %s\n",preselector_parfile_name);
1610 free(data);
1611 return;
1612 }
1613
1614 if ( read(fd, data, size) != size )
1615 { fprintf( stderr,"Cannot read %s\n",preselector_parfile_name);
1616 close(fd);
1617 free(data);
1618 return;
1619 }
1620 close(fd);
1621 data[size]=0;
1622
1623 // Scan the data into the PreSel values arrays.
1624 ptr = data;
1625 while ( ptr!=NULL && ptr<(data + size) )
1626 {
1627 if ( strncmp(ptr, "In", 2) == 0 ) // start of a section
1628 {
1629 if (ptr[2] == '4' ) i = 0; // 1st front end
1630 else if (ptr[2] == '5' ) i = 1; // 2nd
1631 else if (ptr[2] == '6' ) i = 2;
1632 else if (ptr[2] == '7' ) i = 3;
1633 else
1634 { ptr += 3;
1635 continue; // not a valid entry, loop again
1636 }
1637
1638 ptr += 3; // move past the section identifier
1639 if ( i != -1 ) // found a valid front-end entry
1640 {
1641 sscanf(ptr, " %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
1642 &PreSelData[i].freq[1], &PreSelData[i].val[1],
1643 &PreSelData[i].freq[2], &PreSelData[i].val[2],
1644 &PreSelData[i].freq[3], &PreSelData[i].val[3],
1645 &PreSelData[i].freq[4], &PreSelData[i].val[4],
1646 &PreSelData[i].freq[5], &PreSelData[i].val[5],
1647 &PreSelData[i].freq[6], &PreSelData[i].val[6],
1648 &PreSelData[i].freq[7], &PreSelData[i].val[7],
1649 &PreSelData[i].freq[8], &PreSelData[i].val[8],
1650 &PreSelData[i].freq[9], &PreSelData[i].val[9],
1651 &PreSelData[i].freq[10], &PreSelData[i].val[10]);
1652
1653 add_guard_values(i);
1654 }
1655 }
1656 ptr = strstr(ptr, "In");
1657 }
1658 free(data);
1659 // print_array();
1660 }
1661
1662 /*
1663 void print_array(void)
1664 { int i;
1665 // debug printout
1666 fprintf( stderr,"\n");
1667 for ( i=0; i<NUM_SETTINGS+2; ++i )
1668 fprintf( stderr,"%2d In4: %5d %5d In5: %5d %5d In6: %5d %5d In7: %5d %5d\n",
1669 i,
1670 PreSelData[0].freq[i], PreSelData[0].val[i],
1671 PreSelData[1].freq[i], PreSelData[1].val[i],
1672 PreSelData[2].freq[i], PreSelData[2].val[i],
1673 PreSelData[3].freq[i], PreSelData[3].val[i]);
1674
1675 }
1676 */
1677