Added support for the WNC M14A2A Cellular LTE Data Module.

Dependencies:   WNC14A2AInterface

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SimpleSpirit1.h Source File

SimpleSpirit1.h

00001 /*** Mbed Includes ***/
00002 #include "mbed.h"
00003 #include "mbed_debug.h"
00004 
00005 
00006 /*** Cube Includes ***/
00007 #include "SPIRIT_Radio.h"
00008 #include "SPIRIT_Management.h"
00009 #include "SPIRIT_Commands.h"
00010 #include "MCU_Interface.h"
00011 
00012 
00013 /*** Contiki Lib Includes ***/
00014 #include "spirit1.h"
00015 #include "spirit1-config.h"
00016 #include "spirit1-const.h"
00017 
00018 
00019 // betzw: enable beyond macro if you want debug messages also from IRQ handler
00020 // #define DEBUG_IRQ
00021 
00022 
00023 /*** Macros from Cube Implementation ***/
00024 #define CLEAR_TXBUF()           (spirit_tx_len = 0)
00025 #define IS_RXBUF_EMPTY()        (spirit_rx_len == 0)
00026 #define CLEAR_RXBUF()           do {                    \
00027                                     spirit_rx_len = 0;  \
00028                                     _spirit_rx_pos = 0; \
00029                                 } while(0)
00030 
00031 
00032 /*** Macros from Cube Implementation ***/
00033 /* transceiver state. */
00034 #define ON     0
00035 #define OFF    1
00036 
00037 
00038 /*** Missing Cube External Declarations ***/
00039 extern "C" void SpiritManagementSetFrequencyBase(uint32_t);
00040 
00041 
00042 /*** UnlockedSPI for Performance (due to singleton) ***/
00043 class UnlockedSPI : public SPI {
00044 public:
00045     UnlockedSPI(PinName mosi, PinName miso, PinName sclk) :
00046         SPI(mosi, miso, sclk) { }
00047     virtual ~UnlockedSPI() {}
00048     virtual void lock() { }
00049     virtual void unlock() { }
00050 };
00051 
00052 
00053 /*** A Simple Spirit1 Class ***/
00054 // NOTE: must be a singleton (due to mix of MBED/CUBE code)!!!
00055 // NOTE: implementation is IRQ-save but (intentionally) NOT thread-safe!!!
00056 class SimpleSpirit1 {
00057  protected:
00058     static SimpleSpirit1 *_singleton;
00059 
00060     /** Communication Interface Instance Variables **/
00061     UnlockedSPI _spi; // betzw - NOTE: Morpho/Zio pins are valid only for NUCLEO-F401RE
00062                       // mosi: PA_7 (D11)
00063                       // miso: PA_6 (D12)
00064                       // sclk: PB_3 (D3) or
00065                       //       PA_5 (D13) (only in case you unmount R4 & mount R7,
00066                       //                  (note: in this case you may not use LED1 on some platforms)
00067                       // bits: 8-bit
00068                       // mode: 0
00069                       // ordr: MSB
00070                       // freq: max 10MHz
00071     InterruptIn _irq; // PC_7 (D9) (falling)
00072     DigitalOut _chip_select; // PB_6 (D10) ('1' == chip unselected)
00073     DigitalOut _shut_down; // PA_10 (D2) ('1' == shut_down)
00074     DigitalOut _led; // PB_4 (D5) (optional)
00075 
00076     Callback<void(int)> _current_irq_callback;
00077     Timeout _rx_receiving_timeout;
00078 
00079     void rx_timeout_handler(void) {
00080         set_ready_state();
00081         cmd_strobe(SPIRIT1_STROBE_RX);
00082 #ifdef DEBUG_IRQ
00083         debug("\n\r%s (%d)\n\r", __func__, __LINE__);
00084 #endif
00085     }
00086 
00087     void start_rx_timeout(void) {
00088         _rx_receiving_timeout.attach_us(Callback<void()>(this, &SimpleSpirit1::rx_timeout_handler), 100 * 1000); // 100ms
00089     }
00090 
00091     void stop_rx_timeout(void) {
00092         _rx_receiving_timeout.detach();
00093     }
00094 
00095     /** Static Variables from Cube Implementation **/
00096     /*
00097      * The buffers which hold incoming data.
00098      * The +1 because of the first byte,
00099      * which will contain the length of the packet.
00100      */
00101     volatile uint16_t spirit_tx_len;
00102     volatile bool _spirit_tx_started;
00103     volatile uint16_t spirit_rx_len;
00104     volatile uint16_t _spirit_rx_pos;
00105     volatile bool _spirit_rx_err;
00106     uint8_t spirit_rx_buf[MAX_PACKET_LEN];
00107     volatile bool _is_receiving;
00108 
00109     /** Status Variables from Cube Implementation **/
00110     unsigned int spirit_on;
00111     uint8_t last_rssi; //MGR
00112     uint8_t last_sqi;  //MGR
00113 
00114     /** Low Level Instance Variables **/
00115     unsigned int _nr_of_irq_disables;
00116 
00117     /** Low Level Instance Methods **/
00118     void disable_spirit_irq(void) {
00119         _irq.disable_irq();
00120         _nr_of_irq_disables++;
00121 #ifndef NDEBUG
00122         debug_if(_nr_of_irq_disables == 0, "\n\rassert failed in: %s (%d)\n\r", __func__, __LINE__);
00123 #endif
00124     }
00125 
00126     void enable_spirit_irq(void) {
00127 #ifndef NDEBUG
00128         debug_if(_nr_of_irq_disables == 0, "\n\rassert failed in: %s (%d)\n\r", __func__, __LINE__);
00129 #endif
00130         if(--_nr_of_irq_disables == 0)
00131             _irq.enable_irq();
00132     }
00133 
00134     void chip_select() { _chip_select = 0; }
00135     void chip_unselect() { _chip_select = 1; }
00136 
00137     void enter_shutdown() {
00138         _shut_down = 1;
00139         wait_ms(5); // wait 5 milliseconds (to allow Spirit1 to shut down)
00140     }
00141 
00142     void exit_shutdown() {
00143         _shut_down = 0;
00144         wait_ms(10); // wait 10 milliseconds (to allow Spirit1 a proper boot-up sequence)
00145     }
00146 
00147     void cs_to_sclk_delay(void) {
00148         wait_us(1); // heuristic value
00149     }
00150 
00151     /**
00152      * @brief      Write and read a buffer to/from the SPI peripheral device at the same time
00153      *             in 8-bit data mode using synchronous SPI communication.
00154      * @param[in]  pBufferToWrite pointer to the buffer of data to send.
00155      * @param[out] pBufferToRead pointer to the buffer to read data into.
00156      * @param[in]  NumBytes number of bytes to read and write.
00157      * @retval     0 if ok.
00158      * @retval     -1 if data format error.
00159      * @note       When using the SPI in Interrupt-mode, remember to disable interrupts
00160      *             before calling this function and to enable them again after.
00161      */
00162     void spi_write_read(uint8_t* pBufferToWrite, uint8_t* pBufferToRead, uint16_t NumBytes)
00163     {
00164         /* Read and write data at the same time. */
00165         for (int i = 0; i < NumBytes; i++) {
00166             pBufferToRead[i] = _spi.write(pBufferToWrite[i]);
00167         }
00168     }
00169 
00170     /** Radio Instance Methods **/
00171     void radio_set_xtal_freq(uint32_t freq) {
00172         SpiritRadioSetXtalFrequency(freq);
00173     }
00174 
00175     void radio_set_pa_level_dbm(uint8_t cIndex, float fPowerdBm) {
00176         SpiritRadioSetPALeveldBm(cIndex, fPowerdBm);
00177     }
00178 
00179     void radio_set_pa_level_max_index(uint8_t cIndex) {
00180         SpiritRadioSetPALevelMaxIndex(cIndex);
00181     }
00182 
00183     uint8_t radio_init(SRadioInit *init_struct) {
00184         return SpiritRadioInit(init_struct);
00185     }
00186 
00187     void radio_persistent_rx(SpiritFunctionalState xNewState) {
00188         SpiritRadioPersistenRx(xNewState);
00189     }
00190 
00191     void radio_afc_freeze_on_sync(SpiritFunctionalState xNewState) {
00192         SpiritRadioAFCFreezeOnSync(xNewState);
00193     }
00194 
00195     /** Packet System Instance Methods **/
00196     void pkt_basic_init(PktBasicInit* pxPktBasicInit) {
00197         SpiritPktBasicInit(pxPktBasicInit);
00198     }
00199 
00200     void pkt_basic_set_payload_length(uint16_t nPayloadLength) {
00201         SpiritPktBasicSetPayloadLength(nPayloadLength);
00202     }
00203 
00204     uint16_t pkt_basic_get_received_pkt_length(void) {
00205         return SpiritPktBasicGetReceivedPktLength();
00206     }
00207 
00208     /** IRQ Instance Methods **/
00209     void irq_de_init(SpiritIrqs* pxIrqInit) {
00210         SpiritIrqDeInit(pxIrqInit);
00211     }
00212 
00213     void irq_clear_status(void) {
00214         SpiritIrqClearStatus();
00215     }
00216 
00217     void irq_set_status(IrqList xIrq, SpiritFunctionalState xNewState) {
00218         SpiritIrq(xIrq, xNewState);
00219     }
00220 
00221     void irq_get_status(SpiritIrqs* pxIrqStatus) {
00222         SpiritIrqGetStatus(pxIrqStatus);
00223     }
00224 
00225     /** Management Instance Methods **/
00226     void mgmt_set_freq_base(uint32_t freq) {
00227         SpiritManagementSetFrequencyBase(freq);
00228     }
00229 
00230     void mgmt_refresh_status(void) {
00231         SpiritRefreshStatus();
00232     }
00233 
00234     /** Spirit GPIO Instance Methods **/
00235     void spirit_gpio_init(SGpioInit* pxGpioInitStruct) {
00236         SpiritGpioInit(pxGpioInitStruct);
00237     }
00238 
00239     /** Qi Instance Methods **/
00240     void qi_set_sqi_threshold(SqiThreshold xSqiThr) {
00241         SpiritQiSetSqiThreshold(xSqiThr);
00242     }
00243 
00244     void qi_sqi_check(SpiritFunctionalState xNewState) {
00245         SpiritQiSqiCheck(xNewState);
00246     }
00247 
00248     void qi_set_rssi_threshold_dbm(int nDbmValue) {
00249         SpiritQiSetRssiThresholddBm(nDbmValue);
00250     }
00251 
00252     float qi_get_rssi_dbm() {
00253         last_rssi = qi_get_rssi();
00254         return get_last_rssi_dbm();
00255     }
00256 
00257     uint8_t qi_get_rssi() {
00258         return SpiritQiGetRssi();
00259     }
00260 
00261     uint8_t qi_get_sqi() {
00262         return SpiritQiGetSqi();
00263     }
00264 
00265     /** Timer Instance Methods **/
00266     void timer_set_rx_timeout_stop_condition(RxTimeoutStopCondition xStopCondition) {
00267         SpiritTimerSetRxTimeoutStopCondition(xStopCondition);
00268     }
00269 
00270     void timer_set_rx_timeout_counter(uint8_t cCounter) {
00271         SpiritTimerSetRxTimeoutCounter(cCounter);
00272     }
00273 
00274     void timer_set_infinite_rx_timeout(void) {
00275         timer_set_rx_timeout_counter(0);
00276     }
00277 
00278     /** CSMA/CA Instance Methods **/
00279     void csma_ca_state(SpiritFunctionalState xNewState) {
00280         SpiritCsma(xNewState);
00281     }
00282 
00283     void csma_ca_init(CsmaInit* pxCsmaInit) {
00284         csma_ca_state(S_DISABLE); // Disabled at init
00285         SpiritCsmaInit(pxCsmaInit);
00286         SpiritCsmaSeedReloadMode(S_DISABLE); // always disable seed reload
00287     }
00288 
00289     /** Command Instance Methods**/
00290     void cmd_strobe(uint8_t cmd) {
00291         SpiritCmdStrobeCommand((SpiritCmd)cmd);
00292     }
00293 
00294     void cmd_strobe_flush_rx_fifo() {
00295         SpiritCmdStrobeCommand(CMD_FLUSHRXFIFO);
00296     }
00297 
00298     /** SPI Instance Methods **/
00299     StatusBytes spi_write_linear_fifo(uint8_t cNbBytes, uint8_t* pcBuffer) {
00300         return SdkEvalSpiWriteFifo(cNbBytes, pcBuffer);
00301     }
00302 
00303     StatusBytes spi_read_linear_fifo(uint8_t cNbBytes, uint8_t* pcBuffer) {
00304         return SdkEvalSpiReadFifo(cNbBytes, pcBuffer);
00305     }
00306 
00307     /** Linear FIFO Instance Methods **/
00308     uint8_t linear_fifo_read_num_elements_rx_fifo(void) {
00309         return SpiritLinearFifoReadNumElementsRxFifo();
00310     }
00311 
00312     uint8_t linear_fifo_read_num_elements_tx_fifo(void) {
00313         return SpiritLinearFifoReadNumElementsTxFifo();
00314     }
00315 
00316     void linear_fifo_set_almost_full_thr_rx(uint8_t cThrRxFifo) {
00317         SpiritLinearFifoSetAlmostFullThresholdRx(cThrRxFifo);
00318     }
00319 
00320     /** Calibration Instance Methods **/
00321     void calibration_rco(SpiritFunctionalState xNewState) {
00322         SpiritCalibrationRco(xNewState);
00323     }
00324 
00325     /** Internal Spirit Methods */
00326     void set_ready_state(void);
00327     uint8_t refresh_state(void);
00328 
00329     /** Friend Functions **/
00330     friend StatusBytes SdkEvalSpiWriteRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer);
00331     friend StatusBytes SdkEvalSpiReadRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer);
00332     friend StatusBytes SdkEvalSpiCommandStrobes(uint8_t cCommandCode);
00333     friend StatusBytes SdkEvalSpiWriteFifo(uint8_t cNbBytes, uint8_t* pcBuffer);
00334     friend StatusBytes SdkEvalSpiReadFifo(uint8_t cNbBytes, uint8_t* pcBuffer);
00335 
00336     /** Sdk Instance Methods **/
00337     StatusBytes SdkEvalSpiWriteRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer);
00338     StatusBytes SdkEvalSpiReadRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer);
00339     StatusBytes SdkEvalSpiCommandStrobes(uint8_t cCommandCode);
00340     StatusBytes SdkEvalSpiWriteFifo(uint8_t cNbBytes, uint8_t* pcBuffer);
00341     StatusBytes SdkEvalSpiReadFifo(uint8_t cNbBytes, uint8_t* pcBuffer);
00342 
00343     /** Helper Instance Methods **/
00344     void chip_sync_select() {
00345         disable_spirit_irq();
00346         chip_select();
00347         cs_to_sclk_delay();
00348     }
00349 
00350     void chip_sync_unselect() {
00351         chip_unselect();
00352         enable_spirit_irq();
00353     }
00354 
00355     /** Init Instance Method **/
00356     void init();
00357 
00358     /** Spirit Irq Callback */
00359     void IrqHandler();
00360 
00361     /** Constructor **/
00362     SimpleSpirit1(PinName mosi, PinName miso, PinName sclk,
00363           PinName irq, PinName cs, PinName sdn,
00364           PinName led);
00365 
00366     /** Destructor **/
00367     ~SimpleSpirit1(void); // should never be called!
00368 
00369 public:
00370     enum {
00371         RX_DONE,
00372         TX_DONE,
00373         TX_ERR
00374     };
00375 
00376     static SimpleSpirit1& CreateInstance(PinName mosi, PinName miso, PinName sclk,
00377             PinName irq, PinName cs, PinName sdn,
00378             PinName led = NC) {
00379 
00380         if(_singleton == NULL) {
00381             _singleton = new SimpleSpirit1(mosi, miso, sclk,
00382                     irq, cs, sdn, led);
00383             _singleton->init();
00384         } else {
00385             error("SimpleSpirit1 singleton already created!\n");
00386         }
00387 
00388         return *_singleton;
00389     }
00390 
00391     static SimpleSpirit1& Instance() {
00392         if(_singleton == NULL) {
00393             error("SimpleSpirit1 must be created before used!\n");
00394         }
00395 
00396         return *_singleton;
00397     }
00398 
00399     /** Attach a function to be called by the Spirit Irq handler when packet has arrived
00400      *
00401      *  @param func A void() callback, or 0 to set as none
00402      *
00403      *  @note  Function 'func' will be executed in interrupt context!
00404      */
00405     void attach_irq_callback(Callback<void(int)> func) {
00406         _current_irq_callback = func;
00407     }
00408 
00409     /** Switch Radio On/Off **/
00410     int on(void);
00411     int off(void);
00412 
00413     /** Set Channel **/
00414     void set_channel(uint8_t channel) {
00415         SpiritRadioSetChannel(channel);
00416     }
00417 
00418     /** Send a Buffer **/
00419     int send(const void *payload, unsigned int payload_len);
00420 
00421     /** Read into Buffer **/
00422     int read(void *buf, unsigned int bufsize);
00423 
00424     /** Perform a Clear-Channel Assessment (CCA) to find out if there is
00425         a packet in the air or not.
00426         Returns 1 if packet has been seen.
00427       */
00428     int channel_clear(void);
00429 
00430     /** Check if the radio driver has just received a packet **/
00431     int get_pending_packet(void);
00432 
00433     /** Is radio currently receiving **/
00434     bool is_receiving(void) {
00435         return _is_receiving;
00436     }
00437 
00438     /** Get latest value of RSSI (in dBm) **/
00439     float get_last_rssi_dbm(void) {
00440         get_last_rssi_raw();
00441         return (-120.0+((float)(last_rssi-20))/2);
00442     }
00443 
00444     /** Get latest value of RSSI (as Spirit1 raw value) **/
00445     uint8_t get_last_rssi_raw(void) {
00446         if(last_rssi == 0) {
00447             last_rssi = qi_get_rssi();
00448         }
00449         return last_rssi;
00450     }
00451 
00452     /** Get latest value of LQI (scaled to 8-bit) **/
00453     uint8_t get_last_sqi(void) {
00454         const uint8_t max_sqi = 8 * ((SYNC_LENGTH>>1)+1);
00455         if(last_sqi == 0) {
00456             last_sqi = qi_get_sqi();
00457         }
00458         if(last_sqi > max_sqi) last_sqi = max_sqi;
00459 
00460         return (last_sqi * 255 / max_sqi);
00461     }
00462 
00463     /** Reset Board **/
00464     void reset_board() {
00465         init();
00466     }
00467 };