This library reads Wiegand, saving it into a buffer, calling a callback function after it is full or a timeout is reached.

Dependents:   mbed-os-wiegand-example

This library reads Wiegand, saving it into a buffer, calling a callback function after it is full or a timeout is reached. Data can be extracted as :

  • Raw
  • Base 10 Integer
  • Base 10 String
  • Base 16 String

Always call reset after saving Wiegand data.

It automatically calibrates the timeout during the first reading unless specified.

Timeout can be set using setTimout, units are in milliseconds (first call stopCalibrating()).

EventQueue is required for deferring from ISR, it is possible to dispatch the EventQueue from the mainQueue or any other thread.

Revision:
0:4929608f96d0
Child:
2:2c72a6b13593
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wiegand.cpp	Sat Apr 27 23:37:01 2019 +0000
@@ -0,0 +1,204 @@
+#include "wiegand.h"
+
+Wiegand::Wiegand(PinName d0, PinName d1, EventQueue* eventQueue, Callback<void(void)> wiegandCallback, unsigned char bits) :  
+_d0(d0), _d1(d1), _eventQueue(eventQueue), _callback(wiegandCallback), _bits(bits){   
+    _bufferSize = (_bits/8);
+    if((_bits % 8) >0) 
+        _bufferSize++;
+    _hexDigits = (_bits/4);
+    if((_bits % 4) >0) 
+        _hexDigits++;
+    unsigned long long int maxNumber = 0;
+    for(int i = 0; i < _bits; i++)
+        maxNumber +=  pow((long double)2,i);
+    _decDigits = 0;
+    do { maxNumber /= 10; _decDigits++; } while(maxNumber != 0);
+    _transmissionTimeout = 100000;
+    
+    _buffer = new uint8_t [_bufferSize];
+    _d0.fall(callback(this, &Wiegand::_data0ISR));
+    _d1.fall(callback(this, &Wiegand::_data1ISR));
+    startCalibrating();
+    reset();
+}
+
+Wiegand::~Wiegand(){
+    delete[] _buffer;
+    delete[] _interPulseGapBuffer;
+}
+
+void Wiegand::calibrateTimeout(void){
+    unsigned int interPulseGapAvg = 0;
+    for( int i = 1; i < _bits; i++)
+        interPulseGapAvg += _interPulseGapBuffer[i];
+    interPulseGapAvg /= _bits - 1 ;
+    _transmissionTimeout = interPulseGapAvg * 10 ;
+}
+
+void Wiegand::_data0ISR(void){
+    _timeout.detach();
+    if ( _autoCalibration){
+        _interPulseGapTimer.stop();
+        _interPulseGapBuffer[_bitsRead] = _interPulseGapTimer.read_us();
+        _interPulseGapTimer.reset();
+    }
+    _bitsRead++;
+    _shift_left(_buffer,_bufferSize,1);    // shift 0 into buffer
+    if (_bitsRead == _bits)
+        _onWiegandISR();
+    else 
+        _timeout.attach_us(callback(this, &Wiegand::_onWiegandISR), _transmissionTimeout);
+}
+
+void Wiegand::_data0ISRRise(void){
+    _interPulseGapTimer.start();
+}
+
+void Wiegand::_data1ISR(void){
+    _timeout.detach();
+    if ( _autoCalibration){           
+        _interPulseGapTimer.stop();
+        _interPulseGapBuffer[_bitsRead] = _interPulseGapTimer.read_us();
+        _interPulseGapTimer.reset();
+    }
+    _bitsRead++;
+    _shift_left(_buffer,_bufferSize,1);
+    _buffer[_bufferSize-1] |=1; 
+    _timeout.attach_us(callback(this, &Wiegand::_onWiegandISR), _transmissionTimeout);
+    if (_bitsRead == _bits)
+        _onWiegandISR();
+    else 
+        _timeout.attach_us(callback(this, &Wiegand::_onWiegandISR), _transmissionTimeout);
+}
+
+void Wiegand::_data1ISRRise(void){
+    _interPulseGapTimer.start();
+}
+
+unsigned char  Wiegand::getDecDigits(){
+    return _decDigits;
+}
+
+void Wiegand::getDecString(volatile char* decString){
+    long double rawInt = getRawInt();
+    if (!rawInt) return;
+    volatile char* rawString = new volatile char [_decDigits+1];
+    memset((char*)rawString,'\0',_decDigits);
+    int result = snprintf ( (char*)rawString, _decDigits+1, "%.0Lf", rawInt);
+    if (result > 0 && result < _decDigits+1)
+        for(int j=0; j < _decDigits; ++j)
+            decString[j] = rawString[j];
+    delete[] rawString;
+}
+
+unsigned char  Wiegand::getHexDigits(){
+    return _hexDigits;
+}
+
+void Wiegand::getHexString(volatile char* hexString){
+    long double rawInt = getRawInt();
+    if (!rawInt) return;   
+    volatile char* hexadecimalNumber = new volatile char [_hexDigits+1];
+    memset((char*)hexadecimalNumber,'\0',_hexDigits+1);
+    unsigned long long int quotient = rawInt;
+    int i=_hexDigits ,temp = 0;
+    volatile unsigned char counter = 0;
+    while(quotient!=0) {
+        counter++;
+        temp = quotient % 16;
+        if( temp < 10)
+            temp = temp + 48; 
+        else
+            temp = temp + 55;
+        hexadecimalNumber[--i] = temp;
+        quotient = quotient / 16;
+    }
+    //shift array left if string is smaller than array
+    if (counter < _hexDigits){
+        unsigned char difference = _hexDigits - counter;
+        for(int j = 0 ; j < counter; j++){
+            hexadecimalNumber[ j  ] = hexadecimalNumber[ j + difference ];
+            hexadecimalNumber[ j + (_hexDigits - counter)  ] = '\0';
+        }
+    }
+    strcpy ( (char*)hexString,(char*)hexadecimalNumber );
+    delete[] hexadecimalNumber;
+}
+
+uint8_t * Wiegand::getRaw(void){
+    return _buffer;
+} 
+
+long double Wiegand::getRawInt(void){
+    long double rawInt = 0;
+    unsigned char countdown = _bits - 1 ;
+    uint8_t* tempBuffer = new uint8_t [1];
+    memset((unsigned char *)tempBuffer, 0, 1);
+    for (unsigned int i=0; i < _bufferSize;i++){
+        tempBuffer[0] = _buffer[i];
+        for(int x=0; x<8;x++) {
+            if(tempBuffer[0] & 0x80) 
+                rawInt +=  pow((long double)2,countdown);
+            tempBuffer[0]<<=1;
+            countdown--;
+        }
+    }
+    delete[] tempBuffer;
+    return rawInt;
+}
+
+unsigned int Wiegand::getTimeout(void){
+    return _transmissionTimeout;
+}
+
+void Wiegand::_onWiegandISR(void){
+    _eventQueue->call(callback(this, &Wiegand::_onWiegandNonISR));
+}
+
+void Wiegand::_onWiegandNonISR(void){
+    if (_autoCalibration){
+        stopCalibrating();
+        calibrateTimeout();
+    }
+    _callback();
+}
+
+void Wiegand::reset(void){
+    memset((unsigned char *)_buffer, 0, _bufferSize);
+    _bitsRead = 0;
+}
+
+void Wiegand::setTimeout(unsigned int time){
+    _transmissionTimeout = time * 1000;
+}
+
+void Wiegand::_shift_left(volatile unsigned char *ar, int size, int shift){
+    while (shift--) {                           // for each bit to shift ...
+        int carry = 0;                              // clear the initial carry bit.
+        int lastElement = size-1;
+        for (int i = 0; i < size; i++) {            // for each element of the array, from low byte to high byte
+            if (i!=lastElement) {
+                carry = (ar[i+1] & 0x80) ? 1 : 0;
+                ar[i] = carry | (ar[i]<<1);
+            }
+            else {
+                ar[i] <<=1;
+            }
+        }   
+    }
+}
+
+void Wiegand::startCalibrating(void){
+    _autoCalibration = true;
+    _d0.rise(callback(this, &Wiegand::_data0ISRRise));
+    _d1.rise(callback(this, &Wiegand::_data1ISRRise));
+    _interPulseGapBuffer = new volatile int [_bits];
+}
+
+void Wiegand::stopCalibrating(){
+    _autoCalibration = false;
+    _interPulseGapTimer.stop();
+    _d0.rise(0);
+    _d1.rise(0);
+    delete[] _interPulseGapBuffer;
+}
\ No newline at end of file