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

Re: RPi.GPIO Wiegand capture speed?

Thu Aug 28, 2014 6:35 am

I made my own using a humble pi. I started designing one in Fritzing but never completely finished it.

I planned to make a cloud based access control system. The software is the easy part though.

squiggleuk
Posts: 12
Joined: Wed Jun 05, 2013 12:37 pm

Re: RPi.GPIO Wiegand capture speed?

Thu Aug 28, 2014 7:28 am

I made my prototype with a piPlate - It is nice and compact! Don't know how durable it is though, and the cabling looks like a bit of a rats nest!

Do you think you'll continue with the the firtzing pcb KH? If not, would you consider sharing what you've got so far? Might help with my learning! Totally agree the software side is the easy part ;)

Wonder if there would be sufficient interest in such a product to produce in mass if the hardware and software could be packaged...

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

Re: RPi.GPIO Wiegand capture speed?

Thu Aug 28, 2014 1:05 pm

The company I work for sells/ installs access control and the software we buy thousands of access controllers each year. There are some important considerations though. The reader power beads to be 12v you need a logic level shifter for the wiegand pins. All inputs need to be fused/protected in some way so that a reader cannot be shorted out to blow the main supply (this is how people used to bypass the controller and with some cheaper ones you still can).

It needs 2 Reader inputs and at least 2 relay outputs. A push button input and maybe a tamper alarm input.

It needs an RTC to keep the time when offline.

Some status LEDs are helpful.

A 12 to 5v converter so you can power the whole thing from 12v.
To be competitive it needs to have a sale price of less than £150.

I keep meaning to have another bash at it.

rpurdie
Posts: 1
Joined: Sun Jan 24, 2016 2:24 pm

Re: RPi.GPIO Wiegand capture speed?

Sun Jan 24, 2016 2:30 pm

I have also been trying to get Wiegand data to work from within python. Not sure about the timings I saw posted on this thread, elsewhere I saw 1ms between pulses and 50 us being common for the pulse duration. Looking at RPIO under strace, there is overhead which suggests its simply not fast enough and misses bits.

The solution I found was to tweak RPIO with this patch:

Index: RPIO-0.10.0/source/RPIO/_RPIO.py
===================================================================
--- RPIO-0.10.0.orig/source/RPIO/_RPIO.py
+++ RPIO-0.10.0/source/RPIO/_RPIO.py
@@ -207,7 +207,7 @@ class Interruptor:
_PULL_UPDN[pull_up_down]))

# Open the gpio value stream and read the initial value
- f = open(path_gpio + "value", 'r')
+ f = open(path_gpio + "value", 'rb', buffering=0)
val_initial = f.read().strip()
debug("- inital gpio value: %s" % val_initial)
f.seek(0)
@@ -330,9 +330,7 @@ class Interruptor:
elif event & select.EPOLLPRI:
# GPIO interrupts
f = self._map_fileno_to_file[fileno]
- # read() is workaround for not getting new values
- # with read(1)
- val = f.read().strip()
+ val = f.read(2).strip()
f.seek(0)
self._handle_interrupt(fileno, val)

The comment in there suggests the author knew there was an issue but not how to fix it. The result of this is fewer syscalls:

Before:

[pid 2349] 12:10:38.321992 epoll_wait(6, {{EPOLLPRI|EPOLLERR, {u32=9, u64=7529850764001289}}}, 1023, 1000) = 1 <0.000103>
[pid 2349] 12:10:38.322829 fstat64(9, {st_mode=S_IFREG|0644, st_size=4096, ...}) = 0 <0.000091>
[pid 2349] 12:10:38.323312 _llseek(9, 0, [0], SEEK_CUR) = 0 <0.000074>
[pid 2349] 12:10:38.323802 read(9, "1\n", 4096) = 2 <0.000126>
[pid 2349] 12:10:38.324321 read(9, "", 4096) = 0 <0.000086>
[pid 2349] 12:10:38.324870 _llseek(9, 0, [0], SEEK_SET) = 0 <0.000082>
[pid 2349] 12:10:38.325596 epoll_wait(6, {{EPOLLPRI|EPOLLERR, {u32=8, u64=7529850764001288}}}, 1023, 1000) = 1 <0.000332>
[pid 2349] 12:10:38.326760 fstat64(8, {st_mode=S_IFREG|0644, st_size=4096, ...}) = 0 <0.000089>
[pid 2349] 12:10:38.327243 _llseek(8, 0, [0], SEEK_CUR) = 0 <0.000080>
[pid 2349] 12:10:38.327790 read(8, "1\n", 4096) = 2 <0.000102>
[pid 2349] 12:10:38.328240 read(8, "", 4096) = 0 <0.000082>
[pid 2349] 12:10:38.328790 _llseek(8, 0, [0], SEEK_SET) = 0 <0.000081>
[pid 2349] 12:10:38.329518 epoll_wait(6, {{EPOLLPRI|EPOLLERR, {u32=9, u64=7529850764001289}}}, 1023, 1000) = 1 <0.000101>

After:

[pid 2407] 12:32:48.691149 epoll_wait(6, {{EPOLLPRI|EPOLLERR, {u32=8, u64=35237543783956488}}}, 1023, 1000) = 1 <0.000205>
[pid 2407] 12:32:48.692181 read(8, "1\n", 2) = 2 <0.000107>
[pid 2407] 12:32:48.692751 _llseek(8, 0, [0], SEEK_SET) = 0 <0.000081>
[pid 2407] 12:32:48.693461 epoll_wait(6, {{EPOLLPRI|EPOLLERR, {u32=9, u64=35237543783956489}}}, 1023, 1000) = 1 <0.000329>
[pid 2407] 12:32:48.694595 read(9, "1\n", 2) = 2 <0.000109>
[pid 2407] 12:32:48.695169 _llseek(9, 0, [0], SEEK_SET) = 0 <0.000079>
[pid 2407] 12:32:48.695879 epoll_wait(6, {{EPOLLPRI|EPOLLERR, {u32=8, u64=35237543783956488}}}, 1023, 1000) = 1 <0.000304>

One less read() call and one less seek(), you can then see the amount of time spent waiting in epoll increases (which is good) and I see a suitable increase in the reliability of the data. Thought I'd share it in case its useful to others.

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

Re: RPi.GPIO Wiegand capture speed?

Sun Jan 24, 2016 3:59 pm

When I last looked at this I found that wiring-python was much faster than RPI.gpio. Thats probably because it is python wrappers on c code. But even then it still errored too much. The only working solution I had was to use C code to read the pins and pass the binary result and bit length to python for processing.


Mark_M
Posts: 9
Joined: Wed Jun 29, 2016 4:16 pm

Re: RPi.GPIO Wiegand capture speed?

Thu Jun 30, 2016 6:32 am

Hi everyone!
I'm trying to setup a rfid reader also. It's a 125khz ([urlhttp://www.szjat.com.cn/pro_HM6003.html][/url]). I have it set to gpio14 and gpio15.

I have tried both kghunt's code and Joan's code. Both working fine but the only problem I'm having is that is giving the wrong number. Say if my number printed on card is 0009817354 it reads 19634708. Also tried a key fob with number printed on tag 0007789026 and code prints out 15578053. Any idea what's going on?

Thanks so much,
Mark

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

Re: RPi.GPIO Wiegand capture speed?

Thu Jun 30, 2016 6:46 am

Try dividing the answer by 2. It looks like the least significant bit may be a check bit.

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

Re: RPi.GPIO Wiegand capture speed?

Thu Jun 30, 2016 7:01 am

Joan is right.

The number you are getting below converted to binary:
19634708
1001010111001101000010100

The number you want in binary:
9817354
100101011100110100001010

As you can see the binary is almost identical apart from the last bit. You need to change the code to drop the last bit before converting it to decimal.

The chances are the first bit is also a parity bit (it usually is) but in this case its a zero so didn't affect the number so you may have to drop that one too. I assume there are 26 bits in the binary string?

Karl

Mark_M
Posts: 9
Joined: Wed Jun 29, 2016 4:16 pm

Re: RPi.GPIO Wiegand capture speed?

Thu Jun 30, 2016 7:46 am

Thanks Joan and Karl!

Dividing by 2 once converted to demical is doing the trick. But would I be better off doing it your way Karl? I'm new to Python but come from a php background.

Also there's not much information out there on the reader I'm using. It says..
Buzzer control line: when it is activated by access controller, buzzer will sound continually till the line is released to high by access controller or access control panel.

I have a constant 5.8 volts to that line, would you guys know how I would set that up? I'm not understanding it since there is a voltage present. Do I just send a high signal from one of the gpio when I want the buzzer to sound?

Thanks for all your help!

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

Re: RPi.GPIO Wiegand capture speed?

Thu Jun 30, 2016 7:56 am

If I was you I'd take Karl's advice. He actually uses the Wiegand cards so will understand the details.

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

Re: RPi.GPIO Wiegand capture speed?

Thu Jun 30, 2016 8:32 am

Hi Mark_M

As for the binary I would just pull out bits 2-25 and convert them to decimal. I can't remember what the code looks like (it was some time ago I last looked) but for example.

I think this is what you are currently doing:

Code: Select all

binary = "01010101010101010101010101"
print(int(binary,2))
This is what you need to do instead:

Code: Select all

binary = "01010101010101010101010101"
print(int(binary[1:24],2))
The latter will only convert bits 2-25. Calling the variable with the string like this

Code: Select all

binary[1:24]
only calls the 2nd to 24th characters of the string, the numbering starts from zero so character 1 = bit 2 and so on.

As for the buzzer on all the readers we usually use you have to take the buzzer wire to ground to make it beep. Like on our controllers the reader will beep 3 times for access denied or constantly if the door has been forced open without a badge. To do this you will need a transistor, if you ground the wire it will sink too much power and probably burn the GPIO out.

Mark_M
Posts: 9
Joined: Wed Jun 29, 2016 4:16 pm

Re: RPi.GPIO Wiegand capture speed?

Fri Jul 01, 2016 5:20 am

Thanks Karl,
have something odd going on now. I'm able to get a first good read with correct number but after that it adds the bit back to it.. Here is my code..

Code: Select all

#!/usr/bin/env python

#green/data0 is pin 8
#white/data1 is pin 10
import time
import RPi.GPIO as GPIO

D0 = 8
D1 = 10
bits = ''
t = 15
timeout = t

GPIO.setmode(GPIO.BOARD)
GPIO.setup(D0, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(D1,GPIO.IN, pull_up_down=GPIO.PUD_UP)

def set_procname(newname):
    from ctypes import cdll, byref, create_string_buffer
    libc = cdll.LoadLibrary('libc.so.6')    #Loading a 3rd party library C
    buff = create_string_buffer(len(newname)+1) #Note: One larger than the name (man prctl says that)
    buff.value = newname                 #Null terminated string as it should be
    libc.prctl(15, byref(buff), 0, 0, 0) #Refer to "#define" of "/usr/include/linux/prctl.h" for the misterious value 16 & arg[3..5] are zero as the man page says.
    
def one(channel):
    global bits
    global timeout
    bits = bits + '1'
    timeout = t
    
def zero(channel):
    global bits
    global timeout
    bits = bits + '0'
    timeout = t



def main():
    set_procname("Wiegand Reader")
    global bits
    global timeout
    GPIO.add_event_detect(D0, GPIO.FALLING, callback=zero)
    GPIO.add_event_detect(D1, GPIO.FALLING, callback=one)
    while 1:
        if bits:
            timeout = timeout -1
            time.sleep(0.001)
            if len(bits) > 1 and timeout == 0:
                #print "Binary:",bits
                
                #result = int(str(bits),2)
                
                print bits
                result = int(bits[0:25],2)
                
                #rfid_read = result /2
                rfid_read = result
               # print result
                if result == 2923229214: # the number of my test badge
                    bits = '0'
                    print rfid_read
                else:
                    bits = '0'
                    timeout = t
                    print "Bad Read"
                    print rfid_read
        else:
            time.sleep(0.001)



if __name__ == '__main__':
    main()
Thanks for explaining about the buzzer line. I'm just curious, are you using a transistor or a relay for your door strike?

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

Re: RPi.GPIO Wiegand capture speed?

Fri Jul 01, 2016 3:35 pm

If you do a read without applying any formatting do you get 26 bits?

if so you need to do

Code: Select all

result = int(bits[1:24],2)
I use a relay for the lock it will pass too much current for most transistors.

Mark_M
Posts: 9
Joined: Wed Jun 29, 2016 4:16 pm

Re: RPi.GPIO Wiegand capture speed?

Sat Jul 02, 2016 2:25 am

Using same card (9817354), my first read is 26 bits then all reads after that are 27 bits...

Reads with out format
01001010111001101000010100
19634708
-----------
001001010111001101000010100
19634708
-----------
001001010111001101000010100
19634708
-----------
001001010111001101000010100
19634708
-----------
001001010111001101000010100
19634708





reads using result = int(bits[1:24],2)

01001010111001101000010100 # before formatting
10010101110011010000101 # after formatting
4908677
-----------
001001010111001101000010100 # before formatting
1001010111001101000010 # after formatting
2454338
-----------
001001010111001101000010100 # before formatting
1001010111001101000010 # after formatting
2454338
-----------
001001010111001101000010100 #before formatting
1001010111001101000010 # after formatting
2454338

Not sure whats going on here

tom.slick
Posts: 190
Joined: Wed Jan 06, 2016 9:23 pm

Re: RPi.GPIO Wiegand capture speed?

Sat Jul 02, 2016 5:10 am

Mark_M wrote:Using same card (9817354), my first read is 26 bits then all reads after that are 27 bits...

Code: Select all

               if result == 2923229214: # the number of my test badge
                    bits = '0'
                    print rfid_read
                else:
                    bits = '0'
                    timeout = t
                    print "Bad Read"
                    print rfid_read
No, your read is still 26 bits, but when you clear the value of "bits" you add a 0 to the start of it, it should be bits = "" in both of the above lines
Mark_M wrote:reads using result = int(bits[1:24],2)

01001010111001101000010100 # before formatting
10010101110011010000101 # after formatting
4908677

Not sure whats going on here
String slicing is exclusive

Code: Select all

>>> x = '012345'
>>> x[1:2]
'1'
>>> x[1:3]
'12'
>>> x[1:6]
'12345'
>>> x[1:5]
'1234'
so if you want 24 characters it should be

Code: Select all

result = int(bits[1:25], 2) # get index 1 through 24 exclusive
but this assumes you are using a 26 character string

Code: Select all

>>> int('01001010111001101000010100'[1:24],2)
4908677
>>> int('01001010111001101000010100'[1:25],2)
9817354
on a side note

Code: Select all

>>> bin(2923229214)
'0b10101110001111001111000000011110'
32 bits, so I don't think "result" will ever equal 2923229214

Mark_M
Posts: 9
Joined: Wed Jun 29, 2016 4:16 pm

Re: RPi.GPIO Wiegand capture speed?

Sat Jul 09, 2016 4:45 pm

Thanks Tom,
Works like a charm!

I'm going to be reading from an MySQL database, so didn't update the if statement yet.

Edindoffer
Posts: 1
Joined: Sat Dec 15, 2018 1:19 pm

Re: RPi.GPIO Wiegand capture speed?

Sat Dec 15, 2018 1:25 pm

joan wrote:
Fri Jul 05, 2013 9:21 am
I was sufficiently interested to come up with a C implementation of what I think wiegand data looks like.

*
Hi Joan,
can you please help me. I am not sure what am I doing wrong when I am trying to compile the code.
Thanks!

g++ -Wall -pthread -o wiegand wiegand.c -lpigpio -lrt

Code: Select all

wiegand.c:1:2: error: invalid preprocessing directive #!
 #!/usr/bin/env python
  ^
wiegand.c:3:6: error: invalid preprocessing directive #green
     #green/data0 is pin 22
      ^~~~~
wiegand.c:4:6: error: invalid preprocessing directive #white
     #white/data1 is pin 7
      ^~~~~
wiegand.c:11:12: error: empty character constant
     bits = ''

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

Re: RPi.GPIO Wiegand capture speed?

Sat Dec 15, 2018 3:19 pm

A Python version seems to have been copied over the source C code of wiegand.c. So the compiler is trying to compile Python source as a C program. The compiler will error out.

Go to example wiegand code and download the version you want to a clean directory.

Personally I'd use the pdif2 version (which requires the pigpio daemon to be running).

Return to “Python”