-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fcf242a
commit e6acfb4
Showing
2 changed files
with
378 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,374 @@ | ||
#include <furi.h> | ||
#include <toolbox/protocols/protocol.h> | ||
|
||
#include <bit_lib/bit_lib.h> | ||
|
||
#include <toolbox/manchester_decoder.h> | ||
|
||
// #include <lfrfid/tools/fsk_demod.h> | ||
// #include <lfrfid/tools/fsk_osc.h> | ||
|
||
#include "lfrfid_protocols.h" | ||
|
||
#define TAG "InstaFob" | ||
|
||
#define INSTAFOB_DECODED_DATA_SIZE_BYTES (8) | ||
|
||
#define INSTAFOB_ENCODED_DATA_SIZE_BYTES ((4 * 7) + 1) | ||
#define INSTAFOB_ENCODED_DATA_SIZE_BITS ((8 * 4 * 7) + 1) | ||
#define INSTAFOB_ENCODED_DATA_OFFSET (7) | ||
|
||
#define INSTAFOB_BLOCK1 (0x00107060) | ||
|
||
#define LFRFID_FREQUENCY (125000) | ||
#define INSTAFOB_CLOCK_PER_BIT (32) | ||
#define INSTAFOB_READ_LONG_TIME_BASE (1000000 / (LFRFID_FREQUENCY / INSTAFOB_CLOCK_PER_BIT)) | ||
#define INSTAFOB_READ_SHORT_TIME_BASE (INSTAFOB_READ_LONG_TIME_BASE / 2) | ||
#define INSTAFOB_READ_SEQTERM_TIME_BASE \ | ||
(1000000 / (LFRFID_FREQUENCY * 32 / 50 / INSTAFOB_CLOCK_PER_BIT)) | ||
#define INSTAFOB_READ_JITTER_TIME_BASE (INSTAFOB_READ_SHORT_TIME_BASE * 40 / 100) | ||
// #define INSTAFOB_CHECK_AS_WE_GO 1 | ||
|
||
typedef enum { | ||
ProtocolInstaFobSeqTermNone = 0, | ||
ProtocolInstaFobSeqTermS1, | ||
ProtocolInstaFobSeqTermS2, | ||
ProtocolInstaFobSeqTermS3, | ||
ProtocolInstaFobSeqTermS4, | ||
ProtocolInstaFobSeqTermS5, | ||
ProtocolInstaFobSeqTermS6, | ||
ProtocolInstaFobSeqTermSMax, | ||
} ProtocolInstaFobSeqTermState; | ||
|
||
typedef struct { | ||
uint8_t data[INSTAFOB_DECODED_DATA_SIZE_BYTES]; | ||
|
||
uint8_t encoded_data[INSTAFOB_ENCODED_DATA_SIZE_BYTES]; | ||
uint8_t encoded_data_index; | ||
bool encoded_polarity; | ||
ProtocolInstaFobSeqTermState encoded_term_state; | ||
FuriString* debug_string; | ||
|
||
ManchesterState decoder_manchester_state; | ||
} ProtocolInstaFob; | ||
|
||
ProtocolInstaFob* protocol_insta_fob_alloc(void) { | ||
ProtocolInstaFob* protocol = malloc(sizeof(ProtocolInstaFob)); | ||
bit_lib_num_to_bytes_be(INSTAFOB_BLOCK1, 4, protocol->data); | ||
protocol->debug_string = furi_string_alloc(); | ||
return (void*)protocol; | ||
}; | ||
|
||
void protocol_insta_fob_free(ProtocolInstaFob* protocol) { | ||
free(protocol->debug_string); | ||
free(protocol); | ||
}; | ||
|
||
uint8_t* protocol_insta_fob_get_data(ProtocolInstaFob* protocol) { | ||
return protocol->data; | ||
}; | ||
|
||
void protocol_insta_fob_decoder_start(ProtocolInstaFob* protocol) { | ||
memset(protocol->data, 0, INSTAFOB_DECODED_DATA_SIZE_BYTES); | ||
memset(protocol->encoded_data, 0, INSTAFOB_ENCODED_DATA_SIZE_BYTES); | ||
manchester_advance( | ||
protocol->decoder_manchester_state, | ||
ManchesterEventReset, | ||
&protocol->decoder_manchester_state, | ||
NULL); | ||
protocol->encoded_polarity = false; | ||
protocol->encoded_term_state = ProtocolInstaFobSeqTermNone; | ||
}; | ||
|
||
static const char* protocol_insta_fob_get_encoded_data(ProtocolInstaFob* protocol) { | ||
furi_string_reset(protocol->debug_string); | ||
for(size_t i = 0; i < INSTAFOB_ENCODED_DATA_SIZE_BITS; i++) { | ||
furi_string_cat( | ||
protocol->debug_string, bit_lib_get_bit(protocol->encoded_data, i) ? "1" : "0"); | ||
} | ||
return furi_string_get_cstr(protocol->debug_string); | ||
}; | ||
|
||
static bool protocol_insta_fob_can_be_decoded(ProtocolInstaFob* protocol) { | ||
return bit_lib_get_bits_32(protocol->encoded_data, INSTAFOB_ENCODED_DATA_OFFSET, 32) == | ||
INSTAFOB_BLOCK1; | ||
} | ||
|
||
static void protocol_insta_fob_decode(ProtocolInstaFob* protocol) { | ||
bit_lib_copy_bits(protocol->data, 0, 64, protocol->encoded_data, INSTAFOB_ENCODED_DATA_OFFSET); | ||
}; | ||
|
||
static bool protocol_insta_fob_in_range(uint32_t value, uint32_t base, uint32_t jitter) { | ||
return (value > (base - jitter)) && (value < (base + jitter)); | ||
}; | ||
|
||
static ManchesterEvent protocol_insta_fob_manchester_event(bool level, uint32_t duration_us) { | ||
ManchesterEvent event = ManchesterEventReset; | ||
|
||
if(protocol_insta_fob_in_range( | ||
duration_us, INSTAFOB_READ_SHORT_TIME_BASE, INSTAFOB_READ_JITTER_TIME_BASE)) { | ||
if(!level) { | ||
event = ManchesterEventShortHigh; | ||
} else { | ||
event = ManchesterEventShortLow; | ||
} | ||
} else if(protocol_insta_fob_in_range( | ||
duration_us, INSTAFOB_READ_LONG_TIME_BASE, INSTAFOB_READ_JITTER_TIME_BASE)) { | ||
if(!level) { | ||
event = ManchesterEventLongHigh; | ||
} else { | ||
event = ManchesterEventLongLow; | ||
} | ||
} | ||
|
||
return event; | ||
}; | ||
|
||
static bool protocol_insta_fob_is_sequence_terminator(uint32_t duration_us) { | ||
return protocol_insta_fob_in_range( | ||
duration_us, INSTAFOB_READ_SEQTERM_TIME_BASE, INSTAFOB_READ_JITTER_TIME_BASE); | ||
}; | ||
|
||
static bool protocol_insta_fob_decoder_seq_terminator( | ||
ProtocolInstaFob* protocol, | ||
bool level, | ||
uint32_t duration_us) { | ||
bool decoded_signal = false; | ||
ManchesterEvent event = protocol_insta_fob_manchester_event(level, duration_us); | ||
|
||
if(level && protocol_insta_fob_is_sequence_terminator(duration_us)) { | ||
protocol->encoded_term_state = ProtocolInstaFobSeqTermS3; | ||
} else if(protocol->encoded_term_state == ProtocolInstaFobSeqTermS3) { | ||
if(event == ManchesterEventShortHigh) { | ||
// We found expected next part of sequence terminator. | ||
protocol->encoded_term_state = ProtocolInstaFobSeqTermS4; | ||
} else { | ||
// Unexpected signal, start scanning the card again. | ||
protocol->encoded_term_state = ProtocolInstaFobSeqTermNone; | ||
} | ||
} else if(protocol->encoded_term_state == ProtocolInstaFobSeqTermS4) { | ||
if(event == ManchesterEventLongLow) { | ||
protocol->encoded_term_state = ProtocolInstaFobSeqTermS6; | ||
} else { | ||
// Unexpected signal, start scanning the card again. | ||
protocol->encoded_term_state = ProtocolInstaFobSeqTermNone; | ||
} | ||
} else if(protocol->encoded_term_state == ProtocolInstaFobSeqTermS6) { | ||
// We found the last part of sequence terminator! | ||
|
||
// Check if our data is valid. | ||
if(protocol_insta_fob_can_be_decoded(protocol)) { | ||
protocol_insta_fob_decode(protocol); | ||
decoded_signal = true; | ||
|
||
FURI_LOG_D(TAG, "Decoded %s", protocol_insta_fob_get_encoded_data(protocol)); | ||
|
||
// Clear the encoded data, reset to the first bit. | ||
memset(protocol->encoded_data, 0, INSTAFOB_ENCODED_DATA_SIZE_BYTES); | ||
protocol->encoded_polarity = false; | ||
} else { | ||
FURI_LOG_D(TAG, "Failed decoding %s", protocol_insta_fob_get_encoded_data(protocol)); | ||
} | ||
|
||
protocol->encoded_term_state = ProtocolInstaFobSeqTermNone; | ||
} else { | ||
// Unknown signal, ignore. | ||
} | ||
|
||
return decoded_signal; | ||
} | ||
|
||
bool protocol_insta_fob_decoder_feed(ProtocolInstaFob* protocol, bool level, uint32_t duration_us) { | ||
bool decoded_signal = false; | ||
ManchesterEvent event = protocol_insta_fob_manchester_event(level, duration_us); | ||
|
||
if(protocol->encoded_term_state || event == ManchesterEventReset) { | ||
return protocol_insta_fob_decoder_seq_terminator(protocol, level, duration_us); | ||
} | ||
|
||
bool data; | ||
bool data_ok = manchester_advance( | ||
protocol->decoder_manchester_state, event, &protocol->decoder_manchester_state, &data); | ||
// If data_ok is false, it means we only decoded the first half of the bit. | ||
// When data_ok is true, we decoded both halves of the bit and "data" variable is set. | ||
|
||
if(data_ok) { | ||
// Mark that we read the second half of signal | ||
protocol->encoded_polarity = false; | ||
|
||
bit_lib_push_bit(protocol->encoded_data, INSTAFOB_ENCODED_DATA_SIZE_BYTES, data); | ||
|
||
#ifdef INSTAFOB_CHECK_AS_WE_GO | ||
if(protocol_insta_fob_can_be_decoded(protocol)) { | ||
protocol_insta_fob_decode(protocol); | ||
decoded_signal = true; | ||
|
||
memset(protocol->encoded_data, 0, INSTAFOB_ENCODED_DATA_SIZE_BYTES); | ||
protocol->encoded_polarity = false; | ||
} | ||
#endif | ||
} else { | ||
// encoded_polarity should be false when we are at the first half of the signal. | ||
// If it is true, then we are actually at the beginning of the first set bit. | ||
|
||
if(protocol->encoded_polarity) { | ||
memset(protocol->encoded_data, 0, INSTAFOB_ENCODED_DATA_SIZE_BYTES); | ||
bit_lib_push_bit(protocol->encoded_data, INSTAFOB_ENCODED_DATA_SIZE_BYTES, 1); | ||
} | ||
|
||
// Mark that we read the first half of signal | ||
protocol->encoded_polarity = true; | ||
} | ||
|
||
return decoded_signal; | ||
}; | ||
|
||
bool protocol_insta_fob_encoder_start(ProtocolInstaFob* protocol) { | ||
uint32_t block1 = bit_lib_get_bits_32(protocol->data, 0, 32); | ||
if(block1 != INSTAFOB_BLOCK1) { | ||
FURI_LOG_E( | ||
TAG, | ||
"Block 1 has wrong data (%08lx). Updating to %08lx.", | ||
block1, | ||
(uint32_t)INSTAFOB_BLOCK1); | ||
|
||
bit_lib_num_to_bytes_be(INSTAFOB_BLOCK1, 4, protocol->data); | ||
} | ||
|
||
// You can add parity or other data manipulation here. | ||
|
||
// Set all of our encoded_data bits to zeros. | ||
memset(protocol->encoded_data, 0, INSTAFOB_ENCODED_DATA_SIZE_BYTES); | ||
|
||
// Copy the data to the beginning of our data onto the encoded_data | ||
bit_lib_copy_bits( | ||
protocol->encoded_data, 0, 8 * INSTAFOB_DECODED_DATA_SIZE_BYTES, protocol->data, 0); | ||
|
||
// Note: For sending we start at bit 0. | ||
protocol->encoded_data_index = 0; | ||
protocol->encoded_polarity = true; | ||
protocol->encoded_term_state = ProtocolInstaFobSeqTermNone; | ||
|
||
return true; | ||
} | ||
|
||
LevelDuration protocol_insta_fob_encoder_yield(ProtocolInstaFob* protocol) { | ||
bool level = bit_lib_get_bit(protocol->encoded_data, protocol->encoded_data_index); | ||
uint32_t duration_cycles = INSTAFOB_CLOCK_PER_BIT / 2; | ||
|
||
if(protocol->encoded_term_state == ProtocolInstaFobSeqTermNone) { | ||
if(protocol->encoded_polarity) { | ||
protocol->encoded_polarity = false; | ||
} else { | ||
level = !level; | ||
|
||
protocol->encoded_polarity = true; | ||
protocol->encoded_data_index++; | ||
if(protocol->encoded_data_index == (INSTAFOB_ENCODED_DATA_SIZE_BITS - 1)) { | ||
// Next yield call will be the start of the sequence terminator. | ||
protocol->encoded_term_state = ProtocolInstaFobSeqTermS1; | ||
} | ||
} | ||
} else { | ||
// States 1-2 will send a "1" bit. This is what I observed on the ProxMark3. | ||
// States 3-4 will send a "." bit due to invalid duration (Really long high then short low). | ||
// States 5-6 will send a "." bit due to invalid duration (A long high). | ||
if(protocol->encoded_term_state == ProtocolInstaFobSeqTermS1) { | ||
level = true; | ||
} else if(protocol->encoded_term_state == ProtocolInstaFobSeqTermS2) { | ||
level = !true; | ||
} else if(protocol->encoded_term_state == ProtocolInstaFobSeqTermS3) { | ||
level = true; | ||
duration_cycles = INSTAFOB_CLOCK_PER_BIT * 50 / 32; | ||
} else if(protocol->encoded_term_state == ProtocolInstaFobSeqTermS4) { | ||
level = false; | ||
} else if(protocol->encoded_term_state == ProtocolInstaFobSeqTermS5) { | ||
level = true; | ||
} else if(protocol->encoded_term_state == ProtocolInstaFobSeqTermS6) { | ||
level = true; | ||
} | ||
|
||
// Move to the next state. | ||
protocol->encoded_term_state++; | ||
|
||
if(protocol->encoded_term_state == ProtocolInstaFobSeqTermSMax) { | ||
// We are sending the end of the sequence terminator. | ||
// Set variables so next yield call will send the first half of the first bit. | ||
protocol->encoded_term_state = ProtocolInstaFobSeqTermNone; | ||
protocol->encoded_data_index = 0; | ||
protocol->encoded_polarity = true; | ||
} | ||
} | ||
|
||
return level_duration_make(level, duration_cycles); | ||
}; | ||
|
||
void protocol_insta_fob_render_data(ProtocolInstaFob* protocol, FuriString* result) { | ||
furi_string_printf( | ||
result, | ||
"InstaFob\nBlk[1]: %08lX\nBlk[2]: %08lX", | ||
bit_lib_get_bits_32(protocol->data, 0, 32), | ||
bit_lib_get_bits_32(protocol->data, 32, 32)); | ||
}; | ||
|
||
void protocol_insta_fob_render_brief_data(ProtocolInstaFob* protocol, FuriString* result) { | ||
furi_string_printf( | ||
result, | ||
"Fob %08lX %08lX", | ||
bit_lib_get_bits_32(protocol->data, 0, 32), | ||
bit_lib_get_bits_32(protocol->data, 32, 32)); | ||
}; | ||
|
||
bool protocol_insta_fob_write_data(ProtocolInstaFob* protocol, void* data) { | ||
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; | ||
bool result = false; | ||
|
||
// Encode data | ||
protocol_insta_fob_encoder_start(protocol); | ||
|
||
if(request->write_type == LFRFIDWriteTypeT5577) { | ||
request->t5577.block[0] = | ||
(LFRFID_T5577_MODULATION_MANCHESTER | LFRFID_T5577_BITRATE_RF_32 | | ||
LFRFID_T5577_ST_TERMINATOR | (7 << LFRFID_T5577_MAXBLOCK_SHIFT)); | ||
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); | ||
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); | ||
// Clear the rest of the blocks | ||
for(int i = 3; i < 8; i++) { | ||
request->t5577.block[i] = 0; | ||
} | ||
request->t5577.blocks_to_write = 8; | ||
result = true; | ||
|
||
FURI_LOG_D( | ||
TAG, | ||
"block[0]: %08lx block[1]: %08lx block[2]: %08lx", | ||
request->t5577.block[0], | ||
request->t5577.block[1], | ||
request->t5577.block[2]); | ||
} | ||
return result; | ||
}; | ||
|
||
const ProtocolBase protocol_insta_fob = { | ||
.name = "InstaFob", | ||
.manufacturer = "Hillman Group", | ||
.data_size = INSTAFOB_DECODED_DATA_SIZE_BYTES, | ||
.features = LFRFIDFeatureASK, | ||
.validate_count = 3, | ||
.alloc = (ProtocolAlloc)protocol_insta_fob_alloc, | ||
.free = (ProtocolFree)protocol_insta_fob_free, | ||
.get_data = (ProtocolGetData)protocol_insta_fob_get_data, | ||
.decoder = | ||
{ | ||
.start = (ProtocolDecoderStart)protocol_insta_fob_decoder_start, | ||
.feed = (ProtocolDecoderFeed)protocol_insta_fob_decoder_feed, | ||
}, | ||
.encoder = | ||
{ | ||
.start = (ProtocolEncoderStart)protocol_insta_fob_encoder_start, | ||
.yield = (ProtocolEncoderYield)protocol_insta_fob_encoder_yield, | ||
}, | ||
.render_data = (ProtocolRenderData)protocol_insta_fob_render_data, | ||
.render_brief_data = (ProtocolRenderData)protocol_insta_fob_render_brief_data, | ||
.write_data = (ProtocolWriteData)protocol_insta_fob_write_data, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#pragma once | ||
#include <toolbox/protocols/protocol.h> | ||
|
||
extern const ProtocolBase protocol_insta_fob; |