]> git.zerfleddert.de Git - proxmark3-svn/commitdiff
Initial commit for the firmware. Used the 20090306_ela version as baseline.
authoredouard@lafargue.name <edouard@lafargue.name@ef4ab9da-24cd-11de-8aaa-f3a34680c41f>
Thu, 9 Apr 2009 06:43:20 +0000 (06:43 +0000)
committeredouard@lafargue.name <edouard@lafargue.name@ef4ab9da-24cd-11de-8aaa-f3a34680c41f>
Thu, 9 Apr 2009 06:43:20 +0000 (06:43 +0000)
It is identical to the popular 20081211, with the doob addition (20090301), a
linux client, and two additional commands for LF analysis. Let me know if
you find issues here!

91 files changed:
LICENSE.txt [new file with mode: 0644]
LOG.txt [new file with mode: 0644]
README-gj.txt [new file with mode: 0644]
README.txt [new file with mode: 0644]
armsrc/LCD.c [new file with mode: 0644]
armsrc/LCD.h [new file with mode: 0644]
armsrc/Makefile [new file with mode: 0644]
armsrc/appmain.c [new file with mode: 0644]
armsrc/apps.h [new file with mode: 0644]
armsrc/example_lcd.c [new file with mode: 0644]
armsrc/fonts.c [new file with mode: 0644]
armsrc/fonts.h [new file with mode: 0644]
armsrc/fpga.c [new file with mode: 0644]
armsrc/fpgaimg.c [new file with mode: 0644]
armsrc/iso14443.c [new file with mode: 0644]
armsrc/iso14443a.c [new file with mode: 0644]
armsrc/iso15693.c [new file with mode: 0644]
armsrc/ldscript [new file with mode: 0644]
armsrc/ldscript-fpga [new file with mode: 0644]
armsrc/start.c [new file with mode: 0644]
armsrc/util.c [new file with mode: 0644]
bootrom/Makefile [new file with mode: 0644]
bootrom/bootrom.c [new file with mode: 0644]
bootrom/flash-reset.s [new file with mode: 0644]
bootrom/fromflash.c [new file with mode: 0644]
bootrom/ldscript-flash [new file with mode: 0644]
bootrom/ldscript-ram-jtag [new file with mode: 0644]
bootrom/ram-reset.s [new file with mode: 0644]
cockpit/0setpath.bat [new file with mode: 0644]
cockpit/1makearm.bat [new file with mode: 0644]
cockpit/2makeboot.bat [new file with mode: 0644]
cockpit/3makewin.bat [new file with mode: 0644]
cockpit/4flashos.bat [new file with mode: 0644]
cockpit/5makeall.bat [new file with mode: 0644]
cockpit/prox.bat [new file with mode: 0644]
common/iso14443_crc.c [new file with mode: 0644]
common/usb.c [new file with mode: 0644]
doc/CHANGES.TXT [new file with mode: 0644]
doc/README.TXT [new file with mode: 0644]
doc/component-placement.bmp [new file with mode: 0644]
doc/proxmark3.pdf [new file with mode: 0644]
doc/proxmark3.xls [new file with mode: 0644]
doc/schematics.pdf [new file with mode: 0644]
doc/system.txt [new file with mode: 0644]
fpga/fpga.mpf [new file with mode: 0644]
fpga/fpga.ucf [new file with mode: 0644]
fpga/fpga.v [new file with mode: 0644]
fpga/go.bat [new file with mode: 0644]
fpga/hi_iso14443a.v [new file with mode: 0644]
fpga/hi_read_rx_xcorr.v [new file with mode: 0644]
fpga/hi_read_tx.v [new file with mode: 0644]
fpga/hi_simulate.v [new file with mode: 0644]
fpga/lo_read.v [new file with mode: 0644]
fpga/lo_simulate.v [new file with mode: 0644]
fpga/sim.tcl [new file with mode: 0644]
fpga/testbed_fpga.v [new file with mode: 0644]
fpga/testbed_hi_read_tx.v [new file with mode: 0644]
fpga/testbed_hi_simulate.v [new file with mode: 0644]
fpga/testbed_lo_read.v [new file with mode: 0644]
fpga/testbed_lo_simulate.v [new file with mode: 0644]
fpga/util.v [new file with mode: 0644]
fpga/xst.scr [new file with mode: 0644]
include/at91sam7s128.h [new file with mode: 0644]
include/config_gpio.h [new file with mode: 0644]
include/proxmark3.h [new file with mode: 0644]
include/usb_cmd.h [new file with mode: 0644]
linux/Makefile [new file with mode: 0644]
linux/command.c [new file with mode: 0644]
linux/flasher.c [new file with mode: 0644]
linux/gui.c [new file with mode: 0644]
linux/guidummy.c [new file with mode: 0644]
linux/proxgui.cpp [new file with mode: 0644]
linux/proxgui.h [new file with mode: 0644]
linux/proxguiqt.cpp [new file with mode: 0644]
linux/proxguiqt.h [new file with mode: 0644]
linux/proxmark3.c [new file with mode: 0644]
linux/proxmark3.h [new file with mode: 0644]
linux/snooper.c [new file with mode: 0644]
linux/translate.h [new file with mode: 0644]
linux/unbind-proxmark [new file with mode: 0755]
linux/usb.c [new file with mode: 0644]
linux/windows.h [new file with mode: 0644]
winsrc/Makefile [new file with mode: 0644]
winsrc/command.cpp [new file with mode: 0644]
winsrc/gui.cpp [new file with mode: 0644]
winsrc/include/hidpi.h [new file with mode: 0644]
winsrc/include/hidsdi.h [new file with mode: 0644]
winsrc/include/hidusage.h [new file with mode: 0644]
winsrc/prox.cpp [new file with mode: 0644]
winsrc/prox.h [new file with mode: 0644]
winsrc/vc90.pdb [new file with mode: 0644]

diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644 (file)
index 0000000..8094a4a
--- /dev/null
@@ -0,0 +1,281 @@
+\r
+                   GNU GENERAL PUBLIC LICENSE\r
+                      Version 2, June 1991\r
+\r
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\r
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+ Everyone is permitted to copy and distribute verbatim copies\r
+ of this license document, but changing it is not allowed.\r
+\r
+                           Preamble\r
+\r
+  The licenses for most software are designed to take away your\r
+freedom to share and change it.  By contrast, the GNU General Public\r
+License is intended to guarantee your freedom to share and change free\r
+software--to make sure the software is free for all its users.  This\r
+General Public License applies to most of the Free Software\r
+Foundation's software and to any other program whose authors commit to\r
+using it.  (Some other Free Software Foundation software is covered by\r
+the GNU Lesser General Public License instead.)  You can apply it to\r
+your programs, too.\r
+\r
+  When we speak of free software, we are referring to freedom, not\r
+price.  Our General Public Licenses are designed to make sure that you\r
+have the freedom to distribute copies of free software (and charge for\r
+this service if you wish), that you receive source code or can get it\r
+if you want it, that you can change the software or use pieces of it\r
+in new free programs; and that you know you can do these things.\r
+\r
+  To protect your rights, we need to make restrictions that forbid\r
+anyone to deny you these rights or to ask you to surrender the rights.\r
+These restrictions translate to certain responsibilities for you if you\r
+distribute copies of the software, or if you modify it.\r
+\r
+  For example, if you distribute copies of such a program, whether\r
+gratis or for a fee, you must give the recipients all the rights that\r
+you have.  You must make sure that they, too, receive or can get the\r
+source code.  And you must show them these terms so they know their\r
+rights.\r
+\r
+  We protect your rights with two steps: (1) copyright the software, and\r
+(2) offer you this license which gives you legal permission to copy,\r
+distribute and/or modify the software.\r
+\r
+  Also, for each author's protection and ours, we want to make certain\r
+that everyone understands that there is no warranty for this free\r
+software.  If the software is modified by someone else and passed on, we\r
+want its recipients to know that what they have is not the original, so\r
+that any problems introduced by others will not reflect on the original\r
+authors' reputations.\r
+\r
+  Finally, any free program is threatened constantly by software\r
+patents.  We wish to avoid the danger that redistributors of a free\r
+program will individually obtain patent licenses, in effect making the\r
+program proprietary.  To prevent this, we have made it clear that any\r
+patent must be licensed for everyone's free use or not licensed at all.\r
+\r
+  The precise terms and conditions for copying, distribution and\r
+modification follow.\r
+\r
+                   GNU GENERAL PUBLIC LICENSE\r
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\r
+\r
+  0. This License applies to any program or other work which contains\r
+a notice placed by the copyright holder saying it may be distributed\r
+under the terms of this General Public License.  The "Program", below,\r
+refers to any such program or work, and a "work based on the Program"\r
+means either the Program or any derivative work under copyright law:\r
+that is to say, a work containing the Program or a portion of it,\r
+either verbatim or with modifications and/or translated into another\r
+language.  (Hereinafter, translation is included without limitation in\r
+the term "modification".)  Each licensee is addressed as "you".\r
+\r
+Activities other than copying, distribution and modification are not\r
+covered by this License; they are outside its scope.  The act of\r
+running the Program is not restricted, and the output from the Program\r
+is covered only if its contents constitute a work based on the\r
+Program (independent of having been made by running the Program).\r
+Whether that is true depends on what the Program does.\r
+\r
+  1. You may copy and distribute verbatim copies of the Program's\r
+source code as you receive it, in any medium, provided that you\r
+conspicuously and appropriately publish on each copy an appropriate\r
+copyright notice and disclaimer of warranty; keep intact all the\r
+notices that refer to this License and to the absence of any warranty;\r
+and give any other recipients of the Program a copy of this License\r
+along with the Program.\r
+\r
+You may charge a fee for the physical act of transferring a copy, and\r
+you may at your option offer warranty protection in exchange for a fee.\r
+\r
+  2. You may modify your copy or copies of the Program or any portion\r
+of it, thus forming a work based on the Program, and copy and\r
+distribute such modifications or work under the terms of Section 1\r
+above, provided that you also meet all of these conditions:\r
+\r
+    a) You must cause the modified files to carry prominent notices\r
+    stating that you changed the files and the date of any change.\r
+\r
+    b) You must cause any work that you distribute or publish, that in\r
+    whole or in part contains or is derived from the Program or any\r
+    part thereof, to be licensed as a whole at no charge to all third\r
+    parties under the terms of this License.\r
+\r
+    c) If the modified program normally reads commands interactively\r
+    when run, you must cause it, when started running for such\r
+    interactive use in the most ordinary way, to print or display an\r
+    announcement including an appropriate copyright notice and a\r
+    notice that there is no warranty (or else, saying that you provide\r
+    a warranty) and that users may redistribute the program under\r
+    these conditions, and telling the user how to view a copy of this\r
+    License.  (Exception: if the Program itself is interactive but\r
+    does not normally print such an announcement, your work based on\r
+    the Program is not required to print an announcement.)\r
+\r
+These requirements apply to the modified work as a whole.  If\r
+identifiable sections of that work are not derived from the Program,\r
+and can be reasonably considered independent and separate works in\r
+themselves, then this License, and its terms, do not apply to those\r
+sections when you distribute them as separate works.  But when you\r
+distribute the same sections as part of a whole which is a work based\r
+on the Program, the distribution of the whole must be on the terms of\r
+this License, whose permissions for other licensees extend to the\r
+entire whole, and thus to each and every part regardless of who wrote it.\r
+\r
+Thus, it is not the intent of this section to claim rights or contest\r
+your rights to work written entirely by you; rather, the intent is to\r
+exercise the right to control the distribution of derivative or\r
+collective works based on the Program.\r
+\r
+In addition, mere aggregation of another work not based on the Program\r
+with the Program (or with a work based on the Program) on a volume of\r
+a storage or distribution medium does not bring the other work under\r
+the scope of this License.\r
+\r
+  3. You may copy and distribute the Program (or a work based on it,\r
+under Section 2) in object code or executable form under the terms of\r
+Sections 1 and 2 above provided that you also do one of the following:\r
+\r
+    a) Accompany it with the complete corresponding machine-readable\r
+    source code, which must be distributed under the terms of Sections\r
+    1 and 2 above on a medium customarily used for software interchange; or,\r
+\r
+    b) Accompany it with a written offer, valid for at least three\r
+    years, to give any third party, for a charge no more than your\r
+    cost of physically performing source distribution, a complete\r
+    machine-readable copy of the corresponding source code, to be\r
+    distributed under the terms of Sections 1 and 2 above on a medium\r
+    customarily used for software interchange; or,\r
+\r
+    c) Accompany it with the information you received as to the offer\r
+    to distribute corresponding source code.  (This alternative is\r
+    allowed only for noncommercial distribution and only if you\r
+    received the program in object code or executable form with such\r
+    an offer, in accord with Subsection b above.)\r
+\r
+The source code for a work means the preferred form of the work for\r
+making modifications to it.  For an executable work, complete source\r
+code means all the source code for all modules it contains, plus any\r
+associated interface definition files, plus the scripts used to\r
+control compilation and installation of the executable.  However, as a\r
+special exception, the source code distributed need not include\r
+anything that is normally distributed (in either source or binary\r
+form) with the major components (compiler, kernel, and so on) of the\r
+operating system on which the executable runs, unless that component\r
+itself accompanies the executable.\r
+\r
+If distribution of executable or object code is made by offering\r
+access to copy from a designated place, then offering equivalent\r
+access to copy the source code from the same place counts as\r
+distribution of the source code, even though third parties are not\r
+compelled to copy the source along with the object code.\r
+\r
+  4. You may not copy, modify, sublicense, or distribute the Program\r
+except as expressly provided under this License.  Any attempt\r
+otherwise to copy, modify, sublicense or distribute the Program is\r
+void, and will automatically terminate your rights under this License.\r
+However, parties who have received copies, or rights, from you under\r
+this License will not have their licenses terminated so long as such\r
+parties remain in full compliance.\r
+\r
+  5. You are not required to accept this License, since you have not\r
+signed it.  However, nothing else grants you permission to modify or\r
+distribute the Program or its derivative works.  These actions are\r
+prohibited by law if you do not accept this License.  Therefore, by\r
+modifying or distributing the Program (or any work based on the\r
+Program), you indicate your acceptance of this License to do so, and\r
+all its terms and conditions for copying, distributing or modifying\r
+the Program or works based on it.\r
+\r
+  6. Each time you redistribute the Program (or any work based on the\r
+Program), the recipient automatically receives a license from the\r
+original licensor to copy, distribute or modify the Program subject to\r
+these terms and conditions.  You may not impose any further\r
+restrictions on the recipients' exercise of the rights granted herein.\r
+You are not responsible for enforcing compliance by third parties to\r
+this License.\r
+\r
+  7. If, as a consequence of a court judgment or allegation of patent\r
+infringement or for any other reason (not limited to patent issues),\r
+conditions are imposed on you (whether by court order, agreement or\r
+otherwise) that contradict the conditions of this License, they do not\r
+excuse you from the conditions of this License.  If you cannot\r
+distribute so as to satisfy simultaneously your obligations under this\r
+License and any other pertinent obligations, then as a consequence you\r
+may not distribute the Program at all.  For example, if a patent\r
+license would not permit royalty-free redistribution of the Program by\r
+all those who receive copies directly or indirectly through you, then\r
+the only way you could satisfy both it and this License would be to\r
+refrain entirely from distribution of the Program.\r
+\r
+If any portion of this section is held invalid or unenforceable under\r
+any particular circumstance, the balance of the section is intended to\r
+apply and the section as a whole is intended to apply in other\r
+circumstances.\r
+\r
+It is not the purpose of this section to induce you to infringe any\r
+patents or other property right claims or to contest validity of any\r
+such claims; this section has the sole purpose of protecting the\r
+integrity of the free software distribution system, which is\r
+implemented by public license practices.  Many people have made\r
+generous contributions to the wide range of software distributed\r
+through that system in reliance on consistent application of that\r
+system; it is up to the author/donor to decide if he or she is willing\r
+to distribute software through any other system and a licensee cannot\r
+impose that choice.\r
+\r
+This section is intended to make thoroughly clear what is believed to\r
+be a consequence of the rest of this License.\r
+\r
+  8. If the distribution and/or use of the Program is restricted in\r
+certain countries either by patents or by copyrighted interfaces, the\r
+original copyright holder who places the Program under this License\r
+may add an explicit geographical distribution limitation excluding\r
+those countries, so that distribution is permitted only in or among\r
+countries not thus excluded.  In such case, this License incorporates\r
+the limitation as if written in the body of this License.\r
+\r
+  9. The Free Software Foundation may publish revised and/or new versions\r
+of the General Public License from time to time.  Such new versions will\r
+be similar in spirit to the present version, but may differ in detail to\r
+address new problems or concerns.\r
+\r
+Each version is given a distinguishing version number.  If the Program\r
+specifies a version number of this License which applies to it and "any\r
+later version", you have the option of following the terms and conditions\r
+either of that version or of any later version published by the Free\r
+Software Foundation.  If the Program does not specify a version number of\r
+this License, you may choose any version ever published by the Free Software\r
+Foundation.\r
+\r
+  10. If you wish to incorporate parts of the Program into other free\r
+programs whose distribution conditions are different, write to the author\r
+to ask for permission.  For software which is copyrighted by the Free\r
+Software Foundation, write to the Free Software Foundation; we sometimes\r
+make exceptions for this.  Our decision will be guided by the two goals\r
+of preserving the free status of all derivatives of our free software and\r
+of promoting the sharing and reuse of software generally.\r
+\r
+                           NO WARRANTY\r
+\r
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\r
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\r
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\r
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\r
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\r
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\r
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\r
+REPAIR OR CORRECTION.\r
+\r
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\r
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\r
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\r
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\r
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\r
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\r
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\r
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\r
+POSSIBILITY OF SUCH DAMAGES.\r
+\r
+                    END OF TERMS AND CONDITIONS\r
diff --git a/LOG.txt b/LOG.txt
new file mode 100644 (file)
index 0000000..43d215c
--- /dev/null
+++ b/LOG.txt
@@ -0,0 +1,3 @@
+\r
+MAY 2008:      Added ISO14443 type A support, Gerhard de Koning Gans\r
+\r
diff --git a/README-gj.txt b/README-gj.txt
new file mode 100644 (file)
index 0000000..9ce2798
--- /dev/null
@@ -0,0 +1,28 @@
+Modifications to 20081211 release by d18c7db on proxmark.org\r
+\r
+This compiles fine under the pre-built windows compile environment ProxSpace\r
+\r
+I make no apologies for the utterly cr@p coding. It's rubbish, you've been warned.\r
+\r
+Changes made to armsrc and winsrc, no changed to fpga code. Works fine with the bootloader and fpga images that you will build using the 20081211 release.\r
+\r
+\r
+Extra functionality includes:\r
+\r
+ISO1443a support\r
+================\r
+\r
+i) Support for cascade 2 select (used for UID's longer than 4 bytes)\r
+ii) Hard-coded (some) responses in for DESfire \r
+\r
+\r
+ISO15563 support\r
+================\r
+\r
+i) demodulation all moved onto the arm\r
+ii) Addition of a command, hi15reader (a reader simulator)\r
+iii) Addition of a command, hi15sim (a tag simulator) - not working too well\r
+\r
+\r
+\r
+greg.jones@digitalassurance.com
\ No newline at end of file
diff --git a/README.txt b/README.txt
new file mode 100644 (file)
index 0000000..541365c
--- /dev/null
@@ -0,0 +1,156 @@
+INTRO:\r
+\r
+This file contains enough software, logic (for the FPGA), and design\r
+documentation for the hardware that you could, at least in theory,\r
+do something useful with a proxmark3. It has commands to:\r
+\r
+    * read any kind of 125 kHz unidirectional tag\r
+    * simulate any kind of 125 kHz unidirectional tag\r
+\r
+(This is enough to perform all of the silly cloning attacks, like the\r
+ones that I did at the Capitol in Sacramento, or anything involving\r
+a Verichip. From a technical standpoint, these are not that exciting,\r
+although the `software radio' architecture of the proxmark3 makes it\r
+easy and fun to support new formats.)\r
+\r
+As a bonus, I include some code to use the 13.56 MHz hardware, so you can:\r
+\r
+    * do anything that a (medium-range) ISO 15693 reader could\r
+    * read an ISO 14443 tag, if you know the higher-layer protocol\r
+    * pretend to be an ISO 14443 tag, if you know the higher-layer protocol\r
+    * snoop on an ISO 14443 transaction\r
+\r
+I am not actively developing any of this. I have other projects that\r
+seem to be more useful.\r
+\r
+USING THE PACKAGE:\r
+\r
+The software tools required to build include:\r
+\r
+    * cygwin or other unix-like tools for Windows\r
+    * the Microsoft Visual C++ compiler (I use Version 6)\r
+    * arm-elf-gcc; I use WinterMute's build, from http://www.devkitpro.org/\r
+    * Xilinx's WebPack tools\r
+    * Modelsim (for test only)\r
+    * perl\r
+\r
+It is not necessary to build the FPGA image yourself; a pre-compiled\r
+image is provided, as armsrc/fpgaimg.c. This is a generated file,\r
+though, and you can rebuild it by running fpga/go.bat.\r
+\r
+Documentation is minimal, but see the doc/ directory for what exists. A\r
+previous familiarity with the ARM, with digital signal processing,\r
+and with embedded programming in general is assumed.\r
+\r
+The device is used through a specialized command line interface; for\r
+example, to clone a Verichip, you might type:\r
+\r
+    loread                          ; this reads the tag, and stores the\r
+                                    ; raw samples in memory on the ARM\r
+\r
+    losamples                       ; then we download the samples to\r
+                                    ; the PC\r
+\r
+    vchdemod clone                  ; demodulate the ID, and then put it\r
+                                    ; back in a format that we can replay\r
+\r
+    losim                           ; and then replay it\r
+\r
+To read an ISO 15693 tag, you might type:\r
+\r
+    hiread                          ; read the tag; this involves sending a\r
+                                    ; particular command, and then getting\r
+                                    ; the response (which is stored as raw\r
+                                    ; samples in memory on the ARM)\r
+\r
+    hisamples                       ; then download those samples to the PC\r
+\r
+    hi15demod                       ; and demod them to bits (and check the\r
+                                    ; CRC etc. at the same time)\r
+\r
+Notice that in both cases the signal processing mostly happened on the PC\r
+side; that is of course not practical for a real reader, but it is easier\r
+to initially write your code and debug on the PC side than on the ARM. As\r
+long as you use integer math (and I do), it's trivial to port it over\r
+when you're done.\r
+\r
+The USB driver and bootloader are documented (and available separately\r
+for download, if you wish to use them in another project) at\r
+\r
+    http://cq.cx/trivia.pl\r
+\r
+\r
+OBTAINING HARDWARE:\r
+\r
+Most of the ultra-low-volume contract assemblers that have sprung up\r
+(Screaming Circuits, the various cheap Asian suppliers, etc.) could put\r
+something like this together with a reasonable yield. A run of around\r
+a dozen units is probably cost-effective. The BOM includes (possibly-\r
+outdated) component pricing, and everything is available from Digikey\r
+and the usual distributors.\r
+\r
+If you've never assembled a modern circuit board by hand, then this is\r
+not a good place to start. Some of the components (e.g. the crystals)\r
+must not be assembled with a soldering iron, and require hot air.\r
+\r
+The schematics are included; the component values given are not\r
+necessarily correct for all situations, but it should be possible to do\r
+nearly anything you would want with appropriate population options.\r
+\r
+The printed circuit board artwork is also available, as Gerbers and an\r
+Excellon drill file.\r
+\r
+\r
+FUTURE PLANS, ENHANCEMENTS THAT YOU COULD MAKE:\r
+\r
+At some point I should write software involving a proper real-time\r
+operating system for the ARM. I would then provide interrupt-driven\r
+drivers for many of the peripherals that are polled now (the USB,\r
+the data stream from the FPGA), which would make it easier to develop\r
+complex applications.\r
+\r
+It would not be all that hard to implement the ISO 15693 reader properly\r
+(with anticollision, all the commands supported, and so on)--the signal\r
+processing is already written, so it is all straightforward applications\r
+work.\r
+\r
+I have basic support for ISO 14443 as well: a sniffer, a simulated\r
+tag, and a reader. It won't do anything useful unless you fill in the\r
+high-layer protocol.\r
+\r
+Nicer (i.e., closer-to-optimal) implementations of all kinds of signal\r
+processing would be useful as well.\r
+\r
+A practical implementation of the learning-the-tag's-ID-from-what-the-\r
+reader-broadcasts-during-anticollision attacks would be relatively\r
+straightforward. This would involve some signal processing on the FPGA,\r
+but not much else after that.\r
+\r
+It would be neat to write a driver that could stream samples from the A/Ds\r
+over USB to the PC, using the full available bandwidth of USB. I am not\r
+yet sure what that would be good for, but surely something. This would\r
+require a kernel-mode driver under Windows, though, which is more work.\r
+\r
+\r
+LICENSING:\r
+\r
+This program is free software; you can redistribute it and/or modify\r
+it under the terms of the GNU General Public License as published by\r
+the Free Software Foundation; either version 2 of the License, or\r
+(at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
+\r
+\r
+Jonathan Westhues\r
+user jwesthues, at host cq.cx\r
+\r
+May 2007, Cambridge MA\r
+\r
diff --git a/armsrc/LCD.c b/armsrc/LCD.c
new file mode 100644 (file)
index 0000000..02c2f69
--- /dev/null
@@ -0,0 +1,123 @@
+#include <proxmark3.h>\r
+#include "apps.h"\r
+#include "LCD.h"\r
+\r
+void LCDSend(unsigned int data)\r
+{\r
+       // 9th bit set for data, clear for command\r
+       while ((SPI_STATUS & SPI_STATUS_TX_EMPTY) == 0);        // wait for the transfer to complete\r
+       // For clarity's sake we pass data with 9th bit clear and commands with 9th\r
+       // bit set since they're implemented as defines, se we need to invert bit\r
+       SPI_TX_DATA = data^0x100;                                                       // Send the data/command\r
+}\r
+\r
+void LCDSetXY(unsigned char x, unsigned char y)\r
+{\r
+       LCDSend(PPASET);                        // page start/end ram\r
+       LCDSend(y);                                     // Start Page to display to\r
+       LCDSend(131);                           // End Page to display to\r
+\r
+       LCDSend(PCASET);                        // column start/end ram\r
+       LCDSend(x);                                     // Start Column to display to\r
+       LCDSend(131);                           // End Column to display to\r
+}\r
+\r
+void LCDSetPixel(unsigned char x, unsigned char y, unsigned char color)\r
+{\r
+       LCDSetXY(x,y);                          // Set position\r
+       LCDSend(PRAMWR);                        // Now write the pixel to the display\r
+       LCDSend(color);                         // Write the data in the specified Color\r
+}\r
+\r
+void LCDFill (unsigned char xs,unsigned char ys,unsigned char width,unsigned char height, unsigned char color)\r
+{\r
+    unsigned char i,j;\r
+\r
+    for (i=0;i < height;i++)   // Number of horizontal lines\r
+    {\r
+               LCDSetXY(xs,ys+i);              // Goto start of fill area (Top Left)\r
+               LCDSend(PRAMWR);                // Write to display\r
+\r
+               for (j=0;j < width;j++) // pixels per line\r
+                       LCDSend(color);\r
+    }\r
+}\r
+\r
+void LCDString (char *lcd_string, const char *font_style,unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor)\r
+{\r
+       unsigned int  i;\r
+       unsigned char mask=0, px, py, xme, yme, offset;\r
+       const char *data;\r
+\r
+       data = font_style;                      // point to the start of the font table\r
+\r
+       xme = *data;                            // get font x width\r
+       data++;\r
+       yme = *data;                            // get font y length\r
+       data++;\r
+       offset = *data;                         // get data bytes per font\r
+\r
+       do\r
+       {\r
+               // point to data in table to be loaded\r
+               data =  (font_style + offset) + (offset * (int)(*lcd_string - 32));\r
+\r
+               for (i=0;i < yme;i++) {\r
+                       mask |=0x80;\r
+\r
+                       for (px=x; px < (x + xme); px++) {\r
+                               py= y + i;\r
+\r
+                               if (*data & mask)       LCDSetPixel (px,py,fcolor);\r
+                               else                            LCDSetPixel (px,py,bcolor);\r
+\r
+                               mask>>=1;\r
+                       }\r
+                       data++;\r
+               }\r
+               x+=xme;\r
+\r
+               lcd_string++;                                           // next character in string\r
+\r
+       } while(*lcd_string !='\0');                    // keep spitting chars out until end of string\r
+}\r
+\r
+void LCDReset(void)\r
+{\r
+       LED_A_ON();\r
+       SetupSpi(SPI_LCD_MODE);\r
+       LCD_RESET_LOW();\r
+       SpinDelay(100);\r
+\r
+       LCD_RESET_HIGH();\r
+       SpinDelay(100);\r
+       LED_A_OFF();\r
+}\r
+\r
+void LCDInit(void)\r
+{\r
+       int i;\r
+\r
+       LCDReset();\r
+\r
+       LCDSend(PSWRESET);                      // software reset\r
+       SpinDelay(100);\r
+       LCDSend(PSLEEPOUT);                     // exit sleep mode\r
+       LCDSend(PBSTRON);                       // booster on\r
+       LCDSend(PDISPON);                       // display on\r
+       LCDSend(PNORON);                        // normal on\r
+       LCDSend(PMADCTL);                       // rotate display 180 deg\r
+       LCDSend(0xC0);\r
+\r
+       LCDSend(PCOLMOD);                       // color mode\r
+       LCDSend(0x02);                          // 8bpp color mode\r
+\r
+    LCDSend(PSETCON);                  // set contrast\r
+    LCDSend(0xDC);\r
+    \r
+       // clear display\r
+    LCDSetXY(0,0);\r
+       LCDSend(PRAMWR);                        // Write to display\r
+       i=LCD_XRES*LCD_YRES;\r
+       while(i--) LCDSend(WHITE);\r
+}\r
diff --git a/armsrc/LCD.h b/armsrc/LCD.h
new file mode 100644 (file)
index 0000000..27971eb
--- /dev/null
@@ -0,0 +1,120 @@
+#ifndef __LCD\r
+#define __LCD\r
+\r
+#define LCD_RESET_HIGH()       PIO_OUTPUT_DATA_SET   |= (1<<GPIO_LRST)\r
+#define LCD_RESET_LOW()                PIO_OUTPUT_DATA_CLEAR |= (1<<GPIO_LRST)\r
+\r
+// The resolution of the LCD\r
+#define LCD_XRES       132\r
+#define LCD_YRES       132\r
+\r
+// 8bpp Color Mode - Some basic colors defined for ease of use\r
+// remember 8bpp color = 3xRed, 3xGreen & 2xBlue bits\r
+// organised as RRRGGGBB\r
+\r
+#define BLACK          0x00\r
+#define BLUE           0x03\r
+#define GREEN          0x1C\r
+#define CYAN           0x1F\r
+#define RED                    0xE0\r
+#define MAGENTA                0xE3\r
+#define YELLOW         0xFC\r
+#define WHITE          0xFF\r
+\r
+// EPSON LCD command set\r
+#define ECASET         0x115\r
+#define EPWRCTR                0x120\r
+#define ENOP           0x125\r
+#define ERAMWR         0x15C\r
+#define ERAMRD         0x15D\r
+#define EPASET         0x175\r
+#define EEPSRRD1       0x17C\r
+#define EEPSRRD2       0x17D\r
+#define EVOLCTR                0x181\r
+#define ETMPGRD                0x182\r
+#define ESLPOUT                0x194\r
+#define ESLPIN         0x195\r
+#define EDISNOR                0x1A6\r
+#define EDISINV                0x1A7\r
+#define EPTLIN         0x1A8\r
+#define EPTLOUT                0x1A9\r
+#define EASCSET                0x1AA\r
+#define ESCSTART       0x1AB\r
+#define EDISOFF                0x1AE\r
+#define EDISON         0x1AF\r
+#define ECOMSCN                0x1BB\r
+#define EDATCTL                0x1BC\r
+#define EDISCTL                0x1CA\r
+#define EEPCOUT                0x1CC\r
+#define EEPCTIN                0x1CD\r
+#define ERGBSET8       0x1CE\r
+#define EOSCON         0x1D1\r
+#define EOSCOFF                0x1D2\r
+#define EVOLUP         0x1D6\r
+#define EVOLDOWN       0x1D7\r
+#define ERMWIN         0x1E0\r
+#define ERMWOUT                0x1EE\r
+#define EEPMWR         0x1FC\r
+#define EEPMRD         0x1FD\r
+\r
+// PHILIPS LCD command set\r
+#define PNOP           0x100\r
+#define PSWRESET       0x101\r
+#define PBSTROFF       0x102\r
+#define PBSTRON                0x103\r
+#define PRDDIDIF       0x104\r
+#define PRDDST         0x109\r
+#define PSLEEPIN       0x110\r
+#define PSLEEPOUT      0x111\r
+#define PPTLON         0x112\r
+#define PNORON         0x113\r
+#define PINVOFF                0x120\r
+#define PINVON         0x121\r
+#define PDALO          0x122\r
+#define PDAL           0x123\r
+#define PSETCON                0x125\r
+#define PDISPOFF       0x128\r
+#define PDISPON                0x129\r
+#define PCASET         0x12A\r
+#define PPASET         0x12B\r
+#define PRAMWR         0x12C\r
+#define PRGBSET                0x12D\r
+#define PPTLAR         0x130\r
+#define PVSCRDEF       0x133\r
+#define PTEOFF         0x134\r
+#define PTEON          0x135\r
+#define PMADCTL                0x136\r
+#define PSEP           0x137\r
+#define PIDMOFF                0x138\r
+#define PIDMON         0x139\r
+#define PCOLMOD                0x13A\r
+#define PSETVOP                0x1B0\r
+#define PBRS           0x1B4\r
+#define PTRS           0x1B6\r
+#define PFINV          0x1B9\r
+#define PDOR           0x1BA\r
+#define PTCDFE         0x1BD\r
+#define PTCVOPE                0x1BF\r
+#define PEC                    0x1C0\r
+#define PSETMUL                0x1C2\r
+#define PTCVOPAB       0x1C3\r
+#define PTCVOPCD       0x1C4\r
+#define PTCDF          0x1C5\r
+#define PDF8C          0x1C6\r
+#define PSETBS         0x1C7\r
+#define PRDTEMP                0x1C8\r
+#define PNLI           0x1C9\r
+#define PRDID1         0x1DA\r
+#define PRDID2         0x1DB\r
+#define PRDID3         0x1DC\r
+#define PSFD           0x1EF\r
+#define PECM           0x1F0\r
+\r
+void LCDSend(unsigned int data);\r
+void LCDInit(void);\r
+void LCDReset(void);\r
+void LCDSetXY(unsigned char x, unsigned char y);\r
+void LCDSetPixel(unsigned char x, unsigned char y, unsigned char color);\r
+void LCDString (char *lcd_string, const char *font_style,unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor);\r
+void LCDFill (unsigned char xs,unsigned char ys,unsigned char width,unsigned char height, unsigned char color);\r
+#endif\r
diff --git a/armsrc/Makefile b/armsrc/Makefile
new file mode 100644 (file)
index 0000000..e8db3b3
--- /dev/null
@@ -0,0 +1,61 @@
+CC     = arm-elf-gcc\r
+AS     = arm-elf-as\r
+LD     = arm-elf-ld\r
+OBJCOPY = arm-elf-objcopy\r
+\r
+OBJDIR = obj\r
+\r
+INCLUDE = -I../include\r
+\r
+INCLUDES = ../include/proxmark3.h ../include/at91sam7s128.h ../include/config_gpio.h ../include/usb_cmd.h apps.h\r
+LIB = "..\..\devkitARM\lib\gcc\arm-elf\4.1.0\interwork"\r
+\r
+CFLAGS = -O6 -c $(INCLUDE) -Wall\r
+\r
+OBJ =  $(OBJDIR)/start.o \\r
+               $(OBJDIR)/appmain.o \\r
+               $(OBJDIR)/fpga.o \\r
+               $(OBJDIR)/iso14443.o \\r
+               $(OBJDIR)/iso14443a.o \\r
+               $(OBJDIR)/iso15693.o \\r
+               $(OBJDIR)/util.o \\r
+               $(OBJDIR)/fonts.o \\r
+               $(OBJDIR)/LCD.o\r
+\r
+OBJFPGA = \\r
+               $(OBJDIR)/fpgaimg.o\r
+\r
+OBJCOMMON = \\r
+               $(OBJDIR)/usb.o\r
+\r
+all: osimage.s19\r
+\r
+$(OBJDIR)/fpgaimage.s19: $(OBJDIR)/fpgaimg.o\r
+       @echo obj/fpgaimage.s19\r
+       @$(LD) -g -Tldscript-fpga -o $(OBJDIR)\fpgaimage.elf $(OBJDIR)/fpgaimg.o\r
+       @$(OBJCOPY) -Osrec --srec-forceS3 $(OBJDIR)\fpgaimage.elf $(OBJDIR)\fpgaimage.s19\r
+\r
+$(OBJDIR)/osimage.s19: $(OBJ) $(OBJCOMMON)\r
+       @echo obj/osimage.s19\r
+       @$(LD) -g -Tldscript -o $(OBJDIR)\osimage.elf $(OBJ) $(OBJCOMMON) $(LIB)\libgcc.a\r
+       @$(OBJCOPY) -Osrec --srec-forceS3 $(OBJDIR)\osimage.elf $(OBJDIR)\osimage.s19\r
+\r
+osimage.s19: $(OBJDIR)/osimage.s19 $(OBJDIR)/fpgaimage.s19\r
+       @echo osimage.s19\r
+\r
+$(OBJ): $(@B).c $(INCLUDES)\r
+       @echo $(@B).c\r
+       @$(CC) $(CFLAGS) -mthumb -mthumb-interwork $(@B).c -o $(OBJDIR)/$(@B).o\r
+\r
+$(OBJCOMMON): ../common/$(@B).c $(INCLUDES)\r
+       @echo $(@B).c\r
+       @$(CC) $(CFLAGS) -mthumb -mthumb-interwork ../common/$(@B).c -o $(OBJDIR)/$(@B).o\r
+\r
+$(OBJFPGA): $(@B).c $(INCLUDES)\r
+       @echo $(@B).c\r
+       @$(CC) $(CFLAGS) -mthumb -mthumb-interwork $(@B).c -o $(OBJDIR)/$(@B).o\r
+\r
+clean:\r
+       del /q obj\*.o\r
+       del /q obj\*.elf\r
+       del /q obj\*.s19\r
diff --git a/armsrc/appmain.c b/armsrc/appmain.c
new file mode 100644 (file)
index 0000000..3031275
--- /dev/null
@@ -0,0 +1,757 @@
+//-----------------------------------------------------------------------------\r
+// The main application code. This is the first thing called after start.c\r
+// executes.\r
+// Jonathan Westhues, Mar 2006\r
+// Edits by Gerhard de Koning Gans, Sep 2007 (##)\r
+//-----------------------------------------------------------------------------\r
+#include <proxmark3.h>\r
+#include "apps.h"\r
+#include "fonts.h"\r
+#include "LCD.h"\r
+\r
+// The large multi-purpose buffer, typically used to hold A/D samples,\r
+// maybe pre-processed in some way.\r
+DWORD BigBuf[16000];\r
+\r
+//=============================================================================\r
+// A buffer where we can queue things up to be sent through the FPGA, for\r
+// any purpose (fake tag, as reader, whatever). We go MSB first, since that\r
+// is the order in which they go out on the wire.\r
+//=============================================================================\r
+\r
+BYTE ToSend[256];\r
+int ToSendMax;\r
+static int ToSendBit;\r
+\r
+void ToSendReset(void)\r
+{\r
+       ToSendMax = -1;\r
+       ToSendBit = 8;\r
+}\r
+\r
+void ToSendStuffBit(int b)\r
+{\r
+       if(ToSendBit >= 8) {\r
+               ToSendMax++;\r
+               ToSend[ToSendMax] = 0;\r
+               ToSendBit = 0;\r
+       }\r
+\r
+       if(b) {\r
+               ToSend[ToSendMax] |= (1 << (7 - ToSendBit));\r
+       }\r
+\r
+       ToSendBit++;\r
+\r
+       if(ToSendBit >= sizeof(ToSend)) {\r
+               ToSendBit = 0;\r
+               DbpString("ToSendStuffBit overflowed!");\r
+       }\r
+}\r
+\r
+//=============================================================================\r
+// Debug print functions, to go out over USB, to the usual PC-side client.\r
+//=============================================================================\r
+\r
+void DbpString(char *str)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_DEBUG_PRINT_STRING;\r
+       c.ext1 = strlen(str);\r
+       memcpy(c.d.asBytes, str, c.ext1);\r
+\r
+       UsbSendPacket((BYTE *)&c, sizeof(c));\r
+       // TODO fix USB so stupid things like this aren't req'd\r
+       SpinDelay(50);\r
+}\r
+\r
+void DbpIntegers(int x1, int x2, int x3)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_DEBUG_PRINT_INTEGERS;\r
+       c.ext1 = x1;\r
+       c.ext2 = x2;\r
+       c.ext3 = x3;\r
+\r
+       UsbSendPacket((BYTE *)&c, sizeof(c));\r
+       // XXX\r
+       SpinDelay(50);\r
+}\r
+\r
+void AcquireRawAdcSamples125k(BOOL at134khz)\r
+{\r
+       BYTE *dest = (BYTE *)BigBuf;\r
+       int n = sizeof(BigBuf);\r
+       int i;\r
+\r
+       memset(dest,0,n);\r
+\r
+       if(at134khz) {\r
+               FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_134_KHZ);\r
+       } else {\r
+               FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_125_KHZ);\r
+       }\r
+\r
+       // Connect the A/D to the peak-detected low-frequency path.\r
+       SetAdcMuxFor(GPIO_MUXSEL_LOPKD);\r
+\r
+       // Give it a bit of time for the resonant antenna to settle.\r
+       SpinDelay(50);\r
+\r
+       // Now set up the SSC to get the ADC samples that are now streaming at us.\r
+       FpgaSetupSsc();\r
+\r
+       i = 0;\r
+       for(;;) {\r
+               if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+                       SSC_TRANSMIT_HOLDING = 0x43;\r
+                       LED_D_ON();\r
+               }\r
+               if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+                       dest[i] = (BYTE)SSC_RECEIVE_HOLDING;\r
+                       i++;\r
+                       LED_D_OFF();\r
+                       if(i >= n) {\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+       DbpIntegers(dest[0], dest[1], at134khz);\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Read an ADC channel and block till it completes, then return the result\r
+// in ADC units (0 to 1023). Also a routine to average sixteen samples and\r
+// return that.\r
+//-----------------------------------------------------------------------------\r
+static int ReadAdc(int ch)\r
+{\r
+       DWORD d;\r
+\r
+       ADC_CONTROL = ADC_CONTROL_RESET;\r
+       ADC_MODE = ADC_MODE_PRESCALE(32) | ADC_MODE_STARTUP_TIME(16) |\r
+               ADC_MODE_SAMPLE_HOLD_TIME(8);\r
+       ADC_CHANNEL_ENABLE = ADC_CHANNEL(ch);\r
+\r
+       ADC_CONTROL = ADC_CONTROL_START;\r
+       while(!(ADC_STATUS & ADC_END_OF_CONVERSION(ch)))\r
+               ;\r
+       d = ADC_CHANNEL_DATA(ch);\r
+\r
+       return d;\r
+}\r
+\r
+static int AvgAdc(int ch)\r
+{\r
+       int i;\r
+       int a = 0;\r
+\r
+       for(i = 0; i < 32; i++) {\r
+               a += ReadAdc(ch);\r
+       }\r
+\r
+       return (a + 15) >> 5;\r
+}\r
+\r
+void MeasureAntennaTuning(void)\r
+{\r
+// Impedances are Zc = 1/(j*omega*C), in ohms\r
+#define LF_TUNING_CAP_Z        1273    //  1 nF @ 125   kHz\r
+#define HF_TUNING_CAP_Z        235             // 50 pF @ 13.56 MHz\r
+\r
+       int vLf125, vLf134, vHf;        // in mV\r
+\r
+       UsbCommand c;\r
+\r
+       // Let the FPGA drive the low-frequency antenna around 125 kHz.\r
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_125_KHZ);\r
+       SpinDelay(20);\r
+       vLf125 = AvgAdc(4);\r
+       // Vref = 3.3V, and a 10000:240 voltage divider on the input\r
+       // can measure voltages up to 137500 mV\r
+       vLf125 = (137500 * vLf125) >> 10;\r
+\r
+       // Let the FPGA drive the low-frequency antenna around 134 kHz.\r
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_134_KHZ);\r
+       SpinDelay(20);\r
+       vLf134 = AvgAdc(4);\r
+       // Vref = 3.3V, and a 10000:240 voltage divider on the input\r
+       // can measure voltages up to 137500 mV\r
+       vLf134 = (137500 * vLf134) >> 10;\r
+\r
+       // Let the FPGA drive the high-frequency antenna around 13.56 MHz.\r
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
+       SpinDelay(20);\r
+       vHf = AvgAdc(5);\r
+       // Vref = 3300mV, and an 10:1 voltage divider on the input\r
+       // can measure voltages up to 33000 mV\r
+       vHf = (33000 * vHf) >> 10;\r
+\r
+       c.cmd = CMD_MEASURED_ANTENNA_TUNING;\r
+       c.ext1 = (vLf125 << 0) | (vLf134 << 16);\r
+       c.ext2 = vHf;\r
+       c.ext3 = (LF_TUNING_CAP_Z << 0) | (HF_TUNING_CAP_Z << 16);\r
+       UsbSendPacket((BYTE *)&c, sizeof(c));\r
+}\r
+\r
+void SimulateTagLowFrequency(int period)\r
+{\r
+       int i;\r
+       BYTE *tab = (BYTE *)BigBuf;\r
+\r
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_SIMULATOR);\r
+\r
+       PIO_ENABLE = (1 << GPIO_SSC_DOUT) | (1 << GPIO_SSC_CLK);\r
+\r
+       PIO_OUTPUT_ENABLE = (1 << GPIO_SSC_DOUT);\r
+       PIO_OUTPUT_DISABLE = (1 << GPIO_SSC_CLK);\r
+\r
+#define SHORT_COIL()   LOW(GPIO_SSC_DOUT)\r
+#define OPEN_COIL()            HIGH(GPIO_SSC_DOUT)\r
+\r
+       i = 0;\r
+       for(;;) {\r
+               while(!(PIO_PIN_DATA_STATUS & (1<<GPIO_SSC_CLK))) {\r
+                       if(BUTTON_PRESS()) {\r
+                               return;\r
+                       }\r
+                       WDT_HIT();\r
+               }\r
+\r
+               LED_D_ON();\r
+               if(tab[i]) {\r
+                       OPEN_COIL();\r
+               } else {\r
+                       SHORT_COIL();\r
+               }\r
+               LED_D_OFF();\r
+\r
+               while(PIO_PIN_DATA_STATUS & (1<<GPIO_SSC_CLK)) {\r
+                       if(BUTTON_PRESS()) {\r
+                               return;\r
+                       }\r
+                       WDT_HIT();\r
+               }\r
+\r
+               i++;\r
+               if(i == period) i = 0;\r
+       }\r
+}\r
+\r
+// compose fc/8 fc/10 waveform\r
+static void fc(int c, int *n) {\r
+       BYTE *dest = (BYTE *)BigBuf;\r
+       int idx;\r
+\r
+       // for when we want an fc8 pattern every 4 logical bits\r
+       if(c==0) {\r
+               dest[((*n)++)]=1;\r
+               dest[((*n)++)]=1;\r
+               dest[((*n)++)]=0;\r
+               dest[((*n)++)]=0;\r
+               dest[((*n)++)]=0;\r
+               dest[((*n)++)]=0;\r
+               dest[((*n)++)]=0;\r
+               dest[((*n)++)]=0;\r
+       }\r
+       //      an fc/8  encoded bit is a bit pattern of  11000000  x6 = 48 samples\r
+       if(c==8) {\r
+               for (idx=0; idx<6; idx++) {\r
+                       dest[((*n)++)]=1;\r
+                       dest[((*n)++)]=1;\r
+                       dest[((*n)++)]=0;\r
+                       dest[((*n)++)]=0;\r
+                       dest[((*n)++)]=0;\r
+                       dest[((*n)++)]=0;\r
+                       dest[((*n)++)]=0;\r
+                       dest[((*n)++)]=0;\r
+               }\r
+       }\r
+\r
+       //      an fc/10 encoded bit is a bit pattern of 1110000000 x5 = 50 samples\r
+       if(c==10) {\r
+               for (idx=0; idx<5; idx++) {\r
+                       dest[((*n)++)]=1;\r
+                       dest[((*n)++)]=1;\r
+                       dest[((*n)++)]=1;\r
+                       dest[((*n)++)]=0;\r
+                       dest[((*n)++)]=0;\r
+                       dest[((*n)++)]=0;\r
+                       dest[((*n)++)]=0;\r
+                       dest[((*n)++)]=0;\r
+                       dest[((*n)++)]=0;\r
+                       dest[((*n)++)]=0;\r
+               }\r
+       }\r
+}\r
+\r
+// prepare a waveform pattern in the buffer based on the ID given then\r
+// simulate a HID tag until the button is pressed\r
+static void CmdHIDsimTAG(int hi, int lo)\r
+{\r
+       int n=0, i=0;\r
+       /*\r
+        HID tag bitstream format\r
+        The tag contains a 44bit unique code. This is sent out MSB first in sets of 4 bits\r
+        A 1 bit is represented as 6 fc8 and 5 fc10 patterns\r
+        A 0 bit is represented as 5 fc10 and 6 fc8 patterns\r
+        A fc8 is inserted before every 4 bits\r
+        A special start of frame pattern is used consisting a0b0 where a and b are neither 0\r
+        nor 1 bits, they are special patterns (a = set of 12 fc8 and b = set of 10 fc10)\r
+       */\r
+\r
+       if (hi>0xFFF) {\r
+               DbpString("Tags can only have 44 bits.");\r
+               return;\r
+       }\r
+       fc(0,&n);\r
+       // special start of frame marker containing invalid bit sequences\r
+       fc(8,  &n);     fc(8,  &n);     // invalid\r
+       fc(8,  &n);     fc(10, &n); // logical 0\r
+       fc(10, &n);     fc(10, &n); // invalid\r
+       fc(8,  &n);     fc(10, &n); // logical 0\r
+\r
+       WDT_HIT();\r
+       // manchester encode bits 43 to 32\r
+       for (i=11; i>=0; i--) {\r
+               if ((i%4)==3) fc(0,&n);\r
+               if ((hi>>i)&1) {\r
+                       fc(10, &n);     fc(8,  &n);             // low-high transition\r
+               } else {\r
+                       fc(8,  &n);     fc(10, &n);             // high-low transition\r
+               }\r
+       }\r
+\r
+       WDT_HIT();\r
+       // manchester encode bits 31 to 0\r
+       for (i=31; i>=0; i--) {\r
+               if ((i%4)==3) fc(0,&n);\r
+               if ((lo>>i)&1) {\r
+                       fc(10, &n);     fc(8,  &n);             // low-high transition\r
+               } else {\r
+                       fc(8,  &n);     fc(10, &n);             // high-low transition\r
+               }\r
+       }\r
+\r
+       LED_A_ON();\r
+       SimulateTagLowFrequency(n);\r
+       LED_A_OFF();\r
+}\r
+\r
+// loop to capture raw HID waveform then FSK demodulate the TAG ID from it\r
+static void CmdHIDdemodFSK(void)\r
+{\r
+       BYTE *dest = (BYTE *)BigBuf;\r
+       int m=0, n=0, i=0, idx=0, found=0, lastval=0;\r
+       DWORD hi=0, lo=0;\r
+\r
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_125_KHZ);\r
+\r
+       // Connect the A/D to the peak-detected low-frequency path.\r
+       SetAdcMuxFor(GPIO_MUXSEL_LOPKD);\r
+\r
+       // Give it a bit of time for the resonant antenna to settle.\r
+       SpinDelay(50);\r
+\r
+       // Now set up the SSC to get the ADC samples that are now streaming at us.\r
+       FpgaSetupSsc();\r
+\r
+       for(;;) {\r
+               WDT_HIT();\r
+               LED_A_ON();\r
+               if(BUTTON_PRESS()) {\r
+                       LED_A_OFF();\r
+                       return;\r
+               }\r
+\r
+               i = 0;\r
+               m = sizeof(BigBuf);\r
+               memset(dest,128,m);\r
+               for(;;) {\r
+                       if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+                               SSC_TRANSMIT_HOLDING = 0x43;\r
+                               LED_D_ON();\r
+                       }\r
+                       if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+                               dest[i] = (BYTE)SSC_RECEIVE_HOLDING;\r
+                               // we don't care about actual value, only if it's more or less than a\r
+                               // threshold essentially we capture zero crossings for later analysis\r
+                               if(dest[i] < 127) dest[i] = 0; else dest[i] = 1;\r
+                               i++;\r
+                               LED_D_OFF();\r
+                               if(i >= m) {\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+\r
+               // FSK demodulator\r
+\r
+               // sync to first lo-hi transition\r
+               for( idx=1; idx<m; idx++) {\r
+                       if (dest[idx-1]<dest[idx])\r
+                               lastval=idx;\r
+                               break;\r
+               }\r
+               WDT_HIT();\r
+\r
+               // count cycles between consecutive lo-hi transitions, there should be either 8 (fc/8)\r
+               // or 10 (fc/10) cycles but in practice due to noise etc we may end up with with anywhere\r
+               // between 7 to 11 cycles so fuzz it by treat anything <9 as 8 and anything else as 10\r
+               for( i=0; idx<m; idx++) {\r
+                       if (dest[idx-1]<dest[idx]) {\r
+                               dest[i]=idx-lastval;\r
+                               if (dest[i] <= 8) {\r
+                                               dest[i]=1;\r
+                               } else {\r
+                                               dest[i]=0;\r
+                               }\r
+\r
+                               lastval=idx;\r
+                               i++;\r
+                       }\r
+               }\r
+               m=i;\r
+               WDT_HIT();\r
+\r
+               // we now have a set of cycle counts, loop over previous results and aggregate data into bit patterns\r
+               lastval=dest[0];\r
+               idx=0;\r
+               i=0;\r
+               n=0;\r
+               for( idx=0; idx<m; idx++) {\r
+                       if (dest[idx]==lastval) {\r
+                               n++;\r
+                       } else {\r
+                               // a bit time is five fc/10 or six fc/8 cycles so figure out how many bits a pattern width represents,\r
+                               // an extra fc/8 pattern preceeds every 4 bits (about 200 cycles) just to complicate things but it gets\r
+                               // swallowed up by rounding\r
+                               // expected results are 1 or 2 bits, any more and it's an invalid manchester encoding\r
+                               // special start of frame markers use invalid manchester states (no transitions) by using sequences\r
+                               // like 111000\r
+                               if (dest[idx-1]) {\r
+                                       n=(n+1)/6;                      // fc/8 in sets of 6\r
+                               } else {\r
+                                       n=(n+1)/5;                      // fc/10 in sets of 5\r
+                               }\r
+                               switch (n) {                    // stuff appropriate bits in buffer\r
+                                       case 0:\r
+                                       case 1: // one bit\r
+                                               dest[i++]=dest[idx-1];\r
+                                               break;\r
+                                       case 2: // two bits\r
+                                               dest[i++]=dest[idx-1];\r
+                                               dest[i++]=dest[idx-1];\r
+                                               break;\r
+                                       case 3: // 3 bit start of frame markers\r
+                                               dest[i++]=dest[idx-1];\r
+                                               dest[i++]=dest[idx-1];\r
+                                               dest[i++]=dest[idx-1];\r
+                                               break;\r
+                                       // When a logic 0 is immediately followed by the start of the next transmisson \r
+                                       // (special pattern) a pattern of 4 bit duration lengths is created.\r
+                                       case 4:\r
+                                               dest[i++]=dest[idx-1];\r
+                                               dest[i++]=dest[idx-1];\r
+                                               dest[i++]=dest[idx-1];\r
+                                               dest[i++]=dest[idx-1];\r
+                                               break;\r
+                                       default:        // this shouldn't happen, don't stuff any bits\r
+                                               break;\r
+                               }\r
+                               n=0;\r
+                               lastval=dest[idx];\r
+                       }\r
+               }\r
+               m=i;\r
+               WDT_HIT();\r
+\r
+               // final loop, go over previously decoded manchester data and decode into usable tag ID\r
+               // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0\r
+               for( idx=0; idx<m-6; idx++) {\r
+                       // search for a start of frame marker\r
+                       if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) )\r
+                       {\r
+                               found=1;\r
+                               idx+=6;\r
+                               if (found && (hi|lo)) {\r
+                                       DbpString("TAG ID");\r
+                                       DbpIntegers(hi, lo, (lo>>1)&0xffff);\r
+                                       hi=0;\r
+                                       lo=0;\r
+                                       found=0;\r
+                               }\r
+                       }\r
+                       if (found) {\r
+                               if (dest[idx] && (!dest[idx+1]) ) {\r
+                                       hi=(hi<<1)|(lo>>31);\r
+                                       lo=(lo<<1)|0;\r
+                               } else if ( (!dest[idx]) && dest[idx+1]) {\r
+                                       hi=(hi<<1)|(lo>>31);\r
+                                       lo=(lo<<1)|1;\r
+                               } else {\r
+                                       found=0;\r
+                                       hi=0;\r
+                                       lo=0;\r
+                               }\r
+                               idx++;\r
+                       }\r
+                       if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) )\r
+                       {\r
+                               found=1;\r
+                               idx+=6;\r
+                               if (found && (hi|lo)) {\r
+                                       DbpString("TAG ID");\r
+                                       DbpIntegers(hi, lo, (lo>>1)&0xffff);\r
+                                       hi=0;\r
+                                       lo=0;\r
+                                       found=0;\r
+                               }\r
+                       }\r
+               }\r
+               WDT_HIT();\r
+       }\r
+}\r
+\r
+void SimulateTagHfListen(void)\r
+{\r
+       BYTE *dest = (BYTE *)BigBuf;\r
+       int n = sizeof(BigBuf);\r
+       BYTE v = 0;\r
+       int i;\r
+       int p = 0;\r
+\r
+       // We're using this mode just so that I can test it out; the simulated\r
+       // tag mode would work just as well and be simpler.\r
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP);\r
+\r
+       // We need to listen to the high-frequency, peak-detected path.\r
+       SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
+\r
+       FpgaSetupSsc();\r
+\r
+       i = 0;\r
+       for(;;) {\r
+               if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+                       SSC_TRANSMIT_HOLDING = 0xff;\r
+               }\r
+               if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+                       BYTE r = (BYTE)SSC_RECEIVE_HOLDING;\r
+\r
+                       v <<= 1;\r
+                       if(r & 1) {\r
+                               v |= 1;\r
+                       }\r
+                       p++;\r
+\r
+                       if(p >= 8) {\r
+                               dest[i] = v;\r
+                               v = 0;\r
+                               p = 0;\r
+                               i++;\r
+\r
+                               if(i >= n) {\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       DbpString("simulate tag (now type bitsamples)");\r
+}\r
+\r
+void UsbPacketReceived(BYTE *packet, int len)\r
+{\r
+       UsbCommand *c = (UsbCommand *)packet;\r
+\r
+       switch(c->cmd) {\r
+               case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K:\r
+                       AcquireRawAdcSamples125k(c->ext1);\r
+                       break;\r
+\r
+               case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693:\r
+                       AcquireRawAdcSamplesIso15693();\r
+                       break;\r
+\r
+               case CMD_READER_ISO_15693:\r
+                       ReaderIso15693(c->ext1); \r
+                       break;\r
+\r
+               case CMD_SIMTAG_ISO_15693:\r
+                       SimTagIso15693(c->ext1); \r
+                       break;\r
+\r
+\r
+               case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443:\r
+                       AcquireRawAdcSamplesIso14443(c->ext1);\r
+                       break;\r
+\r
+               case CMD_READER_ISO_14443a:\r
+                       ReaderIso14443a(c->ext1); \r
+                       break;\r
+\r
+               case CMD_SNOOP_ISO_14443:\r
+                       SnoopIso14443();\r
+                       break;\r
+\r
+               case CMD_SNOOP_ISO_14443a:\r
+                       SnoopIso14443a();\r
+                       break;\r
+\r
+               case CMD_SIMULATE_TAG_HF_LISTEN:\r
+                       SimulateTagHfListen();\r
+                       break;\r
+\r
+               case CMD_SIMULATE_TAG_ISO_14443:\r
+                       SimulateIso14443Tag();\r
+                       break;\r
+\r
+               case CMD_SIMULATE_TAG_ISO_14443a:\r
+                       SimulateIso14443aTag(c->ext1, c->ext2);  // ## Simulate iso14443a tag - pass tag type & UID\r
+                       break;\r
+\r
+               case CMD_MEASURE_ANTENNA_TUNING:\r
+                       MeasureAntennaTuning();\r
+                       break;\r
+\r
+               case CMD_HID_DEMOD_FSK:\r
+                       CmdHIDdemodFSK();                               // Demodulate HID tag\r
+                       break;\r
+\r
+               case CMD_HID_SIM_TAG:\r
+                       CmdHIDsimTAG(c->ext1, c->ext2);                                 // Simulate HID tag by ID\r
+                       break;\r
+\r
+               case CMD_FPGA_MAJOR_MODE_OFF:           // ## FPGA Control\r
+                       LED_C_ON();\r
+                       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
+                       SpinDelay(200);\r
+                       LED_C_OFF();\r
+                       break;\r
+\r
+               case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K:\r
+               case CMD_DOWNLOAD_RAW_BITS_TI_TYPE: {\r
+                       UsbCommand n;\r
+                       if(c->cmd == CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K) {\r
+                               n.cmd = CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K;\r
+                       } else {\r
+                               n.cmd = CMD_DOWNLOADED_RAW_BITS_TI_TYPE;\r
+                       }\r
+                       n.ext1 = c->ext1;\r
+                       memcpy(n.d.asDwords, BigBuf+c->ext1, 12*sizeof(DWORD));\r
+                       UsbSendPacket((BYTE *)&n, sizeof(n));\r
+                       break;\r
+               }\r
+               case CMD_DOWNLOADED_SIM_SAMPLES_125K: {\r
+                       BYTE *b = (BYTE *)BigBuf;\r
+                       memcpy(b+c->ext1, c->d.asBytes, 48);\r
+                       break;\r
+               }\r
+               case CMD_SIMULATE_TAG_125K:\r
+                       LED_A_ON();\r
+                       SimulateTagLowFrequency(c->ext1);\r
+                       LED_A_OFF();\r
+                       break;\r
+\r
+               case CMD_LCD_RESET:\r
+                       LCDReset();\r
+                       break;\r
+\r
+               case CMD_LCD:\r
+                       LCDSend(c->ext1);\r
+                       break;\r
+\r
+        case CMD_SETUP_WRITE:\r
+               case CMD_FINISH_WRITE:\r
+                       USB_D_PLUS_PULLUP_OFF();\r
+                       SpinDelay(1000);\r
+                       SpinDelay(1000);\r
+                       RSTC_CONTROL = RST_CONTROL_KEY | RST_CONTROL_PROCESSOR_RESET;\r
+                       for(;;) {\r
+                               // We're going to reset, and the bootrom will take control.\r
+                       }\r
+                       break;\r
+\r
+               default:\r
+                       DbpString("unknown command");\r
+                       break;\r
+       }\r
+}\r
+\r
+void AppMain(void)\r
+{\r
+       memset(BigBuf,0,sizeof(BigBuf));\r
+       SpinDelay(100);\r
+\r
+    LED_D_OFF();\r
+    LED_C_OFF();\r
+    LED_B_OFF();\r
+    LED_A_OFF();\r
+\r
+       UsbStart();\r
+\r
+       // The FPGA gets its clock from us from PCK0 output, so set that up.\r
+       PIO_PERIPHERAL_B_SEL = (1 << GPIO_PCK0);\r
+       PIO_DISABLE = (1 << GPIO_PCK0);\r
+       PMC_SYS_CLK_ENABLE = PMC_SYS_CLK_PROGRAMMABLE_CLK_0;\r
+       // PCK0 is PLL clock / 4 = 96Mhz / 4 = 24Mhz\r
+       PMC_PROGRAMMABLE_CLK_0 = PMC_CLK_SELECTION_PLL_CLOCK |\r
+               PMC_CLK_PRESCALE_DIV_4;\r
+       PIO_OUTPUT_ENABLE = (1 << GPIO_PCK0);\r
+\r
+       // Reset SPI\r
+       SPI_CONTROL = SPI_CONTROL_RESET;\r
+       // Reset SSC\r
+       SSC_CONTROL = SSC_CONTROL_RESET;\r
+\r
+       // Load the FPGA image, which we have stored in our flash.\r
+       FpgaDownloadAndGo();\r
+\r
+       LCDInit();\r
+\r
+       // test text on different colored backgrounds\r
+    LCDString(" The quick brown fox  ",        &FONT6x8,1,1+8*0,WHITE  ,BLACK );\r
+    LCDString("  jumped over the     ",        &FONT6x8,1,1+8*1,BLACK  ,WHITE );\r
+    LCDString("     lazy dog.        ",        &FONT6x8,1,1+8*2,YELLOW ,RED   );\r
+    LCDString(" AaBbCcDdEeFfGgHhIiJj ",        &FONT6x8,1,1+8*3,RED    ,GREEN );\r
+    LCDString(" KkLlMmNnOoPpQqRrSsTt ",        &FONT6x8,1,1+8*4,MAGENTA,BLUE  );\r
+    LCDString("UuVvWwXxYyZz0123456789",        &FONT6x8,1,1+8*5,BLUE   ,YELLOW);\r
+    LCDString("`-=[]_;',./~!@#$%^&*()",        &FONT6x8,1,1+8*6,BLACK  ,CYAN  );\r
+    LCDString("     _+{}|:\\\"<>?     ",&FONT6x8,1,1+8*7,BLUE  ,MAGENTA);\r
+\r
+       // color bands\r
+       LCDFill(0, 1+8* 8, 132, 8, BLACK);\r
+       LCDFill(0, 1+8* 9, 132, 8, WHITE);\r
+       LCDFill(0, 1+8*10, 132, 8, RED);\r
+       LCDFill(0, 1+8*11, 132, 8, GREEN);\r
+       LCDFill(0, 1+8*12, 132, 8, BLUE);\r
+       LCDFill(0, 1+8*13, 132, 8, YELLOW);\r
+       LCDFill(0, 1+8*14, 132, 8, CYAN);\r
+       LCDFill(0, 1+8*15, 132, 8, MAGENTA);\r
+\r
+       for(;;) {\r
+               UsbPoll(FALSE);\r
+               WDT_HIT();\r
+       }\r
+}\r
+\r
+void SpinDelay(int ms)\r
+{\r
+       int ticks = (48000*ms) >> 10;\r
+\r
+       // Borrow a PWM unit for my real-time clock\r
+       PWM_ENABLE = PWM_CHANNEL(0);\r
+       // 48 MHz / 1024 gives 46.875 kHz\r
+       PWM_CH_MODE(0) = PWM_CH_MODE_PRESCALER(10);\r
+       PWM_CH_DUTY_CYCLE(0) = 0;\r
+       PWM_CH_PERIOD(0) = 0xffff;\r
+\r
+       WORD start = (WORD)PWM_CH_COUNTER(0);\r
+\r
+       for(;;) {\r
+               WORD now = (WORD)PWM_CH_COUNTER(0);\r
+               if(now == (WORD)(start + ticks)) {\r
+                       return;\r
+               }\r
+               WDT_HIT();\r
+       }\r
+}\r
diff --git a/armsrc/apps.h b/armsrc/apps.h
new file mode 100644 (file)
index 0000000..e09c835
--- /dev/null
@@ -0,0 +1,77 @@
+//-----------------------------------------------------------------------------\r
+// Definitions internal to the app source.\r
+// Jonathan Westhues, Aug 2005\r
+// Added ISO14443-A support by Gerhard de Koning Gans, April 2008\r
+//-----------------------------------------------------------------------------\r
+\r
+#ifndef __APPS_H\r
+#define __APPS_H\r
+\r
+/// appmain.c\r
+void AppMain(void);\r
+void DbpIntegers(int a, int b, int c);\r
+void DbpString(char *str);\r
+void SpinDelay(int ms);\r
+void ToSendStuffBit(int b);\r
+void ToSendReset(void);\r
+extern int ToSendMax;\r
+extern BYTE ToSend[];\r
+extern DWORD BigBuf[];\r
+\r
+/// fpga.c\r
+void FpgaWriteConfWord(BYTE v);\r
+void FpgaDownloadAndGo(void);\r
+void FpgaSetupSsc(void);\r
+void SetupSpi(int mode);\r
+void FpgaSetupSscDma(BYTE *buf, int len);\r
+void SetAdcMuxFor(int whichGpio);\r
+\r
+// Definitions for the FPGA configuration word.\r
+#define FPGA_MAJOR_MODE_LF_READER                      (0<<5)\r
+#define FPGA_MAJOR_MODE_LF_SIMULATOR           (1<<5)\r
+#define FPGA_MAJOR_MODE_HF_READER_TX           (2<<5)\r
+#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR     (3<<5)\r
+#define FPGA_MAJOR_MODE_HF_SIMULATOR           (4<<5)\r
+#define FPGA_MAJOR_MODE_HF_ISO14443A           (5<<5)\r
+#define FPGA_MAJOR_MODE_UNUSED                         (6<<5)\r
+#define FPGA_MAJOR_MODE_OFF                                    (7<<5)\r
+// Options for the LF reader\r
+#define FPGA_LF_READER_USE_125_KHZ                     (1<<3)\r
+#define FPGA_LF_READER_USE_134_KHZ                     (0<<3)\r
+// Options for the HF reader, tx to tag\r
+#define FPGA_HF_READER_TX_SHALLOW_MOD          (1<<0)\r
+// Options for the HF reader, correlating against rx from tag\r
+#define FPGA_HF_READER_RX_XCORR_848_KHZ                (1<<0)\r
+#define FPGA_HF_READER_RX_XCORR_SNOOP          (1<<1)\r
+// Options for the HF simulated tag, how to modulate\r
+#define FPGA_HF_SIMULATOR_NO_MODULATION                (0<<0)\r
+#define FPGA_HF_SIMULATOR_MODULATE_BPSK                (1<<0)\r
+// Options for ISO14443A\r
+#define FPGA_HF_ISO14443A_SNIFFER                      (0<<0)\r
+#define FPGA_HF_ISO14443A_TAGSIM_LISTEN                (1<<0)\r
+#define FPGA_HF_ISO14443A_TAGSIM_MOD           (2<<0)\r
+#define FPGA_HF_ISO14443A_READER_LISTEN                (3<<0)\r
+#define FPGA_HF_ISO14443A_READER_MOD           (4<<0)\r
+\r
+/// iso14443.h\r
+void SimulateIso14443Tag(void);\r
+void AcquireRawAdcSamplesIso14443(DWORD parameter);\r
+void SnoopIso14443(void);\r
+\r
+/// iso14443a.h\r
+void SnoopIso14443a(void);\r
+void SimulateIso14443aTag(int tagType, int TagUid);    // ## simulate iso14443a tag\r
+void ReaderIso14443a(DWORD parameter);\r
+\r
+/// iso15693.h\r
+void AcquireRawAdcSamplesIso15693(void);\r
+void ReaderIso15693(DWORD parameter);  // Simulate an ISO15693 reader - greg\r
+void SimTagIso15693(DWORD parameter);  // simulate an ISO15693 tag - greg\r
+\r
+/// util.h\r
+int strlen(char *str);\r
+void *memcpy(void *dest, const void *src, int len);\r
+void *memset(void *dest, int c, int len);\r
+int memcmp(const void *av, const void *bv, int len);\r
+\r
+#endif\r
diff --git a/armsrc/example_lcd.c b/armsrc/example_lcd.c
new file mode 100644 (file)
index 0000000..a2267ba
--- /dev/null
@@ -0,0 +1,269 @@
+unsigned char somestring[25];\r
+\r
+//*********************************************************************\r
+//********************  SYSTERM HEARTBEAT @ 10 ms *********************\r
+//*********************************************************************\r
+void InitSPI (void)\r
+{\r
+  //set functionalite to pins:\r
+  //port0.11 -> NPCS0\r
+  //port0.12 -> MISO\r
+  //port0.13 -> MOSI\r
+  //port0.14 -> SPCK\r
+  PIOA_PDR = BIT11 | BIT12 | BIT13 | BIT14;\r
+  PIOA_ASR = BIT11 | BIT12 | BIT13 | BIT14;\r
+  PIOA_BSR = 0;\r
+\r
+\r
+  PMC_PCER |= 1 << 5; // Enable SPI timer clock.\r
+\r
+  /****  Fixed mode ****/\r
+  SPI_CR   = 0x81;                                     //SPI Enable, Sowtware reset\r
+  SPI_CR   = 0x01;                                     //SPI Enable\r
+\r
+\r
+\r
+  SPI_MR       = 0x000E0011;                           //Master mode\r
+  SPI_CSR0     = 0x01010B11;                           //9 bit\r
+\r
+}\r
+\r
+//*********************************************************************\r
+//***************************  Task 1  ********************************\r
+//*********************************************************************\r
+void Task_1(void *p)\r
+{\r
+    char beat=0;                                    // just flash the onboard LED for Heatbeat\r
+\r
+    while(1)\r
+    {\r
+       if(beat)\r
+       {\r
+            PIOA_SODR = BIT18;\r
+            beat=0;\r
+       }\r
+       else\r
+       {\r
+            PIOA_CODR = BIT18;\r
+            beat=1;\r
+       }\r
+\r
+       ctl_timeout_wait(ctl_get_current_time()+ 150);\r
+\r
+    }\r
+}\r
+//*********************************************************************\r
+//***************************  Task 2  ********************************\r
+//*********************************************************************\r
+void Task_2(void *p)\r
+{\r
+    unsigned long z;\r
+    unsigned int x,y;\r
+    unsigned char a,b,c,d,e;\r
+\r
+    char seconds,minutes,hours;\r
+\r
+    unsigned int nowold,tenths;\r
+\r
+\r
+    InitLCD();\r
+\r
+\r
+/*******  Put smiley face up in 4096 color mode  *******/\r
+    LCD_Fill(0,0,132,132,Black);\r
+\r
+    LCD_Set_Resolution(HIGH_RES);                        // set 4096 color mode\r
+\r
+//    ShowImage_4096(0,0,smiley);\r
+    LCD_Set_Resolution(LOW_RES);                        // set 256 color mode\r
+\r
+    ctl_timeout_wait(ctl_get_current_time()+ 4000);     // wait 4 seconds to view it\r
+\r
+/*******  Do some static on screen  *******/\r
+\r
+    LCD_Fill(0,0,132,132,Black);\r
+\r
+    for(z=0;z<100000;z++)\r
+    {\r
+        while( (a = rand()) > 132);\r
+        while( (b = rand()) > 132);\r
+        c = rand();\r
+        LCD_PixelPut(a,b,c);\r
+    }\r
+\r
+/*******  Do some lines on screen  *******/\r
+    LCD_Fill(0,0,132,132,Black);\r
+\r
+    for(z=1;z<300;z++)\r
+    {\r
+        while( (a = rand()) > 132);\r
+        while( (b = rand()) > 132);\r
+        while( (c = rand()) > 132);\r
+        while( (d = rand()) > 132);\r
+        e = rand();                                 // pick color\r
+\r
+        LCD_Line(a,b,c,d,e);\r
+       ctl_timeout_wait(ctl_get_current_time()+ 10);\r
+    }\r
+\r
+/*******  Do some Boxes on screen  *******/\r
+    LCD_Fill(0,0,132,132,Black);\r
+\r
+    for(z=0;z<300;z++)\r
+    {\r
+\r
+        while( (a = rand()) > 132);\r
+        while( (b = rand()) > 132);\r
+        while( (c = rand()) > 132);\r
+        while( (d = rand()) > 132);\r
+\r
+        e = rand();                                 // pick color\r
+        LCD_Box(a,b,c,d,e);\r
+\r
+        ctl_timeout_wait(ctl_get_current_time()+ 10);\r
+    }\r
+/*******  Do some Circles on screen  *******/\r
+    LCD_Fill(0,0,132,132,Black);\r
+\r
+    for(z=0;z<100;z++)\r
+    {\r
+\r
+        while( (a = rand()) > 132);\r
+        while( (b = rand()) > 132);\r
+        while( (c = rand()) > 127);                 // diameter\r
+\r
+        d = rand();                                 // pick color\r
+        LCD_Circle(a,b,c,d);\r
+\r
+        ctl_timeout_wait(ctl_get_current_time()+ 10);\r
+    }\r
+\r
+/*******  Do some Thick Circles on screen  *******/\r
+    LCD_Fill(0,0,132,132,Black);\r
+\r
+    for(z=0;z<25;z++)\r
+    {\r
+        while( (a = rand()) > 132);\r
+        while( (b = rand()) > 132);\r
+        while( (c = rand()) > 40);                 // diameter\r
+        while( (d = rand()) > 10);                 // wall thicknes\r
+        e = rand();                                 // pick color\r
+        LCD_Thick_Circle(a,b,c,d,e);\r
+\r
+        ctl_timeout_wait(ctl_get_current_time()+ 1);\r
+    }\r
+\r
+/*******  Do something funky to wipe screen  *******/\r
+       b=0;\r
+\r
+       for(a=0;a<131;a++)\r
+       {\r
+            LCD_Line(a,b,65,65,0x62);\r
+       }\r
+       for(b=0;b<131;b++)\r
+       {\r
+            LCD_Line(a,b,65,65,0x62);\r
+       }\r
+       for(;a>1;a--)\r
+       {\r
+            LCD_Line(a,b,65,65,0x62);\r
+       }\r
+       for(;b>1;b--)\r
+       {\r
+            LCD_Line(a,b,65,65,0x62);\r
+       }\r
+\r
+       ctl_timeout_wait(ctl_get_current_time()+ 1000);\r
+\r
+/*******  Show Image scrolling *******/\r
+    LCD_Fill(0,0,132,132,Black);\r
+\r
+    ShowImage(0,50,sparkfun);\r
+\r
+    sprintf(somestring,"Thanks SparkFun");\r
+    LCD_String(somestring,&FONT8x8F[0][0],5,10,LightGreen,Black);\r
+\r
+    ctl_timeout_wait(ctl_get_current_time()+ 2000);     // hold sparkfun image for a bit\r
+\r
+    for(y=50;y<140;y++)\r
+    {\r
+        LCD_Line(0,y-1,132,y-1,Black);                  // wipe the white line as it moves down\r
+       ShowImage(0,y,sparkfun);                        // move image to Y location\r
+       ctl_timeout_wait(ctl_get_current_time()+ 25);   // wait a bit\r
+    }\r
+\r
+/*******  Run radar in loop with example fonts displayed  *******/\r
+    LCD_Fill(0,0,132,132,Black);\r
+\r
+    LCD_Thick_Circle(66,66,30,2,DarkBlue);\r
+\r
+    y=0;\r
+\r
+    while (1)\r
+    {\r
+       LCD_Circle_Line(66,66,28,0,y,LightGreen);\r
+\r
+       ctl_timeout_wait(ctl_get_current_time()+ 1);\r
+\r
+       tenths = ctl_current_time / 1000;\r
+\r
+       if(tenths != nowold)\r
+       {\r
+            nowold = tenths;\r
+\r
+            if(++seconds == 60)\r
+            {\r
+                seconds = 0;\r
+\r
+                if(++minutes == 60)\r
+                {\r
+                    minutes=0;\r
+                    hours++;\r
+               }\r
+            }\r
+       }\r
+\r
+\r
+       printf("a=%6lu - b=%6lu - c=%6lu - d=%6lu  :  Time=%lu\r\n",a,b,c,d,ctl_current_time);\r
+\r
+       sprintf(somestring,"%05lu",y);\r
+       LCD_String(somestring,&FONT6x8[0][0],52,25,White,Black);\r
+\r
+       sprintf(somestring,"Time:%02u:%02u:%02u",hours,minutes,seconds);\r
+       LCD_String(somestring,&FONT8x8F[0][0],14,10,DarkRed,Black);\r
+\r
+       sprintf(somestring,"Time:%02u:%02u:%02u",hours,minutes,seconds);\r
+       LCD_String(somestring,&FONT8x16[0][0],14,115,LightGreen,Black);\r
+\r
+       LCD_Circle_Line(66,66,28,0,y,Black);\r
+\r
+        if(++y==360)\r
+        {\r
+            y=0;\r
+        }\r
+\r
+       ctl_timeout_wait(ctl_get_current_time()+ 10);\r
+\r
+    }\r
+}\r
+\r
+/*************************************************************************\r
+ *********************        Main Module        *************************\r
+ *********************                           *************************\r
+ *********************     Initialize Program    *************************\r
+ *********************         Sequences         *************************\r
+ *********************                           *************************\r
+ *************************************************************************/\r
+int main(void)\r
+{\r
+       BoardInit();\r
+\r
+       InitSPI();\r
+\r
+       while (1)\r
+       {\r
+            Idle();\r
+       }\r
+\r
+       return 0;\r
+}\r
diff --git a/armsrc/fonts.c b/armsrc/fonts.c
new file mode 100644 (file)
index 0000000..81e99ce
--- /dev/null
@@ -0,0 +1,300 @@
+const char FONT6x8[97][8] = {\r
+       {0x06,0x08,0x08,0x00,0x00,0x00,0x00,0x00},      // columns, rows, bytes per char\r
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},      // space\r
+       {0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00},      // !\r
+       {0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00},      // "\r
+       {0x50,0x50,0xF8,0x50,0xF8,0x50,0x50,0x00},      // #\r
+       {0x20,0x78,0xA0,0x70,0x28,0xF0,0x20,0x00},      // $\r
+       {0xC0,0xC8,0x10,0x20,0x40,0x98,0x18,0x00},      // %\r
+       {0x40,0xA0,0xA0,0x40,0xA8,0x90,0x68,0x00},      // &\r
+       {0x30,0x30,0x20,0x40,0x00,0x00,0x00,0x00},      // '\r
+       {0x10,0x20,0x40,0x40,0x40,0x20,0x10,0x00},      // (\r
+       {0x40,0x20,0x10,0x10,0x10,0x20,0x40,0x00},      // )\r
+       {0x00,0x20,0xA8,0x70,0x70,0xA8,0x20,0x00},      // *\r
+       {0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0x00},      // +\r
+       {0x00,0x00,0x00,0x00,0x30,0x30,0x20,0x40},      // ,\r
+       {0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00},      // -\r
+       {0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00},      // .\r
+       {0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00},      // /\r
+       {0x70,0x88,0x88,0xA8,0x88,0x88,0x70,0x00},      // 0\r
+       {0x20,0x60,0x20,0x20,0x20,0x20,0x70,0x00},      // 1\r
+       {0x70,0x88,0x08,0x70,0x80,0x80,0xF8,0x00},      // 2\r
+       {0xF8,0x08,0x10,0x30,0x08,0x88,0x70,0x00},      // 3\r
+       {0x10,0x30,0x50,0x90,0xF8,0x10,0x10,0x00},      // 4\r
+       {0xF8,0x80,0xF0,0x08,0x08,0x88,0x70,0x00},      // 5\r
+       {0x38,0x40,0x80,0xF0,0x88,0x88,0x70,0x00},      // 6\r
+       {0xF8,0x08,0x08,0x10,0x20,0x40,0x80,0x00},      // 7\r
+       {0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00},      // 8\r
+       {0x70,0x88,0x88,0x78,0x08,0x10,0xE0,0x00},      // 9\r
+       {0x00,0x00,0x20,0x00,0x20,0x00,0x00,0x00},      // :\r
+       {0x00,0x00,0x20,0x00,0x20,0x20,0x40,0x00},      // ;\r
+       {0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x00},      // <\r
+       {0x00,0x00,0xF8,0x00,0xF8,0x00,0x00,0x00},      // =\r
+       {0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00},      // >\r
+       {0x70,0x88,0x08,0x30,0x20,0x00,0x20,0x00},      // ?\r
+       {0x70,0x88,0xA8,0xB8,0xB0,0x80,0x78,0x00},      // @\r
+       {0x20,0x50,0x88,0x88,0xF8,0x88,0x88,0x00},      // A\r
+       {0xF0,0x88,0x88,0xF0,0x88,0x88,0xF0,0x00},      // B\r
+       {0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00},      // C\r
+       {0xF0,0x88,0x88,0x88,0x88,0x88,0xF0,0x00},      // D\r
+       {0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8,0x00},      // E\r
+       {0xF8,0x80,0x80,0xF0,0x80,0x80,0x80,0x00},      // F\r
+       {0x78,0x88,0x80,0x80,0x98,0x88,0x78,0x00},      // G\r
+       {0x88,0x88,0x88,0xF8,0x88,0x88,0x88,0x00},      // H\r
+       {0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00},      // I\r
+       {0x38,0x10,0x10,0x10,0x10,0x90,0x60,0x00},      // J\r
+       {0x88,0x90,0xA0,0xC0,0xA0,0x90,0x88,0x00},      // K\r
+       {0x80,0x80,0x80,0x80,0x80,0x80,0xF8,0x00},      // L\r
+       {0x88,0xD8,0xA8,0xA8,0xA8,0x88,0x88,0x00},      // M\r
+       {0x88,0x88,0xC8,0xA8,0x98,0x88,0x88,0x00},      // N\r
+       {0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00},      // O\r
+       {0xF0,0x88,0x88,0xF0,0x80,0x80,0x80,0x00},      // P\r
+       {0x70,0x88,0x88,0x88,0xA8,0x90,0x68,0x00},      // Q\r
+       {0xF0,0x88,0x88,0xF0,0xA0,0x90,0x88,0x00},      // R\r
+       {0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00},      // S\r
+       {0xF8,0xA8,0x20,0x20,0x20,0x20,0x20,0x00},      // T\r
+       {0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00},      // U\r
+       {0x88,0x88,0x88,0x88,0x88,0x50,0x20,0x00},      // V\r
+       {0x88,0x88,0x88,0xA8,0xA8,0xA8,0x50,0x00},      // W\r
+       {0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00},      // X\r
+       {0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00},      // Y\r
+       {0xF8,0x08,0x10,0x70,0x40,0x80,0xF8,0x00},      // Z\r
+       {0x78,0x40,0x40,0x40,0x40,0x40,0x78,0x00},      // [\r
+       {0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00},      // backslash\r
+       {0x78,0x08,0x08,0x08,0x08,0x08,0x78,0x00},      // ]\r
+       {0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00},      // ^\r
+       {0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00},      // _\r
+       {0x60,0x60,0x20,0x10,0x00,0x00,0x00,0x00},      // `\r
+       {0x00,0x00,0x60,0x10,0x70,0x90,0x78,0x00},      // a\r
+       {0x80,0x80,0xB0,0xC8,0x88,0xC8,0xB0,0x00},      // b\r
+       {0x00,0x00,0x70,0x88,0x80,0x88,0x70,0x00},      // c\r
+       {0x08,0x08,0x68,0x98,0x88,0x98,0x68,0x00},      // d\r
+       {0x00,0x00,0x70,0x88,0xF8,0x80,0x70,0x00},      // e\r
+       {0x10,0x28,0x20,0x70,0x20,0x20,0x20,0x00},      // f\r
+       {0x00,0x00,0x70,0x98,0x98,0x68,0x08,0x70},      // g\r
+       {0x80,0x80,0xB0,0xC8,0x88,0x88,0x88,0x00},      // h\r
+       {0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00},      // i\r
+       {0x10,0x00,0x10,0x10,0x10,0x90,0x60,0x00},      // j\r
+       {0x80,0x80,0x90,0xA0,0xC0,0xA0,0x90,0x00},      // k\r
+       {0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00},      // l\r
+       {0x00,0x00,0xD0,0xA8,0xA8,0xA8,0xA8,0x00},      // m\r
+       {0x00,0x00,0xB0,0xC8,0x88,0x88,0x88,0x00},      // n\r
+       {0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00},      // o\r
+       {0x00,0x00,0xB0,0xC8,0xC8,0xB0,0x80,0x80},      // p\r
+       {0x00,0x00,0x68,0x98,0x98,0x68,0x08,0x08},      // q\r
+       {0x00,0x00,0xB0,0xC8,0x80,0x80,0x80,0x00},      // r\r
+       {0x00,0x00,0x78,0x80,0x70,0x08,0xF0,0x00},      // s\r
+       {0x20,0x20,0xF8,0x20,0x20,0x28,0x10,0x00},      // t\r
+       {0x00,0x00,0x88,0x88,0x88,0x98,0x68,0x00},      // u\r
+       {0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x00},      // v\r
+       {0x00,0x00,0x88,0x88,0xA8,0xA8,0x50,0x00},      // w\r
+       {0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00},      // x\r
+       {0x00,0x00,0x88,0x88,0x78,0x08,0x88,0x70},      // y\r
+       {0x00,0x00,0xF8,0x10,0x20,0x40,0xF8,0x00},      // z\r
+       {0x10,0x20,0x20,0x40,0x20,0x20,0x10,0x00},      // {\r
+       {0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x00},      // |\r
+       {0x40,0x20,0x20,0x10,0x20,0x20,0x40,0x00},      // }\r
+       {0x40,0xA8,0x10,0x00,0x00,0x00,0x00,0x00},      // ~\r
+       {0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00}       // DEL\r
+};\r
+/*\r
+const char FONT8x8F[97][8] = {\r
+       {0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00},      // columns, rows, bytes per char\r
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},      // space\r
+       {0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00},      // !\r
+       {0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00},      // "\r
+       {0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00},      // #\r
+       {0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00},      // $\r
+       {0x00,0x63,0x66,0x0C,0x18,0x33,0x63,0x00},      // %\r
+       {0x1C,0x36,0x1C,0x3B,0x6E,0x66,0x3B,0x00},      // &\r
+       {0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00},      // '\r
+       {0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00},      // (\r
+       {0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00},      // )\r
+       {0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00},      // *\r
+       {0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00},      // +\r
+       {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30},      // ,\r
+       {0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00},      // -\r
+       {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00},      // .\r
+       {0x03,0x06,0x0C,0x18,0x30,0x60,0x40,0x00},      // /\r
+       {0x3E,0x63,0x63,0x6B,0x63,0x63,0x3E,0x00},      // 0\r
+       {0x18,0x38,0x58,0x18,0x18,0x18,0x7E,0x00},      // 1\r
+       {0x3C,0x66,0x06,0x1C,0x30,0x66,0x7E,0x00},      // 2\r
+       {0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00},      // 3\r
+       {0x0E,0x1E,0x36,0x66,0x7F,0x06,0x0F,0x00},      // 4\r
+       {0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00},      // 5\r
+       {0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00},      // 6\r
+       {0x7E,0x66,0x06,0x0C,0x18,0x18,0x18,0x00},      // 7\r
+       {0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00},      // 8\r
+       {0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00},      // 9\r
+       {0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00},      // :\r
+       {0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30},      // ;\r
+       {0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00},      // <\r
+       {0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00},      // =\r
+       {0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00},      // >\r
+       {0x3C,0x66,0x06,0x0C,0x18,0x00,0x18,0x00},      // ?\r
+       {0x3E,0x63,0x6F,0x69,0x6F,0x60,0x3E,0x00},      // @\r
+       {0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x00},      // A\r
+       {0x7E,0x33,0x33,0x3E,0x33,0x33,0x7E,0x00},      // B\r
+       {0x1E,0x33,0x60,0x60,0x60,0x33,0x1E,0x00},      // C\r
+       {0x7C,0x36,0x33,0x33,0x33,0x36,0x7C,0x00},      // D\r
+       {0x7F,0x31,0x34,0x3C,0x34,0x31,0x7F,0x00},      // E\r
+       {0x7F,0x31,0x34,0x3C,0x34,0x30,0x78,0x00},      // F\r
+       {0x1E,0x33,0x60,0x60,0x67,0x33,0x1F,0x00},      // G\r
+       {0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00},      // H\r
+       {0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00},      // I\r
+       {0x0F,0x06,0x06,0x06,0x66,0x66,0x3C,0x00},      // J\r
+       {0x73,0x33,0x36,0x3C,0x36,0x33,0x73,0x00},      // K\r
+       {0x78,0x30,0x30,0x30,0x31,0x33,0x7F,0x00},      // L\r
+       {0x63,0x77,0x7F,0x7F,0x6B,0x63,0x63,0x00},      // M\r
+       {0x63,0x73,0x7B,0x6F,0x67,0x63,0x63,0x00},      // N\r
+       {0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00},      // O\r
+       {0x7E,0x33,0x33,0x3E,0x30,0x30,0x78,0x00},      // P\r
+       {0x3C,0x66,0x66,0x66,0x6E,0x3C,0x0E,0x00},      // Q\r
+       {0x7E,0x33,0x33,0x3E,0x36,0x33,0x73,0x00},      // R\r
+       {0x3C,0x66,0x30,0x18,0x0C,0x66,0x3C,0x00},      // S\r
+       {0x7E,0x5A,0x18,0x18,0x18,0x18,0x3C,0x00},      // T\r
+       {0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x00},      // U\r
+       {0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00},      // V\r
+       {0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x00},      // W\r
+       {0x63,0x63,0x36,0x1C,0x1C,0x36,0x63,0x00},      // X\r
+       {0x66,0x66,0x66,0x3C,0x18,0x18,0x3C,0x00},      // Y\r
+       {0x7F,0x63,0x46,0x0C,0x19,0x33,0x7F,0x00},      // Z\r
+       {0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00},      // [\r
+       {0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00},      // backslash\r
+       {0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00},      // ]\r
+       {0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00},      // ^\r
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF},      // _\r
+       {0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00},      // `\r
+       {0x00,0x00,0x3C,0x06,0x3E,0x66,0x3B,0x00},      // a\r
+       {0x70,0x30,0x3E,0x33,0x33,0x33,0x6E,0x00},      // b\r
+       {0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00},      // c\r
+       {0x0E,0x06,0x3E,0x66,0x66,0x66,0x3B,0x00},      // d\r
+       {0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00},      // e\r
+       {0x1C,0x36,0x30,0x78,0x30,0x30,0x78,0x00},      // f\r
+       {0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x7C},      // g\r
+       {0x70,0x30,0x36,0x3B,0x33,0x33,0x73,0x00},      // h\r
+       {0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00},      // i\r
+       {0x06,0x00,0x06,0x06,0x06,0x66,0x66,0x3C},      // j\r
+       {0x70,0x30,0x33,0x36,0x3C,0x36,0x73,0x00},      // k\r
+       {0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00},      // l\r
+       {0x00,0x00,0x66,0x7F,0x7F,0x6B,0x63,0x00},      // m\r
+       {0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00},      // n\r
+       {0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00},      // o\r
+       {0x00,0x00,0x6E,0x33,0x33,0x3E,0x30,0x78},      // p\r
+       {0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x0F},      // q\r
+       {0x00,0x00,0x6E,0x3B,0x33,0x30,0x78,0x00},      // r\r
+       {0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00},      // s\r
+       {0x08,0x18,0x3E,0x18,0x18,0x1A,0x0C,0x00},      // t\r
+       {0x00,0x00,0x66,0x66,0x66,0x66,0x3B,0x00},      // u\r
+       {0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00},      // v\r
+       {0x00,0x00,0x63,0x6B,0x7F,0x7F,0x36,0x00},      // w\r
+       {0x00,0x00,0x63,0x36,0x1C,0x36,0x63,0x00},      // x\r
+       {0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x7C},      // y\r
+       {0x00,0x00,0x7E,0x4C,0x18,0x32,0x7E,0x00},      // z\r
+       {0x0E,0x18,0x18,0x70,0x18,0x18,0x0E,0x00},      // {\r
+       {0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x0C,0x00},      // |\r
+       {0x70,0x18,0x18,0x0E,0x18,0x18,0x70,0x00},      // }\r
+       {0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00},      // ~\r
+       {0x1C,0x36,0x36,0x1C,0x00,0x00,0x00,0x00}       // DEL\r
+};\r
+\r
+const char FONT8x16[97][16] = {\r
+       {0x08,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},      // columns, rows, bytes per char\r
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},      // space\r
+       {0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00},      // !\r
+       {0x00,0x63,0x63,0x63,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},      // "\r
+       {0x00,0x00,0x00,0x36,0x36,0x7F,0x36,0x36,0x36,0x7F,0x36,0x36,0x00,0x00,0x00,0x00},      // #\r
+       {0x0C,0x0C,0x3E,0x63,0x61,0x60,0x3E,0x03,0x03,0x43,0x63,0x3E,0x0C,0x0C,0x00,0x00},      // $\r
+       {0x00,0x00,0x00,0x00,0x00,0x61,0x63,0x06,0x0C,0x18,0x33,0x63,0x00,0x00,0x00,0x00},      // %\r
+       {0x00,0x00,0x00,0x1C,0x36,0x36,0x1C,0x3B,0x6E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00},      // &\r
+       {0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},      // '\r
+       {0x00,0x00,0x0C,0x18,0x18,0x30,0x30,0x30,0x30,0x18,0x18,0x0C,0x00,0x00,0x00,0x00},      // (\r
+       {0x00,0x00,0x18,0x0C,0x0C,0x06,0x06,0x06,0x06,0x0C,0x0C,0x18,0x00,0x00,0x00,0x00},      // )\r
+       {0x00,0x00,0x00,0x00,0x42,0x66,0x3C,0xFF,0x3C,0x66,0x42,0x00,0x00,0x00,0x00,0x00},      // *\r
+       {0x00,0x00,0x00,0x00,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00},      // +\r
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00},      // ,\r
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},      // -\r
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00},      // .\r
+       {0x00,0x00,0x01,0x03,0x07,0x0E,0x1C,0x38,0x70,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00},      // /\r
+       {0x00,0x00,0x3E,0x63,0x63,0x63,0x6B,0x6B,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00},      // 0\r
+       {0x00,0x00,0x0C,0x1C,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3F,0x00,0x00,0x00,0x00},      // 1\r
+       {0x00,0x00,0x3E,0x63,0x03,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00},      // 2\r
+       {0x00,0x00,0x3E,0x63,0x03,0x03,0x1E,0x03,0x03,0x03,0x63,0x3E,0x00,0x00,0x00,0x00},      // 3\r
+       {0x00,0x00,0x06,0x0E,0x1E,0x36,0x66,0x66,0x7F,0x06,0x06,0x0F,0x00,0x00,0x00,0x00},      // 4\r
+       {0x00,0x00,0x7F,0x60,0x60,0x60,0x7E,0x03,0x03,0x63,0x73,0x3E,0x00,0x00,0x00,0x00},      // 5\r
+       {0x00,0x00,0x1C,0x30,0x60,0x60,0x7E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00},      // 6\r
+       {0x00,0x00,0x7F,0x63,0x03,0x06,0x06,0x0C,0x0C,0x18,0x18,0x18,0x00,0x00,0x00,0x00},      // 7\r
+       {0x00,0x00,0x3E,0x63,0x63,0x63,0x3E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00},      // 8\r
+       {0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x3F,0x03,0x03,0x06,0x3C,0x00,0x00,0x00,0x00},      // 9\r
+       {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00},      // :\r
+       {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00},      // ;\r
+       {0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00},      // <\r
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00},      // =\r
+       {0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00},      // >\r
+       {0x00,0x00,0x3E,0x63,0x63,0x06,0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00},      // ?\r
+       {0x00,0x00,0x3E,0x63,0x63,0x6F,0x6B,0x6B,0x6E,0x60,0x60,0x3E,0x00,0x00,0x00,0x00},      // @\r
+       {0x00,0x00,0x08,0x1C,0x36,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x00,0x00,0x00,0x00},      // A\r
+       {0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x33,0x33,0x33,0x33,0x7E,0x00,0x00,0x00,0x00},      // B\r
+       {0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x60,0x60,0x61,0x33,0x1E,0x00,0x00,0x00,0x00},      // C\r
+       {0x00,0x00,0x7C,0x36,0x33,0x33,0x33,0x33,0x33,0x33,0x36,0x7C,0x00,0x00,0x00,0x00},      // D\r
+       {0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00},      // E\r
+       {0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00},      // F\r
+       {0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x6F,0x63,0x63,0x37,0x1D,0x00,0x00,0x00,0x00},      // G\r
+       {0x00,0x00,0x63,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00},      // H\r
+       {0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},      // I\r
+       {0x00,0x00,0x0F,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00,0x00,0x00},      // J\r
+       {0x00,0x00,0x73,0x33,0x36,0x36,0x3C,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00},      // K\r
+       {0x00,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00},      // L\r
+       {0x00,0x00,0x63,0x77,0x7F,0x6B,0x63,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00},      // M\r
+       {0x00,0x00,0x63,0x63,0x73,0x7B,0x7F,0x6F,0x67,0x63,0x63,0x63,0x00,0x00,0x00,0x00},      // N\r
+       {0x00,0x00,0x1C,0x36,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x00,0x00,0x00,0x00},      // O\r
+       {0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00},      // P\r
+       {0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x63,0x6B,0x6F,0x3E,0x06,0x07,0x00,0x00},      // Q\r
+       {0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00},      // R\r
+       {0x00,0x00,0x3E,0x63,0x63,0x30,0x1C,0x06,0x03,0x63,0x63,0x3E,0x00,0x00,0x00,0x00},      // S\r
+       {0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},      // T\r
+       {0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00},      // U\r
+       {0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x08,0x00,0x00,0x00,0x00},      // V\r
+       {0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x36,0x00,0x00,0x00,0x00},      // W\r
+       {0x00,0x00,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x3C,0x66,0xC3,0xC3,0x00,0x00,0x00,0x00},      // X\r
+       {0x00,0x00,0xC3,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},      // Y\r
+       {0x00,0x00,0x7F,0x63,0x43,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00},      // Z\r
+       {0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00},      // [\r
+       {0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x07,0x03,0x01,0x00,0x00,0x00,0x00},      // backslash\r
+       {0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00},      // ]\r
+       {0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},      // ^\r
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00},      // _\r
+       {0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},      // `\r
+       {0x00,0x00,0x00,0x00,0x00,0x3C,0x46,0x06,0x3E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00},      // a\r
+       {0x00,0x00,0x70,0x30,0x30,0x3C,0x36,0x33,0x33,0x33,0x33,0x6E,0x00,0x00,0x00,0x00},      // b\r
+       {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x60,0x60,0x60,0x63,0x3E,0x00,0x00,0x00,0x00},      // c\r
+       {0x00,0x00,0x0E,0x06,0x06,0x1E,0x36,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00},      // d\r
+       {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x7E,0x60,0x63,0x3E,0x00,0x00,0x00,0x00},      // e\r
+       {0x00,0x00,0x1C,0x36,0x32,0x30,0x7C,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00},      // f\r
+       {0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00,0x00},      // g\r
+       {0x00,0x00,0x70,0x30,0x30,0x36,0x3B,0x33,0x33,0x33,0x33,0x73,0x00,0x00,0x00,0x00},      // h\r
+       {0x00,0x00,0x0C,0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00},      // i\r
+       {0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00},      // j\r
+       {0x00,0x00,0x70,0x30,0x30,0x33,0x33,0x36,0x3C,0x36,0x33,0x73,0x00,0x00,0x00,0x00},      // k\r
+       {0x00,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00},      // l\r
+       {0x00,0x00,0x00,0x00,0x00,0x6E,0x7F,0x6B,0x6B,0x6B,0x6B,0x6B,0x00,0x00,0x00,0x00},      // m\r
+       {0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x00},      // n\r
+       {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00},      // o\r
+       {0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x3E,0x30,0x30,0x78,0x00,0x00},      // p\r
+       {0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x06,0x0F,0x00,0x00},      // q\r
+       {0x00,0x00,0x00,0x00,0x00,0x6E,0x3B,0x33,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00},      // r\r
+       {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x38,0x0E,0x03,0x63,0x3E,0x00,0x00,0x00,0x00},      // s\r
+       {0x00,0x00,0x08,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x1B,0x0E,0x00,0x00,0x00,0x00},      // t\r
+       {0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00},      // u\r
+       {0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x36,0x36,0x1C,0x1C,0x08,0x00,0x00,0x00,0x00},      // v\r
+       {0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x00,0x00,0x00,0x00},      // w\r
+       {0x00,0x00,0x00,0x00,0x00,0x63,0x36,0x1C,0x1C,0x1C,0x36,0x63,0x00,0x00,0x00,0x00},      // x\r
+       {0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x3F,0x03,0x06,0x3C,0x00,0x00},      // y\r
+       {0x00,0x00,0x00,0x00,0x00,0x7F,0x66,0x0C,0x18,0x30,0x63,0x7F,0x00,0x00,0x00,0x00},      // z\r
+       {0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00},      // {\r
+       {0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00},      // |\r
+       {0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00},      // }\r
+       {0x00,0x00,0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},      // ~\r
+       {0x00,0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}       // DEL\r
+};\r
+*/\r
diff --git a/armsrc/fonts.h b/armsrc/fonts.h
new file mode 100644 (file)
index 0000000..621a7f5
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __FONTS_H\r
+#define __FONTS_H\r
+extern const char FONT6x8[97][8];\r
+extern const char FONT8x8F[97][8];\r
+extern const char FONT8x16[97][16];\r
+#endif\r
diff --git a/armsrc/fpga.c b/armsrc/fpga.c
new file mode 100644 (file)
index 0000000..2bcade2
--- /dev/null
@@ -0,0 +1,222 @@
+//-----------------------------------------------------------------------------\r
+// Routines to load the FPGA image, and then to configure the FPGA's major\r
+// mode once it is configured.\r
+//\r
+// Jonathan Westhues, April 2006\r
+//-----------------------------------------------------------------------------\r
+#include <proxmark3.h>\r
+#include "apps.h"\r
+\r
+//-----------------------------------------------------------------------------\r
+// Set up the Serial Peripheral Interface as master\r
+// Used to write the FPGA config word\r
+// May also be used to write to other SPI attached devices like an LCD\r
+//-----------------------------------------------------------------------------\r
+void SetupSpi(int mode)\r
+{\r
+       // PA10 -> SPI_NCS2 chip select (LCD)\r
+       // PA11 -> SPI_NCS0 chip select (FPGA)\r
+       // PA12 -> SPI_MISO Master-In Slave-Out\r
+       // PA13 -> SPI_MOSI Master-Out Slave-In\r
+       // PA14 -> SPI_SPCK Serial Clock\r
+\r
+       // Disable PIO control of the following pins, allows use by the SPI peripheral\r
+       PIO_DISABLE                      =      (1 << GPIO_NCS0)        |\r
+                                                       (1 << GPIO_NCS2)        |\r
+                                                       (1 << GPIO_MISO)        |\r
+                                                       (1 << GPIO_MOSI)        |\r
+                                                       (1 << GPIO_SPCK);\r
+\r
+       PIO_PERIPHERAL_A_SEL =  (1 << GPIO_NCS0)        |\r
+                                                       (1 << GPIO_MISO)        |\r
+                                                       (1 << GPIO_MOSI)        |\r
+                                                       (1 << GPIO_SPCK);\r
+\r
+       PIO_PERIPHERAL_B_SEL =  (1 << GPIO_NCS2);\r
+\r
+       //enable the SPI Peripheral clock\r
+       PMC_PERIPHERAL_CLK_ENABLE = (1<<PERIPH_SPI);\r
+       // Enable SPI\r
+       SPI_CONTROL = SPI_CONTROL_ENABLE;\r
+\r
+       switch (mode) {\r
+               case SPI_FPGA_MODE:\r
+                       SPI_MODE =\r
+                               ( 0 << 24)      |       // Delay between chip selects (take default: 6 MCK periods)\r
+                               (14 << 16)      |       // Peripheral Chip Select (selects FPGA SPI_NCS0 or PA11)\r
+                               ( 0 << 7)       |       // Local Loopback Disabled\r
+                               ( 1 << 4)       |       // Mode Fault Detection disabled\r
+                               ( 0 << 2)       |       // Chip selects connected directly to peripheral\r
+                               ( 0 << 1)       |       // Fixed Peripheral Select\r
+                               ( 1 << 0);              // Master Mode\r
+                       SPI_FOR_CHIPSEL_0 =\r
+                               ( 1 << 24)      |       // Delay between Consecutive Transfers (32 MCK periods)\r
+                               ( 1 << 16)      |       // Delay Before SPCK (1 MCK period)\r
+                               ( 6 << 8)       |       // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud\r
+                               ( 0 << 4)       |       // Bits per Transfer (8 bits)\r
+                               ( 0 << 3)       |       // Chip Select inactive after transfer\r
+                               ( 1 << 1)       |       // Clock Phase data captured on leading edge, changes on following edge\r
+                               ( 0 << 0);              // Clock Polarity inactive state is logic 0\r
+                       break;\r
+               case SPI_LCD_MODE:\r
+                       SPI_MODE =\r
+                               ( 0 << 24)      |       // Delay between chip selects (take default: 6 MCK periods)\r
+                               (11 << 16)      |       // Peripheral Chip Select (selects LCD SPI_NCS2 or PA10)\r
+                               ( 0 << 7)       |       // Local Loopback Disabled\r
+                               ( 1 << 4)       |       // Mode Fault Detection disabled\r
+                               ( 0 << 2)       |       // Chip selects connected directly to peripheral\r
+                               ( 0 << 1)       |       // Fixed Peripheral Select\r
+                               ( 1 << 0);              // Master Mode\r
+                       SPI_FOR_CHIPSEL_2 =\r
+                               ( 1 << 24)      |       // Delay between Consecutive Transfers (32 MCK periods)\r
+                               ( 1 << 16)      |       // Delay Before SPCK (1 MCK period)\r
+                               ( 6 << 8)       |       // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud\r
+                               ( 1 << 4)       |       // Bits per Transfer (9 bits)\r
+                               ( 0 << 3)       |       // Chip Select inactive after transfer\r
+                               ( 1 << 1)       |       // Clock Phase data captured on leading edge, changes on following edge\r
+                               ( 0 << 0);              // Clock Polarity inactive state is logic 0\r
+                       break;\r
+               default:                                // Disable SPI\r
+                       SPI_CONTROL = SPI_CONTROL_DISABLE;\r
+                       break;\r
+       }\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Set up the synchronous serial port, with the one set of options that we\r
+// always use when we are talking to the FPGA. Both RX and TX are enabled.\r
+//-----------------------------------------------------------------------------\r
+void FpgaSetupSsc(void)\r
+{\r
+       // First configure the GPIOs, and get ourselves a clock.\r
+       PIO_PERIPHERAL_A_SEL =  (1 << GPIO_SSC_FRAME)   |\r
+                                                       (1 << GPIO_SSC_DIN)             |\r
+                                                       (1 << GPIO_SSC_DOUT)    |\r
+                                                       (1 << GPIO_SSC_CLK);\r
+       PIO_DISABLE = (1 << GPIO_SSC_DOUT);\r
+\r
+       PMC_PERIPHERAL_CLK_ENABLE = (1 << PERIPH_SSC);\r
+\r
+       // Now set up the SSC proper, starting from a known state.\r
+       SSC_CONTROL = SSC_CONTROL_RESET;\r
+\r
+       // RX clock comes from TX clock, RX starts when TX starts, data changes\r
+       // on RX clock rising edge, sampled on falling edge\r
+       SSC_RECEIVE_CLOCK_MODE = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1);\r
+\r
+       // 8 bits per transfer, no loopback, MSB first, 1 transfer per sync\r
+       // pulse, no output sync, start on positive-going edge of sync\r
+       SSC_RECEIVE_FRAME_MODE = SSC_FRAME_MODE_BITS_IN_WORD(8) |\r
+               SSC_FRAME_MODE_MSB_FIRST | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);\r
+\r
+       // clock comes from TK pin, no clock output, outputs change on falling\r
+       // edge of TK, start on rising edge of TF\r
+       SSC_TRANSMIT_CLOCK_MODE = SSC_CLOCK_MODE_SELECT(2) |\r
+               SSC_CLOCK_MODE_START(5);\r
+\r
+       // tx framing is the same as the rx framing\r
+       SSC_TRANSMIT_FRAME_MODE = SSC_RECEIVE_FRAME_MODE;\r
+\r
+       SSC_CONTROL = SSC_CONTROL_RX_ENABLE | SSC_CONTROL_TX_ENABLE;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Set up DMA to receive samples from the FPGA. We will use the PDC, with\r
+// a single buffer as a circular buffer (so that we just chain back to\r
+// ourselves, not to another buffer). The stuff to manipulate those buffers\r
+// is in apps.h, because it should be inlined, for speed.\r
+//-----------------------------------------------------------------------------\r
+void FpgaSetupSscDma(BYTE *buf, int len)\r
+{\r
+       PDC_RX_POINTER(SSC_BASE) = (DWORD)buf;\r
+       PDC_RX_COUNTER(SSC_BASE) = len;\r
+       PDC_RX_NEXT_POINTER(SSC_BASE) = (DWORD)buf;\r
+       PDC_RX_NEXT_COUNTER(SSC_BASE) = len;\r
+       PDC_CONTROL(SSC_BASE) = PDC_RX_ENABLE;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Download the FPGA image stored in flash (slave serial).\r
+//-----------------------------------------------------------------------------\r
+void FpgaDownloadAndGo(void)\r
+{\r
+       // FPGA image lives in FLASH at base address 0x2000\r
+       // The current board design can not accomodate anything bigger than a XC2S30\r
+       // FPGA and the config file size is fixed at 336,768 bits = 10,524 DWORDs\r
+       const DWORD *FpgaImage=((DWORD *)0x2000);\r
+       const DWORD FpgaImageLen=10524;\r
+\r
+       int i, j;\r
+\r
+       PIO_OUTPUT_ENABLE = (1 << GPIO_FPGA_ON);\r
+       PIO_ENABLE = (1 << GPIO_FPGA_ON);\r
+       PIO_OUTPUT_DATA_SET = (1 << GPIO_FPGA_ON);\r
+\r
+       SpinDelay(50);\r
+\r
+       LED_D_ON();\r
+\r
+       HIGH(GPIO_FPGA_NPROGRAM);\r
+       LOW(GPIO_FPGA_CCLK);\r
+       LOW(GPIO_FPGA_DIN);\r
+       PIO_OUTPUT_ENABLE = (1 << GPIO_FPGA_NPROGRAM)   |\r
+                                               (1 << GPIO_FPGA_CCLK)           |\r
+                                               (1 << GPIO_FPGA_DIN);\r
+       SpinDelay(1);\r
+\r
+       LOW(GPIO_FPGA_NPROGRAM);\r
+       SpinDelay(50);\r
+       HIGH(GPIO_FPGA_NPROGRAM);\r
+\r
+       for(i = 0; i < FpgaImageLen; i++) {\r
+               DWORD v = FpgaImage[i];\r
+               for(j = 0; j < 32; j++) {\r
+                       if(v & 0x80000000) {\r
+                               HIGH(GPIO_FPGA_DIN);\r
+                       } else {\r
+                               LOW(GPIO_FPGA_DIN);\r
+                       }\r
+                       HIGH(GPIO_FPGA_CCLK);\r
+                       LOW(GPIO_FPGA_CCLK);\r
+                       v <<= 1;\r
+               }\r
+       }\r
+\r
+       LED_D_OFF();\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Write the FPGA setup word (that determines what mode the logic is in, read\r
+// vs. clone vs. etc.).\r
+//-----------------------------------------------------------------------------\r
+void FpgaWriteConfWord(BYTE v)\r
+{\r
+       SetupSpi(SPI_FPGA_MODE);\r
+       while ((SPI_STATUS & SPI_STATUS_TX_EMPTY) == 0);        // wait for the transfer to complete\r
+       SPI_TX_DATA = SPI_CONTROL_LAST_TRANSFER | v;            // send the data\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Set up the CMOS switches that mux the ADC: four switches, independently\r
+// closable, but should only close one at a time. Not an FPGA thing, but\r
+// the samples from the ADC always flow through the FPGA.\r
+//-----------------------------------------------------------------------------\r
+void SetAdcMuxFor(int whichGpio)\r
+{\r
+       PIO_OUTPUT_ENABLE = (1 << GPIO_MUXSEL_HIPKD) |\r
+                                               (1 << GPIO_MUXSEL_LOPKD) |\r
+                                               (1 << GPIO_MUXSEL_LORAW) |\r
+                                               (1 << GPIO_MUXSEL_HIRAW);\r
+\r
+       PIO_ENABLE              =       (1 << GPIO_MUXSEL_HIPKD) |\r
+                                               (1 << GPIO_MUXSEL_LOPKD) |\r
+                                               (1 << GPIO_MUXSEL_LORAW) |\r
+                                               (1 << GPIO_MUXSEL_HIRAW);\r
+\r
+       LOW(GPIO_MUXSEL_HIPKD);\r
+       LOW(GPIO_MUXSEL_HIRAW);\r
+       LOW(GPIO_MUXSEL_LORAW);\r
+       LOW(GPIO_MUXSEL_LOPKD);\r
+\r
+       HIGH(whichGpio);\r
+}\r
diff --git a/armsrc/fpgaimg.c b/armsrc/fpgaimg.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/armsrc/iso14443.c b/armsrc/iso14443.c
new file mode 100644 (file)
index 0000000..2a079fd
--- /dev/null
@@ -0,0 +1,988 @@
+//-----------------------------------------------------------------------------\r
+// Routines to support ISO 14443. This includes both the reader software and\r
+// the `fake tag' modes. At the moment only the Type B modulation is\r
+// supported.\r
+// Jonathan Westhues, split Nov 2006\r
+//-----------------------------------------------------------------------------\r
+#include <proxmark3.h>\r
+#include "apps.h"\r
+#include "..\common\iso14443_crc.c"\r
+\r
+\r
+//static void GetSamplesFor14443(BOOL weTx, int n);\r
+\r
+#define DMA_BUFFER_SIZE 256\r
+\r
+//=============================================================================\r
+// An ISO 14443 Type B tag. We listen for commands from the reader, using\r
+// a UART kind of thing that's implemented in software. When we get a\r
+// frame (i.e., a group of bytes between SOF and EOF), we check the CRC.\r
+// If it's good, then we can do something appropriate with it, and send\r
+// a response.\r
+//=============================================================================\r
+\r
+//-----------------------------------------------------------------------------\r
+// Code up a string of octets at layer 2 (including CRC, we don't generate\r
+// that here) so that they can be transmitted to the reader. Doesn't transmit\r
+// them yet, just leaves them ready to send in ToSend[].\r
+//-----------------------------------------------------------------------------\r
+static void CodeIso14443bAsTag(const BYTE *cmd, int len)\r
+{\r
+    int i;\r
+\r
+    ToSendReset();\r
+\r
+    // Transmit a burst of ones, as the initial thing that lets the\r
+    // reader get phase sync. This (TR1) must be > 80/fs, per spec,\r
+    // but tag that I've tried (a Paypass) exceeds that by a fair bit,\r
+    // so I will too.\r
+    for(i = 0; i < 20; i++) {\r
+        ToSendStuffBit(1);\r
+        ToSendStuffBit(1);\r
+        ToSendStuffBit(1);\r
+        ToSendStuffBit(1);\r
+    }\r
+\r
+    // Send SOF.\r
+    for(i = 0; i < 10; i++) {\r
+        ToSendStuffBit(0);\r
+        ToSendStuffBit(0);\r
+        ToSendStuffBit(0);\r
+        ToSendStuffBit(0);\r
+    }\r
+    for(i = 0; i < 2; i++) {\r
+        ToSendStuffBit(1);\r
+        ToSendStuffBit(1);\r
+        ToSendStuffBit(1);\r
+        ToSendStuffBit(1);\r
+    }\r
+\r
+    for(i = 0; i < len; i++) {\r
+        int j;\r
+        BYTE b = cmd[i];\r
+\r
+        // Start bit\r
+        ToSendStuffBit(0);\r
+        ToSendStuffBit(0);\r
+        ToSendStuffBit(0);\r
+        ToSendStuffBit(0);\r
+\r
+        // Data bits\r
+        for(j = 0; j < 8; j++) {\r
+            if(b & 1) {\r
+                ToSendStuffBit(1);\r
+                ToSendStuffBit(1);\r
+                ToSendStuffBit(1);\r
+                ToSendStuffBit(1);\r
+            } else {\r
+                ToSendStuffBit(0);\r
+                ToSendStuffBit(0);\r
+                ToSendStuffBit(0);\r
+                ToSendStuffBit(0);\r
+            }\r
+            b >>= 1;\r
+        }\r
+\r
+        // Stop bit\r
+        ToSendStuffBit(1);\r
+        ToSendStuffBit(1);\r
+        ToSendStuffBit(1);\r
+        ToSendStuffBit(1);\r
+    }\r
+\r
+    // Send SOF.\r
+    for(i = 0; i < 10; i++) {\r
+        ToSendStuffBit(0);\r
+        ToSendStuffBit(0);\r
+        ToSendStuffBit(0);\r
+        ToSendStuffBit(0);\r
+    }\r
+    for(i = 0; i < 10; i++) {\r
+        ToSendStuffBit(1);\r
+        ToSendStuffBit(1);\r
+        ToSendStuffBit(1);\r
+        ToSendStuffBit(1);\r
+    }\r
+\r
+    // Convert from last byte pos to length\r
+    ToSendMax++;\r
+\r
+    // Add a few more for slop\r
+    ToSendMax += 2;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// The software UART that receives commands from the reader, and its state\r
+// variables.\r
+//-----------------------------------------------------------------------------\r
+static struct {\r
+    enum {\r
+        STATE_UNSYNCD,\r
+        STATE_GOT_FALLING_EDGE_OF_SOF,\r
+        STATE_AWAITING_START_BIT,\r
+        STATE_RECEIVING_DATA,\r
+        STATE_ERROR_WAIT\r
+    }       state;\r
+    WORD    shiftReg;\r
+    int     bitCnt;\r
+    int     byteCnt;\r
+    int     byteCntMax;\r
+    int     posCnt;\r
+    BYTE   *output;\r
+} Uart;\r
+\r
+static BOOL Handle14443UartBit(int bit)\r
+{\r
+    switch(Uart.state) {\r
+        case STATE_UNSYNCD:\r
+            if(!bit) {\r
+                // we went low, so this could be the beginning\r
+                // of an SOF\r
+                Uart.state = STATE_GOT_FALLING_EDGE_OF_SOF;\r
+                Uart.posCnt = 0;\r
+                Uart.bitCnt = 0;\r
+            }\r
+            break;\r
+\r
+        case STATE_GOT_FALLING_EDGE_OF_SOF:\r
+            Uart.posCnt++;\r
+            if(Uart.posCnt == 2) {\r
+                if(bit) {\r
+                    if(Uart.bitCnt >= 10) {\r
+                        // we've seen enough consecutive\r
+                        // zeros that it's a valid SOF\r
+                        Uart.posCnt = 0;\r
+                        Uart.byteCnt = 0;\r
+                        Uart.state = STATE_AWAITING_START_BIT;\r
+                    } else {\r
+                        // didn't stay down long enough\r
+                        // before going high, error\r
+                        Uart.state = STATE_ERROR_WAIT;\r
+                    }\r
+                } else {\r
+                    // do nothing, keep waiting\r
+                }\r
+                Uart.bitCnt++;\r
+            }\r
+            if(Uart.posCnt >= 4) Uart.posCnt = 0;\r
+            if(Uart.bitCnt > 14) {\r
+                // Give up if we see too many zeros without\r
+                // a one, too.\r
+                Uart.state = STATE_ERROR_WAIT;\r
+            }\r
+            break;\r
+\r
+        case STATE_AWAITING_START_BIT:\r
+            Uart.posCnt++;\r
+            if(bit) {\r
+                if(Uart.posCnt > 25) {\r
+                    // stayed high for too long between\r
+                    // characters, error\r
+                    Uart.state = STATE_ERROR_WAIT;\r
+                }\r
+            } else {\r
+                // falling edge, this starts the data byte\r
+                Uart.posCnt = 0;\r
+                Uart.bitCnt = 0;\r
+                Uart.shiftReg = 0;\r
+                Uart.state = STATE_RECEIVING_DATA;\r
+            }\r
+            break;\r
+\r
+        case STATE_RECEIVING_DATA:\r
+            Uart.posCnt++;\r
+            if(Uart.posCnt == 2) {\r
+                // time to sample a bit\r
+                Uart.shiftReg >>= 1;\r
+                if(bit) {\r
+                    Uart.shiftReg |= 0x200;\r
+                }\r
+                Uart.bitCnt++;\r
+            }\r
+            if(Uart.posCnt >= 4) {\r
+                Uart.posCnt = 0;\r
+            }\r
+            if(Uart.bitCnt == 10) {\r
+                if((Uart.shiftReg & 0x200) && !(Uart.shiftReg & 0x001))\r
+                {\r
+                    // this is a data byte, with correct\r
+                    // start and stop bits\r
+                    Uart.output[Uart.byteCnt] = (Uart.shiftReg >> 1) & 0xff;\r
+                    Uart.byteCnt++;\r
+\r
+                    if(Uart.byteCnt >= Uart.byteCntMax) {\r
+                        // Buffer overflowed, give up\r
+                        Uart.posCnt = 0;\r
+                        Uart.state = STATE_ERROR_WAIT;\r
+                    } else {\r
+                        // so get the next byte now\r
+                        Uart.posCnt = 0;\r
+                        Uart.state = STATE_AWAITING_START_BIT;\r
+                    }\r
+                } else if(Uart.shiftReg == 0x000) {\r
+                    // this is an EOF byte\r
+                    return TRUE;\r
+                } else {\r
+                    // this is an error\r
+                    Uart.posCnt = 0;\r
+                    Uart.state = STATE_ERROR_WAIT;\r
+                }\r
+            }\r
+            break;\r
+\r
+        case STATE_ERROR_WAIT:\r
+            // We're all screwed up, so wait a little while\r
+            // for whatever went wrong to finish, and then\r
+            // start over.\r
+            Uart.posCnt++;\r
+            if(Uart.posCnt > 10) {\r
+                Uart.state = STATE_UNSYNCD;\r
+            }\r
+            break;\r
+\r
+        default:\r
+            Uart.state = STATE_UNSYNCD;\r
+            break;\r
+    }\r
+\r
+    return FALSE;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Receive a command (from the reader to us, where we are the simulated tag),\r
+// and store it in the given buffer, up to the given maximum length. Keeps\r
+// spinning, waiting for a well-framed command, until either we get one\r
+// (returns TRUE) or someone presses the pushbutton on the board (FALSE).\r
+//\r
+// Assume that we're called with the SSC (to the FPGA) and ADC path set\r
+// correctly.\r
+//-----------------------------------------------------------------------------\r
+static BOOL GetIso14443CommandFromReader(BYTE *received, int *len, int maxLen)\r
+{\r
+    BYTE mask;\r
+    int i, bit;\r
+\r
+    // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen\r
+    // only, since we are receiving, not transmitting).\r
+    FpgaWriteConfWord(\r
+       FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION);\r
+\r
+\r
+    // Now run a `software UART' on the stream of incoming samples.\r
+    Uart.output = received;\r
+    Uart.byteCntMax = maxLen;\r
+    Uart.state = STATE_UNSYNCD;\r
+\r
+    for(;;) {\r
+        WDT_HIT();\r
+\r
+        if(BUTTON_PRESS()) return FALSE;\r
+\r
+        if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+            SSC_TRANSMIT_HOLDING = 0x00;\r
+        }\r
+        if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+            BYTE b = (BYTE)SSC_RECEIVE_HOLDING;\r
+\r
+            mask = 0x80;\r
+            for(i = 0; i < 8; i++, mask >>= 1) {\r
+                bit = (b & mask);\r
+                if(Handle14443UartBit(bit)) {\r
+                    *len = Uart.byteCnt;\r
+                    return TRUE;\r
+                }\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Main loop of simulated tag: receive commands from reader, decide what\r
+// response to send, and send it.\r
+//-----------------------------------------------------------------------------\r
+void SimulateIso14443Tag(void)\r
+{\r
+    static const BYTE cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };\r
+    static const BYTE response1[] = {\r
+        0x50, 0x82, 0x0d, 0xe1, 0x74, 0x20, 0x38, 0x19, 0x22,\r
+        0x00, 0x21, 0x85, 0x5e, 0xd7\r
+    };\r
+\r
+    BYTE *resp;\r
+    int respLen;\r
+\r
+    BYTE *resp1 = (((BYTE *)BigBuf) + 800);\r
+    int resp1Len;\r
+\r
+    BYTE *receivedCmd = (BYTE *)BigBuf;\r
+    int len;\r
+\r
+    int i;\r
+\r
+    int cmdsRecvd = 0;\r
+\r
+    memset(receivedCmd, 0x44, 400);\r
+\r
+    CodeIso14443bAsTag(response1, sizeof(response1));\r
+    memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax;\r
+\r
+    // We need to listen to the high-frequency, peak-detected path.\r
+    SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
+    FpgaSetupSsc();\r
+\r
+    cmdsRecvd = 0;\r
+\r
+    for(;;) {\r
+        BYTE b1, b2;\r
+\r
+        if(!GetIso14443CommandFromReader(receivedCmd, &len, 100)) {\r
+            DbpIntegers(cmdsRecvd, 0, 0);\r
+            DbpString("button press");\r
+            break;\r
+        }\r
+\r
+        // Good, look at the command now.\r
+\r
+        if(len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len)==0) {\r
+            resp = resp1; respLen = resp1Len;\r
+        } else {\r
+            DbpString("new cmd from reader:");\r
+            DbpIntegers(len, 0x1234, cmdsRecvd);\r
+            // And print whether the CRC fails, just for good measure\r
+            ComputeCrc14443(CRC_14443_B, receivedCmd, len-2, &b1, &b2);\r
+            if(b1 != receivedCmd[len-2] || b2 != receivedCmd[len-1]) {\r
+                // Not so good, try again.\r
+                DbpString("+++CRC fail");\r
+            } else {\r
+                DbpString("CRC passes");\r
+            }\r
+            break;\r
+        }\r
+\r
+        memset(receivedCmd, 0x44, 32);\r
+\r
+        cmdsRecvd++;\r
+\r
+        if(cmdsRecvd > 0x30) {\r
+            DbpString("many commands later...");\r
+            break;\r
+        }\r
+\r
+        if(respLen <= 0) continue;\r
+\r
+        // Modulate BPSK\r
+        FpgaWriteConfWord(\r
+               FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK);\r
+        SSC_TRANSMIT_HOLDING = 0xff;\r
+        FpgaSetupSsc();\r
+\r
+        // Transmit the response.\r
+        i = 0;\r
+        for(;;) {\r
+            if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+                BYTE b = resp[i];\r
+\r
+                SSC_TRANSMIT_HOLDING = b;\r
+\r
+                i++;\r
+                if(i > respLen) {\r
+                    break;\r
+                }\r
+            }\r
+            if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+                volatile BYTE b = (BYTE)SSC_RECEIVE_HOLDING;\r
+                (void)b;\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+//=============================================================================\r
+// An ISO 14443 Type B reader. We take layer two commands, code them\r
+// appropriately, and then send them to the tag. We then listen for the\r
+// tag's response, which we leave in the buffer to be demodulated on the\r
+// PC side.\r
+//=============================================================================\r
+\r
+static struct {\r
+    enum {\r
+        DEMOD_UNSYNCD,\r
+        DEMOD_PHASE_REF_TRAINING,\r
+        DEMOD_AWAITING_FALLING_EDGE_OF_SOF,\r
+        DEMOD_GOT_FALLING_EDGE_OF_SOF,\r
+        DEMOD_AWAITING_START_BIT,\r
+        DEMOD_RECEIVING_DATA,\r
+        DEMOD_ERROR_WAIT\r
+    }       state;\r
+    int     bitCount;\r
+    int     posCount;\r
+    int     thisBit;\r
+    int     metric;\r
+    int     metricN;\r
+    WORD    shiftReg;\r
+    BYTE   *output;\r
+    int     len;\r
+    int     sumI;\r
+    int     sumQ;\r
+} Demod;\r
+\r
+static BOOL Handle14443SamplesDemod(int ci, int cq)\r
+{\r
+    int v;\r
+\r
+    // The soft decision on the bit uses an estimate of just the\r
+    // quadrant of the reference angle, not the exact angle.\r
+#define MAKE_SOFT_DECISION() { \\r
+        if(Demod.sumI > 0) { \\r
+            v = ci; \\r
+        } else { \\r
+            v = -ci; \\r
+        } \\r
+        if(Demod.sumQ > 0) { \\r
+            v += cq; \\r
+        } else { \\r
+            v -= cq; \\r
+        } \\r
+    }\r
+\r
+    switch(Demod.state) {\r
+        case DEMOD_UNSYNCD:\r
+            v = ci;\r
+            if(v < 0) v = -v;\r
+            if(cq > 0) {\r
+                v += cq;\r
+            } else {\r
+                v -= cq;\r
+            }\r
+            if(v > 40) {\r
+                Demod.posCount = 0;\r
+                Demod.state = DEMOD_PHASE_REF_TRAINING;\r
+                Demod.sumI = 0;\r
+                Demod.sumQ = 0;\r
+            }\r
+            break;\r
+\r
+        case DEMOD_PHASE_REF_TRAINING:\r
+            if(Demod.posCount < 8) {\r
+                Demod.sumI += ci;\r
+                Demod.sumQ += cq;\r
+            } else if(Demod.posCount > 100) {\r
+                // error, waited too long\r
+                Demod.state = DEMOD_UNSYNCD;\r
+            } else {\r
+                MAKE_SOFT_DECISION();\r
+                if(v < 0) {\r
+                    Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF;\r
+                    Demod.posCount = 0;\r
+                }\r
+            }\r
+            Demod.posCount++;\r
+            break;\r
+\r
+        case DEMOD_AWAITING_FALLING_EDGE_OF_SOF:\r
+            MAKE_SOFT_DECISION();\r
+            if(v < 0) {\r
+                Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF;\r
+                Demod.posCount = 0;\r
+            } else {\r
+                if(Demod.posCount > 100) {\r
+                    Demod.state = DEMOD_UNSYNCD;\r
+                }\r
+            }\r
+            Demod.posCount++;\r
+            break;\r
+\r
+        case DEMOD_GOT_FALLING_EDGE_OF_SOF:\r
+            MAKE_SOFT_DECISION();\r
+            if(v > 0) {\r
+                if(Demod.posCount < 12) {\r
+                    Demod.state = DEMOD_UNSYNCD;\r
+                } else {\r
+                    Demod.state = DEMOD_AWAITING_START_BIT;\r
+                    Demod.posCount = 0;\r
+                    Demod.len = 0;\r
+                    Demod.metricN = 0;\r
+                    Demod.metric = 0;\r
+                }\r
+            } else {\r
+                if(Demod.posCount > 100) {\r
+                    Demod.state = DEMOD_UNSYNCD;\r
+                }\r
+            }\r
+            Demod.posCount++;\r
+            break;\r
+\r
+        case DEMOD_AWAITING_START_BIT:\r
+            MAKE_SOFT_DECISION();\r
+            if(v > 0) {\r
+                if(Demod.posCount > 10) {\r
+                    Demod.state = DEMOD_UNSYNCD;\r
+                }\r
+            } else {\r
+                Demod.bitCount = 0;\r
+                Demod.posCount = 1;\r
+                Demod.thisBit = v;\r
+                Demod.shiftReg = 0;\r
+                Demod.state = DEMOD_RECEIVING_DATA;\r
+            }\r
+            break;\r
+\r
+        case DEMOD_RECEIVING_DATA:\r
+            MAKE_SOFT_DECISION();\r
+            if(Demod.posCount == 0) {\r
+                Demod.thisBit = v;\r
+                Demod.posCount = 1;\r
+            } else {\r
+                Demod.thisBit += v;\r
+\r
+                if(Demod.thisBit > 0) {\r
+                    Demod.metric += Demod.thisBit;\r
+                } else {\r
+                    Demod.metric -= Demod.thisBit;\r
+                }\r
+                (Demod.metricN)++;\r
+\r
+                Demod.shiftReg >>= 1;\r
+                if(Demod.thisBit > 0) {\r
+                    Demod.shiftReg |= 0x200;\r
+                }\r
+\r
+                Demod.bitCount++;\r
+                if(Demod.bitCount == 10) {\r
+                    WORD s = Demod.shiftReg;\r
+                    if((s & 0x200) && !(s & 0x001)) {\r
+                        BYTE b = (s >> 1);\r
+                        Demod.output[Demod.len] = b;\r
+                        Demod.len++;\r
+                        Demod.state = DEMOD_AWAITING_START_BIT;\r
+                    } else if(s == 0x000) {\r
+                        // This is EOF\r
+                        return TRUE;\r
+                        Demod.state = DEMOD_UNSYNCD;\r
+                    } else {\r
+                        Demod.state = DEMOD_UNSYNCD;\r
+                    }\r
+                }\r
+                Demod.posCount = 0;\r
+            }\r
+            break;\r
+\r
+        default:\r
+            Demod.state = DEMOD_UNSYNCD;\r
+            break;\r
+    }\r
+\r
+    return FALSE;\r
+}\r
+\r
+static void GetSamplesFor14443Demod(BOOL weTx, int n)\r
+{\r
+    int max = 0;\r
+    BOOL gotFrame = FALSE;\r
+\r
+//#   define DMA_BUFFER_SIZE 8\r
+    SBYTE *dmaBuf;\r
+\r
+    int lastRxCounter;\r
+    SBYTE *upTo;\r
+\r
+    int ci, cq;\r
+\r
+    int samples = 0;\r
+\r
+    // Clear out the state of the "UART" that receives from the tag.\r
+    memset(BigBuf, 0x44, 400);\r
+    Demod.output = (BYTE *)BigBuf;\r
+    Demod.len = 0;\r
+    Demod.state = DEMOD_UNSYNCD;\r
+\r
+    // And the UART that receives from the reader\r
+    Uart.output = (((BYTE *)BigBuf) + 1024);\r
+    Uart.byteCntMax = 100;\r
+    Uart.state = STATE_UNSYNCD;\r
+\r
+    // Setup for the DMA.\r
+    dmaBuf = (SBYTE *)(BigBuf + 32);\r
+    upTo = dmaBuf;\r
+    lastRxCounter = DMA_BUFFER_SIZE;\r
+    FpgaSetupSscDma((BYTE *)dmaBuf, DMA_BUFFER_SIZE);\r
+\r
+    // And put the FPGA in the appropriate mode\r
+    FpgaWriteConfWord(\r
+       FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |\r
+       (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP));\r
+\r
+    for(;;) {\r
+        int behindBy = lastRxCounter - PDC_RX_COUNTER(SSC_BASE);\r
+        if(behindBy > max) max = behindBy;\r
+\r
+        LED_D_ON();\r
+        while(((lastRxCounter-PDC_RX_COUNTER(SSC_BASE)) & (DMA_BUFFER_SIZE-1))\r
+                    > 2)\r
+        {\r
+            ci = upTo[0];\r
+            cq = upTo[1];\r
+            upTo += 2;\r
+            if(upTo - dmaBuf > DMA_BUFFER_SIZE) {\r
+                upTo -= DMA_BUFFER_SIZE;\r
+                PDC_RX_NEXT_POINTER(SSC_BASE) = (DWORD)upTo;\r
+                PDC_RX_NEXT_COUNTER(SSC_BASE) = DMA_BUFFER_SIZE;\r
+            }\r
+            lastRxCounter -= 2;\r
+            if(lastRxCounter <= 0) {\r
+                lastRxCounter += DMA_BUFFER_SIZE;\r
+            }\r
+\r
+            samples += 2;\r
+\r
+            Handle14443UartBit(1);\r
+            Handle14443UartBit(1);\r
+\r
+            if(Handle14443SamplesDemod(ci, cq)) {\r
+                gotFrame = 1;\r
+            }\r
+        }\r
+        LED_D_OFF();\r
+\r
+        if(samples > 2000) {\r
+            break;\r
+        }\r
+    }\r
+    PDC_CONTROL(SSC_BASE) = PDC_RX_DISABLE;\r
+    DbpIntegers(max, gotFrame, -1);\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Read the tag's response. We just receive a stream of slightly-processed\r
+// samples from the FPGA, which we will later do some signal processing on,\r
+// to get the bits.\r
+//-----------------------------------------------------------------------------\r
+/*static void GetSamplesFor14443(BOOL weTx, int n)\r
+{\r
+    BYTE *dest = (BYTE *)BigBuf;\r
+    int c;\r
+\r
+    FpgaWriteConfWord(\r
+       FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |\r
+       (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP));\r
+\r
+    c = 0;\r
+    for(;;) {\r
+        if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+            SSC_TRANSMIT_HOLDING = 0x43;\r
+        }\r
+        if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+            SBYTE b;\r
+            b = (SBYTE)SSC_RECEIVE_HOLDING;\r
+\r
+            dest[c++] = (BYTE)b;\r
+\r
+            if(c >= n) {\r
+                break;\r
+            }\r
+        }\r
+    }\r
+}*/\r
+\r
+//-----------------------------------------------------------------------------\r
+// Transmit the command (to the tag) that was placed in ToSend[].\r
+//-----------------------------------------------------------------------------\r
+static void TransmitFor14443(void)\r
+{\r
+    int c;\r
+\r
+    FpgaSetupSsc();\r
+\r
+    while(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+        SSC_TRANSMIT_HOLDING = 0xff;\r
+    }\r
+\r
+    FpgaWriteConfWord(\r
+       FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);\r
+\r
+    for(c = 0; c < 10;) {\r
+        if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+            SSC_TRANSMIT_HOLDING = 0xff;\r
+            c++;\r
+        }\r
+        if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+            volatile DWORD r = SSC_RECEIVE_HOLDING;\r
+            (void)r;\r
+        }\r
+        WDT_HIT();\r
+    }\r
+\r
+    c = 0;\r
+    for(;;) {\r
+        if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+            SSC_TRANSMIT_HOLDING = ToSend[c];\r
+            c++;\r
+            if(c >= ToSendMax) {\r
+                break;\r
+            }\r
+        }\r
+        if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+            volatile DWORD r = SSC_RECEIVE_HOLDING;\r
+            (void)r;\r
+        }\r
+        WDT_HIT();\r
+    }\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Code a layer 2 command (string of octets, including CRC) into ToSend[],\r
+// so that it is ready to transmit to the tag using TransmitFor14443().\r
+//-----------------------------------------------------------------------------\r
+void CodeIso14443bAsReader(const BYTE *cmd, int len)\r
+{\r
+    int i, j;\r
+    BYTE b;\r
+\r
+    ToSendReset();\r
+\r
+    // Establish initial reference level\r
+    for(i = 0; i < 40; i++) {\r
+        ToSendStuffBit(1);\r
+    }\r
+    // Send SOF\r
+    for(i = 0; i < 10; i++) {\r
+        ToSendStuffBit(0);\r
+    }\r
+\r
+    for(i = 0; i < len; i++) {\r
+        // Stop bits/EGT\r
+        ToSendStuffBit(1);\r
+        ToSendStuffBit(1);\r
+        // Start bit\r
+        ToSendStuffBit(0);\r
+        // Data bits\r
+        b = cmd[i];\r
+        for(j = 0; j < 8; j++) {\r
+            if(b & 1) {\r
+                ToSendStuffBit(1);\r
+            } else {\r
+                ToSendStuffBit(0);\r
+            }\r
+            b >>= 1;\r
+        }\r
+    }\r
+    // Send EOF\r
+    ToSendStuffBit(1);\r
+    for(i = 0; i < 10; i++) {\r
+        ToSendStuffBit(0);\r
+    }\r
+    for(i = 0; i < 8; i++) {\r
+        ToSendStuffBit(1);\r
+    }\r
+\r
+    // And then a little more, to make sure that the last character makes\r
+    // it out before we switch to rx mode.\r
+    for(i = 0; i < 24; i++) {\r
+        ToSendStuffBit(1);\r
+    }\r
+\r
+    // Convert from last character reference to length\r
+    ToSendMax++;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Read an ISO 14443 tag. We send it some set of commands, and record the\r
+// responses.\r
+//-----------------------------------------------------------------------------\r
+void AcquireRawAdcSamplesIso14443(DWORD parameter)\r
+{\r
+//    BYTE cmd1[] = { 0x05, 0x00, 0x00, 0x71, 0xff };\r
+    BYTE cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };\r
+\r
+    // Make sure that we start from off, since the tags are stateful;\r
+    // confusing things will happen if we don't reset them between reads.\r
+    LED_D_OFF();\r
+    FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
+    SpinDelay(200);\r
+\r
+    SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
+    FpgaSetupSsc();\r
+\r
+    // Now give it time to spin up.\r
+    FpgaWriteConfWord(\r
+       FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);\r
+    SpinDelay(200);\r
+\r
+    CodeIso14443bAsReader(cmd1, sizeof(cmd1));\r
+    TransmitFor14443();\r
+    LED_A_ON();\r
+    GetSamplesFor14443Demod(TRUE, 2000);\r
+    LED_A_OFF();\r
+}\r
+\r
+//=============================================================================\r
+// Finally, the `sniffer' combines elements from both the reader and\r
+// simulated tag, to show both sides of the conversation.\r
+//=============================================================================\r
+\r
+//-----------------------------------------------------------------------------\r
+// Record the sequence of commands sent by the reader to the tag, with\r
+// triggering so that we start recording at the point that the tag is moved\r
+// near the reader.\r
+//-----------------------------------------------------------------------------\r
+void SnoopIso14443(void)\r
+{\r
+    // We won't start recording the frames that we acquire until we trigger;\r
+    // a good trigger condition to get started is probably when we see a\r
+    // response from the tag.\r
+    BOOL triggered = FALSE;\r
+\r
+    // The command (reader -> tag) that we're working on receiving.\r
+    BYTE *receivedCmd = (((BYTE *)BigBuf) + 1024);\r
+    // The response (tag -> reader) that we're working on receiving.\r
+    BYTE *receivedResponse = (((BYTE *)BigBuf) + 1536);\r
+\r
+    // As we receive stuff, we copy it from receivedCmd or receivedResponse\r
+    // into trace, along with its length and other annotations.\r
+    BYTE *trace = (BYTE *)BigBuf;\r
+    int traceLen = 0;\r
+\r
+    // The DMA buffer, used to stream samples from the FPGA.\r
+//#   define DMA_BUFFER_SIZE 256\r
+    SBYTE *dmaBuf = ((SBYTE *)BigBuf) + 2048;\r
+    int lastRxCounter;\r
+    SBYTE *upTo;\r
+    int ci, cq;\r
+    int maxBehindBy = 0;\r
+\r
+    // Count of samples received so far, so that we can include timing\r
+    // information in the trace buffer.\r
+    int samples = 0;\r
+\r
+    memset(trace, 0x44, 1000);\r
+\r
+    // Set up the demodulator for tag -> reader responses.\r
+    Demod.output = receivedResponse;\r
+    Demod.len = 0;\r
+    Demod.state = DEMOD_UNSYNCD;\r
+\r
+    // And the reader -> tag commands\r
+    memset(&Uart, 0, sizeof(Uart));\r
+    Uart.output = receivedCmd;\r
+    Uart.byteCntMax = 100;\r
+    Uart.state = STATE_UNSYNCD;\r
+\r
+    // And put the FPGA in the appropriate mode\r
+    FpgaWriteConfWord(\r
+       FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |\r
+       FPGA_HF_READER_RX_XCORR_SNOOP);\r
+    SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
+\r
+    // Setup for the DMA.\r
+    FpgaSetupSsc();\r
+    upTo = dmaBuf;\r
+    lastRxCounter = DMA_BUFFER_SIZE;\r
+    FpgaSetupSscDma((BYTE *)dmaBuf, DMA_BUFFER_SIZE);\r
+\r
+    LED_A_ON();\r
+\r
+    // And now we loop, receiving samples.\r
+    for(;;) {\r
+        int behindBy = (lastRxCounter - PDC_RX_COUNTER(SSC_BASE)) &\r
+                                (DMA_BUFFER_SIZE-1);\r
+        if(behindBy > maxBehindBy) {\r
+            maxBehindBy = behindBy;\r
+            if(behindBy > 100) {\r
+                DbpString("blew circular buffer!");\r
+                goto done;\r
+            }\r
+        }\r
+        if(behindBy < 2) continue;\r
+\r
+        ci = upTo[0];\r
+        cq = upTo[1];\r
+        upTo += 2;\r
+        lastRxCounter -= 2;\r
+        if(upTo - dmaBuf > DMA_BUFFER_SIZE) {\r
+            upTo -= DMA_BUFFER_SIZE;\r
+            lastRxCounter += DMA_BUFFER_SIZE;\r
+            PDC_RX_NEXT_POINTER(SSC_BASE) = (DWORD)upTo;\r
+            PDC_RX_NEXT_COUNTER(SSC_BASE) = DMA_BUFFER_SIZE;\r
+        }\r
+\r
+        samples += 2;\r
+\r
+#define HANDLE_BIT_IF_BODY \\r
+            if(triggered) { \\r
+                trace[traceLen++] = ((samples >>  0) & 0xff); \\r
+                trace[traceLen++] = ((samples >>  8) & 0xff); \\r
+                trace[traceLen++] = ((samples >> 16) & 0xff); \\r
+                trace[traceLen++] = ((samples >> 24) & 0xff); \\r
+                trace[traceLen++] = 0; \\r
+                trace[traceLen++] = 0; \\r
+                trace[traceLen++] = 0; \\r
+                trace[traceLen++] = 0; \\r
+                trace[traceLen++] = Uart.byteCnt; \\r
+                memcpy(trace+traceLen, receivedCmd, Uart.byteCnt); \\r
+                traceLen += Uart.byteCnt; \\r
+                if(traceLen > 1000) break; \\r
+            } \\r
+            /* And ready to receive another command. */ \\r
+            memset(&Uart, 0, sizeof(Uart)); \\r
+            Uart.output = receivedCmd; \\r
+            Uart.byteCntMax = 100; \\r
+            Uart.state = STATE_UNSYNCD; \\r
+            /* And also reset the demod code, which might have been */ \\r
+            /* false-triggered by the commands from the reader. */ \\r
+            memset(&Demod, 0, sizeof(Demod)); \\r
+            Demod.output = receivedResponse; \\r
+            Demod.state = DEMOD_UNSYNCD; \\r
+\r
+        if(Handle14443UartBit(ci & 1)) {\r
+            HANDLE_BIT_IF_BODY\r
+        }\r
+        if(Handle14443UartBit(cq & 1)) {\r
+            HANDLE_BIT_IF_BODY\r
+        }\r
+\r
+        if(Handle14443SamplesDemod(ci, cq)) {\r
+            // timestamp, as a count of samples\r
+            trace[traceLen++] = ((samples >>  0) & 0xff);\r
+            trace[traceLen++] = ((samples >>  8) & 0xff);\r
+            trace[traceLen++] = ((samples >> 16) & 0xff);\r
+            trace[traceLen++] = 0x80 | ((samples >> 24) & 0xff);\r
+            // correlation metric (~signal strength estimate)\r
+            if(Demod.metricN != 0) {\r
+                Demod.metric /= Demod.metricN;\r
+            }\r
+            trace[traceLen++] = ((Demod.metric >>  0) & 0xff);\r
+            trace[traceLen++] = ((Demod.metric >>  8) & 0xff);\r
+            trace[traceLen++] = ((Demod.metric >> 16) & 0xff);\r
+            trace[traceLen++] = ((Demod.metric >> 24) & 0xff);\r
+            // length\r
+            trace[traceLen++] = Demod.len;\r
+            memcpy(trace+traceLen, receivedResponse, Demod.len);\r
+            traceLen += Demod.len;\r
+            if(traceLen > 1000) break;\r
+\r
+            triggered = TRUE;\r
+            LED_A_OFF();\r
+            LED_B_ON();\r
+\r
+            // And ready to receive another response.\r
+            memset(&Demod, 0, sizeof(Demod));\r
+            Demod.output = receivedResponse;\r
+            Demod.state = DEMOD_UNSYNCD;\r
+        }\r
+\r
+        if(BUTTON_PRESS()) {\r
+            DbpString("cancelled");\r
+            goto done;\r
+        }\r
+    }\r
+\r
+    DbpString("in done pt");\r
+\r
+    DbpIntegers(maxBehindBy, Uart.state, Uart.byteCnt);\r
+    DbpIntegers(Uart.byteCntMax, traceLen, 0x23);\r
+\r
+done:\r
+    PDC_CONTROL(SSC_BASE) = PDC_RX_DISABLE;\r
+    LED_A_OFF();\r
+    LED_B_OFF();\r
+}\r
diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c
new file mode 100644 (file)
index 0000000..a687d87
--- /dev/null
@@ -0,0 +1,1815 @@
+//-----------------------------------------------------------------------------\r
+// Routines to support ISO 14443 type A.\r
+//\r
+// Gerhard de Koning Gans - May 2008\r
+//-----------------------------------------------------------------------------\r
+#include <proxmark3.h>\r
+#include "apps.h"\r
+#include "..\common\iso14443_crc.c"\r
+\r
+typedef enum {\r
+       SEC_D = 1,\r
+       SEC_E = 2,\r
+       SEC_F = 3,\r
+       SEC_X = 4,\r
+       SEC_Y = 5,\r
+       SEC_Z = 6\r
+} SecType;\r
+\r
+//-----------------------------------------------------------------------------\r
+// The software UART that receives commands from the reader, and its state\r
+// variables.\r
+//-----------------------------------------------------------------------------\r
+static struct {\r
+    enum {\r
+        STATE_UNSYNCD,\r
+        STATE_START_OF_COMMUNICATION,\r
+               STATE_MILLER_X,\r
+               STATE_MILLER_Y,\r
+               STATE_MILLER_Z,\r
+        STATE_ERROR_WAIT\r
+    }       state;\r
+    WORD    shiftReg;\r
+    int     bitCnt;\r
+    int     byteCnt;\r
+    int     byteCntMax;\r
+    int     posCnt;\r
+    int     syncBit;\r
+       int     parityBits;\r
+       int     samples;\r
+    int     highCnt;\r
+    int     bitBuffer;\r
+       enum {\r
+               DROP_NONE,\r
+               DROP_FIRST_HALF,\r
+               DROP_SECOND_HALF\r
+       }               drop;\r
+    BYTE   *output;\r
+} Uart;\r
+\r
+static BOOL MillerDecoding(int bit)\r
+{\r
+       int error = 0;\r
+       int bitright;\r
+\r
+       if(!Uart.bitBuffer) {\r
+               Uart.bitBuffer = bit ^ 0xFF0;\r
+               return FALSE;\r
+       }\r
+       else {\r
+               Uart.bitBuffer <<= 4;\r
+               Uart.bitBuffer ^= bit;\r
+       }\r
+\r
+       BOOL EOC = FALSE;\r
+\r
+       if(Uart.state != STATE_UNSYNCD) {\r
+               Uart.posCnt++;\r
+\r
+               if((Uart.bitBuffer & Uart.syncBit) ^ Uart.syncBit) {\r
+                       bit = 0x00;\r
+               }\r
+               else {\r
+                       bit = 0x01;\r
+               }\r
+               if(((Uart.bitBuffer << 1) & Uart.syncBit) ^ Uart.syncBit) {\r
+                       bitright = 0x00;\r
+               }\r
+               else {\r
+                       bitright = 0x01;\r
+               }\r
+               if(bit != bitright) { bit = bitright; }\r
+\r
+               if(Uart.posCnt == 1) {\r
+                       // measurement first half bitperiod\r
+                       if(!bit) {\r
+                               Uart.drop = DROP_FIRST_HALF;\r
+                       }\r
+               }\r
+               else {\r
+                       // measurement second half bitperiod\r
+                       if(!bit & (Uart.drop == DROP_NONE)) {\r
+                               Uart.drop = DROP_SECOND_HALF;\r
+                       }\r
+                       else if(!bit) {\r
+                               // measured a drop in first and second half\r
+                               // which should not be possible\r
+                               Uart.state = STATE_ERROR_WAIT;\r
+                               error = 0x01;\r
+                       }\r
+\r
+                       Uart.posCnt = 0;\r
+\r
+                       switch(Uart.state) {\r
+                               case STATE_START_OF_COMMUNICATION:\r
+                                       Uart.shiftReg = 0;\r
+                                       if(Uart.drop == DROP_SECOND_HALF) {\r
+                                               // error, should not happen in SOC\r
+                                               Uart.state = STATE_ERROR_WAIT;\r
+                                               error = 0x02;\r
+                                       }\r
+                                       else {\r
+                                               // correct SOC\r
+                                               Uart.state = STATE_MILLER_Z;\r
+                                       }\r
+                                       break;\r
+\r
+                               case STATE_MILLER_Z:\r
+                                       Uart.bitCnt++;\r
+                                       Uart.shiftReg >>= 1;\r
+                                       if(Uart.drop == DROP_NONE) {\r
+                                               // logic '0' followed by sequence Y\r
+                                               // end of communication\r
+                                               Uart.state = STATE_UNSYNCD;\r
+                                               EOC = TRUE;\r
+                                       }\r
+                                       // if(Uart.drop == DROP_FIRST_HALF) {\r
+                                       //      Uart.state = STATE_MILLER_Z; stay the same\r
+                                       //      we see a logic '0' }\r
+                                       if(Uart.drop == DROP_SECOND_HALF) {\r
+                                               // we see a logic '1'\r
+                                               Uart.shiftReg |= 0x100;\r
+                                               Uart.state = STATE_MILLER_X;\r
+                                       }\r
+                                       break;\r
+\r
+                               case STATE_MILLER_X:\r
+                                       Uart.shiftReg >>= 1;\r
+                                       if(Uart.drop == DROP_NONE) {\r
+                                               // sequence Y, we see a '0'\r
+                                               Uart.state = STATE_MILLER_Y;\r
+                                               Uart.bitCnt++;\r
+                                       }\r
+                                       if(Uart.drop == DROP_FIRST_HALF) {\r
+                                               // Would be STATE_MILLER_Z\r
+                                               // but Z does not follow X, so error\r
+                                               Uart.state = STATE_ERROR_WAIT;\r
+                                               error = 0x03;\r
+                                       }\r
+                                       if(Uart.drop == DROP_SECOND_HALF) {\r
+                                               // We see a '1' and stay in state X\r
+                                               Uart.shiftReg |= 0x100;\r
+                                               Uart.bitCnt++;\r
+                                       }\r
+                                       break;\r
+\r
+                               case STATE_MILLER_Y:\r
+                                       Uart.bitCnt++;\r
+                                       Uart.shiftReg >>= 1;\r
+                                       if(Uart.drop == DROP_NONE) {\r
+                                               // logic '0' followed by sequence Y\r
+                                               // end of communication\r
+                                               Uart.state = STATE_UNSYNCD;\r
+                                               EOC = TRUE;\r
+                                       }\r
+                                       if(Uart.drop == DROP_FIRST_HALF) {\r
+                                               // we see a '0'\r
+                                               Uart.state = STATE_MILLER_Z;\r
+                                       }\r
+                                       if(Uart.drop == DROP_SECOND_HALF) {\r
+                                               // We see a '1' and go to state X\r
+                                               Uart.shiftReg |= 0x100;\r
+                                               Uart.state = STATE_MILLER_X;\r
+                                       }\r
+                                       break;\r
+\r
+                               case STATE_ERROR_WAIT:\r
+                                       // That went wrong. Now wait for at least two bit periods\r
+                                       // and try to sync again\r
+                                       if(Uart.drop == DROP_NONE) {\r
+                                               Uart.highCnt = 6;\r
+                                               Uart.state = STATE_UNSYNCD;\r
+                                       }\r
+                                       break;\r
+\r
+                               default:\r
+                                       Uart.state = STATE_UNSYNCD;\r
+                                       Uart.highCnt = 0;\r
+                                       break;\r
+                       }\r
+\r
+                       Uart.drop = DROP_NONE;\r
+\r
+                       // should have received at least one whole byte...\r
+                       if((Uart.bitCnt == 2) && EOC && (Uart.byteCnt > 0)) {\r
+                               return TRUE;\r
+                       }\r
+\r
+                       if(Uart.bitCnt == 9) {\r
+                               Uart.output[Uart.byteCnt] = (Uart.shiftReg & 0xff);\r
+                               Uart.byteCnt++;\r
+\r
+                               Uart.parityBits <<= 1;\r
+                               Uart.parityBits ^= ((Uart.shiftReg >> 8) & 0x01);\r
+\r
+                               if(EOC) {\r
+                                       // when End of Communication received and\r
+                                       // all data bits processed..\r
+                                       return TRUE;\r
+                               }\r
+                               Uart.bitCnt = 0;\r
+                       }\r
+\r
+                       /*if(error) {\r
+                               Uart.output[Uart.byteCnt] = 0xAA;\r
+                               Uart.byteCnt++;\r
+                               Uart.output[Uart.byteCnt] = error & 0xFF;\r
+                               Uart.byteCnt++;\r
+                               Uart.output[Uart.byteCnt] = 0xAA;\r
+                               Uart.byteCnt++;\r
+                               Uart.output[Uart.byteCnt] = (Uart.bitBuffer >> 8) & 0xFF;\r
+                               Uart.byteCnt++;\r
+                               Uart.output[Uart.byteCnt] = Uart.bitBuffer & 0xFF;\r
+                               Uart.byteCnt++;\r
+                               Uart.output[Uart.byteCnt] = (Uart.syncBit >> 3) & 0xFF;\r
+                               Uart.byteCnt++;\r
+                               Uart.output[Uart.byteCnt] = 0xAA;\r
+                               Uart.byteCnt++;\r
+                               return TRUE;\r
+                       }*/\r
+               }\r
+\r
+       }\r
+       else {\r
+               bit = Uart.bitBuffer & 0xf0;\r
+               bit >>= 4;\r
+               bit ^= 0x0F;\r
+               if(bit) {\r
+                       // should have been high or at least (4 * 128) / fc\r
+                       // according to ISO this should be at least (9 * 128 + 20) / fc\r
+                       if(Uart.highCnt == 8) {\r
+                               // we went low, so this could be start of communication\r
+                               // it turns out to be safer to choose a less significant\r
+                               // syncbit... so we check whether the neighbour also represents the drop\r
+                               Uart.posCnt = 1;   // apparently we are busy with our first half bit period\r
+                               Uart.syncBit = bit & 8;\r
+                               Uart.samples = 3;\r
+                               if(!Uart.syncBit)       { Uart.syncBit = bit & 4; Uart.samples = 2; }\r
+                               else if(bit & 4)        { Uart.syncBit = bit & 4; Uart.samples = 2; bit <<= 2; }\r
+                               if(!Uart.syncBit)       { Uart.syncBit = bit & 2; Uart.samples = 1; }\r
+                               else if(bit & 2)        { Uart.syncBit = bit & 2; Uart.samples = 1; bit <<= 1; }\r
+                               if(!Uart.syncBit)       { Uart.syncBit = bit & 1; Uart.samples = 0;\r
+                                       if(Uart.syncBit & (Uart.bitBuffer & 8)) {\r
+                                               Uart.syncBit = 8;\r
+\r
+                                               // the first half bit period is expected in next sample\r
+                                               Uart.posCnt = 0;\r
+                                               Uart.samples = 3;\r
+                                       }\r
+                               }\r
+                               else if(bit & 1)        { Uart.syncBit = bit & 1; Uart.samples = 0; }\r
+\r
+                               Uart.syncBit <<= 4;\r
+                               Uart.state = STATE_START_OF_COMMUNICATION;\r
+                               Uart.drop = DROP_FIRST_HALF;\r
+                               Uart.bitCnt = 0;\r
+                               Uart.byteCnt = 0;\r
+                               Uart.parityBits = 0;\r
+                               error = 0;\r
+                       }\r
+                       else {\r
+                               Uart.highCnt = 0;\r
+                       }\r
+               }\r
+               else {\r
+                       if(Uart.highCnt < 8) {\r
+                               Uart.highCnt++;\r
+                       }\r
+               }\r
+       }\r
+\r
+    return FALSE;\r
+}\r
+\r
+//=============================================================================\r
+// ISO 14443 Type A - Manchester\r
+//=============================================================================\r
+\r
+static struct {\r
+    enum {\r
+        DEMOD_UNSYNCD,\r
+               DEMOD_START_OF_COMMUNICATION,\r
+               DEMOD_MANCHESTER_D,\r
+               DEMOD_MANCHESTER_E,\r
+               DEMOD_MANCHESTER_F,\r
+        DEMOD_ERROR_WAIT\r
+    }       state;\r
+    int     bitCount;\r
+    int     posCount;\r
+       int     syncBit;\r
+       int     parityBits;\r
+    WORD    shiftReg;\r
+       int     buffer;\r
+       int     buff;\r
+       int     samples;\r
+    int     len;\r
+       enum {\r
+               SUB_NONE,\r
+               SUB_FIRST_HALF,\r
+               SUB_SECOND_HALF\r
+       }               sub;\r
+    BYTE   *output;\r
+} Demod;\r
+\r
+static BOOL ManchesterDecoding(int v)\r
+{\r
+       int bit;\r
+       int modulation;\r
+       int error = 0;\r
+\r
+       if(!Demod.buff) {\r
+               Demod.buff = 1;\r
+               Demod.buffer = v;\r
+               return FALSE;\r
+       }\r
+       else {\r
+               bit = Demod.buffer;\r
+               Demod.buffer = v;\r
+       }\r
+\r
+       if(Demod.state==DEMOD_UNSYNCD) {\r
+               Demod.output[Demod.len] = 0xfa;\r
+               Demod.syncBit = 0;\r
+               //Demod.samples = 0;\r
+               Demod.posCount = 1;             // This is the first half bit period, so after syncing handle the second part\r
+               if(bit & 0x08) { Demod.syncBit = 0x08; }\r
+               if(!Demod.syncBit)      {\r
+                       if(bit & 0x04) { Demod.syncBit = 0x04; }\r
+               }\r
+               else if(bit & 0x04) { Demod.syncBit = 0x04; bit <<= 4; }\r
+               if(!Demod.syncBit)      {\r
+                       if(bit & 0x02) { Demod.syncBit = 0x02; }\r
+               }\r
+               else if(bit & 0x02) { Demod.syncBit = 0x02; bit <<= 4; }\r
+               if(!Demod.syncBit)      {\r
+                       if(bit & 0x01) { Demod.syncBit = 0x01; }\r
+\r
+                       if(Demod.syncBit & (Demod.buffer & 0x08)) {\r
+                               Demod.syncBit = 0x08;\r
+\r
+                               // The first half bitperiod is expected in next sample\r
+                               Demod.posCount = 0;\r
+                               Demod.output[Demod.len] = 0xfb;\r
+                       }\r
+               }\r
+               else if(bit & 0x01) { Demod.syncBit = 0x01; }\r
+\r
+               if(Demod.syncBit) {\r
+                       Demod.len = 0;\r
+                       Demod.state = DEMOD_START_OF_COMMUNICATION;\r
+                       Demod.sub = SUB_FIRST_HALF;\r
+                       Demod.bitCount = 0;\r
+                       Demod.shiftReg = 0;\r
+                       Demod.parityBits = 0;\r
+                       Demod.samples = 0;\r
+                       if(Demod.posCount) {\r
+                               switch(Demod.syncBit) {\r
+                                       case 0x08: Demod.samples = 3; break;\r
+                                       case 0x04: Demod.samples = 2; break;\r
+                                       case 0x02: Demod.samples = 1; break;\r
+                                       case 0x01: Demod.samples = 0; break;\r
+                               }\r
+                       }\r
+                       error = 0;\r
+               }\r
+       }\r
+       else {\r
+               //modulation = bit & Demod.syncBit;\r
+               modulation = ((bit << 1) ^ ((Demod.buffer & 0x08) >> 3)) & Demod.syncBit;\r
+\r
+               Demod.samples += 4;\r
+\r
+               if(Demod.posCount==0) {\r
+                       Demod.posCount = 1;\r
+                       if(modulation) {\r
+                               Demod.sub = SUB_FIRST_HALF;\r
+                       }\r
+                       else {\r
+                               Demod.sub = SUB_NONE;\r
+                       }\r
+               }\r
+               else {\r
+                       Demod.posCount = 0;\r
+                       if(modulation && (Demod.sub == SUB_FIRST_HALF)) {\r
+                               if(Demod.state!=DEMOD_ERROR_WAIT) {\r
+                                       Demod.state = DEMOD_ERROR_WAIT;\r
+                                       Demod.output[Demod.len] = 0xaa;\r
+                                       error = 0x01;\r
+                               }\r
+                       }\r
+                       else if(modulation) {\r
+                               Demod.sub = SUB_SECOND_HALF;\r
+                       }\r
+\r
+                       switch(Demod.state) {\r
+                               case DEMOD_START_OF_COMMUNICATION:\r
+                                       if(Demod.sub == SUB_FIRST_HALF) {\r
+                                               Demod.state = DEMOD_MANCHESTER_D;\r
+                                       }\r
+                                       else {\r
+                                               Demod.output[Demod.len] = 0xab;\r
+                                               Demod.state = DEMOD_ERROR_WAIT;\r
+                                               error = 0x02;\r
+                                       }\r
+                                       break;\r
+\r
+                               case DEMOD_MANCHESTER_D:\r
+                               case DEMOD_MANCHESTER_E:\r
+                                       if(Demod.sub == SUB_FIRST_HALF) {\r
+                                               Demod.bitCount++;\r
+                                               Demod.shiftReg = (Demod.shiftReg >> 1) ^ 0x100;\r
+                                               Demod.state = DEMOD_MANCHESTER_D;\r
+                                       }\r
+                                       else if(Demod.sub == SUB_SECOND_HALF) {\r
+                                               Demod.bitCount++;\r
+                                               Demod.shiftReg >>= 1;\r
+                                               Demod.state = DEMOD_MANCHESTER_E;\r
+                                       }\r
+                                       else {\r
+                                               Demod.state = DEMOD_MANCHESTER_F;\r
+                                       }\r
+                                       break;\r
+\r
+                               case DEMOD_MANCHESTER_F:\r
+                                       // Tag response does not need to be a complete byte!\r
+                                       if(Demod.len > 0 || Demod.bitCount > 0) {\r
+                                               if(Demod.bitCount > 0) {\r
+                                                       Demod.shiftReg >>= (9 - Demod.bitCount);\r
+                                                       Demod.output[Demod.len] = Demod.shiftReg & 0xff;\r
+                                                       Demod.len++;\r
+                                                       // No parity bit, so just shift a 0\r
+                                                       Demod.parityBits <<= 1;\r
+                                               }\r
+\r
+                                               Demod.state = DEMOD_UNSYNCD;\r
+                                               return TRUE;\r
+                                       }\r
+                                       else {\r
+                                               Demod.output[Demod.len] = 0xad;\r
+                                               Demod.state = DEMOD_ERROR_WAIT;\r
+                                               error = 0x03;\r
+                                       }\r
+                                       break;\r
+\r
+                               case DEMOD_ERROR_WAIT:\r
+                                       Demod.state = DEMOD_UNSYNCD;\r
+                                       break;\r
+\r
+                               default:\r
+                                       Demod.output[Demod.len] = 0xdd;\r
+                                       Demod.state = DEMOD_UNSYNCD;\r
+                                       break;\r
+                       }\r
+\r
+                       if(Demod.bitCount>=9) {\r
+                               Demod.output[Demod.len] = Demod.shiftReg & 0xff;\r
+                               Demod.len++;\r
+\r
+                               Demod.parityBits <<= 1;\r
+                               Demod.parityBits ^= ((Demod.shiftReg >> 8) & 0x01);\r
+\r
+                               Demod.bitCount = 0;\r
+                               Demod.shiftReg = 0;\r
+                       }\r
+\r
+                       /*if(error) {\r
+                               Demod.output[Demod.len] = 0xBB;\r
+                               Demod.len++;\r
+                               Demod.output[Demod.len] = error & 0xFF;\r
+                               Demod.len++;\r
+                               Demod.output[Demod.len] = 0xBB;\r
+                               Demod.len++;\r
+                               Demod.output[Demod.len] = bit & 0xFF;\r
+                               Demod.len++;\r
+                               Demod.output[Demod.len] = Demod.buffer & 0xFF;\r
+                               Demod.len++;\r
+                               Demod.output[Demod.len] = Demod.syncBit & 0xFF;\r
+                               Demod.len++;\r
+                               Demod.output[Demod.len] = 0xBB;\r
+                               Demod.len++;\r
+                               return TRUE;\r
+                       }*/\r
+\r
+               }\r
+\r
+       } // end (state != UNSYNCED)\r
+\r
+    return FALSE;\r
+}\r
+\r
+//=============================================================================\r
+// Finally, a `sniffer' for ISO 14443 Type A\r
+// Both sides of communication!\r
+//=============================================================================\r
+\r
+//-----------------------------------------------------------------------------\r
+// Record the sequence of commands sent by the reader to the tag, with\r
+// triggering so that we start recording at the point that the tag is moved\r
+// near the reader.\r
+//-----------------------------------------------------------------------------\r
+void SnoopIso14443a(void)\r
+{\r
+\r
+       // BIG CHANGE - UNDERSTAND THIS BEFORE WE COMMIT\r
+\r
+       #define RECV_CMD_OFFSET         3032\r
+       #define RECV_RES_OFFSET         3096\r
+       #define DMA_BUFFER_OFFSET       3160\r
+       #define DMA_BUFFER_SIZE         4096\r
+       #define TRACE_LENGTH            3000    \r
+       \r
+//     #define RECV_CMD_OFFSET         2032    // original (working as of 21/2/09) values\r
+//     #define RECV_RES_OFFSET         2096    // original (working as of 21/2/09) values\r
+//     #define DMA_BUFFER_OFFSET       2160    // original (working as of 21/2/09) values\r
+//     #define DMA_BUFFER_SIZE         4096    // original (working as of 21/2/09) values\r
+//     #define TRACE_LENGTH            2000    // original (working as of 21/2/09) values\r
+\r
+    // We won't start recording the frames that we acquire until we trigger;\r
+    // a good trigger condition to get started is probably when we see a\r
+    // response from the tag.\r
+    BOOL triggered = TRUE; // FALSE to wait first for card\r
+\r
+    // The command (reader -> tag) that we're receiving.\r
+       // The length of a received command will in most cases be no more than 18 bytes.\r
+       // So 32 should be enough!\r
+    BYTE *receivedCmd = (((BYTE *)BigBuf) + RECV_CMD_OFFSET);\r
+    // The response (tag -> reader) that we're receiving.\r
+    BYTE *receivedResponse = (((BYTE *)BigBuf) + RECV_RES_OFFSET);\r
+\r
+    // As we receive stuff, we copy it from receivedCmd or receivedResponse\r
+    // into trace, along with its length and other annotations.\r
+    BYTE *trace = (BYTE *)BigBuf;\r
+    int traceLen = 0;\r
+\r
+    // The DMA buffer, used to stream samples from the FPGA\r
+    SBYTE *dmaBuf = ((SBYTE *)BigBuf) + DMA_BUFFER_OFFSET;\r
+    int lastRxCounter;\r
+    SBYTE *upTo;\r
+    int smpl;\r
+    int maxBehindBy = 0;\r
+\r
+    // Count of samples received so far, so that we can include timing\r
+    // information in the trace buffer.\r
+    int samples = 0;\r
+       int rsamples = 0;\r
+\r
+    memset(trace, 0x44, RECV_CMD_OFFSET);\r
+\r
+    // Set up the demodulator for tag -> reader responses.\r
+    Demod.output = receivedResponse;\r
+    Demod.len = 0;\r
+    Demod.state = DEMOD_UNSYNCD;\r
+\r
+    // And the reader -> tag commands\r
+    memset(&Uart, 0, sizeof(Uart));\r
+    Uart.output = receivedCmd;\r
+    Uart.byteCntMax = 32; // was 100 (greg)////////////////////////////////////////////////////////////////////////\r
+    Uart.state = STATE_UNSYNCD;\r
+\r
+    // And put the FPGA in the appropriate mode\r
+    FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_SNIFFER);\r
+    SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
+\r
+       // Setup for the DMA.\r
+    FpgaSetupSsc();\r
+    upTo = dmaBuf;\r
+    lastRxCounter = DMA_BUFFER_SIZE;\r
+    FpgaSetupSscDma((BYTE *)dmaBuf, DMA_BUFFER_SIZE);\r
+\r
+    LED_A_ON();\r
+\r
+    // And now we loop, receiving samples.\r
+    for(;;) {\r
+               WDT_HIT();\r
+        int behindBy = (lastRxCounter - PDC_RX_COUNTER(SSC_BASE)) &\r
+                                (DMA_BUFFER_SIZE-1);\r
+        if(behindBy > maxBehindBy) {\r
+            maxBehindBy = behindBy;\r
+            if(behindBy > 400) {\r
+                DbpString("blew circular buffer!");\r
+                goto done;\r
+            }\r
+        }\r
+        if(behindBy < 1) continue;\r
+\r
+        smpl = upTo[0];\r
+        upTo++;\r
+        lastRxCounter -= 1;\r
+        if(upTo - dmaBuf > DMA_BUFFER_SIZE) {\r
+            upTo -= DMA_BUFFER_SIZE;\r
+            lastRxCounter += DMA_BUFFER_SIZE;\r
+            PDC_RX_NEXT_POINTER(SSC_BASE) = (DWORD)upTo;\r
+            PDC_RX_NEXT_COUNTER(SSC_BASE) = DMA_BUFFER_SIZE;\r
+        }\r
+\r
+        samples += 4;\r
+#define HANDLE_BIT_IF_BODY \\r
+            LED_C_ON(); \\r
+                       if(triggered) { \\r
+                               trace[traceLen++] = ((rsamples >>  0) & 0xff); \\r
+                trace[traceLen++] = ((rsamples >>  8) & 0xff); \\r
+                trace[traceLen++] = ((rsamples >> 16) & 0xff); \\r
+                trace[traceLen++] = ((rsamples >> 24) & 0xff); \\r
+                               trace[traceLen++] = ((Uart.parityBits >>  0) & 0xff); \\r
+                               trace[traceLen++] = ((Uart.parityBits >>  8) & 0xff); \\r
+                               trace[traceLen++] = ((Uart.parityBits >> 16) & 0xff); \\r
+                               trace[traceLen++] = ((Uart.parityBits >> 24) & 0xff); \\r
+                trace[traceLen++] = Uart.byteCnt; \\r
+                memcpy(trace+traceLen, receivedCmd, Uart.byteCnt); \\r
+                traceLen += Uart.byteCnt; \\r
+                if(traceLen > TRACE_LENGTH) break; \\r
+            } \\r
+            /* And ready to receive another command. */ \\r
+            Uart.state = STATE_UNSYNCD; \\r
+            /* And also reset the demod code, which might have been */ \\r
+            /* false-triggered by the commands from the reader. */ \\r
+            Demod.state = DEMOD_UNSYNCD; \\r
+                       LED_B_OFF(); \\r
+\r
+               if(MillerDecoding((smpl & 0xF0) >> 4)) {\r
+            rsamples = samples - Uart.samples;\r
+                       HANDLE_BIT_IF_BODY\r
+        }\r
+               if(ManchesterDecoding(smpl & 0x0F)) {\r
+                       rsamples = samples - Demod.samples;\r
+                       LED_B_ON();\r
+\r
+                       // timestamp, as a count of samples\r
+                       trace[traceLen++] = ((rsamples >>  0) & 0xff);\r
+                       trace[traceLen++] = ((rsamples >>  8) & 0xff);\r
+                       trace[traceLen++] = ((rsamples >> 16) & 0xff);\r
+                       trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff);\r
+                       trace[traceLen++] = ((Demod.parityBits >>  0) & 0xff);\r
+                       trace[traceLen++] = ((Demod.parityBits >>  8) & 0xff);\r
+                       trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff);\r
+                       trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff);\r
+                       // length\r
+                       trace[traceLen++] = Demod.len;\r
+                       memcpy(trace+traceLen, receivedResponse, Demod.len);\r
+                       traceLen += Demod.len;\r
+                       if(traceLen > TRACE_LENGTH) break;\r
+\r
+               triggered = TRUE;\r
+\r
+            // And ready to receive another response.\r
+            memset(&Demod, 0, sizeof(Demod));\r
+            Demod.output = receivedResponse;\r
+            Demod.state = DEMOD_UNSYNCD;\r
+                       LED_C_OFF();\r
+               }\r
+\r
+        if(BUTTON_PRESS()) {\r
+            DbpString("cancelled_a");\r
+            goto done;\r
+        }\r
+    }\r
+\r
+    DbpString("COMMAND FINISHED");\r
+\r
+    DbpIntegers(maxBehindBy, Uart.state, Uart.byteCnt);\r
+    DbpIntegers(Uart.byteCntMax, traceLen, (int)Uart.output[0]);\r
+\r
+done:\r
+    PDC_CONTROL(SSC_BASE) = PDC_RX_DISABLE;\r
+    DbpIntegers(maxBehindBy, Uart.state, Uart.byteCnt);\r
+    DbpIntegers(Uart.byteCntMax, traceLen, (int)Uart.output[0]);\r
+    LED_A_OFF();\r
+    LED_B_OFF();\r
+       LED_C_OFF();\r
+       LED_D_OFF();\r
+}\r
+\r
+// Prepare communication bits to send to FPGA\r
+void Sequence(SecType seq)\r
+{\r
+       ToSendMax++;\r
+       switch(seq) {\r
+       // CARD TO READER\r
+       case SEC_D:\r
+               // Sequence D: 11110000\r
+               // modulation with subcarrier during first half\r
+        ToSend[ToSendMax] = 0xf0;\r
+               break;\r
+       case SEC_E:\r
+               // Sequence E: 00001111\r
+               // modulation with subcarrier during second half\r
+        ToSend[ToSendMax] = 0x0f;\r
+               break;\r
+       case SEC_F:\r
+               // Sequence F: 00000000\r
+               // no modulation with subcarrier\r
+        ToSend[ToSendMax] = 0x00;\r
+               break;\r
+       // READER TO CARD\r
+       case SEC_X:\r
+               // Sequence X: 00001100\r
+               // drop after half a period\r
+        ToSend[ToSendMax] = 0x0c;\r
+               break;\r
+       case SEC_Y:\r
+       default:\r
+               // Sequence Y: 00000000\r
+               // no drop\r
+        ToSend[ToSendMax] = 0x00;\r
+               break;\r
+       case SEC_Z:\r
+               // Sequence Z: 11000000\r
+               // drop at start\r
+        ToSend[ToSendMax] = 0xc0;\r
+               break;\r
+       }\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Prepare tag messages\r
+//-----------------------------------------------------------------------------\r
+static void CodeIso14443aAsTag(const BYTE *cmd, int len)\r
+{\r
+    int i;\r
+       int oddparity;\r
+\r
+    ToSendReset();\r
+\r
+       // Correction bit, might be removed when not needed\r
+       ToSendStuffBit(0);\r
+       ToSendStuffBit(0);\r
+       ToSendStuffBit(0);\r
+       ToSendStuffBit(0);\r
+       ToSendStuffBit(1);  // 1\r
+       ToSendStuffBit(0);\r
+       ToSendStuffBit(0);\r
+       ToSendStuffBit(0);\r
+\r
+       // Send startbit\r
+       Sequence(SEC_D);\r
+\r
+    for(i = 0; i < len; i++) {\r
+        int j;\r
+        BYTE b = cmd[i];\r
+\r
+               // Data bits\r
+        oddparity = 0x01;\r
+               for(j = 0; j < 8; j++) {\r
+            oddparity ^= (b & 1);\r
+                       if(b & 1) {\r
+                               Sequence(SEC_D);\r
+                       } else {\r
+                               Sequence(SEC_E);\r
+            }\r
+            b >>= 1;\r
+        }\r
+\r
+        // Parity bit\r
+        if(oddparity) {\r
+                       Sequence(SEC_D);\r
+               } else {\r
+                       Sequence(SEC_E);\r
+               }\r
+    }\r
+\r
+    // Send stopbit\r
+       Sequence(SEC_F);\r
+\r
+       // Flush the buffer in FPGA!!\r
+       for(i = 0; i < 5; i++) {\r
+               Sequence(SEC_F);\r
+       }\r
+\r
+    // Convert from last byte pos to length\r
+    ToSendMax++;\r
+\r
+    // Add a few more for slop\r
+    ToSend[ToSendMax++] = 0x00;\r
+       ToSend[ToSendMax++] = 0x00;\r
+    //ToSendMax += 2;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// This is to send a NACK kind of answer, its only 3 bits, I know it should be 4\r
+//-----------------------------------------------------------------------------\r
+static void CodeStrangeAnswer()\r
+{\r
+       int i;\r
+\r
+    ToSendReset();\r
+\r
+       // Correction bit, might be removed when not needed\r
+       ToSendStuffBit(0);\r
+       ToSendStuffBit(0);\r
+       ToSendStuffBit(0);\r
+       ToSendStuffBit(0);\r
+       ToSendStuffBit(1);  // 1\r
+       ToSendStuffBit(0);\r
+       ToSendStuffBit(0);\r
+       ToSendStuffBit(0);\r
+\r
+       // Send startbit\r
+       Sequence(SEC_D);\r
+\r
+       // 0\r
+       Sequence(SEC_E);\r
+\r
+       // 0\r
+       Sequence(SEC_E);\r
+\r
+       // 1\r
+       Sequence(SEC_D);\r
+\r
+    // Send stopbit\r
+       Sequence(SEC_F);\r
+\r
+       // Flush the buffer in FPGA!!\r
+       for(i = 0; i < 5; i++) {\r
+               Sequence(SEC_F);\r
+       }\r
+\r
+    // Convert from last byte pos to length\r
+    ToSendMax++;\r
+\r
+    // Add a few more for slop\r
+    ToSend[ToSendMax++] = 0x00;\r
+       ToSend[ToSendMax++] = 0x00;\r
+    //ToSendMax += 2;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Wait for commands from reader\r
+// Stop when button is pressed\r
+// Or return TRUE when command is captured\r
+//-----------------------------------------------------------------------------\r
+static BOOL GetIso14443aCommandFromReader(BYTE *received, int *len, int maxLen)\r
+{\r
+    // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen\r
+    // only, since we are receiving, not transmitting).\r
+    FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN);\r
+\r
+    // Now run a `software UART' on the stream of incoming samples.\r
+    Uart.output = received;\r
+    Uart.byteCntMax = maxLen;\r
+    Uart.state = STATE_UNSYNCD;\r
+\r
+    for(;;) {\r
+        WDT_HIT();\r
+\r
+        if(BUTTON_PRESS()) return FALSE;\r
+\r
+        if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+            SSC_TRANSMIT_HOLDING = 0x00;\r
+        }\r
+        if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+            BYTE b = (BYTE)SSC_RECEIVE_HOLDING;\r
+                       if(MillerDecoding((b & 0xf0) >> 4)) {\r
+                               *len = Uart.byteCnt;\r
+                               return TRUE;\r
+                       }\r
+                       if(MillerDecoding(b & 0x0f)) {\r
+                               *len = Uart.byteCnt;\r
+                               return TRUE;\r
+                       }\r
+        }\r
+    }\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Main loop of simulated tag: receive commands from reader, decide what\r
+// response to send, and send it.\r
+//-----------------------------------------------------------------------------\r
+void SimulateIso14443aTag(int tagType, int TagUid)\r
+{\r
+       // This function contains the tag emulation\r
+\r
+       // Prepare protocol messages\r
+    // static const BYTE cmd1[] = { 0x26 };\r
+//     static const BYTE response1[] = { 0x02, 0x00 }; // Says: I am Mifare 4k - original line - greg\r
+//\r
+       static const BYTE response1[] = { 0x44, 0x03 }; // Says: I am a DESFire Tag, ph33r me\r
+//     static const BYTE response1[] = { 0x44, 0x00 }; // Says: I am a ULTRALITE Tag, 0wn me\r
+\r
+       // UID response\r
+    // static const BYTE cmd2[] = { 0x93, 0x20 };\r
+    //static const BYTE response2[] = { 0x9a, 0xe5, 0xe4, 0x43, 0xd8 }; // original value - greg\r
+\r
+\r
+\r
+// my desfire\r
+    static const BYTE response2[] = { 0x88, 0x04, 0x21, 0x3f, 0x4d }; // known uid - note cascade (0x88), 2nd byte (0x04) = NXP/Phillips\r
+   \r
+       \r
+// When reader selects us during cascade1 it will send cmd3\r
+//BYTE response3[] = { 0x04, 0x00, 0x00 }; // SAK Select (cascade1) successful response (ULTRALITE)\r
+BYTE response3[] = { 0x24, 0x00, 0x00 }; // SAK Select (cascade1) successful response (DESFire)\r
+ComputeCrc14443(CRC_14443_A, response3, 1, &response3[1], &response3[2]);\r
+\r
+// send cascade2 2nd half of UID\r
+static const BYTE response2a[] = { 0x51, 0x48, 0x1d, 0x80, 0x84 }; //  uid - cascade2 - 2nd half (4 bytes) of UID+ BCCheck\r
+// NOTE : THE CRC on the above may be wrong as I have obfuscated the actual UID\r
+\r
+\r
+// When reader selects us during cascade2 it will send cmd3a\r
+//BYTE response3a[] = { 0x00, 0x00, 0x00 }; // SAK Select (cascade2) successful response (ULTRALITE)\r
+BYTE response3a[] = { 0x20, 0x00, 0x00 }; // SAK Select (cascade2) successful response (DESFire)\r
+ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]);\r
+    \r
+// When reader tries to authenticate\r
+       // static const BYTE cmd5[] = { 0x60, 0x00, 0xf5, 0x7b };\r
+    static const BYTE response5[] = { 0x00, 0x00, 0x00, 0x00 }; // Very random tag nonce\r
+\r
+    BYTE *resp;\r
+    int respLen;\r
+\r
+    // Longest possible response will be 16 bytes + 2 CRC = 18 bytes\r
+       // This will need\r
+       //    144        data bits (18 * 8)\r
+       //     18        parity bits\r
+       //      2        Start and stop\r
+       //      1        Correction bit (Answer in 1172 or 1236 periods, see FPGA)\r
+       //      1        just for the case\r
+       // ----------- +\r
+       //    166\r
+       //\r
+       // 166 bytes, since every bit that needs to be send costs us a byte\r
+       //\r
+\r
+\r
+    // Respond with card type\r
+    BYTE *resp1 = (((BYTE *)BigBuf) + 800);\r
+    int resp1Len;\r
+\r
+    // Anticollision cascade1 - respond with uid\r
+    BYTE *resp2 = (((BYTE *)BigBuf) + 970);\r
+    int resp2Len;\r
+\r
+    // Anticollision cascade2 - respond with 2nd half of uid if asked\r
+    // we're only going to be asked if we set the 1st byte of the UID (during cascade1) to 0x88\r
+    BYTE *resp2a = (((BYTE *)BigBuf) + 1140);\r
+    int resp2aLen;\r
+\r
+    // Acknowledge select - cascade 1\r
+    BYTE *resp3 = (((BYTE *)BigBuf) + 1310);\r
+    int resp3Len;\r
+\r
+    // Acknowledge select - cascade 2\r
+    BYTE *resp3a = (((BYTE *)BigBuf) + 1480);\r
+    int resp3aLen;\r
+\r
+    // Response to a read request - not implemented atm\r
+    BYTE *resp4 = (((BYTE *)BigBuf) + 1550);\r
+    int resp4Len;\r
+\r
+    // Authenticate response - nonce\r
+    BYTE *resp5 = (((BYTE *)BigBuf) + 1720);\r
+    int resp5Len;\r
+\r
+    BYTE *receivedCmd = (BYTE *)BigBuf;\r
+    int len;\r
+\r
+    int i;\r
+       int u;\r
+       BYTE b;\r
+\r
+       // To control where we are in the protocol\r
+       int order = 0;\r
+       int lastorder;\r
+\r
+       // Just to allow some checks\r
+       int happened = 0;\r
+       int happened2 = 0;\r
+\r
+    int cmdsRecvd = 0;\r
+\r
+       BOOL fdt_indicator;\r
+\r
+    memset(receivedCmd, 0x44, 400);\r
+\r
+       // Prepare the responses of the anticollision phase\r
+       // there will be not enough time to do this at the moment the reader sends it REQA\r
+\r
+       // Answer to request\r
+       CodeIso14443aAsTag(response1, sizeof(response1));\r
+    memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax;\r
+\r
+       // Send our UID (cascade 1)\r
+       CodeIso14443aAsTag(response2, sizeof(response2));\r
+    memcpy(resp2, ToSend, ToSendMax); resp2Len = ToSendMax;\r
+\r
+       // Answer to select (cascade1)\r
+       CodeIso14443aAsTag(response3, sizeof(response3));\r
+    memcpy(resp3, ToSend, ToSendMax); resp3Len = ToSendMax;\r
+\r
+       // Send the cascade 2 2nd part of the uid\r
+       CodeIso14443aAsTag(response2a, sizeof(response2a));\r
+    memcpy(resp2a, ToSend, ToSendMax); resp2aLen = ToSendMax;\r
+\r
+       // Answer to select (cascade 2)\r
+       CodeIso14443aAsTag(response3a, sizeof(response3a));\r
+    memcpy(resp3a, ToSend, ToSendMax); resp3aLen = ToSendMax;\r
+\r
+       // Strange answer is an example of rare message size (3 bits)\r
+       CodeStrangeAnswer();\r
+       memcpy(resp4, ToSend, ToSendMax); resp4Len = ToSendMax;\r
+\r
+       // Authentication answer (random nonce)\r
+       CodeIso14443aAsTag(response5, sizeof(response5));\r
+    memcpy(resp5, ToSend, ToSendMax); resp5Len = ToSendMax;\r
+\r
+    // We need to listen to the high-frequency, peak-detected path.\r
+    SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
+    FpgaSetupSsc();\r
+\r
+    cmdsRecvd = 0;\r
+\r
+    LED_A_ON();\r
+       for(;;) {\r
+\r
+               if(!GetIso14443aCommandFromReader(receivedCmd, &len, 100)) {\r
+            DbpString("button press");\r
+            break;\r
+        }\r
+       // doob - added loads of debug strings so we can see what the reader is saying to us during the sim as hi14alist is not populated\r
+        // Okay, look at the command now.\r
+        lastorder = order;\r
+               i = 1; // first byte transmitted\r
+        if(receivedCmd[0] == 0x26) {\r
+                       // Received a REQUEST\r
+                       resp = resp1; respLen = resp1Len; order = 1;\r
+                       //DbpString("Hello request from reader:");\r
+               } else if(receivedCmd[0] == 0x52) {\r
+                       // Received a WAKEUP\r
+                       resp = resp1; respLen = resp1Len; order = 6;\r
+//                     //DbpString("Wakeup request from reader:");\r
+\r
+               } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x93) {   // greg - cascade 1 anti-collision\r
+                       // Received request for UID (cascade 1)\r
+                       resp = resp2; respLen = resp2Len; order = 2;\r
+//                     DbpString("UID (cascade 1) request from reader:");\r
+//                     DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]);\r
+\r
+\r
+               } else if(receivedCmd[1] == 0x20 && receivedCmd[0] ==0x95) {    // greg - cascade 2 anti-collision\r
+                       // Received request for UID (cascade 2)\r
+                       resp = resp2a; respLen = resp2aLen; order = 20;\r
+//                     DbpString("UID (cascade 2) request from reader:");\r
+//                     DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]);\r
+\r
+\r
+               } else if(receivedCmd[1] == 0x70 && receivedCmd[0] ==0x93) {    // greg - cascade 1 select\r
+                       // Received a SELECT\r
+                       resp = resp3; respLen = resp3Len; order = 3;\r
+//                     DbpString("Select (cascade 1) request from reader:");\r
+//                     DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]);\r
+\r
+\r
+               } else if(receivedCmd[1] == 0x70 && receivedCmd[0] ==0x95) {    // greg - cascade 2 select\r
+                       // Received a SELECT\r
+                       resp = resp3a; respLen = resp3aLen; order = 30;\r
+//                     DbpString("Select (cascade 2) request from reader:");\r
+//                     DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]);\r
+\r
+\r
+               } else if(receivedCmd[0] == 0x30) {\r
+                       // Received a READ\r
+                       resp = resp4; respLen = resp4Len; order = 4; // Do nothing\r
+                       DbpString("Read request from reader:");\r
+                       DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]);\r
+\r
+\r
+               } else if(receivedCmd[0] == 0x50) {\r
+                       // Received a HALT\r
+                       resp = resp1; respLen = 0; order = 5; // Do nothing\r
+                       DbpString("Reader requested we HALT!:");\r
+\r
+               } else if(receivedCmd[0] == 0x60) {\r
+                       // Received an authentication request\r
+                       resp = resp5; respLen = resp5Len; order = 7;\r
+                       DbpString("Authenticate request from reader:");\r
+                       DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]);\r
+\r
+               } else if(receivedCmd[0] == 0xE0) {\r
+                       // Received a RATS request\r
+                       resp = resp1; respLen = 0;order = 70;\r
+                       DbpString("RATS request from reader:");\r
+                       DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]);\r
+        } else {\r
+            // Never seen this command before\r
+                       DbpString("Unknown command received from reader:");\r
+                       DbpIntegers(receivedCmd[0], receivedCmd[1], receivedCmd[2]);\r
+                       DbpIntegers(receivedCmd[3], receivedCmd[4], receivedCmd[5]);\r
+                       DbpIntegers(receivedCmd[6], receivedCmd[7], receivedCmd[8]);\r
+\r
+                       // Do not respond\r
+                       resp = resp1; respLen = 0; order = 0;\r
+        }\r
+\r
+               // Count number of wakeups received after a halt\r
+               if(order == 6 && lastorder == 5) { happened++; }\r
+\r
+               // Count number of other messages after a halt\r
+               if(order != 6 && lastorder == 5) { happened2++; }\r
+\r
+               // Look at last parity bit to determine timing of answer\r
+               if((Uart.parityBits & 0x01) || receivedCmd[0] == 0x52) {\r
+                       // 1236, so correction bit needed\r
+                       i = 0;\r
+               }\r
+\r
+        memset(receivedCmd, 0x44, 32);\r
+\r
+               if(cmdsRecvd > 999) {\r
+                       DbpString("1000 commands later...");\r
+            break;\r
+        }\r
+               else {\r
+                       cmdsRecvd++;\r
+               }\r
+\r
+        if(respLen <= 0) continue;\r
+\r
+        // Modulate Manchester\r
+               FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD);\r
+        SSC_TRANSMIT_HOLDING = 0x00;\r
+        FpgaSetupSsc();\r
+\r
+               // ### Transmit the response ###\r
+               u = 0;\r
+               b = 0x00;\r
+               fdt_indicator = FALSE;\r
+        for(;;) {\r
+            if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+                               volatile BYTE b = (BYTE)SSC_RECEIVE_HOLDING;\r
+                (void)b;\r
+            }\r
+            if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+                               if(i > respLen) {\r
+                                       b = 0x00;\r
+                                       u++;\r
+                               } else {\r
+                                       b = resp[i];\r
+                                       i++;\r
+                               }\r
+                               SSC_TRANSMIT_HOLDING = b;\r
+\r
+                if(u > 4) {\r
+                    break;\r
+                }\r
+            }\r
+                       if(BUTTON_PRESS()) {\r
+                           break;\r
+                       }\r
+        }\r
+\r
+    }\r
+\r
+       DbpIntegers(happened, happened2, cmdsRecvd);\r
+       LED_A_OFF();\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Transmit the command (to the tag) that was placed in ToSend[].\r
+//-----------------------------------------------------------------------------\r
+static void TransmitFor14443a(const BYTE *cmd, int len, int *samples, int *wait)\r
+{\r
+    int c;\r
+\r
+    FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);\r
+\r
+       if(*wait < 10) { *wait = 10; }\r
+\r
+    for(c = 0; c < *wait;) {\r
+        if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+            SSC_TRANSMIT_HOLDING = 0x00;               // For exact timing!\r
+            c++;\r
+        }\r
+        if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+            volatile DWORD r = SSC_RECEIVE_HOLDING;\r
+            (void)r;\r
+        }\r
+        WDT_HIT();\r
+    }\r
+\r
+    c = 0;\r
+    for(;;) {\r
+        if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+            SSC_TRANSMIT_HOLDING = cmd[c];\r
+            c++;\r
+            if(c >= len) {\r
+                break;\r
+            }\r
+        }\r
+        if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+            volatile DWORD r = SSC_RECEIVE_HOLDING;\r
+            (void)r;\r
+        }\r
+        WDT_HIT();\r
+    }\r
+       *samples = (c + *wait) << 3;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// To generate an arbitrary stream from reader\r
+//\r
+//-----------------------------------------------------------------------------\r
+void ArbitraryFromReader(const BYTE *cmd, int parity, int len)\r
+{\r
+       int i;\r
+       int j;\r
+       int last;\r
+    BYTE b;\r
+\r
+       ToSendReset();\r
+\r
+       // Start of Communication (Seq. Z)\r
+       Sequence(SEC_Z);\r
+       last = 0;\r
+\r
+       for(i = 0; i < len; i++) {\r
+        // Data bits\r
+        b = cmd[i];\r
+               for(j = 0; j < 8; j++) {\r
+                       if(b & 1) {\r
+                               // Sequence X\r
+                               Sequence(SEC_X);\r
+                               last = 1;\r
+                       } else {\r
+                               if(last == 0) {\r
+                                       // Sequence Z\r
+                                       Sequence(SEC_Z);\r
+                               }\r
+                               else {\r
+                                       // Sequence Y\r
+                                       Sequence(SEC_Y);\r
+                                       last = 0;\r
+                               }\r
+                       }\r
+                       b >>= 1;\r
+\r
+               }\r
+\r
+               // Predefined parity bit, the flipper flips when needed, because of flips in byte sent\r
+               if(((parity >> (len - i - 1)) & 1)) {\r
+                       // Sequence X\r
+                       Sequence(SEC_X);\r
+                       last = 1;\r
+               } else {\r
+                       if(last == 0) {\r
+                               // Sequence Z\r
+                               Sequence(SEC_Z);\r
+                       }\r
+                       else {\r
+                               // Sequence Y\r
+                               Sequence(SEC_Y);\r
+                               last = 0;\r
+                       }\r
+               }\r
+       }\r
+\r
+       // End of Communication\r
+       if(last == 0) {\r
+               // Sequence Z\r
+               Sequence(SEC_Z);\r
+       }\r
+       else {\r
+               // Sequence Y\r
+               Sequence(SEC_Y);\r
+               last = 0;\r
+       }\r
+       // Sequence Y\r
+       Sequence(SEC_Y);\r
+\r
+       // Just to be sure!\r
+       Sequence(SEC_Y);\r
+       Sequence(SEC_Y);\r
+       Sequence(SEC_Y);\r
+\r
+    // Convert from last character reference to length\r
+    ToSendMax++;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Code a 7-bit command without parity bit\r
+// This is especially for 0x26 and 0x52 (REQA and WUPA)\r
+//-----------------------------------------------------------------------------\r
+void ShortFrameFromReader(const BYTE *cmd)\r
+{\r
+       int j;\r
+       int last;\r
+    BYTE b;\r
+\r
+       ToSendReset();\r
+\r
+       // Start of Communication (Seq. Z)\r
+       Sequence(SEC_Z);\r
+       last = 0;\r
+\r
+       b = cmd[0];\r
+       for(j = 0; j < 7; j++) {\r
+               if(b & 1) {\r
+                       // Sequence X\r
+                       Sequence(SEC_X);\r
+                       last = 1;\r
+               } else {\r
+                       if(last == 0) {\r
+                               // Sequence Z\r
+                               Sequence(SEC_Z);\r
+                       }\r
+                       else {\r
+                               // Sequence Y\r
+                               Sequence(SEC_Y);\r
+                               last = 0;\r
+                       }\r
+               }\r
+               b >>= 1;\r
+       }\r
+\r
+       // End of Communication\r
+       if(last == 0) {\r
+               // Sequence Z\r
+               Sequence(SEC_Z);\r
+       }\r
+       else {\r
+               // Sequence Y\r
+               Sequence(SEC_Y);\r
+               last = 0;\r
+       }\r
+       // Sequence Y\r
+       Sequence(SEC_Y);\r
+\r
+       // Just to be sure!\r
+       Sequence(SEC_Y);\r
+       Sequence(SEC_Y);\r
+       Sequence(SEC_Y);\r
+\r
+    // Convert from last character reference to length\r
+    ToSendMax++;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Prepare reader command to send to FPGA\r
+//\r
+//-----------------------------------------------------------------------------\r
+void CodeIso14443aAsReader(const BYTE *cmd, int len)\r
+{\r
+    int i, j;\r
+       int last;\r
+       int oddparity;\r
+    BYTE b;\r
+\r
+    ToSendReset();\r
+\r
+       // Start of Communication (Seq. Z)\r
+       Sequence(SEC_Z);\r
+       last = 0;\r
+\r
+       for(i = 0; i < len; i++) {\r
+        // Data bits\r
+        b = cmd[i];\r
+        oddparity = 0x01;\r
+        for(j = 0; j < 8; j++) {\r
+            oddparity ^= (b & 1);\r
+            if(b & 1) {\r
+                               // Sequence X\r
+                               Sequence(SEC_X);\r
+                               last = 1;\r
+            } else {\r
+                if(last == 0) {\r
+                                       // Sequence Z\r
+                                       Sequence(SEC_Z);\r
+                               }\r
+                               else {\r
+                                       // Sequence Y\r
+                                       Sequence(SEC_Y);\r
+                                       last = 0;\r
+                               }\r
+            }\r
+            b >>= 1;\r
+        }\r
+\r
+               // Parity bit\r
+               if(oddparity) {\r
+                       // Sequence X\r
+                       Sequence(SEC_X);\r
+                       last = 1;\r
+               } else {\r
+                       if(last == 0) {\r
+                               // Sequence Z\r
+                               Sequence(SEC_Z);\r
+                       }\r
+                       else {\r
+                               // Sequence Y\r
+                               Sequence(SEC_Y);\r
+                               last = 0;\r
+                       }\r
+               }\r
+    }\r
+\r
+       // End of Communication\r
+       if(last == 0) {\r
+               // Sequence Z\r
+               Sequence(SEC_Z);\r
+       }\r
+       else {\r
+               // Sequence Y\r
+               Sequence(SEC_Y);\r
+               last = 0;\r
+       }\r
+       // Sequence Y\r
+       Sequence(SEC_Y);\r
+\r
+       // Just to be sure!\r
+       Sequence(SEC_Y);\r
+       Sequence(SEC_Y);\r
+       Sequence(SEC_Y);\r
+\r
+    // Convert from last character reference to length\r
+    ToSendMax++;\r
+}\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Wait a certain time for tag response\r
+//  If a response is captured return TRUE\r
+//  If it takes to long return FALSE\r
+//-----------------------------------------------------------------------------\r
+static BOOL GetIso14443aAnswerFromTag(BYTE *receivedResponse, int maxLen, int *samples, int *elapsed) //BYTE *buffer\r
+{\r
+       // buffer needs to be 512 bytes\r
+       int c;\r
+\r
+       // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen\r
+    // only, since we are receiving, not transmitting).\r
+    FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_LISTEN);\r
+\r
+    // Now get the answer from the card\r
+    Demod.output = receivedResponse;\r
+    Demod.len = 0;\r
+    Demod.state = DEMOD_UNSYNCD;\r
+\r
+       BYTE b;\r
+       *elapsed = 0;\r
+\r
+       c = 0;\r
+       for(;;) {\r
+        WDT_HIT();\r
+\r
+        if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+            SSC_TRANSMIT_HOLDING = 0x00;  // To make use of exact timing of next command from reader!!\r
+                       (*elapsed)++;\r
+        }\r
+        if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+                       if(c < 512) { c++; } else { return FALSE; }\r
+            b = (BYTE)SSC_RECEIVE_HOLDING;\r
+                       if(ManchesterDecoding((b & 0xf0) >> 4)) {\r
+                               *samples = ((c - 1) << 3) + 4;\r
+                               return TRUE;\r
+                       }\r
+                       if(ManchesterDecoding(b & 0x0f)) {\r
+                               *samples = c << 3;\r
+                               return TRUE;\r
+                       }\r
+        }\r
+    }\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Read an ISO 14443a tag. Send out commands and store answers.\r
+//\r
+//-----------------------------------------------------------------------------\r
+void ReaderIso14443a(DWORD parameter)\r
+{\r
+       // Anticollision\r
+       static const BYTE cmd1[]       = { 0x52 }; // or 0x26\r
+       static const BYTE cmd2[]       = { 0x93,0x20 };\r
+       // UID = 0x2a,0x69,0x8d,0x43,0x8d, last two bytes are CRC bytes\r
+       BYTE cmd3[] = { 0x93,0x70,0x2a,0x69,0x8d,0x43,0x8d,0x52,0x55 };\r
+\r
+       // For Ultralight add an extra anticollission layer -> 95 20 and then 95 70\r
+\r
+       // greg - here we will add our cascade level 2 anticolission and select functions to deal with ultralight               // and 7-byte UIDs in generall...\r
+       BYTE cmd4[] = {0x95,0x20};      // ask for cascade 2 select\r
+       // 95 20\r
+       //BYTE cmd3a[] = { 0x95,0x70,0x2a,0x69,0x8d,0x43,0x8d,0x52,0x55 };\r
+       // 95 70\r
+\r
+       // cascade 2 select\r
+       BYTE cmd5[] = { 0x95,0x70,0x2a,0x69,0x8d,0x43,0x8d,0x52,0x55 };\r
+\r
+\r
+       // RATS (request for answer to select)\r
+       //BYTE cmd6[] = { 0xe0,0x50,0xbc,0xa5 };  // original RATS\r
+       BYTE cmd6[] = { 0xe0,0x21,0xb2,0xc7 };  // Desfire RATS\r
+\r
+       int reqaddr = 2024;                                     // was 2024 - tied to other size changes\r
+       int reqsize = 60;\r
+\r
+       BYTE *req1 = (((BYTE *)BigBuf) + reqaddr);\r
+    int req1Len;\r
+\r
+    BYTE *req2 = (((BYTE *)BigBuf) + reqaddr + reqsize);\r
+    int req2Len;\r
+\r
+    BYTE *req3 = (((BYTE *)BigBuf) + reqaddr + (reqsize * 2));\r
+    int req3Len;\r
+\r
+// greg added req 4 & 5 to deal with cascade 2 section\r
+    BYTE *req4 = (((BYTE *)BigBuf) + reqaddr + (reqsize * 3));\r
+    int req4Len;\r
+\r
+    BYTE *req5 = (((BYTE *)BigBuf) + reqaddr + (reqsize * 4));\r
+    int req5Len;\r
+\r
+    BYTE *req6 = (((BYTE *)BigBuf) + reqaddr + (reqsize * 5));\r
+    int req6Len;\r
+\r
+       //BYTE *req7 = (((BYTE *)BigBuf) + reqaddr + (reqsize * 6));\r
+       //int req7Len;\r
+\r
+       BYTE *receivedAnswer = (((BYTE *)BigBuf) + 3560);       // was 3560 - tied to other size changes\r
+\r
+       BYTE *trace = (BYTE *)BigBuf;\r
+       int traceLen = 0;\r
+       int rsamples = 0;\r
+\r
+       memset(trace, 0x44, 2000);                              // was 2000 - tied to oter size chnages \r
+       // setting it to 3000 causes no tag responses to be detected (2900 is ok)\r
+       // setting it to 1000 causes no tag responses to be detected\r
+\r
+       // Prepare some commands!\r
+    ShortFrameFromReader(cmd1);\r
+    memcpy(req1, ToSend, ToSendMax); req1Len = ToSendMax;\r
+\r
+       CodeIso14443aAsReader(cmd2, sizeof(cmd2));\r
+    memcpy(req2, ToSend, ToSendMax); req2Len = ToSendMax;\r
+\r
+       CodeIso14443aAsReader(cmd3, sizeof(cmd3));\r
+    memcpy(req3, ToSend, ToSendMax); req3Len = ToSendMax;\r
+\r
+\r
+       CodeIso14443aAsReader(cmd4, sizeof(cmd4));              // 4 is cascade 2 request\r
+    memcpy(req4, ToSend, ToSendMax); req4Len = ToSendMax;\r
+\r
+\r
+       CodeIso14443aAsReader(cmd5, sizeof(cmd5));      // 5 is cascade 2 select\r
+    memcpy(req5, ToSend, ToSendMax); req5Len = ToSendMax;\r
+\r
+\r
+       CodeIso14443aAsReader(cmd6, sizeof(cmd6));\r
+    memcpy(req6, ToSend, ToSendMax); req6Len = ToSendMax;\r
+\r
+       // Setup SSC\r
+       FpgaSetupSsc();\r
+\r
+       // Start from off (no field generated)\r
+    FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
+    SpinDelay(200);\r
+\r
+    SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
+    FpgaSetupSsc();\r
+\r
+       // Now give it time to spin up.\r
+    FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);\r
+       SpinDelay(200);\r
+\r
+       LED_A_ON();\r
+       LED_B_OFF();\r
+       LED_C_OFF();\r
+       LED_D_OFF();\r
+\r
+       int samples = 0;\r
+       int tsamples = 0;\r
+       int wait = 0;\r
+       int elapsed = 0;\r
+\r
+       for(;;) {\r
+               // Send WUPA (or REQA)\r
+               TransmitFor14443a(req1, req1Len, &tsamples, &wait);\r
+               // Store answer in buffer\r
+               trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0;\r
+               trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0;\r
+               trace[traceLen++] = 1;\r
+               memcpy(trace+traceLen, cmd1, 1);\r
+               traceLen += 1;\r
+               if(traceLen > TRACE_LENGTH) goto done;\r
+\r
+               while(!GetIso14443aAnswerFromTag(receivedAnswer, 100, &samples, &elapsed)) {\r
+                       if(BUTTON_PRESS()) goto done;\r
+\r
+                       // No answer, just continue polling\r
+                       TransmitFor14443a(req1, req1Len, &tsamples, &wait);\r
+                       // Store answer in buffer\r
+                       trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0;\r
+                       trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0;\r
+                       trace[traceLen++] = 1;\r
+                       memcpy(trace+traceLen, cmd1, 1);\r
+                       traceLen += 1;\r
+                       if(traceLen > TRACE_LENGTH) goto done;\r
+               }\r
+\r
+               // Store answer in buffer\r
+               rsamples = rsamples + (samples - Demod.samples);\r
+               trace[traceLen++] = ((rsamples >>  0) & 0xff);\r
+               trace[traceLen++] = ((rsamples >>  8) & 0xff);\r
+               trace[traceLen++] = ((rsamples >> 16) & 0xff);\r
+               trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >>  0) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >>  8) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff);\r
+               trace[traceLen++] = Demod.len;\r
+               memcpy(trace+traceLen, receivedAnswer, Demod.len);\r
+               traceLen += Demod.len;\r
+               if(traceLen > TRACE_LENGTH) goto done;\r
+\r
+               // Ask for card UID\r
+               TransmitFor14443a(req2, req2Len, &tsamples, &wait);\r
+               // Store answer in buffer\r
+               trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0;\r
+               trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0;\r
+               trace[traceLen++] = 2;\r
+               memcpy(trace+traceLen, cmd2, 2);\r
+               traceLen += 2;\r
+               if(traceLen > TRACE_LENGTH) goto done;\r
+\r
+               if(!GetIso14443aAnswerFromTag(receivedAnswer, 100, &samples, &elapsed)) {\r
+                       continue;\r
+               }\r
+\r
+               // Store answer in buffer\r
+               rsamples = rsamples + (samples - Demod.samples);\r
+               trace[traceLen++] = ((rsamples >>  0) & 0xff);\r
+               trace[traceLen++] = ((rsamples >>  8) & 0xff);\r
+               trace[traceLen++] = ((rsamples >> 16) & 0xff);\r
+               trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >>  0) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >>  8) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff);\r
+               trace[traceLen++] = Demod.len;\r
+               memcpy(trace+traceLen, receivedAnswer, Demod.len);\r
+               traceLen += Demod.len;\r
+               if(traceLen > TRACE_LENGTH) goto done;\r
+\r
+               // Construct SELECT UID command\r
+               // First copy the 5 bytes (Mifare Classic) after the 93 70\r
+               memcpy(cmd3+2,receivedAnswer,5);\r
+               // Secondly compute the two CRC bytes at the end\r
+               ComputeCrc14443(CRC_14443_A, cmd3, 7, &cmd3[7], &cmd3[8]);\r
+               // Prepare the bit sequence to modulate the subcarrier\r
+               // Store answer in buffer\r
+               trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0;\r
+               trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0;\r
+               trace[traceLen++] = 9;\r
+               memcpy(trace+traceLen, cmd3, 9);\r
+               traceLen += 9;\r
+               if(traceLen > TRACE_LENGTH) goto done;\r
+               CodeIso14443aAsReader(cmd3, sizeof(cmd3));\r
+               memcpy(req3, ToSend, ToSendMax); req3Len = ToSendMax;\r
+\r
+               // Select the card\r
+               TransmitFor14443a(req3, req3Len, &samples, &wait);\r
+               if(!GetIso14443aAnswerFromTag(receivedAnswer, 100, &samples, &elapsed)) {\r
+                       continue;\r
+               }\r
+\r
+               // Store answer in buffer\r
+               rsamples = rsamples + (samples - Demod.samples);\r
+               trace[traceLen++] = ((rsamples >>  0) & 0xff);\r
+               trace[traceLen++] = ((rsamples >>  8) & 0xff);\r
+               trace[traceLen++] = ((rsamples >> 16) & 0xff);\r
+               trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >>  0) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >>  8) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff);\r
+               trace[traceLen++] = Demod.len;\r
+               memcpy(trace+traceLen, receivedAnswer, Demod.len);\r
+               traceLen += Demod.len;\r
+               if(traceLen > TRACE_LENGTH) goto done;\r
+\r
+// OK we have selected at least at cascade 1, lets see if first byte of UID was 0x88 in \r
+// which case we need to make a cascade 2 request and select - this is a long UID\r
+               if (receivedAnswer[0] = 0x88)\r
+               {\r
+               // Do cascade level 2 stuff\r
+               ///////////////////////////////////////////////////////////////////\r
+               // First issue a '95 20' identify request\r
+               // Ask for card UID (part 2)\r
+               TransmitFor14443a(req4, req4Len, &tsamples, &wait);\r
+               // Store answer in buffer\r
+               trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0;\r
+               trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0;\r
+               trace[traceLen++] = 2;\r
+               memcpy(trace+traceLen, cmd4, 2);\r
+               traceLen += 2;\r
+               if(traceLen > TRACE_LENGTH) {\r
+               DbpString("Bugging out, just popped tracelength");\r
+               goto done;}\r
+\r
+               if(!GetIso14443aAnswerFromTag(receivedAnswer, 100, &samples, &elapsed)) {\r
+                       continue;\r
+               }\r
+               // Store answer in buffer\r
+               rsamples = rsamples + (samples - Demod.samples);\r
+               trace[traceLen++] = ((rsamples >>  0) & 0xff);\r
+               trace[traceLen++] = ((rsamples >>  8) & 0xff);\r
+               trace[traceLen++] = ((rsamples >> 16) & 0xff);\r
+               trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >>  0) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >>  8) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff);\r
+               trace[traceLen++] = Demod.len;\r
+               memcpy(trace+traceLen, receivedAnswer, Demod.len);\r
+               traceLen += Demod.len;\r
+               if(traceLen > TRACE_LENGTH) goto done;\r
+               //////////////////////////////////////////////////////////////////\r
+               // Then Construct SELECT UID (cascasde 2) command\r
+               DbpString("Just about to copy the UID out of the cascade 2 id req");\r
+               // First copy the 5 bytes (Mifare Classic) after the 95 70\r
+               memcpy(cmd5+2,receivedAnswer,5);\r
+               // Secondly compute the two CRC bytes at the end\r
+               ComputeCrc14443(CRC_14443_A, cmd4, 7, &cmd5[7], &cmd5[8]);\r
+               // Prepare the bit sequence to modulate the subcarrier\r
+               // Store answer in buffer\r
+               trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0;\r
+               trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0;\r
+               trace[traceLen++] = 9;\r
+               memcpy(trace+traceLen, cmd5, 9);\r
+               traceLen += 9;\r
+               if(traceLen > TRACE_LENGTH) goto done;\r
+               CodeIso14443aAsReader(cmd5, sizeof(cmd5));\r
+               memcpy(req5, ToSend, ToSendMax); req5Len = ToSendMax;\r
+\r
+               // Select the card\r
+               TransmitFor14443a(req4, req4Len, &samples, &wait);\r
+               if(!GetIso14443aAnswerFromTag(receivedAnswer, 100, &samples, &elapsed)) {\r
+                       continue;\r
+               }\r
+\r
+               // Store answer in buffer\r
+               rsamples = rsamples + (samples - Demod.samples);\r
+               trace[traceLen++] = ((rsamples >>  0) & 0xff);\r
+               trace[traceLen++] = ((rsamples >>  8) & 0xff);\r
+               trace[traceLen++] = ((rsamples >> 16) & 0xff);\r
+               trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >>  0) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >>  8) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff);\r
+               trace[traceLen++] = Demod.len;\r
+               memcpy(trace+traceLen, receivedAnswer, Demod.len);\r
+               traceLen += Demod.len;\r
+               if(traceLen > TRACE_LENGTH) goto done;\r
+\r
+\r
+\r
+\r
+\r
+\r
+               }       \r
+\r
+               \r
+\r
+               // Secondly compute the two CRC bytes at the end\r
+               ComputeCrc14443(CRC_14443_A, cmd5, 2, &cmd5[2], &cmd5[3]);\r
+               // Send authentication request (Mifare Classic)\r
+               TransmitFor14443a(req5, req5Len, &samples, &wait);\r
+               trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0;\r
+               trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0; trace[traceLen++] = 0;\r
+               trace[traceLen++] = 4;\r
+               memcpy(trace+traceLen, cmd5, 4);\r
+               traceLen += 4;\r
+               if(traceLen > TRACE_LENGTH) goto done;\r
+               if(GetIso14443aAnswerFromTag(receivedAnswer, 100, &samples, &elapsed)) {\r
+                       rsamples++;\r
+                       // We received probably a random, continue and trace!\r
+               }\r
+               else {\r
+                       // Received nothing\r
+                       continue;\r
+               }\r
+\r
+               // Trace the random, i'm curious\r
+               rsamples = rsamples + (samples - Demod.samples);\r
+               trace[traceLen++] = ((rsamples >>  0) & 0xff);\r
+               trace[traceLen++] = ((rsamples >>  8) & 0xff);\r
+               trace[traceLen++] = ((rsamples >> 16) & 0xff);\r
+               trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >>  0) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >>  8) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff);\r
+               trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff);\r
+               trace[traceLen++] = Demod.len;\r
+               memcpy(trace+traceLen, receivedAnswer, Demod.len);\r
+               traceLen += Demod.len;\r
+               if(traceLen > TRACE_LENGTH) goto done;\r
+\r
+               // Thats it...\r
+       }\r
+\r
+done:\r
+       LED_A_OFF();\r
+       LED_B_OFF();\r
+       LED_C_OFF();\r
+       LED_D_OFF();\r
+       DbpIntegers(rsamples, 0xCC, 0xCC);\r
+       DbpString("ready..");\r
+}\r
diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c
new file mode 100644 (file)
index 0000000..2592cbf
--- /dev/null
@@ -0,0 +1,1226 @@
+//-----------------------------------------------------------------------------\r
+// Routines to support ISO 15693. This includes both the reader software and\r
+// the `fake tag' modes, but at the moment I've implemented only the reader\r
+// stuff, and that barely.\r
+// Jonathan Westhues, split Nov 2006\r
+\r
+// Modified by Greg Jones, Jan 2009 to perform modulation onboard in arm rather than on PC\r
+// Also added additional reader commands (SELECT, READ etc.)\r
+\r
+//-----------------------------------------------------------------------------\r
+#include <proxmark3.h>\r
+#include "apps.h"\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+// FROM winsrc\prox.h //////////////////////////////////\r
+#define arraylen(x) (sizeof(x)/sizeof((x)[0]))\r
+\r
+//-----------------------------------------------------------------------------\r
+// Map a sequence of octets (~layer 2 command) into the set of bits to feed\r
+// to the FPGA, to transmit that command to the tag.\r
+//-----------------------------------------------------------------------------\r
+\r
+       \r
+\r
+\r
+       // The sampling rate is 106.353 ksps/s, for T = 18.8 us\r
+\r
+       // SOF defined as \r
+       // 1) Unmodulated time of 56.64us\r
+       // 2) 24 pulses of 423.75khz\r
+       // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)\r
+\r
+       static const int FrameSOF[] = {\r
+               -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+               -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+                1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,\r
+                1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,\r
+               -1, -1, -1, -1,\r
+               -1, -1, -1, -1,\r
+                1,  1,  1,  1,\r
+                1,  1,  1,  1\r
+       };\r
+       static const int Logic0[] = {\r
+                1,  1,  1,  1,\r
+                1,  1,  1,  1,\r
+               -1, -1, -1, -1,\r
+               -1, -1, -1, -1\r
+       };\r
+       static const int Logic1[] = {\r
+               -1, -1, -1, -1,\r
+               -1, -1, -1, -1,\r
+                1,  1,  1,  1,\r
+                1,  1,  1,  1\r
+       };\r
+\r
+       // EOF defined as \r
+       // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)\r
+       // 2) 24 pulses of 423.75khz\r
+       // 3) Unmodulated time of 56.64us\r
+\r
+       static const int FrameEOF[] = {\r
+                1,  1,  1,  1,\r
+                1,  1,  1,  1,\r
+               -1, -1, -1, -1,\r
+               -1, -1, -1, -1,\r
+                1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,\r
+                1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,\r
+               -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+               -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\r
+       };\r
+\r
+\r
+\r
+\r
+static void CodeIso15693AsReader(BYTE *cmd, int n)\r
+{\r
+       int i, j;\r
+\r
+       ToSendReset();\r
+\r
+       // Give it a bit of slack at the beginning\r
+       for(i = 0; i < 24; i++) {\r
+               ToSendStuffBit(1);\r
+       }\r
+\r
+       ToSendStuffBit(0);\r
+       ToSendStuffBit(1);\r
+       ToSendStuffBit(1);\r
+       ToSendStuffBit(1);\r
+       ToSendStuffBit(1);\r
+       ToSendStuffBit(0);\r
+       ToSendStuffBit(1);\r
+       ToSendStuffBit(1);\r
+       for(i = 0; i < n; i++) {\r
+               for(j = 0; j < 8; j += 2) {\r
+                       int these = (cmd[i] >> j) & 3;\r
+                       switch(these) {\r
+                               case 0:\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(0);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       break;\r
+                               case 1:\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(0);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       break;\r
+                               case 2:\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(0);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       break;\r
+                               case 3:\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(1);\r
+                                       ToSendStuffBit(0);\r
+                                       break;\r
+                       }\r
+               }\r
+       }\r
+       ToSendStuffBit(1);\r
+       ToSendStuffBit(1);\r
+       ToSendStuffBit(0);\r
+       ToSendStuffBit(1);\r
+\r
+       // And slack at the end, too.\r
+       for(i = 0; i < 24; i++) {\r
+               ToSendStuffBit(1);\r
+       }\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// The CRC used by ISO 15693.\r
+//-----------------------------------------------------------------------------\r
+static WORD Crc(BYTE *v, int n)\r
+{\r
+       DWORD reg;\r
+       int i, j;\r
+\r
+       reg = 0xffff;\r
+       for(i = 0; i < n; i++) {\r
+               reg = reg ^ ((DWORD)v[i]);\r
+               for (j = 0; j < 8; j++) {\r
+                       if (reg & 0x0001) {\r
+                               reg = (reg >> 1) ^ 0x8408;\r
+                       } else {\r
+                               reg = (reg >> 1);\r
+                       }\r
+               }\r
+       }\r
+\r
+       return ~reg;\r
+}\r
+\r
+////////////////////////////////////////// code to do 'itoa'\r
\r
+\r
+\r
+/* reverse:  reverse string s in place */\r
+void reverse(char s[])\r
+{\r
+    int c, i, j;\r
+\r
+    for (i = 0, j = strlen(s)-1; i<j; i++, j--) {\r
+        c = s[i];\r
+        s[i] = s[j];\r
+        s[j] = c;\r
+    }\r
+}\r
+\r
+/* itoa:  convert n to characters in s */\r
+void itoa(int n, char s[])\r
+{\r
+    int i, sign;\r
+\r
+    if ((sign = n) < 0)  /* record sign */\r
+        n = -n;          /* make n positive */\r
+    i = 0;\r
+    do {       /* generate digits in reverse order */\r
+        s[i++] = n % 10 + '0';   /* get next digit */\r
+    } while ((n /= 10) > 0);     /* delete it */\r
+    if (sign < 0)\r
+        s[i++] = '-';\r
+    s[i] = '\0';\r
+    reverse(s);\r
+} \r
+\r
+//////////////////////////////////////// END 'itoa' CODE\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Encode (into the ToSend buffers) an identify request, which is the first\r
+// thing that you must send to a tag to get a response.\r
+//-----------------------------------------------------------------------------\r
+static void BuildIdentifyRequest(void)\r
+{\r
+       BYTE cmd[5];\r
+\r
+       WORD crc;\r
+       // one sub-carrier, inventory, 1 slot, fast rate\r
+       // AFI is at bit 5 (1<<4) when doing an INVENTORY\r
+       cmd[0] = (1 << 2) | (1 << 5) | (1 << 1); \r
+       // inventory command code\r
+       cmd[1] = 0x01;\r
+       // no mask\r
+       cmd[2] = 0x00;\r
+       //Now the CRC\r
+       crc = Crc(cmd, 3);\r
+       cmd[3] = crc & 0xff;\r
+       cmd[4] = crc >> 8;\r
+\r
+       CodeIso15693AsReader(cmd, sizeof(cmd));\r
+}\r
+\r
+static void BuildSysInfoRequest(BYTE *uid)\r
+{\r
+       BYTE cmd[12];\r
+\r
+       WORD crc;\r
+       // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block\r
+       // followed by teh block data\r
+       // one sub-carrier, inventory, 1 slot, fast rate\r
+       cmd[0] =  (1 << 5) | (1 << 1); // no SELECT bit\r
+       // System Information command code\r
+       cmd[1] = 0x2B;\r
+       // UID may be optionally specified here\r
+       // 64-bit UID\r
+       cmd[2] = 0x32;\r
+       cmd[3]= 0x4b;\r
+       cmd[4] = 0x03;\r
+       cmd[5] = 0x01;\r
+       cmd[6] = 0x00;\r
+       cmd[7] = 0x10;\r
+       cmd[8] = 0x05; \r
+       cmd[9]= 0xe0; // always e0 (not exactly unique)         \r
+       //Now the CRC\r
+       crc = Crc(cmd, 10); // the crc needs to be calculated over 2 bytes \r
+       cmd[10] = crc & 0xff;\r
+       cmd[11] = crc >> 8;\r
+\r
+       CodeIso15693AsReader(cmd, sizeof(cmd));\r
+}\r
+\r
+static void BuildSelectRequest( BYTE uid[])\r
+{\r
+       \r
+//     uid[6]=0x31;  // this is getting ignored - the uid array is not happening...\r
+       BYTE cmd[12];\r
+\r
+       WORD crc;\r
+       // one sub-carrier, inventory, 1 slot, fast rate\r
+       //cmd[0] = (1 << 2) | (1 << 5) | (1 << 1);      // INVENTROY FLAGS\r
+       cmd[0] = (1 << 4) | (1 << 5) | (1 << 1);        // Select and addressed FLAGS\r
+       // SELECT command code\r
+       cmd[1] = 0x25;\r
+       // 64-bit UID\r
+//     cmd[2] = uid[0];//0x32;\r
+//     cmd[3]= uid[1];//0x4b;\r
+//     cmd[4] = uid[2];//0x03;\r
+//     cmd[5] = uid[3];//0x01;\r
+//     cmd[6] = uid[4];//0x00;\r
+//     cmd[7] = uid[5];//0x10;\r
+//     cmd[8] = uid[6];//0x05; \r
+       cmd[2] = 0x32;//\r
+       cmd[3]= 0x4b;\r
+       cmd[4] = 0x03;\r
+       cmd[5] = 0x01;\r
+       cmd[6] = 0x00;\r
+       cmd[7] = 0x10;\r
+       cmd[8] = 0x05; // infineon?\r
+\r
+       cmd[9]= 0xe0; // always e0 (not exactly unique) \r
+\r
+//     DbpIntegers(cmd[8],cmd[7],cmd[6]);\r
+       // Now the CRC\r
+       crc = Crc(cmd, 10); // the crc needs to be calculated over 10 bytes \r
+       cmd[10] = crc & 0xff;\r
+       cmd[11] = crc >> 8;\r
+\r
+       CodeIso15693AsReader(cmd, sizeof(cmd));\r
+}\r
+\r
+static void BuildReadBlockRequest(BYTE *uid, BYTE blockNumber )\r
+{\r
+       BYTE cmd[13];\r
+\r
+       WORD crc;\r
+       // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block\r
+       // followed by teh block data\r
+       // one sub-carrier, inventory, 1 slot, fast rate\r
+       cmd[0] = (1 << 6)| (1 << 5) | (1 << 1); // no SELECT bit\r
+       // READ BLOCK command code\r
+       cmd[1] = 0x20;\r
+       // UID may be optionally specified here\r
+       // 64-bit UID\r
+       cmd[2] = 0x32;\r
+       cmd[3]= 0x4b;\r
+       cmd[4] = 0x03;\r
+       cmd[5] = 0x01;\r
+       cmd[6] = 0x00;\r
+       cmd[7] = 0x10;\r
+       cmd[8] = 0x05; \r
+       cmd[9]= 0xe0; // always e0 (not exactly unique)         \r
+       // Block number to read\r
+       cmd[10] = blockNumber;//0x00;\r
+       //Now the CRC\r
+       crc = Crc(cmd, 11); // the crc needs to be calculated over 2 bytes \r
+       cmd[11] = crc & 0xff;\r
+       cmd[12] = crc >> 8;\r
+\r
+       CodeIso15693AsReader(cmd, sizeof(cmd));\r
+}\r
+\r
+\r
+static void BuildReadMultiBlockRequest(BYTE *uid)\r
+{\r
+       BYTE cmd[14];\r
+\r
+       WORD crc;\r
+       // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block\r
+       // followed by teh block data\r
+       // one sub-carrier, inventory, 1 slot, fast rate\r
+       cmd[0] =  (1 << 5) | (1 << 1); // no SELECT bit\r
+       // READ Multi BLOCK command code\r
+       cmd[1] = 0x23;\r
+       // UID may be optionally specified here\r
+       // 64-bit UID\r
+       cmd[2] = 0x32;\r
+       cmd[3]= 0x4b;\r
+       cmd[4] = 0x03;\r
+       cmd[5] = 0x01;\r
+       cmd[6] = 0x00;\r
+       cmd[7] = 0x10;\r
+       cmd[8] = 0x05; \r
+       cmd[9]= 0xe0; // always e0 (not exactly unique)         \r
+       // First Block number to read\r
+       cmd[10] = 0x00;\r
+       // Number of Blocks to read\r
+       cmd[11] = 0x2f; // read quite a few\r
+       //Now the CRC\r
+       crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes \r
+       cmd[12] = crc & 0xff;\r
+       cmd[13] = crc >> 8;\r
+\r
+       CodeIso15693AsReader(cmd, sizeof(cmd));\r
+}\r
+\r
+static void BuildArbitraryRequest(BYTE *uid,BYTE CmdCode)\r
+{\r
+       BYTE cmd[14];\r
+\r
+       WORD crc;\r
+       // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block\r
+       // followed by teh block data\r
+       // one sub-carrier, inventory, 1 slot, fast rate\r
+       cmd[0] =   (1 << 5) | (1 << 1); // no SELECT bit\r
+       // READ BLOCK command code\r
+       cmd[1] = CmdCode;\r
+       // UID may be optionally specified here\r
+       // 64-bit UID\r
+       cmd[2] = 0x32;\r
+       cmd[3]= 0x4b;\r
+       cmd[4] = 0x03;\r
+       cmd[5] = 0x01;\r
+       cmd[6] = 0x00;\r
+       cmd[7] = 0x10;\r
+       cmd[8] = 0x05; \r
+       cmd[9]= 0xe0; // always e0 (not exactly unique)         \r
+       // Parameter\r
+       cmd[10] = 0x00;\r
+       cmd[11] = 0x0a;\r
+\r
+//     cmd[12] = 0x00;\r
+//     cmd[13] = 0x00; //Now the CRC\r
+       crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes \r
+       cmd[12] = crc & 0xff;\r
+       cmd[13] = crc >> 8;\r
+\r
+       CodeIso15693AsReader(cmd, sizeof(cmd));\r
+}\r
+\r
+static void BuildArbitraryCustomRequest(BYTE *uid,BYTE CmdCode)\r
+{\r
+       BYTE cmd[14];\r
+\r
+       WORD crc;\r
+       // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block\r
+       // followed by teh block data\r
+       // one sub-carrier, inventory, 1 slot, fast rate\r
+       cmd[0] =   (1 << 5) | (1 << 1); // no SELECT bit\r
+       // READ BLOCK command code\r
+       cmd[1] = CmdCode;\r
+       // UID may be optionally specified here\r
+       // 64-bit UID\r
+       cmd[2] = 0x32;\r
+       cmd[3]= 0x4b;\r
+       cmd[4] = 0x03;\r
+       cmd[5] = 0x01;\r
+       cmd[6] = 0x00;\r
+       cmd[7] = 0x10;\r
+       cmd[8] = 0x05; \r
+       cmd[9]= 0xe0; // always e0 (not exactly unique)         \r
+       // Parameter\r
+       cmd[10] = 0x05; // for custom codes this must be manufcturer code\r
+       cmd[11] = 0x00;\r
+\r
+//     cmd[12] = 0x00;\r
+//     cmd[13] = 0x00; //Now the CRC\r
+       crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes \r
+       cmd[12] = crc & 0xff;\r
+       cmd[13] = crc >> 8;\r
+\r
+       CodeIso15693AsReader(cmd, sizeof(cmd));\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////\r
+// Now the VICC>VCD responses when we are simulating a tag\r
+////////////////////////////////////////////////////////////////////\r
+\r
+ static void BuildInventoryResponse(void)\r
+{\r
+       BYTE cmd[12];\r
+\r
+       WORD crc;\r
+       // one sub-carrier, inventory, 1 slot, fast rate\r
+       // AFI is at bit 5 (1<<4) when doing an INVENTORY\r
+       cmd[0] = 0; //(1 << 2) | (1 << 5) | (1 << 1); \r
+       cmd[1] = 0;\r
+       // 64-bit UID\r
+       cmd[2] = 0x32;\r
+       cmd[3]= 0x4b;\r
+       cmd[4] = 0x03;\r
+       cmd[5] = 0x01;\r
+       cmd[6] = 0x00;\r
+       cmd[7] = 0x10;\r
+       cmd[8] = 0x05; \r
+       cmd[9]= 0xe0;\r
+       //Now the CRC\r
+       crc = Crc(cmd, 10);\r
+       cmd[10] = crc & 0xff;\r
+       cmd[11] = crc >> 8;\r
+\r
+       CodeIso15693AsReader(cmd, sizeof(cmd));\r
+}\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Transmit the command (to the tag) that was placed in ToSend[].\r
+//-----------------------------------------------------------------------------\r
+static void TransmitTo15693Tag(const BYTE *cmd, int len, int *samples, int *wait)\r
+{\r
+    int c;\r
+\r
+//    FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);\r
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);\r
+       if(*wait < 10) { *wait = 10; }\r
+\r
+//    for(c = 0; c < *wait;) {\r
+//        if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+//            SSC_TRANSMIT_HOLDING = 0x00;             // For exact timing!\r
+//            c++;\r
+//        }\r
+//        if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+//            volatile DWORD r = SSC_RECEIVE_HOLDING;\r
+//            (void)r;\r
+//        }\r
+//        WDT_HIT();\r
+//    }\r
+\r
+    c = 0;\r
+    for(;;) {\r
+        if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+            SSC_TRANSMIT_HOLDING = cmd[c];\r
+            c++;\r
+            if(c >= len) {\r
+                break;\r
+            }\r
+        }\r
+        if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+            volatile DWORD r = SSC_RECEIVE_HOLDING;\r
+            (void)r;\r
+        }\r
+        WDT_HIT();\r
+    }\r
+       *samples = (c + *wait) << 3;\r
+}\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Transmit the command (to the reader) that was placed in ToSend[].\r
+//-----------------------------------------------------------------------------\r
+static void TransmitTo15693Reader(const BYTE *cmd, int len, int *samples, int *wait)\r
+{\r
+    int c;\r
+\r
+//     FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);\r
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR);        // No requirement to energise my coils\r
+       if(*wait < 10) { *wait = 10; }\r
+\r
+    c = 0;\r
+    for(;;) {\r
+        if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+            SSC_TRANSMIT_HOLDING = cmd[c];\r
+            c++;\r
+            if(c >= len) {\r
+                break;\r
+            }\r
+        }\r
+        if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+            volatile DWORD r = SSC_RECEIVE_HOLDING;\r
+            (void)r;\r
+        }\r
+        WDT_HIT();\r
+    }\r
+       *samples = (c + *wait) << 3;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+static int GetIso15693AnswerFromTag(BYTE *receivedResponse, int maxLen, int *samples, int *elapsed) \r
+{\r
+       int c = 0;\r
+       BYTE *dest = (BYTE *)BigBuf;\r
+       int getNext = 0;\r
+\r
+\r
+       SBYTE prev = 0;\r
+\r
+// NOW READ RESPONSE\r
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
+       //spindelay(60);        // greg - experiment to get rid of some of the 0 byte/failed reads\r
+       c = 0;\r
+       getNext = FALSE;\r
+       for(;;) {\r
+               if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+                       SSC_TRANSMIT_HOLDING = 0x43;\r
+               }\r
+               if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+                       SBYTE b;\r
+                       b = (SBYTE)SSC_RECEIVE_HOLDING;\r
+\r
+                       // The samples are correlations against I and Q versions of the\r
+                       // tone that the tag AM-modulates, so every other sample is I,\r
+                       // every other is Q. We just want power, so abs(I) + abs(Q) is\r
+                       // close to what we want.\r
+                       if(getNext) {\r
+                               SBYTE r;\r
+\r
+                               if(b < 0) {\r
+                                       r = -b;\r
+                               } else {\r
+                                       r = b;\r
+                               }\r
+                               if(prev < 0) {\r
+                                       r -= prev;\r
+                               } else {\r
+                                       r += prev;\r
+                               }\r
+\r
+                               dest[c++] = (BYTE)r;\r
+\r
+                               if(c >= 2000) {\r
+                                       break;\r
+                               }\r
+                       } else {\r
+                               prev = b;\r
+                       }\r
+\r
+                       getNext = !getNext;\r
+               }\r
+       }\r
+\r
+//////////////////////////////////////////\r
+/////////// DEMODULATE ///////////////////\r
+//////////////////////////////////////////\r
+\r
+       int i, j;\r
+       int max = 0, maxPos;\r
+\r
+       int skip = 4;\r
+\r
+\r
+//     if(GraphTraceLen < 1000) return;        // THIS CHECKS FOR A BUFFER TO SMALL\r
+\r
+       // First, correlate for SOF\r
+       for(i = 0; i < 100; i++) {\r
+               int corr = 0;\r
+               for(j = 0; j < arraylen(FrameSOF); j += skip) {\r
+                       corr += FrameSOF[j]*dest[i+(j/skip)];\r
+               }\r
+               if(corr > max) {\r
+                       max = corr;\r
+                       maxPos = i;\r
+               }\r
+       }\r
+//     DbpString("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip));\r
+\r
+       int k = 0; // this will be our return value\r
+\r
+       // greg - If correlation is less than 1 then there's little point in continuing\r
+       if ((max/(arraylen(FrameSOF)/skip)) >= 1) \r
+       {\r
+\r
+       i = maxPos + arraylen(FrameSOF)/skip;\r
+       \r
+       BYTE outBuf[20];\r
+       memset(outBuf, 0, sizeof(outBuf));\r
+       BYTE mask = 0x01;\r
+       for(;;) {\r
+               int corr0 = 0, corr1 = 0, corrEOF = 0;\r
+               for(j = 0; j < arraylen(Logic0); j += skip) {\r
+                       corr0 += Logic0[j]*dest[i+(j/skip)];\r
+               }\r
+               for(j = 0; j < arraylen(Logic1); j += skip) {\r
+                       corr1 += Logic1[j]*dest[i+(j/skip)];\r
+               }\r
+               for(j = 0; j < arraylen(FrameEOF); j += skip) {\r
+                       corrEOF += FrameEOF[j]*dest[i+(j/skip)];\r
+               }\r
+               // Even things out by the length of the target waveform.\r
+               corr0 *= 4;\r
+               corr1 *= 4;\r
+\r
+               if(corrEOF > corr1 && corrEOF > corr0) {\r
+//                     DbpString("EOF at %d", i);\r
+                       break;\r
+               } else if(corr1 > corr0) {\r
+                       i += arraylen(Logic1)/skip;\r
+                       outBuf[k] |= mask;\r
+               } else {\r
+                       i += arraylen(Logic0)/skip;\r
+               }\r
+               mask <<= 1;\r
+               if(mask == 0) {\r
+                       k++;\r
+                       mask = 0x01;\r
+               }\r
+               if((i+(int)arraylen(FrameEOF)) >= 2000) {\r
+                       DbpString("ran off end!");\r
+                       break;\r
+               }\r
+       }\r
+       if(mask != 0x01) {\r
+               DbpString("error, uneven octet! (discard extra bits!)");\r
+///            DbpString("   mask=%02x", mask);\r
+       }\r
+//     BYTE str1 [8];\r
+//     itoa(k,str1);\r
+//     strcat(str1," octets read");\r
+\r
+//     DbpString(  str1);    // DbpString("%d octets", k);\r
+\r
+//     for(i = 0; i < k; i+=3) {\r
+//             //DbpString("# %2d: %02x ", i, outBuf[i]);\r
+//             DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]);\r
+//     }\r
+\r
+       for(i = 0; i < k; i++) {\r
+               receivedResponse[i] = outBuf[i];\r
+       }       \r
+       } // "end if correlation > 0"   (max/(arraylen(FrameSOF)/skip))\r
+       return k; // return the number of bytes demodulated\r
+\r
+///    DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2));\r
+\r
+\r
+}\r
+\r
+// Now the GetISO15693 message from sniffing command\r
+static int GetIso15693AnswerFromSniff(BYTE *receivedResponse, int maxLen, int *samples, int *elapsed) \r
+{\r
+       int c = 0;\r
+       BYTE *dest = (BYTE *)BigBuf;\r
+       int getNext = 0;\r
+\r
+\r
+       SBYTE prev = 0;\r
+\r
+// NOW READ RESPONSE\r
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
+       //spindelay(60);        // greg - experiment to get rid of some of the 0 byte/failed reads\r
+       c = 0;\r
+       getNext = FALSE;\r
+       for(;;) {\r
+               if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+                       SSC_TRANSMIT_HOLDING = 0x43;\r
+               }\r
+               if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+                       SBYTE b;\r
+                       b = (SBYTE)SSC_RECEIVE_HOLDING;\r
+\r
+                       // The samples are correlations against I and Q versions of the\r
+                       // tone that the tag AM-modulates, so every other sample is I,\r
+                       // every other is Q. We just want power, so abs(I) + abs(Q) is\r
+                       // close to what we want.\r
+                       if(getNext) {\r
+                               SBYTE r;\r
+\r
+                               if(b < 0) {\r
+                                       r = -b;\r
+                               } else {\r
+                                       r = b;\r
+                               }\r
+                               if(prev < 0) {\r
+                                       r -= prev;\r
+                               } else {\r
+                                       r += prev;\r
+                               }\r
+\r
+                               dest[c++] = (BYTE)r;\r
+\r
+                               if(c >= 20000) {\r
+                                       break;\r
+                               }\r
+                       } else {\r
+                               prev = b;\r
+                       }\r
+\r
+                       getNext = !getNext;\r
+               }\r
+       }\r
+\r
+//////////////////////////////////////////\r
+/////////// DEMODULATE ///////////////////\r
+//////////////////////////////////////////\r
+\r
+       int i, j;\r
+       int max = 0, maxPos;\r
+\r
+       int skip = 4;\r
+\r
+\r
+//     if(GraphTraceLen < 1000) return;        // THIS CHECKS FOR A BUFFER TO SMALL\r
+\r
+       // First, correlate for SOF\r
+       for(i = 0; i < 19000; i++) {\r
+               int corr = 0;\r
+               for(j = 0; j < arraylen(FrameSOF); j += skip) {\r
+                       corr += FrameSOF[j]*dest[i+(j/skip)];\r
+               }\r
+               if(corr > max) {\r
+                       max = corr;\r
+                       maxPos = i;\r
+               }\r
+       }\r
+//     DbpString("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip));\r
+\r
+       int k = 0; // this will be our return value\r
+\r
+       // greg - If correlation is less than 1 then there's little point in continuing\r
+       if ((max/(arraylen(FrameSOF)/skip)) >= 1)       // THIS SHOULD BE 1 \r
+       {\r
+\r
+       i = maxPos + arraylen(FrameSOF)/skip;\r
+       \r
+       BYTE outBuf[20];\r
+       memset(outBuf, 0, sizeof(outBuf));\r
+       BYTE mask = 0x01;\r
+       for(;;) {\r
+               int corr0 = 0, corr1 = 0, corrEOF = 0;\r
+               for(j = 0; j < arraylen(Logic0); j += skip) {\r
+                       corr0 += Logic0[j]*dest[i+(j/skip)];\r
+               }\r
+               for(j = 0; j < arraylen(Logic1); j += skip) {\r
+                       corr1 += Logic1[j]*dest[i+(j/skip)];\r
+               }\r
+               for(j = 0; j < arraylen(FrameEOF); j += skip) {\r
+                       corrEOF += FrameEOF[j]*dest[i+(j/skip)];\r
+               }\r
+               // Even things out by the length of the target waveform.\r
+               corr0 *= 4;\r
+               corr1 *= 4;\r
+\r
+               if(corrEOF > corr1 && corrEOF > corr0) {\r
+//                     DbpString("EOF at %d", i);\r
+                       break;\r
+               } else if(corr1 > corr0) {\r
+                       i += arraylen(Logic1)/skip;\r
+                       outBuf[k] |= mask;\r
+               } else {\r
+                       i += arraylen(Logic0)/skip;\r
+               }\r
+               mask <<= 1;\r
+               if(mask == 0) {\r
+                       k++;\r
+                       mask = 0x01;\r
+               }\r
+               if((i+(int)arraylen(FrameEOF)) >= 2000) {\r
+                       DbpString("ran off end!");\r
+                       break;\r
+               }\r
+       }\r
+       if(mask != 0x01) {\r
+               DbpString("error, uneven octet! (discard extra bits!)");\r
+///            DbpString("   mask=%02x", mask);\r
+       }\r
+//     BYTE str1 [8];\r
+//     itoa(k,str1);\r
+//     strcat(str1," octets read");\r
+\r
+//     DbpString(  str1);    // DbpString("%d octets", k);\r
+\r
+//     for(i = 0; i < k; i+=3) {\r
+//             //DbpString("# %2d: %02x ", i, outBuf[i]);\r
+//             DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]);\r
+//     }\r
+\r
+       for(i = 0; i < k; i++) {\r
+               receivedResponse[i] = outBuf[i];\r
+       }       \r
+       } // "end if correlation > 0"   (max/(arraylen(FrameSOF)/skip))\r
+       return k; // return the number of bytes demodulated\r
+\r
+///    DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2));\r
+\r
+\r
+}\r
+\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Start to read an ISO 15693 tag. We send an identify request, then wait\r
+// for the response. The response is not demodulated, just left in the buffer\r
+// so that it can be downloaded to a PC and processed there.\r
+//-----------------------------------------------------------------------------\r
+void AcquireRawAdcSamplesIso15693(void)\r
+{\r
+       int c = 0;\r
+       BYTE *dest = (BYTE *)BigBuf;\r
+       int getNext = 0;\r
+\r
+       SBYTE prev = 0;\r
+\r
+       BuildIdentifyRequest();\r
+\r
+       SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
+\r
+       // Give the tags time to energize\r
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
+       SpinDelay(100);\r
+\r
+       // Now send the command\r
+       FpgaSetupSsc();\r
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);\r
+\r
+       c = 0;\r
+       for(;;) {\r
+               if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+                       SSC_TRANSMIT_HOLDING = ToSend[c];\r
+                       c++;\r
+                       if(c == ToSendMax+3) {\r
+                               break;\r
+                       }\r
+               }\r
+               if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+                       volatile DWORD r = SSC_RECEIVE_HOLDING;\r
+                       (void)r;\r
+               }\r
+               WDT_HIT();\r
+       }\r
+\r
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
+\r
+       c = 0;\r
+       getNext = FALSE;\r
+       for(;;) {\r
+               if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+                       SSC_TRANSMIT_HOLDING = 0x43;\r
+               }\r
+               if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+                       SBYTE b;\r
+                       b = (SBYTE)SSC_RECEIVE_HOLDING;\r
+\r
+                       // The samples are correlations against I and Q versions of the\r
+                       // tone that the tag AM-modulates, so every other sample is I,\r
+                       // every other is Q. We just want power, so abs(I) + abs(Q) is\r
+                       // close to what we want.\r
+                       if(getNext) {\r
+                               SBYTE r;\r
+\r
+                               if(b < 0) {\r
+                                       r = -b;\r
+                               } else {\r
+                                       r = b;\r
+                               }\r
+                               if(prev < 0) {\r
+                                       r -= prev;\r
+                               } else {\r
+                                       r += prev;\r
+                               }\r
+\r
+                               dest[c++] = (BYTE)r;\r
+\r
+                               if(c >= 2000) {\r
+                                       break;\r
+                               }\r
+                       } else {\r
+                               prev = b;\r
+                       }\r
+\r
+                       getNext = !getNext;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector\r
+// all demodulation performed in arm rather than host. - greg\r
+//-----------------------------------------------------------------------------\r
+void ReaderIso15693(DWORD parameter)\r
+{\r
+       LED_A_ON();\r
+       LED_B_ON();\r
+       LED_C_OFF();\r
+       LED_D_OFF();\r
+\r
+\r
+//DbpString(parameter);\r
+\r
+       BYTE *receivedAnswer0 = (((BYTE *)BigBuf) + 3560); // allow 100 bytes per reponse (way too much)\r
+       BYTE *receivedAnswer1 = (((BYTE *)BigBuf) + 3660); // \r
+       BYTE *receivedAnswer2 = (((BYTE *)BigBuf) + 3760);\r
+       BYTE *receivedAnswer3 = (((BYTE *)BigBuf) + 3860);\r
+       //BYTE *TagUID= (((BYTE *)BigBuf) + 3960);              // where we hold the uid for hi15reader \r
+       int responseLen0 = 0;\r
+       int responseLen1 = 0;\r
+       int responseLen2 = 0;\r
+       int responseLen3 = 0;\r
+\r
+       // Blank arrays\r
+       int j;\r
+       for(j = 0; j < 100; j++) {\r
+               receivedAnswer3[j] = 0;\r
+               receivedAnswer2[j] =0;\r
+               receivedAnswer1[j] = 0;\r
+               receivedAnswer0[j] = 0;\r
+       }\r
+\r
+       // Setup SSC\r
+       FpgaSetupSsc();\r
+\r
+       // Start from off (no field generated)\r
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
+       SpinDelay(200);\r
+\r
+       SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
+       FpgaSetupSsc();\r
+\r
+       // Give the tags time to energize\r
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
+       SpinDelay(200);\r
+\r
+       LED_A_ON();\r
+       LED_B_OFF();\r
+       LED_C_OFF();\r
+       LED_D_OFF();\r
+\r
+       int samples = 0;\r
+       int tsamples = 0;\r
+       int wait = 0;\r
+       int elapsed = 0;\r
+\r
+       // FIRST WE RUN AN INVENTORY TO GET THE TAG UID\r
+       // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME\r
+ BYTE TagUID[7];               // where we hold the uid for hi15reader \r
+\r
+\r
+//     BuildIdentifyRequest();\r
+//     //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait);      \r
+//     TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait);  // No longer ToSendMax+3\r
+//     // Now wait for a response\r
+//     responseLen0 = GetIso15693AnswerFromTag(receivedAnswer0, 100, &samples, &elapsed) ;     \r
+//     if (responseLen0 >=12) // we should do a better check than this\r
+//     {\r
+//             // really we should check it is a valid mesg\r
+//             // but for now just grab what we think is the uid\r
+//             TagUID[0] = receivedAnswer0[2];\r
+//             TagUID[1] = receivedAnswer0[3];\r
+//             TagUID[2] = receivedAnswer0[4];\r
+//             TagUID[3] = receivedAnswer0[5];\r
+//             TagUID[4] = receivedAnswer0[6];\r
+//             TagUID[5] = receivedAnswer0[7];\r
+//             TagUID[6] = receivedAnswer0[8]; // IC Manufacturer code\r
+//     DbpIntegers(TagUID[6],TagUID[5],TagUID[4]);     \r
+//}\r
+\r
+       // Now send the IDENTIFY command\r
+       BuildIdentifyRequest();\r
+       //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait);      \r
+       TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait);  // No longer ToSendMax+3\r
+       // Now wait for a response\r
+       responseLen1 = GetIso15693AnswerFromTag(receivedAnswer1, 100, &samples, &elapsed) ;\r
+       \r
+       if (responseLen1 >=12) // we should do a better check than this\r
+       {\r
+               \r
+               TagUID[0] = receivedAnswer1[2];\r
+               TagUID[1] = receivedAnswer1[3];\r
+               TagUID[2] = receivedAnswer1[4];\r
+               TagUID[3] = receivedAnswer1[5];\r
+               TagUID[4] = receivedAnswer1[6];\r
+               TagUID[5] = receivedAnswer1[7];\r
+               TagUID[6] = receivedAnswer1[8]; // IC Manufacturer code\r
+               \r
+               // Now send the SELECT command\r
+               BuildSelectRequest(*TagUID);\r
+               TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait);  // No longer ToSendMax+3\r
+               // Now wait for a response\r
+               responseLen2 = GetIso15693AnswerFromTag(receivedAnswer2, 100, &samples, &elapsed); \r
+\r
+               // Now send the MULTI READ command\r
+//             BuildArbitraryRequest(*TagUID,parameter);\r
+               BuildArbitraryCustomRequest(*TagUID,parameter);\r
+//             BuildReadBlockRequest(*TagUID,parameter);\r
+//             BuildSysInfoRequest(*TagUID);\r
+               //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait);      \r
+               TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait);  // No longer ToSendMax+3        \r
+               // Now wait for a response\r
+               responseLen3 = GetIso15693AnswerFromTag(receivedAnswer3, 100, &samples, &elapsed) ;\r
+\r
+       }\r
+\r
+\r
+\r
+       BYTE str1 [4];\r
+       //char str2 [200];\r
+       int i;\r
+\r
+       itoa(responseLen1,str1);\r
+       strcat(str1," octets read from IDENTIFY request");\r
+       DbpString(str1);\r
+       for(i = 0; i < responseLen1; i+=3) {\r
+               DbpIntegers(receivedAnswer1[i],receivedAnswer1[i+1],receivedAnswer1[i+2]);\r
+       }\r
+\r
+       itoa(responseLen2,str1);\r
+       strcat(str1," octets read from SELECT request");\r
+       DbpString(str1);\r
+       for(i = 0; i < responseLen2; i+=3) {\r
+               DbpIntegers(receivedAnswer2[i],receivedAnswer2[i+1],receivedAnswer2[i+2]);\r
+       }\r
+\r
+       itoa(responseLen3,str1);\r
+       strcat(str1," octets read from XXX request");\r
+       DbpString(str1);\r
+       for(i = 0; i < responseLen3; i+=3) {\r
+               DbpIntegers(receivedAnswer3[i],receivedAnswer3[i+1],receivedAnswer3[i+2]);\r
+       }\r
+       \r
+\r
+//     str2[0]=0;\r
+//     for(i = 0; i < responseLen3; i++) {\r
+//             itoa(str1,receivedAnswer3[i]);\r
+//             strcat(str2,str1);\r
+//     }\r
+//     DbpString(str2);        \r
+\r
+       LED_A_OFF();\r
+       LED_B_OFF();\r
+       LED_C_OFF();\r
+       LED_D_OFF();\r
+\r
+\r
+}\r
+\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands\r
+// all demodulation performed in arm rather than host. - greg\r
+//-----------------------------------------------------------------------------\r
+void SimTagIso15693(DWORD parameter)\r
+{\r
+       LED_A_ON();\r
+       LED_B_ON();\r
+       LED_C_OFF();\r
+       LED_D_OFF();\r
+\r
+\r
+//DbpString(parameter);\r
+\r
+       BYTE *receivedAnswer0 = (((BYTE *)BigBuf) + 3560); // allow 100 bytes per reponse (way too much)\r
+       BYTE *receivedAnswer1 = (((BYTE *)BigBuf) + 3660); // \r
+       BYTE *receivedAnswer2 = (((BYTE *)BigBuf) + 3760);\r
+       BYTE *receivedAnswer3 = (((BYTE *)BigBuf) + 3860);\r
+       //BYTE *TagUID= (((BYTE *)BigBuf) + 3960);              // where we hold the uid for hi15reader \r
+       int responseLen0 = 0;\r
+       int responseLen1 = 0;\r
+       int responseLen2 = 0;\r
+       int responseLen3 = 0;\r
+\r
+       // Blank arrays\r
+       int j;\r
+       for(j = 0; j < 100; j++) {\r
+               receivedAnswer3[j] = 0;\r
+               receivedAnswer2[j] =0;\r
+               receivedAnswer1[j] = 0;\r
+               receivedAnswer0[j] = 0;\r
+       }\r
+\r
+       // Setup SSC\r
+       FpgaSetupSsc();\r
+\r
+       // Start from off (no field generated)\r
+       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
+       SpinDelay(200);\r
+\r
+       SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
+       FpgaSetupSsc();\r
+\r
+       // Give the tags time to energize\r
+//     FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);  // NO GOOD FOR SIM TAG!!!!\r
+       SpinDelay(200);\r
+\r
+       LED_A_OFF();\r
+       LED_B_OFF();\r
+       LED_C_ON();\r
+       LED_D_OFF();\r
+\r
+       int samples = 0;\r
+       int tsamples = 0;\r
+       int wait = 0;\r
+       int elapsed = 0;\r
+\r
+       // FIRST WE RUN AN INVENTORY TO GET THE TAG UID\r
+       // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME\r
+ BYTE TagUID[7];               // where we hold the uid for hi15reader \r
+\r
+\r
+\r
+       // Now send the IDENTIFY command\r
+//     BuildIdentifyRequest();\r
+//     TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait);  // No longer ToSendMax+3\r
+\r
+\r
+       // Now wait for a command from the reader\r
+       responseLen1=0;\r
+//     while(responseLen1=0) {\r
+//             if(BUTTON_PRESS()) break;\r
+               responseLen1 = GetIso15693AnswerFromSniff(receivedAnswer1, 100, &samples, &elapsed) ;\r
+//             }\r
+\r
+       \r
+       if (responseLen1 >=1) // we should do a better check than this\r
+       {\r
+               // Build a suitable reponse to the reader INVENTORY cocmmand\r
+               BuildInventoryResponse;\r
+               TransmitTo15693Reader(ToSend,ToSendMax,&tsamples, &wait);\r
+\r
+               // Now wait for a command from the reader\r
+//             responseLen2 = GetIso15693AnswerFromTag(receivedAnswer2, 100, &samples, &elapsed); \r
+\r
+       \r
+               // Now wait for a command from the reader\r
+//             responseLen3 = GetIso15693AnswerFromTag(receivedAnswer3, 100, &samples, &elapsed) ;\r
+\r
+       }\r
+\r
+\r
+\r
+       BYTE str1 [4];\r
+       //char str2 [200];\r
+       int i;\r
+\r
+       itoa(responseLen1,str1);\r
+       strcat(str1," octets read from reader command");\r
+       DbpString(str1);\r
+       for(i = 0; i < responseLen1; i+=3) {\r
+               DbpIntegers(receivedAnswer1[i],receivedAnswer1[i+1],receivedAnswer1[i+2]);\r
+       }\r
+\r
+//     itoa(responseLen2,str1);\r
+//     strcat(str1," octets read from SELECT request");\r
+//     DbpString(str1);\r
+//     for(i = 0; i < responseLen2; i+=3) {\r
+//             DbpIntegers(receivedAnswer2[i],receivedAnswer2[i+1],receivedAnswer2[i+2]);\r
+//     }\r
+//\r
+//     itoa(responseLen3,str1);\r
+//     strcat(str1," octets read from XXX request");\r
+//     DbpString(str1);\r
+//     for(i = 0; i < responseLen3; i+=3) {\r
+//             DbpIntegers(receivedAnswer3[i],receivedAnswer3[i+1],receivedAnswer3[i+2]);\r
+//     }\r
+       \r
+\r
+//     str2[0]=0;\r
+//     for(i = 0; i < responseLen3; i++) {\r
+//             itoa(str1,receivedAnswer3[i]);\r
+//             strcat(str2,str1);\r
+//     }\r
+//     DbpString(str2);        \r
+\r
+       LED_A_OFF();\r
+       LED_B_OFF();\r
+       LED_C_OFF();\r
+       LED_D_OFF();\r
+\r
+\r
+}
\ No newline at end of file
diff --git a/armsrc/ldscript b/armsrc/ldscript
new file mode 100644 (file)
index 0000000..ac0fe2b
--- /dev/null
@@ -0,0 +1,11 @@
+SECTIONS\r
+{\r
+       . = 0x00010000;\r
+       .text : { obj/start.o(.text) *(.text) }\r
+       .rodata : { *(.rodata) }\r
+       . = 0x00200000;\r
+       .data : { *(.data) }\r
+       __bss_start__ = .;\r
+       .bss : { *(.bss) }\r
+       __bss_end__ = .;\r
+}\r
diff --git a/armsrc/ldscript-fpga b/armsrc/ldscript-fpga
new file mode 100644 (file)
index 0000000..da8b1a2
--- /dev/null
@@ -0,0 +1,11 @@
+SECTIONS\r
+{\r
+       . = 0x00002000;\r
+       .text : { obj/fpgaimg.o(.text) *(.text) }\r
+       .rodata : { *(.rodata) }\r
+       . = 0x00200000;\r
+       .data : { *(.data) }\r
+       __bss_start__ = .;\r
+       .bss : { *(.bss) }\r
+       __bss_end__ = .;\r
+}\r
diff --git a/armsrc/start.c b/armsrc/start.c
new file mode 100644 (file)
index 0000000..52296fc
--- /dev/null
@@ -0,0 +1,12 @@
+//-----------------------------------------------------------------------------\r
+// Just vector to AppMain(). This is in its own file so that I can place it\r
+// with the linker script.\r
+// Jonathan Westhues, Mar 2006\r
+//-----------------------------------------------------------------------------\r
+#include <proxmark3.h>\r
+#include "apps.h"\r
+\r
+void Vector(void)\r
+{\r
+       AppMain();\r
+}\r
diff --git a/armsrc/util.c b/armsrc/util.c
new file mode 100644 (file)
index 0000000..b3f0e76
--- /dev/null
@@ -0,0 +1,53 @@
+//-----------------------------------------------------------------------------\r
+// Utility functions used in many places, not specific to any piece of code.\r
+// Jonathan Westhues, Sept 2005\r
+//-----------------------------------------------------------------------------\r
+#include <proxmark3.h>\r
+#include "apps.h"\r
+\r
+void *memcpy(void *dest, const void *src, int len)\r
+{\r
+       BYTE *d = dest;\r
+       const BYTE *s = src;\r
+       while((len--) > 0) {\r
+               *d = *s;\r
+               d++;\r
+               s++;\r
+       }\r
+       return dest;\r
+}\r
+\r
+void *memset(void *dest, int c, int len)\r
+{\r
+       BYTE *d = dest;\r
+       while((len--) > 0) {\r
+               *d = c;\r
+               d++;\r
+       }\r
+       return dest;\r
+}\r
+\r
+int memcmp(const void *av, const void *bv, int len)\r
+{\r
+       const BYTE *a = av;\r
+       const BYTE *b = bv;\r
+\r
+       while((len--) > 0) {\r
+               if(*a != *b) {\r
+                       return *a - *b;\r
+               }\r
+               a++;\r
+               b++;\r
+       }\r
+       return 0;\r
+}\r
+\r
+int strlen(char *str)\r
+{\r
+       int l = 0;\r
+       while(*str) {\r
+               l++;\r
+               str++;\r
+       }\r
+       return l;\r
+}\r
diff --git a/bootrom/Makefile b/bootrom/Makefile
new file mode 100644 (file)
index 0000000..e18737c
--- /dev/null
@@ -0,0 +1,58 @@
+CC       = arm-elf-gcc\r
+AS       = arm-elf-as\r
+LD       = arm-elf-ld\r
+OBJCOPY = arm-elf-objcopy\r
+\r
+OBJDIR  = obj\r
+\r
+INCLUDE = -I../include\r
+\r
+INCLUDES = ../include/proxmark3.h ../include/at91sam7s128.h ../include/config_gpio.h ../include/usb_cmd.h\r
+\r
+CFLAGS  = -g -c $(INCLUDE) -Wall\r
+\r
+OBJJTAG = $(OBJDIR)/bootrom.o $(OBJDIR)/ram-reset.o $(OBJDIR)/usb.o\r
+\r
+OBJFLASH = $(OBJDIR)/flash-reset.o $(OBJDIR)/fromflash.o\r
+\r
+all: bootrom.s19\r
+\r
+bootrom.s19: $(OBJDIR)/bootrom.s19 $(OBJDIR)/bootrom-forjtag.s19\r
+    @echo bootrom.s19\r
+       @perl ..\tools\merge-srec.pl $(OBJDIR)\bootrom.s19 $(OBJDIR)\bootrom-forjtag.s19 > $(OBJDIR)\bootrom-merged.s19\r
+       @perl ..\tools\srecswap.pl $(OBJDIR)\bootrom-forjtag.s19 > $(OBJDIR)\bootrom-forjtag-swapped.s19\r
+\r
+$(OBJDIR)/bootrom.s19: $(OBJFLASH)\r
+    @echo obj/bootrom.s19\r
+       @$(LD) -g -Tldscript-flash --oformat elf32-littlearm -o $(OBJDIR)/bootrom.elf $(OBJFLASH)\r
+       @$(OBJCOPY) -Osrec --srec-forceS3 $(OBJDIR)/bootrom.elf $(OBJDIR)/bootrom.s19\r
+\r
+$(OBJDIR)/bootrom-forjtag.s19: $(OBJJTAG)\r
+    @echo obj/bootrom-forjtag.s19\r
+       @$(LD) -g -Tldscript-ram-jtag --oformat elf32-littlearm -o $(OBJDIR)/bootrom-forjtag.elf $(OBJJTAG)\r
+       @$(OBJCOPY) -Osrec --srec-forceS3 $(OBJDIR)/bootrom-forjtag.elf $(OBJDIR)/bootrom-forjtag.s19\r
+\r
+$(OBJDIR)/bootrom.o: bootrom.c $(INCLUDES)\r
+    @echo $(@B).c\r
+       @$(CC) $(CFLAGS) -mthumb -mthumb-interwork bootrom.c -o $(OBJDIR)/bootrom.o\r
+\r
+$(OBJDIR)/fromflash.o: fromflash.c $(INCLUDES)\r
+    @echo $(@B).c\r
+       @$(CC) $(CFLAGS) -mthumb -mthumb-interwork fromflash.c -o $(OBJDIR)/fromflash.o\r
+\r
+$(OBJDIR)/usb.o: ../common/usb.c $(INCLUDES)\r
+    @echo $(@B).c\r
+       @$(CC) $(CFLAGS) -mthumb -mthumb-interwork ../common/usb.c -o $(OBJDIR)/usb.o\r
+\r
+$(OBJDIR)/ram-reset.o: ram-reset.s\r
+    @echo $(@B).s\r
+       @$(CC) $(CFLAGS) -mthumb-interwork -o $(OBJDIR)/ram-reset.o ram-reset.s\r
+\r
+$(OBJDIR)/flash-reset.o: flash-reset.s\r
+    @echo $(@B).s\r
+       @$(CC) $(CFLAGS) -mthumb-interwork -o $(OBJDIR)/flash-reset.o flash-reset.s\r
+\r
+clean:\r
+       del /q obj\*.o\r
+       del /q obj\*.elf\r
+       del /q obj\*.s19\r
diff --git a/bootrom/bootrom.c b/bootrom/bootrom.c
new file mode 100644 (file)
index 0000000..c654db2
--- /dev/null
@@ -0,0 +1,190 @@
+#include <proxmark3.h>\r
+\r
+static void ConfigClocks(void)\r
+{\r
+    // we are using a 16 MHz crystal as the basis for everything\r
+    // slow clock runs at 32Khz typical regardless of crystal\r
+\r
+    // enable system clock and USB clock\r
+    PMC_SYS_CLK_ENABLE = PMC_SYS_CLK_PROCESSOR_CLK | PMC_SYS_CLK_UDP_CLK;\r
+\r
+       // enable the clock to the following peripherals\r
+    PMC_PERIPHERAL_CLK_ENABLE =\r
+        (1<<PERIPH_PIOA) |\r
+        (1<<PERIPH_ADC) |\r
+        (1<<PERIPH_SPI) |\r
+        (1<<PERIPH_SSC) |\r
+        (1<<PERIPH_PWMC) |\r
+        (1<<PERIPH_UDP);\r
+\r
+       // worst case scenario, with 16Mhz xtal startup delay is 14.5ms\r
+       // with a slow clock running at it worst case (max) frequency of 42khz\r
+       // max startup delay = (14.5ms*42k)/8 = 76 = 0x4C round up to 0x50\r
+\r
+       // enable main oscillator and set startup delay\r
+    PMC_MAIN_OSCILLATOR = PMC_MAIN_OSCILLATOR_ENABLE |\r
+        PMC_MAIN_OSCILLATOR_STARTUP_DELAY(0x50);\r
+\r
+       // wait for main oscillator to stabilize\r
+       while ( !(PMC_INTERRUPT_STATUS & PMC_MAIN_OSCILLATOR_STABILIZED) )\r
+               ;\r
+\r
+    // minimum PLL clock frequency is 80 MHz in range 00 (96 here so okay)\r
+    // frequency is crystal * multiplier / divisor = 16Mhz * 12 / 2 = 96Mhz\r
+    PMC_PLL = PMC_PLL_DIVISOR(2) | PMC_PLL_COUNT_BEFORE_LOCK(0x50) |\r
+        PMC_PLL_FREQUENCY_RANGE(0) | PMC_PLL_MULTIPLIER(12) |\r
+        PMC_PLL_USB_DIVISOR(1);\r
+\r
+       // wait for PLL to lock\r
+       while ( !(PMC_INTERRUPT_STATUS & PMC_MAIN_OSCILLATOR_PLL_LOCK) )\r
+               ;\r
+\r
+       // we want a master clock (MCK) to be PLL clock / 2 = 96Mhz / 2 = 48Mhz\r
+       // as per datasheet, this register must be programmed in two operations\r
+       // when changing to PLL, program the prescaler first then the source\r
+    PMC_MASTER_CLK = PMC_CLK_PRESCALE_DIV_2;\r
+\r
+       // wait for main clock ready signal\r
+       while ( !(PMC_INTERRUPT_STATUS & PMC_MAIN_OSCILLATOR_MCK_READY) )\r
+               ;\r
+\r
+       // set the source to PLL\r
+    PMC_MASTER_CLK = PMC_CLK_SELECTION_PLL_CLOCK | PMC_CLK_PRESCALE_DIV_2;\r
+\r
+       // wait for main clock ready signal\r
+       while ( !(PMC_INTERRUPT_STATUS & PMC_MAIN_OSCILLATOR_MCK_READY) )\r
+               ;\r
+}\r
+\r
+static void Fatal(void)\r
+{\r
+    for(;;);\r
+}\r
+\r
+void UsbPacketReceived(BYTE *packet, int len)\r
+{\r
+    int i;\r
+    UsbCommand *c = (UsbCommand *)packet;\r
+    volatile DWORD *p;\r
+\r
+    if(len != sizeof(*c)) {\r
+        Fatal();\r
+    }\r
+\r
+    switch(c->cmd) {\r
+        case CMD_DEVICE_INFO:\r
+            break;\r
+\r
+        case CMD_SETUP_WRITE:\r
+            p = (volatile DWORD *)0;\r
+            for(i = 0; i < 12; i++) {\r
+                p[i+c->ext1] = c->d.asDwords[i];\r
+            }\r
+            break;\r
+\r
+        case CMD_FINISH_WRITE:\r
+            p = (volatile DWORD *)0;\r
+            for(i = 0; i < 4; i++) {\r
+                p[i+60] = c->d.asDwords[i];\r
+            }\r
+\r
+            MC_FLASH_COMMAND = MC_FLASH_COMMAND_KEY |\r
+                MC_FLASH_COMMAND_PAGEN(c->ext1/FLASH_PAGE_SIZE_BYTES) |\r
+                FCMD_WRITE_PAGE;\r
+            while(!(MC_FLASH_STATUS & MC_FLASH_STATUS_READY))\r
+                ;\r
+            break;\r
+\r
+        case CMD_HARDWARE_RESET:\r
+            break;\r
+\r
+        default:\r
+            Fatal();\r
+            break;\r
+    }\r
+\r
+    c->cmd = CMD_ACK;\r
+    UsbSendPacket(packet, len);\r
+}\r
+\r
+void BootROM(void)\r
+{\r
+    //------------\r
+    // First set up all the I/O pins; GPIOs configured directly, other ones\r
+    // just need to be assigned to the appropriate peripheral.\r
+\r
+    // Kill all the pullups, especially the one on USB D+; leave them for\r
+    // the unused pins, though.\r
+    PIO_NO_PULL_UP_ENABLE =     (1 << GPIO_USB_PU)          |\r
+                                (1 << GPIO_LED_A)           |\r
+                                (1 << GPIO_LED_B)           |\r
+                                (1 << GPIO_LED_C)           |\r
+                                (1 << GPIO_LED_D)           |\r
+                                (1 << GPIO_FPGA_DIN)        |\r
+                                (1 << GPIO_FPGA_DOUT)       |\r
+                                (1 << GPIO_FPGA_CCLK)       |\r
+                                (1 << GPIO_FPGA_NINIT)      |\r
+                                (1 << GPIO_FPGA_NPROGRAM)   |\r
+                                (1 << GPIO_FPGA_DONE)       |\r
+                                (1 << GPIO_MUXSEL_HIPKD)    |\r
+                                (1 << GPIO_MUXSEL_HIRAW)    |\r
+                                (1 << GPIO_MUXSEL_LOPKD)    |\r
+                                (1 << GPIO_MUXSEL_LORAW)    |\r
+                                (1 << GPIO_RELAY)              |\r
+                                (1 << GPIO_NVDD_ON);\r
+                                // (and add GPIO_FPGA_ON)\r
+       // These pins are outputs\r
+    PIO_OUTPUT_ENABLE =         (1 << GPIO_LED_A)           |\r
+                                (1 << GPIO_LED_B)           |\r
+                                (1 << GPIO_LED_C)           |\r
+                                (1 << GPIO_LED_D)           |\r
+                                (1 << GPIO_RELAY)              |\r
+                                (1 << GPIO_NVDD_ON);\r
+       // PIO controls the following pins\r
+    PIO_ENABLE =                (1 << GPIO_USB_PU)          |\r
+                                (1 << GPIO_LED_A)           |\r
+                                (1 << GPIO_LED_B)           |\r
+                                (1 << GPIO_LED_C)           |\r
+                                (1 << GPIO_LED_D);\r
+\r
+    USB_D_PLUS_PULLUP_OFF();\r
+    LED_D_OFF();\r
+    LED_C_ON();\r
+    LED_B_OFF();\r
+    LED_A_OFF();\r
+\r
+       // if 512K FLASH part - TODO make some defines :)\r
+       if ((DBGU_CIDR | 0xf00) == 0xa00) {\r
+               MC_FLASH_MODE0 = MC_FLASH_MODE_FLASH_WAIT_STATES(1) |\r
+                       MC_FLASH_MODE_MASTER_CLK_IN_MHZ(0x48);\r
+               MC_FLASH_MODE1 = MC_FLASH_MODE_FLASH_WAIT_STATES(1) |\r
+                       MC_FLASH_MODE_MASTER_CLK_IN_MHZ(0x48);\r
+       } else {\r
+               MC_FLASH_MODE0 = MC_FLASH_MODE_FLASH_WAIT_STATES(0) |\r
+                       MC_FLASH_MODE_MASTER_CLK_IN_MHZ(48);\r
+       }\r
+\r
+       // Initialize all system clocks\r
+    ConfigClocks();\r
+\r
+    LED_A_ON();\r
+\r
+       if(BUTTON_PRESS()) {\r
+       UsbStart();\r
+       }\r
+\r
+    for(;;) {\r
+        WDT_HIT();\r
+\r
+        UsbPoll(TRUE);\r
+\r
+               if(!BUTTON_PRESS()) {\r
+            USB_D_PLUS_PULLUP_OFF();\r
+            LED_B_ON();\r
+\r
+                       // jump to RAM address 0x10000 (LSBit set for thumb mode)\r
+            asm("ldr r3, = 0x10001\n");\r
+            asm("bx r3\n");\r
+        }\r
+    }\r
+}\r
diff --git a/bootrom/flash-reset.s b/bootrom/flash-reset.s
new file mode 100644 (file)
index 0000000..afb658a
--- /dev/null
@@ -0,0 +1,38 @@
+.extern CopyBootToRAM\r
+    \r
+.text\r
+.code 32\r
+.align 0\r
+\r
+.global start\r
+start:\r
+    b       Reset\r
+    b       UndefinedInstruction\r
+    b       SoftwareInterrupt\r
+    b       PrefetchAbort\r
+    b       DataAbort\r
+    b       Reserved\r
+    b       Irq\r
+    b       Fiq\r
+\r
+Reset:\r
+    ldr     sp,     = 0x0020FFF8       @ initialize stack pointer to top of RAM\r
+    bl      CopyBootToRAM                      @ copy bootloader to RAM (in case the\r
+                                                               @ user re-flashes the bootloader)\r
+    ldr     r3,     = 0x00200000       @ start address of RAM bootloader\r
+    bx      r3                                         @ jump to it\r
+\r
+Fiq:\r
+    b       Fiq\r
+UndefinedInstruction:\r
+    b       UndefinedInstruction\r
+SoftwareInterrupt:\r
+    b       SoftwareInterrupt\r
+PrefetchAbort:\r
+    b       PrefetchAbort\r
+DataAbort:\r
+    b       DataAbort\r
+Reserved:\r
+    b       Reserved\r
+Irq:\r
+    b       Irq\r
diff --git a/bootrom/fromflash.c b/bootrom/fromflash.c
new file mode 100644 (file)
index 0000000..e686809
--- /dev/null
@@ -0,0 +1,11 @@
+#include <proxmark3.h>\r
+\r
+void CopyBootToRAM(void)\r
+{\r
+       int i;\r
+\r
+       volatile DWORD *s = (volatile DWORD *)0x200;\r
+       volatile DWORD *d = (volatile DWORD *)0x200000;\r
+\r
+       for(i = 0; i < 1024; i++) *d++ = *s++;\r
+}\r
diff --git a/bootrom/ldscript-flash b/bootrom/ldscript-flash
new file mode 100644 (file)
index 0000000..0d5d732
--- /dev/null
@@ -0,0 +1,11 @@
+SECTIONS\r
+{\r
+    . = 0x00000000;\r
+    .text : { obj/flash-reset.o(.text) *(.text) }\r
+    .rodata : { *(.rodata) }\r
+    . = 0x00200000;\r
+    .data : { *(.data) }\r
+    __bss_start__ = .;\r
+    .bss : { *(.bss) }\r
+    __bss_end__ = .;\r
+}\r
diff --git a/bootrom/ldscript-ram-jtag b/bootrom/ldscript-ram-jtag
new file mode 100644 (file)
index 0000000..5dd5706
--- /dev/null
@@ -0,0 +1,10 @@
+SECTIONS\r
+{\r
+    . = 0x00200000;\r
+    .text : { obj/ram-reset.o(.text) *(.text) }\r
+    .rodata : { *(.rodata) }\r
+    .data : { *(.data) }\r
+    __bss_start__ = .;\r
+    .bss : { *(.bss) }\r
+    __bss_end__ = .;\r
+}\r
diff --git a/bootrom/ram-reset.s b/bootrom/ram-reset.s
new file mode 100644 (file)
index 0000000..56bf36e
--- /dev/null
@@ -0,0 +1,10 @@
+.extern BootROM\r
+    \r
+.text\r
+.code 32\r
+.align 0\r
+\r
+.global start\r
+start:\r
+    ldr     sp,     = 0x0020FFF8\r
+    bl      BootROM\r
diff --git a/cockpit/0setpath.bat b/cockpit/0setpath.bat
new file mode 100644 (file)
index 0000000..5010957
--- /dev/null
@@ -0,0 +1,5 @@
+@echo off\r
+set PATH=..\..\devkitARM\bin;..\..\devkitWIN\bin;%PATH%\r
+set INCLUDE=..\..\devkitWIN\include\r
+set LIB=..\..\devkitWIN\lib\r
+cmd.exe
\ No newline at end of file
diff --git a/cockpit/1makearm.bat b/cockpit/1makearm.bat
new file mode 100644 (file)
index 0000000..a8ecb6e
--- /dev/null
@@ -0,0 +1,5 @@
+@echo off\r
+cd ..\armsrc\r
+rem nmake clean\r
+nmake\r
+cd ..\cockpit\r
diff --git a/cockpit/2makeboot.bat b/cockpit/2makeboot.bat
new file mode 100644 (file)
index 0000000..a56fcfe
--- /dev/null
@@ -0,0 +1,5 @@
+@echo off\r
+cd ..\bootrom\r
+rem nmake clean\r
+nmake\r
+cd ..\cockpit\r
diff --git a/cockpit/3makewin.bat b/cockpit/3makewin.bat
new file mode 100644 (file)
index 0000000..82228e3
--- /dev/null
@@ -0,0 +1,5 @@
+@echo off\r
+cd ..\winsrc\r
+rem nmake clean\r
+nmake\r
+cd ..\cockpit\r
diff --git a/cockpit/4flashos.bat b/cockpit/4flashos.bat
new file mode 100644 (file)
index 0000000..6f22618
--- /dev/null
@@ -0,0 +1,3 @@
+@echo off\r
+..\winsrc\prox.exe load ..\armsrc\obj\osimage.s19\r
+..\winsrc\prox.exe load ..\armsrc\obj\osimage.s19\r
diff --git a/cockpit/5makeall.bat b/cockpit/5makeall.bat
new file mode 100644 (file)
index 0000000..072393d
--- /dev/null
@@ -0,0 +1,3 @@
+call 1makearm.bat\r
+call 2makeboot.bat\r
+call 3makewin.bat\r
diff --git a/cockpit/prox.bat b/cockpit/prox.bat
new file mode 100644 (file)
index 0000000..06b24ed
--- /dev/null
@@ -0,0 +1,3 @@
+@echo off\r
+cd ..\winsrc\r
+call prox gui
\ No newline at end of file
diff --git a/common/iso14443_crc.c b/common/iso14443_crc.c
new file mode 100644 (file)
index 0000000..cf29d0e
--- /dev/null
@@ -0,0 +1,35 @@
+//-----------------------------------------------------------------------------\r
+// Routines to compute the CRCs (two different flavours, just for confusion)\r
+// required for ISO 14443, swiped directly from the spec.\r
+//-----------------------------------------------------------------------------\r
+\r
+#define        CRC_14443_A     0x6363  /* ITU-V.41 */\r
+#define        CRC_14443_B 0xFFFF  /* ISO/IEC 13239 (formerly ISO/IEC 3309) */\r
+\r
+static unsigned short UpdateCrc14443(unsigned char ch, unsigned short *lpwCrc)\r
+{\r
+    ch = (ch ^ (unsigned char) ((*lpwCrc) & 0x00FF));\r
+    ch = (ch ^ (ch << 4));\r
+    *lpwCrc =  (*lpwCrc >> 8) ^ ((unsigned short) ch << 8) ^\r
+               ((unsigned short) ch << 3) ^ ((unsigned short) ch >> 4);\r
+    return (*lpwCrc);\r
+}\r
+\r
+static void ComputeCrc14443(int CrcType, BYTE *Data, int Length,\r
+           BYTE *TransmitFirst, BYTE *TransmitSecond)\r
+{\r
+    unsigned char chBlock;\r
+    unsigned short wCrc=CrcType;\r
+\r
+       do {\r
+        chBlock = *Data++;\r
+        UpdateCrc14443(chBlock, &wCrc);\r
+    } while (--Length);\r
+\r
+    if (CrcType == CRC_14443_B)\r
+        wCrc = ~wCrc;                /* ISO/IEC 13239 (formerly ISO/IEC 3309) */\r
+\r
+    *TransmitFirst = (BYTE) (wCrc & 0xFF);\r
+    *TransmitSecond = (BYTE) ((wCrc >> 8) & 0xFF);\r
+    return;\r
+}\r
diff --git a/common/usb.c b/common/usb.c
new file mode 100644 (file)
index 0000000..f0b9529
--- /dev/null
@@ -0,0 +1,472 @@
+//-----------------------------------------------------------------------------\r
+// My USB driver. This has to be common, because it exists in both the\r
+// bootrom and the application.\r
+// Jonathan Westhues, split Aug 14 2005\r
+//-----------------------------------------------------------------------------\r
+#include <proxmark3.h>\r
+\r
+#define min(a, b) (((a) > (b)) ? (b) : (a))\r
+\r
+#define USB_REPORT_PACKET_SIZE 64\r
+\r
+typedef struct PACKED {\r
+       BYTE    bmRequestType;\r
+       BYTE    bRequest;\r
+       WORD    wValue;\r
+       WORD    wIndex;\r
+       WORD    wLength;\r
+} UsbSetupData;\r
+\r
+#define USB_REQUEST_GET_STATUS                                 0\r
+#define USB_REQUEST_CLEAR_FEATURE                              1\r
+#define USB_REQUEST_SET_FEATURE                                        3\r
+#define USB_REQUEST_SET_ADDRESS                                        5\r
+#define USB_REQUEST_GET_DESCRIPTOR                             6\r
+#define USB_REQUEST_SET_DESCRIPTOR                             7\r
+#define USB_REQUEST_GET_CONFIGURATION                  8\r
+#define USB_REQUEST_SET_CONFIGURATION                  9\r
+#define USB_REQUEST_GET_INTERFACE                              10\r
+#define USB_REQUEST_SET_INTERFACE                              11\r
+#define USB_REQUEST_SYNC_FRAME                                 12\r
+\r
+#define USB_DESCRIPTOR_TYPE_DEVICE                             1\r
+#define USB_DESCRIPTOR_TYPE_CONFIGURATION              2\r
+#define USB_DESCRIPTOR_TYPE_STRING                             3\r
+#define USB_DESCRIPTOR_TYPE_INTERFACE                  4\r
+#define USB_DESCRIPTOR_TYPE_ENDPOINT                   5\r
+#define USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER   6\r
+#define USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONF   7\r
+#define USB_DESCRIPTOR_TYPE_INTERFACE_POWER            8\r
+#define USB_DESCRIPTOR_TYPE_HID                                        0x21\r
+#define USB_DESCRIPTOR_TYPE_HID_REPORT                 0x22\r
+\r
+#define USB_DEVICE_CLASS_HID                                   0x03\r
+\r
+static const BYTE HidReportDescriptor[] = {\r
+       0x06,0xA0,0xFF, // Usage Page (vendor defined) FFA0\r
+       0x09,0x01,              // Usage (vendor defined)\r
+       0xA1,0x01,              // Collection (Application)\r
+       0x09,0x02,      // Usage (vendor defined)\r
+       0xA1,0x00,      // Collection (Physical)\r
+       0x06,0xA1,0xFF, // Usage Page (vendor defined)\r
+\r
+       //The,input report\r
+       0x09,0x03,      // usage - vendor defined\r
+       0x09,0x04,      // usage - vendor defined\r
+       0x15,0x80,      // Logical Minimum (-128)\r
+       0x25,0x7F,      // Logical Maximum (127)\r
+       0x35,0x00,      // Physical Minimum (0)\r
+       0x45,0xFF,      // Physical Maximum (255)\r
+       0x75,0x08,      // Report Size (8)  (bits)\r
+       0x95,0x40,      // Report Count (64)  (fields)\r
+       0x81,0x02,      // Input (Data,Variable,Absolute)\r
+\r
+       //The,output report\r
+       0x09,0x05,      // usage - vendor defined\r
+       0x09,0x06,      // usage - vendor defined\r
+       0x15,0x80,      // Logical Minimum (-128)\r
+       0x25,0x7F,      // Logical Maximum (127)\r
+       0x35,0x00,      // Physical Minimum (0)\r
+       0x45,0xFF,      // Physical Maximum (255)\r
+       0x75,0x08,      // Report Size (8)  (bits)\r
+       0x95,0x40,      // Report Count (64)  (fields)\r
+       0x91,0x02,      // Output (Data,Variable,Absolute)\r
+\r
+       0xC0,                   // End Collection\r
+\r
+       0xC0,                   // End Collection\r
+};\r
+\r
+static const BYTE DeviceDescriptor[] = {\r
+       0x12,                   // Descriptor length (18 bytes)\r
+       0x01,                   // Descriptor type (Device)\r
+       0x10,0x01,              // Complies with USB Spec. Release (0110h = release 1.10)\r
+       0x00,                   // Class code (0)\r
+       0x00,                   // Subclass code (0)\r
+       0x00,                   // Protocol (No specific protocol)\r
+       0x08,                   // Maximum packet size for Endpoint 0 (8 bytes)\r
+       0xc4,0x9a,              // Vendor ID (random numbers)\r
+       0x8f,0x4b,              // Product ID (random numbers)\r
+       0x01,0x00,              // Device release number (0001)\r
+       0x01,                   // Manufacturer string descriptor index\r
+       0x02,                   // Product string descriptor index\r
+       0x00,                   // Serial Number string descriptor index (None)\r
+       0x01,                   // Number of possible configurations (1)\r
+};\r
+\r
+static const BYTE ConfigurationDescriptor[] = {\r
+       0x09,                   // Descriptor length (9 bytes)\r
+       0x02,                   // Descriptor type (Configuration)\r
+       0x29,0x00,              // Total data length (41 bytes)\r
+       0x01,                   // Interface supported (1)\r
+       0x01,                   // Configuration value (1)\r
+       0x00,                   // Index of string descriptor (None)\r
+       0x80,                   // Configuration (Bus powered)\r
+       250,                    // Maximum power consumption (500mA)\r
+\r
+       //interface\r
+       0x09,                   // Descriptor length (9 bytes)\r
+       0x04,                   // Descriptor type (Interface)\r
+       0x00,                   // Number of interface (0)\r
+       0x00,                   // Alternate setting (0)\r
+       0x02,                   // Number of interface endpoint (2)\r
+       0x03,                   // Class code (HID)\r
+       0x00,                   // Subclass code ()\r
+       0x00,                   // Protocol code ()\r
+       0x00,                   // Index of string()\r
+\r
+       // class\r
+       0x09,                   // Descriptor length (9 bytes)\r
+       0x21,                   // Descriptor type (HID)\r
+       0x00,0x01,              // HID class release number (1.00)\r
+       0x00,                   // Localized country code (None)\r
+       0x01,                   // # of HID class dscrptr to follow (1)\r
+       0x22,                   // Report descriptor type (HID)\r
+       // Total length of report descriptor\r
+       sizeof(HidReportDescriptor),0x00,\r
+\r
+       // endpoint 1\r
+       0x07,                   // Descriptor length (7 bytes)\r
+       0x05,                   // Descriptor type (Endpoint)\r
+       0x01,                   // Encoded address (Respond to OUT)\r
+       0x03,                   // Endpoint attribute (Interrupt transfer)\r
+       0x08,0x00,              // Maximum packet size (8 bytes)\r
+       0x01,                   // Polling interval (1 ms)\r
+\r
+       // endpoint 2\r
+       0x07,                   // Descriptor length (7 bytes)\r
+       0x05,                   // Descriptor type (Endpoint)\r
+       0x82,                   // Encoded address (Respond to IN)\r
+       0x03,                   // Endpoint attribute (Interrupt transfer)\r
+       0x08,0x00,              // Maximum packet size (8 bytes)\r
+       0x01,                   // Polling interval (1 ms)\r
+};\r
+\r
+static const BYTE StringDescriptor0[] = {\r
+       0x04,                   // Length\r
+       0x03,                   // Type is string\r
+       0x09,                   // English\r
+       0x04,                   //  US\r
+};\r
+\r
+static const BYTE StringDescriptor1[] = {\r
+       24,                             // Length\r
+       0x03,                   // Type is string\r
+       'J', 0x00,\r
+       '.', 0x00,\r
+       ' ', 0x00,\r
+       'W', 0x00,\r
+       'e', 0x00,\r
+       's', 0x00,\r
+       't', 0x00,\r
+       'h', 0x00,\r
+       'u', 0x00,\r
+       'e', 0x00,\r
+       's', 0x00,\r
+};\r
+\r
+static const BYTE StringDescriptor2[] = {\r
+       54,                             // Length\r
+       0x03,                   // Type is string\r
+       'P', 0x00,\r
+       'r', 0x00,\r
+       'o', 0x00,\r
+       'x', 0x00,\r
+       'M', 0x00,\r
+       'a', 0x00,\r
+       'r', 0x00,\r
+       'k', 0x00,\r
+       '-', 0x00,\r
+       '3', 0x00,\r
+       ' ', 0x00,\r
+       'R', 0x00,\r
+       'F', 0x00,\r
+       'I', 0x00,\r
+       'D', 0x00,\r
+       ' ', 0x00,\r
+       'I', 0x00,\r
+       'n', 0x00,\r
+       's', 0x00,\r
+       't', 0x00,\r
+       'r', 0x00,\r
+       'u', 0x00,\r
+       'm', 0x00,\r
+       'e', 0x00,\r
+       'n', 0x00,\r
+       't', 0x00,\r
+};\r
+\r
+static const BYTE * const StringDescriptors[] = {\r
+       StringDescriptor0,\r
+       StringDescriptor1,\r
+       StringDescriptor2,\r
+};\r
+\r
+\r
+static BYTE UsbBuffer[64];\r
+static int  UsbSoFarCount;\r
+\r
+static BYTE CurrentConfiguration;\r
+\r
+static void UsbSendEp0(const BYTE *data, int len)\r
+{\r
+       int thisTime, i;\r
+\r
+       do {\r
+               thisTime = min(len, 8);\r
+               len -= thisTime;\r
+\r
+               for(i = 0; i < thisTime; i++) {\r
+                       UDP_ENDPOINT_FIFO(0) = *data;\r
+                       data++;\r
+               }\r
+\r
+               if(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED) {\r
+                       UDP_ENDPOINT_CSR(0) &= ~UDP_CSR_TX_PACKET_ACKED;\r
+                       while(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED)\r
+                               ;\r
+               }\r
+\r
+               UDP_ENDPOINT_CSR(0) |= UDP_CSR_TX_PACKET;\r
+\r
+               do {\r
+                       if(UDP_ENDPOINT_CSR(0) & UDP_CSR_RX_PACKET_RECEIVED_BANK_0) {\r
+                               // This means that the host is trying to write to us, so\r
+                               // abandon our write to them.\r
+                               UDP_ENDPOINT_CSR(0) &= ~UDP_CSR_RX_PACKET_RECEIVED_BANK_0;\r
+                               return;\r
+                       }\r
+               } while(!(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED));\r
+       } while(len > 0);\r
+\r
+       if(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED) {\r
+               UDP_ENDPOINT_CSR(0) &= ~UDP_CSR_TX_PACKET_ACKED;\r
+               while(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED)\r
+                       ;\r
+       }\r
+}\r
+\r
+static void UsbSendZeroLength(void)\r
+{\r
+       UDP_ENDPOINT_CSR(0) |= UDP_CSR_TX_PACKET;\r
+\r
+       while(!(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED))\r
+               ;\r
+\r
+       UDP_ENDPOINT_CSR(0) &= ~UDP_CSR_TX_PACKET_ACKED;\r
+\r
+       while(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED)\r
+               ;\r
+}\r
+\r
+static void HandleRxdSetupData(void)\r
+{\r
+       int i;\r
+       UsbSetupData usd;\r
+\r
+       for(i = 0; i < sizeof(usd); i++) {\r
+               ((BYTE *)&usd)[i] = UDP_ENDPOINT_FIFO(0);\r
+       }\r
+\r
+       if(usd.bmRequestType & 0x80) {\r
+               UDP_ENDPOINT_CSR(0) |= UDP_CSR_CONTROL_DATA_DIR;\r
+               while(!(UDP_ENDPOINT_CSR(0) & UDP_CSR_CONTROL_DATA_DIR))\r
+                       ;\r
+       }\r
+\r
+       UDP_ENDPOINT_CSR(0) &= ~UDP_CSR_RX_HAVE_READ_SETUP_DATA;\r
+       while(UDP_ENDPOINT_CSR(0) & UDP_CSR_RX_HAVE_READ_SETUP_DATA)\r
+               ;\r
+\r
+       switch(usd.bRequest) {\r
+               case USB_REQUEST_GET_DESCRIPTOR:\r
+                       if((usd.wValue >> 8) == USB_DESCRIPTOR_TYPE_DEVICE) {\r
+                               UsbSendEp0((BYTE *)&DeviceDescriptor,\r
+                                       min(sizeof(DeviceDescriptor), usd.wLength));\r
+                       } else if((usd.wValue >> 8) == USB_DESCRIPTOR_TYPE_CONFIGURATION) {\r
+                               UsbSendEp0((BYTE *)&ConfigurationDescriptor,\r
+                                       min(sizeof(ConfigurationDescriptor), usd.wLength));\r
+                       } else if((usd.wValue >> 8) == USB_DESCRIPTOR_TYPE_STRING) {\r
+                               const BYTE *s = StringDescriptors[usd.wValue & 0xff];\r
+                               UsbSendEp0(s, min(s[0], usd.wLength));\r
+                       } else if((usd.wValue >> 8) == USB_DESCRIPTOR_TYPE_HID_REPORT) {\r
+                               UsbSendEp0((BYTE *)&HidReportDescriptor,\r
+                                       min(sizeof(HidReportDescriptor), usd.wLength));\r
+                       } else {\r
+                               *((DWORD *)0x00200000) = usd.wValue;\r
+                       }\r
+                       break;\r
+\r
+               case USB_REQUEST_SET_ADDRESS:\r
+                       UsbSendZeroLength();\r
+                       UDP_FUNCTION_ADDR = UDP_FUNCTION_ADDR_ENABLED | usd.wValue ;\r
+                       if(usd.wValue != 0) {\r
+                               UDP_GLOBAL_STATE = UDP_GLOBAL_STATE_ADDRESSED;\r
+                       } else {\r
+                               UDP_GLOBAL_STATE = 0;\r
+                       }\r
+                       break;\r
+\r
+               case USB_REQUEST_GET_CONFIGURATION:\r
+                       UsbSendEp0(&CurrentConfiguration, sizeof(CurrentConfiguration));\r
+                       break;\r
+\r
+               case USB_REQUEST_GET_STATUS: {\r
+                       if(usd.bmRequestType & 0x80) {\r
+                               WORD w = 0;\r
+                               UsbSendEp0((BYTE *)&w, sizeof(w));\r
+                       }\r
+                       break;\r
+               }\r
+               case USB_REQUEST_SET_CONFIGURATION:\r
+                       CurrentConfiguration = usd.wValue;\r
+                       if(CurrentConfiguration) {\r
+                               UDP_GLOBAL_STATE = UDP_GLOBAL_STATE_CONFIGURED;\r
+                               UDP_ENDPOINT_CSR(1) = UDP_CSR_ENABLE_EP |\r
+                                       UDP_CSR_EPTYPE_INTERRUPT_OUT;\r
+                               UDP_ENDPOINT_CSR(2) = UDP_CSR_ENABLE_EP |\r
+                                       UDP_CSR_EPTYPE_INTERRUPT_IN;\r
+                       } else {\r
+                               UDP_GLOBAL_STATE = UDP_GLOBAL_STATE_ADDRESSED;\r
+                               UDP_ENDPOINT_CSR(1) = 0;\r
+                               UDP_ENDPOINT_CSR(2) = 0;\r
+                       }\r
+                       UsbSendZeroLength();\r
+                       break;\r
+\r
+               case USB_REQUEST_GET_INTERFACE: {\r
+                       BYTE b = 0;\r
+                       UsbSendEp0(&b, sizeof(b));\r
+                       break;\r
+               }\r
+\r
+               case USB_REQUEST_SET_INTERFACE:\r
+                       UsbSendZeroLength();\r
+                       break;\r
+\r
+               case USB_REQUEST_CLEAR_FEATURE:\r
+               case USB_REQUEST_SET_FEATURE:\r
+               case USB_REQUEST_SET_DESCRIPTOR:\r
+               case USB_REQUEST_SYNC_FRAME:\r
+               default:\r
+                       break;\r
+       }\r
+}\r
+\r
+void UsbSendPacket(BYTE *packet, int len)\r
+{\r
+       int i, thisTime;\r
+\r
+       while(len > 0) {\r
+               thisTime = min(len, 8);\r
+\r
+               for(i = 0; i < thisTime; i++) {\r
+                       UDP_ENDPOINT_FIFO(2) = packet[i];\r
+               }\r
+               UDP_ENDPOINT_CSR(2) |= UDP_CSR_TX_PACKET;\r
+\r
+               while(!(UDP_ENDPOINT_CSR(2) & UDP_CSR_TX_PACKET_ACKED))\r
+                       ;\r
+               UDP_ENDPOINT_CSR(2) &= ~UDP_CSR_TX_PACKET_ACKED;\r
+\r
+               while(UDP_ENDPOINT_CSR(2) & UDP_CSR_TX_PACKET_ACKED)\r
+                       ;\r
+\r
+               len -= thisTime;\r
+               packet += thisTime;\r
+       }\r
+}\r
+\r
+static void HandleRxdData(void)\r
+{\r
+       int i, len;\r
+\r
+       if(UDP_ENDPOINT_CSR(1) & UDP_CSR_RX_PACKET_RECEIVED_BANK_0) {\r
+               len = UDP_CSR_BYTES_RECEIVED(UDP_ENDPOINT_CSR(1));\r
+\r
+               for(i = 0; i < len; i++) {\r
+                       UsbBuffer[UsbSoFarCount] = UDP_ENDPOINT_FIFO(1);\r
+                       UsbSoFarCount++;\r
+               }\r
+\r
+               UDP_ENDPOINT_CSR(1) &= ~UDP_CSR_RX_PACKET_RECEIVED_BANK_0;\r
+               while(UDP_ENDPOINT_CSR(1) & UDP_CSR_RX_PACKET_RECEIVED_BANK_0)\r
+                       ;\r
+\r
+               if(UsbSoFarCount >= 64) {\r
+                       UsbPacketReceived(UsbBuffer, UsbSoFarCount);\r
+                       UsbSoFarCount = 0;\r
+               }\r
+       }\r
+\r
+       if(UDP_ENDPOINT_CSR(1) & UDP_CSR_RX_PACKET_RECEIVED_BANK_1) {\r
+               len = UDP_CSR_BYTES_RECEIVED(UDP_ENDPOINT_CSR(1));\r
+\r
+               for(i = 0; i < len; i++) {\r
+                       UsbBuffer[UsbSoFarCount] = UDP_ENDPOINT_FIFO(1);\r
+                       UsbSoFarCount++;\r
+               }\r
+\r
+               UDP_ENDPOINT_CSR(1) &= ~UDP_CSR_RX_PACKET_RECEIVED_BANK_1;\r
+               while(UDP_ENDPOINT_CSR(1) & UDP_CSR_RX_PACKET_RECEIVED_BANK_1)\r
+                       ;\r
+\r
+               if(UsbSoFarCount >= 64) {\r
+                       UsbPacketReceived(UsbBuffer, UsbSoFarCount);\r
+                       UsbSoFarCount = 0;\r
+               }\r
+       }\r
+}\r
+\r
+void UsbStart(void)\r
+{\r
+       volatile int i;\r
+\r
+       UsbSoFarCount = 0;\r
+\r
+       USB_D_PLUS_PULLUP_OFF();\r
+\r
+       for(i = 0; i < 1000000; i++)\r
+               ;\r
+\r
+       USB_D_PLUS_PULLUP_ON();\r
+\r
+       if(UDP_INTERRUPT_STATUS & UDP_INTERRUPT_END_OF_BUS_RESET) {\r
+               UDP_INTERRUPT_CLEAR = UDP_INTERRUPT_END_OF_BUS_RESET;\r
+       }\r
+}\r
+\r
+BOOL UsbPoll(BOOL blinkLeds)\r
+{\r
+       BOOL ret = FALSE;\r
+\r
+       if(UDP_INTERRUPT_STATUS & UDP_INTERRUPT_END_OF_BUS_RESET) {\r
+               UDP_INTERRUPT_CLEAR = UDP_INTERRUPT_END_OF_BUS_RESET;\r
+\r
+               // following a reset we should be ready to receive a setup packet\r
+               UDP_RESET_ENDPOINT = 0xf;\r
+               UDP_RESET_ENDPOINT = 0;\r
+\r
+               UDP_FUNCTION_ADDR = UDP_FUNCTION_ADDR_ENABLED;\r
+\r
+               UDP_ENDPOINT_CSR(0) = UDP_CSR_EPTYPE_CONTROL | UDP_CSR_ENABLE_EP;\r
+\r
+               CurrentConfiguration = 0;\r
+\r
+               ret = TRUE;\r
+       }\r
+\r
+       if(UDP_INTERRUPT_STATUS & UDP_INTERRUPT_ENDPOINT(0)) {\r
+               if(UDP_ENDPOINT_CSR(0) & UDP_CSR_RX_HAVE_READ_SETUP_DATA) {\r
+                       HandleRxdSetupData();\r
+                       ret = TRUE;\r
+               }\r
+       }\r
+\r
+       if(UDP_INTERRUPT_STATUS & UDP_INTERRUPT_ENDPOINT(1)) {\r
+               HandleRxdData();\r
+               ret = TRUE;\r
+       }\r
+\r
+       return ret;\r
+}\r
diff --git a/doc/CHANGES.TXT b/doc/CHANGES.TXT
new file mode 100644 (file)
index 0000000..b209cc0
--- /dev/null
@@ -0,0 +1,155 @@
+################
+## 2009/03/28 ##
+################
+winsrc/command.cpp
+       Added two new LF commands for tag exploration :
+
+   - askdemod: takes 2 arguments, one is the clock rate, one is the modulation
+               convention (high mod is 1 or high mod is zero)
+
+               This command demodulates the stream into a binary stream into 
+               the trace buffer (0's and 1's)
+
+   - mandemod: manchester decoding of a bitstream: takes a binary stream from
+               the trace buffer (see askdemod) and attempts to do manchester decoding
+              to it. One argument: clock rate. Outputs the bitstream to the scrollback buffer.
+
+  Those two helped me to validate that the unknown tag I had was indeed an EM4100 type of tag
+
+
+################\r
+## 2008/12/11 ##\r
+################\r
+bootrom/bootrom.c\r
+       Significant changes to bootloader. Use of Chip ID register to detect if running on a SAM7S512 then configure FLASH\r
+       waitstates as per SummoningDark's suggestion for a SAM7S512 or SAM7S256.\r
+       Deleted idle loops waiting blindly for clocks to settle and now using status registers to detect when clocks are stable.\r
+\r
+       *************************\r
+       * IMPORTANT INFORMATION *\r
+       **************************************************************************************************************************\r
+       * With this boot code, the device can now only be flashed if button is held down after power on or a software reset.\r
+       * The flash procedure is this:\r
+       * Hold down button. Either plug in USB or software reset it. _While_holding_down_button_ (red and yellow LEDs are lit) you can\r
+       * issue one or more of the "prox bootrom <file>" "prox fpga <file>" "prox load <file>", be sure to hold button down for the\r
+       * entire duration of the flash process. Only release the button when flashing is complete and you want to let the board boot.\r
+       * This process may be less convenient but it's safer and avoids "unintentional" flashing of the board.\r
+       **************************************************************************************************************************\r
+       LED boot sequence now changed, C (red) lights up when boot code jumps from flash to RAM boot code, A (yellow) lights up after\r
+       clocks have been initialized, B (green) lights up when jumping from boot code to main code, then D (red led away from the others)\r
+       lights up while code is being downloaded to FPGA, then all leds turn off and board is ready for action.\r
+\r
+       With these changes the board now boots and is ready to use in about 3 seconds. Also since the USB bus is not initialized\r
+       twice (once during boot, then again when the main code runs) unless the button is held down at boot, this seems to avoid\r
+       the     double USB connect and "USB device not recognized" when device is connected to the USB bus or software reset.\r
+\r
+################\r
+## 2008/12/06 ##\r
+################\r
+armsrc/fpga.c\r
+       Implemented function SetupSpi() to initialize the Serial Peripheral Interface (SPI) in preparation to adding an LCD to the board.\r
+       Changed FpgaWriteConfWord() to use the SPI communication now instead of bit banging the serial data to the FPGA.\r
+\r
+fpga/fpga.v\r
+       The FPGA config word serializer required non standard SPI communication (ie for shifting in a 8 bit word, it required a 9th clock\r
+       cycle with NCS high to load the word from the shift register to the conf register). This was OK for manually bitbanging it but not\r
+       suitable for using SPI comms. The serializer was fixed to load the conf word from the shift register on a NCS lo-hi transition and\r
+       not require additional clocking.\r
+\r
+armsrc/fpgaimg.c\r
+       Recompiled FPGA code after changes above.\r
+\r
+armsrc/LCD.c\r
+       LCD driver for PCF8833 based LCDs like those found on Nokia models 2600,2650,3100,3120,5140,6030,6100,6610,7210,7250 maybe\r
+       others. These color LCDs have a resolution of 132x132 and a serial interface. They are very cheap like even down to $2/pc\r
+       This LCD driver is a straight rip of that found at http://www.sparkfun.com/datasheets/LCD/Jimbo-Nokia-SAM7-Example.zip with\r
+       very small changes, mainly to integrate it and make it compile with our codebase. Also comented out the circle subroutines\r
+       to keep the code to integer math only.\r
+\r
+armsrc/fonts.c\r
+       Font definition for LCD driver\r
+\r
+armsrc/appmain.c\r
+       Fixed a small bug in CmdHIDdemodFSK (added case 4) which prevented reading some tags. When a logic 0 is immediately followed\r
+       by the start of the next transmisson (special pattern) a pattern of 4 bit duration lengths is created.\r
+\r
+################\r
+## 2008/11/27 ##\r
+################\r
+armsrc/appmain.c\r
+       Implemented an HID tag FSK demodulator (CmdHIDdemodFSK) to obtain the tag ID code from the raw sampled waveform.\r
+       Implemented CmdHIDsimTAG which takes a 44bit HID tag ID as a hex number then creates the waveform and simulates the tag\r
+\r
+winsrc/command.cpp\r
+       Added command "hidfskdemod" that calls CmdHIDdemodFSK, the ARM FSK demodulator for HID tags.\r
+\r
+include/usb-cmd.h\r
+       New defines CMD_HID_DEMOD_FSK and CMD_HID_SIM_TAG\r
+\r
+2008/11/25\r
+common/iso14443_crc.c\r
+       Moved CRC calculation code into this file as it's common to both ARM and Windows side. This file is now included as needed.\r
+\r
+################\r
+## 2008/11/21 ##\r
+################\r
+armsrc/Makefile\r
+       Changes to split up the compilation of the ARM and produce separate S files for the FPGA code and the ARM code.\r
+\r
+armsrc/appmain.c\r
+       Replaced some of the hex value params in FpgaWriteConfWord with more explanatory defines.\r
+       Changes to the Tune command as it assumes wrong HF capacitor value (130pF) and produces wrong voltage readings.\r
+       Combined some of the integer arithmetic statements to improve accuracy slightly, since the voltage divider ratio is not an integer.\r
+       Voltage divider resistor network is 10M/240k = ratio of 41.6666\r
+\r
+       Originally the calculation was rounding the ratio down to 41\r
+               3300 (mV) * 41 * sample_value / 1024\r
+       New calculation without rounding error is\r
+               3300 (mV) * 41.66666 * sample_value / 1024 => 137500 * sample_value / 1024\r
+\r
+       New define BUTTON_PRESS() returns status of button\r
+\r
+armsrc/fpga.c\r
+       The current board can only take a X2S30 as there is no larger FPGA in PQFP100 package and\r
+       the smaller X2S15 FPGA can't fit the current code. The X2S30 FPGA config is fixed at 336,768 bits\r
+       The FPGA code base address and length is hard coded to occupy FLASH region 0x2000 - 0xC470.\r
+\r
+armsrc/ldscript-fpga\r
+       New file to place the FPGA code at FLASH address 0x2000\r
+\r
+bootrom/Makefile\r
+       Slight changes, commented out the generation of byteswapped S file, the other S files are generated in the same section of the makefile now.\r
+\r
+bootrom/bootrom.c\r
+       Changed some thumb code with a one line ARM code which is clearer and more explicit. Processor runs in ARM mode at reset anyway.\r
+       Changed jump to RAM address, used to jump to 0x2000 (now FPGA area), now jumps to 0x10000.\r
+\r
+bootrom/flash-reset.s\r
+       Changed name of CMain to CopyBootToRAM. Streamlined reset code, fixed up stack pointer initialization.\r
+\r
+bootrom/fromflash.c\r
+       Removed the whole section of initializing clocks, this is redundant as it's being done once we jump to boot code in RAM\r
+       All fromflash.c does now is copy the boot code to ram and jumps to it.\r
+\r
+bootrom/ram-reset.s\r
+       Fixed up stack pointer initialization that caused crash when using "loread"\r
+\r
+include/at91sam7s128.h\r
+       New defines for debug register, lets you identify what processor flavour the code runs on, RAM and FLASH sizes, etc.\r
+\r
+include/proxmark3.h\r
+       New useful defines for relay and button\r
+\r
+winsrc/Makefile\r
+       Added new define /D_CRT_SECURE_NO_WARNINGS to elliminate a _whole bunch_ of bogus compilation warnings\r
+\r
+winsrc/command.cpp\r
+       Changed CmdLosamples to take a numeric argument (number of samples x4 to retrieve from buffer)\r
+       New command Quit to exit the program from the GUI command prompt.\r
+\r
+winsrc/gui.cpp\r
+       Fixup compilation warnings.\r
+\r
+winsrc/prox.cpp\r
+       Tidy up printing to stdout, flashing progress now updates on the same line instead of scrolling up.\r
+       New command line parameter to load FPGA image to FLASH.\r
diff --git a/doc/README.TXT b/doc/README.TXT
new file mode 100644 (file)
index 0000000..f3b49c7
--- /dev/null
@@ -0,0 +1,39 @@
+This is a bare minimum compile environment for the proxmark3 sources. \r
+\r
+CONTENTS\r
+\r
+This bundle contains the ARM cross compiler in devkitARM and a _tiny_ subset\r
+of the Visual C++ 2008 Express Edition in devkitWIN which is the bare minimum\r
+required for compilation of this current source.\r
+\r
+If you plan on further source code development you are strongly encouraged\r
+to download the full Visual C++ 2008 available for free download from\r
+http://www.microsoft.com/express/download/\r
+\r
+CAVEATS\r
+\r
+There is no provision in this environment for compiling the FPGA source. To\r
+do that you need to download the free (registration required) ISE WebPack\r
+from Xilinx at http://www.xilinx.com/ise/logic_design_prod/webpack.htm\r
+Be warned, the pack is huge, 2Gb download and >4Gb installed.\r
+\r
+USAGE\r
+\r
+First of all run the .msi file in devkitWIN\vcredist_x86 to install the VC++\r
+redistributables, without these, nmake, cl and link won't run.\r
+\r
+Get a command prompts in the cockpit directory and pretty much run the batch\r
+files in the order they appear:\r
+\r
+0setpath.bat  - sets the environment vars for the compile environment\r
+1makearm.bat  - compiles the files in armsrc, output files in armsrc\obj\r
+2makeboot.bat - compiles the files in bootrom, output files in bootrom\obj\r
+3makewin.bat  - compiles the files in winsrc, output files in winsrc\obj\r
+4flashos.bat  - attempts to upload the OS image to the proxmark3 board\r
+\r
+ACKNOWLEDGMENTS\r
+\r
+Thanks to J Westhues for the original proxmark, Roel and the proxmark.org\r
+community. This pack may contain F/OSS or free but copyrighted software\r
+from Xilinx, Microsoft and others. All trademarks are the property of\r
+their respective owners. All rights reserved.\r
diff --git a/doc/component-placement.bmp b/doc/component-placement.bmp
new file mode 100644 (file)
index 0000000..d385431
Binary files /dev/null and b/doc/component-placement.bmp differ
diff --git a/doc/proxmark3.pdf b/doc/proxmark3.pdf
new file mode 100644 (file)
index 0000000..32f3477
Binary files /dev/null and b/doc/proxmark3.pdf differ
diff --git a/doc/proxmark3.xls b/doc/proxmark3.xls
new file mode 100644 (file)
index 0000000..c13169c
Binary files /dev/null and b/doc/proxmark3.xls differ
diff --git a/doc/schematics.pdf b/doc/schematics.pdf
new file mode 100644 (file)
index 0000000..8ed8470
Binary files /dev/null and b/doc/schematics.pdf differ
diff --git a/doc/system.txt b/doc/system.txt
new file mode 100644 (file)
index 0000000..a3ae860
--- /dev/null
@@ -0,0 +1,276 @@
+\r
+This is outdated.\r
+\r
+---\r
+\r
+INTRODUCTION TO THE proxmark3\r
+=============================\r
+\r
+The proxmark3 device is designed to manipulate RFID tags in a number of\r
+different ways. For example, a proxmark3 can:\r
+\r
+    * read a low-frequency (~100 kHz) or high-frequency (13.56 MHz) tag,\r
+      including the ISO-standard tags; standards that require\r
+      bidirectional communication between the reader and the tag are\r
+      not a problem\r
+\r
+    * emulate a low- or high-frequency tag, in a way very similar to the\r
+      way that a real tag behaves (e.g., it derives its timing from the\r
+      incident carrier)\r
+\r
+    * eavesdrop on the signals exchanged between another reader and tag\r
+\r
+    * measure the resonant frequency of an antenna, to a certain extent\r
+      (this is a convenience when building a test setup for the previous\r
+      three functions)\r
+\r
+The proxmark3 may be thought of as a direct-sampling software radio.\r
+There is some complication, though, because of the usual dynamic range\r
+issue in dealing with signals in RFID systems (large signal due to\r
+the reader, small signal due to the tag). Some analog processing is\r
+therefore used to fix this before the signal is digitized. (Although,\r
+it is possible to digitize the signal from the antenna directly, with\r
+appropriate population options. It is just not usually a good idea.)\r
+\r
+SYSTEM ARCHITECTURE\r
+===================\r
+\r
+The ANTENNA sends and receives signals over the air. It is external to\r
+the board; it connects through SV2. Separate pins on the connector are\r
+used for the low- and high-frequency antennas, and the analog receive\r
+paths are separate. The antennas are inductive loops, which are resonated\r
+by on-board capacitors.\r
+\r
+On the transmit side, the antennas are excited by large numbers of\r
+paralleled bus driver buffers. By tri-stating some of the buffers, it\r
+is possible to vary the transmit strength. This may be used to generate\r
+a modulated carrier. The buffers are driven by signals from the FPGA,\r
+as are the output enables. The antennas are excited as series circuits,\r
+which permits a large input power for a relatively small input voltage.\r
+\r
+By driving all of the buffers low, it is possible to make the antenna\r
+look to the receive path like a parallel LC circuit; this provides a\r
+high-voltage output signal. This is typically what will be done when we\r
+are not actively transmitting a carrier (i.e., behaving as a reader).\r
+\r
+On the receive side, there are two possibilities, which are selected by\r
+RLY1. A mechanical relay is used, because the signal from the antenna is\r
+likely to be more positive or negative than the highest or lowest supply\r
+voltages on-board. In the usual case (PEAK-DETECTED mode), the received\r
+signal is peak-detected by an analog circuit, then filtered slightly,\r
+and then digitized by the ADC. This is the case for both the low- and\r
+high-frequency paths, although the details of the circuits for the\r
+two cases are somewhat different. This receive path would typically\r
+be selected when the device is behaving as a reader, or when it is\r
+eavesdropping at close range.\r
+\r
+It is also possible to digitize the signal from the antenna directly (RAW\r
+mode), after passing it through a gain stage. This is more likely to be\r
+useful in reading signals at long range, but the available dynamic range\r
+will be poor, since it is limited by the 8-bit A/D. These modes would be\r
+very appropriate, for example, for the heavily-discussed attacks in which\r
+a tag's ID is learned from the data broadcast by a reader performing an\r
+anticollision loop, because there is no dynamic range problem there. It\r
+would also be possible to program the proxmark3 to receive broadcast AM\r
+radio, with certain changes in component values.\r
+\r
+In either case, an analog signal is digitized by the ADC (IC8), and\r
+from there goes in to the FPGA (IC1). The FPGA is big enough that it\r
+can perform DSP operations itself. For some high-frequency standards,\r
+the subcarriers are fast enough that it would be inconvenient to do all\r
+the math on a general-purpose CPU. The FPGA can therefore correlate for\r
+the desired signal itself, and simply report the total to the ARM. For\r
+low-frequency tags, it probably makes sense just to pass data straight\r
+through to the ARM.\r
+\r
+The FPGA communicates with the ARM through either its SPI port (the ARM\r
+is the master) or its generic synchronous serial port (again, the ARM\r
+is the master). The ARM connects to the outside world over USB.\r
+\r
+DETAILS: POWER DISTRIBUTION\r
+===========================\r
+\r
+I make a half-hearted attempt to meet the USB power specs; this adds a\r
+bit of complexity. I have not made measurements to determine how close\r
+I come to succeeding, but I think that the suspend current might turn\r
+out to be a pain.\r
+\r
+The +3V3 rail is always powered, whenever we are plugged in to USB. This\r
+is generated by an LDO, which burns a quiescent current of 150 uA\r
+(typical) already. The only thing powered from the +3V3 rail is the ARM,\r
+which can presumably do smart power control when we are in suspend.\r
+\r
+The ARM generates two signals to switch power to the rest of the board:\r
+FPGA_ON, and NVDD_ON. When NVDD_ON goes low, the Vdd rail comes up to\r
+about five volts (the filtered-but-unregulated USB voltage). This powers\r
+most of the analog circuitry, including the ADC and all of the opamps\r
+and comparators in the receive path, and the coil drivers as well. Vdd\r
+also feeds the +3V3-FPGA and +2v5 regulators, which power only the\r
+FPGA. These regulators are enabled by FPGA_ON, so the FPGA is powered\r
+only when NVDD_ON is asserted low, and FPGA_ON is asserted high.\r
+\r
+DETAILS: FPGA\r
+=============\r
+\r
+The FPGA is a Spartan-II. This is a little bit old, but it is widely\r
+available, inexpensive, and five-volt tolerant. For development, the FPGA\r
+is configured over JTAG (SV5). In operation, the FPGA is configured in\r
+slave serial mode by the ARM, from a bitstream stored in the ARM's flash.\r
+\r
+Power to the FPGA is managed by regulators IC13 and IC12, both of which\r
+have shutdown. These generate the FPGA's VCCO (+3v3) and VCCINT (+2v5)\r
+supplies. I am a little bit worried about the power-on surge, since we\r
+run off USB. At the very minimum, the FPGA should not get power until\r
+we have enumerated and requested the full 500 mA available from USB. The\r
+large electrolytic capacitors C37 and C38 will presumably help with this.\r
+\r
+The logic is written in Verilog, of course for webpack. I have structured\r
+the FPGA in terms of `major modes:' the FPGA's `major mode' determines\r
+which of several modules is connected to the FPGA's I/O pins. A separate\r
+module is used for each of the FPGA's function; for example, there is\r
+now a module to read a 125 kHz tag, simulate a 125 kHz tag, transmit to\r
+an ISO 15693 tag, and receive from an ISO 15693 tag.\r
+\r
+DETAILS: ANALOG RECEIVE PATH\r
+============================\r
+\r
+For `slow' signals, I use an MCP6294 opamp. This has a GBW of 10 MHz,\r
+which is more than enough for the low-frequency stuff, and enough for\r
+all of the subcarrier frequencies that I know of at high frequency. In\r
+practice, the `slow' signals are all the signals following the peak\r
+detector. These signals are usually centred around the generated\r
+voltage Vmid.\r
+\r
+For `fast' signals, I use an AD8052. This is a very fast voltage-feedback\r
+amplifier (~100 MHz GBW). I use it immediately after the antenna for\r
+both the low- and high-frequency cases, as a sort of an ugly LNA. It is\r
+not optimal, but it certainly made the design easy.\r
+\r
+An ordinary CD4066 is used to multiplex the four possible signals\r
+(low/high frequency paths, RAW/PEAK-DETECTED). There is a potential\r
+problem at startup, when the ARM is in reset; there are pull-ups on the\r
+lines that control the mux, so all of the switches turn on. This shorts\r
+the four opamp outputs together through the on-resistance of the switch.\r
+All four outputs float to the same DC voltage with no signal, however,\r
+and the on-resistance of the switches is fairly large, so I don't think\r
+that will be a problem in practice.\r
+\r
+Comparators are used to generate clock signals when the device is\r
+emulating a tag. These clock signals are generated from the signal on the\r
+antenna, and therefore from the signal transmitted by the reader. This\r
+allows us to clock ourselves off the reader, just like a real tag would.\r
+These signals go in to the FPGA. There is a potential problem when the\r
+FPGA is powered down; these outputs might go high and try to power the\r
+FPGA through the protection diodes. My present solution to this is a\r
+couple of resistors, which is not very elegeant.\r
+\r
+The high-frequency peak-detected receive path contains population options\r
+for many features that I do not currently use. A lot of these are just\r
+me guessing that if I provide options for different series and shunt\r
+passives, perhaps it will come in handy in some way. The Zener diodes D10\r
+and D11 are optional, but may protect the front end from an overvoltage\r
+(which will fry the peak detector diodes) when the `simulated tag'\r
+is read by a powerful reader.\r
+\r
+DETAILS: ANALOG TRANSMIT PATH\r
+=============================\r
+\r
+The coil drivers are just ACT244 bus buffers. I parallel eight of them\r
+for each antenna (eight for the high-frequency antenna, eight for the\r
+low-frequency antenna). This should easily provide a hundred milliamps\r
+coil drive or so, which is more than enough for anything that I imagine\r
+doing with the device. The drivers hit the coil with a square wave\r
+voltage, however, which means that it is only the bandpass filter effect\r
+of a resonant antenna that suppresses the odd harmonics. In practice it\r
+would probably take heroic efforts (high antenna Q) to meet the FCC/CE\r
+harmonic specs; and in practice no one cares.\r
+\r
+The tx strength, given good antenna tuning, is determined by the series\r
+resistors. Choose the ratios to stay within the rated current of the\r
+buffers, and to achieve the desired power ratios by enabling or disabling\r
+nOEs for the desired modulation index. It is useful to populate one of the\r
+resistors as a high value (~10k) for the simulated tag modes; this allows\r
+us to look at the incident carrier without loading the reader very much.\r
+\r
+DETAILS: ARM\r
+============\r
+\r
+Atmel makes a number of pin-compatible ARMs, with slightly different\r
+peripherals, and different amounts of flash and RAM. It is necessary\r
+to choose a device with enough flash not just for the ARM's program,\r
+but also for the FPGA image (which is loaded by the ARM).\r
+\r
+The ARM is responsible for programming the FPGA. It also supplies a\r
+clock to the FPGA (although the FPGA clock can also run off the 13.56\r
+MHz clock not used for anything else, which is obviously asynchronous\r
+to anything in the ARM).\r
+\r
+It is necessary to use JTAG to bring the ARM for the first time; at\r
+that point you can load a bootrom, and subsequently load new software\r
+over USB. It might be possible to use the ARM's pre-loaded bootloader\r
+(see datasheet) instead of JTAG, but I wanted the JTAG anyways for\r
+debugging, so I did not bother. I used a Wiggler clone, with Macraigor's\r
+OCD Commander. More expensive tools would work as well.\r
+\r
+USB SOFTWARE\r
+============\r
+\r
+At present I enumerate as an HID device. This saves me writing a driver,\r
+but it forces me to do interrupt transfers for everything. This limits\r
+speed and is not very elegant. A real USB driver would be nice, maybe\r
+even one that could do stuff like going isochronous to stream samples\r
+from the A/D for processing on the PC.\r
+\r
+PRETENDING TO BE A TAG\r
+======================\r
+\r
+It is not possible, with the given topology, to open-circuit the antenna\r
+entirely and still look at the signal received on it. The simulated tag\r
+modes must therefore switch between slight loading and heavy loading,\r
+not open- and short-circuts across the antenna, evening though they do\r
+not depend upon the incident carrier for power (just timing information).\r
+\r
+RECEIVING SIGNAL STRAIGHT FROM THE ANTENNAS\r
+===========================================\r
+\r
+There is a path straight from the antenna to the A/D, bypassing the peak\r
+detector assembly. This goes through a gain stage (just a fast voltage\r
+feedback opamp), and from there straight in to the mux.\r
+\r
+It is necessary to energize the relay to connect these paths. If the\r
+coil is driven (as if to excite and read a tag) while these paths are\r
+connected, then damage will probably result. Most likely the opamp\r
+will fry.\r
+\r
+READING A TAG\r
+=============\r
+\r
+The tag is excited by a carrier transmitted by the reader. This is\r
+generated by IC9 and IC10, using some combination of buffers. The transmit\r
+power is determined by selecting the right combination of PWR_OEx pins;\r
+drive more of them low for more power. This can be used to modulate the\r
+transmitted signal, and thus send information to the tag.\r
+\r
+The received signal from the antenna is first peak-detected, and then\r
+high-pass filtered to reject the unmodulated carrier. The signal is\r
+amplified a bit, and goes in to the A/D mux from there. The A/D is\r
+controlled by the FPGA. For 13.56 MHz tags, it is easiest to do everything\r
+synchronous to the 13.56 MHz carrier.\r
+\r
+INTERFACE FROM THE ARM TO THE FPGA\r
+==================================\r
+\r
+The FPGA and the ARM can communicate in two main ways: using the ARM's\r
+general-purpose synchronous serial port (the SSP), or using the ARM's\r
+SPI port. The SPI port is used to configure the FPGA. The ARM writes a\r
+configuration word to the FPGA, which determines what operation will\r
+be performed (e.g. read 13.56 MHz vs. read 125 kHz vs. read 134 kHz\r
+vs...). The SPI is used exclusively for configuration.\r
+\r
+The SSP is used for actual data sent over the air. The ARM's SSP can\r
+work in slave mode, which means that we can send the data using clocks\r
+generated by the FPGA (either from the PCK0 clock, which the ARM itself\r
+supplies, or from the 13.56 MHz clock, which is certainly not going to\r
+be synchronous to anything in the ARM), which saves synchronizing logic\r
+in the FPGA. The SSP is bi-directional and full-duplex.\r
+\r
diff --git a/fpga/fpga.mpf b/fpga/fpga.mpf
new file mode 100644 (file)
index 0000000..4a281bc
--- /dev/null
@@ -0,0 +1,239 @@
+;\r
+; Copyright Model Technology, a  Mentor Graphics\r
+;  Corporation company 2003, - All rights reserved.\r
+;   \r
+[Library]\r
+std = $MODEL_TECH/../std\r
+ieee = $MODEL_TECH/../ieee\r
+verilog = $MODEL_TECH/../verilog\r
+vital2000 = $MODEL_TECH/../vital2000\r
+std_developerskit = $MODEL_TECH/../std_developerskit\r
+synopsys = $MODEL_TECH/../synopsys\r
+modelsim_lib = $MODEL_TECH/../modelsim_lib\r
+\r
+\r
+; VHDL Section\r
+unisim = $MODEL_TECH/../xilinx/vhdl/unisim\r
+simprim = $MODEL_TECH/../xilinx/vhdl/simprim\r
+xilinxcorelib = $MODEL_TECH/../xilinx/vhdl/xilinxcorelib\r
+aim = $MODEL_TECH/../xilinx/vhdl/aim\r
+pls = $MODEL_TECH/../xilinx/vhdl/pls\r
+cpld = $MODEL_TECH/../xilinx/vhdl/cpld\r
+\r
+; Verilog Section\r
+unisims_ver = $MODEL_TECH/../xilinx/verilog/unisims_ver\r
+uni9000_ver = $MODEL_TECH/../xilinx/verilog/uni9000_ver\r
+simprims_ver = $MODEL_TECH/../xilinx/verilog/simprims_ver\r
+xilinxcorelib_ver = $MODEL_TECH/../xilinx/verilog/xilinxcorelib_ver\r
+aim_ver = $MODEL_TECH/../xilinx/verilog/aim_ver\r
+cpld_ver = $MODEL_TECH/../xilinx/verilog/cpld_ver\r
+\r
+work = work
+[vcom]\r
+; Turn on VHDL-1993 as the default. Normally is off.\r
+VHDL93 = 1\r
+\r
+; Show source line containing error. Default is off.\r
+; Show_source = 1\r
+\r
+; Turn off unbound-component warnings. Default is on.\r
+; Show_Warning1 = 0\r
+\r
+; Turn off process-without-a-wait-statement warnings. Default is on.\r
+; Show_Warning2 = 0\r
+\r
+; Turn off null-range warnings. Default is on.\r
+; Show_Warning3 = 0\r
+\r
+; Turn off no-space-in-time-literal warnings. Default is on.\r
+; Show_Warning4 = 0\r
+\r
+; Turn off multiple-drivers-on-unresolved-signal warnings. Default is on.\r
+; Show_Warning5 = 0\r
+\r
+; Turn off optimization for IEEE std_logic_1164 package. Default is on.\r
+; Optimize_1164 = 0\r
+\r
+; Turn on resolving of ambiguous function overloading in favor of the\r
+; "explicit" function declaration (not the one automatically created by\r
+; the compiler for each type declaration). Default is off.\r
+ Explicit = 1\r
+\r
+; Turn off VITAL compliance checking. Default is checking on.\r
+; NoVitalCheck = 1\r
+\r
+; Ignore VITAL compliance checking errors. Default is to not ignore.\r
+; IgnoreVitalErrors = 1\r
+\r
+; Turn off VITAL compliance checking warnings. Default is to show warnings.\r
+; Show_VitalChecksWarnings = false\r
+\r
+; Turn off "loading..." messages. Default is messages on.\r
+; Quiet = 1\r
+\r
+; Turn on some limited synthesis rule compliance checking. Checks only:\r
+;      -- signals used (read) by a process must be in the sensitivity list\r
+; CheckSynthesis = 1\r
+\r
+[vlog]\r
+\r
+; Turn off "loading..." messages. Default is messages on.\r
+; Quiet = 1\r
+\r
+; Turn on Verilog hazard checking (order-dependent accessing of global vars).\r
+; Default is off.\r
+; Hazard = 1\r
+\r
+; Turn on converting regular Verilog identifiers to uppercase. Allows case\r
+; insensitivity for module names. Default is no conversion.\r
+; UpCase = 1\r
+\r
+; Turns on incremental compilation of modules \r
+; Incremental = 1\r
+\r
+[vsim]\r
+; Simulator resolution\r
+; Set to fs, ps, ns, us, ms, or sec with optional prefix of 1, 10, or 100.\r
+Resolution = ps\r
+\r
+; User time unit for run commands\r
+; Set to default, fs, ps, ns, us, ms, or sec. The default is to use the\r
+; unit specified for Resolution. For example, if Resolution is 100ps,\r
+; then UserTimeUnit defaults to ps.\r
+UserTimeUnit = default\r
+\r
+; Default run length\r
+RunLength = 100\r
+\r
+; Maximum iterations that can be run without advancing simulation time\r
+IterationLimit = 5000\r
+\r
+; Directive to license manager:\r
+; vhdl          Immediately reserve a VHDL license\r
+; vlog          Immediately reserve a Verilog license\r
+; plus          Immediately reserve a VHDL and Verilog license\r
+; nomgc         Do not look for Mentor Graphics Licenses\r
+; nomti         Do not look for Model Technology Licenses\r
+; noqueue       Do not wait in the license queue when a license isn't available\r
+; License = plus\r
+\r
+; Stop the simulator after an assertion message\r
+; 0 = Note  1 = Warning  2 = Error  3 = Failure  4 = Fatal\r
+BreakOnAssertion = 3\r
+\r
+; Assertion Message Format\r
+; %S - Severity Level \r
+; %R - Report Message\r
+; %T - Time of assertion\r
+; %D - Delta\r
+; %I - Instance or Region pathname (if available)\r
+; %% - print '%' character\r
+; AssertionFormat = "** %S: %R\n   Timf: %T  Iteration: %D%I\n"\r
+\r
+; Assertion File - alternate file for storing assertion messages\r
+; AssertFile = assert.log\r
+\r
+; Default radix for all windows and commands...\r
+; Set to symbolic, ascii, binary, octal, decimal, hex, unsigned\r
+DefaultRadix = symbolic\r
+\r
+; VSIM Startup command\r
+; Startup = do startup.do\r
+\r
+; File for saving command transcript\r
+TranscriptFile = transcript\r
+\r
+; File for saving command history \r
+;CommandHistory = cmdhist.log\r
+\r
+; Specify whether paths in simulator commands should be described \r
+; in VHDL or Verilog format. For VHDL, PathSeparator = /\r
+; for Verilog, PathSeparator = .\r
+PathSeparator = /\r
+\r
+; Specify the dataset separator for fully rooted contexts.\r
+; The default is ':'. For example, sim:/top\r
+; Must not be the same character as PathSeparator.\r
+DatasetSeparator = :\r
+\r
+; Disable assertion messages\r
+; IgnoreNote = 1\r
+; IgnoreWarning = 1\r
+; IgnoreError = 1\r
+; IgnoreFailure = 1\r
+\r
+; Default force kind. May be freeze, drive, or deposit \r
+; or in other terms, fixed, wired or charged.\r
+; DefaultForceKind = freeze\r
+\r
+; If zero, open files when elaborated\r
+; else open files on first read or write\r
+; DelayFileOpen = 0\r
+\r
+; Control VHDL files opened for write\r
+;   0 = Buffered, 1 = Unbuffered\r
+UnbufferedOutput = 0\r
+\r
+; Control number of VHDL files open concurrently\r
+;   This number should always be less then the \r
+;   current ulimit setting for max file descriptors\r
+;   0 = unlimited\r
+ConcurrentFileLimit = 40\r
+\r
+; This controls the number of hierarchical regions displayed as\r
+; part of a signal name shown in the waveform window.  The default\r
+; value or a value of zero tells VSIM to display the full name.\r
+; WaveSignalNameWidth = 0\r
+\r
+; Turn off warnings from the std_logic_arith, std_logic_unsigned\r
+; and std_logic_signed packages.\r
+; StdArithNoWarnings = 1\r
+\r
+; Turn off warnings from the IEEE numeric_std and numeric_bit\r
+; packages.\r
+; NumericStdNoWarnings = 1\r
+\r
+; Control the format of a generate statement label. Don't quote it.\r
+; GenerateFormat = %s__%d\r
+\r
+; Specify whether checkpoint files should be compressed.\r
+; The default is to be compressed.\r
+; CheckpointCompressMode = 0\r
+\r
+; List of dynamically loaded objects for Verilog PLI applications\r
+; Veriuser = veriuser.sl\r
+\r
+[lmc]\r
+[Project]
+Project_Version = 5
+Project_DefaultLib = work
+Project_SortMethod = unused
+Project_Files_Count = 13
+Project_File_0 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/fpga_tb.v
+Project_File_P_0 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1179836462 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 2 dont_compile 0
+Project_File_1 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/hi_simulate.v
+Project_File_P_1 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1225963633 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 compile_to work vlog_upper 0 vlog_options {} compile_order 6 dont_compile 0
+Project_File_2 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/testbed_hi_simulate.v
+Project_File_P_2 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1225964050 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 compile_to work vlog_upper 0 vlog_options {} compile_order 12 dont_compile 0
+Project_File_3 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/fpga.v
+Project_File_P_3 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1207888760 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 1 dont_compile 0
+Project_File_4 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/hi_read_tx.v
+Project_File_P_4 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1225960972 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 5 dont_compile 0
+Project_File_5 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/testbed_hi_read_tx.v
+Project_File_P_5 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1225962515 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 11 dont_compile 0
+Project_File_6 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/hi_iso14443a.v
+Project_File_P_6 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1207889732 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 3 dont_compile 0
+Project_File_7 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/lo_simulate.v
+Project_File_P_7 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1179836462 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 8 dont_compile 0
+Project_File_8 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/lo_read.v
+Project_File_P_8 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1225797126 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 7 dont_compile 0
+Project_File_9 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/util.v
+Project_File_P_9 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1179836462 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 0 dont_compile 0
+Project_File_10 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/testbed_lo_read.v
+Project_File_P_10 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1225960239 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 9 dont_compile 0
+Project_File_11 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/testbed_lo_simulate.v
+Project_File_P_11 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1225960231 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 10 dont_compile 0
+Project_File_12 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/hi_read_rx_xcorr.v
+Project_File_P_12 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1179836462 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 4 dont_compile 0
+Project_Sim_Count = 0
+Project_Folder_Count = 0
diff --git a/fpga/fpga.ucf b/fpga/fpga.ucf
new file mode 100644 (file)
index 0000000..bf0d40b
--- /dev/null
@@ -0,0 +1,41 @@
+# See the schematic for the pin assignment.\r
+\r
+NET "adc_d<0>"  LOC = "P62"  ; \r
+NET "adc_d<1>"  LOC = "P60"  ; \r
+NET "adc_d<2>"  LOC = "P58"  ; \r
+NET "adc_d<3>"  LOC = "P57"  ; \r
+NET "adc_d<4>"  LOC = "P56"  ; \r
+NET "adc_d<5>"  LOC = "P55"  ; \r
+NET "adc_d<6>"  LOC = "P54"  ; \r
+NET "adc_d<7>"  LOC = "P53"  ; \r
+#NET "cross_hi"  LOC = "P88"  ; \r
+#NET "miso"  LOC = "P40"  ; \r
+#PACE: Start of Constraints generated by PACE\r
+\r
+#PACE: Start of PACE I/O Pin Assignments\r
+NET "adc_clk"  LOC = "P46"  ; \r
+NET "adc_noe"  LOC = "P47"  ; \r
+NET "ck_1356meg"  LOC = "P91"  ; \r
+NET "ck_1356megb"  LOC = "P93"  ; \r
+NET "cross_lo"  LOC = "P87"  ; \r
+NET "dbg"  LOC = "P22"  ; \r
+NET "mosi"  LOC = "P43"  ; \r
+NET "ncs"  LOC = "P44"  ; \r
+NET "pck0"  LOC = "P36"  ; \r
+NET "pwr_hi"  LOC = "P80"  ; \r
+NET "pwr_lo"  LOC = "P81"  ; \r
+NET "pwr_oe1"  LOC = "P82"  ; \r
+NET "pwr_oe2"  LOC = "P83"  ; \r
+NET "pwr_oe3"  LOC = "P84"  ; \r
+NET "pwr_oe4"  LOC = "P86"  ; \r
+NET "spck"  LOC = "P39"  ; \r
+NET "ssp_clk"  LOC = "P71"  ; \r
+NET "ssp_din"  LOC = "P32"  ; \r
+NET "ssp_dout"  LOC = "P34"  ; \r
+NET "ssp_frame"  LOC = "P31"  ; \r
+\r
+#PACE: Start of PACE Area Constraints\r
+\r
+#PACE: Start of PACE Prohibit Constraints\r
+\r
+#PACE: End of Constraints generated by PACE\r
diff --git a/fpga/fpga.v b/fpga/fpga.v
new file mode 100644 (file)
index 0000000..cbebc39
--- /dev/null
@@ -0,0 +1,190 @@
+//-----------------------------------------------------------------------------\r
+// The FPGA is responsible for interfacing between the A/D, the coil drivers,\r
+// and the ARM. In the low-frequency modes it passes the data straight\r
+// through, so that the ARM gets raw A/D samples over the SSP. In the high-\r
+// frequency modes, the FPGA might perform some demodulation first, to\r
+// reduce the amount of data that we must send to the ARM.\r
+//\r
+// I am not really an FPGA/ASIC designer, so I am sure that a lot of this\r
+// could be improved.\r
+//\r
+// Jonathan Westhues, March 2006\r
+// Added ISO14443-A support by Gerhard de Koning Gans, April 2008\r
+//-----------------------------------------------------------------------------\r
+\r
+`include "lo_read.v"\r
+`include "lo_simulate.v"\r
+`include "hi_read_tx.v"\r
+`include "hi_read_rx_xcorr.v"\r
+`include "hi_simulate.v"\r
+`include "hi_iso14443a.v"\r
+`include "util.v"\r
+\r
+module fpga(\r
+       spck, miso, mosi, ncs,\r
+       pck0i, ck_1356meg, ck_1356megb,\r
+       pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,\r
+       adc_d, adc_clk, adc_noe,\r
+       ssp_frame, ssp_din, ssp_dout, ssp_clk,\r
+       cross_hi, cross_lo,\r
+       dbg\r
+);\r
+       input spck, mosi, ncs;\r
+       output miso;\r
+       input pck0i, ck_1356meg, ck_1356megb;\r
+       output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;\r
+       input [7:0] adc_d;\r
+       output adc_clk, adc_noe;\r
+       input ssp_dout;\r
+       output ssp_frame, ssp_din, ssp_clk;\r
+       input cross_hi, cross_lo;\r
+       output dbg;\r
+\r
+       IBUFG #(.IOSTANDARD("DEFAULT") ) pck0b(\r
+               .O(pck0),\r
+               .I(pck0i)\r
+       );\r
+//assign pck0 = pck0i;\r
+//-----------------------------------------------------------------------------\r
+// The SPI receiver. This sets up the configuration word, which the rest of\r
+// the logic looks at to determine how to connect the A/D and the coil\r
+// drivers (i.e., which section gets it). Also assign some symbolic names\r
+// to the configuration bits, for use below.\r
+//-----------------------------------------------------------------------------\r
+\r
+reg [7:0] conf_word_shift;\r
+reg [7:0] conf_word;\r
+\r
+// We switch modes between transmitting to the 13.56 MHz tag and receiving\r
+// from it, which means that we must make sure that we can do so without\r
+// glitching, or else we will glitch the transmitted carrier.\r
+always @(posedge ncs)\r
+begin\r
+       conf_word <= conf_word_shift;\r
+end\r
+\r
+always @(posedge spck)\r
+begin\r
+       if(~ncs)\r
+       begin\r
+               conf_word_shift[7:1] <= conf_word_shift[6:0];\r
+               conf_word_shift[0] <= mosi;\r
+       end\r
+end\r
+\r
+wire [2:0] major_mode;\r
+assign major_mode = conf_word[7:5];\r
+\r
+// For the low-frequency configuration:\r
+wire lo_is_125khz;\r
+assign lo_is_125khz = conf_word[3];\r
+\r
+// For the high-frequency transmit configuration: modulation depth, either\r
+// 100% (just quite driving antenna, steady LOW), or shallower (tri-state\r
+// some fraction of the buffers)\r
+wire hi_read_tx_shallow_modulation;\r
+assign hi_read_tx_shallow_modulation = conf_word[0];\r
+\r
+// For the high-frequency receive correlator: frequency against which to\r
+// correlate.\r
+wire hi_read_rx_xcorr_848;\r
+assign hi_read_rx_xcorr_848 = conf_word[0];\r
+// and whether to drive the coil (reader) or just short it (snooper)\r
+wire hi_read_rx_xcorr_snoop;\r
+assign hi_read_rx_xcorr_snoop = conf_word[1];\r
+\r
+// For the high-frequency simulated tag: what kind of modulation to use.\r
+wire [2:0] hi_simulate_mod_type;\r
+assign hi_simulate_mod_type = conf_word[2:0];\r
+\r
+//-----------------------------------------------------------------------------\r
+// And then we instantiate the modules corresponding to each of the FPGA's\r
+// major modes, and use muxes to connect the outputs of the active mode to\r
+// the output pins.\r
+//-----------------------------------------------------------------------------\r
+\r
+lo_read lr(\r
+       pck0, ck_1356meg, ck_1356megb,\r
+       lr_pwr_lo, lr_pwr_hi, lr_pwr_oe1, lr_pwr_oe2, lr_pwr_oe3, lr_pwr_oe4,\r
+       adc_d, lr_adc_clk,\r
+       lr_ssp_frame, lr_ssp_din, ssp_dout, lr_ssp_clk,\r
+       cross_hi, cross_lo,\r
+       lr_dbg,\r
+       lo_is_125khz\r
+);\r
+\r
+lo_simulate ls(\r
+       pck0, ck_1356meg, ck_1356megb,\r
+       ls_pwr_lo, ls_pwr_hi, ls_pwr_oe1, ls_pwr_oe2, ls_pwr_oe3, ls_pwr_oe4,\r
+       adc_d, ls_adc_clk,\r
+       ls_ssp_frame, ls_ssp_din, ssp_dout, ls_ssp_clk,\r
+       cross_hi, cross_lo,\r
+       ls_dbg\r
+);\r
+\r
+hi_read_tx ht(\r
+       pck0, ck_1356meg, ck_1356megb,\r
+       ht_pwr_lo, ht_pwr_hi, ht_pwr_oe1, ht_pwr_oe2, ht_pwr_oe3, ht_pwr_oe4,\r
+       adc_d, ht_adc_clk,\r
+       ht_ssp_frame, ht_ssp_din, ssp_dout, ht_ssp_clk,\r
+       cross_hi, cross_lo,\r
+       ht_dbg,\r
+       hi_read_tx_shallow_modulation\r
+);\r
+\r
+hi_read_rx_xcorr hrxc(\r
+       pck0, ck_1356meg, ck_1356megb,\r
+       hrxc_pwr_lo, hrxc_pwr_hi, hrxc_pwr_oe1, hrxc_pwr_oe2, hrxc_pwr_oe3,     hrxc_pwr_oe4,\r
+       adc_d, hrxc_adc_clk,\r
+       hrxc_ssp_frame, hrxc_ssp_din, ssp_dout, hrxc_ssp_clk,\r
+       cross_hi, cross_lo,\r
+       hrxc_dbg,\r
+       hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop\r
+);\r
+\r
+hi_simulate hs(\r
+       pck0, ck_1356meg, ck_1356megb,\r
+       hs_pwr_lo, hs_pwr_hi, hs_pwr_oe1, hs_pwr_oe2, hs_pwr_oe3, hs_pwr_oe4,\r
+       adc_d, hs_adc_clk,\r
+       hs_ssp_frame, hs_ssp_din, ssp_dout, hs_ssp_clk,\r
+       cross_hi, cross_lo,\r
+       hs_dbg,\r
+       hi_simulate_mod_type\r
+);\r
+\r
+hi_iso14443a hisn(\r
+       pck0, ck_1356meg, ck_1356megb,\r
+       hisn_pwr_lo, hisn_pwr_hi, hisn_pwr_oe1, hisn_pwr_oe2, hisn_pwr_oe3,     hisn_pwr_oe4,\r
+       adc_d, hisn_adc_clk,\r
+       hisn_ssp_frame, hisn_ssp_din, ssp_dout, hisn_ssp_clk,\r
+       cross_hi, cross_lo,\r
+       hisn_dbg,\r
+       hi_simulate_mod_type\r
+);\r
+\r
+// Major modes:\r
+//   000 --  LF reader (generic)\r
+//   001 --  LF simulated tag (generic)\r
+//   010 --  HF reader, transmitting to tag; modulation depth selectable\r
+//   011 --  HF reader, receiving from tag, correlating as it goes; frequency selectable\r
+//   100 --  HF simulated tag\r
+//   101 --  HF ISO14443-A\r
+//   110 --  unused\r
+//   111 --  everything off\r
+\r
+mux8 mux_ssp_clk       (major_mode, ssp_clk,   lr_ssp_clk,   ls_ssp_clk,   ht_ssp_clk,   hrxc_ssp_clk,   hs_ssp_clk,   hisn_ssp_clk,   1'b0, 1'b0);\r
+mux8 mux_ssp_din       (major_mode, ssp_din,   lr_ssp_din,   ls_ssp_din,   ht_ssp_din,   hrxc_ssp_din,   hs_ssp_din,   hisn_ssp_din,   1'b0, 1'b0);\r
+mux8 mux_ssp_frame     (major_mode, ssp_frame, lr_ssp_frame, ls_ssp_frame, ht_ssp_frame, hrxc_ssp_frame, hs_ssp_frame, hisn_ssp_frame, 1'b0, 1'b0);\r
+mux8 mux_pwr_oe1       (major_mode, pwr_oe1,   lr_pwr_oe1,   ls_pwr_oe1,   ht_pwr_oe1,   hrxc_pwr_oe1,   hs_pwr_oe1,   hisn_pwr_oe1,   1'b0, 1'b0);\r
+mux8 mux_pwr_oe2       (major_mode, pwr_oe2,   lr_pwr_oe2,   ls_pwr_oe2,   ht_pwr_oe2,   hrxc_pwr_oe2,   hs_pwr_oe2,   hisn_pwr_oe2,   1'b0, 1'b0);\r
+mux8 mux_pwr_oe3       (major_mode, pwr_oe3,   lr_pwr_oe3,   ls_pwr_oe3,   ht_pwr_oe3,   hrxc_pwr_oe3,   hs_pwr_oe3,   hisn_pwr_oe3,   1'b0, 1'b0);\r
+mux8 mux_pwr_oe4       (major_mode, pwr_oe4,   lr_pwr_oe4,   ls_pwr_oe4,   ht_pwr_oe4,   hrxc_pwr_oe4,   hs_pwr_oe4,   hisn_pwr_oe4,   1'b0, 1'b0);\r
+mux8 mux_pwr_lo                (major_mode, pwr_lo,    lr_pwr_lo,    ls_pwr_lo,    ht_pwr_lo,    hrxc_pwr_lo,    hs_pwr_lo,    hisn_pwr_lo,    1'b0, 1'b0);\r
+mux8 mux_pwr_hi                (major_mode, pwr_hi,    lr_pwr_hi,    ls_pwr_hi,    ht_pwr_hi,    hrxc_pwr_hi,    hs_pwr_hi,    hisn_pwr_hi,    1'b0, 1'b0);\r
+mux8 mux_adc_clk       (major_mode, adc_clk,   lr_adc_clk,   ls_adc_clk,   ht_adc_clk,   hrxc_adc_clk,   hs_adc_clk,   hisn_adc_clk,   1'b0, 1'b0);\r
+mux8 mux_dbg           (major_mode, dbg,       lr_dbg,       ls_dbg,       ht_dbg,       hrxc_dbg,       hs_dbg,       hisn_dbg,       1'b0, 1'b0);\r
+\r
+// In all modes, let the ADC's outputs be enabled.\r
+assign adc_noe = 1'b0;\r
+\r
+endmodule\r
diff --git a/fpga/go.bat b/fpga/go.bat
new file mode 100644 (file)
index 0000000..8600d3c
--- /dev/null
@@ -0,0 +1,38 @@
+@echo off\r
+\r
+rmdir/s/q xst\r
+\r
+del fpga.ngc\r
+xst -ifn xst.scr\r
+if errorlevel 0 goto ok1\r
+goto done\r
+:ok1\r
+\r
+del fpga.ngd\r
+ngdbuild -aul -p xc2s30-6vq100 -nt timestamp -uc fpga.ucf fpga.ngc fpga.ngd\r
+if errorlevel 0 goto ok2\r
+goto done\r
+:ok2\r
+\r
+del fpga.ncd\r
+map -p xc2s30-6vq100 fpga.ngd\r
+if errorlevel 0 goto ok3\r
+goto done\r
+:ok3\r
+\r
+del fpga-placed.ncd\r
+par fpga.ncd fpga-placed.ncd\r
+if errorlevel 0 goto ok4\r
+goto done\r
+:ok4\r
+\r
+del fpga.bit fpga.drc fpga.rbt\r
+bitgen -b fpga-placed.ncd fpga.bit\r
+if errorlevel 0 goto ok5\r
+goto done\r
+:ok5\r
+\r
+echo okay\r
+perl ..\tools\rbt2c.pl fpga.rbt > ..\armsrc\fpgaimg.c\r
+\r
+:done\r
diff --git a/fpga/hi_iso14443a.v b/fpga/hi_iso14443a.v
new file mode 100644 (file)
index 0000000..eb03fa2
--- /dev/null
@@ -0,0 +1,360 @@
+//-----------------------------------------------------------------------------
+// ISO14443-A support for the Proxmark III
+// Gerhard de Koning Gans, April 2008
+//-----------------------------------------------------------------------------
+
+module hi_iso14443a(
+    pck0, ck_1356meg, ck_1356megb,
+    pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
+    adc_d, adc_clk,
+    ssp_frame, ssp_din, ssp_dout, ssp_clk,
+    cross_hi, cross_lo,
+    dbg,
+    mod_type
+);
+    input pck0, ck_1356meg, ck_1356megb;
+    output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;
+    input [7:0] adc_d;
+    output adc_clk;
+    input ssp_dout;
+    output ssp_frame, ssp_din, ssp_clk;
+    input cross_hi, cross_lo;
+    output dbg;
+    input [2:0] mod_type;
+
+reg ssp_clk;
+reg ssp_frame;
+
+reg fc_div_2;
+always @(posedge ck_1356meg)
+    fc_div_2 = ~fc_div_2;
+
+wire adc_clk;
+assign adc_clk = ck_1356meg;
+
+reg after_hysteresis, after_hysteresis_prev1, after_hysteresis_prev2, after_hysteresis_prev3;
+reg [11:0] has_been_low_for;
+reg [8:0] saw_deep_modulation;
+reg [2:0] deep_counter;
+reg deep_modulation;
+always @(negedge adc_clk)
+begin
+       if(& adc_d[7:6]) after_hysteresis <= 1'b1;
+    else if(~(| adc_d[7:4])) after_hysteresis <= 1'b0;
+       
+       if(~(| adc_d[7:0]))
+       begin
+               if(deep_counter == 3'd7)
+               begin
+                       deep_modulation <= 1'b1;
+                       saw_deep_modulation <= 8'd0;
+               end
+               else
+                       deep_counter <= deep_counter + 1;
+       end
+       else
+       begin
+               deep_counter <= 3'd0;
+               if(saw_deep_modulation == 8'd255)
+                       deep_modulation <= 1'b0;
+               else
+                       saw_deep_modulation <= saw_deep_modulation + 1;
+       end
+       
+       if(after_hysteresis)
+    begin
+        has_been_low_for <= 7'b0;
+    end
+    else
+    begin
+        if(has_been_low_for == 12'd4095)
+        begin
+            has_been_low_for <= 12'd0;
+            after_hysteresis <= 1'b1;
+        end
+        else
+            has_been_low_for <= has_been_low_for + 1;
+    end
+end
+
+// Report every 4 subcarrier cycles
+// 64 periods of carrier frequency => 6-bit counter [negedge_cnt]
+reg [5:0] negedge_cnt;
+reg bit1, bit2, bit3;
+reg [3:0] count_ones;
+reg [3:0] count_zeros;
+wire [7:0] avg;
+reg [7:0] lavg;
+reg signed [12:0] step1;
+reg signed [12:0] step2;
+reg [7:0] stepsize;
+reg curbit;
+reg [12:0] average;
+wire signed [9:0] dif;
+
+// A register to send the results to the arm
+reg signed [7:0] to_arm;
+
+assign avg[7:0] = average[11:4];
+assign dif = lavg - avg;
+
+reg bit_to_arm;
+reg fdt_indicator, fdt_elapsed;
+reg [10:0] fdt_counter;
+reg [47:0] mod_sig_buf;
+wire mod_sig_buf_empty;
+reg [5:0] mod_sig_ptr;
+reg [3:0] mod_sig_flip;
+reg mod_sig, mod_sig_coil;
+reg temp_buffer_reset;
+reg sendbit;
+
+assign mod_sig_buf_empty = ~(|mod_sig_buf[47:0]);
+reg [2:0] ssp_frame_counter;
+
+// ADC data appears on the rising edge, so sample it on the falling edge
+always @(negedge adc_clk)
+begin
+
+       // last bit = 0 then fdt = 1172, in case of 0x26 (7-bit command, LSB first!)
+       // last bit = 1 then fdt = 1236, in case of 0x52 (7-bit command, LSB first!)
+       if(fdt_counter == 11'd740) fdt_indicator = 1'b1;
+       
+       if(fdt_counter == 11'd1148)
+       begin
+               if(fdt_elapsed)
+               begin
+                       if(negedge_cnt[3:0] == mod_sig_flip[3:0]) mod_sig_coil <= mod_sig;
+               end
+               else
+               begin
+                       mod_sig_flip[3:0] <= negedge_cnt[3:0];
+                       mod_sig_coil <= mod_sig;
+                       fdt_elapsed = 1'b1;
+                       fdt_indicator = 1'b0;
+
+                       if(~(| mod_sig_ptr[5:0])) mod_sig_ptr <= 6'b001001;
+                       else temp_buffer_reset = 1'b1; // fix position of the buffer pointer
+               end
+       end
+       else
+       begin
+               fdt_counter <= fdt_counter + 1;
+       end
+       
+       if(& negedge_cnt[3:0])
+       begin
+               // When there is a dip in the signal and not in reader mode
+               if(~after_hysteresis && mod_sig_buf_empty && ~((mod_type == 3'b100) || (mod_type == 3'b011) || (mod_type == 3'b010))) // last condition to prevent reset
+               begin
+                       fdt_counter <= 11'd0;
+                       fdt_elapsed = 1'b0;
+                       fdt_indicator = 1'b0;
+                       temp_buffer_reset = 1'b0;
+                       mod_sig_ptr <= 6'b000000;
+               end
+               
+               lavg <= avg;
+               
+               if(stepsize<16) stepsize = 8'd16;
+
+               if(dif>0)
+               begin
+                       step1 = dif*3;
+                       step2 = stepsize*2; // 3:2
+                       if(step1>step2)
+                       begin
+                               curbit = 1'b0;
+                               stepsize = dif;
+                       end
+               end
+               else
+               begin
+                       step1 = dif*3;
+                       step1 = -step1;
+                       step2 = stepsize*2;
+                       if(step1>step2)
+                       begin
+                               curbit = 1'b1;
+                               stepsize = -dif;
+                       end
+               end
+               
+               if(curbit)
+               begin
+                       count_zeros <= 4'd0;
+                       if(& count_ones[3:2])
+                       begin
+                               curbit = 1'b0; // suppressed signal
+                               stepsize = 8'd24; // just a fine number
+                       end
+                       else
+                       begin
+                               count_ones <= count_ones + 1;
+                       end
+               end
+               else
+               begin
+                       count_ones <= 4'd0;
+                       if(& count_zeros[3:0])
+                       begin
+                               stepsize = 8'd24;
+                       end
+                       else
+                       begin
+                               count_zeros <= count_zeros + 1;
+                       end
+               end
+               
+               // What do we communicate to the ARM
+               if(mod_type == 3'b001) sendbit = after_hysteresis;
+               else if(mod_type == 3'b010)
+               begin
+                       if(fdt_counter > 11'd772) sendbit = mod_sig_coil;
+                       else sendbit = fdt_indicator;
+               end
+               else if(mod_type == 3'b011) sendbit = curbit;
+               else sendbit = 1'b0;
+
+       end
+
+       if(~(| negedge_cnt[3:0])) average <= adc_d;
+       else average <= average + adc_d;
+
+       if(negedge_cnt == 7'd63)
+    begin
+               if(deep_modulation)
+               begin
+                       to_arm <= {after_hysteresis_prev1,after_hysteresis_prev2,after_hysteresis_prev3,after_hysteresis,1'b0,1'b0,1'b0,1'b0};
+               end
+               else
+               begin
+                       to_arm <= {after_hysteresis_prev1,after_hysteresis_prev2,after_hysteresis_prev3,after_hysteresis,bit1,bit2,bit3,curbit};
+               end
+
+        negedge_cnt <= 0;
+       
+               end
+    else
+    begin
+        negedge_cnt <= negedge_cnt + 1;
+    end
+
+    if(negedge_cnt == 6'd15)
+       begin
+        after_hysteresis_prev1 <= after_hysteresis;
+               bit1 <= curbit;
+       end
+    if(negedge_cnt == 6'd31)
+       begin
+        after_hysteresis_prev2 <= after_hysteresis;
+               bit2 <= curbit;
+       end
+    if(negedge_cnt == 6'd47)
+       begin
+        after_hysteresis_prev3 <= after_hysteresis;
+               bit3 <= curbit;
+       end
+       
+
+       if(mod_type != 3'b000)
+       begin
+               if(negedge_cnt[3:0] == 4'b1000)
+               begin
+                       // The modulation signal of the tag
+                       mod_sig_buf[47:0] <= {mod_sig_buf[46:1], ssp_dout, 1'b0};
+                       if((ssp_dout || (| mod_sig_ptr[5:0])) && ~fdt_elapsed)
+                               if(mod_sig_ptr == 6'b101110)
+                               begin
+                                       mod_sig_ptr <= 6'b000000;
+                               end
+                               else mod_sig_ptr <= mod_sig_ptr + 1;
+                       else if(fdt_elapsed && ~temp_buffer_reset)
+                       begin
+                               if(ssp_dout) temp_buffer_reset = 1'b1;
+                               if(mod_sig_ptr == 6'b000010) mod_sig_ptr <= 6'b001001;
+                               else mod_sig_ptr <= mod_sig_ptr - 1;
+                       end
+                       else
+                       begin
+                               // side effect: when ptr = 1 it will cancel the first 1 of every block of ones
+                               if(~mod_sig_buf[mod_sig_ptr-1] && ~mod_sig_buf[mod_sig_ptr+1]) mod_sig = 1'b0;
+                               else mod_sig = mod_sig_buf[mod_sig_ptr] & fdt_elapsed; // & fdt_elapsed  was for direct relay to oe4
+                       end
+               end
+       end
+       
+       // SSP Clock and data
+       if(mod_type == 3'b000)
+       begin
+               if(negedge_cnt[2:0] == 3'b100)
+                       ssp_clk <= 1'b0;
+                       
+               if(negedge_cnt[2:0] == 3'b000)
+               begin
+                       ssp_clk <= 1'b1;
+                       // Don't shift if we just loaded new data, obviously.
+                       if(negedge_cnt != 7'd0)
+                       begin
+                               to_arm[7:1] <= to_arm[6:0];
+                       end
+               end
+
+               if(negedge_cnt[5:4] == 2'b00)
+                       ssp_frame = 1'b1;
+               else
+                       ssp_frame = 1'b0;
+               
+               bit_to_arm = to_arm[7];
+       end
+       else
+       begin
+               if(negedge_cnt[3:0] == 4'b1000) ssp_clk <= 1'b0;
+
+               if(negedge_cnt[3:0] == 4'b0111)
+               begin
+                       if(ssp_frame_counter == 3'd7) ssp_frame_counter <= 3'd0;
+                       else ssp_frame_counter <= ssp_frame_counter + 1;
+               end
+
+               if(negedge_cnt[3:0] == 4'b0000)
+               begin
+                       ssp_clk <= 1'b1;
+               end
+               
+               ssp_frame = (ssp_frame_counter == 3'd7);
+       
+               bit_to_arm = sendbit;
+       end
+       
+end
+
+assign ssp_din = bit_to_arm;
+
+// Modulating carrier frequency is fc/16
+wire modulating_carrier;
+assign modulating_carrier = (mod_sig_coil & negedge_cnt[3] & (mod_type == 3'b010));
+assign pwr_hi = (ck_1356megb & (((mod_type == 3'b100) & ~mod_sig_coil) || (mod_type == 3'b011)));
+
+// This one is all LF, so doesn't matter
+//assign pwr_oe2 = modulating_carrier;
+assign pwr_oe2 = 1'b0;
+
+// Toggle only one of these, since we are already producing much deeper
+// modulation than a real tag would.
+//assign pwr_oe1 = modulating_carrier;
+assign pwr_oe1 = 1'b0;
+assign pwr_oe4 = modulating_carrier;
+//assign pwr_oe4 = 1'b0;
+
+// This one is always on, so that we can watch the carrier.
+//assign pwr_oe3 = modulating_carrier;
+assign pwr_oe3 = 1'b0;
+
+
+assign dbg = negedge_cnt[3];
+
+// Unused.
+assign pwr_lo = 1'b0;
+
+endmodule
diff --git a/fpga/hi_read_rx_xcorr.v b/fpga/hi_read_rx_xcorr.v
new file mode 100644 (file)
index 0000000..253f508
--- /dev/null
@@ -0,0 +1,165 @@
+//-----------------------------------------------------------------------------\r
+//\r
+// Jonathan Westhues, April 2006\r
+//-----------------------------------------------------------------------------\r
+\r
+module hi_read_rx_xcorr(\r
+    pck0, ck_1356meg, ck_1356megb,\r
+    pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,\r
+    adc_d, adc_clk,\r
+    ssp_frame, ssp_din, ssp_dout, ssp_clk,\r
+    cross_hi, cross_lo,\r
+    dbg,\r
+    xcorr_is_848, snoop\r
+);\r
+    input pck0, ck_1356meg, ck_1356megb;\r
+    output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;\r
+    input [7:0] adc_d;\r
+    output adc_clk;\r
+    input ssp_dout;\r
+    output ssp_frame, ssp_din, ssp_clk;\r
+    input cross_hi, cross_lo;\r
+    output dbg;\r
+    input xcorr_is_848, snoop;\r
+\r
+// Carrier is steady on through this, unless we're snooping.\r
+assign pwr_hi = ck_1356megb & (~snoop);\r
+assign pwr_oe1 = 1'b0;\r
+assign pwr_oe2 = 1'b0;\r
+assign pwr_oe3 = 1'b0;\r
+assign pwr_oe4 = 1'b0;\r
+\r
+reg ssp_clk;\r
+reg ssp_frame;\r
+\r
+reg fc_div_2;\r
+always @(posedge ck_1356meg)\r
+    fc_div_2 = ~fc_div_2;\r
+\r
+reg adc_clk;\r
+\r
+always @(xcorr_is_848 or fc_div_2 or ck_1356meg)\r
+    if(xcorr_is_848)\r
+        // The subcarrier frequency is fc/16; we will sample at fc, so that \r
+        // means the subcarrier is 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 ...\r
+        adc_clk <= ck_1356meg;\r
+    else\r
+        // The subcarrier frequency is fc/32; we will sample at fc/2, and\r
+        // the subcarrier will look identical.\r
+        adc_clk <= fc_div_2;\r
+\r
+// When we're a reader, we just need to do the BPSK demod; but when we're an\r
+// eavesdropper, we also need to pick out the commands sent by the reader,\r
+// using AM. Do this the same way that we do it for the simulated tag.\r
+reg after_hysteresis, after_hysteresis_prev;\r
+reg [11:0] has_been_low_for;\r
+always @(negedge adc_clk)\r
+begin\r
+    if(& adc_d[7:0]) after_hysteresis <= 1'b1;\r
+    else if(~(| adc_d[7:0])) after_hysteresis <= 1'b0;\r
+\r
+    if(after_hysteresis)\r
+    begin\r
+        has_been_low_for <= 7'b0;\r
+    end\r
+    else\r
+    begin\r
+        if(has_been_low_for == 12'd4095)\r
+        begin\r
+            has_been_low_for <= 12'd0;\r
+            after_hysteresis <= 1'b1;\r
+        end\r
+        else\r
+            has_been_low_for <= has_been_low_for + 1;\r
+    end\r
+end\r
+\r
+// Let us report a correlation every 4 subcarrier cycles, or 4*16 samples,\r
+// so we need a 6-bit counter.\r
+reg [5:0] corr_i_cnt;\r
+reg [5:0] corr_q_cnt;\r
+// And a couple of registers in which to accumulate the correlations.\r
+reg signed [15:0] corr_i_accum;\r
+reg signed [15:0] corr_q_accum;\r
+reg signed [7:0] corr_i_out;\r
+reg signed [7:0] corr_q_out;\r
+\r
+// ADC data appears on the rising edge, so sample it on the falling edge\r
+always @(negedge adc_clk)\r
+begin\r
+    // These are the correlators: we correlate against in-phase and quadrature\r
+    // versions of our reference signal, and keep the (signed) result to\r
+    // send out later over the SSP.\r
+    if(corr_i_cnt == 7'd63)\r
+    begin\r
+        if(snoop)\r
+        begin\r
+            corr_i_out <= {corr_i_accum[12:6], after_hysteresis_prev};\r
+            corr_q_out <= {corr_q_accum[12:6], after_hysteresis};\r
+        end\r
+        else\r
+        begin\r
+            // Only correlations need to be delivered.\r
+            corr_i_out <= corr_i_accum[13:6];\r
+            corr_q_out <= corr_q_accum[13:6];\r
+        end\r
+\r
+        corr_i_accum <= adc_d;\r
+        corr_q_accum <= adc_d;\r
+        corr_q_cnt <= 4;\r
+        corr_i_cnt <= 0;\r
+    end\r
+    else\r
+    begin\r
+        if(corr_i_cnt[3])\r
+            corr_i_accum <= corr_i_accum - adc_d;\r
+        else\r
+            corr_i_accum <= corr_i_accum + adc_d;\r
+\r
+        if(corr_q_cnt[3])\r
+            corr_q_accum <= corr_q_accum - adc_d;\r
+        else\r
+            corr_q_accum <= corr_q_accum + adc_d;\r
+\r
+        corr_i_cnt <= corr_i_cnt + 1;\r
+        corr_q_cnt <= corr_q_cnt + 1;\r
+    end\r
+\r
+    // The logic in hi_simulate.v reports 4 samples per bit. We report two\r
+    // (I, Q) pairs per bit, so we should do 2 samples per pair.\r
+    if(corr_i_cnt == 6'd31)\r
+        after_hysteresis_prev <= after_hysteresis;\r
+\r
+    // Then the result from last time is serialized and send out to the ARM.\r
+    // We get one report each cycle, and each report is 16 bits, so the\r
+    // ssp_clk should be the adc_clk divided by 64/16 = 4.\r
+\r
+    if(corr_i_cnt[1:0] == 2'b10)\r
+        ssp_clk <= 1'b0;\r
+\r
+    if(corr_i_cnt[1:0] == 2'b00)\r
+    begin\r
+        ssp_clk <= 1'b1;\r
+        // Don't shift if we just loaded new data, obviously.\r
+        if(corr_i_cnt != 7'd0)\r
+        begin\r
+            corr_i_out[7:0] <= {corr_i_out[6:0], corr_q_out[7]};\r
+            corr_q_out[7:1] <= corr_q_out[6:0];\r
+        end\r
+    end\r
+\r
+    if(corr_i_cnt[5:2] == 4'b000 || corr_i_cnt[5:2] == 4'b1000)\r
+        ssp_frame = 1'b1;\r
+    else\r
+        ssp_frame = 1'b0;\r
+\r
+end\r
+\r
+assign ssp_din = corr_i_out[7];\r
+\r
+assign dbg = corr_i_cnt[3];\r
+\r
+// Unused.\r
+assign pwr_lo = 1'b0;\r
+\r
+endmodule\r
diff --git a/fpga/hi_read_tx.v b/fpga/hi_read_tx.v
new file mode 100644 (file)
index 0000000..c2cec3a
--- /dev/null
@@ -0,0 +1,76 @@
+//-----------------------------------------------------------------------------\r
+// The way that we connect things when transmitting a command to an ISO\r
+// 15693 tag, using 100% modulation only for now.\r
+//\r
+// Jonathan Westhues, April 2006\r
+//-----------------------------------------------------------------------------\r
+\r
+module hi_read_tx(\r
+    pck0, ck_1356meg, ck_1356megb,\r
+    pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,\r
+    adc_d, adc_clk,\r
+    ssp_frame, ssp_din, ssp_dout, ssp_clk,\r
+    cross_hi, cross_lo,\r
+    dbg,\r
+    shallow_modulation\r
+);\r
+    input pck0, ck_1356meg, ck_1356megb;\r
+    output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;\r
+    input [7:0] adc_d;\r
+    output adc_clk;\r
+    input ssp_dout;\r
+    output ssp_frame, ssp_din, ssp_clk;\r
+    input cross_hi, cross_lo;\r
+    output dbg;\r
+    input shallow_modulation;\r
+\r
+// The high-frequency stuff. For now, for testing, just bring out the carrier,\r
+// and allow the ARM to modulate it over the SSP.\r
+reg pwr_hi;\r
+reg pwr_oe1;\r
+reg pwr_oe2;\r
+reg pwr_oe3;\r
+reg pwr_oe4;\r
+always @(ck_1356megb or ssp_dout or shallow_modulation)\r
+begin\r
+    if(shallow_modulation)\r
+    begin\r
+        pwr_hi <= ck_1356megb;\r
+        pwr_oe1 <= ~ssp_dout;\r
+        pwr_oe2 <= ~ssp_dout;\r
+        pwr_oe3 <= ~ssp_dout;\r
+        pwr_oe4 <= 1'b0;\r
+    end\r
+    else\r
+    begin\r
+        pwr_hi <= ck_1356megb & ssp_dout;\r
+        pwr_oe1 <= 1'b0;\r
+        pwr_oe2 <= 1'b0;\r
+        pwr_oe3 <= 1'b0;\r
+        pwr_oe4 <= 1'b0;\r
+    end\r
+end\r
+\r
+// Then just divide the 13.56 MHz clock down to produce appropriate clocks\r
+// for the synchronous serial port.\r
+\r
+reg [6:0] hi_div_by_128;\r
+\r
+always @(posedge ck_1356meg)\r
+    hi_div_by_128 <= hi_div_by_128 + 1;\r
+\r
+assign ssp_clk = hi_div_by_128[6];\r
+\r
+reg [2:0] hi_byte_div;\r
+\r
+always @(negedge ssp_clk)\r
+    hi_byte_div <= hi_byte_div + 1;\r
+\r
+assign ssp_frame = (hi_byte_div == 3'b000);\r
+\r
+assign ssp_din = 1'b0;\r
+\r
+assign pwr_lo = 1'b0;\r
+assign dbg = ssp_frame;\r
+\r
+endmodule\r
diff --git a/fpga/hi_simulate.v b/fpga/hi_simulate.v
new file mode 100644 (file)
index 0000000..d0a7117
--- /dev/null
@@ -0,0 +1,106 @@
+//-----------------------------------------------------------------------------\r
+// Pretend to be an ISO 14443 tag. We will do this by alternately short-\r
+// circuiting and open-circuiting the antenna coil, with the tri-state\r
+// pins. \r
+//\r
+// We communicate over the SSP, as a bitstream (i.e., might as well be\r
+// unframed, though we still generate the word sync signal). The output\r
+// (ARM -> FPGA) tells us whether to modulate or not. The input (FPGA\r
+// -> ARM) is us using the A/D as a fancy comparator; this is with\r
+// (software-added) hysteresis, to undo the high-pass filter.\r
+//\r
+// At this point only Type A is implemented. This means that we are using a\r
+// bit rate of 106 kbit/s, or fc/128. Oversample by 4, which ought to make\r
+// things practical for the ARM (fc/32, 423.8 kbits/s, ~50 kbytes/s)\r
+//\r
+// Jonathan Westhues, October 2006\r
+//-----------------------------------------------------------------------------\r
+\r
+module hi_simulate(\r
+    pck0, ck_1356meg, ck_1356megb,\r
+    pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,\r
+    adc_d, adc_clk,\r
+    ssp_frame, ssp_din, ssp_dout, ssp_clk,\r
+    cross_hi, cross_lo,\r
+    dbg,\r
+    mod_type\r
+);\r
+    input pck0, ck_1356meg, ck_1356megb;\r
+    output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;\r
+    input [7:0] adc_d;\r
+    output adc_clk;\r
+    input ssp_dout;\r
+    output ssp_frame, ssp_din, ssp_clk;\r
+    input cross_hi, cross_lo;\r
+    output dbg;\r
+    input [2:0] mod_type;\r
+\r
+// Power amp goes between LOW and tri-state, so pwr_hi (and pwr_lo) can\r
+// always be low.\r
+assign pwr_hi = 1'b0;\r
+assign pwr_lo = 1'b0;\r
+\r
+// The comparator with hysteresis on the output from the peak detector.\r
+reg after_hysteresis;\r
+assign adc_clk = ck_1356meg;\r
+\r
+always @(negedge adc_clk)\r
+begin\r
+    if(& adc_d[7:5]) after_hysteresis = 1'b1;\r
+    else if(~(| adc_d[7:5])) after_hysteresis = 1'b0;\r
+end\r
+\r
+// Divide 13.56 MHz by 32 to produce the SSP_CLK\r
+reg [4:0] ssp_clk_divider;\r
+always @(posedge adc_clk)\r
+    ssp_clk_divider <= (ssp_clk_divider + 1);\r
+assign ssp_clk = ssp_clk_divider[4];\r
+\r
+// Divide SSP_CLK by 8 to produce the byte framing signal; the phase of\r
+// this is arbitrary, because it's just a bitstream.\r
+// One nasty issue, though: I can't make it work with both rx and tx at\r
+// once. The phase wrt ssp_clk must be changed. TODO to find out why\r
+// that is and make a better fix.\r
+reg [2:0] ssp_frame_divider_to_arm;\r
+always @(posedge ssp_clk)\r
+    ssp_frame_divider_to_arm <= (ssp_frame_divider_to_arm + 1);\r
+reg [2:0] ssp_frame_divider_from_arm;\r
+always @(negedge ssp_clk)\r
+    ssp_frame_divider_from_arm <= (ssp_frame_divider_from_arm + 1);\r
+\r
+reg ssp_frame;\r
+always @(ssp_frame_divider_to_arm or ssp_frame_divider_from_arm or mod_type)\r
+    if(mod_type == 3'b000) // not modulating, so listening, to ARM\r
+        ssp_frame = (ssp_frame_divider_to_arm == 3'b000);\r
+    else\r
+        ssp_frame = (ssp_frame_divider_from_arm == 3'b000);\r
+\r
+// Synchronize up the after-hysteresis signal, to produce DIN.\r
+reg ssp_din;\r
+always @(posedge ssp_clk)\r
+    ssp_din = after_hysteresis;\r
+\r
+// Modulating carrier frequency is fc/16, reuse ssp_clk divider for that\r
+reg modulating_carrier;\r
+always @(mod_type or ssp_clk or ssp_dout)\r
+    if(mod_type == 3'b000)\r
+        modulating_carrier <= 1'b0;                          // no modulation\r
+    else if(mod_type == 3'b001)\r
+        modulating_carrier <= ssp_dout ^ ssp_clk_divider[3]; // XOR means BPSK\r
+    else\r
+        modulating_carrier <= 1'b0;                           // yet unused\r
+\r
+// This one is all LF, so doesn't matter\r
+assign pwr_oe2 = modulating_carrier;\r
+\r
+// Toggle only one of these, since we are already producing much deeper\r
+// modulation than a real tag would.\r
+assign pwr_oe1 = modulating_carrier;\r
+assign pwr_oe4 = modulating_carrier;\r
+\r
+// This one is always on, so that we can watch the carrier.\r
+assign pwr_oe3 = 1'b0;\r
+\r
+assign dbg = after_hysteresis;\r
+\r
+endmodule\r
diff --git a/fpga/lo_read.v b/fpga/lo_read.v
new file mode 100644 (file)
index 0000000..9c3edb2
--- /dev/null
@@ -0,0 +1,102 @@
+//-----------------------------------------------------------------------------\r
+// The way that we connect things in low-frequency read mode. In this case\r
+// we are generating the 134 kHz or 125 kHz carrier, and running the \r
+// unmodulated carrier at that frequency. The A/D samples at that same rate,\r
+// and the result is serialized.\r
+//\r
+// Jonathan Westhues, April 2006\r
+//-----------------------------------------------------------------------------\r
+\r
+module lo_read(\r
+    pck0, ck_1356meg, ck_1356megb,\r
+    pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,\r
+    adc_d, adc_clk,\r
+    ssp_frame, ssp_din, ssp_dout, ssp_clk,\r
+    cross_hi, cross_lo,\r
+    dbg,\r
+    lo_is_125khz\r
+);\r
+    input pck0, ck_1356meg, ck_1356megb;\r
+    output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;\r
+    input [7:0] adc_d;\r
+    output adc_clk;\r
+    input ssp_dout;\r
+    output ssp_frame, ssp_din, ssp_clk;\r
+    input cross_hi, cross_lo;\r
+    output dbg;\r
+    input lo_is_125khz;\r
+\r
+// The low-frequency RFID stuff. This is relatively simple, because most\r
+// of the work happens on the ARM, and we just pass samples through. The\r
+// PCK0 must be divided down to generate the A/D clock, and from there by\r
+// a factor of 8 to generate the carrier (that we apply to the coil drivers).\r
+//\r
+// This is also where we decode the received synchronous serial port words,\r
+// to determine how to drive the output enables.\r
+\r
+// PCK0 will run at (PLL clock) / 4, or 24 MHz. That means that we can do\r
+// 125 kHz by dividing by a further factor of (8*12*2), or ~134 kHz by\r
+// dividing by a factor of (8*11*2) (for 136 kHz, ~2% error, tolerable).\r
+\r
+reg [3:0] pck_divider;\r
+reg clk_lo;\r
+\r
+always @(posedge pck0)\r
+begin\r
+    if(lo_is_125khz)\r
+    begin\r
+        if(pck_divider == 4'd11)\r
+        begin\r
+            pck_divider <= 4'd0;\r
+            clk_lo = !clk_lo;\r
+        end\r
+        else\r
+            pck_divider <= pck_divider + 1;\r
+    end\r
+    else\r
+    begin\r
+        if(pck_divider == 4'd10)\r
+        begin\r
+            pck_divider <= 4'd0;\r
+            clk_lo = !clk_lo;\r
+        end\r
+        else\r
+            pck_divider <= pck_divider + 1;\r
+    end\r
+end\r
+\r
+reg [2:0] carrier_divider_lo;\r
+\r
+always @(posedge clk_lo)\r
+begin\r
+    carrier_divider_lo <= carrier_divider_lo + 1;\r
+end\r
+\r
+assign pwr_lo = carrier_divider_lo[2];\r
+\r
+// This serializes the values returned from the A/D, and sends them out\r
+// over the SSP.\r
+\r
+reg [7:0] to_arm_shiftreg;\r
+\r
+always @(posedge clk_lo)\r
+begin\r
+    if(carrier_divider_lo == 3'b000)\r
+        to_arm_shiftreg <= adc_d;\r
+    else\r
+        to_arm_shiftreg[7:1] <= to_arm_shiftreg[6:0];\r
+end\r
+\r
+assign ssp_clk = clk_lo;\r
+assign ssp_frame = (carrier_divider_lo == 3'b001);\r
+assign ssp_din = to_arm_shiftreg[7];\r
+\r
+// The ADC converts on the falling edge, and our serializer loads when\r
+// carrier_divider_lo == 3'b000.\r
+assign adc_clk = ~carrier_divider_lo[2];\r
+\r
+assign pwr_hi = 1'b0;\r
+\r
+assign dbg = adc_clk;\r
+\r
+endmodule\r
diff --git a/fpga/lo_simulate.v b/fpga/lo_simulate.v
new file mode 100644 (file)
index 0000000..7eb910b
--- /dev/null
@@ -0,0 +1,37 @@
+//-----------------------------------------------------------------------------\r
+// The way that we connect things in low-frequency simulation mode. In this\r
+// case just pass everything through to the ARM, which can bit-bang this\r
+// (because it is so slow).\r
+//\r
+// Jonathan Westhues, April 2006\r
+//-----------------------------------------------------------------------------\r
+\r
+module lo_simulate(\r
+    pck0, ck_1356meg, ck_1356megb,\r
+    pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,\r
+    adc_d, adc_clk,\r
+    ssp_frame, ssp_din, ssp_dout, ssp_clk,\r
+    cross_hi, cross_lo,\r
+    dbg\r
+);\r
+    input pck0, ck_1356meg, ck_1356megb;\r
+    output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;\r
+    input [7:0] adc_d;\r
+    output adc_clk;\r
+    input ssp_dout;\r
+    output ssp_frame, ssp_din, ssp_clk;\r
+    input cross_hi, cross_lo;\r
+    output dbg;\r
+\r
+// No logic, straight through.\r
+assign pwr_oe3 = 1'b0;\r
+assign pwr_oe1 = ssp_dout;\r
+assign pwr_oe2 = ssp_dout;\r
+assign pwr_oe4 = ssp_dout;\r
+assign ssp_clk = cross_lo;\r
+assign pwr_lo = 1'b0;\r
+assign adc_clk = 1'b0;\r
+assign pwr_hi = 1'b0;\r
+assign dbg = cross_lo;\r
+\r
+endmodule\r
diff --git a/fpga/sim.tcl b/fpga/sim.tcl
new file mode 100644 (file)
index 0000000..477acd1
--- /dev/null
@@ -0,0 +1,27 @@
+#------------------------------------------------------------------------------\r
+# Run the simulation testbench in ModelSim: recompile both Verilog source\r
+# files, then start the simulation, add a lot of signals to the waveform\r
+# viewer, and run. I should (TODO) fix the absolute paths at some point.\r
+#\r
+# Jonathan Westhues, Mar 2006\r
+#------------------------------------------------------------------------------\r
+\r
+vlog -work work -O0 C:/depot/proximity/mark3/fpga/fpga.v\r
+vlog -work work -O0 C:/depot/proximity/mark3/fpga/fpga_tb.v\r
+\r
+vsim work.fpga_tb\r
+\r
+add wave sim:/fpga_tb/adc_clk\r
+add wave sim:/fpga_tb/adc_d\r
+add wave sim:/fpga_tb/pwr_lo\r
+add wave sim:/fpga_tb/ssp_clk\r
+add wave sim:/fpga_tb/ssp_frame\r
+add wave sim:/fpga_tb/ssp_din\r
+add wave sim:/fpga_tb/ssp_dout\r
+\r
+add wave sim:/fpga_tb/dut/clk_lo\r
+add wave sim:/fpga_tb/dut/pck_divider\r
+add wave sim:/fpga_tb/dut/carrier_divider_lo\r
+add wave sim:/fpga_tb/dut/conf_word\r
+\r
+run 30000\r
diff --git a/fpga/testbed_fpga.v b/fpga/testbed_fpga.v
new file mode 100644 (file)
index 0000000..3ef2766
--- /dev/null
@@ -0,0 +1,50 @@
+`include "fpga.v"\r
+\r
+module testbed_fpga;\r
+    reg spck, mosi, ncs;\r
+    wire miso;\r
+    reg pck0i, ck_1356meg, ck_1356megb;\r
+    wire pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;\r
+    reg [7:0] adc_d;\r
+    wire adc_clk, adc_noe;\r
+    reg ssp_dout;\r
+    wire ssp_frame, ssp_din, ssp_clk;\r
+\r
+    fpga dut(\r
+        spck, miso, mosi, ncs,\r
+        pck0i, ck_1356meg, ck_1356megb,\r
+        pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,\r
+        adc_d, adc_clk, adc_noe,\r
+        ssp_frame, ssp_din, ssp_dout, ssp_clk\r
+    );\r
+\r
+       integer i;\r
+\r
+       initial begin\r
+\r
+               // init inputs\r
+               #5 ncs=1;\r
+               #5 spck = 1;\r
+               #5 mosi = 1;\r
+\r
+               #50 ncs=0;\r
+               for (i = 0 ;  i < 8 ;  i = i + 1) begin\r
+                       #5 mosi = $random;\r
+                       #5 spck = 0;\r
+                       #5 spck = 1;\r
+               end\r
+               #5 ncs=1;\r
+\r
+               #50 ncs=0;\r
+               for (i = 0 ;  i < 8 ;  i = i + 1) begin\r
+                       #5 mosi = $random;\r
+                       #5 spck = 0;\r
+                       #5 spck = 1;\r
+               end\r
+               #5 ncs=1;\r
+\r
+               #50 mosi=1;\r
+               $finish;\r
+       end\r
+       \r
+endmodule // main\r
diff --git a/fpga/testbed_hi_read_tx.v b/fpga/testbed_hi_read_tx.v
new file mode 100644 (file)
index 0000000..0d600a1
--- /dev/null
@@ -0,0 +1,109 @@
+`include "hi_read_tx.v"\r
+\r
+/*\r
+       pck0                    - input main 24Mhz clock (PLL / 4)\r
+       [7:0] adc_d             - input data from A/D converter\r
+       shallow_modulation      - modulation type\r
+\r
+       pwr_lo                  - output to coil drivers (ssp_clk / 8)\r
+       adc_clk                 - output A/D clock signal\r
+       ssp_frame               - output SSS frame indicator (goes high while the 8 bits are shifted)\r
+       ssp_din                 - output SSP data to ARM (shifts 8 bit A/D value serially to ARM MSB first)\r
+       ssp_clk                 - output SSP clock signal\r
+\r
+       ck_1356meg              - input unused\r
+       ck_1356megb             - input unused\r
+       ssp_dout                - input unused\r
+       cross_hi                - input unused\r
+       cross_lo                - input unused\r
+\r
+       pwr_hi                  - output unused, tied low\r
+       pwr_oe1                 - output unused, undefined\r
+       pwr_oe2                 - output unused, undefined\r
+       pwr_oe3                 - output unused, undefined\r
+       pwr_oe4                 - output unused, undefined\r
+       dbg                             - output alias for adc_clk\r
+*/\r
+\r
+module testbed_hi_read_tx;\r
+       reg  pck0;\r
+       reg  [7:0] adc_d;\r
+       reg  shallow_modulation;\r
+\r
+       wire pwr_lo;\r
+       wire adc_clk;\r
+       reg ck_1356meg;\r
+       reg  ck_1356megb;\r
+       wire ssp_frame;\r
+       wire ssp_din;\r
+       wire ssp_clk;\r
+       reg  ssp_dout;\r
+       wire pwr_hi;\r
+       wire pwr_oe1;\r
+       wire pwr_oe2;\r
+       wire pwr_oe3;\r
+       wire pwr_oe4;\r
+       wire cross_lo;\r
+       wire cross_hi;\r
+       wire dbg;\r
+\r
+       hi_read_tx #(5,200) dut(\r
+       .pck0(pck0),\r
+       .ck_1356meg(ck_1356meg),\r
+       .ck_1356megb(ck_1356megb),\r
+       .pwr_lo(pwr_lo),\r
+       .pwr_hi(pwr_hi),\r
+       .pwr_oe1(pwr_oe1),\r
+       .pwr_oe2(pwr_oe2),\r
+       .pwr_oe3(pwr_oe3),\r
+       .pwr_oe4(pwr_oe4),\r
+       .adc_d(adc_d),\r
+       .adc_clk(adc_clk),\r
+       .ssp_frame(ssp_frame),\r
+       .ssp_din(ssp_din),\r
+       .ssp_dout(ssp_dout),\r
+       .ssp_clk(ssp_clk),\r
+       .cross_hi(cross_hi),\r
+       .cross_lo(cross_lo),\r
+       .dbg(dbg),\r
+       .shallow_modulation(shallow_modulation)\r
+       );\r
+\r
+       integer idx, i;\r
+\r
+       // main clock\r
+       always #5 begin \r
+               ck_1356megb = !ck_1356megb;\r
+               ck_1356meg = ck_1356megb;\r
+       end\r
+\r
+       //crank DUT\r
+       task crank_dut;\r
+       begin\r
+               @(posedge ssp_clk) ;\r
+               ssp_dout = $random;\r
+       end\r
+       endtask\r
+\r
+       initial begin\r
+\r
+               // init inputs\r
+               ck_1356megb = 0;\r
+               adc_d = 0;\r
+               ssp_dout=0;\r
+\r
+               // shallow modulation off\r
+               shallow_modulation=0;\r
+               for (i = 0 ;  i < 16 ;  i = i + 1) begin\r
+                       crank_dut;\r
+               end\r
+\r
+               // shallow modulation on\r
+               shallow_modulation=1;\r
+               for (i = 0 ;  i < 16 ;  i = i + 1) begin\r
+                       crank_dut;\r
+               end\r
+               $finish;\r
+       end\r
+       \r
+endmodule // main\r
diff --git a/fpga/testbed_hi_simulate.v b/fpga/testbed_hi_simulate.v
new file mode 100644 (file)
index 0000000..6dc30f0
--- /dev/null
@@ -0,0 +1,116 @@
+`include "hi_simulate.v"\r
+\r
+/*\r
+       pck0                    - input main 24Mhz clock (PLL / 4)\r
+       [7:0] adc_d             - input data from A/D converter\r
+       mod_type        - modulation type\r
+\r
+       pwr_lo                  - output to coil drivers (ssp_clk / 8)\r
+       adc_clk                 - output A/D clock signal\r
+       ssp_frame               - output SSS frame indicator (goes high while the 8 bits are shifted)\r
+       ssp_din                 - output SSP data to ARM (shifts 8 bit A/D value serially to ARM MSB first)\r
+       ssp_clk                 - output SSP clock signal\r
+\r
+       ck_1356meg              - input unused\r
+       ck_1356megb             - input unused\r
+       ssp_dout                - input unused\r
+       cross_hi                - input unused\r
+       cross_lo                - input unused\r
+\r
+       pwr_hi                  - output unused, tied low\r
+       pwr_oe1                 - output unused, undefined\r
+       pwr_oe2                 - output unused, undefined\r
+       pwr_oe3                 - output unused, undefined\r
+       pwr_oe4                 - output unused, undefined\r
+       dbg                             - output alias for adc_clk\r
+*/\r
+\r
+module testbed_hi_simulate;\r
+       reg  pck0;\r
+       reg  [7:0] adc_d;\r
+       reg  mod_type;\r
+\r
+       wire pwr_lo;\r
+       wire adc_clk;\r
+       reg ck_1356meg;\r
+       reg  ck_1356megb;\r
+       wire ssp_frame;\r
+       wire ssp_din;\r
+       wire ssp_clk;\r
+       reg  ssp_dout;\r
+       wire pwr_hi;\r
+       wire pwr_oe1;\r
+       wire pwr_oe2;\r
+       wire pwr_oe3;\r
+       wire pwr_oe4;\r
+       wire cross_lo;\r
+       wire cross_hi;\r
+       wire dbg;\r
+\r
+       hi_simulate #(5,200) dut(\r
+       .pck0(pck0),\r
+       .ck_1356meg(ck_1356meg),\r
+       .ck_1356megb(ck_1356megb),\r
+       .pwr_lo(pwr_lo),\r
+       .pwr_hi(pwr_hi),\r
+       .pwr_oe1(pwr_oe1),\r
+       .pwr_oe2(pwr_oe2),\r
+       .pwr_oe3(pwr_oe3),\r
+       .pwr_oe4(pwr_oe4),\r
+       .adc_d(adc_d),\r
+       .adc_clk(adc_clk),\r
+       .ssp_frame(ssp_frame),\r
+       .ssp_din(ssp_din),\r
+       .ssp_dout(ssp_dout),\r
+       .ssp_clk(ssp_clk),\r
+       .cross_hi(cross_hi),\r
+       .cross_lo(cross_lo),\r
+       .dbg(dbg),\r
+       .mod_type(mod_type)\r
+       );\r
+\r
+       integer idx, i;\r
+\r
+       // main clock\r
+       always #5 begin \r
+               ck_1356megb = !ck_1356megb;\r
+               ck_1356meg = ck_1356megb;\r
+       end\r
+\r
+       always begin \r
+               @(negedge adc_clk) ;\r
+               adc_d = $random;\r
+       end\r
+\r
+       //crank DUT\r
+       task crank_dut;\r
+               begin\r
+                       @(negedge ssp_clk) ;\r
+                       ssp_dout = $random;\r
+               end\r
+       endtask\r
+\r
+       initial begin\r
+\r
+               // init inputs\r
+               ck_1356megb = 0;\r
+               // random values\r
+               adc_d = 0;\r
+               ssp_dout=1;\r
+\r
+               // shallow modulation off\r
+               mod_type=0;\r
+               for (i = 0 ;  i < 16 ;  i = i + 1) begin\r
+                       crank_dut;\r
+               end\r
+\r
+               // shallow modulation on\r
+               mod_type=1;\r
+               for (i = 0 ;  i < 16 ;  i = i + 1) begin\r
+                       crank_dut;\r
+               end\r
+               $finish;\r
+       end\r
+       \r
+endmodule // main\r
+\r
diff --git a/fpga/testbed_lo_read.v b/fpga/testbed_lo_read.v
new file mode 100644 (file)
index 0000000..11908d7
--- /dev/null
@@ -0,0 +1,105 @@
+`include "lo_read.v"\r
+\r
+/*\r
+       pck0                    - input main 24Mhz clock (PLL / 4)\r
+       [7:0] adc_d             - input data from A/D converter\r
+       lo_is_125khz    - input freq selector (1=125Khz, 0=136Khz)\r
+\r
+       pwr_lo                  - output to coil drivers (ssp_clk / 8)\r
+       adc_clk                 - output A/D clock signal\r
+       ssp_frame               - output SSS frame indicator (goes high while the 8 bits are shifted)\r
+       ssp_din                 - output SSP data to ARM (shifts 8 bit A/D value serially to ARM MSB first)\r
+       ssp_clk                 - output SSP clock signal 1Mhz/1.09Mhz (pck0 / 2*(11+lo_is_125khz) )\r
+\r
+       ck_1356meg              - input unused\r
+       ck_1356megb             - input unused\r
+       ssp_dout                - input unused\r
+       cross_hi                - input unused\r
+       cross_lo                - input unused\r
+\r
+       pwr_hi                  - output unused, tied low\r
+       pwr_oe1                 - output unused, undefined\r
+       pwr_oe2                 - output unused, undefined\r
+       pwr_oe3                 - output unused, undefined\r
+       pwr_oe4                 - output unused, undefined\r
+       dbg                             - output alias for adc_clk\r
+*/\r
+\r
+module testbed_lo_read;\r
+       reg  pck0;\r
+       reg  [7:0] adc_d;\r
+       reg  lo_is_125khz;\r
+\r
+       wire pwr_lo;\r
+       wire adc_clk;\r
+       wire ck_1356meg;\r
+       wire ck_1356megb;\r
+       wire ssp_frame;\r
+       wire ssp_din;\r
+       wire ssp_clk;\r
+       wire ssp_dout;\r
+       wire pwr_hi;\r
+       wire pwr_oe1;\r
+       wire pwr_oe2;\r
+       wire pwr_oe3;\r
+       wire pwr_oe4;\r
+       wire cross_lo;\r
+       wire cross_hi;\r
+       wire dbg;\r
+\r
+       lo_read #(5,200) dut(\r
+       .pck0(pck0),\r
+       .ck_1356meg(ck_1356meg),\r
+       .ck_1356megb(ck_1356megb),\r
+       .pwr_lo(pwr_lo),\r
+       .pwr_hi(pwr_hi),\r
+       .pwr_oe1(pwr_oe1),\r
+       .pwr_oe2(pwr_oe2),\r
+       .pwr_oe3(pwr_oe3),\r
+       .pwr_oe4(pwr_oe4),\r
+       .adc_d(adc_d),\r
+       .adc_clk(adc_clk),\r
+       .ssp_frame(ssp_frame),\r
+       .ssp_din(ssp_din),\r
+       .ssp_dout(ssp_dout),\r
+       .ssp_clk(ssp_clk),\r
+       .cross_hi(cross_hi),\r
+       .cross_lo(cross_lo),\r
+       .dbg(dbg),\r
+       .lo_is_125khz(lo_is_125khz)\r
+       );\r
+\r
+       integer idx, i;\r
+\r
+       // main clock\r
+       always #5 pck0 = !pck0;\r
+\r
+       //new A/D value available from ADC on positive edge\r
+       task crank_dut;\r
+       begin\r
+               @(posedge adc_clk) ;\r
+               adc_d = $random;\r
+       end\r
+       endtask\r
+\r
+       initial begin\r
+\r
+               // init inputs\r
+               pck0 = 0;\r
+               adc_d = 0;\r
+\r
+               // simulate 4 A/D cycles at 134Khz\r
+               lo_is_125khz=0;\r
+               for (i = 0 ;  i < 4 ;  i = i + 1) begin\r
+                       crank_dut;\r
+               end\r
+\r
+               // simulate 4 A/D cycles at 125Khz\r
+               lo_is_125khz=1;\r
+               for (i = 0 ;  i < 4 ;  i = i + 1) begin\r
+                       crank_dut;\r
+               end\r
+               $finish;\r
+       end\r
+       \r
+endmodule // main\r
diff --git a/fpga/testbed_lo_simulate.v b/fpga/testbed_lo_simulate.v
new file mode 100644 (file)
index 0000000..d30f822
--- /dev/null
@@ -0,0 +1,101 @@
+`include "lo_simulate.v"\r
+\r
+/*\r
+       pck0                    - input main 24Mhz clock (PLL / 4)\r
+       [7:0] adc_d             - input data from A/D converter\r
+\r
+\r
+       pwr_lo                  - output to coil drivers (ssp_clk / 8)\r
+       adc_clk                 - output A/D clock signal\r
+       ssp_frame               - output SSS frame indicator (goes high while the 8 bits are shifted)\r
+       ssp_din                 - output SSP data to ARM (shifts 8 bit A/D value serially to ARM MSB first)\r
+       ssp_clk                 - output SSP clock signal\r
+\r
+       ck_1356meg              - input unused\r
+       ck_1356megb             - input unused\r
+       ssp_dout                - input unused\r
+       cross_hi                - input unused\r
+       cross_lo                - input unused\r
+\r
+       pwr_hi                  - output unused, tied low\r
+       pwr_oe1                 - output unused, undefined\r
+       pwr_oe2                 - output unused, undefined\r
+       pwr_oe3                 - output unused, undefined\r
+       pwr_oe4                 - output unused, undefined\r
+       dbg                             - output alias for adc_clk\r
+*/\r
+\r
+module testbed_lo_simulate;\r
+       reg  pck0;\r
+       reg  [7:0] adc_d;\r
+\r
+\r
+       wire pwr_lo;\r
+       wire adc_clk;\r
+       wire ck_1356meg;\r
+       wire ck_1356megb;\r
+       wire ssp_frame;\r
+       wire ssp_din;\r
+       wire ssp_clk;\r
+       reg  ssp_dout;\r
+       wire pwr_hi;\r
+       wire pwr_oe1;\r
+       wire pwr_oe2;\r
+       wire pwr_oe3;\r
+       wire pwr_oe4;\r
+       reg  cross_lo;\r
+       wire cross_hi;\r
+       wire dbg;\r
+\r
+       lo_simulate #(5,200) dut(\r
+       .pck0(pck0),\r
+       .ck_1356meg(ck_1356meg),\r
+       .ck_1356megb(ck_1356megb),\r
+       .pwr_lo(pwr_lo),\r
+       .pwr_hi(pwr_hi),\r
+       .pwr_oe1(pwr_oe1),\r
+       .pwr_oe2(pwr_oe2),\r
+       .pwr_oe3(pwr_oe3),\r
+       .pwr_oe4(pwr_oe4),\r
+       .adc_d(adc_d),\r
+       .adc_clk(adc_clk),\r
+       .ssp_frame(ssp_frame),\r
+       .ssp_din(ssp_din),\r
+       .ssp_dout(ssp_dout),\r
+       .ssp_clk(ssp_clk),\r
+       .cross_hi(cross_hi),\r
+       .cross_lo(cross_lo),\r
+       .dbg(dbg)\r
+       );\r
+\r
+\r
+       integer i, counter=0;\r
+\r
+       // main clock\r
+       always #5 pck0 = !pck0;\r
+\r
+       //cross_lo is not really synced to pck0 but it's roughly pck0/192 (24Mhz/192=125Khz)\r
+       task crank_dut;\r
+       begin\r
+               @(posedge pck0) ;\r
+               counter = counter + 1;\r
+               if (counter == 192) begin\r
+                       counter = 0;\r
+                       ssp_dout = $random;\r
+                       cross_lo = 1;\r
+               end else begin\r
+                       cross_lo = 0;\r
+               end\r
+                       \r
+       end\r
+       endtask\r
+\r
+       initial begin\r
+               pck0 = 0;\r
+               for (i = 0 ;  i < 4096 ;  i = i + 1) begin\r
+                       crank_dut;\r
+               end\r
+               $finish;\r
+       end\r
+\r
+endmodule // main\r
diff --git a/fpga/util.v b/fpga/util.v
new file mode 100644 (file)
index 0000000..c500edb
--- /dev/null
@@ -0,0 +1,27 @@
+//-----------------------------------------------------------------------------\r
+// General-purpose miscellany.\r
+//\r
+// Jonathan Westhues, April 2006.\r
+//-----------------------------------------------------------------------------\r
+\r
+module mux8(sel, y, x0, x1, x2, x3, x4, x5, x6, x7);\r
+    input [2:0] sel;\r
+    input x0, x1, x2, x3, x4, x5, x6, x7;\r
+    output y;\r
+    reg y;\r
+\r
+always @(x0 or x1 or x2 or x3 or x4 or x5 or x6 or x7 or sel)\r
+begin\r
+    case (sel)\r
+        3'b000: y = x0;\r
+        3'b001: y = x1;\r
+        3'b010: y = x2;\r
+        3'b011: y = x3;\r
+        3'b100: y = x4;\r
+        3'b101: y = x5;\r
+        3'b110: y = x6;\r
+        3'b111: y = x7;\r
+    endcase\r
+end\r
+\r
+endmodule\r
diff --git a/fpga/xst.scr b/fpga/xst.scr
new file mode 100644 (file)
index 0000000..365db39
--- /dev/null
@@ -0,0 +1 @@
+run -ifn fpga.v -ifmt Verilog -ofn fpga.ngc -ofmt NGC -p xc2s30-6vq100 -opt_mode Speed -opt_level 1 -ent fpga\r
diff --git a/include/at91sam7s128.h b/include/at91sam7s128.h
new file mode 100644 (file)
index 0000000..1a5fe1c
--- /dev/null
@@ -0,0 +1,461 @@
+//-----------------------------------------------------------------------------\r
+// Incomplete register definitions for the AT91SAM7S128 chip.\r
+// Jonathan Westhues, Jul 2005\r
+//-----------------------------------------------------------------------------\r
+\r
+#ifndef __AT91SAM7S128_H\r
+#define __AT91SAM7S128_H\r
+\r
+#define REG(x) (*(volatile unsigned long *)(x))\r
+\r
+//-------------\r
+// Peripheral IDs\r
+\r
+#define PERIPH_AIC_FIQ                                                         0\r
+#define PERIPH_SYSIRQ                                                          1\r
+#define PERIPH_PIOA                                                                    2\r
+#define PERIPH_ADC                                                                     4\r
+#define PERIPH_SPI                                                                     5\r
+#define PERIPH_US0                                                                     6\r
+#define PERIPH_US1                                                                     7\r
+#define PERIPH_SSC                                                                     8\r
+#define PERIPH_TWI                                                                     9\r
+#define PERIPH_PWMC                                                                    10\r
+#define PERIPH_UDP                                                                     11\r
+#define PERIPH_TC0                                                                     12\r
+#define PERIPH_TC1                                                                     13\r
+#define PERIPH_TC2                                                                     14\r
+#define PERIPH_AIC_IRQ0                                                        30\r
+#define PERIPH_AIC_IRQ1                                                        31\r
+\r
+//-------------\r
+// Reset Controller\r
+\r
+#define RSTC_BASE                                                                      (0xfffffd00)\r
+\r
+#define RSTC_CONTROL                                                           REG(RSTC_BASE+0x00)\r
+\r
+#define RST_CONTROL_KEY                                                                (0xa5<<24)\r
+#define RST_CONTROL_PROCESSOR_RESET                                    (1<<0)\r
+\r
+//-------------\r
+// PWM Controller\r
+\r
+#define PWM_BASE                                                                       (0xfffcc000)\r
+\r
+#define PWM_MODE                                                                       REG(PWM_BASE+0x00)\r
+#define PWM_ENABLE                                                                     REG(PWM_BASE+0x04)\r
+#define PWM_DISABLE                                                                    REG(PWM_BASE+0x08)\r
+#define PWM_STATUS                                                                     REG(PWM_BASE+0x0c)\r
+#define PWM_INTERRUPT_ENABLE                                           REG(PWM_BASE+0x10)\r
+#define PWM_INTERRUPT_DISABLE                                          REG(PWM_BASE+0x14)\r
+#define PWM_INTERRUPT_MASK                                                     REG(PWM_BASE+0x18)\r
+#define PWM_INTERRUPT_STATUS                                           REG(PWM_BASE+0x1c)\r
+#define PWM_CH_MODE(x)                                                         REG(PWM_BASE+0x200+((x)*0x20))\r
+#define PWM_CH_DUTY_CYCLE(x)                                           REG(PWM_BASE+0x204+((x)*0x20))\r
+#define PWM_CH_PERIOD(x)                                                       REG(PWM_BASE+0x208+((x)*0x20))\r
+#define PWM_CH_COUNTER(x)                                                      REG(PWM_BASE+0x20c+((x)*0x20))\r
+#define PWM_CH_UPDATE(x)                                                       REG(PWM_BASE+0x210+((x)*0x20))\r
+\r
+#define PWM_MODE_DIVA(x)                                                       ((x)<<0)\r
+#define PWM_MODE_PREA(x)                                                       ((x)<<8)\r
+#define PWM_MODE_DIVB(x)                                                       ((x)<<16)\r
+#define PWM_MODE_PREB(x)                                                       ((x)<<24)\r
+\r
+#define PWM_CHANNEL(x)                                                         (1<<(x))\r
+\r
+#define PWM_CH_MODE_PRESCALER(x)                                       ((x)<<0)\r
+#define PWM_CH_MODE_PERIOD_CENTER_ALIGNED                      (1<<8)\r
+#define PWM_CH_MODE_POLARITY_STARTS_HIGH                       (1<<9)\r
+#define PWM_CH_MODE_UPDATE_UPDATES_PERIOD                      (1<<10)\r
+\r
+//-------------\r
+// Debug Unit\r
+\r
+#define DBG_BASE                                                                       (0xfffff200)\r
+\r
+#define DBGU_CR                                                                                REG(DBG_BASE+0x0000)\r
+#define DBGU_MR                                                                                REG(DBG_BASE+0x0004)\r
+#define DBGU_IER                                                                       REG(DBG_BASE+0x0008)\r
+#define DBGU_IDR                                                                       REG(DBG_BASE+0x000C)\r
+#define DBGU_IMR                                                                       REG(DBG_BASE+0x0010)\r
+#define DBGU_SR                                                                                REG(DBG_BASE+0x0014)\r
+#define DBGU_RHR                                                                       REG(DBG_BASE+0x0018)\r
+#define DBGU_THR                                                                       REG(DBG_BASE+0x001C)\r
+#define DBGU_BRGR                                                                      REG(DBG_BASE+0x0020)\r
+#define DBGU_CIDR                                                                      REG(DBG_BASE+0x0040)\r
+#define DBGU_EXID                                                                      REG(DBG_BASE+0x0044)\r
+#define DBGU_FNR                                                                       REG(DBG_BASE+0x0048)\r
+\r
+//-------------\r
+// Embedded Flash Controller\r
+\r
+#define MC_BASE                                                                        (0xffffff00)\r
+\r
+#define MC_FLASH_MODE0                                                         REG(MC_BASE+0x60)\r
+#define MC_FLASH_COMMAND                                                       REG(MC_BASE+0x64)\r
+#define MC_FLASH_STATUS                                                                REG(MC_BASE+0x68)\r
+#define MC_FLASH_MODE1                                                         REG(MC_BASE+0x70)\r
+\r
+#define MC_FLASH_MODE_READY_INTERRUPT_ENABLE           (1<<0)\r
+#define MC_FLASH_MODE_LOCK_INTERRUPT_ENABLE                    (1<<2)\r
+#define MC_FLASH_MODE_PROG_ERROR_INTERRUPT_ENABLE      (1<<3)\r
+#define MC_FLASH_MODE_NO_ERASE_BEFORE_PROGRAMMING      (1<<7)\r
+#define MC_FLASH_MODE_FLASH_WAIT_STATES(x)                     ((x)<<8)\r
+#define MC_FLASH_MODE_MASTER_CLK_IN_MHZ(x)                     ((x)<<16)\r
+\r
+#define MC_FLASH_COMMAND_FCMD(x)                                       ((x)<<0)\r
+#define MC_FLASH_COMMAND_PAGEN(x)                                      ((x)<<8)\r
+#define MC_FLASH_COMMAND_KEY                                           ((0x5a)<<24)\r
+\r
+#define FCMD_NOP                                                                       0x0\r
+#define FCMD_WRITE_PAGE                                                                0x1\r
+#define FCMD_SET_LOCK_BIT                                                      0x2\r
+#define FCMD_WRITE_PAGE_LOCK                                           0x3\r
+#define FCMD_CLEAR_LOCK_BIT                                                    0x4\r
+#define FCMD_ERASE_ALL                                                         0x8\r
+#define FCMD_SET_GP_NVM_BIT                                                    0xb\r
+#define FCMD_SET_SECURITY_BIT                                          0xf\r
+\r
+#define MC_FLASH_STATUS_READY                                          (1<<0)\r
+#define MC_FLASH_STATUS_LOCK_ERROR                                     (1<<2)\r
+#define MC_FLASH_STATUS_PROGRAMMING_ERROR                      (1<<3)\r
+#define MC_FLASH_STATUS_SECURITY_BIT_ACTIVE                    (1<<4)\r
+#define MC_FLASH_STATUS_GP_NVM_ACTIVE_0                                (1<<8)\r
+#define MC_FLASH_STATUS_GP_NVM_ACTIVE_1                                (1<<9)\r
+#define MC_FLASH_STATUS_LOCK_ACTIVE(x)                         (1<<((x)+16))\r
+\r
+#define FLASH_PAGE_SIZE_BYTES                                          256\r
+#define FLASH_PAGE_COUNT                                                       512\r
+\r
+//-------------\r
+// Watchdog Timer - 12 bit down counter, uses slow clock divided by 128 as source\r
+\r
+#define WDT_BASE                                                                       (0xfffffd40)\r
+\r
+#define WDT_CONTROL                                                                    REG(WDT_BASE+0x00)\r
+#define WDT_MODE                                                                       REG(WDT_BASE+0x04)\r
+#define WDT_STATUS                                                                     REG(WDT_BASE+0x08)\r
+\r
+#define WDT_HIT()                                                                      WDT_CONTROL = 0xa5000001\r
+\r
+#define WDT_MODE_COUNT(x)                                                      ((x)<<0)\r
+#define WDT_MODE_INTERRUPT_ON_EVENT                                    (1<<12)\r
+#define WDT_MODE_RESET_ON_EVENT_ENABLE                         (1<<13)\r
+#define WDT_MODE_RESET_ON_EVENT                                                (1<<14)\r
+#define WDT_MODE_WATCHDOG_DELTA(x)                                     ((x)<<16)\r
+#define WDT_MODE_HALT_IN_DEBUG_MODE                                    (1<<28)\r
+#define WDT_MODE_HALT_IN_IDLE_MODE                                     (1<<29)\r
+#define WDT_MODE_DISABLE                                                       (1<<15)\r
+\r
+//-------------\r
+// Parallel Input/Output Controller\r
+\r
+#define PIO_BASE                                                                       (0xfffff400)\r
+\r
+#define PIO_ENABLE                                                                     REG(PIO_BASE+0x000)\r
+#define PIO_DISABLE                                                                    REG(PIO_BASE+0x004)\r
+#define PIO_STATUS                                                                     REG(PIO_BASE+0x008)\r
+#define PIO_OUTPUT_ENABLE                                                      REG(PIO_BASE+0x010)\r
+#define PIO_OUTPUT_DISABLE                                                     REG(PIO_BASE+0x014)\r
+#define PIO_OUTPUT_STATUS                                                      REG(PIO_BASE+0x018)\r
+#define PIO_GLITCH_ENABLE                                                      REG(PIO_BASE+0x020)\r
+#define PIO_GLITCH_DISABLE                                                     REG(PIO_BASE+0x024)\r
+#define PIO_GLITCH_STATUS                                                      REG(PIO_BASE+0x028)\r
+#define PIO_OUTPUT_DATA_SET                                                    REG(PIO_BASE+0x030)\r
+#define PIO_OUTPUT_DATA_CLEAR                                          REG(PIO_BASE+0x034)\r
+#define PIO_OUTPUT_DATA_STATUS                                         REG(PIO_BASE+0x038)\r
+#define PIO_PIN_DATA_STATUS                                                    REG(PIO_BASE+0x03c)\r
+#define PIO_OPEN_DRAIN_ENABLE                                          REG(PIO_BASE+0x050)\r
+#define PIO_OPEN_DRAIN_DISABLE                                         REG(PIO_BASE+0x054)\r
+#define PIO_OPEN_DRAIN_STATUS                                          REG(PIO_BASE+0x058)\r
+#define PIO_NO_PULL_UP_ENABLE                                          REG(PIO_BASE+0x060)\r
+#define PIO_NO_PULL_UP_DISABLE                                         REG(PIO_BASE+0x064)\r
+#define PIO_NO_PULL_UP_STATUS                                          REG(PIO_BASE+0x068)\r
+#define PIO_PERIPHERAL_A_SEL                                           REG(PIO_BASE+0x070)\r
+#define PIO_PERIPHERAL_B_SEL                                           REG(PIO_BASE+0x074)\r
+#define PIO_PERIPHERAL_WHICH                                           REG(PIO_BASE+0x078)\r
+#define PIO_OUT_WRITE_ENABLE                                           REG(PIO_BASE+0x0a0)\r
+#define PIO_OUT_WRITE_DISABLE                                          REG(PIO_BASE+0x0a4)\r
+#define PIO_OUT_WRITE_STATUS                                           REG(PIO_BASE+0x0a8)\r
+\r
+//-------------\r
+// USB Device Port\r
+\r
+#define UDP_BASE                                                                       (0xfffb0000)\r
+\r
+#define UDP_FRAME_NUMBER                                                       REG(UDP_BASE+0x0000)\r
+#define UDP_GLOBAL_STATE                                                       REG(UDP_BASE+0x0004)\r
+#define UDP_FUNCTION_ADDR                                                      REG(UDP_BASE+0x0008)\r
+#define UDP_INTERRUPT_ENABLE                                           REG(UDP_BASE+0x0010)\r
+#define UDP_INTERRUPT_DISABLE                                          REG(UDP_BASE+0x0014)\r
+#define UDP_INTERRUPT_MASK                                                     REG(UDP_BASE+0x0018)\r
+#define UDP_INTERRUPT_STATUS                                           REG(UDP_BASE+0x001c)\r
+#define UDP_INTERRUPT_CLEAR                                                    REG(UDP_BASE+0x0020)\r
+#define UDP_RESET_ENDPOINT                                                     REG(UDP_BASE+0x0028)\r
+#define UDP_ENDPOINT_CSR(x)                                                    REG(UDP_BASE+0x0030+((x)*4))\r
+#define UDP_ENDPOINT_FIFO(x)                                           REG(UDP_BASE+0x0050+((x)*4))\r
+#define UDP_TRANSCEIVER_CTRL                                           REG(UDP_BASE+0x0074)\r
+\r
+#define UDP_GLOBAL_STATE_ADDRESSED                                     (1<<0)\r
+#define UDP_GLOBAL_STATE_CONFIGURED                                    (1<<1)\r
+#define UDP_GLOBAL_STATE_SEND_RESUME_ENABLED           (1<<2)\r
+#define UDP_GLOBAL_STATE_RESUME_RECEIVED                       (1<<3)\r
+#define UDP_GLOBAL_STATE_REMOTE_WAKE_UP_ENABLED        (1<<4)\r
+\r
+#define UDP_FUNCTION_ADDR_ENABLED                                      (1<<8)\r
+\r
+#define UDP_INTERRUPT_ENDPOINT(x)                                      (1<<(x))\r
+#define UDP_INTERRUPT_SUSPEND                                          (1<<8)\r
+#define UDP_INTERRUPT_RESUME                                           (1<<9)\r
+#define UDP_INTERRUPT_EXTERNAL_RESUME                          (1<<10)\r
+#define UDP_INTERRUPT_SOF                                                      (1<<11)\r
+#define UDP_INTERRUPT_END_OF_BUS_RESET                         (1<<12)\r
+#define UDP_INTERRUPT_WAKEUP                                           (1<<13)\r
+\r
+#define UDP_RESET_ENDPOINT_NUMBER(x)                           (1<<(x))\r
+\r
+#define UDP_CSR_TX_PACKET_ACKED                                                (1<<0)\r
+#define UDP_CSR_RX_PACKET_RECEIVED_BANK_0                      (1<<1)\r
+#define UDP_CSR_RX_HAVE_READ_SETUP_DATA                                (1<<2)\r
+#define UDP_CSR_STALL_SENT                                                     (1<<3)\r
+#define UDP_CSR_TX_PACKET                                                      (1<<4)\r
+#define UDP_CSR_FORCE_STALL                                                    (1<<5)\r
+#define UDP_CSR_RX_PACKET_RECEIVED_BANK_1                      (1<<6)\r
+#define UDP_CSR_CONTROL_DATA_DIR                                       (1<<7)\r
+#define UDP_CSR_EPTYPE_CONTROL                                         (0<<8)\r
+#define UDP_CSR_EPTYPE_ISOCHRON_OUT                                    (1<<8)\r
+#define UDP_CSR_EPTYPE_ISOCHRON_IN                                     (5<<8)\r
+#define UDP_CSR_EPTYPE_BULK_OUT                                                (2<<8)\r
+#define UDP_CSR_EPTYPE_BULK_IN                                         (6<<8)\r
+#define UDP_CSR_EPTYPE_INTERRUPT_OUT                           (3<<8)\r
+#define UDP_CSR_EPTYPE_INTERRUPT_IN                                    (7<<8)\r
+#define UDP_CSR_IS_DATA1                                                       (1<<11)\r
+#define UDP_CSR_ENABLE_EP                                                      (1<<15)\r
+#define UDP_CSR_BYTES_RECEIVED(x)                                      (((x) >> 16) & 0x7ff)\r
+\r
+#define UDP_TRANSCEIVER_CTRL_DISABLE                           (1<<8)\r
+\r
+//-------------\r
+// Power Management Controller\r
+\r
+#define PMC_BASE                                                                       (0xfffffc00)\r
+\r
+#define PMC_SYS_CLK_ENABLE                                                     REG(PMC_BASE+0x0000)\r
+#define PMC_SYS_CLK_DISABLE                                                    REG(PMC_BASE+0x0004)\r
+#define PMC_SYS_CLK_STATUS                                                     REG(PMC_BASE+0x0008)\r
+#define PMC_PERIPHERAL_CLK_ENABLE                                      REG(PMC_BASE+0x0010)\r
+#define PMC_PERIPHERAL_CLK_DISABLE                                     REG(PMC_BASE+0x0014)\r
+#define PMC_PERIPHERAL_CLK_STATUS                                      REG(PMC_BASE+0x0018)\r
+#define PMC_MAIN_OSCILLATOR                                                    REG(PMC_BASE+0x0020)\r
+#define PMC_MAIN_CLK_FREQUENCY                                         REG(PMC_BASE+0x0024)\r
+#define PMC_PLL                                                                                REG(PMC_BASE+0x002c)\r
+#define PMC_MASTER_CLK                                                         REG(PMC_BASE+0x0030)\r
+#define PMC_PROGRAMMABLE_CLK_0                                         REG(PMC_BASE+0x0040)\r
+#define PMC_PROGRAMMABLE_CLK_1                                         REG(PMC_BASE+0x0044)\r
+#define PMC_INTERRUPT_ENABLE                                           REG(PMC_BASE+0x0060)\r
+#define PMC_INTERRUPT_DISABLE                                          REG(PMC_BASE+0x0064)\r
+#define PMC_INTERRUPT_STATUS                                           REG(PMC_BASE+0x0068)\r
+#define PMC_INTERRUPT_MASK                                                     REG(PMC_BASE+0x006c)\r
+\r
+#define PMC_SYS_CLK_PROCESSOR_CLK                                      (1<<0)\r
+#define PMC_SYS_CLK_UDP_CLK                                                    (1<<7)\r
+#define PMC_SYS_CLK_PROGRAMMABLE_CLK_0                         (1<<8)\r
+#define PMC_SYS_CLK_PROGRAMMABLE_CLK_1                         (1<<9)\r
+#define PMC_SYS_CLK_PROGRAMMABLE_CLK_2                         (1<<10)\r
+\r
+#define PMC_MAIN_OSCILLATOR_STABILIZED                         (1<<0)\r
+#define PMC_MAIN_OSCILLATOR_PLL_LOCK                           (1<<2)\r
+#define PMC_MAIN_OSCILLATOR_MCK_READY                          (1<<3)\r
+#define PMC_MAIN_OSCILLATOR_ENABLE                                     (1<<0)\r
+#define PMC_MAIN_OSCILLATOR_BYPASS                                     (1<<1)\r
+#define PMC_MAIN_OSCILLATOR_STARTUP_DELAY(x)           ((x)<<8)\r
+\r
+#define PMC_PLL_DIVISOR(x)                                                     (x)\r
+#define PMC_PLL_COUNT_BEFORE_LOCK(x)                           ((x)<<8)\r
+#define PMC_PLL_FREQUENCY_RANGE(x)                                     ((x)<<14)\r
+#define PMC_PLL_MULTIPLIER(x)                                          (((x)-1)<<16)\r
+#define PMC_PLL_USB_DIVISOR(x)                                         ((x)<<28)\r
+\r
+#define PMC_CLK_SELECTION_PLL_CLOCK                                    (3<<0)\r
+#define PMC_CLK_SELECTION_MAIN_CLOCK                           (1<<0)\r
+#define PMC_CLK_SELECTION_SLOW_CLOCK                           (0<<0)\r
+#define PMC_CLK_PRESCALE_DIV_1                                         (0<<2)\r
+#define PMC_CLK_PRESCALE_DIV_2                                         (1<<2)\r
+#define PMC_CLK_PRESCALE_DIV_4                                         (2<<2)\r
+#define PMC_CLK_PRESCALE_DIV_8                                         (3<<2)\r
+#define PMC_CLK_PRESCALE_DIV_16                                                (4<<2)\r
+#define PMC_CLK_PRESCALE_DIV_32                                                (5<<2)\r
+#define PMC_CLK_PRESCALE_DIV_64                                                (6<<2)\r
+\r
+//-------------\r
+// Serial Peripheral Interface (SPI)\r
+\r
+#define SPI_BASE                                                                       (0xfffe0000)\r
+\r
+#define SPI_CONTROL                                                                    REG(SPI_BASE+0x00)\r
+#define SPI_MODE                                                                       REG(SPI_BASE+0x04)\r
+#define SPI_RX_DATA                                                                    REG(SPI_BASE+0x08)\r
+#define SPI_TX_DATA                                                                    REG(SPI_BASE+0x0c)\r
+#define SPI_STATUS                                                                     REG(SPI_BASE+0x10)\r
+#define SPI_INTERRUPT_ENABLE                                           REG(SPI_BASE+0x14)\r
+#define SPI_INTERRUPT_DISABLE                                          REG(SPI_BASE+0x18)\r
+#define SPI_INTERRUPT_MASK                                                     REG(SPI_BASE+0x1c)\r
+#define SPI_FOR_CHIPSEL_0                                                      REG(SPI_BASE+0x30)\r
+#define SPI_FOR_CHIPSEL_1                                                      REG(SPI_BASE+0x34)\r
+#define SPI_FOR_CHIPSEL_2                                                      REG(SPI_BASE+0x38)\r
+#define SPI_FOR_CHIPSEL_3                                                      REG(SPI_BASE+0x3c)\r
+\r
+#define SPI_CONTROL_ENABLE                                                     (1<<0)\r
+#define SPI_CONTROL_DISABLE                                                    (1<<1)\r
+#define SPI_CONTROL_RESET                                                      (1<<7)\r
+#define SPI_CONTROL_LAST_TRANSFER                                      (1<<24)\r
+\r
+#define SPI_MODE_MASTER                                                                (1<<0)\r
+#define SPI_MODE_VARIABLE_CHIPSEL                                      (1<<1)\r
+#define SPI_MODE_CHIPSELS_DECODED                                      (1<<2)\r
+#define SPI_MODE_USE_DIVIDED_CLOCK                                     (1<<3)\r
+#define SPI_MODE_MODE_FAULT_DETECTION_OFF                      (1<<4)\r
+#define SPI_MODE_LOOPBACK                                                      (1<<7)\r
+#define SPI_MODE_CHIPSEL(x)                                                    ((x)<<16)\r
+#define SPI_MODE_DELAY_BETWEEN_CHIPSELS(x)                     ((x)<<24)\r
+\r
+#define SPI_RX_DATA_CHIPSEL(x)                                         (((x)>>16)&0xf)\r
+\r
+#define SPI_TX_DATA_CHIPSEL(x)                                         ((x)<<16)\r
+#define SPI_TX_DATA_LAST_TRANSFER                                      (1<<24)\r
+\r
+#define SPI_STATUS_RECEIVE_FULL                                                (1<<0)\r
+#define SPI_STATUS_TRANSMIT_EMPTY                                      (1<<1)\r
+#define SPI_STATUS_MODE_FAULT                                          (1<<2)\r
+#define SPI_STATUS_OVERRUN                                                     (1<<3)\r
+#define SPI_STATUS_END_OF_RX_BUFFER                                    (1<<4)\r
+#define SPI_STATUS_END_OF_TX_BUFFER                                    (1<<5)\r
+#define SPI_STATUS_RX_BUFFER_FULL                                      (1<<6)\r
+#define SPI_STATUS_TX_BUFFER_EMPTY                                     (1<<7)\r
+#define SPI_STATUS_NSS_RISING_DETECTED                         (1<<8)\r
+#define SPI_STATUS_TX_EMPTY                                                    (1<<9)\r
+#define SPI_STATUS_SPI_ENABLED                                         (1<<16)\r
+\r
+#define SPI_FOR_CHIPSEL_INACTIVE_CLK_1                         (1<<0)\r
+#define SPI_FOR_CHIPSEL_PHASE                                          (1<<1)\r
+#define SPI_FOR_CHIPSEL_LEAVE_CHIPSEL_LOW                      (1<<3)\r
+#define SPI_FOR_CHIPSEL_BITS_IN_WORD(x)                                ((x)<<4)\r
+#define SPI_FOR_CHIPSEL_DIVISOR(x)                                     ((x)<<8)\r
+#define SPI_FOR_CHIPSEL_DELAY_BEFORE_CLK(x)            ((x)<<16)\r
+#define SPI_FOR_CHIPSEL_INTERWORD_DELAY(x)                     ((x)<<24)\r
+\r
+//-------------\r
+// Analog to Digital Converter\r
+\r
+#define ADC_BASE               (0xfffd8000)\r
+\r
+#define ADC_CONTROL                                                                    REG(ADC_BASE+0x00)\r
+#define ADC_MODE                                                                       REG(ADC_BASE+0x04)\r
+#define ADC_CHANNEL_ENABLE                                                     REG(ADC_BASE+0x10)\r
+#define ADC_CHANNEL_DISABLE                                                    REG(ADC_BASE+0x14)\r
+#define ADC_CHANNEL_STATUS                                                     REG(ADC_BASE+0x18)\r
+#define ADC_STATUS                                                                     REG(ADC_BASE+0x1c)\r
+#define ADC_LAST_CONVERTED_DATA                                                REG(ADC_BASE+0x20)\r
+#define ADC_INTERRUPT_ENABLE                                           REG(ADC_BASE+0x24)\r
+#define ADC_INTERRUPT_DISABLE                                          REG(ADC_BASE+0x28)\r
+#define ADC_INTERRUPT_MASK                                                     REG(ADC_BASE+0x2c)\r
+#define ADC_CHANNEL_DATA(x)                                                    REG(ADC_BASE+0x30+(4*(x)))\r
+\r
+#define ADC_CONTROL_RESET                                                      (1<<0)\r
+#define ADC_CONTROL_START                                                      (1<<1)\r
+\r
+#define ADC_MODE_HW_TRIGGERS_ENABLED                           (1<<0)\r
+#define ADC_MODE_8_BIT_RESOLUTION                                      (1<<4)\r
+#define ADC_MODE_SLEEP                                                         (1<<5)\r
+#define ADC_MODE_PRESCALE(x)                                           ((x)<<8)\r
+#define ADC_MODE_STARTUP_TIME(x)                                       ((x)<<16)\r
+#define ADC_MODE_SAMPLE_HOLD_TIME(x)                           ((x)<<24)\r
+\r
+#define ADC_CHANNEL(x)                                                         (1<<(x))\r
+\r
+#define ADC_END_OF_CONVERSION(x)                                       (1<<(x))\r
+#define ADC_OVERRUN_ERROR(x)                                           (1<<(8+(x)))\r
+#define ADC_DATA_READY                                                         (1<<16)\r
+#define ADC_GENERAL_OVERRUN                                                    (1<<17)\r
+#define ADC_END_OF_RX_BUFFER                                           (1<<18)\r
+#define ADC_RX_BUFFER_FULL                                                     (1<<19)\r
+\r
+//-------------\r
+// Synchronous Serial Controller\r
+\r
+#define SSC_BASE                                                                       (0xfffd4000)\r
+\r
+#define SSC_CONTROL                                                                    REG(SSC_BASE+0x00)\r
+#define SSC_CLOCK_DIVISOR                                                      REG(SSC_BASE+0x04)\r
+#define SSC_RECEIVE_CLOCK_MODE                                         REG(SSC_BASE+0x10)\r
+#define SSC_RECEIVE_FRAME_MODE                                         REG(SSC_BASE+0x14)\r
+#define SSC_TRANSMIT_CLOCK_MODE                                                REG(SSC_BASE+0x18)\r
+#define SSC_TRANSMIT_FRAME_MODE                                                REG(SSC_BASE+0x1c)\r
+#define SSC_RECEIVE_HOLDING                                                    REG(SSC_BASE+0x20)\r
+#define SSC_TRANSMIT_HOLDING                                           REG(SSC_BASE+0x24)\r
+#define SSC_RECEIVE_SYNC_HOLDING                                       REG(SSC_BASE+0x30)\r
+#define SSC_TRANSMIT_SYNC_HOLDING                                      REG(SSC_BASE+0x34)\r
+#define SSC_STATUS                                                                     REG(SSC_BASE+0x40)\r
+#define SSC_INTERRUPT_ENABLE                                           REG(SSC_BASE+0x44)\r
+#define SSC_INTERRUPT_DISABLE                                          REG(SSC_BASE+0x48)\r
+#define SSC_INTERRUPT_MASK                                                     REG(SSC_BASE+0x4c)\r
+\r
+#define SSC_CONTROL_RX_ENABLE                                          (1<<0)\r
+#define SSC_CONTROL_RX_DISABLE                                         (1<<1)\r
+#define SSC_CONTROL_TX_ENABLE                                          (1<<8)\r
+#define SSC_CONTROL_TX_DISABLE                                         (1<<9)\r
+#define SSC_CONTROL_RESET                                                      (1<<15)\r
+\r
+#define SSC_CLOCK_MODE_SELECT(x)                                       ((x)<<0)\r
+#define SSC_CLOCK_MODE_OUTPUT(x)                                       ((x)<<2)\r
+#define SSC_CLOCK_MODE_INVERT                                          (1<<5)\r
+#define SSC_CLOCK_MODE_START(x)                                                ((x)<<8)\r
+#define SSC_CLOCK_MODE_START_DELAY(x)                          ((x)<<16)\r
+#define SSC_CLOCK_MODE_FRAME_PERIOD(x)                         ((x)<<24)\r
+\r
+#define SSC_FRAME_MODE_BITS_IN_WORD(x)                         (((x)-1)<<0)\r
+#define SSC_FRAME_MODE_LOOPBACK                                                (1<<5) // for RX\r
+#define SSC_FRAME_MODE_DEFAULT_IS_1                                    (1<<5) // for TX\r
+#define SSC_FRAME_MODE_MSB_FIRST                                       (1<<7)\r
+#define SSC_FRAME_MODE_WORDS_PER_TRANSFER(x)           ((x)<<8)\r
+#define SSC_FRAME_MODE_FRAME_SYNC_LEN(x)                       ((x)<<16)\r
+#define SSC_FRAME_MODE_FRAME_SYNC_TYPE(x)                      ((x)<<20)\r
+#define SSC_FRAME_MODE_SYNC_DATA_ENABLE                                (1<<23) // for TX only\r
+#define SSC_FRAME_MODE_NEGATIVE_EDGE                           (1<<24)\r
+\r
+#define SSC_STATUS_TX_READY                                                    (1<<0)\r
+#define SSC_STATUS_TX_EMPTY                                                    (1<<1)\r
+#define SSC_STATUS_TX_ENDED                                                    (1<<2)\r
+#define SSC_STATUS_TX_BUF_EMPTY                                                (1<<3)\r
+#define SSC_STATUS_RX_READY                                                    (1<<4)\r
+#define SSC_STATUS_RX_OVERRUN                                          (1<<5)\r
+#define SSC_STATUS_RX_ENDED                                                    (1<<6)\r
+#define SSC_STATUS_RX_BUF_FULL                                         (1<<7)\r
+#define SSC_STATUS_TX_SYNC_OCCURRED                                    (1<<10)\r
+#define SSC_STATUS_RX_SYNC_OCCURRED                                    (1<<11)\r
+#define SSC_STATUS_TX_ENABLED                                          (1<<16)\r
+#define SSC_STATUS_RX_ENABLED                                          (1<<17)\r
+\r
+//-------------\r
+// Peripheral DMA Controller\r
+//\r
+// There is one set of registers for every peripheral that supports DMA.\r
+\r
+#define PDC_RX_POINTER(x)                                                      REG((x)+0x100)\r
+#define PDC_RX_COUNTER(x)                                                      REG((x)+0x104)\r
+#define PDC_TX_POINTER(x)                                                      REG((x)+0x108)\r
+#define PDC_TX_COUNTER(x)                                                      REG((x)+0x10c)\r
+#define PDC_RX_NEXT_POINTER(x)                                         REG((x)+0x110)\r
+#define PDC_RX_NEXT_COUNTER(x)                                         REG((x)+0x114)\r
+#define PDC_TX_NEXT_POINTER(x)                                         REG((x)+0x118)\r
+#define PDC_TX_NEXT_COUNTER(x)                                         REG((x)+0x11c)\r
+#define PDC_CONTROL(x)                                                         REG((x)+0x120)\r
+#define PDC_STATUS(x)                                                          REG((x)+0x124)\r
+\r
+#define PDC_RX_ENABLE                                                          (1<<0)\r
+#define PDC_RX_DISABLE                                                         (1<<1)\r
+#define PDC_TX_ENABLE                                                          (1<<8)\r
+#define PDC_TX_DISABLE                                                         (1<<9)\r
+\r
+#endif\r
diff --git a/include/config_gpio.h b/include/config_gpio.h
new file mode 100644 (file)
index 0000000..1a189a9
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef __CONFIG_GPIO_H\r
+#define __CONFIG_GPIO_H\r
+\r
+#define GPIO_LED_A                     0\r
+#define GPIO_PA1                       1\r
+#define GPIO_LED_D                     2\r
+#define GPIO_NVDD_ON           3\r
+#define GPIO_FPGA_NINIT                4\r
+#define GPIO_PA5                       5\r
+#define GPIO_PCK0                      6\r
+#define GPIO_LRST                      7\r
+#define GPIO_LED_B                     8\r
+#define GPIO_LED_C                     9\r
+#define GPIO_NCS2                      10\r
+#define GPIO_NCS0                      11\r
+#define GPIO_MISO                      12\r
+#define GPIO_MOSI                      13\r
+#define GPIO_SPCK                      14\r
+#define GPIO_SSC_FRAME         15\r
+#define GPIO_SSC_CLK           16\r
+#define GPIO_SSC_DOUT          17\r
+#define GPIO_SSC_DIN           18\r
+#define GPIO_MUXSEL_HIPKD      19\r
+#define GPIO_MUXSEL_LOPKD      20\r
+#define GPIO_MUXSEL_HIRAW      21\r
+#define GPIO_MUXSEL_LORAW      22\r
+#define GPIO_BUTTON                    23\r
+#define GPIO_USB_PU                    24\r
+#define GPIO_RELAY                     25\r
+#define GPIO_FPGA_ON           26\r
+#define GPIO_FPGA_DONE         27\r
+#define GPIO_FPGA_NPROGRAM     28\r
+#define GPIO_FPGA_CCLK         29\r
+#define GPIO_FPGA_DIN          30\r
+#define GPIO_FPGA_DOUT         31\r
+\r
+#define ANIN_AMPL_LO           4\r
+#define ANIN_AMPL_HI           5\r
+\r
+#endif\r
diff --git a/include/proxmark3.h b/include/proxmark3.h
new file mode 100644 (file)
index 0000000..a94435e
--- /dev/null
@@ -0,0 +1,62 @@
+//-----------------------------------------------------------------------------\r
+// Definitions of interest to most of the software for this project.\r
+// Jonathan Westhues, Mar 2006\r
+//-----------------------------------------------------------------------------\r
+\r
+#ifndef __PROXMARK3_H\r
+#define __PROXMARK3_H\r
+\r
+// Might as well have the hardware-specific defines everywhere.\r
+#include <at91sam7s128.h>\r
+\r
+#include <config_gpio.h>\r
+#define LOW(x) PIO_OUTPUT_DATA_CLEAR = (1 << (x))\r
+#define HIGH(x)        PIO_OUTPUT_DATA_SET = (1 << (x))\r
+\r
+#define SPI_FPGA_MODE  0\r
+#define SPI_LCD_MODE   1\r
+\r
+typedef unsigned long DWORD;\r
+typedef signed long SDWORD;\r
+typedef unsigned long long QWORD;\r
+typedef int BOOL;\r
+typedef unsigned char BYTE;\r
+typedef signed char SBYTE;\r
+typedef unsigned short WORD;\r
+typedef signed short SWORD;\r
+#define TRUE 1\r
+#define FALSE 0\r
+\r
+#include <usb_cmd.h>\r
+\r
+#define PACKED __attribute__((__packed__))\r
+\r
+#define USB_D_PLUS_PULLUP_ON() { \\r
+               PIO_OUTPUT_DATA_SET = (1<<GPIO_USB_PU); \\r
+               PIO_OUTPUT_ENABLE = (1<<GPIO_USB_PU); \\r
+       }\r
+#define USB_D_PLUS_PULLUP_OFF() PIO_OUTPUT_DISABLE = (1<<GPIO_USB_PU)\r
+\r
+#define LED_A_ON()             PIO_OUTPUT_DATA_SET = (1<<GPIO_LED_A)\r
+#define LED_A_OFF()            PIO_OUTPUT_DATA_CLEAR = (1<<GPIO_LED_A)\r
+#define LED_B_ON()             PIO_OUTPUT_DATA_SET = (1<<GPIO_LED_B)\r
+#define LED_B_OFF()            PIO_OUTPUT_DATA_CLEAR = (1<<GPIO_LED_B)\r
+#define LED_C_ON()             PIO_OUTPUT_DATA_SET = (1<<GPIO_LED_C)\r
+#define LED_C_OFF()            PIO_OUTPUT_DATA_CLEAR = (1<<GPIO_LED_C)\r
+#define LED_D_ON()             PIO_OUTPUT_DATA_SET = (1<<GPIO_LED_D)\r
+#define LED_D_OFF()            PIO_OUTPUT_DATA_CLEAR = (1<<GPIO_LED_D)\r
+#define RELAY_ON()             PIO_OUTPUT_DATA_SET = (1<<GPIO_RELAY)\r
+#define RELAY_OFF()            PIO_OUTPUT_DATA_CLEAR = (1<<GPIO_RELAY)\r
+#define BUTTON_PRESS() !(PIO_PIN_DATA_STATUS & (1<<GPIO_BUTTON))\r
+//--------------------------------\r
+// USB declarations\r
+\r
+void UsbSendPacket(BYTE *packet, int len);\r
+BOOL UsbPoll(BOOL blinkLeds);\r
+void UsbStart(void);\r
+\r
+// This function is provided by the apps/bootrom, and called from UsbPoll\r
+// if data are available.\r
+void UsbPacketReceived(BYTE *packet, int len);\r
+\r
+#endif\r
diff --git a/include/usb_cmd.h b/include/usb_cmd.h
new file mode 100644 (file)
index 0000000..6f3c03d
--- /dev/null
@@ -0,0 +1,71 @@
+//-----------------------------------------------------------------------------\r
+// Definitions for all the types of commands that may be sent over USB; our\r
+// own protocol.\r
+// Jonathan Westhues, Mar 2006\r
+// Edits by Gerhard de Koning Gans, Sep 2007\r
+//-----------------------------------------------------------------------------\r
+\r
+#ifndef __USB_CMD_H\r
+#define __USB_CMD_H\r
+\r
+typedef struct {\r
+       DWORD   cmd;\r
+       DWORD   ext1;\r
+       DWORD   ext2;\r
+       DWORD   ext3;\r
+       union {\r
+               BYTE    asBytes[48];\r
+               DWORD   asDwords[12];\r
+       } d;\r
+} UsbCommand;\r
+\r
+// For the bootloader\r
+#define CMD_DEVICE_INFO                                                                0x0000\r
+#define CMD_SETUP_WRITE                                                                0x0001\r
+#define CMD_FINISH_WRITE                                                       0x0003\r
+#define CMD_HARDWARE_RESET                                                     0x0004\r
+#define CMD_ACK                                                                                0x00ff\r
+\r
+// For general mucking around\r
+#define CMD_DEBUG_PRINT_STRING                                         0x0100\r
+#define CMD_DEBUG_PRINT_INTEGERS                                       0x0101\r
+#define CMD_DEBUG_PRINT_BYTES                                          0x0102\r
+#define CMD_LCD_RESET                                                          0x0103\r
+#define CMD_LCD                                                                                0x0104\r
+\r
+// For low-frequency tags\r
+#define CMD_ACQUIRE_RAW_BITS_TI_TYPE                           0x0200\r
+#define CMD_DOWNLOAD_RAW_BITS_TI_TYPE                          0x0201\r
+#define CMD_DOWNLOADED_RAW_BITS_TI_TYPE                                0x0202\r
+#define CMD_ACQUIRE_RAW_ADC_SAMPLES_125K                       0x0203\r
+#define CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K                      0x0204\r
+#define CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K                    0x0205\r
+#define CMD_DOWNLOADED_SIM_SAMPLES_125K                                0x0206\r
+#define CMD_SIMULATE_TAG_125K                                          0x0207\r
+#define CMD_HID_DEMOD_FSK                                                      0x0208  // ## New command: demodulate HID tag ID\r
+#define CMD_HID_SIM_TAG                                                                0x0209  // ## New command: simulate HID tag by ID\r
+\r
+// For the 13.56 MHz tags\r
+#define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693          0x0300\r
+#define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443          0x0301\r
+#define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443_SIM      0x0302\r
+#define CMD_READER_ISO_15693                                           0x0310  // ## New command to act like a 15693 reader - greg\r
+#define CMD_SIMTAG_ISO_15693                                           0x0311  // ## New command to act like a 15693 reader - greg\r
+\r
+#define CMD_SIMULATE_TAG_HF_LISTEN                                     0x0380\r
+#define CMD_SIMULATE_TAG_ISO_14443                                     0x0381\r
+#define CMD_SNOOP_ISO_14443                                                    0x0382\r
+#define CMD_SNOOP_ISO_14443a                                           0x0383  // ## New snoop command\r
+#define CMD_SIMULATE_TAG_ISO_14443a                                    0x0384  // ## New command: Simulate tag 14443a\r
+#define CMD_READER_ISO_14443a                                          0x0385  // ## New command to act like a 14443a reader\r
+\r
+#define CMD_SIMULATE_MIFARE_CARD                                       0x0386\r
+\r
+// For measurements of the antenna tuning\r
+#define CMD_MEASURE_ANTENNA_TUNING                                     0x0400\r
+#define CMD_MEASURED_ANTENNA_TUNING                                    0x0401\r
+\r
+// For direct FPGA control\r
+#define CMD_FPGA_MAJOR_MODE_OFF                                                0x0500  // ## FPGA Control\r
+\r
+#endif\r
diff --git a/linux/Makefile b/linux/Makefile
new file mode 100644 (file)
index 0000000..7d4b015
--- /dev/null
@@ -0,0 +1,29 @@
+LDFLAGS = -lusb -lreadline -lpthread -L/opt/local/lib
+CFLAGS = -I. -I/opt/local/include -Wall
+
+CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall
+QTLDFLAGS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null)
+
+ifneq ($(QTLDFLAGS),)
+QTGUI = proxgui.o proxguiqt.o proxguiqt.moc.o
+CFLAGS += -DHAVE_GUI
+MOC = $(shell type moc-qt4 >/dev/null 2>&1 && echo moc-qt4 || echo moc)
+LINK.o = $(LINK.cpp)
+else
+QTGUI = guidummy.o
+endif
+
+all: proxmark3 snooper
+
+proxmark3: LDFLAGS+=$(QTLDFLAGS)
+proxmark3: proxmark3.o gui.o command.o usb.o $(QTGUI)
+
+snooper: snooper.o gui.o command.o usb.o guidummy.o
+
+proxguiqt.moc.cpp: proxguiqt.h
+       $(MOC) -o$@ $^
+
+clean:
+       rm -f proxmark3 snooper *.o *.moc.cpp
+
+.PHONY: all clean
diff --git a/linux/command.c b/linux/command.c
new file mode 100644 (file)
index 0000000..902045c
--- /dev/null
@@ -0,0 +1,2 @@
+#include "translate.h"
+#include "../winsrc/command.cpp"
diff --git a/linux/flasher.c b/linux/flasher.c
new file mode 100644 (file)
index 0000000..05f3124
--- /dev/null
@@ -0,0 +1,166 @@
+#include <usb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "translate.h"
+#include "../winsrc/prox.h"
+#include "proxmark3.h"
+
+static DWORD ExpectedAddr;
+static BYTE QueuedToSend[256];
+static BOOL AllWritten;
+
+static void FlushPrevious(void)
+{
+       UsbCommand c;
+       memset(&c, 0, sizeof(c));
+
+       printf("expected = %08x flush, ", ExpectedAddr);
+
+       int i;
+       for(i = 0; i < 240; i += 48) {
+               c.cmd = CMD_SETUP_WRITE;
+               memcpy(c.d.asBytes, QueuedToSend+i, 48);
+               c.ext1 = (i/4);
+               SendCommand(&c, TRUE);
+       }
+
+       c.cmd = CMD_FINISH_WRITE;
+       c.ext1 = (ExpectedAddr-1) & (~255);
+       printf("c.ext1 = %08x\r", c.ext1);
+       memcpy(c.d.asBytes, QueuedToSend+240, 16);
+       SendCommand(&c, TRUE);
+
+       AllWritten = TRUE;
+}
+
+static void GotByte(DWORD where, BYTE which)
+{
+       AllWritten = FALSE;
+
+       if(where != ExpectedAddr) {
+               printf("bad: got at %08x, expected at %08x\n", where, ExpectedAddr);
+               exit(-1);
+       }
+       QueuedToSend[where & 255] = which;
+       ExpectedAddr++;
+
+       if((where & 255) == 255) {
+               // we have completed a full page
+               FlushPrevious();
+       }
+}
+
+static int HexVal(int c)
+{
+       c = tolower(c);
+       if(c >= '0' && c <= '9') {
+               return c - '0';
+       } else if(c >= 'a' && c <= 'f') {
+               return (c - 'a') + 10;
+       } else {
+               printf("bad hex digit '%c'\n", c);
+               exit(-1);
+       }
+}
+
+static BYTE HexByte(char *s)
+{
+       return (HexVal(s[0]) << 4) | HexVal(s[1]);
+}
+
+static void LoadFlashFromSRecords(char *file, int addr)
+{
+       ExpectedAddr = addr;
+
+       FILE *f = fopen(file, "r");
+       if(!f) {
+               printf("couldn't open file\n");
+               exit(-1);
+       }
+
+       char line[512];
+       while(fgets(line, sizeof(line), f)) {
+               if(memcmp(line, "S3", 2)==0) {
+                       char *s = line + 2;
+                       int len = HexByte(s) - 5;
+                       s += 2;
+
+                       char addrStr[9];
+                       memcpy(addrStr, s, 8);
+                       addrStr[8] = '\0';
+                       DWORD addr;
+                       sscanf(addrStr, "%x", &addr);
+                       s += 8;
+
+                       int i;
+                       for(i = 0; i < len; i++) {
+                               while((addr+i) > ExpectedAddr) {
+                                       GotByte(ExpectedAddr, 0xff);
+                               }
+                               GotByte(addr+i, HexByte(s));
+                               s += 2;
+                       }
+               }
+       }
+
+       if(!AllWritten) FlushPrevious();
+
+       fclose(f);
+       printf("\ndone.\n");
+}
+
+int main(int argc, char **argv) {
+       unsigned int addr = 0;
+       UsbCommand c;
+
+       if (argc != 3) {
+               fprintf(stderr,"Usage: %s {bootrom|os|fpga} image.s19\n", argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
+       if (!strcmp(argv[1],"bootrom")) {
+               addr = 0;
+       } else if (!strcmp(argv[1],"os")) {
+               addr = 0x10000;
+       } else if (!strcmp(argv[1],"fpga")) {
+               addr = 0x2000;
+       } else {
+               fprintf(stderr,"Unknown action '%s'!\n", argv[1]);
+               exit(EXIT_FAILURE);
+       }
+
+       usb_init();
+
+       fprintf(stderr,"Waiting for Proxmark to appear on USB...\n");
+       while(!(devh=OpenProxmark(0))) { sleep(1); }
+       fprintf(stderr,"Found...\n");
+
+       fprintf(stderr,"Entering flash-mode...\n");
+       bzero(&c, sizeof(c));
+       c.cmd = CMD_START_FLASH;
+       SendCommand(&c, FALSE);
+       CloseProxmark();
+       sleep(1);
+
+       fprintf(stderr,"Waiting for Proxmark to reappear on USB...\n");
+       while(!(devh=OpenProxmark(0))) { sleep(1); }
+       fprintf(stderr,"Found...\n");
+
+       LoadFlashFromSRecords(argv[2], addr);
+
+       bzero(&c, sizeof(c));
+       c.cmd = CMD_HARDWARE_RESET;
+       SendCommand(&c, FALSE);
+
+       CloseProxmark();
+
+       fprintf(stderr,"Have a nice day!\n");
+
+       return 0;
+}
diff --git a/linux/gui.c b/linux/gui.c
new file mode 100644 (file)
index 0000000..6d442f0
--- /dev/null
@@ -0,0 +1,54 @@
+#include <stdarg.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "proxgui.h"
+#include "translate.h"
+#include "../winsrc/prox.h"
+
+int GraphBuffer[MAX_GRAPH_TRACE_LEN];
+int GraphTraceLen;
+double CursorScaleFactor;
+int CommandFinished;
+
+static char *logfilename = "proxmark3.log";
+
+void PrintToScrollback(char *fmt, ...) {
+       va_list argptr;
+       static FILE *logfile = NULL;
+       static int logging=1;
+
+       if (logging && !logfile) {
+               logfile=fopen(logfilename, "a");
+               if (!logfile) {
+                       fprintf(stderr, "Can't open logfile, logging disabled!\n");
+                       logging=0;
+               }
+       }
+
+       va_start(argptr, fmt);
+       vprintf(fmt, argptr);
+       printf("\n");
+       if (logging && logfile) {
+#if 0
+               char zeit[25];
+               time_t jetzt_t;
+               struct tm *jetzt;
+
+               jetzt_t = time(NULL);
+               jetzt = localtime(&jetzt_t);
+               strftime(zeit, 25, "%b %e %T", jetzt);
+
+               fprintf(logfile,"%s ", zeit);
+#endif
+               vfprintf(logfile, fmt, argptr);
+               fprintf(logfile,"\n");
+               fflush(logfile);
+       }
+       va_end(argptr);
+}
+
+void setlogfilename(char *fn)
+{
+       logfilename = fn;
+}
diff --git a/linux/guidummy.c b/linux/guidummy.c
new file mode 100644 (file)
index 0000000..39bcc75
--- /dev/null
@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+void ShowGraphWindow(void)
+{
+       static int warned = 0;
+
+       if (!warned) {
+               printf("No GUI in this build!\n");
+               warned = 1;
+       }
+}
+
+void HideGraphWindow(void) {}
+void RepaintGraphWindow(void) {}
+void MainGraphics() {}
+void InitGraphics(int argc, char **argv) {}
+void ExitGraphics(void) {}
diff --git a/linux/proxgui.cpp b/linux/proxgui.cpp
new file mode 100644 (file)
index 0000000..7e87b58
--- /dev/null
@@ -0,0 +1,58 @@
+#include "proxgui.h"
+#include "proxguiqt.h"
+
+static ProxGuiQT *gui = NULL;
+
+extern "C" void ShowGraphWindow(void)
+{
+       if (!gui)
+               return;
+       
+       gui->ShowGraphWindow();
+}
+
+extern "C" void HideGraphWindow(void)
+{
+       if (!gui)
+               return;
+       
+       gui->HideGraphWindow();
+}
+
+extern "C" void RepaintGraphWindow(void)
+{
+       if (!gui)
+               return;
+
+       gui->RepaintGraphWindow();
+}
+
+extern "C" void MainGraphics(void)
+{
+       if (!gui)
+               return;
+
+       gui->MainLoop();
+}
+
+extern "C" void InitGraphics(int argc, char **argv)
+{
+#ifdef Q_WS_X11
+       bool useGUI = getenv("DISPLAY") != 0;
+#else
+       bool useGUI = true;
+#endif
+       if (!useGUI)
+               return;
+
+       gui = new ProxGuiQT(argc, argv);
+}
+
+extern "C" void ExitGraphics(void)
+{
+       if (!gui)
+               return;
+       
+       delete gui;
+       gui = NULL;
+}
diff --git a/linux/proxgui.h b/linux/proxgui.h
new file mode 100644 (file)
index 0000000..c1e9198
--- /dev/null
@@ -0,0 +1,20 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void ShowGraphWindow(void);
+void HideGraphWindow(void);
+void RepaintGraphWindow(void);
+void MainGraphics(void);
+void InitGraphics(int argc, char **argv);
+void ExitGraphics(void);
+
+#define MAX_GRAPH_TRACE_LEN (1024*128)
+extern int GraphBuffer[MAX_GRAPH_TRACE_LEN];
+extern int GraphTraceLen;
+extern double CursorScaleFactor;
+extern int CommandFinished;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/linux/proxguiqt.cpp b/linux/proxguiqt.cpp
new file mode 100644 (file)
index 0000000..773d74b
--- /dev/null
@@ -0,0 +1,309 @@
+#include <iostream>
+#include <QPainterPath>
+#include <QBrush>
+#include <QPen>
+#include <QTimer>
+#include <QCloseEvent>
+#include <QMouseEvent>
+#include <QKeyEvent>
+#include <math.h>
+#include <limits.h>
+#include "proxguiqt.h"
+#include "proxgui.h"
+
+void ProxGuiQT::ShowGraphWindow(void)
+{
+       emit ShowGraphWindowSignal();
+}
+
+void ProxGuiQT::RepaintGraphWindow(void)
+{
+       emit RepaintGraphWindowSignal();
+}
+
+void ProxGuiQT::HideGraphWindow(void)
+{
+       emit HideGraphWindowSignal();
+}
+
+void ProxGuiQT::_ShowGraphWindow(void)
+{
+       if(!plotapp)
+               return;
+
+       if (!plotwidget)
+               plotwidget = new ProxWidget();
+
+       plotwidget->show();
+}
+
+void ProxGuiQT::_RepaintGraphWindow(void)
+{
+       if (!plotapp || !plotwidget)
+               return;
+
+       plotwidget->update();
+}
+
+void ProxGuiQT::_HideGraphWindow(void)
+{
+       if (!plotapp || !plotwidget)
+               return;
+
+       plotwidget->hide();
+}
+
+void ProxGuiQT::MainLoop()
+{
+       plotapp = new QApplication(argc, argv);
+
+       connect(this, SIGNAL(ShowGraphWindowSignal()), this, SLOT(_ShowGraphWindow()));
+       connect(this, SIGNAL(RepaintGraphWindowSignal()), this, SLOT(_RepaintGraphWindow()));
+       connect(this, SIGNAL(HideGraphWindowSignal()), this, SLOT(_HideGraphWindow()));
+
+       plotapp->exec();
+}
+
+ProxGuiQT::ProxGuiQT(int argc, char **argv) : plotapp(NULL), plotwidget(NULL),
+       argc(argc), argv(argv)
+{
+}
+
+ProxGuiQT::~ProxGuiQT(void)
+{
+       if (plotwidget) {
+               delete plotwidget;
+               plotwidget = NULL;
+       }
+
+       if (plotapp) {
+               plotapp->quit();
+               delete plotapp;
+               plotapp = NULL;
+       }
+}
+
+void ProxWidget::paintEvent(QPaintEvent *event)
+{
+       QPainter painter(this);
+       QPainterPath penPath, whitePath, greyPath, cursorAPath, cursorBPath;
+       QRect r;
+       QBrush brush(QColor(100, 255, 100));
+       QPen pen(QColor(100, 255, 100));
+
+       painter.setFont(QFont("Arial", 10));
+
+       if(GraphStart < 0) {
+               GraphStart = 0;
+       }
+
+       r = rect();
+
+       painter.fillRect(r, QColor(0, 0, 0));
+
+       whitePath.moveTo(r.left() + 40, r.top());
+       whitePath.lineTo(r.left() + 40, r.bottom());
+
+       int zeroHeight = r.top() + (r.bottom() - r.top()) / 2;
+
+       greyPath.moveTo(r.left(), zeroHeight);
+       greyPath.lineTo(r.right(), zeroHeight);
+       painter.setPen(QColor(100, 100, 100));
+       painter.drawPath(greyPath);
+       
+       int startMax =
+               (GraphTraceLen - (int)((r.right() - r.left() - 40) / GraphPixelsPerPoint));
+       if(startMax < 0) {
+               startMax = 0;
+       }
+       if(GraphStart > startMax) {
+               GraphStart = startMax;
+       }
+
+       int absYMax = 1;
+
+       int i;
+       for(i = GraphStart; ; i++) {
+               if(i >= GraphTraceLen) {
+                       break;
+               }
+               if(fabs((double)GraphBuffer[i]) > absYMax) {
+                       absYMax = (int)fabs((double)GraphBuffer[i]);
+               }
+               int x = 40 + (int)((i - GraphStart)*GraphPixelsPerPoint);
+               if(x > r.right()) {
+                       break;
+               }
+       }
+
+       absYMax = (int)(absYMax*1.2 + 1);
+       
+       // number of points that will be plotted
+       int span = (int)((r.right() - r.left()) / GraphPixelsPerPoint);
+       // one label every 100 pixels, let us say
+       int labels = (r.right() - r.left() - 40) / 100;
+       if(labels <= 0) labels = 1;
+       int pointsPerLabel = span / labels;
+       if(pointsPerLabel <= 0) pointsPerLabel = 1;
+
+       int yMin = INT_MAX;
+       int yMax = INT_MIN;
+       int yMean = 0;
+       int n = 0;
+
+       for(i = GraphStart; ; i++) {
+               if(i >= GraphTraceLen) {
+                       break;
+               }
+               int x = 40 + (int)((i - GraphStart)*GraphPixelsPerPoint);
+               if(x > r.right() + GraphPixelsPerPoint) {
+                       break;
+               }
+
+               int y = GraphBuffer[i];
+               if(y < yMin) {
+                       yMin = y;
+               }
+               if(y > yMax) {
+                       yMax = y;
+               }
+               yMean += y;
+               n++;
+
+               y = (y * (r.top() - r.bottom()) / (2*absYMax)) + zeroHeight;
+               if(i == GraphStart) {
+                       penPath.moveTo(x, y);
+               } else {
+                       penPath.lineTo(x, y);
+               }
+
+               if(GraphPixelsPerPoint > 10) {
+                       QRect f(QPoint(x - 3, y - 3),QPoint(x + 3, y + 3));
+                       painter.fillRect(f, brush);
+               }
+
+               if(((i - GraphStart) % pointsPerLabel == 0) && i != GraphStart) {
+                       whitePath.moveTo(x, zeroHeight - 3);
+                       whitePath.lineTo(x, zeroHeight + 3);
+
+                       char str[100];
+                       sprintf(str, "+%d", (i - GraphStart));
+
+                       painter.setPen(QColor(255, 255, 255));
+                       QRect size;
+                       QFontMetrics metrics(painter.font());
+                       size = metrics.boundingRect(str);
+                       painter.drawText(x - (size.right() - size.left()), zeroHeight + 9, str);
+
+                       penPath.moveTo(x,y);
+               }
+
+               if(i == CursorAPos || i == CursorBPos) {
+                       QPainterPath *cursorPath;
+
+                       if(i == CursorAPos) {
+                               cursorPath = &cursorAPath;
+                       } else {
+                               cursorPath = &cursorBPath;
+                       }
+                       cursorPath->moveTo(x, r.top());
+                       cursorPath->lineTo(x, r.bottom());
+                       penPath.moveTo(x, y);
+               }
+       }
+
+       if(n != 0) {
+               yMean /= n;
+       }
+
+       painter.setPen(QColor(255, 255, 255));
+       painter.drawPath(whitePath);
+       painter.setPen(pen);
+       painter.drawPath(penPath);
+       painter.setPen(QColor(255, 255, 0));
+       painter.drawPath(cursorAPath);
+       painter.setPen(QColor(255, 0, 255));
+       painter.drawPath(cursorBPath);
+
+       char str[100];
+       sprintf(str, "@%d   max=%d min=%d mean=%d n=%d/%d    dt=%d [%.3f]",
+                       GraphStart, yMax, yMin, yMean, n, GraphTraceLen,
+                       CursorBPos - CursorAPos, (CursorBPos - CursorAPos)/CursorScaleFactor);
+
+       painter.setPen(QColor(255, 255, 255));
+       painter.drawText(50, r.bottom() - 20, str);
+}
+
+ProxWidget::ProxWidget(QWidget *parent) : QWidget(parent), GraphStart(0), GraphPixelsPerPoint(1)
+{
+       resize(600, 500);
+
+       QPalette palette(QColor(0,0,0,0));
+       palette.setColor(QPalette::WindowText, QColor(255,255,255));
+       palette.setColor(QPalette::Text, QColor(255,255,255));
+       palette.setColor(QPalette::Button, QColor(100, 100, 100));
+       setPalette(palette);
+       setAutoFillBackground(true);
+}
+
+void ProxWidget::closeEvent(QCloseEvent *event)
+{
+       event->ignore();
+       this->hide();
+}
+
+void ProxWidget::mouseMoveEvent(QMouseEvent *event)
+{
+       int x = event->x();
+       x -= 40;
+       x = (int)(x / GraphPixelsPerPoint);
+       x += GraphStart;
+       if((event->buttons() & Qt::LeftButton)) {
+               CursorAPos = x;
+       } else if (event->buttons() & Qt::RightButton) {
+               CursorBPos = x;
+       }
+
+
+       this->update();
+}
+
+void ProxWidget::keyPressEvent(QKeyEvent *event)
+{
+       switch(event->key()) {
+               case Qt::Key_Down:
+                       if(GraphPixelsPerPoint <= 50) {
+                               GraphPixelsPerPoint *= 2;
+                       }
+                       break;
+
+               case Qt::Key_Up:
+                       if(GraphPixelsPerPoint >= 0.02) {
+                               GraphPixelsPerPoint /= 2;
+                       }
+                       break;
+
+               case Qt::Key_Right:
+                       if(GraphPixelsPerPoint < 20) {
+                               GraphStart += (int)(20 / GraphPixelsPerPoint);
+                       } else {
+                               GraphStart++;
+                       }
+                       break;
+
+               case Qt::Key_Left:
+                       if(GraphPixelsPerPoint < 20) {
+                               GraphStart -= (int)(20 / GraphPixelsPerPoint);
+                       } else {
+                               GraphStart--;
+                       }
+                       break;
+
+               default:
+                       QWidget::keyPressEvent(event);
+                       return;
+                       break;
+       }
+
+       this->update();
+}
diff --git a/linux/proxguiqt.h b/linux/proxguiqt.h
new file mode 100644 (file)
index 0000000..58ff832
--- /dev/null
@@ -0,0 +1,56 @@
+#include <QApplication>
+#include <QPushButton>
+#include <QObject>
+#include <QWidget>
+#include <QPainter>
+
+class ProxWidget : public QWidget
+{
+       Q_OBJECT;
+
+       private:
+               int GraphStart;
+               double GraphPixelsPerPoint;
+               int CursorAPos;
+               int CursorBPos;
+
+       public:
+               ProxWidget(QWidget *parent = 0);
+
+       protected:
+               void paintEvent(QPaintEvent *event);
+               void closeEvent(QCloseEvent *event);
+               void mouseMoveEvent(QMouseEvent *event);
+               void mousePressEvent(QMouseEvent *event) { mouseMoveEvent(event); }
+               void keyPressEvent(QKeyEvent *event);
+};
+
+class ProxGuiQT : public QObject
+{
+       Q_OBJECT;
+
+       private:
+               QApplication *plotapp;
+               ProxWidget *plotwidget;
+               int argc;
+               char **argv;
+               void (*main_func)(void);
+       
+       public:
+               ProxGuiQT(int argc, char **argv);
+               ~ProxGuiQT(void);
+               void ShowGraphWindow(void);
+               void RepaintGraphWindow(void);
+               void HideGraphWindow(void);
+               void MainLoop(void);
+       
+       private slots:
+               void _ShowGraphWindow(void);
+               void _RepaintGraphWindow(void);
+               void _HideGraphWindow(void);
+
+       signals:
+               void ShowGraphWindowSignal(void);
+               void RepaintGraphWindowSignal(void);
+               void HideGraphWindowSignal(void);
+};
diff --git a/linux/proxmark3.c b/linux/proxmark3.c
new file mode 100644 (file)
index 0000000..5a3d6f2
--- /dev/null
@@ -0,0 +1,91 @@
+#include <usb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <errno.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <pthread.h>
+
+#include "translate.h"
+#include "../winsrc/prox.h"
+#include "proxmark3.h"
+#include "proxgui.h"
+
+struct usb_receiver_arg {
+       int run;
+};
+
+static void *usb_receiver(void *targ) {
+       struct usb_receiver_arg *arg = (struct usb_receiver_arg*)targ;
+       UsbCommand cmdbuf;
+
+       while(arg->run) {
+               if (ReceiveCommandP(&cmdbuf) > 0) {
+                       int i;
+
+                       for (i=0; i<strlen(PROXPROMPT); i++)
+                               putchar(0x08);
+
+                       UsbCommandReceived(&cmdbuf);
+                       printf(PROXPROMPT);
+                       fflush(NULL);
+               }
+       }
+
+       pthread_exit(NULL);
+}
+
+static void *main_loop(void *targ)
+{
+       char *cmd = NULL;
+
+       while(1) {
+               struct usb_receiver_arg rarg;
+               pthread_t reader_thread;
+
+               rarg.run=1;
+               pthread_create(&reader_thread, NULL, &usb_receiver, &rarg);
+
+               cmd = readline(PROXPROMPT);
+               rarg.run=0;
+               pthread_join(reader_thread, NULL);
+
+               if (cmd) {
+                       if (cmd[0] != 0x00) {
+                               CommandReceived(cmd);
+                               add_history(cmd);
+                       }
+                       free(cmd);
+               } else {
+                       printf("\n");
+                       break;
+               }
+       }
+
+       ExitGraphics();
+       pthread_exit(NULL);
+}
+
+int main(int argc, char **argv)
+{
+       pthread_t main_loop_t;
+       usb_init();
+
+       if (!(devh = OpenProxmark(1))) {
+               fprintf(stderr,"PROXMARK3: NOT FOUND!\n");
+               exit(1);
+       }
+
+       pthread_create(&main_loop_t, NULL, &main_loop, NULL);
+       InitGraphics(argc, argv);
+
+       MainGraphics();
+
+       pthread_join(main_loop_t, NULL);
+
+       CloseProxmark();
+       return 0;
+}
diff --git a/linux/proxmark3.h b/linux/proxmark3.h
new file mode 100644 (file)
index 0000000..4868f25
--- /dev/null
@@ -0,0 +1,11 @@
+#define PROXPROMPT "proxmark3> "
+
+extern usb_dev_handle *devh;
+extern unsigned char return_on_error;
+extern unsigned char error_occured;
+
+int ReceiveCommandP(UsbCommand *c);
+usb_dev_handle* OpenProxmark(int);
+void CloseProxmark(void);
+
+void setlogfilename(char *fn);
diff --git a/linux/snooper.c b/linux/snooper.c
new file mode 100644 (file)
index 0000000..63fa406
--- /dev/null
@@ -0,0 +1,49 @@
+#include <usb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <errno.h>
+
+#include "translate.h"
+#include "../winsrc/prox.h"
+#include "proxmark3.h"
+
+#define HANDLE_ERROR if (error_occured) { \
+       error_occured = 0;\
+       break;\
+}
+
+int main()
+{
+       usb_init();
+       setlogfilename("snooper.log");
+
+       return_on_error = 1;
+
+       while(1) {
+               while(!(devh=OpenProxmark(0))) { sleep(1); }
+
+               while(1) {
+                       UsbCommand cmdbuf;
+                       int i;
+
+                       CommandReceived("hi14asnoop");
+                       HANDLE_ERROR
+
+                       ReceiveCommand(&cmdbuf);
+                       HANDLE_ERROR
+                       for (i=0; i<5; i++) {
+                               ReceiveCommandP(&cmdbuf);
+                       }
+                       HANDLE_ERROR
+
+                       CommandReceived("hi14alist");
+                       HANDLE_ERROR
+               }
+       }
+
+       CloseProxmark();
+       return 0;
+}
diff --git a/linux/translate.h b/linux/translate.h
new file mode 100644 (file)
index 0000000..145268a
--- /dev/null
@@ -0,0 +1,9 @@
+#define BYTE unsigned char
+#define WORD unsigned short
+#define DWORD unsigned int
+#define TRUE 1
+#define FALSE 0
+#define BOOL int
+
+#define max(a,b) (((a)>(b))?(a):(b))
+#define min(a,b) (((a)>(b))?(b):(a))
diff --git a/linux/unbind-proxmark b/linux/unbind-proxmark
new file mode 100755 (executable)
index 0000000..986c001
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+for i in /sys/bus/usb/devices/*; do
+       if grep "9ac4" "${i}/idVendor" >/dev/null 2>&1; then
+               echo "Found Proxmark..."
+               dev=`basename "${i}"`
+
+               for j in /sys/bus/usb/drivers/usbhid/*; do
+                       if basename "${j}"|grep "^${dev}" >/dev/null; then
+                               bound="`basename "${j}"`"
+                               echo "Unbinding ${bound}..."
+                               echo -n "${bound}" >/sys/bus/usb/drivers/usbhid/unbind
+                       fi
+               done
+       fi
+done
diff --git a/linux/usb.c b/linux/usb.c
new file mode 100644 (file)
index 0000000..8145b64
--- /dev/null
@@ -0,0 +1,171 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <usb.h>
+#include <strings.h>
+#include <errno.h>
+
+#include "translate.h"
+#include "../winsrc/prox.h"
+#include "proxmark3.h"
+
+usb_dev_handle *devh = NULL;
+static unsigned int claimed_iface = 0;
+unsigned char return_on_error = 0;
+unsigned char error_occured = 0;
+
+void SendCommand(UsbCommand *c, BOOL wantAck) {
+       int ret;
+
+#if 0
+       printf("Sending %d bytes\n", sizeof(UsbCommand));
+#endif
+       ret = usb_bulk_write(devh, 0x01, (char*)c, sizeof(UsbCommand), 1000);
+       if (ret<0) {
+               error_occured = 1;
+               if (return_on_error)
+                       return;
+
+               fprintf(stderr, "write failed: %s!\nTrying to reopen device...\n",
+                       usb_strerror());
+
+               if (devh) {
+                       usb_close(devh);
+                       devh = NULL;
+               }
+               while(!(devh=OpenProxmark(0))) { sleep(1); }
+               printf(PROXPROMPT);
+               fflush(NULL);
+               
+               return;
+       }
+
+       if(wantAck) {
+               UsbCommand ack;
+               ReceiveCommand(&ack);
+               if(ack.cmd != CMD_ACK) {
+                       printf("bad ACK\n");
+                       exit(-1);
+               }
+       }
+}
+
+int ReceiveCommandP(UsbCommand *c) {
+       int ret;
+
+       bzero(c, sizeof(UsbCommand));
+       ret = usb_bulk_read(devh, 0x82, (char*)c, sizeof(UsbCommand), 500);
+       if (ret<0) {
+               if (ret != -ETIMEDOUT) {
+                       error_occured = 1;
+                       if (return_on_error)
+                               return 0;
+
+                       fprintf(stderr, "read failed: %s(%d)!\nTrying to reopen device...\n",
+                               usb_strerror(), ret);
+
+                       if (devh) {
+                               usb_close(devh);
+                               devh = NULL;
+                       }
+                       while(!(devh=OpenProxmark(0))) { sleep(1); }
+                       printf(PROXPROMPT);
+                       fflush(NULL);
+
+                       return 0;
+               }
+       } else {
+               if (ret && (ret < sizeof(UsbCommand))) {
+                       fprintf(stderr, "Read only %d instead of requested %d bytes!\n",
+                               ret, (int)sizeof(UsbCommand));
+               }
+
+#if 0
+               {
+                       int i;
+
+                       printf("Read %d bytes\n", ret);
+                       for (i = 0; i < ret; i++) {
+                               printf("0x%02X ", ((unsigned char*)c)[i]);
+                               if (!((i+1)%8))
+                                       printf("\n");
+                       }
+                       printf("\n");
+               }
+#endif
+       }
+
+       return ret;
+}
+
+void ReceiveCommand(UsbCommand *c) {
+       while(ReceiveCommandP(c)<0) {}
+}
+
+usb_dev_handle* findProxmark(int verbose, unsigned int *iface) {
+       struct usb_bus *busses, *bus;
+       usb_dev_handle *handle = NULL;
+
+       usb_find_busses();
+       usb_find_devices();
+
+       busses = usb_get_busses();
+
+       for (bus = busses; bus; bus = bus->next) {
+               struct usb_device *dev;
+
+               for (dev = bus->devices; dev; dev = dev->next) {
+                       struct usb_device_descriptor *desc = &(dev->descriptor);
+
+                       if ((desc->idProduct == 0x4b8f) && (desc->idVendor == 0x9ac4)) {
+                               handle = usb_open(dev);
+                               if (!handle) {
+                                       if (verbose)
+                                               fprintf(stderr, "open failed: %s!\n", usb_strerror());
+                                       return NULL;
+                               }
+
+                               *iface = dev->config[0].interface[0].altsetting[0].bInterfaceNumber;
+
+                               return handle;
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+usb_dev_handle* OpenProxmark(int verbose) {
+       int ret;
+       usb_dev_handle *handle = NULL;
+       unsigned int iface;
+
+#ifndef __APPLE__
+       handle = findProxmark(verbose, &iface);
+       if (!handle)
+               return NULL;
+
+       /* Whatever... */
+       usb_reset(handle);
+#endif
+
+       handle = findProxmark(verbose, &iface);
+       if (!handle)
+               return NULL;
+
+       ret = usb_claim_interface(handle, iface);
+       if (ret<0) {
+               if (verbose)
+                       fprintf(stderr, "claim failed: %s!\n", usb_strerror());
+               return NULL;
+       }
+
+       claimed_iface = iface;
+       devh = handle;
+       return handle;
+}
+
+void CloseProxmark(void) {
+       usb_release_interface(devh, claimed_iface);
+       usb_close(devh);
+}
diff --git a/linux/windows.h b/linux/windows.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/winsrc/Makefile b/winsrc/Makefile
new file mode 100644 (file)
index 0000000..b398c2c
--- /dev/null
@@ -0,0 +1,31 @@
+BASE_DEFS   = /D_WIN32_WINNT=0x501 /DISOLATION_AWARE_ENABLED /D_WIN32_IE=0x600 /DWIN32_LEAN_AND_MEAN /DWIN32 /D_MT /D_CRT_SECURE_NO_WARNINGS\r
+BASE_CFLAGS = /W3 /nologo\r
+\r
+DEFINES  = $(BASE_DEFS)\r
+CFLAGS   = $(BASE_CFLAGS) /Zi /MT\r
+\r
+OBJDIR = obj\r
+\r
+OBJS   = $(OBJDIR)\prox.obj \\r
+         $(OBJDIR)\gui.obj \\r
+         $(OBJDIR)\command.obj\r
+\r
+LIBS   = kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setupapi.lib\r
+\r
+HEADERS = prox.h\r
+\r
+all: $(OBJDIR)/prox.exe\r
+    copy $(OBJDIR)\prox.exe .\r
+\r
+clean:\r
+       del /q obj\*.obj\r
+       del /q obj\*.ilk\r
+       del /q obj\*.exe\r
+       del /q obj\*.pdb\r
+       del /q *.pdb\r
+\r
+$(OBJDIR)/prox.exe: $(OBJS)\r
+    $(CC) $(DEFINES) $(CFLAGS) -Fe$(OBJDIR)/prox.exe $(OBJS) $(LIBS)\r
+\r
+$(OBJS): $(@B).cpp $(HEADERS)\r
+    $(CC) $(CFLAGS) $(DEFINES) -c -Fo$(OBJDIR)/$(@B).obj $(@B).cpp\r
diff --git a/winsrc/command.cpp b/winsrc/command.cpp
new file mode 100644 (file)
index 0000000..1da1e1c
--- /dev/null
@@ -0,0 +1,1812 @@
+//-----------------------------------------------------------------------------\r
+// The actual command interpeter for what the user types at the command line.\r
+// Jonathan Westhues, Sept 2005\r
+// Edits by Gerhard de Koning Gans, Sep 2007 (##)\r
+//-----------------------------------------------------------------------------\r
+#include <windows.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <stdio.h>\r
+#include <limits.h>\r
+#include <math.h>\r
+\r
+#include "prox.h"\r
+#include "../common/iso14443_crc.c"\r
+\r
+#define arraylen(x) (sizeof(x)/sizeof((x)[0]))\r
+\r
+static int CmdHisamplest(char *str, int nrlow);\r
+\r
+static void GetFromBigBuf(BYTE *dest, int bytes)\r
+{\r
+       int n = bytes/4;\r
+\r
+       if(n % 48 != 0) {\r
+               PrintToScrollback("bad len in GetFromBigBuf");\r
+               return;\r
+       }\r
+\r
+       int i;\r
+       for(i = 0; i < n; i += 12) {\r
+               UsbCommand c;\r
+               c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
+               c.ext1 = i;\r
+               SendCommand(&c, FALSE);\r
+               ReceiveCommand(&c);\r
+               if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
+                       PrintToScrollback("bad resp\n");\r
+                       return;\r
+               }\r
+\r
+               memcpy(dest+(i*4), c.d.asBytes, 48);\r
+       }\r
+}\r
+\r
+static void CmdQuit(char *str)\r
+{\r
+       exit(0);\r
+}\r
+\r
+static void CmdHIDdemodFSK(char *str)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_HID_DEMOD_FSK;\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdTune(char *str)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_MEASURE_ANTENNA_TUNING;\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdHi15read(char *str)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693;\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdHi14read(char *str)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;\r
+       c.ext1 = atoi(str);\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+// ## New command\r
+static void CmdHi14areader(char *str)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_READER_ISO_14443a;\r
+       c.ext1 = atoi(str);\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+// ## New command\r
+static void CmdHi15reader(char *str)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_READER_ISO_15693;\r
+       c.ext1 = atoi(str);\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+// ## New command\r
+static void CmdHi15tag(char *str)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_SIMTAG_ISO_15693;\r
+       c.ext1 = atoi(str);\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdHi14read_sim(char *str)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443_SIM;\r
+       c.ext1 = atoi(str);\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdHi14readt(char *str)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;\r
+       c.ext1 = atoi(str);\r
+       SendCommand(&c, FALSE);\r
+\r
+       //CmdHisamplest(str);\r
+       while(CmdHisamplest(str,atoi(str))==0) {\r
+               c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;\r
+               c.ext1 = atoi(str);\r
+               SendCommand(&c, FALSE);\r
+       }\r
+       RepaintGraphWindow();\r
+}\r
+\r
+static void CmdHisimlisten(char *str)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_SIMULATE_TAG_HF_LISTEN;\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdHi14sim(char *str)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_SIMULATE_TAG_ISO_14443;\r
+       SendCommand(&c, FALSE);\r
+}\r
+
+
+\r
+static void CmdHi14asim(char *str)     // ## simulate iso14443a tag\r
+{                                      // ## greg - added ability to specify tag UID\r
+\r
+       unsigned int hi=0, lo=0;\r
+       int n=0, i=0;\r
+       UsbCommand c;\r
+\r
+       while (sscanf(&str[i++], "%1x", &n ) == 1) {\r
+               hi=(hi<<4)|(lo>>28);\r
+               lo=(lo<<4)|(n&0xf);\r
+       }\r
+\r
+       c.cmd = CMD_SIMULATE_TAG_ISO_14443a;\r
+       // c.ext should be set to *str or convert *str to the correct format for a uid\r
+       c.ext1 = hi;\r
+       c.ext2 = lo;\r
+       PrintToScrollback("Emulating 14443A TAG with UID %x%16x", hi, lo);\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdHi14snoop(char *str)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_SNOOP_ISO_14443;\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdHi14asnoop(char *str)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_SNOOP_ISO_14443a;\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdFPGAOff(char *str)              // ## FPGA Control\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_FPGA_MAJOR_MODE_OFF;\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdLosim(char *str)\r
+{\r
+       int i;\r
+\r
+       for(i = 0; i < GraphTraceLen; i += 48) {\r
+               UsbCommand c;\r
+               int j;\r
+               for(j = 0; j < 48; j++) {\r
+                       c.d.asBytes[j] = GraphBuffer[i+j];\r
+               }\r
+               c.cmd = CMD_DOWNLOADED_SIM_SAMPLES_125K;\r
+               c.ext1 = i;\r
+               SendCommand(&c, FALSE);\r
+       }\r
+\r
+       UsbCommand c;\r
+       c.cmd = CMD_SIMULATE_TAG_125K;\r
+       c.ext1 = GraphTraceLen;\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdLoread(char *str)\r
+{\r
+       UsbCommand c;\r
+       // 'h' means higher-low-frequency, 134 kHz\r
+       if(*str == 'h') {\r
+               c.ext1 = 1;\r
+       } else if (*str == '\0') {\r
+               c.ext1 = 0;\r
+       } else {\r
+               PrintToScrollback("use 'loread' or 'loread h'");\r
+               return;\r
+       }\r
+       c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_125K;\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdLosamples(char *str)\r
+{\r
+       int cnt = 0;\r
+       int i;\r
+       int n;\r
+\r
+       n=atoi(str);\r
+       if (n==0) n=128;\r
+       if (n>16000) n=16000;\r
+\r
+       for(i = 0; i < n; i += 12) {\r
+               UsbCommand c;\r
+               c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
+               c.ext1 = i;\r
+               SendCommand(&c, FALSE);\r
+               ReceiveCommand(&c);\r
+               if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
+                       PrintToScrollback("bad resp\n");\r
+                       return;\r
+               }\r
+               int j;\r
+               for(j = 0; j < 48; j++) {\r
+                       GraphBuffer[cnt++] = ((int)c.d.asBytes[j]) - 128;\r
+               }\r
+       }\r
+       GraphTraceLen = n*4;\r
+       RepaintGraphWindow();\r
+}\r
+\r
+static void CmdBitsamples(char *str)\r
+{\r
+       int cnt = 0;\r
+       int i;\r
+       int n;\r
+\r
+       n = 3072;\r
+       for(i = 0; i < n; i += 12) {\r
+               UsbCommand c;\r
+               c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
+               c.ext1 = i;\r
+               SendCommand(&c, FALSE);\r
+               ReceiveCommand(&c);\r
+               if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
+                       PrintToScrollback("bad resp\n");\r
+                       return;\r
+               }\r
+               int j, k;\r
+               for(j = 0; j < 48; j++) {\r
+                       for(k = 0; k < 8; k++) {\r
+                               if(c.d.asBytes[j] & (1 << (7 - k))) {\r
+                                       GraphBuffer[cnt++] = 1;\r
+                               } else {\r
+                                       GraphBuffer[cnt++] = 0;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       GraphTraceLen = cnt;\r
+       RepaintGraphWindow();\r
+}\r
+\r
+static void CmdHisamples(char *str)\r
+{\r
+       int cnt = 0;\r
+       int i;\r
+       int n;\r
+       n = 1000;\r
+       for(i = 0; i < n; i += 12) {\r
+               UsbCommand c;\r
+               c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
+               c.ext1 = i;\r
+               SendCommand(&c, FALSE);\r
+               ReceiveCommand(&c);\r
+               if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
+                       PrintToScrollback("bad resp\n");\r
+                       return;\r
+               }\r
+               int j;\r
+               for(j = 0; j < 48; j++) {\r
+                       GraphBuffer[cnt++] = (int)((BYTE)c.d.asBytes[j]);\r
+               }\r
+       }\r
+       GraphTraceLen = n*4;\r
+\r
+       RepaintGraphWindow();\r
+}\r
+\r
+\r
+static int CmdHisamplest(char *str, int nrlow)\r
+{\r
+       int cnt = 0;\r
+       int t1, t2;\r
+       int i;\r
+       int n;\r
+       int hasbeennull;\r
+       int show;\r
+\r
+\r
+       n = 1000;\r
+       hasbeennull = 0;\r
+       for(i = 0; i < n; i += 12) {\r
+               UsbCommand c;\r
+               c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
+               c.ext1 = i;\r
+               SendCommand(&c, FALSE);\r
+               ReceiveCommand(&c);\r
+               if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
+                       PrintToScrollback("bad resp\n");\r
+                       return 0;\r
+               }\r
+               int j;\r
+               for(j = 0; j < 48; j++) {\r
+                       t2 = (int)((BYTE)c.d.asBytes[j]);\r
+                       if((t2 ^ 0xC0) & 0xC0) { hasbeennull++; }\r
+\r
+                       show = 0;\r
+                       switch(show) {\r
+                               case 0:\r
+                                       // combined\r
+                                       t1 = (t2 & 0x80) ^ (t2 & 0x20);\r
+                                       t2 = ((t2 << 1) & 0x80) ^ ((t2 << 1) & 0x20);\r
+                                       break;\r
+\r
+                               case 1:\r
+                                       // only reader\r
+                                       t1 = (t2 & 0x80);\r
+                                       t2 = ((t2 << 1) & 0x80);\r
+                                       break;\r
+\r
+                               case 2:\r
+                                       // only tag\r
+                                       t1 = (t2 & 0x20);\r
+                                       t2 = ((t2 << 1) & 0x20);\r
+                                       break;\r
+\r
+                               case 3:\r
+                                       // both, but tag with other algorithm\r
+                                       t1 = (t2 & 0x80) ^ (t2 & 0x08);\r
+                                       t2 = ((t2 << 1) & 0x80) ^ ((t2 << 1) & 0x08);\r
+                                       break;\r
+                       }\r
+\r
+                       GraphBuffer[cnt++] = t1;\r
+                       GraphBuffer[cnt++] = t2;\r
+               }\r
+       }\r
+       GraphTraceLen = n*4;\r
+// 1130\r
+       if(hasbeennull>nrlow || nrlow==0) {\r
+               PrintToScrollback("hasbeennull=%d", hasbeennull);\r
+               return 1;\r
+       }\r
+       else {\r
+               return 0;\r
+       }\r
+}\r
+\r
+\r
+static void CmdHexsamples(char *str)\r
+{\r
+       int i;\r
+       int n;\r
+\r
+       if(atoi(str) == 0) {\r
+               n = 12;\r
+       } else {\r
+               n = atoi(str)/4;\r
+       }\r
+\r
+       for(i = 0; i < n; i += 12) {\r
+               UsbCommand c;\r
+               c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
+               c.ext1 = i;\r
+               SendCommand(&c, FALSE);\r
+               ReceiveCommand(&c);\r
+               if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
+                       PrintToScrollback("bad resp\n");\r
+                       return;\r
+               }\r
+               int j;\r
+               for(j = 0; j < 48; j += 8) {\r
+                       PrintToScrollback("%02x %02x %02x %02x %02x %02x %02x %02x",\r
+                               c.d.asBytes[j+0],\r
+                               c.d.asBytes[j+1],\r
+                               c.d.asBytes[j+2],\r
+                               c.d.asBytes[j+3],\r
+                               c.d.asBytes[j+4],\r
+                               c.d.asBytes[j+5],\r
+                               c.d.asBytes[j+6],\r
+                               c.d.asBytes[j+7],\r
+                               c.d.asBytes[j+8]\r
+                       );\r
+               }\r
+       }\r
+}\r
+\r
+static void CmdHisampless(char *str)\r
+{\r
+       int cnt = 0;\r
+       int i;\r
+       int n;\r
+\r
+       if(atoi(str) == 0) {\r
+               n = 1000;\r
+       } else {\r
+               n = atoi(str)/4;\r
+       }\r
+\r
+       for(i = 0; i < n; i += 12) {\r
+               UsbCommand c;\r
+               c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
+               c.ext1 = i;\r
+               SendCommand(&c, FALSE);\r
+               ReceiveCommand(&c);\r
+               if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
+                       PrintToScrollback("bad resp\n");\r
+                       return;\r
+               }\r
+               int j;\r
+               for(j = 0; j < 48; j++) {\r
+                       GraphBuffer[cnt++] = (int)((signed char)c.d.asBytes[j]);\r
+               }\r
+       }\r
+       GraphTraceLen = cnt;\r
+\r
+       RepaintGraphWindow();\r
+}\r
+\r
+static WORD Iso15693Crc(BYTE *v, int n)\r
+{\r
+       DWORD reg;\r
+       int i, j;\r
+\r
+       reg = 0xffff;\r
+       for(i = 0; i < n; i++) {\r
+               reg = reg ^ ((DWORD)v[i]);\r
+               for (j = 0; j < 8; j++) {\r
+                       if (reg & 0x0001) {\r
+                               reg = (reg >> 1) ^ 0x8408;\r
+                       } else {\r
+                               reg = (reg >> 1);\r
+                       }\r
+               }\r
+       }\r
+\r
+       return (WORD)~reg;\r
+}\r
+\r
+static void CmdHi14bdemod(char *str)\r
+{\r
+       int i, j, iold;\r
+       int isum, qsum;\r
+       int outOfWeakAt;\r
+       BOOL negateI, negateQ;\r
+\r
+       BYTE data[256];\r
+       int dataLen=0;\r
+\r
+       // As received, the samples are pairs, correlations against I and Q\r
+       // square waves. So estimate angle of initial carrier (or just\r
+       // quadrant, actually), and then do the demod.\r
+\r
+       // First, estimate where the tag starts modulating.\r
+       for(i = 0; i < GraphTraceLen; i += 2) {\r
+               if(abs(GraphBuffer[i]) + abs(GraphBuffer[i+1]) > 40) {\r
+                       break;\r
+               }\r
+       }\r
+       if(i >= GraphTraceLen) {\r
+               PrintToScrollback("too weak to sync");\r
+               return;\r
+       }\r
+       PrintToScrollback("out of weak at %d", i);\r
+       outOfWeakAt = i;\r
+\r
+       // Now, estimate the phase in the initial modulation of the tag\r
+       isum = 0;\r
+       qsum = 0;\r
+       for(; i < (outOfWeakAt + 16); i += 2) {\r
+               isum += GraphBuffer[i+0];\r
+               qsum += GraphBuffer[i+1];\r
+       }\r
+       negateI = (isum < 0);\r
+       negateQ = (qsum < 0);\r
+\r
+       // Turn the correlation pairs into soft decisions on the bit.\r
+       j = 0;\r
+       for(i = 0; i < GraphTraceLen/2; i++) {\r
+               int si = GraphBuffer[j];\r
+               int sq = GraphBuffer[j+1];\r
+               if(negateI) si = -si;\r
+               if(negateQ) sq = -sq;\r
+               GraphBuffer[i] = si + sq;\r
+               j += 2;\r
+       }\r
+       GraphTraceLen = i;\r
+\r
+       i = outOfWeakAt/2;\r
+       while(GraphBuffer[i] > 0 && i < GraphTraceLen)\r
+               i++;\r
+       if(i >= GraphTraceLen) goto demodError;\r
+\r
+       iold = i;\r
+       while(GraphBuffer[i] < 0 && i < GraphTraceLen)\r
+               i++;\r
+       if(i >= GraphTraceLen) goto demodError;\r
+       if((i - iold) > 23) goto demodError;\r
+\r
+       PrintToScrollback("make it to demod loop");\r
+\r
+       for(;;) {\r
+               iold = i;\r
+               while(GraphBuffer[i] >= 0 && i < GraphTraceLen)\r
+                       i++;\r
+               if(i >= GraphTraceLen) goto demodError;\r
+               if((i - iold) > 6) goto demodError;\r
+\r
+               WORD shiftReg = 0;\r
+               if(i + 20 >= GraphTraceLen) goto demodError;\r
+\r
+               for(j = 0; j < 10; j++) {\r
+                       int soft = GraphBuffer[i] + GraphBuffer[i+1];\r
+\r
+                       if(abs(soft) < ((abs(isum) + abs(qsum))/20)) {\r
+                               PrintToScrollback("weak bit");\r
+                       }\r
+\r
+                       shiftReg >>= 1;\r
+                       if(GraphBuffer[i] + GraphBuffer[i+1] >= 0) {\r
+                               shiftReg |= 0x200;\r
+                       }\r
+\r
+                       i+= 2;\r
+               }\r
+\r
+               if( (shiftReg & 0x200) &&\r
+                       !(shiftReg & 0x001))\r
+               {\r
+                       // valid data byte, start and stop bits okay\r
+                       PrintToScrollback("   %02x", (shiftReg >> 1) & 0xff);\r
+                       data[dataLen++] = (shiftReg >> 1) & 0xff;\r
+                       if(dataLen >= sizeof(data)) {\r
+                               return;\r
+                       }\r
+               } else if(shiftReg == 0x000) {\r
+                       // this is EOF\r
+                       break;\r
+               } else {\r
+                       goto demodError;\r
+               }\r
+       }\r
+\r
+       BYTE first, second;\r
+       ComputeCrc14443(CRC_14443_B, data, dataLen-2, &first, &second);\r
+       PrintToScrollback("CRC: %02x %02x (%s)\n", first, second,\r
+               (first == data[dataLen-2] && second == data[dataLen-1]) ?\r
+                       "ok" : "****FAIL****");\r
+\r
+       RepaintGraphWindow();\r
+       return;\r
+\r
+demodError:\r
+       PrintToScrollback("demod error");\r
+       RepaintGraphWindow();\r
+}\r
+\r
+static void CmdHi14list(char *str)\r
+{\r
+       BYTE got[960];\r
+       GetFromBigBuf(got, sizeof(got));\r
+\r
+       PrintToScrollback("recorded activity:");\r
+       PrintToScrollback(" time        :rssi: who bytes");\r
+       PrintToScrollback("---------+----+----+-----------");\r
+\r
+       int i = 0;\r
+       int prev = -1;\r
+\r
+       for(;;) {\r
+               if(i >= 900) {\r
+                       break;\r
+               }\r
+\r
+               BOOL isResponse;\r
+               int timestamp = *((DWORD *)(got+i));\r
+               if(timestamp & 0x80000000) {\r
+                       timestamp &= 0x7fffffff;\r
+                       isResponse = 1;\r
+               } else {\r
+                       isResponse = 0;\r
+               }\r
+               int metric = *((DWORD *)(got+i+4));\r
+\r
+               int len = got[i+8];\r
+\r
+               if(len > 100) {\r
+                       break;\r
+               }\r
+               if(i + len >= 900) {\r
+                       break;\r
+               }\r
+\r
+               BYTE *frame = (got+i+9);\r
+\r
+               char line[1000] = "";\r
+               int j;\r
+               for(j = 0; j < len; j++) {\r
+                       sprintf(line+(j*3), "%02x  ", frame[j]);\r
+               }\r
+\r
+               char *crc;\r
+               if(len > 2) {\r
+                       BYTE b1, b2;\r
+                       ComputeCrc14443(CRC_14443_B, frame, len-2, &b1, &b2);\r
+                       if(b1 != frame[len-2] || b2 != frame[len-1]) {\r
+                               crc = "**FAIL CRC**";\r
+                       } else {\r
+                               crc = "";\r
+                       }\r
+               } else {\r
+                       crc = "(SHORT)";\r
+               }\r
+\r
+               char metricString[100];\r
+               if(isResponse) {\r
+                       sprintf(metricString, "%3d", metric);\r
+               } else {\r
+                       strcpy(metricString, "   ");\r
+               }\r
+\r
+               PrintToScrollback(" +%7d: %s: %s %s %s",\r
+                       (prev < 0 ? 0 : timestamp - prev),\r
+                       metricString,\r
+                       (isResponse ? "TAG" : "   "), line, crc);\r
+\r
+               prev = timestamp;\r
+               i += (len + 9);\r
+       }\r
+}\r
+\r
+static void CmdHi14alist(char *str)\r
+{\r
+       BYTE got[1920];\r
+       GetFromBigBuf(got, sizeof(got));\r
+\r
+       PrintToScrollback("recorded activity:");\r
+       PrintToScrollback(" ETU     :rssi: who bytes");\r
+       PrintToScrollback("---------+----+----+-----------");\r
+\r
+       int i = 0;\r
+       int prev = -1;\r
+\r
+       for(;;) {\r
+               if(i >= 1900) {\r
+                       break;\r
+               }\r
+\r
+               BOOL isResponse;\r
+               int timestamp = *((DWORD *)(got+i));\r
+               if(timestamp & 0x80000000) {\r
+                       timestamp &= 0x7fffffff;\r
+                       isResponse = 1;\r
+               } else {\r
+                       isResponse = 0;\r
+               }\r
+\r
+               int metric = 0;\r
+               int parityBits = *((DWORD *)(got+i+4));\r
+               // 4 bytes of additional information...\r
+               // maximum of 32 additional parity bit information\r
+               //\r
+               // TODO:\r
+               // at each quarter bit period we can send power level (16 levels)\r
+               // or each half bit period in 256 levels.\r
+\r
+\r
+               int len = got[i+8];\r
+\r
+               if(len > 100) {\r
+                       break;\r
+               }\r
+               if(i + len >= 1900) {\r
+                       break;\r
+               }\r
+\r
+               BYTE *frame = (got+i+9);\r
+\r
+               // Break and stick with current result if buffer was not completely full\r
+               if(frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; }\r
+\r
+               char line[1000] = "";\r
+               int j;\r
+               for(j = 0; j < len; j++) {\r
+                       int oddparity = 0x01;\r
+                       int k;\r
+\r
+                       for(k=0;k<8;k++) {\r
+                               oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01);\r
+                       }\r
+\r
+                       //if((parityBits >> (len - j - 1)) & 0x01) {\r
+                       if(isResponse && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) {\r
+                               sprintf(line+(j*4), "%02x!  ", frame[j]);\r
+                       }\r
+                       else {\r
+                               sprintf(line+(j*4), "%02x   ", frame[j]);\r
+                       }\r
+               }\r
+\r
+               char *crc;\r
+               crc = "";\r
+               if(len > 2) {\r
+                       BYTE b1, b2;\r
+                       for(j = 0; j < (len - 1); j++) {\r
+                               // gives problems... search for the reason..\r
+                               /*if(frame[j] == 0xAA) {\r
+                                       switch(frame[j+1]) {\r
+                                               case 0x01:\r
+                                                       crc = "[1] Two drops close after each other";\r
+                                               break;\r
+                                               case 0x02:\r
+                                                       crc = "[2] Potential SOC with a drop in second half of bitperiod";\r
+                                                       break;\r
+                                               case 0x03:\r
+                                                       crc = "[3] Segment Z after segment X is not possible";\r
+                                                       break;\r
+                                               case 0x04:\r
+                                                       crc = "[4] Parity bit of a fully received byte was wrong";\r
+                                                       break;\r
+                                               default:\r
+                                                       crc = "[?] Unknown error";\r
+                                                       break;\r
+                                       }\r
+                                       break;\r
+                               }*/\r
+                       }\r
+\r
+                       if(strlen(crc)==0) {\r
+                               ComputeCrc14443(CRC_14443_A, frame, len-2, &b1, &b2);\r
+                               if(b1 != frame[len-2] || b2 != frame[len-1]) {\r
+                                       crc = (isResponse & (len < 6)) ? "" : " !crc";\r
+                               } else {\r
+                                       crc = "";\r
+                               }\r
+                       }\r
+               } else {\r
+                       crc = ""; // SHORT\r
+               }\r
+\r
+               char metricString[100];\r
+               if(isResponse) {\r
+                       sprintf(metricString, "%3d", metric);\r
+               } else {\r
+                       strcpy(metricString, "   ");\r
+               }\r
+\r
+               PrintToScrollback(" +%7d: %s: %s %s %s",\r
+                       (prev < 0 ? 0 : (timestamp - prev)),\r
+                       metricString,\r
+                       (isResponse ? "TAG" : "   "), line, crc);\r
+\r
+               prev = timestamp;\r
+               i += (len + 9);\r
+       }\r
+       CommandFinished = 1;\r
+}\r
+\r
+static void CmdHi15demod(char *str)\r
+{\r
+       // The sampling rate is 106.353 ksps/s, for T = 18.8 us\r
+\r
+       // SOF defined as \r
+       // 1) Unmodulated time of 56.64us\r
+       // 2) 24 pulses of 423.75khz\r
+       // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)\r
+\r
+       static const int FrameSOF[] = {\r
+               -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+               -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+                1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,\r
+                1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,\r
+               -1, -1, -1, -1,\r
+               -1, -1, -1, -1,\r
+                1,  1,  1,  1,\r
+                1,  1,  1,  1\r
+       };\r
+       static const int Logic0[] = {\r
+                1,  1,  1,  1,\r
+                1,  1,  1,  1,\r
+               -1, -1, -1, -1,\r
+               -1, -1, -1, -1\r
+       };\r
+       static const int Logic1[] = {\r
+               -1, -1, -1, -1,\r
+               -1, -1, -1, -1,\r
+                1,  1,  1,  1,\r
+                1,  1,  1,  1\r
+       };\r
+\r
+       // EOF defined as \r
+       // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)\r
+       // 2) 24 pulses of 423.75khz\r
+       // 3) Unmodulated time of 56.64us\r
+\r
+       static const int FrameEOF[] = {\r
+                1,  1,  1,  1,\r
+                1,  1,  1,  1,\r
+               -1, -1, -1, -1,\r
+               -1, -1, -1, -1,\r
+                1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,\r
+                1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,\r
+               -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+               -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\r
+       };\r
+\r
+       int i, j;\r
+       int max = 0, maxPos;\r
+\r
+       int skip = 4;\r
+\r
+       if(GraphTraceLen < 1000) return;\r
+\r
+       // First, correlate for SOF\r
+       for(i = 0; i < 100; i++) {\r
+               int corr = 0;\r
+               for(j = 0; j < arraylen(FrameSOF); j += skip) {\r
+                       corr += FrameSOF[j]*GraphBuffer[i+(j/skip)];\r
+               }\r
+               if(corr > max) {\r
+                       max = corr;\r
+                       maxPos = i;\r
+               }\r
+       }\r
+       PrintToScrollback("SOF at %d, correlation %d", maxPos,\r
+               max/(arraylen(FrameSOF)/skip));\r
+\r
+       i = maxPos + arraylen(FrameSOF)/skip;\r
+       int k = 0;\r
+       BYTE outBuf[20];\r
+       memset(outBuf, 0, sizeof(outBuf));\r
+       BYTE mask = 0x01;\r
+       for(;;) {\r
+               int corr0 = 0, corr1 = 0, corrEOF = 0;\r
+               for(j = 0; j < arraylen(Logic0); j += skip) {\r
+                       corr0 += Logic0[j]*GraphBuffer[i+(j/skip)];\r
+               }\r
+               for(j = 0; j < arraylen(Logic1); j += skip) {\r
+                       corr1 += Logic1[j]*GraphBuffer[i+(j/skip)];\r
+               }\r
+               for(j = 0; j < arraylen(FrameEOF); j += skip) {\r
+                       corrEOF += FrameEOF[j]*GraphBuffer[i+(j/skip)];\r
+               }\r
+               // Even things out by the length of the target waveform.\r
+               corr0 *= 4;\r
+               corr1 *= 4;\r
+\r
+               if(corrEOF > corr1 && corrEOF > corr0) {\r
+                       PrintToScrollback("EOF at %d", i);\r
+                       break;\r
+               } else if(corr1 > corr0) {\r
+                       i += arraylen(Logic1)/skip;\r
+                       outBuf[k] |= mask;\r
+               } else {\r
+                       i += arraylen(Logic0)/skip;\r
+               }\r
+               mask <<= 1;\r
+               if(mask == 0) {\r
+                       k++;\r
+                       mask = 0x01;\r
+               }\r
+               if((i+(int)arraylen(FrameEOF)) >= GraphTraceLen) {\r
+                       PrintToScrollback("ran off end!");\r
+                       break;\r
+               }\r
+       }\r
+       if(mask != 0x01) {\r
+               PrintToScrollback("error, uneven octet! (discard extra bits!)");\r
+               PrintToScrollback("   mask=%02x", mask);\r
+       }\r
+       PrintToScrollback("%d octets", k);\r
+\r
+       for(i = 0; i < k; i++) {\r
+               PrintToScrollback("# %2d: %02x ", i, outBuf[i]);\r
+       }\r
+       PrintToScrollback("CRC=%04x", Iso15693Crc(outBuf, k-2));\r
+}\r
+\r
+static void CmdTiread(char *str)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_ACQUIRE_RAW_BITS_TI_TYPE;\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdTibits(char *str)\r
+{\r
+       int cnt = 0;\r
+       int i;\r
+       for(i = 0; i < 1536; i += 12) {\r
+               UsbCommand c;\r
+               c.cmd = CMD_DOWNLOAD_RAW_BITS_TI_TYPE;\r
+               c.ext1 = i;\r
+               SendCommand(&c, FALSE);\r
+               ReceiveCommand(&c);\r
+               if(c.cmd != CMD_DOWNLOADED_RAW_BITS_TI_TYPE) {\r
+                       PrintToScrollback("bad resp\n");\r
+                       return;\r
+               }\r
+               int j;\r
+               for(j = 0; j < 12; j++) {\r
+                       int k;\r
+                       for(k = 31; k >= 0; k--) {\r
+                               if(c.d.asDwords[j] & (1 << k)) {\r
+                                       GraphBuffer[cnt++] = 1;\r
+                               } else {\r
+                                       GraphBuffer[cnt++] = -1;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       GraphTraceLen = 1536*32;\r
+       RepaintGraphWindow();\r
+}\r
+\r
+static void CmdTidemod(char *cmdline)\r
+{\r
+       /* MATLAB as follows:\r
+f_s = 2000000;  % sampling frequency\r
+f_l = 123200;   % low FSK tone\r
+f_h = 134200;   % high FSK tone\r
+\r
+T_l = 119e-6;   % low bit duration\r
+T_h = 130e-6;   % high bit duration\r
+\r
+l = 2*pi*ones(1, floor(f_s*T_l))*(f_l/f_s);\r
+h = 2*pi*ones(1, floor(f_s*T_h))*(f_h/f_s);\r
+\r
+l = sign(sin(cumsum(l)));\r
+h = sign(sin(cumsum(h)));\r
+       */\r
+       static const int LowTone[] = {\r
+               1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1,\r
+               1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
+               1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1,\r
+               -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1,\r
+               -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1,\r
+               -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1,\r
+               1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1,\r
+               1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
+               1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1,\r
+               -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1,\r
+               -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
+               -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1,\r
+               1, 1, 1, 1, 1, 1, 1, -1, -1, -1,\r
+       };\r
+       static const int HighTone[] = {\r
+               1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
+               1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,\r
+               -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
+               -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1,\r
+               1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
+               1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1,\r
+               -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
+               -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+               1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
+               1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,\r
+               -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
+               -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1,\r
+               1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
+               1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1,\r
+       };\r
+\r
+       int convLen = max(arraylen(HighTone), arraylen(LowTone));\r
+\r
+       int i;\r
+       for(i = 0; i < GraphTraceLen - convLen; i++) {\r
+               int j;\r
+               int lowSum = 0, highSum = 0;;\r
+               int lowLen = arraylen(LowTone);\r
+               int highLen = arraylen(HighTone);\r
+\r
+               for(j = 0; j < lowLen; j++) {\r
+                       lowSum += LowTone[j]*GraphBuffer[i+j];\r
+               }\r
+               for(j = 0; j < highLen; j++) {\r
+                       highSum += HighTone[j]*GraphBuffer[i+j];\r
+               }\r
+               lowSum = abs((100*lowSum) / lowLen);\r
+               highSum = abs((100*highSum) / highLen);\r
+               GraphBuffer[i] = (highSum << 16) | lowSum;\r
+       }\r
+\r
+       for(i = 0; i < GraphTraceLen - convLen - 16; i++) {\r
+               int j;\r
+               int lowTot = 0, highTot = 0;\r
+               // 16 and 15 are f_s divided by f_l and f_h, rounded\r
+               for(j = 0; j < 16; j++) {\r
+                       lowTot += (GraphBuffer[i+j] & 0xffff);\r
+               }\r
+               for(j = 0; j < 15; j++) {\r
+                       highTot += (GraphBuffer[i+j] >> 16);\r
+               }\r
+               GraphBuffer[i] = lowTot - highTot;\r
+       }\r
+\r
+       GraphTraceLen -= (convLen + 16);\r
+\r
+       RepaintGraphWindow();\r
+\r
+       // Okay, so now we have unsliced soft decisions; find bit-sync, and then\r
+       // get some bits.\r
+\r
+       int max = 0, maxPos = 0;\r
+       for(i = 0; i < 6000; i++) {\r
+               int j;\r
+               int dec = 0;\r
+               for(j = 0; j < 8*arraylen(LowTone); j++) {\r
+                       dec -= GraphBuffer[i+j];\r
+               }\r
+               for(; j < 8*arraylen(LowTone) + 8*arraylen(HighTone); j++) {\r
+                       dec += GraphBuffer[i+j];\r
+               }\r
+               if(dec > max) {\r
+                       max = dec;\r
+                       maxPos = i;\r
+               }\r
+       }\r
+       GraphBuffer[maxPos] = 800;\r
+       GraphBuffer[maxPos+1] = -800;\r
+\r
+       maxPos += 8*arraylen(LowTone);\r
+       GraphBuffer[maxPos] = 800;\r
+       GraphBuffer[maxPos+1] = -800;\r
+       maxPos += 8*arraylen(HighTone);\r
+\r
+       GraphBuffer[maxPos] = 800;\r
+       GraphBuffer[maxPos+1] = -800;\r
+\r
+       PrintToScrollback("actual data bits start at sample %d", maxPos);\r
+\r
+       PrintToScrollback("length %d/%d", arraylen(HighTone), arraylen(LowTone));\r
+\r
+       GraphBuffer[maxPos] = 800;\r
+       GraphBuffer[maxPos+1] = -800;\r
+\r
+       BYTE bits[64+16+8+1];\r
+       bits[sizeof(bits)-1] = '\0';\r
+\r
+       for(i = 0; i < arraylen(bits); i++) {\r
+               int high = 0;\r
+               int low = 0;\r
+               int j;\r
+               for(j = 0; j < arraylen(LowTone); j++) {\r
+                       low -= GraphBuffer[maxPos+j];\r
+               }\r
+               for(j = 0; j < arraylen(HighTone); j++) {\r
+                       high += GraphBuffer[maxPos+j];\r
+               }\r
+               if(high > low) {\r
+                       bits[i] = '1';\r
+                       maxPos += arraylen(HighTone);\r
+               } else {\r
+                       bits[i] = '.';\r
+                       maxPos += arraylen(LowTone);\r
+               }\r
+               GraphBuffer[maxPos] = 800;\r
+               GraphBuffer[maxPos+1] = -800;\r
+       }\r
+       PrintToScrollback("bits: '%s'", bits);\r
+\r
+       DWORD h = 0, l = 0;\r
+       for(i = 0; i < 32; i++) {\r
+               if(bits[i] == '1') {\r
+                       l |= (1<<i);\r
+               }\r
+       }\r
+       for(i = 32; i < 64; i++) {\r
+               if(bits[i] == '1') {\r
+                       h |= (1<<(i-32));\r
+               }\r
+       }\r
+       PrintToScrollback("hex: %08x %08x", h, l);\r
+}\r
+\r
+static void CmdNorm(char *str)\r
+{\r
+       int i;\r
+       int max = INT_MIN, min = INT_MAX;\r
+       for(i = 10; i < GraphTraceLen; i++) {\r
+               if(GraphBuffer[i] > max) {\r
+                       max = GraphBuffer[i];\r
+               }\r
+               if(GraphBuffer[i] < min) {\r
+                       min = GraphBuffer[i];\r
+               }\r
+       }\r
+       if(max != min) {\r
+               for(i = 0; i < GraphTraceLen; i++) {\r
+                       GraphBuffer[i] = (GraphBuffer[i] - ((max + min)/2))*1000/\r
+                               (max - min);\r
+               }\r
+       }\r
+       RepaintGraphWindow();\r
+}\r
+\r
+static void CmdDec(char *str)\r
+{\r
+       int i;\r
+       for(i = 0; i < (GraphTraceLen/2); i++) {\r
+               GraphBuffer[i] = GraphBuffer[i*2];\r
+       }\r
+       GraphTraceLen /= 2;\r
+       PrintToScrollback("decimated by 2");\r
+       RepaintGraphWindow();\r
+}\r
+\r
+static void CmdHpf(char *str)\r
+{\r
+       int i;\r
+       int accum = 0;\r
+       for(i = 10; i < GraphTraceLen; i++) {\r
+               accum += GraphBuffer[i];\r
+       }\r
+       accum /= (GraphTraceLen - 10);\r
+       for(i = 0; i < GraphTraceLen; i++) {\r
+               GraphBuffer[i] -= accum;\r
+       }\r
+\r
+       RepaintGraphWindow();\r
+}\r
+\r
+static void CmdZerocrossings(char *str)\r
+{\r
+       int i;\r
+       // Zero-crossings aren't meaningful unless the signal is zero-mean.\r
+       CmdHpf("");\r
+\r
+       int sign = 1;\r
+       int zc = 0;\r
+       int lastZc = 0;\r
+       for(i = 0; i < GraphTraceLen; i++) {\r
+               if(GraphBuffer[i]*sign >= 0) {\r
+                       // No change in sign, reproduce the previous sample count.\r
+                       zc++;\r
+                       GraphBuffer[i] = lastZc;\r
+               } else {\r
+                       // Change in sign, reset the sample count.\r
+                       sign = -sign;\r
+                       GraphBuffer[i] = lastZc;\r
+                       if(sign > 0) {\r
+                               lastZc = zc;\r
+                               zc = 0;\r
+                       }\r
+               }\r
+       }\r
+\r
+       RepaintGraphWindow();\r
+}\r
+\r
+static void CmdLtrim(char *str)\r
+{\r
+       int i;\r
+       int ds = atoi(str);\r
+\r
+       for(i = ds; i < GraphTraceLen; i++) {\r
+               GraphBuffer[i-ds] = GraphBuffer[i];\r
+       }\r
+       GraphTraceLen -= ds;\r
+\r
+       RepaintGraphWindow();\r
+}\r
+\r
+static void CmdAutoCorr(char *str)\r
+{\r
+       static int CorrelBuffer[MAX_GRAPH_TRACE_LEN];\r
+\r
+       int window = atoi(str);\r
+\r
+       if(window == 0) {\r
+               PrintToScrollback("needs a window");\r
+               return;\r
+       }\r
+\r
+       if(window >= GraphTraceLen) {\r
+               PrintToScrollback("window must be smaller than trace (%d samples)",\r
+                       GraphTraceLen);\r
+               return;\r
+       }\r
+\r
+       PrintToScrollback("performing %d correlations", GraphTraceLen - window);\r
+\r
+       int i;\r
+       for(i = 0; i < GraphTraceLen - window; i++) {\r
+               int sum = 0;\r
+               int j;\r
+               for(j = 0; j < window; j++) {\r
+                       sum += (GraphBuffer[j]*GraphBuffer[i+j]) / 256;\r
+               }\r
+               CorrelBuffer[i] = sum;\r
+       }\r
+       GraphTraceLen = GraphTraceLen - window;\r
+       memcpy(GraphBuffer, CorrelBuffer, GraphTraceLen*sizeof(int));\r
+\r
+       RepaintGraphWindow();\r
+}\r
+\r
+static void CmdVchdemod(char *str)\r
+{\r
+       // Is this the entire sync pattern, or does this also include some\r
+       // data bits that happen to be the same everywhere? That would be\r
+       // lovely to know.\r
+       static const int SyncPattern[] = {\r
+               1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,\r
+               1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+               1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,\r
+               1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+               1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,\r
+               1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+               1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,\r
+               1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+               1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,\r
+               1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+       };\r
+\r
+       // So first, we correlate for the sync pattern, and mark that.\r
+       int bestCorrel = 0, bestPos = 0;\r
+       int i;\r
+       // It does us no good to find the sync pattern, with fewer than\r
+       // 2048 samples after it...\r
+       for(i = 0; i < (GraphTraceLen-2048); i++) {\r
+               int sum = 0;\r
+               int j;\r
+               for(j = 0; j < arraylen(SyncPattern); j++) {\r
+                       sum += GraphBuffer[i+j]*SyncPattern[j];\r
+               }\r
+               if(sum > bestCorrel) {\r
+                       bestCorrel = sum;\r
+                       bestPos = i;\r
+               }\r
+       }\r
+       PrintToScrollback("best sync at %d [metric %d]", bestPos, bestCorrel);\r
+\r
+       char bits[257];\r
+       bits[256] = '\0';\r
+\r
+       int worst = INT_MAX;\r
+       int worstPos;\r
+\r
+       for(i = 0; i < 2048; i += 8) {\r
+               int sum = 0;\r
+               int j;\r
+               for(j = 0; j < 8; j++) {\r
+                       sum += GraphBuffer[bestPos+i+j];\r
+               }\r
+               if(sum < 0) {\r
+                       bits[i/8] = '.';\r
+               } else {\r
+                       bits[i/8] = '1';\r
+               }\r
+               if(abs(sum) < worst) {\r
+                       worst = abs(sum);\r
+                       worstPos = i;\r
+               }\r
+       }\r
+       PrintToScrollback("bits:");\r
+       PrintToScrollback("%s", bits);\r
+       PrintToScrollback("worst metric: %d at pos %d", worst, worstPos);\r
+\r
+       if(strcmp(str, "clone")==0) {\r
+               GraphTraceLen = 0;\r
+               char *s;\r
+               for(s = bits; *s; s++) {\r
+                       int j;\r
+                       for(j = 0; j < 16; j++) {\r
+                               GraphBuffer[GraphTraceLen++] = (*s == '1') ? 1 : 0;\r
+                       }\r
+               }\r
+               RepaintGraphWindow();\r
+       }\r
+}\r
+\r
+static void CmdFlexdemod(char *str)\r
+{\r
+       int i;\r
+       for(i = 0; i < GraphTraceLen; i++) {\r
+               if(GraphBuffer[i] < 0) {\r
+                       GraphBuffer[i] = -1;\r
+               } else {\r
+                       GraphBuffer[i] = 1;\r
+               }\r
+       }\r
+\r
+#define LONG_WAIT 100\r
+       int start;\r
+       for(start = 0; start < GraphTraceLen - LONG_WAIT; start++) {\r
+               int first = GraphBuffer[start];\r
+               for(i = start; i < start + LONG_WAIT; i++) {\r
+                       if(GraphBuffer[i] != first) {\r
+                               break;\r
+                       }\r
+               }\r
+               if(i == (start + LONG_WAIT)) {\r
+                       break;\r
+               }\r
+       }\r
+       if(start == GraphTraceLen - LONG_WAIT) {\r
+               PrintToScrollback("nothing to wait for");\r
+               return;\r
+       }\r
+\r
+       GraphBuffer[start] = 2;\r
+       GraphBuffer[start+1] = -2;\r
+\r
+       BYTE bits[64];\r
+\r
+       int bit;\r
+       i = start;\r
+       for(bit = 0; bit < 64; bit++) {\r
+               int j;\r
+               int sum = 0;\r
+               for(j = 0; j < 16; j++) {\r
+                       sum += GraphBuffer[i++];\r
+               }\r
+               if(sum > 0) {\r
+                       bits[bit] = 1;\r
+               } else {\r
+                       bits[bit] = 0;\r
+               }\r
+               PrintToScrollback("bit %d sum %d", bit, sum);\r
+       }\r
+\r
+       for(bit = 0; bit < 64; bit++) {\r
+               int j;\r
+               int sum = 0;\r
+               for(j = 0; j < 16; j++) {\r
+                       sum += GraphBuffer[i++];\r
+               }\r
+               if(sum > 0 && bits[bit] != 1) {\r
+                       PrintToScrollback("oops1 at %d", bit);\r
+               }\r
+               if(sum < 0 && bits[bit] != 0) {\r
+                       PrintToScrollback("oops2 at %d", bit);\r
+               }\r
+       }\r
+\r
+       GraphTraceLen = 32*64;\r
+       i = 0;\r
+       int phase = 0;\r
+       for(bit = 0; bit < 64; bit++) {\r
+               if(bits[bit] == 0) {\r
+                       phase = 0;\r
+               } else {\r
+                       phase = 1;\r
+               }\r
+               int j;\r
+               for(j = 0; j < 32; j++) {\r
+                       GraphBuffer[i++] = phase;\r
+                       phase = !phase;\r
+               }\r
+       }\r
+\r
+       RepaintGraphWindow();\r
+}\r
+
+/*
+ * Generic command to demodulate ASK. bit length in argument.
+ * Giving the bit length helps discriminate ripple effects
+ * upon zero crossing for noisy traces.
+ *
+ * Second is convention: positive or negative (High mod means zero
+ * or high mod means one)
+ *
+ * Updates the Graph trace with 0/1 values
+ *
+ * Arguments:
+ * sl : bit length in terms of number of samples per bit
+ *      (use yellow/purple markers to compute).
+ * c : 0 or 1
+ */
+
+static void Cmdaskdemod(char *str) {
+       int i;
+       int sign = 1;
+       int n = 0;
+       int c = 0;\r
+       int t1 = 0;
+
+       // TODO: complain if we do not give 2 arguments here !
+       sscanf(str, "%i %i", &n, &c);
+       if (c == 0) {
+               c = 1 ;
+       } else {
+               c = -1;
+       }
+
+       if (GraphBuffer[0]*c > 0) {
+               GraphBuffer[0] = 1;
+       } else {
+               GraphBuffer[0] = 0;
+       }
+       for(i=1;i<GraphTraceLen;i++) {
+               /* Analyse signal within the symbol length */
+               /* Decide if we crossed a zero */
+               if (GraphBuffer[i]*sign < 0) {
+                        /* Crossed a zero, check if this is a ripple or not */
+                       if ( (i-t1) > n/4 ) {
+                               sign = -sign;
+                               t1=i;
+                               if (GraphBuffer[i]*c > 0){
+                                       GraphBuffer[i]=1;
+                               } else {
+                                       GraphBuffer[i]=0;
+                               }
+                       } else {
+                       /* This is a ripple, set the current sample value
+                          to the same as previous */
+                               GraphBuffer[i] = GraphBuffer[i-1];
+                       }
+               } else {
+                       GraphBuffer[i] = GraphBuffer[i-1];
+               }
+       }
+       RepaintGraphWindow();
+}
+
+
+/*
+ * Manchester demodulate a bitstream. The bitstream needs to be already in
+ * the GraphBuffer as 0 and 1 values
+ *
+ * Give the clock rate as argument in order to help the sync - the algorithm
+ * resyncs at each pulse anyway.
+ *
+ * Not optimized by any means, this is the 1st time I'm writing this type of
+ * routine, feel free to improve...
+ *
+ * 1st argument: clock rate (as number of samples per clock rate)
+ */
+static void Cmdmanchesterdemod(char *str) {
+       int i;
+       int clock;
+       int grouping=16;
+       int lastval;
+       int lc = 0;
+       int bitidx = 0;
+       int bitidx2;
+
+
+       sscanf(str, "%i", &clock);
+
+       int tolerance = clock/4;
+       /* Holds the decoded bitstream. */
+       int BitStream[MAX_GRAPH_TRACE_LEN*2];
+       int BitStream2[MAX_GRAPH_TRACE_LEN];
+
+       /* Detect first transition */
+       /* Lo-Hi (arbitrary) */
+       for(i=1;i<GraphTraceLen;i++) {
+               if (GraphBuffer[i-1]<GraphBuffer[i]) {
+               lastval = i;
+               BitStream[0]=0; // Previous state = 0;
+               break;
+               }
+       }
+
+       /* Then detect duration between 2 successive transitions */
+       /* At this stage, GraphTrace is either 0 or 1 */
+       for(bitidx = 1 ;i<GraphTraceLen;i++) {
+               if (GraphBuffer[i-1] != GraphBuffer[i]) {
+                       lc = i-lastval;
+                       lastval = i;
+                       // Then switch depending on lc length:
+                       // Tolerance is 1/4 of clock rate (arbitrary)
+                       if ((lc-clock/2) < tolerance) {
+                               // Short pulse
+                               BitStream[bitidx++]=GraphBuffer[i-1];
+                       } else if ((lc-clock) < tolerance) {
+                               // Long pulse
+                               BitStream[bitidx++]=GraphBuffer[i-1];
+                               BitStream[bitidx++]=GraphBuffer[i-1];
+                       } else {
+                               // Error
+                               PrintToScrollback("Warning: Manchester decode error for pulse width detection.");                               
+                               PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)");
+                       }
+               }
+       }
+
+       // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream
+       for (bitidx2 = 0; bitidx2<bitidx; bitidx2 += 2) {
+               if ((BitStream[bitidx2] == 0) && (BitStream[bitidx2+1] == 1)) {
+                       BitStream2[bitidx2/2] = 1;
+               } else if ((BitStream[bitidx2] == 1) && (BitStream[bitidx2+1] == 0)) {
+                       BitStream2[bitidx2/2] = 0;
+               } else {
+                       // We cannot end up in this stage, this means we are unsynchronized,
+                       // move up 1 bit:
+                       bitidx2++;
+                       PrintToScrollback("Unsynchronized, resync...");
+                       PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)");
+               }
+       }
+       PrintToScrollback("Manchester decoded bitstream \n---------");
+       // Now output the bitstream to the scrollback by line of 16 bits
+       for (i = 0; i<bitidx/2; i+=16) {
+               PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
+                       BitStream2[i],
+                       BitStream2[i+1],
+                       BitStream2[i+2],
+                       BitStream2[i+3],
+                       BitStream2[i+4],
+                       BitStream2[i+5],
+                       BitStream2[i+6],
+                       BitStream2[i+7],
+                       BitStream2[i+8],
+                       BitStream2[i+9],
+                       BitStream2[i+10],
+                       BitStream2[i+11],
+                       BitStream2[i+12],
+                       BitStream2[i+13],
+                       BitStream2[i+14],
+                       BitStream2[i+15]);
+       }
+}
+
+
+
+/*
+ * Usage ???
+ */\r
+static void CmdHiddemod(char *str)\r
+{\r
+       if(GraphTraceLen < 4800) {\r
+               PrintToScrollback("too short; need at least 4800 samples");\r
+               return;\r
+       }\r
+\r
+       GraphTraceLen = 4800;\r
+       int i;\r
+       for(i = 0; i < GraphTraceLen; i++) {\r
+               if(GraphBuffer[i] < 0) {\r
+                       GraphBuffer[i] = 0;\r
+               } else {\r
+                       GraphBuffer[i] = 1;\r
+               }\r
+       }\r
+       RepaintGraphWindow();\r
+}\r
+\r
+static void CmdPlot(char *str)\r
+{\r
+       ShowGraphWindow();\r
+}\r
+\r
+static void CmdHide(char *str)\r
+{\r
+       HideGraphWindow();\r
+}\r
+\r
+static void CmdScale(char *str)\r
+{\r
+       CursorScaleFactor = atoi(str);\r
+       if(CursorScaleFactor == 0) {\r
+               PrintToScrollback("bad, can't have zero scale");\r
+               CursorScaleFactor = 1;\r
+       }\r
+       RepaintGraphWindow();\r
+}\r
+\r
+static void CmdSave(char *str)\r
+{\r
+       FILE *f = fopen(str, "w");\r
+       if(!f) {\r
+               PrintToScrollback("couldn't open '%s'", str);\r
+               return;\r
+       }\r
+       int i;\r
+       for(i = 0; i < GraphTraceLen; i++) {\r
+               fprintf(f, "%d\n", GraphBuffer[i]);\r
+       }\r
+       fclose(f);\r
+       PrintToScrollback("saved to '%s'", str);\r
+}\r
+\r
+static void CmdLoad(char *str)\r
+{\r
+       FILE *f = fopen(str, "r");\r
+       if(!f) {\r
+               PrintToScrollback("couldn't open '%s'", str);\r
+               return;\r
+       }\r
+\r
+       GraphTraceLen = 0;\r
+       char line[80];\r
+       while(fgets(line, sizeof(line), f)) {\r
+               GraphBuffer[GraphTraceLen] = atoi(line);\r
+               GraphTraceLen++;\r
+       }\r
+       fclose(f);\r
+       PrintToScrollback("loaded %d samples", GraphTraceLen);\r
+       RepaintGraphWindow();\r
+}\r
+\r
+static void CmdHIDsimTAG(char *str)\r
+{\r
+       unsigned int hi=0, lo=0;\r
+       int n=0, i=0;\r
+       UsbCommand c;\r
+\r
+       while (sscanf(&str[i++], "%1x", &n ) == 1) {\r
+               hi=(hi<<4)|(lo>>28);\r
+               lo=(lo<<4)|(n&0xf);\r
+       }\r
+\r
+       PrintToScrollback("Emulating tag with ID %x%16x", hi, lo);\r
+\r
+       c.cmd = CMD_HID_SIM_TAG;\r
+       c.ext1 = hi;\r
+       c.ext2 = lo;\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdLcdReset(char *str)\r
+{\r
+       UsbCommand c;\r
+       c.cmd = CMD_LCD_RESET;\r
+       c.ext1 = atoi(str);\r
+       SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdLcd(char *str)\r
+{\r
+       int i, j;\r
+       UsbCommand c;\r
+       c.cmd = CMD_LCD;\r
+       sscanf(str, "%x %d", &i, &j);\r
+       while (j--) {\r
+               c.ext1 = i&0x1ff;\r
+               SendCommand(&c, FALSE);\r
+       }\r
+}\r
+\r
+static void CmdTest(char *str)\r
+{\r
+}\r
+\r
+typedef void HandlerFunction(char *cmdline);\r
+\r
+static struct {\r
+       char                    *name;\r
+       HandlerFunction         *handler;\r
+       char                    *docString;\r
+} CommandTable[] = {\r
+       "tune",                         CmdTune,                        "measure antenna tuning",\r
+       "tiread",                       CmdTiread,                      "read a TI-type 134 kHz tag",\r
+       "tibits",                       CmdTibits,                      "get raw bits for TI-type LF tag",\r
+       "tidemod",                      CmdTidemod,                     "demod raw bits for TI-type LF tag",\r
+       "vchdemod",                     CmdVchdemod,            "demod samples for VeriChip",\r
+       "plot",                         CmdPlot,                        "show graph window",\r
+       "hide",                         CmdHide,                        "hide graph window",\r
+       "losim",                        CmdLosim,                       "simulate LF tag",\r
+       "loread",                       CmdLoread,                      "read (125/134 kHz) LF ID-only tag",\r
+       "losamples",            CmdLosamples,           "get raw samples for LF tag",\r
+       "hisamples",            CmdHisamples,           "get raw samples for HF tag",\r
+       "hisampless",           CmdHisampless,          "get signed raw samples, HF tag",\r
+       "hisamplest",           CmdHi14readt,           "get samples HF, for testing",\r
+       "higet",                        CmdHi14read_sim,        "get samples HF, 'analog'",\r
+       "bitsamples",           CmdBitsamples,          "get raw samples as bitstring",\r
+       "hexsamples",           CmdHexsamples,          "dump big buffer as hex bytes",\r
+       "hi15read",                     CmdHi15read,            "read HF tag (ISO 15693)",\r
+       "hi15reader",                   CmdHi15reader,          "act like an ISO15693 reader", // new command greg\r
+       "hi15sim",                      CmdHi15tag,             "fake an ISO15693 tag", // new command greg\r
+       "hi14read",                     CmdHi14read,            "read HF tag (ISO 14443)",\r
+       "hi14areader",          CmdHi14areader,         "act like an ISO14443 Type A reader",   // ## New reader command\r
+       "hi15demod",            CmdHi15demod,           "demod ISO15693 from tag",\r
+       "hi14bdemod",           CmdHi14bdemod,          "demod ISO14443 Type B from tag",\r
+       "autocorr",                     CmdAutoCorr,            "autocorrelation over window",\r
+       "norm",                         CmdNorm,                        "normalize max/min to +/-500",\r
+       "dec",                          CmdDec,                         "decimate",\r
+       "hpf",                          CmdHpf,                         "remove DC offset from trace",\r
+       "zerocrossings",        CmdZerocrossings,       "count time between zero-crossings",\r
+       "ltrim",                        CmdLtrim,                       "trim from left of trace",\r
+       "scale",                        CmdScale,                       "set cursor display scale",\r
+       "flexdemod",            CmdFlexdemod,           "demod samples for FlexPass",\r
+       "save",                         CmdSave,                        "save trace (from graph window)",\r
+       "load",                         CmdLoad,                        "load trace (to graph window",\r
+       "hisimlisten",          CmdHisimlisten,         "get HF samples as fake tag",\r
+       "hi14sim",                      CmdHi14sim,                     "fake ISO 14443 tag",\r
+       "hi14asim",                     CmdHi14asim,            "fake ISO 14443a tag",                                  // ## Simulate 14443a tag\r
+       "hi14snoop",            CmdHi14snoop,           "eavesdrop ISO 14443",\r
+       "hi14asnoop",           CmdHi14asnoop,          "eavesdrop ISO 14443 Type A",                   // ## New snoop command\r
+       "hi14list",                     CmdHi14list,            "list ISO 14443 history",\r
+       "hi14alist",            CmdHi14alist,           "list ISO 14443a history",                              // ## New list command\r
+       "hiddemod",                     CmdHiddemod,            "HID Prox Card II (not optimal)",\r
+       "hidfskdemod",          CmdHIDdemodFSK,         "HID FSK demodulator",\r
+       "askdemod",             Cmdaskdemod,            "Attempt to demodulate simple ASK tags",
+       "hidsimtag",            CmdHIDsimTAG,           "HID tag simulator",
+       "mandemod",             Cmdmanchesterdemod,     "Try a Manchester demodulation on a binary stream",
+       "fpgaoff",                      CmdFPGAOff,                     "set FPGA off",                                                 // ## FPGA Control\r
+       "lcdreset",                     CmdLcdReset,            "Hardware reset LCD",\r
+       "lcd",                          CmdLcd,                         "Send command/data to LCD",\r
+       "test",                         CmdTest,                        "Placeholder command for testing new code",\r
+       "quit",                         CmdQuit,                        "quit program"\r
+};\r
+\r
+//-----------------------------------------------------------------------------\r
+// Entry point into our code: called whenever the user types a command and\r
+// then presses Enter, which the full command line that they typed.\r
+//-----------------------------------------------------------------------------\r
+void CommandReceived(char *cmd)\r
+{\r
+       int i;\r
+\r
+       PrintToScrollback("> %s", cmd);\r
+\r
+       if(strcmp(cmd, "help")==0) {\r
+               PrintToScrollback("\r\nAvailable commands:");\r
+               for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) {\r
+                       char line[256];\r
+                       memset(line, ' ', sizeof(line));\r
+                       strcpy(line+2, CommandTable[i].name);\r
+                       line[strlen(line)] = ' ';\r
+                       sprintf(line+15, " -- %s", CommandTable[i].docString);\r
+                       PrintToScrollback("%s", line);\r
+               }\r
+               PrintToScrollback("");\r
+               PrintToScrollback("and also: help, cls");\r
+               return;\r
+       }\r
+\r
+       for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) {\r
+               char *name = CommandTable[i].name;\r
+               if(memcmp(cmd, name, strlen(name))==0 &&\r
+                       (cmd[strlen(name)] == ' ' || cmd[strlen(name)] == '\0'))\r
+               {\r
+                       cmd += strlen(name);\r
+                       while(*cmd == ' ') {\r
+                               cmd++;\r
+                       }\r
+                       (CommandTable[i].handler)(cmd);\r
+                       return;\r
+               }\r
+       }\r
+       PrintToScrollback(">> bad command '%s'", cmd);\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Entry point into our code: called whenever we received a packet over USB\r
+// that we weren't necessarily expecting, for example a debug print.\r
+//-----------------------------------------------------------------------------\r
+void UsbCommandReceived(UsbCommand *c)\r
+{\r
+       switch(c->cmd) {\r
+               case CMD_DEBUG_PRINT_STRING: {\r
+                       char s[100];\r
+                       if(c->ext1 > 70 || c->ext1 < 0) {\r
+                               c->ext1 = 0;\r
+                       }\r
+                       memcpy(s, c->d.asBytes, c->ext1);\r
+                       s[c->ext1] = '\0';\r
+                       PrintToScrollback("#db# %s", s);\r
+                       break;
+               }\r
+\r
+               case CMD_DEBUG_PRINT_INTEGERS:\r
+                       PrintToScrollback("#db# %08x, %08x, %08x\r\n", c->ext1, c->ext2, c->ext3);\r
+                       break;\r
+\r
+               case CMD_MEASURED_ANTENNA_TUNING: {\r
+                       int zLf, zHf;\r
+                       int vLf125, vLf134, vHf;\r
+                       vLf125 = c->ext1 & 0xffff;\r
+                       vLf134 = c->ext1 >> 16;\r
+                       vHf = c->ext2;\r
+                       zLf = c->ext3 & 0xffff;\r
+                       zHf = c->ext3 >> 16;\r
+                       PrintToScrollback("# LF antenna @ %3d mA / %5d mV [%d ohms] 125Khz",\r
+                               vLf125/zLf, vLf125, zLf);\r
+                       PrintToScrollback("# LF antenna @ %3d mA / %5d mV [%d ohms] 134Khz",\r
+                               vLf134/((zLf*125)/134), vLf134, (zLf*125)/134);\r
+                       PrintToScrollback("# HF antenna @ %3d mA / %5d mV [%d ohms] 13.56Mhz",\r
+                               vHf/zHf, vHf, zHf);\r
+                       break;\r
+               }\r
+               default:\r
+                       PrintToScrollback("unrecognized command %08x\n", c->cmd);\r
+                       break;\r
+       }\r
+}\r
diff --git a/winsrc/gui.cpp b/winsrc/gui.cpp
new file mode 100644 (file)
index 0000000..e4e530b
--- /dev/null
@@ -0,0 +1,510 @@
+//-----------------------------------------------------------------------------\r
+// Routines for the user interface when doing interactive things with prox\r
+// cards; this is basically a command line thing, in one window, and then\r
+// another window to do the graphs.\r
+// Jonathan Westhues, Sept 2005\r
+//-----------------------------------------------------------------------------\r
+#include <windows.h>\r
+#include <limits.h>\r
+#include <commctrl.h>\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <math.h>\r
+\r
+#include "prox.h"\r
+\r
+#define oops() do { \\r
+       char line[100]; \\r
+       sprintf(line, "Internal error at line %d file '%s'", __LINE__, \\r
+               __FILE__); \\r
+       MessageBox(NULL, line, "Error", MB_ICONERROR); \\r
+       exit(-1); \\r
+} while(0)\r
+\r
+void dbp(char *str, ...)\r
+{\r
+       va_list f;\r
+       char buf[1024];\r
+       va_start(f, str);\r
+       vsprintf(buf, str, f);\r
+       OutputDebugString(buf);\r
+       OutputDebugString("\n");\r
+}\r
+\r
+int GraphBuffer[MAX_GRAPH_TRACE_LEN];\r
+int GraphTraceLen;\r
+\r
+HPEN GreyPen, GreenPen, WhitePen, YellowPen;\r
+HBRUSH GreenBrush, YellowBrush;\r
+\r
+static int GraphStart = 0;\r
+static double GraphPixelsPerPoint = 1;\r
+\r
+static int CursorAPos;\r
+static int CursorBPos;\r
+double CursorScaleFactor = 1.0;\r
+static HPEN CursorAPen;\r
+static HPEN CursorBPen;\r
+\r
+static HWND CommandWindow;\r
+static HWND GraphWindow;\r
+static HWND ScrollbackEdit;\r
+static HWND CommandEdit;\r
+\r
+#define COMMAND_HISTORY_MAX 16\r
+static char CommandHistory[COMMAND_HISTORY_MAX][256];\r
+static int CommandHistoryPos = -1;\r
+static int CommandHistoryNext;\r
+\r
+static HFONT MyFixedFont;\r
+#define FixedFont(x) SendMessage((x), WM_SETFONT, (WPARAM)MyFixedFont, TRUE)\r
+\r
+void ExecCmd(char *cmd)\r
+{\r
+\r
+}\r
+int CommandFinished;\r
+\r
+static void ResizeCommandWindow(void)\r
+{\r
+       int w, h;\r
+       RECT r;\r
+       GetClientRect(CommandWindow, &r);\r
+       w = r.right - r.left;\r
+       h = r.bottom - r.top;\r
+       MoveWindow(ScrollbackEdit, 10, 10, w - 20, h - 50, TRUE);\r
+       MoveWindow(CommandEdit, 10, h - 29, w - 20, 22, TRUE);\r
+}\r
+\r
+void RepaintGraphWindow(void)\r
+{\r
+       InvalidateRect(GraphWindow, NULL, TRUE);\r
+}\r
+\r
+static LRESULT CALLBACK\r
+       CommandWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
+{\r
+       switch (msg) {\r
+               case WM_DESTROY:\r
+               case WM_QUIT:\r
+                       exit(0);\r
+                       return 0;\r
+\r
+               case WM_SIZE:\r
+                       ResizeCommandWindow();\r
+                       return 0;\r
+\r
+               case WM_SETFOCUS:\r
+                       SetFocus(CommandEdit);\r
+                       break;\r
+\r
+               default:\r
+                       return DefWindowProc(hwnd, msg, wParam, lParam);\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+static void PaintGraph(HDC hdc)\r
+{\r
+       HBRUSH brush;\r
+       HPEN pen;\r
+\r
+       brush = GreenBrush;\r
+       pen = GreenPen;\r
+\r
+       if(GraphStart < 0) {\r
+               GraphStart = 0;\r
+       }\r
+\r
+       RECT r;\r
+       GetClientRect(GraphWindow, &r);\r
+\r
+       SelectObject(hdc, WhitePen);\r
+\r
+       MoveToEx(hdc, r.left + 40, r.top, NULL);\r
+       LineTo(hdc, r.left + 40, r.bottom);\r
+\r
+       int zeroHeight = r.top + (r.bottom - r.top) / 2;\r
+       SelectObject(hdc, GreyPen);\r
+       MoveToEx(hdc, r.left, zeroHeight, NULL);\r
+       LineTo(hdc, r.right, zeroHeight);\r
+\r
+       int startMax =\r
+               (GraphTraceLen - (int)((r.right - r.left - 40) / GraphPixelsPerPoint));\r
+       if(startMax < 0) {\r
+               startMax = 0;\r
+       }\r
+       if(GraphStart > startMax) {\r
+               GraphStart = startMax;\r
+       }\r
+\r
+       int absYMax = 1;\r
+\r
+       SelectObject(hdc, pen);\r
+\r
+       int i;\r
+       for(i = GraphStart; ; i++) {\r
+               if(i >= GraphTraceLen) {\r
+                       break;\r
+               }\r
+               if(fabs((double)GraphBuffer[i]) > absYMax) {\r
+                       absYMax = (int)fabs((double)GraphBuffer[i]);\r
+               }\r
+               int x = 40 + (int)((i - GraphStart)*GraphPixelsPerPoint);\r
+               if(x > r.right) {\r
+                       break;\r
+               }\r
+       }\r
+\r
+       absYMax = (int)(absYMax*1.2 + 1);\r
+       SelectObject(hdc, MyFixedFont);\r
+       SetTextColor(hdc, RGB(255, 255, 255));\r
+       SetBkColor(hdc, RGB(0, 0, 0));\r
+\r
+       // number of points that will be plotted\r
+       int span = (int)((r.right - r.left) / GraphPixelsPerPoint);\r
+       // one label every 100 pixels, let us say\r
+       int labels = (r.right - r.left - 40) / 100;\r
+       if(labels <= 0) labels = 1;\r
+       int pointsPerLabel = span / labels;\r
+       if(pointsPerLabel <= 0) pointsPerLabel = 1;\r
+\r
+       int yMin = INT_MAX;\r
+       int yMax = INT_MIN;\r
+       int yMean = 0;\r
+       int n = 0;\r
+\r
+       for(i = GraphStart; ; i++) {\r
+               if(i >= GraphTraceLen) {\r
+                       break;\r
+               }\r
+               int x = 40 + (int)((i - GraphStart)*GraphPixelsPerPoint);\r
+               if(x > r.right + GraphPixelsPerPoint) {\r
+                       break;\r
+               }\r
+\r
+               int y = GraphBuffer[i];\r
+               if(y < yMin) {\r
+                       yMin = y;\r
+               }\r
+               if(y > yMax) {\r
+                       yMax = y;\r
+               }\r
+               yMean += y;\r
+               n++;\r
+\r
+               y = (y * (r.top - r.bottom) / (2*absYMax)) + zeroHeight;\r
+               if(i == GraphStart) {\r
+                       MoveToEx(hdc, x, y, NULL);\r
+               } else {\r
+                       LineTo(hdc, x, y);\r
+               }\r
+\r
+               if(GraphPixelsPerPoint > 10) {\r
+                       RECT f;\r
+                       f.left = x - 3;\r
+                       f.top = y - 3;\r
+                       f.right = x + 3;\r
+                       f.bottom = y + 3;\r
+                       FillRect(hdc, &f, brush);\r
+               }\r
+\r
+               if(((i - GraphStart) % pointsPerLabel == 0) && i != GraphStart) {\r
+                       SelectObject(hdc, WhitePen);\r
+                       MoveToEx(hdc, x, zeroHeight - 3, NULL);\r
+                       LineTo(hdc, x, zeroHeight + 3);\r
+\r
+                       char str[100];\r
+                       sprintf(str, "+%d", (i - GraphStart));\r
+                       SIZE size;\r
+                       GetTextExtentPoint32(hdc, str, strlen(str), &size);\r
+                       TextOut(hdc, x - size.cx, zeroHeight + 8, str, strlen(str));\r
+\r
+                       SelectObject(hdc, pen);\r
+                       MoveToEx(hdc, x, y, NULL);\r
+               }\r
+\r
+               if(i == CursorAPos || i == CursorBPos) {\r
+                       if(i == CursorAPos) {\r
+                               SelectObject(hdc, CursorAPen);\r
+                       } else {\r
+                               SelectObject(hdc, CursorBPen);\r
+                       }\r
+                       MoveToEx(hdc, x, r.top, NULL);\r
+                       LineTo(hdc, x, r.bottom);\r
+\r
+                       SelectObject(hdc, pen);\r
+                       MoveToEx(hdc, x, y, NULL);\r
+               }\r
+       }\r
+\r
+       if(n != 0) {\r
+               yMean /= n;\r
+       }\r
+\r
+       char str[100];\r
+       sprintf(str, "@%d   max=%d min=%d mean=%d n=%d/%d    dt=%d [%.3f]",\r
+               GraphStart, yMax, yMin, yMean, n, GraphTraceLen,\r
+               CursorBPos - CursorAPos, (CursorBPos - CursorAPos)/CursorScaleFactor);\r
+       TextOut(hdc, 50, r.bottom - 20, str, strlen(str));\r
+}\r
+\r
+static LRESULT CALLBACK\r
+       GraphWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
+{\r
+       switch (msg) {\r
+               case WM_DESTROY:\r
+               case WM_QUIT:\r
+                       GraphWindow = NULL;\r
+                       return DefWindowProc(hwnd, msg, wParam, lParam);\r
+\r
+               case WM_SIZE:\r
+                       RepaintGraphWindow();\r
+                       return 0;\r
+\r
+               case WM_PAINT: {\r
+                       PAINTSTRUCT ps;\r
+                       HDC hdc = BeginPaint(hwnd, &ps);\r
+                       if(GraphStart < 0) {\r
+                               GraphStart = 0;\r
+                       }\r
+                       // This draws the trace.\r
+                       PaintGraph(hdc);\r
+                       EndPaint(hwnd, &ps);\r
+                       break;\r
+               }\r
+               case WM_KEYDOWN:\r
+                       switch(wParam) {\r
+                               case VK_DOWN:\r
+                                       if(GraphPixelsPerPoint <= 50) {\r
+                                               GraphPixelsPerPoint *= 2;\r
+                                       }\r
+                                       break;\r
+\r
+                               case VK_UP:\r
+                                       if(GraphPixelsPerPoint >= 0.02) {\r
+                                               GraphPixelsPerPoint /= 2;\r
+                                       }\r
+                                       break;\r
+\r
+                               case VK_RIGHT:\r
+                                       if(GraphPixelsPerPoint < 20) {\r
+                                               GraphStart += (int)(20 / GraphPixelsPerPoint);\r
+                                       } else {\r
+                                               GraphStart++;\r
+                                       }\r
+                                       break;\r
+\r
+                               case VK_LEFT:\r
+                                       if(GraphPixelsPerPoint < 20) {\r
+                                               GraphStart -= (int)(20 / GraphPixelsPerPoint);\r
+                                       } else {\r
+                                               GraphStart--;\r
+                                       }\r
+                                       break;\r
+\r
+                               default:\r
+                                       goto nopaint;\r
+                       }\r
+                       RepaintGraphWindow();\r
+nopaint:\r
+                       break;\r
+\r
+               case WM_LBUTTONDOWN:\r
+               case WM_RBUTTONDOWN: {\r
+                       int x = LOWORD(lParam);\r
+                       x -= 40;\r
+                       x = (int)(x / GraphPixelsPerPoint);\r
+                       x += GraphStart;\r
+                       if(msg == WM_LBUTTONDOWN) {\r
+                               CursorAPos = x;\r
+                       } else {\r
+                               CursorBPos = x;\r
+                       }\r
+                       RepaintGraphWindow();\r
+                       break;\r
+               }\r
+               default:\r
+                       return DefWindowProc(hwnd, msg, wParam, lParam);\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+void PrintToScrollback(char *fmt, ...)\r
+{\r
+       va_list f;\r
+       char str[1024];\r
+       strcpy(str, "\r\n");\r
+       va_start(f, fmt);\r
+       vsprintf(str+2, fmt, f);\r
+\r
+       static char TextBuf[1024*32];\r
+       SendMessage(ScrollbackEdit, WM_GETTEXT, (WPARAM)sizeof(TextBuf),\r
+               (LPARAM)TextBuf);\r
+\r
+       if(strlen(TextBuf) + strlen(str) + 1 <= sizeof(TextBuf)) {\r
+               strcat(TextBuf, str);\r
+       } else {\r
+               lstrcpyn(TextBuf, str, sizeof(TextBuf));\r
+       }\r
+\r
+       SendMessage(ScrollbackEdit, WM_SETTEXT, 0, (LPARAM)TextBuf);\r
+       SendMessage(ScrollbackEdit, EM_LINESCROLL, 0, (LPARAM)INT_MAX);\r
+}\r
+\r
+void ShowGraphWindow(void)\r
+{\r
+       if(GraphWindow) return;\r
+\r
+       GraphWindow = CreateWindowEx(0, "Graph", "graphed",\r
+               WS_OVERLAPPED | WS_BORDER | WS_MINIMIZEBOX | WS_SYSMENU |\r
+               WS_SIZEBOX | WS_VISIBLE, 200, 150, 600, 500, NULL, NULL, NULL,\r
+               NULL);\r
+       if(!GraphWindow) oops();\r
+}\r
+\r
+void HideGraphWindow(void)\r
+{\r
+       if(GraphWindow) {\r
+               DestroyWindow(GraphWindow);\r
+               GraphWindow = NULL;\r
+       }\r
+}\r
+\r
+static void SetCommandEditTo(char *str)\r
+{\r
+       SendMessage(CommandEdit, WM_SETTEXT, 0, (LPARAM)str);\r
+       SendMessage(CommandEdit, EM_SETSEL, strlen(str), strlen(str));\r
+}\r
+\r
+void ShowGui(void)\r
+{\r
+       WNDCLASSEX wc;\r
+       memset(&wc, 0, sizeof(wc));\r
+       wc.cbSize = sizeof(wc);\r
+\r
+       wc.style                        = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW | CS_OWNDC;\r
+       wc.lpfnWndProc          = (WNDPROC)CommandWindowProc;\r
+       wc.hInstance            = NULL;\r
+       wc.hbrBackground        = (HBRUSH)(COLOR_BTNSHADOW);\r
+       wc.lpszClassName        = "Command";\r
+       wc.lpszMenuName         = NULL;\r
+       wc.hCursor                      = LoadCursor(NULL, IDC_ARROW);\r
+\r
+       if(!RegisterClassEx(&wc)) oops();\r
+\r
+       wc.lpszClassName        = "Graph";\r
+       wc.lpfnWndProc          = (WNDPROC)GraphWindowProc;\r
+       wc.hbrBackground        = (HBRUSH)GetStockObject(BLACK_BRUSH);\r
+\r
+       if(!RegisterClassEx(&wc)) oops();\r
+\r
+       CommandWindow = CreateWindowEx(0, "Command", "prox",\r
+               WS_OVERLAPPED | WS_BORDER | WS_MINIMIZEBOX | WS_SYSMENU |\r
+               WS_SIZEBOX | WS_VISIBLE, 20, 20, 500, 400, NULL, NULL, NULL,\r
+               NULL);\r
+       if(!CommandWindow) oops();\r
+\r
+       ScrollbackEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "edit", "",\r
+               WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | ES_MULTILINE |\r
+               ES_AUTOVSCROLL | WS_VSCROLL, 0, 0, 0, 0, CommandWindow, NULL,\r
+               NULL, NULL);\r
+\r
+       CommandEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "edit", "",\r
+               WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | WS_VISIBLE |\r
+               ES_AUTOHSCROLL, 0, 0, 0, 0, CommandWindow, NULL, NULL, NULL);\r
+\r
+       MyFixedFont = CreateFont(14, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,\r
+               ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,\r
+               FF_DONTCARE, "Lucida Console");\r
+       if(!MyFixedFont)\r
+               MyFixedFont = (HFONT)GetStockObject(SYSTEM_FONT);\r
+\r
+       FixedFont(ScrollbackEdit);\r
+       FixedFont(CommandEdit);\r
+\r
+       ResizeCommandWindow();\r
+       SetFocus(CommandEdit);\r
+\r
+       PrintToScrollback(">> Started prox, built " __DATE__ " " __TIME__);\r
+       PrintToScrollback(">> Connected to device");\r
+\r
+       GreyPen = CreatePen(PS_SOLID, 1, RGB(100, 100, 100));\r
+       GreenPen = CreatePen(PS_SOLID, 1, RGB(100, 255, 100));\r
+       YellowPen = CreatePen(PS_SOLID, 1, RGB(255, 255, 0));\r
+       GreenBrush = CreateSolidBrush(RGB(100, 255, 100));\r
+       YellowBrush = CreateSolidBrush(RGB(255, 255, 0));\r
+       WhitePen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));\r
+\r
+       CursorAPen = CreatePen(PS_DASH, 1, RGB(255, 255, 0));\r
+       CursorBPen = CreatePen(PS_DASH, 1, RGB(255, 0, 255));\r
+\r
+       MSG msg;\r
+       for(;;) {\r
+               if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {\r
+                       if(msg.message == WM_KEYDOWN && msg.wParam == VK_RETURN) {\r
+                               char got[1024];\r
+                               SendMessage(CommandEdit, WM_GETTEXT, (WPARAM)sizeof(got),\r
+                                       (LPARAM)got);\r
+\r
+                               if(strcmp(got, "cls")==0) {\r
+                                       SendMessage(ScrollbackEdit, WM_SETTEXT, 0, (LPARAM)"");\r
+                               } else {\r
+                                       CommandReceived(got);\r
+                               }\r
+                               SendMessage(CommandEdit, WM_SETTEXT, 0, (LPARAM)"");\r
+\r
+                               // Insert it into the command history, unless it is\r
+                               // identical to the previous command in the history.\r
+                               int prev = CommandHistoryNext - 1;\r
+                               if(prev < 0) prev += COMMAND_HISTORY_MAX;\r
+                               if(strcmp(CommandHistory[prev], got) != 0) {\r
+                                       strcpy(CommandHistory[CommandHistoryNext], got);\r
+                                       CommandHistoryNext++;\r
+                                       if(CommandHistoryNext == COMMAND_HISTORY_MAX) {\r
+                                               CommandHistoryNext = 0;\r
+                                       }\r
+                               }\r
+                               CommandHistoryPos = -1;\r
+                       } else if(msg.message == WM_KEYDOWN && msg.wParam == VK_UP &&\r
+                               msg.hwnd == CommandEdit)\r
+                       {\r
+                               if(CommandHistoryPos == -1) {\r
+                                       CommandHistoryPos = CommandHistoryNext;\r
+                               }\r
+                               CommandHistoryPos--;\r
+                               if(CommandHistoryPos < 0) {\r
+                                       CommandHistoryPos = COMMAND_HISTORY_MAX-1;\r
+                               }\r
+                               SetCommandEditTo(CommandHistory[CommandHistoryPos]);\r
+                       } else if(msg.message == WM_KEYDOWN && msg.wParam == VK_DOWN &&\r
+                               msg.hwnd == CommandEdit)\r
+                       {\r
+                               CommandHistoryPos++;\r
+                               if(CommandHistoryPos >= COMMAND_HISTORY_MAX) {\r
+                                       CommandHistoryPos = 0;\r
+                               }\r
+                               SetCommandEditTo(CommandHistory[CommandHistoryPos]);\r
+                       } else if(msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE &&\r
+                               msg.hwnd == CommandEdit)\r
+                       {\r
+                               SendMessage(CommandEdit, WM_SETTEXT, 0, (LPARAM)"");\r
+                       } else {\r
+                               if(msg.message == WM_KEYDOWN) {\r
+                                       CommandHistoryPos = -1;\r
+                               }\r
+                               TranslateMessage(&msg);\r
+                               DispatchMessage(&msg);\r
+                       }\r
+               }\r
+\r
+               UsbCommand c;\r
+               if(ReceiveCommandPoll(&c)) {\r
+                       UsbCommandReceived(&c);\r
+               }\r
+\r
+               Sleep(10);\r
+       }\r
+}\r
diff --git a/winsrc/include/hidpi.h b/winsrc/include/hidpi.h
new file mode 100644 (file)
index 0000000..e9816cf
--- /dev/null
@@ -0,0 +1,1787 @@
+/*++\r
+\r
+Copyright (c) 1996-1998      Microsoft Corporation\r
+\r
+Module Name:\r
+\r
+        HIDPI.H\r
+\r
+Abstract:\r
+\r
+   Public Interface to the HID parsing library.\r
+\r
+Environment:\r
+\r
+    Kernel & user mode\r
+\r
+--*/\r
+\r
+#ifndef   __HIDPI_H__\r
+#define   __HIDPI_H__\r
+\r
+#include <pshpack4.h>\r
+\r
+// Please include "hidsdi.h" to use the user space (dll / parser)\r
+// Please include "hidpddi.h" to use the kernel space parser\r
+\r
+//\r
+// Special Link collection values for using the query functions\r
+//\r
+// Root collection references the collection at the base of the link\r
+// collection tree.\r
+// Unspecifies, references all collections in the link collection tree.\r
+//\r
+#define HIDP_LINK_COLLECTION_ROOT ((USHORT) -1)\r
+#define HIDP_LINK_COLLECTION_UNSPECIFIED ((USHORT) 0)\r
+\r
+\r
+typedef enum _HIDP_REPORT_TYPE\r
+{\r
+    HidP_Input,\r
+    HidP_Output,\r
+    HidP_Feature\r
+} HIDP_REPORT_TYPE;\r
+\r
+typedef struct _USAGE_AND_PAGE\r
+{\r
+    USAGE Usage;\r
+    USAGE UsagePage;\r
+} USAGE_AND_PAGE, *PUSAGE_AND_PAGE;\r
+\r
+#define HidP_IsSameUsageAndPage(u1, u2) ((* (PULONG) &u1) == (* (PULONG) &u2))\r
+\r
+typedef struct _HIDP_BUTTON_CAPS\r
+{\r
+    USAGE    UsagePage;\r
+    UCHAR    ReportID;\r
+    BOOLEAN  IsAlias;\r
+\r
+    USHORT   BitField;\r
+    USHORT   LinkCollection;   // A unique internal index pointer\r
+\r
+    USAGE    LinkUsage;\r
+    USAGE    LinkUsagePage;\r
+\r
+    BOOLEAN  IsRange;\r
+    BOOLEAN  IsStringRange;\r
+    BOOLEAN  IsDesignatorRange;\r
+    BOOLEAN  IsAbsolute;\r
+\r
+    ULONG    Reserved[10];\r
+    union {\r
+        struct {\r
+            USAGE    UsageMin,         UsageMax;\r
+            USHORT   StringMin,        StringMax;\r
+            USHORT   DesignatorMin,    DesignatorMax;\r
+            USHORT   DataIndexMin,     DataIndexMax;\r
+        } Range;\r
+        struct  {\r
+            USAGE    Usage,            Reserved1;\r
+            USHORT   StringIndex,      Reserved2;\r
+            USHORT   DesignatorIndex,  Reserved3;\r
+            USHORT   DataIndex,        Reserved4;\r
+        } NotRange;\r
+    };\r
+\r
+} HIDP_BUTTON_CAPS, *PHIDP_BUTTON_CAPS;\r
+\r
+\r
+typedef struct _HIDP_VALUE_CAPS\r
+{\r
+    USAGE    UsagePage;\r
+    UCHAR    ReportID;\r
+    BOOLEAN  IsAlias;\r
+\r
+    USHORT   BitField;\r
+    USHORT   LinkCollection;   // A unique internal index pointer\r
+\r
+    USAGE    LinkUsage;\r
+    USAGE    LinkUsagePage;\r
+\r
+    BOOLEAN  IsRange;\r
+    BOOLEAN  IsStringRange;\r
+    BOOLEAN  IsDesignatorRange;\r
+    BOOLEAN  IsAbsolute;\r
+\r
+    BOOLEAN  HasNull;        // Does this channel have a null report   union\r
+    UCHAR    Reserved;\r
+    USHORT   BitSize;        // How many bits are devoted to this value?\r
+\r
+    USHORT   ReportCount;    // See Note below.  Usually set to 1.\r
+    USHORT   Reserved2[5];\r
+\r
+    ULONG    UnitsExp;\r
+    ULONG    Units;\r
+\r
+    LONG     LogicalMin,       LogicalMax;\r
+    LONG     PhysicalMin,      PhysicalMax;\r
+\r
+    union {\r
+        struct {\r
+            USAGE    UsageMin,         UsageMax;\r
+            USHORT   StringMin,        StringMax;\r
+            USHORT   DesignatorMin,    DesignatorMax;\r
+            USHORT   DataIndexMin,     DataIndexMax;\r
+        } Range;\r
+\r
+        struct {\r
+            USAGE    Usage,            Reserved1;\r
+            USHORT   StringIndex,      Reserved2;\r
+            USHORT   DesignatorIndex,  Reserved3;\r
+            USHORT   DataIndex,        Reserved4;\r
+        } NotRange;\r
+    };\r
+} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS;\r
+\r
+//\r
+// Notes:\r
+//\r
+// ReportCount:  When a report descriptor declares an Input, Output, or\r
+// Feature main item with fewer usage declarations than the report count, then\r
+// the last usage applies to all remaining unspecified count in that main item.\r
+// (As an example you might have data that required many fields to describe,\r
+// possibly buffered bytes.)  In this case, only one value cap structure is\r
+// allocated for these associtated fields, all with the same usage, and Report\r
+// Count reflects the number of fields involved.  Normally ReportCount is 1.\r
+// To access all of the fields in such a value structure would require using\r
+// HidP_GetUsageValueArray and HidP_SetUsageValueArray.   HidP_GetUsageValue/\r
+// HidP_SetScaledUsageValue will also work, however, these functions will only\r
+// work with the first field of the structure.\r
+//\r
+\r
+//\r
+// The link collection tree consists of an array of LINK_COLLECTION_NODES\r
+// where the index into this array is the same as the collection number.\r
+//\r
+// Given a collection A which contains a subcollection B, A is defined to be\r
+// the parent B, and B is defined to be the child.\r
+//\r
+// Given collections A, B, and C where B and C are children of A, and B was\r
+// encountered before C in the report descriptor, B is defined as a sibling of\r
+// C.  (This implies, of course, that if B is a sibling of C, then C is NOT a\r
+// sibling of B).\r
+//\r
+// B is defined as the NextSibling of C if and only if there exists NO\r
+// child collection of A, call it D, such that B is a sibling of D and D\r
+// is a sibling of C.\r
+//\r
+// E is defined to be the FirstChild of A if and only if for all children of A,\r
+// F, that are not equivalent to E, F is a sibling of E.\r
+// (This implies, of course, that the does not exist a child of A, call it G,\r
+// where E is a sibling of G).  In other words the first sibling is the last\r
+// link collection found in the list.\r
+//\r
+// In other words, if a collection B is defined within the definition of another\r
+// collection A, B becomes a child of A.  All collections with the same parent\r
+// are considered siblings.  The FirstChild of the parent collection, A, will be\r
+// last collection defined that has A as a parent.  The order of sibling pointers\r
+// is similarly determined.  When a collection B is defined, it becomes the\r
+// FirstChild of it's parent collection.  The previously defined FirstChild of the\r
+// parent collection becomes the NextSibling of the new collection.  As new\r
+// collections with the same parent are discovered, the chain of sibling is built.\r
+//\r
+// With that in mind, the following describes conclusively a data structure\r
+// that provides direct traversal up, down, and accross the link collection\r
+// tree.\r
+//\r
+//\r
+typedef struct _HIDP_LINK_COLLECTION_NODE\r
+{\r
+    USAGE    LinkUsage;\r
+    USAGE    LinkUsagePage;\r
+    USHORT   Parent;\r
+    USHORT   NumberOfChildren;\r
+    USHORT   NextSibling;\r
+    USHORT   FirstChild;\r
+    ULONG    CollectionType: 8;  // As defined in 6.2.2.6 of HID spec\r
+    ULONG    IsAlias : 1; // This link node is an allias of the next link node.\r
+    ULONG    Reserved: 23;\r
+    PVOID    UserContext; // The user can hang his coat here.\r
+} HIDP_LINK_COLLECTION_NODE, *PHIDP_LINK_COLLECTION_NODE;\r
+\r
+//\r
+// When a link collection is described by a delimiter, alias link collection\r
+// nodes are created.  (One for each usage within the delimiter).\r
+// The parser assigns each capability description listed above only one\r
+// link collection.\r
+//\r
+// If a control is defined within a collection defined by\r
+// delimited usages, then that control is said to be within multiple link\r
+// collections, one for each usage within the open and close delimiter tokens.\r
+// Such multiple link collecions are said to be aliases.  The first N-1 such\r
+// collections, listed in the link collection node array, have their IsAlias\r
+// bit set.  The last such link collection is the link collection index used\r
+// in the capabilities described above.\r
+// Clients wishing to set a control in an aliased collection, should walk the\r
+// collection array once for each time they see the IsAlias flag set, and use\r
+// the last link collection as the index for the below accessor functions.\r
+//\r
+// NB: if IsAlias is set, then NextSibling should be one more than the current\r
+// link collection node index.\r
+//\r
+\r
+typedef PUCHAR  PHIDP_REPORT_DESCRIPTOR;\r
+typedef struct _HIDP_PREPARSED_DATA * PHIDP_PREPARSED_DATA;\r
+\r
+typedef struct _HIDP_CAPS\r
+{\r
+    USAGE    Usage;\r
+    USAGE    UsagePage;\r
+    USHORT   InputReportByteLength;\r
+    USHORT   OutputReportByteLength;\r
+    USHORT   FeatureReportByteLength;\r
+    USHORT   Reserved[17];\r
+\r
+    USHORT   NumberLinkCollectionNodes;\r
+\r
+    USHORT   NumberInputButtonCaps;\r
+    USHORT   NumberInputValueCaps;\r
+    USHORT   NumberInputDataIndices;\r
+\r
+    USHORT   NumberOutputButtonCaps;\r
+    USHORT   NumberOutputValueCaps;\r
+    USHORT   NumberOutputDataIndices;\r
+\r
+    USHORT   NumberFeatureButtonCaps;\r
+    USHORT   NumberFeatureValueCaps;\r
+    USHORT   NumberFeatureDataIndices;\r
+} HIDP_CAPS, *PHIDP_CAPS;\r
+\r
+typedef struct _HIDP_DATA\r
+{\r
+    USHORT  DataIndex;\r
+    USHORT  Reserved;\r
+    union {\r
+        ULONG   RawValue; // for values\r
+        BOOLEAN On; // for buttons MUST BE TRUE for buttons.\r
+    };\r
+} HIDP_DATA, *PHIDP_DATA;\r
+//\r
+// The HIDP_DATA structure is used with HidP_GetData and HidP_SetData\r
+// functions.\r
+//\r
+// The parser contiguously assigns every control (button or value) in a hid\r
+// device a unique data index from zero to NumberXXXDataIndices -1 , inclusive.\r
+// This value is found in the HIDP_BUTTON_CAPS and HIDP_VALUE_CAPS structures.\r
+//\r
+// Most clients will find the Get/Set Buttons / Value accessor functions\r
+// sufficient to their needs, as they will allow the clients to access the\r
+// data known to them while ignoring the other controls.\r
+//\r
+// More complex clients, which actually read the Button / Value Caps, and which\r
+// do a value add service to these routines (EG Direct Input), will need to\r
+// access all the data in the device without interest in the individual usage\r
+// or link collection location.  These are the clients that will find\r
+// HidP_Data useful.\r
+//\r
+\r
+typedef struct _HIDP_UNKNOWN_TOKEN\r
+{\r
+    UCHAR  Token;\r
+    UCHAR  Reserved[3];\r
+    ULONG  BitField;\r
+} HIDP_UNKNOWN_TOKEN, *PHIDP_UNKNOWN_TOKEN;\r
+\r
+typedef struct _HIDP_EXTENDED_ATTRIBUTES\r
+{\r
+    UCHAR   NumGlobalUnknowns;\r
+    UCHAR   Reserved [3];\r
+    PHIDP_UNKNOWN_TOKEN  GlobalUnknowns;\r
+    // ... Additional attributes\r
+    ULONG   Data [1]; // variableLength  DO NOT ACCESS THIS FIELD\r
+} HIDP_EXTENDED_ATTRIBUTES, *PHIDP_EXTENDED_ATTRIBUTES;\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetCaps (\r
+   IN      PHIDP_PREPARSED_DATA      PreparsedData,\r
+   OUT     PHIDP_CAPS                Capabilities\r
+   );\r
+/*++\r
+Routine Description:\r
+   Returns a list of capabilities of a given hid device as described by its\r
+   preparsed data.\r
+\r
+Arguments:\r
+   PreparsedData    The preparsed data returned from HIDCLASS.\r
+   Capabilities     a HIDP_CAPS structure\r
+\r
+Return Value:\r
+·  HIDP_STATUS_SUCCESS\r
+·  HIDP_STATUS_INVALID_PREPARSED_DATA\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetLinkCollectionNodes (\r
+   OUT      PHIDP_LINK_COLLECTION_NODE LinkCollectionNodes,\r
+   IN OUT   PULONG                     LinkCollectionNodesLength,\r
+   IN       PHIDP_PREPARSED_DATA       PreparsedData\r
+   );\r
+/*++\r
+Routine Description:\r
+   Return a list of PHIDP_LINK_COLLECTION_NODEs used to describe the link\r
+   collection tree of this hid device.  See the above description of\r
+   struct _HIDP_LINK_COLLECTION_NODE.\r
+\r
+Arguments:\r
+   LinkCollectionNodes - a caller allocated array into which\r
+                 HidP_GetLinkCollectionNodes will store the information\r
+\r
+   LinKCollectionNodesLength - the caller sets this value to the length of the\r
+                 the array in terms of number of elements.\r
+                 HidP_GetLinkCollectionNodes sets this value to the actual\r
+                 number of elements set. The total number of nodes required to\r
+                 describe this HID device can be found in the\r
+                 NumberLinkCollectionNodes field in the HIDP_CAPS structure.\r
+\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetButtonCaps (\r
+   IN       HIDP_REPORT_TYPE     ReportType,\r
+   OUT      PHIDP_BUTTON_CAPS    ButtonCaps,\r
+   IN OUT   PUSHORT              ButtonCapsLength,\r
+   IN       PHIDP_PREPARSED_DATA PreparsedData\r
+);\r
+#define HidP_GetButtonCaps(_Type_, _Caps_, _Len_, _Data_) \\r
+        HidP_GetSpecificButtonCaps (_Type_, 0, 0, 0, _Caps_, _Len_, _Data_)\r
+NTSTATUS __stdcall\r
+HidP_GetSpecificButtonCaps (\r
+   IN       HIDP_REPORT_TYPE     ReportType,\r
+   IN       USAGE                UsagePage,      // Optional (0 => ignore)\r
+   IN       USHORT               LinkCollection, // Optional (0 => ignore)\r
+   IN       USAGE                Usage,          // Optional (0 => ignore)\r
+   OUT      PHIDP_BUTTON_CAPS    ButtonCaps,\r
+   IN OUT   PUSHORT              ButtonCapsLength,\r
+   IN       PHIDP_PREPARSED_DATA PreparsedData\r
+   );\r
+/*++\r
+Description:\r
+   HidP_GetButtonCaps returns all the buttons (binary values) that are a part\r
+   of the given report type for the Hid device represented by the given\r
+   preparsed data.\r
+\r
+Parameters:\r
+   ReportType  One of HidP_Input, HidP_Output, or HidP_Feature.\r
+\r
+   UsagePage   A usage page value used to limit the button caps returned to\r
+                those on a given usage page.  If set to 0, this parameter is\r
+                ignored.  Can be used with LinkCollection and Usage parameters\r
+                to further limit the number of button caps structures returned.\r
+\r
+   LinkCollection HIDP_LINK_COLLECTION node array index used to limit the\r
+                  button caps returned to those buttons in a given link\r
+                  collection.  If set to 0, this parameter is\r
+                  ignored.  Can be used with UsagePage and Usage parameters\r
+                  to further limit the number of button caps structures\r
+                  returned.\r
+\r
+   Usage      A usage value used to limit the button caps returned to those\r
+               with the specified usage value.  If set to 0, this parameter\r
+               is ignored.  Can be used with LinkCollection and UsagePage\r
+               parameters to further limit the number of button caps\r
+               structures returned.\r
+\r
+   ButtonCaps A _HIDP_BUTTON_CAPS array containing information about all the\r
+               binary values in the given report.  This buffer is provided by\r
+               the caller.\r
+\r
+   ButtonLength   As input, this parameter specifies the length of the\r
+                  ButtonCaps parameter (array) in number of array elements.\r
+                  As output, this value is set to indicate how many of those\r
+                  array elements were filled in by the function.  The maximum number of\r
+                  button caps that can be returned is found in the HIDP_CAPS\r
+                  structure.  If HIDP_STATUS_BUFFER_TOO_SMALL is returned,\r
+                  this value contains the number of array elements needed to\r
+                  successfully complete the request.\r
+\r
+   PreparsedData  The preparsed data returned from HIDCLASS.\r
+\r
+\r
+Return Value\r
+HidP_GetSpecificButtonCaps returns the following error codes:\r
+· HIDP_STATUS_SUCCESS.\r
+· HIDP_STATUS_INVALID_REPORT_TYPE\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA\r
+· HIDP_STATUS_BUFFER_TOO_SMALL (all given entries however have been filled in)\r
+· HIDP_STATUS_USAGE_NOT_FOUND\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetValueCaps (\r
+   IN       HIDP_REPORT_TYPE     ReportType,\r
+   OUT      PHIDP_VALUE_CAPS     ValueCaps,\r
+   IN OUT   PUSHORT              ValueCapsLength,\r
+   IN       PHIDP_PREPARSED_DATA PreparsedData\r
+);\r
+#define HidP_GetValueCaps(_Type_, _Caps_, _Len_, _Data_) \\r
+        HidP_GetSpecificValueCaps (_Type_, 0, 0, 0, _Caps_, _Len_, _Data_)\r
+NTSTATUS __stdcall\r
+HidP_GetSpecificValueCaps (\r
+   IN       HIDP_REPORT_TYPE     ReportType,\r
+   IN       USAGE                UsagePage,      // Optional (0 => ignore)\r
+   IN       USHORT               LinkCollection, // Optional (0 => ignore)\r
+   IN       USAGE                Usage,          // Optional (0 => ignore)\r
+   OUT      PHIDP_VALUE_CAPS     ValueCaps,\r
+   IN OUT   PUSHORT              ValueCapsLength,\r
+   IN       PHIDP_PREPARSED_DATA PreparsedData\r
+   );\r
+/*++\r
+Description:\r
+   HidP_GetValueCaps returns all the values (non-binary) that are a part\r
+   of the given report type for the Hid device represented by the given\r
+   preparsed data.\r
+\r
+Parameters:\r
+   ReportType  One of HidP_Input, HidP_Output, or HidP_Feature.\r
+\r
+   UsagePage   A usage page value used to limit the value caps returned to\r
+                those on a given usage page.  If set to 0, this parameter is\r
+                ignored.  Can be used with LinkCollection and Usage parameters\r
+                to further limit the number of value caps structures returned.\r
+\r
+   LinkCollection HIDP_LINK_COLLECTION node array index used to limit the\r
+                  value caps returned to those buttons in a given link\r
+                  collection.  If set to 0, this parameter is\r
+                  ignored.  Can be used with UsagePage and Usage parameters\r
+                  to further limit the number of value caps structures\r
+                  returned.\r
+\r
+   Usage      A usage value used to limit the value caps returned to those\r
+               with the specified usage value.  If set to 0, this parameter\r
+               is ignored.  Can be used with LinkCollection and UsagePage\r
+               parameters to further limit the number of value caps\r
+               structures returned.\r
+\r
+   ValueCaps  A _HIDP_VALUE_CAPS array containing information about all the\r
+               non-binary values in the given report.  This buffer is provided\r
+               by the caller.\r
+\r
+   ValueLength   As input, this parameter specifies the length of the ValueCaps\r
+                  parameter (array) in number of array elements.  As output,\r
+                  this value is set to indicate how many of those array elements\r
+                  were filled in by the function.  The maximum number of\r
+                  value caps that can be returned is found in the HIDP_CAPS\r
+                  structure.  If HIDP_STATUS_BUFFER_TOO_SMALL is returned,\r
+                  this value contains the number of array elements needed to\r
+                  successfully complete the request.\r
+\r
+   PreparsedData  The preparsed data returned from HIDCLASS.\r
+\r
+\r
+Return Value\r
+HidP_GetValueCaps returns the following error codes:\r
+· HIDP_STATUS_SUCCESS.\r
+· HIDP_STATUS_INVALID_REPORT_TYPE\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA\r
+· HIDP_STATUS_BUFFER_TOO_SMALL (all given entries however have been filled in)\r
+· HIDP_STATUS_USAGE_NOT_FOUND\r
+\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetExtendedAttributes (\r
+    IN      HIDP_REPORT_TYPE            ReportType,\r
+    IN      USHORT                      DataIndex,\r
+    IN      PHIDP_PREPARSED_DATA        PreparsedData,\r
+    OUT     PHIDP_EXTENDED_ATTRIBUTES   Attributes,\r
+    IN OUT  PULONG                      LengthAttributes\r
+    );\r
+/*++\r
+Description:\r
+    Given a data index from the value or button capabilities of a given control\r
+    return any extended attributes for the control if any exist.\r
+\r
+Parameters:\r
+    ReportType  One of HidP_Input, HidP_Output, or HidP_Feature.\r
+\r
+    DataIndex   The data index for the given control, found in the capabilities\r
+                structure for that control\r
+\r
+    PreparsedData   The preparsed data returned from HIDCLASS.\r
+\r
+    Attributes  Pointer to a buffer into which the extended attribute data will\r
+                be copied.\r
+\r
+    LengthAttributes    Length of the given buffer in bytes.\r
+\r
+Return Value\r
+    HIDP_STATUS_SUCCESS\r
+    HIDP_STATUS_DATA_INDEX_NOT_FOUND\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_InitializeReportForID (\r
+   IN       HIDP_REPORT_TYPE      ReportType,\r
+   IN       UCHAR                 ReportID,\r
+   IN       PHIDP_PREPARSED_DATA  PreparsedData,\r
+   IN OUT   PCHAR                 Report,\r
+   IN       ULONG                 ReportLength\r
+   );\r
+/*++\r
+\r
+Routine Description:\r
+\r
+    Initialize a report based on the given report ID.\r
+\r
+Parameters:\r
+\r
+    ReportType  One of HidP_Input, HidP_Output, or HidP_Feature.\r
+\r
+    PreparasedData  Preparsed data structure returned by HIDCLASS\r
+\r
+    Report      Buffer which to set the data into.\r
+\r
+    ReportLength Length of Report...Report should be at least as long as the\r
+                value indicated in the HIDP_CAPS structure for the device and\r
+                the corresponding ReportType\r
+\r
+Return Value\r
+\r
+· HIDP_STATUS_INVALID_REPORT_TYPE    -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH  -- the length of the report packet is not equal\r
+                                        to the length specified in HIDP_CAPS\r
+                                        structure for the given ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST  -- if there are no reports on this device\r
+                                        for the given ReportType\r
+\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_SetData (\r
+   IN       HIDP_REPORT_TYPE      ReportType,\r
+   IN       PHIDP_DATA            DataList,\r
+   IN OUT   PULONG                DataLength,\r
+   IN       PHIDP_PREPARSED_DATA  PreparsedData,\r
+   IN OUT   PCHAR                 Report,\r
+   IN       ULONG                 ReportLength\r
+   );\r
+/*++\r
+\r
+Routine Description:\r
+\r
+    Please Note: Since usage value arrays deal with multiple fields for\r
+                 for one usage value, they cannot be used with HidP_SetData\r
+                 and HidP_GetData.  In this case,\r
+                 HIDP_STATUS_IS_USAGE_VALUE_ARRAY will be returned.\r
+\r
+Parameters:\r
+\r
+    ReportType  One of HidP_Input, HidP_Output, or HidP_Feature.\r
+\r
+    DataList    Array of HIDP_DATA structures that contains the data values\r
+                that are to be set into the given report\r
+\r
+    DataLength  As input, length in array elements of DataList.  As output,\r
+                contains the number of data elements set on successful\r
+                completion or an index into the DataList array to identify\r
+                the faulting HIDP_DATA value if an error code is returned.\r
+\r
+    PreparasedData  Preparsed data structure returned by HIDCLASS\r
+\r
+    Report      Buffer which to set the data into.\r
+\r
+    ReportLength Length of Report...Report should be at least as long as the\r
+                value indicated in the HIDP_CAPS structure for the device and\r
+                the corresponding ReportType\r
+\r
+Return Value\r
+    HidP_SetData returns the following error codes.  The report packet will\r
+        have all the data set up until the HIDP_DATA structure that caused the\r
+        error.  DataLength, in the error case, will return this problem index.\r
+\r
+· HIDP_STATUS_SUCCESS                -- upon successful insertion of all data\r
+                                        into the report packet.\r
+· HIDP_STATUS_INVALID_REPORT_TYPE    -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_DATA_INDEX_NOT_FOUND   -- if a HIDP_DATA structure referenced a\r
+                                        data index that does not exist for this\r
+                                        device's ReportType\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH  -- the length of the report packet is not equal\r
+                                        to the length specified in HIDP_CAPS\r
+                                        structure for the given ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST  -- if there are no reports on this device\r
+                                        for the given ReportType\r
+· HIDP_STATUS_IS_USAGE_VALUE_ARRAY   -- if one of the HIDP_DATA structures\r
+                                        references a usage value array.\r
+                                        DataLength will contain the index into\r
+                                        the array that was invalid\r
+· HIDP_STATUS_BUTTON_NOT_PRESSED     -- if a HIDP_DATA structure attempted\r
+                                        to unset a button that was not already\r
+                                        set in the Report\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- a HIDP_DATA structure was found with\r
+                                        a valid index value but is contained\r
+                                        in a different report than the one\r
+                                        currently being processed\r
+· HIDP_STATUS_BUFFER_TOO_SMALL       -- if there are not enough entries in\r
+                                        a given Main Array Item to report all\r
+                                        buttons that have been requested to be\r
+                                        set\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetData (\r
+   IN       HIDP_REPORT_TYPE      ReportType,\r
+   OUT      PHIDP_DATA            DataList,\r
+   IN OUT   PULONG                DataLength,\r
+   IN       PHIDP_PREPARSED_DATA  PreparsedData,\r
+   IN       PCHAR                 Report,\r
+   IN       ULONG                 ReportLength\r
+   );\r
+/*++\r
+\r
+Routine Description:\r
+\r
+    Please Note: For obvious reasons HidP_SetData and HidP_GetData will not\r
+    access UsageValueArrays.\r
+\r
+Parameters:\r
+    ReportType  One of HidP_Input, HidP_Output, or HidP_Feature.\r
+\r
+    DataList    Array of HIDP_DATA structures that will receive the data\r
+                values that are set in the given report\r
+\r
+    DataLength  As input, length in array elements of DataList.  As output,\r
+                contains the number of data elements that were successfully\r
+                set by HidP_GetData.  The maximum size necessary for DataList\r
+                can be determined by calling HidP_MaxDataListLength\r
+\r
+    PreparasedData  Preparsed data structure returned by HIDCLASS\r
+\r
+    Report      Buffer which to set the data into.\r
+\r
+    ReportLength Length of Report...Report should be at least as long as the\r
+                value indicated in the HIDP_CAPS structure for the device and\r
+                the corresponding ReportType\r
+\r
+Return Value\r
+    HidP_GetData returns the following error codes.\r
+\r
+· HIDP_STATUS_SUCCESS                -- upon successful retrieval of all data\r
+                                        from the report packet.\r
+· HIDP_STATUS_INVALID_REPORT_TYPE    -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH  -- the length of the report packet is not equal\r
+                                        to the length specified in HIDP_CAPS\r
+                                        structure for the given ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST  -- if there are no reports on this device\r
+                                        for the given ReportType\r
+· HIDP_STATUS_BUFFER_TOO_SMALL       -- if there are not enough array entries in\r
+                                        DataList to store all the indice values\r
+                                        in the given report.  DataLength will\r
+                                        contain the number of array entries\r
+                                        required to hold all data\r
+--*/\r
+\r
+ULONG __stdcall\r
+HidP_MaxDataListLength (\r
+   IN HIDP_REPORT_TYPE      ReportType,\r
+   IN PHIDP_PREPARSED_DATA  PreparsedData\r
+   );\r
+/*++\r
+Routine Description:\r
+\r
+    This function returns the maximum length of HIDP_DATA elements that\r
+    HidP_GetData could return for the given report type.\r
+\r
+Parameters:\r
+\r
+    ReportType  One of HidP_Input, HidP_Output or HidP_Feature.\r
+\r
+    PreparsedData    Preparsed data structure returned by HIDCLASS\r
+\r
+Return Value:\r
+\r
+    The length of the data list array required for the HidP_GetData function\r
+    call.  If an error occurs (either HIDP_STATUS_INVALID_REPORT_TYPE or\r
+    HIDP_STATUS_INVALID_PREPARSED_DATA), this function returns 0.\r
+\r
+--*/\r
+\r
+#define HidP_SetButtons(Rty, Up, Lco, ULi, ULe, Ppd, Rep, Rle) \\r
+        HidP_SetUsages(Rty, Up, Lco, ULi, ULe, Ppd, Rep, Rle)\r
+\r
+NTSTATUS __stdcall\r
+HidP_SetUsages (\r
+   IN       HIDP_REPORT_TYPE      ReportType,\r
+   IN       USAGE                 UsagePage,\r
+   IN       USHORT                LinkCollection, // Optional\r
+   IN       PUSAGE                UsageList,\r
+   IN OUT   PULONG                UsageLength,\r
+   IN       PHIDP_PREPARSED_DATA  PreparsedData,\r
+   IN OUT   PCHAR                 Report,\r
+   IN       ULONG                 ReportLength\r
+   );\r
+/*++\r
+\r
+Routine Description:\r
+    This function sets binary values (buttons) in a report.  Given an\r
+    initialized packet of correct length, it modifies the report packet so that\r
+    each element in the given list of usages has been set in the report packet.\r
+    For example, in an output report with 5 LED\92s, each with a given usage,\r
+    an application could turn on any subset of these lights by placing their\r
+    usages in any order into the usage array (UsageList).  HidP_SetUsages would,\r
+    in turn, set the appropriate bit or add the corresponding byte into the\r
+    HID Main Array Item.\r
+\r
+    A properly initialized Report packet is one of the correct byte length,\r
+    and all zeros.\r
+\r
+    NOTE: A packet that has already been set with a call to a HidP_Set routine\r
+          can also be passed in.  This routine then sets processes the UsageList\r
+          in the same fashion but verifies that the ReportID already set in\r
+          Report matches the report ID for the given usages.\r
+\r
+Parameters:\r
+    ReportType  One of HidP_Input, HidP_Output or HidP_Feature.\r
+\r
+    UsagePage   All of the usages in the usage array, which HidP_SetUsages will\r
+                set in the report, refer to this same usage page.\r
+                If a client wishes to set usages in a report for multiple\r
+                usage pages then that client needs to make multiple calls to\r
+                HidP_SetUsages for each of the usage pages.\r
+\r
+    UsageList   A usage array containing the usages that HidP_SetUsages will set in\r
+                the report packet.\r
+\r
+    UsageLength The length of the given usage array in array elements.\r
+                The parser will set this value to the position in the usage\r
+                array where it stopped processing.  If successful, UsageLength\r
+                will be unchanged.  In any error condition, this parameter\r
+                reflects how many of the usages in the usage list have\r
+                actually been set by the parser.  This is useful for finding\r
+                the usage in the list which caused the error.\r
+\r
+    PreparsedData The preparsed data recevied from HIDCLASS\r
+\r
+    Report      The report packet.\r
+\r
+    ReportLength   Length of the given report packet...Must be equal to the\r
+                   value reported in the HIDP_CAPS structure for the device\r
+                   and corresponding report type.\r
+\r
+Return Value\r
+    HidP_SetUsages returns the following error codes.  On error, the report packet\r
+    will be correct up until the usage element that caused the error.\r
+\r
+· HIDP_STATUS_SUCCESS                -- upon successful insertion of all usages\r
+                                        into the report packet.\r
+· HIDP_STATUS_INVALID_REPORT_TYPE    -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH  -- the length of the report packet is not\r
+                                        equal to the length specified in\r
+                                        the HIDP_CAPS structure for the given\r
+                                        ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST  -- if there are no reports on this device\r
+                                        for the given ReportType\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- if a usage was found that exists in a\r
+                                        different report.  If the report is\r
+                                        zero-initialized on entry the first\r
+                                        usage in the list will determine which\r
+                                        report ID is used.  Otherwise, the\r
+                                        parser will verify that usage matches\r
+                                        the passed in report's ID\r
+· HIDP_STATUS_USAGE_NOT_FOUND        -- if the usage does not exist for any\r
+                                        report (no matter what the report ID)\r
+                                        for the given report type.\r
+· HIDP_STATUS_BUFFER_TOO_SMALL       -- if there are not enough entries in a\r
+                                        given Main Array Item to list all of\r
+                                        the given usages.  The caller needs\r
+                                        to split his request into more than\r
+                                        one call\r
+--*/\r
+\r
+#define HidP_UnsetButtons(Rty, Up, Lco, ULi, ULe, Ppd, Rep, Rle) \\r
+        HidP_UnsetUsages(Rty, Up, Lco, ULi, ULe, Ppd, Rep, Rle)\r
+\r
+NTSTATUS __stdcall\r
+HidP_UnsetUsages (\r
+   IN       HIDP_REPORT_TYPE      ReportType,\r
+   IN       USAGE                 UsagePage,\r
+   IN       USHORT                LinkCollection, // Optional\r
+   IN       PUSAGE                UsageList,\r
+   IN OUT   PULONG                UsageLength,\r
+   IN       PHIDP_PREPARSED_DATA  PreparsedData,\r
+   IN OUT   PCHAR                 Report,\r
+   IN       ULONG                 ReportLength\r
+   );\r
+/*++\r
+\r
+Routine Description:\r
+    This function unsets (turns off) binary values (buttons) in the report.  Given\r
+    an initialized packet of correct length, it modifies the report packet so\r
+    that each element in the given list of usages has been unset in the\r
+    report packet.\r
+\r
+    This function is the "undo" operation for SetUsages.  If the given usage\r
+    is not already set in the Report, it will return an error code of\r
+    HIDP_STATUS_BUTTON_NOT_PRESSED.  If the button is pressed, HidP_UnsetUsages\r
+    will unset the appropriate bit or remove the corresponding index value from\r
+    the HID Main Array Item.\r
+\r
+    A properly initialized Report packet is one of the correct byte length,\r
+    and all zeros..\r
+\r
+    NOTE: A packet that has already been set with a call to a HidP_Set routine\r
+          can also be passed in.  This routine then processes the UsageList\r
+          in the same fashion but verifies that the ReportID already set in\r
+          Report matches the report ID for the given usages.\r
+\r
+Parameters:\r
+    ReportType  One of HidP_Input, HidP_Output or HidP_Feature.\r
+\r
+    UsagePage   All of the usages in the usage array, which HidP_UnsetUsages will\r
+                unset in the report, refer to this same usage page.\r
+                If a client wishes to unset usages in a report for multiple\r
+                usage pages then that client needs to make multiple calls to\r
+                HidP_UnsetUsages for each of the usage pages.\r
+\r
+    UsageList   A usage array containing the usages that HidP_UnsetUsages will\r
+                unset in the report packet.\r
+\r
+    UsageLength The length of the given usage array in array elements.\r
+                The parser will set this value to the position in the usage\r
+                array where it stopped processing.  If successful, UsageLength\r
+                will be unchanged.  In any error condition, this parameter\r
+                reflects how many of the usages in the usage list have\r
+                actually been unset by the parser.  This is useful for finding\r
+                the usage in the list which caused the error.\r
+\r
+    PreparsedData The preparsed data recevied from HIDCLASS\r
+\r
+    Report      The report packet.\r
+\r
+    ReportLength   Length of the given report packet...Must be equal to the\r
+                   value reported in the HIDP_CAPS structure for the device\r
+                   and corresponding report type.\r
+\r
+Return Value\r
+    HidP_UnsetUsages returns the following error codes.  On error, the report\r
+    packet will be correct up until the usage element that caused the error.\r
+\r
+· HIDP_STATUS_SUCCESS                -- upon successful "unsetting" of all usages\r
+                                        in the report packet.\r
+· HIDP_STATUS_INVALID_REPORT_TYPE    -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH  -- the length of the report packet is not\r
+                                        equal to the length specified in\r
+                                        the HIDP_CAPS structure for the given\r
+                                        ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST  -- if there are no reports on this device\r
+                                        for the given ReportType\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- if a usage was found that exists in a\r
+                                        different report.  If the report is\r
+                                        zero-initialized on entry the first\r
+                                        usage in the list will determine which\r
+                                        report ID is used.  Otherwise, the\r
+                                        parser will verify that usage matches\r
+                                        the passed in report's ID\r
+· HIDP_STATUS_USAGE_NOT_FOUND        -- if the usage does not exist for any\r
+                                        report (no matter what the report ID)\r
+                                        for the given report type.\r
+· HIDP_STATUS_BUTTON_NOT_PRESSED     -- if a usage corresponds to a button that\r
+                                        is not already set in the given report\r
+--*/\r
+\r
+#define HidP_GetButtons(Rty, UPa, LCo, ULi, ULe, Ppd, Rep, RLe) \\r
+        HidP_GetUsages(Rty, UPa, LCo, ULi, ULe, Ppd, Rep, RLe)\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetUsages (\r
+   IN       HIDP_REPORT_TYPE     ReportType,\r
+   IN       USAGE                UsagePage,\r
+   IN       USHORT               LinkCollection, // Optional\r
+   OUT      USAGE *              UsageList,\r
+   IN OUT   ULONG *              UsageLength,\r
+   IN       PHIDP_PREPARSED_DATA PreparsedData,\r
+   IN       PCHAR                Report,\r
+   IN       ULONG                ReportLength\r
+   );\r
+/*++\r
+\r
+Routine Description:\r
+    This function returns the binary values (buttons) that are set in a HID\r
+    report.  Given a report packet of correct length, it searches the report\r
+    packet for each usage for the given usage page and returns them in the\r
+    usage list.\r
+\r
+Parameters:\r
+    ReportType One of HidP_Input, HidP_Output or HidP_Feature.\r
+\r
+    UsagePage  All of the usages in the usage list, which HidP_GetUsages will\r
+               retrieve in the report, refer to this same usage page.\r
+               If the client wishes to get usages in a packet for multiple\r
+               usage pages then that client needs to make multiple calls\r
+               to HidP_GetUsages.\r
+\r
+    LinkCollection  An optional value which can limit which usages are returned\r
+                    in the UsageList to those usages that exist in a specific\r
+                    LinkCollection.  A non-zero value indicates the index into\r
+                    the HIDP_LINK_COLLECITON_NODE list returned by\r
+                    HidP_GetLinkCollectionNodes of the link collection the\r
+                    usage should belong to.  A value of 0 indicates this\r
+                    should value be ignored.\r
+\r
+    UsageList  The usage array that will contain all the usages found in\r
+               the report packet.\r
+\r
+    UsageLength The length of the given usage array in array elements.\r
+                On input, this value describes the length of the usage list.\r
+                On output, HidP_GetUsages sets this value to the number of\r
+                usages that was found.  Use HidP_MaxUsageListLength to\r
+                determine the maximum length needed to return all the usages\r
+                that a given report packet may contain.\r
+\r
+    PreparsedData Preparsed data structure returned by HIDCLASS\r
+\r
+    Report       The report packet.\r
+\r
+    ReportLength  Length (in bytes) of the given report packet\r
+\r
+\r
+Return Value\r
+    HidP_GetUsages returns the following error codes:\r
+\r
+· HIDP_STATUS_SUCCESS                -- upon successfully retrieving all the\r
+                                        usages from the report packet\r
+· HIDP_STATUS_INVALID_REPORT_TYPE    -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH  -- the length of the report packet is not\r
+                                        equal to the length specified in\r
+                                        the HIDP_CAPS structure for the given\r
+                                        ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST  -- if there are no reports on this device\r
+                                        for the given ReportType\r
+· HIDP_STATUS_BUFFER_TOO_SMALL       -- if the UsageList is not big enough to\r
+                                        hold all the usages found in the report\r
+                                        packet.  If this is returned, the buffer\r
+                                        will contain UsageLength number of\r
+                                        usages.  Use HidP_MaxUsageListLength to\r
+                                        find the maximum length needed\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- if no usages were found but usages\r
+                                        that match the UsagePage and\r
+                                        LinkCollection specified could be found\r
+                                        in a report with a different report ID\r
+· HIDP_STATUS_USAGE_NOT_FOUND        -- if there are no usages in a reports for\r
+                                        the device and ReportType that match the\r
+                                        UsagePage and LinkCollection that were\r
+                                        specified\r
+--*/\r
+\r
+#define HidP_GetButtonsEx(Rty, LCo, BLi, ULe, Ppd, Rep, RLe)  \\r
+        HidP_GetUsagesEx(Rty, LCo, BLi, ULe, Ppd, Rep, RLe)\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetUsagesEx (\r
+   IN       HIDP_REPORT_TYPE     ReportType,\r
+   IN       USHORT               LinkCollection, // Optional\r
+   OUT      PUSAGE_AND_PAGE      ButtonList,\r
+   IN OUT   ULONG *              UsageLength,\r
+   IN       PHIDP_PREPARSED_DATA PreparsedData,\r
+   IN       PCHAR                Report,\r
+   IN       ULONG                ReportLength\r
+   );\r
+\r
+/*++\r
+\r
+Routine Description:\r
+    This function returns the binary values (buttons) in a HID report.\r
+    Given a report packet of correct length, it searches the report packet\r
+    for all buttons and returns the UsagePage and Usage for each of the buttons\r
+    it finds.\r
+\r
+Parameters:\r
+    ReportType  One of HidP_Input, HidP_Output or HidP_Feature.\r
+\r
+    LinkCollection  An optional value which can limit which usages are returned\r
+                    in the ButtonList to those usages that exist in a specific\r
+                    LinkCollection.  A non-zero value indicates the index into\r
+                    the HIDP_LINK_COLLECITON_NODE list returned by\r
+                    HidP_GetLinkCollectionNodes of the link collection the\r
+                    usage should belong to.  A value of 0 indicates this\r
+                    should value be ignored.\r
+\r
+    ButtonList  An array of USAGE_AND_PAGE structures describing all the\r
+                buttons currently ``down'' in the device.\r
+\r
+    UsageLength The length of the given array in terms of elements.\r
+                On input, this value describes the length of the list.  On\r
+                output, HidP_GetUsagesEx sets this value to the number of\r
+                usages that were found.  Use HidP_MaxUsageListLength to\r
+                determine the maximum length needed to return all the usages\r
+                that a given report packet may contain.\r
+\r
+    PreparsedData Preparsed data returned by HIDCLASS\r
+\r
+    Report       The report packet.\r
+\r
+    ReportLength Length (in bytes) of the given report packet.\r
+\r
+\r
+Return Value\r
+    HidP_GetUsagesEx returns the following error codes:\r
+\r
+· HIDP_STATUS_SUCCESS                -- upon successfully retrieving all the\r
+                                        usages from the report packet\r
+· HIDP_STATUS_INVALID_REPORT_TYPE    -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH  -- the length of the report packet is not\r
+                                        equal to the length specified in\r
+                                        the HIDP_CAPS structure for the given\r
+                                        ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST  -- if there are no reports on this device\r
+                                        for the given ReportType\r
+· HIDP_STATUS_BUFFER_TOO_SMALL       -- if ButtonList is not big enough to\r
+                                        hold all the usages found in the report\r
+                                        packet.  If this is returned, the buffer\r
+                                        will contain UsageLength number of\r
+                                        usages.  Use HidP_MaxUsageListLength to\r
+                                        find the maximum length needed\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- if no usages were found but usages\r
+                                        that match the specified LinkCollection\r
+                                        exist in report with a different report\r
+                                        ID.\r
+· HIDP_STATUS_USAGE_NOT_FOUND        -- if there are no usages in any reports that\r
+                                        match the LinkCollection parameter\r
+--*/\r
+\r
+#define HidP_GetButtonListLength(RTy, UPa, Ppd) \\r
+        HidP_GetUsageListLength(Rty, UPa, Ppd)\r
+\r
+ULONG __stdcall\r
+HidP_MaxUsageListLength (\r
+   IN HIDP_REPORT_TYPE      ReportType,\r
+   IN USAGE                 UsagePage, // Optional\r
+   IN PHIDP_PREPARSED_DATA  PreparsedData\r
+   );\r
+/*++\r
+Routine Description:\r
+    This function returns the maximum number of usages that a call to\r
+    HidP_GetUsages or HidP_GetUsagesEx could return for a given HID report.\r
+    If calling for number of usages returned by HidP_GetUsagesEx, use 0 as\r
+    the UsagePage value.\r
+\r
+Parameters:\r
+    ReportType  One of HidP_Input, HidP_Output or HidP_Feature.\r
+\r
+    UsagePage   Specifies the optional UsagePage to query for.  If 0, will\r
+                return all the maximum number of usage values that could be\r
+                returned for a given ReportType.   If non-zero, will return\r
+                the maximum number of usages that would be returned for the\r
+                ReportType with the given UsagePage.\r
+\r
+    PreparsedData Preparsed data returned from HIDCLASS\r
+\r
+Return Value:\r
+    The length of the usage list array required for the HidP_GetUsages or\r
+    HidP_GetUsagesEx function call.  If an error occurs (such as\r
+    HIDP_STATUS_INVALID_REPORT_TYPE or HIDP_INVALID_PREPARSED_DATA, this\r
+    returns 0.\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_SetUsageValue (\r
+   IN       HIDP_REPORT_TYPE     ReportType,\r
+   IN       USAGE                UsagePage,\r
+   IN       USHORT               LinkCollection, // Optional\r
+   IN       USAGE                Usage,\r
+   IN       ULONG                UsageValue,\r
+   IN       PHIDP_PREPARSED_DATA PreparsedData,\r
+   IN OUT   PCHAR                Report,\r
+   IN       ULONG                ReportLength\r
+   );\r
+/*++\r
+Description:\r
+    HidP_SetUsageValue inserts a value into the HID Report Packet in the field\r
+    corresponding to the given usage page and usage.  HidP_SetUsageValue\r
+    casts this value to the appropriate bit length.  If a report packet\r
+    contains two different fields with the same Usage and UsagePage,\r
+    they can be distinguished with the optional LinkCollection field value.\r
+    Using this function sets the raw value into the report packet with\r
+    no checking done as to whether it actually falls within the logical\r
+    minimum/logical maximum range.  Use HidP_SetScaledUsageValue for this...\r
+\r
+    NOTE: Although the UsageValue parameter is a ULONG, any casting that is\r
+          done will preserve or sign-extend the value.  The value being set\r
+          should be considered a LONG value and will be treated as such by\r
+          this function.\r
+\r
+Parameters:\r
+\r
+    ReportType  One of HidP_Output or HidP_Feature.\r
+\r
+    UsagePage   The usage page to which the given usage refers.\r
+\r
+    LinkCollection  (Optional)  This value can be used to differentiate\r
+                                between two fields that may have the same\r
+                                UsagePage and Usage but exist in different\r
+                                collections.  If the link collection value\r
+                                is zero, this function will set the first field\r
+                                it finds that matches the usage page and\r
+                                usage.\r
+\r
+    Usage       The usage whose value HidP_SetUsageValue will set.\r
+\r
+    UsageValue  The raw value to set in the report buffer.  This value must be within\r
+                the logical range or if a NULL value this value should be the\r
+                most negative value that can be represented by the number of bits\r
+                for this field.\r
+\r
+    PreparsedData The preparsed data returned for HIDCLASS\r
+\r
+    Report      The report packet.\r
+\r
+    ReportLength Length (in bytes) of the given report packet.\r
+\r
+\r
+Return Value:\r
+    HidP_SetUsageValue returns the following error codes:\r
+\r
+· HIDP_STATUS_SUCCESS                -- upon successfully setting the value\r
+                                        in the report packet\r
+· HIDP_STATUS_INVALID_REPORT_TYPE    -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH  -- the length of the report packet is not\r
+                                        equal to the length specified in\r
+                                        the HIDP_CAPS structure for the given\r
+                                        ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST  -- if there are no reports on this device\r
+                                        for the given ReportType\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- the specified usage page, usage and\r
+                                        link collection exist but exists in\r
+                                        a report with a different report ID\r
+                                        than the report being passed in.  To\r
+                                        set this value, call HidP_SetUsageValue\r
+                                        again with a zero-initizialed report\r
+                                        packet\r
+· HIDP_STATUS_USAGE_NOT_FOUND        -- if the usage page, usage, and link\r
+                                        collection combination does not exist\r
+                                        in any reports for this ReportType\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_SetScaledUsageValue (\r
+   IN       HIDP_REPORT_TYPE     ReportType,\r
+   IN       USAGE                UsagePage,\r
+   IN       USHORT               LinkCollection, // Optional\r
+   IN       USAGE                Usage,\r
+   IN       LONG                 UsageValue,\r
+   IN       PHIDP_PREPARSED_DATA PreparsedData,\r
+   IN OUT   PCHAR                Report,\r
+   IN       ULONG                ReportLength\r
+   );\r
+\r
+/*++\r
+Description:\r
+    HidP_SetScaledUsageValue inserts the UsageValue into the HID report packet\r
+    in the field corresponding to the given usage page and usage.  If a report\r
+    packet contains two different fields with the same Usage and UsagePage,\r
+    they can be distinguished with the optional LinkCollection field value.\r
+\r
+    If the specified field has a defined physical range, this function converts\r
+    the physical value specified to the corresponding logical value for the\r
+    report.  If a physical value does not exist, the function will verify that\r
+    the value specified falls within the logical range and set according.\r
+\r
+    If the range checking fails but the field has NULL values, the function will\r
+    set the field to the defined NULL value (most negative number possible) and\r
+    return HIDP_STATUS_NULL.  In other words, use this function to set NULL\r
+    values for a given field by passing in a value that falls outside the\r
+    physical range if it is defined or the logical range otherwise.\r
+\r
+    If the field does not support NULL values, an out of range error will be\r
+    returned instead.\r
+\r
+Parameters:\r
+\r
+    ReportType  One of HidP_Output or HidP_Feature.\r
+\r
+    UsagePage   The usage page to which the given usage refers.\r
+\r
+    LinkCollection  (Optional)  This value can be used to differentiate\r
+                                between two fields that may have the same\r
+                                UsagePage and Usage but exist in different\r
+                                collections.  If the link collection value\r
+                                is zero, this function will set the first field\r
+                                it finds that matches the usage page and\r
+                                usage.\r
+\r
+    Usage       The usage whose value HidP_SetScaledUsageValue will set.\r
+\r
+    UsageValue  The value to set in the report buffer.  See the routine\r
+                description above for the different interpretations of this\r
+                value\r
+\r
+    PreparsedData The preparsed data returned from HIDCLASS\r
+\r
+    Report      The report packet.\r
+\r
+    ReportLength Length (in bytes) of the given report packet.\r
+\r
+\r
+Return Value:\r
+   HidP_SetScaledUsageValue returns the following error codes:\r
+\r
+· HIDP_STATUS_SUCCESS                -- upon successfully setting the value\r
+                                        in the report packet\r
+· HIDP_STATUS_NULL                   -- upon successfully setting the value\r
+                                        in the report packet as a NULL value\r
+· HIDP_STATUS_INVALID_REPORT_TYPE    -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH  -- the length of the report packet is not\r
+                                        equal to the length specified in\r
+                                        the HIDP_CAPS structure for the given\r
+                                        ReportType\r
+· HIDP_STATUS_VALUE_OUT_OF_RANGE     -- if the value specified failed to fall\r
+                                        within the physical range if it exists\r
+                                        or within the logical range otherwise\r
+                                        and the field specified by the usage\r
+                                        does not allow NULL values\r
+· HIDP_STATUS_BAD_LOG_PHY_VALUES     -- if the field has a physical range but\r
+                                        either the logical range is invalid\r
+                                        (max <= min) or the physical range is\r
+                                        invalid\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- the specified usage page, usage and\r
+                                        link collection exist but exists in\r
+                                        a report with a different report ID\r
+                                        than the report being passed in.  To\r
+                                        set this value, call\r
+                                        HidP_SetScaledUsageValue again with\r
+                                        a zero-initialized report packet\r
+· HIDP_STATUS_USAGE_NOT_FOUND        -- if the usage page, usage, and link\r
+                                        collection combination does not exist\r
+                                        in any reports for this ReportType\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_SetUsageValueArray (\r
+    IN    HIDP_REPORT_TYPE     ReportType,\r
+    IN    USAGE                UsagePage,\r
+    IN    USHORT               LinkCollection, // Optional\r
+    IN    USAGE                Usage,\r
+    IN    PCHAR                UsageValue,\r
+    IN    USHORT               UsageValueByteLength,\r
+    IN    PHIDP_PREPARSED_DATA PreparsedData,\r
+    OUT   PCHAR                Report,\r
+    IN    ULONG                ReportLength\r
+    );\r
+\r
+/*++\r
+Routine Descripton:\r
+    A usage value array occurs when the last usage in the list of usages\r
+    describing a main item must be repeated because there are less usages defined\r
+    than there are report counts declared for the given main item.  In this case\r
+    a single value cap is allocated for that usage and the report count of that\r
+    value cap is set to reflect the number of fields to which that usage refers.\r
+\r
+    HidP_SetUsageValueArray sets the raw bits for that usage which spans\r
+    more than one field in a report.\r
+\r
+    NOTE: This function currently does not support value arrays where the\r
+          ReportSize for each of the fields in the array is not a multiple\r
+          of 8 bits.\r
+\r
+          The UsageValue buffer should have the values set as they would appear\r
+          in the report buffer.  If this function supported non 8-bit multiples\r
+          for the ReportSize then caller should format the input buffer so that\r
+          each new value begins at the bit immediately following the last bit\r
+          of the previous value\r
+\r
+Parameters:\r
+\r
+    ReportType  One of HidP_Output or HidP_Feature.\r
+\r
+    UsagePage   The usage page to which the given usage refers.\r
+\r
+    LinkCollection  (Optional)  This value can be used to differentiate\r
+                                between two fields that may have the same\r
+                                UsagePage and Usage but exist in different\r
+                                collections.  If the link collection value\r
+                                is zero, this function will set the first field\r
+                                it finds that matches the usage page and\r
+                                usage.\r
+\r
+    Usage       The usage whose value array HidP_SetUsageValueArray will set.\r
+\r
+    UsageValue  The buffer with the values to set into the value array.\r
+                The number of BITS required is found by multiplying the\r
+                BitSize and ReportCount fields of the Value Cap for this\r
+                control.  The least significant bit of this control found in the\r
+                given report will be placed in the least significan bit location\r
+                of the array given (little-endian format), regardless of whether\r
+                or not the field is byte alligned or if the BitSize is a multiple\r
+                of sizeof (CHAR).\r
+\r
+                See the above note for current implementation limitations.\r
+\r
+    UsageValueByteLength  Length of the UsageValue buffer (in bytes)\r
+\r
+    PreparsedData The preparsed data returned from HIDCLASS\r
+\r
+    Report      The report packet.\r
+\r
+    ReportLength Length (in bytes) of the given report packet.\r
+\r
+\r
+Return Value:\r
+· HIDP_STATUS_SUCCESS                -- upon successfully setting the value\r
+                                        array in the report packet\r
+· HIDP_STATUS_INVALID_REPORT_TYPE    -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH  -- the length of the report packet is not\r
+                                        equal to the length specified in\r
+                                        the HIDP_CAPS structure for the given\r
+                                        ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST  -- if there are no reports on this device\r
+                                        for the given ReportType\r
+· HIDP_STATUS_NOT_VALUE_ARRAY        -- if the control specified is not a\r
+                                        value array -- a value array will have\r
+                                        a ReportCount field in the\r
+                                        HIDP_VALUE_CAPS structure that is > 1\r
+                                        Use HidP_SetUsageValue instead\r
+· HIDP_STATUS_BUFFER_TOO_SMALL       -- if the size of the passed in buffer with\r
+                                        the values to set is too small (ie. has\r
+                                        fewer values than the number of fields in\r
+                                        the array\r
+· HIDP_STATUS_NOT_IMPLEMENTED        -- if the usage value array has field sizes\r
+                                        that are not multiples of 8 bits, this\r
+                                        error code is returned since the function\r
+                                        currently does not handle setting into\r
+                                        such arrays.\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- the specified usage page, usage and\r
+                                        link collection exist but exists in\r
+                                        a report with a different report ID\r
+                                        than the report being passed in.  To\r
+                                        set this value, call\r
+                                        HidP_SetUsageValueArray again with\r
+                                        a zero-initialized report packet\r
+· HIDP_STATUS_USAGE_NOT_FOUND        -- if the usage page, usage, and link\r
+                                        collection combination does not exist\r
+                                        in any reports for this ReportType\r
+--*/\r
+\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetUsageValue (\r
+   IN    HIDP_REPORT_TYPE     ReportType,\r
+   IN    USAGE                UsagePage,\r
+   IN    USHORT               LinkCollection, // Optional\r
+   IN    USAGE                Usage,\r
+   OUT   PULONG               UsageValue,\r
+   IN    PHIDP_PREPARSED_DATA PreparsedData,\r
+   IN    PCHAR                Report,\r
+   IN    ULONG                ReportLength\r
+   );\r
+\r
+/*\r
+Description\r
+    HidP_GetUsageValue retrieves the value from the HID Report for the usage\r
+    specified by the combination of usage page, usage and link collection.\r
+    If a report packet contains two different fields with the same\r
+    Usage and UsagePage, they can be distinguished with the optional\r
+    LinkCollection field value.\r
+\r
+Parameters:\r
+\r
+    ReportType  One of HidP_Input or HidP_Feature.\r
+\r
+    UsagePage   The usage page to which the given usage refers.\r
+\r
+    LinkCollection  (Optional)  This value can be used to differentiate\r
+                                between two fields that may have the same\r
+                                UsagePage and Usage but exist in different\r
+                                collections.  If the link collection value\r
+                                is zero, this function will set the first field\r
+                                it finds that matches the usage page and\r
+                                usage.\r
+\r
+    Usage       The usage whose value HidP_GetUsageValue will retrieve\r
+\r
+    UsageValue  The raw value that is set for the specified field in the report\r
+                buffer. This value will either fall within the logical range\r
+                or if NULL values are allowed, a number outside the range to\r
+                indicate a NULL\r
+\r
+    PreparsedData The preparsed data returned for HIDCLASS\r
+\r
+    Report      The report packet.\r
+\r
+    ReportLength Length (in bytes) of the given report packet.\r
+\r
+\r
+Return Value:\r
+    HidP_GetUsageValue returns the following error codes:\r
+\r
+· HIDP_STATUS_SUCCESS                -- upon successfully retrieving the value\r
+                                        from the report packet\r
+· HIDP_STATUS_INVALID_REPORT_TYPE    -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH  -- the length of the report packet is not\r
+                                        equal to the length specified in\r
+                                        the HIDP_CAPS structure for the given\r
+                                        ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST  -- if there are no reports on this device\r
+                                        for the given ReportType\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- the specified usage page, usage and\r
+                                        link collection exist but exists in\r
+                                        a report with a different report ID\r
+                                        than the report being passed in.  To\r
+                                        set this value, call HidP_GetUsageValue\r
+                                        again with a different report packet\r
+· HIDP_STATUS_USAGE_NOT_FOUND        -- if the usage page, usage, and link\r
+                                        collection combination does not exist\r
+                                        in any reports for this ReportType\r
+--*/\r
+\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetScaledUsageValue (\r
+   IN    HIDP_REPORT_TYPE     ReportType,\r
+   IN    USAGE                UsagePage,\r
+   IN    USHORT               LinkCollection, // Optional\r
+   IN    USAGE                Usage,\r
+   OUT   PLONG                UsageValue,\r
+   IN    PHIDP_PREPARSED_DATA PreparsedData,\r
+   IN    PCHAR                Report,\r
+   IN    ULONG                ReportLength\r
+   );\r
+\r
+/*++\r
+Description\r
+    HidP_GetScaledUsageValue retrieves a UsageValue from the HID report packet\r
+    in the field corresponding to the given usage page and usage.  If a report\r
+    packet contains two different fields with the same Usage and UsagePage,\r
+    they can be distinguished with the optional LinkCollection field value.\r
+\r
+    If the specified field has a defined physical range, this function converts\r
+    the logical value that exists in the report packet to the corresponding\r
+    physical value.  If a physical range does not exist, the function will\r
+    return the logical value.  This function will check to verify that the\r
+    logical value in the report falls within the declared logical range.\r
+\r
+    When doing the conversion between logical and physical values, this\r
+    function assumes a linear extrapolation between the physical max/min and\r
+    the logical max/min. (Where logical is the values reported by the device\r
+    and physical is the value returned by this function).  If the data field\r
+    size is less than 32 bits, then HidP_GetScaledUsageValue will sign extend\r
+    the value to 32 bits.\r
+\r
+    If the range checking fails but the field has NULL values, the function\r
+    will set UsageValue to 0 and return HIDP_STATUS_NULL.  Otherwise, it\r
+    returns a HIDP_STATUS_OUT_OF_RANGE error.\r
+\r
+Parameters:\r
+\r
+    ReportType  One of HidP_Output or HidP_Feature.\r
+\r
+    UsagePage   The usage page to which the given usage refers.\r
+\r
+    LinkCollection  (Optional)  This value can be used to differentiate\r
+                                between two fields that may have the same\r
+                                UsagePage and Usage but exist in different\r
+                                collections.  If the link collection value\r
+                                is zero, this function will retrieve the first\r
+                                field it finds that matches the usage page\r
+                                and usage.\r
+\r
+    Usage       The usage whose value HidP_GetScaledUsageValue will retrieve\r
+\r
+    UsageValue  The value retrieved from the report buffer.  See the routine\r
+                description above for the different interpretations of this\r
+                value\r
+\r
+    PreparsedData The preparsed data returned from HIDCLASS\r
+\r
+    Report      The report packet.\r
+\r
+    ReportLength Length (in bytes) of the given report packet.\r
+\r
+\r
+Return Value:\r
+   HidP_GetScaledUsageValue returns the following error codes:\r
+\r
+· HIDP_STATUS_SUCCESS                -- upon successfully retrieving the value\r
+                                        from the report packet\r
+· HIDP_STATUS_NULL                   -- if the report packet had a NULL value\r
+                                        set\r
+· HIDP_STATUS_INVALID_REPORT_TYPE    -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH  -- the length of the report packet is not\r
+                                        equal to the length specified in\r
+                                        the HIDP_CAPS structure for the given\r
+                                        ReportType\r
+· HIDP_STATUS_VALUE_OUT_OF_RANGE     -- if the value retrieved from the packet\r
+                                        falls outside the logical range and\r
+                                        the field does not support NULL values\r
+· HIDP_STATUS_BAD_LOG_PHY_VALUES     -- if the field has a physical range but\r
+                                        either the logical range is invalid\r
+                                        (max <= min) or the physical range is\r
+                                        invalid\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- the specified usage page, usage and\r
+                                        link collection exist but exists in\r
+                                        a report with a different report ID\r
+                                        than the report being passed in.  To\r
+                                        set this value, call\r
+                                        HidP_GetScaledUsageValue with a\r
+                                        different report packet\r
+· HIDP_STATUS_USAGE_NOT_FOUND        -- if the usage page, usage, and link\r
+                                        collection combination does not exist\r
+                                        in any reports for this ReportType\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetUsageValueArray (\r
+    IN    HIDP_REPORT_TYPE     ReportType,\r
+    IN    USAGE                UsagePage,\r
+    IN    USHORT               LinkCollection, // Optional\r
+    IN    USAGE                Usage,\r
+    OUT   PCHAR                UsageValue,\r
+    IN    USHORT               UsageValueByteLength,\r
+    IN    PHIDP_PREPARSED_DATA PreparsedData,\r
+    IN    PCHAR                Report,\r
+    IN    ULONG                ReportLength\r
+    );\r
+\r
+/*++\r
+Routine Descripton:\r
+    A usage value array occurs when the last usage in the list of usages\r
+    describing a main item must be repeated because there are less usages defined\r
+    than there are report counts declared for the given main item.  In this case\r
+    a single value cap is allocated for that usage and the report count of that\r
+    value cap is set to reflect the number of fields to which that usage refers.\r
+\r
+    HidP_GetUsageValueArray returns the raw bits for that usage which spans\r
+    more than one field in a report.\r
+\r
+    NOTE: This function currently does not support value arrays where the\r
+          ReportSize for each of the fields in the array is not a multiple\r
+          of 8 bits.\r
+\r
+          The UsageValue buffer will have the raw values as they are set\r
+          in the report packet.\r
+\r
+Parameters:\r
+\r
+    ReportType  One of HidP_Input, HidP_Output or HidP_Feature.\r
+\r
+    UsagePage   The usage page to which the given usage refers.\r
+\r
+    LinkCollection  (Optional)  This value can be used to differentiate\r
+                                between two fields that may have the same\r
+                                UsagePage and Usage but exist in different\r
+                                collections.  If the link collection value\r
+                                is zero, this function will set the first field\r
+                                it finds that matches the usage page and\r
+                                usage.\r
+\r
+   Usage       The usage whose value HidP_GetUsageValueArray will retreive.\r
+\r
+   UsageValue  A pointer to an array of characters where the value will be\r
+               placed.  The number of BITS required is found by multiplying the\r
+               BitSize and ReportCount fields of the Value Cap for this\r
+               control.  The least significant bit of this control found in the\r
+               given report will be placed in the least significant bit location\r
+               of the buffer (little-endian format), regardless of whether\r
+               or not the field is byte aligned or if the BitSize is a multiple\r
+               of sizeof (CHAR).\r
+\r
+               See note above about current implementation limitations\r
+\r
+   UsageValueByteLength\r
+               the length of the given UsageValue buffer.\r
+\r
+   PreparsedData The preparsed data returned by the HIDCLASS\r
+\r
+   Report      The report packet.\r
+\r
+   ReportLength   Length of the given report packet.\r
+\r
+Return Value:\r
+\r
+· HIDP_STATUS_SUCCESS                -- upon successfully retrieving the value\r
+                                        from the report packet\r
+· HIDP_STATUS_INVALID_REPORT_TYPE    -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH  -- the length of the report packet is not\r
+                                        equal to the length specified in\r
+                                        the HIDP_CAPS structure for the given\r
+                                        ReportType\r
+· HIDP_STATUS_NOT_VALUE_ARRAY        -- if the control specified is not a\r
+                                        value array -- a value array will have\r
+                                        a ReportCount field in the\r
+                                        HIDP_VALUE_CAPS structure that is > 1\r
+                                        Use HidP_GetUsageValue instead\r
+· HIDP_STATUS_BUFFER_TOO_SMALL       -- if the size of the passed in buffer in\r
+                                        which to return the array is too small\r
+                                        (ie. has fewer values than the number of\r
+                                        fields in the array\r
+· HIDP_STATUS_NOT_IMPLEMENTED        -- if the usage value array has field sizes\r
+                                        that are not multiples of 8 bits, this\r
+                                        error code is returned since the function\r
+                                        currently does not handle getting values\r
+                                        from such arrays.\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- the specified usage page, usage and\r
+                                        link collection exist but exists in\r
+                                        a report with a different report ID\r
+                                        than the report being passed in.  To\r
+                                        set this value, call\r
+                                        HidP_GetUsageValueArray with a\r
+                                        different report packet\r
+· HIDP_STATUS_USAGE_NOT_FOUND        -- if the usage page, usage, and link\r
+                                        collection combination does not exist\r
+                                        in any reports for this ReportType\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_UsageListDifference (\r
+    IN    PUSAGE   PreviousUsageList,\r
+    IN    PUSAGE   CurrentUsageList,\r
+    OUT   PUSAGE   BreakUsageList,\r
+    OUT   PUSAGE   MakeUsageList,\r
+    IN    ULONG    UsageListLength\r
+    );\r
+/*++\r
+Routine Description:\r
+    This function will return the difference between a two lists of usages\r
+    (as might be returned from HidP_GetUsages),  In other words, it will return\r
+    return a list of usages that are in the current list but not the previous\r
+    list as well as a list of usages that are in the previous list but not\r
+    the current list.\r
+\r
+Parameters:\r
+\r
+    PreviousUsageList   The list of usages before.\r
+    CurrentUsageList    The list of usages now.\r
+    BreakUsageList      Previous - Current.\r
+    MakeUsageList       Current - Previous.\r
+    UsageListLength     Represents the length of the usage lists in array\r
+                        elements.  If comparing two lists with a differing\r
+                        number of array elements, this value should be\r
+                        the size of the larger of the two lists.  Any\r
+                        zero found with a list indicates an early termination\r
+                        of the list and any usages found after the first zero\r
+                        will be ignored.\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_UsageAndPageListDifference (\r
+   IN    PUSAGE_AND_PAGE PreviousUsageList,\r
+   IN    PUSAGE_AND_PAGE CurrentUsageList,\r
+   OUT   PUSAGE_AND_PAGE BreakUsageList,\r
+   OUT   PUSAGE_AND_PAGE MakeUsageList,\r
+   IN    ULONG           UsageListLength\r
+   );\r
+\r
+//\r
+// Produce Make or Break Codes\r
+//\r
+typedef enum _HIDP_KEYBOARD_DIRECTION {\r
+    HidP_Keyboard_Break,\r
+    HidP_Keyboard_Make\r
+} HIDP_KEYBOARD_DIRECTION;\r
+\r
+//\r
+// A bitmap of the current shift state of the keyboard when using the\r
+// below keyboard usages to i8042 translation function.\r
+//\r
+typedef struct _HIDP_KEYBOARD_MODIFIER_STATE {\r
+   union {\r
+      struct {\r
+         ULONG LeftControl: 1;\r
+         ULONG LeftShift: 1;\r
+         ULONG LeftAlt: 1;\r
+         ULONG LeftGUI: 1;\r
+         ULONG RightControl: 1;\r
+         ULONG RightShift: 1;\r
+         ULONG RightAlt: 1;\r
+         ULONG RigthGUI: 1;\r
+         ULONG CapsLock: 1;\r
+         ULONG ScollLock: 1;\r
+         ULONG NumLock: 1;\r
+         ULONG Reserved: 21;\r
+      };\r
+      ULONG ul;\r
+   };\r
+\r
+} HIDP_KEYBOARD_MODIFIER_STATE, * PHIDP_KEYBOARD_MODIFIER_STATE;\r
+\r
+//\r
+// A call back function to give the i8042 scan codes to the caller of\r
+// the below translation function.\r
+//\r
+typedef BOOLEAN (* PHIDP_INSERT_SCANCODES) (\r
+                  IN PVOID Context,  // Some caller supplied context.\r
+                  IN PCHAR NewScanCodes, // A list of i8042 scan codes.\r
+                  IN ULONG Length // the length of the scan codes.\r
+                  );\r
+\r
+NTSTATUS __stdcall\r
+HidP_TranslateUsageAndPagesToI8042ScanCodes (\r
+    IN     PUSAGE_AND_PAGE               ChangedUsageList,\r
+    IN     ULONG                         UsageListLength,\r
+    IN     HIDP_KEYBOARD_DIRECTION       KeyAction,\r
+    IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState,\r
+    IN     PHIDP_INSERT_SCANCODES        InsertCodesProcedure,\r
+    IN     PVOID                         InsertCodesContext\r
+    );\r
+/*++\r
+Routine Description:\r
+Parameters:\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_TranslateUsagesToI8042ScanCodes (\r
+    IN     PUSAGE                        ChangedUsageList,\r
+    IN     ULONG                         UsageListLength,\r
+    IN     HIDP_KEYBOARD_DIRECTION       KeyAction,\r
+    IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState,\r
+    IN     PHIDP_INSERT_SCANCODES        InsertCodesProcedure,\r
+    IN     PVOID                         InsertCodesContext\r
+    );\r
+/*++\r
+Routine Description:\r
+Parameters:\r
+--*/\r
+\r
+\r
+\r
+//\r
+// Define NT Status codes with Facility Code of FACILITY_HID_ERROR_CODE\r
+//\r
+\r
+// FACILITY_HID_ERROR_CODE defined in ntstatus.h\r
+#ifndef FACILITY_HID_ERROR_CODE\r
+#define FACILITY_HID_ERROR_CODE 0x11\r
+#endif\r
+\r
+#define HIDP_ERROR_CODES(SEV, CODE) \\r
+        ((NTSTATUS) (((SEV) << 28) | (FACILITY_HID_ERROR_CODE << 16) | (CODE)))\r
+\r
+#define HIDP_STATUS_SUCCESS                  (HIDP_ERROR_CODES(0x0,0))\r
+#define HIDP_STATUS_NULL                     (HIDP_ERROR_CODES(0x8,1))\r
+#define HIDP_STATUS_INVALID_PREPARSED_DATA   (HIDP_ERROR_CODES(0xC,1))\r
+#define HIDP_STATUS_INVALID_REPORT_TYPE      (HIDP_ERROR_CODES(0xC,2))\r
+#define HIDP_STATUS_INVALID_REPORT_LENGTH    (HIDP_ERROR_CODES(0xC,3))\r
+#define HIDP_STATUS_USAGE_NOT_FOUND          (HIDP_ERROR_CODES(0xC,4))\r
+#define HIDP_STATUS_VALUE_OUT_OF_RANGE       (HIDP_ERROR_CODES(0xC,5))\r
+#define HIDP_STATUS_BAD_LOG_PHY_VALUES       (HIDP_ERROR_CODES(0xC,6))\r
+#define HIDP_STATUS_BUFFER_TOO_SMALL         (HIDP_ERROR_CODES(0xC,7))\r
+#define HIDP_STATUS_INTERNAL_ERROR           (HIDP_ERROR_CODES(0xC,8))\r
+#define HIDP_STATUS_I8042_TRANS_UNKNOWN      (HIDP_ERROR_CODES(0xC,9))\r
+#define HIDP_STATUS_INCOMPATIBLE_REPORT_ID   (HIDP_ERROR_CODES(0xC,0xA))\r
+#define HIDP_STATUS_NOT_VALUE_ARRAY          (HIDP_ERROR_CODES(0xC,0xB))\r
+#define HIDP_STATUS_IS_VALUE_ARRAY           (HIDP_ERROR_CODES(0xC,0xC))\r
+#define HIDP_STATUS_DATA_INDEX_NOT_FOUND     (HIDP_ERROR_CODES(0xC,0xD))\r
+#define HIDP_STATUS_DATA_INDEX_OUT_OF_RANGE  (HIDP_ERROR_CODES(0xC,0xE))\r
+#define HIDP_STATUS_BUTTON_NOT_PRESSED       (HIDP_ERROR_CODES(0xC,0xF))\r
+#define HIDP_STATUS_REPORT_DOES_NOT_EXIST    (HIDP_ERROR_CODES(0xC,0x10))\r
+#define HIDP_STATUS_NOT_IMPLEMENTED          (HIDP_ERROR_CODES(0xC,0x20))\r
+\r
+//\r
+// We blundered this status code.\r
+//\r
+#define HIDP_STATUS_I8242_TRANS_UNKNOWN HIDP_STATUS_I8042_TRANS_UNKNOWN\r
+\r
+#include <poppack.h>\r
+\r
+#endif\r
diff --git a/winsrc/include/hidsdi.h b/winsrc/include/hidsdi.h
new file mode 100644 (file)
index 0000000..d0db806
--- /dev/null
@@ -0,0 +1,412 @@
+/*++\r
+\r
+Copyright (c) 1996    Microsoft Corporation\r
+\r
+Module Name:\r
+\r
+    HIDSDI.H\r
+\r
+Abstract:\r
+\r
+    This module contains the PUBLIC definitions for the\r
+    code that implements the HID dll.\r
+\r
+Environment:\r
+\r
+    Kernel & user mode\r
+\r
+--*/\r
+\r
+\r
+#ifndef _HIDSDI_H\r
+#define _HIDSDI_H\r
+\r
+#include <pshpack4.h>\r
+\r
+//#include "wtypes.h"\r
+\r
+//#include <windef.h>\r
+//#include <win32.h>\r
+//#include <basetyps.h>\r
+\r
+typedef LONG NTSTATUS;\r
+#include "hidusage.h"\r
+#include "hidpi.h"\r
+\r
+typedef struct _HIDD_CONFIGURATION {\r
+    PVOID    cookie;\r
+    ULONG    size;\r
+    ULONG    RingBufferSize;\r
+} HIDD_CONFIGURATION, *PHIDD_CONFIGURATION;\r
+\r
+typedef struct _HIDD_ATTRIBUTES {\r
+    ULONG   Size; // = sizeof (struct _HIDD_ATTRIBUTES)\r
+\r
+    //\r
+    // Vendor ids of this hid device\r
+    //\r
+    USHORT  VendorID;\r
+    USHORT  ProductID;\r
+    USHORT  VersionNumber;\r
+\r
+    //\r
+    // Additional fields will be added to the end of this structure.\r
+    //\r
+} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;\r
+\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetAttributes (\r
+    IN  HANDLE              HidDeviceObject,\r
+    OUT PHIDD_ATTRIBUTES    Attributes\r
+    );\r
+/*++\r
+Routine Description:\r
+    Fill in the given HIDD_ATTRIBUTES structure with the attributes of the\r
+    given hid device.\r
+\r
+--*/\r
+\r
+\r
+void __stdcall\r
+HidD_GetHidGuid (\r
+   OUT   LPGUID   HidGuid\r
+   );\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetPreparsedData (\r
+   IN    HANDLE                  HidDeviceObject,\r
+   OUT   PHIDP_PREPARSED_DATA  * PreparsedData\r
+   );\r
+/*++\r
+Routine Description:\r
+    Given a handle to a valid Hid Class Device Object, retrieve the preparsed\r
+    data for the device.  This routine will allocate the appropriately \r
+    sized buffer to hold this preparsed data.  It is up to client to call\r
+    HidP_FreePreparsedData to free the memory allocated to this structure when\r
+    it is no longer needed.\r
+\r
+Arguments:\r
+   HidDeviceObject A handle to a Hid Device that the client obtains using \r
+                   a call to CreateFile on a valid Hid device string name.\r
+                   The string name can be obtained using standard PnP calls.\r
+\r
+   PreparsedData   An opaque data structure used by other functions in this \r
+                   library to retrieve information about a given device.\r
+\r
+Return Value:\r
+   TRUE if successful.\r
+   FALSE otherwise  -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_FreePreparsedData (\r
+   IN    PHIDP_PREPARSED_DATA PreparsedData\r
+   );\r
+\r
+BOOLEAN __stdcall\r
+HidD_FlushQueue (\r
+   IN    HANDLE                HidDeviceObject\r
+   );\r
+/*++\r
+Routine Description:\r
+    Flush the input queue for the given HID device.\r
+\r
+Arguments:\r
+   HidDeviceObject A handle to a Hid Device that the client obtains using \r
+                   a call to CreateFile on a valid Hid device string name.\r
+                   The string name can be obtained using standard PnP calls.\r
+\r
+Return Value:\r
+   TRUE if successful\r
+   FALSE otherwise  -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetConfiguration (\r
+   IN   HANDLE               HidDeviceObject,\r
+   OUT  PHIDD_CONFIGURATION  Configuration,\r
+   IN   ULONG                ConfigurationLength\r
+   );\r
+/*++\r
+Routine Description:\r
+    Get the configuration information for this Hid device\r
+\r
+Arguments:\r
+   HidDeviceObject      A handle to a Hid Device Object.\r
+\r
+   Configuration        A configuration structure.  HidD_GetConfiguration MUST\r
+                        be called before the configuration can be modified and\r
+                        set using HidD_SetConfiguration\r
+\r
+   ConfigurationLength  That is ``sizeof (HIDD_CONFIGURATION)''. Using this\r
+                        parameter, we can later increase the length of the \r
+                        configuration array and not break older apps.\r
+\r
+Return Value:\r
+   TRUE if successful\r
+   FALSE otherwise  -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_SetConfiguration (\r
+   IN   HANDLE               HidDeviceObject,\r
+   IN   PHIDD_CONFIGURATION  Configuration,\r
+   IN   ULONG                ConfigurationLength\r
+   );\r
+/*++\r
+Routine Description:\r
+   Set the configuration information for this Hid device...\r
+   \r
+   NOTE: HidD_GetConfiguration must be called to retrieve the current \r
+         configuration information before this information can be modified \r
+         and set.\r
+\r
+Arguments:\r
+    HidDeviceObject      A handle to a Hid Device Object.\r
\r
+    Configuration        A configuration structure.  HidD_GetConfiguration MUST\r
+                         be called before the configuration can be modified and\r
+                         set using HidD_SetConfiguration\r
\r
+    ConfigurationLength  That is ``sizeof (HIDD_CONFIGURATION)''. Using this\r
+                         parameter, we can later increase the length of the \r
+                         configuration array and not break older apps.\r
+\r
+Return Value:\r
+    TRUE if successful\r
+    FALSE otherwise  -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetFeature (\r
+   IN    HANDLE   HidDeviceObject,\r
+   OUT   PVOID    ReportBuffer,\r
+   IN    ULONG    ReportBufferLength\r
+   );\r
+/*++\r
+Routine Description:\r
+    Retrieve a feature report from a HID device.\r
+\r
+Arguments:\r
+    HidDeviceObject      A handle to a Hid Device Object.\r
\r
+    ReportBuffer         The buffer that the feature report should be placed \r
+                         into.  The first byte of the buffer should be set to\r
+                         the report ID of the desired report\r
\r
+    ReportBufferLength   The size (in bytes) of ReportBuffer.  This value \r
+                         should be greater than or equal to the \r
+                         FeatureReportByteLength field as specified in the \r
+                         HIDP_CAPS structure for the device\r
+Return Value:\r
+    TRUE if successful\r
+    FALSE otherwise  -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_SetFeature (\r
+   IN    HANDLE   HidDeviceObject,\r
+   IN    PVOID    ReportBuffer,\r
+   IN    ULONG    ReportBufferLength\r
+   );\r
+/*++\r
+Routine Description:\r
+    Send a feature report to a HID device.\r
+\r
+Arguments:\r
+    HidDeviceObject      A handle to a Hid Device Object.\r
\r
+    ReportBuffer         The buffer of the feature report to send to the device\r
\r
+    ReportBufferLength   The size (in bytes) of ReportBuffer.  This value \r
+                         should be greater than or equal to the \r
+                         FeatureReportByteLength field as specified in the \r
+                         HIDP_CAPS structure for the device\r
+Return Value:\r
+    TRUE if successful\r
+    FALSE otherwise  -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetNumInputBuffers (\r
+    IN  HANDLE  HidDeviceObject,\r
+    OUT PULONG  NumberBuffers\r
+    );\r
+/*++\r
+Routine Description:\r
+    This function returns the number of input buffers used by the specified\r
+    file handle to the Hid device.  Each file object has a number of buffers\r
+    associated with it to queue reports read from the device but which have\r
+    not yet been read by the user-mode app with a handle to that device.\r
+\r
+Arguments:\r
+    HidDeviceObject      A handle to a Hid Device Object.\r
\r
+    NumberBuffers        Number of buffers currently being used for this file\r
+                         handle to the Hid device\r
+\r
+Return Value:\r
+    TRUE if successful\r
+    FALSE otherwise  -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_SetNumInputBuffers (\r
+    IN  HANDLE HidDeviceObject,\r
+    OUT ULONG  NumberBuffers\r
+    );\r
+/*++\r
+\r
+Routine Description:\r
+    This function sets the number of input buffers used by the specified\r
+    file handle to the Hid device.  Each file object has a number of buffers\r
+    associated with it to queue reports read from the device but which have\r
+    not yet been read by the user-mode app with a handle to that device.\r
+\r
+Arguments:\r
+    HidDeviceObject      A handle to a Hid Device Object.\r
\r
+    NumberBuffers        New number of buffers to use for this file handle to\r
+                         the Hid device\r
+\r
+Return Value:\r
+    TRUE if successful\r
+    FALSE otherwise  -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetPhysicalDescriptor (\r
+   IN    HANDLE   HidDeviceObject,\r
+   OUT   PVOID    Buffer,\r
+   IN    ULONG    BufferLength\r
+   );\r
+/*++\r
+Routine Description:\r
+    This function retrieves the raw physical descriptor for the specified\r
+    Hid device.  \r
+\r
+Arguments:\r
+    HidDeviceObject      A handle to a Hid Device Object.\r
\r
+    Buffer               Buffer which on return will contain the physical\r
+                         descriptor if one exists for the specified device\r
+                         handle\r
+\r
+    BufferLength         Length of buffer (in bytes)\r
+\r
+\r
+Return Value:\r
+    TRUE if successful\r
+    FALSE otherwise  -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetManufacturerString (\r
+   IN    HANDLE   HidDeviceObject,\r
+   OUT   PVOID    Buffer,\r
+   IN    ULONG    BufferLength\r
+   );\r
+/*++\r
+Routine Description:\r
+    This function retrieves the manufacturer string from the specified \r
+    Hid device.  \r
+\r
+Arguments:\r
+    HidDeviceObject      A handle to a Hid Device Object.\r
\r
+    Buffer               Buffer which on return will contain the manufacturer\r
+                         string returned from the device.  This string is a \r
+                         wide-character string\r
+\r
+    BufferLength         Length of Buffer (in bytes)\r
+\r
+\r
+Return Value:\r
+    TRUE if successful\r
+    FALSE otherwise  -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetProductString (\r
+   IN    HANDLE   HidDeviceObject,\r
+   OUT   PVOID    Buffer,\r
+   IN    ULONG    BufferLength\r
+   );\r
+/*++\r
+Routine Description:\r
+    This function retrieves the product string from the specified \r
+    Hid device.  \r
+\r
+Arguments:\r
+    HidDeviceObject      A handle to a Hid Device Object.\r
\r
+    Buffer               Buffer which on return will contain the product\r
+                         string returned from the device.  This string is a \r
+                         wide-character string\r
+\r
+    BufferLength         Length of Buffer (in bytes)\r
+\r
+\r
+Return Value:\r
+    TRUE if successful\r
+    FALSE otherwise  -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetIndexedString (\r
+   IN    HANDLE   HidDeviceObject,\r
+   IN    ULONG    StringIndex,\r
+   OUT   PVOID    Buffer,\r
+   IN    ULONG    BufferLength\r
+   );\r
+/*++\r
+Routine Description:\r
+    This function retrieves a string from the specified Hid device that is\r
+    specified with a certain string index.\r
+\r
+Arguments:\r
+    HidDeviceObject      A handle to a Hid Device Object.\r
\r
+    StringIndex          Index of the string to retrieve\r
+\r
+    Buffer               Buffer which on return will contain the product\r
+                         string returned from the device.  This string is a \r
+                         wide-character string\r
+\r
+    BufferLength         Length of Buffer (in bytes)\r
+\r
+Return Value:\r
+    TRUE if successful\r
+    FALSE otherwise  -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetSerialNumberString (\r
+   IN    HANDLE   HidDeviceObject,\r
+   OUT   PVOID    Buffer,\r
+   IN    ULONG    BufferLength\r
+   );\r
+/*++\r
+Routine Description:\r
+    This function retrieves the serial number string from the specified \r
+    Hid device.  \r
+\r
+Arguments:\r
+    HidDeviceObject      A handle to a Hid Device Object.\r
\r
+    Buffer               Buffer which on return will contain the serial number\r
+                         string returned from the device.  This string is a \r
+                         wide-character string\r
+\r
+    BufferLength         Length of Buffer (in bytes)\r
+\r
+Return Value:\r
+    TRUE if successful\r
+    FALSE otherwise  -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+\r
+#include <poppack.h>\r
+\r
+#endif\r
diff --git a/winsrc/include/hidusage.h b/winsrc/include/hidusage.h
new file mode 100644 (file)
index 0000000..4ea9dd1
--- /dev/null
@@ -0,0 +1,263 @@
+/*++\r
+\r
+Copyright (c) 1996, 1997      Microsoft Corporation\r
+\r
+Module Name:\r
+\r
+        HIDUSAGE.H\r
+\r
+Abstract:\r
+\r
+   Public Definitions of HID USAGES.\r
+\r
+Environment:\r
+\r
+    Kernel & user mode\r
+\r
+--*/\r
+\r
+#ifndef   __HIDUSAGE_H__\r
+#define   __HIDUSAGE_H__\r
+\r
+//\r
+// Usage Pages\r
+//\r
+\r
+typedef USHORT USAGE, *PUSAGE;\r
+\r
+#define HID_USAGE_PAGE_GENERIC        ((USAGE) 0x01)\r
+#define HID_USAGE_PAGE_SIMULATION     ((USAGE) 0x02)\r
+#define HID_USAGE_PAGE_VR             ((USAGE) 0x03)\r
+#define HID_USAGE_PAGE_SPORT          ((USAGE) 0x04)\r
+#define HID_USAGE_PAGE_GAME           ((USAGE) 0x05)\r
+#define HID_USAGE_PAGE_KEYBOARD       ((USAGE) 0x07)\r
+#define HID_USAGE_PAGE_LED            ((USAGE) 0x08)\r
+#define HID_USAGE_PAGE_BUTTON         ((USAGE) 0x09)\r
+#define HID_USAGE_PAGE_ORDINAL        ((USAGE) 0x0A)\r
+#define HID_USAGE_PAGE_TELEPHONY      ((USAGE) 0x0B)\r
+#define HID_USAGE_PAGE_CONSUMER       ((USAGE) 0x0C)\r
+#define HID_USAGE_PAGE_DIGITIZER      ((USAGE) 0x0D)\r
+#define HID_USAGE_PAGE_UNICODE        ((USAGE) 0x10)\r
+#define HID_USAGE_PAGE_ALPHANUMERIC   ((USAGE) 0x14)\r
+\r
+\r
+//\r
+// Usages from Generic Desktop Page (0x01)\r
+//\r
+\r
+#define HID_USAGE_GENERIC_POINTER      ((USAGE) 0x01)\r
+#define HID_USAGE_GENERIC_MOUSE        ((USAGE) 0x02)\r
+#define HID_USAGE_GENERIC_JOYSTICK     ((USAGE) 0x04)\r
+#define HID_USAGE_GENERIC_GAMEPAD      ((USAGE) 0x05)\r
+#define HID_USAGE_GENERIC_KEYBOARD     ((USAGE) 0x06)\r
+#define HID_USAGE_GENERIC_KEYPAD       ((USAGE) 0x07)\r
+#define HID_USAGE_GENERIC_SYSTEM_CTL   ((USAGE) 0x80)\r
+\r
+#define HID_USAGE_GENERIC_X                        ((USAGE) 0x30)\r
+#define HID_USAGE_GENERIC_Y                        ((USAGE) 0x31)\r
+#define HID_USAGE_GENERIC_Z                        ((USAGE) 0x32)\r
+#define HID_USAGE_GENERIC_RX                       ((USAGE) 0x33)\r
+#define HID_USAGE_GENERIC_RY                       ((USAGE) 0x34)\r
+#define HID_USAGE_GENERIC_RZ                       ((USAGE) 0x35)\r
+#define HID_USAGE_GENERIC_SLIDER                   ((USAGE) 0x36)\r
+#define HID_USAGE_GENERIC_DIAL                     ((USAGE) 0x37)\r
+#define HID_USAGE_GENERIC_WHEEL                    ((USAGE) 0x38)\r
+#define HID_USAGE_GENERIC_HATSWITCH                ((USAGE) 0x39)\r
+#define HID_USAGE_GENERIC_COUNTED_BUFFER           ((USAGE) 0x3A)\r
+#define HID_USAGE_GENERIC_BYTE_COUNT               ((USAGE) 0x3B)\r
+#define HID_USAGE_GENERIC_MOTION_WAKEUP            ((USAGE) 0x3C)\r
+#define HID_USAGE_GENERIC_VX                       ((USAGE) 0x40)\r
+#define HID_USAGE_GENERIC_VY                       ((USAGE) 0x41)\r
+#define HID_USAGE_GENERIC_VZ                       ((USAGE) 0x42)\r
+#define HID_USAGE_GENERIC_VBRX                     ((USAGE) 0x43)\r
+#define HID_USAGE_GENERIC_VBRY                     ((USAGE) 0x44)\r
+#define HID_USAGE_GENERIC_VBRZ                     ((USAGE) 0x45)\r
+#define HID_USAGE_GENERIC_VNO                      ((USAGE) 0x46)\r
+#define HID_USAGE_GENERIC_SYSCTL_POWER             ((USAGE) 0x81)\r
+#define HID_USAGE_GENERIC_SYSCTL_SLEEP             ((USAGE) 0x82)\r
+#define HID_USAGE_GENERIC_SYSCTL_WAKE              ((USAGE) 0x83)\r
+#define HID_USAGE_GENERIC_SYSCTL_CONTEXT_MENU      ((USAGE) 0x84)\r
+#define HID_USAGE_GENERIC_SYSCTL_MAIN_MENU         ((USAGE) 0x85)\r
+#define HID_USAGE_GENERIC_SYSCTL_APP_MENU          ((USAGE) 0x86)\r
+#define HID_USAGE_GENERIC_SYSCTL_HELP_MENU         ((USAGE) 0x87)\r
+#define HID_USAGE_GENERIC_SYSCTL_MENU_EXIT         ((USAGE) 0x88)\r
+#define HID_USAGE_GENERIC_SYSCTL_MENU_SELECT       ((USAGE) 0x89)\r
+#define HID_USAGE_GENERIC_SYSCTL_MENU_RIGHT        ((USAGE) 0x8A)\r
+#define HID_USAGE_GENERIC_SYSCTL_MENU_LEFT         ((USAGE) 0x8B)\r
+#define HID_USAGE_GENERIC_SYSCTL_MENU_UP           ((USAGE) 0x8C)\r
+#define HID_USAGE_GENERIC_SYSCTL_MENU_DOWN         ((USAGE) 0x8D)\r
+\r
+//\r
+// Usages from Simulation Controls Page (0x02)\r
+//\r
+\r
+#define HID_USAGE_SIMULATION_RUDDER                ((USAGE) 0xBA)\r
+#define HID_USAGE_SIMULATION_THROTTLE              ((USAGE) 0xBB)\r
+\r
+//\r
+// Virtual Reality Controls Page (0x03)\r
+//\r
+\r
+\r
+//\r
+// Sport Controls Page (0x04)\r
+//\r
+\r
+\r
+//\r
+// Game Controls Page (0x05)\r
+//\r
+\r
+\r
+//\r
+// Keyboard/Keypad Page (0x07)\r
+//\r
+\r
+        // Error "keys"\r
+#define HID_USAGE_KEYBOARD_NOEVENT     ((USAGE) 0x00)\r
+#define HID_USAGE_KEYBOARD_ROLLOVER    ((USAGE) 0x01)\r
+#define HID_USAGE_KEYBOARD_POSTFAIL    ((USAGE) 0x02)\r
+#define HID_USAGE_KEYBOARD_UNDEFINED   ((USAGE) 0x03)\r
+\r
+        // Letters\r
+#define HID_USAGE_KEYBOARD_aA          ((USAGE) 0x04)\r
+#define HID_USAGE_KEYBOARD_zZ          ((USAGE) 0x1D)\r
+        // Numbers\r
+#define HID_USAGE_KEYBOARD_ONE         ((USAGE) 0x1E)\r
+#define HID_USAGE_KEYBOARD_ZERO        ((USAGE) 0x27)\r
+        // Modifier Keys\r
+#define HID_USAGE_KEYBOARD_LCTRL       ((USAGE) 0xE0)\r
+#define HID_USAGE_KEYBOARD_LSHFT       ((USAGE) 0xE1)\r
+#define HID_USAGE_KEYBOARD_LALT        ((USAGE) 0xE2)\r
+#define HID_USAGE_KEYBOARD_LGUI        ((USAGE) 0xE3)\r
+#define HID_USAGE_KEYBOARD_RCTRL       ((USAGE) 0xE4)\r
+#define HID_USAGE_KEYBOARD_RSHFT       ((USAGE) 0xE5)\r
+#define HID_USAGE_KEYBOARD_RALT        ((USAGE) 0xE6)\r
+#define HID_USAGE_KEYBOARD_RGUI        ((USAGE) 0xE7)\r
+#define HID_USAGE_KEYBOARD_SCROLL_LOCK ((USAGE) 0x47)\r
+#define HID_USAGE_KEYBOARD_NUM_LOCK    ((USAGE) 0x53)\r
+#define HID_USAGE_KEYBOARD_CAPS_LOCK   ((USAGE) 0x39)\r
+        // Funtion keys\r
+#define HID_USAGE_KEYBOARD_F1          ((USAGE) 0x3A)\r
+#define HID_USAGE_KEYBOARD_F12         ((USAGE) 0x45)\r
+\r
+#define HID_USAGE_KEYBOARD_RETURN      ((USAGE) 0x28)\r
+#define HID_USAGE_KEYBOARD_ESCAPE      ((USAGE) 0x29)\r
+#define HID_USAGE_KEYBOARD_DELETE      ((USAGE) 0x2A)\r
+\r
+#define HID_USAGE_KEYBOARD_PRINT_SCREEN ((USAGE) 0x46)\r
+\r
+// and hundreds more...\r
+\r
+//\r
+// LED Page (0x08)\r
+//\r
+\r
+#define HID_USAGE_LED_NUM_LOCK               ((USAGE) 0x01)\r
+#define HID_USAGE_LED_CAPS_LOCK              ((USAGE) 0x02)\r
+#define HID_USAGE_LED_SCROLL_LOCK            ((USAGE) 0x03)\r
+#define HID_USAGE_LED_COMPOSE                ((USAGE) 0x04)\r
+#define HID_USAGE_LED_KANA                   ((USAGE) 0x05)\r
+#define HID_USAGE_LED_POWER                  ((USAGE) 0x06)\r
+#define HID_USAGE_LED_SHIFT                  ((USAGE) 0x07)\r
+#define HID_USAGE_LED_DO_NOT_DISTURB         ((USAGE) 0x08)\r
+#define HID_USAGE_LED_MUTE                   ((USAGE) 0x09)\r
+#define HID_USAGE_LED_TONE_ENABLE            ((USAGE) 0x0A)\r
+#define HID_USAGE_LED_HIGH_CUT_FILTER        ((USAGE) 0x0B)\r
+#define HID_USAGE_LED_LOW_CUT_FILTER         ((USAGE) 0x0C)\r
+#define HID_USAGE_LED_EQUALIZER_ENABLE       ((USAGE) 0x0D)\r
+#define HID_USAGE_LED_SOUND_FIELD_ON         ((USAGE) 0x0E)\r
+#define HID_USAGE_LED_SURROUND_FIELD_ON      ((USAGE) 0x0F)\r
+#define HID_USAGE_LED_REPEAT                 ((USAGE) 0x10)\r
+#define HID_USAGE_LED_STEREO                 ((USAGE) 0x11)\r
+#define HID_USAGE_LED_SAMPLING_RATE_DETECT   ((USAGE) 0x12)\r
+#define HID_USAGE_LED_SPINNING               ((USAGE) 0x13)\r
+#define HID_USAGE_LED_CAV                    ((USAGE) 0x14)\r
+#define HID_USAGE_LED_CLV                    ((USAGE) 0x15)\r
+#define HID_USAGE_LED_RECORDING_FORMAT_DET   ((USAGE) 0x16)\r
+#define HID_USAGE_LED_OFF_HOOK               ((USAGE) 0x17)\r
+#define HID_USAGE_LED_RING                   ((USAGE) 0x18)\r
+#define HID_USAGE_LED_MESSAGE_WAITING        ((USAGE) 0x19)\r
+#define HID_USAGE_LED_DATA_MODE              ((USAGE) 0x1A)\r
+#define HID_USAGE_LED_BATTERY_OPERATION      ((USAGE) 0x1B)\r
+#define HID_USAGE_LED_BATTERY_OK             ((USAGE) 0x1C)\r
+#define HID_USAGE_LED_BATTERY_LOW            ((USAGE) 0x1D)\r
+#define HID_USAGE_LED_SPEAKER                ((USAGE) 0x1E)\r
+#define HID_USAGE_LED_HEAD_SET               ((USAGE) 0x1F)\r
+#define HID_USAGE_LED_HOLD                   ((USAGE) 0x20)\r
+#define HID_USAGE_LED_MICROPHONE             ((USAGE) 0x21)\r
+#define HID_USAGE_LED_COVERAGE               ((USAGE) 0x22)\r
+#define HID_USAGE_LED_NIGHT_MODE             ((USAGE) 0x23)\r
+#define HID_USAGE_LED_SEND_CALLS             ((USAGE) 0x24)\r
+#define HID_USAGE_LED_CALL_PICKUP            ((USAGE) 0x25)\r
+#define HID_USAGE_LED_CONFERENCE             ((USAGE) 0x26)\r
+#define HID_USAGE_LED_STAND_BY               ((USAGE) 0x27)\r
+#define HID_USAGE_LED_CAMERA_ON              ((USAGE) 0x28)\r
+#define HID_USAGE_LED_CAMERA_OFF             ((USAGE) 0x29)\r
+#define HID_USAGE_LED_ON_LINE                ((USAGE) 0x2A)\r
+#define HID_USAGE_LED_OFF_LINE               ((USAGE) 0x2B)\r
+#define HID_USAGE_LED_BUSY                   ((USAGE) 0x2C)\r
+#define HID_USAGE_LED_READY                  ((USAGE) 0x2D)\r
+#define HID_USAGE_LED_PAPER_OUT              ((USAGE) 0x2E)\r
+#define HID_USAGE_LED_PAPER_JAM              ((USAGE) 0x2F)\r
+#define HID_USAGE_LED_REMOTE                 ((USAGE) 0x30)\r
+#define HID_USAGE_LED_FORWARD                ((USAGE) 0x31)\r
+#define HID_USAGE_LED_REVERSE                ((USAGE) 0x32)\r
+#define HID_USAGE_LED_STOP                   ((USAGE) 0x33)\r
+#define HID_USAGE_LED_REWIND                 ((USAGE) 0x34)\r
+#define HID_USAGE_LED_FAST_FORWARD           ((USAGE) 0x35)\r
+#define HID_USAGE_LED_PLAY                   ((USAGE) 0x36)\r
+#define HID_USAGE_LED_PAUSE                  ((USAGE) 0x37)\r
+#define HID_USAGE_LED_RECORD                 ((USAGE) 0x38)\r
+#define HID_USAGE_LED_ERROR                  ((USAGE) 0x39)\r
+#define HID_USAGE_LED_SELECTED_INDICATOR     ((USAGE) 0x3A)\r
+#define HID_USAGE_LED_IN_USE_INDICATOR       ((USAGE) 0x3B)\r
+#define HID_USAGE_LED_MULTI_MODE_INDICATOR   ((USAGE) 0x3C)\r
+#define HID_USAGE_LED_INDICATOR_ON           ((USAGE) 0x3D)\r
+#define HID_USAGE_LED_INDICATOR_FLASH        ((USAGE) 0x3E)\r
+#define HID_USAGE_LED_INDICATOR_SLOW_BLINK   ((USAGE) 0x3F)\r
+#define HID_USAGE_LED_INDICATOR_FAST_BLINK   ((USAGE) 0x40)\r
+#define HID_USAGE_LED_INDICATOR_OFF          ((USAGE) 0x41)\r
+#define HID_USAGE_LED_FLASH_ON_TIME          ((USAGE) 0x42)\r
+#define HID_USAGE_LED_SLOW_BLINK_ON_TIME     ((USAGE) 0x43)\r
+#define HID_USAGE_LED_SLOW_BLINK_OFF_TIME    ((USAGE) 0x44)\r
+#define HID_USAGE_LED_FAST_BLINK_ON_TIME     ((USAGE) 0x45)\r
+#define HID_USAGE_LED_FAST_BLINK_OFF_TIME    ((USAGE) 0x46)\r
+#define HID_USAGE_LED_INDICATOR_COLOR        ((USAGE) 0x47)\r
+#define HID_USAGE_LED_RED                    ((USAGE) 0x48)\r
+#define HID_USAGE_LED_GREEN                  ((USAGE) 0x49)\r
+#define HID_USAGE_LED_AMBER                  ((USAGE) 0x4A)\r
+#define HID_USAGE_LED_GENERIC_INDICATOR      ((USAGE) 0x3B)\r
+\r
+//\r
+//  Button Page (0x09)\r
+//\r
+//  There is no need to label these usages.\r
+//\r
+\r
+\r
+//\r
+//  Ordinal Page (0x0A)\r
+//\r
+//  There is no need to label these usages.\r
+//\r
+\r
+\r
+//\r
+//  Telephony Device Page (0x0B)\r
+//\r
+\r
+#define HID_USAGE_TELEPHONY_PHONE                  ((USAGE) 0x01)\r
+#define HID_USAGE_TELEPHONY_ANSWERING_MACHINE      ((USAGE) 0x02)\r
+#define HID_USAGE_TELEPHONY_MESSAGE_CONTROLS       ((USAGE) 0x03)\r
+#define HID_USAGE_TELEPHONY_HANDSET                ((USAGE) 0x04)\r
+#define HID_USAGE_TELEPHONY_HEADSET                ((USAGE) 0x05)\r
+#define HID_USAGE_TELEPHONY_KEYPAD                 ((USAGE) 0x06)\r
+#define HID_USAGE_TELEPHONY_PROGRAMMABLE_BUTTON    ((USAGE) 0x07)\r
+\r
+//\r
+// and others...\r
+//\r
+\r
+\r
+#endif\r
diff --git a/winsrc/prox.cpp b/winsrc/prox.cpp
new file mode 100644 (file)
index 0000000..e95a4af
--- /dev/null
@@ -0,0 +1,379 @@
+#include <windows.h>\r
+#include <setupapi.h>\r
+#include <stdio.h>\r
+#include <ctype.h>\r
+#include <stdlib.h>\r
+extern "C" {\r
+#include "include/hidsdi.h"\r
+#include "include/hidpi.h"\r
+}\r
+\r
+#include "prox.h"\r
+\r
+#define OUR_VID 0x9ac4\r
+#define OUR_PID 0x4b8f\r
+\r
+HANDLE UsbHandle;\r
+\r
+static void ShowError(void)\r
+{\r
+       char buf[1024];\r
+       FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,\r
+               buf, sizeof(buf), NULL);\r
+       printf("ERROR: %s", buf);\r
+}\r
+\r
+static BOOL UsbConnect(void)\r
+{\r
+       typedef void (__stdcall *GetGuidProc)(GUID *);\r
+       typedef BOOLEAN (__stdcall *GetAttrProc)(HANDLE, HIDD_ATTRIBUTES *);\r
+       typedef BOOLEAN (__stdcall *GetPreparsedProc)(HANDLE,\r
+                                                                               PHIDP_PREPARSED_DATA *);\r
+       typedef NTSTATUS (__stdcall *GetCapsProc)(PHIDP_PREPARSED_DATA, PHIDP_CAPS);\r
+       GetGuidProc                     getGuid;\r
+       GetAttrProc                     getAttr;\r
+       GetPreparsedProc        getPreparsed;\r
+       GetCapsProc                     getCaps;\r
+\r
+       HMODULE h               = LoadLibrary("hid.dll");\r
+       getGuid                 = (GetGuidProc)GetProcAddress(h, "HidD_GetHidGuid");\r
+       getAttr                 = (GetAttrProc)GetProcAddress(h, "HidD_GetAttributes");\r
+       getPreparsed    = (GetPreparsedProc)GetProcAddress(h, "HidD_GetPreparsedData");\r
+       getCaps                 = (GetCapsProc)GetProcAddress(h, "HidP_GetCaps");\r
+\r
+       GUID hidGuid;\r
+       getGuid(&hidGuid);\r
+\r
+       HDEVINFO devInfo;\r
+       devInfo = SetupDiGetClassDevs(&hidGuid, NULL, NULL,\r
+               DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);\r
+\r
+       SP_DEVICE_INTERFACE_DATA devInfoData;\r
+       devInfoData.cbSize = sizeof(devInfoData);\r
+\r
+       int i;\r
+       for(i = 0;; i++) {\r
+               if(!SetupDiEnumDeviceInterfaces(devInfo, 0, &hidGuid, i, &devInfoData))\r
+               {\r
+                       if(GetLastError() != ERROR_NO_MORE_ITEMS) {\r
+//                             printf("SetupDiEnumDeviceInterfaces failed\n");\r
+                       }\r
+//                     printf("done list\n");\r
+                       SetupDiDestroyDeviceInfoList(devInfo);\r
+                       return FALSE;\r
+               }\r
+\r
+//             printf("item %d:\n", i);\r
+\r
+               DWORD sizeReqd = 0;\r
+               if(!SetupDiGetDeviceInterfaceDetail(devInfo, &devInfoData,\r
+                       NULL, 0, &sizeReqd, NULL))\r
+               {\r
+                       if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {\r
+//                             printf("SetupDiGetDeviceInterfaceDetail (0) failed\n");\r
+                               continue;\r
+                       }\r
+               }\r
+\r
+               SP_DEVICE_INTERFACE_DETAIL_DATA *devInfoDetailData =\r
+                       (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(sizeReqd);\r
+               devInfoDetailData->cbSize = sizeof(*devInfoDetailData);\r
+\r
+               if(!SetupDiGetDeviceInterfaceDetail(devInfo, &devInfoData,\r
+                       devInfoDetailData, 87, NULL, NULL))\r
+               {\r
+//                     printf("SetupDiGetDeviceInterfaceDetail (1) failed\n");\r
+                       continue;\r
+               }\r
+\r
+               char *path = devInfoDetailData->DevicePath;\r
+\r
+               UsbHandle = CreateFile(path, /*GENERIC_READ |*/ GENERIC_WRITE,\r
+                       FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,\r
+                       FILE_FLAG_OVERLAPPED, NULL);\r
+\r
+               if(UsbHandle == INVALID_HANDLE_VALUE) {\r
+                       ShowError();\r
+//                     printf("CreateFile failed: for '%s'\n", path);\r
+                       continue;\r
+               }\r
+\r
+               HIDD_ATTRIBUTES attr;\r
+               attr.Size = sizeof(attr);\r
+               if(!getAttr(UsbHandle, &attr)) {\r
+                       ShowError();\r
+//                     printf("HidD_GetAttributes failed\n");\r
+                       continue;\r
+               }\r
+\r
+//             printf("VID: %04x PID %04x\n", attr.VendorID, attr.ProductID);\r
+\r
+               if(attr.VendorID != OUR_VID || attr.ProductID != OUR_PID) {\r
+                       CloseHandle(UsbHandle);\r
+//                     printf("        nope, not us\n");\r
+                       continue;\r
+               }\r
+\r
+//             printf ("got it!\n");\r
+               CloseHandle(UsbHandle);\r
+\r
+               UsbHandle = CreateFile(path, GENERIC_READ | GENERIC_WRITE,\r
+                       FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,\r
+                       FILE_FLAG_OVERLAPPED, NULL);\r
+\r
+               if(UsbHandle == INVALID_HANDLE_VALUE) {\r
+                       ShowError();\r
+//                     printf("Error, couldn't open our own handle as desired.\n");\r
+                       return FALSE;\r
+               }\r
+\r
+               PHIDP_PREPARSED_DATA pp;\r
+               getPreparsed(UsbHandle, &pp);\r
+               HIDP_CAPS caps;\r
+\r
+               if(getCaps(pp, &caps) != HIDP_STATUS_SUCCESS) {\r
+//                     printf("getcaps failed\n");\r
+                       return FALSE;\r
+               }\r
+\r
+//             printf("input/out report %d/%d\n", caps.InputReportByteLength,\r
+//                     caps.OutputReportByteLength);\r
+\r
+\r
+               return TRUE;\r
+       }\r
+       return FALSE;\r
+}\r
+\r
+BOOL ReceiveCommandPoll(UsbCommand *c)\r
+{\r
+       static BOOL ReadInProgress = FALSE;\r
+       static OVERLAPPED Ov;\r
+       static BYTE Buf[65];\r
+       static DWORD HaveRead;\r
+\r
+       if(!ReadInProgress) {\r
+               memset(&Ov, 0, sizeof(Ov));\r
+               ReadFile(UsbHandle, Buf, 65, &HaveRead, &Ov);\r
+               if(GetLastError() != ERROR_IO_PENDING) {\r
+                       ShowError();\r
+                       exit(-1);\r
+               }\r
+               ReadInProgress = TRUE;\r
+       }\r
+\r
+       if(HasOverlappedIoCompleted(&Ov)) {\r
+               ReadInProgress = FALSE;\r
+\r
+               if(!GetOverlappedResult(UsbHandle, &Ov, &HaveRead, FALSE)) {\r
+                       ShowError();\r
+                       exit(-1);\r
+               }\r
+\r
+               memcpy(c, Buf+1, 64);\r
+\r
+               return TRUE;\r
+       } else {\r
+               return FALSE;\r
+       }\r
+}\r
+\r
+void ReceiveCommand(UsbCommand *c)\r
+{\r
+       while(!ReceiveCommandPoll(c)) {\r
+               Sleep(0);\r
+       }\r
+}\r
+\r
+void SendCommand(UsbCommand *c, BOOL wantAck)\r
+{\r
+       BYTE buf[65];\r
+       buf[0] = 0;\r
+       memcpy(buf+1, c, 64);\r
+\r
+       DWORD written;\r
+       OVERLAPPED ov;\r
+       memset(&ov, 0, sizeof(ov));\r
+       WriteFile(UsbHandle, buf, 65, &written, &ov);\r
+       if(GetLastError() != ERROR_IO_PENDING) {\r
+               ShowError();\r
+               exit(-1);\r
+       }\r
+\r
+       while(!HasOverlappedIoCompleted(&ov)) {\r
+               Sleep(0);\r
+       }\r
+\r
+       if(!GetOverlappedResult(UsbHandle, &ov, &written, FALSE)) {\r
+               ShowError();\r
+               exit(-1);\r
+       }\r
+\r
+       if(wantAck) {\r
+               UsbCommand ack;\r
+               ReceiveCommand(&ack);\r
+               if(ack.cmd != CMD_ACK) {\r
+                       printf("bad ACK\n");\r
+                       exit(-1);\r
+               }\r
+       }\r
+}\r
+\r
+static DWORD ExpectedAddr;\r
+static BYTE QueuedToSend[256];\r
+static BOOL AllWritten;\r
+\r
+static void FlushPrevious(void)\r
+{\r
+       UsbCommand c;\r
+       memset(&c, 0, sizeof(c));\r
+\r
+       printf("expected = %08x flush, ", ExpectedAddr);\r
+\r
+       int i;\r
+       for(i = 0; i < 240; i += 48) {\r
+               c.cmd = CMD_SETUP_WRITE;\r
+               memcpy(c.d.asBytes, QueuedToSend+i, 48);\r
+               c.ext1 = (i/4);\r
+               SendCommand(&c, TRUE);\r
+       }\r
+\r
+       c.cmd = CMD_FINISH_WRITE;\r
+       c.ext1 = (ExpectedAddr-1) & (~255);\r
+       printf("c.ext1 = %08x\r", c.ext1);\r
+       memcpy(c.d.asBytes, QueuedToSend+240, 16);\r
+       SendCommand(&c, TRUE);\r
+\r
+       AllWritten = TRUE;\r
+}\r
+\r
+static void GotByte(DWORD where, BYTE which)\r
+{\r
+       AllWritten = FALSE;\r
+\r
+       if(where != ExpectedAddr) {\r
+               printf("bad: got at %08x, expected at %08x\n", where, ExpectedAddr);\r
+               exit(-1);\r
+       }\r
+       QueuedToSend[where & 255] = which;\r
+       ExpectedAddr++;\r
+\r
+       if((where & 255) == 255) {\r
+               // we have completed a full page\r
+               FlushPrevious();\r
+       }\r
+}\r
+\r
+static int HexVal(int c)\r
+{\r
+       c = tolower(c);\r
+       if(c >= '0' && c <= '9') {\r
+               return c - '0';\r
+       } else if(c >= 'a' && c <= 'f') {\r
+               return (c - 'a') + 10;\r
+       } else {\r
+               printf("bad hex digit '%c'\n", c);\r
+               exit(-1);\r
+       }\r
+}\r
+\r
+static BYTE HexByte(char *s)\r
+{\r
+       return (HexVal(s[0]) << 4) | HexVal(s[1]);\r
+}\r
+\r
+static void LoadFlashFromSRecords(char *file, int addr)\r
+{\r
+       ExpectedAddr = addr;\r
+\r
+       FILE *f = fopen(file, "r");\r
+       if(!f) {\r
+               printf("couldn't open file\n");\r
+               exit(-1);\r
+       }\r
+\r
+       char line[512];\r
+       while(fgets(line, sizeof(line), f)) {\r
+               if(memcmp(line, "S3", 2)==0) {\r
+                       char *s = line + 2;\r
+                       int len = HexByte(s) - 5;\r
+                       s += 2;\r
+\r
+                       char addrStr[9];\r
+                       memcpy(addrStr, s, 8);\r
+                       addrStr[8] = '\0';\r
+                       DWORD addr;\r
+                       sscanf(addrStr, "%x", &addr);\r
+                       s += 8;\r
+\r
+                       int i;\r
+                       for(i = 0; i < len; i++) {\r
+                               while((addr+i) > ExpectedAddr) {\r
+                                       GotByte(ExpectedAddr, 0xff);\r
+                               }\r
+                               GotByte(addr+i, HexByte(s));\r
+                               s += 2;\r
+                       }\r
+               }\r
+       }\r
+\r
+       if(!AllWritten) FlushPrevious();\r
+\r
+       fclose(f);\r
+       printf("\ndone.\n");\r
+}\r
+\r
+int main(int argc, char **argv)\r
+{\r
+       int i = 0;\r
+\r
+       if(argc < 2) {\r
+               printf("Usage: %s bootrom file.s19\n", argv[0]);\r
+               printf("       %s load osimage.s19\n", argv[0]);\r
+               printf("       %s fpga fpgaimg.s19\n", argv[0]);\r
+               printf("       %s gui\n", argv[0]);\r
+               return -1;\r
+       }\r
+\r
+       for(;;) {\r
+               if(UsbConnect()) {\r
+                       break;\r
+               }\r
+               if(i == 0) {\r
+                       printf("...no device connected, polling for it now\n");\r
+               }\r
+               if(i > 50000) {\r
+                       printf("Could not connect to USB device; exiting.\n");\r
+                       return -1;\r
+               }\r
+               i++;\r
+               Sleep(5);\r
+       }\r
+\r
+       if(strcmp(argv[1], "bootrom")==0 || strcmp(argv[1], "load")==0 || strcmp(argv[1], "fpga")==0) {\r
+               if(argc != 3) {\r
+                       printf("Need filename.\n");\r
+                       return -1;\r
+               }\r
+               if(strcmp(argv[1], "bootrom")==0) {\r
+                       LoadFlashFromSRecords(argv[2], 0);\r
+               } else if(strcmp(argv[1], "fpga")==0) {\r
+                       LoadFlashFromSRecords(argv[2], 0x2000);\r
+               } else {\r
+                       LoadFlashFromSRecords(argv[2], 0x10000);\r
+               }\r
+       } else if(strcmp(argv[1], "gui")==0) {\r
+               ShowGui();\r
+       } else if(strcmp(argv[1], "cmd")==0) {\r
+               if(argc != 3) {\r
+                       printf("Need command.\n");\r
+                       return -1;\r
+               }\r
+               ExecCmd(argv[2]);\r
+       } else {\r
+               printf("Command '%s' not recognized.\n", argv[1]);\r
+               return -1;\r
+       }\r
+\r
+       return 0;\r
+}\r
diff --git a/winsrc/prox.h b/winsrc/prox.h
new file mode 100644 (file)
index 0000000..f3be604
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __PROX_H\r
+#define __PROX_H\r
+\r
+#include "../include/usb_cmd.h"\r
+\r
+// prox.cpp\r
+void ReceiveCommand(UsbCommand *c);\r
+BOOL ReceiveCommandPoll(UsbCommand *c);\r
+void SendCommand(UsbCommand *c, BOOL wantAck);\r
+\r
+// gui.cpp\r
+void ShowGui(void);\r
+void HideGraphWindow(void);\r
+void ShowGraphWindow(void);\r
+void RepaintGraphWindow(void);\r
+void PrintToScrollback(char *fmt, ...);\r
+#define MAX_GRAPH_TRACE_LEN (1024*128)\r
+extern int GraphBuffer[MAX_GRAPH_TRACE_LEN];\r
+extern int GraphTraceLen;\r
+extern double CursorScaleFactor;\r
+extern int CommandFinished;\r
+\r
+// command.cpp\r
+void CommandReceived(char *cmd);\r
+void UsbCommandReceived(UsbCommand *c);\r
+\r
+// cmdline.cpp\r
+void ShowCommandline(void);\r
+void ExecCmd(char *cmd);\r
+//void PrintToScrollback(char *fmt, ...);\r
+\r
+#endif\r
diff --git a/winsrc/vc90.pdb b/winsrc/vc90.pdb
new file mode 100644 (file)
index 0000000..2451797
Binary files /dev/null and b/winsrc/vc90.pdb differ
Impressum, Datenschutz