From 297479844e3d9a6eea54fa69147e6a20c0bfc412 Mon Sep 17 00:00:00 2001 From: jcorgan Date: Sat, 27 Dec 2008 21:09:26 +0000 Subject: [PATCH] Implements USRP2 peek() command, allowing arbitrary reads from the internal Wishbone bus. Minor fix for USRP2 sync_to_pps() (uses correct packet type.) Example: >>> from gnuradio import usrp2 >>> u = usrp2.source_32fc() >>> u.peek(0x1234, 4) # Read four bytes at offset 0x1234 (code) (185, 244, 253, 164) >>> The return value will be zero length upon error. The read address must be 32-bit aligned, and only the lower 16 bits are significant. The length must be an integral multiple of 4 bytes. There is currently a read limit of 176 bytes per read; to change requires some additional firmware changes to allocate a larger reply packet. WARNING: Trying to read from memory locations not serviced by RAM or by a Wishbone peripheral may result in a hang requiring a USRP2 power cycle. The USRP2 internal memory map is documented in usrp2/firmware/lib/memory_map.h. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@10172 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-usrp2/src/usrp2.i | 4 ++ gr-usrp2/src/usrp2_base.cc | 6 +++ gr-usrp2/src/usrp2_base.h | 6 +++ usrp2/firmware/apps/app_common_v2.c | 28 ++++++++++++ usrp2/firmware/include/usrp2_eth_packet.h | 23 ++++++---- usrp2/host/include/usrp2/usrp2.h | 15 ++++++ usrp2/host/lib/control.h | 12 +++++ usrp2/host/lib/usrp2.cc | 6 +++ usrp2/host/lib/usrp2_impl.cc | 56 +++++++++++++++++++---- usrp2/host/lib/usrp2_impl.h | 1 + 10 files changed, 141 insertions(+), 16 deletions(-) diff --git a/gr-usrp2/src/usrp2.i b/gr-usrp2/src/usrp2.i index df07ee8f..a484397f 100644 --- a/gr-usrp2/src/usrp2.i +++ b/gr-usrp2/src/usrp2.i @@ -24,6 +24,7 @@ %include "exception.i" %import "gnuradio.i" // the common stuff +%import %{ #include @@ -35,6 +36,8 @@ %include +%template(uint8_t_vector) std::vector; + // ---------------------------------------------------------------- class usrp2_base : public gr_sync_block @@ -49,6 +52,7 @@ public: %rename(_real_fpga_master_clock_freq) fpga_master_clock_freq; bool fpga_master_clock_freq(long *freq); bool sync_to_pps(); + std::vector peek(uint32_t addr, uint32_t len); }; // ---------------------------------------------------------------- diff --git a/gr-usrp2/src/usrp2_base.cc b/gr-usrp2/src/usrp2_base.cc index 8f80a011..443d1faa 100644 --- a/gr-usrp2/src/usrp2_base.cc +++ b/gr-usrp2/src/usrp2_base.cc @@ -67,6 +67,12 @@ usrp2_base::sync_to_pps() return d_u2->sync_to_pps(); } +std::vector +usrp2_base::peek(uint32_t addr, uint32_t len) +{ + return d_u2->peek(addr, len); +} + bool usrp2_base::start() { diff --git a/gr-usrp2/src/usrp2_base.h b/gr-usrp2/src/usrp2_base.h index df0c862f..87743700 100644 --- a/gr-usrp2/src/usrp2_base.h +++ b/gr-usrp2/src/usrp2_base.h @@ -63,6 +63,12 @@ public: */ bool sync_to_pps(); + + /*! + * \brief Read memory from Wishbone bus + */ + std::vector peek(uint32_t addr, uint32_t len); + /*! * \brief Called by scheduler when starting flowgraph */ diff --git a/usrp2/firmware/apps/app_common_v2.c b/usrp2/firmware/apps/app_common_v2.c index 9bb5e4d7..b51c3b23 100644 --- a/usrp2/firmware/apps/app_common_v2.c +++ b/usrp2/firmware/apps/app_common_v2.c @@ -331,6 +331,30 @@ dboard_info_cmd(const op_generic_t *p, return r->len; } +static size_t +peek_cmd(const op_peek_t *p, + void *reply_payload, size_t reply_payload_space) +{ + op_generic_t *r = (op_generic_t *) reply_payload; + + putstr("peek: addr="); puthex32(p->addr); + printf(" bytes=%u\n", p->bytes); + + if (reply_payload_space < (sizeof(*r) + p->bytes)) { + putstr("peek: insufficient reply packet space\n"); + return 0; // FIXME do partial read? + } + + r->opcode = OP_PEEK_REPLY; + r->len = sizeof(*r)+p->bytes; + r->rid = p->rid; + r->ok = true; + + memcpy_wa(reply_payload+sizeof(*r), p->addr, p->bytes); + + return r->len; +} + static size_t generic_reply(const op_generic_t *p, void *reply_payload, size_t reply_payload_space, @@ -435,6 +459,10 @@ handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len) sync_to_pps((op_generic_t *) payload)); break; + case OP_PEEK: + subpktlen = peek_cmd((op_peek_t *)payload, reply_payload, reply_payload_space); + break; + default: printf("app_common_v2: unhandled opcode = %d\n", gp->opcode); break; diff --git a/usrp2/firmware/include/usrp2_eth_packet.h b/usrp2/firmware/include/usrp2_eth_packet.h index cfff0dd0..8a9994f1 100644 --- a/usrp2/firmware/include/usrp2_eth_packet.h +++ b/usrp2/firmware/include/usrp2_eth_packet.h @@ -185,12 +185,8 @@ typedef struct { #define OP_DBOARD_INFO_REPLY (OP_DBOARD_INFO | OP_REPLY_BIT) #define OP_SYNC_TO_PPS 10 #define OP_SYNC_TO_PPS_REPLY (OP_SYNC_TO_PPS | OP_REPLY_BIT) - - -//#define OP_WRITE_REG xx // not implemented -//#define OP_WRITE_REG_MASKED xx -//#define OP_READ_REG xx -//#define OP_READ_REG_REPLY xx +#define OP_PEEK 11 +#define OP_PEEK_REPLY (OP_PEEK | OP_REPLY_BIT) /* * All subpackets are a multiple of 4 bytes long. @@ -203,7 +199,7 @@ typedef struct { * * Used by: * OP_EOP, OP_BURN_MAC_ADDR_REPLY, OP_START_RX_STREAMING_REPLY, - * OP_STOP_RX_REPLY, OP_DBOARD_INFO + * OP_STOP_RX_REPLY, OP_DBOARD_INFO, OP_SYNC_TO_PPS */ typedef struct { uint8_t opcode; @@ -380,7 +376,17 @@ typedef struct { u2_db_info_t rx_db_info; } _AL4 op_dboard_info_reply_t; - +/*! + * \brief Read from Wishbone memory + */ +typedef struct { + uint8_t opcode; + uint8_t len; + uint8_t rid; + uint8_t mbz; + uint32_t addr; + uint32_t bytes; +} _AL4 op_peek_t; /* * ================================================================ @@ -399,6 +405,7 @@ typedef union { op_config_tx_v2_t op_config_tx_v2; op_config_tx_reply_v2_t op_config_tx_reply_v2; op_config_mimo_t op_config_mimo; + op_peek_t op_peek; } u2_subpkt_t; diff --git a/usrp2/host/include/usrp2/usrp2.h b/usrp2/host/include/usrp2/usrp2.h index 4fa9da1e..e942bb57 100644 --- a/usrp2/host/include/usrp2/usrp2.h +++ b/usrp2/host/include/usrp2/usrp2.h @@ -361,6 +361,21 @@ namespace usrp2 { */ bool sync_to_pps(); + /*! + * Read memory from Wishbone bus + * + * \param addr 32-bit aligned address. Only the lower 16-bits are significant. + * \param len Number of bytes to read, must be positive and multiple of 4. + * + * \returns Vector of 8-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 peek(uint32_t addr, uint32_t len); + + #if 0 // not yet implemented /*! * \brief Write EEPROM on motherboard or any daughterboard. diff --git a/usrp2/host/lib/control.h b/usrp2/host/lib/control.h index fe30b3f7..774ca85f 100644 --- a/usrp2/host/lib/control.h +++ b/usrp2/host/lib/control.h @@ -23,6 +23,13 @@ #include namespace usrp2 { + + struct op_generic_cmd { + u2_eth_packet_t h; + op_generic_t op; + op_generic_t eop; + }; + /*! * OP_CONFIG_RX_V2 command packet */ @@ -73,6 +80,11 @@ namespace usrp2 { op_generic_t eop; }; + struct op_peek_cmd { + u2_eth_packet_t h; + op_peek_t op; + op_generic_t eop; + }; /*! * Control mechanism to allow API calls to block waiting for reply packets diff --git a/usrp2/host/lib/usrp2.cc b/usrp2/host/lib/usrp2.cc index ecfc0b30..136062d0 100644 --- a/usrp2/host/lib/usrp2.cc +++ b/usrp2/host/lib/usrp2.cc @@ -395,6 +395,12 @@ namespace usrp2 { return d_impl->sync_to_pps(); } + std::vector + usrp2::peek(uint32_t addr, uint32_t len) + { + return d_impl->peek(addr, len); + } + } // namespace usrp2 diff --git a/usrp2/host/lib/usrp2_impl.cc b/usrp2/host/lib/usrp2_impl.cc index 24e6d7e7..d7769a84 100644 --- a/usrp2/host/lib/usrp2_impl.cc +++ b/usrp2/host/lib/usrp2_impl.cc @@ -72,12 +72,9 @@ namespace usrp2 { case OP_DBOARD_INFO: return "OP_DBOARD_INFO"; case OP_DBOARD_INFO_REPLY: return "OP_DBOARD_INFO_REPLY"; case OP_SYNC_TO_PPS: return "OP_SYNC_TO_PPS"; -#if 0 - case OP_WRITE_REG: return "OP_WRITE_REG"; - case OP_WRITE_REG_MASKED: return "OP_WRITE_REG_MASKED"; - case OP_READ_REG: return "OP_READ_REG"; - case OP_READ_REG_REPLY: return "OP_READ_REG_REPLY"; -#endif + case OP_PEEK: return "OP_PEEK"; + case OP_PEEK_REPLY: return "OP_PEEK_REPLY"; + default: char buf[64]; snprintf(buf, sizeof(buf), "", opcode); @@ -1024,8 +1021,8 @@ namespace usrp2 { bool usrp2::impl::sync_to_pps() { - op_config_mimo_cmd cmd; - op_generic_t reply; + op_generic_cmd cmd; + op_generic_t reply; memset(&cmd, 0, sizeof(cmd)); init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1); @@ -1042,4 +1039,47 @@ namespace usrp2 { return ntohx(reply.ok) == 1; } + std::vector + usrp2::impl::peek(uint32_t addr, uint32_t len) + { + std::vector result; // zero sized on error return + // fprintf(stderr, "usrp2::peek: addr=%08X len=%u\n", addr, len); + + if (addr % 4 != 0) { + fprintf(stderr, "usrp2::peek: addr (=%08X) must be 32-bit word aligned\n", addr); + return result; + } + + if (len < 4 || len % 4 != 0) { + fprintf(stderr, "usrp2::peek: len (=%u) must be an integral multiple of 4\n", len); + return result; + } + + op_peek_cmd cmd; + op_generic_t *reply; + + memset(&cmd, 0, sizeof(cmd)); + init_etf_hdrs(&cmd.h, d_addr, 0, CONTROL_CHAN, -1); + cmd.op.opcode = OP_PEEK; + cmd.op.len = sizeof(cmd.op); + cmd.op.rid = d_next_rid++; + cmd.eop.opcode = OP_EOP; + cmd.eop.len = sizeof(cmd.eop); + + cmd.op.addr = htonl(addr); + cmd.op.bytes = htonl(len); + + reply = (op_generic_t *)malloc(sizeof(*reply)+len); + pending_reply p(cmd.op.rid, reply, sizeof(*reply)+len); + if (transmit_cmd(&cmd, sizeof(cmd), &p, DEF_CMD_TIMEOUT)) { + uint32_t bytes = reply->len-sizeof(*reply); + uint8_t *data = (uint8_t *)(reply)+sizeof(*reply); + for (unsigned int i = 0; i < bytes; i++) + result.push_back(data[i]); + } + + free(reply); + return result; + } + } // namespace usrp2 diff --git a/usrp2/host/lib/usrp2_impl.h b/usrp2/host/lib/usrp2_impl.h index f5030f54..d9701287 100644 --- a/usrp2/host/lib/usrp2_impl.h +++ b/usrp2/host/lib/usrp2_impl.h @@ -174,6 +174,7 @@ namespace usrp2 { bool burn_mac_addr(const std::string &new_addr); bool sync_to_pps(); + std::vector peek(uint32_t addr, uint32_t len); }; } // namespace usrp2 -- 2.30.2