Skip to content

Commit

Permalink
[SX127x] Handle multiple IRQ flags (#1190)
Browse files Browse the repository at this point in the history
  • Loading branch information
jgromes committed Sep 28, 2024
1 parent 5d076f6 commit 38fc7a9
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 32 deletions.
5 changes: 5 additions & 0 deletions src/TypeDef.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,11 @@
*/
#define RADIOLIB_ERR_NULL_POINTER (-28)

/*!
\brief The requested IRQ configuration is not valid for this module.
*/
#define RADIOLIB_ERR_INVALID_IRQ (-29)

// RF69-specific status codes

/*!
Expand Down
125 changes: 93 additions & 32 deletions src/modules/SX127x/SX127x.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1314,43 +1314,104 @@ uint32_t SX127x::getIrqFlags() {

int16_t SX127x::setIrqFlags(uint32_t irq) {
// this is a bit convoluted, but unfortunately SX127x IRQ flags are not used to enable/disable that IRQ ...
// in addition, the configuration is often mutually exclusive, so we iterate over the set bits in a loop
uint8_t usedPinFlags = 0;
bool conflict = false;
int16_t modem = getActiveModem();
if(modem == RADIOLIB_SX127X_LORA) {
switch(irq) {
case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE):
return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6));
case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE):
return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_RX_DONE, 7, 6));
case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER):
return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO3_LORA_VALID_HEADER, 1, 0));
case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR):
return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO3_LORA_PAYLOAD_CRC_ERROR, 1, 0));
case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE):
return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_CAD_DONE, 7, 6));
case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED):
return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED, 5, 4));
case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT):
return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT, 5, 4));
int16_t state;
for(uint8_t i = 0; i <= 31; i++) {
// check if the bit is set
uint32_t irqBit = irq & (1UL << i);
if(!irqBit) {
continue;
}
return(RADIOLIB_ERR_UNSUPPORTED);

} else if(modem == RADIOLIB_SX127X_FSK_OOK) {
switch(irq) {
case(RADIOLIB_SX127X_FLAG_PACKET_SENT << 8):
return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6));
case(RADIOLIB_SX127X_FLAG_PAYLOAD_READY << 8):
return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY, 7, 6));
case(RADIOLIB_SX127X_FLAG_PREAMBLE_DETECT << 0):
return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, RADIOLIB_SX127X_DIO4_PACK_RSSI_PREAMBLE_DETECT, 7, 6));
case(RADIOLIB_SX127X_FLAG_SYNC_ADDRESS_MATCH << 0):
return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO2_PACK_SYNC_ADDRESS, 3, 2));
case(RADIOLIB_SX127X_FLAG_TIMEOUT << 0):
return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO2_PACK_TIMEOUT, 3, 2));

// if not, decode it
uint8_t dioNum = 0; // DIO pin number and register value to set (address and MSB/LSB can be inferred)
uint8_t regVal = 0;
if(modem == RADIOLIB_SX127X_LORA) {
switch(irqBit) {
case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE):
dioNum = 0;
regVal = RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT;
break;
case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE):
dioNum = 0;
regVal = RADIOLIB_SX127X_DIO0_LORA_RX_DONE;
break;
case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER):
dioNum = 3;
regVal = RADIOLIB_SX127X_DIO3_LORA_VALID_HEADER;
break;
case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR):
dioNum = 3;
regVal = RADIOLIB_SX127X_DIO3_LORA_PAYLOAD_CRC_ERROR;
break;
case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE):
dioNum = 0;
regVal = RADIOLIB_SX127X_DIO0_LORA_CAD_DONE;
break;
case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED):
dioNum = 1;
regVal = RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED;
break;
case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT):
dioNum = 1;
regVal = RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT;
break;
default:
return(RADIOLIB_ERR_UNSUPPORTED);
}

} else if(modem == RADIOLIB_SX127X_FSK_OOK) {
switch(irqBit) {
case(RADIOLIB_SX127X_FLAG_PACKET_SENT << 8):
dioNum = 0;
regVal = RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT;
break;
case(RADIOLIB_SX127X_FLAG_PAYLOAD_READY << 8):
dioNum = 0;
regVal = RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY;
break;
case(RADIOLIB_SX127X_FLAG_PREAMBLE_DETECT << 0):
dioNum = 4;
regVal = RADIOLIB_SX127X_DIO4_PACK_RSSI_PREAMBLE_DETECT;
break;
case(RADIOLIB_SX127X_FLAG_SYNC_ADDRESS_MATCH << 0):
dioNum = 2;
regVal = RADIOLIB_SX127X_DIO2_PACK_SYNC_ADDRESS;
break;
case(RADIOLIB_SX127X_FLAG_TIMEOUT << 0):
dioNum = 2;
regVal = RADIOLIB_SX127X_DIO2_PACK_TIMEOUT;
break;
default:
return(RADIOLIB_ERR_UNSUPPORTED);
}
}
return(RADIOLIB_ERR_UNSUPPORTED);

// check if this DIO pin has been set already
if(usedPinFlags & (1UL << dioNum)) {
// uh oh, this pin is used!
RADIOLIB_DEBUG_PRINTLN("Unable to set IRQ %04x on DIO%d due to conflict!", irqBit, (int)dioNum);
conflict = true;
continue;
}

// DIO pin is unused, set the flag and configure it
usedPinFlags |= (1UL << dioNum);
uint8_t addr = (dioNum > 3) ? RADIOLIB_SX127X_REG_DIO_MAPPING_1 : RADIOLIB_SX127X_REG_DIO_MAPPING_2;
uint8_t msb = 7 - 2*(dioNum % 4);
state = this->mod->SPIsetRegValue(addr, regVal, msb, msb - 1);
RADIOLIB_ASSERT(state);
}

return(RADIOLIB_ERR_UNSUPPORTED);
// if there was at least one conflict, this flag is set
if(conflict) {
return(RADIOLIB_ERR_INVALID_IRQ);
}

return(state);
}

int16_t SX127x::clearIrqFlags(uint32_t irq) {
Expand Down
4 changes: 4 additions & 0 deletions src/modules/SX127x/SX127x.h
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,10 @@ class SX127x: public PhysicalLayer {

/*!
\brief Set interrupt on DIO1 to be sent on a specific IRQ bit (e.g. RxTimeout, CadDone).
NOTE: Unlike other modules that support IRQ abstraction (SX126x, LR11x0, etc.),
SX127x cannot configure multiple IRQs to signal using the same DIOx pin.
This method tries to configure IRQs in a "best effort" approach, and will skip conflicting flags.
RADIOLIB_ERR_INVALID_IRQ will be returned in this case.
\param irq Module-specific IRQ flags.
\returns \ref status_codes
*/
Expand Down

0 comments on commit 38fc7a9

Please sign in to comment.