Farnell-Element14 Bologna IOT Team / wifi-ism43362

Dependents:   DISCO_L475VG_IOT01-Sensors-BSP

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BufferedSpi.cpp Source File

BufferedSpi.cpp

Go to the documentation of this file.
00001 /**
00002  * @file    BufferedSpi.cpp
00003  * @brief   Software Buffer - Extends mbed SPI functionallity
00004  * @author  Armelle Duboc
00005  * @version 1.0
00006  * @see
00007  *
00008  * Copyright (c) STMicroelectronics 2017
00009  *
00010  * Licensed under the Apache License, Version 2.0 (the "License");
00011  * you may not use this file except in compliance with the License.
00012  * You may obtain a copy of the License at
00013  *
00014  *     http://www.apache.org/licenses/LICENSE-2.0
00015  *
00016  * Unless required by applicable law or agreed to in writing, software
00017  * distributed under the License is distributed on an "AS IS" BASIS,
00018  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00019  * See the License for the specific language governing permissions and
00020  * limitations under the License.
00021  */
00022 
00023 #include "BufferedSpi.h"
00024 #include <stdarg.h>
00025 #include "mbed_debug.h"
00026 #include "mbed_error.h"
00027 
00028 // change to true to add few SPI debug lines
00029 #define local_debug false
00030 
00031 extern "C" int BufferedPrintfC(void *stream, int size, const char* format, va_list arg);
00032 
00033 void BufferedSpi::DatareadyRising(void)
00034 {
00035    if (_cmddata_rdy_rising_event == 1) {
00036      _cmddata_rdy_rising_event=0;
00037    }
00038 }
00039 
00040 int BufferedSpi::wait_cmddata_rdy_high(void)
00041 {
00042   Timer timer;
00043   timer.start();
00044 
00045   /* wait for dataready = 1 */
00046   while(dataready.read() == 0) {
00047        if (timer.read_ms() > _timeout) {
00048           debug_if(local_debug,"ERROR: SPI write timeout\r\n");
00049           return -1;
00050        }
00051   }
00052 
00053   _cmddata_rdy_rising_event = 1;
00054 
00055   return 0;
00056 }
00057 
00058 int BufferedSpi::wait_cmddata_rdy_rising_event(void)
00059 {
00060     Timer timer;
00061     timer.start();
00062 
00063     while (_cmddata_rdy_rising_event == 1) {
00064        if (timer.read_ms() > _timeout) {
00065            _cmddata_rdy_rising_event = 0;
00066            if (dataready.read() == 1) {
00067                debug_if(local_debug,"ERROR: We missed rising event !! (timemout=%d)\r\n", _timeout);
00068            }
00069            debug_if(local_debug,"ERROR: SPI read timeout\r\n");
00070            return -1;
00071        }
00072     }
00073 
00074     return 0;
00075 }
00076 
00077 BufferedSpi::BufferedSpi(PinName mosi, PinName miso, PinName sclk, PinName _nss, PinName _datareadypin,
00078                          uint32_t buf_size, uint32_t tx_multiple, const char* name)
00079     : SPI(mosi, miso, sclk, NC), nss(_nss),  _txbuf((uint32_t)(tx_multiple*buf_size)), _rxbuf(buf_size), dataready(_datareadypin)
00080 {
00081     this->_buf_size = buf_size;
00082     this->_tx_multiple = tx_multiple;
00083     this->_sigio_event = 0;
00084 
00085     _datareadyInt = new InterruptIn(_datareadypin);
00086     _datareadyInt->rise(callback(this, &BufferedSpi::DatareadyRising));
00087 
00088     _cmddata_rdy_rising_event = 1;
00089 
00090     return;
00091 }
00092 
00093 BufferedSpi::~BufferedSpi(void)
00094 {
00095 
00096     return;
00097 }
00098 
00099 void BufferedSpi::frequency(int hz)
00100 {
00101     SPI::frequency(hz);
00102 }
00103 
00104 void BufferedSpi::format(int bits, int mode)
00105 {
00106     SPI::format(bits, mode);
00107 }
00108 
00109 void BufferedSpi::disable_nss()
00110 {
00111     nss = 1;
00112     wait_us(15);
00113 }
00114 
00115 void BufferedSpi::enable_nss()
00116 {
00117     nss = 0;
00118     wait_us(15);
00119 }
00120 
00121 int BufferedSpi::readable(void)
00122 {
00123     return _rxbuf.available();  // note: look if things are in the buffer
00124 }
00125 
00126 int BufferedSpi::writeable(void)
00127 {
00128     return 1;   // buffer allows overwriting by design, always true
00129 }
00130 
00131 int BufferedSpi::getc(void)
00132 {
00133     if (_rxbuf.available())
00134         return _rxbuf;
00135     else return -1;
00136 }
00137 
00138 int BufferedSpi::putc(int c)
00139 {
00140     _txbuf = (char)c;
00141 
00142     return c;
00143 }
00144 
00145 void BufferedSpi::flush_txbuf(void)
00146 {
00147     _txbuf.clear();
00148 }
00149 
00150 int BufferedSpi::puts(const char *s)
00151 {
00152     if (s != NULL) {
00153         const char* ptr = s;
00154     
00155         while(*(ptr) != 0) {
00156             _txbuf = *(ptr++);
00157         }
00158         _txbuf = '\n';  // done per puts definition
00159         BufferedSpi::txIrq();                // only write to hardware in one place
00160         return (ptr - s) + 1;
00161     }
00162     return 0;
00163 }
00164 
00165 extern "C" size_t BufferedSpiThunk(void *buf_spi, const void *s, size_t length)
00166 {
00167     BufferedSpi *buffered_spi = (BufferedSpi *)buf_spi;
00168     return buffered_spi->buffwrite(s, length);
00169 }
00170 
00171 int BufferedSpi::printf(const char* format, ...)
00172 {
00173     va_list arg;
00174     va_start(arg, format);
00175     int r = BufferedPrintfC((void*)this, this->_buf_size, format, arg);
00176     va_end(arg);
00177     return r;
00178 }
00179 
00180 ssize_t BufferedSpi::buffwrite(const void *s, size_t length)
00181 {
00182     /* flush buffer from previous message */
00183     this->flush_txbuf();
00184 
00185     if (wait_cmddata_rdy_high() < 0) {
00186         debug_if(local_debug, "BufferedSpi::buffwrite timeout (%d)\r\n", _timeout);
00187         return -1;
00188     }
00189 
00190     this->enable_nss();
00191     
00192     if (s != NULL && length > 0) {
00193         /* 1st fill _txbuf */
00194         const char* ptr = (const char*)s;
00195         const char* end = ptr + length;
00196     
00197         while (ptr != end) {
00198             _txbuf = *(ptr++);
00199         }
00200         if (length&1) { /* padding to send the last char */
00201             _txbuf = '\n';
00202             length++;
00203         }
00204 
00205         /* 2nd write in SPI */
00206         BufferedSpi::txIrq();                // only write to hardware in one place
00207 
00208         this->disable_nss();
00209         return ptr - (const char*)s;
00210     }
00211     this->disable_nss();
00212 
00213     return 0;
00214 }
00215 
00216 ssize_t BufferedSpi::buffsend(size_t length)
00217 {
00218     /* wait for dataready = 1 */
00219     if (wait_cmddata_rdy_high() < 0) {
00220         debug_if(local_debug, "BufferedSpi::buffsend timeout (%d)\r\n", _timeout);
00221         return -1;
00222     }
00223 
00224     this->enable_nss();
00225 
00226     /* _txbuffer is already filled with data to send */
00227     /* check if _txbuffer needs padding to send the last char */
00228     if (length & 1) {
00229         _txbuf = '\n';
00230         length++;
00231     }
00232     BufferedSpi::txIrq();                // only write to hardware in one place
00233 
00234     this->disable_nss();
00235 
00236     return length;
00237 }
00238 
00239 ssize_t BufferedSpi::read()
00240 {
00241     return this->read(0);
00242 }
00243 
00244 ssize_t BufferedSpi::read(uint32_t max)
00245 {
00246     uint32_t len = 0;
00247     int tmp;
00248 
00249     disable_nss();
00250 
00251     /* wait for data ready is up */
00252     if(wait_cmddata_rdy_rising_event() != 0) {
00253         debug_if(local_debug, "BufferedSpi::read timeout (%d)\r\n", _timeout);
00254         return -1;
00255     }
00256 
00257     enable_nss();
00258     while (dataready.read() == 1 && (len < (_buf_size - 1))) {
00259         tmp = SPI::write(0xAA);  // dummy write to receive 2 bytes
00260 
00261         if (!((len == 0) && (tmp == 0x0A0D))) {
00262             /* do not take into account the 2 firts \r \n char in the buffer */
00263             if ((max == 0) || (len < max)) {
00264                 _rxbuf = (char)(tmp & 0x00FF);
00265                 _rxbuf = (char)((tmp >>8)& 0xFF);
00266                 len += 2;
00267             }
00268         }
00269     }
00270     disable_nss();
00271 
00272     if (len >= _buf_size) {
00273         debug_if(local_debug, "firmware ERROR ES_WIFI_ERROR_STUFFING_FOREVER\r\n");
00274         return -1;
00275     }
00276 
00277     debug_if(local_debug, "SPI READ %d BYTES\r\n", len);
00278 
00279     return len;
00280 }
00281 
00282 void BufferedSpi::txIrq(void)
00283 { /* write everything available in the _txbuffer */
00284     int value = 0;
00285     int dbg_cnt = 0;
00286     while (_txbuf.available() && (_txbuf.getNbAvailable()>0)) {
00287         value = _txbuf.get();
00288         if (_txbuf.available() && ((_txbuf.getNbAvailable()%2)!=0)) {
00289             value |= ((_txbuf.get()<<8)&0XFF00);
00290             SPI::write(value);
00291             dbg_cnt++;
00292         }
00293     }
00294     debug_if(local_debug, "SPI Sent %d BYTES\r\n", 2*dbg_cnt);
00295     // disable the TX interrupt when there is nothing left to send
00296     BufferedSpi::attach(NULL, BufferedSpi::TxIrq);
00297     // trigger callback if necessary
00298     if (_cbs[TxIrq]) {
00299         _cbs[TxIrq]();
00300     }
00301     return;
00302 }
00303 
00304 void BufferedSpi::prime(void)
00305 {
00306     BufferedSpi::txIrq();                // only write to hardware in one place
00307     return;
00308 }
00309 
00310 void BufferedSpi::attach(Callback<void()> func, IrqType type)
00311 {
00312     _cbs[type] = func;
00313 }
00314 
00315 void BufferedSpi::sigio(Callback<void()> func) {
00316     core_util_critical_section_enter();
00317     _sigio_cb = func;
00318     if (_sigio_cb) {
00319         if (_sigio_event == 1) {
00320             _sigio_cb();
00321             _sigio_event = 0;
00322         }
00323     }
00324     core_util_critical_section_exit();
00325 }
00326