mirror of https://github.com/arendst/Tasmota.git
Refactor wiegand to 32-bit
Refactor wiegand from 64-bit to 32-bit while keeping full 34-bit support
This commit is contained in:
parent
05ac7ba4f8
commit
4566aaee05
|
@ -40,6 +40,8 @@
|
|||
* 20220215
|
||||
* - fix 34-bit size parity chk
|
||||
* - fix 64-bit representation after removal of %llu support (Tasmota does not support 64-bit decimal output specifier (%llu) saving 60k code)
|
||||
* - change internal rfid size from uint64_t to uint32_t
|
||||
* - limited max amount of kaypad presses to a 32-bit number (at least 999999999)
|
||||
* ---
|
||||
* 20201101
|
||||
* - fix for #11047 Wiegand 26/34 missed some key press if they are press at normal speed
|
||||
|
@ -106,23 +108,21 @@ class Wiegand {
|
|||
#if (DEV_WIEGAND_TEST_MODE!=1)
|
||||
private:
|
||||
#endif //(DEV_WIEGAND_TEST_MODE==1)
|
||||
uint64_t CheckAndConvertRfid(uint64_t,uint16_t);
|
||||
uint32_t CheckAndConvertRfid(uint64_t,uint16_t);
|
||||
uint8_t CalculateParities(uint64_t, int);
|
||||
bool WiegandConversion (uint64_t , uint16_t );
|
||||
void setOutputFormat(void); // fix output HEX format
|
||||
void HandleKeyPad(void); //handle one tag for multi key strokes
|
||||
|
||||
|
||||
static void handleD0Interrupt(void);
|
||||
static void handleD1Interrupt(void);
|
||||
static void handleDxInterrupt(int in); // fix #11047
|
||||
static void ClearRFIDBuffer(int);
|
||||
|
||||
uint64_t rfid;
|
||||
uint32_t rfid;
|
||||
uint32_t tagSize;
|
||||
const char* outFormat;
|
||||
uint64_t mqttRFIDKeypadBuffer;
|
||||
uint64_t webRFIDKeypadBuffer;
|
||||
uint32_t mqttRFIDKeypadBuffer;
|
||||
uint32_t webRFIDKeypadBuffer;
|
||||
|
||||
static volatile uint64_t rfidBuffer;
|
||||
static volatile uint16_t bitCount;
|
||||
|
@ -149,15 +149,14 @@ volatile bool Wiegand::CodeComplete;
|
|||
volatile RFID_store Wiegand::rfid_found[WIEGAND_RFID_ARRAY_SIZE];
|
||||
volatile int Wiegand::currentFoundRFIDcount;
|
||||
|
||||
|
||||
|
||||
void IRAM_ATTR Wiegand::ClearRFIDBuffer(int endIndex = WIEGAND_RFID_ARRAY_SIZE) {
|
||||
currentFoundRFIDcount=WIEGAND_RFID_ARRAY_SIZE-endIndex; // clear all buffers
|
||||
for (int i= 0; i < endIndex; i++) {
|
||||
rfid_found[i].RFID=0;
|
||||
rfid_found[i].bitCount=0;
|
||||
}
|
||||
currentFoundRFIDcount = WIEGAND_RFID_ARRAY_SIZE - endIndex; // clear all buffers
|
||||
for (uint32_t i = 0; i < endIndex; i++) {
|
||||
rfid_found[i].RFID=0;
|
||||
rfid_found[i].bitCount=0;
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR Wiegand::handleD1Interrupt() { // Receive a 1 bit. (D0=high & D1=low)
|
||||
handleDxInterrupt(1);
|
||||
}
|
||||
|
@ -167,9 +166,9 @@ void IRAM_ATTR Wiegand::handleD0Interrupt() { // Receive a 0 bit. (D0=low & D1=
|
|||
}
|
||||
|
||||
void IRAM_ATTR Wiegand::handleDxInterrupt(int in) {
|
||||
unsigned long curTime = micros(); // to be sure I will use micros() instead of millis() overflow is handle by using the minus operator to compare
|
||||
unsigned long diffTime= curTime - lastFoundTime;
|
||||
if ( (diffTime > CodeGapTime) && (bitCount > 0)) {
|
||||
uint32_t curTime = micros(); // to be sure I will use micros() instead of millis() overflow is handle by using the minus operator to compare
|
||||
uint32_t diffTime = curTime - lastFoundTime;
|
||||
if ((diffTime > CodeGapTime) && (bitCount > 0)) {
|
||||
// previous RFID tag (key pad numer)is complete. Will be detected by the code ending gap
|
||||
// one bit will take the time of impulse_time + impulse_gap_time. it (bitTime) will be recalculated each time an impulse is detected
|
||||
// the devices will add some inter_code_gap_time to separate codes this will be much longer than the bit_time. (WIEGAND_CODE_GAP_FACTOR)
|
||||
|
@ -192,7 +191,7 @@ void IRAM_ATTR Wiegand::handleDxInterrupt(int in) {
|
|||
FirstBitTimeStamp = (curTime != 0) ? curTime : 1; // accept 1µs differenct to avoid a miss the first timestamp if curTime is 0.
|
||||
}
|
||||
else if (bitCount == 2) { // only calculate once per RFID tag, but restrict to values, which are in within a plausible range
|
||||
bitTime = ((diffTime > (WIEGAND_BIT_TIME_DEFAULT/4)) && (diffTime < (4*WIEGAND_BIT_TIME_DEFAULT))) ? diffTime : WIEGAND_BIT_TIME_DEFAULT;
|
||||
bitTime = ((diffTime > (WIEGAND_BIT_TIME_DEFAULT / 4)) && (diffTime < (4 * WIEGAND_BIT_TIME_DEFAULT))) ? diffTime : WIEGAND_BIT_TIME_DEFAULT;
|
||||
CodeGapTime = WIEGAND_CODE_GAP_FACTOR * bitTime;
|
||||
}
|
||||
//save current rfid in array otherwise we will never see the last found tag
|
||||
|
@ -247,7 +246,7 @@ void Wiegand::Init() {
|
|||
#endif // DEV_WIEGAND_TEST_MODE>0
|
||||
}
|
||||
|
||||
uint64_t Wiegand::CheckAndConvertRfid(uint64_t rfidIn, uint16_t bitCount) {
|
||||
uint32_t Wiegand::CheckAndConvertRfid(uint64_t rfidIn, uint16_t bitCount) {
|
||||
uint8_t evenParityBit = 0;
|
||||
uint8_t oddParityBit = (uint8_t) (rfidIn & 0x1); // Last bit = odd parity
|
||||
uint8_t calcParity = 0;
|
||||
|
@ -277,8 +276,8 @@ uint64_t Wiegand::CheckAndConvertRfid(uint64_t rfidIn, uint16_t bitCount) {
|
|||
}
|
||||
calcParity = CalculateParities(rfidIn, bitCount); // Check result on http://www.ccdesignworks.com/wiegand_calc.htm with raw tag as input
|
||||
if (calcParity != (evenParityBit | oddParityBit)) { // Parity bit is wrong
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("WIE: %_X parity error"), &rfidIn); // Print up to uint64_t
|
||||
rfidIn=0;
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("WIE: %_X parity error"), &rfidIn);
|
||||
}
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: even (left) parity: %u "), (evenParityBit>>7));
|
||||
|
@ -286,10 +285,10 @@ uint64_t Wiegand::CheckAndConvertRfid(uint64_t rfidIn, uint16_t bitCount) {
|
|||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: odd (right) parity: %u "), oddParityBit);
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: odd (calc) parity: %u "), (calcParity & 0x01));
|
||||
#endif // DEV_WIEGAND_TEST_MODE>0
|
||||
return rfidIn;
|
||||
return (uint32_t)rfidIn;
|
||||
}
|
||||
|
||||
uint8_t Wiegand::CalculateParities(uint64_t tagWithoutParities, int tag_size=26) {
|
||||
uint8_t Wiegand::CalculateParities(uint64_t tagWithoutParities, int tag_size = 26) {
|
||||
// tag_size is the size of the final tag including the 2 parity bits
|
||||
// So length if the tagWithoutParities should be (tag_size-2) !! That will be not profed and
|
||||
// lead to wrong results if the input value is larger!
|
||||
|
@ -299,7 +298,7 @@ uint8_t Wiegand::CalculateParities(uint64_t tagWithoutParities, int tag_size=26)
|
|||
tag_size -= 2;
|
||||
if (tag_size <= 0) { return retValue; } // Prohibit div zero exception and other wrong inputs
|
||||
uint8_t parity = 1; // Check for odd parity on LSB
|
||||
for (uint8_t i = 0; i < (tag_size / 2); i++) {
|
||||
for (uint32_t i = 0; i < (tag_size / 2); i++) {
|
||||
parity ^= (tagWithoutParities & 1);
|
||||
tagWithoutParities >>= 1;
|
||||
}
|
||||
|
@ -318,53 +317,47 @@ uint8_t Wiegand::CalculateParities(uint64_t tagWithoutParities, int tag_size=26)
|
|||
bool Wiegand::WiegandConversion (uint64_t rfidBuffer, uint16_t bitCount) {
|
||||
bool bRet = false;
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Raw tag %llu, Bit count %u"), rfidBuffer, bitCount);
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Raw tag %_X, Bit count %u"), &rfidBuffer, bitCount); // Print up to uint64_t
|
||||
#endif // DEV_WIEGAND_TEST_MODE>0
|
||||
if ((24 == bitCount) || (26 == bitCount) || (32 == bitCount) || (34 == bitCount)) {
|
||||
// 24, 26, 32, 34-bit Wiegand codes
|
||||
rfid = CheckAndConvertRfid(rfidBuffer, bitCount);
|
||||
tagSize = bitCount;
|
||||
if ((24 == bitCount) || (26 == bitCount) || (32 == bitCount) || (34 == bitCount)) {
|
||||
// 24, 26, 32, 34-bit Wiegand codes
|
||||
rfid = CheckAndConvertRfid(rfidBuffer, bitCount);
|
||||
tagSize = bitCount;
|
||||
bRet = true;
|
||||
}
|
||||
else if (4 == bitCount) {
|
||||
// 4-bit Wiegand codes for keypads
|
||||
rfid = (uint32_t)(rfidBuffer & 0x0000000F);
|
||||
tagSize = bitCount;
|
||||
bRet = true;
|
||||
}
|
||||
else if (8 == bitCount) {
|
||||
// 8-bit Wiegand codes for keypads with integrity
|
||||
// 8-bit Wiegand keyboard data, high nibble is the "NOT" of low nibble
|
||||
// eg if key 1 pressed, data=E1 in binary 11100001 , high nibble=1110 , low nibble = 0001
|
||||
char highNibble = (rfidBuffer & 0xf0) >>4;
|
||||
char lowNibble = (rfidBuffer & 0x0f);
|
||||
if (lowNibble == (~highNibble & 0x0f)) { // Check if low nibble matches the "NOT" of high nibble.
|
||||
rfid = (uint32_t)(lowNibble);
|
||||
bRet = true;
|
||||
}
|
||||
else if (4 == bitCount) {
|
||||
// 4-bit Wiegand codes for keypads
|
||||
rfid = (int)(rfidBuffer & 0x0000000F);
|
||||
tagSize = bitCount;
|
||||
bRet = true;
|
||||
}
|
||||
else if (8 == bitCount) {
|
||||
// 8-bit Wiegand codes for keypads with integrity
|
||||
// 8-bit Wiegand keyboard data, high nibble is the "NOT" of low nibble
|
||||
// eg if key 1 pressed, data=E1 in binary 11100001 , high nibble=1110 , low nibble = 0001
|
||||
char highNibble = (rfidBuffer & 0xf0) >>4;
|
||||
char lowNibble = (rfidBuffer & 0x0f);
|
||||
if (lowNibble == (~highNibble & 0x0f)) { // Check if low nibble matches the "NOT" of high nibble.
|
||||
rfid = (int)(lowNibble);
|
||||
bRet = true;
|
||||
} else {
|
||||
bRet = false;
|
||||
}
|
||||
tagSize = bitCount;
|
||||
} else {
|
||||
// Time reached but unknown bitCount, clear and start again
|
||||
tagSize = 0;
|
||||
bRet = false;
|
||||
}
|
||||
tagSize = bitCount;
|
||||
} else {
|
||||
// Time reached but unknown bitCount, clear and start again
|
||||
tagSize = 0;
|
||||
bRet = false;
|
||||
}
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Tag out %llu, tag size %u "), rfid, tagSize);
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Tag out %u, tag size %u "), rfid, tagSize);
|
||||
#endif // DEV_WIEGAND_TEST_MODE>0
|
||||
return bRet;
|
||||
}
|
||||
|
||||
void Wiegand::setOutputFormat(void)
|
||||
{
|
||||
if (GetOption(WIEGAND_OPTION_HEX) == 0) { outFormat = "u"; }
|
||||
else { outFormat = "X" WIEGAND_OPTION_HEX_POSTFIX ; }
|
||||
}
|
||||
|
||||
void Wiegand::HandleKeyPad(void) { // will be called if a valid key pad input was recognized
|
||||
if (GetOption(WIEGAND_OPTION_KEYPAD_TO_TAG) == 0) { // handle all key pad inputs as ONE Tag until # is recognized
|
||||
if ( (tagSize == 4) || (tagSize == 8) ) {
|
||||
if (GetOption(WIEGAND_OPTION_KEYPAD_TO_TAG) == 0) { // handle all key pad inputs as ONE Tag until # is recognized
|
||||
if ((tagSize == 4) || (tagSize == 8)) {
|
||||
//only handle Keypad strokes if it is requested
|
||||
if (rfid >= 0x0a) { // # * as end of input detected -> all key values which are larger than 9
|
||||
rfid = mqttRFIDKeypadBuffer; // original tagsize of 4 or 8 will be kept.
|
||||
|
@ -372,7 +365,7 @@ void Wiegand::HandleKeyPad(void) { // will be called if a valid key pad input wa
|
|||
mqttRFIDKeypadBuffer = 0;
|
||||
}
|
||||
else {
|
||||
mqttRFIDKeypadBuffer = (mqttRFIDKeypadBuffer*10)+rfid; //left shift + new key
|
||||
mqttRFIDKeypadBuffer = (mqttRFIDKeypadBuffer * 10) + rfid; //left shift + new key
|
||||
webRFIDKeypadBuffer = mqttRFIDKeypadBuffer; // visualising the current typed keys
|
||||
rfid = 0;
|
||||
tagSize = 0;
|
||||
|
@ -386,38 +379,33 @@ void Wiegand::HandleKeyPad(void) { // will be called if a valid key pad input wa
|
|||
}
|
||||
|
||||
void Wiegand::ScanForTag() {
|
||||
unsigned long startTime = micros();
|
||||
uint32_t startTime = micros();
|
||||
handleDxInterrupt(3);
|
||||
if (currentFoundRFIDcount > 0) {
|
||||
unsigned int lastFoundRFIDcount = currentFoundRFIDcount;
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag(). bitTime: %0lu lastFoundTime: %0lu RFIDS in buffer: %lu"), bitTime, lastFoundTime, currentFoundRFIDcount);
|
||||
#endif
|
||||
// format MQTT output
|
||||
// setOutputFormat();
|
||||
// char sFormat[50];
|
||||
// snprintf( sFormat, 50, PSTR(",\"Wiegand\":{\"UID\":%%0ll%s,\"" D_JSON_SIZE "\":%%%s}}"), outFormat, outFormat);
|
||||
for (int i= 0; i < WIEGAND_RFID_ARRAY_SIZE; i++)
|
||||
{
|
||||
if (rfid_found[i].RFID != 0 || (rfid_found[i].RFID == 0 && i == 0)) {
|
||||
uint64_t oldTag = rfid;
|
||||
if (currentFoundRFIDcount > 0) {
|
||||
uint32_t lastFoundRFIDcount = currentFoundRFIDcount;
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag(). bitTime: %u lastFoundTime: %u RFIDS in buffer: %u"), bitTime, lastFoundTime, currentFoundRFIDcount);
|
||||
#endif
|
||||
for (uint32_t i = 0; i < WIEGAND_RFID_ARRAY_SIZE; i++) {
|
||||
if (rfid_found[i].RFID != 0 || (rfid_found[i].RFID == 0 && i == 0)) {
|
||||
uint32_t oldTag = rfid;
|
||||
bool validKey = WiegandConversion(rfid_found[i].RFID, rfid_found[i].bitCount);
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ValidKey: %d Previous tag %llu"), validKey, oldTag);
|
||||
#endif // DEV_WIEGAND_TEST_MODE>0
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ValidKey %d, Previous tag %u"), validKey, oldTag);
|
||||
#endif // DEV_WIEGAND_TEST_MODE>0
|
||||
if (validKey) { // Only in case of valid key do action. Issue#10585
|
||||
HandleKeyPad(); //support one tag for multi key input
|
||||
if (tagSize>0) { //do output only for rfids which are complete
|
||||
if (tagSize > 0) { //do output only for rfids which are complete
|
||||
if (oldTag == rfid) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("WIE: Old tag"));
|
||||
}
|
||||
// ResponseTime_P(sFormat, rfid, tagSize);
|
||||
// Tasmota does not support 64-bit decimal output specifier (%llu) saving 60k code
|
||||
ResponseTime_P(PSTR(",\"Wiegand\":{\"UID\":"));
|
||||
if (GetOption(WIEGAND_OPTION_HEX) == 0) {
|
||||
ResponseTime_P(PSTR(",\"Wiegand\":{\"UID\":%lu,\"" D_JSON_SIZE "\":%d}}"), (uint32_t)rfid, tagSize);
|
||||
ResponseAppend_P(PSTR("%u"), rfid);
|
||||
} else {
|
||||
ResponseTime_P(PSTR(",\"Wiegand\":{\"UID\":\"%1_X" WIEGAND_OPTION_HEX_POSTFIX "\",\"" D_JSON_SIZE "\":%d}}"), &rfid, tagSize);
|
||||
ResponseAppend_P(PSTR("\"%X" WIEGAND_OPTION_HEX_POSTFIX "\""), rfid);
|
||||
}
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_SIZE "\":%d}}"), tagSize);
|
||||
MqttPublishTeleSensor();
|
||||
}
|
||||
}
|
||||
|
@ -426,33 +414,29 @@ void Wiegand::ScanForTag() {
|
|||
if (currentFoundRFIDcount > lastFoundRFIDcount) {
|
||||
// if that happens: we need to move the id found during the loop to top of the array
|
||||
// and correct the currentFoundRFIDcount
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag() %lu tags added while working on buffer"), (currentFoundRFIDcount-lastFoundRFIDcount));
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag() %u tags added while working on buffer"), (currentFoundRFIDcount - lastFoundRFIDcount));
|
||||
}
|
||||
ClearRFIDBuffer(); //reset array
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag() time elapsed %lu"), (micros() - startTime));
|
||||
#endif
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag() time elapsed %u"), (micros() - startTime));
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
void Wiegand::Show(void) {
|
||||
// setOutputFormat();
|
||||
// char sFormat [30];
|
||||
// snprintf( sFormat, 30,PSTR("{s}Wiegand UID{m}%%ll%s {e}"), outFormat);
|
||||
// if (tagSize>0) { WSContentSend_PD(sFormat, rfid); }
|
||||
// else { WSContentSend_PD(sFormat, webRFIDKeypadBuffer); }
|
||||
// Tasmota does not support 64-bit decimal output specifier (%llu) saving 60k code
|
||||
if (GetOption(WIEGAND_OPTION_HEX) == 0) {
|
||||
WSContentSend_P(PSTR("{s}Wiegand UID{m}%lu{e}"), (tagSize>0) ? (uint32_t)rfid : (uint32_t)webRFIDKeypadBuffer);
|
||||
} else {
|
||||
WSContentSend_P(PSTR("{s}Wiegand UID{m}%1_X" WIEGAND_OPTION_HEX_POSTFIX "{e}"), (tagSize>0) ? &rfid : &webRFIDKeypadBuffer);
|
||||
}
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Tag %llu, Bits %u"), rfid, bitCount);
|
||||
#endif // DEV_WIEGAND_TEST_MODE>0
|
||||
WSContentSend_P(PSTR("{s}Wiegand UID{m}"));
|
||||
if (GetOption(WIEGAND_OPTION_HEX) == 0) {
|
||||
WSContentSend_P(PSTR("%u"), (tagSize > 0) ? rfid : webRFIDKeypadBuffer);
|
||||
} else {
|
||||
WSContentSend_P(PSTR("%X" WIEGAND_OPTION_HEX_POSTFIX), (tagSize > 0) ? rfid : webRFIDKeypadBuffer);
|
||||
}
|
||||
WSContentSend_P(PSTR("{e}"));
|
||||
|
||||
|
||||
#if (DEV_WIEGAND_TEST_MODE)>0
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Tag %u, Bits %u"), rfid, bitCount);
|
||||
#endif // DEV_WIEGAND_TEST_MODE>0
|
||||
}
|
||||
#endif // USE_WEBSERVER
|
||||
|
||||
|
|
Loading…
Reference in New Issue