|
| 1 | +// TODO: License headers, include guards, etc. |
| 2 | +// TODO: Where should this live? Maybe in its own library? |
| 3 | +#pragma once |
| 4 | + |
| 5 | +#include <functional> |
| 6 | +#include <stdint.h> |
| 7 | +#include <SPI.h> |
| 8 | + |
| 9 | +extern "C" void SUBGHZ_Radio_IRQHandler(); |
| 10 | + |
| 11 | +/** |
| 12 | + * Singleton class to manage the SubGHZ ISR and internal signals |
| 13 | + */ |
| 14 | +class SubGhzClass { |
| 15 | + public: |
| 16 | + using callback_function_t = std::function<void(void)>; |
| 17 | + |
| 18 | + // Attach the passed handler to be called (from ISR context) when |
| 19 | + // the radio IRQ triggers, then clear any pending IRQs and enable |
| 20 | + // it. |
| 21 | + // |
| 22 | + // Note that the radio IRQ is *level* triggered, so the callback |
| 23 | + // should either disable directly process the IRQ and clear the IRQ |
| 24 | + // flags in the radio (so the radio module clears its DIO lines |
| 25 | + // before the ISR returns), or the callback should disable the IRQ |
| 26 | + // to prevent it from being triggered over and over again. |
| 27 | + void attachInterrupt(callback_function_t callback); |
| 28 | + |
| 29 | + // Detach the interrupt handler, disabling the IRQ too. |
| 30 | + void detachInterrupt(); |
| 31 | + |
| 32 | + // Return whether an interrupt callback is currently attached |
| 33 | + bool hasInterrupt(); |
| 34 | + |
| 35 | + // Enable the interrupt agani if it was previously disabled using |
| 36 | + // disableInterrupt(). This does *not* clear any pending interrupts, |
| 37 | + // so if the IRQ was triggered while it was disabled, this will |
| 38 | + // cause the callback (previously registered with attachInterrupt) |
| 39 | + // to fire directly. |
| 40 | + void enableInterrupt(); |
| 41 | + |
| 42 | + // Temporarily disable interrupt processing by disabling the IRQ in |
| 43 | + // the NVIC. |
| 44 | + void disableInterrupt(); |
| 45 | + |
| 46 | + // Clear the interrupt pending flag (to suppress an IRQs that |
| 47 | + // happened while the interrupt was disabled). |
| 48 | + void clearPendingInterrupt(); |
| 49 | + |
| 50 | + // Returns whether the interrupt is currently pending (useful when |
| 51 | + // the interrupt is disabled, or while some higher priority |
| 52 | + // interrupt is currently running). |
| 53 | + bool isInterruptPending(); |
| 54 | + |
| 55 | + // Update the NSS signal that is internally connected to the radio |
| 56 | + // SPI block. |
| 57 | + // This signal is active-low, so passing LOW activates |
| 58 | + // the block, HIGH deactivates it. |
| 59 | + // TODO: Should this just pass a bool and be inverted? |
| 60 | + void writeNSS(uint32_t value); |
| 61 | + |
| 62 | + // Read back the value written to NSS |
| 63 | + uint32_t readNSS(); |
| 64 | + |
| 65 | + // Update the RESET signal that is internally connected to the |
| 66 | + // radio. |
| 67 | + // This signal is active-low, so passing LOW resets the radio and |
| 68 | + // HIGH releases it. |
| 69 | + // TODO: Should this just pass a bool and be inverted? |
| 70 | + void writeReset(uint32_t value); |
| 71 | + |
| 72 | + // Read back the value written to RESET |
| 73 | + uint32_t readReset(); |
| 74 | + |
| 75 | + // Return the state of busy signal exported by the radio module. |
| 76 | + // Returns HIGH when busy, or LOW when idle. |
| 77 | + // TODO: Should this just return a bool? |
| 78 | + uint32_t readBusy(); |
| 79 | + |
| 80 | + // The SPI object that can be used to talk to the radio. Works |
| 81 | + // like regular SPI objects, except that writeNSS() above must be |
| 82 | + // used to controll the (internal) NSS "pin". |
| 83 | + SUBGHZSPIClass SPI; |
| 84 | + |
| 85 | + protected: |
| 86 | + // To access handleIrq() |
| 87 | + friend void SUBGHZ_Radio_IRQHandler(); |
| 88 | + void handleIrq(); |
| 89 | + |
| 90 | + private: |
| 91 | + callback_function_t callback; |
| 92 | +}; |
| 93 | + |
| 94 | +// Singleton instance, no other instances should be created |
| 95 | +extern SubGhzClass SubGhz; |
0 commit comments