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