Implements USRP2 peek() command, allowing arbitrary reads from the internal
authorjcorgan <jcorgan@221aa14e-8319-0410-a670-987f0aec2ac5>
Sat, 27 Dec 2008 21:09:26 +0000 (21:09 +0000)
committerjcorgan <jcorgan@221aa14e-8319-0410-a670-987f0aec2ac5>
Sat, 27 Dec 2008 21:09:26 +0000 (21:09 +0000)
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
gr-usrp2/src/usrp2_base.cc
gr-usrp2/src/usrp2_base.h
usrp2/firmware/apps/app_common_v2.c
usrp2/firmware/include/usrp2_eth_packet.h
usrp2/host/include/usrp2/usrp2.h
usrp2/host/lib/control.h
usrp2/host/lib/usrp2.cc
usrp2/host/lib/usrp2_impl.cc
usrp2/host/lib/usrp2_impl.h

index df07ee8f4a97331561ebc3fc4c99a968e78b6517..a484397f8ea2da7c9881ddcad6abddd88580d644 100644 (file)
@@ -24,6 +24,7 @@
 
 %include "exception.i"
 %import "gnuradio.i"                   // the common stuff
+%import <stdint.i>     
 
 %{
 #include <gnuradio_swig_bug_workaround.h>
@@ -35,6 +36,8 @@
 
 %include <usrp2/tune_result.h>
 
+%template(uint8_t_vector) std::vector<uint8_t>;
+
 // ----------------------------------------------------------------
 
 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<uint8_t> peek(uint32_t addr, uint32_t len);
 };
 
 // ----------------------------------------------------------------
index 8f80a0119d627f462db6892f33d26878648525aa..443d1faaa3b4ea9fd4c9f780ae741b8acefed2fd 100644 (file)
@@ -67,6 +67,12 @@ usrp2_base::sync_to_pps()
   return d_u2->sync_to_pps();
 }
 
+std::vector<uint8_t>
+usrp2_base::peek(uint32_t addr, uint32_t len)
+{
+  return d_u2->peek(addr, len);
+}
+
 bool
 usrp2_base::start()
 {
index df0c862f82148835f7a7df5d6e0713308cea1c08..877437009fb94bf7b31766eb7437cb1fa503db2d 100644 (file)
@@ -63,6 +63,12 @@ public:
    */
   bool sync_to_pps();
 
+
+  /*!
+   * \brief Read memory from Wishbone bus
+   */
+  std::vector<uint8_t> peek(uint32_t addr, uint32_t len);
+
   /*!
    * \brief Called by scheduler when starting flowgraph
    */
index 9bb5e4d74520d4ebd3cdefd9fa7ce4fae9a7d33a..b51c3b23c88173e6d0310d42aad2528c82c9cfc4 100644 (file)
@@ -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;
index cfff0dd08201113a53a3e4121c6d79b735871f8e..8a9994f17549751dca220e27f0ede57ed0187396 100644 (file)
@@ -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;
 
index 4fa9da1eefae6e13f63a968a204715936d9aeffc..e942bb579dc077bd17f57c945e5d6850af4fa59b 100644 (file)
@@ -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<uint8_t> peek(uint32_t addr, uint32_t len);
+
+
 #if 0  // not yet implemented
     /*!
      * \brief Write EEPROM on motherboard or any daughterboard.
index fe30b3f74378824aabf0af75fa4c4e61f849ea85..774ca85f65cec51b39c48fdbb16d9d7f01092c29 100644 (file)
 #include <usrp2_eth_packet.h>
 
 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
index ecfc0b30af672c5db0c92b4c7278ea1034f81d3b..136062d08658dd8a075d56485f9aede0471f153e 100644 (file)
@@ -395,6 +395,12 @@ namespace usrp2 {
     return d_impl->sync_to_pps();
   }
 
+  std::vector<uint8_t>
+  usrp2::peek(uint32_t addr, uint32_t len)
+  {
+    return d_impl->peek(addr, len);
+  }
+
 } // namespace usrp2
 
 
index 24e6d7e7310972f3c4558dbc0241b60eb9b78151..d7769a842a0f3816571078690174a4d3e347254d 100644 (file)
@@ -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), "<unknown opcode: %d>", 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<uint8_t>
+  usrp2::impl::peek(uint32_t addr, uint32_t len)
+  {
+    std::vector<uint8_t> 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
index f5030f5412f4ad032c8fa85b553fdbcce23bbac9..d9701287e8ec5528e0533cc98f6edf8784469d3a 100644 (file)
@@ -174,6 +174,7 @@ namespace usrp2 {
 
     bool burn_mac_addr(const std::string &new_addr);
     bool sync_to_pps();
+    std::vector<uint8_t> peek(uint32_t addr, uint32_t len);
   };
   
 } // namespace usrp2