Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of EV-COG-AD3029LZ by
Diff: stm-spirit1-rf-driver/SimpleSpirit1.h
- Revision:
- 34:edda6a7238ec
- Child:
- 37:bc043030b55a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/stm-spirit1-rf-driver/SimpleSpirit1.h Tue Nov 22 11:40:10 2016 +0100
@@ -0,0 +1,467 @@
+/*** Mbed Includes ***/
+#include "mbed.h"
+#include "mbed_debug.h"
+
+
+/*** Cube Includes ***/
+#include "SPIRIT_Radio.h"
+#include "SPIRIT_Management.h"
+#include "SPIRIT_Commands.h"
+#include "MCU_Interface.h"
+
+
+/*** Contiki Lib Includes ***/
+#include "spirit1.h"
+#include "spirit1-config.h"
+#include "spirit1-const.h"
+
+
+// betzw: enable beyond macro if you want debug messages also from IRQ handler
+#define DEBUG_IRQ
+
+
+/*** Macros from Cube Implementation ***/
+#define CLEAR_TXBUF() (spirit_tx_len = 0)
+#define IS_RXBUF_EMPTY() (spirit_rx_len == 0)
+#define CLEAR_RXBUF() do { \
+ spirit_rx_len = 0; \
+ _spirit_rx_pos = 0; \
+ } while(0)
+
+
+/*** Macros from Cube Implementation ***/
+/* transceiver state. */
+#define ON 0
+#define OFF 1
+
+
+/*** Missing Cube External Declarations ***/
+extern "C" void SpiritManagementSetFrequencyBase(uint32_t);
+
+
+/*** UnlockedSPI for Performance (due to singleton) ***/
+class UnlockedSPI : public SPI {
+public:
+ UnlockedSPI(PinName mosi, PinName miso, PinName sclk) :
+ SPI(mosi, miso, sclk) { }
+ virtual ~UnlockedSPI() {}
+ virtual void lock() { }
+ virtual void unlock() { }
+};
+
+
+/*** A Simple Spirit1 Class ***/
+// NOTE: must be a singleton (due to mix of MBED/CUBE code)!!!
+// NOTE: implementation is IRQ-save but (intentionally) NOT thread-safe!!!
+class SimpleSpirit1 {
+ protected:
+ static SimpleSpirit1 *_singleton;
+
+ /** Communication Interface Instance Variables **/
+ UnlockedSPI _spi; // betzw - NOTE: Arduino pins are valid only for NUCLEO-F401RE
+ // mosi: PA_7 (D11)
+ // miso: PA_6 (D12)
+ // sclk: PB_3 (D3) or
+ // PA_5 (D13) (only in case you unmount R4 & mount R7,
+ // (note: in this case you may not use LED1 on some platforms)
+ // bits: 8-bit
+ // mode: 0
+ // ordr: MSB
+ // freq: max 10MHz
+ InterruptIn _irq; // PC_7 (D9) (falling)
+ DigitalOut _chip_select; // PB_6 (D10) ('1' == chip unselected)
+ DigitalOut _shut_down; // PA_10 (D2) ('1' == shut_down)
+ DigitalOut _led; // PB_4 (D5) (optional)
+
+ Callback<void(int)> _current_irq_callback;
+ Timeout _rx_receiving_timeout;
+
+ void rx_timeout_handler(void) {
+ set_ready_state();
+ cmd_strobe(SPIRIT1_STROBE_RX);
+#ifdef DEBUG_IRQ
+ debug("\n\r%s (%d)\n\r", __func__, __LINE__);
+#endif
+ }
+
+ void start_rx_timeout(void) {
+ _rx_receiving_timeout.attach_us(Callback<void()>(this, &SimpleSpirit1::rx_timeout_handler), 500 * 1000); // 500ms
+ }
+
+ void stop_rx_timeout(void) {
+ _rx_receiving_timeout.detach();
+ }
+
+ /** Static Variables from Cube Implementation **/
+ /*
+ * The buffers which hold incoming data.
+ * The +1 because of the first byte,
+ * which will contain the length of the packet.
+ */
+ volatile uint16_t spirit_tx_len;
+ volatile bool _spirit_tx_started;
+ volatile uint16_t spirit_rx_len;
+ volatile uint16_t _spirit_rx_pos;
+ volatile bool _spirit_rx_err;
+ uint8_t spirit_rx_buf[MAX_PACKET_LEN];
+ volatile bool _is_receiving;
+
+ /** Status Variables from Cube Implementation **/
+ unsigned int spirit_on;
+ uint8_t last_rssi; //MGR
+ uint8_t last_sqi; //MGR
+
+ /** Low Level Instance Variables **/
+ unsigned int _nr_of_irq_disables;
+
+ /** Low Level Instance Methods **/
+ void disable_spirit_irq(void) {
+ _irq.disable_irq();
+ _nr_of_irq_disables++;
+#ifndef NDEBUG
+ debug_if(_nr_of_irq_disables == 0, "\n\rassert failed in: %s (%d)\n\r", __func__, __LINE__);
+#endif
+ }
+
+ void enable_spirit_irq(void) {
+#ifndef NDEBUG
+ debug_if(_nr_of_irq_disables == 0, "\n\rassert failed in: %s (%d)\n\r", __func__, __LINE__);
+#endif
+ if(--_nr_of_irq_disables == 0)
+ _irq.enable_irq();
+ }
+
+ void chip_select() { _chip_select = 0; }
+ void chip_unselect() { _chip_select = 1; }
+
+ void enter_shutdown() {
+ _shut_down = 1;
+ wait_ms(5); // wait 5 milliseconds (to allow Spirit1 to shut down)
+ }
+
+ void exit_shutdown() {
+ _shut_down = 0;
+ wait_ms(10); // wait 10 milliseconds (to allow Spirit1 a proper boot-up sequence)
+ }
+
+ void cs_to_sclk_delay(void) {
+ wait_us(1); // heuristic value
+ }
+
+ /**
+ * @brief Write and read a buffer to/from the SPI peripheral device at the same time
+ * in 8-bit data mode using synchronous SPI communication.
+ * @param[in] pBufferToWrite pointer to the buffer of data to send.
+ * @param[out] pBufferToRead pointer to the buffer to read data into.
+ * @param[in] NumBytes number of bytes to read and write.
+ * @retval 0 if ok.
+ * @retval -1 if data format error.
+ * @note When using the SPI in Interrupt-mode, remember to disable interrupts
+ * before calling this function and to enable them again after.
+ */
+ void spi_write_read(uint8_t* pBufferToWrite, uint8_t* pBufferToRead, uint16_t NumBytes)
+ {
+ /* Read and write data at the same time. */
+ for (int i = 0; i < NumBytes; i++) {
+ pBufferToRead[i] = _spi.write(pBufferToWrite[i]);
+ }
+ }
+
+ /** Radio Instance Methods **/
+ void radio_set_xtal_freq(uint32_t freq) {
+ SpiritRadioSetXtalFrequency(freq);
+ }
+
+ void radio_set_pa_level_dbm(uint8_t cIndex, float fPowerdBm) {
+ SpiritRadioSetPALeveldBm(cIndex, fPowerdBm);
+ }
+
+ void radio_set_pa_level_max_index(uint8_t cIndex) {
+ SpiritRadioSetPALevelMaxIndex(cIndex);
+ }
+
+ uint8_t radio_init(SRadioInit *init_struct) {
+ return SpiritRadioInit(init_struct);
+ }
+
+ void radio_persistent_rx(SpiritFunctionalState xNewState) {
+ SpiritRadioPersistenRx(xNewState);
+ }
+
+ void radio_afc_freeze_on_sync(SpiritFunctionalState xNewState) {
+ SpiritRadioAFCFreezeOnSync(xNewState);
+ }
+
+ /** Packet System Instance Methods **/
+ void pkt_basic_init(PktBasicInit* pxPktBasicInit) {
+ SpiritPktBasicInit(pxPktBasicInit);
+ }
+
+ void pkt_basic_set_payload_length(uint16_t nPayloadLength) {
+ SpiritPktBasicSetPayloadLength(nPayloadLength);
+ }
+
+ uint16_t pkt_basic_get_received_pkt_length(void) {
+ return SpiritPktBasicGetReceivedPktLength();
+ }
+
+ /** IRQ Instance Methods **/
+ void irq_de_init(SpiritIrqs* pxIrqInit) {
+ SpiritIrqDeInit(pxIrqInit);
+ }
+
+ void irq_clear_status(void) {
+ SpiritIrqClearStatus();
+ }
+
+ void irq_set_status(IrqList xIrq, SpiritFunctionalState xNewState) {
+ SpiritIrq(xIrq, xNewState);
+ }
+
+ void irq_get_status(SpiritIrqs* pxIrqStatus) {
+ SpiritIrqGetStatus(pxIrqStatus);
+ }
+
+ /** Management Instance Methods **/
+ void mgmt_set_freq_base(uint32_t freq) {
+ SpiritManagementSetFrequencyBase(freq);
+ }
+
+ void mgmt_refresh_status(void) {
+ SpiritRefreshStatus();
+ }
+
+ /** Spirit GPIO Instance Methods **/
+ void spirit_gpio_init(SGpioInit* pxGpioInitStruct) {
+ SpiritGpioInit(pxGpioInitStruct);
+ }
+
+ /** Qi Instance Methods **/
+ void qi_set_sqi_threshold(SqiThreshold xSqiThr) {
+ SpiritQiSetSqiThreshold(xSqiThr);
+ }
+
+ void qi_sqi_check(SpiritFunctionalState xNewState) {
+ SpiritQiSqiCheck(xNewState);
+ }
+
+ void qi_set_rssi_threshold_dbm(int nDbmValue) {
+ SpiritQiSetRssiThresholddBm(nDbmValue);
+ }
+
+ float qi_get_rssi_dbm() {
+ last_rssi = qi_get_rssi();
+ return get_last_rssi_dbm();
+ }
+
+ uint8_t qi_get_rssi() {
+ return SpiritQiGetRssi();
+ }
+
+ uint8_t qi_get_sqi() {
+ return SpiritQiGetSqi();
+ }
+
+ /** Timer Instance Methods **/
+ void timer_set_rx_timeout_stop_condition(RxTimeoutStopCondition xStopCondition) {
+ SpiritTimerSetRxTimeoutStopCondition(xStopCondition);
+ }
+
+ void timer_set_rx_timeout_counter(uint8_t cCounter) {
+ SpiritTimerSetRxTimeoutCounter(cCounter);
+ }
+
+ void timer_set_infinite_rx_timeout(void) {
+ timer_set_rx_timeout_counter(0);
+ }
+
+ /** CSMA/CA Instance Methods **/
+ void csma_ca_state(SpiritFunctionalState xNewState) {
+ SpiritCsma(xNewState);
+ }
+
+ void csma_ca_init(CsmaInit* pxCsmaInit) {
+ csma_ca_state(S_DISABLE); // Disabled at init
+ SpiritCsmaInit(pxCsmaInit);
+ SpiritCsmaSeedReloadMode(S_DISABLE); // always disable seed reload
+ }
+
+ /** Command Instance Methods**/
+ void cmd_strobe(uint8_t cmd) {
+ SpiritCmdStrobeCommand((SpiritCmd)cmd);
+ }
+
+ void cmd_strobe_flush_rx_fifo() {
+ SpiritCmdStrobeCommand(CMD_FLUSHRXFIFO);
+ }
+
+ /** SPI Instance Methods **/
+ StatusBytes spi_write_linear_fifo(uint8_t cNbBytes, uint8_t* pcBuffer) {
+ return SdkEvalSpiWriteFifo(cNbBytes, pcBuffer);
+ }
+
+ StatusBytes spi_read_linear_fifo(uint8_t cNbBytes, uint8_t* pcBuffer) {
+ return SdkEvalSpiReadFifo(cNbBytes, pcBuffer);
+ }
+
+ /** Linear FIFO Instance Methods **/
+ uint8_t linear_fifo_read_num_elements_rx_fifo(void) {
+ return SpiritLinearFifoReadNumElementsRxFifo();
+ }
+
+ uint8_t linear_fifo_read_num_elements_tx_fifo(void) {
+ return SpiritLinearFifoReadNumElementsTxFifo();
+ }
+
+ void linear_fifo_set_almost_full_thr_rx(uint8_t cThrRxFifo) {
+ SpiritLinearFifoSetAlmostFullThresholdRx(cThrRxFifo);
+ }
+
+ /** Calibration Instance Methods **/
+ void calibration_rco(SpiritFunctionalState xNewState) {
+ SpiritCalibrationRco(xNewState);
+ }
+
+ /** Internal Spirit Methods */
+ void set_ready_state(void);
+ uint8_t refresh_state(void);
+
+ /** Friend Functions **/
+ friend StatusBytes SdkEvalSpiWriteRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer);
+ friend StatusBytes SdkEvalSpiReadRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer);
+ friend StatusBytes SdkEvalSpiCommandStrobes(uint8_t cCommandCode);
+ friend StatusBytes SdkEvalSpiWriteFifo(uint8_t cNbBytes, uint8_t* pcBuffer);
+ friend StatusBytes SdkEvalSpiReadFifo(uint8_t cNbBytes, uint8_t* pcBuffer);
+
+ /** Sdk Instance Methods **/
+ StatusBytes SdkEvalSpiWriteRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer);
+ StatusBytes SdkEvalSpiReadRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer);
+ StatusBytes SdkEvalSpiCommandStrobes(uint8_t cCommandCode);
+ StatusBytes SdkEvalSpiWriteFifo(uint8_t cNbBytes, uint8_t* pcBuffer);
+ StatusBytes SdkEvalSpiReadFifo(uint8_t cNbBytes, uint8_t* pcBuffer);
+
+ /** Helper Instance Methods **/
+ void chip_sync_select() {
+ disable_spirit_irq();
+ chip_select();
+ cs_to_sclk_delay();
+ }
+
+ void chip_sync_unselect() {
+ chip_unselect();
+ enable_spirit_irq();
+ }
+
+ /** Init Instance Method **/
+ void init();
+
+ /** Spirit Irq Callback */
+ void IrqHandler();
+
+ /** Constructor **/
+ SimpleSpirit1(PinName mosi, PinName miso, PinName sclk,
+ PinName irq, PinName cs, PinName sdn,
+ PinName led);
+
+ /** Destructor **/
+ ~SimpleSpirit1(void); // should never be called!
+
+public:
+ enum {
+ RX_DONE,
+ TX_DONE,
+ TX_ERR
+ };
+
+ static SimpleSpirit1& CreateInstance(PinName mosi, PinName miso, PinName sclk,
+ PinName irq, PinName cs, PinName sdn,
+ PinName led = NC) {
+
+ if(_singleton == NULL) {
+ _singleton = new SimpleSpirit1(mosi, miso, sclk,
+ irq, cs, sdn, led);
+ _singleton->init();
+ } else {
+ error("SimpleSpirit1 singleton already created!\n");
+ }
+
+ return *_singleton;
+ }
+
+ static SimpleSpirit1& Instance() {
+ if(_singleton == NULL) {
+ error("SimpleSpirit1 must be created before used!\n");
+ }
+
+ return *_singleton;
+ }
+
+ /** Attach a function to be called by the Spirit Irq handler when packet has arrived
+ *
+ * @param func A void() callback, or 0 to set as none
+ *
+ * @note Function 'func' will be executed in interrupt context!
+ */
+ void attach_irq_callback(Callback<void(int)> func) {
+ _current_irq_callback = func;
+ }
+
+ /** Switch Radio On/Off **/
+ int on(void);
+ int off(void);
+
+ /** Set Channel **/
+ void set_channel(uint8_t channel) {
+ SpiritRadioSetChannel(channel);
+ }
+
+ /** Send a Buffer **/
+ int send(const void *payload, unsigned int payload_len);
+
+ /** Read into Buffer **/
+ int read(void *buf, unsigned int bufsize);
+
+ /** Perform a Clear-Channel Assessment (CCA) to find out if there is
+ a packet in the air or not.
+ Returns 1 if packet has been seen.
+ */
+ int channel_clear(void);
+
+ /** Check if the radio driver has just received a packet **/
+ int get_pending_packet(void);
+
+ /** Is radio currently receiving **/
+ bool is_receiving(void) {
+ return _is_receiving;
+ }
+
+ /** Get latest value of RSSI (in dBm) **/
+ float get_last_rssi_dbm(void) {
+ get_last_rssi_raw();
+ return (-120.0+((float)(last_rssi-20))/2);
+ }
+
+ /** Get latest value of RSSI (as Spirit1 raw value) **/
+ uint8_t get_last_rssi_raw(void) {
+ if(last_rssi == 0) {
+ last_rssi = qi_get_rssi();
+ }
+ return last_rssi;
+ }
+
+ /** Get latest value of LQI (scaled to 8-bit) **/
+ uint8_t get_last_sqi(void) {
+ const uint8_t max_sqi = 8 * ((SYNC_LENGTH>>1)+1);
+ if(last_sqi == 0) {
+ last_sqi = qi_get_sqi();
+ }
+ if(last_sqi > max_sqi) last_sqi = max_sqi;
+
+ return (last_sqi * 255 / max_sqi);
+ }
+
+ /** Reset Board **/
+ void reset_board() {
+ init();
+ }
+};
