센서보드 RF IRQ 테스트 중 and bug fix?
Fork of EV-COG-AD3029LZ by
stm-spirit1-rf-driver/SimpleSpirit1.h
- Committer:
- Wolfgang Betz
- Date:
- 2017-04-28
- Revision:
- 57:8cc871dc6cac
- Parent:
- 51:d46b4cc970c5
- Child:
- 64:28ef790e4ef7
File content as of revision 57:8cc871dc6cac:
/*** 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 Usage in IRQ context ***/ 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(); } };