Matthew Lee
Published © GPL3+

PHPoC Blue with Wiegand RFID Reader

Reading RFID tags from an RFID reader with Wiegand protocol and displaying it in a web browser through a web socket.

IntermediateShowcase (no instructions)8 hours3,137
PHPoC Blue with Wiegand RFID Reader

Things used in this project

Hardware components

PHPoC Blue
PHPoC Blue
with a USB WIFI dongle
×1
Jumper wires (generic)
Jumper wires (generic)
×1
RFID Reader
×1

Story

Read more

Schematics

file_sbqk4twvda_76PpdgoepD.jpg

Code

wiegand.php

PHP
processing wiegand protocol
<?php

define ("WIEGAND_DATA_PULSE_WIDTH", 100); // 100 us
define ("WIEGAND_DATA_INTERVAL", 1600);   // 1600 us

function check_wiegand26_parity($str)
{
    if(strlen($str) != 26) return false;
    
    // bit 0 parity : EVEN for the former 12bit (bit1 ~ bit 12)
    for($i = 1, $cnt = 0; $i < 13; $i++) if(substr($str, $i, 1) == "1") $cnt++;
    if($cnt % 2 && (substr($str, 0, 1) == "0")) return false;
    if(!($cnt % 2) && (substr($str, 0, 1) == "1")) return false;
    
    // bit 25 parity : ODD for the latter 12bit (bit13 ~ bit 24)
    for($i = 13, $cnt = 0; $i < 25; $i++) if(substr($str, $i, 1) == "1") $cnt++;
    if($cnt % 2 && (substr($str, 25, 1) == "1")) return false;
    if(!($cnt % 2) && (substr($str, 25, 1) == "0")) return false;
    
    return true;
}
 
function binstr2int($binstr)
{
    for($i = strlen($binstr) - 1, $pos = 0, $num = 0; $i >= 0; $i--, $pos++)
    {
        if(substr($binstr, $i, 1) == "1") $num |= (1 <<$pos);
    }
    return $num;
}
 
function get_wiegand26_id($str)
{
    if(strlen($str) != 26) return false;
    
    $str_id = substr($str, 9, 16);
    $id = binstr2int($str_id);
    
    return $id;
}
 
function get_wiegand26_fac_code($str)
{
    if(strlen($str) != 26) return false;
    
    $str_code = substr($str, 1, 8);
    $code = binstr2int($str_code);
    
    return $code;
}
 
function get_wiegand26_full_id($str)
{
    if(strlen($str) != 26) return false;
    
    $str_full_id = substr($str, 1, 24);
    $full_id = binstr2int($str_full_id);
    
    return $full_id;
}
 
function wiegand_scan()
{
    $ht0 = pid_open("/mmap/ht0");
    $ht1 = pid_open("/mmap/ht1");
 
/* 
    div_unit : 42(1us)
    data pulse width range: 20us - 100us
    data interval : 200us - 20ms
    Maximum data duration: 520ms (maximum bit length: 20ms * 26 bits)
*/
	$time_unit = 20; // 20us
	$div_unit  = 20 * 42; // 1us: 42
	$bit_slot  = WIEGAND_DATA_INTERVAL / 20;
 
    $frame_len = 26;
    $bad_format = "Bad Wiegand Format";
   
    pid_ioctl($ht0, "set div $div_unit");
    pid_ioctl($ht1, "set div $div_unit");
    pid_ioctl($ht0, "set mode capture fall");
    pid_ioctl($ht1, "set mode capture rise");
    pid_ioctl($ht0, "set repc $frame_len");
    pid_ioctl($ht1, "set repc $frame_len");
    pid_ioctl($ht0, "set trigger from pin fall");
    pid_ioctl($ht1, "set trigger from pin fall");
 
    pid_ioctl($ht0, "start");
    pid_ioctl($ht1, "start");

    // getting durations each edges for D0(ht0) and D1(ht1)
    while(1)
    {
        $st_ht0 = pid_ioctl($ht0, "get state");
        $st_ht1 = pid_ioctl($ht1, "get state");
    
        $ht0_cnt = $frame_len - pid_ioctl($ht0, "get repc");
        $ht1_cnt = $frame_len - pid_ioctl($ht1, "get repc");
 
        if(($ht0_cnt + $ht1_cnt) >= $frame_len) break;
        if($st_ht0 == 0 && $st_ht1 == 0) break;
    }
 
    pid_ioctl($ht0, "stop");
    pid_ioctl($ht1, "stop");

    // making binary string by duration of ht0(D0)
    //   adding "0" for each edge
    //   adding "1" supposed position between "0"s 
    $ht0_str = "0";
    for($i = 1; $i < $ht0_cnt; $i++) 
    {
        $cnt = pid_ioctl($ht0, "get count $i");
        $tmp = (int)(round($cnt/$bit_slot));
        for($j = 1; $j<$tmp; $j++) $ht0_str .= "1";
        $ht0_str .= "0";
    }

    // making binary string by duration of ht1(D1)
    //   adding "1" for each edge
    //   adding "0" supposed position between "1"s 
    $ht1_str = "1";
    for($i = 1; $i < $ht1_cnt; $i++) 
    {    
        $cnt = pid_ioctl($ht1, "get count $i");
        $tmp = (int)(round($cnt/$bit_slot));
        for($j = 1; $j<$tmp; $j++) $ht1_str .= "0";
        $ht1_str .= "1";
    }
    
 
    pid_close($ht0);
    pid_close($ht1);
 
    $strlen_ht0 = strlen($ht0_str);
    $strlen_ht1 = strlen($ht1_str);


     // for debugging
    echo "ht0_str($strlen_ht0) = $ht0_str\r\n";
    echo "ht1_str($strlen_ht1) = $ht1_str\r\n";

	// merging D0 and D1 by removing duplicated data
    $rfid = "";
    $len_intersection = $strlen_ht0 + $strlen_ht1 - $frame_len;
 
    // when either string size is equal to max string size
    if($strlen_ht0 >= $frame_len)
    {
        if(strpos($ht0_str, $ht1_str) !== false) $rfid = $ht0_str;
        else $rfid = $bad_format;
    }
    else if($strlen_ht1 >= $frame_len)
    {
        if(strpos($ht1_str, $ht0_str) !== false) $rfid = $ht1_str;
        else $rfid = $bad_format;
    }
    // when the sum of two string size is equal to max string size
    else if(($strlen_ht0 + $strlen_ht1) == $frame_len)
    {
        if(check_wiegand26_parity($ht0_str . $ht1_str) == true) $rfid = $ht0_str . $ht1_str;
        else if(check_wiegand26_parity($ht1_str . $ht0_str) == true) $rfid = $ht1_str . $ht0_str;
        else $rfid = $bad_format;
    }
    // the others
    else
    {
        $tmp_str = substr($ht0_str, 0, $len_intersection);
        $ident_pos0 = strpos($ht1_str, $tmp_str, $strlen_ht1-$len_intersection);    
 
        $tmp_str = substr($ht1_str, 0, $len_intersection);    
        $ident_pos1 = strpos($ht0_str, $tmp_str, $strlen_ht0-$len_intersection);
 
        if($ident_pos0 !== false) $rfid = $ht1_str . substr($ht0_str, $len_intersection);
        else if($ident_pos1 !== false) $rfid = $ht0_str . substr($ht1_str, $len_intersection);
        else $rfid = $bad_format;
    }
        
    return $rfid;
}
 
 
?>

task0.php

PHP
reading RFID tag and transmitting it through a web socket
<?php
 
include_once "lib/sn_tcp_ws.php";
include_once "wiegand.php";
 
ws_setup(0, "rfid", "csv.phpoc");
 
$rwbuf = "";
$count = 1;
 
$state_old = 0;
 
while(1)
{
    $rfid = wiegand_scan();
    
    if(check_wiegand26_parity($rfid) == false) 
    {
    	$full_id="error";
    	echo "wiegand: parity error($rfid)\r\n";
	}
    else
    {
        $id = get_wiegand26_id($rfid);
        $fac_code = get_wiegand26_fac_code($rfid);
        $full_id = get_wiegand26_full_id($rfid);
        echo "full_id: $full_id, fac_code: $fac_code, id: $id\r\n";
    }
    
    if(ws_state(0) == TCP_CONNECTED)
    {
        ws_write(0, "$full_id");
        echo "full_id: $full_id, fac_code: $fac_code, id: $id\r\n";
    }
}
 
?>

index.php

PHP
web page - getting RFID tag data from the task0.php through the web socket and displaying it in the web page
<?php
$ws_host = _SERVER("HTTP_HOST");
?>
<!DOCTYPE html>
<html>
<head>
<title>PHPoC</title>
<script>
var ws;
var count = 1;
function ws_init()
{
    ws = new WebSocket("ws://<?echo $ws_host?>/rfid", "csv.phpoc");
 
    //ws.onopen  = function(){ document.getElementById("ws_state").innerHTML = "connected" };
    ws.onclose = function(){ document.getElementById("ws_state").innerHTML = "closed"};
    ws.onerror = function(){ alert("websocket error " + this.url) };
 
    ws.onopen = ws_onopen;
    ws.onmessage = ws_onmessage;
}
function ws_onopen(e_msg)
{
    e_msg = e_msg || window.event; // MessageEvent
     
    document.getElementById("ws_state").innerHTML = "connected";
    document.getElementById("ws_reply").innerHTML = e_msg.data;
}
function ws_onmessage(e_msg)
{
    e_msg = e_msg || window.event; // MessageEvent
 
    document.getElementById("ws_reply").innerHTML = e_msg.data;
}
window.onload = ws_init;
</script>
</head>
 
<body>
 
<img style="margin:0px auto;display:block" src="k5-dam.jpg">
<h1 style="text-align:center" id="ws_reply">-</h1>
 
</body>
</html>

Credits

Matthew Lee

Matthew Lee

2 projects • 28 followers
Hardware Engineer

Comments