diff -Nru bladerf-0.3.0+git20130911/.git/FETCH_HEAD bladerf-0.3.0+git20130916/.git/FETCH_HEAD --- bladerf-0.3.0+git20130911/.git/FETCH_HEAD 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/.git/FETCH_HEAD 2013-09-17 07:44:18.000000000 +0000 @@ -0,0 +1,4 @@ +a79bf948c450ba3bdea5872ebd4c0dbbff72baaa branch 'master' of https://github.com/Nuand/bladeRF +a5f68dfeb893d3eae51bb27ebe1f36c63d20eecd not-for-merge branch 'dev-cmake_output_dir' of https://github.com/Nuand/bladeRF +96193ce0922e85a40247e8518cba972b816867de not-for-merge branch 'dev-dc_correction' of https://github.com/Nuand/bladeRF +69be24fc008adcfda1661e75bdd0cdf23928177c not-for-merge branch 'dev-hdl' of https://github.com/Nuand/bladeRF diff -Nru bladerf-0.3.0+git20130911/.git/ORIG_HEAD bladerf-0.3.0+git20130916/.git/ORIG_HEAD --- bladerf-0.3.0+git20130911/.git/ORIG_HEAD 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/.git/ORIG_HEAD 2013-09-13 07:24:44.000000000 +0000 @@ -0,0 +1 @@ +3d91831170997057329c6bd05f0df55156d53496 Binary files /tmp/5rekXlBfYl/bladerf-0.3.0+git20130911/.git/index and /tmp/AKx_HAtxrA/bladerf-0.3.0+git20130916/.git/index differ diff -Nru bladerf-0.3.0+git20130911/.git/logs/HEAD bladerf-0.3.0+git20130916/.git/logs/HEAD --- bladerf-0.3.0+git20130911/.git/logs/HEAD 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/.git/logs/HEAD 2013-09-17 07:44:19.000000000 +0000 @@ -1 +1,2 @@ 0000000000000000000000000000000000000000 3d91831170997057329c6bd05f0df55156d53496 Roman Moravčík 1378986752 +0200 clone: from https://github.com/Nuand/bladeRF +3d91831170997057329c6bd05f0df55156d53496 a79bf948c450ba3bdea5872ebd4c0dbbff72baaa Roman Moravčík 1379403859 +0200 pull: Fast-forward diff -Nru bladerf-0.3.0+git20130911/.git/logs/refs/heads/master bladerf-0.3.0+git20130916/.git/logs/refs/heads/master --- bladerf-0.3.0+git20130911/.git/logs/refs/heads/master 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/.git/logs/refs/heads/master 2013-09-17 07:44:19.000000000 +0000 @@ -1 +1,2 @@ 0000000000000000000000000000000000000000 3d91831170997057329c6bd05f0df55156d53496 Roman Moravčík 1378986752 +0200 clone: from https://github.com/Nuand/bladeRF +3d91831170997057329c6bd05f0df55156d53496 a79bf948c450ba3bdea5872ebd4c0dbbff72baaa Roman Moravčík 1379403859 +0200 pull: Fast-forward diff -Nru bladerf-0.3.0+git20130911/.git/logs/refs/remotes/origin/dev-async_repeater_example bladerf-0.3.0+git20130916/.git/logs/refs/remotes/origin/dev-async_repeater_example --- bladerf-0.3.0+git20130911/.git/logs/refs/remotes/origin/dev-async_repeater_example 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/.git/logs/refs/remotes/origin/dev-async_repeater_example 2013-09-13 07:24:44.000000000 +0000 @@ -0,0 +1 @@ +c3319c8369cfd5272d367d74d7b5439177e40de2 7165e58d0ba09c68c3ed4d5c133798557feffab9 Roman Moravčík 1379057084 +0200 pull: fast-forward diff -Nru bladerf-0.3.0+git20130911/.git/logs/refs/remotes/origin/dev-cmake_output_dir bladerf-0.3.0+git20130916/.git/logs/refs/remotes/origin/dev-cmake_output_dir --- bladerf-0.3.0+git20130911/.git/logs/refs/remotes/origin/dev-cmake_output_dir 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/.git/logs/refs/remotes/origin/dev-cmake_output_dir 2013-09-17 07:44:18.000000000 +0000 @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 a5f68dfeb893d3eae51bb27ebe1f36c63d20eecd Roman Moravčík 1379403858 +0200 pull: storing head diff -Nru bladerf-0.3.0+git20130911/.git/logs/refs/remotes/origin/master bladerf-0.3.0+git20130916/.git/logs/refs/remotes/origin/master --- bladerf-0.3.0+git20130911/.git/logs/refs/remotes/origin/master 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/.git/logs/refs/remotes/origin/master 2013-09-17 07:44:18.000000000 +0000 @@ -0,0 +1 @@ +3d91831170997057329c6bd05f0df55156d53496 a79bf948c450ba3bdea5872ebd4c0dbbff72baaa Roman Moravčík 1379403858 +0200 pull: fast-forward Binary files /tmp/5rekXlBfYl/bladerf-0.3.0+git20130911/.git/objects/43/e849990c813c3f76707d43ca7ddedb4cbf123e and /tmp/AKx_HAtxrA/bladerf-0.3.0+git20130916/.git/objects/43/e849990c813c3f76707d43ca7ddedb4cbf123e differ Binary files /tmp/5rekXlBfYl/bladerf-0.3.0+git20130911/.git/objects/46/72ba3d2b98d190b1ced55ba2a2194197be3418 and /tmp/AKx_HAtxrA/bladerf-0.3.0+git20130916/.git/objects/46/72ba3d2b98d190b1ced55ba2a2194197be3418 differ Binary files /tmp/5rekXlBfYl/bladerf-0.3.0+git20130911/.git/objects/4f/3e9107cc6e0e3720d825578aa2bf5e0781a436 and /tmp/AKx_HAtxrA/bladerf-0.3.0+git20130916/.git/objects/4f/3e9107cc6e0e3720d825578aa2bf5e0781a436 differ diff -Nru bladerf-0.3.0+git20130911/.git/objects/71/65e58d0ba09c68c3ed4d5c133798557feffab9 bladerf-0.3.0+git20130916/.git/objects/71/65e58d0ba09c68c3ed4d5c133798557feffab9 --- bladerf-0.3.0+git20130911/.git/objects/71/65e58d0ba09c68c3ed4d5c133798557feffab9 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/.git/objects/71/65e58d0ba09c68c3ed4d5c133798557feffab9 2013-09-13 07:24:44.000000000 +0000 @@ -0,0 +1 @@ +x=N0sF26BhWtPN 2xqQ ^ \ No newline at end of file Binary files /tmp/5rekXlBfYl/bladerf-0.3.0+git20130911/.git/objects/8e/1fc312d9674f6a8fcb0d9cc4bcf76594921b09 and /tmp/AKx_HAtxrA/bladerf-0.3.0+git20130916/.git/objects/8e/1fc312d9674f6a8fcb0d9cc4bcf76594921b09 differ Binary files /tmp/5rekXlBfYl/bladerf-0.3.0+git20130911/.git/objects/aa/21ecc865fa4ab90ada0e73267d6f9f8a7445ef and /tmp/AKx_HAtxrA/bladerf-0.3.0+git20130916/.git/objects/aa/21ecc865fa4ab90ada0e73267d6f9f8a7445ef differ Binary files /tmp/5rekXlBfYl/bladerf-0.3.0+git20130911/.git/objects/c6/8d7701e4e4bfd0f8f9c6fdc9f143a091708333 and /tmp/AKx_HAtxrA/bladerf-0.3.0+git20130916/.git/objects/c6/8d7701e4e4bfd0f8f9c6fdc9f143a091708333 differ Binary files /tmp/5rekXlBfYl/bladerf-0.3.0+git20130911/.git/objects/c8/2fee585c61130d3cab78becf6f5318a90057a9 and /tmp/AKx_HAtxrA/bladerf-0.3.0+git20130916/.git/objects/c8/2fee585c61130d3cab78becf6f5318a90057a9 differ Binary files /tmp/5rekXlBfYl/bladerf-0.3.0+git20130911/.git/objects/f8/ed160416cf6d8bb4c1b0c7ca9d4d2780382925 and /tmp/AKx_HAtxrA/bladerf-0.3.0+git20130916/.git/objects/f8/ed160416cf6d8bb4c1b0c7ca9d4d2780382925 differ Binary files /tmp/5rekXlBfYl/bladerf-0.3.0+git20130911/.git/objects/pack/pack-088eb6cc220f1f053e0efd73a233910e8ea55a62.idx and /tmp/AKx_HAtxrA/bladerf-0.3.0+git20130916/.git/objects/pack/pack-088eb6cc220f1f053e0efd73a233910e8ea55a62.idx differ Binary files /tmp/5rekXlBfYl/bladerf-0.3.0+git20130911/.git/objects/pack/pack-088eb6cc220f1f053e0efd73a233910e8ea55a62.pack and /tmp/AKx_HAtxrA/bladerf-0.3.0+git20130916/.git/objects/pack/pack-088eb6cc220f1f053e0efd73a233910e8ea55a62.pack differ diff -Nru bladerf-0.3.0+git20130911/.git/refs/heads/master bladerf-0.3.0+git20130916/.git/refs/heads/master --- bladerf-0.3.0+git20130911/.git/refs/heads/master 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/.git/refs/heads/master 2013-09-17 07:44:19.000000000 +0000 @@ -1 +1 @@ -3d91831170997057329c6bd05f0df55156d53496 +a79bf948c450ba3bdea5872ebd4c0dbbff72baaa diff -Nru bladerf-0.3.0+git20130911/.git/refs/remotes/origin/dev-async_repeater_example bladerf-0.3.0+git20130916/.git/refs/remotes/origin/dev-async_repeater_example --- bladerf-0.3.0+git20130911/.git/refs/remotes/origin/dev-async_repeater_example 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/.git/refs/remotes/origin/dev-async_repeater_example 2013-09-13 07:24:44.000000000 +0000 @@ -0,0 +1 @@ +7165e58d0ba09c68c3ed4d5c133798557feffab9 diff -Nru bladerf-0.3.0+git20130911/.git/refs/remotes/origin/dev-cmake_output_dir bladerf-0.3.0+git20130916/.git/refs/remotes/origin/dev-cmake_output_dir --- bladerf-0.3.0+git20130911/.git/refs/remotes/origin/dev-cmake_output_dir 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/.git/refs/remotes/origin/dev-cmake_output_dir 2013-09-17 07:44:18.000000000 +0000 @@ -0,0 +1 @@ +a5f68dfeb893d3eae51bb27ebe1f36c63d20eecd diff -Nru bladerf-0.3.0+git20130911/.git/refs/remotes/origin/master bladerf-0.3.0+git20130916/.git/refs/remotes/origin/master --- bladerf-0.3.0+git20130911/.git/refs/remotes/origin/master 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/.git/refs/remotes/origin/master 2013-09-17 07:44:18.000000000 +0000 @@ -0,0 +1 @@ +a79bf948c450ba3bdea5872ebd4c0dbbff72baaa diff -Nru bladerf-0.3.0+git20130911/debian/bladerf-dkms.dkms bladerf-0.3.0+git20130916/debian/bladerf-dkms.dkms --- bladerf-0.3.0+git20130911/debian/bladerf-dkms.dkms 2013-09-13 06:59:44.000000000 +0000 +++ bladerf-0.3.0+git20130916/debian/bladerf-dkms.dkms 2013-09-17 07:47:43.000000000 +0000 @@ -2,4 +2,6 @@ PACKAGE_VERSION="0.3.0" MAKE[0]="make" CLEAN="make clean" +BUILT_MODULE_NAME[0]="bladeRF" DEST_MODULE_LOCATION[0]="/extra" +AUTOINSTALL="yes" diff -Nru bladerf-0.3.0+git20130911/debian/changelog bladerf-0.3.0+git20130916/debian/changelog --- bladerf-0.3.0+git20130911/debian/changelog 2013-09-14 08:43:08.000000000 +0000 +++ bladerf-0.3.0+git20130916/debian/changelog 2013-09-17 08:19:01.000000000 +0000 @@ -1,8 +1,16 @@ -bladerf (0.3.0+git20130911-3d918311~quantal~rm3) quantal; urgency=low +bladerf (0.3.0+git20130916-a79bf948~quantal~rm1) quantal; urgency=low * Backport from saucy. - -- Roman Moravcik Sat, 14 Sep 2013 09:30:52 +0200 + -- Roman Moravcik Tue, 17 Sep 2013 09:47:50 +0200 + +bladerf (0.3.0+git20130916-a79bf948~saucy~rm1) saucy; urgency=low + + * Update to git revision a79bf948. + * Added missing BUILT_MODULE_NAME directive to dkms.conf. + * libbladerf: recommends bladerf-bin. + + -- Roman Moravcik Tue, 17 Sep 2013 09:47:50 +0200 bladerf (0.3.0+git20130911-3d918311~saucy~rm3) saucy; urgency=low diff -Nru bladerf-0.3.0+git20130911/debian/control bladerf-0.3.0+git20130916/debian/control --- bladerf-0.3.0+git20130911/debian/control 2013-09-13 15:13:29.000000000 +0000 +++ bladerf-0.3.0+git20130916/debian/control 2013-09-17 07:50:15.000000000 +0000 @@ -12,6 +12,7 @@ Section: libs Architecture: any Depends: multiarch-support, ${shlibs:Depends}, ${misc:Depends}, bladerf-dkms (= ${binary:Version}) +Recommends: bladerf-bin (= ${binary:Version}) Description: USB 3.0 Superspeed Software Defined Radio Software for the bladerf SDR platform. diff -Nru bladerf-0.3.0+git20130911/firmware_common/bladeRF.h bladerf-0.3.0+git20130916/firmware_common/bladeRF.h --- bladerf-0.3.0+git20130911/firmware_common/bladeRF.h 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/firmware_common/bladeRF.h 2013-09-17 07:44:19.000000000 +0000 @@ -40,6 +40,7 @@ #define BLADE_USB_CMD_READ_OTP 103 #define BLADE_USB_CMD_WRITE_OTP 104 #define BLADE_USB_CMD_RESET 105 +#define BLADE_USB_CMD_JUMP_TO_BOOTLOADER 106 #define BLADE_USB_CMD_QUERY_VERSION 0 #define BLADE_USB_CMD_QUERY_FPGA_STATUS 1 @@ -63,12 +64,16 @@ unsigned char *ptr; }; +#define USB_CYPRESS_VENDOR_ID 0x04b4 +#define USB_FX3_PRODUCT_ID 0x00f3 + #define BLADE_USB_TYPE_OUT 0x40 #define BLADE_USB_TYPE_IN 0xC0 #define BLADE_USB_TIMEOUT_MS 1000 #define USB_NUAND_VENDOR_ID 0x1d50 #define USB_NUAND_BLADERF_PRODUCT_ID 0x6066 +#define USB_NUAND_BLADERF_BOOT_PRODUCT_ID 0x6080 #define USB_NUAND_BLADERF_MINOR_BASE 193 #define NUM_CONCURRENT 8 #define NUM_DATA_URB (1024) diff -Nru bladerf-0.3.0+git20130911/fx3_firmware/bladeRF.c bladerf-0.3.0+git20130916/fx3_firmware/bladeRF.c --- bladerf-0.3.0+git20130911/fx3_firmware/bladeRF.c 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/fx3_firmware/bladeRF.c 2013-09-17 07:44:19.000000000 +0000 @@ -19,6 +19,7 @@ * can result in linker error. */ #include "cyfxgpif_C4loader.h" #include "cyfxgpif_RFlink.h" +#include "spi_flash_lib.h" uint32_t glAppMode = MODE_NO_CONFIG; @@ -82,7 +83,7 @@ CyU3PIoMatrixConfig_t io_cfg; CyU3PGpioSimpleConfig_t gpioConfig; CyU3PReturnStatus_t status = CY_U3P_SUCCESS; - int i; + size_t i; struct { int pin; // pin number @@ -346,7 +347,6 @@ void CyFxGpioInit(void) { CyU3PGpioClock_t gpioClock; - CyU3PGpioSimpleConfig_t gpioConfig; CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS; /* Init the GPIO module */ @@ -371,7 +371,7 @@ { CyBool_t value; - int tEnd; + unsigned tEnd; CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS; apiRetStatus = CyU3PGpioSetValue(GPIO_nCONFIG, CyFalse); tEnd = CyU3PGetTime() + 10; @@ -396,7 +396,7 @@ if (type == CY_U3P_DMA_CB_PROD_EVENT) { int i; unsigned char *buf = input->buffer_p.buffer; - unsigned *us_buf = (unsigned short *)input->buffer_p.buffer; + unsigned *us_buf = (unsigned *)input->buffer_p.buffer; unsigned tmpr, tmpw; /* Flip the bits in such a way that the FPGA can be programmed @@ -767,6 +767,15 @@ glAppMode = MODE_NO_CONFIG; } +static void StopApplication() +{ + if (glAppMode == MODE_RF_CONFIG) { + NuandRFLinkStop(); + } else if (glAppMode == MODE_FPGA_CONFIG){ + NuandFpgaConfigStop(); + } +} + /* Callback to handle the USB setup requests. */ CyBool_t CyFxbladeRFApplnUSBSetupCB(uint32_t setupdat0, uint32_t setupdat1) { @@ -843,7 +852,7 @@ struct bladeRF_version ver; CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS; int retStatus; - char buf[10]; + uint8_t buf[10]; uint16_t readC; isHandled = CyTrue; @@ -852,15 +861,15 @@ { case BLADE_USB_CMD_QUERY_VERSION: ver.major = 1; - ver.minor = 2; - apiRetStatus = CyU3PUsbSendEP0Data(sizeof(ver), &ver); + ver.minor = 3; + apiRetStatus = CyU3PUsbSendEP0Data(sizeof(ver), (void*)&ver); break; case BLADE_USB_CMD_RF_RX: CyU3PGpioSetValue(GPIO_SYS_RST, CyTrue); CyU3PGpioSetValue(GPIO_SYS_RST, CyFalse); - apiRetStatus = CyU3PUsbGetEP0Data(4, buf, &readC); + apiRetStatus = CyU3PUsbGetEP0Data(4, buf, (void*)&readC); if (!(buf[0] || buf[3])) { apiRetStatus = CyU3PUsbResetEp(BLADE_RF_SAMPLE_EP_CONSUMER); @@ -886,7 +895,7 @@ case BLADE_USB_CMD_BEGIN_PROG: retStatus = FpgaBeginProgram(); - apiRetStatus = CyU3PUsbSendEP0Data (sizeof(retStatus), &retStatus); + apiRetStatus = CyU3PUsbSendEP0Data (sizeof(retStatus), (void*)&retStatus); break; break; @@ -897,13 +906,13 @@ } else { ret = -1; } - apiRetStatus = CyU3PUsbSendEP0Data (sizeof(ret), &ret); + apiRetStatus = CyU3PUsbSendEP0Data (sizeof(ret), (void*)&ret); break; case BLADE_USB_CMD_WRITE_OTP: NuandEnso(); if (CyU3PUsbGetSpeed() == CY_U3P_SUPER_SPEED) { - apiRetStatus = CyU3PUsbGetEP0Data(0x100, &glEp0Buffer, &readC); + apiRetStatus = CyU3PUsbGetEP0Data(0x100, glEp0Buffer, &readC); apiRetStatus = CyFxSpiTransfer (0, 0x100, glEp0Buffer, CyFalse); } @@ -921,7 +930,7 @@ } else { memcpy(glEp0Buffer, glOtp, 0x100); } - apiRetStatus = CyU3PUsbSendEP0Data(wLength, &glEp0Buffer); + apiRetStatus = CyU3PUsbSendEP0Data(wLength, glEp0Buffer); if (glUsbAltInterface == 2) NuandExso(); } else { @@ -937,10 +946,10 @@ NuandEnso(); apiRetStatus = CyFxSpiTransfer (0, 0x100, glEp0Buffer, CyTrue); - apiRetStatus = CyU3PUsbSendEP0Data(0x100, &glEp0Buffer); + apiRetStatus = CyU3PUsbSendEP0Data(0x100, glEp0Buffer); NuandExso(); } else { - apiRetStatus = CyU3PUsbSendEP0Data(0x100, &glOtp); + apiRetStatus = CyU3PUsbSendEP0Data(0x100, glOtp); } } break; @@ -966,9 +975,9 @@ if (glUsbAltInterface == 2) { apiRetStatus = CyFxSpiTransfer (wIndex, 0x100, glEp0Buffer, CyTrue); - apiRetStatus = CyU3PUsbSendEP0Data(0x100, &glEp0Buffer); + apiRetStatus = CyU3PUsbSendEP0Data(0x100, glEp0Buffer); } else { - apiRetStatus = CyU3PUsbSendEP0Data(0x100, &glCal); + apiRetStatus = CyU3PUsbSendEP0Data(0x100, glCal); } } break; @@ -984,7 +993,7 @@ glEp0Idx = 0; } } else if (CyU3PUsbGetSpeed() == CY_U3P_SUPER_SPEED) { - apiRetStatus = CyU3PUsbGetEP0Data(0x100, &glEp0Buffer, &readC); + apiRetStatus = CyU3PUsbGetEP0Data(0x100, glEp0Buffer, &readC); apiRetStatus = CyFxSpiTransfer (wIndex, 0x100, glEp0Buffer, CyFalse); } @@ -993,14 +1002,45 @@ case BLADE_USB_CMD_FLASH_ERASE: apiRetStatus = CyFxSpiEraseSector(CyTrue, wIndex); ret = (apiRetStatus == CY_U3P_SUCCESS); - CyU3PUsbSendEP0Data(sizeof(ret), &ret); + CyU3PUsbSendEP0Data(sizeof(ret), (void*)&ret); break; case BLADE_USB_CMD_RESET: - apiRetStatus = CyU3PUsbGetEP0Data(4, buf, &readC); + CyU3PUsbAckSetup(); CyU3PDeviceReset(CyFalse); break; + case BLADE_USB_CMD_JUMP_TO_BOOTLOADER: + StopApplication(); + NuandFirmwareStart(); + + // Erase the first sector so we can write the bootloader + // header + apiRetStatus = CyFxSpiEraseSector(CyTrue, 0); + if(apiRetStatus != CY_U3P_SUCCESS) { + CyU3PUsbStall(0, CyTrue, CyFalse); + CyU3PDeviceReset(CyFalse); + break; + } + + uint8_t bootloader_header[] = { + 'C','Y', // Common header + 0, // 10 MHz SPI, image data + 0xB2, // Bootloader VID/PID + (USB_NUAND_BLADERF_BOOT_PRODUCT_ID & 0xFF), + (USB_NUAND_BLADERF_BOOT_PRODUCT_ID & 0xFF00) >> 8, + (USB_NUAND_VENDOR_ID & 0xFF), + (USB_NUAND_VENDOR_ID & 0xFF00) >> 8, + }; + + apiRetStatus = CyFxSpiTransfer ( + /* Page */ 0, + sizeof(bootloader_header), bootloader_header, + CyFalse /* Writing */ + ); + + CyU3PUsbAckSetup(); + CyU3PDeviceReset(CyFalse); break; default: isHandled = CyFalse; @@ -1050,11 +1090,7 @@ case CY_U3P_USB_EVENT_RESET: case CY_U3P_USB_EVENT_DISCONNECT: /* Stop the loop back function. */ - if (glAppMode == MODE_RF_CONFIG) { - NuandRFLinkStop(); - } else if (glAppMode == MODE_FPGA_CONFIG){ - NuandFpgaConfigStop(); - } + StopApplication(); break; default: @@ -1220,7 +1256,7 @@ { char serial_buf[32]; int i; - if (!NuandExtractField(glOtp, 0x100, "S", serial_buf, 32)) { + if (!NuandExtractField((void*)glOtp, 0x100, "S", serial_buf, 32)) { for (i = 0; i < 32; i++) { CyFxUSBSerial[2+i*2] = serial_buf[i]; } diff -Nru bladerf-0.3.0+git20130911/fx3_firmware/spi_flash_lib.c bladerf-0.3.0+git20130916/fx3_firmware/spi_flash_lib.c --- bladerf-0.3.0+git20130911/fx3_firmware/spi_flash_lib.c 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/fx3_firmware/spi_flash_lib.c 2013-09-17 07:44:19.000000000 +0000 @@ -18,6 +18,8 @@ #include "pib_regs.h" #include "cyu3spi.h" +#include "spi_flash_lib.h" + uint16_t glSpiPageSize = 0x100; /* SPI Page size to be used for transfers. */ /* SPI initialization for application. */ @@ -52,7 +54,7 @@ } CyU3PReturnStatus_t CyFxSpiDeInit() { - CyU3PSpiDeInit(); + return CyU3PSpiDeInit(); } /* Wait for the status response from the SPI flash. */ @@ -177,7 +179,7 @@ void NuandLockOtp() { CyU3PReturnStatus_t status = CY_U3P_SUCCESS; - char location[4]; + uint8_t location[4]; location[0] = 0x05; /* RDSTATUS */ CyU3PSpiSetSsnLine (CyFalse); @@ -215,7 +217,7 @@ void NuandEnso() { CyU3PReturnStatus_t status = CY_U3P_SUCCESS; - char location[4]; + uint8_t location[4]; location[0] = 0xb1; // ENSO CyU3PSpiSetSsnLine (CyFalse); @@ -226,7 +228,7 @@ void NuandExso() { CyU3PReturnStatus_t status = CY_U3P_SUCCESS; - char location[4]; + uint8_t location[4]; location[0] = 0xc1; // EXSO CyU3PSpiSetSsnLine (CyFalse); @@ -274,7 +276,6 @@ } void NuandFirmwareStart() { - CyU3PIoMatrixConfig_t io_cfg; CyU3PReturnStatus_t status = CY_U3P_SUCCESS; NuandGPIOReconfigure(CyFalse, CyFalse); diff -Nru bladerf-0.3.0+git20130911/fx3_firmware/spi_flash_lib.h bladerf-0.3.0+git20130916/fx3_firmware/spi_flash_lib.h --- bladerf-0.3.0+git20130911/fx3_firmware/spi_flash_lib.h 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/fx3_firmware/spi_flash_lib.h 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,7 @@ +#ifndef _SPI_FLASH_LIB_H_ +#define _SPI_FLASH_LIB_H_ + +CyU3PReturnStatus_t CyFxSpiInit(uint16_t pageLen); +CyU3PReturnStatus_t CyFxSpiTransfer(uint16_t pageAddress, uint16_t byteCount, uint8_t *buffer, CyBool_t isRead); + +#endif diff -Nru bladerf-0.3.0+git20130911/host/CMakeLists.txt bladerf-0.3.0+git20130916/host/CMakeLists.txt --- bladerf-0.3.0+git20130911/host/CMakeLists.txt 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/CMakeLists.txt 2013-09-17 07:44:19.000000000 +0000 @@ -15,6 +15,11 @@ # Project configuration ################################################################################ +# All build output lands in this directory: +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/output) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/output) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/output) + if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release") message(STATUS "Build type not specified: defaulting to a release build.") @@ -88,6 +93,7 @@ # TODO Re-enable these # add_definitions(-pedantic) # add_definitions(-std=c89) + add_definitions(-Werror) add_definitions(-Wno-unused-parameter) if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") @@ -99,8 +105,16 @@ "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") ############################### -# System configuration +# MS Visual Studio ############################### +if(MSVC) + # Cannot enable /WX on Windows build just yet, lots of warnings + #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") +endif(MSVC) + +################################################################################ +# System configuration +################################################################################ # Linux (TODO determine if this will actually be sufficient for BSD) if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "BSD") @@ -145,3 +159,39 @@ COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake ) + +################################################################################ +# Windows-only, Post build: Copy libraries to our build output directory +################################################################################ +if(WIN32) + find_package(LibPThreadsWin32) + if(LIBPTHREADSWIN32_FOUND) + set(WIN_POSTBUILD_ITEMS ${WIN_POSTBUILD_ITEMS} + "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/pthreadVC2.dll") + + add_custom_command( + OUTPUT "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/pthreadVC2.dll" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${LIBPTHREADSWIN32_PATH}/dll/${LIBPTHREADSWIN32_LIBRARY_PATH_SUFFIX}/pthreadVC2.dll" + "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/" + COMMENT "Copying pthreadVC2.dll to output directory..." + ) + endif(LIBPTHREADSWIN32_FOUND) + + find_package(LibUsb) + if(LIBUSB_FOUND) + set(WIN_POSTBUILD_ITEMS ${WIN_POSTBUILD_ITEMS} + "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/libusb-1.0.dll") + + add_custom_command( + OUTPUT "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/libusb-1.0.dll" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${LIBUSB_PATH}/${LIBUSB_LIBRARY_PATH_SUFFIX}/libusb-1.0.dll" + "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/" + COMMENT "Copying libusb-1.0.dll to output directory..." + ) + endif(LIBUSB_FOUND) + + add_custom_target(win_postbuild ALL DEPENDS ${WIN_POSTBUILD_ITEMS}) + +endif(WIN32) diff -Nru bladerf-0.3.0+git20130911/host/cmake/modules/Version.cmake bladerf-0.3.0+git20130916/host/cmake/modules/Version.cmake --- bladerf-0.3.0+git20130911/host/cmake/modules/Version.cmake 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/cmake/modules/Version.cmake 2013-09-17 07:44:19.000000000 +0000 @@ -65,14 +65,14 @@ execute_process( COMMAND ${GIT_EXECUTABLE} diff-index --quiet HEAD -- - RESULT_VARIABLE GIT_NOT_DIRTY + RESULT_VARIABLE GIT_DIRTY WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) - if(GET_NOT_DIRTY) - set(GIT_STATE "") - else() + if(GIT_DIRTY) set(GIT_STATE "-dirty") + else() + set(GIT_STATE "") endif() else() diff -Nru bladerf-0.3.0+git20130911/host/common/include/bladerf_devinfo.h bladerf-0.3.0+git20130916/host/common/include/bladerf_devinfo.h --- bladerf-0.3.0+git20130911/host/common/include/bladerf_devinfo.h 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/common/include/bladerf_devinfo.h 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,96 @@ +#ifndef _BLADERF_DEVINFO_H_ +#define _BLADERF_DEVINFO_H_ + +#include "libbladeRF.h" +#include +#include + +/* Reserved values for bladerf_devinfo fields to indicate "undefined" */ +#define DEVINFO_SERIAL_ANY "ANY" +#define DEVINFO_BUS_ANY UINT8_MAX +#define DEVINFO_ADDR_ANY UINT8_MAX +#define DEVINFO_INST_ANY UINT_MAX + +struct bladerf_devinfo_list { + struct bladerf_devinfo *elt; + size_t num_elt; /* Number of elements in the list */ + size_t backing_size; /* Size of backing array */ +}; + +/** + * Initialize a bladerf_devinfo's fields to wildcards + */ +void bladerf_init_devinfo(struct bladerf_devinfo *d); + +/** + * Compare two devinfo's against each other. + * + * @param a Device information to compare + * @param b Device information to compare + * + * @return true on match, false otherwise + */ +bool bladerf_devinfo_matches(struct bladerf_devinfo *a, + struct bladerf_devinfo *b); + +/** + * Do the device instances for the two provided device info structures match + * (taking wildcards into account)? + * + * @param a Device information to compare + * @param b Device information to compare + * + * @return true on match, false otherwise + */ +bool bladerf_instance_matches(struct bladerf_devinfo *a, + struct bladerf_devinfo *b); + +/** + * Do the serials match for the two provided device info structures match + * (taking wildcards into account)? + * + * @param a Device information to compare + * @param b Device information to compare + * + * @return true on match, false otherwise + */ +bool bladerf_serial_matches(struct bladerf_devinfo *a, + struct bladerf_devinfo *b); + +/** + * Do the bus and addr match for the two provided device info structures match + * (taking wildcards into account)? + * + * @param a Device information to compare + * @param b Device information to compare + * + * @return true on match, false otherwise + */ +bool bladerf_bus_addr_matches(struct bladerf_devinfo *a, + struct bladerf_devinfo *b); + +/** + * Create list of deinfos + */ +int bladerf_devinfo_list_init(struct bladerf_devinfo_list *list); + +/** + * Get a pointer to the parent devinfo_list container of a devinfo + * + * @return pointer to container on success, NULL on error + */ +struct bladerf_devinfo_list * +bladerf_get_devinfo_list(struct bladerf_devinfo *devinfo); + +/** + * Add and item to our internal devinfo list + * + * @param list List to append to + * @param info Info to copy into the list + * + * 0 on success, BLADERF_ERR_* on failure + */ +int bladerf_devinfo_list_add(struct bladerf_devinfo_list *list, + struct bladerf_devinfo *info); + +#endif /* _BLADERF_DEVINFO_H_ */ diff -Nru bladerf-0.3.0+git20130911/host/common/include/device_identifier.h bladerf-0.3.0+git20130916/host/common/include/device_identifier.h --- bladerf-0.3.0+git20130911/host/common/include/device_identifier.h 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/common/include/device_identifier.h 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,22 @@ +/** + * Routines for parsing and handling device identifier strings + */ +#ifndef DEVICE_IDENTIFIER_H__ +#define DEVICE_IDENTIFIER_H__ + + +/** + * Fill out a device info structure based upon the provided device indentifer + * string. If a failure occurrs, the contents of d are undefined. + * + * For device identifier format, see the documentation for bladerf_open + * (in include/libbladeRF.h) + * + * @param[in] device_identifier Device identifier string + * @param[out] d Device info to fill in + * + * @return 0 on success, BLADERF_ERR_* on failure + */ +int str2devinfo(const char *device_identifier, struct bladerf_devinfo *d); + +#endif diff -Nru bladerf-0.3.0+git20130911/host/common/include/ezusb.h bladerf-0.3.0+git20130916/host/common/include/ezusb.h --- bladerf-0.3.0+git20130911/host/common/include/ezusb.h 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/common/include/ezusb.h 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,120 @@ +#ifndef __ezusb_H +#define __ezusb_H +/* + * Copyright © 2001 Stephen Williams (steve@icarus.com) + * Copyright © 2002 David Brownell (dbrownell@users.sourceforge.net) + * Copyright © 2013 Federico Manzan (f.manzan@gmail.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined(_MSC_VER) +#include +#else +#define __attribute__(x) +#if !defined(bool) +#define bool int +#endif +#if !defined(true) +#define true (1 == 1) +#endif +#if !defined(false) +#define false (!true) +#endif +#if defined(_PREFAST_) +#pragma warning(disable:28193) +#endif +#endif + +#define FX_TYPE_UNDEFINED -1 +#define FX_TYPE_AN21 0 /* Original AnchorChips parts */ +#define FX_TYPE_FX1 1 /* Updated Cypress versions */ +#define FX_TYPE_FX2 2 /* USB 2.0 versions */ +#define FX_TYPE_FX2LP 3 /* Updated FX2 */ +#define FX_TYPE_FX3 4 /* USB 3.0 versions */ +#define FX_TYPE_MAX 5 +#define FX_TYPE_NAMES { "an21", "fx", "fx2", "fx2lp", "fx3" } + +#define IMG_TYPE_UNDEFINED -1 +#define IMG_TYPE_HEX 0 /* Intel HEX */ +#define IMG_TYPE_IIC 1 /* Cypress 8051 IIC */ +#define IMG_TYPE_BIX 2 /* Cypress 8051 BIX */ +#define IMG_TYPE_IMG 3 /* Cypress IMG format */ +#define IMG_TYPE_MAX 4 +#define IMG_TYPE_NAMES { "Intel HEX", "Cypress 8051 IIC", "Cypress 8051 BIX", "Cypress IMG format" } + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Automatically identified devices (VID, PID, type, designation). + * TODO: Could use some validation. Also where's the FX2? + */ +typedef struct { + uint16_t vid; + uint16_t pid; + int type; + const char* designation; +} fx_known_device; + +#define FX_KNOWN_DEVICES { \ + { 0x0547, 0x2122, FX_TYPE_AN21, "Cypress EZ-USB (2122S)" },\ + { 0x0547, 0x2125, FX_TYPE_AN21, "Cypress EZ-USB (2121S/2125S)" },\ + { 0x0547, 0x2126, FX_TYPE_AN21, "Cypress EZ-USB (2126S)" },\ + { 0x0547, 0x2131, FX_TYPE_AN21, "Cypress EZ-USB (2131Q/2131S/2135S)" },\ + { 0x0547, 0x2136, FX_TYPE_AN21, "Cypress EZ-USB (2136S)" },\ + { 0x0547, 0x2225, FX_TYPE_AN21, "Cypress EZ-USB (2225)" },\ + { 0x0547, 0x2226, FX_TYPE_AN21, "Cypress EZ-USB (2226)" },\ + { 0x0547, 0x2235, FX_TYPE_AN21, "Cypress EZ-USB (2235)" },\ + { 0x0547, 0x2236, FX_TYPE_AN21, "Cypress EZ-USB (2236)" },\ + { 0x04b4, 0x6473, FX_TYPE_FX1, "Cypress EZ-USB FX1" },\ + { 0x04b4, 0x8613, FX_TYPE_FX2LP, "Cypress EZ-USB FX2LP (68013A/68014A/68015A/68016A)" }, \ + { 0x04b4, 0x00f3, FX_TYPE_FX3, "Cypress FX3" },\ +} + +/* + * This function uploads the firmware from the given file into RAM. + * Stage == 0 means this is a single stage load (or the first of + * two stages). Otherwise it's the second of two stages; the + * caller having preloaded the second stage loader. + * + * The target processor is reset at the end of this upload. + */ +extern int ezusb_load_ram(libusb_device_handle *device, + const char *path, int fx_type, int img_type, int stage); + +/* + * This function uploads the firmware from the given file into EEPROM. + * This uses the right CPUCS address to terminate the EEPROM load with + * a reset command where FX parts behave differently than FX2 ones. + * The configuration byte is as provided here (zero for an21xx parts) + * and the EEPROM type is set so that the microcontroller will boot + * from it. + * + * The caller must have preloaded a second stage loader that knows + * how to respond to the EEPROM write request. + */ +extern int ezusb_load_eeprom(libusb_device_handle *device, + const char *path, int fx_type, int img_type, int config); + +/* Verbosity level (default 1). Can be increased or decreased with options v/q */ +extern int verbose; + +#ifdef __cplusplus +} +#endif + +#endif diff -Nru bladerf-0.3.0+git20130911/host/common/include/host_config.h.in bladerf-0.3.0+git20130916/host/common/include/host_config.h.in --- bladerf-0.3.0+git20130911/host/common/include/host_config.h.in 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/common/include/host_config.h.in 2013-09-17 07:44:19.000000000 +0000 @@ -95,7 +95,7 @@ #define vsnprintf _vsnprintf #define strcasecmp _stricmp #define strncasecmp _strnicmp -#define usleep Sleep +#define usleep(x) Sleep((x)/1000) /* ssize_t lives elsewhere */ #include diff -Nru bladerf-0.3.0+git20130911/host/common/include/log.h bladerf-0.3.0+git20130916/host/common/include/log.h --- bladerf-0.3.0+git20130911/host/common/include/log.h 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/common/include/log.h 2013-09-17 07:44:19.000000000 +0000 @@ -43,10 +43,10 @@ do { log_write(LEVEL, LEVEL_STRING \ " @ " __FILE__ ":" _LOG_STRINGIFY_(__LINE__) "] " \ __VA_ARGS__); \ - } while (0); + } while (0) #else # define LOG_WRITE(LEVEL, LEVEL_STRING, ...) \ - do { log_write(LEVEL, LEVEL_STRING "] " __VA_ARGS__); } while (0); + do { log_write(LEVEL, LEVEL_STRING "] " __VA_ARGS__); } while (0) #endif /** diff -Nru bladerf-0.3.0+git20130911/host/common/include/windows/inttypes.h bladerf-0.3.0+git20130916/host/common/include/windows/inttypes.h --- bladerf-0.3.0+git20130911/host/common/include/windows/inttypes.h 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/common/include/windows/inttypes.h 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,306 @@ +// ISO C9x compliant inttypes.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_INTTYPES_H_ // [ +#define _MSC_INTTYPES_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "stdint.h" + +// 7.8 Format conversion of integer types + +typedef struct { + intmax_t quot; + intmax_t rem; +} imaxdiv_t; + +// 7.8.1 Macros for format specifiers + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 + +// The fprintf macros for signed integers are: +#define PRId8 "d" +#define PRIi8 "i" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" + +#define PRId16 "hd" +#define PRIi16 "hi" +#define PRIdLEAST16 "hd" +#define PRIiLEAST16 "hi" +#define PRIdFAST16 "hd" +#define PRIiFAST16 "hi" + +#define PRId32 "I32d" +#define PRIi32 "I32i" +#define PRIdLEAST32 "I32d" +#define PRIiLEAST32 "I32i" +#define PRIdFAST32 "I32d" +#define PRIiFAST32 "I32i" + +#define PRId64 "I64d" +#define PRIi64 "I64i" +#define PRIdLEAST64 "I64d" +#define PRIiLEAST64 "I64i" +#define PRIdFAST64 "I64d" +#define PRIiFAST64 "I64i" + +#define PRIdMAX "I64d" +#define PRIiMAX "I64i" + +#define PRIdPTR "Id" +#define PRIiPTR "Ii" + +// The fprintf macros for unsigned integers are: +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" + +#define PRIo16 "ho" +#define PRIu16 "hu" +#define PRIx16 "hx" +#define PRIX16 "hX" +#define PRIoLEAST16 "ho" +#define PRIuLEAST16 "hu" +#define PRIxLEAST16 "hx" +#define PRIXLEAST16 "hX" +#define PRIoFAST16 "ho" +#define PRIuFAST16 "hu" +#define PRIxFAST16 "hx" +#define PRIXFAST16 "hX" + +#define PRIo32 "I32o" +#define PRIu32 "I32u" +#define PRIx32 "I32x" +#define PRIX32 "I32X" +#define PRIoLEAST32 "I32o" +#define PRIuLEAST32 "I32u" +#define PRIxLEAST32 "I32x" +#define PRIXLEAST32 "I32X" +#define PRIoFAST32 "I32o" +#define PRIuFAST32 "I32u" +#define PRIxFAST32 "I32x" +#define PRIXFAST32 "I32X" + +#define PRIo64 "I64o" +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#define PRIX64 "I64X" +#define PRIoLEAST64 "I64o" +#define PRIuLEAST64 "I64u" +#define PRIxLEAST64 "I64x" +#define PRIXLEAST64 "I64X" +#define PRIoFAST64 "I64o" +#define PRIuFAST64 "I64u" +#define PRIxFAST64 "I64x" +#define PRIXFAST64 "I64X" + +#define PRIoMAX "I64o" +#define PRIuMAX "I64u" +#define PRIxMAX "I64x" +#define PRIXMAX "I64X" + +#define PRIoPTR "Io" +#define PRIuPTR "Iu" +#define PRIxPTR "Ix" +#define PRIXPTR "IX" + +// The fscanf macros for signed integers are: +#define SCNd8 "d" +#define SCNi8 "i" +#define SCNdLEAST8 "d" +#define SCNiLEAST8 "i" +#define SCNdFAST8 "d" +#define SCNiFAST8 "i" + +#define SCNd16 "hd" +#define SCNi16 "hi" +#define SCNdLEAST16 "hd" +#define SCNiLEAST16 "hi" +#define SCNdFAST16 "hd" +#define SCNiFAST16 "hi" + +#define SCNd32 "ld" +#define SCNi32 "li" +#define SCNdLEAST32 "ld" +#define SCNiLEAST32 "li" +#define SCNdFAST32 "ld" +#define SCNiFAST32 "li" + +#define SCNd64 "I64d" +#define SCNi64 "I64i" +#define SCNdLEAST64 "I64d" +#define SCNiLEAST64 "I64i" +#define SCNdFAST64 "I64d" +#define SCNiFAST64 "I64i" + +#define SCNdMAX "I64d" +#define SCNiMAX "I64i" + +#ifdef _WIN64 // [ +# define SCNdPTR "I64d" +# define SCNiPTR "I64i" +#else // _WIN64 ][ +# define SCNdPTR "ld" +# define SCNiPTR "li" +#endif // _WIN64 ] + +// The fscanf macros for unsigned integers are: +#define SCNo8 "o" +#define SCNu8 "u" +#define SCNx8 "x" +#define SCNX8 "X" +#define SCNoLEAST8 "o" +#define SCNuLEAST8 "u" +#define SCNxLEAST8 "x" +#define SCNXLEAST8 "X" +#define SCNoFAST8 "o" +#define SCNuFAST8 "u" +#define SCNxFAST8 "x" +#define SCNXFAST8 "X" + +#define SCNo16 "ho" +#define SCNu16 "hu" +#define SCNx16 "hx" +#define SCNX16 "hX" +#define SCNoLEAST16 "ho" +#define SCNuLEAST16 "hu" +#define SCNxLEAST16 "hx" +#define SCNXLEAST16 "hX" +#define SCNoFAST16 "ho" +#define SCNuFAST16 "hu" +#define SCNxFAST16 "hx" +#define SCNXFAST16 "hX" + +#define SCNo32 "lo" +#define SCNu32 "lu" +#define SCNx32 "lx" +#define SCNX32 "lX" +#define SCNoLEAST32 "lo" +#define SCNuLEAST32 "lu" +#define SCNxLEAST32 "lx" +#define SCNXLEAST32 "lX" +#define SCNoFAST32 "lo" +#define SCNuFAST32 "lu" +#define SCNxFAST32 "lx" +#define SCNXFAST32 "lX" + +#define SCNo64 "I64o" +#define SCNu64 "I64u" +#define SCNx64 "I64x" +#define SCNX64 "I64X" +#define SCNoLEAST64 "I64o" +#define SCNuLEAST64 "I64u" +#define SCNxLEAST64 "I64x" +#define SCNXLEAST64 "I64X" +#define SCNoFAST64 "I64o" +#define SCNuFAST64 "I64u" +#define SCNxFAST64 "I64x" +#define SCNXFAST64 "I64X" + +#define SCNoMAX "I64o" +#define SCNuMAX "I64u" +#define SCNxMAX "I64x" +#define SCNXMAX "I64X" + +#ifdef _WIN64 // [ +# define SCNoPTR "I64o" +# define SCNuPTR "I64u" +# define SCNxPTR "I64x" +# define SCNXPTR "I64X" +#else // _WIN64 ][ +# define SCNoPTR "lo" +# define SCNuPTR "lu" +# define SCNxPTR "lx" +# define SCNXPTR "lX" +#endif // _WIN64 ] + +#endif // __STDC_FORMAT_MACROS ] + +// 7.8.2 Functions for greatest-width integer types + +// 7.8.2.1 The imaxabs function +#define imaxabs _abs64 + +// 7.8.2.2 The imaxdiv function + +// This is modified version of div() function from Microsoft's div.c found +// in %MSVC.NET%\crt\src\div.c +#ifdef STATIC_IMAXDIV // [ +static +#else // STATIC_IMAXDIV ][ +_inline +#endif // STATIC_IMAXDIV ] +imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) +{ + imaxdiv_t result; + + result.quot = numer / denom; + result.rem = numer % denom; + + if (numer < 0 && result.rem > 0) { + // did division wrong; must fix up + ++result.quot; + result.rem -= denom; + } + + return result; +} + +// 7.8.2.3 The strtoimax and strtoumax functions +#define strtoimax _strtoi64 +#define strtoumax _strtoui64 + +// 7.8.2.4 The wcstoimax and wcstoumax functions +#define wcstoimax _wcstoi64 +#define wcstoumax _wcstoui64 + + +#endif // _MSC_INTTYPES_H_ ] diff -Nru bladerf-0.3.0+git20130911/host/common/src/bladerf_devinfo.c bladerf-0.3.0+git20130916/host/common/src/bladerf_devinfo.c --- bladerf-0.3.0+git20130911/host/common/src/bladerf_devinfo.c 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/common/src/bladerf_devinfo.c 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,93 @@ +#include "bladerf_devinfo.h" + +void bladerf_init_devinfo(struct bladerf_devinfo *d) +{ + d->backend = BLADERF_BACKEND_ANY; + strcpy(d->serial, DEVINFO_SERIAL_ANY); + d->usb_bus = DEVINFO_BUS_ANY; + d->usb_addr = DEVINFO_ADDR_ANY; + d->instance = DEVINFO_INST_ANY; +} + +bool bladerf_devinfo_matches(struct bladerf_devinfo *a, + struct bladerf_devinfo *b) +{ + return + bladerf_instance_matches(a,b) && + bladerf_serial_matches(a,b) && + bladerf_bus_addr_matches(a,b); +} + +bool bladerf_instance_matches(struct bladerf_devinfo *a, + struct bladerf_devinfo *b) +{ + return a->instance == DEVINFO_INST_ANY || + b->instance == DEVINFO_INST_ANY || + a->instance == b->instance; +} + +bool bladerf_serial_matches(struct bladerf_devinfo *a, + struct bladerf_devinfo *b) +{ + return !strcmp(a->serial, DEVINFO_SERIAL_ANY) || + !strcmp(b->serial, DEVINFO_SERIAL_ANY) || + !strcmp(a->serial, b->serial); +} + +bool bladerf_bus_addr_matches(struct bladerf_devinfo *a, + struct bladerf_devinfo *b) +{ + bool bus_match, addr_match; + + bus_match = a->usb_bus == DEVINFO_BUS_ANY || + b->usb_bus == DEVINFO_BUS_ANY || + a->usb_bus == b->usb_bus; + + addr_match = a->usb_addr == DEVINFO_BUS_ANY || + b->usb_addr == DEVINFO_BUS_ANY || + a->usb_addr == b->usb_addr; + + return bus_match && addr_match; +} + +int bladerf_devinfo_list_init(struct bladerf_devinfo_list *list) +{ + int status = 0; + + list->num_elt = 0; + list->backing_size = 5; + + list->elt = malloc(list->backing_size * sizeof(struct bladerf_devinfo)); + + if (!list->elt) { + free(list); + status = BLADERF_ERR_MEM; + } + + return status; +} + +int bladerf_devinfo_list_add(struct bladerf_devinfo_list *list, + struct bladerf_devinfo *info) +{ + int status = 0; + struct bladerf_devinfo *info_tmp; + + if (list->num_elt >= list->backing_size) { + info_tmp = realloc(list->elt, list->backing_size * 2); + if (!info_tmp) { + status = BLADERF_ERR_MEM; + } else { + list->elt = info_tmp; + } + } + + if (status == 0) { + memcpy(&list->elt[list->num_elt], info, sizeof(*info)); + list->num_elt++; + } + + return status; +} + + diff -Nru bladerf-0.3.0+git20130911/host/common/src/device_identifier.c bladerf-0.3.0+git20130916/host/common/src/device_identifier.c --- bladerf-0.3.0+git20130911/host/common/src/device_identifier.c 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/common/src/device_identifier.c 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,210 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "device_identifier.h" +#include "bladerf_devinfo.h" +#include "conversions.h" +#include "log.h" + +#define DELIM_SPACE " \t\r\n\v\f" + + +static int handle_backend(char *str, struct bladerf_devinfo *d) +{ + int status = 0; + char *str_end; + + if (!str || strlen(str) == 0) { + return BLADERF_ERR_INVAL; + } + + + /* Gobble up any leading whitespace */ + while (*str && isspace(*str)) { + str++; + }; + + /* Likewise for trailing whitespace */ + str_end = str + strlen(str) - 1; + while (str_end > str && isspace(*str_end)) { str_end--; }; + str_end[1] = '\0'; + + if (!strcasecmp("libusb", str)) { + d->backend = BLADERF_BACKEND_LIBUSB; + } else if (!strcasecmp("linux", str)) { + d->backend = BLADERF_BACKEND_LINUX; + } else { + log_error("Invalid backend: %s\n", str); + status = BLADERF_ERR_INVAL; + } + + return status; +} + +static int handle_device(struct bladerf_devinfo *d, char *value) +{ + int status = BLADERF_ERR_INVAL; + bool bus_ok, addr_ok; + char *bus = value; + char *addr = strchr(value, ':'); + + if (addr && addr[1] != '\0') { + + /* Null-terminate bus and set addr to start of addr text */ + *addr = '\0'; + addr++; + + d->usb_bus = str2uint(bus, 0, DEVINFO_BUS_ANY - 1, &bus_ok); + d->usb_addr = str2uint(addr, 0, DEVINFO_ADDR_ANY - 1, &addr_ok); + + if (bus_ok && addr_ok) { + status = 0; + log_info("Device: %d:%d\n", d->usb_bus, d->usb_addr); + } else { + log_error("Bad bus (%s) or address (%s)\n", bus, addr); + } + } + + return status; +} + +static int handle_instance(struct bladerf_devinfo *d, char *value) +{ + bool ok; + + d->instance = str2uint(value, 0, DEVINFO_INST_ANY - 1, &ok); + if (!ok) { + log_error("Bad instance: %s\n", value); + return BLADERF_ERR_INVAL; + } else { + log_info("Instance: %u\n", d->instance); + return 0; + } +} + +static int handle_serial(struct bladerf_devinfo *d, char *value) +{ + char c; + int i; + + if (strlen(value) != 32) { + return BLADERF_ERR_INVAL; + } + + for (i = 0; i < 32; i++) { + c = value[i]; + if (c >= 'A' && c <='F') { + value[i] = tolower(c); + } + if ((c < 'a' || c > 'f') && (c < '0' || c > '9')) { + log_error("Bad serial: %s\n", value); + return BLADERF_ERR_INVAL; + } + } + + strncpy(d->serial, value, 32); + d->serial[32] = 0; + + log_info("Serial 0x%s\n", d->serial); + return 0; +} + +/* Returns: 1 on arg and value populated + * 0 on no args left + * BLADERF_ERR_INVAL on bad format + */ + +static int next_arg(char **saveptr, char **arg, char **value) +{ + char *saveptr_local; + char *token = strtok_r(NULL, DELIM_SPACE, saveptr); + + /* No arguments left */ + if (!token) { + return 0; + } + + /* Argument name */ + *arg = strtok_r(token, "=", &saveptr_local); + + if (!*arg) { + return BLADERF_ERR_INVAL; + } + + /* Argument value - gobble up the rest of the line*/ + *value = strtok_r(NULL, "", &saveptr_local); + + if (!*value) { + return BLADERF_ERR_INVAL; + } + + return 1; +} + +int str2devinfo(const char *dev_id_const, struct bladerf_devinfo *d) +{ + char *dev_id, *token, *arg, *val, *saveptr; + int status, arg_status; + + assert(d); + + /* Prep our device info before we begin manpulating it, defaulting to + * a "wildcard" device indentification */ + bladerf_init_devinfo(d); + + /* No device indentifier -- pick anything we can find */ + if ( dev_id_const == NULL || strlen(dev_id_const) == 0) { + return 0; + } + + /* Copy the string so we can butcher it a bit while parsing */ + dev_id = strdup(dev_id_const); + if (!dev_id) { + return BLADERF_ERR_MEM; + } + + /* Extract backend */ + token = strtok_r(dev_id, ":", &saveptr); + + /* We require a valid backend -- args only is not supported */ + if (token) { + status = handle_backend(token, d); + + /* Loop over remainder of string, gathering up args */ + arg_status = 1; + while (arg_status == 1 && status == 0) { + arg_status = next_arg(&saveptr, &arg, &val); + if (arg_status == 1) { + + /* Handle argument if we can */ + if (!strcasecmp("device", arg)) { + status = handle_device(d, val); + } else if (!strcasecmp("instance", arg)) { + status = handle_instance(d, val); + } else if (!strcasecmp("serial", arg)) { + status = handle_serial(d, val); + } else { + arg_status = BLADERF_ERR_INVAL; + } + } + }; + + if (arg_status < 0) { + status = arg_status; + } + + } else { + status = BLADERF_ERR_INVAL; + } + + free(dev_id); + return status; +} diff -Nru bladerf-0.3.0+git20130911/host/common/src/ezusb.c bladerf-0.3.0+git20130916/host/common/src/ezusb.c --- bladerf-0.3.0+git20130911/host/common/src/ezusb.c 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/common/src/ezusb.c 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,780 @@ +/* + * Copyright © 2001 Stephen Williams (steve@icarus.com) + * Copyright © 2001-2002 David Brownell (dbrownell@users.sourceforge.net) + * Copyright © 2008 Roger Williams (rawqux@users.sourceforge.net) + * Copyright © 2012 Pete Batard (pete@akeo.ie) + * Copyright © 2013 Federico Manzan (f.manzan@gmail.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#include +#include +#include +#include +#include + +#include +#include "log.h" +#include "ezusb.h" + +/* + * This file contains functions for uploading firmware into Cypress + * EZ-USB microcontrollers. These chips use control endpoint 0 and vendor + * specific commands to support writing into the on-chip SRAM. They also + * support writing into the CPUCS register, which is how we reset the + * processor after loading firmware (including the reset vector). + * + * These Cypress devices are 8-bit 8051 based microcontrollers with + * special support for USB I/O. They come in several packages, and + * some can be set up with external memory when device costs allow. + * Note that the design was originally by AnchorChips, so you may find + * references to that vendor (which was later merged into Cypress). + * The Cypress FX parts are largely compatible with the Anchorhip ones. + */ + +/* + * return true if [addr,addr+len] includes external RAM + * for Anchorchips EZ-USB or Cypress EZ-USB FX + */ +static bool fx_is_external(uint32_t addr, size_t len) +{ + /* with 8KB RAM, 0x0000-0x1b3f can be written + * we can't tell if it's a 4KB device here + */ + if (addr <= 0x1b3f) + return ((addr + len) > 0x1b40); + + /* there may be more RAM; unclear if we can write it. + * some bulk buffers may be unused, 0x1b3f-0x1f3f + * firmware can set ISODISAB for 2KB at 0x2000-0x27ff + */ + return true; +} + +/* + * return true if [addr,addr+len] includes external RAM + * for Cypress EZ-USB FX2 + */ +static bool fx2_is_external(uint32_t addr, size_t len) +{ + /* 1st 8KB for data/code, 0x0000-0x1fff */ + if (addr <= 0x1fff) + return ((addr + len) > 0x2000); + + /* and 512 for data, 0xe000-0xe1ff */ + else if (addr >= 0xe000 && addr <= 0xe1ff) + return ((addr + len) > 0xe200); + + /* otherwise, it's certainly external */ + else + return true; +} + +/* + * return true if [addr,addr+len] includes external RAM + * for Cypress EZ-USB FX2LP + */ +static bool fx2lp_is_external(uint32_t addr, size_t len) +{ + /* 1st 16KB for data/code, 0x0000-0x3fff */ + if (addr <= 0x3fff) + return ((addr + len) > 0x4000); + + /* and 512 for data, 0xe000-0xe1ff */ + else if (addr >= 0xe000 && addr <= 0xe1ff) + return ((addr + len) > 0xe200); + + /* otherwise, it's certainly external */ + else + return true; +} + + +/*****************************************************************************/ + +/* + * These are the requests (bRequest) that the bootstrap loader is expected + * to recognize. The codes are reserved by Cypress, and these values match + * what EZ-USB hardware, or "Vend_Ax" firmware (2nd stage loader) uses. + * Cypress' "a3load" is nice because it supports both FX and FX2, although + * it doesn't have the EEPROM support (subset of "Vend_Ax"). + */ +#define RW_INTERNAL 0xA0 /* hardware implements this one */ +#define RW_MEMORY 0xA3 + +/* + * Issues the specified vendor-specific write request. + */ +static int ezusb_write(libusb_device_handle *device, const char *label, + uint8_t opcode, uint32_t addr, const unsigned char *data, size_t len) +{ + int status; + + log_debug("%s, addr 0x%08x len %4u (0x%04x)\n", label, addr, (unsigned)len, (unsigned)len); + + status = libusb_control_transfer(device, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + opcode, addr & 0xFFFF, addr >> 16, + (unsigned char*)data, (uint16_t)len, 1000); + if (status != (ssize_t)len) { + if (status < 0) + log_error("%s: %s\n", label, libusb_error_name(status)); + else + log_info("%s ==> %d\n", label, status); + } + return (status < 0) ? -EIO : 0; +} + +/* + * Issues the specified vendor-specific read request. + */ +static int ezusb_read(libusb_device_handle *device, const char *label, + uint8_t opcode, uint32_t addr, const unsigned char *data, size_t len) +{ + int status; + + log_debug("%s, addr 0x%08x len %4u (0x%04x)\n", label, addr, (unsigned)len, (unsigned)len); + + status = libusb_control_transfer(device, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + opcode, addr & 0xFFFF, addr >> 16, + (unsigned char*)data, (uint16_t)len, 1000); + if (status != (ssize_t)len) { + if (status < 0) + log_error("%s: %s\n", label, libusb_error_name(status)); + else + log_info("%s ==> %d\n", label, status); + } + return (status < 0) ? -EIO : 0; +} + +/* + * Modifies the CPUCS register to stop or reset the CPU. + * Returns false on error. + */ +static bool ezusb_cpucs(libusb_device_handle *device, uint32_t addr, bool doRun) +{ + int status; + uint8_t data = doRun ? 0x00 : 0x01; + + log_info("%s\n", data ? "stop CPU" : "reset CPU"); + + status = libusb_control_transfer(device, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + RW_INTERNAL, addr & 0xFFFF, addr >> 16, + &data, 1, 1000); + if ((status != 1) && + /* We may get an I/O error from libusbx as the device disappears */ + ((!doRun) || (status != LIBUSB_ERROR_IO))) + { + const char *mesg = "can't modify CPUCS"; + if (status < 0) + log_error("%s: %s\n", mesg, libusb_error_name(status)); + else + log_info("%s\n", mesg); + return false; + } else + return true; +} + +/* + * Send an FX3 jumpt to address command + * Returns false on error. + */ +static bool ezusb_fx3_jump(libusb_device_handle *device, uint32_t addr) +{ + int status; + + log_info("transfer execution to Program Entry at 0x%08x\n", addr); + + status = libusb_control_transfer(device, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + RW_INTERNAL, addr & 0xFFFF, addr >> 16, + NULL, 0, 1000); + /* We may get an I/O error from libusbx as the device disappears */ + if ((status != 0) && (status != LIBUSB_ERROR_IO)) + { + const char *mesg = "failed to send jump command"; + if (status < 0) + log_error("%s: %s\n", mesg, libusb_error_name(status)); + else + log_info("%s\n", mesg); + return false; + } else + return true; +} + +/*****************************************************************************/ + +/* + * Parse an Intel HEX image file and invoke the poke() function on the + * various segments to implement policies such as writing to RAM (with + * a one or two stage loader setup, depending on the firmware) or to + * EEPROM (two stages required). + * + * image - the hex image file + * context - for use by poke() + * is_external - if non-null, used to check which segments go into + * external memory (writable only by software loader) + * poke - called with each memory segment; errors indicated + * by returning negative values. + * + * Caller is responsible for halting CPU as needed, such as when + * overwriting a second stage loader. + */ +static int parse_ihex(FILE *image, void *context, + bool (*is_external)(uint32_t addr, size_t len), + int (*poke) (void *context, uint32_t addr, bool external, + const unsigned char *data, size_t len)) +{ + unsigned char data[1023]; + uint32_t data_addr = 0; + size_t data_len = 0; + int rc; + int first_line = 1; + bool external = false; + + /* Read the input file as an IHEX file, and report the memory segments + * as we go. Each line holds a max of 16 bytes, but uploading is + * faster (and EEPROM space smaller) if we merge those lines into larger + * chunks. Most hex files keep memory segments together, which makes + * such merging all but free. (But it may still be worth sorting the + * hex files to make up for undesirable behavior from tools.) + * + * Note that EEPROM segments max out at 1023 bytes; the upload protocol + * allows segments of up to 64 KBytes (more than a loader could handle). + */ + for (;;) { + char buf[512], *cp; + char tmp, type; + size_t len; + unsigned idx, off; + + cp = fgets(buf, sizeof(buf), image); + if (cp == NULL) { + log_error("EOF without EOF record!\n"); + break; + } + + /* EXTENSION: "# comment-till-end-of-line", for copyrights etc */ + if (buf[0] == '#') + continue; + + if (buf[0] != ':') { + log_error("not an ihex record: %s", buf); + return -2; + } + + /* ignore any newline */ + cp = strchr(buf, '\n'); + if (cp) + *cp = 0; + + log_verbose("** LINE: %s\n", buf); + + /* Read the length field (up to 16 bytes) */ + tmp = buf[3]; + buf[3] = 0; + len = strtoul(buf+1, NULL, 16); + buf[3] = tmp; + + /* Read the target offset (address up to 64KB) */ + tmp = buf[7]; + buf[7] = 0; + off = (int)strtoul(buf+3, NULL, 16); + buf[7] = tmp; + + /* Initialize data_addr */ + if (first_line) { + data_addr = off; + first_line = 0; + } + + /* Read the record type */ + tmp = buf[9]; + buf[9] = 0; + type = (char)strtoul(buf+7, NULL, 16); + buf[9] = tmp; + + /* If this is an EOF record, then make it so. */ + if (type == 1) { + log_verbose("EOF on hexfile\n"); + break; + } + + if (type != 0) { + log_error("unsupported record type: %u\n", type); + return -3; + } + + if ((len * 2) + 11 > strlen(buf)) { + log_error("record too short?\n"); + return -4; + } + + /* FIXME check for _physically_ contiguous not just virtually + * e.g. on FX2 0x1f00-0x2100 includes both on-chip and external + * memory so it's not really contiguous */ + + /* flush the saved data if it's not contiguous, + * or when we've buffered as much as we can. + */ + if (data_len != 0 + && (off != (data_addr + data_len) + /* || !merge */ + || (data_len + len) > sizeof(data))) { + if (is_external) + external = is_external(data_addr, data_len); + rc = poke(context, data_addr, external, data, data_len); + if (rc < 0) + return -1; + data_addr = off; + data_len = 0; + } + + /* append to saved data, flush later */ + for (idx = 0, cp = buf+9 ; idx < len ; idx += 1, cp += 2) { + tmp = cp[2]; + cp[2] = 0; + data[data_len + idx] = (uint8_t)strtoul(cp, NULL, 16); + cp[2] = tmp; + } + data_len += len; + } + + + /* flush any data remaining */ + if (data_len != 0) { + if (is_external) + external = is_external(data_addr, data_len); + rc = poke(context, data_addr, external, data, data_len); + if (rc < 0) + return -1; + } + return 0; +} + +/* + * Parse a binary image file and write it as is to the target. + * Applies to Cypress BIX images for RAM or Cypress IIC images + * for EEPROM. + * + * image - the BIX image file + * context - for use by poke() + * is_external - if non-null, used to check which segments go into + * external memory (writable only by software loader) + * poke - called with each memory segment; errors indicated + * by returning negative values. + * + * Caller is responsible for halting CPU as needed, such as when + * overwriting a second stage loader. + */ +static int parse_bin(FILE *image, void *context, + bool (*is_external)(uint32_t addr, size_t len), int (*poke)(void *context, + uint32_t addr, bool external, const unsigned char *data, size_t len)) +{ + unsigned char data[4096]; + uint32_t data_addr = 0; + size_t data_len = 0; + int rc; + bool external = false; + + for (;;) { + data_len = fread(data, 1, 4096, image); + if (data_len == 0) + break; + if (is_external) + external = is_external(data_addr, data_len); + rc = poke(context, data_addr, external, data, data_len); + if (rc < 0) + return -1; + data_addr += (uint32_t)data_len; + } + return feof(image)?0:-1; +} + +/* + * Parse a Cypress IIC image file and invoke the poke() function on the + * various segments for writing to RAM + * + * image - the IIC image file + * context - for use by poke() + * is_external - if non-null, used to check which segments go into + * external memory (writable only by software loader) + * poke - called with each memory segment; errors indicated + * by returning negative values. + * + * Caller is responsible for halting CPU as needed, such as when + * overwriting a second stage loader. + */ +static int parse_iic(FILE *image, void *context, + bool (*is_external)(uint32_t addr, size_t len), + int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data, size_t len)) +{ + unsigned char data[4096]; + uint32_t data_addr = 0; + size_t data_len = 0, read_len; + uint8_t block_header[4]; + int rc; + bool external = false; + long file_size, initial_pos = ftell(image); + + fseek(image, 0L, SEEK_END); + file_size = ftell(image); + fseek(image, initial_pos, SEEK_SET); + for (;;) { + /* Ignore the trailing reset IIC data (5 bytes) */ + if (ftell(image) >= (file_size - 5)) + break; + if (fread(&block_header, 1, sizeof(block_header), image) != 4) { + log_error("unable to read IIC block header\n"); + return -1; + } + data_len = (block_header[0] << 8) + block_header[1]; + data_addr = (block_header[2] << 8) + block_header[3]; + if (data_len > sizeof(data)) { + /* If this is ever reported as an error, switch to using malloc/realloc */ + log_error("IIC data block too small - please report this error to libusbx.org\n"); + return -1; + } + read_len = fread(data, 1, data_len, image); + if (read_len != data_len) { + log_error("read error\n"); + return -1; + } + if (is_external) + external = is_external(data_addr, data_len); + rc = poke(context, data_addr, external, data, data_len); + if (rc < 0) + return -1; + } + return 0; +} + +/* the parse call will be selected according to the image type */ +static int (*parse[IMG_TYPE_MAX])(FILE *image, void *context, bool (*is_external)(uint32_t addr, size_t len), + int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data, size_t len)) + = { parse_ihex, parse_iic, parse_bin }; + +/*****************************************************************************/ + +/* + * For writing to RAM using a first (hardware) or second (software) + * stage loader and 0xA0 or 0xA3 vendor requests + */ +typedef enum { + _undef = 0, + internal_only, /* hardware first-stage loader */ + skip_internal, /* first phase, second-stage loader */ + skip_external /* second phase, second-stage loader */ +} ram_mode; + +struct ram_poke_context { + libusb_device_handle *device; + ram_mode mode; + size_t total, count; +}; + +#define RETRY_LIMIT 5 + +static int ram_poke(void *context, uint32_t addr, bool external, + const unsigned char *data, size_t len) +{ + struct ram_poke_context *ctx = (struct ram_poke_context*)context; + int rc; + unsigned retry = 0; + + switch (ctx->mode) { + case internal_only: /* CPU should be stopped */ + if (external) { + log_error("can't write %u bytes external memory at 0x%08x\n", + (unsigned)len, addr); + return -EINVAL; + } + break; + case skip_internal: /* CPU must be running */ + if (!external) { + log_debug("SKIP on-chip RAM, %u bytes at 0x%08x\n", + (unsigned)len, addr); + return 0; + } + break; + case skip_external: /* CPU should be stopped */ + if (external) { + log_debug("SKIP external RAM, %u bytes at 0x%08x\n", + (unsigned)len, addr); + return 0; + } + break; + case _undef: + default: + log_error("bug\n"); + return -EDOM; + } + + ctx->total += len; + ctx->count++; + + /* Retry this till we get a real error. Control messages are not + * NAKed (just dropped) so time out means is a real problem. + */ + while ((rc = ezusb_write(ctx->device, + external ? "write external" : "write on-chip", + external ? RW_MEMORY : RW_INTERNAL, + addr, data, len)) < 0 + && retry < RETRY_LIMIT) { + if (rc != LIBUSB_ERROR_TIMEOUT) + break; + retry += 1; + } + return rc; +} + +/* + * Load a Cypress Image file into target RAM. + * See http://www.cypress.com/?docID=41351 (AN76405 PDF) for more info. + */ +static int fx3_load_ram(libusb_device_handle *device, const char *path) +{ + uint32_t dCheckSum, dExpectedCheckSum, dAddress, i, dLen, dLength; + uint32_t* dImageBuf; + unsigned char *bBuf, hBuf[4], blBuf[4], rBuf[4096]; + FILE *image; + + image = fopen(path, "rb"); + if (image == NULL) { + log_error("unable to open '%s' for input\n", path); + return -2; + } else + log_info("open firmware image %s for RAM upload\n", path); + + // Read header + if (fread(hBuf, sizeof(char), sizeof(hBuf), image) != sizeof(hBuf)) { + log_error("could not read image header"); + return -3; + } + + // check "CY" signature byte and format + if ((hBuf[0] != 'C') || (hBuf[1] != 'Y')) { + log_error("image doesn't have a CYpress signature\n"); + return -3; + } + + // Check bImageType + switch(hBuf[3]) { + case 0xB0: + log_info("normal FW binary %s image with checksum\n", (hBuf[2]&0x01)?"data":"executable"); + break; + case 0xB1: + log_error("security binary image is not currently supported\n"); + return -3; + case 0xB2: + log_error("VID:PID image is not currently supported\n"); + return -3; + default: + log_error("invalid image type 0x%02X\n", hBuf[3]); + return -3; + } + + // Read the bootloader version + if ((ezusb_read(device, "read bootloader version", RW_INTERNAL, 0xFFFF0020, blBuf, 4) < 0)) { + log_error("Could not read bootloader version\n"); + return -8; + } + log_info("FX3 bootloader version: 0x%02X%02X%02X%02X\n", blBuf[3], blBuf[2], blBuf[1], blBuf[0]); + + dCheckSum = 0; + log_info("writing image...\n"); + + while (1) { + if ((fread(&dLength, sizeof(uint32_t), 1, image) != 1) || // read dLength + (fread(&dAddress, sizeof(uint32_t), 1, image) != 1)) { // read dAddress + log_error("could not read image"); + return -3; + } + if (dLength == 0) + break; // done + + dImageBuf = calloc(dLength, sizeof(uint32_t)); + if (dImageBuf == NULL) { + log_error("could not allocate buffer for image chunk\n"); + return -4; + } + + // read sections + if (fread(dImageBuf, sizeof(uint32_t), dLength, image) != dLength) { + log_error("could not read image"); + free(dImageBuf); + return -3; + } + for (i = 0; i < dLength; i++) + dCheckSum += dImageBuf[i]; + dLength <<= 2; // convert to Byte length + bBuf = (unsigned char*) dImageBuf; + + while (dLength > 0) { + dLen = 4096; // 4K max + if (dLen > dLength) + dLen = dLength; + if ((ezusb_write(device, "write firmware", RW_INTERNAL, dAddress, bBuf, dLen) < 0) || + (ezusb_read(device, "read firmware", RW_INTERNAL, dAddress, rBuf, dLen) < 0)) { + log_error("R/W error\n"); + free(dImageBuf); + return -5; + } + // Verify data: rBuf with bBuf + for (i = 0; i < dLen; i++) { + if (rBuf[i] != bBuf[i]) { + log_error("verify error"); + free(dImageBuf); + return -6; + } + } + + dLength -= dLen; + bBuf += dLen; + dAddress += dLen; + } + free(dImageBuf); + } + + // read pre-computed checksum data + if ((fread(&dExpectedCheckSum, sizeof(uint32_t), 1, image) != 1) || + (dCheckSum != dExpectedCheckSum)) { + log_error("checksum error\n"); + return -7; + } + + // transfer execution to Program Entry + if (!ezusb_fx3_jump(device, dAddress)) { + return -6; + } + + return 0; +} + +/* + * Load a firmware file into target RAM. device is the open libusbx + * device, and the path is the name of the source file. Open the file, + * parse the bytes, and write them in one or two phases. + * + * If stage == 0, this uses the first stage loader, built into EZ-USB + * hardware but limited to writing on-chip memory or CPUCS. Everything + * is written during one stage, unless there's an error such as the image + * holding data that needs to be written to external memory. + * + * Otherwise, things are written in two stages. First the external + * memory is written, expecting a second stage loader to have already + * been loaded. Then file is re-parsed and on-chip memory is written. + */ +int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, int img_type, int stage) +{ + FILE *image; + uint32_t cpucs_addr; + bool (*is_external)(uint32_t off, size_t len); + struct ram_poke_context ctx; + int status; + uint8_t iic_header[8] = { 0 }; + + if (fx_type == FX_TYPE_FX3) + return fx3_load_ram(device, path); + + image = fopen(path, "rb"); + if (image == NULL) { + log_error("%s: unable to open for input.\n", path); + return -2; + } else + log_debug("open firmware image %s for RAM upload\n", path); + + if (img_type == IMG_TYPE_IIC) { + if ( (fread(iic_header, 1, sizeof(iic_header), image) != sizeof(iic_header)) + || (((fx_type == FX_TYPE_FX2LP) || (fx_type == FX_TYPE_FX2)) && (iic_header[0] != 0xC2)) + || ((fx_type == FX_TYPE_AN21) && (iic_header[0] != 0xB2)) + || ((fx_type == FX_TYPE_FX1) && (iic_header[0] != 0xB6)) ) { + log_error("IIC image does not contain executable code - cannot load to RAM.\n"); + return -1; + } + } + + /* EZ-USB original/FX and FX2 devices differ, apart from the 8051 core */ + switch(fx_type) { + case FX_TYPE_FX2LP: + cpucs_addr = 0xe600; + is_external = fx2lp_is_external; + break; + case FX_TYPE_FX2: + cpucs_addr = 0xe600; + is_external = fx2_is_external; + break; + default: + cpucs_addr = 0x7f92; + is_external = fx_is_external; + break; + } + + /* use only first stage loader? */ + if (stage == 0) { + ctx.mode = internal_only; + + /* if required, halt the CPU while we overwrite its code/data */ + if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, false)) + return -1; + + /* 2nd stage, first part? loader was already uploaded */ + } else { + ctx.mode = skip_internal; + + /* let CPU run; overwrite the 2nd stage loader later */ + log_info("2nd stage: write external memory\n"); + } + + /* scan the image, first (maybe only) time */ + ctx.device = device; + ctx.total = ctx.count = 0; + status = parse[img_type](image, &ctx, is_external, ram_poke); + if (status < 0) { + log_error("unable to upload %s\n", path); + return status; + } + + /* second part of 2nd stage: rescan */ + // TODO: what should we do for non HEX images there? + if (stage) { + ctx.mode = skip_external; + + /* if needed, halt the CPU while we overwrite the 1st stage loader */ + if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, false)) + return -1; + + /* at least write the interrupt vectors (at 0x0000) for reset! */ + rewind(image); + log_info("2nd stage: write on-chip memory\n"); + status = parse_ihex(image, &ctx, is_external, ram_poke); + if (status < 0) { + log_error("unable to completely upload %s\n", path); + return status; + } + } + + log_info("... WROTE: %d bytes, %d segments, avg %d\n", + (int)ctx.total, (int)ctx.count, (int)(ctx.total/ctx.count)); + + /* if required, reset the CPU so it runs what we just uploaded */ + if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, true)) + return -1; + + return 0; +} diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/CMakeLists.txt bladerf-0.3.0+git20130916/host/libraries/libbladeRF/CMakeLists.txt --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/CMakeLists.txt 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/CMakeLists.txt 2013-09-17 07:44:19.000000000 +0000 @@ -122,11 +122,12 @@ src/backend.c src/bladerf.c src/bladerf_priv.c - src/device_identifier.c src/file_ops.c src/lms.c src/si5338.c src/version.h + ${BLADERF_HOST_COMMON_SOURCE_DIR}/device_identifier.c + ${BLADERF_HOST_COMMON_SOURCE_DIR}/bladerf_devinfo.c ${BLADERF_HOST_COMMON_SOURCE_DIR}/conversions.c ${BLADERF_HOST_COMMON_SOURCE_DIR}/log.c ) @@ -135,6 +136,7 @@ if(LIBUSB_FOUND AND ENABLE_BACKEND_LIBUSB) set(LIBBLADERF_SOURCE ${LIBBLADERF_SOURCE} src/backend/libusb.c) + set(LIBBLADERF_SOURCE ${LIBBLADERF_SOURCE} ${BLADERF_HOST_COMMON_SOURCE_DIR}/ezusb.c) endif() if(ENABLE_BACKEND_LINUX_DRIVER) @@ -254,10 +256,3 @@ ) endif(DOXYGEN_FOUND) - -if(MSVC) - add_custom_command(TARGET libbladerf_shared POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${LIBUSB_PATH}/${LIBUSB_LIBRARY_PATH_SUFFIX}/libusb-1.0.dll" - "${CMAKE_BINARY_DIR}/libraries/libbladeRF/$(Configuration)/") -endif(MSVC) diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/doc/doxygen/Doxyfile.in bladerf-0.3.0+git20130916/host/libraries/libbladeRF/doc/doxygen/Doxyfile.in --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/doc/doxygen/Doxyfile.in 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/doc/doxygen/Doxyfile.in 2013-09-17 07:44:19.000000000 +0000 @@ -678,7 +678,7 @@ # with spaces. INPUT = @CMAKE_CURRENT_SOURCE_DIR@/include \ - @CMAKE_CURRENT_SOURCE_DIR@ + @CMAKE_CURRENT_SOURCE_DIR@/doc/doxygen # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/include/libbladeRF.h bladerf-0.3.0+git20130916/host/libraries/libbladeRF/include/libbladeRF.h --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/include/libbladeRF.h 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/include/libbladeRF.h 2013-09-17 07:44:19.000000000 +0000 @@ -14,7 +14,7 @@ extern "C" { #endif -/* Function visibility */ +/** Marks an API routine to be made visible to dynamic loader */ #if defined _WIN32 || defined _CYGWIN__ # ifdef __GNUC__ # define API_EXPORT __attribute__ ((dllexport)) @@ -66,7 +66,7 @@ BLADERF_BACKEND_LIBUSB /**< libusb */ } bladerf_backend; -/* Length of device serial number string, including NUL-terminator */ +/** Length of device serial number string, including NUL-terminator */ #define BLADERF_SERIAL_LENGTH 33 /** @@ -81,6 +81,16 @@ }; /** + * Rational sample rate representation + */ +struct bladerf_rational_rate { + uint64_t integer; /**< Integer portion */ + uint64_t num; /**< Numerator in fractional portion */ + uint64_t den; /**< Denominator in fractional portion. This + must be > 0. */ +}; + +/** * Device statistics */ struct bladerf_stats { @@ -316,7 +326,7 @@ * - Specifies USB bus and address. Decimal or hex prefixed by '0x' is * permitted. * - instance=\ - * - Nth instance encountered (libusb) + * - Nth instance encountered, 0-indexed (libusb) * - Device node N, such as /dev/bladerfN (linux) * - serial=\ * - Device's serial number. @@ -390,22 +400,18 @@ /** * Configure the device's sample rate as a rational fraction of Hz. * Sample rates are in the form of integer + num/denom. - * TODO: Should this be the only way we set values, and num=0 and denom=1 - * for integer portions? * * @param[in] dev Device handle * @param[in] module Module to change - * @param[in] integer Integer portion of the equation integer + num/denom - * @param[in] num Numerator of rational fractional part - * @param[in] denom Denominator of rational fractional part + * @param[in] rate Rational sample rate + * @param[out] actual Actual rational sample rate * * @return 0 on success, value from \ref RETCODES list on failure */ API_EXPORT int bladerf_set_rational_sample_rate(struct bladerf *dev, bladerf_module module, - unsigned int integer, - unsigned int num, - unsigned int denom); + struct bladerf_rational_rate *rate, + struct bladerf_rational_rate *actual); /** * Configure the sampling of the LMS6002D to be either internal or @@ -447,6 +453,19 @@ unsigned int *rate); /** + * Read the device's sample rate in rational Hz + * + * @param[in] dev Device handle + * @param[in] module Module to query + * @param[out] rate Pointer to returned rational sample rate + * + * @return 0 on success, value from \ref RETCODES list upon failure + */ +API_EXPORT int bladerf_get_rational_sample_rate(struct bladerf *dev, + bladerf_module module, + struct bladerf_rational_rate *rate); + +/** * Set the PA gain in dB * * @param dev Device handle @@ -684,6 +703,21 @@ /** * Begin running a stream. This call will block until the steam completes. * + * Only 1 RX stream and 1 TX stream may be running at a time. Attempting to + * call bladerf_stream() with more than one stream per module will yield + * unexpected (and most likely undesirable) results. + * + * When running a full-duplex configuration with two threads (e.g, + * one thread calling bladerf_stream() for TX, and another for RX), stream + * callbacks may be executed in either thread. Therefore, the caller is + * responsible for ensuring that his or her callbacks are thread-safe. For the + * same reason, it is highly recommended that callbacks do not block. + * + * When starting a TX stream, an initial set of callbacks will be immediately + * invoked. The caller must ensure that there are at *more than* T buffers + * filled before calling bladerf_stream(..., BLADERF_MODULE_TX), where T is the + * num_transfers value provided to bladerf_init_stream(), to avoid an underrun. + * * @param stream A stream handle that has been successfully been initialized * via bladerf_init_stream() * @@ -857,6 +891,104 @@ const char *firmware); /** + * Recover specified device using a device identifier string + * + * This method recovers a bladeRF that is in the FX3 bootloader by loading the + * specified firmware image. + * + * The general form of the device identifier string is; + * @code + * :[device=:] [instance=] [serial=] + * @endcode + * + * An empty ("") or NULL device identifier will result in the first + * encountered device being opened (using the first discovered backend) + * + * The 'backend' describes the mechanism used to communicate with the device, + * and may be one of the following: + * - libusb: libusb (See libusb changelog notes for required version, given + * your OS and controller) + * - linux: Linux Kernel Driver + * + * If no arguments are provided after the backend, the first encountered + * device on the specified backend will be opened. Note that a backend is + * required, if any arguments are to be provided. + * + * Next, any provided arguments are provide as used to find the desired device. + * Be sure not to over constrain the search. Generally, only one of the above + * is required -- providing all of these may over constrain the search for the + * desired device (e.g., if a serial number matches, but not on the specified + * bus and address.) + * + * - device=\:\ + * - Specifies USB bus and address. Decimal or hex prefixed by '0x' is + * permitted. + * - instance=\ + * - Nth instance encountered (libusb) + * - Device node N, such as /dev/bladerfN (linux) + * - serial=\ + * - Device's serial number. + * + * @param[in] device_identifier Device identifier, formatted as described above + * @param[in] fname Filename of FX3 firmware load work + * + * @return 0 on success, or value from \ref RETCODES list on failure + */ +API_EXPORT int bladerf_recover_with_devinfo( + struct bladerf_devinfo *devinfo, + const char *fname + ); +API_EXPORT int bladerf_recover( + const char *device_identifier, + const char *fname + ); + +/** + * Erase pages from FX3 flash device + * + * @note Only entire pages are erased + * + * @param dev Device handle + * @param page_offset Page offset to begin erasing + * @param n_bytes Number of bytes to erase + * + * @return Number of pages erased on success, value from \ref RETCODES list on + * failure + */ +API_EXPORT int bladerf_erase_flash(struct bladerf *dev, int page_offset, + int n_bytes); + +/** + * Read bytes from FX3 flash device + * + * @param dev Device handle + * @param page_offset Page offset to begin reading + * @param ptr Buffer to read into, must be n_bytes long + * @param n_bytes Number of bytes to read + * + * @return Number of bytes read on success, value from \ref RETCODES list on + * failure + */ +API_EXPORT int bladerf_read_flash(struct bladerf *dev, int page_offset, + uint8_t *ptr, size_t n_bytes); + +/** + * Write bytes to FX3 flash device + * + * @note Only write erased pages + * + * @param dev Device handle + * @param page_offset Page offset to begin writing + * @param data Data to write to flash + * @param data_size Number of bytes to write + * + * @return Number of bytes written on success, value from \ref RETCODES list + * on failure + */ +API_EXPORT int bladerf_write_flash(struct bladerf *dev, int page_offset, + uint8_t *data, size_t data_size); + +/** * Reset the device * * @note This also causes the device to reload its firmware @@ -868,14 +1000,23 @@ API_EXPORT int bladerf_device_reset(struct bladerf *dev); /** + * Jump to FX3 bootloader + * + * @note This also causes the device to jump to the FX3 bootloader + * + * @param dev Device handle + * + * @return 0 on success, value from \ref RETCODES list on failure + */ +API_EXPORT int bladerf_jump_to_bootloader(struct bladerf *dev); + +/** * Load device's FPGA * * @param dev Device handle * @param fpga Full path to FPGA bitstream * - * @return 0 upon successfully, - * 1 if FPGA is already loaded, - * or a value from \ref RETCODES list on failure + * @return 0 upon successfully, or a value from \ref RETCODES list on failure */ API_EXPORT int bladerf_load_fpga(struct bladerf *dev, const char *fpga); diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/backend/libusb.c bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/backend/libusb.c --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/backend/libusb.c 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/backend/libusb.c 2013-09-17 07:44:19.000000000 +0000 @@ -10,6 +10,7 @@ #include #include +#include "ezusb.h" #include "bladerf_priv.h" #include "backend/libusb.h" #include "minmax.h" @@ -184,6 +185,27 @@ return rv; } +static int lusb_device_is_fx3(libusb_device *dev) +{ + int err; + int rv = 0; + struct libusb_device_descriptor desc; + + err = libusb_get_device_descriptor(dev, &desc); + if( err ) { + log_error( "Couldn't open libusb device - %s\n", libusb_error_name(err) ); + } else { + if( + (desc.idVendor == USB_CYPRESS_VENDOR_ID && desc.idProduct == USB_FX3_PRODUCT_ID) || + (desc.idVendor == USB_NUAND_VENDOR_ID && desc.idProduct == USB_NUAND_BLADERF_BOOT_PRODUCT_ID) + ) { + rv = 1; + } + } + return rv; +} + + static int lusb_get_devinfo(libusb_device *dev, struct bladerf_devinfo *info) { int status = 0; @@ -223,15 +245,32 @@ } - return error_libusb2bladerf(status); + return status; } static int change_setting(struct bladerf *dev, uint8_t setting) { + int status; + struct bladerf_lusb *lusb = dev->backend ; if (dev->legacy & LEGACY_ALT_SETTING) { log_info("Legacy change to interface %d\n", setting); - return libusb_set_interface_alt_setting(lusb->handle, setting, 0); + + /* + * Workaround: We're not seeing a transfer here in Windows, possibly because + * something in/under libusb_set_interface_alt_setting() assumes + * the interface is already set to the current value and + * suppresses this attempt. Hence, we force this transfer. + */ +#if WIN32 + status = libusb_control_transfer(lusb->handle, LIBUSB_RECIPIENT_DEVICE | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_ENDPOINT_OUT, 11, 0, setting, 0, 0, 0); + if (status > 0) { + status = 0; + } +#else + status = libusb_set_interface_alt_setting(lusb->handle, setting, 0); +#endif + return status; } else { log_info( "Change to alternate interface %d\n", setting); return libusb_set_interface_alt_setting(lusb->handle, 0, setting); @@ -241,6 +280,7 @@ static int lusb_open(struct bladerf **device, struct bladerf_devinfo *info) { int status, i, n, inf, val; + int fx3_status; ssize_t count; struct bladerf *dev = NULL; struct bladerf_lusb *lusb = NULL; @@ -337,6 +377,19 @@ break; } } + + if( lusb_device_is_fx3(list[i]) ) { + fx3_status = lusb_get_devinfo( list[i], &thisinfo ); + if( fx3_status ) { + log_error( "Could not open FX3 bootloader device: %s\n", libusb_error_name(fx3_status) ); + continue; + } + + log_warning( "Found FX3 bootloader device libusb:device=%d:%d, could be bladeRF.\n", + thisinfo.usb_bus, thisinfo.usb_addr); + log_warning( "Use \"recover libusb:device=%d:%d \" to boot bladeRF.\n", + thisinfo.usb_bus, thisinfo.usb_addr); + } } if (dev) { @@ -360,7 +413,7 @@ * in an attempt to release interfaces we haven't claimed... thoughts? */ lusb_open__err_device_list: libusb_free_device_list( list, 1 ); - if (status != 0) { + if (status != 0 && lusb != NULL) { if (lusb->handle) { libusb_close(lusb->handle); } @@ -499,7 +552,7 @@ } /* Note: n_bytes is rounded up to a multiple of the sector size here */ -static int erase_flash(struct bladerf *dev, int sector_offset, int n_bytes) +static int lusb_erase_flash(struct bladerf *dev, int sector_offset, int n_bytes) { int status = 0; int sector_to_erase; @@ -510,6 +563,13 @@ assert(sector_offset < FLASH_NUM_SECTORS); assert((sector_offset + n_sectors) < FLASH_NUM_SECTORS); + status = change_setting(dev, USB_IF_SPI_FLASH); + + if (status) { + log_error("Failed to set interface: %s\n", libusb_error_name(status)); + status = BLADERF_ERR_IO; + } + log_info("Erasing %d sectors starting @ sector %d\n", n_sectors, sector_offset); @@ -542,20 +602,35 @@ } } - return status; + if (status == 0) { + return n_sectors; + } else { + return status; + } } -static int read_flash(struct bladerf *dev, int page_offset, +static int lusb_read_flash(struct bladerf *dev, int page_offset, uint8_t *ptr, size_t n_bytes) { int status = 0; - int page_i, n_read; + int page_i, n_read, total_read; int read_size = dev->speed ? FLASH_PAGE_SIZE: 64; int pages_to_read = FLASH_BYTES_TO_PAGES(n_bytes); struct bladerf_lusb *lusb = dev->backend; assert(page_offset < FLASH_NUM_PAGES); assert((page_offset + n_bytes) < FLASH_NUM_PAGES); + /* FIXME: support data_size that are not multiple of pages */ + assert(n_bytes % FLASH_PAGE_SIZE == 0); + + status = change_setting(dev, USB_IF_SPI_FLASH); + + if (status) { + log_error("Failed to set interface: %s\n", libusb_error_name(status)); + status = BLADERF_ERR_IO; + } + + total_read = 0; for (page_i = page_offset; page_i < (page_offset + pages_to_read) && !status; @@ -588,12 +663,18 @@ status = BLADERF_ERR_IO; } else { n_read += read_size; + total_read += read_size; ptr += read_size; status = 0; } } while (n_read < FLASH_PAGE_SIZE && !status); } - return status; + + if (status == 0) { + return total_read; + } else { + return status; + } } static int verify_flash(struct bladerf *dev, int page_offset, @@ -667,21 +748,33 @@ return status; } -static int write_flash(struct bladerf *dev, int page_offset, +static int lusb_write_flash(struct bladerf *dev, int page_offset, uint8_t *data, size_t data_size) { int status = 0; int i; - int n_write; + int n_write, total_written; int write_size = dev->speed ? FLASH_PAGE_SIZE : 64; int pages_to_write = FLASH_BYTES_TO_PAGES(data_size); struct bladerf_lusb *lusb = dev->backend; uint8_t *data_page; log_info("Flashing with write size = %d\n", write_size); + status = change_setting(dev, USB_IF_SPI_FLASH); + + if (status) { + log_error("Failed to set interface: %s\n", libusb_error_name(status)); + status = BLADERF_ERR_IO; + } + + log_info("Flashing with write size = %d\n", write_size); assert(page_offset < FLASH_NUM_PAGES); assert((page_offset + pages_to_write) < FLASH_NUM_PAGES); + /* FIXME: support data_size that are not multiple of pages */ + assert(data_size % FLASH_PAGE_SIZE == 0); + + total_written = 0; for (i = page_offset; i < (page_offset + pages_to_write) && !status; i++) { n_write = 0; @@ -709,11 +802,96 @@ status = BLADERF_ERR_IO; } else { n_write += write_size; + total_written += write_size; status = 0; } } while (n_write < FLASH_PAGE_SIZE && !status); } + if (status == 0) { + return total_written; + } else { + return status; + } +} + +static int find_fx3_via_info( + libusb_context * context, + struct bladerf_devinfo *info, + libusb_device_handle **handle) { + int status, i; + struct bladerf_devinfo thisinfo; + libusb_device *dev, **devs; + libusb_device *found_dev = NULL; + + status = libusb_get_device_list(context, &devs); + if (status < 0) { + log_error("libusb_get_device_list() failed: %d %s\n", status, libusb_error_name(status)); + return error_libusb2bladerf(status); + } + + for (i=0; (dev=devs[i]) != NULL; i++) { + if (!lusb_device_is_fx3(dev)) { + continue; + } + + status = lusb_get_devinfo(dev, &thisinfo); + if (status < 0) { + log_error( "Could not open bladeRF device: %s\n", libusb_error_name(status) ); + status = error_libusb2bladerf(status); + break; + } + + if (bladerf_devinfo_matches(&thisinfo, info)) { + found_dev = dev; + break; + } + } + + if (found_dev == NULL) { + libusb_free_device_list(devs, 1); + log_error("could not find a known device - try specifing bus, dev\n"); + return BLADERF_ERR_NODEV; + } + + status = libusb_open(found_dev, handle); + libusb_free_device_list(devs, 1); + if (status != 0) { + log_error("Error opening device: %s\n", libusb_error_name(status)); + return error_libusb2bladerf(status); + } + + return 0; +} + +static int lusb_recover( + struct bladerf_devinfo *devinfo, + const char *fname + ) +{ + int status; + libusb_device_handle *device = NULL; + + libusb_context *context; + + status = libusb_init(&context); + if (status != 0) { + log_error( "Could not initialize libusb: %s\n", libusb_error_name(status) ); + return error_libusb2bladerf(status); + } + + status = find_fx3_via_info(context, devinfo, &device); + if (status == 0) { + log_info("Attempting load with file %s\n", fname); + status = ezusb_load_ram(device, fname, FX_TYPE_FX3, IMG_TYPE_IMG, 0); + + libusb_close(device); + } else { + log_error("Failed to locate FX3 bootloader: %s\n", bladerf_strerror(status) ); + } + + libusb_exit(context); + return status; } @@ -730,14 +908,14 @@ } if (status == 0) { - status = erase_flash(dev, 0, image_size); + status = lusb_erase_flash(dev, 0, image_size); } - if (status == 0) { - status = write_flash(dev, 0, image, image_size); + if (status >= 0) { + status = lusb_write_flash(dev, 0, image, image_size); } - if (status == 0) { + if (status >= 0) { status = verify_flash(dev, 0, image, image_size); } @@ -750,8 +928,7 @@ static int lusb_device_reset(struct bladerf *dev) { struct bladerf_lusb *lusb = dev->backend; - int status, ok; - ok = 1; + int status; status = libusb_control_transfer( lusb->handle, LIBUSB_RECIPIENT_INTERFACE | @@ -760,10 +937,41 @@ BLADE_USB_CMD_RESET, 0, 0, - (unsigned char *)&ok, - sizeof(ok), + 0, + 0, BLADERF_LIBUSB_TIMEOUT_MS ); + + if(status != LIBUSB_SUCCESS) { + log_error("Error issuing reset: %s\n", libusb_error_name(status)); + return error_libusb2bladerf(status); + } else { + return status; + } +} + +static int lusb_jump_to_bootloader(struct bladerf *dev) +{ + struct bladerf_lusb *lusb = dev->backend; + int status; + status = libusb_control_transfer( + lusb->handle, + LIBUSB_RECIPIENT_INTERFACE | + LIBUSB_REQUEST_TYPE_VENDOR | + EP_DIR_OUT, + BLADE_USB_CMD_JUMP_TO_BOOTLOADER, + 0, + 0, + 0, + 0, + BLADERF_LIBUSB_TIMEOUT_MS + ); + + if (status < 0) { + log_error( "Error jumping to bootloader: %s\n", libusb_error_name(status) ); + status = error_libusb2bladerf(status); + } + return status; } @@ -794,8 +1002,18 @@ return 0; } +#define CAL_SIZE 256 + static int lusb_get_cal(struct bladerf *dev, char *cal) { - return read_flash(dev, 768, (uint8_t *)cal, 256); + int status = lusb_read_flash(dev, 768, (uint8_t *)cal, CAL_SIZE); + + if (status < 0) { + return status; + } else if (status == CAL_SIZE) { + return 0; + } else { + return BLADERF_ERR_IO; + } } static int lusb_get_fw_version(struct bladerf *dev, @@ -1468,6 +1686,19 @@ } } } + + if( lusb_device_is_fx3(list[i]) ) { + status = lusb_get_devinfo( list[i], &info ); + if( status ) { + log_error( "Could not open bladeRF device: %s\n", libusb_error_name(status) ); + continue; + } + + log_warning( "Found FX3 bootloader device libusb:device=%d:%d, could be bladeRF.\n", + info.usb_bus, info.usb_addr); + log_warning( "Use \"recover libusb:device=%d:%d \" to boot bladeRF.\n", + info.usb_bus, info.usb_addr); + } } libusb_free_device_list(list,1); libusb_exit(context); @@ -1491,8 +1722,13 @@ FIELD_INIT(.load_fpga, lusb_load_fpga), FIELD_INIT(.is_fpga_configured, lusb_is_fpga_configured), + FIELD_INIT(.recover, lusb_recover), FIELD_INIT(.flash_firmware, lusb_flash_firmware), + FIELD_INIT(.erase_flash, lusb_erase_flash), + FIELD_INIT(.read_flash, lusb_read_flash), + FIELD_INIT(.write_flash, lusb_write_flash), FIELD_INIT(.device_reset, lusb_device_reset), + FIELD_INIT(.jump_to_bootloader, lusb_jump_to_bootloader), FIELD_INIT(.get_cal, lusb_get_cal), FIELD_INIT(.get_otp, lusb_get_otp), diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/backend/linux.c bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/backend/linux.c --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/backend/linux.c 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/backend/linux.c 2013-09-17 07:44:19.000000000 +0000 @@ -733,8 +733,13 @@ FIELD_INIT(.load_fpga, linux_load_fpga), FIELD_INIT(.is_fpga_configured, linux_is_fpga_configured), + FIELD_INIT(.recover, NULL), FIELD_INIT(.flash_firmware, linux_flash_firmware), + FIELD_INIT(.erase_flash, NULL), + FIELD_INIT(.read_flash, NULL), + FIELD_INIT(.write_flash, NULL), FIELD_INIT(.device_reset, linux_device_reset), + FIELD_INIT(.jump_to_bootloader, NULL), FIELD_INIT(.get_cal, linux_get_cal), FIELD_INIT(.get_otp, linux_get_otp), diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/backend.c bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/backend.c --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/backend.c 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/backend.c 2013-09-17 07:44:19.000000000 +0000 @@ -27,6 +27,19 @@ return status; } +const struct bladerf_fn * backend_getfns(bladerf_backend type) { + size_t i; + const size_t n_backends = ARRAY_SIZE(backend_list); + + for (i = 0; i < n_backends; i++) { + if (backend_list[i].type == type) { + return backend_list[i].fns; + } + } + + return NULL; +} + int backend_open(struct bladerf **device, struct bladerf_devinfo *info) { size_t i; diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/backend.h bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/backend.h --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/backend.h 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/backend.h 2013-09-17 07:44:19.000000000 +0000 @@ -24,5 +24,14 @@ */ int backend_probe(struct bladerf_devinfo **devinfo_items, size_t *num_items); +/** + * Get functions for a backend + * + * @param type Type of backend + * + * @return NULL on unknown backend + */ +const struct bladerf_fn * backend_getfns(bladerf_backend type); + #endif diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/bladerf.c bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/bladerf.c --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/bladerf.c 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/bladerf.c 2013-09-17 07:44:19.000000000 +0000 @@ -160,10 +160,9 @@ } -int bladerf_set_rational_sample_rate(struct bladerf *dev, bladerf_module module, unsigned int integer, unsigned int num, unsigned int denom) +int bladerf_set_rational_sample_rate(struct bladerf *dev, bladerf_module module, struct bladerf_rational_rate *rate, struct bladerf_rational_rate *actual) { - /* TODO: Program the Si5338 to be 2x the desired sample rate */ - return 0; + return si5338_set_rational_sample_rate(dev, module, rate, actual); } int bladerf_set_sample_rate(struct bladerf *dev, bladerf_module module, uint32_t rate, uint32_t *actual) @@ -171,6 +170,11 @@ return si5338_set_sample_rate(dev, module, rate, actual); } +int bladerf_get_rational_sample_rate(struct bladerf *dev, bladerf_module module, struct bladerf_rational_rate *rate) +{ + return si5338_get_rational_sample_rate(dev, module, rate); +} + int bladerf_get_sample_rate(struct bladerf *dev, bladerf_module module, unsigned int *rate) { return si5338_get_sample_rate(dev, module, rate); @@ -270,12 +274,6 @@ return status; } -int bladerf_get_rational_sample_rate(struct bladerf *dev, bladerf_module module, unsigned int integer, unsigned int num, unsigned int denom) -{ - /* TODO: Read the Si5338 and figure out the sample rate */ - return 0; -} - int bladerf_set_txvga2(struct bladerf *dev, int gain) { if( gain > 25 ) { @@ -662,6 +660,35 @@ /*------------------------------------------------------------------------------ * Device Programming *----------------------------------------------------------------------------*/ +int bladerf_recover_with_devinfo( + struct bladerf_devinfo *devinfo, + const char *fname + ) +{ + const struct bladerf_fn * fn = backend_getfns(devinfo->backend); + + if (!fn->recover) { + return BLADERF_ERR_UNSUPPORTED; + } + + return fn->recover(devinfo, fname); +} + +int bladerf_recover( + const char *dev_id, + const char *fname + ) +{ + struct bladerf_devinfo devinfo; + int status = str2devinfo(dev_id, &devinfo); + + if (!status) { + status = bladerf_recover_with_devinfo(&devinfo, fname); + } + + return status; +} + int bladerf_flash_firmware(struct bladerf *dev, const char *firmware_file) { int status; @@ -698,7 +725,7 @@ } if (!status) { - status = dev->fn->flash_firmware(dev, buf, buf_size); + status = dev->fn->flash_firmware(dev, buf, buf_size_padded); } if (!status) { if (dev->legacy) { @@ -713,25 +740,55 @@ return status; } +int bladerf_erase_flash(struct bladerf *dev, int page_offset, + int n_bytes) +{ + if (!dev->fn->erase_flash) { + return BLADERF_ERR_UNSUPPORTED; + } + + return dev->fn->erase_flash(dev, page_offset, n_bytes); +} + +int bladerf_read_flash(struct bladerf *dev, int page_offset, + uint8_t *ptr, size_t n_bytes) +{ + if (!dev->fn->read_flash) { + return BLADERF_ERR_UNSUPPORTED; + } + + return dev->fn->read_flash(dev, page_offset, ptr, n_bytes); +} + +int bladerf_write_flash(struct bladerf *dev, int page_offset, + uint8_t *data, size_t data_size) +{ + if (!dev->fn->write_flash) { + return BLADERF_ERR_UNSUPPORTED; + } + + return dev->fn->write_flash(dev, page_offset, data, data_size); +} + int bladerf_device_reset(struct bladerf *dev) { return dev->fn->device_reset(dev); } +int bladerf_jump_to_bootloader(struct bladerf *dev) +{ + if (!dev->fn->jump_to_bootloader) { + return BLADERF_ERR_UNSUPPORTED; + } + + return dev->fn->jump_to_bootloader(dev); +} + int bladerf_load_fpga(struct bladerf *dev, const char *fpga_file) { uint8_t *buf; size_t buf_size; int status; - int is_loaded; - - is_loaded = dev->fn->is_fpga_configured(dev); - if (is_loaded > 0) { - log_info("FPGA is already loaded -- reloading.\n"); - } else if (is_loaded < 0) { - log_warning("Failed to determine FPGA status. (%d) " - "Attempting to load anyway...\n", is_loaded); - } /* TODO sanity check FPGA: * - Check for x40 vs x115 and verify FPGA image size diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/bladerf_priv.c bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/bladerf_priv.c --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/bladerf_priv.c 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/bladerf_priv.c 2013-09-17 07:44:19.000000000 +0000 @@ -84,97 +84,6 @@ return 0; } -void bladerf_init_devinfo(struct bladerf_devinfo *d) -{ - d->backend = BLADERF_BACKEND_ANY; - strcpy(d->serial, DEVINFO_SERIAL_ANY); - d->usb_bus = DEVINFO_BUS_ANY; - d->usb_addr = DEVINFO_ADDR_ANY; - d->instance = DEVINFO_INST_ANY; -} - -bool bladerf_devinfo_matches(struct bladerf_devinfo *a, - struct bladerf_devinfo *b) -{ - return - bladerf_instance_matches(a,b) && - bladerf_serial_matches(a,b) && - bladerf_bus_addr_matches(a,b); -} - -bool bladerf_instance_matches(struct bladerf_devinfo *a, - struct bladerf_devinfo *b) -{ - return a->instance == DEVINFO_INST_ANY || - b->instance == DEVINFO_INST_ANY || - a->instance == b->instance; -} - -bool bladerf_serial_matches(struct bladerf_devinfo *a, - struct bladerf_devinfo *b) -{ - return !strcmp(a->serial, DEVINFO_SERIAL_ANY) || - !strcmp(b->serial, DEVINFO_SERIAL_ANY) || - !strcmp(a->serial, b->serial); -} - -bool bladerf_bus_addr_matches(struct bladerf_devinfo *a, - struct bladerf_devinfo *b) -{ - bool bus_match, addr_match; - - bus_match = a->usb_bus == DEVINFO_BUS_ANY || - b->usb_bus == DEVINFO_BUS_ANY || - a->usb_bus == b->usb_bus; - - addr_match = a->usb_addr == DEVINFO_BUS_ANY || - b->usb_addr == DEVINFO_BUS_ANY || - a->usb_addr == b->usb_addr; - - return bus_match && addr_match; -} - -int bladerf_devinfo_list_init(struct bladerf_devinfo_list *list) -{ - int status = 0; - - list->num_elt = 0; - list->backing_size = 5; - - list->elt = malloc(list->backing_size * sizeof(struct bladerf_devinfo)); - - if (!list->elt) { - free(list); - status = BLADERF_ERR_MEM; - } - - return status; -} - -int bladerf_devinfo_list_add(struct bladerf_devinfo_list *list, - struct bladerf_devinfo *info) -{ - int status = 0; - struct bladerf_devinfo *info_tmp; - - if (list->num_elt >= list->backing_size) { - info_tmp = realloc(list->elt, list->backing_size * 2); - if (!info_tmp) { - status = BLADERF_ERR_MEM; - } else { - list->elt = info_tmp; - } - } - - if (status == 0) { - memcpy(&list->elt[list->num_elt], info, sizeof(*info)); - list->num_elt++; - } - - return status; -} - - /****** * CRC16 implementation from http://softwaremonkey.org/Code/CRC16 */ diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/bladerf_priv.h bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/bladerf_priv.h --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/bladerf_priv.h 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/bladerf_priv.h 2013-09-17 07:44:19.000000000 +0000 @@ -9,12 +9,7 @@ #include "host_config.h" #include "minmax.h" #include "conversions.h" - -/* Reserved values for bladerf_devinfo fields to indicate "undefined" */ -#define DEVINFO_SERIAL_ANY "ANY" -#define DEVINFO_BUS_ANY UINT8_MAX -#define DEVINFO_ADDR_ANY UINT8_MAX -#define DEVINFO_INST_ANY UINT_MAX +#include "bladerf_devinfo.h" /* MX25U3235 - 32Mbit flash w/ 4KiB sectors */ #define FLASH_SECTOR_SIZE 0x10000 @@ -41,12 +36,6 @@ int value; }; -struct bladerf_devinfo_list { - struct bladerf_devinfo *elt; - size_t num_elt; /* Number of elements in the list */ - size_t backing_size; /* Size of backing array */ -}; - typedef enum { STREAM_IDLE, /* Idle and initialized */ STREAM_RUNNING, /* Currently running */ @@ -97,8 +86,17 @@ int (*is_fpga_configured)(struct bladerf *dev); /* Flash FX3 firmware */ + int (*recover)(struct bladerf_devinfo *info, + const char *fname); int (*flash_firmware)(struct bladerf *dev, uint8_t *image, size_t image_size); + int (*erase_flash)(struct bladerf *dev, int page_offset, + int n_bytes); + int (*read_flash)(struct bladerf *dev, int page_offset, + uint8_t *ptr, size_t n_bytes); + int (*write_flash)(struct bladerf *dev, int page_offset, + uint8_t *data, size_t data_size); int (*device_reset)(struct bladerf *dev); + int (*jump_to_bootloader)(struct bladerf *dev); /* Platform information */ int (*get_cal)(struct bladerf *dev, char *cal); @@ -189,82 +187,6 @@ bladerf_error *type, int *val); /** - * Initialize a bladerf_devinfo's fields to wildcards - */ -void bladerf_init_devinfo(struct bladerf_devinfo *d); - -/** - * Compare two devinfo's against each other. - * - * @param a Device information to compare - * @param b Device information to compare - * - * @return true on match, false otherwise - */ -bool bladerf_devinfo_matches(struct bladerf_devinfo *a, - struct bladerf_devinfo *b); - -/** - * Do the device instances for the two provided device info structures match - * (taking wildcards into account)? - * - * @param a Device information to compare - * @param b Device information to compare - * - * @return true on match, false otherwise - */ -bool bladerf_instance_matches(struct bladerf_devinfo *a, - struct bladerf_devinfo *b); - -/** - * Do the serials match for the two provided device info structures match - * (taking wildcards into account)? - * - * @param a Device information to compare - * @param b Device information to compare - * - * @return true on match, false otherwise - */ -bool bladerf_serial_matches(struct bladerf_devinfo *a, - struct bladerf_devinfo *b); - -/** - * Do the bus and addr match for the two provided device info structures match - * (taking wildcards into account)? - * - * @param a Device information to compare - * @param b Device information to compare - * - * @return true on match, false otherwise - */ -bool bladerf_bus_addr_matches(struct bladerf_devinfo *a, - struct bladerf_devinfo *b); - -/** - * Create list of deinfos - */ -int bladerf_devinfo_list_init(struct bladerf_devinfo_list *list); - -/** - * Get a pointer to the parent devinfo_list container of a devinfo - * - * @return pointer to container on success, NULL on error - */ -struct bladerf_devinfo_list * -bladerf_get_devinfo_list(struct bladerf_devinfo *devinfo); - -/** - * Add and item to our internal devinfo list - * - * @param list List to append to - * @param info Info to copy into the list - * - * 0 on success, BLADERF_ERR_* on failure - */ -int bladerf_devinfo_list_add(struct bladerf_devinfo_list *list, - struct bladerf_devinfo *info); - -/** * Read data from one-time-programmabe (OTP) section of flash * * @param[in] dev Device handle diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/device_identifier.c bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/device_identifier.c --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/device_identifier.c 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/device_identifier.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,210 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bladerf_priv.h" -#include "device_identifier.h" -#include "conversions.h" -#include "log.h" - -#define DELIM_SPACE " \t\r\n\v\f" - - -static int handle_backend(char *str, struct bladerf_devinfo *d) -{ - int status = 0; - char *str_end; - - if (!str || strlen(str) == 0) { - return BLADERF_ERR_INVAL; - } - - - /* Gobble up any leading whitespace */ - while (*str && isspace(*str)) { - str++; - }; - - /* Likewise for trailing whitespace */ - str_end = str + strlen(str) - 1; - while (str_end > str && isspace(*str_end)) { str_end--; }; - str_end[1] = '\0'; - - if (!strcasecmp("libusb", str)) { - d->backend = BLADERF_BACKEND_LIBUSB; - } else if (!strcasecmp("linux", str)) { - d->backend = BLADERF_BACKEND_LINUX; - } else { - log_error("Invalid backend: %s\n", str); - status = BLADERF_ERR_INVAL; - } - - return status; -} - -static int handle_device(struct bladerf_devinfo *d, char *value) -{ - int status = BLADERF_ERR_INVAL; - bool bus_ok, addr_ok; - char *bus = value; - char *addr = strchr(value, ':'); - - if (addr && addr[1] != '\0') { - - /* Null-terminate bus and set addr to start of addr text */ - *addr = '\0'; - addr++; - - d->usb_bus = str2uint(bus, 0, DEVINFO_BUS_ANY - 1, &bus_ok); - d->usb_addr = str2uint(addr, 0, DEVINFO_ADDR_ANY - 1, &addr_ok); - - if (bus_ok && addr_ok) { - status = 0; - log_info("Device: %d:%d\n", d->usb_bus, d->usb_addr); - } else { - log_error("Bad bus (%s) or address (%s)\n", bus, addr); - } - } - - return status; -} - -static int handle_instance(struct bladerf_devinfo *d, char *value) -{ - bool ok; - - d->instance = str2uint(value, 0, DEVINFO_INST_ANY - 1, &ok); - if (!ok) { - log_error("Bad instance: %s\n", value); - return BLADERF_ERR_INVAL; - } else { - log_info("Instance: %u\n", d->instance); - return 0; - } -} - -static int handle_serial(struct bladerf_devinfo *d, char *value) -{ - char c; - int i; - - if (strlen(value) != 32) { - return BLADERF_ERR_INVAL; - } - - for (i = 0; i < 32; i++) { - c = value[i]; - if (c >= 'A' && c <='F') { - value[i] = tolower(c); - } - if ((c < 'a' || c > 'f') && (c < '0' || c > '9')) { - log_error("Bad serial: %s\n", value); - return BLADERF_ERR_INVAL; - } - } - - strncpy(d->serial, value, 32); - d->serial[32] = 0; - - log_info("Serial 0x%s\n", d->serial); - return 0; -} - -/* Returns: 1 on arg and value populated - * 0 on no args left - * BLADERF_ERR_INVAL on bad format - */ - -static int next_arg(char **saveptr, char **arg, char **value) -{ - char *saveptr_local; - char *token = strtok_r(NULL, DELIM_SPACE, saveptr); - - /* No arguments left */ - if (!token) { - return 0; - } - - /* Argument name */ - *arg = strtok_r(token, "=", &saveptr_local); - - if (!*arg) { - return BLADERF_ERR_INVAL; - } - - /* Argument value - gobble up the rest of the line*/ - *value = strtok_r(NULL, "", &saveptr_local); - - if (!*value) { - return BLADERF_ERR_INVAL; - } - - return 1; -} - -int str2devinfo(const char *dev_id_const, struct bladerf_devinfo *d) -{ - char *dev_id, *token, *arg, *val, *saveptr; - int status, arg_status; - - assert(d); - - /* Prep our device info before we begin manpulating it, defaulting to - * a "wildcard" device indentification */ - bladerf_init_devinfo(d); - - /* No device indentifier -- pick anything we can find */ - if ( dev_id_const == NULL || strlen(dev_id_const) == 0) { - return 0; - } - - /* Copy the string so we can butcher it a bit while parsing */ - dev_id = strdup(dev_id_const); - if (!dev_id) { - return BLADERF_ERR_MEM; - } - - /* Extract backend */ - token = strtok_r(dev_id, ":", &saveptr); - - /* We require a valid backend -- args only is not supported */ - if (token) { - status = handle_backend(token, d); - - /* Loop over remainder of string, gathering up args */ - arg_status = 1; - while (arg_status == 1 && status == 0) { - arg_status = next_arg(&saveptr, &arg, &val); - if (arg_status == 1) { - - /* Handle argument if we can */ - if (!strcasecmp("device", arg)) { - status = handle_device(d, val); - } else if (!strcasecmp("instance", arg)) { - status = handle_instance(d, val); - } else if (!strcasecmp("serial", arg)) { - status = handle_serial(d, val); - } else { - arg_status = BLADERF_ERR_INVAL; - } - } - }; - - if (arg_status < 0) { - status = arg_status; - } - - } else { - status = BLADERF_ERR_INVAL; - } - - free(dev_id); - return status; -} diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/device_identifier.h bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/device_identifier.h --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/device_identifier.h 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/device_identifier.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -/** - * Routines for parsing and handling device identifier strings - */ -#ifndef DEVICE_IDENTIFIER_H__ -#define DEVICE_IDENTIFIER_H__ - - -/** - * Fill out a device info structure based upon the provided device indentifer - * string. If a failure occurrs, the contents of d are undefined. - * - * For device identifier format, see the documentation for bladerf_open - * (in include/libbladeRF.h) - * - * @param[in] device_identifier Device identifier string - * @param[out] d Device info to fill in - * - * @return 0 on success, BLADERF_ERR_* on failure - */ -int str2devinfo(const char *device_identifier, struct bladerf_devinfo *d); - -#endif diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/si5338.c bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/si5338.c --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/si5338.c 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/si5338.c 2013-09-17 07:44:19.000000000 +0000 @@ -1,405 +1,482 @@ #include +#include #include "libbladeRF.h" #include "bladerf_priv.h" #include "log.h" +#define SI5338_EN_A 0x01 +#define SI5338_EN_B 0x02 -#define SI5338_EN_A 0x01 -#define SI5338_EN_B 0x02 - -#define SI5338_F_VCO (38400000UL * 66UL) - +#define SI5338_F_VCO (38400000UL * 66UL) /** * This is used set or recreate the si5338 frequency - * Each si port can be set independently + * Each si5338 multisynth module can be set independently */ -struct si5338_port { - int block_index; - int base; // this can be gotten from block_index +struct si5338_multisynth { + /* Multisynth to program (0-3) */ + uint8_t index; + + /* Base address of the multisynth */ + uint16_t base; - uint32_t want_sample_rate; // if used as setter this is what I wish - uint8_t enable_port_bits; // You may want Just port A out or both port A & B + /* Requested and actual sample rates */ + struct bladerf_rational_rate requested; + struct bladerf_rational_rate actual; - uint32_t sample_rate_r; // the sample rate adjusted with the r multiplier + /* Enables for A and/or B outputs */ + uint8_t enable; - uint32_t P1,P2,P3; // as from section 5.2 of Reference manual - uint32_t a,b,c,r; + /* f_out = fvco / (a + b/c) / r */ + uint32_t a, b, c, r; - uint32_t *f_outP; // write result here + /* (a, b, c) in multisynth (p1, p2, p3) form */ + uint32_t p1, p2, p3; + /* (p1, p2, p3) in register form */ uint8_t regs[10]; - uint8_t raw_r; }; - -/** - * gets the basic regs from Si - * @return 0 if all is fine or an error code - */ -static int si5338_get_sample_rate_regs ( struct bladerf *dev, struct si5338_port *retP ) +void si5338_read_error(int error, const char *s) { - int i,retcode; - - for (i = 0; i < 9; i++) { - if ( (retcode=bladerf_si5338_read(dev, retP->base + i, retP->regs+i)) < 0 ) { - log_error("Could not read from si5338 (%d): %s\n",retcode, bladerf_strerror(retcode)); - return retcode; - } - } - - if ( (retcode=bladerf_si5338_read(dev, 31 + retP->block_index, &retP->raw_r)) < 0 ) { - log_error("Could not read from si5338 (%d): %s\n",retcode, bladerf_strerror(retcode)); - return retcode; - } - - return 0; + log_error( "Could not read from si5338 (%d): %s\n", error, s ); + return; } -static unsigned int bytes_to_uint32 ( uint8_t msb, uint8_t ms1, uint8_t ms2, uint8_t lsb, uint8_t last_shift ) +void si5338_write_error(int error, const char *s) { - unsigned int risul = msb; - risul = (risul << 9) + ms1; - risul = (risul << 8) + ms2; - risul = (risul << last_shift) + lsb; - return risul; + log_error( "Could not write to si5338 (%d): %s\n", error, s ); + return; } +static uint64_t si5338_gcd(uint64_t a, uint64_t b) +{ + uint64_t t; + while (b != 0) { + t = b; + b = a % t; + a = t; + } + return a; +} -static void si5338_get_sample_rate_calc ( struct si5338_port *retP ) +static void si5338_rational_reduce(struct bladerf_rational_rate *r) { - uint64_t c = retP->c = retP->P3; - uint32_t p2 = retP->P2; - uint32_t b=0; - uint32_t p1 ; - uint64_t A, a, f_twice, divisor ; - uint32_t B ; - int i; + int64_t val; - // c should never be zero, but if it is at least we do not crash - if ( c == 0 ) return; + if (r->num >= r->den) { + /* Get whole number */ + uint64_t whole = r->num / r->den; + r->integer += whole; + r->num = r->num - whole*r->den; + } - for (i=1; i<128; i++) { - B = c*i+p2; + /* Reduce fraction */ + val = si5338_gcd(r->num, r->den); + r->num /= val; + r->den /= val; - if ( (B % 128) == 0 ) { - b = B / 128; - retP->b = b; - break; - } - } + return ; +} - p1 = retP->P1; +static void si5338_rational_double(struct bladerf_rational_rate *r) +{ + r->integer *= 2; + r->num *= 2; + si5338_rational_reduce(r); + return; +} - A = (p1 + 512); - A = A * c; - A = A - b * 128; - A = (A * 10) / ( c * 128 ); // switch to fixed decimal point +/** + * Update the base address of the selected multisynth + */ +static void si5338_update_base(struct si5338_multisynth *ms) +{ + ms->base = 53 + ms->index*11 ; + return; +} - // get the integer value - a = A / 10; +/** + * Unpack the recently read registers into (p1, p2, p3) and (a, b, c) + * + * Precondition: + * regs[10] and r have been read + * + * Post-condition: + * (p1, p2, p3), (a, b, c) and actual are populated + */ +static void si5338_unpack_regs(struct si5338_multisynth *ms) +{ + uint64_t temp; - // do manual rounding.... - if ( A % 10 > 5 ) a++; + /* Zeroize */ + ms->p1 = ms->p2 = ms->p3 = 0; - retP->a = a; + /* Populate */ + ms->p1 = ((ms->regs[2]&3)<<16) | (ms->regs[1]<<8) | (ms->regs[0]); + ms->p2 = (ms->regs[5]<<22) | (ms->regs[4]<<14) | (ms->regs[3]<<6) | ((ms->regs[2]>>2)&0x3f); + ms->p3 = ((ms->regs[9]&0x3f)<<24) | (ms->regs[8]<<16) | (ms->regs[7]<<8) | (ms->regs[6]); -// step by step to avoid too much compiler optimization - f_twice = SI5338_F_VCO * c; - divisor = a * c + b; - f_twice = f_twice / divisor; - f_twice = f_twice / retP->r; + log_debug( "Unpacked P1: 0x%8.8x (%u) P2: 0x%8.8x (%u) P3: 0x%8.8x (%u)\n", ms->p1, ms->p1, ms->p2, ms->p2, ms->p3, ms->p3 ); - retP->f_outP[0] = f_twice / 2; // yes, compiler may optimize this to >> 1 -} + /* c = p3 */ + ms->c = ms->p3; -static void print_si5338_port(struct si5338_port *portP) -{ - int i; - log_debug("out_freq: %dHz\n", portP->f_outP[0]); - log_debug("a: %d\n", portP->a); - log_debug("b: %d\n", portP->b); - log_debug("c: %d\n", portP->c); - log_debug("r: %d\n", portP->r); - log_debug("p1: %x\n", portP->P1); - log_debug("p2: %x\n", portP->P2); - log_debug("p3: %x\n", portP->P3); + /* a = (p1+512)/128 + * + * NOTE: The +64 is for rounding purposes. + */ + ms->a = (ms->p1+512)/128; - for (i = 0; i < 9; i++) log_debug("[%d]=0x%.2x\n", portP->base + i, portP->regs[i]); + /* b = (((p1+512)-128*a)*c + (b % c) + 64)/128 */ + temp = (ms->p1+512)-128*ms->a; + temp = (temp * ms->c) + ms->p2; + temp = (temp + 64) / 128; + ms->b = temp; - log_debug("[r]=0x%.2x\n", portP->raw_r); + log_debug( "Unpacked a + b/c: %d + %d/%d\n", ms->a, ms->b, ms->c ); + log_debug( "Unpacked r: %d\n", ms->r ); } - -static int si5338_get_module_sample_rate ( struct bladerf *dev, struct si5338_port *retP ) +/* + * Pack (a, b, c, r) into (p1, p2, p3) and regs[] + */ +static void si5338_pack_regs(struct si5338_multisynth *ms) { - int retcode; - uint8_t *valP, shi; - // gets the raw sample rate regs - if ( (retcode=si5338_get_sample_rate_regs(dev, retP )) ) return retcode; - - // I now need to reverse the packing, see pag. 10 of reference manual - valP = retP->regs; - retP->P1 = bytes_to_uint32 ( 0, valP[2] & 0x03, valP[1], valP[0], 8); - retP->P2 = bytes_to_uint32 ( valP[5], valP[4], valP[3], valP[2] >> 2, 6 ); - retP->P3 = bytes_to_uint32 ( valP[9] & 0x3F, valP[8], valP[7], valP[6], 8 ); + /* Precondition: + * (a, b, c) and r have been populated + * + * Post-condition: + * (p1, p2, p3) and regs[10] are populated + */ + + /* p1 = (a * c + b) * 128 / c - 512 */ + uint64_t temp; + temp = ms->a * ms->c + ms->b; + temp = temp * 128 ; + temp = temp / ms->c - 512; + ms->p1 = temp; + //ms->p1 = ms->a * ms->c + ms->b; + //ms->p1 = ms->p1 * 128; + //ms->p1 = ms->p1 / ms->c - 512; + + /* p2 = (b * 128) % c */ + ms->p2 = ms->b * 128; + ms->p2 = ms->p2 % ms->c; + + /* p3 = c */ + ms->p3 = ms->c; + + log_info( "MSx P1: 0x%8.8x (%u) P2: 0x%8.8x (%u) P3: 0x%8.8x (%u)\n", ms->p1, ms->p1, ms->p2, ms->p2, ms->p3, ms->p3 ); + + /* Regs */ + ms->regs[0] = ms->p1 & 0xff; + ms->regs[1] = (ms->p1 >> 8) & 0xff; + ms->regs[2] = ((ms->p2 & 0x3f) << 2) | ((ms->p1 >> 16) & 0x3); + ms->regs[3] = (ms->p2 >> 6) & 0xff; + ms->regs[4] = (ms->p2 >> 14) & 0xff; + ms->regs[5] = (ms->p2 >> 22) & 0xff; + ms->regs[6] = ms->p3 & 0xff; + ms->regs[7] = (ms->p3 >> 8) & 0xff; + ms->regs[8] = (ms->p3 >> 16) & 0xff; + ms->regs[9] = (ms->p3 >> 24) & 0xff; + + return ; +} + +static int si5338_write_multisynth(struct bladerf *dev, struct si5338_multisynth *ms) +{ + int i, status; + uint8_t r_power, r_count, val; + + log_debug( "Writing MS%d\n", ms->index ); + + /* Write out the enables */ + status = bladerf_si5338_read(dev, 36 + ms->index, &val); + if (status < 0) { + si5338_read_error(status, bladerf_strerror(status)); + return status; + } + val &= ~(7); + val |= ms->enable; + log_debug( "Wrote enable register: 0x%2.2x\n", val ); + status = bladerf_si5338_write(dev, 36 + ms->index, val); + if (status < 0) { + si5338_write_error(status, bladerf_strerror(status)); + return status; + } - shi = (retP->raw_r >> 2) & 0x03; - retP->r = 1 << shi; + /* Write out the registers */ + for (i = 0 ; i < 10 ; i++) { + status = bladerf_si5338_write(dev, ms->base + i, *(ms->regs+i)); + if (status < 0) { + si5338_write_error(status, bladerf_strerror(status)); + return status; + } + log_debug( "Wrote regs[%d]: 0x%2.2x\n", i, *(ms->regs+i) ); + } - si5338_get_sample_rate_calc(retP); + /* Calculate r_power from c_count */ + r_power = 0; + r_count = ms->r >> 1 ; + while (r_count > 0) { + r_count >>= 1; + r_power++; + } - print_si5338_port(retP); + /* Set the r value to the log2(r_count) to match Figure 18 */ + val = 0xc0; + val |= (r_power<<2); + + log_debug( "Wrote r register: 0x%2.2x\n", val ); + + status = bladerf_si5338_write(dev, 31 + ms->index, val); + if (status < 0) { + si5338_write_error(status, bladerf_strerror(status)); + } - return 0; + return status ; } -/** - * get the sample rate back from the Si5338 - * @param module the subsection I wish to know about - * @param rateP pointer to result - * @return 0 if all fine or an error code - */ -int si5338_get_sample_rate(struct bladerf *dev, bladerf_module module, unsigned int *rateP) +static int si5338_read_multisynth(struct bladerf *dev, struct si5338_multisynth *ms) { - struct si5338_port risul; - - // safety check - if ( rateP == NULL ) return BLADERF_ERR_UNEXPECTED; - - memset(&risul,0,sizeof(risul)); + int i, status; + uint8_t val; - risul.f_outP = rateP; + log_debug( "Reading MS%d\n", ms->index ); - switch ( module ) { - case BLADERF_MODULE_RX: - risul.block_index = 1; - risul.base = 53 + 1 * 11; - return si5338_get_module_sample_rate(dev,&risul); + /* Read the enable bits */ + status = bladerf_si5338_read(dev, 36 + ms->index, &val); + if (status < 0) { + si5338_read_error(status, bladerf_strerror(status)); + return status ; + } + ms->enable = val&7; + log_debug( "Read enable register: 0x%2.2x\n", val ); - case BLADERF_MODULE_TX: - risul.block_index = 2; - risul.base = 53 + 2 * 11; - return si5338_get_module_sample_rate(dev,&risul); + /* Read all of the multisynth registers */ + for (i = 0; i < 10; i++) { + status = bladerf_si5338_read(dev, ms->base + i, ms->regs+i); + if (status < 0) { + si5338_read_error(status, bladerf_strerror(status)); + return status; + } + log_debug( "Read regs[%d]: 0x%2.2x\n", i, *(ms->regs+i) ); + } - default: - break; + /* Populate the RxDIV value from the register */ + status = bladerf_si5338_read(dev, 31 + ms->index, &val); + if (status < 0) { + si5338_read_error(status, bladerf_strerror(status)); + return status; } + /* RxDIV is stored as a power of 2, so restore it on readback */ + log_debug( "Read r register: 0x%2.2x\n", val ); + val = (val>>2)&7; + ms->r = (1<a; + abc.num = ms->b; + abc.den = ms->c; - if (n1 > n2){ - a = n1; - b = n2; - } else { - a = n2; - b = n1; - } + rate->integer = 0; + rate->num = SI5338_F_VCO * abc.den; + rate->den = (uint64_t)ms->r*2*(abc.integer * abc.den + abc.num); + si5338_rational_reduce(rate); - if ((a % b) == 0) - mcd = b; - else - mcd = euclide_gcd (b, a % b); + log_info( "Calculated samplerate: %"PRIu64" + %"PRIu64"/%"PRIu64"\n", rate->integer, rate->num, rate->den ); - return mcd; + return; } -/** - * Calculated a,b,c to satisfy the si equations - * see pag 9 of reference manual - */ -static int set_sample_rate_calc_abc ( struct si5338_port *portP ) +static int si5338_calculate_multisynth(struct si5338_multisynth *ms, struct bladerf_rational_rate *rate) { - uint32_t remainder, gcd, b, c; - - // find out the integer part of the result - portP->a = SI5338_F_VCO / portP->sample_rate_r; - if ( portP->a < 4 || portP->a > 567 ) { - log_warning("a=%d too big \n", portP->a); - return BLADERF_ERR_INVAL; - } + struct bladerf_rational_rate req; + struct bladerf_rational_rate abc; + uint8_t r_value, r_power; - // I still have this hertz left that are not integer divisible by VCO - remainder = SI5338_F_VCO - (portP->a * portP->sample_rate_r); + /* Don't muss with the users data */ + req = *rate; - if ( remainder == 0 ) - { - portP->b=0; - portP->c=1; - return 0; - } + /* Double requested frequency since LMS requires 2:1 clock:sample rate */ + si5338_rational_double(&req); - // the gcd is the biggest number that divides both as integers - gcd = euclide_gcd(portP->sample_rate_r, remainder); + /* Find a suitable R value */ + r_value = 1; + r_power = 0; + while (req.integer < 5000000 && r_value < 32) { + si5338_rational_double(&req); + r_value <<= 1; + r_power++; + } -// dbg_printf("VCO=%u a=%u sr=%u remainder=%u gcd=%d \n",SI5338_F_VCO,portP->sample_rate_r,portP->a,remainder,gcd); + if (r_value == 32 && req.integer < 5000000) { + log_error( "Sample rate requires r > 32\n" ); + return BLADERF_ERR_INVAL; + } else { + log_info( "Found r value of: %d\n", r_value ); + } - // I now have to check if any of the b,c satisfy si conditions - b = remainder / gcd; + /* Find suitable MS (a, b, c) values */ + abc.integer = 0; + abc.num = SI5338_F_VCO * req.den; + abc.den = req.integer * req.den + req.num; + si5338_rational_reduce(&abc); + + log_info( "MSx a + b/c: %"PRIu64" + %"PRIu64"/%"PRIu64"\n", abc.integer, abc.num, abc.den ); + + /* Check values to make sure they are OK */ + if (abc.integer < 8) { + switch (abc.integer) { + case 0: + case 1: + case 2: + case 3: + case 5: + case 7: + log_error( "Integer portion too small: %"PRIu64"\n", abc.integer ); + return BLADERF_ERR_INVAL; + } + } else if (abc.integer > 567) { + log_error( "Integer portion too large: %"PRIu64"\n", abc.integer ); + return BLADERF_ERR_INVAL; + } - if ( b > 0x40000000 ) { - log_warning("cannot find suitable b ratio %dHz on MS%d \n", portP->want_sample_rate, portP->block_index); - return BLADERF_ERR_INVAL; + /* Loss of precision if num or den are greater than 2^30-1 */ + while (abc.num > (1<<30) || abc.den > (1<<30) ) { + log_warning( "Loss of precision in reducing fraction from %"PRIu64"/%"PRIu64" to %"PRIu64"/%"PRIu64"\n", abc.num, abc.den, abc.num>>1, abc.den>>1); + abc.num >>= 1; + abc.den >>= 1; } - c = portP->sample_rate_r / gcd; + log_info( "MSx a + b/c: %"PRIu64" + %"PRIu64"/%"PRIu64"\n", abc.integer, abc.num, abc.den ); - if ( c > 0x40000000 ) { - log_warning("cannot find suitable c ratio %dHz on MS%d \n", portP->want_sample_rate, portP->block_index); - return BLADERF_ERR_INVAL; - } + /* Set it in the multisynth */ + ms->a = abc.integer; + ms->b = abc.num; + ms->c = abc.den; + ms->r = r_value; - portP->b = b; - portP->c = c; + /* Pack the registers */ + si5338_pack_regs(ms); return 0; } -/** - * calculates a r that satisfy si5338 - * @return 0 if all is fine or an error code - */ -static int set_sample_rate_calc_r ( struct si5338_port *portP ) +int si5338_set_rational_sample_rate(struct bladerf *dev, bladerf_module module, struct bladerf_rational_rate *rate, struct bladerf_rational_rate *actual) { - uint32_t candidate; - int j; + struct si5338_multisynth ms; + struct bladerf_rational_rate req; + int status; + + /* Save off the value */ + req = *rate; + + /* Setup the multisynth enables and index */ + ms.enable = SI5338_EN_A; + if (module == BLADERF_MODULE_TX) { + ms.enable |= SI5338_EN_B; + } - for (j=0; j <= 5; j++ ) { - // see pag. 27 of si5338 RM rev 1.2 1/13 - // find an R that makes this MS's fout > 5MHz + /* Set the multisynth module we're dealing with */ + ms.index = (module == BLADERF_MODULE_RX) ? 1 : 2; - portP->r = 1 << j; // this is the r I will be using - portP->raw_r = j; // this is what goes into the chip + /* Update the base address register */ + si5338_update_base(&ms); - candidate = portP->want_sample_rate * portP->r; + /* Calculate multisynth values */ + status = si5338_calculate_multisynth(&ms, &req); + if(status != 0) { + return status; + } - if ( candidate >= 5000000) { - portP->sample_rate_r = candidate; - break; - } - } + /* Get the actual rate */ + si5338_calculate_samplerate(&ms, actual); - if ( ! portP->sample_rate_r ) { - log_warning("Requested frequency of %dHz on MS%d is too low\n", portP->want_sample_rate, portP->block_index); - return BLADERF_ERR_INVAL; - } + /* Program it to the part */ + status = si5338_write_multisynth(dev, &ms); - return 0; + /* Done */ + return status ; } -/** - * calculate P1, P2, P3 based off page 9 in the Si5338 reference manual - * make sure we have enough space to handle all cases - */ -static void set_sample_rate_calc_regs (struct si5338_port *portP) +int si5338_set_sample_rate(struct bladerf *dev, bladerf_module module, uint32_t rate, uint32_t *actual) { - uint64_t P1, P2, p1, p2, p3; - uint8_t *regs; - - // P1 = (a * c + b) * 128 / c - 512; - P1 = portP->a * portP->c + portP->b; - P1 = P1 * 128; - P1 = P1 / portP->c - 512; - - // P2 = (b * 128) % c; - P2 = portP->b * 128; - P2 = P2 % portP->c; - - p1 = portP->P1 = P1; - p2 = portP->P2 = P2; - p3 = portP->P3 = portP->c; - - regs = portP->regs; - regs[0] = p1 & 0xff; - regs[1] = (p1 >> 8) & 0xff; - regs[2] = ((p2 & 0x3f) << 2) | ((p1 >> 16) & 0x3); - regs[3] = (p2 >> 6) & 0xff; - regs[4] = (p2 >> 14) & 0xff; - regs[5] = (p2 >> 22) & 0xff; - regs[6] = p3 & 0xff; - regs[7] = (p3 >> 8) & 0xff; - regs[8] = (p3 >> 16) & 0xff; - regs[9] = (p3 >> 24) & 0xff; -} + struct bladerf_rational_rate req, act; + int status; -static int set_sample_rate_write_regs(struct bladerf *dev, struct si5338_port *portP) { - int i,errcode; + memset(&act, 0, sizeof(act)); + log_info( "Setting integer sample rate: %d\n", rate ); + req.integer = rate; + req.num = 0; + req.den = 1; - if ( (errcode=bladerf_si5338_write(dev, 36 + portP->block_index, portP->enable_port_bits )) ) return errcode; + status = si5338_set_rational_sample_rate(dev, module, &req, &act); - for (i = 0; i < 9; i++) { - if ( (errcode=bladerf_si5338_write(dev, portP->base + i, portP->regs[i] )) ) return errcode; + if (status == 0 && act.num != 0) { + log_warning( "Non-integer sample rate set from integer sample rate, truncating output\n" ); } - return bladerf_si5338_write(dev, 31 + portP->block_index, 0xC0 | (portP->raw_r << 2)); + *actual = act.integer; + log_info( "Set actual integer sample rate: %d\n", act.integer ); + + return status ; } -/** - * This just convert the sample rate into a,b,c that is suitable - * @return invalid params if frequency cannot be set - */ -static int set_sample_rate_A (struct bladerf *dev, struct si5338_port *portP) +int si5338_get_rational_sample_rate(struct bladerf *dev, bladerf_module module, struct bladerf_rational_rate *rate) { - int errcode; - portP->base = 53 + portP->block_index * 11; + struct si5338_multisynth ms; + int status; - if ( (errcode=set_sample_rate_calc_r(portP)) ) return errcode; + /* Select the multisynth we want to read */ + ms.index = (module == BLADERF_MODULE_RX) ? 1 : 2; - if ( (errcode=set_sample_rate_calc_abc(portP)) ) return errcode; + /* Update the base address */ + si5338_update_base(&ms); - set_sample_rate_calc_regs(portP); + /* Readback */ + status = si5338_read_multisynth(dev, &ms); - print_si5338_port(portP); - - if ( (errcode=set_sample_rate_write_regs(dev, portP)) ) return errcode; + if (status) { + si5338_read_error( status, bladerf_strerror(status) ); + return status; + } - if ( portP->f_outP ) return si5338_get_module_sample_rate(dev, portP); + si5338_calculate_samplerate(&ms, rate); - return 0; + return 0; } - - -/** - * sets the sample rate as requested - */ -int si5338_set_sample_rate(struct bladerf *dev, bladerf_module module, uint32_t rate, uint32_t *actualP) +int si5338_get_sample_rate(struct bladerf *dev, bladerf_module module, unsigned int *rate) { - struct si5338_port risul; - - memset(&risul,0,sizeof(risul)); + struct bladerf_rational_rate actual; + int status; - risul.f_outP = actualP; // may be NULL - risul.want_sample_rate = rate * 2; // LMS needs one clock for I and one clock for Q + status = si5338_get_rational_sample_rate(dev, module, &actual); - switch ( module ) { - case BLADERF_MODULE_RX: - risul.block_index = 1; - risul.enable_port_bits = SI5338_EN_A; - return set_sample_rate_A(dev,&risul); - - case BLADERF_MODULE_TX: - risul.block_index = 2; - risul.enable_port_bits = SI5338_EN_A | SI5338_EN_B; - return set_sample_rate_A(dev,&risul); + if (status) { + si5338_read_error( status, bladerf_strerror(status) ); + return status; + } - default: - break; + if (actual.num != 0) { + log_warning( "Fractional sample rate truncated during integer sample rate retrieval\n" ); } - return BLADERF_ERR_INVAL; -} + *rate = actual.integer; + return 0; +} diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/si5338.h bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/si5338.h --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/src/si5338.h 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/src/si5338.h 2013-09-17 07:44:19.000000000 +0000 @@ -9,5 +9,7 @@ int si5338_set_rx_freq(struct bladerf *dev, unsigned int freq); int si5338_set_sample_rate(struct bladerf *dev, bladerf_module module, uint32_t rate, uint32_t *actual); int si5338_get_sample_rate(struct bladerf *dev, bladerf_module module, unsigned int *rate); +int si5338_set_rational_sample_rate(struct bladerf *dev, bladerf_module module, struct bladerf_rational_rate *rate, struct bladerf_rational_rate *actual); +int si5338_get_rational_sample_rate(struct bladerf *dev, bladerf_module module, struct bladerf_rational_rate *rate); #endif diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/tests/CMakeLists.txt bladerf-0.3.0+git20130916/host/libraries/libbladeRF/tests/CMakeLists.txt --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/tests/CMakeLists.txt 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/tests/CMakeLists.txt 2013-09-17 07:44:19.000000000 +0000 @@ -1,2 +1,3 @@ cmake_minimum_required(VERSION 2.8) add_subdirectory(test_async) +add_subdirectory(test_repeater) diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/tests/test_repeater/CMakeLists.txt bladerf-0.3.0+git20130916/host/libraries/libbladeRF/tests/test_repeater/CMakeLists.txt --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/tests/test_repeater/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/tests/test_repeater/CMakeLists.txt 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 2.8) +project(libbladeRF_test_repeater C) + +if(MSVC) + find_package(LibPThreadsWin32 REQUIRED) +else(MSVC) + find_package(Threads REQUIRED) +endif(MSVC) + +set(TEST_REPEATER_SRC + src/main.c + src/repeater.c + ${BLADERF_HOST_COMMON_SOURCE_DIR}/conversions.c +) + +if(MSVC) + set(TEST_REPEATER_SRC ${TEST_REPEATER_SRC} + ${BLADERF_HOST_COMMON_SOURCE_DIR}/windows/getopt.c + ${BLADERF_HOST_COMMON_SOURCE_DIR}/windows/getopt_long.c + ) +endif() + +set(TEST_REPEATER_INCLUDE + src + ${libbladeRF_SOURCE_DIR}/include + ${BLADERF_HOST_COMMON_INCLUDE_DIRS} +) + +if(MSVC) + set(TEST_REPEATER_INCLUDE ${TEST_REPEATER_INCLUDE} + ${BLADERF_HOST_COMMON_INCLUDE_DIRS}/windows + ${LIBPTHREADSWIN32_INCLUDE_DIRS} + ) +endif() + + +include_directories(${TEST_REPEATER_INCLUDE}) +add_executable(libbladeRF_test_repeater ${TEST_REPEATER_SRC}) + +set(TEST_REPEATER_LIBS + libbladerf_shared + ${CMAKE_THREAD_LIBS_INIT}) + + +if(LIBPTHREADSWIN32_FOUND) + set(TEST_REPEATER_LIBS ${TEST_REPEATER_LIBS} ${LIBPTHREADSWIN32_LIBRARIES}) +endif() + +target_link_libraries(libbladeRF_test_repeater + ${TEST_REPEATER_LIBS}) \ No newline at end of file diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/tests/test_repeater/src/main.c bladerf-0.3.0+git20130916/host/libraries/libbladeRF/tests/test_repeater/src/main.c --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/tests/test_repeater/src/main.c 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/tests/test_repeater/src/main.c 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,241 @@ +/* + * This test implements a simple full-duplex repeater. + * + * This file handles command line processing and passes control off to the + * repeater.c file. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "conversions.h" /* Conversion routines from host/common */ +#include "repeater.h" + +#define OPTARG_STR "d:s:t:r:S:b:B:T:v:h" + +static struct option long_options[] = { + { "device", required_argument, 0, 'd'}, + { "samplerate", required_argument, 0, 's'}, + { "tx-freq", required_argument, 0, 't'}, + { "rx-freq", required_argument, 0, 'r'}, + { "num-samples", required_argument, 0, 'S'}, + { "num-buffers", required_argument, 0, 'B'}, + { "num-transfers", required_argument, 0, 'T'}, + { "verbosity", required_argument, 0, 'v'}, + { "help", no_argument, 0, 'h'}, + { 0, 0, 0, 0}, +}; + +static const struct numeric_suffix FREQ_SUFFIXES[] = { + { "G", 1000 * 1000 * 1000 }, + { "GHz", 1000 * 1000 * 1000 }, + { "M", 1000 * 1000 }, + { "MHz", 1000 * 1000 }, + { "k", 1000 } , + { "kHz", 1000 } +}; + +static const int NUM_FREQ_SUFFIXES = + sizeof(FREQ_SUFFIXES) / sizeof(struct numeric_suffix); + +static void usage(const char *argv0) +{ + printf("Simple full duplex repeater test\n\n"); + printf("Usage: %s [options]\n\n", argv0); + printf(" -d, --device Device to use. If not specified, the\n" + " first device found will be used.\n\n"); + + printf(" -s, --samplerate Sample rate. Default is %d Hz\n\n", + DEFAULT_SAMPLE_RATE); + + printf(" -b, --bandwidth Bandwidth. Default is %d Hz\n\n", + DEFAULT_BANDWIDTH); + + printf(" -t, --tx-freq Transmit frequency. Default is %d Hz\n\n", + DEFAULT_FREQUENCY); + + printf(" -r, --rx-freq Receive frequency. Default is %d Hz\n\n", + DEFAULT_FREQUENCY); + + printf(" -S, --num-samples Number of samples per buffer. Default is %d.\n" + " Must be a multiple of 1024.\n\n", + DEFAULT_SAMPLES_PER_BUFFER); + + printf(" -B, --num-buffers Number of buffers to use. Default is %d\n\n", + DEFAULT_NUM_BUFFERS); + + printf(" -T, --num-transfers Number of transfers to use. Default is %d.\n" + " This value should be *at least* 2 less than the\n" + " number of buffers being used.\n\n", + DEFAULT_NUM_TRANSFERS); + + printf(" -v, --verbosity Set libbladeRF verbosity level.\n\n"); + + printf(" -h, --help Show this text\n\n"); +} + +static int handle_args(int argc, char *argv[], struct repeater_config *config) +{ + int opt, opt_idx; + bool conv_ok; + + repeater_config_init(config); + + opt = getopt_long(argc, argv, OPTARG_STR, long_options, &opt_idx); + while (opt != -1) { + switch(opt) { + case 'd': + if (!config->device_str) { + config->device_str = strdup(optarg); + if (!config->device_str) { + perror("strdup"); + return -1; + } + } else { + fprintf(stderr, "\nError: Device already specified: %s\n", + config->device_str); + return -1; + } + break; + + case 't': + config->tx_freq = str2uint_suffix(optarg, 1, INT_MAX, + FREQ_SUFFIXES, NUM_FREQ_SUFFIXES, &conv_ok); + + if (!conv_ok) { + fprintf(stderr, "\nError: Invalid TX frequency: %d\n\n", + config->tx_freq); + return -1; + } + break; + + case 'r': + config->rx_freq = str2uint_suffix(optarg, 1, INT_MAX, + FREQ_SUFFIXES, NUM_FREQ_SUFFIXES, &conv_ok); + + if (!conv_ok) { + fprintf(stderr, "\nError: Invalid RX frequency: %d\n\n", + config->rx_freq); + return -1; + } + break; + + case 's': + config->sample_rate = str2uint_suffix(optarg, 1, INT_MAX, + FREQ_SUFFIXES, NUM_FREQ_SUFFIXES, + &conv_ok); + if (!conv_ok) { + fprintf(stderr, "\nError: Invalid sample rate: %d\n", + config->sample_rate); + } + break; + + case 'b': + config->bandwidth = str2uint_suffix(optarg, 1, INT_MAX, + FREQ_SUFFIXES, NUM_FREQ_SUFFIXES, + &conv_ok); + if (!conv_ok) { + fprintf(stderr, "\nError: Invalid bandwidth: %d\n", + config->bandwidth); + } + break; + + case 'S': + config->samples_per_buffer = + str2int(optarg, 1024, INT_MAX, &conv_ok); + + if (!conv_ok || config->samples_per_buffer % 1024 != 0) { + fprintf(stderr, "\nError: Invalid samples value: %d\n\n", + config->samples_per_buffer); + return -1; + } + break; + + case 'B': + config->num_buffers = str2int(optarg, 1, INT_MAX, &conv_ok); + if (!conv_ok) { + fprintf(stderr, "\nError: " + "Invalid number of buffers: %d\n\n", + config->num_buffers); + return -1; + } + break; + + case 'T': + config->num_transfers = str2int(optarg, 1, INT_MAX, &conv_ok); + if (!conv_ok) { + fprintf(stderr, "\nError: " + "Invalid number of transfers: %d\n\n", + config->num_buffers); + return -1; + } + break; + + case 'v': + if (!strcasecmp(optarg, "critical")) { + config->verbosity = BLADERF_LOG_LEVEL_CRITICAL; + } else if (!strcasecmp(optarg, "error")) { + config->verbosity = BLADERF_LOG_LEVEL_ERROR; + } else if (!strcasecmp(optarg, "warning")) { + config->verbosity = BLADERF_LOG_LEVEL_WARNING; + } else if (!strcasecmp(optarg, "info")) { + config->verbosity = BLADERF_LOG_LEVEL_INFO; + } else if (!strcasecmp(optarg, "debug")) { + config->verbosity = BLADERF_LOG_LEVEL_DEBUG; + } else if (!strcasecmp(optarg, "verbose")) { + config->verbosity = BLADERF_LOG_LEVEL_VERBOSE; + } else { + fprintf(stderr, "Unknown verbosity level: %s\n", optarg); + return -1; + } + break; + + case 'h': + return 1; + + default: + return -1; + } + + opt = getopt_long(argc, argv, OPTARG_STR, long_options, &opt_idx); + } + + if (config->samples_per_buffer < 1024 || + config->samples_per_buffer % 1024 != 0) { + fprintf(stderr, "\nError: " + "# samples must be >= 1024 and a multiple of 1024\n\n"); + return -1; + } + + if (config->num_buffers < (config->num_transfers + 2)) { + fprintf(stderr, "\nError: " + "# buffers (%u) must be at least 2 greater than " + "# transfers (%u)\n\n", config->num_buffers, + config->num_transfers); + return -1; + } + + return 0; +} + + + +int main(int argc, char *argv[]) +{ + int status; + struct repeater_config config; + + status = handle_args(argc, argv, &config); + if (!status) { + status = repeater_run(&config); + } else { + usage(argv[0]); + } + + repeater_config_deinit(&config); + return status; +} diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/tests/test_repeater/src/repeater.c bladerf-0.3.0+git20130916/host/libraries/libbladeRF/tests/test_repeater/src/repeater.c --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/tests/test_repeater/src/repeater.c 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/tests/test_repeater/src/repeater.c 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,534 @@ +/* + * This file implements the guts of the simple full-duplex repeater. + * + * We run two threads to block on bladerf_stream() calls and handle + * callbacks, while the "main" thread waits for user input to shut down. + * + * When starting a TX stream, an initial set of callbacks are immediately fired + * off to fill the initial set of transfers. Before starting the TX stream, we + * first wait to start the RX stream has filled enough buffers to account for + * the initial set of TX transfers. This is referred to as the "prefill count" + * in this code. + * + * We set the prefill count halfway between the total number of buffers and + * transfers: + * + * +---------+ <-- # buffers (32) + * | | + * +---------+ <-- prefill count (24) + * | | + * +---------+ <-- # transfers (16) + * | | + * | | + * +---------+ 0 + * + * + * + * Although we designate each thread "RX" or "TX", note that these threads + * may receive callbacks for the other module. Therefore, the callbacks + * cannot block [1] and must be implemented in a thread-safe manner; + * accesses to buffer management data are locked via a mutex. + * + * [1] If a TX callback were to block to wait for RX buffers to + * fill more, deadlock could occur because two TX callbacks could be fired + * off before an RX callback is exectuted to release the TX callbacks. + * + * + * Overruns and underruns are not handled intelligently in this simple test. + * If either occur (they shouldn't), the associated tasks shut down and wait + * for the user to terminate the program. + */ + +#include +#include +#include +#include +#include +#include + +#include "repeater.h" +#include "minmax.h" + +/* Thread-safe wrapper around fprintf(stderr, ...) */ +#define print_error(repeater_, ...) do { \ + pthread_mutex_lock(&repeater_->stderr_lock); \ + fprintf(stderr, __VA_ARGS__); \ + pthread_mutex_unlock(&repeater_->stderr_lock); \ +} while (0) + +struct buf_mgmt +{ + int rx_idx; /* Next sample buffer to RX into. < 0 indicates stop */ + int tx_idx; /* Next sample buffer to TX from. < 0 indicates stop */ + size_t num_filled; /* Number of buffers filled with RX data awaiting TX */ + + size_t prefill_count; /* Since the initial set of TX callbacks will look + to fill all available transfers, we must + ensure that the RX task has prefilled a + sufficient number of buffers */ + + void **samples; /* Sample buffers */ + size_t num_buffers; /* # of sample buffers */ + + /* Used to signal the TX thread when a few samplse have been buffered up */ + pthread_cond_t samples_available; + + pthread_mutex_t lock; +}; + +struct repeater +{ + struct bladerf *device; + + pthread_t rx_task; + struct bladerf_stream *rx_stream; + + pthread_t tx_task; + struct bladerf_stream *tx_stream; + + pthread_mutex_t stderr_lock; + + struct buf_mgmt buf_mgmt; +}; + +void repeater_config_init(struct repeater_config *c) +{ + c->device_str = NULL; + + c->tx_freq = DEFAULT_FREQUENCY; + c->rx_freq = DEFAULT_FREQUENCY; + c->sample_rate = DEFAULT_SAMPLE_RATE; + + c->num_buffers = DEFAULT_NUM_BUFFERS; + c->num_transfers = DEFAULT_NUM_TRANSFERS; + c->samples_per_buffer = DEFAULT_SAMPLES_PER_BUFFER; + + c->verbosity = BLADERF_LOG_LEVEL_INFO; +} + +void repeater_config_deinit(struct repeater_config *c) +{ + free(c->device_str); + c->device_str = NULL; +} + +static void *tx_stream_callback(struct bladerf *dev, + struct bladerf_stream *stream, + struct bladerf_metadata *meta, + void *samples, + size_t num_samples, + void *user_data) +{ + void *ret; + struct repeater *repeater = (struct repeater *)user_data; + + pthread_mutex_lock(&repeater->buf_mgmt.lock); + + if (repeater->buf_mgmt.tx_idx < 0) { + ret = NULL; + } else { + + /* We shouldn't encounter underruns, but for the sake of simplicity + * in this test/example, we'll just error out if we hit one */ + if (repeater->buf_mgmt.num_filled == 0) { + ret = NULL; + print_error(repeater, + "TX underrun encountered. Terminating TX task.\n"); + } else { + + ret = repeater->buf_mgmt.samples[repeater->buf_mgmt.tx_idx++]; + + if (repeater->buf_mgmt.tx_idx >= (int)repeater->buf_mgmt.num_buffers) { + repeater->buf_mgmt.tx_idx = 0; + } + + repeater->buf_mgmt.num_filled--; + } + } + + pthread_mutex_unlock(&repeater->buf_mgmt.lock); + + return ret; +} + +void * tx_task_run(void *repeater_) +{ + int status; + struct repeater *repeater = (struct repeater *)repeater_; + bool exit_early; + + /* Wait for RX task to buffer up some samples before we begin + * consuming them */ + pthread_mutex_lock(&repeater->buf_mgmt.lock); + while(repeater->buf_mgmt.num_filled < repeater->buf_mgmt.prefill_count && + repeater->buf_mgmt.tx_idx >= 0) { + + status = pthread_cond_wait(&repeater->buf_mgmt.samples_available, + &repeater->buf_mgmt.lock); + } + + exit_early = repeater->buf_mgmt.tx_idx < 0; + pthread_mutex_unlock(&repeater->buf_mgmt.lock); + + if (!exit_early) { + /* Call stream */ + status = bladerf_stream(repeater->tx_stream, BLADERF_MODULE_TX); + + if (status < 0) { + print_error(repeater, "TX stream failure: %s\n", + bladerf_strerror(status)); + } + } else { + printf("EARLY EXIT\n"); + } + + return NULL; +} + +static void *rx_stream_callback(struct bladerf *dev, + struct bladerf_stream *stream, + struct bladerf_metadata *meta, + void *samples, + size_t num_samples, + void *user_data) +{ + struct repeater *repeater = (struct repeater *)user_data; + void *ret; + + pthread_mutex_lock(&repeater->buf_mgmt.lock); + + if (repeater->buf_mgmt.rx_idx < 0) { + ret = NULL; + } else { + ret = repeater->buf_mgmt.samples[repeater->buf_mgmt.rx_idx++]; + + /* Wrap back around */ + if (repeater->buf_mgmt.rx_idx >= (int)repeater->buf_mgmt.num_buffers) { + repeater->buf_mgmt.rx_idx = 0; + } + + if (repeater->buf_mgmt.num_filled >= 2 * repeater->buf_mgmt.num_buffers) { + /* We shouldn't encounter overruns, but if we do, we'll just + * error out of the program, for the sake of simplicity */ + print_error(repeater, + "RX Overrun encountered. Terminating RX task.\n"); + ret = NULL; + } else { + repeater->buf_mgmt.num_filled++; + } + pthread_cond_signal(&repeater->buf_mgmt.samples_available); + } + + pthread_mutex_unlock(&repeater->buf_mgmt.lock); + + return ret; +} + +void * rx_task_run(void *repeater_) +{ + int status; + struct repeater *repeater = (struct repeater *)repeater_; + + status = bladerf_stream(repeater->rx_stream, BLADERF_MODULE_RX); + if (status < 0) { + print_error(repeater, "RX stream failure: %s\n", bladerf_strerror(status)); + } + + return NULL; +} + +static inline void repeater_init(struct repeater *repeater, + struct repeater_config *config) +{ + memset(repeater, 0, sizeof(*repeater)); + + pthread_mutex_init(&repeater->stderr_lock, NULL); + pthread_mutex_init(&repeater->buf_mgmt.lock, NULL); + pthread_cond_init(&repeater->buf_mgmt.samples_available, NULL); + + repeater->buf_mgmt.num_filled = 0; + repeater->buf_mgmt.num_buffers = config->num_buffers; + + /* We must prefill, at a minimum, 1 + the number of TX transfers, + * since the intial set of TX callbacks will look to populate each + * transfer. Below, we try to set the prefill count halfway between + * the number of buffers and the number of transfers. */ + repeater->buf_mgmt.prefill_count = config->num_transfers; + repeater->buf_mgmt.prefill_count += + (repeater->buf_mgmt.num_buffers - config->num_transfers) / 2; + + assert(repeater->buf_mgmt.prefill_count != 0); + + bladerf_log_set_verbosity(config->verbosity); +} + +static int init_device(struct repeater *repeater, struct repeater_config *config) +{ + int status; + unsigned int actual_value; + + status = bladerf_open(&repeater->device, config->device_str); + if (!repeater->device) { + fprintf(stderr, "Failed to open %s: %s\n", config->device_str, + bladerf_strerror(status)); + return -1; + } + + status = bladerf_is_fpga_configured(repeater->device); + if (status < 0) { + fprintf(stderr, "Failed to determine if FPGA is loaded: %s\n", + bladerf_strerror(status)); + goto init_device_error; + } else if (status == 0) { + fprintf(stderr, "FPGA is not loaded. Aborting.\n"); + status = BLADERF_ERR_NODEV; + goto init_device_error; + } + + status = bladerf_set_bandwidth(repeater->device, BLADERF_MODULE_TX, + config->bandwidth, &actual_value); + + if (status < 0) { + fprintf(stderr, "Failed to set TX bandwidth: %s\n", + bladerf_strerror(status)); + goto init_device_error; + } else { + printf("Actual TX bandwidth: %d Hz\n", actual_value); + } + + status = bladerf_set_bandwidth(repeater->device, BLADERF_MODULE_RX, + config->bandwidth, &actual_value); + + if (status < 0) { + fprintf(stderr, "Failed to set RX bandwidth: %s\n", + bladerf_strerror(status)); + goto init_device_error; + } else { + printf("Actual RX bandwidth: %d Hz\n", actual_value); + } + + status = bladerf_set_sample_rate(repeater->device, BLADERF_MODULE_TX, + config->sample_rate, &actual_value); + + if (status < 0) { + fprintf(stderr, "Failed to set TX sample rate: %s\n", + bladerf_strerror(status)); + goto init_device_error; + } else { + printf("Actual TX sample rate is %d Hz\n", actual_value); + } + + status = bladerf_set_sample_rate(repeater->device, BLADERF_MODULE_RX, + config->sample_rate, &actual_value); + + if (status < 0) { + fprintf(stderr, "Failed to set RX sample rate: %s\n", + bladerf_strerror(status)); + goto init_device_error; + } else { + printf("Actual RX sample rate is %d Hz\n", actual_value); + } + + status = bladerf_set_frequency(repeater->device, + BLADERF_MODULE_TX, config->tx_freq); + if (status < 0) { + fprintf(stderr, "Failed to set TX frequency: %s\n", + bladerf_strerror(status)); + goto init_device_error; + } else { + printf("Set TX frequency to %d Hz\n", config->tx_freq); + } + + status = bladerf_set_frequency(repeater->device, + BLADERF_MODULE_RX, config->rx_freq); + if (status < 0) { + fprintf(stderr, "Failed to set RX frequency: %s\n", + bladerf_strerror(status)); + goto init_device_error; + } else { + printf("Set RX frequency to %d Hz\n", config->rx_freq); + } + + status = bladerf_enable_module(repeater->device, BLADERF_MODULE_RX, true); + if (status < 0) { + fprintf(stderr, "Failed to enable RX module: %s\n", + bladerf_strerror(status)); + goto init_device_error; + } else { + printf("Enabled RX module\n"); + } + + status = bladerf_enable_module(repeater->device, BLADERF_MODULE_TX, true); + if (status < 0) { + bladerf_enable_module(repeater->device, BLADERF_MODULE_RX, false); + fprintf(stderr, "Failed to enable TX module: %s\n", + bladerf_strerror(status)); + goto init_device_error; + } else { + printf("Enabled TX module\n"); + } + + return status; + +init_device_error: + bladerf_close(repeater->device); + repeater->device = NULL; + + return status; +} + +static int init_streams(struct repeater *repeater, + struct repeater_config *config) +{ + int status; + + /* TODO Until we can provide NULL to the init stream call to indicate that + * we want to use user-probveded buffers, we'll just allocate and not + * use some dummy buffers for TX */ + void **dummy; + + status = bladerf_init_stream(&repeater->rx_stream, + repeater->device, + rx_stream_callback, + &repeater->buf_mgmt.samples, + config->num_buffers, + BLADERF_FORMAT_SC16_Q12, + config->samples_per_buffer, + config->num_transfers, + repeater); + if (status < 0) { + fprintf(stderr, "Failed to initialize RX stream: %s\n", + bladerf_strerror(status)); + return status; + } else { + repeater->buf_mgmt.rx_idx = 0; + } + + + status = bladerf_init_stream(&repeater->tx_stream, + repeater->device, + tx_stream_callback, + &dummy, + config->num_buffers, + BLADERF_FORMAT_SC16_Q12, + config->samples_per_buffer, + config->num_transfers, + repeater); + if (status < 0) { + fprintf(stderr, "Failed to initialize TX stream: %s\n", + bladerf_strerror(status)); + return status; + } else { + repeater->buf_mgmt.tx_idx = 0; + } + + repeater->buf_mgmt.num_buffers = config->num_buffers; + + return 0; +} + +static int start_tasks(struct repeater *repeater) +{ + int status; + + status = pthread_create(&repeater->rx_task, NULL, rx_task_run, repeater); + if (status < 0) { + return -1; + } + + status = pthread_create(&repeater->tx_task, NULL, tx_task_run, repeater); + if (status < 0) { + pthread_cancel(repeater->rx_task); + pthread_join(repeater->rx_task, NULL); + return -1; + } + + return 0; +} + +static void stop_tasks(struct repeater *repeater) +{ + print_error(repeater, "Stoppping RX and tasks...\n"); + pthread_mutex_lock(&repeater->buf_mgmt.lock); + repeater->buf_mgmt.tx_idx = -1; + repeater->buf_mgmt.rx_idx = -1; + pthread_mutex_unlock(&repeater->buf_mgmt.lock); + pthread_join(repeater->rx_task, NULL); + + /* Fire off the "samples available" signal to the TX thread, in case + * it is still awaiting for the prefill completion */ + pthread_mutex_lock(&repeater->buf_mgmt.lock); + pthread_cond_signal(&repeater->buf_mgmt.samples_available); + pthread_mutex_unlock(&repeater->buf_mgmt.lock); + pthread_join(repeater->tx_task, NULL); + +} + +static void deinit(struct repeater *repeater) +{ + + if (repeater->device) { + if (repeater->rx_stream) { + bladerf_deinit_stream(repeater->rx_stream); + } + + if (repeater->tx_stream) { + bladerf_deinit_stream(repeater->tx_stream); + } + + bladerf_enable_module(repeater->device, BLADERF_MODULE_RX, false); + bladerf_enable_module(repeater->device, BLADERF_MODULE_TX, false); + + bladerf_close(repeater->device); + repeater->device = NULL; + } +} + +static int init(struct repeater *repeater, struct repeater_config *config) +{ + int status; + + repeater_init(repeater, config); + + /* Configure the bladeRF */ + status = init_device(repeater, config); + if (status < 0) { + fprintf(stderr, "Failed to initialize device.\n"); + return -1; + } + + /* Allocate streams */ + status = init_streams(repeater, config); + if (status < 0) { + fprintf(stderr, "Failed to allocate streams.\n"); + return -1; + } + + return 0; +} + +int repeater_run(struct repeater_config *config) +{ + int status; + struct repeater repeater; + + status = init(&repeater, config); + if (status == 0) { + + /* Start tasks and wait for a key press to shut down */ + status = start_tasks(&repeater); + if (status < 0) { + fprintf(stderr, "Failed to start tasks.\n"); + } else { + printf("Repeater running. Press enter to stop.\n"); + getchar(); + } + + /* Stop tasks */ + stop_tasks(&repeater); + + deinit(&repeater); + } + + return status; +} diff -Nru bladerf-0.3.0+git20130911/host/libraries/libbladeRF/tests/test_repeater/src/repeater.h bladerf-0.3.0+git20130916/host/libraries/libbladeRF/tests/test_repeater/src/repeater.h --- bladerf-0.3.0+git20130911/host/libraries/libbladeRF/tests/test_repeater/src/repeater.h 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/libraries/libbladeRF/tests/test_repeater/src/repeater.h 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,54 @@ +#ifndef REPEATER_H__ +#define REPEATER_H__ + +#define DEFAULT_NUM_BUFFERS 32 +#define DEFAULT_NUM_TRANSFERS 16 +#define DEFAULT_SAMPLES_PER_BUFFER 8192 +#define DEFAULT_SAMPLE_RATE 10000000 +#define DEFAULT_FREQUENCY 1000000000 +#define DEFAULT_BANDWIDTH 7000000 + +/** + * Application configuration + */ +struct repeater_config +{ + char *device_str; /**< Device to use */ + + int tx_freq; /**< TX frequency */ + int rx_freq; /**< RX frequency */ + int sample_rate; /**< Sampling rate */ + int bandwidth; /**< Bandwidth */ + + int num_buffers; /**< Number of buffers to allocate and use */ + int num_transfers; /**< Number of transfers to allocate and use */ + int samples_per_buffer; /**< Number of SC16Q12 samples per buffer */ + + + bladerf_log_level verbosity; /** Library verbosity */ +}; + +/** + * Initialize the provided application config to defaults + * + * @param c Configuration to initialize + */ +void repeater_config_init(struct repeater_config *c); + +/** + * Deinitialize configuration and free any heap-allocated items + * + * @param c Configuration to deinitialize + */ +void repeater_config_deinit(struct repeater_config *c); + +/** + * Kick off repeater test + * + * @param c Repeater configuration + * + * @return 0 on succes, non-zero on failure + */ +int repeater_run(struct repeater_config *c); + +#endif diff -Nru bladerf-0.3.0+git20130911/host/misc/udev/88-nuand.rules bladerf-0.3.0+git20130916/host/misc/udev/88-nuand.rules --- bladerf-0.3.0+git20130911/host/misc/udev/88-nuand.rules 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/misc/udev/88-nuand.rules 2013-09-17 07:44:19.000000000 +0000 @@ -1,2 +1,4 @@ # nuand bladeRF ATTR{idVendor}=="1d50", ATTR{idProduct}=="6066", MODE="660", GROUP="plugdev" +ATTR{idVendor}=="1d50", ATTR{idProduct}=="6080", MODE="660", GROUP="plugdev" +ATTR{idVendor}=="04b4", ATTR{idProduct}=="00f3", MODE="660", GROUP="plugdev" diff -Nru bladerf-0.3.0+git20130911/host/utilities/CMakeLists.txt bladerf-0.3.0+git20130916/host/utilities/CMakeLists.txt --- bladerf-0.3.0+git20130911/host/utilities/CMakeLists.txt 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/utilities/CMakeLists.txt 2013-09-17 07:44:19.000000000 +0000 @@ -1,2 +1,16 @@ cmake_minimum_required(VERSION 2.8) add_subdirectory(bladeRF-cli) + +if(ENABLE_BACKEND_LIBUSB) + find_package(LibUSB) + include(CheckFunctionExists) + set(CMAKE_REQUIRED_INCLUDES libusb.h) + set(CMAKE_REQUIRED_LIBRARIES ${LIBUSB_LIBRARIES}) + check_function_exists(libusb_hotplug_register_callback HAVE_LIBUSB_HOTPLUG) + unset(CMAKE_REQUIRED_INCLUDES) + unset(CMAKE_REQUIRED_LIBRARIES) +endif(ENABLE_BACKEND_LIBUSB) + +if(${HAVE_LIBUSB_HOTPLUG} MATCHES "1") + add_subdirectory(bladeRF-flash) +endif(${HAVE_LIBUSB_HOTPLUG} MATCHES "1") diff -Nru bladerf-0.3.0+git20130911/host/utilities/bladeRF-cli/CMakeLists.txt bladerf-0.3.0+git20130916/host/utilities/bladeRF-cli/CMakeLists.txt --- bladerf-0.3.0+git20130911/host/utilities/bladeRF-cli/CMakeLists.txt 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/utilities/bladeRF-cli/CMakeLists.txt 2013-09-17 07:44:19.000000000 +0000 @@ -68,7 +68,7 @@ endif() if(MSVC) - set(CLI_INCLUDE_DIRS ${CLI_INCLUDE_DIRS} + set(CLI_INCLUDE_DIRS ${CLI_INCLUDE_DIRS} ${BLADERF_HOST_COMMON_INCLUDE_DIRS}/windows ${LIBPTHREADSWIN32_INCLUDE_DIRS} ) @@ -84,6 +84,7 @@ src/common.c src/cmd/calibrate.c src/cmd/cmd.c + src/cmd/erase.c src/cmd/load.c src/cmd/open.c src/cmd/peek.c @@ -93,6 +94,8 @@ src/cmd/probe.c src/cmd/rxtx.c src/cmd/version.c + src/cmd/recover.c + src/cmd/jump_boot.c src/interactive/interactive.c ${BLADERF_HOST_COMMON_SOURCE_DIR}/conversions.c ${BLADERF_HOST_COMMON_SOURCE_DIR}/log.c @@ -149,21 +152,6 @@ install(TARGETS bladeRF-cli DESTINATION ${BIN_INSTALL_DIR}) -if(MSVC) - add_custom_command(TARGET bladeRF-cli POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${LIBPTHREADSWIN32_PATH}/dll/${LIBPTHREADSWIN32_LIBRARY_PATH_SUFFIX}/pthreadVC2.dll" - "${CMAKE_BINARY_DIR}/utilities/bladeRF-cli/$(Configuration)/") - add_custom_command(TARGET bladeRF-cli POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${CMAKE_BINARY_DIR}/libraries/libbladeRF/$(Configuration)/libusb-1.0.dll" - "${CMAKE_BINARY_DIR}/utilities/bladeRF-cli/$(Configuration)/") - add_custom_command(TARGET bladeRF-cli POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${CMAKE_BINARY_DIR}/libraries/libbladeRF/$(Configuration)/bladeRF.dll" - "${CMAKE_BINARY_DIR}/utilities/bladeRF-cli/$(Configuration)/") -endif(MSVC) - ################################################################################ # Informational output ################################################################################ diff -Nru bladerf-0.3.0+git20130911/host/utilities/bladeRF-cli/src/cmd/cmd.c bladerf-0.3.0+git20130916/host/utilities/bladeRF-cli/src/cmd/cmd.c --- bladerf-0.3.0+git20130911/host/utilities/bladeRF-cli/src/cmd/cmd.c 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/utilities/bladeRF-cli/src/cmd/cmd.c 2013-09-17 07:44:19.000000000 +0000 @@ -14,9 +14,12 @@ DECLARE_CMD(poke); DECLARE_CMD(print); DECLARE_CMD(probe); +DECLARE_CMD(erase); DECLARE_CMD(set); DECLARE_CMD(rxtx); DECLARE_CMD(version); +DECLARE_CMD(recover); +DECLARE_CMD(jump_to_bootloader); #define MAX_ARGS 10 @@ -36,11 +39,14 @@ static const char *cmd_names_poke[] = { "poke", "po", NULL }; static const char *cmd_names_print[] = { "print", "pr", "p", NULL }; static const char *cmd_names_probe[] = { "probe", "pro", NULL }; +static const char *cmd_names_erase[] = { "erase", "e", NULL }; static const char *cmd_names_quit[] = { "quit", "q", "exit", "x", NULL }; static const char *cmd_names_rx[] = { "rx", "receive", NULL }; static const char *cmd_names_tx[] = { "tx", "transmit", NULL }; static const char *cmd_names_set[] = { "set", "s", NULL }; static const char *cmd_names_ver[] = { "version", "ver", "v", NULL }; +static const char *cmd_names_rec[] = { "recover", "r", NULL }; +static const char *cmd_names_jump[] = { "jump_to_boot", "j", NULL }; static const struct cmd cmd_table[] = { { @@ -273,6 +279,18 @@ ) }, { + FIELD_INIT(.names, cmd_names_erase), + FIELD_INIT(.exec, cmd_erase), + FIELD_INIT(.desc, "Erase part of FX3 flash device"), + FIELD_INIT(.help, "erase\n" + "\n" + "Erase pages from FX3 flash device.\n" + "\n" + " page_offset Starting page to erase\n" + " n_bytes Number of pages to erase\n" + ) + }, + { FIELD_INIT(.names, cmd_names_ver), FIELD_INIT(.exec, cmd_version), FIELD_INIT(.desc, "Device and firmware versions"), @@ -283,6 +301,22 @@ ) }, { + FIELD_INIT(.names, cmd_names_rec), + FIELD_INIT(.exec, cmd_recover), + FIELD_INIT(.desc, "Load firmware when operating in FX3 bootloader mode"), + FIELD_INIT(.help, + "recover [device_str] [file]\n" + ) + }, + { + FIELD_INIT(.names, cmd_names_jump), + FIELD_INIT(.exec, cmd_jump_to_bootloader), + FIELD_INIT(.desc, "Jump to FX3 bootloader"), + FIELD_INIT(.help, + "jump_to_boot\n" + ) + }, + { FIELD_INIT(.names, cmd_names_clear), FIELD_INIT(.exec, cmd_clear), FIELD_INIT(.desc, "Clear the screen"), diff -Nru bladerf-0.3.0+git20130911/host/utilities/bladeRF-cli/src/cmd/erase.c bladerf-0.3.0+git20130916/host/utilities/bladeRF-cli/src/cmd/erase.c --- bladerf-0.3.0+git20130911/host/utilities/bladeRF-cli/src/cmd/erase.c 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/utilities/bladeRF-cli/src/cmd/erase.c 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include "cmd.h" + +int cmd_erase(struct cli_state *state, int argc, char **argv) +{ + int status; + int page_offset, n_bytes; + bool ok; + + if (!cli_device_is_opened(state)) { + return CMD_RET_NODEV; + } + + if (argc != 3) { + return CMD_RET_NARGS; + } + + page_offset = str2uint(argv[1], 0, INT_MAX, &ok); + if(!ok) { + cli_err(state, argv[0], "Invalid value for \"page_offset\" (%s)", argv[1]); + return CMD_RET_INVPARAM; + } + + n_bytes = str2uint(argv[2], 0, INT_MAX, &ok); + if(!ok) { + cli_err(state, argv[0], "Invalid value for \"n_bytes\" (%s)", argv[2]); + return CMD_RET_INVPARAM; + } + + status = bladerf_erase_flash(state->dev, page_offset, n_bytes); + + if (status >= 0) { + printf("Erased %d pages at %d\n", status, page_offset); + return CMD_RET_OK; + } else { + state->last_lib_error = status; + return CMD_RET_LIBBLADERF; + } +} + diff -Nru bladerf-0.3.0+git20130911/host/utilities/bladeRF-cli/src/cmd/jump_boot.c bladerf-0.3.0+git20130916/host/utilities/bladeRF-cli/src/cmd/jump_boot.c --- bladerf-0.3.0+git20130911/host/utilities/bladeRF-cli/src/cmd/jump_boot.c 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/utilities/bladeRF-cli/src/cmd/jump_boot.c 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include "cmd.h" + +int cmd_jump_to_bootloader(struct cli_state *state, int argc, char **argv) +{ + int status; + + if (!cli_device_is_opened(state)) { + return CMD_RET_NODEV; + } + + if (argc != 1) { + return CMD_RET_NARGS; + } + + status = bladerf_jump_to_bootloader(state->dev); + + if (status == 0) { + return CMD_RET_OK; + } else { + state->last_lib_error = status; + return CMD_RET_LIBBLADERF; + } +} + diff -Nru bladerf-0.3.0+git20130911/host/utilities/bladeRF-cli/src/cmd/printset.c bladerf-0.3.0+git20130916/host/utilities/bladeRF-cli/src/cmd/printset.c --- bladerf-0.3.0+git20130911/host/utilities/bladeRF-cli/src/cmd/printset.c 2013-09-12 11:52:32.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/utilities/bladeRF-cli/src/cmd/printset.c 2013-09-17 07:44:19.000000000 +0000 @@ -731,7 +731,7 @@ if( argc > 2 && rv == CMD_RET_OK ) { bool ok; unsigned int rate, actual; - rate = str2uint_suffix( argv[argc-1], 160000, 40000000, + rate = str2uint_suffix( argv[argc-1], 80000, 40000000, FREQ_SUFFIXES, NUM_FREQ_SUFFIXES, &ok ); if( !ok ) { diff -Nru bladerf-0.3.0+git20130911/host/utilities/bladeRF-cli/src/cmd/recover.c bladerf-0.3.0+git20130916/host/utilities/bladeRF-cli/src/cmd/recover.c --- bladerf-0.3.0+git20130911/host/utilities/bladeRF-cli/src/cmd/recover.c 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/utilities/bladeRF-cli/src/cmd/recover.c 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include "cmd.h" + +int cmd_recover(struct cli_state *state, int argc, char **argv) +{ + int status; + + if (argc != 3) { + return CMD_RET_NARGS; + } + + status = bladerf_recover(argv[1], argv[2]); + + if (status == 0) { + printf("Loaded! An open is now required\n"); + return CMD_RET_OK; + } else { + state->last_lib_error = status; + return CMD_RET_LIBBLADERF; + } +} + + diff -Nru bladerf-0.3.0+git20130911/host/utilities/bladeRF-flash/CMakeLists.txt bladerf-0.3.0+git20130916/host/utilities/bladeRF-flash/CMakeLists.txt --- bladerf-0.3.0+git20130911/host/utilities/bladeRF-flash/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/utilities/bladeRF-flash/CMakeLists.txt 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,95 @@ +# Copyright 2013 Nuand, LLC. +# +# This file is part of the bladeRF project +# +# TODO license text here (see top-level COPYING for time being) +cmake_minimum_required(VERSION 2.8) +project(bladeRF-flash C) + +################################################################################ +# Version information +################################################################################ + +set(VERSION_INFO_MAJOR 0) +set(VERSION_INFO_MINOR 4) +set(VERSION_INFO_PATCH 0) +set(VERSION_INFO_EXTRA "git") +include(Version) + +set(VERSION "${VERSION_INFO}") + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/src/version.h.in + ${CMAKE_CURRENT_BINARY_DIR}/src/version.h + @ONLY +) + +################################################################################ +# Build dependencies +################################################################################ +if(ENABLE_BACKEND_LIBUSB) + find_package(LibUSB) + if(NOT LIBUSB_FOUND) + message(FATAL_ERROR "libusb-1.0 required to use for libusb backend") + endif(NOT LIBUSB_FOUND) +else() + return() +endif(ENABLE_BACKEND_LIBUSB) + +################################################################################ +# Include paths +################################################################################ +set(FLASH_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_BINARY_DIR}/src + ${BLADERF_HOST_COMMON_INCLUDE_DIRS} + ${libbladeRF_SOURCE_DIR}/include + ${BLADERF_FW_COMMON_INCLUDE_DIR} + ${LIBUSB_INCLUDE_DIRS}) + +include_directories(${FLASH_INCLUDE_DIRS}) + +################################################################################ +# Configure source files +################################################################################ +set(BLADERF_FLASH_SOURCE + src/main.c + ${BLADERF_HOST_COMMON_SOURCE_DIR}/conversions.c + ${BLADERF_HOST_COMMON_SOURCE_DIR}/log.c + ${BLADERF_HOST_COMMON_SOURCE_DIR}/bladerf_devinfo.c + ${BLADERF_HOST_COMMON_SOURCE_DIR}/device_identifier.c + ${BLADERF_HOST_COMMON_SOURCE_DIR}/ezusb.c +) + +if(MSVC) + set(BLADERF_FLASH_SOURCE ${BLADERF_FLASH_SOURCE} + ${BLADERF_HOST_COMMON_SOURCE_DIR}/windows/getopt.c + ${BLADERF_HOST_COMMON_SOURCE_DIR}/windows/getopt_long.c + ) +endif() + +add_executable(bladeRF-flash ${BLADERF_FLASH_SOURCE}) + +################################################################################ +# Build configuration +################################################################################ +set(FLASH_LINK_LIBRARIES + libbladerf_shared + ${CMAKE_THREAD_LIBS_INIT} +) + +target_link_libraries(bladeRF-flash ${FLASH_LINK_LIBRARIES}) + +################################################################################ +# Installation +################################################################################ +if(NOT DEFINED BIN_INSTALL_DIR) + set(BIN_INSTALL_DIR bin) +endif() + +install(TARGETS bladeRF-flash DESTINATION ${BIN_INSTALL_DIR}) + +################################################################################ +# Informational output +################################################################################ +message(STATUS "Configured to build bladeRF-flash version: ${VERSION_INFO}") diff -Nru bladerf-0.3.0+git20130911/host/utilities/bladeRF-flash/src/main.c bladerf-0.3.0+git20130916/host/utilities/bladeRF-flash/src/main.c --- bladerf-0.3.0+git20130911/host/utilities/bladeRF-flash/src/main.c 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/utilities/bladeRF-flash/src/main.c 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,708 @@ +/* + * bladeRF flashing utility + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "version.h" +#include "log.h" +#include "ezusb.h" +#include "device_identifier.h" +#include "host_config.h" +#include "bladerf_devinfo.h" +#include + + +#define RECONNECT_TIME 10 /* Time for USB reconnect after jump */ +#define OPTSTR "d:f:rlLv:Vh" + +static const struct option longopts[] = { + { "device", required_argument, 0, 'd' }, + { "flash-firmware", required_argument, 0, 'f' }, + { "reset", no_argument, 0, 'r' }, + { "load-ram", no_argument, 0, 'l' }, + { "lib-version", no_argument, 0, 'L' }, + { "verbosity", required_argument, 0, 'v' }, + { "version", no_argument, 0, 'V' }, + { "help", no_argument, 0, 'h' }, + { 0, 0, 0, 0 }, +}; + +/* Runtime configuration items */ +struct rc_config { + bool reset; + bool load_ram_only; + bool show_help; + bool show_version; + bool show_lib_version; + + bladerf_log_level verbosity; + + char *device; + char *fw_file; +}; + +static void init_rc_config(struct rc_config *rc) +{ + rc->reset = false; + rc->load_ram_only = false; + rc->show_help = false; + rc->show_version = false; + rc->show_lib_version = false; + + rc->verbosity = BLADERF_LOG_LEVEL_INFO; + + rc->device = NULL; + rc->fw_file = NULL; +} + + +/* Fetch runtime-configuration info + * + * Returns 0 on success, -1 on fatal error (and prints error msg to stderr) + */ +int get_rc_config(int argc, char *argv[], struct rc_config *rc) +{ + int optidx; + int c = getopt_long(argc, argv, OPTSTR, longopts, &optidx); + + do { + switch(c) { + case 'd': + rc->device = strdup(optarg); + if (!rc->device) { + perror("strdup"); + return -1; + } + break; + + case 'f': + rc->fw_file = strdup(optarg); + if (!rc->fw_file) { + perror("strdup"); + return -1; + } + break; + + case 'r': + rc->reset = true; + break; + + case 'l': + rc->load_ram_only = true; + break; + + case 'L': + rc->show_lib_version = true; + break; + + case 'v': + if (!strcasecmp(optarg, "critical")) { + rc->verbosity = BLADERF_LOG_LEVEL_CRITICAL; + } else if (!strcasecmp(optarg, "error")) { + rc->verbosity = BLADERF_LOG_LEVEL_ERROR; + } else if (!strcasecmp(optarg, "warning")) { + rc->verbosity = BLADERF_LOG_LEVEL_WARNING; + } else if (!strcasecmp(optarg, "info")) { + rc->verbosity = BLADERF_LOG_LEVEL_INFO; + } else if (!strcasecmp(optarg, "debug")) { + rc->verbosity = BLADERF_LOG_LEVEL_DEBUG; + } else if (!strcasecmp(optarg, "verbose")) { + rc->verbosity = BLADERF_LOG_LEVEL_VERBOSE; + } else { + fprintf(stderr, "Unknown verbosity level: %s\n", optarg); + return -1; + } + break; + + case 'V': + rc->show_version = true; + break; + + case 'h': + rc->show_help = true; + break; + + default: + return -1; + } + + c = getopt_long(argc, argv, OPTSTR, longopts, &optidx); + } while (c != -1); + + return 0; +} + +void usage(const char *argv0) +{ + printf("Usage: %s \n", argv0); + printf("bladeRF flashing utility (" BLADERF_FLASH_VERSION ")\n\n"); + printf("Options:\n"); + printf(" -d, --device Use the specified bladeRF device.\n"); + printf(" -f, --flash-firmware Flash specified firmware file.\n"); + printf(" -r, --reset Start with RESET instead of JUMP_TO_BOOTLOADER.\n"); + printf(" -l, --load-ram Only load FX3 RAM instead of also flashing.\n"); + printf(" -L, --lib-version Print libbladeRF version and exit.\n"); + printf(" -v, --verbosity Set the libbladeRF verbosity level.\n"); + printf(" Levels, listed in increasing verbosity, are:\n"); + printf(" critical, error, warning,\n"); + printf(" info, debug, verbose\n"); + printf(" -V, --version Print flasher version and exit.\n"); + printf(" -h, --help Show this help text.\n"); + printf("\n"); + printf("Notes:\n"); + printf(" The -d option takes a device specifier string. See the bladerf_open()\n"); + printf(" documentation for more information about the format of this string.\n"); + printf("\n"); + printf(" If the -d parameter is not provided, the first available device\n"); + printf(" will be used for the provided command, or will be opened prior\n"); + printf(" to entering interactive mode.\n"); + printf("\n"); +} + +typedef struct { + int found; + struct bladerf_devinfo devinfo; + libusb_device *dev; +} event_count_t; + +static int event_count = 0; +static event_count_t fx3_bootloader; +static event_count_t bladerf_bootloader; +static event_count_t bladerf; + +static int count_events( + libusb_context *ctx, libusb_device *dev, + libusb_hotplug_event event, void *user_data) +{ + struct libusb_device_descriptor desc; + int rc; + event_count_t * s = (event_count_t *)user_data; + + if(event != LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) { + return 0; + } + + rc = libusb_get_device_descriptor(dev, &desc); + if (LIBUSB_SUCCESS != rc) { + log_error ("Error getting device descriptor for hotplug\n"); + return 0; + } + + event_count += 1; + s->found += 1; + bladerf_init_devinfo(&s->devinfo); + s->devinfo.backend = BLADERF_BACKEND_LIBUSB; + s->devinfo.usb_bus = libusb_get_bus_number(dev); + s->devinfo.usb_addr = libusb_get_device_address(dev); + + if(s->dev != NULL) { + libusb_unref_device(s->dev); + } + s->dev = dev; + libusb_ref_device(s->dev); + + return 0; +} + +static int init_event_counts(libusb_context *ctx, + int vender_id, int product_id, event_count_t * data) +{ + int status; + + memset(data, 0, sizeof(event_count_t)); + + status = libusb_hotplug_register_callback( + ctx, + LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, + 0, + vender_id, product_id, + LIBUSB_HOTPLUG_MATCH_ANY, + count_events, + data, + NULL); + + return status; +} + +static int get_event_counts( + event_count_t * data, + struct bladerf_devinfo * devinfo, libusb_device **device) +{ + int found; + + found = data->found; + *devinfo = data->devinfo; + *device = data->dev; + data->found = 0; + + return found; +} + +static int register_hotplug_notifications(libusb_context *context) +{ + int status = 0; + + status = init_event_counts(context, + USB_CYPRESS_VENDOR_ID, USB_FX3_PRODUCT_ID, + &fx3_bootloader); + if(status != 0) { + log_error("Failed to init fx3_bootloader monitor, status = %s\n", libusb_error_name(status)); + return status; + } + + status = init_event_counts(context, + USB_NUAND_VENDOR_ID, USB_NUAND_BLADERF_BOOT_PRODUCT_ID, + &bladerf_bootloader); + if(status != 0) { + log_error("Failed to init bladeRF bladerf_bootloader monitor, status = %s\n", libusb_error_name(status)); + return status; + } + + status = init_event_counts(context, + USB_NUAND_VENDOR_ID, USB_NUAND_BLADERF_PRODUCT_ID, + &bladerf); + if(status != 0) { + log_error("Failed to init bladerf monitor, status = %s\n", libusb_error_name(status)); + return status; + } + + return status; +} + +static int device_is_fx3(libusb_device *dev) +{ + int err; + int rv = 0; + struct libusb_device_descriptor desc; + + err = libusb_get_device_descriptor(dev, &desc); + if( err ) { + log_error( "Couldn't open libusb device - %s\n", libusb_error_name(err) ); + } else { + if( + (desc.idVendor == USB_CYPRESS_VENDOR_ID && desc.idProduct == USB_FX3_PRODUCT_ID) || + (desc.idVendor == USB_NUAND_VENDOR_ID && desc.idProduct == USB_NUAND_BLADERF_BOOT_PRODUCT_ID) + ) { + rv = 1; + } + } + return rv; +} + +static int get_devinfo(libusb_device *dev, struct bladerf_devinfo *info) +{ + int status = 0; + libusb_device_handle *handle; + struct libusb_device_descriptor desc; + + status = libusb_open( dev, &handle ); + if( status ) { + log_error( "Couldn't populate devinfo - %s\n", libusb_error_name(status) ); + } else { + /* Populate device info */ + info->backend = BLADERF_BACKEND_LIBUSB; + info->usb_bus = libusb_get_bus_number(dev); + info->usb_addr = libusb_get_device_address(dev); + + status = libusb_get_device_descriptor(dev, &desc); + if (status) { + memset(info->serial, 0, BLADERF_SERIAL_LENGTH); + } else { + status = libusb_get_string_descriptor_ascii(handle, + desc.iSerialNumber, + (unsigned char *)&info->serial, + BLADERF_SERIAL_LENGTH); + + /* Consider this to be non-fatal, otherwise firmware <= 1.1 + * wouldn't be able to get far enough to upgrade */ + if (status < 0) { + log_error("Failed to retrieve serial number\n"); + memset(info->serial, 0, BLADERF_SERIAL_LENGTH); + } + + /* Additinally, adjust for > 0 return code */ + status = 0; + } + + libusb_close( handle ); + } + + + return status; +} + +static int find_fx3_via_info( + libusb_context * context, + struct bladerf_devinfo *info, + libusb_device_handle **handle) { + int status, i, count; + struct bladerf_devinfo thisinfo; + libusb_device *dev, **devs; + libusb_device *found_dev = NULL; + + count = 0; + + status = libusb_get_device_list(context, &devs); + if (status < 0) { + log_error("libusb_get_device_list() failed: %d %s\n", status, libusb_error_name(status)); + return status; + } + + for (i=0; (dev=devs[i]) != NULL; i++) { + if (!device_is_fx3(dev)) { + continue; + } + + status = get_devinfo(dev, &thisinfo); + if (status < 0) { + log_error( "Could not open bladeRF device: %s\n", libusb_error_name(status) ); + status = status; + break; + } + + if (bladerf_devinfo_matches(&thisinfo, info)) { + log_verbose("Found bladeRF bootloader, libusb:device=%d:%d\n", + thisinfo.usb_bus, thisinfo.usb_addr); + count += 1; + found_dev = dev; + } + } + + if(count > 1) { + log_error("Multiple bootloaders found, select one:\n"); + for (i=0; (dev=devs[i]) != NULL; i++) { + if (!device_is_fx3(dev)) { + continue; + } + + status = get_devinfo(dev, &thisinfo); + if (status < 0) { + log_error( "Could not open bladeRF device: %s\n", libusb_error_name(status) ); + status = status; + break; + } + + if (bladerf_devinfo_matches(&thisinfo, info)) { + log_error( " libusb:device=%d:%d\n", + thisinfo.usb_bus, thisinfo.usb_addr); + } + } + return BLADERF_ERR_UNEXPECTED; + } + + if (found_dev == NULL) { + libusb_free_device_list(devs, 1); + log_error("could not find a known device - try specifing bus, dev\n"); + return BLADERF_ERR_NODEV; + } + + status = libusb_open(found_dev, handle); + libusb_free_device_list(devs, 1); + if (status != 0) { + log_error("Error opening device: %s\n", libusb_error_name(status)); + return status; + } + + return 0; +} + +static int poll_for_events(libusb_context * ctx) { + time_t end_t = time(NULL) + RECONNECT_TIME; + struct timeval timeout; + int status; + + timeout.tv_sec = RECONNECT_TIME; + timeout.tv_usec = 0; + + event_count = 0; + + while(!event_count) { + status = libusb_handle_events_timeout_completed(ctx, &timeout, NULL); + if(status != 0) { + log_error("Error waiting for events: %s\n", libusb_error_name(status)); + return status; + } + + if(time(NULL) > end_t) { + break; + } + } + + return 0; +} + +static int look_for_bootloader_connect(libusb_context * ctx, libusb_device **device_out) { + struct bladerf_devinfo devinfo; + int count, status; + + status = poll_for_events(ctx); + if(status != 0) { + return status; + } + + count = get_event_counts(&fx3_bootloader, &devinfo, device_out); + if(count == 1) { + return 0; + } else if(count > 1) { + log_error("Just saw %d FX3 bootloader connect events, thats pretty weird, bailing\n", + count); + return BLADERF_ERR_UNEXPECTED; + } + + count = get_event_counts(&bladerf_bootloader, &devinfo, device_out); + if(count == 1) { + return 0; + } else if(count > 1) { + log_error("Just saw %d bladeRF bootloader connect events, thats pretty weird, bailing\n", + count); + return BLADERF_ERR_UNEXPECTED; + } + + return BLADERF_ERR_UNEXPECTED; +} + +static int reach_bootloader(bool reset, struct bladerf *dev, libusb_context *ctx, libusb_device **device_out) { + int status; + if(reset) { + status = bladerf_device_reset(dev); + if(status != 0) { + log_error("Error resetting device: %s\n", bladerf_strerror(status)); + return status; + } + + status = look_for_bootloader_connect(ctx, device_out); + if(status == 0) { + return status; + } + } + + status = bladerf_jump_to_bootloader(dev); + if(status != 0) { + log_info("Older bladeRF's don't support JUMP_TO_BOOTLOADER, " + "so ignore LIBUSB timeout errors until you update the FX3 firmware\n"); + } + + status = look_for_bootloader_connect(ctx, device_out); + if(status == 0) { + return status; + } + + log_info("Falling back to manually erasing first page of FX3 firmware\n"); + + status = bladerf_erase_flash(dev, 0, 1); + if(status != 0) { + log_error("Failed to erase first page. Flashing will likely " + "require manual force to FX3 bootloader. See " + "http://nuand.com/forums/viewtopic.php?f=6&t=3072\n"); + return BLADERF_ERR_UNEXPECTED; + } + + status = bladerf_device_reset(dev); + if(status != 0) { + log_error("Failed to reset device after erasing first page." + "A manual reset of the bladeRF should place it in the FX3 " + "bootloader. After the manual reset, re-run bladeRF-flash."); + return BLADERF_ERR_UNEXPECTED; + } + + status = look_for_bootloader_connect(ctx, device_out); + if(status != 0) { + log_error("Failed to reach bootloader. Flashing will likely " + "require manual force to FX3 bootloader. See " + "http://nuand.com/forums/viewtopic.php?f=6&t=3072\n"); + return BLADERF_ERR_NODEV; + } + + return 0; +} + +static int get_to_bootloader(bool reset, const char *device_identifier, + libusb_context *context, libusb_device_handle **device_out) +{ + struct bladerf *dev; + int status; + libusb_device *device = NULL; + struct bladerf_devinfo devinfo; + + log_verbose("First try to open bladerf with devid provided\n"); + + status = bladerf_open(&dev, device_identifier); + if(status == 0) { + /* Reset bladeRF count */ + log_verbose("bladeRF found, trying to reach the bootloader\n"); + status = reach_bootloader(reset, dev, context, &device); + if(status != 0) { + return status; + } + + status = libusb_open(device, device_out); + if(status != 0) { + log_error("Error opening bootloader: %s\n", + libusb_error_name(status)); + } + return status; + } else { + log_verbose("No bladeRF found, search for bootloader\n"); + status = str2devinfo(device_identifier, &devinfo); + if(status != 0) { + log_error("Failed to parse dev string %s, %s\n", + device_identifier, bladerf_strerror(status)); + return status; + } + + if(devinfo.backend != BLADERF_BACKEND_LIBUSB && devinfo.backend != BLADERF_BACKEND_ANY) { + status = BLADERF_ERR_UNSUPPORTED; + log_error("Only libusb supported, %s\n", + bladerf_strerror(status)); + return status; + } + + return find_fx3_via_info(context, &devinfo, device_out); + } +} + +static int get_bladerf(libusb_context *ctx, struct bladerf_devinfo *devinfo) +{ + libusb_device *device; + int count, status; + + status = poll_for_events(ctx); + if(status != 0) { + return status; + } + + count = get_event_counts(&bladerf, devinfo, &device); + if(count > 1) { + log_error("Just saw %d bladeRF connect events, thats pretty weird, bailing\n", + count); + return BLADERF_ERR_UNEXPECTED; + } else if (count == 0) { + return BLADERF_ERR_NODEV; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + /* Arguments: + * - Firmware image + * - Device string (optional) + * - Load RAM only (option) + * - Issue RESET before JUMP_TO_BOOTLOADER (option) + */ + int status; + struct rc_config rc; + struct bladerf *dev; + struct bladerf_devinfo devinfo; + libusb_context *context; + libusb_device_handle *device; + + /* If no actions are specified, just show the usage text and exit */ + if (argc == 1) { + usage(argv[0]); + return 0; + } + + init_rc_config(&rc); + + if (get_rc_config(argc, argv, &rc)) { + return 1; + } + + log_set_verbosity(rc.verbosity); + + if (rc.show_help) { + usage(argv[0]); + return 0; + } else if (rc.show_version) { + printf(BLADERF_FLASH_VERSION "\n"); + return 0; + } else if (rc.show_lib_version) { + printf("%s\n", bladerf_version(NULL, NULL, NULL)); + return 0; + } + + if (rc.fw_file == NULL) { + fprintf(stderr, "Must provide FX3 firmware to flash\n"); + return -1; + } + + /* Get initial device or scan */ + /* If normal bladeRF, perform protocol to get to FX3 bootloader */ + /* Perform RAM bootloader */ + /* Optionally flash new image to SPI flash */ + status = libusb_init(&context); + if (status != 0) { + log_error( "Could not initialize libusb: %s\n", libusb_error_name(status) ); + return status; + } + + status = register_hotplug_notifications(context); + if (status != 0) { + return status; + } + + log_verbose("Hotplug notifications installed\n"); + + device = NULL; + status = get_to_bootloader(rc.reset, rc.device, context, &device); + if (status != 0) { + log_error("Failed to find bladeRF bootloader after jumping, %d\n", status); + return status; + } + + log_info("Attempting load with file %s\n", rc.fw_file); + status = ezusb_load_ram(device, rc.fw_file, FX_TYPE_FX3, IMG_TYPE_IMG, 0); + libusb_close(device); + + if (status != 0) { + log_error("Failed to load FX3 RAM %d\n", status); + return status; + } + + if (rc.load_ram_only) { + log_info("All done\n"); + return 0; + } + + status = get_bladerf(context, &devinfo); + if (status != 0) { + log_error("Failed to find bladeRF after loading RAM, %d\n", status); + return status; + } + + status = bladerf_open_with_devinfo(&dev, &devinfo); + if (status != 0) { + log_error("Error opening device again, %s\n", bladerf_strerror(status)); + return status; + } + + status = bladerf_flash_firmware(dev, rc.fw_file); + if (status != 0) { + log_error("Error flashing firmware, %s\n", bladerf_strerror(status)); + return status; + } + + status = bladerf_device_reset(dev); + if (status != 0) { + log_error("Error resetting bladeRF, %s\n", bladerf_strerror(status)); + return status; + } + + status = get_bladerf(context, &devinfo); + if (status == 0) { + log_info("Successfully flashed bladeRF\n"); + } else { + log_error("Failed to find bladeRF after flashing FX3 firmware, %d\n", status); + } + + return 0; +} diff -Nru bladerf-0.3.0+git20130911/host/utilities/bladeRF-flash/src/version.h.in bladerf-0.3.0+git20130916/host/utilities/bladeRF-flash/src/version.h.in --- bladerf-0.3.0+git20130911/host/utilities/bladeRF-flash/src/version.h.in 1970-01-01 00:00:00.000000000 +0000 +++ bladerf-0.3.0+git20130916/host/utilities/bladeRF-flash/src/version.h.in 2013-09-17 07:44:19.000000000 +0000 @@ -0,0 +1,10 @@ +#ifndef BLADERF_FLASH_VERSION_H__ +#define BLADERF_FLASH_VERSION_H__ + +#define BLADERF_FLASH_VERSION "@VERSION@" + +#define BLADERF_FLASH_VERSION_MAJOR @VERSION_INFO_MAJOR@ +#define BLADERF_FLASH_VERSION_MINOR @VERSION_INFO_MINOR@ +#define BLADERF_FLASH_VERSION_PATCH @VERSION_INFO_PATCH@ + +#endif