I discovered a problem with dwt_isr() in deca_device.c that people should be aware of.
The scenario is a program that is about to transmit a frame and doesn’t want an interrupt until the response arrives so it uses dwt_setinterrupt() to only enable receive frame interrupts and then calls dwt_starttx() with the DWT_RESPONSE_EXPECTED flag. When a receive interrupt arrives execution passes to dwt_isr(). dwt_isr() reads the SYS_STATUS register to see what interrupts have occurred but it doesn’t apply the SYS_MASK register so as well as invoking the application’s cbRxOk handler it also calls the cbTxDone handler. To make matters worse it calls them in that order so it looks like the receive happened before the transmit when it was actually the other way round.
The specific problem I had was that in the setup as described above my cbRxOk handler was setting up the transmit of the final frame in the 4 frame TWR exchange and I wanted a transmit interrupt to know when the final frame had gone. So the cbRxOk handler set the variables to indicate that the next transmit interrupt would be for the frame about to be sent. But immediately on return from the cbRxOk handler dwt_isr() made that rogue cbTxDone handler call and my code thought the frame had already been sent.