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