1 // Copyright (c) <2012> <Leif Asbrink>
2 //
3 // Permission is hereby granted, free of charge, to any person
4 // obtaining a copy of this software and associated documentation
5 // files (the "Software"), to deal in the Software without restriction,
6 // including without limitation the rights to use, copy, modify,
7 // merge, publish, distribute, sublicense, and/or sell copies of
8 // the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
21 // OR OTHER DEALINGS IN THE SOFTWARE.
22 
23 
24 // In case you want to use the WSE converters or the SDR-14
25 // it is a good idea to fetch the routines for these
26 // hardwares from wse_sdrxx.c and to place them in here.
27 // you may subsequently change the routines to allow
28 // more hardwares or add tx functions, antenna control, whatever.
29 
30 
31 // Prototype for user defined hardware drive routines.
32 // These routines will replace the routines in hwaredriver.c
33 // in case a routine users_hwaredriver.c is present when configure is run.
34 // The Linrad package does not contain a users_hwaredriver.c file
35 // so it is safe to copy a nev version on top of an old one.
36 // The users_hwaredriver.c file will not be overwritten.
37 
38 
update_users_rx_frequency(void)39 void update_users_rx_frequency(void){};
40 
hware_command(void)41 void hware_command(void)
42 {
43 #if RUSAGE_OLD == TRUE
44 int local_workload_counter;
45 #endif
46 #if OSNUM == OSNUM_LINUX
47 clear_thread_times(THREAD_HWARE_COMMAND);
48 #endif
49 #if RUSAGE_OLD == TRUE
50 local_workload_counter=workload_counter;
51 #endif
52 thread_status_flag[THREAD_HWARE_COMMAND]=THRFLAG_ACTIVE;
53 while(!kill_all_flag &&
54          thread_command_flag[THREAD_HWARE_COMMAND]==THRFLAG_ACTIVE)
55   {
56   lir_sleep(30000);
57 #if RUSAGE_OLD == TRUE
58   if(local_workload_counter != workload_counter)
59     {
60     local_workload_counter=workload_counter;
61     make_thread_times(THREAD_HWARE_COMMAND);
62     }
63 #endif
64   while(hware_flag != 0)
65     {
66     control_hware();
67     lir_sleep(3000);
68     }
69   }
70 thread_status_flag[THREAD_HWARE_COMMAND]=THRFLAG_RETURNED;
71 while(!kill_all_flag &&
72             thread_command_flag[THREAD_HWARE_COMMAND] != THRFLAG_NOT_ACTIVE)
73   {
74   lir_sleep(1000);
75   }
76 }
77 
hware_set_rxtx(int state)78 void hware_set_rxtx(int state)
79 {
80 // Use state to set your Rx/Tx switching.
81 int i;
82 i=state;
83 }
84 
set_hardware_tx_frequency(void)85 void set_hardware_tx_frequency(void)
86 {
87 }
88 
89 
90 
users_eme(void)91 void users_eme(void)
92 {
93 // Called each time moon position is updated.
94 // data in degrees is available in:
95 // float moon_az;
96 // float moon_el;
97 }
98 
99 
hware_hand_key(void)100 void hware_hand_key(void)
101 {
102 // This routine is called from the rx_input_thread.
103 // It is responsible for reading the hardware and setting
104 // hand_key to TRUE or FALSE depending on whether the hand key
105 // is depressed or not.
106 }
107 
userdefined_u(void)108 void userdefined_u(void)
109 {
110 // This routine is called when the 'U' key is pressed
111 }
112 
113 // valid ranges: SERPORT_NUMBER = 1 to 4 (1=COM1,4=COM4 )
114 #define SERPORT_NUMBER 1
115 
userdefined_q(void)116 void userdefined_q(void)
117 {
118 // This routine is called when the 'Q' key is pressed
119 // The serial port can be opened and closed for each message
120 // as is done here.
121 // The serial port can also be opened by the function
122 // users_open_devices() which is executed by the main
123 // program before threads are started.
124 // There is no need to close the serial port because the main
125 // program checks its flag and closes the port if it is left open.
126 //
127 // open and close around each write could cost overhead if
128 // one writes single characters very often.
129 //
130 // Leaving the port open the whole time could leave it in an
131 // undefined state if Linrad crashes.
132 //
133 #if 0
134 int n;
135 int serport_baudrate;
136 int serport_stopbits;
137 serport_stopbits=1;
138 serport_baudrate=9600;
139 char serport_message []="TTTTTTTTTTTTTTTTTTTTTTTTT";
140 lir_open_serport(SERPORT_NUMBER,        // 1=COM1 or /dev/ttyS0 , 2=COM2....
141                  serport_baudrate,      // baudrate 110 to 57600
142                  serport_stopbits,      // 1=two stopbits, 0=one stopbit
143                  0);                    // RTS mode = 0
144 n=lir_write_serport(serport_message,10);
145 lir_close_serport();
146 #endif
147 }
148 
users_close_devices(void)149 void users_close_devices(void)
150 {
151 // Write whatever you want to the hardware before exit from Linrad.
152 // the lmain, xmain or wmain will close the serial and/or parallel
153 // ports in case they have been opened so do not worry about them.
154 }
155 
156 
users_open_devices(void)157 void users_open_devices(void)
158 {
159 // Uncomment to open the Linux serial port.
160 // The routine is in lxsys.c for Linux and wsys.c for Windows.
161 // lir_open_serport();
162 // ********************************************************
163 // Place this elsewhere in case you want to make commands to hardware
164 // via the serial port.
165 // Use for a mouse control box or a user key.
166 //
167 // n=write(serport,hhunhz,1);
168 // n=write(serport,htenkhz,1);
169 // n=write(serport,hmhz,1);
170 // ********************************************************
171 }
172 
set_hardware_rx_gain(void)173 void set_hardware_rx_gain(void)
174 {
175 // Input data:
176 // int fg.gain
177 // int fg_new_band
178 // The argument fg_new_band will allow different hardware on different
179 // bands.
180 // Set hardware gain
181 // This is the data entered in the rx gain control box.
182 // This routine is responsible for checking that it is compatible to
183 // hardware capabilities and adjusting it accordingly.
184 // this routine is also responsible for sending the control information
185 // to the hardware. Either by setting hware_flag=1 which will
186 // cause calls to control_hware() until hware_flag is cleared.
187 // (look at hwaredriver.c to see how it works to make serial data
188 // on the parallel port).
189 // In case the hardware can be controlled by the serial port,
190 // just write the control informatio to the serial port here.
191 //************************************************************
192 // This routine is responsible for setting
193 // int fg.gain_increment = The increment in dB for clicking
194 // the arrows in the gain control box.
195 }
196 
set_hardware_rx_frequency(void)197 void set_hardware_rx_frequency(void)
198 {
199 // Input data:
200 // double fg.passband_center = The midpoint of the waterfall in MHz.
201 // This is the data entered in the rx frequency control box.
202 // This routine is responsible for checking that it is compatible to
203 // hardware capabilities and adjusting it accordingly.
204 // this routine is also responsible for sending the control information
205 // to the hardware. Either by setting hware_flag=1 which will
206 // cause calls to control_hware() until hware_flag is cleared.
207 // (look at hwaredriver.c to see how it works to make serial data
208 // on the parallel port).
209 // In case the hardware can be controlled by the serial port,
210 // just write the control informatio to the serial port here.
211 //************************************************************
212 // This routine is responsible for setting
213 // double fg.passband_increment = The increment in MHz for clicking
214 // the arrows in the rx control box.
215 //************************************************************
216 // This routine is responsible for setting
217 // int fg.passband_direction = -1 or +1 depending on whether the
218 // hardware local oscillator is above or below the desired signal.
219 //************************************************************
220 // This routine is responsible for setting
221 // int fft1_direction = fg.passband_direction
222 // Here is an example:
223 fg.passband_increment=0;
224 fg.passband_direction = 1;
225 fft1_direction = fg.passband_direction;
226 // You may override the frequency that has been entered to Linrad
227 // by setting whatever value that your hardware accepts.
228 // Send fg.passband center to your hardware and read whatever
229 // value that the hardware returns (serial or parallel port,
230 // network or whatever)
231 // Or just set the value of your center frequency if it is a fixed
232 // frequency. Like this:
233 // fg.passband_center=28.125;
234 }
235 
236 
237 //    ************ PROTOTYPE ROUTINES FOR USER WINDOWS  ***************
238 // User defined windows to allow mouse control.
239 // In case several windows are desired, give them different
240 // numbers (64 and above) and use scro[m].no to decide what to do
241 // in your mouse_on_users_graph routine.
242 #define USERS_GRAPH_TYPE1 64
243 // Define your parameters in this structure.
244 // Save it to a file and recover it from init_users_control_window(void)
245 
246 typedef struct {
247 int ytop;
248 int ybottom;
249 int xleft;
250 int xright;
251 int par1;
252 int par3;
253 float par2;
254 } UG_PARMS;
255 
256 #define UG_TOP 0
257 #define UG_BOTTOM 1
258 #define UG_LEFT 2
259 #define UG_RIGHT 3
260 #define UG_INCREASE_PAR1 4
261 #define UG_DECREASE_PAR1 5
262 #define UG_DO_WHATEVER 6
263 #define MAX_UGBUTT 7
264 
265 UG_PARMS ug;
266 BUTTONS ugbutt[MAX_UGBUTT];
267 
268 int ug_old_y1;
269 int ug_old_y2;
270 int ug_old_x1;
271 int ug_old_x2;
272 int users_graph_scro;
273 void make_users_control_graph(void);
274 
275 
show_user_parms(void)276 void show_user_parms(void)
277 {
278 char s[80];
279 // Show the user parameters on screen
280 // and issue hardware commands if required.
281 // Use hware_flag to direct calls to control_hware() when cpu time
282 // is available in case whatever you want to do takes too much time
283 // to be done immediately.
284 // Note that mouse control is done in the narrowband processing thread
285 // and that you can not use lir_sleep to wait for hardware response here.
286 hide_mouse(ug.xleft, ug.xright,ug.ytop,ug.ybottom);
287 sprintf(s,"Par1 %d ",ug.par1);
288 lir_pixwrite(ug.xleft+6*text_width,ug.ytop+text_height,s);
289 sprintf(s,"Par2 %f ",ug.par2);
290 lir_pixwrite(ug.xleft+6*text_width,ug.ytop+2*text_height,s);
291 }
292 
293 
mouse_continue_users_graph(void)294 void mouse_continue_users_graph(void)
295 {
296 switch (mouse_active_flag-1)
297   {
298 // Move border lines immediately.
299 // for other functions, wait until button is released.
300 // Look in freq_control.c how to move a fixed size window.
301   case UG_TOP:
302   graph_borders((void*)&ug,0);
303   ug.ytop=mouse_y;
304   graph_borders((void*)&ug,15);
305   break;
306 
307   case UG_BOTTOM:
308   graph_borders((void*)&ug,0);
309   ug.ybottom=mouse_y;
310   graph_borders((void*)&ug,15);
311   break;
312 
313   case UG_LEFT:
314   graph_borders((void*)&ug,0);
315   ug.xleft=mouse_x;
316   graph_borders((void*)&ug,15);
317   break;
318 
319   case UG_RIGHT:
320   graph_borders((void*)&ug,0);
321   ug.xright=mouse_x;
322   graph_borders((void*)&ug,15);
323   break;
324 
325   default:
326   goto await_release;
327   }
328 if(leftpressed == BUTTON_RELEASED)goto finish;
329 return;
330 await_release:;
331 if(leftpressed != BUTTON_RELEASED) return;
332 // Assuming the user wants to control hardware we
333 // allow commands only when data is not over the network.
334 if( (ui.network_flag&NET_RX_INPUT) == 0)
335 
336   {
337   switch (mouse_active_flag-1)
338     {
339     case UG_INCREASE_PAR1:
340     ug.par1++;
341     break;
342 
343     case UG_DECREASE_PAR1:
344     ug.par1--;
345     break;
346 
347     case UG_DO_WHATEVER:
348 // Issue hardware commands or fill the screen
349 // with whatever you like.
350 // Use hware_flag to direct calls to control_hware() when cpu time
351 // is available in case whatever you want to do takes too much time
352 // to be done immediately.
353     ug.par3++;
354     if(ug.par3 < 16)
355       {
356       settextcolor(ug.par3);
357       lir_text(0,screen_last_line-8,"USERS 'DO WHATEVER' PRESSED");
358       }
359     else
360       {
361       ug.par3=0;
362       lir_text(0,screen_last_line-8,"                           ");
363       }
364     settextcolor(7);
365     break;
366 
367     default:
368 // This should never happen.
369     lirerr(211053);
370     break;
371     }
372   }
373 finish:;
374 hide_mouse(ug_old_x1,ug_old_x2,ug_old_y1,ug_old_y2);
375 leftpressed=BUTTON_IDLE;
376 mouse_active_flag=0;
377 graph_borders((void*)&ug,0);
378 lir_fillbox(ug_old_x1,ug_old_y1,ug_old_x2-ug_old_x1,ug_old_y2-ug_old_y1,0);
379 make_users_control_graph();
380 }
381 
new_user_par1(void)382 void new_user_par1(void)
383 {
384 ug.par1=numinput_int_data;
385 pause_thread(THREAD_SCREEN);
386 show_user_parms();
387 resume_thread(THREAD_SCREEN);
388 }
389 
new_user_par2(void)390 void new_user_par2(void)
391 {
392 ug.par2=numinput_float_data;
393 pause_thread(THREAD_SCREEN);
394 show_user_parms();
395 resume_thread(THREAD_SCREEN);
396 }
397 
398 
399 
400 
mouse_on_users_graph(void)401 void mouse_on_users_graph(void)
402 {
403 int event_no;
404 // First find out is we are on a button or border line.
405 for(event_no=0; event_no<MAX_UGBUTT; event_no++)
406   {
407   if( ugbutt[event_no].x1 <= mouse_x &&
408       ugbutt[event_no].x2 >= mouse_x &&
409       ugbutt[event_no].y1 <= mouse_y &&
410       ugbutt[event_no].y2 >= mouse_y)
411     {
412     ug_old_y1=ug.ytop;
413     ug_old_y2=ug.ybottom;
414     ug_old_x1=ug.xleft;
415     ug_old_x2=ug.xright;
416     mouse_active_flag=1+event_no;
417     current_mouse_activity=mouse_continue_users_graph;
418     return;
419     }
420   }
421 // Not button or border.
422 // Prompt the user for par1 or par2 depending on whether the mouse is
423 // in the upper or the lower part of the window.
424 mouse_active_flag=1;
425 numinput_xpix=ug.xleft+11*text_width;
426 if(mouse_x > ug.xleft+2*text_width && mouse_x<ug.xright-2*text_width)
427   {
428   if(mouse_y > (ug.ytop+ug.ybottom)/2)
429     {
430     numinput_ypix=ug.ytop+2*text_height;
431     numinput_chars=12;
432     erase_numinput_txt();
433     numinput_flag=FIXED_FLOAT_PARM;
434     par_from_keyboard_routine=new_user_par2;
435     }
436   else
437     {
438     numinput_ypix=ug.ytop+text_height;
439     numinput_chars=4;
440     erase_numinput_txt();
441     numinput_flag=FIXED_INT_PARM;
442     par_from_keyboard_routine=new_user_par1;
443     }
444   }
445 else
446   {
447 // If we did not select a numeric input by setting numinput_flag
448 // we have to set mouse_active flag.
449 // Set the routine to mouse_nothing, we just want to
450 // set flags when the mouse button is released.
451   current_mouse_activity=mouse_nothing;
452   mouse_active_flag=1;
453   }
454 }
455 
456 
make_users_control_graph(void)457 void make_users_control_graph(void)
458 {
459 pause_thread(THREAD_SCREEN);
460 // Set a negative number here.
461 // In case several windows are desired, give them different
462 // negative numbers and use scro[m].no to decide what to do
463 // in your mouse_on_users_graph routine.
464 scro[users_graph_scro].no=USERS_GRAPH_TYPE1;
465 // These are the coordinates of the border lines.
466 scro[users_graph_scro].x1=ug.xleft;
467 scro[users_graph_scro].x2=ug.xright;
468 scro[users_graph_scro].y1=ug.ytop;
469 scro[users_graph_scro].y2=ug.ybottom;
470 // Each border line is treated as a button.
471 // That is for the mouse to get hold of them so the window can be moved.
472 ugbutt[UG_LEFT].x1=ug.xleft;
473 ugbutt[UG_LEFT].x2=ug.xleft;
474 ugbutt[UG_LEFT].y1=ug.ytop;
475 ugbutt[UG_LEFT].y2=ug.ybottom;
476 ugbutt[UG_RIGHT].x1=ug.xright;
477 ugbutt[UG_RIGHT].x2=ug.xright;
478 ugbutt[UG_RIGHT].y1=ug.ytop;
479 ugbutt[UG_RIGHT].y2=ug.ybottom;
480 ugbutt[UG_TOP].x1=ug.xleft;
481 ugbutt[UG_TOP].x2=ug.xright;
482 ugbutt[UG_TOP].y1=ug.ytop;
483 ugbutt[UG_TOP].y2=ug.ytop;
484 ugbutt[UG_BOTTOM].x1=ug.xleft;
485 ugbutt[UG_BOTTOM].x2=ug.xright;
486 ugbutt[UG_BOTTOM].y1=ug.ybottom;
487 ugbutt[UG_BOTTOM].y2=ug.ybottom;
488 // Draw the border lines
489 graph_borders((void*)&ug,7);
490 settextcolor(7);
491 make_button(ug.xleft+text_width,ug.ybottom-3*text_height/2-2,
492                                          ugbutt,UG_DECREASE_PAR1,25);
493 make_button(ug.xright-text_width,ug.ybottom-3*text_height/2-2,
494                                      ugbutt,UG_INCREASE_PAR1,24);
495 make_button(ug.xleft+text_width,ug.ybottom-text_height/2-2,
496                                          ugbutt,UG_DO_WHATEVER,'A');
497 show_user_parms();
498 resume_thread(THREAD_SCREEN);
499 }
500 
init_users_control_window(void)501 void init_users_control_window(void)
502 {
503 // Set initial values in code or by reading
504 // a file of your own.
505 ug.xleft=0;
506 ug.xright=25*text_width;
507 ug.ytop=0;
508 ug.ybottom=3.5*text_height;
509 ug.par1=5;
510 ug.par2=PI_L;
511 ug.par3=14;
512 users_graph_scro=no_of_scro;
513 make_users_control_graph();
514 no_of_scro++;
515 if(no_of_scro >= MAX_SCRO)lirerr(89);
516 }
517 
users_init_mode(void)518 void users_init_mode(void)
519 {
520 // A switch statement can be used to do different things depending on
521 // the processing mode.
522 switch (rx_mode)
523   {
524   case MODE_WCW:
525   case MODE_HSMS:
526   case MODE_QRSS:
527   break;
528 
529   case MODE_NCW:
530   case MODE_SSB:
531 // Open a window to allow mouse control of your own things
532   init_users_control_window();
533   break;
534 
535   case MODE_FM:
536   case MODE_AM:
537   case MODE_TXTEST:
538   case MODE_RX_ADTEST:
539   case MODE_TUNE:
540   break;
541   }
542 }
543