[FL-1059] T5577 write (#463)
* Api-hal-gpio: extend init functions * App Lfrfid: separate protocol layer * App Lfrfid: write EM key scene * App Lfrfid: syntax fix
This commit is contained in:
		
							parent
							
								
									588480831a
								
							
						
					
					
						commit
						618ddfcd04
					
				| @ -20,84 +20,13 @@ void DecoderEMMarine::reset_state() { | |||||||
|         manchester_saved_state, ManchesterEventReset, &manchester_saved_state, nullptr); |         manchester_saved_state, ManchesterEventReset, &manchester_saved_state, nullptr); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void printEM_raw(uint64_t data) { |  | ||||||
|     // header
 |  | ||||||
|     for(uint8_t i = 0; i < 9; i++) { |  | ||||||
|         printf("%u ", data & (1LLU << 63) ? 1 : 0); |  | ||||||
|         data = data << 1; |  | ||||||
|     } |  | ||||||
|     printf("\r\n"); |  | ||||||
| 
 |  | ||||||
|     // nibbles
 |  | ||||||
|     for(uint8_t r = 0; r < 11; r++) { |  | ||||||
|         printf("        "); |  | ||||||
|         uint8_t value = 0; |  | ||||||
|         for(uint8_t i = 0; i < 5; i++) { |  | ||||||
|             printf("%u ", data & (1LLU << 63) ? 1 : 0); |  | ||||||
|             if(i < 4) value = (value << 1) | (data & (1LLU << 63) ? 1 : 0); |  | ||||||
|             data = data << 1; |  | ||||||
|         } |  | ||||||
|         printf("0x%X", value); |  | ||||||
|         printf("\r\n"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void printEM_data(uint64_t data) { |  | ||||||
|     printf("EM "); |  | ||||||
| 
 |  | ||||||
|     // header
 |  | ||||||
|     for(uint8_t i = 0; i < 9; i++) { |  | ||||||
|         data = data << 1; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // nibbles
 |  | ||||||
|     for(uint8_t r = 0; r < EM_ROW_COUNT; r++) { |  | ||||||
|         uint8_t value = 0; |  | ||||||
|         for(uint8_t i = 0; i < 5; i++) { |  | ||||||
|             if(i < 4) value = (value << 1) | (data & (1LLU << 63) ? 1 : 0); |  | ||||||
|             data = data << 1; |  | ||||||
|         } |  | ||||||
|         printf("%X", value); |  | ||||||
|         if(r % 2) printf(" "); |  | ||||||
|     } |  | ||||||
|     printf("\r\n"); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void copyEM_data(uint64_t data, uint8_t* result, uint8_t result_size) { |  | ||||||
|     furi_assert(result_size >= 5); |  | ||||||
|     uint8_t result_index = 0; |  | ||||||
| 
 |  | ||||||
|     // clean result
 |  | ||||||
|     memset(result, 0, result_size); |  | ||||||
| 
 |  | ||||||
|     // header
 |  | ||||||
|     for(uint8_t i = 0; i < 9; i++) { |  | ||||||
|         data = data << 1; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // nibbles
 |  | ||||||
|     uint8_t value = 0; |  | ||||||
|     for(uint8_t r = 0; r < EM_ROW_COUNT; r++) { |  | ||||||
|         uint8_t nibble = 0; |  | ||||||
|         for(uint8_t i = 0; i < 5; i++) { |  | ||||||
|             if(i < 4) nibble = (nibble << 1) | (data & (1LLU << 63) ? 1 : 0); |  | ||||||
|             data = data << 1; |  | ||||||
|         } |  | ||||||
|         value = (value << 4) | nibble; |  | ||||||
|         if(r % 2) { |  | ||||||
|             result[result_index] |= value; |  | ||||||
|             result_index++; |  | ||||||
|             value = 0; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool DecoderEMMarine::read(uint8_t* data, uint8_t data_size) { | bool DecoderEMMarine::read(uint8_t* data, uint8_t data_size) { | ||||||
|     bool result = false; |     bool result = false; | ||||||
| 
 | 
 | ||||||
|     if(ready) { |     if(ready) { | ||||||
|         result = true; |         result = true; | ||||||
|         copyEM_data(readed_data, data, data_size); |         em_marine.decode( | ||||||
|  |             reinterpret_cast<const uint8_t*>(&readed_data), sizeof(uint64_t), data, data_size); | ||||||
|         ready = false; |         ready = false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -132,37 +61,8 @@ void DecoderEMMarine::process_front(bool polarity, uint32_t time) { | |||||||
|         if(data_ok) { |         if(data_ok) { | ||||||
|             readed_data = (readed_data << 1) | data; |             readed_data = (readed_data << 1) | data; | ||||||
| 
 | 
 | ||||||
|             // header and stop bit
 |             ready = em_marine.can_be_decoded( | ||||||
|             if((readed_data & EM_HEADER_AND_STOP_MASK) != EM_HEADER_AND_STOP_DATA) return; |                 reinterpret_cast<const uint8_t*>(&readed_data), sizeof(uint64_t)); | ||||||
| 
 |  | ||||||
|             // row parity
 |  | ||||||
|             for(uint8_t i = 0; i < EM_ROW_COUNT; i++) { |  | ||||||
|                 uint8_t parity_sum = 0; |  | ||||||
| 
 |  | ||||||
|                 for(uint8_t j = 0; j < 5; j++) { |  | ||||||
|                     parity_sum += (readed_data >> (EM_FIRST_ROW_POS - i * 5 + j)) & 1; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 if((parity_sum % 2)) { |  | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // columns parity
 |  | ||||||
|             for(uint8_t i = 0; i < 4; i++) { |  | ||||||
|                 uint8_t parity_sum = 0; |  | ||||||
| 
 |  | ||||||
|                 for(uint8_t j = 0; j < EM_ROW_COUNT + 1; j++) { |  | ||||||
|                     parity_sum += (readed_data >> (EM_COLUMN_POS - i + j * 5)) & 1; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 if((parity_sum % 2)) { |  | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // checks ok
 |  | ||||||
|             ready = true; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ | |||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <atomic> | #include <atomic> | ||||||
| #include "manchester-decoder.h" | #include "manchester-decoder.h" | ||||||
| 
 | #include "protocols/protocol-emmarin.h" | ||||||
| class DecoderEMMarine { | class DecoderEMMarine { | ||||||
| public: | public: | ||||||
|     bool read(uint8_t* data, uint8_t data_size); |     bool read(uint8_t* data, uint8_t data_size); | ||||||
| @ -17,4 +17,5 @@ private: | |||||||
|     std::atomic<bool> ready; |     std::atomic<bool> ready; | ||||||
| 
 | 
 | ||||||
|     ManchesterState manchester_saved_state; |     ManchesterState manchester_saved_state; | ||||||
|  |     ProtocolEMMarin em_marine; | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -17,11 +17,8 @@ bool DecoderHID26::read(uint8_t* data, uint8_t data_size) { | |||||||
| 
 | 
 | ||||||
|     if(ready) { |     if(ready) { | ||||||
|         result = true; |         result = true; | ||||||
|         data[0] = facility; |         hid.decode( | ||||||
|         data[1] = (uint8_t)(number >> 8); |             reinterpret_cast<const uint8_t*>(&stored_data), sizeof(uint32_t) * 3, data, data_size); | ||||||
|         data[2] = (uint8_t)number; |  | ||||||
| 
 |  | ||||||
|         //printf("HID %02X %02X %02X\r\n", facility, (uint8_t)(number >> 8), (uint8_t)number);
 |  | ||||||
|         ready = false; |         ready = false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -87,94 +84,10 @@ void DecoderHID26::store_data(bool data) { | |||||||
|     stored_data[0] = (stored_data[0] << 1) | ((stored_data[1] >> 31) & 1); |     stored_data[0] = (stored_data[0] << 1) | ((stored_data[1] >> 31) & 1); | ||||||
|     stored_data[1] = (stored_data[1] << 1) | ((stored_data[2] >> 31) & 1); |     stored_data[1] = (stored_data[1] << 1) | ((stored_data[2] >> 31) & 1); | ||||||
|     stored_data[2] = (stored_data[2] << 1) | data; |     stored_data[2] = (stored_data[2] << 1) | data; | ||||||
|     validate_stored_data(); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| void DecoderHID26::validate_stored_data() { |     if(hid.can_be_decoded(reinterpret_cast<const uint8_t*>(&stored_data), sizeof(uint32_t) * 3)) { | ||||||
|     // packet preamble
 |         ready = true; | ||||||
|     // raw data
 |  | ||||||
|     if(*(reinterpret_cast<uint8_t*>(stored_data) + 3) != 0x1D) { |  | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     // encoded company/oem
 |  | ||||||
|     // coded with 01 = 0, 10 = 1 transitions
 |  | ||||||
|     // stored in word 0
 |  | ||||||
|     if((*stored_data >> 10 & 0x3FFF) != 0x1556) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // encoded format/length
 |  | ||||||
|     // coded with 01 = 0, 10 = 1 transitions
 |  | ||||||
|     // stored in word 0 and word 1
 |  | ||||||
|     if((((*stored_data & 0x3FF) << 12) | ((*(stored_data + 1) >> 20) & 0xFFF)) != 0x155556) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // data decoding
 |  | ||||||
|     uint32_t result = 0; |  | ||||||
| 
 |  | ||||||
|     // decode from word 1
 |  | ||||||
|     // coded with 01 = 0, 10 = 1 transitions
 |  | ||||||
|     for(int8_t i = 9; i >= 0; i--) { |  | ||||||
|         switch((*(stored_data + 1) >> (2 * i)) & 0b11) { |  | ||||||
|         case 0b01: |  | ||||||
|             result = (result << 1) | 0; |  | ||||||
|             break; |  | ||||||
|         case 0b10: |  | ||||||
|             result = (result << 1) | 1; |  | ||||||
|             break; |  | ||||||
|         default: |  | ||||||
|             return; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // decode from word 2
 |  | ||||||
|     // coded with 01 = 0, 10 = 1 transitions
 |  | ||||||
|     for(int8_t i = 15; i >= 0; i--) { |  | ||||||
|         switch((*(stored_data + 2) >> (2 * i)) & 0b11) { |  | ||||||
|         case 0b01: |  | ||||||
|             result = (result << 1) | 0; |  | ||||||
|             break; |  | ||||||
|         case 0b10: |  | ||||||
|             result = (result << 1) | 1; |  | ||||||
|             break; |  | ||||||
|         default: |  | ||||||
|             return; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // store decoded data
 |  | ||||||
|     facility = result >> 17; |  | ||||||
|     number = result >> 1; |  | ||||||
| 
 |  | ||||||
|     // trailing parity (odd) test
 |  | ||||||
|     uint8_t parity_sum = 0; |  | ||||||
|     for(int8_t i = 0; i < 13; i++) { |  | ||||||
|         if(((result >> i) & 1) == 1) { |  | ||||||
|             parity_sum++; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if((parity_sum % 2) != 1) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // leading parity (even) test
 |  | ||||||
|     parity_sum = 0; |  | ||||||
|     for(int8_t i = 13; i < 26; i++) { |  | ||||||
|         if(((result >> i) & 1) == 1) { |  | ||||||
|             parity_sum++; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if((parity_sum % 2) == 1) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ready = true; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DecoderHID26::reset_state() { | void DecoderHID26::reset_state() { | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <atomic> | #include <atomic> | ||||||
|  | #include "protocols/protocol-hid-h10301.h" | ||||||
| 
 | 
 | ||||||
| class DecoderHID26 { | class DecoderHID26 { | ||||||
| public: | public: | ||||||
| @ -15,12 +16,9 @@ private: | |||||||
| 
 | 
 | ||||||
|     uint32_t stored_data[3] = {0, 0, 0}; |     uint32_t stored_data[3] = {0, 0, 0}; | ||||||
|     void store_data(bool data); |     void store_data(bool data); | ||||||
|     void validate_stored_data(); |  | ||||||
| 
 |  | ||||||
|     uint8_t facility = 0; |  | ||||||
|     uint16_t number = 0; |  | ||||||
| 
 | 
 | ||||||
|     std::atomic<bool> ready; |     std::atomic<bool> ready; | ||||||
| 
 | 
 | ||||||
|     void reset_state(); |     void reset_state(); | ||||||
|  |     ProtocolHID10301 hid; | ||||||
| }; | }; | ||||||
| @ -1,48 +1,14 @@ | |||||||
| #include "encoder-emmarine.h" | #include "encoder-emmarine.h" | ||||||
|  | #include "protocols/protocol-emmarin.h" | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| void EncoderEM::init(const uint8_t* data, const uint8_t data_size) { | void EncoderEM::init(const uint8_t* data, const uint8_t data_size) { | ||||||
|     furi_check(data_size == 5); |     ProtocolEMMarin em_marin; | ||||||
|  |     em_marin.encode(data, data_size, reinterpret_cast<uint8_t*>(&card_data), sizeof(uint64_t)); | ||||||
| 
 | 
 | ||||||
|     // header
 |  | ||||||
|     card_data = 0b111111111; |  | ||||||
| 
 |  | ||||||
|     // data
 |  | ||||||
|     for(uint8_t i = 0; i < 5; i++) { |  | ||||||
|         write_nibble(false, data[i]); |  | ||||||
|         write_nibble(true, data[i]); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // column parity and stop bit
 |  | ||||||
|     uint8_t parity_sum; |  | ||||||
| 
 |  | ||||||
|     for(uint8_t c = 0; c < 4; c++) { |  | ||||||
|         parity_sum = 0; |  | ||||||
|         for(uint8_t i = 1; i <= 10; i++) { |  | ||||||
|             uint8_t parity_bit = (card_data >> (i * 5 - 1)) & 1; |  | ||||||
|             parity_sum += parity_bit; |  | ||||||
|         } |  | ||||||
|         card_data = (card_data << 1) | ((parity_sum % 2) & 1); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // stop bit
 |  | ||||||
|     card_data = (card_data << 1) | 0; |  | ||||||
|     card_data_index = 0; |     card_data_index = 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void EncoderEM::write_nibble(bool low_nibble, uint8_t data) { |  | ||||||
|     uint8_t parity_sum = 0; |  | ||||||
|     uint8_t start = 0; |  | ||||||
|     if(!low_nibble) start = 4; |  | ||||||
| 
 |  | ||||||
|     for(int8_t i = (start + 3); i >= start; i--) { |  | ||||||
|         parity_sum += (data >> i) & 1; |  | ||||||
|         card_data = (card_data << 1) | ((data >> i) & 1); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     card_data = (card_data << 1) | ((parity_sum % 2) & 1); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // data transmitted as manchester encoding
 | // data transmitted as manchester encoding
 | ||||||
| // 0 - high2low
 | // 0 - high2low
 | ||||||
| // 1 - low2high
 | // 1 - low2high
 | ||||||
|  | |||||||
| @ -19,5 +19,4 @@ private: | |||||||
| 
 | 
 | ||||||
|     uint64_t card_data; |     uint64_t card_data; | ||||||
|     uint8_t card_data_index; |     uint8_t card_data_index; | ||||||
|     void write_nibble(bool low_nibble, uint8_t data); |  | ||||||
| }; | }; | ||||||
| @ -1,73 +1,10 @@ | |||||||
| #include "encoder-hid-h10301.h" | #include "encoder-hid-h10301.h" | ||||||
|  | #include "protocols/protocol-hid-h10301.h" | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| void EncoderHID_H10301::init(const uint8_t* data, const uint8_t data_size) { | void EncoderHID_H10301::init(const uint8_t* data, const uint8_t data_size) { | ||||||
|     furi_check(data_size == 3); |     ProtocolHID10301 hid; | ||||||
| 
 |     hid.encode(data, data_size, reinterpret_cast<uint8_t*>(&card_data), sizeof(card_data) * 3); | ||||||
|     card_data[0] = 0; |  | ||||||
|     card_data[1] = 0; |  | ||||||
|     card_data[2] = 0; |  | ||||||
| 
 |  | ||||||
|     uint32_t fc_cn = (data[0] << 16) | (data[1] << 8) | data[2]; |  | ||||||
| 
 |  | ||||||
|     // even parity sum calculation (high 12 bits of data)
 |  | ||||||
|     uint8_t even_parity_sum = 0; |  | ||||||
|     for(int8_t i = 12; i < 24; i++) { |  | ||||||
|         if(((fc_cn >> i) & 1) == 1) { |  | ||||||
|             even_parity_sum++; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // odd parity sum calculation (low 12 bits of data)
 |  | ||||||
|     uint8_t odd_parity_sum = 1; |  | ||||||
|     for(int8_t i = 0; i < 12; i++) { |  | ||||||
|         if(((fc_cn >> i) & 1) == 1) { |  | ||||||
|             odd_parity_sum++; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // 0x1D preamble
 |  | ||||||
|     write_raw_bit(0, 0); |  | ||||||
|     write_raw_bit(0, 1); |  | ||||||
|     write_raw_bit(0, 2); |  | ||||||
|     write_raw_bit(1, 3); |  | ||||||
|     write_raw_bit(1, 4); |  | ||||||
|     write_raw_bit(1, 5); |  | ||||||
|     write_raw_bit(0, 6); |  | ||||||
|     write_raw_bit(1, 7); |  | ||||||
| 
 |  | ||||||
|     // company / OEM code 1
 |  | ||||||
|     write_bit(0, 8); |  | ||||||
|     write_bit(0, 10); |  | ||||||
|     write_bit(0, 12); |  | ||||||
|     write_bit(0, 14); |  | ||||||
|     write_bit(0, 16); |  | ||||||
|     write_bit(0, 18); |  | ||||||
|     write_bit(1, 20); |  | ||||||
| 
 |  | ||||||
|     // card format / length 1
 |  | ||||||
|     write_bit(0, 22); |  | ||||||
|     write_bit(0, 24); |  | ||||||
|     write_bit(0, 26); |  | ||||||
|     write_bit(0, 28); |  | ||||||
|     write_bit(0, 30); |  | ||||||
|     write_bit(0, 32); |  | ||||||
|     write_bit(0, 34); |  | ||||||
|     write_bit(0, 36); |  | ||||||
|     write_bit(0, 38); |  | ||||||
|     write_bit(0, 40); |  | ||||||
|     write_bit(1, 42); |  | ||||||
| 
 |  | ||||||
|     // even parity bit
 |  | ||||||
|     write_bit((even_parity_sum % 2), 44); |  | ||||||
| 
 |  | ||||||
|     // data
 |  | ||||||
|     for(uint8_t i = 0; i < 24; i++) { |  | ||||||
|         write_bit((fc_cn >> (23 - i)) & 1, 46 + (i * 2)); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // odd parity bit
 |  | ||||||
|     write_bit((odd_parity_sum % 2), 94); |  | ||||||
| 
 | 
 | ||||||
|     card_data_index = 0; |     card_data_index = 0; | ||||||
|     bit_index = 0; |     bit_index = 0; | ||||||
|  | |||||||
| @ -1,102 +1,16 @@ | |||||||
| #include "encoder-indala-40134.h" | #include "encoder-indala-40134.h" | ||||||
|  | #include "protocols/protocol-indala-40134.h" | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| void EncoderIndala_40134::init(const uint8_t* data, const uint8_t data_size) { | void EncoderIndala_40134::init(const uint8_t* data, const uint8_t data_size) { | ||||||
|     furi_check(data_size == 3); |     ProtocolIndala40134 indala; | ||||||
|     uint32_t fc_and_card = (data[0] << 16) | (data[1] << 8) | data[2]; |     indala.encode(data, data_size, reinterpret_cast<uint8_t*>(&card_data), sizeof(card_data)); | ||||||
| 
 |  | ||||||
|     card_data = 0; |  | ||||||
| 
 |  | ||||||
|     // preamble
 |  | ||||||
|     set_bit(1, 0); |  | ||||||
|     set_bit(1, 2); |  | ||||||
|     set_bit(1, 32); |  | ||||||
| 
 |  | ||||||
|     // factory code
 |  | ||||||
|     set_bit(((fc_and_card >> 23) & 1), 57); |  | ||||||
|     set_bit(((fc_and_card >> 22) & 1), 49); |  | ||||||
|     set_bit(((fc_and_card >> 21) & 1), 44); |  | ||||||
|     set_bit(((fc_and_card >> 20) & 1), 47); |  | ||||||
|     set_bit(((fc_and_card >> 19) & 1), 48); |  | ||||||
|     set_bit(((fc_and_card >> 18) & 1), 53); |  | ||||||
|     set_bit(((fc_and_card >> 17) & 1), 39); |  | ||||||
|     set_bit(((fc_and_card >> 16) & 1), 58); |  | ||||||
| 
 |  | ||||||
|     // card number
 |  | ||||||
|     set_bit(((fc_and_card >> 15) & 1), 42); |  | ||||||
|     set_bit(((fc_and_card >> 14) & 1), 45); |  | ||||||
|     set_bit(((fc_and_card >> 13) & 1), 43); |  | ||||||
|     set_bit(((fc_and_card >> 12) & 1), 40); |  | ||||||
|     set_bit(((fc_and_card >> 11) & 1), 52); |  | ||||||
|     set_bit(((fc_and_card >> 10) & 1), 36); |  | ||||||
|     set_bit(((fc_and_card >> 9) & 1), 35); |  | ||||||
|     set_bit(((fc_and_card >> 8) & 1), 51); |  | ||||||
|     set_bit(((fc_and_card >> 7) & 1), 46); |  | ||||||
|     set_bit(((fc_and_card >> 6) & 1), 33); |  | ||||||
|     set_bit(((fc_and_card >> 5) & 1), 37); |  | ||||||
|     set_bit(((fc_and_card >> 4) & 1), 54); |  | ||||||
|     set_bit(((fc_and_card >> 3) & 1), 56); |  | ||||||
|     set_bit(((fc_and_card >> 2) & 1), 59); |  | ||||||
|     set_bit(((fc_and_card >> 1) & 1), 50); |  | ||||||
|     set_bit(((fc_and_card >> 0) & 1), 41); |  | ||||||
| 
 |  | ||||||
|     // checksum
 |  | ||||||
|     uint8_t checksum = 0; |  | ||||||
|     checksum += ((fc_and_card >> 14) & 1); |  | ||||||
|     checksum += ((fc_and_card >> 12) & 1); |  | ||||||
|     checksum += ((fc_and_card >> 9) & 1); |  | ||||||
|     checksum += ((fc_and_card >> 8) & 1); |  | ||||||
|     checksum += ((fc_and_card >> 6) & 1); |  | ||||||
|     checksum += ((fc_and_card >> 5) & 1); |  | ||||||
|     checksum += ((fc_and_card >> 2) & 1); |  | ||||||
|     checksum += ((fc_and_card >> 0) & 1); |  | ||||||
| 
 |  | ||||||
|     // wiegand parity bits
 |  | ||||||
|     // even parity sum calculation (high 12 bits of data)
 |  | ||||||
|     uint8_t even_parity_sum = 0; |  | ||||||
|     for(int8_t i = 12; i < 24; i++) { |  | ||||||
|         if(((fc_and_card >> i) & 1) == 1) { |  | ||||||
|             even_parity_sum++; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // odd parity sum calculation (low 12 bits of data)
 |  | ||||||
|     uint8_t odd_parity_sum = 1; |  | ||||||
|     for(int8_t i = 0; i < 12; i++) { |  | ||||||
|         if(((fc_and_card >> i) & 1) == 1) { |  | ||||||
|             odd_parity_sum++; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // even parity bit
 |  | ||||||
|     set_bit((even_parity_sum % 2), 34); |  | ||||||
| 
 |  | ||||||
|     // odd parity bit
 |  | ||||||
|     set_bit((odd_parity_sum % 2), 38); |  | ||||||
| 
 |  | ||||||
|     // checksum
 |  | ||||||
|     if((checksum & 1) == 1) { |  | ||||||
|         set_bit(0, 62); |  | ||||||
|         set_bit(1, 63); |  | ||||||
|     } else { |  | ||||||
|         set_bit(1, 62); |  | ||||||
|         set_bit(0, 63); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     last_bit = card_data & 1; |     last_bit = card_data & 1; | ||||||
|     card_data_index = 0; |     card_data_index = 0; | ||||||
|     current_polarity = true; |     current_polarity = true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void EncoderIndala_40134::set_bit(bool bit, uint8_t position) { |  | ||||||
|     position = 63 - position; |  | ||||||
|     if(bit) { |  | ||||||
|         card_data |= 1ull << position; |  | ||||||
|     } else { |  | ||||||
|         card_data &= ~(1ull << position); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void EncoderIndala_40134::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) { | void EncoderIndala_40134::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) { | ||||||
|     *period = 2; |     *period = 2; | ||||||
|     *pulse = 1; |     *pulse = 1; | ||||||
|  | |||||||
| @ -20,6 +20,4 @@ private: | |||||||
|     bool last_bit; |     bool last_bit; | ||||||
|     bool current_polarity; |     bool current_polarity; | ||||||
|     static const uint8_t clock_per_bit = 16; |     static const uint8_t clock_per_bit = 16; | ||||||
| 
 |  | ||||||
|     void set_bit(bool bit, uint8_t position); |  | ||||||
| }; | }; | ||||||
| @ -6,4 +6,5 @@ static const uint8_t LFRFID_KEY_SIZE = 8; | |||||||
| enum class LfrfidKeyType : uint8_t { | enum class LfrfidKeyType : uint8_t { | ||||||
|     KeyEmarine, |     KeyEmarine, | ||||||
|     KeyHID, |     KeyHID, | ||||||
|  |     KeyIndala, | ||||||
| }; | }; | ||||||
							
								
								
									
										150
									
								
								applications/lf-rfid/helpers/protocols/protocol-emmarin.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								applications/lf-rfid/helpers/protocols/protocol-emmarin.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,150 @@ | |||||||
|  | #include "protocol-emmarin.h" | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | #define EM_HEADER_POS 55 | ||||||
|  | #define EM_HEADER_MASK (0x1FFLLU << EM_HEADER_POS) | ||||||
|  | 
 | ||||||
|  | #define EM_FIRST_ROW_POS 50 | ||||||
|  | 
 | ||||||
|  | #define EM_ROW_COUNT 10 | ||||||
|  | #define EM_COLUMN_COUNT 4 | ||||||
|  | #define EM_BITS_PER_ROW_COUNT (EM_COLUMN_COUNT + 1) | ||||||
|  | 
 | ||||||
|  | #define EM_COLUMN_POS 4 | ||||||
|  | #define EM_STOP_POS 0 | ||||||
|  | #define EM_STOP_MASK (0x1LLU << EM_STOP_POS) | ||||||
|  | 
 | ||||||
|  | #define EM_HEADER_AND_STOP_MASK (EM_HEADER_MASK | EM_STOP_MASK) | ||||||
|  | #define EM_HEADER_AND_STOP_DATA (EM_HEADER_MASK) | ||||||
|  | 
 | ||||||
|  | typedef uint64_t EMMarinCardData; | ||||||
|  | 
 | ||||||
|  | void write_nibble(bool low_nibble, uint8_t data, EMMarinCardData* card_data) { | ||||||
|  |     uint8_t parity_sum = 0; | ||||||
|  |     uint8_t start = 0; | ||||||
|  |     if(!low_nibble) start = 4; | ||||||
|  | 
 | ||||||
|  |     for(int8_t i = (start + 3); i >= start; i--) { | ||||||
|  |         parity_sum += (data >> i) & 1; | ||||||
|  |         *card_data = (*card_data << 1) | ((data >> i) & 1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     *card_data = (*card_data << 1) | ((parity_sum % 2) & 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t ProtocolEMMarin::get_encoded_data_size() { | ||||||
|  |     return sizeof(EMMarinCardData); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t ProtocolEMMarin::get_decoded_data_size() { | ||||||
|  |     return 5; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ProtocolEMMarin::encode( | ||||||
|  |     const uint8_t* decoded_data, | ||||||
|  |     const uint8_t decoded_data_size, | ||||||
|  |     uint8_t* encoded_data, | ||||||
|  |     const uint8_t encoded_data_size) { | ||||||
|  |     furi_check(decoded_data_size >= get_decoded_data_size()); | ||||||
|  |     furi_check(encoded_data_size >= get_encoded_data_size()); | ||||||
|  | 
 | ||||||
|  |     EMMarinCardData card_data; | ||||||
|  | 
 | ||||||
|  |     // header
 | ||||||
|  |     card_data = 0b111111111; | ||||||
|  | 
 | ||||||
|  |     // data
 | ||||||
|  |     for(uint8_t i = 0; i < get_decoded_data_size(); i++) { | ||||||
|  |         write_nibble(false, decoded_data[i], &card_data); | ||||||
|  |         write_nibble(true, decoded_data[i], &card_data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // column parity and stop bit
 | ||||||
|  |     uint8_t parity_sum; | ||||||
|  | 
 | ||||||
|  |     for(uint8_t c = 0; c < EM_COLUMN_COUNT; c++) { | ||||||
|  |         parity_sum = 0; | ||||||
|  |         for(uint8_t i = 1; i <= EM_ROW_COUNT; i++) { | ||||||
|  |             uint8_t parity_bit = (card_data >> (i * EM_BITS_PER_ROW_COUNT - 1)) & 1; | ||||||
|  |             parity_sum += parity_bit; | ||||||
|  |         } | ||||||
|  |         card_data = (card_data << 1) | ((parity_sum % 2) & 1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // stop bit
 | ||||||
|  |     card_data = (card_data << 1) | 0; | ||||||
|  | 
 | ||||||
|  |     memcpy(encoded_data, &card_data, get_encoded_data_size()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ProtocolEMMarin::decode( | ||||||
|  |     const uint8_t* encoded_data, | ||||||
|  |     const uint8_t encoded_data_size, | ||||||
|  |     uint8_t* decoded_data, | ||||||
|  |     const uint8_t decoded_data_size) { | ||||||
|  |     furi_check(decoded_data_size >= get_decoded_data_size()); | ||||||
|  |     furi_check(encoded_data_size >= get_encoded_data_size()); | ||||||
|  | 
 | ||||||
|  |     uint8_t decoded_data_index = 0; | ||||||
|  |     EMMarinCardData card_data = *(reinterpret_cast<const EMMarinCardData*>(encoded_data)); | ||||||
|  | 
 | ||||||
|  |     // clean result
 | ||||||
|  |     memset(decoded_data, 0, decoded_data_size); | ||||||
|  | 
 | ||||||
|  |     // header
 | ||||||
|  |     for(uint8_t i = 0; i < 9; i++) { | ||||||
|  |         card_data = card_data << 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // nibbles
 | ||||||
|  |     uint8_t value = 0; | ||||||
|  |     for(uint8_t r = 0; r < EM_ROW_COUNT; r++) { | ||||||
|  |         uint8_t nibble = 0; | ||||||
|  |         for(uint8_t i = 0; i < 5; i++) { | ||||||
|  |             if(i < 4) nibble = (nibble << 1) | (card_data & (1LLU << 63) ? 1 : 0); | ||||||
|  |             card_data = card_data << 1; | ||||||
|  |         } | ||||||
|  |         value = (value << 4) | nibble; | ||||||
|  |         if(r % 2) { | ||||||
|  |             decoded_data[decoded_data_index] |= value; | ||||||
|  |             decoded_data_index++; | ||||||
|  |             value = 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ProtocolEMMarin::can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) { | ||||||
|  |     furi_check(encoded_data_size >= get_encoded_data_size()); | ||||||
|  |     const EMMarinCardData* card_data = reinterpret_cast<const EMMarinCardData*>(encoded_data); | ||||||
|  | 
 | ||||||
|  |     // check header and stop bit
 | ||||||
|  |     if((*card_data & EM_HEADER_AND_STOP_MASK) != EM_HEADER_AND_STOP_DATA) return false; | ||||||
|  | 
 | ||||||
|  |     // check row parity
 | ||||||
|  |     for(uint8_t i = 0; i < EM_ROW_COUNT; i++) { | ||||||
|  |         uint8_t parity_sum = 0; | ||||||
|  | 
 | ||||||
|  |         for(uint8_t j = 0; j < EM_BITS_PER_ROW_COUNT; j++) { | ||||||
|  |             parity_sum += (*card_data >> (EM_FIRST_ROW_POS - i * EM_BITS_PER_ROW_COUNT + j)) & 1; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if((parity_sum % 2)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // check columns parity
 | ||||||
|  |     for(uint8_t i = 0; i < EM_COLUMN_COUNT; i++) { | ||||||
|  |         uint8_t parity_sum = 0; | ||||||
|  | 
 | ||||||
|  |         for(uint8_t j = 0; j < EM_ROW_COUNT + 1; j++) { | ||||||
|  |             parity_sum += (*card_data >> (EM_COLUMN_POS - i + j * EM_BITS_PER_ROW_COUNT)) & 1; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if((parity_sum % 2)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								applications/lf-rfid/helpers/protocols/protocol-emmarin.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								applications/lf-rfid/helpers/protocols/protocol-emmarin.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "protocol-generic.h" | ||||||
|  | 
 | ||||||
|  | class ProtocolEMMarin : public ProtocolGeneric { | ||||||
|  | public: | ||||||
|  |     uint8_t get_encoded_data_size() final; | ||||||
|  |     uint8_t get_decoded_data_size() final; | ||||||
|  | 
 | ||||||
|  |     void encode( | ||||||
|  |         const uint8_t* decoded_data, | ||||||
|  |         const uint8_t decoded_data_size, | ||||||
|  |         uint8_t* encoded_data, | ||||||
|  |         const uint8_t encoded_data_size) final; | ||||||
|  | 
 | ||||||
|  |     void decode( | ||||||
|  |         const uint8_t* encoded_data, | ||||||
|  |         const uint8_t encoded_data_size, | ||||||
|  |         uint8_t* decoded_data, | ||||||
|  |         const uint8_t decoded_data_size) final; | ||||||
|  | 
 | ||||||
|  |     bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) final; | ||||||
|  | }; | ||||||
							
								
								
									
										60
									
								
								applications/lf-rfid/helpers/protocols/protocol-generic.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								applications/lf-rfid/helpers/protocols/protocol-generic.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "stdint.h" | ||||||
|  | #include "stdbool.h" | ||||||
|  | 
 | ||||||
|  | class ProtocolGeneric { | ||||||
|  | public: | ||||||
|  |     /**
 | ||||||
|  |      * @brief Get the encoded data size | ||||||
|  |      *  | ||||||
|  |      * @return uint8_t size of encoded data in bytes | ||||||
|  |      */ | ||||||
|  |     virtual uint8_t get_encoded_data_size() = 0; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Get the decoded data size | ||||||
|  |      *  | ||||||
|  |      * @return uint8_t size of decoded data in bytes | ||||||
|  |      */ | ||||||
|  |     virtual uint8_t get_decoded_data_size() = 0; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief encode decoded data | ||||||
|  |      *  | ||||||
|  |      * @param decoded_data  | ||||||
|  |      * @param decoded_data_size  | ||||||
|  |      * @param encoded_data  | ||||||
|  |      * @param encoded_data_size  | ||||||
|  |      */ | ||||||
|  |     virtual void encode( | ||||||
|  |         const uint8_t* decoded_data, | ||||||
|  |         const uint8_t decoded_data_size, | ||||||
|  |         uint8_t* encoded_data, | ||||||
|  |         const uint8_t encoded_data_size) = 0; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief decode encoded data | ||||||
|  |      *  | ||||||
|  |      * @param encoded_data  | ||||||
|  |      * @param encoded_data_size  | ||||||
|  |      * @param decoded_data  | ||||||
|  |      * @param decoded_data_size  | ||||||
|  |      */ | ||||||
|  |     virtual void decode( | ||||||
|  |         const uint8_t* encoded_data, | ||||||
|  |         const uint8_t encoded_data_size, | ||||||
|  |         uint8_t* decoded_data, | ||||||
|  |         const uint8_t decoded_data_size) = 0; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief fast check that data can be correctly decoded | ||||||
|  |      *  | ||||||
|  |      * @param encoded_data  | ||||||
|  |      * @param encoded_data_size  | ||||||
|  |      * @return true - can be correctly decoded | ||||||
|  |      * @return false - cannot be correctly decoded | ||||||
|  |      */ | ||||||
|  |     virtual bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) = 0; | ||||||
|  | 
 | ||||||
|  |     virtual ~ProtocolGeneric(){}; | ||||||
|  | }; | ||||||
							
								
								
									
										238
									
								
								applications/lf-rfid/helpers/protocols/protocol-hid-h10301.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										238
									
								
								applications/lf-rfid/helpers/protocols/protocol-hid-h10301.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,238 @@ | |||||||
|  | #include "protocol-hid-h10301.h" | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | typedef uint32_t HID10301CardData; | ||||||
|  | constexpr uint8_t HID10301Count = 3; | ||||||
|  | constexpr uint8_t HID10301BitSize = sizeof(HID10301CardData) * 8; | ||||||
|  | 
 | ||||||
|  | static void write_raw_bit(bool bit, uint8_t position, HID10301CardData* card_data) { | ||||||
|  |     if(bit) { | ||||||
|  |         card_data[position / HID10301BitSize] |= | ||||||
|  |             1UL << (HID10301BitSize - (position % HID10301BitSize) - 1); | ||||||
|  |     } else { | ||||||
|  |         card_data[position / (sizeof(HID10301CardData) * 8)] &= | ||||||
|  |             ~(1UL << (HID10301BitSize - (position % HID10301BitSize) - 1)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void write_bit(bool bit, uint8_t position, HID10301CardData* card_data) { | ||||||
|  |     write_raw_bit(bit, position + 0, card_data); | ||||||
|  |     write_raw_bit(!bit, position + 1, card_data); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t ProtocolHID10301::get_encoded_data_size() { | ||||||
|  |     return sizeof(HID10301CardData) * HID10301Count; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t ProtocolHID10301::get_decoded_data_size() { | ||||||
|  |     return 3; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ProtocolHID10301::encode( | ||||||
|  |     const uint8_t* decoded_data, | ||||||
|  |     const uint8_t decoded_data_size, | ||||||
|  |     uint8_t* encoded_data, | ||||||
|  |     const uint8_t encoded_data_size) { | ||||||
|  |     furi_check(decoded_data_size >= get_decoded_data_size()); | ||||||
|  |     furi_check(encoded_data_size >= get_encoded_data_size()); | ||||||
|  | 
 | ||||||
|  |     HID10301CardData card_data[HID10301Count] = {0, 0, 0}; | ||||||
|  | 
 | ||||||
|  |     uint32_t fc_cn = (decoded_data[0] << 16) | (decoded_data[1] << 8) | decoded_data[2]; | ||||||
|  | 
 | ||||||
|  |     // even parity sum calculation (high 12 bits of data)
 | ||||||
|  |     uint8_t even_parity_sum = 0; | ||||||
|  |     for(int8_t i = 12; i < 24; i++) { | ||||||
|  |         if(((fc_cn >> i) & 1) == 1) { | ||||||
|  |             even_parity_sum++; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // odd parity sum calculation (low 12 bits of data)
 | ||||||
|  |     uint8_t odd_parity_sum = 1; | ||||||
|  |     for(int8_t i = 0; i < 12; i++) { | ||||||
|  |         if(((fc_cn >> i) & 1) == 1) { | ||||||
|  |             odd_parity_sum++; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // 0x1D preamble
 | ||||||
|  |     write_raw_bit(0, 0, card_data); | ||||||
|  |     write_raw_bit(0, 1, card_data); | ||||||
|  |     write_raw_bit(0, 2, card_data); | ||||||
|  |     write_raw_bit(1, 3, card_data); | ||||||
|  |     write_raw_bit(1, 4, card_data); | ||||||
|  |     write_raw_bit(1, 5, card_data); | ||||||
|  |     write_raw_bit(0, 6, card_data); | ||||||
|  |     write_raw_bit(1, 7, card_data); | ||||||
|  | 
 | ||||||
|  |     // company / OEM code 1
 | ||||||
|  |     write_bit(0, 8, card_data); | ||||||
|  |     write_bit(0, 10, card_data); | ||||||
|  |     write_bit(0, 12, card_data); | ||||||
|  |     write_bit(0, 14, card_data); | ||||||
|  |     write_bit(0, 16, card_data); | ||||||
|  |     write_bit(0, 18, card_data); | ||||||
|  |     write_bit(1, 20, card_data); | ||||||
|  | 
 | ||||||
|  |     // card format / length 1
 | ||||||
|  |     write_bit(0, 22, card_data); | ||||||
|  |     write_bit(0, 24, card_data); | ||||||
|  |     write_bit(0, 26, card_data); | ||||||
|  |     write_bit(0, 28, card_data); | ||||||
|  |     write_bit(0, 30, card_data); | ||||||
|  |     write_bit(0, 32, card_data); | ||||||
|  |     write_bit(0, 34, card_data); | ||||||
|  |     write_bit(0, 36, card_data); | ||||||
|  |     write_bit(0, 38, card_data); | ||||||
|  |     write_bit(0, 40, card_data); | ||||||
|  |     write_bit(1, 42, card_data); | ||||||
|  | 
 | ||||||
|  |     // even parity bit
 | ||||||
|  |     write_bit((even_parity_sum % 2), 44, card_data); | ||||||
|  | 
 | ||||||
|  |     // data
 | ||||||
|  |     for(uint8_t i = 0; i < 24; i++) { | ||||||
|  |         write_bit((fc_cn >> (23 - i)) & 1, 46 + (i * 2), card_data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // odd parity bit
 | ||||||
|  |     write_bit((odd_parity_sum % 2), 94, card_data); | ||||||
|  | 
 | ||||||
|  |     memcpy(encoded_data, &card_data, get_encoded_data_size()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ProtocolHID10301::decode( | ||||||
|  |     const uint8_t* encoded_data, | ||||||
|  |     const uint8_t encoded_data_size, | ||||||
|  |     uint8_t* decoded_data, | ||||||
|  |     const uint8_t decoded_data_size) { | ||||||
|  |     furi_check(decoded_data_size >= get_decoded_data_size()); | ||||||
|  |     furi_check(encoded_data_size >= get_encoded_data_size()); | ||||||
|  | 
 | ||||||
|  |     const HID10301CardData* card_data = reinterpret_cast<const HID10301CardData*>(encoded_data); | ||||||
|  | 
 | ||||||
|  |     // data decoding
 | ||||||
|  |     uint32_t result = 0; | ||||||
|  | 
 | ||||||
|  |     // decode from word 1
 | ||||||
|  |     // coded with 01 = 0, 10 = 1 transitions
 | ||||||
|  |     for(int8_t i = 9; i >= 0; i--) { | ||||||
|  |         switch((*(card_data + 1) >> (2 * i)) & 0b11) { | ||||||
|  |         case 0b01: | ||||||
|  |             result = (result << 1) | 0; | ||||||
|  |             break; | ||||||
|  |         case 0b10: | ||||||
|  |             result = (result << 1) | 1; | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // decode from word 2
 | ||||||
|  |     // coded with 01 = 0, 10 = 1 transitions
 | ||||||
|  |     for(int8_t i = 15; i >= 0; i--) { | ||||||
|  |         switch((*(card_data + 2) >> (2 * i)) & 0b11) { | ||||||
|  |         case 0b01: | ||||||
|  |             result = (result << 1) | 0; | ||||||
|  |             break; | ||||||
|  |         case 0b10: | ||||||
|  |             result = (result << 1) | 1; | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     uint8_t data[3] = {(uint8_t)(result >> 17), (uint8_t)(result >> 9), (uint8_t)(result >> 1)}; | ||||||
|  | 
 | ||||||
|  |     memcpy(decoded_data, &data, get_decoded_data_size()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ProtocolHID10301::can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) { | ||||||
|  |     furi_check(encoded_data_size >= get_encoded_data_size()); | ||||||
|  | 
 | ||||||
|  |     const HID10301CardData* card_data = reinterpret_cast<const HID10301CardData*>(encoded_data); | ||||||
|  | 
 | ||||||
|  |     // packet preamble
 | ||||||
|  |     // raw data
 | ||||||
|  |     if(*(encoded_data + 3) != 0x1D) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // encoded company/oem
 | ||||||
|  |     // coded with 01 = 0, 10 = 1 transitions
 | ||||||
|  |     // stored in word 0
 | ||||||
|  |     if((*card_data >> 10 & 0x3FFF) != 0x1556) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // encoded format/length
 | ||||||
|  |     // coded with 01 = 0, 10 = 1 transitions
 | ||||||
|  |     // stored in word 0 and word 1
 | ||||||
|  |     if((((*card_data & 0x3FF) << 12) | ((*(card_data + 1) >> 20) & 0xFFF)) != 0x155556) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // data decoding
 | ||||||
|  |     uint32_t result = 0; | ||||||
|  | 
 | ||||||
|  |     // decode from word 1
 | ||||||
|  |     // coded with 01 = 0, 10 = 1 transitions
 | ||||||
|  |     for(int8_t i = 9; i >= 0; i--) { | ||||||
|  |         switch((*(card_data + 1) >> (2 * i)) & 0b11) { | ||||||
|  |         case 0b01: | ||||||
|  |             result = (result << 1) | 0; | ||||||
|  |             break; | ||||||
|  |         case 0b10: | ||||||
|  |             result = (result << 1) | 1; | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             return false; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // decode from word 2
 | ||||||
|  |     // coded with 01 = 0, 10 = 1 transitions
 | ||||||
|  |     for(int8_t i = 15; i >= 0; i--) { | ||||||
|  |         switch((*(card_data + 2) >> (2 * i)) & 0b11) { | ||||||
|  |         case 0b01: | ||||||
|  |             result = (result << 1) | 0; | ||||||
|  |             break; | ||||||
|  |         case 0b10: | ||||||
|  |             result = (result << 1) | 1; | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             return false; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // trailing parity (odd) test
 | ||||||
|  |     uint8_t parity_sum = 0; | ||||||
|  |     for(int8_t i = 0; i < 13; i++) { | ||||||
|  |         if(((result >> i) & 1) == 1) { | ||||||
|  |             parity_sum++; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if((parity_sum % 2) != 1) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // leading parity (even) test
 | ||||||
|  |     parity_sum = 0; | ||||||
|  |     for(int8_t i = 13; i < 26; i++) { | ||||||
|  |         if(((result >> i) & 1) == 1) { | ||||||
|  |             parity_sum++; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if((parity_sum % 2) == 1) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								applications/lf-rfid/helpers/protocols/protocol-hid-h10301.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								applications/lf-rfid/helpers/protocols/protocol-hid-h10301.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "protocol-generic.h" | ||||||
|  | 
 | ||||||
|  | class ProtocolHID10301 : public ProtocolGeneric { | ||||||
|  | public: | ||||||
|  |     uint8_t get_encoded_data_size() final; | ||||||
|  |     uint8_t get_decoded_data_size() final; | ||||||
|  | 
 | ||||||
|  |     void encode( | ||||||
|  |         const uint8_t* decoded_data, | ||||||
|  |         const uint8_t decoded_data_size, | ||||||
|  |         uint8_t* encoded_data, | ||||||
|  |         const uint8_t encoded_data_size) final; | ||||||
|  | 
 | ||||||
|  |     void decode( | ||||||
|  |         const uint8_t* encoded_data, | ||||||
|  |         const uint8_t encoded_data_size, | ||||||
|  |         uint8_t* decoded_data, | ||||||
|  |         const uint8_t decoded_data_size) final; | ||||||
|  | 
 | ||||||
|  |     bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) final; | ||||||
|  | }; | ||||||
							
								
								
									
										131
									
								
								applications/lf-rfid/helpers/protocols/protocol-indala-40134.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								applications/lf-rfid/helpers/protocols/protocol-indala-40134.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,131 @@ | |||||||
|  | #include "protocol-indala-40134.h" | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | typedef uint64_t Indala40134CardData; | ||||||
|  | 
 | ||||||
|  | static void set_bit(bool bit, uint8_t position, Indala40134CardData* card_data) { | ||||||
|  |     position = (sizeof(Indala40134CardData) * 8) - 1 - position; | ||||||
|  |     if(bit) { | ||||||
|  |         *card_data |= 1ull << position; | ||||||
|  |     } else { | ||||||
|  |         *card_data &= ~(1ull << position); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t ProtocolIndala40134::get_encoded_data_size() { | ||||||
|  |     return sizeof(Indala40134CardData); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint8_t ProtocolIndala40134::get_decoded_data_size() { | ||||||
|  |     return 3; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ProtocolIndala40134::encode( | ||||||
|  |     const uint8_t* decoded_data, | ||||||
|  |     const uint8_t decoded_data_size, | ||||||
|  |     uint8_t* encoded_data, | ||||||
|  |     const uint8_t encoded_data_size) { | ||||||
|  |     furi_check(decoded_data_size >= get_decoded_data_size()); | ||||||
|  |     furi_check(encoded_data_size >= get_encoded_data_size()); | ||||||
|  | 
 | ||||||
|  |     uint32_t fc_and_card = (decoded_data[0] << 16) | (decoded_data[1] << 8) | decoded_data[2]; | ||||||
|  |     Indala40134CardData card_data = 0; | ||||||
|  | 
 | ||||||
|  |     // preamble
 | ||||||
|  |     set_bit(1, 0, &card_data); | ||||||
|  |     set_bit(1, 2, &card_data); | ||||||
|  |     set_bit(1, 32, &card_data); | ||||||
|  | 
 | ||||||
|  |     // factory code
 | ||||||
|  |     set_bit(((fc_and_card >> 23) & 1), 57, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 22) & 1), 49, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 21) & 1), 44, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 20) & 1), 47, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 19) & 1), 48, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 18) & 1), 53, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 17) & 1), 39, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 16) & 1), 58, &card_data); | ||||||
|  | 
 | ||||||
|  |     // card number
 | ||||||
|  |     set_bit(((fc_and_card >> 15) & 1), 42, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 14) & 1), 45, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 13) & 1), 43, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 12) & 1), 40, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 11) & 1), 52, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 10) & 1), 36, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 9) & 1), 35, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 8) & 1), 51, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 7) & 1), 46, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 6) & 1), 33, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 5) & 1), 37, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 4) & 1), 54, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 3) & 1), 56, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 2) & 1), 59, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 1) & 1), 50, &card_data); | ||||||
|  |     set_bit(((fc_and_card >> 0) & 1), 41, &card_data); | ||||||
|  | 
 | ||||||
|  |     // checksum
 | ||||||
|  |     uint8_t checksum = 0; | ||||||
|  |     checksum += ((fc_and_card >> 14) & 1); | ||||||
|  |     checksum += ((fc_and_card >> 12) & 1); | ||||||
|  |     checksum += ((fc_and_card >> 9) & 1); | ||||||
|  |     checksum += ((fc_and_card >> 8) & 1); | ||||||
|  |     checksum += ((fc_and_card >> 6) & 1); | ||||||
|  |     checksum += ((fc_and_card >> 5) & 1); | ||||||
|  |     checksum += ((fc_and_card >> 2) & 1); | ||||||
|  |     checksum += ((fc_and_card >> 0) & 1); | ||||||
|  | 
 | ||||||
|  |     // wiegand parity bits
 | ||||||
|  |     // even parity sum calculation (high 12 bits of data)
 | ||||||
|  |     uint8_t even_parity_sum = 0; | ||||||
|  |     for(int8_t i = 12; i < 24; i++) { | ||||||
|  |         if(((fc_and_card >> i) & 1) == 1) { | ||||||
|  |             even_parity_sum++; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // odd parity sum calculation (low 12 bits of data)
 | ||||||
|  |     uint8_t odd_parity_sum = 1; | ||||||
|  |     for(int8_t i = 0; i < 12; i++) { | ||||||
|  |         if(((fc_and_card >> i) & 1) == 1) { | ||||||
|  |             odd_parity_sum++; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // even parity bit
 | ||||||
|  |     set_bit((even_parity_sum % 2), 34, &card_data); | ||||||
|  | 
 | ||||||
|  |     // odd parity bit
 | ||||||
|  |     set_bit((odd_parity_sum % 2), 38, &card_data); | ||||||
|  | 
 | ||||||
|  |     // checksum
 | ||||||
|  |     if((checksum & 1) == 1) { | ||||||
|  |         set_bit(0, 62, &card_data); | ||||||
|  |         set_bit(1, 63, &card_data); | ||||||
|  |     } else { | ||||||
|  |         set_bit(1, 62, &card_data); | ||||||
|  |         set_bit(0, 63, &card_data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     memcpy(encoded_data, &card_data, get_encoded_data_size()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ProtocolIndala40134::decode( | ||||||
|  |     const uint8_t* encoded_data, | ||||||
|  |     const uint8_t encoded_data_size, | ||||||
|  |     uint8_t* decoded_data, | ||||||
|  |     const uint8_t decoded_data_size) { | ||||||
|  |     furi_check(decoded_data_size >= get_decoded_data_size()); | ||||||
|  |     furi_check(encoded_data_size >= get_encoded_data_size()); | ||||||
|  |     // TODO implement decoding
 | ||||||
|  |     furi_check(0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ProtocolIndala40134::can_be_decoded( | ||||||
|  |     const uint8_t* encoded_data, | ||||||
|  |     const uint8_t encoded_data_size) { | ||||||
|  |     furi_check(encoded_data_size >= get_encoded_data_size()); | ||||||
|  |     // TODO implement decoding
 | ||||||
|  |     furi_check(0); | ||||||
|  |     return false; | ||||||
|  | } | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "protocol-generic.h" | ||||||
|  | 
 | ||||||
|  | class ProtocolIndala40134 : public ProtocolGeneric { | ||||||
|  | public: | ||||||
|  |     uint8_t get_encoded_data_size() final; | ||||||
|  |     uint8_t get_decoded_data_size() final; | ||||||
|  | 
 | ||||||
|  |     void encode( | ||||||
|  |         const uint8_t* decoded_data, | ||||||
|  |         const uint8_t decoded_data_size, | ||||||
|  |         uint8_t* encoded_data, | ||||||
|  |         const uint8_t encoded_data_size) final; | ||||||
|  | 
 | ||||||
|  |     void decode( | ||||||
|  |         const uint8_t* encoded_data, | ||||||
|  |         const uint8_t encoded_data_size, | ||||||
|  |         uint8_t* decoded_data, | ||||||
|  |         const uint8_t decoded_data_size) final; | ||||||
|  | 
 | ||||||
|  |     bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) final; | ||||||
|  | }; | ||||||
							
								
								
									
										118
									
								
								applications/lf-rfid/helpers/rfid-writer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								applications/lf-rfid/helpers/rfid-writer.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,118 @@ | |||||||
|  | #include "rfid-writer.h" | ||||||
|  | #include <api-hal.h> | ||||||
|  | #include "protocols/protocol-emmarin.h" | ||||||
|  | 
 | ||||||
|  | extern COMP_HandleTypeDef hcomp1; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief all timings are specified in field clocks (field clock = 125 kHz, 8 us) | ||||||
|  |  *  | ||||||
|  |  */ | ||||||
|  | class T55xxTiming { | ||||||
|  | public: | ||||||
|  |     constexpr static const uint16_t wait_time = 400; | ||||||
|  |     constexpr static const uint8_t start_gap = 15; | ||||||
|  |     constexpr static const uint8_t write_gap = 10; | ||||||
|  |     constexpr static const uint8_t data_0 = 24; | ||||||
|  |     constexpr static const uint8_t data_1 = 56; | ||||||
|  |     constexpr static const uint16_t program = 700; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class T55xxCmd { | ||||||
|  | public: | ||||||
|  |     constexpr static const uint8_t opcode_page_0 = 0b10; | ||||||
|  |     constexpr static const uint8_t opcode_page_1 = 0b11; | ||||||
|  |     constexpr static const uint8_t opcode_reset = 0b00; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | RfidWriter::RfidWriter() { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | RfidWriter::~RfidWriter() { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void RfidWriter::start() { | ||||||
|  |     api_hal_rfid_tim_read(125000, 0.5); | ||||||
|  |     api_hal_rfid_pins_read(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void RfidWriter::stop() { | ||||||
|  |     api_hal_rfid_tim_read_stop(); | ||||||
|  |     api_hal_rfid_tim_reset(); | ||||||
|  |     api_hal_rfid_pins_reset(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void RfidWriter::write_gap(uint32_t gap_time) { | ||||||
|  |     api_hal_rfid_tim_read_stop(); | ||||||
|  |     delay_us(gap_time * 8); | ||||||
|  |     api_hal_rfid_tim_read_start(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void RfidWriter::write_bit(bool value) { | ||||||
|  |     if(value) { | ||||||
|  |         delay_us(T55xxTiming::data_1 * 8); | ||||||
|  |     } else { | ||||||
|  |         delay_us(T55xxTiming::data_0 * 8); | ||||||
|  |     } | ||||||
|  |     write_gap(T55xxTiming::write_gap); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void RfidWriter::write_byte(uint8_t value) { | ||||||
|  |     for(uint8_t i = 0; i < 8; i++) { | ||||||
|  |         write_bit((value >> i) & 1); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void RfidWriter::write_block(uint8_t page, uint8_t block, bool lock_bit, uint32_t data) { | ||||||
|  |     // wait to power card
 | ||||||
|  |     api_hal_rfid_tim_read_start(); | ||||||
|  |     delay_us(T55xxTiming::wait_time * 8); | ||||||
|  | 
 | ||||||
|  |     // start gap
 | ||||||
|  |     write_gap(T55xxTiming::start_gap); | ||||||
|  | 
 | ||||||
|  |     // opcode
 | ||||||
|  |     switch(page) { | ||||||
|  |     case 0: | ||||||
|  |         write_bit(1); | ||||||
|  |         write_bit(0); | ||||||
|  |         break; | ||||||
|  |     case 1: | ||||||
|  |         write_bit(1); | ||||||
|  |         write_bit(1); | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         furi_check(false); | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // lock bit
 | ||||||
|  |     write_bit(lock_bit); | ||||||
|  | 
 | ||||||
|  |     // data
 | ||||||
|  |     for(uint8_t i = 0; i < 32; i++) { | ||||||
|  |         write_bit((data >> (31 - i)) & 1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // block address
 | ||||||
|  |     write_bit((block >> 2) & 1); | ||||||
|  |     write_bit((block >> 1) & 1); | ||||||
|  |     write_bit((block >> 0) & 1); | ||||||
|  | 
 | ||||||
|  |     delay_us(T55xxTiming::program * 8); | ||||||
|  | 
 | ||||||
|  |     api_hal_rfid_tim_read_stop(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void RfidWriter::write_em(uint8_t em_data[5]) { | ||||||
|  |     ProtocolEMMarin em_card; | ||||||
|  |     uint64_t em_encoded_data; | ||||||
|  |     em_card.encode(em_data, 5, reinterpret_cast<uint8_t*>(&em_encoded_data), sizeof(uint64_t)); | ||||||
|  |     uint32_t em_config_block_data = 0b01100000000101001000000001000000; | ||||||
|  | 
 | ||||||
|  |     __disable_irq(); | ||||||
|  |     write_block(0, 0, false, em_config_block_data); | ||||||
|  |     write_block(0, 1, false, em_encoded_data); | ||||||
|  |     write_block(0, 2, false, em_encoded_data >> 32); | ||||||
|  |     __enable_irq(); | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								applications/lf-rfid/helpers/rfid-writer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								applications/lf-rfid/helpers/rfid-writer.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "stdint.h" | ||||||
|  | 
 | ||||||
|  | class RfidWriter { | ||||||
|  | public: | ||||||
|  |     RfidWriter(); | ||||||
|  |     ~RfidWriter(); | ||||||
|  |     void start(); | ||||||
|  |     void stop(); | ||||||
|  |     void write_em(uint8_t em_data[5]); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     void write_gap(uint32_t gap_time); | ||||||
|  |     void write_bit(bool value); | ||||||
|  |     void write_byte(uint8_t value); | ||||||
|  |     void write_block(uint8_t page, uint8_t block, bool lock_bit, uint32_t data); | ||||||
|  | }; | ||||||
| @ -144,3 +144,7 @@ RfidReader* LfrfidApp::get_reader() { | |||||||
| RfidTimerEmulator* LfrfidApp::get_emulator() { | RfidTimerEmulator* LfrfidApp::get_emulator() { | ||||||
|     return &emulator; |     return &emulator; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | RfidWriter* LfrfidApp::get_writer() { | ||||||
|  |     return &writer; | ||||||
|  | } | ||||||
| @ -10,6 +10,7 @@ | |||||||
| #include "scene/lf-rfid-scene-read-normal.h" | #include "scene/lf-rfid-scene-read-normal.h" | ||||||
| #include "scene/lf-rfid-scene-read-indala.h" | #include "scene/lf-rfid-scene-read-indala.h" | ||||||
| #include "scene/lf-rfid-scene-tune.h" | #include "scene/lf-rfid-scene-tune.h" | ||||||
|  | #include "scene/lf-rfid-scene-write.h" | ||||||
| 
 | 
 | ||||||
| #include "helpers/rfid-reader.h" | #include "helpers/rfid-reader.h" | ||||||
| #include "helpers/rfid-timer-emulator.h" | #include "helpers/rfid-timer-emulator.h" | ||||||
| @ -30,6 +31,7 @@ public: | |||||||
|         EmulateHID, |         EmulateHID, | ||||||
|         EmulateEM, |         EmulateEM, | ||||||
|         Tune, |         Tune, | ||||||
|  |         Write, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     LfrfidAppViewManager* get_view_manager(); |     LfrfidAppViewManager* get_view_manager(); | ||||||
| @ -49,6 +51,7 @@ public: | |||||||
| 
 | 
 | ||||||
|     RfidReader* get_reader(); |     RfidReader* get_reader(); | ||||||
|     RfidTimerEmulator* get_emulator(); |     RfidTimerEmulator* get_emulator(); | ||||||
|  |     RfidWriter* get_writer(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     std::list<Scene> previous_scenes_list = {Scene::Exit}; |     std::list<Scene> previous_scenes_list = {Scene::Exit}; | ||||||
| @ -63,6 +66,7 @@ private: | |||||||
|         {Scene::EmulateHID, new LfrfidSceneEmulateHID()}, |         {Scene::EmulateHID, new LfrfidSceneEmulateHID()}, | ||||||
|         {Scene::EmulateEM, new LfrfidSceneEmulateEMMarine()}, |         {Scene::EmulateEM, new LfrfidSceneEmulateEMMarine()}, | ||||||
|         {Scene::Tune, new LfrfidSceneTune()}, |         {Scene::Tune, new LfrfidSceneTune()}, | ||||||
|  |         {Scene::Write, new LfrfidSceneWrite()}, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     static const uint8_t text_store_size = 128; |     static const uint8_t text_store_size = 128; | ||||||
| @ -70,4 +74,5 @@ private: | |||||||
| 
 | 
 | ||||||
|     RfidReader reader; |     RfidReader reader; | ||||||
|     RfidTimerEmulator emulator; |     RfidTimerEmulator emulator; | ||||||
|  |     RfidWriter writer; | ||||||
| }; | }; | ||||||
| @ -55,6 +55,15 @@ bool LfrfidSceneReadNormal::on_event(LfrfidApp* app, LfrfidEvent* event) { | |||||||
|                     data[2], |                     data[2], | ||||||
|                     success_reads); |                     success_reads); | ||||||
|                 break; |                 break; | ||||||
|  |             case LfrfidKeyType::KeyIndala: | ||||||
|  |                 app->set_text_store( | ||||||
|  |                     "[IND] %02X %02X %02X\n" | ||||||
|  |                     "count: %u", | ||||||
|  |                     data[0], | ||||||
|  |                     data[1], | ||||||
|  |                     data[2], | ||||||
|  |                     success_reads); | ||||||
|  |                 break; | ||||||
|             } |             } | ||||||
|             popup_set_text( |             popup_set_text( | ||||||
|                 app->get_view_manager()->get_popup(), |                 app->get_view_manager()->get_popup(), | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ | |||||||
| #include <callback-connector.h> | #include <callback-connector.h> | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|  |     SubmenuIndexWrite, | ||||||
|     SubmenuIndexReadNormal, |     SubmenuIndexReadNormal, | ||||||
|     SubmenuIndexReadIndala, |     SubmenuIndexReadIndala, | ||||||
|     SubmenuIndexEmulateEM, |     SubmenuIndexEmulateEM, | ||||||
| @ -18,6 +19,7 @@ void LfrfidSceneStart::on_enter(LfrfidApp* app) { | |||||||
|     Submenu* submenu = view_manager->get_submenu(); |     Submenu* submenu = view_manager->get_submenu(); | ||||||
|     auto callback = cbc::obtain_connector(this, &LfrfidSceneStart::submenu_callback); |     auto callback = cbc::obtain_connector(this, &LfrfidSceneStart::submenu_callback); | ||||||
| 
 | 
 | ||||||
|  |     submenu_add_item(submenu, "Write T5577", SubmenuIndexWrite, callback, app); | ||||||
|     submenu_add_item(submenu, "Read Normal", SubmenuIndexReadNormal, callback, app); |     submenu_add_item(submenu, "Read Normal", SubmenuIndexReadNormal, callback, app); | ||||||
|     submenu_add_item(submenu, "Read Indala", SubmenuIndexReadIndala, callback, app); |     submenu_add_item(submenu, "Read Indala", SubmenuIndexReadIndala, callback, app); | ||||||
|     submenu_add_item(submenu, "Emulate EM", SubmenuIndexEmulateEM, callback, app); |     submenu_add_item(submenu, "Emulate EM", SubmenuIndexEmulateEM, callback, app); | ||||||
| @ -33,6 +35,9 @@ bool LfrfidSceneStart::on_event(LfrfidApp* app, LfrfidEvent* event) { | |||||||
| 
 | 
 | ||||||
|     if(event->type == LfrfidEvent::Type::MenuSelected) { |     if(event->type == LfrfidEvent::Type::MenuSelected) { | ||||||
|         switch(event->payload.menu_index) { |         switch(event->payload.menu_index) { | ||||||
|  |         case SubmenuIndexWrite: | ||||||
|  |             app->switch_to_next_scene(LfrfidApp::Scene::Write); | ||||||
|  |             break; | ||||||
|         case SubmenuIndexReadNormal: |         case SubmenuIndexReadNormal: | ||||||
|             app->switch_to_next_scene(LfrfidApp::Scene::ReadNormal); |             app->switch_to_next_scene(LfrfidApp::Scene::ReadNormal); | ||||||
|             break; |             break; | ||||||
|  | |||||||
							
								
								
									
										70
									
								
								applications/lf-rfid/scene/lf-rfid-scene-write.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								applications/lf-rfid/scene/lf-rfid-scene-write.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | |||||||
|  | #include "lf-rfid-scene-write.h" | ||||||
|  | 
 | ||||||
|  | #include "../lf-rfid-app.h" | ||||||
|  | #include "../lf-rfid-view-manager.h" | ||||||
|  | #include "../lf-rfid-event.h" | ||||||
|  | #include "../helpers/key-info.h" | ||||||
|  | 
 | ||||||
|  | void LfrfidSceneWrite::on_enter(LfrfidApp* app) { | ||||||
|  |     LfrfidAppViewManager* view_manager = app->get_view_manager(); | ||||||
|  | 
 | ||||||
|  |     Popup* popup = view_manager->get_popup(); | ||||||
|  |     popup_set_header(popup, "LF-RFID", 64, 16, AlignCenter, AlignBottom); | ||||||
|  |     app->set_text_store("Writing..."); | ||||||
|  |     popup_set_text(popup, app->get_text_store(), 64, 22, AlignCenter, AlignTop); | ||||||
|  | 
 | ||||||
|  |     view_manager->switch_to(LfrfidAppViewManager::ViewType::Popup); | ||||||
|  | 
 | ||||||
|  |     timing_index = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool LfrfidSceneWrite::on_event(LfrfidApp* app, LfrfidEvent* event) { | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     // TODO move read\write logic to key worker
 | ||||||
|  | 
 | ||||||
|  |     bool readed = false; | ||||||
|  |     uint8_t em_data[5] = {0x1A, 0x2B, 0xC3, 0xD4, 0xE5}; | ||||||
|  | 
 | ||||||
|  |     if(timing_index == 0) { | ||||||
|  |         app->get_reader()->stop(); | ||||||
|  |         app->get_writer()->start(); | ||||||
|  |         app->get_writer()->write_em(em_data); | ||||||
|  |         app->get_writer()->stop(); | ||||||
|  |         delay(100); | ||||||
|  |         app->get_reader()->start(RfidReader::Type::Normal); | ||||||
|  |     } else { | ||||||
|  |         uint8_t data[LFRFID_KEY_SIZE]; | ||||||
|  |         LfrfidKeyType type; | ||||||
|  | 
 | ||||||
|  |         app->get_reader()->read(&type, data, LFRFID_KEY_SIZE); | ||||||
|  |         if(type == LfrfidKeyType::KeyEmarine) { | ||||||
|  |             if(memcmp(em_data, data, 5) == 0) { | ||||||
|  |                 readed = true; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(readed) { | ||||||
|  |         app->set_text_store("Writed!"); | ||||||
|  |         app->notify_green_blink(); | ||||||
|  |     } else { | ||||||
|  |         app->set_text_store("Writing [1A 2B C3 D4 E5]"); | ||||||
|  |         timing_index++; | ||||||
|  |         if(timing_index == 4) { | ||||||
|  |             timing_index = 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     popup_set_text( | ||||||
|  |         app->get_view_manager()->get_popup(), app->get_text_store(), 64, 22, AlignCenter, AlignTop); | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LfrfidSceneWrite::on_exit(LfrfidApp* app) { | ||||||
|  |     LfrfidAppViewManager* view_manager = app->get_view_manager(); | ||||||
|  | 
 | ||||||
|  |     Popup* popup = view_manager->get_popup(); | ||||||
|  |     popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); | ||||||
|  |     popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								applications/lf-rfid/scene/lf-rfid-scene-write.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								applications/lf-rfid/scene/lf-rfid-scene-write.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "lf-rfid-scene-generic.h" | ||||||
|  | #include "../helpers/key-info.h" | ||||||
|  | #include "../helpers/rfid-writer.h" | ||||||
|  | 
 | ||||||
|  | class LfrfidSceneWrite : public LfrfidScene { | ||||||
|  | public: | ||||||
|  |     void on_enter(LfrfidApp* app) final; | ||||||
|  |     bool on_event(LfrfidApp* app, LfrfidEvent* event) final; | ||||||
|  |     void on_exit(LfrfidApp* app) final; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     uint8_t timing_index; | ||||||
|  | }; | ||||||
| @ -41,11 +41,28 @@ static uint8_t hal_gpio_get_pin_num(const GpioPin* gpio) { | |||||||
|     return pin_num; |     return pin_num; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void hal_gpio_init_simple(const GpioPin* gpio, const GpioMode mode) { | ||||||
|  |     hal_gpio_init(gpio, mode, GpioPullNo, GpioSpeedLow); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void hal_gpio_init( | void hal_gpio_init( | ||||||
|     const GpioPin* gpio, |     const GpioPin* gpio, | ||||||
|     const GpioMode mode, |     const GpioMode mode, | ||||||
|     const GpioPull pull, |     const GpioPull pull, | ||||||
|     const GpioSpeed speed) { |     const GpioSpeed speed) { | ||||||
|  |     // we cannot set alternate mode in this function
 | ||||||
|  |     furi_assert(mode != GpioModeAltFunctionPushPull); | ||||||
|  |     furi_assert(mode != GpioModeAltFunctionOpenDrain); | ||||||
|  | 
 | ||||||
|  |     hal_gpio_init_ex(gpio, mode, GpioPullNo, GpioSpeedLow, GpioAltFnUnused); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void hal_gpio_init_ex( | ||||||
|  |     const GpioPin* gpio, | ||||||
|  |     const GpioMode mode, | ||||||
|  |     const GpioPull pull, | ||||||
|  |     const GpioSpeed speed, | ||||||
|  |     const GpioAltFn alt_fn) { | ||||||
|     uint32_t sys_exti_port = GET_SYSCFG_EXTI_PORT(gpio->port); |     uint32_t sys_exti_port = GET_SYSCFG_EXTI_PORT(gpio->port); | ||||||
|     uint32_t sys_exti_line = GET_SYSCFG_EXTI_LINE(gpio->pin); |     uint32_t sys_exti_line = GET_SYSCFG_EXTI_LINE(gpio->pin); | ||||||
|     uint32_t exti_line = GET_EXTI_LINE(gpio->pin); |     uint32_t exti_line = GET_EXTI_LINE(gpio->pin); | ||||||
| @ -112,27 +129,19 @@ void hal_gpio_init( | |||||||
|             LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ANALOG); |             LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ANALOG); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     __enable_irq(); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| void hal_gpio_init_alt( |     if(mode == GpioModeAltFunctionPushPull || mode == GpioModeAltFunctionOpenDrain) { | ||||||
|     const GpioPin* gpio, |         // enable alternate mode
 | ||||||
|     const GpioMode mode, |         LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ALTERNATE); | ||||||
|     const GpioPull pull, |  | ||||||
|     const GpioSpeed speed, |  | ||||||
|     const GpioAltFn alt_fn) { |  | ||||||
|     hal_gpio_init(gpio, mode, pull, speed); |  | ||||||
| 
 | 
 | ||||||
|     __disable_irq(); |         // set alternate function
 | ||||||
|     // enable alternate mode
 |         if(hal_gpio_get_pin_num(gpio) < 8) { | ||||||
|     LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ALTERNATE); |             LL_GPIO_SetAFPin_0_7(gpio->port, gpio->pin, alt_fn); | ||||||
| 
 |         } else { | ||||||
|     // set alternate function
 |             LL_GPIO_SetAFPin_8_15(gpio->port, gpio->pin, alt_fn); | ||||||
|     if(hal_gpio_get_pin_num(gpio) < 8) { |         } | ||||||
|         LL_GPIO_SetAFPin_0_7(gpio->port, gpio->pin, alt_fn); |  | ||||||
|     } else { |  | ||||||
|         LL_GPIO_SetAFPin_8_15(gpio->port, gpio->pin, alt_fn); |  | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     __enable_irq(); |     __enable_irq(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -153,6 +153,8 @@ typedef enum { | |||||||
|     GpioAltFn14LPTIM2 = 14, /*!< LPTIM2 Alternate Function mapping */ |     GpioAltFn14LPTIM2 = 14, /*!< LPTIM2 Alternate Function mapping */ | ||||||
| 
 | 
 | ||||||
|     GpioAltFn15EVENTOUT = 15, /*!< EVENTOUT Alternate Function mapping */ |     GpioAltFn15EVENTOUT = 15, /*!< EVENTOUT Alternate Function mapping */ | ||||||
|  | 
 | ||||||
|  |     GpioAltFnUnused = 16, /*!< just dummy value */ | ||||||
| } GpioAltFn; | } GpioAltFn; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -164,7 +166,14 @@ typedef struct { | |||||||
| } GpioPin; | } GpioPin; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * GPIO initialization function |  * GPIO initialization function, simple version | ||||||
|  |  * @param gpio  GpioPin | ||||||
|  |  * @param mode  GpioMode | ||||||
|  |  */ | ||||||
|  | void hal_gpio_init_simple(const GpioPin* gpio, const GpioMode mode); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * GPIO initialization function, normal version | ||||||
|  * @param gpio  GpioPin |  * @param gpio  GpioPin | ||||||
|  * @param mode  GpioMode |  * @param mode  GpioMode | ||||||
|  * @param pull  GpioPull |  * @param pull  GpioPull | ||||||
| @ -177,14 +186,14 @@ void hal_gpio_init( | |||||||
|     const GpioSpeed speed); |     const GpioSpeed speed); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * GPIO initialization with alternative function |  * GPIO initialization function, extended version | ||||||
|  * @param gpio  GpioPin |  * @param gpio  GpioPin | ||||||
|  * @param mode  GpioMode |  * @param mode  GpioMode | ||||||
|  * @param pull  GpioPull |  * @param pull  GpioPull | ||||||
|  * @param speed GpioSpeed |  * @param speed GpioSpeed | ||||||
|  * @param alt_fn GpioAltFn |  * @param alt_fn GpioAltFn | ||||||
|  */ |  */ | ||||||
| void hal_gpio_init_alt( | void hal_gpio_init_ex( | ||||||
|     const GpioPin* gpio, |     const GpioPin* gpio, | ||||||
|     const GpioMode mode, |     const GpioMode mode, | ||||||
|     const GpioPull pull, |     const GpioPull pull, | ||||||
|  | |||||||
| @ -21,8 +21,8 @@ void api_hal_rfid_pins_emulate() { | |||||||
|     api_hal_ibutton_pin_low(); |     api_hal_ibutton_pin_low(); | ||||||
| 
 | 
 | ||||||
|     // pull pin to timer out
 |     // pull pin to timer out
 | ||||||
|     hal_gpio_init_alt( |     hal_gpio_init_ex( | ||||||
|         &gpio_rfid_pull, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo, GpioAltFn1TIM1); |         &gpio_rfid_pull, GpioModeAltFunctionPushPull, GpioSpeedLow, GpioPullNo, GpioAltFn1TIM1); | ||||||
| 
 | 
 | ||||||
|     // pull rfid antenna from carrier side
 |     // pull rfid antenna from carrier side
 | ||||||
|     hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo); |     hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo); | ||||||
| @ -39,8 +39,12 @@ void api_hal_rfid_pins_read() { | |||||||
|     hal_gpio_write(&gpio_rfid_pull, false); |     hal_gpio_write(&gpio_rfid_pull, false); | ||||||
| 
 | 
 | ||||||
|     // carrier pin to timer out
 |     // carrier pin to timer out
 | ||||||
|     hal_gpio_init_alt( |     hal_gpio_init_ex( | ||||||
|         &gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo, GpioAltFn1TIM1); |         &gpio_rfid_carrier_out, | ||||||
|  |         GpioModeAltFunctionPushPull, | ||||||
|  |         GpioSpeedLow, | ||||||
|  |         GpioPullNo, | ||||||
|  |         GpioAltFn1TIM1); | ||||||
| 
 | 
 | ||||||
|     // comparator in
 |     // comparator in
 | ||||||
|     hal_gpio_init(&gpio_rfid_data_in, GpioModeAnalog, GpioSpeedLow, GpioPullNo); |     hal_gpio_init(&gpio_rfid_data_in, GpioModeAnalog, GpioSpeedLow, GpioPullNo); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 SG
						SG