protocol_emmarin.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #include "protocol_emmarin.h"
  2. #include <furi.h>
  3. #define EM_HEADER_POS 55
  4. #define EM_HEADER_MASK (0x1FFLLU << EM_HEADER_POS)
  5. #define EM_FIRST_ROW_POS 50
  6. #define EM_ROW_COUNT 10
  7. #define EM_COLUMN_COUNT 4
  8. #define EM_BITS_PER_ROW_COUNT (EM_COLUMN_COUNT + 1)
  9. #define EM_COLUMN_POS 4
  10. #define EM_STOP_POS 0
  11. #define EM_STOP_MASK (0x1LLU << EM_STOP_POS)
  12. #define EM_HEADER_AND_STOP_MASK (EM_HEADER_MASK | EM_STOP_MASK)
  13. #define EM_HEADER_AND_STOP_DATA (EM_HEADER_MASK)
  14. typedef uint64_t EMMarinCardData;
  15. void write_nibble(bool low_nibble, uint8_t data, EMMarinCardData* card_data) {
  16. uint8_t parity_sum = 0;
  17. uint8_t start = 0;
  18. if(!low_nibble) start = 4;
  19. for(int8_t i = (start + 3); i >= start; i--) {
  20. parity_sum += (data >> i) & 1;
  21. *card_data = (*card_data << 1) | ((data >> i) & 1);
  22. }
  23. *card_data = (*card_data << 1) | ((parity_sum % 2) & 1);
  24. }
  25. uint8_t ProtocolEMMarin::get_encoded_data_size() {
  26. return sizeof(EMMarinCardData);
  27. }
  28. uint8_t ProtocolEMMarin::get_decoded_data_size() {
  29. return 5;
  30. }
  31. void ProtocolEMMarin::encode(
  32. const uint8_t* decoded_data,
  33. const uint8_t decoded_data_size,
  34. uint8_t* encoded_data,
  35. const uint8_t encoded_data_size) {
  36. furi_check(decoded_data_size >= get_decoded_data_size());
  37. furi_check(encoded_data_size >= get_encoded_data_size());
  38. EMMarinCardData card_data;
  39. // header
  40. card_data = 0b111111111;
  41. // data
  42. for(uint8_t i = 0; i < get_decoded_data_size(); i++) {
  43. write_nibble(false, decoded_data[i], &card_data);
  44. write_nibble(true, decoded_data[i], &card_data);
  45. }
  46. // column parity and stop bit
  47. uint8_t parity_sum;
  48. for(uint8_t c = 0; c < EM_COLUMN_COUNT; c++) {
  49. parity_sum = 0;
  50. for(uint8_t i = 1; i <= EM_ROW_COUNT; i++) {
  51. uint8_t parity_bit = (card_data >> (i * EM_BITS_PER_ROW_COUNT - 1)) & 1;
  52. parity_sum += parity_bit;
  53. }
  54. card_data = (card_data << 1) | ((parity_sum % 2) & 1);
  55. }
  56. // stop bit
  57. card_data = (card_data << 1) | 0;
  58. memcpy(encoded_data, &card_data, get_encoded_data_size());
  59. }
  60. void ProtocolEMMarin::decode(
  61. const uint8_t* encoded_data,
  62. const uint8_t encoded_data_size,
  63. uint8_t* decoded_data,
  64. const uint8_t decoded_data_size) {
  65. furi_check(decoded_data_size >= get_decoded_data_size());
  66. furi_check(encoded_data_size >= get_encoded_data_size());
  67. uint8_t decoded_data_index = 0;
  68. EMMarinCardData card_data = *(reinterpret_cast<const EMMarinCardData*>(encoded_data));
  69. // clean result
  70. memset(decoded_data, 0, decoded_data_size);
  71. // header
  72. for(uint8_t i = 0; i < 9; i++) {
  73. card_data = card_data << 1;
  74. }
  75. // nibbles
  76. uint8_t value = 0;
  77. for(uint8_t r = 0; r < EM_ROW_COUNT; r++) {
  78. uint8_t nibble = 0;
  79. for(uint8_t i = 0; i < 5; i++) {
  80. if(i < 4) nibble = (nibble << 1) | (card_data & (1LLU << 63) ? 1 : 0);
  81. card_data = card_data << 1;
  82. }
  83. value = (value << 4) | nibble;
  84. if(r % 2) {
  85. decoded_data[decoded_data_index] |= value;
  86. decoded_data_index++;
  87. value = 0;
  88. }
  89. }
  90. }
  91. bool ProtocolEMMarin::can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) {
  92. furi_check(encoded_data_size >= get_encoded_data_size());
  93. const EMMarinCardData* card_data = reinterpret_cast<const EMMarinCardData*>(encoded_data);
  94. // check header and stop bit
  95. if((*card_data & EM_HEADER_AND_STOP_MASK) != EM_HEADER_AND_STOP_DATA) return false;
  96. // check row parity
  97. for(uint8_t i = 0; i < EM_ROW_COUNT; i++) {
  98. uint8_t parity_sum = 0;
  99. for(uint8_t j = 0; j < EM_BITS_PER_ROW_COUNT; j++) {
  100. parity_sum += (*card_data >> (EM_FIRST_ROW_POS - i * EM_BITS_PER_ROW_COUNT + j)) & 1;
  101. }
  102. if((parity_sum % 2)) {
  103. return false;
  104. }
  105. }
  106. // check columns parity
  107. for(uint8_t i = 0; i < EM_COLUMN_COUNT; i++) {
  108. uint8_t parity_sum = 0;
  109. for(uint8_t j = 0; j < EM_ROW_COUNT + 1; j++) {
  110. parity_sum += (*card_data >> (EM_COLUMN_POS - i + j * EM_BITS_PER_ROW_COUNT)) & 1;
  111. }
  112. if((parity_sum % 2)) {
  113. return false;
  114. }
  115. }
  116. return true;
  117. }