diff options
-rw-r--r-- | usrp2/firmware/apps/app_common_v2.c | 59 | ||||
-rw-r--r-- | usrp2/firmware/apps/app_common_v2.h | 4 | ||||
-rw-r--r-- | usrp2/firmware/apps/factory_test.c | 25 | ||||
-rw-r--r-- | usrp2/firmware/apps/mimo_tx_slave.c | 10 | ||||
-rw-r--r-- | usrp2/firmware/apps/serdes_txrx.c | 10 | ||||
-rw-r--r-- | usrp2/firmware/apps/txrx.c | 61 | ||||
-rw-r--r-- | usrp2/host/include/usrp2/usrp2.h | 59 | ||||
-rw-r--r-- | usrp2/host/lib/control.h | 26 | ||||
-rw-r--r-- | usrp2/host/lib/usrp2.cc | 52 | ||||
-rw-r--r-- | usrp2/host/lib/usrp2_impl.cc | 296 | ||||
-rw-r--r-- | usrp2/host/lib/usrp2_impl.h | 16 |
11 files changed, 419 insertions, 199 deletions
diff --git a/usrp2/firmware/apps/app_common_v2.c b/usrp2/firmware/apps/app_common_v2.c index 67cccd53b..2d131bda7 100644 --- a/usrp2/firmware/apps/app_common_v2.c +++ b/usrp2/firmware/apps/app_common_v2.c @@ -152,7 +152,7 @@ config_tx_v2_cmd(const op_config_tx_v2_t *p, memset(&tune_result, 0, sizeof(tune_result)); bool ok = true; - + if (p->valid & CFGV_GAIN){ ok &= db_set_gain(tx_dboard, p->gain); } @@ -161,7 +161,7 @@ config_tx_v2_cmd(const op_config_tx_v2_t *p, bool was_streaming = is_streaming(); if (was_streaming) stop_rx_cmd(); - + u2_fxpt_freq_t f = u2_fxpt_freq_from_hilo(p->freq_hi, p->freq_lo); bool tune_ok = db_tune(tx_dboard, f, &tune_result); ok &= tune_ok; @@ -185,7 +185,7 @@ config_tx_v2_cmd(const op_config_tx_v2_t *p, hb1 = 1; interp = interp >> 1; } - + if (interp < MIN_CIC_INTERP || interp > MAX_CIC_INTERP) ok = false; else { @@ -215,7 +215,7 @@ config_tx_v2_cmd(const op_config_tx_v2_t *p, } static size_t -config_rx_v2_cmd(const op_config_rx_v2_t *p, +config_rx_v2_cmd(const op_config_rx_v2_t *p, void *reply_payload, size_t reply_payload_space) { op_config_rx_reply_v2_t *r = (op_config_rx_reply_v2_t *) reply_payload; @@ -226,7 +226,7 @@ config_rx_v2_cmd(const op_config_rx_v2_t *p, memset(&tune_result, 0, sizeof(tune_result)); bool ok = true; - + if (p->valid & CFGV_GAIN){ ok &= db_set_gain(rx_dboard, p->gain); } @@ -235,7 +235,7 @@ config_rx_v2_cmd(const op_config_rx_v2_t *p, bool was_streaming = is_streaming(); if (was_streaming) stop_rx_cmd(); - + u2_fxpt_freq_t f = u2_fxpt_freq_from_hilo(p->freq_hi, p->freq_lo); bool tune_ok = db_tune(rx_dboard, f, &tune_result); ok &= tune_ok; @@ -249,17 +249,17 @@ config_rx_v2_cmd(const op_config_rx_v2_t *p, int decim = p->decim; int hb1 = 0; int hb2 = 0; - + if(!(decim & 1)) { hb2 = 1; decim = decim >> 1; } - + if(!(decim & 1)) { hb1 = 1; decim = decim >> 1; } - + if (decim < MIN_CIC_DECIM || decim > MAX_CIC_DECIM) ok = false; else { @@ -294,7 +294,7 @@ read_time_cmd(const op_generic_t *p, void *reply_payload, size_t reply_payload_space) { op_read_time_reply_t *r = (op_read_time_reply_t *) reply_payload; - if (reply_payload_space < sizeof(*r)) + if (reply_payload_space < sizeof(*r)) return 0; // no room r->opcode = OP_READ_TIME_REPLY; @@ -323,7 +323,7 @@ dboard_info_cmd(const op_generic_t *p, void *reply_payload, size_t reply_payload_space) { op_dboard_info_reply_t *r = (op_dboard_info_reply_t *) reply_payload; - if (reply_payload_space < sizeof(*r)) + if (reply_payload_space < sizeof(*r)) return 0; // no room r->opcode = OP_DBOARD_INFO_REPLY; @@ -411,14 +411,14 @@ generic_reply(const op_generic_t *p, bool ok) { op_generic_t *r = (op_generic_t *) reply_payload; - if (reply_payload_space < sizeof(*r)) + if (reply_payload_space < sizeof(*r)) return 0; // no room - + r->opcode = p->opcode | OP_REPLY_BIT; r->len = sizeof(*r); r->rid = p->rid; r->ok = ok; - + return r->len; } @@ -426,14 +426,14 @@ static size_t add_eop(void *reply_payload, size_t reply_payload_space) { op_generic_t *r = (op_generic_t *) reply_payload; - if (reply_payload_space < sizeof(*r)) + if (reply_payload_space < sizeof(*r)) return 0; // no room - + r->opcode = OP_EOP; r->len = sizeof(*r); r->rid = 0; r->ok = 0; - + return r->len; } @@ -443,15 +443,15 @@ handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len) unsigned char reply[sizeof(u2_eth_packet_t) + 4 * sizeof(u2_subpkt_t)] _AL4; unsigned char *reply_payload = &reply[sizeof(u2_eth_packet_t)]; int reply_payload_space = sizeof(reply) - sizeof(u2_eth_packet_t); - + // initialize reply memset(reply, 0, sizeof(reply)); set_reply_hdr((u2_eth_packet_t *) reply, pkt); - + // point to beginning of payload (subpackets) unsigned char *payload = ((unsigned char *) pkt) + sizeof(u2_eth_packet_t); int payload_len = len - sizeof(u2_eth_packet_t); - + size_t subpktlen = 0; bool ok = false; @@ -468,7 +468,7 @@ handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len) case OP_ID: subpktlen = op_id_cmd(gp, reply_payload, reply_payload_space); break; - + case OP_CONFIG_TX_V2: subpktlen = config_tx_v2_cmd((op_config_tx_v2_t *) payload, reply_payload, reply_payload_space); break; @@ -478,15 +478,18 @@ handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len) break; case OP_START_RX_STREAMING: - start_rx_streaming_cmd(&pkt->ehdr.src, (op_start_rx_streaming_t *) payload); + if (pkt->fixed.timestamp == -1) // Start now (default) + start_rx_streaming_cmd(&pkt->ehdr.src, (op_start_rx_streaming_t *) payload); + else + start_rx_streaming_at_cmd(&pkt->ehdr.src, (op_start_rx_streaming_t *)payload, pkt->fixed.timestamp); ok = true; goto generic_reply; - + case OP_STOP_RX: stop_rx_cmd(); ok = true; goto generic_reply; - + case OP_BURN_MAC_ADDR: ok = ethernet_set_mac_addr(&((op_burn_mac_addr_t *)payload)->addr); goto generic_reply; @@ -532,8 +535,8 @@ handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len) case OP_GPIO_SET_DDR: ok = true; - hal_gpio_set_ddr(((op_gpio_t *)payload)->bank, - ((op_gpio_t *)payload)->value, + hal_gpio_set_ddr(((op_gpio_t *)payload)->bank, + ((op_gpio_t *)payload)->value, ((op_gpio_t *)payload)->mask); goto generic_reply; @@ -549,8 +552,8 @@ handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len) case OP_GPIO_WRITE: ok = true; - hal_gpio_write(((op_gpio_t *)payload)->bank, - ((op_gpio_t *)payload)->value, + hal_gpio_write(((op_gpio_t *)payload)->bank, + ((op_gpio_t *)payload)->value, ((op_gpio_t *)payload)->mask); goto generic_reply; diff --git a/usrp2/firmware/apps/app_common_v2.h b/usrp2/firmware/apps/app_common_v2.h index 5058661ad..ff1baec06 100644 --- a/usrp2/firmware/apps/app_common_v2.h +++ b/usrp2/firmware/apps/app_common_v2.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2007,2008 Free Software Foundation, Inc. + * Copyright 2007,2008,2009 Free Software Foundation, Inc. * * 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 @@ -55,8 +55,10 @@ print_tune_result(char *msg, bool tune_ok, void start_rx_streaming_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p); +void start_rx_streaming_at_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p, uint32_t time); void stop_rx_cmd(void); void restart_streaming(void); +void restart_streaming_at(uint32_t time); bool is_streaming(void); void handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len); diff --git a/usrp2/firmware/apps/factory_test.c b/usrp2/firmware/apps/factory_test.c index a4bc06d58..e7dde524a 100644 --- a/usrp2/firmware/apps/factory_test.c +++ b/usrp2/firmware/apps/factory_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2007,2008 Free Software Foundation, Inc. + * Copyright 2007,2008,2009 Free Software Foundation, Inc. * * 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 @@ -154,7 +154,7 @@ restart_streaming(void) dsp_rx_regs->rx_command = MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, streaming_items_per_frame, - 1, 1); + 1, 1); dsp_rx_regs->rx_time = 0; // enqueue second command } @@ -187,6 +187,11 @@ start_rx_streaming_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p) } +void start_rx_streaming_at_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p, uint32_t time) +{} +void restart_streaming_at(uint32_t time) +{} + void stop_rx_cmd(void) { @@ -224,7 +229,7 @@ setup_tx() * that we didn't handle the packet. A bit of a kludge * but it should work. */ -bool +bool fw_sets_seqno_inspector(dbsm_t *sm, int buf_this) // returns false { uint32_t *p = buffer_ram(buf_this); @@ -259,22 +264,22 @@ int test_ram() { int i,j,k; output_regs->ram_page = 1<<10; - + extram[0] = 0xDEADBEEF; extram[1] = 0xF00D1234; extram[7] = 0x76543210; - + output_regs->ram_page = 2<<10; extram[7] = 0x55555555; extram[1] = 0xaaaaaaaa; extram[0] = 0xeeeeeeee; - + output_regs->ram_page = 1<<10; - + i = extram[0]; k = extram[1]; j = extram[7]; - + if((i != 0xDEADBEEF)||(j!=0x76543210)||(k!=0xF00D1234)) { puts("RAM FAIL1!\n"); puthex32_nl(i); @@ -282,7 +287,7 @@ int test_ram() puthex32_nl(k); return 0; } - + output_regs->ram_page = 2<<10; j = extram[7]; @@ -306,7 +311,7 @@ int test_sd() puts("FAILED INIT of Card\n"); return 0; } - + unsigned char buf[512]; i = sd_read_block(2048,buf); if(i == 0) { diff --git a/usrp2/firmware/apps/mimo_tx_slave.c b/usrp2/firmware/apps/mimo_tx_slave.c index e7da984c5..4c284b7c9 100644 --- a/usrp2/firmware/apps/mimo_tx_slave.c +++ b/usrp2/firmware/apps/mimo_tx_slave.c @@ -160,7 +160,7 @@ restart_streaming(void) dsp_rx_regs->rx_command = MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, streaming_items_per_frame, - 1, 1); + 1, 1); dsp_rx_regs->rx_time = 0; // enqueue second command } @@ -192,6 +192,10 @@ start_rx_streaming_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p) restart_streaming(); } +void start_rx_streaming_at_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p, uint32_t time) +{} +void restart_streaming_at(uint32_t time) +{} void stop_rx_cmd(void) @@ -230,7 +234,7 @@ setup_tx() * that we didn't handle the packet. A bit of a kludge * but it should work. */ -bool +bool fw_sets_seqno_inspector(dbsm_t *sm, int buf_this) // returns false { uint32_t *p = buffer_ram(buf_this); @@ -310,7 +314,7 @@ main(void) //output_regs->flush_icache = 1; - + // initialize double buffering state machine for DSP RX -> Ethernet if (FW_SETS_SEQNO){ diff --git a/usrp2/firmware/apps/serdes_txrx.c b/usrp2/firmware/apps/serdes_txrx.c index 7816f7a65..aa4a3f33c 100644 --- a/usrp2/firmware/apps/serdes_txrx.c +++ b/usrp2/firmware/apps/serdes_txrx.c @@ -152,7 +152,7 @@ restart_streaming(void) dsp_rx_regs->rx_command = MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, streaming_items_per_frame, - 1, 1); + 1, 1); dsp_rx_regs->rx_time = 0; // enqueue second command } @@ -184,6 +184,10 @@ start_rx_streaming_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p) restart_streaming(); } +void start_rx_streaming_at_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p, uint32_t time) +{} +void restart_streaming_at(uint32_t time) +{} void stop_rx_cmd(void) @@ -222,7 +226,7 @@ setup_tx() * that we didn't handle the packet. A bit of a kludge * but it should work. */ -bool +bool fw_sets_seqno_inspector(dbsm_t *sm, int buf_this) // returns false { uint32_t *p = buffer_ram(buf_this); @@ -302,7 +306,7 @@ main(void) //output_regs->flush_icache = 1; - + // initialize double buffering state machine for DSP RX -> Ethernet if (FW_SETS_SEQNO){ diff --git a/usrp2/firmware/apps/txrx.c b/usrp2/firmware/apps/txrx.c index b2487ed89..975f314bd 100644 --- a/usrp2/firmware/apps/txrx.c +++ b/usrp2/firmware/apps/txrx.c @@ -1,5 +1,5 @@ /* - * Copyright 2007,2008 Free Software Foundation, Inc. + * Copyright 2007,2008,2009 Free Software Foundation, Inc. * * 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 @@ -152,7 +152,35 @@ restart_streaming(void) dsp_rx_regs->rx_command = MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, streaming_items_per_frame, - 1, 1); + 1, 1); + + dsp_rx_regs->rx_time = 0; // enqueue second command +} + +void +restart_streaming_at(uint32_t time) +{ + // setup RX DSP regs + dsp_rx_regs->clear_state = 1; // reset + + streaming_p = true; + streaming_frame_count = FRAMES_PER_CMD; + + dsp_rx_regs->rx_command = + MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, + streaming_items_per_frame, + 0, 1); // set "chain" bit + + // kick off the state machine + dbsm_start(&dsp_rx_sm); + + dsp_rx_regs->rx_time = time; // enqueue first of two commands + + // make sure this one and the rest have the "now" and "chain" bits set. + dsp_rx_regs->rx_command = + MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, + streaming_items_per_frame, + 1, 1); dsp_rx_regs->rx_time = 0; // enqueue second command } @@ -184,6 +212,33 @@ start_rx_streaming_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p) restart_streaming(); } +void +start_rx_streaming_at_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p, uint32_t time) +{ + host_mac_addr = *host; // remember who we're sending to + + /* + * Construct ethernet header and word0 and preload into two buffers + */ + u2_eth_packet_t pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.ehdr.dst = *host; + pkt.ehdr.src = *ethernet_mac_addr(); + pkt.ehdr.ethertype = U2_ETHERTYPE; + u2p_set_word0(&pkt.fixed, 0, 0); + // DSP RX will fill in timestamp + + memcpy_wa(buffer_ram(DSP_RX_BUF_0), &pkt, sizeof(pkt)); + memcpy_wa(buffer_ram(DSP_RX_BUF_1), &pkt, sizeof(pkt)); + + + if (FW_SETS_SEQNO) + fw_seqno = 0; + + streaming_items_per_frame = p->items_per_frame; + restart_streaming_at(time); +} + void stop_rx_cmd(void) @@ -222,7 +277,7 @@ setup_tx() * that we didn't handle the packet. A bit of a kludge * but it should work. */ -bool +bool fw_sets_seqno_inspector(dbsm_t *sm, int buf_this) // returns false { uint32_t *p = buffer_ram(buf_this); diff --git a/usrp2/host/include/usrp2/usrp2.h b/usrp2/host/include/usrp2/usrp2.h index 7a612f945..2d9e2a4b0 100644 --- a/usrp2/host/include/usrp2/usrp2.h +++ b/usrp2/host/include/usrp2/usrp2.h @@ -60,7 +60,7 @@ namespace usrp2 { * * \returns a vector of properties, 1 entry for each matching USRP2 found. */ - props_vector_t find(const std::string &ifc, const std::string &mac_addr=""); + props_vector_t find(const std::string &ifc, const std::string &mac_addr=""); class tune_result; @@ -79,10 +79,10 @@ namespace usrp2 { /*! * Shared pointer to this class - */ + */ typedef boost::shared_ptr<usrp2> sptr; - - /*! + + /*! * Static function to return an instance of usrp2 as a shared pointer * * \param ifc Network interface name, e.g., "eth0" @@ -96,7 +96,7 @@ namespace usrp2 { /*! * Class destructor */ - ~usrp2(); + ~usrp2(); /*! * Returns the MAC address associated with this USRP @@ -120,10 +120,10 @@ namespace usrp2 { */ bool set_rx_gain(double gain); - //! return minimum Rx gain + //! return minimum Rx gain double rx_gain_min(); - //! return maximum Rx gain + //! return maximum Rx gain double rx_gain_max(); //! return Rx gain db_per_step @@ -160,7 +160,7 @@ namespace usrp2 { /*! * Set received sample format - * + * * domain: complex or real * type: floating, fixed point, or raw * depth: bits per sample @@ -172,12 +172,33 @@ namespace usrp2 { /*! * Start streaming receive mode. USRP2 will send a continuous stream of * DSP pipeline samples to host. Call rx_samples(...) to access. - * + * * \param channel Stream channel number (0-30) * \param items_per_frame Number of 32-bit items per frame. */ bool start_rx_streaming(unsigned int channel=0, unsigned int items_per_frame=0); - + + /*! + * Start streaming receive mode at specified timestamp. USRP2 will send a + * continuous stream of DSP pipeline samples to host. Call rx_samples(...) + * to access. + * + * \param channel Stream channel number (0-30) + * \param items_per_frame Number of 32-bit items per frame. + * \param time Timestamp to start streaming at + */ + bool start_rx_streaming_at(unsigned int channel=0, unsigned int items_per_frame=0, unsigned int time=0); + + /*! + * Sync to PPS and start streaming receive mode at specified timestamp. + * Just like calling sync_to_pps() and start_rx_streaming_at(). + * + * \param channel Stream channel number (0-30) + * \param items_per_frame Number of 32-bit items per frame. + * \param time Timestamp to start streaming at + */ + bool sync_and_start_rx_streaming_at(unsigned int channel=0, unsigned int items_per_frame=0, uint32_t time=0); + /*! * Stop streaming receive mode. */ @@ -193,7 +214,7 @@ namespace usrp2 { * Returns number of times receive overruns have occurred */ unsigned int rx_overruns(); - + /*! * Returns total number of missing frames from overruns. */ @@ -210,10 +231,10 @@ namespace usrp2 { */ bool set_tx_gain(double gain); - //! return minimum Tx gain + //! return minimum Tx gain double tx_gain_min(); - //! return maximum Tx gain + //! return maximum Tx gain double tx_gain_max(); //! return Tx gain db_per_step @@ -255,7 +276,7 @@ namespace usrp2 { /*! * Set transmit sample format - * + * * domain: complex or real * type: floating, fixed point, or raw * depth: bits per sample @@ -272,7 +293,7 @@ namespace usrp2 { * \param nsamples is the number of samples to transmit * \param metadata provides the timestamp and flags * - * The complex<float> samples are converted to the appropriate + * The complex<float> samples are converted to the appropriate * "on the wire" representation, depending on the current USRP2 * configuration. Typically, this is big-endian 16-bit I & Q. */ @@ -400,12 +421,12 @@ namespace usrp2 { * * \param addr 32-bit aligned address. Only the lower 16-bits are significant. * \param words Number of 32-bit words - * + * * \returns Vector of 32-bit read values * * WARNING: Attempts to read memory from addresses that do not correspond to RAM or * memory-mapped peripherals may cause the USRP2 to hang, requiring a power cycle. - * + * */ std::vector<uint32_t> peek32(uint32_t addr, uint32_t words); @@ -419,7 +440,7 @@ namespace usrp2 { * * WARNING: Attempts to read memory from addresses that do not correspond to RAM or * memory-mapped peripherals may cause the USRP2 to hang, requiring a power cycle. - * + * */ bool poke32(uint32_t addr, const std::vector<uint32_t> &data); @@ -587,7 +608,7 @@ namespace usrp2 { // Only class members can instantiate this class usrp2(const std::string &ifc, props *p, size_t rx_bufsize); - + // All private state is held in opaque pointer std::auto_ptr<impl> d_impl; }; diff --git a/usrp2/host/lib/control.h b/usrp2/host/lib/control.h index 8769e4522..46ce791ea 100644 --- a/usrp2/host/lib/control.h +++ b/usrp2/host/lib/control.h @@ -33,27 +33,35 @@ namespace usrp2 { /*! * OP_CONFIG_RX_V2 command packet */ - struct op_config_rx_v2_cmd + struct op_config_rx_v2_cmd { u2_eth_packet_t h; op_config_rx_v2_t op; op_generic_t eop; }; - struct op_start_rx_streaming_cmd + struct op_start_rx_streaming_cmd { u2_eth_packet_t h; op_start_rx_streaming_t op; op_generic_t eop; }; - + + struct op_sync_and_start_rx_streaming_cmd + { + u2_eth_packet_t h; + op_generic_t sync_op; + op_start_rx_streaming_t rx_op; + op_generic_t eop; + }; + struct op_stop_rx_cmd { u2_eth_packet_t h; op_generic_t op; op_generic_t eop; }; - struct op_config_tx_v2_cmd + struct op_config_tx_v2_cmd { u2_eth_packet_t h; op_config_tx_v2_t op; @@ -67,7 +75,7 @@ namespace usrp2 { op_generic_t eop; }; - struct op_burn_mac_addr_cmd + struct op_burn_mac_addr_cmd { u2_eth_packet_t h; op_burn_mac_addr_t op; @@ -113,20 +121,20 @@ namespace usrp2 { /*! * Control mechanism to allow API calls to block waiting for reply packets - */ + */ class pending_reply { private: unsigned int d_rid; void *d_buffer; size_t d_len; - + // d_mutex is used with d_cond and also protects d_complete omni_mutex d_mutex; omni_condition d_cond; bool d_complete; - public: + public: /*! * Construct a pending reply from the reply ID, response packet * buffer, and buffer length. @@ -165,7 +173,7 @@ namespace usrp2 { */ size_t len() const { return d_len; } }; - + } // namespace usrp2 #endif /* INCLUDED_CONTROL_H */ diff --git a/usrp2/host/lib/usrp2.cc b/usrp2/host/lib/usrp2.cc index a2a9ecc11..801a436a3 100644 --- a/usrp2/host/lib/usrp2.cc +++ b/usrp2/host/lib/usrp2.cc @@ -62,7 +62,7 @@ namespace usrp2 { else { if (key == p->key) // found it return usrp2::sptr(p->value); - else + else ++p; // keep looking } } @@ -90,15 +90,15 @@ namespace usrp2 { p.addr[3] = 0x85; p.addr[4] = 0x30; p.addr[5] = 0x00; - + int len = s.size(); switch (len) { - + case 5: if (sscanf(s.c_str(), "%hhx:%hhx", &p.addr[4], &p.addr[5]) != 2) return false; break; - + case 17: if (sscanf(s.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &p.addr[0], &p.addr[1], &p.addr[2], @@ -109,7 +109,7 @@ namespace usrp2 { default: return false; } - + char buf[128]; snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", @@ -148,13 +148,13 @@ namespace usrp2 { { // NOP } - + // Public class destructor. d_impl will auto-delete. usrp2::~usrp2() { // NOP } - + std::string usrp2::mac_addr() { @@ -169,12 +169,12 @@ namespace usrp2 { // Receive - bool + bool usrp2::set_rx_gain(double gain) { return d_impl->set_rx_gain(gain); } - + double usrp2::rx_gain_min() { @@ -204,7 +204,7 @@ namespace usrp2 { { return d_impl->set_rx_center_freq(frequency, result); } - + double usrp2::rx_freq_min() { @@ -222,7 +222,7 @@ namespace usrp2 { { return d_impl->set_rx_decim(decimation_factor); } - + int usrp2::rx_decim() { @@ -234,13 +234,25 @@ namespace usrp2 { { return d_impl->set_rx_scale_iq(scale_i, scale_q); } - + bool usrp2::start_rx_streaming(unsigned int channel, unsigned int items_per_frame) { return d_impl->start_rx_streaming(channel, items_per_frame); } - + + bool + usrp2::start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time) + { + return d_impl->start_rx_streaming_at(channel, items_per_frame,time); + } + + bool + usrp2::sync_and_start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time) + { + return d_impl->sync_and_start_rx_streaming_at(channel, items_per_frame, time); + } + bool usrp2::rx_samples(unsigned int channel, rx_sample_handler *handler) { @@ -258,7 +270,7 @@ namespace usrp2 { { return d_impl->rx_overruns(); } - + unsigned int usrp2::rx_missing() { @@ -267,12 +279,12 @@ namespace usrp2 { // Transmit - bool + bool usrp2::set_tx_gain(double gain) { return d_impl->set_tx_gain(gain); } - + double usrp2::tx_gain_min() { @@ -302,7 +314,7 @@ namespace usrp2 { { return d_impl->set_tx_center_freq(frequency, result); } - + double usrp2::tx_freq_min() { @@ -321,7 +333,7 @@ namespace usrp2 { { return d_impl->set_tx_interp(interpolation_factor); } - + int usrp2::tx_interp() { @@ -339,7 +351,7 @@ namespace usrp2 { { return d_impl->set_tx_scale_iq(scale_i, scale_q); } - + bool usrp2::tx_32fc(unsigned int channel, const std::complex<float> *samples, @@ -404,7 +416,7 @@ namespace usrp2 { { return d_impl->rx_daughterboard_id(dbid); } - + // low level methods diff --git a/usrp2/host/lib/usrp2_impl.cc b/usrp2/host/lib/usrp2_impl.cc index 3d0304324..a74707634 100644 --- a/usrp2/host/lib/usrp2_impl.cc +++ b/usrp2/host/lib/usrp2_impl.cc @@ -106,7 +106,7 @@ namespace usrp2 { //assert((((uintptr_t) p) % 4) == 0); // must be 4-byte aligned u2_fixed_hdr_t *fh = static_cast<u2_fixed_hdr_t *>(p); - + // FIXME unaligned loads! md->word0 = u2p_word0(fh); md->timestamp = u2p_timestamp(fh); @@ -131,13 +131,13 @@ namespace usrp2 { usrp2::impl::impl(const std::string &ifc, props *p, size_t rx_bufsize) : d_eth_buf(new eth_buffer(rx_bufsize)), d_interface_name(ifc), d_pf(0), d_bg_thread(0), d_bg_running(false), d_rx_seqno(-1), d_tx_seqno(0), d_next_rid(0), - d_num_rx_frames(0), d_num_rx_missing(0), d_num_rx_overruns(0), d_num_rx_bytes(0), + d_num_rx_frames(0), d_num_rx_missing(0), d_num_rx_overruns(0), d_num_rx_bytes(0), d_num_enqueued(0), d_enqueued_mutex(), d_bg_pending_cond(&d_enqueued_mutex), d_channel_rings(NCHANS), d_tx_interp(0), d_rx_decim(0), d_dont_enqueue(true) { if (!d_eth_buf->open(ifc, htons(U2_ETHERTYPE))) throw std::runtime_error("Unable to register USRP2 protocol"); - + d_addr = p->addr; // Create a packet filter for U2_ETHERTYPE packets sourced from target USRP2 @@ -146,7 +146,7 @@ namespace usrp2 { d_pf = pktfilter::make_ethertype_inbound_target(U2_ETHERTYPE, (const unsigned char*)&(usrp_mac.addr)); if (!d_pf || !d_eth_buf->attach_pktfilter(d_pf)) throw std::runtime_error("Unable to attach packet filter."); - + if (USRP2_IMPL_DEBUG) std::cerr << "usrp2 constructor: using USRP2 at " << d_addr << std::endl; @@ -199,12 +199,12 @@ namespace usrp2 { if (!set_rx_decim(12)) std::cerr << "usrp2::ctor set_rx_decim failed\n"; - + // set workable defaults for scaling if (!set_rx_scale_iq(DEFAULT_RX_SCALE, DEFAULT_RX_SCALE)) std::cerr << "usrp2::ctor set_rx_scale_iq failed\n"; } - + usrp2::impl::~impl() { stop_bg(); @@ -212,17 +212,17 @@ namespace usrp2 { delete d_pf; d_eth_buf->close(); delete d_eth_buf; - + if (USRP2_IMPL_DEBUG) { std::cerr << std::endl - << "usrp2 destructor: received " << d_num_rx_frames + << "usrp2 destructor: received " << d_num_rx_frames << " frames, with " << d_num_rx_missing << " lost (" << (d_num_rx_frames == 0 ? 0 : (int)(100.0*d_num_rx_missing/d_num_rx_frames)) << "%), totaling " << d_num_rx_bytes << " bytes" << std::endl; } } - + bool usrp2::impl::parse_mac_addr(const std::string &s, u2_mac_addr_t *p) { @@ -232,14 +232,14 @@ namespace usrp2 { p->addr[3] = 0x85; p->addr[4] = 0x30; p->addr[5] = 0x00; - + int len = s.size(); - + switch (len){ - + case 5: return sscanf(s.c_str(), "%hhx:%hhx", &p->addr[4], &p->addr[5]) == 2; - + case 17: return sscanf(s.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &p->addr[0], &p->addr[1], &p->addr[2], @@ -248,36 +248,36 @@ namespace usrp2 { return false; } } - + void usrp2::impl::init_et_hdrs(u2_eth_packet_t *p, const std::string &dst) { p->ehdr.ethertype = htons(U2_ETHERTYPE); - parse_mac_addr(dst, &p->ehdr.dst); + parse_mac_addr(dst, &p->ehdr.dst); memcpy(&p->ehdr.src, d_eth_buf->mac(), 6); p->thdr.flags = 0; // FIXME transport header values? p->thdr.seqno = d_tx_seqno++; p->thdr.ack = 0; } - - void + + void usrp2::impl::init_etf_hdrs(u2_eth_packet_t *p, const std::string &dst, int word0_flags, int chan, uint32_t timestamp) { init_et_hdrs(p, dst); u2p_set_word0(&p->fixed, word0_flags, chan); u2p_set_timestamp(&p->fixed, timestamp); - + if (chan == CONTROL_CHAN) { // no sequence numbers, back it out p->thdr.seqno = 0; d_tx_seqno--; } } - + void usrp2::impl::init_config_rx_v2_cmd(op_config_rx_v2_cmd *cmd) { - memset(cmd, 0, sizeof(*cmd)); + memset(cmd, 0, sizeof(*cmd)); init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1); cmd->op.opcode = OP_CONFIG_RX_V2; cmd->op.len = sizeof(cmd->op); @@ -289,7 +289,7 @@ namespace usrp2 { void usrp2::impl::init_config_tx_v2_cmd(op_config_tx_v2_cmd *cmd) { - memset(cmd, 0, sizeof(*cmd)); + memset(cmd, 0, sizeof(*cmd)); init_etf_hdrs(&cmd->h, d_addr, 0, CONTROL_CHAN, -1); cmd->op.opcode = OP_CONFIG_TX_V2; cmd->op.len = sizeof(cmd->op); @@ -320,7 +320,7 @@ namespace usrp2 { usrp2::impl::transmit_cmd_and_wait(void *cmd, size_t len, pending_reply *p, double secs) { d_pending_replies[p->rid()] = p; - + if (!transmit_cmd(cmd, len)){ d_pending_replies[p->rid()] = 0; return false; @@ -340,11 +340,11 @@ namespace usrp2 { { d_bg_running = false; d_bg_pending_cond.signal(); - + void *dummy_status; - d_bg_thread->join(&dummy_status); + d_bg_thread->join(&dummy_status); } - + void usrp2::impl::bg_loop() { @@ -356,10 +356,10 @@ namespace usrp2 { // rings, and signal blocked API threads int res = d_eth_buf->rx_frames(this, 100); // FIXME magic timeout if (res == eth_buffer::EB_ERROR) - break; + break; // Wait for user API thread(s) to process all enqueued packets. - // The channel ring thread that decrements d_num_enqueued to zero + // The channel ring thread that decrements d_num_enqueued to zero // will signal this thread to continue. { omni_mutex_lock l(d_enqueued_mutex); @@ -369,7 +369,7 @@ namespace usrp2 { } d_bg_running = false; } - + // // passed to eth_buffer::rx_frames // @@ -401,11 +401,11 @@ namespace usrp2 { { // point to beginning of payload (subpackets) unsigned char *p = (unsigned char *)base + sizeof(u2_eth_packet_t); - + // FIXME (p % 4) == 2. Not good. Must watch for unaligned loads. // FIXME iterate over payload, handling more than a single subpacket. - + int opcode = p[0]; unsigned int oplen = p[1]; unsigned int rid = p[2]; @@ -417,8 +417,8 @@ namespace usrp2 { std::cerr << "usrp2: mismatched command reply length (expected: " << buflen << " got: " << oplen << "). " << "op = " << opcode_to_string(opcode) << std::endl; - } - + } + // Copy reply into caller's buffer memcpy(rp->buffer(), p, std::min(oplen, buflen)); rp->notify_completion(); @@ -430,26 +430,26 @@ namespace usrp2 { DEBUG_LOG("l"); return data_handler::RELEASE; } - + data_handler::result usrp2::impl::handle_data_packet(const void *base, size_t len) { u2_eth_samples_t *pkt = (u2_eth_samples_t *)base; d_num_rx_frames++; d_num_rx_bytes += len; - + /* --- FIXME start of fake transport layer handler --- */ if (d_rx_seqno != -1) { int expected_seqno = (d_rx_seqno + 1) & 0xFF; - int seqno = pkt->hdrs.thdr.seqno; - + int seqno = pkt->hdrs.thdr.seqno; + if (seqno != expected_seqno) { ::write(2, "S", 1); // missing sequence number int missing = seqno - expected_seqno; if (missing < 0) missing += 256; - + d_num_rx_overruns++; d_num_rx_missing += missing; } @@ -469,9 +469,9 @@ namespace usrp2 { DEBUG_LOG("!"); return data_handler::RELEASE; // discard packet, no channel handler } - + // Strip off ethernet header and transport header and enqueue the rest - + size_t offset = offsetof(u2_eth_samples_t, hdrs.fixed); if (d_channel_rings[chan]->enqueue(&pkt->hdrs.fixed, len-offset)) { inc_enqueued(); @@ -481,7 +481,7 @@ namespace usrp2 { else { DEBUG_LOG("!"); return data_handler::RELEASE; // discard, no room in channel ring - } + } return data_handler::RELEASE; } } @@ -491,7 +491,7 @@ namespace usrp2 { // Receive // ---------------------------------------------------------------- - bool + bool usrp2::impl::set_rx_gain(double gain) { op_config_rx_v2_cmd cmd; @@ -500,7 +500,7 @@ namespace usrp2 { init_config_rx_v2_cmd(&cmd); cmd.op.valid = htons(CFGV_GAIN); cmd.op.gain = htons(u2_double_to_fxpt_gain(gain)); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -508,7 +508,7 @@ namespace usrp2 { bool success = (ntohx(reply.ok) == 1); return success; } - + bool usrp2::impl::set_rx_lo_offset(double frequency) { @@ -527,7 +527,7 @@ namespace usrp2 { cmd.eop.opcode = OP_EOP; cmd.eop.len = sizeof(cmd.eop); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -547,7 +547,7 @@ namespace usrp2 { u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency); cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt)); cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt)); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -555,18 +555,18 @@ namespace usrp2 { bool success = (ntohx(reply.ok) == 1); if (result && success) { result->baseband_freq = - u2_fxpt_freq_to_double( - u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi), + u2_fxpt_freq_to_double( + u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi), ntohl(reply.baseband_freq_lo))); result->dxc_freq = - u2_fxpt_freq_to_double( - u2_fxpt_freq_from_hilo(ntohl(reply.ddc_freq_hi), + u2_fxpt_freq_to_double( + u2_fxpt_freq_from_hilo(ntohl(reply.ddc_freq_hi), ntohl(reply.ddc_freq_lo))); result->residual_freq = - u2_fxpt_freq_to_double( - u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi), + u2_fxpt_freq_to_double( + u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi), ntohl(reply.residual_freq_lo))); result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1); @@ -574,7 +574,7 @@ namespace usrp2 { return success; } - + bool usrp2::impl::set_rx_decim(int decimation_factor) { @@ -584,7 +584,7 @@ namespace usrp2 { init_config_rx_v2_cmd(&cmd); cmd.op.valid = htons(CFGV_INTERP_DECIM); cmd.op.decim = htonl(decimation_factor); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -594,7 +594,7 @@ namespace usrp2 { d_rx_decim = decimation_factor; return success; } - + bool usrp2::impl::set_rx_scale_iq(int scale_i, int scale_q) { @@ -604,7 +604,7 @@ namespace usrp2 { init_config_rx_v2_cmd(&cmd); cmd.op.valid = htons(CFGV_SCALE_IQ); cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff)); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -612,7 +612,7 @@ namespace usrp2 { bool success = (ntohx(reply.ok) == 1); return success; } - + bool usrp2::impl::start_rx_streaming(unsigned int channel, unsigned int items_per_frame) { @@ -635,10 +635,10 @@ namespace usrp2 { << " already streaming" << std::endl; return false; } - + if (items_per_frame == 0) items_per_frame = U2_MAX_SAMPLES; // minimize overhead - + op_start_rx_streaming_cmd cmd; op_generic_t reply; @@ -650,13 +650,13 @@ namespace usrp2 { cmd.op.items_per_frame = htonl(items_per_frame); cmd.eop.opcode = OP_EOP; cmd.eop.len = sizeof(cmd.eop); - + d_dont_enqueue = false; bool success = false; pending_reply p(cmd.op.rid, &reply, sizeof(reply)); success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT); success = success && (ntohx(reply.ok) == 1); - + if (success) d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames())); else @@ -666,7 +666,111 @@ namespace usrp2 { return success; } } - + + bool + usrp2::impl::start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time) + { + if (channel > MAX_CHAN) { + std::cerr << "usrp2: invalid channel number (" << channel + << ")" << std::endl; + return false; + } + + if (channel > 0) { // until firmware supports multiple streams + std::cerr << "usrp2: channel " << channel + << " not implemented" << std::endl; + return false; + } + + { + omni_mutex_lock l(d_channel_rings_mutex); + if (d_channel_rings[channel]) { + std::cerr << "usrp2: channel " << channel + << " already streaming" << std::endl; + return false; + } + + if (items_per_frame == 0) + items_per_frame = U2_MAX_SAMPLES; // minimize overhead + + op_start_rx_streaming_cmd cmd; + op_generic_t reply; + + memset(&cmd, 0, sizeof(cmd)); + init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, time); + cmd.op.opcode = OP_START_RX_STREAMING; + cmd.op.len = sizeof(cmd.op); + cmd.op.rid = d_next_rid++; + cmd.op.items_per_frame = htonl(items_per_frame); + cmd.eop.opcode = OP_EOP; + cmd.eop.len = sizeof(cmd.eop); + + bool success = false; + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); + success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT); + success = success && (ntohx(reply.ok) == 1); + + if (success) + d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames())); + + return success; + } + } + + bool + usrp2::impl::sync_and_start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time) + { + + if (channel > MAX_CHAN) { + std::cerr << "usrp2: invalid channel number (" << channel + << ")" << std::endl; + return false; + } + + if (channel > 0) { // until firmware supports multiple streams + std::cerr << "usrp2: channel " << channel + << " not implemented" << std::endl; + return false; + } + + { + omni_mutex_lock l(d_channel_rings_mutex); + if (d_channel_rings[channel]) { + std::cerr << "usrp2: channel " << channel + << " already streaming" << std::endl; + return false; + } + + if (items_per_frame == 0) + items_per_frame = U2_MAX_SAMPLES; // minimize overhead + + op_sync_and_start_rx_streaming_cmd cmd; + op_generic_t reply; + + memset(&cmd, 0, sizeof(cmd)); + init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, time); + cmd.sync_op.opcode = OP_SYNC_TO_PPS; + cmd.sync_op.len = sizeof(cmd.sync_op); + cmd.sync_op.rid = d_next_rid++; + cmd.rx_op.opcode = OP_START_RX_STREAMING; + cmd.rx_op.len = sizeof(cmd.rx_op); + cmd.rx_op.rid = d_next_rid++; + cmd.rx_op.items_per_frame = htonl(items_per_frame); + cmd.eop.opcode = OP_EOP; + cmd.eop.len = sizeof(cmd.eop); + + bool success = false; + pending_reply p(cmd.sync_op.rid, &reply, sizeof(reply)); + success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT); + success = success && (ntohx(reply.ok) == 1); + + if (success) + d_channel_rings[channel] = ring_sptr(new ring(d_eth_buf->max_frames())); + + return success; + } + } + bool usrp2::impl::stop_rx_streaming(unsigned int channel) { @@ -698,7 +802,7 @@ namespace usrp2 { cmd.op.rid = d_next_rid++; cmd.eop.opcode = OP_EOP; cmd.eop.len = sizeof(cmd.eop); - + bool success = false; pending_reply p(cmd.op.rid, &reply, sizeof(reply)); success = transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT); @@ -717,25 +821,25 @@ namespace usrp2 { << " )" << std::endl; return false; } - + if (channel > 0) { std::cerr << "usrp2: channel " << channel << " not implemented" << std::endl; return false; } - + ring_sptr rp = d_channel_rings[channel]; if (!rp){ std::cerr << "usrp2: channel " << channel << " not receiving" << std::endl; return false; } - + // Wait for frames available in channel ring DEBUG_LOG("W"); rp->wait_for_not_empty(); DEBUG_LOG("s"); - + // Iterate through frames and present to user void *p; size_t frame_len_in_bytes; @@ -791,7 +895,7 @@ namespace usrp2 { // Transmit // ---------------------------------------------------------------- - bool + bool usrp2::impl::set_tx_gain(double gain) { op_config_tx_v2_cmd cmd; @@ -800,7 +904,7 @@ namespace usrp2 { init_config_tx_v2_cmd(&cmd); cmd.op.valid = htons(CFGV_GAIN); cmd.op.gain = htons(u2_double_to_fxpt_gain(gain)); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -808,7 +912,7 @@ namespace usrp2 { bool success = (ntohx(reply.ok) == 1); return success; } - + bool usrp2::impl::set_tx_lo_offset(double frequency) { @@ -827,7 +931,7 @@ namespace usrp2 { cmd.eop.opcode = OP_EOP; cmd.eop.len = sizeof(cmd.eop); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -847,7 +951,7 @@ namespace usrp2 { u2_fxpt_freq_t fxpt = u2_double_to_fxpt_freq(frequency); cmd.op.freq_hi = htonl(u2_fxpt_freq_hi(fxpt)); cmd.op.freq_lo = htonl(u2_fxpt_freq_lo(fxpt)); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -855,18 +959,18 @@ namespace usrp2 { bool success = (ntohx(reply.ok) == 1); if (result && success) { result->baseband_freq = - u2_fxpt_freq_to_double( - u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi), + u2_fxpt_freq_to_double( + u2_fxpt_freq_from_hilo(ntohl(reply.baseband_freq_hi), ntohl(reply.baseband_freq_lo))); result->dxc_freq = - u2_fxpt_freq_to_double( - u2_fxpt_freq_from_hilo(ntohl(reply.duc_freq_hi), + u2_fxpt_freq_to_double( + u2_fxpt_freq_from_hilo(ntohl(reply.duc_freq_hi), ntohl(reply.duc_freq_lo))); result->residual_freq = - u2_fxpt_freq_to_double( - u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi), + u2_fxpt_freq_to_double( + u2_fxpt_freq_from_hilo(ntohl(reply.residual_freq_hi), ntohl(reply.residual_freq_lo))); result->spectrum_inverted = (bool)(ntohx(reply.inverted) == 1); @@ -874,7 +978,7 @@ namespace usrp2 { return success; } - + bool usrp2::impl::set_tx_interp(int interpolation_factor) { @@ -884,7 +988,7 @@ namespace usrp2 { init_config_tx_v2_cmd(&cmd); cmd.op.valid = htons(CFGV_INTERP_DECIM); cmd.op.interp = htonl(interpolation_factor); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -901,7 +1005,7 @@ namespace usrp2 { return success; } - + void usrp2::impl::default_tx_scale_iq(int interpolation_factor, int *scale_i, int *scale_q) { @@ -914,7 +1018,7 @@ namespace usrp2 { // Calculate dsp_core_tx gain absent scale multipliers float gain = (1.65*i*i*i)/(4096*pow(2, ceil(log2(i*i*i)))); - + // Calculate closest multiplier constant to reverse gain int scale = (int)rint(1.0/gain); // fprintf(stderr, "if=%i i=%i gain=%f scale=%i\n", interpolation_factor, i, gain, scale); @@ -935,7 +1039,7 @@ namespace usrp2 { init_config_tx_v2_cmd(&cmd); cmd.op.valid = htons(CFGV_SCALE_IQ); cmd.op.scale_iq = htonl(((scale_i & 0xffff) << 16) | (scale_q & 0xffff)); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -1063,7 +1167,7 @@ namespace usrp2 { cmd.op.flags = flags; cmd.eop.opcode = OP_EOP; cmd.eop.len = sizeof(cmd.eop); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -1137,10 +1241,10 @@ namespace usrp2 { dst->dbid = ntohl(src->dbid); dst->freq_min = - u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_min_hi), + u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_min_hi), ntohl(src->freq_min_lo))); dst->freq_max = - u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_max_hi), + u2_fxpt_freq_to_double(u2_fxpt_freq_from_hilo(ntohl(src->freq_max_hi), ntohl(src->freq_max_lo))); dst->gain_min = u2_fxpt_gain_to_double(ntohs(src->gain_min)); @@ -1161,7 +1265,7 @@ namespace usrp2 { cmd.op.rid = d_next_rid++; cmd.eop.opcode = OP_EOP; cmd.eop.len = sizeof(cmd.eop); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -1188,7 +1292,7 @@ namespace usrp2 { cmd.op.rid = d_next_rid++; cmd.eop.opcode = OP_EOP; cmd.eop.len = sizeof(cmd.eop); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -1210,7 +1314,7 @@ namespace usrp2 { cmd.op.ok = enable ? 1 : 0; cmd.eop.opcode = OP_EOP; cmd.eop.len = sizeof(cmd.eop); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -1225,7 +1329,7 @@ namespace usrp2 { // fprintf(stderr, "usrp2::peek: addr=%08X words=%u\n", addr, words); if (addr % 4 != 0) { - fprintf(stderr, "usrp2::peek: addr (=%08X) must be 32-bit word aligned\n", addr); + fprintf(stderr, "usrp2::peek: addr (=%08X) must be 32-bit word aligned\n", addr); return result; } @@ -1267,7 +1371,7 @@ namespace usrp2 { usrp2::impl::poke32(uint32_t addr, const std::vector<uint32_t> &data) { if (addr % 4 != 0) { - fprintf(stderr, "usrp2::poke32: addr (=%08X) must be 32-bit word aligned\n", addr); + fprintf(stderr, "usrp2::poke32: addr (=%08X) must be 32-bit word aligned\n", addr); return false; } @@ -1339,7 +1443,7 @@ namespace usrp2 { cmd.op.rid = d_next_rid++; cmd.eop.opcode = OP_EOP; cmd.eop.len = sizeof(cmd.eop); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -1368,7 +1472,7 @@ namespace usrp2 { cmd.op.mask = htons(mask); cmd.eop.opcode = OP_EOP; cmd.eop.len = sizeof(cmd.eop); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -1401,7 +1505,7 @@ namespace usrp2 { memcpy(&cmd.op.sels, sels.c_str(), 16); cmd.eop.opcode = OP_EOP; cmd.eop.len = sizeof(cmd.eop); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -1430,7 +1534,7 @@ namespace usrp2 { cmd.op.mask = htons(mask); cmd.eop.opcode = OP_EOP; cmd.eop.len = sizeof(cmd.eop); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -1459,7 +1563,7 @@ namespace usrp2 { cmd.op.mask = 0; // not used cmd.eop.opcode = OP_EOP; cmd.eop.len = sizeof(cmd.eop); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; @@ -1496,7 +1600,7 @@ namespace usrp2 { cmd.op.mask = 0; // not used cmd.eop.opcode = OP_EOP; cmd.eop.len = sizeof(cmd.eop); - + pending_reply p(cmd.op.rid, &reply, sizeof(reply)); if (!transmit_cmd_and_wait(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) return false; diff --git a/usrp2/host/lib/usrp2_impl.h b/usrp2/host/lib/usrp2_impl.h index ed71a6ba3..d78a00db4 100644 --- a/usrp2/host/lib/usrp2_impl.h +++ b/usrp2/host/lib/usrp2_impl.h @@ -30,7 +30,7 @@ #define MAX_SUBPKT_LEN 252 namespace usrp2 { - + class eth_buffer; class pktfilter; class usrp2_thread; @@ -62,7 +62,7 @@ namespace usrp2 { std::string d_addr; // FIXME: use u2_mac_addr_t instead usrp2_thread *d_bg_thread; volatile bool d_bg_running; // TODO: multistate if needed - + int d_rx_seqno; int d_tx_seqno; int d_next_rid; @@ -84,7 +84,7 @@ namespace usrp2 { db_info d_tx_db_info; db_info d_rx_db_info; - int d_tx_interp; // shadow tx interp + int d_tx_interp; // shadow tx interp int d_rx_decim; // shadow rx decim bool d_dont_enqueue; @@ -93,13 +93,13 @@ namespace usrp2 { omni_mutex_lock l(d_enqueued_mutex); d_num_enqueued++; } - + void dec_enqueued() { omni_mutex_lock l(d_enqueued_mutex); if (--d_num_enqueued == 0) d_bg_pending_cond.signal(); } - + static bool parse_mac_addr(const std::string &s, u2_mac_addr_t *p); void init_et_hdrs(u2_eth_packet_t *p, const std::string &dst); void init_etf_hdrs(u2_eth_packet_t *p, const std::string &dst, @@ -118,7 +118,7 @@ namespace usrp2 { public: impl(const std::string &ifc, props *p, size_t rx_bufsize); ~impl(); - + void bg_loop(); std::string mac_addr() const { return d_addr; } // FIXME: convert from u2_mac_addr_t @@ -143,6 +143,8 @@ namespace usrp2 { bool write_gpio(int bank, uint16_t value, uint16_t mask); bool read_gpio(int bank, uint16_t *value); bool start_rx_streaming(unsigned int channel, unsigned int items_per_frame); + bool start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time); + bool sync_and_start_rx_streaming_at(unsigned int channel, unsigned int items_per_frame, unsigned int time); bool rx_samples(unsigned int channel, rx_sample_handler *handler); bool flush_rx_samples(unsigned int channel); bool stop_rx_streaming(unsigned int channel); @@ -196,7 +198,7 @@ namespace usrp2 { std::vector<uint32_t> peek32(uint32_t addr, uint32_t words); bool poke32(uint32_t addr, const std::vector<uint32_t> &data); }; - + } // namespace usrp2 #endif /* INCLUDED_USRP2_IMPL_H */ |