--- /dev/null
+\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
--- /dev/null
+\r
+MAY 2008: Added ISO14443 type A support, Gerhard de Koning Gans\r
+\r
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+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
--- /dev/null
+//-----------------------------------------------------------------------------\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
--- /dev/null
+//-----------------------------------------------------------------------------\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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+#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
--- /dev/null
+//-----------------------------------------------------------------------------\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
--- /dev/null
+//-----------------------------------------------------------------------------\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
--- /dev/null
+//-----------------------------------------------------------------------------\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
--- /dev/null
+//-----------------------------------------------------------------------------\r
+// Routines to support ISO 15693. This includes both the reader software and\r
+// the `fake tag' modes, but at the moment I've implemented only the reader\r
+// stuff, and that barely.\r
+// Jonathan Westhues, split Nov 2006\r
+\r
+// Modified by Greg Jones, Jan 2009 to perform modulation onboard in arm rather than on PC\r
+// Also added additional reader commands (SELECT, READ etc.)\r
+\r
+//-----------------------------------------------------------------------------\r
+#include <proxmark3.h>\r
+#include "apps.h"\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+// FROM winsrc\prox.h //////////////////////////////////\r
+#define arraylen(x) (sizeof(x)/sizeof((x)[0]))\r
+\r
+//-----------------------------------------------------------------------------\r
+// Map a sequence of octets (~layer 2 command) into the set of bits to feed\r
+// to the FPGA, to transmit that command to the tag.\r
+//-----------------------------------------------------------------------------\r
+\r
+ \r
+\r
+\r
+ // The sampling rate is 106.353 ksps/s, for T = 18.8 us\r
+\r
+ // SOF defined as \r
+ // 1) Unmodulated time of 56.64us\r
+ // 2) 24 pulses of 423.75khz\r
+ // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)\r
+\r
+ static const int FrameSOF[] = {\r
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ -1, -1, -1, -1,\r
+ -1, -1, -1, -1,\r
+ 1, 1, 1, 1,\r
+ 1, 1, 1, 1\r
+ };\r
+ static const int Logic0[] = {\r
+ 1, 1, 1, 1,\r
+ 1, 1, 1, 1,\r
+ -1, -1, -1, -1,\r
+ -1, -1, -1, -1\r
+ };\r
+ static const int Logic1[] = {\r
+ -1, -1, -1, -1,\r
+ -1, -1, -1, -1,\r
+ 1, 1, 1, 1,\r
+ 1, 1, 1, 1\r
+ };\r
+\r
+ // EOF defined as \r
+ // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)\r
+ // 2) 24 pulses of 423.75khz\r
+ // 3) Unmodulated time of 56.64us\r
+\r
+ static const int FrameEOF[] = {\r
+ 1, 1, 1, 1,\r
+ 1, 1, 1, 1,\r
+ -1, -1, -1, -1,\r
+ -1, -1, -1, -1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\r
+ };\r
+\r
+\r
+\r
+\r
+static void CodeIso15693AsReader(BYTE *cmd, int n)\r
+{\r
+ int i, j;\r
+\r
+ ToSendReset();\r
+\r
+ // Give it a bit of slack at the beginning\r
+ for(i = 0; i < 24; i++) {\r
+ ToSendStuffBit(1);\r
+ }\r
+\r
+ ToSendStuffBit(0);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(0);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ for(i = 0; i < n; i++) {\r
+ for(j = 0; j < 8; j += 2) {\r
+ int these = (cmd[i] >> j) & 3;\r
+ switch(these) {\r
+ case 0:\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(0);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ break;\r
+ case 1:\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(0);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ break;\r
+ case 2:\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(0);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ break;\r
+ case 3:\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(0);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(1);\r
+ ToSendStuffBit(0);\r
+ ToSendStuffBit(1);\r
+\r
+ // And slack at the end, too.\r
+ for(i = 0; i < 24; i++) {\r
+ ToSendStuffBit(1);\r
+ }\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// The CRC used by ISO 15693.\r
+//-----------------------------------------------------------------------------\r
+static WORD Crc(BYTE *v, int n)\r
+{\r
+ DWORD reg;\r
+ int i, j;\r
+\r
+ reg = 0xffff;\r
+ for(i = 0; i < n; i++) {\r
+ reg = reg ^ ((DWORD)v[i]);\r
+ for (j = 0; j < 8; j++) {\r
+ if (reg & 0x0001) {\r
+ reg = (reg >> 1) ^ 0x8408;\r
+ } else {\r
+ reg = (reg >> 1);\r
+ }\r
+ }\r
+ }\r
+\r
+ return ~reg;\r
+}\r
+\r
+////////////////////////////////////////// code to do 'itoa'\r
+ \r
+\r
+\r
+/* reverse: reverse string s in place */\r
+void reverse(char s[])\r
+{\r
+ int c, i, j;\r
+\r
+ for (i = 0, j = strlen(s)-1; i<j; i++, j--) {\r
+ c = s[i];\r
+ s[i] = s[j];\r
+ s[j] = c;\r
+ }\r
+}\r
+\r
+/* itoa: convert n to characters in s */\r
+void itoa(int n, char s[])\r
+{\r
+ int i, sign;\r
+\r
+ if ((sign = n) < 0) /* record sign */\r
+ n = -n; /* make n positive */\r
+ i = 0;\r
+ do { /* generate digits in reverse order */\r
+ s[i++] = n % 10 + '0'; /* get next digit */\r
+ } while ((n /= 10) > 0); /* delete it */\r
+ if (sign < 0)\r
+ s[i++] = '-';\r
+ s[i] = '\0';\r
+ reverse(s);\r
+} \r
+\r
+//////////////////////////////////////// END 'itoa' CODE\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Encode (into the ToSend buffers) an identify request, which is the first\r
+// thing that you must send to a tag to get a response.\r
+//-----------------------------------------------------------------------------\r
+static void BuildIdentifyRequest(void)\r
+{\r
+ BYTE cmd[5];\r
+\r
+ WORD crc;\r
+ // one sub-carrier, inventory, 1 slot, fast rate\r
+ // AFI is at bit 5 (1<<4) when doing an INVENTORY\r
+ cmd[0] = (1 << 2) | (1 << 5) | (1 << 1); \r
+ // inventory command code\r
+ cmd[1] = 0x01;\r
+ // no mask\r
+ cmd[2] = 0x00;\r
+ //Now the CRC\r
+ crc = Crc(cmd, 3);\r
+ cmd[3] = crc & 0xff;\r
+ cmd[4] = crc >> 8;\r
+\r
+ CodeIso15693AsReader(cmd, sizeof(cmd));\r
+}\r
+\r
+static void BuildSysInfoRequest(BYTE *uid)\r
+{\r
+ BYTE cmd[12];\r
+\r
+ WORD crc;\r
+ // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block\r
+ // followed by teh block data\r
+ // one sub-carrier, inventory, 1 slot, fast rate\r
+ cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit\r
+ // System Information command code\r
+ cmd[1] = 0x2B;\r
+ // UID may be optionally specified here\r
+ // 64-bit UID\r
+ cmd[2] = 0x32;\r
+ cmd[3]= 0x4b;\r
+ cmd[4] = 0x03;\r
+ cmd[5] = 0x01;\r
+ cmd[6] = 0x00;\r
+ cmd[7] = 0x10;\r
+ cmd[8] = 0x05; \r
+ cmd[9]= 0xe0; // always e0 (not exactly unique) \r
+ //Now the CRC\r
+ crc = Crc(cmd, 10); // the crc needs to be calculated over 2 bytes \r
+ cmd[10] = crc & 0xff;\r
+ cmd[11] = crc >> 8;\r
+\r
+ CodeIso15693AsReader(cmd, sizeof(cmd));\r
+}\r
+\r
+static void BuildSelectRequest( BYTE uid[])\r
+{\r
+ \r
+// uid[6]=0x31; // this is getting ignored - the uid array is not happening...\r
+ BYTE cmd[12];\r
+\r
+ WORD crc;\r
+ // one sub-carrier, inventory, 1 slot, fast rate\r
+ //cmd[0] = (1 << 2) | (1 << 5) | (1 << 1); // INVENTROY FLAGS\r
+ cmd[0] = (1 << 4) | (1 << 5) | (1 << 1); // Select and addressed FLAGS\r
+ // SELECT command code\r
+ cmd[1] = 0x25;\r
+ // 64-bit UID\r
+// cmd[2] = uid[0];//0x32;\r
+// cmd[3]= uid[1];//0x4b;\r
+// cmd[4] = uid[2];//0x03;\r
+// cmd[5] = uid[3];//0x01;\r
+// cmd[6] = uid[4];//0x00;\r
+// cmd[7] = uid[5];//0x10;\r
+// cmd[8] = uid[6];//0x05; \r
+ cmd[2] = 0x32;//\r
+ cmd[3]= 0x4b;\r
+ cmd[4] = 0x03;\r
+ cmd[5] = 0x01;\r
+ cmd[6] = 0x00;\r
+ cmd[7] = 0x10;\r
+ cmd[8] = 0x05; // infineon?\r
+\r
+ cmd[9]= 0xe0; // always e0 (not exactly unique) \r
+\r
+// DbpIntegers(cmd[8],cmd[7],cmd[6]);\r
+ // Now the CRC\r
+ crc = Crc(cmd, 10); // the crc needs to be calculated over 10 bytes \r
+ cmd[10] = crc & 0xff;\r
+ cmd[11] = crc >> 8;\r
+\r
+ CodeIso15693AsReader(cmd, sizeof(cmd));\r
+}\r
+\r
+static void BuildReadBlockRequest(BYTE *uid, BYTE blockNumber )\r
+{\r
+ BYTE cmd[13];\r
+\r
+ WORD crc;\r
+ // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block\r
+ // followed by teh block data\r
+ // one sub-carrier, inventory, 1 slot, fast rate\r
+ cmd[0] = (1 << 6)| (1 << 5) | (1 << 1); // no SELECT bit\r
+ // READ BLOCK command code\r
+ cmd[1] = 0x20;\r
+ // UID may be optionally specified here\r
+ // 64-bit UID\r
+ cmd[2] = 0x32;\r
+ cmd[3]= 0x4b;\r
+ cmd[4] = 0x03;\r
+ cmd[5] = 0x01;\r
+ cmd[6] = 0x00;\r
+ cmd[7] = 0x10;\r
+ cmd[8] = 0x05; \r
+ cmd[9]= 0xe0; // always e0 (not exactly unique) \r
+ // Block number to read\r
+ cmd[10] = blockNumber;//0x00;\r
+ //Now the CRC\r
+ crc = Crc(cmd, 11); // the crc needs to be calculated over 2 bytes \r
+ cmd[11] = crc & 0xff;\r
+ cmd[12] = crc >> 8;\r
+\r
+ CodeIso15693AsReader(cmd, sizeof(cmd));\r
+}\r
+\r
+\r
+static void BuildReadMultiBlockRequest(BYTE *uid)\r
+{\r
+ BYTE cmd[14];\r
+\r
+ WORD crc;\r
+ // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block\r
+ // followed by teh block data\r
+ // one sub-carrier, inventory, 1 slot, fast rate\r
+ cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit\r
+ // READ Multi BLOCK command code\r
+ cmd[1] = 0x23;\r
+ // UID may be optionally specified here\r
+ // 64-bit UID\r
+ cmd[2] = 0x32;\r
+ cmd[3]= 0x4b;\r
+ cmd[4] = 0x03;\r
+ cmd[5] = 0x01;\r
+ cmd[6] = 0x00;\r
+ cmd[7] = 0x10;\r
+ cmd[8] = 0x05; \r
+ cmd[9]= 0xe0; // always e0 (not exactly unique) \r
+ // First Block number to read\r
+ cmd[10] = 0x00;\r
+ // Number of Blocks to read\r
+ cmd[11] = 0x2f; // read quite a few\r
+ //Now the CRC\r
+ crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes \r
+ cmd[12] = crc & 0xff;\r
+ cmd[13] = crc >> 8;\r
+\r
+ CodeIso15693AsReader(cmd, sizeof(cmd));\r
+}\r
+\r
+static void BuildArbitraryRequest(BYTE *uid,BYTE CmdCode)\r
+{\r
+ BYTE cmd[14];\r
+\r
+ WORD crc;\r
+ // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block\r
+ // followed by teh block data\r
+ // one sub-carrier, inventory, 1 slot, fast rate\r
+ cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit\r
+ // READ BLOCK command code\r
+ cmd[1] = CmdCode;\r
+ // UID may be optionally specified here\r
+ // 64-bit UID\r
+ cmd[2] = 0x32;\r
+ cmd[3]= 0x4b;\r
+ cmd[4] = 0x03;\r
+ cmd[5] = 0x01;\r
+ cmd[6] = 0x00;\r
+ cmd[7] = 0x10;\r
+ cmd[8] = 0x05; \r
+ cmd[9]= 0xe0; // always e0 (not exactly unique) \r
+ // Parameter\r
+ cmd[10] = 0x00;\r
+ cmd[11] = 0x0a;\r
+\r
+// cmd[12] = 0x00;\r
+// cmd[13] = 0x00; //Now the CRC\r
+ crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes \r
+ cmd[12] = crc & 0xff;\r
+ cmd[13] = crc >> 8;\r
+\r
+ CodeIso15693AsReader(cmd, sizeof(cmd));\r
+}\r
+\r
+static void BuildArbitraryCustomRequest(BYTE *uid,BYTE CmdCode)\r
+{\r
+ BYTE cmd[14];\r
+\r
+ WORD crc;\r
+ // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block\r
+ // followed by teh block data\r
+ // one sub-carrier, inventory, 1 slot, fast rate\r
+ cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit\r
+ // READ BLOCK command code\r
+ cmd[1] = CmdCode;\r
+ // UID may be optionally specified here\r
+ // 64-bit UID\r
+ cmd[2] = 0x32;\r
+ cmd[3]= 0x4b;\r
+ cmd[4] = 0x03;\r
+ cmd[5] = 0x01;\r
+ cmd[6] = 0x00;\r
+ cmd[7] = 0x10;\r
+ cmd[8] = 0x05; \r
+ cmd[9]= 0xe0; // always e0 (not exactly unique) \r
+ // Parameter\r
+ cmd[10] = 0x05; // for custom codes this must be manufcturer code\r
+ cmd[11] = 0x00;\r
+\r
+// cmd[12] = 0x00;\r
+// cmd[13] = 0x00; //Now the CRC\r
+ crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes \r
+ cmd[12] = crc & 0xff;\r
+ cmd[13] = crc >> 8;\r
+\r
+ CodeIso15693AsReader(cmd, sizeof(cmd));\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////\r
+// Now the VICC>VCD responses when we are simulating a tag\r
+////////////////////////////////////////////////////////////////////\r
+\r
+ static void BuildInventoryResponse(void)\r
+{\r
+ BYTE cmd[12];\r
+\r
+ WORD crc;\r
+ // one sub-carrier, inventory, 1 slot, fast rate\r
+ // AFI is at bit 5 (1<<4) when doing an INVENTORY\r
+ cmd[0] = 0; //(1 << 2) | (1 << 5) | (1 << 1); \r
+ cmd[1] = 0;\r
+ // 64-bit UID\r
+ cmd[2] = 0x32;\r
+ cmd[3]= 0x4b;\r
+ cmd[4] = 0x03;\r
+ cmd[5] = 0x01;\r
+ cmd[6] = 0x00;\r
+ cmd[7] = 0x10;\r
+ cmd[8] = 0x05; \r
+ cmd[9]= 0xe0;\r
+ //Now the CRC\r
+ crc = Crc(cmd, 10);\r
+ cmd[10] = crc & 0xff;\r
+ cmd[11] = crc >> 8;\r
+\r
+ CodeIso15693AsReader(cmd, sizeof(cmd));\r
+}\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Transmit the command (to the tag) that was placed in ToSend[].\r
+//-----------------------------------------------------------------------------\r
+static void TransmitTo15693Tag(const BYTE *cmd, int len, int *samples, int *wait)\r
+{\r
+ int c;\r
+\r
+// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);\r
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);\r
+ if(*wait < 10) { *wait = 10; }\r
+\r
+// for(c = 0; c < *wait;) {\r
+// if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+// SSC_TRANSMIT_HOLDING = 0x00; // For exact timing!\r
+// c++;\r
+// }\r
+// if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+// volatile DWORD r = SSC_RECEIVE_HOLDING;\r
+// (void)r;\r
+// }\r
+// WDT_HIT();\r
+// }\r
+\r
+ c = 0;\r
+ for(;;) {\r
+ if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+ SSC_TRANSMIT_HOLDING = cmd[c];\r
+ c++;\r
+ if(c >= len) {\r
+ break;\r
+ }\r
+ }\r
+ if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+ volatile DWORD r = SSC_RECEIVE_HOLDING;\r
+ (void)r;\r
+ }\r
+ WDT_HIT();\r
+ }\r
+ *samples = (c + *wait) << 3;\r
+}\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Transmit the command (to the reader) that was placed in ToSend[].\r
+//-----------------------------------------------------------------------------\r
+static void TransmitTo15693Reader(const BYTE *cmd, int len, int *samples, int *wait)\r
+{\r
+ int c;\r
+\r
+// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);\r
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR); // No requirement to energise my coils\r
+ if(*wait < 10) { *wait = 10; }\r
+\r
+ c = 0;\r
+ for(;;) {\r
+ if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+ SSC_TRANSMIT_HOLDING = cmd[c];\r
+ c++;\r
+ if(c >= len) {\r
+ break;\r
+ }\r
+ }\r
+ if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+ volatile DWORD r = SSC_RECEIVE_HOLDING;\r
+ (void)r;\r
+ }\r
+ WDT_HIT();\r
+ }\r
+ *samples = (c + *wait) << 3;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+static int GetIso15693AnswerFromTag(BYTE *receivedResponse, int maxLen, int *samples, int *elapsed) \r
+{\r
+ int c = 0;\r
+ BYTE *dest = (BYTE *)BigBuf;\r
+ int getNext = 0;\r
+\r
+\r
+ SBYTE prev = 0;\r
+\r
+// NOW READ RESPONSE\r
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
+ //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads\r
+ c = 0;\r
+ getNext = FALSE;\r
+ for(;;) {\r
+ if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+ SSC_TRANSMIT_HOLDING = 0x43;\r
+ }\r
+ if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+ SBYTE b;\r
+ b = (SBYTE)SSC_RECEIVE_HOLDING;\r
+\r
+ // The samples are correlations against I and Q versions of the\r
+ // tone that the tag AM-modulates, so every other sample is I,\r
+ // every other is Q. We just want power, so abs(I) + abs(Q) is\r
+ // close to what we want.\r
+ if(getNext) {\r
+ SBYTE r;\r
+\r
+ if(b < 0) {\r
+ r = -b;\r
+ } else {\r
+ r = b;\r
+ }\r
+ if(prev < 0) {\r
+ r -= prev;\r
+ } else {\r
+ r += prev;\r
+ }\r
+\r
+ dest[c++] = (BYTE)r;\r
+\r
+ if(c >= 2000) {\r
+ break;\r
+ }\r
+ } else {\r
+ prev = b;\r
+ }\r
+\r
+ getNext = !getNext;\r
+ }\r
+ }\r
+\r
+//////////////////////////////////////////\r
+/////////// DEMODULATE ///////////////////\r
+//////////////////////////////////////////\r
+\r
+ int i, j;\r
+ int max = 0, maxPos;\r
+\r
+ int skip = 4;\r
+\r
+\r
+// if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL\r
+\r
+ // First, correlate for SOF\r
+ for(i = 0; i < 100; i++) {\r
+ int corr = 0;\r
+ for(j = 0; j < arraylen(FrameSOF); j += skip) {\r
+ corr += FrameSOF[j]*dest[i+(j/skip)];\r
+ }\r
+ if(corr > max) {\r
+ max = corr;\r
+ maxPos = i;\r
+ }\r
+ }\r
+// DbpString("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip));\r
+\r
+ int k = 0; // this will be our return value\r
+\r
+ // greg - If correlation is less than 1 then there's little point in continuing\r
+ if ((max/(arraylen(FrameSOF)/skip)) >= 1) \r
+ {\r
+\r
+ i = maxPos + arraylen(FrameSOF)/skip;\r
+ \r
+ BYTE outBuf[20];\r
+ memset(outBuf, 0, sizeof(outBuf));\r
+ BYTE mask = 0x01;\r
+ for(;;) {\r
+ int corr0 = 0, corr1 = 0, corrEOF = 0;\r
+ for(j = 0; j < arraylen(Logic0); j += skip) {\r
+ corr0 += Logic0[j]*dest[i+(j/skip)];\r
+ }\r
+ for(j = 0; j < arraylen(Logic1); j += skip) {\r
+ corr1 += Logic1[j]*dest[i+(j/skip)];\r
+ }\r
+ for(j = 0; j < arraylen(FrameEOF); j += skip) {\r
+ corrEOF += FrameEOF[j]*dest[i+(j/skip)];\r
+ }\r
+ // Even things out by the length of the target waveform.\r
+ corr0 *= 4;\r
+ corr1 *= 4;\r
+\r
+ if(corrEOF > corr1 && corrEOF > corr0) {\r
+// DbpString("EOF at %d", i);\r
+ break;\r
+ } else if(corr1 > corr0) {\r
+ i += arraylen(Logic1)/skip;\r
+ outBuf[k] |= mask;\r
+ } else {\r
+ i += arraylen(Logic0)/skip;\r
+ }\r
+ mask <<= 1;\r
+ if(mask == 0) {\r
+ k++;\r
+ mask = 0x01;\r
+ }\r
+ if((i+(int)arraylen(FrameEOF)) >= 2000) {\r
+ DbpString("ran off end!");\r
+ break;\r
+ }\r
+ }\r
+ if(mask != 0x01) {\r
+ DbpString("error, uneven octet! (discard extra bits!)");\r
+/// DbpString(" mask=%02x", mask);\r
+ }\r
+// BYTE str1 [8];\r
+// itoa(k,str1);\r
+// strcat(str1," octets read");\r
+\r
+// DbpString( str1); // DbpString("%d octets", k);\r
+\r
+// for(i = 0; i < k; i+=3) {\r
+// //DbpString("# %2d: %02x ", i, outBuf[i]);\r
+// DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]);\r
+// }\r
+\r
+ for(i = 0; i < k; i++) {\r
+ receivedResponse[i] = outBuf[i];\r
+ } \r
+ } // "end if correlation > 0" (max/(arraylen(FrameSOF)/skip))\r
+ return k; // return the number of bytes demodulated\r
+\r
+/// DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2));\r
+\r
+\r
+}\r
+\r
+// Now the GetISO15693 message from sniffing command\r
+static int GetIso15693AnswerFromSniff(BYTE *receivedResponse, int maxLen, int *samples, int *elapsed) \r
+{\r
+ int c = 0;\r
+ BYTE *dest = (BYTE *)BigBuf;\r
+ int getNext = 0;\r
+\r
+\r
+ SBYTE prev = 0;\r
+\r
+// NOW READ RESPONSE\r
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
+ //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads\r
+ c = 0;\r
+ getNext = FALSE;\r
+ for(;;) {\r
+ if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+ SSC_TRANSMIT_HOLDING = 0x43;\r
+ }\r
+ if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+ SBYTE b;\r
+ b = (SBYTE)SSC_RECEIVE_HOLDING;\r
+\r
+ // The samples are correlations against I and Q versions of the\r
+ // tone that the tag AM-modulates, so every other sample is I,\r
+ // every other is Q. We just want power, so abs(I) + abs(Q) is\r
+ // close to what we want.\r
+ if(getNext) {\r
+ SBYTE r;\r
+\r
+ if(b < 0) {\r
+ r = -b;\r
+ } else {\r
+ r = b;\r
+ }\r
+ if(prev < 0) {\r
+ r -= prev;\r
+ } else {\r
+ r += prev;\r
+ }\r
+\r
+ dest[c++] = (BYTE)r;\r
+\r
+ if(c >= 20000) {\r
+ break;\r
+ }\r
+ } else {\r
+ prev = b;\r
+ }\r
+\r
+ getNext = !getNext;\r
+ }\r
+ }\r
+\r
+//////////////////////////////////////////\r
+/////////// DEMODULATE ///////////////////\r
+//////////////////////////////////////////\r
+\r
+ int i, j;\r
+ int max = 0, maxPos;\r
+\r
+ int skip = 4;\r
+\r
+\r
+// if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL\r
+\r
+ // First, correlate for SOF\r
+ for(i = 0; i < 19000; i++) {\r
+ int corr = 0;\r
+ for(j = 0; j < arraylen(FrameSOF); j += skip) {\r
+ corr += FrameSOF[j]*dest[i+(j/skip)];\r
+ }\r
+ if(corr > max) {\r
+ max = corr;\r
+ maxPos = i;\r
+ }\r
+ }\r
+// DbpString("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip));\r
+\r
+ int k = 0; // this will be our return value\r
+\r
+ // greg - If correlation is less than 1 then there's little point in continuing\r
+ if ((max/(arraylen(FrameSOF)/skip)) >= 1) // THIS SHOULD BE 1 \r
+ {\r
+\r
+ i = maxPos + arraylen(FrameSOF)/skip;\r
+ \r
+ BYTE outBuf[20];\r
+ memset(outBuf, 0, sizeof(outBuf));\r
+ BYTE mask = 0x01;\r
+ for(;;) {\r
+ int corr0 = 0, corr1 = 0, corrEOF = 0;\r
+ for(j = 0; j < arraylen(Logic0); j += skip) {\r
+ corr0 += Logic0[j]*dest[i+(j/skip)];\r
+ }\r
+ for(j = 0; j < arraylen(Logic1); j += skip) {\r
+ corr1 += Logic1[j]*dest[i+(j/skip)];\r
+ }\r
+ for(j = 0; j < arraylen(FrameEOF); j += skip) {\r
+ corrEOF += FrameEOF[j]*dest[i+(j/skip)];\r
+ }\r
+ // Even things out by the length of the target waveform.\r
+ corr0 *= 4;\r
+ corr1 *= 4;\r
+\r
+ if(corrEOF > corr1 && corrEOF > corr0) {\r
+// DbpString("EOF at %d", i);\r
+ break;\r
+ } else if(corr1 > corr0) {\r
+ i += arraylen(Logic1)/skip;\r
+ outBuf[k] |= mask;\r
+ } else {\r
+ i += arraylen(Logic0)/skip;\r
+ }\r
+ mask <<= 1;\r
+ if(mask == 0) {\r
+ k++;\r
+ mask = 0x01;\r
+ }\r
+ if((i+(int)arraylen(FrameEOF)) >= 2000) {\r
+ DbpString("ran off end!");\r
+ break;\r
+ }\r
+ }\r
+ if(mask != 0x01) {\r
+ DbpString("error, uneven octet! (discard extra bits!)");\r
+/// DbpString(" mask=%02x", mask);\r
+ }\r
+// BYTE str1 [8];\r
+// itoa(k,str1);\r
+// strcat(str1," octets read");\r
+\r
+// DbpString( str1); // DbpString("%d octets", k);\r
+\r
+// for(i = 0; i < k; i+=3) {\r
+// //DbpString("# %2d: %02x ", i, outBuf[i]);\r
+// DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]);\r
+// }\r
+\r
+ for(i = 0; i < k; i++) {\r
+ receivedResponse[i] = outBuf[i];\r
+ } \r
+ } // "end if correlation > 0" (max/(arraylen(FrameSOF)/skip))\r
+ return k; // return the number of bytes demodulated\r
+\r
+/// DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2));\r
+\r
+\r
+}\r
+\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Start to read an ISO 15693 tag. We send an identify request, then wait\r
+// for the response. The response is not demodulated, just left in the buffer\r
+// so that it can be downloaded to a PC and processed there.\r
+//-----------------------------------------------------------------------------\r
+void AcquireRawAdcSamplesIso15693(void)\r
+{\r
+ int c = 0;\r
+ BYTE *dest = (BYTE *)BigBuf;\r
+ int getNext = 0;\r
+\r
+ SBYTE prev = 0;\r
+\r
+ BuildIdentifyRequest();\r
+\r
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
+\r
+ // Give the tags time to energize\r
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
+ SpinDelay(100);\r
+\r
+ // Now send the command\r
+ FpgaSetupSsc();\r
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);\r
+\r
+ c = 0;\r
+ for(;;) {\r
+ if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+ SSC_TRANSMIT_HOLDING = ToSend[c];\r
+ c++;\r
+ if(c == ToSendMax+3) {\r
+ break;\r
+ }\r
+ }\r
+ if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+ volatile DWORD r = SSC_RECEIVE_HOLDING;\r
+ (void)r;\r
+ }\r
+ WDT_HIT();\r
+ }\r
+\r
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
+\r
+ c = 0;\r
+ getNext = FALSE;\r
+ for(;;) {\r
+ if(SSC_STATUS & (SSC_STATUS_TX_READY)) {\r
+ SSC_TRANSMIT_HOLDING = 0x43;\r
+ }\r
+ if(SSC_STATUS & (SSC_STATUS_RX_READY)) {\r
+ SBYTE b;\r
+ b = (SBYTE)SSC_RECEIVE_HOLDING;\r
+\r
+ // The samples are correlations against I and Q versions of the\r
+ // tone that the tag AM-modulates, so every other sample is I,\r
+ // every other is Q. We just want power, so abs(I) + abs(Q) is\r
+ // close to what we want.\r
+ if(getNext) {\r
+ SBYTE r;\r
+\r
+ if(b < 0) {\r
+ r = -b;\r
+ } else {\r
+ r = b;\r
+ }\r
+ if(prev < 0) {\r
+ r -= prev;\r
+ } else {\r
+ r += prev;\r
+ }\r
+\r
+ dest[c++] = (BYTE)r;\r
+\r
+ if(c >= 2000) {\r
+ break;\r
+ }\r
+ } else {\r
+ prev = b;\r
+ }\r
+\r
+ getNext = !getNext;\r
+ }\r
+ }\r
+}\r
+\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector\r
+// all demodulation performed in arm rather than host. - greg\r
+//-----------------------------------------------------------------------------\r
+void ReaderIso15693(DWORD parameter)\r
+{\r
+ LED_A_ON();\r
+ LED_B_ON();\r
+ LED_C_OFF();\r
+ LED_D_OFF();\r
+\r
+\r
+//DbpString(parameter);\r
+\r
+ BYTE *receivedAnswer0 = (((BYTE *)BigBuf) + 3560); // allow 100 bytes per reponse (way too much)\r
+ BYTE *receivedAnswer1 = (((BYTE *)BigBuf) + 3660); // \r
+ BYTE *receivedAnswer2 = (((BYTE *)BigBuf) + 3760);\r
+ BYTE *receivedAnswer3 = (((BYTE *)BigBuf) + 3860);\r
+ //BYTE *TagUID= (((BYTE *)BigBuf) + 3960); // where we hold the uid for hi15reader \r
+ int responseLen0 = 0;\r
+ int responseLen1 = 0;\r
+ int responseLen2 = 0;\r
+ int responseLen3 = 0;\r
+\r
+ // Blank arrays\r
+ int j;\r
+ for(j = 0; j < 100; j++) {\r
+ receivedAnswer3[j] = 0;\r
+ receivedAnswer2[j] =0;\r
+ receivedAnswer1[j] = 0;\r
+ receivedAnswer0[j] = 0;\r
+ }\r
+\r
+ // Setup SSC\r
+ FpgaSetupSsc();\r
+\r
+ // Start from off (no field generated)\r
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
+ SpinDelay(200);\r
+\r
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
+ FpgaSetupSsc();\r
+\r
+ // Give the tags time to energize\r
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);\r
+ SpinDelay(200);\r
+\r
+ LED_A_ON();\r
+ LED_B_OFF();\r
+ LED_C_OFF();\r
+ LED_D_OFF();\r
+\r
+ int samples = 0;\r
+ int tsamples = 0;\r
+ int wait = 0;\r
+ int elapsed = 0;\r
+\r
+ // FIRST WE RUN AN INVENTORY TO GET THE TAG UID\r
+ // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME\r
+ BYTE TagUID[7]; // where we hold the uid for hi15reader \r
+\r
+\r
+// BuildIdentifyRequest();\r
+// //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait); \r
+// TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3\r
+// // Now wait for a response\r
+// responseLen0 = GetIso15693AnswerFromTag(receivedAnswer0, 100, &samples, &elapsed) ; \r
+// if (responseLen0 >=12) // we should do a better check than this\r
+// {\r
+// // really we should check it is a valid mesg\r
+// // but for now just grab what we think is the uid\r
+// TagUID[0] = receivedAnswer0[2];\r
+// TagUID[1] = receivedAnswer0[3];\r
+// TagUID[2] = receivedAnswer0[4];\r
+// TagUID[3] = receivedAnswer0[5];\r
+// TagUID[4] = receivedAnswer0[6];\r
+// TagUID[5] = receivedAnswer0[7];\r
+// TagUID[6] = receivedAnswer0[8]; // IC Manufacturer code\r
+// DbpIntegers(TagUID[6],TagUID[5],TagUID[4]); \r
+//}\r
+\r
+ // Now send the IDENTIFY command\r
+ BuildIdentifyRequest();\r
+ //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait); \r
+ TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3\r
+ // Now wait for a response\r
+ responseLen1 = GetIso15693AnswerFromTag(receivedAnswer1, 100, &samples, &elapsed) ;\r
+ \r
+ if (responseLen1 >=12) // we should do a better check than this\r
+ {\r
+ \r
+ TagUID[0] = receivedAnswer1[2];\r
+ TagUID[1] = receivedAnswer1[3];\r
+ TagUID[2] = receivedAnswer1[4];\r
+ TagUID[3] = receivedAnswer1[5];\r
+ TagUID[4] = receivedAnswer1[6];\r
+ TagUID[5] = receivedAnswer1[7];\r
+ TagUID[6] = receivedAnswer1[8]; // IC Manufacturer code\r
+ \r
+ // Now send the SELECT command\r
+ BuildSelectRequest(*TagUID);\r
+ TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3\r
+ // Now wait for a response\r
+ responseLen2 = GetIso15693AnswerFromTag(receivedAnswer2, 100, &samples, &elapsed); \r
+\r
+ // Now send the MULTI READ command\r
+// BuildArbitraryRequest(*TagUID,parameter);\r
+ BuildArbitraryCustomRequest(*TagUID,parameter);\r
+// BuildReadBlockRequest(*TagUID,parameter);\r
+// BuildSysInfoRequest(*TagUID);\r
+ //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait); \r
+ TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 \r
+ // Now wait for a response\r
+ responseLen3 = GetIso15693AnswerFromTag(receivedAnswer3, 100, &samples, &elapsed) ;\r
+\r
+ }\r
+\r
+\r
+\r
+ BYTE str1 [4];\r
+ //char str2 [200];\r
+ int i;\r
+\r
+ itoa(responseLen1,str1);\r
+ strcat(str1," octets read from IDENTIFY request");\r
+ DbpString(str1);\r
+ for(i = 0; i < responseLen1; i+=3) {\r
+ DbpIntegers(receivedAnswer1[i],receivedAnswer1[i+1],receivedAnswer1[i+2]);\r
+ }\r
+\r
+ itoa(responseLen2,str1);\r
+ strcat(str1," octets read from SELECT request");\r
+ DbpString(str1);\r
+ for(i = 0; i < responseLen2; i+=3) {\r
+ DbpIntegers(receivedAnswer2[i],receivedAnswer2[i+1],receivedAnswer2[i+2]);\r
+ }\r
+\r
+ itoa(responseLen3,str1);\r
+ strcat(str1," octets read from XXX request");\r
+ DbpString(str1);\r
+ for(i = 0; i < responseLen3; i+=3) {\r
+ DbpIntegers(receivedAnswer3[i],receivedAnswer3[i+1],receivedAnswer3[i+2]);\r
+ }\r
+ \r
+\r
+// str2[0]=0;\r
+// for(i = 0; i < responseLen3; i++) {\r
+// itoa(str1,receivedAnswer3[i]);\r
+// strcat(str2,str1);\r
+// }\r
+// DbpString(str2); \r
+\r
+ LED_A_OFF();\r
+ LED_B_OFF();\r
+ LED_C_OFF();\r
+ LED_D_OFF();\r
+\r
+\r
+}\r
+\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands\r
+// all demodulation performed in arm rather than host. - greg\r
+//-----------------------------------------------------------------------------\r
+void SimTagIso15693(DWORD parameter)\r
+{\r
+ LED_A_ON();\r
+ LED_B_ON();\r
+ LED_C_OFF();\r
+ LED_D_OFF();\r
+\r
+\r
+//DbpString(parameter);\r
+\r
+ BYTE *receivedAnswer0 = (((BYTE *)BigBuf) + 3560); // allow 100 bytes per reponse (way too much)\r
+ BYTE *receivedAnswer1 = (((BYTE *)BigBuf) + 3660); // \r
+ BYTE *receivedAnswer2 = (((BYTE *)BigBuf) + 3760);\r
+ BYTE *receivedAnswer3 = (((BYTE *)BigBuf) + 3860);\r
+ //BYTE *TagUID= (((BYTE *)BigBuf) + 3960); // where we hold the uid for hi15reader \r
+ int responseLen0 = 0;\r
+ int responseLen1 = 0;\r
+ int responseLen2 = 0;\r
+ int responseLen3 = 0;\r
+\r
+ // Blank arrays\r
+ int j;\r
+ for(j = 0; j < 100; j++) {\r
+ receivedAnswer3[j] = 0;\r
+ receivedAnswer2[j] =0;\r
+ receivedAnswer1[j] = 0;\r
+ receivedAnswer0[j] = 0;\r
+ }\r
+\r
+ // Setup SSC\r
+ FpgaSetupSsc();\r
+\r
+ // Start from off (no field generated)\r
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
+ SpinDelay(200);\r
+\r
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);\r
+ FpgaSetupSsc();\r
+\r
+ // Give the tags time to energize\r
+// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); // NO GOOD FOR SIM TAG!!!!\r
+ SpinDelay(200);\r
+\r
+ LED_A_OFF();\r
+ LED_B_OFF();\r
+ LED_C_ON();\r
+ LED_D_OFF();\r
+\r
+ int samples = 0;\r
+ int tsamples = 0;\r
+ int wait = 0;\r
+ int elapsed = 0;\r
+\r
+ // FIRST WE RUN AN INVENTORY TO GET THE TAG UID\r
+ // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME\r
+ BYTE TagUID[7]; // where we hold the uid for hi15reader \r
+\r
+\r
+\r
+ // Now send the IDENTIFY command\r
+// BuildIdentifyRequest();\r
+// TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3\r
+\r
+\r
+ // Now wait for a command from the reader\r
+ responseLen1=0;\r
+// while(responseLen1=0) {\r
+// if(BUTTON_PRESS()) break;\r
+ responseLen1 = GetIso15693AnswerFromSniff(receivedAnswer1, 100, &samples, &elapsed) ;\r
+// }\r
+\r
+ \r
+ if (responseLen1 >=1) // we should do a better check than this\r
+ {\r
+ // Build a suitable reponse to the reader INVENTORY cocmmand\r
+ BuildInventoryResponse;\r
+ TransmitTo15693Reader(ToSend,ToSendMax,&tsamples, &wait);\r
+\r
+ // Now wait for a command from the reader\r
+// responseLen2 = GetIso15693AnswerFromTag(receivedAnswer2, 100, &samples, &elapsed); \r
+\r
+ \r
+ // Now wait for a command from the reader\r
+// responseLen3 = GetIso15693AnswerFromTag(receivedAnswer3, 100, &samples, &elapsed) ;\r
+\r
+ }\r
+\r
+\r
+\r
+ BYTE str1 [4];\r
+ //char str2 [200];\r
+ int i;\r
+\r
+ itoa(responseLen1,str1);\r
+ strcat(str1," octets read from reader command");\r
+ DbpString(str1);\r
+ for(i = 0; i < responseLen1; i+=3) {\r
+ DbpIntegers(receivedAnswer1[i],receivedAnswer1[i+1],receivedAnswer1[i+2]);\r
+ }\r
+\r
+// itoa(responseLen2,str1);\r
+// strcat(str1," octets read from SELECT request");\r
+// DbpString(str1);\r
+// for(i = 0; i < responseLen2; i+=3) {\r
+// DbpIntegers(receivedAnswer2[i],receivedAnswer2[i+1],receivedAnswer2[i+2]);\r
+// }\r
+//\r
+// itoa(responseLen3,str1);\r
+// strcat(str1," octets read from XXX request");\r
+// DbpString(str1);\r
+// for(i = 0; i < responseLen3; i+=3) {\r
+// DbpIntegers(receivedAnswer3[i],receivedAnswer3[i+1],receivedAnswer3[i+2]);\r
+// }\r
+ \r
+\r
+// str2[0]=0;\r
+// for(i = 0; i < responseLen3; i++) {\r
+// itoa(str1,receivedAnswer3[i]);\r
+// strcat(str2,str1);\r
+// }\r
+// DbpString(str2); \r
+\r
+ LED_A_OFF();\r
+ LED_B_OFF();\r
+ LED_C_OFF();\r
+ LED_D_OFF();\r
+\r
+\r
+}
\ No newline at end of file
--- /dev/null
+SECTIONS\r
+{\r
+ . = 0x00010000;\r
+ .text : { obj/start.o(.text) *(.text) }\r
+ .rodata : { *(.rodata) }\r
+ . = 0x00200000;\r
+ .data : { *(.data) }\r
+ __bss_start__ = .;\r
+ .bss : { *(.bss) }\r
+ __bss_end__ = .;\r
+}\r
--- /dev/null
+SECTIONS\r
+{\r
+ . = 0x00002000;\r
+ .text : { obj/fpgaimg.o(.text) *(.text) }\r
+ .rodata : { *(.rodata) }\r
+ . = 0x00200000;\r
+ .data : { *(.data) }\r
+ __bss_start__ = .;\r
+ .bss : { *(.bss) }\r
+ __bss_end__ = .;\r
+}\r
--- /dev/null
+//-----------------------------------------------------------------------------\r
+// Just vector to AppMain(). This is in its own file so that I can place it\r
+// with the linker script.\r
+// Jonathan Westhues, Mar 2006\r
+//-----------------------------------------------------------------------------\r
+#include <proxmark3.h>\r
+#include "apps.h"\r
+\r
+void Vector(void)\r
+{\r
+ AppMain();\r
+}\r
--- /dev/null
+//-----------------------------------------------------------------------------\r
+// Utility functions used in many places, not specific to any piece of code.\r
+// Jonathan Westhues, Sept 2005\r
+//-----------------------------------------------------------------------------\r
+#include <proxmark3.h>\r
+#include "apps.h"\r
+\r
+void *memcpy(void *dest, const void *src, int len)\r
+{\r
+ BYTE *d = dest;\r
+ const BYTE *s = src;\r
+ while((len--) > 0) {\r
+ *d = *s;\r
+ d++;\r
+ s++;\r
+ }\r
+ return dest;\r
+}\r
+\r
+void *memset(void *dest, int c, int len)\r
+{\r
+ BYTE *d = dest;\r
+ while((len--) > 0) {\r
+ *d = c;\r
+ d++;\r
+ }\r
+ return dest;\r
+}\r
+\r
+int memcmp(const void *av, const void *bv, int len)\r
+{\r
+ const BYTE *a = av;\r
+ const BYTE *b = bv;\r
+\r
+ while((len--) > 0) {\r
+ if(*a != *b) {\r
+ return *a - *b;\r
+ }\r
+ a++;\r
+ b++;\r
+ }\r
+ return 0;\r
+}\r
+\r
+int strlen(char *str)\r
+{\r
+ int l = 0;\r
+ while(*str) {\r
+ l++;\r
+ str++;\r
+ }\r
+ return l;\r
+}\r
--- /dev/null
+CC = arm-elf-gcc\r
+AS = arm-elf-as\r
+LD = arm-elf-ld\r
+OBJCOPY = arm-elf-objcopy\r
+\r
+OBJDIR = obj\r
+\r
+INCLUDE = -I../include\r
+\r
+INCLUDES = ../include/proxmark3.h ../include/at91sam7s128.h ../include/config_gpio.h ../include/usb_cmd.h\r
+\r
+CFLAGS = -g -c $(INCLUDE) -Wall\r
+\r
+OBJJTAG = $(OBJDIR)/bootrom.o $(OBJDIR)/ram-reset.o $(OBJDIR)/usb.o\r
+\r
+OBJFLASH = $(OBJDIR)/flash-reset.o $(OBJDIR)/fromflash.o\r
+\r
+all: bootrom.s19\r
+\r
+bootrom.s19: $(OBJDIR)/bootrom.s19 $(OBJDIR)/bootrom-forjtag.s19\r
+ @echo bootrom.s19\r
+ @perl ..\tools\merge-srec.pl $(OBJDIR)\bootrom.s19 $(OBJDIR)\bootrom-forjtag.s19 > $(OBJDIR)\bootrom-merged.s19\r
+ @perl ..\tools\srecswap.pl $(OBJDIR)\bootrom-forjtag.s19 > $(OBJDIR)\bootrom-forjtag-swapped.s19\r
+\r
+$(OBJDIR)/bootrom.s19: $(OBJFLASH)\r
+ @echo obj/bootrom.s19\r
+ @$(LD) -g -Tldscript-flash --oformat elf32-littlearm -o $(OBJDIR)/bootrom.elf $(OBJFLASH)\r
+ @$(OBJCOPY) -Osrec --srec-forceS3 $(OBJDIR)/bootrom.elf $(OBJDIR)/bootrom.s19\r
+\r
+$(OBJDIR)/bootrom-forjtag.s19: $(OBJJTAG)\r
+ @echo obj/bootrom-forjtag.s19\r
+ @$(LD) -g -Tldscript-ram-jtag --oformat elf32-littlearm -o $(OBJDIR)/bootrom-forjtag.elf $(OBJJTAG)\r
+ @$(OBJCOPY) -Osrec --srec-forceS3 $(OBJDIR)/bootrom-forjtag.elf $(OBJDIR)/bootrom-forjtag.s19\r
+\r
+$(OBJDIR)/bootrom.o: bootrom.c $(INCLUDES)\r
+ @echo $(@B).c\r
+ @$(CC) $(CFLAGS) -mthumb -mthumb-interwork bootrom.c -o $(OBJDIR)/bootrom.o\r
+\r
+$(OBJDIR)/fromflash.o: fromflash.c $(INCLUDES)\r
+ @echo $(@B).c\r
+ @$(CC) $(CFLAGS) -mthumb -mthumb-interwork fromflash.c -o $(OBJDIR)/fromflash.o\r
+\r
+$(OBJDIR)/usb.o: ../common/usb.c $(INCLUDES)\r
+ @echo $(@B).c\r
+ @$(CC) $(CFLAGS) -mthumb -mthumb-interwork ../common/usb.c -o $(OBJDIR)/usb.o\r
+\r
+$(OBJDIR)/ram-reset.o: ram-reset.s\r
+ @echo $(@B).s\r
+ @$(CC) $(CFLAGS) -mthumb-interwork -o $(OBJDIR)/ram-reset.o ram-reset.s\r
+\r
+$(OBJDIR)/flash-reset.o: flash-reset.s\r
+ @echo $(@B).s\r
+ @$(CC) $(CFLAGS) -mthumb-interwork -o $(OBJDIR)/flash-reset.o flash-reset.s\r
+\r
+clean:\r
+ del /q obj\*.o\r
+ del /q obj\*.elf\r
+ del /q obj\*.s19\r
--- /dev/null
+#include <proxmark3.h>\r
+\r
+static void ConfigClocks(void)\r
+{\r
+ // we are using a 16 MHz crystal as the basis for everything\r
+ // slow clock runs at 32Khz typical regardless of crystal\r
+\r
+ // enable system clock and USB clock\r
+ PMC_SYS_CLK_ENABLE = PMC_SYS_CLK_PROCESSOR_CLK | PMC_SYS_CLK_UDP_CLK;\r
+\r
+ // enable the clock to the following peripherals\r
+ PMC_PERIPHERAL_CLK_ENABLE =\r
+ (1<<PERIPH_PIOA) |\r
+ (1<<PERIPH_ADC) |\r
+ (1<<PERIPH_SPI) |\r
+ (1<<PERIPH_SSC) |\r
+ (1<<PERIPH_PWMC) |\r
+ (1<<PERIPH_UDP);\r
+\r
+ // worst case scenario, with 16Mhz xtal startup delay is 14.5ms\r
+ // with a slow clock running at it worst case (max) frequency of 42khz\r
+ // max startup delay = (14.5ms*42k)/8 = 76 = 0x4C round up to 0x50\r
+\r
+ // enable main oscillator and set startup delay\r
+ PMC_MAIN_OSCILLATOR = PMC_MAIN_OSCILLATOR_ENABLE |\r
+ PMC_MAIN_OSCILLATOR_STARTUP_DELAY(0x50);\r
+\r
+ // wait for main oscillator to stabilize\r
+ while ( !(PMC_INTERRUPT_STATUS & PMC_MAIN_OSCILLATOR_STABILIZED) )\r
+ ;\r
+\r
+ // minimum PLL clock frequency is 80 MHz in range 00 (96 here so okay)\r
+ // frequency is crystal * multiplier / divisor = 16Mhz * 12 / 2 = 96Mhz\r
+ PMC_PLL = PMC_PLL_DIVISOR(2) | PMC_PLL_COUNT_BEFORE_LOCK(0x50) |\r
+ PMC_PLL_FREQUENCY_RANGE(0) | PMC_PLL_MULTIPLIER(12) |\r
+ PMC_PLL_USB_DIVISOR(1);\r
+\r
+ // wait for PLL to lock\r
+ while ( !(PMC_INTERRUPT_STATUS & PMC_MAIN_OSCILLATOR_PLL_LOCK) )\r
+ ;\r
+\r
+ // we want a master clock (MCK) to be PLL clock / 2 = 96Mhz / 2 = 48Mhz\r
+ // as per datasheet, this register must be programmed in two operations\r
+ // when changing to PLL, program the prescaler first then the source\r
+ PMC_MASTER_CLK = PMC_CLK_PRESCALE_DIV_2;\r
+\r
+ // wait for main clock ready signal\r
+ while ( !(PMC_INTERRUPT_STATUS & PMC_MAIN_OSCILLATOR_MCK_READY) )\r
+ ;\r
+\r
+ // set the source to PLL\r
+ PMC_MASTER_CLK = PMC_CLK_SELECTION_PLL_CLOCK | PMC_CLK_PRESCALE_DIV_2;\r
+\r
+ // wait for main clock ready signal\r
+ while ( !(PMC_INTERRUPT_STATUS & PMC_MAIN_OSCILLATOR_MCK_READY) )\r
+ ;\r
+}\r
+\r
+static void Fatal(void)\r
+{\r
+ for(;;);\r
+}\r
+\r
+void UsbPacketReceived(BYTE *packet, int len)\r
+{\r
+ int i;\r
+ UsbCommand *c = (UsbCommand *)packet;\r
+ volatile DWORD *p;\r
+\r
+ if(len != sizeof(*c)) {\r
+ Fatal();\r
+ }\r
+\r
+ switch(c->cmd) {\r
+ case CMD_DEVICE_INFO:\r
+ break;\r
+\r
+ case CMD_SETUP_WRITE:\r
+ p = (volatile DWORD *)0;\r
+ for(i = 0; i < 12; i++) {\r
+ p[i+c->ext1] = c->d.asDwords[i];\r
+ }\r
+ break;\r
+\r
+ case CMD_FINISH_WRITE:\r
+ p = (volatile DWORD *)0;\r
+ for(i = 0; i < 4; i++) {\r
+ p[i+60] = c->d.asDwords[i];\r
+ }\r
+\r
+ MC_FLASH_COMMAND = MC_FLASH_COMMAND_KEY |\r
+ MC_FLASH_COMMAND_PAGEN(c->ext1/FLASH_PAGE_SIZE_BYTES) |\r
+ FCMD_WRITE_PAGE;\r
+ while(!(MC_FLASH_STATUS & MC_FLASH_STATUS_READY))\r
+ ;\r
+ break;\r
+\r
+ case CMD_HARDWARE_RESET:\r
+ break;\r
+\r
+ default:\r
+ Fatal();\r
+ break;\r
+ }\r
+\r
+ c->cmd = CMD_ACK;\r
+ UsbSendPacket(packet, len);\r
+}\r
+\r
+void BootROM(void)\r
+{\r
+ //------------\r
+ // First set up all the I/O pins; GPIOs configured directly, other ones\r
+ // just need to be assigned to the appropriate peripheral.\r
+\r
+ // Kill all the pullups, especially the one on USB D+; leave them for\r
+ // the unused pins, though.\r
+ PIO_NO_PULL_UP_ENABLE = (1 << GPIO_USB_PU) |\r
+ (1 << GPIO_LED_A) |\r
+ (1 << GPIO_LED_B) |\r
+ (1 << GPIO_LED_C) |\r
+ (1 << GPIO_LED_D) |\r
+ (1 << GPIO_FPGA_DIN) |\r
+ (1 << GPIO_FPGA_DOUT) |\r
+ (1 << GPIO_FPGA_CCLK) |\r
+ (1 << GPIO_FPGA_NINIT) |\r
+ (1 << GPIO_FPGA_NPROGRAM) |\r
+ (1 << GPIO_FPGA_DONE) |\r
+ (1 << GPIO_MUXSEL_HIPKD) |\r
+ (1 << GPIO_MUXSEL_HIRAW) |\r
+ (1 << GPIO_MUXSEL_LOPKD) |\r
+ (1 << GPIO_MUXSEL_LORAW) |\r
+ (1 << GPIO_RELAY) |\r
+ (1 << GPIO_NVDD_ON);\r
+ // (and add GPIO_FPGA_ON)\r
+ // These pins are outputs\r
+ PIO_OUTPUT_ENABLE = (1 << GPIO_LED_A) |\r
+ (1 << GPIO_LED_B) |\r
+ (1 << GPIO_LED_C) |\r
+ (1 << GPIO_LED_D) |\r
+ (1 << GPIO_RELAY) |\r
+ (1 << GPIO_NVDD_ON);\r
+ // PIO controls the following pins\r
+ PIO_ENABLE = (1 << GPIO_USB_PU) |\r
+ (1 << GPIO_LED_A) |\r
+ (1 << GPIO_LED_B) |\r
+ (1 << GPIO_LED_C) |\r
+ (1 << GPIO_LED_D);\r
+\r
+ USB_D_PLUS_PULLUP_OFF();\r
+ LED_D_OFF();\r
+ LED_C_ON();\r
+ LED_B_OFF();\r
+ LED_A_OFF();\r
+\r
+ // if 512K FLASH part - TODO make some defines :)\r
+ if ((DBGU_CIDR | 0xf00) == 0xa00) {\r
+ MC_FLASH_MODE0 = MC_FLASH_MODE_FLASH_WAIT_STATES(1) |\r
+ MC_FLASH_MODE_MASTER_CLK_IN_MHZ(0x48);\r
+ MC_FLASH_MODE1 = MC_FLASH_MODE_FLASH_WAIT_STATES(1) |\r
+ MC_FLASH_MODE_MASTER_CLK_IN_MHZ(0x48);\r
+ } else {\r
+ MC_FLASH_MODE0 = MC_FLASH_MODE_FLASH_WAIT_STATES(0) |\r
+ MC_FLASH_MODE_MASTER_CLK_IN_MHZ(48);\r
+ }\r
+\r
+ // Initialize all system clocks\r
+ ConfigClocks();\r
+\r
+ LED_A_ON();\r
+\r
+ if(BUTTON_PRESS()) {\r
+ UsbStart();\r
+ }\r
+\r
+ for(;;) {\r
+ WDT_HIT();\r
+\r
+ UsbPoll(TRUE);\r
+\r
+ if(!BUTTON_PRESS()) {\r
+ USB_D_PLUS_PULLUP_OFF();\r
+ LED_B_ON();\r
+\r
+ // jump to RAM address 0x10000 (LSBit set for thumb mode)\r
+ asm("ldr r3, = 0x10001\n");\r
+ asm("bx r3\n");\r
+ }\r
+ }\r
+}\r
--- /dev/null
+.extern CopyBootToRAM\r
+ \r
+.text\r
+.code 32\r
+.align 0\r
+\r
+.global start\r
+start:\r
+ b Reset\r
+ b UndefinedInstruction\r
+ b SoftwareInterrupt\r
+ b PrefetchAbort\r
+ b DataAbort\r
+ b Reserved\r
+ b Irq\r
+ b Fiq\r
+\r
+Reset:\r
+ ldr sp, = 0x0020FFF8 @ initialize stack pointer to top of RAM\r
+ bl CopyBootToRAM @ copy bootloader to RAM (in case the\r
+ @ user re-flashes the bootloader)\r
+ ldr r3, = 0x00200000 @ start address of RAM bootloader\r
+ bx r3 @ jump to it\r
+\r
+Fiq:\r
+ b Fiq\r
+UndefinedInstruction:\r
+ b UndefinedInstruction\r
+SoftwareInterrupt:\r
+ b SoftwareInterrupt\r
+PrefetchAbort:\r
+ b PrefetchAbort\r
+DataAbort:\r
+ b DataAbort\r
+Reserved:\r
+ b Reserved\r
+Irq:\r
+ b Irq\r
--- /dev/null
+#include <proxmark3.h>\r
+\r
+void CopyBootToRAM(void)\r
+{\r
+ int i;\r
+\r
+ volatile DWORD *s = (volatile DWORD *)0x200;\r
+ volatile DWORD *d = (volatile DWORD *)0x200000;\r
+\r
+ for(i = 0; i < 1024; i++) *d++ = *s++;\r
+}\r
--- /dev/null
+SECTIONS\r
+{\r
+ . = 0x00000000;\r
+ .text : { obj/flash-reset.o(.text) *(.text) }\r
+ .rodata : { *(.rodata) }\r
+ . = 0x00200000;\r
+ .data : { *(.data) }\r
+ __bss_start__ = .;\r
+ .bss : { *(.bss) }\r
+ __bss_end__ = .;\r
+}\r
--- /dev/null
+SECTIONS\r
+{\r
+ . = 0x00200000;\r
+ .text : { obj/ram-reset.o(.text) *(.text) }\r
+ .rodata : { *(.rodata) }\r
+ .data : { *(.data) }\r
+ __bss_start__ = .;\r
+ .bss : { *(.bss) }\r
+ __bss_end__ = .;\r
+}\r
--- /dev/null
+.extern BootROM\r
+ \r
+.text\r
+.code 32\r
+.align 0\r
+\r
+.global start\r
+start:\r
+ ldr sp, = 0x0020FFF8\r
+ bl BootROM\r
--- /dev/null
+@echo off\r
+set PATH=..\..\devkitARM\bin;..\..\devkitWIN\bin;%PATH%\r
+set INCLUDE=..\..\devkitWIN\include\r
+set LIB=..\..\devkitWIN\lib\r
+cmd.exe
\ No newline at end of file
--- /dev/null
+@echo off\r
+cd ..\armsrc\r
+rem nmake clean\r
+nmake\r
+cd ..\cockpit\r
--- /dev/null
+@echo off\r
+cd ..\bootrom\r
+rem nmake clean\r
+nmake\r
+cd ..\cockpit\r
--- /dev/null
+@echo off\r
+cd ..\winsrc\r
+rem nmake clean\r
+nmake\r
+cd ..\cockpit\r
--- /dev/null
+@echo off\r
+..\winsrc\prox.exe load ..\armsrc\obj\osimage.s19\r
+..\winsrc\prox.exe load ..\armsrc\obj\osimage.s19\r
--- /dev/null
+call 1makearm.bat\r
+call 2makeboot.bat\r
+call 3makewin.bat\r
--- /dev/null
+@echo off\r
+cd ..\winsrc\r
+call prox gui
\ No newline at end of file
--- /dev/null
+//-----------------------------------------------------------------------------\r
+// Routines to compute the CRCs (two different flavours, just for confusion)\r
+// required for ISO 14443, swiped directly from the spec.\r
+//-----------------------------------------------------------------------------\r
+\r
+#define CRC_14443_A 0x6363 /* ITU-V.41 */\r
+#define CRC_14443_B 0xFFFF /* ISO/IEC 13239 (formerly ISO/IEC 3309) */\r
+\r
+static unsigned short UpdateCrc14443(unsigned char ch, unsigned short *lpwCrc)\r
+{\r
+ ch = (ch ^ (unsigned char) ((*lpwCrc) & 0x00FF));\r
+ ch = (ch ^ (ch << 4));\r
+ *lpwCrc = (*lpwCrc >> 8) ^ ((unsigned short) ch << 8) ^\r
+ ((unsigned short) ch << 3) ^ ((unsigned short) ch >> 4);\r
+ return (*lpwCrc);\r
+}\r
+\r
+static void ComputeCrc14443(int CrcType, BYTE *Data, int Length,\r
+ BYTE *TransmitFirst, BYTE *TransmitSecond)\r
+{\r
+ unsigned char chBlock;\r
+ unsigned short wCrc=CrcType;\r
+\r
+ do {\r
+ chBlock = *Data++;\r
+ UpdateCrc14443(chBlock, &wCrc);\r
+ } while (--Length);\r
+\r
+ if (CrcType == CRC_14443_B)\r
+ wCrc = ~wCrc; /* ISO/IEC 13239 (formerly ISO/IEC 3309) */\r
+\r
+ *TransmitFirst = (BYTE) (wCrc & 0xFF);\r
+ *TransmitSecond = (BYTE) ((wCrc >> 8) & 0xFF);\r
+ return;\r
+}\r
--- /dev/null
+//-----------------------------------------------------------------------------\r
+// My USB driver. This has to be common, because it exists in both the\r
+// bootrom and the application.\r
+// Jonathan Westhues, split Aug 14 2005\r
+//-----------------------------------------------------------------------------\r
+#include <proxmark3.h>\r
+\r
+#define min(a, b) (((a) > (b)) ? (b) : (a))\r
+\r
+#define USB_REPORT_PACKET_SIZE 64\r
+\r
+typedef struct PACKED {\r
+ BYTE bmRequestType;\r
+ BYTE bRequest;\r
+ WORD wValue;\r
+ WORD wIndex;\r
+ WORD wLength;\r
+} UsbSetupData;\r
+\r
+#define USB_REQUEST_GET_STATUS 0\r
+#define USB_REQUEST_CLEAR_FEATURE 1\r
+#define USB_REQUEST_SET_FEATURE 3\r
+#define USB_REQUEST_SET_ADDRESS 5\r
+#define USB_REQUEST_GET_DESCRIPTOR 6\r
+#define USB_REQUEST_SET_DESCRIPTOR 7\r
+#define USB_REQUEST_GET_CONFIGURATION 8\r
+#define USB_REQUEST_SET_CONFIGURATION 9\r
+#define USB_REQUEST_GET_INTERFACE 10\r
+#define USB_REQUEST_SET_INTERFACE 11\r
+#define USB_REQUEST_SYNC_FRAME 12\r
+\r
+#define USB_DESCRIPTOR_TYPE_DEVICE 1\r
+#define USB_DESCRIPTOR_TYPE_CONFIGURATION 2\r
+#define USB_DESCRIPTOR_TYPE_STRING 3\r
+#define USB_DESCRIPTOR_TYPE_INTERFACE 4\r
+#define USB_DESCRIPTOR_TYPE_ENDPOINT 5\r
+#define USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER 6\r
+#define USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONF 7\r
+#define USB_DESCRIPTOR_TYPE_INTERFACE_POWER 8\r
+#define USB_DESCRIPTOR_TYPE_HID 0x21\r
+#define USB_DESCRIPTOR_TYPE_HID_REPORT 0x22\r
+\r
+#define USB_DEVICE_CLASS_HID 0x03\r
+\r
+static const BYTE HidReportDescriptor[] = {\r
+ 0x06,0xA0,0xFF, // Usage Page (vendor defined) FFA0\r
+ 0x09,0x01, // Usage (vendor defined)\r
+ 0xA1,0x01, // Collection (Application)\r
+ 0x09,0x02, // Usage (vendor defined)\r
+ 0xA1,0x00, // Collection (Physical)\r
+ 0x06,0xA1,0xFF, // Usage Page (vendor defined)\r
+\r
+ //The,input report\r
+ 0x09,0x03, // usage - vendor defined\r
+ 0x09,0x04, // usage - vendor defined\r
+ 0x15,0x80, // Logical Minimum (-128)\r
+ 0x25,0x7F, // Logical Maximum (127)\r
+ 0x35,0x00, // Physical Minimum (0)\r
+ 0x45,0xFF, // Physical Maximum (255)\r
+ 0x75,0x08, // Report Size (8) (bits)\r
+ 0x95,0x40, // Report Count (64) (fields)\r
+ 0x81,0x02, // Input (Data,Variable,Absolute)\r
+\r
+ //The,output report\r
+ 0x09,0x05, // usage - vendor defined\r
+ 0x09,0x06, // usage - vendor defined\r
+ 0x15,0x80, // Logical Minimum (-128)\r
+ 0x25,0x7F, // Logical Maximum (127)\r
+ 0x35,0x00, // Physical Minimum (0)\r
+ 0x45,0xFF, // Physical Maximum (255)\r
+ 0x75,0x08, // Report Size (8) (bits)\r
+ 0x95,0x40, // Report Count (64) (fields)\r
+ 0x91,0x02, // Output (Data,Variable,Absolute)\r
+\r
+ 0xC0, // End Collection\r
+\r
+ 0xC0, // End Collection\r
+};\r
+\r
+static const BYTE DeviceDescriptor[] = {\r
+ 0x12, // Descriptor length (18 bytes)\r
+ 0x01, // Descriptor type (Device)\r
+ 0x10,0x01, // Complies with USB Spec. Release (0110h = release 1.10)\r
+ 0x00, // Class code (0)\r
+ 0x00, // Subclass code (0)\r
+ 0x00, // Protocol (No specific protocol)\r
+ 0x08, // Maximum packet size for Endpoint 0 (8 bytes)\r
+ 0xc4,0x9a, // Vendor ID (random numbers)\r
+ 0x8f,0x4b, // Product ID (random numbers)\r
+ 0x01,0x00, // Device release number (0001)\r
+ 0x01, // Manufacturer string descriptor index\r
+ 0x02, // Product string descriptor index\r
+ 0x00, // Serial Number string descriptor index (None)\r
+ 0x01, // Number of possible configurations (1)\r
+};\r
+\r
+static const BYTE ConfigurationDescriptor[] = {\r
+ 0x09, // Descriptor length (9 bytes)\r
+ 0x02, // Descriptor type (Configuration)\r
+ 0x29,0x00, // Total data length (41 bytes)\r
+ 0x01, // Interface supported (1)\r
+ 0x01, // Configuration value (1)\r
+ 0x00, // Index of string descriptor (None)\r
+ 0x80, // Configuration (Bus powered)\r
+ 250, // Maximum power consumption (500mA)\r
+\r
+ //interface\r
+ 0x09, // Descriptor length (9 bytes)\r
+ 0x04, // Descriptor type (Interface)\r
+ 0x00, // Number of interface (0)\r
+ 0x00, // Alternate setting (0)\r
+ 0x02, // Number of interface endpoint (2)\r
+ 0x03, // Class code (HID)\r
+ 0x00, // Subclass code ()\r
+ 0x00, // Protocol code ()\r
+ 0x00, // Index of string()\r
+\r
+ // class\r
+ 0x09, // Descriptor length (9 bytes)\r
+ 0x21, // Descriptor type (HID)\r
+ 0x00,0x01, // HID class release number (1.00)\r
+ 0x00, // Localized country code (None)\r
+ 0x01, // # of HID class dscrptr to follow (1)\r
+ 0x22, // Report descriptor type (HID)\r
+ // Total length of report descriptor\r
+ sizeof(HidReportDescriptor),0x00,\r
+\r
+ // endpoint 1\r
+ 0x07, // Descriptor length (7 bytes)\r
+ 0x05, // Descriptor type (Endpoint)\r
+ 0x01, // Encoded address (Respond to OUT)\r
+ 0x03, // Endpoint attribute (Interrupt transfer)\r
+ 0x08,0x00, // Maximum packet size (8 bytes)\r
+ 0x01, // Polling interval (1 ms)\r
+\r
+ // endpoint 2\r
+ 0x07, // Descriptor length (7 bytes)\r
+ 0x05, // Descriptor type (Endpoint)\r
+ 0x82, // Encoded address (Respond to IN)\r
+ 0x03, // Endpoint attribute (Interrupt transfer)\r
+ 0x08,0x00, // Maximum packet size (8 bytes)\r
+ 0x01, // Polling interval (1 ms)\r
+};\r
+\r
+static const BYTE StringDescriptor0[] = {\r
+ 0x04, // Length\r
+ 0x03, // Type is string\r
+ 0x09, // English\r
+ 0x04, // US\r
+};\r
+\r
+static const BYTE StringDescriptor1[] = {\r
+ 24, // Length\r
+ 0x03, // Type is string\r
+ 'J', 0x00,\r
+ '.', 0x00,\r
+ ' ', 0x00,\r
+ 'W', 0x00,\r
+ 'e', 0x00,\r
+ 's', 0x00,\r
+ 't', 0x00,\r
+ 'h', 0x00,\r
+ 'u', 0x00,\r
+ 'e', 0x00,\r
+ 's', 0x00,\r
+};\r
+\r
+static const BYTE StringDescriptor2[] = {\r
+ 54, // Length\r
+ 0x03, // Type is string\r
+ 'P', 0x00,\r
+ 'r', 0x00,\r
+ 'o', 0x00,\r
+ 'x', 0x00,\r
+ 'M', 0x00,\r
+ 'a', 0x00,\r
+ 'r', 0x00,\r
+ 'k', 0x00,\r
+ '-', 0x00,\r
+ '3', 0x00,\r
+ ' ', 0x00,\r
+ 'R', 0x00,\r
+ 'F', 0x00,\r
+ 'I', 0x00,\r
+ 'D', 0x00,\r
+ ' ', 0x00,\r
+ 'I', 0x00,\r
+ 'n', 0x00,\r
+ 's', 0x00,\r
+ 't', 0x00,\r
+ 'r', 0x00,\r
+ 'u', 0x00,\r
+ 'm', 0x00,\r
+ 'e', 0x00,\r
+ 'n', 0x00,\r
+ 't', 0x00,\r
+};\r
+\r
+static const BYTE * const StringDescriptors[] = {\r
+ StringDescriptor0,\r
+ StringDescriptor1,\r
+ StringDescriptor2,\r
+};\r
+\r
+\r
+static BYTE UsbBuffer[64];\r
+static int UsbSoFarCount;\r
+\r
+static BYTE CurrentConfiguration;\r
+\r
+static void UsbSendEp0(const BYTE *data, int len)\r
+{\r
+ int thisTime, i;\r
+\r
+ do {\r
+ thisTime = min(len, 8);\r
+ len -= thisTime;\r
+\r
+ for(i = 0; i < thisTime; i++) {\r
+ UDP_ENDPOINT_FIFO(0) = *data;\r
+ data++;\r
+ }\r
+\r
+ if(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED) {\r
+ UDP_ENDPOINT_CSR(0) &= ~UDP_CSR_TX_PACKET_ACKED;\r
+ while(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED)\r
+ ;\r
+ }\r
+\r
+ UDP_ENDPOINT_CSR(0) |= UDP_CSR_TX_PACKET;\r
+\r
+ do {\r
+ if(UDP_ENDPOINT_CSR(0) & UDP_CSR_RX_PACKET_RECEIVED_BANK_0) {\r
+ // This means that the host is trying to write to us, so\r
+ // abandon our write to them.\r
+ UDP_ENDPOINT_CSR(0) &= ~UDP_CSR_RX_PACKET_RECEIVED_BANK_0;\r
+ return;\r
+ }\r
+ } while(!(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED));\r
+ } while(len > 0);\r
+\r
+ if(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED) {\r
+ UDP_ENDPOINT_CSR(0) &= ~UDP_CSR_TX_PACKET_ACKED;\r
+ while(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED)\r
+ ;\r
+ }\r
+}\r
+\r
+static void UsbSendZeroLength(void)\r
+{\r
+ UDP_ENDPOINT_CSR(0) |= UDP_CSR_TX_PACKET;\r
+\r
+ while(!(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED))\r
+ ;\r
+\r
+ UDP_ENDPOINT_CSR(0) &= ~UDP_CSR_TX_PACKET_ACKED;\r
+\r
+ while(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED)\r
+ ;\r
+}\r
+\r
+static void HandleRxdSetupData(void)\r
+{\r
+ int i;\r
+ UsbSetupData usd;\r
+\r
+ for(i = 0; i < sizeof(usd); i++) {\r
+ ((BYTE *)&usd)[i] = UDP_ENDPOINT_FIFO(0);\r
+ }\r
+\r
+ if(usd.bmRequestType & 0x80) {\r
+ UDP_ENDPOINT_CSR(0) |= UDP_CSR_CONTROL_DATA_DIR;\r
+ while(!(UDP_ENDPOINT_CSR(0) & UDP_CSR_CONTROL_DATA_DIR))\r
+ ;\r
+ }\r
+\r
+ UDP_ENDPOINT_CSR(0) &= ~UDP_CSR_RX_HAVE_READ_SETUP_DATA;\r
+ while(UDP_ENDPOINT_CSR(0) & UDP_CSR_RX_HAVE_READ_SETUP_DATA)\r
+ ;\r
+\r
+ switch(usd.bRequest) {\r
+ case USB_REQUEST_GET_DESCRIPTOR:\r
+ if((usd.wValue >> 8) == USB_DESCRIPTOR_TYPE_DEVICE) {\r
+ UsbSendEp0((BYTE *)&DeviceDescriptor,\r
+ min(sizeof(DeviceDescriptor), usd.wLength));\r
+ } else if((usd.wValue >> 8) == USB_DESCRIPTOR_TYPE_CONFIGURATION) {\r
+ UsbSendEp0((BYTE *)&ConfigurationDescriptor,\r
+ min(sizeof(ConfigurationDescriptor), usd.wLength));\r
+ } else if((usd.wValue >> 8) == USB_DESCRIPTOR_TYPE_STRING) {\r
+ const BYTE *s = StringDescriptors[usd.wValue & 0xff];\r
+ UsbSendEp0(s, min(s[0], usd.wLength));\r
+ } else if((usd.wValue >> 8) == USB_DESCRIPTOR_TYPE_HID_REPORT) {\r
+ UsbSendEp0((BYTE *)&HidReportDescriptor,\r
+ min(sizeof(HidReportDescriptor), usd.wLength));\r
+ } else {\r
+ *((DWORD *)0x00200000) = usd.wValue;\r
+ }\r
+ break;\r
+\r
+ case USB_REQUEST_SET_ADDRESS:\r
+ UsbSendZeroLength();\r
+ UDP_FUNCTION_ADDR = UDP_FUNCTION_ADDR_ENABLED | usd.wValue ;\r
+ if(usd.wValue != 0) {\r
+ UDP_GLOBAL_STATE = UDP_GLOBAL_STATE_ADDRESSED;\r
+ } else {\r
+ UDP_GLOBAL_STATE = 0;\r
+ }\r
+ break;\r
+\r
+ case USB_REQUEST_GET_CONFIGURATION:\r
+ UsbSendEp0(&CurrentConfiguration, sizeof(CurrentConfiguration));\r
+ break;\r
+\r
+ case USB_REQUEST_GET_STATUS: {\r
+ if(usd.bmRequestType & 0x80) {\r
+ WORD w = 0;\r
+ UsbSendEp0((BYTE *)&w, sizeof(w));\r
+ }\r
+ break;\r
+ }\r
+ case USB_REQUEST_SET_CONFIGURATION:\r
+ CurrentConfiguration = usd.wValue;\r
+ if(CurrentConfiguration) {\r
+ UDP_GLOBAL_STATE = UDP_GLOBAL_STATE_CONFIGURED;\r
+ UDP_ENDPOINT_CSR(1) = UDP_CSR_ENABLE_EP |\r
+ UDP_CSR_EPTYPE_INTERRUPT_OUT;\r
+ UDP_ENDPOINT_CSR(2) = UDP_CSR_ENABLE_EP |\r
+ UDP_CSR_EPTYPE_INTERRUPT_IN;\r
+ } else {\r
+ UDP_GLOBAL_STATE = UDP_GLOBAL_STATE_ADDRESSED;\r
+ UDP_ENDPOINT_CSR(1) = 0;\r
+ UDP_ENDPOINT_CSR(2) = 0;\r
+ }\r
+ UsbSendZeroLength();\r
+ break;\r
+\r
+ case USB_REQUEST_GET_INTERFACE: {\r
+ BYTE b = 0;\r
+ UsbSendEp0(&b, sizeof(b));\r
+ break;\r
+ }\r
+\r
+ case USB_REQUEST_SET_INTERFACE:\r
+ UsbSendZeroLength();\r
+ break;\r
+\r
+ case USB_REQUEST_CLEAR_FEATURE:\r
+ case USB_REQUEST_SET_FEATURE:\r
+ case USB_REQUEST_SET_DESCRIPTOR:\r
+ case USB_REQUEST_SYNC_FRAME:\r
+ default:\r
+ break;\r
+ }\r
+}\r
+\r
+void UsbSendPacket(BYTE *packet, int len)\r
+{\r
+ int i, thisTime;\r
+\r
+ while(len > 0) {\r
+ thisTime = min(len, 8);\r
+\r
+ for(i = 0; i < thisTime; i++) {\r
+ UDP_ENDPOINT_FIFO(2) = packet[i];\r
+ }\r
+ UDP_ENDPOINT_CSR(2) |= UDP_CSR_TX_PACKET;\r
+\r
+ while(!(UDP_ENDPOINT_CSR(2) & UDP_CSR_TX_PACKET_ACKED))\r
+ ;\r
+ UDP_ENDPOINT_CSR(2) &= ~UDP_CSR_TX_PACKET_ACKED;\r
+\r
+ while(UDP_ENDPOINT_CSR(2) & UDP_CSR_TX_PACKET_ACKED)\r
+ ;\r
+\r
+ len -= thisTime;\r
+ packet += thisTime;\r
+ }\r
+}\r
+\r
+static void HandleRxdData(void)\r
+{\r
+ int i, len;\r
+\r
+ if(UDP_ENDPOINT_CSR(1) & UDP_CSR_RX_PACKET_RECEIVED_BANK_0) {\r
+ len = UDP_CSR_BYTES_RECEIVED(UDP_ENDPOINT_CSR(1));\r
+\r
+ for(i = 0; i < len; i++) {\r
+ UsbBuffer[UsbSoFarCount] = UDP_ENDPOINT_FIFO(1);\r
+ UsbSoFarCount++;\r
+ }\r
+\r
+ UDP_ENDPOINT_CSR(1) &= ~UDP_CSR_RX_PACKET_RECEIVED_BANK_0;\r
+ while(UDP_ENDPOINT_CSR(1) & UDP_CSR_RX_PACKET_RECEIVED_BANK_0)\r
+ ;\r
+\r
+ if(UsbSoFarCount >= 64) {\r
+ UsbPacketReceived(UsbBuffer, UsbSoFarCount);\r
+ UsbSoFarCount = 0;\r
+ }\r
+ }\r
+\r
+ if(UDP_ENDPOINT_CSR(1) & UDP_CSR_RX_PACKET_RECEIVED_BANK_1) {\r
+ len = UDP_CSR_BYTES_RECEIVED(UDP_ENDPOINT_CSR(1));\r
+\r
+ for(i = 0; i < len; i++) {\r
+ UsbBuffer[UsbSoFarCount] = UDP_ENDPOINT_FIFO(1);\r
+ UsbSoFarCount++;\r
+ }\r
+\r
+ UDP_ENDPOINT_CSR(1) &= ~UDP_CSR_RX_PACKET_RECEIVED_BANK_1;\r
+ while(UDP_ENDPOINT_CSR(1) & UDP_CSR_RX_PACKET_RECEIVED_BANK_1)\r
+ ;\r
+\r
+ if(UsbSoFarCount >= 64) {\r
+ UsbPacketReceived(UsbBuffer, UsbSoFarCount);\r
+ UsbSoFarCount = 0;\r
+ }\r
+ }\r
+}\r
+\r
+void UsbStart(void)\r
+{\r
+ volatile int i;\r
+\r
+ UsbSoFarCount = 0;\r
+\r
+ USB_D_PLUS_PULLUP_OFF();\r
+\r
+ for(i = 0; i < 1000000; i++)\r
+ ;\r
+\r
+ USB_D_PLUS_PULLUP_ON();\r
+\r
+ if(UDP_INTERRUPT_STATUS & UDP_INTERRUPT_END_OF_BUS_RESET) {\r
+ UDP_INTERRUPT_CLEAR = UDP_INTERRUPT_END_OF_BUS_RESET;\r
+ }\r
+}\r
+\r
+BOOL UsbPoll(BOOL blinkLeds)\r
+{\r
+ BOOL ret = FALSE;\r
+\r
+ if(UDP_INTERRUPT_STATUS & UDP_INTERRUPT_END_OF_BUS_RESET) {\r
+ UDP_INTERRUPT_CLEAR = UDP_INTERRUPT_END_OF_BUS_RESET;\r
+\r
+ // following a reset we should be ready to receive a setup packet\r
+ UDP_RESET_ENDPOINT = 0xf;\r
+ UDP_RESET_ENDPOINT = 0;\r
+\r
+ UDP_FUNCTION_ADDR = UDP_FUNCTION_ADDR_ENABLED;\r
+\r
+ UDP_ENDPOINT_CSR(0) = UDP_CSR_EPTYPE_CONTROL | UDP_CSR_ENABLE_EP;\r
+\r
+ CurrentConfiguration = 0;\r
+\r
+ ret = TRUE;\r
+ }\r
+\r
+ if(UDP_INTERRUPT_STATUS & UDP_INTERRUPT_ENDPOINT(0)) {\r
+ if(UDP_ENDPOINT_CSR(0) & UDP_CSR_RX_HAVE_READ_SETUP_DATA) {\r
+ HandleRxdSetupData();\r
+ ret = TRUE;\r
+ }\r
+ }\r
+\r
+ if(UDP_INTERRUPT_STATUS & UDP_INTERRUPT_ENDPOINT(1)) {\r
+ HandleRxdData();\r
+ ret = TRUE;\r
+ }\r
+\r
+ return ret;\r
+}\r
--- /dev/null
+################
+## 2009/03/28 ##
+################
+winsrc/command.cpp
+ Added two new LF commands for tag exploration :
+
+ - askdemod: takes 2 arguments, one is the clock rate, one is the modulation
+ convention (high mod is 1 or high mod is zero)
+
+ This command demodulates the stream into a binary stream into
+ the trace buffer (0's and 1's)
+
+ - mandemod: manchester decoding of a bitstream: takes a binary stream from
+ the trace buffer (see askdemod) and attempts to do manchester decoding
+ to it. One argument: clock rate. Outputs the bitstream to the scrollback buffer.
+
+ Those two helped me to validate that the unknown tag I had was indeed an EM4100 type of tag
+
+
+################\r
+## 2008/12/11 ##\r
+################\r
+bootrom/bootrom.c\r
+ Significant changes to bootloader. Use of Chip ID register to detect if running on a SAM7S512 then configure FLASH\r
+ waitstates as per SummoningDark's suggestion for a SAM7S512 or SAM7S256.\r
+ Deleted idle loops waiting blindly for clocks to settle and now using status registers to detect when clocks are stable.\r
+\r
+ *************************\r
+ * IMPORTANT INFORMATION *\r
+ **************************************************************************************************************************\r
+ * With this boot code, the device can now only be flashed if button is held down after power on or a software reset.\r
+ * The flash procedure is this:\r
+ * Hold down button. Either plug in USB or software reset it. _While_holding_down_button_ (red and yellow LEDs are lit) you can\r
+ * issue one or more of the "prox bootrom <file>" "prox fpga <file>" "prox load <file>", be sure to hold button down for the\r
+ * entire duration of the flash process. Only release the button when flashing is complete and you want to let the board boot.\r
+ * This process may be less convenient but it's safer and avoids "unintentional" flashing of the board.\r
+ **************************************************************************************************************************\r
+ LED boot sequence now changed, C (red) lights up when boot code jumps from flash to RAM boot code, A (yellow) lights up after\r
+ clocks have been initialized, B (green) lights up when jumping from boot code to main code, then D (red led away from the others)\r
+ lights up while code is being downloaded to FPGA, then all leds turn off and board is ready for action.\r
+\r
+ With these changes the board now boots and is ready to use in about 3 seconds. Also since the USB bus is not initialized\r
+ twice (once during boot, then again when the main code runs) unless the button is held down at boot, this seems to avoid\r
+ the double USB connect and "USB device not recognized" when device is connected to the USB bus or software reset.\r
+\r
+################\r
+## 2008/12/06 ##\r
+################\r
+armsrc/fpga.c\r
+ Implemented function SetupSpi() to initialize the Serial Peripheral Interface (SPI) in preparation to adding an LCD to the board.\r
+ Changed FpgaWriteConfWord() to use the SPI communication now instead of bit banging the serial data to the FPGA.\r
+\r
+fpga/fpga.v\r
+ The FPGA config word serializer required non standard SPI communication (ie for shifting in a 8 bit word, it required a 9th clock\r
+ cycle with NCS high to load the word from the shift register to the conf register). This was OK for manually bitbanging it but not\r
+ suitable for using SPI comms. The serializer was fixed to load the conf word from the shift register on a NCS lo-hi transition and\r
+ not require additional clocking.\r
+\r
+armsrc/fpgaimg.c\r
+ Recompiled FPGA code after changes above.\r
+\r
+armsrc/LCD.c\r
+ LCD driver for PCF8833 based LCDs like those found on Nokia models 2600,2650,3100,3120,5140,6030,6100,6610,7210,7250 maybe\r
+ others. These color LCDs have a resolution of 132x132 and a serial interface. They are very cheap like even down to $2/pc\r
+ This LCD driver is a straight rip of that found at http://www.sparkfun.com/datasheets/LCD/Jimbo-Nokia-SAM7-Example.zip with\r
+ very small changes, mainly to integrate it and make it compile with our codebase. Also comented out the circle subroutines\r
+ to keep the code to integer math only.\r
+\r
+armsrc/fonts.c\r
+ Font definition for LCD driver\r
+\r
+armsrc/appmain.c\r
+ Fixed a small bug in CmdHIDdemodFSK (added case 4) which prevented reading some tags. When a logic 0 is immediately followed\r
+ by the start of the next transmisson (special pattern) a pattern of 4 bit duration lengths is created.\r
+\r
+################\r
+## 2008/11/27 ##\r
+################\r
+armsrc/appmain.c\r
+ Implemented an HID tag FSK demodulator (CmdHIDdemodFSK) to obtain the tag ID code from the raw sampled waveform.\r
+ Implemented CmdHIDsimTAG which takes a 44bit HID tag ID as a hex number then creates the waveform and simulates the tag\r
+\r
+winsrc/command.cpp\r
+ Added command "hidfskdemod" that calls CmdHIDdemodFSK, the ARM FSK demodulator for HID tags.\r
+\r
+include/usb-cmd.h\r
+ New defines CMD_HID_DEMOD_FSK and CMD_HID_SIM_TAG\r
+\r
+2008/11/25\r
+common/iso14443_crc.c\r
+ Moved CRC calculation code into this file as it's common to both ARM and Windows side. This file is now included as needed.\r
+\r
+################\r
+## 2008/11/21 ##\r
+################\r
+armsrc/Makefile\r
+ Changes to split up the compilation of the ARM and produce separate S files for the FPGA code and the ARM code.\r
+\r
+armsrc/appmain.c\r
+ Replaced some of the hex value params in FpgaWriteConfWord with more explanatory defines.\r
+ Changes to the Tune command as it assumes wrong HF capacitor value (130pF) and produces wrong voltage readings.\r
+ Combined some of the integer arithmetic statements to improve accuracy slightly, since the voltage divider ratio is not an integer.\r
+ Voltage divider resistor network is 10M/240k = ratio of 41.6666\r
+\r
+ Originally the calculation was rounding the ratio down to 41\r
+ 3300 (mV) * 41 * sample_value / 1024\r
+ New calculation without rounding error is\r
+ 3300 (mV) * 41.66666 * sample_value / 1024 => 137500 * sample_value / 1024\r
+\r
+ New define BUTTON_PRESS() returns status of button\r
+\r
+armsrc/fpga.c\r
+ The current board can only take a X2S30 as there is no larger FPGA in PQFP100 package and\r
+ the smaller X2S15 FPGA can't fit the current code. The X2S30 FPGA config is fixed at 336,768 bits\r
+ The FPGA code base address and length is hard coded to occupy FLASH region 0x2000 - 0xC470.\r
+\r
+armsrc/ldscript-fpga\r
+ New file to place the FPGA code at FLASH address 0x2000\r
+\r
+bootrom/Makefile\r
+ Slight changes, commented out the generation of byteswapped S file, the other S files are generated in the same section of the makefile now.\r
+\r
+bootrom/bootrom.c\r
+ Changed some thumb code with a one line ARM code which is clearer and more explicit. Processor runs in ARM mode at reset anyway.\r
+ Changed jump to RAM address, used to jump to 0x2000 (now FPGA area), now jumps to 0x10000.\r
+\r
+bootrom/flash-reset.s\r
+ Changed name of CMain to CopyBootToRAM. Streamlined reset code, fixed up stack pointer initialization.\r
+\r
+bootrom/fromflash.c\r
+ Removed the whole section of initializing clocks, this is redundant as it's being done once we jump to boot code in RAM\r
+ All fromflash.c does now is copy the boot code to ram and jumps to it.\r
+\r
+bootrom/ram-reset.s\r
+ Fixed up stack pointer initialization that caused crash when using "loread"\r
+\r
+include/at91sam7s128.h\r
+ New defines for debug register, lets you identify what processor flavour the code runs on, RAM and FLASH sizes, etc.\r
+\r
+include/proxmark3.h\r
+ New useful defines for relay and button\r
+\r
+winsrc/Makefile\r
+ Added new define /D_CRT_SECURE_NO_WARNINGS to elliminate a _whole bunch_ of bogus compilation warnings\r
+\r
+winsrc/command.cpp\r
+ Changed CmdLosamples to take a numeric argument (number of samples x4 to retrieve from buffer)\r
+ New command Quit to exit the program from the GUI command prompt.\r
+\r
+winsrc/gui.cpp\r
+ Fixup compilation warnings.\r
+\r
+winsrc/prox.cpp\r
+ Tidy up printing to stdout, flashing progress now updates on the same line instead of scrolling up.\r
+ New command line parameter to load FPGA image to FLASH.\r
--- /dev/null
+This is a bare minimum compile environment for the proxmark3 sources. \r
+\r
+CONTENTS\r
+\r
+This bundle contains the ARM cross compiler in devkitARM and a _tiny_ subset\r
+of the Visual C++ 2008 Express Edition in devkitWIN which is the bare minimum\r
+required for compilation of this current source.\r
+\r
+If you plan on further source code development you are strongly encouraged\r
+to download the full Visual C++ 2008 available for free download from\r
+http://www.microsoft.com/express/download/\r
+\r
+CAVEATS\r
+\r
+There is no provision in this environment for compiling the FPGA source. To\r
+do that you need to download the free (registration required) ISE WebPack\r
+from Xilinx at http://www.xilinx.com/ise/logic_design_prod/webpack.htm\r
+Be warned, the pack is huge, 2Gb download and >4Gb installed.\r
+\r
+USAGE\r
+\r
+First of all run the .msi file in devkitWIN\vcredist_x86 to install the VC++\r
+redistributables, without these, nmake, cl and link won't run.\r
+\r
+Get a command prompts in the cockpit directory and pretty much run the batch\r
+files in the order they appear:\r
+\r
+0setpath.bat - sets the environment vars for the compile environment\r
+1makearm.bat - compiles the files in armsrc, output files in armsrc\obj\r
+2makeboot.bat - compiles the files in bootrom, output files in bootrom\obj\r
+3makewin.bat - compiles the files in winsrc, output files in winsrc\obj\r
+4flashos.bat - attempts to upload the OS image to the proxmark3 board\r
+\r
+ACKNOWLEDGMENTS\r
+\r
+Thanks to J Westhues for the original proxmark, Roel and the proxmark.org\r
+community. This pack may contain F/OSS or free but copyrighted software\r
+from Xilinx, Microsoft and others. All trademarks are the property of\r
+their respective owners. All rights reserved.\r
--- /dev/null
+\r
+This is outdated.\r
+\r
+---\r
+\r
+INTRODUCTION TO THE proxmark3\r
+=============================\r
+\r
+The proxmark3 device is designed to manipulate RFID tags in a number of\r
+different ways. For example, a proxmark3 can:\r
+\r
+ * read a low-frequency (~100 kHz) or high-frequency (13.56 MHz) tag,\r
+ including the ISO-standard tags; standards that require\r
+ bidirectional communication between the reader and the tag are\r
+ not a problem\r
+\r
+ * emulate a low- or high-frequency tag, in a way very similar to the\r
+ way that a real tag behaves (e.g., it derives its timing from the\r
+ incident carrier)\r
+\r
+ * eavesdrop on the signals exchanged between another reader and tag\r
+\r
+ * measure the resonant frequency of an antenna, to a certain extent\r
+ (this is a convenience when building a test setup for the previous\r
+ three functions)\r
+\r
+The proxmark3 may be thought of as a direct-sampling software radio.\r
+There is some complication, though, because of the usual dynamic range\r
+issue in dealing with signals in RFID systems (large signal due to\r
+the reader, small signal due to the tag). Some analog processing is\r
+therefore used to fix this before the signal is digitized. (Although,\r
+it is possible to digitize the signal from the antenna directly, with\r
+appropriate population options. It is just not usually a good idea.)\r
+\r
+SYSTEM ARCHITECTURE\r
+===================\r
+\r
+The ANTENNA sends and receives signals over the air. It is external to\r
+the board; it connects through SV2. Separate pins on the connector are\r
+used for the low- and high-frequency antennas, and the analog receive\r
+paths are separate. The antennas are inductive loops, which are resonated\r
+by on-board capacitors.\r
+\r
+On the transmit side, the antennas are excited by large numbers of\r
+paralleled bus driver buffers. By tri-stating some of the buffers, it\r
+is possible to vary the transmit strength. This may be used to generate\r
+a modulated carrier. The buffers are driven by signals from the FPGA,\r
+as are the output enables. The antennas are excited as series circuits,\r
+which permits a large input power for a relatively small input voltage.\r
+\r
+By driving all of the buffers low, it is possible to make the antenna\r
+look to the receive path like a parallel LC circuit; this provides a\r
+high-voltage output signal. This is typically what will be done when we\r
+are not actively transmitting a carrier (i.e., behaving as a reader).\r
+\r
+On the receive side, there are two possibilities, which are selected by\r
+RLY1. A mechanical relay is used, because the signal from the antenna is\r
+likely to be more positive or negative than the highest or lowest supply\r
+voltages on-board. In the usual case (PEAK-DETECTED mode), the received\r
+signal is peak-detected by an analog circuit, then filtered slightly,\r
+and then digitized by the ADC. This is the case for both the low- and\r
+high-frequency paths, although the details of the circuits for the\r
+two cases are somewhat different. This receive path would typically\r
+be selected when the device is behaving as a reader, or when it is\r
+eavesdropping at close range.\r
+\r
+It is also possible to digitize the signal from the antenna directly (RAW\r
+mode), after passing it through a gain stage. This is more likely to be\r
+useful in reading signals at long range, but the available dynamic range\r
+will be poor, since it is limited by the 8-bit A/D. These modes would be\r
+very appropriate, for example, for the heavily-discussed attacks in which\r
+a tag's ID is learned from the data broadcast by a reader performing an\r
+anticollision loop, because there is no dynamic range problem there. It\r
+would also be possible to program the proxmark3 to receive broadcast AM\r
+radio, with certain changes in component values.\r
+\r
+In either case, an analog signal is digitized by the ADC (IC8), and\r
+from there goes in to the FPGA (IC1). The FPGA is big enough that it\r
+can perform DSP operations itself. For some high-frequency standards,\r
+the subcarriers are fast enough that it would be inconvenient to do all\r
+the math on a general-purpose CPU. The FPGA can therefore correlate for\r
+the desired signal itself, and simply report the total to the ARM. For\r
+low-frequency tags, it probably makes sense just to pass data straight\r
+through to the ARM.\r
+\r
+The FPGA communicates with the ARM through either its SPI port (the ARM\r
+is the master) or its generic synchronous serial port (again, the ARM\r
+is the master). The ARM connects to the outside world over USB.\r
+\r
+DETAILS: POWER DISTRIBUTION\r
+===========================\r
+\r
+I make a half-hearted attempt to meet the USB power specs; this adds a\r
+bit of complexity. I have not made measurements to determine how close\r
+I come to succeeding, but I think that the suspend current might turn\r
+out to be a pain.\r
+\r
+The +3V3 rail is always powered, whenever we are plugged in to USB. This\r
+is generated by an LDO, which burns a quiescent current of 150 uA\r
+(typical) already. The only thing powered from the +3V3 rail is the ARM,\r
+which can presumably do smart power control when we are in suspend.\r
+\r
+The ARM generates two signals to switch power to the rest of the board:\r
+FPGA_ON, and NVDD_ON. When NVDD_ON goes low, the Vdd rail comes up to\r
+about five volts (the filtered-but-unregulated USB voltage). This powers\r
+most of the analog circuitry, including the ADC and all of the opamps\r
+and comparators in the receive path, and the coil drivers as well. Vdd\r
+also feeds the +3V3-FPGA and +2v5 regulators, which power only the\r
+FPGA. These regulators are enabled by FPGA_ON, so the FPGA is powered\r
+only when NVDD_ON is asserted low, and FPGA_ON is asserted high.\r
+\r
+DETAILS: FPGA\r
+=============\r
+\r
+The FPGA is a Spartan-II. This is a little bit old, but it is widely\r
+available, inexpensive, and five-volt tolerant. For development, the FPGA\r
+is configured over JTAG (SV5). In operation, the FPGA is configured in\r
+slave serial mode by the ARM, from a bitstream stored in the ARM's flash.\r
+\r
+Power to the FPGA is managed by regulators IC13 and IC12, both of which\r
+have shutdown. These generate the FPGA's VCCO (+3v3) and VCCINT (+2v5)\r
+supplies. I am a little bit worried about the power-on surge, since we\r
+run off USB. At the very minimum, the FPGA should not get power until\r
+we have enumerated and requested the full 500 mA available from USB. The\r
+large electrolytic capacitors C37 and C38 will presumably help with this.\r
+\r
+The logic is written in Verilog, of course for webpack. I have structured\r
+the FPGA in terms of `major modes:' the FPGA's `major mode' determines\r
+which of several modules is connected to the FPGA's I/O pins. A separate\r
+module is used for each of the FPGA's function; for example, there is\r
+now a module to read a 125 kHz tag, simulate a 125 kHz tag, transmit to\r
+an ISO 15693 tag, and receive from an ISO 15693 tag.\r
+\r
+DETAILS: ANALOG RECEIVE PATH\r
+============================\r
+\r
+For `slow' signals, I use an MCP6294 opamp. This has a GBW of 10 MHz,\r
+which is more than enough for the low-frequency stuff, and enough for\r
+all of the subcarrier frequencies that I know of at high frequency. In\r
+practice, the `slow' signals are all the signals following the peak\r
+detector. These signals are usually centred around the generated\r
+voltage Vmid.\r
+\r
+For `fast' signals, I use an AD8052. This is a very fast voltage-feedback\r
+amplifier (~100 MHz GBW). I use it immediately after the antenna for\r
+both the low- and high-frequency cases, as a sort of an ugly LNA. It is\r
+not optimal, but it certainly made the design easy.\r
+\r
+An ordinary CD4066 is used to multiplex the four possible signals\r
+(low/high frequency paths, RAW/PEAK-DETECTED). There is a potential\r
+problem at startup, when the ARM is in reset; there are pull-ups on the\r
+lines that control the mux, so all of the switches turn on. This shorts\r
+the four opamp outputs together through the on-resistance of the switch.\r
+All four outputs float to the same DC voltage with no signal, however,\r
+and the on-resistance of the switches is fairly large, so I don't think\r
+that will be a problem in practice.\r
+\r
+Comparators are used to generate clock signals when the device is\r
+emulating a tag. These clock signals are generated from the signal on the\r
+antenna, and therefore from the signal transmitted by the reader. This\r
+allows us to clock ourselves off the reader, just like a real tag would.\r
+These signals go in to the FPGA. There is a potential problem when the\r
+FPGA is powered down; these outputs might go high and try to power the\r
+FPGA through the protection diodes. My present solution to this is a\r
+couple of resistors, which is not very elegeant.\r
+\r
+The high-frequency peak-detected receive path contains population options\r
+for many features that I do not currently use. A lot of these are just\r
+me guessing that if I provide options for different series and shunt\r
+passives, perhaps it will come in handy in some way. The Zener diodes D10\r
+and D11 are optional, but may protect the front end from an overvoltage\r
+(which will fry the peak detector diodes) when the `simulated tag'\r
+is read by a powerful reader.\r
+\r
+DETAILS: ANALOG TRANSMIT PATH\r
+=============================\r
+\r
+The coil drivers are just ACT244 bus buffers. I parallel eight of them\r
+for each antenna (eight for the high-frequency antenna, eight for the\r
+low-frequency antenna). This should easily provide a hundred milliamps\r
+coil drive or so, which is more than enough for anything that I imagine\r
+doing with the device. The drivers hit the coil with a square wave\r
+voltage, however, which means that it is only the bandpass filter effect\r
+of a resonant antenna that suppresses the odd harmonics. In practice it\r
+would probably take heroic efforts (high antenna Q) to meet the FCC/CE\r
+harmonic specs; and in practice no one cares.\r
+\r
+The tx strength, given good antenna tuning, is determined by the series\r
+resistors. Choose the ratios to stay within the rated current of the\r
+buffers, and to achieve the desired power ratios by enabling or disabling\r
+nOEs for the desired modulation index. It is useful to populate one of the\r
+resistors as a high value (~10k) for the simulated tag modes; this allows\r
+us to look at the incident carrier without loading the reader very much.\r
+\r
+DETAILS: ARM\r
+============\r
+\r
+Atmel makes a number of pin-compatible ARMs, with slightly different\r
+peripherals, and different amounts of flash and RAM. It is necessary\r
+to choose a device with enough flash not just for the ARM's program,\r
+but also for the FPGA image (which is loaded by the ARM).\r
+\r
+The ARM is responsible for programming the FPGA. It also supplies a\r
+clock to the FPGA (although the FPGA clock can also run off the 13.56\r
+MHz clock not used for anything else, which is obviously asynchronous\r
+to anything in the ARM).\r
+\r
+It is necessary to use JTAG to bring the ARM for the first time; at\r
+that point you can load a bootrom, and subsequently load new software\r
+over USB. It might be possible to use the ARM's pre-loaded bootloader\r
+(see datasheet) instead of JTAG, but I wanted the JTAG anyways for\r
+debugging, so I did not bother. I used a Wiggler clone, with Macraigor's\r
+OCD Commander. More expensive tools would work as well.\r
+\r
+USB SOFTWARE\r
+============\r
+\r
+At present I enumerate as an HID device. This saves me writing a driver,\r
+but it forces me to do interrupt transfers for everything. This limits\r
+speed and is not very elegant. A real USB driver would be nice, maybe\r
+even one that could do stuff like going isochronous to stream samples\r
+from the A/D for processing on the PC.\r
+\r
+PRETENDING TO BE A TAG\r
+======================\r
+\r
+It is not possible, with the given topology, to open-circuit the antenna\r
+entirely and still look at the signal received on it. The simulated tag\r
+modes must therefore switch between slight loading and heavy loading,\r
+not open- and short-circuts across the antenna, evening though they do\r
+not depend upon the incident carrier for power (just timing information).\r
+\r
+RECEIVING SIGNAL STRAIGHT FROM THE ANTENNAS\r
+===========================================\r
+\r
+There is a path straight from the antenna to the A/D, bypassing the peak\r
+detector assembly. This goes through a gain stage (just a fast voltage\r
+feedback opamp), and from there straight in to the mux.\r
+\r
+It is necessary to energize the relay to connect these paths. If the\r
+coil is driven (as if to excite and read a tag) while these paths are\r
+connected, then damage will probably result. Most likely the opamp\r
+will fry.\r
+\r
+READING A TAG\r
+=============\r
+\r
+The tag is excited by a carrier transmitted by the reader. This is\r
+generated by IC9 and IC10, using some combination of buffers. The transmit\r
+power is determined by selecting the right combination of PWR_OEx pins;\r
+drive more of them low for more power. This can be used to modulate the\r
+transmitted signal, and thus send information to the tag.\r
+\r
+The received signal from the antenna is first peak-detected, and then\r
+high-pass filtered to reject the unmodulated carrier. The signal is\r
+amplified a bit, and goes in to the A/D mux from there. The A/D is\r
+controlled by the FPGA. For 13.56 MHz tags, it is easiest to do everything\r
+synchronous to the 13.56 MHz carrier.\r
+\r
+INTERFACE FROM THE ARM TO THE FPGA\r
+==================================\r
+\r
+The FPGA and the ARM can communicate in two main ways: using the ARM's\r
+general-purpose synchronous serial port (the SSP), or using the ARM's\r
+SPI port. The SPI port is used to configure the FPGA. The ARM writes a\r
+configuration word to the FPGA, which determines what operation will\r
+be performed (e.g. read 13.56 MHz vs. read 125 kHz vs. read 134 kHz\r
+vs...). The SPI is used exclusively for configuration.\r
+\r
+The SSP is used for actual data sent over the air. The ARM's SSP can\r
+work in slave mode, which means that we can send the data using clocks\r
+generated by the FPGA (either from the PCK0 clock, which the ARM itself\r
+supplies, or from the 13.56 MHz clock, which is certainly not going to\r
+be synchronous to anything in the ARM), which saves synchronizing logic\r
+in the FPGA. The SSP is bi-directional and full-duplex.\r
+\r
--- /dev/null
+;\r
+; Copyright Model Technology, a Mentor Graphics\r
+; Corporation company 2003, - All rights reserved.\r
+; \r
+[Library]\r
+std = $MODEL_TECH/../std\r
+ieee = $MODEL_TECH/../ieee\r
+verilog = $MODEL_TECH/../verilog\r
+vital2000 = $MODEL_TECH/../vital2000\r
+std_developerskit = $MODEL_TECH/../std_developerskit\r
+synopsys = $MODEL_TECH/../synopsys\r
+modelsim_lib = $MODEL_TECH/../modelsim_lib\r
+\r
+\r
+; VHDL Section\r
+unisim = $MODEL_TECH/../xilinx/vhdl/unisim\r
+simprim = $MODEL_TECH/../xilinx/vhdl/simprim\r
+xilinxcorelib = $MODEL_TECH/../xilinx/vhdl/xilinxcorelib\r
+aim = $MODEL_TECH/../xilinx/vhdl/aim\r
+pls = $MODEL_TECH/../xilinx/vhdl/pls\r
+cpld = $MODEL_TECH/../xilinx/vhdl/cpld\r
+\r
+; Verilog Section\r
+unisims_ver = $MODEL_TECH/../xilinx/verilog/unisims_ver\r
+uni9000_ver = $MODEL_TECH/../xilinx/verilog/uni9000_ver\r
+simprims_ver = $MODEL_TECH/../xilinx/verilog/simprims_ver\r
+xilinxcorelib_ver = $MODEL_TECH/../xilinx/verilog/xilinxcorelib_ver\r
+aim_ver = $MODEL_TECH/../xilinx/verilog/aim_ver\r
+cpld_ver = $MODEL_TECH/../xilinx/verilog/cpld_ver\r
+\r
+work = work
+[vcom]\r
+; Turn on VHDL-1993 as the default. Normally is off.\r
+VHDL93 = 1\r
+\r
+; Show source line containing error. Default is off.\r
+; Show_source = 1\r
+\r
+; Turn off unbound-component warnings. Default is on.\r
+; Show_Warning1 = 0\r
+\r
+; Turn off process-without-a-wait-statement warnings. Default is on.\r
+; Show_Warning2 = 0\r
+\r
+; Turn off null-range warnings. Default is on.\r
+; Show_Warning3 = 0\r
+\r
+; Turn off no-space-in-time-literal warnings. Default is on.\r
+; Show_Warning4 = 0\r
+\r
+; Turn off multiple-drivers-on-unresolved-signal warnings. Default is on.\r
+; Show_Warning5 = 0\r
+\r
+; Turn off optimization for IEEE std_logic_1164 package. Default is on.\r
+; Optimize_1164 = 0\r
+\r
+; Turn on resolving of ambiguous function overloading in favor of the\r
+; "explicit" function declaration (not the one automatically created by\r
+; the compiler for each type declaration). Default is off.\r
+ Explicit = 1\r
+\r
+; Turn off VITAL compliance checking. Default is checking on.\r
+; NoVitalCheck = 1\r
+\r
+; Ignore VITAL compliance checking errors. Default is to not ignore.\r
+; IgnoreVitalErrors = 1\r
+\r
+; Turn off VITAL compliance checking warnings. Default is to show warnings.\r
+; Show_VitalChecksWarnings = false\r
+\r
+; Turn off "loading..." messages. Default is messages on.\r
+; Quiet = 1\r
+\r
+; Turn on some limited synthesis rule compliance checking. Checks only:\r
+; -- signals used (read) by a process must be in the sensitivity list\r
+; CheckSynthesis = 1\r
+\r
+[vlog]\r
+\r
+; Turn off "loading..." messages. Default is messages on.\r
+; Quiet = 1\r
+\r
+; Turn on Verilog hazard checking (order-dependent accessing of global vars).\r
+; Default is off.\r
+; Hazard = 1\r
+\r
+; Turn on converting regular Verilog identifiers to uppercase. Allows case\r
+; insensitivity for module names. Default is no conversion.\r
+; UpCase = 1\r
+\r
+; Turns on incremental compilation of modules \r
+; Incremental = 1\r
+\r
+[vsim]\r
+; Simulator resolution\r
+; Set to fs, ps, ns, us, ms, or sec with optional prefix of 1, 10, or 100.\r
+Resolution = ps\r
+\r
+; User time unit for run commands\r
+; Set to default, fs, ps, ns, us, ms, or sec. The default is to use the\r
+; unit specified for Resolution. For example, if Resolution is 100ps,\r
+; then UserTimeUnit defaults to ps.\r
+UserTimeUnit = default\r
+\r
+; Default run length\r
+RunLength = 100\r
+\r
+; Maximum iterations that can be run without advancing simulation time\r
+IterationLimit = 5000\r
+\r
+; Directive to license manager:\r
+; vhdl Immediately reserve a VHDL license\r
+; vlog Immediately reserve a Verilog license\r
+; plus Immediately reserve a VHDL and Verilog license\r
+; nomgc Do not look for Mentor Graphics Licenses\r
+; nomti Do not look for Model Technology Licenses\r
+; noqueue Do not wait in the license queue when a license isn't available\r
+; License = plus\r
+\r
+; Stop the simulator after an assertion message\r
+; 0 = Note 1 = Warning 2 = Error 3 = Failure 4 = Fatal\r
+BreakOnAssertion = 3\r
+\r
+; Assertion Message Format\r
+; %S - Severity Level \r
+; %R - Report Message\r
+; %T - Time of assertion\r
+; %D - Delta\r
+; %I - Instance or Region pathname (if available)\r
+; %% - print '%' character\r
+; AssertionFormat = "** %S: %R\n Timf: %T Iteration: %D%I\n"\r
+\r
+; Assertion File - alternate file for storing assertion messages\r
+; AssertFile = assert.log\r
+\r
+; Default radix for all windows and commands...\r
+; Set to symbolic, ascii, binary, octal, decimal, hex, unsigned\r
+DefaultRadix = symbolic\r
+\r
+; VSIM Startup command\r
+; Startup = do startup.do\r
+\r
+; File for saving command transcript\r
+TranscriptFile = transcript\r
+\r
+; File for saving command history \r
+;CommandHistory = cmdhist.log\r
+\r
+; Specify whether paths in simulator commands should be described \r
+; in VHDL or Verilog format. For VHDL, PathSeparator = /\r
+; for Verilog, PathSeparator = .\r
+PathSeparator = /\r
+\r
+; Specify the dataset separator for fully rooted contexts.\r
+; The default is ':'. For example, sim:/top\r
+; Must not be the same character as PathSeparator.\r
+DatasetSeparator = :\r
+\r
+; Disable assertion messages\r
+; IgnoreNote = 1\r
+; IgnoreWarning = 1\r
+; IgnoreError = 1\r
+; IgnoreFailure = 1\r
+\r
+; Default force kind. May be freeze, drive, or deposit \r
+; or in other terms, fixed, wired or charged.\r
+; DefaultForceKind = freeze\r
+\r
+; If zero, open files when elaborated\r
+; else open files on first read or write\r
+; DelayFileOpen = 0\r
+\r
+; Control VHDL files opened for write\r
+; 0 = Buffered, 1 = Unbuffered\r
+UnbufferedOutput = 0\r
+\r
+; Control number of VHDL files open concurrently\r
+; This number should always be less then the \r
+; current ulimit setting for max file descriptors\r
+; 0 = unlimited\r
+ConcurrentFileLimit = 40\r
+\r
+; This controls the number of hierarchical regions displayed as\r
+; part of a signal name shown in the waveform window. The default\r
+; value or a value of zero tells VSIM to display the full name.\r
+; WaveSignalNameWidth = 0\r
+\r
+; Turn off warnings from the std_logic_arith, std_logic_unsigned\r
+; and std_logic_signed packages.\r
+; StdArithNoWarnings = 1\r
+\r
+; Turn off warnings from the IEEE numeric_std and numeric_bit\r
+; packages.\r
+; NumericStdNoWarnings = 1\r
+\r
+; Control the format of a generate statement label. Don't quote it.\r
+; GenerateFormat = %s__%d\r
+\r
+; Specify whether checkpoint files should be compressed.\r
+; The default is to be compressed.\r
+; CheckpointCompressMode = 0\r
+\r
+; List of dynamically loaded objects for Verilog PLI applications\r
+; Veriuser = veriuser.sl\r
+\r
+[lmc]\r
+[Project]
+Project_Version = 5
+Project_DefaultLib = work
+Project_SortMethod = unused
+Project_Files_Count = 13
+Project_File_0 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/fpga_tb.v
+Project_File_P_0 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1179836462 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 2 dont_compile 0
+Project_File_1 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/hi_simulate.v
+Project_File_P_1 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1225963633 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 compile_to work vlog_upper 0 vlog_options {} compile_order 6 dont_compile 0
+Project_File_2 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/testbed_hi_simulate.v
+Project_File_P_2 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1225964050 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 compile_to work vlog_upper 0 vlog_options {} compile_order 12 dont_compile 0
+Project_File_3 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/fpga.v
+Project_File_P_3 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1207888760 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 1 dont_compile 0
+Project_File_4 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/hi_read_tx.v
+Project_File_P_4 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1225960972 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 5 dont_compile 0
+Project_File_5 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/testbed_hi_read_tx.v
+Project_File_P_5 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1225962515 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 11 dont_compile 0
+Project_File_6 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/hi_iso14443a.v
+Project_File_P_6 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1207889732 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 3 dont_compile 0
+Project_File_7 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/lo_simulate.v
+Project_File_P_7 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1179836462 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 8 dont_compile 0
+Project_File_8 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/lo_read.v
+Project_File_P_8 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1225797126 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 7 dont_compile 0
+Project_File_9 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/util.v
+Project_File_P_9 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1179836462 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 0 dont_compile 0
+Project_File_10 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/testbed_lo_read.v
+Project_File_P_10 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1225960239 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 9 dont_compile 0
+Project_File_11 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/testbed_lo_simulate.v
+Project_File_P_11 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1225960231 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 10 dont_compile 0
+Project_File_12 = G:/RFID/Hardware/Proxmark3/Sources/prox_work/fpga/hi_read_rx_xcorr.v
+Project_File_P_12 = vlog_protect 0 file_type Verilog group_id 0 vlog_1995compat 0 vlog_nodebug 0 folder {Top Level} vlog_noload 0 last_compile 1179836462 vlog_disableopt 0 vlog_hazard 0 vlog_showsource 0 ood 0 vlog_options {} vlog_upper 0 compile_to work compile_order 4 dont_compile 0
+Project_Sim_Count = 0
+Project_Folder_Count = 0
--- /dev/null
+# See the schematic for the pin assignment.\r
+\r
+NET "adc_d<0>" LOC = "P62" ; \r
+NET "adc_d<1>" LOC = "P60" ; \r
+NET "adc_d<2>" LOC = "P58" ; \r
+NET "adc_d<3>" LOC = "P57" ; \r
+NET "adc_d<4>" LOC = "P56" ; \r
+NET "adc_d<5>" LOC = "P55" ; \r
+NET "adc_d<6>" LOC = "P54" ; \r
+NET "adc_d<7>" LOC = "P53" ; \r
+#NET "cross_hi" LOC = "P88" ; \r
+#NET "miso" LOC = "P40" ; \r
+#PACE: Start of Constraints generated by PACE\r
+\r
+#PACE: Start of PACE I/O Pin Assignments\r
+NET "adc_clk" LOC = "P46" ; \r
+NET "adc_noe" LOC = "P47" ; \r
+NET "ck_1356meg" LOC = "P91" ; \r
+NET "ck_1356megb" LOC = "P93" ; \r
+NET "cross_lo" LOC = "P87" ; \r
+NET "dbg" LOC = "P22" ; \r
+NET "mosi" LOC = "P43" ; \r
+NET "ncs" LOC = "P44" ; \r
+NET "pck0" LOC = "P36" ; \r
+NET "pwr_hi" LOC = "P80" ; \r
+NET "pwr_lo" LOC = "P81" ; \r
+NET "pwr_oe1" LOC = "P82" ; \r
+NET "pwr_oe2" LOC = "P83" ; \r
+NET "pwr_oe3" LOC = "P84" ; \r
+NET "pwr_oe4" LOC = "P86" ; \r
+NET "spck" LOC = "P39" ; \r
+NET "ssp_clk" LOC = "P71" ; \r
+NET "ssp_din" LOC = "P32" ; \r
+NET "ssp_dout" LOC = "P34" ; \r
+NET "ssp_frame" LOC = "P31" ; \r
+\r
+#PACE: Start of PACE Area Constraints\r
+\r
+#PACE: Start of PACE Prohibit Constraints\r
+\r
+#PACE: End of Constraints generated by PACE\r
--- /dev/null
+//-----------------------------------------------------------------------------\r
+// The FPGA is responsible for interfacing between the A/D, the coil drivers,\r
+// and the ARM. In the low-frequency modes it passes the data straight\r
+// through, so that the ARM gets raw A/D samples over the SSP. In the high-\r
+// frequency modes, the FPGA might perform some demodulation first, to\r
+// reduce the amount of data that we must send to the ARM.\r
+//\r
+// I am not really an FPGA/ASIC designer, so I am sure that a lot of this\r
+// could be improved.\r
+//\r
+// Jonathan Westhues, March 2006\r
+// Added ISO14443-A support by Gerhard de Koning Gans, April 2008\r
+//-----------------------------------------------------------------------------\r
+\r
+`include "lo_read.v"\r
+`include "lo_simulate.v"\r
+`include "hi_read_tx.v"\r
+`include "hi_read_rx_xcorr.v"\r
+`include "hi_simulate.v"\r
+`include "hi_iso14443a.v"\r
+`include "util.v"\r
+\r
+module fpga(\r
+ spck, miso, mosi, ncs,\r
+ pck0i, ck_1356meg, ck_1356megb,\r
+ pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,\r
+ adc_d, adc_clk, adc_noe,\r
+ ssp_frame, ssp_din, ssp_dout, ssp_clk,\r
+ cross_hi, cross_lo,\r
+ dbg\r
+);\r
+ input spck, mosi, ncs;\r
+ output miso;\r
+ input pck0i, ck_1356meg, ck_1356megb;\r
+ output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;\r
+ input [7:0] adc_d;\r
+ output adc_clk, adc_noe;\r
+ input ssp_dout;\r
+ output ssp_frame, ssp_din, ssp_clk;\r
+ input cross_hi, cross_lo;\r
+ output dbg;\r
+\r
+ IBUFG #(.IOSTANDARD("DEFAULT") ) pck0b(\r
+ .O(pck0),\r
+ .I(pck0i)\r
+ );\r
+//assign pck0 = pck0i;\r
+//-----------------------------------------------------------------------------\r
+// The SPI receiver. This sets up the configuration word, which the rest of\r
+// the logic looks at to determine how to connect the A/D and the coil\r
+// drivers (i.e., which section gets it). Also assign some symbolic names\r
+// to the configuration bits, for use below.\r
+//-----------------------------------------------------------------------------\r
+\r
+reg [7:0] conf_word_shift;\r
+reg [7:0] conf_word;\r
+\r
+// We switch modes between transmitting to the 13.56 MHz tag and receiving\r
+// from it, which means that we must make sure that we can do so without\r
+// glitching, or else we will glitch the transmitted carrier.\r
+always @(posedge ncs)\r
+begin\r
+ conf_word <= conf_word_shift;\r
+end\r
+\r
+always @(posedge spck)\r
+begin\r
+ if(~ncs)\r
+ begin\r
+ conf_word_shift[7:1] <= conf_word_shift[6:0];\r
+ conf_word_shift[0] <= mosi;\r
+ end\r
+end\r
+\r
+wire [2:0] major_mode;\r
+assign major_mode = conf_word[7:5];\r
+\r
+// For the low-frequency configuration:\r
+wire lo_is_125khz;\r
+assign lo_is_125khz = conf_word[3];\r
+\r
+// For the high-frequency transmit configuration: modulation depth, either\r
+// 100% (just quite driving antenna, steady LOW), or shallower (tri-state\r
+// some fraction of the buffers)\r
+wire hi_read_tx_shallow_modulation;\r
+assign hi_read_tx_shallow_modulation = conf_word[0];\r
+\r
+// For the high-frequency receive correlator: frequency against which to\r
+// correlate.\r
+wire hi_read_rx_xcorr_848;\r
+assign hi_read_rx_xcorr_848 = conf_word[0];\r
+// and whether to drive the coil (reader) or just short it (snooper)\r
+wire hi_read_rx_xcorr_snoop;\r
+assign hi_read_rx_xcorr_snoop = conf_word[1];\r
+\r
+// For the high-frequency simulated tag: what kind of modulation to use.\r
+wire [2:0] hi_simulate_mod_type;\r
+assign hi_simulate_mod_type = conf_word[2:0];\r
+\r
+//-----------------------------------------------------------------------------\r
+// And then we instantiate the modules corresponding to each of the FPGA's\r
+// major modes, and use muxes to connect the outputs of the active mode to\r
+// the output pins.\r
+//-----------------------------------------------------------------------------\r
+\r
+lo_read lr(\r
+ pck0, ck_1356meg, ck_1356megb,\r
+ lr_pwr_lo, lr_pwr_hi, lr_pwr_oe1, lr_pwr_oe2, lr_pwr_oe3, lr_pwr_oe4,\r
+ adc_d, lr_adc_clk,\r
+ lr_ssp_frame, lr_ssp_din, ssp_dout, lr_ssp_clk,\r
+ cross_hi, cross_lo,\r
+ lr_dbg,\r
+ lo_is_125khz\r
+);\r
+\r
+lo_simulate ls(\r
+ pck0, ck_1356meg, ck_1356megb,\r
+ ls_pwr_lo, ls_pwr_hi, ls_pwr_oe1, ls_pwr_oe2, ls_pwr_oe3, ls_pwr_oe4,\r
+ adc_d, ls_adc_clk,\r
+ ls_ssp_frame, ls_ssp_din, ssp_dout, ls_ssp_clk,\r
+ cross_hi, cross_lo,\r
+ ls_dbg\r
+);\r
+\r
+hi_read_tx ht(\r
+ pck0, ck_1356meg, ck_1356megb,\r
+ ht_pwr_lo, ht_pwr_hi, ht_pwr_oe1, ht_pwr_oe2, ht_pwr_oe3, ht_pwr_oe4,\r
+ adc_d, ht_adc_clk,\r
+ ht_ssp_frame, ht_ssp_din, ssp_dout, ht_ssp_clk,\r
+ cross_hi, cross_lo,\r
+ ht_dbg,\r
+ hi_read_tx_shallow_modulation\r
+);\r
+\r
+hi_read_rx_xcorr hrxc(\r
+ pck0, ck_1356meg, ck_1356megb,\r
+ hrxc_pwr_lo, hrxc_pwr_hi, hrxc_pwr_oe1, hrxc_pwr_oe2, hrxc_pwr_oe3, hrxc_pwr_oe4,\r
+ adc_d, hrxc_adc_clk,\r
+ hrxc_ssp_frame, hrxc_ssp_din, ssp_dout, hrxc_ssp_clk,\r
+ cross_hi, cross_lo,\r
+ hrxc_dbg,\r
+ hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop\r
+);\r
+\r
+hi_simulate hs(\r
+ pck0, ck_1356meg, ck_1356megb,\r
+ hs_pwr_lo, hs_pwr_hi, hs_pwr_oe1, hs_pwr_oe2, hs_pwr_oe3, hs_pwr_oe4,\r
+ adc_d, hs_adc_clk,\r
+ hs_ssp_frame, hs_ssp_din, ssp_dout, hs_ssp_clk,\r
+ cross_hi, cross_lo,\r
+ hs_dbg,\r
+ hi_simulate_mod_type\r
+);\r
+\r
+hi_iso14443a hisn(\r
+ pck0, ck_1356meg, ck_1356megb,\r
+ hisn_pwr_lo, hisn_pwr_hi, hisn_pwr_oe1, hisn_pwr_oe2, hisn_pwr_oe3, hisn_pwr_oe4,\r
+ adc_d, hisn_adc_clk,\r
+ hisn_ssp_frame, hisn_ssp_din, ssp_dout, hisn_ssp_clk,\r
+ cross_hi, cross_lo,\r
+ hisn_dbg,\r
+ hi_simulate_mod_type\r
+);\r
+\r
+// Major modes:\r
+// 000 -- LF reader (generic)\r
+// 001 -- LF simulated tag (generic)\r
+// 010 -- HF reader, transmitting to tag; modulation depth selectable\r
+// 011 -- HF reader, receiving from tag, correlating as it goes; frequency selectable\r
+// 100 -- HF simulated tag\r
+// 101 -- HF ISO14443-A\r
+// 110 -- unused\r
+// 111 -- everything off\r
+\r
+mux8 mux_ssp_clk (major_mode, ssp_clk, lr_ssp_clk, ls_ssp_clk, ht_ssp_clk, hrxc_ssp_clk, hs_ssp_clk, hisn_ssp_clk, 1'b0, 1'b0);\r
+mux8 mux_ssp_din (major_mode, ssp_din, lr_ssp_din, ls_ssp_din, ht_ssp_din, hrxc_ssp_din, hs_ssp_din, hisn_ssp_din, 1'b0, 1'b0);\r
+mux8 mux_ssp_frame (major_mode, ssp_frame, lr_ssp_frame, ls_ssp_frame, ht_ssp_frame, hrxc_ssp_frame, hs_ssp_frame, hisn_ssp_frame, 1'b0, 1'b0);\r
+mux8 mux_pwr_oe1 (major_mode, pwr_oe1, lr_pwr_oe1, ls_pwr_oe1, ht_pwr_oe1, hrxc_pwr_oe1, hs_pwr_oe1, hisn_pwr_oe1, 1'b0, 1'b0);\r
+mux8 mux_pwr_oe2 (major_mode, pwr_oe2, lr_pwr_oe2, ls_pwr_oe2, ht_pwr_oe2, hrxc_pwr_oe2, hs_pwr_oe2, hisn_pwr_oe2, 1'b0, 1'b0);\r
+mux8 mux_pwr_oe3 (major_mode, pwr_oe3, lr_pwr_oe3, ls_pwr_oe3, ht_pwr_oe3, hrxc_pwr_oe3, hs_pwr_oe3, hisn_pwr_oe3, 1'b0, 1'b0);\r
+mux8 mux_pwr_oe4 (major_mode, pwr_oe4, lr_pwr_oe4, ls_pwr_oe4, ht_pwr_oe4, hrxc_pwr_oe4, hs_pwr_oe4, hisn_pwr_oe4, 1'b0, 1'b0);\r
+mux8 mux_pwr_lo (major_mode, pwr_lo, lr_pwr_lo, ls_pwr_lo, ht_pwr_lo, hrxc_pwr_lo, hs_pwr_lo, hisn_pwr_lo, 1'b0, 1'b0);\r
+mux8 mux_pwr_hi (major_mode, pwr_hi, lr_pwr_hi, ls_pwr_hi, ht_pwr_hi, hrxc_pwr_hi, hs_pwr_hi, hisn_pwr_hi, 1'b0, 1'b0);\r
+mux8 mux_adc_clk (major_mode, adc_clk, lr_adc_clk, ls_adc_clk, ht_adc_clk, hrxc_adc_clk, hs_adc_clk, hisn_adc_clk, 1'b0, 1'b0);\r
+mux8 mux_dbg (major_mode, dbg, lr_dbg, ls_dbg, ht_dbg, hrxc_dbg, hs_dbg, hisn_dbg, 1'b0, 1'b0);\r
+\r
+// In all modes, let the ADC's outputs be enabled.\r
+assign adc_noe = 1'b0;\r
+\r
+endmodule\r
--- /dev/null
+@echo off\r
+\r
+rmdir/s/q xst\r
+\r
+del fpga.ngc\r
+xst -ifn xst.scr\r
+if errorlevel 0 goto ok1\r
+goto done\r
+:ok1\r
+\r
+del fpga.ngd\r
+ngdbuild -aul -p xc2s30-6vq100 -nt timestamp -uc fpga.ucf fpga.ngc fpga.ngd\r
+if errorlevel 0 goto ok2\r
+goto done\r
+:ok2\r
+\r
+del fpga.ncd\r
+map -p xc2s30-6vq100 fpga.ngd\r
+if errorlevel 0 goto ok3\r
+goto done\r
+:ok3\r
+\r
+del fpga-placed.ncd\r
+par fpga.ncd fpga-placed.ncd\r
+if errorlevel 0 goto ok4\r
+goto done\r
+:ok4\r
+\r
+del fpga.bit fpga.drc fpga.rbt\r
+bitgen -b fpga-placed.ncd fpga.bit\r
+if errorlevel 0 goto ok5\r
+goto done\r
+:ok5\r
+\r
+echo okay\r
+perl ..\tools\rbt2c.pl fpga.rbt > ..\armsrc\fpgaimg.c\r
+\r
+:done\r
--- /dev/null
+//-----------------------------------------------------------------------------
+// ISO14443-A support for the Proxmark III
+// Gerhard de Koning Gans, April 2008
+//-----------------------------------------------------------------------------
+
+module hi_iso14443a(
+ pck0, ck_1356meg, ck_1356megb,
+ pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
+ adc_d, adc_clk,
+ ssp_frame, ssp_din, ssp_dout, ssp_clk,
+ cross_hi, cross_lo,
+ dbg,
+ mod_type
+);
+ input pck0, ck_1356meg, ck_1356megb;
+ output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;
+ input [7:0] adc_d;
+ output adc_clk;
+ input ssp_dout;
+ output ssp_frame, ssp_din, ssp_clk;
+ input cross_hi, cross_lo;
+ output dbg;
+ input [2:0] mod_type;
+
+reg ssp_clk;
+reg ssp_frame;
+
+reg fc_div_2;
+always @(posedge ck_1356meg)
+ fc_div_2 = ~fc_div_2;
+
+wire adc_clk;
+assign adc_clk = ck_1356meg;
+
+reg after_hysteresis, after_hysteresis_prev1, after_hysteresis_prev2, after_hysteresis_prev3;
+reg [11:0] has_been_low_for;
+reg [8:0] saw_deep_modulation;
+reg [2:0] deep_counter;
+reg deep_modulation;
+always @(negedge adc_clk)
+begin
+ if(& adc_d[7:6]) after_hysteresis <= 1'b1;
+ else if(~(| adc_d[7:4])) after_hysteresis <= 1'b0;
+
+ if(~(| adc_d[7:0]))
+ begin
+ if(deep_counter == 3'd7)
+ begin
+ deep_modulation <= 1'b1;
+ saw_deep_modulation <= 8'd0;
+ end
+ else
+ deep_counter <= deep_counter + 1;
+ end
+ else
+ begin
+ deep_counter <= 3'd0;
+ if(saw_deep_modulation == 8'd255)
+ deep_modulation <= 1'b0;
+ else
+ saw_deep_modulation <= saw_deep_modulation + 1;
+ end
+
+ if(after_hysteresis)
+ begin
+ has_been_low_for <= 7'b0;
+ end
+ else
+ begin
+ if(has_been_low_for == 12'd4095)
+ begin
+ has_been_low_for <= 12'd0;
+ after_hysteresis <= 1'b1;
+ end
+ else
+ has_been_low_for <= has_been_low_for + 1;
+ end
+end
+
+// Report every 4 subcarrier cycles
+// 64 periods of carrier frequency => 6-bit counter [negedge_cnt]
+reg [5:0] negedge_cnt;
+reg bit1, bit2, bit3;
+reg [3:0] count_ones;
+reg [3:0] count_zeros;
+wire [7:0] avg;
+reg [7:0] lavg;
+reg signed [12:0] step1;
+reg signed [12:0] step2;
+reg [7:0] stepsize;
+reg curbit;
+reg [12:0] average;
+wire signed [9:0] dif;
+
+// A register to send the results to the arm
+reg signed [7:0] to_arm;
+
+assign avg[7:0] = average[11:4];
+assign dif = lavg - avg;
+
+reg bit_to_arm;
+reg fdt_indicator, fdt_elapsed;
+reg [10:0] fdt_counter;
+reg [47:0] mod_sig_buf;
+wire mod_sig_buf_empty;
+reg [5:0] mod_sig_ptr;
+reg [3:0] mod_sig_flip;
+reg mod_sig, mod_sig_coil;
+reg temp_buffer_reset;
+reg sendbit;
+
+assign mod_sig_buf_empty = ~(|mod_sig_buf[47:0]);
+reg [2:0] ssp_frame_counter;
+
+// ADC data appears on the rising edge, so sample it on the falling edge
+always @(negedge adc_clk)
+begin
+
+ // last bit = 0 then fdt = 1172, in case of 0x26 (7-bit command, LSB first!)
+ // last bit = 1 then fdt = 1236, in case of 0x52 (7-bit command, LSB first!)
+ if(fdt_counter == 11'd740) fdt_indicator = 1'b1;
+
+ if(fdt_counter == 11'd1148)
+ begin
+ if(fdt_elapsed)
+ begin
+ if(negedge_cnt[3:0] == mod_sig_flip[3:0]) mod_sig_coil <= mod_sig;
+ end
+ else
+ begin
+ mod_sig_flip[3:0] <= negedge_cnt[3:0];
+ mod_sig_coil <= mod_sig;
+ fdt_elapsed = 1'b1;
+ fdt_indicator = 1'b0;
+
+ if(~(| mod_sig_ptr[5:0])) mod_sig_ptr <= 6'b001001;
+ else temp_buffer_reset = 1'b1; // fix position of the buffer pointer
+ end
+ end
+ else
+ begin
+ fdt_counter <= fdt_counter + 1;
+ end
+
+ if(& negedge_cnt[3:0])
+ begin
+ // When there is a dip in the signal and not in reader mode
+ if(~after_hysteresis && mod_sig_buf_empty && ~((mod_type == 3'b100) || (mod_type == 3'b011) || (mod_type == 3'b010))) // last condition to prevent reset
+ begin
+ fdt_counter <= 11'd0;
+ fdt_elapsed = 1'b0;
+ fdt_indicator = 1'b0;
+ temp_buffer_reset = 1'b0;
+ mod_sig_ptr <= 6'b000000;
+ end
+
+ lavg <= avg;
+
+ if(stepsize<16) stepsize = 8'd16;
+
+ if(dif>0)
+ begin
+ step1 = dif*3;
+ step2 = stepsize*2; // 3:2
+ if(step1>step2)
+ begin
+ curbit = 1'b0;
+ stepsize = dif;
+ end
+ end
+ else
+ begin
+ step1 = dif*3;
+ step1 = -step1;
+ step2 = stepsize*2;
+ if(step1>step2)
+ begin
+ curbit = 1'b1;
+ stepsize = -dif;
+ end
+ end
+
+ if(curbit)
+ begin
+ count_zeros <= 4'd0;
+ if(& count_ones[3:2])
+ begin
+ curbit = 1'b0; // suppressed signal
+ stepsize = 8'd24; // just a fine number
+ end
+ else
+ begin
+ count_ones <= count_ones + 1;
+ end
+ end
+ else
+ begin
+ count_ones <= 4'd0;
+ if(& count_zeros[3:0])
+ begin
+ stepsize = 8'd24;
+ end
+ else
+ begin
+ count_zeros <= count_zeros + 1;
+ end
+ end
+
+ // What do we communicate to the ARM
+ if(mod_type == 3'b001) sendbit = after_hysteresis;
+ else if(mod_type == 3'b010)
+ begin
+ if(fdt_counter > 11'd772) sendbit = mod_sig_coil;
+ else sendbit = fdt_indicator;
+ end
+ else if(mod_type == 3'b011) sendbit = curbit;
+ else sendbit = 1'b0;
+
+ end
+
+ if(~(| negedge_cnt[3:0])) average <= adc_d;
+ else average <= average + adc_d;
+
+ if(negedge_cnt == 7'd63)
+ begin
+ if(deep_modulation)
+ begin
+ to_arm <= {after_hysteresis_prev1,after_hysteresis_prev2,after_hysteresis_prev3,after_hysteresis,1'b0,1'b0,1'b0,1'b0};
+ end
+ else
+ begin
+ to_arm <= {after_hysteresis_prev1,after_hysteresis_prev2,after_hysteresis_prev3,after_hysteresis,bit1,bit2,bit3,curbit};
+ end
+
+ negedge_cnt <= 0;
+
+ end
+ else
+ begin
+ negedge_cnt <= negedge_cnt + 1;
+ end
+
+ if(negedge_cnt == 6'd15)
+ begin
+ after_hysteresis_prev1 <= after_hysteresis;
+ bit1 <= curbit;
+ end
+ if(negedge_cnt == 6'd31)
+ begin
+ after_hysteresis_prev2 <= after_hysteresis;
+ bit2 <= curbit;
+ end
+ if(negedge_cnt == 6'd47)
+ begin
+ after_hysteresis_prev3 <= after_hysteresis;
+ bit3 <= curbit;
+ end
+
+
+ if(mod_type != 3'b000)
+ begin
+ if(negedge_cnt[3:0] == 4'b1000)
+ begin
+ // The modulation signal of the tag
+ mod_sig_buf[47:0] <= {mod_sig_buf[46:1], ssp_dout, 1'b0};
+ if((ssp_dout || (| mod_sig_ptr[5:0])) && ~fdt_elapsed)
+ if(mod_sig_ptr == 6'b101110)
+ begin
+ mod_sig_ptr <= 6'b000000;
+ end
+ else mod_sig_ptr <= mod_sig_ptr + 1;
+ else if(fdt_elapsed && ~temp_buffer_reset)
+ begin
+ if(ssp_dout) temp_buffer_reset = 1'b1;
+ if(mod_sig_ptr == 6'b000010) mod_sig_ptr <= 6'b001001;
+ else mod_sig_ptr <= mod_sig_ptr - 1;
+ end
+ else
+ begin
+ // side effect: when ptr = 1 it will cancel the first 1 of every block of ones
+ if(~mod_sig_buf[mod_sig_ptr-1] && ~mod_sig_buf[mod_sig_ptr+1]) mod_sig = 1'b0;
+ else mod_sig = mod_sig_buf[mod_sig_ptr] & fdt_elapsed; // & fdt_elapsed was for direct relay to oe4
+ end
+ end
+ end
+
+ // SSP Clock and data
+ if(mod_type == 3'b000)
+ begin
+ if(negedge_cnt[2:0] == 3'b100)
+ ssp_clk <= 1'b0;
+
+ if(negedge_cnt[2:0] == 3'b000)
+ begin
+ ssp_clk <= 1'b1;
+ // Don't shift if we just loaded new data, obviously.
+ if(negedge_cnt != 7'd0)
+ begin
+ to_arm[7:1] <= to_arm[6:0];
+ end
+ end
+
+ if(negedge_cnt[5:4] == 2'b00)
+ ssp_frame = 1'b1;
+ else
+ ssp_frame = 1'b0;
+
+ bit_to_arm = to_arm[7];
+ end
+ else
+ begin
+ if(negedge_cnt[3:0] == 4'b1000) ssp_clk <= 1'b0;
+
+ if(negedge_cnt[3:0] == 4'b0111)
+ begin
+ if(ssp_frame_counter == 3'd7) ssp_frame_counter <= 3'd0;
+ else ssp_frame_counter <= ssp_frame_counter + 1;
+ end
+
+ if(negedge_cnt[3:0] == 4'b0000)
+ begin
+ ssp_clk <= 1'b1;
+ end
+
+ ssp_frame = (ssp_frame_counter == 3'd7);
+
+ bit_to_arm = sendbit;
+ end
+
+end
+
+assign ssp_din = bit_to_arm;
+
+// Modulating carrier frequency is fc/16
+wire modulating_carrier;
+assign modulating_carrier = (mod_sig_coil & negedge_cnt[3] & (mod_type == 3'b010));
+assign pwr_hi = (ck_1356megb & (((mod_type == 3'b100) & ~mod_sig_coil) || (mod_type == 3'b011)));
+
+// This one is all LF, so doesn't matter
+//assign pwr_oe2 = modulating_carrier;
+assign pwr_oe2 = 1'b0;
+
+// Toggle only one of these, since we are already producing much deeper
+// modulation than a real tag would.
+//assign pwr_oe1 = modulating_carrier;
+assign pwr_oe1 = 1'b0;
+assign pwr_oe4 = modulating_carrier;
+//assign pwr_oe4 = 1'b0;
+
+// This one is always on, so that we can watch the carrier.
+//assign pwr_oe3 = modulating_carrier;
+assign pwr_oe3 = 1'b0;
+
+
+assign dbg = negedge_cnt[3];
+
+// Unused.
+assign pwr_lo = 1'b0;
+
+endmodule
--- /dev/null
+//-----------------------------------------------------------------------------\r
+//\r
+// Jonathan Westhues, April 2006\r
+//-----------------------------------------------------------------------------\r
+\r
+module hi_read_rx_xcorr(\r
+ pck0, ck_1356meg, ck_1356megb,\r
+ pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,\r
+ adc_d, adc_clk,\r
+ ssp_frame, ssp_din, ssp_dout, ssp_clk,\r
+ cross_hi, cross_lo,\r
+ dbg,\r
+ xcorr_is_848, snoop\r
+);\r
+ input pck0, ck_1356meg, ck_1356megb;\r
+ output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;\r
+ input [7:0] adc_d;\r
+ output adc_clk;\r
+ input ssp_dout;\r
+ output ssp_frame, ssp_din, ssp_clk;\r
+ input cross_hi, cross_lo;\r
+ output dbg;\r
+ input xcorr_is_848, snoop;\r
+\r
+// Carrier is steady on through this, unless we're snooping.\r
+assign pwr_hi = ck_1356megb & (~snoop);\r
+assign pwr_oe1 = 1'b0;\r
+assign pwr_oe2 = 1'b0;\r
+assign pwr_oe3 = 1'b0;\r
+assign pwr_oe4 = 1'b0;\r
+\r
+reg ssp_clk;\r
+reg ssp_frame;\r
+\r
+reg fc_div_2;\r
+always @(posedge ck_1356meg)\r
+ fc_div_2 = ~fc_div_2;\r
+\r
+reg adc_clk;\r
+\r
+always @(xcorr_is_848 or fc_div_2 or ck_1356meg)\r
+ if(xcorr_is_848)\r
+ // The subcarrier frequency is fc/16; we will sample at fc, so that \r
+ // means the subcarrier is 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 ...\r
+ adc_clk <= ck_1356meg;\r
+ else\r
+ // The subcarrier frequency is fc/32; we will sample at fc/2, and\r
+ // the subcarrier will look identical.\r
+ adc_clk <= fc_div_2;\r
+\r
+// When we're a reader, we just need to do the BPSK demod; but when we're an\r
+// eavesdropper, we also need to pick out the commands sent by the reader,\r
+// using AM. Do this the same way that we do it for the simulated tag.\r
+reg after_hysteresis, after_hysteresis_prev;\r
+reg [11:0] has_been_low_for;\r
+always @(negedge adc_clk)\r
+begin\r
+ if(& adc_d[7:0]) after_hysteresis <= 1'b1;\r
+ else if(~(| adc_d[7:0])) after_hysteresis <= 1'b0;\r
+\r
+ if(after_hysteresis)\r
+ begin\r
+ has_been_low_for <= 7'b0;\r
+ end\r
+ else\r
+ begin\r
+ if(has_been_low_for == 12'd4095)\r
+ begin\r
+ has_been_low_for <= 12'd0;\r
+ after_hysteresis <= 1'b1;\r
+ end\r
+ else\r
+ has_been_low_for <= has_been_low_for + 1;\r
+ end\r
+end\r
+\r
+// Let us report a correlation every 4 subcarrier cycles, or 4*16 samples,\r
+// so we need a 6-bit counter.\r
+reg [5:0] corr_i_cnt;\r
+reg [5:0] corr_q_cnt;\r
+// And a couple of registers in which to accumulate the correlations.\r
+reg signed [15:0] corr_i_accum;\r
+reg signed [15:0] corr_q_accum;\r
+reg signed [7:0] corr_i_out;\r
+reg signed [7:0] corr_q_out;\r
+\r
+// ADC data appears on the rising edge, so sample it on the falling edge\r
+always @(negedge adc_clk)\r
+begin\r
+ // These are the correlators: we correlate against in-phase and quadrature\r
+ // versions of our reference signal, and keep the (signed) result to\r
+ // send out later over the SSP.\r
+ if(corr_i_cnt == 7'd63)\r
+ begin\r
+ if(snoop)\r
+ begin\r
+ corr_i_out <= {corr_i_accum[12:6], after_hysteresis_prev};\r
+ corr_q_out <= {corr_q_accum[12:6], after_hysteresis};\r
+ end\r
+ else\r
+ begin\r
+ // Only correlations need to be delivered.\r
+ corr_i_out <= corr_i_accum[13:6];\r
+ corr_q_out <= corr_q_accum[13:6];\r
+ end\r
+\r
+ corr_i_accum <= adc_d;\r
+ corr_q_accum <= adc_d;\r
+ corr_q_cnt <= 4;\r
+ corr_i_cnt <= 0;\r
+ end\r
+ else\r
+ begin\r
+ if(corr_i_cnt[3])\r
+ corr_i_accum <= corr_i_accum - adc_d;\r
+ else\r
+ corr_i_accum <= corr_i_accum + adc_d;\r
+\r
+ if(corr_q_cnt[3])\r
+ corr_q_accum <= corr_q_accum - adc_d;\r
+ else\r
+ corr_q_accum <= corr_q_accum + adc_d;\r
+\r
+ corr_i_cnt <= corr_i_cnt + 1;\r
+ corr_q_cnt <= corr_q_cnt + 1;\r
+ end\r
+\r
+ // The logic in hi_simulate.v reports 4 samples per bit. We report two\r
+ // (I, Q) pairs per bit, so we should do 2 samples per pair.\r
+ if(corr_i_cnt == 6'd31)\r
+ after_hysteresis_prev <= after_hysteresis;\r
+\r
+ // Then the result from last time is serialized and send out to the ARM.\r
+ // We get one report each cycle, and each report is 16 bits, so the\r
+ // ssp_clk should be the adc_clk divided by 64/16 = 4.\r
+\r
+ if(corr_i_cnt[1:0] == 2'b10)\r
+ ssp_clk <= 1'b0;\r
+\r
+ if(corr_i_cnt[1:0] == 2'b00)\r
+ begin\r
+ ssp_clk <= 1'b1;\r
+ // Don't shift if we just loaded new data, obviously.\r
+ if(corr_i_cnt != 7'd0)\r
+ begin\r
+ corr_i_out[7:0] <= {corr_i_out[6:0], corr_q_out[7]};\r
+ corr_q_out[7:1] <= corr_q_out[6:0];\r
+ end\r
+ end\r
+\r
+ if(corr_i_cnt[5:2] == 4'b000 || corr_i_cnt[5:2] == 4'b1000)\r
+ ssp_frame = 1'b1;\r
+ else\r
+ ssp_frame = 1'b0;\r
+\r
+end\r
+\r
+assign ssp_din = corr_i_out[7];\r
+\r
+assign dbg = corr_i_cnt[3];\r
+\r
+// Unused.\r
+assign pwr_lo = 1'b0;\r
+\r
+endmodule\r
--- /dev/null
+//-----------------------------------------------------------------------------\r
+// The way that we connect things when transmitting a command to an ISO\r
+// 15693 tag, using 100% modulation only for now.\r
+//\r
+// Jonathan Westhues, April 2006\r
+//-----------------------------------------------------------------------------\r
+\r
+module hi_read_tx(\r
+ pck0, ck_1356meg, ck_1356megb,\r
+ pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,\r
+ adc_d, adc_clk,\r
+ ssp_frame, ssp_din, ssp_dout, ssp_clk,\r
+ cross_hi, cross_lo,\r
+ dbg,\r
+ shallow_modulation\r
+);\r
+ input pck0, ck_1356meg, ck_1356megb;\r
+ output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;\r
+ input [7:0] adc_d;\r
+ output adc_clk;\r
+ input ssp_dout;\r
+ output ssp_frame, ssp_din, ssp_clk;\r
+ input cross_hi, cross_lo;\r
+ output dbg;\r
+ input shallow_modulation;\r
+\r
+// The high-frequency stuff. For now, for testing, just bring out the carrier,\r
+// and allow the ARM to modulate it over the SSP.\r
+reg pwr_hi;\r
+reg pwr_oe1;\r
+reg pwr_oe2;\r
+reg pwr_oe3;\r
+reg pwr_oe4;\r
+always @(ck_1356megb or ssp_dout or shallow_modulation)\r
+begin\r
+ if(shallow_modulation)\r
+ begin\r
+ pwr_hi <= ck_1356megb;\r
+ pwr_oe1 <= ~ssp_dout;\r
+ pwr_oe2 <= ~ssp_dout;\r
+ pwr_oe3 <= ~ssp_dout;\r
+ pwr_oe4 <= 1'b0;\r
+ end\r
+ else\r
+ begin\r
+ pwr_hi <= ck_1356megb & ssp_dout;\r
+ pwr_oe1 <= 1'b0;\r
+ pwr_oe2 <= 1'b0;\r
+ pwr_oe3 <= 1'b0;\r
+ pwr_oe4 <= 1'b0;\r
+ end\r
+end\r
+\r
+// Then just divide the 13.56 MHz clock down to produce appropriate clocks\r
+// for the synchronous serial port.\r
+\r
+reg [6:0] hi_div_by_128;\r
+\r
+always @(posedge ck_1356meg)\r
+ hi_div_by_128 <= hi_div_by_128 + 1;\r
+\r
+assign ssp_clk = hi_div_by_128[6];\r
+\r
+reg [2:0] hi_byte_div;\r
+\r
+always @(negedge ssp_clk)\r
+ hi_byte_div <= hi_byte_div + 1;\r
+\r
+assign ssp_frame = (hi_byte_div == 3'b000);\r
+\r
+assign ssp_din = 1'b0;\r
+\r
+assign pwr_lo = 1'b0;\r
+assign dbg = ssp_frame;\r
+\r
+endmodule\r
--- /dev/null
+//-----------------------------------------------------------------------------\r
+// Pretend to be an ISO 14443 tag. We will do this by alternately short-\r
+// circuiting and open-circuiting the antenna coil, with the tri-state\r
+// pins. \r
+//\r
+// We communicate over the SSP, as a bitstream (i.e., might as well be\r
+// unframed, though we still generate the word sync signal). The output\r
+// (ARM -> FPGA) tells us whether to modulate or not. The input (FPGA\r
+// -> ARM) is us using the A/D as a fancy comparator; this is with\r
+// (software-added) hysteresis, to undo the high-pass filter.\r
+//\r
+// At this point only Type A is implemented. This means that we are using a\r
+// bit rate of 106 kbit/s, or fc/128. Oversample by 4, which ought to make\r
+// things practical for the ARM (fc/32, 423.8 kbits/s, ~50 kbytes/s)\r
+//\r
+// Jonathan Westhues, October 2006\r
+//-----------------------------------------------------------------------------\r
+\r
+module hi_simulate(\r
+ pck0, ck_1356meg, ck_1356megb,\r
+ pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,\r
+ adc_d, adc_clk,\r
+ ssp_frame, ssp_din, ssp_dout, ssp_clk,\r
+ cross_hi, cross_lo,\r
+ dbg,\r
+ mod_type\r
+);\r
+ input pck0, ck_1356meg, ck_1356megb;\r
+ output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;\r
+ input [7:0] adc_d;\r
+ output adc_clk;\r
+ input ssp_dout;\r
+ output ssp_frame, ssp_din, ssp_clk;\r
+ input cross_hi, cross_lo;\r
+ output dbg;\r
+ input [2:0] mod_type;\r
+\r
+// Power amp goes between LOW and tri-state, so pwr_hi (and pwr_lo) can\r
+// always be low.\r
+assign pwr_hi = 1'b0;\r
+assign pwr_lo = 1'b0;\r
+\r
+// The comparator with hysteresis on the output from the peak detector.\r
+reg after_hysteresis;\r
+assign adc_clk = ck_1356meg;\r
+\r
+always @(negedge adc_clk)\r
+begin\r
+ if(& adc_d[7:5]) after_hysteresis = 1'b1;\r
+ else if(~(| adc_d[7:5])) after_hysteresis = 1'b0;\r
+end\r
+\r
+// Divide 13.56 MHz by 32 to produce the SSP_CLK\r
+reg [4:0] ssp_clk_divider;\r
+always @(posedge adc_clk)\r
+ ssp_clk_divider <= (ssp_clk_divider + 1);\r
+assign ssp_clk = ssp_clk_divider[4];\r
+\r
+// Divide SSP_CLK by 8 to produce the byte framing signal; the phase of\r
+// this is arbitrary, because it's just a bitstream.\r
+// One nasty issue, though: I can't make it work with both rx and tx at\r
+// once. The phase wrt ssp_clk must be changed. TODO to find out why\r
+// that is and make a better fix.\r
+reg [2:0] ssp_frame_divider_to_arm;\r
+always @(posedge ssp_clk)\r
+ ssp_frame_divider_to_arm <= (ssp_frame_divider_to_arm + 1);\r
+reg [2:0] ssp_frame_divider_from_arm;\r
+always @(negedge ssp_clk)\r
+ ssp_frame_divider_from_arm <= (ssp_frame_divider_from_arm + 1);\r
+\r
+reg ssp_frame;\r
+always @(ssp_frame_divider_to_arm or ssp_frame_divider_from_arm or mod_type)\r
+ if(mod_type == 3'b000) // not modulating, so listening, to ARM\r
+ ssp_frame = (ssp_frame_divider_to_arm == 3'b000);\r
+ else\r
+ ssp_frame = (ssp_frame_divider_from_arm == 3'b000);\r
+\r
+// Synchronize up the after-hysteresis signal, to produce DIN.\r
+reg ssp_din;\r
+always @(posedge ssp_clk)\r
+ ssp_din = after_hysteresis;\r
+\r
+// Modulating carrier frequency is fc/16, reuse ssp_clk divider for that\r
+reg modulating_carrier;\r
+always @(mod_type or ssp_clk or ssp_dout)\r
+ if(mod_type == 3'b000)\r
+ modulating_carrier <= 1'b0; // no modulation\r
+ else if(mod_type == 3'b001)\r
+ modulating_carrier <= ssp_dout ^ ssp_clk_divider[3]; // XOR means BPSK\r
+ else\r
+ modulating_carrier <= 1'b0; // yet unused\r
+\r
+// This one is all LF, so doesn't matter\r
+assign pwr_oe2 = modulating_carrier;\r
+\r
+// Toggle only one of these, since we are already producing much deeper\r
+// modulation than a real tag would.\r
+assign pwr_oe1 = modulating_carrier;\r
+assign pwr_oe4 = modulating_carrier;\r
+\r
+// This one is always on, so that we can watch the carrier.\r
+assign pwr_oe3 = 1'b0;\r
+\r
+assign dbg = after_hysteresis;\r
+\r
+endmodule\r
--- /dev/null
+//-----------------------------------------------------------------------------\r
+// The way that we connect things in low-frequency read mode. In this case\r
+// we are generating the 134 kHz or 125 kHz carrier, and running the \r
+// unmodulated carrier at that frequency. The A/D samples at that same rate,\r
+// and the result is serialized.\r
+//\r
+// Jonathan Westhues, April 2006\r
+//-----------------------------------------------------------------------------\r
+\r
+module lo_read(\r
+ pck0, ck_1356meg, ck_1356megb,\r
+ pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,\r
+ adc_d, adc_clk,\r
+ ssp_frame, ssp_din, ssp_dout, ssp_clk,\r
+ cross_hi, cross_lo,\r
+ dbg,\r
+ lo_is_125khz\r
+);\r
+ input pck0, ck_1356meg, ck_1356megb;\r
+ output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;\r
+ input [7:0] adc_d;\r
+ output adc_clk;\r
+ input ssp_dout;\r
+ output ssp_frame, ssp_din, ssp_clk;\r
+ input cross_hi, cross_lo;\r
+ output dbg;\r
+ input lo_is_125khz;\r
+\r
+// The low-frequency RFID stuff. This is relatively simple, because most\r
+// of the work happens on the ARM, and we just pass samples through. The\r
+// PCK0 must be divided down to generate the A/D clock, and from there by\r
+// a factor of 8 to generate the carrier (that we apply to the coil drivers).\r
+//\r
+// This is also where we decode the received synchronous serial port words,\r
+// to determine how to drive the output enables.\r
+\r
+// PCK0 will run at (PLL clock) / 4, or 24 MHz. That means that we can do\r
+// 125 kHz by dividing by a further factor of (8*12*2), or ~134 kHz by\r
+// dividing by a factor of (8*11*2) (for 136 kHz, ~2% error, tolerable).\r
+\r
+reg [3:0] pck_divider;\r
+reg clk_lo;\r
+\r
+always @(posedge pck0)\r
+begin\r
+ if(lo_is_125khz)\r
+ begin\r
+ if(pck_divider == 4'd11)\r
+ begin\r
+ pck_divider <= 4'd0;\r
+ clk_lo = !clk_lo;\r
+ end\r
+ else\r
+ pck_divider <= pck_divider + 1;\r
+ end\r
+ else\r
+ begin\r
+ if(pck_divider == 4'd10)\r
+ begin\r
+ pck_divider <= 4'd0;\r
+ clk_lo = !clk_lo;\r
+ end\r
+ else\r
+ pck_divider <= pck_divider + 1;\r
+ end\r
+end\r
+\r
+reg [2:0] carrier_divider_lo;\r
+\r
+always @(posedge clk_lo)\r
+begin\r
+ carrier_divider_lo <= carrier_divider_lo + 1;\r
+end\r
+\r
+assign pwr_lo = carrier_divider_lo[2];\r
+\r
+// This serializes the values returned from the A/D, and sends them out\r
+// over the SSP.\r
+\r
+reg [7:0] to_arm_shiftreg;\r
+\r
+always @(posedge clk_lo)\r
+begin\r
+ if(carrier_divider_lo == 3'b000)\r
+ to_arm_shiftreg <= adc_d;\r
+ else\r
+ to_arm_shiftreg[7:1] <= to_arm_shiftreg[6:0];\r
+end\r
+\r
+assign ssp_clk = clk_lo;\r
+assign ssp_frame = (carrier_divider_lo == 3'b001);\r
+assign ssp_din = to_arm_shiftreg[7];\r
+\r
+// The ADC converts on the falling edge, and our serializer loads when\r
+// carrier_divider_lo == 3'b000.\r
+assign adc_clk = ~carrier_divider_lo[2];\r
+\r
+assign pwr_hi = 1'b0;\r
+\r
+assign dbg = adc_clk;\r
+\r
+endmodule\r
--- /dev/null
+//-----------------------------------------------------------------------------\r
+// The way that we connect things in low-frequency simulation mode. In this\r
+// case just pass everything through to the ARM, which can bit-bang this\r
+// (because it is so slow).\r
+//\r
+// Jonathan Westhues, April 2006\r
+//-----------------------------------------------------------------------------\r
+\r
+module lo_simulate(\r
+ pck0, ck_1356meg, ck_1356megb,\r
+ pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,\r
+ adc_d, adc_clk,\r
+ ssp_frame, ssp_din, ssp_dout, ssp_clk,\r
+ cross_hi, cross_lo,\r
+ dbg\r
+);\r
+ input pck0, ck_1356meg, ck_1356megb;\r
+ output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;\r
+ input [7:0] adc_d;\r
+ output adc_clk;\r
+ input ssp_dout;\r
+ output ssp_frame, ssp_din, ssp_clk;\r
+ input cross_hi, cross_lo;\r
+ output dbg;\r
+\r
+// No logic, straight through.\r
+assign pwr_oe3 = 1'b0;\r
+assign pwr_oe1 = ssp_dout;\r
+assign pwr_oe2 = ssp_dout;\r
+assign pwr_oe4 = ssp_dout;\r
+assign ssp_clk = cross_lo;\r
+assign pwr_lo = 1'b0;\r
+assign adc_clk = 1'b0;\r
+assign pwr_hi = 1'b0;\r
+assign dbg = cross_lo;\r
+\r
+endmodule\r
--- /dev/null
+#------------------------------------------------------------------------------\r
+# Run the simulation testbench in ModelSim: recompile both Verilog source\r
+# files, then start the simulation, add a lot of signals to the waveform\r
+# viewer, and run. I should (TODO) fix the absolute paths at some point.\r
+#\r
+# Jonathan Westhues, Mar 2006\r
+#------------------------------------------------------------------------------\r
+\r
+vlog -work work -O0 C:/depot/proximity/mark3/fpga/fpga.v\r
+vlog -work work -O0 C:/depot/proximity/mark3/fpga/fpga_tb.v\r
+\r
+vsim work.fpga_tb\r
+\r
+add wave sim:/fpga_tb/adc_clk\r
+add wave sim:/fpga_tb/adc_d\r
+add wave sim:/fpga_tb/pwr_lo\r
+add wave sim:/fpga_tb/ssp_clk\r
+add wave sim:/fpga_tb/ssp_frame\r
+add wave sim:/fpga_tb/ssp_din\r
+add wave sim:/fpga_tb/ssp_dout\r
+\r
+add wave sim:/fpga_tb/dut/clk_lo\r
+add wave sim:/fpga_tb/dut/pck_divider\r
+add wave sim:/fpga_tb/dut/carrier_divider_lo\r
+add wave sim:/fpga_tb/dut/conf_word\r
+\r
+run 30000\r
--- /dev/null
+`include "fpga.v"\r
+\r
+module testbed_fpga;\r
+ reg spck, mosi, ncs;\r
+ wire miso;\r
+ reg pck0i, ck_1356meg, ck_1356megb;\r
+ wire pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;\r
+ reg [7:0] adc_d;\r
+ wire adc_clk, adc_noe;\r
+ reg ssp_dout;\r
+ wire ssp_frame, ssp_din, ssp_clk;\r
+\r
+ fpga dut(\r
+ spck, miso, mosi, ncs,\r
+ pck0i, ck_1356meg, ck_1356megb,\r
+ pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,\r
+ adc_d, adc_clk, adc_noe,\r
+ ssp_frame, ssp_din, ssp_dout, ssp_clk\r
+ );\r
+\r
+ integer i;\r
+\r
+ initial begin\r
+\r
+ // init inputs\r
+ #5 ncs=1;\r
+ #5 spck = 1;\r
+ #5 mosi = 1;\r
+\r
+ #50 ncs=0;\r
+ for (i = 0 ; i < 8 ; i = i + 1) begin\r
+ #5 mosi = $random;\r
+ #5 spck = 0;\r
+ #5 spck = 1;\r
+ end\r
+ #5 ncs=1;\r
+\r
+ #50 ncs=0;\r
+ for (i = 0 ; i < 8 ; i = i + 1) begin\r
+ #5 mosi = $random;\r
+ #5 spck = 0;\r
+ #5 spck = 1;\r
+ end\r
+ #5 ncs=1;\r
+\r
+ #50 mosi=1;\r
+ $finish;\r
+ end\r
+ \r
+endmodule // main\r
--- /dev/null
+`include "hi_read_tx.v"\r
+\r
+/*\r
+ pck0 - input main 24Mhz clock (PLL / 4)\r
+ [7:0] adc_d - input data from A/D converter\r
+ shallow_modulation - modulation type\r
+\r
+ pwr_lo - output to coil drivers (ssp_clk / 8)\r
+ adc_clk - output A/D clock signal\r
+ ssp_frame - output SSS frame indicator (goes high while the 8 bits are shifted)\r
+ ssp_din - output SSP data to ARM (shifts 8 bit A/D value serially to ARM MSB first)\r
+ ssp_clk - output SSP clock signal\r
+\r
+ ck_1356meg - input unused\r
+ ck_1356megb - input unused\r
+ ssp_dout - input unused\r
+ cross_hi - input unused\r
+ cross_lo - input unused\r
+\r
+ pwr_hi - output unused, tied low\r
+ pwr_oe1 - output unused, undefined\r
+ pwr_oe2 - output unused, undefined\r
+ pwr_oe3 - output unused, undefined\r
+ pwr_oe4 - output unused, undefined\r
+ dbg - output alias for adc_clk\r
+*/\r
+\r
+module testbed_hi_read_tx;\r
+ reg pck0;\r
+ reg [7:0] adc_d;\r
+ reg shallow_modulation;\r
+\r
+ wire pwr_lo;\r
+ wire adc_clk;\r
+ reg ck_1356meg;\r
+ reg ck_1356megb;\r
+ wire ssp_frame;\r
+ wire ssp_din;\r
+ wire ssp_clk;\r
+ reg ssp_dout;\r
+ wire pwr_hi;\r
+ wire pwr_oe1;\r
+ wire pwr_oe2;\r
+ wire pwr_oe3;\r
+ wire pwr_oe4;\r
+ wire cross_lo;\r
+ wire cross_hi;\r
+ wire dbg;\r
+\r
+ hi_read_tx #(5,200) dut(\r
+ .pck0(pck0),\r
+ .ck_1356meg(ck_1356meg),\r
+ .ck_1356megb(ck_1356megb),\r
+ .pwr_lo(pwr_lo),\r
+ .pwr_hi(pwr_hi),\r
+ .pwr_oe1(pwr_oe1),\r
+ .pwr_oe2(pwr_oe2),\r
+ .pwr_oe3(pwr_oe3),\r
+ .pwr_oe4(pwr_oe4),\r
+ .adc_d(adc_d),\r
+ .adc_clk(adc_clk),\r
+ .ssp_frame(ssp_frame),\r
+ .ssp_din(ssp_din),\r
+ .ssp_dout(ssp_dout),\r
+ .ssp_clk(ssp_clk),\r
+ .cross_hi(cross_hi),\r
+ .cross_lo(cross_lo),\r
+ .dbg(dbg),\r
+ .shallow_modulation(shallow_modulation)\r
+ );\r
+\r
+ integer idx, i;\r
+\r
+ // main clock\r
+ always #5 begin \r
+ ck_1356megb = !ck_1356megb;\r
+ ck_1356meg = ck_1356megb;\r
+ end\r
+\r
+ //crank DUT\r
+ task crank_dut;\r
+ begin\r
+ @(posedge ssp_clk) ;\r
+ ssp_dout = $random;\r
+ end\r
+ endtask\r
+\r
+ initial begin\r
+\r
+ // init inputs\r
+ ck_1356megb = 0;\r
+ adc_d = 0;\r
+ ssp_dout=0;\r
+\r
+ // shallow modulation off\r
+ shallow_modulation=0;\r
+ for (i = 0 ; i < 16 ; i = i + 1) begin\r
+ crank_dut;\r
+ end\r
+\r
+ // shallow modulation on\r
+ shallow_modulation=1;\r
+ for (i = 0 ; i < 16 ; i = i + 1) begin\r
+ crank_dut;\r
+ end\r
+ $finish;\r
+ end\r
+ \r
+endmodule // main\r
--- /dev/null
+`include "hi_simulate.v"\r
+\r
+/*\r
+ pck0 - input main 24Mhz clock (PLL / 4)\r
+ [7:0] adc_d - input data from A/D converter\r
+ mod_type - modulation type\r
+\r
+ pwr_lo - output to coil drivers (ssp_clk / 8)\r
+ adc_clk - output A/D clock signal\r
+ ssp_frame - output SSS frame indicator (goes high while the 8 bits are shifted)\r
+ ssp_din - output SSP data to ARM (shifts 8 bit A/D value serially to ARM MSB first)\r
+ ssp_clk - output SSP clock signal\r
+\r
+ ck_1356meg - input unused\r
+ ck_1356megb - input unused\r
+ ssp_dout - input unused\r
+ cross_hi - input unused\r
+ cross_lo - input unused\r
+\r
+ pwr_hi - output unused, tied low\r
+ pwr_oe1 - output unused, undefined\r
+ pwr_oe2 - output unused, undefined\r
+ pwr_oe3 - output unused, undefined\r
+ pwr_oe4 - output unused, undefined\r
+ dbg - output alias for adc_clk\r
+*/\r
+\r
+module testbed_hi_simulate;\r
+ reg pck0;\r
+ reg [7:0] adc_d;\r
+ reg mod_type;\r
+\r
+ wire pwr_lo;\r
+ wire adc_clk;\r
+ reg ck_1356meg;\r
+ reg ck_1356megb;\r
+ wire ssp_frame;\r
+ wire ssp_din;\r
+ wire ssp_clk;\r
+ reg ssp_dout;\r
+ wire pwr_hi;\r
+ wire pwr_oe1;\r
+ wire pwr_oe2;\r
+ wire pwr_oe3;\r
+ wire pwr_oe4;\r
+ wire cross_lo;\r
+ wire cross_hi;\r
+ wire dbg;\r
+\r
+ hi_simulate #(5,200) dut(\r
+ .pck0(pck0),\r
+ .ck_1356meg(ck_1356meg),\r
+ .ck_1356megb(ck_1356megb),\r
+ .pwr_lo(pwr_lo),\r
+ .pwr_hi(pwr_hi),\r
+ .pwr_oe1(pwr_oe1),\r
+ .pwr_oe2(pwr_oe2),\r
+ .pwr_oe3(pwr_oe3),\r
+ .pwr_oe4(pwr_oe4),\r
+ .adc_d(adc_d),\r
+ .adc_clk(adc_clk),\r
+ .ssp_frame(ssp_frame),\r
+ .ssp_din(ssp_din),\r
+ .ssp_dout(ssp_dout),\r
+ .ssp_clk(ssp_clk),\r
+ .cross_hi(cross_hi),\r
+ .cross_lo(cross_lo),\r
+ .dbg(dbg),\r
+ .mod_type(mod_type)\r
+ );\r
+\r
+ integer idx, i;\r
+\r
+ // main clock\r
+ always #5 begin \r
+ ck_1356megb = !ck_1356megb;\r
+ ck_1356meg = ck_1356megb;\r
+ end\r
+\r
+ always begin \r
+ @(negedge adc_clk) ;\r
+ adc_d = $random;\r
+ end\r
+\r
+ //crank DUT\r
+ task crank_dut;\r
+ begin\r
+ @(negedge ssp_clk) ;\r
+ ssp_dout = $random;\r
+ end\r
+ endtask\r
+\r
+ initial begin\r
+\r
+ // init inputs\r
+ ck_1356megb = 0;\r
+ // random values\r
+ adc_d = 0;\r
+ ssp_dout=1;\r
+\r
+ // shallow modulation off\r
+ mod_type=0;\r
+ for (i = 0 ; i < 16 ; i = i + 1) begin\r
+ crank_dut;\r
+ end\r
+\r
+ // shallow modulation on\r
+ mod_type=1;\r
+ for (i = 0 ; i < 16 ; i = i + 1) begin\r
+ crank_dut;\r
+ end\r
+ $finish;\r
+ end\r
+ \r
+endmodule // main\r
+\r
--- /dev/null
+`include "lo_read.v"\r
+\r
+/*\r
+ pck0 - input main 24Mhz clock (PLL / 4)\r
+ [7:0] adc_d - input data from A/D converter\r
+ lo_is_125khz - input freq selector (1=125Khz, 0=136Khz)\r
+\r
+ pwr_lo - output to coil drivers (ssp_clk / 8)\r
+ adc_clk - output A/D clock signal\r
+ ssp_frame - output SSS frame indicator (goes high while the 8 bits are shifted)\r
+ ssp_din - output SSP data to ARM (shifts 8 bit A/D value serially to ARM MSB first)\r
+ ssp_clk - output SSP clock signal 1Mhz/1.09Mhz (pck0 / 2*(11+lo_is_125khz) )\r
+\r
+ ck_1356meg - input unused\r
+ ck_1356megb - input unused\r
+ ssp_dout - input unused\r
+ cross_hi - input unused\r
+ cross_lo - input unused\r
+\r
+ pwr_hi - output unused, tied low\r
+ pwr_oe1 - output unused, undefined\r
+ pwr_oe2 - output unused, undefined\r
+ pwr_oe3 - output unused, undefined\r
+ pwr_oe4 - output unused, undefined\r
+ dbg - output alias for adc_clk\r
+*/\r
+\r
+module testbed_lo_read;\r
+ reg pck0;\r
+ reg [7:0] adc_d;\r
+ reg lo_is_125khz;\r
+\r
+ wire pwr_lo;\r
+ wire adc_clk;\r
+ wire ck_1356meg;\r
+ wire ck_1356megb;\r
+ wire ssp_frame;\r
+ wire ssp_din;\r
+ wire ssp_clk;\r
+ wire ssp_dout;\r
+ wire pwr_hi;\r
+ wire pwr_oe1;\r
+ wire pwr_oe2;\r
+ wire pwr_oe3;\r
+ wire pwr_oe4;\r
+ wire cross_lo;\r
+ wire cross_hi;\r
+ wire dbg;\r
+\r
+ lo_read #(5,200) dut(\r
+ .pck0(pck0),\r
+ .ck_1356meg(ck_1356meg),\r
+ .ck_1356megb(ck_1356megb),\r
+ .pwr_lo(pwr_lo),\r
+ .pwr_hi(pwr_hi),\r
+ .pwr_oe1(pwr_oe1),\r
+ .pwr_oe2(pwr_oe2),\r
+ .pwr_oe3(pwr_oe3),\r
+ .pwr_oe4(pwr_oe4),\r
+ .adc_d(adc_d),\r
+ .adc_clk(adc_clk),\r
+ .ssp_frame(ssp_frame),\r
+ .ssp_din(ssp_din),\r
+ .ssp_dout(ssp_dout),\r
+ .ssp_clk(ssp_clk),\r
+ .cross_hi(cross_hi),\r
+ .cross_lo(cross_lo),\r
+ .dbg(dbg),\r
+ .lo_is_125khz(lo_is_125khz)\r
+ );\r
+\r
+ integer idx, i;\r
+\r
+ // main clock\r
+ always #5 pck0 = !pck0;\r
+\r
+ //new A/D value available from ADC on positive edge\r
+ task crank_dut;\r
+ begin\r
+ @(posedge adc_clk) ;\r
+ adc_d = $random;\r
+ end\r
+ endtask\r
+\r
+ initial begin\r
+\r
+ // init inputs\r
+ pck0 = 0;\r
+ adc_d = 0;\r
+\r
+ // simulate 4 A/D cycles at 134Khz\r
+ lo_is_125khz=0;\r
+ for (i = 0 ; i < 4 ; i = i + 1) begin\r
+ crank_dut;\r
+ end\r
+\r
+ // simulate 4 A/D cycles at 125Khz\r
+ lo_is_125khz=1;\r
+ for (i = 0 ; i < 4 ; i = i + 1) begin\r
+ crank_dut;\r
+ end\r
+ $finish;\r
+ end\r
+ \r
+endmodule // main\r
--- /dev/null
+`include "lo_simulate.v"\r
+\r
+/*\r
+ pck0 - input main 24Mhz clock (PLL / 4)\r
+ [7:0] adc_d - input data from A/D converter\r
+\r
+\r
+ pwr_lo - output to coil drivers (ssp_clk / 8)\r
+ adc_clk - output A/D clock signal\r
+ ssp_frame - output SSS frame indicator (goes high while the 8 bits are shifted)\r
+ ssp_din - output SSP data to ARM (shifts 8 bit A/D value serially to ARM MSB first)\r
+ ssp_clk - output SSP clock signal\r
+\r
+ ck_1356meg - input unused\r
+ ck_1356megb - input unused\r
+ ssp_dout - input unused\r
+ cross_hi - input unused\r
+ cross_lo - input unused\r
+\r
+ pwr_hi - output unused, tied low\r
+ pwr_oe1 - output unused, undefined\r
+ pwr_oe2 - output unused, undefined\r
+ pwr_oe3 - output unused, undefined\r
+ pwr_oe4 - output unused, undefined\r
+ dbg - output alias for adc_clk\r
+*/\r
+\r
+module testbed_lo_simulate;\r
+ reg pck0;\r
+ reg [7:0] adc_d;\r
+\r
+\r
+ wire pwr_lo;\r
+ wire adc_clk;\r
+ wire ck_1356meg;\r
+ wire ck_1356megb;\r
+ wire ssp_frame;\r
+ wire ssp_din;\r
+ wire ssp_clk;\r
+ reg ssp_dout;\r
+ wire pwr_hi;\r
+ wire pwr_oe1;\r
+ wire pwr_oe2;\r
+ wire pwr_oe3;\r
+ wire pwr_oe4;\r
+ reg cross_lo;\r
+ wire cross_hi;\r
+ wire dbg;\r
+\r
+ lo_simulate #(5,200) dut(\r
+ .pck0(pck0),\r
+ .ck_1356meg(ck_1356meg),\r
+ .ck_1356megb(ck_1356megb),\r
+ .pwr_lo(pwr_lo),\r
+ .pwr_hi(pwr_hi),\r
+ .pwr_oe1(pwr_oe1),\r
+ .pwr_oe2(pwr_oe2),\r
+ .pwr_oe3(pwr_oe3),\r
+ .pwr_oe4(pwr_oe4),\r
+ .adc_d(adc_d),\r
+ .adc_clk(adc_clk),\r
+ .ssp_frame(ssp_frame),\r
+ .ssp_din(ssp_din),\r
+ .ssp_dout(ssp_dout),\r
+ .ssp_clk(ssp_clk),\r
+ .cross_hi(cross_hi),\r
+ .cross_lo(cross_lo),\r
+ .dbg(dbg)\r
+ );\r
+\r
+\r
+ integer i, counter=0;\r
+\r
+ // main clock\r
+ always #5 pck0 = !pck0;\r
+\r
+ //cross_lo is not really synced to pck0 but it's roughly pck0/192 (24Mhz/192=125Khz)\r
+ task crank_dut;\r
+ begin\r
+ @(posedge pck0) ;\r
+ counter = counter + 1;\r
+ if (counter == 192) begin\r
+ counter = 0;\r
+ ssp_dout = $random;\r
+ cross_lo = 1;\r
+ end else begin\r
+ cross_lo = 0;\r
+ end\r
+ \r
+ end\r
+ endtask\r
+\r
+ initial begin\r
+ pck0 = 0;\r
+ for (i = 0 ; i < 4096 ; i = i + 1) begin\r
+ crank_dut;\r
+ end\r
+ $finish;\r
+ end\r
+\r
+endmodule // main\r
--- /dev/null
+//-----------------------------------------------------------------------------\r
+// General-purpose miscellany.\r
+//\r
+// Jonathan Westhues, April 2006.\r
+//-----------------------------------------------------------------------------\r
+\r
+module mux8(sel, y, x0, x1, x2, x3, x4, x5, x6, x7);\r
+ input [2:0] sel;\r
+ input x0, x1, x2, x3, x4, x5, x6, x7;\r
+ output y;\r
+ reg y;\r
+\r
+always @(x0 or x1 or x2 or x3 or x4 or x5 or x6 or x7 or sel)\r
+begin\r
+ case (sel)\r
+ 3'b000: y = x0;\r
+ 3'b001: y = x1;\r
+ 3'b010: y = x2;\r
+ 3'b011: y = x3;\r
+ 3'b100: y = x4;\r
+ 3'b101: y = x5;\r
+ 3'b110: y = x6;\r
+ 3'b111: y = x7;\r
+ endcase\r
+end\r
+\r
+endmodule\r
--- /dev/null
+run -ifn fpga.v -ifmt Verilog -ofn fpga.ngc -ofmt NGC -p xc2s30-6vq100 -opt_mode Speed -opt_level 1 -ent fpga\r
--- /dev/null
+//-----------------------------------------------------------------------------\r
+// Incomplete register definitions for the AT91SAM7S128 chip.\r
+// Jonathan Westhues, Jul 2005\r
+//-----------------------------------------------------------------------------\r
+\r
+#ifndef __AT91SAM7S128_H\r
+#define __AT91SAM7S128_H\r
+\r
+#define REG(x) (*(volatile unsigned long *)(x))\r
+\r
+//-------------\r
+// Peripheral IDs\r
+\r
+#define PERIPH_AIC_FIQ 0\r
+#define PERIPH_SYSIRQ 1\r
+#define PERIPH_PIOA 2\r
+#define PERIPH_ADC 4\r
+#define PERIPH_SPI 5\r
+#define PERIPH_US0 6\r
+#define PERIPH_US1 7\r
+#define PERIPH_SSC 8\r
+#define PERIPH_TWI 9\r
+#define PERIPH_PWMC 10\r
+#define PERIPH_UDP 11\r
+#define PERIPH_TC0 12\r
+#define PERIPH_TC1 13\r
+#define PERIPH_TC2 14\r
+#define PERIPH_AIC_IRQ0 30\r
+#define PERIPH_AIC_IRQ1 31\r
+\r
+//-------------\r
+// Reset Controller\r
+\r
+#define RSTC_BASE (0xfffffd00)\r
+\r
+#define RSTC_CONTROL REG(RSTC_BASE+0x00)\r
+\r
+#define RST_CONTROL_KEY (0xa5<<24)\r
+#define RST_CONTROL_PROCESSOR_RESET (1<<0)\r
+\r
+//-------------\r
+// PWM Controller\r
+\r
+#define PWM_BASE (0xfffcc000)\r
+\r
+#define PWM_MODE REG(PWM_BASE+0x00)\r
+#define PWM_ENABLE REG(PWM_BASE+0x04)\r
+#define PWM_DISABLE REG(PWM_BASE+0x08)\r
+#define PWM_STATUS REG(PWM_BASE+0x0c)\r
+#define PWM_INTERRUPT_ENABLE REG(PWM_BASE+0x10)\r
+#define PWM_INTERRUPT_DISABLE REG(PWM_BASE+0x14)\r
+#define PWM_INTERRUPT_MASK REG(PWM_BASE+0x18)\r
+#define PWM_INTERRUPT_STATUS REG(PWM_BASE+0x1c)\r
+#define PWM_CH_MODE(x) REG(PWM_BASE+0x200+((x)*0x20))\r
+#define PWM_CH_DUTY_CYCLE(x) REG(PWM_BASE+0x204+((x)*0x20))\r
+#define PWM_CH_PERIOD(x) REG(PWM_BASE+0x208+((x)*0x20))\r
+#define PWM_CH_COUNTER(x) REG(PWM_BASE+0x20c+((x)*0x20))\r
+#define PWM_CH_UPDATE(x) REG(PWM_BASE+0x210+((x)*0x20))\r
+\r
+#define PWM_MODE_DIVA(x) ((x)<<0)\r
+#define PWM_MODE_PREA(x) ((x)<<8)\r
+#define PWM_MODE_DIVB(x) ((x)<<16)\r
+#define PWM_MODE_PREB(x) ((x)<<24)\r
+\r
+#define PWM_CHANNEL(x) (1<<(x))\r
+\r
+#define PWM_CH_MODE_PRESCALER(x) ((x)<<0)\r
+#define PWM_CH_MODE_PERIOD_CENTER_ALIGNED (1<<8)\r
+#define PWM_CH_MODE_POLARITY_STARTS_HIGH (1<<9)\r
+#define PWM_CH_MODE_UPDATE_UPDATES_PERIOD (1<<10)\r
+\r
+//-------------\r
+// Debug Unit\r
+\r
+#define DBG_BASE (0xfffff200)\r
+\r
+#define DBGU_CR REG(DBG_BASE+0x0000)\r
+#define DBGU_MR REG(DBG_BASE+0x0004)\r
+#define DBGU_IER REG(DBG_BASE+0x0008)\r
+#define DBGU_IDR REG(DBG_BASE+0x000C)\r
+#define DBGU_IMR REG(DBG_BASE+0x0010)\r
+#define DBGU_SR REG(DBG_BASE+0x0014)\r
+#define DBGU_RHR REG(DBG_BASE+0x0018)\r
+#define DBGU_THR REG(DBG_BASE+0x001C)\r
+#define DBGU_BRGR REG(DBG_BASE+0x0020)\r
+#define DBGU_CIDR REG(DBG_BASE+0x0040)\r
+#define DBGU_EXID REG(DBG_BASE+0x0044)\r
+#define DBGU_FNR REG(DBG_BASE+0x0048)\r
+\r
+//-------------\r
+// Embedded Flash Controller\r
+\r
+#define MC_BASE (0xffffff00)\r
+\r
+#define MC_FLASH_MODE0 REG(MC_BASE+0x60)\r
+#define MC_FLASH_COMMAND REG(MC_BASE+0x64)\r
+#define MC_FLASH_STATUS REG(MC_BASE+0x68)\r
+#define MC_FLASH_MODE1 REG(MC_BASE+0x70)\r
+\r
+#define MC_FLASH_MODE_READY_INTERRUPT_ENABLE (1<<0)\r
+#define MC_FLASH_MODE_LOCK_INTERRUPT_ENABLE (1<<2)\r
+#define MC_FLASH_MODE_PROG_ERROR_INTERRUPT_ENABLE (1<<3)\r
+#define MC_FLASH_MODE_NO_ERASE_BEFORE_PROGRAMMING (1<<7)\r
+#define MC_FLASH_MODE_FLASH_WAIT_STATES(x) ((x)<<8)\r
+#define MC_FLASH_MODE_MASTER_CLK_IN_MHZ(x) ((x)<<16)\r
+\r
+#define MC_FLASH_COMMAND_FCMD(x) ((x)<<0)\r
+#define MC_FLASH_COMMAND_PAGEN(x) ((x)<<8)\r
+#define MC_FLASH_COMMAND_KEY ((0x5a)<<24)\r
+\r
+#define FCMD_NOP 0x0\r
+#define FCMD_WRITE_PAGE 0x1\r
+#define FCMD_SET_LOCK_BIT 0x2\r
+#define FCMD_WRITE_PAGE_LOCK 0x3\r
+#define FCMD_CLEAR_LOCK_BIT 0x4\r
+#define FCMD_ERASE_ALL 0x8\r
+#define FCMD_SET_GP_NVM_BIT 0xb\r
+#define FCMD_SET_SECURITY_BIT 0xf\r
+\r
+#define MC_FLASH_STATUS_READY (1<<0)\r
+#define MC_FLASH_STATUS_LOCK_ERROR (1<<2)\r
+#define MC_FLASH_STATUS_PROGRAMMING_ERROR (1<<3)\r
+#define MC_FLASH_STATUS_SECURITY_BIT_ACTIVE (1<<4)\r
+#define MC_FLASH_STATUS_GP_NVM_ACTIVE_0 (1<<8)\r
+#define MC_FLASH_STATUS_GP_NVM_ACTIVE_1 (1<<9)\r
+#define MC_FLASH_STATUS_LOCK_ACTIVE(x) (1<<((x)+16))\r
+\r
+#define FLASH_PAGE_SIZE_BYTES 256\r
+#define FLASH_PAGE_COUNT 512\r
+\r
+//-------------\r
+// Watchdog Timer - 12 bit down counter, uses slow clock divided by 128 as source\r
+\r
+#define WDT_BASE (0xfffffd40)\r
+\r
+#define WDT_CONTROL REG(WDT_BASE+0x00)\r
+#define WDT_MODE REG(WDT_BASE+0x04)\r
+#define WDT_STATUS REG(WDT_BASE+0x08)\r
+\r
+#define WDT_HIT() WDT_CONTROL = 0xa5000001\r
+\r
+#define WDT_MODE_COUNT(x) ((x)<<0)\r
+#define WDT_MODE_INTERRUPT_ON_EVENT (1<<12)\r
+#define WDT_MODE_RESET_ON_EVENT_ENABLE (1<<13)\r
+#define WDT_MODE_RESET_ON_EVENT (1<<14)\r
+#define WDT_MODE_WATCHDOG_DELTA(x) ((x)<<16)\r
+#define WDT_MODE_HALT_IN_DEBUG_MODE (1<<28)\r
+#define WDT_MODE_HALT_IN_IDLE_MODE (1<<29)\r
+#define WDT_MODE_DISABLE (1<<15)\r
+\r
+//-------------\r
+// Parallel Input/Output Controller\r
+\r
+#define PIO_BASE (0xfffff400)\r
+\r
+#define PIO_ENABLE REG(PIO_BASE+0x000)\r
+#define PIO_DISABLE REG(PIO_BASE+0x004)\r
+#define PIO_STATUS REG(PIO_BASE+0x008)\r
+#define PIO_OUTPUT_ENABLE REG(PIO_BASE+0x010)\r
+#define PIO_OUTPUT_DISABLE REG(PIO_BASE+0x014)\r
+#define PIO_OUTPUT_STATUS REG(PIO_BASE+0x018)\r
+#define PIO_GLITCH_ENABLE REG(PIO_BASE+0x020)\r
+#define PIO_GLITCH_DISABLE REG(PIO_BASE+0x024)\r
+#define PIO_GLITCH_STATUS REG(PIO_BASE+0x028)\r
+#define PIO_OUTPUT_DATA_SET REG(PIO_BASE+0x030)\r
+#define PIO_OUTPUT_DATA_CLEAR REG(PIO_BASE+0x034)\r
+#define PIO_OUTPUT_DATA_STATUS REG(PIO_BASE+0x038)\r
+#define PIO_PIN_DATA_STATUS REG(PIO_BASE+0x03c)\r
+#define PIO_OPEN_DRAIN_ENABLE REG(PIO_BASE+0x050)\r
+#define PIO_OPEN_DRAIN_DISABLE REG(PIO_BASE+0x054)\r
+#define PIO_OPEN_DRAIN_STATUS REG(PIO_BASE+0x058)\r
+#define PIO_NO_PULL_UP_ENABLE REG(PIO_BASE+0x060)\r
+#define PIO_NO_PULL_UP_DISABLE REG(PIO_BASE+0x064)\r
+#define PIO_NO_PULL_UP_STATUS REG(PIO_BASE+0x068)\r
+#define PIO_PERIPHERAL_A_SEL REG(PIO_BASE+0x070)\r
+#define PIO_PERIPHERAL_B_SEL REG(PIO_BASE+0x074)\r
+#define PIO_PERIPHERAL_WHICH REG(PIO_BASE+0x078)\r
+#define PIO_OUT_WRITE_ENABLE REG(PIO_BASE+0x0a0)\r
+#define PIO_OUT_WRITE_DISABLE REG(PIO_BASE+0x0a4)\r
+#define PIO_OUT_WRITE_STATUS REG(PIO_BASE+0x0a8)\r
+\r
+//-------------\r
+// USB Device Port\r
+\r
+#define UDP_BASE (0xfffb0000)\r
+\r
+#define UDP_FRAME_NUMBER REG(UDP_BASE+0x0000)\r
+#define UDP_GLOBAL_STATE REG(UDP_BASE+0x0004)\r
+#define UDP_FUNCTION_ADDR REG(UDP_BASE+0x0008)\r
+#define UDP_INTERRUPT_ENABLE REG(UDP_BASE+0x0010)\r
+#define UDP_INTERRUPT_DISABLE REG(UDP_BASE+0x0014)\r
+#define UDP_INTERRUPT_MASK REG(UDP_BASE+0x0018)\r
+#define UDP_INTERRUPT_STATUS REG(UDP_BASE+0x001c)\r
+#define UDP_INTERRUPT_CLEAR REG(UDP_BASE+0x0020)\r
+#define UDP_RESET_ENDPOINT REG(UDP_BASE+0x0028)\r
+#define UDP_ENDPOINT_CSR(x) REG(UDP_BASE+0x0030+((x)*4))\r
+#define UDP_ENDPOINT_FIFO(x) REG(UDP_BASE+0x0050+((x)*4))\r
+#define UDP_TRANSCEIVER_CTRL REG(UDP_BASE+0x0074)\r
+\r
+#define UDP_GLOBAL_STATE_ADDRESSED (1<<0)\r
+#define UDP_GLOBAL_STATE_CONFIGURED (1<<1)\r
+#define UDP_GLOBAL_STATE_SEND_RESUME_ENABLED (1<<2)\r
+#define UDP_GLOBAL_STATE_RESUME_RECEIVED (1<<3)\r
+#define UDP_GLOBAL_STATE_REMOTE_WAKE_UP_ENABLED (1<<4)\r
+\r
+#define UDP_FUNCTION_ADDR_ENABLED (1<<8)\r
+\r
+#define UDP_INTERRUPT_ENDPOINT(x) (1<<(x))\r
+#define UDP_INTERRUPT_SUSPEND (1<<8)\r
+#define UDP_INTERRUPT_RESUME (1<<9)\r
+#define UDP_INTERRUPT_EXTERNAL_RESUME (1<<10)\r
+#define UDP_INTERRUPT_SOF (1<<11)\r
+#define UDP_INTERRUPT_END_OF_BUS_RESET (1<<12)\r
+#define UDP_INTERRUPT_WAKEUP (1<<13)\r
+\r
+#define UDP_RESET_ENDPOINT_NUMBER(x) (1<<(x))\r
+\r
+#define UDP_CSR_TX_PACKET_ACKED (1<<0)\r
+#define UDP_CSR_RX_PACKET_RECEIVED_BANK_0 (1<<1)\r
+#define UDP_CSR_RX_HAVE_READ_SETUP_DATA (1<<2)\r
+#define UDP_CSR_STALL_SENT (1<<3)\r
+#define UDP_CSR_TX_PACKET (1<<4)\r
+#define UDP_CSR_FORCE_STALL (1<<5)\r
+#define UDP_CSR_RX_PACKET_RECEIVED_BANK_1 (1<<6)\r
+#define UDP_CSR_CONTROL_DATA_DIR (1<<7)\r
+#define UDP_CSR_EPTYPE_CONTROL (0<<8)\r
+#define UDP_CSR_EPTYPE_ISOCHRON_OUT (1<<8)\r
+#define UDP_CSR_EPTYPE_ISOCHRON_IN (5<<8)\r
+#define UDP_CSR_EPTYPE_BULK_OUT (2<<8)\r
+#define UDP_CSR_EPTYPE_BULK_IN (6<<8)\r
+#define UDP_CSR_EPTYPE_INTERRUPT_OUT (3<<8)\r
+#define UDP_CSR_EPTYPE_INTERRUPT_IN (7<<8)\r
+#define UDP_CSR_IS_DATA1 (1<<11)\r
+#define UDP_CSR_ENABLE_EP (1<<15)\r
+#define UDP_CSR_BYTES_RECEIVED(x) (((x) >> 16) & 0x7ff)\r
+\r
+#define UDP_TRANSCEIVER_CTRL_DISABLE (1<<8)\r
+\r
+//-------------\r
+// Power Management Controller\r
+\r
+#define PMC_BASE (0xfffffc00)\r
+\r
+#define PMC_SYS_CLK_ENABLE REG(PMC_BASE+0x0000)\r
+#define PMC_SYS_CLK_DISABLE REG(PMC_BASE+0x0004)\r
+#define PMC_SYS_CLK_STATUS REG(PMC_BASE+0x0008)\r
+#define PMC_PERIPHERAL_CLK_ENABLE REG(PMC_BASE+0x0010)\r
+#define PMC_PERIPHERAL_CLK_DISABLE REG(PMC_BASE+0x0014)\r
+#define PMC_PERIPHERAL_CLK_STATUS REG(PMC_BASE+0x0018)\r
+#define PMC_MAIN_OSCILLATOR REG(PMC_BASE+0x0020)\r
+#define PMC_MAIN_CLK_FREQUENCY REG(PMC_BASE+0x0024)\r
+#define PMC_PLL REG(PMC_BASE+0x002c)\r
+#define PMC_MASTER_CLK REG(PMC_BASE+0x0030)\r
+#define PMC_PROGRAMMABLE_CLK_0 REG(PMC_BASE+0x0040)\r
+#define PMC_PROGRAMMABLE_CLK_1 REG(PMC_BASE+0x0044)\r
+#define PMC_INTERRUPT_ENABLE REG(PMC_BASE+0x0060)\r
+#define PMC_INTERRUPT_DISABLE REG(PMC_BASE+0x0064)\r
+#define PMC_INTERRUPT_STATUS REG(PMC_BASE+0x0068)\r
+#define PMC_INTERRUPT_MASK REG(PMC_BASE+0x006c)\r
+\r
+#define PMC_SYS_CLK_PROCESSOR_CLK (1<<0)\r
+#define PMC_SYS_CLK_UDP_CLK (1<<7)\r
+#define PMC_SYS_CLK_PROGRAMMABLE_CLK_0 (1<<8)\r
+#define PMC_SYS_CLK_PROGRAMMABLE_CLK_1 (1<<9)\r
+#define PMC_SYS_CLK_PROGRAMMABLE_CLK_2 (1<<10)\r
+\r
+#define PMC_MAIN_OSCILLATOR_STABILIZED (1<<0)\r
+#define PMC_MAIN_OSCILLATOR_PLL_LOCK (1<<2)\r
+#define PMC_MAIN_OSCILLATOR_MCK_READY (1<<3)\r
+#define PMC_MAIN_OSCILLATOR_ENABLE (1<<0)\r
+#define PMC_MAIN_OSCILLATOR_BYPASS (1<<1)\r
+#define PMC_MAIN_OSCILLATOR_STARTUP_DELAY(x) ((x)<<8)\r
+\r
+#define PMC_PLL_DIVISOR(x) (x)\r
+#define PMC_PLL_COUNT_BEFORE_LOCK(x) ((x)<<8)\r
+#define PMC_PLL_FREQUENCY_RANGE(x) ((x)<<14)\r
+#define PMC_PLL_MULTIPLIER(x) (((x)-1)<<16)\r
+#define PMC_PLL_USB_DIVISOR(x) ((x)<<28)\r
+\r
+#define PMC_CLK_SELECTION_PLL_CLOCK (3<<0)\r
+#define PMC_CLK_SELECTION_MAIN_CLOCK (1<<0)\r
+#define PMC_CLK_SELECTION_SLOW_CLOCK (0<<0)\r
+#define PMC_CLK_PRESCALE_DIV_1 (0<<2)\r
+#define PMC_CLK_PRESCALE_DIV_2 (1<<2)\r
+#define PMC_CLK_PRESCALE_DIV_4 (2<<2)\r
+#define PMC_CLK_PRESCALE_DIV_8 (3<<2)\r
+#define PMC_CLK_PRESCALE_DIV_16 (4<<2)\r
+#define PMC_CLK_PRESCALE_DIV_32 (5<<2)\r
+#define PMC_CLK_PRESCALE_DIV_64 (6<<2)\r
+\r
+//-------------\r
+// Serial Peripheral Interface (SPI)\r
+\r
+#define SPI_BASE (0xfffe0000)\r
+\r
+#define SPI_CONTROL REG(SPI_BASE+0x00)\r
+#define SPI_MODE REG(SPI_BASE+0x04)\r
+#define SPI_RX_DATA REG(SPI_BASE+0x08)\r
+#define SPI_TX_DATA REG(SPI_BASE+0x0c)\r
+#define SPI_STATUS REG(SPI_BASE+0x10)\r
+#define SPI_INTERRUPT_ENABLE REG(SPI_BASE+0x14)\r
+#define SPI_INTERRUPT_DISABLE REG(SPI_BASE+0x18)\r
+#define SPI_INTERRUPT_MASK REG(SPI_BASE+0x1c)\r
+#define SPI_FOR_CHIPSEL_0 REG(SPI_BASE+0x30)\r
+#define SPI_FOR_CHIPSEL_1 REG(SPI_BASE+0x34)\r
+#define SPI_FOR_CHIPSEL_2 REG(SPI_BASE+0x38)\r
+#define SPI_FOR_CHIPSEL_3 REG(SPI_BASE+0x3c)\r
+\r
+#define SPI_CONTROL_ENABLE (1<<0)\r
+#define SPI_CONTROL_DISABLE (1<<1)\r
+#define SPI_CONTROL_RESET (1<<7)\r
+#define SPI_CONTROL_LAST_TRANSFER (1<<24)\r
+\r
+#define SPI_MODE_MASTER (1<<0)\r
+#define SPI_MODE_VARIABLE_CHIPSEL (1<<1)\r
+#define SPI_MODE_CHIPSELS_DECODED (1<<2)\r
+#define SPI_MODE_USE_DIVIDED_CLOCK (1<<3)\r
+#define SPI_MODE_MODE_FAULT_DETECTION_OFF (1<<4)\r
+#define SPI_MODE_LOOPBACK (1<<7)\r
+#define SPI_MODE_CHIPSEL(x) ((x)<<16)\r
+#define SPI_MODE_DELAY_BETWEEN_CHIPSELS(x) ((x)<<24)\r
+\r
+#define SPI_RX_DATA_CHIPSEL(x) (((x)>>16)&0xf)\r
+\r
+#define SPI_TX_DATA_CHIPSEL(x) ((x)<<16)\r
+#define SPI_TX_DATA_LAST_TRANSFER (1<<24)\r
+\r
+#define SPI_STATUS_RECEIVE_FULL (1<<0)\r
+#define SPI_STATUS_TRANSMIT_EMPTY (1<<1)\r
+#define SPI_STATUS_MODE_FAULT (1<<2)\r
+#define SPI_STATUS_OVERRUN (1<<3)\r
+#define SPI_STATUS_END_OF_RX_BUFFER (1<<4)\r
+#define SPI_STATUS_END_OF_TX_BUFFER (1<<5)\r
+#define SPI_STATUS_RX_BUFFER_FULL (1<<6)\r
+#define SPI_STATUS_TX_BUFFER_EMPTY (1<<7)\r
+#define SPI_STATUS_NSS_RISING_DETECTED (1<<8)\r
+#define SPI_STATUS_TX_EMPTY (1<<9)\r
+#define SPI_STATUS_SPI_ENABLED (1<<16)\r
+\r
+#define SPI_FOR_CHIPSEL_INACTIVE_CLK_1 (1<<0)\r
+#define SPI_FOR_CHIPSEL_PHASE (1<<1)\r
+#define SPI_FOR_CHIPSEL_LEAVE_CHIPSEL_LOW (1<<3)\r
+#define SPI_FOR_CHIPSEL_BITS_IN_WORD(x) ((x)<<4)\r
+#define SPI_FOR_CHIPSEL_DIVISOR(x) ((x)<<8)\r
+#define SPI_FOR_CHIPSEL_DELAY_BEFORE_CLK(x) ((x)<<16)\r
+#define SPI_FOR_CHIPSEL_INTERWORD_DELAY(x) ((x)<<24)\r
+\r
+//-------------\r
+// Analog to Digital Converter\r
+\r
+#define ADC_BASE (0xfffd8000)\r
+\r
+#define ADC_CONTROL REG(ADC_BASE+0x00)\r
+#define ADC_MODE REG(ADC_BASE+0x04)\r
+#define ADC_CHANNEL_ENABLE REG(ADC_BASE+0x10)\r
+#define ADC_CHANNEL_DISABLE REG(ADC_BASE+0x14)\r
+#define ADC_CHANNEL_STATUS REG(ADC_BASE+0x18)\r
+#define ADC_STATUS REG(ADC_BASE+0x1c)\r
+#define ADC_LAST_CONVERTED_DATA REG(ADC_BASE+0x20)\r
+#define ADC_INTERRUPT_ENABLE REG(ADC_BASE+0x24)\r
+#define ADC_INTERRUPT_DISABLE REG(ADC_BASE+0x28)\r
+#define ADC_INTERRUPT_MASK REG(ADC_BASE+0x2c)\r
+#define ADC_CHANNEL_DATA(x) REG(ADC_BASE+0x30+(4*(x)))\r
+\r
+#define ADC_CONTROL_RESET (1<<0)\r
+#define ADC_CONTROL_START (1<<1)\r
+\r
+#define ADC_MODE_HW_TRIGGERS_ENABLED (1<<0)\r
+#define ADC_MODE_8_BIT_RESOLUTION (1<<4)\r
+#define ADC_MODE_SLEEP (1<<5)\r
+#define ADC_MODE_PRESCALE(x) ((x)<<8)\r
+#define ADC_MODE_STARTUP_TIME(x) ((x)<<16)\r
+#define ADC_MODE_SAMPLE_HOLD_TIME(x) ((x)<<24)\r
+\r
+#define ADC_CHANNEL(x) (1<<(x))\r
+\r
+#define ADC_END_OF_CONVERSION(x) (1<<(x))\r
+#define ADC_OVERRUN_ERROR(x) (1<<(8+(x)))\r
+#define ADC_DATA_READY (1<<16)\r
+#define ADC_GENERAL_OVERRUN (1<<17)\r
+#define ADC_END_OF_RX_BUFFER (1<<18)\r
+#define ADC_RX_BUFFER_FULL (1<<19)\r
+\r
+//-------------\r
+// Synchronous Serial Controller\r
+\r
+#define SSC_BASE (0xfffd4000)\r
+\r
+#define SSC_CONTROL REG(SSC_BASE+0x00)\r
+#define SSC_CLOCK_DIVISOR REG(SSC_BASE+0x04)\r
+#define SSC_RECEIVE_CLOCK_MODE REG(SSC_BASE+0x10)\r
+#define SSC_RECEIVE_FRAME_MODE REG(SSC_BASE+0x14)\r
+#define SSC_TRANSMIT_CLOCK_MODE REG(SSC_BASE+0x18)\r
+#define SSC_TRANSMIT_FRAME_MODE REG(SSC_BASE+0x1c)\r
+#define SSC_RECEIVE_HOLDING REG(SSC_BASE+0x20)\r
+#define SSC_TRANSMIT_HOLDING REG(SSC_BASE+0x24)\r
+#define SSC_RECEIVE_SYNC_HOLDING REG(SSC_BASE+0x30)\r
+#define SSC_TRANSMIT_SYNC_HOLDING REG(SSC_BASE+0x34)\r
+#define SSC_STATUS REG(SSC_BASE+0x40)\r
+#define SSC_INTERRUPT_ENABLE REG(SSC_BASE+0x44)\r
+#define SSC_INTERRUPT_DISABLE REG(SSC_BASE+0x48)\r
+#define SSC_INTERRUPT_MASK REG(SSC_BASE+0x4c)\r
+\r
+#define SSC_CONTROL_RX_ENABLE (1<<0)\r
+#define SSC_CONTROL_RX_DISABLE (1<<1)\r
+#define SSC_CONTROL_TX_ENABLE (1<<8)\r
+#define SSC_CONTROL_TX_DISABLE (1<<9)\r
+#define SSC_CONTROL_RESET (1<<15)\r
+\r
+#define SSC_CLOCK_MODE_SELECT(x) ((x)<<0)\r
+#define SSC_CLOCK_MODE_OUTPUT(x) ((x)<<2)\r
+#define SSC_CLOCK_MODE_INVERT (1<<5)\r
+#define SSC_CLOCK_MODE_START(x) ((x)<<8)\r
+#define SSC_CLOCK_MODE_START_DELAY(x) ((x)<<16)\r
+#define SSC_CLOCK_MODE_FRAME_PERIOD(x) ((x)<<24)\r
+\r
+#define SSC_FRAME_MODE_BITS_IN_WORD(x) (((x)-1)<<0)\r
+#define SSC_FRAME_MODE_LOOPBACK (1<<5) // for RX\r
+#define SSC_FRAME_MODE_DEFAULT_IS_1 (1<<5) // for TX\r
+#define SSC_FRAME_MODE_MSB_FIRST (1<<7)\r
+#define SSC_FRAME_MODE_WORDS_PER_TRANSFER(x) ((x)<<8)\r
+#define SSC_FRAME_MODE_FRAME_SYNC_LEN(x) ((x)<<16)\r
+#define SSC_FRAME_MODE_FRAME_SYNC_TYPE(x) ((x)<<20)\r
+#define SSC_FRAME_MODE_SYNC_DATA_ENABLE (1<<23) // for TX only\r
+#define SSC_FRAME_MODE_NEGATIVE_EDGE (1<<24)\r
+\r
+#define SSC_STATUS_TX_READY (1<<0)\r
+#define SSC_STATUS_TX_EMPTY (1<<1)\r
+#define SSC_STATUS_TX_ENDED (1<<2)\r
+#define SSC_STATUS_TX_BUF_EMPTY (1<<3)\r
+#define SSC_STATUS_RX_READY (1<<4)\r
+#define SSC_STATUS_RX_OVERRUN (1<<5)\r
+#define SSC_STATUS_RX_ENDED (1<<6)\r
+#define SSC_STATUS_RX_BUF_FULL (1<<7)\r
+#define SSC_STATUS_TX_SYNC_OCCURRED (1<<10)\r
+#define SSC_STATUS_RX_SYNC_OCCURRED (1<<11)\r
+#define SSC_STATUS_TX_ENABLED (1<<16)\r
+#define SSC_STATUS_RX_ENABLED (1<<17)\r
+\r
+//-------------\r
+// Peripheral DMA Controller\r
+//\r
+// There is one set of registers for every peripheral that supports DMA.\r
+\r
+#define PDC_RX_POINTER(x) REG((x)+0x100)\r
+#define PDC_RX_COUNTER(x) REG((x)+0x104)\r
+#define PDC_TX_POINTER(x) REG((x)+0x108)\r
+#define PDC_TX_COUNTER(x) REG((x)+0x10c)\r
+#define PDC_RX_NEXT_POINTER(x) REG((x)+0x110)\r
+#define PDC_RX_NEXT_COUNTER(x) REG((x)+0x114)\r
+#define PDC_TX_NEXT_POINTER(x) REG((x)+0x118)\r
+#define PDC_TX_NEXT_COUNTER(x) REG((x)+0x11c)\r
+#define PDC_CONTROL(x) REG((x)+0x120)\r
+#define PDC_STATUS(x) REG((x)+0x124)\r
+\r
+#define PDC_RX_ENABLE (1<<0)\r
+#define PDC_RX_DISABLE (1<<1)\r
+#define PDC_TX_ENABLE (1<<8)\r
+#define PDC_TX_DISABLE (1<<9)\r
+\r
+#endif\r
--- /dev/null
+#ifndef __CONFIG_GPIO_H\r
+#define __CONFIG_GPIO_H\r
+\r
+#define GPIO_LED_A 0\r
+#define GPIO_PA1 1\r
+#define GPIO_LED_D 2\r
+#define GPIO_NVDD_ON 3\r
+#define GPIO_FPGA_NINIT 4\r
+#define GPIO_PA5 5\r
+#define GPIO_PCK0 6\r
+#define GPIO_LRST 7\r
+#define GPIO_LED_B 8\r
+#define GPIO_LED_C 9\r
+#define GPIO_NCS2 10\r
+#define GPIO_NCS0 11\r
+#define GPIO_MISO 12\r
+#define GPIO_MOSI 13\r
+#define GPIO_SPCK 14\r
+#define GPIO_SSC_FRAME 15\r
+#define GPIO_SSC_CLK 16\r
+#define GPIO_SSC_DOUT 17\r
+#define GPIO_SSC_DIN 18\r
+#define GPIO_MUXSEL_HIPKD 19\r
+#define GPIO_MUXSEL_LOPKD 20\r
+#define GPIO_MUXSEL_HIRAW 21\r
+#define GPIO_MUXSEL_LORAW 22\r
+#define GPIO_BUTTON 23\r
+#define GPIO_USB_PU 24\r
+#define GPIO_RELAY 25\r
+#define GPIO_FPGA_ON 26\r
+#define GPIO_FPGA_DONE 27\r
+#define GPIO_FPGA_NPROGRAM 28\r
+#define GPIO_FPGA_CCLK 29\r
+#define GPIO_FPGA_DIN 30\r
+#define GPIO_FPGA_DOUT 31\r
+\r
+#define ANIN_AMPL_LO 4\r
+#define ANIN_AMPL_HI 5\r
+\r
+#endif\r
--- /dev/null
+//-----------------------------------------------------------------------------\r
+// Definitions of interest to most of the software for this project.\r
+// Jonathan Westhues, Mar 2006\r
+//-----------------------------------------------------------------------------\r
+\r
+#ifndef __PROXMARK3_H\r
+#define __PROXMARK3_H\r
+\r
+// Might as well have the hardware-specific defines everywhere.\r
+#include <at91sam7s128.h>\r
+\r
+#include <config_gpio.h>\r
+#define LOW(x) PIO_OUTPUT_DATA_CLEAR = (1 << (x))\r
+#define HIGH(x) PIO_OUTPUT_DATA_SET = (1 << (x))\r
+\r
+#define SPI_FPGA_MODE 0\r
+#define SPI_LCD_MODE 1\r
+\r
+typedef unsigned long DWORD;\r
+typedef signed long SDWORD;\r
+typedef unsigned long long QWORD;\r
+typedef int BOOL;\r
+typedef unsigned char BYTE;\r
+typedef signed char SBYTE;\r
+typedef unsigned short WORD;\r
+typedef signed short SWORD;\r
+#define TRUE 1\r
+#define FALSE 0\r
+\r
+#include <usb_cmd.h>\r
+\r
+#define PACKED __attribute__((__packed__))\r
+\r
+#define USB_D_PLUS_PULLUP_ON() { \\r
+ PIO_OUTPUT_DATA_SET = (1<<GPIO_USB_PU); \\r
+ PIO_OUTPUT_ENABLE = (1<<GPIO_USB_PU); \\r
+ }\r
+#define USB_D_PLUS_PULLUP_OFF() PIO_OUTPUT_DISABLE = (1<<GPIO_USB_PU)\r
+\r
+#define LED_A_ON() PIO_OUTPUT_DATA_SET = (1<<GPIO_LED_A)\r
+#define LED_A_OFF() PIO_OUTPUT_DATA_CLEAR = (1<<GPIO_LED_A)\r
+#define LED_B_ON() PIO_OUTPUT_DATA_SET = (1<<GPIO_LED_B)\r
+#define LED_B_OFF() PIO_OUTPUT_DATA_CLEAR = (1<<GPIO_LED_B)\r
+#define LED_C_ON() PIO_OUTPUT_DATA_SET = (1<<GPIO_LED_C)\r
+#define LED_C_OFF() PIO_OUTPUT_DATA_CLEAR = (1<<GPIO_LED_C)\r
+#define LED_D_ON() PIO_OUTPUT_DATA_SET = (1<<GPIO_LED_D)\r
+#define LED_D_OFF() PIO_OUTPUT_DATA_CLEAR = (1<<GPIO_LED_D)\r
+#define RELAY_ON() PIO_OUTPUT_DATA_SET = (1<<GPIO_RELAY)\r
+#define RELAY_OFF() PIO_OUTPUT_DATA_CLEAR = (1<<GPIO_RELAY)\r
+#define BUTTON_PRESS() !(PIO_PIN_DATA_STATUS & (1<<GPIO_BUTTON))\r
+//--------------------------------\r
+// USB declarations\r
+\r
+void UsbSendPacket(BYTE *packet, int len);\r
+BOOL UsbPoll(BOOL blinkLeds);\r
+void UsbStart(void);\r
+\r
+// This function is provided by the apps/bootrom, and called from UsbPoll\r
+// if data are available.\r
+void UsbPacketReceived(BYTE *packet, int len);\r
+\r
+#endif\r
--- /dev/null
+//-----------------------------------------------------------------------------\r
+// Definitions for all the types of commands that may be sent over USB; our\r
+// own protocol.\r
+// Jonathan Westhues, Mar 2006\r
+// Edits by Gerhard de Koning Gans, Sep 2007\r
+//-----------------------------------------------------------------------------\r
+\r
+#ifndef __USB_CMD_H\r
+#define __USB_CMD_H\r
+\r
+typedef struct {\r
+ DWORD cmd;\r
+ DWORD ext1;\r
+ DWORD ext2;\r
+ DWORD ext3;\r
+ union {\r
+ BYTE asBytes[48];\r
+ DWORD asDwords[12];\r
+ } d;\r
+} UsbCommand;\r
+\r
+// For the bootloader\r
+#define CMD_DEVICE_INFO 0x0000\r
+#define CMD_SETUP_WRITE 0x0001\r
+#define CMD_FINISH_WRITE 0x0003\r
+#define CMD_HARDWARE_RESET 0x0004\r
+#define CMD_ACK 0x00ff\r
+\r
+// For general mucking around\r
+#define CMD_DEBUG_PRINT_STRING 0x0100\r
+#define CMD_DEBUG_PRINT_INTEGERS 0x0101\r
+#define CMD_DEBUG_PRINT_BYTES 0x0102\r
+#define CMD_LCD_RESET 0x0103\r
+#define CMD_LCD 0x0104\r
+\r
+// For low-frequency tags\r
+#define CMD_ACQUIRE_RAW_BITS_TI_TYPE 0x0200\r
+#define CMD_DOWNLOAD_RAW_BITS_TI_TYPE 0x0201\r
+#define CMD_DOWNLOADED_RAW_BITS_TI_TYPE 0x0202\r
+#define CMD_ACQUIRE_RAW_ADC_SAMPLES_125K 0x0203\r
+#define CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K 0x0204\r
+#define CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K 0x0205\r
+#define CMD_DOWNLOADED_SIM_SAMPLES_125K 0x0206\r
+#define CMD_SIMULATE_TAG_125K 0x0207\r
+#define CMD_HID_DEMOD_FSK 0x0208 // ## New command: demodulate HID tag ID\r
+#define CMD_HID_SIM_TAG 0x0209 // ## New command: simulate HID tag by ID\r
+\r
+// For the 13.56 MHz tags\r
+#define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693 0x0300\r
+#define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443 0x0301\r
+#define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443_SIM 0x0302\r
+#define CMD_READER_ISO_15693 0x0310 // ## New command to act like a 15693 reader - greg\r
+#define CMD_SIMTAG_ISO_15693 0x0311 // ## New command to act like a 15693 reader - greg\r
+\r
+#define CMD_SIMULATE_TAG_HF_LISTEN 0x0380\r
+#define CMD_SIMULATE_TAG_ISO_14443 0x0381\r
+#define CMD_SNOOP_ISO_14443 0x0382\r
+#define CMD_SNOOP_ISO_14443a 0x0383 // ## New snoop command\r
+#define CMD_SIMULATE_TAG_ISO_14443a 0x0384 // ## New command: Simulate tag 14443a\r
+#define CMD_READER_ISO_14443a 0x0385 // ## New command to act like a 14443a reader\r
+\r
+#define CMD_SIMULATE_MIFARE_CARD 0x0386\r
+\r
+// For measurements of the antenna tuning\r
+#define CMD_MEASURE_ANTENNA_TUNING 0x0400\r
+#define CMD_MEASURED_ANTENNA_TUNING 0x0401\r
+\r
+// For direct FPGA control\r
+#define CMD_FPGA_MAJOR_MODE_OFF 0x0500 // ## FPGA Control\r
+\r
+#endif\r
--- /dev/null
+LDFLAGS = -lusb -lreadline -lpthread -L/opt/local/lib
+CFLAGS = -I. -I/opt/local/include -Wall
+
+CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall
+QTLDFLAGS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null)
+
+ifneq ($(QTLDFLAGS),)
+QTGUI = proxgui.o proxguiqt.o proxguiqt.moc.o
+CFLAGS += -DHAVE_GUI
+MOC = $(shell type moc-qt4 >/dev/null 2>&1 && echo moc-qt4 || echo moc)
+LINK.o = $(LINK.cpp)
+else
+QTGUI = guidummy.o
+endif
+
+all: proxmark3 snooper
+
+proxmark3: LDFLAGS+=$(QTLDFLAGS)
+proxmark3: proxmark3.o gui.o command.o usb.o $(QTGUI)
+
+snooper: snooper.o gui.o command.o usb.o guidummy.o
+
+proxguiqt.moc.cpp: proxguiqt.h
+ $(MOC) -o$@ $^
+
+clean:
+ rm -f proxmark3 snooper *.o *.moc.cpp
+
+.PHONY: all clean
--- /dev/null
+#include "translate.h"
+#include "../winsrc/command.cpp"
--- /dev/null
+#include <usb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "translate.h"
+#include "../winsrc/prox.h"
+#include "proxmark3.h"
+
+static DWORD ExpectedAddr;
+static BYTE QueuedToSend[256];
+static BOOL AllWritten;
+
+static void FlushPrevious(void)
+{
+ UsbCommand c;
+ memset(&c, 0, sizeof(c));
+
+ printf("expected = %08x flush, ", ExpectedAddr);
+
+ int i;
+ for(i = 0; i < 240; i += 48) {
+ c.cmd = CMD_SETUP_WRITE;
+ memcpy(c.d.asBytes, QueuedToSend+i, 48);
+ c.ext1 = (i/4);
+ SendCommand(&c, TRUE);
+ }
+
+ c.cmd = CMD_FINISH_WRITE;
+ c.ext1 = (ExpectedAddr-1) & (~255);
+ printf("c.ext1 = %08x\r", c.ext1);
+ memcpy(c.d.asBytes, QueuedToSend+240, 16);
+ SendCommand(&c, TRUE);
+
+ AllWritten = TRUE;
+}
+
+static void GotByte(DWORD where, BYTE which)
+{
+ AllWritten = FALSE;
+
+ if(where != ExpectedAddr) {
+ printf("bad: got at %08x, expected at %08x\n", where, ExpectedAddr);
+ exit(-1);
+ }
+ QueuedToSend[where & 255] = which;
+ ExpectedAddr++;
+
+ if((where & 255) == 255) {
+ // we have completed a full page
+ FlushPrevious();
+ }
+}
+
+static int HexVal(int c)
+{
+ c = tolower(c);
+ if(c >= '0' && c <= '9') {
+ return c - '0';
+ } else if(c >= 'a' && c <= 'f') {
+ return (c - 'a') + 10;
+ } else {
+ printf("bad hex digit '%c'\n", c);
+ exit(-1);
+ }
+}
+
+static BYTE HexByte(char *s)
+{
+ return (HexVal(s[0]) << 4) | HexVal(s[1]);
+}
+
+static void LoadFlashFromSRecords(char *file, int addr)
+{
+ ExpectedAddr = addr;
+
+ FILE *f = fopen(file, "r");
+ if(!f) {
+ printf("couldn't open file\n");
+ exit(-1);
+ }
+
+ char line[512];
+ while(fgets(line, sizeof(line), f)) {
+ if(memcmp(line, "S3", 2)==0) {
+ char *s = line + 2;
+ int len = HexByte(s) - 5;
+ s += 2;
+
+ char addrStr[9];
+ memcpy(addrStr, s, 8);
+ addrStr[8] = '\0';
+ DWORD addr;
+ sscanf(addrStr, "%x", &addr);
+ s += 8;
+
+ int i;
+ for(i = 0; i < len; i++) {
+ while((addr+i) > ExpectedAddr) {
+ GotByte(ExpectedAddr, 0xff);
+ }
+ GotByte(addr+i, HexByte(s));
+ s += 2;
+ }
+ }
+ }
+
+ if(!AllWritten) FlushPrevious();
+
+ fclose(f);
+ printf("\ndone.\n");
+}
+
+int main(int argc, char **argv) {
+ unsigned int addr = 0;
+ UsbCommand c;
+
+ if (argc != 3) {
+ fprintf(stderr,"Usage: %s {bootrom|os|fpga} image.s19\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (!strcmp(argv[1],"bootrom")) {
+ addr = 0;
+ } else if (!strcmp(argv[1],"os")) {
+ addr = 0x10000;
+ } else if (!strcmp(argv[1],"fpga")) {
+ addr = 0x2000;
+ } else {
+ fprintf(stderr,"Unknown action '%s'!\n", argv[1]);
+ exit(EXIT_FAILURE);
+ }
+
+ usb_init();
+
+ fprintf(stderr,"Waiting for Proxmark to appear on USB...\n");
+ while(!(devh=OpenProxmark(0))) { sleep(1); }
+ fprintf(stderr,"Found...\n");
+
+ fprintf(stderr,"Entering flash-mode...\n");
+ bzero(&c, sizeof(c));
+ c.cmd = CMD_START_FLASH;
+ SendCommand(&c, FALSE);
+ CloseProxmark();
+ sleep(1);
+
+ fprintf(stderr,"Waiting for Proxmark to reappear on USB...\n");
+ while(!(devh=OpenProxmark(0))) { sleep(1); }
+ fprintf(stderr,"Found...\n");
+
+ LoadFlashFromSRecords(argv[2], addr);
+
+ bzero(&c, sizeof(c));
+ c.cmd = CMD_HARDWARE_RESET;
+ SendCommand(&c, FALSE);
+
+ CloseProxmark();
+
+ fprintf(stderr,"Have a nice day!\n");
+
+ return 0;
+}
--- /dev/null
+#include <stdarg.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "proxgui.h"
+#include "translate.h"
+#include "../winsrc/prox.h"
+
+int GraphBuffer[MAX_GRAPH_TRACE_LEN];
+int GraphTraceLen;
+double CursorScaleFactor;
+int CommandFinished;
+
+static char *logfilename = "proxmark3.log";
+
+void PrintToScrollback(char *fmt, ...) {
+ va_list argptr;
+ static FILE *logfile = NULL;
+ static int logging=1;
+
+ if (logging && !logfile) {
+ logfile=fopen(logfilename, "a");
+ if (!logfile) {
+ fprintf(stderr, "Can't open logfile, logging disabled!\n");
+ logging=0;
+ }
+ }
+
+ va_start(argptr, fmt);
+ vprintf(fmt, argptr);
+ printf("\n");
+ if (logging && logfile) {
+#if 0
+ char zeit[25];
+ time_t jetzt_t;
+ struct tm *jetzt;
+
+ jetzt_t = time(NULL);
+ jetzt = localtime(&jetzt_t);
+ strftime(zeit, 25, "%b %e %T", jetzt);
+
+ fprintf(logfile,"%s ", zeit);
+#endif
+ vfprintf(logfile, fmt, argptr);
+ fprintf(logfile,"\n");
+ fflush(logfile);
+ }
+ va_end(argptr);
+}
+
+void setlogfilename(char *fn)
+{
+ logfilename = fn;
+}
--- /dev/null
+#include <stdio.h>
+
+void ShowGraphWindow(void)
+{
+ static int warned = 0;
+
+ if (!warned) {
+ printf("No GUI in this build!\n");
+ warned = 1;
+ }
+}
+
+void HideGraphWindow(void) {}
+void RepaintGraphWindow(void) {}
+void MainGraphics() {}
+void InitGraphics(int argc, char **argv) {}
+void ExitGraphics(void) {}
--- /dev/null
+#include "proxgui.h"
+#include "proxguiqt.h"
+
+static ProxGuiQT *gui = NULL;
+
+extern "C" void ShowGraphWindow(void)
+{
+ if (!gui)
+ return;
+
+ gui->ShowGraphWindow();
+}
+
+extern "C" void HideGraphWindow(void)
+{
+ if (!gui)
+ return;
+
+ gui->HideGraphWindow();
+}
+
+extern "C" void RepaintGraphWindow(void)
+{
+ if (!gui)
+ return;
+
+ gui->RepaintGraphWindow();
+}
+
+extern "C" void MainGraphics(void)
+{
+ if (!gui)
+ return;
+
+ gui->MainLoop();
+}
+
+extern "C" void InitGraphics(int argc, char **argv)
+{
+#ifdef Q_WS_X11
+ bool useGUI = getenv("DISPLAY") != 0;
+#else
+ bool useGUI = true;
+#endif
+ if (!useGUI)
+ return;
+
+ gui = new ProxGuiQT(argc, argv);
+}
+
+extern "C" void ExitGraphics(void)
+{
+ if (!gui)
+ return;
+
+ delete gui;
+ gui = NULL;
+}
--- /dev/null
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void ShowGraphWindow(void);
+void HideGraphWindow(void);
+void RepaintGraphWindow(void);
+void MainGraphics(void);
+void InitGraphics(int argc, char **argv);
+void ExitGraphics(void);
+
+#define MAX_GRAPH_TRACE_LEN (1024*128)
+extern int GraphBuffer[MAX_GRAPH_TRACE_LEN];
+extern int GraphTraceLen;
+extern double CursorScaleFactor;
+extern int CommandFinished;
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+#include <iostream>
+#include <QPainterPath>
+#include <QBrush>
+#include <QPen>
+#include <QTimer>
+#include <QCloseEvent>
+#include <QMouseEvent>
+#include <QKeyEvent>
+#include <math.h>
+#include <limits.h>
+#include "proxguiqt.h"
+#include "proxgui.h"
+
+void ProxGuiQT::ShowGraphWindow(void)
+{
+ emit ShowGraphWindowSignal();
+}
+
+void ProxGuiQT::RepaintGraphWindow(void)
+{
+ emit RepaintGraphWindowSignal();
+}
+
+void ProxGuiQT::HideGraphWindow(void)
+{
+ emit HideGraphWindowSignal();
+}
+
+void ProxGuiQT::_ShowGraphWindow(void)
+{
+ if(!plotapp)
+ return;
+
+ if (!plotwidget)
+ plotwidget = new ProxWidget();
+
+ plotwidget->show();
+}
+
+void ProxGuiQT::_RepaintGraphWindow(void)
+{
+ if (!plotapp || !plotwidget)
+ return;
+
+ plotwidget->update();
+}
+
+void ProxGuiQT::_HideGraphWindow(void)
+{
+ if (!plotapp || !plotwidget)
+ return;
+
+ plotwidget->hide();
+}
+
+void ProxGuiQT::MainLoop()
+{
+ plotapp = new QApplication(argc, argv);
+
+ connect(this, SIGNAL(ShowGraphWindowSignal()), this, SLOT(_ShowGraphWindow()));
+ connect(this, SIGNAL(RepaintGraphWindowSignal()), this, SLOT(_RepaintGraphWindow()));
+ connect(this, SIGNAL(HideGraphWindowSignal()), this, SLOT(_HideGraphWindow()));
+
+ plotapp->exec();
+}
+
+ProxGuiQT::ProxGuiQT(int argc, char **argv) : plotapp(NULL), plotwidget(NULL),
+ argc(argc), argv(argv)
+{
+}
+
+ProxGuiQT::~ProxGuiQT(void)
+{
+ if (plotwidget) {
+ delete plotwidget;
+ plotwidget = NULL;
+ }
+
+ if (plotapp) {
+ plotapp->quit();
+ delete plotapp;
+ plotapp = NULL;
+ }
+}
+
+void ProxWidget::paintEvent(QPaintEvent *event)
+{
+ QPainter painter(this);
+ QPainterPath penPath, whitePath, greyPath, cursorAPath, cursorBPath;
+ QRect r;
+ QBrush brush(QColor(100, 255, 100));
+ QPen pen(QColor(100, 255, 100));
+
+ painter.setFont(QFont("Arial", 10));
+
+ if(GraphStart < 0) {
+ GraphStart = 0;
+ }
+
+ r = rect();
+
+ painter.fillRect(r, QColor(0, 0, 0));
+
+ whitePath.moveTo(r.left() + 40, r.top());
+ whitePath.lineTo(r.left() + 40, r.bottom());
+
+ int zeroHeight = r.top() + (r.bottom() - r.top()) / 2;
+
+ greyPath.moveTo(r.left(), zeroHeight);
+ greyPath.lineTo(r.right(), zeroHeight);
+ painter.setPen(QColor(100, 100, 100));
+ painter.drawPath(greyPath);
+
+ int startMax =
+ (GraphTraceLen - (int)((r.right() - r.left() - 40) / GraphPixelsPerPoint));
+ if(startMax < 0) {
+ startMax = 0;
+ }
+ if(GraphStart > startMax) {
+ GraphStart = startMax;
+ }
+
+ int absYMax = 1;
+
+ int i;
+ for(i = GraphStart; ; i++) {
+ if(i >= GraphTraceLen) {
+ break;
+ }
+ if(fabs((double)GraphBuffer[i]) > absYMax) {
+ absYMax = (int)fabs((double)GraphBuffer[i]);
+ }
+ int x = 40 + (int)((i - GraphStart)*GraphPixelsPerPoint);
+ if(x > r.right()) {
+ break;
+ }
+ }
+
+ absYMax = (int)(absYMax*1.2 + 1);
+
+ // number of points that will be plotted
+ int span = (int)((r.right() - r.left()) / GraphPixelsPerPoint);
+ // one label every 100 pixels, let us say
+ int labels = (r.right() - r.left() - 40) / 100;
+ if(labels <= 0) labels = 1;
+ int pointsPerLabel = span / labels;
+ if(pointsPerLabel <= 0) pointsPerLabel = 1;
+
+ int yMin = INT_MAX;
+ int yMax = INT_MIN;
+ int yMean = 0;
+ int n = 0;
+
+ for(i = GraphStart; ; i++) {
+ if(i >= GraphTraceLen) {
+ break;
+ }
+ int x = 40 + (int)((i - GraphStart)*GraphPixelsPerPoint);
+ if(x > r.right() + GraphPixelsPerPoint) {
+ break;
+ }
+
+ int y = GraphBuffer[i];
+ if(y < yMin) {
+ yMin = y;
+ }
+ if(y > yMax) {
+ yMax = y;
+ }
+ yMean += y;
+ n++;
+
+ y = (y * (r.top() - r.bottom()) / (2*absYMax)) + zeroHeight;
+ if(i == GraphStart) {
+ penPath.moveTo(x, y);
+ } else {
+ penPath.lineTo(x, y);
+ }
+
+ if(GraphPixelsPerPoint > 10) {
+ QRect f(QPoint(x - 3, y - 3),QPoint(x + 3, y + 3));
+ painter.fillRect(f, brush);
+ }
+
+ if(((i - GraphStart) % pointsPerLabel == 0) && i != GraphStart) {
+ whitePath.moveTo(x, zeroHeight - 3);
+ whitePath.lineTo(x, zeroHeight + 3);
+
+ char str[100];
+ sprintf(str, "+%d", (i - GraphStart));
+
+ painter.setPen(QColor(255, 255, 255));
+ QRect size;
+ QFontMetrics metrics(painter.font());
+ size = metrics.boundingRect(str);
+ painter.drawText(x - (size.right() - size.left()), zeroHeight + 9, str);
+
+ penPath.moveTo(x,y);
+ }
+
+ if(i == CursorAPos || i == CursorBPos) {
+ QPainterPath *cursorPath;
+
+ if(i == CursorAPos) {
+ cursorPath = &cursorAPath;
+ } else {
+ cursorPath = &cursorBPath;
+ }
+ cursorPath->moveTo(x, r.top());
+ cursorPath->lineTo(x, r.bottom());
+ penPath.moveTo(x, y);
+ }
+ }
+
+ if(n != 0) {
+ yMean /= n;
+ }
+
+ painter.setPen(QColor(255, 255, 255));
+ painter.drawPath(whitePath);
+ painter.setPen(pen);
+ painter.drawPath(penPath);
+ painter.setPen(QColor(255, 255, 0));
+ painter.drawPath(cursorAPath);
+ painter.setPen(QColor(255, 0, 255));
+ painter.drawPath(cursorBPath);
+
+ char str[100];
+ sprintf(str, "@%d max=%d min=%d mean=%d n=%d/%d dt=%d [%.3f]",
+ GraphStart, yMax, yMin, yMean, n, GraphTraceLen,
+ CursorBPos - CursorAPos, (CursorBPos - CursorAPos)/CursorScaleFactor);
+
+ painter.setPen(QColor(255, 255, 255));
+ painter.drawText(50, r.bottom() - 20, str);
+}
+
+ProxWidget::ProxWidget(QWidget *parent) : QWidget(parent), GraphStart(0), GraphPixelsPerPoint(1)
+{
+ resize(600, 500);
+
+ QPalette palette(QColor(0,0,0,0));
+ palette.setColor(QPalette::WindowText, QColor(255,255,255));
+ palette.setColor(QPalette::Text, QColor(255,255,255));
+ palette.setColor(QPalette::Button, QColor(100, 100, 100));
+ setPalette(palette);
+ setAutoFillBackground(true);
+}
+
+void ProxWidget::closeEvent(QCloseEvent *event)
+{
+ event->ignore();
+ this->hide();
+}
+
+void ProxWidget::mouseMoveEvent(QMouseEvent *event)
+{
+ int x = event->x();
+ x -= 40;
+ x = (int)(x / GraphPixelsPerPoint);
+ x += GraphStart;
+ if((event->buttons() & Qt::LeftButton)) {
+ CursorAPos = x;
+ } else if (event->buttons() & Qt::RightButton) {
+ CursorBPos = x;
+ }
+
+
+ this->update();
+}
+
+void ProxWidget::keyPressEvent(QKeyEvent *event)
+{
+ switch(event->key()) {
+ case Qt::Key_Down:
+ if(GraphPixelsPerPoint <= 50) {
+ GraphPixelsPerPoint *= 2;
+ }
+ break;
+
+ case Qt::Key_Up:
+ if(GraphPixelsPerPoint >= 0.02) {
+ GraphPixelsPerPoint /= 2;
+ }
+ break;
+
+ case Qt::Key_Right:
+ if(GraphPixelsPerPoint < 20) {
+ GraphStart += (int)(20 / GraphPixelsPerPoint);
+ } else {
+ GraphStart++;
+ }
+ break;
+
+ case Qt::Key_Left:
+ if(GraphPixelsPerPoint < 20) {
+ GraphStart -= (int)(20 / GraphPixelsPerPoint);
+ } else {
+ GraphStart--;
+ }
+ break;
+
+ default:
+ QWidget::keyPressEvent(event);
+ return;
+ break;
+ }
+
+ this->update();
+}
--- /dev/null
+#include <QApplication>
+#include <QPushButton>
+#include <QObject>
+#include <QWidget>
+#include <QPainter>
+
+class ProxWidget : public QWidget
+{
+ Q_OBJECT;
+
+ private:
+ int GraphStart;
+ double GraphPixelsPerPoint;
+ int CursorAPos;
+ int CursorBPos;
+
+ public:
+ ProxWidget(QWidget *parent = 0);
+
+ protected:
+ void paintEvent(QPaintEvent *event);
+ void closeEvent(QCloseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void mousePressEvent(QMouseEvent *event) { mouseMoveEvent(event); }
+ void keyPressEvent(QKeyEvent *event);
+};
+
+class ProxGuiQT : public QObject
+{
+ Q_OBJECT;
+
+ private:
+ QApplication *plotapp;
+ ProxWidget *plotwidget;
+ int argc;
+ char **argv;
+ void (*main_func)(void);
+
+ public:
+ ProxGuiQT(int argc, char **argv);
+ ~ProxGuiQT(void);
+ void ShowGraphWindow(void);
+ void RepaintGraphWindow(void);
+ void HideGraphWindow(void);
+ void MainLoop(void);
+
+ private slots:
+ void _ShowGraphWindow(void);
+ void _RepaintGraphWindow(void);
+ void _HideGraphWindow(void);
+
+ signals:
+ void ShowGraphWindowSignal(void);
+ void RepaintGraphWindowSignal(void);
+ void HideGraphWindowSignal(void);
+};
--- /dev/null
+#include <usb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <errno.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <pthread.h>
+
+#include "translate.h"
+#include "../winsrc/prox.h"
+#include "proxmark3.h"
+#include "proxgui.h"
+
+struct usb_receiver_arg {
+ int run;
+};
+
+static void *usb_receiver(void *targ) {
+ struct usb_receiver_arg *arg = (struct usb_receiver_arg*)targ;
+ UsbCommand cmdbuf;
+
+ while(arg->run) {
+ if (ReceiveCommandP(&cmdbuf) > 0) {
+ int i;
+
+ for (i=0; i<strlen(PROXPROMPT); i++)
+ putchar(0x08);
+
+ UsbCommandReceived(&cmdbuf);
+ printf(PROXPROMPT);
+ fflush(NULL);
+ }
+ }
+
+ pthread_exit(NULL);
+}
+
+static void *main_loop(void *targ)
+{
+ char *cmd = NULL;
+
+ while(1) {
+ struct usb_receiver_arg rarg;
+ pthread_t reader_thread;
+
+ rarg.run=1;
+ pthread_create(&reader_thread, NULL, &usb_receiver, &rarg);
+
+ cmd = readline(PROXPROMPT);
+ rarg.run=0;
+ pthread_join(reader_thread, NULL);
+
+ if (cmd) {
+ if (cmd[0] != 0x00) {
+ CommandReceived(cmd);
+ add_history(cmd);
+ }
+ free(cmd);
+ } else {
+ printf("\n");
+ break;
+ }
+ }
+
+ ExitGraphics();
+ pthread_exit(NULL);
+}
+
+int main(int argc, char **argv)
+{
+ pthread_t main_loop_t;
+ usb_init();
+
+ if (!(devh = OpenProxmark(1))) {
+ fprintf(stderr,"PROXMARK3: NOT FOUND!\n");
+ exit(1);
+ }
+
+ pthread_create(&main_loop_t, NULL, &main_loop, NULL);
+ InitGraphics(argc, argv);
+
+ MainGraphics();
+
+ pthread_join(main_loop_t, NULL);
+
+ CloseProxmark();
+ return 0;
+}
--- /dev/null
+#define PROXPROMPT "proxmark3> "
+
+extern usb_dev_handle *devh;
+extern unsigned char return_on_error;
+extern unsigned char error_occured;
+
+int ReceiveCommandP(UsbCommand *c);
+usb_dev_handle* OpenProxmark(int);
+void CloseProxmark(void);
+
+void setlogfilename(char *fn);
--- /dev/null
+#include <usb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <errno.h>
+
+#include "translate.h"
+#include "../winsrc/prox.h"
+#include "proxmark3.h"
+
+#define HANDLE_ERROR if (error_occured) { \
+ error_occured = 0;\
+ break;\
+}
+
+int main()
+{
+ usb_init();
+ setlogfilename("snooper.log");
+
+ return_on_error = 1;
+
+ while(1) {
+ while(!(devh=OpenProxmark(0))) { sleep(1); }
+
+ while(1) {
+ UsbCommand cmdbuf;
+ int i;
+
+ CommandReceived("hi14asnoop");
+ HANDLE_ERROR
+
+ ReceiveCommand(&cmdbuf);
+ HANDLE_ERROR
+ for (i=0; i<5; i++) {
+ ReceiveCommandP(&cmdbuf);
+ }
+ HANDLE_ERROR
+
+ CommandReceived("hi14alist");
+ HANDLE_ERROR
+ }
+ }
+
+ CloseProxmark();
+ return 0;
+}
--- /dev/null
+#define BYTE unsigned char
+#define WORD unsigned short
+#define DWORD unsigned int
+#define TRUE 1
+#define FALSE 0
+#define BOOL int
+
+#define max(a,b) (((a)>(b))?(a):(b))
+#define min(a,b) (((a)>(b))?(b):(a))
--- /dev/null
+#!/bin/sh
+
+for i in /sys/bus/usb/devices/*; do
+ if grep "9ac4" "${i}/idVendor" >/dev/null 2>&1; then
+ echo "Found Proxmark..."
+ dev=`basename "${i}"`
+
+ for j in /sys/bus/usb/drivers/usbhid/*; do
+ if basename "${j}"|grep "^${dev}" >/dev/null; then
+ bound="`basename "${j}"`"
+ echo "Unbinding ${bound}..."
+ echo -n "${bound}" >/sys/bus/usb/drivers/usbhid/unbind
+ fi
+ done
+ fi
+done
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <usb.h>
+#include <strings.h>
+#include <errno.h>
+
+#include "translate.h"
+#include "../winsrc/prox.h"
+#include "proxmark3.h"
+
+usb_dev_handle *devh = NULL;
+static unsigned int claimed_iface = 0;
+unsigned char return_on_error = 0;
+unsigned char error_occured = 0;
+
+void SendCommand(UsbCommand *c, BOOL wantAck) {
+ int ret;
+
+#if 0
+ printf("Sending %d bytes\n", sizeof(UsbCommand));
+#endif
+ ret = usb_bulk_write(devh, 0x01, (char*)c, sizeof(UsbCommand), 1000);
+ if (ret<0) {
+ error_occured = 1;
+ if (return_on_error)
+ return;
+
+ fprintf(stderr, "write failed: %s!\nTrying to reopen device...\n",
+ usb_strerror());
+
+ if (devh) {
+ usb_close(devh);
+ devh = NULL;
+ }
+ while(!(devh=OpenProxmark(0))) { sleep(1); }
+ printf(PROXPROMPT);
+ fflush(NULL);
+
+ return;
+ }
+
+ if(wantAck) {
+ UsbCommand ack;
+ ReceiveCommand(&ack);
+ if(ack.cmd != CMD_ACK) {
+ printf("bad ACK\n");
+ exit(-1);
+ }
+ }
+}
+
+int ReceiveCommandP(UsbCommand *c) {
+ int ret;
+
+ bzero(c, sizeof(UsbCommand));
+ ret = usb_bulk_read(devh, 0x82, (char*)c, sizeof(UsbCommand), 500);
+ if (ret<0) {
+ if (ret != -ETIMEDOUT) {
+ error_occured = 1;
+ if (return_on_error)
+ return 0;
+
+ fprintf(stderr, "read failed: %s(%d)!\nTrying to reopen device...\n",
+ usb_strerror(), ret);
+
+ if (devh) {
+ usb_close(devh);
+ devh = NULL;
+ }
+ while(!(devh=OpenProxmark(0))) { sleep(1); }
+ printf(PROXPROMPT);
+ fflush(NULL);
+
+ return 0;
+ }
+ } else {
+ if (ret && (ret < sizeof(UsbCommand))) {
+ fprintf(stderr, "Read only %d instead of requested %d bytes!\n",
+ ret, (int)sizeof(UsbCommand));
+ }
+
+#if 0
+ {
+ int i;
+
+ printf("Read %d bytes\n", ret);
+ for (i = 0; i < ret; i++) {
+ printf("0x%02X ", ((unsigned char*)c)[i]);
+ if (!((i+1)%8))
+ printf("\n");
+ }
+ printf("\n");
+ }
+#endif
+ }
+
+ return ret;
+}
+
+void ReceiveCommand(UsbCommand *c) {
+ while(ReceiveCommandP(c)<0) {}
+}
+
+usb_dev_handle* findProxmark(int verbose, unsigned int *iface) {
+ struct usb_bus *busses, *bus;
+ usb_dev_handle *handle = NULL;
+
+ usb_find_busses();
+ usb_find_devices();
+
+ busses = usb_get_busses();
+
+ for (bus = busses; bus; bus = bus->next) {
+ struct usb_device *dev;
+
+ for (dev = bus->devices; dev; dev = dev->next) {
+ struct usb_device_descriptor *desc = &(dev->descriptor);
+
+ if ((desc->idProduct == 0x4b8f) && (desc->idVendor == 0x9ac4)) {
+ handle = usb_open(dev);
+ if (!handle) {
+ if (verbose)
+ fprintf(stderr, "open failed: %s!\n", usb_strerror());
+ return NULL;
+ }
+
+ *iface = dev->config[0].interface[0].altsetting[0].bInterfaceNumber;
+
+ return handle;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+usb_dev_handle* OpenProxmark(int verbose) {
+ int ret;
+ usb_dev_handle *handle = NULL;
+ unsigned int iface;
+
+#ifndef __APPLE__
+ handle = findProxmark(verbose, &iface);
+ if (!handle)
+ return NULL;
+
+ /* Whatever... */
+ usb_reset(handle);
+#endif
+
+ handle = findProxmark(verbose, &iface);
+ if (!handle)
+ return NULL;
+
+ ret = usb_claim_interface(handle, iface);
+ if (ret<0) {
+ if (verbose)
+ fprintf(stderr, "claim failed: %s!\n", usb_strerror());
+ return NULL;
+ }
+
+ claimed_iface = iface;
+ devh = handle;
+ return handle;
+}
+
+void CloseProxmark(void) {
+ usb_release_interface(devh, claimed_iface);
+ usb_close(devh);
+}
--- /dev/null
+BASE_DEFS = /D_WIN32_WINNT=0x501 /DISOLATION_AWARE_ENABLED /D_WIN32_IE=0x600 /DWIN32_LEAN_AND_MEAN /DWIN32 /D_MT /D_CRT_SECURE_NO_WARNINGS\r
+BASE_CFLAGS = /W3 /nologo\r
+\r
+DEFINES = $(BASE_DEFS)\r
+CFLAGS = $(BASE_CFLAGS) /Zi /MT\r
+\r
+OBJDIR = obj\r
+\r
+OBJS = $(OBJDIR)\prox.obj \\r
+ $(OBJDIR)\gui.obj \\r
+ $(OBJDIR)\command.obj\r
+\r
+LIBS = kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setupapi.lib\r
+\r
+HEADERS = prox.h\r
+\r
+all: $(OBJDIR)/prox.exe\r
+ copy $(OBJDIR)\prox.exe .\r
+\r
+clean:\r
+ del /q obj\*.obj\r
+ del /q obj\*.ilk\r
+ del /q obj\*.exe\r
+ del /q obj\*.pdb\r
+ del /q *.pdb\r
+\r
+$(OBJDIR)/prox.exe: $(OBJS)\r
+ $(CC) $(DEFINES) $(CFLAGS) -Fe$(OBJDIR)/prox.exe $(OBJS) $(LIBS)\r
+\r
+$(OBJS): $(@B).cpp $(HEADERS)\r
+ $(CC) $(CFLAGS) $(DEFINES) -c -Fo$(OBJDIR)/$(@B).obj $(@B).cpp\r
--- /dev/null
+//-----------------------------------------------------------------------------\r
+// The actual command interpeter for what the user types at the command line.\r
+// Jonathan Westhues, Sept 2005\r
+// Edits by Gerhard de Koning Gans, Sep 2007 (##)\r
+//-----------------------------------------------------------------------------\r
+#include <windows.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <stdio.h>\r
+#include <limits.h>\r
+#include <math.h>\r
+\r
+#include "prox.h"\r
+#include "../common/iso14443_crc.c"\r
+\r
+#define arraylen(x) (sizeof(x)/sizeof((x)[0]))\r
+\r
+static int CmdHisamplest(char *str, int nrlow);\r
+\r
+static void GetFromBigBuf(BYTE *dest, int bytes)\r
+{\r
+ int n = bytes/4;\r
+\r
+ if(n % 48 != 0) {\r
+ PrintToScrollback("bad len in GetFromBigBuf");\r
+ return;\r
+ }\r
+\r
+ int i;\r
+ for(i = 0; i < n; i += 12) {\r
+ UsbCommand c;\r
+ c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
+ c.ext1 = i;\r
+ SendCommand(&c, FALSE);\r
+ ReceiveCommand(&c);\r
+ if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
+ PrintToScrollback("bad resp\n");\r
+ return;\r
+ }\r
+\r
+ memcpy(dest+(i*4), c.d.asBytes, 48);\r
+ }\r
+}\r
+\r
+static void CmdQuit(char *str)\r
+{\r
+ exit(0);\r
+}\r
+\r
+static void CmdHIDdemodFSK(char *str)\r
+{\r
+ UsbCommand c;\r
+ c.cmd = CMD_HID_DEMOD_FSK;\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdTune(char *str)\r
+{\r
+ UsbCommand c;\r
+ c.cmd = CMD_MEASURE_ANTENNA_TUNING;\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdHi15read(char *str)\r
+{\r
+ UsbCommand c;\r
+ c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693;\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdHi14read(char *str)\r
+{\r
+ UsbCommand c;\r
+ c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;\r
+ c.ext1 = atoi(str);\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+// ## New command\r
+static void CmdHi14areader(char *str)\r
+{\r
+ UsbCommand c;\r
+ c.cmd = CMD_READER_ISO_14443a;\r
+ c.ext1 = atoi(str);\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+// ## New command\r
+static void CmdHi15reader(char *str)\r
+{\r
+ UsbCommand c;\r
+ c.cmd = CMD_READER_ISO_15693;\r
+ c.ext1 = atoi(str);\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+// ## New command\r
+static void CmdHi15tag(char *str)\r
+{\r
+ UsbCommand c;\r
+ c.cmd = CMD_SIMTAG_ISO_15693;\r
+ c.ext1 = atoi(str);\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdHi14read_sim(char *str)\r
+{\r
+ UsbCommand c;\r
+ c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443_SIM;\r
+ c.ext1 = atoi(str);\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdHi14readt(char *str)\r
+{\r
+ UsbCommand c;\r
+ c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;\r
+ c.ext1 = atoi(str);\r
+ SendCommand(&c, FALSE);\r
+\r
+ //CmdHisamplest(str);\r
+ while(CmdHisamplest(str,atoi(str))==0) {\r
+ c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443;\r
+ c.ext1 = atoi(str);\r
+ SendCommand(&c, FALSE);\r
+ }\r
+ RepaintGraphWindow();\r
+}\r
+\r
+static void CmdHisimlisten(char *str)\r
+{\r
+ UsbCommand c;\r
+ c.cmd = CMD_SIMULATE_TAG_HF_LISTEN;\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdHi14sim(char *str)\r
+{\r
+ UsbCommand c;\r
+ c.cmd = CMD_SIMULATE_TAG_ISO_14443;\r
+ SendCommand(&c, FALSE);\r
+}\r
+
+
+\r
+static void CmdHi14asim(char *str) // ## simulate iso14443a tag\r
+{ // ## greg - added ability to specify tag UID\r
+\r
+ unsigned int hi=0, lo=0;\r
+ int n=0, i=0;\r
+ UsbCommand c;\r
+\r
+ while (sscanf(&str[i++], "%1x", &n ) == 1) {\r
+ hi=(hi<<4)|(lo>>28);\r
+ lo=(lo<<4)|(n&0xf);\r
+ }\r
+\r
+ c.cmd = CMD_SIMULATE_TAG_ISO_14443a;\r
+ // c.ext should be set to *str or convert *str to the correct format for a uid\r
+ c.ext1 = hi;\r
+ c.ext2 = lo;\r
+ PrintToScrollback("Emulating 14443A TAG with UID %x%16x", hi, lo);\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdHi14snoop(char *str)\r
+{\r
+ UsbCommand c;\r
+ c.cmd = CMD_SNOOP_ISO_14443;\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdHi14asnoop(char *str)\r
+{\r
+ UsbCommand c;\r
+ c.cmd = CMD_SNOOP_ISO_14443a;\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdFPGAOff(char *str) // ## FPGA Control\r
+{\r
+ UsbCommand c;\r
+ c.cmd = CMD_FPGA_MAJOR_MODE_OFF;\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdLosim(char *str)\r
+{\r
+ int i;\r
+\r
+ for(i = 0; i < GraphTraceLen; i += 48) {\r
+ UsbCommand c;\r
+ int j;\r
+ for(j = 0; j < 48; j++) {\r
+ c.d.asBytes[j] = GraphBuffer[i+j];\r
+ }\r
+ c.cmd = CMD_DOWNLOADED_SIM_SAMPLES_125K;\r
+ c.ext1 = i;\r
+ SendCommand(&c, FALSE);\r
+ }\r
+\r
+ UsbCommand c;\r
+ c.cmd = CMD_SIMULATE_TAG_125K;\r
+ c.ext1 = GraphTraceLen;\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdLoread(char *str)\r
+{\r
+ UsbCommand c;\r
+ // 'h' means higher-low-frequency, 134 kHz\r
+ if(*str == 'h') {\r
+ c.ext1 = 1;\r
+ } else if (*str == '\0') {\r
+ c.ext1 = 0;\r
+ } else {\r
+ PrintToScrollback("use 'loread' or 'loread h'");\r
+ return;\r
+ }\r
+ c.cmd = CMD_ACQUIRE_RAW_ADC_SAMPLES_125K;\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdLosamples(char *str)\r
+{\r
+ int cnt = 0;\r
+ int i;\r
+ int n;\r
+\r
+ n=atoi(str);\r
+ if (n==0) n=128;\r
+ if (n>16000) n=16000;\r
+\r
+ for(i = 0; i < n; i += 12) {\r
+ UsbCommand c;\r
+ c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
+ c.ext1 = i;\r
+ SendCommand(&c, FALSE);\r
+ ReceiveCommand(&c);\r
+ if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
+ PrintToScrollback("bad resp\n");\r
+ return;\r
+ }\r
+ int j;\r
+ for(j = 0; j < 48; j++) {\r
+ GraphBuffer[cnt++] = ((int)c.d.asBytes[j]) - 128;\r
+ }\r
+ }\r
+ GraphTraceLen = n*4;\r
+ RepaintGraphWindow();\r
+}\r
+\r
+static void CmdBitsamples(char *str)\r
+{\r
+ int cnt = 0;\r
+ int i;\r
+ int n;\r
+\r
+ n = 3072;\r
+ for(i = 0; i < n; i += 12) {\r
+ UsbCommand c;\r
+ c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
+ c.ext1 = i;\r
+ SendCommand(&c, FALSE);\r
+ ReceiveCommand(&c);\r
+ if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
+ PrintToScrollback("bad resp\n");\r
+ return;\r
+ }\r
+ int j, k;\r
+ for(j = 0; j < 48; j++) {\r
+ for(k = 0; k < 8; k++) {\r
+ if(c.d.asBytes[j] & (1 << (7 - k))) {\r
+ GraphBuffer[cnt++] = 1;\r
+ } else {\r
+ GraphBuffer[cnt++] = 0;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ GraphTraceLen = cnt;\r
+ RepaintGraphWindow();\r
+}\r
+\r
+static void CmdHisamples(char *str)\r
+{\r
+ int cnt = 0;\r
+ int i;\r
+ int n;\r
+ n = 1000;\r
+ for(i = 0; i < n; i += 12) {\r
+ UsbCommand c;\r
+ c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
+ c.ext1 = i;\r
+ SendCommand(&c, FALSE);\r
+ ReceiveCommand(&c);\r
+ if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
+ PrintToScrollback("bad resp\n");\r
+ return;\r
+ }\r
+ int j;\r
+ for(j = 0; j < 48; j++) {\r
+ GraphBuffer[cnt++] = (int)((BYTE)c.d.asBytes[j]);\r
+ }\r
+ }\r
+ GraphTraceLen = n*4;\r
+\r
+ RepaintGraphWindow();\r
+}\r
+\r
+\r
+static int CmdHisamplest(char *str, int nrlow)\r
+{\r
+ int cnt = 0;\r
+ int t1, t2;\r
+ int i;\r
+ int n;\r
+ int hasbeennull;\r
+ int show;\r
+\r
+\r
+ n = 1000;\r
+ hasbeennull = 0;\r
+ for(i = 0; i < n; i += 12) {\r
+ UsbCommand c;\r
+ c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
+ c.ext1 = i;\r
+ SendCommand(&c, FALSE);\r
+ ReceiveCommand(&c);\r
+ if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
+ PrintToScrollback("bad resp\n");\r
+ return 0;\r
+ }\r
+ int j;\r
+ for(j = 0; j < 48; j++) {\r
+ t2 = (int)((BYTE)c.d.asBytes[j]);\r
+ if((t2 ^ 0xC0) & 0xC0) { hasbeennull++; }\r
+\r
+ show = 0;\r
+ switch(show) {\r
+ case 0:\r
+ // combined\r
+ t1 = (t2 & 0x80) ^ (t2 & 0x20);\r
+ t2 = ((t2 << 1) & 0x80) ^ ((t2 << 1) & 0x20);\r
+ break;\r
+\r
+ case 1:\r
+ // only reader\r
+ t1 = (t2 & 0x80);\r
+ t2 = ((t2 << 1) & 0x80);\r
+ break;\r
+\r
+ case 2:\r
+ // only tag\r
+ t1 = (t2 & 0x20);\r
+ t2 = ((t2 << 1) & 0x20);\r
+ break;\r
+\r
+ case 3:\r
+ // both, but tag with other algorithm\r
+ t1 = (t2 & 0x80) ^ (t2 & 0x08);\r
+ t2 = ((t2 << 1) & 0x80) ^ ((t2 << 1) & 0x08);\r
+ break;\r
+ }\r
+\r
+ GraphBuffer[cnt++] = t1;\r
+ GraphBuffer[cnt++] = t2;\r
+ }\r
+ }\r
+ GraphTraceLen = n*4;\r
+// 1130\r
+ if(hasbeennull>nrlow || nrlow==0) {\r
+ PrintToScrollback("hasbeennull=%d", hasbeennull);\r
+ return 1;\r
+ }\r
+ else {\r
+ return 0;\r
+ }\r
+}\r
+\r
+\r
+static void CmdHexsamples(char *str)\r
+{\r
+ int i;\r
+ int n;\r
+\r
+ if(atoi(str) == 0) {\r
+ n = 12;\r
+ } else {\r
+ n = atoi(str)/4;\r
+ }\r
+\r
+ for(i = 0; i < n; i += 12) {\r
+ UsbCommand c;\r
+ c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
+ c.ext1 = i;\r
+ SendCommand(&c, FALSE);\r
+ ReceiveCommand(&c);\r
+ if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
+ PrintToScrollback("bad resp\n");\r
+ return;\r
+ }\r
+ int j;\r
+ for(j = 0; j < 48; j += 8) {\r
+ PrintToScrollback("%02x %02x %02x %02x %02x %02x %02x %02x",\r
+ c.d.asBytes[j+0],\r
+ c.d.asBytes[j+1],\r
+ c.d.asBytes[j+2],\r
+ c.d.asBytes[j+3],\r
+ c.d.asBytes[j+4],\r
+ c.d.asBytes[j+5],\r
+ c.d.asBytes[j+6],\r
+ c.d.asBytes[j+7],\r
+ c.d.asBytes[j+8]\r
+ );\r
+ }\r
+ }\r
+}\r
+\r
+static void CmdHisampless(char *str)\r
+{\r
+ int cnt = 0;\r
+ int i;\r
+ int n;\r
+\r
+ if(atoi(str) == 0) {\r
+ n = 1000;\r
+ } else {\r
+ n = atoi(str)/4;\r
+ }\r
+\r
+ for(i = 0; i < n; i += 12) {\r
+ UsbCommand c;\r
+ c.cmd = CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K;\r
+ c.ext1 = i;\r
+ SendCommand(&c, FALSE);\r
+ ReceiveCommand(&c);\r
+ if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {\r
+ PrintToScrollback("bad resp\n");\r
+ return;\r
+ }\r
+ int j;\r
+ for(j = 0; j < 48; j++) {\r
+ GraphBuffer[cnt++] = (int)((signed char)c.d.asBytes[j]);\r
+ }\r
+ }\r
+ GraphTraceLen = cnt;\r
+\r
+ RepaintGraphWindow();\r
+}\r
+\r
+static WORD Iso15693Crc(BYTE *v, int n)\r
+{\r
+ DWORD reg;\r
+ int i, j;\r
+\r
+ reg = 0xffff;\r
+ for(i = 0; i < n; i++) {\r
+ reg = reg ^ ((DWORD)v[i]);\r
+ for (j = 0; j < 8; j++) {\r
+ if (reg & 0x0001) {\r
+ reg = (reg >> 1) ^ 0x8408;\r
+ } else {\r
+ reg = (reg >> 1);\r
+ }\r
+ }\r
+ }\r
+\r
+ return (WORD)~reg;\r
+}\r
+\r
+static void CmdHi14bdemod(char *str)\r
+{\r
+ int i, j, iold;\r
+ int isum, qsum;\r
+ int outOfWeakAt;\r
+ BOOL negateI, negateQ;\r
+\r
+ BYTE data[256];\r
+ int dataLen=0;\r
+\r
+ // As received, the samples are pairs, correlations against I and Q\r
+ // square waves. So estimate angle of initial carrier (or just\r
+ // quadrant, actually), and then do the demod.\r
+\r
+ // First, estimate where the tag starts modulating.\r
+ for(i = 0; i < GraphTraceLen; i += 2) {\r
+ if(abs(GraphBuffer[i]) + abs(GraphBuffer[i+1]) > 40) {\r
+ break;\r
+ }\r
+ }\r
+ if(i >= GraphTraceLen) {\r
+ PrintToScrollback("too weak to sync");\r
+ return;\r
+ }\r
+ PrintToScrollback("out of weak at %d", i);\r
+ outOfWeakAt = i;\r
+\r
+ // Now, estimate the phase in the initial modulation of the tag\r
+ isum = 0;\r
+ qsum = 0;\r
+ for(; i < (outOfWeakAt + 16); i += 2) {\r
+ isum += GraphBuffer[i+0];\r
+ qsum += GraphBuffer[i+1];\r
+ }\r
+ negateI = (isum < 0);\r
+ negateQ = (qsum < 0);\r
+\r
+ // Turn the correlation pairs into soft decisions on the bit.\r
+ j = 0;\r
+ for(i = 0; i < GraphTraceLen/2; i++) {\r
+ int si = GraphBuffer[j];\r
+ int sq = GraphBuffer[j+1];\r
+ if(negateI) si = -si;\r
+ if(negateQ) sq = -sq;\r
+ GraphBuffer[i] = si + sq;\r
+ j += 2;\r
+ }\r
+ GraphTraceLen = i;\r
+\r
+ i = outOfWeakAt/2;\r
+ while(GraphBuffer[i] > 0 && i < GraphTraceLen)\r
+ i++;\r
+ if(i >= GraphTraceLen) goto demodError;\r
+\r
+ iold = i;\r
+ while(GraphBuffer[i] < 0 && i < GraphTraceLen)\r
+ i++;\r
+ if(i >= GraphTraceLen) goto demodError;\r
+ if((i - iold) > 23) goto demodError;\r
+\r
+ PrintToScrollback("make it to demod loop");\r
+\r
+ for(;;) {\r
+ iold = i;\r
+ while(GraphBuffer[i] >= 0 && i < GraphTraceLen)\r
+ i++;\r
+ if(i >= GraphTraceLen) goto demodError;\r
+ if((i - iold) > 6) goto demodError;\r
+\r
+ WORD shiftReg = 0;\r
+ if(i + 20 >= GraphTraceLen) goto demodError;\r
+\r
+ for(j = 0; j < 10; j++) {\r
+ int soft = GraphBuffer[i] + GraphBuffer[i+1];\r
+\r
+ if(abs(soft) < ((abs(isum) + abs(qsum))/20)) {\r
+ PrintToScrollback("weak bit");\r
+ }\r
+\r
+ shiftReg >>= 1;\r
+ if(GraphBuffer[i] + GraphBuffer[i+1] >= 0) {\r
+ shiftReg |= 0x200;\r
+ }\r
+\r
+ i+= 2;\r
+ }\r
+\r
+ if( (shiftReg & 0x200) &&\r
+ !(shiftReg & 0x001))\r
+ {\r
+ // valid data byte, start and stop bits okay\r
+ PrintToScrollback(" %02x", (shiftReg >> 1) & 0xff);\r
+ data[dataLen++] = (shiftReg >> 1) & 0xff;\r
+ if(dataLen >= sizeof(data)) {\r
+ return;\r
+ }\r
+ } else if(shiftReg == 0x000) {\r
+ // this is EOF\r
+ break;\r
+ } else {\r
+ goto demodError;\r
+ }\r
+ }\r
+\r
+ BYTE first, second;\r
+ ComputeCrc14443(CRC_14443_B, data, dataLen-2, &first, &second);\r
+ PrintToScrollback("CRC: %02x %02x (%s)\n", first, second,\r
+ (first == data[dataLen-2] && second == data[dataLen-1]) ?\r
+ "ok" : "****FAIL****");\r
+\r
+ RepaintGraphWindow();\r
+ return;\r
+\r
+demodError:\r
+ PrintToScrollback("demod error");\r
+ RepaintGraphWindow();\r
+}\r
+\r
+static void CmdHi14list(char *str)\r
+{\r
+ BYTE got[960];\r
+ GetFromBigBuf(got, sizeof(got));\r
+\r
+ PrintToScrollback("recorded activity:");\r
+ PrintToScrollback(" time :rssi: who bytes");\r
+ PrintToScrollback("---------+----+----+-----------");\r
+\r
+ int i = 0;\r
+ int prev = -1;\r
+\r
+ for(;;) {\r
+ if(i >= 900) {\r
+ break;\r
+ }\r
+\r
+ BOOL isResponse;\r
+ int timestamp = *((DWORD *)(got+i));\r
+ if(timestamp & 0x80000000) {\r
+ timestamp &= 0x7fffffff;\r
+ isResponse = 1;\r
+ } else {\r
+ isResponse = 0;\r
+ }\r
+ int metric = *((DWORD *)(got+i+4));\r
+\r
+ int len = got[i+8];\r
+\r
+ if(len > 100) {\r
+ break;\r
+ }\r
+ if(i + len >= 900) {\r
+ break;\r
+ }\r
+\r
+ BYTE *frame = (got+i+9);\r
+\r
+ char line[1000] = "";\r
+ int j;\r
+ for(j = 0; j < len; j++) {\r
+ sprintf(line+(j*3), "%02x ", frame[j]);\r
+ }\r
+\r
+ char *crc;\r
+ if(len > 2) {\r
+ BYTE b1, b2;\r
+ ComputeCrc14443(CRC_14443_B, frame, len-2, &b1, &b2);\r
+ if(b1 != frame[len-2] || b2 != frame[len-1]) {\r
+ crc = "**FAIL CRC**";\r
+ } else {\r
+ crc = "";\r
+ }\r
+ } else {\r
+ crc = "(SHORT)";\r
+ }\r
+\r
+ char metricString[100];\r
+ if(isResponse) {\r
+ sprintf(metricString, "%3d", metric);\r
+ } else {\r
+ strcpy(metricString, " ");\r
+ }\r
+\r
+ PrintToScrollback(" +%7d: %s: %s %s %s",\r
+ (prev < 0 ? 0 : timestamp - prev),\r
+ metricString,\r
+ (isResponse ? "TAG" : " "), line, crc);\r
+\r
+ prev = timestamp;\r
+ i += (len + 9);\r
+ }\r
+}\r
+\r
+static void CmdHi14alist(char *str)\r
+{\r
+ BYTE got[1920];\r
+ GetFromBigBuf(got, sizeof(got));\r
+\r
+ PrintToScrollback("recorded activity:");\r
+ PrintToScrollback(" ETU :rssi: who bytes");\r
+ PrintToScrollback("---------+----+----+-----------");\r
+\r
+ int i = 0;\r
+ int prev = -1;\r
+\r
+ for(;;) {\r
+ if(i >= 1900) {\r
+ break;\r
+ }\r
+\r
+ BOOL isResponse;\r
+ int timestamp = *((DWORD *)(got+i));\r
+ if(timestamp & 0x80000000) {\r
+ timestamp &= 0x7fffffff;\r
+ isResponse = 1;\r
+ } else {\r
+ isResponse = 0;\r
+ }\r
+\r
+ int metric = 0;\r
+ int parityBits = *((DWORD *)(got+i+4));\r
+ // 4 bytes of additional information...\r
+ // maximum of 32 additional parity bit information\r
+ //\r
+ // TODO:\r
+ // at each quarter bit period we can send power level (16 levels)\r
+ // or each half bit period in 256 levels.\r
+\r
+\r
+ int len = got[i+8];\r
+\r
+ if(len > 100) {\r
+ break;\r
+ }\r
+ if(i + len >= 1900) {\r
+ break;\r
+ }\r
+\r
+ BYTE *frame = (got+i+9);\r
+\r
+ // Break and stick with current result if buffer was not completely full\r
+ if(frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; }\r
+\r
+ char line[1000] = "";\r
+ int j;\r
+ for(j = 0; j < len; j++) {\r
+ int oddparity = 0x01;\r
+ int k;\r
+\r
+ for(k=0;k<8;k++) {\r
+ oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01);\r
+ }\r
+\r
+ //if((parityBits >> (len - j - 1)) & 0x01) {\r
+ if(isResponse && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) {\r
+ sprintf(line+(j*4), "%02x! ", frame[j]);\r
+ }\r
+ else {\r
+ sprintf(line+(j*4), "%02x ", frame[j]);\r
+ }\r
+ }\r
+\r
+ char *crc;\r
+ crc = "";\r
+ if(len > 2) {\r
+ BYTE b1, b2;\r
+ for(j = 0; j < (len - 1); j++) {\r
+ // gives problems... search for the reason..\r
+ /*if(frame[j] == 0xAA) {\r
+ switch(frame[j+1]) {\r
+ case 0x01:\r
+ crc = "[1] Two drops close after each other";\r
+ break;\r
+ case 0x02:\r
+ crc = "[2] Potential SOC with a drop in second half of bitperiod";\r
+ break;\r
+ case 0x03:\r
+ crc = "[3] Segment Z after segment X is not possible";\r
+ break;\r
+ case 0x04:\r
+ crc = "[4] Parity bit of a fully received byte was wrong";\r
+ break;\r
+ default:\r
+ crc = "[?] Unknown error";\r
+ break;\r
+ }\r
+ break;\r
+ }*/\r
+ }\r
+\r
+ if(strlen(crc)==0) {\r
+ ComputeCrc14443(CRC_14443_A, frame, len-2, &b1, &b2);\r
+ if(b1 != frame[len-2] || b2 != frame[len-1]) {\r
+ crc = (isResponse & (len < 6)) ? "" : " !crc";\r
+ } else {\r
+ crc = "";\r
+ }\r
+ }\r
+ } else {\r
+ crc = ""; // SHORT\r
+ }\r
+\r
+ char metricString[100];\r
+ if(isResponse) {\r
+ sprintf(metricString, "%3d", metric);\r
+ } else {\r
+ strcpy(metricString, " ");\r
+ }\r
+\r
+ PrintToScrollback(" +%7d: %s: %s %s %s",\r
+ (prev < 0 ? 0 : (timestamp - prev)),\r
+ metricString,\r
+ (isResponse ? "TAG" : " "), line, crc);\r
+\r
+ prev = timestamp;\r
+ i += (len + 9);\r
+ }\r
+ CommandFinished = 1;\r
+}\r
+\r
+static void CmdHi15demod(char *str)\r
+{\r
+ // The sampling rate is 106.353 ksps/s, for T = 18.8 us\r
+\r
+ // SOF defined as \r
+ // 1) Unmodulated time of 56.64us\r
+ // 2) 24 pulses of 423.75khz\r
+ // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)\r
+\r
+ static const int FrameSOF[] = {\r
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ -1, -1, -1, -1,\r
+ -1, -1, -1, -1,\r
+ 1, 1, 1, 1,\r
+ 1, 1, 1, 1\r
+ };\r
+ static const int Logic0[] = {\r
+ 1, 1, 1, 1,\r
+ 1, 1, 1, 1,\r
+ -1, -1, -1, -1,\r
+ -1, -1, -1, -1\r
+ };\r
+ static const int Logic1[] = {\r
+ -1, -1, -1, -1,\r
+ -1, -1, -1, -1,\r
+ 1, 1, 1, 1,\r
+ 1, 1, 1, 1\r
+ };\r
+\r
+ // EOF defined as \r
+ // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)\r
+ // 2) 24 pulses of 423.75khz\r
+ // 3) Unmodulated time of 56.64us\r
+\r
+ static const int FrameEOF[] = {\r
+ 1, 1, 1, 1,\r
+ 1, 1, 1, 1,\r
+ -1, -1, -1, -1,\r
+ -1, -1, -1, -1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\r
+ };\r
+\r
+ int i, j;\r
+ int max = 0, maxPos;\r
+\r
+ int skip = 4;\r
+\r
+ if(GraphTraceLen < 1000) return;\r
+\r
+ // First, correlate for SOF\r
+ for(i = 0; i < 100; i++) {\r
+ int corr = 0;\r
+ for(j = 0; j < arraylen(FrameSOF); j += skip) {\r
+ corr += FrameSOF[j]*GraphBuffer[i+(j/skip)];\r
+ }\r
+ if(corr > max) {\r
+ max = corr;\r
+ maxPos = i;\r
+ }\r
+ }\r
+ PrintToScrollback("SOF at %d, correlation %d", maxPos,\r
+ max/(arraylen(FrameSOF)/skip));\r
+\r
+ i = maxPos + arraylen(FrameSOF)/skip;\r
+ int k = 0;\r
+ BYTE outBuf[20];\r
+ memset(outBuf, 0, sizeof(outBuf));\r
+ BYTE mask = 0x01;\r
+ for(;;) {\r
+ int corr0 = 0, corr1 = 0, corrEOF = 0;\r
+ for(j = 0; j < arraylen(Logic0); j += skip) {\r
+ corr0 += Logic0[j]*GraphBuffer[i+(j/skip)];\r
+ }\r
+ for(j = 0; j < arraylen(Logic1); j += skip) {\r
+ corr1 += Logic1[j]*GraphBuffer[i+(j/skip)];\r
+ }\r
+ for(j = 0; j < arraylen(FrameEOF); j += skip) {\r
+ corrEOF += FrameEOF[j]*GraphBuffer[i+(j/skip)];\r
+ }\r
+ // Even things out by the length of the target waveform.\r
+ corr0 *= 4;\r
+ corr1 *= 4;\r
+\r
+ if(corrEOF > corr1 && corrEOF > corr0) {\r
+ PrintToScrollback("EOF at %d", i);\r
+ break;\r
+ } else if(corr1 > corr0) {\r
+ i += arraylen(Logic1)/skip;\r
+ outBuf[k] |= mask;\r
+ } else {\r
+ i += arraylen(Logic0)/skip;\r
+ }\r
+ mask <<= 1;\r
+ if(mask == 0) {\r
+ k++;\r
+ mask = 0x01;\r
+ }\r
+ if((i+(int)arraylen(FrameEOF)) >= GraphTraceLen) {\r
+ PrintToScrollback("ran off end!");\r
+ break;\r
+ }\r
+ }\r
+ if(mask != 0x01) {\r
+ PrintToScrollback("error, uneven octet! (discard extra bits!)");\r
+ PrintToScrollback(" mask=%02x", mask);\r
+ }\r
+ PrintToScrollback("%d octets", k);\r
+\r
+ for(i = 0; i < k; i++) {\r
+ PrintToScrollback("# %2d: %02x ", i, outBuf[i]);\r
+ }\r
+ PrintToScrollback("CRC=%04x", Iso15693Crc(outBuf, k-2));\r
+}\r
+\r
+static void CmdTiread(char *str)\r
+{\r
+ UsbCommand c;\r
+ c.cmd = CMD_ACQUIRE_RAW_BITS_TI_TYPE;\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdTibits(char *str)\r
+{\r
+ int cnt = 0;\r
+ int i;\r
+ for(i = 0; i < 1536; i += 12) {\r
+ UsbCommand c;\r
+ c.cmd = CMD_DOWNLOAD_RAW_BITS_TI_TYPE;\r
+ c.ext1 = i;\r
+ SendCommand(&c, FALSE);\r
+ ReceiveCommand(&c);\r
+ if(c.cmd != CMD_DOWNLOADED_RAW_BITS_TI_TYPE) {\r
+ PrintToScrollback("bad resp\n");\r
+ return;\r
+ }\r
+ int j;\r
+ for(j = 0; j < 12; j++) {\r
+ int k;\r
+ for(k = 31; k >= 0; k--) {\r
+ if(c.d.asDwords[j] & (1 << k)) {\r
+ GraphBuffer[cnt++] = 1;\r
+ } else {\r
+ GraphBuffer[cnt++] = -1;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ GraphTraceLen = 1536*32;\r
+ RepaintGraphWindow();\r
+}\r
+\r
+static void CmdTidemod(char *cmdline)\r
+{\r
+ /* MATLAB as follows:\r
+f_s = 2000000; % sampling frequency\r
+f_l = 123200; % low FSK tone\r
+f_h = 134200; % high FSK tone\r
+\r
+T_l = 119e-6; % low bit duration\r
+T_h = 130e-6; % high bit duration\r
+\r
+l = 2*pi*ones(1, floor(f_s*T_l))*(f_l/f_s);\r
+h = 2*pi*ones(1, floor(f_s*T_h))*(f_h/f_s);\r
+\r
+l = sign(sin(cumsum(l)));\r
+h = sign(sin(cumsum(h)));\r
+ */\r
+ static const int LowTone[] = {\r
+ 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1,\r
+ 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1,\r
+ -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1,\r
+ -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1,\r
+ -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1,\r
+ 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1,\r
+ 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1,\r
+ -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1,\r
+ -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,\r
+ -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1,\r
+ 1, 1, 1, 1, 1, 1, 1, -1, -1, -1,\r
+ };\r
+ static const int HighTone[] = {\r
+ 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,\r
+ -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
+ -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1,\r
+ 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
+ 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1,\r
+ -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
+ -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,\r
+ -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,\r
+ -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1,\r
+ 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1,\r
+ 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1,\r
+ };\r
+\r
+ int convLen = max(arraylen(HighTone), arraylen(LowTone));\r
+\r
+ int i;\r
+ for(i = 0; i < GraphTraceLen - convLen; i++) {\r
+ int j;\r
+ int lowSum = 0, highSum = 0;;\r
+ int lowLen = arraylen(LowTone);\r
+ int highLen = arraylen(HighTone);\r
+\r
+ for(j = 0; j < lowLen; j++) {\r
+ lowSum += LowTone[j]*GraphBuffer[i+j];\r
+ }\r
+ for(j = 0; j < highLen; j++) {\r
+ highSum += HighTone[j]*GraphBuffer[i+j];\r
+ }\r
+ lowSum = abs((100*lowSum) / lowLen);\r
+ highSum = abs((100*highSum) / highLen);\r
+ GraphBuffer[i] = (highSum << 16) | lowSum;\r
+ }\r
+\r
+ for(i = 0; i < GraphTraceLen - convLen - 16; i++) {\r
+ int j;\r
+ int lowTot = 0, highTot = 0;\r
+ // 16 and 15 are f_s divided by f_l and f_h, rounded\r
+ for(j = 0; j < 16; j++) {\r
+ lowTot += (GraphBuffer[i+j] & 0xffff);\r
+ }\r
+ for(j = 0; j < 15; j++) {\r
+ highTot += (GraphBuffer[i+j] >> 16);\r
+ }\r
+ GraphBuffer[i] = lowTot - highTot;\r
+ }\r
+\r
+ GraphTraceLen -= (convLen + 16);\r
+\r
+ RepaintGraphWindow();\r
+\r
+ // Okay, so now we have unsliced soft decisions; find bit-sync, and then\r
+ // get some bits.\r
+\r
+ int max = 0, maxPos = 0;\r
+ for(i = 0; i < 6000; i++) {\r
+ int j;\r
+ int dec = 0;\r
+ for(j = 0; j < 8*arraylen(LowTone); j++) {\r
+ dec -= GraphBuffer[i+j];\r
+ }\r
+ for(; j < 8*arraylen(LowTone) + 8*arraylen(HighTone); j++) {\r
+ dec += GraphBuffer[i+j];\r
+ }\r
+ if(dec > max) {\r
+ max = dec;\r
+ maxPos = i;\r
+ }\r
+ }\r
+ GraphBuffer[maxPos] = 800;\r
+ GraphBuffer[maxPos+1] = -800;\r
+\r
+ maxPos += 8*arraylen(LowTone);\r
+ GraphBuffer[maxPos] = 800;\r
+ GraphBuffer[maxPos+1] = -800;\r
+ maxPos += 8*arraylen(HighTone);\r
+\r
+ GraphBuffer[maxPos] = 800;\r
+ GraphBuffer[maxPos+1] = -800;\r
+\r
+ PrintToScrollback("actual data bits start at sample %d", maxPos);\r
+\r
+ PrintToScrollback("length %d/%d", arraylen(HighTone), arraylen(LowTone));\r
+\r
+ GraphBuffer[maxPos] = 800;\r
+ GraphBuffer[maxPos+1] = -800;\r
+\r
+ BYTE bits[64+16+8+1];\r
+ bits[sizeof(bits)-1] = '\0';\r
+\r
+ for(i = 0; i < arraylen(bits); i++) {\r
+ int high = 0;\r
+ int low = 0;\r
+ int j;\r
+ for(j = 0; j < arraylen(LowTone); j++) {\r
+ low -= GraphBuffer[maxPos+j];\r
+ }\r
+ for(j = 0; j < arraylen(HighTone); j++) {\r
+ high += GraphBuffer[maxPos+j];\r
+ }\r
+ if(high > low) {\r
+ bits[i] = '1';\r
+ maxPos += arraylen(HighTone);\r
+ } else {\r
+ bits[i] = '.';\r
+ maxPos += arraylen(LowTone);\r
+ }\r
+ GraphBuffer[maxPos] = 800;\r
+ GraphBuffer[maxPos+1] = -800;\r
+ }\r
+ PrintToScrollback("bits: '%s'", bits);\r
+\r
+ DWORD h = 0, l = 0;\r
+ for(i = 0; i < 32; i++) {\r
+ if(bits[i] == '1') {\r
+ l |= (1<<i);\r
+ }\r
+ }\r
+ for(i = 32; i < 64; i++) {\r
+ if(bits[i] == '1') {\r
+ h |= (1<<(i-32));\r
+ }\r
+ }\r
+ PrintToScrollback("hex: %08x %08x", h, l);\r
+}\r
+\r
+static void CmdNorm(char *str)\r
+{\r
+ int i;\r
+ int max = INT_MIN, min = INT_MAX;\r
+ for(i = 10; i < GraphTraceLen; i++) {\r
+ if(GraphBuffer[i] > max) {\r
+ max = GraphBuffer[i];\r
+ }\r
+ if(GraphBuffer[i] < min) {\r
+ min = GraphBuffer[i];\r
+ }\r
+ }\r
+ if(max != min) {\r
+ for(i = 0; i < GraphTraceLen; i++) {\r
+ GraphBuffer[i] = (GraphBuffer[i] - ((max + min)/2))*1000/\r
+ (max - min);\r
+ }\r
+ }\r
+ RepaintGraphWindow();\r
+}\r
+\r
+static void CmdDec(char *str)\r
+{\r
+ int i;\r
+ for(i = 0; i < (GraphTraceLen/2); i++) {\r
+ GraphBuffer[i] = GraphBuffer[i*2];\r
+ }\r
+ GraphTraceLen /= 2;\r
+ PrintToScrollback("decimated by 2");\r
+ RepaintGraphWindow();\r
+}\r
+\r
+static void CmdHpf(char *str)\r
+{\r
+ int i;\r
+ int accum = 0;\r
+ for(i = 10; i < GraphTraceLen; i++) {\r
+ accum += GraphBuffer[i];\r
+ }\r
+ accum /= (GraphTraceLen - 10);\r
+ for(i = 0; i < GraphTraceLen; i++) {\r
+ GraphBuffer[i] -= accum;\r
+ }\r
+\r
+ RepaintGraphWindow();\r
+}\r
+\r
+static void CmdZerocrossings(char *str)\r
+{\r
+ int i;\r
+ // Zero-crossings aren't meaningful unless the signal is zero-mean.\r
+ CmdHpf("");\r
+\r
+ int sign = 1;\r
+ int zc = 0;\r
+ int lastZc = 0;\r
+ for(i = 0; i < GraphTraceLen; i++) {\r
+ if(GraphBuffer[i]*sign >= 0) {\r
+ // No change in sign, reproduce the previous sample count.\r
+ zc++;\r
+ GraphBuffer[i] = lastZc;\r
+ } else {\r
+ // Change in sign, reset the sample count.\r
+ sign = -sign;\r
+ GraphBuffer[i] = lastZc;\r
+ if(sign > 0) {\r
+ lastZc = zc;\r
+ zc = 0;\r
+ }\r
+ }\r
+ }\r
+\r
+ RepaintGraphWindow();\r
+}\r
+\r
+static void CmdLtrim(char *str)\r
+{\r
+ int i;\r
+ int ds = atoi(str);\r
+\r
+ for(i = ds; i < GraphTraceLen; i++) {\r
+ GraphBuffer[i-ds] = GraphBuffer[i];\r
+ }\r
+ GraphTraceLen -= ds;\r
+\r
+ RepaintGraphWindow();\r
+}\r
+\r
+static void CmdAutoCorr(char *str)\r
+{\r
+ static int CorrelBuffer[MAX_GRAPH_TRACE_LEN];\r
+\r
+ int window = atoi(str);\r
+\r
+ if(window == 0) {\r
+ PrintToScrollback("needs a window");\r
+ return;\r
+ }\r
+\r
+ if(window >= GraphTraceLen) {\r
+ PrintToScrollback("window must be smaller than trace (%d samples)",\r
+ GraphTraceLen);\r
+ return;\r
+ }\r
+\r
+ PrintToScrollback("performing %d correlations", GraphTraceLen - window);\r
+\r
+ int i;\r
+ for(i = 0; i < GraphTraceLen - window; i++) {\r
+ int sum = 0;\r
+ int j;\r
+ for(j = 0; j < window; j++) {\r
+ sum += (GraphBuffer[j]*GraphBuffer[i+j]) / 256;\r
+ }\r
+ CorrelBuffer[i] = sum;\r
+ }\r
+ GraphTraceLen = GraphTraceLen - window;\r
+ memcpy(GraphBuffer, CorrelBuffer, GraphTraceLen*sizeof(int));\r
+\r
+ RepaintGraphWindow();\r
+}\r
+\r
+static void CmdVchdemod(char *str)\r
+{\r
+ // Is this the entire sync pattern, or does this also include some\r
+ // data bits that happen to be the same everywhere? That would be\r
+ // lovely to know.\r
+ static const int SyncPattern[] = {\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
+ };\r
+\r
+ // So first, we correlate for the sync pattern, and mark that.\r
+ int bestCorrel = 0, bestPos = 0;\r
+ int i;\r
+ // It does us no good to find the sync pattern, with fewer than\r
+ // 2048 samples after it...\r
+ for(i = 0; i < (GraphTraceLen-2048); i++) {\r
+ int sum = 0;\r
+ int j;\r
+ for(j = 0; j < arraylen(SyncPattern); j++) {\r
+ sum += GraphBuffer[i+j]*SyncPattern[j];\r
+ }\r
+ if(sum > bestCorrel) {\r
+ bestCorrel = sum;\r
+ bestPos = i;\r
+ }\r
+ }\r
+ PrintToScrollback("best sync at %d [metric %d]", bestPos, bestCorrel);\r
+\r
+ char bits[257];\r
+ bits[256] = '\0';\r
+\r
+ int worst = INT_MAX;\r
+ int worstPos;\r
+\r
+ for(i = 0; i < 2048; i += 8) {\r
+ int sum = 0;\r
+ int j;\r
+ for(j = 0; j < 8; j++) {\r
+ sum += GraphBuffer[bestPos+i+j];\r
+ }\r
+ if(sum < 0) {\r
+ bits[i/8] = '.';\r
+ } else {\r
+ bits[i/8] = '1';\r
+ }\r
+ if(abs(sum) < worst) {\r
+ worst = abs(sum);\r
+ worstPos = i;\r
+ }\r
+ }\r
+ PrintToScrollback("bits:");\r
+ PrintToScrollback("%s", bits);\r
+ PrintToScrollback("worst metric: %d at pos %d", worst, worstPos);\r
+\r
+ if(strcmp(str, "clone")==0) {\r
+ GraphTraceLen = 0;\r
+ char *s;\r
+ for(s = bits; *s; s++) {\r
+ int j;\r
+ for(j = 0; j < 16; j++) {\r
+ GraphBuffer[GraphTraceLen++] = (*s == '1') ? 1 : 0;\r
+ }\r
+ }\r
+ RepaintGraphWindow();\r
+ }\r
+}\r
+\r
+static void CmdFlexdemod(char *str)\r
+{\r
+ int i;\r
+ for(i = 0; i < GraphTraceLen; i++) {\r
+ if(GraphBuffer[i] < 0) {\r
+ GraphBuffer[i] = -1;\r
+ } else {\r
+ GraphBuffer[i] = 1;\r
+ }\r
+ }\r
+\r
+#define LONG_WAIT 100\r
+ int start;\r
+ for(start = 0; start < GraphTraceLen - LONG_WAIT; start++) {\r
+ int first = GraphBuffer[start];\r
+ for(i = start; i < start + LONG_WAIT; i++) {\r
+ if(GraphBuffer[i] != first) {\r
+ break;\r
+ }\r
+ }\r
+ if(i == (start + LONG_WAIT)) {\r
+ break;\r
+ }\r
+ }\r
+ if(start == GraphTraceLen - LONG_WAIT) {\r
+ PrintToScrollback("nothing to wait for");\r
+ return;\r
+ }\r
+\r
+ GraphBuffer[start] = 2;\r
+ GraphBuffer[start+1] = -2;\r
+\r
+ BYTE bits[64];\r
+\r
+ int bit;\r
+ i = start;\r
+ for(bit = 0; bit < 64; bit++) {\r
+ int j;\r
+ int sum = 0;\r
+ for(j = 0; j < 16; j++) {\r
+ sum += GraphBuffer[i++];\r
+ }\r
+ if(sum > 0) {\r
+ bits[bit] = 1;\r
+ } else {\r
+ bits[bit] = 0;\r
+ }\r
+ PrintToScrollback("bit %d sum %d", bit, sum);\r
+ }\r
+\r
+ for(bit = 0; bit < 64; bit++) {\r
+ int j;\r
+ int sum = 0;\r
+ for(j = 0; j < 16; j++) {\r
+ sum += GraphBuffer[i++];\r
+ }\r
+ if(sum > 0 && bits[bit] != 1) {\r
+ PrintToScrollback("oops1 at %d", bit);\r
+ }\r
+ if(sum < 0 && bits[bit] != 0) {\r
+ PrintToScrollback("oops2 at %d", bit);\r
+ }\r
+ }\r
+\r
+ GraphTraceLen = 32*64;\r
+ i = 0;\r
+ int phase = 0;\r
+ for(bit = 0; bit < 64; bit++) {\r
+ if(bits[bit] == 0) {\r
+ phase = 0;\r
+ } else {\r
+ phase = 1;\r
+ }\r
+ int j;\r
+ for(j = 0; j < 32; j++) {\r
+ GraphBuffer[i++] = phase;\r
+ phase = !phase;\r
+ }\r
+ }\r
+\r
+ RepaintGraphWindow();\r
+}\r
+
+/*
+ * Generic command to demodulate ASK. bit length in argument.
+ * Giving the bit length helps discriminate ripple effects
+ * upon zero crossing for noisy traces.
+ *
+ * Second is convention: positive or negative (High mod means zero
+ * or high mod means one)
+ *
+ * Updates the Graph trace with 0/1 values
+ *
+ * Arguments:
+ * sl : bit length in terms of number of samples per bit
+ * (use yellow/purple markers to compute).
+ * c : 0 or 1
+ */
+
+static void Cmdaskdemod(char *str) {
+ int i;
+ int sign = 1;
+ int n = 0;
+ int c = 0;\r
+ int t1 = 0;
+
+ // TODO: complain if we do not give 2 arguments here !
+ sscanf(str, "%i %i", &n, &c);
+ if (c == 0) {
+ c = 1 ;
+ } else {
+ c = -1;
+ }
+
+ if (GraphBuffer[0]*c > 0) {
+ GraphBuffer[0] = 1;
+ } else {
+ GraphBuffer[0] = 0;
+ }
+ for(i=1;i<GraphTraceLen;i++) {
+ /* Analyse signal within the symbol length */
+ /* Decide if we crossed a zero */
+ if (GraphBuffer[i]*sign < 0) {
+ /* Crossed a zero, check if this is a ripple or not */
+ if ( (i-t1) > n/4 ) {
+ sign = -sign;
+ t1=i;
+ if (GraphBuffer[i]*c > 0){
+ GraphBuffer[i]=1;
+ } else {
+ GraphBuffer[i]=0;
+ }
+ } else {
+ /* This is a ripple, set the current sample value
+ to the same as previous */
+ GraphBuffer[i] = GraphBuffer[i-1];
+ }
+ } else {
+ GraphBuffer[i] = GraphBuffer[i-1];
+ }
+ }
+ RepaintGraphWindow();
+}
+
+
+/*
+ * Manchester demodulate a bitstream. The bitstream needs to be already in
+ * the GraphBuffer as 0 and 1 values
+ *
+ * Give the clock rate as argument in order to help the sync - the algorithm
+ * resyncs at each pulse anyway.
+ *
+ * Not optimized by any means, this is the 1st time I'm writing this type of
+ * routine, feel free to improve...
+ *
+ * 1st argument: clock rate (as number of samples per clock rate)
+ */
+static void Cmdmanchesterdemod(char *str) {
+ int i;
+ int clock;
+ int grouping=16;
+ int lastval;
+ int lc = 0;
+ int bitidx = 0;
+ int bitidx2;
+
+
+ sscanf(str, "%i", &clock);
+
+ int tolerance = clock/4;
+ /* Holds the decoded bitstream. */
+ int BitStream[MAX_GRAPH_TRACE_LEN*2];
+ int BitStream2[MAX_GRAPH_TRACE_LEN];
+
+ /* Detect first transition */
+ /* Lo-Hi (arbitrary) */
+ for(i=1;i<GraphTraceLen;i++) {
+ if (GraphBuffer[i-1]<GraphBuffer[i]) {
+ lastval = i;
+ BitStream[0]=0; // Previous state = 0;
+ break;
+ }
+ }
+
+ /* Then detect duration between 2 successive transitions */
+ /* At this stage, GraphTrace is either 0 or 1 */
+ for(bitidx = 1 ;i<GraphTraceLen;i++) {
+ if (GraphBuffer[i-1] != GraphBuffer[i]) {
+ lc = i-lastval;
+ lastval = i;
+ // Then switch depending on lc length:
+ // Tolerance is 1/4 of clock rate (arbitrary)
+ if ((lc-clock/2) < tolerance) {
+ // Short pulse
+ BitStream[bitidx++]=GraphBuffer[i-1];
+ } else if ((lc-clock) < tolerance) {
+ // Long pulse
+ BitStream[bitidx++]=GraphBuffer[i-1];
+ BitStream[bitidx++]=GraphBuffer[i-1];
+ } else {
+ // Error
+ PrintToScrollback("Warning: Manchester decode error for pulse width detection.");
+ PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)");
+ }
+ }
+ }
+
+ // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream
+ for (bitidx2 = 0; bitidx2<bitidx; bitidx2 += 2) {
+ if ((BitStream[bitidx2] == 0) && (BitStream[bitidx2+1] == 1)) {
+ BitStream2[bitidx2/2] = 1;
+ } else if ((BitStream[bitidx2] == 1) && (BitStream[bitidx2+1] == 0)) {
+ BitStream2[bitidx2/2] = 0;
+ } else {
+ // We cannot end up in this stage, this means we are unsynchronized,
+ // move up 1 bit:
+ bitidx2++;
+ PrintToScrollback("Unsynchronized, resync...");
+ PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)");
+ }
+ }
+ PrintToScrollback("Manchester decoded bitstream \n---------");
+ // Now output the bitstream to the scrollback by line of 16 bits
+ for (i = 0; i<bitidx/2; i+=16) {
+ PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
+ BitStream2[i],
+ BitStream2[i+1],
+ BitStream2[i+2],
+ BitStream2[i+3],
+ BitStream2[i+4],
+ BitStream2[i+5],
+ BitStream2[i+6],
+ BitStream2[i+7],
+ BitStream2[i+8],
+ BitStream2[i+9],
+ BitStream2[i+10],
+ BitStream2[i+11],
+ BitStream2[i+12],
+ BitStream2[i+13],
+ BitStream2[i+14],
+ BitStream2[i+15]);
+ }
+}
+
+
+
+/*
+ * Usage ???
+ */\r
+static void CmdHiddemod(char *str)\r
+{\r
+ if(GraphTraceLen < 4800) {\r
+ PrintToScrollback("too short; need at least 4800 samples");\r
+ return;\r
+ }\r
+\r
+ GraphTraceLen = 4800;\r
+ int i;\r
+ for(i = 0; i < GraphTraceLen; i++) {\r
+ if(GraphBuffer[i] < 0) {\r
+ GraphBuffer[i] = 0;\r
+ } else {\r
+ GraphBuffer[i] = 1;\r
+ }\r
+ }\r
+ RepaintGraphWindow();\r
+}\r
+\r
+static void CmdPlot(char *str)\r
+{\r
+ ShowGraphWindow();\r
+}\r
+\r
+static void CmdHide(char *str)\r
+{\r
+ HideGraphWindow();\r
+}\r
+\r
+static void CmdScale(char *str)\r
+{\r
+ CursorScaleFactor = atoi(str);\r
+ if(CursorScaleFactor == 0) {\r
+ PrintToScrollback("bad, can't have zero scale");\r
+ CursorScaleFactor = 1;\r
+ }\r
+ RepaintGraphWindow();\r
+}\r
+\r
+static void CmdSave(char *str)\r
+{\r
+ FILE *f = fopen(str, "w");\r
+ if(!f) {\r
+ PrintToScrollback("couldn't open '%s'", str);\r
+ return;\r
+ }\r
+ int i;\r
+ for(i = 0; i < GraphTraceLen; i++) {\r
+ fprintf(f, "%d\n", GraphBuffer[i]);\r
+ }\r
+ fclose(f);\r
+ PrintToScrollback("saved to '%s'", str);\r
+}\r
+\r
+static void CmdLoad(char *str)\r
+{\r
+ FILE *f = fopen(str, "r");\r
+ if(!f) {\r
+ PrintToScrollback("couldn't open '%s'", str);\r
+ return;\r
+ }\r
+\r
+ GraphTraceLen = 0;\r
+ char line[80];\r
+ while(fgets(line, sizeof(line), f)) {\r
+ GraphBuffer[GraphTraceLen] = atoi(line);\r
+ GraphTraceLen++;\r
+ }\r
+ fclose(f);\r
+ PrintToScrollback("loaded %d samples", GraphTraceLen);\r
+ RepaintGraphWindow();\r
+}\r
+\r
+static void CmdHIDsimTAG(char *str)\r
+{\r
+ unsigned int hi=0, lo=0;\r
+ int n=0, i=0;\r
+ UsbCommand c;\r
+\r
+ while (sscanf(&str[i++], "%1x", &n ) == 1) {\r
+ hi=(hi<<4)|(lo>>28);\r
+ lo=(lo<<4)|(n&0xf);\r
+ }\r
+\r
+ PrintToScrollback("Emulating tag with ID %x%16x", hi, lo);\r
+\r
+ c.cmd = CMD_HID_SIM_TAG;\r
+ c.ext1 = hi;\r
+ c.ext2 = lo;\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdLcdReset(char *str)\r
+{\r
+ UsbCommand c;\r
+ c.cmd = CMD_LCD_RESET;\r
+ c.ext1 = atoi(str);\r
+ SendCommand(&c, FALSE);\r
+}\r
+\r
+static void CmdLcd(char *str)\r
+{\r
+ int i, j;\r
+ UsbCommand c;\r
+ c.cmd = CMD_LCD;\r
+ sscanf(str, "%x %d", &i, &j);\r
+ while (j--) {\r
+ c.ext1 = i&0x1ff;\r
+ SendCommand(&c, FALSE);\r
+ }\r
+}\r
+\r
+static void CmdTest(char *str)\r
+{\r
+}\r
+\r
+typedef void HandlerFunction(char *cmdline);\r
+\r
+static struct {\r
+ char *name;\r
+ HandlerFunction *handler;\r
+ char *docString;\r
+} CommandTable[] = {\r
+ "tune", CmdTune, "measure antenna tuning",\r
+ "tiread", CmdTiread, "read a TI-type 134 kHz tag",\r
+ "tibits", CmdTibits, "get raw bits for TI-type LF tag",\r
+ "tidemod", CmdTidemod, "demod raw bits for TI-type LF tag",\r
+ "vchdemod", CmdVchdemod, "demod samples for VeriChip",\r
+ "plot", CmdPlot, "show graph window",\r
+ "hide", CmdHide, "hide graph window",\r
+ "losim", CmdLosim, "simulate LF tag",\r
+ "loread", CmdLoread, "read (125/134 kHz) LF ID-only tag",\r
+ "losamples", CmdLosamples, "get raw samples for LF tag",\r
+ "hisamples", CmdHisamples, "get raw samples for HF tag",\r
+ "hisampless", CmdHisampless, "get signed raw samples, HF tag",\r
+ "hisamplest", CmdHi14readt, "get samples HF, for testing",\r
+ "higet", CmdHi14read_sim, "get samples HF, 'analog'",\r
+ "bitsamples", CmdBitsamples, "get raw samples as bitstring",\r
+ "hexsamples", CmdHexsamples, "dump big buffer as hex bytes",\r
+ "hi15read", CmdHi15read, "read HF tag (ISO 15693)",\r
+ "hi15reader", CmdHi15reader, "act like an ISO15693 reader", // new command greg\r
+ "hi15sim", CmdHi15tag, "fake an ISO15693 tag", // new command greg\r
+ "hi14read", CmdHi14read, "read HF tag (ISO 14443)",\r
+ "hi14areader", CmdHi14areader, "act like an ISO14443 Type A reader", // ## New reader command\r
+ "hi15demod", CmdHi15demod, "demod ISO15693 from tag",\r
+ "hi14bdemod", CmdHi14bdemod, "demod ISO14443 Type B from tag",\r
+ "autocorr", CmdAutoCorr, "autocorrelation over window",\r
+ "norm", CmdNorm, "normalize max/min to +/-500",\r
+ "dec", CmdDec, "decimate",\r
+ "hpf", CmdHpf, "remove DC offset from trace",\r
+ "zerocrossings", CmdZerocrossings, "count time between zero-crossings",\r
+ "ltrim", CmdLtrim, "trim from left of trace",\r
+ "scale", CmdScale, "set cursor display scale",\r
+ "flexdemod", CmdFlexdemod, "demod samples for FlexPass",\r
+ "save", CmdSave, "save trace (from graph window)",\r
+ "load", CmdLoad, "load trace (to graph window",\r
+ "hisimlisten", CmdHisimlisten, "get HF samples as fake tag",\r
+ "hi14sim", CmdHi14sim, "fake ISO 14443 tag",\r
+ "hi14asim", CmdHi14asim, "fake ISO 14443a tag", // ## Simulate 14443a tag\r
+ "hi14snoop", CmdHi14snoop, "eavesdrop ISO 14443",\r
+ "hi14asnoop", CmdHi14asnoop, "eavesdrop ISO 14443 Type A", // ## New snoop command\r
+ "hi14list", CmdHi14list, "list ISO 14443 history",\r
+ "hi14alist", CmdHi14alist, "list ISO 14443a history", // ## New list command\r
+ "hiddemod", CmdHiddemod, "HID Prox Card II (not optimal)",\r
+ "hidfskdemod", CmdHIDdemodFSK, "HID FSK demodulator",\r
+ "askdemod", Cmdaskdemod, "Attempt to demodulate simple ASK tags",
+ "hidsimtag", CmdHIDsimTAG, "HID tag simulator",
+ "mandemod", Cmdmanchesterdemod, "Try a Manchester demodulation on a binary stream",
+ "fpgaoff", CmdFPGAOff, "set FPGA off", // ## FPGA Control\r
+ "lcdreset", CmdLcdReset, "Hardware reset LCD",\r
+ "lcd", CmdLcd, "Send command/data to LCD",\r
+ "test", CmdTest, "Placeholder command for testing new code",\r
+ "quit", CmdQuit, "quit program"\r
+};\r
+\r
+//-----------------------------------------------------------------------------\r
+// Entry point into our code: called whenever the user types a command and\r
+// then presses Enter, which the full command line that they typed.\r
+//-----------------------------------------------------------------------------\r
+void CommandReceived(char *cmd)\r
+{\r
+ int i;\r
+\r
+ PrintToScrollback("> %s", cmd);\r
+\r
+ if(strcmp(cmd, "help")==0) {\r
+ PrintToScrollback("\r\nAvailable commands:");\r
+ for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) {\r
+ char line[256];\r
+ memset(line, ' ', sizeof(line));\r
+ strcpy(line+2, CommandTable[i].name);\r
+ line[strlen(line)] = ' ';\r
+ sprintf(line+15, " -- %s", CommandTable[i].docString);\r
+ PrintToScrollback("%s", line);\r
+ }\r
+ PrintToScrollback("");\r
+ PrintToScrollback("and also: help, cls");\r
+ return;\r
+ }\r
+\r
+ for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) {\r
+ char *name = CommandTable[i].name;\r
+ if(memcmp(cmd, name, strlen(name))==0 &&\r
+ (cmd[strlen(name)] == ' ' || cmd[strlen(name)] == '\0'))\r
+ {\r
+ cmd += strlen(name);\r
+ while(*cmd == ' ') {\r
+ cmd++;\r
+ }\r
+ (CommandTable[i].handler)(cmd);\r
+ return;\r
+ }\r
+ }\r
+ PrintToScrollback(">> bad command '%s'", cmd);\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// Entry point into our code: called whenever we received a packet over USB\r
+// that we weren't necessarily expecting, for example a debug print.\r
+//-----------------------------------------------------------------------------\r
+void UsbCommandReceived(UsbCommand *c)\r
+{\r
+ switch(c->cmd) {\r
+ case CMD_DEBUG_PRINT_STRING: {\r
+ char s[100];\r
+ if(c->ext1 > 70 || c->ext1 < 0) {\r
+ c->ext1 = 0;\r
+ }\r
+ memcpy(s, c->d.asBytes, c->ext1);\r
+ s[c->ext1] = '\0';\r
+ PrintToScrollback("#db# %s", s);\r
+ break;
+ }\r
+\r
+ case CMD_DEBUG_PRINT_INTEGERS:\r
+ PrintToScrollback("#db# %08x, %08x, %08x\r\n", c->ext1, c->ext2, c->ext3);\r
+ break;\r
+\r
+ case CMD_MEASURED_ANTENNA_TUNING: {\r
+ int zLf, zHf;\r
+ int vLf125, vLf134, vHf;\r
+ vLf125 = c->ext1 & 0xffff;\r
+ vLf134 = c->ext1 >> 16;\r
+ vHf = c->ext2;\r
+ zLf = c->ext3 & 0xffff;\r
+ zHf = c->ext3 >> 16;\r
+ PrintToScrollback("# LF antenna @ %3d mA / %5d mV [%d ohms] 125Khz",\r
+ vLf125/zLf, vLf125, zLf);\r
+ PrintToScrollback("# LF antenna @ %3d mA / %5d mV [%d ohms] 134Khz",\r
+ vLf134/((zLf*125)/134), vLf134, (zLf*125)/134);\r
+ PrintToScrollback("# HF antenna @ %3d mA / %5d mV [%d ohms] 13.56Mhz",\r
+ vHf/zHf, vHf, zHf);\r
+ break;\r
+ }\r
+ default:\r
+ PrintToScrollback("unrecognized command %08x\n", c->cmd);\r
+ break;\r
+ }\r
+}\r
--- /dev/null
+//-----------------------------------------------------------------------------\r
+// Routines for the user interface when doing interactive things with prox\r
+// cards; this is basically a command line thing, in one window, and then\r
+// another window to do the graphs.\r
+// Jonathan Westhues, Sept 2005\r
+//-----------------------------------------------------------------------------\r
+#include <windows.h>\r
+#include <limits.h>\r
+#include <commctrl.h>\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <math.h>\r
+\r
+#include "prox.h"\r
+\r
+#define oops() do { \\r
+ char line[100]; \\r
+ sprintf(line, "Internal error at line %d file '%s'", __LINE__, \\r
+ __FILE__); \\r
+ MessageBox(NULL, line, "Error", MB_ICONERROR); \\r
+ exit(-1); \\r
+} while(0)\r
+\r
+void dbp(char *str, ...)\r
+{\r
+ va_list f;\r
+ char buf[1024];\r
+ va_start(f, str);\r
+ vsprintf(buf, str, f);\r
+ OutputDebugString(buf);\r
+ OutputDebugString("\n");\r
+}\r
+\r
+int GraphBuffer[MAX_GRAPH_TRACE_LEN];\r
+int GraphTraceLen;\r
+\r
+HPEN GreyPen, GreenPen, WhitePen, YellowPen;\r
+HBRUSH GreenBrush, YellowBrush;\r
+\r
+static int GraphStart = 0;\r
+static double GraphPixelsPerPoint = 1;\r
+\r
+static int CursorAPos;\r
+static int CursorBPos;\r
+double CursorScaleFactor = 1.0;\r
+static HPEN CursorAPen;\r
+static HPEN CursorBPen;\r
+\r
+static HWND CommandWindow;\r
+static HWND GraphWindow;\r
+static HWND ScrollbackEdit;\r
+static HWND CommandEdit;\r
+\r
+#define COMMAND_HISTORY_MAX 16\r
+static char CommandHistory[COMMAND_HISTORY_MAX][256];\r
+static int CommandHistoryPos = -1;\r
+static int CommandHistoryNext;\r
+\r
+static HFONT MyFixedFont;\r
+#define FixedFont(x) SendMessage((x), WM_SETFONT, (WPARAM)MyFixedFont, TRUE)\r
+\r
+void ExecCmd(char *cmd)\r
+{\r
+\r
+}\r
+int CommandFinished;\r
+\r
+static void ResizeCommandWindow(void)\r
+{\r
+ int w, h;\r
+ RECT r;\r
+ GetClientRect(CommandWindow, &r);\r
+ w = r.right - r.left;\r
+ h = r.bottom - r.top;\r
+ MoveWindow(ScrollbackEdit, 10, 10, w - 20, h - 50, TRUE);\r
+ MoveWindow(CommandEdit, 10, h - 29, w - 20, 22, TRUE);\r
+}\r
+\r
+void RepaintGraphWindow(void)\r
+{\r
+ InvalidateRect(GraphWindow, NULL, TRUE);\r
+}\r
+\r
+static LRESULT CALLBACK\r
+ CommandWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ switch (msg) {\r
+ case WM_DESTROY:\r
+ case WM_QUIT:\r
+ exit(0);\r
+ return 0;\r
+\r
+ case WM_SIZE:\r
+ ResizeCommandWindow();\r
+ return 0;\r
+\r
+ case WM_SETFOCUS:\r
+ SetFocus(CommandEdit);\r
+ break;\r
+\r
+ default:\r
+ return DefWindowProc(hwnd, msg, wParam, lParam);\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+static void PaintGraph(HDC hdc)\r
+{\r
+ HBRUSH brush;\r
+ HPEN pen;\r
+\r
+ brush = GreenBrush;\r
+ pen = GreenPen;\r
+\r
+ if(GraphStart < 0) {\r
+ GraphStart = 0;\r
+ }\r
+\r
+ RECT r;\r
+ GetClientRect(GraphWindow, &r);\r
+\r
+ SelectObject(hdc, WhitePen);\r
+\r
+ MoveToEx(hdc, r.left + 40, r.top, NULL);\r
+ LineTo(hdc, r.left + 40, r.bottom);\r
+\r
+ int zeroHeight = r.top + (r.bottom - r.top) / 2;\r
+ SelectObject(hdc, GreyPen);\r
+ MoveToEx(hdc, r.left, zeroHeight, NULL);\r
+ LineTo(hdc, r.right, zeroHeight);\r
+\r
+ int startMax =\r
+ (GraphTraceLen - (int)((r.right - r.left - 40) / GraphPixelsPerPoint));\r
+ if(startMax < 0) {\r
+ startMax = 0;\r
+ }\r
+ if(GraphStart > startMax) {\r
+ GraphStart = startMax;\r
+ }\r
+\r
+ int absYMax = 1;\r
+\r
+ SelectObject(hdc, pen);\r
+\r
+ int i;\r
+ for(i = GraphStart; ; i++) {\r
+ if(i >= GraphTraceLen) {\r
+ break;\r
+ }\r
+ if(fabs((double)GraphBuffer[i]) > absYMax) {\r
+ absYMax = (int)fabs((double)GraphBuffer[i]);\r
+ }\r
+ int x = 40 + (int)((i - GraphStart)*GraphPixelsPerPoint);\r
+ if(x > r.right) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ absYMax = (int)(absYMax*1.2 + 1);\r
+ SelectObject(hdc, MyFixedFont);\r
+ SetTextColor(hdc, RGB(255, 255, 255));\r
+ SetBkColor(hdc, RGB(0, 0, 0));\r
+\r
+ // number of points that will be plotted\r
+ int span = (int)((r.right - r.left) / GraphPixelsPerPoint);\r
+ // one label every 100 pixels, let us say\r
+ int labels = (r.right - r.left - 40) / 100;\r
+ if(labels <= 0) labels = 1;\r
+ int pointsPerLabel = span / labels;\r
+ if(pointsPerLabel <= 0) pointsPerLabel = 1;\r
+\r
+ int yMin = INT_MAX;\r
+ int yMax = INT_MIN;\r
+ int yMean = 0;\r
+ int n = 0;\r
+\r
+ for(i = GraphStart; ; i++) {\r
+ if(i >= GraphTraceLen) {\r
+ break;\r
+ }\r
+ int x = 40 + (int)((i - GraphStart)*GraphPixelsPerPoint);\r
+ if(x > r.right + GraphPixelsPerPoint) {\r
+ break;\r
+ }\r
+\r
+ int y = GraphBuffer[i];\r
+ if(y < yMin) {\r
+ yMin = y;\r
+ }\r
+ if(y > yMax) {\r
+ yMax = y;\r
+ }\r
+ yMean += y;\r
+ n++;\r
+\r
+ y = (y * (r.top - r.bottom) / (2*absYMax)) + zeroHeight;\r
+ if(i == GraphStart) {\r
+ MoveToEx(hdc, x, y, NULL);\r
+ } else {\r
+ LineTo(hdc, x, y);\r
+ }\r
+\r
+ if(GraphPixelsPerPoint > 10) {\r
+ RECT f;\r
+ f.left = x - 3;\r
+ f.top = y - 3;\r
+ f.right = x + 3;\r
+ f.bottom = y + 3;\r
+ FillRect(hdc, &f, brush);\r
+ }\r
+\r
+ if(((i - GraphStart) % pointsPerLabel == 0) && i != GraphStart) {\r
+ SelectObject(hdc, WhitePen);\r
+ MoveToEx(hdc, x, zeroHeight - 3, NULL);\r
+ LineTo(hdc, x, zeroHeight + 3);\r
+\r
+ char str[100];\r
+ sprintf(str, "+%d", (i - GraphStart));\r
+ SIZE size;\r
+ GetTextExtentPoint32(hdc, str, strlen(str), &size);\r
+ TextOut(hdc, x - size.cx, zeroHeight + 8, str, strlen(str));\r
+\r
+ SelectObject(hdc, pen);\r
+ MoveToEx(hdc, x, y, NULL);\r
+ }\r
+\r
+ if(i == CursorAPos || i == CursorBPos) {\r
+ if(i == CursorAPos) {\r
+ SelectObject(hdc, CursorAPen);\r
+ } else {\r
+ SelectObject(hdc, CursorBPen);\r
+ }\r
+ MoveToEx(hdc, x, r.top, NULL);\r
+ LineTo(hdc, x, r.bottom);\r
+\r
+ SelectObject(hdc, pen);\r
+ MoveToEx(hdc, x, y, NULL);\r
+ }\r
+ }\r
+\r
+ if(n != 0) {\r
+ yMean /= n;\r
+ }\r
+\r
+ char str[100];\r
+ sprintf(str, "@%d max=%d min=%d mean=%d n=%d/%d dt=%d [%.3f]",\r
+ GraphStart, yMax, yMin, yMean, n, GraphTraceLen,\r
+ CursorBPos - CursorAPos, (CursorBPos - CursorAPos)/CursorScaleFactor);\r
+ TextOut(hdc, 50, r.bottom - 20, str, strlen(str));\r
+}\r
+\r
+static LRESULT CALLBACK\r
+ GraphWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ switch (msg) {\r
+ case WM_DESTROY:\r
+ case WM_QUIT:\r
+ GraphWindow = NULL;\r
+ return DefWindowProc(hwnd, msg, wParam, lParam);\r
+\r
+ case WM_SIZE:\r
+ RepaintGraphWindow();\r
+ return 0;\r
+\r
+ case WM_PAINT: {\r
+ PAINTSTRUCT ps;\r
+ HDC hdc = BeginPaint(hwnd, &ps);\r
+ if(GraphStart < 0) {\r
+ GraphStart = 0;\r
+ }\r
+ // This draws the trace.\r
+ PaintGraph(hdc);\r
+ EndPaint(hwnd, &ps);\r
+ break;\r
+ }\r
+ case WM_KEYDOWN:\r
+ switch(wParam) {\r
+ case VK_DOWN:\r
+ if(GraphPixelsPerPoint <= 50) {\r
+ GraphPixelsPerPoint *= 2;\r
+ }\r
+ break;\r
+\r
+ case VK_UP:\r
+ if(GraphPixelsPerPoint >= 0.02) {\r
+ GraphPixelsPerPoint /= 2;\r
+ }\r
+ break;\r
+\r
+ case VK_RIGHT:\r
+ if(GraphPixelsPerPoint < 20) {\r
+ GraphStart += (int)(20 / GraphPixelsPerPoint);\r
+ } else {\r
+ GraphStart++;\r
+ }\r
+ break;\r
+\r
+ case VK_LEFT:\r
+ if(GraphPixelsPerPoint < 20) {\r
+ GraphStart -= (int)(20 / GraphPixelsPerPoint);\r
+ } else {\r
+ GraphStart--;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ goto nopaint;\r
+ }\r
+ RepaintGraphWindow();\r
+nopaint:\r
+ break;\r
+\r
+ case WM_LBUTTONDOWN:\r
+ case WM_RBUTTONDOWN: {\r
+ int x = LOWORD(lParam);\r
+ x -= 40;\r
+ x = (int)(x / GraphPixelsPerPoint);\r
+ x += GraphStart;\r
+ if(msg == WM_LBUTTONDOWN) {\r
+ CursorAPos = x;\r
+ } else {\r
+ CursorBPos = x;\r
+ }\r
+ RepaintGraphWindow();\r
+ break;\r
+ }\r
+ default:\r
+ return DefWindowProc(hwnd, msg, wParam, lParam);\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+void PrintToScrollback(char *fmt, ...)\r
+{\r
+ va_list f;\r
+ char str[1024];\r
+ strcpy(str, "\r\n");\r
+ va_start(f, fmt);\r
+ vsprintf(str+2, fmt, f);\r
+\r
+ static char TextBuf[1024*32];\r
+ SendMessage(ScrollbackEdit, WM_GETTEXT, (WPARAM)sizeof(TextBuf),\r
+ (LPARAM)TextBuf);\r
+\r
+ if(strlen(TextBuf) + strlen(str) + 1 <= sizeof(TextBuf)) {\r
+ strcat(TextBuf, str);\r
+ } else {\r
+ lstrcpyn(TextBuf, str, sizeof(TextBuf));\r
+ }\r
+\r
+ SendMessage(ScrollbackEdit, WM_SETTEXT, 0, (LPARAM)TextBuf);\r
+ SendMessage(ScrollbackEdit, EM_LINESCROLL, 0, (LPARAM)INT_MAX);\r
+}\r
+\r
+void ShowGraphWindow(void)\r
+{\r
+ if(GraphWindow) return;\r
+\r
+ GraphWindow = CreateWindowEx(0, "Graph", "graphed",\r
+ WS_OVERLAPPED | WS_BORDER | WS_MINIMIZEBOX | WS_SYSMENU |\r
+ WS_SIZEBOX | WS_VISIBLE, 200, 150, 600, 500, NULL, NULL, NULL,\r
+ NULL);\r
+ if(!GraphWindow) oops();\r
+}\r
+\r
+void HideGraphWindow(void)\r
+{\r
+ if(GraphWindow) {\r
+ DestroyWindow(GraphWindow);\r
+ GraphWindow = NULL;\r
+ }\r
+}\r
+\r
+static void SetCommandEditTo(char *str)\r
+{\r
+ SendMessage(CommandEdit, WM_SETTEXT, 0, (LPARAM)str);\r
+ SendMessage(CommandEdit, EM_SETSEL, strlen(str), strlen(str));\r
+}\r
+\r
+void ShowGui(void)\r
+{\r
+ WNDCLASSEX wc;\r
+ memset(&wc, 0, sizeof(wc));\r
+ wc.cbSize = sizeof(wc);\r
+\r
+ wc.style = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW | CS_OWNDC;\r
+ wc.lpfnWndProc = (WNDPROC)CommandWindowProc;\r
+ wc.hInstance = NULL;\r
+ wc.hbrBackground = (HBRUSH)(COLOR_BTNSHADOW);\r
+ wc.lpszClassName = "Command";\r
+ wc.lpszMenuName = NULL;\r
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);\r
+\r
+ if(!RegisterClassEx(&wc)) oops();\r
+\r
+ wc.lpszClassName = "Graph";\r
+ wc.lpfnWndProc = (WNDPROC)GraphWindowProc;\r
+ wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);\r
+\r
+ if(!RegisterClassEx(&wc)) oops();\r
+\r
+ CommandWindow = CreateWindowEx(0, "Command", "prox",\r
+ WS_OVERLAPPED | WS_BORDER | WS_MINIMIZEBOX | WS_SYSMENU |\r
+ WS_SIZEBOX | WS_VISIBLE, 20, 20, 500, 400, NULL, NULL, NULL,\r
+ NULL);\r
+ if(!CommandWindow) oops();\r
+\r
+ ScrollbackEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "edit", "",\r
+ WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | ES_MULTILINE |\r
+ ES_AUTOVSCROLL | WS_VSCROLL, 0, 0, 0, 0, CommandWindow, NULL,\r
+ NULL, NULL);\r
+\r
+ CommandEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "edit", "",\r
+ WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | WS_VISIBLE |\r
+ ES_AUTOHSCROLL, 0, 0, 0, 0, CommandWindow, NULL, NULL, NULL);\r
+\r
+ MyFixedFont = CreateFont(14, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,\r
+ ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,\r
+ FF_DONTCARE, "Lucida Console");\r
+ if(!MyFixedFont)\r
+ MyFixedFont = (HFONT)GetStockObject(SYSTEM_FONT);\r
+\r
+ FixedFont(ScrollbackEdit);\r
+ FixedFont(CommandEdit);\r
+\r
+ ResizeCommandWindow();\r
+ SetFocus(CommandEdit);\r
+\r
+ PrintToScrollback(">> Started prox, built " __DATE__ " " __TIME__);\r
+ PrintToScrollback(">> Connected to device");\r
+\r
+ GreyPen = CreatePen(PS_SOLID, 1, RGB(100, 100, 100));\r
+ GreenPen = CreatePen(PS_SOLID, 1, RGB(100, 255, 100));\r
+ YellowPen = CreatePen(PS_SOLID, 1, RGB(255, 255, 0));\r
+ GreenBrush = CreateSolidBrush(RGB(100, 255, 100));\r
+ YellowBrush = CreateSolidBrush(RGB(255, 255, 0));\r
+ WhitePen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));\r
+\r
+ CursorAPen = CreatePen(PS_DASH, 1, RGB(255, 255, 0));\r
+ CursorBPen = CreatePen(PS_DASH, 1, RGB(255, 0, 255));\r
+\r
+ MSG msg;\r
+ for(;;) {\r
+ if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {\r
+ if(msg.message == WM_KEYDOWN && msg.wParam == VK_RETURN) {\r
+ char got[1024];\r
+ SendMessage(CommandEdit, WM_GETTEXT, (WPARAM)sizeof(got),\r
+ (LPARAM)got);\r
+\r
+ if(strcmp(got, "cls")==0) {\r
+ SendMessage(ScrollbackEdit, WM_SETTEXT, 0, (LPARAM)"");\r
+ } else {\r
+ CommandReceived(got);\r
+ }\r
+ SendMessage(CommandEdit, WM_SETTEXT, 0, (LPARAM)"");\r
+\r
+ // Insert it into the command history, unless it is\r
+ // identical to the previous command in the history.\r
+ int prev = CommandHistoryNext - 1;\r
+ if(prev < 0) prev += COMMAND_HISTORY_MAX;\r
+ if(strcmp(CommandHistory[prev], got) != 0) {\r
+ strcpy(CommandHistory[CommandHistoryNext], got);\r
+ CommandHistoryNext++;\r
+ if(CommandHistoryNext == COMMAND_HISTORY_MAX) {\r
+ CommandHistoryNext = 0;\r
+ }\r
+ }\r
+ CommandHistoryPos = -1;\r
+ } else if(msg.message == WM_KEYDOWN && msg.wParam == VK_UP &&\r
+ msg.hwnd == CommandEdit)\r
+ {\r
+ if(CommandHistoryPos == -1) {\r
+ CommandHistoryPos = CommandHistoryNext;\r
+ }\r
+ CommandHistoryPos--;\r
+ if(CommandHistoryPos < 0) {\r
+ CommandHistoryPos = COMMAND_HISTORY_MAX-1;\r
+ }\r
+ SetCommandEditTo(CommandHistory[CommandHistoryPos]);\r
+ } else if(msg.message == WM_KEYDOWN && msg.wParam == VK_DOWN &&\r
+ msg.hwnd == CommandEdit)\r
+ {\r
+ CommandHistoryPos++;\r
+ if(CommandHistoryPos >= COMMAND_HISTORY_MAX) {\r
+ CommandHistoryPos = 0;\r
+ }\r
+ SetCommandEditTo(CommandHistory[CommandHistoryPos]);\r
+ } else if(msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE &&\r
+ msg.hwnd == CommandEdit)\r
+ {\r
+ SendMessage(CommandEdit, WM_SETTEXT, 0, (LPARAM)"");\r
+ } else {\r
+ if(msg.message == WM_KEYDOWN) {\r
+ CommandHistoryPos = -1;\r
+ }\r
+ TranslateMessage(&msg);\r
+ DispatchMessage(&msg);\r
+ }\r
+ }\r
+\r
+ UsbCommand c;\r
+ if(ReceiveCommandPoll(&c)) {\r
+ UsbCommandReceived(&c);\r
+ }\r
+\r
+ Sleep(10);\r
+ }\r
+}\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 1996-1998 Microsoft Corporation\r
+\r
+Module Name:\r
+\r
+ HIDPI.H\r
+\r
+Abstract:\r
+\r
+ Public Interface to the HID parsing library.\r
+\r
+Environment:\r
+\r
+ Kernel & user mode\r
+\r
+--*/\r
+\r
+#ifndef __HIDPI_H__\r
+#define __HIDPI_H__\r
+\r
+#include <pshpack4.h>\r
+\r
+// Please include "hidsdi.h" to use the user space (dll / parser)\r
+// Please include "hidpddi.h" to use the kernel space parser\r
+\r
+//\r
+// Special Link collection values for using the query functions\r
+//\r
+// Root collection references the collection at the base of the link\r
+// collection tree.\r
+// Unspecifies, references all collections in the link collection tree.\r
+//\r
+#define HIDP_LINK_COLLECTION_ROOT ((USHORT) -1)\r
+#define HIDP_LINK_COLLECTION_UNSPECIFIED ((USHORT) 0)\r
+\r
+\r
+typedef enum _HIDP_REPORT_TYPE\r
+{\r
+ HidP_Input,\r
+ HidP_Output,\r
+ HidP_Feature\r
+} HIDP_REPORT_TYPE;\r
+\r
+typedef struct _USAGE_AND_PAGE\r
+{\r
+ USAGE Usage;\r
+ USAGE UsagePage;\r
+} USAGE_AND_PAGE, *PUSAGE_AND_PAGE;\r
+\r
+#define HidP_IsSameUsageAndPage(u1, u2) ((* (PULONG) &u1) == (* (PULONG) &u2))\r
+\r
+typedef struct _HIDP_BUTTON_CAPS\r
+{\r
+ USAGE UsagePage;\r
+ UCHAR ReportID;\r
+ BOOLEAN IsAlias;\r
+\r
+ USHORT BitField;\r
+ USHORT LinkCollection; // A unique internal index pointer\r
+\r
+ USAGE LinkUsage;\r
+ USAGE LinkUsagePage;\r
+\r
+ BOOLEAN IsRange;\r
+ BOOLEAN IsStringRange;\r
+ BOOLEAN IsDesignatorRange;\r
+ BOOLEAN IsAbsolute;\r
+\r
+ ULONG Reserved[10];\r
+ union {\r
+ struct {\r
+ USAGE UsageMin, UsageMax;\r
+ USHORT StringMin, StringMax;\r
+ USHORT DesignatorMin, DesignatorMax;\r
+ USHORT DataIndexMin, DataIndexMax;\r
+ } Range;\r
+ struct {\r
+ USAGE Usage, Reserved1;\r
+ USHORT StringIndex, Reserved2;\r
+ USHORT DesignatorIndex, Reserved3;\r
+ USHORT DataIndex, Reserved4;\r
+ } NotRange;\r
+ };\r
+\r
+} HIDP_BUTTON_CAPS, *PHIDP_BUTTON_CAPS;\r
+\r
+\r
+typedef struct _HIDP_VALUE_CAPS\r
+{\r
+ USAGE UsagePage;\r
+ UCHAR ReportID;\r
+ BOOLEAN IsAlias;\r
+\r
+ USHORT BitField;\r
+ USHORT LinkCollection; // A unique internal index pointer\r
+\r
+ USAGE LinkUsage;\r
+ USAGE LinkUsagePage;\r
+\r
+ BOOLEAN IsRange;\r
+ BOOLEAN IsStringRange;\r
+ BOOLEAN IsDesignatorRange;\r
+ BOOLEAN IsAbsolute;\r
+\r
+ BOOLEAN HasNull; // Does this channel have a null report union\r
+ UCHAR Reserved;\r
+ USHORT BitSize; // How many bits are devoted to this value?\r
+\r
+ USHORT ReportCount; // See Note below. Usually set to 1.\r
+ USHORT Reserved2[5];\r
+\r
+ ULONG UnitsExp;\r
+ ULONG Units;\r
+\r
+ LONG LogicalMin, LogicalMax;\r
+ LONG PhysicalMin, PhysicalMax;\r
+\r
+ union {\r
+ struct {\r
+ USAGE UsageMin, UsageMax;\r
+ USHORT StringMin, StringMax;\r
+ USHORT DesignatorMin, DesignatorMax;\r
+ USHORT DataIndexMin, DataIndexMax;\r
+ } Range;\r
+\r
+ struct {\r
+ USAGE Usage, Reserved1;\r
+ USHORT StringIndex, Reserved2;\r
+ USHORT DesignatorIndex, Reserved3;\r
+ USHORT DataIndex, Reserved4;\r
+ } NotRange;\r
+ };\r
+} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS;\r
+\r
+//\r
+// Notes:\r
+//\r
+// ReportCount: When a report descriptor declares an Input, Output, or\r
+// Feature main item with fewer usage declarations than the report count, then\r
+// the last usage applies to all remaining unspecified count in that main item.\r
+// (As an example you might have data that required many fields to describe,\r
+// possibly buffered bytes.) In this case, only one value cap structure is\r
+// allocated for these associtated fields, all with the same usage, and Report\r
+// Count reflects the number of fields involved. Normally ReportCount is 1.\r
+// To access all of the fields in such a value structure would require using\r
+// HidP_GetUsageValueArray and HidP_SetUsageValueArray. HidP_GetUsageValue/\r
+// HidP_SetScaledUsageValue will also work, however, these functions will only\r
+// work with the first field of the structure.\r
+//\r
+\r
+//\r
+// The link collection tree consists of an array of LINK_COLLECTION_NODES\r
+// where the index into this array is the same as the collection number.\r
+//\r
+// Given a collection A which contains a subcollection B, A is defined to be\r
+// the parent B, and B is defined to be the child.\r
+//\r
+// Given collections A, B, and C where B and C are children of A, and B was\r
+// encountered before C in the report descriptor, B is defined as a sibling of\r
+// C. (This implies, of course, that if B is a sibling of C, then C is NOT a\r
+// sibling of B).\r
+//\r
+// B is defined as the NextSibling of C if and only if there exists NO\r
+// child collection of A, call it D, such that B is a sibling of D and D\r
+// is a sibling of C.\r
+//\r
+// E is defined to be the FirstChild of A if and only if for all children of A,\r
+// F, that are not equivalent to E, F is a sibling of E.\r
+// (This implies, of course, that the does not exist a child of A, call it G,\r
+// where E is a sibling of G). In other words the first sibling is the last\r
+// link collection found in the list.\r
+//\r
+// In other words, if a collection B is defined within the definition of another\r
+// collection A, B becomes a child of A. All collections with the same parent\r
+// are considered siblings. The FirstChild of the parent collection, A, will be\r
+// last collection defined that has A as a parent. The order of sibling pointers\r
+// is similarly determined. When a collection B is defined, it becomes the\r
+// FirstChild of it's parent collection. The previously defined FirstChild of the\r
+// parent collection becomes the NextSibling of the new collection. As new\r
+// collections with the same parent are discovered, the chain of sibling is built.\r
+//\r
+// With that in mind, the following describes conclusively a data structure\r
+// that provides direct traversal up, down, and accross the link collection\r
+// tree.\r
+//\r
+//\r
+typedef struct _HIDP_LINK_COLLECTION_NODE\r
+{\r
+ USAGE LinkUsage;\r
+ USAGE LinkUsagePage;\r
+ USHORT Parent;\r
+ USHORT NumberOfChildren;\r
+ USHORT NextSibling;\r
+ USHORT FirstChild;\r
+ ULONG CollectionType: 8; // As defined in 6.2.2.6 of HID spec\r
+ ULONG IsAlias : 1; // This link node is an allias of the next link node.\r
+ ULONG Reserved: 23;\r
+ PVOID UserContext; // The user can hang his coat here.\r
+} HIDP_LINK_COLLECTION_NODE, *PHIDP_LINK_COLLECTION_NODE;\r
+\r
+//\r
+// When a link collection is described by a delimiter, alias link collection\r
+// nodes are created. (One for each usage within the delimiter).\r
+// The parser assigns each capability description listed above only one\r
+// link collection.\r
+//\r
+// If a control is defined within a collection defined by\r
+// delimited usages, then that control is said to be within multiple link\r
+// collections, one for each usage within the open and close delimiter tokens.\r
+// Such multiple link collecions are said to be aliases. The first N-1 such\r
+// collections, listed in the link collection node array, have their IsAlias\r
+// bit set. The last such link collection is the link collection index used\r
+// in the capabilities described above.\r
+// Clients wishing to set a control in an aliased collection, should walk the\r
+// collection array once for each time they see the IsAlias flag set, and use\r
+// the last link collection as the index for the below accessor functions.\r
+//\r
+// NB: if IsAlias is set, then NextSibling should be one more than the current\r
+// link collection node index.\r
+//\r
+\r
+typedef PUCHAR PHIDP_REPORT_DESCRIPTOR;\r
+typedef struct _HIDP_PREPARSED_DATA * PHIDP_PREPARSED_DATA;\r
+\r
+typedef struct _HIDP_CAPS\r
+{\r
+ USAGE Usage;\r
+ USAGE UsagePage;\r
+ USHORT InputReportByteLength;\r
+ USHORT OutputReportByteLength;\r
+ USHORT FeatureReportByteLength;\r
+ USHORT Reserved[17];\r
+\r
+ USHORT NumberLinkCollectionNodes;\r
+\r
+ USHORT NumberInputButtonCaps;\r
+ USHORT NumberInputValueCaps;\r
+ USHORT NumberInputDataIndices;\r
+\r
+ USHORT NumberOutputButtonCaps;\r
+ USHORT NumberOutputValueCaps;\r
+ USHORT NumberOutputDataIndices;\r
+\r
+ USHORT NumberFeatureButtonCaps;\r
+ USHORT NumberFeatureValueCaps;\r
+ USHORT NumberFeatureDataIndices;\r
+} HIDP_CAPS, *PHIDP_CAPS;\r
+\r
+typedef struct _HIDP_DATA\r
+{\r
+ USHORT DataIndex;\r
+ USHORT Reserved;\r
+ union {\r
+ ULONG RawValue; // for values\r
+ BOOLEAN On; // for buttons MUST BE TRUE for buttons.\r
+ };\r
+} HIDP_DATA, *PHIDP_DATA;\r
+//\r
+// The HIDP_DATA structure is used with HidP_GetData and HidP_SetData\r
+// functions.\r
+//\r
+// The parser contiguously assigns every control (button or value) in a hid\r
+// device a unique data index from zero to NumberXXXDataIndices -1 , inclusive.\r
+// This value is found in the HIDP_BUTTON_CAPS and HIDP_VALUE_CAPS structures.\r
+//\r
+// Most clients will find the Get/Set Buttons / Value accessor functions\r
+// sufficient to their needs, as they will allow the clients to access the\r
+// data known to them while ignoring the other controls.\r
+//\r
+// More complex clients, which actually read the Button / Value Caps, and which\r
+// do a value add service to these routines (EG Direct Input), will need to\r
+// access all the data in the device without interest in the individual usage\r
+// or link collection location. These are the clients that will find\r
+// HidP_Data useful.\r
+//\r
+\r
+typedef struct _HIDP_UNKNOWN_TOKEN\r
+{\r
+ UCHAR Token;\r
+ UCHAR Reserved[3];\r
+ ULONG BitField;\r
+} HIDP_UNKNOWN_TOKEN, *PHIDP_UNKNOWN_TOKEN;\r
+\r
+typedef struct _HIDP_EXTENDED_ATTRIBUTES\r
+{\r
+ UCHAR NumGlobalUnknowns;\r
+ UCHAR Reserved [3];\r
+ PHIDP_UNKNOWN_TOKEN GlobalUnknowns;\r
+ // ... Additional attributes\r
+ ULONG Data [1]; // variableLength DO NOT ACCESS THIS FIELD\r
+} HIDP_EXTENDED_ATTRIBUTES, *PHIDP_EXTENDED_ATTRIBUTES;\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetCaps (\r
+ IN PHIDP_PREPARSED_DATA PreparsedData,\r
+ OUT PHIDP_CAPS Capabilities\r
+ );\r
+/*++\r
+Routine Description:\r
+ Returns a list of capabilities of a given hid device as described by its\r
+ preparsed data.\r
+\r
+Arguments:\r
+ PreparsedData The preparsed data returned from HIDCLASS.\r
+ Capabilities a HIDP_CAPS structure\r
+\r
+Return Value:\r
+· HIDP_STATUS_SUCCESS\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetLinkCollectionNodes (\r
+ OUT PHIDP_LINK_COLLECTION_NODE LinkCollectionNodes,\r
+ IN OUT PULONG LinkCollectionNodesLength,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData\r
+ );\r
+/*++\r
+Routine Description:\r
+ Return a list of PHIDP_LINK_COLLECTION_NODEs used to describe the link\r
+ collection tree of this hid device. See the above description of\r
+ struct _HIDP_LINK_COLLECTION_NODE.\r
+\r
+Arguments:\r
+ LinkCollectionNodes - a caller allocated array into which\r
+ HidP_GetLinkCollectionNodes will store the information\r
+\r
+ LinKCollectionNodesLength - the caller sets this value to the length of the\r
+ the array in terms of number of elements.\r
+ HidP_GetLinkCollectionNodes sets this value to the actual\r
+ number of elements set. The total number of nodes required to\r
+ describe this HID device can be found in the\r
+ NumberLinkCollectionNodes field in the HIDP_CAPS structure.\r
+\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetButtonCaps (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ OUT PHIDP_BUTTON_CAPS ButtonCaps,\r
+ IN OUT PUSHORT ButtonCapsLength,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData\r
+);\r
+#define HidP_GetButtonCaps(_Type_, _Caps_, _Len_, _Data_) \\r
+ HidP_GetSpecificButtonCaps (_Type_, 0, 0, 0, _Caps_, _Len_, _Data_)\r
+NTSTATUS __stdcall\r
+HidP_GetSpecificButtonCaps (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ IN USAGE UsagePage, // Optional (0 => ignore)\r
+ IN USHORT LinkCollection, // Optional (0 => ignore)\r
+ IN USAGE Usage, // Optional (0 => ignore)\r
+ OUT PHIDP_BUTTON_CAPS ButtonCaps,\r
+ IN OUT PUSHORT ButtonCapsLength,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData\r
+ );\r
+/*++\r
+Description:\r
+ HidP_GetButtonCaps returns all the buttons (binary values) that are a part\r
+ of the given report type for the Hid device represented by the given\r
+ preparsed data.\r
+\r
+Parameters:\r
+ ReportType One of HidP_Input, HidP_Output, or HidP_Feature.\r
+\r
+ UsagePage A usage page value used to limit the button caps returned to\r
+ those on a given usage page. If set to 0, this parameter is\r
+ ignored. Can be used with LinkCollection and Usage parameters\r
+ to further limit the number of button caps structures returned.\r
+\r
+ LinkCollection HIDP_LINK_COLLECTION node array index used to limit the\r
+ button caps returned to those buttons in a given link\r
+ collection. If set to 0, this parameter is\r
+ ignored. Can be used with UsagePage and Usage parameters\r
+ to further limit the number of button caps structures\r
+ returned.\r
+\r
+ Usage A usage value used to limit the button caps returned to those\r
+ with the specified usage value. If set to 0, this parameter\r
+ is ignored. Can be used with LinkCollection and UsagePage\r
+ parameters to further limit the number of button caps\r
+ structures returned.\r
+\r
+ ButtonCaps A _HIDP_BUTTON_CAPS array containing information about all the\r
+ binary values in the given report. This buffer is provided by\r
+ the caller.\r
+\r
+ ButtonLength As input, this parameter specifies the length of the\r
+ ButtonCaps parameter (array) in number of array elements.\r
+ As output, this value is set to indicate how many of those\r
+ array elements were filled in by the function. The maximum number of\r
+ button caps that can be returned is found in the HIDP_CAPS\r
+ structure. If HIDP_STATUS_BUFFER_TOO_SMALL is returned,\r
+ this value contains the number of array elements needed to\r
+ successfully complete the request.\r
+\r
+ PreparsedData The preparsed data returned from HIDCLASS.\r
+\r
+\r
+Return Value\r
+HidP_GetSpecificButtonCaps returns the following error codes:\r
+· HIDP_STATUS_SUCCESS.\r
+· HIDP_STATUS_INVALID_REPORT_TYPE\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA\r
+· HIDP_STATUS_BUFFER_TOO_SMALL (all given entries however have been filled in)\r
+· HIDP_STATUS_USAGE_NOT_FOUND\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetValueCaps (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ OUT PHIDP_VALUE_CAPS ValueCaps,\r
+ IN OUT PUSHORT ValueCapsLength,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData\r
+);\r
+#define HidP_GetValueCaps(_Type_, _Caps_, _Len_, _Data_) \\r
+ HidP_GetSpecificValueCaps (_Type_, 0, 0, 0, _Caps_, _Len_, _Data_)\r
+NTSTATUS __stdcall\r
+HidP_GetSpecificValueCaps (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ IN USAGE UsagePage, // Optional (0 => ignore)\r
+ IN USHORT LinkCollection, // Optional (0 => ignore)\r
+ IN USAGE Usage, // Optional (0 => ignore)\r
+ OUT PHIDP_VALUE_CAPS ValueCaps,\r
+ IN OUT PUSHORT ValueCapsLength,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData\r
+ );\r
+/*++\r
+Description:\r
+ HidP_GetValueCaps returns all the values (non-binary) that are a part\r
+ of the given report type for the Hid device represented by the given\r
+ preparsed data.\r
+\r
+Parameters:\r
+ ReportType One of HidP_Input, HidP_Output, or HidP_Feature.\r
+\r
+ UsagePage A usage page value used to limit the value caps returned to\r
+ those on a given usage page. If set to 0, this parameter is\r
+ ignored. Can be used with LinkCollection and Usage parameters\r
+ to further limit the number of value caps structures returned.\r
+\r
+ LinkCollection HIDP_LINK_COLLECTION node array index used to limit the\r
+ value caps returned to those buttons in a given link\r
+ collection. If set to 0, this parameter is\r
+ ignored. Can be used with UsagePage and Usage parameters\r
+ to further limit the number of value caps structures\r
+ returned.\r
+\r
+ Usage A usage value used to limit the value caps returned to those\r
+ with the specified usage value. If set to 0, this parameter\r
+ is ignored. Can be used with LinkCollection and UsagePage\r
+ parameters to further limit the number of value caps\r
+ structures returned.\r
+\r
+ ValueCaps A _HIDP_VALUE_CAPS array containing information about all the\r
+ non-binary values in the given report. This buffer is provided\r
+ by the caller.\r
+\r
+ ValueLength As input, this parameter specifies the length of the ValueCaps\r
+ parameter (array) in number of array elements. As output,\r
+ this value is set to indicate how many of those array elements\r
+ were filled in by the function. The maximum number of\r
+ value caps that can be returned is found in the HIDP_CAPS\r
+ structure. If HIDP_STATUS_BUFFER_TOO_SMALL is returned,\r
+ this value contains the number of array elements needed to\r
+ successfully complete the request.\r
+\r
+ PreparsedData The preparsed data returned from HIDCLASS.\r
+\r
+\r
+Return Value\r
+HidP_GetValueCaps returns the following error codes:\r
+· HIDP_STATUS_SUCCESS.\r
+· HIDP_STATUS_INVALID_REPORT_TYPE\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA\r
+· HIDP_STATUS_BUFFER_TOO_SMALL (all given entries however have been filled in)\r
+· HIDP_STATUS_USAGE_NOT_FOUND\r
+\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetExtendedAttributes (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ IN USHORT DataIndex,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData,\r
+ OUT PHIDP_EXTENDED_ATTRIBUTES Attributes,\r
+ IN OUT PULONG LengthAttributes\r
+ );\r
+/*++\r
+Description:\r
+ Given a data index from the value or button capabilities of a given control\r
+ return any extended attributes for the control if any exist.\r
+\r
+Parameters:\r
+ ReportType One of HidP_Input, HidP_Output, or HidP_Feature.\r
+\r
+ DataIndex The data index for the given control, found in the capabilities\r
+ structure for that control\r
+\r
+ PreparsedData The preparsed data returned from HIDCLASS.\r
+\r
+ Attributes Pointer to a buffer into which the extended attribute data will\r
+ be copied.\r
+\r
+ LengthAttributes Length of the given buffer in bytes.\r
+\r
+Return Value\r
+ HIDP_STATUS_SUCCESS\r
+ HIDP_STATUS_DATA_INDEX_NOT_FOUND\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_InitializeReportForID (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ IN UCHAR ReportID,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData,\r
+ IN OUT PCHAR Report,\r
+ IN ULONG ReportLength\r
+ );\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Initialize a report based on the given report ID.\r
+\r
+Parameters:\r
+\r
+ ReportType One of HidP_Input, HidP_Output, or HidP_Feature.\r
+\r
+ PreparasedData Preparsed data structure returned by HIDCLASS\r
+\r
+ Report Buffer which to set the data into.\r
+\r
+ ReportLength Length of Report...Report should be at least as long as the\r
+ value indicated in the HIDP_CAPS structure for the device and\r
+ the corresponding ReportType\r
+\r
+Return Value\r
+\r
+· HIDP_STATUS_INVALID_REPORT_TYPE -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH -- the length of the report packet is not equal\r
+ to the length specified in HIDP_CAPS\r
+ structure for the given ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST -- if there are no reports on this device\r
+ for the given ReportType\r
+\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_SetData (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ IN PHIDP_DATA DataList,\r
+ IN OUT PULONG DataLength,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData,\r
+ IN OUT PCHAR Report,\r
+ IN ULONG ReportLength\r
+ );\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Please Note: Since usage value arrays deal with multiple fields for\r
+ for one usage value, they cannot be used with HidP_SetData\r
+ and HidP_GetData. In this case,\r
+ HIDP_STATUS_IS_USAGE_VALUE_ARRAY will be returned.\r
+\r
+Parameters:\r
+\r
+ ReportType One of HidP_Input, HidP_Output, or HidP_Feature.\r
+\r
+ DataList Array of HIDP_DATA structures that contains the data values\r
+ that are to be set into the given report\r
+\r
+ DataLength As input, length in array elements of DataList. As output,\r
+ contains the number of data elements set on successful\r
+ completion or an index into the DataList array to identify\r
+ the faulting HIDP_DATA value if an error code is returned.\r
+\r
+ PreparasedData Preparsed data structure returned by HIDCLASS\r
+\r
+ Report Buffer which to set the data into.\r
+\r
+ ReportLength Length of Report...Report should be at least as long as the\r
+ value indicated in the HIDP_CAPS structure for the device and\r
+ the corresponding ReportType\r
+\r
+Return Value\r
+ HidP_SetData returns the following error codes. The report packet will\r
+ have all the data set up until the HIDP_DATA structure that caused the\r
+ error. DataLength, in the error case, will return this problem index.\r
+\r
+· HIDP_STATUS_SUCCESS -- upon successful insertion of all data\r
+ into the report packet.\r
+· HIDP_STATUS_INVALID_REPORT_TYPE -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_DATA_INDEX_NOT_FOUND -- if a HIDP_DATA structure referenced a\r
+ data index that does not exist for this\r
+ device's ReportType\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH -- the length of the report packet is not equal\r
+ to the length specified in HIDP_CAPS\r
+ structure for the given ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST -- if there are no reports on this device\r
+ for the given ReportType\r
+· HIDP_STATUS_IS_USAGE_VALUE_ARRAY -- if one of the HIDP_DATA structures\r
+ references a usage value array.\r
+ DataLength will contain the index into\r
+ the array that was invalid\r
+· HIDP_STATUS_BUTTON_NOT_PRESSED -- if a HIDP_DATA structure attempted\r
+ to unset a button that was not already\r
+ set in the Report\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- a HIDP_DATA structure was found with\r
+ a valid index value but is contained\r
+ in a different report than the one\r
+ currently being processed\r
+· HIDP_STATUS_BUFFER_TOO_SMALL -- if there are not enough entries in\r
+ a given Main Array Item to report all\r
+ buttons that have been requested to be\r
+ set\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetData (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ OUT PHIDP_DATA DataList,\r
+ IN OUT PULONG DataLength,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData,\r
+ IN PCHAR Report,\r
+ IN ULONG ReportLength\r
+ );\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Please Note: For obvious reasons HidP_SetData and HidP_GetData will not\r
+ access UsageValueArrays.\r
+\r
+Parameters:\r
+ ReportType One of HidP_Input, HidP_Output, or HidP_Feature.\r
+\r
+ DataList Array of HIDP_DATA structures that will receive the data\r
+ values that are set in the given report\r
+\r
+ DataLength As input, length in array elements of DataList. As output,\r
+ contains the number of data elements that were successfully\r
+ set by HidP_GetData. The maximum size necessary for DataList\r
+ can be determined by calling HidP_MaxDataListLength\r
+\r
+ PreparasedData Preparsed data structure returned by HIDCLASS\r
+\r
+ Report Buffer which to set the data into.\r
+\r
+ ReportLength Length of Report...Report should be at least as long as the\r
+ value indicated in the HIDP_CAPS structure for the device and\r
+ the corresponding ReportType\r
+\r
+Return Value\r
+ HidP_GetData returns the following error codes.\r
+\r
+· HIDP_STATUS_SUCCESS -- upon successful retrieval of all data\r
+ from the report packet.\r
+· HIDP_STATUS_INVALID_REPORT_TYPE -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH -- the length of the report packet is not equal\r
+ to the length specified in HIDP_CAPS\r
+ structure for the given ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST -- if there are no reports on this device\r
+ for the given ReportType\r
+· HIDP_STATUS_BUFFER_TOO_SMALL -- if there are not enough array entries in\r
+ DataList to store all the indice values\r
+ in the given report. DataLength will\r
+ contain the number of array entries\r
+ required to hold all data\r
+--*/\r
+\r
+ULONG __stdcall\r
+HidP_MaxDataListLength (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData\r
+ );\r
+/*++\r
+Routine Description:\r
+\r
+ This function returns the maximum length of HIDP_DATA elements that\r
+ HidP_GetData could return for the given report type.\r
+\r
+Parameters:\r
+\r
+ ReportType One of HidP_Input, HidP_Output or HidP_Feature.\r
+\r
+ PreparsedData Preparsed data structure returned by HIDCLASS\r
+\r
+Return Value:\r
+\r
+ The length of the data list array required for the HidP_GetData function\r
+ call. If an error occurs (either HIDP_STATUS_INVALID_REPORT_TYPE or\r
+ HIDP_STATUS_INVALID_PREPARSED_DATA), this function returns 0.\r
+\r
+--*/\r
+\r
+#define HidP_SetButtons(Rty, Up, Lco, ULi, ULe, Ppd, Rep, Rle) \\r
+ HidP_SetUsages(Rty, Up, Lco, ULi, ULe, Ppd, Rep, Rle)\r
+\r
+NTSTATUS __stdcall\r
+HidP_SetUsages (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ IN USAGE UsagePage,\r
+ IN USHORT LinkCollection, // Optional\r
+ IN PUSAGE UsageList,\r
+ IN OUT PULONG UsageLength,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData,\r
+ IN OUT PCHAR Report,\r
+ IN ULONG ReportLength\r
+ );\r
+/*++\r
+\r
+Routine Description:\r
+ This function sets binary values (buttons) in a report. Given an\r
+ initialized packet of correct length, it modifies the report packet so that\r
+ each element in the given list of usages has been set in the report packet.\r
+ For example, in an output report with 5 LED\92s, each with a given usage,\r
+ an application could turn on any subset of these lights by placing their\r
+ usages in any order into the usage array (UsageList). HidP_SetUsages would,\r
+ in turn, set the appropriate bit or add the corresponding byte into the\r
+ HID Main Array Item.\r
+\r
+ A properly initialized Report packet is one of the correct byte length,\r
+ and all zeros.\r
+\r
+ NOTE: A packet that has already been set with a call to a HidP_Set routine\r
+ can also be passed in. This routine then sets processes the UsageList\r
+ in the same fashion but verifies that the ReportID already set in\r
+ Report matches the report ID for the given usages.\r
+\r
+Parameters:\r
+ ReportType One of HidP_Input, HidP_Output or HidP_Feature.\r
+\r
+ UsagePage All of the usages in the usage array, which HidP_SetUsages will\r
+ set in the report, refer to this same usage page.\r
+ If a client wishes to set usages in a report for multiple\r
+ usage pages then that client needs to make multiple calls to\r
+ HidP_SetUsages for each of the usage pages.\r
+\r
+ UsageList A usage array containing the usages that HidP_SetUsages will set in\r
+ the report packet.\r
+\r
+ UsageLength The length of the given usage array in array elements.\r
+ The parser will set this value to the position in the usage\r
+ array where it stopped processing. If successful, UsageLength\r
+ will be unchanged. In any error condition, this parameter\r
+ reflects how many of the usages in the usage list have\r
+ actually been set by the parser. This is useful for finding\r
+ the usage in the list which caused the error.\r
+\r
+ PreparsedData The preparsed data recevied from HIDCLASS\r
+\r
+ Report The report packet.\r
+\r
+ ReportLength Length of the given report packet...Must be equal to the\r
+ value reported in the HIDP_CAPS structure for the device\r
+ and corresponding report type.\r
+\r
+Return Value\r
+ HidP_SetUsages returns the following error codes. On error, the report packet\r
+ will be correct up until the usage element that caused the error.\r
+\r
+· HIDP_STATUS_SUCCESS -- upon successful insertion of all usages\r
+ into the report packet.\r
+· HIDP_STATUS_INVALID_REPORT_TYPE -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH -- the length of the report packet is not\r
+ equal to the length specified in\r
+ the HIDP_CAPS structure for the given\r
+ ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST -- if there are no reports on this device\r
+ for the given ReportType\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- if a usage was found that exists in a\r
+ different report. If the report is\r
+ zero-initialized on entry the first\r
+ usage in the list will determine which\r
+ report ID is used. Otherwise, the\r
+ parser will verify that usage matches\r
+ the passed in report's ID\r
+· HIDP_STATUS_USAGE_NOT_FOUND -- if the usage does not exist for any\r
+ report (no matter what the report ID)\r
+ for the given report type.\r
+· HIDP_STATUS_BUFFER_TOO_SMALL -- if there are not enough entries in a\r
+ given Main Array Item to list all of\r
+ the given usages. The caller needs\r
+ to split his request into more than\r
+ one call\r
+--*/\r
+\r
+#define HidP_UnsetButtons(Rty, Up, Lco, ULi, ULe, Ppd, Rep, Rle) \\r
+ HidP_UnsetUsages(Rty, Up, Lco, ULi, ULe, Ppd, Rep, Rle)\r
+\r
+NTSTATUS __stdcall\r
+HidP_UnsetUsages (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ IN USAGE UsagePage,\r
+ IN USHORT LinkCollection, // Optional\r
+ IN PUSAGE UsageList,\r
+ IN OUT PULONG UsageLength,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData,\r
+ IN OUT PCHAR Report,\r
+ IN ULONG ReportLength\r
+ );\r
+/*++\r
+\r
+Routine Description:\r
+ This function unsets (turns off) binary values (buttons) in the report. Given\r
+ an initialized packet of correct length, it modifies the report packet so\r
+ that each element in the given list of usages has been unset in the\r
+ report packet.\r
+\r
+ This function is the "undo" operation for SetUsages. If the given usage\r
+ is not already set in the Report, it will return an error code of\r
+ HIDP_STATUS_BUTTON_NOT_PRESSED. If the button is pressed, HidP_UnsetUsages\r
+ will unset the appropriate bit or remove the corresponding index value from\r
+ the HID Main Array Item.\r
+\r
+ A properly initialized Report packet is one of the correct byte length,\r
+ and all zeros..\r
+\r
+ NOTE: A packet that has already been set with a call to a HidP_Set routine\r
+ can also be passed in. This routine then processes the UsageList\r
+ in the same fashion but verifies that the ReportID already set in\r
+ Report matches the report ID for the given usages.\r
+\r
+Parameters:\r
+ ReportType One of HidP_Input, HidP_Output or HidP_Feature.\r
+\r
+ UsagePage All of the usages in the usage array, which HidP_UnsetUsages will\r
+ unset in the report, refer to this same usage page.\r
+ If a client wishes to unset usages in a report for multiple\r
+ usage pages then that client needs to make multiple calls to\r
+ HidP_UnsetUsages for each of the usage pages.\r
+\r
+ UsageList A usage array containing the usages that HidP_UnsetUsages will\r
+ unset in the report packet.\r
+\r
+ UsageLength The length of the given usage array in array elements.\r
+ The parser will set this value to the position in the usage\r
+ array where it stopped processing. If successful, UsageLength\r
+ will be unchanged. In any error condition, this parameter\r
+ reflects how many of the usages in the usage list have\r
+ actually been unset by the parser. This is useful for finding\r
+ the usage in the list which caused the error.\r
+\r
+ PreparsedData The preparsed data recevied from HIDCLASS\r
+\r
+ Report The report packet.\r
+\r
+ ReportLength Length of the given report packet...Must be equal to the\r
+ value reported in the HIDP_CAPS structure for the device\r
+ and corresponding report type.\r
+\r
+Return Value\r
+ HidP_UnsetUsages returns the following error codes. On error, the report\r
+ packet will be correct up until the usage element that caused the error.\r
+\r
+· HIDP_STATUS_SUCCESS -- upon successful "unsetting" of all usages\r
+ in the report packet.\r
+· HIDP_STATUS_INVALID_REPORT_TYPE -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH -- the length of the report packet is not\r
+ equal to the length specified in\r
+ the HIDP_CAPS structure for the given\r
+ ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST -- if there are no reports on this device\r
+ for the given ReportType\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- if a usage was found that exists in a\r
+ different report. If the report is\r
+ zero-initialized on entry the first\r
+ usage in the list will determine which\r
+ report ID is used. Otherwise, the\r
+ parser will verify that usage matches\r
+ the passed in report's ID\r
+· HIDP_STATUS_USAGE_NOT_FOUND -- if the usage does not exist for any\r
+ report (no matter what the report ID)\r
+ for the given report type.\r
+· HIDP_STATUS_BUTTON_NOT_PRESSED -- if a usage corresponds to a button that\r
+ is not already set in the given report\r
+--*/\r
+\r
+#define HidP_GetButtons(Rty, UPa, LCo, ULi, ULe, Ppd, Rep, RLe) \\r
+ HidP_GetUsages(Rty, UPa, LCo, ULi, ULe, Ppd, Rep, RLe)\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetUsages (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ IN USAGE UsagePage,\r
+ IN USHORT LinkCollection, // Optional\r
+ OUT USAGE * UsageList,\r
+ IN OUT ULONG * UsageLength,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData,\r
+ IN PCHAR Report,\r
+ IN ULONG ReportLength\r
+ );\r
+/*++\r
+\r
+Routine Description:\r
+ This function returns the binary values (buttons) that are set in a HID\r
+ report. Given a report packet of correct length, it searches the report\r
+ packet for each usage for the given usage page and returns them in the\r
+ usage list.\r
+\r
+Parameters:\r
+ ReportType One of HidP_Input, HidP_Output or HidP_Feature.\r
+\r
+ UsagePage All of the usages in the usage list, which HidP_GetUsages will\r
+ retrieve in the report, refer to this same usage page.\r
+ If the client wishes to get usages in a packet for multiple\r
+ usage pages then that client needs to make multiple calls\r
+ to HidP_GetUsages.\r
+\r
+ LinkCollection An optional value which can limit which usages are returned\r
+ in the UsageList to those usages that exist in a specific\r
+ LinkCollection. A non-zero value indicates the index into\r
+ the HIDP_LINK_COLLECITON_NODE list returned by\r
+ HidP_GetLinkCollectionNodes of the link collection the\r
+ usage should belong to. A value of 0 indicates this\r
+ should value be ignored.\r
+\r
+ UsageList The usage array that will contain all the usages found in\r
+ the report packet.\r
+\r
+ UsageLength The length of the given usage array in array elements.\r
+ On input, this value describes the length of the usage list.\r
+ On output, HidP_GetUsages sets this value to the number of\r
+ usages that was found. Use HidP_MaxUsageListLength to\r
+ determine the maximum length needed to return all the usages\r
+ that a given report packet may contain.\r
+\r
+ PreparsedData Preparsed data structure returned by HIDCLASS\r
+\r
+ Report The report packet.\r
+\r
+ ReportLength Length (in bytes) of the given report packet\r
+\r
+\r
+Return Value\r
+ HidP_GetUsages returns the following error codes:\r
+\r
+· HIDP_STATUS_SUCCESS -- upon successfully retrieving all the\r
+ usages from the report packet\r
+· HIDP_STATUS_INVALID_REPORT_TYPE -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH -- the length of the report packet is not\r
+ equal to the length specified in\r
+ the HIDP_CAPS structure for the given\r
+ ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST -- if there are no reports on this device\r
+ for the given ReportType\r
+· HIDP_STATUS_BUFFER_TOO_SMALL -- if the UsageList is not big enough to\r
+ hold all the usages found in the report\r
+ packet. If this is returned, the buffer\r
+ will contain UsageLength number of\r
+ usages. Use HidP_MaxUsageListLength to\r
+ find the maximum length needed\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- if no usages were found but usages\r
+ that match the UsagePage and\r
+ LinkCollection specified could be found\r
+ in a report with a different report ID\r
+· HIDP_STATUS_USAGE_NOT_FOUND -- if there are no usages in a reports for\r
+ the device and ReportType that match the\r
+ UsagePage and LinkCollection that were\r
+ specified\r
+--*/\r
+\r
+#define HidP_GetButtonsEx(Rty, LCo, BLi, ULe, Ppd, Rep, RLe) \\r
+ HidP_GetUsagesEx(Rty, LCo, BLi, ULe, Ppd, Rep, RLe)\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetUsagesEx (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ IN USHORT LinkCollection, // Optional\r
+ OUT PUSAGE_AND_PAGE ButtonList,\r
+ IN OUT ULONG * UsageLength,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData,\r
+ IN PCHAR Report,\r
+ IN ULONG ReportLength\r
+ );\r
+\r
+/*++\r
+\r
+Routine Description:\r
+ This function returns the binary values (buttons) in a HID report.\r
+ Given a report packet of correct length, it searches the report packet\r
+ for all buttons and returns the UsagePage and Usage for each of the buttons\r
+ it finds.\r
+\r
+Parameters:\r
+ ReportType One of HidP_Input, HidP_Output or HidP_Feature.\r
+\r
+ LinkCollection An optional value which can limit which usages are returned\r
+ in the ButtonList to those usages that exist in a specific\r
+ LinkCollection. A non-zero value indicates the index into\r
+ the HIDP_LINK_COLLECITON_NODE list returned by\r
+ HidP_GetLinkCollectionNodes of the link collection the\r
+ usage should belong to. A value of 0 indicates this\r
+ should value be ignored.\r
+\r
+ ButtonList An array of USAGE_AND_PAGE structures describing all the\r
+ buttons currently ``down'' in the device.\r
+\r
+ UsageLength The length of the given array in terms of elements.\r
+ On input, this value describes the length of the list. On\r
+ output, HidP_GetUsagesEx sets this value to the number of\r
+ usages that were found. Use HidP_MaxUsageListLength to\r
+ determine the maximum length needed to return all the usages\r
+ that a given report packet may contain.\r
+\r
+ PreparsedData Preparsed data returned by HIDCLASS\r
+\r
+ Report The report packet.\r
+\r
+ ReportLength Length (in bytes) of the given report packet.\r
+\r
+\r
+Return Value\r
+ HidP_GetUsagesEx returns the following error codes:\r
+\r
+· HIDP_STATUS_SUCCESS -- upon successfully retrieving all the\r
+ usages from the report packet\r
+· HIDP_STATUS_INVALID_REPORT_TYPE -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH -- the length of the report packet is not\r
+ equal to the length specified in\r
+ the HIDP_CAPS structure for the given\r
+ ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST -- if there are no reports on this device\r
+ for the given ReportType\r
+· HIDP_STATUS_BUFFER_TOO_SMALL -- if ButtonList is not big enough to\r
+ hold all the usages found in the report\r
+ packet. If this is returned, the buffer\r
+ will contain UsageLength number of\r
+ usages. Use HidP_MaxUsageListLength to\r
+ find the maximum length needed\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- if no usages were found but usages\r
+ that match the specified LinkCollection\r
+ exist in report with a different report\r
+ ID.\r
+· HIDP_STATUS_USAGE_NOT_FOUND -- if there are no usages in any reports that\r
+ match the LinkCollection parameter\r
+--*/\r
+\r
+#define HidP_GetButtonListLength(RTy, UPa, Ppd) \\r
+ HidP_GetUsageListLength(Rty, UPa, Ppd)\r
+\r
+ULONG __stdcall\r
+HidP_MaxUsageListLength (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ IN USAGE UsagePage, // Optional\r
+ IN PHIDP_PREPARSED_DATA PreparsedData\r
+ );\r
+/*++\r
+Routine Description:\r
+ This function returns the maximum number of usages that a call to\r
+ HidP_GetUsages or HidP_GetUsagesEx could return for a given HID report.\r
+ If calling for number of usages returned by HidP_GetUsagesEx, use 0 as\r
+ the UsagePage value.\r
+\r
+Parameters:\r
+ ReportType One of HidP_Input, HidP_Output or HidP_Feature.\r
+\r
+ UsagePage Specifies the optional UsagePage to query for. If 0, will\r
+ return all the maximum number of usage values that could be\r
+ returned for a given ReportType. If non-zero, will return\r
+ the maximum number of usages that would be returned for the\r
+ ReportType with the given UsagePage.\r
+\r
+ PreparsedData Preparsed data returned from HIDCLASS\r
+\r
+Return Value:\r
+ The length of the usage list array required for the HidP_GetUsages or\r
+ HidP_GetUsagesEx function call. If an error occurs (such as\r
+ HIDP_STATUS_INVALID_REPORT_TYPE or HIDP_INVALID_PREPARSED_DATA, this\r
+ returns 0.\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_SetUsageValue (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ IN USAGE UsagePage,\r
+ IN USHORT LinkCollection, // Optional\r
+ IN USAGE Usage,\r
+ IN ULONG UsageValue,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData,\r
+ IN OUT PCHAR Report,\r
+ IN ULONG ReportLength\r
+ );\r
+/*++\r
+Description:\r
+ HidP_SetUsageValue inserts a value into the HID Report Packet in the field\r
+ corresponding to the given usage page and usage. HidP_SetUsageValue\r
+ casts this value to the appropriate bit length. If a report packet\r
+ contains two different fields with the same Usage and UsagePage,\r
+ they can be distinguished with the optional LinkCollection field value.\r
+ Using this function sets the raw value into the report packet with\r
+ no checking done as to whether it actually falls within the logical\r
+ minimum/logical maximum range. Use HidP_SetScaledUsageValue for this...\r
+\r
+ NOTE: Although the UsageValue parameter is a ULONG, any casting that is\r
+ done will preserve or sign-extend the value. The value being set\r
+ should be considered a LONG value and will be treated as such by\r
+ this function.\r
+\r
+Parameters:\r
+\r
+ ReportType One of HidP_Output or HidP_Feature.\r
+\r
+ UsagePage The usage page to which the given usage refers.\r
+\r
+ LinkCollection (Optional) This value can be used to differentiate\r
+ between two fields that may have the same\r
+ UsagePage and Usage but exist in different\r
+ collections. If the link collection value\r
+ is zero, this function will set the first field\r
+ it finds that matches the usage page and\r
+ usage.\r
+\r
+ Usage The usage whose value HidP_SetUsageValue will set.\r
+\r
+ UsageValue The raw value to set in the report buffer. This value must be within\r
+ the logical range or if a NULL value this value should be the\r
+ most negative value that can be represented by the number of bits\r
+ for this field.\r
+\r
+ PreparsedData The preparsed data returned for HIDCLASS\r
+\r
+ Report The report packet.\r
+\r
+ ReportLength Length (in bytes) of the given report packet.\r
+\r
+\r
+Return Value:\r
+ HidP_SetUsageValue returns the following error codes:\r
+\r
+· HIDP_STATUS_SUCCESS -- upon successfully setting the value\r
+ in the report packet\r
+· HIDP_STATUS_INVALID_REPORT_TYPE -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH -- the length of the report packet is not\r
+ equal to the length specified in\r
+ the HIDP_CAPS structure for the given\r
+ ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST -- if there are no reports on this device\r
+ for the given ReportType\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- the specified usage page, usage and\r
+ link collection exist but exists in\r
+ a report with a different report ID\r
+ than the report being passed in. To\r
+ set this value, call HidP_SetUsageValue\r
+ again with a zero-initizialed report\r
+ packet\r
+· HIDP_STATUS_USAGE_NOT_FOUND -- if the usage page, usage, and link\r
+ collection combination does not exist\r
+ in any reports for this ReportType\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_SetScaledUsageValue (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ IN USAGE UsagePage,\r
+ IN USHORT LinkCollection, // Optional\r
+ IN USAGE Usage,\r
+ IN LONG UsageValue,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData,\r
+ IN OUT PCHAR Report,\r
+ IN ULONG ReportLength\r
+ );\r
+\r
+/*++\r
+Description:\r
+ HidP_SetScaledUsageValue inserts the UsageValue into the HID report packet\r
+ in the field corresponding to the given usage page and usage. If a report\r
+ packet contains two different fields with the same Usage and UsagePage,\r
+ they can be distinguished with the optional LinkCollection field value.\r
+\r
+ If the specified field has a defined physical range, this function converts\r
+ the physical value specified to the corresponding logical value for the\r
+ report. If a physical value does not exist, the function will verify that\r
+ the value specified falls within the logical range and set according.\r
+\r
+ If the range checking fails but the field has NULL values, the function will\r
+ set the field to the defined NULL value (most negative number possible) and\r
+ return HIDP_STATUS_NULL. In other words, use this function to set NULL\r
+ values for a given field by passing in a value that falls outside the\r
+ physical range if it is defined or the logical range otherwise.\r
+\r
+ If the field does not support NULL values, an out of range error will be\r
+ returned instead.\r
+\r
+Parameters:\r
+\r
+ ReportType One of HidP_Output or HidP_Feature.\r
+\r
+ UsagePage The usage page to which the given usage refers.\r
+\r
+ LinkCollection (Optional) This value can be used to differentiate\r
+ between two fields that may have the same\r
+ UsagePage and Usage but exist in different\r
+ collections. If the link collection value\r
+ is zero, this function will set the first field\r
+ it finds that matches the usage page and\r
+ usage.\r
+\r
+ Usage The usage whose value HidP_SetScaledUsageValue will set.\r
+\r
+ UsageValue The value to set in the report buffer. See the routine\r
+ description above for the different interpretations of this\r
+ value\r
+\r
+ PreparsedData The preparsed data returned from HIDCLASS\r
+\r
+ Report The report packet.\r
+\r
+ ReportLength Length (in bytes) of the given report packet.\r
+\r
+\r
+Return Value:\r
+ HidP_SetScaledUsageValue returns the following error codes:\r
+\r
+· HIDP_STATUS_SUCCESS -- upon successfully setting the value\r
+ in the report packet\r
+· HIDP_STATUS_NULL -- upon successfully setting the value\r
+ in the report packet as a NULL value\r
+· HIDP_STATUS_INVALID_REPORT_TYPE -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH -- the length of the report packet is not\r
+ equal to the length specified in\r
+ the HIDP_CAPS structure for the given\r
+ ReportType\r
+· HIDP_STATUS_VALUE_OUT_OF_RANGE -- if the value specified failed to fall\r
+ within the physical range if it exists\r
+ or within the logical range otherwise\r
+ and the field specified by the usage\r
+ does not allow NULL values\r
+· HIDP_STATUS_BAD_LOG_PHY_VALUES -- if the field has a physical range but\r
+ either the logical range is invalid\r
+ (max <= min) or the physical range is\r
+ invalid\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- the specified usage page, usage and\r
+ link collection exist but exists in\r
+ a report with a different report ID\r
+ than the report being passed in. To\r
+ set this value, call\r
+ HidP_SetScaledUsageValue again with\r
+ a zero-initialized report packet\r
+· HIDP_STATUS_USAGE_NOT_FOUND -- if the usage page, usage, and link\r
+ collection combination does not exist\r
+ in any reports for this ReportType\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_SetUsageValueArray (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ IN USAGE UsagePage,\r
+ IN USHORT LinkCollection, // Optional\r
+ IN USAGE Usage,\r
+ IN PCHAR UsageValue,\r
+ IN USHORT UsageValueByteLength,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData,\r
+ OUT PCHAR Report,\r
+ IN ULONG ReportLength\r
+ );\r
+\r
+/*++\r
+Routine Descripton:\r
+ A usage value array occurs when the last usage in the list of usages\r
+ describing a main item must be repeated because there are less usages defined\r
+ than there are report counts declared for the given main item. In this case\r
+ a single value cap is allocated for that usage and the report count of that\r
+ value cap is set to reflect the number of fields to which that usage refers.\r
+\r
+ HidP_SetUsageValueArray sets the raw bits for that usage which spans\r
+ more than one field in a report.\r
+\r
+ NOTE: This function currently does not support value arrays where the\r
+ ReportSize for each of the fields in the array is not a multiple\r
+ of 8 bits.\r
+\r
+ The UsageValue buffer should have the values set as they would appear\r
+ in the report buffer. If this function supported non 8-bit multiples\r
+ for the ReportSize then caller should format the input buffer so that\r
+ each new value begins at the bit immediately following the last bit\r
+ of the previous value\r
+\r
+Parameters:\r
+\r
+ ReportType One of HidP_Output or HidP_Feature.\r
+\r
+ UsagePage The usage page to which the given usage refers.\r
+\r
+ LinkCollection (Optional) This value can be used to differentiate\r
+ between two fields that may have the same\r
+ UsagePage and Usage but exist in different\r
+ collections. If the link collection value\r
+ is zero, this function will set the first field\r
+ it finds that matches the usage page and\r
+ usage.\r
+\r
+ Usage The usage whose value array HidP_SetUsageValueArray will set.\r
+\r
+ UsageValue The buffer with the values to set into the value array.\r
+ The number of BITS required is found by multiplying the\r
+ BitSize and ReportCount fields of the Value Cap for this\r
+ control. The least significant bit of this control found in the\r
+ given report will be placed in the least significan bit location\r
+ of the array given (little-endian format), regardless of whether\r
+ or not the field is byte alligned or if the BitSize is a multiple\r
+ of sizeof (CHAR).\r
+\r
+ See the above note for current implementation limitations.\r
+\r
+ UsageValueByteLength Length of the UsageValue buffer (in bytes)\r
+\r
+ PreparsedData The preparsed data returned from HIDCLASS\r
+\r
+ Report The report packet.\r
+\r
+ ReportLength Length (in bytes) of the given report packet.\r
+\r
+\r
+Return Value:\r
+· HIDP_STATUS_SUCCESS -- upon successfully setting the value\r
+ array in the report packet\r
+· HIDP_STATUS_INVALID_REPORT_TYPE -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH -- the length of the report packet is not\r
+ equal to the length specified in\r
+ the HIDP_CAPS structure for the given\r
+ ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST -- if there are no reports on this device\r
+ for the given ReportType\r
+· HIDP_STATUS_NOT_VALUE_ARRAY -- if the control specified is not a\r
+ value array -- a value array will have\r
+ a ReportCount field in the\r
+ HIDP_VALUE_CAPS structure that is > 1\r
+ Use HidP_SetUsageValue instead\r
+· HIDP_STATUS_BUFFER_TOO_SMALL -- if the size of the passed in buffer with\r
+ the values to set is too small (ie. has\r
+ fewer values than the number of fields in\r
+ the array\r
+· HIDP_STATUS_NOT_IMPLEMENTED -- if the usage value array has field sizes\r
+ that are not multiples of 8 bits, this\r
+ error code is returned since the function\r
+ currently does not handle setting into\r
+ such arrays.\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- the specified usage page, usage and\r
+ link collection exist but exists in\r
+ a report with a different report ID\r
+ than the report being passed in. To\r
+ set this value, call\r
+ HidP_SetUsageValueArray again with\r
+ a zero-initialized report packet\r
+· HIDP_STATUS_USAGE_NOT_FOUND -- if the usage page, usage, and link\r
+ collection combination does not exist\r
+ in any reports for this ReportType\r
+--*/\r
+\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetUsageValue (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ IN USAGE UsagePage,\r
+ IN USHORT LinkCollection, // Optional\r
+ IN USAGE Usage,\r
+ OUT PULONG UsageValue,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData,\r
+ IN PCHAR Report,\r
+ IN ULONG ReportLength\r
+ );\r
+\r
+/*\r
+Description\r
+ HidP_GetUsageValue retrieves the value from the HID Report for the usage\r
+ specified by the combination of usage page, usage and link collection.\r
+ If a report packet contains two different fields with the same\r
+ Usage and UsagePage, they can be distinguished with the optional\r
+ LinkCollection field value.\r
+\r
+Parameters:\r
+\r
+ ReportType One of HidP_Input or HidP_Feature.\r
+\r
+ UsagePage The usage page to which the given usage refers.\r
+\r
+ LinkCollection (Optional) This value can be used to differentiate\r
+ between two fields that may have the same\r
+ UsagePage and Usage but exist in different\r
+ collections. If the link collection value\r
+ is zero, this function will set the first field\r
+ it finds that matches the usage page and\r
+ usage.\r
+\r
+ Usage The usage whose value HidP_GetUsageValue will retrieve\r
+\r
+ UsageValue The raw value that is set for the specified field in the report\r
+ buffer. This value will either fall within the logical range\r
+ or if NULL values are allowed, a number outside the range to\r
+ indicate a NULL\r
+\r
+ PreparsedData The preparsed data returned for HIDCLASS\r
+\r
+ Report The report packet.\r
+\r
+ ReportLength Length (in bytes) of the given report packet.\r
+\r
+\r
+Return Value:\r
+ HidP_GetUsageValue returns the following error codes:\r
+\r
+· HIDP_STATUS_SUCCESS -- upon successfully retrieving the value\r
+ from the report packet\r
+· HIDP_STATUS_INVALID_REPORT_TYPE -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH -- the length of the report packet is not\r
+ equal to the length specified in\r
+ the HIDP_CAPS structure for the given\r
+ ReportType\r
+· HIDP_STATUS_REPORT_DOES_NOT_EXIST -- if there are no reports on this device\r
+ for the given ReportType\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- the specified usage page, usage and\r
+ link collection exist but exists in\r
+ a report with a different report ID\r
+ than the report being passed in. To\r
+ set this value, call HidP_GetUsageValue\r
+ again with a different report packet\r
+· HIDP_STATUS_USAGE_NOT_FOUND -- if the usage page, usage, and link\r
+ collection combination does not exist\r
+ in any reports for this ReportType\r
+--*/\r
+\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetScaledUsageValue (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ IN USAGE UsagePage,\r
+ IN USHORT LinkCollection, // Optional\r
+ IN USAGE Usage,\r
+ OUT PLONG UsageValue,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData,\r
+ IN PCHAR Report,\r
+ IN ULONG ReportLength\r
+ );\r
+\r
+/*++\r
+Description\r
+ HidP_GetScaledUsageValue retrieves a UsageValue from the HID report packet\r
+ in the field corresponding to the given usage page and usage. If a report\r
+ packet contains two different fields with the same Usage and UsagePage,\r
+ they can be distinguished with the optional LinkCollection field value.\r
+\r
+ If the specified field has a defined physical range, this function converts\r
+ the logical value that exists in the report packet to the corresponding\r
+ physical value. If a physical range does not exist, the function will\r
+ return the logical value. This function will check to verify that the\r
+ logical value in the report falls within the declared logical range.\r
+\r
+ When doing the conversion between logical and physical values, this\r
+ function assumes a linear extrapolation between the physical max/min and\r
+ the logical max/min. (Where logical is the values reported by the device\r
+ and physical is the value returned by this function). If the data field\r
+ size is less than 32 bits, then HidP_GetScaledUsageValue will sign extend\r
+ the value to 32 bits.\r
+\r
+ If the range checking fails but the field has NULL values, the function\r
+ will set UsageValue to 0 and return HIDP_STATUS_NULL. Otherwise, it\r
+ returns a HIDP_STATUS_OUT_OF_RANGE error.\r
+\r
+Parameters:\r
+\r
+ ReportType One of HidP_Output or HidP_Feature.\r
+\r
+ UsagePage The usage page to which the given usage refers.\r
+\r
+ LinkCollection (Optional) This value can be used to differentiate\r
+ between two fields that may have the same\r
+ UsagePage and Usage but exist in different\r
+ collections. If the link collection value\r
+ is zero, this function will retrieve the first\r
+ field it finds that matches the usage page\r
+ and usage.\r
+\r
+ Usage The usage whose value HidP_GetScaledUsageValue will retrieve\r
+\r
+ UsageValue The value retrieved from the report buffer. See the routine\r
+ description above for the different interpretations of this\r
+ value\r
+\r
+ PreparsedData The preparsed data returned from HIDCLASS\r
+\r
+ Report The report packet.\r
+\r
+ ReportLength Length (in bytes) of the given report packet.\r
+\r
+\r
+Return Value:\r
+ HidP_GetScaledUsageValue returns the following error codes:\r
+\r
+· HIDP_STATUS_SUCCESS -- upon successfully retrieving the value\r
+ from the report packet\r
+· HIDP_STATUS_NULL -- if the report packet had a NULL value\r
+ set\r
+· HIDP_STATUS_INVALID_REPORT_TYPE -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH -- the length of the report packet is not\r
+ equal to the length specified in\r
+ the HIDP_CAPS structure for the given\r
+ ReportType\r
+· HIDP_STATUS_VALUE_OUT_OF_RANGE -- if the value retrieved from the packet\r
+ falls outside the logical range and\r
+ the field does not support NULL values\r
+· HIDP_STATUS_BAD_LOG_PHY_VALUES -- if the field has a physical range but\r
+ either the logical range is invalid\r
+ (max <= min) or the physical range is\r
+ invalid\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- the specified usage page, usage and\r
+ link collection exist but exists in\r
+ a report with a different report ID\r
+ than the report being passed in. To\r
+ set this value, call\r
+ HidP_GetScaledUsageValue with a\r
+ different report packet\r
+· HIDP_STATUS_USAGE_NOT_FOUND -- if the usage page, usage, and link\r
+ collection combination does not exist\r
+ in any reports for this ReportType\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_GetUsageValueArray (\r
+ IN HIDP_REPORT_TYPE ReportType,\r
+ IN USAGE UsagePage,\r
+ IN USHORT LinkCollection, // Optional\r
+ IN USAGE Usage,\r
+ OUT PCHAR UsageValue,\r
+ IN USHORT UsageValueByteLength,\r
+ IN PHIDP_PREPARSED_DATA PreparsedData,\r
+ IN PCHAR Report,\r
+ IN ULONG ReportLength\r
+ );\r
+\r
+/*++\r
+Routine Descripton:\r
+ A usage value array occurs when the last usage in the list of usages\r
+ describing a main item must be repeated because there are less usages defined\r
+ than there are report counts declared for the given main item. In this case\r
+ a single value cap is allocated for that usage and the report count of that\r
+ value cap is set to reflect the number of fields to which that usage refers.\r
+\r
+ HidP_GetUsageValueArray returns the raw bits for that usage which spans\r
+ more than one field in a report.\r
+\r
+ NOTE: This function currently does not support value arrays where the\r
+ ReportSize for each of the fields in the array is not a multiple\r
+ of 8 bits.\r
+\r
+ The UsageValue buffer will have the raw values as they are set\r
+ in the report packet.\r
+\r
+Parameters:\r
+\r
+ ReportType One of HidP_Input, HidP_Output or HidP_Feature.\r
+\r
+ UsagePage The usage page to which the given usage refers.\r
+\r
+ LinkCollection (Optional) This value can be used to differentiate\r
+ between two fields that may have the same\r
+ UsagePage and Usage but exist in different\r
+ collections. If the link collection value\r
+ is zero, this function will set the first field\r
+ it finds that matches the usage page and\r
+ usage.\r
+\r
+ Usage The usage whose value HidP_GetUsageValueArray will retreive.\r
+\r
+ UsageValue A pointer to an array of characters where the value will be\r
+ placed. The number of BITS required is found by multiplying the\r
+ BitSize and ReportCount fields of the Value Cap for this\r
+ control. The least significant bit of this control found in the\r
+ given report will be placed in the least significant bit location\r
+ of the buffer (little-endian format), regardless of whether\r
+ or not the field is byte aligned or if the BitSize is a multiple\r
+ of sizeof (CHAR).\r
+\r
+ See note above about current implementation limitations\r
+\r
+ UsageValueByteLength\r
+ the length of the given UsageValue buffer.\r
+\r
+ PreparsedData The preparsed data returned by the HIDCLASS\r
+\r
+ Report The report packet.\r
+\r
+ ReportLength Length of the given report packet.\r
+\r
+Return Value:\r
+\r
+· HIDP_STATUS_SUCCESS -- upon successfully retrieving the value\r
+ from the report packet\r
+· HIDP_STATUS_INVALID_REPORT_TYPE -- if ReportType is not valid.\r
+· HIDP_STATUS_INVALID_PREPARSED_DATA -- if PreparsedData is not valid\r
+· HIDP_STATUS_INVALID_REPORT_LENGTH -- the length of the report packet is not\r
+ equal to the length specified in\r
+ the HIDP_CAPS structure for the given\r
+ ReportType\r
+· HIDP_STATUS_NOT_VALUE_ARRAY -- if the control specified is not a\r
+ value array -- a value array will have\r
+ a ReportCount field in the\r
+ HIDP_VALUE_CAPS structure that is > 1\r
+ Use HidP_GetUsageValue instead\r
+· HIDP_STATUS_BUFFER_TOO_SMALL -- if the size of the passed in buffer in\r
+ which to return the array is too small\r
+ (ie. has fewer values than the number of\r
+ fields in the array\r
+· HIDP_STATUS_NOT_IMPLEMENTED -- if the usage value array has field sizes\r
+ that are not multiples of 8 bits, this\r
+ error code is returned since the function\r
+ currently does not handle getting values\r
+ from such arrays.\r
+· HIDP_STATUS_INCOMPATIBLE_REPORT_ID -- the specified usage page, usage and\r
+ link collection exist but exists in\r
+ a report with a different report ID\r
+ than the report being passed in. To\r
+ set this value, call\r
+ HidP_GetUsageValueArray with a\r
+ different report packet\r
+· HIDP_STATUS_USAGE_NOT_FOUND -- if the usage page, usage, and link\r
+ collection combination does not exist\r
+ in any reports for this ReportType\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_UsageListDifference (\r
+ IN PUSAGE PreviousUsageList,\r
+ IN PUSAGE CurrentUsageList,\r
+ OUT PUSAGE BreakUsageList,\r
+ OUT PUSAGE MakeUsageList,\r
+ IN ULONG UsageListLength\r
+ );\r
+/*++\r
+Routine Description:\r
+ This function will return the difference between a two lists of usages\r
+ (as might be returned from HidP_GetUsages), In other words, it will return\r
+ return a list of usages that are in the current list but not the previous\r
+ list as well as a list of usages that are in the previous list but not\r
+ the current list.\r
+\r
+Parameters:\r
+\r
+ PreviousUsageList The list of usages before.\r
+ CurrentUsageList The list of usages now.\r
+ BreakUsageList Previous - Current.\r
+ MakeUsageList Current - Previous.\r
+ UsageListLength Represents the length of the usage lists in array\r
+ elements. If comparing two lists with a differing\r
+ number of array elements, this value should be\r
+ the size of the larger of the two lists. Any\r
+ zero found with a list indicates an early termination\r
+ of the list and any usages found after the first zero\r
+ will be ignored.\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_UsageAndPageListDifference (\r
+ IN PUSAGE_AND_PAGE PreviousUsageList,\r
+ IN PUSAGE_AND_PAGE CurrentUsageList,\r
+ OUT PUSAGE_AND_PAGE BreakUsageList,\r
+ OUT PUSAGE_AND_PAGE MakeUsageList,\r
+ IN ULONG UsageListLength\r
+ );\r
+\r
+//\r
+// Produce Make or Break Codes\r
+//\r
+typedef enum _HIDP_KEYBOARD_DIRECTION {\r
+ HidP_Keyboard_Break,\r
+ HidP_Keyboard_Make\r
+} HIDP_KEYBOARD_DIRECTION;\r
+\r
+//\r
+// A bitmap of the current shift state of the keyboard when using the\r
+// below keyboard usages to i8042 translation function.\r
+//\r
+typedef struct _HIDP_KEYBOARD_MODIFIER_STATE {\r
+ union {\r
+ struct {\r
+ ULONG LeftControl: 1;\r
+ ULONG LeftShift: 1;\r
+ ULONG LeftAlt: 1;\r
+ ULONG LeftGUI: 1;\r
+ ULONG RightControl: 1;\r
+ ULONG RightShift: 1;\r
+ ULONG RightAlt: 1;\r
+ ULONG RigthGUI: 1;\r
+ ULONG CapsLock: 1;\r
+ ULONG ScollLock: 1;\r
+ ULONG NumLock: 1;\r
+ ULONG Reserved: 21;\r
+ };\r
+ ULONG ul;\r
+ };\r
+\r
+} HIDP_KEYBOARD_MODIFIER_STATE, * PHIDP_KEYBOARD_MODIFIER_STATE;\r
+\r
+//\r
+// A call back function to give the i8042 scan codes to the caller of\r
+// the below translation function.\r
+//\r
+typedef BOOLEAN (* PHIDP_INSERT_SCANCODES) (\r
+ IN PVOID Context, // Some caller supplied context.\r
+ IN PCHAR NewScanCodes, // A list of i8042 scan codes.\r
+ IN ULONG Length // the length of the scan codes.\r
+ );\r
+\r
+NTSTATUS __stdcall\r
+HidP_TranslateUsageAndPagesToI8042ScanCodes (\r
+ IN PUSAGE_AND_PAGE ChangedUsageList,\r
+ IN ULONG UsageListLength,\r
+ IN HIDP_KEYBOARD_DIRECTION KeyAction,\r
+ IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState,\r
+ IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,\r
+ IN PVOID InsertCodesContext\r
+ );\r
+/*++\r
+Routine Description:\r
+Parameters:\r
+--*/\r
+\r
+NTSTATUS __stdcall\r
+HidP_TranslateUsagesToI8042ScanCodes (\r
+ IN PUSAGE ChangedUsageList,\r
+ IN ULONG UsageListLength,\r
+ IN HIDP_KEYBOARD_DIRECTION KeyAction,\r
+ IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState,\r
+ IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,\r
+ IN PVOID InsertCodesContext\r
+ );\r
+/*++\r
+Routine Description:\r
+Parameters:\r
+--*/\r
+\r
+\r
+\r
+//\r
+// Define NT Status codes with Facility Code of FACILITY_HID_ERROR_CODE\r
+//\r
+\r
+// FACILITY_HID_ERROR_CODE defined in ntstatus.h\r
+#ifndef FACILITY_HID_ERROR_CODE\r
+#define FACILITY_HID_ERROR_CODE 0x11\r
+#endif\r
+\r
+#define HIDP_ERROR_CODES(SEV, CODE) \\r
+ ((NTSTATUS) (((SEV) << 28) | (FACILITY_HID_ERROR_CODE << 16) | (CODE)))\r
+\r
+#define HIDP_STATUS_SUCCESS (HIDP_ERROR_CODES(0x0,0))\r
+#define HIDP_STATUS_NULL (HIDP_ERROR_CODES(0x8,1))\r
+#define HIDP_STATUS_INVALID_PREPARSED_DATA (HIDP_ERROR_CODES(0xC,1))\r
+#define HIDP_STATUS_INVALID_REPORT_TYPE (HIDP_ERROR_CODES(0xC,2))\r
+#define HIDP_STATUS_INVALID_REPORT_LENGTH (HIDP_ERROR_CODES(0xC,3))\r
+#define HIDP_STATUS_USAGE_NOT_FOUND (HIDP_ERROR_CODES(0xC,4))\r
+#define HIDP_STATUS_VALUE_OUT_OF_RANGE (HIDP_ERROR_CODES(0xC,5))\r
+#define HIDP_STATUS_BAD_LOG_PHY_VALUES (HIDP_ERROR_CODES(0xC,6))\r
+#define HIDP_STATUS_BUFFER_TOO_SMALL (HIDP_ERROR_CODES(0xC,7))\r
+#define HIDP_STATUS_INTERNAL_ERROR (HIDP_ERROR_CODES(0xC,8))\r
+#define HIDP_STATUS_I8042_TRANS_UNKNOWN (HIDP_ERROR_CODES(0xC,9))\r
+#define HIDP_STATUS_INCOMPATIBLE_REPORT_ID (HIDP_ERROR_CODES(0xC,0xA))\r
+#define HIDP_STATUS_NOT_VALUE_ARRAY (HIDP_ERROR_CODES(0xC,0xB))\r
+#define HIDP_STATUS_IS_VALUE_ARRAY (HIDP_ERROR_CODES(0xC,0xC))\r
+#define HIDP_STATUS_DATA_INDEX_NOT_FOUND (HIDP_ERROR_CODES(0xC,0xD))\r
+#define HIDP_STATUS_DATA_INDEX_OUT_OF_RANGE (HIDP_ERROR_CODES(0xC,0xE))\r
+#define HIDP_STATUS_BUTTON_NOT_PRESSED (HIDP_ERROR_CODES(0xC,0xF))\r
+#define HIDP_STATUS_REPORT_DOES_NOT_EXIST (HIDP_ERROR_CODES(0xC,0x10))\r
+#define HIDP_STATUS_NOT_IMPLEMENTED (HIDP_ERROR_CODES(0xC,0x20))\r
+\r
+//\r
+// We blundered this status code.\r
+//\r
+#define HIDP_STATUS_I8242_TRANS_UNKNOWN HIDP_STATUS_I8042_TRANS_UNKNOWN\r
+\r
+#include <poppack.h>\r
+\r
+#endif\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 1996 Microsoft Corporation\r
+\r
+Module Name:\r
+\r
+ HIDSDI.H\r
+\r
+Abstract:\r
+\r
+ This module contains the PUBLIC definitions for the\r
+ code that implements the HID dll.\r
+\r
+Environment:\r
+\r
+ Kernel & user mode\r
+\r
+--*/\r
+\r
+\r
+#ifndef _HIDSDI_H\r
+#define _HIDSDI_H\r
+\r
+#include <pshpack4.h>\r
+\r
+//#include "wtypes.h"\r
+\r
+//#include <windef.h>\r
+//#include <win32.h>\r
+//#include <basetyps.h>\r
+\r
+typedef LONG NTSTATUS;\r
+#include "hidusage.h"\r
+#include "hidpi.h"\r
+\r
+typedef struct _HIDD_CONFIGURATION {\r
+ PVOID cookie;\r
+ ULONG size;\r
+ ULONG RingBufferSize;\r
+} HIDD_CONFIGURATION, *PHIDD_CONFIGURATION;\r
+\r
+typedef struct _HIDD_ATTRIBUTES {\r
+ ULONG Size; // = sizeof (struct _HIDD_ATTRIBUTES)\r
+\r
+ //\r
+ // Vendor ids of this hid device\r
+ //\r
+ USHORT VendorID;\r
+ USHORT ProductID;\r
+ USHORT VersionNumber;\r
+\r
+ //\r
+ // Additional fields will be added to the end of this structure.\r
+ //\r
+} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;\r
+\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetAttributes (\r
+ IN HANDLE HidDeviceObject,\r
+ OUT PHIDD_ATTRIBUTES Attributes\r
+ );\r
+/*++\r
+Routine Description:\r
+ Fill in the given HIDD_ATTRIBUTES structure with the attributes of the\r
+ given hid device.\r
+\r
+--*/\r
+\r
+\r
+void __stdcall\r
+HidD_GetHidGuid (\r
+ OUT LPGUID HidGuid\r
+ );\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetPreparsedData (\r
+ IN HANDLE HidDeviceObject,\r
+ OUT PHIDP_PREPARSED_DATA * PreparsedData\r
+ );\r
+/*++\r
+Routine Description:\r
+ Given a handle to a valid Hid Class Device Object, retrieve the preparsed\r
+ data for the device. This routine will allocate the appropriately \r
+ sized buffer to hold this preparsed data. It is up to client to call\r
+ HidP_FreePreparsedData to free the memory allocated to this structure when\r
+ it is no longer needed.\r
+\r
+Arguments:\r
+ HidDeviceObject A handle to a Hid Device that the client obtains using \r
+ a call to CreateFile on a valid Hid device string name.\r
+ The string name can be obtained using standard PnP calls.\r
+\r
+ PreparsedData An opaque data structure used by other functions in this \r
+ library to retrieve information about a given device.\r
+\r
+Return Value:\r
+ TRUE if successful.\r
+ FALSE otherwise -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_FreePreparsedData (\r
+ IN PHIDP_PREPARSED_DATA PreparsedData\r
+ );\r
+\r
+BOOLEAN __stdcall\r
+HidD_FlushQueue (\r
+ IN HANDLE HidDeviceObject\r
+ );\r
+/*++\r
+Routine Description:\r
+ Flush the input queue for the given HID device.\r
+\r
+Arguments:\r
+ HidDeviceObject A handle to a Hid Device that the client obtains using \r
+ a call to CreateFile on a valid Hid device string name.\r
+ The string name can be obtained using standard PnP calls.\r
+\r
+Return Value:\r
+ TRUE if successful\r
+ FALSE otherwise -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetConfiguration (\r
+ IN HANDLE HidDeviceObject,\r
+ OUT PHIDD_CONFIGURATION Configuration,\r
+ IN ULONG ConfigurationLength\r
+ );\r
+/*++\r
+Routine Description:\r
+ Get the configuration information for this Hid device\r
+\r
+Arguments:\r
+ HidDeviceObject A handle to a Hid Device Object.\r
+\r
+ Configuration A configuration structure. HidD_GetConfiguration MUST\r
+ be called before the configuration can be modified and\r
+ set using HidD_SetConfiguration\r
+\r
+ ConfigurationLength That is ``sizeof (HIDD_CONFIGURATION)''. Using this\r
+ parameter, we can later increase the length of the \r
+ configuration array and not break older apps.\r
+\r
+Return Value:\r
+ TRUE if successful\r
+ FALSE otherwise -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_SetConfiguration (\r
+ IN HANDLE HidDeviceObject,\r
+ IN PHIDD_CONFIGURATION Configuration,\r
+ IN ULONG ConfigurationLength\r
+ );\r
+/*++\r
+Routine Description:\r
+ Set the configuration information for this Hid device...\r
+ \r
+ NOTE: HidD_GetConfiguration must be called to retrieve the current \r
+ configuration information before this information can be modified \r
+ and set.\r
+\r
+Arguments:\r
+ HidDeviceObject A handle to a Hid Device Object.\r
+ \r
+ Configuration A configuration structure. HidD_GetConfiguration MUST\r
+ be called before the configuration can be modified and\r
+ set using HidD_SetConfiguration\r
+ \r
+ ConfigurationLength That is ``sizeof (HIDD_CONFIGURATION)''. Using this\r
+ parameter, we can later increase the length of the \r
+ configuration array and not break older apps.\r
+\r
+Return Value:\r
+ TRUE if successful\r
+ FALSE otherwise -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetFeature (\r
+ IN HANDLE HidDeviceObject,\r
+ OUT PVOID ReportBuffer,\r
+ IN ULONG ReportBufferLength\r
+ );\r
+/*++\r
+Routine Description:\r
+ Retrieve a feature report from a HID device.\r
+\r
+Arguments:\r
+ HidDeviceObject A handle to a Hid Device Object.\r
+ \r
+ ReportBuffer The buffer that the feature report should be placed \r
+ into. The first byte of the buffer should be set to\r
+ the report ID of the desired report\r
+ \r
+ ReportBufferLength The size (in bytes) of ReportBuffer. This value \r
+ should be greater than or equal to the \r
+ FeatureReportByteLength field as specified in the \r
+ HIDP_CAPS structure for the device\r
+Return Value:\r
+ TRUE if successful\r
+ FALSE otherwise -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_SetFeature (\r
+ IN HANDLE HidDeviceObject,\r
+ IN PVOID ReportBuffer,\r
+ IN ULONG ReportBufferLength\r
+ );\r
+/*++\r
+Routine Description:\r
+ Send a feature report to a HID device.\r
+\r
+Arguments:\r
+ HidDeviceObject A handle to a Hid Device Object.\r
+ \r
+ ReportBuffer The buffer of the feature report to send to the device\r
+ \r
+ ReportBufferLength The size (in bytes) of ReportBuffer. This value \r
+ should be greater than or equal to the \r
+ FeatureReportByteLength field as specified in the \r
+ HIDP_CAPS structure for the device\r
+Return Value:\r
+ TRUE if successful\r
+ FALSE otherwise -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetNumInputBuffers (\r
+ IN HANDLE HidDeviceObject,\r
+ OUT PULONG NumberBuffers\r
+ );\r
+/*++\r
+Routine Description:\r
+ This function returns the number of input buffers used by the specified\r
+ file handle to the Hid device. Each file object has a number of buffers\r
+ associated with it to queue reports read from the device but which have\r
+ not yet been read by the user-mode app with a handle to that device.\r
+\r
+Arguments:\r
+ HidDeviceObject A handle to a Hid Device Object.\r
+ \r
+ NumberBuffers Number of buffers currently being used for this file\r
+ handle to the Hid device\r
+\r
+Return Value:\r
+ TRUE if successful\r
+ FALSE otherwise -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_SetNumInputBuffers (\r
+ IN HANDLE HidDeviceObject,\r
+ OUT ULONG NumberBuffers\r
+ );\r
+/*++\r
+\r
+Routine Description:\r
+ This function sets the number of input buffers used by the specified\r
+ file handle to the Hid device. Each file object has a number of buffers\r
+ associated with it to queue reports read from the device but which have\r
+ not yet been read by the user-mode app with a handle to that device.\r
+\r
+Arguments:\r
+ HidDeviceObject A handle to a Hid Device Object.\r
+ \r
+ NumberBuffers New number of buffers to use for this file handle to\r
+ the Hid device\r
+\r
+Return Value:\r
+ TRUE if successful\r
+ FALSE otherwise -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetPhysicalDescriptor (\r
+ IN HANDLE HidDeviceObject,\r
+ OUT PVOID Buffer,\r
+ IN ULONG BufferLength\r
+ );\r
+/*++\r
+Routine Description:\r
+ This function retrieves the raw physical descriptor for the specified\r
+ Hid device. \r
+\r
+Arguments:\r
+ HidDeviceObject A handle to a Hid Device Object.\r
+ \r
+ Buffer Buffer which on return will contain the physical\r
+ descriptor if one exists for the specified device\r
+ handle\r
+\r
+ BufferLength Length of buffer (in bytes)\r
+\r
+\r
+Return Value:\r
+ TRUE if successful\r
+ FALSE otherwise -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetManufacturerString (\r
+ IN HANDLE HidDeviceObject,\r
+ OUT PVOID Buffer,\r
+ IN ULONG BufferLength\r
+ );\r
+/*++\r
+Routine Description:\r
+ This function retrieves the manufacturer string from the specified \r
+ Hid device. \r
+\r
+Arguments:\r
+ HidDeviceObject A handle to a Hid Device Object.\r
+ \r
+ Buffer Buffer which on return will contain the manufacturer\r
+ string returned from the device. This string is a \r
+ wide-character string\r
+\r
+ BufferLength Length of Buffer (in bytes)\r
+\r
+\r
+Return Value:\r
+ TRUE if successful\r
+ FALSE otherwise -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetProductString (\r
+ IN HANDLE HidDeviceObject,\r
+ OUT PVOID Buffer,\r
+ IN ULONG BufferLength\r
+ );\r
+/*++\r
+Routine Description:\r
+ This function retrieves the product string from the specified \r
+ Hid device. \r
+\r
+Arguments:\r
+ HidDeviceObject A handle to a Hid Device Object.\r
+ \r
+ Buffer Buffer which on return will contain the product\r
+ string returned from the device. This string is a \r
+ wide-character string\r
+\r
+ BufferLength Length of Buffer (in bytes)\r
+\r
+\r
+Return Value:\r
+ TRUE if successful\r
+ FALSE otherwise -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetIndexedString (\r
+ IN HANDLE HidDeviceObject,\r
+ IN ULONG StringIndex,\r
+ OUT PVOID Buffer,\r
+ IN ULONG BufferLength\r
+ );\r
+/*++\r
+Routine Description:\r
+ This function retrieves a string from the specified Hid device that is\r
+ specified with a certain string index.\r
+\r
+Arguments:\r
+ HidDeviceObject A handle to a Hid Device Object.\r
+ \r
+ StringIndex Index of the string to retrieve\r
+\r
+ Buffer Buffer which on return will contain the product\r
+ string returned from the device. This string is a \r
+ wide-character string\r
+\r
+ BufferLength Length of Buffer (in bytes)\r
+\r
+Return Value:\r
+ TRUE if successful\r
+ FALSE otherwise -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+BOOLEAN __stdcall\r
+HidD_GetSerialNumberString (\r
+ IN HANDLE HidDeviceObject,\r
+ OUT PVOID Buffer,\r
+ IN ULONG BufferLength\r
+ );\r
+/*++\r
+Routine Description:\r
+ This function retrieves the serial number string from the specified \r
+ Hid device. \r
+\r
+Arguments:\r
+ HidDeviceObject A handle to a Hid Device Object.\r
+ \r
+ Buffer Buffer which on return will contain the serial number\r
+ string returned from the device. This string is a \r
+ wide-character string\r
+\r
+ BufferLength Length of Buffer (in bytes)\r
+\r
+Return Value:\r
+ TRUE if successful\r
+ FALSE otherwise -- Use GetLastError() to get extended error information\r
+--*/\r
+\r
+\r
+#include <poppack.h>\r
+\r
+#endif\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 1996, 1997 Microsoft Corporation\r
+\r
+Module Name:\r
+\r
+ HIDUSAGE.H\r
+\r
+Abstract:\r
+\r
+ Public Definitions of HID USAGES.\r
+\r
+Environment:\r
+\r
+ Kernel & user mode\r
+\r
+--*/\r
+\r
+#ifndef __HIDUSAGE_H__\r
+#define __HIDUSAGE_H__\r
+\r
+//\r
+// Usage Pages\r
+//\r
+\r
+typedef USHORT USAGE, *PUSAGE;\r
+\r
+#define HID_USAGE_PAGE_GENERIC ((USAGE) 0x01)\r
+#define HID_USAGE_PAGE_SIMULATION ((USAGE) 0x02)\r
+#define HID_USAGE_PAGE_VR ((USAGE) 0x03)\r
+#define HID_USAGE_PAGE_SPORT ((USAGE) 0x04)\r
+#define HID_USAGE_PAGE_GAME ((USAGE) 0x05)\r
+#define HID_USAGE_PAGE_KEYBOARD ((USAGE) 0x07)\r
+#define HID_USAGE_PAGE_LED ((USAGE) 0x08)\r
+#define HID_USAGE_PAGE_BUTTON ((USAGE) 0x09)\r
+#define HID_USAGE_PAGE_ORDINAL ((USAGE) 0x0A)\r
+#define HID_USAGE_PAGE_TELEPHONY ((USAGE) 0x0B)\r
+#define HID_USAGE_PAGE_CONSUMER ((USAGE) 0x0C)\r
+#define HID_USAGE_PAGE_DIGITIZER ((USAGE) 0x0D)\r
+#define HID_USAGE_PAGE_UNICODE ((USAGE) 0x10)\r
+#define HID_USAGE_PAGE_ALPHANUMERIC ((USAGE) 0x14)\r
+\r
+\r
+//\r
+// Usages from Generic Desktop Page (0x01)\r
+//\r
+\r
+#define HID_USAGE_GENERIC_POINTER ((USAGE) 0x01)\r
+#define HID_USAGE_GENERIC_MOUSE ((USAGE) 0x02)\r
+#define HID_USAGE_GENERIC_JOYSTICK ((USAGE) 0x04)\r
+#define HID_USAGE_GENERIC_GAMEPAD ((USAGE) 0x05)\r
+#define HID_USAGE_GENERIC_KEYBOARD ((USAGE) 0x06)\r
+#define HID_USAGE_GENERIC_KEYPAD ((USAGE) 0x07)\r
+#define HID_USAGE_GENERIC_SYSTEM_CTL ((USAGE) 0x80)\r
+\r
+#define HID_USAGE_GENERIC_X ((USAGE) 0x30)\r
+#define HID_USAGE_GENERIC_Y ((USAGE) 0x31)\r
+#define HID_USAGE_GENERIC_Z ((USAGE) 0x32)\r
+#define HID_USAGE_GENERIC_RX ((USAGE) 0x33)\r
+#define HID_USAGE_GENERIC_RY ((USAGE) 0x34)\r
+#define HID_USAGE_GENERIC_RZ ((USAGE) 0x35)\r
+#define HID_USAGE_GENERIC_SLIDER ((USAGE) 0x36)\r
+#define HID_USAGE_GENERIC_DIAL ((USAGE) 0x37)\r
+#define HID_USAGE_GENERIC_WHEEL ((USAGE) 0x38)\r
+#define HID_USAGE_GENERIC_HATSWITCH ((USAGE) 0x39)\r
+#define HID_USAGE_GENERIC_COUNTED_BUFFER ((USAGE) 0x3A)\r
+#define HID_USAGE_GENERIC_BYTE_COUNT ((USAGE) 0x3B)\r
+#define HID_USAGE_GENERIC_MOTION_WAKEUP ((USAGE) 0x3C)\r
+#define HID_USAGE_GENERIC_VX ((USAGE) 0x40)\r
+#define HID_USAGE_GENERIC_VY ((USAGE) 0x41)\r
+#define HID_USAGE_GENERIC_VZ ((USAGE) 0x42)\r
+#define HID_USAGE_GENERIC_VBRX ((USAGE) 0x43)\r
+#define HID_USAGE_GENERIC_VBRY ((USAGE) 0x44)\r
+#define HID_USAGE_GENERIC_VBRZ ((USAGE) 0x45)\r
+#define HID_USAGE_GENERIC_VNO ((USAGE) 0x46)\r
+#define HID_USAGE_GENERIC_SYSCTL_POWER ((USAGE) 0x81)\r
+#define HID_USAGE_GENERIC_SYSCTL_SLEEP ((USAGE) 0x82)\r
+#define HID_USAGE_GENERIC_SYSCTL_WAKE ((USAGE) 0x83)\r
+#define HID_USAGE_GENERIC_SYSCTL_CONTEXT_MENU ((USAGE) 0x84)\r
+#define HID_USAGE_GENERIC_SYSCTL_MAIN_MENU ((USAGE) 0x85)\r
+#define HID_USAGE_GENERIC_SYSCTL_APP_MENU ((USAGE) 0x86)\r
+#define HID_USAGE_GENERIC_SYSCTL_HELP_MENU ((USAGE) 0x87)\r
+#define HID_USAGE_GENERIC_SYSCTL_MENU_EXIT ((USAGE) 0x88)\r
+#define HID_USAGE_GENERIC_SYSCTL_MENU_SELECT ((USAGE) 0x89)\r
+#define HID_USAGE_GENERIC_SYSCTL_MENU_RIGHT ((USAGE) 0x8A)\r
+#define HID_USAGE_GENERIC_SYSCTL_MENU_LEFT ((USAGE) 0x8B)\r
+#define HID_USAGE_GENERIC_SYSCTL_MENU_UP ((USAGE) 0x8C)\r
+#define HID_USAGE_GENERIC_SYSCTL_MENU_DOWN ((USAGE) 0x8D)\r
+\r
+//\r
+// Usages from Simulation Controls Page (0x02)\r
+//\r
+\r
+#define HID_USAGE_SIMULATION_RUDDER ((USAGE) 0xBA)\r
+#define HID_USAGE_SIMULATION_THROTTLE ((USAGE) 0xBB)\r
+\r
+//\r
+// Virtual Reality Controls Page (0x03)\r
+//\r
+\r
+\r
+//\r
+// Sport Controls Page (0x04)\r
+//\r
+\r
+\r
+//\r
+// Game Controls Page (0x05)\r
+//\r
+\r
+\r
+//\r
+// Keyboard/Keypad Page (0x07)\r
+//\r
+\r
+ // Error "keys"\r
+#define HID_USAGE_KEYBOARD_NOEVENT ((USAGE) 0x00)\r
+#define HID_USAGE_KEYBOARD_ROLLOVER ((USAGE) 0x01)\r
+#define HID_USAGE_KEYBOARD_POSTFAIL ((USAGE) 0x02)\r
+#define HID_USAGE_KEYBOARD_UNDEFINED ((USAGE) 0x03)\r
+\r
+ // Letters\r
+#define HID_USAGE_KEYBOARD_aA ((USAGE) 0x04)\r
+#define HID_USAGE_KEYBOARD_zZ ((USAGE) 0x1D)\r
+ // Numbers\r
+#define HID_USAGE_KEYBOARD_ONE ((USAGE) 0x1E)\r
+#define HID_USAGE_KEYBOARD_ZERO ((USAGE) 0x27)\r
+ // Modifier Keys\r
+#define HID_USAGE_KEYBOARD_LCTRL ((USAGE) 0xE0)\r
+#define HID_USAGE_KEYBOARD_LSHFT ((USAGE) 0xE1)\r
+#define HID_USAGE_KEYBOARD_LALT ((USAGE) 0xE2)\r
+#define HID_USAGE_KEYBOARD_LGUI ((USAGE) 0xE3)\r
+#define HID_USAGE_KEYBOARD_RCTRL ((USAGE) 0xE4)\r
+#define HID_USAGE_KEYBOARD_RSHFT ((USAGE) 0xE5)\r
+#define HID_USAGE_KEYBOARD_RALT ((USAGE) 0xE6)\r
+#define HID_USAGE_KEYBOARD_RGUI ((USAGE) 0xE7)\r
+#define HID_USAGE_KEYBOARD_SCROLL_LOCK ((USAGE) 0x47)\r
+#define HID_USAGE_KEYBOARD_NUM_LOCK ((USAGE) 0x53)\r
+#define HID_USAGE_KEYBOARD_CAPS_LOCK ((USAGE) 0x39)\r
+ // Funtion keys\r
+#define HID_USAGE_KEYBOARD_F1 ((USAGE) 0x3A)\r
+#define HID_USAGE_KEYBOARD_F12 ((USAGE) 0x45)\r
+\r
+#define HID_USAGE_KEYBOARD_RETURN ((USAGE) 0x28)\r
+#define HID_USAGE_KEYBOARD_ESCAPE ((USAGE) 0x29)\r
+#define HID_USAGE_KEYBOARD_DELETE ((USAGE) 0x2A)\r
+\r
+#define HID_USAGE_KEYBOARD_PRINT_SCREEN ((USAGE) 0x46)\r
+\r
+// and hundreds more...\r
+\r
+//\r
+// LED Page (0x08)\r
+//\r
+\r
+#define HID_USAGE_LED_NUM_LOCK ((USAGE) 0x01)\r
+#define HID_USAGE_LED_CAPS_LOCK ((USAGE) 0x02)\r
+#define HID_USAGE_LED_SCROLL_LOCK ((USAGE) 0x03)\r
+#define HID_USAGE_LED_COMPOSE ((USAGE) 0x04)\r
+#define HID_USAGE_LED_KANA ((USAGE) 0x05)\r
+#define HID_USAGE_LED_POWER ((USAGE) 0x06)\r
+#define HID_USAGE_LED_SHIFT ((USAGE) 0x07)\r
+#define HID_USAGE_LED_DO_NOT_DISTURB ((USAGE) 0x08)\r
+#define HID_USAGE_LED_MUTE ((USAGE) 0x09)\r
+#define HID_USAGE_LED_TONE_ENABLE ((USAGE) 0x0A)\r
+#define HID_USAGE_LED_HIGH_CUT_FILTER ((USAGE) 0x0B)\r
+#define HID_USAGE_LED_LOW_CUT_FILTER ((USAGE) 0x0C)\r
+#define HID_USAGE_LED_EQUALIZER_ENABLE ((USAGE) 0x0D)\r
+#define HID_USAGE_LED_SOUND_FIELD_ON ((USAGE) 0x0E)\r
+#define HID_USAGE_LED_SURROUND_FIELD_ON ((USAGE) 0x0F)\r
+#define HID_USAGE_LED_REPEAT ((USAGE) 0x10)\r
+#define HID_USAGE_LED_STEREO ((USAGE) 0x11)\r
+#define HID_USAGE_LED_SAMPLING_RATE_DETECT ((USAGE) 0x12)\r
+#define HID_USAGE_LED_SPINNING ((USAGE) 0x13)\r
+#define HID_USAGE_LED_CAV ((USAGE) 0x14)\r
+#define HID_USAGE_LED_CLV ((USAGE) 0x15)\r
+#define HID_USAGE_LED_RECORDING_FORMAT_DET ((USAGE) 0x16)\r
+#define HID_USAGE_LED_OFF_HOOK ((USAGE) 0x17)\r
+#define HID_USAGE_LED_RING ((USAGE) 0x18)\r
+#define HID_USAGE_LED_MESSAGE_WAITING ((USAGE) 0x19)\r
+#define HID_USAGE_LED_DATA_MODE ((USAGE) 0x1A)\r
+#define HID_USAGE_LED_BATTERY_OPERATION ((USAGE) 0x1B)\r
+#define HID_USAGE_LED_BATTERY_OK ((USAGE) 0x1C)\r
+#define HID_USAGE_LED_BATTERY_LOW ((USAGE) 0x1D)\r
+#define HID_USAGE_LED_SPEAKER ((USAGE) 0x1E)\r
+#define HID_USAGE_LED_HEAD_SET ((USAGE) 0x1F)\r
+#define HID_USAGE_LED_HOLD ((USAGE) 0x20)\r
+#define HID_USAGE_LED_MICROPHONE ((USAGE) 0x21)\r
+#define HID_USAGE_LED_COVERAGE ((USAGE) 0x22)\r
+#define HID_USAGE_LED_NIGHT_MODE ((USAGE) 0x23)\r
+#define HID_USAGE_LED_SEND_CALLS ((USAGE) 0x24)\r
+#define HID_USAGE_LED_CALL_PICKUP ((USAGE) 0x25)\r
+#define HID_USAGE_LED_CONFERENCE ((USAGE) 0x26)\r
+#define HID_USAGE_LED_STAND_BY ((USAGE) 0x27)\r
+#define HID_USAGE_LED_CAMERA_ON ((USAGE) 0x28)\r
+#define HID_USAGE_LED_CAMERA_OFF ((USAGE) 0x29)\r
+#define HID_USAGE_LED_ON_LINE ((USAGE) 0x2A)\r
+#define HID_USAGE_LED_OFF_LINE ((USAGE) 0x2B)\r
+#define HID_USAGE_LED_BUSY ((USAGE) 0x2C)\r
+#define HID_USAGE_LED_READY ((USAGE) 0x2D)\r
+#define HID_USAGE_LED_PAPER_OUT ((USAGE) 0x2E)\r
+#define HID_USAGE_LED_PAPER_JAM ((USAGE) 0x2F)\r
+#define HID_USAGE_LED_REMOTE ((USAGE) 0x30)\r
+#define HID_USAGE_LED_FORWARD ((USAGE) 0x31)\r
+#define HID_USAGE_LED_REVERSE ((USAGE) 0x32)\r
+#define HID_USAGE_LED_STOP ((USAGE) 0x33)\r
+#define HID_USAGE_LED_REWIND ((USAGE) 0x34)\r
+#define HID_USAGE_LED_FAST_FORWARD ((USAGE) 0x35)\r
+#define HID_USAGE_LED_PLAY ((USAGE) 0x36)\r
+#define HID_USAGE_LED_PAUSE ((USAGE) 0x37)\r
+#define HID_USAGE_LED_RECORD ((USAGE) 0x38)\r
+#define HID_USAGE_LED_ERROR ((USAGE) 0x39)\r
+#define HID_USAGE_LED_SELECTED_INDICATOR ((USAGE) 0x3A)\r
+#define HID_USAGE_LED_IN_USE_INDICATOR ((USAGE) 0x3B)\r
+#define HID_USAGE_LED_MULTI_MODE_INDICATOR ((USAGE) 0x3C)\r
+#define HID_USAGE_LED_INDICATOR_ON ((USAGE) 0x3D)\r
+#define HID_USAGE_LED_INDICATOR_FLASH ((USAGE) 0x3E)\r
+#define HID_USAGE_LED_INDICATOR_SLOW_BLINK ((USAGE) 0x3F)\r
+#define HID_USAGE_LED_INDICATOR_FAST_BLINK ((USAGE) 0x40)\r
+#define HID_USAGE_LED_INDICATOR_OFF ((USAGE) 0x41)\r
+#define HID_USAGE_LED_FLASH_ON_TIME ((USAGE) 0x42)\r
+#define HID_USAGE_LED_SLOW_BLINK_ON_TIME ((USAGE) 0x43)\r
+#define HID_USAGE_LED_SLOW_BLINK_OFF_TIME ((USAGE) 0x44)\r
+#define HID_USAGE_LED_FAST_BLINK_ON_TIME ((USAGE) 0x45)\r
+#define HID_USAGE_LED_FAST_BLINK_OFF_TIME ((USAGE) 0x46)\r
+#define HID_USAGE_LED_INDICATOR_COLOR ((USAGE) 0x47)\r
+#define HID_USAGE_LED_RED ((USAGE) 0x48)\r
+#define HID_USAGE_LED_GREEN ((USAGE) 0x49)\r
+#define HID_USAGE_LED_AMBER ((USAGE) 0x4A)\r
+#define HID_USAGE_LED_GENERIC_INDICATOR ((USAGE) 0x3B)\r
+\r
+//\r
+// Button Page (0x09)\r
+//\r
+// There is no need to label these usages.\r
+//\r
+\r
+\r
+//\r
+// Ordinal Page (0x0A)\r
+//\r
+// There is no need to label these usages.\r
+//\r
+\r
+\r
+//\r
+// Telephony Device Page (0x0B)\r
+//\r
+\r
+#define HID_USAGE_TELEPHONY_PHONE ((USAGE) 0x01)\r
+#define HID_USAGE_TELEPHONY_ANSWERING_MACHINE ((USAGE) 0x02)\r
+#define HID_USAGE_TELEPHONY_MESSAGE_CONTROLS ((USAGE) 0x03)\r
+#define HID_USAGE_TELEPHONY_HANDSET ((USAGE) 0x04)\r
+#define HID_USAGE_TELEPHONY_HEADSET ((USAGE) 0x05)\r
+#define HID_USAGE_TELEPHONY_KEYPAD ((USAGE) 0x06)\r
+#define HID_USAGE_TELEPHONY_PROGRAMMABLE_BUTTON ((USAGE) 0x07)\r
+\r
+//\r
+// and others...\r
+//\r
+\r
+\r
+#endif\r
--- /dev/null
+#include <windows.h>\r
+#include <setupapi.h>\r
+#include <stdio.h>\r
+#include <ctype.h>\r
+#include <stdlib.h>\r
+extern "C" {\r
+#include "include/hidsdi.h"\r
+#include "include/hidpi.h"\r
+}\r
+\r
+#include "prox.h"\r
+\r
+#define OUR_VID 0x9ac4\r
+#define OUR_PID 0x4b8f\r
+\r
+HANDLE UsbHandle;\r
+\r
+static void ShowError(void)\r
+{\r
+ char buf[1024];\r
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,\r
+ buf, sizeof(buf), NULL);\r
+ printf("ERROR: %s", buf);\r
+}\r
+\r
+static BOOL UsbConnect(void)\r
+{\r
+ typedef void (__stdcall *GetGuidProc)(GUID *);\r
+ typedef BOOLEAN (__stdcall *GetAttrProc)(HANDLE, HIDD_ATTRIBUTES *);\r
+ typedef BOOLEAN (__stdcall *GetPreparsedProc)(HANDLE,\r
+ PHIDP_PREPARSED_DATA *);\r
+ typedef NTSTATUS (__stdcall *GetCapsProc)(PHIDP_PREPARSED_DATA, PHIDP_CAPS);\r
+ GetGuidProc getGuid;\r
+ GetAttrProc getAttr;\r
+ GetPreparsedProc getPreparsed;\r
+ GetCapsProc getCaps;\r
+\r
+ HMODULE h = LoadLibrary("hid.dll");\r
+ getGuid = (GetGuidProc)GetProcAddress(h, "HidD_GetHidGuid");\r
+ getAttr = (GetAttrProc)GetProcAddress(h, "HidD_GetAttributes");\r
+ getPreparsed = (GetPreparsedProc)GetProcAddress(h, "HidD_GetPreparsedData");\r
+ getCaps = (GetCapsProc)GetProcAddress(h, "HidP_GetCaps");\r
+\r
+ GUID hidGuid;\r
+ getGuid(&hidGuid);\r
+\r
+ HDEVINFO devInfo;\r
+ devInfo = SetupDiGetClassDevs(&hidGuid, NULL, NULL,\r
+ DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);\r
+\r
+ SP_DEVICE_INTERFACE_DATA devInfoData;\r
+ devInfoData.cbSize = sizeof(devInfoData);\r
+\r
+ int i;\r
+ for(i = 0;; i++) {\r
+ if(!SetupDiEnumDeviceInterfaces(devInfo, 0, &hidGuid, i, &devInfoData))\r
+ {\r
+ if(GetLastError() != ERROR_NO_MORE_ITEMS) {\r
+// printf("SetupDiEnumDeviceInterfaces failed\n");\r
+ }\r
+// printf("done list\n");\r
+ SetupDiDestroyDeviceInfoList(devInfo);\r
+ return FALSE;\r
+ }\r
+\r
+// printf("item %d:\n", i);\r
+\r
+ DWORD sizeReqd = 0;\r
+ if(!SetupDiGetDeviceInterfaceDetail(devInfo, &devInfoData,\r
+ NULL, 0, &sizeReqd, NULL))\r
+ {\r
+ if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {\r
+// printf("SetupDiGetDeviceInterfaceDetail (0) failed\n");\r
+ continue;\r
+ }\r
+ }\r
+\r
+ SP_DEVICE_INTERFACE_DETAIL_DATA *devInfoDetailData =\r
+ (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(sizeReqd);\r
+ devInfoDetailData->cbSize = sizeof(*devInfoDetailData);\r
+\r
+ if(!SetupDiGetDeviceInterfaceDetail(devInfo, &devInfoData,\r
+ devInfoDetailData, 87, NULL, NULL))\r
+ {\r
+// printf("SetupDiGetDeviceInterfaceDetail (1) failed\n");\r
+ continue;\r
+ }\r
+\r
+ char *path = devInfoDetailData->DevicePath;\r
+\r
+ UsbHandle = CreateFile(path, /*GENERIC_READ |*/ GENERIC_WRITE,\r
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,\r
+ FILE_FLAG_OVERLAPPED, NULL);\r
+\r
+ if(UsbHandle == INVALID_HANDLE_VALUE) {\r
+ ShowError();\r
+// printf("CreateFile failed: for '%s'\n", path);\r
+ continue;\r
+ }\r
+\r
+ HIDD_ATTRIBUTES attr;\r
+ attr.Size = sizeof(attr);\r
+ if(!getAttr(UsbHandle, &attr)) {\r
+ ShowError();\r
+// printf("HidD_GetAttributes failed\n");\r
+ continue;\r
+ }\r
+\r
+// printf("VID: %04x PID %04x\n", attr.VendorID, attr.ProductID);\r
+\r
+ if(attr.VendorID != OUR_VID || attr.ProductID != OUR_PID) {\r
+ CloseHandle(UsbHandle);\r
+// printf(" nope, not us\n");\r
+ continue;\r
+ }\r
+\r
+// printf ("got it!\n");\r
+ CloseHandle(UsbHandle);\r
+\r
+ UsbHandle = CreateFile(path, GENERIC_READ | GENERIC_WRITE,\r
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,\r
+ FILE_FLAG_OVERLAPPED, NULL);\r
+\r
+ if(UsbHandle == INVALID_HANDLE_VALUE) {\r
+ ShowError();\r
+// printf("Error, couldn't open our own handle as desired.\n");\r
+ return FALSE;\r
+ }\r
+\r
+ PHIDP_PREPARSED_DATA pp;\r
+ getPreparsed(UsbHandle, &pp);\r
+ HIDP_CAPS caps;\r
+\r
+ if(getCaps(pp, &caps) != HIDP_STATUS_SUCCESS) {\r
+// printf("getcaps failed\n");\r
+ return FALSE;\r
+ }\r
+\r
+// printf("input/out report %d/%d\n", caps.InputReportByteLength,\r
+// caps.OutputReportByteLength);\r
+\r
+\r
+ return TRUE;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+BOOL ReceiveCommandPoll(UsbCommand *c)\r
+{\r
+ static BOOL ReadInProgress = FALSE;\r
+ static OVERLAPPED Ov;\r
+ static BYTE Buf[65];\r
+ static DWORD HaveRead;\r
+\r
+ if(!ReadInProgress) {\r
+ memset(&Ov, 0, sizeof(Ov));\r
+ ReadFile(UsbHandle, Buf, 65, &HaveRead, &Ov);\r
+ if(GetLastError() != ERROR_IO_PENDING) {\r
+ ShowError();\r
+ exit(-1);\r
+ }\r
+ ReadInProgress = TRUE;\r
+ }\r
+\r
+ if(HasOverlappedIoCompleted(&Ov)) {\r
+ ReadInProgress = FALSE;\r
+\r
+ if(!GetOverlappedResult(UsbHandle, &Ov, &HaveRead, FALSE)) {\r
+ ShowError();\r
+ exit(-1);\r
+ }\r
+\r
+ memcpy(c, Buf+1, 64);\r
+\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+void ReceiveCommand(UsbCommand *c)\r
+{\r
+ while(!ReceiveCommandPoll(c)) {\r
+ Sleep(0);\r
+ }\r
+}\r
+\r
+void SendCommand(UsbCommand *c, BOOL wantAck)\r
+{\r
+ BYTE buf[65];\r
+ buf[0] = 0;\r
+ memcpy(buf+1, c, 64);\r
+\r
+ DWORD written;\r
+ OVERLAPPED ov;\r
+ memset(&ov, 0, sizeof(ov));\r
+ WriteFile(UsbHandle, buf, 65, &written, &ov);\r
+ if(GetLastError() != ERROR_IO_PENDING) {\r
+ ShowError();\r
+ exit(-1);\r
+ }\r
+\r
+ while(!HasOverlappedIoCompleted(&ov)) {\r
+ Sleep(0);\r
+ }\r
+\r
+ if(!GetOverlappedResult(UsbHandle, &ov, &written, FALSE)) {\r
+ ShowError();\r
+ exit(-1);\r
+ }\r
+\r
+ if(wantAck) {\r
+ UsbCommand ack;\r
+ ReceiveCommand(&ack);\r
+ if(ack.cmd != CMD_ACK) {\r
+ printf("bad ACK\n");\r
+ exit(-1);\r
+ }\r
+ }\r
+}\r
+\r
+static DWORD ExpectedAddr;\r
+static BYTE QueuedToSend[256];\r
+static BOOL AllWritten;\r
+\r
+static void FlushPrevious(void)\r
+{\r
+ UsbCommand c;\r
+ memset(&c, 0, sizeof(c));\r
+\r
+ printf("expected = %08x flush, ", ExpectedAddr);\r
+\r
+ int i;\r
+ for(i = 0; i < 240; i += 48) {\r
+ c.cmd = CMD_SETUP_WRITE;\r
+ memcpy(c.d.asBytes, QueuedToSend+i, 48);\r
+ c.ext1 = (i/4);\r
+ SendCommand(&c, TRUE);\r
+ }\r
+\r
+ c.cmd = CMD_FINISH_WRITE;\r
+ c.ext1 = (ExpectedAddr-1) & (~255);\r
+ printf("c.ext1 = %08x\r", c.ext1);\r
+ memcpy(c.d.asBytes, QueuedToSend+240, 16);\r
+ SendCommand(&c, TRUE);\r
+\r
+ AllWritten = TRUE;\r
+}\r
+\r
+static void GotByte(DWORD where, BYTE which)\r
+{\r
+ AllWritten = FALSE;\r
+\r
+ if(where != ExpectedAddr) {\r
+ printf("bad: got at %08x, expected at %08x\n", where, ExpectedAddr);\r
+ exit(-1);\r
+ }\r
+ QueuedToSend[where & 255] = which;\r
+ ExpectedAddr++;\r
+\r
+ if((where & 255) == 255) {\r
+ // we have completed a full page\r
+ FlushPrevious();\r
+ }\r
+}\r
+\r
+static int HexVal(int c)\r
+{\r
+ c = tolower(c);\r
+ if(c >= '0' && c <= '9') {\r
+ return c - '0';\r
+ } else if(c >= 'a' && c <= 'f') {\r
+ return (c - 'a') + 10;\r
+ } else {\r
+ printf("bad hex digit '%c'\n", c);\r
+ exit(-1);\r
+ }\r
+}\r
+\r
+static BYTE HexByte(char *s)\r
+{\r
+ return (HexVal(s[0]) << 4) | HexVal(s[1]);\r
+}\r
+\r
+static void LoadFlashFromSRecords(char *file, int addr)\r
+{\r
+ ExpectedAddr = addr;\r
+\r
+ FILE *f = fopen(file, "r");\r
+ if(!f) {\r
+ printf("couldn't open file\n");\r
+ exit(-1);\r
+ }\r
+\r
+ char line[512];\r
+ while(fgets(line, sizeof(line), f)) {\r
+ if(memcmp(line, "S3", 2)==0) {\r
+ char *s = line + 2;\r
+ int len = HexByte(s) - 5;\r
+ s += 2;\r
+\r
+ char addrStr[9];\r
+ memcpy(addrStr, s, 8);\r
+ addrStr[8] = '\0';\r
+ DWORD addr;\r
+ sscanf(addrStr, "%x", &addr);\r
+ s += 8;\r
+\r
+ int i;\r
+ for(i = 0; i < len; i++) {\r
+ while((addr+i) > ExpectedAddr) {\r
+ GotByte(ExpectedAddr, 0xff);\r
+ }\r
+ GotByte(addr+i, HexByte(s));\r
+ s += 2;\r
+ }\r
+ }\r
+ }\r
+\r
+ if(!AllWritten) FlushPrevious();\r
+\r
+ fclose(f);\r
+ printf("\ndone.\n");\r
+}\r
+\r
+int main(int argc, char **argv)\r
+{\r
+ int i = 0;\r
+\r
+ if(argc < 2) {\r
+ printf("Usage: %s bootrom file.s19\n", argv[0]);\r
+ printf(" %s load osimage.s19\n", argv[0]);\r
+ printf(" %s fpga fpgaimg.s19\n", argv[0]);\r
+ printf(" %s gui\n", argv[0]);\r
+ return -1;\r
+ }\r
+\r
+ for(;;) {\r
+ if(UsbConnect()) {\r
+ break;\r
+ }\r
+ if(i == 0) {\r
+ printf("...no device connected, polling for it now\n");\r
+ }\r
+ if(i > 50000) {\r
+ printf("Could not connect to USB device; exiting.\n");\r
+ return -1;\r
+ }\r
+ i++;\r
+ Sleep(5);\r
+ }\r
+\r
+ if(strcmp(argv[1], "bootrom")==0 || strcmp(argv[1], "load")==0 || strcmp(argv[1], "fpga")==0) {\r
+ if(argc != 3) {\r
+ printf("Need filename.\n");\r
+ return -1;\r
+ }\r
+ if(strcmp(argv[1], "bootrom")==0) {\r
+ LoadFlashFromSRecords(argv[2], 0);\r
+ } else if(strcmp(argv[1], "fpga")==0) {\r
+ LoadFlashFromSRecords(argv[2], 0x2000);\r
+ } else {\r
+ LoadFlashFromSRecords(argv[2], 0x10000);\r
+ }\r
+ } else if(strcmp(argv[1], "gui")==0) {\r
+ ShowGui();\r
+ } else if(strcmp(argv[1], "cmd")==0) {\r
+ if(argc != 3) {\r
+ printf("Need command.\n");\r
+ return -1;\r
+ }\r
+ ExecCmd(argv[2]);\r
+ } else {\r
+ printf("Command '%s' not recognized.\n", argv[1]);\r
+ return -1;\r
+ }\r
+\r
+ return 0;\r
+}\r
--- /dev/null
+#ifndef __PROX_H\r
+#define __PROX_H\r
+\r
+#include "../include/usb_cmd.h"\r
+\r
+// prox.cpp\r
+void ReceiveCommand(UsbCommand *c);\r
+BOOL ReceiveCommandPoll(UsbCommand *c);\r
+void SendCommand(UsbCommand *c, BOOL wantAck);\r
+\r
+// gui.cpp\r
+void ShowGui(void);\r
+void HideGraphWindow(void);\r
+void ShowGraphWindow(void);\r
+void RepaintGraphWindow(void);\r
+void PrintToScrollback(char *fmt, ...);\r
+#define MAX_GRAPH_TRACE_LEN (1024*128)\r
+extern int GraphBuffer[MAX_GRAPH_TRACE_LEN];\r
+extern int GraphTraceLen;\r
+extern double CursorScaleFactor;\r
+extern int CommandFinished;\r
+\r
+// command.cpp\r
+void CommandReceived(char *cmd);\r
+void UsbCommandReceived(UsbCommand *c);\r
+\r
+// cmdline.cpp\r
+void ShowCommandline(void);\r
+void ExecCmd(char *cmd);\r
+//void PrintToScrollback(char *fmt, ...);\r
+\r
+#endif\r