-----------------chop-with-axe----------------chop-with-axe---------------------
Subject: Mag Stripe Card Info SUMMARY (long)

Summary of information on the SR&D MCR-175-1R-0803 mag stripe card
reader. Due to the large volume of summary requests I received, I am
posting this summary instead of mailing it. It's somewhat long, so hit
'n' now if you're not interested in this stuff.

[Editor's Note: The following is a concatenation of the replies I received
to a net.request about my mag stripe card reader. After the replies I have
included some software that I threw together to play with the card reader.
This file contains all the information I have on this subject.
Additions are most welcome. Note also that there was another summary
post in recent days with information on how the data on the cards is
encoded. See article <kms26oINNojs@network.ucsd.edu> for this info.

You'll notice I didn't get any farther than simply reading the raw signal
from the card; of the two card readers I ordered, one was completely DOA,
and the other had a faulty clock output (at least I assume that it was a
clock output; I was never able to read any sort of signal from that line).
Someone with a fully functional reader can easily extend what I wrote to get
it to decode the actual data content of the card. If you do decide to make
modifications and/or extensions, I'd appreciate a copy of whatever
changes you make (email to tmkk@uiuc.edu).  Enjoy!]

---

From: tmkk@uiuc.edu (K. Khan)
Subject: Re: Mag Card Swipe Reader: Need Help!

I am truly amazed that someone else is trying to use this device!  I got
mine about 2 years ago and spent some time trying to find the manufacturer.
I found a listing for SR&D in the Noth America technical directory at 
the public library.  I found the listing for the American sales office
in Los Angeles.  I tried calling but the company had gone out of 
business.  There was no listing in the local phone directory either.
I then tried calling the head office in Japan, but they also had
gone out of business.  I haven't seen the company listed in any recent
electronics directories, so I think they really are gone.

I have spent about an hour looking at the signals on the outputs
of the device.  One signal line is a /STATUS line which indicates
when a card is been moved through the unit.  The other 2 lines
pulse in response to a magnetic card.  I believe the IC performs
Manchester decoding and clock recovery for the read channel, so one
output line is DATA and the other is CLOCK.  

That is as far as I got 2 years ago and I had forgot about it until
now.  If you receive any other info, please send a copy to me!

---

>Finally, there are 5 wires coming from the assembly and terminating in a
>small connector similar to power supply connectors for 3.5" floppy drives.
>The wires are red, yellow, green, blue, and black.

If its anything like the units I worked with, I think you will find
that the five wires are:

        +5v
        Gnd
        Clock
        Data
        Card detected

But I don't know active levels, or which wire is what.

---

I picked few week ago a magnetic credit card reader from a another surplus 
outfit. It cost about the sam es yours. My card reader was made by MAGTEK and 
was diffrent from your reder in many ways. The reader I have has 4 ICs and
some of them are standard TTL chip, so I could easily quess the power 
requiments (5V) and power connectors. My card reader had 6 pin connector. I 
put the power to the reader and started to examine the signals with multimeter 
and a little crystal earphone (my favourite electronics hacking tool). I found 
that output signals were something like that: data out, data clock out, data 
readable and and card ath the end of the reader. Then I connected the reader 
to the joystick port of my 386SX and made a little Turbo Pascal program for 
reading the card.

Spare printer port is the interface I use very often to connect diffrent 
hardware circuit to my computer. This time I decided to use game port because 
it can also provide the power to the user.

My program simply prints out the bits from the card. I have not found the way 
to decode the bits to corresponding numbers. The program so prints all 237 
bits form the card to screen. If you have any information about data coding, I 
an interested in hearing about it.

Here is the meanings of the bytes in port $201:

D7: 0 -> card pushed to the end of the reader
D6: the read data from card
D5: 0 -> data stream readable
D4: the data clock

--- Pascal program ---

Program CardReader;
 
Uses Crt,Binary;
 
Const
   gameport=$201;
 
 
Procedure Wait_start;
Begin
   Repeat Until (Port[gameport] and 32)=0;
End;
 
Function data_readable:boolean;
Begin
   data_readable:=((Port[gameport] and 32)=0);
End;
 
Procedure Wait_clock;
Begin
   Repeat Until (Port[gameport] and 16)=0;
End;
 
Procedure Wait_clock_end;
Begin
   Repeat Until (Port[gameport] and 16)=16;
End;
 
Function data_input:byte;
Begin
   If (Port[gameport] and 64)=0 Then data_input:=0
      Else data_input:=1;
End;
 
Function card_at_end:boolean;
Begin
   card_at_end:=((Port[gameport] and 128)=0);
End;
 
Procedure test;
Begin
   Wait_start;
   Repeat
      Writeln(ByteBin(Port[$201]));
   Until keypressed;
End;
 
Begin
   ClrScr;
   Wait_start;
   While data_readable Do Begin
      Wait_clock;
      Write(data_input);
      Wait_clock_end;
   End;
   Repeat Until KeyPressed;
End.

---

Wiring color code for the SR&D MCR-175-1R-0803 mag stripe card reader:

   Red:         +5V
 Black:         Gnd
Yellow:         /Card Detect
 Green:         Clock (?? - non-functional on the unit I have)
  Blue:         /Data

The leading '/' indicates an active low TTL signal.

---

           Quick 'n Dirty guide to the enclosed reader software
           ----------------------------------------------------

Hooking the SR&D MCR-175-1R-0803 card reader to your PC:

The included software is written specifically for the following configuration; 
if your wiring is different, you'll need to make corresponding changes to the 
software. Note also that the port address is hard-coded to look for LPT2's 
status port (at address 0x279). If you're using a different port address, be 
sure to change the port address value.

SR&D Wire       Printer Port Pin        Port Bit        Signal
---------       ----------------        --------        ------
Yellow          11                      7               /CARD DETECT
Blue            10                      6               /DATA
Black           18                      N/A             (Ground)

Power to the reader was provided by a separate power supply, basically one of 
those black plastic DC power packs fed through a 7805 regulator chip.

Compiling the software:

Compile SWIPE.C (using SMALL memory model), assemble SWIPEISR.ASM, and
link the two together.

Using the software:

To use SWIPE.EXE, simply hook the reader up to your LPT2: port, power it
up, then run SWIPE. When you're ready, press the ENTER key, and swipe a
card through the reader. The program will read the data from the card and
store it in a buffer (but will not decode the data; that is left as an
excercise ;-). After the card has been read, press ENTER again and the
contents of the buffer will be dumped to stdout. To save the card data to
a file, simply redirect SWIPE's output on the command line, e.g.

SWIPE > citibank.out

Please let me know of any changes, bug fixes, or improvements you make to
this code. Send email to tmkk@uiuc.edu.

Thanks, and have fun!

--- CUT HERE ---

/*
 * S W I P E . C
 *
 * Written:
 *     1/11/92
 *
 * Description: Quick 'n Dirty reader program for SR&D mag stripe card reader.
 *     Reads data from the input port as long as a card is detected in the
 *     card slot. After sampling, the data is dumped to stdout, and may
 *     be redirected to a file if desired.
 *
 * Note: Written for Borland C++ 3.0 - may require changes to compile under
 *     MSC or others. Compile in SMALL model.
 *
 */

#include <stdio.h>
#include <conio.h>
#include <process.h>
#include <dos.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

/* timer chip programming register port addresses */
#define COMMAND_REG 0x43
#define CHANNEL0 0x40

/* size of sample buffer */
#define MAXSAMPLE 4096

typedef unsigned char byte;


/* global variables */
byte *databuf;  /* buffer for the sampled data */

/* interprocess communication data */
byte *bufp;         /* data buffer pointer */
unsigned nsamp;     /* number of samples to be made */
unsigned port;      /* input port address */
int enab=0;         /* flag to enable/disable sampling */
int start=0;        /* flag indicating that sampling has begun */

/* ISR prototype */
extern void interrupt shand(void);

void program_timer(int channel, unsigned count)
/*
 * P R O G R A M _ T I M E R
 *
 * Description: Programs the given count value into the specified channel of
 *     the IBM 825x timer chip. Channel 0 is the time-of-day-clock interrupt;
 *     channel 2 is the speaker pulser.
 *
 * Parameter:
 *     channel (in) - Channel to be programmed.
 *     count (in) - Count value with which to program timer chip.
 *
 */
{

    outportb(COMMAND_REG, 0x36);  /* set up for reprogramming */
    outportb(CHANNEL0 + channel, count & 0xff);  /* lo byte first */
    outportb(CHANNEL0 + channel, count >> 8);  /* then hi byte */
}

void sample_data(int count)
/*
 * S A M P L E _ D A T A
 *
 * Description: Sets up for data collection from the printer port using
 *     the SHAND interrupt service routine (see SWIPEISR.ASM). This routine
 *     reprograms the timer chip for the desired sampling rate, sets up
 *     the interprocess communication area, and starts the sampling process.
 *     The actual sampling is done in the SHAND procedure. This routine
 *     waits until sampling has been completed before returning.
 *
 */
{
void interrupt (*oldhand)(void);  /* pointer to old interrupt vector */

    /* save old interrupt vector */
    oldhand = getvect(0x1c);

    /* clear enable flag */
    enab = 0;
    start = 0;

    /* install new vector */
    setvect(0x1c, shand);

    /* set up interprocess communications area */
    nsamp = 0;
    bufp = databuf;
    port = 0x279;  /* address of printer status register */

    cprintf("Sampling at %fHz (= %fms)....",
       1193180.0 / (float)count, (float)count / 1193.18);

    /* reprogram timer chip */
    program_timer(0, count);

    /* enable sampling */
    enab = 1;

    /* wait until sampling is completed */
    while (enab) ;

    /* restore standard timing value */
    program_timer(0, 0);

    /* reinstall old handler vector */
    setvect(0x1c, oldhand);

    cprintf(" completed.\r\n");

}


void main()
{
unsigned i;

    /* allocate memory */
    databuf = calloc(MAXSAMPLE, sizeof(byte));
    assert (databuf != NULL);

    cprintf("Press <ENTER> when ready to swipe card:");
    getchar();
    sample_data(12);  /* This works out to about a 100kHz sampling rate  */

    cprintf("Sampling completed, %u samples total.\r\n", nsamp);
    cprintf("Press <ENTER> to dump data.\r\n\r\n");
    getchar();

    /* dump data to stdout */
    for (i=0; i<nsamp; ++i)
        if (kbhit())
            break;
        else
            printf("%u\n", databuf[i]);

    free (databuf);

}

--- CUT HERE ---

;
; S W I P E I S R . A S M
;
; Interrupt Service Routine to sample swipe reader.
;

_TEXT   segment byte public 'CODE'
DGROUP  group   _DATA,_BSS
        assume  cs:_TEXT,ds:DGROUP,ss:DGROUP
_TEXT   ends

_DATA   segment word public 'DATA'
; Nuthin' in here!
_DATA   ends

_BSS    segment word public 'BSS'
; Nuthin' in here either!
_BSS    ends

_TEXT   segment byte public 'CODE'
;
; S H A N D
;
; Description: Sample interrupt handler for timer extension interrupt 0x1c.
;
; Note: Assumes that the /CARD DETECT line appears on bit 7 of the input
;     port. This bit corresponds to pin 11 on the standard PC printer port.
;     Also, the PC printer port card inverts the signal on this pin; thus,
;     bit 7 is *set* when a card is in the reader, even though /CARD DETECT
;     is an active low signal.
;
_shand  proc    far
        push    ax
        push    bx
        push    dx
        push    ds
        push    si
        push    di
        push    bp
        mov     bp,DGROUP
        mov     ds,bp

        cmp     word ptr DGROUP:_enab, 0                ; Are we turned on?
        je      ciao                                    ; Nope - goodbye!

        mov     dx, word ptr DGROUP:_port               ; Get port address
        cmp     word ptr DGROUP:_start, 0               ; Has sampling begun?
        jne     doit                                    ; Yup - hop to it!

;
; Sampling is enabled but has not actually begun because no card has yet been
;     detected in the slot of the reader. Check to see if a card has arrived
;     yet and, if it has, set the flag to indicate that sampling should begin.
;
        in      al, dx                                  ; sample port
        test    al, 80h                                 ; card detected?
        jz      ciao                                    ; nope - later!

        mov     word ptr DGROUP:_start, 1               ; card's there,
                                                        ; start reading it
        jmp     saveit
;
doit:
        in      al, dx                                  ; Read the port
        test    al, 80h                                 ; card detect bit set?
        jz      disable                                 ; if not, quit
;
; Data is still valid; get buffer pointer and save the data
;
saveit:
        mov     bx,word ptr DGROUP:_bufp                ; get addr. to write
        mov     byte ptr [bx],al                        ; save sampled value
        inc     word ptr DGROUP:_bufp                   ; and bump the ptr

        inc     word ptr DGROUP:_nsamp                  ; update sample count
        jmp     ciao                                    ; and skeedaddle

disable:
        mov     word ptr DGROUP:_enab,0                 ; card no longer
                                                        ; detected - disable
                                                        ; sampling
ciao:
        pop     bp                                      ; restore context
        pop     di
        pop     si
        pop     ds
        pop     dx
        pop     bx
        pop     ax
        iret    
_shand  endp
_TEXT   ends

_DATA   segment word public 'DATA'
;s@      label   byte
_DATA   ends
        extrn   _nsamp:word
        extrn   _port:word
        extrn   _bufp:word
        extrn   _enab:word
        extrn   _start:word
_TEXT   segment byte public 'CODE'
        extrn   _inportb:near
_TEXT   ends
        public  _shand
        end

=== END OF SUMMARY ===
-----------------chop-with-axe----------------chop-with-axe---------------------
