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