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