// users_hwaredriver.c for external frequency control via serial port // for IC-275/IC-706/FT-1000/FT-736/TS-850/TS-2000 // version: 04 may 2007 // written for linrad 02-31 // runs under windows and linux // // To select a transceiver: uncomment the corresponding define statement // To generate a windows version in linux: // install mingw32 from Leif's website, // save this users_hwaredriver.c as wusers_hwaredriver.c // run ./configure and make linrad.exe // To generate a windows version in windows: // install mingw.zip and nasm.zip from Leif's website, // save this users_hwaredriver.c as wusers_hwaredriver.c // run configure.exe and make.bat //To add your own transceiver: // 1. Add a statement #define TRANSCEIVER_NAME "MYTRX" ( maximum 7 characters) // 2. Define the corresponding serial port parameters and frequency range. // (Look at line 618 for details ) // 3. Add the corresponding serial protocol // (Look at line 720 for details) // // Based on work from DL3IAE/IK7EZN/K1JT/ON4IY/ON7EH/W3SZ // with the support of Leif SM5BSZ // All errors are mine // Use at your own risk and enjoy // Pierre/ON5GN //#define TRANSCEIVER_NAME "IC-275" //#define TRANSCEIVER_NAME "IC-706A" //ICOM-706 //#define TRANSCEIVER_NAME "IC-706B" //ICOM-706MKII //#define TRANSCEIVER_NAME "IC-706C" //ICOM-706MKIIG //#define TRANSCEIVER_NAME "FT-1000" #define TRANSCEIVER_NAME "FT-736" //#define TRANSCEIVER_NAME "TS-850" //#define TRANSCEIVER_NAME "TS-2000" // valid ranges: SERPORT_NUMBER = 1 to 4 (1=COM1,4=COM4 ) #define SERPORT_NUMBER 1 // ****************************************************************************** // ROUTINES FOR A 'MOVABLE' FIXED SIZE USERGRAPH // screenposition of usergraph and offset values are // saved in the file par_"TRANSCEIVER_NAME" // The same file is used in all rx modes. // ****************************************************************************** #include #define NO_OF_BANDS 12 float bandlim[]={2.5, //0 5.0, //1 9.0, //2 12.0, //3 16.0, //4 19.0, //5 23.0, //6 26.0, //7 40.0, //8 100.0, //9 300.0, //10 BIG}; //11 #define USERS_GRAPH_TYPE1 64 typedef struct { int ytop; int ybottom; int xleft; int xright; int offs_hz[NO_OF_BANDS]; int offs_khz[NO_OF_BANDS]; int yborder; // required for move graph } UG_PARMS; #define UG_TOP 0 #define UG_BOTTOM 1 #define UG_LEFT 2 #define UG_RIGHT 3 #define UG_INCREASE_OFFS_HZ 4 #define UG_DECREASE_OFFS_HZ 5 #define UG_INCREASE_OFFS_KHZ 6 #define UG_DECREASE_OFFS_KHZ 7 #define MAX_UGBUTT 8 UG_PARMS ug; BUTTONS ugbutt[MAX_UGBUTT]; int ug_old_y1; int ug_old_y2; int ug_old_x1; int ug_old_x2; int users_graph_scro; int ug_oldx; // required for move graph int ug_oldy; // required for move graph int ug_yborder; // required for move graph int ug_hsiz; // required for move graph int ug_vsiz; // required for move graph int ug_band_no; #define MAX_MSGSIZE 30 //Size of messages. min size=30 char ug_msg0[MAX_MSGSIZE]; //messages in usergraph char ug_msg1[MAX_MSGSIZE]; char ug_msg2[MAX_MSGSIZE]; int ug_msg_red; //switch for message-color in usergraph char ugfile[20]; //name of usergraph parameter file double min_transceiver_freq=0; double max_transceiver_freq=0; void set_press_q_key_msg(void) { ug_msg_red=1; strcpy(ug_msg0,"PRESS Q-KEY TO SET FREQUENCY"); ug_msg1[0]=0; ug_msg2[0]=0; } void check_ug_borders(void) // required for move graph { current_graph_minh=ug_vsiz; current_graph_minw=ug_hsiz; check_graph_placement((void*)(&ug)); set_graph_minwidth((void*)(&ug)); } void show_offset(void) { char s[80]; sprintf(s,"Offset-fine(Hz): %d ",ug.offs_hz[ug_band_no]); s[25]=0; lir_pixwrite(ug.xleft+1.5*text_width,ug.ytop+1.5*text_height,s); sprintf(s,"Offset-raw(Khz): %d ",ug.offs_khz[ug_band_no]); s[25]=0; lir_pixwrite(ug.xleft+1.5*text_width,ug.ytop+1+2.5*text_height,s); } void blankfill_ugmsg(char *msg) { int i; i=strlen(msg); if(i>=MAX_MSGSIZE)lirerr(3413400); while(i>1; } graph_borders((void*)&ug,15); resume_thread(THREAD_SCREEN); break; default: goto await_release; } if(leftpressed == BUTTON_RELEASED)goto finish; return; await_release:; if(leftpressed != BUTTON_RELEASED) return; // Assuming the user wants to control hardware we // allow commands only when data is not over the network. if((ui.network_flag&NET_RX_INPUT) == 0) //for linrad02.23 { switch (mouse_active_flag-1) { case UG_INCREASE_OFFS_HZ: ug.offs_hz[ug_band_no]++; break; case UG_DECREASE_OFFS_HZ: ug.offs_hz[ug_band_no]--; break; case UG_INCREASE_OFFS_KHZ: ug.offs_khz[ug_band_no]++; break; case UG_DECREASE_OFFS_KHZ: ug.offs_khz[ug_band_no]--; break; default: // This should never happen. lirerr(211053); break; } set_press_q_key_msg(); } finish:; hide_mouse(ug_old_x1,ug_old_x2,ug_old_y1,ug_old_y2); leftpressed=BUTTON_IDLE; mouse_active_flag=0; graph_borders((void*)&ug,0); lir_fillbox(ug_old_x1,ug_old_y1,ug_old_x2-ug_old_x1,ug_old_y2-ug_old_y1,0); make_users_control_graph(); ug_oldx=-10000; } void new_user_offs_hz(void) { ug.offs_hz[ug_band_no]=numinput_int_data; pause_thread(THREAD_SCREEN); set_press_q_key_msg(); show_user_parms(); resume_thread(THREAD_SCREEN); } void new_user_offs_khz(void) { ug.offs_khz[ug_band_no]=numinput_float_data; pause_thread(THREAD_SCREEN); set_press_q_key_msg(); show_user_parms(); resume_thread(THREAD_SCREEN); } void mouse_on_users_graph(void) { int event_no; // First find out if we are on a button or border line. for(event_no=0; event_no= mouse_x && ugbutt[event_no].y1 <= mouse_y && ugbutt[event_no].y2 >= mouse_y) { ug_old_y1=ug.ytop; ug_old_y2=ug.ybottom; ug_old_x1=ug.xleft; ug_old_x2=ug.xright; mouse_active_flag=1+event_no; current_mouse_activity=mouse_continue_users_graph; return; } } // Not button or border. // Prompt the user for offs_hz or offs_khz depending on whether the mouse is // in the upper or the lower part of the window. mouse_active_flag=1; numinput_xpix=ug.xleft+18.5*text_width; if(mouse_x > ug.xleft+18.5*text_width && mouse_x < ug.xleft+25*text_width) { if(mouse_y > (ug.ytop+2*text_height)) { numinput_ypix=ug.ytop+(2.5*text_height)+1; numinput_chars=7; erase_numinput_txt(); numinput_flag=FIXED_FLOAT_PARM; par_from_keyboard_routine=new_user_offs_khz; //offset-raw } else { numinput_ypix=ug.ytop+1.5*text_height; numinput_chars=4; erase_numinput_txt(); numinput_flag=FIXED_INT_PARM; par_from_keyboard_routine=new_user_offs_hz; //offset-fine } } else { // If we did not select a numeric input by setting numinput_flag // we have to set mouse_active flag. // Set the routine to mouse_nothing, we just want to // set flags when the mouse button is released. current_mouse_activity=mouse_nothing; mouse_active_flag=1; } } void init_users_control_window(void) { int i; // Set graph position and offset values by reading usergraph file // FILE *Fp; sprintf(ugfile,"%s_ug",rxpar_filenames[rx_mode]); Fp=fopen(ugfile,"r"); if (Fp==NULL) // if file not found, use default-values { ug.xleft=60*text_width; //default-value for initial x position ug.ytop=(screen_last_line-4)*text_height; //default-value for initial y position for(i=0; i= MAX_SCRO)lirerr(89); } } void users_init_mode(void) { // A switch statement can be used to do different things depending on // the processing mode. //switch (rx_mode) // { // case MODE_WCW: // case MODE_HSMS: // case MODE_QRSS: // break; // case MODE_NCW: // case MODE_SSB: // Open a window to allow mouse control of your own things init_users_control_window(); // break; // case MODE_FM: // case MODE_AM: // case MODE_TXTEST: // case MODE_RX_ADTEST: // case MODE_TUNE: // break; // } } // ************************************************************* // END ROUTINES FOR 'MOVABLE' FIXED SIZE USERGRAPH // ************************************************************* void users_eme(void) { } void userdefined_u(void) { } void edit_ugmsg(char *s, double fq) { double t1; int i, j, k, m; // We are called with a frequency in Hz and already something written // in the msg string. Find out how many characters we have at our disposal. j=strlen(s); i=MAX_MSGSIZE-j-3; // We will insert separators for each group of 3 digits so we loose i/3 // positions. i-=i/3; // Find out the largest fq we can write in Hz. // Write in kHz if fq is above the limit. t1=i; t1=pow(10.0,t1)-1; if(fabs(fq) < t1) { sprintf (&s[j],"%.0f Hz",fq); } else { sprintf(&s[j],"%.0f kHz",fq/1000); } // Locate the blank in front of Hz or kHz. i=strlen(s); k=i; while(s[i] != ' ')i--; // Insert a separator for every 3 digits. i--; j=0; while(s[i-1] != ' ' && s[i-1] != '-') { j++; if(j==3) { k++; m=k; while(m > i) { s[m]=s[m-1]; m--; } s[i]=39; j=0; } i--; } // Align frequency information to the right j=MAX_MSGSIZE-1; s[j]='\x0'; k=j; while(s[k] != 'z')k--; if (k!=j-1){ m=j; while(s[m] != '=')m--; j--; for (i=k; i > m; i--) { s[j] = s[i]; s[i] = 32; j--; } for (i=j; i > m; i--) { s[i] = 32; j--; } } } void users_close_devices(void) { lir_close_serport(); } void users_open_devices(void) { int serport_baudrate; int serport_stopbits=1; // The parallel port is for the WSE units. if(ui.parport == 0) { allow_parport=FALSE; } else { if(lir_parport_permission()==TRUE) { allow_parport=TRUE; } else { allow_parport=FALSE; } } // initialize serial port parameters and frequency-range // according TRANSCEIVER_NAME // serport_baudrate = 110 to 57600 ( look at lxsys.c ) // serport_stopbits = 0 or 1 // min and max transceiver_frequency(Hz) : check your manual if (TRANSCEIVER_NAME=="IC-275") { serport_baudrate=9600; serport_stopbits=0; min_transceiver_freq=144000000; max_transceiver_freq=146000000; } if ( (TRANSCEIVER_NAME=="IC-706A") |(TRANSCEIVER_NAME=="IC-706B") |(TRANSCEIVER_NAME=="IC-706C") ) { serport_baudrate=9600; serport_stopbits=0; min_transceiver_freq=1800000; max_transceiver_freq=148000000; } if (TRANSCEIVER_NAME=="TS-850") { serport_baudrate=4800; serport_stopbits=1; min_transceiver_freq=1600000; max_transceiver_freq=30000000; } if (TRANSCEIVER_NAME=="TS-2000") { serport_baudrate=9600; serport_stopbits=0; min_transceiver_freq=1600000; max_transceiver_freq=148000000; } if (TRANSCEIVER_NAME=="FT-736") { serport_baudrate=4800; serport_stopbits=1; min_transceiver_freq=144000000; max_transceiver_freq=146000000; } if (TRANSCEIVER_NAME=="FT-1000") { serport_baudrate=4800; serport_stopbits=1; min_transceiver_freq=1600000; max_transceiver_freq=30000000; } lir_open_serport(SERPORT_NUMBER, // 1=COM1 or /dev/ttyS0 , 2=COM2.... serport_baudrate, // baudrate 110 to 57600 serport_stopbits); // 1=two stopbits, 0=one stopbit } void userdefined_q(void) { // ************************************************************************** // ROUTINES FOR EXTERNAL FREQUENCY CONTROL VIA SERIAL PORT // These routines are called when the 'Q' key is pressed // ************************************************************************** double transceiver_freq; double offset_hwfreq; unsigned long freq; double transverter_offset_raw; //raw offset in Khz (for tranverter) double transverter_offset_fine; //fine offset in Hz (for transverter) extern char serport_name[10]; unsigned char a; int n=-1; int i; char s[80]; //INITIALIZE //initialize message-area in usergraph ug_msg_red=1; strcpy(ug_msg0,"FREQUENCY SETTING IN PROGRESS"); ug_msg1[0]=0; ug_msg2[0]=0; show_user_parms(); //EXIT IF NO LINRAD-FREQUENCY IS SELECTED if(mix1_selfreq[0] < 0) { ug_msg_red=1; sprintf (ug_msg0,"NO FREQ. SELECT. ON W/F GRAPH"); goto userdefined_q_exit_1; } // EXIT IF INVALID TRANSCEIVER-FREQUENCY transverter_offset_raw=ug.offs_khz[ug_band_no]; //raw offset in Khz for transverter transverter_offset_fine=ug.offs_hz[ug_band_no]; //fine offset in Hz for transverter offset_hwfreq= transverter_offset_raw +(transverter_offset_fine*.001) ; //Freq in KHz transceiver_freq= (hwfreq+offset_hwfreq)*1000; transceiver_freq=floor(transceiver_freq); //Freq in Hz freq= transceiver_freq; if ((transceiver_freq < min_transceiver_freq ) ||(transceiver_freq > max_transceiver_freq)) { ug_msg_red=1; sprintf (ug_msg0,"INVALID %s FREQ.",TRANSCEIVER_NAME); goto userdefined_q_exit_2; } //OPEN SERIAL PORT ug_msg_red=0; sprintf (ug_msg0,"OPEN %s OK",serport_name ); // ISSUE 'SET FREQUENCY COMMAND' ACCORDING TRANSCEIVER_NAME // input: freq or transceiver_freq // proces:convert input to 'set frequency command' message string // output: use 'n=lir_write_serport(message string,message_length);' // ***********************IC-275/IC-706 ROUTINE******************** if ((TRANSCEIVER_NAME=="IC-275") |(TRANSCEIVER_NAME=="IC-706A") |(TRANSCEIVER_NAME=="IC-706B") |(TRANSCEIVER_NAME=="IC-706C") ) { struct { // 'Set Frequency message' for IC-275/IC-706 char prefix[2]; char radio_addr; char computer_addr; char cmd_nr; unsigned char freq[5]; char suffix; } msg0 = {0xFE, 0xFE, // preamble code x 2 0x10, // receive address for IC-275 0xE0, // transmit address of controller 0x05, // 'set freq' cmnd code 0x00,0x00,0x00,0x00,0x00, // freq // 145.678.900 Hz is encoded as x00 x89 x67 x45 x01 0xFD}; // end of message code if (TRANSCEIVER_NAME=="IC-706A") msg0.radio_addr='\x48'; // receive address for IC-706 if (TRANSCEIVER_NAME=="IC-706B") msg0.radio_addr='\x4e'; // receive address for IC-706MKII if (TRANSCEIVER_NAME=="IC-706C") msg0.radio_addr='\x58'; // receive address for IC-706MKIIG //convert 10 digits of freq to packed bcd and store in msg0.freq, //put first digit-pair in FIRST output byte for (i=0; i < 5; i++) { a = freq%10; freq /= 10; a |= (freq%10)<<4; freq /= 10; msg0.freq[i]= a; //printf("\n %#4.2x ",msg0.freq[i]); //trace output to screen } //printf("\n"); //'next line' to display last trace entry // write 'Set Frequency message' to serial port n=lir_write_serport((char *) &msg0, sizeof(msg0)); } // ***********************TS850/TS-2000 ROUTINE**************** if ((TRANSCEIVER_NAME=="TS-850") |(TRANSCEIVER_NAME=="TS-2000")) { // "VFO-A frequency" command // Freq in Hz; 11 digits, leading zeros, no decimal point, trailing semicolon. sprintf (s,"FA%011.0f;",transceiver_freq); n=lir_write_serport(s,14); //printf("\n %s",s); //trace output to screen //printf("\n"); //'next line' to display last trace entry } // ************************FT736 ROUTINE********************** if (TRANSCEIVER_NAME=="FT-736") { unsigned char open_cmnd[5] = { 0x00, 0x00, 0x00, 0x00, 0x00}; unsigned char close_cmnd[5] = { 0x80, 0x80, 0x80, 0x80, 0x80}; unsigned char setfreq_cmnd[5]= { 0x00, 0x00, 0x00, 0x00, 0x01}; // 145.678.900 HZ is encoded as x14 x56 x78 x90, last byte 0x01 is set freq cmnd code unsigned char cat_cmnd[5]; int write_cat_cmnd(void) { int r; for (i=0;i<5;i=i+1) { r=lir_write_serport((char*)&cat_cmnd[i],1); if (r<0) return -1; // printf("\n %#4.2x ",cat_cmnd[i]); //trace output to screen lir_sleep(50000); // wait 50msec between each byte } return 0; } //open CAT system memcpy(cat_cmnd,open_cmnd, 5); n=write_cat_cmnd(); if (n<0) goto ft736_exit; //discard least significant digit of freq //convert next 8 digits of freq to packed bcd and store in setfreq_cmd //put first digit-pair in LAST output byte freq /= 10; for (i=0; i < 4; i++) { a = freq%10; freq /= 10; a |= (freq%10)<<4; freq /= 10; setfreq_cmnd[3-i]= a; } //write setfreq_cmd to the serial port memcpy(cat_cmnd,setfreq_cmnd, 5); n=write_cat_cmnd(); if (n<0) goto ft736_exit; //close CAT system memcpy(cat_cmnd,close_cmnd, 5); n=write_cat_cmnd(); ft736_exit:; //printf("\n"); //'next line' to display last trace entry } // ***************************FT-1000 ROUTINE********************* if (TRANSCEIVER_NAME=="FT-1000") { unsigned char setfreq_cmnd[5]= { 0x00, 0x00, 0x00, 0x00, 0x0a}; // 014.250.000 Hz is encoded as x00 x50 x42 x01,last byte 0x0a is set freq cmnd code //discard least significant digit of freq //convert next 8 digits of freq to packed bcd and store in setfreq_cmd, //put first digit-pair in FIRST output byte freq /= 10; for (i=0; i < 4; i++) { a = freq%10; freq /= 10; a |= (freq%10)<<4; freq /= 10; setfreq_cmnd[i]= a; } //write setfreq_cmnd to the serial port for (i=0;i<5;i=i+1) { n=lir_write_serport((char*)&setfreq_cmnd[i],1); if (n<0) goto ft1000_exit; //printf("\n %#4.2x ",setfreq_cmnd[i]); //trace output to screen lir_sleep(5000); // wait 5msec between each write } ft1000_exit:; //printf("\n"); //'next line' to display last trace entry } // *************END 'SET FREQUENCY COMMAND' ROUTINES ******** //DISPLAY MESSAGES IN USERGRAPH if (n<0) { ug_msg_red=1; sprintf (ug_msg0,"WRITE TO %s FAILED",serport_name); goto userdefined_q_exit_1; } ug_msg_red=0; sprintf (ug_msg0,"LINRAD FREQ = "); i=strlen(ug_msg0); edit_ugmsg(ug_msg0,floor(hwfreq*1000)); userdefined_q_exit_2:; sprintf (ug_msg1,"TOTAL OFFSET= "); i=strlen(ug_msg1); edit_ugmsg(ug_msg1,offset_hwfreq*1000); sprintf (ug_msg2,"%s FREQ= ",TRANSCEIVER_NAME); edit_ugmsg(ug_msg2, transceiver_freq); userdefined_q_exit_1:; show_user_parms(); } // ************************************************************************** // **** END ROUTINES FOR FREQUENCY SETTING OF TRANSCEIVER VIA SERIAL PORT *** // ************************************************************************** // ********************************************************** // WSE and SDR-14/SDR-IQ drive routines // Note that set_hardware_rx_frequency() makes a call to // set_ug_band_no(). This is an addition to the code in // hwaredriver.c which is otherwise identical to the code here. // ********************************************************** char hware_outdat; char device_bits[256]; int device_data[256]; unsigned char hware_updates[256]; char *device_name[256]; int hware_retry; int hware_device_no; int hware_data; int hware_bits; int hware_no_of_updates; typedef struct { double increment; double lowest; double highest; int direction; int label; } FQ_INFO; // ********************************************************** // WSE TX drive routines // ********************************************************** // Associate a number to each frequency band that will // need a separate case in set_hardware_tx_frequency. #define TX_AUDIO_MODE 0 #define TX2500_TO_ANT 1 #define TX10700_TO_ANT 2 #define TX70_TO_ANT 3 #define TX144_TO_ANT 4 #define TXHFA_TO_ANT_1800 5 #define TXHFA_TO_ANT_3500 6 #define TXHFA_TO_ANT_7000 7 #define TXHFA_TO_ANT_10000 8 #define TXHFA_TO_ANT_14000 9 #define MAX_TX_BANDS 10 #define TX_BASEBAND_MINFREQ 0.013 //13 kHz #define TX_BASEBAND_MAXFREQ 0.038 //38 kHz (13+25kHz) FQ_INFO tx_fqinfo[MAX_TX_BANDS]= {0.0 , 0.0 , 0.0 , 1, TX_AUDIO_MODE, 0.025, 1.675, 2.150,-1, TXHFA_TO_ANT_1800, 0.025, 2.500, 2.500, 1, TX2500_TO_ANT, 0.025, 3.475, 3.950,-1, TXHFA_TO_ANT_3500, 0.025, 6.975, 7.450,-1, TXHFA_TO_ANT_7000, 0.025, 9.975, 10.450,-1, TXHFA_TO_ANT_10000, 0.025, 10.675, 10.750,-1, TX10700_TO_ANT, 0.025, 13.975, 14.450,-1, TXHFA_TO_ANT_14000, 0.025, 69.975, 70.450,-1, TX70_TO_ANT, 0.025, 143.975, 145.950,-1, TX144_TO_ANT }; char *device_name_tx10700={"TX10700"}; char *device_name_tx70={"TX70"}; char *device_name_txhfa144={"TX144 or TXHFA"}; void set_txhfa_data(int band) { if(device_data[TX144] != band) { device_data[TXHFA]=band; device_bits[TXHFA]=5; hware_no_of_updates++; hware_updates[hware_no_of_updates]=TXHFA; } } int set_tx144_data(int stepno) { int i; i=8; while(stepno >= 20) { i>>=1; stepno-=20; } if(device_data[TX144] != i) { device_data[TX144]=i; device_bits[TX144]=4; hware_no_of_updates++; hware_updates[hware_no_of_updates]=TX144; } return stepno; } void set_tx10700_data(int stepno) { int i; i=8; while(stepno != 0) { i>>=1; stepno--; } if(device_data[TX10700] != i) { device_data[TX10700]=i; device_bits[TX10700]=4; hware_no_of_updates++; hware_updates[hware_no_of_updates]=TX10700; } } int set_tx70_data(int stepno) { int i; i=16; while(stepno >= 4) { i>>=1; stepno-=4; } if(device_data[TX70] != i) { device_data[TX70]=i; device_bits[TX70]=5; hware_no_of_updates++; hware_updates[hware_no_of_updates]=TX70; } return stepno; } void set_hardware_tx_frequency(void) { int old_updates; float t1; int band_no, stepno; if( ui.parport == 0 || !allow_parport)return; if(hware_no_of_updates > 127)lirerr(213766); band_no=0; while(band_no < MAX_TX_BANDS-1 && tg.freq+TX_BASEBAND_MINFREQ > tx_fqinfo[band_no].highest)band_no++; if(tg.freq+TX_BASEBAND_MAXFREQ < tx_fqinfo[band_no].lowest && band_no > 0) { t1=0.5*(tx_fqinfo[band_no].lowest+tx_fqinfo[band_no-1].highest); if(tg.freq < t1)band_no--; } t1=tg.freq+0.5*(TX_BASEBAND_MINFREQ-TX_BASEBAND_MAXFREQ); if(t1<0)t1=0; stepno=(t1-tx_fqinfo[band_no].lowest)/tx_fqinfo[band_no].increment; if(stepno < 0)stepno=0; set_fq:; tg.band_center=tx_fqinfo[band_no].lowest+stepno*tx_fqinfo[band_no].increment; if(tg.band_center > tx_fqinfo[band_no].highest+0.001) { stepno--; goto set_fq; } tg_basebfreq=tg.freq-tg.band_center; if(tg_basebfreq < TX_BASEBAND_MINFREQ)tg_basebfreq=TX_BASEBAND_MINFREQ; if(tg_basebfreq > TX_BASEBAND_MAXFREQ)tg_basebfreq=TX_BASEBAND_MAXFREQ; tg.freq=tg_basebfreq+tg.band_center; tg.band_increment = tx_fqinfo[band_no].increment; tg.band_direction = tx_fqinfo[band_no].direction; // ööö tx_sideband=tg.band_direction; // Set up data to switch relays to connect units properly. // and to select the correct LO frequency for all units in use. make_tx_phstep(); old_updates=hware_no_of_updates; switch (tx_fqinfo[band_no].label) { case TX_AUDIO_MODE: // Send nothing to the hardware, just set frequency // and direction to zero so frequency scale in waterfall and // other graphs gives audio frequency. break; case TX2500_TO_ANT: // Route the signal source to the TX2500 input. break; case TX10700_TO_ANT: // Route TX10700 output to the TX2500 input. // Route the signal source to the TX10700 input. goto set_10700; case TX70_TO_ANT: // Route TX70 output to the TX10700 input. // Route TX10700 output to the TX2500 input. // Route the signal source to the TX10700 input. goto set_70; case TXHFA_TO_ANT_1800: // Route TXHFA output to the TX70 input. // Route TX70 output to the TX10700 input. // Route TX10700 output to the TX2500 input. // Route the signal source to the TXHFA input. set_txhfa_data(16); goto set_70; case TXHFA_TO_ANT_3500: // Route TXHFA output to the TX70 input. // Route TX70 output to the TX10700 input. // Route TX10700 output to the TX2500 input. // Route the signal source to the TXHFA input. set_txhfa_data(8); goto set_70; case TXHFA_TO_ANT_7000: // Route TXHFA output to the TX70 input. // Route TX70 output to the TX10700 input. // Route TX10700 output to the TX2500 input. // Route the signal source to the TXHFA input. set_txhfa_data(4); goto set_70; case TXHFA_TO_ANT_10000: // Route TXHFA output to the TX70 input. // Route TX70 output to the TX10700 input. // Route TX10700 output to the TX2500 input. // Route the signal source to the TXHFA input. set_txhfa_data(2); goto set_70; case TXHFA_TO_ANT_14000: // Route TXHFA output to the TX70 input. // Route TX70 output to the TX10700 input. // Route TX10700 output to the TX2500 input. // Route the signal source to the TXHFA input. set_txhfa_data(1); goto set_70; case TX144_TO_ANT: // Route TX144 output to the TX70 input. // Route TX70 output to the TX10700 input. // Route TX10700 output to the TX2500 input. // Route the signal source to the TX10700 input. stepno=set_tx144_data(stepno); set_70:; stepno=set_tx70_data(stepno); set_10700:; set_tx10700_data(stepno); break; } if(hware_no_of_updates != old_updates) { hware_flag=1; hware_time=current_time(); } } void hware_hand_key(void) { int i; // This routine is called from the rx_input_thread. // It is responsible for reading the hardware and setting // hand_key to TRUE or FALSE depending on whether the hand key // is depressed or not. if( ui.parport != 0 && allow_parport) { i=lir_inb(parport_status)&HWARE_MORSE_KEY; if(i==0) { hand_key=TRUE; } else { hand_key=FALSE; } } } void hware_set_rxtx(int state) { if( ui.parport != 0 && allow_parport) { lir_mutex_lock(); if(state == TRUE) { hware_outdat&=-1-HWARE_RXTX; } else { hware_outdat|=HWARE_RXTX; } lir_mutex_unlock(); lir_outb(hware_outdat,parport_control); } } // ********************************************************** // WSE RX drive routines // ********************************************************** // The radio hardware may be designed in many different ways. // When the user selects a new frequency there may be several // different hardware units that have to be changed. // The routine supplied here is designed to work with the // RXxxx -> RX70 -> RX10700 -> RX2500 converters. // If you have some other hardware, you may replace or modify these // routines and move them into (w)users_hwaredriver.c // // Associate a number to each frequency band that will // need a separate case in set_hardware_rx_frequency. #define RX_AUDIO_MODE 0 #define RX2500_TO_ANT 1 #define RX10700_TO_ANT 2 #define RX70_TO_ANT 3 #define RX144_TO_ANT 4 #define RXHFA_TO_ANT_1800 5 #define RXHFA_TO_ANT_3500 6 #define RXHFA_TO_ANT_7000 7 #define RXHFA_TO_ANT_10000 8 #define RXHFA_TO_ANT_14000 9 #define MAX_RX_BANDS 10 #define TEST_GROUP_Y1 4 #define TEST_GROUP_Y2 TEST_GROUP_Y1 +10 #define TEST_GROUP_Y3 TEST_GROUP_Y2 +8 char *undefmsg={"Undef"}; char *device_name_rx10700={"RX10700"}; char *device_name_rx70={"RX70"}; char *device_name_rx144={"RX144"}; char *device_name_rxhfa={"RXHFA"}; char *device_name_rxhfa_gain={"Gain(RXHFA)"}; FQ_INFO rx_fqinfo[MAX_RX_BANDS]= {0.0 , 0.0 , 0.0 , 1, RX_AUDIO_MODE, 0.025, 1.675, 2.150,-1, RXHFA_TO_ANT_1800, 0.025, 2.500, 2.500, 1, RX2500_TO_ANT, 0.025, 3.475, 3.950,-1, RXHFA_TO_ANT_3500, 0.025, 6.975, 7.450,-1, RXHFA_TO_ANT_7000, 0.025, 9.975, 10.450,-1, RXHFA_TO_ANT_10000, 0.025, 10.675, 10.750,-1, RX10700_TO_ANT, 0.025, 13.975, 14.450,-1, RXHFA_TO_ANT_14000, 0.025, 69.975, 70.450,-1, RX70_TO_ANT, 0.025, 143.975, 145.950,-1, RX144_TO_ANT }; void hware_interface_test(void) { int i, pardat, j, k, xpos, bits[8]; int cntrldat; char inpins[5]={15,13,12,10,11}; char s[80]; clear_screen(); clear_hware_data(); pardat=0; cntrldat=0; lir_text(3,TEST_GROUP_Y1,"DATA PORT (address, output only)"); lir_text(2,TEST_GROUP_Y1+2,"Enter 0 to 7 for bit to toggle"); lir_text(5,TEST_GROUP_Y1+4,"Bit:"); lir_text(2,TEST_GROUP_Y1+5,"Status:"); lir_text(5,TEST_GROUP_Y1+6,"Pin:"); lir_text(3,TEST_GROUP_Y3,"CONTROL PORT input pins"); lir_text(5,TEST_GROUP_Y3+3,"Bit:"); lir_text(2,TEST_GROUP_Y3+4,"Status:"); lir_text(5,TEST_GROUP_Y3+5,"Pin:"); lir_text(5,TEST_GROUP_Y2,"Enter D to toggle data (pin 17)"); lir_text(5,TEST_GROUP_Y2+1,"Enter C to toggle clock (pin 1)"); goto show; loop:; lir_refresh_screen(); lir_sleep(10000); test_keyboard(); if(kill_all_flag) return; if(lir_inkey != 0) { process_current_lir_inkey(); if(kill_all_flag) return; if(lir_inkey >= '0' && lir_inkey <= '7') { k=1; j=lir_inkey-'0'; while(j != 0) { k<<=1; j--; } pardat^=k; } if(lir_inkey=='D') { cntrldat ^= HWARE_DATA; } if(lir_inkey=='C') { cntrldat ^= HWARE_CLOCK; } show:; j=pardat; k=0; while(k<8) { bits[k]=j&1; if(bits[k] >0)bits[k]=1; j>>=1; k++; } xpos=11; for(k=0; k<8; k++) { sprintf(s,"%1d",k); lir_text(xpos,TEST_GROUP_Y1+4,s); sprintf(s,"%1d",bits[k]); lir_text(xpos,TEST_GROUP_Y1+5,s); sprintf(s,"%1d",k+2); lir_text(xpos,TEST_GROUP_Y1+6,s); xpos+=3; } for(i=0; i<20;i++)s[i]=' '; s[20]=0; lir_text(xpos+5,TEST_GROUP_Y1+5,s); lir_text(xpos+5,TEST_GROUP_Y1+5,device_name[pardat]); s[1]=0; if( (cntrldat&HWARE_DATA) == 0) { s[0]='H'; } else { s[0]='L'; } lir_text(3,TEST_GROUP_Y2+3,"Data="); lir_text(8,TEST_GROUP_Y2+3,s); if( (cntrldat&HWARE_CLOCK) == 0) { s[0]='H'; } else { s[0]='L'; } lir_text(23,TEST_GROUP_Y2+3,"Clock="); lir_text(29,TEST_GROUP_Y2+3,s); lir_outb(pardat,ui.parport); lir_outb(cntrldat,parport_control); } i=lir_inb(parport_status); xpos=11; i >>= 3; j=8; for(k=0; k<5; k++) { settextcolor(7); if( (j & parport_ack) !=0)settextcolor(12); sprintf(s,"%1d",k+3); lir_text(xpos+1,TEST_GROUP_Y3+3,s); sprintf(s,"%1d",i&1); lir_text(xpos+1,TEST_GROUP_Y3+4,s); sprintf(s,"%1d",inpins[k]); lir_text(xpos,TEST_GROUP_Y3+5,s); xpos+=3; i >>= 1; j <<= 1; } settextcolor(7); if(lir_inkey != 'X')goto loop; } void set_rxhfa_data(int band) { if(device_data[RX144] != band) { device_data[RXHFA]=band; device_bits[RXHFA]=5; hware_no_of_updates++; hware_updates[hware_no_of_updates]=RXHFA; } } int set_rx144_data(int stepno) { int i; i=8; while(stepno >= 20) { i>>=1; stepno-=20; } if(device_data[RX144] != i) { device_data[RX144]=i; device_bits[RX144]=4; hware_no_of_updates++; hware_updates[hware_no_of_updates]=RX144; } return stepno; } void set_rx10700_data(int stepno) { int i; i=8; while(stepno != 0) { i>>=1; stepno--; } if(device_data[RX10700] != i) { device_data[RX10700]=i; device_bits[RX10700]=4; hware_no_of_updates++; hware_updates[hware_no_of_updates]=RX10700; } } int set_rx70_data(int stepno) { int i; i=16; while(stepno >= 4) { i>>=1; stepno-=4; } if(device_data[RX70] != i) { device_data[RX70]=i; device_bits[RX70]=5; hware_no_of_updates++; hware_updates[hware_no_of_updates]=RX70; } return stepno; } void set_hardware_rx_gain(void) { // bit0 to bit 2 for amplifier/bypass/-10 dB. // bit0-bit2 = 6 => -10dB // bit0-bit2 = 3 => 0dB // bit0-bit2 = 5 => +10dB // // bit3 for 5 dB attenuator. // bit3 = 0 => -5dB // bit3 = 1 => 0dB int gaindat[6]={6,14,3,11,5,13}; int i; if(ui.rx_addev_no == SDR14_DEVICE_CODE) { fg.gain_increment=10; fg.gain/=10; fg.gain*=10; if(fg.gain > 0)fg.gain=0; if(fg.gain<-30)fg.gain=-30; if(rx_hware_init_flag==0)sdr14_att_counter++; return; } if(ui.rx_addev_no == SDRIQ_DEVICE_CODE) { fg.gain_increment=1; if(fg.gain > 0)fg.gain=0; if(fg.gain<-36)fg.gain=-36; if(rx_hware_init_flag==0)sdr14_att_counter++; return; } if( ui.parport == 0 || !allow_parport)return; if(hware_no_of_updates > 127)lirerr(213767); switch (rx_fqinfo[fg_new_band].label) { case RXHFA_TO_ANT_1800: case RXHFA_TO_ANT_3500: case RXHFA_TO_ANT_7000: case RXHFA_TO_ANT_10000: case RXHFA_TO_ANT_14000: fg.gain_increment=5; fg.gain/=5; fg.gain*=5; if(fg.gain < -15)fg.gain=-15; if(fg.gain > 10)fg.gain=10; i=fg.gain/5+3; if(device_data[RXHFA_GAIN] != gaindat[i]) { device_data[RXHFA_GAIN]=gaindat[i]; device_bits[RXHFA_GAIN]=4; hware_no_of_updates++; hware_updates[hware_no_of_updates]=RXHFA_GAIN; hware_flag=1; hware_time=current_time(); } break; default: break; } } void set_hardware_rx_frequency(void) { float t1; int i, stepno; int old_updates; if(ui.rx_addev_no == SDR14_DEVICE_CODE || ui.rx_addev_no == SDRIQ_DEVICE_CODE ) { t1=fg.passband_center; fg.passband_direction=1; if(fg.passband_center > SDR14_SAMPLING_CLOCK) { i=fg.passband_center/SDR14_SAMPLING_CLOCK; t1=fg.passband_center-i*SDR14_SAMPLING_CLOCK; } if(t1 > 0.5*SDR14_SAMPLING_CLOCK) { t1=SDR14_SAMPLING_CLOCK-t1; fg.passband_direction=-1; } sdr14_freq=t1*1000000+0.5; fft1_direction=fg.passband_direction; fg.passband_increment=.025; if(rx_hware_init_flag==0)sdr14_nco_counter++; return; } if( ui.parport == 0 || !allow_parport)return; if(hware_no_of_updates > 127)lirerr(213768); fg_new_band=0; while(fg_new_band < MAX_RX_BANDS-1 && fg.passband_center > rx_fqinfo[fg_new_band].highest)fg_new_band++; if(fg.passband_center < rx_fqinfo[fg_new_band].lowest && fg_new_band > 0) { t1=0.5*(rx_fqinfo[fg_new_band].lowest+rx_fqinfo[fg_new_band-1].highest); if(fg.passband_center < t1)fg_new_band--; } if(fg_old_band != fg_new_band)set_hardware_rx_gain(); fg_old_band=fg_new_band; t1=(fg.passband_center-rx_fqinfo[fg_new_band].lowest)/ rx_fqinfo[fg_new_band].increment; stepno=t1+0.5; if(stepno < 0)stepno=0; set_fq:; fg.passband_center=rx_fqinfo[fg_new_band].lowest+ stepno*rx_fqinfo[fg_new_band].increment; if(fg.passband_center > rx_fqinfo[fg_new_band].highest+0.0000001) { stepno--; goto set_fq; } fg.passband_increment = rx_fqinfo[fg_new_band].increment; fg.passband_direction = rx_fqinfo[fg_new_band].direction; fft1_direction=fg.passband_direction; // Send a message to the screen thread to redraw the frequency scale // on the main spectrum. sc[SC_WG_FQ_SCALE]++; // Set up data to switch relays to connect units properly. // and to select the correct LO frequency for all units in use. old_updates=hware_no_of_updates; switch (rx_fqinfo[fg_new_band].label) { case RX_AUDIO_MODE: // Send nothing to the hardware, just set frequency // and direction to zero so frequency scale in waterfall and // other graphs gives audio frequency. break; case RX2500_TO_ANT: // Route the signal source to the RX2500 input. break; case RX10700_TO_ANT: // Route RX10700 output to the RX2500 input. // Route the signal source to the RX10700 input. goto set_10700; case RX70_TO_ANT: // Route RX70 output to the RX10700 input. // Route RX10700 output to the RX2500 input. // Route the signal source to the RX10700 input. goto set_70; case RXHFA_TO_ANT_1800: // Route RXHFA output to the RX70 input. // Route RX70 output to the RX10700 input. // Route RX10700 output to the RX2500 input. // Route the signal source to the RXHFA input. set_rxhfa_data(16); goto set_70; case RXHFA_TO_ANT_3500: // Route RXHFA output to the RX70 input. // Route RX70 output to the RX10700 input. // Route RX10700 output to the RX2500 input. // Route the signal source to the RXHFA input. set_rxhfa_data(8); goto set_70; case RXHFA_TO_ANT_7000: // Route RXHFA output to the RX70 input. // Route RX70 output to the RX10700 input. // Route RX10700 output to the RX2500 input. // Route the signal source to the RXHFA input. set_rxhfa_data(4); goto set_70; case RXHFA_TO_ANT_10000: // Route RXHFA output to the RX70 input. // Route RX70 output to the RX10700 input. // Route RX10700 output to the RX2500 input. // Route the signal source to the RXHFA input. set_rxhfa_data(2); goto set_70; case RXHFA_TO_ANT_14000: // Route RXHFA output to the RX70 input. // Route RX70 output to the RX10700 input. // Route RX10700 output to the RX2500 input. // Route the signal source to the RXHFA input. set_rxhfa_data(1); goto set_70; case RX144_TO_ANT: // Route RX144 output to the RX70 input. // Route RX70 output to the RX10700 input. // Route RX10700 output to the RX2500 input. // Route the signal source to the RX10700 input. stepno=set_rx144_data(stepno); set_70:; stepno=set_rx70_data(stepno); set_10700:; set_rx10700_data(stepno); break; } if(hware_no_of_updates != old_updates) { hware_flag=1; hware_time=current_time(); } else { rx_hware_init_flag=0; } } void clear_hware_data(void) { int i; // Set -1 in device_data. // A data word is max 31 bit, the sign bit is a flag // saying the data is not valid. for(i=0; i<256; i++) { device_data[i]=-1; device_name[i]=undefmsg; } device_name[RX10700]=device_name_rx10700; device_name[RX70]=device_name_rx70; device_name[RX144]=device_name_rx144; device_name[RXHFA]=device_name_rxhfa; device_name[RXHFA_GAIN]=device_name_rxhfa_gain; device_name[TX10700]=device_name_tx10700; device_name[TX70]=device_name_tx70; device_name[TXHFA]=device_name_txhfa144; rx_hware_init_flag=1; hware_no_of_updates=-1; hware_flag=0; hware_time=current_time(); fg_old_band=-1; } void control_hware(void) { int err; unsigned char outdat; char s[80]; switch(hware_flag) { case 1: if(hware_no_of_updates <0) { lirerr(988342); return; } hware_device_no=hware_updates[hware_no_of_updates]; hware_error_flag=0; hware_data=device_data[hware_device_no]; hware_bits=device_bits[hware_device_no]; // A new unit is selected. // Write the number of this unit to the data port outdat=hware_device_no; lir_outb(outdat,ui.parport); hware_flag=2; // Set clock low and make data the first bit of current output. lir_mutex_lock(); if( (hware_data & 1) == 0) { hware_outdat=HWARE_DATA+HWARE_CLOCK; } else { hware_outdat=HWARE_CLOCK; } lir_outb(hware_outdat,parport_control); lir_mutex_unlock(); break; case 2: // Set clock high to clock in new data bit. lir_mutex_lock(); hware_outdat^=HWARE_CLOCK; lir_outb(hware_outdat,parport_control); lir_mutex_unlock(); hware_flag=3; hware_retry=0; break; case 3: // Read status to see if we really got the data bit into the unit. outdat=lir_inb(parport_status)&parport_ack; outdat^=parport_ack_sign; err=0; if(outdat == 0) { if( (hware_outdat&HWARE_DATA) != 0) { err=1; } } else { if( (hware_outdat&HWARE_DATA) == 0) { err=1; } } hware_retry++; if(err==1) { if(hware_retry<4)return; hware_error_flag=1; } hware_bits--; if(hware_bits == 0) { // No more. Deselect unit. lir_outb(0,ui.parport); hware_flag=4; return; } else { // Set clock low and make data the next bit of current output. hware_data=hware_data>>1; lir_mutex_lock(); if( (hware_data & 1) == 0) { hware_outdat=HWARE_DATA+HWARE_CLOCK; } else { hware_outdat=HWARE_CLOCK; } lir_outb(hware_outdat,parport_control); lir_mutex_unlock(); hware_flag=2; } break; case 4: // Select unit. This time we actually clock the new data // from the shift register into the latch. outdat=hware_device_no; lir_outb(outdat,ui.parport); hware_flag=5; return; case 5: lir_outb(0,ui.parport); hware_no_of_updates--; if(hware_no_of_updates >= 0) { hware_flag=1; } else { hware_flag=0; rx_hware_init_flag=0; } lir_mutex_lock(); hware_outdat=HWARE_CLOCK; lir_outb(hware_outdat,parport_control); lir_mutex_unlock(); if(hware_error_flag != 0) { sprintf(s,"ERROR: %s",device_name[hware_device_no]); wg_error(s,5); } break; } } // ******************************************************** // End WSE routines // ********************************************************