Initial commit for the firmware. Used the 20090306_ela version as baseline.

It is identical to the popular 20081211, with the doob addition (20090301), a
linux client, and two additional commands for LF analysis. Let me know if
you find issues here!
This commit is contained in:
edouard@lafargue.name 2009-04-09 06:43:20 +00:00
parent b811cc51f9
commit 6658905f18
91 changed files with 16661 additions and 0 deletions

281
LICENSE.txt Normal file
View file

@ -0,0 +1,281 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS

3
LOG.txt Normal file
View file

@ -0,0 +1,3 @@
MAY 2008: Added ISO14443 type A support, Gerhard de Koning Gans

28
README-gj.txt Normal file
View file

@ -0,0 +1,28 @@
Modifications to 20081211 release by d18c7db on proxmark.org
This compiles fine under the pre-built windows compile environment ProxSpace
I make no apologies for the utterly cr@p coding. It's rubbish, you've been warned.
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.
Extra functionality includes:
ISO1443a support
================
i) Support for cascade 2 select (used for UID's longer than 4 bytes)
ii) Hard-coded (some) responses in for DESfire
ISO15563 support
================
i) demodulation all moved onto the arm
ii) Addition of a command, hi15reader (a reader simulator)
iii) Addition of a command, hi15sim (a tag simulator) - not working too well
greg.jones@digitalassurance.com

156
README.txt Normal file
View file

@ -0,0 +1,156 @@
INTRO:
This file contains enough software, logic (for the FPGA), and design
documentation for the hardware that you could, at least in theory,
do something useful with a proxmark3. It has commands to:
* read any kind of 125 kHz unidirectional tag
* simulate any kind of 125 kHz unidirectional tag
(This is enough to perform all of the silly cloning attacks, like the
ones that I did at the Capitol in Sacramento, or anything involving
a Verichip. From a technical standpoint, these are not that exciting,
although the `software radio' architecture of the proxmark3 makes it
easy and fun to support new formats.)
As a bonus, I include some code to use the 13.56 MHz hardware, so you can:
* do anything that a (medium-range) ISO 15693 reader could
* read an ISO 14443 tag, if you know the higher-layer protocol
* pretend to be an ISO 14443 tag, if you know the higher-layer protocol
* snoop on an ISO 14443 transaction
I am not actively developing any of this. I have other projects that
seem to be more useful.
USING THE PACKAGE:
The software tools required to build include:
* cygwin or other unix-like tools for Windows
* the Microsoft Visual C++ compiler (I use Version 6)
* arm-elf-gcc; I use WinterMute's build, from http://www.devkitpro.org/
* Xilinx's WebPack tools
* Modelsim (for test only)
* perl
It is not necessary to build the FPGA image yourself; a pre-compiled
image is provided, as armsrc/fpgaimg.c. This is a generated file,
though, and you can rebuild it by running fpga/go.bat.
Documentation is minimal, but see the doc/ directory for what exists. A
previous familiarity with the ARM, with digital signal processing,
and with embedded programming in general is assumed.
The device is used through a specialized command line interface; for
example, to clone a Verichip, you might type:
loread ; this reads the tag, and stores the
; raw samples in memory on the ARM
losamples ; then we download the samples to
; the PC
vchdemod clone ; demodulate the ID, and then put it
; back in a format that we can replay
losim ; and then replay it
To read an ISO 15693 tag, you might type:
hiread ; read the tag; this involves sending a
; particular command, and then getting
; the response (which is stored as raw
; samples in memory on the ARM)
hisamples ; then download those samples to the PC
hi15demod ; and demod them to bits (and check the
; CRC etc. at the same time)
Notice that in both cases the signal processing mostly happened on the PC
side; that is of course not practical for a real reader, but it is easier
to initially write your code and debug on the PC side than on the ARM. As
long as you use integer math (and I do), it's trivial to port it over
when you're done.
The USB driver and bootloader are documented (and available separately
for download, if you wish to use them in another project) at
http://cq.cx/trivia.pl
OBTAINING HARDWARE:
Most of the ultra-low-volume contract assemblers that have sprung up
(Screaming Circuits, the various cheap Asian suppliers, etc.) could put
something like this together with a reasonable yield. A run of around
a dozen units is probably cost-effective. The BOM includes (possibly-
outdated) component pricing, and everything is available from Digikey
and the usual distributors.
If you've never assembled a modern circuit board by hand, then this is
not a good place to start. Some of the components (e.g. the crystals)
must not be assembled with a soldering iron, and require hot air.
The schematics are included; the component values given are not
necessarily correct for all situations, but it should be possible to do
nearly anything you would want with appropriate population options.
The printed circuit board artwork is also available, as Gerbers and an
Excellon drill file.
FUTURE PLANS, ENHANCEMENTS THAT YOU COULD MAKE:
At some point I should write software involving a proper real-time
operating system for the ARM. I would then provide interrupt-driven
drivers for many of the peripherals that are polled now (the USB,
the data stream from the FPGA), which would make it easier to develop
complex applications.
It would not be all that hard to implement the ISO 15693 reader properly
(with anticollision, all the commands supported, and so on)--the signal
processing is already written, so it is all straightforward applications
work.
I have basic support for ISO 14443 as well: a sniffer, a simulated
tag, and a reader. It won't do anything useful unless you fill in the
high-layer protocol.
Nicer (i.e., closer-to-optimal) implementations of all kinds of signal
processing would be useful as well.
A practical implementation of the learning-the-tag's-ID-from-what-the-
reader-broadcasts-during-anticollision attacks would be relatively
straightforward. This would involve some signal processing on the FPGA,
but not much else after that.
It would be neat to write a driver that could stream samples from the A/Ds
over USB to the PC, using the full available bandwidth of USB. I am not
yet sure what that would be good for, but surely something. This would
require a kernel-mode driver under Windows, though, which is more work.
LICENSING:
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Jonathan Westhues
user jwesthues, at host cq.cx
May 2007, Cambridge MA

123
armsrc/LCD.c Normal file
View file

@ -0,0 +1,123 @@
#include <proxmark3.h>
#include "apps.h"
#include "LCD.h"
void LCDSend(unsigned int data)
{
// 9th bit set for data, clear for command
while ((SPI_STATUS & SPI_STATUS_TX_EMPTY) == 0); // wait for the transfer to complete
// For clarity's sake we pass data with 9th bit clear and commands with 9th
// bit set since they're implemented as defines, se we need to invert bit
SPI_TX_DATA = data^0x100; // Send the data/command
}
void LCDSetXY(unsigned char x, unsigned char y)
{
LCDSend(PPASET); // page start/end ram
LCDSend(y); // Start Page to display to
LCDSend(131); // End Page to display to
LCDSend(PCASET); // column start/end ram
LCDSend(x); // Start Column to display to
LCDSend(131); // End Column to display to
}
void LCDSetPixel(unsigned char x, unsigned char y, unsigned char color)
{
LCDSetXY(x,y); // Set position
LCDSend(PRAMWR); // Now write the pixel to the display
LCDSend(color); // Write the data in the specified Color
}
void LCDFill (unsigned char xs,unsigned char ys,unsigned char width,unsigned char height, unsigned char color)
{
unsigned char i,j;
for (i=0;i < height;i++) // Number of horizontal lines
{
LCDSetXY(xs,ys+i); // Goto start of fill area (Top Left)
LCDSend(PRAMWR); // Write to display
for (j=0;j < width;j++) // pixels per line
LCDSend(color);
}
}
void LCDString (char *lcd_string, const char *font_style,unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor)
{
unsigned int i;
unsigned char mask=0, px, py, xme, yme, offset;
const char *data;
data = font_style; // point to the start of the font table
xme = *data; // get font x width
data++;
yme = *data; // get font y length
data++;
offset = *data; // get data bytes per font
do
{
// point to data in table to be loaded
data = (font_style + offset) + (offset * (int)(*lcd_string - 32));
for (i=0;i < yme;i++) {
mask |=0x80;
for (px=x; px < (x + xme); px++) {
py= y + i;
if (*data & mask) LCDSetPixel (px,py,fcolor);
else LCDSetPixel (px,py,bcolor);
mask>>=1;
}
data++;
}
x+=xme;
lcd_string++; // next character in string
} while(*lcd_string !='\0'); // keep spitting chars out until end of string
}
void LCDReset(void)
{
LED_A_ON();
SetupSpi(SPI_LCD_MODE);
LCD_RESET_LOW();
SpinDelay(100);
LCD_RESET_HIGH();
SpinDelay(100);
LED_A_OFF();
}
void LCDInit(void)
{
int i;
LCDReset();
LCDSend(PSWRESET); // software reset
SpinDelay(100);
LCDSend(PSLEEPOUT); // exit sleep mode
LCDSend(PBSTRON); // booster on
LCDSend(PDISPON); // display on
LCDSend(PNORON); // normal on
LCDSend(PMADCTL); // rotate display 180 deg
LCDSend(0xC0);
LCDSend(PCOLMOD); // color mode
LCDSend(0x02); // 8bpp color mode
LCDSend(PSETCON); // set contrast
LCDSend(0xDC);
// clear display
LCDSetXY(0,0);
LCDSend(PRAMWR); // Write to display
i=LCD_XRES*LCD_YRES;
while(i--) LCDSend(WHITE);
}

120
armsrc/LCD.h Normal file
View file

@ -0,0 +1,120 @@
#ifndef __LCD
#define __LCD
#define LCD_RESET_HIGH() PIO_OUTPUT_DATA_SET |= (1<<GPIO_LRST)
#define LCD_RESET_LOW() PIO_OUTPUT_DATA_CLEAR |= (1<<GPIO_LRST)
// The resolution of the LCD
#define LCD_XRES 132
#define LCD_YRES 132
// 8bpp Color Mode - Some basic colors defined for ease of use
// remember 8bpp color = 3xRed, 3xGreen & 2xBlue bits
// organised as RRRGGGBB
#define BLACK 0x00
#define BLUE 0x03
#define GREEN 0x1C
#define CYAN 0x1F
#define RED 0xE0
#define MAGENTA 0xE3
#define YELLOW 0xFC
#define WHITE 0xFF
// EPSON LCD command set
#define ECASET 0x115
#define EPWRCTR 0x120
#define ENOP 0x125
#define ERAMWR 0x15C
#define ERAMRD 0x15D
#define EPASET 0x175
#define EEPSRRD1 0x17C
#define EEPSRRD2 0x17D
#define EVOLCTR 0x181
#define ETMPGRD 0x182
#define ESLPOUT 0x194
#define ESLPIN 0x195
#define EDISNOR 0x1A6
#define EDISINV 0x1A7
#define EPTLIN 0x1A8
#define EPTLOUT 0x1A9
#define EASCSET 0x1AA
#define ESCSTART 0x1AB
#define EDISOFF 0x1AE
#define EDISON 0x1AF
#define ECOMSCN 0x1BB
#define EDATCTL 0x1BC
#define EDISCTL 0x1CA
#define EEPCOUT 0x1CC
#define EEPCTIN 0x1CD
#define ERGBSET8 0x1CE
#define EOSCON 0x1D1
#define EOSCOFF 0x1D2
#define EVOLUP 0x1D6
#define EVOLDOWN 0x1D7
#define ERMWIN 0x1E0
#define ERMWOUT 0x1EE
#define EEPMWR 0x1FC
#define EEPMRD 0x1FD
// PHILIPS LCD command set
#define PNOP 0x100
#define PSWRESET 0x101
#define PBSTROFF 0x102
#define PBSTRON 0x103
#define PRDDIDIF 0x104
#define PRDDST 0x109
#define PSLEEPIN 0x110
#define PSLEEPOUT 0x111
#define PPTLON 0x112
#define PNORON 0x113
#define PINVOFF 0x120
#define PINVON 0x121
#define PDALO 0x122
#define PDAL 0x123
#define PSETCON 0x125
#define PDISPOFF 0x128
#define PDISPON 0x129
#define PCASET 0x12A
#define PPASET 0x12B
#define PRAMWR 0x12C
#define PRGBSET 0x12D
#define PPTLAR 0x130
#define PVSCRDEF 0x133
#define PTEOFF 0x134
#define PTEON 0x135
#define PMADCTL 0x136
#define PSEP 0x137
#define PIDMOFF 0x138
#define PIDMON 0x139
#define PCOLMOD 0x13A
#define PSETVOP 0x1B0
#define PBRS 0x1B4
#define PTRS 0x1B6
#define PFINV 0x1B9
#define PDOR 0x1BA
#define PTCDFE 0x1BD
#define PTCVOPE 0x1BF
#define PEC 0x1C0
#define PSETMUL 0x1C2
#define PTCVOPAB 0x1C3
#define PTCVOPCD 0x1C4
#define PTCDF 0x1C5
#define PDF8C 0x1C6
#define PSETBS 0x1C7
#define PRDTEMP 0x1C8
#define PNLI 0x1C9
#define PRDID1 0x1DA
#define PRDID2 0x1DB
#define PRDID3 0x1DC
#define PSFD 0x1EF
#define PECM 0x1F0
void LCDSend(unsigned int data);
void LCDInit(void);
void LCDReset(void);
void LCDSetXY(unsigned char x, unsigned char y);
void LCDSetPixel(unsigned char x, unsigned char y, unsigned char color);
void LCDString (char *lcd_string, const char *font_style,unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor);
void LCDFill (unsigned char xs,unsigned char ys,unsigned char width,unsigned char height, unsigned char color);
#endif

61
armsrc/Makefile Normal file
View file

@ -0,0 +1,61 @@
CC = arm-elf-gcc
AS = arm-elf-as
LD = arm-elf-ld
OBJCOPY = arm-elf-objcopy
OBJDIR = obj
INCLUDE = -I../include
INCLUDES = ../include/proxmark3.h ../include/at91sam7s128.h ../include/config_gpio.h ../include/usb_cmd.h apps.h
LIB = "..\..\devkitARM\lib\gcc\arm-elf\4.1.0\interwork"
CFLAGS = -O6 -c $(INCLUDE) -Wall
OBJ = $(OBJDIR)/start.o \
$(OBJDIR)/appmain.o \
$(OBJDIR)/fpga.o \
$(OBJDIR)/iso14443.o \
$(OBJDIR)/iso14443a.o \
$(OBJDIR)/iso15693.o \
$(OBJDIR)/util.o \
$(OBJDIR)/fonts.o \
$(OBJDIR)/LCD.o
OBJFPGA = \
$(OBJDIR)/fpgaimg.o
OBJCOMMON = \
$(OBJDIR)/usb.o
all: osimage.s19
$(OBJDIR)/fpgaimage.s19: $(OBJDIR)/fpgaimg.o
@echo obj/fpgaimage.s19
@$(LD) -g -Tldscript-fpga -o $(OBJDIR)\fpgaimage.elf $(OBJDIR)/fpgaimg.o
@$(OBJCOPY) -Osrec --srec-forceS3 $(OBJDIR)\fpgaimage.elf $(OBJDIR)\fpgaimage.s19
$(OBJDIR)/osimage.s19: $(OBJ) $(OBJCOMMON)
@echo obj/osimage.s19
@$(LD) -g -Tldscript -o $(OBJDIR)\osimage.elf $(OBJ) $(OBJCOMMON) $(LIB)\libgcc.a
@$(OBJCOPY) -Osrec --srec-forceS3 $(OBJDIR)\osimage.elf $(OBJDIR)\osimage.s19
osimage.s19: $(OBJDIR)/osimage.s19 $(OBJDIR)/fpgaimage.s19
@echo osimage.s19
$(OBJ): $(@B).c $(INCLUDES)
@echo $(@B).c
@$(CC) $(CFLAGS) -mthumb -mthumb-interwork $(@B).c -o $(OBJDIR)/$(@B).o
$(OBJCOMMON): ../common/$(@B).c $(INCLUDES)
@echo $(@B).c
@$(CC) $(CFLAGS) -mthumb -mthumb-interwork ../common/$(@B).c -o $(OBJDIR)/$(@B).o
$(OBJFPGA): $(@B).c $(INCLUDES)
@echo $(@B).c
@$(CC) $(CFLAGS) -mthumb -mthumb-interwork $(@B).c -o $(OBJDIR)/$(@B).o
clean:
del /q obj\*.o
del /q obj\*.elf
del /q obj\*.s19

757
armsrc/appmain.c Normal file
View file

@ -0,0 +1,757 @@
//-----------------------------------------------------------------------------
// The main application code. This is the first thing called after start.c
// executes.
// Jonathan Westhues, Mar 2006
// Edits by Gerhard de Koning Gans, Sep 2007 (##)
//-----------------------------------------------------------------------------
#include <proxmark3.h>
#include "apps.h"
#include "fonts.h"
#include "LCD.h"
// The large multi-purpose buffer, typically used to hold A/D samples,
// maybe pre-processed in some way.
DWORD BigBuf[16000];
//=============================================================================
// A buffer where we can queue things up to be sent through the FPGA, for
// any purpose (fake tag, as reader, whatever). We go MSB first, since that
// is the order in which they go out on the wire.
//=============================================================================
BYTE ToSend[256];
int ToSendMax;
static int ToSendBit;
void ToSendReset(void)
{
ToSendMax = -1;
ToSendBit = 8;
}
void ToSendStuffBit(int b)
{
if(ToSendBit >= 8) {
ToSendMax++;
ToSend[ToSendMax] = 0;
ToSendBit = 0;
}
if(b) {
ToSend[ToSendMax] |= (1 << (7 - ToSendBit));
}
ToSendBit++;
if(ToSendBit >= sizeof(ToSend)) {
ToSendBit = 0;
DbpString("ToSendStuffBit overflowed!");
}
}
//=============================================================================
// Debug print functions, to go out over USB, to the usual PC-side client.
//=============================================================================
void DbpString(char *str)
{
UsbCommand c;
c.cmd = CMD_DEBUG_PRINT_STRING;
c.ext1 = strlen(str);
memcpy(c.d.asBytes, str, c.ext1);
UsbSendPacket((BYTE *)&c, sizeof(c));
// TODO fix USB so stupid things like this aren't req'd
SpinDelay(50);
}
void DbpIntegers(int x1, int x2, int x3)
{
UsbCommand c;
c.cmd = CMD_DEBUG_PRINT_INTEGERS;
c.ext1 = x1;
c.ext2 = x2;
c.ext3 = x3;
UsbSendPacket((BYTE *)&c, sizeof(c));
// XXX
SpinDelay(50);
}
void AcquireRawAdcSamples125k(BOOL at134khz)
{
BYTE *dest = (BYTE *)BigBuf;
int n = sizeof(BigBuf);
int i;
memset(dest,0,n);
if(at134khz) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_134_KHZ);
} else {
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_125_KHZ);
}
// Connect the A/D to the peak-detected low-frequency path.
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// Give it a bit of time for the resonant antenna to settle.
SpinDelay(50);
// Now set up the SSC to get the ADC samples that are now streaming at us.
FpgaSetupSsc();
i = 0;
for(;;) {
if(SSC_STATUS & (SSC_STATUS_TX_READY)) {
SSC_TRANSMIT_HOLDING = 0x43;
LED_D_ON();
}
if(SSC_STATUS & (SSC_STATUS_RX_READY)) {
dest[i] = (BYTE)SSC_RECEIVE_HOLDING;
i++;
LED_D_OFF();
if(i >= n) {
break;
}
}
}
DbpIntegers(dest[0], dest[1], at134khz);
}
//-----------------------------------------------------------------------------
// Read an ADC channel and block till it completes, then return the result
// in ADC units (0 to 1023). Also a routine to average sixteen samples and
// return that.
//-----------------------------------------------------------------------------
static int ReadAdc(int ch)
{
DWORD d;
ADC_CONTROL = ADC_CONTROL_RESET;
ADC_MODE = ADC_MODE_PRESCALE(32) | ADC_MODE_STARTUP_TIME(16) |
ADC_MODE_SAMPLE_HOLD_TIME(8);
ADC_CHANNEL_ENABLE = ADC_CHANNEL(ch);
ADC_CONTROL = ADC_CONTROL_START;
while(!(ADC_STATUS & ADC_END_OF_CONVERSION(ch)))
;
d = ADC_CHANNEL_DATA(ch);
return d;
}
static int AvgAdc(int ch)
{
int i;
int a = 0;
for(i = 0; i < 32; i++) {
a += ReadAdc(ch);
}
return (a + 15) >> 5;
}
void MeasureAntennaTuning(void)
{
// Impedances are Zc = 1/(j*omega*C), in ohms
#define LF_TUNING_CAP_Z 1273 // 1 nF @ 125 kHz
#define HF_TUNING_CAP_Z 235 // 50 pF @ 13.56 MHz
int vLf125, vLf134, vHf; // in mV
UsbCommand c;
// Let the FPGA drive the low-frequency antenna around 125 kHz.
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_125_KHZ);
SpinDelay(20);
vLf125 = AvgAdc(4);
// Vref = 3.3V, and a 10000:240 voltage divider on the input
// can measure voltages up to 137500 mV
vLf125 = (137500 * vLf125) >> 10;
// Let the FPGA drive the low-frequency antenna around 134 kHz.
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_134_KHZ);
SpinDelay(20);
vLf134 = AvgAdc(4);
// Vref = 3.3V, and a 10000:240 voltage divider on the input
// can measure voltages up to 137500 mV
vLf134 = (137500 * vLf134) >> 10;
// Let the FPGA drive the high-frequency antenna around 13.56 MHz.
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
SpinDelay(20);
vHf = AvgAdc(5);
// Vref = 3300mV, and an 10:1 voltage divider on the input
// can measure voltages up to 33000 mV
vHf = (33000 * vHf) >> 10;
c.cmd = CMD_MEASURED_ANTENNA_TUNING;
c.ext1 = (vLf125 << 0) | (vLf134 << 16);
c.ext2 = vHf;
c.ext3 = (LF_TUNING_CAP_Z << 0) | (HF_TUNING_CAP_Z << 16);
UsbSendPacket((BYTE *)&c, sizeof(c));
}
void SimulateTagLowFrequency(int period)
{
int i;
BYTE *tab = (BYTE *)BigBuf;
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_SIMULATOR);
PIO_ENABLE = (1 << GPIO_SSC_DOUT) | (1 << GPIO_SSC_CLK);
PIO_OUTPUT_ENABLE = (1 << GPIO_SSC_DOUT);
PIO_OUTPUT_DISABLE = (1 << GPIO_SSC_CLK);
#define SHORT_COIL() LOW(GPIO_SSC_DOUT)
#define OPEN_COIL() HIGH(GPIO_SSC_DOUT)
i = 0;
for(;;) {
while(!(PIO_PIN_DATA_STATUS & (1<<GPIO_SSC_CLK))) {
if(BUTTON_PRESS()) {
return;
}
WDT_HIT();
}
LED_D_ON();
if(tab[i]) {
OPEN_COIL();
} else {
SHORT_COIL();
}
LED_D_OFF();
while(PIO_PIN_DATA_STATUS & (1<<GPIO_SSC_CLK)) {
if(BUTTON_PRESS()) {
return;
}
WDT_HIT();
}
i++;
if(i == period) i = 0;
}
}
// compose fc/8 fc/10 waveform
static void fc(int c, int *n) {
BYTE *dest = (BYTE *)BigBuf;
int idx;
// for when we want an fc8 pattern every 4 logical bits
if(c==0) {
dest[((*n)++)]=1;
dest[((*n)++)]=1;
dest[((*n)++)]=0;
dest[((*n)++)]=0;
dest[((*n)++)]=0;
dest[((*n)++)]=0;
dest[((*n)++)]=0;
dest[((*n)++)]=0;
}
// an fc/8 encoded bit is a bit pattern of 11000000 x6 = 48 samples
if(c==8) {
for (idx=0; idx<6; idx++) {
dest[((*n)++)]=1;
dest[((*n)++)]=1;
dest[((*n)++)]=0;
dest[((*n)++)]=0;
dest[((*n)++)]=0;
dest[((*n)++)]=0;
dest[((*n)++)]=0;
dest[((*n)++)]=0;
}
}
// an fc/10 encoded bit is a bit pattern of 1110000000 x5 = 50 samples
if(c==10) {
for (idx=0; idx<5; idx++) {
dest[((*n)++)]=1;
dest[((*n)++)]=1;
dest[((*n)++)]=1;
dest[((*n)++)]=0;
dest[((*n)++)]=0;
dest[((*n)++)]=0;
dest[((*n)++)]=0;
dest[((*n)++)]=0;
dest[((*n)++)]=0;
dest[((*n)++)]=0;
}
}
}
// prepare a waveform pattern in the buffer based on the ID given then
// simulate a HID tag until the button is pressed
static void CmdHIDsimTAG(int hi, int lo)
{
int n=0, i=0;
/*
HID tag bitstream format
The tag contains a 44bit unique code. This is sent out MSB first in sets of 4 bits
A 1 bit is represented as 6 fc8 and 5 fc10 patterns
A 0 bit is represented as 5 fc10 and 6 fc8 patterns
A fc8 is inserted before every 4 bits
A special start of frame pattern is used consisting a0b0 where a and b are neither 0
nor 1 bits, they are special patterns (a = set of 12 fc8 and b = set of 10 fc10)
*/
if (hi>0xFFF) {
DbpString("Tags can only have 44 bits.");
return;
}
fc(0,&n);
// special start of frame marker containing invalid bit sequences
fc(8, &n); fc(8, &n); // invalid
fc(8, &n); fc(10, &n); // logical 0
fc(10, &n); fc(10, &n); // invalid
fc(8, &n); fc(10, &n); // logical 0
WDT_HIT();
// manchester encode bits 43 to 32
for (i=11; i>=0; i--) {
if ((i%4)==3) fc(0,&n);
if ((hi>>i)&1) {
fc(10, &n); fc(8, &n); // low-high transition
} else {
fc(8, &n); fc(10, &n); // high-low transition
}
}
WDT_HIT();
// manchester encode bits 31 to 0
for (i=31; i>=0; i--) {
if ((i%4)==3) fc(0,&n);
if ((lo>>i)&1) {
fc(10, &n); fc(8, &n); // low-high transition
} else {
fc(8, &n); fc(10, &n); // high-low transition
}
}
LED_A_ON();
SimulateTagLowFrequency(n);
LED_A_OFF();
}
// loop to capture raw HID waveform then FSK demodulate the TAG ID from it
static void CmdHIDdemodFSK(void)
{
BYTE *dest = (BYTE *)BigBuf;
int m=0, n=0, i=0, idx=0, found=0, lastval=0;
DWORD hi=0, lo=0;
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_READER_USE_125_KHZ);
// Connect the A/D to the peak-detected low-frequency path.
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// Give it a bit of time for the resonant antenna to settle.
SpinDelay(50);
// Now set up the SSC to get the ADC samples that are now streaming at us.
FpgaSetupSsc();
for(;;) {
WDT_HIT();
LED_A_ON();
if(BUTTON_PRESS()) {
LED_A_OFF();
return;
}
i = 0;
m = sizeof(BigBuf);
memset(dest,128,m);
for(;;) {
if(SSC_STATUS & (SSC_STATUS_TX_READY)) {
SSC_TRANSMIT_HOLDING = 0x43;
LED_D_ON();
}
if(SSC_STATUS & (SSC_STATUS_RX_READY)) {
dest[i] = (BYTE)SSC_RECEIVE_HOLDING;
// we don't care about actual value, only if it's more or less than a
// threshold essentially we capture zero crossings for later analysis
if(dest[i] < 127) dest[i] = 0; else dest[i] = 1;
i++;
LED_D_OFF();
if(i >= m) {
break;
}
}
}
// FSK demodulator
// sync to first lo-hi transition
for( idx=1; idx<m; idx++) {
if (dest[idx-1]<dest[idx])
lastval=idx;
break;
}
WDT_HIT();
// count cycles between consecutive lo-hi transitions, there should be either 8 (fc/8)
// or 10 (fc/10) cycles but in practice due to noise etc we may end up with with anywhere
// between 7 to 11 cycles so fuzz it by treat anything <9 as 8 and anything else as 10
for( i=0; idx<m; idx++) {
if (dest[idx-1]<dest[idx]) {
dest[i]=idx-lastval;
if (dest[i] <= 8) {
dest[i]=1;
} else {
dest[i]=0;
}
lastval=idx;
i++;
}
}
m=i;
WDT_HIT();
// we now have a set of cycle counts, loop over previous results and aggregate data into bit patterns
lastval=dest[0];
idx=0;
i=0;
n=0;
for( idx=0; idx<m; idx++) {
if (dest[idx]==lastval) {
n++;
} else {
// a bit time is five fc/10 or six fc/8 cycles so figure out how many bits a pattern width represents,
// an extra fc/8 pattern preceeds every 4 bits (about 200 cycles) just to complicate things but it gets
// swallowed up by rounding
// expected results are 1 or 2 bits, any more and it's an invalid manchester encoding
// special start of frame markers use invalid manchester states (no transitions) by using sequences
// like 111000
if (dest[idx-1]) {
n=(n+1)/6; // fc/8 in sets of 6
} else {
n=(n+1)/5; // fc/10 in sets of 5
}
switch (n) { // stuff appropriate bits in buffer
case 0:
case 1: // one bit
dest[i++]=dest[idx-1];
break;
case 2: // two bits
dest[i++]=dest[idx-1];
dest[i++]=dest[idx-1];
break;
case 3: // 3 bit start of frame markers
dest[i++]=dest[idx-1];
dest[i++]=dest[idx-1];
dest[i++]=dest[idx-1];
break;
// When a logic 0 is immediately followed by the start of the next transmisson
// (special pattern) a pattern of 4 bit duration lengths is created.
case 4:
dest[i++]=dest[idx-1];
dest[i++]=dest[idx-1];
dest[i++]=dest[idx-1];
dest[i++]=dest[idx-1];
break;
default: // this shouldn't happen, don't stuff any bits
break;
}
n=0;
lastval=dest[idx];
}
}
m=i;
WDT_HIT();
// final loop, go over previously decoded manchester data and decode into usable tag ID
// 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0
for( idx=0; idx<m-6; idx++) {
// search for a start of frame marker
if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) )
{
found=1;
idx+=6;
if (found && (hi|lo)) {
DbpString("TAG ID");
DbpIntegers(hi, lo, (lo>>1)&0xffff);
hi=0;
lo=0;
found=0;
}
}
if (found) {
if (dest[idx] && (!dest[idx+1]) ) {
hi=(hi<<1)|(lo>>31);
lo=(lo<<1)|0;
} else if ( (!dest[idx]) && dest[idx+1]) {
hi=(hi<<1)|(lo>>31);
lo=(lo<<1)|1;
} else {
found=0;
hi=0;
lo=0;
}
idx++;
}
if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) )
{
found=1;
idx+=6;
if (found && (hi|lo)) {
DbpString("TAG ID");
DbpIntegers(hi, lo, (lo>>1)&0xffff);
hi=0;
lo=0;
found=0;
}
}
}
WDT_HIT();
}
}
void SimulateTagHfListen(void)
{
BYTE *dest = (BYTE *)BigBuf;
int n = sizeof(BigBuf);
BYTE v = 0;
int i;
int p = 0;
// We're using this mode just so that I can test it out; the simulated
// tag mode would work just as well and be simpler.
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP);
// We need to listen to the high-frequency, peak-detected path.
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc();
i = 0;
for(;;) {
if(SSC_STATUS & (SSC_STATUS_TX_READY)) {
SSC_TRANSMIT_HOLDING = 0xff;
}
if(SSC_STATUS & (SSC_STATUS_RX_READY)) {
BYTE r = (BYTE)SSC_RECEIVE_HOLDING;
v <<= 1;
if(r & 1) {
v |= 1;
}
p++;
if(p >= 8) {
dest[i] = v;
v = 0;
p = 0;
i++;
if(i >= n) {
break;
}
}
}
}
DbpString("simulate tag (now type bitsamples)");
}
void UsbPacketReceived(BYTE *packet, int len)
{
UsbCommand *c = (UsbCommand *)packet;
switch(c->cmd) {
case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K:
AcquireRawAdcSamples125k(c->ext1);
break;
case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693:
AcquireRawAdcSamplesIso15693();
break;
case CMD_READER_ISO_15693:
ReaderIso15693(c->ext1);
break;
case CMD_SIMTAG_ISO_15693:
SimTagIso15693(c->ext1);
break;
case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443:
AcquireRawAdcSamplesIso14443(c->ext1);
break;
case CMD_READER_ISO_14443a:
ReaderIso14443a(c->ext1);
break;
case CMD_SNOOP_ISO_14443:
SnoopIso14443();
break;
case CMD_SNOOP_ISO_14443a:
SnoopIso14443a();
break;
case CMD_SIMULATE_TAG_HF_LISTEN:
SimulateTagHfListen();
break;
case CMD_SIMULATE_TAG_ISO_14443:
SimulateIso14443Tag();
break;
case CMD_SIMULATE_TAG_ISO_14443a:
SimulateIso14443aTag(c->ext1, c->ext2); // ## Simulate iso14443a tag - pass tag type & UID
break;
case CMD_MEASURE_ANTENNA_TUNING:
MeasureAntennaTuning();
break;
case CMD_HID_DEMOD_FSK:
CmdHIDdemodFSK(); // Demodulate HID tag
break;
case CMD_HID_SIM_TAG:
CmdHIDsimTAG(c->ext1, c->ext2); // Simulate HID tag by ID
break;
case CMD_FPGA_MAJOR_MODE_OFF: // ## FPGA Control
LED_C_ON();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(200);
LED_C_OFF();
break;
case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K:
case CMD_DOWNLOAD_RAW_BITS_TI_TYPE: {
UsbCommand n;
if(c->cmd == CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K) {
n.cmd = CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K;
} else {
n.cmd = CMD_DOWNLOADED_RAW_BITS_TI_TYPE;
}
n.ext1 = c->ext1;
memcpy(n.d.asDwords, BigBuf+c->ext1, 12*sizeof(DWORD));
UsbSendPacket((BYTE *)&n, sizeof(n));
break;
}
case CMD_DOWNLOADED_SIM_SAMPLES_125K: {
BYTE *b = (BYTE *)BigBuf;
memcpy(b+c->ext1, c->d.asBytes, 48);
break;
}
case CMD_SIMULATE_TAG_125K:
LED_A_ON();
SimulateTagLowFrequency(c->ext1);
LED_A_OFF();
break;
case CMD_LCD_RESET:
LCDReset();
break;
case CMD_LCD:
LCDSend(c->ext1);
break;
case CMD_SETUP_WRITE:
case CMD_FINISH_WRITE:
USB_D_PLUS_PULLUP_OFF();
SpinDelay(1000);
SpinDelay(1000);
RSTC_CONTROL = RST_CONTROL_KEY | RST_CONTROL_PROCESSOR_RESET;
for(;;) {
// We're going to reset, and the bootrom will take control.
}
break;
default:
DbpString("unknown command");
break;
}
}
void AppMain(void)
{
memset(BigBuf,0,sizeof(BigBuf));
SpinDelay(100);
LED_D_OFF();
LED_C_OFF();
LED_B_OFF();
LED_A_OFF();
UsbStart();
// The FPGA gets its clock from us from PCK0 output, so set that up.
PIO_PERIPHERAL_B_SEL = (1 << GPIO_PCK0);
PIO_DISABLE = (1 << GPIO_PCK0);
PMC_SYS_CLK_ENABLE = PMC_SYS_CLK_PROGRAMMABLE_CLK_0;
// PCK0 is PLL clock / 4 = 96Mhz / 4 = 24Mhz
PMC_PROGRAMMABLE_CLK_0 = PMC_CLK_SELECTION_PLL_CLOCK |
PMC_CLK_PRESCALE_DIV_4;
PIO_OUTPUT_ENABLE = (1 << GPIO_PCK0);
// Reset SPI
SPI_CONTROL = SPI_CONTROL_RESET;
// Reset SSC
SSC_CONTROL = SSC_CONTROL_RESET;
// Load the FPGA image, which we have stored in our flash.
FpgaDownloadAndGo();
LCDInit();
// test text on different colored backgrounds
LCDString(" The quick brown fox ", &FONT6x8,1,1+8*0,WHITE ,BLACK );
LCDString(" jumped over the ", &FONT6x8,1,1+8*1,BLACK ,WHITE );
LCDString(" lazy dog. ", &FONT6x8,1,1+8*2,YELLOW ,RED );
LCDString(" AaBbCcDdEeFfGgHhIiJj ", &FONT6x8,1,1+8*3,RED ,GREEN );
LCDString(" KkLlMmNnOoPpQqRrSsTt ", &FONT6x8,1,1+8*4,MAGENTA,BLUE );
LCDString("UuVvWwXxYyZz0123456789", &FONT6x8,1,1+8*5,BLUE ,YELLOW);
LCDString("`-=[]_;',./~!@#$%^&*()", &FONT6x8,1,1+8*6,BLACK ,CYAN );
LCDString(" _+{}|:\\\"<>? ",&FONT6x8,1,1+8*7,BLUE ,MAGENTA);
// color bands
LCDFill(0, 1+8* 8, 132, 8, BLACK);
LCDFill(0, 1+8* 9, 132, 8, WHITE);
LCDFill(0, 1+8*10, 132, 8, RED);
LCDFill(0, 1+8*11, 132, 8, GREEN);
LCDFill(0, 1+8*12, 132, 8, BLUE);
LCDFill(0, 1+8*13, 132, 8, YELLOW);
LCDFill(0, 1+8*14, 132, 8, CYAN);
LCDFill(0, 1+8*15, 132, 8, MAGENTA);
for(;;) {
UsbPoll(FALSE);
WDT_HIT();
}
}
void SpinDelay(int ms)
{
int ticks = (48000*ms) >> 10;
// Borrow a PWM unit for my real-time clock
PWM_ENABLE = PWM_CHANNEL(0);
// 48 MHz / 1024 gives 46.875 kHz
PWM_CH_MODE(0) = PWM_CH_MODE_PRESCALER(10);
PWM_CH_DUTY_CYCLE(0) = 0;
PWM_CH_PERIOD(0) = 0xffff;
WORD start = (WORD)PWM_CH_COUNTER(0);
for(;;) {
WORD now = (WORD)PWM_CH_COUNTER(0);
if(now == (WORD)(start + ticks)) {
return;
}
WDT_HIT();
}
}

77
armsrc/apps.h Normal file
View file

@ -0,0 +1,77 @@
//-----------------------------------------------------------------------------
// Definitions internal to the app source.
// Jonathan Westhues, Aug 2005
// Added ISO14443-A support by Gerhard de Koning Gans, April 2008
//-----------------------------------------------------------------------------
#ifndef __APPS_H
#define __APPS_H
/// appmain.c
void AppMain(void);
void DbpIntegers(int a, int b, int c);
void DbpString(char *str);
void SpinDelay(int ms);
void ToSendStuffBit(int b);
void ToSendReset(void);
extern int ToSendMax;
extern BYTE ToSend[];
extern DWORD BigBuf[];
/// fpga.c
void FpgaWriteConfWord(BYTE v);
void FpgaDownloadAndGo(void);
void FpgaSetupSsc(void);
void SetupSpi(int mode);
void FpgaSetupSscDma(BYTE *buf, int len);
void SetAdcMuxFor(int whichGpio);
// Definitions for the FPGA configuration word.
#define FPGA_MAJOR_MODE_LF_READER (0<<5)
#define FPGA_MAJOR_MODE_LF_SIMULATOR (1<<5)
#define FPGA_MAJOR_MODE_HF_READER_TX (2<<5)
#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (3<<5)
#define FPGA_MAJOR_MODE_HF_SIMULATOR (4<<5)
#define FPGA_MAJOR_MODE_HF_ISO14443A (5<<5)
#define FPGA_MAJOR_MODE_UNUSED (6<<5)
#define FPGA_MAJOR_MODE_OFF (7<<5)
// Options for the LF reader
#define FPGA_LF_READER_USE_125_KHZ (1<<3)
#define FPGA_LF_READER_USE_134_KHZ (0<<3)
// Options for the HF reader, tx to tag
#define FPGA_HF_READER_TX_SHALLOW_MOD (1<<0)
// Options for the HF reader, correlating against rx from tag
#define FPGA_HF_READER_RX_XCORR_848_KHZ (1<<0)
#define FPGA_HF_READER_RX_XCORR_SNOOP (1<<1)
// Options for the HF simulated tag, how to modulate
#define FPGA_HF_SIMULATOR_NO_MODULATION (0<<0)
#define FPGA_HF_SIMULATOR_MODULATE_BPSK (1<<0)
// Options for ISO14443A
#define FPGA_HF_ISO14443A_SNIFFER (0<<0)
#define FPGA_HF_ISO14443A_TAGSIM_LISTEN (1<<0)
#define FPGA_HF_ISO14443A_TAGSIM_MOD (2<<0)
#define FPGA_HF_ISO14443A_READER_LISTEN (3<<0)
#define FPGA_HF_ISO14443A_READER_MOD (4<<0)
/// iso14443.h
void SimulateIso14443Tag(void);
void AcquireRawAdcSamplesIso14443(DWORD parameter);
void SnoopIso14443(void);
/// iso14443a.h
void SnoopIso14443a(void);
void SimulateIso14443aTag(int tagType, int TagUid); // ## simulate iso14443a tag
void ReaderIso14443a(DWORD parameter);
/// iso15693.h
void AcquireRawAdcSamplesIso15693(void);
void ReaderIso15693(DWORD parameter); // Simulate an ISO15693 reader - greg
void SimTagIso15693(DWORD parameter); // simulate an ISO15693 tag - greg
/// util.h
int strlen(char *str);
void *memcpy(void *dest, const void *src, int len);
void *memset(void *dest, int c, int len);
int memcmp(const void *av, const void *bv, int len);
#endif

269
armsrc/example_lcd.c Normal file
View file

@ -0,0 +1,269 @@
unsigned char somestring[25];
//*********************************************************************
//******************** SYSTERM HEARTBEAT @ 10 ms *********************
//*********************************************************************
void InitSPI (void)
{
//set functionalite to pins:
//port0.11 -> NPCS0
//port0.12 -> MISO
//port0.13 -> MOSI
//port0.14 -> SPCK
PIOA_PDR = BIT11 | BIT12 | BIT13 | BIT14;
PIOA_ASR = BIT11 | BIT12 | BIT13 | BIT14;
PIOA_BSR = 0;
PMC_PCER |= 1 << 5; // Enable SPI timer clock.
/**** Fixed mode ****/
SPI_CR = 0x81; //SPI Enable, Sowtware reset
SPI_CR = 0x01; //SPI Enable
SPI_MR = 0x000E0011; //Master mode
SPI_CSR0 = 0x01010B11; //9 bit
}
//*********************************************************************
//*************************** Task 1 ********************************
//*********************************************************************
void Task_1(void *p)
{
char beat=0; // just flash the onboard LED for Heatbeat
while(1)
{
if(beat)
{
PIOA_SODR = BIT18;
beat=0;
}
else
{
PIOA_CODR = BIT18;
beat=1;
}
ctl_timeout_wait(ctl_get_current_time()+ 150);
}
}
//*********************************************************************
//*************************** Task 2 ********************************
//*********************************************************************
void Task_2(void *p)
{
unsigned long z;
unsigned int x,y;
unsigned char a,b,c,d,e;
char seconds,minutes,hours;
unsigned int nowold,tenths;
InitLCD();
/******* Put smiley face up in 4096 color mode *******/
LCD_Fill(0,0,132,132,Black);
LCD_Set_Resolution(HIGH_RES); // set 4096 color mode
// ShowImage_4096(0,0,smiley);
LCD_Set_Resolution(LOW_RES); // set 256 color mode
ctl_timeout_wait(ctl_get_current_time()+ 4000); // wait 4 seconds to view it
/******* Do some static on screen *******/
LCD_Fill(0,0,132,132,Black);
for(z=0;z<100000;z++)
{
while( (a = rand()) > 132);
while( (b = rand()) > 132);
c = rand();
LCD_PixelPut(a,b,c);
}
/******* Do some lines on screen *******/
LCD_Fill(0,0,132,132,Black);
for(z=1;z<300;z++)
{
while( (a = rand()) > 132);
while( (b = rand()) > 132);
while( (c = rand()) > 132);
while( (d = rand()) > 132);
e = rand(); // pick color
LCD_Line(a,b,c,d,e);
ctl_timeout_wait(ctl_get_current_time()+ 10);
}
/******* Do some Boxes on screen *******/
LCD_Fill(0,0,132,132,Black);
for(z=0;z<300;z++)
{
while( (a = rand()) > 132);
while( (b = rand()) > 132);
while( (c = rand()) > 132);
while( (d = rand()) > 132);
e = rand(); // pick color
LCD_Box(a,b,c,d,e);
ctl_timeout_wait(ctl_get_current_time()+ 10);
}
/******* Do some Circles on screen *******/
LCD_Fill(0,0,132,132,Black);
for(z=0;z<100;z++)
{
while( (a = rand()) > 132);
while( (b = rand()) > 132);
while( (c = rand()) > 127); // diameter
d = rand(); // pick color
LCD_Circle(a,b,c,d);
ctl_timeout_wait(ctl_get_current_time()+ 10);
}
/******* Do some Thick Circles on screen *******/
LCD_Fill(0,0,132,132,Black);
for(z=0;z<25;z++)
{
while( (a = rand()) > 132);
while( (b = rand()) > 132);
while( (c = rand()) > 40); // diameter
while( (d = rand()) > 10); // wall thicknes
e = rand(); // pick color
LCD_Thick_Circle(a,b,c,d,e);
ctl_timeout_wait(ctl_get_current_time()+ 1);
}
/******* Do something funky to wipe screen *******/
b=0;
for(a=0;a<131;a++)
{
LCD_Line(a,b,65,65,0x62);
}
for(b=0;b<131;b++)
{
LCD_Line(a,b,65,65,0x62);
}
for(;a>1;a--)
{
LCD_Line(a,b,65,65,0x62);
}
for(;b>1;b--)
{
LCD_Line(a,b,65,65,0x62);
}
ctl_timeout_wait(ctl_get_current_time()+ 1000);
/******* Show Image scrolling *******/
LCD_Fill(0,0,132,132,Black);
ShowImage(0,50,sparkfun);
sprintf(somestring,"Thanks SparkFun");
LCD_String(somestring,&FONT8x8F[0][0],5,10,LightGreen,Black);
ctl_timeout_wait(ctl_get_current_time()+ 2000); // hold sparkfun image for a bit
for(y=50;y<140;y++)
{
LCD_Line(0,y-1,132,y-1,Black); // wipe the white line as it moves down
ShowImage(0,y,sparkfun); // move image to Y location
ctl_timeout_wait(ctl_get_current_time()+ 25); // wait a bit
}
/******* Run radar in loop with example fonts displayed *******/
LCD_Fill(0,0,132,132,Black);
LCD_Thick_Circle(66,66,30,2,DarkBlue);
y=0;
while (1)
{
LCD_Circle_Line(66,66,28,0,y,LightGreen);
ctl_timeout_wait(ctl_get_current_time()+ 1);
tenths = ctl_current_time / 1000;
if(tenths != nowold)
{
nowold = tenths;
if(++seconds == 60)
{
seconds = 0;
if(++minutes == 60)
{
minutes=0;
hours++;
}
}
}
printf("a=%6lu - b=%6lu - c=%6lu - d=%6lu : Time=%lu\r\n",a,b,c,d,ctl_current_time);
sprintf(somestring,"%05lu",y);
LCD_String(somestring,&FONT6x8[0][0],52,25,White,Black);
sprintf(somestring,"Time:%02u:%02u:%02u",hours,minutes,seconds);
LCD_String(somestring,&FONT8x8F[0][0],14,10,DarkRed,Black);
sprintf(somestring,"Time:%02u:%02u:%02u",hours,minutes,seconds);
LCD_String(somestring,&FONT8x16[0][0],14,115,LightGreen,Black);
LCD_Circle_Line(66,66,28,0,y,Black);
if(++y==360)
{
y=0;
}
ctl_timeout_wait(ctl_get_current_time()+ 10);
}
}
/*************************************************************************
********************* Main Module *************************
********************* *************************
********************* Initialize Program *************************
********************* Sequences *************************
********************* *************************
*************************************************************************/
int main(void)
{
BoardInit();
InitSPI();
while (1)
{
Idle();
}
return 0;
}

300
armsrc/fonts.c Normal file
View file

@ -0,0 +1,300 @@
const char FONT6x8[97][8] = {
{0x06,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space
{0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00}, // !
{0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00}, // "
{0x50,0x50,0xF8,0x50,0xF8,0x50,0x50,0x00}, // #
{0x20,0x78,0xA0,0x70,0x28,0xF0,0x20,0x00}, // $
{0xC0,0xC8,0x10,0x20,0x40,0x98,0x18,0x00}, // %
{0x40,0xA0,0xA0,0x40,0xA8,0x90,0x68,0x00}, // &
{0x30,0x30,0x20,0x40,0x00,0x00,0x00,0x00}, // '
{0x10,0x20,0x40,0x40,0x40,0x20,0x10,0x00}, // (
{0x40,0x20,0x10,0x10,0x10,0x20,0x40,0x00}, // )
{0x00,0x20,0xA8,0x70,0x70,0xA8,0x20,0x00}, // *
{0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0x00}, // +
{0x00,0x00,0x00,0x00,0x30,0x30,0x20,0x40}, // ,
{0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00}, // -
{0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00}, // .
{0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00}, // /
{0x70,0x88,0x88,0xA8,0x88,0x88,0x70,0x00}, // 0
{0x20,0x60,0x20,0x20,0x20,0x20,0x70,0x00}, // 1
{0x70,0x88,0x08,0x70,0x80,0x80,0xF8,0x00}, // 2
{0xF8,0x08,0x10,0x30,0x08,0x88,0x70,0x00}, // 3
{0x10,0x30,0x50,0x90,0xF8,0x10,0x10,0x00}, // 4
{0xF8,0x80,0xF0,0x08,0x08,0x88,0x70,0x00}, // 5
{0x38,0x40,0x80,0xF0,0x88,0x88,0x70,0x00}, // 6
{0xF8,0x08,0x08,0x10,0x20,0x40,0x80,0x00}, // 7
{0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00}, // 8
{0x70,0x88,0x88,0x78,0x08,0x10,0xE0,0x00}, // 9
{0x00,0x00,0x20,0x00,0x20,0x00,0x00,0x00}, // :
{0x00,0x00,0x20,0x00,0x20,0x20,0x40,0x00}, // ;
{0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x00}, // <
{0x00,0x00,0xF8,0x00,0xF8,0x00,0x00,0x00}, // =
{0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00}, // >
{0x70,0x88,0x08,0x30,0x20,0x00,0x20,0x00}, // ?
{0x70,0x88,0xA8,0xB8,0xB0,0x80,0x78,0x00}, // @
{0x20,0x50,0x88,0x88,0xF8,0x88,0x88,0x00}, // A
{0xF0,0x88,0x88,0xF0,0x88,0x88,0xF0,0x00}, // B
{0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00}, // C
{0xF0,0x88,0x88,0x88,0x88,0x88,0xF0,0x00}, // D
{0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8,0x00}, // E
{0xF8,0x80,0x80,0xF0,0x80,0x80,0x80,0x00}, // F
{0x78,0x88,0x80,0x80,0x98,0x88,0x78,0x00}, // G
{0x88,0x88,0x88,0xF8,0x88,0x88,0x88,0x00}, // H
{0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00}, // I
{0x38,0x10,0x10,0x10,0x10,0x90,0x60,0x00}, // J
{0x88,0x90,0xA0,0xC0,0xA0,0x90,0x88,0x00}, // K
{0x80,0x80,0x80,0x80,0x80,0x80,0xF8,0x00}, // L
{0x88,0xD8,0xA8,0xA8,0xA8,0x88,0x88,0x00}, // M
{0x88,0x88,0xC8,0xA8,0x98,0x88,0x88,0x00}, // N
{0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00}, // O
{0xF0,0x88,0x88,0xF0,0x80,0x80,0x80,0x00}, // P
{0x70,0x88,0x88,0x88,0xA8,0x90,0x68,0x00}, // Q
{0xF0,0x88,0x88,0xF0,0xA0,0x90,0x88,0x00}, // R
{0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00}, // S
{0xF8,0xA8,0x20,0x20,0x20,0x20,0x20,0x00}, // T
{0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00}, // U
{0x88,0x88,0x88,0x88,0x88,0x50,0x20,0x00}, // V
{0x88,0x88,0x88,0xA8,0xA8,0xA8,0x50,0x00}, // W
{0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00}, // X
{0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00}, // Y
{0xF8,0x08,0x10,0x70,0x40,0x80,0xF8,0x00}, // Z
{0x78,0x40,0x40,0x40,0x40,0x40,0x78,0x00}, // [
{0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00}, // backslash
{0x78,0x08,0x08,0x08,0x08,0x08,0x78,0x00}, // ]
{0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00}, // ^
{0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00}, // _
{0x60,0x60,0x20,0x10,0x00,0x00,0x00,0x00}, // `
{0x00,0x00,0x60,0x10,0x70,0x90,0x78,0x00}, // a
{0x80,0x80,0xB0,0xC8,0x88,0xC8,0xB0,0x00}, // b
{0x00,0x00,0x70,0x88,0x80,0x88,0x70,0x00}, // c
{0x08,0x08,0x68,0x98,0x88,0x98,0x68,0x00}, // d
{0x00,0x00,0x70,0x88,0xF8,0x80,0x70,0x00}, // e
{0x10,0x28,0x20,0x70,0x20,0x20,0x20,0x00}, // f
{0x00,0x00,0x70,0x98,0x98,0x68,0x08,0x70}, // g
{0x80,0x80,0xB0,0xC8,0x88,0x88,0x88,0x00}, // h
{0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00}, // i
{0x10,0x00,0x10,0x10,0x10,0x90,0x60,0x00}, // j
{0x80,0x80,0x90,0xA0,0xC0,0xA0,0x90,0x00}, // k
{0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00}, // l
{0x00,0x00,0xD0,0xA8,0xA8,0xA8,0xA8,0x00}, // m
{0x00,0x00,0xB0,0xC8,0x88,0x88,0x88,0x00}, // n
{0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00}, // o
{0x00,0x00,0xB0,0xC8,0xC8,0xB0,0x80,0x80}, // p
{0x00,0x00,0x68,0x98,0x98,0x68,0x08,0x08}, // q
{0x00,0x00,0xB0,0xC8,0x80,0x80,0x80,0x00}, // r
{0x00,0x00,0x78,0x80,0x70,0x08,0xF0,0x00}, // s
{0x20,0x20,0xF8,0x20,0x20,0x28,0x10,0x00}, // t
{0x00,0x00,0x88,0x88,0x88,0x98,0x68,0x00}, // u
{0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x00}, // v
{0x00,0x00,0x88,0x88,0xA8,0xA8,0x50,0x00}, // w
{0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00}, // x
{0x00,0x00,0x88,0x88,0x78,0x08,0x88,0x70}, // y
{0x00,0x00,0xF8,0x10,0x20,0x40,0xF8,0x00}, // z
{0x10,0x20,0x20,0x40,0x20,0x20,0x10,0x00}, // {
{0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x00}, // |
{0x40,0x20,0x20,0x10,0x20,0x20,0x40,0x00}, // }
{0x40,0xA8,0x10,0x00,0x00,0x00,0x00,0x00}, // ~
{0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00} // DEL
};
/*
const char FONT8x8F[97][8] = {
{0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space
{0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00}, // !
{0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00}, // "
{0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00}, // #
{0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00}, // $
{0x00,0x63,0x66,0x0C,0x18,0x33,0x63,0x00}, // %
{0x1C,0x36,0x1C,0x3B,0x6E,0x66,0x3B,0x00}, // &
{0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00}, // '
{0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00}, // (
{0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00}, // )
{0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00}, // *
{0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00}, // +
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30}, // ,
{0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00}, // -
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00}, // .
{0x03,0x06,0x0C,0x18,0x30,0x60,0x40,0x00}, // /
{0x3E,0x63,0x63,0x6B,0x63,0x63,0x3E,0x00}, // 0
{0x18,0x38,0x58,0x18,0x18,0x18,0x7E,0x00}, // 1
{0x3C,0x66,0x06,0x1C,0x30,0x66,0x7E,0x00}, // 2
{0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00}, // 3
{0x0E,0x1E,0x36,0x66,0x7F,0x06,0x0F,0x00}, // 4
{0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00}, // 5
{0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00}, // 6
{0x7E,0x66,0x06,0x0C,0x18,0x18,0x18,0x00}, // 7
{0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00}, // 8
{0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00}, // 9
{0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00}, // :
{0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30}, // ;
{0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00}, // <
{0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00}, // =
{0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00}, // >
{0x3C,0x66,0x06,0x0C,0x18,0x00,0x18,0x00}, // ?
{0x3E,0x63,0x6F,0x69,0x6F,0x60,0x3E,0x00}, // @
{0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x00}, // A
{0x7E,0x33,0x33,0x3E,0x33,0x33,0x7E,0x00}, // B
{0x1E,0x33,0x60,0x60,0x60,0x33,0x1E,0x00}, // C
{0x7C,0x36,0x33,0x33,0x33,0x36,0x7C,0x00}, // D
{0x7F,0x31,0x34,0x3C,0x34,0x31,0x7F,0x00}, // E
{0x7F,0x31,0x34,0x3C,0x34,0x30,0x78,0x00}, // F
{0x1E,0x33,0x60,0x60,0x67,0x33,0x1F,0x00}, // G
{0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, // H
{0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // I
{0x0F,0x06,0x06,0x06,0x66,0x66,0x3C,0x00}, // J
{0x73,0x33,0x36,0x3C,0x36,0x33,0x73,0x00}, // K
{0x78,0x30,0x30,0x30,0x31,0x33,0x7F,0x00}, // L
{0x63,0x77,0x7F,0x7F,0x6B,0x63,0x63,0x00}, // M
{0x63,0x73,0x7B,0x6F,0x67,0x63,0x63,0x00}, // N
{0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00}, // O
{0x7E,0x33,0x33,0x3E,0x30,0x30,0x78,0x00}, // P
{0x3C,0x66,0x66,0x66,0x6E,0x3C,0x0E,0x00}, // Q
{0x7E,0x33,0x33,0x3E,0x36,0x33,0x73,0x00}, // R
{0x3C,0x66,0x30,0x18,0x0C,0x66,0x3C,0x00}, // S
{0x7E,0x5A,0x18,0x18,0x18,0x18,0x3C,0x00}, // T
{0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x00}, // U
{0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00}, // V
{0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x00}, // W
{0x63,0x63,0x36,0x1C,0x1C,0x36,0x63,0x00}, // X
{0x66,0x66,0x66,0x3C,0x18,0x18,0x3C,0x00}, // Y
{0x7F,0x63,0x46,0x0C,0x19,0x33,0x7F,0x00}, // Z
{0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00}, // [
{0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00}, // backslash
{0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00}, // ]
{0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00}, // ^
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF}, // _
{0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00}, // `
{0x00,0x00,0x3C,0x06,0x3E,0x66,0x3B,0x00}, // a
{0x70,0x30,0x3E,0x33,0x33,0x33,0x6E,0x00}, // b
{0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00}, // c
{0x0E,0x06,0x3E,0x66,0x66,0x66,0x3B,0x00}, // d
{0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00}, // e
{0x1C,0x36,0x30,0x78,0x30,0x30,0x78,0x00}, // f
{0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x7C}, // g
{0x70,0x30,0x36,0x3B,0x33,0x33,0x73,0x00}, // h
{0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00}, // i
{0x06,0x00,0x06,0x06,0x06,0x66,0x66,0x3C}, // j
{0x70,0x30,0x33,0x36,0x3C,0x36,0x73,0x00}, // k
{0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // l
{0x00,0x00,0x66,0x7F,0x7F,0x6B,0x63,0x00}, // m
{0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00}, // n
{0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00}, // o
{0x00,0x00,0x6E,0x33,0x33,0x3E,0x30,0x78}, // p
{0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x0F}, // q
{0x00,0x00,0x6E,0x3B,0x33,0x30,0x78,0x00}, // r
{0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00}, // s
{0x08,0x18,0x3E,0x18,0x18,0x1A,0x0C,0x00}, // t
{0x00,0x00,0x66,0x66,0x66,0x66,0x3B,0x00}, // u
{0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00}, // v
{0x00,0x00,0x63,0x6B,0x7F,0x7F,0x36,0x00}, // w
{0x00,0x00,0x63,0x36,0x1C,0x36,0x63,0x00}, // x
{0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x7C}, // y
{0x00,0x00,0x7E,0x4C,0x18,0x32,0x7E,0x00}, // z
{0x0E,0x18,0x18,0x70,0x18,0x18,0x0E,0x00}, // {
{0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x0C,0x00}, // |
{0x70,0x18,0x18,0x0E,0x18,0x18,0x70,0x00}, // }
{0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00}, // ~
{0x1C,0x36,0x36,0x1C,0x00,0x00,0x00,0x00} // DEL
};
const char FONT8x16[97][16] = {
{0x08,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space
{0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // !
{0x00,0x63,0x63,0x63,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // "
{0x00,0x00,0x00,0x36,0x36,0x7F,0x36,0x36,0x36,0x7F,0x36,0x36,0x00,0x00,0x00,0x00}, // #
{0x0C,0x0C,0x3E,0x63,0x61,0x60,0x3E,0x03,0x03,0x43,0x63,0x3E,0x0C,0x0C,0x00,0x00}, // $
{0x00,0x00,0x00,0x00,0x00,0x61,0x63,0x06,0x0C,0x18,0x33,0x63,0x00,0x00,0x00,0x00}, // %
{0x00,0x00,0x00,0x1C,0x36,0x36,0x1C,0x3B,0x6E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // &
{0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '
{0x00,0x00,0x0C,0x18,0x18,0x30,0x30,0x30,0x30,0x18,0x18,0x0C,0x00,0x00,0x00,0x00}, // (
{0x00,0x00,0x18,0x0C,0x0C,0x06,0x06,0x06,0x06,0x0C,0x0C,0x18,0x00,0x00,0x00,0x00}, // )
{0x00,0x00,0x00,0x00,0x42,0x66,0x3C,0xFF,0x3C,0x66,0x42,0x00,0x00,0x00,0x00,0x00}, // *
{0x00,0x00,0x00,0x00,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00}, // +
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00}, // ,
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // -
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // .
{0x00,0x00,0x01,0x03,0x07,0x0E,0x1C,0x38,0x70,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00}, // /
{0x00,0x00,0x3E,0x63,0x63,0x63,0x6B,0x6B,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 0
{0x00,0x00,0x0C,0x1C,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3F,0x00,0x00,0x00,0x00}, // 1
{0x00,0x00,0x3E,0x63,0x03,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00}, // 2
{0x00,0x00,0x3E,0x63,0x03,0x03,0x1E,0x03,0x03,0x03,0x63,0x3E,0x00,0x00,0x00,0x00}, // 3
{0x00,0x00,0x06,0x0E,0x1E,0x36,0x66,0x66,0x7F,0x06,0x06,0x0F,0x00,0x00,0x00,0x00}, // 4
{0x00,0x00,0x7F,0x60,0x60,0x60,0x7E,0x03,0x03,0x63,0x73,0x3E,0x00,0x00,0x00,0x00}, // 5
{0x00,0x00,0x1C,0x30,0x60,0x60,0x7E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 6
{0x00,0x00,0x7F,0x63,0x03,0x06,0x06,0x0C,0x0C,0x18,0x18,0x18,0x00,0x00,0x00,0x00}, // 7
{0x00,0x00,0x3E,0x63,0x63,0x63,0x3E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 8
{0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x3F,0x03,0x03,0x06,0x3C,0x00,0x00,0x00,0x00}, // 9
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // :
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00}, // ;
{0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00}, // <
{0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00}, // =
{0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00}, // >
{0x00,0x00,0x3E,0x63,0x63,0x06,0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00}, // ?
{0x00,0x00,0x3E,0x63,0x63,0x6F,0x6B,0x6B,0x6E,0x60,0x60,0x3E,0x00,0x00,0x00,0x00}, // @
{0x00,0x00,0x08,0x1C,0x36,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // A
{0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x33,0x33,0x33,0x33,0x7E,0x00,0x00,0x00,0x00}, // B
{0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x60,0x60,0x61,0x33,0x1E,0x00,0x00,0x00,0x00}, // C
{0x00,0x00,0x7C,0x36,0x33,0x33,0x33,0x33,0x33,0x33,0x36,0x7C,0x00,0x00,0x00,0x00}, // D
{0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00}, // E
{0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // F
{0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x6F,0x63,0x63,0x37,0x1D,0x00,0x00,0x00,0x00}, // G
{0x00,0x00,0x63,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // H
{0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // I
{0x00,0x00,0x0F,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00,0x00,0x00}, // J
{0x00,0x00,0x73,0x33,0x36,0x36,0x3C,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // K
{0x00,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00}, // L
{0x00,0x00,0x63,0x77,0x7F,0x6B,0x63,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // M
{0x00,0x00,0x63,0x63,0x73,0x7B,0x7F,0x6F,0x67,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // N
{0x00,0x00,0x1C,0x36,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x00,0x00,0x00,0x00}, // O
{0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // P
{0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x63,0x6B,0x6F,0x3E,0x06,0x07,0x00,0x00}, // Q
{0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // R
{0x00,0x00,0x3E,0x63,0x63,0x30,0x1C,0x06,0x03,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // S
{0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // T
{0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // U
{0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x08,0x00,0x00,0x00,0x00}, // V
{0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x36,0x00,0x00,0x00,0x00}, // W
{0x00,0x00,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x3C,0x66,0xC3,0xC3,0x00,0x00,0x00,0x00}, // X
{0x00,0x00,0xC3,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // Y
{0x00,0x00,0x7F,0x63,0x43,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00}, // Z
{0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00}, // [
{0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x07,0x03,0x01,0x00,0x00,0x00,0x00}, // backslash
{0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00}, // ]
{0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ^
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00}, // _
{0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // `
{0x00,0x00,0x00,0x00,0x00,0x3C,0x46,0x06,0x3E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // a
{0x00,0x00,0x70,0x30,0x30,0x3C,0x36,0x33,0x33,0x33,0x33,0x6E,0x00,0x00,0x00,0x00}, // b
{0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x60,0x60,0x60,0x63,0x3E,0x00,0x00,0x00,0x00}, // c
{0x00,0x00,0x0E,0x06,0x06,0x1E,0x36,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // d
{0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x7E,0x60,0x63,0x3E,0x00,0x00,0x00,0x00}, // e
{0x00,0x00,0x1C,0x36,0x32,0x30,0x7C,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // f
{0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00,0x00}, // g
{0x00,0x00,0x70,0x30,0x30,0x36,0x3B,0x33,0x33,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // h
{0x00,0x00,0x0C,0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00}, // i
{0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00}, // j
{0x00,0x00,0x70,0x30,0x30,0x33,0x33,0x36,0x3C,0x36,0x33,0x73,0x00,0x00,0x00,0x00}, // k
{0x00,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00}, // l
{0x00,0x00,0x00,0x00,0x00,0x6E,0x7F,0x6B,0x6B,0x6B,0x6B,0x6B,0x00,0x00,0x00,0x00}, // m
{0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x00}, // n
{0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // o
{0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x3E,0x30,0x30,0x78,0x00,0x00}, // p
{0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x06,0x0F,0x00,0x00}, // q
{0x00,0x00,0x00,0x00,0x00,0x6E,0x3B,0x33,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // r
{0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x38,0x0E,0x03,0x63,0x3E,0x00,0x00,0x00,0x00}, // s
{0x00,0x00,0x08,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x1B,0x0E,0x00,0x00,0x00,0x00}, // t
{0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // u
{0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x36,0x36,0x1C,0x1C,0x08,0x00,0x00,0x00,0x00}, // v
{0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x00,0x00,0x00,0x00}, // w
{0x00,0x00,0x00,0x00,0x00,0x63,0x36,0x1C,0x1C,0x1C,0x36,0x63,0x00,0x00,0x00,0x00}, // x
{0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x3F,0x03,0x06,0x3C,0x00,0x00}, // y
{0x00,0x00,0x00,0x00,0x00,0x7F,0x66,0x0C,0x18,0x30,0x63,0x7F,0x00,0x00,0x00,0x00}, // z
{0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00}, // {
{0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00}, // |
{0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00}, // }
{0x00,0x00,0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ~
{0x00,0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // DEL
};
*/

6
armsrc/fonts.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef __FONTS_H
#define __FONTS_H
extern const char FONT6x8[97][8];
extern const char FONT8x8F[97][8];
extern const char FONT8x16[97][16];
#endif

222
armsrc/fpga.c Normal file
View file

@ -0,0 +1,222 @@
//-----------------------------------------------------------------------------
// Routines to load the FPGA image, and then to configure the FPGA's major
// mode once it is configured.
//
// Jonathan Westhues, April 2006
//-----------------------------------------------------------------------------
#include <proxmark3.h>
#include "apps.h"
//-----------------------------------------------------------------------------
// Set up the Serial Peripheral Interface as master
// Used to write the FPGA config word
// May also be used to write to other SPI attached devices like an LCD
//-----------------------------------------------------------------------------
void SetupSpi(int mode)
{
// PA10 -> SPI_NCS2 chip select (LCD)
// PA11 -> SPI_NCS0 chip select (FPGA)
// PA12 -> SPI_MISO Master-In Slave-Out
// PA13 -> SPI_MOSI Master-Out Slave-In
// PA14 -> SPI_SPCK Serial Clock
// Disable PIO control of the following pins, allows use by the SPI peripheral
PIO_DISABLE = (1 << GPIO_NCS0) |
(1 << GPIO_NCS2) |
(1 << GPIO_MISO) |
(1 << GPIO_MOSI) |
(1 << GPIO_SPCK);
PIO_PERIPHERAL_A_SEL = (1 << GPIO_NCS0) |
(1 << GPIO_MISO) |
(1 << GPIO_MOSI) |
(1 << GPIO_SPCK);
PIO_PERIPHERAL_B_SEL = (1 << GPIO_NCS2);
//enable the SPI Peripheral clock
PMC_PERIPHERAL_CLK_ENABLE = (1<<PERIPH_SPI);
// Enable SPI
SPI_CONTROL = SPI_CONTROL_ENABLE;
switch (mode) {
case SPI_FPGA_MODE:
SPI_MODE =
( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods)
(14 << 16) | // Peripheral Chip Select (selects FPGA SPI_NCS0 or PA11)
( 0 << 7) | // Local Loopback Disabled
( 1 << 4) | // Mode Fault Detection disabled
( 0 << 2) | // Chip selects connected directly to peripheral
( 0 << 1) | // Fixed Peripheral Select
( 1 << 0); // Master Mode
SPI_FOR_CHIPSEL_0 =
( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods)
( 1 << 16) | // Delay Before SPCK (1 MCK period)
( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud
( 0 << 4) | // Bits per Transfer (8 bits)
( 0 << 3) | // Chip Select inactive after transfer
( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge
( 0 << 0); // Clock Polarity inactive state is logic 0
break;
case SPI_LCD_MODE:
SPI_MODE =
( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods)
(11 << 16) | // Peripheral Chip Select (selects LCD SPI_NCS2 or PA10)
( 0 << 7) | // Local Loopback Disabled
( 1 << 4) | // Mode Fault Detection disabled
( 0 << 2) | // Chip selects connected directly to peripheral
( 0 << 1) | // Fixed Peripheral Select
( 1 << 0); // Master Mode
SPI_FOR_CHIPSEL_2 =
( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods)
( 1 << 16) | // Delay Before SPCK (1 MCK period)
( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud
( 1 << 4) | // Bits per Transfer (9 bits)
( 0 << 3) | // Chip Select inactive after transfer
( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge
( 0 << 0); // Clock Polarity inactive state is logic 0
break;
default: // Disable SPI
SPI_CONTROL = SPI_CONTROL_DISABLE;
break;
}
}
//-----------------------------------------------------------------------------
// Set up the synchronous serial port, with the one set of options that we
// always use when we are talking to the FPGA. Both RX and TX are enabled.
//-----------------------------------------------------------------------------
void FpgaSetupSsc(void)
{
// First configure the GPIOs, and get ourselves a clock.
PIO_PERIPHERAL_A_SEL = (1 << GPIO_SSC_FRAME) |
(1 << GPIO_SSC_DIN) |
(1 << GPIO_SSC_DOUT) |
(1 << GPIO_SSC_CLK);
PIO_DISABLE = (1 << GPIO_SSC_DOUT);
PMC_PERIPHERAL_CLK_ENABLE = (1 << PERIPH_SSC);
// Now set up the SSC proper, starting from a known state.
SSC_CONTROL = SSC_CONTROL_RESET;
// RX clock comes from TX clock, RX starts when TX starts, data changes
// on RX clock rising edge, sampled on falling edge
SSC_RECEIVE_CLOCK_MODE = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1);
// 8 bits per transfer, no loopback, MSB first, 1 transfer per sync
// pulse, no output sync, start on positive-going edge of sync
SSC_RECEIVE_FRAME_MODE = SSC_FRAME_MODE_BITS_IN_WORD(8) |
SSC_FRAME_MODE_MSB_FIRST | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
// clock comes from TK pin, no clock output, outputs change on falling
// edge of TK, start on rising edge of TF
SSC_TRANSMIT_CLOCK_MODE = SSC_CLOCK_MODE_SELECT(2) |
SSC_CLOCK_MODE_START(5);
// tx framing is the same as the rx framing
SSC_TRANSMIT_FRAME_MODE = SSC_RECEIVE_FRAME_MODE;
SSC_CONTROL = SSC_CONTROL_RX_ENABLE | SSC_CONTROL_TX_ENABLE;
}
//-----------------------------------------------------------------------------
// Set up DMA to receive samples from the FPGA. We will use the PDC, with
// a single buffer as a circular buffer (so that we just chain back to
// ourselves, not to another buffer). The stuff to manipulate those buffers
// is in apps.h, because it should be inlined, for speed.
//-----------------------------------------------------------------------------
void FpgaSetupSscDma(BYTE *buf, int len)
{
PDC_RX_POINTER(SSC_BASE) = (DWORD)buf;
PDC_RX_COUNTER(SSC_BASE) = len;
PDC_RX_NEXT_POINTER(SSC_BASE) = (DWORD)buf;
PDC_RX_NEXT_COUNTER(SSC_BASE) = len;
PDC_CONTROL(SSC_BASE) = PDC_RX_ENABLE;
}
//-----------------------------------------------------------------------------
// Download the FPGA image stored in flash (slave serial).
//-----------------------------------------------------------------------------
void FpgaDownloadAndGo(void)
{
// FPGA image lives in FLASH at base address 0x2000
// The current board design can not accomodate anything bigger than a XC2S30
// FPGA and the config file size is fixed at 336,768 bits = 10,524 DWORDs
const DWORD *FpgaImage=((DWORD *)0x2000);
const DWORD FpgaImageLen=10524;
int i, j;
PIO_OUTPUT_ENABLE = (1 << GPIO_FPGA_ON);
PIO_ENABLE = (1 << GPIO_FPGA_ON);
PIO_OUTPUT_DATA_SET = (1 << GPIO_FPGA_ON);
SpinDelay(50);
LED_D_ON();
HIGH(GPIO_FPGA_NPROGRAM);
LOW(GPIO_FPGA_CCLK);
LOW(GPIO_FPGA_DIN);
PIO_OUTPUT_ENABLE = (1 << GPIO_FPGA_NPROGRAM) |
(1 << GPIO_FPGA_CCLK) |
(1 << GPIO_FPGA_DIN);
SpinDelay(1);
LOW(GPIO_FPGA_NPROGRAM);
SpinDelay(50);
HIGH(GPIO_FPGA_NPROGRAM);
for(i = 0; i < FpgaImageLen; i++) {
DWORD v = FpgaImage[i];
for(j = 0; j < 32; j++) {
if(v & 0x80000000) {
HIGH(GPIO_FPGA_DIN);
} else {
LOW(GPIO_FPGA_DIN);
}
HIGH(GPIO_FPGA_CCLK);
LOW(GPIO_FPGA_CCLK);
v <<= 1;
}
}
LED_D_OFF();
}
//-----------------------------------------------------------------------------
// Write the FPGA setup word (that determines what mode the logic is in, read
// vs. clone vs. etc.).
//-----------------------------------------------------------------------------
void FpgaWriteConfWord(BYTE v)
{
SetupSpi(SPI_FPGA_MODE);
while ((SPI_STATUS & SPI_STATUS_TX_EMPTY) == 0); // wait for the transfer to complete
SPI_TX_DATA = SPI_CONTROL_LAST_TRANSFER | v; // send the data
}
//-----------------------------------------------------------------------------
// Set up the CMOS switches that mux the ADC: four switches, independently
// closable, but should only close one at a time. Not an FPGA thing, but
// the samples from the ADC always flow through the FPGA.
//-----------------------------------------------------------------------------
void SetAdcMuxFor(int whichGpio)
{
PIO_OUTPUT_ENABLE = (1 << GPIO_MUXSEL_HIPKD) |
(1 << GPIO_MUXSEL_LOPKD) |
(1 << GPIO_MUXSEL_LORAW) |
(1 << GPIO_MUXSEL_HIRAW);
PIO_ENABLE = (1 << GPIO_MUXSEL_HIPKD) |
(1 << GPIO_MUXSEL_LOPKD) |
(1 << GPIO_MUXSEL_LORAW) |
(1 << GPIO_MUXSEL_HIRAW);
LOW(GPIO_MUXSEL_HIPKD);
LOW(GPIO_MUXSEL_HIRAW);
LOW(GPIO_MUXSEL_LORAW);
LOW(GPIO_MUXSEL_LOPKD);
HIGH(whichGpio);
}

0
armsrc/fpgaimg.c Normal file
View file

988
armsrc/iso14443.c Normal file
View file

@ -0,0 +1,988 @@
//-----------------------------------------------------------------------------
// Routines to support ISO 14443. This includes both the reader software and
// the `fake tag' modes. At the moment only the Type B modulation is
// supported.
// Jonathan Westhues, split Nov 2006
//-----------------------------------------------------------------------------
#include <proxmark3.h>
#include "apps.h"
#include "..\common\iso14443_crc.c"
//static void GetSamplesFor14443(BOOL weTx, int n);
#define DMA_BUFFER_SIZE 256
//=============================================================================
// An ISO 14443 Type B tag. We listen for commands from the reader, using
// a UART kind of thing that's implemented in software. When we get a
// frame (i.e., a group of bytes between SOF and EOF), we check the CRC.
// If it's good, then we can do something appropriate with it, and send
// a response.
//=============================================================================
//-----------------------------------------------------------------------------
// Code up a string of octets at layer 2 (including CRC, we don't generate
// that here) so that they can be transmitted to the reader. Doesn't transmit
// them yet, just leaves them ready to send in ToSend[].
//-----------------------------------------------------------------------------
static void CodeIso14443bAsTag(const BYTE *cmd, int len)
{
int i;
ToSendReset();
// Transmit a burst of ones, as the initial thing that lets the
// reader get phase sync. This (TR1) must be > 80/fs, per spec,
// but tag that I've tried (a Paypass) exceeds that by a fair bit,
// so I will too.
for(i = 0; i < 20; i++) {
ToSendStuffBit(1);
ToSendStuffBit(1);
ToSendStuffBit(1);
ToSendStuffBit(1);
}
// Send SOF.
for(i = 0; i < 10; i++) {
ToSendStuffBit(0);
ToSendStuffBit(0);
ToSendStuffBit(0);
ToSendStuffBit(0);
}
for(i = 0; i < 2; i++) {
ToSendStuffBit(1);
ToSendStuffBit(1);
ToSendStuffBit(1);
ToSendStuffBit(1);
}
for(i = 0; i < len; i++) {
int j;
BYTE b = cmd[i];
// Start bit
ToSendStuffBit(0);
ToSendStuffBit(0);
ToSendStuffBit(0);
ToSendStuffBit(0);
// Data bits
for(j = 0; j < 8; j++) {
if(b & 1) {
ToSendStuffBit(1);
ToSendStuffBit(1);
ToSendStuffBit(1);
ToSendStuffBit(1);
} else {
ToSendStuffBit(0);
ToSendStuffBit(0);
ToSendStuffBit(0);
ToSendStuffBit(0);
}
b >>= 1;
}
// Stop bit
ToSendStuffBit(1);
ToSendStuffBit(1);
ToSendStuffBit(1);
ToSendStuffBit(1);
}
// Send SOF.
for(i = 0; i < 10; i++) {
ToSendStuffBit(0);
ToSendStuffBit(0);
ToSendStuffBit(0);
ToSendStuffBit(0);
}
for(i = 0; i < 10; i++) {
ToSendStuffBit(1);
ToSendStuffBit(1);
ToSendStuffBit(1);
ToSendStuffBit(1);
}
// Convert from last byte pos to length
ToSendMax++;
// Add a few more for slop
ToSendMax += 2;
}
//-----------------------------------------------------------------------------
// The software UART that receives commands from the reader, and its state
// variables.
//-----------------------------------------------------------------------------
static struct {
enum {
STATE_UNSYNCD,
STATE_GOT_FALLING_EDGE_OF_SOF,
STATE_AWAITING_START_BIT,
STATE_RECEIVING_DATA,
STATE_ERROR_WAIT
} state;
WORD shiftReg;
int bitCnt;
int byteCnt;
int byteCntMax;
int posCnt;
BYTE *output;
} Uart;
static BOOL Handle14443UartBit(int bit)
{
switch(Uart.state) {
case STATE_UNSYNCD:
if(!bit) {
// we went low, so this could be the beginning
// of an SOF
Uart.state = STATE_GOT_FALLING_EDGE_OF_SOF;
Uart.posCnt = 0;
Uart.bitCnt = 0;
}
break;
case STATE_GOT_FALLING_EDGE_OF_SOF:
Uart.posCnt++;
if(Uart.posCnt == 2) {
if(bit) {
if(Uart.bitCnt >= 10) {
// we've seen enough consecutive
// zeros that it's a valid SOF
Uart.posCnt = 0;
Uart.byteCnt = 0;
Uart.state = STATE_AWAITING_START_BIT;
} else {
// didn't stay down long enough
// before going high, error
Uart.state = STATE_ERROR_WAIT;
}
} else {
// do nothing, keep waiting
}
Uart.bitCnt++;
}
if(Uart.posCnt >= 4) Uart.posCnt = 0;
if(Uart.bitCnt > 14) {
// Give up if we see too many zeros without
// a one, too.
Uart.state = STATE_ERROR_WAIT;
}
break;
case STATE_AWAITING_START_BIT:
Uart.posCnt++;
if(bit) {
if(Uart.posCnt > 25) {
// stayed high for too long between
// characters, error
Uart.state = STATE_ERROR_WAIT;
}
} else {
// falling edge, this starts the data byte
Uart.posCnt = 0;
Uart.bitCnt = 0;
Uart.shiftReg = 0;
Uart.state = STATE_RECEIVING_DATA;
}
break;
case STATE_RECEIVING_DATA:
Uart.posCnt++;
if(Uart.posCnt == 2) {
// time to sample a bit
Uart.shiftReg >>= 1;
if(bit) {
Uart.shiftReg |= 0x200;
}
Uart.bitCnt++;
}
if(Uart.posCnt >= 4) {
Uart.posCnt = 0;
}
if(Uart.bitCnt == 10) {
if((Uart.shiftReg & 0x200) && !(Uart.shiftReg & 0x001))
{
// this is a data byte, with correct
// start and stop bits
Uart.output[Uart.byteCnt] = (Uart.shiftReg >> 1) & 0xff;
Uart.byteCnt++;
if(Uart.byteCnt >= Uart.byteCntMax) {
// Buffer overflowed, give up
Uart.posCnt = 0;
Uart.state = STATE_ERROR_WAIT;
} else {
// so get the next byte now
Uart.posCnt = 0;
Uart.state = STATE_AWAITING_START_BIT;
}
} else if(Uart.shiftReg == 0x000) {
// this is an EOF byte
return TRUE;
} else {
// this is an error
Uart.posCnt = 0;
Uart.state = STATE_ERROR_WAIT;
}
}
break;
case STATE_ERROR_WAIT:
// We're all screwed up, so wait a little while
// for whatever went wrong to finish, and then
// start over.
Uart.posCnt++;
if(Uart.posCnt > 10) {
Uart.state = STATE_UNSYNCD;
}
break;
default:
Uart.state = STATE_UNSYNCD;
break;
}
return FALSE;
}
//-----------------------------------------------------------------------------
// Receive a command (from the reader to us, where we are the simulated tag),
// and store it in the given buffer, up to the given maximum length. Keeps
// spinning, waiting for a well-framed command, until either we get one
// (returns TRUE) or someone presses the pushbutton on the board (FALSE).
//
// Assume that we're called with the SSC (to the FPGA) and ADC path set
// correctly.
//-----------------------------------------------------------------------------
static BOOL GetIso14443CommandFromReader(BYTE *received, int *len, int maxLen)
{
BYTE mask;
int i, bit;
// Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen
// only, since we are receiving, not transmitting).
FpgaWriteConfWord(
FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION);
// Now run a `software UART' on the stream of incoming samples.
Uart.output = received;
Uart.byteCntMax = maxLen;
Uart.state = STATE_UNSYNCD;
for(;;) {
WDT_HIT();
if(BUTTON_PRESS()) return FALSE;
if(SSC_STATUS & (SSC_STATUS_TX_READY)) {
SSC_TRANSMIT_HOLDING = 0x00;
}
if(SSC_STATUS & (SSC_STATUS_RX_READY)) {
BYTE b = (BYTE)SSC_RECEIVE_HOLDING;
mask = 0x80;
for(i = 0; i < 8; i++, mask >>= 1) {
bit = (b & mask);
if(Handle14443UartBit(bit)) {
*len = Uart.byteCnt;
return TRUE;
}
}
}
}
}
//-----------------------------------------------------------------------------
// Main loop of simulated tag: receive commands from reader, decide what
// response to send, and send it.
//-----------------------------------------------------------------------------
void SimulateIso14443Tag(void)
{
static const BYTE cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };
static const BYTE response1[] = {
0x50, 0x82, 0x0d, 0xe1, 0x74, 0x20, 0x38, 0x19, 0x22,
0x00, 0x21, 0x85, 0x5e, 0xd7
};
BYTE *resp;
int respLen;
BYTE *resp1 = (((BYTE *)BigBuf) + 800);
int resp1Len;
BYTE *receivedCmd = (BYTE *)BigBuf;
int len;
int i;
int cmdsRecvd = 0;
memset(receivedCmd, 0x44, 400);
CodeIso14443bAsTag(response1, sizeof(response1));
memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax;
// We need to listen to the high-frequency, peak-detected path.
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc();
cmdsRecvd = 0;
for(;;) {
BYTE b1, b2;
if(!GetIso14443CommandFromReader(receivedCmd, &len, 100)) {
DbpIntegers(cmdsRecvd, 0, 0);
DbpString("button press");
break;
}
// Good, look at the command now.
if(len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len)==0) {
resp = resp1; respLen = resp1Len;
} else {
DbpString("new cmd from reader:");
DbpIntegers(len, 0x1234, cmdsRecvd);
// And print whether the CRC fails, just for good measure
ComputeCrc14443(CRC_14443_B, receivedCmd, len-2, &b1, &b2);
if(b1 != receivedCmd[len-2] || b2 != receivedCmd[len-1]) {
// Not so good, try again.
DbpString("+++CRC fail");
} else {
DbpString("CRC passes");
}
break;
}
memset(receivedCmd, 0x44, 32);
cmdsRecvd++;
if(cmdsRecvd > 0x30) {
DbpString("many commands later...");
break;
}
if(respLen <= 0) continue;
// Modulate BPSK
FpgaWriteConfWord(
FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK);
SSC_TRANSMIT_HOLDING = 0xff;
FpgaSetupSsc();
// Transmit the response.
i = 0;
for(;;) {
if(SSC_STATUS & (SSC_STATUS_TX_READY)) {
BYTE b = resp[i];
SSC_TRANSMIT_HOLDING = b;
i++;
if(i > respLen) {
break;
}
}
if(SSC_STATUS & (SSC_STATUS_RX_READY)) {
volatile BYTE b = (BYTE)SSC_RECEIVE_HOLDING;
(void)b;
}
}
}
}
//=============================================================================
// An ISO 14443 Type B reader. We take layer two commands, code them
// appropriately, and then send them to the tag. We then listen for the
// tag's response, which we leave in the buffer to be demodulated on the
// PC side.
//=============================================================================
static struct {
enum {
DEMOD_UNSYNCD,
DEMOD_PHASE_REF_TRAINING,
DEMOD_AWAITING_FALLING_EDGE_OF_SOF,
DEMOD_GOT_FALLING_EDGE_OF_SOF,
DEMOD_AWAITING_START_BIT,
DEMOD_RECEIVING_DATA,
DEMOD_ERROR_WAIT
} state;
int bitCount;
int posCount;
int thisBit;
int metric;
int metricN;
WORD shiftReg;
BYTE *output;
int len;
int sumI;
int sumQ;
} Demod;
static BOOL Handle14443SamplesDemod(int ci, int cq)
{
int v;
// The soft decision on the bit uses an estimate of just the
// quadrant of the reference angle, not the exact angle.
#define MAKE_SOFT_DECISION() { \
if(Demod.sumI > 0) { \
v = ci; \
} else { \
v = -ci; \
} \
if(Demod.sumQ > 0) { \
v += cq; \
} else { \
v -= cq; \
} \
}
switch(Demod.state) {
case DEMOD_UNSYNCD:
v = ci;
if(v < 0) v = -v;
if(cq > 0) {
v += cq;
} else {
v -= cq;
}
if(v > 40) {
Demod.posCount = 0;
Demod.state = DEMOD_PHASE_REF_TRAINING;
Demod.sumI = 0;
Demod.sumQ = 0;
}
break;
case DEMOD_PHASE_REF_TRAINING:
if(Demod.posCount < 8) {
Demod.sumI += ci;
Demod.sumQ += cq;
} else if(Demod.posCount > 100) {
// error, waited too long
Demod.state = DEMOD_UNSYNCD;
} else {
MAKE_SOFT_DECISION();
if(v < 0) {
Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF;
Demod.posCount = 0;
}
}
Demod.posCount++;
break;
case DEMOD_AWAITING_FALLING_EDGE_OF_SOF:
MAKE_SOFT_DECISION();
if(v < 0) {
Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF;
Demod.posCount = 0;
} else {
if(Demod.posCount > 100) {
Demod.state = DEMOD_UNSYNCD;
}
}
Demod.posCount++;
break;
case DEMOD_GOT_FALLING_EDGE_OF_SOF:
MAKE_SOFT_DECISION();
if(v > 0) {
if(Demod.posCount < 12) {
Demod.state = DEMOD_UNSYNCD;
} else {
Demod.state = DEMOD_AWAITING_START_BIT;
Demod.posCount = 0;
Demod.len = 0;
Demod.metricN = 0;
Demod.metric = 0;
}
} else {
if(Demod.posCount > 100) {
Demod.state = DEMOD_UNSYNCD;
}
}
Demod.posCount++;
break;
case DEMOD_AWAITING_START_BIT:
MAKE_SOFT_DECISION();
if(v > 0) {
if(Demod.posCount > 10) {
Demod.state = DEMOD_UNSYNCD;
}
} else {
Demod.bitCount = 0;
Demod.posCount = 1;
Demod.thisBit = v;
Demod.shiftReg = 0;
Demod.state = DEMOD_RECEIVING_DATA;
}
break;
case DEMOD_RECEIVING_DATA:
MAKE_SOFT_DECISION();
if(Demod.posCount == 0) {
Demod.thisBit = v;
Demod.posCount = 1;
} else {
Demod.thisBit += v;
if(Demod.thisBit > 0) {
Demod.metric += Demod.thisBit;
} else {
Demod.metric -= Demod.thisBit;
}
(Demod.metricN)++;
Demod.shiftReg >>= 1;
if(Demod.thisBit > 0) {
Demod.shiftReg |= 0x200;
}
Demod.bitCount++;
if(Demod.bitCount == 10) {
WORD s = Demod.shiftReg;
if((s & 0x200) && !(s & 0x001)) {
BYTE b = (s >> 1);
Demod.output[Demod.len] = b;
Demod.len++;
Demod.state = DEMOD_AWAITING_START_BIT;
} else if(s == 0x000) {
// This is EOF
return TRUE;
Demod.state = DEMOD_UNSYNCD;
} else {
Demod.state = DEMOD_UNSYNCD;
}
}
Demod.posCount = 0;
}
break;
default:
Demod.state = DEMOD_UNSYNCD;
break;
}
return FALSE;
}
static void GetSamplesFor14443Demod(BOOL weTx, int n)
{
int max = 0;
BOOL gotFrame = FALSE;
//# define DMA_BUFFER_SIZE 8
SBYTE *dmaBuf;
int lastRxCounter;
SBYTE *upTo;
int ci, cq;
int samples = 0;
// Clear out the state of the "UART" that receives from the tag.
memset(BigBuf, 0x44, 400);
Demod.output = (BYTE *)BigBuf;
Demod.len = 0;
Demod.state = DEMOD_UNSYNCD;
// And the UART that receives from the reader
Uart.output = (((BYTE *)BigBuf) + 1024);
Uart.byteCntMax = 100;
Uart.state = STATE_UNSYNCD;
// Setup for the DMA.
dmaBuf = (SBYTE *)(BigBuf + 32);
upTo = dmaBuf;
lastRxCounter = DMA_BUFFER_SIZE;
FpgaSetupSscDma((BYTE *)dmaBuf, DMA_BUFFER_SIZE);
// And put the FPGA in the appropriate mode
FpgaWriteConfWord(
FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |
(weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP));
for(;;) {
int behindBy = lastRxCounter - PDC_RX_COUNTER(SSC_BASE);
if(behindBy > max) max = behindBy;
LED_D_ON();
while(((lastRxCounter-PDC_RX_COUNTER(SSC_BASE)) & (DMA_BUFFER_SIZE-1))
> 2)
{
ci = upTo[0];
cq = upTo[1];
upTo += 2;
if(upTo - dmaBuf > DMA_BUFFER_SIZE) {
upTo -= DMA_BUFFER_SIZE;
PDC_RX_NEXT_POINTER(SSC_BASE) = (DWORD)upTo;
PDC_RX_NEXT_COUNTER(SSC_BASE) = DMA_BUFFER_SIZE;
}
lastRxCounter -= 2;
if(lastRxCounter <= 0) {
lastRxCounter += DMA_BUFFER_SIZE;
}
samples += 2;
Handle14443UartBit(1);
Handle14443UartBit(1);
if(Handle14443SamplesDemod(ci, cq)) {
gotFrame = 1;
}
}
LED_D_OFF();
if(samples > 2000) {
break;
}
}
PDC_CONTROL(SSC_BASE) = PDC_RX_DISABLE;
DbpIntegers(max, gotFrame, -1);
}
//-----------------------------------------------------------------------------
// Read the tag's response. We just receive a stream of slightly-processed
// samples from the FPGA, which we will later do some signal processing on,
// to get the bits.
//-----------------------------------------------------------------------------
/*static void GetSamplesFor14443(BOOL weTx, int n)
{
BYTE *dest = (BYTE *)BigBuf;
int c;
FpgaWriteConfWord(
FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |
(weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP));
c = 0;
for(;;) {
if(SSC_STATUS & (SSC_STATUS_TX_READY)) {
SSC_TRANSMIT_HOLDING = 0x43;
}
if(SSC_STATUS & (SSC_STATUS_RX_READY)) {
SBYTE b;
b = (SBYTE)SSC_RECEIVE_HOLDING;
dest[c++] = (BYTE)b;
if(c >= n) {
break;
}
}
}
}*/
//-----------------------------------------------------------------------------
// Transmit the command (to the tag) that was placed in ToSend[].
//-----------------------------------------------------------------------------
static void TransmitFor14443(void)
{
int c;
FpgaSetupSsc();
while(SSC_STATUS & (SSC_STATUS_TX_READY)) {
SSC_TRANSMIT_HOLDING = 0xff;
}
FpgaWriteConfWord(
FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);
for(c = 0; c < 10;) {
if(SSC_STATUS & (SSC_STATUS_TX_READY)) {
SSC_TRANSMIT_HOLDING = 0xff;
c++;
}
if(SSC_STATUS & (SSC_STATUS_RX_READY)) {
volatile DWORD r = SSC_RECEIVE_HOLDING;
(void)r;
}
WDT_HIT();
}
c = 0;
for(;;) {
if(SSC_STATUS & (SSC_STATUS_TX_READY)) {
SSC_TRANSMIT_HOLDING = ToSend[c];
c++;
if(c >= ToSendMax) {
break;
}
}
if(SSC_STATUS & (SSC_STATUS_RX_READY)) {
volatile DWORD r = SSC_RECEIVE_HOLDING;
(void)r;
}
WDT_HIT();
}
}
//-----------------------------------------------------------------------------
// Code a layer 2 command (string of octets, including CRC) into ToSend[],
// so that it is ready to transmit to the tag using TransmitFor14443().
//-----------------------------------------------------------------------------
void CodeIso14443bAsReader(const BYTE *cmd, int len)
{
int i, j;
BYTE b;
ToSendReset();
// Establish initial reference level
for(i = 0; i < 40; i++) {
ToSendStuffBit(1);
}
// Send SOF
for(i = 0; i < 10; i++) {
ToSendStuffBit(0);
}
for(i = 0; i < len; i++) {
// Stop bits/EGT
ToSendStuffBit(1);
ToSendStuffBit(1);
// Start bit
ToSendStuffBit(0);
// Data bits
b = cmd[i];
for(j = 0; j < 8; j++) {
if(b & 1) {
ToSendStuffBit(1);
} else {
ToSendStuffBit(0);
}
b >>= 1;
}
}
// Send EOF
ToSendStuffBit(1);
for(i = 0; i < 10; i++) {
ToSendStuffBit(0);
}
for(i = 0; i < 8; i++) {
ToSendStuffBit(1);
}
// And then a little more, to make sure that the last character makes
// it out before we switch to rx mode.
for(i = 0; i < 24; i++) {
ToSendStuffBit(1);
}
// Convert from last character reference to length
ToSendMax++;
}
//-----------------------------------------------------------------------------
// Read an ISO 14443 tag. We send it some set of commands, and record the
// responses.
//-----------------------------------------------------------------------------
void AcquireRawAdcSamplesIso14443(DWORD parameter)
{
// BYTE cmd1[] = { 0x05, 0x00, 0x00, 0x71, 0xff };
BYTE cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 };
// Make sure that we start from off, since the tags are stateful;
// confusing things will happen if we don't reset them between reads.
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(200);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc();
// Now give it time to spin up.
FpgaWriteConfWord(
FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);
SpinDelay(200);
CodeIso14443bAsReader(cmd1, sizeof(cmd1));
TransmitFor14443();
LED_A_ON();
GetSamplesFor14443Demod(TRUE, 2000);
LED_A_OFF();
}
//=============================================================================
// Finally, the `sniffer' combines elements from both the reader and
// simulated tag, to show both sides of the conversation.
//=============================================================================
//-----------------------------------------------------------------------------
// Record the sequence of commands sent by the reader to the tag, with
// triggering so that we start recording at the point that the tag is moved
// near the reader.
//-----------------------------------------------------------------------------
void SnoopIso14443(void)
{
// We won't start recording the frames that we acquire until we trigger;
// a good trigger condition to get started is probably when we see a
// response from the tag.
BOOL triggered = FALSE;
// The command (reader -> tag) that we're working on receiving.
BYTE *receivedCmd = (((BYTE *)BigBuf) + 1024);
// The response (tag -> reader) that we're working on receiving.
BYTE *receivedResponse = (((BYTE *)BigBuf) + 1536);
// As we receive stuff, we copy it from receivedCmd or receivedResponse
// into trace, along with its length and other annotations.
BYTE *trace = (BYTE *)BigBuf;
int traceLen = 0;
// The DMA buffer, used to stream samples from the FPGA.
//# define DMA_BUFFER_SIZE 256
SBYTE *dmaBuf = ((SBYTE *)BigBuf) + 2048;
int lastRxCounter;
SBYTE *upTo;
int ci, cq;
int maxBehindBy = 0;
// Count of samples received so far, so that we can include timing
// information in the trace buffer.
int samples = 0;
memset(trace, 0x44, 1000);
// Set up the demodulator for tag -> reader responses.
Demod.output = receivedResponse;
Demod.len = 0;
Demod.state = DEMOD_UNSYNCD;
// And the reader -> tag commands
memset(&Uart, 0, sizeof(Uart));
Uart.output = receivedCmd;
Uart.byteCntMax = 100;
Uart.state = STATE_UNSYNCD;
// And put the FPGA in the appropriate mode
FpgaWriteConfWord(
FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ |
FPGA_HF_READER_RX_XCORR_SNOOP);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Setup for the DMA.
FpgaSetupSsc();
upTo = dmaBuf;
lastRxCounter = DMA_BUFFER_SIZE;
FpgaSetupSscDma((BYTE *)dmaBuf, DMA_BUFFER_SIZE);
LED_A_ON();
// And now we loop, receiving samples.
for(;;) {
int behindBy = (lastRxCounter - PDC_RX_COUNTER(SSC_BASE)) &
(DMA_BUFFER_SIZE-1);
if(behindBy > maxBehindBy) {
maxBehindBy = behindBy;
if(behindBy > 100) {
DbpString("blew circular buffer!");
goto done;
}
}
if(behindBy < 2) continue;
ci = upTo[0];
cq = upTo[1];
upTo += 2;
lastRxCounter -= 2;
if(upTo - dmaBuf > DMA_BUFFER_SIZE) {
upTo -= DMA_BUFFER_SIZE;
lastRxCounter += DMA_BUFFER_SIZE;
PDC_RX_NEXT_POINTER(SSC_BASE) = (DWORD)upTo;
PDC_RX_NEXT_COUNTER(SSC_BASE) = DMA_BUFFER_SIZE;
}
samples += 2;
#define HANDLE_BIT_IF_BODY \
if(triggered) { \
trace[traceLen++] = ((samples >> 0) & 0xff); \
trace[traceLen++] = ((samples >> 8) & 0xff); \
trace[traceLen++] = ((samples >> 16) & 0xff); \
trace[traceLen++] = ((samples >> 24) & 0xff); \
trace[traceLen++] = 0; \
trace[traceLen++] = 0; \
trace[traceLen++] = 0; \
trace[traceLen++] = 0; \
trace[traceLen++] = Uart.byteCnt; \
memcpy(trace+traceLen, receivedCmd, Uart.byteCnt); \
traceLen += Uart.byteCnt; \
if(traceLen > 1000) break; \
} \
/* And ready to receive another command. */ \
memset(&Uart, 0, sizeof(Uart)); \
Uart.output = receivedCmd; \
Uart.byteCntMax = 100; \
Uart.state = STATE_UNSYNCD; \
/* And also reset the demod code, which might have been */ \
/* false-triggered by the commands from the reader. */ \
memset(&Demod, 0, sizeof(Demod)); \
Demod.output = receivedResponse; \
Demod.state = DEMOD_UNSYNCD; \
if(Handle14443UartBit(ci & 1)) {
HANDLE_BIT_IF_BODY
}
if(Handle14443UartBit(cq & 1)) {
HANDLE_BIT_IF_BODY
}
if(Handle14443SamplesDemod(ci, cq)) {
// timestamp, as a count of samples
trace[traceLen++] = ((samples >> 0) & 0xff);
trace[traceLen++] = ((samples >> 8) & 0xff);
trace[traceLen++] = ((samples >> 16) & 0xff);
trace[traceLen++] = 0x80 | ((samples >> 24) & 0xff);
// correlation metric (~signal strength estimate)
if(Demod.metricN != 0) {
Demod.metric /= Demod.metricN;
}
trace[traceLen++] = ((Demod.metric >> 0) & 0xff);
trace[traceLen++] = ((Demod.metric >> 8) & 0xff);
trace[traceLen++] = ((Demod.metric >> 16) & 0xff);
trace[traceLen++] = ((Demod.metric >> 24) & 0xff);
// length
trace[traceLen++] = Demod.len;
memcpy(trace+traceLen, receivedResponse, Demod.len);
traceLen += Demod.len;
if(traceLen > 1000) break;
triggered = TRUE;
LED_A_OFF();
LED_B_ON();
// And ready to receive another response.
memset(&Demod, 0, sizeof(Demod));
Demod.output = receivedResponse;
Demod.state = DEMOD_UNSYNCD;
}
if(BUTTON_PRESS()) {
DbpString("cancelled");
goto done;
}
}
DbpString("in done pt");
DbpIntegers(maxBehindBy, Uart.state, Uart.byteCnt);
DbpIntegers(Uart.byteCntMax, traceLen, 0x23);
done:
PDC_CONTROL(SSC_BASE) = PDC_RX_DISABLE;
LED_A_OFF();
LED_B_OFF();
}

1815
armsrc/iso14443a.c Normal file

File diff suppressed because it is too large Load diff

1226
armsrc/iso15693.c Normal file

File diff suppressed because it is too large Load diff

11
armsrc/ldscript Normal file
View file

@ -0,0 +1,11 @@
SECTIONS
{
. = 0x00010000;
.text : { obj/start.o(.text) *(.text) }
.rodata : { *(.rodata) }
. = 0x00200000;
.data : { *(.data) }
__bss_start__ = .;
.bss : { *(.bss) }
__bss_end__ = .;
}

11
armsrc/ldscript-fpga Normal file
View file

@ -0,0 +1,11 @@
SECTIONS
{
. = 0x00002000;
.text : { obj/fpgaimg.o(.text) *(.text) }
.rodata : { *(.rodata) }
. = 0x00200000;
.data : { *(.data) }
__bss_start__ = .;
.bss : { *(.bss) }
__bss_end__ = .;
}

12
armsrc/start.c Normal file
View file

@ -0,0 +1,12 @@
//-----------------------------------------------------------------------------
// Just vector to AppMain(). This is in its own file so that I can place it
// with the linker script.
// Jonathan Westhues, Mar 2006
//-----------------------------------------------------------------------------
#include <proxmark3.h>
#include "apps.h"
void Vector(void)
{
AppMain();
}

53
armsrc/util.c Normal file
View file

@ -0,0 +1,53 @@
//-----------------------------------------------------------------------------
// Utility functions used in many places, not specific to any piece of code.
// Jonathan Westhues, Sept 2005
//-----------------------------------------------------------------------------
#include <proxmark3.h>
#include "apps.h"
void *memcpy(void *dest, const void *src, int len)
{
BYTE *d = dest;
const BYTE *s = src;
while((len--) > 0) {
*d = *s;
d++;
s++;
}
return dest;
}
void *memset(void *dest, int c, int len)
{
BYTE *d = dest;
while((len--) > 0) {
*d = c;
d++;
}
return dest;
}
int memcmp(const void *av, const void *bv, int len)
{
const BYTE *a = av;
const BYTE *b = bv;
while((len--) > 0) {
if(*a != *b) {
return *a - *b;
}
a++;
b++;
}
return 0;
}
int strlen(char *str)
{
int l = 0;
while(*str) {
l++;
str++;
}
return l;
}

58
bootrom/Makefile Normal file
View file

@ -0,0 +1,58 @@
CC = arm-elf-gcc
AS = arm-elf-as
LD = arm-elf-ld
OBJCOPY = arm-elf-objcopy
OBJDIR = obj
INCLUDE = -I../include
INCLUDES = ../include/proxmark3.h ../include/at91sam7s128.h ../include/config_gpio.h ../include/usb_cmd.h
CFLAGS = -g -c $(INCLUDE) -Wall
OBJJTAG = $(OBJDIR)/bootrom.o $(OBJDIR)/ram-reset.o $(OBJDIR)/usb.o
OBJFLASH = $(OBJDIR)/flash-reset.o $(OBJDIR)/fromflash.o
all: bootrom.s19
bootrom.s19: $(OBJDIR)/bootrom.s19 $(OBJDIR)/bootrom-forjtag.s19
@echo bootrom.s19
@perl ..\tools\merge-srec.pl $(OBJDIR)\bootrom.s19 $(OBJDIR)\bootrom-forjtag.s19 > $(OBJDIR)\bootrom-merged.s19
@perl ..\tools\srecswap.pl $(OBJDIR)\bootrom-forjtag.s19 > $(OBJDIR)\bootrom-forjtag-swapped.s19
$(OBJDIR)/bootrom.s19: $(OBJFLASH)
@echo obj/bootrom.s19
@$(LD) -g -Tldscript-flash --oformat elf32-littlearm -o $(OBJDIR)/bootrom.elf $(OBJFLASH)
@$(OBJCOPY) -Osrec --srec-forceS3 $(OBJDIR)/bootrom.elf $(OBJDIR)/bootrom.s19
$(OBJDIR)/bootrom-forjtag.s19: $(OBJJTAG)
@echo obj/bootrom-forjtag.s19
@$(LD) -g -Tldscript-ram-jtag --oformat elf32-littlearm -o $(OBJDIR)/bootrom-forjtag.elf $(OBJJTAG)
@$(OBJCOPY) -Osrec --srec-forceS3 $(OBJDIR)/bootrom-forjtag.elf $(OBJDIR)/bootrom-forjtag.s19
$(OBJDIR)/bootrom.o: bootrom.c $(INCLUDES)
@echo $(@B).c
@$(CC) $(CFLAGS) -mthumb -mthumb-interwork bootrom.c -o $(OBJDIR)/bootrom.o
$(OBJDIR)/fromflash.o: fromflash.c $(INCLUDES)
@echo $(@B).c
@$(CC) $(CFLAGS) -mthumb -mthumb-interwork fromflash.c -o $(OBJDIR)/fromflash.o
$(OBJDIR)/usb.o: ../common/usb.c $(INCLUDES)
@echo $(@B).c
@$(CC) $(CFLAGS) -mthumb -mthumb-interwork ../common/usb.c -o $(OBJDIR)/usb.o
$(OBJDIR)/ram-reset.o: ram-reset.s
@echo $(@B).s
@$(CC) $(CFLAGS) -mthumb-interwork -o $(OBJDIR)/ram-reset.o ram-reset.s
$(OBJDIR)/flash-reset.o: flash-reset.s
@echo $(@B).s
@$(CC) $(CFLAGS) -mthumb-interwork -o $(OBJDIR)/flash-reset.o flash-reset.s
clean:
del /q obj\*.o
del /q obj\*.elf
del /q obj\*.s19

190
bootrom/bootrom.c Normal file
View file

@ -0,0 +1,190 @@
#include <proxmark3.h>
static void ConfigClocks(void)
{
// we are using a 16 MHz crystal as the basis for everything
// slow clock runs at 32Khz typical regardless of crystal
// enable system clock and USB clock
PMC_SYS_CLK_ENABLE = PMC_SYS_CLK_PROCESSOR_CLK | PMC_SYS_CLK_UDP_CLK;
// enable the clock to the following peripherals
PMC_PERIPHERAL_CLK_ENABLE =
(1<<PERIPH_PIOA) |
(1<<PERIPH_ADC) |
(1<<PERIPH_SPI) |
(1<<PERIPH_SSC) |
(1<<PERIPH_PWMC) |
(1<<PERIPH_UDP);
// worst case scenario, with 16Mhz xtal startup delay is 14.5ms
// with a slow clock running at it worst case (max) frequency of 42khz
// max startup delay = (14.5ms*42k)/8 = 76 = 0x4C round up to 0x50
// enable main oscillator and set startup delay
PMC_MAIN_OSCILLATOR = PMC_MAIN_OSCILLATOR_ENABLE |
PMC_MAIN_OSCILLATOR_STARTUP_DELAY(0x50);
// wait for main oscillator to stabilize
while ( !(PMC_INTERRUPT_STATUS & PMC_MAIN_OSCILLATOR_STABILIZED) )
;
// minimum PLL clock frequency is 80 MHz in range 00 (96 here so okay)
// frequency is crystal * multiplier / divisor = 16Mhz * 12 / 2 = 96Mhz
PMC_PLL = PMC_PLL_DIVISOR(2) | PMC_PLL_COUNT_BEFORE_LOCK(0x50) |
PMC_PLL_FREQUENCY_RANGE(0) | PMC_PLL_MULTIPLIER(12) |
PMC_PLL_USB_DIVISOR(1);
// wait for PLL to lock
while ( !(PMC_INTERRUPT_STATUS & PMC_MAIN_OSCILLATOR_PLL_LOCK) )
;
// we want a master clock (MCK) to be PLL clock / 2 = 96Mhz / 2 = 48Mhz
// as per datasheet, this register must be programmed in two operations
// when changing to PLL, program the prescaler first then the source
PMC_MASTER_CLK = PMC_CLK_PRESCALE_DIV_2;
// wait for main clock ready signal
while ( !(PMC_INTERRUPT_STATUS & PMC_MAIN_OSCILLATOR_MCK_READY) )
;
// set the source to PLL
PMC_MASTER_CLK = PMC_CLK_SELECTION_PLL_CLOCK | PMC_CLK_PRESCALE_DIV_2;
// wait for main clock ready signal
while ( !(PMC_INTERRUPT_STATUS & PMC_MAIN_OSCILLATOR_MCK_READY) )
;
}
static void Fatal(void)
{
for(;;);
}
void UsbPacketReceived(BYTE *packet, int len)
{
int i;
UsbCommand *c = (UsbCommand *)packet;
volatile DWORD *p;
if(len != sizeof(*c)) {
Fatal();
}
switch(c->cmd) {
case CMD_DEVICE_INFO:
break;
case CMD_SETUP_WRITE:
p = (volatile DWORD *)0;
for(i = 0; i < 12; i++) {
p[i+c->ext1] = c->d.asDwords[i];
}
break;
case CMD_FINISH_WRITE:
p = (volatile DWORD *)0;
for(i = 0; i < 4; i++) {
p[i+60] = c->d.asDwords[i];
}
MC_FLASH_COMMAND = MC_FLASH_COMMAND_KEY |
MC_FLASH_COMMAND_PAGEN(c->ext1/FLASH_PAGE_SIZE_BYTES) |
FCMD_WRITE_PAGE;
while(!(MC_FLASH_STATUS & MC_FLASH_STATUS_READY))
;
break;
case CMD_HARDWARE_RESET:
break;
default:
Fatal();
break;
}
c->cmd = CMD_ACK;
UsbSendPacket(packet, len);
}
void BootROM(void)
{
//------------
// First set up all the I/O pins; GPIOs configured directly, other ones
// just need to be assigned to the appropriate peripheral.
// Kill all the pullups, especially the one on USB D+; leave them for
// the unused pins, though.
PIO_NO_PULL_UP_ENABLE = (1 << GPIO_USB_PU) |
(1 << GPIO_LED_A) |
(1 << GPIO_LED_B) |
(1 << GPIO_LED_C) |
(1 << GPIO_LED_D) |
(1 << GPIO_FPGA_DIN) |
(1 << GPIO_FPGA_DOUT) |
(1 << GPIO_FPGA_CCLK) |
(1 << GPIO_FPGA_NINIT) |
(1 << GPIO_FPGA_NPROGRAM) |
(1 << GPIO_FPGA_DONE) |
(1 << GPIO_MUXSEL_HIPKD) |
(1 << GPIO_MUXSEL_HIRAW) |
(1 << GPIO_MUXSEL_LOPKD) |
(1 << GPIO_MUXSEL_LORAW) |
(1 << GPIO_RELAY) |
(1 << GPIO_NVDD_ON);
// (and add GPIO_FPGA_ON)
// These pins are outputs
PIO_OUTPUT_ENABLE = (1 << GPIO_LED_A) |
(1 << GPIO_LED_B) |
(1 << GPIO_LED_C) |
(1 << GPIO_LED_D) |
(1 << GPIO_RELAY) |
(1 << GPIO_NVDD_ON);
// PIO controls the following pins
PIO_ENABLE = (1 << GPIO_USB_PU) |
(1 << GPIO_LED_A) |
(1 << GPIO_LED_B) |
(1 << GPIO_LED_C) |
(1 << GPIO_LED_D);
USB_D_PLUS_PULLUP_OFF();
LED_D_OFF();
LED_C_ON();
LED_B_OFF();
LED_A_OFF();
// if 512K FLASH part - TODO make some defines :)
if ((DBGU_CIDR | 0xf00) == 0xa00) {
MC_FLASH_MODE0 = MC_FLASH_MODE_FLASH_WAIT_STATES(1) |
MC_FLASH_MODE_MASTER_CLK_IN_MHZ(0x48);
MC_FLASH_MODE1 = MC_FLASH_MODE_FLASH_WAIT_STATES(1) |
MC_FLASH_MODE_MASTER_CLK_IN_MHZ(0x48);
} else {
MC_FLASH_MODE0 = MC_FLASH_MODE_FLASH_WAIT_STATES(0) |
MC_FLASH_MODE_MASTER_CLK_IN_MHZ(48);
}
// Initialize all system clocks
ConfigClocks();
LED_A_ON();
if(BUTTON_PRESS()) {
UsbStart();
}
for(;;) {
WDT_HIT();
UsbPoll(TRUE);
if(!BUTTON_PRESS()) {
USB_D_PLUS_PULLUP_OFF();
LED_B_ON();
// jump to RAM address 0x10000 (LSBit set for thumb mode)
asm("ldr r3, = 0x10001\n");
asm("bx r3\n");
}
}
}

38
bootrom/flash-reset.s Normal file
View file

@ -0,0 +1,38 @@
.extern CopyBootToRAM
.text
.code 32
.align 0
.global start
start:
b Reset
b UndefinedInstruction
b SoftwareInterrupt
b PrefetchAbort
b DataAbort
b Reserved
b Irq
b Fiq
Reset:
ldr sp, = 0x0020FFF8 @ initialize stack pointer to top of RAM
bl CopyBootToRAM @ copy bootloader to RAM (in case the
@ user re-flashes the bootloader)
ldr r3, = 0x00200000 @ start address of RAM bootloader
bx r3 @ jump to it
Fiq:
b Fiq
UndefinedInstruction:
b UndefinedInstruction
SoftwareInterrupt:
b SoftwareInterrupt
PrefetchAbort:
b PrefetchAbort
DataAbort:
b DataAbort
Reserved:
b Reserved
Irq:
b Irq

11
bootrom/fromflash.c Normal file
View file

@ -0,0 +1,11 @@
#include <proxmark3.h>
void CopyBootToRAM(void)
{
int i;
volatile DWORD *s = (volatile DWORD *)0x200;
volatile DWORD *d = (volatile DWORD *)0x200000;
for(i = 0; i < 1024; i++) *d++ = *s++;
}

11
bootrom/ldscript-flash Normal file
View file

@ -0,0 +1,11 @@
SECTIONS
{
. = 0x00000000;
.text : { obj/flash-reset.o(.text) *(.text) }
.rodata : { *(.rodata) }
. = 0x00200000;
.data : { *(.data) }
__bss_start__ = .;
.bss : { *(.bss) }
__bss_end__ = .;
}

10
bootrom/ldscript-ram-jtag Normal file
View file

@ -0,0 +1,10 @@
SECTIONS
{
. = 0x00200000;
.text : { obj/ram-reset.o(.text) *(.text) }
.rodata : { *(.rodata) }
.data : { *(.data) }
__bss_start__ = .;
.bss : { *(.bss) }
__bss_end__ = .;
}

10
bootrom/ram-reset.s Normal file
View file

@ -0,0 +1,10 @@
.extern BootROM
.text
.code 32
.align 0
.global start
start:
ldr sp, = 0x0020FFF8
bl BootROM

5
cockpit/0setpath.bat Normal file
View file

@ -0,0 +1,5 @@
@echo off
set PATH=..\..\devkitARM\bin;..\..\devkitWIN\bin;%PATH%
set INCLUDE=..\..\devkitWIN\include
set LIB=..\..\devkitWIN\lib
cmd.exe

5
cockpit/1makearm.bat Normal file
View file

@ -0,0 +1,5 @@
@echo off
cd ..\armsrc
rem nmake clean
nmake
cd ..\cockpit

5
cockpit/2makeboot.bat Normal file
View file

@ -0,0 +1,5 @@
@echo off
cd ..\bootrom
rem nmake clean
nmake
cd ..\cockpit

5
cockpit/3makewin.bat Normal file
View file

@ -0,0 +1,5 @@
@echo off
cd ..\winsrc
rem nmake clean
nmake
cd ..\cockpit

3
cockpit/4flashos.bat Normal file
View file

@ -0,0 +1,3 @@
@echo off
..\winsrc\prox.exe load ..\armsrc\obj\osimage.s19
..\winsrc\prox.exe load ..\armsrc\obj\osimage.s19

3
cockpit/5makeall.bat Normal file
View file

@ -0,0 +1,3 @@
call 1makearm.bat
call 2makeboot.bat
call 3makewin.bat

3
cockpit/prox.bat Normal file
View file

@ -0,0 +1,3 @@
@echo off
cd ..\winsrc
call prox gui

35
common/iso14443_crc.c Normal file
View file

@ -0,0 +1,35 @@
//-----------------------------------------------------------------------------
// Routines to compute the CRCs (two different flavours, just for confusion)
// required for ISO 14443, swiped directly from the spec.
//-----------------------------------------------------------------------------
#define CRC_14443_A 0x6363 /* ITU-V.41 */
#define CRC_14443_B 0xFFFF /* ISO/IEC 13239 (formerly ISO/IEC 3309) */
static unsigned short UpdateCrc14443(unsigned char ch, unsigned short *lpwCrc)
{
ch = (ch ^ (unsigned char) ((*lpwCrc) & 0x00FF));
ch = (ch ^ (ch << 4));
*lpwCrc = (*lpwCrc >> 8) ^ ((unsigned short) ch << 8) ^
((unsigned short) ch << 3) ^ ((unsigned short) ch >> 4);
return (*lpwCrc);
}
static void ComputeCrc14443(int CrcType, BYTE *Data, int Length,
BYTE *TransmitFirst, BYTE *TransmitSecond)
{
unsigned char chBlock;
unsigned short wCrc=CrcType;
do {
chBlock = *Data++;
UpdateCrc14443(chBlock, &wCrc);
} while (--Length);
if (CrcType == CRC_14443_B)
wCrc = ~wCrc; /* ISO/IEC 13239 (formerly ISO/IEC 3309) */
*TransmitFirst = (BYTE) (wCrc & 0xFF);
*TransmitSecond = (BYTE) ((wCrc >> 8) & 0xFF);
return;
}

472
common/usb.c Normal file
View file

@ -0,0 +1,472 @@
//-----------------------------------------------------------------------------
// My USB driver. This has to be common, because it exists in both the
// bootrom and the application.
// Jonathan Westhues, split Aug 14 2005
//-----------------------------------------------------------------------------
#include <proxmark3.h>
#define min(a, b) (((a) > (b)) ? (b) : (a))
#define USB_REPORT_PACKET_SIZE 64
typedef struct PACKED {
BYTE bmRequestType;
BYTE bRequest;
WORD wValue;
WORD wIndex;
WORD wLength;
} UsbSetupData;
#define USB_REQUEST_GET_STATUS 0
#define USB_REQUEST_CLEAR_FEATURE 1
#define USB_REQUEST_SET_FEATURE 3
#define USB_REQUEST_SET_ADDRESS 5
#define USB_REQUEST_GET_DESCRIPTOR 6
#define USB_REQUEST_SET_DESCRIPTOR 7
#define USB_REQUEST_GET_CONFIGURATION 8
#define USB_REQUEST_SET_CONFIGURATION 9
#define USB_REQUEST_GET_INTERFACE 10
#define USB_REQUEST_SET_INTERFACE 11
#define USB_REQUEST_SYNC_FRAME 12
#define USB_DESCRIPTOR_TYPE_DEVICE 1
#define USB_DESCRIPTOR_TYPE_CONFIGURATION 2
#define USB_DESCRIPTOR_TYPE_STRING 3
#define USB_DESCRIPTOR_TYPE_INTERFACE 4
#define USB_DESCRIPTOR_TYPE_ENDPOINT 5
#define USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER 6
#define USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONF 7
#define USB_DESCRIPTOR_TYPE_INTERFACE_POWER 8
#define USB_DESCRIPTOR_TYPE_HID 0x21
#define USB_DESCRIPTOR_TYPE_HID_REPORT 0x22
#define USB_DEVICE_CLASS_HID 0x03
static const BYTE HidReportDescriptor[] = {
0x06,0xA0,0xFF, // Usage Page (vendor defined) FFA0
0x09,0x01, // Usage (vendor defined)
0xA1,0x01, // Collection (Application)
0x09,0x02, // Usage (vendor defined)
0xA1,0x00, // Collection (Physical)
0x06,0xA1,0xFF, // Usage Page (vendor defined)
//The,input report
0x09,0x03, // usage - vendor defined
0x09,0x04, // usage - vendor defined
0x15,0x80, // Logical Minimum (-128)
0x25,0x7F, // Logical Maximum (127)
0x35,0x00, // Physical Minimum (0)
0x45,0xFF, // Physical Maximum (255)
0x75,0x08, // Report Size (8) (bits)
0x95,0x40, // Report Count (64) (fields)
0x81,0x02, // Input (Data,Variable,Absolute)
//The,output report
0x09,0x05, // usage - vendor defined
0x09,0x06, // usage - vendor defined
0x15,0x80, // Logical Minimum (-128)
0x25,0x7F, // Logical Maximum (127)
0x35,0x00, // Physical Minimum (0)
0x45,0xFF, // Physical Maximum (255)
0x75,0x08, // Report Size (8) (bits)
0x95,0x40, // Report Count (64) (fields)
0x91,0x02, // Output (Data,Variable,Absolute)
0xC0, // End Collection
0xC0, // End Collection
};
static const BYTE DeviceDescriptor[] = {
0x12, // Descriptor length (18 bytes)
0x01, // Descriptor type (Device)
0x10,0x01, // Complies with USB Spec. Release (0110h = release 1.10)
0x00, // Class code (0)
0x00, // Subclass code (0)
0x00, // Protocol (No specific protocol)
0x08, // Maximum packet size for Endpoint 0 (8 bytes)
0xc4,0x9a, // Vendor ID (random numbers)
0x8f,0x4b, // Product ID (random numbers)
0x01,0x00, // Device release number (0001)
0x01, // Manufacturer string descriptor index
0x02, // Product string descriptor index
0x00, // Serial Number string descriptor index (None)
0x01, // Number of possible configurations (1)
};
static const BYTE ConfigurationDescriptor[] = {
0x09, // Descriptor length (9 bytes)
0x02, // Descriptor type (Configuration)
0x29,0x00, // Total data length (41 bytes)
0x01, // Interface supported (1)
0x01, // Configuration value (1)
0x00, // Index of string descriptor (None)
0x80, // Configuration (Bus powered)
250, // Maximum power consumption (500mA)
//interface
0x09, // Descriptor length (9 bytes)
0x04, // Descriptor type (Interface)
0x00, // Number of interface (0)
0x00, // Alternate setting (0)
0x02, // Number of interface endpoint (2)
0x03, // Class code (HID)
0x00, // Subclass code ()
0x00, // Protocol code ()
0x00, // Index of string()
// class
0x09, // Descriptor length (9 bytes)
0x21, // Descriptor type (HID)
0x00,0x01, // HID class release number (1.00)
0x00, // Localized country code (None)
0x01, // # of HID class dscrptr to follow (1)
0x22, // Report descriptor type (HID)
// Total length of report descriptor
sizeof(HidReportDescriptor),0x00,
// endpoint 1
0x07, // Descriptor length (7 bytes)
0x05, // Descriptor type (Endpoint)
0x01, // Encoded address (Respond to OUT)
0x03, // Endpoint attribute (Interrupt transfer)
0x08,0x00, // Maximum packet size (8 bytes)
0x01, // Polling interval (1 ms)
// endpoint 2
0x07, // Descriptor length (7 bytes)
0x05, // Descriptor type (Endpoint)
0x82, // Encoded address (Respond to IN)
0x03, // Endpoint attribute (Interrupt transfer)
0x08,0x00, // Maximum packet size (8 bytes)
0x01, // Polling interval (1 ms)
};
static const BYTE StringDescriptor0[] = {
0x04, // Length
0x03, // Type is string
0x09, // English
0x04, // US
};
static const BYTE StringDescriptor1[] = {
24, // Length
0x03, // Type is string
'J', 0x00,
'.', 0x00,
' ', 0x00,
'W', 0x00,
'e', 0x00,
's', 0x00,
't', 0x00,
'h', 0x00,
'u', 0x00,
'e', 0x00,
's', 0x00,
};
static const BYTE StringDescriptor2[] = {
54, // Length
0x03, // Type is string
'P', 0x00,
'r', 0x00,
'o', 0x00,
'x', 0x00,
'M', 0x00,
'a', 0x00,
'r', 0x00,
'k', 0x00,
'-', 0x00,
'3', 0x00,
' ', 0x00,
'R', 0x00,
'F', 0x00,
'I', 0x00,
'D', 0x00,
' ', 0x00,
'I', 0x00,
'n', 0x00,
's', 0x00,
't', 0x00,
'r', 0x00,
'u', 0x00,
'm', 0x00,
'e', 0x00,
'n', 0x00,
't', 0x00,
};
static const BYTE * const StringDescriptors[] = {
StringDescriptor0,
StringDescriptor1,
StringDescriptor2,
};
static BYTE UsbBuffer[64];
static int UsbSoFarCount;
static BYTE CurrentConfiguration;
static void UsbSendEp0(const BYTE *data, int len)
{
int thisTime, i;
do {
thisTime = min(len, 8);
len -= thisTime;
for(i = 0; i < thisTime; i++) {
UDP_ENDPOINT_FIFO(0) = *data;
data++;
}
if(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED) {
UDP_ENDPOINT_CSR(0) &= ~UDP_CSR_TX_PACKET_ACKED;
while(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED)
;
}
UDP_ENDPOINT_CSR(0) |= UDP_CSR_TX_PACKET;
do {
if(UDP_ENDPOINT_CSR(0) & UDP_CSR_RX_PACKET_RECEIVED_BANK_0) {
// This means that the host is trying to write to us, so
// abandon our write to them.
UDP_ENDPOINT_CSR(0) &= ~UDP_CSR_RX_PACKET_RECEIVED_BANK_0;
return;
}
} while(!(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED));
} while(len > 0);
if(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED) {
UDP_ENDPOINT_CSR(0) &= ~UDP_CSR_TX_PACKET_ACKED;
while(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED)
;
}
}
static void UsbSendZeroLength(void)
{
UDP_ENDPOINT_CSR(0) |= UDP_CSR_TX_PACKET;
while(!(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED))
;
UDP_ENDPOINT_CSR(0) &= ~UDP_CSR_TX_PACKET_ACKED;
while(UDP_ENDPOINT_CSR(0) & UDP_CSR_TX_PACKET_ACKED)
;
}
static void HandleRxdSetupData(void)
{
int i;
UsbSetupData usd;
for(i = 0; i < sizeof(usd); i++) {
((BYTE *)&usd)[i] = UDP_ENDPOINT_FIFO(0);
}
if(usd.bmRequestType & 0x80) {
UDP_ENDPOINT_CSR(0) |= UDP_CSR_CONTROL_DATA_DIR;
while(!(UDP_ENDPOINT_CSR(0) & UDP_CSR_CONTROL_DATA_DIR))
;
}
UDP_ENDPOINT_CSR(0) &= ~UDP_CSR_RX_HAVE_READ_SETUP_DATA;
while(UDP_ENDPOINT_CSR(0) & UDP_CSR_RX_HAVE_READ_SETUP_DATA)
;
switch(usd.bRequest) {
case USB_REQUEST_GET_DESCRIPTOR:
if((usd.wValue >> 8) == USB_DESCRIPTOR_TYPE_DEVICE) {
UsbSendEp0((BYTE *)&DeviceDescriptor,
min(sizeof(DeviceDescriptor), usd.wLength));
} else if((usd.wValue >> 8) == USB_DESCRIPTOR_TYPE_CONFIGURATION) {
UsbSendEp0((BYTE *)&ConfigurationDescriptor,
min(sizeof(ConfigurationDescriptor), usd.wLength));
} else if((usd.wValue >> 8) == USB_DESCRIPTOR_TYPE_STRING) {
const BYTE *s = StringDescriptors[usd.wValue & 0xff];
UsbSendEp0(s, min(s[0], usd.wLength));
} else if((usd.wValue >> 8) == USB_DESCRIPTOR_TYPE_HID_REPORT) {
UsbSendEp0((BYTE *)&HidReportDescriptor,
min(sizeof(HidReportDescriptor), usd.wLength));
} else {
*((DWORD *)0x00200000) = usd.wValue;
}
break;
case USB_REQUEST_SET_ADDRESS:
UsbSendZeroLength();
UDP_FUNCTION_ADDR = UDP_FUNCTION_ADDR_ENABLED | usd.wValue ;
if(usd.wValue != 0) {
UDP_GLOBAL_STATE = UDP_GLOBAL_STATE_ADDRESSED;
} else {
UDP_GLOBAL_STATE = 0;
}
break;
case USB_REQUEST_GET_CONFIGURATION:
UsbSendEp0(&CurrentConfiguration, sizeof(CurrentConfiguration));
break;
case USB_REQUEST_GET_STATUS: {
if(usd.bmRequestType & 0x80) {
WORD w = 0;
UsbSendEp0((BYTE *)&w, sizeof(w));
}
break;
}
case USB_REQUEST_SET_CONFIGURATION:
CurrentConfiguration = usd.wValue;
if(CurrentConfiguration) {
UDP_GLOBAL_STATE = UDP_GLOBAL_STATE_CONFIGURED;
UDP_ENDPOINT_CSR(1) = UDP_CSR_ENABLE_EP |
UDP_CSR_EPTYPE_INTERRUPT_OUT;
UDP_ENDPOINT_CSR(2) = UDP_CSR_ENABLE_EP |
UDP_CSR_EPTYPE_INTERRUPT_IN;
} else {
UDP_GLOBAL_STATE = UDP_GLOBAL_STATE_ADDRESSED;
UDP_ENDPOINT_CSR(1) = 0;
UDP_ENDPOINT_CSR(2) = 0;
}
UsbSendZeroLength();
break;
case USB_REQUEST_GET_INTERFACE: {
BYTE b = 0;
UsbSendEp0(&b, sizeof(b));
break;
}
case USB_REQUEST_SET_INTERFACE:
UsbSendZeroLength();
break;
case USB_REQUEST_CLEAR_FEATURE:
case USB_REQUEST_SET_FEATURE:
case USB_REQUEST_SET_DESCRIPTOR:
case USB_REQUEST_SYNC_FRAME:
default:
break;
}
}
void UsbSendPacket(BYTE *packet, int len)
{
int i, thisTime;
while(len > 0) {
thisTime = min(len, 8);
for(i = 0; i < thisTime; i++) {
UDP_ENDPOINT_FIFO(2) = packet[i];
}
UDP_ENDPOINT_CSR(2) |= UDP_CSR_TX_PACKET;
while(!(UDP_ENDPOINT_CSR(2) & UDP_CSR_TX_PACKET_ACKED))
;
UDP_ENDPOINT_CSR(2) &= ~UDP_CSR_TX_PACKET_ACKED;
while(UDP_ENDPOINT_CSR(2) & UDP_CSR_TX_PACKET_ACKED)
;
len -= thisTime;
packet += thisTime;
}
}
static void HandleRxdData(void)
{
int i, len;
if(UDP_ENDPOINT_CSR(1) & UDP_CSR_RX_PACKET_RECEIVED_BANK_0) {
len = UDP_CSR_BYTES_RECEIVED(UDP_ENDPOINT_CSR(1));
for(i = 0; i < len; i++) {
UsbBuffer[UsbSoFarCount] = UDP_ENDPOINT_FIFO(1);
UsbSoFarCount++;
}
UDP_ENDPOINT_CSR(1) &= ~UDP_CSR_RX_PACKET_RECEIVED_BANK_0;
while(UDP_ENDPOINT_CSR(1) & UDP_CSR_RX_PACKET_RECEIVED_BANK_0)
;
if(UsbSoFarCount >= 64) {
UsbPacketReceived(UsbBuffer, UsbSoFarCount);
UsbSoFarCount = 0;
}
}
if(UDP_ENDPOINT_CSR(1) & UDP_CSR_RX_PACKET_RECEIVED_BANK_1) {
len = UDP_CSR_BYTES_RECEIVED(UDP_ENDPOINT_CSR(1));
for(i = 0; i < len; i++) {
UsbBuffer[UsbSoFarCount] = UDP_ENDPOINT_FIFO(1);
UsbSoFarCount++;
}
UDP_ENDPOINT_CSR(1) &= ~UDP_CSR_RX_PACKET_RECEIVED_BANK_1;
while(UDP_ENDPOINT_CSR(1) & UDP_CSR_RX_PACKET_RECEIVED_BANK_1)
;
if(UsbSoFarCount >= 64) {
UsbPacketReceived(UsbBuffer, UsbSoFarCount);
UsbSoFarCount = 0;
}
}
}
void UsbStart(void)
{
volatile int i;
UsbSoFarCount = 0;
USB_D_PLUS_PULLUP_OFF();
for(i = 0; i < 1000000; i++)
;
USB_D_PLUS_PULLUP_ON();
if(UDP_INTERRUPT_STATUS & UDP_INTERRUPT_END_OF_BUS_RESET) {
UDP_INTERRUPT_CLEAR = UDP_INTERRUPT_END_OF_BUS_RESET;
}
}
BOOL UsbPoll(BOOL blinkLeds)
{
BOOL ret = FALSE;
if(UDP_INTERRUPT_STATUS & UDP_INTERRUPT_END_OF_BUS_RESET) {
UDP_INTERRUPT_CLEAR = UDP_INTERRUPT_END_OF_BUS_RESET;
// following a reset we should be ready to receive a setup packet
UDP_RESET_ENDPOINT = 0xf;
UDP_RESET_ENDPOINT = 0;
UDP_FUNCTION_ADDR = UDP_FUNCTION_ADDR_ENABLED;
UDP_ENDPOINT_CSR(0) = UDP_CSR_EPTYPE_CONTROL | UDP_CSR_ENABLE_EP;
CurrentConfiguration = 0;
ret = TRUE;
}
if(UDP_INTERRUPT_STATUS & UDP_INTERRUPT_ENDPOINT(0)) {
if(UDP_ENDPOINT_CSR(0) & UDP_CSR_RX_HAVE_READ_SETUP_DATA) {
HandleRxdSetupData();
ret = TRUE;
}
}
if(UDP_INTERRUPT_STATUS & UDP_INTERRUPT_ENDPOINT(1)) {
HandleRxdData();
ret = TRUE;
}
return ret;
}

155
doc/CHANGES.TXT Normal file
View file

@ -0,0 +1,155 @@
################
## 2009/03/28 ##
################
winsrc/command.cpp
Added two new LF commands for tag exploration :
- askdemod: takes 2 arguments, one is the clock rate, one is the modulation
convention (high mod is 1 or high mod is zero)
This command demodulates the stream into a binary stream into
the trace buffer (0's and 1's)
- mandemod: manchester decoding of a bitstream: takes a binary stream from
the trace buffer (see askdemod) and attempts to do manchester decoding
to it. One argument: clock rate. Outputs the bitstream to the scrollback buffer.
Those two helped me to validate that the unknown tag I had was indeed an EM4100 type of tag
################
## 2008/12/11 ##
################
bootrom/bootrom.c
Significant changes to bootloader. Use of Chip ID register to detect if running on a SAM7S512 then configure FLASH
waitstates as per SummoningDark's suggestion for a SAM7S512 or SAM7S256.
Deleted idle loops waiting blindly for clocks to settle and now using status registers to detect when clocks are stable.
*************************
* IMPORTANT INFORMATION *
**************************************************************************************************************************
* With this boot code, the device can now only be flashed if button is held down after power on or a software reset.
* The flash procedure is this:
* Hold down button. Either plug in USB or software reset it. _While_holding_down_button_ (red and yellow LEDs are lit) you can
* issue one or more of the "prox bootrom <file>" "prox fpga <file>" "prox load <file>", be sure to hold button down for the
* entire duration of the flash process. Only release the button when flashing is complete and you want to let the board boot.
* This process may be less convenient but it's safer and avoids "unintentional" flashing of the board.
**************************************************************************************************************************
LED boot sequence now changed, C (red) lights up when boot code jumps from flash to RAM boot code, A (yellow) lights up after
clocks have been initialized, B (green) lights up when jumping from boot code to main code, then D (red led away from the others)
lights up while code is being downloaded to FPGA, then all leds turn off and board is ready for action.
With these changes the board now boots and is ready to use in about 3 seconds. Also since the USB bus is not initialized
twice (once during boot, then again when the main code runs) unless the button is held down at boot, this seems to avoid
the double USB connect and "USB device not recognized" when device is connected to the USB bus or software reset.
################
## 2008/12/06 ##
################
armsrc/fpga.c
Implemented function SetupSpi() to initialize the Serial Peripheral Interface (SPI) in preparation to adding an LCD to the board.
Changed FpgaWriteConfWord() to use the SPI communication now instead of bit banging the serial data to the FPGA.
fpga/fpga.v
The FPGA config word serializer required non standard SPI communication (ie for shifting in a 8 bit word, it required a 9th clock
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
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
not require additional clocking.
armsrc/fpgaimg.c
Recompiled FPGA code after changes above.
armsrc/LCD.c
LCD driver for PCF8833 based LCDs like those found on Nokia models 2600,2650,3100,3120,5140,6030,6100,6610,7210,7250 maybe
others. These color LCDs have a resolution of 132x132 and a serial interface. They are very cheap like even down to $2/pc
This LCD driver is a straight rip of that found at http://www.sparkfun.com/datasheets/LCD/Jimbo-Nokia-SAM7-Example.zip with
very small changes, mainly to integrate it and make it compile with our codebase. Also comented out the circle subroutines
to keep the code to integer math only.
armsrc/fonts.c
Font definition for LCD driver
armsrc/appmain.c
Fixed a small bug in CmdHIDdemodFSK (added case 4) which prevented reading some tags. When a logic 0 is immediately followed
by the start of the next transmisson (special pattern) a pattern of 4 bit duration lengths is created.
################
## 2008/11/27 ##
################
armsrc/appmain.c
Implemented an HID tag FSK demodulator (CmdHIDdemodFSK) to obtain the tag ID code from the raw sampled waveform.
Implemented CmdHIDsimTAG which takes a 44bit HID tag ID as a hex number then creates the waveform and simulates the tag
winsrc/command.cpp
Added command "hidfskdemod" that calls CmdHIDdemodFSK, the ARM FSK demodulator for HID tags.
include/usb-cmd.h
New defines CMD_HID_DEMOD_FSK and CMD_HID_SIM_TAG
2008/11/25
common/iso14443_crc.c
Moved CRC calculation code into this file as it's common to both ARM and Windows side. This file is now included as needed.
################
## 2008/11/21 ##
################
armsrc/Makefile
Changes to split up the compilation of the ARM and produce separate S files for the FPGA code and the ARM code.
armsrc/appmain.c
Replaced some of the hex value params in FpgaWriteConfWord with more explanatory defines.
Changes to the Tune command as it assumes wrong HF capacitor value (130pF) and produces wrong voltage readings.
Combined some of the integer arithmetic statements to improve accuracy slightly, since the voltage divider ratio is not an integer.
Voltage divider resistor network is 10M/240k = ratio of 41.6666
Originally the calculation was rounding the ratio down to 41
3300 (mV) * 41 * sample_value / 1024
New calculation without rounding error is
3300 (mV) * 41.66666 * sample_value / 1024 => 137500 * sample_value / 1024
New define BUTTON_PRESS() returns status of button
armsrc/fpga.c
The current board can only take a X2S30 as there is no larger FPGA in PQFP100 package and
the smaller X2S15 FPGA can't fit the current code. The X2S30 FPGA config is fixed at 336,768 bits
The FPGA code base address and length is hard coded to occupy FLASH region 0x2000 - 0xC470.
armsrc/ldscript-fpga
New file to place the FPGA code at FLASH address 0x2000
bootrom/Makefile
Slight changes, commented out the generation of byteswapped S file, the other S files are generated in the same section of the makefile now.
bootrom/bootrom.c
Changed some thumb code with a one line ARM code which is clearer and more explicit. Processor runs in ARM mode at reset anyway.
Changed jump to RAM address, used to jump to 0x2000 (now FPGA area), now jumps to 0x10000.
bootrom/flash-reset.s
Changed name of CMain to CopyBootToRAM. Streamlined reset code, fixed up stack pointer initialization.
bootrom/fromflash.c
Removed the whole section of initializing clocks, this is redundant as it's being done once we jump to boot code in RAM
All fromflash.c does now is copy the boot code to ram and jumps to it.
bootrom/ram-reset.s
Fixed up stack pointer initialization that caused crash when using "loread"
include/at91sam7s128.h
New defines for debug register, lets you identify what processor flavour the code runs on, RAM and FLASH sizes, etc.
include/proxmark3.h
New useful defines for relay and button
winsrc/Makefile
Added new define /D_CRT_SECURE_NO_WARNINGS to elliminate a _whole bunch_ of bogus compilation warnings
winsrc/command.cpp
Changed CmdLosamples to take a numeric argument (number of samples x4 to retrieve from buffer)
New command Quit to exit the program from the GUI command prompt.
winsrc/gui.cpp
Fixup compilation warnings.
winsrc/prox.cpp
Tidy up printing to stdout, flashing progress now updates on the same line instead of scrolling up.
New command line parameter to load FPGA image to FLASH.

39
doc/README.TXT Normal file
View file

@ -0,0 +1,39 @@
This is a bare minimum compile environment for the proxmark3 sources.
CONTENTS
This bundle contains the ARM cross compiler in devkitARM and a _tiny_ subset
of the Visual C++ 2008 Express Edition in devkitWIN which is the bare minimum
required for compilation of this current source.
If you plan on further source code development you are strongly encouraged
to download the full Visual C++ 2008 available for free download from
http://www.microsoft.com/express/download/
CAVEATS
There is no provision in this environment for compiling the FPGA source. To
do that you need to download the free (registration required) ISE WebPack
from Xilinx at http://www.xilinx.com/ise/logic_design_prod/webpack.htm
Be warned, the pack is huge, 2Gb download and >4Gb installed.
USAGE
First of all run the .msi file in devkitWIN\vcredist_x86 to install the VC++
redistributables, without these, nmake, cl and link won't run.
Get a command prompts in the cockpit directory and pretty much run the batch
files in the order they appear:
0setpath.bat - sets the environment vars for the compile environment
1makearm.bat - compiles the files in armsrc, output files in armsrc\obj
2makeboot.bat - compiles the files in bootrom, output files in bootrom\obj
3makewin.bat - compiles the files in winsrc, output files in winsrc\obj
4flashos.bat - attempts to upload the OS image to the proxmark3 board
ACKNOWLEDGMENTS
Thanks to J Westhues for the original proxmark, Roel and the proxmark.org
community. This pack may contain F/OSS or free but copyrighted software
from Xilinx, Microsoft and others. All trademarks are the property of
their respective owners. All rights reserved.

BIN
doc/component-placement.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

BIN
doc/proxmark3.pdf Normal file

Binary file not shown.

BIN
doc/proxmark3.xls Normal file

Binary file not shown.

BIN
doc/schematics.pdf Normal file

Binary file not shown.

276
doc/system.txt Normal file
View file

@ -0,0 +1,276 @@
This is outdated.
---
INTRODUCTION TO THE proxmark3
=============================
The proxmark3 device is designed to manipulate RFID tags in a number of
different ways. For example, a proxmark3 can:
* read a low-frequency (~100 kHz) or high-frequency (13.56 MHz) tag,
including the ISO-standard tags; standards that require
bidirectional communication between the reader and the tag are
not a problem
* emulate a low- or high-frequency tag, in a way very similar to the
way that a real tag behaves (e.g., it derives its timing from the
incident carrier)
* eavesdrop on the signals exchanged between another reader and tag
* measure the resonant frequency of an antenna, to a certain extent
(this is a convenience when building a test setup for the previous
three functions)
The proxmark3 may be thought of as a direct-sampling software radio.
There is some complication, though, because of the usual dynamic range
issue in dealing with signals in RFID systems (large signal due to
the reader, small signal due to the tag). Some analog processing is
therefore used to fix this before the signal is digitized. (Although,
it is possible to digitize the signal from the antenna directly, with
appropriate population options. It is just not usually a good idea.)
SYSTEM ARCHITECTURE
===================
The ANTENNA sends and receives signals over the air. It is external to
the board; it connects through SV2. Separate pins on the connector are
used for the low- and high-frequency antennas, and the analog receive
paths are separate. The antennas are inductive loops, which are resonated
by on-board capacitors.
On the transmit side, the antennas are excited by large numbers of
paralleled bus driver buffers. By tri-stating some of the buffers, it
is possible to vary the transmit strength. This may be used to generate
a modulated carrier. The buffers are driven by signals from the FPGA,
as are the output enables. The antennas are excited as series circuits,
which permits a large input power for a relatively small input voltage.
By driving all of the buffers low, it is possible to make the antenna
look to the receive path like a parallel LC circuit; this provides a
high-voltage output signal. This is typically what will be done when we
are not actively transmitting a carrier (i.e., behaving as a reader).
On the receive side, there are two possibilities, which are selected by
RLY1. A mechanical relay is used, because the signal from the antenna is
likely to be more positive or negative than the highest or lowest supply
voltages on-board. In the usual case (PEAK-DETECTED mode), the received
signal is peak-detected by an analog circuit, then filtered slightly,
and then digitized by the ADC. This is the case for both the low- and
high-frequency paths, although the details of the circuits for the
two cases are somewhat different. This receive path would typically
be selected when the device is behaving as a reader, or when it is
eavesdropping at close range.
It is also possible to digitize the signal from the antenna directly (RAW
mode), after passing it through a gain stage. This is more likely to be
useful in reading signals at long range, but the available dynamic range
will be poor, since it is limited by the 8-bit A/D. These modes would be
very appropriate, for example, for the heavily-discussed attacks in which
a tag's ID is learned from the data broadcast by a reader performing an
anticollision loop, because there is no dynamic range problem there. It
would also be possible to program the proxmark3 to receive broadcast AM
radio, with certain changes in component values.
In either case, an analog signal is digitized by the ADC (IC8), and
from there goes in to the FPGA (IC1). The FPGA is big enough that it
can perform DSP operations itself. For some high-frequency standards,
the subcarriers are fast enough that it would be inconvenient to do all
the math on a general-purpose CPU. The FPGA can therefore correlate for
the desired signal itself, and simply report the total to the ARM. For
low-frequency tags, it probably makes sense just to pass data straight
through to the ARM.
The FPGA communicates with the ARM through either its SPI port (the ARM
is the master) or its generic synchronous serial port (again, the ARM
is the master). The ARM connects to the outside world over USB.
DETAILS: POWER DISTRIBUTION
===========================
I make a half-hearted attempt to meet the USB power specs; this adds a
bit of complexity. I have not made measurements to determine how close
I come to succeeding, but I think that the suspend current might turn
out to be a pain.
The +3V3 rail is always powered, whenever we are plugged in to USB. This
is generated by an LDO, which burns a quiescent current of 150 uA
(typical) already. The only thing powered from the +3V3 rail is the ARM,
which can presumably do smart power control when we are in suspend.
The ARM generates two signals to switch power to the rest of the board:
FPGA_ON, and NVDD_ON. When NVDD_ON goes low, the Vdd rail comes up to
about five volts (the filtered-but-unregulated USB voltage). This powers
most of the analog circuitry, including the ADC and all of the opamps
and comparators in the receive path, and the coil drivers as well. Vdd
also feeds the +3V3-FPGA and +2v5 regulators, which power only the
FPGA. These regulators are enabled by FPGA_ON, so the FPGA is powered
only when NVDD_ON is asserted low, and FPGA_ON is asserted high.
DETAILS: FPGA
=============
The FPGA is a Spartan-II. This is a little bit old, but it is widely
available, inexpensive, and five-volt tolerant. For development, the FPGA
is configured over JTAG (SV5). In operation, the FPGA is configured in
slave serial mode by the ARM, from a bitstream stored in the ARM's flash.
Power to the FPGA is managed by regulators IC13 and IC12, both of which
have shutdown. These generate the FPGA's VCCO (+3v3) and VCCINT (+2v5)
supplies. I am a little bit worried about the power-on surge, since we
run off USB. At the very minimum, the FPGA should not get power until
we have enumerated and requested the full 500 mA available from USB. The
large electrolytic capacitors C37 and C38 will presumably help with this.
The logic is written in Verilog, of course for webpack. I have structured
the FPGA in terms of `major modes:' the FPGA's `major mode' determines
which of several modules is connected to the FPGA's I/O pins. A separate
module is used for each of the FPGA's function; for example, there is
now a module to read a 125 kHz tag, simulate a 125 kHz tag, transmit to
an ISO 15693 tag, and receive from an ISO 15693 tag.
DETAILS: ANALOG RECEIVE PATH
============================
For `slow' signals, I use an MCP6294 opamp. This has a GBW of 10 MHz,
which is more than enough for the low-frequency stuff, and enough for
all of the subcarrier frequencies that I know of at high frequency. In
practice, the `slow' signals are all the signals following the peak
detector. These signals are usually centred around the generated
voltage Vmid.
For `fast' signals, I use an AD8052. This is a very fast voltage-feedback
amplifier (~100 MHz GBW). I use it immediately after the antenna for
both the low- and high-frequency cases, as a sort of an ugly LNA. It is
not optimal, but it certainly made the design easy.
An ordinary CD4066 is used to multiplex the four possible signals
(low/high frequency paths, RAW/PEAK-DETECTED). There is a potential
problem at startup, when the ARM is in reset; there are pull-ups on the
lines that control the mux, so all of the switches turn on. This shorts
the four opamp outputs together through the on-resistance of the switch.
All four outputs float to the same DC voltage with no signal, however,
and the on-resistance of the switches is fairly large, so I don't think
that will be a problem in practice.
Comparators are used to generate clock signals when the device is
emulating a tag. These clock signals are generated from the signal on the
antenna, and therefore from the signal transmitted by the reader. This
allows us to clock ourselves off the reader, just like a real tag would.
These signals go in to the FPGA. There is a potential problem when the
FPGA is powered down; these outputs might go high and try to power the
FPGA through the protection diodes. My present solution to this is a
couple of resistors, which is not very elegeant.
The high-frequency peak-detected receive path contains population options
for many features that I do not currently use. A lot of these are just
me guessing that if I provide options for different series and shunt
passives, perhaps it will come in handy in some way. The Zener diodes D10
and D11 are optional, but may protect the front end from an overvoltage
(which will fry the peak detector diodes) when the `simulated tag'
is read by a powerful reader.
DETAILS: ANALOG TRANSMIT PATH
=============================
The coil drivers are just ACT244 bus buffers. I parallel eight of them
for each antenna (eight for the high-frequency antenna, eight for the
low-frequency antenna). This should easily provide a hundred milliamps
coil drive or so, which is more than enough for anything that I imagine
doing with the device. The drivers hit the coil with a square wave
voltage, however, which means that it is only the bandpass filter effect
of a resonant antenna that suppresses the odd harmonics. In practice it
would probably take heroic efforts (high antenna Q) to meet the FCC/CE
harmonic specs; and in practice no one cares.
The tx strength, given good antenna tuning, is determined by the series
resistors. Choose the ratios to stay within the rated current of the
buffers, and to achieve the desired power ratios by enabling or disabling
nOEs for the desired modulation index. It is useful to populate one of the
resistors as a high value (~10k) for the simulated tag modes; this allows
us to look at the incident carrier without loading the reader very much.
DETAILS: ARM
============
Atmel makes a number of pin-compatible ARMs, with slightly different
peripherals, and different amounts of flash and RAM. It is necessary
to choose a device with enough flash not just for the ARM's program,
but also for the FPGA image (which is loaded by the ARM).
The ARM is responsible for programming the FPGA. It also supplies a
clock to the FPGA (although the FPGA clock can also run off the 13.56
MHz clock not used for anything else, which is obviously asynchronous
to anything in the ARM).
It is necessary to use JTAG to bring the ARM for the first time; at
that point you can load a bootrom, and subsequently load new software
over USB. It might be possible to use the ARM's pre-loaded bootloader
(see datasheet) instead of JTAG, but I wanted the JTAG anyways for
debugging, so I did not bother. I used a Wiggler clone, with Macraigor's
OCD Commander. More expensive tools would work as well.
USB SOFTWARE
============
At present I enumerate as an HID device. This saves me writing a driver,
but it forces me to do interrupt transfers for everything. This limits
speed and is not very elegant. A real USB driver would be nice, maybe
even one that could do stuff like going isochronous to stream samples
from the A/D for processing on the PC.
PRETENDING TO BE A TAG
======================
It is not possible, with the given topology, to open-circuit the antenna
entirely and still look at the signal received on it. The simulated tag
modes must therefore switch between slight loading and heavy loading,
not open- and short-circuts across the antenna, evening though they do
not depend upon the incident carrier for power (just timing information).
RECEIVING SIGNAL STRAIGHT FROM THE ANTENNAS
===========================================
There is a path straight from the antenna to the A/D, bypassing the peak
detector assembly. This goes through a gain stage (just a fast voltage
feedback opamp), and from there straight in to the mux.
It is necessary to energize the relay to connect these paths. If the
coil is driven (as if to excite and read a tag) while these paths are
connected, then damage will probably result. Most likely the opamp
will fry.
READING A TAG
=============
The tag is excited by a carrier transmitted by the reader. This is
generated by IC9 and IC10, using some combination of buffers. The transmit
power is determined by selecting the right combination of PWR_OEx pins;
drive more of them low for more power. This can be used to modulate the
transmitted signal, and thus send information to the tag.
The received signal from the antenna is first peak-detected, and then
high-pass filtered to reject the unmodulated carrier. The signal is
amplified a bit, and goes in to the A/D mux from there. The A/D is
controlled by the FPGA. For 13.56 MHz tags, it is easiest to do everything
synchronous to the 13.56 MHz carrier.
INTERFACE FROM THE ARM TO THE FPGA
==================================
The FPGA and the ARM can communicate in two main ways: using the ARM's
general-purpose synchronous serial port (the SSP), or using the ARM's
SPI port. The SPI port is used to configure the FPGA. The ARM writes a
configuration word to the FPGA, which determines what operation will
be performed (e.g. read 13.56 MHz vs. read 125 kHz vs. read 134 kHz
vs...). The SPI is used exclusively for configuration.
The SSP is used for actual data sent over the air. The ARM's SSP can
work in slave mode, which means that we can send the data using clocks
generated by the FPGA (either from the PCK0 clock, which the ARM itself
supplies, or from the 13.56 MHz clock, which is certainly not going to
be synchronous to anything in the ARM), which saves synchronizing logic
in the FPGA. The SSP is bi-directional and full-duplex.

239
fpga/fpga.mpf Normal file
View file

@ -0,0 +1,239 @@
;
; Copyright Model Technology, a Mentor Graphics
; Corporation company 2003, - All rights reserved.
;
[Library]
std = $MODEL_TECH/../std
ieee = $MODEL_TECH/../ieee
verilog = $MODEL_TECH/../verilog
vital2000 = $MODEL_TECH/../vital2000
std_developerskit = $MODEL_TECH/../std_developerskit
synopsys = $MODEL_TECH/../synopsys
modelsim_lib = $MODEL_TECH/../modelsim_lib
; VHDL Section
unisim = $MODEL_TECH/../xilinx/vhdl/unisim
simprim = $MODEL_TECH/../xilinx/vhdl/simprim
xilinxcorelib = $MODEL_TECH/../xilinx/vhdl/xilinxcorelib
aim = $MODEL_TECH/../xilinx/vhdl/aim
pls = $MODEL_TECH/../xilinx/vhdl/pls
cpld = $MODEL_TECH/../xilinx/vhdl/cpld
; Verilog Section
unisims_ver = $MODEL_TECH/../xilinx/verilog/unisims_ver
uni9000_ver = $MODEL_TECH/../xilinx/verilog/uni9000_ver
simprims_ver = $MODEL_TECH/../xilinx/verilog/simprims_ver
xilinxcorelib_ver = $MODEL_TECH/../xilinx/verilog/xilinxcorelib_ver
aim_ver = $MODEL_TECH/../xilinx/verilog/aim_ver
cpld_ver = $MODEL_TECH/../xilinx/verilog/cpld_ver
work = work
[vcom]
; Turn on VHDL-1993 as the default. Normally is off.
VHDL93 = 1
; Show source line containing error. Default is off.
; Show_source = 1
; Turn off unbound-component warnings. Default is on.
; Show_Warning1 = 0
; Turn off process-without-a-wait-statement warnings. Default is on.
; Show_Warning2 = 0
; Turn off null-range warnings. Default is on.
; Show_Warning3 = 0
; Turn off no-space-in-time-literal warnings. Default is on.
; Show_Warning4 = 0
; Turn off multiple-drivers-on-unresolved-signal warnings. Default is on.
; Show_Warning5 = 0
; Turn off optimization for IEEE std_logic_1164 package. Default is on.
; Optimize_1164 = 0
; Turn on resolving of ambiguous function overloading in favor of the
; "explicit" function declaration (not the one automatically created by
; the compiler for each type declaration). Default is off.
Explicit = 1
; Turn off VITAL compliance checking. Default is checking on.
; NoVitalCheck = 1
; Ignore VITAL compliance checking errors. Default is to not ignore.
; IgnoreVitalErrors = 1
; Turn off VITAL compliance checking warnings. Default is to show warnings.
; Show_VitalChecksWarnings = false
; Turn off "loading..." messages. Default is messages on.
; Quiet = 1
; Turn on some limited synthesis rule compliance checking. Checks only:
; -- signals used (read) by a process must be in the sensitivity list
; CheckSynthesis = 1
[vlog]
; Turn off "loading..." messages. Default is messages on.
; Quiet = 1
; Turn on Verilog hazard checking (order-dependent accessing of global vars).
; Default is off.
; Hazard = 1
; Turn on converting regular Verilog identifiers to uppercase. Allows case
; insensitivity for module names. Default is no conversion.
; UpCase = 1
; Turns on incremental compilation of modules
; Incremental = 1
[vsim]
; Simulator resolution
; Set to fs, ps, ns, us, ms, or sec with optional prefix of 1, 10, or 100.
Resolution = ps
; User time unit for run commands
; Set to default, fs, ps, ns, us, ms, or sec. The default is to use the
; unit specified for Resolution. For example, if Resolution is 100ps,
; then UserTimeUnit defaults to ps.
UserTimeUnit = default
; Default run length
RunLength = 100
; Maximum iterations that can be run without advancing simulation time
IterationLimit = 5000
; Directive to license manager:
; vhdl Immediately reserve a VHDL license
; vlog Immediately reserve a Verilog license
; plus Immediately reserve a VHDL and Verilog license
; nomgc Do not look for Mentor Graphics Licenses
; nomti Do not look for Model Technology Licenses
; noqueue Do not wait in the license queue when a license isn't available
; License = plus
; Stop the simulator after an assertion message
; 0 = Note 1 = Warning 2 = Error 3 = Failure 4 = Fatal
BreakOnAssertion = 3
; Assertion Message Format
; %S - Severity Level
; %R - Report Message
; %T - Time of assertion
; %D - Delta
; %I - Instance or Region pathname (if available)
; %% - print '%' character
; AssertionFormat = "** %S: %R\n Timf: %T Iteration: %D%I\n"
; Assertion File - alternate file for storing assertion messages
; AssertFile = assert.log
; Default radix for all windows and commands...
; Set to symbolic, ascii, binary, octal, decimal, hex, unsigned
DefaultRadix = symbolic
; VSIM Startup command
; Startup = do startup.do
; File for saving command transcript
TranscriptFile = transcript
; File for saving command history
;CommandHistory = cmdhist.log
; Specify whether paths in simulator commands should be described
; in VHDL or Verilog format. For VHDL, PathSeparator = /
; for Verilog, PathSeparator = .
PathSeparator = /
; Specify the dataset separator for fully rooted contexts.
; The default is ':'. For example, sim:/top
; Must not be the same character as PathSeparator.
DatasetSeparator = :
; Disable assertion messages
; IgnoreNote = 1
; IgnoreWarning = 1
; IgnoreError = 1
; IgnoreFailure = 1
; Default force kind. May be freeze, drive, or deposit
; or in other terms, fixed, wired or charged.
; DefaultForceKind = freeze
; If zero, open files when elaborated
; else open files on first read or write
; DelayFileOpen = 0
; Control VHDL files opened for write
; 0 = Buffered, 1 = Unbuffered
UnbufferedOutput = 0
; Control number of VHDL files open concurrently
; This number should always be less then the
; current ulimit setting for max file descriptors
; 0 = unlimited
ConcurrentFileLimit = 40
; This controls the number of hierarchical regions displayed as
; part of a signal name shown in the waveform window. The default
; value or a value of zero tells VSIM to display the full name.
; WaveSignalNameWidth = 0
; Turn off warnings from the std_logic_arith, std_logic_unsigned
; and std_logic_signed packages.
; StdArithNoWarnings = 1
; Turn off warnings from the IEEE numeric_std and numeric_bit
; packages.
; NumericStdNoWarnings = 1
; Control the format of a generate statement label. Don't quote it.
; GenerateFormat = %s__%d
; Specify whether checkpoint files should be compressed.
; The default is to be compressed.
; CheckpointCompressMode = 0
; List of dynamically loaded objects for Verilog PLI applications
; Veriuser = veriuser.sl
[lmc]
[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

41
fpga/fpga.ucf Normal file
View file

@ -0,0 +1,41 @@
# See the schematic for the pin assignment.
NET "adc_d<0>" LOC = "P62" ;
NET "adc_d<1>" LOC = "P60" ;
NET "adc_d<2>" LOC = "P58" ;
NET "adc_d<3>" LOC = "P57" ;
NET "adc_d<4>" LOC = "P56" ;
NET "adc_d<5>" LOC = "P55" ;
NET "adc_d<6>" LOC = "P54" ;
NET "adc_d<7>" LOC = "P53" ;
#NET "cross_hi" LOC = "P88" ;
#NET "miso" LOC = "P40" ;
#PACE: Start of Constraints generated by PACE
#PACE: Start of PACE I/O Pin Assignments
NET "adc_clk" LOC = "P46" ;
NET "adc_noe" LOC = "P47" ;
NET "ck_1356meg" LOC = "P91" ;
NET "ck_1356megb" LOC = "P93" ;
NET "cross_lo" LOC = "P87" ;
NET "dbg" LOC = "P22" ;
NET "mosi" LOC = "P43" ;
NET "ncs" LOC = "P44" ;
NET "pck0" LOC = "P36" ;
NET "pwr_hi" LOC = "P80" ;
NET "pwr_lo" LOC = "P81" ;
NET "pwr_oe1" LOC = "P82" ;
NET "pwr_oe2" LOC = "P83" ;
NET "pwr_oe3" LOC = "P84" ;
NET "pwr_oe4" LOC = "P86" ;
NET "spck" LOC = "P39" ;
NET "ssp_clk" LOC = "P71" ;
NET "ssp_din" LOC = "P32" ;
NET "ssp_dout" LOC = "P34" ;
NET "ssp_frame" LOC = "P31" ;
#PACE: Start of PACE Area Constraints
#PACE: Start of PACE Prohibit Constraints
#PACE: End of Constraints generated by PACE

190
fpga/fpga.v Normal file
View file

@ -0,0 +1,190 @@
//-----------------------------------------------------------------------------
// The FPGA is responsible for interfacing between the A/D, the coil drivers,
// and the ARM. In the low-frequency modes it passes the data straight
// through, so that the ARM gets raw A/D samples over the SSP. In the high-
// frequency modes, the FPGA might perform some demodulation first, to
// reduce the amount of data that we must send to the ARM.
//
// I am not really an FPGA/ASIC designer, so I am sure that a lot of this
// could be improved.
//
// Jonathan Westhues, March 2006
// Added ISO14443-A support by Gerhard de Koning Gans, April 2008
//-----------------------------------------------------------------------------
`include "lo_read.v"
`include "lo_simulate.v"
`include "hi_read_tx.v"
`include "hi_read_rx_xcorr.v"
`include "hi_simulate.v"
`include "hi_iso14443a.v"
`include "util.v"
module fpga(
spck, miso, mosi, ncs,
pck0i, ck_1356meg, ck_1356megb,
pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
adc_d, adc_clk, adc_noe,
ssp_frame, ssp_din, ssp_dout, ssp_clk,
cross_hi, cross_lo,
dbg
);
input spck, mosi, ncs;
output miso;
input pck0i, 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, adc_noe;
input ssp_dout;
output ssp_frame, ssp_din, ssp_clk;
input cross_hi, cross_lo;
output dbg;
IBUFG #(.IOSTANDARD("DEFAULT") ) pck0b(
.O(pck0),
.I(pck0i)
);
//assign pck0 = pck0i;
//-----------------------------------------------------------------------------
// The SPI receiver. This sets up the configuration word, which the rest of
// the logic looks at to determine how to connect the A/D and the coil
// drivers (i.e., which section gets it). Also assign some symbolic names
// to the configuration bits, for use below.
//-----------------------------------------------------------------------------
reg [7:0] conf_word_shift;
reg [7:0] conf_word;
// We switch modes between transmitting to the 13.56 MHz tag and receiving
// from it, which means that we must make sure that we can do so without
// glitching, or else we will glitch the transmitted carrier.
always @(posedge ncs)
begin
conf_word <= conf_word_shift;
end
always @(posedge spck)
begin
if(~ncs)
begin
conf_word_shift[7:1] <= conf_word_shift[6:0];
conf_word_shift[0] <= mosi;
end
end
wire [2:0] major_mode;
assign major_mode = conf_word[7:5];
// For the low-frequency configuration:
wire lo_is_125khz;
assign lo_is_125khz = conf_word[3];
// For the high-frequency transmit configuration: modulation depth, either
// 100% (just quite driving antenna, steady LOW), or shallower (tri-state
// some fraction of the buffers)
wire hi_read_tx_shallow_modulation;
assign hi_read_tx_shallow_modulation = conf_word[0];
// For the high-frequency receive correlator: frequency against which to
// correlate.
wire hi_read_rx_xcorr_848;
assign hi_read_rx_xcorr_848 = conf_word[0];
// and whether to drive the coil (reader) or just short it (snooper)
wire hi_read_rx_xcorr_snoop;
assign hi_read_rx_xcorr_snoop = conf_word[1];
// For the high-frequency simulated tag: what kind of modulation to use.
wire [2:0] hi_simulate_mod_type;
assign hi_simulate_mod_type = conf_word[2:0];
//-----------------------------------------------------------------------------
// And then we instantiate the modules corresponding to each of the FPGA's
// major modes, and use muxes to connect the outputs of the active mode to
// the output pins.
//-----------------------------------------------------------------------------
lo_read lr(
pck0, ck_1356meg, ck_1356megb,
lr_pwr_lo, lr_pwr_hi, lr_pwr_oe1, lr_pwr_oe2, lr_pwr_oe3, lr_pwr_oe4,
adc_d, lr_adc_clk,
lr_ssp_frame, lr_ssp_din, ssp_dout, lr_ssp_clk,
cross_hi, cross_lo,
lr_dbg,
lo_is_125khz
);
lo_simulate ls(
pck0, ck_1356meg, ck_1356megb,
ls_pwr_lo, ls_pwr_hi, ls_pwr_oe1, ls_pwr_oe2, ls_pwr_oe3, ls_pwr_oe4,
adc_d, ls_adc_clk,
ls_ssp_frame, ls_ssp_din, ssp_dout, ls_ssp_clk,
cross_hi, cross_lo,
ls_dbg
);
hi_read_tx ht(
pck0, ck_1356meg, ck_1356megb,
ht_pwr_lo, ht_pwr_hi, ht_pwr_oe1, ht_pwr_oe2, ht_pwr_oe3, ht_pwr_oe4,
adc_d, ht_adc_clk,
ht_ssp_frame, ht_ssp_din, ssp_dout, ht_ssp_clk,
cross_hi, cross_lo,
ht_dbg,
hi_read_tx_shallow_modulation
);
hi_read_rx_xcorr hrxc(
pck0, ck_1356meg, ck_1356megb,
hrxc_pwr_lo, hrxc_pwr_hi, hrxc_pwr_oe1, hrxc_pwr_oe2, hrxc_pwr_oe3, hrxc_pwr_oe4,
adc_d, hrxc_adc_clk,
hrxc_ssp_frame, hrxc_ssp_din, ssp_dout, hrxc_ssp_clk,
cross_hi, cross_lo,
hrxc_dbg,
hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop
);
hi_simulate hs(
pck0, ck_1356meg, ck_1356megb,
hs_pwr_lo, hs_pwr_hi, hs_pwr_oe1, hs_pwr_oe2, hs_pwr_oe3, hs_pwr_oe4,
adc_d, hs_adc_clk,
hs_ssp_frame, hs_ssp_din, ssp_dout, hs_ssp_clk,
cross_hi, cross_lo,
hs_dbg,
hi_simulate_mod_type
);
hi_iso14443a hisn(
pck0, ck_1356meg, ck_1356megb,
hisn_pwr_lo, hisn_pwr_hi, hisn_pwr_oe1, hisn_pwr_oe2, hisn_pwr_oe3, hisn_pwr_oe4,
adc_d, hisn_adc_clk,
hisn_ssp_frame, hisn_ssp_din, ssp_dout, hisn_ssp_clk,
cross_hi, cross_lo,
hisn_dbg,
hi_simulate_mod_type
);
// Major modes:
// 000 -- LF reader (generic)
// 001 -- LF simulated tag (generic)
// 010 -- HF reader, transmitting to tag; modulation depth selectable
// 011 -- HF reader, receiving from tag, correlating as it goes; frequency selectable
// 100 -- HF simulated tag
// 101 -- HF ISO14443-A
// 110 -- unused
// 111 -- everything off
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
mux8 mux_dbg (major_mode, dbg, lr_dbg, ls_dbg, ht_dbg, hrxc_dbg, hs_dbg, hisn_dbg, 1'b0, 1'b0);
// In all modes, let the ADC's outputs be enabled.
assign adc_noe = 1'b0;
endmodule

38
fpga/go.bat Normal file
View file

@ -0,0 +1,38 @@
@echo off
rmdir/s/q xst
del fpga.ngc
xst -ifn xst.scr
if errorlevel 0 goto ok1
goto done
:ok1
del fpga.ngd
ngdbuild -aul -p xc2s30-6vq100 -nt timestamp -uc fpga.ucf fpga.ngc fpga.ngd
if errorlevel 0 goto ok2
goto done
:ok2
del fpga.ncd
map -p xc2s30-6vq100 fpga.ngd
if errorlevel 0 goto ok3
goto done
:ok3
del fpga-placed.ncd
par fpga.ncd fpga-placed.ncd
if errorlevel 0 goto ok4
goto done
:ok4
del fpga.bit fpga.drc fpga.rbt
bitgen -b fpga-placed.ncd fpga.bit
if errorlevel 0 goto ok5
goto done
:ok5
echo okay
perl ..\tools\rbt2c.pl fpga.rbt > ..\armsrc\fpgaimg.c
:done

360
fpga/hi_iso14443a.v Normal file
View file

@ -0,0 +1,360 @@
//-----------------------------------------------------------------------------
// ISO14443-A support for the Proxmark III
// Gerhard de Koning Gans, April 2008
//-----------------------------------------------------------------------------
module hi_iso14443a(
pck0, ck_1356meg, ck_1356megb,
pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
adc_d, adc_clk,
ssp_frame, ssp_din, ssp_dout, ssp_clk,
cross_hi, cross_lo,
dbg,
mod_type
);
input pck0, ck_1356meg, ck_1356megb;
output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;
input [7:0] adc_d;
output adc_clk;
input ssp_dout;
output ssp_frame, ssp_din, ssp_clk;
input cross_hi, cross_lo;
output dbg;
input [2:0] mod_type;
reg ssp_clk;
reg ssp_frame;
reg fc_div_2;
always @(posedge ck_1356meg)
fc_div_2 = ~fc_div_2;
wire adc_clk;
assign adc_clk = ck_1356meg;
reg after_hysteresis, after_hysteresis_prev1, after_hysteresis_prev2, after_hysteresis_prev3;
reg [11:0] has_been_low_for;
reg [8:0] saw_deep_modulation;
reg [2:0] deep_counter;
reg deep_modulation;
always @(negedge adc_clk)
begin
if(& adc_d[7:6]) after_hysteresis <= 1'b1;
else if(~(| adc_d[7:4])) after_hysteresis <= 1'b0;
if(~(| adc_d[7:0]))
begin
if(deep_counter == 3'd7)
begin
deep_modulation <= 1'b1;
saw_deep_modulation <= 8'd0;
end
else
deep_counter <= deep_counter + 1;
end
else
begin
deep_counter <= 3'd0;
if(saw_deep_modulation == 8'd255)
deep_modulation <= 1'b0;
else
saw_deep_modulation <= saw_deep_modulation + 1;
end
if(after_hysteresis)
begin
has_been_low_for <= 7'b0;
end
else
begin
if(has_been_low_for == 12'd4095)
begin
has_been_low_for <= 12'd0;
after_hysteresis <= 1'b1;
end
else
has_been_low_for <= has_been_low_for + 1;
end
end
// Report every 4 subcarrier cycles
// 64 periods of carrier frequency => 6-bit counter [negedge_cnt]
reg [5:0] negedge_cnt;
reg bit1, bit2, bit3;
reg [3:0] count_ones;
reg [3:0] count_zeros;
wire [7:0] avg;
reg [7:0] lavg;
reg signed [12:0] step1;
reg signed [12:0] step2;
reg [7:0] stepsize;
reg curbit;
reg [12:0] average;
wire signed [9:0] dif;
// A register to send the results to the arm
reg signed [7:0] to_arm;
assign avg[7:0] = average[11:4];
assign dif = lavg - avg;
reg bit_to_arm;
reg fdt_indicator, fdt_elapsed;
reg [10:0] fdt_counter;
reg [47:0] mod_sig_buf;
wire mod_sig_buf_empty;
reg [5:0] mod_sig_ptr;
reg [3:0] mod_sig_flip;
reg mod_sig, mod_sig_coil;
reg temp_buffer_reset;
reg sendbit;
assign mod_sig_buf_empty = ~(|mod_sig_buf[47:0]);
reg [2:0] ssp_frame_counter;
// ADC data appears on the rising edge, so sample it on the falling edge
always @(negedge adc_clk)
begin
// last bit = 0 then fdt = 1172, in case of 0x26 (7-bit command, LSB first!)
// last bit = 1 then fdt = 1236, in case of 0x52 (7-bit command, LSB first!)
if(fdt_counter == 11'd740) fdt_indicator = 1'b1;
if(fdt_counter == 11'd1148)
begin
if(fdt_elapsed)
begin
if(negedge_cnt[3:0] == mod_sig_flip[3:0]) mod_sig_coil <= mod_sig;
end
else
begin
mod_sig_flip[3:0] <= negedge_cnt[3:0];
mod_sig_coil <= mod_sig;
fdt_elapsed = 1'b1;
fdt_indicator = 1'b0;
if(~(| mod_sig_ptr[5:0])) mod_sig_ptr <= 6'b001001;
else temp_buffer_reset = 1'b1; // fix position of the buffer pointer
end
end
else
begin
fdt_counter <= fdt_counter + 1;
end
if(& negedge_cnt[3:0])
begin
// When there is a dip in the signal and not in reader mode
if(~after_hysteresis && mod_sig_buf_empty && ~((mod_type == 3'b100) || (mod_type == 3'b011) || (mod_type == 3'b010))) // last condition to prevent reset
begin
fdt_counter <= 11'd0;
fdt_elapsed = 1'b0;
fdt_indicator = 1'b0;
temp_buffer_reset = 1'b0;
mod_sig_ptr <= 6'b000000;
end
lavg <= avg;
if(stepsize<16) stepsize = 8'd16;
if(dif>0)
begin
step1 = dif*3;
step2 = stepsize*2; // 3:2
if(step1>step2)
begin
curbit = 1'b0;
stepsize = dif;
end
end
else
begin
step1 = dif*3;
step1 = -step1;
step2 = stepsize*2;
if(step1>step2)
begin
curbit = 1'b1;
stepsize = -dif;
end
end
if(curbit)
begin
count_zeros <= 4'd0;
if(& count_ones[3:2])
begin
curbit = 1'b0; // suppressed signal
stepsize = 8'd24; // just a fine number
end
else
begin
count_ones <= count_ones + 1;
end
end
else
begin
count_ones <= 4'd0;
if(& count_zeros[3:0])
begin
stepsize = 8'd24;
end
else
begin
count_zeros <= count_zeros + 1;
end
end
// What do we communicate to the ARM
if(mod_type == 3'b001) sendbit = after_hysteresis;
else if(mod_type == 3'b010)
begin
if(fdt_counter > 11'd772) sendbit = mod_sig_coil;
else sendbit = fdt_indicator;
end
else if(mod_type == 3'b011) sendbit = curbit;
else sendbit = 1'b0;
end
if(~(| negedge_cnt[3:0])) average <= adc_d;
else average <= average + adc_d;
if(negedge_cnt == 7'd63)
begin
if(deep_modulation)
begin
to_arm <= {after_hysteresis_prev1,after_hysteresis_prev2,after_hysteresis_prev3,after_hysteresis,1'b0,1'b0,1'b0,1'b0};
end
else
begin
to_arm <= {after_hysteresis_prev1,after_hysteresis_prev2,after_hysteresis_prev3,after_hysteresis,bit1,bit2,bit3,curbit};
end
negedge_cnt <= 0;
end
else
begin
negedge_cnt <= negedge_cnt + 1;
end
if(negedge_cnt == 6'd15)
begin
after_hysteresis_prev1 <= after_hysteresis;
bit1 <= curbit;
end
if(negedge_cnt == 6'd31)
begin
after_hysteresis_prev2 <= after_hysteresis;
bit2 <= curbit;
end
if(negedge_cnt == 6'd47)
begin
after_hysteresis_prev3 <= after_hysteresis;
bit3 <= curbit;
end
if(mod_type != 3'b000)
begin
if(negedge_cnt[3:0] == 4'b1000)
begin
// The modulation signal of the tag
mod_sig_buf[47:0] <= {mod_sig_buf[46:1], ssp_dout, 1'b0};
if((ssp_dout || (| mod_sig_ptr[5:0])) && ~fdt_elapsed)
if(mod_sig_ptr == 6'b101110)
begin
mod_sig_ptr <= 6'b000000;
end
else mod_sig_ptr <= mod_sig_ptr + 1;
else if(fdt_elapsed && ~temp_buffer_reset)
begin
if(ssp_dout) temp_buffer_reset = 1'b1;
if(mod_sig_ptr == 6'b000010) mod_sig_ptr <= 6'b001001;
else mod_sig_ptr <= mod_sig_ptr - 1;
end
else
begin
// side effect: when ptr = 1 it will cancel the first 1 of every block of ones
if(~mod_sig_buf[mod_sig_ptr-1] && ~mod_sig_buf[mod_sig_ptr+1]) mod_sig = 1'b0;
else mod_sig = mod_sig_buf[mod_sig_ptr] & fdt_elapsed; // & fdt_elapsed was for direct relay to oe4
end
end
end
// SSP Clock and data
if(mod_type == 3'b000)
begin
if(negedge_cnt[2:0] == 3'b100)
ssp_clk <= 1'b0;
if(negedge_cnt[2:0] == 3'b000)
begin
ssp_clk <= 1'b1;
// Don't shift if we just loaded new data, obviously.
if(negedge_cnt != 7'd0)
begin
to_arm[7:1] <= to_arm[6:0];
end
end
if(negedge_cnt[5:4] == 2'b00)
ssp_frame = 1'b1;
else
ssp_frame = 1'b0;
bit_to_arm = to_arm[7];
end
else
begin
if(negedge_cnt[3:0] == 4'b1000) ssp_clk <= 1'b0;
if(negedge_cnt[3:0] == 4'b0111)
begin
if(ssp_frame_counter == 3'd7) ssp_frame_counter <= 3'd0;
else ssp_frame_counter <= ssp_frame_counter + 1;
end
if(negedge_cnt[3:0] == 4'b0000)
begin
ssp_clk <= 1'b1;
end
ssp_frame = (ssp_frame_counter == 3'd7);
bit_to_arm = sendbit;
end
end
assign ssp_din = bit_to_arm;
// Modulating carrier frequency is fc/16
wire modulating_carrier;
assign modulating_carrier = (mod_sig_coil & negedge_cnt[3] & (mod_type == 3'b010));
assign pwr_hi = (ck_1356megb & (((mod_type == 3'b100) & ~mod_sig_coil) || (mod_type == 3'b011)));
// This one is all LF, so doesn't matter
//assign pwr_oe2 = modulating_carrier;
assign pwr_oe2 = 1'b0;
// Toggle only one of these, since we are already producing much deeper
// modulation than a real tag would.
//assign pwr_oe1 = modulating_carrier;
assign pwr_oe1 = 1'b0;
assign pwr_oe4 = modulating_carrier;
//assign pwr_oe4 = 1'b0;
// This one is always on, so that we can watch the carrier.
//assign pwr_oe3 = modulating_carrier;
assign pwr_oe3 = 1'b0;
assign dbg = negedge_cnt[3];
// Unused.
assign pwr_lo = 1'b0;
endmodule

165
fpga/hi_read_rx_xcorr.v Normal file
View file

@ -0,0 +1,165 @@
//-----------------------------------------------------------------------------
//
// Jonathan Westhues, April 2006
//-----------------------------------------------------------------------------
module hi_read_rx_xcorr(
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,
xcorr_is_848, snoop
);
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 xcorr_is_848, snoop;
// Carrier is steady on through this, unless we're snooping.
assign pwr_hi = ck_1356megb & (~snoop);
assign pwr_oe1 = 1'b0;
assign pwr_oe2 = 1'b0;
assign pwr_oe3 = 1'b0;
assign pwr_oe4 = 1'b0;
reg ssp_clk;
reg ssp_frame;
reg fc_div_2;
always @(posedge ck_1356meg)
fc_div_2 = ~fc_div_2;
reg adc_clk;
always @(xcorr_is_848 or fc_div_2 or ck_1356meg)
if(xcorr_is_848)
// The subcarrier frequency is fc/16; we will sample at fc, so that
// means the subcarrier is 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 ...
adc_clk <= ck_1356meg;
else
// The subcarrier frequency is fc/32; we will sample at fc/2, and
// the subcarrier will look identical.
adc_clk <= fc_div_2;
// When we're a reader, we just need to do the BPSK demod; but when we're an
// eavesdropper, we also need to pick out the commands sent by the reader,
// using AM. Do this the same way that we do it for the simulated tag.
reg after_hysteresis, after_hysteresis_prev;
reg [11:0] has_been_low_for;
always @(negedge adc_clk)
begin
if(& adc_d[7:0]) after_hysteresis <= 1'b1;
else if(~(| adc_d[7:0])) after_hysteresis <= 1'b0;
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
// Let us report a correlation every 4 subcarrier cycles, or 4*16 samples,
// so we need a 6-bit counter.
reg [5:0] corr_i_cnt;
reg [5:0] corr_q_cnt;
// And a couple of registers in which to accumulate the correlations.
reg signed [15:0] corr_i_accum;
reg signed [15:0] corr_q_accum;
reg signed [7:0] corr_i_out;
reg signed [7:0] corr_q_out;
// ADC data appears on the rising edge, so sample it on the falling edge
always @(negedge adc_clk)
begin
// These are the correlators: we correlate against in-phase and quadrature
// versions of our reference signal, and keep the (signed) result to
// send out later over the SSP.
if(corr_i_cnt == 7'd63)
begin
if(snoop)
begin
corr_i_out <= {corr_i_accum[12:6], after_hysteresis_prev};
corr_q_out <= {corr_q_accum[12:6], after_hysteresis};
end
else
begin
// Only correlations need to be delivered.
corr_i_out <= corr_i_accum[13:6];
corr_q_out <= corr_q_accum[13:6];
end
corr_i_accum <= adc_d;
corr_q_accum <= adc_d;
corr_q_cnt <= 4;
corr_i_cnt <= 0;
end
else
begin
if(corr_i_cnt[3])
corr_i_accum <= corr_i_accum - adc_d;
else
corr_i_accum <= corr_i_accum + adc_d;
if(corr_q_cnt[3])
corr_q_accum <= corr_q_accum - adc_d;
else
corr_q_accum <= corr_q_accum + adc_d;
corr_i_cnt <= corr_i_cnt + 1;
corr_q_cnt <= corr_q_cnt + 1;
end
// The logic in hi_simulate.v reports 4 samples per bit. We report two
// (I, Q) pairs per bit, so we should do 2 samples per pair.
if(corr_i_cnt == 6'd31)
after_hysteresis_prev <= after_hysteresis;
// Then the result from last time is serialized and send out to the ARM.
// We get one report each cycle, and each report is 16 bits, so the
// ssp_clk should be the adc_clk divided by 64/16 = 4.
if(corr_i_cnt[1:0] == 2'b10)
ssp_clk <= 1'b0;
if(corr_i_cnt[1:0] == 2'b00)
begin
ssp_clk <= 1'b1;
// Don't shift if we just loaded new data, obviously.
if(corr_i_cnt != 7'd0)
begin
corr_i_out[7:0] <= {corr_i_out[6:0], corr_q_out[7]};
corr_q_out[7:1] <= corr_q_out[6:0];
end
end
if(corr_i_cnt[5:2] == 4'b000 || corr_i_cnt[5:2] == 4'b1000)
ssp_frame = 1'b1;
else
ssp_frame = 1'b0;
end
assign ssp_din = corr_i_out[7];
assign dbg = corr_i_cnt[3];
// Unused.
assign pwr_lo = 1'b0;
endmodule

76
fpga/hi_read_tx.v Normal file
View file

@ -0,0 +1,76 @@
//-----------------------------------------------------------------------------
// The way that we connect things when transmitting a command to an ISO
// 15693 tag, using 100% modulation only for now.
//
// Jonathan Westhues, April 2006
//-----------------------------------------------------------------------------
module hi_read_tx(
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,
shallow_modulation
);
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 shallow_modulation;
// The high-frequency stuff. For now, for testing, just bring out the carrier,
// and allow the ARM to modulate it over the SSP.
reg pwr_hi;
reg pwr_oe1;
reg pwr_oe2;
reg pwr_oe3;
reg pwr_oe4;
always @(ck_1356megb or ssp_dout or shallow_modulation)
begin
if(shallow_modulation)
begin
pwr_hi <= ck_1356megb;
pwr_oe1 <= ~ssp_dout;
pwr_oe2 <= ~ssp_dout;
pwr_oe3 <= ~ssp_dout;
pwr_oe4 <= 1'b0;
end
else
begin
pwr_hi <= ck_1356megb & ssp_dout;
pwr_oe1 <= 1'b0;
pwr_oe2 <= 1'b0;
pwr_oe3 <= 1'b0;
pwr_oe4 <= 1'b0;
end
end
// Then just divide the 13.56 MHz clock down to produce appropriate clocks
// for the synchronous serial port.
reg [6:0] hi_div_by_128;
always @(posedge ck_1356meg)
hi_div_by_128 <= hi_div_by_128 + 1;
assign ssp_clk = hi_div_by_128[6];
reg [2:0] hi_byte_div;
always @(negedge ssp_clk)
hi_byte_div <= hi_byte_div + 1;
assign ssp_frame = (hi_byte_div == 3'b000);
assign ssp_din = 1'b0;
assign pwr_lo = 1'b0;
assign dbg = ssp_frame;
endmodule

106
fpga/hi_simulate.v Normal file
View file

@ -0,0 +1,106 @@
//-----------------------------------------------------------------------------
// Pretend to be an ISO 14443 tag. We will do this by alternately short-
// circuiting and open-circuiting the antenna coil, with the tri-state
// pins.
//
// We communicate over the SSP, as a bitstream (i.e., might as well be
// unframed, though we still generate the word sync signal). The output
// (ARM -> FPGA) tells us whether to modulate or not. The input (FPGA
// -> ARM) is us using the A/D as a fancy comparator; this is with
// (software-added) hysteresis, to undo the high-pass filter.
//
// At this point only Type A is implemented. This means that we are using a
// bit rate of 106 kbit/s, or fc/128. Oversample by 4, which ought to make
// things practical for the ARM (fc/32, 423.8 kbits/s, ~50 kbytes/s)
//
// Jonathan Westhues, October 2006
//-----------------------------------------------------------------------------
module hi_simulate(
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;
// Power amp goes between LOW and tri-state, so pwr_hi (and pwr_lo) can
// always be low.
assign pwr_hi = 1'b0;
assign pwr_lo = 1'b0;
// The comparator with hysteresis on the output from the peak detector.
reg after_hysteresis;
assign adc_clk = ck_1356meg;
always @(negedge adc_clk)
begin
if(& adc_d[7:5]) after_hysteresis = 1'b1;
else if(~(| adc_d[7:5])) after_hysteresis = 1'b0;
end
// Divide 13.56 MHz by 32 to produce the SSP_CLK
reg [4:0] ssp_clk_divider;
always @(posedge adc_clk)
ssp_clk_divider <= (ssp_clk_divider + 1);
assign ssp_clk = ssp_clk_divider[4];
// Divide SSP_CLK by 8 to produce the byte framing signal; the phase of
// this is arbitrary, because it's just a bitstream.
// One nasty issue, though: I can't make it work with both rx and tx at
// once. The phase wrt ssp_clk must be changed. TODO to find out why
// that is and make a better fix.
reg [2:0] ssp_frame_divider_to_arm;
always @(posedge ssp_clk)
ssp_frame_divider_to_arm <= (ssp_frame_divider_to_arm + 1);
reg [2:0] ssp_frame_divider_from_arm;
always @(negedge ssp_clk)
ssp_frame_divider_from_arm <= (ssp_frame_divider_from_arm + 1);
reg ssp_frame;
always @(ssp_frame_divider_to_arm or ssp_frame_divider_from_arm or mod_type)
if(mod_type == 3'b000) // not modulating, so listening, to ARM
ssp_frame = (ssp_frame_divider_to_arm == 3'b000);
else
ssp_frame = (ssp_frame_divider_from_arm == 3'b000);
// Synchronize up the after-hysteresis signal, to produce DIN.
reg ssp_din;
always @(posedge ssp_clk)
ssp_din = after_hysteresis;
// Modulating carrier frequency is fc/16, reuse ssp_clk divider for that
reg modulating_carrier;
always @(mod_type or ssp_clk or ssp_dout)
if(mod_type == 3'b000)
modulating_carrier <= 1'b0; // no modulation
else if(mod_type == 3'b001)
modulating_carrier <= ssp_dout ^ ssp_clk_divider[3]; // XOR means BPSK
else
modulating_carrier <= 1'b0; // yet unused
// This one is all LF, so doesn't matter
assign pwr_oe2 = modulating_carrier;
// 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_oe4 = modulating_carrier;
// This one is always on, so that we can watch the carrier.
assign pwr_oe3 = 1'b0;
assign dbg = after_hysteresis;
endmodule

102
fpga/lo_read.v Normal file
View file

@ -0,0 +1,102 @@
//-----------------------------------------------------------------------------
// The way that we connect things in low-frequency read mode. In this case
// we are generating the 134 kHz or 125 kHz carrier, and running the
// unmodulated carrier at that frequency. The A/D samples at that same rate,
// and the result is serialized.
//
// Jonathan Westhues, April 2006
//-----------------------------------------------------------------------------
module lo_read(
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,
lo_is_125khz
);
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 lo_is_125khz;
// The low-frequency RFID stuff. This is relatively simple, because most
// of the work happens on the ARM, and we just pass samples through. The
// PCK0 must be divided down to generate the A/D clock, and from there by
// a factor of 8 to generate the carrier (that we apply to the coil drivers).
//
// This is also where we decode the received synchronous serial port words,
// to determine how to drive the output enables.
// PCK0 will run at (PLL clock) / 4, or 24 MHz. That means that we can do
// 125 kHz by dividing by a further factor of (8*12*2), or ~134 kHz by
// dividing by a factor of (8*11*2) (for 136 kHz, ~2% error, tolerable).
reg [3:0] pck_divider;
reg clk_lo;
always @(posedge pck0)
begin
if(lo_is_125khz)
begin
if(pck_divider == 4'd11)
begin
pck_divider <= 4'd0;
clk_lo = !clk_lo;
end
else
pck_divider <= pck_divider + 1;
end
else
begin
if(pck_divider == 4'd10)
begin
pck_divider <= 4'd0;
clk_lo = !clk_lo;
end
else
pck_divider <= pck_divider + 1;
end
end
reg [2:0] carrier_divider_lo;
always @(posedge clk_lo)
begin
carrier_divider_lo <= carrier_divider_lo + 1;
end
assign pwr_lo = carrier_divider_lo[2];
// This serializes the values returned from the A/D, and sends them out
// over the SSP.
reg [7:0] to_arm_shiftreg;
always @(posedge clk_lo)
begin
if(carrier_divider_lo == 3'b000)
to_arm_shiftreg <= adc_d;
else
to_arm_shiftreg[7:1] <= to_arm_shiftreg[6:0];
end
assign ssp_clk = clk_lo;
assign ssp_frame = (carrier_divider_lo == 3'b001);
assign ssp_din = to_arm_shiftreg[7];
// The ADC converts on the falling edge, and our serializer loads when
// carrier_divider_lo == 3'b000.
assign adc_clk = ~carrier_divider_lo[2];
assign pwr_hi = 1'b0;
assign dbg = adc_clk;
endmodule

37
fpga/lo_simulate.v Normal file
View file

@ -0,0 +1,37 @@
//-----------------------------------------------------------------------------
// The way that we connect things in low-frequency simulation mode. In this
// case just pass everything through to the ARM, which can bit-bang this
// (because it is so slow).
//
// Jonathan Westhues, April 2006
//-----------------------------------------------------------------------------
module lo_simulate(
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
);
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;
// No logic, straight through.
assign pwr_oe3 = 1'b0;
assign pwr_oe1 = ssp_dout;
assign pwr_oe2 = ssp_dout;
assign pwr_oe4 = ssp_dout;
assign ssp_clk = cross_lo;
assign pwr_lo = 1'b0;
assign adc_clk = 1'b0;
assign pwr_hi = 1'b0;
assign dbg = cross_lo;
endmodule

27
fpga/sim.tcl Normal file
View file

@ -0,0 +1,27 @@
#------------------------------------------------------------------------------
# Run the simulation testbench in ModelSim: recompile both Verilog source
# files, then start the simulation, add a lot of signals to the waveform
# viewer, and run. I should (TODO) fix the absolute paths at some point.
#
# Jonathan Westhues, Mar 2006
#------------------------------------------------------------------------------
vlog -work work -O0 C:/depot/proximity/mark3/fpga/fpga.v
vlog -work work -O0 C:/depot/proximity/mark3/fpga/fpga_tb.v
vsim work.fpga_tb
add wave sim:/fpga_tb/adc_clk
add wave sim:/fpga_tb/adc_d
add wave sim:/fpga_tb/pwr_lo
add wave sim:/fpga_tb/ssp_clk
add wave sim:/fpga_tb/ssp_frame
add wave sim:/fpga_tb/ssp_din
add wave sim:/fpga_tb/ssp_dout
add wave sim:/fpga_tb/dut/clk_lo
add wave sim:/fpga_tb/dut/pck_divider
add wave sim:/fpga_tb/dut/carrier_divider_lo
add wave sim:/fpga_tb/dut/conf_word
run 30000

50
fpga/testbed_fpga.v Normal file
View file

@ -0,0 +1,50 @@
`include "fpga.v"
module testbed_fpga;
reg spck, mosi, ncs;
wire miso;
reg pck0i, ck_1356meg, ck_1356megb;
wire pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;
reg [7:0] adc_d;
wire adc_clk, adc_noe;
reg ssp_dout;
wire ssp_frame, ssp_din, ssp_clk;
fpga dut(
spck, miso, mosi, ncs,
pck0i, ck_1356meg, ck_1356megb,
pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
adc_d, adc_clk, adc_noe,
ssp_frame, ssp_din, ssp_dout, ssp_clk
);
integer i;
initial begin
// init inputs
#5 ncs=1;
#5 spck = 1;
#5 mosi = 1;
#50 ncs=0;
for (i = 0 ; i < 8 ; i = i + 1) begin
#5 mosi = $random;
#5 spck = 0;
#5 spck = 1;
end
#5 ncs=1;
#50 ncs=0;
for (i = 0 ; i < 8 ; i = i + 1) begin
#5 mosi = $random;
#5 spck = 0;
#5 spck = 1;
end
#5 ncs=1;
#50 mosi=1;
$finish;
end
endmodule // main

109
fpga/testbed_hi_read_tx.v Normal file
View file

@ -0,0 +1,109 @@
`include "hi_read_tx.v"
/*
pck0 - input main 24Mhz clock (PLL / 4)
[7:0] adc_d - input data from A/D converter
shallow_modulation - modulation type
pwr_lo - output to coil drivers (ssp_clk / 8)
adc_clk - output A/D clock signal
ssp_frame - output SSS frame indicator (goes high while the 8 bits are shifted)
ssp_din - output SSP data to ARM (shifts 8 bit A/D value serially to ARM MSB first)
ssp_clk - output SSP clock signal
ck_1356meg - input unused
ck_1356megb - input unused
ssp_dout - input unused
cross_hi - input unused
cross_lo - input unused
pwr_hi - output unused, tied low
pwr_oe1 - output unused, undefined
pwr_oe2 - output unused, undefined
pwr_oe3 - output unused, undefined
pwr_oe4 - output unused, undefined
dbg - output alias for adc_clk
*/
module testbed_hi_read_tx;
reg pck0;
reg [7:0] adc_d;
reg shallow_modulation;
wire pwr_lo;
wire adc_clk;
reg ck_1356meg;
reg ck_1356megb;
wire ssp_frame;
wire ssp_din;
wire ssp_clk;
reg ssp_dout;
wire pwr_hi;
wire pwr_oe1;
wire pwr_oe2;
wire pwr_oe3;
wire pwr_oe4;
wire cross_lo;
wire cross_hi;
wire dbg;
hi_read_tx #(5,200) dut(
.pck0(pck0),
.ck_1356meg(ck_1356meg),
.ck_1356megb(ck_1356megb),
.pwr_lo(pwr_lo),
.pwr_hi(pwr_hi),
.pwr_oe1(pwr_oe1),
.pwr_oe2(pwr_oe2),
.pwr_oe3(pwr_oe3),
.pwr_oe4(pwr_oe4),
.adc_d(adc_d),
.adc_clk(adc_clk),
.ssp_frame(ssp_frame),
.ssp_din(ssp_din),
.ssp_dout(ssp_dout),
.ssp_clk(ssp_clk),
.cross_hi(cross_hi),
.cross_lo(cross_lo),
.dbg(dbg),
.shallow_modulation(shallow_modulation)
);
integer idx, i;
// main clock
always #5 begin
ck_1356megb = !ck_1356megb;
ck_1356meg = ck_1356megb;
end
//crank DUT
task crank_dut;
begin
@(posedge ssp_clk) ;
ssp_dout = $random;
end
endtask
initial begin
// init inputs
ck_1356megb = 0;
adc_d = 0;
ssp_dout=0;
// shallow modulation off
shallow_modulation=0;
for (i = 0 ; i < 16 ; i = i + 1) begin
crank_dut;
end
// shallow modulation on
shallow_modulation=1;
for (i = 0 ; i < 16 ; i = i + 1) begin
crank_dut;
end
$finish;
end
endmodule // main

116
fpga/testbed_hi_simulate.v Normal file
View file

@ -0,0 +1,116 @@
`include "hi_simulate.v"
/*
pck0 - input main 24Mhz clock (PLL / 4)
[7:0] adc_d - input data from A/D converter
mod_type - modulation type
pwr_lo - output to coil drivers (ssp_clk / 8)
adc_clk - output A/D clock signal
ssp_frame - output SSS frame indicator (goes high while the 8 bits are shifted)
ssp_din - output SSP data to ARM (shifts 8 bit A/D value serially to ARM MSB first)
ssp_clk - output SSP clock signal
ck_1356meg - input unused
ck_1356megb - input unused
ssp_dout - input unused
cross_hi - input unused
cross_lo - input unused
pwr_hi - output unused, tied low
pwr_oe1 - output unused, undefined
pwr_oe2 - output unused, undefined
pwr_oe3 - output unused, undefined
pwr_oe4 - output unused, undefined
dbg - output alias for adc_clk
*/
module testbed_hi_simulate;
reg pck0;
reg [7:0] adc_d;
reg mod_type;
wire pwr_lo;
wire adc_clk;
reg ck_1356meg;
reg ck_1356megb;
wire ssp_frame;
wire ssp_din;
wire ssp_clk;
reg ssp_dout;
wire pwr_hi;
wire pwr_oe1;
wire pwr_oe2;
wire pwr_oe3;
wire pwr_oe4;
wire cross_lo;
wire cross_hi;
wire dbg;
hi_simulate #(5,200) dut(
.pck0(pck0),
.ck_1356meg(ck_1356meg),
.ck_1356megb(ck_1356megb),
.pwr_lo(pwr_lo),
.pwr_hi(pwr_hi),
.pwr_oe1(pwr_oe1),
.pwr_oe2(pwr_oe2),
.pwr_oe3(pwr_oe3),
.pwr_oe4(pwr_oe4),
.adc_d(adc_d),
.adc_clk(adc_clk),
.ssp_frame(ssp_frame),
.ssp_din(ssp_din),
.ssp_dout(ssp_dout),
.ssp_clk(ssp_clk),
.cross_hi(cross_hi),
.cross_lo(cross_lo),
.dbg(dbg),
.mod_type(mod_type)
);
integer idx, i;
// main clock
always #5 begin
ck_1356megb = !ck_1356megb;
ck_1356meg = ck_1356megb;
end
always begin
@(negedge adc_clk) ;
adc_d = $random;
end
//crank DUT
task crank_dut;
begin
@(negedge ssp_clk) ;
ssp_dout = $random;
end
endtask
initial begin
// init inputs
ck_1356megb = 0;
// random values
adc_d = 0;
ssp_dout=1;
// shallow modulation off
mod_type=0;
for (i = 0 ; i < 16 ; i = i + 1) begin
crank_dut;
end
// shallow modulation on
mod_type=1;
for (i = 0 ; i < 16 ; i = i + 1) begin
crank_dut;
end
$finish;
end
endmodule // main

105
fpga/testbed_lo_read.v Normal file
View file

@ -0,0 +1,105 @@
`include "lo_read.v"
/*
pck0 - input main 24Mhz clock (PLL / 4)
[7:0] adc_d - input data from A/D converter
lo_is_125khz - input freq selector (1=125Khz, 0=136Khz)
pwr_lo - output to coil drivers (ssp_clk / 8)
adc_clk - output A/D clock signal
ssp_frame - output SSS frame indicator (goes high while the 8 bits are shifted)
ssp_din - output SSP data to ARM (shifts 8 bit A/D value serially to ARM MSB first)
ssp_clk - output SSP clock signal 1Mhz/1.09Mhz (pck0 / 2*(11+lo_is_125khz) )
ck_1356meg - input unused
ck_1356megb - input unused
ssp_dout - input unused
cross_hi - input unused
cross_lo - input unused
pwr_hi - output unused, tied low
pwr_oe1 - output unused, undefined
pwr_oe2 - output unused, undefined
pwr_oe3 - output unused, undefined
pwr_oe4 - output unused, undefined
dbg - output alias for adc_clk
*/
module testbed_lo_read;
reg pck0;
reg [7:0] adc_d;
reg lo_is_125khz;
wire pwr_lo;
wire adc_clk;
wire ck_1356meg;
wire ck_1356megb;
wire ssp_frame;
wire ssp_din;
wire ssp_clk;
wire ssp_dout;
wire pwr_hi;
wire pwr_oe1;
wire pwr_oe2;
wire pwr_oe3;
wire pwr_oe4;
wire cross_lo;
wire cross_hi;
wire dbg;
lo_read #(5,200) dut(
.pck0(pck0),
.ck_1356meg(ck_1356meg),
.ck_1356megb(ck_1356megb),
.pwr_lo(pwr_lo),
.pwr_hi(pwr_hi),
.pwr_oe1(pwr_oe1),
.pwr_oe2(pwr_oe2),
.pwr_oe3(pwr_oe3),
.pwr_oe4(pwr_oe4),
.adc_d(adc_d),
.adc_clk(adc_clk),
.ssp_frame(ssp_frame),
.ssp_din(ssp_din),
.ssp_dout(ssp_dout),
.ssp_clk(ssp_clk),
.cross_hi(cross_hi),
.cross_lo(cross_lo),
.dbg(dbg),
.lo_is_125khz(lo_is_125khz)
);
integer idx, i;
// main clock
always #5 pck0 = !pck0;
//new A/D value available from ADC on positive edge
task crank_dut;
begin
@(posedge adc_clk) ;
adc_d = $random;
end
endtask
initial begin
// init inputs
pck0 = 0;
adc_d = 0;
// simulate 4 A/D cycles at 134Khz
lo_is_125khz=0;
for (i = 0 ; i < 4 ; i = i + 1) begin
crank_dut;
end
// simulate 4 A/D cycles at 125Khz
lo_is_125khz=1;
for (i = 0 ; i < 4 ; i = i + 1) begin
crank_dut;
end
$finish;
end
endmodule // main

101
fpga/testbed_lo_simulate.v Normal file
View file

@ -0,0 +1,101 @@
`include "lo_simulate.v"
/*
pck0 - input main 24Mhz clock (PLL / 4)
[7:0] adc_d - input data from A/D converter
pwr_lo - output to coil drivers (ssp_clk / 8)
adc_clk - output A/D clock signal
ssp_frame - output SSS frame indicator (goes high while the 8 bits are shifted)
ssp_din - output SSP data to ARM (shifts 8 bit A/D value serially to ARM MSB first)
ssp_clk - output SSP clock signal
ck_1356meg - input unused
ck_1356megb - input unused
ssp_dout - input unused
cross_hi - input unused
cross_lo - input unused
pwr_hi - output unused, tied low
pwr_oe1 - output unused, undefined
pwr_oe2 - output unused, undefined
pwr_oe3 - output unused, undefined
pwr_oe4 - output unused, undefined
dbg - output alias for adc_clk
*/
module testbed_lo_simulate;
reg pck0;
reg [7:0] adc_d;
wire pwr_lo;
wire adc_clk;
wire ck_1356meg;
wire ck_1356megb;
wire ssp_frame;
wire ssp_din;
wire ssp_clk;
reg ssp_dout;
wire pwr_hi;
wire pwr_oe1;
wire pwr_oe2;
wire pwr_oe3;
wire pwr_oe4;
reg cross_lo;
wire cross_hi;
wire dbg;
lo_simulate #(5,200) dut(
.pck0(pck0),
.ck_1356meg(ck_1356meg),
.ck_1356megb(ck_1356megb),
.pwr_lo(pwr_lo),
.pwr_hi(pwr_hi),
.pwr_oe1(pwr_oe1),
.pwr_oe2(pwr_oe2),
.pwr_oe3(pwr_oe3),
.pwr_oe4(pwr_oe4),
.adc_d(adc_d),
.adc_clk(adc_clk),
.ssp_frame(ssp_frame),
.ssp_din(ssp_din),
.ssp_dout(ssp_dout),
.ssp_clk(ssp_clk),
.cross_hi(cross_hi),
.cross_lo(cross_lo),
.dbg(dbg)
);
integer i, counter=0;
// main clock
always #5 pck0 = !pck0;
//cross_lo is not really synced to pck0 but it's roughly pck0/192 (24Mhz/192=125Khz)
task crank_dut;
begin
@(posedge pck0) ;
counter = counter + 1;
if (counter == 192) begin
counter = 0;
ssp_dout = $random;
cross_lo = 1;
end else begin
cross_lo = 0;
end
end
endtask
initial begin
pck0 = 0;
for (i = 0 ; i < 4096 ; i = i + 1) begin
crank_dut;
end
$finish;
end
endmodule // main

27
fpga/util.v Normal file
View file

@ -0,0 +1,27 @@
//-----------------------------------------------------------------------------
// General-purpose miscellany.
//
// Jonathan Westhues, April 2006.
//-----------------------------------------------------------------------------
module mux8(sel, y, x0, x1, x2, x3, x4, x5, x6, x7);
input [2:0] sel;
input x0, x1, x2, x3, x4, x5, x6, x7;
output y;
reg y;
always @(x0 or x1 or x2 or x3 or x4 or x5 or x6 or x7 or sel)
begin
case (sel)
3'b000: y = x0;
3'b001: y = x1;
3'b010: y = x2;
3'b011: y = x3;
3'b100: y = x4;
3'b101: y = x5;
3'b110: y = x6;
3'b111: y = x7;
endcase
end
endmodule

1
fpga/xst.scr Normal file
View file

@ -0,0 +1 @@
run -ifn fpga.v -ifmt Verilog -ofn fpga.ngc -ofmt NGC -p xc2s30-6vq100 -opt_mode Speed -opt_level 1 -ent fpga

461
include/at91sam7s128.h Normal file
View file

@ -0,0 +1,461 @@
//-----------------------------------------------------------------------------
// Incomplete register definitions for the AT91SAM7S128 chip.
// Jonathan Westhues, Jul 2005
//-----------------------------------------------------------------------------
#ifndef __AT91SAM7S128_H
#define __AT91SAM7S128_H
#define REG(x) (*(volatile unsigned long *)(x))
//-------------
// Peripheral IDs
#define PERIPH_AIC_FIQ 0
#define PERIPH_SYSIRQ 1
#define PERIPH_PIOA 2
#define PERIPH_ADC 4
#define PERIPH_SPI 5
#define PERIPH_US0 6
#define PERIPH_US1 7
#define PERIPH_SSC 8
#define PERIPH_TWI 9
#define PERIPH_PWMC 10
#define PERIPH_UDP 11
#define PERIPH_TC0 12
#define PERIPH_TC1 13
#define PERIPH_TC2 14
#define PERIPH_AIC_IRQ0 30
#define PERIPH_AIC_IRQ1 31
//-------------
// Reset Controller
#define RSTC_BASE (0xfffffd00)
#define RSTC_CONTROL REG(RSTC_BASE+0x00)
#define RST_CONTROL_KEY (0xa5<<24)
#define RST_CONTROL_PROCESSOR_RESET (1<<0)
//-------------
// PWM Controller
#define PWM_BASE (0xfffcc000)
#define PWM_MODE REG(PWM_BASE+0x00)
#define PWM_ENABLE REG(PWM_BASE+0x04)
#define PWM_DISABLE REG(PWM_BASE+0x08)
#define PWM_STATUS REG(PWM_BASE+0x0c)
#define PWM_INTERRUPT_ENABLE REG(PWM_BASE+0x10)
#define PWM_INTERRUPT_DISABLE REG(PWM_BASE+0x14)
#define PWM_INTERRUPT_MASK REG(PWM_BASE+0x18)
#define PWM_INTERRUPT_STATUS REG(PWM_BASE+0x1c)
#define PWM_CH_MODE(x) REG(PWM_BASE+0x200+((x)*0x20))
#define PWM_CH_DUTY_CYCLE(x) REG(PWM_BASE+0x204+((x)*0x20))
#define PWM_CH_PERIOD(x) REG(PWM_BASE+0x208+((x)*0x20))
#define PWM_CH_COUNTER(x) REG(PWM_BASE+0x20c+((x)*0x20))
#define PWM_CH_UPDATE(x) REG(PWM_BASE+0x210+((x)*0x20))
#define PWM_MODE_DIVA(x) ((x)<<0)
#define PWM_MODE_PREA(x) ((x)<<8)
#define PWM_MODE_DIVB(x) ((x)<<16)
#define PWM_MODE_PREB(x) ((x)<<24)
#define PWM_CHANNEL(x) (1<<(x))
#define PWM_CH_MODE_PRESCALER(x) ((x)<<0)
#define PWM_CH_MODE_PERIOD_CENTER_ALIGNED (1<<8)
#define PWM_CH_MODE_POLARITY_STARTS_HIGH (1<<9)
#define PWM_CH_MODE_UPDATE_UPDATES_PERIOD (1<<10)
//-------------
// Debug Unit
#define DBG_BASE (0xfffff200)
#define DBGU_CR REG(DBG_BASE+0x0000)
#define DBGU_MR REG(DBG_BASE+0x0004)
#define DBGU_IER REG(DBG_BASE+0x0008)
#define DBGU_IDR REG(DBG_BASE+0x000C)
#define DBGU_IMR REG(DBG_BASE+0x0010)
#define DBGU_SR REG(DBG_BASE+0x0014)
#define DBGU_RHR REG(DBG_BASE+0x0018)
#define DBGU_THR REG(DBG_BASE+0x001C)
#define DBGU_BRGR REG(DBG_BASE+0x0020)
#define DBGU_CIDR REG(DBG_BASE+0x0040)
#define DBGU_EXID REG(DBG_BASE+0x0044)
#define DBGU_FNR REG(DBG_BASE+0x0048)
//-------------
// Embedded Flash Controller
#define MC_BASE (0xffffff00)
#define MC_FLASH_MODE0 REG(MC_BASE+0x60)
#define MC_FLASH_COMMAND REG(MC_BASE+0x64)
#define MC_FLASH_STATUS REG(MC_BASE+0x68)
#define MC_FLASH_MODE1 REG(MC_BASE+0x70)
#define MC_FLASH_MODE_READY_INTERRUPT_ENABLE (1<<0)
#define MC_FLASH_MODE_LOCK_INTERRUPT_ENABLE (1<<2)
#define MC_FLASH_MODE_PROG_ERROR_INTERRUPT_ENABLE (1<<3)
#define MC_FLASH_MODE_NO_ERASE_BEFORE_PROGRAMMING (1<<7)
#define MC_FLASH_MODE_FLASH_WAIT_STATES(x) ((x)<<8)
#define MC_FLASH_MODE_MASTER_CLK_IN_MHZ(x) ((x)<<16)
#define MC_FLASH_COMMAND_FCMD(x) ((x)<<0)
#define MC_FLASH_COMMAND_PAGEN(x) ((x)<<8)
#define MC_FLASH_COMMAND_KEY ((0x5a)<<24)
#define FCMD_NOP 0x0
#define FCMD_WRITE_PAGE 0x1
#define FCMD_SET_LOCK_BIT 0x2
#define FCMD_WRITE_PAGE_LOCK 0x3
#define FCMD_CLEAR_LOCK_BIT 0x4
#define FCMD_ERASE_ALL 0x8
#define FCMD_SET_GP_NVM_BIT 0xb
#define FCMD_SET_SECURITY_BIT 0xf
#define MC_FLASH_STATUS_READY (1<<0)
#define MC_FLASH_STATUS_LOCK_ERROR (1<<2)
#define MC_FLASH_STATUS_PROGRAMMING_ERROR (1<<3)
#define MC_FLASH_STATUS_SECURITY_BIT_ACTIVE (1<<4)
#define MC_FLASH_STATUS_GP_NVM_ACTIVE_0 (1<<8)
#define MC_FLASH_STATUS_GP_NVM_ACTIVE_1 (1<<9)
#define MC_FLASH_STATUS_LOCK_ACTIVE(x) (1<<((x)+16))
#define FLASH_PAGE_SIZE_BYTES 256
#define FLASH_PAGE_COUNT 512
//-------------
// Watchdog Timer - 12 bit down counter, uses slow clock divided by 128 as source
#define WDT_BASE (0xfffffd40)
#define WDT_CONTROL REG(WDT_BASE+0x00)
#define WDT_MODE REG(WDT_BASE+0x04)
#define WDT_STATUS REG(WDT_BASE+0x08)
#define WDT_HIT() WDT_CONTROL = 0xa5000001
#define WDT_MODE_COUNT(x) ((x)<<0)
#define WDT_MODE_INTERRUPT_ON_EVENT (1<<12)
#define WDT_MODE_RESET_ON_EVENT_ENABLE (1<<13)
#define WDT_MODE_RESET_ON_EVENT (1<<14)
#define WDT_MODE_WATCHDOG_DELTA(x) ((x)<<16)
#define WDT_MODE_HALT_IN_DEBUG_MODE (1<<28)
#define WDT_MODE_HALT_IN_IDLE_MODE (1<<29)
#define WDT_MODE_DISABLE (1<<15)
//-------------
// Parallel Input/Output Controller
#define PIO_BASE (0xfffff400)
#define PIO_ENABLE REG(PIO_BASE+0x000)
#define PIO_DISABLE REG(PIO_BASE+0x004)
#define PIO_STATUS REG(PIO_BASE+0x008)
#define PIO_OUTPUT_ENABLE REG(PIO_BASE+0x010)
#define PIO_OUTPUT_DISABLE REG(PIO_BASE+0x014)
#define PIO_OUTPUT_STATUS REG(PIO_BASE+0x018)
#define PIO_GLITCH_ENABLE REG(PIO_BASE+0x020)
#define PIO_GLITCH_DISABLE REG(PIO_BASE+0x024)
#define PIO_GLITCH_STATUS REG(PIO_BASE+0x028)
#define PIO_OUTPUT_DATA_SET REG(PIO_BASE+0x030)
#define PIO_OUTPUT_DATA_CLEAR REG(PIO_BASE+0x034)
#define PIO_OUTPUT_DATA_STATUS REG(PIO_BASE+0x038)
#define PIO_PIN_DATA_STATUS REG(PIO_BASE+0x03c)
#define PIO_OPEN_DRAIN_ENABLE REG(PIO_BASE+0x050)
#define PIO_OPEN_DRAIN_DISABLE REG(PIO_BASE+0x054)
#define PIO_OPEN_DRAIN_STATUS REG(PIO_BASE+0x058)
#define PIO_NO_PULL_UP_ENABLE REG(PIO_BASE+0x060)
#define PIO_NO_PULL_UP_DISABLE REG(PIO_BASE+0x064)
#define PIO_NO_PULL_UP_STATUS REG(PIO_BASE+0x068)
#define PIO_PERIPHERAL_A_SEL REG(PIO_BASE+0x070)
#define PIO_PERIPHERAL_B_SEL REG(PIO_BASE+0x074)
#define PIO_PERIPHERAL_WHICH REG(PIO_BASE+0x078)
#define PIO_OUT_WRITE_ENABLE REG(PIO_BASE+0x0a0)
#define PIO_OUT_WRITE_DISABLE REG(PIO_BASE+0x0a4)
#define PIO_OUT_WRITE_STATUS REG(PIO_BASE+0x0a8)
//-------------
// USB Device Port
#define UDP_BASE (0xfffb0000)
#define UDP_FRAME_NUMBER REG(UDP_BASE+0x0000)
#define UDP_GLOBAL_STATE REG(UDP_BASE+0x0004)
#define UDP_FUNCTION_ADDR REG(UDP_BASE+0x0008)
#define UDP_INTERRUPT_ENABLE REG(UDP_BASE+0x0010)
#define UDP_INTERRUPT_DISABLE REG(UDP_BASE+0x0014)
#define UDP_INTERRUPT_MASK REG(UDP_BASE+0x0018)
#define UDP_INTERRUPT_STATUS REG(UDP_BASE+0x001c)
#define UDP_INTERRUPT_CLEAR REG(UDP_BASE+0x0020)
#define UDP_RESET_ENDPOINT REG(UDP_BASE+0x0028)
#define UDP_ENDPOINT_CSR(x) REG(UDP_BASE+0x0030+((x)*4))
#define UDP_ENDPOINT_FIFO(x) REG(UDP_BASE+0x0050+((x)*4))
#define UDP_TRANSCEIVER_CTRL REG(UDP_BASE+0x0074)
#define UDP_GLOBAL_STATE_ADDRESSED (1<<0)
#define UDP_GLOBAL_STATE_CONFIGURED (1<<1)
#define UDP_GLOBAL_STATE_SEND_RESUME_ENABLED (1<<2)
#define UDP_GLOBAL_STATE_RESUME_RECEIVED (1<<3)
#define UDP_GLOBAL_STATE_REMOTE_WAKE_UP_ENABLED (1<<4)
#define UDP_FUNCTION_ADDR_ENABLED (1<<8)
#define UDP_INTERRUPT_ENDPOINT(x) (1<<(x))
#define UDP_INTERRUPT_SUSPEND (1<<8)
#define UDP_INTERRUPT_RESUME (1<<9)
#define UDP_INTERRUPT_EXTERNAL_RESUME (1<<10)
#define UDP_INTERRUPT_SOF (1<<11)
#define UDP_INTERRUPT_END_OF_BUS_RESET (1<<12)
#define UDP_INTERRUPT_WAKEUP (1<<13)
#define UDP_RESET_ENDPOINT_NUMBER(x) (1<<(x))
#define UDP_CSR_TX_PACKET_ACKED (1<<0)
#define UDP_CSR_RX_PACKET_RECEIVED_BANK_0 (1<<1)
#define UDP_CSR_RX_HAVE_READ_SETUP_DATA (1<<2)
#define UDP_CSR_STALL_SENT (1<<3)
#define UDP_CSR_TX_PACKET (1<<4)
#define UDP_CSR_FORCE_STALL (1<<5)
#define UDP_CSR_RX_PACKET_RECEIVED_BANK_1 (1<<6)
#define UDP_CSR_CONTROL_DATA_DIR (1<<7)
#define UDP_CSR_EPTYPE_CONTROL (0<<8)
#define UDP_CSR_EPTYPE_ISOCHRON_OUT (1<<8)
#define UDP_CSR_EPTYPE_ISOCHRON_IN (5<<8)
#define UDP_CSR_EPTYPE_BULK_OUT (2<<8)
#define UDP_CSR_EPTYPE_BULK_IN (6<<8)
#define UDP_CSR_EPTYPE_INTERRUPT_OUT (3<<8)
#define UDP_CSR_EPTYPE_INTERRUPT_IN (7<<8)
#define UDP_CSR_IS_DATA1 (1<<11)
#define UDP_CSR_ENABLE_EP (1<<15)
#define UDP_CSR_BYTES_RECEIVED(x) (((x) >> 16) & 0x7ff)
#define UDP_TRANSCEIVER_CTRL_DISABLE (1<<8)
//-------------
// Power Management Controller
#define PMC_BASE (0xfffffc00)
#define PMC_SYS_CLK_ENABLE REG(PMC_BASE+0x0000)
#define PMC_SYS_CLK_DISABLE REG(PMC_BASE+0x0004)
#define PMC_SYS_CLK_STATUS REG(PMC_BASE+0x0008)
#define PMC_PERIPHERAL_CLK_ENABLE REG(PMC_BASE+0x0010)
#define PMC_PERIPHERAL_CLK_DISABLE REG(PMC_BASE+0x0014)
#define PMC_PERIPHERAL_CLK_STATUS REG(PMC_BASE+0x0018)
#define PMC_MAIN_OSCILLATOR REG(PMC_BASE+0x0020)
#define PMC_MAIN_CLK_FREQUENCY REG(PMC_BASE+0x0024)
#define PMC_PLL REG(PMC_BASE+0x002c)
#define PMC_MASTER_CLK REG(PMC_BASE+0x0030)
#define PMC_PROGRAMMABLE_CLK_0 REG(PMC_BASE+0x0040)
#define PMC_PROGRAMMABLE_CLK_1 REG(PMC_BASE+0x0044)
#define PMC_INTERRUPT_ENABLE REG(PMC_BASE+0x0060)
#define PMC_INTERRUPT_DISABLE REG(PMC_BASE+0x0064)
#define PMC_INTERRUPT_STATUS REG(PMC_BASE+0x0068)
#define PMC_INTERRUPT_MASK REG(PMC_BASE+0x006c)
#define PMC_SYS_CLK_PROCESSOR_CLK (1<<0)
#define PMC_SYS_CLK_UDP_CLK (1<<7)
#define PMC_SYS_CLK_PROGRAMMABLE_CLK_0 (1<<8)
#define PMC_SYS_CLK_PROGRAMMABLE_CLK_1 (1<<9)
#define PMC_SYS_CLK_PROGRAMMABLE_CLK_2 (1<<10)
#define PMC_MAIN_OSCILLATOR_STABILIZED (1<<0)
#define PMC_MAIN_OSCILLATOR_PLL_LOCK (1<<2)
#define PMC_MAIN_OSCILLATOR_MCK_READY (1<<3)
#define PMC_MAIN_OSCILLATOR_ENABLE (1<<0)
#define PMC_MAIN_OSCILLATOR_BYPASS (1<<1)
#define PMC_MAIN_OSCILLATOR_STARTUP_DELAY(x) ((x)<<8)
#define PMC_PLL_DIVISOR(x) (x)
#define PMC_PLL_COUNT_BEFORE_LOCK(x) ((x)<<8)
#define PMC_PLL_FREQUENCY_RANGE(x) ((x)<<14)
#define PMC_PLL_MULTIPLIER(x) (((x)-1)<<16)
#define PMC_PLL_USB_DIVISOR(x) ((x)<<28)
#define PMC_CLK_SELECTION_PLL_CLOCK (3<<0)
#define PMC_CLK_SELECTION_MAIN_CLOCK (1<<0)
#define PMC_CLK_SELECTION_SLOW_CLOCK (0<<0)
#define PMC_CLK_PRESCALE_DIV_1 (0<<2)
#define PMC_CLK_PRESCALE_DIV_2 (1<<2)
#define PMC_CLK_PRESCALE_DIV_4 (2<<2)
#define PMC_CLK_PRESCALE_DIV_8 (3<<2)
#define PMC_CLK_PRESCALE_DIV_16 (4<<2)
#define PMC_CLK_PRESCALE_DIV_32 (5<<2)
#define PMC_CLK_PRESCALE_DIV_64 (6<<2)
//-------------
// Serial Peripheral Interface (SPI)
#define SPI_BASE (0xfffe0000)
#define SPI_CONTROL REG(SPI_BASE+0x00)
#define SPI_MODE REG(SPI_BASE+0x04)
#define SPI_RX_DATA REG(SPI_BASE+0x08)
#define SPI_TX_DATA REG(SPI_BASE+0x0c)
#define SPI_STATUS REG(SPI_BASE+0x10)
#define SPI_INTERRUPT_ENABLE REG(SPI_BASE+0x14)
#define SPI_INTERRUPT_DISABLE REG(SPI_BASE+0x18)
#define SPI_INTERRUPT_MASK REG(SPI_BASE+0x1c)
#define SPI_FOR_CHIPSEL_0 REG(SPI_BASE+0x30)
#define SPI_FOR_CHIPSEL_1 REG(SPI_BASE+0x34)
#define SPI_FOR_CHIPSEL_2 REG(SPI_BASE+0x38)
#define SPI_FOR_CHIPSEL_3 REG(SPI_BASE+0x3c)
#define SPI_CONTROL_ENABLE (1<<0)
#define SPI_CONTROL_DISABLE (1<<1)
#define SPI_CONTROL_RESET (1<<7)
#define SPI_CONTROL_LAST_TRANSFER (1<<24)
#define SPI_MODE_MASTER (1<<0)
#define SPI_MODE_VARIABLE_CHIPSEL (1<<1)
#define SPI_MODE_CHIPSELS_DECODED (1<<2)
#define SPI_MODE_USE_DIVIDED_CLOCK (1<<3)
#define SPI_MODE_MODE_FAULT_DETECTION_OFF (1<<4)
#define SPI_MODE_LOOPBACK (1<<7)
#define SPI_MODE_CHIPSEL(x) ((x)<<16)
#define SPI_MODE_DELAY_BETWEEN_CHIPSELS(x) ((x)<<24)
#define SPI_RX_DATA_CHIPSEL(x) (((x)>>16)&0xf)
#define SPI_TX_DATA_CHIPSEL(x) ((x)<<16)
#define SPI_TX_DATA_LAST_TRANSFER (1<<24)
#define SPI_STATUS_RECEIVE_FULL (1<<0)
#define SPI_STATUS_TRANSMIT_EMPTY (1<<1)
#define SPI_STATUS_MODE_FAULT (1<<2)
#define SPI_STATUS_OVERRUN (1<<3)
#define SPI_STATUS_END_OF_RX_BUFFER (1<<4)
#define SPI_STATUS_END_OF_TX_BUFFER (1<<5)
#define SPI_STATUS_RX_BUFFER_FULL (1<<6)
#define SPI_STATUS_TX_BUFFER_EMPTY (1<<7)
#define SPI_STATUS_NSS_RISING_DETECTED (1<<8)
#define SPI_STATUS_TX_EMPTY (1<<9)
#define SPI_STATUS_SPI_ENABLED (1<<16)
#define SPI_FOR_CHIPSEL_INACTIVE_CLK_1 (1<<0)
#define SPI_FOR_CHIPSEL_PHASE (1<<1)
#define SPI_FOR_CHIPSEL_LEAVE_CHIPSEL_LOW (1<<3)
#define SPI_FOR_CHIPSEL_BITS_IN_WORD(x) ((x)<<4)
#define SPI_FOR_CHIPSEL_DIVISOR(x) ((x)<<8)
#define SPI_FOR_CHIPSEL_DELAY_BEFORE_CLK(x) ((x)<<16)
#define SPI_FOR_CHIPSEL_INTERWORD_DELAY(x) ((x)<<24)
//-------------
// Analog to Digital Converter
#define ADC_BASE (0xfffd8000)
#define ADC_CONTROL REG(ADC_BASE+0x00)
#define ADC_MODE REG(ADC_BASE+0x04)
#define ADC_CHANNEL_ENABLE REG(ADC_BASE+0x10)
#define ADC_CHANNEL_DISABLE REG(ADC_BASE+0x14)
#define ADC_CHANNEL_STATUS REG(ADC_BASE+0x18)
#define ADC_STATUS REG(ADC_BASE+0x1c)
#define ADC_LAST_CONVERTED_DATA REG(ADC_BASE+0x20)
#define ADC_INTERRUPT_ENABLE REG(ADC_BASE+0x24)
#define ADC_INTERRUPT_DISABLE REG(ADC_BASE+0x28)
#define ADC_INTERRUPT_MASK REG(ADC_BASE+0x2c)
#define ADC_CHANNEL_DATA(x) REG(ADC_BASE+0x30+(4*(x)))
#define ADC_CONTROL_RESET (1<<0)
#define ADC_CONTROL_START (1<<1)
#define ADC_MODE_HW_TRIGGERS_ENABLED (1<<0)
#define ADC_MODE_8_BIT_RESOLUTION (1<<4)
#define ADC_MODE_SLEEP (1<<5)
#define ADC_MODE_PRESCALE(x) ((x)<<8)
#define ADC_MODE_STARTUP_TIME(x) ((x)<<16)
#define ADC_MODE_SAMPLE_HOLD_TIME(x) ((x)<<24)
#define ADC_CHANNEL(x) (1<<(x))
#define ADC_END_OF_CONVERSION(x) (1<<(x))
#define ADC_OVERRUN_ERROR(x) (1<<(8+(x)))
#define ADC_DATA_READY (1<<16)
#define ADC_GENERAL_OVERRUN (1<<17)
#define ADC_END_OF_RX_BUFFER (1<<18)
#define ADC_RX_BUFFER_FULL (1<<19)
//-------------
// Synchronous Serial Controller
#define SSC_BASE (0xfffd4000)
#define SSC_CONTROL REG(SSC_BASE+0x00)
#define SSC_CLOCK_DIVISOR REG(SSC_BASE+0x04)
#define SSC_RECEIVE_CLOCK_MODE REG(SSC_BASE+0x10)
#define SSC_RECEIVE_FRAME_MODE REG(SSC_BASE+0x14)
#define SSC_TRANSMIT_CLOCK_MODE REG(SSC_BASE+0x18)
#define SSC_TRANSMIT_FRAME_MODE REG(SSC_BASE+0x1c)
#define SSC_RECEIVE_HOLDING REG(SSC_BASE+0x20)
#define SSC_TRANSMIT_HOLDING REG(SSC_BASE+0x24)
#define SSC_RECEIVE_SYNC_HOLDING REG(SSC_BASE+0x30)
#define SSC_TRANSMIT_SYNC_HOLDING REG(SSC_BASE+0x34)
#define SSC_STATUS REG(SSC_BASE+0x40)
#define SSC_INTERRUPT_ENABLE REG(SSC_BASE+0x44)
#define SSC_INTERRUPT_DISABLE REG(SSC_BASE+0x48)
#define SSC_INTERRUPT_MASK REG(SSC_BASE+0x4c)
#define SSC_CONTROL_RX_ENABLE (1<<0)
#define SSC_CONTROL_RX_DISABLE (1<<1)
#define SSC_CONTROL_TX_ENABLE (1<<8)
#define SSC_CONTROL_TX_DISABLE (1<<9)
#define SSC_CONTROL_RESET (1<<15)
#define SSC_CLOCK_MODE_SELECT(x) ((x)<<0)
#define SSC_CLOCK_MODE_OUTPUT(x) ((x)<<2)
#define SSC_CLOCK_MODE_INVERT (1<<5)
#define SSC_CLOCK_MODE_START(x) ((x)<<8)
#define SSC_CLOCK_MODE_START_DELAY(x) ((x)<<16)
#define SSC_CLOCK_MODE_FRAME_PERIOD(x) ((x)<<24)
#define SSC_FRAME_MODE_BITS_IN_WORD(x) (((x)-1)<<0)
#define SSC_FRAME_MODE_LOOPBACK (1<<5) // for RX
#define SSC_FRAME_MODE_DEFAULT_IS_1 (1<<5) // for TX
#define SSC_FRAME_MODE_MSB_FIRST (1<<7)
#define SSC_FRAME_MODE_WORDS_PER_TRANSFER(x) ((x)<<8)
#define SSC_FRAME_MODE_FRAME_SYNC_LEN(x) ((x)<<16)
#define SSC_FRAME_MODE_FRAME_SYNC_TYPE(x) ((x)<<20)
#define SSC_FRAME_MODE_SYNC_DATA_ENABLE (1<<23) // for TX only
#define SSC_FRAME_MODE_NEGATIVE_EDGE (1<<24)
#define SSC_STATUS_TX_READY (1<<0)
#define SSC_STATUS_TX_EMPTY (1<<1)
#define SSC_STATUS_TX_ENDED (1<<2)
#define SSC_STATUS_TX_BUF_EMPTY (1<<3)
#define SSC_STATUS_RX_READY (1<<4)
#define SSC_STATUS_RX_OVERRUN (1<<5)
#define SSC_STATUS_RX_ENDED (1<<6)
#define SSC_STATUS_RX_BUF_FULL (1<<7)
#define SSC_STATUS_TX_SYNC_OCCURRED (1<<10)
#define SSC_STATUS_RX_SYNC_OCCURRED (1<<11)
#define SSC_STATUS_TX_ENABLED (1<<16)
#define SSC_STATUS_RX_ENABLED (1<<17)
//-------------
// Peripheral DMA Controller
//
// There is one set of registers for every peripheral that supports DMA.
#define PDC_RX_POINTER(x) REG((x)+0x100)
#define PDC_RX_COUNTER(x) REG((x)+0x104)
#define PDC_TX_POINTER(x) REG((x)+0x108)
#define PDC_TX_COUNTER(x) REG((x)+0x10c)
#define PDC_RX_NEXT_POINTER(x) REG((x)+0x110)
#define PDC_RX_NEXT_COUNTER(x) REG((x)+0x114)
#define PDC_TX_NEXT_POINTER(x) REG((x)+0x118)
#define PDC_TX_NEXT_COUNTER(x) REG((x)+0x11c)
#define PDC_CONTROL(x) REG((x)+0x120)
#define PDC_STATUS(x) REG((x)+0x124)
#define PDC_RX_ENABLE (1<<0)
#define PDC_RX_DISABLE (1<<1)
#define PDC_TX_ENABLE (1<<8)
#define PDC_TX_DISABLE (1<<9)
#endif

40
include/config_gpio.h Normal file
View file

@ -0,0 +1,40 @@
#ifndef __CONFIG_GPIO_H
#define __CONFIG_GPIO_H
#define GPIO_LED_A 0
#define GPIO_PA1 1
#define GPIO_LED_D 2
#define GPIO_NVDD_ON 3
#define GPIO_FPGA_NINIT 4
#define GPIO_PA5 5
#define GPIO_PCK0 6
#define GPIO_LRST 7
#define GPIO_LED_B 8
#define GPIO_LED_C 9
#define GPIO_NCS2 10
#define GPIO_NCS0 11
#define GPIO_MISO 12
#define GPIO_MOSI 13
#define GPIO_SPCK 14
#define GPIO_SSC_FRAME 15
#define GPIO_SSC_CLK 16
#define GPIO_SSC_DOUT 17
#define GPIO_SSC_DIN 18
#define GPIO_MUXSEL_HIPKD 19
#define GPIO_MUXSEL_LOPKD 20
#define GPIO_MUXSEL_HIRAW 21
#define GPIO_MUXSEL_LORAW 22
#define GPIO_BUTTON 23
#define GPIO_USB_PU 24
#define GPIO_RELAY 25
#define GPIO_FPGA_ON 26
#define GPIO_FPGA_DONE 27
#define GPIO_FPGA_NPROGRAM 28
#define GPIO_FPGA_CCLK 29
#define GPIO_FPGA_DIN 30
#define GPIO_FPGA_DOUT 31
#define ANIN_AMPL_LO 4
#define ANIN_AMPL_HI 5
#endif

62
include/proxmark3.h Normal file
View file

@ -0,0 +1,62 @@
//-----------------------------------------------------------------------------
// Definitions of interest to most of the software for this project.
// Jonathan Westhues, Mar 2006
//-----------------------------------------------------------------------------
#ifndef __PROXMARK3_H
#define __PROXMARK3_H
// Might as well have the hardware-specific defines everywhere.
#include <at91sam7s128.h>
#include <config_gpio.h>
#define LOW(x) PIO_OUTPUT_DATA_CLEAR = (1 << (x))
#define HIGH(x) PIO_OUTPUT_DATA_SET = (1 << (x))
#define SPI_FPGA_MODE 0
#define SPI_LCD_MODE 1
typedef unsigned long DWORD;
typedef signed long SDWORD;
typedef unsigned long long QWORD;
typedef int BOOL;
typedef unsigned char BYTE;
typedef signed char SBYTE;
typedef unsigned short WORD;
typedef signed short SWORD;
#define TRUE 1
#define FALSE 0
#include <usb_cmd.h>
#define PACKED __attribute__((__packed__))
#define USB_D_PLUS_PULLUP_ON() { \
PIO_OUTPUT_DATA_SET = (1<<GPIO_USB_PU); \
PIO_OUTPUT_ENABLE = (1<<GPIO_USB_PU); \
}
#define USB_D_PLUS_PULLUP_OFF() PIO_OUTPUT_DISABLE = (1<<GPIO_USB_PU)
#define LED_A_ON() PIO_OUTPUT_DATA_SET = (1<<GPIO_LED_A)
#define LED_A_OFF() PIO_OUTPUT_DATA_CLEAR = (1<<GPIO_LED_A)
#define LED_B_ON() PIO_OUTPUT_DATA_SET = (1<<GPIO_LED_B)
#define LED_B_OFF() PIO_OUTPUT_DATA_CLEAR = (1<<GPIO_LED_B)
#define LED_C_ON() PIO_OUTPUT_DATA_SET = (1<<GPIO_LED_C)
#define LED_C_OFF() PIO_OUTPUT_DATA_CLEAR = (1<<GPIO_LED_C)
#define LED_D_ON() PIO_OUTPUT_DATA_SET = (1<<GPIO_LED_D)
#define LED_D_OFF() PIO_OUTPUT_DATA_CLEAR = (1<<GPIO_LED_D)
#define RELAY_ON() PIO_OUTPUT_DATA_SET = (1<<GPIO_RELAY)
#define RELAY_OFF() PIO_OUTPUT_DATA_CLEAR = (1<<GPIO_RELAY)
#define BUTTON_PRESS() !(PIO_PIN_DATA_STATUS & (1<<GPIO_BUTTON))
//--------------------------------
// USB declarations
void UsbSendPacket(BYTE *packet, int len);
BOOL UsbPoll(BOOL blinkLeds);
void UsbStart(void);
// This function is provided by the apps/bootrom, and called from UsbPoll
// if data are available.
void UsbPacketReceived(BYTE *packet, int len);
#endif

71
include/usb_cmd.h Normal file
View file

@ -0,0 +1,71 @@
//-----------------------------------------------------------------------------
// Definitions for all the types of commands that may be sent over USB; our
// own protocol.
// Jonathan Westhues, Mar 2006
// Edits by Gerhard de Koning Gans, Sep 2007
//-----------------------------------------------------------------------------
#ifndef __USB_CMD_H
#define __USB_CMD_H
typedef struct {
DWORD cmd;
DWORD ext1;
DWORD ext2;
DWORD ext3;
union {
BYTE asBytes[48];
DWORD asDwords[12];
} d;
} UsbCommand;
// For the bootloader
#define CMD_DEVICE_INFO 0x0000
#define CMD_SETUP_WRITE 0x0001
#define CMD_FINISH_WRITE 0x0003
#define CMD_HARDWARE_RESET 0x0004
#define CMD_ACK 0x00ff
// For general mucking around
#define CMD_DEBUG_PRINT_STRING 0x0100
#define CMD_DEBUG_PRINT_INTEGERS 0x0101
#define CMD_DEBUG_PRINT_BYTES 0x0102
#define CMD_LCD_RESET 0x0103
#define CMD_LCD 0x0104
// For low-frequency tags
#define CMD_ACQUIRE_RAW_BITS_TI_TYPE 0x0200
#define CMD_DOWNLOAD_RAW_BITS_TI_TYPE 0x0201
#define CMD_DOWNLOADED_RAW_BITS_TI_TYPE 0x0202
#define CMD_ACQUIRE_RAW_ADC_SAMPLES_125K 0x0203
#define CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K 0x0204
#define CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K 0x0205
#define CMD_DOWNLOADED_SIM_SAMPLES_125K 0x0206
#define CMD_SIMULATE_TAG_125K 0x0207
#define CMD_HID_DEMOD_FSK 0x0208 // ## New command: demodulate HID tag ID
#define CMD_HID_SIM_TAG 0x0209 // ## New command: simulate HID tag by ID
// For the 13.56 MHz tags
#define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693 0x0300
#define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443 0x0301
#define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443_SIM 0x0302
#define CMD_READER_ISO_15693 0x0310 // ## New command to act like a 15693 reader - greg
#define CMD_SIMTAG_ISO_15693 0x0311 // ## New command to act like a 15693 reader - greg
#define CMD_SIMULATE_TAG_HF_LISTEN 0x0380
#define CMD_SIMULATE_TAG_ISO_14443 0x0381
#define CMD_SNOOP_ISO_14443 0x0382
#define CMD_SNOOP_ISO_14443a 0x0383 // ## New snoop command
#define CMD_SIMULATE_TAG_ISO_14443a 0x0384 // ## New command: Simulate tag 14443a
#define CMD_READER_ISO_14443a 0x0385 // ## New command to act like a 14443a reader
#define CMD_SIMULATE_MIFARE_CARD 0x0386
// For measurements of the antenna tuning
#define CMD_MEASURE_ANTENNA_TUNING 0x0400
#define CMD_MEASURED_ANTENNA_TUNING 0x0401
// For direct FPGA control
#define CMD_FPGA_MAJOR_MODE_OFF 0x0500 // ## FPGA Control
#endif

29
linux/Makefile Normal file
View file

@ -0,0 +1,29 @@
LDFLAGS = -lusb -lreadline -lpthread -L/opt/local/lib
CFLAGS = -I. -I/opt/local/include -Wall
CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall
QTLDFLAGS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null)
ifneq ($(QTLDFLAGS),)
QTGUI = proxgui.o proxguiqt.o proxguiqt.moc.o
CFLAGS += -DHAVE_GUI
MOC = $(shell type moc-qt4 >/dev/null 2>&1 && echo moc-qt4 || echo moc)
LINK.o = $(LINK.cpp)
else
QTGUI = guidummy.o
endif
all: proxmark3 snooper
proxmark3: LDFLAGS+=$(QTLDFLAGS)
proxmark3: proxmark3.o gui.o command.o usb.o $(QTGUI)
snooper: snooper.o gui.o command.o usb.o guidummy.o
proxguiqt.moc.cpp: proxguiqt.h
$(MOC) -o$@ $^
clean:
rm -f proxmark3 snooper *.o *.moc.cpp
.PHONY: all clean

2
linux/command.c Normal file
View file

@ -0,0 +1,2 @@
#include "translate.h"
#include "../winsrc/command.cpp"

166
linux/flasher.c Normal file
View file

@ -0,0 +1,166 @@
#include <usb.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include "translate.h"
#include "../winsrc/prox.h"
#include "proxmark3.h"
static DWORD ExpectedAddr;
static BYTE QueuedToSend[256];
static BOOL AllWritten;
static void FlushPrevious(void)
{
UsbCommand c;
memset(&c, 0, sizeof(c));
printf("expected = %08x flush, ", ExpectedAddr);
int i;
for(i = 0; i < 240; i += 48) {
c.cmd = CMD_SETUP_WRITE;
memcpy(c.d.asBytes, QueuedToSend+i, 48);
c.ext1 = (i/4);
SendCommand(&c, TRUE);
}
c.cmd = CMD_FINISH_WRITE;
c.ext1 = (ExpectedAddr-1) & (~255);
printf("c.ext1 = %08x\r", c.ext1);
memcpy(c.d.asBytes, QueuedToSend+240, 16);
SendCommand(&c, TRUE);
AllWritten = TRUE;
}
static void GotByte(DWORD where, BYTE which)
{
AllWritten = FALSE;
if(where != ExpectedAddr) {
printf("bad: got at %08x, expected at %08x\n", where, ExpectedAddr);
exit(-1);
}
QueuedToSend[where & 255] = which;
ExpectedAddr++;
if((where & 255) == 255) {
// we have completed a full page
FlushPrevious();
}
}
static int HexVal(int c)
{
c = tolower(c);
if(c >= '0' && c <= '9') {
return c - '0';
} else if(c >= 'a' && c <= 'f') {
return (c - 'a') + 10;
} else {
printf("bad hex digit '%c'\n", c);
exit(-1);
}
}
static BYTE HexByte(char *s)
{
return (HexVal(s[0]) << 4) | HexVal(s[1]);
}
static void LoadFlashFromSRecords(char *file, int addr)
{
ExpectedAddr = addr;
FILE *f = fopen(file, "r");
if(!f) {
printf("couldn't open file\n");
exit(-1);
}
char line[512];
while(fgets(line, sizeof(line), f)) {
if(memcmp(line, "S3", 2)==0) {
char *s = line + 2;
int len = HexByte(s) - 5;
s += 2;
char addrStr[9];
memcpy(addrStr, s, 8);
addrStr[8] = '\0';
DWORD addr;
sscanf(addrStr, "%x", &addr);
s += 8;
int i;
for(i = 0; i < len; i++) {
while((addr+i) > ExpectedAddr) {
GotByte(ExpectedAddr, 0xff);
}
GotByte(addr+i, HexByte(s));
s += 2;
}
}
}
if(!AllWritten) FlushPrevious();
fclose(f);
printf("\ndone.\n");
}
int main(int argc, char **argv) {
unsigned int addr = 0;
UsbCommand c;
if (argc != 3) {
fprintf(stderr,"Usage: %s {bootrom|os|fpga} image.s19\n", argv[0]);
exit(EXIT_FAILURE);
}
if (!strcmp(argv[1],"bootrom")) {
addr = 0;
} else if (!strcmp(argv[1],"os")) {
addr = 0x10000;
} else if (!strcmp(argv[1],"fpga")) {
addr = 0x2000;
} else {
fprintf(stderr,"Unknown action '%s'!\n", argv[1]);
exit(EXIT_FAILURE);
}
usb_init();
fprintf(stderr,"Waiting for Proxmark to appear on USB...\n");
while(!(devh=OpenProxmark(0))) { sleep(1); }
fprintf(stderr,"Found...\n");
fprintf(stderr,"Entering flash-mode...\n");
bzero(&c, sizeof(c));
c.cmd = CMD_START_FLASH;
SendCommand(&c, FALSE);
CloseProxmark();
sleep(1);
fprintf(stderr,"Waiting for Proxmark to reappear on USB...\n");
while(!(devh=OpenProxmark(0))) { sleep(1); }
fprintf(stderr,"Found...\n");
LoadFlashFromSRecords(argv[2], addr);
bzero(&c, sizeof(c));
c.cmd = CMD_HARDWARE_RESET;
SendCommand(&c, FALSE);
CloseProxmark();
fprintf(stderr,"Have a nice day!\n");
return 0;
}

54
linux/gui.c Normal file
View file

@ -0,0 +1,54 @@
#include <stdarg.h>
#include <stdio.h>
#include <time.h>
#include "proxgui.h"
#include "translate.h"
#include "../winsrc/prox.h"
int GraphBuffer[MAX_GRAPH_TRACE_LEN];
int GraphTraceLen;
double CursorScaleFactor;
int CommandFinished;
static char *logfilename = "proxmark3.log";
void PrintToScrollback(char *fmt, ...) {
va_list argptr;
static FILE *logfile = NULL;
static int logging=1;
if (logging && !logfile) {
logfile=fopen(logfilename, "a");
if (!logfile) {
fprintf(stderr, "Can't open logfile, logging disabled!\n");
logging=0;
}
}
va_start(argptr, fmt);
vprintf(fmt, argptr);
printf("\n");
if (logging && logfile) {
#if 0
char zeit[25];
time_t jetzt_t;
struct tm *jetzt;
jetzt_t = time(NULL);
jetzt = localtime(&jetzt_t);
strftime(zeit, 25, "%b %e %T", jetzt);
fprintf(logfile,"%s ", zeit);
#endif
vfprintf(logfile, fmt, argptr);
fprintf(logfile,"\n");
fflush(logfile);
}
va_end(argptr);
}
void setlogfilename(char *fn)
{
logfilename = fn;
}

17
linux/guidummy.c Normal file
View file

@ -0,0 +1,17 @@
#include <stdio.h>
void ShowGraphWindow(void)
{
static int warned = 0;
if (!warned) {
printf("No GUI in this build!\n");
warned = 1;
}
}
void HideGraphWindow(void) {}
void RepaintGraphWindow(void) {}
void MainGraphics() {}
void InitGraphics(int argc, char **argv) {}
void ExitGraphics(void) {}

58
linux/proxgui.cpp Normal file
View file

@ -0,0 +1,58 @@
#include "proxgui.h"
#include "proxguiqt.h"
static ProxGuiQT *gui = NULL;
extern "C" void ShowGraphWindow(void)
{
if (!gui)
return;
gui->ShowGraphWindow();
}
extern "C" void HideGraphWindow(void)
{
if (!gui)
return;
gui->HideGraphWindow();
}
extern "C" void RepaintGraphWindow(void)
{
if (!gui)
return;
gui->RepaintGraphWindow();
}
extern "C" void MainGraphics(void)
{
if (!gui)
return;
gui->MainLoop();
}
extern "C" void InitGraphics(int argc, char **argv)
{
#ifdef Q_WS_X11
bool useGUI = getenv("DISPLAY") != 0;
#else
bool useGUI = true;
#endif
if (!useGUI)
return;
gui = new ProxGuiQT(argc, argv);
}
extern "C" void ExitGraphics(void)
{
if (!gui)
return;
delete gui;
gui = NULL;
}

20
linux/proxgui.h Normal file
View file

@ -0,0 +1,20 @@
#ifdef __cplusplus
extern "C" {
#endif
void ShowGraphWindow(void);
void HideGraphWindow(void);
void RepaintGraphWindow(void);
void MainGraphics(void);
void InitGraphics(int argc, char **argv);
void ExitGraphics(void);
#define MAX_GRAPH_TRACE_LEN (1024*128)
extern int GraphBuffer[MAX_GRAPH_TRACE_LEN];
extern int GraphTraceLen;
extern double CursorScaleFactor;
extern int CommandFinished;
#ifdef __cplusplus
}
#endif

309
linux/proxguiqt.cpp Normal file
View file

@ -0,0 +1,309 @@
#include <iostream>
#include <QPainterPath>
#include <QBrush>
#include <QPen>
#include <QTimer>
#include <QCloseEvent>
#include <QMouseEvent>
#include <QKeyEvent>
#include <math.h>
#include <limits.h>
#include "proxguiqt.h"
#include "proxgui.h"
void ProxGuiQT::ShowGraphWindow(void)
{
emit ShowGraphWindowSignal();
}
void ProxGuiQT::RepaintGraphWindow(void)
{
emit RepaintGraphWindowSignal();
}
void ProxGuiQT::HideGraphWindow(void)
{
emit HideGraphWindowSignal();
}
void ProxGuiQT::_ShowGraphWindow(void)
{
if(!plotapp)
return;
if (!plotwidget)
plotwidget = new ProxWidget();
plotwidget->show();
}
void ProxGuiQT::_RepaintGraphWindow(void)
{
if (!plotapp || !plotwidget)
return;
plotwidget->update();
}
void ProxGuiQT::_HideGraphWindow(void)
{
if (!plotapp || !plotwidget)
return;
plotwidget->hide();
}
void ProxGuiQT::MainLoop()
{
plotapp = new QApplication(argc, argv);
connect(this, SIGNAL(ShowGraphWindowSignal()), this, SLOT(_ShowGraphWindow()));
connect(this, SIGNAL(RepaintGraphWindowSignal()), this, SLOT(_RepaintGraphWindow()));
connect(this, SIGNAL(HideGraphWindowSignal()), this, SLOT(_HideGraphWindow()));
plotapp->exec();
}
ProxGuiQT::ProxGuiQT(int argc, char **argv) : plotapp(NULL), plotwidget(NULL),
argc(argc), argv(argv)
{
}
ProxGuiQT::~ProxGuiQT(void)
{
if (plotwidget) {
delete plotwidget;
plotwidget = NULL;
}
if (plotapp) {
plotapp->quit();
delete plotapp;
plotapp = NULL;
}
}
void ProxWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QPainterPath penPath, whitePath, greyPath, cursorAPath, cursorBPath;
QRect r;
QBrush brush(QColor(100, 255, 100));
QPen pen(QColor(100, 255, 100));
painter.setFont(QFont("Arial", 10));
if(GraphStart < 0) {
GraphStart = 0;
}
r = rect();
painter.fillRect(r, QColor(0, 0, 0));
whitePath.moveTo(r.left() + 40, r.top());
whitePath.lineTo(r.left() + 40, r.bottom());
int zeroHeight = r.top() + (r.bottom() - r.top()) / 2;
greyPath.moveTo(r.left(), zeroHeight);
greyPath.lineTo(r.right(), zeroHeight);
painter.setPen(QColor(100, 100, 100));
painter.drawPath(greyPath);
int startMax =
(GraphTraceLen - (int)((r.right() - r.left() - 40) / GraphPixelsPerPoint));
if(startMax < 0) {
startMax = 0;
}
if(GraphStart > startMax) {
GraphStart = startMax;
}
int absYMax = 1;
int i;
for(i = GraphStart; ; i++) {
if(i >= GraphTraceLen) {
break;
}
if(fabs((double)GraphBuffer[i]) > absYMax) {
absYMax = (int)fabs((double)GraphBuffer[i]);
}
int x = 40 + (int)((i - GraphStart)*GraphPixelsPerPoint);
if(x > r.right()) {
break;
}
}
absYMax = (int)(absYMax*1.2 + 1);
// number of points that will be plotted
int span = (int)((r.right() - r.left()) / GraphPixelsPerPoint);
// one label every 100 pixels, let us say
int labels = (r.right() - r.left() - 40) / 100;
if(labels <= 0) labels = 1;
int pointsPerLabel = span / labels;
if(pointsPerLabel <= 0) pointsPerLabel = 1;
int yMin = INT_MAX;
int yMax = INT_MIN;
int yMean = 0;
int n = 0;
for(i = GraphStart; ; i++) {
if(i >= GraphTraceLen) {
break;
}
int x = 40 + (int)((i - GraphStart)*GraphPixelsPerPoint);
if(x > r.right() + GraphPixelsPerPoint) {
break;
}
int y = GraphBuffer[i];
if(y < yMin) {
yMin = y;
}
if(y > yMax) {
yMax = y;
}
yMean += y;
n++;
y = (y * (r.top() - r.bottom()) / (2*absYMax)) + zeroHeight;
if(i == GraphStart) {
penPath.moveTo(x, y);
} else {
penPath.lineTo(x, y);
}
if(GraphPixelsPerPoint > 10) {
QRect f(QPoint(x - 3, y - 3),QPoint(x + 3, y + 3));
painter.fillRect(f, brush);
}
if(((i - GraphStart) % pointsPerLabel == 0) && i != GraphStart) {
whitePath.moveTo(x, zeroHeight - 3);
whitePath.lineTo(x, zeroHeight + 3);
char str[100];
sprintf(str, "+%d", (i - GraphStart));
painter.setPen(QColor(255, 255, 255));
QRect size;
QFontMetrics metrics(painter.font());
size = metrics.boundingRect(str);
painter.drawText(x - (size.right() - size.left()), zeroHeight + 9, str);
penPath.moveTo(x,y);
}
if(i == CursorAPos || i == CursorBPos) {
QPainterPath *cursorPath;
if(i == CursorAPos) {
cursorPath = &cursorAPath;
} else {
cursorPath = &cursorBPath;
}
cursorPath->moveTo(x, r.top());
cursorPath->lineTo(x, r.bottom());
penPath.moveTo(x, y);
}
}
if(n != 0) {
yMean /= n;
}
painter.setPen(QColor(255, 255, 255));
painter.drawPath(whitePath);
painter.setPen(pen);
painter.drawPath(penPath);
painter.setPen(QColor(255, 255, 0));
painter.drawPath(cursorAPath);
painter.setPen(QColor(255, 0, 255));
painter.drawPath(cursorBPath);
char str[100];
sprintf(str, "@%d max=%d min=%d mean=%d n=%d/%d dt=%d [%.3f]",
GraphStart, yMax, yMin, yMean, n, GraphTraceLen,
CursorBPos - CursorAPos, (CursorBPos - CursorAPos)/CursorScaleFactor);
painter.setPen(QColor(255, 255, 255));
painter.drawText(50, r.bottom() - 20, str);
}
ProxWidget::ProxWidget(QWidget *parent) : QWidget(parent), GraphStart(0), GraphPixelsPerPoint(1)
{
resize(600, 500);
QPalette palette(QColor(0,0,0,0));
palette.setColor(QPalette::WindowText, QColor(255,255,255));
palette.setColor(QPalette::Text, QColor(255,255,255));
palette.setColor(QPalette::Button, QColor(100, 100, 100));
setPalette(palette);
setAutoFillBackground(true);
}
void ProxWidget::closeEvent(QCloseEvent *event)
{
event->ignore();
this->hide();
}
void ProxWidget::mouseMoveEvent(QMouseEvent *event)
{
int x = event->x();
x -= 40;
x = (int)(x / GraphPixelsPerPoint);
x += GraphStart;
if((event->buttons() & Qt::LeftButton)) {
CursorAPos = x;
} else if (event->buttons() & Qt::RightButton) {
CursorBPos = x;
}
this->update();
}
void ProxWidget::keyPressEvent(QKeyEvent *event)
{
switch(event->key()) {
case Qt::Key_Down:
if(GraphPixelsPerPoint <= 50) {
GraphPixelsPerPoint *= 2;
}
break;
case Qt::Key_Up:
if(GraphPixelsPerPoint >= 0.02) {
GraphPixelsPerPoint /= 2;
}
break;
case Qt::Key_Right:
if(GraphPixelsPerPoint < 20) {
GraphStart += (int)(20 / GraphPixelsPerPoint);
} else {
GraphStart++;
}
break;
case Qt::Key_Left:
if(GraphPixelsPerPoint < 20) {
GraphStart -= (int)(20 / GraphPixelsPerPoint);
} else {
GraphStart--;
}
break;
default:
QWidget::keyPressEvent(event);
return;
break;
}
this->update();
}

56
linux/proxguiqt.h Normal file
View file

@ -0,0 +1,56 @@
#include <QApplication>
#include <QPushButton>
#include <QObject>
#include <QWidget>
#include <QPainter>
class ProxWidget : public QWidget
{
Q_OBJECT;
private:
int GraphStart;
double GraphPixelsPerPoint;
int CursorAPos;
int CursorBPos;
public:
ProxWidget(QWidget *parent = 0);
protected:
void paintEvent(QPaintEvent *event);
void closeEvent(QCloseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event) { mouseMoveEvent(event); }
void keyPressEvent(QKeyEvent *event);
};
class ProxGuiQT : public QObject
{
Q_OBJECT;
private:
QApplication *plotapp;
ProxWidget *plotwidget;
int argc;
char **argv;
void (*main_func)(void);
public:
ProxGuiQT(int argc, char **argv);
~ProxGuiQT(void);
void ShowGraphWindow(void);
void RepaintGraphWindow(void);
void HideGraphWindow(void);
void MainLoop(void);
private slots:
void _ShowGraphWindow(void);
void _RepaintGraphWindow(void);
void _HideGraphWindow(void);
signals:
void ShowGraphWindowSignal(void);
void RepaintGraphWindowSignal(void);
void HideGraphWindowSignal(void);
};

91
linux/proxmark3.c Normal file
View file

@ -0,0 +1,91 @@
#include <usb.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <pthread.h>
#include "translate.h"
#include "../winsrc/prox.h"
#include "proxmark3.h"
#include "proxgui.h"
struct usb_receiver_arg {
int run;
};
static void *usb_receiver(void *targ) {
struct usb_receiver_arg *arg = (struct usb_receiver_arg*)targ;
UsbCommand cmdbuf;
while(arg->run) {
if (ReceiveCommandP(&cmdbuf) > 0) {
int i;
for (i=0; i<strlen(PROXPROMPT); i++)
putchar(0x08);
UsbCommandReceived(&cmdbuf);
printf(PROXPROMPT);
fflush(NULL);
}
}
pthread_exit(NULL);
}
static void *main_loop(void *targ)
{
char *cmd = NULL;
while(1) {
struct usb_receiver_arg rarg;
pthread_t reader_thread;
rarg.run=1;
pthread_create(&reader_thread, NULL, &usb_receiver, &rarg);
cmd = readline(PROXPROMPT);
rarg.run=0;
pthread_join(reader_thread, NULL);
if (cmd) {
if (cmd[0] != 0x00) {
CommandReceived(cmd);
add_history(cmd);
}
free(cmd);
} else {
printf("\n");
break;
}
}
ExitGraphics();
pthread_exit(NULL);
}
int main(int argc, char **argv)
{
pthread_t main_loop_t;
usb_init();
if (!(devh = OpenProxmark(1))) {
fprintf(stderr,"PROXMARK3: NOT FOUND!\n");
exit(1);
}
pthread_create(&main_loop_t, NULL, &main_loop, NULL);
InitGraphics(argc, argv);
MainGraphics();
pthread_join(main_loop_t, NULL);
CloseProxmark();
return 0;
}

11
linux/proxmark3.h Normal file
View file

@ -0,0 +1,11 @@
#define PROXPROMPT "proxmark3> "
extern usb_dev_handle *devh;
extern unsigned char return_on_error;
extern unsigned char error_occured;
int ReceiveCommandP(UsbCommand *c);
usb_dev_handle* OpenProxmark(int);
void CloseProxmark(void);
void setlogfilename(char *fn);

49
linux/snooper.c Normal file
View file

@ -0,0 +1,49 @@
#include <usb.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include "translate.h"
#include "../winsrc/prox.h"
#include "proxmark3.h"
#define HANDLE_ERROR if (error_occured) { \
error_occured = 0;\
break;\
}
int main()
{
usb_init();
setlogfilename("snooper.log");
return_on_error = 1;
while(1) {
while(!(devh=OpenProxmark(0))) { sleep(1); }
while(1) {
UsbCommand cmdbuf;
int i;
CommandReceived("hi14asnoop");
HANDLE_ERROR
ReceiveCommand(&cmdbuf);
HANDLE_ERROR
for (i=0; i<5; i++) {
ReceiveCommandP(&cmdbuf);
}
HANDLE_ERROR
CommandReceived("hi14alist");
HANDLE_ERROR
}
}
CloseProxmark();
return 0;
}

9
linux/translate.h Normal file
View file

@ -0,0 +1,9 @@
#define BYTE unsigned char
#define WORD unsigned short
#define DWORD unsigned int
#define TRUE 1
#define FALSE 0
#define BOOL int
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)>(b))?(b):(a))

16
linux/unbind-proxmark Executable file
View file

@ -0,0 +1,16 @@
#!/bin/sh
for i in /sys/bus/usb/devices/*; do
if grep "9ac4" "${i}/idVendor" >/dev/null 2>&1; then
echo "Found Proxmark..."
dev=`basename "${i}"`
for j in /sys/bus/usb/drivers/usbhid/*; do
if basename "${j}"|grep "^${dev}" >/dev/null; then
bound="`basename "${j}"`"
echo "Unbinding ${bound}..."
echo -n "${bound}" >/sys/bus/usb/drivers/usbhid/unbind
fi
done
fi
done

171
linux/usb.c Normal file
View file

@ -0,0 +1,171 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <usb.h>
#include <strings.h>
#include <errno.h>
#include "translate.h"
#include "../winsrc/prox.h"
#include "proxmark3.h"
usb_dev_handle *devh = NULL;
static unsigned int claimed_iface = 0;
unsigned char return_on_error = 0;
unsigned char error_occured = 0;
void SendCommand(UsbCommand *c, BOOL wantAck) {
int ret;
#if 0
printf("Sending %d bytes\n", sizeof(UsbCommand));
#endif
ret = usb_bulk_write(devh, 0x01, (char*)c, sizeof(UsbCommand), 1000);
if (ret<0) {
error_occured = 1;
if (return_on_error)
return;
fprintf(stderr, "write failed: %s!\nTrying to reopen device...\n",
usb_strerror());
if (devh) {
usb_close(devh);
devh = NULL;
}
while(!(devh=OpenProxmark(0))) { sleep(1); }
printf(PROXPROMPT);
fflush(NULL);
return;
}
if(wantAck) {
UsbCommand ack;
ReceiveCommand(&ack);
if(ack.cmd != CMD_ACK) {
printf("bad ACK\n");
exit(-1);
}
}
}
int ReceiveCommandP(UsbCommand *c) {
int ret;
bzero(c, sizeof(UsbCommand));
ret = usb_bulk_read(devh, 0x82, (char*)c, sizeof(UsbCommand), 500);
if (ret<0) {
if (ret != -ETIMEDOUT) {
error_occured = 1;
if (return_on_error)
return 0;
fprintf(stderr, "read failed: %s(%d)!\nTrying to reopen device...\n",
usb_strerror(), ret);
if (devh) {
usb_close(devh);
devh = NULL;
}
while(!(devh=OpenProxmark(0))) { sleep(1); }
printf(PROXPROMPT);
fflush(NULL);
return 0;
}
} else {
if (ret && (ret < sizeof(UsbCommand))) {
fprintf(stderr, "Read only %d instead of requested %d bytes!\n",
ret, (int)sizeof(UsbCommand));
}
#if 0
{
int i;
printf("Read %d bytes\n", ret);
for (i = 0; i < ret; i++) {
printf("0x%02X ", ((unsigned char*)c)[i]);
if (!((i+1)%8))
printf("\n");
}
printf("\n");
}
#endif
}
return ret;
}
void ReceiveCommand(UsbCommand *c) {
while(ReceiveCommandP(c)<0) {}
}
usb_dev_handle* findProxmark(int verbose, unsigned int *iface) {
struct usb_bus *busses, *bus;
usb_dev_handle *handle = NULL;
usb_find_busses();
usb_find_devices();
busses = usb_get_busses();
for (bus = busses; bus; bus = bus->next) {
struct usb_device *dev;
for (dev = bus->devices; dev; dev = dev->next) {
struct usb_device_descriptor *desc = &(dev->descriptor);
if ((desc->idProduct == 0x4b8f) && (desc->idVendor == 0x9ac4)) {
handle = usb_open(dev);
if (!handle) {
if (verbose)
fprintf(stderr, "open failed: %s!\n", usb_strerror());
return NULL;
}
*iface = dev->config[0].interface[0].altsetting[0].bInterfaceNumber;
return handle;
}
}
}
return NULL;
}
usb_dev_handle* OpenProxmark(int verbose) {
int ret;
usb_dev_handle *handle = NULL;
unsigned int iface;
#ifndef __APPLE__
handle = findProxmark(verbose, &iface);
if (!handle)
return NULL;
/* Whatever... */
usb_reset(handle);
#endif
handle = findProxmark(verbose, &iface);
if (!handle)
return NULL;
ret = usb_claim_interface(handle, iface);
if (ret<0) {
if (verbose)
fprintf(stderr, "claim failed: %s!\n", usb_strerror());
return NULL;
}
claimed_iface = iface;
devh = handle;
return handle;
}
void CloseProxmark(void) {
usb_release_interface(devh, claimed_iface);
usb_close(devh);
}

0
linux/windows.h Normal file
View file

31
winsrc/Makefile Normal file
View file

@ -0,0 +1,31 @@
BASE_DEFS = /D_WIN32_WINNT=0x501 /DISOLATION_AWARE_ENABLED /D_WIN32_IE=0x600 /DWIN32_LEAN_AND_MEAN /DWIN32 /D_MT /D_CRT_SECURE_NO_WARNINGS
BASE_CFLAGS = /W3 /nologo
DEFINES = $(BASE_DEFS)
CFLAGS = $(BASE_CFLAGS) /Zi /MT
OBJDIR = obj
OBJS = $(OBJDIR)\prox.obj \
$(OBJDIR)\gui.obj \
$(OBJDIR)\command.obj
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
HEADERS = prox.h
all: $(OBJDIR)/prox.exe
copy $(OBJDIR)\prox.exe .
clean:
del /q obj\*.obj
del /q obj\*.ilk
del /q obj\*.exe
del /q obj\*.pdb
del /q *.pdb
$(OBJDIR)/prox.exe: $(OBJS)
$(CC) $(DEFINES) $(CFLAGS) -Fe$(OBJDIR)/prox.exe $(OBJS) $(LIBS)
$(OBJS): $(@B).cpp $(HEADERS)
$(CC) $(CFLAGS) $(DEFINES) -c -Fo$(OBJDIR)/$(@B).obj $(@B).cpp

1812
winsrc/command.cpp Normal file

File diff suppressed because it is too large Load diff

510
winsrc/gui.cpp Normal file
View file

@ -0,0 +1,510 @@
//-----------------------------------------------------------------------------
// Routines for the user interface when doing interactive things with prox
// cards; this is basically a command line thing, in one window, and then
// another window to do the graphs.
// Jonathan Westhues, Sept 2005
//-----------------------------------------------------------------------------
#include <windows.h>
#include <limits.h>
#include <commctrl.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "prox.h"
#define oops() do { \
char line[100]; \
sprintf(line, "Internal error at line %d file '%s'", __LINE__, \
__FILE__); \
MessageBox(NULL, line, "Error", MB_ICONERROR); \
exit(-1); \
} while(0)
void dbp(char *str, ...)
{
va_list f;
char buf[1024];
va_start(f, str);
vsprintf(buf, str, f);
OutputDebugString(buf);
OutputDebugString("\n");
}
int GraphBuffer[MAX_GRAPH_TRACE_LEN];
int GraphTraceLen;
HPEN GreyPen, GreenPen, WhitePen, YellowPen;
HBRUSH GreenBrush, YellowBrush;
static int GraphStart = 0;
static double GraphPixelsPerPoint = 1;
static int CursorAPos;
static int CursorBPos;
double CursorScaleFactor = 1.0;
static HPEN CursorAPen;
static HPEN CursorBPen;
static HWND CommandWindow;
static HWND GraphWindow;
static HWND ScrollbackEdit;
static HWND CommandEdit;
#define COMMAND_HISTORY_MAX 16
static char CommandHistory[COMMAND_HISTORY_MAX][256];
static int CommandHistoryPos = -1;
static int CommandHistoryNext;
static HFONT MyFixedFont;
#define FixedFont(x) SendMessage((x), WM_SETFONT, (WPARAM)MyFixedFont, TRUE)
void ExecCmd(char *cmd)
{
}
int CommandFinished;
static void ResizeCommandWindow(void)
{
int w, h;
RECT r;
GetClientRect(CommandWindow, &r);
w = r.right - r.left;
h = r.bottom - r.top;
MoveWindow(ScrollbackEdit, 10, 10, w - 20, h - 50, TRUE);
MoveWindow(CommandEdit, 10, h - 29, w - 20, 22, TRUE);
}
void RepaintGraphWindow(void)
{
InvalidateRect(GraphWindow, NULL, TRUE);
}
static LRESULT CALLBACK
CommandWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_DESTROY:
case WM_QUIT:
exit(0);
return 0;
case WM_SIZE:
ResizeCommandWindow();
return 0;
case WM_SETFOCUS:
SetFocus(CommandEdit);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 1;
}
static void PaintGraph(HDC hdc)
{
HBRUSH brush;
HPEN pen;
brush = GreenBrush;
pen = GreenPen;
if(GraphStart < 0) {
GraphStart = 0;
}
RECT r;
GetClientRect(GraphWindow, &r);
SelectObject(hdc, WhitePen);
MoveToEx(hdc, r.left + 40, r.top, NULL);
LineTo(hdc, r.left + 40, r.bottom);
int zeroHeight = r.top + (r.bottom - r.top) / 2;
SelectObject(hdc, GreyPen);
MoveToEx(hdc, r.left, zeroHeight, NULL);
LineTo(hdc, r.right, zeroHeight);
int startMax =
(GraphTraceLen - (int)((r.right - r.left - 40) / GraphPixelsPerPoint));
if(startMax < 0) {
startMax = 0;
}
if(GraphStart > startMax) {
GraphStart = startMax;
}
int absYMax = 1;
SelectObject(hdc, pen);
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);
SelectObject(hdc, MyFixedFont);
SetTextColor(hdc, RGB(255, 255, 255));
SetBkColor(hdc, RGB(0, 0, 0));
// 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) {
MoveToEx(hdc, x, y, NULL);
} else {
LineTo(hdc, x, y);
}
if(GraphPixelsPerPoint > 10) {
RECT f;
f.left = x - 3;
f.top = y - 3;
f.right = x + 3;
f.bottom = y + 3;
FillRect(hdc, &f, brush);
}
if(((i - GraphStart) % pointsPerLabel == 0) && i != GraphStart) {
SelectObject(hdc, WhitePen);
MoveToEx(hdc, x, zeroHeight - 3, NULL);
LineTo(hdc, x, zeroHeight + 3);
char str[100];
sprintf(str, "+%d", (i - GraphStart));
SIZE size;
GetTextExtentPoint32(hdc, str, strlen(str), &size);
TextOut(hdc, x - size.cx, zeroHeight + 8, str, strlen(str));
SelectObject(hdc, pen);
MoveToEx(hdc, x, y, NULL);
}
if(i == CursorAPos || i == CursorBPos) {
if(i == CursorAPos) {
SelectObject(hdc, CursorAPen);
} else {
SelectObject(hdc, CursorBPen);
}
MoveToEx(hdc, x, r.top, NULL);
LineTo(hdc, x, r.bottom);
SelectObject(hdc, pen);
MoveToEx(hdc, x, y, NULL);
}
}
if(n != 0) {
yMean /= n;
}
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);
TextOut(hdc, 50, r.bottom - 20, str, strlen(str));
}
static LRESULT CALLBACK
GraphWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_DESTROY:
case WM_QUIT:
GraphWindow = NULL;
return DefWindowProc(hwnd, msg, wParam, lParam);
case WM_SIZE:
RepaintGraphWindow();
return 0;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
if(GraphStart < 0) {
GraphStart = 0;
}
// This draws the trace.
PaintGraph(hdc);
EndPaint(hwnd, &ps);
break;
}
case WM_KEYDOWN:
switch(wParam) {
case VK_DOWN:
if(GraphPixelsPerPoint <= 50) {
GraphPixelsPerPoint *= 2;
}
break;
case VK_UP:
if(GraphPixelsPerPoint >= 0.02) {
GraphPixelsPerPoint /= 2;
}
break;
case VK_RIGHT:
if(GraphPixelsPerPoint < 20) {
GraphStart += (int)(20 / GraphPixelsPerPoint);
} else {
GraphStart++;
}
break;
case VK_LEFT:
if(GraphPixelsPerPoint < 20) {
GraphStart -= (int)(20 / GraphPixelsPerPoint);
} else {
GraphStart--;
}
break;
default:
goto nopaint;
}
RepaintGraphWindow();
nopaint:
break;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN: {
int x = LOWORD(lParam);
x -= 40;
x = (int)(x / GraphPixelsPerPoint);
x += GraphStart;
if(msg == WM_LBUTTONDOWN) {
CursorAPos = x;
} else {
CursorBPos = x;
}
RepaintGraphWindow();
break;
}
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 1;
}
void PrintToScrollback(char *fmt, ...)
{
va_list f;
char str[1024];
strcpy(str, "\r\n");
va_start(f, fmt);
vsprintf(str+2, fmt, f);
static char TextBuf[1024*32];
SendMessage(ScrollbackEdit, WM_GETTEXT, (WPARAM)sizeof(TextBuf),
(LPARAM)TextBuf);
if(strlen(TextBuf) + strlen(str) + 1 <= sizeof(TextBuf)) {
strcat(TextBuf, str);
} else {
lstrcpyn(TextBuf, str, sizeof(TextBuf));
}
SendMessage(ScrollbackEdit, WM_SETTEXT, 0, (LPARAM)TextBuf);
SendMessage(ScrollbackEdit, EM_LINESCROLL, 0, (LPARAM)INT_MAX);
}
void ShowGraphWindow(void)
{
if(GraphWindow) return;
GraphWindow = CreateWindowEx(0, "Graph", "graphed",
WS_OVERLAPPED | WS_BORDER | WS_MINIMIZEBOX | WS_SYSMENU |
WS_SIZEBOX | WS_VISIBLE, 200, 150, 600, 500, NULL, NULL, NULL,
NULL);
if(!GraphWindow) oops();
}
void HideGraphWindow(void)
{
if(GraphWindow) {
DestroyWindow(GraphWindow);
GraphWindow = NULL;
}
}
static void SetCommandEditTo(char *str)
{
SendMessage(CommandEdit, WM_SETTEXT, 0, (LPARAM)str);
SendMessage(CommandEdit, EM_SETSEL, strlen(str), strlen(str));
}
void ShowGui(void)
{
WNDCLASSEX wc;
memset(&wc, 0, sizeof(wc));
wc.cbSize = sizeof(wc);
wc.style = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC)CommandWindowProc;
wc.hInstance = NULL;
wc.hbrBackground = (HBRUSH)(COLOR_BTNSHADOW);
wc.lpszClassName = "Command";
wc.lpszMenuName = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
if(!RegisterClassEx(&wc)) oops();
wc.lpszClassName = "Graph";
wc.lpfnWndProc = (WNDPROC)GraphWindowProc;
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
if(!RegisterClassEx(&wc)) oops();
CommandWindow = CreateWindowEx(0, "Command", "prox",
WS_OVERLAPPED | WS_BORDER | WS_MINIMIZEBOX | WS_SYSMENU |
WS_SIZEBOX | WS_VISIBLE, 20, 20, 500, 400, NULL, NULL, NULL,
NULL);
if(!CommandWindow) oops();
ScrollbackEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "edit", "",
WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | ES_MULTILINE |
ES_AUTOVSCROLL | WS_VSCROLL, 0, 0, 0, 0, CommandWindow, NULL,
NULL, NULL);
CommandEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "edit", "",
WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | WS_VISIBLE |
ES_AUTOHSCROLL, 0, 0, 0, 0, CommandWindow, NULL, NULL, NULL);
MyFixedFont = CreateFont(14, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
FF_DONTCARE, "Lucida Console");
if(!MyFixedFont)
MyFixedFont = (HFONT)GetStockObject(SYSTEM_FONT);
FixedFont(ScrollbackEdit);
FixedFont(CommandEdit);
ResizeCommandWindow();
SetFocus(CommandEdit);
PrintToScrollback(">> Started prox, built " __DATE__ " " __TIME__);
PrintToScrollback(">> Connected to device");
GreyPen = CreatePen(PS_SOLID, 1, RGB(100, 100, 100));
GreenPen = CreatePen(PS_SOLID, 1, RGB(100, 255, 100));
YellowPen = CreatePen(PS_SOLID, 1, RGB(255, 255, 0));
GreenBrush = CreateSolidBrush(RGB(100, 255, 100));
YellowBrush = CreateSolidBrush(RGB(255, 255, 0));
WhitePen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
CursorAPen = CreatePen(PS_DASH, 1, RGB(255, 255, 0));
CursorBPen = CreatePen(PS_DASH, 1, RGB(255, 0, 255));
MSG msg;
for(;;) {
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if(msg.message == WM_KEYDOWN && msg.wParam == VK_RETURN) {
char got[1024];
SendMessage(CommandEdit, WM_GETTEXT, (WPARAM)sizeof(got),
(LPARAM)got);
if(strcmp(got, "cls")==0) {
SendMessage(ScrollbackEdit, WM_SETTEXT, 0, (LPARAM)"");
} else {
CommandReceived(got);
}
SendMessage(CommandEdit, WM_SETTEXT, 0, (LPARAM)"");
// Insert it into the command history, unless it is
// identical to the previous command in the history.
int prev = CommandHistoryNext - 1;
if(prev < 0) prev += COMMAND_HISTORY_MAX;
if(strcmp(CommandHistory[prev], got) != 0) {
strcpy(CommandHistory[CommandHistoryNext], got);
CommandHistoryNext++;
if(CommandHistoryNext == COMMAND_HISTORY_MAX) {
CommandHistoryNext = 0;
}
}
CommandHistoryPos = -1;
} else if(msg.message == WM_KEYDOWN && msg.wParam == VK_UP &&
msg.hwnd == CommandEdit)
{
if(CommandHistoryPos == -1) {
CommandHistoryPos = CommandHistoryNext;
}
CommandHistoryPos--;
if(CommandHistoryPos < 0) {
CommandHistoryPos = COMMAND_HISTORY_MAX-1;
}
SetCommandEditTo(CommandHistory[CommandHistoryPos]);
} else if(msg.message == WM_KEYDOWN && msg.wParam == VK_DOWN &&
msg.hwnd == CommandEdit)
{
CommandHistoryPos++;
if(CommandHistoryPos >= COMMAND_HISTORY_MAX) {
CommandHistoryPos = 0;
}
SetCommandEditTo(CommandHistory[CommandHistoryPos]);
} else if(msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE &&
msg.hwnd == CommandEdit)
{
SendMessage(CommandEdit, WM_SETTEXT, 0, (LPARAM)"");
} else {
if(msg.message == WM_KEYDOWN) {
CommandHistoryPos = -1;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
UsbCommand c;
if(ReceiveCommandPoll(&c)) {
UsbCommandReceived(&c);
}
Sleep(10);
}
}

1787
winsrc/include/hidpi.h Normal file

File diff suppressed because it is too large Load diff

412
winsrc/include/hidsdi.h Normal file
View file

@ -0,0 +1,412 @@
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
HIDSDI.H
Abstract:
This module contains the PUBLIC definitions for the
code that implements the HID dll.
Environment:
Kernel & user mode
--*/
#ifndef _HIDSDI_H
#define _HIDSDI_H
#include <pshpack4.h>
//#include "wtypes.h"
//#include <windef.h>
//#include <win32.h>
//#include <basetyps.h>
typedef LONG NTSTATUS;
#include "hidusage.h"
#include "hidpi.h"
typedef struct _HIDD_CONFIGURATION {
PVOID cookie;
ULONG size;
ULONG RingBufferSize;
} HIDD_CONFIGURATION, *PHIDD_CONFIGURATION;
typedef struct _HIDD_ATTRIBUTES {
ULONG Size; // = sizeof (struct _HIDD_ATTRIBUTES)
//
// Vendor ids of this hid device
//
USHORT VendorID;
USHORT ProductID;
USHORT VersionNumber;
//
// Additional fields will be added to the end of this structure.
//
} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
BOOLEAN __stdcall
HidD_GetAttributes (
IN HANDLE HidDeviceObject,
OUT PHIDD_ATTRIBUTES Attributes
);
/*++
Routine Description:
Fill in the given HIDD_ATTRIBUTES structure with the attributes of the
given hid device.
--*/
void __stdcall
HidD_GetHidGuid (
OUT LPGUID HidGuid
);
BOOLEAN __stdcall
HidD_GetPreparsedData (
IN HANDLE HidDeviceObject,
OUT PHIDP_PREPARSED_DATA * PreparsedData
);
/*++
Routine Description:
Given a handle to a valid Hid Class Device Object, retrieve the preparsed
data for the device. This routine will allocate the appropriately
sized buffer to hold this preparsed data. It is up to client to call
HidP_FreePreparsedData to free the memory allocated to this structure when
it is no longer needed.
Arguments:
HidDeviceObject A handle to a Hid Device that the client obtains using
a call to CreateFile on a valid Hid device string name.
The string name can be obtained using standard PnP calls.
PreparsedData An opaque data structure used by other functions in this
library to retrieve information about a given device.
Return Value:
TRUE if successful.
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_FreePreparsedData (
IN PHIDP_PREPARSED_DATA PreparsedData
);
BOOLEAN __stdcall
HidD_FlushQueue (
IN HANDLE HidDeviceObject
);
/*++
Routine Description:
Flush the input queue for the given HID device.
Arguments:
HidDeviceObject A handle to a Hid Device that the client obtains using
a call to CreateFile on a valid Hid device string name.
The string name can be obtained using standard PnP calls.
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_GetConfiguration (
IN HANDLE HidDeviceObject,
OUT PHIDD_CONFIGURATION Configuration,
IN ULONG ConfigurationLength
);
/*++
Routine Description:
Get the configuration information for this Hid device
Arguments:
HidDeviceObject A handle to a Hid Device Object.
Configuration A configuration structure. HidD_GetConfiguration MUST
be called before the configuration can be modified and
set using HidD_SetConfiguration
ConfigurationLength That is ``sizeof (HIDD_CONFIGURATION)''. Using this
parameter, we can later increase the length of the
configuration array and not break older apps.
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_SetConfiguration (
IN HANDLE HidDeviceObject,
IN PHIDD_CONFIGURATION Configuration,
IN ULONG ConfigurationLength
);
/*++
Routine Description:
Set the configuration information for this Hid device...
NOTE: HidD_GetConfiguration must be called to retrieve the current
configuration information before this information can be modified
and set.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
Configuration A configuration structure. HidD_GetConfiguration MUST
be called before the configuration can be modified and
set using HidD_SetConfiguration
ConfigurationLength That is ``sizeof (HIDD_CONFIGURATION)''. Using this
parameter, we can later increase the length of the
configuration array and not break older apps.
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_GetFeature (
IN HANDLE HidDeviceObject,
OUT PVOID ReportBuffer,
IN ULONG ReportBufferLength
);
/*++
Routine Description:
Retrieve a feature report from a HID device.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
ReportBuffer The buffer that the feature report should be placed
into. The first byte of the buffer should be set to
the report ID of the desired report
ReportBufferLength The size (in bytes) of ReportBuffer. This value
should be greater than or equal to the
FeatureReportByteLength field as specified in the
HIDP_CAPS structure for the device
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_SetFeature (
IN HANDLE HidDeviceObject,
IN PVOID ReportBuffer,
IN ULONG ReportBufferLength
);
/*++
Routine Description:
Send a feature report to a HID device.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
ReportBuffer The buffer of the feature report to send to the device
ReportBufferLength The size (in bytes) of ReportBuffer. This value
should be greater than or equal to the
FeatureReportByteLength field as specified in the
HIDP_CAPS structure for the device
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_GetNumInputBuffers (
IN HANDLE HidDeviceObject,
OUT PULONG NumberBuffers
);
/*++
Routine Description:
This function returns the number of input buffers used by the specified
file handle to the Hid device. Each file object has a number of buffers
associated with it to queue reports read from the device but which have
not yet been read by the user-mode app with a handle to that device.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
NumberBuffers Number of buffers currently being used for this file
handle to the Hid device
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_SetNumInputBuffers (
IN HANDLE HidDeviceObject,
OUT ULONG NumberBuffers
);
/*++
Routine Description:
This function sets the number of input buffers used by the specified
file handle to the Hid device. Each file object has a number of buffers
associated with it to queue reports read from the device but which have
not yet been read by the user-mode app with a handle to that device.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
NumberBuffers New number of buffers to use for this file handle to
the Hid device
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_GetPhysicalDescriptor (
IN HANDLE HidDeviceObject,
OUT PVOID Buffer,
IN ULONG BufferLength
);
/*++
Routine Description:
This function retrieves the raw physical descriptor for the specified
Hid device.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
Buffer Buffer which on return will contain the physical
descriptor if one exists for the specified device
handle
BufferLength Length of buffer (in bytes)
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_GetManufacturerString (
IN HANDLE HidDeviceObject,
OUT PVOID Buffer,
IN ULONG BufferLength
);
/*++
Routine Description:
This function retrieves the manufacturer string from the specified
Hid device.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
Buffer Buffer which on return will contain the manufacturer
string returned from the device. This string is a
wide-character string
BufferLength Length of Buffer (in bytes)
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_GetProductString (
IN HANDLE HidDeviceObject,
OUT PVOID Buffer,
IN ULONG BufferLength
);
/*++
Routine Description:
This function retrieves the product string from the specified
Hid device.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
Buffer Buffer which on return will contain the product
string returned from the device. This string is a
wide-character string
BufferLength Length of Buffer (in bytes)
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_GetIndexedString (
IN HANDLE HidDeviceObject,
IN ULONG StringIndex,
OUT PVOID Buffer,
IN ULONG BufferLength
);
/*++
Routine Description:
This function retrieves a string from the specified Hid device that is
specified with a certain string index.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
StringIndex Index of the string to retrieve
Buffer Buffer which on return will contain the product
string returned from the device. This string is a
wide-character string
BufferLength Length of Buffer (in bytes)
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_GetSerialNumberString (
IN HANDLE HidDeviceObject,
OUT PVOID Buffer,
IN ULONG BufferLength
);
/*++
Routine Description:
This function retrieves the serial number string from the specified
Hid device.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
Buffer Buffer which on return will contain the serial number
string returned from the device. This string is a
wide-character string
BufferLength Length of Buffer (in bytes)
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
#include <poppack.h>
#endif

263
winsrc/include/hidusage.h Normal file
View file

@ -0,0 +1,263 @@
/*++
Copyright (c) 1996, 1997 Microsoft Corporation
Module Name:
HIDUSAGE.H
Abstract:
Public Definitions of HID USAGES.
Environment:
Kernel & user mode
--*/
#ifndef __HIDUSAGE_H__
#define __HIDUSAGE_H__
//
// Usage Pages
//
typedef USHORT USAGE, *PUSAGE;
#define HID_USAGE_PAGE_GENERIC ((USAGE) 0x01)
#define HID_USAGE_PAGE_SIMULATION ((USAGE) 0x02)
#define HID_USAGE_PAGE_VR ((USAGE) 0x03)
#define HID_USAGE_PAGE_SPORT ((USAGE) 0x04)
#define HID_USAGE_PAGE_GAME ((USAGE) 0x05)
#define HID_USAGE_PAGE_KEYBOARD ((USAGE) 0x07)
#define HID_USAGE_PAGE_LED ((USAGE) 0x08)
#define HID_USAGE_PAGE_BUTTON ((USAGE) 0x09)
#define HID_USAGE_PAGE_ORDINAL ((USAGE) 0x0A)
#define HID_USAGE_PAGE_TELEPHONY ((USAGE) 0x0B)
#define HID_USAGE_PAGE_CONSUMER ((USAGE) 0x0C)
#define HID_USAGE_PAGE_DIGITIZER ((USAGE) 0x0D)
#define HID_USAGE_PAGE_UNICODE ((USAGE) 0x10)
#define HID_USAGE_PAGE_ALPHANUMERIC ((USAGE) 0x14)
//
// Usages from Generic Desktop Page (0x01)
//
#define HID_USAGE_GENERIC_POINTER ((USAGE) 0x01)
#define HID_USAGE_GENERIC_MOUSE ((USAGE) 0x02)
#define HID_USAGE_GENERIC_JOYSTICK ((USAGE) 0x04)
#define HID_USAGE_GENERIC_GAMEPAD ((USAGE) 0x05)
#define HID_USAGE_GENERIC_KEYBOARD ((USAGE) 0x06)
#define HID_USAGE_GENERIC_KEYPAD ((USAGE) 0x07)
#define HID_USAGE_GENERIC_SYSTEM_CTL ((USAGE) 0x80)
#define HID_USAGE_GENERIC_X ((USAGE) 0x30)
#define HID_USAGE_GENERIC_Y ((USAGE) 0x31)
#define HID_USAGE_GENERIC_Z ((USAGE) 0x32)
#define HID_USAGE_GENERIC_RX ((USAGE) 0x33)
#define HID_USAGE_GENERIC_RY ((USAGE) 0x34)
#define HID_USAGE_GENERIC_RZ ((USAGE) 0x35)
#define HID_USAGE_GENERIC_SLIDER ((USAGE) 0x36)
#define HID_USAGE_GENERIC_DIAL ((USAGE) 0x37)
#define HID_USAGE_GENERIC_WHEEL ((USAGE) 0x38)
#define HID_USAGE_GENERIC_HATSWITCH ((USAGE) 0x39)
#define HID_USAGE_GENERIC_COUNTED_BUFFER ((USAGE) 0x3A)
#define HID_USAGE_GENERIC_BYTE_COUNT ((USAGE) 0x3B)
#define HID_USAGE_GENERIC_MOTION_WAKEUP ((USAGE) 0x3C)
#define HID_USAGE_GENERIC_VX ((USAGE) 0x40)
#define HID_USAGE_GENERIC_VY ((USAGE) 0x41)
#define HID_USAGE_GENERIC_VZ ((USAGE) 0x42)
#define HID_USAGE_GENERIC_VBRX ((USAGE) 0x43)
#define HID_USAGE_GENERIC_VBRY ((USAGE) 0x44)
#define HID_USAGE_GENERIC_VBRZ ((USAGE) 0x45)
#define HID_USAGE_GENERIC_VNO ((USAGE) 0x46)
#define HID_USAGE_GENERIC_SYSCTL_POWER ((USAGE) 0x81)
#define HID_USAGE_GENERIC_SYSCTL_SLEEP ((USAGE) 0x82)
#define HID_USAGE_GENERIC_SYSCTL_WAKE ((USAGE) 0x83)
#define HID_USAGE_GENERIC_SYSCTL_CONTEXT_MENU ((USAGE) 0x84)
#define HID_USAGE_GENERIC_SYSCTL_MAIN_MENU ((USAGE) 0x85)
#define HID_USAGE_GENERIC_SYSCTL_APP_MENU ((USAGE) 0x86)
#define HID_USAGE_GENERIC_SYSCTL_HELP_MENU ((USAGE) 0x87)
#define HID_USAGE_GENERIC_SYSCTL_MENU_EXIT ((USAGE) 0x88)
#define HID_USAGE_GENERIC_SYSCTL_MENU_SELECT ((USAGE) 0x89)
#define HID_USAGE_GENERIC_SYSCTL_MENU_RIGHT ((USAGE) 0x8A)
#define HID_USAGE_GENERIC_SYSCTL_MENU_LEFT ((USAGE) 0x8B)
#define HID_USAGE_GENERIC_SYSCTL_MENU_UP ((USAGE) 0x8C)
#define HID_USAGE_GENERIC_SYSCTL_MENU_DOWN ((USAGE) 0x8D)
//
// Usages from Simulation Controls Page (0x02)
//
#define HID_USAGE_SIMULATION_RUDDER ((USAGE) 0xBA)
#define HID_USAGE_SIMULATION_THROTTLE ((USAGE) 0xBB)
//
// Virtual Reality Controls Page (0x03)
//
//
// Sport Controls Page (0x04)
//
//
// Game Controls Page (0x05)
//
//
// Keyboard/Keypad Page (0x07)
//
// Error "keys"
#define HID_USAGE_KEYBOARD_NOEVENT ((USAGE) 0x00)
#define HID_USAGE_KEYBOARD_ROLLOVER ((USAGE) 0x01)
#define HID_USAGE_KEYBOARD_POSTFAIL ((USAGE) 0x02)
#define HID_USAGE_KEYBOARD_UNDEFINED ((USAGE) 0x03)
// Letters
#define HID_USAGE_KEYBOARD_aA ((USAGE) 0x04)
#define HID_USAGE_KEYBOARD_zZ ((USAGE) 0x1D)
// Numbers
#define HID_USAGE_KEYBOARD_ONE ((USAGE) 0x1E)
#define HID_USAGE_KEYBOARD_ZERO ((USAGE) 0x27)
// Modifier Keys
#define HID_USAGE_KEYBOARD_LCTRL ((USAGE) 0xE0)
#define HID_USAGE_KEYBOARD_LSHFT ((USAGE) 0xE1)
#define HID_USAGE_KEYBOARD_LALT ((USAGE) 0xE2)
#define HID_USAGE_KEYBOARD_LGUI ((USAGE) 0xE3)
#define HID_USAGE_KEYBOARD_RCTRL ((USAGE) 0xE4)
#define HID_USAGE_KEYBOARD_RSHFT ((USAGE) 0xE5)
#define HID_USAGE_KEYBOARD_RALT ((USAGE) 0xE6)
#define HID_USAGE_KEYBOARD_RGUI ((USAGE) 0xE7)
#define HID_USAGE_KEYBOARD_SCROLL_LOCK ((USAGE) 0x47)
#define HID_USAGE_KEYBOARD_NUM_LOCK ((USAGE) 0x53)
#define HID_USAGE_KEYBOARD_CAPS_LOCK ((USAGE) 0x39)
// Funtion keys
#define HID_USAGE_KEYBOARD_F1 ((USAGE) 0x3A)
#define HID_USAGE_KEYBOARD_F12 ((USAGE) 0x45)
#define HID_USAGE_KEYBOARD_RETURN ((USAGE) 0x28)
#define HID_USAGE_KEYBOARD_ESCAPE ((USAGE) 0x29)
#define HID_USAGE_KEYBOARD_DELETE ((USAGE) 0x2A)
#define HID_USAGE_KEYBOARD_PRINT_SCREEN ((USAGE) 0x46)
// and hundreds more...
//
// LED Page (0x08)
//
#define HID_USAGE_LED_NUM_LOCK ((USAGE) 0x01)
#define HID_USAGE_LED_CAPS_LOCK ((USAGE) 0x02)
#define HID_USAGE_LED_SCROLL_LOCK ((USAGE) 0x03)
#define HID_USAGE_LED_COMPOSE ((USAGE) 0x04)
#define HID_USAGE_LED_KANA ((USAGE) 0x05)
#define HID_USAGE_LED_POWER ((USAGE) 0x06)
#define HID_USAGE_LED_SHIFT ((USAGE) 0x07)
#define HID_USAGE_LED_DO_NOT_DISTURB ((USAGE) 0x08)
#define HID_USAGE_LED_MUTE ((USAGE) 0x09)
#define HID_USAGE_LED_TONE_ENABLE ((USAGE) 0x0A)
#define HID_USAGE_LED_HIGH_CUT_FILTER ((USAGE) 0x0B)
#define HID_USAGE_LED_LOW_CUT_FILTER ((USAGE) 0x0C)
#define HID_USAGE_LED_EQUALIZER_ENABLE ((USAGE) 0x0D)
#define HID_USAGE_LED_SOUND_FIELD_ON ((USAGE) 0x0E)
#define HID_USAGE_LED_SURROUND_FIELD_ON ((USAGE) 0x0F)
#define HID_USAGE_LED_REPEAT ((USAGE) 0x10)
#define HID_USAGE_LED_STEREO ((USAGE) 0x11)
#define HID_USAGE_LED_SAMPLING_RATE_DETECT ((USAGE) 0x12)
#define HID_USAGE_LED_SPINNING ((USAGE) 0x13)
#define HID_USAGE_LED_CAV ((USAGE) 0x14)
#define HID_USAGE_LED_CLV ((USAGE) 0x15)
#define HID_USAGE_LED_RECORDING_FORMAT_DET ((USAGE) 0x16)
#define HID_USAGE_LED_OFF_HOOK ((USAGE) 0x17)
#define HID_USAGE_LED_RING ((USAGE) 0x18)
#define HID_USAGE_LED_MESSAGE_WAITING ((USAGE) 0x19)
#define HID_USAGE_LED_DATA_MODE ((USAGE) 0x1A)
#define HID_USAGE_LED_BATTERY_OPERATION ((USAGE) 0x1B)
#define HID_USAGE_LED_BATTERY_OK ((USAGE) 0x1C)
#define HID_USAGE_LED_BATTERY_LOW ((USAGE) 0x1D)
#define HID_USAGE_LED_SPEAKER ((USAGE) 0x1E)
#define HID_USAGE_LED_HEAD_SET ((USAGE) 0x1F)
#define HID_USAGE_LED_HOLD ((USAGE) 0x20)
#define HID_USAGE_LED_MICROPHONE ((USAGE) 0x21)
#define HID_USAGE_LED_COVERAGE ((USAGE) 0x22)
#define HID_USAGE_LED_NIGHT_MODE ((USAGE) 0x23)
#define HID_USAGE_LED_SEND_CALLS ((USAGE) 0x24)
#define HID_USAGE_LED_CALL_PICKUP ((USAGE) 0x25)
#define HID_USAGE_LED_CONFERENCE ((USAGE) 0x26)
#define HID_USAGE_LED_STAND_BY ((USAGE) 0x27)
#define HID_USAGE_LED_CAMERA_ON ((USAGE) 0x28)
#define HID_USAGE_LED_CAMERA_OFF ((USAGE) 0x29)
#define HID_USAGE_LED_ON_LINE ((USAGE) 0x2A)
#define HID_USAGE_LED_OFF_LINE ((USAGE) 0x2B)
#define HID_USAGE_LED_BUSY ((USAGE) 0x2C)
#define HID_USAGE_LED_READY ((USAGE) 0x2D)
#define HID_USAGE_LED_PAPER_OUT ((USAGE) 0x2E)
#define HID_USAGE_LED_PAPER_JAM ((USAGE) 0x2F)
#define HID_USAGE_LED_REMOTE ((USAGE) 0x30)
#define HID_USAGE_LED_FORWARD ((USAGE) 0x31)
#define HID_USAGE_LED_REVERSE ((USAGE) 0x32)
#define HID_USAGE_LED_STOP ((USAGE) 0x33)
#define HID_USAGE_LED_REWIND ((USAGE) 0x34)
#define HID_USAGE_LED_FAST_FORWARD ((USAGE) 0x35)
#define HID_USAGE_LED_PLAY ((USAGE) 0x36)
#define HID_USAGE_LED_PAUSE ((USAGE) 0x37)
#define HID_USAGE_LED_RECORD ((USAGE) 0x38)
#define HID_USAGE_LED_ERROR ((USAGE) 0x39)
#define HID_USAGE_LED_SELECTED_INDICATOR ((USAGE) 0x3A)
#define HID_USAGE_LED_IN_USE_INDICATOR ((USAGE) 0x3B)
#define HID_USAGE_LED_MULTI_MODE_INDICATOR ((USAGE) 0x3C)
#define HID_USAGE_LED_INDICATOR_ON ((USAGE) 0x3D)
#define HID_USAGE_LED_INDICATOR_FLASH ((USAGE) 0x3E)
#define HID_USAGE_LED_INDICATOR_SLOW_BLINK ((USAGE) 0x3F)
#define HID_USAGE_LED_INDICATOR_FAST_BLINK ((USAGE) 0x40)
#define HID_USAGE_LED_INDICATOR_OFF ((USAGE) 0x41)
#define HID_USAGE_LED_FLASH_ON_TIME ((USAGE) 0x42)
#define HID_USAGE_LED_SLOW_BLINK_ON_TIME ((USAGE) 0x43)
#define HID_USAGE_LED_SLOW_BLINK_OFF_TIME ((USAGE) 0x44)
#define HID_USAGE_LED_FAST_BLINK_ON_TIME ((USAGE) 0x45)
#define HID_USAGE_LED_FAST_BLINK_OFF_TIME ((USAGE) 0x46)
#define HID_USAGE_LED_INDICATOR_COLOR ((USAGE) 0x47)
#define HID_USAGE_LED_RED ((USAGE) 0x48)
#define HID_USAGE_LED_GREEN ((USAGE) 0x49)
#define HID_USAGE_LED_AMBER ((USAGE) 0x4A)
#define HID_USAGE_LED_GENERIC_INDICATOR ((USAGE) 0x3B)
//
// Button Page (0x09)
//
// There is no need to label these usages.
//
//
// Ordinal Page (0x0A)
//
// There is no need to label these usages.
//
//
// Telephony Device Page (0x0B)
//
#define HID_USAGE_TELEPHONY_PHONE ((USAGE) 0x01)
#define HID_USAGE_TELEPHONY_ANSWERING_MACHINE ((USAGE) 0x02)
#define HID_USAGE_TELEPHONY_MESSAGE_CONTROLS ((USAGE) 0x03)
#define HID_USAGE_TELEPHONY_HANDSET ((USAGE) 0x04)
#define HID_USAGE_TELEPHONY_HEADSET ((USAGE) 0x05)
#define HID_USAGE_TELEPHONY_KEYPAD ((USAGE) 0x06)
#define HID_USAGE_TELEPHONY_PROGRAMMABLE_BUTTON ((USAGE) 0x07)
//
// and others...
//
#endif

379
winsrc/prox.cpp Normal file
View file

@ -0,0 +1,379 @@
#include <windows.h>
#include <setupapi.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
extern "C" {
#include "include/hidsdi.h"
#include "include/hidpi.h"
}
#include "prox.h"
#define OUR_VID 0x9ac4
#define OUR_PID 0x4b8f
HANDLE UsbHandle;
static void ShowError(void)
{
char buf[1024];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
buf, sizeof(buf), NULL);
printf("ERROR: %s", buf);
}
static BOOL UsbConnect(void)
{
typedef void (__stdcall *GetGuidProc)(GUID *);
typedef BOOLEAN (__stdcall *GetAttrProc)(HANDLE, HIDD_ATTRIBUTES *);
typedef BOOLEAN (__stdcall *GetPreparsedProc)(HANDLE,
PHIDP_PREPARSED_DATA *);
typedef NTSTATUS (__stdcall *GetCapsProc)(PHIDP_PREPARSED_DATA, PHIDP_CAPS);
GetGuidProc getGuid;
GetAttrProc getAttr;
GetPreparsedProc getPreparsed;
GetCapsProc getCaps;
HMODULE h = LoadLibrary("hid.dll");
getGuid = (GetGuidProc)GetProcAddress(h, "HidD_GetHidGuid");
getAttr = (GetAttrProc)GetProcAddress(h, "HidD_GetAttributes");
getPreparsed = (GetPreparsedProc)GetProcAddress(h, "HidD_GetPreparsedData");
getCaps = (GetCapsProc)GetProcAddress(h, "HidP_GetCaps");
GUID hidGuid;
getGuid(&hidGuid);
HDEVINFO devInfo;
devInfo = SetupDiGetClassDevs(&hidGuid, NULL, NULL,
DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
SP_DEVICE_INTERFACE_DATA devInfoData;
devInfoData.cbSize = sizeof(devInfoData);
int i;
for(i = 0;; i++) {
if(!SetupDiEnumDeviceInterfaces(devInfo, 0, &hidGuid, i, &devInfoData))
{
if(GetLastError() != ERROR_NO_MORE_ITEMS) {
// printf("SetupDiEnumDeviceInterfaces failed\n");
}
// printf("done list\n");
SetupDiDestroyDeviceInfoList(devInfo);
return FALSE;
}
// printf("item %d:\n", i);
DWORD sizeReqd = 0;
if(!SetupDiGetDeviceInterfaceDetail(devInfo, &devInfoData,
NULL, 0, &sizeReqd, NULL))
{
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
// printf("SetupDiGetDeviceInterfaceDetail (0) failed\n");
continue;
}
}
SP_DEVICE_INTERFACE_DETAIL_DATA *devInfoDetailData =
(SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(sizeReqd);
devInfoDetailData->cbSize = sizeof(*devInfoDetailData);
if(!SetupDiGetDeviceInterfaceDetail(devInfo, &devInfoData,
devInfoDetailData, 87, NULL, NULL))
{
// printf("SetupDiGetDeviceInterfaceDetail (1) failed\n");
continue;
}
char *path = devInfoDetailData->DevicePath;
UsbHandle = CreateFile(path, /*GENERIC_READ |*/ GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, NULL);
if(UsbHandle == INVALID_HANDLE_VALUE) {
ShowError();
// printf("CreateFile failed: for '%s'\n", path);
continue;
}
HIDD_ATTRIBUTES attr;
attr.Size = sizeof(attr);
if(!getAttr(UsbHandle, &attr)) {
ShowError();
// printf("HidD_GetAttributes failed\n");
continue;
}
// printf("VID: %04x PID %04x\n", attr.VendorID, attr.ProductID);
if(attr.VendorID != OUR_VID || attr.ProductID != OUR_PID) {
CloseHandle(UsbHandle);
// printf(" nope, not us\n");
continue;
}
// printf ("got it!\n");
CloseHandle(UsbHandle);
UsbHandle = CreateFile(path, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, NULL);
if(UsbHandle == INVALID_HANDLE_VALUE) {
ShowError();
// printf("Error, couldn't open our own handle as desired.\n");
return FALSE;
}
PHIDP_PREPARSED_DATA pp;
getPreparsed(UsbHandle, &pp);
HIDP_CAPS caps;
if(getCaps(pp, &caps) != HIDP_STATUS_SUCCESS) {
// printf("getcaps failed\n");
return FALSE;
}
// printf("input/out report %d/%d\n", caps.InputReportByteLength,
// caps.OutputReportByteLength);
return TRUE;
}
return FALSE;
}
BOOL ReceiveCommandPoll(UsbCommand *c)
{
static BOOL ReadInProgress = FALSE;
static OVERLAPPED Ov;
static BYTE Buf[65];
static DWORD HaveRead;
if(!ReadInProgress) {
memset(&Ov, 0, sizeof(Ov));
ReadFile(UsbHandle, Buf, 65, &HaveRead, &Ov);
if(GetLastError() != ERROR_IO_PENDING) {
ShowError();
exit(-1);
}
ReadInProgress = TRUE;
}
if(HasOverlappedIoCompleted(&Ov)) {
ReadInProgress = FALSE;
if(!GetOverlappedResult(UsbHandle, &Ov, &HaveRead, FALSE)) {
ShowError();
exit(-1);
}
memcpy(c, Buf+1, 64);
return TRUE;
} else {
return FALSE;
}
}
void ReceiveCommand(UsbCommand *c)
{
while(!ReceiveCommandPoll(c)) {
Sleep(0);
}
}
void SendCommand(UsbCommand *c, BOOL wantAck)
{
BYTE buf[65];
buf[0] = 0;
memcpy(buf+1, c, 64);
DWORD written;
OVERLAPPED ov;
memset(&ov, 0, sizeof(ov));
WriteFile(UsbHandle, buf, 65, &written, &ov);
if(GetLastError() != ERROR_IO_PENDING) {
ShowError();
exit(-1);
}
while(!HasOverlappedIoCompleted(&ov)) {
Sleep(0);
}
if(!GetOverlappedResult(UsbHandle, &ov, &written, FALSE)) {
ShowError();
exit(-1);
}
if(wantAck) {
UsbCommand ack;
ReceiveCommand(&ack);
if(ack.cmd != CMD_ACK) {
printf("bad ACK\n");
exit(-1);
}
}
}
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)
{
int i = 0;
if(argc < 2) {
printf("Usage: %s bootrom file.s19\n", argv[0]);
printf(" %s load osimage.s19\n", argv[0]);
printf(" %s fpga fpgaimg.s19\n", argv[0]);
printf(" %s gui\n", argv[0]);
return -1;
}
for(;;) {
if(UsbConnect()) {
break;
}
if(i == 0) {
printf("...no device connected, polling for it now\n");
}
if(i > 50000) {
printf("Could not connect to USB device; exiting.\n");
return -1;
}
i++;
Sleep(5);
}
if(strcmp(argv[1], "bootrom")==0 || strcmp(argv[1], "load")==0 || strcmp(argv[1], "fpga")==0) {
if(argc != 3) {
printf("Need filename.\n");
return -1;
}
if(strcmp(argv[1], "bootrom")==0) {
LoadFlashFromSRecords(argv[2], 0);
} else if(strcmp(argv[1], "fpga")==0) {
LoadFlashFromSRecords(argv[2], 0x2000);
} else {
LoadFlashFromSRecords(argv[2], 0x10000);
}
} else if(strcmp(argv[1], "gui")==0) {
ShowGui();
} else if(strcmp(argv[1], "cmd")==0) {
if(argc != 3) {
printf("Need command.\n");
return -1;
}
ExecCmd(argv[2]);
} else {
printf("Command '%s' not recognized.\n", argv[1]);
return -1;
}
return 0;
}

32
winsrc/prox.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef __PROX_H
#define __PROX_H
#include "../include/usb_cmd.h"
// prox.cpp
void ReceiveCommand(UsbCommand *c);
BOOL ReceiveCommandPoll(UsbCommand *c);
void SendCommand(UsbCommand *c, BOOL wantAck);
// gui.cpp
void ShowGui(void);
void HideGraphWindow(void);
void ShowGraphWindow(void);
void RepaintGraphWindow(void);
void PrintToScrollback(char *fmt, ...);
#define MAX_GRAPH_TRACE_LEN (1024*128)
extern int GraphBuffer[MAX_GRAPH_TRACE_LEN];
extern int GraphTraceLen;
extern double CursorScaleFactor;
extern int CommandFinished;
// command.cpp
void CommandReceived(char *cmd);
void UsbCommandReceived(UsbCommand *c);
// cmdline.cpp
void ShowCommandline(void);
void ExecCmd(char *cmd);
//void PrintToScrollback(char *fmt, ...);
#endif

BIN
winsrc/vc90.pdb Normal file

Binary file not shown.