[SOLVED] Using wireless to eliminate wiegand wiring

I must emphasize that I whipped this up quickly this afternoon and there might be bugs. But it is sort of a proof of concept of this sort of thing.

The HID ProxPoint Plus reader is connected to the top Photon, which reads the Wiegand signals, decodes, and does a Particle.publish. The bottom left Photon subscribes to the events and reconstitutes the signal, which is read by the bottom right Photon.

Reader code:

#include "Particle.h"

const int WIEGAND_D0_PIN = D2; // Green
const int WIEGAND_D1_PIN = D3; // White

void wiegandInterrupt(); // forward declaration
bool decodeWiegand(unsigned long value); // forward declaration

volatile int cardBitCount = 0;
volatile unsigned long cardValue = 0;
volatile unsigned long cardReadStart = 0;

void setup() {
	Serial.begin(9600);

	// Wiegand pulse are narrow, typically 100 microseconds, so interrupts are desirable to accurately
	// detect them
	attachInterrupt(WIEGAND_D0_PIN, wiegandInterrupt, FALLING);
	attachInterrupt(WIEGAND_D1_PIN, wiegandInterrupt, FALLING);
}

void loop() {
	if (cardReadStart != 0) {
		if (cardBitCount == 26) {
			// Got a valid 26-bit card
			if (decodeWiegand(cardValue)) {
				// Is valid
				Particle.publish("card", String(cardValue), PRIVATE);
			}
			cardReadStart = 0;
			cardBitCount = 0;
		}
		else
		if (millis() - cardReadStart > 500) {
			Serial.println("failed to read enough bits");
			cardReadStart = 0;
			cardBitCount = 0;
		}
	}
}

void wiegandInterrupt() {
	if (cardBitCount == 0) {
		cardReadStart = millis();
		cardValue = 0;
	}
	else {
		cardValue <<= 1;
	}

	if (pinReadFast(WIEGAND_D1_PIN) == LOW) {
		cardValue |= 1;
	}
	cardBitCount++;
}

// Note: in the following table the bit numbers are 0-based, 0 - 25 for a 26-bit Wiegand code!
// Bit 25: Even parity, first half of bits
// Bits 24 - 17: Facility code, MSB first 0 - 255
// Bits 16 - 1: Card code, MSB first, 0 - 65536
// Bit 0: Odd parity, second half of bits
bool decodeWiegand(unsigned long value) {
	bool valid = false;

	int facility = (value >> 17) & 0xff;
	int card = (value >> 1) & 0xffff;

	unsigned long tempValue = value;
	int parity = 0;
	for(int ii = 0; ii < 13; ii++) {
		if (tempValue & 1) {
			parity++;
		}
		tempValue >>= 1;
	}
    if ((parity & 0x1) == 1) {
    	// First parity passed
    	parity = 0;
		for(int ii = 0; ii < 13; ii++) {
			if (tempValue & 1) {
				parity++;
			}
			tempValue >>= 1;
		}
		if ((parity & 0x1) == 0) {
			// Second parity passed; looks valid
			Serial.printlnf("value=0x%x facility=%d card=%d", value, facility, card);
			valid = true;
		}
		else {
	    	Serial.printlnf("even parity error value=0x%x", value);
		}
    }
    else {
    	Serial.printlnf("odd parity error value=0x%x", value);
    }
    return valid;
}


Sender (makes Wiegand signals from data):

#include "Particle.h"

#include "SparkIntervalTimer/SparkIntervalTimer.h"

void subscriptionHandler(const char *event, const char *data); // forward declaration
void senderInterrupt(); // forward declaration

const int WIEGAND_D0_PIN = D2; // Green
const int WIEGAND_D1_PIN = D3; // White

const int TIMER_PERIOD_US = 100;
const int LOW_PERIOD = 1;
const int HIGH_PERIOD = 10;

IntervalTimer timer;
int sendBitsLeft = 0;
int sendPeriod = 0;
unsigned long sendValue;

void setup() {
	Serial.begin(9600);

	pinMode(WIEGAND_D0_PIN, OUTPUT);
	digitalWrite(WIEGAND_D0_PIN, HIGH);

	pinMode(WIEGAND_D1_PIN, OUTPUT);
	digitalWrite(WIEGAND_D1_PIN, HIGH);

	timer.begin(senderInterrupt, TIMER_PERIOD_US, uSec);

	Particle.subscribe("card", subscriptionHandler, MY_DEVICES);
}

void loop() {
}

void subscriptionHandler(const char *event, const char *data) {
	unsigned long value = strtoul(data, NULL, 0);
	Serial.printlnf("received value=0x%x", value);

	sendPeriod = 0;
	sendValue = value;
	sendBitsLeft = 26;
}

void senderInterrupt() {
	if (sendBitsLeft > 0) {
		if (sendPeriod == HIGH_PERIOD) {
			sendPeriod = 0;
		}

		if (sendPeriod == 0) {
			// Write out the data bit
			if ((sendValue >> (sendBitsLeft - 1)) & 1) {
				// 1 bit
				digitalWrite(WIEGAND_D1_PIN, LOW);
			}
			else {
				// 0 bit
				digitalWrite(WIEGAND_D0_PIN, LOW);
			}
		}
		else
		if (sendPeriod == LOW_PERIOD) {
			// Restore high
			digitalWrite(WIEGAND_D0_PIN, HIGH);
			digitalWrite(WIEGAND_D1_PIN, HIGH);
			sendBitsLeft--;
		}

		sendPeriod++;
	}
}


4 Likes