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.

wiegand.cpp

Committer:
goymame
Date:
2019-05-08
Revision:
2:2c72a6b13593
Parent:
0:4929608f96d0
Child:
3:ea5e0ab156b5

File content as of revision 2:2c72a6b13593:

#include "wiegand.h"

Wiegand::Wiegand(PinName d0, PinName d1, EventQueue* eventQueue, unsigned char bits, unsigned char id) :  
_d0(d0), _d1(d1), _eventQueue(eventQueue), _bits(bits), _id(id){   
    _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::attach(Callback<void(Wiegand *WiegandObj)> wiegandCallback){
    _callback = wiegandCallback;
}

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();
    }
    _shift_left(_buffer,_bufferSize,1);
    _buffer[_bufferSize-1] |=1; 
    _bitsRead++;
    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;
}

unsigned char Wiegand::getId(){
    return _id;
}

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(this);
}

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;
}