/* * Copyright 2012 Jared Boone * Copyright 2013 Benjamin Vernoux * * This file is part of HackRF. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include "usb.h" #include "usb_standard_request.h" #include #include "usb_descriptor.h" #include "usb_device.h" #include "usb_endpoint.h" #include "usb_api_board_info.h" #include "usb_api_cpld.h" #include "usb_api_register.h" #include "usb_api_spiflash.h" #include "usb_api_transceiver.h" #include "sgpio_isr.h" #include "usb_bulk_buffer.h" static volatile transceiver_mode_t _transceiver_mode = TRANSCEIVER_MODE_OFF; static volatile hw_sync_mode_t _hw_sync_mode = HW_SYNC_MODE_OFF; void set_hw_sync_mode(const hw_sync_mode_t new_hw_sync_mode) { _hw_sync_mode = new_hw_sync_mode; } void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) { baseband_streaming_disable(&sgpio_config); usb_endpoint_disable(&usb_endpoint_bulk_in); usb_endpoint_disable(&usb_endpoint_bulk_out); _transceiver_mode = new_transceiver_mode; if( _transceiver_mode == TRANSCEIVER_MODE_RX ) { led_off(LED3); led_on(LED2); usb_endpoint_init(&usb_endpoint_bulk_in); rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_RX); vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_rx; } else if (_transceiver_mode == TRANSCEIVER_MODE_TX) { led_off(LED2); led_on(LED3); usb_endpoint_init(&usb_endpoint_bulk_out); rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_TX); vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_tx; } else { led_off(LED2); led_off(LED3); rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_OFF); vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_rx; hw_sync_stop(); } hw_sync_stop(); if( _transceiver_mode != TRANSCEIVER_MODE_OFF ) { si5351c_activate_best_clock_source(&clock_gen); if( _hw_sync_mode != HW_SYNC_MODE_OFF) { hw_sync_syn(); } else { baseband_streaming_enable(&sgpio_config); } } } transceiver_mode_t transceiver_mode(void) { return _transceiver_mode; } usb_request_status_t usb_vendor_request_set_hw_sync_mode( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ) { if( stage == USB_TRANSFER_STAGE_SETUP ) { set_hw_sync_mode(endpoint->setup.value); usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; } else { return USB_REQUEST_STATUS_OK; } } usb_request_status_t usb_vendor_request_set_transceiver_mode( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ) { if( stage == USB_TRANSFER_STAGE_SETUP ) { switch( endpoint->setup.value ) { case TRANSCEIVER_MODE_OFF: case TRANSCEIVER_MODE_RX: case TRANSCEIVER_MODE_TX: set_transceiver_mode(endpoint->setup.value); usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; case TRANSCEIVER_MODE_CPLD_UPDATE: usb_endpoint_init(&usb_endpoint_bulk_out); start_cpld_update = true; usb_transfer_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; default: return USB_REQUEST_STATUS_STALL; } } else { return USB_REQUEST_STATUS_OK; } } static const usb_request_handler_fn vendor_request_handler[] = { NULL, usb_vendor_request_set_transceiver_mode, usb_vendor_request_write_max2837, usb_vendor_request_read_max2837, usb_vendor_request_write_si5351c, usb_vendor_request_read_si5351c, usb_vendor_request_set_sample_rate_frac, usb_vendor_request_set_baseband_filter_bandwidth, usb_vendor_request_write_rffc5071, usb_vendor_request_read_rffc5071, usb_vendor_request_erase_spiflash, usb_vendor_request_write_spiflash, usb_vendor_request_read_spiflash, NULL, // used to be write_cpld usb_vendor_request_read_board_id, usb_vendor_request_read_version_string, usb_vendor_request_set_freq, usb_vendor_request_set_amp_enable, usb_vendor_request_read_partid_serialno, usb_vendor_request_set_lna_gain, usb_vendor_request_set_vga_gain, usb_vendor_request_set_txvga_gain, NULL, // was set_if_freq #ifdef HACKRF_ONE usb_vendor_request_set_antenna_enable, #else NULL, #endif usb_vendor_request_set_freq_explicit, usb_vendor_request_read_wcid, // USB_WCID_VENDOR_REQ usb_vendor_request_set_hw_sync_mode, }; static const uint32_t vendor_request_handler_count = sizeof(vendor_request_handler) / sizeof(vendor_request_handler[0]); usb_request_status_t usb_vendor_request( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ) { usb_request_status_t status = USB_REQUEST_STATUS_STALL; if( endpoint->setup.request < vendor_request_handler_count ) { usb_request_handler_fn handler = vendor_request_handler[endpoint->setup.request]; if( handler ) { status = handler(endpoint, stage); } } return status; } const usb_request_handlers_t usb_request_handlers = { .standard = usb_standard_request, .class = 0, .vendor = usb_vendor_request, .reserved = 0, }; void usb_configuration_changed( usb_device_t* const device ) { /* Reset transceiver to idle state until other commands are received */ set_transceiver_mode(TRANSCEIVER_MODE_OFF); if( device->configuration->number == 1 ) { // transceiver configuration cpu_clock_pll1_max_speed(); led_on(LED1); } else { /* Configuration number equal 0 means usb bus reset. */ cpu_clock_pll1_low_speed(); led_off(LED1); } } void usb_set_descriptor_by_serial_number(void) { iap_cmd_res_t iap_cmd_res; /* Read IAP Serial Number Identification */ iap_cmd_res.cmd_param.command_code = IAP_CMD_READ_SERIAL_NO; iap_cmd_call(&iap_cmd_res); if (iap_cmd_res.status_res.status_ret == CMD_SUCCESS) { usb_descriptor_string_serial_number[0] = USB_DESCRIPTOR_STRING_SERIAL_BUF_LEN; usb_descriptor_string_serial_number[1] = USB_DESCRIPTOR_TYPE_STRING; /* 32 characters of serial number, convert to UTF-16LE */ for (size_t i=0; i> 3] >> (28 - (i & 7) * 4)) & 0xf; const char c = (nibble > 9) ? ('a' + nibble - 10) : ('0' + nibble); usb_descriptor_string_serial_number[2 + i * 2] = c; usb_descriptor_string_serial_number[3 + i * 2] = 0x00; } } else { usb_descriptor_string_serial_number[0] = 2; usb_descriptor_string_serial_number[1] = USB_DESCRIPTOR_TYPE_STRING; } } int main(void) { uint8_t usb_dummy_buffer[32768]; for(int i = 0; i < 0x4000; i += 2) { usb_dummy_buffer[i] = 0xff; usb_dummy_buffer[i + 1] = 0x0; } for(int i = 0x4000; i < 0x8000; i += 2) { usb_dummy_buffer[i] = 0xff; usb_dummy_buffer[i + 1] = 0x0; } pin_setup(); enable_1v8_power(); #ifdef HACKRF_ONE enable_rf_power(); #endif cpu_clock_init(); usb_set_descriptor_by_serial_number(); usb_set_configuration_changed_cb(usb_configuration_changed); usb_peripheral_reset(); usb_device_init(0, &usb_device); usb_queue_init(&usb_endpoint_control_out_queue); usb_queue_init(&usb_endpoint_control_in_queue); usb_queue_init(&usb_endpoint_bulk_out_queue); usb_queue_init(&usb_endpoint_bulk_in_queue); usb_endpoint_init(&usb_endpoint_control_out); usb_endpoint_init(&usb_endpoint_control_in); nvic_set_priority(NVIC_USB0_IRQ, 255); usb_run(&usb_device); rf_path_init(&rf_path); unsigned int phase = 0; while(true) { // Check whether we need to initiate a CPLD update if (start_cpld_update) cpld_update(); if( _hw_sync_mode != HW_SYNC_MODE_OFF) { while(!hw_sync_ready()) { } hw_sync_ack(); led_on(LED3); baseband_streaming_enable(&sgpio_config); } // Set up IN transfer of buffer 0. if ( usb_bulk_buffer_offset >= 16384 && phase == 1 && transceiver_mode() != TRANSCEIVER_MODE_OFF) { usb_transfer_schedule_block( (transceiver_mode() == TRANSCEIVER_MODE_RX) ? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out, &usb_bulk_buffer[0x0000], 0x4000, NULL, NULL ); phase = 0; } // Set up IN transfer of buffer 1. if ( usb_bulk_buffer_offset < 16384 && phase == 0 && transceiver_mode() != TRANSCEIVER_MODE_OFF) { usb_transfer_schedule_block( (transceiver_mode() == TRANSCEIVER_MODE_RX) ? &usb_endpoint_bulk_in : &usb_endpoint_bulk_out, &usb_bulk_buffer[0x4000], 0x4000, NULL, NULL ); phase = 1; } } return 0; }