Page 1 of 1

HID RFID card reader API (Wiegand Protocol)

Posted: 26 October 2007, 22:17 PM
by lewtwo
This is an API to read RFID cards using a standard Wiegand Protocol HID reader. Only two wires are needed and no additional hardware. It will read cards with any number of bits. The output is stored in an array of bytes. It may be retrieved as binary string, decimal string or unsigned long.

Have a nice day ...

Posted: 28 October 2007, 15:53 PM
by dkinzer
Thanks for contributing. Are you using this in a commercial product?

Posted: 28 October 2007, 18:58 PM
by lewtwo
dkinzer wrote:Thanks for contributing. Are you using this in a commercial product?
No ... just internally to get around a wee problem.

Re: HID RFID card reader API (Wiegand Protocol)

Posted: 28 October 2007, 19:35 PM
by mikep
lewtwo wrote:This is an API to read RFID cards using a standard Wiegand Protocol HID reader. Only two wires are needed and no additional hardware.
I did a quick code review and I found some places that could be improved. It is up to you if you want to take these changes but I thought I would pass them on as they are also instructive for other people.

Here are the first three things that hit me:
1. The multitasking and sharing of variable seems very dependent on the hardware protocol. You may want to look at writing more robust code that uses a semaphore to access the shared memory.
2. There are a number of hard-coded constants and dependent constants that could be stored in a lookup table.
3. The line

Code: Select all

 J=Shl(J,1)	'same as multiplying by 2
looks a bit incongruous. This shift left is hardly going to save any time. Then looking at the problem further I realized that you could eliminate the calculate loop and save memory as well.

The basic problem is that you are using an array of bytes rather than bits and not using the Alias feature of ZBasic. This is a very powerful feature that allows the memory for variables to be overlaid, within some constraints. Here is the declarations reusing some of your variable names. Note the 4 aliases of UnsignedLongs with byte alignment.

Code: Select all

Private RfidIdx as Byte
Private Const RFID_MAX_BITS as Byte = 64
Private ByteAlign RFIDQue(1 To RFID_MAX_BITS) As Bit
Private RFIDValues(1 to RFID_MAX_BITS\8) As Byte Alias RFIDQue(1) ' only used for initialization
Private RFCODE26 as UnsignedLong Alias RFIDQue(1)
Private RFCODE34 as UnsignedLong Alias RFIDQue(1)
Private RFID26 as UnsignedLong Alias RFIDQue(9)
Private RFID34 as UnsignedLong Alias RFIDQue(17)
I initialized the array of 64 bits as follows to provide a test case:

Code: Select all

	' initialize bit values
	RFIDValues(1) = FlipBits(&H07)
	RFIDValues(2) = FlipBits(&H08)
	RFIDValues(3) = FlipBits(&H40)
	RFIDValues(4) = FlipBits(&HA6)	
	RFIDValues(5) = FlipBits(&H80)
	RFIDValues(6) = FlipBits(&H00)
	RFIDValues(7) = FlipBits(&H00)
	RFIDValues(8) = FlipBits(&H00)
Here is the rewrite of the function to retrieve the ID without a loop. Note the shifts to get the correct 15/16 bits and the method to convert the big-endian bit format to a little-endian number. There is a small bug in this code for 26-bit devices - I will leave it to you resolve it.

Code: Select all

Public Function RfIDDec2() as UnsignedLong
	Dim Val As UnsignedInteger
	
		Select Case RfidIdx
		Case 26
		    RfIDDec2 = RFID26
			Val = CUInt(Shr(RfIDDec2,1))
			RfIDDec2 = CULng(MakeWord(FlipBits(HiByte(Val)), FlipBits(LoByte(Val))))
		Case 34
		    RfIDDec2 = RFID34
			Val = CUInt(Shr(RfIDDec2,1))
			RfIDDec2 = CULng(MakeWord(FlipBits(HiByte(Val)), FlipBits(LoByte(Val))))		
		Case Else
			RfIDDec2=0
	End Select
End Function
Here is the simplified code to retrieve the facility code that uses a similar mechanism of bit shifts and endian flipping to retrieve the correct code as an unsigned long:

Code: Select all

Public Function RfIDFacility2() as UnsignedLong
	Dim Val As UnsignedInteger
	
		Select Case RfidIdx
		Case 26
			RfIDFacility2 = RFCODE26
			Val = CUInt(Shl(Shr(RfIDFacility2,1),7))
			RfIDFacility2 = CULng(MakeWord(FlipBits(HiByte(Val)), FlipBits(LoByte(Val))))
		Case 34
			RfIDFacility2 = RFCODE34
			Val = CUInt(Shr(RfIDFacility2,1))
			RfIDFacility2 = CULng(MakeWord(FlipBits(HiByte(Val)), FlipBits(LoByte(Val))))
		Case Else
			RfIDFacility2=0
	End Select
End Function
There is a more cleanup that could be applied to this code but I wanted to give you an initial idea of the 9x speedup that can be achieved and leave the rest to you. Here are some performance results in microseconds for the old and new code:
[table]
[row][mcol]Card Type[mcol]Old Code[mcol]Improved Code
[row]Facility Code[col]26[col]373[col]59
[row]ID[col]26[col]531[col]57
[row]Facility Code[col]34[col]623[col]63
[row]ID[col]34[col]580[col]63
[/table]
Mike Perks
Check out the new ZX-128e and ZX-1281e ZBasic devices at OakMicros.com

Posted: 28 October 2007, 20:46 PM
by lewtwo
Thank you.

I am new to the MPU environment. I just got into this a couple of weeks ago because tossing a dedicated Intel based XP machine at the problem seemed a little extreme. I first tried a Basic Stamp, then a New Media BX24 and moved to the ZX24 because it had the handy interrupts (negating the need for extra hardware).

I completely missed the "alias" feature . Even the ZX-24a is over kill for what I am trying to do. On the other hand there is not point to wasting cycles or ram. I will work on the code and post a cleaned up version later.

Currently I am learning how to design a circuit board and get it made so I can have real RS-232 levels (I was so trying to avoid doing anything at that hardware level). I did look at ZX-24ae but I did not find any readily available generic carrier boards.

Posted: 30 October 2007, 20:47 PM
by DocJC
The number of options for getting circuit boards made keeps growing, a good thing.
I've used ExpressPCB (www.expresspcb.com) numerous times, always with good results.
The user interface is easy to learn, the software is provided without charge, and the board prices are reasonable.
JC