Version of easy-connect with the u-blox cellular platforms C027 and C030 added.
Embed:
(wiki syntax)
Show/hide line numbers
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 1.7.2