mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-30 12:30:20 -04:00 
			
		
		
		
	Deep redesign: Better support for FCD dongles #1
This commit is contained in:
		
							parent
							
								
									3a6f2b5481
								
							
						
					
					
						commit
						a909c4c40c
					
				| @ -329,3 +329,4 @@ qt5_use_modules(sdrangel Widgets Multimedia) | ||||
| ############################################################################## | ||||
| 
 | ||||
| add_subdirectory(plugins) | ||||
| add_subdirectory(fcdhid) | ||||
|  | ||||
							
								
								
									
										11
									
								
								Readme.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								Readme.md
									
									
									
									
									
								
							| @ -18,11 +18,16 @@ These plugins come from the parent code base and are still present in the source | ||||
| - Channels: | ||||
|   - tetra  | ||||
| - Sample sources: | ||||
|   - fcd | ||||
|   - gnuradio | ||||
|   - osmosdr | ||||
|   - v4l-msi | ||||
|   - v4l-rtl | ||||
|    | ||||
| <h3>Funcube Dongle (fcd)</h3> | ||||
| 
 | ||||
| This is the old driver. | ||||
| 
 | ||||
| <h3>Gnuradio</h3> | ||||
| 
 | ||||
| The Gnuradio plugin source needs extra packages, including `liblog4cpp-dev libboost-system-dev gnuradio-dev libosmosdr-dev` | ||||
| @ -51,11 +56,11 @@ If you use your own location for libbladeRF install directory you need to specif | ||||
| 
 | ||||
| `-DLIBBLADERF_LIBRARIES=/opt/install/libbladeRF/lib/libbladeRF.so -DLIBBLADERF_INCLUDE_DIR=/opt/install/libbladeRF/include` | ||||
| 
 | ||||
| <h2>Funcube Dongle</h2> | ||||
| <h2>FunCube Dongle</h2> | ||||
| 
 | ||||
| Only the original Funcube Dongle Pro is supported. Funcube Dongle Pro+ will come later. | ||||
| At the moment only the Pro+ is supported with the plugin in fcdpro. This is a work in progress. Support of features is still limited (no IF gain, no filter settings). | ||||
| 
 | ||||
| The interface is built in the software and do not require additional libraries other than USB support with libusb.  | ||||
| The control interface is based on qthid and has been built in the software in the fcdhid library. You don't need anything else than libusb support. | ||||
| 
 | ||||
| <h2>RTL-SDR</h2> | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										30
									
								
								fcdhid/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								fcdhid/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | ||||
| project(fcdhid) | ||||
| 
 | ||||
| set(fcdhid_SOURCES | ||||
| 	hid-libusb.c | ||||
| 	fcdhid.c | ||||
| ) | ||||
| 
 | ||||
| set(fcdhid_HEADERS | ||||
| 	fcdhid.h | ||||
| 	hid-libusb.h | ||||
| 	hidapi.h | ||||
| ) | ||||
| 
 | ||||
| include_directories( | ||||
| 	. | ||||
| 	${CMAKE_CURRENT_BINARY_DIR} | ||||
| 	${CMAKE_SOURCE_DIR}/include | ||||
| 	${CMAKE_SOURCE_DIR}/include-gpl | ||||
| ) | ||||
| 
 | ||||
| #add_definitions(-DQT_PLUGIN) | ||||
| add_definitions(-DQT_SHARED) | ||||
| 
 | ||||
| add_library(fcdhid SHARED | ||||
| 	${fcdhid_SOURCES} | ||||
| ) | ||||
| 
 | ||||
| target_link_libraries(fcdhid | ||||
| 	${LIBUSB_LIBRARIES} | ||||
| ) | ||||
							
								
								
									
										927
									
								
								fcdhid/fcdhid.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										927
									
								
								fcdhid/fcdhid.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,927 @@ | ||||
| /***************************************************************************
 | ||||
|  *  This file is part of Qthid. | ||||
|  *  | ||||
|  *  Copyright (C) 2010  Howard Long, G6LVB | ||||
|  *  CopyRight (C) 2011  Alexandru Csete, OZ9AEC | ||||
|  *                      Mario Lorenz, DL5MLO | ||||
|  *  | ||||
|  *  Qthid is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  Qthid is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with Qthid.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  ***************************************************************************/ | ||||
| 
 | ||||
| #include "fcdhid.h" | ||||
| 
 | ||||
| /** \brief Open FCD device.
 | ||||
|  * \return Pointer to the FCD HID device or NULL if none found | ||||
|  * | ||||
|  * This function looks for FCD devices connected to the computer and | ||||
|  * opens the first one found. | ||||
|  */ | ||||
| hid_device *fcdOpen(uint16_t usVID, uint16_t usPID, int whichdongle) | ||||
| { | ||||
|     struct hid_device_info *phdi=NULL; | ||||
|     hid_device *phd=NULL; | ||||
|     char *pszPath=NULL; | ||||
| 
 | ||||
|     phdi = hid_enumerate(usVID, usPID); | ||||
| 
 | ||||
|     int which = whichdongle; | ||||
| 
 | ||||
|     while (phdi && which) | ||||
|     { | ||||
|         phdi=phdi->next;     | ||||
|         which--; | ||||
|     } | ||||
| 
 | ||||
|     if (phdi==NULL) | ||||
|     { | ||||
|         return NULL; // No FCD device found
 | ||||
|     } | ||||
| 
 | ||||
|     pszPath=strdup(phdi->path); | ||||
| 
 | ||||
|     if (pszPath==NULL) | ||||
|     { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     hid_free_enumeration(phdi); | ||||
|     phdi=NULL; | ||||
| 
 | ||||
|     if ((phd=hid_open_path(pszPath)) == NULL) | ||||
|     { | ||||
|         free(pszPath); | ||||
|         pszPath=NULL; | ||||
| 
 | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     free(pszPath); | ||||
|     pszPath=NULL; | ||||
| 
 | ||||
|     return phd; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** \brief Close FCD HID device. */ | ||||
| void fcdClose(hid_device *phd) | ||||
| { | ||||
|     hid_close(phd); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** \brief Get FCD mode.
 | ||||
|  * \return The current FCD mode. | ||||
|  * \sa FCD_MODE_ENUM | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdGetMode(hid_device *phd) | ||||
| { | ||||
|     //hid_device *phd=NULL;
 | ||||
|     unsigned char aucBufIn[65]; | ||||
|     unsigned char aucBufOut[65]; | ||||
|     FCD_MODE_ENUM fcd_mode = FCD_MODE_NONE; | ||||
| 
 | ||||
|     /*
 | ||||
|     phd = fcdOpen(); | ||||
| 
 | ||||
|     if (phd == NULL) | ||||
|     { | ||||
|         return FCD_MODE_DEAD; | ||||
|     }*/ | ||||
| 
 | ||||
|     /* Send a BL Query Command */ | ||||
|     aucBufOut[0] = 0; // Report ID, ignored
 | ||||
|     aucBufOut[1] = FCD_CMD_BL_QUERY; | ||||
|     hid_write(phd, aucBufOut, 65); | ||||
|     memset(aucBufIn, 0xCC, 65); // Clear out the response buffer
 | ||||
|     hid_read(phd, aucBufIn, 65); | ||||
| 
 | ||||
|     /*
 | ||||
|     fcdClose(phd); | ||||
|     phd = NULL;*/ | ||||
| 
 | ||||
|     /* first check status bytes then check which mode */ | ||||
|     if (aucBufIn[0]==FCD_CMD_BL_QUERY && aucBufIn[1]==1) { | ||||
| 
 | ||||
|         /* In bootloader mode we have the string "FCDBL" starting at acBufIn[2] **/ | ||||
|         if (strncmp((char *)(aucBufIn+2), "FCDBL", 5) == 0) { | ||||
|             fcd_mode = FCD_MODE_BL; | ||||
|         } | ||||
|         /* In application mode we have "FCDAPP_18.06" where the number is the FW version */ | ||||
|         else if (strncmp((char *)(aucBufIn+2), "FCDAPP", 6) == 0) { | ||||
|             fcd_mode = FCD_MODE_APP; | ||||
|         } | ||||
|         /* either no FCD or firmware less than 18f */ | ||||
|         else { | ||||
|             fcd_mode = FCD_MODE_NONE; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return fcd_mode; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** \brief Get FCD firmware version as string.
 | ||||
|  * \param str The returned vesion number as a 0 terminated string (must be pre-allocated) | ||||
|  * \return The current FCD mode. | ||||
|  * \sa FCD_MODE_ENUM | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdGetFwVerStr(hid_device *phd, char *str) | ||||
| { | ||||
|     //hid_device *phd=NULL;
 | ||||
|     unsigned char aucBufIn[65]; | ||||
|     unsigned char aucBufOut[65]; | ||||
|     FCD_MODE_ENUM fcd_mode = FCD_MODE_NONE; | ||||
| 
 | ||||
|     /*
 | ||||
|     phd = fcdOpen(); | ||||
| 
 | ||||
|     if (phd == NULL) | ||||
|     { | ||||
|         return FCD_MODE_NONE; | ||||
|     }*/ | ||||
| 
 | ||||
|     /* Send a BL Query Command */ | ||||
|     aucBufOut[0] = 0; // Report ID, ignored
 | ||||
|     aucBufOut[1] = FCD_CMD_BL_QUERY; | ||||
|     hid_write(phd, aucBufOut, 65); | ||||
|     memset(aucBufIn, 0xCC, 65); // Clear out the response buffer
 | ||||
|     hid_read(phd, aucBufIn, 65); | ||||
| 
 | ||||
|     /*
 | ||||
|     fcdClose(phd); | ||||
|     phd = NULL;*/ | ||||
| 
 | ||||
|     /* first check status bytes then check which mode */ | ||||
|     if (aucBufIn[0]==FCD_CMD_BL_QUERY && aucBufIn[1]==1) { | ||||
| 
 | ||||
|         /* In bootloader mode we have the string "FCDBL" starting at acBufIn[2] **/ | ||||
|         if (strncmp((char *)(aucBufIn+2), "FCDBL", 5) == 0) { | ||||
|             fcd_mode = FCD_MODE_BL; | ||||
|         } | ||||
|         /* In application mode we have "FCDAPP_18.06" where the number is the FW version */ | ||||
|         else if (strncmp((char *)(aucBufIn+2), "FCDAPP", 6) == 0) { | ||||
|             strncpy(str, (char *)(aucBufIn+9), 5); | ||||
|             str[5] = 0; | ||||
|             fcd_mode = FCD_MODE_APP; | ||||
|         } | ||||
|         /* either no FCD or firmware less than 18f */ | ||||
|         else { | ||||
|             fcd_mode = FCD_MODE_NONE; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return fcd_mode; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** \brief Get hardware and firmware dependent FCD capabilities.
 | ||||
|  * \param fcd_caps Pointer to an FCD_CAPS_STRUCT | ||||
|  * \return The current FCD mode. | ||||
|  * | ||||
|  * This function queries the FCD and extracts the hardware and firmware dependent | ||||
|  * capabilities. Currently these capabilities are: | ||||
|  *  - Bias T (available since S/N TBD) | ||||
|  *  - Cellular block (the certified version of the FCD) | ||||
|  * When the FCD is in application mode, the string returned by the query command is | ||||
|  * (starting at index 2): | ||||
|  *    FCDAPP 18.08 Brd 1.0 No blk | ||||
|  * 1.0 means no bias tee, 1.1 means there is a bias tee | ||||
|  * 'No blk' means it is not cellular blocked. | ||||
|  * | ||||
|  * Ref: http://uk.groups.yahoo.com/group/FCDevelopment/message/303
 | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdGetCaps(hid_device *phd, FCD_CAPS_STRUCT *fcd_caps) | ||||
| { | ||||
|     //hid_device *phd=NULL;
 | ||||
|     unsigned char aucBufIn[65]; | ||||
|     unsigned char aucBufOut[65]; | ||||
|     FCD_MODE_ENUM fcd_mode = FCD_MODE_NONE; | ||||
| 
 | ||||
|     /* clear output buffer */ | ||||
|     fcd_caps->hasBiasT = 0; | ||||
|     fcd_caps->hasCellBlock = 0; | ||||
| 
 | ||||
|     /*
 | ||||
|     phd = fcdOpen(); | ||||
| 
 | ||||
|     if (phd == NULL) | ||||
|     { | ||||
|         return FCD_MODE_NONE; | ||||
|     }*/ | ||||
| 
 | ||||
|     /* Send a BL Query Command */ | ||||
|     aucBufOut[0] = 0; // Report ID, ignored
 | ||||
|     aucBufOut[1] = FCD_CMD_BL_QUERY; | ||||
|     hid_write(phd, aucBufOut, 65); | ||||
|     memset(aucBufIn, 0xCC, 65); // Clear out the response buffer
 | ||||
|     hid_read(phd, aucBufIn, 65); | ||||
| 
 | ||||
|     /*
 | ||||
|     fcdClose(phd); | ||||
|     phd = NULL;*/ | ||||
| 
 | ||||
|     /* first check status bytes then check which mode */ | ||||
|     if (aucBufIn[0]==FCD_CMD_BL_QUERY && aucBufIn[1]==1) { | ||||
| 
 | ||||
|         /* In bootloader mode we have the string "FCDBL" starting at acBufIn[2] **/ | ||||
|         if (strncmp((char *)(aucBufIn+2), "FCDBL", 5) == 0) { | ||||
|             fcd_mode = FCD_MODE_BL; | ||||
|         } | ||||
|         /* In application mode we have "FCDAPP 18.08 Brd 1.0 No blk" (see API doc) */ | ||||
|         else if (strncmp((char *)(aucBufIn+2), "FCDAPP", 6) == 0) { | ||||
| 
 | ||||
|             /* Bias T */ | ||||
|             fcd_caps->hasBiasT = (aucBufIn[21] == '1') ? 1 : 0; | ||||
| 
 | ||||
|             /* cellular block */ | ||||
|             if (strncmp((char *)(aucBufIn+23), "No blk", 6) == 0) { | ||||
|                 fcd_caps->hasCellBlock = 0; | ||||
|             } else { | ||||
|                 fcd_caps->hasCellBlock = 1; | ||||
|             } | ||||
| 
 | ||||
|             fcd_mode = FCD_MODE_APP; | ||||
|         } | ||||
|         /* either no FCD or firmware less than 18f */ | ||||
|         else { | ||||
|             fcd_mode = FCD_MODE_NONE; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return fcd_mode; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** \brief Get hardware and firmware dependent FCD capabilities as string.
 | ||||
|  * \param caps_str Pointer to a pre-allocated string buffer where the info will be copied. | ||||
|  * \return The current FCD mode. | ||||
|  * | ||||
|  * This function queries the FCD and copies the returned string into the caps_str parameter. | ||||
|  * THe return buffer must be at least 28 characters. | ||||
|  * When the FCD is in application mode, the string returned by the query command is | ||||
|  * (starting at index 2): | ||||
|  *    FCDAPP 18.08 Brd 1.0 No blk | ||||
|  * 1.0 means no bias tee, 1.1 means there is a bias tee | ||||
|  * 'No blk' means it is not cellular blocked. | ||||
|  * | ||||
|  * Ref: http://uk.groups.yahoo.com/group/FCDevelopment/message/303
 | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdGetCapsStr(hid_device *phd, char *caps_str) | ||||
| { | ||||
|     //hid_device *phd=NULL;
 | ||||
|     unsigned char aucBufIn[65]; | ||||
|     unsigned char aucBufOut[65]; | ||||
|     FCD_MODE_ENUM fcd_mode = FCD_MODE_NONE; | ||||
| 
 | ||||
|     /*
 | ||||
|     phd = fcdOpen(); | ||||
| 
 | ||||
|     if (phd == NULL) | ||||
|     { | ||||
|         return FCD_MODE_NONE; | ||||
|     }*/ | ||||
| 
 | ||||
|     /* Send a BL Query Command */ | ||||
|     aucBufOut[0] = 0; // Report ID, ignored
 | ||||
|     aucBufOut[1] = FCD_CMD_BL_QUERY; | ||||
|     hid_write(phd, aucBufOut, 65); | ||||
|     memset(aucBufIn, 0xCC, 65); // Clear out the response buffer
 | ||||
|     hid_read(phd, aucBufIn, 65); | ||||
| 
 | ||||
|     /*
 | ||||
|     fcdClose(phd); | ||||
|     phd = NULL;*/ | ||||
| 
 | ||||
|     /* first check status bytes then check which mode */ | ||||
|     if (aucBufIn[0]==FCD_CMD_BL_QUERY && aucBufIn[1]==1) { | ||||
| 
 | ||||
|         /* In bootloader mode we have the string "FCDBL" starting at acBufIn[2] **/ | ||||
|         if (strncmp((char *)(aucBufIn+2), "FCDBL", 5) == 0) { | ||||
|             fcd_mode = FCD_MODE_BL; | ||||
|         } | ||||
|         /* In application mode we have "FCDAPP 18.08 Brd 1.0 No blk" (see API doc) */ | ||||
|         else if (strncmp((char *)(aucBufIn+2), "FCDAPP", 6) == 0) { | ||||
| 
 | ||||
|             strncpy(caps_str, (char *)(aucBufIn+2), 27); | ||||
|             caps_str[27] = 0; | ||||
| 
 | ||||
|             fcd_mode = FCD_MODE_APP; | ||||
|         } | ||||
|         /* either no FCD or firmware less than 18f */ | ||||
|         else { | ||||
|             fcd_mode = FCD_MODE_NONE; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return fcd_mode; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /** \brief Reset FCD to bootloader mode.
 | ||||
|  * \return FCD_MODE_NONE | ||||
|  * | ||||
|  * This function is used to switch the FCD into bootloader mode in which | ||||
|  * various firmware operations can be performed. | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdAppReset(hid_device *phd) | ||||
| { | ||||
|     //hid_device *phd=NULL;
 | ||||
|     //unsigned char aucBufIn[65];
 | ||||
|     unsigned char aucBufOut[65]; | ||||
| 
 | ||||
|     /*
 | ||||
|     phd = fcdOpen(); | ||||
| 
 | ||||
|     if (phd == NULL) | ||||
|     { | ||||
|         return FCD_MODE_NONE; | ||||
|     }*/ | ||||
| 
 | ||||
|     // Send an App reset command
 | ||||
|     aucBufOut[0] = 0; // Report ID, ignored
 | ||||
|     aucBufOut[1] = FCD_CMD_APP_RESET; | ||||
|     hid_write(phd, aucBufOut, 65); | ||||
| 
 | ||||
|     /** FIXME: hid_read() will occasionally hang due to a pthread_cond_wait() never returning.
 | ||||
|       It seems that the read_callback() in hid-libusb.c will never receive any | ||||
|       data during the reconfiguration. Since the same logic works in the native | ||||
|       windows application, it could be a libusb thing. Anyhow, since the value | ||||
|       returned by this function is not used, we may as well just skip the hid_read() | ||||
|       and return FME_NONE. | ||||
|       Correct switch from APP to BL mode can be observed in /var/log/messages (linux) | ||||
|       (when in bootloader mode the device version includes 'BL') | ||||
|       */ | ||||
|     /*
 | ||||
|        memset(aucBufIn,0xCC,65); // Clear out the response buffer
 | ||||
|        hid_read(phd,aucBufIn,65); | ||||
| 
 | ||||
|        if (aucBufIn[0]==FCDCMDAPPRESET && aucBufIn[1]==1) | ||||
|        { | ||||
|        FCDClose(phd); | ||||
|        phd=NULL; | ||||
|        return FME_APP; | ||||
|        } | ||||
|        FCDClose(phd); | ||||
|        phd=NULL; | ||||
|        return FME_BL; | ||||
|        */ | ||||
| 
 | ||||
|     /*
 | ||||
|     fcdClose(phd); | ||||
|     phd = NULL;*/ | ||||
| 
 | ||||
|     return FCD_MODE_NONE; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** \brief Set FCD frequency with kHz resolution.
 | ||||
|  * \param nFreq The new frequency in kHz. | ||||
|  * \return The FCD mode. | ||||
|  * | ||||
|  * This function sets the frequency of the FCD with 1 kHz resolution. The parameter | ||||
|  * nFreq must already contain any necessary frequency correction. | ||||
|  * | ||||
|  * \sa fcdAppSetFreq | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdAppSetFreqkHz(hid_device *phd, int nFreq) | ||||
| { | ||||
|     //hid_device *phd=NULL;
 | ||||
|     unsigned char aucBufIn[65]; | ||||
|     unsigned char aucBufOut[65]; | ||||
| 
 | ||||
|     /*
 | ||||
|     phd = fcdOpen(); | ||||
| 
 | ||||
|     if (phd == NULL) | ||||
|     { | ||||
|         return FCD_MODE_NONE; | ||||
|     }*/ | ||||
| 
 | ||||
|     // Send an App reset command
 | ||||
|     aucBufOut[0] = 0; // Report ID, ignored
 | ||||
|     aucBufOut[1] = FCD_CMD_APP_SET_FREQ_KHZ; | ||||
|     aucBufOut[2] = (unsigned char)nFreq; | ||||
|     aucBufOut[3] = (unsigned char)(nFreq>>8); | ||||
|     aucBufOut[4] = (unsigned char)(nFreq>>16); | ||||
|     hid_write(phd, aucBufOut, 65); | ||||
|     memset(aucBufIn, 0xCC, 65); // Clear out the response buffer
 | ||||
|     hid_read(phd, aucBufIn, 65); | ||||
| 
 | ||||
|     if (aucBufIn[0]==FCD_CMD_APP_SET_FREQ_KHZ && aucBufIn[1]==1) | ||||
|     { | ||||
|     	/*
 | ||||
|         fcdClose(phd); | ||||
|         phd = NULL;*/ | ||||
| 
 | ||||
|         return FCD_MODE_APP; | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|     fcdClose(phd); | ||||
|     phd = NULL;*/ | ||||
| 
 | ||||
|     return FCD_MODE_BL; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** \brief Set FCD frequency with Hz resolution.
 | ||||
|  * \param nFreq The new frequency in Hz. | ||||
|  * \return The FCD mode. | ||||
|  * | ||||
|  * This function sets the frequency of the FCD with 1 Hz resolution. The parameter | ||||
|  * nFreq must already contain any necessary frequency correction. | ||||
|  * | ||||
|  * \sa fcdAppSetFreq | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdAppSetFreq(hid_device *phd, int nFreq) | ||||
| { | ||||
|     //hid_device *phd=NULL;
 | ||||
|     unsigned char aucBufIn[65]; | ||||
|     unsigned char aucBufOut[65]; | ||||
| 
 | ||||
|     /*
 | ||||
|     phd = fcdOpen(); | ||||
| 
 | ||||
|     if (phd == NULL) | ||||
|     { | ||||
|         return FCD_MODE_NONE; | ||||
|     }*/ | ||||
| 
 | ||||
|     // Send an App reset command
 | ||||
|     aucBufOut[0] = 0; // Report ID, ignored
 | ||||
|     aucBufOut[1] = FCD_CMD_APP_SET_FREQ_HZ; | ||||
|     aucBufOut[2] = (unsigned char)nFreq; | ||||
|     aucBufOut[3] = (unsigned char)(nFreq>>8); | ||||
|     aucBufOut[4] = (unsigned char)(nFreq>>16); | ||||
|     aucBufOut[5] = (unsigned char)(nFreq>>24); | ||||
|     hid_write(phd, aucBufOut, 65); | ||||
|     memset(aucBufIn, 0xCC, 65); // Clear out the response buffer
 | ||||
|     hid_read(phd, aucBufIn, 65); | ||||
| 
 | ||||
|     if (aucBufIn[0]==FCD_CMD_APP_SET_FREQ_HZ && aucBufIn[1]==1) | ||||
|     { | ||||
|     	/*
 | ||||
|         fcdClose(phd); | ||||
|         phd = NULL;*/ | ||||
| 
 | ||||
|         return FCD_MODE_APP; | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|     fcdClose(phd); | ||||
|     phd = NULL;*/ | ||||
| 
 | ||||
|     return FCD_MODE_BL; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /** \brief Reset FCD to application mode.
 | ||||
|  * \return FCD_MODE_NONE | ||||
|  * | ||||
|  * This function is used to switch the FCD from bootloader mode | ||||
|  * into application mode. | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdBlReset(hid_device *phd) | ||||
| { | ||||
|     //hid_device *phd=NULL;
 | ||||
|     //    unsigned char aucBufIn[65];
 | ||||
|     unsigned char aucBufOut[65]; | ||||
| 
 | ||||
|     /*
 | ||||
|     phd = fcdOpen(); | ||||
| 
 | ||||
|     if (phd == NULL) | ||||
|     { | ||||
|         return FCD_MODE_NONE; | ||||
|     }*/ | ||||
| 
 | ||||
|     // Send an BL reset command
 | ||||
|     aucBufOut[0] = 0; // Report ID, ignored
 | ||||
|     aucBufOut[1] = FCD_CMD_BL_RESET; | ||||
|     hid_write(phd, aucBufOut, 65); | ||||
| 
 | ||||
|     /** FIXME: hid_read() will hang due to a pthread_cond_wait() never returning.
 | ||||
|       It seems that the read_callback() in hid-libusb.c will never receive any | ||||
|       data during the reconfiguration. Since the same logic works in the native | ||||
|       windows application, it could be a libusb thing. Anyhow, since the value | ||||
|       returned by this function is not used, we may as well jsut skip the hid_read() | ||||
|       and return FME_NONE. | ||||
|       Correct switch from BL to APP mode can be observed in /var/log/messages (linux) | ||||
|       (when in bootloader mode the device version includes 'BL') | ||||
|       */ | ||||
|     /*
 | ||||
|        memset(aucBufIn,0xCC,65); // Clear out the response buffer
 | ||||
|        hid_read(phd,aucBufIn,65); | ||||
| 
 | ||||
|        if (aucBufIn[0]==FCDCMDBLRESET && aucBufIn[1]==1) | ||||
|        { | ||||
|        FCDClose(phd); | ||||
|        phd=NULL; | ||||
|        return FME_BL; | ||||
|        } | ||||
|        FCDClose(phd); | ||||
|        phd=NULL; | ||||
|        return FME_APP; | ||||
|        */ | ||||
| 
 | ||||
|     /*
 | ||||
|     fcdClose(phd); | ||||
|     phd = NULL;*/ | ||||
| 
 | ||||
|     return FCD_MODE_NONE; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** \brief Erase firmware from FCD.
 | ||||
|  * \return The FCD mode | ||||
|  * | ||||
|  * This function deletes the firmware from the FCD. This is required | ||||
|  * before writing new firmware into the FCD. | ||||
|  * | ||||
|  * \sa fcdBlWriteFirmware | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdBlErase(hid_device *phd) | ||||
| { | ||||
|     //hid_device *phd=NULL;
 | ||||
|     unsigned char aucBufIn[65]; | ||||
|     unsigned char aucBufOut[65]; | ||||
| 
 | ||||
|     /*
 | ||||
|     phd = fcdOpen(); | ||||
| 
 | ||||
|     if (phd == NULL) | ||||
|     { | ||||
|         return FCD_MODE_NONE; | ||||
|     }*/ | ||||
| 
 | ||||
|     // Send an App reset command
 | ||||
|     aucBufOut[0] = 0; // Report ID, ignored
 | ||||
|     aucBufOut[1] = FCD_CMD_BL_ERASE; | ||||
|     hid_write(phd, aucBufOut, 65); | ||||
|     memset(aucBufIn, 0xCC, 65); // Clear out the response buffer
 | ||||
|     hid_read(phd, aucBufIn, 65); | ||||
| 
 | ||||
|     if (aucBufIn[0]==FCD_CMD_BL_ERASE && aucBufIn[1]==1) | ||||
|     { | ||||
|     	/*
 | ||||
|         fcdClose(phd); | ||||
|         phd = NULL;*/ | ||||
| 
 | ||||
|         return FCD_MODE_BL; | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|     fcdClose(phd); | ||||
|     phd = NULL;*/ | ||||
| 
 | ||||
|     return FCD_MODE_APP; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** \brief Write new firmware into the FCD.
 | ||||
|  * \param pc Pointer to the new firmware data | ||||
|  * \param n64size The number of bytes in the data | ||||
|  * \return The FCD mode | ||||
|  * | ||||
|  * This function is used to upload new firmware into the FCD flash. | ||||
|  * | ||||
|  * \sa fcdBlErase | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdBlWriteFirmware(hid_device *phd, char *pc, int64_t n64Size) | ||||
| { | ||||
|     //hid_device *phd=NULL;
 | ||||
|     unsigned char aucBufIn[65]; | ||||
|     unsigned char aucBufOut[65]; | ||||
|     uint32_t u32AddrStart; | ||||
|     uint32_t u32AddrEnd; | ||||
|     uint32_t u32Addr; | ||||
|     BOOL bFinished=FALSE; | ||||
| 
 | ||||
|     /*
 | ||||
|     phd = fcdOpen(); | ||||
| 
 | ||||
|     if (phd==NULL) | ||||
|     { | ||||
|         return FCD_MODE_NONE; | ||||
|     }*/ | ||||
| 
 | ||||
|     // Get the valid flash address range
 | ||||
|     aucBufOut[0] = 0; // Report ID, ignored
 | ||||
|     aucBufOut[1] = FCD_CMD_BL_GET_BYTE_ADDR_RANGE; | ||||
|     hid_write(phd, aucBufOut, 65); | ||||
|     memset(aucBufIn, 0xCC, 65); // Clear out the response buffer
 | ||||
|     hid_read(phd, aucBufIn, 65); | ||||
| 
 | ||||
|     if (aucBufIn[0]!=FCD_CMD_BL_GET_BYTE_ADDR_RANGE || aucBufIn[1]!=1) | ||||
|     { | ||||
|     	/*
 | ||||
|         fcdClose(phd); | ||||
|         phd = NULL;*/ | ||||
| 
 | ||||
|         return FCD_MODE_APP; | ||||
|     } | ||||
| 
 | ||||
|     u32AddrStart= | ||||
|         aucBufIn[2]+ | ||||
|         (((uint32_t)aucBufIn[3])<<8)+ | ||||
|         (((uint32_t)aucBufIn[4])<<16)+ | ||||
|         (((uint32_t)aucBufIn[5])<<24); | ||||
|     u32AddrEnd= | ||||
|         aucBufIn[6]+ | ||||
|         (((uint32_t)aucBufIn[7])<<8)+ | ||||
|         (((uint32_t)aucBufIn[8])<<16)+ | ||||
|         (((uint32_t)aucBufIn[9])<<24); | ||||
| 
 | ||||
|     // Set start address for flash
 | ||||
|     aucBufOut[0] = 0; // Report ID, ignored
 | ||||
|     aucBufOut[1] = FCD_CMD_BL_SET_BYTE_ADDR; | ||||
|     aucBufOut[2] = ((unsigned char)u32AddrStart); | ||||
|     aucBufOut[3] = ((unsigned char)(u32AddrStart>>8)); | ||||
|     aucBufOut[4] = ((unsigned char)(u32AddrStart>>16)); | ||||
|     aucBufOut[5] = ((unsigned char)(u32AddrStart>>24)); | ||||
|     hid_write(phd, aucBufOut, 65); | ||||
|     memset(aucBufIn, 0xCC, 65); // Clear out the response buffer
 | ||||
|     hid_read(phd, aucBufIn, 65); | ||||
| 
 | ||||
|     if (aucBufIn[0]!=FCD_CMD_BL_SET_BYTE_ADDR || aucBufIn[1]!=1) | ||||
|     { | ||||
|     	/*
 | ||||
|         fcdClose(phd); | ||||
|         phd = NULL;*/ | ||||
| 
 | ||||
|         return FCD_MODE_APP; | ||||
|     } | ||||
| 
 | ||||
|     // Write blocks
 | ||||
|     aucBufOut[0] = 0; // Report ID, ignored
 | ||||
|     aucBufOut[1] = FCD_CMD_BL_WRITE_FLASH_BLOCK; | ||||
|     for (u32Addr=u32AddrStart; u32Addr+47<u32AddrEnd && u32Addr+47<n64Size && !bFinished; u32Addr+=48) | ||||
|     { | ||||
|         memcpy(&aucBufOut[3], &pc[u32Addr], 48); | ||||
| 
 | ||||
|         hid_write(phd, aucBufOut, 65); | ||||
|         memset(aucBufIn, 0xCC, 65); // Clear out the response buffer
 | ||||
|         hid_read(phd, aucBufIn, 65); | ||||
| 
 | ||||
|         if (aucBufIn[0]!=FCD_CMD_BL_WRITE_FLASH_BLOCK || aucBufIn[1]!=1) | ||||
|         { | ||||
|             bFinished = TRUE; | ||||
|             /*
 | ||||
|             fcdClose(phd); | ||||
|             phd = NULL;*/ | ||||
| 
 | ||||
|             return FCD_MODE_APP; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|     fcdClose(phd); | ||||
|     phd = NULL;*/ | ||||
| 
 | ||||
|     return FCD_MODE_BL; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** \brief Verify firmware in FCd flash.
 | ||||
|  * \param pc Pointer to firmware data to verify against. | ||||
|  * \param n64Size Size of the data in pc. | ||||
|  * \return The FCD_MODE_BL if verification was succesful. | ||||
|  * | ||||
|  * This function verifies the firmware currently in the FCd flash against the firmware | ||||
|  * image pointed to by pc. The function return FCD_MODE_BL if the verification is OK and | ||||
|  * FCD_MODE_APP otherwise. | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdBlVerifyFirmware(hid_device *phd, char *pc, int64_t n64Size) | ||||
| { | ||||
|     //hid_device *phd=NULL;
 | ||||
|     unsigned char aucBufIn[65]; | ||||
|     unsigned char aucBufOut[65]; | ||||
|     uint32_t u32AddrStart; | ||||
|     uint32_t u32AddrEnd; | ||||
|     uint32_t u32Addr; | ||||
|     BOOL bFinished=FALSE; | ||||
| 
 | ||||
|     /*
 | ||||
|     phd = fcdOpen(); | ||||
| 
 | ||||
|     if (phd==NULL) | ||||
|     { | ||||
|         return FCD_MODE_NONE; | ||||
|     }*/ | ||||
| 
 | ||||
|     // Get the valid flash address range
 | ||||
|     aucBufOut[0] = 0; // Report ID, ignored
 | ||||
|     aucBufOut[1] = FCD_CMD_BL_GET_BYTE_ADDR_RANGE; | ||||
|     hid_write(phd, aucBufOut, 65); | ||||
|     memset(aucBufIn, 0xCC, 65); // Clear out the response buffer
 | ||||
|     hid_read(phd, aucBufIn, 65); | ||||
| 
 | ||||
|     if (aucBufIn[0]!=FCD_CMD_BL_GET_BYTE_ADDR_RANGE || aucBufIn[1]!=1) | ||||
|     { | ||||
|     	/*
 | ||||
|         fcdClose(phd); | ||||
|         phd = NULL;*/ | ||||
| 
 | ||||
|         return FCD_MODE_APP; | ||||
|     } | ||||
| 
 | ||||
|     u32AddrStart= | ||||
|         aucBufIn[2]+ | ||||
|         (((uint32_t)aucBufIn[3])<<8)+ | ||||
|         (((uint32_t)aucBufIn[4])<<16)+ | ||||
|         (((uint32_t)aucBufIn[5])<<24); | ||||
| 
 | ||||
|     u32AddrEnd= | ||||
|         aucBufIn[6]+ | ||||
|         (((uint32_t)aucBufIn[7])<<8)+ | ||||
|         (((uint32_t)aucBufIn[8])<<16)+ | ||||
|         (((uint32_t)aucBufIn[9])<<24); | ||||
| 
 | ||||
|     // Set start address for flash
 | ||||
|     aucBufOut[0] = 0; // Report ID, ignored
 | ||||
|     aucBufOut[1] = FCD_CMD_BL_SET_BYTE_ADDR; | ||||
|     aucBufOut[2] = ((unsigned char)u32AddrStart); | ||||
|     aucBufOut[3] = ((unsigned char)(u32AddrStart>>8)); | ||||
|     aucBufOut[4] = ((unsigned char)(u32AddrStart>>16)); | ||||
|     aucBufOut[5] = ((unsigned char)(u32AddrStart>>24)); | ||||
|     hid_write(phd, aucBufOut, 65); | ||||
|     memset(aucBufIn, 0xCC, 65); // Clear out the response buffer
 | ||||
|     hid_read(phd, aucBufIn, 65); | ||||
| 
 | ||||
|     if (aucBufIn[0]!=FCD_CMD_BL_SET_BYTE_ADDR || aucBufIn[1]!=1) | ||||
|     { | ||||
|     	/*
 | ||||
|         fcdClose(phd); | ||||
|         phd = NULL;*/ | ||||
| 
 | ||||
|         return FCD_MODE_APP; | ||||
|     } | ||||
| 
 | ||||
|     // Read blocks
 | ||||
|     aucBufOut[0] = 0; // Report ID, ignored
 | ||||
|     aucBufOut[1] = FCD_CMD_BL_READ_FLASH_BLOCK; | ||||
|     for (u32Addr=u32AddrStart; u32Addr+47<u32AddrEnd && u32Addr+47<n64Size && !bFinished; u32Addr+=48) | ||||
|     { | ||||
|         hid_write(phd, aucBufOut, 65); | ||||
|         memset(aucBufIn, 0xCC, 65); // Clear out the response buffer
 | ||||
|         hid_read(phd, aucBufIn, 65); | ||||
| 
 | ||||
|         if (aucBufIn[0]!=FCD_CMD_BL_READ_FLASH_BLOCK || aucBufIn[1]!=1) | ||||
|         { | ||||
|             bFinished = TRUE; | ||||
|             /*
 | ||||
|             fcdClose(phd); | ||||
|             phd = NULL;*/ | ||||
| 
 | ||||
|             return FCD_MODE_APP; | ||||
|         } | ||||
| 
 | ||||
|         if (memcmp(&aucBufIn[2],&pc[u32Addr],48)!=0) | ||||
|         { | ||||
|             bFinished = TRUE; | ||||
|             /*
 | ||||
|             fcdClose(phd); | ||||
|             phd = NULL;*/ | ||||
| 
 | ||||
|             return FCD_MODE_APP; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|     fcdClose(phd); | ||||
|     phd = NULL;*/ | ||||
| 
 | ||||
|     return FCD_MODE_BL; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /** \brief Write FCD parameter (e.g. gain or filter)
 | ||||
|  * \param u8Cmd The command byte / parameter ID, see FCD_CMD_APP_SET_* | ||||
|  * \param pu8Data The parameter value to be written | ||||
|  * \param u8len Length of pu8Data in bytes | ||||
|  * \return One of FCD_MODE_NONE, FCD_MODE_APP or FCD_MODE_BL (see description) | ||||
|  * | ||||
|  * This function can be used to set the value of a parameter in the FCD for which there is no | ||||
|  * high level API call. It gives access to the low level API of the FCD and the caller is expected | ||||
|  * to be aware of the various FCD commands, since they are required to be supplied as parameter | ||||
|  * to this function. | ||||
|  * | ||||
|  * The return value can be used to determine the success or failure of the command execution: | ||||
|  * - FCD_MODE_APP : Reply from FCD was as expected (nominal case). | ||||
|  * - FCD_MODE_BL : Reply from FCD was not as expected. | ||||
|  * - FCD_MODE_NONE : No FCD was found | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdAppSetParam(hid_device *phd, uint8_t u8Cmd, uint8_t *pu8Data, uint8_t u8len) | ||||
| { | ||||
|     //hid_device *phd=NULL;
 | ||||
|     unsigned char aucBufOut[65]; | ||||
|     unsigned char aucBufIn[65]; | ||||
| 
 | ||||
|     /*
 | ||||
|     phd = fcdOpen(); | ||||
| 
 | ||||
|     if (phd == NULL) | ||||
|     { | ||||
|         return FCD_MODE_NONE; | ||||
|     }*/ | ||||
| 
 | ||||
|     aucBufOut[0]=0; // Report ID, ignored
 | ||||
|     aucBufOut[1]=u8Cmd; | ||||
|     memcpy(aucBufOut+2, pu8Data,u8len); | ||||
|     hid_write(phd,aucBufOut,65); | ||||
| 
 | ||||
|     /* we must read after each write in order to empty FCD/HID buffer */ | ||||
|     memset(aucBufIn,0xCC,65); // Clear out the response buffer
 | ||||
|     hid_read(phd,aucBufIn,65); | ||||
| 
 | ||||
|     /* Check the response, if OK return FCD_MODE_APP */ | ||||
|     if (aucBufIn[0]==u8Cmd && aucBufIn[1]==1) { | ||||
|     	/*
 | ||||
|         fcdClose(phd); | ||||
|         phd = NULL;*/ | ||||
| 
 | ||||
|         return FCD_MODE_APP; | ||||
|     } | ||||
| 
 | ||||
|     /* Response did not contain the expected bytes */ | ||||
|     /*
 | ||||
|     fcdClose(phd); | ||||
|     phd = NULL;*/ | ||||
| 
 | ||||
|     return FCD_MODE_BL; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** \brief Read FCD parameter (e.g. gain or filter)
 | ||||
|  * \param u8Cmd The command byte / parameter ID, see FCD_CMD_APP_GET_* | ||||
|  * \param pu8Data TPointer to buffer where the parameter value(s) will be written | ||||
|  * \param u8len Length of pu8Data in bytes | ||||
|  * \return One of FCD_MODE_NONE, FCD_MODE_APP or FCD_MODE_BL (see description) | ||||
|  * | ||||
|  * This function can be used to read the value of a parameter in the FCD for which there is no | ||||
|  * high level API call. It gives access to the low level API of the FCD and the caller is expected | ||||
|  * to be aware of the various FCD commands, since they are required to be supplied as parameter | ||||
|  * to this function. | ||||
|  * | ||||
|  * The return value can be used to determine the success or failure of the command execution: | ||||
|  * - FCD_MODE_APP : Reply from FCD was as expected (nominal case). | ||||
|  * - FCD_MODE_BL : Reply from FCD was not as expected. | ||||
|  * - FCD_MODE_NONE : No FCD was found | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdAppGetParam(hid_device *phd, uint8_t u8Cmd, uint8_t *pu8Data, uint8_t u8len) | ||||
| { | ||||
|     //hid_device *phd=NULL;
 | ||||
|     unsigned char aucBufOut[65]; | ||||
|     unsigned char aucBufIn[65]; | ||||
| 
 | ||||
|     /*
 | ||||
|     phd = fcdOpen(); | ||||
|     if (phd == NULL) | ||||
|     { | ||||
|         return FCD_MODE_NONE; | ||||
|     }*/ | ||||
| 
 | ||||
|     aucBufOut[0]=0; // Report ID, ignored
 | ||||
|     aucBufOut[1]=u8Cmd; | ||||
|     hid_write(phd,aucBufOut,65); | ||||
| 
 | ||||
|     memset(aucBufIn,0xCC,65); // Clear out the response buffer
 | ||||
|     hid_read(phd,aucBufIn,65); | ||||
|     /* Copy return data to output buffer (even if cmd exec failed) */ | ||||
|     memcpy(pu8Data,aucBufIn+2,u8len); | ||||
| 
 | ||||
|     /* Check status bytes in returned data */ | ||||
|     if (aucBufIn[0]==u8Cmd && aucBufIn[1]==1) { | ||||
|     	/*
 | ||||
|         fcdClose(phd); | ||||
|         phd = NULL;*/ | ||||
| 
 | ||||
|         return FCD_MODE_APP; | ||||
|     } | ||||
| 
 | ||||
|     /* Response did not contain the expected bytes */ | ||||
|     /*
 | ||||
|     fcdClose(phd); | ||||
|     phd = NULL;*/ | ||||
| 
 | ||||
|     return FCD_MODE_BL; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										234
									
								
								fcdhid/fcdhid.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								fcdhid/fcdhid.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,234 @@ | ||||
| /***************************************************************************
 | ||||
|  *  This file is part of Qthid. | ||||
|  *  | ||||
|  *  Copyright (C) 2010  Howard Long, G6LVB | ||||
|  *  CopyRight (C) 2011  Alexandru Csete, OZ9AEC | ||||
|  *                      Mario Lorenz, DL5MLO | ||||
|  *  | ||||
|  *  Qthid is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  Qthid is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with Qthid.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  ***************************************************************************/ | ||||
| 
 | ||||
| #ifndef _QTHID_H_ | ||||
| #define _QTHID_H_ | ||||
| 
 | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <stdint.h> | ||||
| #include "fcdhidcmd.h" | ||||
| #include "hidapi.h" | ||||
| 
 | ||||
| #include <inttypes.h> | ||||
| 
 | ||||
| #define FALSE 0 | ||||
| #define TRUE 1 | ||||
| typedef int BOOL; | ||||
| 
 | ||||
| /** \brief FCD mode enumeration. */ | ||||
| typedef enum { | ||||
|     FCD_MODE_NONE,  /*!< No FCD detected. */ | ||||
|     FCD_MODE_DEAD, | ||||
|     FCD_MODE_BL,    /*!< FCD present in bootloader mode. */ | ||||
|     FCD_MODE_APP    /*!< FCD present in aplpication mode. */ | ||||
| } FCD_MODE_ENUM; // The current mode of the FCD: none inserted, in bootloader mode or in normal application mode
 | ||||
| 
 | ||||
| /** \brief FCD capabilities that depend on both hardware and firmware. */ | ||||
| typedef struct { | ||||
|     unsigned char hasBiasT;     /*!< Whether FCD has hardware bias tee (1=yes, 0=no) */ | ||||
|     unsigned char hasCellBlock; /*!< Whether FCD has cellular blocking. */ | ||||
| } FCD_CAPS_STRUCT; | ||||
| 
 | ||||
| 
 | ||||
| //#define FCDPP // FIXME: the Pro / Pro+ switch should be handled better than this!
 | ||||
| //const unsigned short _usVID=0x04D8;  /*!< USB vendor ID. */
 | ||||
| //#ifdef FCDPP
 | ||||
| //const unsigned short _usPID=0xFB31;  /*!< USB product ID. */
 | ||||
| //#else
 | ||||
| //const unsigned short _usPID=0xFB56;  /*!< USB product ID. */
 | ||||
| //#endif
 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /** \brief Open FCD device.
 | ||||
|  * \return Pointer to the FCD HID device or NULL if none found | ||||
|  * | ||||
|  * This function looks for FCD devices connected to the computer and | ||||
|  * opens the first one found. | ||||
|  */ | ||||
| hid_device *fcdOpen(uint16_t usVID, uint16_t usPID, int whichdongle); | ||||
| 
 | ||||
| /** \brief Close FCD HID device. */ | ||||
| void fcdClose(hid_device *phd); | ||||
| 
 | ||||
| /** \brief Get FCD mode.
 | ||||
|  * \return The current FCD mode. | ||||
|  * \sa FCD_MODE_ENUM | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdGetMode(hid_device *phd); | ||||
| 
 | ||||
| /** \brief Get FCD firmware version as string.
 | ||||
|  * \param str The returned vesion number as a 0 terminated string (must be pre-allocated) | ||||
|  * \return The current FCD mode. | ||||
|  * \sa FCD_MODE_ENUM | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdGetFwVerStr(hid_device *phd, char *str); | ||||
| 
 | ||||
| /** \brief Get hardware and firmware dependent FCD capabilities.
 | ||||
|  * \param fcd_caps Pointer to an FCD_CAPS_STRUCT | ||||
|  * \return The current FCD mode. | ||||
|  * | ||||
|  * This function queries the FCD and extracts the hardware and firmware dependent | ||||
|  * capabilities. Currently these capabilities are: | ||||
|  *  - Bias T (available since S/N TBD) | ||||
|  *  - Cellular block (the certified version of the FCD) | ||||
|  * When the FCD is in application mode, the string returned by the query command is | ||||
|  * (starting at index 2): | ||||
|  *    FCDAPP 18.08 Brd 1.0 No blk | ||||
|  * 1.0 means no bias tee, 1.1 means there is a bias tee | ||||
|  * 'No blk' means it is not cellular blocked. | ||||
|  * | ||||
|  * Ref: http://uk.groups.yahoo.com/group/FCDevelopment/message/303
 | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdGetCaps(hid_device *phd, FCD_CAPS_STRUCT *fcd_caps); | ||||
| 
 | ||||
| /** \brief Get hardware and firmware dependent FCD capabilities as string.
 | ||||
|  * \param caps_str Pointer to a pre-allocated string buffer where the info will be copied. | ||||
|  * \return The current FCD mode. | ||||
|  * | ||||
|  * This function queries the FCD and copies the returned string into the caps_str parameter. | ||||
|  * THe return buffer must be at least 28 characters. | ||||
|  * When the FCD is in application mode, the string returned by the query command is | ||||
|  * (starting at index 2): | ||||
|  *    FCDAPP 18.08 Brd 1.0 No blk | ||||
|  * 1.0 means no bias tee, 1.1 means there is a bias tee | ||||
|  * 'No blk' means it is not cellular blocked. | ||||
|  * | ||||
|  * Ref: http://uk.groups.yahoo.com/group/FCDevelopment/message/303
 | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdGetCapsStr(hid_device *phd, char *caps_str); | ||||
| 
 | ||||
| /** \brief Reset FCD to bootloader mode.
 | ||||
|  * \return FCD_MODE_NONE | ||||
|  * | ||||
|  * This function is used to switch the FCD into bootloader mode in which | ||||
|  * various firmware operations can be performed. | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdAppReset(hid_device *phd); | ||||
| 
 | ||||
| /** \brief Set FCD frequency with kHz resolution.
 | ||||
|  * \param nFreq The new frequency in kHz. | ||||
|  * \return The FCD mode. | ||||
|  * | ||||
|  * This function sets the frequency of the FCD with 1 kHz resolution. The parameter | ||||
|  * nFreq must already contain any necessary frequency correction. | ||||
|  * | ||||
|  * \sa fcdAppSetFreq | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdAppSetFreqkHz(hid_device *phd, int nFreq); | ||||
| 
 | ||||
| /** \brief Set FCD frequency with Hz resolution.
 | ||||
|  * \param nFreq The new frequency in Hz. | ||||
|  * \return The FCD mode. | ||||
|  * | ||||
|  * This function sets the frequency of the FCD with 1 Hz resolution. The parameter | ||||
|  * nFreq must already contain any necessary frequency correction. | ||||
|  * | ||||
|  * \sa fcdAppSetFreq | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdAppSetFreq(hid_device *phd, int nFreq); | ||||
| 
 | ||||
| /** \brief Reset FCD to application mode.
 | ||||
|  * \return FCD_MODE_NONE | ||||
|  * | ||||
|  * This function is used to switch the FCD from bootloader mode | ||||
|  * into application mode. | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdBlReset(hid_device *phd); | ||||
| 
 | ||||
| /** \brief Erase firmware from FCD.
 | ||||
|  * \return The FCD mode | ||||
|  * | ||||
|  * This function deletes the firmware from the FCD. This is required | ||||
|  * before writing new firmware into the FCD. | ||||
|  * | ||||
|  * \sa fcdBlWriteFirmware | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdBlErase(hid_device *phd); | ||||
| 
 | ||||
| /** \brief Write new firmware into the FCD.
 | ||||
|  * \param pc Pointer to the new firmware data | ||||
|  * \param n64size The number of bytes in the data | ||||
|  * \return The FCD mode | ||||
|  * | ||||
|  * This function is used to upload new firmware into the FCD flash. | ||||
|  * | ||||
|  * \sa fcdBlErase | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdBlWriteFirmware(hid_device *phd, char *pc, int64_t n64Size); | ||||
| 
 | ||||
| /** \brief Verify firmware in FCd flash.
 | ||||
|  * \param pc Pointer to firmware data to verify against. | ||||
|  * \param n64Size Size of the data in pc. | ||||
|  * \return The FCD_MODE_BL if verification was succesful. | ||||
|  * | ||||
|  * This function verifies the firmware currently in the FCd flash against the firmware | ||||
|  * image pointed to by pc. The function return FCD_MODE_BL if the verification is OK and | ||||
|  * FCD_MODE_APP otherwise. | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdBlVerifyFirmware(hid_device *phd, char *pc, int64_t n64Size); | ||||
| 
 | ||||
| /** \brief Write FCD parameter (e.g. gain or filter)
 | ||||
|  * \param u8Cmd The command byte / parameter ID, see FCD_CMD_APP_SET_* | ||||
|  * \param pu8Data The parameter value to be written | ||||
|  * \param u8len Length of pu8Data in bytes | ||||
|  * \return One of FCD_MODE_NONE, FCD_MODE_APP or FCD_MODE_BL (see description) | ||||
|  * | ||||
|  * This function can be used to set the value of a parameter in the FCD for which there is no | ||||
|  * high level API call. It gives access to the low level API of the FCD and the caller is expected | ||||
|  * to be aware of the various FCD commands, since they are required to be supplied as parameter | ||||
|  * to this function. | ||||
|  * | ||||
|  * The return value can be used to determine the success or failure of the command execution: | ||||
|  * - FCD_MODE_APP : Reply from FCD was as expected (nominal case). | ||||
|  * - FCD_MODE_BL : Reply from FCD was not as expected. | ||||
|  * - FCD_MODE_NONE : No FCD was found | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdAppSetParam(hid_device *phd, uint8_t u8Cmd, uint8_t *pu8Data, uint8_t u8len); | ||||
| 
 | ||||
| /** \brief Read FCD parameter (e.g. gain or filter)
 | ||||
|  * \param u8Cmd The command byte / parameter ID, see FCD_CMD_APP_GET_* | ||||
|  * \param pu8Data TPointer to buffer where the parameter value(s) will be written | ||||
|  * \param u8len Length of pu8Data in bytes | ||||
|  * \return One of FCD_MODE_NONE, FCD_MODE_APP or FCD_MODE_BL (see description) | ||||
|  * | ||||
|  * This function can be used to read the value of a parameter in the FCD for which there is no | ||||
|  * high level API call. It gives access to the low level API of the FCD and the caller is expected | ||||
|  * to be aware of the various FCD commands, since they are required to be supplied as parameter | ||||
|  * to this function. | ||||
|  * | ||||
|  * The return value can be used to determine the success or failure of the command execution: | ||||
|  * - FCD_MODE_APP : Reply from FCD was as expected (nominal case). | ||||
|  * - FCD_MODE_BL : Reply from FCD was not as expected. | ||||
|  * - FCD_MODE_NONE : No FCD was found | ||||
|  */ | ||||
| FCD_MODE_ENUM fcdAppGetParam(hid_device *phd, uint8_t u8Cmd, uint8_t *pu8Data, uint8_t u8len); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif // _QTHID_H_
 | ||||
							
								
								
									
										305
									
								
								fcdhid/fcdhidcmd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										305
									
								
								fcdhid/fcdhidcmd.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,305 @@ | ||||
| /***************************************************************************
 | ||||
|  *  This file is part of Qthid. | ||||
|  * | ||||
|  *  Copyright (C) 2010  Howard Long, G6LVB | ||||
|  *  CopyRight (C) 2011  Alexandru Csete, OZ9AEC | ||||
|  *                      Mario Lorenz, DL5MLO | ||||
|  * | ||||
|  *  Qthid is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  Qthid is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with Qthid.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  ***************************************************************************/ | ||||
| #ifndef FCDHIDCMD_H | ||||
| #define FCDHIDCMD_H | ||||
| 
 | ||||
| 
 | ||||
| /* Commands applicable in bootloader mode */ | ||||
| #define FCD_CMD_BL_QUERY                1  /*!< Returns string with "FCDAPP version". */ | ||||
| #define FCD_CMD_BL_RESET                8  /*!< Reset to application mode. */ | ||||
| #define FCD_CMD_BL_ERASE               24  /*!< Erase firmware from FCD flash. */ | ||||
| #define FCD_CMD_BL_SET_BYTE_ADDR       25  /*!< TBD */ | ||||
| #define FCD_CMD_BL_GET_BYTE_ADDR_RANGE 26  /*!< Get address range. */ | ||||
| #define FCD_CMD_BL_WRITE_FLASH_BLOCK   27  /*!< Write flash block. */ | ||||
| #define FCD_CMD_BL_READ_FLASH_BLOCK    28  /*!< Read flash block. */ | ||||
| 
 | ||||
| /* Commands applicable in application mode */ | ||||
| #define FCD_CMD_APP_SET_FREQ_KHZ     100 /*!< Send with 3 byte unsigned little endian frequency in kHz. */ | ||||
| #define FCD_CMD_APP_SET_FREQ_HZ      101 /*!< Send with 4 byte unsigned little endian frequency in Hz, returns with actual frequency set in Hz */ | ||||
| #define FCD_CMD_APP_GET_FREQ_HZ      102 /*!< Returns 4 byte unsigned little endian frequency in Hz. */ | ||||
| 
 | ||||
| #define FCD_CMD_APP_GET_IF_RSSI      104 /*!< Supposed to return 1 byte unsigned IF RSSI (-35dBm=0, -10dBm=70) but it is not functional. */ | ||||
| #define FCD_CMD_APP_GET_PLL_LOCK     105 /*!< Returns 1 bit, true if locked. */ | ||||
| 
 | ||||
| #define FCD_CMD_APP_SET_DC_CORR      106 /*!< Send with 2 byte unsigned I DC correction followed by 2 byte unsigned Q DC correction. 32768 is the default centre value. */ | ||||
| #define FCD_CMD_APP_GET_DC_CORR      107 /*!< Returns 2 byte unsigned I DC correction followed by 2 byte unsigned Q DC correction. 32768 is the default centre value. */ | ||||
| #define FCD_CMD_APP_SET_IQ_CORR      108 /*!< Send with 2 byte signed phase correction followed by 2 byte unsigned gain correction. 0 is the default centre value for phase correction, 32768 is the default centre value for gain. */ | ||||
| #define FCD_CMD_APP_GET_IQ_CORR      109 /*!< Returns 2 byte signed phase correction followed by 2 byte unsigned gain correction. 0 is the default centre value for phase correction, 32768 is the default centre value for gain. */ | ||||
| 
 | ||||
| #define FCD_CMD_APP_SET_LNA_GAIN     110 /*!< Send a 1 byte value, see enums for reference. */ | ||||
| #define FCD_CMD_APP_SET_LNA_ENHANCE  111 | ||||
| #define FCD_CMD_APP_SET_BAND         112 | ||||
| #define FCD_CMD_APP_SET_RF_FILTER    113 | ||||
| #define FCD_CMD_APP_SET_MIXER_GAIN   114 | ||||
| #define FCD_CMD_APP_SET_BIAS_CURRENT 115 | ||||
| #define FCD_CMD_APP_SET_MIXER_FILTER 116 | ||||
| #define FCD_CMD_APP_SET_IF_GAIN1     117 | ||||
| #define FCD_CMD_APP_SET_IF_GAIN_MODE 118 | ||||
| #define FCD_CMD_APP_SET_IF_RC_FILTER 119 | ||||
| #define FCD_CMD_APP_SET_IF_GAIN2     120 | ||||
| #define FCD_CMD_APP_SET_IF_GAIN3     121 | ||||
| #define FCD_CMD_APP_SET_IF_FILTER    122 | ||||
| #define FCD_CMD_APP_SET_IF_GAIN4     123 | ||||
| #define FCD_CMD_APP_SET_IF_GAIN5     124 | ||||
| #define FCD_CMD_APP_SET_IF_GAIN6     125 | ||||
| #define FCD_CMD_APP_SET_BIAS_TEE     126 /*!< Bias T for ext LNA. Send with one byte: 1=ON, 0=OFF. */ | ||||
| 
 | ||||
| #define FCD_CMD_APP_GET_LNA_GAIN     150 // Retrieve a 1 byte value, see enums for reference
 | ||||
| #define FCD_CMD_APP_GET_LNA_ENHANCE  151 | ||||
| #define FCD_CMD_APP_GET_BAND         152 | ||||
| #define FCD_CMD_APP_GET_RF_FILTER    153 | ||||
| #define FCD_CMD_APP_GET_MIXER_GAIN   154 | ||||
| #define FCD_CMD_APP_GET_BIAS_CURRENT 155 | ||||
| #define FCD_CMD_APP_GET_MIXER_FILTER 156 | ||||
| #define FCD_CMD_APP_GET_IF_GAIN1     157 | ||||
| #define FCD_CMD_APP_GET_IF_GAIN_MODE 158 | ||||
| #define FCD_CMD_APP_GET_IF_RC_FILTER 159 | ||||
| #define FCD_CMD_APP_GET_IF_GAIN2     160 | ||||
| #define FCD_CMD_APP_GET_IF_GAIN3     161 | ||||
| #define FCD_CMD_APP_GET_IF_FILTER    162 | ||||
| #define FCD_CMD_APP_GET_IF_GAIN4     163 | ||||
| #define FCD_CMD_APP_GET_IF_GAIN5     164 | ||||
| #define FCD_CMD_APP_GET_IF_GAIN6     165 | ||||
| #define FCD_CMD_APP_GET_BIAS_TEE     166 /*!< Bias T. 1=ON, 0=OFF. */ | ||||
| 
 | ||||
| #define FCD_CMD_APP_SEND_I2C_BYTE    200 | ||||
| #define FCD_CMD_APP_RECV_I2C_BYTE    201 | ||||
| 
 | ||||
| #define FCD_CMD_APP_RESET            255 // Reset to bootloader
 | ||||
| 
 | ||||
| 
 | ||||
| typedef enum  | ||||
| { | ||||
| 	TLGE_N5_0DB=0, | ||||
| 	TLGE_N2_5DB=1, | ||||
| 	TLGE_P0_0DB=4, | ||||
| 	TLGE_P2_5DB=5, | ||||
| 	TLGE_P5_0DB=6, | ||||
| 	TLGE_P7_5DB=7, | ||||
| 	TLGE_P10_0DB=8, | ||||
| 	TLGE_P12_5DB=9, | ||||
| 	TLGE_P15_0DB=10, | ||||
| 	TLGE_P17_5DB=11, | ||||
| 	TLGE_P20_0DB=12, | ||||
| 	TLGE_P25_0DB=13, | ||||
| 	TLGE_P30_0DB=14 | ||||
| } TUNER_LNA_GAIN_ENUM; | ||||
| 
 | ||||
| typedef enum | ||||
| { | ||||
|   TLEE_OFF=0, | ||||
|   TLEE_0=1, | ||||
|   TLEE_1=3, | ||||
|   TLEE_2=5, | ||||
|   TLEE_3=7 | ||||
| } TUNER_LNA_ENHANCE_ENUM; | ||||
| 
 | ||||
| typedef enum | ||||
| { | ||||
|   TBE_VHF2, | ||||
|   TBE_VHF3, | ||||
|   TBE_UHF, | ||||
|   TBE_LBAND | ||||
| } TUNER_BAND_ENUM; | ||||
| 
 | ||||
| typedef enum | ||||
| { | ||||
|   // Band 0, VHF II
 | ||||
|   TRFE_LPF268MHZ=0, | ||||
|   TRFE_LPF299MHZ=8, | ||||
|   // Band 1, VHF III
 | ||||
|   TRFE_LPF509MHZ=0, | ||||
|   TRFE_LPF656MHZ=8, | ||||
|   // Band 2, UHF
 | ||||
|   TRFE_BPF360MHZ=0, | ||||
|   TRFE_BPF380MHZ=1, | ||||
|   TRFE_BPF405MHZ=2, | ||||
|   TRFE_BPF425MHZ=3, | ||||
|   TRFE_BPF450MHZ=4, | ||||
|   TRFE_BPF475MHZ=5, | ||||
|   TRFE_BPF505MHZ=6, | ||||
|   TRFE_BPF540MHZ=7, | ||||
|   TRFE_BPF575MHZ=8, | ||||
|   TRFE_BPF615MHZ=9, | ||||
|   TRFE_BPF670MHZ=10, | ||||
|   TRFE_BPF720MHZ=11, | ||||
|   TRFE_BPF760MHZ=12, | ||||
|   TRFE_BPF840MHZ=13, | ||||
|   TRFE_BPF890MHZ=14, | ||||
|   TRFE_BPF970MHZ=15, | ||||
|   // Band 2, L band
 | ||||
|   TRFE_BPF1300MHZ=0, | ||||
|   TRFE_BPF1320MHZ=1, | ||||
|   TRFE_BPF1360MHZ=2, | ||||
|   TRFE_BPF1410MHZ=3, | ||||
|   TRFE_BPF1445MHZ=4, | ||||
|   TRFE_BPF1460MHZ=5, | ||||
|   TRFE_BPF1490MHZ=6, | ||||
|   TRFE_BPF1530MHZ=7, | ||||
|   TRFE_BPF1560MHZ=8, | ||||
|   TRFE_BPF1590MHZ=9, | ||||
|   TRFE_BPF1640MHZ=10, | ||||
|   TRFE_BPF1660MHZ=11, | ||||
|   TRFE_BPF1680MHZ=12, | ||||
|   TRFE_BPF1700MHZ=13, | ||||
|   TRFE_BPF1720MHZ=14, | ||||
|   TRFE_BPF1750MHZ=15 | ||||
| } TUNER_RF_FILTER_ENUM; | ||||
| 
 | ||||
| typedef enum | ||||
| { | ||||
|   TMGE_P4_0DB=0, | ||||
|   TMGE_P12_0DB=1 | ||||
| } TUNER_MIXER_GAIN_ENUM; | ||||
| 
 | ||||
| typedef enum | ||||
| { | ||||
|   TBCE_LBAND=0, | ||||
|   TBCE_1=1, | ||||
|   TBCE_2=2, | ||||
|   TBCE_VUBAND=3 | ||||
| } TUNER_BIAS_CURRENT_ENUM; | ||||
| 
 | ||||
| typedef enum | ||||
| { | ||||
|   TMFE_27_0MHZ=0, | ||||
|   TMFE_4_6MHZ=8, | ||||
|   TMFE_4_2MHZ=9, | ||||
|   TMFE_3_8MHZ=10, | ||||
|   TMFE_3_4MHZ=11, | ||||
|   TMFE_3_0MHZ=12, | ||||
|   TMFE_2_7MHZ=13, | ||||
|   TMFE_2_3MHZ=14, | ||||
|   TMFE_1_9MHZ=15 | ||||
| } TUNER_MIXER_FILTER_ENUM; | ||||
| 
 | ||||
| typedef enum | ||||
| { | ||||
|   TIG1E_N3_0DB=0, | ||||
|   TIG1E_P6_0DB=1 | ||||
| } TUNER_IF_GAIN1_ENUM; | ||||
| 
 | ||||
| typedef enum | ||||
| { | ||||
|   TIGME_LINEARITY=0, | ||||
|   TIGME_SENSITIVITY=1 | ||||
| } TUNER_IF_GAIN_MODE_ENUM; | ||||
| 
 | ||||
| typedef enum | ||||
| { | ||||
|   TIRFE_21_4MHZ=0, | ||||
|   TIRFE_21_0MHZ=1, | ||||
|   TIRFE_17_6MHZ=2, | ||||
|   TIRFE_14_7MHZ=3, | ||||
|   TIRFE_12_4MHZ=4, | ||||
|   TIRFE_10_6MHZ=5, | ||||
|   TIRFE_9_0MHZ=6, | ||||
|   TIRFE_7_7MHZ=7, | ||||
|   TIRFE_6_4MHZ=8, | ||||
|   TIRFE_5_3MHZ=9, | ||||
|   TIRFE_4_4MHZ=10, | ||||
|   TIRFE_3_4MHZ=11, | ||||
|   TIRFE_2_6MHZ=12, | ||||
|   TIRFE_1_8MHZ=13, | ||||
|   TIRFE_1_2MHZ=14, | ||||
|   TIRFE_1_0MHZ=15 | ||||
| } TUNER_IF_RC_FILTER_ENUM; | ||||
| 
 | ||||
| typedef enum | ||||
| { | ||||
|   TIG2E_P0_0DB=0, | ||||
|   TIG2E_P3_0DB=1, | ||||
|   TIG2E_P6_0DB=2, | ||||
|   TIG2E_P9_0DB=3 | ||||
| } TUNER_IF_GAIN2_ENUM; | ||||
| 
 | ||||
| typedef enum | ||||
| { | ||||
|   TIG3E_P0_0DB=0, | ||||
|   TIG3E_P3_0DB=1, | ||||
|   TIG3E_P6_0DB=2, | ||||
|   TIG3E_P9_0DB=3 | ||||
| } TUNER_IF_GAIN3_ENUM; | ||||
| 
 | ||||
| typedef enum | ||||
| { | ||||
|   TIG4E_P0_0DB=0, | ||||
|   TIG4E_P1_0DB=1, | ||||
|   TIG4E_P2_0DB=2 | ||||
| } TUNER_IF_GAIN4_ENUM; | ||||
| 
 | ||||
| typedef enum | ||||
| { | ||||
|   TIFE_5_50MHZ=0, | ||||
|   TIFE_5_30MHZ=1, | ||||
|   TIFE_5_00MHZ=2, | ||||
|   TIFE_4_80MHZ=3, | ||||
|   TIFE_4_60MHZ=4, | ||||
|   TIFE_4_40MHZ=5, | ||||
|   TIFE_4_30MHZ=6, | ||||
|   TIFE_4_10MHZ=7, | ||||
|   TIFE_3_90MHZ=8, | ||||
|   TIFE_3_80MHZ=9, | ||||
|   TIFE_3_70MHZ=10, | ||||
|   TIFE_3_60MHZ=11, | ||||
|   TIFE_3_40MHZ=12, | ||||
|   TIFE_3_30MHZ=13, | ||||
|   TIFE_3_20MHZ=14, | ||||
|   TIFE_3_10MHZ=15, | ||||
|   TIFE_3_00MHZ=16, | ||||
|   TIFE_2_95MHZ=17, | ||||
|   TIFE_2_90MHZ=18, | ||||
|   TIFE_2_80MHZ=19, | ||||
|   TIFE_2_75MHZ=20, | ||||
|   TIFE_2_70MHZ=21, | ||||
|   TIFE_2_60MHZ=22, | ||||
|   TIFE_2_55MHZ=23, | ||||
|   TIFE_2_50MHZ=24, | ||||
|   TIFE_2_45MHZ=25, | ||||
|   TIFE_2_40MHZ=26, | ||||
|   TIFE_2_30MHZ=27, | ||||
|   TIFE_2_28MHZ=28, | ||||
|   TIFE_2_24MHZ=29, | ||||
|   TIFE_2_20MHZ=30, | ||||
|   TIFE_2_15MHZ=31 | ||||
| } TUNER_IF_FILTER_ENUM; | ||||
| 
 | ||||
| typedef enum | ||||
| { | ||||
|   TIG5E_P3_0DB=0, | ||||
|   TIG5E_P6_0DB=1, | ||||
|   TIG5E_P9_0DB=2, | ||||
|   TIG5E_P12_0DB=3, | ||||
|   TIG5E_P15_0DB=4 | ||||
| } TUNER_IF_GAIN5_ENUM; | ||||
| 
 | ||||
| typedef enum | ||||
| { | ||||
|   TIG6E_P3_0DB=0, | ||||
|   TIG6E_P6_0DB=1, | ||||
|   TIG6E_P9_0DB=2, | ||||
|   TIG6E_P12_0DB=3, | ||||
|   TIG6E_P15_0DB=4 | ||||
| } TUNER_IF_GAIN6_ENUM; | ||||
| 
 | ||||
| 
 | ||||
| #endif // FCDHIDCMD_H
 | ||||
							
								
								
									
										1427
									
								
								fcdhid/hid-libusb.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1427
									
								
								fcdhid/hid-libusb.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1432
									
								
								fcdhid/hid-libusb.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1432
									
								
								fcdhid/hid-libusb.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										387
									
								
								fcdhid/hidapi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										387
									
								
								fcdhid/hidapi.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,387 @@ | ||||
| /*******************************************************
 | ||||
|  HIDAPI - Multi-Platform library for | ||||
|  communication with HID devices. | ||||
| 
 | ||||
|  Alan Ott | ||||
|  Signal 11 Software | ||||
| 
 | ||||
|  8/22/2009 | ||||
| 
 | ||||
|  Copyright 2009, All Rights Reserved. | ||||
| 
 | ||||
|  At the discretion of the user of this library, | ||||
|  this software may be licensed under the terms of the | ||||
|  GNU General Public License v3, a BSD-Style license, or the | ||||
|  original HIDAPI license as outlined in the LICENSE.txt, | ||||
|  LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt | ||||
|  files located at the root of the source distribution. | ||||
|  These files may also be found in the public source | ||||
|  code repository located at: | ||||
|         http://github.com/signal11/hidapi .
 | ||||
| ********************************************************/ | ||||
| 
 | ||||
| /** @file
 | ||||
|  * @defgroup API hidapi API | ||||
|  */ | ||||
| 
 | ||||
| #ifndef HIDAPI_H__ | ||||
| #define HIDAPI_H__ | ||||
| 
 | ||||
| #include <wchar.h> | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
|       #define HID_API_EXPORT __declspec(dllexport) | ||||
|       #define HID_API_CALL | ||||
| #else | ||||
|       #define HID_API_EXPORT /**< API export macro */ | ||||
|       #define HID_API_CALL /**< API call macro */ | ||||
| #endif | ||||
| 
 | ||||
| #define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/ | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 		struct hid_device_; | ||||
| 		typedef struct hid_device_ hid_device; /**< opaque hidapi structure */ | ||||
| 
 | ||||
| 		/** hidapi info structure */ | ||||
| 		struct hid_device_info { | ||||
| 			/** Platform-specific device path */ | ||||
| 			char *path; | ||||
| 			/** Device Vendor ID */ | ||||
| 			unsigned short vendor_id; | ||||
| 			/** Device Product ID */ | ||||
| 			unsigned short product_id; | ||||
| 			/** Serial Number */ | ||||
| 			wchar_t *serial_number; | ||||
| 			/** Device Release Number in binary-coded decimal,
 | ||||
| 			    also known as Device Version Number */ | ||||
| 			unsigned short release_number; | ||||
| 			/** Manufacturer String */ | ||||
| 			wchar_t *manufacturer_string; | ||||
| 			/** Product string */ | ||||
| 			wchar_t *product_string; | ||||
| 			/** Usage Page for this Device/Interface
 | ||||
| 			    (Windows/Mac only). */ | ||||
| 			unsigned short usage_page; | ||||
| 			/** Usage for this Device/Interface
 | ||||
| 			    (Windows/Mac only).*/ | ||||
| 			unsigned short usage; | ||||
| 			/** The USB interface which this logical device
 | ||||
| 			    represents. Valid on both Linux implementations | ||||
| 			    in all cases, and valid on the Windows implementation | ||||
| 			    only if the device contains more than one interface. */ | ||||
| 			int interface_number; | ||||
| 
 | ||||
| 			/** Pointer to the next device */ | ||||
| 			struct hid_device_info *next; | ||||
| 		}; | ||||
| 
 | ||||
| 
 | ||||
| 		/** @brief Initialize the HIDAPI library.
 | ||||
| 
 | ||||
| 			This function initializes the HIDAPI library. Calling it is not | ||||
| 			strictly necessary, as it will be called automatically by | ||||
| 			hid_enumerate() and any of the hid_open_*() functions if it is | ||||
| 			needed.  This function should be called at the beginning of | ||||
| 			execution however, if there is a chance of HIDAPI handles | ||||
| 			being opened by different threads simultaneously. | ||||
| 			 | ||||
| 			@ingroup API | ||||
| 
 | ||||
| 			@returns | ||||
| 				This function returns 0 on success and -1 on error. | ||||
| 		*/ | ||||
| 		int HID_API_EXPORT HID_API_CALL hid_init(void); | ||||
| 
 | ||||
| 		/** @brief Finalize the HIDAPI library.
 | ||||
| 
 | ||||
| 			This function frees all of the static data associated with | ||||
| 			HIDAPI. It should be called at the end of execution to avoid | ||||
| 			memory leaks. | ||||
| 
 | ||||
| 			@ingroup API | ||||
| 
 | ||||
| 		    @returns | ||||
| 				This function returns 0 on success and -1 on error. | ||||
| 		*/ | ||||
| 		int HID_API_EXPORT HID_API_CALL hid_exit(void); | ||||
| 
 | ||||
| 		/** @brief Enumerate the HID Devices.
 | ||||
| 
 | ||||
| 			This function returns a linked list of all the HID devices | ||||
| 			attached to the system which match vendor_id and product_id. | ||||
| 			If @p vendor_id is set to 0 then any vendor matches. | ||||
| 			If @p product_id is set to 0 then any product matches. | ||||
| 			If @p vendor_id and @p product_id are both set to 0, then | ||||
| 			all HID devices will be returned. | ||||
| 
 | ||||
| 			@ingroup API | ||||
| 			@param vendor_id The Vendor ID (VID) of the types of device | ||||
| 				to open. | ||||
| 			@param product_id The Product ID (PID) of the types of | ||||
| 				device to open. | ||||
| 
 | ||||
| 		    @returns | ||||
| 		    	This function returns a pointer to a linked list of type | ||||
| 		    	struct #hid_device, containing information about the HID devices | ||||
| 		    	attached to the system, or NULL in the case of failure. Free | ||||
| 		    	this linked list by calling hid_free_enumeration(). | ||||
| 		*/ | ||||
| 		struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id); | ||||
| 
 | ||||
| 		/** @brief Free an enumeration Linked List
 | ||||
| 
 | ||||
| 		    This function frees a linked list created by hid_enumerate(). | ||||
| 
 | ||||
| 			@ingroup API | ||||
| 		    @param devs Pointer to a list of struct_device returned from | ||||
| 		    	      hid_enumerate(). | ||||
| 		*/ | ||||
| 		void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs); | ||||
| 
 | ||||
| 		/** @brief Open a HID device using a Vendor ID (VID), Product ID
 | ||||
| 			(PID) and optionally a serial number. | ||||
| 
 | ||||
| 			If @p serial_number is NULL, the first device with the | ||||
| 			specified VID and PID is opened. | ||||
| 
 | ||||
| 			@ingroup API | ||||
| 			@param vendor_id The Vendor ID (VID) of the device to open. | ||||
| 			@param product_id The Product ID (PID) of the device to open. | ||||
| 			@param serial_number The Serial Number of the device to open | ||||
| 				               (Optionally NULL). | ||||
| 
 | ||||
| 			@returns | ||||
| 				This function returns a pointer to a #hid_device object on | ||||
| 				success or NULL on failure. | ||||
| 		*/ | ||||
| 		HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number); | ||||
| 
 | ||||
| 		/** @brief Open a HID device by its path name.
 | ||||
| 
 | ||||
| 			The path name be determined by calling hid_enumerate(), or a | ||||
| 			platform-specific path name can be used (eg: /dev/hidraw0 on | ||||
| 			Linux). | ||||
| 
 | ||||
| 			@ingroup API | ||||
| 		    @param path The path name of the device to open | ||||
| 
 | ||||
| 			@returns | ||||
| 				This function returns a pointer to a #hid_device object on | ||||
| 				success or NULL on failure. | ||||
| 		*/ | ||||
| 		HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path); | ||||
| 
 | ||||
| 		/** @brief Write an Output report to a HID device.
 | ||||
| 
 | ||||
| 			The first byte of @p data[] must contain the Report ID. For | ||||
| 			devices which only support a single report, this must be set | ||||
| 			to 0x0. The remaining bytes contain the report data. Since | ||||
| 			the Report ID is mandatory, calls to hid_write() will always | ||||
| 			contain one more byte than the report contains. For example, | ||||
| 			if a hid report is 16 bytes long, 17 bytes must be passed to | ||||
| 			hid_write(), the Report ID (or 0x0, for devices with a | ||||
| 			single report), followed by the report data (16 bytes). In | ||||
| 			this example, the length passed in would be 17. | ||||
| 
 | ||||
| 			hid_write() will send the data on the first OUT endpoint, if | ||||
| 			one exists. If it does not, it will send the data through | ||||
| 			the Control Endpoint (Endpoint 0). | ||||
| 
 | ||||
| 			@ingroup API | ||||
| 			@param device A device handle returned from hid_open(). | ||||
| 			@param data The data to send, including the report number as | ||||
| 				the first byte. | ||||
| 			@param length The length in bytes of the data to send. | ||||
| 
 | ||||
| 			@returns | ||||
| 				This function returns the actual number of bytes written and | ||||
| 				-1 on error. | ||||
| 		*/ | ||||
| 		int  HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length); | ||||
| 
 | ||||
| 		/** @brief Read an Input report from a HID device with timeout.
 | ||||
| 
 | ||||
| 			Input reports are returned | ||||
| 			to the host through the INTERRUPT IN endpoint. The first byte will | ||||
| 			contain the Report number if the device uses numbered reports. | ||||
| 
 | ||||
| 			@ingroup API | ||||
| 			@param device A device handle returned from hid_open(). | ||||
| 			@param data A buffer to put the read data into. | ||||
| 			@param length The number of bytes to read. For devices with | ||||
| 				multiple reports, make sure to read an extra byte for | ||||
| 				the report number. | ||||
| 			@param milliseconds timeout in milliseconds or -1 for blocking wait. | ||||
| 
 | ||||
| 			@returns | ||||
| 				This function returns the actual number of bytes read and | ||||
| 				-1 on error. If no packet was available to be read within | ||||
| 				the timeout period, this function returns 0. | ||||
| 		*/ | ||||
| 		int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds); | ||||
| 
 | ||||
| 		/** @brief Read an Input report from a HID device.
 | ||||
| 
 | ||||
| 			Input reports are returned | ||||
| 		    to the host through the INTERRUPT IN endpoint. The first byte will | ||||
| 			contain the Report number if the device uses numbered reports. | ||||
| 
 | ||||
| 			@ingroup API | ||||
| 			@param device A device handle returned from hid_open(). | ||||
| 			@param data A buffer to put the read data into. | ||||
| 			@param length The number of bytes to read. For devices with | ||||
| 				multiple reports, make sure to read an extra byte for | ||||
| 				the report number. | ||||
| 
 | ||||
| 			@returns | ||||
| 				This function returns the actual number of bytes read and | ||||
| 				-1 on error. If no packet was available to be read and | ||||
| 				the handle is in non-blocking mode, this function returns 0. | ||||
| 		*/ | ||||
| 		int  HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length); | ||||
| 
 | ||||
| 		/** @brief Set the device handle to be non-blocking.
 | ||||
| 
 | ||||
| 			In non-blocking mode calls to hid_read() will return | ||||
| 			immediately with a value of 0 if there is no data to be | ||||
| 			read. In blocking mode, hid_read() will wait (block) until | ||||
| 			there is data to read before returning. | ||||
| 
 | ||||
| 			Nonblocking can be turned on and off at any time. | ||||
| 
 | ||||
| 			@ingroup API | ||||
| 			@param device A device handle returned from hid_open(). | ||||
| 			@param nonblock enable or not the nonblocking reads | ||||
| 			 - 1 to enable nonblocking | ||||
| 			 - 0 to disable nonblocking. | ||||
| 
 | ||||
| 			@returns | ||||
| 				This function returns 0 on success and -1 on error. | ||||
| 		*/ | ||||
| 		int  HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock); | ||||
| 
 | ||||
| 		/** @brief Send a Feature report to the device.
 | ||||
| 
 | ||||
| 			Feature reports are sent over the Control endpoint as a | ||||
| 			Set_Report transfer.  The first byte of @p data[] must | ||||
| 			contain the Report ID. For devices which only support a | ||||
| 			single report, this must be set to 0x0. The remaining bytes | ||||
| 			contain the report data. Since the Report ID is mandatory, | ||||
| 			calls to hid_send_feature_report() will always contain one | ||||
| 			more byte than the report contains. For example, if a hid | ||||
| 			report is 16 bytes long, 17 bytes must be passed to | ||||
| 			hid_send_feature_report(): the Report ID (or 0x0, for | ||||
| 			devices which do not use numbered reports), followed by the | ||||
| 			report data (16 bytes). In this example, the length passed | ||||
| 			in would be 17. | ||||
| 
 | ||||
| 			@ingroup API | ||||
| 			@param device A device handle returned from hid_open(). | ||||
| 			@param data The data to send, including the report number as | ||||
| 				the first byte. | ||||
| 			@param length The length in bytes of the data to send, including | ||||
| 				the report number. | ||||
| 
 | ||||
| 			@returns | ||||
| 				This function returns the actual number of bytes written and | ||||
| 				-1 on error. | ||||
| 		*/ | ||||
| 		int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length); | ||||
| 
 | ||||
| 		/** @brief Get a feature report from a HID device.
 | ||||
| 
 | ||||
| 			Make sure to set the first byte of @p data[] to the Report | ||||
| 			ID of the report to be read.  Make sure to allow space for | ||||
| 			this extra byte in @p data[]. | ||||
| 
 | ||||
| 			@ingroup API | ||||
| 			@param device A device handle returned from hid_open(). | ||||
| 			@param data A buffer to put the read data into, including | ||||
| 				the Report ID. Set the first byte of @p data[] to the | ||||
| 				Report ID of the report to be read. | ||||
| 			@param length The number of bytes to read, including an | ||||
| 				extra byte for the report ID. The buffer can be longer | ||||
| 				than the actual report. | ||||
| 
 | ||||
| 			@returns | ||||
| 				This function returns the number of bytes read and | ||||
| 				-1 on error. | ||||
| 		*/ | ||||
| 		int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length); | ||||
| 
 | ||||
| 		/** @brief Close a HID device.
 | ||||
| 
 | ||||
| 			@ingroup API | ||||
| 			@param device A device handle returned from hid_open(). | ||||
| 		*/ | ||||
| 		void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device); | ||||
| 
 | ||||
| 		/** @brief Get The Manufacturer String from a HID device.
 | ||||
| 
 | ||||
| 			@ingroup API | ||||
| 			@param device A device handle returned from hid_open(). | ||||
| 			@param string A wide string buffer to put the data into. | ||||
| 			@param maxlen The length of the buffer in multiples of wchar_t. | ||||
| 
 | ||||
| 			@returns | ||||
| 				This function returns 0 on success and -1 on error. | ||||
| 		*/ | ||||
| 		int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen); | ||||
| 
 | ||||
| 		/** @brief Get The Product String from a HID device.
 | ||||
| 
 | ||||
| 			@ingroup API | ||||
| 			@param device A device handle returned from hid_open(). | ||||
| 			@param string A wide string buffer to put the data into. | ||||
| 			@param maxlen The length of the buffer in multiples of wchar_t. | ||||
| 
 | ||||
| 			@returns | ||||
| 				This function returns 0 on success and -1 on error. | ||||
| 		*/ | ||||
| 		int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen); | ||||
| 
 | ||||
| 		/** @brief Get The Serial Number String from a HID device.
 | ||||
| 
 | ||||
| 			@ingroup API | ||||
| 			@param device A device handle returned from hid_open(). | ||||
| 			@param string A wide string buffer to put the data into. | ||||
| 			@param maxlen The length of the buffer in multiples of wchar_t. | ||||
| 
 | ||||
| 			@returns | ||||
| 				This function returns 0 on success and -1 on error. | ||||
| 		*/ | ||||
| 		int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen); | ||||
| 
 | ||||
| 		/** @brief Get a string from a HID device, based on its string index.
 | ||||
| 
 | ||||
| 			@ingroup API | ||||
| 			@param device A device handle returned from hid_open(). | ||||
| 			@param string_index The index of the string to get. | ||||
| 			@param string A wide string buffer to put the data into. | ||||
| 			@param maxlen The length of the buffer in multiples of wchar_t. | ||||
| 
 | ||||
| 			@returns | ||||
| 				This function returns 0 on success and -1 on error. | ||||
| 		*/ | ||||
| 		int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen); | ||||
| 
 | ||||
| 		/** @brief Get a string describing the last error which occurred.
 | ||||
| 
 | ||||
| 			@ingroup API | ||||
| 			@param device A device handle returned from hid_open(). | ||||
| 
 | ||||
| 			@returns | ||||
| 				This function returns a string containing the last error | ||||
| 				which occurred or NULL if none has occurred. | ||||
| 		*/ | ||||
| 		HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| @ -18,7 +18,7 @@ if(LIBUSB_FOUND AND UNIX) | ||||
| 	FIND_LIBRARY (LIBASOUND asound) | ||||
| endif() | ||||
| if(LIBASOUND AND ASOUNDH) | ||||
| 	add_subdirectory(fcd) | ||||
| 	add_subdirectory(fcdpro) | ||||
| endif() | ||||
| 
 | ||||
| find_package(LibRTLSDR) | ||||
|  | ||||
| @ -25,7 +25,7 @@ include_directories( | ||||
| 	${CMAKE_CURRENT_BINARY_DIR} | ||||
| 	${CMAKE_SOURCE_DIR}/include | ||||
| 	${CMAKE_SOURCE_DIR}/include-gpl | ||||
| 	${LIBRTLSDR_INCLUDE_DIR} | ||||
| 	${LIBBLADERF_INCLUDE_DIR} | ||||
| ) | ||||
| 
 | ||||
| #include(${QT_USE_FILE}) | ||||
|  | ||||
| @ -171,7 +171,7 @@ const QString& FCDInput::getDeviceDescription() const | ||||
| 
 | ||||
| int FCDInput::getSampleRate() const | ||||
| { | ||||
| 	return 96000; | ||||
| 	return 192000; | ||||
| } | ||||
| 
 | ||||
| quint64 FCDInput::getCenterFrequency() const | ||||
| @ -220,7 +220,7 @@ void FCDInput::applySettings(const Settings& settings, bool force) | ||||
|      | ||||
|     if (signalChange) | ||||
|     { | ||||
| 		DSPSignalNotification *notif = new DSPSignalNotification(96000, m_settings.centerFrequency); | ||||
| 		DSPSignalNotification *notif = new DSPSignalNotification(192000, m_settings.centerFrequency); | ||||
| 		getOutputMessageQueue()->push(notif);         | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -42,7 +42,7 @@ void FCDThread::stopWork() | ||||
| 
 | ||||
| void FCDThread::run() | ||||
| { | ||||
| 	if ( !OpenSource("hw:CARD=V10") ) // FIXME: original is V10 pro is V20. Make it an option
 | ||||
| 	if ( !OpenSource("hw:CARD=V20") ) // FIXME: pro is V10 pro+ is V20. Make it an option
 | ||||
|                 return; | ||||
| 	// TODO: fallback to original fcd
 | ||||
| 
 | ||||
| @ -70,6 +70,7 @@ bool FCDThread::OpenSource(const char* cardname) | ||||
| 
 | ||||
| 	if (snd_pcm_open(&fcd_handle, cardname, fcd_stream, 0) < 0) | ||||
| 	{ | ||||
| 		qCritical("FCDThread::OpenSource: cannot open %s", cardname); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| @ -77,10 +78,12 @@ bool FCDThread::OpenSource(const char* cardname) | ||||
| 
 | ||||
| 	if (snd_pcm_hw_params_any(fcd_handle, params) < 0) | ||||
| 	{ | ||||
| 		qCritical("FCDThread::OpenSource: snd_pcm_hw_params_any failed"); | ||||
| 		fail = true; | ||||
| 	} | ||||
| 	else if (snd_pcm_hw_params(fcd_handle, params) < 0) | ||||
| 	{ | ||||
| 		qCritical("FCDThread::OpenSource: snd_pcm_hw_params failed"); | ||||
| 		fail = true; | ||||
| 		// TODO: check actual samplerate, may be crippled firmware
 | ||||
| 	} | ||||
| @ -88,6 +91,7 @@ bool FCDThread::OpenSource(const char* cardname) | ||||
| 	{ | ||||
| 		if (snd_pcm_start(fcd_handle) < 0) | ||||
| 		{ | ||||
| 			qCritical("FCDThread::OpenSource: snd_pcm_start failed"); | ||||
| 			fail = true; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -34,7 +34,7 @@ | ||||
| typedef bool BOOL; | ||||
| 
 | ||||
| 
 | ||||
| //#define FCDPP // FIXME: the Pro / Pro+ switch should be handled better than this!
 | ||||
| #define FCDPP // FIXME: the Pro / Pro+ switch should be handled better than this!
 | ||||
| const unsigned short _usVID=0x04D8;  /*!< USB vendor ID. */ | ||||
| #ifdef FCDPP | ||||
| const unsigned short _usPID=0xFB31;  /*!< USB product ID. */ | ||||
|  | ||||
							
								
								
									
										53
									
								
								plugins/samplesource/fcdpro/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								plugins/samplesource/fcdpro/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| project(fcdpro) | ||||
| 
 | ||||
| set(fcdpro_SOURCES | ||||
| 	fcdgui.cpp | ||||
| 	fcdinput.cpp | ||||
| 	fcdplugin.cpp | ||||
| 	fcdserializer.cpp | ||||
| 	fcdthread.cpp | ||||
| ) | ||||
| 
 | ||||
| set(fcdpro_HEADERS | ||||
| 	fcdgui.h | ||||
| 	fcdinput.h | ||||
| 	fcdplugin.h | ||||
| 	fcdserializer.h | ||||
| 	fcdthread.h | ||||
| ) | ||||
| 
 | ||||
| set(fcdpro_FORMS | ||||
| 	fcdgui.ui | ||||
| ) | ||||
| 
 | ||||
| include_directories( | ||||
| 	. | ||||
| 	${CMAKE_CURRENT_BINARY_DIR} | ||||
| 	${CMAKE_SOURCE_DIR}/include | ||||
| 	${CMAKE_SOURCE_DIR}/include-gpl | ||||
| 	${CMAKE_SOURCE_DIR}/fcdhid | ||||
| ) | ||||
| 
 | ||||
| #include(${QT_USE_FILE}) | ||||
| add_definitions(${QT_DEFINITIONS}) | ||||
| add_definitions(-DQT_PLUGIN) | ||||
| add_definitions(-DQT_SHARED) | ||||
| 
 | ||||
| #qt4_wrap_cpp(fcdpro_HEADERS_MOC ${fcdpro_HEADERS}) | ||||
| qt5_wrap_ui(fcdpro_FORMS_HEADERS ${fcdpro_FORMS}) | ||||
| 
 | ||||
| add_library(inputfcdpro SHARED | ||||
| 	${fcdpro_SOURCES} | ||||
| 	${fcdpro_HEADERS_MOC} | ||||
| 	${fcdpro_FORMS_HEADERS} | ||||
| ) | ||||
| 
 | ||||
| target_link_libraries(inputfcdpro | ||||
| 	${QT_LIBRARIES} | ||||
| 	${LIBUSB_LIBRARIES} | ||||
| 	asound | ||||
| 	fcdhid | ||||
| 	sdrbase | ||||
| ) | ||||
| 
 | ||||
| qt5_use_modules(inputfcdpro Core Widgets OpenGL Multimedia) | ||||
							
								
								
									
										149
									
								
								plugins/samplesource/fcdpro/fcdgui.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								plugins/samplesource/fcdpro/fcdgui.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,149 @@ | ||||
| #include "fcdgui.h" | ||||
| #include "ui_fcdgui.h" | ||||
| #include "plugin/pluginapi.h" | ||||
| #include "gui/colormapper.h" | ||||
| #include "dsp/dspengine.h" | ||||
| 
 | ||||
| FCDGui::FCDGui(PluginAPI* pluginAPI, QWidget* parent) : | ||||
| 	QWidget(parent), | ||||
| 	ui(new Ui::FCDGui), | ||||
| 	m_pluginAPI(pluginAPI), | ||||
| 	m_settings(), | ||||
| 	m_sampleSource(NULL) | ||||
| { | ||||
| 	ui->setupUi(this); | ||||
| 	ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold)); | ||||
| 	ui->centerFrequency->setValueRange(7, 64000U, 1700000U); | ||||
| 	connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); | ||||
| 	displaySettings(); | ||||
| 
 | ||||
| 	m_sampleSource = new FCDInput(); | ||||
| 	DSPEngine::instance()->setSource(m_sampleSource); | ||||
| } | ||||
| 
 | ||||
| FCDGui::~FCDGui() | ||||
| { | ||||
| 	delete ui; | ||||
| } | ||||
| 
 | ||||
| void FCDGui::destroy() | ||||
| { | ||||
| 	delete this; | ||||
| } | ||||
| 
 | ||||
| void FCDGui::setName(const QString& name) | ||||
| { | ||||
| 	setObjectName(name); | ||||
| } | ||||
| 
 | ||||
| QString FCDGui::getName() const | ||||
| { | ||||
| 	return objectName(); | ||||
| } | ||||
| 
 | ||||
| void FCDGui::resetToDefaults() | ||||
| { | ||||
| 	m_settings.resetToDefaults(); | ||||
| 	displaySettings(); | ||||
| 	sendSettings(); | ||||
| } | ||||
| 
 | ||||
| QByteArray FCDGui::serialize() const | ||||
| { | ||||
| 	return m_settings.serialize(); | ||||
| } | ||||
| 
 | ||||
| bool FCDGui::deserialize(const QByteArray& data) | ||||
| { | ||||
| 	if(m_settings.deserialize(data)) | ||||
| 	{ | ||||
| 		displaySettings(); | ||||
| 		sendSettings(); | ||||
| 		return true; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		resetToDefaults(); | ||||
| 		return false; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| bool FCDGui::handleMessage(const Message& message) | ||||
| { | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| void FCDGui::displaySettings() | ||||
| { | ||||
| 	ui->centerFrequency->setValue(m_settings.centerFrequency / 1000); | ||||
| 	ui->checkBoxR->setChecked(m_settings.range); | ||||
| 	ui->checkBoxG->setChecked(m_settings.gain); | ||||
| 	ui->checkBoxB->setChecked(m_settings.bias); | ||||
| } | ||||
| 
 | ||||
| void FCDGui::sendSettings() | ||||
| { | ||||
| 	if(!m_updateTimer.isActive()) | ||||
| 		m_updateTimer.start(100); | ||||
| } | ||||
| 
 | ||||
| void FCDGui::on_centerFrequency_changed(quint64 value) | ||||
| { | ||||
| 	m_settings.centerFrequency = value * 1000; | ||||
| 	sendSettings(); | ||||
| } | ||||
| 
 | ||||
| void FCDGui::updateHardware() | ||||
| { | ||||
| 	FCDInput::MsgConfigureFCD* message = FCDInput::MsgConfigureFCD::create(m_settings); | ||||
| 	m_sampleSource->getInputMessageQueue()->push(message); | ||||
| 	m_updateTimer.stop(); | ||||
| } | ||||
| 
 | ||||
| void FCDGui::on_checkBoxR_stateChanged(int state) | ||||
| { | ||||
| 	if (state == Qt::Checked) // FIXME: this is for the Pro+ version only!
 | ||||
| 	{ | ||||
| 		ui->centerFrequency->setValueRange(7, 150U, 240000U); | ||||
| 		ui->centerFrequency->setValue(7000); | ||||
| 		m_settings.centerFrequency = 7000 * 1000; | ||||
| 		m_settings.range = 1; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		ui->centerFrequency->setValueRange(7, 64000U, 1900000U); | ||||
| 		ui->centerFrequency->setValue(435000); | ||||
| 		m_settings.centerFrequency = 435000 * 1000; | ||||
| 		m_settings.range = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	sendSettings(); | ||||
| } | ||||
| 
 | ||||
| void FCDGui::on_checkBoxG_stateChanged(int state) | ||||
| { | ||||
| 	if (state == Qt::Checked) | ||||
| 	{ | ||||
| 		m_settings.gain = 1; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		m_settings.gain = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	sendSettings(); | ||||
| } | ||||
| 
 | ||||
| void FCDGui::on_checkBoxB_stateChanged(int state) | ||||
| { | ||||
| 	if (state == Qt::Checked) | ||||
| 	{ | ||||
| 		m_settings.bias = 1; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		m_settings.bias = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	sendSettings(); | ||||
| } | ||||
							
								
								
									
										51
									
								
								plugins/samplesource/fcdpro/fcdgui.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								plugins/samplesource/fcdpro/fcdgui.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| #ifndef INCLUDE_FCDGUI_H | ||||
| #define INCLUDE_FCDGUI_H | ||||
| 
 | ||||
| #include <QTimer> | ||||
| #include "plugin/plugingui.h" | ||||
| #include "fcdinput.h" | ||||
| 
 | ||||
| class PluginAPI; | ||||
| 
 | ||||
| namespace Ui { | ||||
| 	class FCDGui; | ||||
| } | ||||
| 
 | ||||
| class FCDGui : public QWidget, public PluginGUI { | ||||
| 	Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
| 	explicit FCDGui(PluginAPI* pluginAPI, QWidget* parent = NULL); | ||||
| 	virtual ~FCDGui(); | ||||
| 	void destroy(); | ||||
| 
 | ||||
| 	void setName(const QString& name); | ||||
| 	QString getName() const; | ||||
| 
 | ||||
| 	void resetToDefaults(); | ||||
| 	QByteArray serialize() const; | ||||
| 	bool deserialize(const QByteArray& data); | ||||
| 
 | ||||
| 	virtual bool handleMessage(const Message& message); | ||||
| 
 | ||||
| private: | ||||
| 	Ui::FCDGui* ui; | ||||
| 
 | ||||
| 	PluginAPI* m_pluginAPI; | ||||
| 	FCDInput::Settings m_settings; | ||||
| 	QTimer m_updateTimer; | ||||
| 	std::vector<int> m_gains; | ||||
| 	SampleSource* m_sampleSource; | ||||
| 
 | ||||
| 	void displaySettings(); | ||||
| 	void sendSettings(); | ||||
| 
 | ||||
| private slots: | ||||
| 	void on_centerFrequency_changed(quint64 value); | ||||
| 	void on_checkBoxR_stateChanged(int state); | ||||
| 	void on_checkBoxG_stateChanged(int state); | ||||
| 	void on_checkBoxB_stateChanged(int state); | ||||
| 	void updateHardware(); | ||||
| }; | ||||
| 
 | ||||
| #endif // INCLUDE_FCDGUI_H
 | ||||
							
								
								
									
										144
									
								
								plugins/samplesource/fcdpro/fcdgui.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								plugins/samplesource/fcdpro/fcdgui.ui
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,144 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <ui version="4.0"> | ||||
|  <class>FCDGui</class> | ||||
|  <widget class="QWidget" name="FCDGui"> | ||||
|   <property name="geometry"> | ||||
|    <rect> | ||||
|     <x>0</x> | ||||
|     <y>0</y> | ||||
|     <width>132</width> | ||||
|     <height>119</height> | ||||
|    </rect> | ||||
|   </property> | ||||
|   <property name="sizePolicy"> | ||||
|    <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> | ||||
|     <horstretch>0</horstretch> | ||||
|     <verstretch>0</verstretch> | ||||
|    </sizepolicy> | ||||
|   </property> | ||||
|   <property name="windowTitle"> | ||||
|    <string>FunCubeDongle</string> | ||||
|   </property> | ||||
|   <layout class="QVBoxLayout" name="verticalLayout"> | ||||
|    <property name="spacing"> | ||||
|     <number>3</number> | ||||
|    </property> | ||||
|    <property name="leftMargin"> | ||||
|     <number>2</number> | ||||
|    </property> | ||||
|    <property name="topMargin"> | ||||
|     <number>2</number> | ||||
|    </property> | ||||
|    <property name="rightMargin"> | ||||
|     <number>2</number> | ||||
|    </property> | ||||
|    <property name="bottomMargin"> | ||||
|     <number>2</number> | ||||
|    </property> | ||||
|    <item> | ||||
|     <layout class="QHBoxLayout" name="horizontalLayout_3"> | ||||
|      <item> | ||||
|       <spacer name="horizontalSpacer"> | ||||
|        <property name="orientation"> | ||||
|         <enum>Qt::Horizontal</enum> | ||||
|        </property> | ||||
|        <property name="sizeHint" stdset="0"> | ||||
|         <size> | ||||
|          <width>0</width> | ||||
|          <height>0</height> | ||||
|         </size> | ||||
|        </property> | ||||
|       </spacer> | ||||
|      </item> | ||||
|      <item> | ||||
|       <widget class="ValueDial" name="centerFrequency" native="true"> | ||||
|        <property name="sizePolicy"> | ||||
|         <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> | ||||
|          <horstretch>0</horstretch> | ||||
|          <verstretch>0</verstretch> | ||||
|         </sizepolicy> | ||||
|        </property> | ||||
|        <property name="minimumSize"> | ||||
|         <size> | ||||
|          <width>32</width> | ||||
|          <height>16</height> | ||||
|         </size> | ||||
|        </property> | ||||
|        <property name="font"> | ||||
|         <font> | ||||
|          <family>Monospace</family> | ||||
|          <pointsize>20</pointsize> | ||||
|         </font> | ||||
|        </property> | ||||
|        <property name="focusPolicy"> | ||||
|         <enum>Qt::StrongFocus</enum> | ||||
|        </property> | ||||
|        <property name="toolTip"> | ||||
|         <string>Tuner center frequency in kHz</string> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|      <item> | ||||
|       <spacer name="horizontalSpacer_2"> | ||||
|        <property name="orientation"> | ||||
|         <enum>Qt::Horizontal</enum> | ||||
|        </property> | ||||
|        <property name="sizeHint" stdset="0"> | ||||
|         <size> | ||||
|          <width>0</width> | ||||
|          <height>0</height> | ||||
|         </size> | ||||
|        </property> | ||||
|       </spacer> | ||||
|      </item> | ||||
|     </layout> | ||||
|    </item> | ||||
|    <item> | ||||
|     <widget class="Line" name="line_4"> | ||||
|      <property name="orientation"> | ||||
|       <enum>Qt::Horizontal</enum> | ||||
|      </property> | ||||
|     </widget> | ||||
|    </item> | ||||
|    <item> | ||||
|     <layout class="QHBoxLayout" name="horizontalLayoutR"> | ||||
|      <item> | ||||
|       <widget class="QCheckBox" name="checkBoxR"> | ||||
|        <property name="text"> | ||||
|         <string>Low Range</string> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|     </layout> | ||||
|    </item> | ||||
|    <item> | ||||
|     <layout class="QHBoxLayout" name="horizontalLayoutG"> | ||||
|      <item> | ||||
|       <widget class="QCheckBox" name="checkBoxG"> | ||||
|        <property name="text"> | ||||
|         <string>LNA Gain</string> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|      <item> | ||||
|       <widget class="QCheckBox" name="checkBoxB"> | ||||
|        <property name="text"> | ||||
|         <string>Bias T</string> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|     </layout> | ||||
|    </item> | ||||
|   </layout> | ||||
|  </widget> | ||||
|  <customwidgets> | ||||
|   <customwidget> | ||||
|    <class>ValueDial</class> | ||||
|    <extends>QWidget</extends> | ||||
|    <header>gui/valuedial.h</header> | ||||
|    <container>1</container> | ||||
|   </customwidget> | ||||
|  </customwidgets> | ||||
|  <resources/> | ||||
|  <connections/> | ||||
| </ui> | ||||
							
								
								
									
										286
									
								
								plugins/samplesource/fcdpro/fcdinput.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								plugins/samplesource/fcdpro/fcdinput.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,286 @@ | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
 | ||||
| // written by Christian Daniel                                                   //
 | ||||
| //                                                                               //
 | ||||
| // This program is free software; you can redistribute it and/or modify          //
 | ||||
| // it under the terms of the GNU General Public License as published by          //
 | ||||
| // the Free Software Foundation as version 3 of the License, or                  //
 | ||||
| //                                                                               //
 | ||||
| // This program is distributed in the hope that it will be useful,               //
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | ||||
| // GNU General Public License V3 for more details.                               //
 | ||||
| //                                                                               //
 | ||||
| // You should have received a copy of the GNU General Public License             //
 | ||||
| // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| // FIXME: FCD is handled very badly!
 | ||||
| 
 | ||||
| #include <QDebug> | ||||
| #include <string.h> | ||||
| #include <errno.h> | ||||
| #include "fcdinput.h" | ||||
| #include "fcdthread.h" | ||||
| #include "fcdgui.h" | ||||
| #include "dsp/dspcommands.h" | ||||
| #include "fcdserializer.h" | ||||
| 
 | ||||
| MESSAGE_CLASS_DEFINITION(FCDInput::MsgConfigureFCD, Message) | ||||
| //MESSAGE_CLASS_DEFINITION(FCDInput::MsgReportFCD, Message)
 | ||||
| 
 | ||||
| const uint16_t FCDInput::m_vendorId  = 0x04D8; | ||||
| 
 | ||||
| const uint16_t FCDInput::m_productId = 0xFB31; | ||||
| const int FCDInput::m_sampleRate = 192000; | ||||
| const std::string FCDInput::m_deviceName("hw:CARD=V20"); | ||||
| 
 | ||||
| //const uint16_t FCDInput::m_productId = 0xFB56;
 | ||||
| //const int FCDInput::m_sampleRate = 96000;
 | ||||
| //const std::string FCDInput::m_deviceName("hw:CARD=V10");
 | ||||
| 
 | ||||
| FCDInput::Settings::Settings() : | ||||
| 	centerFrequency(435000000), | ||||
| 	range(0), | ||||
| 	gain(0), | ||||
| 	bias(0) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| void FCDInput::Settings::resetToDefaults() | ||||
| { | ||||
| 	centerFrequency = 435000000; | ||||
| 	range = 0; | ||||
| 	gain = 0; | ||||
| 	bias = 0; | ||||
| } | ||||
| 
 | ||||
| QByteArray FCDInput::Settings::serialize() const | ||||
| { | ||||
| 	FCDSerializer::FCDData data; | ||||
| 
 | ||||
| 	data.m_data.m_lnaGain = gain; | ||||
| 	data.m_data.m_frequency = centerFrequency; | ||||
| 	data.m_range = range; | ||||
| 	data.m_bias = bias; | ||||
| 
 | ||||
| 	QByteArray byteArray; | ||||
| 
 | ||||
| 	FCDSerializer::writeSerializedData(data, byteArray); | ||||
| 
 | ||||
| 	return byteArray; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	SimpleSerializer s(1); | ||||
| 	s.writeU64(1, centerFrequency); | ||||
| 	s.writeS32(2, range); | ||||
| 	s.writeS32(3, gain); | ||||
| 	s.writeS32(4, bias); | ||||
| 	return s.final();*/ | ||||
| } | ||||
| 
 | ||||
| bool FCDInput::Settings::deserialize(const QByteArray& serializedData) | ||||
| { | ||||
| 	FCDSerializer::FCDData data; | ||||
| 
 | ||||
| 	bool valid = FCDSerializer::readSerializedData(serializedData, data); | ||||
| 
 | ||||
| 	gain = data.m_data.m_lnaGain; | ||||
| 	centerFrequency = data.m_data.m_frequency; | ||||
| 	range = data.m_range; | ||||
| 	bias = data.m_bias; | ||||
| 
 | ||||
| 	return valid; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	SimpleDeserializer d(data); | ||||
| 
 | ||||
| 	if (d.isValid() && d.getVersion() == 1) | ||||
| 	{ | ||||
| 		d.readU64(1, ¢erFrequency, 435000000); | ||||
|         d.readS32(2, &range, 0); | ||||
| 		d.readS32(3, &gain, 0); | ||||
| 		d.readS32(4, &bias, 0); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	resetToDefaults(); | ||||
| 	return true;*/ | ||||
| } | ||||
| 
 | ||||
| FCDInput::FCDInput() : | ||||
| 	m_dev(0), | ||||
| 	m_settings(), | ||||
| 	m_FCDThread(0), | ||||
| 	m_deviceDescription() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| FCDInput::~FCDInput() | ||||
| { | ||||
| 	stop(); | ||||
| } | ||||
| 
 | ||||
| bool FCDInput::init(const Message& cmd) | ||||
| { | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| bool FCDInput::start(int device) | ||||
| { | ||||
| 	qDebug() << "FCDInput::start with device #" << device; | ||||
| 
 | ||||
| 	QMutexLocker mutexLocker(&m_mutex); | ||||
| 
 | ||||
| 	if (m_FCDThread) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	m_dev = fcdOpen(m_vendorId, m_productId, device); | ||||
| 
 | ||||
| 	if (m_dev == 0) | ||||
| 	{ | ||||
| 		qCritical("FCDInput::start: could not open FCD"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Apply settings before streaming to avoid bus contention;
 | ||||
| 	 * there is very little spare bandwidth on a full speed USB device. | ||||
| 	 * Failure is harmless if no device is found */ | ||||
| 
 | ||||
| 	applySettings(m_settings, true); | ||||
| 
 | ||||
| 	if(!m_sampleFifo.setSize(96000*4)) | ||||
| 	{ | ||||
| 		qCritical("Could not allocate SampleFifo"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if ((m_FCDThread = new FCDThread(&m_sampleFifo)) == NULL) | ||||
| 	{ | ||||
| 		qFatal("out of memory"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	m_deviceDescription = QString("Funcube Dongle"); | ||||
| 
 | ||||
| 	qDebug("FCDInput::started"); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void FCDInput::stop() | ||||
| { | ||||
| 	QMutexLocker mutexLocker(&m_mutex); | ||||
| 
 | ||||
| 	if (m_FCDThread) | ||||
| 	{ | ||||
| 		m_FCDThread->stopWork(); | ||||
| 		// wait for thread to quit ?
 | ||||
| 		delete m_FCDThread; | ||||
| 		m_FCDThread = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	fcdClose(m_dev); | ||||
| 	m_dev = 0; | ||||
| 
 | ||||
| 	m_deviceDescription.clear(); | ||||
| } | ||||
| 
 | ||||
| const QString& FCDInput::getDeviceDescription() const | ||||
| { | ||||
| 	return m_deviceDescription; | ||||
| } | ||||
| 
 | ||||
| int FCDInput::getSampleRate() const | ||||
| { | ||||
| 	return m_sampleRate; | ||||
| } | ||||
| 
 | ||||
| quint64 FCDInput::getCenterFrequency() const | ||||
| { | ||||
| 	return m_settings.centerFrequency; | ||||
| } | ||||
| 
 | ||||
| bool FCDInput::handleMessage(const Message& message) | ||||
| { | ||||
| 	if(MsgConfigureFCD::match(message)) | ||||
| 	{ | ||||
| 		qDebug() << "FCDInput::handleMessage: MsgConfigureFCD"; | ||||
| 		MsgConfigureFCD& conf = (MsgConfigureFCD&) message; | ||||
| 		applySettings(conf.getSettings(), false); | ||||
| 		return true; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void FCDInput::applySettings(const Settings& settings, bool force) | ||||
| { | ||||
| 	bool signalChange = false; | ||||
| 
 | ||||
| 	if ((m_settings.centerFrequency != settings.centerFrequency)) | ||||
| 	{ | ||||
| 		qDebug() << "FCDInput::applySettings: fc: " << settings.centerFrequency; | ||||
| 		m_settings.centerFrequency = settings.centerFrequency; | ||||
| 
 | ||||
| 		if (m_dev != 0) | ||||
| 		{ | ||||
| 			set_center_freq((double) m_settings.centerFrequency); | ||||
| 		} | ||||
| 
 | ||||
| 		signalChange = true; | ||||
| 	} | ||||
| 
 | ||||
| 	if ((m_settings.gain != settings.gain) || force) | ||||
| 	{ | ||||
| 		m_settings.gain = settings.gain; | ||||
| 
 | ||||
| 		if (m_dev != 0) | ||||
| 		{ | ||||
| 			set_lna_gain(settings.gain > 0); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if ((m_settings.bias != settings.bias) || force) | ||||
| 	{ | ||||
| 		m_settings.bias = settings.bias; | ||||
| 
 | ||||
| 		if (m_dev != 0) | ||||
| 		{ | ||||
| 			set_bias_t(settings.bias > 0); | ||||
| 		} | ||||
| 	} | ||||
|      | ||||
|     if (signalChange) | ||||
|     { | ||||
| 		DSPSignalNotification *notif = new DSPSignalNotification(m_sampleRate, m_settings.centerFrequency); | ||||
| 		getOutputMessageQueue()->push(notif);         | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void FCDInput::set_center_freq(double freq) | ||||
| { | ||||
| 	if (fcdAppSetFreq(m_dev, freq) == FCD_MODE_NONE) | ||||
| 	{ | ||||
| 		qDebug("No FCD HID found for frquency change"); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void FCDInput::set_bias_t(bool on) | ||||
| { | ||||
| 	quint8 cmd = on ? 1 : 0; | ||||
| 
 | ||||
| 	fcdAppSetParam(m_dev, FCD_CMD_APP_SET_BIAS_TEE, &cmd, 1); | ||||
| } | ||||
| 
 | ||||
| void FCDInput::set_lna_gain(bool on) | ||||
| { | ||||
| 	quint8 cmd = on ? 1 : 0; | ||||
| 
 | ||||
| 	fcdAppSetParam(m_dev, FCD_CMD_APP_SET_LNA_GAIN, &cmd, 1); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										98
									
								
								plugins/samplesource/fcdpro/fcdinput.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								plugins/samplesource/fcdpro/fcdinput.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,98 @@ | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
 | ||||
| // written by Christian Daniel                                                   //
 | ||||
| //                                                                               //
 | ||||
| // This program is free software; you can redistribute it and/or modify          //
 | ||||
| // it under the terms of the GNU General Public License as published by          //
 | ||||
| // the Free Software Foundation as version 3 of the License, or                  //
 | ||||
| //                                                                               //
 | ||||
| // This program is distributed in the hope that it will be useful,               //
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | ||||
| // GNU General Public License V3 for more details.                               //
 | ||||
| //                                                                               //
 | ||||
| // You should have received a copy of the GNU General Public License             //
 | ||||
| // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #ifndef INCLUDE_FCDINPUT_H | ||||
| #define INCLUDE_FCDINPUT_H | ||||
| 
 | ||||
| #include "dsp/samplesource.h" | ||||
| #include "fcdhid.h" | ||||
| #include <QString> | ||||
| #include <inttypes.h> | ||||
| 
 | ||||
| struct fcd_buffer { | ||||
| 	void *start; | ||||
| 	std::size_t length; | ||||
| }; | ||||
| 
 | ||||
| class FCDThread; | ||||
| 
 | ||||
| class FCDInput : public SampleSource { | ||||
| public: | ||||
| 	struct Settings { | ||||
| 		Settings(); | ||||
| 		quint64 centerFrequency; | ||||
| 		qint32 range; | ||||
| 		qint32 gain; | ||||
| 		qint32 bias; | ||||
| 		void resetToDefaults(); | ||||
| 		QByteArray serialize() const; | ||||
| 		bool deserialize(const QByteArray& data); | ||||
| 	}; | ||||
| 
 | ||||
| 	class MsgConfigureFCD : public Message { | ||||
| 		MESSAGE_CLASS_DECLARATION | ||||
| 
 | ||||
| 	public: | ||||
| 		const Settings& getSettings() const { return m_settings; } | ||||
| 
 | ||||
| 		static MsgConfigureFCD* create(const Settings& settings) | ||||
| 		{ | ||||
| 			return new MsgConfigureFCD(settings); | ||||
| 		} | ||||
| 
 | ||||
| 	private: | ||||
| 		Settings m_settings; | ||||
| 
 | ||||
| 		MsgConfigureFCD(const Settings& settings) : | ||||
| 			Message(), | ||||
| 			m_settings(settings) | ||||
| 		{ } | ||||
| 	}; | ||||
| 
 | ||||
| 	FCDInput(); | ||||
| 	virtual ~FCDInput(); | ||||
| 
 | ||||
| 	virtual bool init(const Message& cmd); | ||||
| 	virtual bool start(int device); | ||||
| 	virtual void stop(); | ||||
| 
 | ||||
| 	virtual const QString& getDeviceDescription() const; | ||||
| 	virtual int getSampleRate() const; | ||||
| 	virtual quint64 getCenterFrequency() const; | ||||
| 
 | ||||
| 	virtual bool handleMessage(const Message& message); | ||||
| 
 | ||||
| 	void set_center_freq(double freq); | ||||
| 	void set_bias_t(bool on); | ||||
| 	void set_lna_gain(bool on); | ||||
| 
 | ||||
| 	static const uint16_t m_vendorId;  //!< USB vendor ID.
 | ||||
| 	static const uint16_t m_productId; //!< USB product ID.
 | ||||
| 	static const int m_sampleRate; | ||||
| 	static const std::string m_deviceName; | ||||
| 
 | ||||
| private: | ||||
| 	void applySettings(const Settings& settings, bool force); | ||||
| 
 | ||||
| 	hid_device *m_dev; | ||||
| 	QMutex m_mutex; | ||||
| 	Settings m_settings; | ||||
| 	FCDThread* m_FCDThread; | ||||
| 	QString m_deviceDescription; | ||||
| }; | ||||
| 
 | ||||
| #endif // INCLUDE_FCD_H
 | ||||
							
								
								
									
										71
									
								
								plugins/samplesource/fcdpro/fcdplugin.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								plugins/samplesource/fcdpro/fcdplugin.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Copyright (C) 2015 Edouard Griffiths, F4EXB                                   //
 | ||||
| //                                                                               //
 | ||||
| // This program is free software; you can redistribute it and/or modify          //
 | ||||
| // it under the terms of the GNU General Public License as published by          //
 | ||||
| // the Free Software Foundation as version 3 of the License, or                  //
 | ||||
| //                                                                               //
 | ||||
| // This program is distributed in the hope that it will be useful,               //
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | ||||
| // GNU General Public License V3 for more details.                               //
 | ||||
| //                                                                               //
 | ||||
| // You should have received a copy of the GNU General Public License             //
 | ||||
| // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #include <QtPlugin> | ||||
| #include <QAction> | ||||
| #include "plugin/pluginapi.h" | ||||
| #include "util/simpleserializer.h" | ||||
| #include "fcdplugin.h" | ||||
| #include "fcdgui.h" | ||||
| 
 | ||||
| const PluginDescriptor FCDPlugin::m_pluginDescriptor = { | ||||
| 	QString("FunCube Pro Input"), | ||||
| 	QString("---"), | ||||
| 	QString("(c) Edouard Griffiths, F4EXB"), | ||||
| 	QString("https://github.com/f4exb/sdrangel"), | ||||
| 	true, | ||||
| 	QString("https://github.com/f4exb/sdrangel") | ||||
| }; | ||||
| 
 | ||||
| FCDPlugin::FCDPlugin(QObject* parent) : | ||||
| 	QObject(parent) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| const PluginDescriptor& FCDPlugin::getPluginDescriptor() const | ||||
| { | ||||
| 	return m_pluginDescriptor; | ||||
| } | ||||
| 
 | ||||
| void FCDPlugin::initPlugin(PluginAPI* pluginAPI) | ||||
| { | ||||
| 	m_pluginAPI = pluginAPI; | ||||
| 
 | ||||
| 	m_pluginAPI->registerSampleSource("org.osmocom.sdr.samplesource.fcdpro", this); | ||||
| } | ||||
| 
 | ||||
| PluginInterface::SampleSourceDevices FCDPlugin::enumSampleSources() | ||||
| { | ||||
| 	SampleSourceDevices result; | ||||
| 
 | ||||
| 	QString displayedName(QString("Funcube Dongle Pro #1")); | ||||
| 	SimpleSerializer s(1); | ||||
| 	s.writeS32(1, 0); | ||||
| 	result.append(SampleSourceDevice(displayedName, "org.osmocom.sdr.samplesource.fcdpro", s.final())); | ||||
| 
 | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| PluginGUI* FCDPlugin::createSampleSourcePluginGUI(const QString& sourceName, const QByteArray& address) | ||||
| { | ||||
| 	if(sourceName == "org.osmocom.sdr.samplesource.fcdpro") { | ||||
| 		FCDGui* gui = new FCDGui(m_pluginAPI); | ||||
| 		m_pluginAPI->setInputGUI(gui); | ||||
| 		return gui; | ||||
| 	} else { | ||||
| 		return NULL; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										27
									
								
								plugins/samplesource/fcdpro/fcdplugin.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								plugins/samplesource/fcdpro/fcdplugin.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| #ifndef INCLUDE_FCDPLUGIN_H | ||||
| #define INCLUDE_FCDPLUGIN_H | ||||
| 
 | ||||
| #include <QObject> | ||||
| #include "plugin/plugininterface.h" | ||||
| 
 | ||||
| class FCDPlugin : public QObject, public PluginInterface { | ||||
| 	Q_OBJECT | ||||
| 	Q_INTERFACES(PluginInterface) | ||||
| 	Q_PLUGIN_METADATA(IID "org.osmocom.sdr.samplesource.fcdpro") | ||||
| 
 | ||||
| public: | ||||
| 	explicit FCDPlugin(QObject* parent = NULL); | ||||
| 
 | ||||
| 	const PluginDescriptor& getPluginDescriptor() const; | ||||
| 	void initPlugin(PluginAPI* pluginAPI); | ||||
| 
 | ||||
| 	SampleSourceDevices enumSampleSources(); | ||||
| 	PluginGUI* createSampleSourcePluginGUI(const QString& sourceName, const QByteArray& address); | ||||
| 
 | ||||
| private: | ||||
| 	static const PluginDescriptor m_pluginDescriptor; | ||||
| 
 | ||||
| 	PluginAPI* m_pluginAPI; | ||||
| }; | ||||
| 
 | ||||
| #endif // INCLUDE_FCDPLUGIN_H
 | ||||
							
								
								
									
										68
									
								
								plugins/samplesource/fcdpro/fcdserializer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								plugins/samplesource/fcdpro/fcdserializer.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,68 @@ | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Copyright (C) 2015 Edouard Griffiths, F4EXB                                   //
 | ||||
| //                                                                               //
 | ||||
| // This program is free software; you can redistribute it and/or modify          //
 | ||||
| // it under the terms of the GNU General Public License as published by          //
 | ||||
| // the Free Software Foundation as version 3 of the License, or                  //
 | ||||
| //                                                                               //
 | ||||
| // This program is distributed in the hope that it will be useful,               //
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | ||||
| // GNU General Public License V3 for more details.                               //
 | ||||
| //                                                                               //
 | ||||
| // You should have received a copy of the GNU General Public License             //
 | ||||
| // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #include "fcdserializer.h" | ||||
| 
 | ||||
| void FCDSerializer::writeSerializedData(const FCDData& data, QByteArray& serializedData) | ||||
| { | ||||
| 	QByteArray sampleSourceSerialized; | ||||
| 	SampleSourceSerializer::writeSerializedData(data.m_data, sampleSourceSerialized); | ||||
| 
 | ||||
| 	SimpleSerializer s(1); | ||||
| 
 | ||||
| 	s.writeBlob(1, sampleSourceSerialized); | ||||
| 	s.writeS32(2, data.m_bias); | ||||
| 	s.writeS32(3, data.m_range); | ||||
| 
 | ||||
| 	serializedData = s.final(); | ||||
| } | ||||
| 
 | ||||
| bool FCDSerializer::readSerializedData(const QByteArray& serializedData, FCDData& data) | ||||
| { | ||||
| 	bool valid = SampleSourceSerializer::readSerializedData(serializedData, data.m_data); | ||||
| 
 | ||||
| 	QByteArray sampleSourceSerialized; | ||||
| 
 | ||||
| 	SimpleDeserializer d(serializedData); | ||||
| 
 | ||||
| 	if (!d.isValid()) | ||||
| 	{ | ||||
| 		setDefaults(data); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (d.getVersion() == SampleSourceSerializer::getSerializerVersion()) | ||||
| 	{ | ||||
| 		int intval; | ||||
| 
 | ||||
| 		d.readBlob(1, &sampleSourceSerialized); | ||||
| 		d.readS32(2, &data.m_bias); | ||||
| 		d.readS32(3, &data.m_range); | ||||
| 
 | ||||
| 		return SampleSourceSerializer::readSerializedData(sampleSourceSerialized, data.m_data); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		setDefaults(data); | ||||
| 		return false; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void FCDSerializer::setDefaults(FCDData& data) | ||||
| { | ||||
| 	data.m_range = 0; | ||||
| 	data.m_bias = 0; | ||||
| } | ||||
							
								
								
									
										39
									
								
								plugins/samplesource/fcdpro/fcdserializer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								plugins/samplesource/fcdpro/fcdserializer.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Copyright (C) 2015 Edouard Griffiths, F4EXB                                   //
 | ||||
| //                                                                               //
 | ||||
| // This program is free software; you can redistribute it and/or modify          //
 | ||||
| // it under the terms of the GNU General Public License as published by          //
 | ||||
| // the Free Software Foundation as version 3 of the License, or                  //
 | ||||
| //                                                                               //
 | ||||
| // This program is distributed in the hope that it will be useful,               //
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | ||||
| // GNU General Public License V3 for more details.                               //
 | ||||
| //                                                                               //
 | ||||
| // You should have received a copy of the GNU General Public License             //
 | ||||
| // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #ifndef PLUGINS_SAMPLESOURCE_FCD_FCDSERIALIZER_H_ | ||||
| #define PLUGINS_SAMPLESOURCE_FCD_FCDSERIALIZER_H_ | ||||
| 
 | ||||
| #include "util/samplesourceserializer.h" | ||||
| 
 | ||||
| class FCDSerializer | ||||
| { | ||||
| public: | ||||
| 	struct FCDData | ||||
| 	{ | ||||
| 		SampleSourceSerializer::Data m_data; | ||||
| 		qint32 m_bias; | ||||
| 		qint32 m_range; | ||||
| 	}; | ||||
| 
 | ||||
| 	static void writeSerializedData(const FCDData& data, QByteArray& serializedData); | ||||
| 	static bool readSerializedData(const QByteArray& serializedData, FCDData& data); | ||||
| 	static void setDefaults(FCDData& data); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #endif /* PLUGINS_SAMPLESOURCE_FCD_FCDSERIALIZER_H_ */ | ||||
							
								
								
									
										150
									
								
								plugins/samplesource/fcdpro/fcdthread.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								plugins/samplesource/fcdpro/fcdthread.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,150 @@ | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
 | ||||
| // written by Christian Daniel                                                   //
 | ||||
| //                                                                               //
 | ||||
| // This program is free software; you can redistribute it and/or modify          //
 | ||||
| // it under the terms of the GNU General Public License as published by          //
 | ||||
| // the Free Software Foundation as version 3 of the License, or                  //
 | ||||
| //                                                                               //
 | ||||
| // This program is distributed in the hope that it will be useful,               //
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | ||||
| // GNU General Public License V3 for more details.                               //
 | ||||
| //                                                                               //
 | ||||
| // You should have received a copy of the GNU General Public License             //
 | ||||
| // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #include <QDebug> | ||||
| #include <stdio.h> | ||||
| #include <errno.h> | ||||
| #include "fcdthread.h" | ||||
| #include "fcdinput.h" | ||||
| #include "dsp/samplefifo.h" | ||||
| 
 | ||||
| FCDThread::FCDThread(SampleFifo* sampleFifo, QObject* parent) : | ||||
| 	QThread(parent), | ||||
| 	fcd_handle(NULL), | ||||
| 	m_running(false), | ||||
| 	m_convertBuffer(FCD_BLOCKSIZE), | ||||
| 	m_sampleFifo(sampleFifo) | ||||
| { | ||||
| 	start(); | ||||
| } | ||||
| 
 | ||||
| FCDThread::~FCDThread() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| void FCDThread::stopWork() | ||||
| { | ||||
| 	m_running = false; | ||||
| 	wait(); | ||||
| } | ||||
| 
 | ||||
| void FCDThread::run() | ||||
| { | ||||
| 	if ( !OpenSource(FCDInput::m_deviceName.c_str()) ) | ||||
| 	{ | ||||
| 		qCritical() << "FCDThread::run: cannot open FCD sound card"; | ||||
| 		return; | ||||
| 	} | ||||
| 	// TODO: fallback to original fcd
 | ||||
| 
 | ||||
| 	m_running = true; | ||||
| 
 | ||||
| 	while(m_running) | ||||
| 	{ | ||||
| 		if (work(FCD_BLOCKSIZE) < 0) | ||||
| 		{ | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	CloseSource(); | ||||
| } | ||||
| 
 | ||||
| bool FCDThread::OpenSource(const char* cardname) | ||||
| { | ||||
| 	bool fail = false; | ||||
| 	snd_pcm_hw_params_t* params; | ||||
| 	//fcd_rate = FCDPP_RATE;
 | ||||
| 	//fcd_channels =2;
 | ||||
| 	//fcd_format = SND_PCM_SFMT_U16_LE;
 | ||||
| 	snd_pcm_stream_t fcd_stream = SND_PCM_STREAM_CAPTURE; | ||||
| 
 | ||||
| 	if (fcd_handle) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (snd_pcm_open(&fcd_handle, cardname, fcd_stream, 0) < 0) | ||||
| 	{ | ||||
| 		qCritical("FCDThread::OpenSource: cannot open %s", cardname); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	snd_pcm_hw_params_alloca(¶ms); | ||||
| 
 | ||||
| 	if (snd_pcm_hw_params_any(fcd_handle, params) < 0) | ||||
| 	{ | ||||
| 		qCritical("FCDThread::OpenSource: snd_pcm_hw_params_any failed"); | ||||
| 		fail = true; | ||||
| 	} | ||||
| 	else if (snd_pcm_hw_params(fcd_handle, params) < 0) | ||||
| 	{ | ||||
| 		qCritical("FCDThread::OpenSource: snd_pcm_hw_params failed"); | ||||
| 		fail = true; | ||||
| 		// TODO: check actual samplerate, may be crippled firmware
 | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if (snd_pcm_start(fcd_handle) < 0) | ||||
| 		{ | ||||
| 			qCritical("FCDThread::OpenSource: snd_pcm_start failed"); | ||||
| 			fail = true; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (fail) | ||||
| 	{ | ||||
| 		snd_pcm_close( fcd_handle ); | ||||
| 		return false; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		qDebug("FCDThread::OpenSource: Funcube stream started"); | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void FCDThread::CloseSource() | ||||
| { | ||||
| 	if (fcd_handle) | ||||
| 	{ | ||||
| 		snd_pcm_close( fcd_handle ); | ||||
| 	} | ||||
| 
 | ||||
| 	fcd_handle = NULL; | ||||
| } | ||||
| 
 | ||||
| int FCDThread::work(int n_items) | ||||
| { | ||||
| 	int l; | ||||
| 	SampleVector::iterator it; | ||||
| 	void *out; | ||||
| 
 | ||||
| 	it = m_convertBuffer.begin(); | ||||
| 	out = (void *)&it[0]; | ||||
| 	l = snd_pcm_mmap_readi(fcd_handle, out, (snd_pcm_uframes_t)n_items); | ||||
| 	if (l > 0) | ||||
| 		m_sampleFifo->write(it, it + l); | ||||
| 	if (l == -EPIPE) { | ||||
| 		qDebug("FCD: Overrun detected"); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	return l; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										56
									
								
								plugins/samplesource/fcdpro/fcdthread.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								plugins/samplesource/fcdpro/fcdthread.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
 | ||||
| // written by Christian Daniel                                                   //
 | ||||
| //                                                                               //
 | ||||
| // This program is free software; you can redistribute it and/or modify          //
 | ||||
| // it under the terms of the GNU General Public License as published by          //
 | ||||
| // the Free Software Foundation as version 3 of the License, or                  //
 | ||||
| //                                                                               //
 | ||||
| // This program is distributed in the hope that it will be useful,               //
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | ||||
| // GNU General Public License V3 for more details.                               //
 | ||||
| //                                                                               //
 | ||||
| // You should have received a copy of the GNU General Public License             //
 | ||||
| // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #ifndef INCLUDE_FCDTHREAD_H | ||||
| #define INCLUDE_FCDTHREAD_H | ||||
| 
 | ||||
| #include <QThread> | ||||
| #include <QMutex> | ||||
| #include <QWaitCondition> | ||||
| #include "dsp/samplefifo.h" | ||||
| #include "dsp/inthalfbandfilter.h" | ||||
| #include <alsa/asoundlib.h> | ||||
| 
 | ||||
| #define FCDPP_RATE 192000 // FIXME: The Pro / Pro+ switch should be handled better than this!
 | ||||
| #define FCD_BLOCKSIZE (1<<11) | ||||
| 
 | ||||
| class FCDThread : public QThread { | ||||
| 	Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
| 	FCDThread(SampleFifo* sampleFifo, QObject* parent = NULL); | ||||
| 	~FCDThread(); | ||||
| 
 | ||||
| 	void stopWork(); | ||||
| 	bool OpenSource(const char *filename); | ||||
| 	void CloseSource(); | ||||
| 	int work(int n_items); | ||||
| private: | ||||
| 	snd_pcm_format_t fcd_format; | ||||
| 	snd_pcm_t* fcd_handle; | ||||
| 
 | ||||
| 	QMutex m_startWaitMutex; | ||||
| 	QWaitCondition m_startWaiter; | ||||
| 	bool m_running; | ||||
| 
 | ||||
| 	SampleVector m_convertBuffer; | ||||
| 	SampleFifo* m_sampleFifo; | ||||
| 
 | ||||
| 	void run(); | ||||
| 
 | ||||
| }; | ||||
| #endif // INCLUDE_FCDTHREAD_H
 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user