wiegand.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. #include "wiegand.h"
  2. #include <furi.h>
  3. #include <furi_hal.h>
  4. volatile unsigned long WIEGAND::_cardTempHigh = 0;
  5. volatile unsigned long WIEGAND::_cardTemp = 0;
  6. volatile unsigned long WIEGAND::_lastWiegand = 0;
  7. unsigned long WIEGAND::_code = 0;
  8. unsigned long WIEGAND::_codeHigh = 0;
  9. volatile int WIEGAND::_bitCount = 0;
  10. int WIEGAND::_wiegandType = 0;
  11. constexpr uint32_t clocks_in_ms = 64 * 1000;
  12. const GpioPin* const pinD0 = &gpio_ext_pa4;
  13. const GpioPin* const pinD1 = &gpio_ext_pa7;
  14. WIEGAND::WIEGAND() {
  15. }
  16. unsigned long WIEGAND::getCode() {
  17. return _code;
  18. }
  19. unsigned long WIEGAND::getCodeHigh() {
  20. return _codeHigh;
  21. }
  22. int WIEGAND::getWiegandType() {
  23. return _wiegandType;
  24. }
  25. bool WIEGAND::available() {
  26. bool ret;
  27. FURI_CRITICAL_ENTER();
  28. ret = DoWiegandConversion();
  29. FURI_CRITICAL_EXIT();
  30. return ret;
  31. }
  32. static void input_isr_d0(void* _ctx) {
  33. WIEGAND* _this = static_cast<WIEGAND*>(_ctx);
  34. _this->ReadD0();
  35. }
  36. static void input_isr_d1(void* _ctx) {
  37. WIEGAND* _this = static_cast<WIEGAND*>(_ctx);
  38. _this->ReadD1();
  39. }
  40. void WIEGAND::begin() {
  41. _lastWiegand = 0;
  42. _cardTempHigh = 0;
  43. _cardTemp = 0;
  44. _code = 0;
  45. _wiegandType = 0;
  46. _bitCount = 0;
  47. furi_hal_gpio_init_simple(pinD0, GpioModeInterruptFall); // Set D0 pin as input
  48. furi_hal_gpio_init_simple(pinD1, GpioModeInterruptFall); // Set D1 pin as input
  49. furi_hal_gpio_add_int_callback(pinD0, input_isr_d0, this);
  50. furi_hal_gpio_add_int_callback(pinD1, input_isr_d1, this);
  51. }
  52. void WIEGAND::end() {
  53. furi_hal_gpio_remove_int_callback(pinD0);
  54. furi_hal_gpio_remove_int_callback(pinD1);
  55. furi_hal_gpio_init_simple(pinD0, GpioModeAnalog);
  56. furi_hal_gpio_init_simple(pinD1, GpioModeAnalog);
  57. }
  58. void WIEGAND::ReadD0() {
  59. _bitCount++; // Increament bit count for Interrupt connected to D0
  60. if(_bitCount > 31) // If bit count more than 31, process high bits
  61. {
  62. _cardTempHigh |= ((0x80000000 & _cardTemp) >> 31); // shift value to high bits
  63. _cardTempHigh <<= 1;
  64. _cardTemp <<= 1;
  65. } else {
  66. _cardTemp <<= 1; // D0 represent binary 0, so just left shift card data
  67. }
  68. _lastWiegand = DWT->CYCCNT; // Keep track of last wiegand bit received
  69. }
  70. void WIEGAND::ReadD1() {
  71. _bitCount++; // Increment bit count for Interrupt connected to D1
  72. if(_bitCount > 31) // If bit count more than 31, process high bits
  73. {
  74. _cardTempHigh |= ((0x80000000 & _cardTemp) >> 31); // shift value to high bits
  75. _cardTempHigh <<= 1;
  76. _cardTemp |= 1;
  77. _cardTemp <<= 1;
  78. } else {
  79. _cardTemp |= 1; // D1 represent binary 1, so OR card data with 1 then
  80. _cardTemp <<= 1; // left shift card data
  81. }
  82. _lastWiegand = DWT->CYCCNT; // Keep track of last wiegand bit received
  83. }
  84. unsigned long WIEGAND::GetCardId(
  85. volatile unsigned long* codehigh,
  86. volatile unsigned long* codelow,
  87. char bitlength) {
  88. if(bitlength == 26) // EM tag
  89. return (*codelow & 0x1FFFFFE) >> 1;
  90. if(bitlength == 24) return (*codelow & 0x7FFFFE) >> 1;
  91. if(bitlength == 34) // Mifare
  92. {
  93. *codehigh = *codehigh & 0x03; // only need the 2 LSB of the codehigh
  94. *codehigh <<= 30; // shift 2 LSB to MSB
  95. *codelow >>= 1;
  96. return *codehigh | *codelow;
  97. }
  98. if(bitlength == 32) {
  99. return (*codelow & 0x7FFFFFFE) >> 1;
  100. }
  101. return *codelow; // EM tag or Mifare without parity bits
  102. }
  103. char translateEnterEscapeKeyPress(char originalKeyPress) {
  104. switch(originalKeyPress) {
  105. case 0x0b: // 11 or * key
  106. return 0x0d; // 13 or ASCII ENTER
  107. case 0x0a: // 10 or # key
  108. return 0x1b; // 27 or ASCII ESCAPE
  109. default:
  110. return originalKeyPress;
  111. }
  112. }
  113. bool WIEGAND::DoWiegandConversion() {
  114. unsigned long cardID;
  115. unsigned long sysTick = DWT->CYCCNT;
  116. if((sysTick - _lastWiegand) >
  117. (25 * clocks_in_ms)) // if no more signal coming through after 25ms
  118. {
  119. if((_bitCount == 24) || (_bitCount == 26) || (_bitCount == 32) || (_bitCount == 34) ||
  120. (_bitCount == 37) || (_bitCount == 40) || (_bitCount == 8) ||
  121. (_bitCount ==
  122. 4)) // bitCount for keypress=4 or 8, Wiegand 26=24 or 26, Wiegand 34=32 or 34
  123. {
  124. _codeHigh = 0;
  125. // shift right 1 bit to get back the real value - interrupt done 1 left shift in advance
  126. _cardTemp >>= 1;
  127. // bit count more than 32 bits, shift high bits right to make adjustment
  128. if(_bitCount > 32) _cardTempHigh >>= 1;
  129. if(_bitCount == 8) // keypress wiegand with integrity
  130. {
  131. // 8-bit Wiegand keyboard data, high nibble is the "NOT" of low nibble
  132. // eg if key 1 pressed, data=E1 in binary 11100001 , high nibble=1110 , low nibble = 0001
  133. char highNibble = (_cardTemp & 0xf0) >> 4;
  134. char lowNibble = (_cardTemp & 0x0f);
  135. _wiegandType = _bitCount;
  136. _bitCount = 0;
  137. _cardTemp = 0;
  138. _cardTempHigh = 0;
  139. if(lowNibble ==
  140. (~highNibble & 0x0f)) // check if low nibble matches the "NOT" of high nibble.
  141. {
  142. _code = (int)translateEnterEscapeKeyPress(lowNibble);
  143. return true;
  144. } else {
  145. _lastWiegand = sysTick;
  146. _bitCount = 0;
  147. _cardTemp = 0;
  148. _cardTempHigh = 0;
  149. return false;
  150. }
  151. // TODO: Handle validation failure case!
  152. } else if(4 == _bitCount) {
  153. // 4-bit Wiegand codes have no data integrity check so we just
  154. // read the LOW nibble.
  155. _code = (int)translateEnterEscapeKeyPress(_cardTemp & 0x0000000F);
  156. _wiegandType = _bitCount;
  157. _bitCount = 0;
  158. _cardTemp = 0;
  159. _cardTempHigh = 0;
  160. return true;
  161. } else if(40 == _bitCount) {
  162. _cardTempHigh >>= 1;
  163. _code = _cardTemp;
  164. _codeHigh = _cardTempHigh;
  165. _wiegandType = _bitCount;
  166. _bitCount = 0;
  167. _cardTemp = 0;
  168. _cardTempHigh = 0;
  169. return true;
  170. } else {
  171. // wiegand 26 or wiegand 34
  172. cardID = GetCardId(&_cardTempHigh, &_cardTemp, _bitCount);
  173. _wiegandType = _bitCount;
  174. _bitCount = 0;
  175. _cardTemp = 0;
  176. _cardTempHigh = 0;
  177. _code = cardID;
  178. return true;
  179. }
  180. } else {
  181. // well time over 25 ms and bitCount !=8 , !=26, !=34 , must be noise or nothing then.
  182. _lastWiegand = sysTick;
  183. _bitCount = 0;
  184. _cardTemp = 0;
  185. _cardTempHigh = 0;
  186. return false;
  187. }
  188. } else
  189. return false;
  190. }