kghunt
Posts: 383
Joined: Sun Mar 04, 2012 9:28 am

RPi.GPIO Wiegand capture speed?

Fri Jul 27, 2012 2:37 pm

I am trying to interface a wiegand reader to 2 gpio pins. I am currently using RPi.GPIO.

Wiegand Protocol:-
data0 data1 result
HIGH HIGH none
LOW HIGH 0
HIGH LOW 1

I have written a basic program to read the state of the pins and convert it to bits but it doesnt seem fast enough?

Code: Select all

#!/usr/bin/env python
import RPi.GPIO as GPIO
from time import sleep
GPIO.setmode(GPIO.BOARD)

result = ""
result = str(result)
GPIO.setup(3, GPIO.IN) #data 0
GPIO.setup(5, GPIO.IN) #data 1
leng = len(result)

def main():
	global result
	global leng
	while True:
		d0 = GPIO.input(3)
		d1 = GPIO.input(5)
		if d0 == False and d1 == True:
			result = result + "0"
			leng = len(result)
		elif d0 == True and d1 == False:
			result = result + "1"
			leng = len(result)
		elif  leng == 16:
			print result
			return result
		print result

if __name__ == '__main__':
	main()

At best is seems I can get 3 bits (unsure if there are missing bits in between) There should be 26 bits in total.

The data sheet says the following

Wiegand Data Pulse Widths (default) 40uS
Wiegand Data Interval (default) 2mS

Should I use wiring pi instead? or is Python the bottleneck?

paulstaf
Posts: 1
Joined: Mon Aug 13, 2012 3:12 pm

Re: RPi.GPIO Wiegand capture speed?

Mon Aug 13, 2012 4:07 pm

Here is my circuit:
Image

I am using this code:

Code: Select all

#!/usr/bin/env python
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)

GPIO.setup(21, GPIO.IN) #data 0
GPIO.setup(22, GPIO.IN) #data 1
x = 1
bit = 0
d0 = 0
d1 = 0

def main():
   global bit
   global x
   global d0
   global d1
   while True:
      d0 = GPIO.input(21)
      d1 = GPIO.input(22)
      if d0 == False or d1 == False:
        if d0 == False and d1 == True:
                bit = 0
        if d0 == True and d1 == False:
                bit = 1
        print "Bit %s: %s" % (x,bit)
        x = x + 1


if __name__ == '__main__':
   main()
I am able to get a string of bits. I did notice that the first burst is only 24 bits, but every burst after that one is the standard Weigand 26 bits. I don't know what is causing the first burst to be only 24 bits.

I am new to RPI, Python and just saw an HID reader for the first time 2 days ago so I am a newbie in all aspects.

One thing I have noticed while playing with my code is that the RPI seems to read TOO fast and can actually catch the state transition between 0 and 1 of the data lines. So there are several times that both data lines are True when they are passing their transition states.

This is causing me grief as I am trying to reset my bit counter using the default state instead of counting bits because the first burst is always 24 instead of 26 thus throwing off my initial count.

So when I try and make x = 0 if Data0 and Data1 are True (the default state), my x is always 0 because the RPI catches the transition where they are both True for a microsecond.

I'll keep hacking on it and post any breakthroughs I find.

paul

kghunt
Posts: 383
Joined: Sun Mar 04, 2012 9:28 am

Re: RPi.GPIO Wiegand capture speed?

Mon Aug 13, 2012 5:22 pm

The pins are meant to be true true in between bits. This shows no data is currently being sent. I have managed to tweak my code so that I get a good read 8 out of 10 times. The problem is that is not efficient enough for access control or clocking machines.

I have decided that the pi is not time critical enough to do a 100% good read. I am going to use a micro controller (atmel) to do the reading and then pass the raw data by serial to the pi.

User avatar
Grumpy Mike
Posts: 909
Joined: Sat Sep 10, 2011 7:49 pm
Location: Manchester (England England)
Contact: Website

Re: RPi.GPIO Wiegand capture speed?

Tue Aug 14, 2012 4:07 am

You can use the edge detection mode on the GPIO pins. That way you don't miss anything if you are not looking at the exact moment the pin is low.

That circuit above is bad, it pulls up the GPIO line to 5V, this will eventually burn out the pin.

kghunt
Posts: 383
Joined: Sun Mar 04, 2012 9:28 am

Re: RPi.GPIO Wiegand capture speed?

Tue Aug 14, 2012 7:10 am

Can you use edge detection in rpu.gpio or wiringpython?

On my circuit I am splitting the current to ground using a resistor to lower the voltage that the reader puts to the gpio to 3v.

texy
Forum Moderator
Forum Moderator
Posts: 5156
Joined: Sat Mar 03, 2012 10:59 am
Location: Berkshire, England

Re: RPi.GPIO Wiegand capture speed?

Tue Aug 14, 2012 12:31 pm

kghunt wrote: On my circuit I am splitting the current to ground using a resistor to lower the voltage that the reader puts to the gpio to 3v.
..that's not evident in the circuit you have posted. I would expect a pull down resistor between GND and the line to the GPIO pin, ie potential difference.

Texy
Various male/female 40- and 26-way GPIO header for sale here ( IDEAL FOR YOUR PiZero ):
https://www.raspberrypi.org/forums/viewtopic.php?f=93&t=147682#p971555

kghunt
Posts: 383
Joined: Sun Mar 04, 2012 9:28 am

Re: RPi.GPIO Wiegand capture speed?

Tue Aug 14, 2012 1:21 pm

I didnt post the above circuit. :-)

texy
Forum Moderator
Forum Moderator
Posts: 5156
Joined: Sat Mar 03, 2012 10:59 am
Location: Berkshire, England

Re: RPi.GPIO Wiegand capture speed?

Tue Aug 14, 2012 1:31 pm

:oops:

:)

T.
Various male/female 40- and 26-way GPIO header for sale here ( IDEAL FOR YOUR PiZero ):
https://www.raspberrypi.org/forums/viewtopic.php?f=93&t=147682#p971555

stevebird
Posts: 8
Joined: Fri Mar 01, 2013 8:46 pm

Re: RPi.GPIO Wiegand capture speed?

Fri Mar 01, 2013 9:04 pm

I've ordered an RFID reader that outputs the wiegand protocol. But its not here yet, the plan will be to make it the front end to my door access project for woodsidebreaks.

looking at the spec, D0 &D1 being the data outputs are at 5v when at rest, which is too high a voltage for the Pi. options are either a buffer or a simple potential divider.

Two resistors in series, an 8k2 and 12k connected between D0 and ground and the mid point connected to the Pi. same for D1, should make something in the region of 3v presented to the Pi and a total loading of 22k sinking about 2mA to the reader which it should be able to cope with.

I'll post how I get on.......

kghunt
Posts: 383
Joined: Sun Mar 04, 2012 9:28 am

Re: RPi.GPIO Wiegand capture speed?

Fri Mar 01, 2013 10:14 pm

I have done exactly what you said. Unfortunately I was never able to get a perfect read I would miss bits either due to the slowness of the pi or its non real time nature. I tweaked and tweaked my code but the best I could get was 8 or 9 times out of 10.

In the end I used and arduino chip to do the read and pass it back to the Pi by serial. Works flawlessly every time. To be fair that's how all the commercial ac units work anyway. But I mainly use a ttl mifare reader I get from china removes the whole problem and it helps that the reader is on $13 too :-)

stevebird
Posts: 8
Joined: Fri Mar 01, 2013 8:46 pm

Re: RPi.GPIO Wiegand capture speed?

Mon Mar 04, 2013 7:08 pm

This is my test Wiegand code, written in PHP and seems to produce some output, which most of the time seems to be correct.

My Wiegand keypad has the buttons, 0-9 , ESC & ENT on it, its also an RFID reader but the tags where not in the box so I cant test those until they arrive, but I see no reason why it shouldn't produce a string of data when a tag is put across it.

For info; The gpio functions to init/read/write are the same ones I wrote/use for the PiClock and door access project as on YouTube.

I make no claims that this this it properly coded, there's certainly other ways to do it, I'm happy to receive suggestions, remember that it will just output the data it sees, so press enter after every 4 bits of data or you'll end up with a line of 0's and 1's ;)


#!/usr/bin/php
<?php
#
# Wiegand Keypad for the WoodsideBreaks.co.uk project.
# Written by Steve Bird.
#

global $LED,$BUZ,$D0,$D1;

$LED = "22"; # LED Connected to GPIO 22
$BUZ = "23"; # BUZ Connected to GPIO 23
$D0 = "18"; # D0 Connected to GPIO 18
$D1 = "21"; # D1 Connected to GPIO 21

gpio_init($LED,"out"); # LED
gpio_init($BUZ,"out"); # BUZ
$FH_D0 = gpio_init($D0,"in"); # D0
$FH_D1 = gpio_init($D1,"in"); # D1

gpio_write($LED,1); # Set LED, 0=GREEN, 1=BLUE
gpio_write($BUZ,1); # Set Buz, 0=ON, 1=OFF

$LD = 0;

################### Main Loop.
while (1) {

$DA0 = gpio_read($FH_D0) ^1; # Invert the answer.
$DA1 = gpio_read($FH_D1) ^1;

$LD = $LD ^1 ;
gpio_write($LED,$LD); # Flash the LED 8^)

if ($DA0 == 1) print "0";
if ($DA1 == 1) print "1";

}
###################
# gpio init
function gpio_init($gp,$dir) {

# export
$fp = fopen('/sys/class/gpio/export', 'w');
fwrite($fp, $gp);
fclose($fp);

# set direction
$fp = fopen("/sys/class/gpio/gpio" . $gp . "/direction", "w");
fwrite($fp, $dir);
fclose($fp);

# If "in" then open a filehandle ready to read later on.
if ($dir == "in" ) {
$fh = fopen('/sys/class/gpio/gpio' . $gp . '/value', 'rb');
return($fh); # Return filehandle.
}

}

# gpio write - Note to self: Mod for filehandle open.
function gpio_write($gp,$value) {
$fp = fopen('/sys/class/gpio/gpio' . $gp . '/value', 'w');
fwrite($fp, $value);
fclose($fp);
}
# gpio read
function gpio_read($fh) {
fseek($fh,0); # Move back to beginning.
return(fread($fh,1));
}


?>

stevebird
Posts: 8
Joined: Fri Mar 01, 2013 8:46 pm

Re: RPi.GPIO Wiegand capture speed?

Tue Mar 05, 2013 4:17 pm

I think I've started to hit the same problems as the OP, when doing anything other than simply printing a 0 or 1 depending on the data detected, it seems the cycle time just isn't fast enough to be able to detect the data.

Storing the detected data, counting the detected bits and outputting the result takes clock cycles which then seem mean the 50us (micro second) negative going pulse gets missed resulting in wrong data.

Anyone got any ideas or code suggestions, ideally I'm still wanting to stay with PHP for other reasons.

I wondered if something coded in C and running as a daemon which could then be polled for the entire sequence ? - but that's beyond me.

kghunt
Posts: 383
Joined: Sun Mar 04, 2012 9:28 am

Re: RPi.GPIO Wiegand capture speed?

Wed Mar 06, 2013 7:08 am

You are going through exactly the same process as I did only I was using python. Even if you did write a c program or a shell script to do the reading. What happens when the device decides to do a file write that take too much CPU or something similar? The wiegand protocol states around 40 microseconds between data bits.

What I discovered is you can tweak it and tweak it but essentially what you are trying to do is make a non real time device perform a real time task and it is never going to be perfect.

I got an atmega328p chip with an arduino bootloader and programmed that to perform the wiegand read and pass the raw bits as a whole string to the pi via serial. This works perfect. I even put the atmega on a humble pi board and fitted some screw terminals to it (for the reader) and a real time clock plus a few other bits for LCD's buttons etc. The whole thing cost less than a tenner and makes a nice plug in add on board.

I work in the access control business and all of the hardware although they are embedded linux devices use microcontroller for reader interfacing and other inputs (HID vertex V2000). There is a reason they do this.

I think it is fine if you are fiddling and messing around but if you want to actually use the pi for access control then you will either need a serial reader or make your own wiegand to serial converter.

stevebird
Posts: 8
Joined: Fri Mar 01, 2013 8:46 pm

Re: RPi.GPIO Wiegand capture speed?

Wed Mar 06, 2013 8:04 am

I was coming round to that idea, would it be a cheaky ask to see your arduino code please? ;)

kghunt
Posts: 383
Joined: Sun Mar 04, 2012 9:28 am

Re: RPi.GPIO Wiegand capture speed?

Wed Mar 06, 2013 9:03 am

I think this is it. It was a while ago I flashed the Arduino and I have reloaded my laptop since then but I am pretty sure this is it. Just remove the stuff about the LCD.

Code: Select all

#include <LiquidCrystal.h>
int data0 = 2;
int data1 = 3;
int timeout = 0;
String bit_holder;
String oldbit = 0;
volatile int bit_count = 0;
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);


void setup() {
  time = 0; 
  lcd.begin(16, 2);
  lcd.print("Present Badge");
  delay(2);
  Serial.println("Present Badge");
  

  Serial.begin(9600);
  pinMode(data0, INPUT);
  digitalWrite(data0, HIGH);
  pinMode(data1, INPUT);
  digitalWrite(data1, HIGH);
  attachInterrupt(0, zero, FALLING);
  attachInterrupt(1, one, FALLING);
}


void zero(){
  bit_count ++; bit_holder = (bit_holder + 0);
}



void one(){
  bit_count ++; bit_holder = (bit_holder + 1);
}

void loop() {
  if (bit_holder != oldbit){lcd.setCursor(0,0);lcd.print(bit_holder);}
  delay(1000);  
  
  if (bit_count == 26){
Serial.println("26 bits detected"); 
Serial.print("bits="); 
Serial.println(bit_holder);
Serial.println(time);    
oldbit = bit_holder;
delay(timeout * 5000);
bit_count = 0;
bit_holder = 0;
Serial.println("timeout");
setup();
  }
    
  
}


 

kghunt
Posts: 383
Joined: Sun Mar 04, 2012 9:28 am

v 2.0 RPi.GPIO Wiegand capture speed?

Thu Jul 04, 2013 12:40 pm

So I have re-visited this old post to simplify my circuit. Since RPi.GPIO now supports interrupts I thought I would have another go.

Initially I set up a test program running on the pi that times how long it takes to concatenate at string on 32 or 26 1's and 0's. I was averaging around 18 microseconds even If I put the pi on a moderate load. Since every pulse is 40 microseconds long with a 2 millisecond gap between I was pretty confident I could make this work well with a reasonable amount of overhead for system load.

So I bashed this together.

Code: Select all

#!/usr/bin/env python

#green/data0 is pin 22
#white/data1 is pin 7
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(7, GPIO.IN)
GPIO.setup(22, GPIO.IN)

bits = ''
timeout = 5
def one(channel):
    global bits
    bits = bits + '1'
    #timeout = 5
    
def zero(channel):
    global bits
    bits = bits + '0'
    #timeout = 5

GPIO.add_event_detect(7, GPIO.FALLING, callback=one)
GPIO.add_event_detect(22, GPIO.FALLING, callback=zero)

print "Present Card"
while 1:
    if len(bits) == 32:
        print 25 * "-"
        print "32 Bit Mifare Card"
        print "Binary:",bits
        print "Decimal:",int(str(bits),2)
        print "Hex:",hex(int(str(bits),2))
        bits = '0'
        print 25 * "-"
        print 
        print "Present Card"
This works ok but... This is the output I get:

Code: Select all

Present Card                                                                                                                                            
-------------------------                                                                                                                               
32 Bit Mifare Card                                                                                                                                      
Binary: 10101110001111001111000000011110                                                                                                                
Decimal: 2923229214                                                                                                                                     
Hex: 0xae3cf01eL                                                                                                                                        
-------------------------                                                                                                                               
                                                                                                                                                        
Present Card                                                                                                                                            
-------------------------                                                                                                                               
32 Bit Mifare Card                                                                                                                                      
Binary: 010101110001111001111000000011110                                                                                                               
Decimal: 2923229214                                                                                                                                     
Hex: 0xae3cf01eL                                                                                                                                        
-------------------------                                                                                                                               
                                                                                                                                                        
Present Card


The decimal and hex numbers are correct and match my test mifare card. The only weirdness is the with the bits they are printing the wrong number of and they are not the same. As you see the first read is one set of bits but every subsequent read is different to the first although they are the same from 2nd read onwards.

Any Ideas?

User avatar
joan
Posts: 14024
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: RPi.GPIO Wiegand capture speed?

Thu Jul 04, 2013 12:47 pm

Just looks like a superfluous leading 0 on the binary.

kghunt
Posts: 383
Joined: Sun Mar 04, 2012 9:28 am

Re: RPi.GPIO Wiegand capture speed?

Thu Jul 04, 2013 12:56 pm

Why would that be though? D0 should only be pulled low if it has a zero to send and it doesn't do it every subsequent time.

kghunt
Posts: 383
Joined: Sun Mar 04, 2012 9:28 am

Re: RPi.GPIO Wiegand capture speed?

Thu Jul 04, 2013 4:24 pm

I seem to have it tweaked up quite a bit now but I am getting 1 bad read in about 25 - 30. I may have to go back down the AVR route.

This is what I am working with at the moment.

Code: Select all

#!/usr/bin/env python

#green/data0 is pin 22
#white/data1 is pin 7
import time
import RPi.GPIO as GPIO

D0 = 22
D1 = 7
bits = ''
timeout = 5

GPIO.setmode(GPIO.BOARD)
GPIO.setup(D0, GPIO.IN)
GPIO.setup(D1,GPIO.IN)

def one(channel):
    global bits
    bits = bits + '1'
    
def zero(channel):
    global bits
    bits = bits + '0'
        

GPIO.add_event_detect(D0, GPIO.FALLING, callback=zero)
GPIO.add_event_detect(D1, GPIO.FALLING, callback=one)

print "Present Card"
try:
    while 1:
        if len(bits) == 32:
            time.sleep(0.1)
            #print "Binary:",bits
            print "Decimal:",int(str(bits),2)
            #print "Hex:",hex(int(str(bits),2))
            bits = '0'
            time.sleep(0.1)
except KeyboardInterrupt:
    GPIO.cleanup()
    print "Clean Exit By user"

GPIO.cleanup()
I am not sure how I can optimise this any more. I am also running the Adafruit web IDE on this pi I'm sure that doesn't help and I wouldn't be doing that when its in use. Other than that it is a clean install of Moebius. The 0.1 sleeps seem to improve the read rate a lot. I read something about the interrupts only using 1 thread maybe I should multithread this script?

User avatar
joan
Posts: 14024
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: RPi.GPIO Wiegand capture speed?

Thu Jul 04, 2013 4:47 pm

Why not just use C? That's pretty much what you would be doing if you went down the micro-controller route.

stevebird
Posts: 8
Joined: Fri Mar 01, 2013 8:46 pm

Re: RPi.GPIO Wiegand capture speed?

Thu Jul 04, 2013 6:17 pm

Image
http://www.avtsuk.com/cromer/doorman_sc ... _schem.jpg

I've abandoned trying to read the Wiegand keypad with the Pi, it just wasn't reliable, I've ended up using a £3 atmega IC to do the read, as well as a complete re-write of the audrino code examples I found as I couldn't find any that supported my odd 4 bit keypad I had, although it does support RFID cards and fobs too, we primarily need the keypad to function.

Its been a good learning curve, but at least I can say whilst I've learned from others examples, I ended up writing some original code. I've attached my diagram so people can see how I'm using the atmega chip with the Pi to then operate relays, led & buzzer.

Its nearly a finished project and ready for installation as the entry system at the holiday flats of WoodsideBreaks http://www.woodsidebreaks.co.uk

kghunt
Posts: 383
Joined: Sun Mar 04, 2012 9:28 am

Re: RPi.GPIO Wiegand capture speed?

Thu Jul 04, 2013 6:49 pm

You think doing it in C would make that much difference? I'm leaning more towards its because the OS is not real time.

I was trying to avoid using an atmel chip for a few reasons.

Simplicity (I want to get a few boards printed and the simpler the cheaper)

Only maintaining one piece of code (also how to update the avr atmel in situe)

Python is easier for me it probably takes me a tenth of the time in python as it does in c to perform the same task.

The other reason is the atmega 328 only has 2 hardware interrupts and I need at least 6 maybe 7.

I suppose the easiest thing to do with an atmel is have it just return the binary data then decode it in python. That way I am not tied to a specific bit length or card type.

stevebird
Posts: 8
Joined: Fri Mar 01, 2013 8:46 pm

Re: RPi.GPIO Wiegand capture speed?

Thu Jul 04, 2013 7:06 pm

HI,

For me, I only do the time critical keypad reading with the atmel ic, I do appreciate what you say about not being able to update it and maintaining once piece of code though. I could have designed in a programmer for the pi to update the atmel but I've tested that code and it seems very very stable. All its doing for me is reading the code and passing it via serial to the Pi which then makes the decision to unlock the door or not.

Mines all done in PHP not for any other reason other than I wanted to do something different and it had SQL support, which I use to check the door entry codes against. Its all part of the bigger back end system.

In our application, a randomly generated entry code is generated and stored against the booking record for the holiday and only valid for the period of the booking. Plus a little time before and afterwards for the lazy to leave guests :)

We looked at an existing commercial solution and was quoted £1040 per door + fitting, so far its cost less than £100 per door.

User avatar
joan
Posts: 14024
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: RPi.GPIO Wiegand capture speed?

Thu Jul 04, 2013 7:08 pm

What are the characteristics of the pulses? All I've seen mentioned is 40 micros long with gaps of 2 millis. That doesn't sound right.


Return to “Python”