diff options
author | Martin Braun <martin.braun@ettus.com> | 2017-03-24 19:06:32 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2017-03-24 19:06:32 -0700 |
commit | f3cabe9ffd7a27ee8c0a6d57b4e1dd6835760a18 (patch) | |
tree | 073efbb38e81ad1f8563c4844dad3f7449eab38b | |
parent | 4d3572494e979bb94a929a0485813c0ba3fcc453 (diff) | |
parent | 04b205d15bea5ef56d4f96446db6ec20124df9e7 (diff) | |
download | uhd-f3cabe9ffd7a27ee8c0a6d57b4e1dd6835760a18.tar.gz uhd-f3cabe9ffd7a27ee8c0a6d57b4e1dd6835760a18.tar.bz2 uhd-f3cabe9ffd7a27ee8c0a6d57b4e1dd6835760a18.zip |
Merge branch 'maint'
-rw-r--r-- | firmware/fx3/README.md | 2 | ||||
-rw-r--r-- | host/CMakeLists.txt | 4 | ||||
-rw-r--r-- | host/docs/vrt_chdr.dox | 24 | ||||
-rw-r--r-- | host/examples/CMakeLists.txt | 4 | ||||
-rw-r--r-- | host/examples/twinrx_freq_hopping.cpp | 280 | ||||
-rw-r--r-- | host/include/uhd/types/sid.hpp | 8 | ||||
-rw-r--r-- | host/include/uhd/usrp/multi_usrp.hpp | 2 | ||||
-rw-r--r-- | host/lib/transport/udp_common.hpp | 3 | ||||
-rw-r--r-- | host/lib/transport/udp_zero_copy.cpp | 16 | ||||
-rw-r--r-- | host/lib/usrp/common/max287x.hpp | 6 | ||||
-rw-r--r-- | tools/dissectors/packet-chdr.c | 95 |
11 files changed, 376 insertions, 68 deletions
diff --git a/firmware/fx3/README.md b/firmware/fx3/README.md index 29d72a9ad..9b3d65489 100644 --- a/firmware/fx3/README.md +++ b/firmware/fx3/README.md @@ -16,7 +16,7 @@ managing the transport from the host to the FPGA by configuring IO and DMA. In order to compile the USRP B200 and B210 firmware, you will need the FX3 SDK distributed by the FX3 manufacturer, Cypress Semiconductor. You can download the -[FX3 SDK from here](http://www.cypress.com/?rID=57990). +[FX3 SDK from here](http://www.cypress.com/documentation/software-and-drivers/ez-usb-fx3-sdk-archives) *Note*: You *must* use SDK version 1.2.3! Once you have downloaded it, extract the ARM cross-compiler from the tarball diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index aab71d7e8..8def96811 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -238,8 +238,8 @@ IF(MSVC) -D_CRT_NONSTDC_NO_DEPRECATE -D_WINSOCK_DEPRECATED_NO_WARNINGS ) - ADD_DEFINITIONS(/MP) #multi-threaded build - ADD_DEFINITIONS(/bigobj) #Increases the number of addressable sections in an .obj file. + # multi-threaded build and increases the number of addressable sections in an .obj file. + SET (COMPILE_FLAGS ${COMPILE_FLAGS} /MP /bigobj) ENDIF(MSVC) IF(CYGWIN) diff --git a/host/docs/vrt_chdr.dox b/host/docs/vrt_chdr.dox index a2d36c93e..8675349f9 100644 --- a/host/docs/vrt_chdr.dox +++ b/host/docs/vrt_chdr.dox @@ -51,20 +51,20 @@ Bits | Meaning 60 | End-of-burst or error flag 59:48 | 12-bit sequence number 47:32 | Total packet length in Bytes -31:0 | Stream ID (SID) - +31:0 | Stream ID (SID). For the format of SID, see uhd::sid_t. The packet type is determined mainly by the first two bits, although -the EOB or error flag are also taken into consideration: - -Bit 63 | Bit 62 | Bit 60 | Packet Type --------|--------|--------|-------------- -0 | 0 | 0 | Data -0 | 0 | 1 | Data (End-of-burst) -0 | 1 | 0 | Flow Control -1 | 0 | 0 | Command Packet -1 | 1 | 0 | Command Response -1 | 1 | 1 | Command Response (Error) +the EOB or error flag are also taken into consideration (the third bit does not +affect the packet type): + +Bit 63 | Bit 62 | Bit 61 | Bit 60 | Packet Type +-------|--------|--------|--------|-------------- +0 | 0 | x | 0 | Data +0 | 0 | x | 1 | Data (End-of-burst) +0 | 1 | x | 0 | Flow Control +1 | 0 | x | 0 | Command Packet +1 | 1 | x | 0 | Command Response +1 | 1 | x | 1 | Command Response (Error) \section vrt_tools Tools diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt index e61fd897f..e10c463f8 100644 --- a/host/examples/CMakeLists.txt +++ b/host/examples/CMakeLists.txt @@ -61,6 +61,10 @@ IF(CURSES_FOUND) ADD_EXECUTABLE(rx_ascii_art_dft rx_ascii_art_dft.cpp) TARGET_LINK_LIBRARIES(rx_ascii_art_dft uhd ${CURSES_LIBRARIES} ${Boost_LIBRARIES}) UHD_INSTALL(TARGETS rx_ascii_art_dft RUNTIME DESTINATION ${PKG_LIB_DIR}/examples COMPONENT examples) + + ADD_EXECUTABLE(twinrx_freq_hopping twinrx_freq_hopping.cpp) + TARGET_LINK_LIBRARIES(twinrx_freq_hopping uhd ${CURSES_LIBRARIES} ${Boost_LIBRARIES}) + UHD_INSTALL(TARGETS twinrx_freq_hopping RUNTIME DESTINATION ${PKG_LIB_DIR}/examples COMPONENT examples) ENDIF(CURSES_FOUND) ######################################################################## diff --git a/host/examples/twinrx_freq_hopping.cpp b/host/examples/twinrx_freq_hopping.cpp new file mode 100644 index 000000000..6d7018912 --- /dev/null +++ b/host/examples/twinrx_freq_hopping.cpp @@ -0,0 +1,280 @@ +// +// Copyright 2016 Ettus Research LLC +// +// 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 3 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, see <http://www.gnu.org/licenses/>. +// + +// FFT conversion +#include "ascii_art_dft.hpp" + +#include <uhd/utils/thread_priority.hpp> +#include <uhd/utils/safe_main.hpp> +#include <uhd/usrp/multi_usrp.hpp> + +#include <boost/program_options.hpp> +#include <boost/thread.hpp> + +#include <fstream> + +/* + * This example shows how to implement fast frequency hopping using an X-Series + * motherboard and a TwinRX daughterboard. + * + * The TwinRX daughterboard is different than previous daughterboards in that it has two + * RX channels, each with a set of Local Oscillators (LOs). Either channel can be configured + * to use either LO set, allowing for the two channels to share an LO source. + * + * The TwinRX can be used like any other daughterboard, as the multi_usrp::set_rx_freq() + * function will automatically calculate and set the two LO frequencies as needed. + * However, this adds to the overall tuning time. If the LO frequencies are manually set + * with the multi_usrp::set_rx_lo_freq() function, the TwinRX will will not perform the + * calculation itself, resulting in a faster tune time. This example shows how to take + * advantage of this as follows: + * + * 1. Tune across the given frequency range, storing the calculated LO frequencies along + * the way. + * 2. Use timed commands to tell the TwinRX to receive bursts of samples at given intervals. + * 3. For each frequency, tune the LOs for the inactive channel for the next frequency and + * receive at the current frequency. + * 4. If applicable, send the next timed command for streaming. + */ + +namespace pt = boost::posix_time; +namespace po = boost::program_options; + +typedef std::vector<std::complex<float> > recv_buff_t; +typedef std::vector<recv_buff_t> recv_buffs_t; + +// Global objects +static uhd::usrp::multi_usrp::sptr usrp; +static uhd::rx_streamer::sptr rx_stream; +static recv_buffs_t buffs; +static size_t recv_spb, spb; + +static std::vector<double> rf_freqs; + +static uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE); + +double receive_interval; + +// Define the active channel (connected to antenna) and the unused channel +size_t ACTIVE_CHAN = 0; +size_t UNUSED_CHAN = 1; + +const int X300_COMMAND_FIFO_DEPTH = 16; + + +// This is a helper function for receiving samples from the USRP +static void twinrx_recv(recv_buff_t &buffer) { + + size_t num_acc_samps = 0; + uhd::rx_metadata_t md; + + // Repeatedly retrieve samples until the entire acquisition is received + while (num_acc_samps < spb) { + size_t num_to_recv = std::min<size_t>(recv_spb, (spb - num_acc_samps)); + + // recv call will block until samples are ready or the call times out + size_t num_recvd = rx_stream->recv(&buffer[num_acc_samps], num_to_recv, md, receive_interval); + + if(md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE) { + std::cout << md.strerror() << std::endl; + break; + } + num_acc_samps += num_recvd; + } +} + +// Function to write the acquisition FFT to a binary file +static void write_fft_to_file(const std::string &fft_path) { + std::cout << "Calculating FFTs (this may take a while)... " << std::flush; + std::ofstream ofile(fft_path.c_str(), std::ios::binary); + BOOST_FOREACH(const recv_buff_t &buff, buffs) { + std::vector<float> fft = acsii_art_dft::log_pwr_dft(&buff.front(), buff.size()); + ofile.write((char*)&fft[0], (sizeof(float)*fft.size())); + } + ofile.close(); + std::cout << "done." << std::endl; +} + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + uhd::set_thread_priority_safe(); + + // Program options + std::string args, fft_path, subdev, ant; + double rate, gain; + double start_freq, end_freq; + + // Set up the program options + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "Print this help message") + ("args", po::value<std::string>(&args)->default_value(""), "UHD device args") + ("subdev", po::value<std::string>(&subdev)->default_value("A:0 A:1"), "Subdevice specification") + ("ant", po::value<std::string>(&ant)->default_value("RX1"), "RX Antenna") + ("start-freq", po::value<double>(&start_freq), "Start frequency (defaults to lowest valid frequency)") + ("end-freq", po::value<double>(&end_freq), "End frequency (defaults to highest valid frequency)") + ("receive-interval", po::value<double>(&receive_interval)->default_value(5e-3), "Interval between scheduled receives") + ("rate", po::value<double>(&rate)->default_value(1e6), "Incoming sample rate") + ("gain", po::value<double>(&gain)->default_value(60), "RX gain") + ("spb", po::value<size_t>(&spb)->default_value(1024), "Samples per buffer") + ("fft-path", po::value<std::string>(&fft_path), "Output an FFT to this file (optional)") + ("repeat", "repeat sweep until Ctrl-C is pressed") + ; + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + if(vm.count("help")) { + std::cout << "TwinRX Frequency Hopping Example - " << desc << std::endl; + return EXIT_SUCCESS; + } + + // Create a USRP device + std::cout << boost::format("\nCreating the USRP device with args: \"%s\"...\n") % args; + usrp = uhd::usrp::multi_usrp::make(args); + + // Make sure the USRP is an X3xx with a TwinRX + uhd::dict<std::string, std::string> info = usrp->get_usrp_rx_info(); + if(info.get("mboard_id").find("X3") == std::string::npos) { + throw uhd::runtime_error("This example can only be used with an X-Series motherboard."); + } + if(info.get("rx_id").find("TwinRX") == std::string::npos) { + throw uhd::runtime_error("This example can only be used with a TwinRX daughterboard."); + } + + // Validate frequency range + uhd::freq_range_t rx_freq_range = usrp->get_rx_freq_range(); + if (!vm.count("start-freq")) { + start_freq = rx_freq_range.start(); + } + if (!vm.count("end-freq")) { + end_freq = rx_freq_range.stop(); + } + if (start_freq < rx_freq_range.start() or end_freq > rx_freq_range.stop()) { + throw uhd::runtime_error((boost::format("Start and stop frequencies must be between %d and %d MHz") + % ((rx_freq_range.start() / 1e6), (rx_freq_range.stop() / 1e6))).str()); + } + if (start_freq > end_freq) { + throw uhd::runtime_error("Start frequency must be less than end frequency."); + } + if ((end_freq - start_freq) > 0 and (end_freq - start_freq) < rate) { + throw uhd::runtime_error("The sample rate must be less than the range between the start and end frequencies."); + } + + // Set TwinRX settings + usrp->set_rx_subdev_spec(subdev); + + // Set the unused channel to not use any LOs. This allows the active channel to control them. + usrp->set_rx_lo_source("disabled", uhd::usrp::multi_usrp::ALL_LOS, UNUSED_CHAN); + + // Set user settings + std::cout << boost::format("Setting antenna to: %s\n") % ant; + usrp->set_rx_antenna(ant, ACTIVE_CHAN); + std::cout << boost::format("Actual antenna: %s\n") % usrp->get_rx_antenna(ACTIVE_CHAN); + + std::cout << boost::format("Setting sample rate to: %d\n") % rate; + usrp->set_rx_rate(rate); + std::cout << boost::format("Actual sample rate: %d\n") % usrp->get_rx_rate(); + + std::cout << boost::format("Setting gain to: %d\n") % gain; + usrp->set_rx_gain(gain); + std::cout << boost::format("Actual gain: %d\n") % usrp->get_rx_gain(); + + // Get an rx_streamer from the device + uhd::stream_args_t stream_args("fc32", "sc16"); + stream_args.channels.push_back(0); + rx_stream = usrp->get_rx_stream(stream_args); + recv_spb = rx_stream->get_max_num_samps(); + + // Calculate the frequency hops + for (double rx_freq = start_freq; rx_freq <= end_freq; rx_freq += rate) { + rf_freqs.push_back(rx_freq); + } + std::cout << boost::format("Total Hops: %d\n") % rf_freqs.size(); + + // Set up buffers + buffs = recv_buffs_t(rf_freqs.size(), recv_buff_t(spb)); + + // Tune the active channel to the first frequency and reset the USRP's time + usrp->set_rx_freq(rf_freqs[0], ACTIVE_CHAN); + usrp->set_time_now(uhd::time_spec_t(0.0)); + + // Configure the stream command which will be issued to acquire samples at each frequency + stream_cmd.num_samps = spb; + stream_cmd.stream_now = false; + stream_cmd.time_spec = uhd::time_spec_t(0.0); + + // Stream commands will be scheduled at regular intervals + uhd::time_spec_t receive_interval_ts = uhd::time_spec_t(receive_interval); + + // Issue stream commands to fill the command queue on the FPGA + size_t num_initial_cmds = std::min<size_t>(X300_COMMAND_FIFO_DEPTH, rf_freqs.size()); + size_t num_issued_commands; + + for (num_issued_commands = 0; num_issued_commands < num_initial_cmds; num_issued_commands++) { + stream_cmd.time_spec += receive_interval_ts; + rx_stream->issue_stream_cmd(stream_cmd); + } + + // Hop frequencies and acquire bursts of samples at each until done sweeping + while(1) { + + std::cout << "Scanning..." << std::endl; + uhd::time_spec_t start_time = uhd::time_spec_t::get_system_time(); + + for (size_t i = 0; i < rf_freqs.size(); i++) { + // Swap the mapping of synthesizers by setting the LO source + // The unused channel will always + std::string lo_src = (i % 2) ? "companion" : "internal"; + usrp->set_rx_lo_source(lo_src, uhd::usrp::multi_usrp::ALL_LOS, ACTIVE_CHAN); + + // Preconfigure the next frequency + usrp->set_rx_freq(rf_freqs[(i+1) % rf_freqs.size()], UNUSED_CHAN); + + // Program the current frequency + // This frequency was already pre-programmed in the previous iteration so the local oscillators + // are already tuned. This call will only configure front-end filter, amplifiers, etc + usrp->set_rx_freq(rf_freqs[i], ACTIVE_CHAN); + + // Receive one burst of samples + twinrx_recv(buffs[i]); + + // Schedule another acquisition if necessary + if (vm.count("repeat") or num_issued_commands < rf_freqs.size()) { + stream_cmd.time_spec += receive_interval_ts; + rx_stream->issue_stream_cmd(stream_cmd); + num_issued_commands++; + } + } + + uhd::time_spec_t end_time = uhd::time_spec_t::get_system_time(); + std::cout << boost::format("Sweep done in %d milliseconds.\n") % ((end_time - start_time).get_real_secs() * 1000); + + // Optionally convert received samples to FFT and write to file + if(vm.count("fft-path")) { + write_fft_to_file(fft_path); + } + + if (!vm.count("repeat")){ + break; + } + } + + std::cout << "Done!" << std::endl; + + usrp.reset(); + return EXIT_SUCCESS; +} + diff --git a/host/include/uhd/types/sid.hpp b/host/include/uhd/types/sid.hpp index f1471549e..f9fa40273 100644 --- a/host/include/uhd/types/sid.hpp +++ b/host/include/uhd/types/sid.hpp @@ -39,7 +39,13 @@ namespace uhd { * is required, we use the combination of the 8-bit address and the 8-bit * endpoint. * - * \section sid_str_repr String Representation + * <pre> + * +-------------+--------------+-------------+--------------+ + * | SRC address | SRC endpoint | DST address | DST endpoint | + * +-------------+--------------+-------------+--------------+ + * </pre> + * + * \section sid_str_repr String Representation (pretty printing) * * The string representation of a SID is of the form * diff --git a/host/include/uhd/usrp/multi_usrp.hpp b/host/include/uhd/usrp/multi_usrp.hpp index 1a64a8f3a..fee430fe0 100644 --- a/host/include/uhd/usrp/multi_usrp.hpp +++ b/host/include/uhd/usrp/multi_usrp.hpp @@ -120,6 +120,8 @@ public: * Make a new multi usrp from the device address. * \param dev_addr the device address * \return a new single usrp object + * \throws uhd::key_error no device found + * \throws uhd::index_error fewer devices found than expected */ static sptr make(const device_addr_t &dev_addr); diff --git a/host/lib/transport/udp_common.hpp b/host/lib/transport/udp_common.hpp index 82eee237b..d6e73cc5f 100644 --- a/host/lib/transport/udp_common.hpp +++ b/host/lib/transport/udp_common.hpp @@ -23,6 +23,9 @@ namespace uhd{ namespace transport{ + // Jumbo frames are limited to 9000; + static const size_t MAX_ETHERNET_MTU = 9000; + typedef boost::shared_ptr<boost::asio::ip::udp::socket> socket_sptr; /*! diff --git a/host/lib/transport/udp_zero_copy.cpp b/host/lib/transport/udp_zero_copy.cpp index 121bb9b64..68970f332 100644 --- a/host/lib/transport/udp_zero_copy.cpp +++ b/host/lib/transport/udp_zero_copy.cpp @@ -310,22 +310,22 @@ udp_zero_copy::sptr udp_zero_copy::make( xport_params.num_send_frames = size_t(hints.cast<double>("num_send_frames", default_buff_args.num_send_frames)); //extract buffer size hints from the device addr - size_t usr_recv_buff_size = size_t(hints.cast<double>("recv_buff_size", 0.0)); - size_t usr_send_buff_size = size_t(hints.cast<double>("send_buff_size", 0.0)); + size_t usr_recv_buff_size = size_t(hints.cast<double>("recv_buff_size", xport_params.num_recv_frames * MAX_ETHERNET_MTU)); + size_t usr_send_buff_size = size_t(hints.cast<double>("send_buff_size", xport_params.num_send_frames * MAX_ETHERNET_MTU)); if (hints.has_key("recv_buff_size")) { - if (usr_recv_buff_size < xport_params.recv_frame_size * xport_params.num_recv_frames) { + if (usr_recv_buff_size < xport_params.num_recv_frames * MAX_ETHERNET_MTU) { throw uhd::value_error((boost::format( - "recv_buff_size must be equal to or greater than (num_recv_frames * recv_frame_size) where num_recv_frames=%d, recv_frame_size=%d") - % xport_params.num_recv_frames % xport_params.recv_frame_size).str()); + "recv_buff_size must be equal to or greater than %d") + % (xport_params.num_recv_frames * MAX_ETHERNET_MTU)).str()); } } if (hints.has_key("send_buff_size")) { - if (usr_send_buff_size < xport_params.send_frame_size * xport_params.num_send_frames) { + if (usr_send_buff_size < xport_params.num_send_frames * MAX_ETHERNET_MTU) { throw uhd::value_error((boost::format( - "send_buff_size must be equal to or greater than (num_send_frames * send_frame_size) where num_send_frames=%d, send_frame_size=%d") - % xport_params.num_send_frames % xport_params.send_frame_size).str()); + "send_buff_size must be equal to or greater than %d") + % (xport_params.num_send_frames * MAX_ETHERNET_MTU)).str()); } } diff --git a/host/lib/usrp/common/max287x.hpp b/host/lib/usrp/common/max287x.hpp index 1209d194e..a0400f651 100644 --- a/host/lib/usrp/common/max287x.hpp +++ b/host/lib/usrp/common/max287x.hpp @@ -900,6 +900,12 @@ void max287x<max287x_regs_t>::commit() } else { try { changed_regs = _regs.template get_changed_addrs<uint32_t> (); + // register 0 must be written to apply double buffered fields + if (changed_regs.size() > 0) + { + changed_regs.insert(0); + } + for (int addr = 5; addr >= 0; addr--) { if (changed_regs.find(uint32_t(addr)) != changed_regs.end()) diff --git a/tools/dissectors/packet-chdr.c b/tools/dissectors/packet-chdr.c index ba85a016f..95e537518 100644 --- a/tools/dissectors/packet-chdr.c +++ b/tools/dissectors/packet-chdr.c @@ -163,7 +163,6 @@ static void dissect_chdr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) gint flag_offset; guint8 *bytes; guint8 hdr_bits = 0; - guint8 pkt_type = 0; gboolean flag_has_time = 0; gboolean flag_is_data = 0; gboolean flag_is_fc = 0; @@ -171,12 +170,12 @@ static void dissect_chdr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) gboolean flag_is_resp = 0; gboolean flag_is_eob = 0; gboolean flag_is_error = 0; - unsigned long long timestamp; + uint64_t timestamp; gboolean is_network; gint endianness; - gint id_pos_usb[4] = {7, 6, 5, 4}; - gint id_pos_net[4] = {4, 5, 6, 7}; - gint id_pos[4] = {7, 6, 5, 4}; + gint id_pos_usb[4] = {3, 2, 1, 0}; + gint id_pos_net[4] = {0, 1, 2, 3}; + gint id_pos[4] = {0, 1, 2, 3}; if(pinfo->match_uint == CHDR_PORT){ is_network = TRUE; @@ -199,26 +198,30 @@ static void dissect_chdr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "CHDR"); if (tree){ - int chdr_size = -1; + int header_size = -1; // Total size of the CHDR header. Either 8 or 16. + guint16 hdr_info; if (len >= 4){ - chdr_size = 8; - bytes = tvb_get_string(wmem_packet_scope(), tvb, 0, 4); - hdr_bits = (bytes[flag_offset] & 0xF0) >> 4; - pkt_type = hdr_bits >> 2; - flag_is_data = (pkt_type == 0); - flag_is_fc = (pkt_type == 1); - flag_is_cmd = (pkt_type == 2); - flag_is_resp = (pkt_type == 3); - flag_is_eob = flag_is_data && (hdr_bits & 0x1); - flag_is_error = flag_is_resp && (hdr_bits & 0x1); + guint8 pkt_type = 0; + hdr_info = tvb_get_ntohs(tvb, flag_offset); + header_size = 8; // We now know the header is at least 8 bytes long. + hdr_bits = (hdr_info & 0xF000) >> 12; + pkt_type = hdr_bits >> 2; + flag_is_data = (pkt_type == 0); + flag_is_fc = (pkt_type == 1); + flag_is_cmd = (pkt_type == 2); + flag_is_resp = (pkt_type == 3); + flag_is_eob = flag_is_data && (hdr_bits & 0x1); + flag_is_error = flag_is_resp && (hdr_bits & 0x1); flag_has_time = hdr_bits & 0x2; - if (flag_has_time) - chdr_size += 8; // 64-bit timestamp + if (flag_has_time) { + header_size += 8; // 64-bit timestamp. + } + /* header_size is now final. */ } /* Start with a top-level item to add everything else to */ - item = proto_tree_add_item(tree, proto_chdr, tvb, 0, min(len, chdr_size), ENC_NA); + item = proto_tree_add_item(tree, proto_chdr, tvb, 0, min(len, header_size), ENC_NA); if (len >= 4) { chdr_tree = proto_item_add_subtree(item, ett_chdr); @@ -226,8 +229,8 @@ static void dissect_chdr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) /* Header info. First, a top-level header tree item: */ header_item = proto_tree_add_item(chdr_tree, hf_chdr_hdr, tvb, flag_offset, 1, endianness); header_tree = proto_item_add_subtree(header_item, ett_chdr_header); - proto_item_append_text(header_item, ", Packet type: %s", - val_to_str(hdr_bits & 0xD, CHDR_PACKET_TYPES, "Unknown (0x%x)") + proto_item_append_text(header_item, ", Packet type: %s %04x", + val_to_str(hdr_bits & 0xD, CHDR_PACKET_TYPES, "Unknown (0x%x)"), hdr_bits ); /* Let us query hdr.type */ proto_tree_add_string( @@ -241,6 +244,7 @@ static void dissect_chdr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) } if (flag_is_resp) { proto_tree_add_boolean(header_tree, hf_chdr_error, tvb, flag_offset, 1, flag_is_error); + /*proto_tree_add_boolean(header_tree, hf_chdr_error, tvb, flag_offset, 1, true);*/ } /* These lines add sequence, packet_size and stream ID */ @@ -251,56 +255,59 @@ static void dissect_chdr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) /* stream id can be broken down to 4 sections. these are collapsed in a subtree */ stream_item = proto_tree_add_item(chdr_tree, hf_chdr_stream_id, tvb, 4, 4, endianness); stream_tree = proto_item_add_subtree(stream_item, ett_chdr_id); - proto_tree_add_item(stream_tree, hf_chdr_src_dev, tvb, id_pos[0], 1, ENC_NA); - proto_tree_add_item(stream_tree, hf_chdr_src_ep, tvb, id_pos[1], 1, ENC_NA); - proto_tree_add_item(stream_tree, hf_chdr_dst_dev, tvb, id_pos[2], 1, ENC_NA); - proto_tree_add_item(stream_tree, hf_chdr_dst_ep, tvb, id_pos[3], 1, ENC_NA); + proto_tree_add_item(stream_tree, hf_chdr_src_dev, tvb, 4+id_pos[0], 1, ENC_NA); + proto_tree_add_item(stream_tree, hf_chdr_src_ep, tvb, 4+id_pos[1], 1, ENC_NA); + proto_tree_add_item(stream_tree, hf_chdr_dst_dev, tvb, 4+id_pos[2], 1, ENC_NA); + proto_tree_add_item(stream_tree, hf_chdr_dst_ep, tvb, 4+id_pos[3], 1, ENC_NA); /* Block ports (only add them if address points to a device) */ - bytes = tvb_get_string(wmem_packet_scope(), tvb, 0, 8); - if (bytes[id_pos[0]] != 0) { - proto_tree_add_item(stream_tree, hf_chdr_src_blockport, tvb, id_pos[1], 1, ENC_NA); + guint32 sid = tvb_get_ntohl(tvb, 4); + guint8* sid_bytes = (guint8*) &sid; + if (sid_bytes[3] != 0) { + proto_tree_add_item(stream_tree, hf_chdr_src_blockport, tvb, 4+2, 1, ENC_NA); } - if (bytes[id_pos[2]] != 0) { - proto_tree_add_item(stream_tree, hf_chdr_dst_blockport, tvb, id_pos[3], 1, ENC_NA); + if (sid_bytes[1] != 0) { + proto_tree_add_item(stream_tree, hf_chdr_dst_blockport, tvb, 4+0, 1, ENC_NA); } /* Append SID in sid_t hex format */ proto_item_append_text(stream_item, " (%02X:%02X>%02X:%02X)", - bytes[id_pos[0]], - bytes[id_pos[1]], - bytes[id_pos[2]], - bytes[id_pos[3]] + sid_bytes[3], + sid_bytes[2], + sid_bytes[1], + sid_bytes[0] ); + /*proto_item_append_text(stream_item, "%08X", sid);*/ + /* if has_time flag is present interpret timestamp */ if ((flag_has_time) && (len >= 16)){ if (is_network) item = proto_tree_add_item(chdr_tree, hf_chdr_timestamp, tvb, 8, 8, endianness); else{ - bytes = (guint8*) tvb_get_string(wmem_packet_scope(), tvb, 8, sizeof(unsigned long long)); + bytes = (guint8*) tvb_get_string_enc(wmem_packet_scope(), tvb, 8, sizeof(unsigned long long), ENC_ASCII); timestamp = get_timestamp(bytes, sizeof(unsigned long long)); proto_tree_add_uint64(chdr_tree, hf_chdr_timestamp, tvb, 8, 8, timestamp); } } - int remaining_bytes = (len - chdr_size); + int remaining_bytes = (len - header_size); int show_raw_payload = (remaining_bytes > 0); if (flag_is_cmd && remaining_bytes == 8) { - cmd_item = proto_tree_add_item(chdr_tree, hf_chdr_cmd, tvb, chdr_size, 8, endianness); + cmd_item = proto_tree_add_item(chdr_tree, hf_chdr_cmd, tvb, header_size, 8, endianness); cmd_tree = proto_item_add_subtree(cmd_item, ett_chdr_cmd); - proto_tree_add_item(cmd_tree, hf_chdr_cmd_address, tvb, chdr_size, 4, endianness); - proto_tree_add_item(cmd_tree, hf_chdr_cmd_value, tvb, chdr_size + 4, 4, endianness); + proto_tree_add_item(cmd_tree, hf_chdr_cmd_address, tvb, header_size, 4, endianness); + proto_tree_add_item(cmd_tree, hf_chdr_cmd_value, tvb, header_size + 4, 4, endianness); } else if (flag_is_resp) { - response_item = proto_tree_add_item(chdr_tree, hf_chdr_ext_response, tvb, chdr_size, 8, endianness); + response_item = proto_tree_add_item(chdr_tree, hf_chdr_ext_response, tvb, header_size, 8, endianness); response_tree = proto_item_add_subtree(response_item, ett_chdr_response); - proto_tree_add_item(response_tree, hf_chdr_ext_status_code, tvb, chdr_size, 4, endianness); + proto_tree_add_item(response_tree, hf_chdr_ext_status_code, tvb, header_size, 4, endianness); /* This will show the 12-bits of sequence ID in the last 2 bytes */ - proto_tree_add_item(response_tree, hf_chdr_ext_seq_num, tvb, (chdr_size + 4 + (is_network ? 2 : 0)), 2, endianness); + proto_tree_add_item(response_tree, hf_chdr_ext_seq_num, tvb, (header_size + 4 + (is_network ? 2 : 0)), 2, endianness); } else if (show_raw_payload) { - proto_tree_add_item(chdr_tree, hf_chdr_payload, tvb, chdr_size, -1, ENC_NA); + proto_tree_add_item(chdr_tree, hf_chdr_payload, tvb, header_size, -1, ENC_NA); } } } @@ -323,7 +330,7 @@ void proto_register_chdr(void) "Packet Type", HFILL } }, { &hf_chdr_has_time, - { "Time present", "chdr.hdr.has_time", + { "Has time", "chdr.hdr.has_time", FT_BOOLEAN, BASE_NONE, NULL, 0x20, NULL, HFILL } |