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.
This commit is contained in:
gornekich
2023-10-24 07:08:09 +04:00
committed by GitHub
parent 35c903494c
commit d92b0a82cc
514 changed files with 41488 additions and 68125 deletions
+20
View File
@@ -0,0 +1,20 @@
Import("env")
env.Append(
CPPPATH=[
"#/lib/signal_reader",
],
SDK_HEADERS=[
File("signal_reader.h"),
],
)
libenv = env.Clone(FW_LIB_NAME="signal_reader")
libenv.ApplyLibFlags()
libenv.Append(CCFLAGS=["-O3", "-funroll-loops", "-Ofast"])
sources = libenv.GlobRecursive("*.c*")
lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources)
libenv.Install("${LIB_DIST_DIR}", lib)
Return("lib")
@@ -0,0 +1,300 @@
#include "iso15693_parser.h"
#include <toolbox/bit_buffer.h>
#include <furi/furi.h>
#define ISO15693_PARSER_SIGNAL_READER_BUFF_SIZE (2)
#define ISO15693_PARSER_BITSTREAM_BUFF_SIZE (32)
#define ISO15693_PARSER_BITRATE_F64MHZ (603U)
#define TAG "Iso15693Parser"
typedef enum {
Iso15693ParserStateParseSoF,
Iso15693ParserStateParseFrame,
Iso15693ParserStateFail,
} Iso15693ParserState;
typedef enum {
Iso15693ParserMode1OutOf4,
Iso15693ParserMode1OutOf256,
Iso15693ParserModeNum,
} Iso15693ParserMode;
struct Iso15693Parser {
Iso15693ParserState state;
Iso15693ParserMode mode;
SignalReader* signal_reader;
uint8_t bitstream_buff[ISO15693_PARSER_BITSTREAM_BUFF_SIZE];
size_t bitstream_idx;
uint8_t last_byte;
bool signal_detected;
bool bit_offset_calculated;
uint8_t bit_offset;
size_t byte_idx;
size_t bytes_to_process;
uint8_t next_byte;
uint16_t next_byte_part;
bool zero_found;
BitBuffer* parsed_frame;
bool eof_received;
bool frame_parsed;
Iso15693ParserCallback callback;
void* context;
};
typedef enum {
Iso15693ParserCommandProcessed,
Iso15693ParserCommandWaitData,
Iso15693ParserCommandFail,
Iso15693ParserCommandSuccess,
} Iso15693ParserCommand;
typedef Iso15693ParserCommand (*Iso15693ParserStateHandler)(Iso15693Parser* instance);
Iso15693Parser* iso15693_parser_alloc(const GpioPin* pin, size_t max_frame_size) {
Iso15693Parser* instance = malloc(sizeof(Iso15693Parser));
instance->parsed_frame = bit_buffer_alloc(max_frame_size);
instance->signal_reader = signal_reader_alloc(pin, ISO15693_PARSER_SIGNAL_READER_BUFF_SIZE);
signal_reader_set_sample_rate(
instance->signal_reader, SignalReaderTimeUnit64Mhz, ISO15693_PARSER_BITRATE_F64MHZ);
signal_reader_set_pull(instance->signal_reader, GpioPullDown);
signal_reader_set_polarity(instance->signal_reader, SignalReaderPolarityInverted);
signal_reader_set_trigger(instance->signal_reader, SignalReaderTriggerRisingFallingEdge);
return instance;
}
void iso15693_parser_free(Iso15693Parser* instance) {
furi_assert(instance);
bit_buffer_free(instance->parsed_frame);
signal_reader_free(instance->signal_reader);
free(instance);
}
void iso15693_parser_reset(Iso15693Parser* instance) {
furi_assert(instance);
instance->state = Iso15693ParserStateParseSoF;
instance->mode = Iso15693ParserMode1OutOf4;
memset(instance->bitstream_buff, 0x00, sizeof(instance->bitstream_buff));
instance->bitstream_idx = 0;
instance->next_byte = 0;
instance->next_byte_part = 0;
instance->bit_offset = 0;
instance->byte_idx = 0;
instance->bytes_to_process = 0;
instance->signal_detected = false;
instance->bit_offset_calculated = false;
instance->last_byte = 0x00;
instance->zero_found = false;
instance->eof_received = false;
bit_buffer_reset(instance->parsed_frame);
instance->frame_parsed = false;
}
static void signal_reader_callback(SignalReaderEvent event, void* context) {
furi_assert(context);
furi_assert(event.data->data);
furi_assert(event.data->len == ISO15693_PARSER_SIGNAL_READER_BUFF_SIZE / 2);
Iso15693Parser* instance = context;
furi_assert(instance->callback);
const uint8_t sof_1_out_of_4 = 0x21;
const uint8_t sof_1_out_of_256 = 0x81;
const uint8_t eof_single = 0x01;
const uint8_t eof = 0x04;
if(instance->state == Iso15693ParserStateParseSoF) {
if(event.data->data[0] == sof_1_out_of_4) {
instance->mode = Iso15693ParserMode1OutOf4;
instance->state = Iso15693ParserStateParseFrame;
} else if(event.data->data[0] == sof_1_out_of_256) {
instance->mode = Iso15693ParserMode1OutOf256;
instance->state = Iso15693ParserStateParseFrame;
} else if(event.data->data[0] == eof_single) {
instance->eof_received = true;
instance->callback(Iso15693ParserEventDataReceived, instance->context);
} else {
instance->state = Iso15693ParserStateFail;
instance->callback(Iso15693ParserEventDataReceived, instance->context);
}
} else {
if(instance->mode == Iso15693ParserMode1OutOf4) {
if(event.data->data[0] == eof) {
instance->eof_received = true;
instance->callback(Iso15693ParserEventDataReceived, instance->context);
} else {
instance->bitstream_buff[instance->bytes_to_process] = event.data->data[0];
instance->bytes_to_process++;
if(instance->bytes_to_process == ISO15693_PARSER_BITSTREAM_BUFF_SIZE) {
instance->callback(Iso15693ParserEventDataReceived, instance->context);
}
}
} else {
instance->bitstream_buff[instance->bytes_to_process] = event.data->data[0];
instance->bytes_to_process++;
if(instance->bytes_to_process == ISO15693_PARSER_BITSTREAM_BUFF_SIZE) {
instance->callback(Iso15693ParserEventDataReceived, instance->context);
}
}
}
}
static void iso15693_parser_start_signal_reader(Iso15693Parser* instance) {
iso15693_parser_reset(instance);
signal_reader_start(instance->signal_reader, signal_reader_callback, instance);
}
void iso15693_parser_start(
Iso15693Parser* instance,
Iso15693ParserCallback callback,
void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
iso15693_parser_start_signal_reader(instance);
}
void iso15693_parser_stop(Iso15693Parser* instance) {
furi_assert(instance);
signal_reader_stop(instance->signal_reader);
}
static Iso15693ParserCommand iso15693_parser_parse_1_out_of_4(Iso15693Parser* instance) {
Iso15693ParserCommand command = Iso15693ParserCommandWaitData;
const uint8_t bit_patterns_1_out_of_4[] = {0x02, 0x08, 0x20, 0x80};
for(size_t i = 0; i < instance->bytes_to_process; i++) {
// Check next pattern
size_t j = 0;
for(j = 0; j < COUNT_OF(bit_patterns_1_out_of_4); j++) {
if(instance->bitstream_buff[i] == bit_patterns_1_out_of_4[j]) {
instance->next_byte |= j << (instance->next_byte_part * 2);
instance->next_byte_part++;
if(instance->next_byte_part == 4) {
instance->next_byte_part = 0;
bit_buffer_append_byte(instance->parsed_frame, instance->next_byte);
instance->next_byte = 0;
}
break;
}
}
if(j == COUNT_OF(bit_patterns_1_out_of_4)) {
command = Iso15693ParserCommandFail;
break;
}
}
if(command != Iso15693ParserCommandFail) {
if(instance->eof_received) {
command = Iso15693ParserCommandSuccess;
instance->frame_parsed = true;
}
}
instance->bytes_to_process = 0;
return command;
}
static Iso15693ParserCommand iso15693_parser_parse_1_out_of_256(Iso15693Parser* instance) {
Iso15693ParserCommand command = Iso15693ParserCommandWaitData;
const uint8_t eof = 0x04;
for(size_t i = instance->byte_idx; i < instance->bytes_to_process; i++) {
// Check EoF
if(instance->next_byte_part == 0) {
if(instance->bitstream_buff[i] == eof) {
instance->frame_parsed = true;
command = Iso15693ParserCommandSuccess;
break;
}
}
if(instance->zero_found) {
if(instance->bitstream_buff[i] != 0x00) {
command = Iso15693ParserCommandFail;
break;
}
} else {
if(instance->bitstream_buff[i] != 0x00) {
for(size_t j = 0; j < 8; j++) {
if(FURI_BIT(instance->bitstream_buff[i], j) == 1) {
bit_buffer_append_byte(
instance->parsed_frame, instance->next_byte_part * 4 + j / 2);
}
}
}
}
instance->next_byte_part = (instance->next_byte_part + 1) % 64;
}
instance->bytes_to_process = 0;
instance->byte_idx = 0;
return command;
}
static const Iso15693ParserStateHandler iso15693_parser_state_handlers[Iso15693ParserModeNum] = {
[Iso15693ParserMode1OutOf4] = iso15693_parser_parse_1_out_of_4,
[Iso15693ParserMode1OutOf256] = iso15693_parser_parse_1_out_of_256,
};
bool iso15693_parser_run(Iso15693Parser* instance) {
if(instance->state == Iso15693ParserStateFail) {
iso15693_parser_stop(instance);
iso15693_parser_start_signal_reader(instance);
} else if((instance->state == Iso15693ParserStateParseSoF) && (instance->eof_received)) {
instance->frame_parsed = true;
} else if(instance->bytes_to_process) {
Iso15693ParserCommand command = Iso15693ParserCommandProcessed;
while(command == Iso15693ParserCommandProcessed) {
command = iso15693_parser_state_handlers[instance->mode](instance);
}
if(command == Iso15693ParserCommandFail) {
iso15693_parser_stop(instance);
iso15693_parser_start_signal_reader(instance);
FURI_LOG_D(TAG, "Frame parse failed");
}
}
return instance->frame_parsed;
}
size_t iso15693_parser_get_data_size_bytes(Iso15693Parser* instance) {
furi_assert(instance);
return bit_buffer_get_size_bytes(instance->parsed_frame);
}
void iso15693_parser_get_data(
Iso15693Parser* instance,
uint8_t* buff,
size_t buff_size,
size_t* data_bits) {
furi_assert(instance);
furi_assert(buff);
furi_assert(data_bits);
bit_buffer_write_bytes(instance->parsed_frame, buff, buff_size);
*data_bits = bit_buffer_get_size(instance->parsed_frame);
}
@@ -0,0 +1,42 @@
#pragma once
#include "../../signal_reader.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct Iso15693Parser Iso15693Parser;
typedef enum {
Iso15693ParserEventDataReceived,
} Iso15693ParserEvent;
typedef void (*Iso15693ParserCallback)(Iso15693ParserEvent event, void* context);
Iso15693Parser* iso15693_parser_alloc(const GpioPin* pin, size_t max_frame_size);
void iso15693_parser_free(Iso15693Parser* instance);
void iso15693_parser_reset(Iso15693Parser* instance);
void iso15693_parser_start(
Iso15693Parser* instance,
Iso15693ParserCallback callback,
void* context);
void iso15693_parser_stop(Iso15693Parser* instance);
bool iso15693_parser_run(Iso15693Parser* instance);
size_t iso15693_parser_get_data_size_bytes(Iso15693Parser* instance);
void iso15693_parser_get_data(
Iso15693Parser* instance,
uint8_t* buff,
size_t buff_size,
size_t* data_bits);
#ifdef __cplusplus
}
#endif
+317
View File
@@ -0,0 +1,317 @@
#include "signal_reader.h"
#include <limits.h>
#include <furi.h>
#include <furi_hal.h>
#include <furi_hal_gpio.h>
#include <stm32wbxx_ll_dma.h>
#include <stm32wbxx_ll_dmamux.h>
#include <stm32wbxx_ll_tim.h>
#include <stm32wbxx_ll_exti.h>
#include <furi_hal_bus.h>
#define SIGNAL_READER_DMA DMA2
#define SIGNAL_READER_CAPTURE_TIM (TIM16)
#define SIGNAL_READER_CAPTURE_TIM_CHANNEL LL_TIM_CHANNEL_CH1
#define SIGNAL_READER_DMA_GPIO LL_DMA_CHANNEL_2
#define SIGNAL_READER_DMA_GPIO_IRQ FuriHalInterruptIdDma2Ch2
#define SIGNAL_READER_DMA_GPIO_DEF SIGNAL_READER_DMA, SIGNAL_READER_DMA_GPIO
#define SIGNAL_READER_DMA_TRIGGER LL_DMA_CHANNEL_3
#define SIGNAL_READER_DMA_TRIGGER_IRQ FuriHalInterruptIdDma2Ch3
#define SIGNAL_READER_DMA_TRIGGER_DEF SIGNAL_READER_DMA, SIGNAL_READER_DMA_TRIGGER
#define SIGNAL_READER_DMA_CNT_SYNC LL_DMA_CHANNEL_5
#define SIGNAL_READER_DMA_CNT_SYNC_IRQ FuriHalInterruptIdDma2Ch5
#define SIGNAL_READER_DMA_CNT_SYNC_DEF SIGNAL_READER_DMA, SIGNAL_READER_DMA_CNT_SYNC
struct SignalReader {
size_t buffer_size;
const GpioPin* pin;
GpioPull pull;
SignalReaderPolarity polarity;
SignalReaderTrigger trigger;
uint16_t* gpio_buffer;
uint8_t* bitstream_buffer;
uint32_t cnt_en;
uint32_t tim_cnt_compensation;
uint32_t tim_arr;
SignalReaderEvent event;
SignalReaderEventData event_data;
SignalReaderCallback callback;
void* context;
};
#define GPIO_PIN_MAP(pin, prefix) \
(((pin) == (LL_GPIO_PIN_0)) ? prefix##0 : \
((pin) == (LL_GPIO_PIN_1)) ? prefix##1 : \
((pin) == (LL_GPIO_PIN_2)) ? prefix##2 : \
((pin) == (LL_GPIO_PIN_3)) ? prefix##3 : \
((pin) == (LL_GPIO_PIN_4)) ? prefix##4 : \
((pin) == (LL_GPIO_PIN_5)) ? prefix##5 : \
((pin) == (LL_GPIO_PIN_6)) ? prefix##6 : \
((pin) == (LL_GPIO_PIN_7)) ? prefix##7 : \
((pin) == (LL_GPIO_PIN_8)) ? prefix##8 : \
((pin) == (LL_GPIO_PIN_9)) ? prefix##9 : \
((pin) == (LL_GPIO_PIN_10)) ? prefix##10 : \
((pin) == (LL_GPIO_PIN_11)) ? prefix##11 : \
((pin) == (LL_GPIO_PIN_12)) ? prefix##12 : \
((pin) == (LL_GPIO_PIN_13)) ? prefix##13 : \
((pin) == (LL_GPIO_PIN_14)) ? prefix##14 : \
prefix##15)
#define GET_DMAMUX_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_DMAMUX_REQ_GEN_EXTI_LINE)
SignalReader* signal_reader_alloc(const GpioPin* gpio_pin, uint32_t size) {
SignalReader* instance = malloc(sizeof(SignalReader));
instance->pin = gpio_pin;
instance->pull = GpioPullNo;
instance->buffer_size = size;
instance->gpio_buffer = malloc(sizeof(uint16_t) * size * 8);
instance->bitstream_buffer = malloc(size);
instance->event.data = &instance->event_data;
return instance;
}
void signal_reader_free(SignalReader* instance) {
furi_assert(instance);
furi_assert(instance->gpio_buffer);
furi_assert(instance->bitstream_buffer);
free(instance->gpio_buffer);
free(instance->bitstream_buffer);
free(instance);
}
void signal_reader_set_pull(SignalReader* instance, GpioPull pull) {
furi_assert(instance);
instance->pull = pull;
}
void signal_reader_set_polarity(SignalReader* instance, SignalReaderPolarity polarity) {
furi_assert(instance);
instance->polarity = polarity;
}
void signal_reader_set_sample_rate(
SignalReader* instance,
SignalReaderTimeUnit time_unit,
uint32_t time) {
furi_assert(instance);
UNUSED(time_unit);
instance->tim_arr = time;
}
void signal_reader_set_trigger(SignalReader* instance, SignalReaderTrigger trigger) {
furi_assert(instance);
instance->trigger = trigger;
}
static void furi_hal_sw_digital_pin_dma_rx_isr(void* context) {
SignalReader* instance = context;
uint16_t* gpio_buff_start = NULL;
uint8_t* bitstream_buff_start = NULL;
if(LL_DMA_IsActiveFlag_HT2(SIGNAL_READER_DMA)) {
LL_DMA_ClearFlag_HT2(SIGNAL_READER_DMA);
instance->event.type = SignalReaderEventTypeHalfBufferFilled;
gpio_buff_start = instance->gpio_buffer;
bitstream_buff_start = instance->bitstream_buffer;
if(instance->callback) {
furi_assert(gpio_buff_start);
furi_assert(bitstream_buff_start);
for(size_t i = 0; i < instance->buffer_size * 4; i++) {
if((i % 8) == 0) {
bitstream_buff_start[i / 8] = 0;
}
uint8_t bit = 0;
if(instance->polarity == SignalReaderPolarityNormal) {
bit = (gpio_buff_start[i] & instance->pin->pin) == instance->pin->pin;
} else {
bit = (gpio_buff_start[i] & instance->pin->pin) == 0;
}
bitstream_buff_start[i / 8] |= bit << (i % 8);
}
instance->event_data.data = bitstream_buff_start;
instance->event_data.len = instance->buffer_size / 2;
instance->callback(instance->event, instance->context);
}
}
if(LL_DMA_IsActiveFlag_TC2(SIGNAL_READER_DMA)) {
LL_DMA_ClearFlag_TC2(SIGNAL_READER_DMA);
instance->event.type = SignalReaderEventTypeFullBufferFilled;
gpio_buff_start = &instance->gpio_buffer[instance->buffer_size * 4];
bitstream_buff_start = &instance->bitstream_buffer[instance->buffer_size / 2];
if(instance->callback) {
furi_assert(gpio_buff_start);
furi_assert(bitstream_buff_start);
for(size_t i = 0; i < instance->buffer_size * 4; i++) {
if((i % 8) == 0) {
bitstream_buff_start[i / 8] = 0;
}
uint8_t bit = 0;
if(instance->polarity == SignalReaderPolarityNormal) {
bit = (gpio_buff_start[i] & instance->pin->pin) == instance->pin->pin;
} else {
bit = (gpio_buff_start[i] & instance->pin->pin) == 0;
}
bitstream_buff_start[i / 8] |= bit << (i % 8);
}
instance->event_data.data = bitstream_buff_start;
instance->event_data.len = instance->buffer_size / 2;
instance->callback(instance->event, instance->context);
}
}
}
void signal_reader_start(SignalReader* instance, SignalReaderCallback callback, void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
// EXTI delay compensation
instance->tim_cnt_compensation = 9;
instance->cnt_en = SIGNAL_READER_CAPTURE_TIM->CR1;
instance->cnt_en |= TIM_CR1_CEN;
furi_hal_bus_enable(FuriHalBusTIM16);
// Capture timer config
LL_TIM_SetPrescaler(SIGNAL_READER_CAPTURE_TIM, 0);
LL_TIM_SetCounterMode(SIGNAL_READER_CAPTURE_TIM, LL_TIM_COUNTERMODE_UP);
LL_TIM_SetAutoReload(SIGNAL_READER_CAPTURE_TIM, instance->tim_arr);
LL_TIM_SetClockDivision(SIGNAL_READER_CAPTURE_TIM, LL_TIM_CLOCKDIVISION_DIV1);
LL_TIM_DisableARRPreload(SIGNAL_READER_CAPTURE_TIM);
LL_TIM_SetClockSource(SIGNAL_READER_CAPTURE_TIM, LL_TIM_CLOCKSOURCE_INTERNAL);
// Configure TIM channel CC1
LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {};
TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_FROZEN;
TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE;
TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE;
TIM_OC_InitStruct.CompareValue = (instance->tim_arr / 2);
TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH;
LL_TIM_OC_Init(
SIGNAL_READER_CAPTURE_TIM, SIGNAL_READER_CAPTURE_TIM_CHANNEL, &TIM_OC_InitStruct);
LL_TIM_OC_DisableFast(SIGNAL_READER_CAPTURE_TIM, SIGNAL_READER_CAPTURE_TIM_CHANNEL);
LL_TIM_SetTriggerOutput(SIGNAL_READER_CAPTURE_TIM, LL_TIM_TRGO_RESET);
LL_TIM_DisableMasterSlaveMode(SIGNAL_READER_CAPTURE_TIM);
// Start
LL_TIM_GenerateEvent_UPDATE(SIGNAL_READER_CAPTURE_TIM);
/* We need the EXTI to be configured as interrupt generating line, but no ISR registered */
furi_hal_gpio_init(
instance->pin, GpioModeInterruptRiseFall, instance->pull, GpioSpeedVeryHigh);
/* Set DMAMUX request generation signal ID on specified DMAMUX channel */
LL_DMAMUX_SetRequestSignalID(
DMAMUX1, LL_DMAMUX_REQ_GEN_0, GET_DMAMUX_EXTI_LINE(instance->pin->pin));
/* Set the polarity of the signal on which the DMA request is generated */
LL_DMAMUX_SetRequestGenPolarity(DMAMUX1, LL_DMAMUX_REQ_GEN_0, LL_DMAMUX_REQ_GEN_POL_RISING);
/* Set the number of DMA requests that will be authorized after a generation event */
LL_DMAMUX_SetGenRequestNb(DMAMUX1, LL_DMAMUX_REQ_GEN_0, 1);
// Configure DMA Sync
LL_DMA_SetMemoryAddress(
SIGNAL_READER_DMA_CNT_SYNC_DEF, (uint32_t)&instance->tim_cnt_compensation);
LL_DMA_SetPeriphAddress(
SIGNAL_READER_DMA_CNT_SYNC_DEF, (uint32_t) & (SIGNAL_READER_CAPTURE_TIM->CNT));
LL_DMA_ConfigTransfer(
SIGNAL_READER_DMA_CNT_SYNC_DEF,
LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT |
LL_DMA_MEMORY_NOINCREMENT | LL_DMA_PDATAALIGN_HALFWORD | LL_DMA_MDATAALIGN_HALFWORD |
LL_DMA_PRIORITY_VERYHIGH);
LL_DMA_SetDataLength(SIGNAL_READER_DMA_CNT_SYNC_DEF, 1);
LL_DMA_SetPeriphRequest(SIGNAL_READER_DMA_CNT_SYNC_DEF, LL_DMAMUX_REQ_GENERATOR0);
// Configure DMA Sync
LL_DMA_SetMemoryAddress(SIGNAL_READER_DMA_TRIGGER_DEF, (uint32_t)&instance->cnt_en);
LL_DMA_SetPeriphAddress(
SIGNAL_READER_DMA_TRIGGER_DEF, (uint32_t) & (SIGNAL_READER_CAPTURE_TIM->CR1));
LL_DMA_ConfigTransfer(
SIGNAL_READER_DMA_TRIGGER_DEF,
LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_NOINCREMENT |
LL_DMA_PDATAALIGN_HALFWORD | LL_DMA_MDATAALIGN_HALFWORD | LL_DMA_PRIORITY_VERYHIGH);
LL_DMA_SetDataLength(SIGNAL_READER_DMA_TRIGGER_DEF, 1);
LL_DMA_SetPeriphRequest(SIGNAL_READER_DMA_TRIGGER_DEF, LL_DMAMUX_REQ_GENERATOR0);
// Configure DMA Rx pin
LL_DMA_SetMemoryAddress(SIGNAL_READER_DMA_GPIO_DEF, (uint32_t)instance->gpio_buffer);
LL_DMA_SetPeriphAddress(SIGNAL_READER_DMA_GPIO_DEF, (uint32_t) & (instance->pin->port->IDR));
LL_DMA_ConfigTransfer(
SIGNAL_READER_DMA_GPIO_DEF,
LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT |
LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_HALFWORD | LL_DMA_MDATAALIGN_HALFWORD |
LL_DMA_PRIORITY_HIGH);
LL_DMA_SetDataLength(SIGNAL_READER_DMA_GPIO_DEF, instance->buffer_size * 8);
LL_DMA_SetPeriphRequest(SIGNAL_READER_DMA_GPIO_DEF, LL_DMAMUX_REQ_TIM16_CH1);
// Configure DMA Channel CC1
LL_TIM_EnableDMAReq_CC1(SIGNAL_READER_CAPTURE_TIM);
LL_TIM_CC_EnableChannel(SIGNAL_READER_CAPTURE_TIM, SIGNAL_READER_CAPTURE_TIM_CHANNEL);
// Start DMA irq, higher priority than normal
furi_hal_interrupt_set_isr_ex(
SIGNAL_READER_DMA_GPIO_IRQ, 14, furi_hal_sw_digital_pin_dma_rx_isr, instance);
// Start DMA Sync timer
LL_DMA_EnableChannel(SIGNAL_READER_DMA_CNT_SYNC_DEF);
// Start DMA Rx pin
LL_DMA_EnableChannel(SIGNAL_READER_DMA_GPIO_DEF);
// Strat timer
LL_TIM_SetCounter(SIGNAL_READER_CAPTURE_TIM, 0);
if(instance->trigger == SignalReaderTriggerNone) {
LL_TIM_EnableCounter(SIGNAL_READER_CAPTURE_TIM);
} else {
LL_DMA_EnableChannel(SIGNAL_READER_DMA_TRIGGER_DEF);
}
LL_DMAMUX_EnableRequestGen(DMAMUX1, LL_DMAMUX_REQ_GEN_0);
// Need to clear flags before enabling DMA !!!!
if(LL_DMA_IsActiveFlag_TC2(SIGNAL_READER_DMA)) LL_DMA_ClearFlag_TC1(SIGNAL_READER_DMA);
if(LL_DMA_IsActiveFlag_TE2(SIGNAL_READER_DMA)) LL_DMA_ClearFlag_TE1(SIGNAL_READER_DMA);
LL_DMA_EnableIT_TC(SIGNAL_READER_DMA_GPIO_DEF);
LL_DMA_EnableIT_HT(SIGNAL_READER_DMA_GPIO_DEF);
}
void signal_reader_stop(SignalReader* instance) {
furi_assert(instance);
furi_hal_interrupt_set_isr(SIGNAL_READER_DMA_GPIO_IRQ, NULL, NULL);
// Deinit DMA Rx pin
LL_DMA_DeInit(SIGNAL_READER_DMA_GPIO_DEF);
// Deinit DMA Sync timer
LL_DMA_DeInit(SIGNAL_READER_DMA_CNT_SYNC_DEF);
// Deinit DMA Trigger timer
LL_DMA_DeInit(SIGNAL_READER_DMA_TRIGGER_DEF);
furi_hal_bus_disable(FuriHalBusTIM16);
}
+67
View File
@@ -0,0 +1,67 @@
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <furi_hal_gpio.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
SignalReaderEventTypeHalfBufferFilled,
SignalReaderEventTypeFullBufferFilled,
} SignalReaderEventType;
typedef struct {
uint8_t* data;
size_t len;
} SignalReaderEventData;
typedef struct {
SignalReaderEventType type;
SignalReaderEventData* data;
} SignalReaderEvent;
typedef enum {
SignalReaderTimeUnit64Mhz,
} SignalReaderTimeUnit;
typedef enum {
SignalReaderPolarityNormal,
SignalReaderPolarityInverted,
} SignalReaderPolarity;
typedef enum {
SignalReaderTriggerNone,
SignalReaderTriggerRisingFallingEdge,
} SignalReaderTrigger;
typedef void (*SignalReaderCallback)(SignalReaderEvent event, void* context);
typedef struct SignalReader SignalReader;
SignalReader* signal_reader_alloc(const GpioPin* gpio_pin, uint32_t size);
void signal_reader_free(SignalReader* instance);
void signal_reader_set_pull(SignalReader* instance, GpioPull pull);
void signal_reader_set_polarity(SignalReader* instance, SignalReaderPolarity polarity);
void signal_reader_set_sample_rate(
SignalReader* instance,
SignalReaderTimeUnit time_unit,
uint32_t time);
void signal_reader_set_trigger(SignalReader* instance, SignalReaderTrigger trigger);
void signal_reader_start(SignalReader* instance, SignalReaderCallback callback, void* context);
void signal_reader_stop(SignalReader* instance);
#ifdef __cplusplus
}
#endif