flipperzero-firmware/lib/ST25RFAL002/source/st25r3916/st25r3916_irq.c
あく 389ff92cc1
Naming and coding style convention, new linter tool. (#945)
* Makefile, Scripts: new linter
* About: remove ID from IC
* Firmware: remove double define for DIVC/DIVR
* Scripts: check folder names too. Docker: replace syntax check with make lint.
* Reformat Sources and Migrate to new file naming convention
* Docker: symlink clang-format-12 to clang-format
* Add coding style guide
2022-01-05 19:10:18 +03:00

232 lines
7.6 KiB
C

/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
*
* Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* www.st.com/myliberty
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
* AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*
* PROJECT: ST25R3916 firmware
* Revision:
* LANGUAGE: ISO C99
*/
/*! \file
*
* \author Gustavo Patricio
*
* \brief ST25R3916 Interrupt handling
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "st25r3916_irq.h"
#include "st25r3916_com.h"
#include "st25r3916_led.h"
#include "st25r3916.h"
#include "utils.h"
/*
******************************************************************************
* LOCAL DATA TYPES
******************************************************************************
*/
/*! Holds current and previous interrupt callback pointer as well as current Interrupt status and mask */
typedef struct {
void (*prevCallback)(void); /*!< call back function for ST25R3916 interrupt */
void (*callback)(void); /*!< call back function for ST25R3916 interrupt */
uint32_t status; /*!< latest interrupt status */
uint32_t mask; /*!< Interrupt mask. Negative mask = ST25R3916 mask regs */
} st25r3916Interrupt;
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
/*! Length of the interrupt registers */
#define ST25R3916_INT_REGS_LEN ((ST25R3916_REG_IRQ_TARGET - ST25R3916_REG_IRQ_MAIN) + 1U)
/*
******************************************************************************
* GLOBAL VARIABLES
******************************************************************************
*/
static volatile st25r3916Interrupt st25r3916interrupt; /*!< Instance of ST25R3916 interrupt */
/*
******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************
*/
void st25r3916InitInterrupts(void) {
platformIrqST25RPinInitialize();
platformIrqST25RSetCallback(st25r3916Isr);
st25r3916interrupt.callback = NULL;
st25r3916interrupt.prevCallback = NULL;
st25r3916interrupt.status = ST25R3916_IRQ_MASK_NONE;
st25r3916interrupt.mask = ST25R3916_IRQ_MASK_NONE;
}
/*******************************************************************************/
void st25r3916Isr(void) {
st25r3916CheckForReceivedInterrupts();
// Check if callback is set and run it
if(NULL != st25r3916interrupt.callback) {
st25r3916interrupt.callback();
}
}
/*******************************************************************************/
void st25r3916CheckForReceivedInterrupts(void) {
uint8_t iregs[ST25R3916_INT_REGS_LEN];
uint32_t irqStatus;
/* Initialize iregs */
irqStatus = ST25R3916_IRQ_MASK_NONE;
ST_MEMSET(iregs, (int32_t)(ST25R3916_IRQ_MASK_ALL & 0xFFU), ST25R3916_INT_REGS_LEN);
/* In case the IRQ is Edge (not Level) triggered read IRQs until done */
while(platformGpioIsHigh(ST25R_INT_PORT, ST25R_INT_PIN)) {
st25r3916ReadMultipleRegisters(ST25R3916_REG_IRQ_MAIN, iregs, ST25R3916_INT_REGS_LEN);
irqStatus |= (uint32_t)iregs[0];
irqStatus |= (uint32_t)iregs[1] << 8;
irqStatus |= (uint32_t)iregs[2] << 16;
irqStatus |= (uint32_t)iregs[3] << 24;
}
/* Forward all interrupts, even masked ones to application */
platformProtectST25RIrqStatus();
st25r3916interrupt.status |= irqStatus;
platformUnprotectST25RIrqStatus();
/* Send an IRQ event to LED handling */
st25r3916ledEvtIrq(st25r3916interrupt.status);
}
/*******************************************************************************/
void st25r3916ModifyInterrupts(uint32_t clr_mask, uint32_t set_mask) {
uint8_t i;
uint32_t old_mask;
uint32_t new_mask;
old_mask = st25r3916interrupt.mask;
new_mask = ((~old_mask & set_mask) | (old_mask & clr_mask));
st25r3916interrupt.mask &= ~clr_mask;
st25r3916interrupt.mask |= set_mask;
for(i = 0; i < ST25R3916_INT_REGS_LEN; i++) {
if(((new_mask >> (8U * i)) & 0xFFU) == 0U) {
continue;
}
st25r3916WriteRegister(
ST25R3916_REG_IRQ_MASK_MAIN + i,
(uint8_t)((st25r3916interrupt.mask >> (8U * i)) & 0xFFU));
}
return;
}
/*******************************************************************************/
uint32_t st25r3916WaitForInterruptsTimed(uint32_t mask, uint16_t tmo) {
uint32_t tmrDelay;
uint32_t status;
tmrDelay = platformTimerCreate(tmo);
/* Run until specific interrupt has happen or the timer has expired */
do {
status = (st25r3916interrupt.status & mask);
} while((!platformTimerIsExpired(tmrDelay) || (tmo == 0U)) && (status == 0U));
platformTimerDestroy(tmrDelay);
status = st25r3916interrupt.status & mask;
platformProtectST25RIrqStatus();
st25r3916interrupt.status &= ~status;
platformUnprotectST25RIrqStatus();
return status;
}
/*******************************************************************************/
uint32_t st25r3916GetInterrupt(uint32_t mask) {
uint32_t irqs;
irqs = (st25r3916interrupt.status & mask);
if(irqs != ST25R3916_IRQ_MASK_NONE) {
platformProtectST25RIrqStatus();
st25r3916interrupt.status &= ~irqs;
platformUnprotectST25RIrqStatus();
}
return irqs;
}
/*******************************************************************************/
void st25r3916ClearAndEnableInterrupts(uint32_t mask) {
st25r3916GetInterrupt(mask);
st25r3916EnableInterrupts(mask);
}
/*******************************************************************************/
void st25r3916EnableInterrupts(uint32_t mask) {
st25r3916ModifyInterrupts(mask, 0);
}
/*******************************************************************************/
void st25r3916DisableInterrupts(uint32_t mask) {
st25r3916ModifyInterrupts(0, mask);
}
/*******************************************************************************/
void st25r3916ClearInterrupts(void) {
uint8_t iregs[ST25R3916_INT_REGS_LEN];
st25r3916ReadMultipleRegisters(ST25R3916_REG_IRQ_MAIN, iregs, ST25R3916_INT_REGS_LEN);
platformProtectST25RIrqStatus();
st25r3916interrupt.status = ST25R3916_IRQ_MASK_NONE;
platformUnprotectST25RIrqStatus();
return;
}
/*******************************************************************************/
void st25r3916IRQCallbackSet(void (*cb)(void)) {
st25r3916interrupt.prevCallback = st25r3916interrupt.callback;
st25r3916interrupt.callback = cb;
}
/*******************************************************************************/
void st25r3916IRQCallbackRestore(void) {
st25r3916interrupt.callback = st25r3916interrupt.prevCallback;
st25r3916interrupt.prevCallback = NULL;
}