/*
 howto compile: gcc -O2 readcard_with_parity_check.c
                gcc readcard_with_parity_check.c // will still work but will
                                                 // give implicit warning

 read bit stream from card (typically 700 bits or so);
 usage: ./readcard 1000
 reads up to 1000 (e.g. all of) the data on a typical track 1 card
 (track 1 is the track closest to the edge of the card).

 data reversed for parallel port; uncomment for isa --{mann,ben}@eyetap.org
 data also masked out for parallel port (can leave that way for isa also)
 because parallel port inputs go high by default.

 this allows use on pci only system, e.g. with pci parallel port cards:
   - SIIG Cyber Parallel PCI (both versions)
   - SIIG Cyber Parallel Dual PCI (both versions)
   - SIIG Cyber 2P1S PCI
   - SIIG Cyber I/O PCI (both versions)
   - SIIG Cyber 2S1P PCI (both versions)
   - Lava Parallel PCI
   - Lava Dual Parallel PCI
   - Lava 2SP PCI
   - LavaPort Plus
*/

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

int main(int argc, char **argv) {

 // long lrc;  /* cyclic reduncancy code is commented out now */
  int fd, parity_index, parity_chk;
  long count, recv;
  unsigned char *buf,*tmp_uchptr;
  //char parity_err[64]; // there's <=64 char. on card but if err
                         // reading end sentinel may seg fault */
  //char parity_err[143]; /* 143 char is enough for 1000 bits */
  char parity_err[1000]; /* 1000 char is enough for 7000 bits */
  int k, i;
  long check = 0;
  unsigned char tmp_uchar;

 // lrc = 0;

  if(argc>1)
    count = strtol(argv[1],NULL,10);
  else {
    fprintf(stderr,"Use %s number_of_bits_you_want_to_read\n",argv[0]);
    fprintf(stderr,"    %s %d  # for example, reads 1000 bits\n",argv[0],1000);
    fprintf(stderr,"    usually there's approx. 700 bits read\n");
    fprintf(stderr,"    so a buffer of 1000 is more than enough\n");
    exit(0);
  }
  buf = (unsigned char *) malloc(count*sizeof(unsigned char));

  if(!buf){
    fprintf(stderr,"malloc\n");
    exit(1); 
  }

  fd = open("/dev/paraseat0", O_RDWR);
  if(fd == -1) {
    fprintf(stderr, "Error: could not open /dev/paraseat0 for reading.\n");
    exit(1);
  }

  recv = read(fd,buf,count);
  close(fd);
//  fprintf(stderr,"%lu bits requested; %lu bits read\n",count,recv);
  tmp_uchptr = buf;
  // uncomment one line below for use with isa card or para with inverter:
  for (k=0;k<recv;k++) tmp_uchptr[k] = ~tmp_uchptr[k]; // for para, no inverter
  for (k=0;k<recv;k++) tmp_uchptr[k] = tmp_uchptr[k] & 0x01; //zero other bits
  while(check<recv-6){ //number of bits received-6 (since it's 7bits per char)
          //typ recv is 700 (alloc 1000 typically); of uchar for 1 bit
    // read the 7 bit (ascii-32) values:
    // start sentinel is ascii 69-32
    tmp_uchar = (unsigned char)(        // finding start sentinel 1000101=69
                                        // start sentinel is 0x45=69
                  tmp_uchptr[6] << 6 | 
                  tmp_uchptr[5] << 5 | 
                  tmp_uchptr[4] << 4 | 
                  tmp_uchptr[3] << 3 | 
                  tmp_uchptr[2] << 2 | 
                  tmp_uchptr[1] << 1 | 
                  tmp_uchptr[0]);
    // negate if using parallel port
    // tmp_uchar = ~tmp_uchar;  // comment out this line on ISA version
    //if(tmp_uchar == 0x45){ // isa
    if(tmp_uchar == 69){ // para
      //fprintf(stderr,"readcard: start sentinel found at %ld\n",check);
      break;
    }
    check++;
    tmp_uchptr++;
  }
  tmp_uchptr += 7;
  check += 7;
  
  //initialize parity array; typically 64 characters, use 80 or more to be safe
  for(i=0; i<1000; i++){
    parity_err[i] = ' ';
  }
  parity_index = 0;
  
  while(check<recv-6){
    
   //check for odd parity (odd number of ones in the byte)
   // ^ this symbol at a location indicates that parity has failed at
   //           that position.
   parity_chk = tmp_uchptr[0] + tmp_uchptr[1] + tmp_uchptr[2] + tmp_uchptr[3] 
		          + tmp_uchptr[4] + tmp_uchptr[5] + tmp_uchptr[6];
	
	if((parity_chk%2) == 1){
		parity_err[parity_index] = ' ';
		parity_index++;
	}else{
		parity_err[parity_index] = '^';
		parity_index++;
	}
		   
	tmp_uchar = (unsigned char) (        // parsing actual data
                  tmp_uchptr[6] << 6 | 
                  tmp_uchptr[5] << 5 | 
                  tmp_uchptr[4] << 4 | 
                  tmp_uchptr[3] << 3 | 
                  tmp_uchptr[2] << 2 | 
                  tmp_uchptr[1] << 1 | 
                  tmp_uchptr[0]); 
    // negate if using parallel port
    // tmp_uchar = ~tmp_uchar;  // comment out this line on ISA version
    if(tmp_uchar == 31){
      //fprintf(stderr,"readcard: end sentinel found\n");
      break;
    }
    
  /*  // add up Longitudinal Redundancy Check (LRC) character
	lrc+=tmp_uchar; */
	
	// display on screen
	printf("%c",(63&tmp_uchar)+32);
    check+=7;
    tmp_uchptr+=7;
  }

  printf("\n");
  //display parity failed positions
  for(i=0; i<1000; i++){ // 64 is enough; use argv[1]/7 or more to be safe
    printf("%c", parity_err[i]);
  }
  printf("\n");
  
 /* //display everything after the end sentinel so that the LCR can be inspected
  printf("lrc: ");
  while(check < recv-1){
	  check++;
      tmp_uchptr++;	  
      printf("%d", tmp_uchptr[0]);
  } 

  //display the calculated lrc
  //lrc+=36; //this takes care of the start sentinel (5 w/o parity) and the end
           	     //sentinel (31 w/o parity)
  printf("\ncalculated lrc: %d\n", lrc); */
return 0;
}


