Vergil Cola
/
MQTTGatewayK64
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(); + } +};