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 
25 // *********************************************************************
26 // *  This software uses the Perseus API which is defined through the  *
27 // *  following four files of the Microtelecom Software Defined Radio  *
28 // *  Developer Kit (SDRK):                                            *
29 // *  main.cpp, perseusdll.cpp, perseusdefs.h, perseusdll.h            *
30 // *  To use the Perseus hardware you need the perseususb.dll file     *
31 // *  You also need at least one of the following files:               *
32 // *  perseus125k24v21.sbs                                             *
33 // *  perseus250k24v21.sbs                                             *
34 // *  perseus500k24v21.sbs                                             *
35 // *  perseus1m24v21.sbs                                               *
36 // *  perseus2m24v21.sbs                                               *
37 // *  The dll and the sbs files are copyright protected and only       *
38 // *  available at the official Microtelecom Internet site:            *
39 // *  http://www.microtelecom.it                                       *
40 // *********************************************************************
41 // *   Under linux the GNU licensed libperseus_sdr library is used.    *
42 // *********************************************************************
43 
44 #include <string.h>
45 #include "globdef.h"
46 #include "uidef.h"
47 #include "vernr.h"
48 #include "rusage.h"
49 #include "thrdef.h"
50 #include "rusage.h"
51 #include "thrdef.h"
52 #include "sdrdef.h"
53 #include "fft1def.h"
54 #include "screendef.h"
55 
56 // Values returned by FirmwareDownload()
57 #define IHEX_DOWNLOAD_OK              0 //FX2 Firmware successfully downloaded
58 #define IHEX_DOWNLOAD_FILENOTFOUND    1 //FX2 Firmware file not found
59 #define IHEX_DOWNLOAD_IOERROR         2 //USB IO Error
60 #define IHEX_DOWNLOAD_INVALIDHEXREC   3 //Invalid HEX Record
61 #define IHEX_DOWNLOAD_INVALIDEXTREC   4 //Invalide Extended HEX Record
62 
63 // Values returned by FpgaConfig()
64 #define FPGA_CONFIG_OK              0 //FPGA successfully configured
65 #define FPGA_CONFIG_FILENOTFOUND    1 //FPGA bitstream file not found
66 #define FPGA_CONFIG_IOERROR         2 //USB IO Error
67 #define FPGA_CONFIG_FWNOTLOADED     3 //FX2 Firmware not loaded
68 
69 // Perseus SIO (serial I/O) interface definitions
70 
71 // Receiver control bit masks (ctl field of SIOCTL data structure)
72 #define PERSEUS_SIO_FIFOEN    0x01 //Enable inbound data USB endpoint
73 #define PERSEUS_SIO_DITHER    0x02 //Enable ADC dither generator
74 #define PERSEUS_SIO_GAINHIGH  0x04 //Enable ADC preamplifier
75 #define PERSEUS_SIO_RSVD      0x08 //For Microtelecm internal use only
76 #define PERSEUS_SIO_TESTFIFO  0x10 //For Microtelecm internal use only
77 #define PERSEUS_SIO_ADCBYPASS 0x20 //For Microtelecm internal use only
78 #define PERSEUS_SIO_ADCATT60  0x40 //For Microtelecm internal use only
79 #define PERSEUS_SIO_SCRAMBLE  0x80 //For Microtelecm internal use only
80 
81 // Perseus receiver USB buffering scheme definitions (never touch)
82 #define PERSEUS_SAMPLESPERFRAME	170   // Samples in one FX2 USB transaction
83 #define PERSEUS_COMPONENTSPERSAMPLE 2 // I & Q components
84 #define PERSEUS_BYTESPERCOMPONENT   3 // 24 bit data
85 // Derived defines
86 #define PERSEUS_BYTESPERSAMPLE (PERSEUS_BYTESPERCOMPONENT*PERSEUS_COMPONENTSPERSAMPLE)
87 #define PERSEUS_BYTESPERFRAME (PERSEUS_SAMPLESPERFRAME*PERSEUS_BYTESPERSAMPLE)
88 
89 // When calling PerseusStartAsyncInput(...)
90 // the buffer size must always be a multiple of PERSEUS_BYTESPERFRAME
91 #define PERSEUS_BYTESPERFRAME (PERSEUS_SAMPLESPERFRAME*PERSEUS_BYTESPERSAMPLE)
92 
93 // SIO Receiver Control data structure
94 #pragma pack(1)
95 typedef struct {
96 unsigned char ctl; // Receiver control bit mask
97 int freg;          // Receiver DDC LO frequency register
98 } SIOCTL;
99 #pragma pack()
100 
101 // Structure for Perseus parameters
102 typedef struct {
103 int rate_no;
104 int clock_adjust;
105 int presel;
106 int preamp;
107 int dither;
108 int check;
109 }P_PERSEUS;
110 #define MAX_PERSEUS_PARM 6
111 
112 
113 char *perseus_parfil_name="par_perseus";
114 int perseus_bytesperbuf;
115 
116 char *perseus_parm_text[MAX_PERSEUS_PARM]={"Rate no",           //0
117                                            "Sampl. clk adjust", //1
118                                            "Preselector",       //2
119                                            "Preamp",            //3
120                                            "Dither",            //4
121                                            "Check"};            //5
122 #define MAX_PERSEUS_FILTER 10
123 float perseus_filter_cutoff[MAX_PERSEUS_FILTER+1]={
124                   1.7,
125                   2.1,
126                   3.0,
127                   4.2,
128                   6.0,
129                   8.4,
130                  12.0,
131                  17.0,
132                  24.0,
133                  32.0,
134                  BIG};
135 
136 // Data structure which holds controls for the receiver ADC and DDC
137 
138 // Perseus EEPROM Definitions and data structures
139 #define ADDR_EEPROM_PRODID 8
140 #pragma pack(1)
141 typedef struct {
142 unsigned short int sn;       // Receiver Serial Number
143 unsigned short int prodcode; // Microtelecom Product Code
144 unsigned char hwrel;         // Product release
145 unsigned char hwver;         // Product version
146 unsigned char signature[6];  // Microtelecom Original Product Signature
147 } eeprom_prodid;
148 #pragma pack()
149 
150 int no_of_perseus_rates;
151 #define PERSEUS_RATES_BUFSIZE 20
152 double perseus_rates[PERSEUS_RATES_BUFSIZE];
153 P_PERSEUS pers;
154 
155 
156 
157 
158 #if(OSNUM == OSNUM_WINDOWS)
159 #include "wdef.h"
160 #if defined(interface)
161 #undef interface
162 #endif
163 extern char *unable_to_load;
164 
165 // Microtelecom original FPGA bitstream signature
166 typedef struct {
167 unsigned char sz[6];
168 } Key48;
169 
170 typedef int   (WINAPI *PtrToGetDLLVersion)(void);
171 typedef int   (WINAPI *PtrToOpen)(void);
172 typedef int   (WINAPI *PtrToClose)(void);
173 typedef char* (WINAPI *PtrToGetDeviceName)(void);
174 typedef int   (WINAPI *PtrToEepromFunc)(UCHAR *, DWORD, UCHAR);
175 typedef int   (WINAPI *PtrToFwDownload)(char* fname);
176 typedef int   (WINAPI *PtrToFpgaConfig)(char* fname, Key48 *pKey);
177 typedef int   (WINAPI *PtrToSetAttPresel)(unsigned char idSet);
178 typedef int   (WINAPI *PtrToSio)(void *ctl, int nbytes);
179 typedef int   (WINAPI *PInputCallback)(char *pBuf, int nothing);
180 typedef int   (WINAPI *PtrToStartAsyncInput)(int dwBufferSize,
181                            PInputCallback pInputCallback, void *pExtra);
182 typedef int  (WINAPI *PtrToStopAsyncInput)(void);
183 
184 #define MAX_PERSEUS_RATES 9
185 double rate_factor[MAX_PERSEUS_RATES]={1666.6666667,  //48kHz
186                                        840.0,         //95.238 kHz
187                                        832.0,         //96.154 kHz
188                                        640.0,         //125 kHz
189                                        416.0,         //192.308 kHz
190                                        320.0,         //250 kHz
191                                        160.0,         //500 kHz
192                                        80.0,          //1 MHz
193                                        40.0};         //2 MHz
194 
195 char *perseus_bitstream_names[MAX_PERSEUS_RATES]={
196                  "perseus48k24v31",
197                  "perseus95k24v31",
198                  "perseus96k24v31",
199                  "perseus125k24v21",
200                  "perseus192k24v31",
201                  "perseus250k24v21",
202                  "perseus500k24v21",
203                  "perseus1m24v21",
204                  "perseus2m24v21"};
205 
206 char *rate_names[MAX_PERSEUS_RATES]={"48k",
207                                      "95.2k",
208                                      "96k",
209                                      "125k",
210                                      "192k",
211                                      "250k",
212                                      "500k",
213                                      "1M",
214                                      "2M"};
215 
216 
217 extern int perseus_bytesperbuf;
218 extern P_PERSEUS pers;
219 extern char *perseus_bitstream_names[MAX_PERSEUS_RATES];
220 
221 static HINSTANCE h_pers=NULL;
222 
223 PtrToGetDLLVersion		m_pGetDLLVersion;
224 PtrToOpen		    	m_pOpen;
225 PtrToClose			    m_pClose;
226 PtrToGetDeviceName		m_pGetDeviceName;
227 PtrToGetDeviceName		m_pGetFriendlyDeviceName;
228 PtrToEepromFunc			m_pEepromRead;
229 PtrToFwDownload			m_pFwDownload;
230 PtrToFpgaConfig			m_pFpgaConfig;
231 PtrToSetAttPresel		m_pSetAttenuator;
232 PtrToSetAttPresel		m_pSetPreselector;
233 PtrToSio                m_pSio;
234 PtrToStartAsyncInput	m_pStartAsyncInput;
235 PtrToStopAsyncInput     m_pStopAsyncInput;
236 
237 int perseus_bytesperbuf;
238 SIOCTL sioctl;
239 extern float perseus_filter_cutoff[MAX_PERSEUS_FILTER+1];
240 
241 
242 Key48 perseus48k24v31_signature= {{0xE4, 0x37, 0x73, 0x7B, 0x9A, 0x6A }};
243 Key48 perseus95k24v31_signature= {{0x22, 0x33, 0xB8, 0xEA, 0x2C, 0xBC }};
244 Key48 perseus96k24v31_signature= {{0x39, 0x18, 0x79, 0xF5, 0x90, 0x8C }};
245 Key48 perseus125k24v21_signature={{0x45, 0x7C, 0xD4, 0x3A, 0x0E, 0xD4 }};
246 Key48 perseus192k24v31_signature={{0x7B, 0x39, 0x26, 0x75, 0x9F, 0x7B }};
247 Key48 perseus250k24v21_signature={{0xCF, 0x4B, 0x9F, 0x02, 0xB2, 0x1E }};
248 Key48 perseus500k24v21_signature={{0xF2, 0x9E, 0x67, 0x49, 0x51, 0x6B }};
249 Key48 perseus1m24v21_signature=  {{0xC5, 0xC1, 0x96, 0x4D, 0xA8, 0x05 }};
250 Key48 perseus2m24v21_signature=  {{0xDE, 0xEA, 0x57, 0x52, 0x14, 0x35 }};
251 
252 Key48 *perseus_bitstream_signatures[MAX_PERSEUS_RATES]={
253                                &perseus48k24v31_signature,
254                                &perseus95k24v31_signature,
255                                &perseus96k24v31_signature,
256                                &perseus125k24v21_signature,
257                                &perseus192k24v31_signature,
258                                &perseus250k24v21_signature,
259                                &perseus500k24v21_signature,
260                                &perseus1m24v21_signature,
261                                &perseus2m24v21_signature};
262 
263 int perseus_dll_version;
264 
perseus_callback(char * pBuf,int nothing)265 int WINAPI perseus_callback(char *pBuf, int nothing)
266 {
267 register char c1;
268 int i;
269 c1=0;
270 // This callback gets called whenever a buffer is ready
271 // from the USB interface
272 for(i=0; i<perseus_bytesperbuf; i+=6)
273   {
274   timf1_char[timf1p_sdr+3]=pBuf[i+2];
275   c1=pBuf[i+2]&0x80;
276   timf1_char[timf1p_sdr+2]=pBuf[i+1];
277   timf1_char[timf1p_sdr+1]=pBuf[i  ];
278   c1|=pBuf[i];
279   timf1_char[timf1p_sdr  ]=0;
280   timf1_char[timf1p_sdr+7]=pBuf[i+5];
281   timf1_char[timf1p_sdr+6]=pBuf[i+4];
282   timf1_char[timf1p_sdr+5]=pBuf[i+3];
283   timf1_char[timf1p_sdr+4]=0;
284   timf1p_sdr=(timf1p_sdr+8)&timf1_bytemask;
285   }
286 if( (c1&1) != 0)
287   {
288   ad_maxamp[0]=0x7fff;
289   ad_maxamp[1]=0x7fff;
290   }
291 SetEvent(rxin1_bufready);
292 return nothing;
293 }
294 
lir_perseus_read(void)295 void lir_perseus_read(void)
296 {
297 if(((timf1p_sdr-timf1p_pa+timf1_bytes)&timf1_bytemask) < (int)snd[RXAD].block_bytes)
298   {
299   WaitForSingleObject(rxin1_bufready, INFINITE);
300   }
301 }
302 
perseus_load_proprietary_code(int rate_no)303 int perseus_load_proprietary_code(int rate_no)
304 {
305 int i;
306 // Download the standard Microtelecom FX2 firmware to the Perseus receiver
307 // IMPORTANT NOTE:
308 // The parameter passed to PerseusFirmwareDownload() must be NULL
309 // for the Perseus hardware to be operated safely.
310 // Permanent damages to the receiver can result if a third-party firmware
311 // is downloaded to the Perseus FX2 controller. You're advised.
312 //
313 // During the execution of the PerseusFirmwareDownload() function
314 // the Perseus USB hardware is renumerated. This causes the function
315 // to be blocking for a while. It is suggested to put an hourglass cursor
316 // before calling this function if the code has to be developed for a real
317 // Window application (and removing it when it returns)
318 i=(*m_pFwDownload)(NULL);
319 if(i != IHEX_DOWNLOAD_OK)
320   {
321   switch (i)
322     {
323     case IHEX_DOWNLOAD_IOERROR:
324     return 1083;
325 
326     case IHEX_DOWNLOAD_FILENOTFOUND:
327     return 1084;
328 
329     case IHEX_DOWNLOAD_INVALIDHEXREC:
330     return 1085;
331 
332     case IHEX_DOWNLOAD_INVALIDEXTREC:
333     return 1089;
334 
335     default:
336     return 1090;
337     }
338   }
339 // Download the FPGA bitstream to the Perseus' FPGA
340 // There are three bitstream provided with the current software version
341 // one for each of the output sample rate provided by the receiver
342 // (125, 250, 500, 1000 or 2000 kS/s)
343 // Each FPGA bistream (.sbs file) has an original Microtelecom
344 // signature which must be provided as the second parameter to the
345 // function PerseusFpgaConfig() to prevent the configuration of the
346 // FPGA with non authorized, third-party, code which could damage
347 // the receiver hardware.
348 // The bitstream files should be located in the same directory of
349 // the executing software for things to work.
350 i=(*m_pFpgaConfig)( perseus_bitstream_names[rate_no],
351                     perseus_bitstream_signatures[rate_no]);
352 if(i != FPGA_CONFIG_OK)
353   {
354   switch (i)
355     {
356     case FPGA_CONFIG_FILENOTFOUND:
357     return 1092;
358 
359     case FPGA_CONFIG_IOERROR:
360     return 1096;
361 
362     default:
363     return 1097;
364     }
365   }
366 return 0;
367 }
368 
perseus_eeprom_read(unsigned char * buf,int addr,unsigned char count)369 int perseus_eeprom_read(unsigned char *buf, int addr, unsigned char count)
370 {
371 return (*m_pEepromRead)(buf, addr, count);
372 }
373 
perseus_frname(void)374 char *perseus_frname(void)
375 {
376 return (*m_pGetFriendlyDeviceName)();
377 }
378 
perseus_store_att(unsigned char idAtt)379 void perseus_store_att(unsigned char idAtt)
380 {
381 m_pSetAttenuator(idAtt);
382 }
383 
384 
perseus_store_presel(unsigned char idPresel)385 void perseus_store_presel(unsigned char idPresel)
386 {
387 m_pSetPreselector(idPresel);
388 }
389 
set_perseus_frequency(void)390 void set_perseus_frequency(void)
391 {
392 unsigned char sl;
393 double dt1;
394 sl=MAX_PERSEUS_FILTER;
395 if(pers.presel !=0 )
396   {
397   sl=0;
398 // select filter according to frequency.
399   while(perseus_filter_cutoff[sl]<fg.passband_center)sl++;
400   }
401 perseus_store_presel(sl);
402 dt1=fg.passband_center*1000000;
403 if(dt1 < 0 || dt1 > adjusted_sdr_clock/2)
404   {
405   fg.passband_center=7.05;
406   dt1=fg.passband_center*1000000;
407   }
408 sioctl.freg=4.294967296E9*dt1/adjusted_sdr_clock;
409 m_pSio(&sioctl,sizeof(sioctl));
410 }
411 
start_perseus_read(void)412 void start_perseus_read(void)
413 {
414 int i;
415 sdr=-1;
416 rxin1_bufready=CreateEvent( NULL, FALSE, FALSE, NULL);
417 if(rxin1_bufready== NULL)
418   {
419   close_perseus();
420   lirerr(1223);
421   return;
422   }
423 perseus_bytesperbuf=snd[RXAD].block_bytes/PERSEUS_BYTESPERFRAME;
424 perseus_bytesperbuf*=PERSEUS_BYTESPERFRAME;
425 timf1p_sdr=timf1p_pa;
426 lir_sched_yield();
427 i=m_pStartAsyncInput(perseus_bytesperbuf, perseus_callback, 0);
428 if(i == FALSE)
429   {
430   close_perseus();
431   lirerr(1098);
432   return;
433   }
434 // Enable the Perseus data FIFO through its SIO interface
435 // setting the PERSEUS_SIO_FIFOEN bit in the ctl field of
436 // the (global) sioctl variable.
437 sioctl.ctl |=PERSEUS_SIO_FIFOEN;
438 m_pSio(&sioctl,sizeof(sioctl));
439 sdr=0;
440 }
441 
perseus_stop(void)442 void perseus_stop(void)
443 {
444 m_pStopAsyncInput();
445 sioctl.ctl &=~PERSEUS_SIO_FIFOEN;
446 m_pSio(&sioctl,sizeof(sioctl));
447 lir_sleep(10000);
448 CloseHandle(rxin1_bufready);
449 }
450 
close_perseus(void)451 void close_perseus(void)
452 {
453 if(perseus_dll_version <=2)
454   {
455 // There is a bug that prevents close and re-open so we just leave the
456 // perseus open. This can cause problems when the user wants to change
457 // the hardware. It will become necessary to exit and restart Linrad.
458   return;
459   }
460 m_pClose();
461 FreeLibrary(h_pers);
462 h_pers=NULL;
463 sdr=-1;
464 unload_usb1_library();
465 }
466 
open_perseus(void)467 void open_perseus(void)
468 {
469 int j, k;
470 char s[80];
471 load_usb1_library(TRUE);
472 if(libusb1_library_flag == FALSE)return;
473 char *perseus_dll_name="perseususb.dll";
474 if(h_pers == NULL)
475   {
476   h_pers = LoadLibrary(perseus_dll_name);
477   if(h_pers == NULL)
478     {
479     sprintf(s,"%s%s",unable_to_load, perseus_dll_name);
480     SNDLOG"\n%s",s);
481     if(!write_log)clear_screen();
482     lir_text(3,2,s);
483     return;
484     }
485   m_pGetDLLVersion	= (PtrToGetDLLVersion)GetProcAddress(h_pers,"GetDLLVersion");
486   m_pOpen                 = (PtrToOpen)GetProcAddress(h_pers,"Open");
487   m_pClose                = (PtrToClose)GetProcAddress(h_pers,"Close");
488   m_pGetDeviceName	= (PtrToGetDeviceName)GetProcAddress(h_pers,"GetDeviceName");
489   m_pGetFriendlyDeviceName= (PtrToGetDeviceName)GetProcAddress(h_pers,"GetFriendlyDeviceName");
490   m_pEepromRead		= (PtrToEepromFunc)GetProcAddress(h_pers,"EepromRead");
491   m_pFwDownload           = (PtrToFwDownload)GetProcAddress(h_pers,"FirmwareDownload");
492   m_pFpgaConfig		= (PtrToFpgaConfig)GetProcAddress(h_pers,"FpgaConfig");
493   m_pSetAttenuator	= (PtrToSetAttPresel)GetProcAddress(h_pers,"SetAttenuator");
494   m_pSetPreselector	= (PtrToSetAttPresel)GetProcAddress(h_pers,"SetPreselector");
495   m_pSio			= (PtrToSio)GetProcAddress(h_pers,"Sio");
496   m_pStartAsyncInput	= (PtrToStartAsyncInput)GetProcAddress(h_pers,"StartAsyncInput");
497   m_pStopAsyncInput	= (PtrToStopAsyncInput)GetProcAddress(h_pers,"StopAsyncInput");
498   SNDLOG"\nperseususb.dll loaded");
499   if( m_pGetDLLVersion == NULL ||
500       m_pOpen == NULL ||
501       m_pGetDeviceName == NULL ||
502       m_pGetFriendlyDeviceName == NULL ||
503       m_pEepromRead == NULL ||
504       m_pFwDownload == NULL ||
505       m_pFpgaConfig == NULL ||
506       m_pSetAttenuator == NULL ||
507       m_pSetPreselector == NULL ||
508       m_pSio  == NULL ||
509       m_pStartAsyncInput == NULL ||
510       m_pStopAsyncInput == NULL
511       )
512     {
513     SNDLOG"\nDLL function(s) missing");
514 free_pdll:;
515     lir_text(3,2,"The Perseus seems to not be properly installed");
516     FreeLibrary(h_pers);
517     h_pers=NULL;
518     return;
519     }
520   j = m_pGetDLLVersion();
521   if (!j)
522     {
523     SNDLOG"\nDLLversion failed");
524     goto free_pdll;
525     }
526   k=j>>16;
527   j&=0xffff;
528   SNDLOG" vers %d.%d",k,j);
529   perseus_dll_version=k;
530   j=m_pOpen();
531   if(j==FALSE)
532     {
533     SNDLOG"\nPerseus receiver not detected");
534     if(write_log)fflush(sndlog);
535     goto free_pdll;
536     }
537   }
538 sioctl.ctl=0;
539 if(pers.preamp != 0)sioctl.ctl|=PERSEUS_SIO_GAINHIGH;
540 if(pers.dither != 0)sioctl.ctl|=PERSEUS_SIO_DITHER;
541 sdr=0;
542 }
543 #endif
544 
545 #if(OSNUM == OSNUM_LINUX)
546 #include <unistd.h>
547 #include <stdint.h>
548 #include <dlfcn.h>
549 
550 // Perseus VID/PID
551 #define PERSEUS_VID                     0x04B4
552 #define PERSEUS_PID_BLANKEEPROM         0x8613
553 #define PERSEUS_PID                     0x325C
554 
555 // Perseus Fx2 firmware end points
556 #define PERSEUS_EP_CMD			0x01
557 #define PERSEUS_EP_STATUS		0x81
558 #define PERSEUS_EP_DATAIN	  	0x82
559 
560 // Fx2 MCU specific vendor command defines
561 #define FX2_BM_VENDOR_REQUEST		0x40
562 #define FX2_REQUEST_FIRMWARE_LOAD	0xA0
563 #define FX2_ADDR_CPUCS				0xE600
564 
565 // Defines and commands interpreted by the Perseus Fx2 firmware
566 #define PERSEUS_CMD_CONFIG_TRANSFER_SIZE 64
567 #define PERSEUS_EEPROMADR_PRODID 8
568 
569 #define PERSEUS_CMD_FPGACONFIG	0x00
570 #define PERSEUS_CMD_FPGARESET	0x01
571 #define PERSEUS_CMD_FPGACHECK	0x02
572 #define PERSEUS_CMD_FPGASIO		0x03
573 #define PERSEUS_CMD_FX2PORTE	0x04
574 #define PERSEUS_CMD_EEPROMREAD	0x06
575 #define PERSEUS_CMD_SHUTDOWN	0x08
576 
577 #define PERSEUS_NOERROR			 0
578 #define PERSEUS_INVALIDDEV		-1
579 #define PERSEUS_NULLDESCR		-2
580 #define PERSEUS_ALREADYOPEN		-3
581 #define PERSEUS_LIBUSBERR		-4
582 #define PERSEUS_DEVNOTOPEN		-5
583 #define PERSEUS_DEVCONF			-6
584 #define PERSEUS_DEVCLAIMINT		-7
585 #define PERSEUS_DEVALTINT		-8
586 #define PERSEUS_FNNOTAVAIL		-9
587 #define PERSEUS_DEVNOTFOUND		-10
588 #define PERSEUS_EEPROMREAD		-11
589 #define PERSEUS_FILENOTFOUND	-12
590 #define PERSEUS_IOERROR			-13
591 #define PERSEUS_INVALIDHEXREC	-14
592 #define PERSEUS_INVALIDEXTREC	-15
593 #define PERSEUS_FWNOTLOADED		-16
594 #define PERSEUS_FPGACFGERROR	-17
595 #define PERSEUS_FPGANOTCFGD	    -18
596 #define PERSEUS_ASYNCSTARTED	-19
597 #define PERSEUS_NOMEM			-20
598 #define PERSEUS_CANTCREAT		-21
599 #define PERSEUS_ERRPARAM		-22
600 #define PERSEUS_MUTEXIN			-23
601 #define PERSEUS_BUFFERSIZE		-24
602 #define PERSEUS_ATTERROR		-25
603 
604 typedef struct libusb_device libusb_device;
605 typedef struct libusb_device_handle libusb_device_handle;
606 
607 // Fx2 MCU <-> FPGA serial io data structure
608 typedef struct __attribute__((__packed__)) {
609 	uint8_t 	ctl;
610 	uint32_t	freg;
611 } fpga_sioctl;
612 
613 typedef int (*perseus_input_callback)(void *buf, int buf_size, void *extra);
614 
615 typedef struct perseus_input_queue_ds *perseus_input_queue_ptr;
616 
617 typedef struct {
618 	int						 idx;
619 	perseus_input_queue_ptr  queue;
620 	struct libusb_transfer 	*transfer;
621 	int cancelled;
622 } perseus_input_transfer;
623 
624 typedef struct perseus_input_queue_ds {
625 	int						size;
626 	perseus_input_transfer	*transfer_queue;
627 	volatile int 			cancelling;
628 	char					*buf;
629 	int						transfer_buf_size;
630 	int						timeout;
631 	perseus_input_callback 	callback_fn;
632 	void					*callback_extra;
633 	int						idx_expected;
634 	volatile int			completed;
635 	struct timeval 			start;
636 	struct timeval			stop;
637 	unsigned long int		bytes_received;
638 } perseus_input_queue;
639 
640 // Microtelecom product code for the Perseus receiver
641 #define PERSEUS_PRODCODE    0x8014
642 #define MAX_LIBUSB_BULK_BUFFER 16320
643 #define MAX_PERSEUS_RATES 6
644 
645 
646 typedef struct perseus_descr_ds {
647 		int						index;
648 		libusb_device		 	*device;
649 	    libusb_device_handle 	*handle;
650 		uint8_t					bus;
651 		uint8_t					devaddr;
652 		int						is_cypress_ezusb;
653 		int						is_preserie;
654 		int						firmware_downloaded;
655 		int						fpga_configured;
656 		eeprom_prodid 			product_id;
657 		uint8_t					frontendctl;
658 		double					adc_clk_freq;
659 		double					ddc_lo_freq;
660 		uint8_t					presel_flt_id;
661 		fpga_sioctl				sioctl;
662 		perseus_input_queue		input_queue;
663 } perseus_descr;
664 
665 perseus_descr *descr;
666 double rate_factor[PERSEUS_RATES_BUFSIZE];
667 char *perseus_bitstream_names[MAX_PERSEUS_RATES]={
668                  "perseus95k24v31.rbs",
669                  "perseus125k24v21.rbs",
670                  "perseus250k24v21.rbs",
671                  "perseus500k24v21.rbs",
672                  "perseus1m24v21.rbs",
673                  "perseus2m24v21.rbs"};
674 
675 
676 // ******* Perseus library functions that we do not use *******
677 // int perseus_set_adc(perseus_descr *descr, int enableDither, int enablePreamp);
678 // int perseus_set_sampling_rate(perseus_descr *descr, int new_sample_rate);
679 // int perseus_set_attenuator_in_db (perseus_descr *descr, int new_level_in_db);
680 // int perseus_get_attenuator_values (perseus_descr *descr, int *buf, unsigned int size);
681 // int perseus_set_attenuator_n (perseus_descr *descr, int nlo);
682 // void perseus_set_debug(int level);
683 // *************************************************************
684 
685 typedef int (*p_perseus_init)(void);
686 typedef int (*p_perseus_exit)(void);
687 typedef perseus_descr* (*p_perseus_open)(int nDev);
688 typedef int (*p_perseus_set_attenuator)(perseus_descr *descr, uint8_t atten_id);
689 typedef int (*p_perseus_close)(perseus_descr *descr);
690 typedef int (*p_perseus_firmware_download)(perseus_descr *descr, char *fname);
691 typedef int (*p_perseus_get_product_id)(perseus_descr *descr, eeprom_prodid *prodid);
692 typedef int (*p_perseus_set_ddc_center_freq)(perseus_descr *descr,  double center_freq_hz, int enablePresel);
693 typedef int (*p_perseus_start_async_input)(perseus_descr *descr, uint32_t buffersize, perseus_input_callback callback, void *cb_extra);
694 typedef int (*p_perseus_get_sampling_rates)(perseus_descr *descr, int *buf, unsigned int size);
695 typedef int (*p_perseus_set_sampling_rate_n)(perseus_descr *descr, unsigned int new_sample_rate_ordinal);
696 typedef int (*p_perseus_stop_async_input)(perseus_descr *descr);
697 typedef char* (*p_perseus_errorstr)(void);
698 
699 p_perseus_init perseus_init;
700 p_perseus_exit perseus_exit;
701 p_perseus_open perseus_open;
702 p_perseus_set_attenuator perseus_set_attenuator;
703 p_perseus_close perseus_close;
704 p_perseus_firmware_download perseus_firmware_download;
705 p_perseus_get_product_id perseus_get_product_id;
706 p_perseus_set_ddc_center_freq perseus_set_ddc_center_freq;
707 p_perseus_start_async_input perseus_start_async_input;
708 p_perseus_get_sampling_rates perseus_get_sampling_rates;
709 p_perseus_set_sampling_rate_n perseus_set_sampling_rate_n;
710 p_perseus_stop_async_input  perseus_stop_async_input;
711 p_perseus_errorstr perseus_errorstr;
712 
713 static void *perseus_libhandle=NULL;
714 
load_perseus_library(void)715 int load_perseus_library(void)
716 {
717 int info;
718 info=0;
719 if(perseus_libhandle)return 0;
720 perseus_libhandle=dlopen(PERSEUS_LIBNAME, RTLD_LAZY);
721 if(!perseus_libhandle)goto perseus_load_error;
722 info=1;
723 perseus_init=(p_perseus_init)dlsym(perseus_libhandle, "perseus_init");
724 if(!perseus_init)goto perseus_sym_error;
725 perseus_exit=(p_perseus_exit)dlsym(perseus_libhandle, "perseus_exit");
726 perseus_open=(p_perseus_open)dlsym(perseus_libhandle, "perseus_open");
727 perseus_set_attenuator=(p_perseus_set_attenuator)dlsym(perseus_libhandle, "perseus_set_attenuator");
728 perseus_close=(p_perseus_close)dlsym(perseus_libhandle, "perseus_close");
729 perseus_firmware_download=(p_perseus_firmware_download)dlsym(perseus_libhandle, "perseus_firmware_download");
730 perseus_get_product_id=(p_perseus_get_product_id)dlsym(perseus_libhandle, "perseus_get_product_id");
731 perseus_set_ddc_center_freq=(p_perseus_set_ddc_center_freq)dlsym(perseus_libhandle, "perseus_set_ddc_center_freq");
732 perseus_start_async_input=(p_perseus_start_async_input)dlsym(perseus_libhandle, "perseus_start_async_input");
733 perseus_get_sampling_rates=(p_perseus_get_sampling_rates)dlsym(perseus_libhandle, "perseus_get_sampling_rates");
734 perseus_set_sampling_rate_n=(p_perseus_set_sampling_rate_n)dlsym(perseus_libhandle, "perseus_set_sampling_rate_n");
735 perseus_stop_async_input=(p_perseus_stop_async_input)dlsym(perseus_libhandle, "perseus_stop_async_input");
736 perseus_errorstr=(p_perseus_errorstr)dlsym(perseus_libhandle, "perseus_errorstr");
737 return 0;
738 perseus_sym_error:;
739 dlclose(perseus_libhandle);
740 perseus_load_error:;
741 library_error_screen(PERSEUS_LIBNAME,info);
742 return -1;
743 }
744 
unload_perseus_library(void)745 void unload_perseus_library(void)
746 {
747 if(!perseus_libhandle)return;
748 dlclose(perseus_libhandle);
749 perseus_libhandle=NULL;
750 }
751 
752 
set_perseus_frequency(void)753 void set_perseus_frequency(void)
754 {
755 double dt1;
756 dt1=fg.passband_center*1000000;
757 if(dt1 < 0 || dt1 > adjusted_sdr_clock/2)
758   {
759   fg.passband_center=7.05;
760   dt1=fg.passband_center*1000000;
761   }
762 dt1/=adjusted_sdr_clock/PERSEUS_SAMPLING_CLOCK;
763 perseus_set_ddc_center_freq(descr, dt1, pers.presel);
764 }
765 
fill_perseus_rates(void)766 void fill_perseus_rates(void)
767 {
768 /*
769 if (perseus_get_sampling_rates (descr, perseus_rates, PERSEUS_RATES_BUFSIZE))
770   {
771   lirerr(1196);
772   return;
773   }
774 no_of_perseus_rates = 0;
775 while (perseus_rates[no_of_perseus_rates] > 1)
776   {
777   no_of_perseus_rates++;
778   }
779 */
780 int pr[PERSEUS_RATES_BUFSIZE];
781 double dt1;
782 if (perseus_get_sampling_rates (descr, pr, PERSEUS_RATES_BUFSIZE))
783   {
784   lirerr(1196);
785   return;
786   }
787 no_of_perseus_rates = 0;
788 while (pr[no_of_perseus_rates] > 1)
789   {
790   switch (pr[no_of_perseus_rates])
791     {
792     case 48000:
793     dt1=PERSEUS_SAMPLING_CLOCK/1664;
794     break;
795 
796     case 95000:
797     dt1=PERSEUS_SAMPLING_CLOCK/840;
798     break;
799 
800     case 96000:
801     dt1=PERSEUS_SAMPLING_CLOCK/832;
802     break;
803 
804     case 192000:
805     dt1=PERSEUS_SAMPLING_CLOCK/416;
806     break;
807 
808     default:
809     dt1=(double)pr[no_of_perseus_rates];
810     }
811   perseus_rates[no_of_perseus_rates]=dt1;
812   no_of_perseus_rates++;
813   }
814 }
815 
perseus_stop(void)816 void perseus_stop(void)
817 {
818 perseus_stop_async_input(descr);
819 lir_sleep(10000);
820 }
821 
822 
823 
perseus_callback(void * buf,int buf_size,void * extra)824 int perseus_callback(void *buf, int buf_size, void *extra)
825 {
826 int i;
827 register char c1;
828 char *pBuf;
829 (void)extra;
830 pBuf=(char*)buf;
831 c1=0;
832 // This callback gets called whenever a buffer is ready
833 // from the USB interface
834 for(i=0; i<buf_size; i+=6)
835   {
836   timf1_char[timf1p_sdr+3]=pBuf[i+2];
837   c1=pBuf[i+2]&0x80;
838   timf1_char[timf1p_sdr+2]=pBuf[i+1];
839   timf1_char[timf1p_sdr+1]=pBuf[i  ];
840   c1|=pBuf[i];
841   timf1_char[timf1p_sdr  ]=0;
842   timf1_char[timf1p_sdr+7]=pBuf[i+5];
843   timf1_char[timf1p_sdr+6]=pBuf[i+4];
844   timf1_char[timf1p_sdr+5]=pBuf[i+3];
845   timf1_char[timf1p_sdr+4]=0;
846   timf1p_sdr=(timf1p_sdr+8)&timf1_bytemask;
847   }
848 if( (c1&1) != 0)
849   {
850   ad_maxamp[0]=0x7fff;
851   ad_maxamp[1]=0x7fff;
852   }
853 if(((timf1p_sdr-timf1p_pa+timf1_bytes)&timf1_bytemask) >=
854               (int)snd[RXAD].block_bytes)lir_set_event(EVENT_PERSEUS_INPUT);
855 return 0;
856 }
857 
start_perseus_read(void)858 void start_perseus_read(void)
859 {
860 int i;
861 sdr=-1;
862 perseus_bytesperbuf=snd[RXAD].block_bytes/PERSEUS_BYTESPERFRAME;
863 perseus_bytesperbuf*=PERSEUS_BYTESPERFRAME;
864 if(perseus_bytesperbuf > MAX_LIBUSB_BULK_BUFFER)
865   {
866   perseus_bytesperbuf=MAX_LIBUSB_BULK_BUFFER/PERSEUS_BYTESPERFRAME;
867   perseus_bytesperbuf*=PERSEUS_BYTESPERFRAME;
868   }
869 timf1p_sdr=timf1p_pa;
870 lir_sched_yield();
871 i=perseus_start_async_input(descr,perseus_bytesperbuf, perseus_callback, NULL);
872 if(i < 0)
873   {
874   lirerr(1195);
875   return;
876   }
877 sdr=0;
878 }
879 
lir_perseus_read(void)880 void lir_perseus_read(void)
881 {
882 while(((timf1p_sdr-timf1p_pa+timf1_bytes)&timf1_bytemask) < (int)snd[RXAD].block_bytes)
883   {
884   lir_await_event(EVENT_PERSEUS_INPUT);
885   }
886 }
887 
perseus_load_proprietary_code(int rate_no)888 int perseus_load_proprietary_code(int rate_no)
889 {
890 int i;
891 i=perseus_set_sampling_rate_n(descr, rate_no);
892 if(i<0) return 1194;
893 return 0;
894 }
895 
perseus_eeprom_read(unsigned char * buf,int addr,unsigned char count)896 int perseus_eeprom_read(unsigned char *buf, int addr, unsigned char count)
897 {
898 eeprom_prodid *prodid;
899 int i;
900 char s[80];
901 prodid=(eeprom_prodid*) buf;
902 (void) buf;
903 (void) addr;
904 (void) count;
905 i=perseus_get_product_id(descr,prodid);
906 if(i<0)
907   {
908   sprintf(s,"get product id error: %s", perseus_errorstr());
909   clear_screen();
910   lir_text(5,5,s);
911   lir_text(5,7,press_any_key);
912   await_processed_keyboard();
913   lirerr(1193);
914   return 1;
915   }
916 return 0;
917 }
918 
open_perseus(void)919 void open_perseus(void)
920 {
921 int i;
922 if(sdr != -1)
923   {
924   return;
925   }
926 load_usb1_library(TRUE);
927 if(libusb1_library_flag == FALSE)return;
928 if(load_perseus_library() != 0)return;
929 if(perseus_init() == 0)
930   {
931   lir_text(3,3,"Could not init. Is Perseus connected with power on?");
932 conerr:;
933   return;
934   }
935 descr=perseus_open(0);
936 if(descr == NULL)
937   {
938   clear_screen();
939   lir_text(3,2,"Could not open Perseus. Do you have write permission to USB?");
940   lir_text(3,3,"Maybe you should use sudo (or run as root)");
941   goto conerr;
942   }
943 i=perseus_firmware_download(descr,NULL);
944 if(i < 0)
945   {
946   close_perseus();
947   return;
948   }
949 sdr=0;
950 }
951 
perseus_store_att(unsigned char idAtt)952 void perseus_store_att(unsigned char idAtt)
953 {
954 perseus_set_attenuator(descr, idAtt);
955 }
956 
perseus_store_presel(unsigned char idPresel)957 void perseus_store_presel(unsigned char idPresel)
958 {
959 (void) idPresel;
960 }
961 
close_perseus(void)962 void close_perseus(void)
963 {
964 perseus_close(descr);
965 perseus_exit();
966 sdr=-1;
967 unload_perseus_library();
968 unload_usb1_library();
969 }
970 
971 #endif
972 
973 // |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
974 
display_perseus_parm_info(int * line)975 int display_perseus_parm_info(int *line)
976 {
977 char s[80];
978 int i, errcod;
979 errcod=read_sdrpar(perseus_parfil_name, MAX_PERSEUS_PARM,
980                                      perseus_parm_text, (int*)((void*)&pers));
981 if(errcod == 0)
982   {
983 #if(OSNUM == OSNUM_LINUX)
984     if(load_perseus_library() != 0)return -99;
985     fill_perseus_rates();
986     for(i=0; i<no_of_perseus_rates; i++)
987       {
988       rate_factor[i]=PERSEUS_SAMPLING_CLOCK/perseus_rates[i];
989       }
990     unload_perseus_library();
991 #endif
992 #if(OSNUM == OSNUM_WINDOWS)
993     for(i=0; i<MAX_PERSEUS_RATES; i++)
994       {
995       perseus_rates[i]=PERSEUS_SAMPLING_CLOCK/rate_factor[i];
996       }
997     no_of_perseus_rates=MAX_PERSEUS_RATES;
998 #endif
999   settextcolor(7);
1000   sprintf(s,"rate number        = %i ", pers.rate_no);
1001   if(perseus_rates[pers.rate_no] > 999999.9)
1002     {
1003     sprintf(s,"rate number        = %i (%8.3f MHz)",
1004                          pers.rate_no, 0.000001*perseus_rates[pers.rate_no]);
1005     }
1006   else
1007     {
1008     sprintf(s,"rate number        = %i (%8.3f kHz)",
1009                          pers.rate_no, 0.001*perseus_rates[pers.rate_no]);
1010     }
1011   lir_text(24,line[0],s);
1012   SNDLOG"\n%s",s);
1013   line[0]+=1;
1014   sprintf(s,"clock adjustment   = %i", pers.clock_adjust);
1015   lir_text(24,line[0],s);
1016   SNDLOG"\n%s",s);
1017   line[0]+=1;
1018   sprintf(s,"preselector        = %i", pers.presel);
1019   lir_text(24,line[0],s);
1020   SNDLOG"\n%s",s);
1021   line[0]+=1;
1022   sprintf(s,"preamplifier       = %i", pers.preamp);
1023   lir_text(24,line[0],s);
1024   SNDLOG"\n%s",s);
1025   line[0]+=1;
1026   sprintf(s,"dither             = %i", pers.dither);
1027   lir_text(24,line[0],s);
1028   SNDLOG"\n%s\n",s);
1029   }
1030 return (errcod);
1031 }
1032 
init_perseus(void)1033 void init_perseus(void)
1034 {
1035 int i, k;
1036 char s[80];
1037 char *ss;
1038 int *sdr_pi;
1039 int line;
1040 char *looking;
1041 eeprom_prodid prodid;
1042 FILE *perseus_file;
1043 looking="Looking for a Perseus on the USB port.";
1044 settextcolor(12);
1045 lir_text(10,10,looking);
1046 SNDLOG"\n%s",looking);
1047 lir_text(10,11,"Reset CPU, USB and SDR hardware if system hangs here.");
1048 lir_refresh_screen();
1049 settextcolor(14);
1050 sdr=-1;
1051 open_perseus();
1052 settextcolor(7);
1053 clear_lines(10,11);
1054 lir_refresh_screen();
1055 line=0;
1056 if(sdr != -1)
1057   {
1058   lir_text(5,5,"A Perseus is detected on the USB port.");
1059   lir_text(5,6,"Do you want to use it for RX input (Y/N)?");
1060 qpers:;
1061   await_processed_keyboard();
1062   if(kill_all_flag) goto pers_errexit;
1063   if(lir_inkey == 'Y')
1064     {
1065 #if(OSNUM == OSNUM_WINDOWS)
1066     ss=perseus_frname();
1067     if(ss == NULL)goto pers_errexit;
1068     sprintf(s,"USB Friendly device Name is: %s",ss);
1069     lir_text(2,8,s);
1070     SNDLOG"%s\n",s);
1071     ss=m_pGetDeviceName();
1072     if(ss == NULL)goto pers_errexit;
1073     sprintf(s,"USB Device Name is: %s",ss);
1074     lir_text(2,9,s);
1075     SNDLOG"%s\n",s);
1076 #else
1077     ss="Perseus";
1078 #endif
1079     ui.rx_addev_no=PERSEUS_DEVICE_CODE;
1080     ui.rx_input_mode=IQ_DATA+DIGITAL_IQ+DWORD_INPUT;
1081     ui.rx_rf_channels=1;
1082     ui.rx_ad_channels=2;
1083     ui.rx_admode=0;
1084     perseus_eeprom_read((unsigned char*)&prodid,
1085                                        ADDR_EEPROM_PRODID, sizeof(prodid));
1086     if(kill_all_flag)goto pers_errexit;
1087     sprintf(s,"Microtelecom product code: 0x%04X", prodid.prodcode);
1088     lir_text(2,10,s);
1089     SNDLOG"%s\n",s);
1090     sprintf(s,"Serial Number: %05hd-%02hX%02hX-%02hX%02hX-%02hX%02hX",
1091 				(unsigned short)prodid.sn,
1092 				(unsigned short)prodid.signature[5],
1093 				(unsigned short)prodid.signature[4],
1094 				(unsigned short)prodid.signature[3],
1095 				(unsigned short)prodid.signature[2],
1096 				(unsigned short)prodid.signature[1],
1097 				(unsigned short)prodid.signature[0]);
1098     lir_text(2,11,s);
1099     SNDLOG"%s\n",s);
1100     sprintf(s,"Hardware version/revision: %d.%d",
1101                          (unsigned)prodid.hwver, (unsigned)prodid.hwrel);
1102     lir_text(2,12,s);
1103     SNDLOG"%s\n",s);
1104     lir_text(10,16,"PRESS ANY KEY");
1105     await_processed_keyboard();
1106     if(kill_all_flag) goto pers_errexit;
1107     clear_screen();
1108     sprintf(s,"%s selected for input",ss);
1109     lir_text(10,line,s);
1110     line+=2;
1111 #if(OSNUM == OSNUM_WINDOWS)
1112     for(i=0; i<MAX_PERSEUS_RATES; i++)
1113       {
1114       perseus_rates[i]=PERSEUS_SAMPLING_CLOCK/rate_factor[i];
1115       }
1116     no_of_perseus_rates=MAX_PERSEUS_RATES;
1117 #else
1118     fill_perseus_rates();
1119     for(i=0; i<no_of_perseus_rates; i++)
1120       {
1121       rate_factor[i]=PERSEUS_SAMPLING_CLOCK/perseus_rates[i];
1122       }
1123 #endif
1124     k=no_of_perseus_rates-1;
1125     if(ui.operator_skil == OPERATOR_SKIL_NEWCOMER)k-=2;
1126     for(i=0; i<no_of_perseus_rates; i++)
1127       {
1128       if(i>k)settextcolor(8);
1129       if(perseus_rates[i] > 999999.9)
1130         {
1131         sprintf(s,"%d %8.3f MHz ",i,0.000001*perseus_rates[i]);
1132         }
1133       else
1134         {
1135         sprintf(s,"%d %8.3f kHz ",i,0.001*perseus_rates[i]);
1136         }
1137       lir_text(5,line,s);
1138       line++;
1139       }
1140     settextcolor(7);
1141     line++;
1142     sprintf(s,"Set USB sampling rate (by number 0 to %d)",k);
1143     lir_text(5,line,s);
1144     pers.rate_no=lir_get_integer(50, line, 2, 0, k);
1145     if(kill_all_flag)goto pers_errexit;
1146     line++;
1147     if(ui.operator_skil == OPERATOR_SKIL_NEWCOMER)
1148       {
1149       pers.clock_adjust=0;
1150       }
1151     else
1152       {
1153       sprintf(s,"Set sampling clock shift (Hz))");
1154       lir_text(5,line,s);
1155       pers.clock_adjust=lir_get_integer(50, line, 5,-10000,10000);
1156       if(kill_all_flag)goto pers_errexit;
1157       line++;
1158       }
1159     adjusted_sdr_clock=PERSEUS_SAMPLING_CLOCK+pers.clock_adjust;
1160     ui.rx_ad_speed=rint(adjusted_sdr_clock/rate_factor[pers.rate_no]);
1161     if(ui.operator_skil == OPERATOR_SKIL_NEWCOMER)
1162       {
1163       pers.presel=1;
1164       pers.preamp=1;
1165       pers.dither=1;
1166       }
1167     else
1168       {
1169       lir_text(5,line,"Enable preselector ? (0/1)");
1170       pers.presel=lir_get_integer(32, line, 1, 0, 1);
1171       if(kill_all_flag)goto pers_errexit;
1172       line++;
1173       lir_text(5,line,"Enable preamp ? (0/1)");
1174       pers.preamp=lir_get_integer(27, line, 1, 0, 1);
1175       if(kill_all_flag)goto pers_errexit;
1176       line++;
1177       lir_text(5,line,"Enable dither ? (0/1)");
1178       pers.dither=lir_get_integer(27, line, 1, 0, 1);
1179       if(kill_all_flag)goto pers_errexit;
1180       line++;
1181       }
1182     pers.check=PERSEUS_PAR_VERNR;
1183     perseus_file=fopen(perseus_parfil_name,"w");
1184     if(perseus_file == NULL)
1185       {
1186 pers_errexit:;
1187       close_perseus();
1188       clear_screen();
1189       ui.rx_addev_no=UNDEFINED_DEVICE_CODE;
1190       return;
1191       }
1192     sdr_pi=(int*)(&pers);
1193     for(i=0; i<MAX_PERSEUS_PARM; i++)
1194       {
1195       fprintf(perseus_file,"%s [%d]\n",perseus_parm_text[i],sdr_pi[i]);
1196       }
1197     parfile_end(perseus_file);
1198     }
1199   else
1200     {
1201     if(lir_inkey != 'N')goto qpers;
1202     clear_screen();
1203     }
1204   close_perseus();
1205   sdr=0;
1206   }
1207 else
1208   {
1209   clear_screen();
1210   lir_text(3,3,"Could not open Perseus.");
1211   lir_text(3,5,"Is the USB cable connected and the unit powered?");
1212 #if OSNUM == OSNUM_WINDOWS
1213   lir_text(3,7,"Are drive routines installed?");
1214 #endif
1215   SNDLOG"\nopen_perseus failed.\n");
1216   lir_text(8,11,press_any_key);
1217   await_processed_keyboard();
1218   }
1219 return;
1220 }
1221 
set_perseus_att(void)1222 void set_perseus_att(void)
1223 {
1224 int i;
1225 i=-fg.gain/10;
1226 perseus_store_att(i);
1227 }
1228 
perseus_input(void)1229 void perseus_input(void)
1230 {
1231 #if RUSAGE_OLD == TRUE
1232 int local_workload_counter;
1233 #endif
1234 int rxin_local_workload_reset;
1235 int i, j, errcod;
1236 char s[80];
1237 double dt1, read_start_time, total_reads;
1238 int timing_loop_counter,timing_loop_counter_max,initial_skip_flag;
1239 float t1;
1240 int local_att_counter;
1241 int local_nco_counter;
1242 #if OSNUM == OSNUM_LINUX
1243 clear_thread_times(THREAD_PERSEUS_INPUT);
1244 #endif
1245 #if RUSAGE_OLD == TRUE
1246 local_workload_counter=workload_counter;
1247 #endif
1248 local_att_counter=sdr_att_counter;
1249 local_nco_counter=sdr_nco_counter;
1250 dt1=current_time();
1251 j=0;
1252 while(sdr == -1)
1253   {
1254   open_perseus();
1255   if(sdr == -1)
1256     {
1257     sprintf(s,"Waiting %.2f", current_time()-dt1);
1258     lir_text(3,5,s);
1259     lir_refresh_screen();
1260     if(kill_all_flag)goto perseus_init_error_exit;
1261     lir_sleep(100000);
1262     if(j==0)
1263       {
1264       clear_screen();
1265       j=1;
1266       }
1267     }
1268   }
1269 errcod=1365;
1270 if(!libusb1_library_flag)goto perseus_init_error_exit;
1271 // ****************************************************
1272 // We have a connection to the Perseus.
1273 i=read_sdrpar(perseus_parfil_name, MAX_PERSEUS_PARM,
1274                                      perseus_parm_text, (int*)((void*)&pers));
1275 errcod=1080;
1276 if(i != 0)goto perseus_error_exit;
1277 if( pers.check != PERSEUS_PAR_VERNR ||
1278     pers.rate_no < 0 ||
1279     abs(pers.clock_adjust) > 10000)goto perseus_error_exit;
1280 #if(OSNUM == OSNUM_WINDOWS)
1281 if(pers.rate_no  >= MAX_PERSEUS_RATES)goto perseus_error_exit;
1282 #endif
1283 #if(OSNUM == OSNUM_LINUX)
1284 fill_perseus_rates();
1285 if(pers.rate_no  >= no_of_perseus_rates)goto perseus_error_exit;
1286 for(i=0; i<no_of_perseus_rates; i++)
1287   {
1288   rate_factor[i]=PERSEUS_SAMPLING_CLOCK/perseus_rates[i];
1289   }
1290 #endif
1291 errcod=0;
1292 adjusted_sdr_clock=PERSEUS_SAMPLING_CLOCK+pers.clock_adjust;
1293 t1=ui.rx_ad_speed-adjusted_sdr_clock/rate_factor[pers.rate_no];
1294 if(fabs(t1/ui.rx_ad_speed) > 0.0001)
1295   {
1296   errcod=1091;
1297   goto perseus_error_exit;
1298   }
1299 errcod=perseus_load_proprietary_code(pers.rate_no);
1300 if(errcod != 0)goto perseus_error_exit;
1301 ui.rx_ad_speed=adjusted_sdr_clock/rate_factor[pers.rate_no];
1302 timf1_sampling_speed=adjusted_sdr_clock/rate_factor[pers.rate_no];
1303 check_filtercorr_direction();
1304 set_perseus_att();
1305 set_perseus_frequency();
1306 fft1_block_timing();
1307 if(thread_command_flag[THREAD_SCREEN]!=THRFLAG_NOT_ACTIVE)
1308   {
1309   while(thread_status_flag[THREAD_SCREEN]!=THRFLAG_ACTIVE &&
1310         thread_status_flag[THREAD_SCREEN]!=THRFLAG_IDLE &&
1311         thread_status_flag[THREAD_SCREEN]!=THRFLAG_SEM_WAIT)
1312     {
1313     if(thread_command_flag[THREAD_PERSEUS_INPUT] ==
1314                                            THRFLAG_KILL)goto perseus_error_exit;
1315     lir_sleep(10000);
1316     }
1317   }
1318 start_perseus_read();
1319 if(sdr != 0) goto perseus_error_exit;
1320 #include "timing_setup.c"
1321 thread_status_flag[THREAD_PERSEUS_INPUT]=THRFLAG_ACTIVE;
1322 while(thread_command_flag[THREAD_PERSEUS_INPUT] == THRFLAG_ACTIVE)
1323   {
1324 #if RUSAGE_OLD == TRUE
1325   if(local_workload_counter != workload_counter)
1326     {
1327     local_workload_counter=workload_counter;
1328     make_thread_times(THREAD_PERSEUS_INPUT);
1329     }
1330 #endif
1331   if(local_att_counter != sdr_att_counter)
1332     {
1333     local_att_counter=sdr_att_counter;
1334     set_perseus_att();
1335     }
1336   if(local_nco_counter != sdr_nco_counter)
1337     {
1338     local_nco_counter=sdr_nco_counter;
1339     set_perseus_frequency();
1340     }
1341   lir_perseus_read();
1342   if(kill_all_flag)goto perseus_exit;
1343   while (!kill_all_flag &&
1344       ((timf1p_sdr-timf1p_pa+timf1_bytes)&timf1_bytemask)
1345                                          >= (int)snd[RXAD].block_bytes)
1346     {
1347 #include "input_speed.c"
1348     finish_rx_read();
1349     }
1350   }
1351 perseus_exit:;
1352 perseus_stop();
1353 perseus_error_exit:;
1354 if(errcod != 0)lirerr(errcod);
1355 close_perseus();
1356 perseus_init_error_exit:;
1357 thread_status_flag[THREAD_PERSEUS_INPUT]=THRFLAG_RETURNED;
1358 while(thread_command_flag[THREAD_PERSEUS_INPUT] != THRFLAG_NOT_ACTIVE)
1359   {
1360   lir_sleep(1000);
1361   }
1362 }
1363 
1364