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
+     &n