Fork of my MQTTGateway
Diff: easy-connect/stm-spirit1-rf-driver/stm-spirit1-rf-driver/SimpleSpirit1.h
- Revision:
- 0:f1d3878b8dd9
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/easy-connect/stm-spirit1-rf-driver/stm-spirit1-rf-driver/SimpleSpirit1.h Sat Apr 08 14:45:51 2017 +0000
@@ -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: Morpho/Zio 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), 100 * 1000); // 100ms
+ }
+
+ 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();
+ }
+};