unleashed-firmware/lib/digital_signal/presets/nfc/iso15693_signal.c
gornekich d92b0a82cc
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring.

Starring:

- @gornekich - NFC refactoring project lead, architect, senior developer
- @gsurkov - architect, senior developer
- @RebornedBrain - senior developer

Supporting roles:

- @skotopes, @DrZlo13, @hedger - general architecture advisors, code review
- @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance

Special thanks:

@bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
2023-10-24 12:08:09 +09:00

205 lines
7.2 KiB
C

#include "iso15693_signal.h"
#include <digital_signal/digital_sequence.h>
#define BITS_IN_BYTE (8U)
#define ISO15693_SIGNAL_COEFF_HI (1U)
#define ISO15693_SIGNAL_COEFF_LO (4U)
#define ISO15693_SIGNAL_ZERO_EDGES (16U)
#define ISO15693_SIGNAL_ONE_EDGES (ISO15693_SIGNAL_ZERO_EDGES + 1U)
#define ISO15693_SIGNAL_EOF_EDGES (64U)
#define ISO15693_SIGNAL_SOF_EDGES (ISO15693_SIGNAL_EOF_EDGES + 1U)
#define ISO15693_SIGNAL_EDGES (1350U)
#define ISO15693_SIGNAL_FC (13.56e6)
#define ISO15693_SIGNAL_FC_16 (16.0e11 / ISO15693_SIGNAL_FC)
#define ISO15693_SIGNAL_FC_256 (256.0e11 / ISO15693_SIGNAL_FC)
#define ISO15693_SIGNAL_FC_768 (768.0e11 / ISO15693_SIGNAL_FC)
typedef enum {
Iso15693SignalIndexSof,
Iso15693SignalIndexEof,
Iso15693SignalIndexOne,
Iso15693SignalIndexZero,
Iso15693SignalIndexNum,
} Iso15693SignalIndex;
typedef DigitalSignal* Iso15693SignalBank[Iso15693SignalIndexNum];
struct Iso15693Signal {
DigitalSequence* tx_sequence;
Iso15693SignalBank banks[Iso15693SignalDataRateNum];
};
// Add an unmodulated signal for the length of Fc / 256 * k (where k = 1 or 4)
static void iso15693_add_silence(DigitalSignal* signal, Iso15693SignalDataRate data_rate) {
const uint32_t k = data_rate == Iso15693SignalDataRateHi ? ISO15693_SIGNAL_COEFF_HI :
ISO15693_SIGNAL_COEFF_LO;
digital_signal_add_period_with_level(signal, ISO15693_SIGNAL_FC_256 * k, false);
}
// Add 8 * k subcarrier pulses of Fc / 16 (where k = 1 or 4)
static void iso15693_add_subcarrier(DigitalSignal* signal, Iso15693SignalDataRate data_rate) {
const uint32_t k = data_rate == Iso15693SignalDataRateHi ? ISO15693_SIGNAL_COEFF_HI :
ISO15693_SIGNAL_COEFF_LO;
for(uint32_t i = 0; i < ISO15693_SIGNAL_ZERO_EDGES * k; ++i) {
digital_signal_add_period_with_level(signal, ISO15693_SIGNAL_FC_16, !(i % 2));
}
}
static void iso15693_add_bit(DigitalSignal* signal, Iso15693SignalDataRate data_rate, bool bit) {
if(bit) {
iso15693_add_silence(signal, data_rate);
iso15693_add_subcarrier(signal, data_rate);
} else {
iso15693_add_subcarrier(signal, data_rate);
iso15693_add_silence(signal, data_rate);
}
}
static inline void iso15693_add_sof(DigitalSignal* signal, Iso15693SignalDataRate data_rate) {
// Not adding silence since it only increases response time
for(uint32_t i = 0; i < ISO15693_SIGNAL_FC_768 / ISO15693_SIGNAL_FC_256; ++i) {
iso15693_add_subcarrier(signal, data_rate);
}
iso15693_add_bit(signal, data_rate, true);
}
static inline void iso15693_add_eof(DigitalSignal* signal, Iso15693SignalDataRate data_rate) {
iso15693_add_bit(signal, data_rate, false);
for(uint32_t i = 0; i < ISO15693_SIGNAL_FC_768 / ISO15693_SIGNAL_FC_256; ++i) {
iso15693_add_subcarrier(signal, data_rate);
}
// Not adding silence since it does nothing here
}
static inline uint32_t
iso15693_get_sequence_index(Iso15693SignalIndex index, Iso15693SignalDataRate data_rate) {
return index + data_rate * Iso15693SignalIndexNum;
}
static inline void
iso15693_add_byte(Iso15693Signal* instance, Iso15693SignalDataRate data_rate, uint8_t byte) {
for(size_t i = 0; i < BITS_IN_BYTE; i++) {
const uint8_t bit = byte & (1U << i);
digital_sequence_add_signal(
instance->tx_sequence,
iso15693_get_sequence_index(
bit ? Iso15693SignalIndexOne : Iso15693SignalIndexZero, data_rate));
}
}
static inline void iso15693_signal_encode(
Iso15693Signal* instance,
Iso15693SignalDataRate data_rate,
const uint8_t* tx_data,
size_t tx_data_size) {
digital_sequence_add_signal(
instance->tx_sequence, iso15693_get_sequence_index(Iso15693SignalIndexSof, data_rate));
for(size_t i = 0; i < tx_data_size; i++) {
iso15693_add_byte(instance, data_rate, tx_data[i]);
}
digital_sequence_add_signal(
instance->tx_sequence, iso15693_get_sequence_index(Iso15693SignalIndexEof, data_rate));
}
static void iso15693_signal_bank_fill(Iso15693Signal* instance, Iso15693SignalDataRate data_rate) {
const uint32_t k = data_rate == Iso15693SignalDataRateHi ? ISO15693_SIGNAL_COEFF_HI :
ISO15693_SIGNAL_COEFF_LO;
DigitalSignal** bank = instance->banks[data_rate];
bank[Iso15693SignalIndexSof] = digital_signal_alloc(ISO15693_SIGNAL_SOF_EDGES * k);
bank[Iso15693SignalIndexEof] = digital_signal_alloc(ISO15693_SIGNAL_EOF_EDGES * k);
bank[Iso15693SignalIndexOne] = digital_signal_alloc(ISO15693_SIGNAL_ONE_EDGES * k);
bank[Iso15693SignalIndexZero] = digital_signal_alloc(ISO15693_SIGNAL_ZERO_EDGES * k);
iso15693_add_sof(bank[Iso15693SignalIndexSof], data_rate);
iso15693_add_eof(bank[Iso15693SignalIndexEof], data_rate);
iso15693_add_bit(bank[Iso15693SignalIndexOne], data_rate, true);
iso15693_add_bit(bank[Iso15693SignalIndexZero], data_rate, false);
}
static void
iso15693_signal_bank_clear(Iso15693Signal* instance, Iso15693SignalDataRate data_rate) {
DigitalSignal** bank = instance->banks[data_rate];
for(uint32_t i = 0; i < Iso15693SignalIndexNum; ++i) {
digital_signal_free(bank[i]);
}
}
static void
iso15693_signal_bank_register(Iso15693Signal* instance, Iso15693SignalDataRate data_rate) {
for(uint32_t i = 0; i < Iso15693SignalIndexNum; ++i) {
digital_sequence_register_signal(
instance->tx_sequence,
iso15693_get_sequence_index(i, data_rate),
instance->banks[data_rate][i]);
}
}
Iso15693Signal* iso15693_signal_alloc(const GpioPin* pin) {
furi_assert(pin);
Iso15693Signal* instance = malloc(sizeof(Iso15693Signal));
instance->tx_sequence = digital_sequence_alloc(BITS_IN_BYTE * 255 + 2, pin);
for(uint32_t i = 0; i < Iso15693SignalDataRateNum; ++i) {
iso15693_signal_bank_fill(instance, i);
iso15693_signal_bank_register(instance, i);
}
return instance;
}
void iso15693_signal_free(Iso15693Signal* instance) {
furi_assert(instance);
digital_sequence_free(instance->tx_sequence);
for(uint32_t i = 0; i < Iso15693SignalDataRateNum; ++i) {
iso15693_signal_bank_clear(instance, i);
}
free(instance);
}
void iso15693_signal_tx(
Iso15693Signal* instance,
Iso15693SignalDataRate data_rate,
const uint8_t* tx_data,
size_t tx_data_size) {
furi_assert(instance);
furi_assert(data_rate < Iso15693SignalDataRateNum);
furi_assert(tx_data);
FURI_CRITICAL_ENTER();
digital_sequence_clear(instance->tx_sequence);
iso15693_signal_encode(instance, data_rate, tx_data, tx_data_size);
digital_sequence_transmit(instance->tx_sequence);
FURI_CRITICAL_EXIT();
}
void iso15693_signal_tx_sof(Iso15693Signal* instance, Iso15693SignalDataRate data_rate) {
furi_assert(instance);
furi_assert(data_rate < Iso15693SignalDataRateNum);
FURI_CRITICAL_ENTER();
digital_sequence_clear(instance->tx_sequence);
digital_sequence_add_signal(
instance->tx_sequence, iso15693_get_sequence_index(Iso15693SignalIndexSof, data_rate));
digital_sequence_transmit(instance->tx_sequence);
FURI_CRITICAL_EXIT();
}