#include #include #include #include #include #include #define FURI_HAL_IBUTTON_TIMER TIM1 #define FURI_HAL_IBUTTON_TIMER_IRQ FuriHalInterruptIdTim1UpTim16 typedef enum { FuriHalIbuttonStateIdle, FuriHalIbuttonStateRunning, } FuriHalIbuttonState; typedef struct { FuriHalIbuttonState state; FuriHalIbuttonEmulateCallback callback; void* context; } FuriHalIbutton; FuriHalIbutton* furi_hal_ibutton = NULL; static void furi_hal_ibutton_emulate_isr() { if(LL_TIM_IsActiveFlag_UPDATE(FURI_HAL_IBUTTON_TIMER)) { LL_TIM_ClearFlag_UPDATE(FURI_HAL_IBUTTON_TIMER); furi_hal_ibutton->callback(furi_hal_ibutton->context); } } void furi_hal_ibutton_init() { furi_hal_ibutton = malloc(sizeof(FuriHalIbutton)); furi_hal_ibutton->state = FuriHalIbuttonStateIdle; } void furi_hal_ibutton_emulate_start( uint32_t period, FuriHalIbuttonEmulateCallback callback, void* context) { furi_assert(furi_hal_ibutton); furi_assert(furi_hal_ibutton->state == FuriHalIbuttonStateIdle); furi_hal_ibutton->state = FuriHalIbuttonStateRunning; furi_hal_ibutton->callback = callback; furi_hal_ibutton->context = context; FURI_CRITICAL_ENTER(); LL_TIM_DeInit(FURI_HAL_IBUTTON_TIMER); FURI_CRITICAL_EXIT(); furi_hal_interrupt_set_isr(FURI_HAL_IBUTTON_TIMER_IRQ, furi_hal_ibutton_emulate_isr, NULL); LL_TIM_SetPrescaler(FURI_HAL_IBUTTON_TIMER, 0); LL_TIM_SetCounterMode(FURI_HAL_IBUTTON_TIMER, LL_TIM_COUNTERMODE_UP); LL_TIM_SetAutoReload(FURI_HAL_IBUTTON_TIMER, period); LL_TIM_DisableARRPreload(FURI_HAL_IBUTTON_TIMER); LL_TIM_SetRepetitionCounter(FURI_HAL_IBUTTON_TIMER, 0); LL_TIM_SetClockDivision(FURI_HAL_IBUTTON_TIMER, LL_TIM_CLOCKDIVISION_DIV1); LL_TIM_SetClockSource(FURI_HAL_IBUTTON_TIMER, LL_TIM_CLOCKSOURCE_INTERNAL); LL_TIM_GenerateEvent_UPDATE(FURI_HAL_IBUTTON_TIMER); LL_TIM_EnableIT_UPDATE(FURI_HAL_IBUTTON_TIMER); LL_TIM_EnableCounter(FURI_HAL_IBUTTON_TIMER); } void furi_hal_ibutton_emulate_set_next(uint32_t period) { LL_TIM_SetAutoReload(FURI_HAL_IBUTTON_TIMER, period); } void furi_hal_ibutton_emulate_stop() { furi_assert(furi_hal_ibutton); if(furi_hal_ibutton->state == FuriHalIbuttonStateRunning) { furi_hal_ibutton->state = FuriHalIbuttonStateIdle; LL_TIM_DisableCounter(FURI_HAL_IBUTTON_TIMER); FURI_CRITICAL_ENTER(); LL_TIM_DeInit(FURI_HAL_IBUTTON_TIMER); FURI_CRITICAL_EXIT(); furi_hal_interrupt_set_isr(FURI_HAL_IBUTTON_TIMER_IRQ, NULL, NULL); furi_hal_ibutton->callback = NULL; furi_hal_ibutton->context = NULL; } } void furi_hal_ibutton_start_drive() { furi_hal_ibutton_pin_high(); furi_hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); } void furi_hal_ibutton_start_drive_in_isr() { furi_hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); LL_EXTI_ClearFlag_0_31(ibutton_gpio.pin); } void furi_hal_ibutton_start_interrupt() { furi_hal_ibutton_pin_high(); furi_hal_gpio_init(&ibutton_gpio, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow); } void furi_hal_ibutton_start_interrupt_in_isr() { furi_hal_gpio_init(&ibutton_gpio, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow); LL_EXTI_ClearFlag_0_31(ibutton_gpio.pin); } void furi_hal_ibutton_stop() { furi_hal_ibutton_pin_high(); furi_hal_gpio_init(&ibutton_gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } void furi_hal_ibutton_add_interrupt(GpioExtiCallback cb, void* context) { furi_hal_gpio_add_int_callback(&ibutton_gpio, cb, context); } void furi_hal_ibutton_remove_interrupt() { furi_hal_gpio_remove_int_callback(&ibutton_gpio); } void furi_hal_ibutton_pin_low() { furi_hal_gpio_write(&ibutton_gpio, false); } void furi_hal_ibutton_pin_high() { furi_hal_gpio_write(&ibutton_gpio, true); } bool furi_hal_ibutton_pin_get_level() { return furi_hal_gpio_read(&ibutton_gpio); }