From 70eae1d242a9530cab4efa927bd1331b099fdd00 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Thu, 5 Aug 2010 11:48:41 -0700 Subject: usrp1: Add FX2 firmware files These firmware files for the usrp1 are imported from GNURadio. --- firmware/fx2/.gitignore | 25 + firmware/fx2/AUTHORS | 0 firmware/fx2/COPYING | 674 +++++++++++++++++++++++++ firmware/fx2/ChangeLog | 0 firmware/fx2/Makefile.am | 22 + firmware/fx2/Makefile.common | 122 +++++ firmware/fx2/NEWS | 0 firmware/fx2/README | 0 firmware/fx2/bootstrap | 30 ++ firmware/fx2/config/.gitignore | 15 + firmware/fx2/config/Makefile.am | 49 ++ firmware/fx2/config/gr_git.m4 | 58 +++ firmware/fx2/config/gr_lib64.m4 | 85 ++++ firmware/fx2/config/gr_no_undefined.m4 | 44 ++ firmware/fx2/config/gr_pwin32.m4 | 149 ++++++ firmware/fx2/config/gr_python.m4 | 172 +++++++ firmware/fx2/config/gr_scripting.m4 | 26 + firmware/fx2/config/gr_standalone.m4 | 116 +++++ firmware/fx2/config/grc_build.m4 | 287 +++++++++++ firmware/fx2/config/grc_fx2.m4 | 58 +++ firmware/fx2/config/lf_cc.m4 | 41 ++ firmware/fx2/config/lf_cxx.m4 | 67 +++ firmware/fx2/config/lf_warnings.m4 | 121 +++++ firmware/fx2/config/mkstemp.m4 | 89 ++++ firmware/fx2/config/onceonly.m4 | 63 +++ firmware/fx2/config/pkg.m4 | 201 ++++++++ firmware/fx2/config/usrp_sdcc.m4 | 75 +++ firmware/fx2/configure.ac | 335 +++++++++++++ firmware/fx2/include/.gitignore | 25 + firmware/fx2/include/Makefile.am | 61 +++ firmware/fx2/include/delay.h | 38 ++ firmware/fx2/include/fpga_regs0.h | 42 ++ firmware/fx2/include/fpga_regs_common.h | 150 ++++++ firmware/fx2/include/fpga_regs_common.v | 117 +++++ firmware/fx2/include/fpga_regs_standard.h | 300 +++++++++++ firmware/fx2/include/fpga_regs_standard.v | 256 ++++++++++ firmware/fx2/include/fx2regs.h | 716 +++++++++++++++++++++++++++ firmware/fx2/include/fx2utils.h | 31 ++ firmware/fx2/include/generate_regs.py | 57 +++ firmware/fx2/include/i2c.h | 32 ++ firmware/fx2/include/isr.h | 172 +++++++ firmware/fx2/include/syncdelay.h | 65 +++ firmware/fx2/include/timer.h | 35 ++ firmware/fx2/include/usb_common.h | 37 ++ firmware/fx2/include/usb_descriptors.h | 40 ++ firmware/fx2/include/usb_requests.h | 88 ++++ firmware/fx2/include/usrp_commands.h | 99 ++++ firmware/fx2/include/usrp_config.h | 44 ++ firmware/fx2/include/usrp_i2c_addr.h | 78 +++ firmware/fx2/include/usrp_ids.h | 68 +++ firmware/fx2/include/usrp_interfaces.h | 47 ++ firmware/fx2/include/usrp_spi_defs.h | 86 ++++ firmware/fx2/lib/.gitignore | 18 + firmware/fx2/lib/Makefile.am | 79 +++ firmware/fx2/lib/delay.c | 76 +++ firmware/fx2/lib/fx2utils.c | 54 ++ firmware/fx2/lib/i2c-compiler-bug.c | 129 +++++ firmware/fx2/lib/i2c.c | 123 +++++ firmware/fx2/lib/isr.c | 167 +++++++ firmware/fx2/lib/timer.c | 49 ++ firmware/fx2/lib/usb_common.c | 386 +++++++++++++++ firmware/fx2/src/.gitignore | 17 + firmware/fx2/src/Makefile.am | 22 + firmware/fx2/src/common/.gitignore | 17 + firmware/fx2/src/common/Makefile.am | 50 ++ firmware/fx2/src/common/_startup.a51 | 80 +++ firmware/fx2/src/common/_startup.a51.brittle | 78 +++ firmware/fx2/src/common/blink_leds.c | 36 ++ firmware/fx2/src/common/build_eeprom.py | 182 +++++++ firmware/fx2/src/common/check_mdelay.c | 37 ++ firmware/fx2/src/common/check_udelay.c | 37 ++ firmware/fx2/src/common/edit-gpif | 114 +++++ firmware/fx2/src/common/fpga.h | 31 ++ firmware/fx2/src/common/fpga_load.c | 193 ++++++++ firmware/fx2/src/common/fpga_load.h | 28 ++ firmware/fx2/src/common/gpif.c | 292 +++++++++++ firmware/fx2/src/common/gpif.gpf | Bin 0 -> 5281 bytes firmware/fx2/src/common/init_gpif.c | 59 +++ firmware/fx2/src/common/usrp_common.c | 109 ++++ firmware/fx2/src/common/usrp_globals.h | 32 ++ firmware/fx2/src/common/vectors.a51 | 180 +++++++ firmware/fx2/src/usrp1/.gitignore | 20 + firmware/fx2/src/usrp1/Makefile.am | 171 +++++++ firmware/fx2/src/usrp1/_startup.a51 | 1 + firmware/fx2/src/usrp1/blink_leds.c | 1 + firmware/fx2/src/usrp1/board_specific.c | 113 +++++ firmware/fx2/src/usrp1/check_mdelay.c | 1 + firmware/fx2/src/usrp1/check_udelay.c | 1 + firmware/fx2/src/usrp1/edit-gpif | 114 +++++ firmware/fx2/src/usrp1/eeprom_boot.a51 | 573 +++++++++++++++++++++ firmware/fx2/src/usrp1/eeprom_init.c | 116 +++++ firmware/fx2/src/usrp1/eeprom_io.c | 65 +++ firmware/fx2/src/usrp1/eeprom_io.h | 38 ++ firmware/fx2/src/usrp1/fpga_load.c | 1 + firmware/fx2/src/usrp1/fpga_rev2.c | 122 +++++ firmware/fx2/src/usrp1/fpga_rev2.h | 58 +++ firmware/fx2/src/usrp1/gpif.c | 292 +++++++++++ firmware/fx2/src/usrp1/gpif.gpf | Bin 0 -> 5341 bytes firmware/fx2/src/usrp1/init_gpif.c | 1 + firmware/fx2/src/usrp1/spi.c | 381 ++++++++++++++ firmware/fx2/src/usrp1/spi.h | 43 ++ firmware/fx2/src/usrp1/usb_descriptors.a51 | 404 +++++++++++++++ firmware/fx2/src/usrp1/usrp_common.c | 1 + firmware/fx2/src/usrp1/usrp_common.h | 77 +++ firmware/fx2/src/usrp1/usrp_main.c | 380 ++++++++++++++ firmware/fx2/src/usrp1/usrp_rev2_regs.h | 163 ++++++ firmware/fx2/src/usrp1/vectors.a51 | 1 + 107 files changed, 11421 insertions(+) create mode 100644 firmware/fx2/.gitignore create mode 100644 firmware/fx2/AUTHORS create mode 100644 firmware/fx2/COPYING create mode 100644 firmware/fx2/ChangeLog create mode 100644 firmware/fx2/Makefile.am create mode 100644 firmware/fx2/Makefile.common create mode 100644 firmware/fx2/NEWS create mode 100644 firmware/fx2/README create mode 100755 firmware/fx2/bootstrap create mode 100644 firmware/fx2/config/.gitignore create mode 100644 firmware/fx2/config/Makefile.am create mode 100644 firmware/fx2/config/gr_git.m4 create mode 100644 firmware/fx2/config/gr_lib64.m4 create mode 100644 firmware/fx2/config/gr_no_undefined.m4 create mode 100644 firmware/fx2/config/gr_pwin32.m4 create mode 100644 firmware/fx2/config/gr_python.m4 create mode 100644 firmware/fx2/config/gr_scripting.m4 create mode 100644 firmware/fx2/config/gr_standalone.m4 create mode 100644 firmware/fx2/config/grc_build.m4 create mode 100644 firmware/fx2/config/grc_fx2.m4 create mode 100644 firmware/fx2/config/lf_cc.m4 create mode 100644 firmware/fx2/config/lf_cxx.m4 create mode 100644 firmware/fx2/config/lf_warnings.m4 create mode 100644 firmware/fx2/config/mkstemp.m4 create mode 100644 firmware/fx2/config/onceonly.m4 create mode 100644 firmware/fx2/config/pkg.m4 create mode 100644 firmware/fx2/config/usrp_sdcc.m4 create mode 100644 firmware/fx2/configure.ac create mode 100644 firmware/fx2/include/.gitignore create mode 100644 firmware/fx2/include/Makefile.am create mode 100644 firmware/fx2/include/delay.h create mode 100644 firmware/fx2/include/fpga_regs0.h create mode 100644 firmware/fx2/include/fpga_regs_common.h create mode 100644 firmware/fx2/include/fpga_regs_common.v create mode 100644 firmware/fx2/include/fpga_regs_standard.h create mode 100644 firmware/fx2/include/fpga_regs_standard.v create mode 100644 firmware/fx2/include/fx2regs.h create mode 100644 firmware/fx2/include/fx2utils.h create mode 100755 firmware/fx2/include/generate_regs.py create mode 100644 firmware/fx2/include/i2c.h create mode 100644 firmware/fx2/include/isr.h create mode 100644 firmware/fx2/include/syncdelay.h create mode 100644 firmware/fx2/include/timer.h create mode 100644 firmware/fx2/include/usb_common.h create mode 100644 firmware/fx2/include/usb_descriptors.h create mode 100644 firmware/fx2/include/usb_requests.h create mode 100644 firmware/fx2/include/usrp_commands.h create mode 100644 firmware/fx2/include/usrp_config.h create mode 100644 firmware/fx2/include/usrp_i2c_addr.h create mode 100644 firmware/fx2/include/usrp_ids.h create mode 100644 firmware/fx2/include/usrp_interfaces.h create mode 100644 firmware/fx2/include/usrp_spi_defs.h create mode 100644 firmware/fx2/lib/.gitignore create mode 100644 firmware/fx2/lib/Makefile.am create mode 100644 firmware/fx2/lib/delay.c create mode 100644 firmware/fx2/lib/fx2utils.c create mode 100644 firmware/fx2/lib/i2c-compiler-bug.c create mode 100644 firmware/fx2/lib/i2c.c create mode 100644 firmware/fx2/lib/isr.c create mode 100644 firmware/fx2/lib/timer.c create mode 100644 firmware/fx2/lib/usb_common.c create mode 100644 firmware/fx2/src/.gitignore create mode 100644 firmware/fx2/src/Makefile.am create mode 100644 firmware/fx2/src/common/.gitignore create mode 100644 firmware/fx2/src/common/Makefile.am create mode 100644 firmware/fx2/src/common/_startup.a51 create mode 100644 firmware/fx2/src/common/_startup.a51.brittle create mode 100644 firmware/fx2/src/common/blink_leds.c create mode 100755 firmware/fx2/src/common/build_eeprom.py create mode 100644 firmware/fx2/src/common/check_mdelay.c create mode 100644 firmware/fx2/src/common/check_udelay.c create mode 100755 firmware/fx2/src/common/edit-gpif create mode 100644 firmware/fx2/src/common/fpga.h create mode 100644 firmware/fx2/src/common/fpga_load.c create mode 100644 firmware/fx2/src/common/fpga_load.h create mode 100755 firmware/fx2/src/common/gpif.c create mode 100755 firmware/fx2/src/common/gpif.gpf create mode 100644 firmware/fx2/src/common/init_gpif.c create mode 100644 firmware/fx2/src/common/usrp_common.c create mode 100644 firmware/fx2/src/common/usrp_globals.h create mode 100644 firmware/fx2/src/common/vectors.a51 create mode 100644 firmware/fx2/src/usrp1/.gitignore create mode 100644 firmware/fx2/src/usrp1/Makefile.am create mode 100644 firmware/fx2/src/usrp1/_startup.a51 create mode 100644 firmware/fx2/src/usrp1/blink_leds.c create mode 100644 firmware/fx2/src/usrp1/board_specific.c create mode 100644 firmware/fx2/src/usrp1/check_mdelay.c create mode 100644 firmware/fx2/src/usrp1/check_udelay.c create mode 100755 firmware/fx2/src/usrp1/edit-gpif create mode 100644 firmware/fx2/src/usrp1/eeprom_boot.a51 create mode 100644 firmware/fx2/src/usrp1/eeprom_init.c create mode 100644 firmware/fx2/src/usrp1/eeprom_io.c create mode 100644 firmware/fx2/src/usrp1/eeprom_io.h create mode 100644 firmware/fx2/src/usrp1/fpga_load.c create mode 100644 firmware/fx2/src/usrp1/fpga_rev2.c create mode 100644 firmware/fx2/src/usrp1/fpga_rev2.h create mode 100644 firmware/fx2/src/usrp1/gpif.c create mode 100755 firmware/fx2/src/usrp1/gpif.gpf create mode 100644 firmware/fx2/src/usrp1/init_gpif.c create mode 100644 firmware/fx2/src/usrp1/spi.c create mode 100644 firmware/fx2/src/usrp1/spi.h create mode 100644 firmware/fx2/src/usrp1/usb_descriptors.a51 create mode 100644 firmware/fx2/src/usrp1/usrp_common.c create mode 100644 firmware/fx2/src/usrp1/usrp_common.h create mode 100644 firmware/fx2/src/usrp1/usrp_main.c create mode 100644 firmware/fx2/src/usrp1/usrp_rev2_regs.h create mode 100644 firmware/fx2/src/usrp1/vectors.a51 diff --git a/firmware/fx2/.gitignore b/firmware/fx2/.gitignore new file mode 100644 index 000000000..75bb241c8 --- /dev/null +++ b/firmware/fx2/.gitignore @@ -0,0 +1,25 @@ +/Makefile +/Makefile.in +/aclocal.m4 +/configure +/config.h.in +/stamp-h.in +/libtool +/config.log +/config.h +/config.cache +/config.status +/missing +/stamp-h +/stamp-h1 +/.la +/.lo +/.deps +/.libs +/*.la +/*.lo +/autom4te.cache +/*.cache +/missing +/make.log +/usrp.pc diff --git a/firmware/fx2/AUTHORS b/firmware/fx2/AUTHORS new file mode 100644 index 000000000..e69de29bb diff --git a/firmware/fx2/COPYING b/firmware/fx2/COPYING new file mode 100644 index 000000000..94a9ed024 --- /dev/null +++ b/firmware/fx2/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/firmware/fx2/ChangeLog b/firmware/fx2/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/firmware/fx2/Makefile.am b/firmware/fx2/Makefile.am new file mode 100644 index 000000000..9c0da3573 --- /dev/null +++ b/firmware/fx2/Makefile.am @@ -0,0 +1,22 @@ +# +# Copyright 2003 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +SUBDIRS = include lib src diff --git a/firmware/fx2/Makefile.common b/firmware/fx2/Makefile.common new file mode 100644 index 000000000..fb83b9470 --- /dev/null +++ b/firmware/fx2/Makefile.common @@ -0,0 +1,122 @@ +# -*- Makefile -*- +# +# Copyright 2004,2006,2007,2008,2009,2010 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +AM_CFLAGS = @autoconf_default_CFLAGS@ @lf_CFLAGS@ +AM_CXXFLAGS = @autoconf_default_CXXFLAGS@ @lf_CXXFLAGS@ + +# Sets ABI version in SONAME and appends -LIBVER to filename +LTVERSIONFLAGS = -version-info 0:0:0 -release $(LIBVER) + +# includes +grincludedir = $(includedir)/gnuradio + +if PYTHON +# swig includes +swigincludedir = $(grincludedir)/swig + +# Install the gnuradio stuff in the appropriate subdirectory +# This usually ends up at: +# ${prefix}/lib/python${python_version}/site-packages/gnuradio + +grpythondir = $(pythondir)/gnuradio +grpyexecdir = $(pyexecdir)/gnuradio + +# Install the non-gnuradio usrp stuff in the appropriate subdirectory +# This usually ends up at: +# ${prefix}/lib/python${python_version}/site-packages/usrpm + +usrppythondir = $(pythondir)/usrpm +usrppyexecdir = $(pyexecdir)/usrpm +endif + +# gcell includes +gcellincludedir = $(includedir)/gcell +gcellspuincludedir = $(includedir)/gcell/spu + +# Cell spu libs +libspudir = $(libdir)spu + +# This used to be set in configure.ac but is now defined here for all +# Makefiles when this fragment is included. +STD_DEFINES_AND_INCLUDES = $(DEFINES) $(BOOST_CPPFLAGS) \ + $(GNURADIO_INCLUDES) $(GRUEL_INCLUDES) + +# when including for compilation from pre-installed libraries and such, +# need to make sure those are put last on the compile command +WITH_INCLUDES = @with_INCLUDES@ +WITH_SWIG_INCLUDES = @with_SWIG_INCLUDES@ + +# Where to find gnuradio include files in the current build tree +# top_srcdir for original stuff, top_builddir for generated files +GNURADIO_INCLUDES = @gnuradio_core_INCLUDES@ + +# How to link in GNU Radio core library from inside the tree +GNURADIO_CORE_LA = @gnuradio_core_LA@ + +# How to link in the USRP library from inside the tree +GRUEL_INCLUDES = @gruel_INCLUDES@ +GRUEL_LA = @gruel_LA@ + +# How to link in the USRP library from inside the tree +USRP_INCLUDES = @usrp_INCLUDES@ +USRP_LA = @usrp_LA@ + +# How to link the gcell library from inside the tree (the PPU part) +GCELL_INCLUDES = @gcell_INCLUDES@ +GCELL_LA = @gcell_LA@ + +# How to link the gcell library from inside the tree (the SPU part) +GCELL_SPU_INCLUDES = @gcell_spu_INCLUDES@ +GCELL_SPU_LA = @gcell_spu_LA@ + +# libtool aware wrapper for ppu-embedspu +GCELL_EMBEDSPU_LIBTOOL = @abs_top_srcdir@/gcell/lib/runtime/gcell-embedspu-libtool + +# Fix for BSD make not defining $(RM). We define it now in configure.ac +# using AM_PATH_PROG, but now here have to add a -f to be like GNU make +RM=$(RM_PROG) -f + +RUN_GUILE = GUILE_LOAD_PATH="@abs_top_srcdir@/gruel/src/scheme" @GUILE@ -e main -s + +# Base directory for example applications +exampledir = $(datadir)/gnuradio/examples + +# Base directory for documentation (docdir undefined in autoconf < 1.60) +docdir ?= $(datadir)/doc/$(PACKAGE) +gr_docdir = $(docdir)-$(DOCVER) + +# System configuration files +gr_prefsdir = $(GR_PREFSDIR) + +# Data directory for grc block wrappers +grc_blocksdir = $(pkgdatadir)/grc/blocks + +# Other common defines; use "+=" to add to these +STAMPS = +MOSTLYCLEANFILES = $(BUILT_SOURCES) $(STAMPS) *.pyc *.pyo *~ *.tmp *.loT + +# Don't distribute the files defined in the variable 'no_dist_files' +dist-hook: + @for file in $(no_dist_files); do \ + echo $(RM) $(distdir)/$$file; \ + $(RM) $(distdir)/$$file; \ + done; diff --git a/firmware/fx2/NEWS b/firmware/fx2/NEWS new file mode 100644 index 000000000..e69de29bb diff --git a/firmware/fx2/README b/firmware/fx2/README new file mode 100644 index 000000000..e69de29bb diff --git a/firmware/fx2/bootstrap b/firmware/fx2/bootstrap new file mode 100755 index 000000000..7daff90d1 --- /dev/null +++ b/firmware/fx2/bootstrap @@ -0,0 +1,30 @@ +#!/bin/sh + +# Copyright 2001,2005,2008 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + + +rm -fr config.cache autom4te*.cache + +aclocal -I config +autoconf +autoheader +libtoolize --automake +automake --add-missing -Wno-portability -Wno-override -Wnone +#automake --add-missing -Wno-portability diff --git a/firmware/fx2/config/.gitignore b/firmware/fx2/config/.gitignore new file mode 100644 index 000000000..16f775e32 --- /dev/null +++ b/firmware/fx2/config/.gitignore @@ -0,0 +1,15 @@ +/*.cache +/*.la +/*.lo +/*.pc +/.deps +/.la +/.libs +/.lo +/Makefile +/Makefile.in +/libtool.m4 +/lt~obsolete.m4 +/ltsugar.m4 +/ltversion.m4 +/ltoptions.m4 diff --git a/firmware/fx2/config/Makefile.am b/firmware/fx2/config/Makefile.am new file mode 100644 index 000000000..487ceed1b --- /dev/null +++ b/firmware/fx2/config/Makefile.am @@ -0,0 +1,49 @@ +# +# Copyright 2001,2006,2008,2009,2010 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +include $(top_srcdir)/Makefile.common + +# Install m4 macros in this directory +m4datadir = $(datadir)/aclocal + +# List your m4 macros here +m4macros = \ + grc_build.m4 \ + grc_fx2.m4 \ + gr_git.m4 \ + gr_lib64.m4 \ + gr_no_undefined.m4 \ + gr_pwin32.m4 \ + gr_python.m4 \ + gr_require_mc4020.m4 \ + gr_scripting.m4 \ + gr_set_md_cpu.m4 \ + gr_standalone.m4 \ + lf_cc.m4 \ + lf_cxx.m4 \ + lf_warnings.m4 \ + lf_x11.m4 \ + mkstemp.m4 \ + onceonly.m4 \ + pkg.m4 \ + usrp_sdcc.m4 + +EXTRA_DIST = $(m4macros) diff --git a/firmware/fx2/config/gr_git.m4 b/firmware/fx2/config/gr_git.m4 new file mode 100644 index 000000000..5e8aa663b --- /dev/null +++ b/firmware/fx2/config/gr_git.m4 @@ -0,0 +1,58 @@ +dnl Copyright 2009,2010 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, +dnl Boston, MA 02110-1301, USA. + + +AC_DEFUN([GR_GIT],[ + dnl Identify git binary + AC_PATH_PROG([GIT],[git]) + + dnl If it exists, get either 'git describe' or fallback to current commit + if test x$GIT != x ; then + AC_MSG_CHECKING([existence of git version control directory]) + if test -d $srcdir/.git ; then + AC_MSG_RESULT([ok]) + AC_MSG_CHECKING([git description of current commit]) + if (cd $srcdir && $GIT describe >/dev/null 2>&1); then + GIT_DESCRIBE=`cd $srcdir && $GIT describe --abbrev=8 --long` + GIT_TAG=`echo $GIT_DESCRIBE | cut -f 1 -d '-'` + GIT_SEQNO=`echo $GIT_DESCRIBE | cut -f 2 -d '-'` + GIT_COMMIT=`echo $GIT_DESCRIBE | cut -f 3 -d '-' | cut -f 2- -d 'g'` + # Release candidate tags create an extra -rcX field + if test x`echo $GIT_DESCRIBE | cut -f 1- -d '-' --output-delimiter=' ' | wc -w` = x4; then + GIT_TAG=`echo $GIT_DESCRIBE | cut -f -2 -d '-'` + GIT_SEQNO=`echo $GIT_DESCRIBE | cut -f 3 -d '-'` + GIT_COMMIT=`echo $GIT_DESCRIBE | cut -f 4 -d '-' | cut -f 2- -d 'g'` + fi + AC_MSG_RESULT([$GIT_DESCRIBE]) + else + AC_MSG_RESULT([unable to find, using current commit]) + GIT_TAG='' + GIT_SEQNO='' + GIT_COMMIT=`cd $srcdir && $GIT describe --always --abbrev=8` + fi + else + AC_MSG_RESULT([not found]) + fi + + AC_SUBST([GIT_DESCRIBE]) + AC_SUBST([GIT_TAG]) + AC_SUBST([GIT_SEQNO]) + AC_SUBST([GIT_COMMIT]) + fi +]) diff --git a/firmware/fx2/config/gr_lib64.m4 b/firmware/fx2/config/gr_lib64.m4 new file mode 100644 index 000000000..751f774b4 --- /dev/null +++ b/firmware/fx2/config/gr_lib64.m4 @@ -0,0 +1,85 @@ +dnl +dnl Copyright 2005,2008 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, +dnl Boston, MA 02110-1301, USA. +dnl + +dnl GR_LIB64() +dnl +dnl Checks to see if we're on a x86_64 or powerpc64 machine, and if so, determine +dnl if libdir should end in "64" or not. +dnl +dnl Sets gr_libdir_suffix to "" or "64" and calls AC_SUBST(gr_libdir_suffix) +dnl May append "64" to libdir. +dnl +dnl The current heuristic is: +dnl if the host_cpu isn't x86_64 or powerpc64, then "" +dnl if the host_os isn't linux, then "" +dnl if we're cross-compiling, ask the linker, by way of the selected compiler +dnl if we're x86_64 and there's a /lib64 and it's not a symlink, then "64", else "" +dnl else ask the compiler +dnl +AC_DEFUN([GR_LIB64],[ + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([AC_PROG_CXX]) + + AC_MSG_CHECKING([gr_libdir_suffix]) + gr_libdir_suffix="" + AC_SUBST(gr_libdir_suffix) + + case "$host_os" in + linux*) is_linux=yes ;; + *) is_linux=no ;; + esac + + if test "$is_linux" = no || test "$host_cpu" != "x86_64" && test "$host_cpu" != "powerpc64"; then + gr_libdir_suffix="" + elif test "$cross_compiling" = yes; then + _GR_LIB64_ASK_COMPILER + elif test "$host_cpu" = "x86_64"; then + if test -d /lib64 && test ! -L /lib64; then + gr_libdir_suffix=64 + fi + else + _GR_LIB64_ASK_COMPILER + fi + AC_MSG_RESULT([$gr_libdir_suffix]) + + + AC_MSG_CHECKING([whether to append 64 to libdir]) + t=${libdir##*/lib} + if test "$t" != 64 && test "$gr_libdir_suffix" = "64"; then + libdir=${libdir}64 + AC_MSG_RESULT([yes. Setting libdir to $libdir]) + else + AC_MSG_RESULT([no]) + fi +]) + +dnl If we're using g++, extract the first SEARCH_DIR("...") entry from the linker script +dnl and see if it contains a suffix after the final .../lib part of the path. +dnl (This works because the linker script varies depending on whether we're generating +dnl 32-bit or 64-bit executables) +dnl +AC_DEFUN([_GR_LIB64_ASK_COMPILER],[ + if test "$ac_cv_cxx_compiler_gnu" = "yes"; + then + gr_libdir_suffix=`$CXX -Wl,--verbose 2>/dev/null | sed -n -e '/SEARCH_DIR/{s/;.*$//; s,^.*/,,; s/".*$//; s/^lib//; p}'` + fi +]) + diff --git a/firmware/fx2/config/gr_no_undefined.m4 b/firmware/fx2/config/gr_no_undefined.m4 new file mode 100644 index 000000000..c8d745d5f --- /dev/null +++ b/firmware/fx2/config/gr_no_undefined.m4 @@ -0,0 +1,44 @@ +dnl +dnl Copyright 2005 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, +dnl Boston, MA 02110-1301, USA. +dnl + +# GR_NO_UNDEFINED() +# +# Detemine whether we need to use the -no-undefined linker flag +# when building shared libraries. +# Sets NO_UNDEFINED to "" or "-no-undefined" +# +# As far as I can tell, we need -no-undefined only when building +# windows DLLs. This occurs when using MinGW and Cygwin. +# +# For now, we stub this out. + +AC_DEFUN([GR_NO_UNDEFINED],[ + AC_REQUIRE([AC_CANONICAL_HOST]) + no_undefined="" + case "${host_os}" in + *mingw* | *cygwin*) + + # on MinGW/Cygwin extra LDFLAGS are required + no_undefined="-no-undefined" + ;; + esac + AC_SUBST(NO_UNDEFINED,[$no_undefined]) +]) diff --git a/firmware/fx2/config/gr_pwin32.m4 b/firmware/fx2/config/gr_pwin32.m4 new file mode 100644 index 000000000..495e9dd4d --- /dev/null +++ b/firmware/fx2/config/gr_pwin32.m4 @@ -0,0 +1,149 @@ +# Check for (mingw)win32 POSIX replacements. -*- Autoconf -*- + +# Copyright 2003,2004,2005 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + + +AC_DEFUN([GR_PWIN32], +[ +AC_REQUIRE([AC_HEADER_TIME]) +AC_CHECK_HEADERS([sys/types.h fcntl.h io.h]) +AC_CHECK_HEADERS([windows.h]) +AC_CHECK_HEADERS([winioctl.h winbase.h], [], [], [ + #if HAVE_WINDOWS_H + #include + #endif +]) + +AC_CHECK_FUNCS([getopt usleep gettimeofday nanosleep rand srand random srandom sleep sigaction]) +AC_CHECK_TYPES([struct timezone, struct timespec, ssize_t],[],[],[ + #if HAVE_SYS_TYPES_H + # include + #endif + #if TIME_WITH_SYS_TIME + # include + # include + #else + # if HAVE_SYS_TIME_H + # include + # else + # include + # endif + #endif +]) + +dnl Checks for replacements +AC_REPLACE_FUNCS([getopt usleep gettimeofday]) + + +AC_MSG_CHECKING(for Sleep) +AC_TRY_LINK([ #include + #include + ], [ Sleep(0); ], + [AC_DEFINE(HAVE_SSLEEP,1,[Define to 1 if you have win32 Sleep]) + AC_MSG_RESULT(yes)], + AC_MSG_RESULT(no) + ) + +dnl Under Win32, mkdir prototype in io.h has only one arg +AC_MSG_CHECKING(whether mkdir accepts only one arg) +AC_TRY_COMPILE([#include + #include + #include ], [ + mkdir("") + ], [ AC_MSG_RESULT(yes) + AC_DEFINE(MKDIR_TAKES_ONE_ARG,[],[Define if mkdir accepts only one arg]) ], + [ AC_MSG_RESULT(no) + ]) + +AH_BOTTOM( +[ +/* Define missing prototypes, implemented in replacement lib */ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef HAVE_GETOPT +int getopt (int argc, char * const argv[], const char * optstring); +extern char * optarg; +extern int optind, opterr, optopt; +#endif + +#ifndef HAVE_USLEEP +int usleep(unsigned long usec); /* SUSv2 */ +#endif + +#ifndef HAVE_NANOSLEEP +#ifndef HAVE_STRUCT_TIMESPEC +#if HAVE_SYS_TYPES_H +# include /* need time_t */ +#endif +struct timespec { + time_t tv_sec; + long tv_nsec; +}; +#endif +#if HAVE_UNISTD_H +#include +#endif +static inline int nanosleep(const struct timespec *req, struct timespec *rem) { return usleep(req->tv_sec*1000000+req->tv_nsec/1000); } +#endif + +#if defined(HAVE_SSLEEP) && !defined(HAVE_SLEEP) +#ifdef HAVE_WINBASE_H +#include +#include +#endif +/* TODO: what about SleepEx? */ +static inline unsigned int sleep (unsigned int nb_sec) { Sleep(nb_sec*1000); return 0; } +#endif + +#ifndef HAVE_GETTIMEOFDAY +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifndef HAVE_STRUCT_TIMEZONE +struct timezone { + int tz_minuteswest; + int tz_dsttime; +}; +#endif +int gettimeofday(struct timeval *tv, struct timezone *tz); +#endif + +#if !defined(HAVE_RANDOM) && defined(HAVE_RAND) +#include +static inline long int random (void) { return rand(); } +#endif + +#if !defined(HAVE_SRANDOM) && defined(HAVE_SRAND) +static inline void srandom (unsigned int seed) { srand(seed); } +#endif + +#ifndef HAVE_SSIZE_T +typedef size_t ssize_t; +#endif + +#ifdef __cplusplus +} +#endif +]) + + +]) diff --git a/firmware/fx2/config/gr_python.m4 b/firmware/fx2/config/gr_python.m4 new file mode 100644 index 000000000..43ccfc015 --- /dev/null +++ b/firmware/fx2/config/gr_python.m4 @@ -0,0 +1,172 @@ +dnl +dnl Copyright 2003,2004,2005 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, +dnl Boston, MA 02110-1301, USA. +dnl + +# PYTHON_DEVEL() +# +# Checks for Python and tries to get the include path to 'Python.h'. +# It sets the $(PYTHON_CPPFLAGS), $(PYTHON_LDFLAGS) and $(pythondir) output variables, +# +AC_DEFUN([PYTHON_DEVEL],[ + AC_REQUIRE([AM_PATH_PYTHON]) + AC_REQUIRE([AC_CANONICAL_HOST]) + + AC_ARG_WITH(pythondir, + AC_HELP_STRING([--with-pythondir=DIR], + [python installation directory (cross-compiling) [[default=$prefix/lib/python2.5/site-packages]]]), + [with_pythondir=${withval}],[with_pythondir=${prefix}/lib/python2.5/site-packages]) + + # if we're cross-compiling, asking the host python about any of + # this is completely useless... + + if test x$cross_compiling != xno + then + pythondir=$with_pythondir + pyexecdir=$with_pythondir + AC_SUBST(PYTHON_CPPFLAGS) + AC_SUBST(PYTHON_LDFLAGS) + else + + # For Fedora Core 5 and 6, see ticket:39 in Trac + if test -f '/etc/redhat-release'; then + if (echo $pyexecdir | grep -q lib64); then + pythondir="$pyexecdir" + fi + fi + + # Check for Python include path + AC_MSG_CHECKING([for Python include path]) + if test -z "$PYTHON" ; then + AC_MSG_ERROR([cannot find Python path]) + fi + + # ask distutils which include path we should use + python_cmd=' +import distutils.sysconfig +import os +path = distutils.sysconfig.get_python_inc(plat_specific=False) +if os.sep == "\\": + path = path.replace("\\", "/") +print path +' + python_path=`$PYTHON -c "$python_cmd"` + AC_MSG_RESULT([$python_path]) + if test -z "$python_path" ; then + AC_MSG_ERROR([cannot find Python include path]) + fi + + AC_SUBST(PYTHON_CPPFLAGS,[-I$python_path]) + + # Check for Python headers usability + python_save_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $PYTHON_CPPFLAGS" + AC_CHECK_HEADERS([Python.h], [], + [AC_MSG_ERROR([cannot find usable Python headers])]) + CPPFLAGS="$python_save_CPPFLAGS" + + # Only set this on mingw and cygwin hosts, (only implemented + # for mingw host, for crosscompiling you need to trick this) + + PYTHON_LDFLAGS="" + case $host_os in + *mingw* | *cygwin* ) + AC_MSG_CHECKING([for Python LDFLAGS]) + + python_cmd=' +import distutils.sysconfig +import os +path = distutils.sysconfig.get_config_var("LIBPL") +if path == None: + path = distutils.sysconfig.PREFIX + "/libs" +if os.sep == "\\": + path = path.replace("\\", "/") +print path +' + python_stdlib_path=`$PYTHON -c "$python_cmd"` + + python_version_nodot=`echo $PYTHON_VERSION | sed "s,\.,,"` + libpython_name="python$PYTHON_VERSION" + + # Standard install of python for win32 has libpython24.a + # instead of libpython2.4.a so we check for the library + # without the dot in the version number. + + python_stdlib_filename=`find $python_stdlib_path -type f -name libpython$python_version_nodot.* -print | sed "1q"` + if test -n "$python_stdlib_filename" ; then + libpython_name="python$python_version_nodot" + fi + + PYTHON_LDFLAGS="-L$python_stdlib_path -l$libpython_name" + AC_MSG_RESULT($PYTHON_LDFLAGS) + # Replace all backslashes in PYTHON Paths with forward slashes + pythondir=`echo $pythondir |sed 's,\\\\,/,g'` + pkgpythondir=`echo $pkgpythondir |sed 's,\\\\,/,g'` + pyexecdir=`echo $pyexecdir |sed 's,\\\\,/,g'` + pkgpyexecdir=`echo $pkgpyexecdir |sed 's,\\\\,/,g'` + ;; + esac + + case $host_os in + *mingw* ) + # Python 2.5 requires ".pyd" instead of ".dll" for extensions + PYTHON_LDFLAGS="-shrext .pyd ${PYTHON_LDFLAGS}" + esac + + AC_SUBST(PYTHON_LDFLAGS) + fi +]) + +# PYTHON_CHECK_MODULE +# +# Determines if a particular Python module can be imported +# +# $1 - module name +# $2 - module description +# $3 - action if found +# $4 - action if not found +# $5 - test command + +AC_DEFUN([PYTHON_CHECK_MODULE],[ + AC_MSG_CHECKING([for $2]) + dnl ######################################## + dnl # import and test checking + dnl ######################################## + if test "$5"; then + python_cmd=' +try: + import $1 + assert $5 +except: exit(1)' + dnl ######################################## + dnl # import checking only + dnl ######################################## + else + python_cmd=' +try: import $1 +except: exit(1)' + fi + if ! $PYTHON -c "$python_cmd" 2> /dev/null; then + AC_MSG_RESULT([no]) + $4 + else + AC_MSG_RESULT([yes]) + $3 + fi +]) diff --git a/firmware/fx2/config/gr_scripting.m4 b/firmware/fx2/config/gr_scripting.m4 new file mode 100644 index 000000000..2803e975f --- /dev/null +++ b/firmware/fx2/config/gr_scripting.m4 @@ -0,0 +1,26 @@ +dnl +dnl Copyright 2003 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, +dnl Boston, MA 02110-1301, USA. +dnl + +AC_DEFUN([GR_SCRIPTING],[ + AC_REQUIRE([AC_PROG_LN_S]) + AC_REQUIRE([AC_PROG_CXX]) + AC_REQUIRE([AC_PROG_LIBTOOL]) +]) diff --git a/firmware/fx2/config/gr_standalone.m4 b/firmware/fx2/config/gr_standalone.m4 new file mode 100644 index 000000000..370f7fb03 --- /dev/null +++ b/firmware/fx2/config/gr_standalone.m4 @@ -0,0 +1,116 @@ +dnl +dnl Copyright 2008 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License along +dnl with this program; if not, write to the Free Software Foundation, Inc., +dnl 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +dnl + +dnl +dnl GR_STANDALONE([package],[version]) +dnl +dnl Handles the bulk of the configure.ac work for an out-of-tree build +dnl +dnl N.B., this is an m4_define because if it were an AC_DEFUN it would +dnl get called too late to be useful. + +m4_define([GR_STANDALONE], +[ + AC_INIT([$1],[$2]) + AC_PREREQ(2.57) + AC_CONFIG_SRCDIR([config/gr_standalone.m4]) + AC_CONFIG_AUX_DIR([.]) + AM_CONFIG_HEADER(config.h) + + AC_CANONICAL_BUILD + AC_CANONICAL_HOST + AC_CANONICAL_TARGET + + AM_INIT_AUTOMAKE + + LF_CONFIGURE_CC + LF_CONFIGURE_CXX + GR_LIB64 dnl check for lib64 suffix after choosing compilers + + dnl add ${prefix}/lib${gr_libdir_suffix}/pkgconfig to the head of the PKG_CONFIG_PATH + if test x${PKG_CONFIG_PATH} = x; then + PKG_CONFIG_PATH=${prefix}/lib${gr_libdir_suffix}/pkgconfig + else + PKG_CONFIG_PATH=${prefix}/lib${gr_libdir_suffix}/pkgconfig:${PKG_CONFIG_PATH} + fi + export PKG_CONFIG_PATH + + LF_SET_WARNINGS + GR_SET_GPROF + GR_SET_PROF + AM_PROG_AS + AC_PROG_LN_S + AC_PROG_MAKE_SET + AC_PROG_INSTALL + AC_PATH_PROG([RM_PROG], [rm]) + + AC_LIBTOOL_WIN32_DLL + AC_ENABLE_SHARED dnl do build shared libraries + AC_DISABLE_STATIC dnl don't build static libraries + m4_ifdef([LT_INIT],[LT_INIT],[AC_PROG_LIBTOOL]) + dnl GR_FORTRAN + + GR_NO_UNDEFINED dnl do we need the -no-undefined linker flag + GR_SCRIPTING dnl Locate python, SWIG, etc + + AC_ARG_WITH([python], + AC_HELP_STRING([--with-python], [Should we use python? [[default=yes]]]), + [case "$with_python" in + (no | yes) ;; + (*) AC_MSG_ERROR([Invalid argument ($with_python) to --with-python]) ;; + esac], + [with_python=yes]) + + AM_CONDITIONAL([USE_PYTHON], [test "$with_python" = yes]) + + + dnl Set the c++ compiler that we use for the build system when cross compiling + if test "x$CXX_FOR_BUILD" = x + then + CXX_FOR_BUILD=${CXX} + fi + AC_SUBST(CXX_FOR_BUILD) + + dnl Checks for header files. + AC_HEADER_STDC + + dnl Checks for typedefs, structures, and compiler characteristics. + AC_C_CONST + AC_C_INLINE + AC_TYPE_SIZE_T + AC_HEADER_TIME + AC_C_BIGENDIAN + + dnl Check for Mingw support + GR_PWIN32 + + AC_CHECK_PROG([XMLTO],[xmlto],[yes],[]) + AM_CONDITIONAL([HAS_XMLTO], [test x$XMLTO = xyes]) + + dnl Define where to look for cppunit includes and libs + dnl sets CPPUNIT_CFLAGS and CPPUNIT_LIBS + dnl Try using pkg-config first, then fall back to cppunit-config. + PKG_CHECK_EXISTS(cppunit, + [PKG_CHECK_MODULES(CPPUNIT, cppunit >= 1.9.14)], + [AM_PATH_CPPUNIT([1.9.14],[], + [AC_MSG_ERROR([GNU Radio requires cppunit. Stop])])]) + + PKG_CHECK_MODULES(GNURADIO_CORE, gnuradio-core >= 3) +]) diff --git a/firmware/fx2/config/grc_build.m4 b/firmware/fx2/config/grc_build.m4 new file mode 100644 index 000000000..77b59db6b --- /dev/null +++ b/firmware/fx2/config/grc_build.m4 @@ -0,0 +1,287 @@ +dnl Copyright 2006,2008,2009 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, +dnl Boston, MA 02110-1301, USA. + +dnl Create --enable-foo argument for named component, create variables as needed +dnl $1 is component name +AC_DEFUN([GRC_ENABLE], [ + _GRC_ENABLE($1,m4_bpatsubst($1,-,_)) +]) +dnl $2 is the '_'d component name +dnl on exit variable enable_$2 will be set to [yes|no]; +dnl passed will be [yes|no] (same as enable_$2) + +AC_DEFUN([_GRC_ENABLE],[ + passed=yes + AC_ARG_ENABLE([$1], + AC_HELP_STRING([--enable-$1], + [Stop if $1 fails configuration]), + [],[ + [enable_]$2=$enable_all_components + if test x$enable_all_components = xno; then + passed=no + fi + ]) +]) +dnl Component specific configuration +dnl The order of the GR_ macros determines the order of compilation +dnl For -any- checks on $enable_all_components +dnl use the following guildlines: +dnl yes : --enable-all-components was specified, so error out if any +dnl components do not pass configuration checks. +dnl no : --disable-all-components was specified, so try to build the +dnl --enable'd components, and error out if any do not pass +dnl configuration checks. +dnl "" : this option was not specified on the command line; try to +dnl build all components that are not --with'd, but don't +dnl error out if any component does not pass configuration checks. +dnl +dnl For each --enable-foo component, if that flag is not specified on +dnl the command line, the related variable $enable_foo will be set to +dnl $enable_all_components . + +dnl Create --with-foo argument for named compoment, create variables as needed +dnl $1 is component name +dnl $2 is what to do on success +dnl $3 is the PKG_CONFIG name; if not given, then $1 +AC_DEFUN([GRC_WITH], [ + if test [x]$3 = x; then + pc_comp_name="$1" + else + pc_comp_name="$3" + fi + _GRC_WITH($1,[$2],${pc_comp_name},m4_bpatsubst($1,-,_)) +]) +dnl $3 is the pkg-config component name +dnl $4 is the '_'d component name +dnl on exit variable passed will be [yes|no|with]: +dnl yes: if --enable-$1 and/or --enable-all-components was specified, +dnl but --with was not; +dnl with: if --with-$1 was specified, and passed checks; +dnl no: all other conditions +AC_DEFUN([_GRC_WITH],[ + AC_ARG_WITH([$1], + AC_HELP_STRING([--with-$1@<:@=PATH@:>@], + [Use package $1 if installed in PATH (if specified) or PKG_CONFIG_PATH (if PATH not specified); stop if $1 not found]), + [if test "x$withval" != "xyes"; then + [with_]$4[_val]=$withval + [with_]$4=yes + fi], + []) + if test x$[with_]$4 = xyes; then + if test x$[enable_]$4 = xyes; then + AC_MSG_ERROR([Component $1: Cannot use both --enable and --with]) + else + _GRC_WITH_PKG_CONFIG_CHECK($1,$3,$4) + ifelse([$2], , :, [$2]) + fi + fi +]) + +dnl Use 'pkgconfig' to check for a package +dnl $1 is the --with component name +dnl $2 is the pkg-config component name, if provided; otherwise use $1 for this +dnl on success, resulting INCLUDES, INCLUDEDIR, LA, and LIBDIRPATH variables +dnl will be set; on failure, will exit with an error. +AC_DEFUN([GRC_WITH_PKG_CONFIG_CHECK], [ + if test [x]$2 = x; then + pc_comp_name="$1" + else + pc_comp_name="$2" + fi + _GRC_WITH_PKG_CONFIG_CHECK($1,${pc_comp_name},m4_bpatsubst($1,-,_)) +]) +dnl $2 is the pkg-config component name +dnl $3 is the '_'d component name +AC_DEFUN([_GRC_WITH_PKG_CONFIG_CHECK],[ + dnl save PKG_CONFIG_PATH, restore at the end + s_PKG_CONFIG_PATH=$PKG_CONFIG_PATH + + dnl create the PKG_CONFIG_PATH, via this component arg, if provided; + dnl else use the environment PKG_CONFIG_PATH + l_PKG_CONFIG_PATH=$[with_]$3[_val] + if test "x$l_PKG_CONFIG_PATH" != "x"; then + export PKG_CONFIG_PATH=$l_PKG_CONFIG_PATH + + dnl verify that the file exists; if not, no point in continuing + if ! test -r ${l_PKG_CONFIG_PATH}/$2[.pc]; then + AC_MSG_ERROR([Component $1: PKGCONFIG cannot find info for $2, with provided PKG_CONFIG_PATH = @<:@ $l_PKG_CONFIG_PATH @:>@ .]) + fi + fi + + dnl do the check; error out if not found + PKG_CHECK_EXISTS($2, [passed=with; check1=yes], [ + check1=no + dnl pkg-config returned an error; this might be that the .pc + dnl file was not valid, or the Requires: were not met. + dnl If the arg was provided and the input PKG_CONFIG_PATH , then try + dnl again appending the whole PKG_CONFIG_PATH. + if test "x$l_PKG_CONFIG_PATH" != "x"; then + if test "x$s_PKG_CONFIG_PATH" != "x"; then + export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:${s_PKG_CONFIG_PATH} + PKG_CHECK_EXISTS($2, passed=with, passed=no) + fi + fi + if test $passed != with; then + AC_MSG_ERROR([Component $1: PKGCONFIG cannot find info for $2, with PKG_CONFIG_PATH = @<:@ $PKG_CONFIG_PATH @:>@ .]) + fi + dnl pkg-config Requires are now met; save the new PKG_CONFIG_PATH + s_PKG_CONFIG_PATH=$PKG_CONFIG_PATH + ]) + + dnl if PKG_CHECK_EXISTS returned, then this component's .pc file was + dnl found in the provided 'arg' PKG_CONFIG_PATH; + dnl retrieve various parameters + $3[_INCLUDES]=`$PKG_CONFIG --cflags-only-I $2` + $3[_LA]=`$PKG_CONFIG --libs $2` + $3[_INCLUDEDIR]=`$PKG_CONFIG --variable=includedir $2` + + if test x$check1 = xyes; then + dnl prepend the args PKG_CONFIG_PATH to the saved one, if the + dnl saved version was not empty + if test "x$s_PKG_CONFIG_PATH" != "x"; then + export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:${s_PKG_CONFIG_PATH} + fi + fi +]) + +dnl Check the $prefix versus the --with libdirpath for this component +dnl $1 is the prefix +dnl $2 is the --with component name +dnl $3 is the --with component library path +AC_DEFUN([GRC_PREFIX_LDFLAGS],[ + $2[_LIBDIRPATH]=$3 + dnl create LDFLAGS for this --with, if different from the provided $prefix + if test [x]$1[/lib] != [x]$3; then + $2[_LDFLAG]=[-L]$3 + else + $2[_LDFLAG]= + fi +]) + +dnl Check to make sure this dependency is fulfilled for this component +dnl $1 is the component's name +dnl $2 is the component dependency name +dnl On input and exit, $passed will be: +dnl with : if --with passed muster +dnl yes : if --enable passed muster +dnl no : otherwise +dnl If trying --with, will error-out if any dependency was not --with'd +AC_DEFUN([GRC_CHECK_DEPENDENCY],[ +dnl f0=[enable_]m4_bpatsubst($1,-,_) +dnl f1=[$enable_]m4_bpatsubst($1,-,_) +dnl echo +dnl echo "$1 : Checking Dependency $2" +dnl echo "$1 : enable_all_components is '$enable_all_components'" +dnl echo "$1 : $f0 is '$f1'" +dnl echo "$1 : passed is '$passed'" +dnl echo + if test $passed != no; then + if test $passed = yes; then + dnl make sure this dependency was not skipped + if test [x$]m4_bpatsubst($2,-,_)[_skipped] = xyes; then + AC_MSG_RESULT([Component $1 requires $2, which is not being built or specified via pre-installed files.]) + passed=no + fi + else + dnl make sure this dependency was --with'd only; not --enable'd + if test [x$]m4_bpatsubst($2,-,_)[_with] = xno; then + AC_MSG_ERROR([Component $1 requires $2 to be included as --with-$2@<:@=arg@:>@]) + fi + fi + fi +]) + +dnl Check to make sure GUILE is available +dnl $1 is the component name +AC_DEFUN([GRC_CHECK_GUILE],[ + if test x"$GUILE" = x; then + AC_MSG_RESULT([Component $1 requires guile, which was not found.]) + passed=no + fi +]) + +dnl Add the specified "with" list; clear the provided variable +dnl $1 is the component name +dnl $2 is the path list name suffix +dnl $3 is the separator (for paths, ":"; for includes " ") +AC_DEFUN([GRC_ADD_TO_LIST],[ + if test "x${$1[_]$2}" != "x"; then + if test "x$[with_]$2" = "x"; then + [with_]$2="${$1[_]$2}" + else + [with_]$2="${$1[_]$2}"$3"$[with_]$2" + fi + $1[_]$2= + fi +]) + +dnl Conditionally build named component. +dnl $1 is component name +dnl $2 is executed if configuration passes and build is desired +AC_DEFUN([GRC_BUILD_CONDITIONAL],[ + _GRC_BUILD_CONDITIONAL($1, $2, m4_bpatsubst($1,-,_)) +]) +dnl $3=m4_bpatsubst($1,-,_) +dnl Use $passed=no to indicate configuration failure; +dnl Use $passed=with to indicate the use of pre-installed libraries and headers; +dnl Any other value of $passed, including blank, assumes success; +dnl Defines $3_with=[yes|no] depending on if $passed=with or not (respectively) +dnl Defines $3_skipped=[yes|no] depending on if $passed=no or not (respectively) +AC_DEFUN([_GRC_BUILD_CONDITIONAL],[ + $3[_with]=no + if test $passed = no; then + if test x$[enable_]$3 = xyes; then + AC_MSG_ERROR([Component $1 has errors; stopping.]) + else + AC_MSG_RESULT([Not building component $1.]) + fi + else + if test $passed = with; then + with_dirs="$with_dirs $1" + GRC_ADD_TO_LIST($3, INCLUDES, " ") + GRC_ADD_TO_LIST($3, SWIG_INCLUDES, " ") + GRC_ADD_TO_LIST($3, PYDIRPATH, ":") + GRC_ADD_TO_LIST($3, SWIGDIRPATH, ":") + GRC_ADD_TO_LIST($3, LIBDIRPATH, ":") + AC_MSG_RESULT([Component $1 will be included from a pre-installed library and includes.]) + $3[_with]=yes + else + $3[_LDFLAG]= + if test x$[enable_]$3 != xno; then + ifelse([$2], , :, [$2]) + build_dirs="$build_dirs $1" + AC_MSG_RESULT([Component $1 passed configuration checks; building.]) + else + passed=no + AC_MSG_RESULT([Component $1 passed configuration checks; but not building.]) + fi + fi + fi + if test $passed = no; then + skipped_dirs="$skipped_dirs $1" + $3[_skipped]=yes + else + $3[_skipped]=no + fi + AC_SUBST($3[_INCLUDES]) + AC_SUBST($3[_LA]) + AC_SUBST($3[_INCLUDEDIR]) + AC_SUBST($3[_LIBDIRPATH]) + AC_SUBST($3[_LDFLAG]) +]) diff --git a/firmware/fx2/config/grc_fx2.m4 b/firmware/fx2/config/grc_fx2.m4 new file mode 100644 index 000000000..00a41c973 --- /dev/null +++ b/firmware/fx2/config/grc_fx2.m4 @@ -0,0 +1,58 @@ +dnl Copyright 2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, +dnl Boston, MA 02110-1301, USA. + +AC_DEFUN([GRC_FX2],[ + GRC_ENABLE(usrp) + + GRC_WITH(usrp) + + dnl If execution gets to here, $passed will be: + dnl with : if the --with code didn't error out + dnl yes : if the --enable code passed muster and all dependencies are met + dnl no : otherwise + if test $passed = yes; then + dnl gnulib. + dnl FIXME: this needs to fail gracefully and continue, not implemented yet + UTILS_FUNC_MKSTEMP + + dnl These checks don't fail + AC_C_BIGENDIAN + AC_CHECK_HEADERS([byteswap.h linux/compiler.h]) + AC_CHECK_FUNCS([getrusage sched_setscheduler pthread_setschedparam]) + AC_CHECK_FUNCS([sigaction snprintf]) + + dnl Make sure SDCC >= 2.4.0 is available. + USRP_SDCC([2.4.0],[],[passed=no;AC_MSG_RESULT([Unable to find firmware compiler SDCC.])]) + fi + if test $passed != with; then + dnl how and where to find INCLUDES and LA + usrp_INCLUDES=" \ + -I\${abs_top_srcdir}/include" + fi + + AC_CONFIG_FILES([ \ + include/Makefile \ + lib/Makefile \ + src/Makefile \ + src/common/Makefile \ + src/usrp1/Makefile \ + ]) + + GRC_BUILD_CONDITIONAL(usrp) +]) diff --git a/firmware/fx2/config/lf_cc.m4 b/firmware/fx2/config/lf_cc.m4 new file mode 100644 index 000000000..b75e1a4c5 --- /dev/null +++ b/firmware/fx2/config/lf_cc.m4 @@ -0,0 +1,41 @@ +dnl Autoconf support for C++ +dnl Copyright (C) 1988 Eleftherios Gkioulekas +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a configuration +dnl script generated by Autoconf, you may include it under the same +dnl distribution terms that you use for the rest of that program. + +# ------------------------------------------------------------------------- +# Use this macro to configure your C compiler +# When called the macro does the following things: +# 1. It finds an appropriate C compiler. +# If you passed the flag --with-cc=foo then it uses that +# particular compiler +# 2. Check whether the compiler works. +# 3. Checks whether the compiler accepts the -g +# ------------------------------------------------------------------------- + +AC_DEFUN([LF_CONFIGURE_CC],[ + dnl Sing the song + AC_REQUIRE([AC_PROG_CC])dnl + AC_REQUIRE([AC_PROG_CPP])dnl + AC_REQUIRE([AC_AIX])dnl + AC_REQUIRE([AC_ISC_POSIX])dnl + AC_REQUIRE([AC_HEADER_STDC])dnl +]) + diff --git a/firmware/fx2/config/lf_cxx.m4 b/firmware/fx2/config/lf_cxx.m4 new file mode 100644 index 000000000..dfc6bfbfe --- /dev/null +++ b/firmware/fx2/config/lf_cxx.m4 @@ -0,0 +1,67 @@ +dnl Autoconf support for C++ +dnl Copyright (C) 1988 Eleftherios Gkioulekas +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a configuration +dnl script generated by Autoconf, you may include it under the same +dnl distribution terms that you use for the rest of that program. + +# ----------------------------------------------------------------- +# This macro should be called to configure your C++ compiler. +# When called, the macro does the following things: +# 1. It finds an appropriate C++ compiler +# If you passed the flag --with-cxx=foo, then it uses that +# particular compiler +# 2. Checks whether the compiler accepts the -g +# ------------------------------------------------------------------ + +AC_DEFUN([LF_CONFIGURE_CXX],[ + AC_REQUIRE([AC_PROG_CXX])dnl + AC_REQUIRE([AC_PROG_CXXCPP])dnl + LF_CXX_PORTABILITY +]) + +# ----------------------------------------------------------------------- +# This macro tests the C++ compiler for various portability problem. +# ----------------------------------------------------------------------- + + +AC_DEFUN([LF_CXX_PORTABILITY],[ + + dnl + dnl Check for common C++ portability problems + dnl + + dnl AC_LANG_PUSH + dnl AC_LANG_CPLUSPLUS + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + + dnl Test whether C++ has std::isnan + AC_MSG_CHECKING(whether C++ has std::isnan) + AC_TRY_COMPILE([#include ], [ + std::isnan(0); +], [ AC_MSG_RESULT(yes) + AC_DEFINE(CXX_HAS_STD_ISNAN,[],[Define if has std::isnan]) ], + [ AC_MSG_RESULT(no) ]) + + dnl Done with the portability checks + dnl AC_LANG_POP([C++]) + AC_LANG_RESTORE +]) + diff --git a/firmware/fx2/config/lf_warnings.m4 b/firmware/fx2/config/lf_warnings.m4 new file mode 100644 index 000000000..d40c77f14 --- /dev/null +++ b/firmware/fx2/config/lf_warnings.m4 @@ -0,0 +1,121 @@ +dnl Copyright (C) 1988 Eleftherios Gkioulekas +dnl Copyright (C) 2009 Free Software Foundation, Inc. +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a configuration +dnl script generated by Autoconf, you may include it under the same +dnl distribution terms that you use for the rest of that program. + +# -------------------------------------------------------------------------- +# Check whether the C++ compiler accepts a certain flag +# If it does it adds the flag to lf_CXXFLAGS +# If it does not then it returns an error to lf_ok +# Usage: +# LF_CHECK_CXX_FLAG(-flag1 -flag2 -flag3 ...) +# ------------------------------------------------------------------------- + +AC_DEFUN([LF_CHECK_CXX_FLAG],[ + echo 'void f(){}' > conftest.cc + for i in $1 + do + AC_MSG_CHECKING([whether $CXX accepts $i]) + if test -z "`${CXX} $i -c conftest.cc 2>&1`" + then + lf_CXXFLAGS="${lf_CXXFLAGS} $i" + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + done + rm -f conftest.cc conftest.o + AC_SUBST(lf_CXXFLAGS) +]) + +# -------------------------------------------------------------------------- +# Check whether the C compiler accepts a certain flag +# If it does it adds the flag to lf_CFLAGS +# If it does not then it returns an error to lf_ok +# Usage: +# LF_CHECK_CC_FLAG(-flag1 -flag2 -flag3 ...) +# ------------------------------------------------------------------------- + +AC_DEFUN([LF_CHECK_CC_FLAG],[ + echo 'void f(){}' > conftest.c + for i in $1 + do + AC_MSG_CHECKING([whether $CC accepts $i]) + if test -z "`${CC} $i -c conftest.c 2>&1`" + then + lf_CFLAGS="${lf_CFLAGS} $i" + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + done + rm -f conftest.c conftest.o + AC_SUBST(lf_CFLAGS) +]) + +# -------------------------------------------------------------------------- +# Check whether the Fortran compiler accepts a certain flag +# If it does it adds the flag to lf_FFLAGS +# If it does not then it returns an error to lf_ok +# Usage: +# LF_CHECK_F77_FLAG(-flag1 -flag2 -flag3 ...) +# ------------------------------------------------------------------------- + +AC_DEFUN([LF_CHECK_F77_FLAG],[ + cat << EOF > conftest.f +c....:++++++++++++++++++++++++ + PROGRAM MAIN + PRINT*,'Hello World!' + END +EOF + for i in $1 + do + AC_MSG_CHECKING([whether $F77 accepts $i]) + if test -z "`${F77} $i -c conftest.f 2>&1`" + then + lf_FFLAGS="${lf_FFLAGS} $i" + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + done + rm -f conftest.f conftest.o + AC_SUBST(lf_FFLAGS) +]) + +# ---------------------------------------------------------------------- +# Enable compiler warnings. +# Call this command AFTER you have configured ALL your compilers. +# ---------------------------------------------------------------------- + +AC_DEFUN([LF_SET_WARNINGS],[ + dnl Warnings for the two main compilers + dnl add -Wextra when you're got time to fix a bunch of them ;-) + cc_warning_flags="-Wall -Werror-implicit-function-declaration" + cxx_warning_flags="-Wall -Woverloaded-virtual" + if test -n "${CC}" + then + LF_CHECK_CC_FLAG($cc_warning_flags) + fi + if test -n "${CXX}" + then + LF_CHECK_CXX_FLAG($cxx_warning_flags) + fi +]) diff --git a/firmware/fx2/config/mkstemp.m4 b/firmware/fx2/config/mkstemp.m4 new file mode 100644 index 000000000..4af0f0a9b --- /dev/null +++ b/firmware/fx2/config/mkstemp.m4 @@ -0,0 +1,89 @@ +#serial 4 + +# On some hosts (e.g., HP-UX 10.20, SunOS 4.1.4, Solaris 2.5.1), mkstemp has a +# silly limit that it can create no more than 26 files from a given template. +# Other systems lack mkstemp altogether. +# On OSF1/Tru64 V4.0F, the system-provided mkstemp function can create +# only 32 files per process. +# On systems like the above, arrange to use the replacement function. +AC_DEFUN([UTILS_FUNC_MKSTEMP], +[dnl + AC_REPLACE_FUNCS(mkstemp) + if test $ac_cv_func_mkstemp = no; then + utils_cv_func_mkstemp_limitations=yes + else + AC_CACHE_CHECK([for mkstemp limitations], + utils_cv_func_mkstemp_limitations, + [ + AC_TRY_RUN([ +# include + int main () + { + int i; + for (i = 0; i < 70; i++) + { + char template[] = "conftestXXXXXX"; + int fd = mkstemp (template); + if (fd == -1) + exit (1); + close (fd); + } + exit (0); + } + ], + utils_cv_func_mkstemp_limitations=no, + utils_cv_func_mkstemp_limitations=yes, + utils_cv_func_mkstemp_limitations=yes + ) + ] + ) + fi + + if test $utils_cv_func_mkstemp_limitations = yes; then + AC_LIBOBJ(mkstemp) + AC_LIBOBJ(tempname) + AC_DEFINE(mkstemp, rpl_mkstemp, + [Define to rpl_mkstemp if the replacement function should be used.]) + gl_PREREQ_MKSTEMP + jm_PREREQ_TEMPNAME + fi +]) + +# Prerequisites of lib/mkstemp.c. +AC_DEFUN([gl_PREREQ_MKSTEMP], +[ + AH_BOTTOM( + [ + #ifndef HAVE_MKSTEMP + #ifdef __cplusplus + extern "C" { + #endif + int rpl_mkstemp (char *templ); + #ifdef __cplusplus + } + #endif + #endif + ]) +]) + +# Prerequisites of lib/tempname.c. +AC_DEFUN([jm_PREREQ_TEMPNAME], +[ + AC_REQUIRE([AC_HEADER_STAT]) + AC_CHECK_HEADERS_ONCE(fcntl.h sys/time.h unistd.h) + AC_CHECK_HEADERS(stdint.h) + AC_CHECK_FUNCS(__secure_getenv gettimeofday lstat) + AC_CHECK_DECLS_ONCE(getenv) + # AC_REQUIRE([jm_AC_TYPE_UINTMAX_T]) + + dnl Under Win32, mkdir prototype in io.h has only one arg + AC_MSG_CHECKING(whether mkdir accepts only one arg) + AC_TRY_COMPILE([#include + #include + #include ], [ + mkdir("") + ], [ AC_MSG_RESULT(yes) + AC_DEFINE(MKDIR_TAKES_ONE_ARG,[],[Define if mkdir accepts only one arg]) ], + [ AC_MSG_RESULT(no) + ]) +]) diff --git a/firmware/fx2/config/onceonly.m4 b/firmware/fx2/config/onceonly.m4 new file mode 100644 index 000000000..f6fec37cb --- /dev/null +++ b/firmware/fx2/config/onceonly.m4 @@ -0,0 +1,63 @@ +# onceonly.m4 serial 3 +dnl Copyright (C) 2002, 2003 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl This file defines some "once only" variants of standard autoconf macros. +dnl AC_CHECK_HEADERS_ONCE like AC_CHECK_HEADERS +dnl AC_CHECK_FUNCS_ONCE like AC_CHECK_FUNCS +dnl AC_CHECK_DECLS_ONCE like AC_CHECK_DECLS +dnl AC_REQUIRE([AC_HEADER_STDC]) like AC_HEADER_STDC +dnl The advantage is that the check for each of the headers/functions/decls +dnl will be put only once into the 'configure' file. It keeps the size of +dnl the 'configure' file down, and avoids redundant output when 'configure' +dnl is run. +dnl The drawback is that the checks cannot be conditionalized. If you write +dnl if some_condition; then gl_CHECK_HEADERS(stdlib.h); fi +dnl inside an AC_DEFUNed function, the gl_CHECK_HEADERS macro call expands to +dnl empty, and the check will be inserted before the body of the AC_DEFUNed +dnl function. + +dnl Autoconf version 2.57 or newer is recommended. +AC_PREREQ(2.54) + +# AC_CHECK_HEADERS_ONCE(HEADER1 HEADER2 ...) is a once-only variant of +# AC_CHECK_HEADERS(HEADER1 HEADER2 ...). +AC_DEFUN([AC_CHECK_HEADERS_ONCE], [ + : + AC_FOREACH([gl_HEADER_NAME], [$1], [ + AC_DEFUN([gl_CHECK_HEADER_]m4_quote(translit(defn([gl_HEADER_NAME]), + [-./], [___])), [ + AC_CHECK_HEADERS(gl_HEADER_NAME) + ]) + AC_REQUIRE([gl_CHECK_HEADER_]m4_quote(translit(gl_HEADER_NAME, + [-./], [___]))) + ]) +]) + +# AC_CHECK_FUNCS_ONCE(FUNC1 FUNC2 ...) is a once-only variant of +# AC_CHECK_FUNCS(FUNC1 FUNC2 ...). +AC_DEFUN([AC_CHECK_FUNCS_ONCE], [ + : + AC_FOREACH([gl_FUNC_NAME], [$1], [ + AC_DEFUN([gl_CHECK_FUNC_]defn([gl_FUNC_NAME]), [ + AC_CHECK_FUNCS(defn([gl_FUNC_NAME])) + ]) + AC_REQUIRE([gl_CHECK_FUNC_]defn([gl_FUNC_NAME])) + ]) +]) + +# AC_CHECK_DECLS_ONCE(DECL1 DECL2 ...) is a once-only variant of +# AC_CHECK_DECLS(DECL1, DECL2, ...). +AC_DEFUN([AC_CHECK_DECLS_ONCE], [ + : + AC_FOREACH([gl_DECL_NAME], [$1], [ + AC_DEFUN([gl_CHECK_DECL_]defn([gl_DECL_NAME]), [ + AC_CHECK_DECLS(defn([gl_DECL_NAME])) + ]) + AC_REQUIRE([gl_CHECK_DECL_]defn([gl_DECL_NAME])) + ]) +]) diff --git a/firmware/fx2/config/pkg.m4 b/firmware/fx2/config/pkg.m4 new file mode 100644 index 000000000..2d4d96109 --- /dev/null +++ b/firmware/fx2/config/pkg.m4 @@ -0,0 +1,201 @@ +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# +# Copyright © 2004 Scott James Remnant . +# Copyright © 2008 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 +# the Free Software Foundation; either version 2 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.18]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi + +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists. Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# +# Similar to PKG_CHECK_MODULES, make sure that the first instance of +# this or PKG_CHECK_MODULES is called, or make sure to call +# PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_ifval([$2], [$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$PKG_CONFIG"; then + if test -n "$$1"; then + pkg_cv_[]$1="$$1" + else + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], + [pkg_failed=yes]) + fi +else + pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# _PKG_SHORT_ERRORS_SUPPORTED +# ----------------------------- +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])# _PKG_SHORT_ERRORS_SUPPORTED + + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# E.g., +# PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not) +# defines: +# +# GSTUFF_LIBS +# GSTUFF_CFLAGS +# GSTUFF_INCLUDEDIR +# GSTUFF_CPPFLAGS # the -I, -D and -U's out of CFLAGS +# +# see pkg-config man page also defines GSTUFF_PKG_ERRORS on error +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES],[ +AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl + +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_INCLUDEDIR], [includedir for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) + +if test x$cross_compiling = xyes +then + dnl _PKG_CONFIG([$1][_LIBS], [libs-only-l --static], [$2]) + _PKG_CONFIG([$1][_LIBS], [libs --static], [$2]) + dnl prune out any -L/lib or -L/usr/lib since they're pointing to the wrong filesystem root + _pkg_tmp= + for flag in [$]pkg_cv_[$1][_LIBS]; do + case $flag in + (-L/lib* | -L/usr/lib* ) ;; # ignore + (*) _pkg_tmp="$_pkg_tmp $flag" ;; + esac + done + pkg_cv_[$1][_LIBS]="$_pkg_tmp" +else + _PKG_CONFIG([$1][_LIBS], [libs --static], [$2]) +fi + +_PKG_CONFIG([$1][_INCLUDEDIR], [variable=includedir], [$2]) + + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + ifelse([$4], , [AC_MSG_ERROR(dnl +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT +])], + [AC_MSG_RESULT([no]) + $4]) +elif test $pkg_failed = untried; then + ifelse([$4], , [AC_MSG_FAILURE(dnl +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])], + [$4]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + $1[]_INCLUDEDIR=$pkg_cv_[]$1[]_INCLUDEDIR + + $1[]_CPPFLAGS="" + for flag in $$1[]_CFLAGS; do + case $flag in + -I* | -D* | -U*) $1[]_CPPFLAGS="$$1[]_CPPFLAGS $flag" ;; + esac + done + pkg_cv_[]$1[]_CPPFLAGS=$$1[]_CPPFLAGS + AC_SUBST($1[]_CPPFLAGS) + + AC_MSG_RESULT([yes]) + ifelse([$3], , :, [$3]) +fi[]dnl +])# PKG_CHECK_MODULES diff --git a/firmware/fx2/config/usrp_sdcc.m4 b/firmware/fx2/config/usrp_sdcc.m4 new file mode 100644 index 000000000..86f6429e5 --- /dev/null +++ b/firmware/fx2/config/usrp_sdcc.m4 @@ -0,0 +1,75 @@ +# Check for sdcc support. -*- Autoconf -*- + +# Copyright 2004 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 +# the Free Software Foundation; either version 3, 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Boston, MA +# 02110-1301, USA. + +AC_DEFUN([USRP_SDCC], +[ + sdccok=yes + AC_CHECK_PROG(XCC, sdcc, sdcc -mmcs51 --no-xinit-opt,no) + AC_CHECK_PROG(XAS, asx8051, asx8051 -plosgff,no) + + if test "$XCC" = "no" -o "$XAS" = "no" ; then + AC_MSG_RESULT([USRP requires sdcc. sdcc not found. See http://sdcc.sf.net]) + sdccok=no + else + sdcc_version_min=$1 + + sdcc_version=`sdcc --version 2>&1 | \ + sed 's/\(SDCC.* \)\([[0-9]]*\.[[0-9]]*\.[[0-9]]*\)\( .*$\)/\2/'` + + AC_MSG_CHECKING([sdcc_version "$sdcc_version"]) + + sdcc_major_version=`echo $sdcc_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + sdcc_minor_version=`echo $sdcc_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + sdcc_micro_version=`echo $sdcc_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + + sdcc_major_min=`echo $sdcc_version_min | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + sdcc_minor_min=`echo $sdcc_version_min | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + sdcc_micro_min=`echo $sdcc_version_min | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + + sdcc_version_proper=`expr \ + "$sdcc_major_version" \> "$sdcc_major_min" \| \ + "$sdcc_major_version" \= "$sdcc_major_min" \& \ + "$sdcc_minor_version" \> "$sdcc_minor_min" \| \ + "$sdcc_major_version" \= "$sdcc_major_min" \& \ + "$sdcc_minor_version" \= "$sdcc_minor_min" \& \ + "$sdcc_micro_version" \>= "$sdcc_micro_min" ` + + if test "$sdcc_version_proper" = "1" ; then + AC_MSG_RESULT([$sdcc_major_version.$sdcc_minor_version.$sdcc_micro_version]) + else + sdccok=no + AC_MSG_RESULT([USRP requires sdcc >= $sdcc_version_min. sdcc not found. See http://sdcc.sf.net]) + fi + + AC_SUBST(XCC) + AC_SUBST(XAS) + fi + + if test $sdccok = yes; then + ifelse([$2], , :, [$2]) + else + ifelse([$3], , :, [$3]) + fi +]) diff --git a/firmware/fx2/configure.ac b/firmware/fx2/configure.ac new file mode 100644 index 000000000..a4fa59c2e --- /dev/null +++ b/firmware/fx2/configure.ac @@ -0,0 +1,335 @@ +dnl Copyright 2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, +dnl Boston, MA 02110-1301, USA. + +AC_INIT +AC_PREREQ(2.57) +AM_CONFIG_HEADER(config.h) + +AC_CANONICAL_BUILD +AC_CANONICAL_HOST +AC_CANONICAL_TARGET + +dnl ustar required to have pathnames > 99 chars +_AM_SET_OPTION([tar-ustar]) +AM_INIT_AUTOMAKE(gnuradio,$RELEASE) + +DEFINES="" +AC_SUBST(DEFINES) + +dnl Remember if the user explicity set CFLAGS +if test -n "${CFLAGS}"; then + user_set_cflags=yes +fi +dnl Remember if the user explicity set CXXFLAGS +if test -n "${CXXFLAGS}"; then + user_set_cxxflags=yes +fi + + +LF_CONFIGURE_CC +LF_CONFIGURE_CXX +GR_LIB64 dnl check for lib64 suffix after choosing compilers + + +dnl The three macros above are known to override CFLAGS if the user +dnl didn't specify them. Though I'm sure somebody thought this was +dnl a good idea, it makes it hard to use other than -g -O2 when compiling +dnl selected files. Thus we "undo" the damage here... +dnl +dnl If the user specified CFLAGS, we use them. +dnl See Makefile.common for the rest of the magic. +if test "$user_set_cflags" != yes; then + autoconf_default_CFLAGS="$CFLAGS" + CFLAGS="" +fi +AC_SUBST(autoconf_default_CFLAGS) + + +dnl The three macros above are known to override CXXFLAGS if the user +dnl didn't specify them. Though I'm sure somebody thought this was +dnl a good idea, it makes it hard to use other than -g -O2 when compiling +dnl selected files. Thus we "undo" the damage here... +dnl +dnl If the user specified CXXFLAGS, we use them. Otherwise when compiling +dnl the output of swig use use -O1 if we're using g++. +dnl See Makefile.common for the rest of the magic. +if test "$user_set_cxxflags" != yes; then + autoconf_default_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="" + if test "$GXX" = yes; then + case "$host_cpu" in + powerpc*) + dnl "-O1" is broken on the PPC for some reason + dnl (at least as of g++ 4.1.1) + swig_CXXFLAGS="-g1 -O2 -Wno-strict-aliasing -Wno-parentheses" + ;; + *) + swig_CXXFLAGS="-g -O1 -Wno-strict-aliasing -Wno-parentheses" + ;; + esac + fi +fi +AC_SUBST(autoconf_default_CXXFLAGS) +AC_SUBST(swig_CXXFLAGS) + +dnl add ${prefix}/lib${gr_libdir_suffix}/pkgconfig to the head of the PKG_CONFIG_PATH +if test x${PKG_CONFIG_PATH} = x; then + PKG_CONFIG_PATH=${prefix}/lib${gr_libdir_suffix}/pkgconfig +else + PKG_CONFIG_PATH=${prefix}/lib${gr_libdir_suffix}/pkgconfig:${PKG_CONFIG_PATH} +fi +export PKG_CONFIG_PATH + +LF_SET_WARNINGS +AM_PROG_AS +AC_PROG_LN_S +AC_PROG_MAKE_SET +AC_PROG_INSTALL + +# AC_PROG_MKDIR_P +# is a backport of autoconf-2.60's AC_PROG_MKDIR_P. +# Remove this macro when we can assume autoconf >= 2.60. +m4_ifdef([AC_PROG_MKDIR_P], [], [ + AC_DEFUN([AC_PROG_MKDIR_P], + [AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake + MKDIR_P='$(mkdir_p)' + AC_SUBST([MKDIR_P])]) +]) +AC_PROG_MKDIR_P + +AC_PATH_PROG([RM_PROG], [rm]) + +AC_LIBTOOL_WIN32_DLL +dnl AC_DISABLE_SHARED dnl don't build shared libraries +AC_ENABLE_SHARED dnl do build shared libraries +AC_DISABLE_STATIC dnl don't build static libraries +m4_ifdef([LT_INIT],[LT_INIT],[AC_PROG_LIBTOOL]) +dnl GR_FORTRAN + +GR_NO_UNDEFINED dnl do we need the -no-undefined linker flag +GR_SCRIPTING + + +AM_CONDITIONAL([PYTHON], [test x$enable_python = xyes]) + +dnl Checks for libraries. +AC_CHECK_LIB(socket,socket) + +dnl Set the c++ compiler that we use for the build system when cross compiling +if test x$CXX_FOR_BUILD = x +then + if test x$cross_compiling = xno; then + CXX_FOR_BUILD=${CXX} + else + CXX_FOR_BUILD=g++ + fi +fi +AC_SUBST(CXX_FOR_BUILD) + +dnl Checks for header files. +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(fcntl.h limits.h strings.h time.h sys/ioctl.h sys/time.h unistd.h) +AC_CHECK_HEADERS(linux/ppdev.h dev/ppbus/ppi.h sys/mman.h sys/select.h sys/types.h) +AC_CHECK_HEADERS(sys/resource.h stdint.h sched.h signal.h sys/syscall.h malloc.h) +AC_CHECK_HEADERS(windows.h) +AC_CHECK_HEADERS(vec_types.h) +AC_CHECK_HEADERS(netdb.h netinet/in.h arpa/inet.h sys/types.h sys/socket.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_TYPE_SIZE_T +AC_HEADER_TIME +AC_C_BIGENDIAN([GR_ARCH_BIGENDIAN=1],[GR_ARCH_BIGENDIAN=0]) +AC_SUBST(GR_ARCH_BIGENDIAN) +AC_STRUCT_TM + +dnl Checks for library functions. +AC_FUNC_ALLOCA +AC_FUNC_SETVBUF_REVERSED +AC_FUNC_VPRINTF +AC_CHECK_FUNCS([mmap select socket strcspn strerror strspn getpagesize sysconf]) +AC_CHECK_FUNCS([snprintf gettimeofday nanosleep sched_setscheduler]) +AC_CHECK_FUNCS([modf sqrt sigaction sigprocmask pthread_sigmask]) +AC_CHECK_FUNCS([sched_setaffinity]) + +AC_CHECK_LIB(m, sincos, [AC_DEFINE([HAVE_SINCOS],[1],[Define to 1 if your system has `sincos'.])]) +AC_CHECK_LIB(m, sincosf,[AC_DEFINE([HAVE_SINCOSF],[1],[Define to 1 if your system has `sincosf'.])]) +AC_CHECK_LIB(m, sinf, [AC_DEFINE([HAVE_SINF],[1],[Define to 1 if your system has `sinf'.])]) +AC_CHECK_LIB(m, cosf, [AC_DEFINE([HAVE_COSF],[1],[Define to 1 if your system has `cosf'.])]) +AC_CHECK_LIB(m, trunc, [AC_DEFINE([HAVE_TRUNC],[1],[Define to 1 if your system has `trunc'.])]) +AC_CHECK_LIB(m, exp10, [AC_DEFINE([HAVE_EXP10],[1],[Define to 1 if your system has 'exp10'.])]) +AC_CHECK_LIB(m, log2, [AC_DEFINE([HAVE_LOG2],[1],[Define to 1 if your system has 'log2'.])]) +#AC_FUNC_MKTIME + +AH_BOTTOM([ +#ifndef HAVE_TRUNC +#include +inline static double trunc(double x) +{ + return x >= 0 ? floor(x) : ceil(x); +} +#endif + +#ifndef HAVE_EXP10 +#include +inline static double exp10(double x) +{ + return pow(10.0, x); +} +#endif + +#ifdef HAVE_WINDOWS_H +#define NOMINMAX +#endif +]) + +dnl Do we have "dot", part of the graphviz package from AT&T? +dnl Doxgen will use it to draw pretty diagrams ;-) +AC_CHECK_PROG(HAVE_DOT, [dot],[YES],[NO]) + +PKG_CHECK_MODULES(FFTW3F, fftw3f >= 3.0) +AC_SUBST(FFTW3F_LIBS) + +dnl Define where to look for cppunit includes and libs +dnl sets CPPUNIT_CFLAGS and CPPUNIT_LIBS +dnl Try using pkg-config first, then fall back to cppunit-config. +PKG_CHECK_EXISTS(cppunit, + [PKG_CHECK_MODULES(CPPUNIT, cppunit >= 1.9.14)], + [AM_PATH_CPPUNIT([1.9.14],[], + [AC_MSG_ERROR([GNU Radio requires cppunit. Stop])])]) + +CPPUNIT_INCLUDES=$CPPUNIT_CFLAGS +AC_SUBST(CPPUNIT_INCLUDES) + +dnl see if GUILE is installed +AC_PATH_PROG(GUILE,guile) + + +BUILD_DATE=`date -R -u` +AC_SUBST(BUILD_DATE) + +dnl SYSCONFDIR substitution +if test "${sysconfdir}" == "\${prefix}/etc" ; then + if test "${prefix}" == "NONE" ; then + SYSCONFDIR=["$ac_default_prefix/etc"] + else + SYSCONFDIR=["${prefix}/etc"] + fi +else + SYSCONFDIR=[${sysconfdir}] +fi +AC_SUBST(SYSCONFDIR) + +dnl System configuration files +GR_PREFSDIR=[$SYSCONFDIR/${PACKAGE}/conf.d] +AC_SUBST(GR_PREFSDIR) + +dnl Component specific configuration +dnl The order of the GR_ macros determines the order of compilation +dnl For -any- checks on $enable_all_components +dnl use the following guidelines: +dnl yes : --enable-all-components was specified, so error out if any +dnl components do not pass configuration checks. +dnl no : --disable-all-components was specified, so try to build the +dnl --enable'd components, and error out if any do not pass +dnl configuration checks. +dnl "" : this option was not specified on the command line; try to +dnl build all components that are not --with'd, but don't +dnl error out if any component does not pass configuration checks. +dnl +dnl For each --enable-foo component, if that flag is not specified on +dnl the command line, the related variable $enable_foo will be set to +dnl $enable_all_components . + +AC_ARG_ENABLE( + [all-components], + [ --enable-all-components Build all configurable components (default), or stop on failed dependencies] +) + +build_dirs="config" +GRC_FX2 + +# Each component is now either to be built, was skipped, will be +# included from pre-installed libraries and includes, or failed +# dependencies. +AC_SUBST([build_dirs], [$build_dirs]) +AC_SUBST([skipped_dirs], [$skipped_dirs]) +AC_SUBST([with_dirs], [$with_dirs]) + +# fix for older autotools that don't define these by default +AC_SUBST(abs_top_srcdir) +AC_SUBST(abs_top_builddir) +AC_SUBST(MKDIR_P) + +# 'with' variables - the pre-installed libraries, includes, and paths +# - must always come last in the lists, so they require special +# treatment. +AC_SUBST(with_INCLUDES) +AC_SUBST(with_PYDIRPATH) +AC_SUBST(with_LIBDIRPATH) + +# Local files tweaked by AC +AC_CONFIG_FILES([\ + Makefile \ + config/Makefile \ +]) + +AC_OUTPUT + +echo +echo "*********************************************************************" +echo The following GNU Radio components have been successfully configured: +echo +for dir in $build_dirs +do + echo $dir +done +echo +echo You my now run the 'make' command to build these components. +echo +if test "$skipped_dirs" != ""; then + echo "*********************************************************************" + echo The following components were skipped either because you asked not + echo to build them or they didn\'t pass configuration checks: + echo + for dir in $skipped_dirs + do + echo $dir + done + echo + echo These components will not be built. + echo +fi +if test "$with_dirs" != ""; then + echo "*********************************************************************" + echo The following components will be included from pre-installed + echo libraries and includes: + echo + for dir in $with_dirs + do + echo $dir + done + echo + echo These components will not be built. + echo +fi + +echo Configured GNU Radio release $RELEASE for build. diff --git a/firmware/fx2/include/.gitignore b/firmware/fx2/include/.gitignore new file mode 100644 index 000000000..75bb241c8 --- /dev/null +++ b/firmware/fx2/include/.gitignore @@ -0,0 +1,25 @@ +/Makefile +/Makefile.in +/aclocal.m4 +/configure +/config.h.in +/stamp-h.in +/libtool +/config.log +/config.h +/config.cache +/config.status +/missing +/stamp-h +/stamp-h1 +/.la +/.lo +/.deps +/.libs +/*.la +/*.lo +/autom4te.cache +/*.cache +/missing +/make.log +/usrp.pc diff --git a/firmware/fx2/include/Makefile.am b/firmware/fx2/include/Makefile.am new file mode 100644 index 000000000..e17726c07 --- /dev/null +++ b/firmware/fx2/include/Makefile.am @@ -0,0 +1,61 @@ +# +# Copyright 2003 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +usrpincludedir = $(includedir)/usrp + +usrpinclude_HEADERS = \ + usrp_i2c_addr.h \ + usrp_spi_defs.h \ + fpga_regs_common.h \ + fpga_regs_standard.h + + +noinst_HEADERS = \ + delay.h \ + fpga_regs_common.v \ + fpga_regs_standard.v \ + fpga_regs0.h \ + fx2regs.h \ + fx2utils.h \ + i2c.h \ + isr.h \ + syncdelay.h \ + timer.h \ + usb_common.h \ + usb_descriptors.h \ + usb_requests.h \ + usrp_commands.h \ + usrp_config.h \ + usrp_ids.h \ + usrp_interfaces.h + + +CODE_GENERATOR = \ + generate_regs.py + +EXTRA_DIST = \ + $(CODE_GENERATOR) + +fpga_regs_common.v: fpga_regs_common.h generate_regs.py + PYTHONPATH=$(top_srcdir)/usrp/firmware/include $(PYTHON) $(srcdir)/generate_regs.py $(srcdir)/fpga_regs_common.h $@ + +fpga_regs_standard.v: fpga_regs_standard.h generate_regs.py + PYTHONPATH=$(top_srcdir)/usrp/firmware/include $(PYTHON) $(srcdir)/generate_regs.py $(srcdir)/fpga_regs_standard.h $@ diff --git a/firmware/fx2/include/delay.h b/firmware/fx2/include/delay.h new file mode 100644 index 000000000..f5df779e1 --- /dev/null +++ b/firmware/fx2/include/delay.h @@ -0,0 +1,38 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _DELAY_H_ +#define _DELAY_H_ + +/* + * delay for approximately usecs microseconds + * Note limit of 255 usecs. + */ +void udelay (unsigned char usecs); + +/* + * delay for approximately msecs milliseconds + */ +void mdelay (unsigned short msecs); + + +#endif /* _DELAY_H_ */ diff --git a/firmware/fx2/include/fpga_regs0.h b/firmware/fx2/include/fpga_regs0.h new file mode 100644 index 000000000..883798301 --- /dev/null +++ b/firmware/fx2/include/fpga_regs0.h @@ -0,0 +1,42 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _FPGA_REGS0_H_ +#define _FPGA_REGS0_H_ + +#define FR_RX_FREQ_0 0 +#define FR_RX_FREQ_1 1 +#define FR_RX_FREQ_2 2 +#define FR_RX_FREQ_3 3 +#define FR_TX_FREQ_0 4 +#define FR_TX_FREQ_1 5 +#define FR_TX_FREQ_2 6 +#define FR_TX_FREQ_3 7 +#define FR_COMBO 8 + + +#define FR_ADC_CLK_DIV 128 // pseudo regs mapped to FR_COMBO by f/w +#define FR_EXT_CLK_DIV 129 +#define FR_INTERP 130 +#define FR_DECIM 131 + +#endif diff --git a/firmware/fx2/include/fpga_regs_common.h b/firmware/fx2/include/fpga_regs_common.h new file mode 100644 index 000000000..b4a496af7 --- /dev/null +++ b/firmware/fx2/include/fpga_regs_common.h @@ -0,0 +1,150 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef INCLUDED_FPGA_REGS_COMMON_H +#define INCLUDED_FPGA_REGS_COMMON_H + +// This file defines registers common to all FPGA configurations. +// Registers 0 to 31 are reserved for use in this file. + + +// The FPGA needs to know the rate that samples are coming from and +// going to the A/D's and D/A's. div = 128e6 / sample_rate + +#define FR_TX_SAMPLE_RATE_DIV 0 +#define FR_RX_SAMPLE_RATE_DIV 1 + +// 2 and 3 are defined in the ATR section + +#define FR_MASTER_CTRL 4 // master enable and reset controls +# define bmFR_MC_ENABLE_TX (1 << 0) +# define bmFR_MC_ENABLE_RX (1 << 1) +# define bmFR_MC_RESET_TX (1 << 2) +# define bmFR_MC_RESET_RX (1 << 3) + +// i/o direction registers for pins that go to daughterboards. +// Setting the bit makes it an output from the FPGA to the d'board. +// top 16 is mask, low 16 is value + +#define FR_OE_0 5 // slot 0 +#define FR_OE_1 6 +#define FR_OE_2 7 +#define FR_OE_3 8 + +// i/o registers for pins that go to daughterboards. +// top 16 is a mask, low 16 is value + +#define FR_IO_0 9 // slot 0 +#define FR_IO_1 10 +#define FR_IO_2 11 +#define FR_IO_3 12 + +#define FR_MODE 13 +# define bmFR_MODE_NORMAL 0 +# define bmFR_MODE_LOOPBACK (1 << 0) // enable digital loopback +# define bmFR_MODE_RX_COUNTING (1 << 1) // Rx is counting +# define bmFR_MODE_RX_COUNTING_32BIT (1 << 2) // Rx is counting with a 32 bit counter + // low and high 16 bits are multiplexed across channel I and Q + + +// If the corresponding bit is set, internal FPGA debug circuitry +// controls the i/o pins for the associated bank of daughterboard +// i/o pins. Typically used for debugging FPGA designs. + +#define FR_DEBUG_EN 14 +# define bmFR_DEBUG_EN_TX_A (1 << 0) // debug controls TX_A i/o +# define bmFR_DEBUG_EN_RX_A (1 << 1) // debug controls RX_A i/o +# define bmFR_DEBUG_EN_TX_B (1 << 2) // debug controls TX_B i/o +# define bmFR_DEBUG_EN_RX_B (1 << 3) // debug controls RX_B i/o + + +// If the corresponding bit is set, enable the automatic DC +// offset correction control loop. +// +// The 4 low bits are significant: +// +// ADC0 = (1 << 0) +// ADC1 = (1 << 1) +// ADC2 = (1 << 2) +// ADC3 = (1 << 3) +// +// This control loop works if the attached daugherboard blocks DC. +// Currently all daughterboards do block DC. This includes: +// basic rx, dbs_rx, tv_rx, flex_xxx_rx. + +#define FR_DC_OFFSET_CL_EN 15 // DC Offset Control Loop Enable + + +// offset corrections for ADC's and DAC's (2's complement) + +#define FR_ADC_OFFSET_0 16 +#define FR_ADC_OFFSET_1 17 +#define FR_ADC_OFFSET_2 18 +#define FR_ADC_OFFSET_3 19 + + +// ------------------------------------------------------------------------ +// Automatic Transmit/Receive switching +// +// If automatic transmit/receive (ATR) switching is enabled in the +// FR_ATR_CTL register, the presence or absence of data in the FPGA +// transmit fifo selects between two sets of values for each of the 4 +// banks of daughterboard i/o pins. +// +// Each daughterboard slot has 3 16-bit registers associated with it: +// FR_ATR_MASK_*, FR_ATR_TXVAL_* and FR_ATR_RXVAL_* +// +// FR_ATR_MASK_{0,1,2,3}: +// +// These registers determine which of the daugherboard i/o pins are +// affected by ATR switching. If a bit in the mask is set, the +// corresponding i/o bit is controlled by ATR, else it's output +// value comes from the normal i/o pin output register: +// FR_IO_{0,1,2,3}. +// +// FR_ATR_TXVAL_{0,1,2,3}: +// FR_ATR_RXVAL_{0,1,2,3}: +// +// If the Tx fifo contains data, then the bits from TXVAL that are +// selected by MASK are output. Otherwise, the bits from RXVAL that +// are selected by MASK are output. + +#define FR_ATR_MASK_0 20 // slot 0 +#define FR_ATR_TXVAL_0 21 +#define FR_ATR_RXVAL_0 22 + +#define FR_ATR_MASK_1 23 // slot 1 +#define FR_ATR_TXVAL_1 24 +#define FR_ATR_RXVAL_1 25 + +#define FR_ATR_MASK_2 26 // slot 2 +#define FR_ATR_TXVAL_2 27 +#define FR_ATR_RXVAL_2 28 + +#define FR_ATR_MASK_3 29 // slot 3 +#define FR_ATR_TXVAL_3 30 +#define FR_ATR_RXVAL_3 31 + +// Clock ticks to delay rising and falling edge of T/R signal +#define FR_ATR_TX_DELAY 2 +#define FR_ATR_RX_DELAY 3 + +#endif /* INCLUDED_FPGA_REGS_COMMON_H */ diff --git a/firmware/fx2/include/fpga_regs_common.v b/firmware/fx2/include/fpga_regs_common.v new file mode 100644 index 000000000..8035d8565 --- /dev/null +++ b/firmware/fx2/include/fpga_regs_common.v @@ -0,0 +1,117 @@ +// +// This file is machine generated from ./fpga_regs_common.h +// Do not edit by hand; your edits will be overwritten. +// + +// This file defines registers common to all FPGA configurations. +// Registers 0 to 31 are reserved for use in this file. + + +// The FPGA needs to know the rate that samples are coming from and +// going to the A/D's and D/A's. div = 128e6 / sample_rate + +`define FR_TX_SAMPLE_RATE_DIV 7'd0 +`define FR_RX_SAMPLE_RATE_DIV 7'd1 + +// 2 and 3 are defined in the ATR section + +`define FR_MASTER_CTRL 7'd4 // master enable and reset controls + +// i/o direction registers for pins that go to daughterboards. +// Setting the bit makes it an output from the FPGA to the d'board. +// top 16 is mask, low 16 is value + +`define FR_OE_0 7'd5 // slot 0 +`define FR_OE_1 7'd6 +`define FR_OE_2 7'd7 +`define FR_OE_3 7'd8 + +// i/o registers for pins that go to daughterboards. +// top 16 is a mask, low 16 is value + +`define FR_IO_0 7'd9 // slot 0 +`define FR_IO_1 7'd10 +`define FR_IO_2 7'd11 +`define FR_IO_3 7'd12 + +`define FR_MODE 7'd13 + + +// If the corresponding bit is set, internal FPGA debug circuitry +// controls the i/o pins for the associated bank of daughterboard +// i/o pins. Typically used for debugging FPGA designs. + +`define FR_DEBUG_EN 7'd14 + + +// If the corresponding bit is set, enable the automatic DC +// offset correction control loop. +// +// The 4 low bits are significant: +// +// ADC0 = (1 << 0) +// ADC1 = (1 << 1) +// ADC2 = (1 << 2) +// ADC3 = (1 << 3) +// +// This control loop works if the attached daugherboard blocks DC. +// Currently all daughterboards do block DC. This includes: +// basic rx, dbs_rx, tv_rx, flex_xxx_rx. + +`define FR_DC_OFFSET_CL_EN 7'd15 // DC Offset Control Loop Enable + + +// offset corrections for ADC's and DAC's (2's complement) + +`define FR_ADC_OFFSET_0 7'd16 +`define FR_ADC_OFFSET_1 7'd17 +`define FR_ADC_OFFSET_2 7'd18 +`define FR_ADC_OFFSET_3 7'd19 + + +// ------------------------------------------------------------------------ +// Automatic Transmit/Receive switching +// +// If automatic transmit/receive (ATR) switching is enabled in the +// FR_ATR_CTL register, the presence or absence of data in the FPGA +// transmit fifo selects between two sets of values for each of the 4 +// banks of daughterboard i/o pins. +// +// Each daughterboard slot has 3 16-bit registers associated with it: +// FR_ATR_MASK_*, FR_ATR_TXVAL_* and FR_ATR_RXVAL_* +// +// FR_ATR_MASK_{0,1,2,3}: +// +// These registers determine which of the daugherboard i/o pins are +// affected by ATR switching. If a bit in the mask is set, the +// corresponding i/o bit is controlled by ATR, else it's output +// value comes from the normal i/o pin output register: +// FR_IO_{0,1,2,3}. +// +// FR_ATR_TXVAL_{0,1,2,3}: +// FR_ATR_RXVAL_{0,1,2,3}: +// +// If the Tx fifo contains data, then the bits from TXVAL that are +// selected by MASK are output. Otherwise, the bits from RXVAL that +// are selected by MASK are output. + +`define FR_ATR_MASK_0 7'd20 // slot 0 +`define FR_ATR_TXVAL_0 7'd21 +`define FR_ATR_RXVAL_0 7'd22 + +`define FR_ATR_MASK_1 7'd23 // slot 1 +`define FR_ATR_TXVAL_1 7'd24 +`define FR_ATR_RXVAL_1 7'd25 + +`define FR_ATR_MASK_2 7'd26 // slot 2 +`define FR_ATR_TXVAL_2 7'd27 +`define FR_ATR_RXVAL_2 7'd28 + +`define FR_ATR_MASK_3 7'd29 // slot 3 +`define FR_ATR_TXVAL_3 7'd30 +`define FR_ATR_RXVAL_3 7'd31 + +// Clock ticks to delay rising and falling edge of T/R signal +`define FR_ATR_TX_DELAY 7'd2 +`define FR_ATR_RX_DELAY 7'd3 + diff --git a/firmware/fx2/include/fpga_regs_standard.h b/firmware/fx2/include/fpga_regs_standard.h new file mode 100644 index 000000000..7485e2bab --- /dev/null +++ b/firmware/fx2/include/fpga_regs_standard.h @@ -0,0 +1,300 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2004,2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef INCLUDED_FPGA_REGS_STANDARD_H +#define INCLUDED_FPGA_REGS_STANDARD_H + +// Register numbers 0 to 31 are reserved for use in fpga_regs_common.h. +// Registers 64 to 79 are available for custom FPGA builds. + + +// DDC / DUC + +#define FR_INTERP_RATE 32 // [1,1024] +#define FR_DECIM_RATE 33 // [1,256] + +// DDC center freq + +#define FR_RX_FREQ_0 34 +#define FR_RX_FREQ_1 35 +#define FR_RX_FREQ_2 36 +#define FR_RX_FREQ_3 37 + +// See below for DDC Starting Phase + +// ------------------------------------------------------------------------ +// configure FPGA Rx mux +// +// 3 2 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-----------------------+-------+-------+-------+-------+-+-----+ +// | must be zero | Q3| I3| Q2| I2| Q1| I1| Q0| I0|Z| NCH | +// +-----------------------+-------+-------+-------+-------+-+-----+ +// +// There are a maximum of 4 digital downconverters in the the FPGA. +// Each DDC has two 16-bit inputs, I and Q, and two 16-bit outputs, I & Q. +// +// DDC I inputs are specified by the two bit fields I3, I2, I1 & I0 +// +// 0 = DDC input is from ADC 0 +// 1 = DDC input is from ADC 1 +// 2 = DDC input is from ADC 2 +// 3 = DDC input is from ADC 3 +// +// If Z == 1, all DDC Q inputs are set to zero +// If Z == 0, DDC Q inputs are specified by the two bit fields Q3, Q2, Q1 & Q0 +// +// NCH specifies the number of complex channels that are sent across +// the USB. The legal values are 1, 2 or 4, corresponding to 2, 4 or +// 8 16-bit values. + +#define FR_RX_MUX 38 + +// ------------------------------------------------------------------------ +// configure FPGA Tx Mux. +// +// 3 2 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-----------------------+-------+-------+-------+-------+-+-----+ +// | | DAC3 | DAC2 | DAC1 | DAC0 |0| NCH | +// +-----------------------------------------------+-------+-+-----+ +// +// NCH specifies the number of complex channels that are sent across +// the USB. The legal values are 1 or 2, corresponding to 2 or 4 +// 16-bit values. +// +// There are two interpolators with complex inputs and outputs. +// There are four DACs. (We use the DUC in each AD9862.) +// +// Each 4-bit DACx field specifies the source for the DAC and +// whether or not that DAC is enabled. Each subfield is coded +// like this: +// +// 3 2 1 0 +// +-+-----+ +// |E| N | +// +-+-----+ +// +// Where E is set if the DAC is enabled, and N specifies which +// interpolator output is connected to this DAC. +// +// N which interp output +// --- ------------------- +// 0 chan 0 I +// 1 chan 0 Q +// 2 chan 1 I +// 3 chan 1 Q + +#define FR_TX_MUX 39 + +// ------------------------------------------------------------------------ +// REFCLK control +// +// Control whether a reference clock is sent to the daughterboards, +// and what frequency. The refclk is sent on d'board i/o pin 0. +// +// 3 2 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-----------------------------------------------+-+------------+ +// | Reserved (Must be zero) |E| DIVISOR | +// +-----------------------------------------------+-+------------+ + +// +// Bit 7 -- 1 turns on refclk, 0 allows IO use +// Bits 6:0 Divider value + +#define FR_TX_A_REFCLK 40 +#define FR_RX_A_REFCLK 41 +#define FR_TX_B_REFCLK 42 +#define FR_RX_B_REFCLK 43 + +# define bmFR_REFCLK_EN 0x80 +# define bmFR_REFCLK_DIVISOR_MASK 0x7f + +// ------------------------------------------------------------------------ +// DDC Starting Phase + +#define FR_RX_PHASE_0 44 +#define FR_RX_PHASE_1 45 +#define FR_RX_PHASE_2 46 +#define FR_RX_PHASE_3 47 + +// ------------------------------------------------------------------------ +// Tx data format control register +// +// 3 2 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-------------------------------------------------------+-------+ +// | Reserved (Must be zero) | FMT | +// +-------------------------------------------------------+-------+ +// +// FMT values: + +#define FR_TX_FORMAT 48 +# define bmFR_TX_FORMAT_16_IQ 0 // 16-bit I, 16-bit Q + +// ------------------------------------------------------------------------ +// Rx data format control register +// +// 3 2 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-----------------------------------------+-+-+---------+-------+ +// | Reserved (Must be zero) |B|Q| WIDTH | SHIFT | +// +-----------------------------------------+-+-+---------+-------+ +// +// FMT values: + +#define FR_RX_FORMAT 49 + +# define bmFR_RX_FORMAT_SHIFT_MASK (0x0f << 0) // arithmetic right shift [0, 15] +# define bmFR_RX_FORMAT_SHIFT_SHIFT 0 +# define bmFR_RX_FORMAT_WIDTH_MASK (0x1f << 4) // data width in bits [1, 16] (not all valid) +# define bmFR_RX_FORMAT_WIDTH_SHIFT 4 +# define bmFR_RX_FORMAT_WANT_Q (0x1 << 9) // deliver both I & Q, else just I +# define bmFR_RX_FORMAT_BYPASS_HB (0x1 << 10) // bypass half-band filter + +// The valid combinations currently are: +// +// B Q WIDTH SHIFT +// 0 1 16 0 +// 0 1 8 8 + + +// Possible future values of WIDTH = {4, 2, 1} +// 12 takes a bit more work, since we need to know packet alignment. + +// ------------------------------------------------------------------------ +// FIXME register numbers 50 to 63 are available + +// ------------------------------------------------------------------------ +// Registers 64 to 95 are reserved for user custom FPGA builds. +// The standard USRP software will not touch these. + +#define FR_USER_0 64 +#define FR_USER_1 65 +#define FR_USER_2 66 +#define FR_USER_3 67 +#define FR_USER_4 68 +#define FR_USER_5 69 +#define FR_USER_6 70 +#define FR_USER_7 71 +#define FR_USER_8 72 +#define FR_USER_9 73 +#define FR_USER_10 74 +#define FR_USER_11 75 +#define FR_USER_12 76 +#define FR_USER_13 77 +#define FR_USER_14 78 +#define FR_USER_15 79 +#define FR_USER_16 80 +#define FR_USER_17 81 +#define FR_USER_18 82 +#define FR_USER_19 83 +#define FR_USER_20 84 +#define FR_USER_21 85 +#define FR_USER_22 86 +#define FR_USER_23 87 +#define FR_USER_24 88 +#define FR_USER_25 89 +#define FR_USER_26 90 +#define FR_USER_27 91 +#define FR_USER_28 92 +#define FR_USER_29 93 +#define FR_USER_30 94 +#define FR_USER_31 95 + +//Registers needed for multi usrp master/slave configuration +// +//Rx Master/slave control register (FR_RX_MASTER_SLAVE = FR_USER_0) +// +#define FR_RX_MASTER_SLAVE 64 +#define bitnoFR_RX_SYNC 0 +#define bitnoFR_RX_SYNC_MASTER 1 +#define bitnoFR_RX_SYNC_SLAVE 2 +# define bmFR_RX_SYNC (1 < list above. + * addr is the address of the interrupt service routine. + */ +void hook_sv (unsigned char vector_number, unsigned short addr); + +/* + * Hook usb interrupt vector. + * + * vector_number is from the UV_ list above. + * addr is the address of the interrupt service routine. + */ +void hook_uv (unsigned char vector_number, unsigned short addr); + +/* + * Hook fifo/gpif interrupt vector. + * + * vector_number is from the FGV_ list above. + * addr is the address of the interrupt service routine. + */ +void hook_fgv (unsigned char vector_number, unsigned short addr); + +/* + * One time call to enable autovectoring for both USB and FIFO/GPIF + */ +void setup_autovectors (void); + + +/* + * Must be called in each usb interrupt handler + */ +#define clear_usb_irq() \ + EXIF &= ~bmEXIF_USBINT; \ + INT2CLR = 0 + +/* + * Must be calledin each fifo/gpif interrupt handler + */ +#define clear_fifo_gpif_irq() \ + EXIF &= ~bmEXIF_IE4; \ + INT4CLR = 0 + +#endif /* _ISR_H_ */ diff --git a/firmware/fx2/include/syncdelay.h b/firmware/fx2/include/syncdelay.h new file mode 100644 index 000000000..0af7d099f --- /dev/null +++ b/firmware/fx2/include/syncdelay.h @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef _SYNCDELAY_H_ +#define _SYNCDELAY_H_ + +/* + * Magic delay required between access to certain xdata registers (TRM page 15-106). + * For our configuration, 48 MHz FX2 / 48 MHz IFCLK, we need three cycles. Each + * NOP is a single cycle.... + * + * From TRM page 15-105: + * + * Under certain conditions, some read and write access to the FX2 registers must + * be separated by a "synchronization delay". The delay is necessary only under the + * following conditions: + * + * - between a write to any register in the 0xE600 - 0xE6FF range and a write to one + * of the registers listed below. + * + * - between a write to one of the registers listed below and a read from any register + * in the 0xE600 - 0xE6FF range. + * + * Registers which require a synchronization delay: + * + * FIFORESET FIFOPINPOLAR + * INPKTEND EPxBCH:L + * EPxFIFOPFH:L EPxAUTOINLENH:L + * EPxFIFOCFG EPxGPIFFLGSEL + * PINFLAGSAB PINFLAGSCD + * EPxFIFOIE EPxFIFOIRQ + * GPIFIE GPIFIRQ + * UDMACRCH:L GPIFADRH:L + * GPIFTRIG EPxGPIFTRIG + * OUTPKTEND REVCTL + * GPIFTCB3 GPIFTCB2 + * GPIFTCB1 GPIFTCB0 + */ + +/* + * FIXME ensure that the peep hole optimizer isn't screwing us + */ +#define SYNCDELAY _asm nop; nop; nop; _endasm +#define NOP _asm nop; _endasm + + +#endif /* _SYNCDELAY_H_ */ diff --git a/firmware/fx2/include/timer.h b/firmware/fx2/include/timer.h new file mode 100644 index 000000000..3181874d5 --- /dev/null +++ b/firmware/fx2/include/timer.h @@ -0,0 +1,35 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _TIMER_H_ +#define _TIMER_H_ + +/* + * Arrange to have isr_tick_handler called at 100 Hz + */ +void hook_timer_tick (unsigned short isr_tick_handler); + +#define clear_timer_irq() \ + TF2 = 0 /* clear overflow flag */ + + +#endif /* _TIMER_H_ */ diff --git a/firmware/fx2/include/usb_common.h b/firmware/fx2/include/usb_common.h new file mode 100644 index 000000000..ae07b236c --- /dev/null +++ b/firmware/fx2/include/usb_common.h @@ -0,0 +1,37 @@ +/* -*- c -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _USB_COMMON_H_ +#define _USB_COMMON_H_ + +extern volatile bit _usb_got_SUDAV; + +// Provided by user application to handle VENDOR commands. +// returns non-zero if it handled the command. +unsigned char app_vendor_cmd (void); + +void usb_install_handlers (void); +void usb_handle_setup_packet (void); + +#define usb_setup_packet_avail() _usb_got_SUDAV + +#endif /* _USB_COMMON_H_ */ diff --git a/firmware/fx2/include/usb_descriptors.h b/firmware/fx2/include/usb_descriptors.h new file mode 100644 index 000000000..0b8c6212f --- /dev/null +++ b/firmware/fx2/include/usb_descriptors.h @@ -0,0 +1,40 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +extern xdata const char high_speed_device_descr[]; +extern xdata const char high_speed_devqual_descr[]; +extern xdata const char high_speed_config_descr[]; + +extern xdata const char full_speed_device_descr[]; +extern xdata const char full_speed_devqual_descr[]; +extern xdata const char full_speed_config_descr[]; + +extern xdata unsigned char nstring_descriptors; +extern xdata char * xdata string_descriptors[]; + +/* + * We patch these locations with info read from the usrp config eeprom + */ +extern xdata char usb_desc_hw_rev_binary_patch_location_0[]; +extern xdata char usb_desc_hw_rev_binary_patch_location_1[]; +extern xdata char usb_desc_hw_rev_ascii_patch_location_0[]; +extern xdata char usb_desc_serial_number_ascii[]; diff --git a/firmware/fx2/include/usb_requests.h b/firmware/fx2/include/usb_requests.h new file mode 100644 index 000000000..7a543abb0 --- /dev/null +++ b/firmware/fx2/include/usb_requests.h @@ -0,0 +1,88 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +// Standard USB requests. +// These are contained in end point 0 setup packets + + +#ifndef _USB_REQUESTS_H_ +#define _USB_REQUESTS_H_ + +// format of bmRequestType byte + +#define bmRT_DIR_MASK (0x1 << 7) +#define bmRT_DIR_IN (1 << 7) +#define bmRT_DIR_OUT (0 << 7) + +#define bmRT_TYPE_MASK (0x3 << 5) +#define bmRT_TYPE_STD (0 << 5) +#define bmRT_TYPE_CLASS (1 << 5) +#define bmRT_TYPE_VENDOR (2 << 5) +#define bmRT_TYPE_RESERVED (3 << 5) + +#define bmRT_RECIP_MASK (0x1f << 0) +#define bmRT_RECIP_DEVICE (0 << 0) +#define bmRT_RECIP_INTERFACE (1 << 0) +#define bmRT_RECIP_ENDPOINT (2 << 0) +#define bmRT_RECIP_OTHER (3 << 0) + + +// standard request codes (bRequest) + +#define RQ_GET_STATUS 0 +#define RQ_CLEAR_FEATURE 1 +#define RQ_RESERVED_2 2 +#define RQ_SET_FEATURE 3 +#define RQ_RESERVED_4 4 +#define RQ_SET_ADDRESS 5 +#define RQ_GET_DESCR 6 +#define RQ_SET_DESCR 7 +#define RQ_GET_CONFIG 8 +#define RQ_SET_CONFIG 9 +#define RQ_GET_INTERFACE 10 +#define RQ_SET_INTERFACE 11 +#define RQ_SYNCH_FRAME 12 + +// standard descriptor types + +#define DT_DEVICE 1 +#define DT_CONFIG 2 +#define DT_STRING 3 +#define DT_INTERFACE 4 +#define DT_ENDPOINT 5 +#define DT_DEVQUAL 6 +#define DT_OTHER_SPEED 7 +#define DT_INTERFACE_POWER 8 + +// standard feature selectors + +#define FS_ENDPOINT_HALT 0 // recip: endpoint +#define FS_DEV_REMOTE_WAKEUP 1 // recip: device +#define FS_TEST_MODE 2 // recip: device + +// Get Status device attributes + +#define bmGSDA_SELF_POWERED 0x01 +#define bmGSDA_REM_WAKEUP 0x02 + + +#endif /* _USB_REQUESTS_H_ */ diff --git a/firmware/fx2/include/usrp_commands.h b/firmware/fx2/include/usrp_commands.h new file mode 100644 index 000000000..20c28e264 --- /dev/null +++ b/firmware/fx2/include/usrp_commands.h @@ -0,0 +1,99 @@ +/* + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003,2004 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 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA + */ + +#ifndef _USRP_COMMANDS_H_ +#define _USRP_COMMANDS_H_ + +#include +#include + +#define MAX_EP0_PKTSIZE 64 // max size of EP0 packet on FX2 + +// ---------------------------------------------------------------- +// Vendor bmRequestType's +// ---------------------------------------------------------------- + +#define VRT_VENDOR_IN 0xC0 +#define VRT_VENDOR_OUT 0x40 + +// ---------------------------------------------------------------- +// USRP Vendor Requests +// +// Note that Cypress reserves [0xA0,0xAF]. +// 0xA0 is the firmware load function. +// ---------------------------------------------------------------- + + +// IN commands + +#define VRQ_GET_STATUS 0x80 +#define GS_TX_UNDERRUN 0 // wIndexL // returns 1 byte +#define GS_RX_OVERRUN 1 // wIndexL // returns 1 byte + +#define VRQ_I2C_READ 0x81 // wValueL: i2c address; length: how much to read + +#define VRQ_SPI_READ 0x82 // wValue: optional header bytes + // wIndexH: enables + // wIndexL: format + // len: how much to read + +// OUT commands + +#define VRQ_SET_LED 0x01 // wValueL off/on {0,1}; wIndexL: which {0,1} + +#define VRQ_FPGA_LOAD 0x02 +# define FL_BEGIN 0 // wIndexL: begin fpga programming cycle. stalls if trouble. +# define FL_XFER 1 // wIndexL: xfer up to 64 bytes of data +# define FL_END 2 // wIndexL: end programming cycle, check for success. + // stalls endpoint if trouble. + +#define VRQ_FPGA_WRITE_REG 0x03 // wIndexL: regno; data: 32-bit regval MSB first +#define VRQ_FPGA_SET_RESET 0x04 // wValueL: {0,1} +#define VRQ_FPGA_SET_TX_ENABLE 0x05 // wValueL: {0,1} +#define VRQ_FPGA_SET_RX_ENABLE 0x06 // wValueL: {0,1} +// see below VRQ_FPGA_SET_{TX,RX}_RESET + +#define VRQ_SET_SLEEP_BITS 0x07 // wValueH: mask; wValueL: bits. set bits given by mask to bits + +# define SLEEP_ADC0 0x01 +# define SLEEP_ADC1 0x02 +# define SLEEP_DAC0 0x04 +# define SLEEP_DAC1 0x08 + +#define VRQ_I2C_WRITE 0x08 // wValueL: i2c address; data: data + +#define VRQ_SPI_WRITE 0x09 // wValue: optional header bytes + // wIndexH: enables + // wIndexL: format + // len: how much to write + +#define VRQ_FPGA_SET_TX_RESET 0x0a // wValueL: {0, 1} +#define VRQ_FPGA_SET_RX_RESET 0x0b // wValueL: {0, 1} + + +// ------------------------------------------------------------------- +// we store the hashes at fixed addresses in the FX2 internal memory + +#define USRP_HASH_SLOT_0_ADDR 0xe1e0 +#define USRP_HASH_SLOT_1_ADDR 0xe1f0 + + + +#endif /* _USRP_COMMANDS_H_ */ diff --git a/firmware/fx2/include/usrp_config.h b/firmware/fx2/include/usrp_config.h new file mode 100644 index 000000000..e77f8e4c5 --- /dev/null +++ b/firmware/fx2/include/usrp_config.h @@ -0,0 +1,44 @@ +/* + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003 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 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA + */ + +/* + * configuration stuff for debugging + */ + +/* + * Define to 0 for normal use of port A, i.e., FPGA control bus. + * Define to 1 to write trace to port A for scoping with logic analyzer. + */ +#define UC_TRACE_USING_PORT_A 0 + + +/* + * Define to 0 for normal use of low 3 bits of port E, i.e., A/D, D/A SLEEP bits. + * Define to 1 to enable by default driving the GPIF state to the + * low three bits of port E. + */ +#define UC_START_WITH_GSTATE_OUTPUT_ENABLED 0 + + +/* + * Define to 1 for normal use (the board really has an FPGA on it). + * Define to 0 for debug use on board without FPGA. + */ +#define UC_BOARD_HAS_FPGA 1 diff --git a/firmware/fx2/include/usrp_i2c_addr.h b/firmware/fx2/include/usrp_i2c_addr.h new file mode 100644 index 000000000..0a4f3ea59 --- /dev/null +++ b/firmware/fx2/include/usrp_i2c_addr.h @@ -0,0 +1,78 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef INCLUDED_USRP_I2C_ADDR_H +#define INCLUDED_USRP_I2C_ADDR_H + +// I2C addresses + +#define I2C_DEV_EEPROM 0x50 // 24LC02[45]: 7-bits 1010xxx + +#define I2C_ADDR_BOOT (I2C_DEV_EEPROM | 0x0) +#define I2C_ADDR_TX_A (I2C_DEV_EEPROM | 0x4) +#define I2C_ADDR_RX_A (I2C_DEV_EEPROM | 0x5) +#define I2C_ADDR_TX_B (I2C_DEV_EEPROM | 0x6) +#define I2C_ADDR_RX_B (I2C_DEV_EEPROM | 0x7) + + +// format of FX2 BOOT EEPROM +// 00: 0xC0 code for ``Read IDs from EEPROM'' +// 01: 0xFE USB Vendor ID (LSB) +// 02: 0xFF USB Vendor ID (MSB) +// 03: 0x02 USB Product ID (LSB) +// 04: 0x00 USB Product ID (MSB) +// 05: 0x01 USB Device ID (LSB) // rev1 +// 06: 0x00 USB Device ID (MSB) // 0 = unconfig'd (no firmware) +// 07: 0x00 option byte + + +// format of daughterboard EEPROM +// 00: 0xDB code for ``I'm a daughterboard'' +// 01: .. Daughterboard ID (LSB) +// 02: .. Daughterboard ID (MSB) +// 03: .. io bits 7-0 direction (bit set if it's an output from m'board) +// 04: .. io bits 15-8 direction (bit set if it's an output from m'board) +// 05: .. ADC0 DC offset correction (LSB) +// 06: .. ADC0 DC offset correction (MSB) +// 07: .. ADC1 DC offset correction (LSB) +// 08: .. ADC1 DC offset correction (MSB) +// ... +// 1f: .. negative of the sum of bytes [0x00, 0x1e] + +#define DB_EEPROM_MAGIC 0x00 +#define DB_EEPROM_MAGIC_VALUE 0xDB +#define DB_EEPROM_ID_LSB 0x01 +#define DB_EEPROM_ID_MSB 0x02 +#define DB_EEPROM_OE_LSB 0x03 +#define DB_EEPROM_OE_MSB 0x04 +#define DB_EEPROM_OFFSET_0_LSB 0x05 // offset correction for ADC or DAC 0 +#define DB_EEPROM_OFFSET_0_MSB 0x06 +#define DB_EEPROM_OFFSET_1_LSB 0x07 // offset correction for ADC or DAC 1 +#define DB_EEPROM_OFFSET_1_MSB 0x08 +#define DB_EEPROM_CHKSUM 0x1f + +#define DB_EEPROM_CLEN 0x20 // length of common portion of eeprom + +#define DB_EEPROM_CUSTOM_BASE DB_EEPROM_CLEN // first avail offset for + // daughterboard specific use + +#endif /* INCLUDED_USRP_I2C_ADDR_H */ + diff --git a/firmware/fx2/include/usrp_ids.h b/firmware/fx2/include/usrp_ids.h new file mode 100644 index 000000000..46a069434 --- /dev/null +++ b/firmware/fx2/include/usrp_ids.h @@ -0,0 +1,68 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2006,2007 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* + * USB Vendor and Product IDs that we use + * + * (keep in sync with usb_descriptors.a51) + */ + +#ifndef _USRP_IDS_H_ +#define _USRP_IDS_H_ + +#define USB_VID_CYPRESS 0x04b4 +#define USB_PID_CYPRESS_FX2 0x8613 + + +#define USB_VID_FSF 0xfffe // Free Software Folks +#define USB_PID_FSF_EXP_0 0x0000 // Experimental 0 +#define USB_PID_FSF_EXP_1 0x0001 // Experimental 1 +#define USB_PID_FSF_USRP 0x0002 // Universal Software Radio Peripheral +#define USB_PID_FSF_USRP_reserved 0x0003 // Universal Software Radio Peripheral +#define USB_PID_FSF_SSRP 0x0004 // Simple Software Radio Peripheral +#define USB_PID_FSF_SSRP_reserved 0x0005 // Simple Software Radio Peripheral +#define USB_PID_FSF_HPSDR 0x0006 // High Performance Software Defined Radio (Internal Boot) +#define USB_PID_FSF_HPSDR_HA 0x0007 // High Performance Software Defined Radio (Host Assisted Boot) +#define USB_PID_FSF_QS1R 0x0008 // QS1R HF receiver +#define USB_PID_FSF_EZDOP 0x0009 // ezdop +#define USB_PID_FSF_BDALE_0 0x000a // Bdale Garbee +#define USB_PID_FSF_BDALE_1 0x000b // Bdale Garbee +#define USB_PID_FSF_BDALE_2 0x000c // Bdale Garbee +#define USB_PID_FSF_BDALE_3 0x000d // Bdale Garbee +#define USB_PID_FSF_BDALE_4 0x000e // Bdale Garbee +#define USB_PID_FSF_BDALE_5 0x000f // Bdale Garbee +#define USB_PID_FSF_BDALE_6 0x0010 // Bdale Garbee +#define USB_PID_FSF_BDALE_7 0x0011 // Bdale Garbee +#define USB_PID_FSF_BDALE_8 0x0012 // Bdale Garbee +#define USB_PID_FSF_BDALE_9 0x0013 // Bdale Garbee +#define USB_PID_FSF_HPSDR_HERMES 0x0014 // HPSDR Hermes +#define USB_PID_FSF_THINKRF 0x0015 // Catalin Patulea +#define USB_PID_FSF_MSA 0x0016 // Hans de Bok Scotty's Modular Spectrum Analyzer + +#define USB_PID_FSF_LBNL_UXO 0x0018 // http://recycle.lbl.gov/~ldoolitt/uxo/ + + +#define USB_DID_USRP_0 0x0000 // unconfigured rev 0 USRP +#define USB_DID_USRP_1 0x0001 // unconfigured rev 1 USRP +#define USB_DID_USRP_2 0x0002 // unconfigured rev 2 USRP + +#endif /* _USRP_IDS_H_ */ diff --git a/firmware/fx2/include/usrp_interfaces.h b/firmware/fx2/include/usrp_interfaces.h new file mode 100644 index 000000000..8666e0490 --- /dev/null +++ b/firmware/fx2/include/usrp_interfaces.h @@ -0,0 +1,47 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _USRP_INTERFACES_H_ +#define _USRP_INTERFACES_H_ + +/* + * We've now split the USRP into 3 separate interfaces. + * + * Interface 0 contains only ep0 and is used for command and status. + * Interface 1 is the Tx path and it uses ep2 OUT BULK. + * Interface 2 is the Rx path and it uses ep6 IN BULK. + */ + +#define USRP_CMD_INTERFACE 0 +#define USRP_CMD_ALTINTERFACE 0 +#define USRP_CMD_ENDPOINT 0 + +#define USRP_TX_INTERFACE 1 +#define USRP_TX_ALTINTERFACE 0 +#define USRP_TX_ENDPOINT 2 // streaming data from host to FPGA + +#define USRP_RX_INTERFACE 2 +#define USRP_RX_ALTINTERFACE 0 +#define USRP_RX_ENDPOINT 6 // streaming data from FPGA to host + + +#endif /* _USRP_INTERFACES_H_ */ diff --git a/firmware/fx2/include/usrp_spi_defs.h b/firmware/fx2/include/usrp_spi_defs.h new file mode 100644 index 000000000..963463ef2 --- /dev/null +++ b/firmware/fx2/include/usrp_spi_defs.h @@ -0,0 +1,86 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_USRP_SPI_DEFS_H +#define INCLUDED_USRP_SPI_DEFS_H + +/* + * defines for the VRQ_SPI_READ and VRQ_SPI_WRITE commands + * + * SPI == "Serial Port Interface". SPI is a 3 wire bus plus a + * separate enable for each peripheral. The common lines are SCLK, + * SDI and SDO. The FX2 always drives SCLK and SDI, the clock and + * data lines from the FX2 to the peripheral. When enabled, a + * peripheral may drive SDO, the data line from the peripheral to the + * FX2. + * + * The SPI_READ and SPI_WRITE commands are formatted identically. + * Each specifies which peripherals to enable, whether the bits should + * be transmistted Most Significant Bit first or Least Significant Bit + * first, the number of bytes in the optional header, and the number + * of bytes to read or write in the body. + * + * The body is limited to 64 bytes. The optional header may contain + * 0, 1 or 2 bytes. For an SPI_WRITE, the header bytes are + * transmitted to the peripheral followed by the the body bytes. For + * an SPI_READ, the header bytes are transmitted to the peripheral, + * then len bytes are read back from the peripheral. + */ + +/* + * SPI_FMT_* goes in wIndexL + */ +#define SPI_FMT_xSB_MASK (1 << 7) +# define SPI_FMT_LSB (1 << 7) // least signficant bit first +# define SPI_FMT_MSB (0 << 7) // most significant bit first +#define SPI_FMT_HDR_MASK (3 << 5) +# define SPI_FMT_HDR_0 (0 << 5) // 0 header bytes +# define SPI_FMT_HDR_1 (1 << 5) // 1 header byte +# define SPI_FMT_HDR_2 (2 << 5) // 2 header bytes + +/* + * SPI_ENABLE_* goes in wIndexH + * + * For the software interface, the enables are active high. + * For reads, it's an error to have more than one enable set. + * + * [FWIW, the hardware implements them as active low. Don't change the + * definitions of these. They are related to usrp_rev1_regs.h] + */ +#define SPI_ENABLE_FPGA 0x01 // select FPGA +#define SPI_ENABLE_CODEC_A 0x02 // select AD9862 A +#define SPI_ENABLE_CODEC_B 0x04 // select AD9862 B +#define SPI_ENABLE_reserved 0x08 +#define SPI_ENABLE_TX_A 0x10 // select d'board TX A +#define SPI_ENABLE_RX_A 0x20 // select d'board RX A +#define SPI_ENABLE_TX_B 0x40 // select d'board TX B +#define SPI_ENABLE_RX_B 0x80 // select d'board RX B + +/* + * If there's one header byte, it goes in wValueL. + * + * If there are two header bytes, they go in wValueH | wValueL. + * The transmit order of the bytes (and bits within them) is + * determined by SPI_FMT_*SB + */ + +#endif /* INCLUDED_USRP_SPI_DEFS_H */ diff --git a/firmware/fx2/lib/.gitignore b/firmware/fx2/lib/.gitignore new file mode 100644 index 000000000..04f253234 --- /dev/null +++ b/firmware/fx2/lib/.gitignore @@ -0,0 +1,18 @@ +/*.ihx +/*.lnk +/*.lst +/*.map +/*.mem +/*.rel +/*.rst +/*.sym +/blink_leds.asm +/usrp_common.asm +/command_loop.asm +/fpga.asm +/*.asm +/usrp_gpif.c +/usrp_gpif_inline.h +/*.lib +/Makefile +/Makefile.in diff --git a/firmware/fx2/lib/Makefile.am b/firmware/fx2/lib/Makefile.am new file mode 100644 index 000000000..f9e1b2317 --- /dev/null +++ b/firmware/fx2/lib/Makefile.am @@ -0,0 +1,79 @@ +# +# Copyright 2003 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +EXTRA_DIST = \ + delay.c \ + fx2utils.c \ + i2c.c \ + isr.c \ + timer.c \ + usb_common.c + + + +DEFINES= +FW_INCLUDES=-I$(top_srcdir)/include + +# with EA = 0, the FX2 implements a portion of the 8051 "external memory" +# on chip. This memory is mapped like this: +# +# The bottom 8K of memory (0x0000 - 0x1fff) is used for both data and +# code accesses. There's also 512 bytes for data only from 0xe000 - 0xe1ff. +# +# We tell the linker to start the xdata segment at 0x1800, 6K up from +# the bottom. + +LINKOPTS = --code-loc 0x0000 --code-size 0x1800 --xram-loc 0x1800 --xram-size 0x0800 + +LIBRARY = libfx2.lib + +LIBOBJS = \ + delay.rel \ + fx2utils.rel \ + i2c.rel \ + isr.rel \ + timer.rel \ + usb_common.rel + + + +all: libfx2.lib + +.c.rel: + $(XCC) $(FW_INCLUDES) $(DEFINES) -c $< -o $@ + +$(LIBRARY): $(LIBOBJS) + -rm -f $(LIBRARY) + touch $(LIBRARY) + for obj in $(LIBOBJS); do basename $$obj .rel >> $(LIBRARY) ; done + + +CLEANFILES = \ + *.ihx *.lnk *.lst *.map *.mem *.rel *.rst *.sym *.asm *.lib + +DISTCLEANFILES = \ + *.ihx *.lnk *.lst *.map *.mem *.rel *.rst *.sym *.asm *.lib + +install: all + + +# dependencies + diff --git a/firmware/fx2/lib/delay.c b/firmware/fx2/lib/delay.c new file mode 100644 index 000000000..13cf0eec8 --- /dev/null +++ b/firmware/fx2/lib/delay.c @@ -0,0 +1,76 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* + * Delay approximately 1 microsecond (including overhead in udelay). + */ +static void +udelay1 (void) _naked +{ + _asm ; lcall that got us here took 4 bus cycles + ret ; 4 bus cycles + _endasm; +} + +/* + * delay for approximately usecs microseconds + */ +void +udelay (unsigned char usecs) +{ + do { + udelay1 (); + } while (--usecs != 0); +} + + +/* + * Delay approximately 1 millisecond. + * We're running at 48 MHz, so we need 48,000 clock cycles. + * + * Note however, that each bus cycle takes 4 clock cycles (not obvious, + * but explains the factor of 4 problem below). + */ +static void +mdelay1 (void) _naked +{ + _asm + mov dptr,#(-1200 & 0xffff) +002$: + inc dptr ; 3 bus cycles + mov a, dpl ; 2 bus cycles + orl a, dph ; 2 bus cycles + jnz 002$ ; 3 bus cycles + + ret + _endasm; +} + +void +mdelay (unsigned int msecs) +{ + do { + mdelay1 (); + } while (--msecs != 0); +} + + diff --git a/firmware/fx2/lib/fx2utils.c b/firmware/fx2/lib/fx2utils.c new file mode 100644 index 000000000..64ffcc896 --- /dev/null +++ b/firmware/fx2/lib/fx2utils.c @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "fx2utils.h" +#include "fx2regs.h" +#include "delay.h" + +void +fx2_stall_ep0 (void) +{ + EP0CS |= bmEPSTALL; +} + +void +fx2_reset_data_toggle (unsigned char ep) +{ + TOGCTL = ((ep & 0x80) >> 3 | (ep & 0x0f)); + TOGCTL |= bmRESETTOGGLE; +} + +void +fx2_renumerate (void) +{ + USBCS |= bmDISCON | bmRENUM; + + // mdelay (1500); // FIXME why 1.5 seconds? + mdelay (250); // FIXME why 1.5 seconds? + + USBIRQ = 0xff; // clear any pending USB irqs... + EPIRQ = 0xff; // they're from before the renumeration + + EXIF &= ~bmEXIF_USBINT; + + USBCS &= ~bmDISCON; // reconnect USB +} diff --git a/firmware/fx2/lib/i2c-compiler-bug.c b/firmware/fx2/lib/i2c-compiler-bug.c new file mode 100644 index 000000000..360b779bc --- /dev/null +++ b/firmware/fx2/lib/i2c-compiler-bug.c @@ -0,0 +1,129 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "i2c.h" +#include "fx2regs.h" +#include + + +// issue a stop bus cycle and wait for completion + + +// returns non-zero if successful, else 0 +unsigned char +i2c_read (unsigned char addr, xdata unsigned char *buf, unsigned char len) +{ + volatile unsigned char junk; + + if (len == 0) // reading zero bytes always works + return 1; + + // memset (buf, 0, len); // FIXME, remove + + while (I2CS & bmSTOP) // wait for stop to clear + ; + + + I2CS = bmSTART; + I2DAT = (addr << 1) | 1; // write address and direction (1's the read bit) + + while ((I2CS & bmDONE) == 0) + ; + + if ((I2CS & bmBERR) || (I2CS & bmACK) == 0) // no device answered... + goto fail; + + if (len == 1) + I2CS |= bmLASTRD; + + junk = I2DAT; // trigger the first read cycle + +#if 1 + while (len != 1){ + while ((I2CS & bmDONE) == 0) + ; + + if (I2CS & bmBERR) + goto fail; + + len--; + if (len == 1) + I2CS |= bmLASTRD; + + *buf++ = I2DAT; // get data, trigger another read + } +#endif + + // wait for final byte + + while ((I2CS & bmDONE) == 0) + ; + + if (I2CS & bmBERR) + goto fail; + + I2CS |= bmSTOP; + *buf = I2DAT; + + return 1; + + fail: + I2CS |= bmSTOP; + return 0; +} + + + +// returns non-zero if successful, else 0 +unsigned char +i2c_write (unsigned char addr, xdata const unsigned char *buf, unsigned char len) +{ + while (I2CS & bmSTOP) // wait for stop to clear + ; + + I2CS = bmSTART; + I2DAT = (addr << 1) | 0; // write address and direction (0's the write bit) + + while ((I2CS & bmDONE) == 0) + ; + + if ((I2CS & bmBERR) || (I2CS & bmACK) == 0) // no device answered... + goto fail; + + while (len > 0){ + I2DAT = *buf++; + len--; + + while ((I2CS & bmDONE) == 0) + ; + + if ((I2CS & bmBERR) || (I2CS & bmACK) == 0) // no device answered... + goto fail; + } + + I2CS |= bmSTOP; + return 1; + + fail: + I2CS |= bmSTOP; + return 0; +} diff --git a/firmware/fx2/lib/i2c.c b/firmware/fx2/lib/i2c.c new file mode 100644 index 000000000..0f238b5cf --- /dev/null +++ b/firmware/fx2/lib/i2c.c @@ -0,0 +1,123 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "i2c.h" +#include "fx2regs.h" +#include + + +// issue a stop bus cycle and wait for completion + + +// returns non-zero if successful, else 0 +unsigned char +i2c_read (unsigned char addr, xdata unsigned char *buf, unsigned char len) +{ + volatile unsigned char junk; + + if (len == 0) // reading zero bytes always works + return 1; + + while (I2CS & bmSTOP) // wait for stop to clear + ; + + I2CS = bmSTART; + I2DAT = (addr << 1) | 1; // write address and direction (1's the read bit) + + while ((I2CS & bmDONE) == 0) + ; + + if ((I2CS & bmBERR) || (I2CS & bmACK) == 0) // no device answered... + goto fail; + + if (len == 1) + I2CS |= bmLASTRD; + + junk = I2DAT; // trigger the first read cycle + + while (--len != 0){ + while ((I2CS & bmDONE) == 0) + ; + + if (I2CS & bmBERR) + goto fail; + + if (len == 1) + I2CS |= bmLASTRD; + + *buf++ = I2DAT; // get data, trigger another read + } + + // wait for final byte + + while ((I2CS & bmDONE) == 0) + ; + + if (I2CS & bmBERR) + goto fail; + + I2CS |= bmSTOP; + *buf = I2DAT; + + return 1; + + fail: + I2CS |= bmSTOP; + return 0; +} + + + +// returns non-zero if successful, else 0 +unsigned char +i2c_write (unsigned char addr, xdata const unsigned char *buf, unsigned char len) +{ + while (I2CS & bmSTOP) // wait for stop to clear + ; + + I2CS = bmSTART; + I2DAT = (addr << 1) | 0; // write address and direction (0's the write bit) + + while ((I2CS & bmDONE) == 0) + ; + + if ((I2CS & bmBERR) || (I2CS & bmACK) == 0) // no device answered... + goto fail; + + while (len > 0){ + I2DAT = *buf++; + len--; + + while ((I2CS & bmDONE) == 0) + ; + + if ((I2CS & bmBERR) || (I2CS & bmACK) == 0) // no device answered... + goto fail; + } + + I2CS |= bmSTOP; + return 1; + + fail: + I2CS |= bmSTOP; + return 0; +} diff --git a/firmware/fx2/lib/isr.c b/firmware/fx2/lib/isr.c new file mode 100644 index 000000000..05412daf5 --- /dev/null +++ b/firmware/fx2/lib/isr.c @@ -0,0 +1,167 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "isr.h" +#include "fx2regs.h" +#include "syncdelay.h" + +extern xdata unsigned char _standard_interrupt_vector[]; +extern xdata unsigned char _usb_autovector[]; +extern xdata unsigned char _fifo_gpif_autovector[]; + +#define LJMP_OPCODE 0x02 + +/* + * Hook standard interrupt vector. + * + * vector_number is from the SV_ list. + * addr is the address of the interrupt service routine. + */ +void +hook_sv (unsigned char vector_number, unsigned short addr) +{ + bit t; + + // sanity checks + + if (vector_number < SV_MIN || vector_number > SV_MAX) + return; + + if ((vector_number & 0x0f) != 0x03 && (vector_number & 0x0f) != 0x0b) + return; + + t = EA; + EA = 0; + _standard_interrupt_vector[vector_number] = LJMP_OPCODE; + _standard_interrupt_vector[vector_number + 1] = addr >> 8; + _standard_interrupt_vector[vector_number + 2] = addr & 0xff; + EA = t; +} + +/* + * Hook usb interrupt vector. + * + * vector_number is from the UV_ list. + * addr is the address of the interrupt service routine. + */ +void +hook_uv (unsigned char vector_number, unsigned short addr) +{ + bit t; + + // sanity checks + + if (vector_number < UV_MIN || vector_number > UV_MAX) + return; + + if ((vector_number & 0x3) != 0) + return; + + t = EA; + EA = 0; + _usb_autovector[vector_number] = LJMP_OPCODE; + _usb_autovector[vector_number + 1] = addr >> 8; + _usb_autovector[vector_number + 2] = addr & 0xff; + EA = t; +} + +/* + * Hook fifo/gpif interrupt vector. + * + * vector_number is from the FGV_ list. + * addr is the address of the interrupt service routine. + */ +void +hook_fgv (unsigned char vector_number, unsigned short addr) +{ + bit t; + + // sanity checks + + if (vector_number < FGV_MIN || vector_number > FGV_MAX) + return; + + if ((vector_number & 0x3) != 0) + return; + + t = EA; + EA = 0; + _fifo_gpif_autovector[vector_number] = LJMP_OPCODE; + _fifo_gpif_autovector[vector_number + 1] = addr >> 8; + _fifo_gpif_autovector[vector_number + 2] = addr & 0xff; + EA = t; +} + +/* + * One time call to enable autovectoring for both USB and FIFO/GPIF. + * + * This disables all USB and FIFO/GPIF interrupts and clears + * any pending interrupts too. It leaves the master USB and FIFO/GPIF + * interrupts enabled. + */ +void +setup_autovectors (void) +{ + // disable master usb and fifo/gpif interrupt enables + EIUSB = 0; + EIEX4 = 0; + + hook_sv (SV_INT_2, (unsigned short) _usb_autovector); + hook_sv (SV_INT_4, (unsigned short) _fifo_gpif_autovector); + + // disable all fifo interrupt enables + SYNCDELAY; + EP2FIFOIE = 0; SYNCDELAY; + EP4FIFOIE = 0; SYNCDELAY; + EP6FIFOIE = 0; SYNCDELAY; + EP8FIFOIE = 0; SYNCDELAY; + + // clear all pending fifo irqs + EP2FIFOIRQ = 0xff; SYNCDELAY; + EP4FIFOIRQ = 0xff; SYNCDELAY; + EP6FIFOIRQ = 0xff; SYNCDELAY; + EP8FIFOIRQ = 0xff; SYNCDELAY; + + IBNIE = 0; + IBNIRQ = 0xff; + NAKIE = 0; + NAKIRQ = 0xff; + USBIE = 0; + USBIRQ = 0xff; + EPIE = 0; + EPIRQ = 0xff; + SYNCDELAY; GPIFIE = 0; + SYNCDELAY; GPIFIRQ = 0xff; + USBERRIE = 0; + USBERRIRQ = 0xff; + CLRERRCNT = 0; + + INTSETUP = bmAV2EN | bmAV4EN | bmINT4IN; + + // clear master irq's for usb and fifo/gpif + EXIF &= ~bmEXIF_USBINT; + EXIF &= ~bmEXIF_IE4; + + // enable master usb and fifo/gpif interrrupts + EIUSB = 1; + EIEX4 = 1; +} diff --git a/firmware/fx2/lib/timer.c b/firmware/fx2/lib/timer.c new file mode 100644 index 000000000..97e2f7cf9 --- /dev/null +++ b/firmware/fx2/lib/timer.c @@ -0,0 +1,49 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "timer.h" +#include "fx2regs.h" +#include "isr.h" + +/* + * Arrange to have isr_tick_handler called at 100 Hz. + * + * The cpu clock is running at 48e6. The input to the timer + * is 48e6 / 12 = 4e6. + * + * We arrange to have the timer overflow every 40000 clocks == 100 Hz + */ + +#define RELOAD_VALUE ((unsigned short) -40000) + +void +hook_timer_tick (unsigned short isr_tick_handler) +{ + ET2 = 0; // disable timer 2 interrupts + hook_sv (SV_TIMER_2, isr_tick_handler); + + RCAP2H = RELOAD_VALUE >> 8; // setup the auto reload value + RCAP2L = RELOAD_VALUE; + + T2CON = 0x04; // interrupt on overflow; reload; run + ET2 = 1; // enable timer 2 interrupts +} diff --git a/firmware/fx2/lib/usb_common.c b/firmware/fx2/lib/usb_common.c new file mode 100644 index 000000000..3b0547b2f --- /dev/null +++ b/firmware/fx2/lib/usb_common.c @@ -0,0 +1,386 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "usb_common.h" +#include "fx2regs.h" +#include "syncdelay.h" +#include "fx2utils.h" +#include "isr.h" +#include "usb_descriptors.h" +#include "usb_requests.h" + +extern xdata char str0[]; +extern xdata char str1[]; +extern xdata char str2[]; +extern xdata char str3[]; +extern xdata char str4[]; +extern xdata char str5[]; + + +#define bRequestType SETUPDAT[0] +#define bRequest SETUPDAT[1] +#define wValueL SETUPDAT[2] +#define wValueH SETUPDAT[3] +#define wIndexL SETUPDAT[4] +#define wIndexH SETUPDAT[5] +#define wLengthL SETUPDAT[6] +#define wLengthH SETUPDAT[7] + +#define MSB(x) (((unsigned short) x) >> 8) +#define LSB(x) (((unsigned short) x) & 0xff) + +volatile bit _usb_got_SUDAV; + +unsigned char _usb_config = 0; +unsigned char _usb_alt_setting = 0; // FIXME really 1/interface + +xdata unsigned char *current_device_descr; +xdata unsigned char *current_devqual_descr; +xdata unsigned char *current_config_descr; +xdata unsigned char *other_config_descr; + +static void +setup_descriptors (void) +{ + if (USBCS & bmHSM){ // high speed mode + current_device_descr = high_speed_device_descr; + current_devqual_descr = high_speed_devqual_descr; + current_config_descr = high_speed_config_descr; + other_config_descr = full_speed_config_descr; + } + else { + current_device_descr = full_speed_device_descr; + current_devqual_descr = full_speed_devqual_descr; + current_config_descr = full_speed_config_descr; + other_config_descr = high_speed_config_descr; + } + + // whack the type fields + // FIXME, may not be required. + // current_config_descr[1] = DT_CONFIG; + // other_config_descr[1] = DT_OTHER_SPEED; +} + +static void +isr_SUDAV (void) interrupt +{ + clear_usb_irq (); + _usb_got_SUDAV = 1; +} + +static void +isr_USBRESET (void) interrupt +{ + clear_usb_irq (); + setup_descriptors (); +} + +static void +isr_HIGHSPEED (void) interrupt +{ + clear_usb_irq (); + setup_descriptors (); +} + +void +usb_install_handlers (void) +{ + setup_descriptors (); // ensure that they're set before use + + hook_uv (UV_SUDAV, (unsigned short) isr_SUDAV); + hook_uv (UV_USBRESET, (unsigned short) isr_USBRESET); + hook_uv (UV_HIGHSPEED, (unsigned short) isr_HIGHSPEED); + + USBIE = bmSUDAV | bmURES | bmHSGRANT; +} + +// On the FX2 the only plausible endpoints are 0, 1, 2, 4, 6, 8 +// This doesn't check to see that they're enabled + +unsigned char +plausible_endpoint (unsigned char ep) +{ + ep &= ~0x80; // ignore direction bit + + if (ep > 8) + return 0; + + if (ep == 1) + return 1; + + return (ep & 0x1) == 0; // must be even +} + +// return pointer to control and status register for endpoint. +// only called with plausible_endpoints + +xdata volatile unsigned char * +epcs (unsigned char ep) +{ + if (ep == 0x01) // ep1 has different in and out CS regs + return EP1OUTCS; + + if (ep == 0x81) + return EP1INCS; + + ep &= ~0x80; // ignore direction bit + + if (ep == 0x00) // ep0 + return EP0CS; + + return EP2CS + (ep >> 1); // 2, 4, 6, 8 are consecutive +} + +void +usb_handle_setup_packet (void) +{ + _usb_got_SUDAV = 0; + + // handle the standard requests... + + switch (bRequestType & bmRT_TYPE_MASK){ + + case bmRT_TYPE_CLASS: + case bmRT_TYPE_RESERVED: + fx2_stall_ep0 (); // we don't handle these. indicate error + break; + + case bmRT_TYPE_VENDOR: + // call the application code. + // If it handles the command it returns non-zero + + if (!app_vendor_cmd ()) + fx2_stall_ep0 (); + break; + + case bmRT_TYPE_STD: + // these are the standard requests... + + if ((bRequestType & bmRT_DIR_MASK) == bmRT_DIR_IN){ + + //////////////////////////////////// + // handle the IN requests + //////////////////////////////////// + + switch (bRequest){ + + case RQ_GET_CONFIG: + EP0BUF[0] = _usb_config; // FIXME app should handle + EP0BCH = 0; + EP0BCL = 1; + break; + + // -------------------------------- + + case RQ_GET_INTERFACE: + EP0BUF[0] = _usb_alt_setting; // FIXME app should handle + EP0BCH = 0; + EP0BCL = 1; + break; + + // -------------------------------- + + case RQ_GET_DESCR: + switch (wValueH){ + + case DT_DEVICE: + SUDPTRH = MSB (current_device_descr); + SUDPTRL = LSB (current_device_descr); + break; + + case DT_DEVQUAL: + SUDPTRH = MSB (current_devqual_descr); + SUDPTRL = LSB (current_devqual_descr); + break; + + case DT_CONFIG: + if (0 && wValueL != 1) // FIXME only a single configuration + fx2_stall_ep0 (); + else { + SUDPTRH = MSB (current_config_descr); + SUDPTRL = LSB (current_config_descr); + } + break; + + case DT_OTHER_SPEED: + if (0 && wValueL != 1) // FIXME only a single configuration + fx2_stall_ep0 (); + else { + SUDPTRH = MSB (other_config_descr); + SUDPTRL = LSB (other_config_descr); + } + break; + + case DT_STRING: + if (wValueL >= nstring_descriptors) + fx2_stall_ep0 (); + else { + xdata char *p = string_descriptors[wValueL]; + SUDPTRH = MSB (p); + SUDPTRL = LSB (p); + } + break; + + default: + fx2_stall_ep0 (); // invalid request + break; + } + break; + + // -------------------------------- + + case RQ_GET_STATUS: + switch (bRequestType & bmRT_RECIP_MASK){ + case bmRT_RECIP_DEVICE: + EP0BUF[0] = bmGSDA_SELF_POWERED; // FIXME app should handle + EP0BUF[1] = 0; + EP0BCH = 0; + EP0BCL = 2; + break; + + case bmRT_RECIP_INTERFACE: + EP0BUF[0] = 0; + EP0BUF[1] = 0; + EP0BCH = 0; + EP0BCL = 2; + break; + + case bmRT_RECIP_ENDPOINT: + if (plausible_endpoint (wIndexL)){ + EP0BUF[0] = *epcs (wIndexL) & bmEPSTALL; + EP0BUF[1] = 0; + EP0BCH = 0; + EP0BCL = 2; + } + else + fx2_stall_ep0 (); + break; + + default: + fx2_stall_ep0 (); + break; + } + break; + + // -------------------------------- + + case RQ_SYNCH_FRAME: // not implemented + default: + fx2_stall_ep0 (); + break; + } + } + + else { + + //////////////////////////////////// + // handle the OUT requests + //////////////////////////////////// + + switch (bRequest){ + + case RQ_SET_CONFIG: + _usb_config = wValueL; // FIXME app should handle + break; + + case RQ_SET_INTERFACE: + _usb_alt_setting = wValueL; // FIXME app should handle + break; + + // -------------------------------- + + case RQ_CLEAR_FEATURE: + switch (bRequestType & bmRT_RECIP_MASK){ + + case bmRT_RECIP_DEVICE: + switch (wValueL){ + case FS_DEV_REMOTE_WAKEUP: + default: + fx2_stall_ep0 (); + } + break; + + case bmRT_RECIP_ENDPOINT: + if (wValueL == FS_ENDPOINT_HALT && plausible_endpoint (wIndexL)){ + *epcs (wIndexL) &= ~bmEPSTALL; + fx2_reset_data_toggle (wIndexL); + } + else + fx2_stall_ep0 (); + break; + + default: + fx2_stall_ep0 (); + break; + } + break; + + // -------------------------------- + + case RQ_SET_FEATURE: + switch (bRequestType & bmRT_RECIP_MASK){ + + case bmRT_RECIP_DEVICE: + switch (wValueL){ + case FS_TEST_MODE: + // hardware handles this after we complete SETUP phase handshake + break; + + case FS_DEV_REMOTE_WAKEUP: + default: + fx2_stall_ep0 (); + break; + } + } + break; + + case bmRT_RECIP_ENDPOINT: + switch (wValueL){ + case FS_ENDPOINT_HALT: + if (plausible_endpoint (wIndexL)) + *epcs (wIndexL) |= bmEPSTALL; + else + fx2_stall_ep0 (); + break; + + default: + fx2_stall_ep0 (); + break; + } + break; + + // -------------------------------- + + case RQ_SET_ADDRESS: // handled by fx2 hardware + case RQ_SET_DESCR: // not implemented + default: + fx2_stall_ep0 (); + } + + } + break; + + } // bmRT_TYPE_MASK + + // ack handshake phase of device request + EP0CS |= bmHSNAK; +} diff --git a/firmware/fx2/src/.gitignore b/firmware/fx2/src/.gitignore new file mode 100644 index 000000000..d46c52c00 --- /dev/null +++ b/firmware/fx2/src/.gitignore @@ -0,0 +1,17 @@ +/*.ihx +/*.lnk +/*.lst +/*.map +/*.mem +/*.rel +/*.rst +/*.sym +/blink_leds.asm +/usrp_common.asm +/command_loop.asm +/fpga.asm +/*.asm +/usrp_gpif.c +/usrp_gpif_inline.h +/Makefile +/Makefile.in diff --git a/firmware/fx2/src/Makefile.am b/firmware/fx2/src/Makefile.am new file mode 100644 index 000000000..5dcff2c85 --- /dev/null +++ b/firmware/fx2/src/Makefile.am @@ -0,0 +1,22 @@ +# +# Copyright 2004 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +SUBDIRS = common usrp1 diff --git a/firmware/fx2/src/common/.gitignore b/firmware/fx2/src/common/.gitignore new file mode 100644 index 000000000..d46c52c00 --- /dev/null +++ b/firmware/fx2/src/common/.gitignore @@ -0,0 +1,17 @@ +/*.ihx +/*.lnk +/*.lst +/*.map +/*.mem +/*.rel +/*.rst +/*.sym +/blink_leds.asm +/usrp_common.asm +/command_loop.asm +/fpga.asm +/*.asm +/usrp_gpif.c +/usrp_gpif_inline.h +/Makefile +/Makefile.in diff --git a/firmware/fx2/src/common/Makefile.am b/firmware/fx2/src/common/Makefile.am new file mode 100644 index 000000000..95232324d --- /dev/null +++ b/firmware/fx2/src/common/Makefile.am @@ -0,0 +1,50 @@ +# +# Copyright 2004 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +EXTRA_DIST = \ + _startup.a51 \ + blink_leds.c \ + check_mdelay.c \ + check_udelay.c \ + edit-gpif \ + fpga.h \ + fpga_load.h \ + fpga_load.c \ + gpif.c \ + gpif.gpf \ + init_gpif.c \ + usrp_common.c \ + usrp_globals.h \ + vectors.a51 \ + build_eeprom.py + +all: usrp_gpif.c + +usrp_gpif.c usrp_gpif_inline.h : gpif.c + srcdir=$(srcdir) $(PYTHON) $(srcdir)/edit-gpif $(srcdir)/gpif.c usrp_gpif.c usrp_gpif_inline.h + +CLEANFILES = \ + *.ihx *.lnk *.lst *.map *.mem *.rel *.rst *.sym *.asm *.lib \ + usrp_gpif.c usrp_gpif_inline.h + +DISTCLEANFILES = \ + *.ihx *.lnk *.lst *.map *.mem *.rel *.rst *.sym *.asm *.lib \ + usrp_gpif.c usrp_gpif_inline.h diff --git a/firmware/fx2/src/common/_startup.a51 b/firmware/fx2/src/common/_startup.a51 new file mode 100644 index 000000000..30a907857 --- /dev/null +++ b/firmware/fx2/src/common/_startup.a51 @@ -0,0 +1,80 @@ +;;; -*- asm -*- +;;; +;;; Copyright 2003,2004 Free Software Foundation, Inc. +;;; +;;; This file is part of GNU Radio +;;; +;;; GNU Radio 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, or (at your option) +;;; any later version. +;;; +;;; GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +;;; the Free Software Foundation, Inc., 51 Franklin Street, +;;; Boston, MA 02110-1301, USA. + + +;;; The default external memory initialization provided by sdcc is not +;;; appropriate to the FX2. This is derived from the sdcc code, but uses +;;; the FX2 specific _MPAGE sfr. + + + ;; .area XISEG (XDATA) ; the initialized external data area + ;; .area XINIT (CODE) ; the code space consts to init XISEG + .area XSEG (XDATA) ; zero initialized xdata + .area USBDESCSEG (XDATA) ; usb descriptors + + + .area CSEG (CODE) + + ;; sfr that sets upper address byte of MOVX using @r0 or @r1 + _MPAGE = 0x0092 + +__sdcc_external_startup:: + ;; This system is now compiled with the --no-xinit-opt + ;; which means that any initialized XDATA is handled + ;; inline by code in the GSINIT segs emitted for each file. + ;; + ;; We zero XSEG and all of the internal ram to ensure + ;; a known good state for uninitialized variables. + +; _mcs51_genRAMCLEAR() start + mov r0,#l_XSEG + mov a,r0 + orl a,#(l_XSEG >> 8) + jz 00002$ + mov r1,#((l_XSEG + 255) >> 8) + mov dptr,#s_XSEG + clr a + +00001$: movx @dptr,a + inc dptr + djnz r0,00001$ + djnz r1,00001$ + + ;; We're about to clear internal memory. This will overwrite + ;; the stack which contains our return address. + ;; Pop our return address into DPH, DPL +00002$: pop dph + pop dpl + + ;; R0 and A contain 0. This loop will execute 256 times. + ;; + ;; FWIW the first iteration writes direct address 0x00, + ;; which is the location of r0. We get lucky, we're + ;; writing the correct value (0) + +00003$: mov @r0,a + djnz r0,00003$ + + push dpl ; restore our return address + push dph + + mov dpl,#0 ; indicate that data init is still required + ret diff --git a/firmware/fx2/src/common/_startup.a51.brittle b/firmware/fx2/src/common/_startup.a51.brittle new file mode 100644 index 000000000..2996275cf --- /dev/null +++ b/firmware/fx2/src/common/_startup.a51.brittle @@ -0,0 +1,78 @@ +;;; -*- asm -*- +;;; +;;; Copyright 2003 Free Software Foundation, Inc. +;;; +;;; This file is part of GNU Radio +;;; +;;; GNU Radio 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, or (at your option) +;;; any later version. +;;; +;;; GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +;;; the Free Software Foundation, Inc., 51 Franklin Street, +;;; Boston, MA 02110-1301, USA. + + +;;; The default external memory initialization provided by sdcc is not +;;; appropriate to the FX2. This is derived from the sdcc code, but uses +;;; the FX2 specific _MPAGE sfr. + + + .area XISEG (XDATA) ; the initialized external data area + .area XINIT (CODE) ; the code space consts to init XISEG + .area XSEG (XDATA) ; zero initialized xdata + .area USBDESCSEG (XDATA); usb descriptors + + + ;; BIG TIME KLUDGE! + ;; Look at usrp_main.rst and count the bytes from our + ;; "normal return location" to the first instruction following + ;; the comment: "_mcs51_getRAMCLEAR () start" + + INSTRUCTION_BYTES_TO_SKIP = 0x29 ; valid for sdcc 2.4.0 + + + .area CSEG (CODE) + + ;; sfr that sets upper address byte of MOVX using @r0 or @r1 + _MPAGE = 0x0092 + +__sdcc_external_startup:: +; _mcs51_genXINIT() start + mov r1,#l_XINIT + mov a,r1 + orl a,#(l_XINIT >> 8) + jz 00003$ + mov r2,#((l_XINIT+255) >> 8) + mov dptr,#s_XINIT + mov r0,#s_XISEG + mov _MPAGE,#(s_XISEG >> 8) +00001$: clr a + movc a,@a+dptr + movx @r0,a + inc dptr + inc r0 + cjne r0,#0,00002$ + inc _MPAGE +00002$: djnz r1,00001$ + djnz r2,00001$ + mov _MPAGE,#0xFF +00003$: + + ;; Danger! Total KLUDGE! + ;; We pop the return address, add a magic number to it + ;; then jump to that address. Believe it or not, this + ;; looks like the least kludgy way to handle this, + ;; short of patching the compiler... + + pop dph + pop dpl + mov a,#INSTRUCTION_BYTES_TO_SKIP + jmp @a+dptr diff --git a/firmware/fx2/src/common/blink_leds.c b/firmware/fx2/src/common/blink_leds.c new file mode 100644 index 000000000..255c69733 --- /dev/null +++ b/firmware/fx2/src/common/blink_leds.c @@ -0,0 +1,36 @@ +/* + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003 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 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA + */ + +#include "usrp_common.h" + +void +main (void) +{ + unsigned short counter = 0; + + init_usrp (); + + while (1){ + unsigned char counter_high = counter >> 8; + set_led_0 (counter_high & 0x40); + set_led_1 (counter_high & 0x80); + counter++; + } +} diff --git a/firmware/fx2/src/common/build_eeprom.py b/firmware/fx2/src/common/build_eeprom.py new file mode 100755 index 000000000..023c4b3f5 --- /dev/null +++ b/firmware/fx2/src/common/build_eeprom.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python +# +# Copyright 2004,2006 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +import re +import sys +import os, os.path +from optparse import OptionParser + +# USB Vendor and Product ID's + +VID = 0xfffe # Free Software Folks +PID = 0x0002 # Universal Software Radio Peripheral + + +def hex_to_bytes (s): + if len (s) & 0x1: + raise ValueError, "Length must be even" + r = [] + for i in range (0, len(s), 2): + r.append (int (s[i:i+2], 16)) + return r + +def msb (x): + return (x >> 8) & 0xff + +def lsb (x): + return x & 0xff + +class ihx_rec (object): + def __init__ (self, addr, type, data): + self.addr = addr + self.type = type + self.data = data + +class ihx_file (object): + def __init__ (self): + self.pat = re.compile (r':[0-9A-F]{10,}') + def read (self, file): + r = [] + for line in file: + line = line.strip().upper () + if not self.pat.match (line): + raise ValueError, "Invalid hex record format" + bytes = hex_to_bytes (line[1:]) + sum = reduce (lambda x, y: x + y, bytes, 0) % 256 + if sum != 0: + raise ValueError, "Bad hex checksum" + lenx = bytes[0] + addr = (bytes[1] << 8) + bytes[2] + type = bytes[3] + data = bytes[4:-1] + if lenx != len (data): + raise ValueError, "Invalid hex record (bad length)" + if type != 0: + break; + r.append (ihx_rec (addr, type, data)) + + return r + +def get_code (filename): + """Read the intel hex format file FILENAME and return a tuple + of the code starting address and a list of bytes to load there. + """ + f = open (filename, 'r') + ifx = ihx_file () + r = ifx.read (f) + r.sort (lambda a,b: a.addr - b.addr) + code_start = r[0].addr + code_end = r[-1].addr + len (r[-1].data) + code_len = code_end - code_start + code = [0] * code_len + for x in r: + a = x.addr + l = len (x.data) + code[a-code_start:a-code_start+l] = x.data + return (code_start, code) + + +def build_eeprom_image (filename, rev): + """Build a ``C2 Load'' EEPROM image. + + For details on this format, see section 3.4.3 of + the EZ-USB FX2 Technical Reference Manual + """ + # get the code we want to run + (start_addr, bytes) = get_code (filename) + + devid = rev + + rom_header = [ + 0xC2, # boot from EEPROM + lsb (VID), + msb (VID), + lsb (PID), + msb (PID), + lsb (devid), + msb (devid), + 0 # configuration byte + ] + + # 4 byte header that indicates where to load + # the immediately follow code bytes. + code_header = [ + msb (len (bytes)), + lsb (len (bytes)), + msb (start_addr), + lsb (start_addr) + ] + + # writes 0 to CPUCS reg (brings FX2 out of reset) + trailer = [ + 0x80, + 0x01, + 0xe6, + 0x00, + 0x00 + ] + + image = rom_header + code_header + bytes + trailer + + assert (len (image) <= 256) + return image + +def build_shell_script (out, ihx_filename, rev): + + image = build_eeprom_image (ihx_filename, rev) + + out.write ('#!/bin/sh\n') + out.write ('usrper -x load_firmware /usr/local/share/usrp/rev%d/std.ihx\n' % rev) + out.write ('sleep 1\n') + + # print "len(image) =", len(image) + + i2c_addr = 0x50 + rom_addr = 0x00 + + hex_image = map (lambda x : "%02x" % (x,), image) + + while (len (hex_image) > 0): + l = min (len (hex_image), 16) + out.write ('usrper i2c_write 0x%02x %02x%s\n' % + (i2c_addr, rom_addr, ''.join (hex_image[0:l]))) + hex_image = hex_image[l:] + rom_addr = rom_addr + l + out.write ('sleep 1\n') + +if __name__ == '__main__': + usage = "usage: %prog -r REV [options] bootfile.ihx" + parser = OptionParser (usage=usage) + parser.add_option ("-r", "--rev", type="int", default=-1, + help="Specify USRP revision number REV (2 or 4)") + (options, args) = parser.parse_args () + if len (args) != 1: + parser.print_help () + sys.exit (1) + if options.rev < 0: + sys.stderr.write ( + "You must specify the USRP revision number (2 or 4) with -r REV\n") + sys.exit (1) + + ihx_filename = args[0] + + build_shell_script (sys.stdout, ihx_filename, options.rev) diff --git a/firmware/fx2/src/common/check_mdelay.c b/firmware/fx2/src/common/check_mdelay.c new file mode 100644 index 000000000..de1af47f6 --- /dev/null +++ b/firmware/fx2/src/common/check_mdelay.c @@ -0,0 +1,37 @@ +/* + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003 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 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA + */ + +#include "usrp_common.h" +#include "delay.h" + +void +main (void) +{ + init_usrp (); + + // CPUCS = 0; // 12 MHz + // CPUCS = bmCLKSPD0; // 24 MHz + CPUCS = bmCLKSPD1; // 48 MHz + + while (1){ + USRP_LED_REG ^= bmLED0; + mdelay (10); + } +} diff --git a/firmware/fx2/src/common/check_udelay.c b/firmware/fx2/src/common/check_udelay.c new file mode 100644 index 000000000..46885a067 --- /dev/null +++ b/firmware/fx2/src/common/check_udelay.c @@ -0,0 +1,37 @@ +/* + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003 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 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA + */ + +#include "usrp_common.h" +#include "delay.h" + +void +main (void) +{ + init_usrp (); + + // CPUCS = 0; // 12 MHz + // CPUCS = bmCLKSPD0; // 24 MHz + CPUCS = bmCLKSPD1; // 48 MHz + + while (1){ + USRP_LED_REG ^= bmLED0; + udelay (250); + } +} diff --git a/firmware/fx2/src/common/edit-gpif b/firmware/fx2/src/common/edit-gpif new file mode 100755 index 000000000..5367b75a5 --- /dev/null +++ b/firmware/fx2/src/common/edit-gpif @@ -0,0 +1,114 @@ +#!/usr/bin/env python +# -*- Python -*- +# +# Copyright 2003 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + + +# Edit the gpif.c file generated by the Cypress GPIF Designer Tool and +# produce usrp_gpif.c, and usrp_gpif_inline.h, files suitable for our +# uses. + +import re +import string +import sys + +def check_flow_state (line, flow_state_dict): + mo = re.match (r'/\* Wave (\d) FlowStates \*/ (.*),', line) + if mo: + wave = int (mo.group (1)) + data = mo.group (2) + split = data.split (',', 8) + v = map (lambda x : int (x, 16), split) + # print "%s, %s" % (wave, data) + # print "split: ", split + # print "v : ", v + flow_state_dict[wave] = v + + +def delta (xseq, yseq): + # set subtraction + z = [] + for x in xseq: + if x not in yseq: + z.append (x) + return z + + +def write_define (output, name, pairs): + output.write ('#define %s()\t\\\n' % name) + output.write ('do {\t\t\t\t\t\\\n') + for reg, val in pairs: + output.write ('%14s = 0x%02x;\t\t\t\\\n' % (reg, val)) + output.write ('} while (0)\n\n') + +def write_inlines (output, dict): + regs = ['FLOWSTATE', 'FLOWLOGIC', 'FLOWEQ0CTL', 'FLOWEQ1CTL', 'FLOWHOLDOFF', + 'FLOWSTB', 'FLOWSTBEDGE', 'FLOWSTBHPERIOD', 'GPIFHOLDAMOUNT'] + + READ_FLOW_STATE = 2 + WRITE_FLOW_STATE = 3 + + read_info = zip (regs, dict[READ_FLOW_STATE]) + write_info = zip (regs, dict[WRITE_FLOW_STATE]) + + output.write ('''/* + * Machine generated by "edit-gpif". Do not edit by hand. + */ + +''') + write_define (output, 'setup_flowstate_common', read_info) + write_define (output, 'setup_flowstate_read', delta (read_info, write_info)) + write_define (output, 'setup_flowstate_write', delta (write_info, read_info)) + + +def edit_gpif (input_name, output_name, inline_name): + input = open (input_name, 'r') + output = open (output_name, 'w') + inline = open (inline_name, 'w') + flow_state_dict = {} + + output.write ('''/* + * Machine generated by "edit-gpif". Do not edit by hand. + */ + +''') + + while 1: + line = input.readline () + line = string.replace (line, '\r','') + line = re.sub (r' *$', r'', line) + + check_flow_state (line, flow_state_dict) + + line = re.sub (r'#include', r'// #include', line) + line = re.sub (r'xdata ', r'', line) + if re.search (r'GpifInit', line): + break + + output.write (line) + + output.close () + write_inlines (inline, flow_state_dict) + inline.close () + + +# gpif.c usrp_gpif.c usrp_gpif_inline.h +edit_gpif (sys.argv[1], sys.argv[2], sys.argv[3]) diff --git a/firmware/fx2/src/common/fpga.h b/firmware/fx2/src/common/fpga.h new file mode 100644 index 000000000..6cd5de8e2 --- /dev/null +++ b/firmware/fx2/src/common/fpga.h @@ -0,0 +1,31 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef INCLUDED_FPGA_H +#define INCLUDED_FPGA_H + +#include "fpga_load.h" + +#if defined(HAVE_USRP2) +#include "fpga_rev2.h" +#endif + +#endif /* INCLUDED_FPGA_H */ diff --git a/firmware/fx2/src/common/fpga_load.c b/firmware/fx2/src/common/fpga_load.c new file mode 100644 index 000000000..c3ae9e707 --- /dev/null +++ b/firmware/fx2/src/common/fpga_load.c @@ -0,0 +1,193 @@ +/* + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003 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 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA + */ + +#include "usrp_common.h" +#include "fpga_load.h" +#include "delay.h" + +/* + * setup altera FPGA serial load (PS). + * + * On entry: + * don't care + * + * On exit: + * ALTERA_DCLK = 0 + * ALTERA_NCONFIG = 1 + * ALTERA_NSTATUS = 1 (input) + */ +unsigned char +fpga_load_begin (void) +{ + USRP_ALTERA_CONFIG &= ~bmALTERA_BITS; // clear all bits (NCONFIG low) + udelay (40); // wait 40 us + USRP_ALTERA_CONFIG |= bmALTERA_NCONFIG; // set NCONFIG high + + if (UC_BOARD_HAS_FPGA){ + // FIXME should really cap this loop with a counter so we + // don't hang forever on a hardware failure. + while ((USRP_ALTERA_CONFIG & bmALTERA_NSTATUS) == 0) // wait for NSTATUS to go high + ; + } + + // ready to xfer now + + return 1; +} + +/* + * clock out the low bit of bits. + * + * On entry: + * ALTERA_DCLK = 0 + * ALTERA_NCONFIG = 1 + * ALTERA_NSTATUS = 1 (input) + * + * On exit: + * ALTERA_DCLK = 0 + * ALTERA_NCONFIG = 1 + * ALTERA_NSTATUS = 1 (input) + */ + + +#if 0 + +static void +clock_out_config_byte (unsigned char bits) +{ + unsigned char i; + + // clock out configuration byte, least significant bit first + + for (i = 0; i < 8; i++){ + + USRP_ALTERA_CONFIG = ((USRP_ALTERA_CONFIG & ~bmALTERA_DATA0) | ((bits & 1) ? bmALTERA_DATA0 : 0)); + USRP_ALTERA_CONFIG |= bmALTERA_DCLK; /* set DCLK to 1 */ + USRP_ALTERA_CONFIG &= ~bmALTERA_DCLK; /* set DCLK to 0 */ + + bits = bits >> 1; + } +} + +#else + +static void +clock_out_config_byte (unsigned char bits) _naked +{ + _asm + mov a, dpl + + rrc a + mov _bitALTERA_DATA0,c + setb _bitALTERA_DCLK + clr _bitALTERA_DCLK + + rrc a + mov _bitALTERA_DATA0,c + setb _bitALTERA_DCLK + clr _bitALTERA_DCLK + + rrc a + mov _bitALTERA_DATA0,c + setb _bitALTERA_DCLK + clr _bitALTERA_DCLK + + rrc a + mov _bitALTERA_DATA0,c + setb _bitALTERA_DCLK + clr _bitALTERA_DCLK + + rrc a + mov _bitALTERA_DATA0,c + setb _bitALTERA_DCLK + clr _bitALTERA_DCLK + + rrc a + mov _bitALTERA_DATA0,c + setb _bitALTERA_DCLK + clr _bitALTERA_DCLK + + rrc a + mov _bitALTERA_DATA0,c + setb _bitALTERA_DCLK + clr _bitALTERA_DCLK + + rrc a + mov _bitALTERA_DATA0,c + setb _bitALTERA_DCLK + clr _bitALTERA_DCLK + + ret + + _endasm; +} + +#endif + +static void +clock_out_bytes (unsigned char bytecount, + unsigned char xdata *p) +{ + while (bytecount-- > 0) + clock_out_config_byte (*p++); +} + +/* + * Transfer block of bytes from packet to FPGA serial configuration port + * + * On entry: + * ALTERA_DCLK = 0 + * ALTERA_NCONFIG = 1 + * ALTERA_NSTATUS = 1 (input) + * + * On exit: + * ALTERA_DCLK = 0 + * ALTERA_NCONFIG = 1 + * ALTERA_NSTATUS = 1 (input) + */ +unsigned char +fpga_load_xfer (xdata unsigned char *p, unsigned char bytecount) +{ + clock_out_bytes (bytecount, p); + return 1; +} + +/* + * check for successful load... + */ +unsigned char +fpga_load_end (void) +{ + unsigned char status = USRP_ALTERA_CONFIG; + + if (!UC_BOARD_HAS_FPGA) // always true if we don't have FPGA + return 1; + + if ((status & bmALTERA_NSTATUS) == 0) // failed to program + return 0; + + if ((status & bmALTERA_CONF_DONE) == bmALTERA_CONF_DONE) + return 1; // everything's cool + + // I don't think this should happen. It indicates that + // programming is still in progress. + + return 0; +} diff --git a/firmware/fx2/src/common/fpga_load.h b/firmware/fx2/src/common/fpga_load.h new file mode 100644 index 000000000..7c36a04c8 --- /dev/null +++ b/firmware/fx2/src/common/fpga_load.h @@ -0,0 +1,28 @@ +/* + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003 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 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA + */ + +#ifndef INCLUDED_FPGA_LOAD_H +#define INCLUDED_FPGA_LOAD_H + +unsigned char fpga_load_begin (void); +unsigned char fpga_load_xfer (xdata unsigned char *p, unsigned char len); +unsigned char fpga_load_end (void); + +#endif /* INCLUDED_FPGA_LOAD_H */ diff --git a/firmware/fx2/src/common/gpif.c b/firmware/fx2/src/common/gpif.c new file mode 100755 index 000000000..489e6e81a --- /dev/null +++ b/firmware/fx2/src/common/gpif.c @@ -0,0 +1,292 @@ +// This program configures the General Programmable Interface (GPIF) for FX2. +// Please do not modify sections of text which are marked as "DO NOT EDIT ...". +// +// DO NOT EDIT ... +// GPIF Initialization +// Interface Timing Async +// Internal Ready Init IntRdy=1 +// CTL Out Tristate-able Binary +// SingleWrite WF Select 1 +// SingleRead WF Select 0 +// FifoWrite WF Select 3 +// FifoRead WF Select 2 +// Data Bus Idle Drive Tristate +// END DO NOT EDIT + +// DO NOT EDIT ... +// GPIF Wave Names +// Wave 0 = singlerd +// Wave 1 = singlewr +// Wave 2 = FIFORd +// Wave 3 = FIFOWr + +// GPIF Ctrl Outputs Level +// CTL 0 = WEN# CMOS +// CTL 1 = REN# CMOS +// CTL 2 = OE# CMOS +// CTL 3 = CLRST CMOS +// CTL 4 = unused CMOS +// CTL 5 = BOGUS CMOS + +// GPIF Rdy Inputs +// RDY0 = EF# +// RDY1 = FF# +// RDY2 = unused +// RDY3 = unused +// RDY4 = unused +// RDY5 = TCXpire +// FIFOFlag = FIFOFlag +// IntReady = IntReady +// END DO NOT EDIT +// DO NOT EDIT ... +// +// GPIF Waveform 0: singlerd +// +// Interval 0 1 2 3 4 5 6 Idle (7) +// _________ _________ _________ _________ _________ _________ _________ _________ +// +// AddrMode Same Val Same Val Same Val Same Val Same Val Same Val Same Val +// DataMode NO Data NO Data NO Data NO Data NO Data NO Data NO Data +// NextData SameData SameData SameData SameData SameData SameData SameData +// Int Trig No Int No Int No Int No Int No Int No Int No Int +// IF/Wait Wait 1 Wait 1 Wait 1 Wait 1 Wait 1 Wait 1 Wait 1 +// Term A +// LFunc +// Term B +// Branch1 +// Branch0 +// Re-Exec +// Sngl/CRC Default Default Default Default Default Default Default +// WEN# 0 0 0 0 0 0 0 0 +// REN# 0 0 0 0 0 0 0 0 +// OE# 0 0 0 0 0 0 0 0 +// CLRST 0 0 0 0 0 0 0 0 +// unused 0 0 0 0 0 0 0 0 +// BOGUS 0 0 0 0 0 0 0 0 +// +// END DO NOT EDIT +// DO NOT EDIT ... +// +// GPIF Waveform 1: singlewr +// +// Interval 0 1 2 3 4 5 6 Idle (7) +// _________ _________ _________ _________ _________ _________ _________ _________ +// +// AddrMode Same Val Same Val Same Val Same Val Same Val Same Val Same Val +// DataMode Activate Activate Activate Activate Activate Activate Activate +// NextData SameData SameData SameData SameData SameData SameData SameData +// Int Trig No Int No Int No Int No Int No Int No Int No Int +// IF/Wait Wait 1 IF Wait 1 Wait 1 Wait 1 Wait 1 Wait 1 +// Term A EF# +// LFunc AND +// Term B EF# +// Branch1 ThenIdle +// Branch0 ElseIdle +// Re-Exec No +// Sngl/CRC Default Default Default Default Default Default Default +// WEN# 0 1 1 1 1 1 1 0 +// REN# 0 0 0 0 0 0 0 0 +// OE# 0 0 0 0 0 0 0 0 +// CLRST 0 0 0 0 0 0 0 0 +// unused 0 0 0 0 0 0 0 0 +// BOGUS 0 0 0 0 0 0 0 0 +// +// END DO NOT EDIT +// DO NOT EDIT ... +// +// GPIF Waveform 2: FIFORd +// +// Interval 0 1 2 3 4 5 6 Idle (7) +// _________ _________ _________ _________ _________ _________ _________ _________ +// +// AddrMode Same Val Same Val Same Val Same Val Same Val Same Val Same Val +// DataMode NO Data Activate NO Data NO Data NO Data NO Data NO Data +// NextData SameData SameData SameData SameData SameData SameData SameData +// Int Trig No Int No Int No Int No Int No Int No Int No Int +// IF/Wait Wait 1 IF Wait 1 IF Wait 1 Wait 1 Wait 1 +// Term A TCXpire TCXpire +// LFunc AND AND +// Term B TCXpire TCXpire +// Branch1 Then 2 ThenIdle +// Branch0 Else 1 ElseIdle +// Re-Exec No No +// Sngl/CRC Default Default Default Default Default Default Default +// WEN# 0 0 0 0 0 0 0 0 +// REN# 0 0 0 0 0 0 0 0 +// OE# 1 1 1 0 0 0 0 0 +// CLRST 0 0 0 0 0 0 0 0 +// unused 0 0 0 0 0 0 0 0 +// BOGUS 0 0 0 0 0 0 0 0 +// +// END DO NOT EDIT +// DO NOT EDIT ... +// +// GPIF Waveform 3: FIFOWr +// +// Interval 0 1 2 3 4 5 6 Idle (7) +// _________ _________ _________ _________ _________ _________ _________ _________ +// +// AddrMode Same Val Same Val Same Val Same Val Same Val Same Val Same Val +// DataMode NO Data Activate Activate Activate Activate Activate Activate +// NextData SameData SameData SameData SameData SameData SameData SameData +// Int Trig No Int No Int No Int No Int No Int No Int No Int +// IF/Wait Wait 1 IF Wait 1 Wait 1 Wait 1 Wait 1 Wait 1 +// Term A TCXpire +// LFunc AND +// Term B TCXpire +// Branch1 ThenIdle +// Branch0 Else 1 +// Re-Exec No +// Sngl/CRC Default Default Default Default Default Default Default +// WEN# 0 0 0 0 0 0 0 0 +// REN# 0 0 0 0 0 0 0 0 +// OE# 0 0 0 0 0 0 0 0 +// CLRST 0 0 0 0 0 0 0 0 +// unused 0 0 0 0 0 0 0 0 +// BOGUS 0 0 0 0 0 0 0 0 +// +// END DO NOT EDIT + +// GPIF Program Code + +// DO NOT EDIT ... +#include "fx2.h" +#include "fx2regs.h" +#include "fx2sdly.h" // SYNCDELAY macro +// END DO NOT EDIT + +// DO NOT EDIT ... +const char xdata WaveData[128] = +{ +// Wave 0 +/* LenBr */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Output*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* LFun */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, +// Wave 1 +/* LenBr */ 0x01, 0x3F, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x22, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, +/* Output*/ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, +/* LFun */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, +// Wave 2 +/* LenBr */ 0x01, 0x11, 0x01, 0x3F, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, +/* Output*/ 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, +/* LFun */ 0x00, 0x2D, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x3F, +// Wave 3 +/* LenBr */ 0x01, 0x39, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, +/* Output*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* LFun */ 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, +}; +// END DO NOT EDIT + +// DO NOT EDIT ... +const char xdata FlowStates[36] = +{ +/* Wave 0 FlowStates */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* Wave 1 FlowStates */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* Wave 2 FlowStates */ 0x81,0x2D,0x26,0x00,0x04,0x04,0x03,0x02,0x00, +/* Wave 3 FlowStates */ 0x81,0x2D,0x21,0x00,0x04,0x04,0x03,0x02,0x00, +}; +// END DO NOT EDIT + +// DO NOT EDIT ... +const char xdata InitData[7] = +{ +/* Regs */ 0xA0,0x00,0x00,0x00,0xEE,0x4E,0x00 +}; +// END DO NOT EDIT + +// TO DO: You may add additional code below. + +void GpifInit( void ) +{ + BYTE i; + + // Registers which require a synchronization delay, see section 15.14 + // FIFORESET FIFOPINPOLAR + // INPKTEND OUTPKTEND + // EPxBCH:L REVCTL + // GPIFTCB3 GPIFTCB2 + // GPIFTCB1 GPIFTCB0 + // EPxFIFOPFH:L EPxAUTOINLENH:L + // EPxFIFOCFG EPxGPIFFLGSEL + // PINFLAGSxx EPxFIFOIRQ + // EPxFIFOIE GPIFIRQ + // GPIFIE GPIFADRH:L + // UDMACRCH:L EPxGPIFTRIG + // GPIFTRIG + + // Note: The pre-REVE EPxGPIFTCH/L register are affected, as well... + // ...these have been replaced by GPIFTC[B3:B0] registers + + // 8051 doesn't have access to waveform memories 'til + // the part is in GPIF mode. + + IFCONFIG = 0xEE; + // IFCLKSRC=1 , FIFOs executes on internal clk source + // xMHz=1 , 48MHz internal clk rate + // IFCLKOE=0 , Don't drive IFCLK pin signal at 48MHz + // IFCLKPOL=0 , Don't invert IFCLK pin signal from internal clk + // ASYNC=1 , master samples asynchronous + // GSTATE=1 , Drive GPIF states out on PORTE[2:0], debug WF + // IFCFG[1:0]=10, FX2 in GPIF master mode + + GPIFABORT = 0xFF; // abort any waveforms pending + + GPIFREADYCFG = InitData[ 0 ]; + GPIFCTLCFG = InitData[ 1 ]; + GPIFIDLECS = InitData[ 2 ]; + GPIFIDLECTL = InitData[ 3 ]; + GPIFWFSELECT = InitData[ 5 ]; + GPIFREADYSTAT = InitData[ 6 ]; + + // use dual autopointer feature... + AUTOPTRSETUP = 0x07; // inc both pointers, + // ...warning: this introduces pdata hole(s) + // ...at E67B (XAUTODAT1) and E67C (XAUTODAT2) + + // source + AUTOPTRH1 = MSB( &WaveData ); + AUTOPTRL1 = LSB( &WaveData ); + + // destination + AUTOPTRH2 = 0xE4; + AUTOPTRL2 = 0x00; + + // transfer + for ( i = 0x00; i < 128; i++ ) + { + EXTAUTODAT2 = EXTAUTODAT1; + } + +// Configure GPIF Address pins, output initial value, + PORTCCFG = 0xFF; // [7:0] as alt. func. GPIFADR[7:0] + OEC = 0xFF; // and as outputs + PORTECFG |= 0x80; // [8] as alt. func. GPIFADR[8] + OEE |= 0x80; // and as output + +// ...OR... tri-state GPIFADR[8:0] pins +// PORTCCFG = 0x00; // [7:0] as port I/O +// OEC = 0x00; // and as inputs +// PORTECFG &= 0x7F; // [8] as port I/O +// OEE &= 0x7F; // and as input + +// GPIF address pins update when GPIFADRH/L written + SYNCDELAY; // + GPIFADRH = 0x00; // bits[7:1] always 0 + SYNCDELAY; // + GPIFADRL = 0x00; // point to PERIPHERAL address 0x0000 + +// Configure GPIF FlowStates registers for Wave 0 of WaveData + FLOWSTATE = FlowStates[ 0 ]; + FLOWLOGIC = FlowStates[ 1 ]; + FLOWEQ0CTL = FlowStates[ 2 ]; + FLOWEQ1CTL = FlowStates[ 3 ]; + FLOWHOLDOFF = FlowStates[ 4 ]; + FLOWSTB = FlowStates[ 5 ]; + FLOWSTBEDGE = FlowStates[ 6 ]; + FLOWSTBHPERIOD = FlowStates[ 7 ]; +} + diff --git a/firmware/fx2/src/common/gpif.gpf b/firmware/fx2/src/common/gpif.gpf new file mode 100755 index 000000000..a954ac193 Binary files /dev/null and b/firmware/fx2/src/common/gpif.gpf differ diff --git a/firmware/fx2/src/common/init_gpif.c b/firmware/fx2/src/common/init_gpif.c new file mode 100644 index 000000000..edde919be --- /dev/null +++ b/firmware/fx2/src/common/init_gpif.c @@ -0,0 +1,59 @@ +/* + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003 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 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA + */ + +#include "usrp_common.h" + +// These are the tables generated by the Cypress GPIF Designer + +extern const char WaveData[128]; +extern const char FlowStates[36]; +extern const char InitData[7]; + +// The tool is kind of screwed up, in that it doesn't configure some +// of the ports correctly. We just use their tables and handle the +// initialization ourselves. They also declare that their static +// initialized data is in xdata, which screws us too. + +void +init_gpif (void) +{ + // we've already setup IFCONFIG before calling this... + + GPIFABORT = 0xFF; // abort any waveforms pending + SYNCDELAY; + + GPIFREADYCFG = InitData[ 0 ]; + GPIFCTLCFG = InitData[ 1 ]; + GPIFIDLECS = InitData[ 2 ]; + GPIFIDLECTL = InitData[ 3 ]; + // Hmmm, what's InitData[ 4 ] ... + GPIFWFSELECT = InitData[ 5 ]; + // GPIFREADYSTAT = InitData[ 6 ]; // I think this register is read only... + + { + BYTE i; + + for (i = 0; i < 128; i++){ + GPIF_WAVE_DATA[i] = WaveData[i]; + } + } + + FLOWSTATE = 0; /* ensure it's off */ +} diff --git a/firmware/fx2/src/common/usrp_common.c b/firmware/fx2/src/common/usrp_common.c new file mode 100644 index 000000000..0998653c2 --- /dev/null +++ b/firmware/fx2/src/common/usrp_common.c @@ -0,0 +1,109 @@ +/* + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003 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 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA + */ + +/* + * common code for USRP + */ + +#include "usrp_common.h" + +void init_board (void); + +void +init_usrp (void) +{ + CPUCS = bmCLKSPD1; // CPU runs @ 48 MHz + CKCON = 0; // MOVX takes 2 cycles + + // IFCLK is generated internally and runs at 48 MHz; GPIF "master mode" + + IFCONFIG = bmIFCLKSRC | bm3048MHZ | bmIFCLKOE | bmIFCLKPOL | bmIFGPIF; + SYNCDELAY; + + // configure IO ports (B and D are used by GPIF) + + IOA = bmPORT_A_INITIAL; // Port A initial state + OEA = bmPORT_A_OUTPUTS; // Port A direction register + + IOC = bmPORT_C_INITIAL; // Port C initial state + OEC = bmPORT_C_OUTPUTS; // Port C direction register + + IOE = bmPORT_E_INITIAL; // Port E initial state + OEE = bmPORT_E_OUTPUTS; // Port E direction register + + + // REVCTL = bmDYN_OUT | bmENH_PKT; // highly recommended by docs + // SYNCDELAY; + + // configure end points + + EP1OUTCFG = bmVALID | bmBULK; SYNCDELAY; + EP1INCFG = bmVALID | bmBULK | bmIN; SYNCDELAY; + + EP2CFG = bmVALID | bmBULK | bmQUADBUF; SYNCDELAY; // 512 quad bulk OUT + EP4CFG = 0; SYNCDELAY; // disabled + EP6CFG = bmVALID | bmBULK | bmQUADBUF | bmIN; SYNCDELAY; // 512 quad bulk IN + EP8CFG = 0; SYNCDELAY; // disabled + + // reset FIFOs + + FIFORESET = bmNAKALL; SYNCDELAY; + FIFORESET = 2; SYNCDELAY; + // FIFORESET = 4; SYNCDELAY; + FIFORESET = 6; SYNCDELAY; + // FIFORESET = 8; SYNCDELAY; + FIFORESET = 0; SYNCDELAY; + + // configure end point FIFOs + + // let core see 0 to 1 transistion of autoout bit + + EP2FIFOCFG = bmWORDWIDE; SYNCDELAY; + EP2FIFOCFG = bmAUTOOUT | bmWORDWIDE; SYNCDELAY; + EP6FIFOCFG = bmAUTOIN | bmWORDWIDE; SYNCDELAY; + + + // prime the pump + +#if 0 + EP2BCL = 0x80; SYNCDELAY; + EP2BCL = 0x80; SYNCDELAY; + EP2BCL = 0x80; SYNCDELAY; + EP2BCL = 0x80; SYNCDELAY; +#endif + + EP0BCH = 0; SYNCDELAY; + + // arm EP1OUT so we can receive "out" packets (TRM pg 8-8) + + EP1OUTBC = 0; SYNCDELAY; + + EP2GPIFFLGSEL = 0x01; SYNCDELAY; // For EP2OUT, GPIF uses EF flag + EP6GPIFFLGSEL = 0x02; SYNCDELAY; // For EP6IN, GPIF uses FF flag + + // set autoin length for EP6 + // FIXME should be f(enumeration) + + EP6AUTOINLENH = (512) >> 8; SYNCDELAY; // this is the length for high speed + EP6AUTOINLENL = (512) & 0xff; SYNCDELAY; + + init_board (); +} + diff --git a/firmware/fx2/src/common/usrp_globals.h b/firmware/fx2/src/common/usrp_globals.h new file mode 100644 index 000000000..445e9e6b4 --- /dev/null +++ b/firmware/fx2/src/common/usrp_globals.h @@ -0,0 +1,32 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef _USRP_GLOBALS_H_ +#define _USRP_GLOBALS_H_ + +extern unsigned char g_tx_enable; +extern unsigned char g_rx_enable; +extern unsigned char g_fpga_reset; +extern unsigned char g_rx_overrun; +extern unsigned char g_tx_underrun; + + +#endif /* _USRP_GLOBALS_H_ */ diff --git a/firmware/fx2/src/common/vectors.a51 b/firmware/fx2/src/common/vectors.a51 new file mode 100644 index 000000000..e9382ab84 --- /dev/null +++ b/firmware/fx2/src/common/vectors.a51 @@ -0,0 +1,180 @@ +;;; -*- asm -*- +;;; +;;; Copyright 2003 Free Software Foundation, Inc. +;;; +;;; This file is part of GNU Radio +;;; +;;; GNU Radio 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, or (at your option) +;;; any later version. +;;; +;;; GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +;;; the Free Software Foundation, Inc., 51 Franklin Street, +;;; Boston, MA 02110-1301, USA. +;;; + +;;; Interrupt vectors. + +;;; N.B. This object module must come first in the list of modules + + .module vectors + +;;; ---------------------------------------------------------------- +;;; standard FX2 interrupt vectors +;;; ---------------------------------------------------------------- + + .area CSEG (CODE) + .area GSINIT (CODE) + .area CSEG (CODE) +__standard_interrupt_vector:: +__reset_vector:: + ljmp s_GSINIT + + ;; 13 8-byte entries. We point them all at __isr_nop + ljmp __isr_nop ; 3 bytes + .ds 5 ; + 5 = 8 bytes for vector slot + ljmp __isr_nop + .ds 5 + ljmp __isr_nop + .ds 5 + ljmp __isr_nop + .ds 5 + ljmp __isr_nop + .ds 5 + ljmp __isr_nop + .ds 5 + ljmp __isr_nop + .ds 5 + ljmp __isr_nop + .ds 5 + ljmp __isr_nop + .ds 5 + ljmp __isr_nop + .ds 5 + ljmp __isr_nop + .ds 5 + ljmp __isr_nop + .ds 5 + ljmp __isr_nop + .ds 5 + +__isr_nop:: + reti + +;;; ---------------------------------------------------------------- +;;; the FIFO/GPIF autovector. 14 4-byte entries. +;;; must start on a 128 byte boundary. +;;; ---------------------------------------------------------------- + + . = __reset_vector + 0x0080 + +__fifo_gpif_autovector:: + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + + +;;; ---------------------------------------------------------------- +;;; the USB autovector. 32 4-byte entries. +;;; must start on a 256 byte boundary. +;;; ---------------------------------------------------------------- + + . = __reset_vector + 0x0100 + +__usb_autovector:: + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop + ljmp __isr_nop + nop diff --git a/firmware/fx2/src/usrp1/.gitignore b/firmware/fx2/src/usrp1/.gitignore new file mode 100644 index 000000000..54a9e9415 --- /dev/null +++ b/firmware/fx2/src/usrp1/.gitignore @@ -0,0 +1,20 @@ +/*.ihx +/*.lnk +/*.lst +/*.map +/*.mem +/*.rel +/*.rst +/*.sym +/blink_leds.asm +/usrp_common.asm +/command_loop.asm +/fpga.asm +/*.asm +/Makefile +/Makefile.in +/usrp_gpif.c +/usrp_gpif_inline.h +/Makefile.in +/burn-usrp2-eeprom +/burn-usrp4-eeprom diff --git a/firmware/fx2/src/usrp1/Makefile.am b/firmware/fx2/src/usrp1/Makefile.am new file mode 100644 index 000000000..5586e83a3 --- /dev/null +++ b/firmware/fx2/src/usrp1/Makefile.am @@ -0,0 +1,171 @@ +# +# Copyright 2003,2006 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +firmware2dir = $(prefix)/share/usrp/rev2 +firmware2_DATA = std.ihx + +# we put the same stuff in the rev4 directory +firmware4dir = $(prefix)/share/usrp/rev4 +firmware4_DATA = std.ihx + +EXTRA_DIST = \ + edit-gpif \ + _startup.a51 \ + blink_leds.c \ + board_specific.c \ + check_mdelay.c \ + check_udelay.c \ + eeprom_boot.a51 \ + eeprom_init.c \ + eeprom_io.c \ + eeprom_io.h \ + fpga_load.c \ + fpga_rev2.c \ + fpga_rev2.h \ + gpif.c \ + init_gpif.c \ + spi.c \ + spi.h \ + usb_descriptors.a51 \ + usrp_common.c \ + usrp_common.h \ + usrp_gpif.c \ + usrp_main.c \ + usrp_rev2_regs.h \ + vectors.a51 + + +DEFINES=-DHAVE_USRP2 +FW_INCLUDES=-I$(top_srcdir)/include \ + -I$(top_srcdir)/src/usrp1 \ + -I$(top_srcdir)/src/common \ + -I$(top_builddir)/src/common + +# with EA = 0, the FX2 implements a portion of the 8051 "external memory" +# on chip. This memory is mapped like this: +# +# The bottom 8K of memory (0x0000 - 0x1fff) is used for both data and +# code accesses. There's also 512 bytes for data only from 0xe000 - 0xe1ff. +# +# We tell the linker to start the xdata segment at 0x1800, 6K up from +# the bottom. + +MEMOPTS = --code-loc 0x0000 --code-size 0x1800 --xram-loc 0x1800 --xram-size 0x0800 \ + -Wl '-b USBDESCSEG = 0xE000' + +LIBOPTS = -L ../../lib libfx2.lib +LIBDEP = ../../lib/libfx2.lib + +LINKOPTS = $(MEMOPTS) $(LIBOPTS) + +EXECUTABLES = \ + std.ihx \ + blink_leds.ihx \ + check_mdelay.ihx \ + check_udelay.ihx \ + eeprom_boot.ihx + +STARTUP = _startup.rel + +noinst_SCRIPTS = \ + burn-usrp2-eeprom \ + burn-usrp4-eeprom + + +.c.rel: + $(XCC) $(FW_INCLUDES) $(DEFINES) \ + -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +.a51.rel: + test -f `basename '$<'` || $(LN_S) '$<' . + test -f ../common/`basename '$<'` -o \ + \! -f `dirname '$<'`/../common/`basename '$<'` \ + || $(LN_S) `dirname '$<'`/../common/`basename '$<'` ../common/`basename '$<'` + $(XAS) `basename '$<'` + + +EEPROM_BOOT_OBJS = eeprom_boot.rel eeprom_init.rel $(STARTUP) + +eeprom_boot.ihx: $(EEPROM_BOOT_OBJS) $(LIBDEP) + $(XCC) $(LINKOPTS) -o $@ $(EEPROM_BOOT_OBJS) + +burn-usrp2-eeprom: eeprom_boot.ihx + $(PYTHON) $(srcdir)/../common/build_eeprom.py -r2 eeprom_boot.ihx > $@ + chmod +x $@ + +burn-usrp4-eeprom: eeprom_boot.ihx + $(PYTHON) $(srcdir)/../common/build_eeprom.py -r4 eeprom_boot.ihx > $@ + chmod +x $@ + + +BLINK_LEDS_OBJS = blink_leds.rel usrp_common.rel board_specific.rel spi.rel $(STARTUP) + +blink_leds.ihx: $(BLINK_LEDS_OBJS) $(LIBDEP) + $(XCC) $(LINKOPTS) -o $@ $(BLINK_LEDS_OBJS) + + +CHECK_MDELAY_OBJS = check_mdelay.rel usrp_common.rel board_specific.rel spi.rel $(STARTUP) + +check_mdelay.ihx: $(CHECK_MDELAY_OBJS) $(LIBDEP) + $(XCC) $(LINKOPTS) -o $@ $(CHECK_MDELAY_OBJS) + + + +CHECK_UDELAY_OBJS = check_udelay.rel usrp_common.rel board_specific.rel spi.rel $(STARTUP) + +check_udelay.ihx: $(CHECK_UDELAY_OBJS) $(LIBDEP) + $(XCC) $(LINKOPTS) -o $@ $(CHECK_UDELAY_OBJS) + + + +USRP_OBJS = \ + vectors.rel \ + usrp_main.rel usrp_common.rel board_specific.rel \ + fpga_load.rel fpga_rev2.rel init_gpif.rel usrp_gpif.rel \ + usb_descriptors.rel spi.rel eeprom_io.rel $(STARTUP) + +std.ihx: $(USRP_OBJS) $(LIBDEP) + $(XCC) $(LINKOPTS) -o $@ $(USRP_OBJS) + +CLEANFILES = \ + *.ihx *.lnk *.lst *.map *.mem *.rel *.rst *.sym *.asm *.lib \ + usrp_gpif.c usrp_gpif_inline.h \ + burn-usrp2-eeprom \ + burn-usrp4-eeprom + +DISTCLEANFILES = \ + *.ihx *.lnk *.lst *.map *.mem *.rel *.rst *.sym *.asm *.lib + +# build gpif stuff + +all: usrp_gpif.c + +usrp_gpif.c usrp_gpif_inline.h : gpif.c + srcdir=$(srcdir) $(PYTHON) $(srcdir)/edit-gpif $(srcdir)/gpif.c usrp_gpif.c usrp_gpif_inline.h + + +# dependencies + +usrp_main.rel: usrp_gpif_inline.h +#usrp_main.rel: fpga.h usrp_common.h ../../include/usrp_commands.h usrp_gpif_inline.h ../../include/usrp_config.h usrp_rev2_regs.h ../../include/fx2regs.h +#usrp_common.rel: usrp_common.h ../../include/usrp_commands.h ../../include/usrp_config.h usrp_rev2_regs.h ../../include/fx2regs.h +#fpga.rel: usrp_common.h ../../include/usrp_commands.h fpga.h ../../include/usrp_config.h usrp_rev2_regs.h ../../include/fx2regs.h +#init_gpif.rel: usrp_common.h ../../include/usrp_config.h usrp_rev2_regs.h ../../include/fx2regs.h diff --git a/firmware/fx2/src/usrp1/_startup.a51 b/firmware/fx2/src/usrp1/_startup.a51 new file mode 100644 index 000000000..4f5309922 --- /dev/null +++ b/firmware/fx2/src/usrp1/_startup.a51 @@ -0,0 +1 @@ + .include "../common/_startup.a51" diff --git a/firmware/fx2/src/usrp1/blink_leds.c b/firmware/fx2/src/usrp1/blink_leds.c new file mode 100644 index 000000000..c633d5d48 --- /dev/null +++ b/firmware/fx2/src/usrp1/blink_leds.c @@ -0,0 +1 @@ +#include "../common/blink_leds.c" diff --git a/firmware/fx2/src/usrp1/board_specific.c b/firmware/fx2/src/usrp1/board_specific.c new file mode 100644 index 000000000..ef0081d84 --- /dev/null +++ b/firmware/fx2/src/usrp1/board_specific.c @@ -0,0 +1,113 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "usrp_common.h" +#include "spi.h" + +void +set_led_0 (unsigned char on) +{ + if (!on) // active low + USRP_PC |= bmPC_LED0; + else + USRP_PC &= ~bmPC_LED0; +} + +void +set_led_1 (unsigned char on) +{ + if (!on) // active low + USRP_PC |= bmPC_LED1; + else + USRP_PC &= ~bmPC_LED1; +} + +void +toggle_led_0 (void) +{ + USRP_PC ^= bmPC_LED0; +} + +void +toggle_led_1 (void) +{ + USRP_PC ^= bmPC_LED1; +} + +void +la_trace_init (void) +{ +} + +void +set_sleep_bits (unsigned char bits, unsigned char mask) +{ + // NOP on usrp1 +} + +static xdata unsigned char xbuf[1]; + +void +write_9862 (unsigned char which, unsigned char regno, unsigned char value) +{ + xbuf[0] = value; + + spi_write (0, regno & 0x3f, + which == 0 ? SPI_ENABLE_CODEC_A : SPI_ENABLE_CODEC_B, + SPI_FMT_MSB | SPI_FMT_HDR_1, + xbuf, 1); +} + +void +write_both_9862s (unsigned char regno, unsigned char value) +{ + xbuf[0] = value; + + spi_write (0, regno & 0x3f, + SPI_ENABLE_CODEC_A | SPI_ENABLE_CODEC_B, + SPI_FMT_MSB | SPI_FMT_HDR_1, + xbuf, 1); +} + +#define REG_RX_PWR_DN 1 +#define REG_TX_PWR_DN 8 +#define REG_TX_MODULATOR 20 + +static void +power_down_9862s (void) +{ + write_both_9862s (REG_RX_PWR_DN, 0x01); + write_both_9862s (REG_TX_PWR_DN, 0x0f); // pwr dn digital and analog_both + write_both_9862s (REG_TX_MODULATOR, 0x00); // coarse & fine modulators disabled +} + +void +init_board (void) +{ + la_trace_init (); + init_spi (); + + USRP_PC &= ~bmPC_nRESET; // active low reset + USRP_PC |= bmPC_nRESET; + + power_down_9862s (); +} diff --git a/firmware/fx2/src/usrp1/check_mdelay.c b/firmware/fx2/src/usrp1/check_mdelay.c new file mode 100644 index 000000000..ea4ccdb14 --- /dev/null +++ b/firmware/fx2/src/usrp1/check_mdelay.c @@ -0,0 +1 @@ +#include "../common/check_mdelay.c" diff --git a/firmware/fx2/src/usrp1/check_udelay.c b/firmware/fx2/src/usrp1/check_udelay.c new file mode 100644 index 000000000..d01622e5e --- /dev/null +++ b/firmware/fx2/src/usrp1/check_udelay.c @@ -0,0 +1 @@ +#include "../common/check_udelay.c" diff --git a/firmware/fx2/src/usrp1/edit-gpif b/firmware/fx2/src/usrp1/edit-gpif new file mode 100755 index 000000000..5367b75a5 --- /dev/null +++ b/firmware/fx2/src/usrp1/edit-gpif @@ -0,0 +1,114 @@ +#!/usr/bin/env python +# -*- Python -*- +# +# Copyright 2003 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + + +# Edit the gpif.c file generated by the Cypress GPIF Designer Tool and +# produce usrp_gpif.c, and usrp_gpif_inline.h, files suitable for our +# uses. + +import re +import string +import sys + +def check_flow_state (line, flow_state_dict): + mo = re.match (r'/\* Wave (\d) FlowStates \*/ (.*),', line) + if mo: + wave = int (mo.group (1)) + data = mo.group (2) + split = data.split (',', 8) + v = map (lambda x : int (x, 16), split) + # print "%s, %s" % (wave, data) + # print "split: ", split + # print "v : ", v + flow_state_dict[wave] = v + + +def delta (xseq, yseq): + # set subtraction + z = [] + for x in xseq: + if x not in yseq: + z.append (x) + return z + + +def write_define (output, name, pairs): + output.write ('#define %s()\t\\\n' % name) + output.write ('do {\t\t\t\t\t\\\n') + for reg, val in pairs: + output.write ('%14s = 0x%02x;\t\t\t\\\n' % (reg, val)) + output.write ('} while (0)\n\n') + +def write_inlines (output, dict): + regs = ['FLOWSTATE', 'FLOWLOGIC', 'FLOWEQ0CTL', 'FLOWEQ1CTL', 'FLOWHOLDOFF', + 'FLOWSTB', 'FLOWSTBEDGE', 'FLOWSTBHPERIOD', 'GPIFHOLDAMOUNT'] + + READ_FLOW_STATE = 2 + WRITE_FLOW_STATE = 3 + + read_info = zip (regs, dict[READ_FLOW_STATE]) + write_info = zip (regs, dict[WRITE_FLOW_STATE]) + + output.write ('''/* + * Machine generated by "edit-gpif". Do not edit by hand. + */ + +''') + write_define (output, 'setup_flowstate_common', read_info) + write_define (output, 'setup_flowstate_read', delta (read_info, write_info)) + write_define (output, 'setup_flowstate_write', delta (write_info, read_info)) + + +def edit_gpif (input_name, output_name, inline_name): + input = open (input_name, 'r') + output = open (output_name, 'w') + inline = open (inline_name, 'w') + flow_state_dict = {} + + output.write ('''/* + * Machine generated by "edit-gpif". Do not edit by hand. + */ + +''') + + while 1: + line = input.readline () + line = string.replace (line, '\r','') + line = re.sub (r' *$', r'', line) + + check_flow_state (line, flow_state_dict) + + line = re.sub (r'#include', r'// #include', line) + line = re.sub (r'xdata ', r'', line) + if re.search (r'GpifInit', line): + break + + output.write (line) + + output.close () + write_inlines (inline, flow_state_dict) + inline.close () + + +# gpif.c usrp_gpif.c usrp_gpif_inline.h +edit_gpif (sys.argv[1], sys.argv[2], sys.argv[3]) diff --git a/firmware/fx2/src/usrp1/eeprom_boot.a51 b/firmware/fx2/src/usrp1/eeprom_boot.a51 new file mode 100644 index 000000000..65e452668 --- /dev/null +++ b/firmware/fx2/src/usrp1/eeprom_boot.a51 @@ -0,0 +1,573 @@ +;-------------------------------------------------------- +; Hand tweaked minimal eeprom boot code +;-------------------------------------------------------- + .module eeprom_boot + .optsdcc -mmcs51 --model-small + +;-------------------------------------------------------- +; Public variables in this module +;-------------------------------------------------------- + .globl _eeprom_init + .globl _EP8FIFOBUF + .globl _EP6FIFOBUF + .globl _EP4FIFOBUF + .globl _EP2FIFOBUF + .globl _EP1INBUF + .globl _EP1OUTBUF + .globl _EP0BUF + .globl _CT4 + .globl _CT3 + .globl _CT2 + .globl _CT1 + .globl _USBTEST + .globl _TESTCFG + .globl _DBUG + .globl _UDMACRCQUAL + .globl _UDMACRCL + .globl _UDMACRCH + .globl _GPIFHOLDAMOUNT + .globl _FLOWSTBHPERIOD + .globl _FLOWSTBEDGE + .globl _FLOWSTB + .globl _FLOWHOLDOFF + .globl _FLOWEQ1CTL + .globl _FLOWEQ0CTL + .globl _FLOWLOGIC + .globl _FLOWSTATE + .globl _GPIFABORT + .globl _GPIFREADYSTAT + .globl _GPIFREADYCFG + .globl _XGPIFSGLDATLNOX + .globl _XGPIFSGLDATLX + .globl _XGPIFSGLDATH + .globl _EP8GPIFTRIG + .globl _EP8GPIFPFSTOP + .globl _EP8GPIFFLGSEL + .globl _EP6GPIFTRIG + .globl _EP6GPIFPFSTOP + .globl _EP6GPIFFLGSEL + .globl _EP4GPIFTRIG + .globl _EP4GPIFPFSTOP + .globl _EP4GPIFFLGSEL + .globl _EP2GPIFTRIG + .globl _EP2GPIFPFSTOP + .globl _EP2GPIFFLGSEL + .globl _GPIFTCB0 + .globl _GPIFTCB1 + .globl _GPIFTCB2 + .globl _GPIFTCB3 + .globl _GPIFADRL + .globl _GPIFADRH + .globl _GPIFCTLCFG + .globl _GPIFIDLECTL + .globl _GPIFIDLECS + .globl _GPIFWFSELECT + .globl _SETUPDAT + .globl _SUDPTRCTL + .globl _SUDPTRL + .globl _SUDPTRH + .globl _EP8FIFOBCL + .globl _EP8FIFOBCH + .globl _EP6FIFOBCL + .globl _EP6FIFOBCH + .globl _EP4FIFOBCL + .globl _EP4FIFOBCH + .globl _EP2FIFOBCL + .globl _EP2FIFOBCH + .globl _EP8FIFOFLGS + .globl _EP6FIFOFLGS + .globl _EP4FIFOFLGS + .globl _EP2FIFOFLGS + .globl _EP8CS + .globl _EP6CS + .globl _EP4CS + .globl _EP2CS + .globl _EP1INCS + .globl _EP1OUTCS + .globl _EP0CS + .globl _EP8BCL + .globl _EP8BCH + .globl _EP6BCL + .globl _EP6BCH + .globl _EP4BCL + .globl _EP4BCH + .globl _EP2BCL + .globl _EP2BCH + .globl _EP1INBC + .globl _EP1OUTBC + .globl _EP0BCL + .globl _EP0BCH + .globl _FNADDR + .globl _MICROFRAME + .globl _USBFRAMEL + .globl _USBFRAMEH + .globl _TOGCTL + .globl _WAKEUPCS + .globl _SUSPEND + .globl _USBCS + .globl _XAUTODAT2 + .globl _XAUTODAT1 + .globl _I2CTL + .globl _I2DAT + .globl _I2CS + .globl _PORTECFG + .globl _PORTCCFG + .globl _PORTACFG + .globl _INTSETUP + .globl _INT4IVEC + .globl _INT2IVEC + .globl _CLRERRCNT + .globl _ERRCNTLIM + .globl _USBERRIRQ + .globl _USBERRIE + .globl _GPIFIRQ + .globl _GPIFIE + .globl _EPIRQ + .globl _EPIE + .globl _USBIRQ + .globl _USBIE + .globl _NAKIRQ + .globl _NAKIE + .globl _IBNIRQ + .globl _IBNIE + .globl _EP8FIFOIRQ + .globl _EP8FIFOIE + .globl _EP6FIFOIRQ + .globl _EP6FIFOIE + .globl _EP4FIFOIRQ + .globl _EP4FIFOIE + .globl _EP2FIFOIRQ + .globl _EP2FIFOIE + .globl _OUTPKTEND + .globl _INPKTEND + .globl _EP8ISOINPKTS + .globl _EP6ISOINPKTS + .globl _EP4ISOINPKTS + .globl _EP2ISOINPKTS + .globl _EP8FIFOPFL + .globl _EP8FIFOPFH + .globl _EP6FIFOPFL + .globl _EP6FIFOPFH + .globl _EP4FIFOPFL + .globl _EP4FIFOPFH + .globl _EP2FIFOPFL + .globl _EP2FIFOPFH + .globl _EP8AUTOINLENL + .globl _EP8AUTOINLENH + .globl _EP6AUTOINLENL + .globl _EP6AUTOINLENH + .globl _EP4AUTOINLENL + .globl _EP4AUTOINLENH + .globl _EP2AUTOINLENL + .globl _EP2AUTOINLENH + .globl _EP8FIFOCFG + .globl _EP6FIFOCFG + .globl _EP4FIFOCFG + .globl _EP2FIFOCFG + .globl _EP8CFG + .globl _EP6CFG + .globl _EP4CFG + .globl _EP2CFG + .globl _EP1INCFG + .globl _EP1OUTCFG + .globl _REVCTL + .globl _REVID + .globl _FIFOPINPOLAR + .globl _UART230 + .globl _BPADDRL + .globl _BPADDRH + .globl _BREAKPT + .globl _FIFORESET + .globl _PINFLAGSCD + .globl _PINFLAGSAB + .globl _IFCONFIG + .globl _CPUCS + .globl _RES_WAVEDATA_END + .globl _GPIF_WAVE_DATA +;-------------------------------------------------------- +; special function registers +;-------------------------------------------------------- +_IOA = 0x0080 +_SP = 0x0081 +_DPL = 0x0082 +_DPH = 0x0083 +_DPL1 = 0x0084 +_DPH1 = 0x0085 +_DPS = 0x0086 +_PCON = 0x0087 +_TCON = 0x0088 +_TMOD = 0x0089 +_TL0 = 0x008a +_TL1 = 0x008b +_TH0 = 0x008c +_TH1 = 0x008d +_CKCON = 0x008e +_IOB = 0x0090 +_EXIF = 0x0091 +_MPAGE = 0x0092 +_SCON0 = 0x0098 +_SBUF0 = 0x0099 +_APTR1H = 0x009a +_APTR1L = 0x009b +_AUTODAT1 = 0x009c +_AUTOPTRH2 = 0x009d +_AUTOPTRL2 = 0x009e +_AUTODAT2 = 0x009f +_IOC = 0x00a0 +_INT2CLR = 0x00a1 +_INT4CLR = 0x00a2 +_IE = 0x00a8 +_EP2468STAT = 0x00aa +_EP24FIFOFLGS = 0x00ab +_EP68FIFOFLGS = 0x00ac +_AUTOPTRSETUP = 0x00af +_IOD = 0x00b0 +_IOE = 0x00b1 +_OEA = 0x00b2 +_OEB = 0x00b3 +_OEC = 0x00b4 +_OED = 0x00b5 +_OEE = 0x00b6 +_IP = 0x00b8 +_EP01STAT = 0x00ba +_GPIFTRIG = 0x00bb +_GPIFSGLDATH = 0x00bd +_GPIFSGLDATLX = 0x00be +_GPIFSGLDATLNOX = 0x00bf +_SCON1 = 0x00c0 +_SBUF1 = 0x00c1 +_T2CON = 0x00c8 +_RCAP2L = 0x00ca +_RCAP2H = 0x00cb +_TL2 = 0x00cc +_TH2 = 0x00cd +_PSW = 0x00d0 +_EICON = 0x00d8 +_ACC = 0x00e0 +_EIE = 0x00e8 +_B = 0x00f0 +_EIP = 0x00f8 +;-------------------------------------------------------- +; special function bits +;-------------------------------------------------------- +_SEL = 0x0086 +_IT0 = 0x0088 +_IE0 = 0x0089 +_IT1 = 0x008a +_IE1 = 0x008b +_TR0 = 0x008c +_TF0 = 0x008d +_TR1 = 0x008e +_TF1 = 0x008f +_RI = 0x0098 +_TI = 0x0099 +_RB8 = 0x009a +_TB8 = 0x009b +_REN = 0x009c +_SM2 = 0x009d +_SM1 = 0x009e +_SM0 = 0x009f +_EX0 = 0x00a8 +_ET0 = 0x00a9 +_EX1 = 0x00aa +_ET1 = 0x00ab +_ES0 = 0x00ac +_ET2 = 0x00ad +_ES1 = 0x00ae +_EA = 0x00af +_PX0 = 0x00b8 +_PT0 = 0x00b9 +_PX1 = 0x00ba +_PT1 = 0x00bb +_PS0 = 0x00bc +_PT2 = 0x00bd +_PS1 = 0x00be +_RI1 = 0x00c0 +_TI1 = 0x00c1 +_RB81 = 0x00c2 +_TB81 = 0x00c3 +_REN1 = 0x00c4 +_SM21 = 0x00c5 +_SM11 = 0x00c6 +_SM01 = 0x00c7 +_CP_RL2 = 0x00c8 +_C_T2 = 0x00c9 +_TR2 = 0x00ca +_EXEN2 = 0x00cb +_TCLK = 0x00cc +_RCLK = 0x00cd +_EXF2 = 0x00ce +_TF2 = 0x00cf +_P = 0x00d0 +_FL = 0x00d1 +_OV = 0x00d2 +_RS0 = 0x00d3 +_RS1 = 0x00d4 +_F0 = 0x00d5 +_AC = 0x00d6 +_CY = 0x00d7 +_INT6 = 0x00db +_RESI = 0x00dc +_ERESI = 0x00dd +_SMOD1 = 0x00df +_EIUSB = 0x00e8 +_EI2C = 0x00e9 +_EIEX4 = 0x00ea +_EIEX5 = 0x00eb +_EIEX6 = 0x00ec +_PUSB = 0x00f8 +_PI2C = 0x00f9 +_EIPX4 = 0x00fa +_EIPX5 = 0x00fb +_EIPX6 = 0x00fc +_bitS_CLK = 0x0080 +_bitS_OUT = 0x0081 +_bitS_IN = 0x0082 +_bitALTERA_DATA0 = 0x00a1 +_bitALTERA_DCLK = 0x00a3 +;-------------------------------------------------------- +; overlayable register banks +;-------------------------------------------------------- + .area REG_BANK_0 (REL,OVR,DATA) + .ds 8 +;-------------------------------------------------------- +; internal ram data +;-------------------------------------------------------- + .area DSEG (DATA) +;-------------------------------------------------------- +; overlayable items in internal ram +;-------------------------------------------------------- + .area OSEG (OVR,DATA) +;-------------------------------------------------------- +; Stack segment in internal ram +;-------------------------------------------------------- + .area SSEG (DATA) +__start__stack: + .ds 1 + +;-------------------------------------------------------- +; indirectly addressable internal ram data +;-------------------------------------------------------- + .area ISEG (DATA) +;-------------------------------------------------------- +; bit data +;-------------------------------------------------------- + .area BSEG (BIT) +;-------------------------------------------------------- +; external ram data +;-------------------------------------------------------- + .area XSEG (XDATA) +_GPIF_WAVE_DATA = 0xe400 +_RES_WAVEDATA_END = 0xe480 +_CPUCS = 0xe600 +_IFCONFIG = 0xe601 +_PINFLAGSAB = 0xe602 +_PINFLAGSCD = 0xe603 +_FIFORESET = 0xe604 +_BREAKPT = 0xe605 +_BPADDRH = 0xe606 +_BPADDRL = 0xe607 +_UART230 = 0xe608 +_FIFOPINPOLAR = 0xe609 +_REVID = 0xe60a +_REVCTL = 0xe60b +_EP1OUTCFG = 0xe610 +_EP1INCFG = 0xe611 +_EP2CFG = 0xe612 +_EP4CFG = 0xe613 +_EP6CFG = 0xe614 +_EP8CFG = 0xe615 +_EP2FIFOCFG = 0xe618 +_EP4FIFOCFG = 0xe619 +_EP6FIFOCFG = 0xe61a +_EP8FIFOCFG = 0xe61b +_EP2AUTOINLENH = 0xe620 +_EP2AUTOINLENL = 0xe621 +_EP4AUTOINLENH = 0xe622 +_EP4AUTOINLENL = 0xe623 +_EP6AUTOINLENH = 0xe624 +_EP6AUTOINLENL = 0xe625 +_EP8AUTOINLENH = 0xe626 +_EP8AUTOINLENL = 0xe627 +_EP2FIFOPFH = 0xe630 +_EP2FIFOPFL = 0xe631 +_EP4FIFOPFH = 0xe632 +_EP4FIFOPFL = 0xe633 +_EP6FIFOPFH = 0xe634 +_EP6FIFOPFL = 0xe635 +_EP8FIFOPFH = 0xe636 +_EP8FIFOPFL = 0xe637 +_EP2ISOINPKTS = 0xe640 +_EP4ISOINPKTS = 0xe641 +_EP6ISOINPKTS = 0xe642 +_EP8ISOINPKTS = 0xe643 +_INPKTEND = 0xe648 +_OUTPKTEND = 0xe649 +_EP2FIFOIE = 0xe650 +_EP2FIFOIRQ = 0xe651 +_EP4FIFOIE = 0xe652 +_EP4FIFOIRQ = 0xe653 +_EP6FIFOIE = 0xe654 +_EP6FIFOIRQ = 0xe655 +_EP8FIFOIE = 0xe656 +_EP8FIFOIRQ = 0xe657 +_IBNIE = 0xe658 +_IBNIRQ = 0xe659 +_NAKIE = 0xe65a +_NAKIRQ = 0xe65b +_USBIE = 0xe65c +_USBIRQ = 0xe65d +_EPIE = 0xe65e +_EPIRQ = 0xe65f +_GPIFIE = 0xe660 +_GPIFIRQ = 0xe661 +_USBERRIE = 0xe662 +_USBERRIRQ = 0xe663 +_ERRCNTLIM = 0xe664 +_CLRERRCNT = 0xe665 +_INT2IVEC = 0xe666 +_INT4IVEC = 0xe667 +_INTSETUP = 0xe668 +_PORTACFG = 0xe670 +_PORTCCFG = 0xe671 +_PORTECFG = 0xe672 +_I2CS = 0xe678 +_I2DAT = 0xe679 +_I2CTL = 0xe67a +_XAUTODAT1 = 0xe67b +_XAUTODAT2 = 0xe67c +_USBCS = 0xe680 +_SUSPEND = 0xe681 +_WAKEUPCS = 0xe682 +_TOGCTL = 0xe683 +_USBFRAMEH = 0xe684 +_USBFRAMEL = 0xe685 +_MICROFRAME = 0xe686 +_FNADDR = 0xe687 +_EP0BCH = 0xe68a +_EP0BCL = 0xe68b +_EP1OUTBC = 0xe68d +_EP1INBC = 0xe68f +_EP2BCH = 0xe690 +_EP2BCL = 0xe691 +_EP4BCH = 0xe694 +_EP4BCL = 0xe695 +_EP6BCH = 0xe698 +_EP6BCL = 0xe699 +_EP8BCH = 0xe69c +_EP8BCL = 0xe69d +_EP0CS = 0xe6a0 +_EP1OUTCS = 0xe6a1 +_EP1INCS = 0xe6a2 +_EP2CS = 0xe6a3 +_EP4CS = 0xe6a4 +_EP6CS = 0xe6a5 +_EP8CS = 0xe6a6 +_EP2FIFOFLGS = 0xe6a7 +_EP4FIFOFLGS = 0xe6a8 +_EP6FIFOFLGS = 0xe6a9 +_EP8FIFOFLGS = 0xe6aa +_EP2FIFOBCH = 0xe6ab +_EP2FIFOBCL = 0xe6ac +_EP4FIFOBCH = 0xe6ad +_EP4FIFOBCL = 0xe6ae +_EP6FIFOBCH = 0xe6af +_EP6FIFOBCL = 0xe6b0 +_EP8FIFOBCH = 0xe6b1 +_EP8FIFOBCL = 0xe6b2 +_SUDPTRH = 0xe6b3 +_SUDPTRL = 0xe6b4 +_SUDPTRCTL = 0xe6b5 +_SETUPDAT = 0xe6b8 +_GPIFWFSELECT = 0xe6c0 +_GPIFIDLECS = 0xe6c1 +_GPIFIDLECTL = 0xe6c2 +_GPIFCTLCFG = 0xe6c3 +_GPIFADRH = 0xe6c4 +_GPIFADRL = 0xe6c5 +_GPIFTCB3 = 0xe6ce +_GPIFTCB2 = 0xe6cf +_GPIFTCB1 = 0xe6d0 +_GPIFTCB0 = 0xe6d1 +_EP2GPIFFLGSEL = 0xe6d2 +_EP2GPIFPFSTOP = 0xe6d3 +_EP2GPIFTRIG = 0xe6d4 +_EP4GPIFFLGSEL = 0xe6da +_EP4GPIFPFSTOP = 0xe6db +_EP4GPIFTRIG = 0xe6dc +_EP6GPIFFLGSEL = 0xe6e2 +_EP6GPIFPFSTOP = 0xe6e3 +_EP6GPIFTRIG = 0xe6e4 +_EP8GPIFFLGSEL = 0xe6ea +_EP8GPIFPFSTOP = 0xe6eb +_EP8GPIFTRIG = 0xe6ec +_XGPIFSGLDATH = 0xe6f0 +_XGPIFSGLDATLX = 0xe6f1 +_XGPIFSGLDATLNOX = 0xe6f2 +_GPIFREADYCFG = 0xe6f3 +_GPIFREADYSTAT = 0xe6f4 +_GPIFABORT = 0xe6f5 +_FLOWSTATE = 0xe6c6 +_FLOWLOGIC = 0xe6c7 +_FLOWEQ0CTL = 0xe6c8 +_FLOWEQ1CTL = 0xe6c9 +_FLOWHOLDOFF = 0xe6ca +_FLOWSTB = 0xe6cb +_FLOWSTBEDGE = 0xe6cc +_FLOWSTBHPERIOD = 0xe6cd +_GPIFHOLDAMOUNT = 0xe60c +_UDMACRCH = 0xe67d +_UDMACRCL = 0xe67e +_UDMACRCQUAL = 0xe67f +_DBUG = 0xe6f8 +_TESTCFG = 0xe6f9 +_USBTEST = 0xe6fa +_CT1 = 0xe6fb +_CT2 = 0xe6fc +_CT3 = 0xe6fd +_CT4 = 0xe6fe +_EP0BUF = 0xe740 +_EP1OUTBUF = 0xe780 +_EP1INBUF = 0xe7c0 +_EP2FIFOBUF = 0xf000 +_EP4FIFOBUF = 0xf400 +_EP6FIFOBUF = 0xf800 +_EP8FIFOBUF = 0xfc00 +;-------------------------------------------------------- +; external initialized ram data +;-------------------------------------------------------- +;-------------------------------------------------------- +; interrupt vector +;-------------------------------------------------------- + .area CSEG (CODE) +__interrupt_vect: + ljmp __sdcc_gsinit_startup +;-------------------------------------------------------- +; global & static initialisations +;-------------------------------------------------------- + .area GSINIT (CODE) + .area GSFINAL (CODE) + .area GSINIT (CODE) +__sdcc_gsinit_startup: + mov sp,#__start__stack - 1 + lcall __sdcc_external_startup + mov a,dpl + jz __sdcc_init_data + ljmp __sdcc_program_startup +__sdcc_init_data: + .area GSFINAL (CODE) + ljmp __sdcc_program_startup +;-------------------------------------------------------- +; Home +;-------------------------------------------------------- + .area HOME (CODE) + .area CSEG (CODE) +;-------------------------------------------------------- +; code +;-------------------------------------------------------- + .area CSEG (CODE) +__sdcc_program_startup: + lcall _eeprom_init +; return from _eeprom_init will spin here + sjmp . + .area CSEG (CODE) diff --git a/firmware/fx2/src/usrp1/eeprom_init.c b/firmware/fx2/src/usrp1/eeprom_init.c new file mode 100644 index 000000000..a6f6cbe2d --- /dev/null +++ b/firmware/fx2/src/usrp1/eeprom_init.c @@ -0,0 +1,116 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "usrp_common.h" +#include "usrp_commands.h" +#include "spi.h" + +/* + * the host side fpga loader code pushes an MD5 hash of the bitstream + * into hash1. + */ +#define USRP_HASH_SIZE 16 +xdata at USRP_HASH_SLOT_0_ADDR unsigned char hash0[USRP_HASH_SIZE]; + + +#define enable_codecs() USRP_PA &= ~(bmPA_SEN_CODEC_A | bmPA_SEN_CODEC_B) +#define disable_all() USRP_PA |= (bmPA_SEN_CODEC_A | bmPA_SEN_CODEC_B) + +static void +write_byte_msb (unsigned char v); + +void +write_both_9862s (unsigned char header_lo, unsigned char v) +{ + enable_codecs (); + + write_byte_msb (header_lo); + write_byte_msb (v); + + disable_all (); +} + +// ---------------------------------------------------------------- + +static void +write_byte_msb (unsigned char v) +{ + unsigned char n = 8; + do { + v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit) + bitS_OUT = v & 0x1; + bitS_CLK = 1; + bitS_CLK = 0; + } while (--n != 0); +} + +// ---------------------------------------------------------------- + +#define REG_RX_PWR_DN 1 +#define REG_TX_PWR_DN 8 +#define REG_TX_MODULATOR 20 + +void eeprom_init (void) +{ + unsigned short counter; + unsigned char i; + + // configure IO ports (B and D are used by GPIF) + + IOA = bmPORT_A_INITIAL; // Port A initial state + OEA = bmPORT_A_OUTPUTS; // Port A direction register + + IOC = bmPORT_C_INITIAL; // Port C initial state + OEC = bmPORT_C_OUTPUTS; // Port C direction register + + IOE = bmPORT_E_INITIAL; // Port E initial state + OEE = bmPORT_E_OUTPUTS; // Port E direction register + + EP0BCH = 0; SYNCDELAY; + + // USBCS &= ~bmRENUM; // chip firmware handles commands + USBCS = 0; // chip firmware handles commands + + USRP_PC &= ~bmPC_nRESET; // active low reset + USRP_PC |= bmPC_nRESET; + + // init_spi (); + bitS_OUT = 0; /* idle state has CLK = 0 */ + + write_both_9862s (REG_RX_PWR_DN, 0x01); + write_both_9862s (REG_TX_PWR_DN, 0x0f); // pwr dn digital and analog_both + write_both_9862s (REG_TX_MODULATOR, 0x00); // coarse & fine modulators disabled + + // zero firmware hash slot + i = 0; + do { + hash0[i] = 0; + i++; + } while (i != USRP_HASH_SIZE); + + counter = 0; + while (1){ + counter++; + if (counter & 0x8000) + IOC ^= bmPC_LED0; + } +} diff --git a/firmware/fx2/src/usrp1/eeprom_io.c b/firmware/fx2/src/usrp1/eeprom_io.c new file mode 100644 index 000000000..9eeb53636 --- /dev/null +++ b/firmware/fx2/src/usrp1/eeprom_io.c @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "eeprom_io.h" +#include "i2c.h" +#include "delay.h" + +// returns non-zero if successful, else 0 +unsigned char +eeprom_read (unsigned char i2c_addr, unsigned char eeprom_offset, + xdata unsigned char *buf, unsigned char len) +{ + // We setup a random read by first doing a "zero byte write". + // Writes carry an address. Reads use an implicit address. + + static xdata unsigned char cmd[1]; + cmd[0] = eeprom_offset; + if (!i2c_write(i2c_addr, cmd, 1)) + return 0; + + return i2c_read(i2c_addr, buf, len); +} + + +#if 0 + +// returns non-zero if successful, else 0 +unsigned char +eeprom_write (unsigned char i2c_addr, unsigned char eeprom_offset, + const xdata unsigned char *buf, unsigned char len) +{ + static xdata unsigned char cmd[2]; + unsigned char ok; + + while (len-- > 0){ + cmd[0] = eeprom_offset++; + cmd[1] = *buf++; + ok = i2c_write(i2c_addr, cmd, 2); + mdelay(10); // delay 10ms worst case write time + if (!ok) + return 0; + } + return 1; +} + +#endif diff --git a/firmware/fx2/src/usrp1/eeprom_io.h b/firmware/fx2/src/usrp1/eeprom_io.h new file mode 100644 index 000000000..558017b12 --- /dev/null +++ b/firmware/fx2/src/usrp1/eeprom_io.h @@ -0,0 +1,38 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_EEPROM_IO_H +#define INCLUDED_EEPROM_IO_H + + +// returns non-zero if successful, else 0 +unsigned char +eeprom_read (unsigned char i2c_addr, unsigned char eeprom_offset, + xdata unsigned char *buf, unsigned char len); + +// returns non-zero if successful, else 0 +unsigned char +eeprom_write (unsigned char i2c_addr, unsigned char eeprom_offset, + const xdata unsigned char *buf, unsigned char len); + + +#endif /* INCLUDED_EEPROM_IO_H */ diff --git a/firmware/fx2/src/usrp1/fpga_load.c b/firmware/fx2/src/usrp1/fpga_load.c new file mode 100644 index 000000000..b0256e925 --- /dev/null +++ b/firmware/fx2/src/usrp1/fpga_load.c @@ -0,0 +1 @@ +#include "../common/fpga_load.c" diff --git a/firmware/fx2/src/usrp1/fpga_rev2.c b/firmware/fx2/src/usrp1/fpga_rev2.c new file mode 100644 index 000000000..cca961dc4 --- /dev/null +++ b/firmware/fx2/src/usrp1/fpga_rev2.c @@ -0,0 +1,122 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "fpga.h" +#include "fpga_regs_common.h" +#include "usrp_common.h" +#include "usrp_globals.h" +#include "spi.h" + +unsigned char g_tx_reset = 0; +unsigned char g_rx_reset = 0; + +void +fpga_write_reg (unsigned char regno, const xdata unsigned char *regval) +{ + spi_write (0, 0x00 | (regno & 0x7f), + SPI_ENABLE_FPGA, + SPI_FMT_MSB | SPI_FMT_HDR_1, + regval, 4); +} + + +static xdata unsigned char regval[4] = {0, 0, 0, 0}; + +static void +write_fpga_master_ctrl (void) +{ + unsigned char v = 0; + if (g_tx_enable) + v |= bmFR_MC_ENABLE_TX; + if (g_rx_enable) + v |= bmFR_MC_ENABLE_RX; + if (g_tx_reset) + v |= bmFR_MC_RESET_TX; + if (g_rx_reset) + v |= bmFR_MC_RESET_RX; + regval[3] = v; + + fpga_write_reg (FR_MASTER_CTRL, regval); +} + +// Resets both AD9862's and the FPGA serial bus interface. + +void +fpga_set_reset (unsigned char on) +{ + on &= 0x1; + + if (on){ + USRP_PC &= ~bmPC_nRESET; // active low + g_tx_enable = 0; + g_rx_enable = 0; + g_tx_reset = 0; + g_rx_reset = 0; + } + else + USRP_PC |= bmPC_nRESET; +} + +void +fpga_set_tx_enable (unsigned char on) +{ + on &= 0x1; + g_tx_enable = on; + + write_fpga_master_ctrl (); + + if (on){ + g_tx_underrun = 0; + fpga_clear_flags (); + } +} + +void +fpga_set_rx_enable (unsigned char on) +{ + on &= 0x1; + g_rx_enable = on; + + write_fpga_master_ctrl (); + if (on){ + g_rx_overrun = 0; + fpga_clear_flags (); + } +} + +void +fpga_set_tx_reset (unsigned char on) +{ + on &= 0x1; + g_tx_reset = on; + + write_fpga_master_ctrl (); +} + +void +fpga_set_rx_reset (unsigned char on) +{ + on &= 0x1; + g_rx_reset = on; + + write_fpga_master_ctrl (); +} diff --git a/firmware/fx2/src/usrp1/fpga_rev2.h b/firmware/fx2/src/usrp1/fpga_rev2.h new file mode 100644 index 000000000..54ec3f9fa --- /dev/null +++ b/firmware/fx2/src/usrp1/fpga_rev2.h @@ -0,0 +1,58 @@ +/* + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003,2004 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 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA + */ + +#ifndef INCLUDED_FPGA_REV1_H +#define INCLUDED_FPGA_REV1_H + +void fpga_set_reset (unsigned char v); +void fpga_set_tx_enable (unsigned char v); +void fpga_set_rx_enable (unsigned char v); +void fpga_set_tx_reset (unsigned char v); +void fpga_set_rx_reset (unsigned char v); + +unsigned char fpga_has_room_for_packet (void); +unsigned char fpga_has_packet_avail (void); + +#if (UC_BOARD_HAS_FPGA) +/* + * return TRUE iff FPGA internal fifo has room for 512 bytes. + */ +#define fpga_has_room_for_packet() (GPIFREADYSTAT & bmFPGA_HAS_SPACE) + +/* + * return TRUE iff FPGA internal fifo has at least 512 bytes available. + */ +#define fpga_has_packet_avail() (GPIFREADYSTAT & bmFPGA_PKT_AVAIL) + +#else /* no FPGA on board. fake it. */ + +#define fpga_has_room_for_packet() TRUE +#define fpga_has_packet_avail() TRUE + +#endif + +#define fpga_clear_flags() \ + do { \ + USRP_PE |= bmPE_FPGA_CLR_STATUS; \ + USRP_PE &= ~bmPE_FPGA_CLR_STATUS; \ + } while (0) + + +#endif /* INCLUDED_FPGA_REV1_H */ diff --git a/firmware/fx2/src/usrp1/gpif.c b/firmware/fx2/src/usrp1/gpif.c new file mode 100644 index 000000000..f6745a43b --- /dev/null +++ b/firmware/fx2/src/usrp1/gpif.c @@ -0,0 +1,292 @@ +// This program configures the General Programmable Interface (GPIF) for FX2. +// Please do not modify sections of text which are marked as "DO NOT EDIT ...". +// +// DO NOT EDIT ... +// GPIF Initialization +// Interface Timing Async +// Internal Ready Init IntRdy=1 +// CTL Out Tristate-able Binary +// SingleWrite WF Select 1 +// SingleRead WF Select 0 +// FifoWrite WF Select 3 +// FifoRead WF Select 2 +// Data Bus Idle Drive Tristate +// END DO NOT EDIT + +// DO NOT EDIT ... +// GPIF Wave Names +// Wave 0 = singlerd +// Wave 1 = singlewr +// Wave 2 = FIFORd +// Wave 3 = FIFOWr + +// GPIF Ctrl Outputs Level +// CTL 0 = WEN# CMOS +// CTL 1 = REN# CMOS +// CTL 2 = OE# CMOS +// CTL 3 = CLRST CMOS +// CTL 4 = unused CMOS +// CTL 5 = BOGUS CMOS + +// GPIF Rdy Inputs +// RDY0 = EF# +// RDY1 = FF# +// RDY2 = unused +// RDY3 = unused +// RDY4 = unused +// RDY5 = TCXpire +// FIFOFlag = FIFOFlag +// IntReady = IntReady +// END DO NOT EDIT +// DO NOT EDIT ... +// +// GPIF Waveform 0: singlerd +// +// Interval 0 1 2 3 4 5 6 Idle (7) +// _________ _________ _________ _________ _________ _________ _________ _________ +// +// AddrMode Same Val Same Val Same Val Same Val Same Val Same Val Same Val +// DataMode NO Data NO Data NO Data NO Data NO Data NO Data NO Data +// NextData SameData SameData SameData SameData SameData SameData SameData +// Int Trig No Int No Int No Int No Int No Int No Int No Int +// IF/Wait Wait 1 Wait 1 Wait 1 Wait 1 Wait 1 Wait 1 Wait 1 +// Term A +// LFunc +// Term B +// Branch1 +// Branch0 +// Re-Exec +// Sngl/CRC Default Default Default Default Default Default Default +// WEN# 0 0 0 0 0 0 0 0 +// REN# 0 0 0 0 0 0 0 0 +// OE# 0 0 0 0 0 0 0 0 +// CLRST 0 0 0 0 0 0 0 0 +// unused 0 0 0 0 0 0 0 0 +// BOGUS 0 0 0 0 0 0 0 0 +// +// END DO NOT EDIT +// DO NOT EDIT ... +// +// GPIF Waveform 1: singlewr +// +// Interval 0 1 2 3 4 5 6 Idle (7) +// _________ _________ _________ _________ _________ _________ _________ _________ +// +// AddrMode Same Val Same Val Same Val Same Val Same Val Same Val Same Val +// DataMode Activate Activate Activate Activate Activate Activate Activate +// NextData SameData SameData SameData SameData SameData SameData SameData +// Int Trig No Int No Int No Int No Int No Int No Int No Int +// IF/Wait Wait 1 IF Wait 1 Wait 1 Wait 1 Wait 1 Wait 1 +// Term A EF# +// LFunc AND +// Term B EF# +// Branch1 ThenIdle +// Branch0 ElseIdle +// Re-Exec No +// Sngl/CRC Default Default Default Default Default Default Default +// WEN# 0 1 1 1 1 1 1 0 +// REN# 0 0 0 0 0 0 0 0 +// OE# 0 0 0 0 0 0 0 0 +// CLRST 0 0 0 0 0 0 0 0 +// unused 0 0 0 0 0 0 0 0 +// BOGUS 0 0 0 0 0 0 0 0 +// +// END DO NOT EDIT +// DO NOT EDIT ... +// +// GPIF Waveform 2: FIFORd +// +// Interval 0 1 2 3 4 5 6 Idle (7) +// _________ _________ _________ _________ _________ _________ _________ _________ +// +// AddrMode Same Val Same Val Same Val Same Val Same Val Same Val Same Val +// DataMode NO Data Activate NO Data NO Data NO Data NO Data NO Data +// NextData SameData SameData SameData SameData SameData SameData SameData +// Int Trig No Int No Int No Int No Int No Int No Int No Int +// IF/Wait Wait 1 IF Wait 1 IF Wait 1 Wait 1 Wait 1 +// Term A TCXpire TCXpire +// LFunc AND AND +// Term B TCXpire TCXpire +// Branch1 Then 2 ThenIdle +// Branch0 Else 1 ElseIdle +// Re-Exec No No +// Sngl/CRC Default Default Default Default Default Default Default +// WEN# 0 0 0 0 0 0 0 0 +// REN# 1 0 0 0 0 0 0 0 +// OE# 1 1 1 0 0 0 0 0 +// CLRST 0 0 0 0 0 0 0 0 +// unused 0 0 0 0 0 0 0 0 +// BOGUS 0 0 0 0 0 0 0 0 +// +// END DO NOT EDIT +// DO NOT EDIT ... +// +// GPIF Waveform 3: FIFOWr +// +// Interval 0 1 2 3 4 5 6 Idle (7) +// _________ _________ _________ _________ _________ _________ _________ _________ +// +// AddrMode Same Val Same Val Same Val Same Val Same Val Same Val Same Val +// DataMode NO Data Activate Activate Activate Activate Activate Activate +// NextData SameData SameData SameData SameData SameData SameData SameData +// Int Trig No Int No Int No Int No Int No Int No Int No Int +// IF/Wait Wait 1 IF Wait 1 Wait 1 Wait 1 Wait 1 Wait 1 +// Term A TCXpire +// LFunc AND +// Term B TCXpire +// Branch1 ThenIdle +// Branch0 Else 1 +// Re-Exec No +// Sngl/CRC Default Default Default Default Default Default Default +// WEN# 0 0 0 0 0 0 0 0 +// REN# 0 0 0 0 0 0 0 0 +// OE# 0 0 0 0 0 0 0 0 +// CLRST 0 0 0 0 0 0 0 0 +// unused 0 0 0 0 0 0 0 0 +// BOGUS 0 0 0 0 0 0 0 0 +// +// END DO NOT EDIT + +// GPIF Program Code + +// DO NOT EDIT ... +#include "fx2.h" +#include "fx2regs.h" +#include "fx2sdly.h" // SYNCDELAY macro +// END DO NOT EDIT + +// DO NOT EDIT ... +const char xdata WaveData[128] = +{ +// Wave 0 +/* LenBr */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Output*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* LFun */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, +// Wave 1 +/* LenBr */ 0x01, 0x3F, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x22, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, +/* Output*/ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, +/* LFun */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, +// Wave 2 +/* LenBr */ 0x01, 0x11, 0x01, 0x3F, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, +/* Output*/ 0x06, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, +/* LFun */ 0x00, 0x2D, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x3F, +// Wave 3 +/* LenBr */ 0x01, 0x39, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, +/* Output*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* LFun */ 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, +}; +// END DO NOT EDIT + +// DO NOT EDIT ... +const char xdata FlowStates[36] = +{ +/* Wave 0 FlowStates */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* Wave 1 FlowStates */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* Wave 2 FlowStates */ 0x81,0x2D,0x26,0x00,0x04,0x04,0x03,0x02,0x00, +/* Wave 3 FlowStates */ 0x81,0x2D,0x21,0x00,0x04,0x04,0x03,0x02,0x00, +}; +// END DO NOT EDIT + +// DO NOT EDIT ... +const char xdata InitData[7] = +{ +/* Regs */ 0xA0,0x00,0x00,0x00,0xEE,0x4E,0x00 +}; +// END DO NOT EDIT + +// TO DO: You may add additional code below. + +void GpifInit( void ) +{ + BYTE i; + + // Registers which require a synchronization delay, see section 15.14 + // FIFORESET FIFOPINPOLAR + // INPKTEND OUTPKTEND + // EPxBCH:L REVCTL + // GPIFTCB3 GPIFTCB2 + // GPIFTCB1 GPIFTCB0 + // EPxFIFOPFH:L EPxAUTOINLENH:L + // EPxFIFOCFG EPxGPIFFLGSEL + // PINFLAGSxx EPxFIFOIRQ + // EPxFIFOIE GPIFIRQ + // GPIFIE GPIFADRH:L + // UDMACRCH:L EPxGPIFTRIG + // GPIFTRIG + + // Note: The pre-REVE EPxGPIFTCH/L register are affected, as well... + // ...these have been replaced by GPIFTC[B3:B0] registers + + // 8051 doesn't have access to waveform memories 'til + // the part is in GPIF mode. + + IFCONFIG = 0xEE; + // IFCLKSRC=1 , FIFOs executes on internal clk source + // xMHz=1 , 48MHz internal clk rate + // IFCLKOE=0 , Don't drive IFCLK pin signal at 48MHz + // IFCLKPOL=0 , Don't invert IFCLK pin signal from internal clk + // ASYNC=1 , master samples asynchronous + // GSTATE=1 , Drive GPIF states out on PORTE[2:0], debug WF + // IFCFG[1:0]=10, FX2 in GPIF master mode + + GPIFABORT = 0xFF; // abort any waveforms pending + + GPIFREADYCFG = InitData[ 0 ]; + GPIFCTLCFG = InitData[ 1 ]; + GPIFIDLECS = InitData[ 2 ]; + GPIFIDLECTL = InitData[ 3 ]; + GPIFWFSELECT = InitData[ 5 ]; + GPIFREADYSTAT = InitData[ 6 ]; + + // use dual autopointer feature... + AUTOPTRSETUP = 0x07; // inc both pointers, + // ...warning: this introduces pdata hole(s) + // ...at E67B (XAUTODAT1) and E67C (XAUTODAT2) + + // source + AUTOPTRH1 = MSB( &WaveData ); + AUTOPTRL1 = LSB( &WaveData ); + + // destination + AUTOPTRH2 = 0xE4; + AUTOPTRL2 = 0x00; + + // transfer + for ( i = 0x00; i < 128; i++ ) + { + EXTAUTODAT2 = EXTAUTODAT1; + } + +// Configure GPIF Address pins, output initial value, + PORTCCFG = 0xFF; // [7:0] as alt. func. GPIFADR[7:0] + OEC = 0xFF; // and as outputs + PORTECFG |= 0x80; // [8] as alt. func. GPIFADR[8] + OEE |= 0x80; // and as output + +// ...OR... tri-state GPIFADR[8:0] pins +// PORTCCFG = 0x00; // [7:0] as port I/O +// OEC = 0x00; // and as inputs +// PORTECFG &= 0x7F; // [8] as port I/O +// OEE &= 0x7F; // and as input + +// GPIF address pins update when GPIFADRH/L written + SYNCDELAY; // + GPIFADRH = 0x00; // bits[7:1] always 0 + SYNCDELAY; // + GPIFADRL = 0x00; // point to PERIPHERAL address 0x0000 + +// Configure GPIF FlowStates registers for Wave 0 of WaveData + FLOWSTATE = FlowStates[ 0 ]; + FLOWLOGIC = FlowStates[ 1 ]; + FLOWEQ0CTL = FlowStates[ 2 ]; + FLOWEQ1CTL = FlowStates[ 3 ]; + FLOWHOLDOFF = FlowStates[ 4 ]; + FLOWSTB = FlowStates[ 5 ]; + FLOWSTBEDGE = FlowStates[ 6 ]; + FLOWSTBHPERIOD = FlowStates[ 7 ]; +} + diff --git a/firmware/fx2/src/usrp1/gpif.gpf b/firmware/fx2/src/usrp1/gpif.gpf new file mode 100755 index 000000000..854e25399 Binary files /dev/null and b/firmware/fx2/src/usrp1/gpif.gpf differ diff --git a/firmware/fx2/src/usrp1/init_gpif.c b/firmware/fx2/src/usrp1/init_gpif.c new file mode 100644 index 000000000..0f5944b3b --- /dev/null +++ b/firmware/fx2/src/usrp1/init_gpif.c @@ -0,0 +1 @@ +#include "../common/init_gpif.c" diff --git a/firmware/fx2/src/usrp1/spi.c b/firmware/fx2/src/usrp1/spi.c new file mode 100644 index 000000000..f5803c55b --- /dev/null +++ b/firmware/fx2/src/usrp1/spi.c @@ -0,0 +1,381 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "spi.h" +#include "usrp_rev2_regs.h" + +static void +setup_enables (unsigned char enables) +{ + // Software eanbles are active high. + // Hardware enables are active low. + + // Uhh, the CODECs are active low, but the FPGA is active high... + enables ^= SPI_ENABLE_FPGA; + + // KLUDGE: This code is fragile, but reasonably fast... + // low three bits of enables go into port A + USRP_PA = USRP_PA | (0x7 << 3); // disable FPGA, CODEC_A, CODEC_B + USRP_PA ^= (enables & 0x7) << 3; // enable specified devs + + // high four bits of enables go into port E + USRP_PE = USRP_PE | (0xf << 4); // disable TX_A, RX_A, TX_B, RX_B + USRP_PE ^= (enables & 0xf0); // enable specified devs +} + +#define disable_all() setup_enables (0) + +void +init_spi (void) +{ + disable_all (); /* disable all devs */ + bitS_OUT = 0; /* idle state has CLK = 0 */ +} + +#if 0 +static unsigned char +count_bits8 (unsigned char v) +{ + static unsigned char count4[16] = { + 0, // 0 + 1, // 1 + 1, // 2 + 2, // 3 + 1, // 4 + 2, // 5 + 2, // 6 + 3, // 7 + 1, // 8 + 2, // 9 + 2, // a + 3, // b + 2, // c + 3, // d + 3, // e + 4 // f + }; + return count4[v & 0xf] + count4[(v >> 4) & 0xf]; +} + +#else + +static unsigned char +count_bits8 (unsigned char v) +{ + unsigned char count = 0; + if (v & (1 << 0)) count++; + if (v & (1 << 1)) count++; + if (v & (1 << 2)) count++; + if (v & (1 << 3)) count++; + if (v & (1 << 4)) count++; + if (v & (1 << 5)) count++; + if (v & (1 << 6)) count++; + if (v & (1 << 7)) count++; + return count; +} +#endif + +static void +write_byte_msb (unsigned char v); + +static void +write_bytes_msb (const xdata unsigned char *buf, unsigned char len); + +static void +read_bytes_msb (xdata unsigned char *buf, unsigned char len); + + +// returns non-zero if successful, else 0 +unsigned char +spi_read (unsigned char header_hi, unsigned char header_lo, + unsigned char enables, unsigned char format, + xdata unsigned char *buf, unsigned char len) +{ + if (count_bits8 (enables) > 1) + return 0; // error, too many enables set + + setup_enables (enables); + + if (format & SPI_FMT_LSB){ // order: LSB +#if 1 + return 0; // error, not implemented +#else + switch (format & SPI_FMR_HDR_MASK){ + case SPI_FMT_HDR_0: + break; + case SPI_FMT_HDR_1: + write_byte_lsb (header_lo); + break; + case SPI_FMT_HDR_2: + write_byte_lsb (header_lo); + write_byte_lsb (header_hi); + break; + default: + return 0; // error + } + if (len != 0) + read_bytes_lsb (buf, len); +#endif + } + + else { // order: MSB + + switch (format & SPI_FMT_HDR_MASK){ + case SPI_FMT_HDR_0: + break; + case SPI_FMT_HDR_1: + write_byte_msb (header_lo); + break; + case SPI_FMT_HDR_2: + write_byte_msb (header_hi); + write_byte_msb (header_lo); + break; + default: + return 0; // error + } + if (len != 0) + read_bytes_msb (buf, len); + } + + disable_all (); + return 1; // success +} + + +// returns non-zero if successful, else 0 +unsigned char +spi_write (unsigned char header_hi, unsigned char header_lo, + unsigned char enables, unsigned char format, + const xdata unsigned char *buf, unsigned char len) +{ + setup_enables (enables); + + if (format & SPI_FMT_LSB){ // order: LSB +#if 1 + return 0; // error, not implemented +#else + switch (format & SPI_FMR_HDR_MASK){ + case SPI_FMT_HDR_0: + break; + case SPI_FMT_HDR_1: + write_byte_lsb (header_lo); + break; + case SPI_FMT_HDR_2: + write_byte_lsb (header_lo); + write_byte_lsb (header_hi); + break; + default: + return 0; // error + } + if (len != 0) + write_bytes_lsb (buf, len); +#endif + } + + else { // order: MSB + + switch (format & SPI_FMT_HDR_MASK){ + case SPI_FMT_HDR_0: + break; + case SPI_FMT_HDR_1: + write_byte_msb (header_lo); + break; + case SPI_FMT_HDR_2: + write_byte_msb (header_hi); + write_byte_msb (header_lo); + break; + default: + return 0; // error + } + if (len != 0) + write_bytes_msb (buf, len); + } + + disable_all (); + return 1; // success +} + +// ---------------------------------------------------------------- + +static void +write_byte_msb (unsigned char v) +{ + v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit) + bitS_OUT = v & 0x1; + bitS_CLK = 1; + bitS_CLK = 0; + + v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit) + bitS_OUT = v & 0x1; + bitS_CLK = 1; + bitS_CLK = 0; + + v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit) + bitS_OUT = v & 0x1; + bitS_CLK = 1; + bitS_CLK = 0; + + v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit) + bitS_OUT = v & 0x1; + bitS_CLK = 1; + bitS_CLK = 0; + + v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit) + bitS_OUT = v & 0x1; + bitS_CLK = 1; + bitS_CLK = 0; + + v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit) + bitS_OUT = v & 0x1; + bitS_CLK = 1; + bitS_CLK = 0; + + v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit) + bitS_OUT = v & 0x1; + bitS_CLK = 1; + bitS_CLK = 0; + + v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit) + bitS_OUT = v & 0x1; + bitS_CLK = 1; + bitS_CLK = 0; +} + +static void +write_bytes_msb (const xdata unsigned char *buf, unsigned char len) +{ + while (len-- != 0){ + write_byte_msb (*buf++); + } +} + +#if 0 +/* + * This is incorrectly compiled by SDCC 2.4.0 + */ +static unsigned char +read_byte_msb (void) +{ + unsigned char v = 0; + + bitS_CLK = 1; + v |= bitS_IN; + bitS_CLK = 0; + + v = v << 1; + bitS_CLK = 1; + v |= bitS_IN; + bitS_CLK = 0; + + v = v << 1; + bitS_CLK = 1; + v |= bitS_IN; + bitS_CLK = 0; + + v = v << 1; + bitS_CLK = 1; + v |= bitS_IN; + bitS_CLK = 0; + + v = v << 1; + bitS_CLK = 1; + v |= bitS_IN; + bitS_CLK = 0; + + v = v << 1; + bitS_CLK = 1; + v |= bitS_IN; + bitS_CLK = 0; + + v = v << 1; + bitS_CLK = 1; + v |= bitS_IN; + bitS_CLK = 0; + + v = v << 1; + bitS_CLK = 1; + v |= bitS_IN; + bitS_CLK = 0; + + return v; +} +#else +static unsigned char +read_byte_msb (void) _naked +{ + _asm + clr a + + setb _bitS_CLK + mov c, _bitS_IN + rlc a + clr _bitS_CLK + + setb _bitS_CLK + mov c, _bitS_IN + rlc a + clr _bitS_CLK + + setb _bitS_CLK + mov c, _bitS_IN + rlc a + clr _bitS_CLK + + setb _bitS_CLK + mov c, _bitS_IN + rlc a + clr _bitS_CLK + + setb _bitS_CLK + mov c, _bitS_IN + rlc a + clr _bitS_CLK + + setb _bitS_CLK + mov c, _bitS_IN + rlc a + clr _bitS_CLK + + setb _bitS_CLK + mov c, _bitS_IN + rlc a + clr _bitS_CLK + + setb _bitS_CLK + mov c, _bitS_IN + rlc a + clr _bitS_CLK + + mov dpl,a + ret + _endasm; +} +#endif + +static void +read_bytes_msb (xdata unsigned char *buf, unsigned char len) +{ + while (len-- != 0){ + *buf++ = read_byte_msb (); + } +} + diff --git a/firmware/fx2/src/usrp1/spi.h b/firmware/fx2/src/usrp1/spi.h new file mode 100644 index 000000000..12bc5e544 --- /dev/null +++ b/firmware/fx2/src/usrp1/spi.h @@ -0,0 +1,43 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_SPI_H +#define INCLUDED_SPI_H + +#include "usrp_spi_defs.h" + +void init_spi (void); // one time call to init + +// returns non-zero if successful, else 0 +unsigned char +spi_read (unsigned char header_hi, unsigned char header_lo, + unsigned char enables, unsigned char format, + xdata unsigned char *buf, unsigned char len); + +// returns non-zero if successful, else 0 +unsigned char +spi_write (unsigned char header_hi, unsigned char header_lo, + unsigned char enables, unsigned char format, + const xdata unsigned char *buf, unsigned char len); + + +#endif /* INCLUDED_SPI_H */ diff --git a/firmware/fx2/src/usrp1/usb_descriptors.a51 b/firmware/fx2/src/usrp1/usb_descriptors.a51 new file mode 100644 index 000000000..a60adbef8 --- /dev/null +++ b/firmware/fx2/src/usrp1/usb_descriptors.a51 @@ -0,0 +1,404 @@ +;;; -*- asm -*- +;;; +;;; Copyright 2003 Free Software Foundation, Inc. +;;; +;;; This file is part of GNU Radio +;;; +;;; GNU Radio 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, or (at your option) +;;; any later version. +;;; +;;; GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +;;; the Free Software Foundation, Inc., 51 Franklin Street, +;;; Boston, MA 02110-1301, USA. +;;; + +;;; USB Descriptor table for the USRP +;;; +;;; We're a high-speed only device (480 Mb/sec) with 1 configuration +;;; and 3 interfaces. +;;; +;;; interface 0: command and status (ep0 COMMAND) +;;; interface 1: Transmit path (ep2 OUT BULK) +;;; interface 2: Receive path (ep6 IN BULK) + + .module usb_descriptors + + VID_FREE = 0xfffe ; Free Software Folks + PID_USRP = 0x0002 ; USRP + + ;; We distinguish configured from unconfigured USRPs using the Device ID. + ;; If the MSB of the DID is 0, the device is unconfigured. + ;; The LSB of the DID is reserved for hardware revs. + + DID_USRP = 0x0100 ; Device ID (bcd) + + + DSCR_DEVICE = 1 ; Descriptor type: Device + DSCR_CONFIG = 2 ; Descriptor type: Configuration + DSCR_STRING = 3 ; Descriptor type: String + DSCR_INTRFC = 4 ; Descriptor type: Interface + DSCR_ENDPNT = 5 ; Descriptor type: Endpoint + DSCR_DEVQUAL = 6 ; Descriptor type: Device Qualifier + + DSCR_DEVICE_LEN = 18 + DSCR_CONFIG_LEN = 9 + DSCR_INTRFC_LEN = 9 + DSCR_ENDPNT_LEN = 7 + DSCR_DEVQUAL_LEN = 10 + + ET_CONTROL = 0 ; Endpoint type: Control + ET_ISO = 1 ; Endpoint type: Isochronous + ET_BULK = 2 ; Endpoint type: Bulk + ET_INT = 3 ; Endpoint type: Interrupt + + + ;; configuration attributes + bmSELF_POWERED = 1 << 6 + +;;; -------------------------------------------------------- +;;; external ram data +;;;-------------------------------------------------------- + + .area USBDESCSEG (XDATA) + +;;; ---------------------------------------------------------------- +;;; descriptors used when operating at high speed (480Mb/sec) +;;; ---------------------------------------------------------------- + + .even ; descriptors must be 2-byte aligned for SUDPTR{H,L} to work + + ;; The .even directive isn't really honored by the linker. Bummer! + ;; (There's no way to specify an alignment requirement for a given area, + ;; hence when they're concatenated together, even doesn't work.) + ;; + ;; We work around this by telling the linker to put USBDESCSEG + ;; at 0xE000 absolute. This means that the maximimum length of this + ;; segment is 480 bytes, leaving room for the two hash slots + ;; at 0xE1EO to 0xE1FF. + ;; + ;; As of July 7, 2004, this segment is 326 bytes long + +_high_speed_device_descr:: + .db DSCR_DEVICE_LEN + .db DSCR_DEVICE + .db <0x0200 ; Specification version (LSB) + .db >0x0200 ; Specification version (MSB) + .db 0xff ; device class (vendor specific) + .db 0xff ; device subclass (vendor specific) + .db 0xff ; device protocol (vendor specific) + .db 64 ; bMaxPacketSize0 for endpoint 0 + .db VID_FREE ; idVendor + .db PID_USRP ; idProduct +_usb_desc_hw_rev_binary_patch_location_0:: + .db DID_USRP ; bcdDevice + .db SI_VENDOR ; iManufacturer (string index) + .db SI_PRODUCT ; iProduct (string index) + .db SI_SERIAL ; iSerial number (string index) + .db 1 ; bNumConfigurations + +;;; describes the other speed (12Mb/sec) + .even +_high_speed_devqual_descr:: + .db DSCR_DEVQUAL_LEN + .db DSCR_DEVQUAL + .db <0x0200 ; bcdUSB (LSB) + .db >0x0200 ; bcdUSB (MSB) + .db 0xff ; bDeviceClass + .db 0xff ; bDeviceSubClass + .db 0xff ; bDeviceProtocol + .db 64 ; bMaxPacketSize0 + .db 1 ; bNumConfigurations (one config at 12Mb/sec) + .db 0 ; bReserved + + .even +_high_speed_config_descr:: + .db DSCR_CONFIG_LEN + .db DSCR_CONFIG + .db <(_high_speed_config_descr_end - _high_speed_config_descr) ; LSB + .db >(_high_speed_config_descr_end - _high_speed_config_descr) ; MSB + .db 3 ; bNumInterfaces + .db 1 ; bConfigurationValue + .db 0 ; iConfiguration + .db 0x80 | bmSELF_POWERED ; bmAttributes + .db 0 ; bMaxPower + + ;; interface descriptor 0 (command & status, ep0 COMMAND) + + .db DSCR_INTRFC_LEN + .db DSCR_INTRFC + .db 0 ; bInterfaceNumber (zero based) + .db 0 ; bAlternateSetting + .db 0 ; bNumEndpoints + .db 0xff ; bInterfaceClass (vendor specific) + .db 0xff ; bInterfaceSubClass (vendor specific) + .db 0xff ; bInterfaceProtocol (vendor specific) + .db SI_COMMAND_AND_STATUS ; iInterface (description) + + ;; interface descriptor 1 (transmit path, ep2 OUT BULK) + + .db DSCR_INTRFC_LEN + .db DSCR_INTRFC + .db 1 ; bInterfaceNumber (zero based) + .db 0 ; bAlternateSetting + .db 1 ; bNumEndpoints + .db 0xff ; bInterfaceClass (vendor specific) + .db 0xff ; bInterfaceSubClass (vendor specific) + .db 0xff ; bInterfaceProtocol (vendor specific) + .db SI_TX_PATH ; iInterface (description) + + ;; interface 1's end point + + .db DSCR_ENDPNT_LEN + .db DSCR_ENDPNT + .db 0x02 ; bEndpointAddress (ep 2 OUT) + .db ET_BULK ; bmAttributes + .db <512 ; wMaxPacketSize (LSB) + .db >512 ; wMaxPacketSize (MSB) + .db 0 ; bInterval (iso only) + + ;; interface descriptor 2 (receive path, ep6 IN BULK) + + .db DSCR_INTRFC_LEN + .db DSCR_INTRFC + .db 2 ; bInterfaceNumber (zero based) + .db 0 ; bAlternateSetting + .db 1 ; bNumEndpoints + .db 0xff ; bInterfaceClass (vendor specific) + .db 0xff ; bInterfaceSubClass (vendor specific) + .db 0xff ; bInterfaceProtocol (vendor specific) + .db SI_RX_PATH ; iInterface (description) + + ;; interface 2's end point + + .db DSCR_ENDPNT_LEN + .db DSCR_ENDPNT + .db 0x86 ; bEndpointAddress (ep 6 IN) + .db ET_BULK ; bmAttributes + .db <512 ; wMaxPacketSize (LSB) + .db >512 ; wMaxPacketSize (MSB) + .db 0 ; bInterval (iso only) + +_high_speed_config_descr_end: + +;;; ---------------------------------------------------------------- +;;; descriptors used when operating at full speed (12Mb/sec) +;;; ---------------------------------------------------------------- + + .even +_full_speed_device_descr:: + .db DSCR_DEVICE_LEN + .db DSCR_DEVICE + .db <0x0200 ; Specification version (LSB) + .db >0x0200 ; Specification version (MSB) + .db 0xff ; device class (vendor specific) + .db 0xff ; device subclass (vendor specific) + .db 0xff ; device protocol (vendor specific) + .db 64 ; bMaxPacketSize0 for endpoint 0 + .db VID_FREE ; idVendor + .db PID_USRP ; idProduct +_usb_desc_hw_rev_binary_patch_location_1:: + .db DID_USRP ; bcdDevice + .db SI_VENDOR ; iManufacturer (string index) + .db SI_PRODUCT ; iProduct (string index) + .db SI_NONE ; iSerial number (None) + .db 1 ; bNumConfigurations + + +;;; describes the other speed (480Mb/sec) + .even +_full_speed_devqual_descr:: + .db DSCR_DEVQUAL_LEN + .db DSCR_DEVQUAL + .db <0x0200 ; bcdUSB + .db >0x0200 ; bcdUSB + .db 0xff ; bDeviceClass + .db 0xff ; bDeviceSubClass + .db 0xff ; bDeviceProtocol + .db 64 ; bMaxPacketSize0 + .db 1 ; bNumConfigurations (one config at 480Mb/sec) + .db 0 ; bReserved + + .even +_full_speed_config_descr:: + .db DSCR_CONFIG_LEN + .db DSCR_CONFIG + .db <(_full_speed_config_descr_end - _full_speed_config_descr) ; LSB + .db >(_full_speed_config_descr_end - _full_speed_config_descr) ; MSB + .db 1 ; bNumInterfaces + .db 1 ; bConfigurationValue + .db 0 ; iConfiguration + .db 0x80 | bmSELF_POWERED ; bmAttributes + .db 0 ; bMaxPower + + ;; interface descriptor 0 (command & status, ep0 COMMAND) + + .db DSCR_INTRFC_LEN + .db DSCR_INTRFC + .db 0 ; bInterfaceNumber (zero based) + .db 0 ; bAlternateSetting + .db 0 ; bNumEndpoints + .db 0xff ; bInterfaceClass (vendor specific) + .db 0xff ; bInterfaceSubClass (vendor specific) + .db 0xff ; bInterfaceProtocol (vendor specific) + .db SI_COMMAND_AND_STATUS ; iInterface (description) + +_full_speed_config_descr_end: + +;;; ---------------------------------------------------------------- +;;; string descriptors +;;; ---------------------------------------------------------------- + +_nstring_descriptors:: + .db (_string_descriptors_end - _string_descriptors) / 2 + +_string_descriptors:: + .db str0 + .db str1 + .db str2 + .db str3 + .db str4 + .db str5 + .db str6 +_string_descriptors_end: + + SI_NONE = 0 + ;; str0 contains the language ID's. + .even +str0: .db str0_end - str0 + .db DSCR_STRING + .db 0 + .db 0 + .db <0x0409 ; magic code for US English (LSB) + .db >0x0409 ; magic code for US English (MSB) +str0_end: + + SI_VENDOR = 1 + .even +str1: .db str1_end - str1 + .db DSCR_STRING + .db 'F, 0 ; 16-bit unicode + .db 'r, 0 + .db 'e, 0 + .db 'e, 0 + .db ' , 0 + .db 'S, 0 + .db 'o, 0 + .db 'f, 0 + .db 't, 0 + .db 'w, 0 + .db 'a, 0 + .db 'r, 0 + .db 'e, 0 + .db ' , 0 + .db 'F, 0 + .db 'o, 0 + .db 'l, 0 + .db 'k, 0 + .db 's, 0 +str1_end: + + SI_PRODUCT = 2 + .even +str2: .db str2_end - str2 + .db DSCR_STRING + .db 'U, 0 + .db 'S, 0 + .db 'R, 0 + .db 'P, 0 + .db ' , 0 + .db 'R, 0 + .db 'e, 0 + .db 'v, 0 + .db ' , 0 +_usb_desc_hw_rev_ascii_patch_location_0:: + .db '?, 0 +str2_end: + + SI_COMMAND_AND_STATUS = 3 + .even +str3: .db str3_end - str3 + .db DSCR_STRING + .db 'C, 0 + .db 'o, 0 + .db 'm, 0 + .db 'm, 0 + .db 'a, 0 + .db 'n, 0 + .db 'd, 0 + .db ' , 0 + .db '&, 0 + .db ' , 0 + .db 'S, 0 + .db 't, 0 + .db 'a, 0 + .db 't, 0 + .db 'u, 0 + .db 's, 0 +str3_end: + + SI_TX_PATH = 4 + .even +str4: .db str4_end - str4 + .db DSCR_STRING + .db 'T, 0 + .db 'r, 0 + .db 'a, 0 + .db 'n, 0 + .db 's, 0 + .db 'm, 0 + .db 'i, 0 + .db 't, 0 + .db ' , 0 + .db 'P, 0 + .db 'a, 0 + .db 't, 0 + .db 'h, 0 +str4_end: + + SI_RX_PATH = 5 + .even +str5: .db str5_end - str5 + .db DSCR_STRING + .db 'R, 0 + .db 'e, 0 + .db 'c, 0 + .db 'e, 0 + .db 'i, 0 + .db 'v, 0 + .db 'e, 0 + .db ' , 0 + .db 'P, 0 + .db 'a, 0 + .db 't, 0 + .db 'h, 0 +str5_end: + + SI_SERIAL = 6 + .even +str6: .db str6_end - str6 + .db DSCR_STRING +_usb_desc_serial_number_ascii:: + .db '3, 0 + .db '., 0 + .db '1, 0 + .db '4, 0 + .db '1, 0 + .db '5, 0 + .db '9, 0 + .db '3, 0 +str6_end: + diff --git a/firmware/fx2/src/usrp1/usrp_common.c b/firmware/fx2/src/usrp1/usrp_common.c new file mode 100644 index 000000000..f389d9253 --- /dev/null +++ b/firmware/fx2/src/usrp1/usrp_common.c @@ -0,0 +1 @@ +#include "../common/usrp_common.c" diff --git a/firmware/fx2/src/usrp1/usrp_common.h b/firmware/fx2/src/usrp1/usrp_common.h new file mode 100644 index 000000000..738ba6b37 --- /dev/null +++ b/firmware/fx2/src/usrp1/usrp_common.h @@ -0,0 +1,77 @@ +/* + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003,2006 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 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA + */ + +/* + * common defines and prototypes for USRP + * + * In comments below "TRM" refers to the EZ-USB FX2 Technical Reference Manual + */ + +#ifndef _USRPCOMMON_H_ +#define _USRPCOMMON_H_ + +#include +#include +#include + +/* + * From TRM page 15-105: + * + * Under certain conditions, some read and write access to the FX2 + * registers must be separated by a "synchronization delay". The + * delay is necessary only under the following conditions: + * + * - between a write to any register in the 0xE600 - 0xE6FF range + * and a write to one of the registers listed below. + * + * - between a write to one of the registers listed below and a read + * from any register in the 0xE600 - 0xE6FF range. + * + * Registers which require a synchronization delay: + * + * FIFORESET FIFOPINPOLAR + * INPKTEND EPxBCH:L + * EPxFIFOPFH:L EPxAUTOINLENH:L + * EPxFIFOCFG EPxGPIFFLGSEL + * PINFLAGSAB PINFLAGSCD + * EPxFIFOIE EPxFIFOIRQ + * GPIFIE GPIFIRQ + * UDMACRCH:L GPIFADRH:L + * GPIFTRIG EPxGPIFTRIG + * OUTPKTEND REVCTL + * GPIFTCB3 GPIFTCB2 + * GPIFTCB1 GPIFTCB0 + */ + +#define TRUE 1 +#define FALSE 0 + + +void init_usrp (void); +void init_gpif (void); + +void set_led_0 (unsigned char on); +void set_led_1 (unsigned char on); +void toggle_led_0 (void); +void toggle_led_1 (void); + +#define la_trace(v) + +#endif /* _USRPCOMMON_H_ */ diff --git a/firmware/fx2/src/usrp1/usrp_main.c b/firmware/fx2/src/usrp1/usrp_main.c new file mode 100644 index 000000000..c7c09f8c5 --- /dev/null +++ b/firmware/fx2/src/usrp1/usrp_main.c @@ -0,0 +1,380 @@ +/* + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003,2004 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 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA + */ + +#include "usrp_common.h" +#include "usrp_commands.h" +#include "fpga.h" +#include "usrp_gpif_inline.h" +#include "timer.h" +#include "i2c.h" +#include "isr.h" +#include "usb_common.h" +#include "fx2utils.h" +#include "usrp_globals.h" +#include "usrp_i2c_addr.h" +#include +#include "spi.h" +#include "eeprom_io.h" +#include "usb_descriptors.h" + +/* + * offsets into boot eeprom for configuration values + */ +#define HW_REV_OFFSET 5 +#define SERIAL_NO_OFFSET 248 +#define SERIAL_NO_LEN 8 + + +#define bRequestType SETUPDAT[0] +#define bRequest SETUPDAT[1] +#define wValueL SETUPDAT[2] +#define wValueH SETUPDAT[3] +#define wIndexL SETUPDAT[4] +#define wIndexH SETUPDAT[5] +#define wLengthL SETUPDAT[6] +#define wLengthH SETUPDAT[7] + + +unsigned char g_tx_enable = 0; +unsigned char g_rx_enable = 0; +unsigned char g_rx_overrun = 0; +unsigned char g_tx_underrun = 0; + +/* + * the host side fpga loader code pushes an MD5 hash of the bitstream + * into hash1. + */ +#define USRP_HASH_SIZE 16 +xdata at USRP_HASH_SLOT_1_ADDR unsigned char hash1[USRP_HASH_SIZE]; + +static void +get_ep0_data (void) +{ + EP0BCL = 0; // arm EP0 for OUT xfer. This sets the busy bit + + while (EP0CS & bmEPBUSY) // wait for busy to clear + ; +} + +/* + * Handle our "Vendor Extension" commands on endpoint 0. + * If we handle this one, return non-zero. + */ +unsigned char +app_vendor_cmd (void) +{ + if (bRequestType == VRT_VENDOR_IN){ + + ///////////////////////////////// + // handle the IN requests + ///////////////////////////////// + + switch (bRequest){ + + case VRQ_GET_STATUS: + switch (wIndexL){ + + case GS_TX_UNDERRUN: + EP0BUF[0] = g_tx_underrun; + g_tx_underrun = 0; + EP0BCH = 0; + EP0BCL = 1; + break; + + case GS_RX_OVERRUN: + EP0BUF[0] = g_rx_overrun; + g_rx_overrun = 0; + EP0BCH = 0; + EP0BCL = 1; + break; + + default: + return 0; + } + break; + + case VRQ_I2C_READ: + if (!i2c_read (wValueL, EP0BUF, wLengthL)) + return 0; + + EP0BCH = 0; + EP0BCL = wLengthL; + break; + + case VRQ_SPI_READ: + if (!spi_read (wValueH, wValueL, wIndexH, wIndexL, EP0BUF, wLengthL)) + return 0; + + EP0BCH = 0; + EP0BCL = wLengthL; + break; + + default: + return 0; + } + } + + else if (bRequestType == VRT_VENDOR_OUT){ + + ///////////////////////////////// + // handle the OUT requests + ///////////////////////////////// + + switch (bRequest){ + + case VRQ_SET_LED: + switch (wIndexL){ + case 0: + set_led_0 (wValueL); + break; + + case 1: + set_led_1 (wValueL); + break; + + default: + return 0; + } + break; + + case VRQ_FPGA_LOAD: + switch (wIndexL){ // sub-command + case FL_BEGIN: + return fpga_load_begin (); + + case FL_XFER: + get_ep0_data (); + return fpga_load_xfer (EP0BUF, EP0BCL); + + case FL_END: + return fpga_load_end (); + + default: + return 0; + } + break; + + + case VRQ_FPGA_SET_RESET: + fpga_set_reset (wValueL); + break; + + case VRQ_FPGA_SET_TX_ENABLE: + fpga_set_tx_enable (wValueL); + break; + + case VRQ_FPGA_SET_RX_ENABLE: + fpga_set_rx_enable (wValueL); + break; + + case VRQ_FPGA_SET_TX_RESET: + fpga_set_tx_reset (wValueL); + break; + + case VRQ_FPGA_SET_RX_RESET: + fpga_set_rx_reset (wValueL); + break; + + case VRQ_I2C_WRITE: + get_ep0_data (); + if (!i2c_write (wValueL, EP0BUF, EP0BCL)) + return 0; + break; + + case VRQ_SPI_WRITE: + get_ep0_data (); + if (!spi_write (wValueH, wValueL, wIndexH, wIndexL, EP0BUF, EP0BCL)) + return 0; + break; + + default: + return 0; + } + + } + else + return 0; // invalid bRequestType + + return 1; +} + + + +static void +main_loop (void) +{ + setup_flowstate_common (); + + while (1){ + + if (usb_setup_packet_avail ()) + usb_handle_setup_packet (); + + + if (GPIFTRIG & bmGPIF_IDLE){ + + // OK, GPIF is idle. Let's try to give it some work. + + // First check for underruns and overruns + + if (UC_BOARD_HAS_FPGA && (USRP_PA & (bmPA_TX_UNDERRUN | bmPA_RX_OVERRUN))){ + + // record the under/over run + if (USRP_PA & bmPA_TX_UNDERRUN) + g_tx_underrun = 1; + + if (USRP_PA & bmPA_RX_OVERRUN) + g_rx_overrun = 1; + + // tell the FPGA to clear the flags + fpga_clear_flags (); + } + + // Next see if there are any "OUT" packets waiting for our attention, + // and if so, if there's room in the FPGA's FIFO for them. + + if (g_tx_enable && !(EP24FIFOFLGS & 0x02)){ // USB end point fifo is not empty... + + if (fpga_has_room_for_packet ()){ // ... and FPGA has room for packet + + GPIFTCB1 = 0x01; SYNCDELAY; + GPIFTCB0 = 0x00; SYNCDELAY; + + setup_flowstate_write (); + + SYNCDELAY; + GPIFTRIG = bmGPIF_EP2_START | bmGPIF_WRITE; // start the xfer + SYNCDELAY; + + while (!(GPIFTRIG & bmGPIF_IDLE)){ + // wait for the transaction to complete + } + } + } + + // See if there are any requests for "IN" packets, and if so + // whether the FPGA's got any packets for us. + + if (g_rx_enable && !(EP6CS & bmEPFULL)){ // USB end point fifo is not full... + + if (fpga_has_packet_avail ()){ // ... and FPGA has packet available + + GPIFTCB1 = 0x01; SYNCDELAY; + GPIFTCB0 = 0x00; SYNCDELAY; + + setup_flowstate_read (); + + SYNCDELAY; + GPIFTRIG = bmGPIF_EP6_START | bmGPIF_READ; // start the xfer + SYNCDELAY; + + while (!(GPIFTRIG & bmGPIF_IDLE)){ + // wait for the transaction to complete + } + + SYNCDELAY; + INPKTEND = 6; // tell USB we filled buffer (6 is our endpoint num) + } + } + } + } +} + + +/* + * called at 100 Hz from timer2 interrupt + * + * Toggle led 0 + */ +void +isr_tick (void) interrupt +{ + static unsigned char count = 1; + + if (--count == 0){ + count = 50; + USRP_LED_REG ^= bmLED0; + } + + clear_timer_irq (); +} + +/* + * Read h/w rev code and serial number out of boot eeprom and + * patch the usb descriptors with the values. + */ +void +patch_usb_descriptors(void) +{ + static xdata unsigned char hw_rev; + static xdata unsigned char serial_no[8]; + unsigned char i; + + eeprom_read(I2C_ADDR_BOOT, HW_REV_OFFSET, &hw_rev, 1); // LSB of device id + usb_desc_hw_rev_binary_patch_location_0[0] = hw_rev; + usb_desc_hw_rev_binary_patch_location_1[0] = hw_rev; + usb_desc_hw_rev_ascii_patch_location_0[0] = hw_rev + '0'; // FIXME if we get > 9 + + eeprom_read(I2C_ADDR_BOOT, SERIAL_NO_OFFSET, serial_no, SERIAL_NO_LEN); + + for (i = 0; i < SERIAL_NO_LEN; i++){ + unsigned char ch = serial_no[i]; + if (ch == 0xff) // make unprogrammed EEPROM default to '0' + ch = '0'; + usb_desc_serial_number_ascii[i << 1] = ch; + } +} + +void +main (void) +{ +#if 0 + g_rx_enable = 0; // FIXME (work around initialization bug) + g_tx_enable = 0; + g_rx_overrun = 0; + g_tx_underrun = 0; +#endif + + memset (hash1, 0, USRP_HASH_SIZE); // zero fpga bitstream hash. This forces reload + + init_usrp (); + init_gpif (); + + // if (UC_START_WITH_GSTATE_OUTPUT_ENABLED) + IFCONFIG |= bmGSTATE; // no conflict, start with it on + + set_led_0 (0); + set_led_1 (0); + + EA = 0; // disable all interrupts + + patch_usb_descriptors(); + + setup_autovectors (); + usb_install_handlers (); + hook_timer_tick ((unsigned short) isr_tick); + + EIEX4 = 1; // disable INT4 FIXME + EA = 1; // global interrupt enable + + fx2_renumerate (); // simulates disconnect / reconnect + + main_loop (); +} diff --git a/firmware/fx2/src/usrp1/usrp_rev2_regs.h b/firmware/fx2/src/usrp1/usrp_rev2_regs.h new file mode 100644 index 000000000..a4f1d9896 --- /dev/null +++ b/firmware/fx2/src/usrp1/usrp_rev2_regs.h @@ -0,0 +1,163 @@ +/* + * USRP - Universal Software Radio Peripheral + * + * Copyright (C) 2003 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 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA + */ + +/* + * These are the register definitions for the Rev 1 USRP prototype + * The Rev 1 is the version with the AD9862's and daughterboards + */ + +#ifndef _USRP_REV1_REGS_H_ +#define _USRP_REV1_REGS_H_ + +#include "fx2regs.h" + +/* + * Port A (bit addressable): + */ + +#define USRP_PA IOA // Port A +#define USRP_PA_OE OEA // Port A direction register + +#define bmPA_S_CLK bmBIT0 // SPI serial clock +#define bmPA_S_DATA_TO_PERIPH bmBIT1 // SPI SDI (peripheral rel name) +#define bmPA_S_DATA_FROM_PERIPH bmBIT2 // SPI SDO (peripheral rel name) +#define bmPA_SEN_FPGA bmBIT3 // serial enable for FPGA (active low) +#define bmPA_SEN_CODEC_A bmBIT4 // serial enable AD9862 A (active low) +#define bmPA_SEN_CODEC_B bmBIT5 // serial enable AD9862 B (active low) +//#define bmPA_FX2_2 bmBIT6 // misc pin to FPGA (overflow) +//#define bmPA_FX2_3 bmBIT7 // misc pin to FPGA (underflow) +#define bmPA_RX_OVERRUN bmBIT6 // misc pin to FPGA (overflow) +#define bmPA_TX_UNDERRUN bmBIT7 // misc pin to FPGA (underflow) + + +sbit at 0x80+0 bitS_CLK; // 0x80 is the bit address of PORT A +sbit at 0x80+1 bitS_OUT; // out from FX2 point of view +sbit at 0x80+2 bitS_IN; // in from FX2 point of view + + +/* all outputs except S_DATA_FROM_PERIPH, FX2_2, FX2_3 */ + +#define bmPORT_A_OUTPUTS (bmPA_S_CLK \ + | bmPA_S_DATA_TO_PERIPH \ + | bmPA_SEN_FPGA \ + | bmPA_SEN_CODEC_A \ + | bmPA_SEN_CODEC_B \ + ) + +#define bmPORT_A_INITIAL (bmPA_SEN_FPGA | bmPA_SEN_CODEC_A | bmPA_SEN_CODEC_B) + + +/* Port B: GPIF FD[7:0] */ + +/* + * Port C (bit addressable): + * 5:1 FPGA configuration + */ + +#define USRP_PC IOC // Port C +#define USRP_PC_OE OEC // Port C direction register + +#define USRP_ALTERA_CONFIG USRP_PC + +#define bmPC_nRESET bmBIT0 // reset line to codecs (active low) +#define bmALTERA_DATA0 bmBIT1 +#define bmALTERA_NCONFIG bmBIT2 +#define bmALTERA_DCLK bmBIT3 +#define bmALTERA_CONF_DONE bmBIT4 +#define bmALTERA_NSTATUS bmBIT5 +#define bmPC_LED0 bmBIT6 // active low +#define bmPC_LED1 bmBIT7 // active low + +sbit at 0xA0+1 bitALTERA_DATA0; // 0xA0 is the bit address of PORT C +sbit at 0xA0+3 bitALTERA_DCLK; + + +#define bmALTERA_BITS (bmALTERA_DATA0 \ + | bmALTERA_NCONFIG \ + | bmALTERA_DCLK \ + | bmALTERA_CONF_DONE \ + | bmALTERA_NSTATUS) + +#define bmPORT_C_OUTPUTS (bmPC_nRESET \ + | bmALTERA_DATA0 \ + | bmALTERA_NCONFIG \ + | bmALTERA_DCLK \ + | bmPC_LED0 \ + | bmPC_LED1 \ + ) + +#define bmPORT_C_INITIAL (bmPC_LED0 | bmPC_LED1) + + +#define USRP_LED_REG USRP_PC +#define bmLED0 bmPC_LED0 +#define bmLED1 bmPC_LED1 + + +/* Port D: GPIF FD[15:8] */ + +/* Port E: not bit addressible */ + +#define USRP_PE IOE // Port E +#define USRP_PE_OE OEE // Port E direction register + +#define bmPE_PE0 bmBIT0 // GPIF debug output +#define bmPE_PE1 bmBIT1 // GPIF debug output +#define bmPE_PE2 bmBIT2 // GPIF debug output +#define bmPE_FPGA_CLR_STATUS bmBIT3 // misc pin to FPGA (clear status) +#define bmPE_SEN_TX_A bmBIT4 // serial enable d'board TX A (active low) +#define bmPE_SEN_RX_A bmBIT5 // serial enable d'board RX A (active low) +#define bmPE_SEN_TX_B bmBIT6 // serial enable d'board TX B (active low) +#define bmPE_SEN_RX_B bmBIT7 // serial enable d'board RX B (active low) + + +#define bmPORT_E_OUTPUTS (bmPE_FPGA_CLR_STATUS \ + | bmPE_SEN_TX_A \ + | bmPE_SEN_RX_A \ + | bmPE_SEN_TX_B \ + | bmPE_SEN_RX_B \ + ) + + +#define bmPORT_E_INITIAL (bmPE_SEN_TX_A \ + | bmPE_SEN_RX_A \ + | bmPE_SEN_TX_B \ + | bmPE_SEN_RX_B \ + ) + +/* + * FPGA output lines that are tied to FX2 RDYx inputs. + * These are readable using GPIFREADYSTAT. + */ +#define bmFPGA_HAS_SPACE bmBIT0 // usbrdy[0] has room for 512 byte packet +#define bmFPGA_PKT_AVAIL bmBIT1 // usbrdy[1] has >= 512 bytes available +// #define bmTX_UNDERRUN bmBIT2 // usbrdy[2] D/A ran out of data +// #define bmRX_OVERRUN bmBIT3 // usbrdy[3] A/D ran out of buffer + +/* + * FPGA input lines that are tied to the FX2 CTLx outputs. + * + * These are controlled by the GPIF microprogram... + */ +// WR bmBIT0 // usbctl[0] +// RD bmBIT1 // usbctl[1] +// OE bmBIT2 // usbctl[2] + +#endif /* _USRP_REV1_REGS_H_ */ diff --git a/firmware/fx2/src/usrp1/vectors.a51 b/firmware/fx2/src/usrp1/vectors.a51 new file mode 100644 index 000000000..fa579ba8a --- /dev/null +++ b/firmware/fx2/src/usrp1/vectors.a51 @@ -0,0 +1 @@ + .include "../common/vectors.a51" -- cgit v1.2.3 From b3a092055abacb99b3e9d71edd26c2dd2059dd7f Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Thu, 12 Aug 2010 16:22:04 -0700 Subject: usrp1: Add SPI transaction command to FX2 firmware The existing SPI read command is set for half-duplex 8-bit or 16-bit writes followed by an equivalent sized read. This patch adds a new command, VRQ_SPI_TRANSACT, which performs a full-duplex transaction up to 4-bytes. Since the data buffer of the USB control transfer is not available for outbound data on IN requests, the 4 bytes of write data are sent through the request parameters. Enables are sent in the previsouly unused high byte of the length parameter. The USB field mappings are shown below. Only rising edge and MSB operation is supported. Field (8-bit) Description ===== ===== bmRequestType 0x80 (USB Device IN request) bRequest 0x83 (VRQ_SPI_TRANSACT) wValueH OUT data(0) wValueL OUT data(1) wIndexH OUT data(2) wIndexL OUT data(3) wLengthH SPI enables wLengthL Number of bytes to transfer (1-4) EP0BUF IN data --- firmware/fx2/include/usrp_commands.h | 7 +++ firmware/fx2/src/usrp1/spi.c | 95 +++++++++++++++++++++++++++++++++++- firmware/fx2/src/usrp1/spi.h | 7 +++ firmware/fx2/src/usrp1/usrp_main.c | 10 +++- 4 files changed, 116 insertions(+), 3 deletions(-) diff --git a/firmware/fx2/include/usrp_commands.h b/firmware/fx2/include/usrp_commands.h index 20c28e264..02778c7e3 100644 --- a/firmware/fx2/include/usrp_commands.h +++ b/firmware/fx2/include/usrp_commands.h @@ -54,6 +54,13 @@ // wIndexL: format // len: how much to read +#define VRQ_SPI_TRANSACT 0x83 // wValueH: OUT byte 0 + // wValueL: OUT byte 1 + // wIndexH: OUT byte 2 + // wIndexL: OUT byte 3 + // wLengthH: enables + // wLengthL: transaction length + // OUT commands #define VRQ_SET_LED 0x01 // wValueL off/on {0,1}; wIndexL: which {0,1} diff --git a/firmware/fx2/src/usrp1/spi.c b/firmware/fx2/src/usrp1/spi.c index f5803c55b..0aaffea5d 100644 --- a/firmware/fx2/src/usrp1/spi.c +++ b/firmware/fx2/src/usrp1/spi.c @@ -97,13 +97,18 @@ count_bits8 (unsigned char v) static void write_byte_msb (unsigned char v); +unsigned char +transact_byte_msb (unsigned char v); + static void write_bytes_msb (const xdata unsigned char *buf, unsigned char len); static void read_bytes_msb (xdata unsigned char *buf, unsigned char len); - +static void +transact_bytes_msb (xdata unsigned char *buf, unsigned char len); + // returns non-zero if successful, else 0 unsigned char spi_read (unsigned char header_hi, unsigned char header_lo, @@ -214,7 +219,93 @@ spi_write (unsigned char header_hi, unsigned char header_lo, return 1; // success } -// ---------------------------------------------------------------- +unsigned char +spi_transact (unsigned char data0, unsigned char data1, + unsigned char data2, unsigned char data3, + unsigned char enables, xdata unsigned char *buf, + unsigned char len) +{ + if (count_bits8 (enables) > 1) + return 0; // error, too many enables set + + if (len > 4) + return 0; + + setup_enables (enables); + + buf[0] = data0; + buf[1] = data1; + buf[2] = data2; + buf[3] = data3; + + if (len != 0) + transact_bytes_msb(buf, len); + + disable_all (); + return 1; // success +} + +static unsigned char +transact_byte_msb (unsigned char v) +{ + v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit) + bitS_OUT = v & 0x1; + bitS_CLK = 1; + v |= bitS_IN; // read into bottom bit + bitS_CLK = 0; + + v = (v << 1) | (v >> 7); + bitS_OUT = v & 0x1; + bitS_CLK = 1; + v |= bitS_IN; + bitS_CLK = 0; + + v = (v << 1) | (v >> 7); + bitS_OUT = v & 0x1; + bitS_CLK = 1; + v |= bitS_IN; + bitS_CLK = 0; + + v = (v << 1) | (v >> 7); + bitS_OUT = v & 0x1; + bitS_CLK = 1; + v |= bitS_IN; + bitS_CLK = 0; + + v = (v << 1) | (v >> 7); + bitS_OUT = v & 0x1; + bitS_CLK = 1; + v |= bitS_IN; + bitS_CLK = 0; + + v = (v << 1) | (v >> 7); + bitS_OUT = v & 0x1; + bitS_CLK = 1; + v |= bitS_IN; + bitS_CLK = 0; + + v = (v << 1) | (v >> 7); + bitS_OUT = v & 0x1; + bitS_CLK = 1; + v |= bitS_IN; + bitS_CLK = 0; + + v = (v << 1) | (v >> 7); + bitS_OUT = v & 0x1; + bitS_CLK = 1; + v |= bitS_IN; + bitS_CLK = 0; + + return v; +} + +static void +transact_bytes_msb (xdata unsigned char *buf, unsigned char len) +{ + while (len-- != 0){ + *buf++ = transact_byte_msb (*buf); + } +} static void write_byte_msb (unsigned char v) diff --git a/firmware/fx2/src/usrp1/spi.h b/firmware/fx2/src/usrp1/spi.h index 12bc5e544..5342b82b8 100644 --- a/firmware/fx2/src/usrp1/spi.h +++ b/firmware/fx2/src/usrp1/spi.h @@ -39,5 +39,12 @@ spi_write (unsigned char header_hi, unsigned char header_lo, unsigned char enables, unsigned char format, const xdata unsigned char *buf, unsigned char len); +// returns non-zero if successful, else 0 +unsigned char +spi_transact (unsigned char data0, unsigned char data1, + unsigned char data2, unsigned char data3, + unsigned char enables, xdata unsigned char *buf, + unsigned char len); + #endif /* INCLUDED_SPI_H */ diff --git a/firmware/fx2/src/usrp1/usrp_main.c b/firmware/fx2/src/usrp1/usrp_main.c index c7c09f8c5..b8c2e98ec 100644 --- a/firmware/fx2/src/usrp1/usrp_main.c +++ b/firmware/fx2/src/usrp1/usrp_main.c @@ -117,7 +117,7 @@ app_vendor_cmd (void) EP0BCH = 0; EP0BCL = wLengthL; break; - + case VRQ_SPI_READ: if (!spi_read (wValueH, wValueL, wIndexH, wIndexL, EP0BUF, wLengthL)) return 0; @@ -126,6 +126,14 @@ app_vendor_cmd (void) EP0BCL = wLengthL; break; + case VRQ_SPI_TRANSACT: + if (!spi_transact (wValueH, wValueL, wIndexH, wIndexL, wLengthH, EP0BUF, wLengthL)) + return 0; + + EP0BCH = 0; + EP0BCL = wLengthL; + break; + default: return 0; } -- cgit v1.2.3 From 38746242eab47845c1b1b6cb264c3e3041977488 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 13 Aug 2010 12:59:32 -0700 Subject: usrp1: Add USB transport interfaces This patch adds generic interfaces for control and zero-copy transport of data between the host and a slave device. The interfaces are separate and generic to accommodate multiple implementations that may include cross platform libraries such as libusb or a platform specific implementation such as Linux usbfs. --- host/include/uhd/transport/CMakeLists.txt | 2 + host/include/uhd/transport/usb_control.hpp | 76 ++++++++++++++++++++++++++++ host/include/uhd/transport/usb_zero_copy.hpp | 64 +++++++++++++++++++++++ host/include/uhd/types/CMakeLists.txt | 1 + host/include/uhd/types/usb_descriptor.hpp | 49 ++++++++++++++++++ 5 files changed, 192 insertions(+) create mode 100644 host/include/uhd/transport/usb_control.hpp create mode 100644 host/include/uhd/transport/usb_zero_copy.hpp create mode 100644 host/include/uhd/types/usb_descriptor.hpp diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index 93e9a6485..dd1a20eed 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -25,6 +25,8 @@ INSTALL(FILES if_addrs.hpp udp_simple.hpp udp_zero_copy.hpp + usb_control.hpp + usb_zero_copy.hpp vrt_if_packet.hpp zero_copy.hpp DESTINATION ${INCLUDE_DIR}/uhd/transport diff --git a/host/include/uhd/transport/usb_control.hpp b/host/include/uhd/transport/usb_control.hpp new file mode 100644 index 000000000..6b5591a21 --- /dev/null +++ b/host/include/uhd/transport/usb_control.hpp @@ -0,0 +1,76 @@ +// +// Copyright 2010 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 . +// + +#ifndef INCLUDED_UHD_TRANSPORT_USB_CONTROL_HPP +#define INCLUDED_UHD_TRANSPORT_USB_CONTROL_HPP + +#include +#include +#include +#include +#include + +namespace uhd { namespace transport { + +class UHD_API usb_control : boost::noncopyable { +public: + typedef boost::shared_ptr sptr; + + /*! + * Create a new usb control transport: + * This transport is for sending and receiving control information from + * the host to device using the Default Control Pipe. + * + * \param descriptor a descriptor that identifies a USB device + */ + static sptr make(usb_descriptor_t descriptor); + + /*! + * Submit a USB device request: + * Blocks until the request returns + * + * For format and corresponding USB request fields + * see USB Specification Revision 2.0 - 9.3 USB Device Requests + * + * Usage is device specific + * + * \param request_type 1-byte bitmask (bmRequestType) + * \param request 1-byte (bRequest) + * \param value 2-byte (wValue) + * \param index 2-byte (wIndex) + * \param buff buffer to hold send or receive data + * \param length 2-byte (wLength) + * \return number of bytes submitted + */ + virtual size_t submit(boost::uint8_t request_type, + boost::uint8_t request, + boost::uint16_t value, + boost::uint16_t index, + unsigned char *buff, + boost::uint16_t length) = 0; + + /*! + * Get a vector of USB device descriptors + * + * \return a vector of usb_descriptors + */ + static usb_descriptors_t get_device_list(); +}; + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_USB_CONTROL_HPP */ diff --git a/host/include/uhd/transport/usb_zero_copy.hpp b/host/include/uhd/transport/usb_zero_copy.hpp new file mode 100644 index 000000000..7b9692fa5 --- /dev/null +++ b/host/include/uhd/transport/usb_zero_copy.hpp @@ -0,0 +1,64 @@ +// +// Copyright 2010 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 . +// + +#ifndef INCLUDED_UHD_TRANSPORT_USB_ZERO_COPY_HPP +#define INCLUDED_UHD_TRANSPORT_USB_ZERO_COPY_HPP + +#include +#include +#include +#include + +namespace uhd { namespace transport { + +/*! + * A zero copy usb transport provides an efficient way to handle data. + * by avoiding the extra copy when recv() or send() is called on the handle. + * Rather, the zero copy transport gives the caller memory references. + * The caller informs the transport when it is finished with the reference. + * + * On linux systems, the zero copy transport can use a kernel packet ring. + * If no platform specific solution is available, make returns a boost asio + * implementation that wraps functionality around standard send/recv calls. + */ +class UHD_API usb_zero_copy : public virtual zero_copy_if { +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a new zero copy usb transport: + * This transport is for sending and receiving between the host + * and a pair of USB bulk transfer endpoints. + * The primary usage for this transport is data transactions. + * The underlying implementation may be platform specific. + * + * \param descriptor a USB descriptor identifying the device + * \param rx_endpoint an integer specifiying an IN endpoint number + * \param tx_endpoint an integer specifiying an OUT endpoint number + * \param buff_size total number of bytes of buffer space to allocate + * \param block_size number of bytes allocated for each I/O transaction + */ + static sptr make(usb_descriptor_t descriptor, + unsigned int rx_endpoint, + unsigned int tx_endpoint, + size_t buff_size = 0, + size_t block_size = 0); +}; + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_USB_ZERO_COPY_HPP */ diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt index dbce21c98..8e302eed2 100644 --- a/host/include/uhd/types/CMakeLists.txt +++ b/host/include/uhd/types/CMakeLists.txt @@ -29,5 +29,6 @@ INSTALL(FILES stream_cmd.hpp time_spec.hpp tune_result.hpp + usb_descriptor.hpp DESTINATION ${INCLUDE_DIR}/uhd/types ) diff --git a/host/include/uhd/types/usb_descriptor.hpp b/host/include/uhd/types/usb_descriptor.hpp new file mode 100644 index 000000000..0e4c8c369 --- /dev/null +++ b/host/include/uhd/types/usb_descriptor.hpp @@ -0,0 +1,49 @@ +// +// Copyright 2010 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 . +// + +#ifndef INCLUDED_UHD_TYPES_USB_DESCRIPTOR_HPP +#define INCLUDED_UHD_TYPES_USB_DESCRIPTOR_HPP + +#include +#include +#include +#include + +namespace uhd{ + + /*! + * The USB descriptor struct holds identity information for a USB device + */ + struct UHD_API usb_descriptor_t{ + std::string serial; + boost::uint16_t vendor_id; + boost::uint16_t product_id; + boost::uint16_t device_addr; + + /*! + * Create a pretty print string for this USB descriptor struct. + * \return the printable string + */ + std::string to_pp_string(void) const; + }; + + //handy typde for a vector of usb descriptors + typedef std::vector usb_descriptors_t; + +} //namespace uhd + +#endif /* INCLUDED_UHD_TYPES_USB_DESCRIPTOR_HPP */ -- cgit v1.2.3 From 86c86ede9775824411262e36f104489bcd171e21 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 13 Aug 2010 13:40:13 -0700 Subject: usrp1: Add libusb-1.0 implementations of USB interfaces --- host/lib/transport/libusb1_control.cpp | 238 +++++++++ host/lib/transport/libusb1_zero_copy.cpp | 854 +++++++++++++++++++++++++++++++ 2 files changed, 1092 insertions(+) create mode 100644 host/lib/transport/libusb1_control.cpp create mode 100644 host/lib/transport/libusb1_zero_copy.cpp diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp new file mode 100644 index 000000000..2903d943d --- /dev/null +++ b/host/lib/transport/libusb1_control.cpp @@ -0,0 +1,238 @@ +// +// Copyright 2010 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 . +// + +#include +#include +#include +#include +#include +#include + +using namespace uhd::transport; + +static int libusb_debug_level = 0; +static int libusb_timeout = 0; + +/*********************************************************************** + * libusb-1.0 implementation of USB control transport + **********************************************************************/ +class libusb_control_impl : public usb_control { +public: + libusb_control_impl(uhd::usb_descriptor_t descriptor); + ~libusb_control_impl(); + + size_t submit(boost::uint8_t request_type, + boost::uint8_t request, + boost::uint16_t value, + boost::uint16_t index, + unsigned char *buff, + boost::uint16_t length); + + static uhd::usb_descriptor_t create_descriptor(libusb_device *dev); + static std::string get_serial(libusb_device *dev); + +private: + uhd::usb_descriptor_t _descriptor; + + libusb_context *_ctx; + libusb_device_handle *_dev_handle; + + bool open_device(); + bool open_interface(); + bool compare_device(libusb_device *dev, uhd::usb_descriptor_t descriptor); +}; + + +libusb_control_impl::libusb_control_impl(uhd::usb_descriptor_t descriptor) + : _descriptor(descriptor), _ctx(NULL), _dev_handle(NULL) +{ + if (libusb_init(&_ctx) < 0) + UHD_THROW_SITE_INFO("USB: failed to initialize libusb"); + + libusb_set_debug(_ctx, libusb_debug_level); + + if (!open_device()) + UHD_THROW_SITE_INFO("USB: failed to open device"); + + if (!open_interface()) + UHD_THROW_SITE_INFO("USB: failed to open device interface"); +} + + +libusb_control_impl::~libusb_control_impl() +{ + libusb_close(_dev_handle); + libusb_exit(_ctx); +} + + +uhd::usb_descriptor_t libusb_control_impl::create_descriptor(libusb_device *dev) +{ + libusb_device_descriptor desc; + + if (libusb_get_device_descriptor(dev, &desc) < 0) + UHD_THROW_SITE_INFO("USB: failed to get device descriptor"); + + uhd::usb_descriptor_t descriptor; + + descriptor.serial = get_serial(dev); + descriptor.product_id = desc.idProduct; + descriptor.vendor_id = desc.idVendor; + descriptor.device_addr = libusb_get_device_address(dev); + + return descriptor; +} + + +std::string libusb_control_impl::get_serial(libusb_device *dev) +{ + unsigned char buff[32]; + + libusb_device_descriptor desc; + if (libusb_get_device_descriptor(dev, &desc) < 0) + return ""; + + if (desc.iSerialNumber == 0) + return ""; + + //open the device because we have to + libusb_device_handle *dev_handle; + if (libusb_open(dev, &dev_handle) < 0) + return ""; + + if (libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber, + buff, sizeof(buff)) < 0) { + return ""; + } + + libusb_close(dev_handle); + + return (char*) buff; +} + + +bool libusb_control_impl::open_device() +{ + libusb_device **list; + libusb_device *dev; + + ssize_t cnt = libusb_get_device_list(_ctx, &list); + + if (cnt < 0) + return cnt; + + ssize_t i = 0; + for (i = 0; i < cnt; i++) { + dev = list[i]; + if (compare_device(dev, _descriptor)) + goto found; + } + return false; + +found: + int ret; + if ((ret = libusb_open(dev, &_dev_handle)) < 0) + return false; + else + return true; +} + + +bool libusb_control_impl::compare_device(libusb_device *dev, + uhd::usb_descriptor_t descriptor) +{ + std::string serial = descriptor.serial; + boost::uint16_t vendor_id = descriptor.vendor_id; + boost::uint16_t product_id = descriptor.product_id; + boost::uint8_t device_addr = descriptor.device_addr; + + libusb_device_descriptor libusb_desc; + if (libusb_get_device_descriptor(dev, &libusb_desc) < 0) + return false; + if (serial != get_serial(dev)) + return false; + if (vendor_id != libusb_desc.idVendor) + return false; + if (product_id != libusb_desc.idProduct) + return false; + if (device_addr != libusb_get_device_address(dev)) + return false; + + return true; +} + + +bool libusb_control_impl::open_interface() +{ + if (libusb_claim_interface(_dev_handle, 0) < 0) + return false; + else + return true; +} + + +size_t libusb_control_impl::submit(boost::uint8_t request_type, + boost::uint8_t request, + boost::uint16_t value, + boost::uint16_t index, + unsigned char *buff, + boost::uint16_t length) +{ + return libusb_control_transfer(_dev_handle, + request_type, + request, + value, + index, + buff, + length, + libusb_timeout); +} + + +/*********************************************************************** + * USB control public make functions + **********************************************************************/ +usb_control::sptr usb_control::make(uhd::usb_descriptor_t descriptor) +{ + return sptr(new libusb_control_impl(descriptor)); +} + +uhd::usb_descriptors_t usb_control::get_device_list() +{ + libusb_device **list; + uhd::usb_descriptors_t descriptors; + + if (libusb_init(NULL) < 0) + UHD_THROW_SITE_INFO("USB: failed to initialize libusb"); + + ssize_t cnt = libusb_get_device_list(NULL, &list); + + if (cnt < 0) + UHD_THROW_SITE_INFO("USB: failed to get device list"); + + ssize_t i = 0; + for (i = 0; i < cnt; i++) { + libusb_device *dev = list[i]; + descriptors.push_back(libusb_control_impl::create_descriptor(dev)); + } + + libusb_free_device_list(list, 0); + libusb_exit(NULL); + return descriptors; +} + + diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp new file mode 100644 index 000000000..39617e4dd --- /dev/null +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -0,0 +1,854 @@ +// +// Copyright 2010 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 . +// + + +#include +#include +#include +#include +#include +#include +#include + +using namespace uhd::transport; + +static int libusb_debug_level = 3; + +/*********************************************************************** + * Helper functions + * + * Print to stdout the values of a libusb_transfer struct + ***********************************************************************/ +void pp_transfer(libusb_transfer *lut) +{ + std::cout << "Libusb transfer" << std::endl; + std::cout << " flags: 0x" << std::hex << (unsigned int) lut->flags << std::endl; + std::cout << " endpoint: 0x" << std::hex << (unsigned int) lut->endpoint << std::endl; + std::cout << " type: 0x" << std::hex << (unsigned int) lut->type << std::endl; + std::cout << " timeout: " << std::dec << lut->timeout << std::endl; + std::cout << " status: 0x" << std::hex << lut->status << std::endl; + std::cout << " length: " << std::dec << lut->length << std::endl; + std::cout << " actual_length: " << std::dec << lut->actual_length << std::endl; +} + +/*********************************************************************** + * USB asynchronous phony zero_copy endpoint + * This endpoint implementation provides asynchronous I/O to libusb-1.0 + * devices. Each endpoint is directional and two can be combined to + * create a bidirectional interface. It is a zero copy implementation + * with respect to libusb, however, each send and recv requires a copy + * operation from kernel to userspace; this is due to the usbfs + * interface provided by the kernel. + **********************************************************************/ +class usb_endpoint { +private: + libusb_device_handle *_dev_handle; + libusb_context *_ctx; + int _endpoint; + bool _input; + + size_t _transfer_size; + size_t _num_transfers; + + /* + * Transfer state lists (free, pending, or completed) + */ + std::list _free_list; + std::list _pending_list; + std::list _completed_list; + + /* + * Calls for processing asynchronous I/O + */ + libusb_transfer *allocate_transfer(int buff_len); + bool cancel(libusb_transfer *lut); + bool cancel_all(); + bool reap_pending_list(); + bool reap_pending_list_timeout(); + bool reap_completed_list(); + + /* + * Transfer state manipulators + */ + void free_list_add(libusb_transfer *lut); + void pending_list_add(libusb_transfer *lut); + void completed_list_add(libusb_transfer *lut); + libusb_transfer *free_list_get(); + libusb_transfer *completed_list_get(); + bool pending_list_remove(libusb_transfer *lut); + + /* + * Misc + */ + void print_transfer_status(libusb_transfer *lut); + +public: + usb_endpoint(libusb_device_handle *dev_handle, + libusb_context *ctx, int endpoint, bool input, + size_t transfer_size, size_t num_transfers); + + ~usb_endpoint(); + + /* + * Accessors + */ + int get_endpoint() const { return _endpoint; } + bool get_direction() const { return _input; } + libusb_device_handle *get_dev_handle() const { return _dev_handle; } + libusb_context *get_ctx() const { return _ctx; } + + /* + * Exposed interface for submitting / retrieving transfer buffers + * used in zero-copy interface + */ + bool submit(libusb_transfer *lut); + libusb_transfer *get_completed_transfer(); + libusb_transfer *get_free_transfer(); + + /* + * Callback use only + */ + void callback_handle_transfer(libusb_transfer *lut); +}; + + +/* + * Callback function called when submitted transfers complete. + * The endpoint upon which the transfer is part of is recovered + * and the transfer moved from pending to completed state. + */ +static void callback(libusb_transfer *lut) +{ + usb_endpoint *endpoint = (usb_endpoint *) lut->user_data; + endpoint->callback_handle_transfer(lut); +} + + +/* + * Accessor call to allow list access from callback space + */ +void usb_endpoint::callback_handle_transfer(libusb_transfer *lut) +{ + if (!pending_list_remove(lut)) { + std::cerr << "USB: pending remove failed" << std::endl; + return; + } + + completed_list_add(lut); +} + + +/* + * Constructor + * + * Allocate libusb transfers. For IN endpoints, submit the transfers + * so that they're ready to return when data is available. + */ +usb_endpoint::usb_endpoint(libusb_device_handle *dev_handle, + libusb_context *ctx, int endpoint, bool input, + size_t transfer_size, size_t num_transfers) + : _dev_handle(dev_handle), + _ctx(ctx), _endpoint(endpoint), _input(input), + _transfer_size(transfer_size), _num_transfers(num_transfers) +{ + unsigned int i; + for (i = 0; i < _num_transfers; i++) { + free_list_add(allocate_transfer(_transfer_size)); + + if (_input) + submit(free_list_get()); + } +} + + +/* + * Destructor + */ +usb_endpoint::~usb_endpoint() +{ + cancel_all(); + + while (!_pending_list.empty()) { + if (!reap_pending_list()) + std::cerr << "error: destructor failed to reap" << std::endl; + } + + while (!_completed_list.empty()) { + if (!reap_completed_list()) + std::cerr << "error: destructor failed to reap" << std::endl; + } + + while (!_free_list.empty()) { + libusb_free_transfer(free_list_get()); + } +} + + +/* + * Allocate a libusb transfer + * + * The allocated transfer is continuously reused and should be freed at + * shutdown. + */ +libusb_transfer *usb_endpoint::allocate_transfer(int buff_len) +{ + libusb_transfer *lut = libusb_alloc_transfer(0); + + unsigned char *buff = new unsigned char[buff_len]; + + unsigned int endpoint = ((_endpoint & 0x7f) | (_input ? 0x80 : 0)); + + libusb_fill_bulk_transfer(lut, // transfer + _dev_handle, // dev_handle + endpoint, // endpoint + buff, // buffer + buff_len, // length + callback, // callback + this, // user_data + 0); // timeout + return lut; +} + + +/* + * Asynchonous transfer submission + * + * Submit and mark transfer as pending. + */ +bool usb_endpoint::submit(libusb_transfer *lut) +{ + int retval; + if ((retval = libusb_submit_transfer(lut)) < 0) { + std::cerr << "error: libusb_submit_transfer: " << retval << std::endl; + return false; + } + + pending_list_add(lut); + return true; +} + + +/* + * Cancel a pending transfer + * + * Search the pending list for the transfer and cancel if found. + * Returns true on success. False otherwise or on error. + * + * Note: success only indicates submission of cancelation request. + * Sucessful cancelation is not known until the callback occurs. + */ +bool usb_endpoint::cancel(libusb_transfer *lut) +{ + std::list::iterator iter; + for (iter = _pending_list.begin(); iter != _pending_list.end(); iter++) { + if (*iter == lut) { + libusb_cancel_transfer(lut); + return true; + } + } + return false; +} + + +/* + * Cancel all pending transfers + * + * Note: success only indicates submission of cancelation request. + * Sucessful cancelation is not known until the callback occurs. + */ +bool usb_endpoint::cancel_all() +{ + std::list::iterator iter; + + for (iter = _pending_list.begin(); iter != _pending_list.end(); iter++) { + if (libusb_cancel_transfer(*iter) < 0) { + std::cerr << "error: libusb_cancal_transfer() failed" << std::endl; + return false; + } + } + + return true; +} + + +/* + * Reap completed transfers + * + * return true if at least one transfer was reaped, false otherwise. + * + * Check completed transfers for errors and mark as free. This is a + * blocking call. + */ +bool usb_endpoint::reap_completed_list() +{ + libusb_transfer *lut; + + if (_completed_list.empty()) { + if (!reap_pending_list_timeout()) + return false; + } + + while (!_completed_list.empty()) { + lut = completed_list_get(); + print_transfer_status(lut); + free_list_add(lut); + } + + return true; +} + + +/* + * Print completed transfer status error(s) + * + * return true if at least one transfer was reaped, false otherwise. + * + * Check completed transfers for errors and mark as free. This is a + * blocking call. + */ +void usb_endpoint::print_transfer_status(libusb_transfer *lut) +{ + switch (lut->status) { + case LIBUSB_TRANSFER_COMPLETED: + if (lut->actual_length < lut->length) { + std::cerr << "USB: transfer completed with short write," + << " length = " << lut->length + << " actual = " << lut->actual_length << std::endl; + } + + if ((lut->actual_length < 0) || (lut->length < 0)) { + std::cerr << "USB: transfer completed with invalid response" + << std::endl; + } + break; + case LIBUSB_TRANSFER_CANCELLED: + break; + case LIBUSB_TRANSFER_NO_DEVICE: + std::cerr << "USB: device was disconnected" << std::endl; + break; + case LIBUSB_TRANSFER_OVERFLOW: + std::cerr << "USB: device sent more data than requested" << std::endl; + break; + case LIBUSB_TRANSFER_TIMED_OUT: + std::cerr << "USB: transfer timed out" << std::endl; + break; + case LIBUSB_TRANSFER_STALL: + std::cerr << "USB: halt condition detected (endpoint stalled)" << std::endl; + break; + case LIBUSB_TRANSFER_ERROR: + std::cerr << "USB: transfer failed" << std::endl; + break; + default: + std::cerr << "USB: received unknown transfer status" << std::endl; + } +} + + +/* + * Reap pending transfers + * + * Return true if at least one transfer was reaped, false otherwise. This is + * a blocking call. + * + * Reaping submitted transfers is handled by libusb and the assigned callback + * function. Block until at least one transfer is reaped. + */ +bool usb_endpoint::reap_pending_list() +{ + int retval; + + if ((retval = libusb_handle_events(_ctx)) < 0) { + std::cerr << "error: libusb_handle_events: " << retval << std::endl; + return false; + } + + return true; +} + + +/* + * Reap pending transfers with timeout + * + * Return true if at least one transfer was reaped, false otherwise. This call + * blocks until a transfer is reaped or timeout. + * + * Reaping submitted transfers is handled by libusb and the assigned callback + * function. Block until at least one transfer is reaped or timeout occurs. + */ +bool usb_endpoint::reap_pending_list_timeout() +{ + int retval; + timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 100000; //100ms + + size_t pending_list_size = _pending_list.size(); + + if ((retval = libusb_handle_events_timeout(_ctx, &tv)) < 0) { + std::cerr << "error: libusb_handle_events: " << retval << std::endl; + return false; + } + + if (_pending_list.size() < pending_list_size) { + return true; + } + else { + return false; + } +} + + +/* + * Returns a free transfer with empty data bufer for OUT requests + */ +libusb_transfer *usb_endpoint::get_free_transfer() +{ + if (_free_list.empty()) { + if (!reap_completed_list()) + return NULL; + } + + return free_list_get(); +} + + +/* + * Returns a transfer containing data for IN requests + */ +libusb_transfer *usb_endpoint::get_completed_transfer() +{ + if (_completed_list.empty()) { + if (!reap_pending_list_timeout()) + return NULL; + } + + return completed_list_get(); +} + +/* + * List operations + */ +void usb_endpoint::free_list_add(libusb_transfer *lut) +{ + _free_list.push_back(lut); +} + +void usb_endpoint::pending_list_add(libusb_transfer *lut) +{ + _pending_list.push_back(lut); +} + +void usb_endpoint::completed_list_add(libusb_transfer *lut) +{ + _completed_list.push_back(lut); +} + + +/* + * Free and completed lists don't have ordered content + * + * Pop transfers from the front as needed + */ +libusb_transfer *usb_endpoint::free_list_get() +{ + libusb_transfer *lut; + + if (_free_list.size() == 0) { + return NULL; + } + else { + lut = _free_list.front(); + _free_list.pop_front(); + return lut; + } +} + + +/* + * Free and completed lists don't have ordered content + * + * Pop transfers from the front as needed + */ +libusb_transfer *usb_endpoint::completed_list_get() +{ + libusb_transfer *lut; + + if (_completed_list.empty()) { + return NULL; + } + else { + lut = _completed_list.front(); + _completed_list.pop_front(); + return lut; + } +} + + +/* + * Search and remove transfer from pending list + * + * Assuming that the callbacks occur in order, the front element + * should yield the correct transfer. If not, then something else + * is going on. If no transfers match, then something went wrong. + */ +bool usb_endpoint::pending_list_remove(libusb_transfer *lut) +{ + std::list::iterator iter; + for (iter = _pending_list.begin(); iter != _pending_list.end(); iter++) { + if (*iter == lut) { + _pending_list.erase(iter); + return true; + } + } + return false; +} + + +/*********************************************************************** + * Managed buffers + **********************************************************************/ +class libusb_managed_recv_buffer_impl : public managed_recv_buffer { +public: + libusb_managed_recv_buffer_impl(libusb_transfer *lut, + usb_endpoint *endpoint) + : _buff(lut->buffer, lut->length) + { + _lut = lut; + _endpoint = endpoint; + } + + ~libusb_managed_recv_buffer_impl() + { + if (!_endpoint->submit(_lut)) + std::cerr << "USB: failed to submit IN transfer" << std::endl; + } + +private: + const boost::asio::const_buffer &get() const + { + return _buff; + } + + libusb_transfer *_lut; + usb_endpoint *_endpoint; + const boost::asio::const_buffer _buff; +}; + + +class libusb_managed_send_buffer_impl : public managed_send_buffer { +public: + libusb_managed_send_buffer_impl(libusb_transfer *lut, + usb_endpoint *endpoint, + size_t buff_size) + : _buff(lut->buffer, buff_size) + { + _lut = lut; + _endpoint = endpoint; + } + + ~libusb_managed_send_buffer_impl() + { + /* NOP */ + } + + ssize_t commit(size_t num_bytes) + { + _lut->length = num_bytes; + _lut->actual_length = 0; + + if (_endpoint->submit(_lut)) + return num_bytes; + else + return 0; + } + +private: + const boost::asio::mutable_buffer &get() const + { + return _buff; + } + + libusb_transfer *_lut; + usb_endpoint *_endpoint; + const boost::asio::mutable_buffer _buff; +}; + + +/*********************************************************************** + * USB zero_copy device class + **********************************************************************/ +class libusb_zero_copy_impl : public usb_zero_copy +{ +private: + usb_endpoint *_rx_ep; + usb_endpoint *_tx_ep; + + /* + * Libusb handles + */ + libusb_context *_rx_ctx; + libusb_context *_tx_ctx; + libusb_device_handle *_rx_dev_handle; + libusb_device_handle *_tx_dev_handle; + + int _rx_endpoint; + int _tx_endpoint; + + size_t _recv_buff_size; + size_t _send_buff_size; + size_t _num_frames; + + bool open_device(uhd::usb_descriptor_t descriptor); + bool open_interface(libusb_device_handle *dev_handle, int interface); + bool compare_device(libusb_device *dev, uhd::usb_descriptor_t descriptor); + + std::string get_serial(libusb_device *dev); + +public: + typedef boost::shared_ptr sptr; + + /* + * Structors + */ + libusb_zero_copy_impl(uhd::usb_descriptor_t descriptor, + unsigned int rx_endpoint, + unsigned int tx_endpoint, + size_t recv_buff_size, + size_t send_buff_size); + + ~libusb_zero_copy_impl(); + + managed_recv_buffer::sptr get_recv_buff(void); + managed_send_buffer::sptr get_send_buff(void); + + size_t get_num_recv_frames(void) const { return _num_frames; } + size_t get_num_send_frames(void) const { return _num_frames; } +}; + + +libusb_zero_copy_impl::libusb_zero_copy_impl(uhd::usb_descriptor_t descriptor, + unsigned int rx_endpoint, + unsigned int tx_endpoint, + size_t buff_size, + size_t block_size) + : _rx_ctx(NULL), _tx_ctx(NULL), _rx_dev_handle(NULL), _tx_dev_handle(NULL), + _recv_buff_size(block_size), _send_buff_size(block_size), + _num_frames(buff_size / block_size) +{ + if (libusb_init(&_rx_ctx) < 0) + std::cerr << "error: libusb_init" << std::endl; + + if (libusb_init(&_tx_ctx) < 0) + std::cerr << "error: libusb_init" << std::endl; + + libusb_set_debug(_rx_ctx, libusb_debug_level); + libusb_set_debug(_tx_ctx, libusb_debug_level); + + open_device(descriptor); + + open_interface(_rx_dev_handle, 2); + open_interface(_tx_dev_handle, 1); + + _rx_ep = new usb_endpoint(_rx_dev_handle, + _rx_ctx, + rx_endpoint, + true, + _recv_buff_size, + _num_frames); + + _tx_ep = new usb_endpoint(_tx_dev_handle, + _tx_ctx, + tx_endpoint, + false, + _send_buff_size, + _num_frames); +} + + +libusb_zero_copy_impl::~libusb_zero_copy_impl() +{ + delete _rx_ep; + delete _tx_ep; + + libusb_close(_rx_dev_handle); + libusb_close(_tx_dev_handle); + + libusb_exit(_rx_ctx); + libusb_exit(_tx_ctx); +} + + +bool libusb_zero_copy_impl::open_device(uhd::usb_descriptor_t descriptor) +{ + libusb_device **rx_list; + libusb_device **tx_list; + + bool rx_found = false; + bool tx_found = false; + + ssize_t rx_cnt = libusb_get_device_list(_rx_ctx, &rx_list); + ssize_t tx_cnt = libusb_get_device_list(_tx_ctx, &tx_list); + + if ((rx_cnt < 0) | (tx_cnt < 0) | (rx_cnt != tx_cnt)) + return false; + + //find and open the receive device + for (ssize_t i = 0; i < rx_cnt; i++) { + libusb_device *dev = rx_list[i]; + + if (compare_device(dev, descriptor)) { + libusb_open(dev, &_rx_dev_handle); + rx_found = true; + break; + } + } + + //find and open the transmit device + for (ssize_t i = 0; i < tx_cnt; i++) { + libusb_device *dev = tx_list[i]; + + if (compare_device(dev, descriptor)) { + libusb_open(dev, &_tx_dev_handle); + tx_found = true; + } + } + + libusb_free_device_list(rx_list, 0); + libusb_free_device_list(tx_list, 0); + + if (tx_found && rx_found) + return true; + else + return false; +} + +bool libusb_zero_copy_impl::compare_device(libusb_device *dev, + uhd::usb_descriptor_t descriptor) +{ + std::string serial = descriptor.serial; + boost::uint16_t vendor_id = descriptor.vendor_id; + boost::uint16_t product_id = descriptor.product_id; + boost::uint8_t device_addr = descriptor.device_addr; + + libusb_device_descriptor desc; + libusb_get_device_descriptor(dev, &desc); + + if (serial.compare(get_serial(dev))) + return false; + if (vendor_id != desc.idVendor) + return false; + if (product_id != desc.idProduct) + return false; + if (device_addr != libusb_get_device_address(dev)) + return false; + + return true; +} + +bool libusb_zero_copy_impl::open_interface(libusb_device_handle *dev_handle, + int interface) +{ + int ret = libusb_claim_interface(dev_handle, interface); + if (ret < 0) { + std::cerr << "error: libusb_claim_interface() " << ret << std::endl; + return false; + } + else { + return true; + } +} + +std::string libusb_zero_copy_impl::get_serial(libusb_device *dev) +{ + unsigned char buff[32]; + + libusb_device_descriptor desc; + if (libusb_get_device_descriptor(dev, &desc) < 0) { + std::cerr << "error: libusb_get_device_descriptor()" << std::endl; + return ""; + } + + if (desc.iSerialNumber == 0) + return ""; + + //open the device because we have to + libusb_device_handle *dev_handle; + if (libusb_open(dev, &dev_handle) < 0) { + return ""; + } + + if (libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber, + buff, sizeof(buff)) < 0) { + std::cerr << "error: libusb_get_string_descriptor_ascii()" << std::endl; + return ""; + } + + libusb_close(dev_handle); + + return (char*) buff; +} + + +managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff() +{ + libusb_transfer *lut = _rx_ep->get_completed_transfer(); + if (lut == NULL) { + return managed_recv_buffer::sptr(); + } + else { + return managed_recv_buffer::sptr( + new libusb_managed_recv_buffer_impl(lut, + _rx_ep)); + } +} + + +managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff() +{ + libusb_transfer *lut = _tx_ep->get_free_transfer(); + if (lut == NULL) { + return managed_send_buffer::sptr(); + } + else { + return managed_send_buffer::sptr( + new libusb_managed_send_buffer_impl(lut, + _tx_ep, + _send_buff_size)); + } +} + + +/*********************************************************************** + * USB zero_copy make functions + **********************************************************************/ +usb_zero_copy::sptr usb_zero_copy::make(uhd::usb_descriptor_t descriptor, + unsigned int rx_endpoint, + unsigned int tx_endpoint, + size_t buff_size, + size_t block_size) + +{ + return sptr(new libusb_zero_copy_impl(descriptor, + rx_endpoint, + tx_endpoint, + buff_size, + block_size)); +} + + + -- cgit v1.2.3 From d10de2f6a68ebf0611368e50d85709cbecf8fd0f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 13 Aug 2010 16:06:14 -0700 Subject: usrp1: Cmake changes to find libusb-1.0 FindUSB1.cmake file imported from the libFTDI project, http://www.intra2net.com/en/developer/libftdi --- host/lib/transport/CMakeLists.txt | 15 +++++++++++++++ host/lib/transport/FindUSB1.cmake | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 host/lib/transport/FindUSB1.cmake diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index bde2b72b9..d6e1ff7ba 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -17,6 +17,21 @@ #This file will be included by cmake, use absolute paths! +######################################################################## +# Setup libusb +######################################################################## +LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/lib/transport) +FIND_PACKAGE(USB1 REQUIRED) + +IF(LIBUSB_FOUND) + INCLUDE_DIRECTORIES(${LIBUSB_INCLUDE_DIR}) + LIBUHD_APPEND_LIBS(${LIBUSB_LIBRARIES}) + LIBUHD_APPEND_SOURCES( + ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_control.cpp + ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_zero_copy.cpp + ) +ENDIF(LIBUSB_FOUND) + ######################################################################## # Check for SIMD headers ######################################################################## diff --git a/host/lib/transport/FindUSB1.cmake b/host/lib/transport/FindUSB1.cmake new file mode 100644 index 000000000..ebcac99eb --- /dev/null +++ b/host/lib/transport/FindUSB1.cmake @@ -0,0 +1,38 @@ +# - Try to find the freetype library +# Once done this defines +# +# LIBUSB_FOUND - system has libusb +# LIBUSB_INCLUDE_DIR - the libusb include directory +# LIBUSB_LIBRARIES - Link these to use libusb + +# Copyright (c) 2006, 2008 Laurent Montel, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +if (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) + + # in cache already + set(LIBUSB_FOUND TRUE) + +else (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) + IF (NOT WIN32) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + find_package(PkgConfig) + pkg_check_modules(PC_LIBUSB libusb-1.0) + ENDIF(NOT WIN32) + + FIND_PATH(LIBUSB_INCLUDE_DIR libusb.h + PATHS ${PC_LIBUSB_INCLUDEDIR} ${PC_LIBUSB_INCLUDE_DIRS}) + + FIND_LIBRARY(LIBUSB_LIBRARIES NAMES usb-1.0 + PATHS ${PC_LIBUSB_LIBDIR} ${PC_LIBUSB_LIBRARY_DIRS}) + + include(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBUSB DEFAULT_MSG LIBUSB_LIBRARIES LIBUSB_INCLUDE_DIR) + + MARK_AS_ADVANCED(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES) + +endif (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) -- cgit v1.2.3 From 9cb9e7d52255d3e14e57867eee76b555f705954c Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 13 Aug 2010 16:20:41 -0700 Subject: usrp1: Add usrp1 implementation --- host/lib/usrp/CMakeLists.txt | 1 + host/lib/usrp/usrp1/CMakeLists.txt | 39 ++++ host/lib/usrp/usrp1/clock_ctrl.cpp | 124 ++++++++++ host/lib/usrp/usrp1/clock_ctrl.hpp | 88 +++++++ host/lib/usrp/usrp1/codec_ctrl.cpp | 441 +++++++++++++++++++++++++++++++++++ host/lib/usrp/usrp1/codec_ctrl.hpp | 76 ++++++ host/lib/usrp/usrp1/codec_impl.cpp | 156 +++++++++++++ host/lib/usrp/usrp1/dboard_iface.cpp | 304 ++++++++++++++++++++++++ host/lib/usrp/usrp1/dboard_impl.cpp | 196 ++++++++++++++++ host/lib/usrp/usrp1/dsp_impl.cpp | 197 ++++++++++++++++ host/lib/usrp/usrp1/io_impl.cpp | 229 ++++++++++++++++++ host/lib/usrp/usrp1/mboard_impl.cpp | 188 +++++++++++++++ host/lib/usrp/usrp1/usrp1_ctrl.cpp | 381 ++++++++++++++++++++++++++++++ host/lib/usrp/usrp1/usrp1_ctrl.hpp | 132 +++++++++++ host/lib/usrp/usrp1/usrp1_iface.cpp | 262 +++++++++++++++++++++ host/lib/usrp/usrp1/usrp1_iface.hpp | 100 ++++++++ host/lib/usrp/usrp1/usrp1_impl.cpp | 196 ++++++++++++++++ host/lib/usrp/usrp1/usrp1_impl.hpp | 182 +++++++++++++++ 18 files changed, 3292 insertions(+) create mode 100644 host/lib/usrp/usrp1/CMakeLists.txt create mode 100644 host/lib/usrp/usrp1/clock_ctrl.cpp create mode 100644 host/lib/usrp/usrp1/clock_ctrl.hpp create mode 100644 host/lib/usrp/usrp1/codec_ctrl.cpp create mode 100644 host/lib/usrp/usrp1/codec_ctrl.hpp create mode 100644 host/lib/usrp/usrp1/codec_impl.cpp create mode 100644 host/lib/usrp/usrp1/dboard_iface.cpp create mode 100644 host/lib/usrp/usrp1/dboard_impl.cpp create mode 100644 host/lib/usrp/usrp1/dsp_impl.cpp create mode 100644 host/lib/usrp/usrp1/io_impl.cpp create mode 100644 host/lib/usrp/usrp1/mboard_impl.cpp create mode 100644 host/lib/usrp/usrp1/usrp1_ctrl.cpp create mode 100644 host/lib/usrp/usrp1/usrp1_ctrl.hpp create mode 100644 host/lib/usrp/usrp1/usrp1_iface.cpp create mode 100644 host/lib/usrp/usrp1/usrp1_iface.hpp create mode 100644 host/lib/usrp/usrp1/usrp1_impl.cpp create mode 100644 host/lib/usrp/usrp1/usrp1_impl.hpp diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index d951ab412..8272c4ba0 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -32,4 +32,5 @@ LIBUHD_APPEND_SOURCES( ) INCLUDE(${CMAKE_SOURCE_DIR}/lib/usrp/dboard/CMakeLists.txt) +INCLUDE(${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/CMakeLists.txt) INCLUDE(${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/CMakeLists.txt) diff --git a/host/lib/usrp/usrp1/CMakeLists.txt b/host/lib/usrp/usrp1/CMakeLists.txt new file mode 100644 index 000000000..eb7bd4b06 --- /dev/null +++ b/host/lib/usrp/usrp1/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# Copyright 2010 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 . +# + +#This file will be included by cmake, use absolute paths! + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../firmware/fx2/include) + +LIBUHD_APPEND_SOURCES( + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/clock_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/clock_ctrl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/codec_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/codec_ctrl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/codec_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/dboard_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/dboard_iface.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/dsp_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/io_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/mboard_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_iface.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_iface.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_impl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_ctrl.hpp +) diff --git a/host/lib/usrp/usrp1/clock_ctrl.cpp b/host/lib/usrp/usrp1/clock_ctrl.cpp new file mode 100644 index 000000000..c83ad4c68 --- /dev/null +++ b/host/lib/usrp/usrp1/clock_ctrl.cpp @@ -0,0 +1,124 @@ +// +// Copyright 2010 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 . +// + +#include "clock_ctrl.hpp" +#include "fpga_regs_standard.h" +#include +#include +#include +#include +#include +#include + +using namespace uhd; + +/*********************************************************************** + * Constants + **********************************************************************/ +static const double master_clock_rate = 64e6; + +/*********************************************************************** + * Clock Control Implementation + **********************************************************************/ +class usrp1_clock_ctrl_impl : public usrp1_clock_ctrl { +public: + usrp1_clock_ctrl_impl(usrp1_iface::sptr iface) + { + _iface = iface; + } + + double get_master_clock_freq(void) + { + return master_clock_rate; + } + + /*********************************************************************** + * RX Dboard Clock Control (output 9, divider 3) + **********************************************************************/ + void enable_rx_dboard_clock(bool) + { + std::cerr << "USRP: enable_rx_dboard_clock() disabled" << std::endl; + _iface->poke32(FR_RX_A_REFCLK, 0); + _iface->poke32(FR_RX_B_REFCLK, 0); + } + + std::vector get_rx_dboard_clock_rates(void) + { +#if 0 + std::vector rates; + for (size_t div = 1; div <= 127; div++) + rates.push_back(master_clock_rate / div); + return rates; +#else + return std::vector(1, 64e6); +#endif + } + + /* + * Daughterboard reference clock register + * + * Bit 7 - 1 turns on refclk, 0 allows IO use + * Bits 6:0 - Divider value + */ + void set_rx_dboard_clock_rate(double) + { +#if 0 + assert_has(get_rx_dboard_clock_rates(), rate, "rx dboard clock rate"); + size_t divider = size_t(rate/master_clock_rate); + _iface->poke32(FR_RX_A_REFCLK, (divider & 0x7f) | 0x80); +#else + std::cerr << "USRP: set_rx_dboard_clock_rate() disabled" << std::endl; + _iface->poke32(FR_RX_A_REFCLK, 0); + _iface->poke32(FR_RX_B_REFCLK, 0); +#endif + } + + /*********************************************************************** + * TX Dboard Clock Control + **********************************************************************/ + void enable_tx_dboard_clock(bool) + { + std::cerr << "USRP: set_tx_dboard_clock() disabled" << std::endl; + _iface->poke32(FR_TX_A_REFCLK, 0); + _iface->poke32(FR_TX_B_REFCLK, 0); + + } + + std::vector get_tx_dboard_clock_rates(void) + { + return get_rx_dboard_clock_rates(); //same master clock, same dividers... + } + + void set_tx_dboard_clock_rate(double) + { + std::cerr << "USRP: set_tx_dboard_clock_rate() disabled" << std::endl; + _iface->poke32(FR_TX_A_REFCLK, 0); + _iface->poke32(FR_TX_B_REFCLK, 0); + } + +private: + usrp1_iface::sptr _iface; + +}; + +/*********************************************************************** + * Clock Control Make + **********************************************************************/ +usrp1_clock_ctrl::sptr usrp1_clock_ctrl::make(usrp1_iface::sptr iface) +{ + return sptr(new usrp1_clock_ctrl_impl(iface)); +} diff --git a/host/lib/usrp/usrp1/clock_ctrl.hpp b/host/lib/usrp/usrp1/clock_ctrl.hpp new file mode 100644 index 000000000..9ba4d56e3 --- /dev/null +++ b/host/lib/usrp/usrp1/clock_ctrl.hpp @@ -0,0 +1,88 @@ +// +// Copyright 2010 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 . +// + +#ifndef INCLUDED_USRP1_CLOCK_CTRL_HPP +#define INCLUDED_USRP1_CLOCK_CTRL_HPP + +#include "usrp1_iface.hpp" +#include +#include +#include + +/*! + * The usrp1 clock control: + * - Setup system clocks. + * - Disable/enable clock lines. + */ +class usrp1_clock_ctrl : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a new clock control object. + * \param iface the usrp1 iface object + * \return the clock control object + */ + static sptr make(usrp1_iface::sptr iface); + + /*! + * Get the rate of the fpga clock line. + * \return the fpga clock rate in Hz + */ + virtual double get_master_clock_freq(void) = 0; + + /*! + * Get the possible rates of the rx dboard clock. + * \return a vector of clock rates in Hz + */ + virtual std::vector get_rx_dboard_clock_rates(void) = 0; + + /*! + * Get the possible rates of the tx dboard clock. + * \return a vector of clock rates in Hz + */ + virtual std::vector get_tx_dboard_clock_rates(void) = 0; + + /*! + * Set the rx dboard clock rate to a possible rate. + * \param rate the new clock rate in Hz + * \throw exception when rate cannot be achieved + */ + virtual void set_rx_dboard_clock_rate(double rate) = 0; + + /*! + * Set the tx dboard clock rate to a possible rate. + * \param rate the new clock rate in Hz + * \throw exception when rate cannot be achieved + */ + virtual void set_tx_dboard_clock_rate(double rate) = 0; + + /*! + * Enable/disable the rx dboard clock. + * \param enb true to enable + */ + virtual void enable_rx_dboard_clock(bool enb) = 0; + + /*! + * Enable/disable the tx dboard clock. + * \param enb true to enable + */ + virtual void enable_tx_dboard_clock(bool enb) = 0; + +}; + +#endif /* INCLUDED_USRP1_CLOCK_CTRL_HPP */ diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp new file mode 100644 index 000000000..866650c2c --- /dev/null +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -0,0 +1,441 @@ +// +// Copyright 2010 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 . +// + +#include "codec_ctrl.hpp" +#include "usrp_commands.h" +#include "fpga_regs_standard.h" +#include "usrp_spi_defs.h" +#include "ad9862_regs.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace uhd; + +static const bool codec_debug = true; + +const gain_range_t usrp1_codec_ctrl::tx_pga_gain_range(-20, 0, float(0.1)); +const gain_range_t usrp1_codec_ctrl::rx_pga_gain_range(0, 20, 1); + +/*********************************************************************** + * Codec Control Implementation + **********************************************************************/ +class usrp1_codec_ctrl_impl : public usrp1_codec_ctrl { +public: + //structors + usrp1_codec_ctrl_impl(usrp1_iface::sptr iface); + ~usrp1_codec_ctrl_impl(void); + + //aux adc and dac control + float read_aux_adc(aux_adc_t which); + void write_aux_dac(aux_dac_t which, float volts); + + //duc control + bool set_duc_freq(double freq); + + //pga gain control + void set_tx_pga_gain(float); + float get_tx_pga_gain(void); + void set_rx_pga_gain(float, char); + float get_rx_pga_gain(char); + +private: + usrp1_iface::sptr _iface; + ad9862_regs_t _ad9862_regs; + aux_adc_t _last_aux_adc_a, _last_aux_adc_b; + void send_reg(boost::uint8_t addr); + void recv_reg(boost::uint8_t addr); + + //FIXME: poison + double _tx_freq[4]; + unsigned int compute_freq_control_word_9862 (double master_freq, + double target_freq, + double *actual_freq); +}; + +/*********************************************************************** + * Codec Control Structors + **********************************************************************/ +usrp1_codec_ctrl_impl::usrp1_codec_ctrl_impl(usrp1_iface::sptr iface) +{ + _iface = iface; + + //soft reset + _ad9862_regs.soft_reset = 1; + this->send_reg(0); + + //initialize the codec register settings + _ad9862_regs.sdio_bidir = ad9862_regs_t::SDIO_BIDIR_SDIO_SDO; + _ad9862_regs.lsb_first = ad9862_regs_t::LSB_FIRST_MSB; + _ad9862_regs.soft_reset = 0; + + //setup rx side of codec + _ad9862_regs.byp_buffer_a = 1; + _ad9862_regs.byp_buffer_b = 1; + _ad9862_regs.buffer_a_pd = 1; + _ad9862_regs.buffer_b_pd = 1; + _ad9862_regs.rx_pga_a = 0;//0x1f; //TODO bring under api control + _ad9862_regs.rx_pga_b = 0;//0x1f; //TODO bring under api control + _ad9862_regs.rx_twos_comp = 1; + _ad9862_regs.rx_hilbert = ad9862_regs_t::RX_HILBERT_DIS; + + //setup tx side of codec + _ad9862_regs.two_data_paths = ad9862_regs_t::TWO_DATA_PATHS_BOTH; + _ad9862_regs.interleaved = ad9862_regs_t::INTERLEAVED_INTERLEAVED; + _ad9862_regs.tx_pga_gain = 199; //TODO bring under api control + _ad9862_regs.tx_hilbert = ad9862_regs_t::TX_HILBERT_DIS; + _ad9862_regs.interp = ad9862_regs_t::INTERP_4; + _ad9862_regs.tx_twos_comp = 1; + _ad9862_regs.fine_mode = ad9862_regs_t::FINE_MODE_NCO; + _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_BYPASS; + _ad9862_regs.dac_a_coarse_gain = 0x3; + _ad9862_regs.dac_b_coarse_gain = 0x3; + + //setup the dll + _ad9862_regs.input_clk_ctrl = ad9862_regs_t::INPUT_CLK_CTRL_EXTERNAL; + _ad9862_regs.dll_mult = ad9862_regs_t::DLL_MULT_2; + _ad9862_regs.dll_mode = ad9862_regs_t::DLL_MODE_FAST; + + //setup clockout + _ad9862_regs.clkout2_div_factor = ad9862_regs_t::CLKOUT2_DIV_FACTOR_2; + + //write the register settings to the codec + for (uint8_t addr = 0; addr <= 25; addr++) { + this->send_reg(addr); + } + + //aux adc clock + _ad9862_regs.clk_4 = ad9862_regs_t::CLK_4_1_4; + this->send_reg(34); +} + +usrp1_codec_ctrl_impl::~usrp1_codec_ctrl_impl(void) +{ + //set aux dacs to zero + this->write_aux_dac(AUX_DAC_A, 0); + this->write_aux_dac(AUX_DAC_B, 0); + this->write_aux_dac(AUX_DAC_C, 0); + this->write_aux_dac(AUX_DAC_D, 0); + + //power down + _ad9862_regs.all_rx_pd = 1; + this->send_reg(1); + _ad9862_regs.tx_digital_pd = 1; + _ad9862_regs.tx_analog_pd = ad9862_regs_t::TX_ANALOG_PD_BOTH; + this->send_reg(8); +} + +/*********************************************************************** + * Codec Control Gain Control Methods + **********************************************************************/ +void usrp1_codec_ctrl_impl::set_tx_pga_gain(float gain) +{ + int gain_word = int(63*(gain - tx_pga_gain_range.min)/(tx_pga_gain_range.max - tx_pga_gain_range.min)); + _ad9862_regs.tx_pga_gain = std::clip(gain_word, 0, 63); + this->send_reg(16); +} + +float usrp1_codec_ctrl_impl::get_tx_pga_gain(void) +{ + return (_ad9862_regs.tx_pga_gain*(tx_pga_gain_range.max - tx_pga_gain_range.min)/63) + tx_pga_gain_range.min; +} + +void usrp1_codec_ctrl_impl::set_rx_pga_gain(float gain, char which) +{ + int gain_word = int(0x14*(gain - rx_pga_gain_range.min)/(rx_pga_gain_range.max - rx_pga_gain_range.min)); + gain_word = std::clip(gain_word, 0, 0x14); + switch(which){ + case 'A': + _ad9862_regs.rx_pga_a = gain_word; + this->send_reg(2); + return; + case 'B': + _ad9862_regs.rx_pga_b = gain_word; + this->send_reg(3); + return; + default: UHD_THROW_INVALID_CODE_PATH(); + } +} + +float usrp1_codec_ctrl_impl::get_rx_pga_gain(char which) +{ + int gain_word; + switch(which){ + case 'A': gain_word = _ad9862_regs.rx_pga_a; break; + case 'B': gain_word = _ad9862_regs.rx_pga_b; break; + default: UHD_THROW_INVALID_CODE_PATH(); + } + return (gain_word*(rx_pga_gain_range.max - rx_pga_gain_range.min)/0x14) + rx_pga_gain_range.min; +} + +/*********************************************************************** + * Codec Control AUX ADC Methods + **********************************************************************/ +static float aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low) +{ + return float((boost::uint16_t(high) << 2) | low)*3.3/0x3ff; +} + +float usrp1_codec_ctrl_impl::read_aux_adc(aux_adc_t which) +{ + //check to see if the switch needs to be set + bool write_switch = false; + switch(which) { + + case AUX_ADC_A1: + case AUX_ADC_A2: + if (which != _last_aux_adc_a) { + _ad9862_regs.select_a = (which == AUX_ADC_A1)? + ad9862_regs_t::SELECT_A_AUX_ADC1: ad9862_regs_t::SELECT_A_AUX_ADC2; + _last_aux_adc_a = which; + write_switch = true; + } + break; + + case AUX_ADC_B1: + case AUX_ADC_B2: + if (which != _last_aux_adc_b) { + _ad9862_regs.select_b = (which == AUX_ADC_B1)? + ad9862_regs_t::SELECT_B_AUX_ADC1: ad9862_regs_t::SELECT_B_AUX_ADC2; + _last_aux_adc_b = which; + write_switch = true; + } + break; + + } + + //write the switch if it changed + if(write_switch) this->send_reg(34); + + //map aux adcs to register values to read + static const uhd::dict aux_dac_to_addr = boost::assign::map_list_of + (AUX_ADC_A2, 26) (AUX_ADC_A1, 28) + (AUX_ADC_B2, 30) (AUX_ADC_B1, 32) + ; + + //read the value + this->recv_reg(aux_dac_to_addr[which]+0); + this->recv_reg(aux_dac_to_addr[which]+1); + + //return the value scaled to volts + switch(which) { + case AUX_ADC_A1: return aux_adc_to_volts(_ad9862_regs.aux_adc_a1_9_2, _ad9862_regs.aux_adc_a1_1_0); + case AUX_ADC_A2: return aux_adc_to_volts(_ad9862_regs.aux_adc_a2_9_2, _ad9862_regs.aux_adc_a2_1_0); + case AUX_ADC_B1: return aux_adc_to_volts(_ad9862_regs.aux_adc_b1_9_2, _ad9862_regs.aux_adc_b1_1_0); + case AUX_ADC_B2: return aux_adc_to_volts(_ad9862_regs.aux_adc_b2_9_2, _ad9862_regs.aux_adc_b2_1_0); + } + UHD_ASSERT_THROW(false); +} + +/*********************************************************************** + * Codec Control AUX DAC Methods + **********************************************************************/ +void usrp1_codec_ctrl_impl::write_aux_dac(aux_dac_t which, float volts) +{ + //special case for aux dac d (aka sigma delta word) + if (which == AUX_DAC_D) { + boost::uint16_t dac_word = std::clip(boost::math::iround(volts*0xfff/3.3), 0, 0xfff); + _ad9862_regs.sig_delt_11_4 = boost::uint8_t(dac_word >> 4); + _ad9862_regs.sig_delt_3_0 = boost::uint8_t(dac_word & 0xf); + this->send_reg(42); + this->send_reg(43); + return; + } + + //calculate the dac word for aux dac a, b, c + boost::uint8_t dac_word = std::clip(boost::math::iround(volts*0xff/3.3), 0, 0xff); + + //setup a lookup table for the aux dac params (reg ref, reg addr) + typedef boost::tuple dac_params_t; + uhd::dict aux_dac_to_params = boost::assign::map_list_of + (AUX_DAC_A, dac_params_t(&_ad9862_regs.aux_dac_a, 36)) + (AUX_DAC_B, dac_params_t(&_ad9862_regs.aux_dac_b, 37)) + (AUX_DAC_C, dac_params_t(&_ad9862_regs.aux_dac_c, 38)) + ; + + //set the aux dac register + UHD_ASSERT_THROW(aux_dac_to_params.has_key(which)); + boost::uint8_t *reg_ref, reg_addr; + boost::tie(reg_ref, reg_addr) = aux_dac_to_params[which]; + *reg_ref = dac_word; + this->send_reg(reg_addr); +} + +/*********************************************************************** + * Codec Control SPI Methods + **********************************************************************/ +void usrp1_codec_ctrl_impl::send_reg(boost::uint8_t addr) +{ + boost::uint32_t reg = _ad9862_regs.get_write_reg(addr); + + if (codec_debug) { + std::cout.fill('0'); + std::cout << "codec control write reg: 0x"; + std::cout << std::setw(8) << std::hex << reg << std::endl; + } + _iface->transact_spi(SPI_ENABLE_CODEC_A, + spi_config_t::EDGE_RISE, reg, 16, false); +} + +void usrp1_codec_ctrl_impl::recv_reg(boost::uint8_t addr) +{ + boost::uint32_t reg = _ad9862_regs.get_read_reg(addr); + + if (codec_debug) { + std::cout.fill('0'); + std::cout << "codec control read reg: 0x"; + std::cout << std::setw(8) << std::hex << reg << std::endl; + } + + boost::uint32_t ret = _iface->transact_spi(SPI_ENABLE_CODEC_A, + spi_config_t::EDGE_RISE, reg, 16, true); + + if (codec_debug) { + std::cout.fill('0'); + std::cout << "codec control read ret: 0x"; + std::cout << std::setw(8) << std::hex << ret << std::endl; + } + + _ad9862_regs.set_reg(addr, boost::uint16_t(ret)); +} + +/*********************************************************************** + * DUC tuning + **********************************************************************/ +unsigned int usrp1_codec_ctrl_impl::compute_freq_control_word_9862( + double master_freq, double target_freq, double *actual_freq) +{ + double sign = 1.0; + + if (target_freq < 0) + sign = -1.0; + + int v = (int) rint (fabs (target_freq) / master_freq * pow (2.0, 24.0)); + *actual_freq = v * master_freq / pow (2.0, 24.0) * sign; + + fprintf(stdout, + "compute_freq_control_word_9862: target = %g actual = %g delta = %g v = %8d\n", + target_freq, *actual_freq, *actual_freq - target_freq, v); + + return (unsigned int) v; +} + +bool usrp1_codec_ctrl_impl::set_duc_freq(double freq) +{ + int channel = 0; + float dac_rate = 128e6; + + double coarse; + + std::cout << "duc_freq: " << freq << std::endl; + + // First coarse frequency + double coarse_freq_1 = dac_rate / 8; + // Second coarse frequency + double coarse_freq_2 = dac_rate / 4; + // Midpoint of [0 , freq1] range + double coarse_limit_1 = coarse_freq_1 / 2; + // Midpoint of [freq1 , freq2] range + double coarse_limit_2 = (coarse_freq_1 + coarse_freq_2) / 2; + // Highest meaningful frequency + double high_limit = (double) 44e6 / 128e6 * dac_rate; + + if (freq < -high_limit) { // too low + return false; + } + else if (freq < -coarse_limit_2) { // For 64MHz: [-44, -24) + _ad9862_regs.neg_coarse_tune = ad9862_regs_t::NEG_COARSE_TUNE_NEG_SHIFT; + _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_FDAC_4; + coarse = -coarse_freq_2; + } + else if (freq < -coarse_limit_1) { // For 64MHz: [-24, -8) + _ad9862_regs.neg_coarse_tune = ad9862_regs_t::NEG_COARSE_TUNE_NEG_SHIFT; + _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_FDAC_8; + coarse = -coarse_freq_1; + } + else if (freq < coarse_limit_1) { // For 64MHz: [-8, 8) + _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_BYPASS; + coarse = 0; + } + else if (freq < coarse_limit_2) { // For 64MHz: [8, 24) + _ad9862_regs.neg_coarse_tune = ad9862_regs_t::NEG_COARSE_TUNE_POS_SHIFT; + _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_FDAC_8; + coarse = coarse_freq_1; + } + else if (freq <= high_limit) { // For 64MHz: [24, 44] + _ad9862_regs.neg_coarse_tune = ad9862_regs_t::NEG_COARSE_TUNE_POS_SHIFT; + _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_FDAC_4; + coarse = coarse_freq_2; + } + else { // too high + return false; + } + + double fine = freq - coarse; + + // Compute fine tuning word... + // This assumes we're running the 4x on-chip interpolator. + // (This is required to use the fine modulator.) + + unsigned int v = compute_freq_control_word_9862 (dac_rate / 4, fine, + &_tx_freq[channel]); + + _tx_freq[channel] += coarse; // adjust actual + + boost::uint8_t high; + boost::uint8_t mid; + boost::uint8_t low; + + high = (v >> 16) & 0xff; + mid = (v >> 8) & 0xff; + low = (v >> 0) & 0xff; + + // write the fine tuning word + _ad9862_regs.ftw_23_16 = high; + _ad9862_regs.ftw_15_8 = mid; + _ad9862_regs.ftw_7_0 = low; + + _ad9862_regs.fine_mode = ad9862_regs_t::FINE_MODE_NCO; + + if (fine < 0) + _ad9862_regs.neg_fine_tune = ad9862_regs_t::NEG_FINE_TUNE_NEG_SHIFT; + else + _ad9862_regs.neg_fine_tune = ad9862_regs_t::NEG_FINE_TUNE_POS_SHIFT; + + this->send_reg(20); + this->send_reg(21); + this->send_reg(22); + this->send_reg(23); + + return true; +} + +/*********************************************************************** + * Codec Control Make + **********************************************************************/ +usrp1_codec_ctrl::sptr usrp1_codec_ctrl::make(usrp1_iface::sptr iface) +{ + return sptr(new usrp1_codec_ctrl_impl(iface)); +} diff --git a/host/lib/usrp/usrp1/codec_ctrl.hpp b/host/lib/usrp/usrp1/codec_ctrl.hpp new file mode 100644 index 000000000..51e29345a --- /dev/null +++ b/host/lib/usrp/usrp1/codec_ctrl.hpp @@ -0,0 +1,76 @@ +// +// Copyright 2010 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 . +// + +#ifndef INCLUDED_USRP1_CODEC_CTRL_HPP +#define INCLUDED_USRP1_CODEC_CTRL_HPP + +#include "usrp1_iface.hpp" +#include +#include + +/*! + * The usrp1 codec control: + * - Init/power down codec. + * - Read aux adc, write aux dac. + */ +class usrp1_codec_ctrl : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a new clock control object. + * \param iface the usrp1 iface object + * \return the clock control object + */ + static sptr make(usrp1_iface::sptr iface); + + //! aux adc identifier constants + enum aux_adc_t{ + AUX_ADC_A2 = 0xA2, + AUX_ADC_A1 = 0xA1, + AUX_ADC_B2 = 0xB2, + AUX_ADC_B1 = 0xB1 + }; + + /*! + * Read an auxiliary adc: + * The internals remember which aux adc was read last. + * Therefore, the aux adc switch is only changed as needed. + * \param which which of the 4 adcs + * \return a value in volts + */ + virtual float read_aux_adc(aux_adc_t which) = 0; + + //! aux dac identifier constants + enum aux_dac_t{ + AUX_DAC_A = 0xA, + AUX_DAC_B = 0xB, + AUX_DAC_C = 0xC, + AUX_DAC_D = 0xD + }; + + /*! + * Write an auxiliary dac. + * \param which which of the 4 dacs + * \param volts the level in in volts + */ + virtual void write_aux_dac(aux_dac_t which, float volts) = 0; + + virtual bool set_duc_freq(double freq) = 0; +}; + +#endif /* INCLUDED_USRP1_CODEC_CTRL_HPP */ diff --git a/host/lib/usrp/usrp1/codec_impl.cpp b/host/lib/usrp/usrp1/codec_impl.cpp new file mode 100644 index 000000000..9253c06ba --- /dev/null +++ b/host/lib/usrp/usrp1/codec_impl.cpp @@ -0,0 +1,156 @@ +// +// Copyright 2010 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 . +// + +#include "usrp1_impl.hpp" +#include +#include + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * Helper Methods + **********************************************************************/ +void usrp1_impl::codec_init(void) +{ + //make proxies + _rx_codec_proxy = wax_obj_proxy::make( + boost::bind(&usrp1_impl::rx_codec_get, this, _1, _2), + boost::bind(&usrp1_impl::rx_codec_set, this, _1, _2)); + + _tx_codec_proxy = wax_obj_proxy::make( + boost::bind(&usrp1_impl::tx_codec_get, this, _1, _2), + boost::bind(&usrp1_impl::tx_codec_set, this, _1, _2)); +} + +/*********************************************************************** + * RX Codec Properties + **********************************************************************/ +static const std::string ad9862_pga_gain_name = "ad9862 pga"; + +void usrp1_impl::rx_codec_get(const wax::obj &key_, wax::obj &val) +{ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(key.as()) { + case CODEC_PROP_NAME: + val = std::string("usrp1 adc - ad9862"); + return; + + case CODEC_PROP_OTHERS: + val = prop_names_t(); + return; + + case CODEC_PROP_GAIN_NAMES: + val = prop_names_t(1, ad9862_pga_gain_name); + return; + + case CODEC_PROP_GAIN_RANGE: + UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + val = usrp1_codec_ctrl::rx_pga_gain_range; + return; + + case CODEC_PROP_GAIN_I: + UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + val = _codec_ctrl->get_rx_pga_gain('A'); + return; + + case CODEC_PROP_GAIN_Q: + UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + val = _codec_ctrl->get_rx_pga_gain('B'); + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } +} + +void usrp1_impl::rx_codec_set(const wax::obj &, const wax::obj &) +{ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the set request conditioned on the key + switch(key.as()) { + case CODEC_PROP_GAIN_I: + UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + _codec_ctrl->set_rx_pga_gain(val.as(), 'A'); + return; + + case CODEC_PROP_GAIN_Q: + UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + _codec_ctrl->set_rx_pga_gain(val.as(), 'B'); + return; + + default: UHD_THROW_PROP_SET_ERROR(); + } +} + +/*********************************************************************** + * TX Codec Properties + **********************************************************************/ +void usrp1_impl::tx_codec_get(const wax::obj &key_, wax::obj &val) +{ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(key.as()) { + case CODEC_PROP_NAME: + val = std::string("usrp1 dac - ad9862"); + return; + + case CODEC_PROP_OTHERS: + val = prop_names_t(); + return; + + case CODEC_PROP_GAIN_NAMES: + val = prop_names_t(1, ad9862_pga_gain_name); + return; + + case CODEC_PROP_GAIN_RANGE: + UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + val = usrp1_codec_ctrl::tx_pga_gain_range; + return; + + case CODEC_PROP_GAIN_I: //only one gain for I and Q + case CODEC_PROP_GAIN_Q: + UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + val = _codec_ctrl->get_tx_pga_gain(); + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } +} + +void usrp1_impl::tx_codec_set(const wax::obj &, const wax::obj &) +{ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the set request conditioned on the key + switch(key.as()){ + case CODEC_PROP_GAIN_I: //only one gain for I and Q + case CODEC_PROP_GAIN_Q: + UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + _codec_ctrl->set_tx_pga_gain(val.as()); + return; + + default: UHD_THROW_PROP_SET_ERROR(); + } +} diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp new file mode 100644 index 000000000..11ad3fe8a --- /dev/null +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -0,0 +1,304 @@ +// +// Copyright 2010 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 . +// + +#include "usrp1_iface.hpp" +#include "fpga_regs_common.h" +#include "usrp_spi_defs.h" +#include "clock_ctrl.hpp" +#include "codec_ctrl.hpp" +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; +using namespace boost::assign; + +class usrp1_dboard_iface : public dboard_iface { +public: + + usrp1_dboard_iface(usrp1_iface::sptr iface, + usrp1_clock_ctrl::sptr clock, + usrp1_codec_ctrl::sptr codec) + { + _iface = iface; + _clock = clock; + _codec = codec; + + //init the clock rate shadows + this->set_clock_rate(UNIT_RX, _clock->get_master_clock_freq()); + this->set_clock_rate(UNIT_TX, _clock->get_master_clock_freq()); + } + + ~usrp1_dboard_iface() + { + /* NOP */ + } + + std::string get_mboard_name() + { + return "usrp1"; + } + + void write_aux_dac(unit_t, aux_dac_t, float); + float read_aux_adc(unit_t, aux_adc_t); + + void set_pin_ctrl(unit_t, boost::uint16_t); + void set_atr_reg(unit_t, atr_reg_t, boost::uint16_t); + void set_gpio_ddr(unit_t, boost::uint16_t); + void write_gpio(unit_t, boost::uint16_t); + boost::uint16_t read_gpio(unit_t); + + void write_i2c(boost::uint8_t, const byte_vector_t &); + byte_vector_t read_i2c(boost::uint8_t, size_t); + + void write_spi(unit_t unit, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits); + + boost::uint32_t read_write_spi(unit_t unit, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits); + + void set_clock_rate(unit_t, double); + std::vector get_clock_rates(unit_t); + double get_clock_rate(unit_t); + void set_clock_enabled(unit_t, bool); + +private: + usrp1_iface::sptr _iface; + usrp1_clock_ctrl::sptr _clock; + usrp1_codec_ctrl::sptr _codec; + uhd::dict _clock_rates; +}; + +/*********************************************************************** + * Make Function + **********************************************************************/ +dboard_iface::sptr make_usrp1_dboard_iface(usrp1_iface::sptr iface, + usrp1_clock_ctrl::sptr clock, + usrp1_codec_ctrl::sptr codec) +{ + return dboard_iface::sptr(new usrp1_dboard_iface(iface, clock, codec)); +} + +/*********************************************************************** + * Clock Rates + **********************************************************************/ +void usrp1_dboard_iface::set_clock_rate(unit_t unit, double rate) +{ + _clock_rates[unit] = rate; + switch(unit) { + case UNIT_RX: return _clock->set_rx_dboard_clock_rate(rate); + case UNIT_TX: return _clock->set_tx_dboard_clock_rate(rate); + } +} + +/* + * TODO: if this is a dbsrx return the rate of 4MHZ and set FPGA magic + */ +std::vector usrp1_dboard_iface::get_clock_rates(unit_t unit) +{ + switch(unit) { + case UNIT_RX: return _clock->get_rx_dboard_clock_rates(); + case UNIT_TX: return _clock->get_tx_dboard_clock_rates(); + default: UHD_THROW_INVALID_CODE_PATH(); + } +} + +double usrp1_dboard_iface::get_clock_rate(unit_t unit) +{ + return _clock_rates[unit]; +} + +void usrp1_dboard_iface::set_clock_enabled(unit_t unit, bool enb) +{ + switch(unit) { + case UNIT_RX: return _clock->enable_rx_dboard_clock(enb); + case UNIT_TX: return _clock->enable_tx_dboard_clock(enb); + } +} + +/*********************************************************************** + * GPIO + **********************************************************************/ +void usrp1_dboard_iface::set_pin_ctrl(unit_t unit, boost::uint16_t value) +{ + switch(unit) { + case UNIT_RX: + _iface->poke32(FR_ATR_MASK_1, value); + _iface->poke32(FR_ATR_MASK_3, 0x00000000); + break; + case UNIT_TX: + _iface->poke32(FR_ATR_MASK_0, value); + _iface->poke32(FR_ATR_MASK_2, 0x00000000); + break; + } +} + +void usrp1_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value) +{ + switch(unit) { + case UNIT_RX: + _iface->poke32(FR_OE_1, 0xffff0000 | value); + _iface->poke32(FR_OE_3, 0xffff0000); + break; + case UNIT_TX: + _iface->poke32(FR_OE_0, 0xffff0000 | value); + _iface->poke32(FR_OE_2, 0xffff0000); + break; + } +} + +void usrp1_dboard_iface::write_gpio(unit_t unit, boost::uint16_t value) +{ + switch(unit) { + case UNIT_RX: + _iface->poke32(FR_IO_1, 0xffff0000 | value); + break; + case UNIT_TX: + _iface->poke32(FR_IO_0, 0xffff0000 | value); + break; + } +} + +boost::uint16_t usrp1_dboard_iface::read_gpio(unit_t unit) +{ + boost::uint32_t out_value; + boost::uint16_t ret_value; + + switch(unit) { + case UNIT_RX: + //magic + out_value = _iface->peek32(1); + ret_value = (out_value >> 16) & 0x0000ffff; + return ret_value; + case UNIT_TX: + //magic + out_value = _iface->peek32(1); + ret_value = (out_value >> 0) & 0x0000ffff; + return ret_value; + } + UHD_ASSERT_THROW(false); +} + +void usrp1_dboard_iface::set_atr_reg(unit_t unit, + atr_reg_t atr, boost::uint16_t value) +{ + if ((atr == ATR_REG_IDLE) || (atr == ATR_REG_FULL_DUPLEX)) { + std::cerr << "error: set_atr_reg(): unsupported state" << std::endl; + return; + } + + switch(unit) { + case UNIT_RX: + _iface->poke32(FR_ATR_RXVAL_1, value); + _iface->poke32(FR_ATR_RXVAL_3, 0x0000); + break; + case UNIT_TX: + //_iface->poke32(FR_ATR_TXVAL_0, value); + _iface->poke32(FR_ATR_TXVAL_0, 0x0000); + _iface->poke32(FR_ATR_TXVAL_2, 0x0000); + break; + } +} +/*********************************************************************** + * SPI + **********************************************************************/ +/*! + * Static function to convert a unit type to a spi slave device number. + * \param unit the dboard interface unit type enum + * \return the slave device number + */ +static boost::uint32_t unit_to_otw_spi_dev(dboard_iface::unit_t unit) +{ + switch(unit) { + case dboard_iface::UNIT_TX: return SPI_ENABLE_TX_A; + case dboard_iface::UNIT_RX: return SPI_ENABLE_RX_A; + } + throw std::invalid_argument("unknown unit type"); + +} + +void usrp1_dboard_iface::write_spi(unit_t unit, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits) +{ + _iface->transact_spi(unit_to_otw_spi_dev(unit), + config, data, num_bits, false); +} + +boost::uint32_t usrp1_dboard_iface::read_write_spi(unit_t unit, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits) +{ + return _iface->transact_spi(unit_to_otw_spi_dev(unit), + config, data, num_bits, true); +} + +/*********************************************************************** + * I2C + **********************************************************************/ +void usrp1_dboard_iface::write_i2c(boost::uint8_t addr, + const byte_vector_t &bytes) +{ + return _iface->write_i2c(addr, bytes); +} + +byte_vector_t usrp1_dboard_iface::read_i2c(boost::uint8_t addr, + size_t num_bytes) +{ + return _iface->read_i2c(addr, num_bytes); +} + +/*********************************************************************** + * Aux DAX/ADC + **********************************************************************/ +void usrp1_dboard_iface::write_aux_dac(dboard_iface::unit_t, + aux_dac_t which, float value) +{ + //same aux dacs for each unit + static const uhd::dict + which_to_aux_dac = map_list_of + (AUX_DAC_A, usrp1_codec_ctrl::AUX_DAC_A) + (AUX_DAC_B, usrp1_codec_ctrl::AUX_DAC_B) + (AUX_DAC_C, usrp1_codec_ctrl::AUX_DAC_C) + (AUX_DAC_D, usrp1_codec_ctrl::AUX_DAC_D); + + _codec->write_aux_dac(which_to_aux_dac[which], value); +} + +float usrp1_dboard_iface::read_aux_adc(dboard_iface::unit_t unit, + aux_adc_t which) +{ + static const + uhd::dict > + unit_to_which_to_aux_adc = map_list_of(UNIT_RX, map_list_of + (AUX_ADC_A, usrp1_codec_ctrl::AUX_ADC_A1) + (AUX_ADC_B, usrp1_codec_ctrl::AUX_ADC_B1)) + (UNIT_TX, map_list_of + (AUX_ADC_A, usrp1_codec_ctrl::AUX_ADC_A2) + (AUX_ADC_B, usrp1_codec_ctrl::AUX_ADC_B2)); + + return _codec->read_aux_adc(unit_to_which_to_aux_adc[unit][which]); +} diff --git a/host/lib/usrp/usrp1/dboard_impl.cpp b/host/lib/usrp/usrp1/dboard_impl.cpp new file mode 100644 index 000000000..4f2836ea9 --- /dev/null +++ b/host/lib/usrp/usrp1/dboard_impl.cpp @@ -0,0 +1,196 @@ +// +// Copyright 2010 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 . +// + +#include "usrp1_impl.hpp" +#include "usrp_i2c_addr.h" +#include "../dsp_utils.hpp" +#include "../misc_utils.hpp" +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * Dboard Initialization + **********************************************************************/ +void usrp1_impl::dboard_init(void) +{ + _rx_db_eeprom = dboard_eeprom_t( + _iface->read_eeprom(I2C_ADDR_RX_A, 0, dboard_eeprom_t::num_bytes())); + + _tx_db_eeprom = dboard_eeprom_t( + _iface->read_eeprom(I2C_ADDR_TX_A, 0, dboard_eeprom_t::num_bytes())); + + + //create a new dboard interface and manager + _dboard_iface = make_usrp1_dboard_iface(_iface, _clock_ctrl, _codec_ctrl); + + _dboard_manager = dboard_manager::make(_rx_db_eeprom.id, + _tx_db_eeprom.id, + _dboard_iface); + + //setup the dboard proxies + _rx_dboard_proxy = wax_obj_proxy::make( + boost::bind(&usrp1_impl::rx_dboard_get, this, _1, _2), + boost::bind(&usrp1_impl::rx_dboard_set, this, _1, _2)); + + _tx_dboard_proxy = wax_obj_proxy::make( + boost::bind(&usrp1_impl::tx_dboard_get, this, _1, _2), + boost::bind(&usrp1_impl::tx_dboard_set, this, _1, _2)); + +} +/*********************************************************************** + * Helper functions + **********************************************************************/ +//static int slot_to_i2c_addr (int slot) +//{ +// switch (slot) { +// case SLOT_TX_A: +// return I2C_ADDR_TX_A; +// case SLOT_RX_A: +// return I2C_ADDR_RX_A; +// case SLOT_TX_B: +// return I2C_ADDR_TX_B; +// case SLOT_RX_B: +// return I2C_ADDR_RX_B; +// default: +// return -1; +// } +//} + + +/*********************************************************************** + * RX Dboard Get + **********************************************************************/ +void usrp1_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val) +{ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(key.as()){ + case DBOARD_PROP_NAME: + val = std::string("usrp1 dboard (rx unit)"); + return; + + case DBOARD_PROP_SUBDEV: + val = _dboard_manager->get_rx_subdev(name); + return; + + case DBOARD_PROP_SUBDEV_NAMES: + val = _dboard_manager->get_rx_subdev_names(); + return; + + case DBOARD_PROP_DBOARD_ID: + val = _rx_db_eeprom.id; + return; + + case DBOARD_PROP_DBOARD_IFACE: + val = _dboard_iface; + return; + + case DBOARD_PROP_CODEC: + val = _rx_codec_proxy->get_link(); + return; + + case DBOARD_PROP_GAIN_GROUP: + val = make_gain_group(_dboard_manager->get_rx_subdev(name), + _rx_codec_proxy->get_link()); + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } +} + +/*********************************************************************** + * RX Dboard Set + **********************************************************************/ +void usrp1_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val) +{ + switch(key.as()) { + case DBOARD_PROP_DBOARD_ID: + _rx_db_eeprom.id = val.as(); + _iface->write_eeprom(I2C_ADDR_RX_A, 0, + _rx_db_eeprom.get_eeprom_bytes()); + return; + + default: + UHD_THROW_PROP_SET_ERROR(); + } +} + +/*********************************************************************** + * TX Dboard Get + **********************************************************************/ +void usrp1_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val) +{ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(key.as()){ + case DBOARD_PROP_NAME: + val = std::string("usrp1 dboard (tx unit)"); + return; + + case DBOARD_PROP_SUBDEV: + val = _dboard_manager->get_tx_subdev(name); + return; + + case DBOARD_PROP_SUBDEV_NAMES: + val = _dboard_manager->get_tx_subdev_names(); + return; + + case DBOARD_PROP_DBOARD_ID: + val = _tx_db_eeprom.id; + return; + + case DBOARD_PROP_DBOARD_IFACE: + val = _dboard_iface; + return; + + case DBOARD_PROP_CODEC: + val = _tx_codec_proxy->get_link(); + return; + + case DBOARD_PROP_GAIN_GROUP: + val = make_gain_group(_dboard_manager->get_tx_subdev(name), + _tx_codec_proxy->get_link()); + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } +} + +/*********************************************************************** + * TX Dboard Set + **********************************************************************/ +void usrp1_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val) +{ + switch(key.as()) { + case DBOARD_PROP_DBOARD_ID: + _tx_db_eeprom.id = val.as(); + _iface->write_eeprom(I2C_ADDR_TX_A, 0, _tx_db_eeprom.get_eeprom_bytes()); + return; + + default: UHD_THROW_PROP_SET_ERROR(); + } +} diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp new file mode 100644 index 000000000..e9900131f --- /dev/null +++ b/host/lib/usrp/usrp1/dsp_impl.cpp @@ -0,0 +1,197 @@ +// +// Copyright 2010 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 . +// + +#include "usrp1_impl.hpp" +#include "fpga_regs_standard.h" +#include "../dsp_utils.hpp" +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * RX DDC Initialization + **********************************************************************/ +void usrp1_impl::rx_ddc_init(void) +{ + _rx_ddc_proxy = wax_obj_proxy::make( + boost::bind(&usrp1_impl::rx_ddc_get, this, _1, _2), + boost::bind(&usrp1_impl::rx_ddc_set, this, _1, _2)); + + rx_ddc_set(DSP_PROP_HOST_RATE, double(64e6/10)); +} + +/*********************************************************************** + * RX DDC Get + **********************************************************************/ +void usrp1_impl::rx_ddc_get(const wax::obj &key, wax::obj &val) +{ + switch(key.as()){ + case DSP_PROP_NAME: + val = std::string("usrp1 ddc0"); + return; + + case DSP_PROP_OTHERS: + val = prop_names_t(); + return; + + case DSP_PROP_FREQ_SHIFT: + val = _ddc_freq; + return; + + case DSP_PROP_CODEC_RATE: + val = _clock_ctrl->get_master_clock_freq(); + return; + + case DSP_PROP_HOST_RATE: + val = _clock_ctrl->get_master_clock_freq()/_ddc_decim; + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } + +} + +/*********************************************************************** + * RX DDC Set + **********************************************************************/ +unsigned int compute_freq_word(double master, double target) +{ + static const int NBITS = 14; + int v = (int) rint (target / master * pow(2.0, 32.0)); + + if (0) + v = (v >> (32 - NBITS)) << (32 - NBITS); // keep only top NBITS + + double actual_freq = v * master / pow(2.0, 32.0); + + if (0) + fprintf (stderr, + "compute_freq_control_word_fpga: target = %g actual = %g delta = %g\n", + target, actual_freq, actual_freq - target); + + return (unsigned int) v; +} + +void usrp1_impl::rx_ddc_set(const wax::obj &key, const wax::obj &val) +{ + switch(key.as()) { + case DSP_PROP_FREQ_SHIFT: { + double new_freq = val.as(); + _iface->poke32(FR_RX_FREQ_0, compute_freq_word(64e6, new_freq)); + _ddc_freq = new_freq; + return; + } + case DSP_PROP_HOST_RATE: { + //FIXME: Stop and resume streaming during set? + unsigned int rate = + _clock_ctrl->get_master_clock_freq() / val.as(); + + if ((rate & 0x01) || (rate < 4) || (rate > 256)) { + std::cerr << "Decimation must be even and between 4 and 256" + << std::endl; + return; + } + + _ddc_decim = rate; + _iface->poke32(FR_DECIM_RATE, _ddc_decim/2 - 1); + } + return; + + default: UHD_THROW_PROP_SET_ERROR(); + } + +} + +/*********************************************************************** + * TX DUC Initialization + **********************************************************************/ +void usrp1_impl::tx_duc_init(void) +{ + _tx_duc_proxy = wax_obj_proxy::make( + boost::bind(&usrp1_impl::tx_duc_get, this, _1, _2), + boost::bind(&usrp1_impl::tx_duc_set, this, _1, _2)); + + //initial config and update + tx_duc_set(DSP_PROP_HOST_RATE, double(64e6/10)); +} + +/*********************************************************************** + * TX DUC Get + **********************************************************************/ +void usrp1_impl::tx_duc_get(const wax::obj &key, wax::obj &val) +{ + switch(key.as()) { + case DSP_PROP_NAME: + val = std::string("usrp1 duc0"); + return; + + case DSP_PROP_OTHERS: + val = prop_names_t(); //empty + return; + + case DSP_PROP_FREQ_SHIFT: + val = _duc_freq; + return; + + case DSP_PROP_CODEC_RATE: + val = MASTER_CLOCK_RATE; + return; + + case DSP_PROP_HOST_RATE: + val = _clock_ctrl->get_master_clock_freq() * 2 / _duc_interp; + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } + +} + +/*********************************************************************** + * TX DUC Set + **********************************************************************/ +void usrp1_impl::tx_duc_set(const wax::obj &key, const wax::obj &val) +{ + switch(key.as()) { + + case DSP_PROP_FREQ_SHIFT: { + double new_freq = val.as(); + _codec_ctrl->set_duc_freq(new_freq); + _duc_freq = new_freq; + return; + } + case DSP_PROP_HOST_RATE: { + unsigned int rate = + _clock_ctrl->get_master_clock_freq() * 2 / val.as(); + + if ((rate & 0x01) || (rate < 8) || (rate > 512)) { + std::cerr << "Interpolation rate must be even and between 8 and 512" + << std::endl; + return; + } + + _duc_interp = rate; + _iface->poke32(FR_INTERP_RATE, _duc_interp / 4 - 1); + return; + } + default: UHD_THROW_PROP_SET_ERROR(); + } + +} diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp new file mode 100644 index 000000000..3f3e74b80 --- /dev/null +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -0,0 +1,229 @@ +// +// Copyright 2010 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 . +// + +#include "../../transport/vrt_packet_handler.hpp" +#include "usrp_commands.h" +#include "usrp1_impl.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; +using namespace uhd::transport; +namespace asio = boost::asio; + +/* + * The FX2 firmware bursts data to the FPGA in 512 byte chunks so + * maintain send state to make sure that happens. + */ +struct usrp1_send_state { + uhd::transport::managed_send_buffer::sptr send_buff; + size_t bytes_used; + size_t bytes_free; +}; + +/*********************************************************************** + * IO Implementation Details + **********************************************************************/ +struct usrp1_impl::io_impl { + io_impl(zero_copy_if::sptr zc_if); + ~io_impl(void); + + bool get_recv_buff(managed_recv_buffer::sptr buff); + + //state management for the vrt packet handler code + vrt_packet_handler::recv_state packet_handler_recv_state; + usrp1_send_state send_state; + + zero_copy_if::sptr data_transport; + unsigned int count; +}; + +usrp1_impl::io_impl::io_impl(zero_copy_if::sptr zc_if) + : packet_handler_recv_state(1), data_transport(zc_if), count(0) +{ + /* NOP */ +} + +usrp1_impl::io_impl::~io_impl(void) +{ + /* NOP */ +} + +void usrp1_impl::io_init(void) +{ + _rx_otw_type.width = 16; + _rx_otw_type.shift = 0; + _rx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; + + _tx_otw_type.width = 16; + _tx_otw_type.shift = 0; + _tx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; + + _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport)); +} + +/*********************************************************************** + * Data Send + **********************************************************************/ +size_t usrp1_impl::send(const std::vector &buffs, + size_t num_samps, + const tx_metadata_t &, + const io_type_t &io_type, + send_mode_t) +{ + UHD_ASSERT_THROW(buffs.size() == 1); + + size_t total_samps_sent = 0; + + while (total_samps_sent < num_samps) { + + if (_io_impl->send_state.send_buff == NULL) { + _io_impl->send_state.send_buff = _data_transport->get_send_buff(); + if (_io_impl->send_state.send_buff == NULL) { + return 0; + } + _io_impl->send_state.bytes_used = 0; + _io_impl->send_state.bytes_free = _io_impl->send_state.send_buff->size(); + } + + size_t copy_samps = + std::min(num_samps - total_samps_sent, _io_impl->send_state.bytes_free / _tx_otw_type.get_sample_size()); + + const boost::uint8_t *io_mem = + reinterpret_cast(buffs[0]); + + boost::uint8_t *otw_mem = _io_impl->send_state.send_buff->cast(); + + // Type conversion and copy + convert_io_type_to_otw_type( + io_mem + total_samps_sent * io_type.size, + io_type, + otw_mem + _io_impl->send_state.bytes_used, + _tx_otw_type, + copy_samps); + + _io_impl->send_state.bytes_used += copy_samps * _tx_otw_type.get_sample_size(); + _io_impl->send_state.bytes_free -= copy_samps * _tx_otw_type.get_sample_size(); + + if (_io_impl->send_state.bytes_free == 0) { + _io_impl->send_state.send_buff->commit(_io_impl->send_state.bytes_used); + _io_impl->send_state.send_buff = uhd::transport::managed_send_buffer::sptr(); + } + + total_samps_sent += copy_samps; + + //check for underruns + if (!(_io_impl->count++ % 1000)) { + unsigned char underrun; + int ret = _ctrl_transport->usrp_control_read(VRQ_GET_STATUS, + 0, + GS_TX_UNDERRUN, + &underrun, sizeof(char)); + if (ret < 0) + std::cerr << "error: underrun check failed" << std::endl; + if (underrun) + std::cerr << "U" << std::endl; + } + } + + return total_samps_sent; +} + +/*********************************************************************** + * Data Recv + **********************************************************************/ +void _recv_helper(vrt_packet_handler::recv_state &state) +{ + size_t num_packet_words32 = + state.managed_buffs[0]->size() / sizeof(boost::uint32_t); + + const boost::uint32_t *data = + state.managed_buffs[0]->cast(); + + state.copy_buffs[0] = reinterpret_cast(data); + size_t num_payload_bytes = num_packet_words32 * sizeof(boost::uint32_t); + state.size_of_copy_buffs = num_payload_bytes; +} + +size_t usrp1_impl::recv(const std::vector &buffs, + size_t num_samps, + rx_metadata_t &, + const io_type_t &io_type, + recv_mode_t, + size_t) +{ + UHD_ASSERT_THROW(_io_impl->packet_handler_recv_state.width == 1); + UHD_ASSERT_THROW(buffs.size() == 1); + + size_t sent_samps = 0; + size_t nsamps_to_copy = 0;; + + while (sent_samps < num_samps) { + if (_io_impl->packet_handler_recv_state.size_of_copy_buffs == 0) { + _io_impl->packet_handler_recv_state.fragment_offset_in_samps = 0; + _io_impl->packet_handler_recv_state.managed_buffs[0] = + _io_impl->data_transport->get_recv_buff(); + + //timeout or something bad returns zero + if (!_io_impl->packet_handler_recv_state.managed_buffs[0].get()) + return 0; + + _recv_helper(_io_impl->packet_handler_recv_state); + } + + size_t bytes_per_item = _rx_otw_type.get_sample_size(); + size_t nsamps_available = + _io_impl->packet_handler_recv_state.size_of_copy_buffs / bytes_per_item; + nsamps_to_copy = std::min(num_samps, nsamps_available); + size_t bytes_to_copy = nsamps_to_copy * bytes_per_item; + + convert_otw_type_to_io_type( + _io_impl->packet_handler_recv_state.copy_buffs[0], + _rx_otw_type, + reinterpret_cast(buffs[0]) + sent_samps * io_type.size, + io_type, + nsamps_to_copy); + + _io_impl->packet_handler_recv_state.copy_buffs[0] += bytes_to_copy; + _io_impl->packet_handler_recv_state.size_of_copy_buffs -= bytes_to_copy; + + sent_samps += nsamps_to_copy; + + //check for overruns + if (!(_io_impl->count++ % 10000)) { + unsigned char overrun; + int ret = _ctrl_transport->usrp_control_read( + VRQ_GET_STATUS, + 0, + GS_RX_OVERRUN, + &overrun, sizeof(char)); + if (ret < 0) + std::cerr << "error: overrun check failed" << std::endl; + if (overrun) + std::cerr << "O" << std::endl; + } + } + return sent_samps; +} diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp new file mode 100644 index 000000000..ee1ba305b --- /dev/null +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -0,0 +1,188 @@ +// +// Copyright 2010 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 . +// + +#include "usrp1_impl.hpp" +#include "usrp_commands.h" +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * Mboard Initialization + **********************************************************************/ +void usrp1_impl::mboard_init(void) +{ + _mboard_proxy = wax_obj_proxy::make( + boost::bind(&usrp1_impl::mboard_get, this, _1, _2), + boost::bind(&usrp1_impl::mboard_set, this, _1, _2)); + + /* + * Basic initialization + */ + _iface->poke32( 13, 0x00000000); //FR_MODE + _iface->poke32( 14, 0x00000000); //FR_DEBUG_EN + _iface->poke32( 1, 0x00000001); //FR_RX_SAMPLE_RATE_DEV + _iface->poke32( 0, 0x00000003); //FR_TX_SAMPLE_RATE_DEV + _iface->poke32( 15, 0x0000000f); //FR_DC_OFFSET_CL_EN + + /* + * Reset codecs + */ + _iface->poke32( 16, 0x00000000); //FR_ADC_OFFSET_0 + _iface->poke32( 17, 0x00000000); //FR_ADC_OFFSET_1 + _iface->poke32( 18, 0x00000000); //FR_ADC_OFFSET_2 + _iface->poke32( 19, 0x00000000); //FR_ADC_OFFSET_3 + + /* + * Reset GPIO masks + */ + _iface->poke32( 6, 0xffff0000); //FR_OE_1 + _iface->poke32( 10, 0xffff0000); //FR_IO_1 + _iface->poke32( 8, 0xffff0000); //FR_OE_3 + _iface->poke32( 12, 0xffff0000); //FR_IO_3 + + /* + * Disable ATR masks and reset state registers + */ + _iface->poke32( 23, 0x00000000); //FR_ATR_MASK_1 + _iface->poke32( 24, 0x00000000); //FR_ATR_TXVAL_1 + _iface->poke32( 25, 0x00000000); //FR_ATR_RXVAL_1 + _iface->poke32( 29, 0x00000000); //FR_ATR_MASK_3 + _iface->poke32( 30, 0x00000000); //FR_ATR_TXVAL_3 + _iface->poke32( 31, 0x00000000); //FR_ATR_RXVAL_3 + + /* + * Set defaults for RX format, decimation, and mux + */ + _iface->poke32( 49, 0x00000300); //FR_RX_FORMAT + _iface->poke32( 38, 0x000e4e41); //FR_RX_MUX + + /* + * Set defaults for TX format, interpolation, and mux + */ + _iface->poke32( 48, 0x00000000); //FR_TX_FORMAT + _iface->poke32( 39, 0x00000981); //FR_TX_MUX + + /* + * Reset DDC registers + */ + _iface->poke32( 34, 0x00000000); //FR_RX_FREQ_0 + _iface->poke32( 44, 0x00000000); //FR_RX_PHASE_0 + _iface->poke32( 35, 0x00000000); //FR_RX_FREQ_1 + _iface->poke32( 45, 0x00000000); //FR_RX_PHASE_1 + _iface->poke32( 36, 0x00000000); //FR_RX_FREQ_2 + _iface->poke32( 46, 0x00000000); //FR_RX_PHASE_2 + _iface->poke32( 37, 0x00000000); //FR_RX_FREQ_3 + _iface->poke32( 47, 0x00000000); //FR_RX_PHASE_3 + +} + +void usrp1_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd) +{ + if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS) { + _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, true, 0, 0, 0); + } + + if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS) { + _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, false, 0, 0, 0); + } +} + +/*********************************************************************** + * Mboard Get + **********************************************************************/ +void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) +{ + wax::obj key; + std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(key.as()){ + case MBOARD_PROP_NAME: + val = std::string("usrp1 mboard"); + return; + + case MBOARD_PROP_OTHERS: + val = prop_names_t(); + return; + + case MBOARD_PROP_RX_DBOARD: + UHD_ASSERT_THROW(name == ""); + val = _rx_dboard_proxy->get_link(); + return; + + case MBOARD_PROP_RX_DBOARD_NAMES: + val = prop_names_t(1, ""); //vector of size 1 with empty string + return; + + case MBOARD_PROP_TX_DBOARD: + UHD_ASSERT_THROW(name == ""); + val = _tx_dboard_proxy->get_link(); + return; + + case MBOARD_PROP_TX_DBOARD_NAMES: + val = prop_names_t(1, ""); //vector of size 1 with empty string + return; + + case MBOARD_PROP_RX_DSP: + UHD_ASSERT_THROW(name == ""); + val = _rx_ddc_proxy->get_link(); + return; + + case MBOARD_PROP_RX_DSP_NAMES: + val = prop_names_t(1, ""); + return; + + case MBOARD_PROP_TX_DSP: + UHD_ASSERT_THROW(name == ""); + val = _tx_duc_proxy->get_link(); + return; + + case MBOARD_PROP_TX_DSP_NAMES: + val = prop_names_t(1, ""); + return; + + case MBOARD_PROP_CLOCK_CONFIG: + val = _clock_config; + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } +} + +/*********************************************************************** + * Mboard Set + **********************************************************************/ +void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val) +{ + //handle the get request conditioned on the key + switch(key.as()){ + + case MBOARD_PROP_STREAM_CMD: + issue_stream_cmd(val.as()); + return; + + case MBOARD_PROP_TIME_NOW: + case MBOARD_PROP_TIME_NEXT_PPS: + default: UHD_THROW_PROP_SET_ERROR(); + } +} diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp new file mode 100644 index 000000000..b7c6bdaf6 --- /dev/null +++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp @@ -0,0 +1,381 @@ +// +// Copyright 2010 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 . +// + +#include "usrp1_ctrl.hpp" +#include "usrp_commands.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace uhd; + +enum firmware_code { + USRP_FPGA_LOAD_SUCCESS, + USRP_FPGA_ALREADY_LOADED, + USRP_FIRMWARE_LOAD_SUCCESS, + USRP_FIRMWARE_ALREADY_LOADED +}; + +#define FX2_FIRMWARE_LOAD 0xa0 + +/*********************************************************************** + * Helper Functions + **********************************************************************/ +/*! + * Create a file hash + * The hash will be used to identify the loaded firmware and fpga image + * \param filename file used to generate hash value + * \return hash value in a size_t type + */ +static size_t generate_hash(const char *filename) +{ + std::ifstream file(filename); + if (!file) + std::cerr << "error: cannot open input file " << filename << std::endl; + + size_t hash = 0; + + char ch; + while (file.get(ch)) { + boost::hash_combine(hash, ch); + } + + if (!file.eof()) + std::cerr << "error: file error " << filename << std::endl; + + file.close(); + return hash; +} + + +/*! + * Verify checksum of a Intel HEX record + * \param record a line from an Intel HEX file + * \return true if record is valid, false otherwise + */ +static bool checksum(std::string *record) +{ + + size_t len = record->length(); + unsigned int i; + unsigned char sum = 0; + unsigned int val; + + for (i = 1; i < len; i += 2) { + std::istringstream(record->substr(i, 2)) >> std::hex >> val; + sum += val; + } + + if (sum == 0) + return true; + else + return false; +} + + +/*! + * Parse Intel HEX record + * + * \param record a line from an Intel HEX file + * \param len output length of record + * \param addr output address + * \param type output type + * \param data output data + * \return true if record is sucessfully read, false on error + */ +bool parse_record(std::string *record, unsigned int &len, + unsigned int &addr, unsigned int &type, + unsigned char* data) +{ + unsigned int i; + std::string _data; + unsigned int val; + + if (record->substr(0, 1) != ":") + return false; + + std::istringstream(record->substr(1, 2)) >> std::hex >> len; + std::istringstream(record->substr(3, 4)) >> std::hex >> addr; + std::istringstream(record->substr(7, 2)) >> std::hex >> type; + + for (i = 0; i < len; i++) { + std::istringstream(record->substr(9 + 2 * i, 2)) >> std::hex >> val; + data[i] = (unsigned char) val; + } + + return true; +} + + +/*! + * USRP control implementation for device discovery and configuration + */ +class usrp_ctrl_impl : public usrp_ctrl { +public: + usrp_ctrl_impl(uhd::transport::usb_control::sptr ctrl_transport) + { + _ctrl_transport = ctrl_transport; + } + + + ~usrp_ctrl_impl(void) + { + /* NOP */ + } + + + int usrp_load_firmware(std::string filestring, bool force) + { + const char *filename = filestring.c_str(); + + size_t hash = generate_hash(filename); + + size_t loaded_hash; + if (usrp_get_firmware_hash(loaded_hash) < 0) { + std::cerr << "firmware hash retrieval failed" << std::endl; + return -1; + } + + if (!force && (hash == loaded_hash)) + return USRP_FIRMWARE_ALREADY_LOADED; + + //FIXME: verify types + unsigned int len; + unsigned int addr; + unsigned int type; + unsigned char data[512]; + + int ret; + std::ifstream file; + file.open(filename, std::ifstream::in); + + if (!file.good()) { + std::cerr << "cannot open firmware input file" << std::endl; + return -1; + } + + unsigned char reset_y = 1; + unsigned char reset_n = 0; + + //hit the reset line + usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, + &reset_y, 1); + + while (!file.eof()) { + std::string record; + file >> record; + + //check for valid record + if (!checksum(&record) || + !parse_record(&record, len, addr, type, data)) { + std::cerr << "error: bad record" << std::endl; + file.close(); + return -1; + } + + //type 0x00 is data + if (type == 0x00) { + ret = usrp_control_write(FX2_FIRMWARE_LOAD, addr, 0, + data, len); + if (ret < 0) { + std::cerr << "error: usrp_control_write failed: "; + std::cerr << ret << std::endl; + file.close(); + return -1; + } + } + //type 0x00 is end + else if (type == 0x01) { + usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, + &reset_n, 1); + usrp_set_firmware_hash(hash); + file.close(); + + return USRP_FIRMWARE_LOAD_SUCCESS; + } + //type anything else is unhandled + else { + std::cerr << "error: unsupported record" << std::endl; + file.close(); + return -1; + } + } + + //file did not end + std::cerr << "error: bad record" << std::endl; + file.close(); + return -1; + } + + + int usrp_load_fpga(std::string filestring) + { + const char *filename = filestring.c_str(); + + size_t hash = generate_hash(filename); + + size_t loaded_hash; + if (usrp_get_fpga_hash(loaded_hash) < 0) { + std::cerr << "fpga hash retrieval failed" << std::endl; + return -1; + } + + if (hash == loaded_hash) + return USRP_FPGA_ALREADY_LOADED; + const int ep0_size = 64; + unsigned char buf[ep0_size]; + int ret; + + FILE *fp; + if ((fp = fopen(filename, "rb")) == NULL) { + std::cerr << "cannot open fpga input file" << std::endl; + fclose(fp); + return -1; + } + + if (usrp_control_write_cmd(VRQ_FPGA_LOAD, 0, FL_BEGIN) < 0) { + std::cerr << "fpga load error" << std::endl; + fclose(fp); + return -1; + } + + ssize_t n; + while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) { + ret = usrp_control_write(VRQ_FPGA_LOAD, 0, FL_XFER, + buf, n); + if (ret != n) { + std::cerr << "fpga load error " << ret << std::endl; + fclose(fp); + return -1; + } + } + + if (usrp_control_write_cmd(VRQ_FPGA_LOAD, 0, FL_END) < 0) { + std::cerr << "fpga load error" << std::endl; + fclose(fp); + return -1; + } + + usrp_set_fpga_hash(hash); + fclose(fp); + return 0; + } + + + int usrp_set_led(int led_num, bool on) + { + return usrp_control_write_cmd(VRQ_SET_LED, on, led_num); + } + + + int usrp_get_firmware_hash(size_t &hash) + { + return usrp_control_read(0xa0, USRP_HASH_SLOT_0_ADDR, 0, + (unsigned char*) &hash, sizeof(size_t)); + } + + + int usrp_set_firmware_hash(size_t hash) + { + return usrp_control_write(0xa0, USRP_HASH_SLOT_0_ADDR, 0, + (unsigned char*) &hash, sizeof(size_t)); + + } + + + int usrp_get_fpga_hash(size_t &hash) + { + return usrp_control_read(0xa0, USRP_HASH_SLOT_1_ADDR, 0, + (unsigned char*) &hash, sizeof(size_t)); + } + + + int usrp_set_fpga_hash(size_t hash) + { + return usrp_control_write(0xa0, USRP_HASH_SLOT_1_ADDR, 0, + (unsigned char*) &hash, sizeof(size_t)); + } + + int usrp_tx_enable(bool on) + { + return usrp_control_write_cmd(VRQ_FPGA_SET_TX_ENABLE, on, 0); + } + + + int usrp_rx_enable(bool on) + { + return usrp_control_write_cmd(VRQ_FPGA_SET_RX_ENABLE, on, 0); + } + + + int usrp_tx_reset(bool on) + { + return usrp_control_write_cmd(VRQ_FPGA_SET_TX_RESET, on, 0); + } + + + int usrp_control_write(boost::uint8_t request, + boost::uint16_t value, + boost::uint16_t index, + unsigned char *buff, + boost::uint16_t length) + { + return _ctrl_transport->submit(VRT_VENDOR_OUT, // bmReqeustType + request, // bRequest + value, // wValue + index, // wIndex + buff, // data + length); // wLength + } + + + int usrp_control_read(boost::uint8_t request, + boost::uint16_t value, + boost::uint16_t index, + unsigned char *buff, + boost::uint16_t length) + { + return _ctrl_transport->submit(VRT_VENDOR_IN, // bmReqeustType + request, // bRequest + value, // wValue + index, // wIndex + buff, // data + length); // wLength + } + + + int usrp_control_write_cmd(uint8_t request, uint16_t value, uint16_t index) + { + return usrp_control_write(request, value, index, 0, 0); + } + + +private: + uhd::transport::usb_control::sptr _ctrl_transport; +}; + +/*********************************************************************** + * Public make function for usrp_ctrl interface + **********************************************************************/ +usrp_ctrl::sptr usrp_ctrl::make(uhd::transport::usb_control::sptr ctrl_transport){ + return sptr(new usrp_ctrl_impl(ctrl_transport)); +} + diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.hpp b/host/lib/usrp/usrp1/usrp1_ctrl.hpp new file mode 100644 index 000000000..deedec4e8 --- /dev/null +++ b/host/lib/usrp/usrp1/usrp1_ctrl.hpp @@ -0,0 +1,132 @@ +// +// Copyright 2010 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 . +// + +#ifndef INCLUDED_USRP_CTRL_HPP +#define INCLUDED_USRP_CTRL_HPP + +#include +#include +#include + +class usrp_ctrl : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a usrp control object from a control transport + * \param ctrl_transport a USB control transport + * \return a new usrp control object + */ + static sptr make(uhd::transport::usb_control::sptr ctrl_transport); + + /*! + * Load firmware in Intel HEX Format onto device + * \param filename name of firmware file + * \param force reload firmware if already loaded + * \return 0 on success, error code otherwise + */ + virtual int usrp_load_firmware(std::string filename, + bool force = false) = 0; + + /*! + * Load fpga file onto usrp + * \param filename name of fpga image + * \return 0 on success, error code otherwise + */ + virtual int usrp_load_fpga(std::string filename) = 0; + + /*! + * Set led usrp + * \param led_num which LED to control (0 or 1) + * \param on turn LED on or off + * \return 0 on success, error code otherwise + */ + virtual int usrp_set_led(int led_num, bool on) = 0; + + /*! + * Get firmware hash + * \param hash a size_t hash value + * \return 0 on success, error code otherwise + */ + virtual int usrp_get_firmware_hash(size_t &hash) = 0; + + /*! + * Set firmware hash + * \param hash a size_t hash value + * \return 0 on success, error code otherwise + */ + virtual int usrp_set_firmware_hash(size_t hash) = 0; + + /*! + * Get fpga hash + * \param hash a size_t hash value + * \return 0 on success, error code otherwise + */ + virtual int usrp_get_fpga_hash(size_t &hash) = 0; + + /*! + * Set fpga hash + * \param hash a size_t hash value + * \return 0 on success, error code otherwise + */ + virtual int usrp_set_fpga_hash(size_t hash) = 0; + + /*! + * Set rx enable or disable + * \param on enable or disable value + * \return 0 on success, error code otherwise + */ + virtual int usrp_rx_enable(bool on) = 0; + + /*! + * Set rx enable or disable + * \param on enable or disable value + * \return 0 on success, error code otherwise + */ + virtual int usrp_tx_enable(bool on) = 0; + + /*! + * Submit an IN transfer + * \param request device specific request + * \param value device specific field + * \param index device specific field + * \param buff buffer to place data + * \return number of bytes read or error + */ + virtual int usrp_control_read(boost::uint8_t request, + boost::uint16_t value, + boost::uint16_t index, + unsigned char *buff, + boost::uint16_t length) = 0; + + /*! + * Submit an OUT transfer + * \param request device specific request + * \param value device specific field + * \param index device specific field + * \param buff buffer of data to be sent + * \return number of bytes written or error + */ + virtual int usrp_control_write(boost::uint8_t request, + boost::uint16_t value, + boost::uint16_t index, + unsigned char *buff, + boost::uint16_t length) = 0; + +}; + +#endif /* INCLUDED_USRP_CTRL_HPP */ diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp new file mode 100644 index 000000000..b175ba21f --- /dev/null +++ b/host/lib/usrp/usrp1/usrp1_iface.cpp @@ -0,0 +1,262 @@ +// +// Copyright 2010 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 . +// + +#include "usrp1_iface.hpp" +#include "usrp_commands.h" +#include +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::transport; + +static const bool iface_debug = false; + +class usrp1_iface_impl : public usrp1_iface{ +public: + /******************************************************************* + * Structors + ******************************************************************/ + usrp1_iface_impl(usrp_ctrl::sptr ctrl_transport) + { + _ctrl_transport = ctrl_transport; + } + + ~usrp1_iface_impl(void) + { + /* NOP */ + } + + /******************************************************************* + * Peek and Poke + ******************************************************************/ + void poke32(boost::uint32_t addr, boost::uint32_t value) + { + boost::uint32_t swapped = byteswap(value); + + if (iface_debug) { + std::cout.fill('0'); + std::cout << "poke32(" << std::dec << addr << ", 0x"; + std::cout << std::hex << std::setw(8) << value << ")" << std::endl; + } + + boost::uint8_t w_index_h = SPI_ENABLE_FPGA & 0xff; + boost::uint8_t w_index_l = (SPI_FMT_MSB | SPI_FMT_HDR_1) & 0xff; + + int ret =_ctrl_transport->usrp_control_write( + VRQ_SPI_WRITE, + addr & 0x7f, + (w_index_h << 8) | (w_index_l << 0), + (unsigned char*) &swapped, + sizeof(boost::uint32_t)); + + if (ret < 0) + std::cerr << "USRP: failed memory write: " << ret << std::endl; + } + + void poke16(boost::uint32_t, boost::uint16_t) + { + //fpga only handles 32 bit writes + std::cerr << "USRP: unsupported operation: poke16()" << std::endl; + } + + boost::uint32_t peek32(boost::uint32_t addr) + { + uint32_t value_out; + + boost::uint8_t w_index_h = SPI_ENABLE_FPGA & 0xff; + boost::uint8_t w_index_l = (SPI_FMT_MSB | SPI_FMT_HDR_1) & 0xff; + + int ret = _ctrl_transport->usrp_control_read( + VRQ_SPI_READ, + 0x80 | (addr & 0x7f), + (w_index_h << 8) | (w_index_l << 0), + (unsigned char*) &value_out, + sizeof(boost::uint32_t)); + + if (ret < 0) + std::cerr << "USRP: failed memory read: " << ret << std::endl; + + return byteswap(value_out); + } + + boost::uint16_t peek16(boost::uint32_t addr) + { + uint32_t val = peek32(addr); + return boost::uint16_t(val & 0xff); + } + + /******************************************************************* + * I2C + ******************************************************************/ + static const size_t max_i2c_data_bytes = 64; + + void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes) + { + UHD_ASSERT_THROW(bytes.size() < max_i2c_data_bytes); + + unsigned char buff[max_i2c_data_bytes]; + std::copy(bytes.begin(), bytes.end(), buff); + + int ret = _ctrl_transport->usrp_control_write(VRQ_I2C_WRITE, + addr & 0xff, + 0, + buff, + bytes.size()); + + if (ret < 0) + std::cerr << "USRP: failed i2c write: " << ret << std::endl; + } + + byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes) + { + UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes); + + byte_vector_t out_bytes; + byte_vector_t::iterator it = out_bytes.begin(); + + unsigned char buff[max_i2c_data_bytes]; + + int ret = _ctrl_transport->usrp_control_read(VRQ_I2C_READ, + addr & 0xff, + 0, + buff, + num_bytes); + + if ((ret < 0) || (unsigned)ret < (num_bytes)) { + std::cerr << "USRP: failed i2c read: " << ret << std::endl; + return out_bytes; + } + + for (size_t i = 0; i < num_bytes; i++) + out_bytes.push_back(buff[i]); + + return out_bytes; + } + + /******************************************************************* + * SPI + * + * For non-readback transactions use the SPI_WRITE command, which is + * simpler and uses the USB control buffer for OUT data. No data + * needs to be returned. + * + * For readback transactions use SPI_TRANSACT, which places up to + * 4 bytes of OUT data in the device request fields and uses the + * control buffer for IN data. + ******************************************************************/ + boost::uint32_t transact_spi(int which_slave, + const spi_config_t &, + boost::uint32_t bits, + size_t num_bits, + bool readback) + { + UHD_ASSERT_THROW((num_bits < 32) && !(num_bits % 8)); + size_t num_bytes = num_bits / 8; + + // Byteswap on num_bytes + unsigned char buff[4] = { 0 }; + for (size_t i = 1; i <= num_bytes; i++) + buff[num_bytes - i] = (bits >> ((i - 1) * 8)) & 0xff; + + if (readback) { + boost::uint8_t w_len_h = which_slave & 0xff; + boost::uint8_t w_len_l = num_bytes & 0xff; + + int ret = _ctrl_transport->usrp_control_read( + VRQ_SPI_TRANSACT, + (buff[0] << 8) | (buff[1] << 0), + (buff[2] << 8) | (buff[3] << 0), + buff, + (w_len_h << 8) | (w_len_l << 0)); + + if (ret < 0) { + std::cout << "USRP: failed SPI readback transaction: " + << std::dec << ret << std::endl; + } + + boost::uint32_t val = (((boost::uint32_t)buff[0]) << 0) | + (((boost::uint32_t)buff[1]) << 8) | + (((boost::uint32_t)buff[2]) << 16) | + (((boost::uint32_t)buff[3]) << 24); + return val; + } + else { + boost::uint8_t w_index_h = which_slave & 0xff; + boost::uint8_t w_index_l = (SPI_FMT_MSB | SPI_FMT_HDR_0) & 0xff; + + int ret =_ctrl_transport->usrp_control_write( + VRQ_SPI_WRITE, + 0x00, + (w_index_h << 8) | (w_index_l << 0), + buff, num_bytes); + + if (ret < 0) { + std::cout << "USRP: failed SPI transaction: " + << std::dec << ret << std::endl; + } + + return 0; + } + } + + /******************************************************************* + * Firmware + * + * This call is deprecated. + ******************************************************************/ + void write_firmware_cmd(boost::uint8_t request, + boost::uint16_t value, + boost::uint16_t index, + unsigned char *buff, + boost::uint16_t length) + { + int ret; + + if (request & 0x80) { + ret = _ctrl_transport->usrp_control_read(request, + value, + index, + buff, + length); + } + else { + ret = _ctrl_transport->usrp_control_write(request, + value, + index, + buff, + length); + } + + if (ret < 0) + std::cerr << "USRP: failed firmware command: " << ret << std::endl; + } + +private: + usrp_ctrl::sptr _ctrl_transport; +}; + +/*********************************************************************** + * Public Make Function + **********************************************************************/ +usrp1_iface::sptr usrp1_iface::make(usrp_ctrl::sptr ctrl_transport) +{ + return sptr(new usrp1_iface_impl(ctrl_transport)); +} diff --git a/host/lib/usrp/usrp1/usrp1_iface.hpp b/host/lib/usrp/usrp1/usrp1_iface.hpp new file mode 100644 index 000000000..9a3fdd6bc --- /dev/null +++ b/host/lib/usrp/usrp1/usrp1_iface.hpp @@ -0,0 +1,100 @@ +// +// Copyright 2010 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 . +// + +#ifndef INCLUDED_USRP1_IFACE_HPP +#define INCLUDED_USRP1_IFACE_HPP + +#include +#include +#include +#include "usrp1_ctrl.hpp" + +/*! + * The usrp1 interface class: + * Provides a set of functions to implementation layer. + * Including spi, peek, poke, control... + */ +class usrp1_iface : boost::noncopyable, public uhd::i2c_iface{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a new usrp1 interface with the control transport. + * \param ctrl_transport the usrp controller object + * \return a new usrp1 interface object + */ + static sptr make(usrp_ctrl::sptr ctrl_transport); + + /*! + * Write a register (32 bits) + * \param addr the address + * \param data the 32bit data + */ + virtual void poke32(boost::uint32_t addr, boost::uint32_t data) = 0; + + /*! + * Read a register (32 bits) + * \param addr the address + * \return the 32bit data + */ + virtual boost::uint32_t peek32(boost::uint32_t addr) = 0; + + /*! + * Write a register (16 bits) + * \param addr the address + * \param data the 16bit data + */ + virtual void poke16(boost::uint32_t addr, boost::uint16_t data) = 0; + + /*! + * read a register (16 bits) + * \param addr the address + * \return the 16bit data + */ + virtual boost::uint16_t peek16(boost::uint32_t addr) = 0; + + /*! + * Perform an spi transaction. + * \param which_slave the slave device number + * \param config spi config args + * \param data the bits to write + * \param num_bits how many bits in data + * \param readback true to readback a value + * \return spi data if readback set + */ + virtual boost::uint32_t transact_spi(int which_slave, + const uhd::spi_config_t &config, + boost::uint32_t data, + size_t num_bits, + bool readback) = 0; + + /*! + * Perform a general USB firmware OUT operation + * \param request + * \param value + * \param index + * \param data + * \return + */ + virtual void write_firmware_cmd(boost::uint8_t request, + boost::uint16_t value, + boost::uint16_t index, + unsigned char* buff, + boost::uint16_t length) = 0; +}; + +#endif /* INCLUDED_USRP1_IFACE_HPP */ diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp new file mode 100644 index 000000000..4cb286354 --- /dev/null +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -0,0 +1,196 @@ +// +// Copyright 2010 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 . +// + +#include "usrp1_impl.hpp" +#include "usrp1_ctrl.hpp" +#include "fpga_regs_standard.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; +using namespace uhd::transport; + +/*********************************************************************** + * Discovery + **********************************************************************/ +static device_addrs_t usrp1_find(const device_addr_t &hint) +{ + device_addrs_t usrp1_addrs; + std::string filename = "/usr/local/share/usrp/rev4/std.ihx"; + + //return an empty list of addresses when type is set to non-usrp1 + if (hint.has_key("type") and hint["type"] != "usrp1") return usrp1_addrs; + + //see what we got on the USB bus + usb_descriptors_t usb_descriptors; + usb_descriptors = usb_control::get_device_list(); + + //find the usrps and load firmware + BOOST_FOREACH(usb_descriptor_t desc, usb_descriptors) { + if (desc.vendor_id == 0xfffe && desc.product_id == 0x0002) { + usb_control::sptr ctrl_transport = usb_control::make(desc); + usrp_ctrl::sptr usrp_ctrl = usrp_ctrl::make(ctrl_transport); + usrp_ctrl->usrp_load_firmware(filename); + } + } + + //wait for things to settle + sleep(1); + + //get descriptors again with serial number + usb_descriptors = usb_control::get_device_list(); + + BOOST_FOREACH(usb_descriptor_t desc, usb_descriptors) { + if (desc.vendor_id == 0xfffe && desc.product_id == 0x0002) { + device_addr_t new_addr; + new_addr["type"] = "usrp1"; + new_addr["serial"] = desc.serial; + usrp1_addrs.push_back(new_addr); + } + } + + return usrp1_addrs; +} + +/*********************************************************************** + * Make + **********************************************************************/ +static device::sptr usrp1_make(const device_addr_t &device_addr) +{ + std::string filename; + + if (device_addr.has_key("fpga")) + filename = device_addr["fpga"]; + else + filename = "/usr/local/share/usrp/rev4/std_2rxhb_2tx.rbf"; + + std::cout << "Make usrp1 with " << filename << std::endl; + + //try to match the given device address with something on the USB bus + usb_descriptors_t usb_descriptors; + usb_descriptors = usb_control::get_device_list(); + + //create data and control transports + usb_zero_copy::sptr data_transport; + usrp_ctrl::sptr usrp_ctrl; + + BOOST_FOREACH(usb_descriptor_t desc, usb_descriptors) { + if (desc.serial == device_addr["serial"] + && desc.vendor_id == 0xfffe && desc.product_id == 0x0002) { + + usb_control::sptr ctrl_transport = usb_control::make(desc); + usrp_ctrl = usrp_ctrl::make(ctrl_transport); + usrp_ctrl->usrp_load_fpga(filename); + + data_transport = usb_zero_copy::make(desc, // identifier + 6, // IN endpoint + 2, // OUT endpoint + 2 * (1 << 20), // buffer size + 16384); // transfer size + break; + } + } + + //create the usrp1 implementation guts + return device::sptr(new usrp1_impl(data_transport, usrp_ctrl)); +} + +UHD_STATIC_BLOCK(register_usrp1_device){ + device::register_device(&usrp1_find, &usrp1_make); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +usrp1_impl::usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport, + usrp_ctrl::sptr ctrl_transport) + : _data_transport(data_transport), _ctrl_transport(ctrl_transport) +{ + _iface = usrp1_iface::make(ctrl_transport); + + //create clock interface + _clock_ctrl = usrp1_clock_ctrl::make(_iface); + + //create codec interface + _codec_ctrl = usrp1_codec_ctrl::make(_iface); + + //initialize the codecs + codec_init(); + + //initialize the mboard + mboard_init(); + + //initialize the dboards + dboard_init(); + + //initialize the dsps + rx_ddc_init(); + + //initialize the dsps + tx_duc_init(); + + //initialize the send/recv + io_init(); + + //turn on the transmitter + _ctrl_transport->usrp_tx_enable(true); +} + +usrp1_impl::~usrp1_impl(void){ + /* NOP */ +} + +/*********************************************************************** + * Device Get + **********************************************************************/ +void usrp1_impl::get(const wax::obj &key_, wax::obj &val) +{ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(key.as()){ + case DEVICE_PROP_NAME: + val = std::string("usrp1 device"); + return; + + case DEVICE_PROP_MBOARD: + UHD_ASSERT_THROW(name == ""); + val = _mboard_proxy->get_link(); + return; + + case DEVICE_PROP_MBOARD_NAMES: + val = prop_names_t(1, ""); //vector of size 1 with empty string + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } +} + +/*********************************************************************** + * Device Set + **********************************************************************/ +void usrp1_impl::set(const wax::obj &, const wax::obj &) +{ + UHD_THROW_PROP_SET_ERROR(); +} diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp new file mode 100644 index 000000000..5abc37c7f --- /dev/null +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -0,0 +1,182 @@ +// +// Copyright 2010 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 . +// + +#include "usrp1_iface.hpp" +#include "usrp1_ctrl.hpp" +#include "clock_ctrl.hpp" +#include "codec_ctrl.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef INCLUDED_USRP1_IMPL_HPP +#define INCLUDED_USRP1_IMPL_HPP + +static const double MASTER_CLOCK_RATE = 64e6; //TODO get from clock control + +/*! + * Make a usrp1 dboard interface. + * \param iface the usrp1 interface object + * \param clock the clock control interface + * \param codec the codec control interface + * \return a sptr to a new dboard interface + */ +uhd::usrp::dboard_iface::sptr make_usrp1_dboard_iface(usrp1_iface::sptr iface, + usrp1_clock_ctrl::sptr clock, + usrp1_codec_ctrl::sptr codec); + +/*! + * Simple wax obj proxy class: + * Provides a wax obj interface for a set and a get function. + * This allows us to create nested properties structures + * while maintaining flattened code within the implementation. + */ +class wax_obj_proxy : public wax::obj { +public: + typedef boost::function get_t; + typedef boost::function set_t; + typedef boost::shared_ptr sptr; + + static sptr make(const get_t &get, const set_t &set) + { + return sptr(new wax_obj_proxy(get, set)); + } + +private: + get_t _get; set_t _set; + wax_obj_proxy(const get_t &get, const set_t &set): _get(get), _set(set) {}; + void get(const wax::obj &key, wax::obj &val) {return _get(key, val);} + void set(const wax::obj &key, const wax::obj &val) {return _set(key, val);} +}; + +/*! + * USRP1 implementation guts: + * The implementation details are encapsulated here. + * Handles properties on the mboard, dboard, dsps... + */ +class usrp1_impl : public uhd::device { +public: + //structors + usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport, + usrp_ctrl::sptr ctrl_transport); + + ~usrp1_impl(void); + + //the io interface + size_t send(const std::vector &, + size_t, + const uhd::tx_metadata_t &, + const uhd::io_type_t &, + send_mode_t); + + size_t recv(const std::vector &, + size_t, uhd::rx_metadata_t &, + const uhd::io_type_t &, + recv_mode_t, + size_t timeout); + + size_t get_max_send_samps_per_packet(void) const { return 0; } + size_t get_max_recv_samps_per_packet(void) const { return 0; } + + bool recv_async_msg(uhd::async_metadata_t &, size_t) { return true; } + +private: + //interface to ioctls and file descriptor + usrp1_iface::sptr _iface; + + //handle io stuff + UHD_PIMPL_DECL(io_impl) _io_impl; + void io_init(void); + void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd); + void handle_overrun(size_t); + + //otw types + uhd::otw_type_t _rx_otw_type; + uhd::otw_type_t _tx_otw_type; + + //configuration shadows + uhd::clock_config_t _clock_config; + + //clock control + usrp1_clock_ctrl::sptr _clock_ctrl; + + //ad9862 codec control interface + usrp1_codec_ctrl::sptr _codec_ctrl; + + //codec properties interfaces + void codec_init(void); + void rx_codec_get(const wax::obj &, wax::obj &); + void rx_codec_set(const wax::obj &, const wax::obj &); + void tx_codec_get(const wax::obj &, wax::obj &); + void tx_codec_set(const wax::obj &, const wax::obj &); + wax_obj_proxy::sptr _rx_codec_proxy; + wax_obj_proxy::sptr _tx_codec_proxy; + + //device functions and settings + void get(const wax::obj &, wax::obj &); + void set(const wax::obj &, const wax::obj &); + + //mboard functions and settings + void mboard_init(void); + void mboard_get(const wax::obj &, wax::obj &); + void mboard_set(const wax::obj &, const wax::obj &); + wax_obj_proxy::sptr _mboard_proxy; + + //xx dboard functions and settings + void dboard_init(void); + uhd::usrp::dboard_manager::sptr _dboard_manager; + uhd::usrp::dboard_iface::sptr _dboard_iface; + + //rx dboard functions and settings + uhd::usrp::dboard_eeprom_t _rx_db_eeprom; + void rx_dboard_get(const wax::obj &, wax::obj &); + void rx_dboard_set(const wax::obj &, const wax::obj &); + uhd::prop_names_t _rx_subdevs_in_use; + wax_obj_proxy::sptr _rx_dboard_proxy; + + //tx dboard functions and settings + uhd::usrp::dboard_eeprom_t _tx_db_eeprom; + void tx_dboard_get(const wax::obj &, wax::obj &); + void tx_dboard_set(const wax::obj &, const wax::obj &); + uhd::prop_names_t _tx_subdevs_in_use; + wax_obj_proxy::sptr _tx_dboard_proxy; + + //rx ddc functions and settings + void rx_ddc_init(void); + void rx_ddc_get(const wax::obj &, wax::obj &); + void rx_ddc_set(const wax::obj &, const wax::obj &); + double _ddc_freq; size_t _ddc_decim; + wax_obj_proxy::sptr _rx_ddc_proxy; + + //tx duc functions and settings + void tx_duc_init(void); + void tx_duc_get(const wax::obj &, wax::obj &); + void tx_duc_set(const wax::obj &, const wax::obj &); + double _duc_freq; size_t _duc_interp; + wax_obj_proxy::sptr _tx_duc_proxy; + + //transports + uhd::transport::usb_zero_copy::sptr _data_transport; + usrp_ctrl::sptr _ctrl_transport; +}; + +#endif /* INCLUDED_USRP1_IMPL_HPP */ -- cgit v1.2.3 From 2e978d8835b8f954b7c34c42138b64d3a5767f81 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 15 Aug 2010 12:40:37 -0700 Subject: usrp1: compiling off next branch made usb checking changes implemented named_prop_t::extract change copied the remainder of the codec pga gain control --- host/lib/transport/CMakeLists.txt | 1 + host/lib/transport/libusb1_control.cpp | 14 ++++----- host/lib/usrp/usrp1/CMakeLists.txt | 56 ++++++++++++++++++++++------------ host/lib/usrp/usrp1/codec_ctrl.cpp | 8 ++--- host/lib/usrp/usrp1/codec_ctrl.hpp | 16 ++++++++++ host/lib/usrp/usrp1/codec_impl.cpp | 33 +++++++++----------- host/lib/usrp/usrp1/dboard_iface.cpp | 7 +++-- host/lib/usrp/usrp1/dboard_impl.cpp | 14 ++++----- host/lib/usrp/usrp1/mboard_impl.cpp | 12 +++----- host/lib/usrp/usrp1/usrp1_impl.cpp | 5 ++- 10 files changed, 98 insertions(+), 68 deletions(-) diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index d6e1ff7ba..627d2d806 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -30,6 +30,7 @@ IF(LIBUSB_FOUND) ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_control.cpp ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_zero_copy.cpp ) + SET(HAVE_USB_SUPPORT TRUE) ENDIF(LIBUSB_FOUND) ######################################################################## diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp index 2903d943d..c2f7060e8 100644 --- a/host/lib/transport/libusb1_control.cpp +++ b/host/lib/transport/libusb1_control.cpp @@ -16,10 +16,10 @@ // #include -#include #include #include #include +#include #include using namespace uhd::transport; @@ -61,15 +61,15 @@ libusb_control_impl::libusb_control_impl(uhd::usb_descriptor_t descriptor) : _descriptor(descriptor), _ctx(NULL), _dev_handle(NULL) { if (libusb_init(&_ctx) < 0) - UHD_THROW_SITE_INFO("USB: failed to initialize libusb"); + throw std::runtime_error("USB: failed to initialize libusb"); libusb_set_debug(_ctx, libusb_debug_level); if (!open_device()) - UHD_THROW_SITE_INFO("USB: failed to open device"); + throw std::runtime_error("USB: failed to open device"); if (!open_interface()) - UHD_THROW_SITE_INFO("USB: failed to open device interface"); + throw std::runtime_error("USB: failed to open device interface"); } @@ -85,7 +85,7 @@ uhd::usb_descriptor_t libusb_control_impl::create_descriptor(libusb_device *dev) libusb_device_descriptor desc; if (libusb_get_device_descriptor(dev, &desc) < 0) - UHD_THROW_SITE_INFO("USB: failed to get device descriptor"); + throw std::runtime_error("USB: failed to get device descriptor"); uhd::usb_descriptor_t descriptor; @@ -217,12 +217,12 @@ uhd::usb_descriptors_t usb_control::get_device_list() uhd::usb_descriptors_t descriptors; if (libusb_init(NULL) < 0) - UHD_THROW_SITE_INFO("USB: failed to initialize libusb"); + throw std::runtime_error("USB: failed to initialize libusb"); ssize_t cnt = libusb_get_device_list(NULL, &list); if (cnt < 0) - UHD_THROW_SITE_INFO("USB: failed to get device list"); + throw std::runtime_error("USB: failed to get device list"); ssize_t i = 0; for (i = 0; i < cnt; i++) { diff --git a/host/lib/usrp/usrp1/CMakeLists.txt b/host/lib/usrp/usrp1/CMakeLists.txt index eb7bd4b06..229a4ce63 100644 --- a/host/lib/usrp/usrp1/CMakeLists.txt +++ b/host/lib/usrp/usrp1/CMakeLists.txt @@ -17,23 +17,41 @@ #This file will be included by cmake, use absolute paths! -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../firmware/fx2/include) +######################################################################## +# Conditionally configure the USRP1 support +######################################################################## +MESSAGE(STATUS "Configuring usrp1 support...") -LIBUHD_APPEND_SOURCES( - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/clock_ctrl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/clock_ctrl.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/codec_ctrl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/codec_ctrl.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/codec_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/dboard_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/dboard_iface.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/dsp_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/io_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/mboard_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_iface.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_iface.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_impl.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_ctrl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_ctrl.hpp -) +IF(HAVE_USB_SUPPORT) + MESSAGE(STATUS "Has USB support - found") +ELSE(HAVE_USB_SUPPORT) + MESSAGE(STATUS "Has USB support - not found") +ENDIF(HAVE_USB_SUPPORT) + +#TODO check for usrp1 enable/disable option flag + +IF(HAVE_USB_SUPPORT) + MESSAGE(STATUS " Building usrp1 support.") + INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../firmware/fx2/include) + + LIBUHD_APPEND_SOURCES( + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/clock_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/clock_ctrl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/codec_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/codec_ctrl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/codec_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/dboard_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/dboard_iface.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/dsp_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/io_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/mboard_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_iface.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_iface.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_impl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_ctrl.hpp + ) +ELSE(HAVE_USB_SUPPORT) + MESSAGE(STATUS " Skipping usrp1 support.") +ENDIF(HAVE_USB_SUPPORT) diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index 866650c2c..d0576a769 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -25,12 +25,12 @@ #include #include #include +#include #include #include #include #include #include -#include using namespace uhd; @@ -335,9 +335,9 @@ unsigned int usrp1_codec_ctrl_impl::compute_freq_control_word_9862( int v = (int) rint (fabs (target_freq) / master_freq * pow (2.0, 24.0)); *actual_freq = v * master_freq / pow (2.0, 24.0) * sign; - fprintf(stdout, - "compute_freq_control_word_9862: target = %g actual = %g delta = %g v = %8d\n", - target_freq, *actual_freq, *actual_freq - target_freq, v); + std::cout << boost::format( + "compute_freq_control_word_9862: target = %g actual = %g delta = %g v = %8d\n" + ) % target_freq % *actual_freq % (*actual_freq - target_freq) % v; return (unsigned int) v; } diff --git a/host/lib/usrp/usrp1/codec_ctrl.hpp b/host/lib/usrp/usrp1/codec_ctrl.hpp index 51e29345a..0605e3228 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.hpp +++ b/host/lib/usrp/usrp1/codec_ctrl.hpp @@ -19,6 +19,7 @@ #define INCLUDED_USRP1_CODEC_CTRL_HPP #include "usrp1_iface.hpp" +#include #include #include @@ -31,6 +32,9 @@ class usrp1_codec_ctrl : boost::noncopyable{ public: typedef boost::shared_ptr sptr; + static const uhd::gain_range_t tx_pga_gain_range; + static const uhd::gain_range_t rx_pga_gain_range; + /*! * Make a new clock control object. * \param iface the usrp1 iface object @@ -70,6 +74,18 @@ public: */ virtual void write_aux_dac(aux_dac_t which, float volts) = 0; + //! Set the TX PGA gain + virtual void set_tx_pga_gain(float gain) = 0; + + //! Get the TX PGA gain + virtual float get_tx_pga_gain(void) = 0; + + //! Set the RX PGA gain ('A' or 'B') + virtual void set_rx_pga_gain(float gain, char which) = 0; + + //! Get the RX PGA gain ('A' or 'B') + virtual float get_rx_pga_gain(char which) = 0; + virtual bool set_duc_freq(double freq) = 0; }; diff --git a/host/lib/usrp/usrp1/codec_impl.cpp b/host/lib/usrp/usrp1/codec_impl.cpp index 9253c06ba..7bf5631fb 100644 --- a/host/lib/usrp/usrp1/codec_impl.cpp +++ b/host/lib/usrp/usrp1/codec_impl.cpp @@ -16,6 +16,7 @@ // #include "usrp1_impl.hpp" +#include #include #include @@ -44,8 +45,7 @@ static const std::string ad9862_pga_gain_name = "ad9862 pga"; void usrp1_impl::rx_codec_get(const wax::obj &key_, wax::obj &val) { - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as()) { @@ -62,17 +62,17 @@ void usrp1_impl::rx_codec_get(const wax::obj &key_, wax::obj &val) return; case CODEC_PROP_GAIN_RANGE: - UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); val = usrp1_codec_ctrl::rx_pga_gain_range; return; case CODEC_PROP_GAIN_I: - UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); val = _codec_ctrl->get_rx_pga_gain('A'); return; case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); val = _codec_ctrl->get_rx_pga_gain('B'); return; @@ -80,20 +80,19 @@ void usrp1_impl::rx_codec_get(const wax::obj &key_, wax::obj &val) } } -void usrp1_impl::rx_codec_set(const wax::obj &, const wax::obj &) +void usrp1_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val) { - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the set request conditioned on the key switch(key.as()) { case CODEC_PROP_GAIN_I: - UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); _codec_ctrl->set_rx_pga_gain(val.as(), 'A'); return; case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); _codec_ctrl->set_rx_pga_gain(val.as(), 'B'); return; @@ -106,8 +105,7 @@ void usrp1_impl::rx_codec_set(const wax::obj &, const wax::obj &) **********************************************************************/ void usrp1_impl::tx_codec_get(const wax::obj &key_, wax::obj &val) { - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as()) { @@ -124,13 +122,13 @@ void usrp1_impl::tx_codec_get(const wax::obj &key_, wax::obj &val) return; case CODEC_PROP_GAIN_RANGE: - UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); val = usrp1_codec_ctrl::tx_pga_gain_range; return; case CODEC_PROP_GAIN_I: //only one gain for I and Q case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); val = _codec_ctrl->get_tx_pga_gain(); return; @@ -138,16 +136,15 @@ void usrp1_impl::tx_codec_get(const wax::obj &key_, wax::obj &val) } } -void usrp1_impl::tx_codec_set(const wax::obj &, const wax::obj &) +void usrp1_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val) { - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the set request conditioned on the key switch(key.as()){ case CODEC_PROP_GAIN_I: //only one gain for I and Q case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(name == ad9862_pga_gain_name); + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); _codec_ctrl->set_tx_pga_gain(val.as()); return; diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp index 11ad3fe8a..ef6a1e67b 100644 --- a/host/lib/usrp/usrp1/dboard_iface.cpp +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -51,9 +51,12 @@ public: /* NOP */ } - std::string get_mboard_name() + special_props_t get_special_props() { - return "usrp1"; + special_props_t props; + props.soft_clock_divider = true; + props.mangle_i2c_addrs = false; //TODO true on side B + return props; } void write_aux_dac(unit_t, aux_dac_t, float); diff --git a/host/lib/usrp/usrp1/dboard_impl.cpp b/host/lib/usrp/usrp1/dboard_impl.cpp index 4f2836ea9..9df87432d 100644 --- a/host/lib/usrp/usrp1/dboard_impl.cpp +++ b/host/lib/usrp/usrp1/dboard_impl.cpp @@ -82,8 +82,7 @@ void usrp1_impl::dboard_init(void) **********************************************************************/ void usrp1_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val) { - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as()){ @@ -92,7 +91,7 @@ void usrp1_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val) return; case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_rx_subdev(name); + val = _dboard_manager->get_rx_subdev(key.name); return; case DBOARD_PROP_SUBDEV_NAMES: @@ -112,7 +111,7 @@ void usrp1_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val) return; case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group(_dboard_manager->get_rx_subdev(name), + val = make_gain_group(_dboard_manager->get_rx_subdev(key.name), _rx_codec_proxy->get_link()); return; @@ -142,8 +141,7 @@ void usrp1_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val) **********************************************************************/ void usrp1_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val) { - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as()){ @@ -152,7 +150,7 @@ void usrp1_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val) return; case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_tx_subdev(name); + val = _dboard_manager->get_tx_subdev(key.name); return; case DBOARD_PROP_SUBDEV_NAMES: @@ -172,7 +170,7 @@ void usrp1_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val) return; case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group(_dboard_manager->get_tx_subdev(name), + val = make_gain_group(_dboard_manager->get_tx_subdev(key.name), _tx_codec_proxy->get_link()); return; diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index ee1ba305b..2514072e0 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -111,9 +111,7 @@ void usrp1_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd) **********************************************************************/ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) { - wax::obj key; - std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as()){ @@ -126,7 +124,7 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) return; case MBOARD_PROP_RX_DBOARD: - UHD_ASSERT_THROW(name == ""); + UHD_ASSERT_THROW(key.name == ""); val = _rx_dboard_proxy->get_link(); return; @@ -135,7 +133,7 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) return; case MBOARD_PROP_TX_DBOARD: - UHD_ASSERT_THROW(name == ""); + UHD_ASSERT_THROW(key.name == ""); val = _tx_dboard_proxy->get_link(); return; @@ -144,7 +142,7 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) return; case MBOARD_PROP_RX_DSP: - UHD_ASSERT_THROW(name == ""); + UHD_ASSERT_THROW(key.name == ""); val = _rx_ddc_proxy->get_link(); return; @@ -153,7 +151,7 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) return; case MBOARD_PROP_TX_DSP: - UHD_ASSERT_THROW(name == ""); + UHD_ASSERT_THROW(key.name == ""); val = _tx_duc_proxy->get_link(); return; diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 4cb286354..1435b981c 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -165,8 +165,7 @@ usrp1_impl::~usrp1_impl(void){ **********************************************************************/ void usrp1_impl::get(const wax::obj &key_, wax::obj &val) { - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); + named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as()){ @@ -175,7 +174,7 @@ void usrp1_impl::get(const wax::obj &key_, wax::obj &val) return; case DEVICE_PROP_MBOARD: - UHD_ASSERT_THROW(name == ""); + UHD_ASSERT_THROW(key.name == ""); val = _mboard_proxy->get_link(); return; -- cgit v1.2.3 From 5c0d3d30606b25c72c98785d49c13cc27ad49ec1 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 15 Aug 2010 18:49:06 -0700 Subject: usrp1: created daughterboard duality everything that should have two is now stored into a dictionary of slot to type the set and get functions are now bound with a third argument for dboard slot the dboard iface has yet to be completed with the correct registers for a vs b --- host/lib/usrp/usrp1/codec_ctrl.cpp | 16 ++-- host/lib/usrp/usrp1/codec_ctrl.hpp | 3 +- host/lib/usrp/usrp1/codec_impl.cpp | 42 +++++----- host/lib/usrp/usrp1/dboard_iface.cpp | 28 +++++-- host/lib/usrp/usrp1/dboard_impl.cpp | 148 +++++++++++++++++++---------------- host/lib/usrp/usrp1/dsp_impl.cpp | 55 +++++++------ host/lib/usrp/usrp1/mboard_impl.cpp | 21 +++-- host/lib/usrp/usrp1/usrp1_impl.cpp | 13 ++- host/lib/usrp/usrp1/usrp1_impl.hpp | 103 +++++++++++++----------- 9 files changed, 246 insertions(+), 183 deletions(-) diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index d0576a769..01617de94 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -17,8 +17,6 @@ #include "codec_ctrl.hpp" #include "usrp_commands.h" -#include "fpga_regs_standard.h" -#include "usrp_spi_defs.h" #include "ad9862_regs.hpp" #include #include @@ -45,7 +43,7 @@ const gain_range_t usrp1_codec_ctrl::rx_pga_gain_range(0, 20, 1); class usrp1_codec_ctrl_impl : public usrp1_codec_ctrl { public: //structors - usrp1_codec_ctrl_impl(usrp1_iface::sptr iface); + usrp1_codec_ctrl_impl(usrp1_iface::sptr iface, int spi_slave); ~usrp1_codec_ctrl_impl(void); //aux adc and dac control @@ -63,6 +61,7 @@ public: private: usrp1_iface::sptr _iface; + int _spi_slave; ad9862_regs_t _ad9862_regs; aux_adc_t _last_aux_adc_a, _last_aux_adc_b; void send_reg(boost::uint8_t addr); @@ -78,9 +77,10 @@ private: /*********************************************************************** * Codec Control Structors **********************************************************************/ -usrp1_codec_ctrl_impl::usrp1_codec_ctrl_impl(usrp1_iface::sptr iface) +usrp1_codec_ctrl_impl::usrp1_codec_ctrl_impl(usrp1_iface::sptr iface, int spi_slave) { _iface = iface; + _spi_slave = spi_slave; //soft reset _ad9862_regs.soft_reset = 1; @@ -295,7 +295,7 @@ void usrp1_codec_ctrl_impl::send_reg(boost::uint8_t addr) std::cout << "codec control write reg: 0x"; std::cout << std::setw(8) << std::hex << reg << std::endl; } - _iface->transact_spi(SPI_ENABLE_CODEC_A, + _iface->transact_spi(_spi_slave, spi_config_t::EDGE_RISE, reg, 16, false); } @@ -309,7 +309,7 @@ void usrp1_codec_ctrl_impl::recv_reg(boost::uint8_t addr) std::cout << std::setw(8) << std::hex << reg << std::endl; } - boost::uint32_t ret = _iface->transact_spi(SPI_ENABLE_CODEC_A, + boost::uint32_t ret = _iface->transact_spi(_spi_slave, spi_config_t::EDGE_RISE, reg, 16, true); if (codec_debug) { @@ -435,7 +435,7 @@ bool usrp1_codec_ctrl_impl::set_duc_freq(double freq) /*********************************************************************** * Codec Control Make **********************************************************************/ -usrp1_codec_ctrl::sptr usrp1_codec_ctrl::make(usrp1_iface::sptr iface) +usrp1_codec_ctrl::sptr usrp1_codec_ctrl::make(usrp1_iface::sptr iface, int spi_slave) { - return sptr(new usrp1_codec_ctrl_impl(iface)); + return sptr(new usrp1_codec_ctrl_impl(iface, spi_slave)); } diff --git a/host/lib/usrp/usrp1/codec_ctrl.hpp b/host/lib/usrp/usrp1/codec_ctrl.hpp index 0605e3228..6440f97d1 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.hpp +++ b/host/lib/usrp/usrp1/codec_ctrl.hpp @@ -38,9 +38,10 @@ public: /*! * Make a new clock control object. * \param iface the usrp1 iface object + * \param spi_slave which spi device * \return the clock control object */ - static sptr make(usrp1_iface::sptr iface); + static sptr make(usrp1_iface::sptr iface, int spi_slave); //! aux adc identifier constants enum aux_adc_t{ diff --git a/host/lib/usrp/usrp1/codec_impl.cpp b/host/lib/usrp/usrp1/codec_impl.cpp index 7bf5631fb..766a7948f 100644 --- a/host/lib/usrp/usrp1/codec_impl.cpp +++ b/host/lib/usrp/usrp1/codec_impl.cpp @@ -19,6 +19,8 @@ #include #include #include +#include +#include using namespace uhd; using namespace uhd::usrp; @@ -29,13 +31,15 @@ using namespace uhd::usrp; void usrp1_impl::codec_init(void) { //make proxies - _rx_codec_proxy = wax_obj_proxy::make( - boost::bind(&usrp1_impl::rx_codec_get, this, _1, _2), - boost::bind(&usrp1_impl::rx_codec_set, this, _1, _2)); - - _tx_codec_proxy = wax_obj_proxy::make( - boost::bind(&usrp1_impl::tx_codec_get, this, _1, _2), - boost::bind(&usrp1_impl::tx_codec_set, this, _1, _2)); + BOOST_FOREACH(dboard_slot_t dboard_slot, _dboard_slots){ + _rx_codec_proxies[dboard_slot] = wax_obj_proxy::make( + boost::bind(&usrp1_impl::rx_codec_get, this, _1, _2, dboard_slot), + boost::bind(&usrp1_impl::rx_codec_set, this, _1, _2, dboard_slot)); + + _tx_codec_proxies[dboard_slot] = wax_obj_proxy::make( + boost::bind(&usrp1_impl::tx_codec_get, this, _1, _2, dboard_slot), + boost::bind(&usrp1_impl::tx_codec_set, this, _1, _2, dboard_slot)); + } } /*********************************************************************** @@ -43,14 +47,14 @@ void usrp1_impl::codec_init(void) **********************************************************************/ static const std::string ad9862_pga_gain_name = "ad9862 pga"; -void usrp1_impl::rx_codec_get(const wax::obj &key_, wax::obj &val) +void usrp1_impl::rx_codec_get(const wax::obj &key_, wax::obj &val, dboard_slot_t dboard_slot) { named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as()) { case CODEC_PROP_NAME: - val = std::string("usrp1 adc - ad9862"); + val = str(boost::format("usrp1 adc - ad9862 - slot %c") % dboard_slot); return; case CODEC_PROP_OTHERS: @@ -68,19 +72,19 @@ void usrp1_impl::rx_codec_get(const wax::obj &key_, wax::obj &val) case CODEC_PROP_GAIN_I: UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = _codec_ctrl->get_rx_pga_gain('A'); + val = _codec_ctrls[dboard_slot]->get_rx_pga_gain('A'); return; case CODEC_PROP_GAIN_Q: UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = _codec_ctrl->get_rx_pga_gain('B'); + val = _codec_ctrls[dboard_slot]->get_rx_pga_gain('B'); return; default: UHD_THROW_PROP_GET_ERROR(); } } -void usrp1_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val) +void usrp1_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val, dboard_slot_t dboard_slot) { named_prop_t key = named_prop_t::extract(key_); @@ -88,12 +92,12 @@ void usrp1_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val) switch(key.as()) { case CODEC_PROP_GAIN_I: UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - _codec_ctrl->set_rx_pga_gain(val.as(), 'A'); + _codec_ctrls[dboard_slot]->set_rx_pga_gain(val.as(), 'A'); return; case CODEC_PROP_GAIN_Q: UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - _codec_ctrl->set_rx_pga_gain(val.as(), 'B'); + _codec_ctrls[dboard_slot]->set_rx_pga_gain(val.as(), 'B'); return; default: UHD_THROW_PROP_SET_ERROR(); @@ -103,14 +107,14 @@ void usrp1_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val) /*********************************************************************** * TX Codec Properties **********************************************************************/ -void usrp1_impl::tx_codec_get(const wax::obj &key_, wax::obj &val) +void usrp1_impl::tx_codec_get(const wax::obj &key_, wax::obj &val, dboard_slot_t dboard_slot) { named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as()) { case CODEC_PROP_NAME: - val = std::string("usrp1 dac - ad9862"); + val = str(boost::format("usrp1 dac - ad9862 - slot %c") % dboard_slot); return; case CODEC_PROP_OTHERS: @@ -129,14 +133,14 @@ void usrp1_impl::tx_codec_get(const wax::obj &key_, wax::obj &val) case CODEC_PROP_GAIN_I: //only one gain for I and Q case CODEC_PROP_GAIN_Q: UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = _codec_ctrl->get_tx_pga_gain(); + val = _codec_ctrls[dboard_slot]->get_tx_pga_gain(); return; default: UHD_THROW_PROP_GET_ERROR(); } } -void usrp1_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val) +void usrp1_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val, dboard_slot_t dboard_slot) { named_prop_t key = named_prop_t::extract(key_); @@ -145,7 +149,7 @@ void usrp1_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val) case CODEC_PROP_GAIN_I: //only one gain for I and Q case CODEC_PROP_GAIN_Q: UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - _codec_ctrl->set_tx_pga_gain(val.as()); + _codec_ctrls[dboard_slot]->set_tx_pga_gain(val.as()); return; default: UHD_THROW_PROP_SET_ERROR(); diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp index ef6a1e67b..82ef9e65b 100644 --- a/host/lib/usrp/usrp1/dboard_iface.cpp +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -16,6 +16,7 @@ // #include "usrp1_iface.hpp" +#include "usrp1_impl.hpp" #include "fpga_regs_common.h" #include "usrp_spi_defs.h" #include "clock_ctrl.hpp" @@ -30,16 +31,27 @@ using namespace uhd; using namespace uhd::usrp; using namespace boost::assign; +/*********************************************************************** + * TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO + * TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO + * TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO + * TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO + * + * check the _dboard_slot and handle conditionally... + **********************************************************************/ + class usrp1_dboard_iface : public dboard_iface { public: usrp1_dboard_iface(usrp1_iface::sptr iface, usrp1_clock_ctrl::sptr clock, - usrp1_codec_ctrl::sptr codec) - { + usrp1_codec_ctrl::sptr codec, + usrp1_impl::dboard_slot_t dboard_slot + ){ _iface = iface; _clock = clock; _codec = codec; + _dboard_slot = dboard_slot; //init the clock rate shadows this->set_clock_rate(UNIT_RX, _clock->get_master_clock_freq()); @@ -55,7 +67,7 @@ public: { special_props_t props; props.soft_clock_divider = true; - props.mangle_i2c_addrs = false; //TODO true on side B + props.mangle_i2c_addrs = (_dboard_slot == usrp1_impl::DBOARD_SLOT_B); return props; } @@ -91,16 +103,18 @@ private: usrp1_clock_ctrl::sptr _clock; usrp1_codec_ctrl::sptr _codec; uhd::dict _clock_rates; + usrp1_impl::dboard_slot_t _dboard_slot; }; /*********************************************************************** * Make Function **********************************************************************/ -dboard_iface::sptr make_usrp1_dboard_iface(usrp1_iface::sptr iface, +dboard_iface::sptr usrp1_impl::make_dboard_iface(usrp1_iface::sptr iface, usrp1_clock_ctrl::sptr clock, - usrp1_codec_ctrl::sptr codec) -{ - return dboard_iface::sptr(new usrp1_dboard_iface(iface, clock, codec)); + usrp1_codec_ctrl::sptr codec, + usrp1_impl::dboard_slot_t dboard_slot +){ + return dboard_iface::sptr(new usrp1_dboard_iface(iface, clock, codec, dboard_slot)); } /*********************************************************************** diff --git a/host/lib/usrp/usrp1/dboard_impl.cpp b/host/lib/usrp/usrp1/dboard_impl.cpp index 9df87432d..ba826d2f5 100644 --- a/host/lib/usrp/usrp1/dboard_impl.cpp +++ b/host/lib/usrp/usrp1/dboard_impl.cpp @@ -23,96 +23,107 @@ #include #include #include +#include +#include #include using namespace uhd; using namespace uhd::usrp; /*********************************************************************** - * Dboard Initialization + * Helper Functions **********************************************************************/ -void usrp1_impl::dboard_init(void) -{ - _rx_db_eeprom = dboard_eeprom_t( - _iface->read_eeprom(I2C_ADDR_RX_A, 0, dboard_eeprom_t::num_bytes())); - - _tx_db_eeprom = dboard_eeprom_t( - _iface->read_eeprom(I2C_ADDR_TX_A, 0, dboard_eeprom_t::num_bytes())); - - - //create a new dboard interface and manager - _dboard_iface = make_usrp1_dboard_iface(_iface, _clock_ctrl, _codec_ctrl); - - _dboard_manager = dboard_manager::make(_rx_db_eeprom.id, - _tx_db_eeprom.id, - _dboard_iface); - - //setup the dboard proxies - _rx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp1_impl::rx_dboard_get, this, _1, _2), - boost::bind(&usrp1_impl::rx_dboard_set, this, _1, _2)); - - _tx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp1_impl::tx_dboard_get, this, _1, _2), - boost::bind(&usrp1_impl::tx_dboard_set, this, _1, _2)); +static boost::uint8_t get_rx_ee_addr(usrp1_impl::dboard_slot_t dboard_slot){ + switch(dboard_slot){ + case usrp1_impl::DBOARD_SLOT_A: return I2C_ADDR_RX_A; + case usrp1_impl::DBOARD_SLOT_B: return I2C_ADDR_RX_B; + default: UHD_THROW_INVALID_CODE_PATH(); + } +} +static boost::uint8_t get_tx_ee_addr(usrp1_impl::dboard_slot_t dboard_slot){ + switch(dboard_slot){ + case usrp1_impl::DBOARD_SLOT_A: return I2C_ADDR_TX_A; + case usrp1_impl::DBOARD_SLOT_B: return I2C_ADDR_TX_B; + default: UHD_THROW_INVALID_CODE_PATH(); + } } + /*********************************************************************** - * Helper functions + * Dboard Initialization **********************************************************************/ -//static int slot_to_i2c_addr (int slot) -//{ -// switch (slot) { -// case SLOT_TX_A: -// return I2C_ADDR_TX_A; -// case SLOT_RX_A: -// return I2C_ADDR_RX_A; -// case SLOT_TX_B: -// return I2C_ADDR_TX_B; -// case SLOT_RX_B: -// return I2C_ADDR_RX_B; -// default: -// return -1; -// } -//} +void usrp1_impl::dboard_init(void) +{ + BOOST_FOREACH(dboard_slot_t dboard_slot, _dboard_slots){ + + //read the tx and rx dboard eeproms + _rx_db_eeproms[dboard_slot] = dboard_eeprom_t(_iface->read_eeprom( + get_rx_ee_addr(dboard_slot), 0, dboard_eeprom_t::num_bytes() + )); + + _tx_db_eeproms[dboard_slot] = dboard_eeprom_t(_iface->read_eeprom( + get_tx_ee_addr(dboard_slot), 0, dboard_eeprom_t::num_bytes() + )); + + //create a new dboard interface and manager + _dboard_ifaces[dboard_slot] = make_dboard_iface( + _iface, _clock_ctrl, _codec_ctrls[dboard_slot], dboard_slot + ); + + _dboard_managers[dboard_slot] = dboard_manager::make( + _rx_db_eeproms[dboard_slot].id, + _tx_db_eeproms[dboard_slot].id, + _dboard_ifaces[dboard_slot] + ); + + //setup the dboard proxies + _rx_dboard_proxies[dboard_slot] = wax_obj_proxy::make( + boost::bind(&usrp1_impl::rx_dboard_get, this, _1, _2, dboard_slot), + boost::bind(&usrp1_impl::rx_dboard_set, this, _1, _2, dboard_slot)); + + _tx_dboard_proxies[dboard_slot] = wax_obj_proxy::make( + boost::bind(&usrp1_impl::tx_dboard_get, this, _1, _2, dboard_slot), + boost::bind(&usrp1_impl::tx_dboard_set, this, _1, _2, dboard_slot)); + } +} /*********************************************************************** * RX Dboard Get **********************************************************************/ -void usrp1_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val) +void usrp1_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val, dboard_slot_t dboard_slot) { named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as()){ case DBOARD_PROP_NAME: - val = std::string("usrp1 dboard (rx unit)"); + val = str(boost::format("usrp1 dboard (rx unit) - %c") % dboard_slot); return; case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_rx_subdev(key.name); + val = _dboard_managers[dboard_slot]->get_rx_subdev(key.name); return; case DBOARD_PROP_SUBDEV_NAMES: - val = _dboard_manager->get_rx_subdev_names(); + val = _dboard_managers[dboard_slot]->get_rx_subdev_names(); return; case DBOARD_PROP_DBOARD_ID: - val = _rx_db_eeprom.id; + val = _rx_db_eeproms[dboard_slot].id; return; case DBOARD_PROP_DBOARD_IFACE: - val = _dboard_iface; + val = _dboard_ifaces[dboard_slot]; return; case DBOARD_PROP_CODEC: - val = _rx_codec_proxy->get_link(); + val = _rx_codec_proxies[dboard_slot]->get_link(); return; case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group(_dboard_manager->get_rx_subdev(key.name), - _rx_codec_proxy->get_link()); + val = make_gain_group(_dboard_managers[dboard_slot]->get_rx_subdev(key.name), + _rx_codec_proxies[dboard_slot]->get_link()); return; default: UHD_THROW_PROP_GET_ERROR(); @@ -122,13 +133,15 @@ void usrp1_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val) /*********************************************************************** * RX Dboard Set **********************************************************************/ -void usrp1_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val) +void usrp1_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val, dboard_slot_t dboard_slot) { switch(key.as()) { case DBOARD_PROP_DBOARD_ID: - _rx_db_eeprom.id = val.as(); - _iface->write_eeprom(I2C_ADDR_RX_A, 0, - _rx_db_eeprom.get_eeprom_bytes()); + _rx_db_eeproms[dboard_slot].id = val.as(); + _iface->write_eeprom( + get_rx_ee_addr(dboard_slot), 0, + _rx_db_eeproms[dboard_slot].get_eeprom_bytes() + ); return; default: @@ -139,39 +152,39 @@ void usrp1_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val) /*********************************************************************** * TX Dboard Get **********************************************************************/ -void usrp1_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val) +void usrp1_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val, dboard_slot_t dboard_slot) { named_prop_t key = named_prop_t::extract(key_); //handle the get request conditioned on the key switch(key.as()){ case DBOARD_PROP_NAME: - val = std::string("usrp1 dboard (tx unit)"); + val = str(boost::format("usrp1 dboard (tx unit) - %c") % dboard_slot); return; case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_tx_subdev(key.name); + val = _dboard_managers[dboard_slot]->get_tx_subdev(key.name); return; case DBOARD_PROP_SUBDEV_NAMES: - val = _dboard_manager->get_tx_subdev_names(); + val = _dboard_managers[dboard_slot]->get_tx_subdev_names(); return; case DBOARD_PROP_DBOARD_ID: - val = _tx_db_eeprom.id; + val = _tx_db_eeproms[dboard_slot].id; return; case DBOARD_PROP_DBOARD_IFACE: - val = _dboard_iface; + val = _dboard_ifaces[dboard_slot]; return; case DBOARD_PROP_CODEC: - val = _tx_codec_proxy->get_link(); + val = _tx_codec_proxies[dboard_slot]->get_link(); return; case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group(_dboard_manager->get_tx_subdev(key.name), - _tx_codec_proxy->get_link()); + val = make_gain_group(_dboard_managers[dboard_slot]->get_tx_subdev(key.name), + _tx_codec_proxies[dboard_slot]->get_link()); return; default: UHD_THROW_PROP_GET_ERROR(); @@ -181,12 +194,15 @@ void usrp1_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val) /*********************************************************************** * TX Dboard Set **********************************************************************/ -void usrp1_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val) +void usrp1_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val, dboard_slot_t dboard_slot) { switch(key.as()) { case DBOARD_PROP_DBOARD_ID: - _tx_db_eeprom.id = val.as(); - _iface->write_eeprom(I2C_ADDR_TX_A, 0, _tx_db_eeprom.get_eeprom_bytes()); + _tx_db_eeproms[dboard_slot].id = val.as(); + _iface->write_eeprom( + get_tx_ee_addr(dboard_slot), 0, + _tx_db_eeproms[dboard_slot].get_eeprom_bytes() + ); return; default: UHD_THROW_PROP_SET_ERROR(); diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp index e9900131f..1a8993a01 100644 --- a/host/lib/usrp/usrp1/dsp_impl.cpp +++ b/host/lib/usrp/usrp1/dsp_impl.cpp @@ -29,19 +29,19 @@ using namespace uhd::usrp; /*********************************************************************** * RX DDC Initialization **********************************************************************/ -void usrp1_impl::rx_ddc_init(void) +void usrp1_impl::rx_dsp_init(void) { - _rx_ddc_proxy = wax_obj_proxy::make( - boost::bind(&usrp1_impl::rx_ddc_get, this, _1, _2), - boost::bind(&usrp1_impl::rx_ddc_set, this, _1, _2)); + _rx_dsp_proxy = wax_obj_proxy::make( + boost::bind(&usrp1_impl::rx_dsp_get, this, _1, _2), + boost::bind(&usrp1_impl::rx_dsp_set, this, _1, _2)); - rx_ddc_set(DSP_PROP_HOST_RATE, double(64e6/10)); + rx_dsp_set(DSP_PROP_HOST_RATE, double(64e6/10)); //FIXME magic number } /*********************************************************************** * RX DDC Get **********************************************************************/ -void usrp1_impl::rx_ddc_get(const wax::obj &key, wax::obj &val) +void usrp1_impl::rx_dsp_get(const wax::obj &key, wax::obj &val) { switch(key.as()){ case DSP_PROP_NAME: @@ -53,7 +53,7 @@ void usrp1_impl::rx_ddc_get(const wax::obj &key, wax::obj &val) return; case DSP_PROP_FREQ_SHIFT: - val = _ddc_freq; + val = _rx_dsp_freq; return; case DSP_PROP_CODEC_RATE: @@ -61,7 +61,7 @@ void usrp1_impl::rx_ddc_get(const wax::obj &key, wax::obj &val) return; case DSP_PROP_HOST_RATE: - val = _clock_ctrl->get_master_clock_freq()/_ddc_decim; + val = _clock_ctrl->get_master_clock_freq()/_rx_dsp_decim; return; default: UHD_THROW_PROP_GET_ERROR(); @@ -90,13 +90,13 @@ unsigned int compute_freq_word(double master, double target) return (unsigned int) v; } -void usrp1_impl::rx_ddc_set(const wax::obj &key, const wax::obj &val) +void usrp1_impl::rx_dsp_set(const wax::obj &key, const wax::obj &val) { switch(key.as()) { case DSP_PROP_FREQ_SHIFT: { double new_freq = val.as(); - _iface->poke32(FR_RX_FREQ_0, compute_freq_word(64e6, new_freq)); - _ddc_freq = new_freq; + _iface->poke32(FR_RX_FREQ_0, compute_freq_word(64e6, new_freq)); //FIXME magic rate + _tx_dsp_freq = new_freq; return; } case DSP_PROP_HOST_RATE: { @@ -110,8 +110,8 @@ void usrp1_impl::rx_ddc_set(const wax::obj &key, const wax::obj &val) return; } - _ddc_decim = rate; - _iface->poke32(FR_DECIM_RATE, _ddc_decim/2 - 1); + _rx_dsp_decim = rate; + _iface->poke32(FR_DECIM_RATE, _rx_dsp_decim/2 - 1); } return; @@ -123,20 +123,20 @@ void usrp1_impl::rx_ddc_set(const wax::obj &key, const wax::obj &val) /*********************************************************************** * TX DUC Initialization **********************************************************************/ -void usrp1_impl::tx_duc_init(void) +void usrp1_impl::tx_dsp_init(void) { - _tx_duc_proxy = wax_obj_proxy::make( - boost::bind(&usrp1_impl::tx_duc_get, this, _1, _2), - boost::bind(&usrp1_impl::tx_duc_set, this, _1, _2)); + _tx_dsp_proxy = wax_obj_proxy::make( + boost::bind(&usrp1_impl::tx_dsp_get, this, _1, _2), + boost::bind(&usrp1_impl::tx_dsp_set, this, _1, _2)); //initial config and update - tx_duc_set(DSP_PROP_HOST_RATE, double(64e6/10)); + tx_dsp_set(DSP_PROP_HOST_RATE, double(64e6/10)); //FIXME magic number } /*********************************************************************** * TX DUC Get **********************************************************************/ -void usrp1_impl::tx_duc_get(const wax::obj &key, wax::obj &val) +void usrp1_impl::tx_dsp_get(const wax::obj &key, wax::obj &val) { switch(key.as()) { case DSP_PROP_NAME: @@ -148,7 +148,7 @@ void usrp1_impl::tx_duc_get(const wax::obj &key, wax::obj &val) return; case DSP_PROP_FREQ_SHIFT: - val = _duc_freq; + val = _tx_dsp_freq; return; case DSP_PROP_CODEC_RATE: @@ -156,7 +156,7 @@ void usrp1_impl::tx_duc_get(const wax::obj &key, wax::obj &val) return; case DSP_PROP_HOST_RATE: - val = _clock_ctrl->get_master_clock_freq() * 2 / _duc_interp; + val = _clock_ctrl->get_master_clock_freq() * 2 / _tx_dsp_interp; return; default: UHD_THROW_PROP_GET_ERROR(); @@ -167,16 +167,19 @@ void usrp1_impl::tx_duc_get(const wax::obj &key, wax::obj &val) /*********************************************************************** * TX DUC Set **********************************************************************/ -void usrp1_impl::tx_duc_set(const wax::obj &key, const wax::obj &val) +void usrp1_impl::tx_dsp_set(const wax::obj &key, const wax::obj &val) { switch(key.as()) { case DSP_PROP_FREQ_SHIFT: { double new_freq = val.as(); - _codec_ctrl->set_duc_freq(new_freq); - _duc_freq = new_freq; + _codec_ctrls[DBOARD_SLOT_A]->set_duc_freq(new_freq); + _tx_dsp_freq = new_freq; return; } + + //TODO freq prop secondary: DBOARD_SLOT_B codec... + case DSP_PROP_HOST_RATE: { unsigned int rate = _clock_ctrl->get_master_clock_freq() * 2 / val.as(); @@ -187,8 +190,8 @@ void usrp1_impl::tx_duc_set(const wax::obj &key, const wax::obj &val) return; } - _duc_interp = rate; - _iface->poke32(FR_INTERP_RATE, _duc_interp / 4 - 1); + _tx_dsp_interp = rate; + _iface->poke32(FR_INTERP_RATE, _tx_dsp_interp / 4 - 1); return; } default: UHD_THROW_PROP_SET_ERROR(); diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index 2514072e0..e0a7fefb1 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -19,6 +19,7 @@ #include "usrp_commands.h" #include #include +#include #include #include @@ -109,6 +110,8 @@ void usrp1_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd) /*********************************************************************** * Mboard Get **********************************************************************/ +static prop_names_t dboard_names = boost::assign::list_of("A")("B"); + void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) { named_prop_t key = named_prop_t::extract(key_); @@ -124,26 +127,28 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) return; case MBOARD_PROP_RX_DBOARD: - UHD_ASSERT_THROW(key.name == ""); - val = _rx_dboard_proxy->get_link(); + uhd::assert_has(dboard_names, key.name, "dboard name"); + if (key.name == "A") val = _rx_dboard_proxies[DBOARD_SLOT_A]->get_link(); + if (key.name == "B") val = _rx_dboard_proxies[DBOARD_SLOT_B]->get_link(); return; case MBOARD_PROP_RX_DBOARD_NAMES: - val = prop_names_t(1, ""); //vector of size 1 with empty string + val = dboard_names; return; case MBOARD_PROP_TX_DBOARD: - UHD_ASSERT_THROW(key.name == ""); - val = _tx_dboard_proxy->get_link(); + uhd::assert_has(dboard_names, key.name, "dboard name"); + if (key.name == "A") val = _tx_dboard_proxies[DBOARD_SLOT_A]->get_link(); + if (key.name == "B") val = _tx_dboard_proxies[DBOARD_SLOT_B]->get_link(); return; case MBOARD_PROP_TX_DBOARD_NAMES: - val = prop_names_t(1, ""); //vector of size 1 with empty string + val = dboard_names; return; case MBOARD_PROP_RX_DSP: UHD_ASSERT_THROW(key.name == ""); - val = _rx_ddc_proxy->get_link(); + val = _rx_dsp_proxy->get_link(); return; case MBOARD_PROP_RX_DSP_NAMES: @@ -152,7 +157,7 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) case MBOARD_PROP_TX_DSP: UHD_ASSERT_THROW(key.name == ""); - val = _tx_duc_proxy->get_link(); + val = _tx_dsp_proxy->get_link(); return; case MBOARD_PROP_TX_DSP_NAMES: diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 1435b981c..ece5f1dea 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -18,11 +18,13 @@ #include "usrp1_impl.hpp" #include "usrp1_ctrl.hpp" #include "fpga_regs_standard.h" +#include "usrp_spi_defs.h" #include #include #include #include #include +#include #include #include @@ -30,6 +32,10 @@ using namespace uhd; using namespace uhd::usrp; using namespace uhd::transport; +const std::vector usrp1_impl::_dboard_slots = boost::assign::list_of + (usrp1_impl::DBOARD_SLOT_A)(usrp1_impl::DBOARD_SLOT_B) +; + /*********************************************************************** * Discovery **********************************************************************/ @@ -132,7 +138,8 @@ usrp1_impl::usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport, _clock_ctrl = usrp1_clock_ctrl::make(_iface); //create codec interface - _codec_ctrl = usrp1_codec_ctrl::make(_iface); + _codec_ctrls[DBOARD_SLOT_A] = usrp1_codec_ctrl::make(_iface, SPI_ENABLE_CODEC_A); + _codec_ctrls[DBOARD_SLOT_B] = usrp1_codec_ctrl::make(_iface, SPI_ENABLE_CODEC_B); //initialize the codecs codec_init(); @@ -144,10 +151,10 @@ usrp1_impl::usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport, dboard_init(); //initialize the dsps - rx_ddc_init(); + rx_dsp_init(); //initialize the dsps - tx_duc_init(); + tx_dsp_init(); //initialize the send/recv io_init(); diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index 5abc37c7f..84ec26827 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -21,6 +21,7 @@ #include "codec_ctrl.hpp" #include #include +#include #include #include #include @@ -33,17 +34,6 @@ static const double MASTER_CLOCK_RATE = 64e6; //TODO get from clock control -/*! - * Make a usrp1 dboard interface. - * \param iface the usrp1 interface object - * \param clock the clock control interface - * \param codec the codec control interface - * \return a sptr to a new dboard interface - */ -uhd::usrp::dboard_iface::sptr make_usrp1_dboard_iface(usrp1_iface::sptr iface, - usrp1_clock_ctrl::sptr clock, - usrp1_codec_ctrl::sptr codec); - /*! * Simple wax obj proxy class: * Provides a wax obj interface for a set and a get function. @@ -75,6 +65,14 @@ private: */ class usrp1_impl : public uhd::device { public: + //! used everywhere to differentiate slots/sides... + enum dboard_slot_t{ + DBOARD_SLOT_A = 'A', + DBOARD_SLOT_B = 'B' + }; + //and a way to enumerate through a list of the above... + static const std::vector _dboard_slots; + //structors usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport, usrp_ctrl::sptr ctrl_transport); @@ -97,9 +95,27 @@ public: size_t get_max_send_samps_per_packet(void) const { return 0; } size_t get_max_recv_samps_per_packet(void) const { return 0; } - bool recv_async_msg(uhd::async_metadata_t &, size_t) { return true; } + bool recv_async_msg(uhd::async_metadata_t &, size_t) { + //TODO sleep the number of ms supplied (dont want to hog CPU) + return false; + } private: + /*! + * Make a usrp1 dboard interface. + * \param iface the usrp1 interface object + * \param clock the clock control interface + * \param codec the codec control interface + * \param dboard_slot the slot identifier + * \return a sptr to a new dboard interface + */ + static uhd::usrp::dboard_iface::sptr make_dboard_iface( + usrp1_iface::sptr iface, + usrp1_clock_ctrl::sptr clock, + usrp1_codec_ctrl::sptr codec, + dboard_slot_t dboard_slot + ); + //interface to ioctls and file descriptor usrp1_iface::sptr _iface; @@ -120,16 +136,15 @@ private: usrp1_clock_ctrl::sptr _clock_ctrl; //ad9862 codec control interface - usrp1_codec_ctrl::sptr _codec_ctrl; + uhd::dict _codec_ctrls; //codec properties interfaces void codec_init(void); - void rx_codec_get(const wax::obj &, wax::obj &); - void rx_codec_set(const wax::obj &, const wax::obj &); - void tx_codec_get(const wax::obj &, wax::obj &); - void tx_codec_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _rx_codec_proxy; - wax_obj_proxy::sptr _tx_codec_proxy; + void rx_codec_get(const wax::obj &, wax::obj &, dboard_slot_t); + void rx_codec_set(const wax::obj &, const wax::obj &, dboard_slot_t); + void tx_codec_get(const wax::obj &, wax::obj &, dboard_slot_t); + void tx_codec_set(const wax::obj &, const wax::obj &, dboard_slot_t); + uhd::dict _rx_codec_proxies, _tx_codec_proxies; //device functions and settings void get(const wax::obj &, wax::obj &); @@ -143,36 +158,34 @@ private: //xx dboard functions and settings void dboard_init(void); - uhd::usrp::dboard_manager::sptr _dboard_manager; - uhd::usrp::dboard_iface::sptr _dboard_iface; + uhd::dict _dboard_managers; + uhd::dict _dboard_ifaces; //rx dboard functions and settings - uhd::usrp::dboard_eeprom_t _rx_db_eeprom; - void rx_dboard_get(const wax::obj &, wax::obj &); - void rx_dboard_set(const wax::obj &, const wax::obj &); - uhd::prop_names_t _rx_subdevs_in_use; - wax_obj_proxy::sptr _rx_dboard_proxy; + uhd::dict _rx_db_eeproms; + void rx_dboard_get(const wax::obj &, wax::obj &, dboard_slot_t); + void rx_dboard_set(const wax::obj &, const wax::obj &, dboard_slot_t); + uhd::dict _rx_dboard_proxies; //tx dboard functions and settings - uhd::usrp::dboard_eeprom_t _tx_db_eeprom; - void tx_dboard_get(const wax::obj &, wax::obj &); - void tx_dboard_set(const wax::obj &, const wax::obj &); - uhd::prop_names_t _tx_subdevs_in_use; - wax_obj_proxy::sptr _tx_dboard_proxy; - - //rx ddc functions and settings - void rx_ddc_init(void); - void rx_ddc_get(const wax::obj &, wax::obj &); - void rx_ddc_set(const wax::obj &, const wax::obj &); - double _ddc_freq; size_t _ddc_decim; - wax_obj_proxy::sptr _rx_ddc_proxy; - - //tx duc functions and settings - void tx_duc_init(void); - void tx_duc_get(const wax::obj &, wax::obj &); - void tx_duc_set(const wax::obj &, const wax::obj &); - double _duc_freq; size_t _duc_interp; - wax_obj_proxy::sptr _tx_duc_proxy; + uhd::dict _tx_db_eeproms; + void tx_dboard_get(const wax::obj &, wax::obj &, dboard_slot_t); + void tx_dboard_set(const wax::obj &, const wax::obj &, dboard_slot_t); + uhd::dict _tx_dboard_proxies; + + //rx dsp functions and settings + void rx_dsp_init(void); + void rx_dsp_get(const wax::obj &, wax::obj &); + void rx_dsp_set(const wax::obj &, const wax::obj &); + double _rx_dsp_freq; size_t _rx_dsp_decim; + wax_obj_proxy::sptr _rx_dsp_proxy; + + //tx dsp functions and settings + void tx_dsp_init(void); + void tx_dsp_get(const wax::obj &, wax::obj &); + void tx_dsp_set(const wax::obj &, const wax::obj &); + double _tx_dsp_freq; size_t _tx_dsp_interp; + wax_obj_proxy::sptr _tx_dsp_proxy; //transports uhd::transport::usb_zero_copy::sptr _data_transport; -- cgit v1.2.3 From e7d4233a94571a2479b21bc081567214c38cc155 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 15 Aug 2010 19:12:41 -0700 Subject: usrp1: add skeleton code for setting subdev spec --- host/lib/usrp/usrp1/dboard_iface.cpp | 3 ++- host/lib/usrp/usrp1/mboard_impl.cpp | 33 +++++++++++++++++++++++++++++++-- host/lib/usrp/usrp1/usrp1_impl.hpp | 2 ++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp index 82ef9e65b..142907e57 100644 --- a/host/lib/usrp/usrp1/dboard_iface.cpp +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -112,7 +112,7 @@ private: dboard_iface::sptr usrp1_impl::make_dboard_iface(usrp1_iface::sptr iface, usrp1_clock_ctrl::sptr clock, usrp1_codec_ctrl::sptr codec, - usrp1_impl::dboard_slot_t dboard_slot + dboard_slot_t dboard_slot ){ return dboard_iface::sptr(new usrp1_dboard_iface(iface, clock, codec, dboard_slot)); } @@ -221,6 +221,7 @@ void usrp1_dboard_iface::set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value) { if ((atr == ATR_REG_IDLE) || (atr == ATR_REG_FULL_DUPLEX)) { + //TODO probably just ignore these two atr settings because all dboards will try to set them std::cerr << "error: set_atr_reg(): unsupported state" << std::endl; return; } diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index e0a7fefb1..5e0285dfd 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -17,6 +17,7 @@ #include "usrp1_impl.hpp" #include "usrp_commands.h" +#include "../misc_utils.hpp" #include #include #include @@ -168,6 +169,14 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) val = _clock_config; return; + case MBOARD_PROP_RX_SUBDEV_SPEC: + val = _rx_subdev_spec; + return; + + case MBOARD_PROP_TX_SUBDEV_SPEC: + val = _tx_subdev_spec; + return; + default: UHD_THROW_PROP_GET_ERROR(); } } @@ -184,8 +193,28 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val) issue_stream_cmd(val.as()); return; - case MBOARD_PROP_TIME_NOW: - case MBOARD_PROP_TIME_NEXT_PPS: + case MBOARD_PROP_RX_SUBDEV_SPEC: + _rx_subdev_spec = val.as(); + verify_rx_subdev_spec(_rx_subdev_spec, this->get_link()); + //sanity check + UHD_ASSERT_THROW(_rx_subdev_spec.size() <= 2); + //set the mux and set the number of rx channels + //-------------------------------------------------- + // TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO + //-------------------------------------------------- + return; + + case MBOARD_PROP_TX_SUBDEV_SPEC: + _tx_subdev_spec = val.as(); + verify_tx_subdev_spec(_tx_subdev_spec, this->get_link()); + //sanity check + UHD_ASSERT_THROW(_tx_subdev_spec.size() <= 2); + //set the mux and set the number of tx channels + //-------------------------------------------------- + // TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO + //-------------------------------------------------- + return; + default: UHD_THROW_PROP_SET_ERROR(); } } diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index 84ec26827..5166f989f 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -131,6 +132,7 @@ private: //configuration shadows uhd::clock_config_t _clock_config; + uhd::usrp::subdev_spec_t _rx_subdev_spec, _tx_subdev_spec; //clock control usrp1_clock_ctrl::sptr _clock_ctrl; -- cgit v1.2.3 From 564bfee0389d0274e7cd128d61dcbe50ca6a6cdd Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 16 Aug 2010 00:09:47 -0700 Subject: usrp1: compiling with the latest next --- host/lib/usrp/usrp1/dboard_impl.cpp | 18 ++++++++++++------ host/lib/usrp/usrp1/dsp_impl.cpp | 12 ++++++------ host/lib/usrp/usrp1/mboard_impl.cpp | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/host/lib/usrp/usrp1/dboard_impl.cpp b/host/lib/usrp/usrp1/dboard_impl.cpp index ba826d2f5..c8d9c55dd 100644 --- a/host/lib/usrp/usrp1/dboard_impl.cpp +++ b/host/lib/usrp/usrp1/dboard_impl.cpp @@ -17,8 +17,8 @@ #include "usrp1_impl.hpp" #include "usrp_i2c_addr.h" -#include "../dsp_utils.hpp" -#include "../misc_utils.hpp" +#include +#include #include #include #include @@ -122,8 +122,11 @@ void usrp1_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val, dboard_slot_ return; case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group(_dboard_managers[dboard_slot]->get_rx_subdev(key.name), - _rx_codec_proxies[dboard_slot]->get_link()); + val = make_gain_group( + _dboard_managers[dboard_slot]->get_rx_subdev(key.name), + _rx_codec_proxies[dboard_slot]->get_link(), + GAIN_GROUP_POLICY_RX + ); return; default: UHD_THROW_PROP_GET_ERROR(); @@ -183,8 +186,11 @@ void usrp1_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val, dboard_slot_ return; case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group(_dboard_managers[dboard_slot]->get_tx_subdev(key.name), - _tx_codec_proxies[dboard_slot]->get_link()); + val = make_gain_group( + _dboard_managers[dboard_slot]->get_tx_subdev(key.name), + _tx_codec_proxies[dboard_slot]->get_link(), + GAIN_GROUP_POLICY_TX + ); return; default: UHD_THROW_PROP_GET_ERROR(); diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp index 1a8993a01..260c01ea8 100644 --- a/host/lib/usrp/usrp1/dsp_impl.cpp +++ b/host/lib/usrp/usrp1/dsp_impl.cpp @@ -17,11 +17,12 @@ #include "usrp1_impl.hpp" #include "fpga_regs_standard.h" -#include "../dsp_utils.hpp" +#include #include #include +#include #include -#include +#include using namespace uhd; using namespace uhd::usrp; @@ -82,10 +83,9 @@ unsigned int compute_freq_word(double master, double target) double actual_freq = v * master / pow(2.0, 32.0); - if (0) - fprintf (stderr, - "compute_freq_control_word_fpga: target = %g actual = %g delta = %g\n", - target, actual_freq, actual_freq - target); + if (0) std::cerr << boost::format( + "compute_freq_control_word_fpga: target = %g actual = %g delta = %g\n" + ) % target % actual_freq % (actual_freq - target); return (unsigned int) v; } diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index 5e0285dfd..ede9b2681 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -17,7 +17,7 @@ #include "usrp1_impl.hpp" #include "usrp_commands.h" -#include "../misc_utils.hpp" +#include #include #include #include -- cgit v1.2.3 From acc508a1ee21cf8c6f48f846dad53477c64c10d9 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 16 Aug 2010 18:16:49 -0700 Subject: usrp1: rx and tx mux calculation --- host/lib/usrp/usrp1/mboard_impl.cpp | 113 +++++++++++++++++++++++++++++++++--- 1 file changed, 106 insertions(+), 7 deletions(-) diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index ede9b2681..c3343f1f8 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -17,16 +17,119 @@ #include "usrp1_impl.hpp" #include "usrp_commands.h" +#include "fpga_regs_standard.h" #include -#include #include +#include +#include +#include +#include #include +#include #include #include using namespace uhd; using namespace uhd::usrp; +/*********************************************************************** + * Helper Functions + **********************************************************************/ +static boost::uint32_t calc_rx_mux( + const subdev_spec_t &subdev_spec, wax::obj mboard +){ + //create look-up-table for mapping dboard name and connection type to ADC flags + static const int ADC0 = 0, ADC1 = 1, ADC2 = 2, ADC3 = 3; + static const uhd::dict > name_to_conn_to_flag = boost::assign::map_list_of + ("A", boost::assign::map_list_of + (SUBDEV_CONN_COMPLEX_IQ, (ADC0 << 0) | (ADC1 << 2)) //I and Q + (SUBDEV_CONN_COMPLEX_QI, (ADC1 << 0) | (ADC0 << 2)) //I and Q + (SUBDEV_CONN_REAL_I, (ADC0 << 0) | (ADC0 << 2)) //I and Q (Q identical but ignored Z=1) + (SUBDEV_CONN_REAL_Q, (ADC1 << 0) | (ADC1 << 2)) //I and Q (Q identical but ignored Z=1) + ) + ("B", boost::assign::map_list_of + (SUBDEV_CONN_COMPLEX_IQ, (ADC2 << 0) | (ADC3 << 2)) //I and Q + (SUBDEV_CONN_COMPLEX_QI, (ADC3 << 0) | (ADC2 << 2)) //I and Q + (SUBDEV_CONN_REAL_I, (ADC2 << 0) | (ADC2 << 2)) //I and Q (Q identical but ignored Z=1) + (SUBDEV_CONN_REAL_Q, (ADC3 << 0) | (ADC3 << 2)) //I and Q (Q identical but ignored Z=1) + ) + ; + + //extract the number of channels + size_t nchan = subdev_spec.size(); + + //calculate the channel flags + int channel_flags = 0; + size_t num_reals = 0, num_quads = 0; + BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){ + wax::obj dboard = mboard[named_prop_t(MBOARD_PROP_RX_DBOARD, pair.db_name)]; + wax::obj subdev = dboard[named_prop_t(DBOARD_PROP_SUBDEV, pair.sd_name)]; + subdev_conn_t conn = subdev[SUBDEV_PROP_CONNECTION].as(); + switch(conn){ + case SUBDEV_CONN_COMPLEX_IQ: + case SUBDEV_CONN_COMPLEX_QI: num_quads++; break; + case SUBDEV_CONN_REAL_I: + case SUBDEV_CONN_REAL_Q: num_reals++; break; + } + channel_flags = (channel_flags << 4) | name_to_conn_to_flag[pair.db_name][conn]; + } + + //calculate Z: + // for all real sources: Z = 1 + // for all quadrature sources: Z = 0 + // for mixed sources: warning + Z = 0 + int Z = (num_quads > 0)? 0 : 1; + if (num_quads != 0 and num_reals != 0) uhd::print_warning( + "Mixing real and quadrature rx subdevices is not supported.\n" + "The Q input to the real source(s) will be non-zero.\n" + ); + + //calculate the rx mux value + return ((channel_flags & 0xffff) << 4) | ((Z & 0x1) << 3) | ((nchan & 0x7) << 0); +} + +static boost::uint32_t calc_tx_mux( + const subdev_spec_t &subdev_spec, wax::obj mboard +){ + //create look-up-table for mapping channel number and connection type to flags + static const int ENB = 1 << 3, CHAN_I0 = 0, CHAN_Q0 = 1, CHAN_I1 = 2, CHAN_Q1 = 3; + static const uhd::dict > chan_to_conn_to_flag = boost::assign::map_list_of + (0, boost::assign::map_list_of + (SUBDEV_CONN_COMPLEX_IQ, ((CHAN_I0 | ENB) << 0) | ((CHAN_Q0 | ENB) << 4)) + (SUBDEV_CONN_COMPLEX_QI, ((CHAN_I0 | ENB) << 4) | ((CHAN_Q0 | ENB) << 0)) + (SUBDEV_CONN_REAL_I, ((CHAN_I0 | ENB) << 0)) + (SUBDEV_CONN_REAL_Q, ((CHAN_I0 | ENB) << 4)) + ) + (1, boost::assign::map_list_of + (SUBDEV_CONN_COMPLEX_IQ, ((CHAN_I1 | ENB) << 0) | ((CHAN_Q1 | ENB) << 4)) + (SUBDEV_CONN_COMPLEX_QI, ((CHAN_I1 | ENB) << 4) | ((CHAN_Q1 | ENB) << 0)) + (SUBDEV_CONN_REAL_I, ((CHAN_I1 | ENB) << 0)) + (SUBDEV_CONN_REAL_Q, ((CHAN_I1 | ENB) << 4)) + ) + ; + + //extract the number of channels + size_t nchan = subdev_spec.size(); + + //calculate the channel flags + int channel_flags = 0, chan = 0; + BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){ + wax::obj dboard = mboard[named_prop_t(MBOARD_PROP_RX_DBOARD, pair.db_name)]; + wax::obj subdev = dboard[named_prop_t(DBOARD_PROP_SUBDEV, pair.sd_name)]; + subdev_conn_t conn = subdev[SUBDEV_PROP_CONNECTION].as(); + + //combine the channel flags: shift for slot A vs B + if (pair.db_name == "A") channel_flags |= chan_to_conn_to_flag[chan][conn] << 0; + if (pair.db_name == "B") channel_flags |= chan_to_conn_to_flag[chan][conn] << 8; + + //increment for the next channel + chan++; + } + + //calculate the tx mux value + return ((channel_flags & 0xffff) << 4) | ((nchan & 0x7) << 0); +} + /*********************************************************************** * Mboard Initialization **********************************************************************/ @@ -199,9 +302,7 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val) //sanity check UHD_ASSERT_THROW(_rx_subdev_spec.size() <= 2); //set the mux and set the number of rx channels - //-------------------------------------------------- - // TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO - //-------------------------------------------------- + _iface->poke32(FR_RX_MUX, calc_rx_mux(_rx_subdev_spec, _mboard_proxy->get_link())); return; case MBOARD_PROP_TX_SUBDEV_SPEC: @@ -210,9 +311,7 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val) //sanity check UHD_ASSERT_THROW(_tx_subdev_spec.size() <= 2); //set the mux and set the number of tx channels - //-------------------------------------------------- - // TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO - //-------------------------------------------------- + _iface->poke32(FR_TX_MUX, calc_tx_mux(_tx_subdev_spec, _mboard_proxy->get_link())); return; default: UHD_THROW_PROP_SET_ERROR(); -- cgit v1.2.3 From df74cfa4ad134faeafd9fb97420db8acb227d9af Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Mon, 16 Aug 2010 16:21:13 -0700 Subject: usrp1: Setup dboard interface duality --- host/lib/usrp/usrp1/dboard_iface.cpp | 105 +++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 42 deletions(-) diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp index 142907e57..fe4ebe04c 100644 --- a/host/lib/usrp/usrp1/dboard_iface.cpp +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -31,15 +31,6 @@ using namespace uhd; using namespace uhd::usrp; using namespace boost::assign; -/*********************************************************************** - * TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO - * TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO - * TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO - * TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO - * - * check the _dboard_slot and handle conditionally... - **********************************************************************/ - class usrp1_dboard_iface : public dboard_iface { public: @@ -161,13 +152,17 @@ void usrp1_dboard_iface::set_pin_ctrl(unit_t unit, boost::uint16_t value) { switch(unit) { case UNIT_RX: - _iface->poke32(FR_ATR_MASK_1, value); - _iface->poke32(FR_ATR_MASK_3, 0x00000000); - break; + if (_dboard_slot == usrp1_impl::DBOARD_SLOT_A) + _iface->poke32(FR_ATR_MASK_1, value); + else if (_dboard_slot == usrp1_impl::DBOARD_SLOT_B) + _iface->poke32(FR_ATR_MASK_3, value); + break; case UNIT_TX: - _iface->poke32(FR_ATR_MASK_0, value); - _iface->poke32(FR_ATR_MASK_2, 0x00000000); - break; + if (_dboard_slot == usrp1_impl::DBOARD_SLOT_A) + _iface->poke32(FR_ATR_MASK_0, value); + else if (_dboard_slot == usrp1_impl::DBOARD_SLOT_B) + _iface->poke32(FR_ATR_MASK_2, value); + break; } } @@ -175,12 +170,16 @@ void usrp1_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value) { switch(unit) { case UNIT_RX: - _iface->poke32(FR_OE_1, 0xffff0000 | value); - _iface->poke32(FR_OE_3, 0xffff0000); - break; + if (_dboard_slot == usrp1_impl::DBOARD_SLOT_A) + _iface->poke32(FR_OE_1, 0xffff0000 | value); + else if (_dboard_slot == usrp1_impl::DBOARD_SLOT_B) + _iface->poke32(FR_OE_3, 0xffff0000 | value); + break; case UNIT_TX: - _iface->poke32(FR_OE_0, 0xffff0000 | value); - _iface->poke32(FR_OE_2, 0xffff0000); + if (_dboard_slot == usrp1_impl::DBOARD_SLOT_A) + _iface->poke32(FR_OE_0, 0xffff0000 | value); + else if (_dboard_slot == usrp1_impl::DBOARD_SLOT_B) + _iface->poke32(FR_OE_2, 0xffff0000 | value); break; } } @@ -189,10 +188,16 @@ void usrp1_dboard_iface::write_gpio(unit_t unit, boost::uint16_t value) { switch(unit) { case UNIT_RX: - _iface->poke32(FR_IO_1, 0xffff0000 | value); + if (_dboard_slot == usrp1_impl::DBOARD_SLOT_A) + _iface->poke32(FR_IO_1, 0xffff0000 | value); + else if (_dboard_slot == usrp1_impl::DBOARD_SLOT_B) + _iface->poke32(FR_IO_3, 0xffff0000 | value); break; case UNIT_TX: - _iface->poke32(FR_IO_0, 0xffff0000 | value); + if (_dboard_slot == usrp1_impl::DBOARD_SLOT_A) + _iface->poke32(FR_IO_0, 0xffff0000 | value); + else if (_dboard_slot == usrp1_impl::DBOARD_SLOT_B) + _iface->poke32(FR_IO_2, 0xffff0000 | value); break; } } @@ -200,19 +205,19 @@ void usrp1_dboard_iface::write_gpio(unit_t unit, boost::uint16_t value) boost::uint16_t usrp1_dboard_iface::read_gpio(unit_t unit) { boost::uint32_t out_value; - boost::uint16_t ret_value; + + if (_dboard_slot == usrp1_impl::DBOARD_SLOT_A) + out_value = _iface->peek32(1); + else if (_dboard_slot == usrp1_impl::DBOARD_SLOT_B) + out_value = _iface->peek32(2); + else + UHD_THROW_INVALID_CODE_PATH(); switch(unit) { case UNIT_RX: - //magic - out_value = _iface->peek32(1); - ret_value = (out_value >> 16) & 0x0000ffff; - return ret_value; + return (boost::uint16_t)((out_value >> 16) & 0x0000ffff); case UNIT_TX: - //magic - out_value = _iface->peek32(1); - ret_value = (out_value >> 0) & 0x0000ffff; - return ret_value; + return (boost::uint16_t)((out_value >> 0) & 0x0000ffff); } UHD_ASSERT_THROW(false); } @@ -228,13 +233,16 @@ void usrp1_dboard_iface::set_atr_reg(unit_t unit, switch(unit) { case UNIT_RX: - _iface->poke32(FR_ATR_RXVAL_1, value); - _iface->poke32(FR_ATR_RXVAL_3, 0x0000); + if (_dboard_slot == usrp1_impl::DBOARD_SLOT_A) + _iface->poke32(FR_ATR_RXVAL_1, value); + else if (_dboard_slot == usrp1_impl::DBOARD_SLOT_B) + _iface->poke32(FR_ATR_RXVAL_3, value); break; case UNIT_TX: - //_iface->poke32(FR_ATR_TXVAL_0, value); - _iface->poke32(FR_ATR_TXVAL_0, 0x0000); - _iface->poke32(FR_ATR_TXVAL_2, 0x0000); + if (_dboard_slot == usrp1_impl::DBOARD_SLOT_A) + _iface->poke32(FR_ATR_TXVAL_0, value); + else if (_dboard_slot == usrp1_impl::DBOARD_SLOT_B) + _iface->poke32(FR_ATR_TXVAL_2, value); break; } } @@ -244,16 +252,29 @@ void usrp1_dboard_iface::set_atr_reg(unit_t unit, /*! * Static function to convert a unit type to a spi slave device number. * \param unit the dboard interface unit type enum + * \param slot the side (A or B) the dboard is attached * \return the slave device number */ -static boost::uint32_t unit_to_otw_spi_dev(dboard_iface::unit_t unit) +static boost::uint32_t unit_to_otw_spi_dev(dboard_iface::unit_t unit, + usrp1_impl::dboard_slot_t slot) { switch(unit) { - case dboard_iface::UNIT_TX: return SPI_ENABLE_TX_A; - case dboard_iface::UNIT_RX: return SPI_ENABLE_RX_A; + case dboard_iface::UNIT_TX: + if (slot == usrp1_impl::DBOARD_SLOT_A) + return SPI_ENABLE_TX_A; + else if (slot == usrp1_impl::DBOARD_SLOT_B) + return SPI_ENABLE_TX_B; + else + break; + case dboard_iface::UNIT_RX: + if (slot == usrp1_impl::DBOARD_SLOT_A) + return SPI_ENABLE_RX_A; + else if (slot == usrp1_impl::DBOARD_SLOT_B) + return SPI_ENABLE_RX_B; + else + break; } throw std::invalid_argument("unknown unit type"); - } void usrp1_dboard_iface::write_spi(unit_t unit, @@ -261,7 +282,7 @@ void usrp1_dboard_iface::write_spi(unit_t unit, boost::uint32_t data, size_t num_bits) { - _iface->transact_spi(unit_to_otw_spi_dev(unit), + _iface->transact_spi(unit_to_otw_spi_dev(unit, _dboard_slot), config, data, num_bits, false); } @@ -270,7 +291,7 @@ boost::uint32_t usrp1_dboard_iface::read_write_spi(unit_t unit, boost::uint32_t data, size_t num_bits) { - return _iface->transact_spi(unit_to_otw_spi_dev(unit), + return _iface->transact_spi(unit_to_otw_spi_dev(unit, _dboard_slot), config, data, num_bits, true); } -- cgit v1.2.3 From cc6bbf949f8e4eabefdccf8d8cc4d9ed803ce40e Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Mon, 16 Aug 2010 16:31:48 -0700 Subject: usrp1: Remove error message for unsupported ATR registers --- host/lib/usrp/usrp1/dboard_iface.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp index fe4ebe04c..f6fbab033 100644 --- a/host/lib/usrp/usrp1/dboard_iface.cpp +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -225,11 +225,9 @@ boost::uint16_t usrp1_dboard_iface::read_gpio(unit_t unit) void usrp1_dboard_iface::set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value) { - if ((atr == ATR_REG_IDLE) || (atr == ATR_REG_FULL_DUPLEX)) { - //TODO probably just ignore these two atr settings because all dboards will try to set them - std::cerr << "error: set_atr_reg(): unsupported state" << std::endl; + // Ignore unsupported states + if ((atr == ATR_REG_IDLE) || (atr == ATR_REG_FULL_DUPLEX)) return; - } switch(unit) { case UNIT_RX: -- cgit v1.2.3 From 43e5480dee9f6068ffe84bf1b86526189043ee87 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Mon, 16 Aug 2010 17:03:06 -0700 Subject: usrp1: Remove hard coded clock values Get clock values from clock control, where the master setting lives. --- host/lib/usrp/usrp1/dsp_impl.cpp | 10 ++++++---- host/lib/usrp/usrp1/usrp1_impl.hpp | 2 -- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp index 260c01ea8..0db3cb473 100644 --- a/host/lib/usrp/usrp1/dsp_impl.cpp +++ b/host/lib/usrp/usrp1/dsp_impl.cpp @@ -36,7 +36,7 @@ void usrp1_impl::rx_dsp_init(void) boost::bind(&usrp1_impl::rx_dsp_get, this, _1, _2), boost::bind(&usrp1_impl::rx_dsp_set, this, _1, _2)); - rx_dsp_set(DSP_PROP_HOST_RATE, double(64e6/10)); //FIXME magic number + rx_dsp_set(DSP_PROP_HOST_RATE, _clock_ctrl->get_master_clock_freq() / 16); } /*********************************************************************** @@ -95,7 +95,9 @@ void usrp1_impl::rx_dsp_set(const wax::obj &key, const wax::obj &val) switch(key.as()) { case DSP_PROP_FREQ_SHIFT: { double new_freq = val.as(); - _iface->poke32(FR_RX_FREQ_0, compute_freq_word(64e6, new_freq)); //FIXME magic rate + boost::uint32_t hw_freq_word = compute_freq_word( + _clock_ctrl->get_master_clock_freq(), new_freq); + _iface->poke32(FR_RX_FREQ_0, hw_freq_word); _tx_dsp_freq = new_freq; return; } @@ -130,7 +132,7 @@ void usrp1_impl::tx_dsp_init(void) boost::bind(&usrp1_impl::tx_dsp_set, this, _1, _2)); //initial config and update - tx_dsp_set(DSP_PROP_HOST_RATE, double(64e6/10)); //FIXME magic number + tx_dsp_set(DSP_PROP_HOST_RATE, _clock_ctrl->get_master_clock_freq() * 2 / 16); } /*********************************************************************** @@ -152,7 +154,7 @@ void usrp1_impl::tx_dsp_get(const wax::obj &key, wax::obj &val) return; case DSP_PROP_CODEC_RATE: - val = MASTER_CLOCK_RATE; + val = _clock_ctrl->get_master_clock_freq() * 2; return; case DSP_PROP_HOST_RATE: diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index 5166f989f..f57f9a09a 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -33,8 +33,6 @@ #ifndef INCLUDED_USRP1_IMPL_HPP #define INCLUDED_USRP1_IMPL_HPP -static const double MASTER_CLOCK_RATE = 64e6; //TODO get from clock control - /*! * Simple wax obj proxy class: * Provides a wax obj interface for a set and a get function. -- cgit v1.2.3 From e4c12fbfb2a928574b33260f04f9622e3c876700 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Tue, 17 Aug 2010 17:38:23 -0700 Subject: usrp1: Return unknown (0xff) on invalid I2C read This allows a dboard eeprom read to continue when reading from an empty slot. --- host/lib/usrp/usrp1/usrp1_iface.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp index b175ba21f..d228161f1 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.cpp +++ b/host/lib/usrp/usrp1/usrp1_iface.cpp @@ -129,11 +129,7 @@ public: { UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes); - byte_vector_t out_bytes; - byte_vector_t::iterator it = out_bytes.begin(); - unsigned char buff[max_i2c_data_bytes]; - int ret = _ctrl_transport->usrp_control_read(VRQ_I2C_READ, addr & 0xff, 0, @@ -142,9 +138,10 @@ public: if ((ret < 0) || (unsigned)ret < (num_bytes)) { std::cerr << "USRP: failed i2c read: " << ret << std::endl; - return out_bytes; + return byte_vector_t(num_bytes, 0xff); } + byte_vector_t out_bytes; for (size_t i = 0; i < num_bytes; i++) out_bytes.push_back(buff[i]); -- cgit v1.2.3 From 0f2bf7bf709f417e0ef5a0860e18b190f740fd1b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 17 Aug 2010 18:40:17 -0700 Subject: usrp1: added firmware to images makefile and prebuilt fpga images --- images/Makefile | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/images/Makefile b/images/Makefile index 6ab54e6ac..0a829a296 100644 --- a/images/Makefile +++ b/images/Makefile @@ -30,6 +30,30 @@ CMAKE_BUILD_DIR = $(TOP_DIR)/build ##filled in below IMAGES_LIST = +######################################################################## +# USRP1 firmware +######################################################################## +_usrp1_fw_dir = $(TOP_FW_DIR)/fx2 +_usrp1_fw_ihx = $(BUILT_IMAGES_DIR)/usrp1_fw.ihx +IMAGES_LIST += $(_usrp1_fw_ihx) + +$(_usrp1_fw_ihx): + cd $(_usrp1_fw_dir) && ./bootstrap + cd $(_usrp1_fw_dir) && ./configure + make -C $(_usrp1_fw_dir) clean + make -C $(_usrp1_fw_dir) all + cp $(_usrp1_fw_dir)/src/usrp1/std.ihx $@ + +######################################################################## +# USRP1 fpga +######################################################################## +_usrp1_fpga_dir = $(TOP_FPGA_DIR)/usrp1/rbf/rev4 +_usrp1_fpga_rbf = $(BUILT_IMAGES_DIR)/usrp1_fpga.rbf +IMAGES_LIST += $(_usrp1_fpga_rbf) + +$(_usrp1_fpga_rbf): + cp $(_usrp1_fpga_dir)/std_2rxhb_2tx.rbf $@ + ######################################################################## # USRP2 firmware ######################################################################## -- cgit v1.2.3 From 024377afa9628c282a5f7584ca5cc8991dd1296f Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Wed, 18 Aug 2010 11:06:57 -0700 Subject: usrp1: Refactor mboard tuning code --- host/lib/usrp/usrp1/codec_ctrl.cpp | 164 +++++++++++++++++-------------------- host/lib/usrp/usrp1/codec_ctrl.hpp | 8 +- host/lib/usrp/usrp1/dsp_impl.cpp | 26 +----- host/lib/usrp/usrp1/usrp1_impl.cpp | 8 +- 4 files changed, 92 insertions(+), 114 deletions(-) diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index 01617de94..419e4c5e2 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -17,6 +17,7 @@ #include "codec_ctrl.hpp" #include "usrp_commands.h" +#include "clock_ctrl.hpp" #include "ad9862_regs.hpp" #include #include @@ -43,7 +44,9 @@ const gain_range_t usrp1_codec_ctrl::rx_pga_gain_range(0, 20, 1); class usrp1_codec_ctrl_impl : public usrp1_codec_ctrl { public: //structors - usrp1_codec_ctrl_impl(usrp1_iface::sptr iface, int spi_slave); + usrp1_codec_ctrl_impl(usrp1_iface::sptr iface, + usrp1_clock_ctrl::sptr clock, + int spi_slave); ~usrp1_codec_ctrl_impl(void); //aux adc and dac control @@ -51,7 +54,7 @@ public: void write_aux_dac(aux_dac_t which, float volts); //duc control - bool set_duc_freq(double freq); + void set_duc_freq(double freq); //pga gain control void set_tx_pga_gain(float); @@ -61,25 +64,26 @@ public: private: usrp1_iface::sptr _iface; + usrp1_clock_ctrl::sptr _clock_ctrl; int _spi_slave; ad9862_regs_t _ad9862_regs; aux_adc_t _last_aux_adc_a, _last_aux_adc_b; void send_reg(boost::uint8_t addr); void recv_reg(boost::uint8_t addr); - //FIXME: poison - double _tx_freq[4]; - unsigned int compute_freq_control_word_9862 (double master_freq, - double target_freq, - double *actual_freq); + double coarse_tune(double codec_rate, double freq); + double fine_tune(double codec_rate, double freq); }; /*********************************************************************** * Codec Control Structors **********************************************************************/ -usrp1_codec_ctrl_impl::usrp1_codec_ctrl_impl(usrp1_iface::sptr iface, int spi_slave) +usrp1_codec_ctrl_impl::usrp1_codec_ctrl_impl(usrp1_iface::sptr iface, + usrp1_clock_ctrl::sptr clock, + int spi_slave) { _iface = iface; + _clock_ctrl = clock; _spi_slave = spi_slave; //soft reset @@ -324,118 +328,102 @@ void usrp1_codec_ctrl_impl::recv_reg(boost::uint8_t addr) /*********************************************************************** * DUC tuning **********************************************************************/ -unsigned int usrp1_codec_ctrl_impl::compute_freq_control_word_9862( - double master_freq, double target_freq, double *actual_freq) +double usrp1_codec_ctrl_impl::coarse_tune(double codec_rate, double freq) { - double sign = 1.0; - - if (target_freq < 0) - sign = -1.0; - - int v = (int) rint (fabs (target_freq) / master_freq * pow (2.0, 24.0)); - *actual_freq = v * master_freq / pow (2.0, 24.0) * sign; - - std::cout << boost::format( - "compute_freq_control_word_9862: target = %g actual = %g delta = %g v = %8d\n" - ) % target_freq % *actual_freq % (*actual_freq - target_freq) % v; - - return (unsigned int) v; -} + double coarse_freq; -bool usrp1_codec_ctrl_impl::set_duc_freq(double freq) -{ - int channel = 0; - float dac_rate = 128e6; - - double coarse; - - std::cout << "duc_freq: " << freq << std::endl; - - // First coarse frequency - double coarse_freq_1 = dac_rate / 8; - // Second coarse frequency - double coarse_freq_2 = dac_rate / 4; - // Midpoint of [0 , freq1] range + double coarse_freq_1 = codec_rate / 8; + double coarse_freq_2 = codec_rate / 4; double coarse_limit_1 = coarse_freq_1 / 2; - // Midpoint of [freq1 , freq2] range double coarse_limit_2 = (coarse_freq_1 + coarse_freq_2) / 2; - // Highest meaningful frequency - double high_limit = (double) 44e6 / 128e6 * dac_rate; + double max_freq = coarse_freq_2 + .09375 * codec_rate; - if (freq < -high_limit) { // too low + if (freq < -max_freq) { return false; } - else if (freq < -coarse_limit_2) { // For 64MHz: [-44, -24) + else if (freq < -coarse_limit_2) { _ad9862_regs.neg_coarse_tune = ad9862_regs_t::NEG_COARSE_TUNE_NEG_SHIFT; _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_FDAC_4; - coarse = -coarse_freq_2; + coarse_freq = -coarse_freq_2; } - else if (freq < -coarse_limit_1) { // For 64MHz: [-24, -8) + else if (freq < -coarse_limit_1) { _ad9862_regs.neg_coarse_tune = ad9862_regs_t::NEG_COARSE_TUNE_NEG_SHIFT; _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_FDAC_8; - coarse = -coarse_freq_1; + coarse_freq = -coarse_freq_1; } - else if (freq < coarse_limit_1) { // For 64MHz: [-8, 8) + else if (freq < coarse_limit_1) { _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_BYPASS; - coarse = 0; + coarse_freq = 0; } - else if (freq < coarse_limit_2) { // For 64MHz: [8, 24) + else if (freq < coarse_limit_2) { _ad9862_regs.neg_coarse_tune = ad9862_regs_t::NEG_COARSE_TUNE_POS_SHIFT; _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_FDAC_8; - coarse = coarse_freq_1; + coarse_freq = coarse_freq_1; } - else if (freq <= high_limit) { // For 64MHz: [24, 44] + else if (freq <= max_freq) { _ad9862_regs.neg_coarse_tune = ad9862_regs_t::NEG_COARSE_TUNE_POS_SHIFT; _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_FDAC_4; - coarse = coarse_freq_2; + coarse_freq = coarse_freq_2; } - else { // too high - return false; + else { + return 0; } - - double fine = freq - coarse; - - // Compute fine tuning word... - // This assumes we're running the 4x on-chip interpolator. - // (This is required to use the fine modulator.) - - unsigned int v = compute_freq_control_word_9862 (dac_rate / 4, fine, - &_tx_freq[channel]); - - _tx_freq[channel] += coarse; // adjust actual - - boost::uint8_t high; - boost::uint8_t mid; - boost::uint8_t low; - - high = (v >> 16) & 0xff; - mid = (v >> 8) & 0xff; - low = (v >> 0) & 0xff; - - // write the fine tuning word - _ad9862_regs.ftw_23_16 = high; - _ad9862_regs.ftw_15_8 = mid; - _ad9862_regs.ftw_7_0 = low; - - _ad9862_regs.fine_mode = ad9862_regs_t::FINE_MODE_NCO; - - if (fine < 0) + + return coarse_freq; +} + +double usrp1_codec_ctrl_impl::fine_tune(double codec_rate, double target_freq) +{ + static const double scale_factor = std::pow(2.0, 24); + + boost::uint32_t freq_word = boost::uint32_t( + boost::math::round(abs((target_freq / codec_rate) * scale_factor))); + + double actual_freq = freq_word * codec_rate / scale_factor; + + if (target_freq < 0) { _ad9862_regs.neg_fine_tune = ad9862_regs_t::NEG_FINE_TUNE_NEG_SHIFT; - else + actual_freq = -actual_freq; + } + else { _ad9862_regs.neg_fine_tune = ad9862_regs_t::NEG_FINE_TUNE_POS_SHIFT; - + } + + _ad9862_regs.fine_mode = ad9862_regs_t::FINE_MODE_NCO; + _ad9862_regs.ftw_23_16 = (freq_word >> 16) & 0xff; + _ad9862_regs.ftw_15_8 = (freq_word >> 8) & 0xff; + _ad9862_regs.ftw_7_0 = (freq_word >> 0) & 0xff; + + return actual_freq; +} + +void usrp1_codec_ctrl_impl::set_duc_freq(double freq) +{ + double codec_rate = _clock_ctrl->get_master_clock_freq() * 2; + double coarse_freq = coarse_tune(codec_rate, freq); + double fine_freq = fine_tune(codec_rate / 4, freq - coarse_freq); + + if (codec_debug) { + std::cout << "ad9862 tuning result:" << std::endl; + std::cout << " requested: " << freq << std::endl; + std::cout << " actual: " << coarse_freq + fine_freq << std::endl; + std::cout << " coarse freq: " << coarse_freq << std::endl; + std::cout << " fine freq: " << fine_freq << std::endl; + std::cout << " codec rate: " << codec_rate << std::endl; + } + this->send_reg(20); this->send_reg(21); this->send_reg(22); this->send_reg(23); - - return true; } /*********************************************************************** * Codec Control Make **********************************************************************/ -usrp1_codec_ctrl::sptr usrp1_codec_ctrl::make(usrp1_iface::sptr iface, int spi_slave) +usrp1_codec_ctrl::sptr usrp1_codec_ctrl::make(usrp1_iface::sptr iface, + usrp1_clock_ctrl::sptr clock, + int spi_slave) { - return sptr(new usrp1_codec_ctrl_impl(iface, spi_slave)); + return sptr(new usrp1_codec_ctrl_impl(iface, clock, spi_slave)); } diff --git a/host/lib/usrp/usrp1/codec_ctrl.hpp b/host/lib/usrp/usrp1/codec_ctrl.hpp index 6440f97d1..259d10ef4 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.hpp +++ b/host/lib/usrp/usrp1/codec_ctrl.hpp @@ -19,6 +19,7 @@ #define INCLUDED_USRP1_CODEC_CTRL_HPP #include "usrp1_iface.hpp" +#include "clock_ctrl.hpp" #include #include #include @@ -41,7 +42,9 @@ public: * \param spi_slave which spi device * \return the clock control object */ - static sptr make(usrp1_iface::sptr iface, int spi_slave); + static sptr make(usrp1_iface::sptr iface, + usrp1_clock_ctrl::sptr clock, int spi_slave + ); //! aux adc identifier constants enum aux_adc_t{ @@ -87,7 +90,8 @@ public: //! Get the RX PGA gain ('A' or 'B') virtual float get_rx_pga_gain(char which) = 0; - virtual bool set_duc_freq(double freq) = 0; + //! Set the TX modulator frequency + virtual void set_duc_freq(double freq) = 0; }; #endif /* INCLUDED_USRP1_CODEC_CTRL_HPP */ diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp index 0db3cb473..ce0c12e4b 100644 --- a/host/lib/usrp/usrp1/dsp_impl.cpp +++ b/host/lib/usrp/usrp1/dsp_impl.cpp @@ -73,31 +73,13 @@ void usrp1_impl::rx_dsp_get(const wax::obj &key, wax::obj &val) /*********************************************************************** * RX DDC Set **********************************************************************/ -unsigned int compute_freq_word(double master, double target) -{ - static const int NBITS = 14; - int v = (int) rint (target / master * pow(2.0, 32.0)); - - if (0) - v = (v >> (32 - NBITS)) << (32 - NBITS); // keep only top NBITS - - double actual_freq = v * master / pow(2.0, 32.0); - - if (0) std::cerr << boost::format( - "compute_freq_control_word_fpga: target = %g actual = %g delta = %g\n" - ) % target % actual_freq % (actual_freq - target); - - return (unsigned int) v; -} - void usrp1_impl::rx_dsp_set(const wax::obj &key, const wax::obj &val) { switch(key.as()) { case DSP_PROP_FREQ_SHIFT: { double new_freq = val.as(); - boost::uint32_t hw_freq_word = compute_freq_word( - _clock_ctrl->get_master_clock_freq(), new_freq); - _iface->poke32(FR_RX_FREQ_0, hw_freq_word); + _iface->poke32(FR_RX_FREQ_0, + -dsp_type1::calc_cordic_word_and_update(new_freq, _clock_ctrl->get_master_clock_freq())); _tx_dsp_freq = new_freq; return; } @@ -173,15 +155,15 @@ void usrp1_impl::tx_dsp_set(const wax::obj &key, const wax::obj &val) { switch(key.as()) { + // TODO: Set both codec frequencies until we have duality properties case DSP_PROP_FREQ_SHIFT: { double new_freq = val.as(); _codec_ctrls[DBOARD_SLOT_A]->set_duc_freq(new_freq); + _codec_ctrls[DBOARD_SLOT_B]->set_duc_freq(new_freq); _tx_dsp_freq = new_freq; return; } - //TODO freq prop secondary: DBOARD_SLOT_B codec... - case DSP_PROP_HOST_RATE: { unsigned int rate = _clock_ctrl->get_master_clock_freq() * 2 / val.as(); diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index ece5f1dea..ee6fe6e99 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -138,8 +138,12 @@ usrp1_impl::usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport, _clock_ctrl = usrp1_clock_ctrl::make(_iface); //create codec interface - _codec_ctrls[DBOARD_SLOT_A] = usrp1_codec_ctrl::make(_iface, SPI_ENABLE_CODEC_A); - _codec_ctrls[DBOARD_SLOT_B] = usrp1_codec_ctrl::make(_iface, SPI_ENABLE_CODEC_B); + _codec_ctrls[DBOARD_SLOT_A] = usrp1_codec_ctrl::make( + _iface, _clock_ctrl, SPI_ENABLE_CODEC_A + ); + _codec_ctrls[DBOARD_SLOT_B] = usrp1_codec_ctrl::make( + _iface, _clock_ctrl, SPI_ENABLE_CODEC_B + ); //initialize the codecs codec_init(); -- cgit v1.2.3 From 5ac2f224154c819c0e0a788cbcd98da764950e70 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Wed, 18 Aug 2010 19:26:38 -0700 Subject: usrp1: Return proper mboard proxy --- host/lib/usrp/usrp1/mboard_impl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index c3343f1f8..48a919f2a 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -298,7 +298,7 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val) case MBOARD_PROP_RX_SUBDEV_SPEC: _rx_subdev_spec = val.as(); - verify_rx_subdev_spec(_rx_subdev_spec, this->get_link()); + verify_rx_subdev_spec(_rx_subdev_spec, _mboard_proxy->get_link()); //sanity check UHD_ASSERT_THROW(_rx_subdev_spec.size() <= 2); //set the mux and set the number of rx channels @@ -307,7 +307,7 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val) case MBOARD_PROP_TX_SUBDEV_SPEC: _tx_subdev_spec = val.as(); - verify_tx_subdev_spec(_tx_subdev_spec, this->get_link()); + verify_tx_subdev_spec(_tx_subdev_spec, _mboard_proxy->get_link()); //sanity check UHD_ASSERT_THROW(_tx_subdev_spec.size() <= 2); //set the mux and set the number of tx channels -- cgit v1.2.3 From 7ce6f4752c436eb3d1b027bd8e9e8bdb05f4f43b Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Thu, 19 Aug 2010 12:37:56 -0700 Subject: usrp1: Remove codec gain TODO comments --- host/lib/usrp/usrp1/codec_ctrl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index 419e4c5e2..a618eff6d 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -100,15 +100,15 @@ usrp1_codec_ctrl_impl::usrp1_codec_ctrl_impl(usrp1_iface::sptr iface, _ad9862_regs.byp_buffer_b = 1; _ad9862_regs.buffer_a_pd = 1; _ad9862_regs.buffer_b_pd = 1; - _ad9862_regs.rx_pga_a = 0;//0x1f; //TODO bring under api control - _ad9862_regs.rx_pga_b = 0;//0x1f; //TODO bring under api control + _ad9862_regs.rx_pga_a = 0; + _ad9862_regs.rx_pga_b = 0; _ad9862_regs.rx_twos_comp = 1; _ad9862_regs.rx_hilbert = ad9862_regs_t::RX_HILBERT_DIS; //setup tx side of codec _ad9862_regs.two_data_paths = ad9862_regs_t::TWO_DATA_PATHS_BOTH; _ad9862_regs.interleaved = ad9862_regs_t::INTERLEAVED_INTERLEAVED; - _ad9862_regs.tx_pga_gain = 199; //TODO bring under api control + _ad9862_regs.tx_pga_gain = 199; _ad9862_regs.tx_hilbert = ad9862_regs_t::TX_HILBERT_DIS; _ad9862_regs.interp = ad9862_regs_t::INTERP_4; _ad9862_regs.tx_twos_comp = 1; -- cgit v1.2.3 From 2f3269f359043290fcaa7659e90292919306a8bc Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 19 Aug 2010 18:23:19 -0700 Subject: usrp1: images for usrp1, makefile checks for image generation dependencies --- firmware/fx2/.gitignore | 5 +++++ host/AUTHORS | 10 +++++++++- host/lib/usrp/usrp1/usrp1_impl.cpp | 34 ++++++++++++++++++++++------------ host/lib/usrp/usrp1/usrp1_impl.hpp | 6 +----- images/Makefile | 27 +++++++++++++++++++++++++++ 5 files changed, 64 insertions(+), 18 deletions(-) diff --git a/firmware/fx2/.gitignore b/firmware/fx2/.gitignore index 75bb241c8..affc0b779 100644 --- a/firmware/fx2/.gitignore +++ b/firmware/fx2/.gitignore @@ -23,3 +23,8 @@ /missing /make.log /usrp.pc +/INSTALL +/config.guess +/config.sub +/install-sh +/ltmain.sh diff --git a/host/AUTHORS b/host/AUTHORS index 137eba0e6..7292da8f9 100644 --- a/host/AUTHORS +++ b/host/AUTHORS @@ -1,5 +1,6 @@ Matt Ettus - matt@ettus.com - USRP1/USRP2 FPGA code + USRP1 FPGA code + USRP2 FPGA code Josh Blum - josh@ettus.com driver framework @@ -14,4 +15,11 @@ Jason Abele - jason@ettus.com WBX host code Eric Blossom - eb@comsec.com + USRP1 firmware USRP2 firmware + +Tom Tsou - ttsou@vt.edu + UHD-USB framework + LIBUSB host code + USRP1 host code + USRP1 firmware diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index ece5f1dea..33a069bc6 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -23,9 +23,11 @@ #include #include #include +#include #include #include #include +#include #include using namespace uhd; @@ -42,11 +44,16 @@ const std::vector usrp1_impl::_dboard_slots = boost:: static device_addrs_t usrp1_find(const device_addr_t &hint) { device_addrs_t usrp1_addrs; - std::string filename = "/usr/local/share/usrp/rev4/std.ihx"; //return an empty list of addresses when type is set to non-usrp1 if (hint.has_key("type") and hint["type"] != "usrp1") return usrp1_addrs; + //extract the firmware path for the USRP1 + std::string usrp1_fw_image = find_image_path( + hint.has_key("fw")? hint["fw"] : "usrp1_fw.ihx" + ); + std::cout << "USRP1 firmware image: " << usrp1_fw_image << std::endl; + //see what we got on the USB bus usb_descriptors_t usb_descriptors; usb_descriptors = usb_control::get_device_list(); @@ -56,12 +63,12 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) if (desc.vendor_id == 0xfffe && desc.product_id == 0x0002) { usb_control::sptr ctrl_transport = usb_control::make(desc); usrp_ctrl::sptr usrp_ctrl = usrp_ctrl::make(ctrl_transport); - usrp_ctrl->usrp_load_firmware(filename); + usrp_ctrl->usrp_load_firmware(usrp1_fw_image); } } //wait for things to settle - sleep(1); + boost::this_thread::sleep(boost::posix_time::milliseconds(500)); //get descriptors again with serial number usb_descriptors = usb_control::get_device_list(); @@ -83,14 +90,11 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) **********************************************************************/ static device::sptr usrp1_make(const device_addr_t &device_addr) { - std::string filename; - - if (device_addr.has_key("fpga")) - filename = device_addr["fpga"]; - else - filename = "/usr/local/share/usrp/rev4/std_2rxhb_2tx.rbf"; - - std::cout << "Make usrp1 with " << filename << std::endl; + //extract the FPGA path for the USRP1 + std::string usrp1_fpga_image = find_image_path( + device_addr.has_key("fpga")? device_addr["fpga"] : "usrp1_fpga.rbf" + ); + std::cout << "USRP1 FPGA image: " << usrp1_fpga_image << std::endl; //try to match the given device address with something on the USB bus usb_descriptors_t usb_descriptors; @@ -106,7 +110,7 @@ static device::sptr usrp1_make(const device_addr_t &device_addr) usb_control::sptr ctrl_transport = usb_control::make(desc); usrp_ctrl = usrp_ctrl::make(ctrl_transport); - usrp_ctrl->usrp_load_fpga(filename); + usrp_ctrl->usrp_load_fpga(usrp1_fpga_image); data_transport = usb_zero_copy::make(desc, // identifier 6, // IN endpoint @@ -167,6 +171,12 @@ usrp1_impl::~usrp1_impl(void){ /* NOP */ } +bool usrp1_impl::recv_async_msg(uhd::async_metadata_t &, size_t timeout_ms){ + //dummy fill-in for the recv_async_msg + boost::this_thread::sleep(boost::posix_time::milliseconds(timeout_ms)); + return false; +} + /*********************************************************************** * Device Get **********************************************************************/ diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index f57f9a09a..cbd3d5315 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -93,11 +93,7 @@ public: size_t get_max_send_samps_per_packet(void) const { return 0; } size_t get_max_recv_samps_per_packet(void) const { return 0; } - - bool recv_async_msg(uhd::async_metadata_t &, size_t) { - //TODO sleep the number of ms supplied (dont want to hog CPU) - return false; - } + bool recv_async_msg(uhd::async_metadata_t &, size_t); private: /*! diff --git a/images/Makefile b/images/Makefile index 0a829a296..0e58fbb18 100644 --- a/images/Makefile +++ b/images/Makefile @@ -30,9 +30,26 @@ CMAKE_BUILD_DIR = $(TOP_DIR)/build ##filled in below IMAGES_LIST = +######################################################################## +# Utility Checks +######################################################################## +ifeq ($(shell sdcc --help > /dev/null 2>&1 && echo $$?),0) + HAS_SDCC=1 +endif + +ifeq ($(shell mb-gcc --help > /dev/null 2>&1 && echo $$?),0) + HAS_MB_GCC=1 +endif + +ifeq ($(shell xtclsh -h > /dev/null 2>&1 && echo $$?),0) + HAS_XTCLSH=1 +endif + ######################################################################## # USRP1 firmware ######################################################################## +ifdef HAS_SDCC + _usrp1_fw_dir = $(TOP_FW_DIR)/fx2 _usrp1_fw_ihx = $(BUILT_IMAGES_DIR)/usrp1_fw.ihx IMAGES_LIST += $(_usrp1_fw_ihx) @@ -44,6 +61,8 @@ $(_usrp1_fw_ihx): make -C $(_usrp1_fw_dir) all cp $(_usrp1_fw_dir)/src/usrp1/std.ihx $@ +endif + ######################################################################## # USRP1 fpga ######################################################################## @@ -57,6 +76,8 @@ $(_usrp1_fpga_rbf): ######################################################################## # USRP2 firmware ######################################################################## +ifdef HAS_MB_GCC + _usrp2_fw_dir = $(TOP_FW_DIR)/microblaze _usrp2_fw_bin = $(BUILT_IMAGES_DIR)/usrp2_fw.bin IMAGES_LIST += $(_usrp2_fw_bin) @@ -68,9 +89,13 @@ $(_usrp2_fw_bin): make -C $(_usrp2_fw_dir) all cp $(_usrp2_fw_dir)/usrp2/usrp2_txrx_uhd.bin $@ +endif + ######################################################################## # USRP2 fpga ######################################################################## +ifdef HAS_XTCLSH + _usrp2_fpga_dir = $(TOP_FPGA_DIR)/usrp2/top/u2_rev3 _usrp2_fpga_bin = $(BUILT_IMAGES_DIR)/usrp2_fpga.bin IMAGES_LIST += $(_usrp2_fpga_bin) @@ -80,6 +105,8 @@ $(_usrp2_fpga_bin): cd $(_usrp2_fpga_dir) && make -f Makefile.udp bin cp $(_usrp2_fpga_dir)/build-udp/u2_rev3.bin $@ +endif + ######################################################################## # Build rules ######################################################################## -- cgit v1.2.3 From dafbb2c047fc0878288a67ec161c7c2735e1dcb8 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Thu, 19 Aug 2010 17:44:07 -0700 Subject: usrp1: Make underrun/overrun checking rate dependent Calculate a polling interval based on the sample rate and size. --- host/lib/usrp/usrp1/io_impl.cpp | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 3f3e74b80..71b2c4fc5 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -33,6 +33,8 @@ using namespace uhd::usrp; using namespace uhd::transport; namespace asio = boost::asio; +static const float poll_interval = 0.1; //100ms + /* * The FX2 firmware bursts data to the FPGA in 512 byte chunks so * maintain send state to make sure that happens. @@ -57,11 +59,15 @@ struct usrp1_impl::io_impl { usrp1_send_state send_state; zero_copy_if::sptr data_transport; - unsigned int count; + + //overun-underrun values + unsigned int tx_underrun_count; + unsigned int rx_overrun_count; }; usrp1_impl::io_impl::io_impl(zero_copy_if::sptr zc_if) - : packet_handler_recv_state(1), data_transport(zc_if), count(0) + : packet_handler_recv_state(1), data_transport(zc_if), + tx_underrun_count(0), rx_overrun_count(0) { /* NOP */ } @@ -133,9 +139,10 @@ size_t usrp1_impl::send(const std::vector &buffs, } total_samps_sent += copy_samps; + _io_impl->tx_underrun_count += copy_samps * _tx_otw_type.get_sample_size(); //check for underruns - if (!(_io_impl->count++ % 1000)) { + if (!(_io_impl->tx_underrun_count > _tx_dsp_freq * poll_interval * _tx_otw_type.get_sample_size())) { unsigned char underrun; int ret = _ctrl_transport->usrp_control_read(VRQ_GET_STATUS, 0, @@ -145,6 +152,8 @@ size_t usrp1_impl::send(const std::vector &buffs, std::cerr << "error: underrun check failed" << std::endl; if (underrun) std::cerr << "U" << std::endl; + + _io_impl->tx_underrun_count = 0; } } @@ -208,22 +217,25 @@ size_t usrp1_impl::recv(const std::vector &buffs, _io_impl->packet_handler_recv_state.copy_buffs[0] += bytes_to_copy; _io_impl->packet_handler_recv_state.size_of_copy_buffs -= bytes_to_copy; + _io_impl->rx_overrun_count += nsamps_to_copy; sent_samps += nsamps_to_copy; - //check for overruns - if (!(_io_impl->count++ % 10000)) { + //check for overruns + if (_io_impl->rx_overrun_count > (8e6 * poll_interval)) { unsigned char overrun; - int ret = _ctrl_transport->usrp_control_read( - VRQ_GET_STATUS, - 0, - GS_RX_OVERRUN, - &overrun, sizeof(char)); + int ret = _ctrl_transport->usrp_control_read(VRQ_GET_STATUS, + 0, + GS_RX_OVERRUN, + &overrun, sizeof(char)); if (ret < 0) std::cerr << "error: overrun check failed" << std::endl; if (overrun) std::cerr << "O" << std::endl; + + _io_impl->rx_overrun_count = 0; } } + return sent_samps; } -- cgit v1.2.3 From f41cdf4eeb31a2fed2a93b23e0fbe5f3b2142296 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Thu, 19 Aug 2010 19:33:18 -0700 Subject: usrp1: Change codec transmit gain scaling The AD9862 datasheet states that maximum gain is achieved with a value of 111111 (0x3f), however, empirical testing reveals that the gain scaling value spans the full register width of 8-bits. --- host/lib/usrp/usrp1/codec_ctrl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index a618eff6d..6751b9b7e 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -156,8 +156,8 @@ usrp1_codec_ctrl_impl::~usrp1_codec_ctrl_impl(void) **********************************************************************/ void usrp1_codec_ctrl_impl::set_tx_pga_gain(float gain) { - int gain_word = int(63*(gain - tx_pga_gain_range.min)/(tx_pga_gain_range.max - tx_pga_gain_range.min)); - _ad9862_regs.tx_pga_gain = std::clip(gain_word, 0, 63); + int gain_word = int(255*(gain - tx_pga_gain_range.min)/(tx_pga_gain_range.max - tx_pga_gain_range.min)); + _ad9862_regs.tx_pga_gain = std::clip(gain_word, 0, 255); this->send_reg(16); } -- cgit v1.2.3 From f65bdc31e4432d09d52b7f45d5bfbd1f945a1a6f Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Mon, 23 Aug 2010 15:12:28 -0700 Subject: usrp1: Fix bug in calculating transmit mux Use transmit instead of receive properties. --- host/lib/usrp/usrp1/mboard_impl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index 48a919f2a..74ec514ff 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -114,7 +114,7 @@ static boost::uint32_t calc_tx_mux( //calculate the channel flags int channel_flags = 0, chan = 0; BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){ - wax::obj dboard = mboard[named_prop_t(MBOARD_PROP_RX_DBOARD, pair.db_name)]; + wax::obj dboard = mboard[named_prop_t(MBOARD_PROP_TX_DBOARD, pair.db_name)]; wax::obj subdev = dboard[named_prop_t(DBOARD_PROP_SUBDEV, pair.sd_name)]; subdev_conn_t conn = subdev[SUBDEV_PROP_CONNECTION].as(); -- cgit v1.2.3 From 4021779856d6b971fa8add5f617528158bf727a2 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Mon, 23 Aug 2010 15:13:44 -0700 Subject: usrp1: Refactor I/O implementation --- host/lib/usrp/usrp1/dsp_impl.cpp | 4 + host/lib/usrp/usrp1/io_impl.cpp | 337 +++++++++++++++++++++++-------------- host/lib/usrp/usrp1/usrp1_impl.hpp | 4 + 3 files changed, 215 insertions(+), 130 deletions(-) diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp index ce0c12e4b..ddd1e811b 100644 --- a/host/lib/usrp/usrp1/dsp_impl.cpp +++ b/host/lib/usrp/usrp1/dsp_impl.cpp @@ -95,6 +95,8 @@ void usrp1_impl::rx_dsp_set(const wax::obj &key, const wax::obj &val) } _rx_dsp_decim = rate; + _rx_samps_per_poll_interval = 0.1 * _clock_ctrl->get_master_clock_freq() / rate; + _iface->poke32(FR_DECIM_RATE, _rx_dsp_decim/2 - 1); } return; @@ -175,6 +177,8 @@ void usrp1_impl::tx_dsp_set(const wax::obj &key, const wax::obj &val) } _tx_dsp_interp = rate; + _tx_samps_per_poll_interval = 0.1 * _clock_ctrl->get_master_clock_freq() * 2 / rate; + _iface->poke32(FR_INTERP_RATE, _tx_dsp_interp / 4 - 1); return; } diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 71b2c4fc5..33a04ffe6 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -35,41 +35,53 @@ namespace asio = boost::asio; static const float poll_interval = 0.1; //100ms -/* - * The FX2 firmware bursts data to the FPGA in 512 byte chunks so - * maintain send state to make sure that happens. - */ struct usrp1_send_state { uhd::transport::managed_send_buffer::sptr send_buff; - size_t bytes_used; + size_t bytes_written; size_t bytes_free; + size_t underrun_poll_samp_count; +}; + +struct usrp1_recv_state { + uhd::transport::managed_recv_buffer::sptr recv_buff; + size_t bytes_read; + size_t bytes_avail; + size_t overrun_poll_samp_count; }; /*********************************************************************** * IO Implementation Details **********************************************************************/ struct usrp1_impl::io_impl { - io_impl(zero_copy_if::sptr zc_if); + io_impl(); ~io_impl(void); - bool get_recv_buff(managed_recv_buffer::sptr buff); - - //state management for the vrt packet handler code - vrt_packet_handler::recv_state packet_handler_recv_state; + //state handling for buffer management + usrp1_recv_state recv_state; usrp1_send_state send_state; - zero_copy_if::sptr data_transport; - - //overun-underrun values - unsigned int tx_underrun_count; - unsigned int rx_overrun_count; + //send transport management + bool get_send_buffer(zero_copy_if::sptr zc_if); + size_t copy_convert_send_samps(const void *buff, size_t num_samps, + size_t sample_offset, const io_type_t io_type, + otw_type_t otw_type); + bool conditional_buff_commit(bool force); + bool check_underrun(usrp_ctrl::sptr ctrl_if, + size_t poll_interval, bool force); + + //recv transport management + bool get_recv_buffer(zero_copy_if::sptr zc_if); + size_t copy_convert_recv_samps(void *buff, size_t num_samps, + size_t sample_offset, const io_type_t io_type, + otw_type_t otw_type); + bool check_overrun(usrp_ctrl::sptr ctrl_if, + size_t poll_interval, bool force); }; -usrp1_impl::io_impl::io_impl(zero_copy_if::sptr zc_if) - : packet_handler_recv_state(1), data_transport(zc_if), - tx_underrun_count(0), rx_overrun_count(0) +usrp1_impl::io_impl::io_impl() { - /* NOP */ + send_state.send_buff = uhd::transport::managed_send_buffer::sptr(); + recv_state.recv_buff = uhd::transport::managed_recv_buffer::sptr(); } usrp1_impl::io_impl::~io_impl(void) @@ -87,12 +99,94 @@ void usrp1_impl::io_init(void) _tx_otw_type.shift = 0; _tx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport)); + _io_impl = UHD_PIMPL_MAKE(io_impl, ()); } /*********************************************************************** * Data Send **********************************************************************/ +bool usrp1_impl::io_impl::get_send_buffer(zero_copy_if::sptr zc_if) +{ + if (send_state.send_buff == NULL) { + + send_state.send_buff = zc_if->get_send_buff(); + if (send_state.send_buff == NULL) + return false; + + send_state.bytes_free = send_state.send_buff->size(); + send_state.bytes_written = 0; + } + + return true; +} + +size_t usrp1_impl::io_impl::copy_convert_send_samps(const void *buff, + size_t num_samps, + size_t sample_offset, + const io_type_t io_type, + otw_type_t otw_type) +{ + UHD_ASSERT_THROW(send_state.bytes_free % otw_type.get_sample_size() == 0); + + size_t samps_free = send_state.bytes_free / otw_type.get_sample_size(); + size_t copy_samps = std::min(num_samps - sample_offset, samps_free); + + const boost::uint8_t *io_mem = + reinterpret_cast(buff); + + boost::uint8_t *otw_mem = send_state.send_buff->cast(); + + convert_io_type_to_otw_type(io_mem + sample_offset * io_type.size, + io_type, + otw_mem + send_state.bytes_written, + otw_type, + copy_samps); + + send_state.bytes_written += copy_samps * otw_type.get_sample_size(); + send_state.bytes_free -= copy_samps * otw_type.get_sample_size(); + send_state.underrun_poll_samp_count += copy_samps; + + return copy_samps; +} + +bool usrp1_impl::io_impl::conditional_buff_commit(bool force) +{ + if (send_state.bytes_written % 512) + return false; + + if (force || send_state.bytes_free == 0) { + send_state.send_buff->commit(send_state.bytes_written); + send_state.send_buff = uhd::transport::managed_send_buffer::sptr(); + return true; + } + + return false; +} + +bool usrp1_impl::io_impl::check_underrun(usrp_ctrl::sptr ctrl_if, + size_t poll_interval, + bool force) +{ + unsigned char underrun = 0; + + bool ready_to_poll = send_state.underrun_poll_samp_count > poll_interval; + + if (force || ready_to_poll) { + int ret = ctrl_if->usrp_control_read(VRQ_GET_STATUS, + 0, + GS_TX_UNDERRUN, + &underrun, sizeof(char)); + if (ret < 0) + std::cerr << "USRP: underrun check failed" << std::endl; + if (underrun) + std::cerr << "U" << std::endl; + + send_state.underrun_poll_samp_count = 0; + } + + return (bool) underrun; +} + size_t usrp1_impl::send(const std::vector &buffs, size_t num_samps, const tx_metadata_t &, @@ -104,57 +198,21 @@ size_t usrp1_impl::send(const std::vector &buffs, size_t total_samps_sent = 0; while (total_samps_sent < num_samps) { - - if (_io_impl->send_state.send_buff == NULL) { - _io_impl->send_state.send_buff = _data_transport->get_send_buff(); - if (_io_impl->send_state.send_buff == NULL) { - return 0; - } - _io_impl->send_state.bytes_used = 0; - _io_impl->send_state.bytes_free = _io_impl->send_state.send_buff->size(); - } - - size_t copy_samps = - std::min(num_samps - total_samps_sent, _io_impl->send_state.bytes_free / _tx_otw_type.get_sample_size()); - - const boost::uint8_t *io_mem = - reinterpret_cast(buffs[0]); - - boost::uint8_t *otw_mem = _io_impl->send_state.send_buff->cast(); - - // Type conversion and copy - convert_io_type_to_otw_type( - io_mem + total_samps_sent * io_type.size, - io_type, - otw_mem + _io_impl->send_state.bytes_used, - _tx_otw_type, - copy_samps); - - _io_impl->send_state.bytes_used += copy_samps * _tx_otw_type.get_sample_size(); - _io_impl->send_state.bytes_free -= copy_samps * _tx_otw_type.get_sample_size(); - - if (_io_impl->send_state.bytes_free == 0) { - _io_impl->send_state.send_buff->commit(_io_impl->send_state.bytes_used); - _io_impl->send_state.send_buff = uhd::transport::managed_send_buffer::sptr(); - } - - total_samps_sent += copy_samps; - _io_impl->tx_underrun_count += copy_samps * _tx_otw_type.get_sample_size(); - - //check for underruns - if (!(_io_impl->tx_underrun_count > _tx_dsp_freq * poll_interval * _tx_otw_type.get_sample_size())) { - unsigned char underrun; - int ret = _ctrl_transport->usrp_control_read(VRQ_GET_STATUS, - 0, - GS_TX_UNDERRUN, - &underrun, sizeof(char)); - if (ret < 0) - std::cerr << "error: underrun check failed" << std::endl; - if (underrun) - std::cerr << "U" << std::endl; - - _io_impl->tx_underrun_count = 0; - } + if (!_io_impl->get_send_buffer(_data_transport)) + return 0; + + total_samps_sent += _io_impl->copy_convert_send_samps(buffs[0], + num_samps, + total_samps_sent, + io_type, + _tx_otw_type); + if (total_samps_sent == num_samps) + _io_impl->conditional_buff_commit(true); + else + _io_impl->conditional_buff_commit(false); + + _io_impl->check_underrun(_ctrl_transport, + _tx_samps_per_poll_interval, false); } return total_samps_sent; @@ -163,17 +221,72 @@ size_t usrp1_impl::send(const std::vector &buffs, /*********************************************************************** * Data Recv **********************************************************************/ -void _recv_helper(vrt_packet_handler::recv_state &state) +bool usrp1_impl::io_impl::get_recv_buffer(zero_copy_if::sptr zc_if) +{ + if ((recv_state.recv_buff == NULL) || (recv_state.bytes_avail == 0)) { + + recv_state.recv_buff = zc_if->get_recv_buff(); + if (recv_state.recv_buff == NULL) + return false; + + recv_state.bytes_read = 0; + recv_state.bytes_avail = recv_state.recv_buff->size(); + } + + return true; +} + +size_t usrp1_impl::io_impl::copy_convert_recv_samps(void *buff, + size_t num_samps, + size_t sample_offset, + const io_type_t io_type, + otw_type_t otw_type) +{ + UHD_ASSERT_THROW(recv_state.bytes_avail % otw_type.get_sample_size() == 0); + + size_t samps_avail = recv_state.bytes_avail / otw_type.get_sample_size(); + size_t copy_samps = std::min(num_samps - sample_offset, samps_avail); + + const boost::uint8_t *otw_mem = + recv_state.recv_buff->cast(); + + boost::uint8_t *io_mem = reinterpret_cast(buff); + + convert_otw_type_to_io_type(otw_mem + recv_state.bytes_read, + otw_type, + io_mem + sample_offset * io_type.size, + io_type, + copy_samps); + + recv_state.bytes_read += copy_samps * otw_type.get_sample_size(); + recv_state.bytes_avail -= copy_samps * otw_type.get_sample_size(); + recv_state.overrun_poll_samp_count += copy_samps; + + return copy_samps; +} + +bool usrp1_impl::io_impl::check_overrun(usrp_ctrl::sptr ctrl_if, + size_t poll_interval, + bool force) { - size_t num_packet_words32 = - state.managed_buffs[0]->size() / sizeof(boost::uint32_t); + unsigned char overrun = 0; + + bool ready_to_poll = recv_state.overrun_poll_samp_count > poll_interval; - const boost::uint32_t *data = - state.managed_buffs[0]->cast(); + if (force || ready_to_poll) { + int ret = ctrl_if->usrp_control_read(VRQ_GET_STATUS, + 0, + GS_RX_OVERRUN, + &overrun, sizeof(char)); + if (ret < 0) + std::cerr << "USRP: overrrun check failed" << std::endl; + if (overrun) + std::cerr << "O" << std::endl; + + recv_state.overrun_poll_samp_count = 0; + } - state.copy_buffs[0] = reinterpret_cast(data); - size_t num_payload_bytes = num_packet_words32 * sizeof(boost::uint32_t); - state.size_of_copy_buffs = num_payload_bytes; + return (bool) overrun; } size_t usrp1_impl::recv(const std::vector &buffs, @@ -183,59 +296,23 @@ size_t usrp1_impl::recv(const std::vector &buffs, recv_mode_t, size_t) { - UHD_ASSERT_THROW(_io_impl->packet_handler_recv_state.width == 1); UHD_ASSERT_THROW(buffs.size() == 1); - size_t sent_samps = 0; - size_t nsamps_to_copy = 0;; - - while (sent_samps < num_samps) { - if (_io_impl->packet_handler_recv_state.size_of_copy_buffs == 0) { - _io_impl->packet_handler_recv_state.fragment_offset_in_samps = 0; - _io_impl->packet_handler_recv_state.managed_buffs[0] = - _io_impl->data_transport->get_recv_buff(); - - //timeout or something bad returns zero - if (!_io_impl->packet_handler_recv_state.managed_buffs[0].get()) - return 0; - - _recv_helper(_io_impl->packet_handler_recv_state); - } - - size_t bytes_per_item = _rx_otw_type.get_sample_size(); - size_t nsamps_available = - _io_impl->packet_handler_recv_state.size_of_copy_buffs / bytes_per_item; - nsamps_to_copy = std::min(num_samps, nsamps_available); - size_t bytes_to_copy = nsamps_to_copy * bytes_per_item; - - convert_otw_type_to_io_type( - _io_impl->packet_handler_recv_state.copy_buffs[0], - _rx_otw_type, - reinterpret_cast(buffs[0]) + sent_samps * io_type.size, - io_type, - nsamps_to_copy); - - _io_impl->packet_handler_recv_state.copy_buffs[0] += bytes_to_copy; - _io_impl->packet_handler_recv_state.size_of_copy_buffs -= bytes_to_copy; - _io_impl->rx_overrun_count += nsamps_to_copy; - - sent_samps += nsamps_to_copy; - - //check for overruns - if (_io_impl->rx_overrun_count > (8e6 * poll_interval)) { - unsigned char overrun; - int ret = _ctrl_transport->usrp_control_read(VRQ_GET_STATUS, - 0, - GS_RX_OVERRUN, - &overrun, sizeof(char)); - if (ret < 0) - std::cerr << "error: overrun check failed" << std::endl; - if (overrun) - std::cerr << "O" << std::endl; - - _io_impl->rx_overrun_count = 0; - } + size_t total_samps_recv = 0; + + while (total_samps_recv < num_samps) { + + if (!_io_impl->get_recv_buffer(_data_transport)) + return 0; + + total_samps_recv += _io_impl->copy_convert_recv_samps(buffs[0], + num_samps, + total_samps_recv, + io_type, + _rx_otw_type); + _io_impl->check_overrun(_ctrl_transport, + _rx_samps_per_poll_interval, false); } - return sent_samps; + return total_samps_recv; } diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index f57f9a09a..5934d1779 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -124,6 +124,10 @@ private: void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd); void handle_overrun(size_t); + //underrun and overrun poll intervals + size_t _rx_samps_per_poll_interval; + size_t _tx_samps_per_poll_interval; + //otw types uhd::otw_type_t _rx_otw_type; uhd::otw_type_t _tx_otw_type; -- cgit v1.2.3 From 3f4e998bbf59dcc1c5df88ed37ca74f80a1b2e70 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Mon, 23 Aug 2010 15:21:14 -0700 Subject: usrp1: Remove hard coded value in clock rate property --- host/lib/usrp/usrp1/clock_ctrl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/lib/usrp/usrp1/clock_ctrl.cpp b/host/lib/usrp/usrp1/clock_ctrl.cpp index c83ad4c68..54f7b0b98 100644 --- a/host/lib/usrp/usrp1/clock_ctrl.cpp +++ b/host/lib/usrp/usrp1/clock_ctrl.cpp @@ -64,7 +64,7 @@ public: rates.push_back(master_clock_rate / div); return rates; #else - return std::vector(1, 64e6); + return std::vector(1, master_clock_rate); #endif } -- cgit v1.2.3 From 54debe30bbbc85c1cd1863d21a8e66ed4c8703e0 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Mon, 23 Aug 2010 15:30:14 -0700 Subject: usrp1: Fix assertion that prevents 32-bit SPI transactions --- host/lib/usrp/usrp1/usrp1_iface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp index d228161f1..e52f3d952 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.cpp +++ b/host/lib/usrp/usrp1/usrp1_iface.cpp @@ -165,7 +165,7 @@ public: size_t num_bits, bool readback) { - UHD_ASSERT_THROW((num_bits < 32) && !(num_bits % 8)); + UHD_ASSERT_THROW((num_bits <= 32) && !(num_bits % 8)); size_t num_bytes = num_bits / 8; // Byteswap on num_bytes -- cgit v1.2.3 From 8c5768ae1a5c30453a120bb0bb727dda1144629e Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Tue, 24 Aug 2010 15:04:39 -0700 Subject: usrp1: Improve debug output readability --- host/lib/usrp/usrp1/usrp1_iface.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp index e52f3d952..9d326d6bd 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.cpp +++ b/host/lib/usrp/usrp1/usrp1_iface.cpp @@ -53,7 +53,8 @@ public: if (iface_debug) { std::cout.fill('0'); - std::cout << "poke32(" << std::dec << addr << ", 0x"; + std::cout << "poke32("; + std::cout << std::dec << std::setw(2) << addr << ", 0x"; std::cout << std::hex << std::setw(8) << value << ")" << std::endl; } -- cgit v1.2.3 From 9449d05773c0e3d328ff721ef01b1d0dd50aa372 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Tue, 24 Aug 2010 16:04:24 -0700 Subject: usrp1: Cleanup unnecessary state variables --- host/lib/usrp/usrp1/io_impl.cpp | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 33a04ffe6..a0efa14d1 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -38,15 +38,29 @@ static const float poll_interval = 0.1; //100ms struct usrp1_send_state { uhd::transport::managed_send_buffer::sptr send_buff; size_t bytes_written; - size_t bytes_free; size_t underrun_poll_samp_count; + + size_t bytes_free() + { + if (send_buff != NULL) + return send_buff->size() - bytes_written; + else + return 0; + } }; struct usrp1_recv_state { uhd::transport::managed_recv_buffer::sptr recv_buff; size_t bytes_read; - size_t bytes_avail; size_t overrun_poll_samp_count; + + size_t bytes_avail() + { + if (recv_buff != NULL) + return recv_buff->size() - bytes_read; + else + return 0; + } }; /*********************************************************************** @@ -113,7 +127,6 @@ bool usrp1_impl::io_impl::get_send_buffer(zero_copy_if::sptr zc_if) if (send_state.send_buff == NULL) return false; - send_state.bytes_free = send_state.send_buff->size(); send_state.bytes_written = 0; } @@ -126,9 +139,9 @@ size_t usrp1_impl::io_impl::copy_convert_send_samps(const void *buff, const io_type_t io_type, otw_type_t otw_type) { - UHD_ASSERT_THROW(send_state.bytes_free % otw_type.get_sample_size() == 0); + UHD_ASSERT_THROW(send_state.bytes_free() % otw_type.get_sample_size() == 0); - size_t samps_free = send_state.bytes_free / otw_type.get_sample_size(); + size_t samps_free = send_state.bytes_free() / otw_type.get_sample_size(); size_t copy_samps = std::min(num_samps - sample_offset, samps_free); const boost::uint8_t *io_mem = @@ -143,7 +156,6 @@ size_t usrp1_impl::io_impl::copy_convert_send_samps(const void *buff, copy_samps); send_state.bytes_written += copy_samps * otw_type.get_sample_size(); - send_state.bytes_free -= copy_samps * otw_type.get_sample_size(); send_state.underrun_poll_samp_count += copy_samps; return copy_samps; @@ -154,7 +166,7 @@ bool usrp1_impl::io_impl::conditional_buff_commit(bool force) if (send_state.bytes_written % 512) return false; - if (force || send_state.bytes_free == 0) { + if (force || send_state.bytes_free() == 0) { send_state.send_buff->commit(send_state.bytes_written); send_state.send_buff = uhd::transport::managed_send_buffer::sptr(); return true; @@ -223,14 +235,13 @@ size_t usrp1_impl::send(const std::vector &buffs, **********************************************************************/ bool usrp1_impl::io_impl::get_recv_buffer(zero_copy_if::sptr zc_if) { - if ((recv_state.recv_buff == NULL) || (recv_state.bytes_avail == 0)) { + if ((recv_state.recv_buff == NULL) || (recv_state.bytes_avail() == 0)) { recv_state.recv_buff = zc_if->get_recv_buff(); if (recv_state.recv_buff == NULL) return false; recv_state.bytes_read = 0; - recv_state.bytes_avail = recv_state.recv_buff->size(); } return true; @@ -242,9 +253,9 @@ size_t usrp1_impl::io_impl::copy_convert_recv_samps(void *buff, const io_type_t io_type, otw_type_t otw_type) { - UHD_ASSERT_THROW(recv_state.bytes_avail % otw_type.get_sample_size() == 0); + UHD_ASSERT_THROW(recv_state.bytes_avail() % otw_type.get_sample_size() == 0); - size_t samps_avail = recv_state.bytes_avail / otw_type.get_sample_size(); + size_t samps_avail = recv_state.bytes_avail() / otw_type.get_sample_size(); size_t copy_samps = std::min(num_samps - sample_offset, samps_avail); const boost::uint8_t *otw_mem = @@ -259,7 +270,6 @@ size_t usrp1_impl::io_impl::copy_convert_recv_samps(void *buff, copy_samps); recv_state.bytes_read += copy_samps * otw_type.get_sample_size(); - recv_state.bytes_avail -= copy_samps * otw_type.get_sample_size(); recv_state.overrun_poll_samp_count += copy_samps; return copy_samps; -- cgit v1.2.3 From df6e52627540124e35e114522a897ff1409dc3a7 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Tue, 24 Aug 2010 16:06:11 -0700 Subject: usrp1: Remove unused overrun/underrun poll variable The polling inverval for overrun and underrun checking is rate dependent and calculated in the dsp code whenever the interpolation or decimation is changed. --- host/lib/usrp/usrp1/io_impl.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index a0efa14d1..5e206b3d5 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -33,8 +33,6 @@ using namespace uhd::usrp; using namespace uhd::transport; namespace asio = boost::asio; -static const float poll_interval = 0.1; //100ms - struct usrp1_send_state { uhd::transport::managed_send_buffer::sptr send_buff; size_t bytes_written; -- cgit v1.2.3 From 8c872ffb2e4f24927b6ec9de825a31c5eda014b8 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 24 Aug 2010 17:26:07 -0700 Subject: uhd: convert types corrected for little endian, created SSE2 float/short conversion for no-swap case --- host/lib/transport/convert_types_impl.hpp | 141 ++++++++++++++++++++++++------ host/test/convert_types_test.cpp | 139 ++++++++++++++++++----------- 2 files changed, 202 insertions(+), 78 deletions(-) diff --git a/host/lib/transport/convert_types_impl.hpp b/host/lib/transport/convert_types_impl.hpp index 5958b08cb..641029795 100644 --- a/host/lib/transport/convert_types_impl.hpp +++ b/host/lib/transport/convert_types_impl.hpp @@ -28,6 +28,13 @@ #define USE_EMMINTRIN_H //use sse2 intrinsics #endif +#if defined(USE_EMMINTRIN_H) + #include +#endif + +//! shortcut for a byteswap16 with casting +#define BSWAP16_C(num) uhd::byteswap(boost::uint16_t(num)) + /*********************************************************************** * Typedefs **********************************************************************/ @@ -47,9 +54,10 @@ static UHD_INLINE void sc16_to_item32_nswap( static UHD_INLINE void sc16_to_item32_bswap( const sc16_t *input, item32_t *output, size_t nsamps ){ - const item32_t *item32_input = (const item32_t *)input; for (size_t i = 0; i < nsamps; i++){ - output[i] = uhd::byteswap(item32_input[i]); + boost::uint16_t real = BSWAP16_C(input[i].real()); + boost::uint16_t imag = BSWAP16_C(input[i].imag()); + output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); } } @@ -65,34 +73,71 @@ static UHD_INLINE void item32_to_sc16_nswap( static UHD_INLINE void item32_to_sc16_bswap( const item32_t *input, sc16_t *output, size_t nsamps ){ - item32_t *item32_output = (item32_t *)output; for (size_t i = 0; i < nsamps; i++){ - item32_output[i] = uhd::byteswap(input[i]); + boost::int16_t real = BSWAP16_C(input[i] >> 0); + boost::int16_t imag = BSWAP16_C(input[i] >> 16); + output[i] = sc16_t(real, imag); } } /*********************************************************************** - * Convert complex float buffer to items32 + * Convert complex float buffer to items32 (no swap) **********************************************************************/ static const float shorts_per_float = float(32767); -static UHD_INLINE item32_t fc32_to_item32(fc32_t num){ - boost::uint16_t real = boost::int16_t(num.real()*shorts_per_float); - boost::uint16_t imag = boost::int16_t(num.imag()*shorts_per_float); - return (item32_t(real) << 16) | (item32_t(imag) << 0); +#define FC32_TO_SC16_C(num) boost::int16_t(num*shorts_per_float) + +//////////////////////////////////// +// none-swap +//////////////////////////////////// +#if defined(USE_EMMINTRIN_H) +static UHD_INLINE void fc32_to_item32_nswap( + const fc32_t *input, item32_t *output, size_t nsamps +){ + __m128 scalar = _mm_set_ps1(shorts_per_float); + + //convert blocks of samples with intrinsics + size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ + //load from input + __m128 tmplo = _mm_loadu_ps(reinterpret_cast(input+i+0)); + __m128 tmphi = _mm_loadu_ps(reinterpret_cast(input+i+2)); + + //convert and scale + __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); + __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); + + //pack + __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); + + //store to output + _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); + } + + //convert remainder + for (; i < nsamps; i++){ + boost::uint16_t real = FC32_TO_SC16_C(input[i].real()); + boost::uint16_t imag = FC32_TO_SC16_C(input[i].imag()); + output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); + } } +#else static UHD_INLINE void fc32_to_item32_nswap( const fc32_t *input, item32_t *output, size_t nsamps ){ for (size_t i = 0; i < nsamps; i++){ - output[i] = fc32_to_item32(input[i]); + boost::uint16_t real = FC32_TO_SC16_C(input[i].real()); + boost::uint16_t imag = FC32_TO_SC16_C(input[i].imag()); + output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); } } -#if defined(USE_EMMINTRIN_H) -#include +#endif +//////////////////////////////////// +// byte-swap +//////////////////////////////////// +#if defined(USE_EMMINTRIN_H) static UHD_INLINE void fc32_to_item32_bswap( const fc32_t *input, item32_t *output, size_t nsamps ){ @@ -108,7 +153,7 @@ static UHD_INLINE void fc32_to_item32_bswap( __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); - //pack + byteswap -> byteswap 32 bit words + //pack + byteswap -> byteswap 16 bit words __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); @@ -118,7 +163,9 @@ static UHD_INLINE void fc32_to_item32_bswap( //convert remainder for (; i < nsamps; i++){ - output[i] = uhd::byteswap(fc32_to_item32(input[i])); + boost::uint16_t real = BSWAP16_C(FC32_TO_SC16_C(input[i].real())); + boost::uint16_t imag = BSWAP16_C(FC32_TO_SC16_C(input[i].imag())); + output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); } } @@ -127,7 +174,9 @@ static UHD_INLINE void fc32_to_item32_bswap( const fc32_t *input, item32_t *output, size_t nsamps ){ for (size_t i = 0; i < nsamps; i++){ - output[i] = uhd::byteswap(fc32_to_item32(input[i])); + boost::uint16_t real = BSWAP16_C(FC32_TO_SC16_C(input[i].real())); + boost::uint16_t imag = BSWAP16_C(FC32_TO_SC16_C(input[i].imag())); + output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); } } @@ -138,24 +187,60 @@ static UHD_INLINE void fc32_to_item32_bswap( **********************************************************************/ static const float floats_per_short = float(1.0/shorts_per_float); -static UHD_INLINE fc32_t item32_to_fc32(item32_t item){ - return fc32_t( - float(boost::int16_t(item >> 16)*floats_per_short), - float(boost::int16_t(item >> 0)*floats_per_short) - ); +#define I16_TO_FC32_C(num) (boost::int16_t(num)*floats_per_short) + +//////////////////////////////////// +// none-swap +//////////////////////////////////// +#if defined(USE_EMMINTRIN_H) +static UHD_INLINE void item32_to_fc32_nswap( + const item32_t *input, fc32_t *output, size_t nsamps +){ + __m128 scalar = _mm_set_ps1(floats_per_short/(1 << 16)); + __m128i zeroi = _mm_setzero_si128(); + + //convert blocks of samples with intrinsics + size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){ + //load from input + __m128i tmpi = _mm_loadu_si128(reinterpret_cast(input+i)); + + //unpack + __m128i tmpilo = _mm_unpacklo_epi16(zeroi, tmpi); //value in upper 16 bits + __m128i tmpihi = _mm_unpackhi_epi16(zeroi, tmpi); + + //convert and scale + __m128 tmplo = _mm_mul_ps(_mm_cvtepi32_ps(tmpilo), scalar); + __m128 tmphi = _mm_mul_ps(_mm_cvtepi32_ps(tmpihi), scalar); + + //store to output + _mm_storeu_ps(reinterpret_cast(output+i+0), tmplo); + _mm_storeu_ps(reinterpret_cast(output+i+2), tmphi); + } + + //convert remainder + for (; i < nsamps; i++){ + float real = I16_TO_FC32_C(input[i] >> 0); + float imag = I16_TO_FC32_C(input[i] >> 16); + output[i] = fc32_t(real, imag); + } } +#else static UHD_INLINE void item32_to_fc32_nswap( const item32_t *input, fc32_t *output, size_t nsamps ){ for (size_t i = 0; i < nsamps; i++){ - output[i] = item32_to_fc32(input[i]); + float real = I16_TO_FC32_C(input[i] >> 0); + float imag = I16_TO_FC32_C(input[i] >> 16); + output[i] = fc32_t(real, imag); } } +#endif +//////////////////////////////////// +// byte-swap +//////////////////////////////////// #if defined(USE_EMMINTRIN_H) -#include - static UHD_INLINE void item32_to_fc32_bswap( const item32_t *input, fc32_t *output, size_t nsamps ){ @@ -167,7 +252,7 @@ static UHD_INLINE void item32_to_fc32_bswap( //load from input __m128i tmpi = _mm_loadu_si128(reinterpret_cast(input+i)); - //byteswap + unpack -> byteswap 32 bit words + //byteswap + unpack -> byteswap 16 bit words tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8)); __m128i tmpilo = _mm_unpacklo_epi16(zeroi, tmpi); //value in upper 16 bits __m128i tmpihi = _mm_unpackhi_epi16(zeroi, tmpi); @@ -183,7 +268,9 @@ static UHD_INLINE void item32_to_fc32_bswap( //convert remainder for (; i < nsamps; i++){ - output[i] = item32_to_fc32(uhd::byteswap(input[i])); + float real = I16_TO_FC32_C(BSWAP16_C(input[i] >> 0)); + float imag = I16_TO_FC32_C(BSWAP16_C(input[i] >> 16)); + output[i] = fc32_t(real, imag); } } @@ -192,7 +279,9 @@ static UHD_INLINE void item32_to_fc32_bswap( const item32_t *input, fc32_t *output, size_t nsamps ){ for (size_t i = 0; i < nsamps; i++){ - output[i] = item32_to_fc32(uhd::byteswap(input[i])); + float real = I16_TO_FC32_C(BSWAP16_C(input[i] >> 0)); + float imag = I16_TO_FC32_C(BSWAP16_C(input[i] >> 16)); + output[i] = fc32_t(real, imag); } } diff --git a/host/test/convert_types_test.cpp b/host/test/convert_types_test.cpp index 1587be57f..d132a708b 100644 --- a/host/test/convert_types_test.cpp +++ b/host/test/convert_types_test.cpp @@ -17,109 +17,144 @@ #include #include +#include #include +#include #include +#include +#include using namespace uhd; -template -void loopback( +//typedefs for complex types +typedef std::complex sc16_t; +typedef std::complex fc32_t; + +//extract pointer to POD since using &vector.front() throws in MSVC +template void * pod2ptr(T &pod){ + return boost::asio::buffer_cast(boost::asio::buffer(pod)); +} +template const void * pod2ptr(const T &pod){ + return boost::asio::buffer_cast(boost::asio::buffer(pod)); +} + +/*********************************************************************** + * Loopback runner: + * convert input buffer into intermediate buffer + * convert intermediate buffer into output buffer + **********************************************************************/ +template static void loopback( + size_t nsamps, const io_type_t &io_type, const otw_type_t &otw_type, - const host_type *input, - host_type *output + const Range &input, + Range &output ){ - dev_type dev[nsamps]; + //item32 is largest device type + std::vector dev(nsamps); //convert to dev type transport::convert_io_type_to_otw_type( - input, io_type, - dev, otw_type, + pod2ptr(input), io_type, + pod2ptr(dev), otw_type, nsamps ); //convert back to host type transport::convert_otw_type_to_io_type( - dev, otw_type, - output, io_type, + pod2ptr(dev), otw_type, + pod2ptr(output), io_type, nsamps ); } -typedef std::complex sc16_t; +/*********************************************************************** + * Test short conversion + **********************************************************************/ +static void test_convert_types_sc16( + size_t nsamps, + const io_type_t &io_type, + const otw_type_t &otw_type +){ + //fill the input samples + std::vector input(nsamps), output(nsamps); + BOOST_FOREACH(sc16_t &in, input) in = sc16_t( + std::rand()-(RAND_MAX/2), + std::rand()-(RAND_MAX/2) + ); -BOOST_AUTO_TEST_CASE(test_convert_types_be_sc16){ - sc16_t in_sc16[] = { - sc16_t(0, -1234), sc16_t(4321, 1234), - sc16_t(9876, -4567), sc16_t(8912, 0) - }, out_sc16[4]; + //run the loopback and test + loopback(nsamps, io_type, otw_type, input, output); + BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); +} +BOOST_AUTO_TEST_CASE(test_convert_types_be_sc16){ io_type_t io_type(io_type_t::COMPLEX_INT16); otw_type_t otw_type; otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; otw_type.width = 16; - loopback(io_type, otw_type, in_sc16, out_sc16); - BOOST_CHECK_EQUAL_COLLECTIONS(in_sc16, in_sc16+4, out_sc16, out_sc16+4); + //try various lengths to test edge cases + for (size_t nsamps = 0; nsamps < 16; nsamps++){ + test_convert_types_sc16(nsamps, io_type, otw_type); + } } BOOST_AUTO_TEST_CASE(test_convert_types_le_sc16){ - sc16_t in_sc16[] = { - sc16_t(0, -1234), sc16_t(4321, 1234), - sc16_t(9876, -4567), sc16_t(8912, 0) - }, out_sc16[4]; - io_type_t io_type(io_type_t::COMPLEX_INT16); otw_type_t otw_type; otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; otw_type.width = 16; - loopback(io_type, otw_type, in_sc16, out_sc16); - BOOST_CHECK_EQUAL_COLLECTIONS(in_sc16, in_sc16+4, out_sc16, out_sc16+4); + //try various lengths to test edge cases + for (size_t nsamps = 0; nsamps < 16; nsamps++){ + test_convert_types_sc16(nsamps, io_type, otw_type); + } } -typedef std::complex fc32_t; - -#define BOOST_CHECK_CLOSE_COMPLEX(a1, a2, p) \ - BOOST_CHECK_CLOSE(a1.real(), a2.real(), p); \ - BOOST_CHECK_CLOSE(a1.imag(), a2.imag(), p); +/*********************************************************************** + * Test float conversion + **********************************************************************/ +static void test_convert_types_fc32( + size_t nsamps, + const io_type_t &io_type, + const otw_type_t &otw_type +){ + //fill the input samples + std::vector input(nsamps), output(nsamps); + BOOST_FOREACH(fc32_t &in, input) in = fc32_t( + (std::rand()/float(RAND_MAX/2)) - 1, + (std::rand()/float(RAND_MAX/2)) - 1 + ); -static const float tolerance = float(0.1); + //run the loopback and test + loopback(nsamps, io_type, otw_type, input, output); + for (size_t i = 0; i < nsamps; i++){ + BOOST_CHECK_CLOSE_FRACTION(input[i].real(), output[i].real(), float(0.01)); + BOOST_CHECK_CLOSE_FRACTION(input[i].imag(), output[i].imag(), float(0.01)); + } +} BOOST_AUTO_TEST_CASE(test_convert_types_be_fc32){ - fc32_t in_fc32[] = { - fc32_t(float(0), float(-0.2)), fc32_t(float(0.03), float(-0.16)), - fc32_t(float(1.0), float(.45)), fc32_t(float(0.09), float(0)) - }, out_fc32[4]; - io_type_t io_type(io_type_t::COMPLEX_FLOAT32); otw_type_t otw_type; otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; otw_type.width = 16; - loopback(io_type, otw_type, in_fc32, out_fc32); - - BOOST_CHECK_CLOSE_COMPLEX(in_fc32[0], out_fc32[0], tolerance); - BOOST_CHECK_CLOSE_COMPLEX(in_fc32[1], out_fc32[1], tolerance); - BOOST_CHECK_CLOSE_COMPLEX(in_fc32[2], out_fc32[2], tolerance); - BOOST_CHECK_CLOSE_COMPLEX(in_fc32[3], out_fc32[3], tolerance); + //try various lengths to test edge cases + for (size_t nsamps = 0; nsamps < 16; nsamps++){ + test_convert_types_fc32(nsamps, io_type, otw_type); + } } BOOST_AUTO_TEST_CASE(test_convert_types_le_fc32){ - fc32_t in_fc32[] = { - fc32_t(float(0), float(-0.2)), fc32_t(float(0.03), float(-0.16)), - fc32_t(float(1.0), float(.45)), fc32_t(float(0.09), float(0)) - }, out_fc32[4]; - io_type_t io_type(io_type_t::COMPLEX_FLOAT32); otw_type_t otw_type; otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; otw_type.width = 16; - loopback(io_type, otw_type, in_fc32, out_fc32); - - BOOST_CHECK_CLOSE_COMPLEX(in_fc32[0], out_fc32[0], tolerance); - BOOST_CHECK_CLOSE_COMPLEX(in_fc32[1], out_fc32[1], tolerance); - BOOST_CHECK_CLOSE_COMPLEX(in_fc32[2], out_fc32[2], tolerance); - BOOST_CHECK_CLOSE_COMPLEX(in_fc32[3], out_fc32[3], tolerance); + //try various lengths to test edge cases + for (size_t nsamps = 0; nsamps < 16; nsamps++){ + test_convert_types_fc32(nsamps, io_type, otw_type); + } } -- cgit v1.2.3 From 7c057ae28c7dda5f60944fdf79c2bafa081b9bfe Mon Sep 17 00:00:00 2001 From: Matt Ettus Date: Wed, 25 Aug 2010 17:44:17 -0700 Subject: Clean up iq swapping on RX. It is now swapped in the top level. widened muxes to 4 bits to match tx side and handle more ADCs in future --- usrp2/sdr_lib/dsp_core_rx.v | 35 +++++++++++++---------------------- usrp2/top/u2_rev3/u2_core_udp.v | 2 +- usrp2/top/u2_rev3/u2_rev3.v | 8 ++++---- 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/usrp2/sdr_lib/dsp_core_rx.v b/usrp2/sdr_lib/dsp_core_rx.v index 1e689fc7f..1318809d6 100644 --- a/usrp2/sdr_lib/dsp_core_rx.v +++ b/usrp2/sdr_lib/dsp_core_rx.v @@ -57,41 +57,32 @@ module dsp_core_rx (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), .adc_in(adc_b),.adc_out(adc_b_ofs)); - wire [3:0] muxctrl; - setting_reg #(.my_addr(BASE+5)) sr_8 + wire [7:0] muxctrl; + setting_reg #(.my_addr(BASE+5), .width(8)) sr_8 (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out({UNUSED_2,muxctrl}),.changed()); wire [1:0] gpio_ena; - setting_reg #(.my_addr(BASE+6)) sr_9 + setting_reg #(.my_addr(BASE+6), .width(2)) sr_9 (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out({UNUSED_3,gpio_ena}),.changed()); - // The TVRX connects to what is called adc_b, thus A and B are - // swapped throughout the design. - // - // In the interest of expediency and keeping the s/w sane, we just remap them here. - // The I & Q fields are mapped the same: - // 0 -> "the real A" (as determined by the TVRX) - // 1 -> "the real B" - // 2 -> const zero - always @(posedge clk) - case(muxctrl[1:0]) // The I mapping - 0: adc_i <= adc_b_ofs; // "the real A" - 1: adc_i <= adc_a_ofs; + case(muxctrl[3:0]) // The I mapping + 0: adc_i <= adc_a_ofs; + 1: adc_i <= adc_b_ofs; 2: adc_i <= 0; default: adc_i <= 0; - endcase // case(muxctrl[1:0]) - + endcase // case (muxctrl[3:0]) + always @(posedge clk) - case(muxctrl[3:2]) // The Q mapping - 0: adc_q <= adc_b_ofs; // "the real A" - 1: adc_q <= adc_a_ofs; + case(muxctrl[7:4]) // The Q mapping + 0: adc_q <= adc_a_ofs; + 1: adc_q <= adc_b_ofs; 2: adc_q <= 0; default: adc_q <= 0; - endcase // case(muxctrl[3:2]) - + endcase // case (muxctrl[7:4]) + always @(posedge clk) if(rst) phase <= 0; diff --git a/usrp2/top/u2_rev3/u2_core_udp.v b/usrp2/top/u2_rev3/u2_core_udp.v index 124930c23..c9502898b 100644 --- a/usrp2/top/u2_rev3/u2_core_udp.v +++ b/usrp2/top/u2_rev3/u2_core_udp.v @@ -425,7 +425,7 @@ module u2_core cycle_count <= cycle_count + 1; //compatibility number -> increment when the fpga has been sufficiently altered - localparam compat_num = 32'd1; + localparam compat_num = 32'd2; wb_readback_mux buff_pool_status (.wb_clk_i(wb_clk), .wb_rst_i(wb_rst), .wb_stb_i(s5_stb), diff --git a/usrp2/top/u2_rev3/u2_rev3.v b/usrp2/top/u2_rev3/u2_rev3.v index 3a43e4ffe..d5b382c19 100644 --- a/usrp2/top/u2_rev3/u2_rev3.v +++ b/usrp2/top/u2_rev3/u2_rev3.v @@ -205,10 +205,10 @@ module u2_rev3 always @(posedge dsp_clk) begin - adc_a_reg1 <= adc_a; - adc_b_reg1 <= adc_b; - adc_ovf_a_reg1 <= adc_ovf_a; - adc_ovf_b_reg1 <= adc_ovf_b; + adc_a_reg1 <= adc_b; // I and Q on RX are swapped in layout + adc_b_reg1 <= adc_a; + adc_ovf_a_reg1 <= adc_ovf_b; + adc_ovf_b_reg1 <= adc_ovf_a; end always @(posedge dsp_clk) -- cgit v1.2.3 From 9fa6105a49f41e39321438086b00ab12d8437828 Mon Sep 17 00:00:00 2001 From: Matt Ettus Date: Wed, 25 Aug 2010 17:57:06 -0700 Subject: clean up DAC inversion and swapping to match schematics --- usrp2/top/u2_rev3/u2_rev3.v | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/usrp2/top/u2_rev3/u2_rev3.v b/usrp2/top/u2_rev3/u2_rev3.v index d5b382c19..4daa66212 100644 --- a/usrp2/top/u2_rev3/u2_rev3.v +++ b/usrp2/top/u2_rev3/u2_rev3.v @@ -203,9 +203,10 @@ module u2_rev3 reg [13:0] adc_a_reg1, adc_b_reg1, adc_a_reg2, adc_b_reg2; reg adc_ovf_a_reg1, adc_ovf_a_reg2, adc_ovf_b_reg1, adc_ovf_b_reg2; + // ADC A and B are swapped in schematic to facilitate clean layout always @(posedge dsp_clk) begin - adc_a_reg1 <= adc_b; // I and Q on RX are swapped in layout + adc_a_reg1 <= adc_b; adc_b_reg1 <= adc_a; adc_ovf_a_reg1 <= adc_ovf_b; adc_ovf_b_reg1 <= adc_ovf_a; @@ -327,8 +328,10 @@ module u2_rev3 end wire [15:0] dac_a_int, dac_b_int; - always @(negedge dsp_clk) dac_a <= dac_a_int; - always @(negedge dsp_clk) dac_b <= dac_b_int; + // DAC A and B are swapped in schematic to facilitate clean layout + // DAC A is also inverted in schematic to facilitate clean layout + always @(negedge dsp_clk) dac_a <= ~dac_b_int; + always @(negedge dsp_clk) dac_b <= dac_a_int; /* OFDDRRSE OFDDRRSE_serdes_inst -- cgit v1.2.3 From fb1f8e1abbd349b1ef42853cd1a312ae80fbdaef Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 25 Aug 2010 18:08:03 -0700 Subject: usrp2: changes to mux calculation routine and usrp2 fpga compat number --- host/lib/usrp/dsp_utils.cpp | 30 ++++++++++++++------ host/lib/usrp/usrp2/fw_common.h | 2 +- host/lib/usrp/usrp2/usrp2_regs.hpp | 56 -------------------------------------- 3 files changed, 23 insertions(+), 65 deletions(-) diff --git a/host/lib/usrp/dsp_utils.cpp b/host/lib/usrp/dsp_utils.cpp index fe1313af1..10ae9a086 100644 --- a/host/lib/usrp/dsp_utils.cpp +++ b/host/lib/usrp/dsp_utils.cpp @@ -30,22 +30,36 @@ template T ceil_log2(T num){ return std::ceil(std::log(num)/std::log(T(2))); } +/*! + * 3 2 1 0 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-------------------------------+-------+-------+-------+-------+ + * | | DDC0Q | DDC0I | + * +-------------------------------+-------+-------+-------+-------+ + */ boost::uint32_t dsp_type1::calc_rx_mux_word(subdev_conn_t subdev_conn){ switch(subdev_conn){ - case SUBDEV_CONN_COMPLEX_IQ: return (0x1 << 2) | (0x0 << 0); //DDC0Q=ADC1, DDC0I=ADC0 - case SUBDEV_CONN_COMPLEX_QI: return (0x0 << 2) | (0x1 << 0); //DDC0Q=ADC0, DDC0I=ADC1 - case SUBDEV_CONN_REAL_I: return (0x3 << 2) | (0x0 << 0); //DDC0Q=ZERO, DDC0I=ADC0 - case SUBDEV_CONN_REAL_Q: return (0x1 << 2) | (0x3 << 0); //DDC0Q=ADC1, DDC0I=ZERO + case SUBDEV_CONN_COMPLEX_IQ: return (0x1 << 4) | (0x0 << 0); //DDC0Q=ADC0Q, DDC0I=ADC0I + case SUBDEV_CONN_COMPLEX_QI: return (0x0 << 4) | (0x1 << 0); //DDC0Q=ADC0I, DDC0I=ADC0Q + case SUBDEV_CONN_REAL_I: return (0xf << 4) | (0x0 << 0); //DDC0Q=ZERO, DDC0I=ADC0I + case SUBDEV_CONN_REAL_Q: return (0x1 << 4) | (0xf << 0); //DDC0Q=ADC0Q, DDC0I=ZERO default: UHD_THROW_INVALID_CODE_PATH(); } } +/*! + * 3 2 1 0 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-------------------------------+-------+-------+-------+-------+ + * | | DAC0Q | DAC0I | + * +-------------------------------+-------+-------+-------+-------+ + */ boost::uint32_t dsp_type1::calc_tx_mux_word(subdev_conn_t subdev_conn){ switch(subdev_conn){ - case SUBDEV_CONN_COMPLEX_IQ: return (0x1 << 4) | (0x0 << 0); //DAC1=DUC0Q, DAC0=DUC0I - case SUBDEV_CONN_COMPLEX_QI: return (0x0 << 4) | (0x1 << 0); //DAC1=DUC0I, DAC0=DUC0Q - case SUBDEV_CONN_REAL_I: return (0xf << 4) | (0x0 << 0); //DAC1=ZERO, DAC0=DUC0I - case SUBDEV_CONN_REAL_Q: return (0x0 << 4) | (0xf << 0); //DAC1=DUC0I, DAC0=ZERO + case SUBDEV_CONN_COMPLEX_IQ: return (0x1 << 4) | (0x0 << 0); //DAC0Q=DUC0Q, DAC0I=DUC0I + case SUBDEV_CONN_COMPLEX_QI: return (0x0 << 4) | (0x1 << 0); //DAC0Q=DUC0I, DAC0I=DUC0Q + case SUBDEV_CONN_REAL_I: return (0xf << 4) | (0x0 << 0); //DAC0Q=ZERO, DAC0I=DUC0I + case SUBDEV_CONN_REAL_Q: return (0x0 << 4) | (0xf << 0); //DAC0Q=DUC0I, DAC0I=ZERO default: UHD_THROW_INVALID_CODE_PATH(); } } diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index cc6c41ba7..e812e1221 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -33,7 +33,7 @@ extern "C" { #endif //fpga and firmware compatibility numbers -#define USRP2_FPGA_COMPAT_NUM 1 +#define USRP2_FPGA_COMPAT_NUM 2 #define USRP2_FW_COMPAT_NUM 6 //used to differentiate control packets over data port diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index 9d306090b..064ad4e95 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -124,41 +124,6 @@ #define U2_REG_DSP_TX_FREQ _SR_ADDR(SR_TX_DSP + 0) #define U2_REG_DSP_TX_SCALE_IQ _SR_ADDR(SR_TX_DSP + 1) // {scale_i,scale_q} #define U2_REG_DSP_TX_INTERP_RATE _SR_ADDR(SR_TX_DSP + 2) - - /*! - * \brief output mux configuration. - * - *
-   *     3                   2                   1                       
-   *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
-   *  +-------------------------------+-------+-------+-------+-------+
-   *  |                                               | DAC1  |  DAC0 |
-   *  +-------------------------------+-------+-------+-------+-------+
-   * 
-   *  There are N DUCs (1 now) with complex inputs and outputs.
-   *  There are two DACs.
-   * 
-   *  Each 4-bit DACx field specifies the source for the DAC
-   *  Each subfield is coded like this: 
-   * 
-   *     3 2 1 0
-   *    +-------+
-   *    |   N   |
-   *    +-------+
-   * 
-   *  N specifies which DUC output is connected to this DAC.
-   * 
-   *   N   which interp output
-   *  ---  -------------------
-   *   0   DUC 0 I
-   *   1   DUC 0 Q
-   *   2   DUC 1 I
-   *   3   DUC 1 Q
-   *   F   All Zeros
-   *   
-   * The default value is 0x10
-   * 
- */ #define U2_REG_DSP_TX_MUX _SR_ADDR(SR_TX_DSP + 4) ///////////////////////////////////////////////// @@ -170,27 +135,6 @@ #define U2_REG_DSP_RX_DCOFFSET_I _SR_ADDR(SR_RX_DSP + 3) // Bit 31 high sets fixed offset mode, using lower 14 bits, // otherwise it is automatic #define U2_REG_DSP_RX_DCOFFSET_Q _SR_ADDR(SR_RX_DSP + 4) // Bit 31 high sets fixed offset mode, using lower 14 bits - /*! - * \brief input mux configuration. - * - * This determines which ADC (or constant zero) is connected to - * each DDC input. There are N DDCs (1 now). Each has two inputs. - * - *
-   * Mux value:
-   *
-   *    3                   2                   1                       
-   *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
-   * +-------+-------+-------+-------+-------+-------+-------+-------+
-   * |                                                       |Q0 |I0 |
-   * +-------+-------+-------+-------+-------+-------+-------+-------+
-   *
-   * Each 2-bit I field is either 00 (A/D A), 01 (A/D B) or 1X (const zero)
-   * Each 2-bit Q field is either 00 (A/D A), 01 (A/D B) or 1X (const zero)
-   *
-   * The default value is 0x4
-   * 
- */ #define U2_REG_DSP_RX_MUX _SR_ADDR(SR_RX_DSP + 5) // called adc_mux in dsp_core_rx.v //////////////////////////////////////////////// -- cgit v1.2.3 From 738f4a86558aca8d2fdfecd480613766bfc82510 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 25 Aug 2010 21:15:17 -0700 Subject: uhd: switched the IQ order interpretation for convert types --- host/lib/transport/convert_types_impl.hpp | 66 ++++++++++++++----------------- 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/host/lib/transport/convert_types_impl.hpp b/host/lib/transport/convert_types_impl.hpp index 641029795..fdc859883 100644 --- a/host/lib/transport/convert_types_impl.hpp +++ b/host/lib/transport/convert_types_impl.hpp @@ -32,9 +32,6 @@ #include #endif -//! shortcut for a byteswap16 with casting -#define BSWAP16_C(num) uhd::byteswap(boost::uint16_t(num)) - /*********************************************************************** * Typedefs **********************************************************************/ @@ -54,10 +51,9 @@ static UHD_INLINE void sc16_to_item32_nswap( static UHD_INLINE void sc16_to_item32_bswap( const sc16_t *input, item32_t *output, size_t nsamps ){ + const item32_t *item32_input = (const item32_t *)input; for (size_t i = 0; i < nsamps; i++){ - boost::uint16_t real = BSWAP16_C(input[i].real()); - boost::uint16_t imag = BSWAP16_C(input[i].imag()); - output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); + output[i] = uhd::byteswap(item32_input[i]); } } @@ -73,10 +69,9 @@ static UHD_INLINE void item32_to_sc16_nswap( static UHD_INLINE void item32_to_sc16_bswap( const item32_t *input, sc16_t *output, size_t nsamps ){ + item32_t *item32_output = (item32_t *)output; for (size_t i = 0; i < nsamps; i++){ - boost::int16_t real = BSWAP16_C(input[i] >> 0); - boost::int16_t imag = BSWAP16_C(input[i] >> 16); - output[i] = sc16_t(real, imag); + item32_output[i] = uhd::byteswap(input[i]); } } @@ -85,7 +80,11 @@ static UHD_INLINE void item32_to_sc16_bswap( **********************************************************************/ static const float shorts_per_float = float(32767); -#define FC32_TO_SC16_C(num) boost::int16_t(num*shorts_per_float) +static UHD_INLINE item32_t fc32_to_item32(fc32_t num){ + boost::uint16_t real = boost::int16_t(num.real()*shorts_per_float); + boost::uint16_t imag = boost::int16_t(num.imag()*shorts_per_float); + return (item32_t(real) << 16) | (item32_t(imag) << 0); +} //////////////////////////////////// // none-swap @@ -106,8 +105,10 @@ static UHD_INLINE void fc32_to_item32_nswap( __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar)); __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar)); - //pack + //pack + swap 16-bit pairs __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi); + tmpi = _mm_shufflelo_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); + tmpi = _mm_shufflehi_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); //store to output _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi); @@ -115,9 +116,7 @@ static UHD_INLINE void fc32_to_item32_nswap( //convert remainder for (; i < nsamps; i++){ - boost::uint16_t real = FC32_TO_SC16_C(input[i].real()); - boost::uint16_t imag = FC32_TO_SC16_C(input[i].imag()); - output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); + output[i] = fc32_to_item32(input[i]); } } @@ -126,9 +125,7 @@ static UHD_INLINE void fc32_to_item32_nswap( const fc32_t *input, item32_t *output, size_t nsamps ){ for (size_t i = 0; i < nsamps; i++){ - boost::uint16_t real = FC32_TO_SC16_C(input[i].real()); - boost::uint16_t imag = FC32_TO_SC16_C(input[i].imag()); - output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); + output[i] = fc32_to_item32(input[i]); } } @@ -163,9 +160,7 @@ static UHD_INLINE void fc32_to_item32_bswap( //convert remainder for (; i < nsamps; i++){ - boost::uint16_t real = BSWAP16_C(FC32_TO_SC16_C(input[i].real())); - boost::uint16_t imag = BSWAP16_C(FC32_TO_SC16_C(input[i].imag())); - output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); + output[i] = uhd::byteswap(fc32_to_item32(input[i])); } } @@ -174,9 +169,7 @@ static UHD_INLINE void fc32_to_item32_bswap( const fc32_t *input, item32_t *output, size_t nsamps ){ for (size_t i = 0; i < nsamps; i++){ - boost::uint16_t real = BSWAP16_C(FC32_TO_SC16_C(input[i].real())); - boost::uint16_t imag = BSWAP16_C(FC32_TO_SC16_C(input[i].imag())); - output[i] = (item32_t(real) << 0) | (item32_t(imag) << 16); + output[i] = uhd::byteswap(fc32_to_item32(input[i])); } } @@ -187,7 +180,12 @@ static UHD_INLINE void fc32_to_item32_bswap( **********************************************************************/ static const float floats_per_short = float(1.0/shorts_per_float); -#define I16_TO_FC32_C(num) (boost::int16_t(num)*floats_per_short) +static UHD_INLINE fc32_t item32_to_fc32(item32_t item){ + return fc32_t( + float(boost::int16_t(item >> 16)*floats_per_short), + float(boost::int16_t(item >> 0)*floats_per_short) + ); +} //////////////////////////////////// // none-swap @@ -204,7 +202,9 @@ static UHD_INLINE void item32_to_fc32_nswap( //load from input __m128i tmpi = _mm_loadu_si128(reinterpret_cast(input+i)); - //unpack + //unpack + swap 16-bit pairs + tmpi = _mm_shufflelo_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); + tmpi = _mm_shufflehi_epi16(tmpi, _MM_SHUFFLE(2, 3, 0, 1)); __m128i tmpilo = _mm_unpacklo_epi16(zeroi, tmpi); //value in upper 16 bits __m128i tmpihi = _mm_unpackhi_epi16(zeroi, tmpi); @@ -219,9 +219,7 @@ static UHD_INLINE void item32_to_fc32_nswap( //convert remainder for (; i < nsamps; i++){ - float real = I16_TO_FC32_C(input[i] >> 0); - float imag = I16_TO_FC32_C(input[i] >> 16); - output[i] = fc32_t(real, imag); + output[i] = item32_to_fc32(input[i]); } } @@ -230,9 +228,7 @@ static UHD_INLINE void item32_to_fc32_nswap( const item32_t *input, fc32_t *output, size_t nsamps ){ for (size_t i = 0; i < nsamps; i++){ - float real = I16_TO_FC32_C(input[i] >> 0); - float imag = I16_TO_FC32_C(input[i] >> 16); - output[i] = fc32_t(real, imag); + output[i] = item32_to_fc32(input[i]); } } #endif @@ -268,9 +264,7 @@ static UHD_INLINE void item32_to_fc32_bswap( //convert remainder for (; i < nsamps; i++){ - float real = I16_TO_FC32_C(BSWAP16_C(input[i] >> 0)); - float imag = I16_TO_FC32_C(BSWAP16_C(input[i] >> 16)); - output[i] = fc32_t(real, imag); + output[i] = item32_to_fc32(uhd::byteswap(input[i])); } } @@ -279,9 +273,7 @@ static UHD_INLINE void item32_to_fc32_bswap( const item32_t *input, fc32_t *output, size_t nsamps ){ for (size_t i = 0; i < nsamps; i++){ - float real = I16_TO_FC32_C(BSWAP16_C(input[i] >> 0)); - float imag = I16_TO_FC32_C(BSWAP16_C(input[i] >> 16)); - output[i] = fc32_t(real, imag); + output[i] = item32_to_fc32(uhd::byteswap(input[i])); } } -- cgit v1.2.3 From 687e118eefd7e35e3a094152a51927bd82ac030d Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Thu, 26 Aug 2010 11:16:46 -0700 Subject: usrp1: Modifiy USB interfaces to use new device handle The interface previously defined a descriptor type, which is now replaced with a generalized handle. This change provides more flexibility in implementations that may pass internal representations of device handles or identifier objects. --- host/include/uhd/transport/CMakeLists.txt | 1 + host/include/uhd/transport/usb_control.hpp | 17 +---- host/include/uhd/transport/usb_device_handle.hpp | 79 ++++++++++++++++++++++++ host/include/uhd/transport/usb_zero_copy.hpp | 8 +-- host/include/uhd/types/CMakeLists.txt | 1 - host/include/uhd/types/usb_descriptor.hpp | 49 --------------- 6 files changed, 86 insertions(+), 69 deletions(-) create mode 100644 host/include/uhd/transport/usb_device_handle.hpp delete mode 100644 host/include/uhd/types/usb_descriptor.hpp diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index dd1a20eed..0f1cbf2a2 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -27,6 +27,7 @@ INSTALL(FILES udp_zero_copy.hpp usb_control.hpp usb_zero_copy.hpp + usb_device_handle.hpp vrt_if_packet.hpp zero_copy.hpp DESTINATION ${INCLUDE_DIR}/uhd/transport diff --git a/host/include/uhd/transport/usb_control.hpp b/host/include/uhd/transport/usb_control.hpp index 6b5591a21..6137ecf84 100644 --- a/host/include/uhd/transport/usb_control.hpp +++ b/host/include/uhd/transport/usb_control.hpp @@ -18,11 +18,7 @@ #ifndef INCLUDED_UHD_TRANSPORT_USB_CONTROL_HPP #define INCLUDED_UHD_TRANSPORT_USB_CONTROL_HPP -#include -#include -#include -#include -#include +#include "usb_device_handle.hpp" namespace uhd { namespace transport { @@ -35,9 +31,9 @@ public: * This transport is for sending and receiving control information from * the host to device using the Default Control Pipe. * - * \param descriptor a descriptor that identifies a USB device + * \param handle a device handle that uniquely identifies a USB device */ - static sptr make(usb_descriptor_t descriptor); + static sptr make(usb_device_handle::sptr handle); /*! * Submit a USB device request: @@ -62,13 +58,6 @@ public: boost::uint16_t index, unsigned char *buff, boost::uint16_t length) = 0; - - /*! - * Get a vector of USB device descriptors - * - * \return a vector of usb_descriptors - */ - static usb_descriptors_t get_device_list(); }; }} //namespace diff --git a/host/include/uhd/transport/usb_device_handle.hpp b/host/include/uhd/transport/usb_device_handle.hpp new file mode 100644 index 000000000..78c78f6b5 --- /dev/null +++ b/host/include/uhd/transport/usb_device_handle.hpp @@ -0,0 +1,79 @@ +// +// Copyright 2010 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 . +// + +#ifndef INCLUDED_UHD_TRANSPORT_USB_DEVICE_HANDLE_HPP +#define INCLUDED_UHD_TRANSPORT_USB_DEVICE_HANDLE_HPP + +#include +#include +#include +#include +#include + +namespace uhd { namespace transport { + +/*! + * Device handle class that represents a USB device + * Used for identifying devices on the USB bus and selecting which device is + * used when creating a USB transport. A minimal subset of USB descriptor + * fields are used. Fields can be found in the USB 2.0 specification Table + * 9-8 (Standard Device Descriptor). In addition to fields of the device + * descriptor, the interface returns the device's USB device address. + * + * Note: The USB 2.0 Standard Device Descriptor contains an index rather then + * a true descriptor serial number string. This interface returns the + * actual string descriptor. + */ +class UHD_API usb_device_handle : boost::noncopyable { +public: + typedef boost::shared_ptr sptr; + + /*! + * Return the device's serial number + * \return a string describing the device's serial number + */ + virtual UHD_API std::string get_serial() const = 0; + + /*! + * Return the device's Vendor ID (usually assigned by the USB-IF) + * \return a Vendor ID + */ + virtual UHD_API boost::uint16_t get_vendor_id() const = 0; + + /*! + * Return the device's Product ID (usually assigned by manufacturer) + * \return a Product ID + */ + virtual UHD_API boost::uint16_t get_product_id() const = 0; + + /*! + * Return the device's USB address + * \return a Product ID + */ + virtual UHD_API boost::uint16_t get_device_addr() const = 0; + + /*! + * Return a vector of USB devices on this host + * \return a vector of USB device handles + */ + static UHD_API std::vector get_device_list(); + +}; //namespace usb + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_USB_DEVICE_HANDLE_HPP */ diff --git a/host/include/uhd/transport/usb_zero_copy.hpp b/host/include/uhd/transport/usb_zero_copy.hpp index 7b9692fa5..2edd6d91d 100644 --- a/host/include/uhd/transport/usb_zero_copy.hpp +++ b/host/include/uhd/transport/usb_zero_copy.hpp @@ -18,10 +18,8 @@ #ifndef INCLUDED_UHD_TRANSPORT_USB_ZERO_COPY_HPP #define INCLUDED_UHD_TRANSPORT_USB_ZERO_COPY_HPP -#include -#include +#include "usb_device_handle.hpp" #include -#include namespace uhd { namespace transport { @@ -46,13 +44,13 @@ public: * The primary usage for this transport is data transactions. * The underlying implementation may be platform specific. * - * \param descriptor a USB descriptor identifying the device + * \param handle a device handle that uniquely identifying the device * \param rx_endpoint an integer specifiying an IN endpoint number * \param tx_endpoint an integer specifiying an OUT endpoint number * \param buff_size total number of bytes of buffer space to allocate * \param block_size number of bytes allocated for each I/O transaction */ - static sptr make(usb_descriptor_t descriptor, + static sptr make(usb_device_handle::sptr handle, unsigned int rx_endpoint, unsigned int tx_endpoint, size_t buff_size = 0, diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt index 8e302eed2..dbce21c98 100644 --- a/host/include/uhd/types/CMakeLists.txt +++ b/host/include/uhd/types/CMakeLists.txt @@ -29,6 +29,5 @@ INSTALL(FILES stream_cmd.hpp time_spec.hpp tune_result.hpp - usb_descriptor.hpp DESTINATION ${INCLUDE_DIR}/uhd/types ) diff --git a/host/include/uhd/types/usb_descriptor.hpp b/host/include/uhd/types/usb_descriptor.hpp deleted file mode 100644 index 0e4c8c369..000000000 --- a/host/include/uhd/types/usb_descriptor.hpp +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright 2010 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 . -// - -#ifndef INCLUDED_UHD_TYPES_USB_DESCRIPTOR_HPP -#define INCLUDED_UHD_TYPES_USB_DESCRIPTOR_HPP - -#include -#include -#include -#include - -namespace uhd{ - - /*! - * The USB descriptor struct holds identity information for a USB device - */ - struct UHD_API usb_descriptor_t{ - std::string serial; - boost::uint16_t vendor_id; - boost::uint16_t product_id; - boost::uint16_t device_addr; - - /*! - * Create a pretty print string for this USB descriptor struct. - * \return the printable string - */ - std::string to_pp_string(void) const; - }; - - //handy typde for a vector of usb descriptors - typedef std::vector usb_descriptors_t; - -} //namespace uhd - -#endif /* INCLUDED_UHD_TYPES_USB_DESCRIPTOR_HPP */ -- cgit v1.2.3 From fe7df530e69834e974108d2c3e682f38b8a75524 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Thu, 26 Aug 2010 12:21:50 -0700 Subject: usrp1: Modifiy USB transport implementations to use new interface Common libusb1 code is consolidated in the libusb base file. --- host/lib/transport/CMakeLists.txt | 2 + host/lib/transport/libusb1_base.cpp | 118 +++++++++++++++++++ host/lib/transport/libusb1_base.hpp | 42 +++++++ host/lib/transport/libusb1_control.cpp | 170 ++------------------------- host/lib/transport/libusb1_device_handle.cpp | 114 ++++++++++++++++++ host/lib/transport/libusb1_zero_copy.cpp | 153 +++--------------------- host/lib/usrp/usrp1/usrp1_impl.cpp | 37 +++--- 7 files changed, 322 insertions(+), 314 deletions(-) create mode 100644 host/lib/transport/libusb1_base.cpp create mode 100644 host/lib/transport/libusb1_base.hpp create mode 100644 host/lib/transport/libusb1_device_handle.cpp diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index 627d2d806..753fd5e85 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -29,6 +29,8 @@ IF(LIBUSB_FOUND) LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_control.cpp ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_zero_copy.cpp + ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_base.cpp + ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_device_handle.cpp ) SET(HAVE_USB_SUPPORT TRUE) ENDIF(LIBUSB_FOUND) diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp new file mode 100644 index 000000000..6965de214 --- /dev/null +++ b/host/lib/transport/libusb1_base.cpp @@ -0,0 +1,118 @@ +// +// Copyright 2010 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 . +// + +#include "libusb1_base.hpp" +#include + +using namespace uhd::transport; + +void libusb::init(libusb_context **ctx, int debug_level) +{ + if (libusb_init(ctx) < 0) + std::cerr << "error: libusb_init" << std::endl; + + libusb_set_debug(*ctx, debug_level); +} + + +libusb_device_handle *libusb::open_device(libusb_context *ctx, + usb_device_handle::sptr handle) +{ + libusb_device **dev_list; + libusb_device_handle *dev_handle; + + ssize_t dev_cnt = libusb_get_device_list(ctx, &dev_list); + + //find and open the receive device + for (ssize_t i = 0; i < dev_cnt; i++) { + libusb_device *dev = dev_list[i]; + + if (compare_device(dev, handle)) { + libusb_open(dev, &dev_handle); + break; + } + } + + libusb_free_device_list(dev_list, 0); + + return dev_handle; +} + + +bool libusb::compare_device(libusb_device *dev, + usb_device_handle::sptr handle) +{ + std::string serial = handle->get_serial(); + boost::uint16_t vendor_id = handle->get_vendor_id(); + boost::uint16_t product_id = handle->get_product_id(); + boost::uint8_t device_addr = handle->get_device_addr(); + + libusb_device_descriptor libusb_desc; + if (libusb_get_device_descriptor(dev, &libusb_desc) < 0) + return false; + if (serial != get_serial(dev)) + return false; + if (vendor_id != libusb_desc.idVendor) + return false; + if (product_id != libusb_desc.idProduct) + return false; + if (device_addr != libusb_get_device_address(dev)) + return false; + + return true; +} + + +bool libusb::open_interface(libusb_device_handle *dev_handle, + int interface) +{ + int ret = libusb_claim_interface(dev_handle, interface); + if (ret < 0) { + std::cerr << "error: libusb_claim_interface() " << ret << std::endl; + return false; + } + else { + return true; + } +} + + +std::string libusb::get_serial(libusb_device *dev) +{ + unsigned char buff[32]; + + libusb_device_descriptor desc; + if (libusb_get_device_descriptor(dev, &desc) < 0) + return ""; + + if (desc.iSerialNumber == 0) + return ""; + + //open the device because we have to + libusb_device_handle *dev_handle; + if (libusb_open(dev, &dev_handle) < 0) + return ""; + + if (libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber, + buff, sizeof(buff)) < 0) { + return ""; + } + + libusb_close(dev_handle); + + return (char*) buff; +} diff --git a/host/lib/transport/libusb1_base.hpp b/host/lib/transport/libusb1_base.hpp new file mode 100644 index 000000000..ae560cd52 --- /dev/null +++ b/host/lib/transport/libusb1_base.hpp @@ -0,0 +1,42 @@ +// +// Copyright 2010 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 . +// + +#ifndef INCLUDED_TRANSPORT_LIBUSB_HPP +#define INCLUDED_TRANSPORT_LIBUSB_HPP + +#include +#include +#include + +namespace uhd { namespace transport { + +namespace libusb { + void init(libusb_context **ctx, int debug_level); + + libusb_device_handle *open_device(libusb_context *ctx, + usb_device_handle::sptr handle); + + bool compare_device(libusb_device *dev, usb_device_handle::sptr handle); + + bool open_interface(libusb_device_handle *dev_handle, int interface); + + std::string get_serial(libusb_device *dev); +} + +}} //namespace + +#endif /* INCLUDED_TRANSPORT_LIBUSB_HPP */ diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp index c2f7060e8..8bf271256 100644 --- a/host/lib/transport/libusb1_control.cpp +++ b/host/lib/transport/libusb1_control.cpp @@ -15,24 +15,20 @@ // along with this program. If not, see . // -#include +#include "libusb1_base.hpp" #include -#include -#include -#include -#include using namespace uhd::transport; -static int libusb_debug_level = 0; -static int libusb_timeout = 0; +const int libusb_debug_level = 3; +const int libusb_timeout = 0; /*********************************************************************** * libusb-1.0 implementation of USB control transport **********************************************************************/ class libusb_control_impl : public usb_control { public: - libusb_control_impl(uhd::usb_descriptor_t descriptor); + libusb_control_impl(usb_device_handle::sptr handle); ~libusb_control_impl(); size_t submit(boost::uint8_t request_type, @@ -42,34 +38,19 @@ public: unsigned char *buff, boost::uint16_t length); - static uhd::usb_descriptor_t create_descriptor(libusb_device *dev); - static std::string get_serial(libusb_device *dev); - private: - uhd::usb_descriptor_t _descriptor; - libusb_context *_ctx; libusb_device_handle *_dev_handle; - - bool open_device(); - bool open_interface(); - bool compare_device(libusb_device *dev, uhd::usb_descriptor_t descriptor); }; -libusb_control_impl::libusb_control_impl(uhd::usb_descriptor_t descriptor) - : _descriptor(descriptor), _ctx(NULL), _dev_handle(NULL) +libusb_control_impl::libusb_control_impl(usb_device_handle::sptr handle) { - if (libusb_init(&_ctx) < 0) - throw std::runtime_error("USB: failed to initialize libusb"); + libusb::init(&_ctx, libusb_debug_level); - libusb_set_debug(_ctx, libusb_debug_level); + _dev_handle = libusb::open_device(_ctx, handle); - if (!open_device()) - throw std::runtime_error("USB: failed to open device"); - - if (!open_interface()) - throw std::runtime_error("USB: failed to open device interface"); + libusb::open_interface(_dev_handle, 0); } @@ -80,111 +61,6 @@ libusb_control_impl::~libusb_control_impl() } -uhd::usb_descriptor_t libusb_control_impl::create_descriptor(libusb_device *dev) -{ - libusb_device_descriptor desc; - - if (libusb_get_device_descriptor(dev, &desc) < 0) - throw std::runtime_error("USB: failed to get device descriptor"); - - uhd::usb_descriptor_t descriptor; - - descriptor.serial = get_serial(dev); - descriptor.product_id = desc.idProduct; - descriptor.vendor_id = desc.idVendor; - descriptor.device_addr = libusb_get_device_address(dev); - - return descriptor; -} - - -std::string libusb_control_impl::get_serial(libusb_device *dev) -{ - unsigned char buff[32]; - - libusb_device_descriptor desc; - if (libusb_get_device_descriptor(dev, &desc) < 0) - return ""; - - if (desc.iSerialNumber == 0) - return ""; - - //open the device because we have to - libusb_device_handle *dev_handle; - if (libusb_open(dev, &dev_handle) < 0) - return ""; - - if (libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber, - buff, sizeof(buff)) < 0) { - return ""; - } - - libusb_close(dev_handle); - - return (char*) buff; -} - - -bool libusb_control_impl::open_device() -{ - libusb_device **list; - libusb_device *dev; - - ssize_t cnt = libusb_get_device_list(_ctx, &list); - - if (cnt < 0) - return cnt; - - ssize_t i = 0; - for (i = 0; i < cnt; i++) { - dev = list[i]; - if (compare_device(dev, _descriptor)) - goto found; - } - return false; - -found: - int ret; - if ((ret = libusb_open(dev, &_dev_handle)) < 0) - return false; - else - return true; -} - - -bool libusb_control_impl::compare_device(libusb_device *dev, - uhd::usb_descriptor_t descriptor) -{ - std::string serial = descriptor.serial; - boost::uint16_t vendor_id = descriptor.vendor_id; - boost::uint16_t product_id = descriptor.product_id; - boost::uint8_t device_addr = descriptor.device_addr; - - libusb_device_descriptor libusb_desc; - if (libusb_get_device_descriptor(dev, &libusb_desc) < 0) - return false; - if (serial != get_serial(dev)) - return false; - if (vendor_id != libusb_desc.idVendor) - return false; - if (product_id != libusb_desc.idProduct) - return false; - if (device_addr != libusb_get_device_address(dev)) - return false; - - return true; -} - - -bool libusb_control_impl::open_interface() -{ - if (libusb_claim_interface(_dev_handle, 0) < 0) - return false; - else - return true; -} - - size_t libusb_control_impl::submit(boost::uint8_t request_type, boost::uint8_t request, boost::uint16_t value, @@ -206,33 +82,7 @@ size_t libusb_control_impl::submit(boost::uint8_t request_type, /*********************************************************************** * USB control public make functions **********************************************************************/ -usb_control::sptr usb_control::make(uhd::usb_descriptor_t descriptor) +usb_control::sptr usb_control::make(usb_device_handle::sptr handle) { - return sptr(new libusb_control_impl(descriptor)); + return sptr(new libusb_control_impl(handle)); } - -uhd::usb_descriptors_t usb_control::get_device_list() -{ - libusb_device **list; - uhd::usb_descriptors_t descriptors; - - if (libusb_init(NULL) < 0) - throw std::runtime_error("USB: failed to initialize libusb"); - - ssize_t cnt = libusb_get_device_list(NULL, &list); - - if (cnt < 0) - throw std::runtime_error("USB: failed to get device list"); - - ssize_t i = 0; - for (i = 0; i < cnt; i++) { - libusb_device *dev = list[i]; - descriptors.push_back(libusb_control_impl::create_descriptor(dev)); - } - - libusb_free_device_list(list, 0); - libusb_exit(NULL); - return descriptors; -} - - diff --git a/host/lib/transport/libusb1_device_handle.cpp b/host/lib/transport/libusb1_device_handle.cpp new file mode 100644 index 000000000..f80090f15 --- /dev/null +++ b/host/lib/transport/libusb1_device_handle.cpp @@ -0,0 +1,114 @@ +// +// Copyright 2010 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 . +// + +#include "libusb1_base.hpp" +#include + +using namespace uhd::transport; + +const int libusb_debug_level = 3; + +class libusb1_device_handle_impl : public usb_device_handle { +public: + libusb1_device_handle_impl(std::string serial, + boost::uint32_t product_id, + boost::uint32_t vendor_id, + boost::uint32_t device_addr) + : _serial(serial), _product_id(product_id), + _vendor_id(vendor_id), _device_addr(device_addr) + { + /* NOP */ + } + + ~libusb1_device_handle_impl() + { + /* NOP */ + } + + std::string get_serial() const + { + return _serial; + } + + boost::uint16_t get_vendor_id() const + { + return _vendor_id; + } + + + boost::uint16_t get_product_id() const + { + return _product_id; + } + + boost::uint16_t get_device_addr() const + { + return _device_addr; + } + +private: + std::string _serial; + boost::uint32_t _product_id; + boost::uint32_t _vendor_id; + boost::uint32_t _device_addr; +}; + + +usb_device_handle::sptr make_usb_device_handle(libusb_device *dev) +{ + libusb_device_descriptor desc; + + if (libusb_get_device_descriptor(dev, &desc) < 0) { + UHD_ASSERT_THROW("USB: failed to get device descriptor"); + } + + std::string serial = libusb::get_serial(dev); + boost::uint32_t product_id = desc.idProduct; + boost::uint32_t vendor_id = desc.idVendor; + boost::uint32_t device_addr = libusb_get_device_address(dev); + + return usb_device_handle::sptr(new libusb1_device_handle_impl( + serial, + product_id, + vendor_id, + device_addr)); +} + + +std::vector usb_device_handle::get_device_list() +{ + libusb_context *ctx = NULL; + libusb_device **list; + std::vector device_list; + + libusb::init(&ctx, libusb_debug_level); + + ssize_t cnt = libusb_get_device_list(ctx, &list); + + if (cnt < 0) + throw std::runtime_error("USB: enumeration failed"); + + ssize_t i = 0; + for (i = 0; i < cnt; i++) { + libusb_device *dev = list[i]; + device_list.push_back(make_usb_device_handle(dev)); + } + + libusb_free_device_list(list, 0); + libusb_exit(ctx); + return device_list; +} diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 39617e4dd..55aa10cbb 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -15,10 +15,9 @@ // along with this program. If not, see . // - +#include "libusb1_base.hpp" #include #include -#include #include #include #include @@ -26,7 +25,8 @@ using namespace uhd::transport; -static int libusb_debug_level = 3; +const int libusb_debug_level = 3; +const int libusb_timeout = 0; /*********************************************************************** * Helper functions @@ -347,7 +347,7 @@ void usb_endpoint::print_transfer_status(libusb_transfer *lut) std::cerr << "USB: transfer timed out" << std::endl; break; case LIBUSB_TRANSFER_STALL: - std::cerr << "USB: halt condition detected (endpoint stalled)" << std::endl; + std::cerr << "USB: halt condition detected (stalled)" << std::endl; break; case LIBUSB_TRANSFER_ERROR: std::cerr << "USB: transfer failed" << std::endl; @@ -606,26 +606,17 @@ private: libusb_device_handle *_rx_dev_handle; libusb_device_handle *_tx_dev_handle; - int _rx_endpoint; - int _tx_endpoint; - size_t _recv_buff_size; size_t _send_buff_size; size_t _num_frames; - bool open_device(uhd::usb_descriptor_t descriptor); - bool open_interface(libusb_device_handle *dev_handle, int interface); - bool compare_device(libusb_device *dev, uhd::usb_descriptor_t descriptor); - - std::string get_serial(libusb_device *dev); - public: typedef boost::shared_ptr sptr; /* * Structors */ - libusb_zero_copy_impl(uhd::usb_descriptor_t descriptor, + libusb_zero_copy_impl(usb_device_handle::sptr handle, unsigned int rx_endpoint, unsigned int tx_endpoint, size_t recv_buff_size, @@ -641,7 +632,7 @@ public: }; -libusb_zero_copy_impl::libusb_zero_copy_impl(uhd::usb_descriptor_t descriptor, +libusb_zero_copy_impl::libusb_zero_copy_impl(usb_device_handle::sptr handle, unsigned int rx_endpoint, unsigned int tx_endpoint, size_t buff_size, @@ -650,19 +641,16 @@ libusb_zero_copy_impl::libusb_zero_copy_impl(uhd::usb_descriptor_t descriptor, _recv_buff_size(block_size), _send_buff_size(block_size), _num_frames(buff_size / block_size) { - if (libusb_init(&_rx_ctx) < 0) - std::cerr << "error: libusb_init" << std::endl; + libusb::init(&_rx_ctx, libusb_debug_level); + libusb::init(&_tx_ctx, libusb_debug_level); - if (libusb_init(&_tx_ctx) < 0) - std::cerr << "error: libusb_init" << std::endl; + UHD_ASSERT_THROW((_rx_ctx != NULL) && (_tx_ctx != NULL)); - libusb_set_debug(_rx_ctx, libusb_debug_level); - libusb_set_debug(_tx_ctx, libusb_debug_level); + _rx_dev_handle = libusb::open_device(_rx_ctx, handle); + _tx_dev_handle = libusb::open_device(_tx_ctx, handle); - open_device(descriptor); - - open_interface(_rx_dev_handle, 2); - open_interface(_tx_dev_handle, 1); + libusb::open_interface(_rx_dev_handle, 2); + libusb::open_interface(_tx_dev_handle, 1); _rx_ep = new usb_endpoint(_rx_dev_handle, _rx_ctx, @@ -693,117 +681,6 @@ libusb_zero_copy_impl::~libusb_zero_copy_impl() } -bool libusb_zero_copy_impl::open_device(uhd::usb_descriptor_t descriptor) -{ - libusb_device **rx_list; - libusb_device **tx_list; - - bool rx_found = false; - bool tx_found = false; - - ssize_t rx_cnt = libusb_get_device_list(_rx_ctx, &rx_list); - ssize_t tx_cnt = libusb_get_device_list(_tx_ctx, &tx_list); - - if ((rx_cnt < 0) | (tx_cnt < 0) | (rx_cnt != tx_cnt)) - return false; - - //find and open the receive device - for (ssize_t i = 0; i < rx_cnt; i++) { - libusb_device *dev = rx_list[i]; - - if (compare_device(dev, descriptor)) { - libusb_open(dev, &_rx_dev_handle); - rx_found = true; - break; - } - } - - //find and open the transmit device - for (ssize_t i = 0; i < tx_cnt; i++) { - libusb_device *dev = tx_list[i]; - - if (compare_device(dev, descriptor)) { - libusb_open(dev, &_tx_dev_handle); - tx_found = true; - } - } - - libusb_free_device_list(rx_list, 0); - libusb_free_device_list(tx_list, 0); - - if (tx_found && rx_found) - return true; - else - return false; -} - -bool libusb_zero_copy_impl::compare_device(libusb_device *dev, - uhd::usb_descriptor_t descriptor) -{ - std::string serial = descriptor.serial; - boost::uint16_t vendor_id = descriptor.vendor_id; - boost::uint16_t product_id = descriptor.product_id; - boost::uint8_t device_addr = descriptor.device_addr; - - libusb_device_descriptor desc; - libusb_get_device_descriptor(dev, &desc); - - if (serial.compare(get_serial(dev))) - return false; - if (vendor_id != desc.idVendor) - return false; - if (product_id != desc.idProduct) - return false; - if (device_addr != libusb_get_device_address(dev)) - return false; - - return true; -} - -bool libusb_zero_copy_impl::open_interface(libusb_device_handle *dev_handle, - int interface) -{ - int ret = libusb_claim_interface(dev_handle, interface); - if (ret < 0) { - std::cerr << "error: libusb_claim_interface() " << ret << std::endl; - return false; - } - else { - return true; - } -} - -std::string libusb_zero_copy_impl::get_serial(libusb_device *dev) -{ - unsigned char buff[32]; - - libusb_device_descriptor desc; - if (libusb_get_device_descriptor(dev, &desc) < 0) { - std::cerr << "error: libusb_get_device_descriptor()" << std::endl; - return ""; - } - - if (desc.iSerialNumber == 0) - return ""; - - //open the device because we have to - libusb_device_handle *dev_handle; - if (libusb_open(dev, &dev_handle) < 0) { - return ""; - } - - if (libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber, - buff, sizeof(buff)) < 0) { - std::cerr << "error: libusb_get_string_descriptor_ascii()" << std::endl; - return ""; - } - - libusb_close(dev_handle); - - return (char*) buff; -} - - managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff() { libusb_transfer *lut = _rx_ep->get_completed_transfer(); @@ -836,14 +713,14 @@ managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff() /*********************************************************************** * USB zero_copy make functions **********************************************************************/ -usb_zero_copy::sptr usb_zero_copy::make(uhd::usb_descriptor_t descriptor, +usb_zero_copy::sptr usb_zero_copy::make(usb_device_handle::sptr handle, unsigned int rx_endpoint, unsigned int tx_endpoint, size_t buff_size, size_t block_size) { - return sptr(new libusb_zero_copy_impl(descriptor, + return sptr(new libusb_zero_copy_impl(handle, rx_endpoint, tx_endpoint, buff_size, diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index ee6fe6e99..a4effb907 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -48,13 +48,15 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) if (hint.has_key("type") and hint["type"] != "usrp1") return usrp1_addrs; //see what we got on the USB bus - usb_descriptors_t usb_descriptors; - usb_descriptors = usb_control::get_device_list(); + std::vector device_list = + usb_device_handle::get_device_list(); //find the usrps and load firmware - BOOST_FOREACH(usb_descriptor_t desc, usb_descriptors) { - if (desc.vendor_id == 0xfffe && desc.product_id == 0x0002) { - usb_control::sptr ctrl_transport = usb_control::make(desc); + BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { + if (handle->get_vendor_id() == 0xfffe && + handle->get_product_id() == 0x0002) { + + usb_control::sptr ctrl_transport = usb_control::make(handle); usrp_ctrl::sptr usrp_ctrl = usrp_ctrl::make(ctrl_transport); usrp_ctrl->usrp_load_firmware(filename); } @@ -64,13 +66,15 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) sleep(1); //get descriptors again with serial number - usb_descriptors = usb_control::get_device_list(); + device_list = usb_device_handle::get_device_list(); + + BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { + if (handle->get_vendor_id() == 0xfffe && + handle->get_product_id() == 0x0002) { - BOOST_FOREACH(usb_descriptor_t desc, usb_descriptors) { - if (desc.vendor_id == 0xfffe && desc.product_id == 0x0002) { device_addr_t new_addr; new_addr["type"] = "usrp1"; - new_addr["serial"] = desc.serial; + new_addr["serial"] = handle->get_serial(); usrp1_addrs.push_back(new_addr); } } @@ -93,22 +97,23 @@ static device::sptr usrp1_make(const device_addr_t &device_addr) std::cout << "Make usrp1 with " << filename << std::endl; //try to match the given device address with something on the USB bus - usb_descriptors_t usb_descriptors; - usb_descriptors = usb_control::get_device_list(); + std::vector device_list = + usb_device_handle::get_device_list(); //create data and control transports usb_zero_copy::sptr data_transport; usrp_ctrl::sptr usrp_ctrl; - BOOST_FOREACH(usb_descriptor_t desc, usb_descriptors) { - if (desc.serial == device_addr["serial"] - && desc.vendor_id == 0xfffe && desc.product_id == 0x0002) { + BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { + if (handle->get_vendor_id() == 0xfffe && + handle->get_product_id() == 0x0002 && + handle->get_serial() == device_addr["serial"]) { - usb_control::sptr ctrl_transport = usb_control::make(desc); + usb_control::sptr ctrl_transport = usb_control::make(handle); usrp_ctrl = usrp_ctrl::make(ctrl_transport); usrp_ctrl->usrp_load_fpga(filename); - data_transport = usb_zero_copy::make(desc, // identifier + data_transport = usb_zero_copy::make(handle, // identifier 6, // IN endpoint 2, // OUT endpoint 2 * (1 << 20), // buffer size -- cgit v1.2.3 From be904c0e7f23f454b0a6e2a0c4b2e4b91023b88a Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Thu, 26 Aug 2010 12:42:11 -0700 Subject: usrp1: Fill in missing dboard interface with an empty call --- host/lib/usrp/usrp1/dboard_iface.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp index f6fbab033..3078b884d 100644 --- a/host/lib/usrp/usrp1/dboard_iface.cpp +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -69,6 +69,7 @@ public: void set_atr_reg(unit_t, atr_reg_t, boost::uint16_t); void set_gpio_ddr(unit_t, boost::uint16_t); void write_gpio(unit_t, boost::uint16_t); + void set_gpio_debug(unit_t, int); boost::uint16_t read_gpio(unit_t); void write_i2c(boost::uint8_t, const byte_vector_t &); @@ -202,6 +203,11 @@ void usrp1_dboard_iface::write_gpio(unit_t unit, boost::uint16_t value) } } +void usrp1_dboard_iface::set_gpio_debug(unit_t, int) +{ + /* NOP */ +} + boost::uint16_t usrp1_dboard_iface::read_gpio(unit_t unit) { boost::uint32_t out_value; -- cgit v1.2.3 From 988cba70e0737cd2b4ad0015d4630743a80fe0c3 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 26 Aug 2010 13:26:05 -0700 Subject: basic-tx: mirror the rx subdevices for basic tx boards as well --- host/lib/usrp/dboard/db_basic_and_lf.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp index 0b6e4a75a..2a9bf2ca5 100644 --- a/host/lib/usrp/dboard/db_basic_and_lf.cpp +++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp @@ -57,6 +57,12 @@ private: double _max_freq; }; +static const uhd::dict sd_name_to_conn = map_list_of + ("AB", SUBDEV_CONN_COMPLEX_IQ) + ("A", SUBDEV_CONN_REAL_I) + ("B", SUBDEV_CONN_REAL_Q) +; + /*********************************************************************** * Register the basic and LF dboards **********************************************************************/ @@ -77,10 +83,10 @@ static dboard_base::sptr make_lf_tx(dboard_base::ctor_args_t args){ } UHD_STATIC_BLOCK(reg_basic_and_lf_dboards){ - dboard_manager::register_dboard(0x0000, &make_basic_tx, "Basic TX"); - dboard_manager::register_dboard(0x0001, &make_basic_rx, "Basic RX", list_of("AB")("A")("B")); - dboard_manager::register_dboard(0x000e, &make_lf_tx, "LF TX"); - dboard_manager::register_dboard(0x000f, &make_lf_rx, "LF RX", list_of("AB")("A")("B")); + dboard_manager::register_dboard(0x0000, &make_basic_tx, "Basic TX", sd_name_to_conn.keys()); + dboard_manager::register_dboard(0x0001, &make_basic_rx, "Basic RX", sd_name_to_conn.keys()); + dboard_manager::register_dboard(0x000e, &make_lf_tx, "LF TX", sd_name_to_conn.keys()); + dboard_manager::register_dboard(0x000f, &make_lf_rx, "LF RX", sd_name_to_conn.keys()); } /*********************************************************************** @@ -138,14 +144,9 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){ val = prop_names_t(1, ""); //vector of 1 empty string return; - case SUBDEV_PROP_CONNECTION:{ - static const uhd::dict name_to_conn = map_list_of - ("A", SUBDEV_CONN_REAL_I) - ("B", SUBDEV_CONN_REAL_Q) - ("AB", SUBDEV_CONN_COMPLEX_IQ) - ; - val = name_to_conn[get_subdev_name()]; - } return; + case SUBDEV_PROP_CONNECTION: + val = sd_name_to_conn[get_subdev_name()]; + return; case SUBDEV_PROP_USE_LO_OFFSET: val = false; @@ -197,7 +198,10 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){ //handle the get request conditioned on the key switch(key.as()){ case SUBDEV_PROP_NAME: - val = get_tx_id().to_pp_string(); + val = std::string(str(boost::format("%s - %s") + % get_tx_id().to_pp_string() + % get_subdev_name() + )); return; case SUBDEV_PROP_OTHERS: @@ -233,7 +237,7 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_CONNECTION: - val = SUBDEV_CONN_COMPLEX_IQ; + val = sd_name_to_conn[get_subdev_name()]; return; case SUBDEV_PROP_USE_LO_OFFSET: -- cgit v1.2.3 From 3c783f9a3dea262020ea143cfa5d928206aa50fe Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 26 Aug 2010 16:10:33 -0700 Subject: basic-tx: added docs for new subdevices --- host/docs/dboards.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/host/docs/dboards.rst b/host/docs/dboards.rst index b66fd2069..0f6d1cfeb 100644 --- a/host/docs/dboards.rst +++ b/host/docs/dboards.rst @@ -28,7 +28,11 @@ greater than the Nyquist rate of the ADC. ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Basic TX and and LFTX ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The Basic TX and LFTX boards have 1 quadrature subdevice using both antennas. +The Basic TX and LFTX boards have 3 subdevices: + +* **Subdevice A:** real signal on antenna TXA +* **Subdevice B:** real signal on antenna TXB +* **Subdevice AB:** quadrature subdevice using both antennas The boards have no tunable elements or programmable gains. Though the magic of aliasing, you can up-convert signals -- cgit v1.2.3 From eeb724169569d79390478ca4b6d7a2da60987128 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 26 Aug 2010 16:43:11 -0700 Subject: usrp1: codec pga gain control fix --- host/lib/usrp/usrp1/codec_ctrl.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index 6751b9b7e..e4417e7fd 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -154,22 +154,23 @@ usrp1_codec_ctrl_impl::~usrp1_codec_ctrl_impl(void) /*********************************************************************** * Codec Control Gain Control Methods **********************************************************************/ -void usrp1_codec_ctrl_impl::set_tx_pga_gain(float gain) -{ - int gain_word = int(255*(gain - tx_pga_gain_range.min)/(tx_pga_gain_range.max - tx_pga_gain_range.min)); - _ad9862_regs.tx_pga_gain = std::clip(gain_word, 0, 255); +static const int mtpgw = 255; //maximum tx pga gain word + +void usrp1_codec_ctrl_impl::set_tx_pga_gain(float gain){ + int gain_word = int(mtpgw*(gain - tx_pga_gain_range.min)/(tx_pga_gain_range.max - tx_pga_gain_range.min)); + _ad9862_regs.tx_pga_gain = std::clip(gain_word, 0, mtpgw); this->send_reg(16); } -float usrp1_codec_ctrl_impl::get_tx_pga_gain(void) -{ - return (_ad9862_regs.tx_pga_gain*(tx_pga_gain_range.max - tx_pga_gain_range.min)/63) + tx_pga_gain_range.min; +float usrp1_codec_ctrl_impl::get_tx_pga_gain(void){ + return (_ad9862_regs.tx_pga_gain*(tx_pga_gain_range.max - tx_pga_gain_range.min)/mtpgw) + tx_pga_gain_range.min; } -void usrp1_codec_ctrl_impl::set_rx_pga_gain(float gain, char which) -{ - int gain_word = int(0x14*(gain - rx_pga_gain_range.min)/(rx_pga_gain_range.max - rx_pga_gain_range.min)); - gain_word = std::clip(gain_word, 0, 0x14); +static const int mrpgw = 0x14; //maximum rx pga gain word + +void usrp1_codec_ctrl_impl::set_rx_pga_gain(float gain, char which){ + int gain_word = int(mrpgw*(gain - rx_pga_gain_range.min)/(rx_pga_gain_range.max - rx_pga_gain_range.min)); + gain_word = std::clip(gain_word, 0, mrpgw); switch(which){ case 'A': _ad9862_regs.rx_pga_a = gain_word; @@ -183,15 +184,14 @@ void usrp1_codec_ctrl_impl::set_rx_pga_gain(float gain, char which) } } -float usrp1_codec_ctrl_impl::get_rx_pga_gain(char which) -{ +float usrp1_codec_ctrl_impl::get_rx_pga_gain(char which){ int gain_word; switch(which){ case 'A': gain_word = _ad9862_regs.rx_pga_a; break; case 'B': gain_word = _ad9862_regs.rx_pga_b; break; default: UHD_THROW_INVALID_CODE_PATH(); } - return (gain_word*(rx_pga_gain_range.max - rx_pga_gain_range.min)/0x14) + rx_pga_gain_range.min; + return (gain_word*(rx_pga_gain_range.max - rx_pga_gain_range.min)/mrpgw) + rx_pga_gain_range.min; } /*********************************************************************** -- cgit v1.2.3 From a161923ee63c5a8073fb14226b080895b491d998 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 26 Aug 2010 17:52:10 -0700 Subject: usrp1: swapped the mux values to account for the convert types routines --- host/lib/usrp/usrp1/mboard_impl.cpp | 63 +++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index 74ec514ff..612dc732c 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -33,8 +33,21 @@ using namespace uhd; using namespace uhd::usrp; /*********************************************************************** - * Helper Functions + * Calculate the RX mux value: + * The I and Q mux values are intentionally reversed to flip I and Q + * to account for the reversal in the type conversion routines. **********************************************************************/ +static int calc_rx_mux_pair(int adc_for_i, int adc_for_q){ + return (adc_for_i << 2) | (adc_for_q << 0); //shift reversal here +} + +/*! + * 3 2 1 0 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------------------+-------+-------+-------+-------+-+-----+ + * | must be zero | Q3| I3| Q2| I2| Q1| I1| Q0| I0|Z| NCH | + * +-----------------------+-------+-------+-------+-------+-+-----+ + */ static boost::uint32_t calc_rx_mux( const subdev_spec_t &subdev_spec, wax::obj mboard ){ @@ -42,16 +55,16 @@ static boost::uint32_t calc_rx_mux( static const int ADC0 = 0, ADC1 = 1, ADC2 = 2, ADC3 = 3; static const uhd::dict > name_to_conn_to_flag = boost::assign::map_list_of ("A", boost::assign::map_list_of - (SUBDEV_CONN_COMPLEX_IQ, (ADC0 << 0) | (ADC1 << 2)) //I and Q - (SUBDEV_CONN_COMPLEX_QI, (ADC1 << 0) | (ADC0 << 2)) //I and Q - (SUBDEV_CONN_REAL_I, (ADC0 << 0) | (ADC0 << 2)) //I and Q (Q identical but ignored Z=1) - (SUBDEV_CONN_REAL_Q, (ADC1 << 0) | (ADC1 << 2)) //I and Q (Q identical but ignored Z=1) + (SUBDEV_CONN_COMPLEX_IQ, calc_rx_mux_pair(ADC0, ADC1)) //I and Q + (SUBDEV_CONN_COMPLEX_QI, calc_rx_mux_pair(ADC1, ADC0)) //I and Q + (SUBDEV_CONN_REAL_I, calc_rx_mux_pair(ADC0, ADC0)) //I and Q (Q identical but ignored Z=1) + (SUBDEV_CONN_REAL_Q, calc_rx_mux_pair(ADC1, ADC1)) //I and Q (Q identical but ignored Z=1) ) ("B", boost::assign::map_list_of - (SUBDEV_CONN_COMPLEX_IQ, (ADC2 << 0) | (ADC3 << 2)) //I and Q - (SUBDEV_CONN_COMPLEX_QI, (ADC3 << 0) | (ADC2 << 2)) //I and Q - (SUBDEV_CONN_REAL_I, (ADC2 << 0) | (ADC2 << 2)) //I and Q (Q identical but ignored Z=1) - (SUBDEV_CONN_REAL_Q, (ADC3 << 0) | (ADC3 << 2)) //I and Q (Q identical but ignored Z=1) + (SUBDEV_CONN_COMPLEX_IQ, calc_rx_mux_pair(ADC2, ADC3)) //I and Q + (SUBDEV_CONN_COMPLEX_QI, calc_rx_mux_pair(ADC3, ADC2)) //I and Q + (SUBDEV_CONN_REAL_I, calc_rx_mux_pair(ADC2, ADC2)) //I and Q (Q identical but ignored Z=1) + (SUBDEV_CONN_REAL_Q, calc_rx_mux_pair(ADC3, ADC3)) //I and Q (Q identical but ignored Z=1) ) ; @@ -88,6 +101,22 @@ static boost::uint32_t calc_rx_mux( return ((channel_flags & 0xffff) << 4) | ((Z & 0x1) << 3) | ((nchan & 0x7) << 0); } +/*********************************************************************** + * Calculate the TX mux value: + * The I and Q mux values are intentionally reversed to flip I and Q + * to account for the reversal in the type conversion routines. + **********************************************************************/ +static int calc_tx_mux_pair(int chn_for_i, int chn_for_q){ + return (chn_for_i << 4) | (chn_for_q << 0); //shift reversal here +} + +/*! + * 3 2 1 0 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------------------+-------+-------+-------+-------+-+-----+ + * | | DAC1Q | DAC1I | DAC0Q | DAC0I |0| NCH | + * +-----------------------------------------------+-------+-+-----+ + */ static boost::uint32_t calc_tx_mux( const subdev_spec_t &subdev_spec, wax::obj mboard ){ @@ -95,16 +124,16 @@ static boost::uint32_t calc_tx_mux( static const int ENB = 1 << 3, CHAN_I0 = 0, CHAN_Q0 = 1, CHAN_I1 = 2, CHAN_Q1 = 3; static const uhd::dict > chan_to_conn_to_flag = boost::assign::map_list_of (0, boost::assign::map_list_of - (SUBDEV_CONN_COMPLEX_IQ, ((CHAN_I0 | ENB) << 0) | ((CHAN_Q0 | ENB) << 4)) - (SUBDEV_CONN_COMPLEX_QI, ((CHAN_I0 | ENB) << 4) | ((CHAN_Q0 | ENB) << 0)) - (SUBDEV_CONN_REAL_I, ((CHAN_I0 | ENB) << 0)) - (SUBDEV_CONN_REAL_Q, ((CHAN_I0 | ENB) << 4)) + (SUBDEV_CONN_COMPLEX_IQ, calc_tx_mux_pair(CHAN_I0 | ENB, CHAN_Q0 | ENB)) + (SUBDEV_CONN_COMPLEX_QI, calc_tx_mux_pair(CHAN_Q0 | ENB, CHAN_I0 | ENB)) + (SUBDEV_CONN_REAL_I, calc_tx_mux_pair(CHAN_I0 | ENB, 0 )) + (SUBDEV_CONN_REAL_Q, calc_tx_mux_pair(0, CHAN_I0 | ENB)) ) (1, boost::assign::map_list_of - (SUBDEV_CONN_COMPLEX_IQ, ((CHAN_I1 | ENB) << 0) | ((CHAN_Q1 | ENB) << 4)) - (SUBDEV_CONN_COMPLEX_QI, ((CHAN_I1 | ENB) << 4) | ((CHAN_Q1 | ENB) << 0)) - (SUBDEV_CONN_REAL_I, ((CHAN_I1 | ENB) << 0)) - (SUBDEV_CONN_REAL_Q, ((CHAN_I1 | ENB) << 4)) + (SUBDEV_CONN_COMPLEX_IQ, calc_tx_mux_pair(CHAN_I1 | ENB, CHAN_Q1 | ENB)) + (SUBDEV_CONN_COMPLEX_QI, calc_tx_mux_pair(CHAN_Q1 | ENB, CHAN_I1 | ENB)) + (SUBDEV_CONN_REAL_I, calc_tx_mux_pair(CHAN_I1 | ENB, 0 )) + (SUBDEV_CONN_REAL_Q, calc_tx_mux_pair(0, CHAN_I1 | ENB)) ) ; -- cgit v1.2.3 From 7bf409478fe65593d8e4b47dcf682ed35cc2cc45 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 26 Aug 2010 18:31:32 -0700 Subject: usrp1: cast enum to char before printing as %c --- host/lib/usrp/usrp1/codec_impl.cpp | 4 ++-- host/lib/usrp/usrp1/dboard_impl.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/host/lib/usrp/usrp1/codec_impl.cpp b/host/lib/usrp/usrp1/codec_impl.cpp index 766a7948f..1756c1ed4 100644 --- a/host/lib/usrp/usrp1/codec_impl.cpp +++ b/host/lib/usrp/usrp1/codec_impl.cpp @@ -54,7 +54,7 @@ void usrp1_impl::rx_codec_get(const wax::obj &key_, wax::obj &val, dboard_slot_t //handle the get request conditioned on the key switch(key.as()) { case CODEC_PROP_NAME: - val = str(boost::format("usrp1 adc - ad9862 - slot %c") % dboard_slot); + val = str(boost::format("usrp1 adc - ad9862 - slot %c") % char(dboard_slot)); return; case CODEC_PROP_OTHERS: @@ -114,7 +114,7 @@ void usrp1_impl::tx_codec_get(const wax::obj &key_, wax::obj &val, dboard_slot_t //handle the get request conditioned on the key switch(key.as()) { case CODEC_PROP_NAME: - val = str(boost::format("usrp1 dac - ad9862 - slot %c") % dboard_slot); + val = str(boost::format("usrp1 dac - ad9862 - slot %c") % char(dboard_slot)); return; case CODEC_PROP_OTHERS: diff --git a/host/lib/usrp/usrp1/dboard_impl.cpp b/host/lib/usrp/usrp1/dboard_impl.cpp index c8d9c55dd..f52117c34 100644 --- a/host/lib/usrp/usrp1/dboard_impl.cpp +++ b/host/lib/usrp/usrp1/dboard_impl.cpp @@ -98,7 +98,7 @@ void usrp1_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val, dboard_slot_ //handle the get request conditioned on the key switch(key.as()){ case DBOARD_PROP_NAME: - val = str(boost::format("usrp1 dboard (rx unit) - %c") % dboard_slot); + val = str(boost::format("usrp1 dboard (rx unit) - %c") % char(dboard_slot)); return; case DBOARD_PROP_SUBDEV: @@ -162,7 +162,7 @@ void usrp1_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val, dboard_slot_ //handle the get request conditioned on the key switch(key.as()){ case DBOARD_PROP_NAME: - val = str(boost::format("usrp1 dboard (tx unit) - %c") % dboard_slot); + val = str(boost::format("usrp1 dboard (tx unit) - %c") % char(dboard_slot)); return; case DBOARD_PROP_SUBDEV: -- cgit v1.2.3 From c9569736930cf436f340d70c7537a5f46f3ab3aa Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 26 Aug 2010 22:15:12 -0700 Subject: usrp1: handle special dbsrx clocking case --- host/lib/usrp/usrp1/clock_ctrl.cpp | 64 -------------------------------- host/lib/usrp/usrp1/clock_ctrl.hpp | 38 ------------------- host/lib/usrp/usrp1/dboard_iface.cpp | 72 ++++++++++++++++++++++++------------ host/lib/usrp/usrp1/dboard_impl.cpp | 3 +- host/lib/usrp/usrp1/usrp1_impl.hpp | 8 ++-- 5 files changed, 55 insertions(+), 130 deletions(-) diff --git a/host/lib/usrp/usrp1/clock_ctrl.cpp b/host/lib/usrp/usrp1/clock_ctrl.cpp index 54f7b0b98..68c5f5320 100644 --- a/host/lib/usrp/usrp1/clock_ctrl.cpp +++ b/host/lib/usrp/usrp1/clock_ctrl.cpp @@ -46,70 +46,6 @@ public: return master_clock_rate; } - /*********************************************************************** - * RX Dboard Clock Control (output 9, divider 3) - **********************************************************************/ - void enable_rx_dboard_clock(bool) - { - std::cerr << "USRP: enable_rx_dboard_clock() disabled" << std::endl; - _iface->poke32(FR_RX_A_REFCLK, 0); - _iface->poke32(FR_RX_B_REFCLK, 0); - } - - std::vector get_rx_dboard_clock_rates(void) - { -#if 0 - std::vector rates; - for (size_t div = 1; div <= 127; div++) - rates.push_back(master_clock_rate / div); - return rates; -#else - return std::vector(1, master_clock_rate); -#endif - } - - /* - * Daughterboard reference clock register - * - * Bit 7 - 1 turns on refclk, 0 allows IO use - * Bits 6:0 - Divider value - */ - void set_rx_dboard_clock_rate(double) - { -#if 0 - assert_has(get_rx_dboard_clock_rates(), rate, "rx dboard clock rate"); - size_t divider = size_t(rate/master_clock_rate); - _iface->poke32(FR_RX_A_REFCLK, (divider & 0x7f) | 0x80); -#else - std::cerr << "USRP: set_rx_dboard_clock_rate() disabled" << std::endl; - _iface->poke32(FR_RX_A_REFCLK, 0); - _iface->poke32(FR_RX_B_REFCLK, 0); -#endif - } - - /*********************************************************************** - * TX Dboard Clock Control - **********************************************************************/ - void enable_tx_dboard_clock(bool) - { - std::cerr << "USRP: set_tx_dboard_clock() disabled" << std::endl; - _iface->poke32(FR_TX_A_REFCLK, 0); - _iface->poke32(FR_TX_B_REFCLK, 0); - - } - - std::vector get_tx_dboard_clock_rates(void) - { - return get_rx_dboard_clock_rates(); //same master clock, same dividers... - } - - void set_tx_dboard_clock_rate(double) - { - std::cerr << "USRP: set_tx_dboard_clock_rate() disabled" << std::endl; - _iface->poke32(FR_TX_A_REFCLK, 0); - _iface->poke32(FR_TX_B_REFCLK, 0); - } - private: usrp1_iface::sptr _iface; diff --git a/host/lib/usrp/usrp1/clock_ctrl.hpp b/host/lib/usrp/usrp1/clock_ctrl.hpp index 9ba4d56e3..366869dab 100644 --- a/host/lib/usrp/usrp1/clock_ctrl.hpp +++ b/host/lib/usrp/usrp1/clock_ctrl.hpp @@ -45,44 +45,6 @@ public: */ virtual double get_master_clock_freq(void) = 0; - /*! - * Get the possible rates of the rx dboard clock. - * \return a vector of clock rates in Hz - */ - virtual std::vector get_rx_dboard_clock_rates(void) = 0; - - /*! - * Get the possible rates of the tx dboard clock. - * \return a vector of clock rates in Hz - */ - virtual std::vector get_tx_dboard_clock_rates(void) = 0; - - /*! - * Set the rx dboard clock rate to a possible rate. - * \param rate the new clock rate in Hz - * \throw exception when rate cannot be achieved - */ - virtual void set_rx_dboard_clock_rate(double rate) = 0; - - /*! - * Set the tx dboard clock rate to a possible rate. - * \param rate the new clock rate in Hz - * \throw exception when rate cannot be achieved - */ - virtual void set_tx_dboard_clock_rate(double rate) = 0; - - /*! - * Enable/disable the rx dboard clock. - * \param enb true to enable - */ - virtual void enable_rx_dboard_clock(bool enb) = 0; - - /*! - * Enable/disable the tx dboard clock. - * \param enb true to enable - */ - virtual void enable_tx_dboard_clock(bool enb) = 0; - }; #endif /* INCLUDED_USRP1_CLOCK_CTRL_HPP */ diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp index 3078b884d..b2221e221 100644 --- a/host/lib/usrp/usrp1/dboard_iface.cpp +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -19,6 +19,7 @@ #include "usrp1_impl.hpp" #include "fpga_regs_common.h" #include "usrp_spi_defs.h" +#include "fpga_regs_standard.h" #include "clock_ctrl.hpp" #include "codec_ctrl.hpp" #include @@ -37,12 +38,15 @@ public: usrp1_dboard_iface(usrp1_iface::sptr iface, usrp1_clock_ctrl::sptr clock, usrp1_codec_ctrl::sptr codec, - usrp1_impl::dboard_slot_t dboard_slot - ){ + usrp1_impl::dboard_slot_t dboard_slot, + const dboard_id_t &rx_dboard_id + ): + _dboard_slot(dboard_slot), + _rx_dboard_id(rx_dboard_id) + { _iface = iface; _clock = clock; _codec = codec; - _dboard_slot = dboard_slot; //init the clock rate shadows this->set_clock_rate(UNIT_RX, _clock->get_master_clock_freq()); @@ -95,7 +99,8 @@ private: usrp1_clock_ctrl::sptr _clock; usrp1_codec_ctrl::sptr _codec; uhd::dict _clock_rates; - usrp1_impl::dboard_slot_t _dboard_slot; + const usrp1_impl::dboard_slot_t _dboard_slot; + const dboard_id_t &_rx_dboard_id; }; /*********************************************************************** @@ -104,33 +109,55 @@ private: dboard_iface::sptr usrp1_impl::make_dboard_iface(usrp1_iface::sptr iface, usrp1_clock_ctrl::sptr clock, usrp1_codec_ctrl::sptr codec, - dboard_slot_t dboard_slot + dboard_slot_t dboard_slot, + const dboard_id_t &rx_dboard_id ){ - return dboard_iface::sptr(new usrp1_dboard_iface(iface, clock, codec, dboard_slot)); + return dboard_iface::sptr(new usrp1_dboard_iface( + iface, clock, codec, dboard_slot, rx_dboard_id + )); } /*********************************************************************** * Clock Rates **********************************************************************/ +static const dboard_id_t dbsrx_classic_id(0x0002); + +/* + * Daughterboard reference clock register + * + * Bit 7 - 1 turns on refclk, 0 allows IO use + * Bits 6:0 - Divider value + */ void usrp1_dboard_iface::set_clock_rate(unit_t unit, double rate) { + assert_has(this->get_clock_rates(unit), rate, "dboard clock rate"); _clock_rates[unit] = rate; - switch(unit) { - case UNIT_RX: return _clock->set_rx_dboard_clock_rate(rate); - case UNIT_TX: return _clock->set_tx_dboard_clock_rate(rate); + + if (unit == UNIT_RX && _rx_dboard_id == dbsrx_classic_id){ + size_t divider = size_t(rate/_clock->get_master_clock_freq()); + switch(_dboard_slot){ + case usrp1_impl::DBOARD_SLOT_A: + _iface->poke32(FR_RX_A_REFCLK, (divider & 0x7f) | 0x80); + break; + + case usrp1_impl::DBOARD_SLOT_B: + _iface->poke32(FR_RX_B_REFCLK, (divider & 0x7f) | 0x80); + break; + } } } -/* - * TODO: if this is a dbsrx return the rate of 4MHZ and set FPGA magic - */ std::vector usrp1_dboard_iface::get_clock_rates(unit_t unit) { - switch(unit) { - case UNIT_RX: return _clock->get_rx_dboard_clock_rates(); - case UNIT_TX: return _clock->get_tx_dboard_clock_rates(); - default: UHD_THROW_INVALID_CODE_PATH(); + std::vector rates; + if (unit == UNIT_RX && _rx_dboard_id == dbsrx_classic_id){ + for (size_t div = 1; div <= 127; div++) + rates.push_back(_clock->get_master_clock_freq() / div); } + else{ + rates.push_back(_clock->get_master_clock_freq()); + } + return rates; } double usrp1_dboard_iface::get_clock_rate(unit_t unit) @@ -138,12 +165,9 @@ double usrp1_dboard_iface::get_clock_rate(unit_t unit) return _clock_rates[unit]; } -void usrp1_dboard_iface::set_clock_enabled(unit_t unit, bool enb) +void usrp1_dboard_iface::set_clock_enabled(unit_t, bool) { - switch(unit) { - case UNIT_RX: return _clock->enable_rx_dboard_clock(enb); - case UNIT_TX: return _clock->enable_tx_dboard_clock(enb); - } + //TODO we can only enable for special case anyway... } /*********************************************************************** @@ -241,7 +265,7 @@ void usrp1_dboard_iface::set_atr_reg(unit_t unit, _iface->poke32(FR_ATR_RXVAL_1, value); else if (_dboard_slot == usrp1_impl::DBOARD_SLOT_B) _iface->poke32(FR_ATR_RXVAL_3, value); - break; + break; case UNIT_TX: if (_dboard_slot == usrp1_impl::DBOARD_SLOT_A) _iface->poke32(FR_ATR_TXVAL_0, value); @@ -265,14 +289,14 @@ static boost::uint32_t unit_to_otw_spi_dev(dboard_iface::unit_t unit, switch(unit) { case dboard_iface::UNIT_TX: if (slot == usrp1_impl::DBOARD_SLOT_A) - return SPI_ENABLE_TX_A; + return SPI_ENABLE_TX_A; else if (slot == usrp1_impl::DBOARD_SLOT_B) return SPI_ENABLE_TX_B; else break; case dboard_iface::UNIT_RX: if (slot == usrp1_impl::DBOARD_SLOT_A) - return SPI_ENABLE_RX_A; + return SPI_ENABLE_RX_A; else if (slot == usrp1_impl::DBOARD_SLOT_B) return SPI_ENABLE_RX_B; else diff --git a/host/lib/usrp/usrp1/dboard_impl.cpp b/host/lib/usrp/usrp1/dboard_impl.cpp index f52117c34..3a8480e1b 100644 --- a/host/lib/usrp/usrp1/dboard_impl.cpp +++ b/host/lib/usrp/usrp1/dboard_impl.cpp @@ -67,7 +67,8 @@ void usrp1_impl::dboard_init(void) //create a new dboard interface and manager _dboard_ifaces[dboard_slot] = make_dboard_iface( - _iface, _clock_ctrl, _codec_ctrls[dboard_slot], dboard_slot + _iface, _clock_ctrl, _codec_ctrls[dboard_slot], + dboard_slot, _rx_db_eeproms[dboard_slot].id ); _dboard_managers[dboard_slot] = dboard_manager::make( diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index 4b4ac51dd..c2f693eeb 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -45,8 +46,7 @@ public: typedef boost::function set_t; typedef boost::shared_ptr sptr; - static sptr make(const get_t &get, const set_t &set) - { + static sptr make(const get_t &get, const set_t &set){ return sptr(new wax_obj_proxy(get, set)); } @@ -102,13 +102,15 @@ private: * \param clock the clock control interface * \param codec the codec control interface * \param dboard_slot the slot identifier + * \param rx_dboard_id the db id for the rx board (used for evil dbsrx purposes) * \return a sptr to a new dboard interface */ static uhd::usrp::dboard_iface::sptr make_dboard_iface( usrp1_iface::sptr iface, usrp1_clock_ctrl::sptr clock, usrp1_codec_ctrl::sptr codec, - dboard_slot_t dboard_slot + dboard_slot_t dboard_slot, + const uhd::usrp::dboard_id_t &rx_dboard_id ); //interface to ioctls and file descriptor -- cgit v1.2.3 From 273a10487699f8c2748a62b55f6f11f34b078f03 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 11:44:38 -0700 Subject: usrp1: Add TODO comments --- host/lib/usrp/usrp1/dsp_impl.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp index ddd1e811b..ab2eed91c 100644 --- a/host/lib/usrp/usrp1/dsp_impl.cpp +++ b/host/lib/usrp/usrp1/dsp_impl.cpp @@ -95,6 +95,7 @@ void usrp1_impl::rx_dsp_set(const wax::obj &key, const wax::obj &val) } _rx_dsp_decim = rate; + //TODO Poll every 100ms. Make it selectable? _rx_samps_per_poll_interval = 0.1 * _clock_ctrl->get_master_clock_freq() / rate; _iface->poke32(FR_DECIM_RATE, _rx_dsp_decim/2 - 1); @@ -157,7 +158,11 @@ void usrp1_impl::tx_dsp_set(const wax::obj &key, const wax::obj &val) { switch(key.as()) { - // TODO: Set both codec frequencies until we have duality properties + //TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO + // + // Set both codec frequencies until we have duality properties + // + //TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO case DSP_PROP_FREQ_SHIFT: { double new_freq = val.as(); _codec_ctrls[DBOARD_SLOT_A]->set_duc_freq(new_freq); @@ -177,6 +182,8 @@ void usrp1_impl::tx_dsp_set(const wax::obj &key, const wax::obj &val) } _tx_dsp_interp = rate; + + //TODO Poll every 100ms. Make it selectable? _tx_samps_per_poll_interval = 0.1 * _clock_ctrl->get_master_clock_freq() * 2 / rate; _iface->poke32(FR_INTERP_RATE, _tx_dsp_interp / 4 - 1); -- cgit v1.2.3 From a455ed962ea29634ef658a0e6cfa58e2790312d6 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 11:44:55 -0700 Subject: usrp1: Fix fpga load issue by increasing delay after firmware load 500ms is not enough. 1-2 seconds is suitable. --- host/lib/usrp/usrp1/usrp1_impl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index a15d0a244..d37eec566 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -70,7 +70,7 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) } //wait for things to settle - boost::this_thread::sleep(boost::posix_time::milliseconds(500)); + boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); //get descriptors again with serial number device_list = usb_device_handle::get_device_list(); -- cgit v1.2.3 From 45d8240f77609914116e743c9ed24fad80288b57 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Thu, 26 Aug 2010 15:59:04 -0700 Subject: usrp1: Clean up initialization sequence of fpga registers --- host/lib/usrp/usrp1/mboard_impl.cpp | 77 +++++++++---------------------------- 1 file changed, 18 insertions(+), 59 deletions(-) diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index 612dc732c..8c9be9f73 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -168,65 +168,24 @@ void usrp1_impl::mboard_init(void) boost::bind(&usrp1_impl::mboard_get, this, _1, _2), boost::bind(&usrp1_impl::mboard_set, this, _1, _2)); - /* - * Basic initialization - */ - _iface->poke32( 13, 0x00000000); //FR_MODE - _iface->poke32( 14, 0x00000000); //FR_DEBUG_EN - _iface->poke32( 1, 0x00000001); //FR_RX_SAMPLE_RATE_DEV - _iface->poke32( 0, 0x00000003); //FR_TX_SAMPLE_RATE_DEV - _iface->poke32( 15, 0x0000000f); //FR_DC_OFFSET_CL_EN - - /* - * Reset codecs - */ - _iface->poke32( 16, 0x00000000); //FR_ADC_OFFSET_0 - _iface->poke32( 17, 0x00000000); //FR_ADC_OFFSET_1 - _iface->poke32( 18, 0x00000000); //FR_ADC_OFFSET_2 - _iface->poke32( 19, 0x00000000); //FR_ADC_OFFSET_3 - - /* - * Reset GPIO masks - */ - _iface->poke32( 6, 0xffff0000); //FR_OE_1 - _iface->poke32( 10, 0xffff0000); //FR_IO_1 - _iface->poke32( 8, 0xffff0000); //FR_OE_3 - _iface->poke32( 12, 0xffff0000); //FR_IO_3 - - /* - * Disable ATR masks and reset state registers - */ - _iface->poke32( 23, 0x00000000); //FR_ATR_MASK_1 - _iface->poke32( 24, 0x00000000); //FR_ATR_TXVAL_1 - _iface->poke32( 25, 0x00000000); //FR_ATR_RXVAL_1 - _iface->poke32( 29, 0x00000000); //FR_ATR_MASK_3 - _iface->poke32( 30, 0x00000000); //FR_ATR_TXVAL_3 - _iface->poke32( 31, 0x00000000); //FR_ATR_RXVAL_3 - - /* - * Set defaults for RX format, decimation, and mux - */ - _iface->poke32( 49, 0x00000300); //FR_RX_FORMAT - _iface->poke32( 38, 0x000e4e41); //FR_RX_MUX - - /* - * Set defaults for TX format, interpolation, and mux - */ - _iface->poke32( 48, 0x00000000); //FR_TX_FORMAT - _iface->poke32( 39, 0x00000981); //FR_TX_MUX - - /* - * Reset DDC registers - */ - _iface->poke32( 34, 0x00000000); //FR_RX_FREQ_0 - _iface->poke32( 44, 0x00000000); //FR_RX_PHASE_0 - _iface->poke32( 35, 0x00000000); //FR_RX_FREQ_1 - _iface->poke32( 45, 0x00000000); //FR_RX_PHASE_1 - _iface->poke32( 36, 0x00000000); //FR_RX_FREQ_2 - _iface->poke32( 46, 0x00000000); //FR_RX_PHASE_2 - _iface->poke32( 37, 0x00000000); //FR_RX_FREQ_3 - _iface->poke32( 47, 0x00000000); //FR_RX_PHASE_3 - + // Normal mode with no loopback or Rx counting + _iface->poke32(FR_MODE, 0x00000000); + _iface->poke32(FR_DEBUG_EN, 0x00000000); + _iface->poke32(FR_RX_SAMPLE_RATE_DIV, 0x00000001); + _iface->poke32(FR_TX_SAMPLE_RATE_DIV, 0x00000003); + _iface->poke32(FR_DC_OFFSET_CL_EN, 0x0000000f); + + // Reset offset correction registers + _iface->poke32(FR_ADC_OFFSET_0, 0x00000000); + _iface->poke32(FR_ADC_OFFSET_1, 0x00000000); + _iface->poke32(FR_ADC_OFFSET_2, 0x00000000); + _iface->poke32(FR_ADC_OFFSET_3, 0x00000000); + + // Set default for RX format to 16-bit I&Q and no half-band filter bypass + _iface->poke32(FR_RX_FORMAT, 0x00000300); + + // Set default for TX format to 16-bit I&Q + _iface->poke32(FR_TX_FORMAT, 0x00000000); } void usrp1_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd) -- cgit v1.2.3 From ab068598b62b5c05dc56df0e2a2a54cc0b37cdf2 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Thu, 26 Aug 2010 18:42:29 -0700 Subject: usrp1: Fix DDC rate storage value and comments for multiple channel support --- host/lib/usrp/usrp1/dsp_impl.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp index ab2eed91c..d5a88fa2d 100644 --- a/host/lib/usrp/usrp1/dsp_impl.cpp +++ b/host/lib/usrp/usrp1/dsp_impl.cpp @@ -78,13 +78,23 @@ void usrp1_impl::rx_dsp_set(const wax::obj &key, const wax::obj &val) switch(key.as()) { case DSP_PROP_FREQ_SHIFT: { double new_freq = val.as(); - _iface->poke32(FR_RX_FREQ_0, - -dsp_type1::calc_cordic_word_and_update(new_freq, _clock_ctrl->get_master_clock_freq())); - _tx_dsp_freq = new_freq; + boost::uint32_t reg_word = dsp_type1::calc_cordic_word_and_update( + new_freq, _clock_ctrl->get_master_clock_freq()); + + //TODO TODO TODO TODO TODO TODO TODO TODO TODO + // + // Handle multiple receive channels / DDC's + // + //TODO TODO TODO TODO TODO TODO TODO TODO TODO + _iface->poke32(FR_RX_FREQ_0, reg_word); + _iface->poke32(FR_RX_FREQ_1, reg_word); + _iface->poke32(FR_RX_FREQ_2, reg_word); + _iface->poke32(FR_RX_FREQ_3, reg_word); + + _rx_dsp_freq = new_freq; return; } case DSP_PROP_HOST_RATE: { - //FIXME: Stop and resume streaming during set? unsigned int rate = _clock_ctrl->get_master_clock_freq() / val.as(); -- cgit v1.2.3 From 5e047eb5cb6f51b0c86ace7e5b4ea6c8089f0de9 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Thu, 26 Aug 2010 19:00:05 -0700 Subject: usrp1: Only return a list of FSF devices --- host/lib/transport/libusb1_device_handle.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/host/lib/transport/libusb1_device_handle.cpp b/host/lib/transport/libusb1_device_handle.cpp index f80090f15..5289f668f 100644 --- a/host/lib/transport/libusb1_device_handle.cpp +++ b/host/lib/transport/libusb1_device_handle.cpp @@ -88,6 +88,16 @@ usb_device_handle::sptr make_usb_device_handle(libusb_device *dev) device_addr)); } +bool check_fsf_device(libusb_device *dev) +{ + libusb_device_descriptor desc; + + if (libusb_get_device_descriptor(dev, &desc) < 0) { + UHD_ASSERT_THROW("USB: failed to get device descriptor"); + } + + return desc.idVendor == 0xfffe; +} std::vector usb_device_handle::get_device_list() { @@ -105,7 +115,8 @@ std::vector usb_device_handle::get_device_list() ssize_t i = 0; for (i = 0; i < cnt; i++) { libusb_device *dev = list[i]; - device_list.push_back(make_usb_device_handle(dev)); + if (check_fsf_device(dev)) + device_list.push_back(make_usb_device_handle(dev)); } libusb_free_device_list(list, 0); -- cgit v1.2.3 From 98510590c453bf366d29e488c1d3b54ec022f919 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Thu, 26 Aug 2010 17:07:17 -0700 Subject: usrp1: Add missing include for fpga registers --- host/lib/usrp/usrp1/mboard_impl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index 8c9be9f73..0b1335acf 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -18,6 +18,7 @@ #include "usrp1_impl.hpp" #include "usrp_commands.h" #include "fpga_regs_standard.h" +#include "fpga_regs_common.h" #include #include #include -- cgit v1.2.3 From 1e1e70373943113b5339a7229219e3851af36561 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 12:20:37 -0700 Subject: usrp1: Disable default codec debug output --- host/lib/usrp/usrp1/codec_ctrl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index e4417e7fd..08f2d2a8e 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -33,7 +33,7 @@ using namespace uhd; -static const bool codec_debug = true; +static const bool codec_debug = false; const gain_range_t usrp1_codec_ctrl::tx_pga_gain_range(-20, 0, float(0.1)); const gain_range_t usrp1_codec_ctrl::rx_pga_gain_range(0, 20, 1); -- cgit v1.2.3 From c30cbf651ba5efc734faa96c1b12a99b15b6e41e Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 12:22:42 -0700 Subject: usrp1: Disable i2c error messages unless debug is enabled Failed i2c operations can be normal under certain situations. Notably, write failures are used to detect unpopulated daughterboard slots. --- host/lib/usrp/usrp1/usrp1_iface.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp index 9d326d6bd..8756a21c9 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.cpp +++ b/host/lib/usrp/usrp1/usrp1_iface.cpp @@ -122,7 +122,8 @@ public: buff, bytes.size()); - if (ret < 0) + // TODO throw and catch i2c failures during eeprom read + if (iface_debug && (ret < 0)) std::cerr << "USRP: failed i2c write: " << ret << std::endl; } @@ -137,7 +138,8 @@ public: buff, num_bytes); - if ((ret < 0) || (unsigned)ret < (num_bytes)) { + // TODO throw and catch i2c failures during eeprom read + if (iface_debug && ((ret < 0) || (unsigned)ret < (num_bytes))) { std::cerr << "USRP: failed i2c read: " << ret << std::endl; return byte_vector_t(num_bytes, 0xff); } -- cgit v1.2.3 From b6099569e31705174920f44083f7f1bc22c445c7 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 13:27:32 -0700 Subject: usrp1: Cleanup libusb device handling This patch limits all libusb device enumeration operations to FSF (Vendor ID = 0xfffe) devices, which removes a lot of unncessary libusb output when debug mode is enabled. The reference counts held by the libusb device list are also reduced, which prevents holding references to unused devices. --- host/lib/transport/libusb1_base.cpp | 50 +++++++++++++++++++++++----- host/lib/transport/libusb1_base.hpp | 2 ++ host/lib/transport/libusb1_device_handle.cpp | 31 ++++------------- 3 files changed, 50 insertions(+), 33 deletions(-) diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index 6965de214..493d4eff3 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -16,10 +16,22 @@ // #include "libusb1_base.hpp" +#include #include using namespace uhd::transport; +bool check_fsf_device(libusb_device *dev) +{ + libusb_device_descriptor desc; + + if (libusb_get_device_descriptor(dev, &desc) < 0) { + UHD_ASSERT_THROW("USB: failed to get device descriptor"); + } + + return desc.idVendor == 0xfffe; +} + void libusb::init(libusb_context **ctx, int debug_level) { if (libusb_init(ctx) < 0) @@ -28,27 +40,47 @@ void libusb::init(libusb_context **ctx, int debug_level) libusb_set_debug(*ctx, debug_level); } +std::vector libusb::get_fsf_device_list(libusb_context *ctx) +{ + libusb_device **libusb_dev_list; + std::vector fsf_dev_list; + + ssize_t dev_cnt = libusb_get_device_list(ctx, &libusb_dev_list); + + //find the FSF devices + for (ssize_t i = 0; i < dev_cnt; i++) { + libusb_device *dev = libusb_dev_list[i]; + + if (check_fsf_device(dev)) + fsf_dev_list.push_back(dev); + else + libusb_unref_device(dev); + } + + libusb_free_device_list(libusb_dev_list, 0); + + return fsf_dev_list; +} libusb_device_handle *libusb::open_device(libusb_context *ctx, usb_device_handle::sptr handle) { - libusb_device **dev_list; - libusb_device_handle *dev_handle; + libusb_device_handle *dev_handle = NULL; + std::vector fsf_dev_list = get_fsf_device_list(ctx); - ssize_t dev_cnt = libusb_get_device_list(ctx, &dev_list); - - //find and open the receive device - for (ssize_t i = 0; i < dev_cnt; i++) { - libusb_device *dev = dev_list[i]; + //find and open the USB device + for (size_t i = 0; i < fsf_dev_list.size(); i++) { + libusb_device *dev = fsf_dev_list[i]; if (compare_device(dev, handle)) { libusb_open(dev, &dev_handle); + libusb_unref_device(dev); break; } + + libusb_unref_device(dev); } - libusb_free_device_list(dev_list, 0); - return dev_handle; } diff --git a/host/lib/transport/libusb1_base.hpp b/host/lib/transport/libusb1_base.hpp index ae560cd52..708a42c73 100644 --- a/host/lib/transport/libusb1_base.hpp +++ b/host/lib/transport/libusb1_base.hpp @@ -27,6 +27,8 @@ namespace uhd { namespace transport { namespace libusb { void init(libusb_context **ctx, int debug_level); + std::vector get_fsf_device_list(libusb_context *ctx); + libusb_device_handle *open_device(libusb_context *ctx, usb_device_handle::sptr handle); diff --git a/host/lib/transport/libusb1_device_handle.cpp b/host/lib/transport/libusb1_device_handle.cpp index 5289f668f..4885099eb 100644 --- a/host/lib/transport/libusb1_device_handle.cpp +++ b/host/lib/transport/libusb1_device_handle.cpp @@ -88,38 +88,21 @@ usb_device_handle::sptr make_usb_device_handle(libusb_device *dev) device_addr)); } -bool check_fsf_device(libusb_device *dev) -{ - libusb_device_descriptor desc; - - if (libusb_get_device_descriptor(dev, &desc) < 0) { - UHD_ASSERT_THROW("USB: failed to get device descriptor"); - } - - return desc.idVendor == 0xfffe; -} - std::vector usb_device_handle::get_device_list() { libusb_context *ctx = NULL; - libusb_device **list; - std::vector device_list; + std::vector libusb_device_list; + std::vector device_handle_list; libusb::init(&ctx, libusb_debug_level); - ssize_t cnt = libusb_get_device_list(ctx, &list); - - if (cnt < 0) - throw std::runtime_error("USB: enumeration failed"); + libusb_device_list = libusb::get_fsf_device_list(ctx); - ssize_t i = 0; - for (i = 0; i < cnt; i++) { - libusb_device *dev = list[i]; - if (check_fsf_device(dev)) - device_list.push_back(make_usb_device_handle(dev)); + for (size_t i = 0; i < libusb_device_list.size(); i++) { + libusb_device *dev = libusb_device_list[i]; + device_handle_list.push_back(make_usb_device_handle(dev)); } - libusb_free_device_list(list, 0); libusb_exit(ctx); - return device_list; + return device_handle_list; } -- cgit v1.2.3 From 72fc20bc8ba4cb636a04de78210aac483f4ffaf3 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 13:46:22 -0700 Subject: usrp1: Disable default debug output for libusb implementations --- host/lib/transport/libusb1_control.cpp | 2 +- host/lib/transport/libusb1_device_handle.cpp | 2 +- host/lib/transport/libusb1_zero_copy.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp index 8bf271256..4b827c350 100644 --- a/host/lib/transport/libusb1_control.cpp +++ b/host/lib/transport/libusb1_control.cpp @@ -20,7 +20,7 @@ using namespace uhd::transport; -const int libusb_debug_level = 3; +const int libusb_debug_level = 0; const int libusb_timeout = 0; /*********************************************************************** diff --git a/host/lib/transport/libusb1_device_handle.cpp b/host/lib/transport/libusb1_device_handle.cpp index 4885099eb..3476fdc4e 100644 --- a/host/lib/transport/libusb1_device_handle.cpp +++ b/host/lib/transport/libusb1_device_handle.cpp @@ -20,7 +20,7 @@ using namespace uhd::transport; -const int libusb_debug_level = 3; +const int libusb_debug_level = 0; class libusb1_device_handle_impl : public usb_device_handle { public: diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 55aa10cbb..2149625f9 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -25,7 +25,7 @@ using namespace uhd::transport; -const int libusb_debug_level = 3; +const int libusb_debug_level = 0; const int libusb_timeout = 0; /*********************************************************************** -- cgit v1.2.3 From aa4a6b6686967d39bd2f295c7170dc196abd68e6 Mon Sep 17 00:00:00 2001 From: Jason Abele Date: Fri, 27 Aug 2010 15:22:55 -0700 Subject: Created pps_test example and docs --- host/docs/usrp2.rst | 15 ++++++++ host/examples/CMakeLists.txt | 4 +++ host/examples/pps_test.cpp | 86 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 host/examples/pps_test.cpp diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index 3ac326f58..0d48209be 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -205,3 +205,18 @@ Example, set the args string to the following: :: addr=192.168.10.2, recv_buff_size=100e6 + +------------------------------------------------------------------------ +Hardware setup notes +------------------------------------------------------------------------ + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Ref Clock - 10MHz +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Using an external 10MHz reference clock requires a signal level between +5dBm and +20dBm at 10MHz applied to the Ref Clock SMA port on the front panel. + + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +PPS - Pulse Per Second +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Using a PPS signal for timestamp synchronization requires a 5Vpp square wave signal diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt index c3bbbcd04..5b241e284 100644 --- a/host/examples/CMakeLists.txt +++ b/host/examples/CMakeLists.txt @@ -28,10 +28,14 @@ TARGET_LINK_LIBRARIES(tx_timed_samples uhd) ADD_EXECUTABLE(tx_waveforms tx_waveforms.cpp) TARGET_LINK_LIBRARIES(tx_waveforms uhd) +ADD_EXECUTABLE(pps_test pps_test.cpp) +TARGET_LINK_LIBRARIES(pps_test uhd) + INSTALL(TARGETS benchmark_rx_rate rx_timed_samples tx_timed_samples tx_waveforms + pps_test RUNTIME DESTINATION ${PKG_DATA_DIR}/examples ) diff --git a/host/examples/pps_test.cpp b/host/examples/pps_test.cpp new file mode 100644 index 000000000..c25cbe94f --- /dev/null +++ b/host/examples/pps_test.cpp @@ -0,0 +1,86 @@ +// +// Copyright 2010 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 . +// + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + uhd::set_thread_priority_safe(); + + //variables to be set by po + std::string args; + float seconds; + + //setup the program options + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("args", po::value(&args)->default_value(""), "simple uhd device address args") + ; + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //print the help message + if (vm.count("help")){ + std::cout << boost::format("UHD PPS Test %s") % desc << std::endl; + return ~0; + } + + //create a usrp device + std::cout << std::endl; + std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; + uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); + uhd::device::sptr dev = sdev->get_device(); + std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; + + //set a known time value + std::cout << "Set time to known value (100.0) without regard to pps:" << std::endl; + sdev->set_time_now(uhd::time_spec_t(100.0)); + boost::this_thread::sleep(boost::posix_time::seconds(1)); + std::cout << boost::format("Reading time 1 second later: %f\n") % (sdev->get_time_now().get_full_secs()) << std::endl; + + //store the time to see if PPS resets it + seconds = sdev->get_time_now().get_full_secs(); + + //set a known time at next PPS, check that time increments + uhd::time_spec_t time_spec = uhd::time_spec_t(0.0); + std::cout << "Set time to known value (0.0) at next pps:" << std::endl; + sdev->set_time_next_pps(time_spec); + boost::this_thread::sleep(boost::posix_time::seconds(1)); + std::cout << boost::format("Reading time 1 second later: %f\n") % (sdev->get_time_now().get_full_secs()) << std::endl; + + //finished + if (seconds > sdev->get_time_now().get_full_secs()){ + std::cout << std::endl << "Success!" << std::endl << std::endl; + return 0; + } else { + std::cout << std::endl << "Failed!" << std::endl << std::endl + << "If you expected PPS to work:" << std::endl + << "\tsee Device App Notes for PPS level information" + << std::endl << std::endl; + return -1; + } +} -- cgit v1.2.3 From 94c450b32538272d714ec3b9da27e45152f6a099 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 27 Aug 2010 15:51:18 -0700 Subject: usrp1: some app notes --- host/docs/CMakeLists.txt | 1 + host/docs/index.rst | 1 + host/docs/usrp1.rst | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 host/docs/usrp1.rst diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt index b4383f88d..bbb8812b0 100644 --- a/host/docs/CMakeLists.txt +++ b/host/docs/CMakeLists.txt @@ -25,6 +25,7 @@ SET(manual_sources dboards.rst general.rst images.rst + usrp1.rst usrp2.rst ) diff --git a/host/docs/index.rst b/host/docs/index.rst index 6973ede19..bd55edc0b 100644 --- a/host/docs/index.rst +++ b/host/docs/index.rst @@ -22,6 +22,7 @@ Application Notes ^^^^^^^^^^^^^^^^^^^^^ * `General App Notes <./general.html>`_ * `Firmware and FPGA Image Notes <./images.html>`_ +* `USRP1 App Notes <./usrp1.html>`_ * `USRP2 App Notes <./usrp2.html>`_ * `Daughterboard App Notes <./dboards.html>`_ diff --git a/host/docs/usrp1.rst b/host/docs/usrp1.rst new file mode 100644 index 000000000..ebc33cbfa --- /dev/null +++ b/host/docs/usrp1.rst @@ -0,0 +1,41 @@ +======================================================================== +UHD - USRP1 Application Notes +======================================================================== + +.. contents:: Table of Contents + +------------------------------------------------------------------------ +Addressing the device +------------------------------------------------------------------------ +A USRP1 can be identified though its serial number, +designated by the "serial" key in the device address. + +The device address string representation for a USRP1 with serial 1234 + +:: + + serial=1234 + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Change the USRP1's serial number +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +TODO + +------------------------------------------------------------------------ +OS Specific Notes +------------------------------------------------------------------------ + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Setup Udev on Linux +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +On Linux, Udev handles USB plug and unplug events. +The following command creates a Udev rule for the USRP1 +so that non-root users may access the device: + +:: + + echo 'ACTION=="add", BUS=="usb", SYSFS{idVendor}=="fffe", SYSFS{idProduct}=="0002", MODE:="0666"' > tmpfile + sudo chown root.root tmpfile + sudo mv tmpfile /etc/udev/rules.d/10-usrp.rules + sudo udevadm control --reload-rules + -- cgit v1.2.3 From 7f8c73faa22aaf2a381193d9f460857785e45023 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 15:59:05 -0700 Subject: usrp1: Handle degenerate managed send buffer cases Handle degenerate usage of send buffer commits. If the buffer is destroyed without ever being submitted, submit a zero byte transfer to return control to the underlying structure. If a committed buffer is re-committed, then report an error message and return 0 bytes back. --- host/lib/transport/libusb1_zero_copy.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 2149625f9..4469991b8 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -555,7 +555,7 @@ public: libusb_managed_send_buffer_impl(libusb_transfer *lut, usb_endpoint *endpoint, size_t buff_size) - : _buff(lut->buffer, buff_size) + : _buff(lut->buffer, buff_size), _committed(false) { _lut = lut; _endpoint = endpoint; @@ -563,18 +563,32 @@ public: ~libusb_managed_send_buffer_impl() { - /* NOP */ + if (!_committed) { + _lut->length = 0; + _lut->actual_length = 0; + _endpoint->submit(_lut); + } } ssize_t commit(size_t num_bytes) { + if (_committed) { + std::cerr << "UHD: send buffer already committed" << std::endl; + return 0; + } + + UHD_ASSERT_THROW(num_bytes <= boost::asio::buffer_size(_buff)); + _lut->length = num_bytes; _lut->actual_length = 0; - if (_endpoint->submit(_lut)) + if (_endpoint->submit(_lut)) { + _committed = true; return num_bytes; - else + } + else { return 0; + } } private: @@ -586,6 +600,7 @@ private: libusb_transfer *_lut; usb_endpoint *_endpoint; const boost::asio::mutable_buffer _buff; + bool _committed; }; -- cgit v1.2.3 From ec8005e3d5d1a80f89f5cfbaa8e1cdadf2d14db6 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 16:20:15 -0700 Subject: usrp1: Wait for USB device renumeration only when necessary Waiting for FX2 renumeration is only needed after a firmware load so move it out of the main device discovery loop and into the firmware load itself. --- host/lib/usrp/usrp1/usrp1_ctrl.cpp | 4 ++++ host/lib/usrp/usrp1/usrp1_impl.cpp | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp index b7c6bdaf6..98226b738 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp @@ -19,6 +19,7 @@ #include "usrp_commands.h" #include #include +#include #include #include #include @@ -209,6 +210,9 @@ public: usrp_set_firmware_hash(hash); file.close(); + //wait for things to settle + boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); + return USRP_FIRMWARE_LOAD_SUCCESS; } //type anything else is unhandled diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index d37eec566..3c3306525 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -69,9 +69,6 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) } } - //wait for things to settle - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - //get descriptors again with serial number device_list = usb_device_handle::get_device_list(); -- cgit v1.2.3 From aa2ef7d246e93f4e6c0cb8b9b985a487cd2ea548 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 27 Aug 2010 16:59:13 -0700 Subject: usrp1: add the 4rx image to the installed usrp1 fpga images --- images/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/images/Makefile b/images/Makefile index 0e58fbb18..57277e787 100644 --- a/images/Makefile +++ b/images/Makefile @@ -68,11 +68,15 @@ endif ######################################################################## _usrp1_fpga_dir = $(TOP_FPGA_DIR)/usrp1/rbf/rev4 _usrp1_fpga_rbf = $(BUILT_IMAGES_DIR)/usrp1_fpga.rbf -IMAGES_LIST += $(_usrp1_fpga_rbf) +_usrp1_fpga_4rx_rbf = $(BUILT_IMAGES_DIR)/usrp1_fpga_4rx.rbf +IMAGES_LIST += $(_usrp1_fpga_rbf) $(_usrp1_fpga_4rx_rbf) $(_usrp1_fpga_rbf): cp $(_usrp1_fpga_dir)/std_2rxhb_2tx.rbf $@ +$(_usrp1_fpga_4rx_rbf): + cp $(_usrp1_fpga_dir)/std_4rx_0tx.rbf $@ + ######################################################################## # USRP2 firmware ######################################################################## -- cgit v1.2.3 From 55da3154519639d84f4d008431461829646823bd Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 20:35:17 -0700 Subject: usrp1: Additional comments to libusb transport implementation --- host/lib/transport/libusb1_zero_copy.cpp | 183 ++++++++++++++++++------------- 1 file changed, 104 insertions(+), 79 deletions(-) diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 4469991b8..edbeb5673 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -64,16 +64,12 @@ private: size_t _transfer_size; size_t _num_transfers; - /* - * Transfer state lists (free, pending, or completed) - */ + // Transfer state lists (transfers are free, pending, or completed) std::list _free_list; std::list _pending_list; std::list _completed_list; - /* - * Calls for processing asynchronous I/O - */ + // Calls for processing asynchronous I/O libusb_transfer *allocate_transfer(int buff_len); bool cancel(libusb_transfer *lut); bool cancel_all(); @@ -81,9 +77,7 @@ private: bool reap_pending_list_timeout(); bool reap_completed_list(); - /* - * Transfer state manipulators - */ + // Transfer state manipulators void free_list_add(libusb_transfer *lut); void pending_list_add(libusb_transfer *lut); void completed_list_add(libusb_transfer *lut); @@ -91,9 +85,7 @@ private: libusb_transfer *completed_list_get(); bool pending_list_remove(libusb_transfer *lut); - /* - * Misc - */ + // Debug use void print_transfer_status(libusb_transfer *lut); public: @@ -103,25 +95,18 @@ public: ~usb_endpoint(); - /* - * Accessors - */ + // Accessors int get_endpoint() const { return _endpoint; } bool get_direction() const { return _input; } libusb_device_handle *get_dev_handle() const { return _dev_handle; } libusb_context *get_ctx() const { return _ctx; } - /* - * Exposed interface for submitting / retrieving transfer buffers - * used in zero-copy interface - */ + // Exposed interface for submitting / retrieving transfer buffers bool submit(libusb_transfer *lut); libusb_transfer *get_completed_transfer(); libusb_transfer *get_free_transfer(); - /* - * Callback use only - */ + //Callback use only void callback_handle_transfer(libusb_transfer *lut); }; @@ -130,6 +115,10 @@ public: * Callback function called when submitted transfers complete. * The endpoint upon which the transfer is part of is recovered * and the transfer moved from pending to completed state. + * Callbacks occur during the reaping calls where libusb_handle_events() + * is used. The callback only modifies the transfer state by moving + * it from the pending to completed status list. + * \param lut pointer to libusb_transfer */ static void callback(libusb_transfer *lut) { @@ -140,6 +129,7 @@ static void callback(libusb_transfer *lut) /* * Accessor call to allow list access from callback space + * \param pointer to libusb_transfer */ void usb_endpoint::callback_handle_transfer(libusb_transfer *lut) { @@ -154,9 +144,9 @@ void usb_endpoint::callback_handle_transfer(libusb_transfer *lut) /* * Constructor - * - * Allocate libusb transfers. For IN endpoints, submit the transfers - * so that they're ready to return when data is available. + * Allocate libusb transfers and mark as free. For IN endpoints, + * submit the transfers so that they're ready to return when + * data is available. */ usb_endpoint::usb_endpoint(libusb_device_handle *dev_handle, libusb_context *ctx, int endpoint, bool input, @@ -177,6 +167,10 @@ usb_endpoint::usb_endpoint(libusb_device_handle *dev_handle, /* * Destructor + * Make sure all the memory is freed. Cancel any pending transfers. + * When all completed transfers are moved to the free list, release + * the transfers. Libusb will deallocate the data buffer held by + * each transfer. */ usb_endpoint::~usb_endpoint() { @@ -200,9 +194,10 @@ usb_endpoint::~usb_endpoint() /* * Allocate a libusb transfer - * - * The allocated transfer is continuously reused and should be freed at - * shutdown. + * The allocated transfer - and buffer it contains - is repeatedly + * submitted, reaped, and reused and should not be freed until shutdown. + * \param buff_len size of the individual buffer held by each transfer + * \return pointer to an allocated libusb_transfer */ libusb_transfer *usb_endpoint::allocate_transfer(int buff_len) { @@ -226,8 +221,9 @@ libusb_transfer *usb_endpoint::allocate_transfer(int buff_len) /* * Asynchonous transfer submission - * - * Submit and mark transfer as pending. + * Submit a libusb transfer to libusb add pending status + * \param lut pointer to libusb_transfer + * \return true on success or false on error */ bool usb_endpoint::submit(libusb_transfer *lut) { @@ -244,9 +240,9 @@ bool usb_endpoint::submit(libusb_transfer *lut) /* * Cancel a pending transfer - * * Search the pending list for the transfer and cancel if found. - * Returns true on success. False otherwise or on error. + * \param lut pointer to libusb_transfer to cancel + * \return true on success or false if transfer is not found * * Note: success only indicates submission of cancelation request. * Sucessful cancelation is not known until the callback occurs. @@ -266,6 +262,7 @@ bool usb_endpoint::cancel(libusb_transfer *lut) /* * Cancel all pending transfers + * \return bool true if cancelation request is submitted * * Note: success only indicates submission of cancelation request. * Sucessful cancelation is not known until the callback occurs. @@ -287,11 +284,10 @@ bool usb_endpoint::cancel_all() /* * Reap completed transfers - * * return true if at least one transfer was reaped, false otherwise. - * * Check completed transfers for errors and mark as free. This is a * blocking call. + * \return bool true if a libusb transfer is reaped, false otherwise */ bool usb_endpoint::reap_completed_list() { @@ -313,12 +309,8 @@ bool usb_endpoint::reap_completed_list() /* - * Print completed transfer status error(s) - * - * return true if at least one transfer was reaped, false otherwise. - * - * Check completed transfers for errors and mark as free. This is a - * blocking call. + * Print status errors of a completed transfer + * \param lut pointer to an libusb_transfer */ void usb_endpoint::print_transfer_status(libusb_transfer *lut) { @@ -359,13 +351,11 @@ void usb_endpoint::print_transfer_status(libusb_transfer *lut) /* - * Reap pending transfers - * - * Return true if at least one transfer was reaped, false otherwise. This is - * a blocking call. - * - * Reaping submitted transfers is handled by libusb and the assigned callback - * function. Block until at least one transfer is reaped. + * Reap pending transfers without timeout + * This is a blocking call. Reaping submitted transfers is + * handled by libusb and the assigned callback function. + * Block until at least one transfer is reaped. + * \return true true if a transfer was reaped or false otherwise */ bool usb_endpoint::reap_pending_list() { @@ -382,12 +372,11 @@ bool usb_endpoint::reap_pending_list() /* * Reap pending transfers with timeout - * - * Return true if at least one transfer was reaped, false otherwise. This call - * blocks until a transfer is reaped or timeout. - * - * Reaping submitted transfers is handled by libusb and the assigned callback - * function. Block until at least one transfer is reaped or timeout occurs. + * This call blocks until a transfer is reaped or timeout. + * Reaping submitted transfers is handled by libusb and the + * assigned callback function. Block until at least one + * transfer is reaped or timeout occurs. + * \return true if a transfer was reaped or false otherwise */ bool usb_endpoint::reap_pending_list_timeout() { @@ -414,7 +403,9 @@ bool usb_endpoint::reap_pending_list_timeout() /* - * Returns a free transfer with empty data bufer for OUT requests + * Get a free transfer + * The transfer has an empty data bufer for OUT requests + * \return pointer to a libusb_transfer */ libusb_transfer *usb_endpoint::get_free_transfer() { @@ -428,7 +419,9 @@ libusb_transfer *usb_endpoint::get_free_transfer() /* - * Returns a transfer containing data for IN requests + * Get a completed transfer + * The transfer has a full data buffer for IN requests + * \return pointer to libusb_transfer */ libusb_transfer *usb_endpoint::get_completed_transfer() { @@ -461,7 +454,6 @@ void usb_endpoint::completed_list_add(libusb_transfer *lut) /* * Free and completed lists don't have ordered content - * * Pop transfers from the front as needed */ libusb_transfer *usb_endpoint::free_list_get() @@ -481,7 +473,6 @@ libusb_transfer *usb_endpoint::free_list_get() /* * Free and completed lists don't have ordered content - * * Pop transfers from the front as needed */ libusb_transfer *usb_endpoint::completed_list_get() @@ -501,7 +492,6 @@ libusb_transfer *usb_endpoint::completed_list_get() /* * Search and remove transfer from pending list - * * Assuming that the callbacks occur in order, the front element * should yield the correct transfer. If not, then something else * is going on. If no transfers match, then something went wrong. @@ -522,6 +512,13 @@ bool usb_endpoint::pending_list_remove(libusb_transfer *lut) /*********************************************************************** * Managed buffers **********************************************************************/ +/* + * Libusb managed receive buffer + * Construct a recv buffer from a libusb transfer. The memory held by + * the libusb transfer is exposed through the managed buffer interface. + * Upon destruction, the transfer and buffer are resubmitted to the + * endpoint for further use. + */ class libusb_managed_recv_buffer_impl : public managed_recv_buffer { public: libusb_managed_recv_buffer_impl(libusb_transfer *lut, @@ -549,7 +546,15 @@ private: const boost::asio::const_buffer _buff; }; - +/* + * Libusb managed send buffer + * Construct a send buffer from a libusb transfer. The memory held by + * the libusb transfer is exposed through the managed buffer interface. + * Committing the buffer will set the data length and submit the buffer + * to the endpoint. Submitting a buffer multiple times or destroying + * the buffer before committing is an error. For the latter, the transfer + * is returned to the endpoint with no data for reuse. + */ class libusb_managed_send_buffer_impl : public managed_send_buffer { public: libusb_managed_send_buffer_impl(libusb_transfer *lut, @@ -613,9 +618,7 @@ private: usb_endpoint *_rx_ep; usb_endpoint *_tx_ep; - /* - * Libusb handles - */ + // Maintain libusb values libusb_context *_rx_ctx; libusb_context *_tx_ctx; libusb_device_handle *_rx_dev_handle; @@ -628,9 +631,6 @@ private: public: typedef boost::shared_ptr sptr; - /* - * Structors - */ libusb_zero_copy_impl(usb_device_handle::sptr handle, unsigned int rx_endpoint, unsigned int tx_endpoint, @@ -646,7 +646,11 @@ public: size_t get_num_send_frames(void) const { return _num_frames; } }; - +/* + * Constructor + * Initializes libusb, opens devices, and sets up interfaces for I/O. + * Finally, creates endpoints for asynchronous I/O. + */ libusb_zero_copy_impl::libusb_zero_copy_impl(usb_device_handle::sptr handle, unsigned int rx_endpoint, unsigned int tx_endpoint, @@ -656,30 +660,39 @@ libusb_zero_copy_impl::libusb_zero_copy_impl(usb_device_handle::sptr handle, _recv_buff_size(block_size), _send_buff_size(block_size), _num_frames(buff_size / block_size) { + // Initialize libusb with separate contexts to allow + // thread safe operation of transmit and receive libusb::init(&_rx_ctx, libusb_debug_level); libusb::init(&_tx_ctx, libusb_debug_level); UHD_ASSERT_THROW((_rx_ctx != NULL) && (_tx_ctx != NULL)); + // Find and open the libusb_device corresponding to the + // given handle and return the libusb_device_handle + // that can be used for I/O purposes. _rx_dev_handle = libusb::open_device(_rx_ctx, handle); _tx_dev_handle = libusb::open_device(_tx_ctx, handle); + // Open USB interfaces for tx/rx using magic values. + // IN interface: 2 + // OUT interface: 1 + // Control interface: 0 libusb::open_interface(_rx_dev_handle, 2); libusb::open_interface(_tx_dev_handle, 1); - _rx_ep = new usb_endpoint(_rx_dev_handle, - _rx_ctx, - rx_endpoint, - true, - _recv_buff_size, - _num_frames); - - _tx_ep = new usb_endpoint(_tx_dev_handle, - _tx_ctx, - tx_endpoint, - false, - _send_buff_size, - _num_frames); + _rx_ep = new usb_endpoint(_rx_dev_handle, // libusb device_handle + _rx_ctx, // libusb context + rx_endpoint, // USB endpoint number + true, // IN endpoint + _recv_buff_size, // buffer size per transfer + _num_frames); // number of libusb transfers + + _tx_ep = new usb_endpoint(_tx_dev_handle, // libusb device_handle + _tx_ctx, // libusb context + tx_endpoint, // USB endpoint number + false, // OUT endpoint + _send_buff_size, // buffer size per transfer + _num_frames); // number of libusb transfers } @@ -696,6 +709,12 @@ libusb_zero_copy_impl::~libusb_zero_copy_impl() } +/* + * Construct a managed receive buffer from a completed libusb transfer + * (happy with buffer full of data) obtained from the receive endpoint. + * Return empty pointer if no transfer is available (timeout or error). + * \return pointer to a managed receive buffer + */ managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff() { libusb_transfer *lut = _rx_ep->get_completed_transfer(); @@ -710,6 +729,12 @@ managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff() } +/* + * Construct a managed send buffer from a free libusb transfer (with + * empty buffer). Return empty pointer of no transfer is available + * (timeout or error). + * \return pointer to a managed send buffer + */ managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff() { libusb_transfer *lut = _tx_ep->get_free_transfer(); -- cgit v1.2.3 From 76365acdbb22c5a4c6c2d9b6fbcc015ace6df09a Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 20:39:26 -0700 Subject: usrp1: Remove unused funtions libusb transport --- host/lib/transport/libusb1_zero_copy.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index edbeb5673..518b8baf0 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -95,12 +95,6 @@ public: ~usb_endpoint(); - // Accessors - int get_endpoint() const { return _endpoint; } - bool get_direction() const { return _input; } - libusb_device_handle *get_dev_handle() const { return _dev_handle; } - libusb_context *get_ctx() const { return _ctx; } - // Exposed interface for submitting / retrieving transfer buffers bool submit(libusb_transfer *lut); libusb_transfer *get_completed_transfer(); -- cgit v1.2.3 From 7d7479ad0569337910f01b77df9bd8e3d385f8a5 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 22:40:21 -0700 Subject: usrp1: Don't flush the stream buffer after every overrun/underrun --- host/lib/usrp/usrp1/io_impl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 5e206b3d5..920c47b30 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -189,7 +189,7 @@ bool usrp1_impl::io_impl::check_underrun(usrp_ctrl::sptr ctrl_if, if (ret < 0) std::cerr << "USRP: underrun check failed" << std::endl; if (underrun) - std::cerr << "U" << std::endl; + std::cerr << "Uu"; send_state.underrun_poll_samp_count = 0; } @@ -289,7 +289,7 @@ bool usrp1_impl::io_impl::check_overrun(usrp_ctrl::sptr ctrl_if, if (ret < 0) std::cerr << "USRP: overrrun check failed" << std::endl; if (overrun) - std::cerr << "O" << std::endl; + std::cerr << "Oo"; recv_state.overrun_poll_samp_count = 0; } -- cgit v1.2.3 From 2c85b17215fbe5fd2f80a8c6d0c47504a631c09b Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 23:16:43 -0700 Subject: usrp1: Read capabilities register --- host/lib/usrp/usrp1/mboard_impl.cpp | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index 0b1335acf..75129c32f 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -160,6 +160,35 @@ static boost::uint32_t calc_tx_mux( return ((channel_flags & 0xffff) << 4) | ((nchan & 0x7) << 0); } +/*! + * Capabilities Register + * + * 3 2 1 0 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-----------------------------------------------+-+-----+-+-----+ + * | Reserved |T|DUCs |R|DDCs | + * +-----------------------------------------------+-+-----+-+-----+ + */ +static int num_ddcs(boost::uint32_t regval) +{ + return (regval >> 0) & 0x0007; +} + +static int num_ducs(boost::uint32_t regval) +{ + return (regval >> 4) & 0x0007; +} + +static bool has_rx_halfband(boost::uint32_t regval) +{ + return (regval >> 3) & 0x0001; +} + +static bool has_tx_halfband(boost::uint32_t regval) +{ + return (regval >> 7) & 0x0001; +} + /*********************************************************************** * Mboard Initialization **********************************************************************/ @@ -187,6 +216,17 @@ void usrp1_impl::mboard_init(void) // Set default for TX format to 16-bit I&Q _iface->poke32(FR_TX_FORMAT, 0x00000000); + + // TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO + // + // Do something useful with the capabilities register + // + boost::uint32_t regval = _iface->peek32(FR_RB_CAPS); + std::cout << "USRP1 Capabilities" << std::endl; + std::cout << " number of duc's: " << num_ddcs(regval) << std::endl; + std::cout << " number of ddc's: " << num_ducs(regval) << std::endl; + std::cout << " rx halfband: " << has_rx_halfband(regval) << std::endl; + std::cout << " tx halfband: " << has_tx_halfband(regval) << std::endl; } void usrp1_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd) -- cgit v1.2.3 From ad55e25aeb273fb7278c6d5175cd0df01fc90924 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 27 Aug 2010 23:46:16 -0700 Subject: usrp1: Additional comments on libusb transport implemenation --- host/lib/transport/libusb1_base.cpp | 12 ++++++ host/lib/transport/libusb1_base.hpp | 60 ++++++++++++++++++++++++++++ host/lib/transport/libusb1_control.cpp | 7 ++++ host/lib/transport/libusb1_device_handle.cpp | 3 ++ host/lib/transport/libusb1_zero_copy.cpp | 8 ++-- 5 files changed, 87 insertions(+), 3 deletions(-) diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index 493d4eff3..92dcd969f 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -21,6 +21,15 @@ using namespace uhd::transport; +/********************************************************** + * Helper Methods + **********************************************************/ +/* + * Check for FSF device + * Compare the device's descriptor Vendor ID + * \param dev pointer to libusb_device + * \return true if Vendor ID matches 0xfffe + */ bool check_fsf_device(libusb_device *dev) { libusb_device_descriptor desc; @@ -32,6 +41,9 @@ bool check_fsf_device(libusb_device *dev) return desc.idVendor == 0xfffe; } +/********************************************************** + * libusb namespace + **********************************************************/ void libusb::init(libusb_context **ctx, int debug_level) { if (libusb_init(ctx) < 0) diff --git a/host/lib/transport/libusb1_base.hpp b/host/lib/transport/libusb1_base.hpp index 708a42c73..442f89ded 100644 --- a/host/lib/transport/libusb1_base.hpp +++ b/host/lib/transport/libusb1_base.hpp @@ -25,17 +25,77 @@ namespace uhd { namespace transport { namespace libusb { + /* + * Initialize libusb and set debug level + * Takes a pointer to context pointer because that's + * how libusb rolls. Debug levels. + * + * Level 0: no messages ever printed by the library (default) + * Level 1: error messages are printed to stderr + * Level 2: warning and error messages are printed to stderr + * Level 3: informational messages are printed to stdout, warning + * and error messages are printed to stderr + * + * \param ctx pointer to context pointer + * \param debug_level + */ void init(libusb_context **ctx, int debug_level); + /* + * Get a list of Free Software Foundation devices (Vendor ID 0xfffe) + * As opposed to the public USB device handle interface, which returns + * generic identifiers, this call returns device pointers speficic + * to libusb. + * \param ctx the libusb context used for init + * \return a vector of libusb devices + */ std::vector get_fsf_device_list(libusb_context *ctx); + /* + * Open the device specified by a generic handle + * Find the libusb_device cooresponding to the generic handle + * and open it for I/O, which returns a libusb_device_handle + * ready for an interface + * \param ctx the libusb context used for init + * \return a libusb_device_handle ready for action + */ libusb_device_handle *open_device(libusb_context *ctx, usb_device_handle::sptr handle); + /* + * Compare a libusb device with a generic handle + * Check the descriptors and open the device to check the + * serial number string. Compare values against the given + * handle. The libusb context is already implied in the + * libusb_device. + * \param dev a libusb_device pointer + * \param handle a generic handle specifier + * \return true if handle and device match, false otherwise + */ bool compare_device(libusb_device *dev, usb_device_handle::sptr handle); + /* + * Open an interface to the device + * This is a logical operation for operating system housekeeping as + * nothing is sent over the bus. The interface much correspond + * to the USB device descriptors. + * \param dev_handle libusb handle to an opened device + * \param interface integer of the interface to use + * \return true on success, false on error + */ bool open_interface(libusb_device_handle *dev_handle, int interface); + /* + * Get serial number + * The standard USB device descriptor contains an index to an + * actual serial number string descriptor. The index is readily + * readble, but the string descriptor requires probing the device. + * Because this call attempts to open the device, it may not + * succeed because not all USB devices are readily opened. + * The default language is used for the request (English). + * \param dev a libusb_device pointer + * \return string serial number or 0 on error or unavailablity + */ std::string get_serial(libusb_device *dev); } diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp index 4b827c350..3531128b2 100644 --- a/host/lib/transport/libusb1_control.cpp +++ b/host/lib/transport/libusb1_control.cpp @@ -48,8 +48,15 @@ libusb_control_impl::libusb_control_impl(usb_device_handle::sptr handle) { libusb::init(&_ctx, libusb_debug_level); + // Find and open the libusb_device corresponding to the + // given handle and return the libusb_device_handle + // that can be used for I/O purposes. _dev_handle = libusb::open_device(_ctx, handle); + // Open USB interfaces for control using magic value + // IN interface: 2 + // OUT interface: 1 + // Control interface: 0 libusb::open_interface(_dev_handle, 0); } diff --git a/host/lib/transport/libusb1_device_handle.cpp b/host/lib/transport/libusb1_device_handle.cpp index 3476fdc4e..5d9d8faf0 100644 --- a/host/lib/transport/libusb1_device_handle.cpp +++ b/host/lib/transport/libusb1_device_handle.cpp @@ -22,6 +22,9 @@ using namespace uhd::transport; const int libusb_debug_level = 0; +/**************************************************************** + * libusb USB device handle implementation class + ***************************************************************/ class libusb1_device_handle_impl : public usb_device_handle { public: libusb1_device_handle_impl(std::string serial, diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 518b8baf0..b890a87f9 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -30,9 +30,11 @@ const int libusb_timeout = 0; /*********************************************************************** * Helper functions - * - * Print to stdout the values of a libusb_transfer struct ***********************************************************************/ +/* + * Print the values of a libusb_transfer struct + * http://libusb.sourceforge.net/api-1.0/structlibusb__transfer.html + */ void pp_transfer(libusb_transfer *lut) { std::cout << "Libusb transfer" << std::endl; @@ -46,7 +48,7 @@ void pp_transfer(libusb_transfer *lut) } /*********************************************************************** - * USB asynchronous phony zero_copy endpoint + * USB asynchronous zero_copy endpoint * This endpoint implementation provides asynchronous I/O to libusb-1.0 * devices. Each endpoint is directional and two can be combined to * create a bidirectional interface. It is a zero copy implementation -- cgit v1.2.3 From 79ea83d6b352a7865ff6143ba77fcc0956c6452f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 30 Aug 2010 12:33:13 -0700 Subject: uhd: fixed short conversion (IQ swap) and added test between short/float --- host/lib/transport/convert_types_impl.hpp | 27 +++++++--- host/lib/transport/gen_convert_types.py | 2 +- host/test/convert_types_test.cpp | 84 ++++++++++++++++++++++++++++++- 3 files changed, 105 insertions(+), 8 deletions(-) diff --git a/host/lib/transport/convert_types_impl.hpp b/host/lib/transport/convert_types_impl.hpp index fdc859883..90618dec6 100644 --- a/host/lib/transport/convert_types_impl.hpp +++ b/host/lib/transport/convert_types_impl.hpp @@ -42,36 +42,51 @@ typedef boost::uint32_t item32_t; /*********************************************************************** * Convert complex short buffer to items32 **********************************************************************/ +static UHD_INLINE item32_t sc16_to_item32(sc16_t num){ + boost::uint16_t real = num.real(); + boost::uint16_t imag = num.imag(); + return (item32_t(real) << 16) | (item32_t(imag) << 0); +} + static UHD_INLINE void sc16_to_item32_nswap( const sc16_t *input, item32_t *output, size_t nsamps ){ - std::memcpy(output, input, nsamps*sizeof(item32_t)); + for (size_t i = 0; i < nsamps; i++){ + output[i] = sc16_to_item32(input[i]); + } } static UHD_INLINE void sc16_to_item32_bswap( const sc16_t *input, item32_t *output, size_t nsamps ){ - const item32_t *item32_input = (const item32_t *)input; for (size_t i = 0; i < nsamps; i++){ - output[i] = uhd::byteswap(item32_input[i]); + output[i] = uhd::byteswap(sc16_to_item32(input[i])); } } /*********************************************************************** * Convert items32 buffer to complex short **********************************************************************/ +static UHD_INLINE sc16_t item32_to_sc16(item32_t item){ + return sc16_t( + boost::int16_t(item >> 16), + boost::int16_t(item >> 0) + ); +} + static UHD_INLINE void item32_to_sc16_nswap( const item32_t *input, sc16_t *output, size_t nsamps ){ - std::memcpy(output, input, nsamps*sizeof(item32_t)); + for (size_t i = 0; i < nsamps; i++){ + output[i] = item32_to_sc16(input[i]); + } } static UHD_INLINE void item32_to_sc16_bswap( const item32_t *input, sc16_t *output, size_t nsamps ){ - item32_t *item32_output = (item32_t *)output; for (size_t i = 0; i < nsamps; i++){ - item32_output[i] = uhd::byteswap(input[i]); + output[i] = item32_to_sc16(uhd::byteswap(input[i])); } } diff --git a/host/lib/transport/gen_convert_types.py b/host/lib/transport/gen_convert_types.py index 951b634d9..17d8ffde0 100755 --- a/host/lib/transport/gen_convert_types.py +++ b/host/lib/transport/gen_convert_types.py @@ -95,7 +95,7 @@ void transport::convert_otw_type_to_io_type( size_t num_samps ){ switch(get_pred(io_type, otw_type)){ - #for $pred in range(4) + #for $pred in range(2**$ph.nbits) case $pred: #set $out_type = $ph.get_host_type($pred) #set $in_type = $ph.get_dev_type($pred) diff --git a/host/test/convert_types_test.cpp b/host/test/convert_types_test.cpp index d132a708b..2148302b6 100644 --- a/host/test/convert_types_test.cpp +++ b/host/test/convert_types_test.cpp @@ -27,7 +27,7 @@ using namespace uhd; //typedefs for complex types -typedef std::complex sc16_t; +typedef std::complex sc16_t; typedef std::complex fc32_t; //extract pointer to POD since using &vector.front() throws in MSVC @@ -158,3 +158,85 @@ BOOST_AUTO_TEST_CASE(test_convert_types_le_fc32){ test_convert_types_fc32(nsamps, io_type, otw_type); } } + +/*********************************************************************** + * Test float to short conversion loopback + **********************************************************************/ +BOOST_AUTO_TEST_CASE(test_convert_types_fc32_to_sc16){ + io_type_t io_type_in(io_type_t::COMPLEX_FLOAT32); + io_type_t io_type_out(io_type_t::COMPLEX_INT16); + + otw_type_t otw_type; + otw_type.byteorder = otw_type_t::BO_NATIVE; + otw_type.width = 16; + + const size_t nsamps = 13; + std::vector input(nsamps); + BOOST_FOREACH(fc32_t &in, input) in = fc32_t( + (std::rand()/float(RAND_MAX/2)) - 1, + (std::rand()/float(RAND_MAX/2)) - 1 + ); + + //convert float to dev + std::vector tmp(nsamps); + transport::convert_io_type_to_otw_type( + pod2ptr(input), io_type_in, + pod2ptr(tmp), otw_type, + nsamps + ); + + //convert dev to short + std::vector output(nsamps); + transport::convert_otw_type_to_io_type( + pod2ptr(tmp), otw_type, + pod2ptr(output), io_type_out, + nsamps + ); + + //test that the inputs and outputs match + for (size_t i = 0; i < nsamps; i++){ + BOOST_CHECK_CLOSE_FRACTION(input[i].real(), output[i].real()/float(32767), float(0.01)); + BOOST_CHECK_CLOSE_FRACTION(input[i].imag(), output[i].imag()/float(32767), float(0.01)); + } +} + +/*********************************************************************** + * Test short to float conversion loopback + **********************************************************************/ +BOOST_AUTO_TEST_CASE(test_convert_types_sc16_to_fc32){ + io_type_t io_type_in(io_type_t::COMPLEX_INT16); + io_type_t io_type_out(io_type_t::COMPLEX_FLOAT32); + + otw_type_t otw_type; + otw_type.byteorder = otw_type_t::BO_NATIVE; + otw_type.width = 16; + + const size_t nsamps = 13; + std::vector input(nsamps); + BOOST_FOREACH(sc16_t &in, input) in = sc16_t( + std::rand()-(RAND_MAX/2), + std::rand()-(RAND_MAX/2) + ); + + //convert short to dev + std::vector tmp(nsamps); + transport::convert_io_type_to_otw_type( + pod2ptr(input), io_type_in, + pod2ptr(tmp), otw_type, + nsamps + ); + + //convert dev to float + std::vector output(nsamps); + transport::convert_otw_type_to_io_type( + pod2ptr(tmp), otw_type, + pod2ptr(output), io_type_out, + nsamps + ); + + //test that the inputs and outputs match + for (size_t i = 0; i < nsamps; i++){ + BOOST_CHECK_CLOSE_FRACTION(input[i].real()/float(32767), output[i].real(), float(0.01)); + BOOST_CHECK_CLOSE_FRACTION(input[i].imag()/float(32767), output[i].imag(), float(0.01)); + } +} -- cgit v1.2.3 From 99494305b35adf5c4f89b4888192c723f32d9da2 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 30 Aug 2010 16:00:35 -0700 Subject: uhd: added interleave/de-interleave type conversion routines --- host/include/uhd/transport/CMakeLists.txt | 1 + host/include/uhd/transport/convert_types.hpp | 37 ++++++++++ host/include/uhd/transport/convert_types.ipp | 43 +++++++++++ host/lib/transport/gen_convert_types.py | 105 ++++++++++++++++++++++----- 4 files changed, 166 insertions(+), 20 deletions(-) create mode 100644 host/include/uhd/transport/convert_types.ipp diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index 93e9a6485..01856454f 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -22,6 +22,7 @@ INSTALL(FILES bounded_buffer.hpp bounded_buffer.ipp convert_types.hpp + convert_types.ipp if_addrs.hpp udp_simple.hpp udp_zero_copy.hpp diff --git a/host/include/uhd/transport/convert_types.hpp b/host/include/uhd/transport/convert_types.hpp index a4d999240..dc7fa6c1a 100644 --- a/host/include/uhd/transport/convert_types.hpp +++ b/host/include/uhd/transport/convert_types.hpp @@ -21,6 +21,7 @@ #include #include #include +#include namespace uhd{ namespace transport{ @@ -39,6 +40,23 @@ UHD_API void convert_io_type_to_otw_type( size_t num_samps ); +/*! + * Convert IO samples to OWT samples + interleave. + * + * \param io_buffs buffers containing samples + * \param io_type the type of these samples + * \param otw_buff memory to write converted samples + * \param otw_type the type of these samples + * \param nsamps_per_io_buff samples per io_buff + */ +UHD_API void convert_io_type_to_otw_type( + const std::vector &io_buffs, + const io_type_t &io_type, + void *otw_buff, + const otw_type_t &otw_type, + size_t nsamps_per_io_buff +); + /*! * Convert OTW samples to IO samples. * @@ -54,6 +72,25 @@ UHD_API void convert_otw_type_to_io_type( size_t num_samps ); +/*! + * Convert OTW samples to IO samples + de-interleave. + * + * \param otw_buff memory containing samples + * \param otw_type the type of these samples + * \param io_buffs buffers to write converted samples + * \param io_type the type of these samples + * \param nsamps_per_io_buff samples per io_buff + */ +UHD_API void convert_otw_type_to_io_type( + const void *otw_buff, + const otw_type_t &otw_type, + std::vector &io_buffs, + const io_type_t &io_type, + size_t nsamps_per_io_buff +); + }} //namespace +#include + #endif /* INCLUDED_UHD_TRANSPORT_CONVERT_TYPES_HPP */ diff --git a/host/include/uhd/transport/convert_types.ipp b/host/include/uhd/transport/convert_types.ipp new file mode 100644 index 000000000..914ca6f17 --- /dev/null +++ b/host/include/uhd/transport/convert_types.ipp @@ -0,0 +1,43 @@ +// +// Copyright 2010 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 . +// + +#ifndef INCLUDED_UHD_TRANSPORT_CONVERT_TYPES_IPP +#define INCLUDED_UHD_TRANSPORT_CONVERT_TYPES_IPP + +UHD_INLINE void uhd::transport::convert_io_type_to_otw_type( + const void *io_buff, const io_type_t &io_type, + void *otw_buff, const otw_type_t &otw_type, + size_t num_samps +){ + std::vector buffs(1, io_buff); + return uhd::transport::convert_io_type_to_otw_type( + buffs, io_type, otw_buff, otw_type, num_samps + ); +} + +UHD_INLINE void uhd::transport::convert_otw_type_to_io_type( + const void *otw_buff, const otw_type_t &otw_type, + void *io_buff, const io_type_t &io_type, + size_t num_samps +){ + std::vector buffs(1, io_buff); + return uhd::transport::convert_otw_type_to_io_type( + otw_buff, otw_type, buffs, io_type, num_samps + ); +} + +#endif /* INCLUDED_UHD_TRANSPORT_CONVERT_TYPES_IPP */ diff --git a/host/lib/transport/gen_convert_types.py b/host/lib/transport/gen_convert_types.py index 17d8ffde0..adbd22868 100755 --- a/host/lib/transport/gen_convert_types.py +++ b/host/lib/transport/gen_convert_types.py @@ -36,7 +36,8 @@ using namespace uhd; **********************************************************************/ UHD_INLINE boost::uint8_t get_pred( const io_type_t &io_type, - const otw_type_t &otw_type + const otw_type_t &otw_type, + size_t num_chans ){ boost::uint8_t pred = 0; @@ -63,6 +64,14 @@ UHD_INLINE boost::uint8_t get_pred( default: throw std::runtime_error("unhandled io type id"); } + switch(num_chans){ + case 1: pred |= $ph.chan1_p; break; + case 2: pred |= $ph.chan2_p; break; + case 3: pred |= $ph.chan3_p; break; + case 4: pred |= $ph.chan4_p; break; + default: throw std::runtime_error("unhandled number of channels"); + } + return pred; } @@ -70,17 +79,37 @@ UHD_INLINE boost::uint8_t get_pred( * Convert host type to device type **********************************************************************/ void transport::convert_io_type_to_otw_type( - const void *io_buff, const io_type_t &io_type, - void *otw_buff, const otw_type_t &otw_type, - size_t num_samps + const std::vector &io_buffs, + const io_type_t &io_type, + void *otw_buff, + const otw_type_t &otw_type, + size_t nsamps_per_io_buff ){ - switch(get_pred(io_type, otw_type)){ + switch(get_pred(io_type, otw_type, io_buffs.size())){ #for $pred in range(2**$ph.nbits) case $pred: #set $out_type = $ph.get_dev_type($pred) #set $in_type = $ph.get_host_type($pred) - #set $converter = '_'.join([$in_type, 'to', $out_type, $ph.get_swap_type($pred)]) - $(converter)((const $(in_type)_t *)io_buff, ($(out_type)_t *)otw_buff, num_samps); + #set $num_chans = $ph.get_num_chans($pred) + #set $converter = '_'.join([$in_type, 'to', $out_type]) + #if $num_chans == 1 + $(converter)_$ph.get_swap_type($pred)( + reinterpret_cast(io_buffs.front()), + reinterpret_cast<$(out_type)_t *>(otw_buff), + nsamps_per_io_buff + ); + #else + for (size_t i = 0; i < nsamps_per_io_buff; i++){ + #for $j in range($num_chans) + reinterpret_cast<$(out_type)_t *>(otw_buff)[i*$num_chans + $j] = + #if $ph.get_swap_type($pred) == 'bswap' + uhd::byteswap($(converter)(reinterpret_cast(io_buffs[$j])[i])); + #else + $(converter)(reinterpret_cast(io_buffs[$j])[i]); + #end if + #end for + } + #end if break; #end for } @@ -90,17 +119,37 @@ void transport::convert_io_type_to_otw_type( * Convert device type to host type **********************************************************************/ void transport::convert_otw_type_to_io_type( - const void *otw_buff, const otw_type_t &otw_type, - void *io_buff, const io_type_t &io_type, - size_t num_samps + const void *otw_buff, + const otw_type_t &otw_type, + std::vector &io_buffs, + const io_type_t &io_type, + size_t nsamps_per_io_buff ){ - switch(get_pred(io_type, otw_type)){ + switch(get_pred(io_type, otw_type, io_buffs.size())){ #for $pred in range(2**$ph.nbits) case $pred: #set $out_type = $ph.get_host_type($pred) #set $in_type = $ph.get_dev_type($pred) - #set $converter = '_'.join([$in_type, 'to', $out_type, $ph.get_swap_type($pred)]) - $(converter)((const $(in_type)_t *)otw_buff, ($(out_type)_t *)io_buff, num_samps); + #set $num_chans = $ph.get_num_chans($pred) + #set $converter = '_'.join([$in_type, 'to', $out_type]) + #if $num_chans == 1 + $(converter)_$ph.get_swap_type($pred)( + reinterpret_cast(otw_buff), + reinterpret_cast<$(out_type)_t *>(io_buffs.front()), + nsamps_per_io_buff + ); + #else + for (size_t i = 0; i < nsamps_per_io_buff; i++){ + #for $j in range($num_chans) + reinterpret_cast<$(out_type)_t *>(io_buffs[$j])[i] = + #if $ph.get_swap_type($pred) == 'bswap' + $(converter)(uhd::byteswap(reinterpret_cast(otw_buff)[i*$num_chans + $j])); + #else + $(converter)(reinterpret_cast(otw_buff)[i*$num_chans + $j]); + #end if + #end for + } + #end if break; #end for } @@ -118,27 +167,43 @@ class ph: item32_p = 0b00000 sc16_p = 0b00010 fc32_p = 0b00000 + chan1_p = 0b00000 + chan2_p = 0b00100 + chan3_p = 0b01000 + chan4_p = 0b01100 - nbits = 2 #see above + nbits = 4 #see above @staticmethod - def has(pred, flag): return (pred & flag) == flag + def has(pred, mask, flag): return (pred & mask) == flag @staticmethod def get_swap_type(pred): - if ph.has(pred, ph.bswap_p): return 'bswap' - if ph.has(pred, ph.nswap_p): return 'nswap' + mask = 0b1 + if ph.has(pred, mask, ph.bswap_p): return 'bswap' + if ph.has(pred, mask, ph.nswap_p): return 'nswap' raise NotImplementedError @staticmethod def get_dev_type(pred): - if ph.has(pred, ph.item32_p): return 'item32' + mask = 0b0 + if ph.has(pred, mask, ph.item32_p): return 'item32' raise NotImplementedError @staticmethod def get_host_type(pred): - if ph.has(pred, ph.sc16_p): return 'sc16' - if ph.has(pred, ph.fc32_p): return 'fc32' + mask = 0b10 + if ph.has(pred, mask, ph.sc16_p): return 'sc16' + if ph.has(pred, mask, ph.fc32_p): return 'fc32' + raise NotImplementedError + + @staticmethod + def get_num_chans(pred): + mask = 0b1100 + if ph.has(pred, mask, ph.chan1_p): return 1 + if ph.has(pred, mask, ph.chan2_p): return 2 + if ph.has(pred, mask, ph.chan3_p): return 3 + if ph.has(pred, mask, ph.chan4_p): return 4 raise NotImplementedError if __name__ == '__main__': -- cgit v1.2.3 From f5c62a46cbc44e254c0214b463d51f06675c17ab Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 30 Aug 2010 16:54:18 -0700 Subject: usrp1: subdev spec tweaks and docs --- host/docs/usrp1.rst | 35 +++++++++++++++++++++++++++++++++++ host/include/uhd/usrp/subdev_spec.hpp | 9 --------- host/lib/usrp/misc_utils.cpp | 13 +++++++++++-- 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/host/docs/usrp1.rst b/host/docs/usrp1.rst index ebc33cbfa..c960b928b 100644 --- a/host/docs/usrp1.rst +++ b/host/docs/usrp1.rst @@ -21,6 +21,41 @@ Change the USRP1's serial number ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TODO +------------------------------------------------------------------------ +Specifying the subdevice to use +------------------------------------------------------------------------ +The USRP1 has multiple daughterboard slots, known as slot A and slot B. +The subdevice specification can be used to select +the daughterboard and subdevice for each channel. +For daughterboards with one one subdevice, +the subdevice name may be left blank for automatic selection. + +Ex: The subdev spec markup string to select a WBX on slot B. +Notice the use of the blank subdevice name for automatic selection. + +:: + + B: + + -- OR -- + + B:0 + +Ex: The subdev spec markup string to select a BasicRX on slot B. +Notice that the subdevice name is always specified in the 3 possible cases. + +:: + + B:AB + + -- OR -- + + B:A + + -- OR -- + + B:B + ------------------------------------------------------------------------ OS Specific Notes ------------------------------------------------------------------------ diff --git a/host/include/uhd/usrp/subdev_spec.hpp b/host/include/uhd/usrp/subdev_spec.hpp index 56aa0df20..2f32509b9 100644 --- a/host/include/uhd/usrp/subdev_spec.hpp +++ b/host/include/uhd/usrp/subdev_spec.hpp @@ -56,17 +56,8 @@ namespace uhd{ namespace usrp{ * * The subdevice specification can be represented as a markup-string. * The markup-string is a whitespace separated list of dboard:subdev pairs. - * The "dboard:" part is optional on boards with only one daughterboard slot. * The first pair represents the subdevice for channel zero, * the second pair represents the subdevice for channel one, and so on. - * - * Examples: - * - Use subdevice AB on daughterboard A (USRP1): "A:AB" - * - Use subdevice A on daughterboard A for channel zero and subdevice A on daughterboard B for channel one (USRP1): "A:A B:A" - * - Use subdevice AB (USRP2): "AB" or ":AB" - * - * An empty subdevice specification can be used to automatically - * select the first subdevice on the first present daughterboard. */ class UHD_API subdev_spec_t : public std::vector{ public: diff --git a/host/lib/usrp/misc_utils.cpp b/host/lib/usrp/misc_utils.cpp index a1664d810..5cfcdc8d3 100644 --- a/host/lib/usrp/misc_utils.cpp +++ b/host/lib/usrp/misc_utils.cpp @@ -164,13 +164,22 @@ static void verify_xx_subdev_spec( //empty db name means select dboard automatically if (pair.db_name.empty()){ if (dboard_names.size() != 1) throw std::runtime_error( - "A daughterboard name must be provided for multi-slot boards: " + subdev_spec.to_string() + "A daughterboard name must be provided for multi-slot motherboards: " + subdev_spec.to_string() ); pair.db_name == dboard_names.front(); } uhd::assert_has(dboard_names, pair.db_name, xx_type + " dboard name"); wax::obj dboard = mboard[named_prop_t(dboard_prop, pair.db_name)]; - uhd::assert_has(dboard[DBOARD_PROP_SUBDEV_NAMES].as(), pair.sd_name, xx_type + " subdev name"); + prop_names_t subdev_names = dboard[DBOARD_PROP_SUBDEV_NAMES].as(); + + //empty sd name means select the subdev automatically + if (pair.sd_name.empty()){ + if (subdev_names.size() != 1) throw std::runtime_error( + "A subdevice name must be provided for multi-subdev daughterboards: " + subdev_spec.to_string() + ); + pair.sd_name == subdev_names.front(); + } + uhd::assert_has(subdev_names, pair.sd_name, xx_type + " subdev name"); } }catch(const std::exception &e){ throw std::runtime_error(str(boost::format( -- cgit v1.2.3 From af0543a8b72e924c26503d838976e249d8ca6fbb Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 30 Aug 2010 18:42:45 -0700 Subject: usrp1: work on gpio clock divider for dbsrx, still not locking --- host/docs/build.rst | 8 ++++++++ host/lib/usrp/dboard/db_dbsrx.cpp | 7 ++++++- host/lib/usrp/usrp1/dboard_iface.cpp | 12 ++++++------ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/host/docs/build.rst b/host/docs/build.rst index 8f0d0db59..d7dfd05e5 100644 --- a/host/docs/build.rst +++ b/host/docs/build.rst @@ -52,6 +52,14 @@ Boost * **Download URL:** http://www.boost.org/users/download/ * **Download URL (windows installer):** http://www.boostpro.com/download +^^^^^^^^^^^^^^^^ +LibUSB +^^^^^^^^^^^^^^^^ +* **Purpose:** USB userspace library +* **Version:** at least 1.0 +* **Required for:** build time + run time (optional) +* **Download URL:** http://www.libusb.org/ + ^^^^^^^^^^^^^^^^ Python ^^^^^^^^^^^^^^^^ diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp index 06cf91d3b..81434f054 100644 --- a/host/lib/usrp/dboard/db_dbsrx.cpp +++ b/host/lib/usrp/dboard/db_dbsrx.cpp @@ -205,7 +205,12 @@ dbsrx::dbsrx(ctor_args_t args) : rx_dboard_base(args){ //set the gpio directions and atr controls (identically) this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, 0x0); // All unused in atr - this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x0); // All Inputs + if (this->get_iface()->get_special_props().soft_clock_divider){ + this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x1); // GPIO0 is clock + } + else{ + this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x0); // All Inputs + } //send initial register settings this->send_reg(0x0, 0x5); diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp index b2221e221..454de3ece 100644 --- a/host/lib/usrp/usrp1/dboard_iface.cpp +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -49,8 +49,8 @@ public: _codec = codec; //init the clock rate shadows - this->set_clock_rate(UNIT_RX, _clock->get_master_clock_freq()); - this->set_clock_rate(UNIT_TX, _clock->get_master_clock_freq()); + this->set_clock_rate(UNIT_RX, this->get_clock_rates(UNIT_RX).front()); + this->set_clock_rate(UNIT_TX, this->get_clock_rates(UNIT_TX).front()); } ~usrp1_dboard_iface() @@ -134,14 +134,14 @@ void usrp1_dboard_iface::set_clock_rate(unit_t unit, double rate) _clock_rates[unit] = rate; if (unit == UNIT_RX && _rx_dboard_id == dbsrx_classic_id){ - size_t divider = size_t(rate/_clock->get_master_clock_freq()); + size_t divider = size_t(_clock->get_master_clock_freq()/rate); switch(_dboard_slot){ case usrp1_impl::DBOARD_SLOT_A: - _iface->poke32(FR_RX_A_REFCLK, (divider & 0x7f) | 0x80); + _iface->poke32(FR_RX_A_REFCLK, (2*divider & 0x7f) | 0x80); break; case usrp1_impl::DBOARD_SLOT_B: - _iface->poke32(FR_RX_B_REFCLK, (divider & 0x7f) | 0x80); + _iface->poke32(FR_RX_B_REFCLK, (2*divider & 0x7f) | 0x80); break; } } @@ -151,7 +151,7 @@ std::vector usrp1_dboard_iface::get_clock_rates(unit_t unit) { std::vector rates; if (unit == UNIT_RX && _rx_dboard_id == dbsrx_classic_id){ - for (size_t div = 1; div <= 127; div++) + for (size_t div = 8; div <= 127; div++) rates.push_back(_clock->get_master_clock_freq() / div); } else{ -- cgit v1.2.3 From 954be82738b9237e77162566d39e2daed8105a2a Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 30 Aug 2010 19:02:56 -0700 Subject: usrp1: init the subdev specs so they will be non-empty --- host/lib/usrp/usrp1/usrp1_impl.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 3c3306525..ccb41a09d 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -21,6 +21,7 @@ #include "usrp_spi_defs.h" #include #include +#include #include #include #include @@ -171,6 +172,10 @@ usrp1_impl::usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport, //turn on the transmitter _ctrl_transport->usrp_tx_enable(true); + + //init the subdev specs + this->mboard_set(MBOARD_PROP_RX_SUBDEV_SPEC, subdev_spec_t()); + this->mboard_set(MBOARD_PROP_TX_SUBDEV_SPEC, subdev_spec_t()); } usrp1_impl::~usrp1_impl(void){ -- cgit v1.2.3 From 11c83c60100a52d309e21684731908a199353919 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 31 Aug 2010 12:11:43 -0700 Subject: usrp2: flush the error flow messages, issue the stop before register configure to align count --- host/lib/usrp/usrp2/io_impl.cpp | 4 ++-- host/lib/usrp/usrp2/mboard_impl.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 9e29edd82..4e883cf81 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -113,7 +113,7 @@ void usrp2_impl::io_impl::recv_pirate_loop( metadata.event_code = vrt_packet_handler::get_context_code(vrt_hdr, if_packet_info); //print the famous U, and push the metadata into the message queue - if (metadata.event_code & underflow_flags) std::cerr << "U"; + if (metadata.event_code & underflow_flags) std::cerr << "U" << std::flush; async_msg_fifo->push_with_pop_on_full(metadata); continue; } @@ -121,7 +121,7 @@ void usrp2_impl::io_impl::recv_pirate_loop( //handle the packet count / sequence number if (if_packet_info.packet_count != next_packet_seq){ //std::cerr << "S" << (if_packet_info.packet_count - next_packet_seq)%16; - std::cerr << "O"; //report overflow (drops in the kernel) + std::cerr << "O" << std::flush; //report overflow (drops in the kernel) } next_packet_seq = (if_packet_info.packet_count+1)%16; diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index d5785f326..0b9f8ee83 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -69,6 +69,11 @@ usrp2_mboard_impl::usrp2_mboard_impl( _allowed_decim_and_interp_rates.push_back(i); } + //Issue a stop streaming command (in case it was left running). + //Since this command is issued before the networking is setup, + //most if not all junk packets will never make it to the socket. + this->issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); + //init the rx control registers _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _io_helper.get_max_recv_samps_per_packet()); _iface->poke32(U2_REG_RX_CTRL_NCHANNELS, 1); @@ -107,11 +112,6 @@ usrp2_mboard_impl::usrp2_mboard_impl( //set default subdev specs (*this)[MBOARD_PROP_RX_SUBDEV_SPEC] = subdev_spec_t(); (*this)[MBOARD_PROP_TX_SUBDEV_SPEC] = subdev_spec_t(); - - //Issue a stop streaming command (in case it was left running). - //Since this command is issued before the networking is setup, - //most if not all junk packets will never make it to the socket. - this->issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); } usrp2_mboard_impl::~usrp2_mboard_impl(void){ -- cgit v1.2.3 From 02e339cc501eebd38f72b0f172551930106b8634 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 31 Aug 2010 12:17:48 -0700 Subject: uhd: sine table for tx waveforms --- host/examples/tx_waveforms.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/host/examples/tx_waveforms.cpp b/host/examples/tx_waveforms.cpp index 9886000b1..3f319cf68 100644 --- a/host/examples/tx_waveforms.cpp +++ b/host/examples/tx_waveforms.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include //system time @@ -44,9 +45,16 @@ float gen_ramp(float x){ return std::fmod(x, 1)*2 - 1; } +#define sine_table_len 2048 +static float sine_table[sine_table_len]; +UHD_STATIC_BLOCK(gen_sine_table){ + static const float m_pi = std::acos(float(-1)); + for (size_t i = 0; i < sine_table_len; i++) + sine_table[i] = std::sin((2*m_pi*i)/sine_table_len); +} + float gen_sine(float x){ - static const float two_pi = 2*std::acos(float(-1)); - return std::sin(x*two_pi); + return sine_table[size_t(x*sine_table_len)%sine_table_len]; } int UHD_SAFE_MAIN(int argc, char *argv[]){ @@ -65,11 +73,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ ("args", po::value(&args)->default_value(""), "simple uhd device address args") ("duration", po::value(&total_duration)->default_value(3), "number of seconds to transmit") ("spb", po::value(&spb)->default_value(10000), "samples per buffer") - ("rate", po::value(&rate)->default_value(100e6/16), "rate of outgoing samples") + ("rate", po::value(&rate)->default_value(1.5e6), "rate of outgoing samples") ("freq", po::value(&freq)->default_value(0), "rf center frequency in Hz") ("ampl", po::value(&l)->default_value(float(0.3)), "amplitude of the waveform") ("gain", po::value(&gain)->default_value(float(0)), "gain for the RF chain") - ("wave-type", po::value(&wave_type)->default_value("SINE"), "waveform type (CONST, SQUARE, RAMP, SINE)") + ("wave-type", po::value(&wave_type)->default_value("CONST"), "waveform type (CONST, SQUARE, RAMP, SINE)") ("wave-freq", po::value(&wave_freq)->default_value(0), "waveform frequency in Hz") ; po::variables_map vm; @@ -113,6 +121,9 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ if (std::abs(wave_freq) > sdev->get_tx_rate()/2){ throw std::runtime_error("wave freq out of Nyquist zone"); } + if (sdev->get_tx_rate()/std::abs(wave_freq) > sine_table_len/2 and wave_type == "SINE"){ + throw std::runtime_error("sine freq too small for table"); + } //store the generator function for the selected waveform boost::function wave_gen; -- cgit v1.2.3 From c9cd9b605897078daed77c8b7f9c538cb77bd4bc Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 31 Aug 2010 12:19:17 -0700 Subject: usrp1: flush for flow error messages --- host/lib/usrp/usrp1/io_impl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 920c47b30..92e8bc20a 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -189,7 +189,7 @@ bool usrp1_impl::io_impl::check_underrun(usrp_ctrl::sptr ctrl_if, if (ret < 0) std::cerr << "USRP: underrun check failed" << std::endl; if (underrun) - std::cerr << "Uu"; + std::cerr << "U" << std::flush; send_state.underrun_poll_samp_count = 0; } @@ -289,7 +289,7 @@ bool usrp1_impl::io_impl::check_overrun(usrp_ctrl::sptr ctrl_if, if (ret < 0) std::cerr << "USRP: overrrun check failed" << std::endl; if (overrun) - std::cerr << "Oo"; + std::cerr << "O" << std::flush; recv_state.overrun_poll_samp_count = 0; } -- cgit v1.2.3 From 80fe3189afd52d1aab95ee95e71d5d50bddbba55 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 31 Aug 2010 13:08:50 -0700 Subject: usrp1: Fedora sdcc note and change fw error to warning (find should not error) --- host/lib/usrp/usrp1/usrp1_impl.cpp | 17 ++++++++++++++--- images/README | 5 +++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index ccb41a09d..9f824045d 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -50,9 +51,19 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) if (hint.has_key("type") and hint["type"] != "usrp1") return usrp1_addrs; //extract the firmware path for the USRP1 - std::string usrp1_fw_image = find_image_path( - hint.has_key("fw")? hint["fw"] : "usrp1_fw.ihx" - ); + std::string usrp1_fw_image; + try{ + usrp1_fw_image = find_image_path( + hint.has_key("fw")? hint["fw"] : "usrp1_fw.ihx" + ); + } + catch(const std::exception &e){ + uhd::print_warning( + "Could not locate USRP1 firmware.\n" + "Please install the images package.\n" + ); + return usrp1_addrs; + } std::cout << "USRP1 firmware image: " << usrp1_fw_image << std::endl; //see what we got on the USB bus diff --git a/images/README b/images/README index ec8391826..2f9c6a95e 100644 --- a/images/README +++ b/images/README @@ -18,3 +18,8 @@ To build the package (unix): The package generator types are described here: http://www.cmake.org/Wiki/CMake:CPackPackageGenerators + +Fedora note: + The sdcc binaries are prefixed with "sdcc-" which breaks the build. + However, /usr/libexec/sdcc contains properly named sdcc binaries. + export PATH=${PATH}:/usr/libexec/sdcc -- cgit v1.2.3 From 9a3217cbbeb39d677a439fe0982a7ac4d7f251c2 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 31 Aug 2010 13:21:32 -0700 Subject: usrp1: tested dbsrx, works with lower divider --- host/lib/usrp/usrp1/dboard_iface.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp index 454de3ece..4791b55ce 100644 --- a/host/lib/usrp/usrp1/dboard_iface.cpp +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -137,11 +137,11 @@ void usrp1_dboard_iface::set_clock_rate(unit_t unit, double rate) size_t divider = size_t(_clock->get_master_clock_freq()/rate); switch(_dboard_slot){ case usrp1_impl::DBOARD_SLOT_A: - _iface->poke32(FR_RX_A_REFCLK, (2*divider & 0x7f) | 0x80); + _iface->poke32(FR_RX_A_REFCLK, (divider & 0x7f) | 0x80); break; case usrp1_impl::DBOARD_SLOT_B: - _iface->poke32(FR_RX_B_REFCLK, (2*divider & 0x7f) | 0x80); + _iface->poke32(FR_RX_B_REFCLK, (divider & 0x7f) | 0x80); break; } } @@ -151,7 +151,7 @@ std::vector usrp1_dboard_iface::get_clock_rates(unit_t unit) { std::vector rates; if (unit == UNIT_RX && _rx_dboard_id == dbsrx_classic_id){ - for (size_t div = 8; div <= 127; div++) + for (size_t div = 1; div <= 127; div++) rates.push_back(_clock->get_master_clock_freq() / div); } else{ -- cgit v1.2.3 From b96088b692a5c44974919ee36e253b6ea8c51972 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 31 Aug 2010 16:44:30 -0700 Subject: EEPROM burning in UHD. Changed some USB device handle stuff. Added usrp_init_eeprom.cpp. Hacked up the firmware makefile to behave and to generate .bin EEPROM images instead of IHX. --- firmware/fx2/src/common/build_eeprom.py | 103 +++-------------------- firmware/fx2/src/usrp1/Makefile.am | 58 +++---------- host/include/uhd/transport/usb_device_handle.hpp | 4 +- host/lib/transport/libusb1_base.cpp | 52 ++---------- host/lib/transport/libusb1_base.hpp | 10 --- host/lib/transport/libusb1_device_handle.cpp | 18 ++-- host/lib/usrp/usrp1/mboard_impl.cpp | 11 +++ host/lib/usrp/usrp1/usrp1_ctrl.cpp | 63 +++++++++++++- host/lib/usrp/usrp1/usrp1_ctrl.hpp | 31 +++++++ host/lib/usrp/usrp1/usrp1_iface.cpp | 21 +++-- host/lib/usrp/usrp1/usrp1_impl.cpp | 34 ++++---- host/utils/CMakeLists.txt | 4 + host/utils/usrp_init_eeprom.cpp | 69 +++++++++++++++ 13 files changed, 255 insertions(+), 223 deletions(-) create mode 100644 host/utils/usrp_init_eeprom.cpp diff --git a/firmware/fx2/src/common/build_eeprom.py b/firmware/fx2/src/common/build_eeprom.py index 023c4b3f5..ae62587db 100755 --- a/firmware/fx2/src/common/build_eeprom.py +++ b/firmware/fx2/src/common/build_eeprom.py @@ -29,15 +29,6 @@ from optparse import OptionParser VID = 0xfffe # Free Software Folks PID = 0x0002 # Universal Software Radio Peripheral - - -def hex_to_bytes (s): - if len (s) & 0x1: - raise ValueError, "Length must be even" - r = [] - for i in range (0, len(s), 2): - r.append (int (s[i:i+2], 16)) - return r def msb (x): return (x >> 8) & 0xff @@ -45,56 +36,6 @@ def msb (x): def lsb (x): return x & 0xff -class ihx_rec (object): - def __init__ (self, addr, type, data): - self.addr = addr - self.type = type - self.data = data - -class ihx_file (object): - def __init__ (self): - self.pat = re.compile (r':[0-9A-F]{10,}') - def read (self, file): - r = [] - for line in file: - line = line.strip().upper () - if not self.pat.match (line): - raise ValueError, "Invalid hex record format" - bytes = hex_to_bytes (line[1:]) - sum = reduce (lambda x, y: x + y, bytes, 0) % 256 - if sum != 0: - raise ValueError, "Bad hex checksum" - lenx = bytes[0] - addr = (bytes[1] << 8) + bytes[2] - type = bytes[3] - data = bytes[4:-1] - if lenx != len (data): - raise ValueError, "Invalid hex record (bad length)" - if type != 0: - break; - r.append (ihx_rec (addr, type, data)) - - return r - -def get_code (filename): - """Read the intel hex format file FILENAME and return a tuple - of the code starting address and a list of bytes to load there. - """ - f = open (filename, 'r') - ifx = ihx_file () - r = ifx.read (f) - r.sort (lambda a,b: a.addr - b.addr) - code_start = r[0].addr - code_end = r[-1].addr + len (r[-1].data) - code_len = code_end - code_start - code = [0] * code_len - for x in r: - a = x.addr - l = len (x.data) - code[a-code_start:a-code_start+l] = x.data - return (code_start, code) - - def build_eeprom_image (filename, rev): """Build a ``C2 Load'' EEPROM image. @@ -102,9 +43,11 @@ def build_eeprom_image (filename, rev): the EZ-USB FX2 Technical Reference Manual """ # get the code we want to run - (start_addr, bytes) = get_code (filename) + f = open(filename, 'rb') + bytes = f.read() devid = rev + start_addr = 0 #prove me wrong rom_header = [ 0xC2, # boot from EEPROM @@ -135,41 +78,18 @@ def build_eeprom_image (filename, rev): 0x00 ] - image = rom_header + code_header + bytes + trailer + image = rom_header + code_header + [ord(c) for c in bytes] + trailer assert (len (image) <= 256) - return image - -def build_shell_script (out, ihx_filename, rev): - - image = build_eeprom_image (ihx_filename, rev) - - out.write ('#!/bin/sh\n') - out.write ('usrper -x load_firmware /usr/local/share/usrp/rev%d/std.ihx\n' % rev) - out.write ('sleep 1\n') - - # print "len(image) =", len(image) - - i2c_addr = 0x50 - rom_addr = 0x00 - - hex_image = map (lambda x : "%02x" % (x,), image) - - while (len (hex_image) > 0): - l = min (len (hex_image), 16) - out.write ('usrper i2c_write 0x%02x %02x%s\n' % - (i2c_addr, rom_addr, ''.join (hex_image[0:l]))) - hex_image = hex_image[l:] - rom_addr = rom_addr + l - out.write ('sleep 1\n') + return image if __name__ == '__main__': - usage = "usage: %prog -r REV [options] bootfile.ihx" + usage = "usage: %prog -r REV [options] bootfile.bin outfile.bin" parser = OptionParser (usage=usage) parser.add_option ("-r", "--rev", type="int", default=-1, help="Specify USRP revision number REV (2 or 4)") (options, args) = parser.parse_args () - if len (args) != 1: + if len (args) != 2: parser.print_help () sys.exit (1) if options.rev < 0: @@ -177,6 +97,11 @@ if __name__ == '__main__': "You must specify the USRP revision number (2 or 4) with -r REV\n") sys.exit (1) - ihx_filename = args[0] + infile = args[0] + outfile = args[1] + + image = "".join(chr(c) for c in build_eeprom_image(infile, options.rev)) - build_shell_script (sys.stdout, ihx_filename, options.rev) + f = open(outfile, 'wb') + f.write(str(image)) + f.close() diff --git a/firmware/fx2/src/usrp1/Makefile.am b/firmware/fx2/src/usrp1/Makefile.am index 5586e83a3..a964f9198 100644 --- a/firmware/fx2/src/usrp1/Makefile.am +++ b/firmware/fx2/src/usrp1/Makefile.am @@ -19,12 +19,12 @@ # Boston, MA 02110-1301, USA. # -firmware2dir = $(prefix)/share/usrp/rev2 -firmware2_DATA = std.ihx +#firmwaredir = $(prefix)/share/uhd/images +#firmware_DATA = usrp1_fw.ihx -# we put the same stuff in the rev4 directory -firmware4dir = $(prefix)/share/usrp/rev4 -firmware4_DATA = std.ihx +#eepromdir = $(firmwaredir) +#eepromfile = eeprom_boot.ihx +#eeprom_DATA = usrp1_eeprom.bin EXTRA_DIST = \ edit-gpif \ @@ -85,11 +85,6 @@ EXECUTABLES = \ STARTUP = _startup.rel -noinst_SCRIPTS = \ - burn-usrp2-eeprom \ - burn-usrp4-eeprom - - .c.rel: $(XCC) $(FW_INCLUDES) $(DEFINES) \ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< @@ -107,34 +102,11 @@ EEPROM_BOOT_OBJS = eeprom_boot.rel eeprom_init.rel $(STARTUP) eeprom_boot.ihx: $(EEPROM_BOOT_OBJS) $(LIBDEP) $(XCC) $(LINKOPTS) -o $@ $(EEPROM_BOOT_OBJS) -burn-usrp2-eeprom: eeprom_boot.ihx - $(PYTHON) $(srcdir)/../common/build_eeprom.py -r2 eeprom_boot.ihx > $@ - chmod +x $@ - -burn-usrp4-eeprom: eeprom_boot.ihx - $(PYTHON) $(srcdir)/../common/build_eeprom.py -r4 eeprom_boot.ihx > $@ - chmod +x $@ - - -BLINK_LEDS_OBJS = blink_leds.rel usrp_common.rel board_specific.rel spi.rel $(STARTUP) - -blink_leds.ihx: $(BLINK_LEDS_OBJS) $(LIBDEP) - $(XCC) $(LINKOPTS) -o $@ $(BLINK_LEDS_OBJS) - - -CHECK_MDELAY_OBJS = check_mdelay.rel usrp_common.rel board_specific.rel spi.rel $(STARTUP) - -check_mdelay.ihx: $(CHECK_MDELAY_OBJS) $(LIBDEP) - $(XCC) $(LINKOPTS) -o $@ $(CHECK_MDELAY_OBJS) - - - -CHECK_UDELAY_OBJS = check_udelay.rel usrp_common.rel board_specific.rel spi.rel $(STARTUP) - -check_udelay.ihx: $(CHECK_UDELAY_OBJS) $(LIBDEP) - $(XCC) $(LINKOPTS) -o $@ $(CHECK_UDELAY_OBJS) - +usrp1_eeprom.bin: eeprom_boot.bin + $(PYTHON) ../common/build_eeprom.py -r4 $< $@ +eeprom_boot.bin: eeprom_boot.ihx + objcopy -I ihex -O binary $< $@ USRP_OBJS = \ vectors.rel \ @@ -146,25 +118,23 @@ std.ihx: $(USRP_OBJS) $(LIBDEP) $(XCC) $(LINKOPTS) -o $@ $(USRP_OBJS) CLEANFILES = \ - *.ihx *.lnk *.lst *.map *.mem *.rel *.rst *.sym *.asm *.lib \ - usrp_gpif.c usrp_gpif_inline.h \ - burn-usrp2-eeprom \ - burn-usrp4-eeprom + *.ihx *.lnk *.lst *.map *.mem *.rel *.rst *.sym *.asm *.lib *.bin \ + usrp_gpif.c usrp_gpif_inline.h DISTCLEANFILES = \ - *.ihx *.lnk *.lst *.map *.mem *.rel *.rst *.sym *.asm *.lib + *.ihx *.lnk *.lst *.map *.mem *.rel *.rst *.sym *.asm *.lib *.bin # build gpif stuff -all: usrp_gpif.c +all: usrp_gpif.c std.ihx usrp1_eeprom.bin usrp_gpif.c usrp_gpif_inline.h : gpif.c srcdir=$(srcdir) $(PYTHON) $(srcdir)/edit-gpif $(srcdir)/gpif.c usrp_gpif.c usrp_gpif_inline.h - # dependencies usrp_main.rel: usrp_gpif_inline.h + #usrp_main.rel: fpga.h usrp_common.h ../../include/usrp_commands.h usrp_gpif_inline.h ../../include/usrp_config.h usrp_rev2_regs.h ../../include/fx2regs.h #usrp_common.rel: usrp_common.h ../../include/usrp_commands.h ../../include/usrp_config.h usrp_rev2_regs.h ../../include/fx2regs.h #fpga.rel: usrp_common.h ../../include/usrp_commands.h fpga.h ../../include/usrp_config.h usrp_rev2_regs.h ../../include/fx2regs.h diff --git a/host/include/uhd/transport/usb_device_handle.hpp b/host/include/uhd/transport/usb_device_handle.hpp index 78c78f6b5..c3eb72b00 100644 --- a/host/include/uhd/transport/usb_device_handle.hpp +++ b/host/include/uhd/transport/usb_device_handle.hpp @@ -68,9 +68,9 @@ public: /*! * Return a vector of USB devices on this host - * \return a vector of USB device handles + * \return a vector of USB device handles that match vid and pid */ - static UHD_API std::vector get_device_list(); + static UHD_API std::vector get_device_list(boost::uint16_t vid, boost::uint16_t pid); }; //namespace usb diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index 92dcd969f..e21c39aa3 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -24,22 +24,6 @@ using namespace uhd::transport; /********************************************************** * Helper Methods **********************************************************/ -/* - * Check for FSF device - * Compare the device's descriptor Vendor ID - * \param dev pointer to libusb_device - * \return true if Vendor ID matches 0xfffe - */ -bool check_fsf_device(libusb_device *dev) -{ - libusb_device_descriptor desc; - - if (libusb_get_device_descriptor(dev, &desc) < 0) { - UHD_ASSERT_THROW("USB: failed to get device descriptor"); - } - - return desc.idVendor == 0xfffe; -} /********************************************************** * libusb namespace @@ -52,37 +36,16 @@ void libusb::init(libusb_context **ctx, int debug_level) libusb_set_debug(*ctx, debug_level); } -std::vector libusb::get_fsf_device_list(libusb_context *ctx) -{ - libusb_device **libusb_dev_list; - std::vector fsf_dev_list; - - ssize_t dev_cnt = libusb_get_device_list(ctx, &libusb_dev_list); - - //find the FSF devices - for (ssize_t i = 0; i < dev_cnt; i++) { - libusb_device *dev = libusb_dev_list[i]; - - if (check_fsf_device(dev)) - fsf_dev_list.push_back(dev); - else - libusb_unref_device(dev); - } - - libusb_free_device_list(libusb_dev_list, 0); - - return fsf_dev_list; -} - libusb_device_handle *libusb::open_device(libusb_context *ctx, usb_device_handle::sptr handle) { libusb_device_handle *dev_handle = NULL; - std::vector fsf_dev_list = get_fsf_device_list(ctx); + libusb_device **libusb_dev_list; + size_t dev_cnt = libusb_get_device_list(ctx, &libusb_dev_list); //find and open the USB device - for (size_t i = 0; i < fsf_dev_list.size(); i++) { - libusb_device *dev = fsf_dev_list[i]; + for (size_t i = 0; i < dev_cnt; i++) { + libusb_device *dev = libusb_dev_list[i]; if (compare_device(dev, handle)) { libusb_open(dev, &dev_handle); @@ -96,7 +59,8 @@ libusb_device_handle *libusb::open_device(libusb_context *ctx, return dev_handle; } - +//note: changed order of checks so it only tries to get_serial and get_device_address if vid and pid match +//doing this so it doesn't try to open the device if it's not ours bool libusb::compare_device(libusb_device *dev, usb_device_handle::sptr handle) { @@ -108,12 +72,12 @@ bool libusb::compare_device(libusb_device *dev, libusb_device_descriptor libusb_desc; if (libusb_get_device_descriptor(dev, &libusb_desc) < 0) return false; - if (serial != get_serial(dev)) - return false; if (vendor_id != libusb_desc.idVendor) return false; if (product_id != libusb_desc.idProduct) return false; + if (serial != get_serial(dev)) + return false; if (device_addr != libusb_get_device_address(dev)) return false; diff --git a/host/lib/transport/libusb1_base.hpp b/host/lib/transport/libusb1_base.hpp index 442f89ded..abe5e22a2 100644 --- a/host/lib/transport/libusb1_base.hpp +++ b/host/lib/transport/libusb1_base.hpp @@ -41,16 +41,6 @@ namespace libusb { */ void init(libusb_context **ctx, int debug_level); - /* - * Get a list of Free Software Foundation devices (Vendor ID 0xfffe) - * As opposed to the public USB device handle interface, which returns - * generic identifiers, this call returns device pointers speficic - * to libusb. - * \param ctx the libusb context used for init - * \return a vector of libusb devices - */ - std::vector get_fsf_device_list(libusb_context *ctx); - /* * Open the device specified by a generic handle * Find the libusb_device cooresponding to the generic handle diff --git a/host/lib/transport/libusb1_device_handle.cpp b/host/lib/transport/libusb1_device_handle.cpp index 5d9d8faf0..43d0f0e26 100644 --- a/host/lib/transport/libusb1_device_handle.cpp +++ b/host/lib/transport/libusb1_device_handle.cpp @@ -17,6 +17,7 @@ #include "libusb1_base.hpp" #include +#include using namespace uhd::transport; @@ -91,19 +92,24 @@ usb_device_handle::sptr make_usb_device_handle(libusb_device *dev) device_addr)); } -std::vector usb_device_handle::get_device_list() +std::vector usb_device_handle::get_device_list(boost::uint16_t vid, boost::uint16_t pid) { libusb_context *ctx = NULL; - std::vector libusb_device_list; + libusb_device** libusb_device_list; std::vector device_handle_list; + libusb_device_descriptor desc; libusb::init(&ctx, libusb_debug_level); - libusb_device_list = libusb::get_fsf_device_list(ctx); - - for (size_t i = 0; i < libusb_device_list.size(); i++) { + size_t dev_size = libusb_get_device_list(ctx, &libusb_device_list); + for (size_t i = 0; i < dev_size; i++) { libusb_device *dev = libusb_device_list[i]; - device_handle_list.push_back(make_usb_device_handle(dev)); + if(libusb_get_device_descriptor(dev, &desc) < 0) { + UHD_ASSERT_THROW("USB: failed to get device descriptor"); + } + if(desc.idVendor == vid && desc.idProduct == pid) { + device_handle_list.push_back(make_usb_device_handle(dev)); + } } libusb_exit(ctx); diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index 75129c32f..1409855cb 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -318,6 +319,16 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) **********************************************************************/ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val) { + if(key.type() == typeid(std::string)) { + if(key.as() == "load_eeprom") { + std::string usrp1_fpga_image = val.as(); + std::cout << "USRP1 EEPROM image: " << usrp1_fpga_image << std::endl; + _ctrl_transport->usrp_load_eeprom(val.as()); + } + + return; + } + //handle the get request conditioned on the key switch(key.as()){ diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp index 98226b738..451129ef5 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp @@ -25,6 +25,7 @@ #include #include #include +#include using namespace uhd; @@ -203,7 +204,7 @@ public: return -1; } } - //type 0x00 is end + //type 0x01 is end else if (type == 0x01) { usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_n, 1); @@ -283,6 +284,55 @@ public: return 0; } + int usrp_load_eeprom(std::string filestring) + { + const char *filename = filestring.c_str(); + const uint16_t i2c_addr = 0x50; + + //FIXME: verify types + int len; + unsigned int addr; + unsigned char data[256]; + unsigned char sendbuf[17]; + + int ret; + std::ifstream file; + file.open(filename, std::ifstream::in); + + if (!file.good()) { + std::cerr << "cannot open EEPROM input file" << std::endl; + return -1; + } + + file.read((char *)data, 256); + len = file.gcount(); + + if(len == 256) { + std::cerr << "error: image size too large" << std::endl; + file.close(); + return -1; + } + + const int pagesize = 16; + addr = 0; + while(len > 0) { + sendbuf[0] = addr; + memcpy(sendbuf+1, &data[addr], len > pagesize ? pagesize : len); + ret = usrp_i2c_write(i2c_addr, sendbuf, (len > pagesize ? pagesize : len)+1); + if (ret < 0) { + std::cerr << "error: usrp_i2c_write failed: "; + std::cerr << ret << std::endl; + file.close(); + return -1; + } + addr += pagesize; + len -= pagesize; + boost::this_thread::sleep(boost::posix_time::milliseconds(100)); + } + file.close(); + return 0; + } + int usrp_set_led(int led_num, bool on) { @@ -371,6 +421,17 @@ public: return usrp_control_write(request, value, index, 0, 0); } + int usrp_i2c_write(boost::uint16_t i2c_addr, unsigned char *buf, boost::uint16_t len) + { + return usrp_control_write(VRQ_I2C_WRITE, i2c_addr, 0, buf, len); + } + + int usrp_i2c_read(boost::uint16_t i2c_addr, unsigned char *buf, boost::uint16_t len) + { + return usrp_control_read(VRQ_I2C_READ, i2c_addr, 0, buf, len); + } + + private: uhd::transport::usb_control::sptr _ctrl_transport; diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.hpp b/host/lib/usrp/usrp1/usrp1_ctrl.hpp index deedec4e8..a02d9f96c 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.hpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.hpp @@ -49,6 +49,13 @@ public: */ virtual int usrp_load_fpga(std::string filename) = 0; + /*! + * Load USB descriptor file in Intel HEX format into EEPROM + * \param filename name of EEPROM image + * \return 0 on success, error code otherwise + */ + virtual int usrp_load_eeprom(std::string filestring) = 0; + /*! * Set led usrp * \param led_num which LED to control (0 or 1) @@ -127,6 +134,30 @@ public: unsigned char *buff, boost::uint16_t length) = 0; + /*! + * Perform an I2C write + * \param i2c_addr I2C device address + * \param buf data to be written + * \param len length of data in bytes + * \return number of bytes written or error + */ + + virtual int usrp_i2c_write(boost::uint16_t i2c_addr, + unsigned char *buf, + boost::uint16_t len) = 0; + + /*! + * Perform an I2C read + * \param i2c_addr I2C device address + * \param buf data to be read + * \param len length of data in bytes + * \return number of bytes read or error + */ + + virtual int usrp_i2c_read(boost::uint16_t i2c_addr, + unsigned char *buf, + boost::uint16_t len) = 0; + }; #endif /* INCLUDED_USRP_CTRL_HPP */ diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp index 8756a21c9..4bc18dd16 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.cpp +++ b/host/lib/usrp/usrp1/usrp1_iface.cpp @@ -109,18 +109,19 @@ public: ******************************************************************/ static const size_t max_i2c_data_bytes = 64; + //TODO: make this handle EEPROM page sizes. right now you can't write over a 16-byte boundary. + //to accomplish this you'll have to have addr offset as a separate parameter. + void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes) { UHD_ASSERT_THROW(bytes.size() < max_i2c_data_bytes); unsigned char buff[max_i2c_data_bytes]; - std::copy(bytes.begin(), bytes.end(), buff); + std::copy(bytes.begin(), bytes.end(), buff); - int ret = _ctrl_transport->usrp_control_write(VRQ_I2C_WRITE, - addr & 0xff, - 0, - buff, - bytes.size()); + int ret = _ctrl_transport->usrp_i2c_write(addr & 0xff, + buff, + bytes.size()); // TODO throw and catch i2c failures during eeprom read if (iface_debug && (ret < 0)) @@ -132,11 +133,9 @@ public: UHD_ASSERT_THROW(num_bytes < max_i2c_data_bytes); unsigned char buff[max_i2c_data_bytes]; - int ret = _ctrl_transport->usrp_control_read(VRQ_I2C_READ, - addr & 0xff, - 0, - buff, - num_bytes); + int ret = _ctrl_transport->usrp_i2c_read(addr & 0xff, + buff, + num_bytes); // TODO throw and catch i2c failures during eeprom read if (iface_debug && ((ret < 0) || (unsigned)ret < (num_bytes))) { diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 3c3306525..8ad148274 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -34,6 +34,11 @@ using namespace uhd; using namespace uhd::usrp; using namespace uhd::transport; +const boost::uint16_t USRP1_VENDOR_ID = 0xfffe; +const boost::uint16_t USRP1_PRODUCT_ID = 0x0002; +const boost::uint16_t FX2_VENDOR_ID = 0x04b4; +const boost::uint16_t FX2_PRODUCT_ID = 0x8613; + const std::vector usrp1_impl::_dboard_slots = boost::assign::list_of (usrp1_impl::DBOARD_SLOT_A)(usrp1_impl::DBOARD_SLOT_B) ; @@ -54,33 +59,32 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) ); std::cout << "USRP1 firmware image: " << usrp1_fw_image << std::endl; + boost::uint16_t vid = hint.has_key("uninit") ? FX2_VENDOR_ID : USRP1_VENDOR_ID; + boost::uint16_t pid = hint.has_key("uninit") ? FX2_PRODUCT_ID : USRP1_PRODUCT_ID; + //see what we got on the USB bus std::vector device_list = - usb_device_handle::get_device_list(); + usb_device_handle::get_device_list(vid, pid); + + if(device_list.size() == 0) return usrp1_addrs; //return nothing if no USRPs found //find the usrps and load firmware BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { - if (handle->get_vendor_id() == 0xfffe && - handle->get_product_id() == 0x0002) { - usb_control::sptr ctrl_transport = usb_control::make(handle); usrp_ctrl::sptr usrp_ctrl = usrp_ctrl::make(ctrl_transport); usrp_ctrl->usrp_load_firmware(usrp1_fw_image); - } } - //get descriptors again with serial number - device_list = usb_device_handle::get_device_list(); + //get descriptors again with serial number, but using the initialized VID/PID now since we have firmware + vid = USRP1_VENDOR_ID; + pid = USRP1_PRODUCT_ID; + device_list = usb_device_handle::get_device_list(vid, pid); BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { - if (handle->get_vendor_id() == 0xfffe && - handle->get_product_id() == 0x0002) { - device_addr_t new_addr; new_addr["type"] = "usrp1"; new_addr["serial"] = handle->get_serial(); usrp1_addrs.push_back(new_addr); - } } return usrp1_addrs; @@ -99,17 +103,15 @@ static device::sptr usrp1_make(const device_addr_t &device_addr) //try to match the given device address with something on the USB bus std::vector device_list = - usb_device_handle::get_device_list(); + usb_device_handle::get_device_list(USRP1_VENDOR_ID, USRP1_PRODUCT_ID); //create data and control transports usb_zero_copy::sptr data_transport; usrp_ctrl::sptr usrp_ctrl; - BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { - if (handle->get_vendor_id() == 0xfffe && - handle->get_product_id() == 0x0002 && - handle->get_serial() == device_addr["serial"]) { + BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { + if (handle->get_serial() == device_addr["serial"]) { usb_control::sptr ctrl_transport = usb_control::make(handle); usrp_ctrl = usrp_ctrl::make(ctrl_transport); usrp_ctrl->usrp_load_fpga(usrp1_fpga_image); diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index c349a9018..9d788b06c 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -39,9 +39,13 @@ TARGET_LINK_LIBRARIES(usrp2_addr_burner uhd) ADD_EXECUTABLE(usrp_burn_db_eeprom usrp_burn_db_eeprom.cpp) TARGET_LINK_LIBRARIES(usrp_burn_db_eeprom uhd) +ADD_EXECUTABLE(usrp_init_eeprom usrp_init_eeprom.cpp) +TARGET_LINK_LIBRARIES(usrp_init_eeprom uhd) + INSTALL(TARGETS usrp2_addr_burner usrp_burn_db_eeprom + usrp_init_eeprom RUNTIME DESTINATION ${PKG_DATA_DIR}/utils ) diff --git a/host/utils/usrp_init_eeprom.cpp b/host/utils/usrp_init_eeprom.cpp new file mode 100644 index 000000000..28c7c5745 --- /dev/null +++ b/host/utils/usrp_init_eeprom.cpp @@ -0,0 +1,69 @@ +// +// Copyright 2010 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 . +// + +#include +#include +#include +#include +#include +#include + +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("image", po::value(), "IHX image file") + ; + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //print the help message + if (vm.count("help")){ + std::cout << boost::format("USRP EEPROM initialization %s") % desc << std::endl; + return ~0; + } + + //load the options into the address + uhd::device_addr_t device_addr; + device_addr["type"] = "usrp1"; + device_addr["uninit"] = "yeah"; //tell find to look for an uninitialized FX2 + + //find and create a control transport to do the writing. + + uhd::device_addrs_t found_addrs = uhd::device::find(device_addr); + + if (found_addrs.size() == 0){ + std::cerr << "No uninitialized USRP devices found" << std::endl; + return ~0; + } + + for (size_t i = 0; i < found_addrs.size(); i++){ + std::cout << "Writing EEPROM data..." << std::endl; + //uhd::device_addrs_t devs = uhd::device::find(found_addrs[i]); + uhd::device::sptr dev = uhd::device::make(found_addrs[i]); + wax::obj mb = (*dev)[uhd::usrp::DEVICE_PROP_MBOARD]; + mb[std::string("load_eeprom")] = vm["image"].as(); + } + + + std::cout << "Power-cycle the usrp for the changes to take effect." << std::endl; + return 0; +} -- cgit v1.2.3 From 7b066a4593646b6023f56283ff02cf0e4ee099a6 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 31 Aug 2010 17:32:55 -0700 Subject: Added usrp_serial_burner.cpp and capabilities for setting serial number in mboard_impl. Have not yet added read support. --- host/lib/usrp/usrp1/mboard_impl.cpp | 12 +++++- host/utils/CMakeLists.txt | 4 ++ host/utils/usrp_init_eeprom.cpp | 2 +- host/utils/usrp_serial_burner.cpp | 74 +++++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 host/utils/usrp_serial_burner.cpp diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index 1409855cb..8555577f5 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -19,6 +19,7 @@ #include "usrp_commands.h" #include "fpga_regs_standard.h" #include "fpga_regs_common.h" +#include "usrp_i2c_addr.h" #include #include #include @@ -321,11 +322,18 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val) { if(key.type() == typeid(std::string)) { if(key.as() == "load_eeprom") { - std::string usrp1_fpga_image = val.as(); - std::cout << "USRP1 EEPROM image: " << usrp1_fpga_image << std::endl; + std::string usrp1_eeprom_image = val.as(); + std::cout << "USRP1 EEPROM image: " << usrp1_eeprom_image << std::endl; _ctrl_transport->usrp_load_eeprom(val.as()); } + if(key.as() == "serial") { + std::string sernum = val.as(); + uhd::byte_vector_t buf(sernum.begin(), sernum.end()); + buf.insert(buf.begin(), 248); + _iface->write_i2c(I2C_DEV_EEPROM, buf); + } + return; } diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index 9d788b06c..48f91aaa7 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -42,10 +42,14 @@ TARGET_LINK_LIBRARIES(usrp_burn_db_eeprom uhd) ADD_EXECUTABLE(usrp_init_eeprom usrp_init_eeprom.cpp) TARGET_LINK_LIBRARIES(usrp_init_eeprom uhd) +ADD_EXECUTABLE(usrp_serial_burner usrp_serial_burner.cpp) +TARGET_LINK_LIBRARIES(usrp_serial_burner uhd) + INSTALL(TARGETS usrp2_addr_burner usrp_burn_db_eeprom usrp_init_eeprom + usrp_serial_burner RUNTIME DESTINATION ${PKG_DATA_DIR}/utils ) diff --git a/host/utils/usrp_init_eeprom.cpp b/host/utils/usrp_init_eeprom.cpp index 28c7c5745..b05e400b1 100644 --- a/host/utils/usrp_init_eeprom.cpp +++ b/host/utils/usrp_init_eeprom.cpp @@ -28,7 +28,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") - ("image", po::value(), "IHX image file") + ("image", po::value(), "BIN image file") ; po::variables_map vm; diff --git a/host/utils/usrp_serial_burner.cpp b/host/utils/usrp_serial_burner.cpp new file mode 100644 index 000000000..cdb6eff65 --- /dev/null +++ b/host/utils/usrp_serial_burner.cpp @@ -0,0 +1,74 @@ +// +// Copyright 2010 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 . +// + +#include +#include +#include +#include +#include +#include + +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("old", po::value(), "old USRP serial number (optional)") + ("new", po::value(), "new USRP serial number") + ; + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //print the help message + if (vm.count("help")){ + std::cout << boost::format("USRP serial burner %s") % desc << std::endl; + return ~0; + } + + if(vm.count("new") == 0) { + std::cout << "error: must input --new arg" << std::endl; + return ~0; + } + + //load the options into the address + uhd::device_addr_t device_addr; + device_addr["type"] = "usrp1"; + if(vm.count("old")) device_addr["serial"] = vm["old"].as(); + + //find and create a control transport to do the writing. + + uhd::device_addrs_t found_addrs = uhd::device::find(device_addr); + + if (found_addrs.size() == 0){ + std::cerr << "No USRP devices found" << std::endl; + return ~0; + } + + for (size_t i = 0; i < found_addrs.size(); i++){ + uhd::device::sptr dev = uhd::device::make(found_addrs[i]); + wax::obj mb = (*dev)[uhd::usrp::DEVICE_PROP_MBOARD]; + std::cout << "Writing serial number..." << std::endl; + mb[std::string("serial")] = vm["new"].as(); + } + + + std::cout << "Power-cycle the usrp for the changes to take effect." << std::endl; + return 0; +} -- cgit v1.2.3 From 4c7a66cfa0b84955fcd34b0e356c1141b21a7e17 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 31 Aug 2010 17:52:10 -0700 Subject: Added serial number read. Renamed the usrp1-specific utilities. --- host/lib/usrp/usrp1/mboard_impl.cpp | 15 ++++++++ host/utils/CMakeLists.txt | 12 +++--- host/utils/usrp1_init_eeprom.cpp | 69 ++++++++++++++++++++++++++++++++++ host/utils/usrp1_serial_burner.cpp | 75 +++++++++++++++++++++++++++++++++++++ host/utils/usrp_init_eeprom.cpp | 69 ---------------------------------- host/utils/usrp_serial_burner.cpp | 74 ------------------------------------ 6 files changed, 165 insertions(+), 149 deletions(-) create mode 100644 host/utils/usrp1_init_eeprom.cpp create mode 100644 host/utils/usrp1_serial_burner.cpp delete mode 100644 host/utils/usrp_init_eeprom.cpp delete mode 100644 host/utils/usrp_serial_burner.cpp diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index 8555577f5..a90532cb8 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include using namespace uhd; @@ -251,6 +252,20 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val) { named_prop_t key = named_prop_t::extract(key_); + if(key_.type() == typeid(std::string)) { + if(key.as() == "serial") { + uhd::byte_vector_t buf; + buf.insert(buf.begin(), 248); + boost::this_thread::sleep(boost::posix_time::milliseconds(100)); + _iface->write_i2c(I2C_DEV_EEPROM, buf); + boost::this_thread::sleep(boost::posix_time::milliseconds(100)); + buf = _iface->read_i2c(I2C_DEV_EEPROM, 8); + val = std::string(buf.begin(), buf.end()); + } + + return; + } + //handle the get request conditioned on the key switch(key.as()){ case MBOARD_PROP_NAME: diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index 48f91aaa7..a95864ca7 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -39,17 +39,17 @@ TARGET_LINK_LIBRARIES(usrp2_addr_burner uhd) ADD_EXECUTABLE(usrp_burn_db_eeprom usrp_burn_db_eeprom.cpp) TARGET_LINK_LIBRARIES(usrp_burn_db_eeprom uhd) -ADD_EXECUTABLE(usrp_init_eeprom usrp_init_eeprom.cpp) -TARGET_LINK_LIBRARIES(usrp_init_eeprom uhd) +ADD_EXECUTABLE(usrp1_init_eeprom usrp1_init_eeprom.cpp) +TARGET_LINK_LIBRARIES(usrp1_init_eeprom uhd) -ADD_EXECUTABLE(usrp_serial_burner usrp_serial_burner.cpp) -TARGET_LINK_LIBRARIES(usrp_serial_burner uhd) +ADD_EXECUTABLE(usrp1_serial_burner usrp1_serial_burner.cpp) +TARGET_LINK_LIBRARIES(usrp1_serial_burner uhd) INSTALL(TARGETS usrp2_addr_burner usrp_burn_db_eeprom - usrp_init_eeprom - usrp_serial_burner + usrp1_init_eeprom + usrp1_serial_burner RUNTIME DESTINATION ${PKG_DATA_DIR}/utils ) diff --git a/host/utils/usrp1_init_eeprom.cpp b/host/utils/usrp1_init_eeprom.cpp new file mode 100644 index 000000000..b05e400b1 --- /dev/null +++ b/host/utils/usrp1_init_eeprom.cpp @@ -0,0 +1,69 @@ +// +// Copyright 2010 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 . +// + +#include +#include +#include +#include +#include +#include + +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("image", po::value(), "BIN image file") + ; + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //print the help message + if (vm.count("help")){ + std::cout << boost::format("USRP EEPROM initialization %s") % desc << std::endl; + return ~0; + } + + //load the options into the address + uhd::device_addr_t device_addr; + device_addr["type"] = "usrp1"; + device_addr["uninit"] = "yeah"; //tell find to look for an uninitialized FX2 + + //find and create a control transport to do the writing. + + uhd::device_addrs_t found_addrs = uhd::device::find(device_addr); + + if (found_addrs.size() == 0){ + std::cerr << "No uninitialized USRP devices found" << std::endl; + return ~0; + } + + for (size_t i = 0; i < found_addrs.size(); i++){ + std::cout << "Writing EEPROM data..." << std::endl; + //uhd::device_addrs_t devs = uhd::device::find(found_addrs[i]); + uhd::device::sptr dev = uhd::device::make(found_addrs[i]); + wax::obj mb = (*dev)[uhd::usrp::DEVICE_PROP_MBOARD]; + mb[std::string("load_eeprom")] = vm["image"].as(); + } + + + std::cout << "Power-cycle the usrp for the changes to take effect." << std::endl; + return 0; +} diff --git a/host/utils/usrp1_serial_burner.cpp b/host/utils/usrp1_serial_burner.cpp new file mode 100644 index 000000000..bf7d3d3bb --- /dev/null +++ b/host/utils/usrp1_serial_burner.cpp @@ -0,0 +1,75 @@ +// +// Copyright 2010 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 . +// + +#include +#include +#include +#include +#include +#include + +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("old", po::value(), "old USRP serial number (optional)") + ("new", po::value(), "new USRP serial number") + ; + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //print the help message + if (vm.count("help")){ + std::cout << boost::format("USRP serial burner %s") % desc << std::endl; + return ~0; + } + + if(vm.count("new") == 0) { + std::cout << "error: must input --new arg" << std::endl; + return ~0; + } + + //load the options into the address + uhd::device_addr_t device_addr; + device_addr["type"] = "usrp1"; + if(vm.count("old")) device_addr["serial"] = vm["old"].as(); + + //find and create a control transport to do the writing. + + uhd::device_addrs_t found_addrs = uhd::device::find(device_addr); + + if (found_addrs.size() == 0){ + std::cerr << "No USRP devices found" << std::endl; + return ~0; + } + + for (size_t i = 0; i < found_addrs.size(); i++){ + uhd::device::sptr dev = uhd::device::make(found_addrs[i]); + wax::obj mb = (*dev)[uhd::usrp::DEVICE_PROP_MBOARD]; + std::cout << "Writing serial number..." << std::endl; + mb[std::string("serial")] = vm["new"].as(); + std::cout << "Reading back serial number: " << mb[std::string("serial")].as() << std::endl; + } + + + std::cout << "Power-cycle the usrp for the changes to take effect." << std::endl; + return 0; +} diff --git a/host/utils/usrp_init_eeprom.cpp b/host/utils/usrp_init_eeprom.cpp deleted file mode 100644 index b05e400b1..000000000 --- a/host/utils/usrp_init_eeprom.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// -// Copyright 2010 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 . -// - -#include -#include -#include -#include -#include -#include - -namespace po = boost::program_options; - -int UHD_SAFE_MAIN(int argc, char *argv[]){ - po::options_description desc("Allowed options"); - desc.add_options() - ("help", "help message") - ("image", po::value(), "BIN image file") - ; - - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); - - //print the help message - if (vm.count("help")){ - std::cout << boost::format("USRP EEPROM initialization %s") % desc << std::endl; - return ~0; - } - - //load the options into the address - uhd::device_addr_t device_addr; - device_addr["type"] = "usrp1"; - device_addr["uninit"] = "yeah"; //tell find to look for an uninitialized FX2 - - //find and create a control transport to do the writing. - - uhd::device_addrs_t found_addrs = uhd::device::find(device_addr); - - if (found_addrs.size() == 0){ - std::cerr << "No uninitialized USRP devices found" << std::endl; - return ~0; - } - - for (size_t i = 0; i < found_addrs.size(); i++){ - std::cout << "Writing EEPROM data..." << std::endl; - //uhd::device_addrs_t devs = uhd::device::find(found_addrs[i]); - uhd::device::sptr dev = uhd::device::make(found_addrs[i]); - wax::obj mb = (*dev)[uhd::usrp::DEVICE_PROP_MBOARD]; - mb[std::string("load_eeprom")] = vm["image"].as(); - } - - - std::cout << "Power-cycle the usrp for the changes to take effect." << std::endl; - return 0; -} diff --git a/host/utils/usrp_serial_burner.cpp b/host/utils/usrp_serial_burner.cpp deleted file mode 100644 index cdb6eff65..000000000 --- a/host/utils/usrp_serial_burner.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// -// Copyright 2010 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 . -// - -#include -#include -#include -#include -#include -#include - -namespace po = boost::program_options; - -int UHD_SAFE_MAIN(int argc, char *argv[]){ - po::options_description desc("Allowed options"); - desc.add_options() - ("help", "help message") - ("old", po::value(), "old USRP serial number (optional)") - ("new", po::value(), "new USRP serial number") - ; - - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); - - //print the help message - if (vm.count("help")){ - std::cout << boost::format("USRP serial burner %s") % desc << std::endl; - return ~0; - } - - if(vm.count("new") == 0) { - std::cout << "error: must input --new arg" << std::endl; - return ~0; - } - - //load the options into the address - uhd::device_addr_t device_addr; - device_addr["type"] = "usrp1"; - if(vm.count("old")) device_addr["serial"] = vm["old"].as(); - - //find and create a control transport to do the writing. - - uhd::device_addrs_t found_addrs = uhd::device::find(device_addr); - - if (found_addrs.size() == 0){ - std::cerr << "No USRP devices found" << std::endl; - return ~0; - } - - for (size_t i = 0; i < found_addrs.size(); i++){ - uhd::device::sptr dev = uhd::device::make(found_addrs[i]); - wax::obj mb = (*dev)[uhd::usrp::DEVICE_PROP_MBOARD]; - std::cout << "Writing serial number..." << std::endl; - mb[std::string("serial")] = vm["new"].as(); - } - - - std::cout << "Power-cycle the usrp for the changes to take effect." << std::endl; - return 0; -} -- cgit v1.2.3 From ce3a95dbefa8528354301529eeb30957412d9b9f Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 31 Aug 2010 18:01:36 -0700 Subject: Removed USRP1 firmware path debug messages --- host/lib/usrp/usrp1/usrp1_impl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index a18b697fb..a6806dbc3 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -69,7 +69,7 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) ); return usrp1_addrs; } - std::cout << "USRP1 firmware image: " << usrp1_fw_image << std::endl; + //std::cout << "USRP1 firmware image: " << usrp1_fw_image << std::endl; boost::uint16_t vid = hint.has_key("uninit") ? FX2_VENDOR_ID : USRP1_VENDOR_ID; boost::uint16_t pid = hint.has_key("uninit") ? FX2_PRODUCT_ID : USRP1_PRODUCT_ID; @@ -111,7 +111,7 @@ static device::sptr usrp1_make(const device_addr_t &device_addr) std::string usrp1_fpga_image = find_image_path( device_addr.has_key("fpga")? device_addr["fpga"] : "usrp1_fpga.rbf" ); - std::cout << "USRP1 FPGA image: " << usrp1_fpga_image << std::endl; + //std::cout << "USRP1 FPGA image: " << usrp1_fpga_image << std::endl; //try to match the given device address with something on the USB bus std::vector device_list = -- cgit v1.2.3 From 5058145dcc5cb681887773b8245cf89df58399f9 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 31 Aug 2010 18:11:13 -0700 Subject: usrp1: added docs and author --- host/AUTHORS | 4 ++++ host/docs/usrp1.rst | 49 ++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/host/AUTHORS b/host/AUTHORS index 7292da8f9..e0775f3a1 100644 --- a/host/AUTHORS +++ b/host/AUTHORS @@ -23,3 +23,7 @@ Tom Tsou - ttsou@vt.edu LIBUSB host code USRP1 host code USRP1 firmware + +Nick Foster - nick@nerdnetworks.org + LIBUSB host code + USRP1 host code diff --git a/host/docs/usrp1.rst b/host/docs/usrp1.rst index c960b928b..3c1431d30 100644 --- a/host/docs/usrp1.rst +++ b/host/docs/usrp1.rst @@ -7,19 +7,58 @@ UHD - USRP1 Application Notes ------------------------------------------------------------------------ Addressing the device ------------------------------------------------------------------------ -A USRP1 can be identified though its serial number, +A USRP1 can be identified though its 8 digit serial number, designated by the "serial" key in the device address. -The device address string representation for a USRP1 with serial 1234 +The device address string representation for a USRP1 with serial 12345678: :: - serial=1234 + serial=12345678 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Change the USRP1's serial number +Change the serial number ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -TODO +The USRP1 serial number can be changed to any 8 byte string. Examples: + +:: + + cd /share/uhd/utils + ./usrp1_serial_burner --new=87654321 + + -- OR -- + + ./usrp1_serial_burner --new=Beatrice + + -- OR -- + + ./usrp1_serial_burner --old=12345678 --new=87654321 + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Specify a non-standard image +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The standard USRP1 images installer comes with two FPGA images: + * **usrp1_fpga.rbf:** 2 DDCs + 2 DUCs + * **usrp1_fpga_4rx.rbf:** 4 DDCs + 0 DUCs + +By default, the USRP1 uses the FPGA image with 2 DDCs and 2 DUCs. +However, a device address parameter can be used to override +the FPGA image selection to use an alternate or a custom FPGA image. +See the images application notes for installing custom images. + +Example device address string representations to specify non-standard firmware and/or FPGA images: + +:: + + fpga=usrp1_fpga_4rx.rbf + + -- OR -- + + fw=usrp1_fw_custom.ihx + + -- OR -- + + fpga=usrp1_fpga_4rx.rbf, fw=usrp1_fw_custom.ihx ------------------------------------------------------------------------ Specifying the subdevice to use -- cgit v1.2.3 From 6d315076ba2ef5aa7612ebe3cf39f72bc2bb76e5 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 9 Sep 2010 11:07:59 -0700 Subject: usrp: dboard eeprom burner app takes slot param (fixed for automatic) --- host/docs/dboards.rst | 4 ++-- host/utils/usrp_burn_db_eeprom.cpp | 15 +++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/host/docs/dboards.rst b/host/docs/dboards.rst index 0f6d1cfeb..985fbc12b 100644 --- a/host/docs/dboards.rst +++ b/host/docs/dboards.rst @@ -141,7 +141,7 @@ With the daughterboard plugged-in, run the following commands: :: cd /share/uhd/utils - ./usrp_burn_db_eeprom --id=0x000d --unit=RX --args= --db= + ./usrp_burn_db_eeprom --id=0x000d --unit=RX --args= --slot= * are device address arguments (optional if only one USRP is on your machine) -* is the name of the daughterboard slot (optional if the USRP has only one slot) +* is the name of the daughterboard slot (optional if the USRP has only one slot) diff --git a/host/utils/usrp_burn_db_eeprom.cpp b/host/utils/usrp_burn_db_eeprom.cpp index db2981e87..64ecf75d6 100644 --- a/host/utils/usrp_burn_db_eeprom.cpp +++ b/host/utils/usrp_burn_db_eeprom.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -34,16 +35,19 @@ namespace po = boost::program_options; int UHD_SAFE_MAIN(int argc, char *argv[]){ //command line variables - std::string args, db_name, unit; + std::string args, slot, unit; static const uhd::dict unit_to_db_prop = boost::assign::map_list_of ("RX", MBOARD_PROP_RX_DBOARD) ("TX", MBOARD_PROP_TX_DBOARD) ; + static const uhd::dict unit_to_db_names_prop = boost::assign::map_list_of + ("RX", MBOARD_PROP_RX_DBOARD_NAMES) ("TX", MBOARD_PROP_TX_DBOARD_NAMES) + ; po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") ("args", po::value(&args)->default_value(""), "device address args [default = \"\"]") - ("db", po::value(&db_name)->default_value(""), "dboard name [default = \"\"]") + ("slot", po::value(&slot)->default_value(""), "dboard slot name [default is blank for automatic]") ("unit", po::value(&unit)->default_value(""), "which unit [RX or TX]") ("id", po::value(), "dboard id to burn, omit for readback") ; @@ -70,8 +74,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //make the device and extract the dboard w/ property device::sptr dev = device::make(args); - wax::obj dboard = (*dev)[DEVICE_PROP_MBOARD][named_prop_t(unit_to_db_prop[unit], db_name)]; - std::string prefix = (db_name == "")? unit : (unit + ":" + db_name); + uhd::prop_names_t dboard_names = (*dev)[DEVICE_PROP_MBOARD][unit_to_db_names_prop[unit]].as(); + if (dboard_names.size() == 1 and slot.empty()) slot = dboard_names.front(); + uhd::assert_has(dboard_names, slot, "dboard slot name"); + wax::obj dboard = (*dev)[DEVICE_PROP_MBOARD][named_prop_t(unit_to_db_prop[unit], slot)]; + std::string prefix = unit + ":" + slot; //read the current dboard id from eeprom if (vm.count("id") == 0){ -- cgit v1.2.3 From b7e3450a9b02e3236f94d06e5102a47567733963 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 9 Sep 2010 12:24:20 -0700 Subject: usrp: test for async messages, also renamed pps test --- host/examples/CMakeLists.txt | 14 ++- host/examples/pps_test.cpp | 86 -------------- host/examples/test_async_messages.cpp | 208 ++++++++++++++++++++++++++++++++++ host/examples/test_pps_input.cpp | 86 ++++++++++++++ 4 files changed, 303 insertions(+), 91 deletions(-) delete mode 100644 host/examples/pps_test.cpp create mode 100644 host/examples/test_async_messages.cpp create mode 100644 host/examples/test_pps_input.cpp diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt index 5b241e284..d19838335 100644 --- a/host/examples/CMakeLists.txt +++ b/host/examples/CMakeLists.txt @@ -15,27 +15,31 @@ # along with this program. If not, see . # - +######################################################################## ADD_EXECUTABLE(benchmark_rx_rate benchmark_rx_rate.cpp) TARGET_LINK_LIBRARIES(benchmark_rx_rate uhd) ADD_EXECUTABLE(rx_timed_samples rx_timed_samples.cpp) TARGET_LINK_LIBRARIES(rx_timed_samples uhd) +ADD_EXECUTABLE(test_async_messages test_async_messages.cpp) +TARGET_LINK_LIBRARIES(test_async_messages uhd) + +ADD_EXECUTABLE(test_pps_input test_pps_input.cpp) +TARGET_LINK_LIBRARIES(test_pps_input uhd) + ADD_EXECUTABLE(tx_timed_samples tx_timed_samples.cpp) TARGET_LINK_LIBRARIES(tx_timed_samples uhd) ADD_EXECUTABLE(tx_waveforms tx_waveforms.cpp) TARGET_LINK_LIBRARIES(tx_waveforms uhd) -ADD_EXECUTABLE(pps_test pps_test.cpp) -TARGET_LINK_LIBRARIES(pps_test uhd) - INSTALL(TARGETS benchmark_rx_rate rx_timed_samples + test_async_messages + test_pps_input tx_timed_samples tx_waveforms - pps_test RUNTIME DESTINATION ${PKG_DATA_DIR}/examples ) diff --git a/host/examples/pps_test.cpp b/host/examples/pps_test.cpp deleted file mode 100644 index c25cbe94f..000000000 --- a/host/examples/pps_test.cpp +++ /dev/null @@ -1,86 +0,0 @@ -// -// Copyright 2010 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 . -// - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace po = boost::program_options; - -int UHD_SAFE_MAIN(int argc, char *argv[]){ - uhd::set_thread_priority_safe(); - - //variables to be set by po - std::string args; - float seconds; - - //setup the program options - po::options_description desc("Allowed options"); - desc.add_options() - ("help", "help message") - ("args", po::value(&args)->default_value(""), "simple uhd device address args") - ; - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); - - //print the help message - if (vm.count("help")){ - std::cout << boost::format("UHD PPS Test %s") % desc << std::endl; - return ~0; - } - - //create a usrp device - std::cout << std::endl; - std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; - uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); - uhd::device::sptr dev = sdev->get_device(); - std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; - - //set a known time value - std::cout << "Set time to known value (100.0) without regard to pps:" << std::endl; - sdev->set_time_now(uhd::time_spec_t(100.0)); - boost::this_thread::sleep(boost::posix_time::seconds(1)); - std::cout << boost::format("Reading time 1 second later: %f\n") % (sdev->get_time_now().get_full_secs()) << std::endl; - - //store the time to see if PPS resets it - seconds = sdev->get_time_now().get_full_secs(); - - //set a known time at next PPS, check that time increments - uhd::time_spec_t time_spec = uhd::time_spec_t(0.0); - std::cout << "Set time to known value (0.0) at next pps:" << std::endl; - sdev->set_time_next_pps(time_spec); - boost::this_thread::sleep(boost::posix_time::seconds(1)); - std::cout << boost::format("Reading time 1 second later: %f\n") % (sdev->get_time_now().get_full_secs()) << std::endl; - - //finished - if (seconds > sdev->get_time_now().get_full_secs()){ - std::cout << std::endl << "Success!" << std::endl << std::endl; - return 0; - } else { - std::cout << std::endl << "Failed!" << std::endl << std::endl - << "If you expected PPS to work:" << std::endl - << "\tsee Device App Notes for PPS level information" - << std::endl << std::endl; - return -1; - } -} diff --git a/host/examples/test_async_messages.cpp b/host/examples/test_async_messages.cpp new file mode 100644 index 000000000..e02bc5f40 --- /dev/null +++ b/host/examples/test_async_messages.cpp @@ -0,0 +1,208 @@ +// +// Copyright 2010 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 . +// + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace po = boost::program_options; + +static const size_t async_to_ms = 100; + +/*! + * Test that no messages are received: + * Send a burst of many samples that will fragment internally. + * We expect to not get any async messages. + */ +void test_no_async_message(uhd::usrp::simple_usrp::sptr sdev){ + uhd::device::sptr dev = sdev->get_device(); + std::cout << "Test no async message... " << std::flush; + + uhd::tx_metadata_t md; + md.start_of_burst = true; + md.end_of_burst = true; + md.has_time_spec = false; + + //3 times max-sps guarantees a SOB, no burst, and EOB packet + std::vector > buff(dev->get_max_send_samps_per_packet()*3); + + dev->send( + &buff.front(), buff.size(), md, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::SEND_MODE_FULL_BUFF + ); + + uhd::async_metadata_t async_md; + if (dev->recv_async_msg(async_md, async_to_ms)){ + std::cout << boost::format( + "failed:\n" + " Got unexpected event code 0x%x.\n" + ) % async_md.event_code << std::endl; + //clear the async messages + while (dev->recv_async_msg(async_md, 0)); + } + else{ + std::cout << boost::format( + "success:\n" + " Did not get an async message.\n" + ) << std::endl; + } +} + +/*! + * Test the underflow message: + * Send a start of burst packet with no following end of burst. + * We expect to get an underflow(within a burst) async message. + */ +void test_underflow_message(uhd::usrp::simple_usrp::sptr sdev){ + uhd::device::sptr dev = sdev->get_device(); + std::cout << "Test underflow message... " << std::flush; + + uhd::tx_metadata_t md; + md.start_of_burst = true; + md.end_of_burst = false; + md.has_time_spec = false; + + dev->send(NULL, 0, md, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::SEND_MODE_FULL_BUFF + ); + + uhd::async_metadata_t async_md; + if (not dev->recv_async_msg(async_md, async_to_ms)){ + std::cout << boost::format( + "failed:\n" + " Async message recv timed out.\n" + ) << std::endl; + return; + } + + switch(async_md.event_code){ + case uhd::async_metadata_t::EVENT_CODE_UNDERFLOW: + std::cout << boost::format( + "success:\n" + " Got event code underflow message.\n" + ) << std::endl; + break; + + default: + std::cout << boost::format( + "failed:\n" + " Got unexpected event code 0x%x.\n" + ) % async_md.event_code << std::endl; + } +} + +/*! + * Test the time error message: + * Send a burst packet that occurs at a time in the past. + * We expect to get a time error async message. + */ +void test_time_error_message(uhd::usrp::simple_usrp::sptr sdev){ + uhd::device::sptr dev = sdev->get_device(); + std::cout << "Test time error message... " << std::flush; + + uhd::tx_metadata_t md; + md.start_of_burst = true; + md.end_of_burst = true; + md.has_time_spec = true; + md.time_spec = uhd::time_spec_t(100.0); //send at 100s + + sdev->set_time_now(uhd::time_spec_t(200.0)); //time at 200s + + dev->send(NULL, 0, md, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::SEND_MODE_FULL_BUFF + ); + + uhd::async_metadata_t async_md; + if (not dev->recv_async_msg(async_md, async_to_ms)){ + std::cout << boost::format( + "failed:\n" + " Async message recv timed out.\n" + ) << std::endl; + return; + } + + switch(async_md.event_code){ + case uhd::async_metadata_t::EVENT_CODE_TIME_ERROR: + std::cout << boost::format( + "success:\n" + " Got event code time error message.\n" + ) << std::endl; + break; + + default: + std::cout << boost::format( + "failed:\n" + " Got unexpected event code 0x%x.\n" + ) % async_md.event_code << std::endl; + } +} + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + uhd::set_thread_priority_safe(); + + //variables to be set by po + std::string args; + double rate; + + //setup the program options + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("args", po::value(&args)->default_value(""), "simple uhd device address args") + ("rate", po::value(&rate)->default_value(1.5e6), "rate of outgoing samples") + ; + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //print the help message + if (vm.count("help")){ + std::cout << boost::format("UHD Test Async Messages %s") % desc << std::endl; + return ~0; + } + + //create a usrp device + std::cout << std::endl; + std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; + uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); + std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; + + //set the tx sample rate + std::cout << boost::format("Setting TX Rate: %f Msps...") % (rate/1e6) << std::endl; + sdev->set_tx_rate(rate); + std::cout << boost::format("Actual TX Rate: %f Msps...") % (sdev->get_tx_rate()/1e6) << std::endl << std::endl; + + //------------------------------------------------------------------ + // begin asyc messages test + //------------------------------------------------------------------ + test_no_async_message(sdev); + test_underflow_message(sdev); + test_time_error_message(sdev); + + //finished + std::cout << std::endl << "Done!" << std::endl << std::endl; + + return 0; +} diff --git a/host/examples/test_pps_input.cpp b/host/examples/test_pps_input.cpp new file mode 100644 index 000000000..e01d32910 --- /dev/null +++ b/host/examples/test_pps_input.cpp @@ -0,0 +1,86 @@ +// +// Copyright 2010 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 . +// + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + uhd::set_thread_priority_safe(); + + //variables to be set by po + std::string args; + float seconds; + + //setup the program options + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("args", po::value(&args)->default_value(""), "simple uhd device address args") + ; + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //print the help message + if (vm.count("help")){ + std::cout << boost::format("UHD Test PPS Input %s") % desc << std::endl; + return ~0; + } + + //create a usrp device + std::cout << std::endl; + std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; + uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); + uhd::device::sptr dev = sdev->get_device(); + std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; + + //set a known time value + std::cout << "Set time to known value (100.0) without regard to pps:" << std::endl; + sdev->set_time_now(uhd::time_spec_t(100.0)); + boost::this_thread::sleep(boost::posix_time::seconds(1)); + std::cout << boost::format("Reading time 1 second later: %f\n") % (sdev->get_time_now().get_full_secs()) << std::endl; + + //store the time to see if PPS resets it + seconds = sdev->get_time_now().get_full_secs(); + + //set a known time at next PPS, check that time increments + uhd::time_spec_t time_spec = uhd::time_spec_t(0.0); + std::cout << "Set time to known value (0.0) at next pps:" << std::endl; + sdev->set_time_next_pps(time_spec); + boost::this_thread::sleep(boost::posix_time::seconds(1)); + std::cout << boost::format("Reading time 1 second later: %f\n") % (sdev->get_time_now().get_full_secs()) << std::endl; + + //finished + if (seconds > sdev->get_time_now().get_full_secs()){ + std::cout << std::endl << "Success!" << std::endl << std::endl; + return 0; + } else { + std::cout << std::endl << "Failed!" << std::endl << std::endl + << "If you expected PPS to work:" << std::endl + << "\tsee Device App Notes for PPS level information" + << std::endl << std::endl; + return -1; + } +} -- cgit v1.2.3 From ddfcc114bfd6d37c182a3279368852f4b96f9ffd Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 9 Sep 2010 12:35:37 -0700 Subject: usrp2: added some pps docs using the test example app --- host/docs/usrp2.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index 0d48209be..745361b77 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -213,10 +213,19 @@ Hardware setup notes ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Ref Clock - 10MHz ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Using an external 10MHz reference clock requires a signal level between +5dBm and +20dBm at 10MHz applied to the Ref Clock SMA port on the front panel. +Using an external 10MHz reference clock requires a signal level between ++5dBm and +20dBm at 10MHz applied to the Ref Clock SMA port on the front panel. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PPS - Pulse Per Second ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Using a PPS signal for timestamp synchronization requires a 5Vpp square wave signal + +Test the PPS input of the USRP2 with the following app: +:: + + cd /share/uhd/examples + ./test_pps_input --args= + +* are device address arguments (optional if only one USRP is on your machine) -- cgit v1.2.3 From 72646d1960b0c979afec225e741d7d89a827c7d0 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 9 Sep 2010 15:53:04 -0700 Subject: uhd: added enable flags for usrp1 and usrp2 --- host/lib/transport/CMakeLists.txt | 6 ++++ host/lib/usrp/usrp1/CMakeLists.txt | 32 +++++++++++++-------- host/lib/usrp/usrp2/CMakeLists.txt | 59 ++++++++++++++++++++++++++------------ 3 files changed, 66 insertions(+), 31 deletions(-) diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index 753fd5e85..71a3a1494 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -35,6 +35,12 @@ IF(LIBUSB_FOUND) SET(HAVE_USB_SUPPORT TRUE) ENDIF(LIBUSB_FOUND) +IF(HAVE_USB_SUPPORT) + MESSAGE(STATUS "Has USB support - found") +ELSE(HAVE_USB_SUPPORT) + MESSAGE(STATUS "Has USB support - not found") +ENDIF(HAVE_USB_SUPPORT) + ######################################################################## # Check for SIMD headers ######################################################################## diff --git a/host/lib/usrp/usrp1/CMakeLists.txt b/host/lib/usrp/usrp1/CMakeLists.txt index 229a4ce63..67487f99e 100644 --- a/host/lib/usrp/usrp1/CMakeLists.txt +++ b/host/lib/usrp/usrp1/CMakeLists.txt @@ -20,18 +20,26 @@ ######################################################################## # Conditionally configure the USRP1 support ######################################################################## -MESSAGE(STATUS "Configuring usrp1 support...") +MESSAGE(STATUS "Configuring USRP1 support...") -IF(HAVE_USB_SUPPORT) - MESSAGE(STATUS "Has USB support - found") -ELSE(HAVE_USB_SUPPORT) - MESSAGE(STATUS "Has USB support - not found") -ENDIF(HAVE_USB_SUPPORT) +IF(DEFINED ENABLE_USRP1) + IF(ENABLE_USRP1) + MESSAGE(STATUS "USRP1 support enabled by configure flag") + ELSE(ENABLE_USRP1) + MESSAGE(STATUS "USRP1 support disabled by configure flag") + ENDIF(ENABLE_USRP1) +ELSE(DEFINED ENABLE_USRP1) #not defined: automatic enabling of component + SET(ENABLE_USRP1 ${HAVE_USB_SUPPORT}) +ENDIF(DEFINED ENABLE_USRP1) +SET(ENABLE_USRP1 ${ENABLE_USRP1} CACHE BOOL "enable USRP1 support") -#TODO check for usrp1 enable/disable option flag +#sanity check when USRP1 support enabled +IF(ENABLE_USRP1 AND NOT HAVE_USB_SUPPORT) + MESSAGE(FATAL_ERROR "USRP1 support enabled without USB support") +ENDIF(ENABLE_USRP1 AND NOT HAVE_USB_SUPPORT) -IF(HAVE_USB_SUPPORT) - MESSAGE(STATUS " Building usrp1 support.") +IF(ENABLE_USRP1) + MESSAGE(STATUS " Building USRP1 support.") INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/../firmware/fx2/include) LIBUHD_APPEND_SOURCES( @@ -52,6 +60,6 @@ IF(HAVE_USB_SUPPORT) ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_ctrl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp1/usrp1_ctrl.hpp ) -ELSE(HAVE_USB_SUPPORT) - MESSAGE(STATUS " Skipping usrp1 support.") -ENDIF(HAVE_USB_SUPPORT) +ELSE(ENABLE_USRP1) + MESSAGE(STATUS " Skipping USRP1 support.") +ENDIF(ENABLE_USRP1) diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index 796126d07..078485d6a 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -17,22 +17,43 @@ #This file will be included by cmake, use absolute paths! -LIBUHD_APPEND_SOURCES( - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_iface.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dsp_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/io_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/mboard_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/serdes_ctrl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/serdes_ctrl.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_iface.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_iface.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.hpp - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_regs.hpp -) +######################################################################## +# Conditionally configure the USRP2 support +######################################################################## +MESSAGE(STATUS "Configuring USRP2 support...") + +IF(DEFINED ENABLE_USRP2) + IF(ENABLE_USRP2) + MESSAGE(STATUS "USRP2 support enabled by configure flag") + ELSE(ENABLE_USRP2) + MESSAGE(STATUS "USRP2 support disabled by configure flag") + ENDIF(ENABLE_USRP2) +ELSE(DEFINED ENABLE_USRP2) #not defined: automatic enabling of component + SET(ENABLE_USRP2 TRUE) +ENDIF(DEFINED ENABLE_USRP2) +SET(ENABLE_USRP2 ${ENABLE_USRP2} CACHE BOOL "enable USRP2 support") + +IF(ENABLE_USRP2) + MESSAGE(STATUS " Building USRP2 support.") + LIBUHD_APPEND_SOURCES( + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_iface.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dsp_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/io_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/mboard_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/serdes_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/serdes_ctrl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_iface.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_iface.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_regs.hpp + ) +ELSE(ENABLE_USRP2) + MESSAGE(STATUS " Skipping USRP2 support.") +ENDIF(ENABLE_USRP2) -- cgit v1.2.3