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-16
Revision:
3:ea5e0ab156b5
Parent:
2:2c72a6b13593

File content as of revision 3:ea5e0ab156b5:

#include "wiegand.h"

Wiegand::Wiegand(PinName d0, PinName d1, EventQueue* eventQueue, unsigned char id) :  
_d0(d0), _d1(d1), _eventQueue(eventQueue), _id(id){   
    _transmissionTimeout = 100000;
    _d0.fall(callback(this, &Wiegand::_data0ISR));
    _d1.fall(callback(this, &Wiegand::_data1ISR));
    startCalibrating();
}

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);    
    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;
    }
    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::setBits(unsigned char bits){
    _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);
    _buffer = new uint8_t [_bufferSize];
    reset();
}

void Wiegand::setTimeout(unsigned int time){
    _transmissionTimeout = time * 1000;
}

void Wiegand::_shift_left(volatile unsigned char *ar, int size, int shift){
    while (shift--) {                           
        int carry = 0;                              
        int lastElement = size-1;
        for (int i = 0; i < size; i++) {            
            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;
}