Toyomasa Watarai / Mbed OS Mbed-example-WS-W27

Dependencies:   MMA7660 LM75B

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