Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 };
Generated on Tue Jul 12 2022 16:22:11 by
